diff --git a/.editorconfig b/.editorconfig index ae4c97662..1eaf77ae6 100644 --- a/.editorconfig +++ b/.editorconfig @@ -17,8 +17,8 @@ tab_width = 4 end_of_line = lf insert_final_newline = true -# JSON files -[*.json] +# Markdown, JSON, YAML, props and csproj files +[*.{md,json,yml,props,csproj}] # Indentation and spacing indent_size = 2 diff --git a/.github/labeler.yml b/.github/labeler.yml index 027448437..b967cc776 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -20,7 +20,7 @@ gpu: gui: - changed-files: - - any-glob-to-any-file: ['src/Ryujinx/**', 'src/Ryujinx.Ui.Common/**', 'src/Ryujinx.Ui.LocaleGenerator/**', 'src/Ryujinx.Ava/**'] + - any-glob-to-any-file: ['src/Ryujinx/**', 'src/Ryujinx.UI.Common/**', 'src/Ryujinx.UI.LocaleGenerator/**', 'src/Ryujinx.Ava/**'] horizon: - changed-files: diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cf4fdf051..598f23c5e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,28 +10,17 @@ env: jobs: build: - name: ${{ matrix.OS_NAME }} (${{ matrix.configuration }}) - runs-on: ${{ matrix.os }} + name: ${{ matrix.platform.name }} (${{ matrix.configuration }}) + runs-on: ${{ matrix.platform.os }} timeout-minutes: 45 strategy: matrix: - os: [ubuntu-latest, macOS-latest, windows-latest] configuration: [Debug, Release] - include: - - os: ubuntu-latest - OS_NAME: Linux x64 - DOTNET_RUNTIME_IDENTIFIER: linux-x64 - RELEASE_ZIP_OS_NAME: linux_x64 - - - os: macOS-latest - OS_NAME: macOS x64 - DOTNET_RUNTIME_IDENTIFIER: osx-x64 - RELEASE_ZIP_OS_NAME: osx_x64 - - - os: windows-latest - OS_NAME: Windows x64 - DOTNET_RUNTIME_IDENTIFIER: win-x64 - RELEASE_ZIP_OS_NAME: win_x64 + platform: + - { name: win-x64, os: windows-latest, zip_os_name: win_x64 } + - { name: linux-x64, os: ubuntu-latest, zip_os_name: linux_x64 } + - { name: linux-arm64, os: ubuntu-latest, zip_os_name: linux_arm64 } + - { name: osx-x64, os: macOS-latest, zip_os_name: osx_x64 } fail-fast: false steps: @@ -40,7 +29,7 @@ jobs: - uses: actions/setup-dotnet@v4 with: global-json-file: global.json - + - name: Overwrite csc problem matcher run: echo "::add-matcher::.github/csc.json" @@ -49,6 +38,16 @@ jobs: run: echo "result=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT shell: bash + - name: Change config filename + run: sed -r --in-place 's/\%\%RYUJINX_CONFIG_FILE_NAME\%\%/PRConfig\.json/g;' src/Ryujinx.Common/ReleaseInformation.cs + shell: bash + if: github.event_name == 'pull_request' && matrix.platform.os != 'macOS-latest' + + - name: Change config filename for macOS + run: sed -r -i '' 's/\%\%RYUJINX_CONFIG_FILE_NAME\%\%/PRConfig\.json/g;' src/Ryujinx.Common/ReleaseInformation.cs + shell: bash + if: github.event_name == 'pull_request' && matrix.platform.os == 'macOS-latest' + - name: Build run: dotnet build -c "${{ matrix.configuration }}" -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER @@ -58,46 +57,47 @@ jobs: commands: dotnet test --no-build -c "${{ matrix.configuration }}" timeout-minutes: 10 retry-codes: 139 + if: matrix.platform.name != 'linux-arm64' - name: Publish Ryujinx - run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx --self-contained true - if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest' + run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.platform.name }}" -o ./publish -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx --self-contained true + if: github.event_name == 'pull_request' && matrix.platform.os != 'macOS-latest' - name: Publish Ryujinx.Headless.SDL2 - run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_sdl2_headless -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx.Headless.SDL2 --self-contained true - if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest' + run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.platform.name }}" -o ./publish_sdl2_headless -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx.Headless.SDL2 --self-contained true + if: github.event_name == 'pull_request' && matrix.platform.os != 'macOS-latest' - name: Publish Ryujinx.Ava - run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_ava -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx.Ava --self-contained true - if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest' + run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.platform.name }}" -o ./publish_ava -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx.Ava --self-contained true + if: github.event_name == 'pull_request' && matrix.platform.os != 'macOS-latest' - name: Set executable bit run: | chmod +x ./publish/Ryujinx ./publish/Ryujinx.sh chmod +x ./publish_sdl2_headless/Ryujinx.Headless.SDL2 ./publish_sdl2_headless/Ryujinx.sh chmod +x ./publish_ava/Ryujinx.Ava ./publish_ava/Ryujinx.sh - if: github.event_name == 'pull_request' && matrix.os == 'ubuntu-latest' + if: github.event_name == 'pull_request' && matrix.platform.os == 'ubuntu-latest' - name: Upload Ryujinx artifact uses: actions/upload-artifact@v4 with: - name: ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.RELEASE_ZIP_OS_NAME }} + name: ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.platform.zip_os_name }} path: publish - if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest' + if: github.event_name == 'pull_request' && matrix.platform.os != 'macOS-latest' - name: Upload Ryujinx.Headless.SDL2 artifact uses: actions/upload-artifact@v4 with: - name: sdl2-ryujinx-headless-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.RELEASE_ZIP_OS_NAME }} + name: sdl2-ryujinx-headless-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.platform.zip_os_name }} path: publish_sdl2_headless - if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest' + if: github.event_name == 'pull_request' && matrix.platform.os != 'macOS-latest' - name: Upload Ryujinx.Ava artifact uses: actions/upload-artifact@v4 with: - name: ava-ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.RELEASE_ZIP_OS_NAME }} + name: ava-ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.platform.zip_os_name }} path: publish_ava - if: github.event_name == 'pull_request' && matrix.os != 'macOS-latest' + if: github.event_name == 'pull_request' && matrix.platform.os != 'macOS-latest' build_macos: name: macOS Universal (${{ matrix.configuration }}) @@ -135,6 +135,11 @@ jobs: id: git_short_hash run: echo "result=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT + - name: Change config filename + run: sed -r --in-place 's/\%\%RYUJINX_CONFIG_FILE_NAME\%\%/PRConfig\.json/g;' src/Ryujinx.Common/ReleaseInformation.cs + shell: bash + if: github.event_name == 'pull_request' + - name: Publish macOS Ryujinx.Ava run: | ./distribution/macos/create_macos_build_ava.sh . publish_tmp_ava publish_ava ./distribution/macos/entitlements.xml "${{ env.RYUJINX_BASE_VERSION }}" "${{ steps.git_short_hash.outputs.result }}" "${{ matrix.configuration }}" "-p:ExtraDefineConstants=DISABLE_UPDATER" diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 5311a67f6..2bef2d8e0 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -8,7 +8,7 @@ on: - '!.github/**' - '!*.yml' - '!*.config' - - '!README.md' + - '!*.md' - '.github/workflows/*.yml' permissions: diff --git a/.github/workflows/mako.yml b/.github/workflows/mako.yml new file mode 100644 index 000000000..19165fb04 --- /dev/null +++ b/.github/workflows/mako.yml @@ -0,0 +1,41 @@ +name: Mako +on: + discussion: + types: [created, edited, answered, unanswered, category_changed] + discussion_comment: + types: [created, edited] + gollum: + issue_comment: + types: [created, edited] + issues: + types: [opened, edited, reopened, pinned, milestoned, demilestoned, assigned, unassigned, labeled, unlabeled] + pull_request_target: + types: [opened, edited, reopened, synchronize, ready_for_review, assigned, unassigned] + +jobs: + tasks: + name: Run Ryujinx tasks + permissions: + actions: read + contents: read + discussions: write + issues: write + pull-requests: write + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + if: github.event_name == 'pull_request_target' + with: + # Ensure we pin the source origin as pull_request_target run under forks. + fetch-depth: 0 + repository: Ryujinx/Ryujinx + ref: master + + - name: Run Mako command + uses: Ryujinx/Ryujinx-Mako@master + with: + command: exec-ryujinx-tasks + args: --event-name "${{ github.event_name }}" --event-path "${{ github.event_path }}" -w "${{ github.workspace }}" "${{ github.repository }}" "${{ github.run_id }}" + app_id: ${{ secrets.MAKO_APP_ID }} + private_key: ${{ secrets.MAKO_PRIVATE_KEY }} + installation_id: ${{ secrets.MAKO_INSTALLATION_ID }} diff --git a/.github/workflows/pr_triage.yml b/.github/workflows/pr_triage.yml index 93aa89626..d8d66b70f 100644 --- a/.github/workflows/pr_triage.yml +++ b/.github/workflows/pr_triage.yml @@ -21,27 +21,8 @@ jobs: repository: Ryujinx/Ryujinx ref: master - - name: Checkout Ryujinx-Mako - uses: actions/checkout@v4 - with: - repository: Ryujinx/Ryujinx-Mako - ref: master - path: '.ryujinx-mako' - - - name: Setup Ryujinx-Mako - uses: ./.ryujinx-mako/.github/actions/setup-mako - - name: Update labels based on changes uses: actions/labeler@v5 with: sync-labels: true dot: true - - - name: Assign reviewers - run: | - poetry -n -C .ryujinx-mako run ryujinx-mako update-reviewers ${{ github.repository }} ${{ github.event.pull_request.number }} .github/reviewers.yml - shell: bash - env: - MAKO_APP_ID: ${{ secrets.MAKO_APP_ID }} - MAKO_PRIVATE_KEY: ${{ secrets.MAKO_PRIVATE_KEY }} - MAKO_INSTALLATION_ID: ${{ secrets.MAKO_INSTALLATION_ID }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7a4b13d7d..ac598684f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,7 +10,7 @@ on: - '*.yml' - '*.json' - '*.config' - - 'README.md' + - '*.md' concurrency: release @@ -45,22 +45,15 @@ jobs: }) release: - name: Release ${{ matrix.OS_NAME }} - runs-on: ${{ matrix.os }} + name: Release for ${{ matrix.platform.name }} + runs-on: ${{ matrix.platform.os }} timeout-minutes: ${{ fromJSON(vars.JOB_TIMEOUT) }} strategy: matrix: - os: [ ubuntu-latest, windows-latest ] - include: - - os: ubuntu-latest - OS_NAME: Linux x64 - DOTNET_RUNTIME_IDENTIFIER: linux-x64 - RELEASE_ZIP_OS_NAME: linux_x64 - - - os: windows-latest - OS_NAME: Windows x64 - DOTNET_RUNTIME_IDENTIFIER: win-x64 - RELEASE_ZIP_OS_NAME: win_x64 + platform: + - { name: win-x64, os: windows-latest, zip_os_name: win_x64 } + - { name: linux-x64, os: ubuntu-latest, zip_os_name: linux_x64 } + - { name: linux-arm64, os: ubuntu-latest, zip_os_name: linux_arm64 } steps: - uses: actions/checkout@v4 @@ -85,6 +78,7 @@ jobs: sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_NAME\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_NAME }}/g;' src/Ryujinx.Common/ReleaseInformation.cs sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_OWNER\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/g;' src/Ryujinx.Common/ReleaseInformation.cs sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/g;' src/Ryujinx.Common/ReleaseInformation.cs + sed -r --in-place 's/\%\%RYUJINX_CONFIG_FILE_NAME\%\%/Config\.json/g;' src/Ryujinx.Common/ReleaseInformation.cs shell: bash - name: Create output dir @@ -92,42 +86,42 @@ jobs: - name: Publish run: | - dotnet publish -c Release -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_gtk/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx --self-contained true - dotnet publish -c Release -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_sdl2_headless/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx.Headless.SDL2 --self-contained true - dotnet publish -c Release -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_ava/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx.Ava --self-contained true + dotnet publish -c Release -r "${{ matrix.platform.name }}" -o ./publish_gtk/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx --self-contained true + dotnet publish -c Release -r "${{ matrix.platform.name }}" -o ./publish_sdl2_headless/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx.Headless.SDL2 --self-contained true + dotnet publish -c Release -r "${{ matrix.platform.name }}" -o ./publish_ava/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx.Ava --self-contained true - name: Packing Windows builds - if: matrix.os == 'windows-latest' + if: matrix.platform.os == 'windows-latest' run: | pushd publish_gtk - 7z a ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish + 7z a ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip publish popd pushd publish_sdl2_headless - 7z a ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish + 7z a ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip publish popd pushd publish_ava - 7z a ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish + 7z a ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip publish popd shell: bash - name: Packing Linux builds - if: matrix.os == 'ubuntu-latest' + if: matrix.platform.os == 'ubuntu-latest' run: | pushd publish_gtk chmod +x publish/Ryujinx.sh publish/Ryujinx - tar -czvf ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish + tar -czvf ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz publish popd pushd publish_sdl2_headless chmod +x publish/Ryujinx.sh publish/Ryujinx.Headless.SDL2 - tar -czvf ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish + tar -czvf ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz publish popd pushd publish_ava chmod +x publish/Ryujinx.sh publish/Ryujinx.Ava - tar -czvf ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish + tar -czvf ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz publish popd shell: bash @@ -186,6 +180,7 @@ jobs: sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_NAME\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_NAME }}/g;' src/Ryujinx.Common/ReleaseInformation.cs sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_OWNER\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/g;' src/Ryujinx.Common/ReleaseInformation.cs sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/g;' src/Ryujinx.Common/ReleaseInformation.cs + sed -r --in-place 's/\%\%RYUJINX_CONFIG_FILE_NAME\%\%/Config\.json/g;' src/Ryujinx.Common/ReleaseInformation.cs shell: bash - name: Publish macOS Ryujinx.Ava diff --git a/Directory.Packages.props b/Directory.Packages.props index 4c573e157..3fa3bfe2c 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -3,40 +3,39 @@ true - - - - - - - + + + + + + + - - + + - - - - - + + + + - + - - - - + + + + - + - + @@ -45,10 +44,10 @@ - - + + - \ No newline at end of file + diff --git a/README.md b/README.md index b2f95cc1f..f2f3cb001 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,21 @@ -


- Ryujinx + Ryujinx
Ryujinx
(REE-YOU-JINX)
-

- Ryujinx is an open-source Nintendo Switch emulator, created by gdkchan, written in C#. - 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. Ryujinx is available on Github under the MIT license.
- + Ryujinx is an open-source Nintendo Switch emulator, created by gdkchan, written in C#. + 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. + Ryujinx is available on Github under the MIT license. +

+

-
- -
- ## Compatibility -As of April 2023, Ryujinx has been tested on approximately 4,050 titles; over 4,000 boot past menus and into gameplay, with roughly 3,400 of those being considered playable. -You can check out the compatibility list [here](https://github.com/Ryujinx/Ryujinx-Games-List/issues). Anyone is free to submit a new game test or update an existing game test entry; simply follow the new issue template and testing guidelines, or post as a reply to the applicable game issue. Use the search function to see if a game has been tested already! +As of October 2023, Ryujinx has been tested on approximately 4,200 titles; +over 4,150 boot past menus and into gameplay, with roughly 3,500 of those being considered playable. + +You can check out the compatibility list [here](https://github.com/Ryujinx/Ryujinx-Games-List/issues). + +Anyone is free to submit a new game test or update an existing game test entry; +simply follow the new issue template and testing guidelines, or post as a reply to the applicable game issue. +Use the search function to see if a game has been tested already! ## Usage -To run this emulator, your PC must be equipped with at least 8GiB of RAM; failing to meet this requirement may result in a poor gameplay experience or unexpected crashes. +To run this emulator, your PC must be equipped with at least 8GiB of RAM; +failing to meet this requirement may result in a poor gameplay experience or unexpected crashes. See our [Setup & Configuration Guide](https://github.com/Ryujinx/Ryujinx/wiki/Ryujinx-Setup-&-Configuration-Guide) on how to set up the emulator. -For our Local Wireless and LAN builds, see our [Multiplayer: Local Play/Local Wireless Guide +For our Local Wireless (LDN) builds, see our [Multiplayer: Local Play/Local Wireless Guide ](https://github.com/Ryujinx/Ryujinx/wiki/Multiplayer-(LDN-Local-Wireless)-Guide). Avalonia UI comes with translations for various languages. See [Crowdin](https://crwd.in/ryujinx) for more information. ## Latest build -These builds are compiled automatically for each commit on the master branch. While we strive to ensure optimal stability and performance prior to pushing an update, our automated builds **may be unstable or completely broken.** +These builds are compiled automatically for each commit on the master branch. +While we strive to ensure optimal stability and performance prior to pushing an update, our automated builds **may be unstable or completely broken**. If you want to see details on updates to the emulator, you can visit our [Changelog](https://github.com/Ryujinx/Ryujinx/wiki/Changelog). The latest automatic build for Windows, macOS, and Linux can be found on the [Official Website](https://ryujinx.org/download). +## Documentation + +If you are planning to contribute or just want to learn more about this project please read through our [documentation](docs/README.md). ## Building If you wish to build the emulator yourself, follow these steps: ### Step 1 -Install the X64 version of [.NET 8.0 (or higher) SDK](https://dotnet.microsoft.com/download/dotnet/8.0). + +Install the [.NET 8.0 (or higher) SDK](https://dotnet.microsoft.com/download/dotnet/8.0). +Make sure your SDK version is higher or equal to the required version specified in [global.json](global.json). ### Step 2 + Either use `git clone https://github.com/Ryujinx/Ryujinx` on the command line to clone the repository or use Code --> Download zip button to get the files. ### Step 3 -To build Ryujinx, open a command prompt inside the project directory. You can quickly access it on Windows by holding shift in File Explorer, then right clicking and selecting `Open command window here`. Then type the following command: -`dotnet build -c Release -o build` +To build Ryujinx, open a command prompt inside the project directory. +You can quickly access it on Windows by holding shift in File Explorer, then right clicking and selecting `Open command window here`. +Then type the following command: `dotnet build -c Release -o build` the built files will be found in the newly created build directory. -Ryujinx system files are stored in the `Ryujinx` folder. This folder is located in the user folder, which can be accessed by clicking `Open Ryujinx Folder` under the File menu in the GUI. - +Ryujinx system files are stored in the `Ryujinx` folder. +This folder is located in the user folder, which can be accessed by clicking `Open Ryujinx Folder` under the File menu in the GUI. ## Features - - **Audio** +- **Audio** - Audio output is entirely supported, audio input (microphone) isn't supported. We use C# wrappers for [OpenAL](https://openal-soft.org/), and [SDL2](https://www.libsdl.org/) & [libsoundio](http://libsound.io/) as fallbacks. + Audio output is entirely supported, audio input (microphone) isn't supported. + We use C# wrappers for [OpenAL](https://openal-soft.org/), and [SDL2](https://www.libsdl.org/) & [libsoundio](http://libsound.io/) as fallbacks. - **CPU** - 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, including partial 32-bit support. It translates the ARM code to a custom IR, performs a few optimizations, and turns that into x86 code. - There are three memory manager options available depending on the user's preference, leveraging both software-based (slower) and host-mapped modes (much faster). The fastest option (host, unchecked) is set by default. - Ryujinx also features an optional Profiled Persistent Translation Cache, which essentially caches translated functions so that they do not need to be translated every time the game loads. The net result is a significant reduction in load times (the amount of time between launching a game and arriving at the title screen) for nearly every game. NOTE: this feature is enabled by default in the Options menu > System tab. You must launch the game at least twice to the title screen or beyond before performance improvements are unlocked on the third launch! These improvements are permanent and do not require any extra launches going forward. + 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, including partial 32-bit support. + It translates the ARM code to a custom IR, performs a few optimizations, and turns that into x86 code. + There are three memory manager options available depending on the user's preference, leveraging both software-based (slower) and host-mapped modes (much faster). + The fastest option (host, unchecked) is set by default. + Ryujinx also features an optional Profiled Persistent Translation Cache, which essentially caches translated functions so that they do not need to be translated every time the game loads. + The net result is a significant reduction in load times (the amount of time between launching a game and arriving at the title screen) for nearly every game. + NOTE: This feature is enabled by default in the Options menu > System tab. + You must launch the game at least twice to the title screen or beyond before performance improvements are unlocked on the third launch! + These improvements are permanent and do not require any extra launches going forward. - **GPU** - 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. There are currently six graphics enhancements available to the end user in Ryujinx: Disk Shader Caching, Resolution Scaling, Anti-Aliasing, Scaling Filters (including FSR), Anisotropic Filtering and Aspect Ratio Adjustment. These enhancements can be adjusted or toggled as desired in the GUI. + 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. + There are currently six graphics enhancements available to the end user in Ryujinx: Disk Shader Caching, Resolution Scaling, Anti-Aliasing, Scaling Filters (including FSR), Anisotropic Filtering and Aspect Ratio Adjustment. + These enhancements can be adjusted or toggled as desired in the GUI. - **Input** - We currently have support for keyboard, mouse, touch input, JoyCon input support, and nearly all controllers. Motion controls are natively supported in most cases; for dual-JoyCon motion support, DS4Windows or BetterJoy are currently required. - In all scenarios, you can set up everything inside the input configuration menu. + We currently have support for keyboard, mouse, touch input, JoyCon input support, and nearly all controllers. + Motion controls are natively supported in most cases; for dual-JoyCon motion support, DS4Windows or BetterJoy are currently required. + In all scenarios, you can set up everything inside the input configuration menu. - **DLC & Modifications** - Ryujinx is able to manage add-on content/downloadable content through the GUI. Mods (romfs, exefs, and runtime mods such as cheats) are also supported; the GUI contains a shortcut to open the respective mods folder for a particular game. + Ryujinx is able to manage add-on content/downloadable content through the GUI. + Mods (romfs, exefs, and runtime mods such as cheats) are also supported; + the GUI contains a shortcut to open the respective mods folder for a particular game. - **Configuration** - The emulator has settings for enabling or disabling some logging, remapping controllers, and more. You can configure all of them through the graphical interface or manually through the config file, `Config.json`, found in the user folder which can be accessed by clicking `Open Ryujinx Folder` under the File menu in the GUI. - + The emulator has settings for enabling or disabling some logging, remapping controllers, and more. + You can configure all of them through the graphical interface or manually through the config file, `Config.json`, found in the user folder which can be accessed by clicking `Open Ryujinx Folder` under the File menu in the GUI. ## Contact -If you have contributions, suggestions, need emulator support or just want to get in touch with the team, join our [Discord server](https://discord.com/invite/Ryujinx). You may also review our [FAQ](https://github.com/Ryujinx/Ryujinx/wiki/Frequently-Asked-Questions). +If you have contributions, suggestions, need emulator support or just want to get in touch with the team, join our [Discord server](https://discord.com/invite/Ryujinx). +You may also review our [FAQ](https://github.com/Ryujinx/Ryujinx/wiki/Frequently-Asked-Questions). ## Donations @@ -134,9 +158,10 @@ All funds received through Patreon are considered a donation to support the proj ## License -This software is licensed under the terms of the
MIT license.
+This software is licensed under the terms of the [MIT license](LICENSE.txt). This project makes use of code authored by the libvpx project, licensed under BSD and the ffmpeg project, licensed under LGPLv3. See [LICENSE.txt](LICENSE.txt) and [THIRDPARTY.md](distribution/legal/THIRDPARTY.md) for more details. + ## Credits - [LibHac](https://github.com/Thealexbarney/LibHac) is used for our file-system. diff --git a/Ryujinx.sln b/Ryujinx.sln index bb196cabc..47a5c714c 100644 --- a/Ryujinx.sln +++ b/Ryujinx.sln @@ -71,7 +71,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Nvdec.FFmp EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Ava", "src\Ryujinx.Ava\Ryujinx.Ava.csproj", "{7C1B2721-13DA-4B62-B046-C626605ECCE6}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Ui.Common", "src\Ryujinx.Ui.Common\Ryujinx.Ui.Common.csproj", "{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.UI.Common", "src\Ryujinx.UI.Common\Ryujinx.UI.Common.csproj", "{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Generators", "src\Ryujinx.Horizon.Generators\Ryujinx.Horizon.Generators.csproj", "{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}" EndProject @@ -79,7 +79,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Vulkan", " EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spv.Generator", "src\Spv.Generator\Spv.Generator.csproj", "{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Ui.LocaleGenerator", "src\Ryujinx.Ui.LocaleGenerator\Ryujinx.Ui.LocaleGenerator.csproj", "{77D01AD9-2C98-478E-AE1D-8F7100738FB4}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.UI.LocaleGenerator", "src\Ryujinx.UI.LocaleGenerator\Ryujinx.UI.LocaleGenerator.csproj", "{77D01AD9-2C98-478E-AE1D-8F7100738FB4}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Common", "src\Ryujinx.Horizon.Common\Ryujinx.Horizon.Common.csproj", "{77F96ECE-4952-42DB-A528-DED25572A573}" EndProject diff --git a/distribution/linux/Ryujinx.desktop b/distribution/linux/Ryujinx.desktop index a4550d104..44f05bf3f 100644 --- a/distribution/linux/Ryujinx.desktop +++ b/distribution/linux/Ryujinx.desktop @@ -4,7 +4,7 @@ Name=Ryujinx Type=Application Icon=Ryujinx Exec=Ryujinx.sh %f -Comment=Plays Nintendo Switch applications +Comment=A Nintendo Switch Emulator GenericName=Nintendo Switch Emulator Terminal=false Categories=Game;Emulator; diff --git a/distribution/linux/Ryujinx.sh b/distribution/linux/Ryujinx.sh old mode 100644 new mode 100755 index f356cad01..6cce4d213 --- a/distribution/linux/Ryujinx.sh +++ b/distribution/linux/Ryujinx.sh @@ -1,14 +1,21 @@ #!/bin/sh SCRIPT_DIR=$(dirname "$(realpath "$0")") -RYUJINX_BIN="Ryujinx" + +if [ -f "$SCRIPT_DIR/Ryujinx.Headless.SDL2" ]; then + RYUJINX_BIN="Ryujinx.Headless.SDL2" +fi if [ -f "$SCRIPT_DIR/Ryujinx.Ava" ]; then RYUJINX_BIN="Ryujinx.Ava" fi -if [ -f "$SCRIPT_DIR/Ryujinx.Headless.SDL2" ]; then - RYUJINX_BIN="Ryujinx.Headless.SDL2" +if [ -f "$SCRIPT_DIR/Ryujinx" ]; then + RYUJINX_BIN="Ryujinx" +fi + +if [ -z "$RYUJINX_BIN" ]; then + exit 1 fi COMMAND="env DOTNET_EnableAlternateStackCheck=1" @@ -17,4 +24,4 @@ if command -v gamemoderun > /dev/null 2>&1; then COMMAND="$COMMAND gamemoderun" fi -$COMMAND "$SCRIPT_DIR/$RYUJINX_BIN" "$@" \ No newline at end of file +exec $COMMAND "$SCRIPT_DIR/$RYUJINX_BIN" "$@" diff --git a/distribution/macos/shortcut-launch-script.sh b/distribution/macos/shortcut-launch-script.sh new file mode 100644 index 000000000..784d780aa --- /dev/null +++ b/distribution/macos/shortcut-launch-script.sh @@ -0,0 +1,8 @@ +#!/bin/sh +launch_arch="$(uname -m)" +if [ "$(sysctl -in sysctl.proc_translated)" = "1" ] +then + launch_arch="arm64" +fi + +arch -$launch_arch {0} {1} diff --git a/src/ARMeilleure/Common/AddressTable.cs b/src/ARMeilleure/Common/AddressTable.cs index c9b0062b5..fcab3a202 100644 --- a/src/ARMeilleure/Common/AddressTable.cs +++ b/src/ARMeilleure/Common/AddressTable.cs @@ -9,7 +9,7 @@ namespace ARMeilleure.Common /// Represents a table of guest address to a value. /// /// Type of the value - unsafe class AddressTable : IDisposable where TEntry : unmanaged + public unsafe class AddressTable : IDisposable where TEntry : unmanaged { /// /// Represents a level in an . diff --git a/src/ARMeilleure/Decoders/OpCodeTable.cs b/src/ARMeilleure/Decoders/OpCodeTable.cs index 9e13bd9b5..edc004125 100644 --- a/src/ARMeilleure/Decoders/OpCodeTable.cs +++ b/src/ARMeilleure/Decoders/OpCodeTable.cs @@ -517,7 +517,10 @@ namespace ARMeilleure.Decoders SetA64("0x00111100>>>xxx100111xxxxxxxxxx", InstName.Sqrshrn_V, InstEmit.Sqrshrn_V, OpCodeSimdShImm.Create); SetA64("0111111100>>>xxx100011xxxxxxxxxx", InstName.Sqrshrun_S, InstEmit.Sqrshrun_S, OpCodeSimdShImm.Create); SetA64("0x10111100>>>xxx100011xxxxxxxxxx", InstName.Sqrshrun_V, InstEmit.Sqrshrun_V, OpCodeSimdShImm.Create); + SetA64("010111110>>>>xxx011101xxxxxxxxxx", InstName.Sqshl_Si, InstEmit.Sqshl_Si, OpCodeSimdShImm.Create); SetA64("0>001110<<1xxxxx010011xxxxxxxxxx", InstName.Sqshl_V, InstEmit.Sqshl_V, OpCodeSimdReg.Create); + SetA64("0000111100>>>xxx011101xxxxxxxxxx", InstName.Sqshl_Vi, InstEmit.Sqshl_Vi, OpCodeSimdShImm.Create); + SetA64("010011110>>>>xxx011101xxxxxxxxxx", InstName.Sqshl_Vi, InstEmit.Sqshl_Vi, OpCodeSimdShImm.Create); SetA64("0101111100>>>xxx100101xxxxxxxxxx", InstName.Sqshrn_S, InstEmit.Sqshrn_S, OpCodeSimdShImm.Create); SetA64("0x00111100>>>xxx100101xxxxxxxxxx", InstName.Sqshrn_V, InstEmit.Sqshrn_V, OpCodeSimdShImm.Create); SetA64("0111111100>>>xxx100001xxxxxxxxxx", InstName.Sqshrun_S, InstEmit.Sqshrun_S, OpCodeSimdShImm.Create); @@ -872,6 +875,7 @@ namespace ARMeilleure.Decoders SetVfp("<<<<11100x10xxxxxxxx101xx1x0xxxx", InstName.Vnmul, InstEmit32.Vnmul_S, OpCode32SimdRegS.Create, OpCode32SimdRegS.CreateT32); SetVfp("111111101x1110xxxxxx101x01x0xxxx", InstName.Vrint, InstEmit32.Vrint_RM, OpCode32SimdS.Create, OpCode32SimdS.CreateT32); SetVfp("<<<<11101x110110xxxx101x11x0xxxx", InstName.Vrint, InstEmit32.Vrint_Z, OpCode32SimdS.Create, OpCode32SimdS.CreateT32); + SetVfp("<<<<11101x110110xxxx101x01x0xxxx", InstName.Vrintr, InstEmit32.Vrintr_S, OpCode32SimdS.Create, OpCode32SimdS.CreateT32); SetVfp("<<<<11101x110111xxxx101x01x0xxxx", InstName.Vrintx, InstEmit32.Vrintx_S, OpCode32SimdS.Create, OpCode32SimdS.CreateT32); SetVfp("<<<<11101x110001xxxx101x11x0xxxx", InstName.Vsqrt, InstEmit32.Vsqrt_S, OpCode32SimdS.Create, OpCode32SimdS.CreateT32); SetVfp("111111100xxxxxxxxxxx101xx0x0xxxx", InstName.Vsel, InstEmit32.Vsel, OpCode32SimdSel.Create, OpCode32SimdSel.CreateT32); @@ -992,6 +996,7 @@ namespace ARMeilleure.Decoders SetAsimd("1111001x1x000xxxxxxx< context.Add(context.Add(op1, op2), op3), op.Opc != 1); + } + public static void Vpaddl(ArmEmitterContext context) { OpCode32Simd op = (OpCode32Simd)context.CurrOp; diff --git a/src/ARMeilleure/Instructions/InstEmitSimdCvt32.cs b/src/ARMeilleure/Instructions/InstEmitSimdCvt32.cs index 630e114c4..8eef6b14d 100644 --- a/src/ARMeilleure/Instructions/InstEmitSimdCvt32.cs +++ b/src/ARMeilleure/Instructions/InstEmitSimdCvt32.cs @@ -578,6 +578,22 @@ namespace ARMeilleure.Instructions } } + // VRINTR (floating-point). + public static void Vrintr_S(ArmEmitterContext context) + { + if (Optimizations.UseAdvSimd) + { + InstEmitSimdHelper32Arm64.EmitScalarUnaryOpF32(context, Intrinsic.Arm64FrintiS); + } + else + { + EmitScalarUnaryOpF32(context, (op1) => + { + return EmitRoundByRMode(context, op1); + }); + } + } + // VRINTZ (floating-point). public static void Vrint_Z(ArmEmitterContext context) { diff --git a/src/ARMeilleure/Instructions/InstEmitSimdHelper32.cs b/src/ARMeilleure/Instructions/InstEmitSimdHelper32.cs index c1c59b87b..2f021a1a1 100644 --- a/src/ARMeilleure/Instructions/InstEmitSimdHelper32.cs +++ b/src/ARMeilleure/Instructions/InstEmitSimdHelper32.cs @@ -673,6 +673,35 @@ namespace ARMeilleure.Instructions context.Copy(GetVecA32(op.Qd), res); } + public static void EmitVectorPairwiseTernaryLongOpI32(ArmEmitterContext context, Func3I emit, bool signed) + { + OpCode32Simd op = (OpCode32Simd)context.CurrOp; + + int elems = op.GetBytesCount() >> op.Size; + int pairs = elems >> 1; + + Operand res = GetVecA32(op.Qd); + + for (int index = 0; index < pairs; index++) + { + int pairIndex = index * 2; + Operand m1 = EmitVectorExtract32(context, op.Qm, op.Im + pairIndex, op.Size, signed); + Operand m2 = EmitVectorExtract32(context, op.Qm, op.Im + pairIndex + 1, op.Size, signed); + + if (op.Size == 2) + { + m1 = signed ? context.SignExtend32(OperandType.I64, m1) : context.ZeroExtend32(OperandType.I64, m1); + m2 = signed ? context.SignExtend32(OperandType.I64, m2) : context.ZeroExtend32(OperandType.I64, m2); + } + + Operand d1 = EmitVectorExtract32(context, op.Qd, op.Id + index, op.Size + 1, signed); + + res = EmitVectorInsert(context, res, emit(m1, m2, d1), op.Id + index, op.Size + 1); + } + + context.Copy(GetVecA32(op.Qd), res); + } + // Narrow public static void EmitVectorUnaryNarrowOp32(ArmEmitterContext context, Func1I emit, bool signed = false) diff --git a/src/ARMeilleure/Instructions/InstEmitSimdShift.cs b/src/ARMeilleure/Instructions/InstEmitSimdShift.cs index be0670645..94e912579 100644 --- a/src/ARMeilleure/Instructions/InstEmitSimdShift.cs +++ b/src/ARMeilleure/Instructions/InstEmitSimdShift.cs @@ -116,7 +116,7 @@ namespace ARMeilleure.Instructions } else if (shift >= eSize) { - if ((op.RegisterSize == RegisterSize.Simd64)) + if (op.RegisterSize == RegisterSize.Simd64) { Operand res = context.VectorZeroUpper64(GetVec(op.Rd)); @@ -359,6 +359,16 @@ namespace ARMeilleure.Instructions } } + public static void Sqshl_Si(ArmEmitterContext context) + { + EmitShlImmOp(context, signedDst: true, ShlRegFlags.Signed | ShlRegFlags.Scalar | ShlRegFlags.Saturating); + } + + public static void Sqshl_Vi(ArmEmitterContext context) + { + EmitShlImmOp(context, signedDst: true, ShlRegFlags.Signed | ShlRegFlags.Saturating); + } + public static void Sqshrn_S(ArmEmitterContext context) { if (Optimizations.UseAdvSimd) @@ -1593,6 +1603,99 @@ namespace ARMeilleure.Instructions Saturating = 1 << 3, } + private static void EmitShlImmOp(ArmEmitterContext context, bool signedDst, ShlRegFlags flags = ShlRegFlags.None) + { + bool scalar = flags.HasFlag(ShlRegFlags.Scalar); + bool signed = flags.HasFlag(ShlRegFlags.Signed); + bool saturating = flags.HasFlag(ShlRegFlags.Saturating); + + OpCodeSimdShImm op = (OpCodeSimdShImm)context.CurrOp; + + Operand res = context.VectorZero(); + + int elems = !scalar ? op.GetBytesCount() >> op.Size : 1; + + for (int index = 0; index < elems; index++) + { + Operand ne = EmitVectorExtract(context, op.Rn, index, op.Size, signed); + + Operand e = !saturating + ? EmitShlImm(context, ne, GetImmShl(op), op.Size) + : EmitShlImmSatQ(context, ne, GetImmShl(op), op.Size, signed, signedDst); + + res = EmitVectorInsert(context, res, e, index, op.Size); + } + + context.Copy(GetVec(op.Rd), res); + } + + private static Operand EmitShlImm(ArmEmitterContext context, Operand op, int shiftLsB, int size) + { + int eSize = 8 << size; + + Debug.Assert(op.Type == OperandType.I64); + Debug.Assert(eSize == 8 || eSize == 16 || eSize == 32 || eSize == 64); + + Operand res = context.AllocateLocal(OperandType.I64); + + if (shiftLsB >= eSize) + { + Operand shl = context.ShiftLeft(op, Const(shiftLsB)); + context.Copy(res, shl); + } + else + { + Operand zeroL = Const(0L); + context.Copy(res, zeroL); + } + + return res; + } + + private static Operand EmitShlImmSatQ(ArmEmitterContext context, Operand op, int shiftLsB, int size, bool signedSrc, bool signedDst) + { + int eSize = 8 << size; + + Debug.Assert(op.Type == OperandType.I64); + Debug.Assert(eSize == 8 || eSize == 16 || eSize == 32 || eSize == 64); + + Operand lblEnd = Label(); + + Operand res = context.Copy(context.AllocateLocal(OperandType.I64), op); + + if (shiftLsB >= eSize) + { + context.Copy(res, signedSrc + ? EmitSignedSignSatQ(context, op, size) + : EmitUnsignedSignSatQ(context, op, size)); + } + else + { + Operand shl = context.ShiftLeft(op, Const(shiftLsB)); + if (eSize == 64) + { + Operand sarOrShr = signedSrc + ? context.ShiftRightSI(shl, Const(shiftLsB)) + : context.ShiftRightUI(shl, Const(shiftLsB)); + context.Copy(res, shl); + context.BranchIf(lblEnd, sarOrShr, op, Comparison.Equal); + context.Copy(res, signedSrc + ? EmitSignedSignSatQ(context, op, size) + : EmitUnsignedSignSatQ(context, op, size)); + } + else + { + context.Copy(res, signedSrc + ? EmitSignedSrcSatQ(context, shl, size, signedDst) + : EmitUnsignedSrcSatQ(context, shl, size, signedDst)); + } + } + + context.MarkLabel(lblEnd); + + return res; + } + private static void EmitShlRegOp(ArmEmitterContext context, ShlRegFlags flags = ShlRegFlags.None) { bool scalar = flags.HasFlag(ShlRegFlags.Scalar); diff --git a/src/ARMeilleure/Instructions/InstName.cs b/src/ARMeilleure/Instructions/InstName.cs index 32ae38dad..457abbf49 100644 --- a/src/ARMeilleure/Instructions/InstName.cs +++ b/src/ARMeilleure/Instructions/InstName.cs @@ -384,7 +384,9 @@ namespace ARMeilleure.Instructions Sqrshrn_V, Sqrshrun_S, Sqrshrun_V, + Sqshl_Si, Sqshl_V, + Sqshl_Vi, Sqshrn_S, Sqshrn_V, Sqshrun_S, @@ -635,6 +637,7 @@ namespace ARMeilleure.Instructions Vorn, Vorr, Vpadd, + Vpadal, Vpaddl, Vpmax, Vpmin, @@ -654,6 +657,7 @@ namespace ARMeilleure.Instructions Vrintm, Vrintn, Vrintp, + Vrintr, Vrintx, Vrshr, Vrshrn, diff --git a/src/ARMeilleure/Memory/IJitMemoryAllocator.cs b/src/ARMeilleure/Memory/IJitMemoryAllocator.cs index 171bfd2f1..ff64bf13e 100644 --- a/src/ARMeilleure/Memory/IJitMemoryAllocator.cs +++ b/src/ARMeilleure/Memory/IJitMemoryAllocator.cs @@ -4,7 +4,5 @@ namespace ARMeilleure.Memory { IJitMemoryBlock Allocate(ulong size); IJitMemoryBlock Reserve(ulong size); - - ulong GetPageSize(); } } diff --git a/src/ARMeilleure/Memory/IJitMemoryBlock.cs b/src/ARMeilleure/Memory/IJitMemoryBlock.cs index cd49f314a..c103fe8d1 100644 --- a/src/ARMeilleure/Memory/IJitMemoryBlock.cs +++ b/src/ARMeilleure/Memory/IJitMemoryBlock.cs @@ -8,6 +8,7 @@ namespace ARMeilleure.Memory void Commit(ulong offset, ulong size); + void MapAsRw(ulong offset, ulong size); void MapAsRx(ulong offset, ulong size); void MapAsRwx(ulong offset, ulong size); } diff --git a/src/ARMeilleure/Memory/MemoryManagerType.cs b/src/ARMeilleure/Memory/MemoryManagerType.cs index 1e656ba27..b1cdbb069 100644 --- a/src/ARMeilleure/Memory/MemoryManagerType.cs +++ b/src/ARMeilleure/Memory/MemoryManagerType.cs @@ -31,7 +31,7 @@ namespace ARMeilleure.Memory HostMappedUnsafe, } - static class MemoryManagerTypeExtensions + public static class MemoryManagerTypeExtensions { public static bool IsHostMapped(this MemoryManagerType type) { diff --git a/src/ARMeilleure/Memory/ReservedRegion.cs b/src/ARMeilleure/Memory/ReservedRegion.cs index d0ffa8f1b..3870d4c84 100644 --- a/src/ARMeilleure/Memory/ReservedRegion.cs +++ b/src/ARMeilleure/Memory/ReservedRegion.cs @@ -2,7 +2,7 @@ using System; namespace ARMeilleure.Memory { - class ReservedRegion + public class ReservedRegion { public const int DefaultGranularity = 65536; // Mapping granularity in Windows. diff --git a/src/ARMeilleure/Native/JitSupportDarwin.cs b/src/ARMeilleure/Native/JitSupportDarwin.cs index ed347b9cf..339460397 100644 --- a/src/ARMeilleure/Native/JitSupportDarwin.cs +++ b/src/ARMeilleure/Native/JitSupportDarwin.cs @@ -5,7 +5,7 @@ using System.Runtime.Versioning; namespace ARMeilleure.Native { [SupportedOSPlatform("macos")] - internal static partial class JitSupportDarwin + static partial class JitSupportDarwin { [LibraryImport("libarmeilleure-jitsupport", EntryPoint = "armeilleure_jit_memcpy")] public static partial void Copy(IntPtr dst, IntPtr src, ulong n); diff --git a/src/ARMeilleure/Signal/NativeSignalHandler.cs b/src/ARMeilleure/Signal/NativeSignalHandlerGenerator.cs similarity index 62% rename from src/ARMeilleure/Signal/NativeSignalHandler.cs rename to src/ARMeilleure/Signal/NativeSignalHandlerGenerator.cs index 31ec16cb1..c5e708e16 100644 --- a/src/ARMeilleure/Signal/NativeSignalHandler.cs +++ b/src/ARMeilleure/Signal/NativeSignalHandlerGenerator.cs @@ -1,63 +1,14 @@ using ARMeilleure.IntermediateRepresentation; -using ARMeilleure.Memory; using ARMeilleure.Translation; -using ARMeilleure.Translation.Cache; using System; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using static ARMeilleure.IntermediateRepresentation.Operand.Factory; namespace ARMeilleure.Signal { - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct SignalHandlerRange + public static class NativeSignalHandlerGenerator { - public int IsActive; - public nuint RangeAddress; - public nuint RangeEndAddress; - public IntPtr ActionPointer; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - struct SignalHandlerConfig - { - /// - /// The byte offset of the faulting address in the SigInfo or ExceptionRecord struct. - /// - public int StructAddressOffset; - - /// - /// The byte offset of the write flag in the SigInfo or ExceptionRecord struct. - /// - public int StructWriteOffset; - - /// - /// The sigaction handler that was registered before this one. (unix only) - /// - public nuint UnixOldSigaction; - - /// - /// The type of the previous sigaction. True for the 3 argument variant. (unix only) - /// - public int UnixOldSigaction3Arg; - - public SignalHandlerRange Range0; - public SignalHandlerRange Range1; - public SignalHandlerRange Range2; - public SignalHandlerRange Range3; - public SignalHandlerRange Range4; - public SignalHandlerRange Range5; - public SignalHandlerRange Range6; - public SignalHandlerRange Range7; - } - - public static class NativeSignalHandler - { - private delegate void UnixExceptionHandler(int sig, IntPtr info, IntPtr ucontext); - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - private delegate int VectoredExceptionHandler(IntPtr exceptionInfo); - - private const int MaxTrackedRanges = 8; + public const int MaxTrackedRanges = 8; private const int StructAddressOffset = 0; private const int StructWriteOffset = 4; @@ -70,125 +21,10 @@ namespace ARMeilleure.Signal private const uint EXCEPTION_ACCESS_VIOLATION = 0xc0000005; - private static ulong _pageSize; - private static ulong _pageMask; - - private static readonly IntPtr _handlerConfig; - private static IntPtr _signalHandlerPtr; - private static IntPtr _signalHandlerHandle; - - private static readonly object _lock = new(); - private static bool _initialized; - - static NativeSignalHandler() + private static Operand EmitGenericRegionCheck(EmitterContext context, IntPtr signalStructPtr, Operand faultAddress, Operand isWrite, int rangeStructSize, ulong pageSize) { - _handlerConfig = Marshal.AllocHGlobal(Unsafe.SizeOf()); - ref SignalHandlerConfig config = ref GetConfigRef(); + ulong pageMask = pageSize - 1; - config = new SignalHandlerConfig(); - } - - public static void Initialize(IJitMemoryAllocator allocator) - { - JitCache.Initialize(allocator); - } - - public static void InitializeSignalHandler(ulong pageSize, Func customSignalHandlerFactory = null) - { - if (_initialized) - { - return; - } - - lock (_lock) - { - if (_initialized) - { - return; - } - - _pageSize = pageSize; - _pageMask = pageSize - 1; - - ref SignalHandlerConfig config = ref GetConfigRef(); - - if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS()) - { - _signalHandlerPtr = Marshal.GetFunctionPointerForDelegate(GenerateUnixSignalHandler(_handlerConfig)); - - if (customSignalHandlerFactory != null) - { - _signalHandlerPtr = customSignalHandlerFactory(UnixSignalHandlerRegistration.GetSegfaultExceptionHandler().sa_handler, _signalHandlerPtr); - } - - var old = UnixSignalHandlerRegistration.RegisterExceptionHandler(_signalHandlerPtr); - - config.UnixOldSigaction = (nuint)(ulong)old.sa_handler; - config.UnixOldSigaction3Arg = old.sa_flags & 4; - } - else - { - config.StructAddressOffset = 40; // ExceptionInformation1 - config.StructWriteOffset = 32; // ExceptionInformation0 - - _signalHandlerPtr = Marshal.GetFunctionPointerForDelegate(GenerateWindowsSignalHandler(_handlerConfig)); - - if (customSignalHandlerFactory != null) - { - _signalHandlerPtr = customSignalHandlerFactory(IntPtr.Zero, _signalHandlerPtr); - } - - _signalHandlerHandle = WindowsSignalHandlerRegistration.RegisterExceptionHandler(_signalHandlerPtr); - } - - _initialized = true; - } - } - - private static unsafe ref SignalHandlerConfig GetConfigRef() - { - return ref Unsafe.AsRef((void*)_handlerConfig); - } - - public static unsafe bool AddTrackedRegion(nuint address, nuint endAddress, IntPtr action) - { - var ranges = &((SignalHandlerConfig*)_handlerConfig)->Range0; - - for (int i = 0; i < MaxTrackedRanges; i++) - { - if (ranges[i].IsActive == 0) - { - ranges[i].RangeAddress = address; - ranges[i].RangeEndAddress = endAddress; - ranges[i].ActionPointer = action; - ranges[i].IsActive = 1; - - return true; - } - } - - return false; - } - - public static unsafe bool RemoveTrackedRegion(nuint address) - { - var ranges = &((SignalHandlerConfig*)_handlerConfig)->Range0; - - for (int i = 0; i < MaxTrackedRanges; i++) - { - if (ranges[i].IsActive == 1 && ranges[i].RangeAddress == address) - { - ranges[i].IsActive = 0; - - return true; - } - } - - return false; - } - - private static Operand EmitGenericRegionCheck(EmitterContext context, IntPtr signalStructPtr, Operand faultAddress, Operand isWrite) - { Operand inRegionLocal = context.AllocateLocal(OperandType.I32); context.Copy(inRegionLocal, Const(0)); @@ -196,7 +32,7 @@ namespace ARMeilleure.Signal for (int i = 0; i < MaxTrackedRanges; i++) { - ulong rangeBaseOffset = (ulong)(RangeOffset + i * Unsafe.SizeOf()); + ulong rangeBaseOffset = (ulong)(RangeOffset + i * rangeStructSize); Operand nextLabel = Label(); @@ -210,13 +46,12 @@ namespace ARMeilleure.Signal // Is the fault address within this tracked region? Operand inRange = context.BitwiseAnd( context.ICompare(faultAddress, rangeAddress, Comparison.GreaterOrEqualUI), - context.ICompare(faultAddress, rangeEndAddress, Comparison.LessUI) - ); + context.ICompare(faultAddress, rangeEndAddress, Comparison.LessUI)); // Only call tracking if in range. context.BranchIfFalse(nextLabel, inRange, BasicBlockFrequency.Cold); - Operand offset = context.BitwiseAnd(context.Subtract(faultAddress, rangeAddress), Const(~_pageMask)); + Operand offset = context.BitwiseAnd(context.Subtract(faultAddress, rangeAddress), Const(~pageMask)); // Call the tracking action, with the pointer's relative offset to the base address. Operand trackingActionPtr = context.Load(OperandType.I64, Const((ulong)signalStructPtr + rangeBaseOffset + 20)); @@ -227,7 +62,7 @@ namespace ARMeilleure.Signal // Tracking action should be non-null to call it, otherwise assume false return. context.BranchIfFalse(skipActionLabel, trackingActionPtr); - Operand result = context.Call(trackingActionPtr, OperandType.I32, offset, Const(_pageSize), isWrite); + Operand result = context.Call(trackingActionPtr, OperandType.I32, offset, Const(pageSize), isWrite); context.Copy(inRegionLocal, result); context.MarkLabel(skipActionLabel); @@ -269,8 +104,7 @@ namespace ARMeilleure.Signal Operand esr = context.Load(OperandType.I64, context.Add(ctxPtr, Const(EsrOffset))); return context.BitwiseAnd(esr, Const(0x40ul)); } - - if (RuntimeInformation.ProcessArchitecture == Architecture.X64) + else if (RuntimeInformation.ProcessArchitecture == Architecture.X64) { const ulong ErrOffset = 4; // __es.__err Operand err = context.Load(OperandType.I64, context.Add(ctxPtr, Const(ErrOffset))); @@ -310,8 +144,7 @@ namespace ARMeilleure.Signal Operand esr = context.Load(OperandType.I64, context.Add(auxPtr, Const(8ul))); return context.BitwiseAnd(esr, Const(0x40ul)); } - - if (RuntimeInformation.ProcessArchitecture == Architecture.X64) + else if (RuntimeInformation.ProcessArchitecture == Architecture.X64) { const int ErrOffset = 192; // uc_mcontext.gregs[REG_ERR] Operand err = context.Load(OperandType.I64, context.Add(ucontextPtr, Const(ErrOffset))); @@ -322,7 +155,7 @@ namespace ARMeilleure.Signal throw new PlatformNotSupportedException(); } - private static UnixExceptionHandler GenerateUnixSignalHandler(IntPtr signalStructPtr) + public static byte[] GenerateUnixSignalHandler(IntPtr signalStructPtr, int rangeStructSize, ulong pageSize) { EmitterContext context = new(); @@ -335,7 +168,7 @@ namespace ARMeilleure.Signal Operand isWrite = context.ICompareNotEqual(writeFlag, Const(0L)); // Normalize to 0/1. - Operand isInRegion = EmitGenericRegionCheck(context, signalStructPtr, faultAddress, isWrite); + Operand isInRegion = EmitGenericRegionCheck(context, signalStructPtr, faultAddress, isWrite, rangeStructSize, pageSize); Operand endLabel = Label(); @@ -367,10 +200,10 @@ namespace ARMeilleure.Signal OperandType[] argTypes = new OperandType[] { OperandType.I32, OperandType.I64, OperandType.I64 }; - return Compiler.Compile(cfg, argTypes, OperandType.None, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map(); + return Compiler.Compile(cfg, argTypes, OperandType.None, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Code; } - private static VectoredExceptionHandler GenerateWindowsSignalHandler(IntPtr signalStructPtr) + public static byte[] GenerateWindowsSignalHandler(IntPtr signalStructPtr, int rangeStructSize, ulong pageSize) { EmitterContext context = new(); @@ -399,7 +232,7 @@ namespace ARMeilleure.Signal Operand isWrite = context.ICompareNotEqual(writeFlag, Const(0L)); // Normalize to 0/1. - Operand isInRegion = EmitGenericRegionCheck(context, signalStructPtr, faultAddress, isWrite); + Operand isInRegion = EmitGenericRegionCheck(context, signalStructPtr, faultAddress, isWrite, rangeStructSize, pageSize); Operand endLabel = Label(); @@ -421,7 +254,7 @@ namespace ARMeilleure.Signal OperandType[] argTypes = new OperandType[] { OperandType.I64 }; - return Compiler.Compile(cfg, argTypes, OperandType.I32, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Map(); + return Compiler.Compile(cfg, argTypes, OperandType.I32, CompilerOptions.HighCq, RuntimeInformation.ProcessArchitecture).Code; } } } diff --git a/src/ARMeilleure/Signal/WindowsPartialUnmapHandler.cs b/src/ARMeilleure/Signal/WindowsPartialUnmapHandler.cs index 27a9ea83c..3bf6a4498 100644 --- a/src/ARMeilleure/Signal/WindowsPartialUnmapHandler.cs +++ b/src/ARMeilleure/Signal/WindowsPartialUnmapHandler.cs @@ -2,7 +2,7 @@ using ARMeilleure.IntermediateRepresentation; using ARMeilleure.Translation; using Ryujinx.Common.Memory.PartialUnmaps; using System; - +using System.Runtime.InteropServices; using static ARMeilleure.IntermediateRepresentation.Operand.Factory; namespace ARMeilleure.Signal @@ -10,8 +10,28 @@ namespace ARMeilleure.Signal /// /// Methods to handle signals caused by partial unmaps. See the structs for C# implementations of the methods. /// - internal static class WindowsPartialUnmapHandler + internal static partial class WindowsPartialUnmapHandler { + [LibraryImport("kernel32.dll", SetLastError = true, EntryPoint = "LoadLibraryA")] + private static partial IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string lpFileName); + + [LibraryImport("kernel32.dll", SetLastError = true)] + private static partial IntPtr GetProcAddress(IntPtr hModule, [MarshalAs(UnmanagedType.LPStr)] string procName); + + private static IntPtr _getCurrentThreadIdPtr; + + public static IntPtr GetCurrentThreadIdFunc() + { + if (_getCurrentThreadIdPtr == IntPtr.Zero) + { + IntPtr handle = LoadLibrary("kernel32.dll"); + + _getCurrentThreadIdPtr = GetProcAddress(handle, "GetCurrentThreadId"); + } + + return _getCurrentThreadIdPtr; + } + public static Operand EmitRetryFromAccessViolation(EmitterContext context) { IntPtr partialRemapStatePtr = PartialUnmapState.GlobalState; @@ -20,7 +40,7 @@ namespace ARMeilleure.Signal // Get the lock first. EmitNativeReaderLockAcquire(context, IntPtr.Add(partialRemapStatePtr, PartialUnmapState.PartialUnmapLockOffset)); - IntPtr getCurrentThreadId = WindowsSignalHandlerRegistration.GetCurrentThreadIdFunc(); + IntPtr getCurrentThreadId = GetCurrentThreadIdFunc(); Operand threadId = context.Call(Const((ulong)getCurrentThreadId), OperandType.I32); Operand threadIndex = EmitThreadLocalMapIntGetOrReserve(context, localCountsPtr, threadId, Const(0)); @@ -137,17 +157,6 @@ namespace ARMeilleure.Signal return context.Add(structsPtr, context.SignExtend32(OperandType.I64, offset)); } -#pragma warning disable IDE0051 // Remove unused private member - private static void EmitThreadLocalMapIntRelease(EmitterContext context, IntPtr threadLocalMapPtr, Operand threadId, Operand index) - { - Operand offset = context.Multiply(index, Const(sizeof(int))); - Operand idsPtr = Const((ulong)IntPtr.Add(threadLocalMapPtr, ThreadLocalMap.ThreadIdsOffset)); - Operand idPtr = context.Add(idsPtr, context.SignExtend32(OperandType.I64, offset)); - - context.CompareAndSwap(idPtr, threadId, Const(0)); - } -#pragma warning restore IDE0051 - private static void EmitAtomicAddI32(EmitterContext context, Operand ptr, Operand additive) { Operand loop = Label(); diff --git a/src/ARMeilleure/Signal/WindowsSignalHandlerRegistration.cs b/src/ARMeilleure/Signal/WindowsSignalHandlerRegistration.cs deleted file mode 100644 index 5444da0ca..000000000 --- a/src/ARMeilleure/Signal/WindowsSignalHandlerRegistration.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace ARMeilleure.Signal -{ - unsafe partial class WindowsSignalHandlerRegistration - { - [LibraryImport("kernel32.dll")] - private static partial IntPtr AddVectoredExceptionHandler(uint first, IntPtr handler); - - [LibraryImport("kernel32.dll")] - private static partial ulong RemoveVectoredExceptionHandler(IntPtr handle); - - [LibraryImport("kernel32.dll", SetLastError = true, EntryPoint = "LoadLibraryA")] - private static partial IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string lpFileName); - - [LibraryImport("kernel32.dll", SetLastError = true)] - private static partial IntPtr GetProcAddress(IntPtr hModule, [MarshalAs(UnmanagedType.LPStr)] string procName); - - private static IntPtr _getCurrentThreadIdPtr; - - public static IntPtr RegisterExceptionHandler(IntPtr action) - { - return AddVectoredExceptionHandler(1, action); - } - - public static bool RemoveExceptionHandler(IntPtr handle) - { - return RemoveVectoredExceptionHandler(handle) != 0; - } - - public static IntPtr GetCurrentThreadIdFunc() - { - if (_getCurrentThreadIdPtr == IntPtr.Zero) - { - IntPtr handle = LoadLibrary("kernel32.dll"); - - _getCurrentThreadIdPtr = GetProcAddress(handle, "GetCurrentThreadId"); - } - - return _getCurrentThreadIdPtr; - } - } -} diff --git a/src/ARMeilleure/Translation/IntervalTree.cs b/src/ARMeilleure/Translation/IntervalTree.cs index da29d6a68..a5f9b5d5e 100644 --- a/src/ARMeilleure/Translation/IntervalTree.cs +++ b/src/ARMeilleure/Translation/IntervalTree.cs @@ -8,7 +8,7 @@ namespace ARMeilleure.Translation /// /// Key /// Value - class IntervalTree where TK : IComparable + public class IntervalTree where TK : IComparable { private const int ArrayGrowthSize = 32; diff --git a/src/ARMeilleure/Translation/Translator.cs b/src/ARMeilleure/Translation/Translator.cs index dc18038ba..014b12035 100644 --- a/src/ARMeilleure/Translation/Translator.cs +++ b/src/ARMeilleure/Translation/Translator.cs @@ -57,9 +57,6 @@ namespace ARMeilleure.Translation private Thread[] _backgroundTranslationThreads; private volatile int _threadCount; - // FIXME: Remove this once the init logic of the emulator will be redone. - public static readonly ManualResetEvent IsReadyForTranslation = new(false); - public Translator(IJitMemoryAllocator allocator, IMemoryManager memory, bool for64Bits) { _allocator = allocator; @@ -76,14 +73,9 @@ namespace ARMeilleure.Translation CountTable = new EntryTable(); Functions = new TranslatorCache(); FunctionTable = new AddressTable(for64Bits ? _levels64Bit : _levels32Bit); - Stubs = new TranslatorStubs(this); + Stubs = new TranslatorStubs(FunctionTable); FunctionTable.Fill = (ulong)Stubs.SlowDispatchStub; - - if (memory.Type.IsHostMapped()) - { - NativeSignalHandler.InitializeSignalHandler(allocator.GetPageSize()); - } } public IPtcLoadState LoadDiskCache(string titleIdText, string displayVersion, bool enabled) @@ -105,8 +97,6 @@ namespace ARMeilleure.Translation { if (Interlocked.Increment(ref _threadCount) == 1) { - IsReadyForTranslation.WaitOne(); - if (_ptc.State == PtcState.Enabled) { Debug.Assert(Functions.Count == 0); diff --git a/src/ARMeilleure/Translation/TranslatorStubs.cs b/src/ARMeilleure/Translation/TranslatorStubs.cs index bbe48c165..d80823a8b 100644 --- a/src/ARMeilleure/Translation/TranslatorStubs.cs +++ b/src/ARMeilleure/Translation/TranslatorStubs.cs @@ -1,3 +1,4 @@ +using ARMeilleure.Common; using ARMeilleure.Instructions; using ARMeilleure.IntermediateRepresentation; using ARMeilleure.State; @@ -14,11 +15,11 @@ namespace ARMeilleure.Translation /// class TranslatorStubs : IDisposable { - private static readonly Lazy _slowDispatchStub = new(GenerateSlowDispatchStub, isThreadSafe: true); + private readonly Lazy _slowDispatchStub; private bool _disposed; - private readonly Translator _translator; + private readonly AddressTable _functionTable; private readonly Lazy _dispatchStub; private readonly Lazy _dispatchLoop; private readonly Lazy _contextWrapper; @@ -83,13 +84,14 @@ namespace ARMeilleure.Translation /// Initializes a new instance of the class with the specified /// instance. /// - /// instance to use + /// Function table used to store pointers to the functions that the guest code will call /// is null - public TranslatorStubs(Translator translator) + public TranslatorStubs(AddressTable functionTable) { - ArgumentNullException.ThrowIfNull(translator); + ArgumentNullException.ThrowIfNull(functionTable); - _translator = translator; + _functionTable = functionTable; + _slowDispatchStub = new(GenerateSlowDispatchStub, isThreadSafe: true); _dispatchStub = new(GenerateDispatchStub, isThreadSafe: true); _dispatchLoop = new(GenerateDispatchLoop, isThreadSafe: true); _contextWrapper = new(GenerateContextWrapper, isThreadSafe: true); @@ -151,15 +153,15 @@ namespace ARMeilleure.Translation context.Add(nativeContext, Const((ulong)NativeContext.GetDispatchAddressOffset()))); // Check if guest address is within range of the AddressTable. - Operand masked = context.BitwiseAnd(guestAddress, Const(~_translator.FunctionTable.Mask)); + Operand masked = context.BitwiseAnd(guestAddress, Const(~_functionTable.Mask)); context.BranchIfTrue(lblFallback, masked); Operand index = default; - Operand page = Const((long)_translator.FunctionTable.Base); + Operand page = Const((long)_functionTable.Base); - for (int i = 0; i < _translator.FunctionTable.Levels.Length; i++) + for (int i = 0; i < _functionTable.Levels.Length; i++) { - ref var level = ref _translator.FunctionTable.Levels[i]; + ref var level = ref _functionTable.Levels[i]; // level.Mask is not used directly because it is more often bigger than 32-bits, so it will not // be encoded as an immediate on x86's bitwise and operation. @@ -167,7 +169,7 @@ namespace ARMeilleure.Translation index = context.BitwiseAnd(context.ShiftRightUI(guestAddress, Const(level.Index)), mask); - if (i < _translator.FunctionTable.Levels.Length - 1) + if (i < _functionTable.Levels.Length - 1) { page = context.Load(OperandType.I64, context.Add(page, context.ShiftLeft(index, Const(3)))); context.BranchIfFalse(lblFallback, page); @@ -196,7 +198,7 @@ namespace ARMeilleure.Translation /// Generates a . /// /// Generated - private static IntPtr GenerateSlowDispatchStub() + private IntPtr GenerateSlowDispatchStub() { var context = new EmitterContext(); @@ -205,8 +207,7 @@ namespace ARMeilleure.Translation Operand guestAddress = context.Load(OperandType.I64, context.Add(nativeContext, Const((ulong)NativeContext.GetDispatchAddressOffset()))); - MethodInfo getFuncAddress = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress)); - Operand hostAddress = context.Call(getFuncAddress, guestAddress); + Operand hostAddress = context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress)), guestAddress); context.Tailcall(hostAddress, nativeContext); var cfg = context.GetControlFlowGraph(); diff --git a/src/Ryujinx.Audio.Backends.SoundIo/Ryujinx.Audio.Backends.SoundIo.csproj b/src/Ryujinx.Audio.Backends.SoundIo/Ryujinx.Audio.Backends.SoundIo.csproj index 1d92d9d2e..5c9423463 100644 --- a/src/Ryujinx.Audio.Backends.SoundIo/Ryujinx.Audio.Backends.SoundIo.csproj +++ b/src/Ryujinx.Audio.Backends.SoundIo/Ryujinx.Audio.Backends.SoundIo.csproj @@ -11,15 +11,15 @@ - + PreserveNewest libsoundio.dll - + PreserveNewest libsoundio.dylib - + PreserveNewest libsoundio.so diff --git a/src/Ryujinx.Audio/Backends/CompatLayer/Downmixing.cs b/src/Ryujinx.Audio/Backends/CompatLayer/Downmixing.cs index ffd427a5e..7a5ea0deb 100644 --- a/src/Ryujinx.Audio/Backends/CompatLayer/Downmixing.cs +++ b/src/Ryujinx.Audio/Backends/CompatLayer/Downmixing.cs @@ -31,7 +31,7 @@ namespace Ryujinx.Audio.Backends.CompatLayer private const int Minus6dBInQ15 = (int)(0.501f * RawQ15One); private const int Minus12dBInQ15 = (int)(0.251f * RawQ15One); - private static readonly int[] _defaultSurroundToStereoCoefficients = new int[4] + private static readonly long[] _defaultSurroundToStereoCoefficients = new long[4] { RawQ15One, Minus3dBInQ15, @@ -39,7 +39,7 @@ namespace Ryujinx.Audio.Backends.CompatLayer Minus3dBInQ15, }; - private static readonly int[] _defaultStereoToMonoCoefficients = new int[2] + private static readonly long[] _defaultStereoToMonoCoefficients = new long[2] { Minus6dBInQ15, Minus6dBInQ15, @@ -62,19 +62,23 @@ namespace Ryujinx.Audio.Backends.CompatLayer } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static short DownMixStereoToMono(ReadOnlySpan coefficients, short left, short right) + private static short DownMixStereoToMono(ReadOnlySpan coefficients, short left, short right) { - return (short)((left * coefficients[0] + right * coefficients[1]) >> Q15Bits); + return (short)Math.Clamp((left * coefficients[0] + right * coefficients[1]) >> Q15Bits, short.MinValue, short.MaxValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static short DownMixSurroundToStereo(ReadOnlySpan coefficients, short back, short lfe, short center, short front) + private static short DownMixSurroundToStereo(ReadOnlySpan coefficients, short back, short lfe, short center, short front) { - return (short)((coefficients[3] * back + coefficients[2] * lfe + coefficients[1] * center + coefficients[0] * front + RawQ15HalfOne) >> Q15Bits); + return (short)Math.Clamp( + (coefficients[3] * back + + coefficients[2] * lfe + + coefficients[1] * center + + coefficients[0] * front + RawQ15HalfOne) >> Q15Bits, short.MinValue, short.MaxValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static short[] DownMixSurroundToStereo(ReadOnlySpan coefficients, ReadOnlySpan data) + private static short[] DownMixSurroundToStereo(ReadOnlySpan coefficients, ReadOnlySpan data) { int samplePerChannelCount = data.Length / SurroundChannelCount; @@ -94,7 +98,7 @@ namespace Ryujinx.Audio.Backends.CompatLayer } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static short[] DownMixStereoToMono(ReadOnlySpan coefficients, ReadOnlySpan data) + private static short[] DownMixStereoToMono(ReadOnlySpan coefficients, ReadOnlySpan data) { int samplePerChannelCount = data.Length / StereoChannelCount; diff --git a/src/Ryujinx.Ava/App.axaml.cs b/src/Ryujinx.Ava/App.axaml.cs index c1a3ab3e2..387a6dc14 100644 --- a/src/Ryujinx.Ava/App.axaml.cs +++ b/src/Ryujinx.Ava/App.axaml.cs @@ -8,11 +8,10 @@ using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Windows; using Ryujinx.Common; using Ryujinx.Common.Logging; -using Ryujinx.Ui.Common.Configuration; -using Ryujinx.Ui.Common.Helper; +using Ryujinx.UI.Common.Configuration; +using Ryujinx.UI.Common.Helper; using System; using System.Diagnostics; -using System.IO; namespace Ryujinx.Ava { @@ -43,9 +42,9 @@ namespace Ryujinx.Ava { ApplyConfiguredTheme(); - ConfigurationState.Instance.Ui.BaseStyle.Event += ThemeChanged_Event; - ConfigurationState.Instance.Ui.CustomThemePath.Event += ThemeChanged_Event; - ConfigurationState.Instance.Ui.EnableCustomTheme.Event += CustomThemeChanged_Event; + ConfigurationState.Instance.UI.BaseStyle.Event += ThemeChanged_Event; + ConfigurationState.Instance.UI.CustomThemePath.Event += ThemeChanged_Event; + ConfigurationState.Instance.UI.EnableCustomTheme.Event += CustomThemeChanged_Event; } } @@ -89,15 +88,13 @@ namespace Ryujinx.Ava { try { - string baseStyle = ConfigurationState.Instance.Ui.BaseStyle; - string themePath = ConfigurationState.Instance.Ui.CustomThemePath; - bool enableCustomTheme = ConfigurationState.Instance.Ui.EnableCustomTheme; + string baseStyle = ConfigurationState.Instance.UI.BaseStyle; if (string.IsNullOrWhiteSpace(baseStyle)) { - ConfigurationState.Instance.Ui.BaseStyle.Value = "Dark"; + ConfigurationState.Instance.UI.BaseStyle.Value = "Dark"; - baseStyle = ConfigurationState.Instance.Ui.BaseStyle; + baseStyle = ConfigurationState.Instance.UI.BaseStyle; } RequestedThemeVariant = baseStyle switch @@ -106,24 +103,6 @@ namespace Ryujinx.Ava "Dark" => ThemeVariant.Dark, _ => ThemeVariant.Default, }; - - if (enableCustomTheme) - { - if (!string.IsNullOrWhiteSpace(themePath)) - { - try - { - var themeContent = File.ReadAllText(themePath); - var customStyle = AvaloniaRuntimeXamlLoader.Parse(themeContent); - - Styles.Add(customStyle); - } - catch (Exception ex) - { - Logger.Error?.Print(LogClass.Application, $"Failed to Apply Custom Theme. Error: {ex.Message}"); - } - } - } } catch (Exception) { diff --git a/src/Ryujinx.Ava/AppHost.cs b/src/Ryujinx.Ava/AppHost.cs index 2fd9ce00d..04cec9579 100644 --- a/src/Ryujinx.Ava/AppHost.cs +++ b/src/Ryujinx.Ava/AppHost.cs @@ -1,4 +1,3 @@ -using ARMeilleure.Translation; using Avalonia; using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; @@ -35,10 +34,10 @@ using Ryujinx.HLE.HOS.Services.Account.Acc; using Ryujinx.HLE.HOS.SystemState; using Ryujinx.Input; using Ryujinx.Input.HLE; -using Ryujinx.Ui.App.Common; -using Ryujinx.Ui.Common; -using Ryujinx.Ui.Common.Configuration; -using Ryujinx.Ui.Common.Helper; +using Ryujinx.UI.App.Common; +using Ryujinx.UI.Common; +using Ryujinx.UI.Common.Configuration; +using Ryujinx.UI.Common.Helper; using Silk.NET.Vulkan; using SixLabors.ImageSharp; using SixLabors.ImageSharp.Formats.Png; @@ -916,7 +915,6 @@ namespace Ryujinx.Ava { Device.Gpu.SetGpuThread(); Device.Gpu.InitializeShaderCache(_gpuCancellationTokenSource.Token); - Translator.IsReadyForTranslation.Set(); _renderer.Window.ChangeVSyncMode(Device.EnableDeviceVsync); @@ -980,7 +978,7 @@ namespace Ryujinx.Ava ConfigurationState.Instance.Graphics.AspectRatio.Value.ToText(), LocaleManager.Instance[LocaleKeys.Game] + $": {Device.Statistics.GetGameFrameRate():00.00} FPS ({Device.Statistics.GetGameFrameTime():00.00} ms)", $"FIFO: {Device.Statistics.GetFifoPercent():00.00} %", - $"GPU: {_renderer.GetHardwareInfo().GpuVendor}")); + $"GPU: {_renderer.GetHardwareInfo().GpuDriver}")); } public async Task ShowExitPrompt() @@ -1072,7 +1070,7 @@ namespace Ryujinx.Ava case KeyboardHotkeyState.Screenshot: ScreenshotRequested = true; break; - case KeyboardHotkeyState.ShowUi: + case KeyboardHotkeyState.ShowUI: _viewModel.ShowMenuAndStatusBar = !_viewModel.ShowMenuAndStatusBar; break; case KeyboardHotkeyState.Pause: @@ -1162,9 +1160,9 @@ namespace Ryujinx.Ava { state = KeyboardHotkeyState.Screenshot; } - else if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.ShowUi)) + else if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.ShowUI)) { - state = KeyboardHotkeyState.ShowUi; + state = KeyboardHotkeyState.ShowUI; } else if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Pause)) { diff --git a/src/Ryujinx.Ava/Assets/Locales/en_US.json b/src/Ryujinx.Ava/Assets/Locales/en_US.json index 75327185a..ee8b38832 100644 --- a/src/Ryujinx.Ava/Assets/Locales/en_US.json +++ b/src/Ryujinx.Ava/Assets/Locales/en_US.json @@ -54,8 +54,6 @@ "GameListContextMenuManageTitleUpdatesToolTip": "Opens the Title Update management window", "GameListContextMenuManageDlc": "Manage DLC", "GameListContextMenuManageDlcToolTip": "Opens the DLC management window", - "GameListContextMenuOpenModsDirectory": "Open Mods Directory", - "GameListContextMenuOpenModsDirectoryToolTip": "Opens the directory which contains Application's Mods", "GameListContextMenuCacheManagement": "Cache Management", "GameListContextMenuCacheManagementPurgePptc": "Queue PPTC Rebuild", "GameListContextMenuCacheManagementPurgePptcToolTip": "Trigger PPTC to rebuild at boot time on the next game launch", @@ -74,6 +72,11 @@ "GameListContextMenuExtractDataLogoToolTip": "Extract the Logo section from Application's current config (including updates)", "GameListContextMenuCreateShortcut": "Create Application Shortcut", "GameListContextMenuCreateShortcutToolTip": "Create a Desktop Shortcut that launches the selected Application", + "GameListContextMenuCreateShortcutToolTipMacOS": "Create a shortcut in macOS's Applications folder that launches the selected Application", + "GameListContextMenuOpenModsDirectory": "Open Mods Directory", + "GameListContextMenuOpenModsDirectoryToolTip": "Opens the directory which contains Application's Mods", + "GameListContextMenuOpenSdModsDirectory": "Open Atmosphere Mods Directory", + "GameListContextMenuOpenSdModsDirectoryToolTip": "Opens the alternative SD card Atmosphere directory which contains Application's Mods. Useful for mods that are packaged for real hardware.", "StatusBarGamesLoaded": "{0}/{1} Games Loaded", "StatusBarSystemVersion": "System Version: {0}", "LinuxVmMaxMapCountDialogTitle": "Low limit for memory mappings detected", @@ -294,13 +297,9 @@ "GameListContextMenuRunApplication": "Run Application", "GameListContextMenuToggleFavorite": "Toggle Favorite", "GameListContextMenuToggleFavoriteToolTip": "Toggle Favorite status of Game", - "SettingsTabGeneralTheme": "Theme", - "SettingsTabGeneralThemeCustomTheme": "Custom Theme Path", - "SettingsTabGeneralThemeBaseStyle": "Base Style", - "SettingsTabGeneralThemeBaseStyleDark": "Dark", - "SettingsTabGeneralThemeBaseStyleLight": "Light", - "SettingsTabGeneralThemeEnableCustomTheme": "Enable Custom Theme", - "ButtonBrowse": "Browse", + "SettingsTabGeneralTheme": "Theme:", + "SettingsTabGeneralThemeDark": "Dark", + "SettingsTabGeneralThemeLight": "Light", "ControllerSettingsConfigureGeneral": "Configure", "ControllerSettingsRumble": "Rumble", "ControllerSettingsRumbleStrongMultiplier": "Strong Rumble Multiplier", @@ -387,7 +386,10 @@ "DialogUserProfileUnsavedChangesSubMessage": "Do you want to discard your changes?", "DialogControllerSettingsModifiedConfirmMessage": "The current controller settings has been updated.", "DialogControllerSettingsModifiedConfirmSubMessage": "Do you want to save?", - "DialogLoadNcaErrorMessage": "{0}. Errored File: {1}", + "DialogLoadFileErrorMessage": "{0}. Errored File: {1}", + "DialogModAlreadyExistsMessage": "Mod already exists", + "DialogModInvalidMessage": "The specified directory does not contain a mod!", + "DialogModDeleteNoParentMessage": "Failed to Delete: Could not find the parent directory for mod \"{0}\"!", "DialogDlcNoDlcErrorMessage": "The specified file does not contain a DLC for the selected title!", "DialogPerformanceCheckLoggingEnabledMessage": "You have trace logging enabled, which is designed to be used by developers only.", "DialogPerformanceCheckLoggingEnabledConfirmMessage": "For optimal performance, it's recommended to disable trace logging. Would you like to disable trace logging now?", @@ -398,6 +400,8 @@ "DialogUpdateAddUpdateErrorMessage": "The specified file does not contain an update for the selected title!", "DialogSettingsBackendThreadingWarningTitle": "Warning - Backend Threading", "DialogSettingsBackendThreadingWarningMessage": "Ryujinx must be restarted after changing this option for it to apply fully. Depending on your platform, you may need to manually disable your driver's own multithreading when using Ryujinx's.", + "DialogModManagerDeletionWarningMessage": "You are about to delete the mod: {0}\n\nAre you sure you want to proceed?", + "DialogModManagerDeletionAllWarningMessage": "You are about to delete all mods for this title.\n\nAre you sure you want to proceed?", "SettingsTabGraphicsFeaturesOptions": "Features", "SettingsTabGraphicsBackendMultithreading": "Graphics Backend Multithreading:", "CommonAuto": "Auto", @@ -432,6 +436,7 @@ "DlcManagerRemoveAllButton": "Remove All", "DlcManagerEnableAllButton": "Enable All", "DlcManagerDisableAllButton": "Disable All", + "ModManagerDeleteAllButton": "Delete All", "MenuBarOptionsChangeLanguage": "Change Language", "MenuBarShowFileTypes": "Show File Types", "CommonSort": "Sort", @@ -506,6 +511,8 @@ "EnableInternetAccessTooltip": "Allows the emulated application to connect to the Internet.\n\nGames with a LAN mode can connect to each other when this is enabled and the systems are connected to the same access point. This includes real consoles as well.\n\nDoes NOT allow connecting to Nintendo servers. May cause crashing in certain games that try to connect to the Internet.\n\nLeave OFF if unsure.", "GameListContextMenuManageCheatToolTip": "Manage Cheats", "GameListContextMenuManageCheat": "Manage Cheats", + "GameListContextMenuManageModToolTip": "Manage Mods", + "GameListContextMenuManageMod": "Manage Mods", "ControllerSettingsStickRange": "Range:", "DialogStopEmulationTitle": "Ryujinx - Stop Emulation", "DialogStopEmulationMessage": "Are you sure you want to stop emulation?", @@ -517,8 +524,6 @@ "SettingsTabCpuMemory": "CPU Mode", "DialogUpdaterFlatpakNotSupportedMessage": "Please update Ryujinx via FlatHub.", "UpdaterDisabledWarningTitle": "Updater Disabled!", - "GameListContextMenuOpenSdModsDirectory": "Open Atmosphere Mods Directory", - "GameListContextMenuOpenSdModsDirectoryToolTip": "Opens the alternative SD card Atmosphere directory which contains Application's Mods. Useful for mods that are packaged for real hardware.", "ControllerSettingsRotate90": "Rotate 90° Clockwise", "IconSize": "Icon Size", "IconSizeTooltip": "Change the size of game icons", @@ -590,12 +595,14 @@ "Writable": "Writable", "SelectDlcDialogTitle": "Select DLC files", "SelectUpdateDialogTitle": "Select update files", + "SelectModDialogTitle": "Select mod directory", "UserProfileWindowTitle": "User Profiles Manager", "DlcWindowTitle": "Manage Downloadable Content for {0} ({1})", "UpdateWindowTitle": "Title Update Manager", "CheatWindowHeading": "Manage Cheats for {0} ({1})", "BuildId": "Build ID:", "DlcWindowHeading": "{0} Downloadable Content(s)", + "ModWindowHeading": "{0} Mod(s)", "UserProfilesEditProfile": "Edit Selected", "Cancel": "Cancel", "Save": "Save", diff --git a/src/Ryujinx.Ava/Common/ApplicationHelper.cs b/src/Ryujinx.Ava/Common/ApplicationHelper.cs index 91ca8f4d5..622a6a024 100644 --- a/src/Ryujinx.Ava/Common/ApplicationHelper.cs +++ b/src/Ryujinx.Ava/Common/ApplicationHelper.cs @@ -18,8 +18,8 @@ using Ryujinx.Ava.UI.Helpers; using Ryujinx.Common.Logging; using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.HOS.Services.Account.Acc; -using Ryujinx.Ui.App.Common; -using Ryujinx.Ui.Common.Helper; +using Ryujinx.UI.App.Common; +using Ryujinx.UI.Common.Helper; using System; using System.Buffers; using System.IO; diff --git a/src/Ryujinx.Ava/Common/KeyboardHotkeyState.cs b/src/Ryujinx.Ava/Common/KeyboardHotkeyState.cs index b24016404..6e4920988 100644 --- a/src/Ryujinx.Ava/Common/KeyboardHotkeyState.cs +++ b/src/Ryujinx.Ava/Common/KeyboardHotkeyState.cs @@ -5,7 +5,7 @@ namespace Ryujinx.Ava.Common None, ToggleVSync, Screenshot, - ShowUi, + ShowUI, Pause, ToggleMute, ResScaleUp, diff --git a/src/Ryujinx.Ava/Common/Locale/LocaleManager.cs b/src/Ryujinx.Ava/Common/Locale/LocaleManager.cs index 0e613838d..b2f3e7ab9 100644 --- a/src/Ryujinx.Ava/Common/Locale/LocaleManager.cs +++ b/src/Ryujinx.Ava/Common/Locale/LocaleManager.cs @@ -1,7 +1,7 @@ using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Common; using Ryujinx.Common.Utilities; -using Ryujinx.Ui.Common.Configuration; +using Ryujinx.UI.Common.Configuration; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -38,9 +38,9 @@ namespace Ryujinx.Ava.Common.Locale // If the view is loaded with the UI Previewer detached, then override it with the saved one or default. if (Program.PreviewerDetached) { - if (!string.IsNullOrEmpty(ConfigurationState.Instance.Ui.LanguageCode.Value)) + if (!string.IsNullOrEmpty(ConfigurationState.Instance.UI.LanguageCode.Value)) { - localeLanguageCode = ConfigurationState.Instance.Ui.LanguageCode.Value; + localeLanguageCode = ConfigurationState.Instance.UI.LanguageCode.Value; } else { diff --git a/src/Ryujinx.Ava/Modules/Updater/Updater.cs b/src/Ryujinx.Ava/Modules/Updater/Updater.cs index af7608d34..bd211fa5b 100644 --- a/src/Ryujinx.Ava/Modules/Updater/Updater.cs +++ b/src/Ryujinx.Ava/Modules/Updater/Updater.cs @@ -10,8 +10,8 @@ using Ryujinx.Ava.UI.Helpers; using Ryujinx.Common; using Ryujinx.Common.Logging; using Ryujinx.Common.Utilities; -using Ryujinx.Ui.Common.Helper; -using Ryujinx.Ui.Common.Models.Github; +using Ryujinx.UI.Common.Helper; +using Ryujinx.UI.Common.Models.Github; using System; using System.Collections.Generic; using System.Diagnostics; @@ -665,7 +665,7 @@ namespace Ryujinx.Modules return false; } - if (Program.Version.Contains("dirty") || !ReleaseInformation.IsValid()) + if (Program.Version.Contains("dirty") || !ReleaseInformation.IsValid) { if (showWarnings) { @@ -683,7 +683,7 @@ namespace Ryujinx.Modules #else if (showWarnings) { - if (ReleaseInformation.IsFlatHubBuild()) + if (ReleaseInformation.IsFlatHubBuild) { Dispatcher.UIThread.InvokeAsync(() => ContentDialogHelper.CreateWarningDialog( diff --git a/src/Ryujinx.Ava/Program.cs b/src/Ryujinx.Ava/Program.cs index cc062a256..7751bb520 100644 --- a/src/Ryujinx.Ava/Program.cs +++ b/src/Ryujinx.Ava/Program.cs @@ -9,10 +9,10 @@ using Ryujinx.Common.Logging; using Ryujinx.Common.SystemInterop; using Ryujinx.Modules; using Ryujinx.SDL2.Common; -using Ryujinx.Ui.Common; -using Ryujinx.Ui.Common.Configuration; -using Ryujinx.Ui.Common.Helper; -using Ryujinx.Ui.Common.SystemInfo; +using Ryujinx.UI.Common; +using Ryujinx.UI.Common.Configuration; +using Ryujinx.UI.Common.Helper; +using Ryujinx.UI.Common.SystemInfo; using System; using System.IO; using System.Runtime.InteropServices; @@ -35,7 +35,7 @@ namespace Ryujinx.Ava public static void Main(string[] args) { - Version = ReleaseInformation.GetVersion(); + Version = ReleaseInformation.Version; if (OperatingSystem.IsWindows() && !OperatingSystem.IsWindowsVersionAtLeast(10, 0, 17134)) { @@ -125,8 +125,8 @@ namespace Ryujinx.Ava public static void ReloadConfig() { - string localConfigurationPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json"); - string appDataConfigurationPath = Path.Combine(AppDataManager.BaseDirPath, "Config.json"); + string localConfigurationPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ReleaseInformation.ConfigName); + string appDataConfigurationPath = Path.Combine(AppDataManager.BaseDirPath, ReleaseInformation.ConfigName); // Now load the configuration as the other subsystems are now registered if (File.Exists(localConfigurationPath)) diff --git a/src/Ryujinx.Ava/Ryujinx.Ava.csproj b/src/Ryujinx.Ava/Ryujinx.Ava.csproj index b6d37a2f1..91c2744f0 100644 --- a/src/Ryujinx.Ava/Ryujinx.Ava.csproj +++ b/src/Ryujinx.Ava/Ryujinx.Ava.csproj @@ -43,14 +43,13 @@ - - + - + @@ -74,12 +73,12 @@ - - + + - + Always alsoft.ini @@ -93,7 +92,7 @@ - + Always @@ -104,7 +103,7 @@ - + Designer diff --git a/src/Ryujinx.Ava/UI/Applet/AvaHostUiHandler.cs b/src/Ryujinx.Ava/UI/Applet/AvaHostUIHandler.cs similarity index 94% rename from src/Ryujinx.Ava/UI/Applet/AvaHostUiHandler.cs rename to src/Ryujinx.Ava/UI/Applet/AvaHostUIHandler.cs index e11939104..4bcc35a7a 100644 --- a/src/Ryujinx.Ava/UI/Applet/AvaHostUiHandler.cs +++ b/src/Ryujinx.Ava/UI/Applet/AvaHostUIHandler.cs @@ -8,26 +8,26 @@ using Ryujinx.Ava.UI.Windows; using Ryujinx.HLE; using Ryujinx.HLE.HOS.Applets; using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types; -using Ryujinx.HLE.Ui; +using Ryujinx.HLE.UI; using System; using System.Threading; namespace Ryujinx.Ava.UI.Applet { - internal class AvaHostUiHandler : IHostUiHandler + internal class AvaHostUIHandler : IHostUIHandler { private readonly MainWindow _parent; - public IHostUiTheme HostUiTheme { get; } + public IHostUITheme HostUITheme { get; } - public AvaHostUiHandler(MainWindow parent) + public AvaHostUIHandler(MainWindow parent) { _parent = parent; - HostUiTheme = new AvaloniaHostUiTheme(parent); + HostUITheme = new AvaloniaHostUITheme(parent); } - public bool DisplayMessageDialog(ControllerAppletUiArgs args) + public bool DisplayMessageDialog(ControllerAppletUIArgs args) { ManualResetEvent dialogCloseEvent = new(false); @@ -110,7 +110,7 @@ namespace Ryujinx.Ava.UI.Applet return okPressed; } - public bool DisplayInputDialog(SoftwareKeyboardUiArgs args, out string userText) + public bool DisplayInputDialog(SoftwareKeyboardUIArgs args, out string userText) { ManualResetEvent dialogCloseEvent = new(false); diff --git a/src/Ryujinx.Ava/UI/Applet/AvaloniaDynamicTextInputHandler.cs b/src/Ryujinx.Ava/UI/Applet/AvaloniaDynamicTextInputHandler.cs index 2411659f7..531d00611 100644 --- a/src/Ryujinx.Ava/UI/Applet/AvaloniaDynamicTextInputHandler.cs +++ b/src/Ryujinx.Ava/UI/Applet/AvaloniaDynamicTextInputHandler.cs @@ -5,7 +5,7 @@ using Avalonia.Threading; using Ryujinx.Ava.Input; using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Windows; -using Ryujinx.HLE.Ui; +using Ryujinx.HLE.UI; using System; using System.Threading; using HidKey = Ryujinx.Common.Configuration.Hid.Key; diff --git a/src/Ryujinx.Ava/UI/Applet/AvaloniaHostUiTheme.cs b/src/Ryujinx.Ava/UI/Applet/AvaloniaHostUITheme.cs similarity index 92% rename from src/Ryujinx.Ava/UI/Applet/AvaloniaHostUiTheme.cs rename to src/Ryujinx.Ava/UI/Applet/AvaloniaHostUITheme.cs index 4ee177d72..016fb4842 100644 --- a/src/Ryujinx.Ava/UI/Applet/AvaloniaHostUiTheme.cs +++ b/src/Ryujinx.Ava/UI/Applet/AvaloniaHostUITheme.cs @@ -1,13 +1,13 @@ using Avalonia.Media; using Ryujinx.Ava.UI.Windows; -using Ryujinx.HLE.Ui; +using Ryujinx.HLE.UI; using System; namespace Ryujinx.Ava.UI.Applet { - class AvaloniaHostUiTheme : IHostUiTheme + class AvaloniaHostUITheme : IHostUITheme { - public AvaloniaHostUiTheme(MainWindow parent) + public AvaloniaHostUITheme(MainWindow parent) { FontFamily = OperatingSystem.IsWindows() && OperatingSystem.IsWindowsVersionAtLeast(10, 0, 22000) ? "Segoe UI Variable" : parent.FontFamily.Name; DefaultBackgroundColor = BrushToThemeColor(parent.Background); diff --git a/src/Ryujinx.Ava/UI/Applet/ControllerAppletDialog.axaml.cs b/src/Ryujinx.Ava/UI/Applet/ControllerAppletDialog.axaml.cs index 34de5223b..279af07c3 100644 --- a/src/Ryujinx.Ava/UI/Applet/ControllerAppletDialog.axaml.cs +++ b/src/Ryujinx.Ava/UI/Applet/ControllerAppletDialog.axaml.cs @@ -9,6 +9,7 @@ using Ryujinx.Ava.UI.Windows; using Ryujinx.Common; using Ryujinx.HLE.HOS.Applets; using Ryujinx.HLE.HOS.Services.Hid; +using System; using System.Linq; using System.Threading.Tasks; @@ -35,7 +36,7 @@ namespace Ryujinx.Ava.UI.Applet private readonly MainWindow _mainWindow; - public ControllerAppletDialog(MainWindow mainWindow, ControllerAppletUiArgs args) + public ControllerAppletDialog(MainWindow mainWindow, ControllerAppletUIArgs args) { if (args.PlayerCountMin == args.PlayerCountMax) { @@ -68,7 +69,7 @@ namespace Ryujinx.Ava.UI.Applet InitializeComponent(); } - public static async Task ShowControllerAppletDialog(MainWindow window, ControllerAppletUiArgs args) + public static async Task ShowControllerAppletDialog(MainWindow window, ControllerAppletUIArgs args) { ContentDialog contentDialog = new(); UserResult result = UserResult.Cancel; @@ -103,7 +104,7 @@ namespace Ryujinx.Ava.UI.Applet if (!string.IsNullOrWhiteSpace(path)) { - SvgSource source = new(); + SvgSource source = new(default(Uri)); source.Load(EmbeddedResources.GetStream(path)); diff --git a/src/Ryujinx.Ava/UI/Applet/ErrorAppletWindow.axaml b/src/Ryujinx.Ava/UI/Applet/ErrorAppletWindow.axaml index 6186b7d93..51f370519 100644 --- a/src/Ryujinx.Ava/UI/Applet/ErrorAppletWindow.axaml +++ b/src/Ryujinx.Ava/UI/Applet/ErrorAppletWindow.axaml @@ -34,7 +34,7 @@ Height="80" MinWidth="50" Margin="5,10,20,10" - Source="resm:Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png?assembly=Ryujinx.Ui.Common" /> + Source="resm:Ryujinx.UI.Common.Resources.Logo_Ryujinx.png?assembly=Ryujinx.UI.Common" /> + Source="resm:Ryujinx.UI.Common.Resources.Logo_Ryujinx.png?assembly=Ryujinx.UI.Common" /> ShowInputDialog(string title, SoftwareKeyboardUiArgs args) + public static async Task<(UserResult Result, string Input)> ShowInputDialog(string title, SoftwareKeyboardUIArgs args) { ContentDialog contentDialog = new(); diff --git a/src/Ryujinx.Ava/UI/Controls/ApplicationContextMenu.axaml b/src/Ryujinx.Ava/UI/Controls/ApplicationContextMenu.axaml index b8fe7e76f..dd0926fc9 100644 --- a/src/Ryujinx.Ava/UI/Controls/ApplicationContextMenu.axaml +++ b/src/Ryujinx.Ava/UI/Controls/ApplicationContextMenu.axaml @@ -16,7 +16,7 @@ Click="CreateApplicationShortcut_Click" Header="{locale:Locale GameListContextMenuCreateShortcut}" IsEnabled="{Binding CreateShortcutEnabled}" - ToolTip.Tip="{locale:Locale GameListContextMenuCreateShortcutToolTip}" /> + ToolTip.Tip="{OnPlatform Default={locale:Locale GameListContextMenuCreateShortcutToolTip}, macOS={locale:Locale GameListContextMenuCreateShortcutToolTipMacOS}}" /> + + - + VerticalAlignment="Top" + Orientation="Horizontal" /> diff --git a/src/Ryujinx.Ava/UI/Controls/ApplicationGridView.axaml.cs b/src/Ryujinx.Ava/UI/Controls/ApplicationGridView.axaml.cs index 821d6fd9f..ee15bc8d5 100644 --- a/src/Ryujinx.Ava/UI/Controls/ApplicationGridView.axaml.cs +++ b/src/Ryujinx.Ava/UI/Controls/ApplicationGridView.axaml.cs @@ -3,7 +3,7 @@ using Avalonia.Input; using Avalonia.Interactivity; using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.ViewModels; -using Ryujinx.Ui.App.Common; +using Ryujinx.UI.App.Common; using System; namespace Ryujinx.Ava.UI.Controls diff --git a/src/Ryujinx.Ava/UI/Controls/ApplicationListView.axaml.cs b/src/Ryujinx.Ava/UI/Controls/ApplicationListView.axaml.cs index dd60503af..8681158ff 100644 --- a/src/Ryujinx.Ava/UI/Controls/ApplicationListView.axaml.cs +++ b/src/Ryujinx.Ava/UI/Controls/ApplicationListView.axaml.cs @@ -3,7 +3,7 @@ using Avalonia.Input; using Avalonia.Interactivity; using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.ViewModels; -using Ryujinx.Ui.App.Common; +using Ryujinx.UI.App.Common; using System; namespace Ryujinx.Ava.UI.Controls diff --git a/src/Ryujinx.Ava/UI/Controls/UpdateWaitWindow.axaml b/src/Ryujinx.Ava/UI/Controls/UpdateWaitWindow.axaml index c5041230d..09fa04045 100644 --- a/src/Ryujinx.Ava/UI/Controls/UpdateWaitWindow.axaml +++ b/src/Ryujinx.Ava/UI/Controls/UpdateWaitWindow.axaml @@ -26,7 +26,7 @@ Height="70" MinWidth="50" Margin="5,10,20,10" - Source="resm:Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png?assembly=Ryujinx.Ui.Common" /> + Source="resm:Ryujinx.UI.Common.Resources.Logo_Ryujinx.png?assembly=Ryujinx.UI.Common" /> - \ No newline at end of file + diff --git a/src/Ryujinx.Ava/UI/Helpers/ApplicationOpenedEventArgs.cs b/src/Ryujinx.Ava/UI/Helpers/ApplicationOpenedEventArgs.cs index cd63a99b0..bc5622b54 100644 --- a/src/Ryujinx.Ava/UI/Helpers/ApplicationOpenedEventArgs.cs +++ b/src/Ryujinx.Ava/UI/Helpers/ApplicationOpenedEventArgs.cs @@ -1,5 +1,5 @@ using Avalonia.Interactivity; -using Ryujinx.Ui.App.Common; +using Ryujinx.UI.App.Common; namespace Ryujinx.Ava.UI.Helpers { diff --git a/src/Ryujinx.Ava/UI/Helpers/ContentDialogHelper.cs b/src/Ryujinx.Ava/UI/Helpers/ContentDialogHelper.cs index a57deb1a0..15b7ddd14 100644 --- a/src/Ryujinx.Ava/UI/Helpers/ContentDialogHelper.cs +++ b/src/Ryujinx.Ava/UI/Helpers/ContentDialogHelper.cs @@ -336,6 +336,11 @@ namespace Ryujinx.Ava.UI.Helpers void OverlayOnPositionChanged(object sender, PixelPointEventArgs e) { + if (_contentDialogOverlayWindow is null) + { + return; + } + _contentDialogOverlayWindow.Position = parent.PointToScreen(new Point()); } @@ -378,7 +383,7 @@ namespace Ryujinx.Ava.UI.Helpers { result = ContentDialogResult.None; - Logger.Warning?.Print(LogClass.Ui, "Content dialog overlay failed to populate. Default value has been returned."); + Logger.Warning?.Print(LogClass.UI, "Content dialog overlay failed to populate. Default value has been returned."); } return result; @@ -388,6 +393,7 @@ namespace Ryujinx.Ava.UI.Helpers { _contentDialogOverlayWindow.Content = null; _contentDialogOverlayWindow.Close(); + _contentDialogOverlayWindow = null; } return result; diff --git a/src/Ryujinx.Ava/UI/Helpers/LocalizedNeverConverter.cs b/src/Ryujinx.Ava/UI/Helpers/LocalizedNeverConverter.cs index b61a924f4..26fe36c4c 100644 --- a/src/Ryujinx.Ava/UI/Helpers/LocalizedNeverConverter.cs +++ b/src/Ryujinx.Ava/UI/Helpers/LocalizedNeverConverter.cs @@ -1,7 +1,7 @@ using Avalonia.Data.Converters; using Avalonia.Markup.Xaml; using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ui.Common.Helper; +using Ryujinx.UI.Common.Helper; using System; using System.Globalization; diff --git a/src/Ryujinx.Ava/UI/Helpers/LoggerAdapter.cs b/src/Ryujinx.Ava/UI/Helpers/LoggerAdapter.cs index 0b1789880..fc7145410 100644 --- a/src/Ryujinx.Ava/UI/Helpers/LoggerAdapter.cs +++ b/src/Ryujinx.Ava/UI/Helpers/LoggerAdapter.cs @@ -39,12 +39,12 @@ namespace Ryujinx.Ava.UI.Helpers public void Log(AvaLogLevel level, string area, object source, string messageTemplate) { - GetLog(level)?.PrintMsg(RyuLogClass.Ui, Format(level, area, messageTemplate, source, null)); + GetLog(level)?.PrintMsg(RyuLogClass.UI, Format(level, area, messageTemplate, source, null)); } public void Log(AvaLogLevel level, string area, object source, string messageTemplate, params object[] propertyValues) { - GetLog(level)?.PrintMsg(RyuLogClass.Ui, Format(level, area, messageTemplate, source, propertyValues)); + GetLog(level)?.PrintMsg(RyuLogClass.UI, Format(level, area, messageTemplate, source, propertyValues)); } private static string Format(AvaLogLevel level, string area, string template, object source, object[] v) diff --git a/src/Ryujinx.Ava/UI/Helpers/UserErrorDialog.cs b/src/Ryujinx.Ava/UI/Helpers/UserErrorDialog.cs index fc82bd6b1..9a44b862b 100644 --- a/src/Ryujinx.Ava/UI/Helpers/UserErrorDialog.cs +++ b/src/Ryujinx.Ava/UI/Helpers/UserErrorDialog.cs @@ -1,6 +1,6 @@ using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ui.Common; -using Ryujinx.Ui.Common.Helper; +using Ryujinx.UI.Common; +using Ryujinx.UI.Common.Helper; using System.Threading.Tasks; namespace Ryujinx.Ava.UI.Helpers diff --git a/src/Ryujinx.Ava/UI/Models/Generic/LastPlayedSortComparer.cs b/src/Ryujinx.Ava/UI/Models/Generic/LastPlayedSortComparer.cs index 8340d39df..224f78f45 100644 --- a/src/Ryujinx.Ava/UI/Models/Generic/LastPlayedSortComparer.cs +++ b/src/Ryujinx.Ava/UI/Models/Generic/LastPlayedSortComparer.cs @@ -1,4 +1,4 @@ -using Ryujinx.Ui.App.Common; +using Ryujinx.UI.App.Common; using System; using System.Collections.Generic; diff --git a/src/Ryujinx.Ava/UI/Models/Generic/TimePlayedSortComparer.cs b/src/Ryujinx.Ava/UI/Models/Generic/TimePlayedSortComparer.cs index d53ff566f..f0fb035d1 100644 --- a/src/Ryujinx.Ava/UI/Models/Generic/TimePlayedSortComparer.cs +++ b/src/Ryujinx.Ava/UI/Models/Generic/TimePlayedSortComparer.cs @@ -1,4 +1,4 @@ -using Ryujinx.Ui.App.Common; +using Ryujinx.UI.App.Common; using System; using System.Collections.Generic; diff --git a/src/Ryujinx.Ava/UI/Models/ModModel.cs b/src/Ryujinx.Ava/UI/Models/ModModel.cs new file mode 100644 index 000000000..ee28ca5f5 --- /dev/null +++ b/src/Ryujinx.Ava/UI/Models/ModModel.cs @@ -0,0 +1,32 @@ +using Ryujinx.Ava.UI.ViewModels; +using System.IO; + +namespace Ryujinx.Ava.UI.Models +{ + public class ModModel : BaseModel + { + private bool _enabled; + + public bool Enabled + { + get => _enabled; + set + { + _enabled = value; + OnPropertyChanged(); + } + } + + public bool InSd { get; } + public string Path { get; } + public string Name { get; } + + public ModModel(string path, string name, bool enabled, bool inSd) + { + Path = path; + Name = name; + Enabled = enabled; + InSd = inSd; + } + } +} diff --git a/src/Ryujinx.Ava/UI/Models/SaveModel.cs b/src/Ryujinx.Ava/UI/Models/SaveModel.cs index 7b476932b..d6dea2f69 100644 --- a/src/Ryujinx.Ava/UI/Models/SaveModel.cs +++ b/src/Ryujinx.Ava/UI/Models/SaveModel.cs @@ -3,8 +3,8 @@ using LibHac.Ncm; using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Ava.UI.Windows; using Ryujinx.HLE.FileSystem; -using Ryujinx.Ui.App.Common; -using Ryujinx.Ui.Common.Helper; +using Ryujinx.UI.App.Common; +using Ryujinx.UI.Common.Helper; using System.IO; using System.Linq; using System.Threading.Tasks; diff --git a/src/Ryujinx.Ava/UI/Renderer/EmbeddedWindow.cs b/src/Ryujinx.Ava/UI/Renderer/EmbeddedWindow.cs index fa55c8d3f..3bf19b43e 100644 --- a/src/Ryujinx.Ava/UI/Renderer/EmbeddedWindow.cs +++ b/src/Ryujinx.Ava/UI/Renderer/EmbeddedWindow.cs @@ -3,8 +3,8 @@ using Avalonia.Controls; using Avalonia.Input; using Avalonia.Platform; using Ryujinx.Common.Configuration; -using Ryujinx.Ui.Common.Configuration; -using Ryujinx.Ui.Common.Helper; +using Ryujinx.UI.Common.Configuration; +using Ryujinx.UI.Common.Helper; using SPB.Graphics; using SPB.Platform; using SPB.Platform.GLX; diff --git a/src/Ryujinx.Ava/UI/Renderer/EmbeddedWindowOpenGL.cs b/src/Ryujinx.Ava/UI/Renderer/EmbeddedWindowOpenGL.cs index 769a1c91a..3842301de 100644 --- a/src/Ryujinx.Ava/UI/Renderer/EmbeddedWindowOpenGL.cs +++ b/src/Ryujinx.Ava/UI/Renderer/EmbeddedWindowOpenGL.cs @@ -3,7 +3,7 @@ using Ryujinx.Common.Configuration; using Ryujinx.Common.Logging; using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.OpenGL; -using Ryujinx.Ui.Common.Configuration; +using Ryujinx.UI.Common.Configuration; using SPB.Graphics; using SPB.Graphics.Exceptions; using SPB.Graphics.OpenGL; @@ -75,7 +75,7 @@ namespace Ryujinx.Ava.UI.Renderer throw; } - Logger.Warning?.Print(LogClass.Ui, $"Failed to {(!unbind ? "bind" : "unbind")} OpenGL context: {e}"); + Logger.Warning?.Print(LogClass.UI, $"Failed to {(!unbind ? "bind" : "unbind")} OpenGL context: {e}"); } } diff --git a/src/Ryujinx.Ava/UI/Renderer/RendererHost.axaml.cs b/src/Ryujinx.Ava/UI/Renderer/RendererHost.axaml.cs index 12c18e4a7..d055d9ea4 100644 --- a/src/Ryujinx.Ava/UI/Renderer/RendererHost.axaml.cs +++ b/src/Ryujinx.Ava/UI/Renderer/RendererHost.axaml.cs @@ -1,7 +1,7 @@ using Avalonia; using Avalonia.Controls; using Ryujinx.Common.Configuration; -using Ryujinx.Ui.Common.Configuration; +using Ryujinx.UI.Common.Configuration; using System; namespace Ryujinx.Ava.UI.Renderer diff --git a/src/Ryujinx.Ava/UI/Renderer/SPBOpenGLContext.cs b/src/Ryujinx.Ava/UI/Renderer/SPBOpenGLContext.cs index 5ff756f24..63bf6cf7c 100644 --- a/src/Ryujinx.Ava/UI/Renderer/SPBOpenGLContext.cs +++ b/src/Ryujinx.Ava/UI/Renderer/SPBOpenGLContext.cs @@ -29,6 +29,8 @@ namespace Ryujinx.Ava.UI.Renderer _context.MakeCurrent(_window); } + public bool HasContext() => _context.IsCurrent; + public static SPBOpenGLContext CreateBackgroundContext(OpenGLContextBase sharedContext) { OpenGLContextBase context = PlatformHelper.CreateOpenGLContext(FramebufferFormat.Default, 3, 3, OpenGLContextFlags.Compat, true, sharedContext); diff --git a/src/Ryujinx.Ava/UI/ViewModels/AboutWindowViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/AboutWindowViewModel.cs index 70ede4c12..6020f40e0 100644 --- a/src/Ryujinx.Ava/UI/ViewModels/AboutWindowViewModel.cs +++ b/src/Ryujinx.Ava/UI/ViewModels/AboutWindowViewModel.cs @@ -3,7 +3,7 @@ using Avalonia.Platform; using Avalonia.Threading; using Ryujinx.Ava.Common.Locale; using Ryujinx.Common.Utilities; -using Ryujinx.Ui.Common.Configuration; +using Ryujinx.UI.Common.Configuration; using System; using System.Net.Http; using System.Net.NetworkInformation; @@ -87,19 +87,19 @@ namespace Ryujinx.Ava.UI.ViewModels { Version = Program.Version; - if (ConfigurationState.Instance.Ui.BaseStyle.Value == "Light") + if (ConfigurationState.Instance.UI.BaseStyle.Value == "Light") { - GithubLogo = new Bitmap(AssetLoader.Open(new Uri("resm:Ryujinx.Ui.Common.Resources.Logo_GitHub_Light.png?assembly=Ryujinx.Ui.Common"))); - DiscordLogo = new Bitmap(AssetLoader.Open(new Uri("resm:Ryujinx.Ui.Common.Resources.Logo_Discord_Light.png?assembly=Ryujinx.Ui.Common"))); - PatreonLogo = new Bitmap(AssetLoader.Open(new Uri("resm:Ryujinx.Ui.Common.Resources.Logo_Patreon_Light.png?assembly=Ryujinx.Ui.Common"))); - TwitterLogo = new Bitmap(AssetLoader.Open(new Uri("resm:Ryujinx.Ui.Common.Resources.Logo_Twitter_Light.png?assembly=Ryujinx.Ui.Common"))); + GithubLogo = new Bitmap(AssetLoader.Open(new Uri("resm:Ryujinx.UI.Common.Resources.Logo_GitHub_Light.png?assembly=Ryujinx.UI.Common"))); + DiscordLogo = new Bitmap(AssetLoader.Open(new Uri("resm:Ryujinx.UI.Common.Resources.Logo_Discord_Light.png?assembly=Ryujinx.UI.Common"))); + PatreonLogo = new Bitmap(AssetLoader.Open(new Uri("resm:Ryujinx.UI.Common.Resources.Logo_Patreon_Light.png?assembly=Ryujinx.UI.Common"))); + TwitterLogo = new Bitmap(AssetLoader.Open(new Uri("resm:Ryujinx.UI.Common.Resources.Logo_Twitter_Light.png?assembly=Ryujinx.UI.Common"))); } else { - GithubLogo = new Bitmap(AssetLoader.Open(new Uri("resm:Ryujinx.Ui.Common.Resources.Logo_GitHub_Dark.png?assembly=Ryujinx.Ui.Common"))); - DiscordLogo = new Bitmap(AssetLoader.Open(new Uri("resm:Ryujinx.Ui.Common.Resources.Logo_Discord_Dark.png?assembly=Ryujinx.Ui.Common"))); - PatreonLogo = new Bitmap(AssetLoader.Open(new Uri("resm:Ryujinx.Ui.Common.Resources.Logo_Patreon_Dark.png?assembly=Ryujinx.Ui.Common"))); - TwitterLogo = new Bitmap(AssetLoader.Open(new Uri("resm:Ryujinx.Ui.Common.Resources.Logo_Twitter_Dark.png?assembly=Ryujinx.Ui.Common"))); + GithubLogo = new Bitmap(AssetLoader.Open(new Uri("resm:Ryujinx.UI.Common.Resources.Logo_GitHub_Dark.png?assembly=Ryujinx.UI.Common"))); + DiscordLogo = new Bitmap(AssetLoader.Open(new Uri("resm:Ryujinx.UI.Common.Resources.Logo_Discord_Dark.png?assembly=Ryujinx.UI.Common"))); + PatreonLogo = new Bitmap(AssetLoader.Open(new Uri("resm:Ryujinx.UI.Common.Resources.Logo_Patreon_Dark.png?assembly=Ryujinx.UI.Common"))); + TwitterLogo = new Bitmap(AssetLoader.Open(new Uri("resm:Ryujinx.UI.Common.Resources.Logo_Twitter_Dark.png?assembly=Ryujinx.UI.Common"))); } Dispatcher.UIThread.InvokeAsync(DownloadPatronsJson); diff --git a/src/Ryujinx.Ava/UI/ViewModels/AmiiboWindowViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/AmiiboWindowViewModel.cs index 0e0d858a4..8f09568a6 100644 --- a/src/Ryujinx.Ava/UI/ViewModels/AmiiboWindowViewModel.cs +++ b/src/Ryujinx.Ava/UI/ViewModels/AmiiboWindowViewModel.cs @@ -9,7 +9,7 @@ using Ryujinx.Common; using Ryujinx.Common.Configuration; using Ryujinx.Common.Logging; using Ryujinx.Common.Utilities; -using Ryujinx.Ui.Common.Models.Amiibo; +using Ryujinx.UI.Common.Models.Amiibo; using System; using System.Collections.Generic; using System.Collections.ObjectModel; @@ -65,7 +65,7 @@ namespace Ryujinx.Ava.UI.ViewModels _amiiboSeries = new ObservableCollection(); _amiibos = new AvaloniaList(); - _amiiboLogoBytes = EmbeddedResources.Read("Ryujinx.Ui.Common/Resources/Logo_Amiibo.png"); + _amiiboLogoBytes = EmbeddedResources.Read("Ryujinx.UI.Common/Resources/Logo_Amiibo.png"); _ = LoadContentAsync(); } diff --git a/src/Ryujinx.Ava/UI/ViewModels/ControllerInputViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/ControllerInputViewModel.cs index c0c625321..71ad2c127 100644 --- a/src/Ryujinx.Ava/UI/ViewModels/ControllerInputViewModel.cs +++ b/src/Ryujinx.Ava/UI/ViewModels/ControllerInputViewModel.cs @@ -19,7 +19,7 @@ using Ryujinx.Common.Configuration.Hid.Keyboard; using Ryujinx.Common.Logging; using Ryujinx.Common.Utilities; using Ryujinx.Input; -using Ryujinx.Ui.Common.Configuration; +using Ryujinx.UI.Common.Configuration; using System; using System.Collections.Generic; using System.Collections.ObjectModel; @@ -35,10 +35,10 @@ namespace Ryujinx.Ava.UI.ViewModels public class ControllerInputViewModel : BaseModel, IDisposable { private const string Disabled = "disabled"; - private const string ProControllerResource = "Ryujinx.Ui.Common/Resources/Controller_ProCon.svg"; - private const string JoyConPairResource = "Ryujinx.Ui.Common/Resources/Controller_JoyConPair.svg"; - private const string JoyConLeftResource = "Ryujinx.Ui.Common/Resources/Controller_JoyConLeft.svg"; - private const string JoyConRightResource = "Ryujinx.Ui.Common/Resources/Controller_JoyConRight.svg"; + private const string ProControllerResource = "Ryujinx.UI.Common/Resources/Controller_ProCon.svg"; + private const string JoyConPairResource = "Ryujinx.UI.Common/Resources/Controller_JoyConPair.svg"; + private const string JoyConLeftResource = "Ryujinx.UI.Common/Resources/Controller_JoyConLeft.svg"; + private const string JoyConRightResource = "Ryujinx.UI.Common/Resources/Controller_JoyConRight.svg"; private const string KeyboardString = "keyboard"; private const string ControllerString = "controller"; private readonly MainWindow _mainWindow; @@ -180,7 +180,7 @@ namespace Ryujinx.Ava.UI.ViewModels if (!string.IsNullOrWhiteSpace(_controllerImage)) { - SvgSource source = new(); + SvgSource source = new(default(Uri)); source.Load(EmbeddedResources.GetStream(_controllerImage)); diff --git a/src/Ryujinx.Ava/UI/ViewModels/DownloadableContentManagerViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/DownloadableContentManagerViewModel.cs index cdecae77d..2cd714f44 100644 --- a/src/Ryujinx.Ava/UI/ViewModels/DownloadableContentManagerViewModel.cs +++ b/src/Ryujinx.Ava/UI/ViewModels/DownloadableContentManagerViewModel.cs @@ -39,6 +39,7 @@ namespace Ryujinx.Ava.UI.ViewModels private string _search; private readonly ulong _titleId; + private readonly IStorageProvider _storageProvider; private static readonly DownloadableContentJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions()); @@ -90,8 +91,6 @@ namespace Ryujinx.Ava.UI.ViewModels get => string.Format(LocaleManager.Instance[LocaleKeys.DlcWindowHeading], DownloadableContents.Count); } - public IStorageProvider StorageProvider; - public DownloadableContentManagerViewModel(VirtualFileSystem virtualFileSystem, ulong titleId) { _virtualFileSystem = virtualFileSystem; @@ -100,7 +99,7 @@ namespace Ryujinx.Ava.UI.ViewModels if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { - StorageProvider = desktop.MainWindow.StorageProvider; + _storageProvider = desktop.MainWindow.StorageProvider; } _downloadableContentJsonPath = Path.Combine(AppDataManager.GamesDirPath, titleId.ToString("x16"), "dlc.json"); @@ -194,7 +193,7 @@ namespace Ryujinx.Ava.UI.ViewModels { Dispatcher.UIThread.InvokeAsync(async () => { - await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance[LocaleKeys.DialogLoadNcaErrorMessage], ex.Message, containerPath)); + await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance[LocaleKeys.DialogLoadFileErrorMessage], ex.Message, containerPath)); }); } @@ -203,7 +202,7 @@ namespace Ryujinx.Ava.UI.ViewModels public async void Add() { - var result = await StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions + var result = await _storageProvider.OpenFilePickerAsync(new FilePickerOpenOptions { Title = LocaleManager.Instance[LocaleKeys.SelectDlcDialogTitle], AllowMultiple = true, diff --git a/src/Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs index 7146dfd7c..17bd69b14 100644 --- a/src/Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs +++ b/src/Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs @@ -25,13 +25,13 @@ using Ryujinx.HLE; using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.HOS; using Ryujinx.HLE.HOS.Services.Account.Acc; -using Ryujinx.HLE.Ui; +using Ryujinx.HLE.UI; using Ryujinx.Input.HLE; using Ryujinx.Modules; -using Ryujinx.Ui.App.Common; -using Ryujinx.Ui.Common; -using Ryujinx.Ui.Common.Configuration; -using Ryujinx.Ui.Common.Helper; +using Ryujinx.UI.App.Common; +using Ryujinx.UI.Common; +using Ryujinx.UI.Common.Configuration; +using Ryujinx.UI.Common.Helper; using SixLabors.ImageSharp.PixelFormats; using System; using System.Collections.Generic; @@ -138,7 +138,7 @@ namespace Ryujinx.Ava.UI.ViewModels InputManager inputManager, UserChannelPersistence userChannelPersistence, LibHacHorizonManager libHacHorizonManager, - IHostUiHandler uiHandler, + IHostUIHandler uiHandler, Action showLoading, Action switchToGameControl, Action setMainContent, @@ -357,7 +357,7 @@ namespace Ryujinx.Ava.UI.ViewModels public bool OpenBcatSaveDirectoryEnabled => !SelectedApplication.ControlHolder.ByteSpan.IsZeros() && SelectedApplication.ControlHolder.Value.BcatDeliveryCacheStorageSize > 0; - public bool CreateShortcutEnabled => !ReleaseInformation.IsFlatHubBuild(); + public bool CreateShortcutEnabled => !ReleaseInformation.IsFlatHubBuild; public string LoadHeading { @@ -685,10 +685,10 @@ namespace Ryujinx.Ava.UI.ViewModels public bool StartGamesInFullscreen { - get => ConfigurationState.Instance.Ui.StartFullscreen; + get => ConfigurationState.Instance.UI.StartFullscreen; set { - ConfigurationState.Instance.Ui.StartFullscreen.Value = value; + ConfigurationState.Instance.UI.StartFullscreen.Value = value; ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath); @@ -698,10 +698,10 @@ namespace Ryujinx.Ava.UI.ViewModels public bool ShowConsole { - get => ConfigurationState.Instance.Ui.ShowConsole; + get => ConfigurationState.Instance.UI.ShowConsole; set { - ConfigurationState.Instance.Ui.ShowConsole.Value = value; + ConfigurationState.Instance.UI.ShowConsole.Value = value; ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath); @@ -743,10 +743,10 @@ namespace Ryujinx.Ava.UI.ViewModels public Glyph Glyph { - get => (Glyph)ConfigurationState.Instance.Ui.GameListViewMode.Value; + get => (Glyph)ConfigurationState.Instance.UI.GameListViewMode.Value; set { - ConfigurationState.Instance.Ui.GameListViewMode.Value = (int)value; + ConfigurationState.Instance.UI.GameListViewMode.Value = (int)value; OnPropertyChanged(); OnPropertyChanged(nameof(IsGrid)); @@ -758,9 +758,9 @@ namespace Ryujinx.Ava.UI.ViewModels public bool ShowNames { - get => ConfigurationState.Instance.Ui.ShowNames && ConfigurationState.Instance.Ui.GridSize > 1; set + get => ConfigurationState.Instance.UI.ShowNames && ConfigurationState.Instance.UI.GridSize > 1; set { - ConfigurationState.Instance.Ui.ShowNames.Value = value; + ConfigurationState.Instance.UI.ShowNames.Value = value; OnPropertyChanged(); OnPropertyChanged(nameof(GridSizeScale)); @@ -772,10 +772,10 @@ namespace Ryujinx.Ava.UI.ViewModels internal ApplicationSort SortMode { - get => (ApplicationSort)ConfigurationState.Instance.Ui.ApplicationSort.Value; + get => (ApplicationSort)ConfigurationState.Instance.UI.ApplicationSort.Value; private set { - ConfigurationState.Instance.Ui.ApplicationSort.Value = (int)value; + ConfigurationState.Instance.UI.ApplicationSort.Value = (int)value; OnPropertyChanged(); OnPropertyChanged(nameof(SortName)); @@ -788,7 +788,7 @@ namespace Ryujinx.Ava.UI.ViewModels { get { - return ConfigurationState.Instance.Ui.GridSize.Value switch + return ConfigurationState.Instance.UI.GridSize.Value switch { 1 => 78, 2 => 100, @@ -803,7 +803,7 @@ namespace Ryujinx.Ava.UI.ViewModels { get { - return ConfigurationState.Instance.Ui.GridSize.Value switch + return ConfigurationState.Instance.UI.GridSize.Value switch { 1 => 120, 2 => ShowNames ? 210 : 150, @@ -816,10 +816,10 @@ namespace Ryujinx.Ava.UI.ViewModels public int GridSizeScale { - get => ConfigurationState.Instance.Ui.GridSize; + get => ConfigurationState.Instance.UI.GridSize; set { - ConfigurationState.Instance.Ui.GridSize.Value = value; + ConfigurationState.Instance.UI.GridSize.Value = value; if (value < 2) { @@ -860,10 +860,10 @@ namespace Ryujinx.Ava.UI.ViewModels public bool IsAscending { - get => ConfigurationState.Instance.Ui.IsAscendingOrder; + get => ConfigurationState.Instance.UI.IsAscendingOrder; private set { - ConfigurationState.Instance.Ui.IsAscendingOrder.Value = value; + ConfigurationState.Instance.UI.IsAscendingOrder.Value = value; OnPropertyChanged(); OnPropertyChanged(nameof(SortMode)); @@ -919,7 +919,7 @@ namespace Ryujinx.Ava.UI.ViewModels public RendererHost RendererHostControl { get; private set; } public bool IsClosing { get; set; } public LibHacHorizonManager LibHacHorizonManager { get; internal set; } - public IHostUiHandler UiHandler { get; internal set; } + public IHostUIHandler UiHandler { get; internal set; } public bool IsSortedByFavorite => SortMode == ApplicationSort.Favorite; public bool IsSortedByTitle => SortMode == ApplicationSort.Title; public bool IsSortedByDeveloper => SortMode == ApplicationSort.Developer; @@ -928,10 +928,10 @@ namespace Ryujinx.Ava.UI.ViewModels public bool IsSortedByType => SortMode == ApplicationSort.FileType; public bool IsSortedBySize => SortMode == ApplicationSort.FileSize; public bool IsSortedByPath => SortMode == ApplicationSort.Path; - public bool IsGridSmall => ConfigurationState.Instance.Ui.GridSize == 1; - public bool IsGridMedium => ConfigurationState.Instance.Ui.GridSize == 2; - public bool IsGridLarge => ConfigurationState.Instance.Ui.GridSize == 3; - public bool IsGridHuge => ConfigurationState.Instance.Ui.GridSize == 4; + public bool IsGridSmall => ConfigurationState.Instance.UI.GridSize == 1; + public bool IsGridMedium => ConfigurationState.Instance.UI.GridSize == 2; + public bool IsGridLarge => ConfigurationState.Instance.UI.GridSize == 3; + public bool IsGridHuge => ConfigurationState.Instance.UI.GridSize == 4; #endregion @@ -1245,7 +1245,7 @@ namespace Ryujinx.Ava.UI.ViewModels public void LoadConfigurableHotKeys() { - if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.ShowUi, out var showUiKey)) + if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.ShowUI, out var showUiKey)) { ShowUiKey = new KeyGesture(showUiKey); } @@ -1350,11 +1350,11 @@ namespace Ryujinx.Ava.UI.ViewModels public void OpenLogsFolder() { - string logPath = Path.Combine(ReleaseInformation.GetBaseApplicationDirectory(), "Logs"); - - new DirectoryInfo(logPath).Create(); - - OpenHelper.OpenFolder(logPath); + string logPath = AppDataManager.GetOrCreateLogsDir(); + if (!string.IsNullOrEmpty(logPath)) + { + OpenHelper.OpenFolder(logPath); + } } public void ToggleDockMode() @@ -1385,7 +1385,7 @@ namespace Ryujinx.Ava.UI.ViewModels if (Program.PreviewerDetached) { - ConfigurationState.Instance.Ui.LanguageCode.Value = (string)languageCode; + ConfigurationState.Instance.UI.LanguageCode.Value = (string)languageCode; ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath); } } diff --git a/src/Ryujinx.Ava/UI/ViewModels/ModManagerViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/ModManagerViewModel.cs new file mode 100644 index 000000000..8321bf894 --- /dev/null +++ b/src/Ryujinx.Ava/UI/ViewModels/ModManagerViewModel.cs @@ -0,0 +1,336 @@ +using Avalonia; +using Avalonia.Collections; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Platform.Storage; +using Avalonia.Threading; +using DynamicData; +using Ryujinx.Ava.Common.Locale; +using Ryujinx.Ava.UI.Helpers; +using Ryujinx.Ava.UI.Models; +using Ryujinx.Common.Configuration; +using Ryujinx.Common.Logging; +using Ryujinx.Common.Utilities; +using Ryujinx.HLE.HOS; +using System; +using System.IO; +using System.Linq; + +namespace Ryujinx.Ava.UI.ViewModels +{ + public class ModManagerViewModel : BaseModel + { + private readonly string _modJsonPath; + + private AvaloniaList _mods = new(); + private AvaloniaList _views = new(); + private AvaloniaList _selectedMods = new(); + + private string _search; + private readonly ulong _applicationId; + private readonly IStorageProvider _storageProvider; + + private static readonly ModMetadataJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions()); + + public AvaloniaList Mods + { + get => _mods; + set + { + _mods = value; + OnPropertyChanged(); + OnPropertyChanged(nameof(ModCount)); + Sort(); + } + } + + public AvaloniaList Views + { + get => _views; + set + { + _views = value; + OnPropertyChanged(); + } + } + + public AvaloniaList SelectedMods + { + get => _selectedMods; + set + { + _selectedMods = value; + OnPropertyChanged(); + } + } + + public string Search + { + get => _search; + set + { + _search = value; + OnPropertyChanged(); + Sort(); + } + } + + public string ModCount + { + get => string.Format(LocaleManager.Instance[LocaleKeys.ModWindowHeading], Mods.Count); + } + + public ModManagerViewModel(ulong applicationId) + { + _applicationId = applicationId; + + _modJsonPath = Path.Combine(AppDataManager.GamesDirPath, applicationId.ToString("x16"), "mods.json"); + + if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + { + _storageProvider = desktop.MainWindow.StorageProvider; + } + + LoadMods(applicationId); + } + + private void LoadMods(ulong applicationId) + { + Mods.Clear(); + SelectedMods.Clear(); + + string[] modsBasePaths = [ModLoader.GetSdModsBasePath(), ModLoader.GetModsBasePath()]; + + foreach (var path in modsBasePaths) + { + var inSd = path == ModLoader.GetSdModsBasePath(); + var modCache = new ModLoader.ModCache(); + + ModLoader.QueryContentsDir(modCache, new DirectoryInfo(Path.Combine(path, "contents")), applicationId); + + foreach (var mod in modCache.RomfsDirs) + { + var modModel = new ModModel(mod.Path.Parent.FullName, mod.Name, mod.Enabled, inSd); + if (Mods.All(x => x.Path != mod.Path.Parent.FullName)) + { + Mods.Add(modModel); + } + } + + foreach (var mod in modCache.RomfsContainers) + { + Mods.Add(new ModModel(mod.Path.FullName, mod.Name, mod.Enabled, inSd)); + } + + foreach (var mod in modCache.ExefsDirs) + { + var modModel = new ModModel(mod.Path.Parent.FullName, mod.Name, mod.Enabled, inSd); + if (Mods.All(x => x.Path != mod.Path.Parent.FullName)) + { + Mods.Add(modModel); + } + } + + foreach (var mod in modCache.ExefsContainers) + { + Mods.Add(new ModModel(mod.Path.FullName, mod.Name, mod.Enabled, inSd)); + } + } + + Sort(); + } + + public void Sort() + { + Mods.AsObservableChangeSet() + .Filter(Filter) + .Bind(out var view).AsObservableList(); + + _views.Clear(); + _views.AddRange(view); + + SelectedMods = new(Views.Where(x => x.Enabled)); + + OnPropertyChanged(nameof(ModCount)); + OnPropertyChanged(nameof(Views)); + OnPropertyChanged(nameof(SelectedMods)); + } + + private bool Filter(object arg) + { + if (arg is ModModel content) + { + return string.IsNullOrWhiteSpace(_search) || content.Name.ToLower().Contains(_search.ToLower()); + } + + return false; + } + + public void Save() + { + ModMetadata modData = new(); + + foreach (ModModel mod in Mods) + { + modData.Mods.Add(new Mod + { + Name = mod.Name, + Path = mod.Path, + Enabled = SelectedMods.Contains(mod), + }); + } + + JsonHelper.SerializeToFile(_modJsonPath, modData, _serializerContext.ModMetadata); + } + + public void Delete(ModModel model) + { + var isSubdir = true; + var pathToDelete = model.Path; + var basePath = model.InSd ? ModLoader.GetSdModsBasePath() : ModLoader.GetModsBasePath(); + var modsDir = ModLoader.GetApplicationDir(basePath, _applicationId.ToString("x16")); + + if (new DirectoryInfo(model.Path).Parent?.FullName == modsDir) + { + isSubdir = false; + } + + if (isSubdir) + { + var parentDir = String.Empty; + + foreach (var dir in Directory.GetDirectories(modsDir, "*", SearchOption.TopDirectoryOnly)) + { + if (Directory.GetDirectories(dir, "*", SearchOption.AllDirectories).Contains(model.Path)) + { + parentDir = dir; + break; + } + } + + if (parentDir == String.Empty) + { + Dispatcher.UIThread.Post(async () => + { + await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue( + LocaleKeys.DialogModDeleteNoParentMessage, + model.Path)); + }); + return; + } + } + + Logger.Info?.Print(LogClass.Application, $"Deleting mod at \"{pathToDelete}\""); + Directory.Delete(pathToDelete, true); + + Mods.Remove(model); + OnPropertyChanged(nameof(ModCount)); + Sort(); + } + + private void AddMod(DirectoryInfo directory) + { + string[] directories; + + try + { + directories = Directory.GetDirectories(directory.ToString(), "*", SearchOption.AllDirectories); + } + catch (Exception exception) + { + Dispatcher.UIThread.Post(async () => + { + await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue( + LocaleKeys.DialogLoadFileErrorMessage, + exception.ToString(), + directory)); + }); + return; + } + + var destinationDir = ModLoader.GetApplicationDir(ModLoader.GetSdModsBasePath(), _applicationId.ToString("x16")); + + // TODO: More robust checking for valid mod folders + var isDirectoryValid = true; + + if (directories.Length == 0) + { + isDirectoryValid = false; + } + + if (!isDirectoryValid) + { + Dispatcher.UIThread.Post(async () => + { + await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogModInvalidMessage]); + }); + return; + } + + foreach (var dir in directories) + { + string dirToCreate = dir.Replace(directory.Parent.ToString(), destinationDir); + + // Mod already exists + if (Directory.Exists(dirToCreate)) + { + Dispatcher.UIThread.Post(async () => + { + await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue( + LocaleKeys.DialogLoadFileErrorMessage, + LocaleManager.Instance[LocaleKeys.DialogModAlreadyExistsMessage], + dirToCreate)); + }); + + return; + } + + Directory.CreateDirectory(dirToCreate); + } + + var files = Directory.GetFiles(directory.ToString(), "*", SearchOption.AllDirectories); + + foreach (var file in files) + { + File.Copy(file, file.Replace(directory.Parent.ToString(), destinationDir), true); + } + + LoadMods(_applicationId); + } + + public async void Add() + { + var result = await _storageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions + { + Title = LocaleManager.Instance[LocaleKeys.SelectModDialogTitle], + AllowMultiple = true, + }); + + foreach (var folder in result) + { + AddMod(new DirectoryInfo(folder.Path.LocalPath)); + } + } + + public void DeleteAll() + { + foreach (var mod in Mods) + { + Delete(mod); + } + + Mods.Clear(); + OnPropertyChanged(nameof(ModCount)); + Sort(); + } + + public void EnableAll() + { + SelectedMods = new(Mods); + } + + public void DisableAll() + { + SelectedMods.Clear(); + } + } +} diff --git a/src/Ryujinx.Ava/UI/ViewModels/SettingsViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/SettingsViewModel.cs index 604e34067..bcaa08600 100644 --- a/src/Ryujinx.Ava/UI/ViewModels/SettingsViewModel.cs +++ b/src/Ryujinx.Ava/UI/ViewModels/SettingsViewModel.cs @@ -16,8 +16,8 @@ using Ryujinx.Common.Logging; using Ryujinx.Graphics.Vulkan; using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.HOS.Services.Time.TimeZone; -using Ryujinx.Ui.Common.Configuration; -using Ryujinx.Ui.Common.Configuration.System; +using Ryujinx.UI.Common.Configuration; +using Ryujinx.UI.Common.Configuration.System; using System; using System.Collections.Generic; using System.Collections.ObjectModel; @@ -48,7 +48,6 @@ namespace Ryujinx.Ava.UI.ViewModels private readonly List _gpuIds = new(); private KeyboardHotkeys _keyboardHotkeys; private int _graphicsBackendIndex; - private string _customThemePath; private int _scalingFilter; private int _scalingFilterLevel; @@ -160,7 +159,6 @@ namespace Ryujinx.Ava.UI.ViewModels public bool IsOpenAlEnabled { get; set; } public bool IsSoundIoEnabled { get; set; } public bool IsSDL2Enabled { get; set; } - public bool EnableCustomTheme { get; set; } public bool IsCustomResolutionScaleActive => _resolutionScale == 4; public bool IsScalingFilterActive => _scalingFilter == (int)Ryujinx.Common.Configuration.ScalingFilter.Fsr; @@ -170,20 +168,6 @@ namespace Ryujinx.Ava.UI.ViewModels public string TimeZone { get; set; } public string ShaderDumpPath { get; set; } - public string CustomThemePath - { - get - { - return _customThemePath; - } - set - { - _customThemePath = value; - - OnPropertyChanged(); - } - } - public int Language { get; set; } public int Region { get; set; } public int FsGlobalAccessLogMode { get; set; } @@ -424,11 +408,9 @@ namespace Ryujinx.Ava.UI.ViewModels HideCursor = (int)config.HideCursor.Value; GameDirectories.Clear(); - GameDirectories.AddRange(config.Ui.GameDirs.Value); + GameDirectories.AddRange(config.UI.GameDirs.Value); - EnableCustomTheme = config.Ui.EnableCustomTheme; - CustomThemePath = config.Ui.CustomThemePath; - BaseStyleIndex = config.Ui.BaseStyle == "Light" ? 0 : 1; + BaseStyleIndex = config.UI.BaseStyle == "Light" ? 0 : 1; // Input EnableDockedMode = config.System.EnableDockedMode; @@ -512,12 +494,10 @@ namespace Ryujinx.Ava.UI.ViewModels if (_directoryChanged) { List gameDirs = new(GameDirectories); - config.Ui.GameDirs.Value = gameDirs; + config.UI.GameDirs.Value = gameDirs; } - config.Ui.EnableCustomTheme.Value = EnableCustomTheme; - config.Ui.CustomThemePath.Value = CustomThemePath; - config.Ui.BaseStyle.Value = BaseStyleIndex == 0 ? "Light" : "Dark"; + config.UI.BaseStyle.Value = BaseStyleIndex == 0 ? "Light" : "Dark"; // Input config.System.EnableDockedMode.Value = EnableDockedMode; diff --git a/src/Ryujinx.Ava/UI/ViewModels/TitleUpdateViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/TitleUpdateViewModel.cs index 5090a8c70..5989ce09a 100644 --- a/src/Ryujinx.Ava/UI/ViewModels/TitleUpdateViewModel.cs +++ b/src/Ryujinx.Ava/UI/ViewModels/TitleUpdateViewModel.cs @@ -17,7 +17,7 @@ using Ryujinx.Common.Configuration; using Ryujinx.Common.Logging; using Ryujinx.Common.Utilities; using Ryujinx.HLE.FileSystem; -using Ryujinx.Ui.App.Common; +using Ryujinx.UI.App.Common; using System; using System.Collections.Generic; using System.IO; @@ -192,7 +192,7 @@ namespace Ryujinx.Ava.UI.ViewModels } catch (Exception ex) { - Dispatcher.UIThread.InvokeAsync(() => ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogLoadNcaErrorMessage, ex.Message, path))); + Dispatcher.UIThread.InvokeAsync(() => ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogLoadFileErrorMessage, ex.Message, path))); } } } diff --git a/src/Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml.cs b/src/Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml.cs index 439c6fcc6..0fdad7679 100644 --- a/src/Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml.cs +++ b/src/Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml.cs @@ -10,9 +10,9 @@ using Ryujinx.Ava.UI.Windows; using Ryujinx.Common; using Ryujinx.Common.Utilities; using Ryujinx.Modules; -using Ryujinx.Ui.Common; -using Ryujinx.Ui.Common.Configuration; -using Ryujinx.Ui.Common.Helper; +using Ryujinx.UI.Common; +using Ryujinx.UI.Common.Configuration; +using Ryujinx.UI.Common.Helper; using System; using System.Collections.Generic; using System.Globalization; @@ -44,7 +44,7 @@ namespace Ryujinx.Ava.UI.Views.Main checkBoxes.Add(new CheckBox { Content = $".{fileName}", - IsChecked = ((FileTypes)item).GetConfigValue(ConfigurationState.Instance.Ui.ShownFileTypes), + IsChecked = ((FileTypes)item).GetConfigValue(ConfigurationState.Instance.UI.ShownFileTypes), Command = MiniCommand.Create(() => Window.ToggleFileType(fileName)), }); } diff --git a/src/Ryujinx.Ava/UI/Views/Main/MainStatusBarView.axaml.cs b/src/Ryujinx.Ava/UI/Views/Main/MainStatusBarView.axaml.cs index 822045d44..239a7cbfc 100644 --- a/src/Ryujinx.Ava/UI/Views/Main/MainStatusBarView.axaml.cs +++ b/src/Ryujinx.Ava/UI/Views/Main/MainStatusBarView.axaml.cs @@ -5,7 +5,7 @@ using Avalonia.Interactivity; using Ryujinx.Ava.UI.Windows; using Ryujinx.Common.Configuration; using Ryujinx.Common.Logging; -using Ryujinx.Ui.Common.Configuration; +using Ryujinx.UI.Common.Configuration; using System; namespace Ryujinx.Ava.UI.Views.Main diff --git a/src/Ryujinx.Ava/UI/Views/Settings/SettingsHotkeysView.axaml b/src/Ryujinx.Ava/UI/Views/Settings/SettingsHotkeysView.axaml index a53c1dfe4..b4eae01ef 100644 --- a/src/Ryujinx.Ava/UI/Views/Settings/SettingsHotkeysView.axaml +++ b/src/Ryujinx.Ava/UI/Views/Settings/SettingsHotkeysView.axaml @@ -45,7 +45,7 @@ diff --git a/src/Ryujinx.Ava/UI/Views/Settings/SettingsUIView.axaml b/src/Ryujinx.Ava/UI/Views/Settings/SettingsUIView.axaml index b7471d385..6504637e6 100644 --- a/src/Ryujinx.Ava/UI/Views/Settings/SettingsUIView.axaml +++ b/src/Ryujinx.Ava/UI/Views/Settings/SettingsUIView.axaml @@ -36,7 +36,7 @@ - + @@ -54,6 +54,22 @@ + + + + + + + + + + + @@ -106,64 +122,6 @@ - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Ryujinx.Ava/UI/Windows/ModManagerWindow.axaml.cs b/src/Ryujinx.Ava/UI/Windows/ModManagerWindow.axaml.cs new file mode 100644 index 000000000..d9ae0d4f3 --- /dev/null +++ b/src/Ryujinx.Ava/UI/Windows/ModManagerWindow.axaml.cs @@ -0,0 +1,139 @@ +using Avalonia.Controls; +using Avalonia.Interactivity; +using Avalonia.Styling; +using FluentAvalonia.UI.Controls; +using Ryujinx.Ava.Common.Locale; +using Ryujinx.Ava.UI.Helpers; +using Ryujinx.Ava.UI.Models; +using Ryujinx.Ava.UI.ViewModels; +using Ryujinx.UI.Common.Helper; +using System.Threading.Tasks; +using Button = Avalonia.Controls.Button; + +namespace Ryujinx.Ava.UI.Windows +{ + public partial class ModManagerWindow : UserControl + { + public ModManagerViewModel ViewModel; + + public ModManagerWindow() + { + DataContext = this; + + InitializeComponent(); + } + + public ModManagerWindow(ulong titleId) + { + DataContext = ViewModel = new ModManagerViewModel(titleId); + + InitializeComponent(); + } + + public static async Task Show(ulong titleId, string titleName) + { + ContentDialog contentDialog = new() + { + PrimaryButtonText = "", + SecondaryButtonText = "", + CloseButtonText = "", + Content = new ModManagerWindow(titleId), + Title = string.Format(LocaleManager.Instance[LocaleKeys.ModWindowHeading], titleName, titleId.ToString("X16")), + }; + + Style bottomBorder = new(x => x.OfType().Name("DialogSpace").Child().OfType()); + bottomBorder.Setters.Add(new Setter(IsVisibleProperty, false)); + + contentDialog.Styles.Add(bottomBorder); + + await contentDialog.ShowAsync(); + } + + private void SaveAndClose(object sender, RoutedEventArgs e) + { + ViewModel.Save(); + ((ContentDialog)Parent).Hide(); + } + + private void Close(object sender, RoutedEventArgs e) + { + ((ContentDialog)Parent).Hide(); + } + + private async void DeleteMod(object sender, RoutedEventArgs e) + { + if (sender is Button button) + { + if (button.DataContext is ModModel model) + { + var result = await ContentDialogHelper.CreateConfirmationDialog( + LocaleManager.Instance[LocaleKeys.DialogWarning], + LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogModManagerDeletionWarningMessage, model.Name), + LocaleManager.Instance[LocaleKeys.InputDialogYes], + LocaleManager.Instance[LocaleKeys.InputDialogNo], + LocaleManager.Instance[LocaleKeys.RyujinxConfirm]); + + if (result == UserResult.Yes) + { + ViewModel.Delete(model); + } + } + } + } + + private async void DeleteAll(object sender, RoutedEventArgs e) + { + var result = await ContentDialogHelper.CreateConfirmationDialog( + LocaleManager.Instance[LocaleKeys.DialogWarning], + LocaleManager.Instance[LocaleKeys.DialogModManagerDeletionAllWarningMessage], + LocaleManager.Instance[LocaleKeys.InputDialogYes], + LocaleManager.Instance[LocaleKeys.InputDialogNo], + LocaleManager.Instance[LocaleKeys.RyujinxConfirm]); + + if (result == UserResult.Yes) + { + ViewModel.DeleteAll(); + } + } + + private void OpenLocation(object sender, RoutedEventArgs e) + { + if (sender is Button button) + { + if (button.DataContext is ModModel model) + { + OpenHelper.OpenFolder(model.Path); + } + } + } + + private void OnSelectionChanged(object sender, SelectionChangedEventArgs e) + { + foreach (var content in e.AddedItems) + { + if (content is ModModel model) + { + var index = ViewModel.Mods.IndexOf(model); + + if (index != -1) + { + ViewModel.Mods[index].Enabled = true; + } + } + } + + foreach (var content in e.RemovedItems) + { + if (content is ModModel model) + { + var index = ViewModel.Mods.IndexOf(model); + + if (index != -1) + { + ViewModel.Mods[index].Enabled = false; + } + } + } + } + } +} diff --git a/src/Ryujinx.Ava/UI/Windows/StyleableWindow.cs b/src/Ryujinx.Ava/UI/Windows/StyleableWindow.cs index 3cd12bc8c..a12d2b3e8 100644 --- a/src/Ryujinx.Ava/UI/Windows/StyleableWindow.cs +++ b/src/Ryujinx.Ava/UI/Windows/StyleableWindow.cs @@ -4,7 +4,7 @@ using Avalonia.Media; using Avalonia.Media.Imaging; using Avalonia.Platform; using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ui.Common.Configuration; +using Ryujinx.UI.Common.Configuration; using System.IO; using System.Reflection; @@ -19,7 +19,7 @@ namespace Ryujinx.Ava.UI.Windows WindowStartupLocation = WindowStartupLocation.CenterOwner; TransparencyLevelHint = new[] { WindowTransparencyLevel.None }; - using Stream stream = Assembly.GetAssembly(typeof(ConfigurationState)).GetManifestResourceStream("Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png"); + using Stream stream = Assembly.GetAssembly(typeof(ConfigurationState)).GetManifestResourceStream("Ryujinx.UI.Common.Resources.Logo_Ryujinx.png"); Icon = new WindowIcon(stream); stream.Position = 0; diff --git a/src/Ryujinx.Ava/UI/Windows/TitleUpdateWindow.axaml.cs b/src/Ryujinx.Ava/UI/Windows/TitleUpdateWindow.axaml.cs index 7ece63355..f3ac69600 100644 --- a/src/Ryujinx.Ava/UI/Windows/TitleUpdateWindow.axaml.cs +++ b/src/Ryujinx.Ava/UI/Windows/TitleUpdateWindow.axaml.cs @@ -7,7 +7,7 @@ using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Models; using Ryujinx.Ava.UI.ViewModels; using Ryujinx.HLE.FileSystem; -using Ryujinx.Ui.Common.Helper; +using Ryujinx.UI.Common.Helper; using System.Threading.Tasks; using Button = Avalonia.Controls.Button; diff --git a/src/Ryujinx.Common/Configuration/AppDataManager.cs b/src/Ryujinx.Common/Configuration/AppDataManager.cs index 2b4a594d3..f3df0fc9d 100644 --- a/src/Ryujinx.Common/Configuration/AppDataManager.cs +++ b/src/Ryujinx.Common/Configuration/AppDataManager.cs @@ -1,4 +1,5 @@ using Ryujinx.Common.Logging; +using Ryujinx.Common.Utilities; using System; using System.IO; @@ -6,8 +7,8 @@ namespace Ryujinx.Common.Configuration { public static class AppDataManager { - public const string DefaultBaseDir = "Ryujinx"; - public const string DefaultPortableDir = "portable"; + private const string DefaultBaseDir = "Ryujinx"; + private const string DefaultPortableDir = "portable"; // The following 3 are always part of Base Directory private const string GamesDir = "games"; @@ -29,6 +30,8 @@ namespace Ryujinx.Common.Configuration public static string KeysDirPath { get; private set; } public static string KeysDirPathUser { get; } + public static string LogsDirPath { get; private set; } + public const string DefaultNandDir = "bis"; public const string DefaultSdcardDir = "sdcard"; private const string DefaultModsDir = "mods"; @@ -45,15 +48,7 @@ namespace Ryujinx.Common.Configuration public static void Initialize(string baseDirPath) { - string appDataPath; - if (OperatingSystem.IsMacOS()) - { - appDataPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Library", "Application Support"); - } - else - { - appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); - } + string appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); if (appDataPath.Length == 0) { @@ -63,6 +58,17 @@ namespace Ryujinx.Common.Configuration string userProfilePath = Path.Combine(appDataPath, DefaultBaseDir); string portablePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, DefaultPortableDir); + // On macOS, check for a portable directory next to the app bundle as well. + if (OperatingSystem.IsMacOS() && !Directory.Exists(portablePath)) + { + string bundlePath = Path.GetFullPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "..", "..")); + // Make sure we're actually running within an app bundle. + if (bundlePath.EndsWith(".app")) + { + portablePath = Path.GetFullPath(Path.Combine(bundlePath, "..", DefaultPortableDir)); + } + } + if (Directory.Exists(portablePath)) { BaseDirPath = portablePath; @@ -98,8 +104,7 @@ namespace Ryujinx.Common.Configuration string oldConfigPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), DefaultBaseDir); if (Path.Exists(oldConfigPath) && !IsPathSymlink(oldConfigPath) && !Path.Exists(BaseDirPath)) { - CopyDirectory(oldConfigPath, BaseDirPath); - Directory.Delete(oldConfigPath, true); + FileSystemUtils.MoveDirectory(oldConfigPath, BaseDirPath); Directory.CreateSymbolicLink(oldConfigPath, BaseDirPath); } } @@ -107,50 +112,139 @@ namespace Ryujinx.Common.Configuration SetupBasePaths(); } + public static string GetOrCreateLogsDir() + { + if (Directory.Exists(LogsDirPath)) + { + return LogsDirPath; + } + + Logger.Notice.Print(LogClass.Application, "Logging directory not found; attempting to create new logging directory."); + LogsDirPath = SetUpLogsDir(); + + return LogsDirPath; + } + + private static string SetUpLogsDir() + { + string logDir = ""; + + if (Mode == LaunchMode.Portable) + { + logDir = Path.Combine(BaseDirPath, "Logs"); + try + { + Directory.CreateDirectory(logDir); + } + catch + { + Logger.Warning?.Print(LogClass.Application, $"Logging directory could not be created '{logDir}'"); + + return null; + } + } + else + { + if (OperatingSystem.IsMacOS()) + { + // NOTE: Should evaluate to "~/Library/Logs/Ryujinx/". + logDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Library", "Logs", DefaultBaseDir); + try + { + Directory.CreateDirectory(logDir); + } + catch + { + Logger.Warning?.Print(LogClass.Application, $"Logging directory could not be created '{logDir}'"); + logDir = ""; + } + + if (string.IsNullOrEmpty(logDir)) + { + // NOTE: Should evaluate to "~/Library/Application Support/Ryujinx/Logs". + logDir = Path.Combine(BaseDirPath, "Logs"); + + try + { + Directory.CreateDirectory(logDir); + } + catch + { + Logger.Warning?.Print(LogClass.Application, $"Logging directory could not be created '{logDir}'"); + + return null; + } + } + } + else if (OperatingSystem.IsWindows()) + { + // NOTE: Should evaluate to a "Logs" directory in whatever directory Ryujinx was launched from. + logDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logs"); + try + { + Directory.CreateDirectory(logDir); + } + catch + { + Logger.Warning?.Print(LogClass.Application, $"Logging directory could not be created '{logDir}'"); + logDir = ""; + } + + if (string.IsNullOrEmpty(logDir)) + { + // NOTE: Should evaluate to "C:\Users\user\AppData\Roaming\Ryujinx\Logs". + logDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), DefaultBaseDir, "Logs"); + + try + { + Directory.CreateDirectory(logDir); + } + catch + { + Logger.Warning?.Print(LogClass.Application, $"Logging directory could not be created '{logDir}'"); + + return null; + } + } + } + else if (OperatingSystem.IsLinux()) + { + // NOTE: Should evaluate to "~/.config/Ryujinx/Logs". + logDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), DefaultBaseDir, "Logs"); + + try + { + Directory.CreateDirectory(logDir); + } + catch + { + Logger.Warning?.Print(LogClass.Application, $"Logging directory could not be created '{logDir}'"); + + return null; + } + } + } + + return logDir; + } + private static void SetupBasePaths() { Directory.CreateDirectory(BaseDirPath); + LogsDirPath = SetUpLogsDir(); Directory.CreateDirectory(GamesDirPath = Path.Combine(BaseDirPath, GamesDir)); Directory.CreateDirectory(ProfilesDirPath = Path.Combine(BaseDirPath, ProfilesDir)); Directory.CreateDirectory(KeysDirPath = Path.Combine(BaseDirPath, KeysDir)); } // Check if existing old baseDirPath is a symlink, to prevent possible errors. - // Should be removed, when the existance of the old directory isn't checked anymore. + // Should be removed, when the existence of the old directory isn't checked anymore. private static bool IsPathSymlink(string path) { FileAttributes attributes = File.GetAttributes(path); return (attributes & FileAttributes.ReparsePoint) == FileAttributes.ReparsePoint; } - private static void CopyDirectory(string sourceDir, string destinationDir) - { - var dir = new DirectoryInfo(sourceDir); - - if (!dir.Exists) - { - throw new DirectoryNotFoundException($"Source directory not found: {dir.FullName}"); - } - - DirectoryInfo[] subDirs = dir.GetDirectories(); - Directory.CreateDirectory(destinationDir); - - foreach (FileInfo file in dir.GetFiles()) - { - if (file.Name == ".DS_Store") - { - continue; - } - - file.CopyTo(Path.Combine(destinationDir, file.Name)); - } - - foreach (DirectoryInfo subDir in subDirs) - { - CopyDirectory(subDir.FullName, Path.Combine(destinationDir, subDir.Name)); - } - } - public static string GetModsPath() => CustomModsPath ?? Directory.CreateDirectory(Path.Combine(BaseDirPath, DefaultModsDir)).FullName; public static string GetSdModsPath() => CustomSdModsPath ?? Directory.CreateDirectory(Path.Combine(BaseDirPath, DefaultSdcardDir, "atmosphere")).FullName; } diff --git a/src/Ryujinx.Common/Configuration/Hid/KeyboardHotkeys.cs b/src/Ryujinx.Common/Configuration/Hid/KeyboardHotkeys.cs index b4f2f9468..e9c163cf2 100644 --- a/src/Ryujinx.Common/Configuration/Hid/KeyboardHotkeys.cs +++ b/src/Ryujinx.Common/Configuration/Hid/KeyboardHotkeys.cs @@ -6,7 +6,7 @@ namespace Ryujinx.Common.Configuration.Hid { public Key ToggleVsync { get; set; } public Key Screenshot { get; set; } - public Key ShowUi { get; set; } + public Key ShowUI { get; set; } public Key Pause { get; set; } public Key ToggleMute { get; set; } public Key ResScaleUp { get; set; } diff --git a/src/Ryujinx.Common/Configuration/Mod.cs b/src/Ryujinx.Common/Configuration/Mod.cs new file mode 100644 index 000000000..052c7c8d1 --- /dev/null +++ b/src/Ryujinx.Common/Configuration/Mod.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.Common.Configuration +{ + public class Mod + { + public string Name { get; set; } + public string Path { get; set; } + public bool Enabled { get; set; } + } +} diff --git a/src/Ryujinx.Common/Configuration/ModMetadata.cs b/src/Ryujinx.Common/Configuration/ModMetadata.cs new file mode 100644 index 000000000..174320d0a --- /dev/null +++ b/src/Ryujinx.Common/Configuration/ModMetadata.cs @@ -0,0 +1,14 @@ +using System.Collections.Generic; + +namespace Ryujinx.Common.Configuration +{ + public struct ModMetadata + { + public List Mods { get; set; } + + public ModMetadata() + { + Mods = new List(); + } + } +} diff --git a/src/Ryujinx.Common/Configuration/ModMetadataJsonSerializerContext.cs b/src/Ryujinx.Common/Configuration/ModMetadataJsonSerializerContext.cs new file mode 100644 index 000000000..8c1e242ad --- /dev/null +++ b/src/Ryujinx.Common/Configuration/ModMetadataJsonSerializerContext.cs @@ -0,0 +1,10 @@ +using System.Text.Json.Serialization; + +namespace Ryujinx.Common.Configuration +{ + [JsonSourceGenerationOptions(WriteIndented = true)] + [JsonSerializable(typeof(ModMetadata))] + public partial class ModMetadataJsonSerializerContext : JsonSerializerContext + { + } +} diff --git a/src/Ryujinx.Common/Logging/LogClass.cs b/src/Ryujinx.Common/Logging/LogClass.cs index f277dd06d..1b404a06a 100644 --- a/src/Ryujinx.Common/Logging/LogClass.cs +++ b/src/Ryujinx.Common/Logging/LogClass.cs @@ -70,7 +70,7 @@ namespace Ryujinx.Common.Logging ServiceVi, SurfaceFlinger, TamperMachine, - Ui, + UI, Vic, } } diff --git a/src/Ryujinx.Common/Logging/Logger.cs b/src/Ryujinx.Common/Logging/Logger.cs index f03a7fd8f..db46739ac 100644 --- a/src/Ryujinx.Common/Logging/Logger.cs +++ b/src/Ryujinx.Common/Logging/Logger.cs @@ -3,6 +3,7 @@ using Ryujinx.Common.SystemInterop; using System; using System.Collections.Generic; using System.Diagnostics; +using System.IO; using System.Runtime.CompilerServices; using System.Threading; @@ -22,6 +23,9 @@ namespace Ryujinx.Common.Logging public readonly struct Log { + private static readonly string _homeDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); + private static readonly string _homeDirRedacted = Path.Combine(Directory.GetParent(_homeDir).FullName, "[redacted]"); + internal readonly LogLevel Level; internal Log(LogLevel level) @@ -100,7 +104,12 @@ namespace Ryujinx.Common.Logging } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static string FormatMessage(LogClass logClass, string caller, string message) => $"{logClass} {caller}: {message}"; + private static string FormatMessage(LogClass logClass, string caller, string message) + { + message = message.Replace(_homeDir, _homeDirRedacted); + + return $"{logClass} {caller}: {message}"; + } } public static Log? Debug { get; private set; } diff --git a/src/Ryujinx.Common/Logging/Targets/FileLogTarget.cs b/src/Ryujinx.Common/Logging/Targets/FileLogTarget.cs index 8aa2a26b9..8d4ede96c 100644 --- a/src/Ryujinx.Common/Logging/Targets/FileLogTarget.cs +++ b/src/Ryujinx.Common/Logging/Targets/FileLogTarget.cs @@ -13,31 +13,82 @@ namespace Ryujinx.Common.Logging.Targets string ILogTarget.Name { get => _name; } - public FileLogTarget(string path, string name) - : this(path, name, FileShare.Read, FileMode.Append) - { } + public FileLogTarget(string name, FileStream fileStream) + { + _name = name; + _logWriter = new StreamWriter(fileStream); + _formatter = new DefaultLogFormatter(); + } - public FileLogTarget(string path, string name, FileShare fileShare, FileMode fileMode) + public static FileStream PrepareLogFile(string path) { // Ensure directory is present - DirectoryInfo logDir = new(Path.Combine(path, "Logs")); - logDir.Create(); + DirectoryInfo logDir; + try + { + logDir = new DirectoryInfo(path); + } + catch (ArgumentException exception) + { + Logger.Warning?.Print(LogClass.Application, $"Logging directory path ('{path}') was invalid: {exception}"); + + return null; + } + + try + { + logDir.Create(); + } + catch (IOException exception) + { + Logger.Warning?.Print(LogClass.Application, $"Logging directory could not be created '{logDir}': {exception}"); + + return null; + } // Clean up old logs, should only keep 3 FileInfo[] files = logDir.GetFiles("*.log").OrderBy((info => info.CreationTime)).ToArray(); for (int i = 0; i < files.Length - 2; i++) { - files[i].Delete(); + try + { + files[i].Delete(); + } + catch (UnauthorizedAccessException exception) + { + Logger.Warning?.Print(LogClass.Application, $"Old log file could not be deleted '{files[i].FullName}': {exception}"); + + return null; + } + catch (IOException exception) + { + Logger.Warning?.Print(LogClass.Application, $"Old log file could not be deleted '{files[i].FullName}': {exception}"); + + return null; + } } - string version = ReleaseInformation.GetVersion(); + string version = ReleaseInformation.Version; // Get path for the current time path = Path.Combine(logDir.FullName, $"Ryujinx_{version}_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.log"); - _name = name; - _logWriter = new StreamWriter(File.Open(path, fileMode, FileAccess.Write, fileShare)); - _formatter = new DefaultLogFormatter(); + try + { + return File.Open(path, FileMode.Append, FileAccess.Write, FileShare.Read); + } + catch (UnauthorizedAccessException exception) + { + Logger.Warning?.Print(LogClass.Application, $"Log file could not be created '{path}': {exception}"); + + return null; + } + catch (IOException exception) + { + Logger.Warning?.Print(LogClass.Application, $"Log file could not be created '{path}': {exception}"); + + return null; + } } public void Log(object sender, LogEventArgs args) diff --git a/src/Ryujinx.Common/Memory/StructArrayHelpers.cs b/src/Ryujinx.Common/Memory/StructArrayHelpers.cs index 94ce8d2f5..762c73889 100644 --- a/src/Ryujinx.Common/Memory/StructArrayHelpers.cs +++ b/src/Ryujinx.Common/Memory/StructArrayHelpers.cs @@ -744,6 +744,17 @@ namespace Ryujinx.Common.Memory public Span AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length); } + public struct Array65 : IArray where T : unmanaged + { + T _e0; + Array64 _other; + public readonly int Length => 65; + public ref T this[int index] => ref AsSpan()[index]; + + [Pure] + public Span AsSpan() => MemoryMarshal.CreateSpan(ref _e0, Length); + } + public struct Array73 : IArray where T : unmanaged { T _e0; diff --git a/src/Ryujinx.Common/Memory/StructByteArrayHelpers.cs b/src/Ryujinx.Common/Memory/StructByteArrayHelpers.cs index 3b0666628..79b7d681a 100644 --- a/src/Ryujinx.Common/Memory/StructByteArrayHelpers.cs +++ b/src/Ryujinx.Common/Memory/StructByteArrayHelpers.cs @@ -63,6 +63,18 @@ namespace Ryujinx.Common.Memory public Span AsSpan() => MemoryMarshal.CreateSpan(ref _element, Size); } + [StructLayout(LayoutKind.Sequential, Size = Size, Pack = 1)] + public struct ByteArray3000 : IArray + { + private const int Size = 3000; + + byte _element; + + public readonly int Length => Size; + public ref byte this[int index] => ref AsSpan()[index]; + public Span AsSpan() => MemoryMarshal.CreateSpan(ref _element, Size); + } + [StructLayout(LayoutKind.Sequential, Size = Size, Pack = 1)] public struct ByteArray4096 : IArray { diff --git a/src/Ryujinx.Common/ReleaseInformation.cs b/src/Ryujinx.Common/ReleaseInformation.cs index ab65a98f3..774ae012a 100644 --- a/src/Ryujinx.Common/ReleaseInformation.cs +++ b/src/Ryujinx.Common/ReleaseInformation.cs @@ -1,5 +1,3 @@ -using Ryujinx.Common.Configuration; -using System; using System.Reflection; namespace Ryujinx.Common @@ -9,50 +7,25 @@ namespace Ryujinx.Common { private const string FlatHubChannelOwner = "flathub"; - public const string BuildVersion = "%%RYUJINX_BUILD_VERSION%%"; - public const string BuildGitHash = "%%RYUJINX_BUILD_GIT_HASH%%"; - public const string ReleaseChannelName = "%%RYUJINX_TARGET_RELEASE_CHANNEL_NAME%%"; + private const string BuildVersion = "%%RYUJINX_BUILD_VERSION%%"; + private const string BuildGitHash = "%%RYUJINX_BUILD_GIT_HASH%%"; + private const string ReleaseChannelName = "%%RYUJINX_TARGET_RELEASE_CHANNEL_NAME%%"; + private const string ConfigFileName = "%%RYUJINX_CONFIG_FILE_NAME%%"; + public const string ReleaseChannelOwner = "%%RYUJINX_TARGET_RELEASE_CHANNEL_OWNER%%"; public const string ReleaseChannelRepo = "%%RYUJINX_TARGET_RELEASE_CHANNEL_REPO%%"; - public static bool IsValid() - { - return !BuildGitHash.StartsWith("%%") && - !ReleaseChannelName.StartsWith("%%") && - !ReleaseChannelOwner.StartsWith("%%") && - !ReleaseChannelRepo.StartsWith("%%"); - } + public static string ConfigName => !ConfigFileName.StartsWith("%%") ? ConfigFileName : "Config.json"; - public static bool IsFlatHubBuild() - { - return IsValid() && ReleaseChannelOwner.Equals(FlatHubChannelOwner); - } + public static bool IsValid => + !BuildGitHash.StartsWith("%%") && + !ReleaseChannelName.StartsWith("%%") && + !ReleaseChannelOwner.StartsWith("%%") && + !ReleaseChannelRepo.StartsWith("%%") && + !ConfigFileName.StartsWith("%%"); - public static string GetVersion() - { - if (IsValid()) - { - return BuildVersion; - } + public static bool IsFlatHubBuild => IsValid && ReleaseChannelOwner.Equals(FlatHubChannelOwner); - return Assembly.GetEntryAssembly().GetCustomAttribute().InformationalVersion; - } - -#if FORCE_EXTERNAL_BASE_DIR - public static string GetBaseApplicationDirectory() - { - return AppDataManager.BaseDirPath; - } -#else - public static string GetBaseApplicationDirectory() - { - if (IsFlatHubBuild() || OperatingSystem.IsMacOS()) - { - return AppDataManager.BaseDirPath; - } - - return AppDomain.CurrentDomain.BaseDirectory; - } -#endif + public static string Version => IsValid ? BuildVersion : Assembly.GetEntryAssembly()!.GetCustomAttribute()?.InformationalVersion; } } diff --git a/src/Ryujinx.Common/Utilities/FileSystemUtils.cs b/src/Ryujinx.Common/Utilities/FileSystemUtils.cs new file mode 100644 index 000000000..e76c2b60b --- /dev/null +++ b/src/Ryujinx.Common/Utilities/FileSystemUtils.cs @@ -0,0 +1,48 @@ +using System.IO; + +namespace Ryujinx.Common.Utilities +{ + public static class FileSystemUtils + { + public static void CopyDirectory(string sourceDir, string destinationDir, bool recursive) + { + // Get information about the source directory + var dir = new DirectoryInfo(sourceDir); + + // Check if the source directory exists + if (!dir.Exists) + { + throw new DirectoryNotFoundException($"Source directory not found: {dir.FullName}"); + } + + // Cache directories before we start copying + DirectoryInfo[] dirs = dir.GetDirectories(); + + // Create the destination directory + Directory.CreateDirectory(destinationDir); + + // Get the files in the source directory and copy to the destination directory + foreach (FileInfo file in dir.GetFiles()) + { + string targetFilePath = Path.Combine(destinationDir, file.Name); + file.CopyTo(targetFilePath); + } + + // If recursive and copying subdirectories, recursively call this method + if (recursive) + { + foreach (DirectoryInfo subDir in dirs) + { + string newDestinationDir = Path.Combine(destinationDir, subDir.Name); + CopyDirectory(subDir.FullName, newDestinationDir, true); + } + } + } + + public static void MoveDirectory(string sourceDir, string destinationDir) + { + CopyDirectory(sourceDir, destinationDir, true); + Directory.Delete(sourceDir, true); + } + } +} diff --git a/src/Ryujinx.Cpu/AppleHv/HvCpuContext.cs b/src/Ryujinx.Cpu/AppleHv/HvCpuContext.cs index 2c4ff2b64..99e4c0479 100644 --- a/src/Ryujinx.Cpu/AppleHv/HvCpuContext.cs +++ b/src/Ryujinx.Cpu/AppleHv/HvCpuContext.cs @@ -40,5 +40,9 @@ namespace Ryujinx.Cpu.AppleHv public void PrepareCodeRange(ulong address, ulong size) { } + + public void Dispose() + { + } } } diff --git a/src/Ryujinx.Cpu/DummyDiskCacheLoadState.cs b/src/Ryujinx.Cpu/DummyDiskCacheLoadState.cs new file mode 100644 index 000000000..d050bddeb --- /dev/null +++ b/src/Ryujinx.Cpu/DummyDiskCacheLoadState.cs @@ -0,0 +1,17 @@ +using System; + +namespace Ryujinx.Cpu +{ + public class DummyDiskCacheLoadState : IDiskCacheLoadState + { +#pragma warning disable CS0067 // The event is never used + /// + public event Action StateChanged; +#pragma warning restore CS0067 + + /// + public void Cancel() + { + } + } +} diff --git a/src/Ryujinx.Cpu/ICpuContext.cs b/src/Ryujinx.Cpu/ICpuContext.cs index 80916d1ca..edcebdfc4 100644 --- a/src/Ryujinx.Cpu/ICpuContext.cs +++ b/src/Ryujinx.Cpu/ICpuContext.cs @@ -1,9 +1,11 @@ +using System; + namespace Ryujinx.Cpu { /// /// CPU context interface. /// - public interface ICpuContext + public interface ICpuContext : IDisposable { /// /// Creates a new execution context that will store thread CPU register state when executing guest code. diff --git a/src/Ryujinx.Cpu/Jit/JitCpuContext.cs b/src/Ryujinx.Cpu/Jit/JitCpuContext.cs index 24bc1e595..dce0490a4 100644 --- a/src/Ryujinx.Cpu/Jit/JitCpuContext.cs +++ b/src/Ryujinx.Cpu/Jit/JitCpuContext.cs @@ -1,5 +1,7 @@ using ARMeilleure.Memory; using ARMeilleure.Translation; +using Ryujinx.Cpu.Signal; +using Ryujinx.Memory; namespace Ryujinx.Cpu.Jit { @@ -11,7 +13,13 @@ namespace Ryujinx.Cpu.Jit public JitCpuContext(ITickSource tickSource, IMemoryManager memory, bool for64Bit) { _tickSource = tickSource; - _translator = new Translator(new JitMemoryAllocator(), memory, for64Bit); + _translator = new Translator(new JitMemoryAllocator(forJit: true), memory, for64Bit); + + if (memory.Type.IsHostMapped()) + { + NativeSignalHandler.InitializeSignalHandler(MemoryBlock.GetPageSize()); + } + memory.UnmapEvent += UnmapHandler; } @@ -49,5 +57,9 @@ namespace Ryujinx.Cpu.Jit { _translator.PrepareCodeRange(address, size); } + + public void Dispose() + { + } } } diff --git a/src/Ryujinx.Cpu/Jit/JitMemoryAllocator.cs b/src/Ryujinx.Cpu/Jit/JitMemoryAllocator.cs index 529a1a808..06c11b7b9 100644 --- a/src/Ryujinx.Cpu/Jit/JitMemoryAllocator.cs +++ b/src/Ryujinx.Cpu/Jit/JitMemoryAllocator.cs @@ -5,9 +5,14 @@ namespace Ryujinx.Cpu.Jit { public class JitMemoryAllocator : IJitMemoryAllocator { - public IJitMemoryBlock Allocate(ulong size) => new JitMemoryBlock(size, MemoryAllocationFlags.None); - public IJitMemoryBlock Reserve(ulong size) => new JitMemoryBlock(size, MemoryAllocationFlags.Reserve | MemoryAllocationFlags.Jit); + private readonly MemoryAllocationFlags _jitFlag; - public ulong GetPageSize() => MemoryBlock.GetPageSize(); + public JitMemoryAllocator(bool forJit = false) + { + _jitFlag = forJit ? MemoryAllocationFlags.Jit : MemoryAllocationFlags.None; + } + + public IJitMemoryBlock Allocate(ulong size) => new JitMemoryBlock(size, MemoryAllocationFlags.None); + public IJitMemoryBlock Reserve(ulong size) => new JitMemoryBlock(size, MemoryAllocationFlags.Reserve | _jitFlag); } } diff --git a/src/Ryujinx.Cpu/Jit/JitMemoryBlock.cs b/src/Ryujinx.Cpu/Jit/JitMemoryBlock.cs index bcacd116a..bd07d349c 100644 --- a/src/Ryujinx.Cpu/Jit/JitMemoryBlock.cs +++ b/src/Ryujinx.Cpu/Jit/JitMemoryBlock.cs @@ -16,6 +16,7 @@ namespace Ryujinx.Cpu.Jit } 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); diff --git a/src/Ryujinx.Cpu/LightningJit/AarchCompiler.cs b/src/Ryujinx.Cpu/LightningJit/AarchCompiler.cs new file mode 100644 index 000000000..ee4fc439f --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/AarchCompiler.cs @@ -0,0 +1,32 @@ +using ARMeilleure.Common; +using ARMeilleure.Memory; +using Ryujinx.Cpu.LightningJit.Arm32; +using Ryujinx.Cpu.LightningJit.Arm64; +using Ryujinx.Cpu.LightningJit.State; +using System; +using System.Runtime.InteropServices; + +namespace Ryujinx.Cpu.LightningJit +{ + class AarchCompiler + { + public static CompiledFunction Compile( + CpuPreset cpuPreset, + IMemoryManager memoryManager, + ulong address, + AddressTable funcTable, + IntPtr dispatchStubPtr, + ExecutionMode executionMode, + Architecture targetArch) + { + if (executionMode == ExecutionMode.Aarch64) + { + return A64Compiler.Compile(cpuPreset, memoryManager, address, funcTable, dispatchStubPtr, targetArch); + } + else + { + return A32Compiler.Compile(cpuPreset, memoryManager, address, funcTable, dispatchStubPtr, executionMode == ExecutionMode.Aarch32Thumb, targetArch); + } + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/AddressForm.cs b/src/Ryujinx.Cpu/LightningJit/AddressForm.cs new file mode 100644 index 000000000..a9ad7e8a3 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/AddressForm.cs @@ -0,0 +1,18 @@ + +namespace Ryujinx.Cpu.LightningJit +{ + enum AddressForm : byte + { + None, + OffsetReg, + PostIndexed, + PreIndexed, + SignedScaled, + UnsignedScaled, + BaseRegister, + BasePlusOffset, + Literal, + StructNoOffset, + StructPostIndexedReg, + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/A32Compiler.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/A32Compiler.cs new file mode 100644 index 000000000..7f6024d47 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/A32Compiler.cs @@ -0,0 +1,30 @@ +using ARMeilleure.Common; +using ARMeilleure.Memory; +using Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64; +using System; +using System.Runtime.InteropServices; + +namespace Ryujinx.Cpu.LightningJit.Arm32 +{ + static class A32Compiler + { + public static CompiledFunction Compile( + CpuPreset cpuPreset, + IMemoryManager memoryManager, + ulong address, + AddressTable funcTable, + IntPtr dispatchStubPtr, + bool isThumb, + Architecture targetArch) + { + if (targetArch == Architecture.Arm64) + { + return Compiler.Compile(cpuPreset, memoryManager, address, funcTable, dispatchStubPtr, isThumb); + } + else + { + throw new PlatformNotSupportedException(); + } + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Block.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Block.cs new file mode 100644 index 000000000..c4568995c --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Block.cs @@ -0,0 +1,106 @@ +using System.Collections.Generic; +using System.Diagnostics; + +namespace Ryujinx.Cpu.LightningJit.Arm32 +{ + class Block + { + public readonly ulong Address; + public readonly ulong EndAddress; + public readonly List Instructions; + public readonly bool EndsWithBranch; + public readonly bool HasHostCall; + public readonly bool HasHostCallSkipContext; + public readonly bool IsTruncated; + public readonly bool IsLoopEnd; + public readonly bool IsThumb; + + public Block( + ulong address, + ulong endAddress, + List instructions, + bool endsWithBranch, + bool hasHostCall, + bool hasHostCallSkipContext, + bool isTruncated, + bool isLoopEnd, + bool isThumb) + { + Debug.Assert(isThumb || (int)((endAddress - address) / 4) == instructions.Count); + + Address = address; + EndAddress = endAddress; + Instructions = instructions; + EndsWithBranch = endsWithBranch; + HasHostCall = hasHostCall; + HasHostCallSkipContext = hasHostCallSkipContext; + IsTruncated = isTruncated; + IsLoopEnd = isLoopEnd; + IsThumb = isThumb; + } + + public (Block, Block) SplitAtAddress(ulong address) + { + int splitIndex = FindSplitIndex(address); + + if (splitIndex < 0) + { + return (null, null); + } + + int splitCount = Instructions.Count - splitIndex; + + // Technically those are valid, but we don't want to create empty blocks. + Debug.Assert(splitIndex != 0); + Debug.Assert(splitCount != 0); + + Block leftBlock = new( + Address, + address, + Instructions.GetRange(0, splitIndex), + false, + HasHostCall, + HasHostCallSkipContext, + false, + false, + IsThumb); + + Block rightBlock = new( + address, + EndAddress, + Instructions.GetRange(splitIndex, splitCount), + EndsWithBranch, + HasHostCall, + HasHostCallSkipContext, + IsTruncated, + IsLoopEnd, + IsThumb); + + return (leftBlock, rightBlock); + } + + private int FindSplitIndex(ulong address) + { + if (IsThumb) + { + ulong pc = Address; + + for (int index = 0; index < Instructions.Count; index++) + { + if (pc == address) + { + return index; + } + + pc += Instructions[index].Flags.HasFlag(InstFlags.Thumb16) ? 2UL : 4UL; + } + + return -1; + } + else + { + return (int)((address - Address) / 4); + } + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/BranchType.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/BranchType.cs new file mode 100644 index 000000000..6d9fdf2c4 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/BranchType.cs @@ -0,0 +1,15 @@ +namespace Ryujinx.Cpu.LightningJit.Arm32 +{ + enum BranchType + { + Branch, + Call, + IndirectBranch, + TableBranchByte, + TableBranchHalfword, + IndirectCall, + SyncPoint, + SoftwareInterrupt, + ReadCntpct, + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/CodeGenContext.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/CodeGenContext.cs new file mode 100644 index 000000000..f55e2bb99 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/CodeGenContext.cs @@ -0,0 +1,198 @@ +using ARMeilleure.Memory; +using Ryujinx.Cpu.LightningJit.CodeGen.Arm64; +using System; +using System.Collections.Generic; + +namespace Ryujinx.Cpu.LightningJit.Arm32 +{ + class CodeGenContext + { + public CodeWriter CodeWriter { get; } + public Assembler Arm64Assembler { get; } + public RegisterAllocator RegisterAllocator { get; } + + public MemoryManagerType MemoryManagerType { get; } + + private uint _instructionAddress; + + public bool IsThumb { get; } + public uint Pc { get; private set; } + public bool InITBlock { get; private set; } + + private InstInfo _nextInstruction; + private bool _skipNextInstruction; + + private readonly ArmCondition[] _itConditions; + private int _itCount; + + private readonly List _pendingBranches; + + private bool _nzcvModified; + + public CodeGenContext(CodeWriter codeWriter, Assembler arm64Assembler, RegisterAllocator registerAllocator, MemoryManagerType mmType, bool isThumb) + { + CodeWriter = codeWriter; + Arm64Assembler = arm64Assembler; + RegisterAllocator = registerAllocator; + MemoryManagerType = mmType; + _itConditions = new ArmCondition[4]; + _pendingBranches = new(); + IsThumb = isThumb; + } + + public void SetPc(uint address) + { + // Due to historical reasons, the PC value is always 2 instructions ahead on 32-bit Arm CPUs. + Pc = address + (IsThumb ? 4u : 8u); + _instructionAddress = address; + } + + public void SetNextInstruction(InstInfo info) + { + _nextInstruction = info; + } + + public InstInfo PeekNextInstruction() + { + return _nextInstruction; + } + + public void SetSkipNextInstruction() + { + _skipNextInstruction = true; + } + + public bool ConsumeSkipNextInstruction() + { + bool skip = _skipNextInstruction; + _skipNextInstruction = false; + + return skip; + } + + public void AddPendingBranch(InstName name, int offset) + { + _pendingBranches.Add(new(BranchType.Branch, Pc + (uint)offset, 0u, name, CodeWriter.InstructionPointer)); + } + + public void AddPendingCall(uint targetAddress, uint nextAddress) + { + _pendingBranches.Add(new(BranchType.Call, targetAddress, nextAddress, InstName.BlI, CodeWriter.InstructionPointer)); + + RegisterAllocator.EnsureTempGprRegisters(1); + RegisterAllocator.MarkGprAsUsed(RegisterUtils.LrRegister); + } + + public void AddPendingIndirectBranch(InstName name, uint targetRegister) + { + _pendingBranches.Add(new(BranchType.IndirectBranch, targetRegister, 0u, name, CodeWriter.InstructionPointer)); + + RegisterAllocator.MarkGprAsUsed((int)targetRegister); + } + + public void AddPendingTableBranch(uint rn, uint rm, bool halfword) + { + _pendingBranches.Add(new(halfword ? BranchType.TableBranchHalfword : BranchType.TableBranchByte, rn, rm, InstName.Tbb, CodeWriter.InstructionPointer)); + + RegisterAllocator.EnsureTempGprRegisters(2); + RegisterAllocator.MarkGprAsUsed((int)rn); + RegisterAllocator.MarkGprAsUsed((int)rm); + } + + public void AddPendingIndirectCall(uint targetRegister, uint nextAddress) + { + _pendingBranches.Add(new(BranchType.IndirectCall, targetRegister, nextAddress, InstName.BlxR, CodeWriter.InstructionPointer)); + + RegisterAllocator.EnsureTempGprRegisters(targetRegister == RegisterUtils.LrRegister ? 1 : 0); + RegisterAllocator.MarkGprAsUsed((int)targetRegister); + RegisterAllocator.MarkGprAsUsed(RegisterUtils.LrRegister); + } + + public void AddPendingSyncPoint() + { + _pendingBranches.Add(new(BranchType.SyncPoint, 0, 0, default, CodeWriter.InstructionPointer)); + + RegisterAllocator.EnsureTempGprRegisters(1); + } + + public void AddPendingBkpt(uint imm) + { + _pendingBranches.Add(new(BranchType.SoftwareInterrupt, imm, _instructionAddress, InstName.Bkpt, CodeWriter.InstructionPointer)); + + RegisterAllocator.EnsureTempGprRegisters(1); + } + + public void AddPendingSvc(uint imm) + { + _pendingBranches.Add(new(BranchType.SoftwareInterrupt, imm, _instructionAddress, InstName.Svc, CodeWriter.InstructionPointer)); + + RegisterAllocator.EnsureTempGprRegisters(1); + } + + public void AddPendingUdf(uint imm) + { + _pendingBranches.Add(new(BranchType.SoftwareInterrupt, imm, _instructionAddress, InstName.Udf, CodeWriter.InstructionPointer)); + + RegisterAllocator.EnsureTempGprRegisters(1); + } + + public void AddPendingReadCntpct(uint rt, uint rt2) + { + _pendingBranches.Add(new(BranchType.ReadCntpct, rt, rt2, InstName.Mrrc, CodeWriter.InstructionPointer)); + + RegisterAllocator.EnsureTempGprRegisters(1); + } + + public IEnumerable GetPendingBranches() + { + return _pendingBranches; + } + + public void SetItBlockStart(ReadOnlySpan conditions) + { + _itCount = conditions.Length; + + for (int index = 0; index < conditions.Length; index++) + { + _itConditions[index] = conditions[index]; + } + + InITBlock = true; + } + + public bool ConsumeItCondition(out ArmCondition condition) + { + if (_itCount != 0) + { + condition = _itConditions[--_itCount]; + + return true; + } + + condition = ArmCondition.Al; + + return false; + } + + public void UpdateItState() + { + if (_itCount == 0) + { + InITBlock = false; + } + } + + public void SetNzcvModified() + { + _nzcvModified = true; + } + + public bool ConsumeNzcvModified() + { + bool modified = _nzcvModified; + _nzcvModified = false; + + return modified; + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Decoder.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Decoder.cs new file mode 100644 index 000000000..8a2b389ad --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Decoder.cs @@ -0,0 +1,556 @@ +using ARMeilleure.Memory; +using Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64; +using Ryujinx.Cpu.LightningJit.CodeGen.Arm64; +using System.Collections.Generic; +using System.Diagnostics; + +namespace Ryujinx.Cpu.LightningJit.Arm32 +{ + static class Decoder where T : IInstEmit + { + public static MultiBlock DecodeMulti(CpuPreset cpuPreset, IMemoryManager memoryManager, ulong address, bool isThumb) + { + List blocks = new(); + List branchTargets = new(); + + while (true) + { + Block block = Decode(cpuPreset, memoryManager, address, isThumb); + + if (!block.IsTruncated && TryGetBranchTarget(block, out ulong targetAddress)) + { + branchTargets.Add(targetAddress); + } + + blocks.Add(block); + + if (block.IsTruncated || !HasNextBlock(block, block.EndAddress - 4UL, branchTargets)) + { + break; + } + + address = block.EndAddress; + } + + branchTargets.Sort(); + SplitBlocks(blocks, branchTargets); + + return new(blocks); + } + + private static bool TryGetBranchTarget(Block block, out ulong targetAddress) + { + // PC is 2 instructions ahead, since the end address is already one instruction after the last one, we just need to add + // another instruction. + + ulong pc = block.EndAddress + (block.IsThumb ? 2UL : 4UL); + + return TryGetBranchTarget(block.Instructions[^1].Name, block.Instructions[^1].Flags, pc, block.Instructions[^1].Encoding, block.IsThumb, out targetAddress); + } + + private static bool TryGetBranchTarget(InstName name, InstFlags flags, ulong pc, uint encoding, bool isThumb, out ulong targetAddress) + { + int originalOffset; + + switch (name) + { + case InstName.B: + if (isThumb) + { + if (flags.HasFlag(InstFlags.Thumb16)) + { + if ((encoding & (1u << 29)) != 0) + { + InstImm11b16w11 inst = new(encoding); + + originalOffset = ImmUtils.ExtractT16SImm11Times2(inst.Imm11); + } + else + { + InstCondb24w4Imm8b16w8 inst = new(encoding); + + originalOffset = ImmUtils.ExtractT16SImm8Times2(inst.Imm8); + } + } + else + { + if ((encoding & (1u << 12)) != 0) + { + InstSb26w1Imm10b16w10J1b13w1J2b11w1Imm11b0w11 inst = new(encoding); + + originalOffset = ImmUtils.CombineSImm24Times2(inst.Imm11, inst.Imm10, inst.J1, inst.J2, inst.S); + } + else + { + InstSb26w1Condb22w4Imm6b16w6J1b13w1J2b11w1Imm11b0w11 inst = new(encoding); + + originalOffset = ImmUtils.CombineSImm20Times2(inst.Imm11, inst.Imm6, inst.J1, inst.J2, inst.S); + } + } + } + else + { + originalOffset = ImmUtils.ExtractSImm24Times4(encoding); + } + + targetAddress = pc + (ulong)originalOffset; + Debug.Assert((targetAddress & 1) == 0); + + return true; + + case InstName.Cbnz: + originalOffset = ImmUtils.ExtractT16UImm5Times2(encoding); + targetAddress = pc + (ulong)originalOffset; + Debug.Assert((targetAddress & 1) == 0); + + return true; + } + + targetAddress = 0; + + return false; + } + + private static void SplitBlocks(List blocks, List branchTargets) + { + int btIndex = 0; + + while (btIndex < branchTargets.Count) + { + for (int blockIndex = 0; blockIndex < blocks.Count && btIndex < branchTargets.Count; blockIndex++) + { + Block block = blocks[blockIndex]; + ulong currentBranchTarget = branchTargets[btIndex]; + + while (currentBranchTarget >= block.Address && currentBranchTarget < block.EndAddress) + { + if (block.Address != currentBranchTarget) + { + (Block leftBlock, Block rightBlock) = block.SplitAtAddress(currentBranchTarget); + + if (leftBlock != null && rightBlock != null) + { + blocks.Insert(blockIndex, leftBlock); + blocks[blockIndex + 1] = rightBlock; + + block = leftBlock; + } + else + { + // Split can only fail in thumb mode, where the instruction size is not fixed. + + Debug.Assert(block.IsThumb); + } + } + + btIndex++; + + while (btIndex < branchTargets.Count && branchTargets[btIndex] == currentBranchTarget) + { + btIndex++; + } + + if (btIndex >= branchTargets.Count) + { + break; + } + + currentBranchTarget = branchTargets[btIndex]; + } + } + + Debug.Assert(btIndex < int.MaxValue); + btIndex++; + } + } + + private static bool HasNextBlock(in Block block, ulong pc, List branchTargets) + { + InstFlags lastInstFlags = block.Instructions[^1].Flags; + + // Thumb has separate encodings for conditional and unconditional branch instructions. + if (lastInstFlags.HasFlag(InstFlags.Cond) && (block.IsThumb || (ArmCondition)(block.Instructions[^1].Encoding >> 28) < ArmCondition.Al)) + { + return true; + } + + switch (block.Instructions[^1].Name) + { + case InstName.B: + return branchTargets.Contains(pc + 4UL) || + (TryGetBranchTarget(block, out ulong targetAddress) && targetAddress >= pc && targetAddress < pc + 0x1000); + + case InstName.Bx: + case InstName.Bxj: + return branchTargets.Contains(pc + 4UL); + + case InstName.Cbnz: + case InstName.BlI: + case InstName.BlxR: + return true; + } + + if (WritesToPC(block.Instructions[^1].Encoding, block.Instructions[^1].Name, lastInstFlags, block.IsThumb)) + { + return branchTargets.Contains(pc + 4UL); + } + + return !block.EndsWithBranch; + } + + private static Block Decode(CpuPreset cpuPreset, IMemoryManager memoryManager, ulong address, bool isThumb) + { + ulong startAddress = address; + + List insts = new(); + + uint encoding; + InstMeta meta; + InstFlags extraFlags = InstFlags.None; + bool hasHostCall = false; + bool hasHostCallSkipContext = false; + bool isTruncated = false; + + do + { + if (!memoryManager.IsMapped(address)) + { + encoding = 0; + meta = default; + isTruncated = true; + break; + } + + if (isThumb) + { + encoding = (uint)memoryManager.Read(address) << 16; + address += 2UL; + + extraFlags = InstFlags.Thumb16; + + if (!InstTableT16.TryGetMeta(encoding, cpuPreset.Version, cpuPreset.Features, out meta)) + { + encoding |= memoryManager.Read(address); + + if (InstTableT32.TryGetMeta(encoding, cpuPreset.Version, cpuPreset.Features, out meta)) + { + address += 2UL; + extraFlags = InstFlags.None; + } + } + } + else + { + encoding = memoryManager.Read(address); + address += 4UL; + + meta = InstTableA32.GetMeta(encoding, cpuPreset.Version, cpuPreset.Features); + } + + if (meta.Name.IsSystemOrCall()) + { + if (!hasHostCall) + { + hasHostCall = InstEmitSystem.NeedsCall(meta.Name); + } + + if (!hasHostCallSkipContext) + { + hasHostCallSkipContext = meta.Name.IsCall() || InstEmitSystem.NeedsCallSkipContext(meta.Name); + } + } + + insts.Add(new(encoding, meta.Name, meta.EmitFunc, meta.Flags | extraFlags)); + } + while (!IsControlFlow(encoding, meta.Name, meta.Flags | extraFlags, isThumb)); + + bool isLoopEnd = false; + + if (!isTruncated && IsBackwardsBranch(meta.Name, encoding)) + { + isLoopEnd = true; + hasHostCallSkipContext = true; + } + + return new( + startAddress, + address, + insts, + !isTruncated, + hasHostCall, + hasHostCallSkipContext, + isTruncated, + isLoopEnd, + isThumb); + } + + private static bool IsControlFlow(uint encoding, InstName name, InstFlags flags, bool isThumb) + { + switch (name) + { + case InstName.B: + case InstName.BlI: + case InstName.BlxR: + case InstName.Bx: + case InstName.Bxj: + case InstName.Cbnz: + case InstName.Tbb: + return true; + } + + return WritesToPC(encoding, name, flags, isThumb); + } + + public static bool WritesToPC(uint encoding, InstName name, InstFlags flags, bool isThumb) + { + return (GetRegisterWriteMask(encoding, name, flags, isThumb) & (1u << RegisterUtils.PcRegister)) != 0; + } + + private static uint GetRegisterWriteMask(uint encoding, InstName name, InstFlags flags, bool isThumb) + { + uint mask = 0; + + if (isThumb) + { + if (flags.HasFlag(InstFlags.Thumb16)) + { + if (flags.HasFlag(InstFlags.Rdn)) + { + mask |= 1u << RegisterUtils.ExtractRdn(flags, encoding); + } + + if (flags.HasFlag(InstFlags.Rd)) + { + mask |= 1u << RegisterUtils.ExtractRdT16(flags, encoding); + } + + Debug.Assert(!flags.HasFlag(InstFlags.RdHi)); + + if (IsRegisterWrite(flags, InstFlags.Rt)) + { + mask |= 1u << RegisterUtils.ExtractRtT16(flags, encoding); + } + + Debug.Assert(!flags.HasFlag(InstFlags.Rt2)); + + if (IsRegisterWrite(flags, InstFlags.Rlist)) + { + mask |= (byte)(encoding >> 16); + + if (name == InstName.Push) + { + mask |= (encoding >> 10) & 0x4000; // LR + } + else if (name == InstName.Pop) + { + mask |= (encoding >> 9) & 0x8000; // PC + } + } + + Debug.Assert(!flags.HasFlag(InstFlags.WBack)); + } + else + { + if (flags.HasFlag(InstFlags.Rd)) + { + mask |= 1u << RegisterUtils.ExtractRdT32(flags, encoding); + } + + if (flags.HasFlag(InstFlags.RdLo)) + { + mask |= 1u << RegisterUtils.ExtractRdLoT32(encoding); + } + + if (flags.HasFlag(InstFlags.RdHi)) + { + mask |= 1u << RegisterUtils.ExtractRdHiT32(encoding); + } + + if (IsRegisterWrite(flags, InstFlags.Rt) && IsRtWrite(name, encoding) && !IsR15RtEncodingSpecial(name, encoding)) + { + mask |= 1u << RegisterUtils.ExtractRtT32(encoding); + } + + if (IsRegisterWrite(flags, InstFlags.Rt2) && IsRtWrite(name, encoding)) + { + mask |= 1u << RegisterUtils.ExtractRt2T32(encoding); + } + + if (IsRegisterWrite(flags, InstFlags.Rlist)) + { + mask |= (ushort)encoding; + } + + if (flags.HasFlag(InstFlags.WBack) && HasWriteBackT32(name, encoding)) + { + mask |= 1u << RegisterUtils.ExtractRn(encoding); // This is at the same bit position as A32. + } + } + } + else + { + if (flags.HasFlag(InstFlags.Rd)) + { + mask |= 1u << RegisterUtils.ExtractRd(flags, encoding); + } + + if (flags.HasFlag(InstFlags.RdHi)) + { + mask |= 1u << RegisterUtils.ExtractRdHi(encoding); + } + + if (IsRegisterWrite(flags, InstFlags.Rt) && IsRtWrite(name, encoding) && !IsR15RtEncodingSpecial(name, encoding)) + { + mask |= 1u << RegisterUtils.ExtractRt(encoding); + } + + if (IsRegisterWrite(flags, InstFlags.Rt2) && IsRtWrite(name, encoding)) + { + mask |= 1u << RegisterUtils.ExtractRt2(encoding); + } + + if (IsRegisterWrite(flags, InstFlags.Rlist)) + { + mask |= (ushort)encoding; + } + + if (flags.HasFlag(InstFlags.WBack) && HasWriteBack(name, encoding)) + { + mask |= 1u << RegisterUtils.ExtractRn(encoding); + } + } + + return mask; + } + + private static bool IsRtWrite(InstName name, uint encoding) + { + // Some instructions can move GPR to FP/SIMD or FP/SIMD to GPR depending on the encoding. + // Detect those cases so that we can tell if we're actually doing a register write. + + switch (name) + { + case InstName.VmovD: + case InstName.VmovH: + case InstName.VmovS: + case InstName.VmovSs: + return (encoding & (1u << 20)) != 0; + } + + return true; + } + + private static bool HasWriteBack(InstName name, uint encoding) + { + if (IsLoadStoreMultiple(name)) + { + return (encoding & (1u << 21)) != 0; + } + + if (IsVLDnVSTn(name)) + { + return (encoding & 0xf) != RegisterUtils.PcRegister; + } + + bool w = (encoding & (1u << 21)) != 0; + bool p = (encoding & (1u << 24)) != 0; + + return !p || w; + } + + private static bool HasWriteBackT32(InstName name, uint encoding) + { + if (IsLoadStoreMultiple(name)) + { + return (encoding & (1u << 21)) != 0; + } + + if (IsVLDnVSTn(name)) + { + return (encoding & 0xf) != RegisterUtils.PcRegister; + } + + return (encoding & (1u << 8)) != 0; + } + + private static bool IsLoadStoreMultiple(InstName name) + { + switch (name) + { + case InstName.Ldm: + case InstName.Ldmda: + case InstName.Ldmdb: + case InstName.LdmE: + case InstName.Ldmib: + case InstName.LdmU: + case InstName.Stm: + case InstName.Stmda: + case InstName.Stmdb: + case InstName.Stmib: + case InstName.StmU: + case InstName.Fldmx: + case InstName.Fstmx: + case InstName.Vldm: + case InstName.Vstm: + return true; + } + + return false; + } + + private static bool IsVLDnVSTn(InstName name) + { + switch (name) + { + case InstName.Vld11: + case InstName.Vld1A: + case InstName.Vld1M: + case InstName.Vld21: + case InstName.Vld2A: + case InstName.Vld2M: + case InstName.Vld31: + case InstName.Vld3A: + case InstName.Vld3M: + case InstName.Vld41: + case InstName.Vld4A: + case InstName.Vld4M: + case InstName.Vst11: + case InstName.Vst1M: + case InstName.Vst21: + case InstName.Vst2M: + case InstName.Vst31: + case InstName.Vst3M: + case InstName.Vst41: + case InstName.Vst4M: + return true; + } + + return false; + } + + private static bool IsR15RtEncodingSpecial(InstName name, uint encoding) + { + if (name == InstName.Vmrs) + { + return ((encoding >> 16) & 0xf) == 1; + } + + return false; + } + + private static bool IsRegisterWrite(InstFlags flags, InstFlags testFlag) + { + return flags.HasFlag(testFlag) && !flags.HasFlag(InstFlags.ReadRd); + } + + private static bool IsBackwardsBranch(InstName name, uint encoding) + { + if (name == InstName.B) + { + return ImmUtils.ExtractSImm24Times4(encoding) < 0; + } + + return false; + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/IInstEmit.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/IInstEmit.cs new file mode 100644 index 000000000..32dc5aeb8 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/IInstEmit.cs @@ -0,0 +1,1231 @@ +namespace Ryujinx.Cpu.LightningJit.Arm32 +{ + interface IInstEmit + { + static abstract void AdcIA1(CodeGenContext context, uint encoding); + static abstract void AdcIT1(CodeGenContext context, uint encoding); + static abstract void AdcRA1(CodeGenContext context, uint encoding); + static abstract void AdcRT1(CodeGenContext context, uint encoding); + static abstract void AdcRT2(CodeGenContext context, uint encoding); + static abstract void AdcRrA1(CodeGenContext context, uint encoding); + static abstract void AddIA1(CodeGenContext context, uint encoding); + static abstract void AddIT1(CodeGenContext context, uint encoding); + static abstract void AddIT2(CodeGenContext context, uint encoding); + static abstract void AddIT3(CodeGenContext context, uint encoding); + static abstract void AddIT4(CodeGenContext context, uint encoding); + static abstract void AddRA1(CodeGenContext context, uint encoding); + static abstract void AddRT1(CodeGenContext context, uint encoding); + static abstract void AddRT2(CodeGenContext context, uint encoding); + static abstract void AddRT3(CodeGenContext context, uint encoding); + static abstract void AddRrA1(CodeGenContext context, uint encoding); + static abstract void AddSpIA1(CodeGenContext context, uint encoding); + static abstract void AddSpIT1(CodeGenContext context, uint encoding); + static abstract void AddSpIT2(CodeGenContext context, uint encoding); + static abstract void AddSpIT3(CodeGenContext context, uint encoding); + static abstract void AddSpIT4(CodeGenContext context, uint encoding); + static abstract void AddSpRA1(CodeGenContext context, uint encoding); + static abstract void AddSpRT1(CodeGenContext context, uint encoding); + static abstract void AddSpRT2(CodeGenContext context, uint encoding); + static abstract void AddSpRT3(CodeGenContext context, uint encoding); + static abstract void AdrA1(CodeGenContext context, uint encoding); + static abstract void AdrA2(CodeGenContext context, uint encoding); + static abstract void AdrT1(CodeGenContext context, uint encoding); + static abstract void AdrT2(CodeGenContext context, uint encoding); + static abstract void AdrT3(CodeGenContext context, uint encoding); + static abstract void AesdA1(CodeGenContext context, uint encoding); + static abstract void AesdT1(CodeGenContext context, uint encoding); + static abstract void AeseA1(CodeGenContext context, uint encoding); + static abstract void AeseT1(CodeGenContext context, uint encoding); + static abstract void AesimcA1(CodeGenContext context, uint encoding); + static abstract void AesimcT1(CodeGenContext context, uint encoding); + static abstract void AesmcA1(CodeGenContext context, uint encoding); + static abstract void AesmcT1(CodeGenContext context, uint encoding); + static abstract void AndIA1(CodeGenContext context, uint encoding); + static abstract void AndIT1(CodeGenContext context, uint encoding); + static abstract void AndRA1(CodeGenContext context, uint encoding); + static abstract void AndRT1(CodeGenContext context, uint encoding); + static abstract void AndRT2(CodeGenContext context, uint encoding); + static abstract void AndRrA1(CodeGenContext context, uint encoding); + static abstract void BA1(CodeGenContext context, uint encoding); + static abstract void BT1(CodeGenContext context, uint encoding); + static abstract void BT2(CodeGenContext context, uint encoding); + static abstract void BT3(CodeGenContext context, uint encoding); + static abstract void BT4(CodeGenContext context, uint encoding); + static abstract void BfcA1(CodeGenContext context, uint encoding); + static abstract void BfcT1(CodeGenContext context, uint encoding); + static abstract void BfiA1(CodeGenContext context, uint encoding); + static abstract void BfiT1(CodeGenContext context, uint encoding); + static abstract void BicIA1(CodeGenContext context, uint encoding); + static abstract void BicIT1(CodeGenContext context, uint encoding); + static abstract void BicRA1(CodeGenContext context, uint encoding); + static abstract void BicRT1(CodeGenContext context, uint encoding); + static abstract void BicRT2(CodeGenContext context, uint encoding); + static abstract void BicRrA1(CodeGenContext context, uint encoding); + static abstract void BkptA1(CodeGenContext context, uint encoding); + static abstract void BkptT1(CodeGenContext context, uint encoding); + static abstract void BlxRA1(CodeGenContext context, uint encoding); + static abstract void BlxRT1(CodeGenContext context, uint encoding); + static abstract void BlIA1(CodeGenContext context, uint encoding); + static abstract void BlIA2(CodeGenContext context, uint encoding); + static abstract void BlIT1(CodeGenContext context, uint encoding); + static abstract void BlIT2(CodeGenContext context, uint encoding); + static abstract void BxA1(CodeGenContext context, uint encoding); + static abstract void BxT1(CodeGenContext context, uint encoding); + static abstract void BxjA1(CodeGenContext context, uint encoding); + static abstract void BxjT1(CodeGenContext context, uint encoding); + static abstract void CbnzT1(CodeGenContext context, uint encoding); + static abstract void ClrbhbA1(CodeGenContext context, uint encoding); + static abstract void ClrbhbT1(CodeGenContext context, uint encoding); + static abstract void ClrexA1(CodeGenContext context, uint encoding); + static abstract void ClrexT1(CodeGenContext context, uint encoding); + static abstract void ClzA1(CodeGenContext context, uint encoding); + static abstract void ClzT1(CodeGenContext context, uint encoding); + static abstract void CmnIA1(CodeGenContext context, uint encoding); + static abstract void CmnIT1(CodeGenContext context, uint encoding); + static abstract void CmnRA1(CodeGenContext context, uint encoding); + static abstract void CmnRT1(CodeGenContext context, uint encoding); + static abstract void CmnRT2(CodeGenContext context, uint encoding); + static abstract void CmnRrA1(CodeGenContext context, uint encoding); + static abstract void CmpIA1(CodeGenContext context, uint encoding); + static abstract void CmpIT1(CodeGenContext context, uint encoding); + static abstract void CmpIT2(CodeGenContext context, uint encoding); + static abstract void CmpRA1(CodeGenContext context, uint encoding); + static abstract void CmpRT1(CodeGenContext context, uint encoding); + static abstract void CmpRT2(CodeGenContext context, uint encoding); + static abstract void CmpRT3(CodeGenContext context, uint encoding); + static abstract void CmpRrA1(CodeGenContext context, uint encoding); + static abstract void CpsA1(CodeGenContext context, uint encoding); + static abstract void CpsT1(CodeGenContext context, uint encoding); + static abstract void CpsT2(CodeGenContext context, uint encoding); + static abstract void Crc32A1(CodeGenContext context, uint encoding); + static abstract void Crc32T1(CodeGenContext context, uint encoding); + static abstract void Crc32cA1(CodeGenContext context, uint encoding); + static abstract void Crc32cT1(CodeGenContext context, uint encoding); + static abstract void CsdbA1(CodeGenContext context, uint encoding); + static abstract void CsdbT1(CodeGenContext context, uint encoding); + static abstract void DbgA1(CodeGenContext context, uint encoding); + static abstract void DbgT1(CodeGenContext context, uint encoding); + static abstract void Dcps1T1(CodeGenContext context, uint encoding); + static abstract void Dcps2T1(CodeGenContext context, uint encoding); + static abstract void Dcps3T1(CodeGenContext context, uint encoding); + static abstract void DmbA1(CodeGenContext context, uint encoding); + static abstract void DmbT1(CodeGenContext context, uint encoding); + static abstract void DsbA1(CodeGenContext context, uint encoding); + static abstract void DsbT1(CodeGenContext context, uint encoding); + static abstract void EorIA1(CodeGenContext context, uint encoding); + static abstract void EorIT1(CodeGenContext context, uint encoding); + static abstract void EorRA1(CodeGenContext context, uint encoding); + static abstract void EorRT1(CodeGenContext context, uint encoding); + static abstract void EorRT2(CodeGenContext context, uint encoding); + static abstract void EorRrA1(CodeGenContext context, uint encoding); + static abstract void EretA1(CodeGenContext context, uint encoding); + static abstract void EretT1(CodeGenContext context, uint encoding); + static abstract void EsbA1(CodeGenContext context, uint encoding); + static abstract void EsbT1(CodeGenContext context, uint encoding); + static abstract void FldmxA1(CodeGenContext context, uint encoding); + static abstract void FldmxT1(CodeGenContext context, uint encoding); + static abstract void FstmxA1(CodeGenContext context, uint encoding); + static abstract void FstmxT1(CodeGenContext context, uint encoding); + static abstract void HltA1(CodeGenContext context, uint encoding); + static abstract void HltT1(CodeGenContext context, uint encoding); + static abstract void HvcA1(CodeGenContext context, uint encoding); + static abstract void HvcT1(CodeGenContext context, uint encoding); + static abstract void IsbA1(CodeGenContext context, uint encoding); + static abstract void IsbT1(CodeGenContext context, uint encoding); + static abstract void ItT1(CodeGenContext context, uint encoding); + static abstract void LdaA1(CodeGenContext context, uint encoding); + static abstract void LdaT1(CodeGenContext context, uint encoding); + static abstract void LdabA1(CodeGenContext context, uint encoding); + static abstract void LdabT1(CodeGenContext context, uint encoding); + static abstract void LdaexA1(CodeGenContext context, uint encoding); + static abstract void LdaexT1(CodeGenContext context, uint encoding); + static abstract void LdaexbA1(CodeGenContext context, uint encoding); + static abstract void LdaexbT1(CodeGenContext context, uint encoding); + static abstract void LdaexdA1(CodeGenContext context, uint encoding); + static abstract void LdaexdT1(CodeGenContext context, uint encoding); + static abstract void LdaexhA1(CodeGenContext context, uint encoding); + static abstract void LdaexhT1(CodeGenContext context, uint encoding); + static abstract void LdahA1(CodeGenContext context, uint encoding); + static abstract void LdahT1(CodeGenContext context, uint encoding); + static abstract void LdcIA1(CodeGenContext context, uint encoding); + static abstract void LdcIT1(CodeGenContext context, uint encoding); + static abstract void LdcLA1(CodeGenContext context, uint encoding); + static abstract void LdcLT1(CodeGenContext context, uint encoding); + static abstract void LdmA1(CodeGenContext context, uint encoding); + static abstract void LdmT1(CodeGenContext context, uint encoding); + static abstract void LdmT2(CodeGenContext context, uint encoding); + static abstract void LdmdaA1(CodeGenContext context, uint encoding); + static abstract void LdmdbA1(CodeGenContext context, uint encoding); + static abstract void LdmdbT1(CodeGenContext context, uint encoding); + static abstract void LdmibA1(CodeGenContext context, uint encoding); + static abstract void LdmEA1(CodeGenContext context, uint encoding); + static abstract void LdmUA1(CodeGenContext context, uint encoding); + static abstract void LdrbtA1(CodeGenContext context, uint encoding); + static abstract void LdrbtA2(CodeGenContext context, uint encoding); + static abstract void LdrbtT1(CodeGenContext context, uint encoding); + static abstract void LdrbIA1(CodeGenContext context, uint encoding); + static abstract void LdrbIT1(CodeGenContext context, uint encoding); + static abstract void LdrbIT2(CodeGenContext context, uint encoding); + static abstract void LdrbIT3(CodeGenContext context, uint encoding); + static abstract void LdrbLA1(CodeGenContext context, uint encoding); + static abstract void LdrbLT1(CodeGenContext context, uint encoding); + static abstract void LdrbRA1(CodeGenContext context, uint encoding); + static abstract void LdrbRT1(CodeGenContext context, uint encoding); + static abstract void LdrbRT2(CodeGenContext context, uint encoding); + static abstract void LdrdIA1(CodeGenContext context, uint encoding); + static abstract void LdrdIT1(CodeGenContext context, uint encoding); + static abstract void LdrdLA1(CodeGenContext context, uint encoding); + static abstract void LdrdLT1(CodeGenContext context, uint encoding); + static abstract void LdrdRA1(CodeGenContext context, uint encoding); + static abstract void LdrexA1(CodeGenContext context, uint encoding); + static abstract void LdrexT1(CodeGenContext context, uint encoding); + static abstract void LdrexbA1(CodeGenContext context, uint encoding); + static abstract void LdrexbT1(CodeGenContext context, uint encoding); + static abstract void LdrexdA1(CodeGenContext context, uint encoding); + static abstract void LdrexdT1(CodeGenContext context, uint encoding); + static abstract void LdrexhA1(CodeGenContext context, uint encoding); + static abstract void LdrexhT1(CodeGenContext context, uint encoding); + static abstract void LdrhtA1(CodeGenContext context, uint encoding); + static abstract void LdrhtA2(CodeGenContext context, uint encoding); + static abstract void LdrhtT1(CodeGenContext context, uint encoding); + static abstract void LdrhIA1(CodeGenContext context, uint encoding); + static abstract void LdrhIT1(CodeGenContext context, uint encoding); + static abstract void LdrhIT2(CodeGenContext context, uint encoding); + static abstract void LdrhIT3(CodeGenContext context, uint encoding); + static abstract void LdrhLA1(CodeGenContext context, uint encoding); + static abstract void LdrhLT1(CodeGenContext context, uint encoding); + static abstract void LdrhRA1(CodeGenContext context, uint encoding); + static abstract void LdrhRT1(CodeGenContext context, uint encoding); + static abstract void LdrhRT2(CodeGenContext context, uint encoding); + static abstract void LdrsbtA1(CodeGenContext context, uint encoding); + static abstract void LdrsbtA2(CodeGenContext context, uint encoding); + static abstract void LdrsbtT1(CodeGenContext context, uint encoding); + static abstract void LdrsbIA1(CodeGenContext context, uint encoding); + static abstract void LdrsbIT1(CodeGenContext context, uint encoding); + static abstract void LdrsbIT2(CodeGenContext context, uint encoding); + static abstract void LdrsbLA1(CodeGenContext context, uint encoding); + static abstract void LdrsbLT1(CodeGenContext context, uint encoding); + static abstract void LdrsbRA1(CodeGenContext context, uint encoding); + static abstract void LdrsbRT1(CodeGenContext context, uint encoding); + static abstract void LdrsbRT2(CodeGenContext context, uint encoding); + static abstract void LdrshtA1(CodeGenContext context, uint encoding); + static abstract void LdrshtA2(CodeGenContext context, uint encoding); + static abstract void LdrshtT1(CodeGenContext context, uint encoding); + static abstract void LdrshIA1(CodeGenContext context, uint encoding); + static abstract void LdrshIT1(CodeGenContext context, uint encoding); + static abstract void LdrshIT2(CodeGenContext context, uint encoding); + static abstract void LdrshLA1(CodeGenContext context, uint encoding); + static abstract void LdrshLT1(CodeGenContext context, uint encoding); + static abstract void LdrshRA1(CodeGenContext context, uint encoding); + static abstract void LdrshRT1(CodeGenContext context, uint encoding); + static abstract void LdrshRT2(CodeGenContext context, uint encoding); + static abstract void LdrtA1(CodeGenContext context, uint encoding); + static abstract void LdrtA2(CodeGenContext context, uint encoding); + static abstract void LdrtT1(CodeGenContext context, uint encoding); + static abstract void LdrIA1(CodeGenContext context, uint encoding); + static abstract void LdrIT1(CodeGenContext context, uint encoding); + static abstract void LdrIT2(CodeGenContext context, uint encoding); + static abstract void LdrIT3(CodeGenContext context, uint encoding); + static abstract void LdrIT4(CodeGenContext context, uint encoding); + static abstract void LdrLA1(CodeGenContext context, uint encoding); + static abstract void LdrLT1(CodeGenContext context, uint encoding); + static abstract void LdrLT2(CodeGenContext context, uint encoding); + static abstract void LdrRA1(CodeGenContext context, uint encoding); + static abstract void LdrRT1(CodeGenContext context, uint encoding); + static abstract void LdrRT2(CodeGenContext context, uint encoding); + static abstract void McrA1(CodeGenContext context, uint encoding); + static abstract void McrT1(CodeGenContext context, uint encoding); + static abstract void McrrA1(CodeGenContext context, uint encoding); + static abstract void McrrT1(CodeGenContext context, uint encoding); + static abstract void MlaA1(CodeGenContext context, uint encoding); + static abstract void MlaT1(CodeGenContext context, uint encoding); + static abstract void MlsA1(CodeGenContext context, uint encoding); + static abstract void MlsT1(CodeGenContext context, uint encoding); + static abstract void MovtA1(CodeGenContext context, uint encoding); + static abstract void MovtT1(CodeGenContext context, uint encoding); + static abstract void MovIA1(CodeGenContext context, uint encoding); + static abstract void MovIA2(CodeGenContext context, uint encoding); + static abstract void MovIT1(CodeGenContext context, uint encoding); + static abstract void MovIT2(CodeGenContext context, uint encoding); + static abstract void MovIT3(CodeGenContext context, uint encoding); + static abstract void MovRA1(CodeGenContext context, uint encoding); + static abstract void MovRT1(CodeGenContext context, uint encoding); + static abstract void MovRT2(CodeGenContext context, uint encoding); + static abstract void MovRT3(CodeGenContext context, uint encoding); + static abstract void MovRrA1(CodeGenContext context, uint encoding); + static abstract void MovRrT1(CodeGenContext context, uint encoding); + static abstract void MovRrT2(CodeGenContext context, uint encoding); + static abstract void MrcA1(CodeGenContext context, uint encoding); + static abstract void MrcT1(CodeGenContext context, uint encoding); + static abstract void MrrcA1(CodeGenContext context, uint encoding); + static abstract void MrrcT1(CodeGenContext context, uint encoding); + static abstract void MrsA1(CodeGenContext context, uint encoding); + static abstract void MrsT1(CodeGenContext context, uint encoding); + static abstract void MrsBrA1(CodeGenContext context, uint encoding); + static abstract void MrsBrT1(CodeGenContext context, uint encoding); + static abstract void MsrBrA1(CodeGenContext context, uint encoding); + static abstract void MsrBrT1(CodeGenContext context, uint encoding); + static abstract void MsrIA1(CodeGenContext context, uint encoding); + static abstract void MsrRA1(CodeGenContext context, uint encoding); + static abstract void MsrRT1(CodeGenContext context, uint encoding); + static abstract void MulA1(CodeGenContext context, uint encoding); + static abstract void MulT1(CodeGenContext context, uint encoding); + static abstract void MulT2(CodeGenContext context, uint encoding); + static abstract void MvnIA1(CodeGenContext context, uint encoding); + static abstract void MvnIT1(CodeGenContext context, uint encoding); + static abstract void MvnRA1(CodeGenContext context, uint encoding); + static abstract void MvnRT1(CodeGenContext context, uint encoding); + static abstract void MvnRT2(CodeGenContext context, uint encoding); + static abstract void MvnRrA1(CodeGenContext context, uint encoding); + static abstract void NopA1(CodeGenContext context, uint encoding); + static abstract void NopT1(CodeGenContext context, uint encoding); + static abstract void NopT2(CodeGenContext context, uint encoding); + static abstract void OrnIT1(CodeGenContext context, uint encoding); + static abstract void OrnRT1(CodeGenContext context, uint encoding); + static abstract void OrrIA1(CodeGenContext context, uint encoding); + static abstract void OrrIT1(CodeGenContext context, uint encoding); + static abstract void OrrRA1(CodeGenContext context, uint encoding); + static abstract void OrrRT1(CodeGenContext context, uint encoding); + static abstract void OrrRT2(CodeGenContext context, uint encoding); + static abstract void OrrRrA1(CodeGenContext context, uint encoding); + static abstract void PkhA1(CodeGenContext context, uint encoding); + static abstract void PkhT1(CodeGenContext context, uint encoding); + static abstract void PldIA1(CodeGenContext context, uint encoding); + static abstract void PldIT1(CodeGenContext context, uint encoding); + static abstract void PldIT2(CodeGenContext context, uint encoding); + static abstract void PldLA1(CodeGenContext context, uint encoding); + static abstract void PldLT1(CodeGenContext context, uint encoding); + static abstract void PldRA1(CodeGenContext context, uint encoding); + static abstract void PldRT1(CodeGenContext context, uint encoding); + static abstract void PliIA1(CodeGenContext context, uint encoding); + static abstract void PliIT1(CodeGenContext context, uint encoding); + static abstract void PliIT2(CodeGenContext context, uint encoding); + static abstract void PliIT3(CodeGenContext context, uint encoding); + static abstract void PliRA1(CodeGenContext context, uint encoding); + static abstract void PliRT1(CodeGenContext context, uint encoding); + static abstract void PopT1(CodeGenContext context, uint encoding); + static abstract void PssbbA1(CodeGenContext context, uint encoding); + static abstract void PssbbT1(CodeGenContext context, uint encoding); + static abstract void PushT1(CodeGenContext context, uint encoding); + static abstract void QaddA1(CodeGenContext context, uint encoding); + static abstract void QaddT1(CodeGenContext context, uint encoding); + static abstract void Qadd16A1(CodeGenContext context, uint encoding); + static abstract void Qadd16T1(CodeGenContext context, uint encoding); + static abstract void Qadd8A1(CodeGenContext context, uint encoding); + static abstract void Qadd8T1(CodeGenContext context, uint encoding); + static abstract void QasxA1(CodeGenContext context, uint encoding); + static abstract void QasxT1(CodeGenContext context, uint encoding); + static abstract void QdaddA1(CodeGenContext context, uint encoding); + static abstract void QdaddT1(CodeGenContext context, uint encoding); + static abstract void QdsubA1(CodeGenContext context, uint encoding); + static abstract void QdsubT1(CodeGenContext context, uint encoding); + static abstract void QsaxA1(CodeGenContext context, uint encoding); + static abstract void QsaxT1(CodeGenContext context, uint encoding); + static abstract void QsubA1(CodeGenContext context, uint encoding); + static abstract void QsubT1(CodeGenContext context, uint encoding); + static abstract void Qsub16A1(CodeGenContext context, uint encoding); + static abstract void Qsub16T1(CodeGenContext context, uint encoding); + static abstract void Qsub8A1(CodeGenContext context, uint encoding); + static abstract void Qsub8T1(CodeGenContext context, uint encoding); + static abstract void RbitA1(CodeGenContext context, uint encoding); + static abstract void RbitT1(CodeGenContext context, uint encoding); + static abstract void RevA1(CodeGenContext context, uint encoding); + static abstract void RevT1(CodeGenContext context, uint encoding); + static abstract void RevT2(CodeGenContext context, uint encoding); + static abstract void Rev16A1(CodeGenContext context, uint encoding); + static abstract void Rev16T1(CodeGenContext context, uint encoding); + static abstract void Rev16T2(CodeGenContext context, uint encoding); + static abstract void RevshA1(CodeGenContext context, uint encoding); + static abstract void RevshT1(CodeGenContext context, uint encoding); + static abstract void RevshT2(CodeGenContext context, uint encoding); + static abstract void RfeA1(CodeGenContext context, uint encoding); + static abstract void RfeT1(CodeGenContext context, uint encoding); + static abstract void RfeT2(CodeGenContext context, uint encoding); + static abstract void RsbIA1(CodeGenContext context, uint encoding); + static abstract void RsbIT1(CodeGenContext context, uint encoding); + static abstract void RsbIT2(CodeGenContext context, uint encoding); + static abstract void RsbRA1(CodeGenContext context, uint encoding); + static abstract void RsbRT1(CodeGenContext context, uint encoding); + static abstract void RsbRrA1(CodeGenContext context, uint encoding); + static abstract void RscIA1(CodeGenContext context, uint encoding); + static abstract void RscRA1(CodeGenContext context, uint encoding); + static abstract void RscRrA1(CodeGenContext context, uint encoding); + static abstract void Sadd16A1(CodeGenContext context, uint encoding); + static abstract void Sadd16T1(CodeGenContext context, uint encoding); + static abstract void Sadd8A1(CodeGenContext context, uint encoding); + static abstract void Sadd8T1(CodeGenContext context, uint encoding); + static abstract void SasxA1(CodeGenContext context, uint encoding); + static abstract void SasxT1(CodeGenContext context, uint encoding); + static abstract void SbA1(CodeGenContext context, uint encoding); + static abstract void SbT1(CodeGenContext context, uint encoding); + static abstract void SbcIA1(CodeGenContext context, uint encoding); + static abstract void SbcIT1(CodeGenContext context, uint encoding); + static abstract void SbcRA1(CodeGenContext context, uint encoding); + static abstract void SbcRT1(CodeGenContext context, uint encoding); + static abstract void SbcRT2(CodeGenContext context, uint encoding); + static abstract void SbcRrA1(CodeGenContext context, uint encoding); + static abstract void SbfxA1(CodeGenContext context, uint encoding); + static abstract void SbfxT1(CodeGenContext context, uint encoding); + static abstract void SdivA1(CodeGenContext context, uint encoding); + static abstract void SdivT1(CodeGenContext context, uint encoding); + static abstract void SelA1(CodeGenContext context, uint encoding); + static abstract void SelT1(CodeGenContext context, uint encoding); + static abstract void SetendA1(CodeGenContext context, uint encoding); + static abstract void SetendT1(CodeGenContext context, uint encoding); + static abstract void SetpanA1(CodeGenContext context, uint encoding); + static abstract void SetpanT1(CodeGenContext context, uint encoding); + static abstract void SevA1(CodeGenContext context, uint encoding); + static abstract void SevT1(CodeGenContext context, uint encoding); + static abstract void SevT2(CodeGenContext context, uint encoding); + static abstract void SevlA1(CodeGenContext context, uint encoding); + static abstract void SevlT1(CodeGenContext context, uint encoding); + static abstract void SevlT2(CodeGenContext context, uint encoding); + static abstract void Sha1cA1(CodeGenContext context, uint encoding); + static abstract void Sha1cT1(CodeGenContext context, uint encoding); + static abstract void Sha1hA1(CodeGenContext context, uint encoding); + static abstract void Sha1hT1(CodeGenContext context, uint encoding); + static abstract void Sha1mA1(CodeGenContext context, uint encoding); + static abstract void Sha1mT1(CodeGenContext context, uint encoding); + static abstract void Sha1pA1(CodeGenContext context, uint encoding); + static abstract void Sha1pT1(CodeGenContext context, uint encoding); + static abstract void Sha1su0A1(CodeGenContext context, uint encoding); + static abstract void Sha1su0T1(CodeGenContext context, uint encoding); + static abstract void Sha1su1A1(CodeGenContext context, uint encoding); + static abstract void Sha1su1T1(CodeGenContext context, uint encoding); + static abstract void Sha256hA1(CodeGenContext context, uint encoding); + static abstract void Sha256hT1(CodeGenContext context, uint encoding); + static abstract void Sha256h2A1(CodeGenContext context, uint encoding); + static abstract void Sha256h2T1(CodeGenContext context, uint encoding); + static abstract void Sha256su0A1(CodeGenContext context, uint encoding); + static abstract void Sha256su0T1(CodeGenContext context, uint encoding); + static abstract void Sha256su1A1(CodeGenContext context, uint encoding); + static abstract void Sha256su1T1(CodeGenContext context, uint encoding); + static abstract void Shadd16A1(CodeGenContext context, uint encoding); + static abstract void Shadd16T1(CodeGenContext context, uint encoding); + static abstract void Shadd8A1(CodeGenContext context, uint encoding); + static abstract void Shadd8T1(CodeGenContext context, uint encoding); + static abstract void ShasxA1(CodeGenContext context, uint encoding); + static abstract void ShasxT1(CodeGenContext context, uint encoding); + static abstract void ShsaxA1(CodeGenContext context, uint encoding); + static abstract void ShsaxT1(CodeGenContext context, uint encoding); + static abstract void Shsub16A1(CodeGenContext context, uint encoding); + static abstract void Shsub16T1(CodeGenContext context, uint encoding); + static abstract void Shsub8A1(CodeGenContext context, uint encoding); + static abstract void Shsub8T1(CodeGenContext context, uint encoding); + static abstract void SmcA1(CodeGenContext context, uint encoding); + static abstract void SmcT1(CodeGenContext context, uint encoding); + static abstract void SmlabbA1(CodeGenContext context, uint encoding); + static abstract void SmlabbT1(CodeGenContext context, uint encoding); + static abstract void SmladA1(CodeGenContext context, uint encoding); + static abstract void SmladT1(CodeGenContext context, uint encoding); + static abstract void SmlalA1(CodeGenContext context, uint encoding); + static abstract void SmlalT1(CodeGenContext context, uint encoding); + static abstract void SmlalbbA1(CodeGenContext context, uint encoding); + static abstract void SmlalbbT1(CodeGenContext context, uint encoding); + static abstract void SmlaldA1(CodeGenContext context, uint encoding); + static abstract void SmlaldT1(CodeGenContext context, uint encoding); + static abstract void SmlawbA1(CodeGenContext context, uint encoding); + static abstract void SmlawbT1(CodeGenContext context, uint encoding); + static abstract void SmlsdA1(CodeGenContext context, uint encoding); + static abstract void SmlsdT1(CodeGenContext context, uint encoding); + static abstract void SmlsldA1(CodeGenContext context, uint encoding); + static abstract void SmlsldT1(CodeGenContext context, uint encoding); + static abstract void SmmlaA1(CodeGenContext context, uint encoding); + static abstract void SmmlaT1(CodeGenContext context, uint encoding); + static abstract void SmmlsA1(CodeGenContext context, uint encoding); + static abstract void SmmlsT1(CodeGenContext context, uint encoding); + static abstract void SmmulA1(CodeGenContext context, uint encoding); + static abstract void SmmulT1(CodeGenContext context, uint encoding); + static abstract void SmuadA1(CodeGenContext context, uint encoding); + static abstract void SmuadT1(CodeGenContext context, uint encoding); + static abstract void SmulbbA1(CodeGenContext context, uint encoding); + static abstract void SmulbbT1(CodeGenContext context, uint encoding); + static abstract void SmullA1(CodeGenContext context, uint encoding); + static abstract void SmullT1(CodeGenContext context, uint encoding); + static abstract void SmulwbA1(CodeGenContext context, uint encoding); + static abstract void SmulwbT1(CodeGenContext context, uint encoding); + static abstract void SmusdA1(CodeGenContext context, uint encoding); + static abstract void SmusdT1(CodeGenContext context, uint encoding); + static abstract void SrsA1(CodeGenContext context, uint encoding); + static abstract void SrsT1(CodeGenContext context, uint encoding); + static abstract void SrsT2(CodeGenContext context, uint encoding); + static abstract void SsatA1(CodeGenContext context, uint encoding); + static abstract void SsatT1(CodeGenContext context, uint encoding); + static abstract void Ssat16A1(CodeGenContext context, uint encoding); + static abstract void Ssat16T1(CodeGenContext context, uint encoding); + static abstract void SsaxA1(CodeGenContext context, uint encoding); + static abstract void SsaxT1(CodeGenContext context, uint encoding); + static abstract void SsbbA1(CodeGenContext context, uint encoding); + static abstract void SsbbT1(CodeGenContext context, uint encoding); + static abstract void Ssub16A1(CodeGenContext context, uint encoding); + static abstract void Ssub16T1(CodeGenContext context, uint encoding); + static abstract void Ssub8A1(CodeGenContext context, uint encoding); + static abstract void Ssub8T1(CodeGenContext context, uint encoding); + static abstract void StcA1(CodeGenContext context, uint encoding); + static abstract void StcT1(CodeGenContext context, uint encoding); + static abstract void StlA1(CodeGenContext context, uint encoding); + static abstract void StlT1(CodeGenContext context, uint encoding); + static abstract void StlbA1(CodeGenContext context, uint encoding); + static abstract void StlbT1(CodeGenContext context, uint encoding); + static abstract void StlexA1(CodeGenContext context, uint encoding); + static abstract void StlexT1(CodeGenContext context, uint encoding); + static abstract void StlexbA1(CodeGenContext context, uint encoding); + static abstract void StlexbT1(CodeGenContext context, uint encoding); + static abstract void StlexdA1(CodeGenContext context, uint encoding); + static abstract void StlexdT1(CodeGenContext context, uint encoding); + static abstract void StlexhA1(CodeGenContext context, uint encoding); + static abstract void StlexhT1(CodeGenContext context, uint encoding); + static abstract void StlhA1(CodeGenContext context, uint encoding); + static abstract void StlhT1(CodeGenContext context, uint encoding); + static abstract void StmA1(CodeGenContext context, uint encoding); + static abstract void StmT1(CodeGenContext context, uint encoding); + static abstract void StmT2(CodeGenContext context, uint encoding); + static abstract void StmdaA1(CodeGenContext context, uint encoding); + static abstract void StmdbA1(CodeGenContext context, uint encoding); + static abstract void StmdbT1(CodeGenContext context, uint encoding); + static abstract void StmibA1(CodeGenContext context, uint encoding); + static abstract void StmUA1(CodeGenContext context, uint encoding); + static abstract void StrbtA1(CodeGenContext context, uint encoding); + static abstract void StrbtA2(CodeGenContext context, uint encoding); + static abstract void StrbtT1(CodeGenContext context, uint encoding); + static abstract void StrbIA1(CodeGenContext context, uint encoding); + static abstract void StrbIT1(CodeGenContext context, uint encoding); + static abstract void StrbIT2(CodeGenContext context, uint encoding); + static abstract void StrbIT3(CodeGenContext context, uint encoding); + static abstract void StrbRA1(CodeGenContext context, uint encoding); + static abstract void StrbRT1(CodeGenContext context, uint encoding); + static abstract void StrbRT2(CodeGenContext context, uint encoding); + static abstract void StrdIA1(CodeGenContext context, uint encoding); + static abstract void StrdIT1(CodeGenContext context, uint encoding); + static abstract void StrdRA1(CodeGenContext context, uint encoding); + static abstract void StrexA1(CodeGenContext context, uint encoding); + static abstract void StrexT1(CodeGenContext context, uint encoding); + static abstract void StrexbA1(CodeGenContext context, uint encoding); + static abstract void StrexbT1(CodeGenContext context, uint encoding); + static abstract void StrexdA1(CodeGenContext context, uint encoding); + static abstract void StrexdT1(CodeGenContext context, uint encoding); + static abstract void StrexhA1(CodeGenContext context, uint encoding); + static abstract void StrexhT1(CodeGenContext context, uint encoding); + static abstract void StrhtA1(CodeGenContext context, uint encoding); + static abstract void StrhtA2(CodeGenContext context, uint encoding); + static abstract void StrhtT1(CodeGenContext context, uint encoding); + static abstract void StrhIA1(CodeGenContext context, uint encoding); + static abstract void StrhIT1(CodeGenContext context, uint encoding); + static abstract void StrhIT2(CodeGenContext context, uint encoding); + static abstract void StrhIT3(CodeGenContext context, uint encoding); + static abstract void StrhRA1(CodeGenContext context, uint encoding); + static abstract void StrhRT1(CodeGenContext context, uint encoding); + static abstract void StrhRT2(CodeGenContext context, uint encoding); + static abstract void StrtA1(CodeGenContext context, uint encoding); + static abstract void StrtA2(CodeGenContext context, uint encoding); + static abstract void StrtT1(CodeGenContext context, uint encoding); + static abstract void StrIA1(CodeGenContext context, uint encoding); + static abstract void StrIT1(CodeGenContext context, uint encoding); + static abstract void StrIT2(CodeGenContext context, uint encoding); + static abstract void StrIT3(CodeGenContext context, uint encoding); + static abstract void StrIT4(CodeGenContext context, uint encoding); + static abstract void StrRA1(CodeGenContext context, uint encoding); + static abstract void StrRT1(CodeGenContext context, uint encoding); + static abstract void StrRT2(CodeGenContext context, uint encoding); + static abstract void SubIA1(CodeGenContext context, uint encoding); + static abstract void SubIT1(CodeGenContext context, uint encoding); + static abstract void SubIT2(CodeGenContext context, uint encoding); + static abstract void SubIT3(CodeGenContext context, uint encoding); + static abstract void SubIT4(CodeGenContext context, uint encoding); + static abstract void SubIT5(CodeGenContext context, uint encoding); + static abstract void SubRA1(CodeGenContext context, uint encoding); + static abstract void SubRT1(CodeGenContext context, uint encoding); + static abstract void SubRT2(CodeGenContext context, uint encoding); + static abstract void SubRrA1(CodeGenContext context, uint encoding); + static abstract void SubSpIA1(CodeGenContext context, uint encoding); + static abstract void SubSpIT1(CodeGenContext context, uint encoding); + static abstract void SubSpIT2(CodeGenContext context, uint encoding); + static abstract void SubSpIT3(CodeGenContext context, uint encoding); + static abstract void SubSpRA1(CodeGenContext context, uint encoding); + static abstract void SubSpRT1(CodeGenContext context, uint encoding); + static abstract void SvcA1(CodeGenContext context, uint encoding); + static abstract void SvcT1(CodeGenContext context, uint encoding); + static abstract void SxtabA1(CodeGenContext context, uint encoding); + static abstract void SxtabT1(CodeGenContext context, uint encoding); + static abstract void Sxtab16A1(CodeGenContext context, uint encoding); + static abstract void Sxtab16T1(CodeGenContext context, uint encoding); + static abstract void SxtahA1(CodeGenContext context, uint encoding); + static abstract void SxtahT1(CodeGenContext context, uint encoding); + static abstract void SxtbA1(CodeGenContext context, uint encoding); + static abstract void SxtbT1(CodeGenContext context, uint encoding); + static abstract void SxtbT2(CodeGenContext context, uint encoding); + static abstract void Sxtb16A1(CodeGenContext context, uint encoding); + static abstract void Sxtb16T1(CodeGenContext context, uint encoding); + static abstract void SxthA1(CodeGenContext context, uint encoding); + static abstract void SxthT1(CodeGenContext context, uint encoding); + static abstract void SxthT2(CodeGenContext context, uint encoding); + static abstract void TbbT1(CodeGenContext context, uint encoding); + static abstract void TeqIA1(CodeGenContext context, uint encoding); + static abstract void TeqIT1(CodeGenContext context, uint encoding); + static abstract void TeqRA1(CodeGenContext context, uint encoding); + static abstract void TeqRT1(CodeGenContext context, uint encoding); + static abstract void TeqRrA1(CodeGenContext context, uint encoding); + static abstract void TsbA1(CodeGenContext context, uint encoding); + static abstract void TsbT1(CodeGenContext context, uint encoding); + static abstract void TstIA1(CodeGenContext context, uint encoding); + static abstract void TstIT1(CodeGenContext context, uint encoding); + static abstract void TstRA1(CodeGenContext context, uint encoding); + static abstract void TstRT1(CodeGenContext context, uint encoding); + static abstract void TstRT2(CodeGenContext context, uint encoding); + static abstract void TstRrA1(CodeGenContext context, uint encoding); + static abstract void Uadd16A1(CodeGenContext context, uint encoding); + static abstract void Uadd16T1(CodeGenContext context, uint encoding); + static abstract void Uadd8A1(CodeGenContext context, uint encoding); + static abstract void Uadd8T1(CodeGenContext context, uint encoding); + static abstract void UasxA1(CodeGenContext context, uint encoding); + static abstract void UasxT1(CodeGenContext context, uint encoding); + static abstract void UbfxA1(CodeGenContext context, uint encoding); + static abstract void UbfxT1(CodeGenContext context, uint encoding); + static abstract void UdfA1(CodeGenContext context, uint encoding); + static abstract void UdfT1(CodeGenContext context, uint encoding); + static abstract void UdfT2(CodeGenContext context, uint encoding); + static abstract void UdivA1(CodeGenContext context, uint encoding); + static abstract void UdivT1(CodeGenContext context, uint encoding); + static abstract void Uhadd16A1(CodeGenContext context, uint encoding); + static abstract void Uhadd16T1(CodeGenContext context, uint encoding); + static abstract void Uhadd8A1(CodeGenContext context, uint encoding); + static abstract void Uhadd8T1(CodeGenContext context, uint encoding); + static abstract void UhasxA1(CodeGenContext context, uint encoding); + static abstract void UhasxT1(CodeGenContext context, uint encoding); + static abstract void UhsaxA1(CodeGenContext context, uint encoding); + static abstract void UhsaxT1(CodeGenContext context, uint encoding); + static abstract void Uhsub16A1(CodeGenContext context, uint encoding); + static abstract void Uhsub16T1(CodeGenContext context, uint encoding); + static abstract void Uhsub8A1(CodeGenContext context, uint encoding); + static abstract void Uhsub8T1(CodeGenContext context, uint encoding); + static abstract void UmaalA1(CodeGenContext context, uint encoding); + static abstract void UmaalT1(CodeGenContext context, uint encoding); + static abstract void UmlalA1(CodeGenContext context, uint encoding); + static abstract void UmlalT1(CodeGenContext context, uint encoding); + static abstract void UmullA1(CodeGenContext context, uint encoding); + static abstract void UmullT1(CodeGenContext context, uint encoding); + static abstract void Uqadd16A1(CodeGenContext context, uint encoding); + static abstract void Uqadd16T1(CodeGenContext context, uint encoding); + static abstract void Uqadd8A1(CodeGenContext context, uint encoding); + static abstract void Uqadd8T1(CodeGenContext context, uint encoding); + static abstract void UqasxA1(CodeGenContext context, uint encoding); + static abstract void UqasxT1(CodeGenContext context, uint encoding); + static abstract void UqsaxA1(CodeGenContext context, uint encoding); + static abstract void UqsaxT1(CodeGenContext context, uint encoding); + static abstract void Uqsub16A1(CodeGenContext context, uint encoding); + static abstract void Uqsub16T1(CodeGenContext context, uint encoding); + static abstract void Uqsub8A1(CodeGenContext context, uint encoding); + static abstract void Uqsub8T1(CodeGenContext context, uint encoding); + static abstract void Usad8A1(CodeGenContext context, uint encoding); + static abstract void Usad8T1(CodeGenContext context, uint encoding); + static abstract void Usada8A1(CodeGenContext context, uint encoding); + static abstract void Usada8T1(CodeGenContext context, uint encoding); + static abstract void UsatA1(CodeGenContext context, uint encoding); + static abstract void UsatT1(CodeGenContext context, uint encoding); + static abstract void Usat16A1(CodeGenContext context, uint encoding); + static abstract void Usat16T1(CodeGenContext context, uint encoding); + static abstract void UsaxA1(CodeGenContext context, uint encoding); + static abstract void UsaxT1(CodeGenContext context, uint encoding); + static abstract void Usub16A1(CodeGenContext context, uint encoding); + static abstract void Usub16T1(CodeGenContext context, uint encoding); + static abstract void Usub8A1(CodeGenContext context, uint encoding); + static abstract void Usub8T1(CodeGenContext context, uint encoding); + static abstract void UxtabA1(CodeGenContext context, uint encoding); + static abstract void UxtabT1(CodeGenContext context, uint encoding); + static abstract void Uxtab16A1(CodeGenContext context, uint encoding); + static abstract void Uxtab16T1(CodeGenContext context, uint encoding); + static abstract void UxtahA1(CodeGenContext context, uint encoding); + static abstract void UxtahT1(CodeGenContext context, uint encoding); + static abstract void UxtbA1(CodeGenContext context, uint encoding); + static abstract void UxtbT1(CodeGenContext context, uint encoding); + static abstract void UxtbT2(CodeGenContext context, uint encoding); + static abstract void Uxtb16A1(CodeGenContext context, uint encoding); + static abstract void Uxtb16T1(CodeGenContext context, uint encoding); + static abstract void UxthA1(CodeGenContext context, uint encoding); + static abstract void UxthT1(CodeGenContext context, uint encoding); + static abstract void UxthT2(CodeGenContext context, uint encoding); + static abstract void VabaA1(CodeGenContext context, uint encoding); + static abstract void VabaT1(CodeGenContext context, uint encoding); + static abstract void VabalA1(CodeGenContext context, uint encoding); + static abstract void VabalT1(CodeGenContext context, uint encoding); + static abstract void VabdlIA1(CodeGenContext context, uint encoding); + static abstract void VabdlIT1(CodeGenContext context, uint encoding); + static abstract void VabdFA1(CodeGenContext context, uint encoding); + static abstract void VabdFT1(CodeGenContext context, uint encoding); + static abstract void VabdIA1(CodeGenContext context, uint encoding); + static abstract void VabdIT1(CodeGenContext context, uint encoding); + static abstract void VabsA1(CodeGenContext context, uint encoding); + static abstract void VabsA2(CodeGenContext context, uint encoding); + static abstract void VabsT1(CodeGenContext context, uint encoding); + static abstract void VabsT2(CodeGenContext context, uint encoding); + static abstract void VacgeA1(CodeGenContext context, uint encoding); + static abstract void VacgeT1(CodeGenContext context, uint encoding); + static abstract void VacgtA1(CodeGenContext context, uint encoding); + static abstract void VacgtT1(CodeGenContext context, uint encoding); + static abstract void VaddhnA1(CodeGenContext context, uint encoding); + static abstract void VaddhnT1(CodeGenContext context, uint encoding); + static abstract void VaddlA1(CodeGenContext context, uint encoding); + static abstract void VaddlT1(CodeGenContext context, uint encoding); + static abstract void VaddwA1(CodeGenContext context, uint encoding); + static abstract void VaddwT1(CodeGenContext context, uint encoding); + static abstract void VaddFA1(CodeGenContext context, uint encoding); + static abstract void VaddFA2(CodeGenContext context, uint encoding); + static abstract void VaddFT1(CodeGenContext context, uint encoding); + static abstract void VaddFT2(CodeGenContext context, uint encoding); + static abstract void VaddIA1(CodeGenContext context, uint encoding); + static abstract void VaddIT1(CodeGenContext context, uint encoding); + static abstract void VandRA1(CodeGenContext context, uint encoding); + static abstract void VandRT1(CodeGenContext context, uint encoding); + static abstract void VbicIA1(CodeGenContext context, uint encoding); + static abstract void VbicIA2(CodeGenContext context, uint encoding); + static abstract void VbicIT1(CodeGenContext context, uint encoding); + static abstract void VbicIT2(CodeGenContext context, uint encoding); + static abstract void VbicRA1(CodeGenContext context, uint encoding); + static abstract void VbicRT1(CodeGenContext context, uint encoding); + static abstract void VbifA1(CodeGenContext context, uint encoding); + static abstract void VbifT1(CodeGenContext context, uint encoding); + static abstract void VbitA1(CodeGenContext context, uint encoding); + static abstract void VbitT1(CodeGenContext context, uint encoding); + static abstract void VbslA1(CodeGenContext context, uint encoding); + static abstract void VbslT1(CodeGenContext context, uint encoding); + static abstract void VcaddA1(CodeGenContext context, uint encoding); + static abstract void VcaddT1(CodeGenContext context, uint encoding); + static abstract void VceqIA1(CodeGenContext context, uint encoding); + static abstract void VceqIT1(CodeGenContext context, uint encoding); + static abstract void VceqRA1(CodeGenContext context, uint encoding); + static abstract void VceqRA2(CodeGenContext context, uint encoding); + static abstract void VceqRT1(CodeGenContext context, uint encoding); + static abstract void VceqRT2(CodeGenContext context, uint encoding); + static abstract void VcgeIA1(CodeGenContext context, uint encoding); + static abstract void VcgeIT1(CodeGenContext context, uint encoding); + static abstract void VcgeRA1(CodeGenContext context, uint encoding); + static abstract void VcgeRA2(CodeGenContext context, uint encoding); + static abstract void VcgeRT1(CodeGenContext context, uint encoding); + static abstract void VcgeRT2(CodeGenContext context, uint encoding); + static abstract void VcgtIA1(CodeGenContext context, uint encoding); + static abstract void VcgtIT1(CodeGenContext context, uint encoding); + static abstract void VcgtRA1(CodeGenContext context, uint encoding); + static abstract void VcgtRA2(CodeGenContext context, uint encoding); + static abstract void VcgtRT1(CodeGenContext context, uint encoding); + static abstract void VcgtRT2(CodeGenContext context, uint encoding); + static abstract void VcleIA1(CodeGenContext context, uint encoding); + static abstract void VcleIT1(CodeGenContext context, uint encoding); + static abstract void VclsA1(CodeGenContext context, uint encoding); + static abstract void VclsT1(CodeGenContext context, uint encoding); + static abstract void VcltIA1(CodeGenContext context, uint encoding); + static abstract void VcltIT1(CodeGenContext context, uint encoding); + static abstract void VclzA1(CodeGenContext context, uint encoding); + static abstract void VclzT1(CodeGenContext context, uint encoding); + static abstract void VcmlaA1(CodeGenContext context, uint encoding); + static abstract void VcmlaT1(CodeGenContext context, uint encoding); + static abstract void VcmlaSA1(CodeGenContext context, uint encoding); + static abstract void VcmlaST1(CodeGenContext context, uint encoding); + static abstract void VcmpA1(CodeGenContext context, uint encoding); + static abstract void VcmpA2(CodeGenContext context, uint encoding); + static abstract void VcmpT1(CodeGenContext context, uint encoding); + static abstract void VcmpT2(CodeGenContext context, uint encoding); + static abstract void VcmpeA1(CodeGenContext context, uint encoding); + static abstract void VcmpeA2(CodeGenContext context, uint encoding); + static abstract void VcmpeT1(CodeGenContext context, uint encoding); + static abstract void VcmpeT2(CodeGenContext context, uint encoding); + static abstract void VcntA1(CodeGenContext context, uint encoding); + static abstract void VcntT1(CodeGenContext context, uint encoding); + static abstract void VcvtaAsimdA1(CodeGenContext context, uint encoding); + static abstract void VcvtaAsimdT1(CodeGenContext context, uint encoding); + static abstract void VcvtaVfpA1(CodeGenContext context, uint encoding); + static abstract void VcvtaVfpT1(CodeGenContext context, uint encoding); + static abstract void VcvtbA1(CodeGenContext context, uint encoding); + static abstract void VcvtbT1(CodeGenContext context, uint encoding); + static abstract void VcvtbBfsA1(CodeGenContext context, uint encoding); + static abstract void VcvtbBfsT1(CodeGenContext context, uint encoding); + static abstract void VcvtmAsimdA1(CodeGenContext context, uint encoding); + static abstract void VcvtmAsimdT1(CodeGenContext context, uint encoding); + static abstract void VcvtmVfpA1(CodeGenContext context, uint encoding); + static abstract void VcvtmVfpT1(CodeGenContext context, uint encoding); + static abstract void VcvtnAsimdA1(CodeGenContext context, uint encoding); + static abstract void VcvtnAsimdT1(CodeGenContext context, uint encoding); + static abstract void VcvtnVfpA1(CodeGenContext context, uint encoding); + static abstract void VcvtnVfpT1(CodeGenContext context, uint encoding); + static abstract void VcvtpAsimdA1(CodeGenContext context, uint encoding); + static abstract void VcvtpAsimdT1(CodeGenContext context, uint encoding); + static abstract void VcvtpVfpA1(CodeGenContext context, uint encoding); + static abstract void VcvtpVfpT1(CodeGenContext context, uint encoding); + static abstract void VcvtrIvA1(CodeGenContext context, uint encoding); + static abstract void VcvtrIvT1(CodeGenContext context, uint encoding); + static abstract void VcvttA1(CodeGenContext context, uint encoding); + static abstract void VcvttT1(CodeGenContext context, uint encoding); + static abstract void VcvttBfsA1(CodeGenContext context, uint encoding); + static abstract void VcvttBfsT1(CodeGenContext context, uint encoding); + static abstract void VcvtBfsA1(CodeGenContext context, uint encoding); + static abstract void VcvtBfsT1(CodeGenContext context, uint encoding); + static abstract void VcvtDsA1(CodeGenContext context, uint encoding); + static abstract void VcvtDsT1(CodeGenContext context, uint encoding); + static abstract void VcvtHsA1(CodeGenContext context, uint encoding); + static abstract void VcvtHsT1(CodeGenContext context, uint encoding); + static abstract void VcvtIsA1(CodeGenContext context, uint encoding); + static abstract void VcvtIsT1(CodeGenContext context, uint encoding); + static abstract void VcvtIvA1(CodeGenContext context, uint encoding); + static abstract void VcvtIvT1(CodeGenContext context, uint encoding); + static abstract void VcvtViA1(CodeGenContext context, uint encoding); + static abstract void VcvtViT1(CodeGenContext context, uint encoding); + static abstract void VcvtXsA1(CodeGenContext context, uint encoding); + static abstract void VcvtXsT1(CodeGenContext context, uint encoding); + static abstract void VcvtXvA1(CodeGenContext context, uint encoding); + static abstract void VcvtXvT1(CodeGenContext context, uint encoding); + static abstract void VdivA1(CodeGenContext context, uint encoding); + static abstract void VdivT1(CodeGenContext context, uint encoding); + static abstract void VdotA1(CodeGenContext context, uint encoding); + static abstract void VdotT1(CodeGenContext context, uint encoding); + static abstract void VdotSA1(CodeGenContext context, uint encoding); + static abstract void VdotST1(CodeGenContext context, uint encoding); + static abstract void VdupRA1(CodeGenContext context, uint encoding); + static abstract void VdupRT1(CodeGenContext context, uint encoding); + static abstract void VdupSA1(CodeGenContext context, uint encoding); + static abstract void VdupST1(CodeGenContext context, uint encoding); + static abstract void VeorA1(CodeGenContext context, uint encoding); + static abstract void VeorT1(CodeGenContext context, uint encoding); + static abstract void VextA1(CodeGenContext context, uint encoding); + static abstract void VextT1(CodeGenContext context, uint encoding); + static abstract void VfmaA1(CodeGenContext context, uint encoding); + static abstract void VfmaA2(CodeGenContext context, uint encoding); + static abstract void VfmaT1(CodeGenContext context, uint encoding); + static abstract void VfmaT2(CodeGenContext context, uint encoding); + static abstract void VfmalA1(CodeGenContext context, uint encoding); + static abstract void VfmalT1(CodeGenContext context, uint encoding); + static abstract void VfmalSA1(CodeGenContext context, uint encoding); + static abstract void VfmalST1(CodeGenContext context, uint encoding); + static abstract void VfmaBfA1(CodeGenContext context, uint encoding); + static abstract void VfmaBfT1(CodeGenContext context, uint encoding); + static abstract void VfmaBfsA1(CodeGenContext context, uint encoding); + static abstract void VfmaBfsT1(CodeGenContext context, uint encoding); + static abstract void VfmsA1(CodeGenContext context, uint encoding); + static abstract void VfmsA2(CodeGenContext context, uint encoding); + static abstract void VfmsT1(CodeGenContext context, uint encoding); + static abstract void VfmsT2(CodeGenContext context, uint encoding); + static abstract void VfmslA1(CodeGenContext context, uint encoding); + static abstract void VfmslT1(CodeGenContext context, uint encoding); + static abstract void VfmslSA1(CodeGenContext context, uint encoding); + static abstract void VfmslST1(CodeGenContext context, uint encoding); + static abstract void VfnmaA1(CodeGenContext context, uint encoding); + static abstract void VfnmaT1(CodeGenContext context, uint encoding); + static abstract void VfnmsA1(CodeGenContext context, uint encoding); + static abstract void VfnmsT1(CodeGenContext context, uint encoding); + static abstract void VhaddA1(CodeGenContext context, uint encoding); + static abstract void VhaddT1(CodeGenContext context, uint encoding); + static abstract void VhsubA1(CodeGenContext context, uint encoding); + static abstract void VhsubT1(CodeGenContext context, uint encoding); + static abstract void VinsA1(CodeGenContext context, uint encoding); + static abstract void VinsT1(CodeGenContext context, uint encoding); + static abstract void VjcvtA1(CodeGenContext context, uint encoding); + static abstract void VjcvtT1(CodeGenContext context, uint encoding); + static abstract void Vld11A1(CodeGenContext context, uint encoding); + static abstract void Vld11A2(CodeGenContext context, uint encoding); + static abstract void Vld11A3(CodeGenContext context, uint encoding); + static abstract void Vld11T1(CodeGenContext context, uint encoding); + static abstract void Vld11T2(CodeGenContext context, uint encoding); + static abstract void Vld11T3(CodeGenContext context, uint encoding); + static abstract void Vld1AA1(CodeGenContext context, uint encoding); + static abstract void Vld1AT1(CodeGenContext context, uint encoding); + static abstract void Vld1MA1(CodeGenContext context, uint encoding); + static abstract void Vld1MA2(CodeGenContext context, uint encoding); + static abstract void Vld1MA3(CodeGenContext context, uint encoding); + static abstract void Vld1MA4(CodeGenContext context, uint encoding); + static abstract void Vld1MT1(CodeGenContext context, uint encoding); + static abstract void Vld1MT2(CodeGenContext context, uint encoding); + static abstract void Vld1MT3(CodeGenContext context, uint encoding); + static abstract void Vld1MT4(CodeGenContext context, uint encoding); + static abstract void Vld21A1(CodeGenContext context, uint encoding); + static abstract void Vld21A2(CodeGenContext context, uint encoding); + static abstract void Vld21A3(CodeGenContext context, uint encoding); + static abstract void Vld21T1(CodeGenContext context, uint encoding); + static abstract void Vld21T2(CodeGenContext context, uint encoding); + static abstract void Vld21T3(CodeGenContext context, uint encoding); + static abstract void Vld2AA1(CodeGenContext context, uint encoding); + static abstract void Vld2AT1(CodeGenContext context, uint encoding); + static abstract void Vld2MA1(CodeGenContext context, uint encoding); + static abstract void Vld2MA2(CodeGenContext context, uint encoding); + static abstract void Vld2MT1(CodeGenContext context, uint encoding); + static abstract void Vld2MT2(CodeGenContext context, uint encoding); + static abstract void Vld31A1(CodeGenContext context, uint encoding); + static abstract void Vld31A2(CodeGenContext context, uint encoding); + static abstract void Vld31A3(CodeGenContext context, uint encoding); + static abstract void Vld31T1(CodeGenContext context, uint encoding); + static abstract void Vld31T2(CodeGenContext context, uint encoding); + static abstract void Vld31T3(CodeGenContext context, uint encoding); + static abstract void Vld3AA1(CodeGenContext context, uint encoding); + static abstract void Vld3AT1(CodeGenContext context, uint encoding); + static abstract void Vld3MA1(CodeGenContext context, uint encoding); + static abstract void Vld3MT1(CodeGenContext context, uint encoding); + static abstract void Vld41A1(CodeGenContext context, uint encoding); + static abstract void Vld41A2(CodeGenContext context, uint encoding); + static abstract void Vld41A3(CodeGenContext context, uint encoding); + static abstract void Vld41T1(CodeGenContext context, uint encoding); + static abstract void Vld41T2(CodeGenContext context, uint encoding); + static abstract void Vld41T3(CodeGenContext context, uint encoding); + static abstract void Vld4AA1(CodeGenContext context, uint encoding); + static abstract void Vld4AT1(CodeGenContext context, uint encoding); + static abstract void Vld4MA1(CodeGenContext context, uint encoding); + static abstract void Vld4MT1(CodeGenContext context, uint encoding); + static abstract void VldmA1(CodeGenContext context, uint encoding); + static abstract void VldmA2(CodeGenContext context, uint encoding); + static abstract void VldmT1(CodeGenContext context, uint encoding); + static abstract void VldmT2(CodeGenContext context, uint encoding); + static abstract void VldrIA1(CodeGenContext context, uint encoding); + static abstract void VldrIT1(CodeGenContext context, uint encoding); + static abstract void VldrLA1(CodeGenContext context, uint encoding); + static abstract void VldrLT1(CodeGenContext context, uint encoding); + static abstract void VmaxnmA1(CodeGenContext context, uint encoding); + static abstract void VmaxnmA2(CodeGenContext context, uint encoding); + static abstract void VmaxnmT1(CodeGenContext context, uint encoding); + static abstract void VmaxnmT2(CodeGenContext context, uint encoding); + static abstract void VmaxFA1(CodeGenContext context, uint encoding); + static abstract void VmaxFT1(CodeGenContext context, uint encoding); + static abstract void VmaxIA1(CodeGenContext context, uint encoding); + static abstract void VmaxIT1(CodeGenContext context, uint encoding); + static abstract void VminnmA1(CodeGenContext context, uint encoding); + static abstract void VminnmA2(CodeGenContext context, uint encoding); + static abstract void VminnmT1(CodeGenContext context, uint encoding); + static abstract void VminnmT2(CodeGenContext context, uint encoding); + static abstract void VminFA1(CodeGenContext context, uint encoding); + static abstract void VminFT1(CodeGenContext context, uint encoding); + static abstract void VminIA1(CodeGenContext context, uint encoding); + static abstract void VminIT1(CodeGenContext context, uint encoding); + static abstract void VmlalIA1(CodeGenContext context, uint encoding); + static abstract void VmlalIT1(CodeGenContext context, uint encoding); + static abstract void VmlalSA1(CodeGenContext context, uint encoding); + static abstract void VmlalST1(CodeGenContext context, uint encoding); + static abstract void VmlaFA1(CodeGenContext context, uint encoding); + static abstract void VmlaFA2(CodeGenContext context, uint encoding); + static abstract void VmlaFT1(CodeGenContext context, uint encoding); + static abstract void VmlaFT2(CodeGenContext context, uint encoding); + static abstract void VmlaIA1(CodeGenContext context, uint encoding); + static abstract void VmlaIT1(CodeGenContext context, uint encoding); + static abstract void VmlaSA1(CodeGenContext context, uint encoding); + static abstract void VmlaST1(CodeGenContext context, uint encoding); + static abstract void VmlslIA1(CodeGenContext context, uint encoding); + static abstract void VmlslIT1(CodeGenContext context, uint encoding); + static abstract void VmlslSA1(CodeGenContext context, uint encoding); + static abstract void VmlslST1(CodeGenContext context, uint encoding); + static abstract void VmlsFA1(CodeGenContext context, uint encoding); + static abstract void VmlsFA2(CodeGenContext context, uint encoding); + static abstract void VmlsFT1(CodeGenContext context, uint encoding); + static abstract void VmlsFT2(CodeGenContext context, uint encoding); + static abstract void VmlsIA1(CodeGenContext context, uint encoding); + static abstract void VmlsIT1(CodeGenContext context, uint encoding); + static abstract void VmlsSA1(CodeGenContext context, uint encoding); + static abstract void VmlsST1(CodeGenContext context, uint encoding); + static abstract void VmmlaA1(CodeGenContext context, uint encoding); + static abstract void VmmlaT1(CodeGenContext context, uint encoding); + static abstract void VmovlA1(CodeGenContext context, uint encoding); + static abstract void VmovlT1(CodeGenContext context, uint encoding); + static abstract void VmovnA1(CodeGenContext context, uint encoding); + static abstract void VmovnT1(CodeGenContext context, uint encoding); + static abstract void VmovxA1(CodeGenContext context, uint encoding); + static abstract void VmovxT1(CodeGenContext context, uint encoding); + static abstract void VmovDA1(CodeGenContext context, uint encoding); + static abstract void VmovDT1(CodeGenContext context, uint encoding); + static abstract void VmovHA1(CodeGenContext context, uint encoding); + static abstract void VmovHT1(CodeGenContext context, uint encoding); + static abstract void VmovIA1(CodeGenContext context, uint encoding); + static abstract void VmovIA2(CodeGenContext context, uint encoding); + static abstract void VmovIA3(CodeGenContext context, uint encoding); + static abstract void VmovIA4(CodeGenContext context, uint encoding); + static abstract void VmovIA5(CodeGenContext context, uint encoding); + static abstract void VmovIT1(CodeGenContext context, uint encoding); + static abstract void VmovIT2(CodeGenContext context, uint encoding); + static abstract void VmovIT3(CodeGenContext context, uint encoding); + static abstract void VmovIT4(CodeGenContext context, uint encoding); + static abstract void VmovIT5(CodeGenContext context, uint encoding); + static abstract void VmovRA2(CodeGenContext context, uint encoding); + static abstract void VmovRT2(CodeGenContext context, uint encoding); + static abstract void VmovRsA1(CodeGenContext context, uint encoding); + static abstract void VmovRsT1(CodeGenContext context, uint encoding); + static abstract void VmovSA1(CodeGenContext context, uint encoding); + static abstract void VmovST1(CodeGenContext context, uint encoding); + static abstract void VmovSrA1(CodeGenContext context, uint encoding); + static abstract void VmovSrT1(CodeGenContext context, uint encoding); + static abstract void VmovSsA1(CodeGenContext context, uint encoding); + static abstract void VmovSsT1(CodeGenContext context, uint encoding); + static abstract void VmrsA1(CodeGenContext context, uint encoding); + static abstract void VmrsT1(CodeGenContext context, uint encoding); + static abstract void VmsrA1(CodeGenContext context, uint encoding); + static abstract void VmsrT1(CodeGenContext context, uint encoding); + static abstract void VmullIA1(CodeGenContext context, uint encoding); + static abstract void VmullIT1(CodeGenContext context, uint encoding); + static abstract void VmullSA1(CodeGenContext context, uint encoding); + static abstract void VmullST1(CodeGenContext context, uint encoding); + static abstract void VmulFA1(CodeGenContext context, uint encoding); + static abstract void VmulFA2(CodeGenContext context, uint encoding); + static abstract void VmulFT1(CodeGenContext context, uint encoding); + static abstract void VmulFT2(CodeGenContext context, uint encoding); + static abstract void VmulIA1(CodeGenContext context, uint encoding); + static abstract void VmulIT1(CodeGenContext context, uint encoding); + static abstract void VmulSA1(CodeGenContext context, uint encoding); + static abstract void VmulST1(CodeGenContext context, uint encoding); + static abstract void VmvnIA1(CodeGenContext context, uint encoding); + static abstract void VmvnIA2(CodeGenContext context, uint encoding); + static abstract void VmvnIA3(CodeGenContext context, uint encoding); + static abstract void VmvnIT1(CodeGenContext context, uint encoding); + static abstract void VmvnIT2(CodeGenContext context, uint encoding); + static abstract void VmvnIT3(CodeGenContext context, uint encoding); + static abstract void VmvnRA1(CodeGenContext context, uint encoding); + static abstract void VmvnRT1(CodeGenContext context, uint encoding); + static abstract void VnegA1(CodeGenContext context, uint encoding); + static abstract void VnegA2(CodeGenContext context, uint encoding); + static abstract void VnegT1(CodeGenContext context, uint encoding); + static abstract void VnegT2(CodeGenContext context, uint encoding); + static abstract void VnmlaA1(CodeGenContext context, uint encoding); + static abstract void VnmlaT1(CodeGenContext context, uint encoding); + static abstract void VnmlsA1(CodeGenContext context, uint encoding); + static abstract void VnmlsT1(CodeGenContext context, uint encoding); + static abstract void VnmulA1(CodeGenContext context, uint encoding); + static abstract void VnmulT1(CodeGenContext context, uint encoding); + static abstract void VornRA1(CodeGenContext context, uint encoding); + static abstract void VornRT1(CodeGenContext context, uint encoding); + static abstract void VorrIA1(CodeGenContext context, uint encoding); + static abstract void VorrIA2(CodeGenContext context, uint encoding); + static abstract void VorrIT1(CodeGenContext context, uint encoding); + static abstract void VorrIT2(CodeGenContext context, uint encoding); + static abstract void VorrRA1(CodeGenContext context, uint encoding); + static abstract void VorrRT1(CodeGenContext context, uint encoding); + static abstract void VpadalA1(CodeGenContext context, uint encoding); + static abstract void VpadalT1(CodeGenContext context, uint encoding); + static abstract void VpaddlA1(CodeGenContext context, uint encoding); + static abstract void VpaddlT1(CodeGenContext context, uint encoding); + static abstract void VpaddFA1(CodeGenContext context, uint encoding); + static abstract void VpaddFT1(CodeGenContext context, uint encoding); + static abstract void VpaddIA1(CodeGenContext context, uint encoding); + static abstract void VpaddIT1(CodeGenContext context, uint encoding); + static abstract void VpmaxFA1(CodeGenContext context, uint encoding); + static abstract void VpmaxFT1(CodeGenContext context, uint encoding); + static abstract void VpmaxIA1(CodeGenContext context, uint encoding); + static abstract void VpmaxIT1(CodeGenContext context, uint encoding); + static abstract void VpminFA1(CodeGenContext context, uint encoding); + static abstract void VpminFT1(CodeGenContext context, uint encoding); + static abstract void VpminIA1(CodeGenContext context, uint encoding); + static abstract void VpminIT1(CodeGenContext context, uint encoding); + static abstract void VqabsA1(CodeGenContext context, uint encoding); + static abstract void VqabsT1(CodeGenContext context, uint encoding); + static abstract void VqaddA1(CodeGenContext context, uint encoding); + static abstract void VqaddT1(CodeGenContext context, uint encoding); + static abstract void VqdmlalA1(CodeGenContext context, uint encoding); + static abstract void VqdmlalA2(CodeGenContext context, uint encoding); + static abstract void VqdmlalT1(CodeGenContext context, uint encoding); + static abstract void VqdmlalT2(CodeGenContext context, uint encoding); + static abstract void VqdmlslA1(CodeGenContext context, uint encoding); + static abstract void VqdmlslA2(CodeGenContext context, uint encoding); + static abstract void VqdmlslT1(CodeGenContext context, uint encoding); + static abstract void VqdmlslT2(CodeGenContext context, uint encoding); + static abstract void VqdmulhA1(CodeGenContext context, uint encoding); + static abstract void VqdmulhA2(CodeGenContext context, uint encoding); + static abstract void VqdmulhT1(CodeGenContext context, uint encoding); + static abstract void VqdmulhT2(CodeGenContext context, uint encoding); + static abstract void VqdmullA1(CodeGenContext context, uint encoding); + static abstract void VqdmullA2(CodeGenContext context, uint encoding); + static abstract void VqdmullT1(CodeGenContext context, uint encoding); + static abstract void VqdmullT2(CodeGenContext context, uint encoding); + static abstract void VqmovnA1(CodeGenContext context, uint encoding); + static abstract void VqmovnT1(CodeGenContext context, uint encoding); + static abstract void VqnegA1(CodeGenContext context, uint encoding); + static abstract void VqnegT1(CodeGenContext context, uint encoding); + static abstract void VqrdmlahA1(CodeGenContext context, uint encoding); + static abstract void VqrdmlahA2(CodeGenContext context, uint encoding); + static abstract void VqrdmlahT1(CodeGenContext context, uint encoding); + static abstract void VqrdmlahT2(CodeGenContext context, uint encoding); + static abstract void VqrdmlshA1(CodeGenContext context, uint encoding); + static abstract void VqrdmlshA2(CodeGenContext context, uint encoding); + static abstract void VqrdmlshT1(CodeGenContext context, uint encoding); + static abstract void VqrdmlshT2(CodeGenContext context, uint encoding); + static abstract void VqrdmulhA1(CodeGenContext context, uint encoding); + static abstract void VqrdmulhA2(CodeGenContext context, uint encoding); + static abstract void VqrdmulhT1(CodeGenContext context, uint encoding); + static abstract void VqrdmulhT2(CodeGenContext context, uint encoding); + static abstract void VqrshlA1(CodeGenContext context, uint encoding); + static abstract void VqrshlT1(CodeGenContext context, uint encoding); + static abstract void VqrshrnA1(CodeGenContext context, uint encoding); + static abstract void VqrshrnT1(CodeGenContext context, uint encoding); + static abstract void VqshlIA1(CodeGenContext context, uint encoding); + static abstract void VqshlIT1(CodeGenContext context, uint encoding); + static abstract void VqshlRA1(CodeGenContext context, uint encoding); + static abstract void VqshlRT1(CodeGenContext context, uint encoding); + static abstract void VqshrnA1(CodeGenContext context, uint encoding); + static abstract void VqshrnT1(CodeGenContext context, uint encoding); + static abstract void VqsubA1(CodeGenContext context, uint encoding); + static abstract void VqsubT1(CodeGenContext context, uint encoding); + static abstract void VraddhnA1(CodeGenContext context, uint encoding); + static abstract void VraddhnT1(CodeGenContext context, uint encoding); + static abstract void VrecpeA1(CodeGenContext context, uint encoding); + static abstract void VrecpeT1(CodeGenContext context, uint encoding); + static abstract void VrecpsA1(CodeGenContext context, uint encoding); + static abstract void VrecpsT1(CodeGenContext context, uint encoding); + static abstract void Vrev16A1(CodeGenContext context, uint encoding); + static abstract void Vrev16T1(CodeGenContext context, uint encoding); + static abstract void Vrev32A1(CodeGenContext context, uint encoding); + static abstract void Vrev32T1(CodeGenContext context, uint encoding); + static abstract void Vrev64A1(CodeGenContext context, uint encoding); + static abstract void Vrev64T1(CodeGenContext context, uint encoding); + static abstract void VrhaddA1(CodeGenContext context, uint encoding); + static abstract void VrhaddT1(CodeGenContext context, uint encoding); + static abstract void VrintaAsimdA1(CodeGenContext context, uint encoding); + static abstract void VrintaAsimdT1(CodeGenContext context, uint encoding); + static abstract void VrintaVfpA1(CodeGenContext context, uint encoding); + static abstract void VrintaVfpT1(CodeGenContext context, uint encoding); + static abstract void VrintmAsimdA1(CodeGenContext context, uint encoding); + static abstract void VrintmAsimdT1(CodeGenContext context, uint encoding); + static abstract void VrintmVfpA1(CodeGenContext context, uint encoding); + static abstract void VrintmVfpT1(CodeGenContext context, uint encoding); + static abstract void VrintnAsimdA1(CodeGenContext context, uint encoding); + static abstract void VrintnAsimdT1(CodeGenContext context, uint encoding); + static abstract void VrintnVfpA1(CodeGenContext context, uint encoding); + static abstract void VrintnVfpT1(CodeGenContext context, uint encoding); + static abstract void VrintpAsimdA1(CodeGenContext context, uint encoding); + static abstract void VrintpAsimdT1(CodeGenContext context, uint encoding); + static abstract void VrintpVfpA1(CodeGenContext context, uint encoding); + static abstract void VrintpVfpT1(CodeGenContext context, uint encoding); + static abstract void VrintrVfpA1(CodeGenContext context, uint encoding); + static abstract void VrintrVfpT1(CodeGenContext context, uint encoding); + static abstract void VrintxAsimdA1(CodeGenContext context, uint encoding); + static abstract void VrintxAsimdT1(CodeGenContext context, uint encoding); + static abstract void VrintxVfpA1(CodeGenContext context, uint encoding); + static abstract void VrintxVfpT1(CodeGenContext context, uint encoding); + static abstract void VrintzAsimdA1(CodeGenContext context, uint encoding); + static abstract void VrintzAsimdT1(CodeGenContext context, uint encoding); + static abstract void VrintzVfpA1(CodeGenContext context, uint encoding); + static abstract void VrintzVfpT1(CodeGenContext context, uint encoding); + static abstract void VrshlA1(CodeGenContext context, uint encoding); + static abstract void VrshlT1(CodeGenContext context, uint encoding); + static abstract void VrshrA1(CodeGenContext context, uint encoding); + static abstract void VrshrT1(CodeGenContext context, uint encoding); + static abstract void VrshrnA1(CodeGenContext context, uint encoding); + static abstract void VrshrnT1(CodeGenContext context, uint encoding); + static abstract void VrsqrteA1(CodeGenContext context, uint encoding); + static abstract void VrsqrteT1(CodeGenContext context, uint encoding); + static abstract void VrsqrtsA1(CodeGenContext context, uint encoding); + static abstract void VrsqrtsT1(CodeGenContext context, uint encoding); + static abstract void VrsraA1(CodeGenContext context, uint encoding); + static abstract void VrsraT1(CodeGenContext context, uint encoding); + static abstract void VrsubhnA1(CodeGenContext context, uint encoding); + static abstract void VrsubhnT1(CodeGenContext context, uint encoding); + static abstract void VsdotA1(CodeGenContext context, uint encoding); + static abstract void VsdotT1(CodeGenContext context, uint encoding); + static abstract void VsdotSA1(CodeGenContext context, uint encoding); + static abstract void VsdotST1(CodeGenContext context, uint encoding); + static abstract void VselA1(CodeGenContext context, uint encoding); + static abstract void VselT1(CodeGenContext context, uint encoding); + static abstract void VshllA1(CodeGenContext context, uint encoding); + static abstract void VshllA2(CodeGenContext context, uint encoding); + static abstract void VshllT1(CodeGenContext context, uint encoding); + static abstract void VshllT2(CodeGenContext context, uint encoding); + static abstract void VshlIA1(CodeGenContext context, uint encoding); + static abstract void VshlIT1(CodeGenContext context, uint encoding); + static abstract void VshlRA1(CodeGenContext context, uint encoding); + static abstract void VshlRT1(CodeGenContext context, uint encoding); + static abstract void VshrA1(CodeGenContext context, uint encoding); + static abstract void VshrT1(CodeGenContext context, uint encoding); + static abstract void VshrnA1(CodeGenContext context, uint encoding); + static abstract void VshrnT1(CodeGenContext context, uint encoding); + static abstract void VsliA1(CodeGenContext context, uint encoding); + static abstract void VsliT1(CodeGenContext context, uint encoding); + static abstract void VsmmlaA1(CodeGenContext context, uint encoding); + static abstract void VsmmlaT1(CodeGenContext context, uint encoding); + static abstract void VsqrtA1(CodeGenContext context, uint encoding); + static abstract void VsqrtT1(CodeGenContext context, uint encoding); + static abstract void VsraA1(CodeGenContext context, uint encoding); + static abstract void VsraT1(CodeGenContext context, uint encoding); + static abstract void VsriA1(CodeGenContext context, uint encoding); + static abstract void VsriT1(CodeGenContext context, uint encoding); + static abstract void Vst11A1(CodeGenContext context, uint encoding); + static abstract void Vst11A2(CodeGenContext context, uint encoding); + static abstract void Vst11A3(CodeGenContext context, uint encoding); + static abstract void Vst11T1(CodeGenContext context, uint encoding); + static abstract void Vst11T2(CodeGenContext context, uint encoding); + static abstract void Vst11T3(CodeGenContext context, uint encoding); + static abstract void Vst1MA1(CodeGenContext context, uint encoding); + static abstract void Vst1MA2(CodeGenContext context, uint encoding); + static abstract void Vst1MA3(CodeGenContext context, uint encoding); + static abstract void Vst1MA4(CodeGenContext context, uint encoding); + static abstract void Vst1MT1(CodeGenContext context, uint encoding); + static abstract void Vst1MT2(CodeGenContext context, uint encoding); + static abstract void Vst1MT3(CodeGenContext context, uint encoding); + static abstract void Vst1MT4(CodeGenContext context, uint encoding); + static abstract void Vst21A1(CodeGenContext context, uint encoding); + static abstract void Vst21A2(CodeGenContext context, uint encoding); + static abstract void Vst21A3(CodeGenContext context, uint encoding); + static abstract void Vst21T1(CodeGenContext context, uint encoding); + static abstract void Vst21T2(CodeGenContext context, uint encoding); + static abstract void Vst21T3(CodeGenContext context, uint encoding); + static abstract void Vst2MA1(CodeGenContext context, uint encoding); + static abstract void Vst2MA2(CodeGenContext context, uint encoding); + static abstract void Vst2MT1(CodeGenContext context, uint encoding); + static abstract void Vst2MT2(CodeGenContext context, uint encoding); + static abstract void Vst31A1(CodeGenContext context, uint encoding); + static abstract void Vst31A2(CodeGenContext context, uint encoding); + static abstract void Vst31A3(CodeGenContext context, uint encoding); + static abstract void Vst31T1(CodeGenContext context, uint encoding); + static abstract void Vst31T2(CodeGenContext context, uint encoding); + static abstract void Vst31T3(CodeGenContext context, uint encoding); + static abstract void Vst3MA1(CodeGenContext context, uint encoding); + static abstract void Vst3MT1(CodeGenContext context, uint encoding); + static abstract void Vst41A1(CodeGenContext context, uint encoding); + static abstract void Vst41A2(CodeGenContext context, uint encoding); + static abstract void Vst41A3(CodeGenContext context, uint encoding); + static abstract void Vst41T1(CodeGenContext context, uint encoding); + static abstract void Vst41T2(CodeGenContext context, uint encoding); + static abstract void Vst41T3(CodeGenContext context, uint encoding); + static abstract void Vst4MA1(CodeGenContext context, uint encoding); + static abstract void Vst4MT1(CodeGenContext context, uint encoding); + static abstract void VstmA1(CodeGenContext context, uint encoding); + static abstract void VstmA2(CodeGenContext context, uint encoding); + static abstract void VstmT1(CodeGenContext context, uint encoding); + static abstract void VstmT2(CodeGenContext context, uint encoding); + static abstract void VstrA1(CodeGenContext context, uint encoding); + static abstract void VstrT1(CodeGenContext context, uint encoding); + static abstract void VsubhnA1(CodeGenContext context, uint encoding); + static abstract void VsubhnT1(CodeGenContext context, uint encoding); + static abstract void VsublA1(CodeGenContext context, uint encoding); + static abstract void VsublT1(CodeGenContext context, uint encoding); + static abstract void VsubwA1(CodeGenContext context, uint encoding); + static abstract void VsubwT1(CodeGenContext context, uint encoding); + static abstract void VsubFA1(CodeGenContext context, uint encoding); + static abstract void VsubFA2(CodeGenContext context, uint encoding); + static abstract void VsubFT1(CodeGenContext context, uint encoding); + static abstract void VsubFT2(CodeGenContext context, uint encoding); + static abstract void VsubIA1(CodeGenContext context, uint encoding); + static abstract void VsubIT1(CodeGenContext context, uint encoding); + static abstract void VsudotSA1(CodeGenContext context, uint encoding); + static abstract void VsudotST1(CodeGenContext context, uint encoding); + static abstract void VswpA1(CodeGenContext context, uint encoding); + static abstract void VswpT1(CodeGenContext context, uint encoding); + static abstract void VtblA1(CodeGenContext context, uint encoding); + static abstract void VtblT1(CodeGenContext context, uint encoding); + static abstract void VtrnA1(CodeGenContext context, uint encoding); + static abstract void VtrnT1(CodeGenContext context, uint encoding); + static abstract void VtstA1(CodeGenContext context, uint encoding); + static abstract void VtstT1(CodeGenContext context, uint encoding); + static abstract void VudotA1(CodeGenContext context, uint encoding); + static abstract void VudotT1(CodeGenContext context, uint encoding); + static abstract void VudotSA1(CodeGenContext context, uint encoding); + static abstract void VudotST1(CodeGenContext context, uint encoding); + static abstract void VummlaA1(CodeGenContext context, uint encoding); + static abstract void VummlaT1(CodeGenContext context, uint encoding); + static abstract void VusdotA1(CodeGenContext context, uint encoding); + static abstract void VusdotT1(CodeGenContext context, uint encoding); + static abstract void VusdotSA1(CodeGenContext context, uint encoding); + static abstract void VusdotST1(CodeGenContext context, uint encoding); + static abstract void VusmmlaA1(CodeGenContext context, uint encoding); + static abstract void VusmmlaT1(CodeGenContext context, uint encoding); + static abstract void VuzpA1(CodeGenContext context, uint encoding); + static abstract void VuzpT1(CodeGenContext context, uint encoding); + static abstract void VzipA1(CodeGenContext context, uint encoding); + static abstract void VzipT1(CodeGenContext context, uint encoding); + static abstract void WfeA1(CodeGenContext context, uint encoding); + static abstract void WfeT1(CodeGenContext context, uint encoding); + static abstract void WfeT2(CodeGenContext context, uint encoding); + static abstract void WfiA1(CodeGenContext context, uint encoding); + static abstract void WfiT1(CodeGenContext context, uint encoding); + static abstract void WfiT2(CodeGenContext context, uint encoding); + static abstract void YieldA1(CodeGenContext context, uint encoding); + static abstract void YieldT1(CodeGenContext context, uint encoding); + static abstract void YieldT2(CodeGenContext context, uint encoding); + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/ImmUtils.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/ImmUtils.cs new file mode 100644 index 000000000..516845fc9 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/ImmUtils.cs @@ -0,0 +1,137 @@ +using System.Numerics; + +namespace Ryujinx.Cpu.LightningJit.Arm32 +{ + static class ImmUtils + { + public static uint ExpandImm(uint imm) + { + return BitOperations.RotateRight((byte)imm, (int)(imm >> 8) * 2); + } + + public static bool ExpandedImmRotated(uint imm) + { + return (imm >> 8) != 0; + } + + public static uint ExpandImm(uint imm8, uint imm3, uint i) + { + uint imm = CombineImmU12(imm8, imm3, i); + + if (imm >> 10 == 0) + { + return ((imm >> 8) & 3) switch + { + 0 => (byte)imm, + 1 => (byte)imm * 0x00010001u, + 2 => (byte)imm * 0x01000100u, + 3 => (byte)imm * 0x01010101u, + _ => 0, + }; + } + else + { + return BitOperations.RotateRight(0x80u | (byte)imm, (int)(imm >> 7)); + } + } + + public static bool ExpandedImmRotated(uint imm8, uint imm3, uint i) + { + uint imm = CombineImmU12(imm8, imm3, i); + + return (imm >> 7) != 0; + } + + public static uint CombineImmU5(uint imm2, uint imm3) + { + return imm2 | (imm3 << 2); + } + + public static uint CombineImmU5IImm4(uint i, uint imm4) + { + return i | (imm4 << 1); + } + + public static uint CombineImmU8(uint imm4l, uint imm4h) + { + return imm4l | (imm4h << 4); + } + + public static uint CombineImmU8(uint imm4, uint imm3, uint i) + { + return imm4 | (imm3 << 4) | (i << 7); + } + + public static uint CombineImmU12(uint imm8, uint imm3, uint i) + { + return imm8 | (imm3 << 8) | (i << 11); + } + + public static uint CombineImmU16(uint imm12, uint imm4) + { + return imm12 | (imm4 << 12); + } + + public static uint CombineImmU16(uint imm8, uint imm3, uint i, uint imm4) + { + return imm8 | (imm3 << 8) | (i << 11) | (imm4 << 12); + } + + public static int CombineSImm20Times2(uint imm11, uint imm6, uint j1, uint j2, uint s) + { + int imm32 = (int)(imm11 | (imm6 << 11) | (j1 << 17) | (j2 << 18) | (s << 19)); + + return (imm32 << 13) >> 12; + } + + public static int CombineSImm24Times2(uint imm11, uint imm10, uint j1, uint j2, uint s) + { + uint i1 = j1 ^ s ^ 1; + uint i2 = j2 ^ s ^ 1; + + int imm32 = (int)(imm11 | (imm10 << 11) | (i2 << 21) | (i1 << 22) | (s << 23)); + + return (imm32 << 8) >> 7; + } + + public static int CombineSImm24Times4(uint imm10L, uint imm10H, uint j1, uint j2, uint s) + { + uint i1 = j1 ^ s ^ 1; + uint i2 = j2 ^ s ^ 1; + + int imm32 = (int)(imm10L | (imm10H << 10) | (i2 << 20) | (i1 << 21) | (s << 22)); + + return (imm32 << 9) >> 7; + } + + public static uint CombineRegisterList(uint registerList, uint m) + { + return registerList | (m << 14); + } + + public static uint CombineRegisterList(uint registerList, uint m, uint p) + { + return registerList | (m << 14) | (p << 15); + } + + public static int ExtractSImm24Times4(uint encoding) + { + return (int)(encoding << 8) >> 6; + } + + public static int ExtractT16UImm5Times2(uint encoding) + { + return (int)(encoding >> 18) & 0x3e; + } + + public static int ExtractT16SImm8Times2(uint encoding) + { + return (int)(encoding << 24) >> 23; + } + + public static int ExtractT16SImm11Times2(uint encoding) + { + return (int)(encoding << 21) >> 20; + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/InstDecoders.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/InstDecoders.cs new file mode 100644 index 000000000..41b105e4a --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/InstDecoders.cs @@ -0,0 +1,2927 @@ +namespace Ryujinx.Cpu.LightningJit.Arm32 +{ + readonly struct InstCondb28w4Sb20w1Rnb16w4Rdb12w4Imm12b0w12 + { + private readonly uint _value; + public InstCondb28w4Sb20w1Rnb16w4Rdb12w4Imm12b0w12(uint value) => _value = value; + public readonly uint Imm12 => (_value >> 0) & 0xFFF; + public readonly uint Rd => (_value >> 12) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint S => (_value >> 20) & 0x1; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstIb26w1Sb20w1Rnb16w4Imm3b12w3Rdb8w4Imm8b0w8 + { + private readonly uint _value; + public InstIb26w1Sb20w1Rnb16w4Imm3b12w3Rdb8w4Imm8b0w8(uint value) => _value = value; + public readonly uint Imm8 => (_value >> 0) & 0xFF; + public readonly uint Rd => (_value >> 8) & 0xF; + public readonly uint Imm3 => (_value >> 12) & 0x7; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint S => (_value >> 20) & 0x1; + public readonly uint I => (_value >> 26) & 0x1; + } + + readonly struct InstCondb28w4Sb20w1Rnb16w4Rdb12w4Imm5b7w5Stypeb5w2Rmb0w4 + { + private readonly uint _value; + public InstCondb28w4Sb20w1Rnb16w4Rdb12w4Imm5b7w5Stypeb5w2Rmb0w4(uint value) => _value = value; + public readonly uint Rm => (_value >> 0) & 0xF; + public readonly uint Stype => (_value >> 5) & 0x3; + public readonly uint Imm5 => (_value >> 7) & 0x1F; + public readonly uint Rd => (_value >> 12) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint S => (_value >> 20) & 0x1; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstRmb19w3Rdnb16w3 + { + private readonly uint _value; + public InstRmb19w3Rdnb16w3(uint value) => _value = value; + public readonly uint Rdn => (_value >> 16) & 0x7; + public readonly uint Rm => (_value >> 19) & 0x7; + } + + readonly struct InstSb20w1Rnb16w4Imm3b12w3Rdb8w4Imm2b6w2Stypeb4w2Rmb0w4 + { + private readonly uint _value; + public InstSb20w1Rnb16w4Imm3b12w3Rdb8w4Imm2b6w2Stypeb4w2Rmb0w4(uint value) => _value = value; + public readonly uint Rm => (_value >> 0) & 0xF; + public readonly uint Stype => (_value >> 4) & 0x3; + public readonly uint Imm2 => (_value >> 6) & 0x3; + public readonly uint Rd => (_value >> 8) & 0xF; + public readonly uint Imm3 => (_value >> 12) & 0x7; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint S => (_value >> 20) & 0x1; + } + + readonly struct InstCondb28w4Sb20w1Rnb16w4Rdb12w4Rsb8w4Stypeb5w2Rmb0w4 + { + private readonly uint _value; + public InstCondb28w4Sb20w1Rnb16w4Rdb12w4Rsb8w4Stypeb5w2Rmb0w4(uint value) => _value = value; + public readonly uint Rm => (_value >> 0) & 0xF; + public readonly uint Stype => (_value >> 5) & 0x3; + public readonly uint Rs => (_value >> 8) & 0xF; + public readonly uint Rd => (_value >> 12) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint S => (_value >> 20) & 0x1; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstImm3b22w3Rnb19w3Rdb16w3 + { + private readonly uint _value; + public InstImm3b22w3Rnb19w3Rdb16w3(uint value) => _value = value; + public readonly uint Rd => (_value >> 16) & 0x7; + public readonly uint Rn => (_value >> 19) & 0x7; + public readonly uint Imm3 => (_value >> 22) & 0x7; + } + + readonly struct InstRdnb24w3Imm8b16w8 + { + private readonly uint _value; + public InstRdnb24w3Imm8b16w8(uint value) => _value = value; + public readonly uint Imm8 => (_value >> 16) & 0xFF; + public readonly uint Rdn => (_value >> 24) & 0x7; + } + + readonly struct InstIb26w1Rnb16w4Imm3b12w3Rdb8w4Imm8b0w8 + { + private readonly uint _value; + public InstIb26w1Rnb16w4Imm3b12w3Rdb8w4Imm8b0w8(uint value) => _value = value; + public readonly uint Imm8 => (_value >> 0) & 0xFF; + public readonly uint Rd => (_value >> 8) & 0xF; + public readonly uint Imm3 => (_value >> 12) & 0x7; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint I => (_value >> 26) & 0x1; + } + + readonly struct InstRmb22w3Rnb19w3Rdb16w3 + { + private readonly uint _value; + public InstRmb22w3Rnb19w3Rdb16w3(uint value) => _value = value; + public readonly uint Rd => (_value >> 16) & 0x7; + public readonly uint Rn => (_value >> 19) & 0x7; + public readonly uint Rm => (_value >> 22) & 0x7; + } + + readonly struct InstDnb23w1Rmb19w4Rdnb16w3 + { + private readonly uint _value; + public InstDnb23w1Rmb19w4Rdnb16w3(uint value) => _value = value; + public readonly uint Rdn => (_value >> 16) & 0x7; + public readonly uint Rm => (_value >> 19) & 0xF; + public readonly uint Dn => (_value >> 23) & 0x1; + } + + readonly struct InstCondb28w4Sb20w1Rdb12w4Imm12b0w12 + { + private readonly uint _value; + public InstCondb28w4Sb20w1Rdb12w4Imm12b0w12(uint value) => _value = value; + public readonly uint Imm12 => (_value >> 0) & 0xFFF; + public readonly uint Rd => (_value >> 12) & 0xF; + public readonly uint S => (_value >> 20) & 0x1; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstRdb24w3Imm8b16w8 + { + private readonly uint _value; + public InstRdb24w3Imm8b16w8(uint value) => _value = value; + public readonly uint Imm8 => (_value >> 16) & 0xFF; + public readonly uint Rd => (_value >> 24) & 0x7; + } + + readonly struct InstImm7b16w7 + { + private readonly uint _value; + public InstImm7b16w7(uint value) => _value = value; + public readonly uint Imm7 => (_value >> 16) & 0x7F; + } + + readonly struct InstIb26w1Sb20w1Imm3b12w3Rdb8w4Imm8b0w8 + { + private readonly uint _value; + public InstIb26w1Sb20w1Imm3b12w3Rdb8w4Imm8b0w8(uint value) => _value = value; + public readonly uint Imm8 => (_value >> 0) & 0xFF; + public readonly uint Rd => (_value >> 8) & 0xF; + public readonly uint Imm3 => (_value >> 12) & 0x7; + public readonly uint S => (_value >> 20) & 0x1; + public readonly uint I => (_value >> 26) & 0x1; + } + + readonly struct InstIb26w1Imm3b12w3Rdb8w4Imm8b0w8 + { + private readonly uint _value; + public InstIb26w1Imm3b12w3Rdb8w4Imm8b0w8(uint value) => _value = value; + public readonly uint Imm8 => (_value >> 0) & 0xFF; + public readonly uint Rd => (_value >> 8) & 0xF; + public readonly uint Imm3 => (_value >> 12) & 0x7; + public readonly uint I => (_value >> 26) & 0x1; + } + + readonly struct InstCondb28w4Sb20w1Rdb12w4Imm5b7w5Stypeb5w2Rmb0w4 + { + private readonly uint _value; + public InstCondb28w4Sb20w1Rdb12w4Imm5b7w5Stypeb5w2Rmb0w4(uint value) => _value = value; + public readonly uint Rm => (_value >> 0) & 0xF; + public readonly uint Stype => (_value >> 5) & 0x3; + public readonly uint Imm5 => (_value >> 7) & 0x1F; + public readonly uint Rd => (_value >> 12) & 0xF; + public readonly uint S => (_value >> 20) & 0x1; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstDmb23w1Rdmb16w3 + { + private readonly uint _value; + public InstDmb23w1Rdmb16w3(uint value) => _value = value; + public readonly uint Rdm => (_value >> 16) & 0x7; + public readonly uint Dm => (_value >> 23) & 0x1; + } + + readonly struct InstRmb19w4 + { + private readonly uint _value; + public InstRmb19w4(uint value) => _value = value; + public readonly uint Rm => (_value >> 19) & 0xF; + } + + readonly struct InstSb20w1Imm3b12w3Rdb8w4Imm2b6w2Stypeb4w2Rmb0w4 + { + private readonly uint _value; + public InstSb20w1Imm3b12w3Rdb8w4Imm2b6w2Stypeb4w2Rmb0w4(uint value) => _value = value; + public readonly uint Rm => (_value >> 0) & 0xF; + public readonly uint Stype => (_value >> 4) & 0x3; + public readonly uint Imm2 => (_value >> 6) & 0x3; + public readonly uint Rd => (_value >> 8) & 0xF; + public readonly uint Imm3 => (_value >> 12) & 0x7; + public readonly uint S => (_value >> 20) & 0x1; + } + + readonly struct InstCondb28w4Rdb12w4Imm12b0w12 + { + private readonly uint _value; + public InstCondb28w4Rdb12w4Imm12b0w12(uint value) => _value = value; + public readonly uint Imm12 => (_value >> 0) & 0xFFF; + public readonly uint Rd => (_value >> 12) & 0xF; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstDb22w1Sizeb18w2Vdb12w4Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstDb22w1Sizeb18w2Vdb12w4Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Size => (_value >> 18) & 0x3; + public readonly uint D => (_value >> 22) & 0x1; + } + + readonly struct InstCondb28w4Imm24b0w24 + { + private readonly uint _value; + public InstCondb28w4Imm24b0w24(uint value) => _value = value; + public readonly uint Imm24 => (_value >> 0) & 0xFFFFFF; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstCondb24w4Imm8b16w8 + { + private readonly uint _value; + public InstCondb24w4Imm8b16w8(uint value) => _value = value; + public readonly uint Imm8 => (_value >> 16) & 0xFF; + public readonly uint Cond => (_value >> 24) & 0xF; + } + + readonly struct InstImm11b16w11 + { + private readonly uint _value; + public InstImm11b16w11(uint value) => _value = value; + public readonly uint Imm11 => (_value >> 16) & 0x7FF; + } + + readonly struct InstSb26w1Condb22w4Imm6b16w6J1b13w1J2b11w1Imm11b0w11 + { + private readonly uint _value; + public InstSb26w1Condb22w4Imm6b16w6J1b13w1J2b11w1Imm11b0w11(uint value) => _value = value; + public readonly uint Imm11 => (_value >> 0) & 0x7FF; + public readonly uint J2 => (_value >> 11) & 0x1; + public readonly uint J1 => (_value >> 13) & 0x1; + public readonly uint Imm6 => (_value >> 16) & 0x3F; + public readonly uint Cond => (_value >> 22) & 0xF; + public readonly uint S => (_value >> 26) & 0x1; + } + + readonly struct InstSb26w1Imm10b16w10J1b13w1J2b11w1Imm11b0w11 + { + private readonly uint _value; + public InstSb26w1Imm10b16w10J1b13w1J2b11w1Imm11b0w11(uint value) => _value = value; + public readonly uint Imm11 => (_value >> 0) & 0x7FF; + public readonly uint J2 => (_value >> 11) & 0x1; + public readonly uint J1 => (_value >> 13) & 0x1; + public readonly uint Imm10 => (_value >> 16) & 0x3FF; + public readonly uint S => (_value >> 26) & 0x1; + } + + readonly struct InstCondb28w4Msbb16w5Rdb12w4Lsbb7w5 + { + private readonly uint _value; + public InstCondb28w4Msbb16w5Rdb12w4Lsbb7w5(uint value) => _value = value; + public readonly uint Lsb => (_value >> 7) & 0x1F; + public readonly uint Rd => (_value >> 12) & 0xF; + public readonly uint Msb => (_value >> 16) & 0x1F; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstImm3b12w3Rdb8w4Imm2b6w2Msbb0w5 + { + private readonly uint _value; + public InstImm3b12w3Rdb8w4Imm2b6w2Msbb0w5(uint value) => _value = value; + public readonly uint Msb => (_value >> 0) & 0x1F; + public readonly uint Imm2 => (_value >> 6) & 0x3; + public readonly uint Rd => (_value >> 8) & 0xF; + public readonly uint Imm3 => (_value >> 12) & 0x7; + } + + readonly struct InstCondb28w4Msbb16w5Rdb12w4Lsbb7w5Rnb0w4 + { + private readonly uint _value; + public InstCondb28w4Msbb16w5Rdb12w4Lsbb7w5Rnb0w4(uint value) => _value = value; + public readonly uint Rn => (_value >> 0) & 0xF; + public readonly uint Lsb => (_value >> 7) & 0x1F; + public readonly uint Rd => (_value >> 12) & 0xF; + public readonly uint Msb => (_value >> 16) & 0x1F; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstRnb16w4Imm3b12w3Rdb8w4Imm2b6w2Msbb0w5 + { + private readonly uint _value; + public InstRnb16w4Imm3b12w3Rdb8w4Imm2b6w2Msbb0w5(uint value) => _value = value; + public readonly uint Msb => (_value >> 0) & 0x1F; + public readonly uint Imm2 => (_value >> 6) & 0x3; + public readonly uint Rd => (_value >> 8) & 0xF; + public readonly uint Imm3 => (_value >> 12) & 0x7; + public readonly uint Rn => (_value >> 16) & 0xF; + } + + readonly struct InstCondb28w4Imm12b8w12Imm4b0w4 + { + private readonly uint _value; + public InstCondb28w4Imm12b8w12Imm4b0w4(uint value) => _value = value; + public readonly uint Imm4 => (_value >> 0) & 0xF; + public readonly uint Imm12 => (_value >> 8) & 0xFFF; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstImm8b16w8 + { + private readonly uint _value; + public InstImm8b16w8(uint value) => _value = value; + public readonly uint Imm8 => (_value >> 16) & 0xFF; + } + + readonly struct InstCondb28w4Rmb0w4 + { + private readonly uint _value; + public InstCondb28w4Rmb0w4(uint value) => _value = value; + public readonly uint Rm => (_value >> 0) & 0xF; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstHb24w1Imm24b0w24 + { + private readonly uint _value; + public InstHb24w1Imm24b0w24(uint value) => _value = value; + public readonly uint Imm24 => (_value >> 0) & 0xFFFFFF; + public readonly uint H => (_value >> 24) & 0x1; + } + + readonly struct InstSb26w1Imm10hb16w10J1b13w1J2b11w1Imm10lb1w10Hb0w1 + { + private readonly uint _value; + public InstSb26w1Imm10hb16w10J1b13w1J2b11w1Imm10lb1w10Hb0w1(uint value) => _value = value; + public readonly uint H => (_value >> 0) & 0x1; + public readonly uint Imm10l => (_value >> 1) & 0x3FF; + public readonly uint J2 => (_value >> 11) & 0x1; + public readonly uint J1 => (_value >> 13) & 0x1; + public readonly uint Imm10h => (_value >> 16) & 0x3FF; + public readonly uint S => (_value >> 26) & 0x1; + } + + readonly struct InstRmb16w4 + { + private readonly uint _value; + public InstRmb16w4(uint value) => _value = value; + public readonly uint Rm => (_value >> 16) & 0xF; + } + + readonly struct InstOpb27w1Ib25w1Imm5b19w5Rnb16w3 + { + private readonly uint _value; + public InstOpb27w1Ib25w1Imm5b19w5Rnb16w3(uint value) => _value = value; + public readonly uint Rn => (_value >> 16) & 0x7; + public readonly uint Imm5 => (_value >> 19) & 0x1F; + public readonly uint I => (_value >> 25) & 0x1; + public readonly uint Op => (_value >> 27) & 0x1; + } + + readonly struct InstCondb28w4 + { + private readonly uint _value; + public InstCondb28w4(uint value) => _value = value; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstCondb28w4Rdb12w4Rmb0w4 + { + private readonly uint _value; + public InstCondb28w4Rdb12w4Rmb0w4(uint value) => _value = value; + public readonly uint Rm => (_value >> 0) & 0xF; + public readonly uint Rd => (_value >> 12) & 0xF; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstRnb16w4Rdb8w4Rmb0w4 + { + private readonly uint _value; + public InstRnb16w4Rdb8w4Rmb0w4(uint value) => _value = value; + public readonly uint Rm => (_value >> 0) & 0xF; + public readonly uint Rd => (_value >> 8) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + } + + readonly struct InstCondb28w4Rnb16w4Imm12b0w12 + { + private readonly uint _value; + public InstCondb28w4Rnb16w4Imm12b0w12(uint value) => _value = value; + public readonly uint Imm12 => (_value >> 0) & 0xFFF; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstIb26w1Rnb16w4Imm3b12w3Imm8b0w8 + { + private readonly uint _value; + public InstIb26w1Rnb16w4Imm3b12w3Imm8b0w8(uint value) => _value = value; + public readonly uint Imm8 => (_value >> 0) & 0xFF; + public readonly uint Imm3 => (_value >> 12) & 0x7; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint I => (_value >> 26) & 0x1; + } + + readonly struct InstCondb28w4Rnb16w4Imm5b7w5Stypeb5w2Rmb0w4 + { + private readonly uint _value; + public InstCondb28w4Rnb16w4Imm5b7w5Stypeb5w2Rmb0w4(uint value) => _value = value; + public readonly uint Rm => (_value >> 0) & 0xF; + public readonly uint Stype => (_value >> 5) & 0x3; + public readonly uint Imm5 => (_value >> 7) & 0x1F; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstRmb19w3Rnb16w3 + { + private readonly uint _value; + public InstRmb19w3Rnb16w3(uint value) => _value = value; + public readonly uint Rn => (_value >> 16) & 0x7; + public readonly uint Rm => (_value >> 19) & 0x7; + } + + readonly struct InstRnb16w4Imm3b12w3Imm2b6w2Stypeb4w2Rmb0w4 + { + private readonly uint _value; + public InstRnb16w4Imm3b12w3Imm2b6w2Stypeb4w2Rmb0w4(uint value) => _value = value; + public readonly uint Rm => (_value >> 0) & 0xF; + public readonly uint Stype => (_value >> 4) & 0x3; + public readonly uint Imm2 => (_value >> 6) & 0x3; + public readonly uint Imm3 => (_value >> 12) & 0x7; + public readonly uint Rn => (_value >> 16) & 0xF; + } + + readonly struct InstCondb28w4Rnb16w4Rsb8w4Stypeb5w2Rmb0w4 + { + private readonly uint _value; + public InstCondb28w4Rnb16w4Rsb8w4Stypeb5w2Rmb0w4(uint value) => _value = value; + public readonly uint Rm => (_value >> 0) & 0xF; + public readonly uint Stype => (_value >> 5) & 0x3; + public readonly uint Rs => (_value >> 8) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstRnb24w3Imm8b16w8 + { + private readonly uint _value; + public InstRnb24w3Imm8b16w8(uint value) => _value = value; + public readonly uint Imm8 => (_value >> 16) & 0xFF; + public readonly uint Rn => (_value >> 24) & 0x7; + } + + readonly struct InstNb23w1Rmb19w4Rnb16w3 + { + private readonly uint _value; + public InstNb23w1Rmb19w4Rnb16w3(uint value) => _value = value; + public readonly uint Rn => (_value >> 16) & 0x7; + public readonly uint Rm => (_value >> 19) & 0xF; + public readonly uint N => (_value >> 23) & 0x1; + } + + readonly struct InstImodb18w2Mb17w1Ab8w1Ib7w1Fb6w1Modeb0w5 + { + private readonly uint _value; + public InstImodb18w2Mb17w1Ab8w1Ib7w1Fb6w1Modeb0w5(uint value) => _value = value; + public readonly uint Mode => (_value >> 0) & 0x1F; + public readonly uint F => (_value >> 6) & 0x1; + public readonly uint I => (_value >> 7) & 0x1; + public readonly uint A => (_value >> 8) & 0x1; + public readonly uint M => (_value >> 17) & 0x1; + public readonly uint Imod => (_value >> 18) & 0x3; + } + + readonly struct InstImb20w1Ab18w1Ib17w1Fb16w1 + { + private readonly uint _value; + public InstImb20w1Ab18w1Ib17w1Fb16w1(uint value) => _value = value; + public readonly uint F => (_value >> 16) & 0x1; + public readonly uint I => (_value >> 17) & 0x1; + public readonly uint A => (_value >> 18) & 0x1; + public readonly uint Im => (_value >> 20) & 0x1; + } + + readonly struct InstImodb9w2Mb8w1Ab7w1Ib6w1Fb5w1Modeb0w5 + { + private readonly uint _value; + public InstImodb9w2Mb8w1Ab7w1Ib6w1Fb5w1Modeb0w5(uint value) => _value = value; + public readonly uint Mode => (_value >> 0) & 0x1F; + public readonly uint F => (_value >> 5) & 0x1; + public readonly uint I => (_value >> 6) & 0x1; + public readonly uint A => (_value >> 7) & 0x1; + public readonly uint M => (_value >> 8) & 0x1; + public readonly uint Imod => (_value >> 9) & 0x3; + } + + readonly struct InstCondb28w4Szb21w2Rnb16w4Rdb12w4Rmb0w4 + { + private readonly uint _value; + public InstCondb28w4Szb21w2Rnb16w4Rdb12w4Rmb0w4(uint value) => _value = value; + public readonly uint Rm => (_value >> 0) & 0xF; + public readonly uint Rd => (_value >> 12) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint Sz => (_value >> 21) & 0x3; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstRnb16w4Rdb8w4Szb4w2Rmb0w4 + { + private readonly uint _value; + public InstRnb16w4Rdb8w4Szb4w2Rmb0w4(uint value) => _value = value; + public readonly uint Rm => (_value >> 0) & 0xF; + public readonly uint Sz => (_value >> 4) & 0x3; + public readonly uint Rd => (_value >> 8) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + } + + readonly struct InstCondb28w4Optionb0w4 + { + private readonly uint _value; + public InstCondb28w4Optionb0w4(uint value) => _value = value; + public readonly uint Option => (_value >> 0) & 0xF; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstOptionb0w4 + { + private readonly uint _value; + public InstOptionb0w4(uint value) => _value = value; + public readonly uint Option => (_value >> 0) & 0xF; + } + + readonly struct InstCondb28w4Pb24w1Ub23w1Db22w1Wb21w1Rnb16w4Vdb12w4Imm871b1w7 + { + private readonly uint _value; + public InstCondb28w4Pb24w1Ub23w1Db22w1Wb21w1Rnb16w4Vdb12w4Imm871b1w7(uint value) => _value = value; + public readonly uint Imm871 => (_value >> 1) & 0x7F; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint W => (_value >> 21) & 0x1; + public readonly uint D => (_value >> 22) & 0x1; + public readonly uint U => (_value >> 23) & 0x1; + public readonly uint P => (_value >> 24) & 0x1; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstPb24w1Ub23w1Db22w1Wb21w1Rnb16w4Vdb12w4Imm871b1w7 + { + private readonly uint _value; + public InstPb24w1Ub23w1Db22w1Wb21w1Rnb16w4Vdb12w4Imm871b1w7(uint value) => _value = value; + public readonly uint Imm871 => (_value >> 1) & 0x7F; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint W => (_value >> 21) & 0x1; + public readonly uint D => (_value >> 22) & 0x1; + public readonly uint U => (_value >> 23) & 0x1; + public readonly uint P => (_value >> 24) & 0x1; + } + + readonly struct InstImm6b16w6 + { + private readonly uint _value; + public InstImm6b16w6(uint value) => _value = value; + public readonly uint Imm6 => (_value >> 16) & 0x3F; + } + + readonly struct InstFirstcondb20w4Maskb16w4 + { + private readonly uint _value; + public InstFirstcondb20w4Maskb16w4(uint value) => _value = value; + public readonly uint Mask => (_value >> 16) & 0xF; + public readonly uint Firstcond => (_value >> 20) & 0xF; + } + + readonly struct InstCondb28w4Rnb16w4Rtb12w4 + { + private readonly uint _value; + public InstCondb28w4Rnb16w4Rtb12w4(uint value) => _value = value; + public readonly uint Rt => (_value >> 12) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstRnb16w4Rtb12w4 + { + private readonly uint _value; + public InstRnb16w4Rtb12w4(uint value) => _value = value; + public readonly uint Rt => (_value >> 12) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + } + + readonly struct InstRnb16w4Rtb12w4Rt2b8w4 + { + private readonly uint _value; + public InstRnb16w4Rtb12w4Rt2b8w4(uint value) => _value = value; + public readonly uint Rt2 => (_value >> 8) & 0xF; + public readonly uint Rt => (_value >> 12) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + } + + readonly struct InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Imm8b0w8 + { + private readonly uint _value; + public InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Imm8b0w8(uint value) => _value = value; + public readonly uint Imm8 => (_value >> 0) & 0xFF; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint W => (_value >> 21) & 0x1; + public readonly uint U => (_value >> 23) & 0x1; + public readonly uint P => (_value >> 24) & 0x1; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstPb24w1Ub23w1Wb21w1Rnb16w4Imm8b0w8 + { + private readonly uint _value; + public InstPb24w1Ub23w1Wb21w1Rnb16w4Imm8b0w8(uint value) => _value = value; + public readonly uint Imm8 => (_value >> 0) & 0xFF; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint W => (_value >> 21) & 0x1; + public readonly uint U => (_value >> 23) & 0x1; + public readonly uint P => (_value >> 24) & 0x1; + } + + readonly struct InstCondb28w4Pb24w1Ub23w1Wb21w1Imm8b0w8 + { + private readonly uint _value; + public InstCondb28w4Pb24w1Ub23w1Wb21w1Imm8b0w8(uint value) => _value = value; + public readonly uint Imm8 => (_value >> 0) & 0xFF; + public readonly uint W => (_value >> 21) & 0x1; + public readonly uint U => (_value >> 23) & 0x1; + public readonly uint P => (_value >> 24) & 0x1; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstPb24w1Ub23w1Wb21w1Imm8b0w8 + { + private readonly uint _value; + public InstPb24w1Ub23w1Wb21w1Imm8b0w8(uint value) => _value = value; + public readonly uint Imm8 => (_value >> 0) & 0xFF; + public readonly uint W => (_value >> 21) & 0x1; + public readonly uint U => (_value >> 23) & 0x1; + public readonly uint P => (_value >> 24) & 0x1; + } + + readonly struct InstCondb28w4Wb21w1Rnb16w4RegisterListb0w16 + { + private readonly uint _value; + public InstCondb28w4Wb21w1Rnb16w4RegisterListb0w16(uint value) => _value = value; + public readonly uint RegisterList => (_value >> 0) & 0xFFFF; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint W => (_value >> 21) & 0x1; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstRnb24w3RegisterListb16w8 + { + private readonly uint _value; + public InstRnb24w3RegisterListb16w8(uint value) => _value = value; + public readonly uint RegisterList => (_value >> 16) & 0xFF; + public readonly uint Rn => (_value >> 24) & 0x7; + } + + readonly struct InstWb21w1Rnb16w4Pb15w1Mb14w1RegisterListb0w14 + { + private readonly uint _value; + public InstWb21w1Rnb16w4Pb15w1Mb14w1RegisterListb0w14(uint value) => _value = value; + public readonly uint RegisterList => (_value >> 0) & 0x3FFF; + public readonly uint M => (_value >> 14) & 0x1; + public readonly uint P => (_value >> 15) & 0x1; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint W => (_value >> 21) & 0x1; + } + + readonly struct InstCondb28w4Ub23w1Rnb16w4Rtb12w4Imm12b0w12 + { + private readonly uint _value; + public InstCondb28w4Ub23w1Rnb16w4Rtb12w4Imm12b0w12(uint value) => _value = value; + public readonly uint Imm12 => (_value >> 0) & 0xFFF; + public readonly uint Rt => (_value >> 12) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint U => (_value >> 23) & 0x1; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstCondb28w4Ub23w1Rnb16w4Rtb12w4Imm5b7w5Stypeb5w2Rmb0w4 + { + private readonly uint _value; + public InstCondb28w4Ub23w1Rnb16w4Rtb12w4Imm5b7w5Stypeb5w2Rmb0w4(uint value) => _value = value; + public readonly uint Rm => (_value >> 0) & 0xF; + public readonly uint Stype => (_value >> 5) & 0x3; + public readonly uint Imm5 => (_value >> 7) & 0x1F; + public readonly uint Rt => (_value >> 12) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint U => (_value >> 23) & 0x1; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstRnb16w4Rtb12w4Imm8b0w8 + { + private readonly uint _value; + public InstRnb16w4Rtb12w4Imm8b0w8(uint value) => _value = value; + public readonly uint Imm8 => (_value >> 0) & 0xFF; + public readonly uint Rt => (_value >> 12) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + } + + readonly struct InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Imm12b0w12 + { + private readonly uint _value; + public InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Imm12b0w12(uint value) => _value = value; + public readonly uint Imm12 => (_value >> 0) & 0xFFF; + public readonly uint Rt => (_value >> 12) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint W => (_value >> 21) & 0x1; + public readonly uint U => (_value >> 23) & 0x1; + public readonly uint P => (_value >> 24) & 0x1; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstImm5b22w5Rnb19w3Rtb16w3 + { + private readonly uint _value; + public InstImm5b22w5Rnb19w3Rtb16w3(uint value) => _value = value; + public readonly uint Rt => (_value >> 16) & 0x7; + public readonly uint Rn => (_value >> 19) & 0x7; + public readonly uint Imm5 => (_value >> 22) & 0x1F; + } + + readonly struct InstRnb16w4Rtb12w4Imm12b0w12 + { + private readonly uint _value; + public InstRnb16w4Rtb12w4Imm12b0w12(uint value) => _value = value; + public readonly uint Imm12 => (_value >> 0) & 0xFFF; + public readonly uint Rt => (_value >> 12) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + } + + readonly struct InstRnb16w4Rtb12w4Pb10w1Ub9w1Wb8w1Imm8b0w8 + { + private readonly uint _value; + public InstRnb16w4Rtb12w4Pb10w1Ub9w1Wb8w1Imm8b0w8(uint value) => _value = value; + public readonly uint Imm8 => (_value >> 0) & 0xFF; + public readonly uint W => (_value >> 8) & 0x1; + public readonly uint U => (_value >> 9) & 0x1; + public readonly uint P => (_value >> 10) & 0x1; + public readonly uint Rt => (_value >> 12) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + } + + readonly struct InstCondb28w4Pb24w1Ub23w1Wb21w1Rtb12w4Imm12b0w12 + { + private readonly uint _value; + public InstCondb28w4Pb24w1Ub23w1Wb21w1Rtb12w4Imm12b0w12(uint value) => _value = value; + public readonly uint Imm12 => (_value >> 0) & 0xFFF; + public readonly uint Rt => (_value >> 12) & 0xF; + public readonly uint W => (_value >> 21) & 0x1; + public readonly uint U => (_value >> 23) & 0x1; + public readonly uint P => (_value >> 24) & 0x1; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstUb23w1Rtb12w4Imm12b0w12 + { + private readonly uint _value; + public InstUb23w1Rtb12w4Imm12b0w12(uint value) => _value = value; + public readonly uint Imm12 => (_value >> 0) & 0xFFF; + public readonly uint Rt => (_value >> 12) & 0xF; + public readonly uint U => (_value >> 23) & 0x1; + } + + readonly struct InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Imm5b7w5Stypeb5w2Rmb0w4 + { + private readonly uint _value; + public InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Imm5b7w5Stypeb5w2Rmb0w4(uint value) => _value = value; + public readonly uint Rm => (_value >> 0) & 0xF; + public readonly uint Stype => (_value >> 5) & 0x3; + public readonly uint Imm5 => (_value >> 7) & 0x1F; + public readonly uint Rt => (_value >> 12) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint W => (_value >> 21) & 0x1; + public readonly uint U => (_value >> 23) & 0x1; + public readonly uint P => (_value >> 24) & 0x1; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstRmb22w3Rnb19w3Rtb16w3 + { + private readonly uint _value; + public InstRmb22w3Rnb19w3Rtb16w3(uint value) => _value = value; + public readonly uint Rt => (_value >> 16) & 0x7; + public readonly uint Rn => (_value >> 19) & 0x7; + public readonly uint Rm => (_value >> 22) & 0x7; + } + + readonly struct InstRnb16w4Rtb12w4Imm2b4w2Rmb0w4 + { + private readonly uint _value; + public InstRnb16w4Rtb12w4Imm2b4w2Rmb0w4(uint value) => _value = value; + public readonly uint Rm => (_value >> 0) & 0xF; + public readonly uint Imm2 => (_value >> 4) & 0x3; + public readonly uint Rt => (_value >> 12) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + } + + readonly struct InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Imm4hb8w4Imm4lb0w4 + { + private readonly uint _value; + public InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Imm4hb8w4Imm4lb0w4(uint value) => _value = value; + public readonly uint Imm4l => (_value >> 0) & 0xF; + public readonly uint Imm4h => (_value >> 8) & 0xF; + public readonly uint Rt => (_value >> 12) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint W => (_value >> 21) & 0x1; + public readonly uint U => (_value >> 23) & 0x1; + public readonly uint P => (_value >> 24) & 0x1; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstPb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Rt2b8w4Imm8b0w8 + { + private readonly uint _value; + public InstPb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Rt2b8w4Imm8b0w8(uint value) => _value = value; + public readonly uint Imm8 => (_value >> 0) & 0xFF; + public readonly uint Rt2 => (_value >> 8) & 0xF; + public readonly uint Rt => (_value >> 12) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint W => (_value >> 21) & 0x1; + public readonly uint U => (_value >> 23) & 0x1; + public readonly uint P => (_value >> 24) & 0x1; + } + + readonly struct InstCondb28w4Ub23w1Rtb12w4Imm4hb8w4Imm4lb0w4 + { + private readonly uint _value; + public InstCondb28w4Ub23w1Rtb12w4Imm4hb8w4Imm4lb0w4(uint value) => _value = value; + public readonly uint Imm4l => (_value >> 0) & 0xF; + public readonly uint Imm4h => (_value >> 8) & 0xF; + public readonly uint Rt => (_value >> 12) & 0xF; + public readonly uint U => (_value >> 23) & 0x1; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstPb24w1Ub23w1Wb21w1Rtb12w4Rt2b8w4Imm8b0w8 + { + private readonly uint _value; + public InstPb24w1Ub23w1Wb21w1Rtb12w4Rt2b8w4Imm8b0w8(uint value) => _value = value; + public readonly uint Imm8 => (_value >> 0) & 0xFF; + public readonly uint Rt2 => (_value >> 8) & 0xF; + public readonly uint Rt => (_value >> 12) & 0xF; + public readonly uint W => (_value >> 21) & 0x1; + public readonly uint U => (_value >> 23) & 0x1; + public readonly uint P => (_value >> 24) & 0x1; + } + + readonly struct InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Rmb0w4 + { + private readonly uint _value; + public InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Rmb0w4(uint value) => _value = value; + public readonly uint Rm => (_value >> 0) & 0xF; + public readonly uint Rt => (_value >> 12) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint W => (_value >> 21) & 0x1; + public readonly uint U => (_value >> 23) & 0x1; + public readonly uint P => (_value >> 24) & 0x1; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstCondb28w4Ub23w1Rnb16w4Rtb12w4Imm4hb8w4Imm4lb0w4 + { + private readonly uint _value; + public InstCondb28w4Ub23w1Rnb16w4Rtb12w4Imm4hb8w4Imm4lb0w4(uint value) => _value = value; + public readonly uint Imm4l => (_value >> 0) & 0xF; + public readonly uint Imm4h => (_value >> 8) & 0xF; + public readonly uint Rt => (_value >> 12) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint U => (_value >> 23) & 0x1; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstCondb28w4Ub23w1Rnb16w4Rtb12w4Rmb0w4 + { + private readonly uint _value; + public InstCondb28w4Ub23w1Rnb16w4Rtb12w4Rmb0w4(uint value) => _value = value; + public readonly uint Rm => (_value >> 0) & 0xF; + public readonly uint Rt => (_value >> 12) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint U => (_value >> 23) & 0x1; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstCondb28w4Pb24w1Ub23w1Wb21w1Rtb12w4Imm4hb8w4Imm4lb0w4 + { + private readonly uint _value; + public InstCondb28w4Pb24w1Ub23w1Wb21w1Rtb12w4Imm4hb8w4Imm4lb0w4(uint value) => _value = value; + public readonly uint Imm4l => (_value >> 0) & 0xF; + public readonly uint Imm4h => (_value >> 8) & 0xF; + public readonly uint Rt => (_value >> 12) & 0xF; + public readonly uint W => (_value >> 21) & 0x1; + public readonly uint U => (_value >> 23) & 0x1; + public readonly uint P => (_value >> 24) & 0x1; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstRtb24w3Imm8b16w8 + { + private readonly uint _value; + public InstRtb24w3Imm8b16w8(uint value) => _value = value; + public readonly uint Imm8 => (_value >> 16) & 0xFF; + public readonly uint Rt => (_value >> 24) & 0x7; + } + + readonly struct InstCondb28w4Opc1b21w3Crnb16w4Rtb12w4Coproc0b8w1Opc2b5w3Crmb0w4 + { + private readonly uint _value; + public InstCondb28w4Opc1b21w3Crnb16w4Rtb12w4Coproc0b8w1Opc2b5w3Crmb0w4(uint value) => _value = value; + public readonly uint Crm => (_value >> 0) & 0xF; + public readonly uint Opc2 => (_value >> 5) & 0x7; + public readonly uint Coproc0 => (_value >> 8) & 0x1; + public readonly uint Rt => (_value >> 12) & 0xF; + public readonly uint Crn => (_value >> 16) & 0xF; + public readonly uint Opc1 => (_value >> 21) & 0x7; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstOpc1b21w3Crnb16w4Rtb12w4Coproc0b8w1Opc2b5w3Crmb0w4 + { + private readonly uint _value; + public InstOpc1b21w3Crnb16w4Rtb12w4Coproc0b8w1Opc2b5w3Crmb0w4(uint value) => _value = value; + public readonly uint Crm => (_value >> 0) & 0xF; + public readonly uint Opc2 => (_value >> 5) & 0x7; + public readonly uint Coproc0 => (_value >> 8) & 0x1; + public readonly uint Rt => (_value >> 12) & 0xF; + public readonly uint Crn => (_value >> 16) & 0xF; + public readonly uint Opc1 => (_value >> 21) & 0x7; + } + + readonly struct InstCondb28w4Rt2b16w4Rtb12w4Coproc0b8w1Opc1b4w4Crmb0w4 + { + private readonly uint _value; + public InstCondb28w4Rt2b16w4Rtb12w4Coproc0b8w1Opc1b4w4Crmb0w4(uint value) => _value = value; + public readonly uint Crm => (_value >> 0) & 0xF; + public readonly uint Opc1 => (_value >> 4) & 0xF; + public readonly uint Coproc0 => (_value >> 8) & 0x1; + public readonly uint Rt => (_value >> 12) & 0xF; + public readonly uint Rt2 => (_value >> 16) & 0xF; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstRt2b16w4Rtb12w4Coproc0b8w1Opc1b4w4Crmb0w4 + { + private readonly uint _value; + public InstRt2b16w4Rtb12w4Coproc0b8w1Opc1b4w4Crmb0w4(uint value) => _value = value; + public readonly uint Crm => (_value >> 0) & 0xF; + public readonly uint Opc1 => (_value >> 4) & 0xF; + public readonly uint Coproc0 => (_value >> 8) & 0x1; + public readonly uint Rt => (_value >> 12) & 0xF; + public readonly uint Rt2 => (_value >> 16) & 0xF; + } + + readonly struct InstCondb28w4Sb20w1Rdb16w4Rab12w4Rmb8w4Rnb0w4 + { + private readonly uint _value; + public InstCondb28w4Sb20w1Rdb16w4Rab12w4Rmb8w4Rnb0w4(uint value) => _value = value; + public readonly uint Rn => (_value >> 0) & 0xF; + public readonly uint Rm => (_value >> 8) & 0xF; + public readonly uint Ra => (_value >> 12) & 0xF; + public readonly uint Rd => (_value >> 16) & 0xF; + public readonly uint S => (_value >> 20) & 0x1; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstRnb16w4Rab12w4Rdb8w4Rmb0w4 + { + private readonly uint _value; + public InstRnb16w4Rab12w4Rdb8w4Rmb0w4(uint value) => _value = value; + public readonly uint Rm => (_value >> 0) & 0xF; + public readonly uint Rd => (_value >> 8) & 0xF; + public readonly uint Ra => (_value >> 12) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + } + + readonly struct InstCondb28w4Rdb16w4Rab12w4Rmb8w4Rnb0w4 + { + private readonly uint _value; + public InstCondb28w4Rdb16w4Rab12w4Rmb8w4Rnb0w4(uint value) => _value = value; + public readonly uint Rn => (_value >> 0) & 0xF; + public readonly uint Rm => (_value >> 8) & 0xF; + public readonly uint Ra => (_value >> 12) & 0xF; + public readonly uint Rd => (_value >> 16) & 0xF; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstCondb28w4Imm4b16w4Rdb12w4Imm12b0w12 + { + private readonly uint _value; + public InstCondb28w4Imm4b16w4Rdb12w4Imm12b0w12(uint value) => _value = value; + public readonly uint Imm12 => (_value >> 0) & 0xFFF; + public readonly uint Rd => (_value >> 12) & 0xF; + public readonly uint Imm4 => (_value >> 16) & 0xF; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstIb26w1Imm4b16w4Imm3b12w3Rdb8w4Imm8b0w8 + { + private readonly uint _value; + public InstIb26w1Imm4b16w4Imm3b12w3Rdb8w4Imm8b0w8(uint value) => _value = value; + public readonly uint Imm8 => (_value >> 0) & 0xFF; + public readonly uint Rd => (_value >> 8) & 0xF; + public readonly uint Imm3 => (_value >> 12) & 0x7; + public readonly uint Imm4 => (_value >> 16) & 0xF; + public readonly uint I => (_value >> 26) & 0x1; + } + + readonly struct InstDb23w1Rmb19w4Rdb16w3 + { + private readonly uint _value; + public InstDb23w1Rmb19w4Rdb16w3(uint value) => _value = value; + public readonly uint Rd => (_value >> 16) & 0x7; + public readonly uint Rm => (_value >> 19) & 0xF; + public readonly uint D => (_value >> 23) & 0x1; + } + + readonly struct InstOpb27w2Imm5b22w5Rmb19w3Rdb16w3 + { + private readonly uint _value; + public InstOpb27w2Imm5b22w5Rmb19w3Rdb16w3(uint value) => _value = value; + public readonly uint Rd => (_value >> 16) & 0x7; + public readonly uint Rm => (_value >> 19) & 0x7; + public readonly uint Imm5 => (_value >> 22) & 0x1F; + public readonly uint Op => (_value >> 27) & 0x3; + } + + readonly struct InstCondb28w4Sb20w1Rdb12w4Rsb8w4Stypeb5w2Rmb0w4 + { + private readonly uint _value; + public InstCondb28w4Sb20w1Rdb12w4Rsb8w4Stypeb5w2Rmb0w4(uint value) => _value = value; + public readonly uint Rm => (_value >> 0) & 0xF; + public readonly uint Stype => (_value >> 5) & 0x3; + public readonly uint Rs => (_value >> 8) & 0xF; + public readonly uint Rd => (_value >> 12) & 0xF; + public readonly uint S => (_value >> 20) & 0x1; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstRsb19w3Rdmb16w3 + { + private readonly uint _value; + public InstRsb19w3Rdmb16w3(uint value) => _value = value; + public readonly uint Rdm => (_value >> 16) & 0x7; + public readonly uint Rs => (_value >> 19) & 0x7; + } + + readonly struct InstStypeb21w2Sb20w1Rmb16w4Rdb8w4Rsb0w4 + { + private readonly uint _value; + public InstStypeb21w2Sb20w1Rmb16w4Rdb8w4Rsb0w4(uint value) => _value = value; + public readonly uint Rs => (_value >> 0) & 0xF; + public readonly uint Rd => (_value >> 8) & 0xF; + public readonly uint Rm => (_value >> 16) & 0xF; + public readonly uint S => (_value >> 20) & 0x1; + public readonly uint Stype => (_value >> 21) & 0x3; + } + + readonly struct InstCondb28w4Rb22w1Rdb12w4 + { + private readonly uint _value; + public InstCondb28w4Rb22w1Rdb12w4(uint value) => _value = value; + public readonly uint Rd => (_value >> 12) & 0xF; + public readonly uint R => (_value >> 22) & 0x1; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstRb20w1Rdb8w4 + { + private readonly uint _value; + public InstRb20w1Rdb8w4(uint value) => _value = value; + public readonly uint Rd => (_value >> 8) & 0xF; + public readonly uint R => (_value >> 20) & 0x1; + } + + readonly struct InstCondb28w4Rb22w1M1b16w4Rdb12w4Mb8w1 + { + private readonly uint _value; + public InstCondb28w4Rb22w1M1b16w4Rdb12w4Mb8w1(uint value) => _value = value; + public readonly uint M => (_value >> 8) & 0x1; + public readonly uint Rd => (_value >> 12) & 0xF; + public readonly uint M1 => (_value >> 16) & 0xF; + public readonly uint R => (_value >> 22) & 0x1; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstRb20w1M1b16w4Rdb8w4Mb4w1 + { + private readonly uint _value; + public InstRb20w1M1b16w4Rdb8w4Mb4w1(uint value) => _value = value; + public readonly uint M => (_value >> 4) & 0x1; + public readonly uint Rd => (_value >> 8) & 0xF; + public readonly uint M1 => (_value >> 16) & 0xF; + public readonly uint R => (_value >> 20) & 0x1; + } + + readonly struct InstCondb28w4Rb22w1M1b16w4Mb8w1Rnb0w4 + { + private readonly uint _value; + public InstCondb28w4Rb22w1M1b16w4Mb8w1Rnb0w4(uint value) => _value = value; + public readonly uint Rn => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 8) & 0x1; + public readonly uint M1 => (_value >> 16) & 0xF; + public readonly uint R => (_value >> 22) & 0x1; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstRb20w1Rnb16w4M1b8w4Mb4w1 + { + private readonly uint _value; + public InstRb20w1Rnb16w4M1b8w4Mb4w1(uint value) => _value = value; + public readonly uint M => (_value >> 4) & 0x1; + public readonly uint M1 => (_value >> 8) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint R => (_value >> 20) & 0x1; + } + + readonly struct InstCondb28w4Rb22w1Maskb16w4Imm12b0w12 + { + private readonly uint _value; + public InstCondb28w4Rb22w1Maskb16w4Imm12b0w12(uint value) => _value = value; + public readonly uint Imm12 => (_value >> 0) & 0xFFF; + public readonly uint Mask => (_value >> 16) & 0xF; + public readonly uint R => (_value >> 22) & 0x1; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstCondb28w4Rb22w1Maskb16w4Rnb0w4 + { + private readonly uint _value; + public InstCondb28w4Rb22w1Maskb16w4Rnb0w4(uint value) => _value = value; + public readonly uint Rn => (_value >> 0) & 0xF; + public readonly uint Mask => (_value >> 16) & 0xF; + public readonly uint R => (_value >> 22) & 0x1; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstRb20w1Rnb16w4Maskb8w4 + { + private readonly uint _value; + public InstRb20w1Rnb16w4Maskb8w4(uint value) => _value = value; + public readonly uint Mask => (_value >> 8) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint R => (_value >> 20) & 0x1; + } + + readonly struct InstCondb28w4Sb20w1Rdb16w4Rmb8w4Rnb0w4 + { + private readonly uint _value; + public InstCondb28w4Sb20w1Rdb16w4Rmb8w4Rnb0w4(uint value) => _value = value; + public readonly uint Rn => (_value >> 0) & 0xF; + public readonly uint Rm => (_value >> 8) & 0xF; + public readonly uint Rd => (_value >> 16) & 0xF; + public readonly uint S => (_value >> 20) & 0x1; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstRnb19w3Rdmb16w3 + { + private readonly uint _value; + public InstRnb19w3Rdmb16w3(uint value) => _value = value; + public readonly uint Rdm => (_value >> 16) & 0x7; + public readonly uint Rn => (_value >> 19) & 0x7; + } + + readonly struct InstRmb19w3Rdb16w3 + { + private readonly uint _value; + public InstRmb19w3Rdb16w3(uint value) => _value = value; + public readonly uint Rd => (_value >> 16) & 0x7; + public readonly uint Rm => (_value >> 19) & 0x7; + } + + readonly struct InstCondb28w4Rnb16w4Rdb12w4Imm5b7w5Tbb6w1Rmb0w4 + { + private readonly uint _value; + public InstCondb28w4Rnb16w4Rdb12w4Imm5b7w5Tbb6w1Rmb0w4(uint value) => _value = value; + public readonly uint Rm => (_value >> 0) & 0xF; + public readonly uint Tb => (_value >> 6) & 0x1; + public readonly uint Imm5 => (_value >> 7) & 0x1F; + public readonly uint Rd => (_value >> 12) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstRnb16w4Imm3b12w3Rdb8w4Imm2b6w2Tbb5w1Rmb0w4 + { + private readonly uint _value; + public InstRnb16w4Imm3b12w3Rdb8w4Imm2b6w2Tbb5w1Rmb0w4(uint value) => _value = value; + public readonly uint Rm => (_value >> 0) & 0xF; + public readonly uint Tb => (_value >> 5) & 0x1; + public readonly uint Imm2 => (_value >> 6) & 0x3; + public readonly uint Rd => (_value >> 8) & 0xF; + public readonly uint Imm3 => (_value >> 12) & 0x7; + public readonly uint Rn => (_value >> 16) & 0xF; + } + + readonly struct InstUb23w1Rb22w1Rnb16w4Imm12b0w12 + { + private readonly uint _value; + public InstUb23w1Rb22w1Rnb16w4Imm12b0w12(uint value) => _value = value; + public readonly uint Imm12 => (_value >> 0) & 0xFFF; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint R => (_value >> 22) & 0x1; + public readonly uint U => (_value >> 23) & 0x1; + } + + readonly struct InstWb21w1Rnb16w4Imm12b0w12 + { + private readonly uint _value; + public InstWb21w1Rnb16w4Imm12b0w12(uint value) => _value = value; + public readonly uint Imm12 => (_value >> 0) & 0xFFF; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint W => (_value >> 21) & 0x1; + } + + readonly struct InstWb21w1Rnb16w4Imm8b0w8 + { + private readonly uint _value; + public InstWb21w1Rnb16w4Imm8b0w8(uint value) => _value = value; + public readonly uint Imm8 => (_value >> 0) & 0xFF; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint W => (_value >> 21) & 0x1; + } + + readonly struct InstUb23w1Imm12b0w12 + { + private readonly uint _value; + public InstUb23w1Imm12b0w12(uint value) => _value = value; + public readonly uint Imm12 => (_value >> 0) & 0xFFF; + public readonly uint U => (_value >> 23) & 0x1; + } + + readonly struct InstUb23w1Rb22w1Rnb16w4Imm5b7w5Stypeb5w2Rmb0w4 + { + private readonly uint _value; + public InstUb23w1Rb22w1Rnb16w4Imm5b7w5Stypeb5w2Rmb0w4(uint value) => _value = value; + public readonly uint Rm => (_value >> 0) & 0xF; + public readonly uint Stype => (_value >> 5) & 0x3; + public readonly uint Imm5 => (_value >> 7) & 0x1F; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint R => (_value >> 22) & 0x1; + public readonly uint U => (_value >> 23) & 0x1; + } + + readonly struct InstWb21w1Rnb16w4Imm2b4w2Rmb0w4 + { + private readonly uint _value; + public InstWb21w1Rnb16w4Imm2b4w2Rmb0w4(uint value) => _value = value; + public readonly uint Rm => (_value >> 0) & 0xF; + public readonly uint Imm2 => (_value >> 4) & 0x3; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint W => (_value >> 21) & 0x1; + } + + readonly struct InstUb23w1Rnb16w4Imm12b0w12 + { + private readonly uint _value; + public InstUb23w1Rnb16w4Imm12b0w12(uint value) => _value = value; + public readonly uint Imm12 => (_value >> 0) & 0xFFF; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint U => (_value >> 23) & 0x1; + } + + readonly struct InstRnb16w4Imm12b0w12 + { + private readonly uint _value; + public InstRnb16w4Imm12b0w12(uint value) => _value = value; + public readonly uint Imm12 => (_value >> 0) & 0xFFF; + public readonly uint Rn => (_value >> 16) & 0xF; + } + + readonly struct InstRnb16w4Imm8b0w8 + { + private readonly uint _value; + public InstRnb16w4Imm8b0w8(uint value) => _value = value; + public readonly uint Imm8 => (_value >> 0) & 0xFF; + public readonly uint Rn => (_value >> 16) & 0xF; + } + + readonly struct InstUb23w1Rnb16w4Imm5b7w5Stypeb5w2Rmb0w4 + { + private readonly uint _value; + public InstUb23w1Rnb16w4Imm5b7w5Stypeb5w2Rmb0w4(uint value) => _value = value; + public readonly uint Rm => (_value >> 0) & 0xF; + public readonly uint Stype => (_value >> 5) & 0x3; + public readonly uint Imm5 => (_value >> 7) & 0x1F; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint U => (_value >> 23) & 0x1; + } + + readonly struct InstRnb16w4Imm2b4w2Rmb0w4 + { + private readonly uint _value; + public InstRnb16w4Imm2b4w2Rmb0w4(uint value) => _value = value; + public readonly uint Rm => (_value >> 0) & 0xF; + public readonly uint Imm2 => (_value >> 4) & 0x3; + public readonly uint Rn => (_value >> 16) & 0xF; + } + + readonly struct InstPb24w1RegisterListb16w8 + { + private readonly uint _value; + public InstPb24w1RegisterListb16w8(uint value) => _value = value; + public readonly uint RegisterList => (_value >> 16) & 0xFF; + public readonly uint P => (_value >> 24) & 0x1; + } + + readonly struct InstMb24w1RegisterListb16w8 + { + private readonly uint _value; + public InstMb24w1RegisterListb16w8(uint value) => _value = value; + public readonly uint RegisterList => (_value >> 16) & 0xFF; + public readonly uint M => (_value >> 24) & 0x1; + } + + readonly struct InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 + { + private readonly uint _value; + public InstCondb28w4Rnb16w4Rdb12w4Rmb0w4(uint value) => _value = value; + public readonly uint Rm => (_value >> 0) & 0xF; + public readonly uint Rd => (_value >> 12) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstRnb19w3Rdb16w3 + { + private readonly uint _value; + public InstRnb19w3Rdb16w3(uint value) => _value = value; + public readonly uint Rd => (_value >> 16) & 0x7; + public readonly uint Rn => (_value >> 19) & 0x7; + } + + readonly struct InstCondb28w4Widthm1b16w5Rdb12w4Lsbb7w5Rnb0w4 + { + private readonly uint _value; + public InstCondb28w4Widthm1b16w5Rdb12w4Lsbb7w5Rnb0w4(uint value) => _value = value; + public readonly uint Rn => (_value >> 0) & 0xF; + public readonly uint Lsb => (_value >> 7) & 0x1F; + public readonly uint Rd => (_value >> 12) & 0xF; + public readonly uint Widthm1 => (_value >> 16) & 0x1F; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstRnb16w4Imm3b12w3Rdb8w4Imm2b6w2Widthm1b0w5 + { + private readonly uint _value; + public InstRnb16w4Imm3b12w3Rdb8w4Imm2b6w2Widthm1b0w5(uint value) => _value = value; + public readonly uint Widthm1 => (_value >> 0) & 0x1F; + public readonly uint Imm2 => (_value >> 6) & 0x3; + public readonly uint Rd => (_value >> 8) & 0xF; + public readonly uint Imm3 => (_value >> 12) & 0x7; + public readonly uint Rn => (_value >> 16) & 0xF; + } + + readonly struct InstCondb28w4Rdb16w4Rmb8w4Rnb0w4 + { + private readonly uint _value; + public InstCondb28w4Rdb16w4Rmb8w4Rnb0w4(uint value) => _value = value; + public readonly uint Rn => (_value >> 0) & 0xF; + public readonly uint Rm => (_value >> 8) & 0xF; + public readonly uint Rd => (_value >> 16) & 0xF; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstEb9w1 + { + private readonly uint _value; + public InstEb9w1(uint value) => _value = value; + public readonly uint E => (_value >> 9) & 0x1; + } + + readonly struct InstEb19w1 + { + private readonly uint _value; + public InstEb19w1(uint value) => _value = value; + public readonly uint E => (_value >> 19) & 0x1; + } + + readonly struct InstImm1b9w1 + { + private readonly uint _value; + public InstImm1b9w1(uint value) => _value = value; + public readonly uint Imm1 => (_value >> 9) & 0x1; + } + + readonly struct InstImm1b19w1 + { + private readonly uint _value; + public InstImm1b19w1(uint value) => _value = value; + public readonly uint Imm1 => (_value >> 19) & 0x1; + } + + readonly struct InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Q => (_value >> 6) & 0x1; + public readonly uint N => (_value >> 7) & 0x1; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Vn => (_value >> 16) & 0xF; + public readonly uint D => (_value >> 22) & 0x1; + } + + readonly struct InstCondb28w4Rdb16w4Rab12w4Rmb8w4Mb6w1Nb5w1Rnb0w4 + { + private readonly uint _value; + public InstCondb28w4Rdb16w4Rab12w4Rmb8w4Mb6w1Nb5w1Rnb0w4(uint value) => _value = value; + public readonly uint Rn => (_value >> 0) & 0xF; + public readonly uint N => (_value >> 5) & 0x1; + public readonly uint M => (_value >> 6) & 0x1; + public readonly uint Rm => (_value >> 8) & 0xF; + public readonly uint Ra => (_value >> 12) & 0xF; + public readonly uint Rd => (_value >> 16) & 0xF; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstRnb16w4Rab12w4Rdb8w4Nb5w1Mb4w1Rmb0w4 + { + private readonly uint _value; + public InstRnb16w4Rab12w4Rdb8w4Nb5w1Mb4w1Rmb0w4(uint value) => _value = value; + public readonly uint Rm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 4) & 0x1; + public readonly uint N => (_value >> 5) & 0x1; + public readonly uint Rd => (_value >> 8) & 0xF; + public readonly uint Ra => (_value >> 12) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + } + + readonly struct InstCondb28w4Rdb16w4Rab12w4Rmb8w4Mb5w1Rnb0w4 + { + private readonly uint _value; + public InstCondb28w4Rdb16w4Rab12w4Rmb8w4Mb5w1Rnb0w4(uint value) => _value = value; + public readonly uint Rn => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Rm => (_value >> 8) & 0xF; + public readonly uint Ra => (_value >> 12) & 0xF; + public readonly uint Rd => (_value >> 16) & 0xF; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstRnb16w4Rab12w4Rdb8w4Mb4w1Rmb0w4 + { + private readonly uint _value; + public InstRnb16w4Rab12w4Rdb8w4Mb4w1Rmb0w4(uint value) => _value = value; + public readonly uint Rm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 4) & 0x1; + public readonly uint Rd => (_value >> 8) & 0xF; + public readonly uint Ra => (_value >> 12) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + } + + readonly struct InstCondb28w4Sb20w1Rdhib16w4Rdlob12w4Rmb8w4Rnb0w4 + { + private readonly uint _value; + public InstCondb28w4Sb20w1Rdhib16w4Rdlob12w4Rmb8w4Rnb0w4(uint value) => _value = value; + public readonly uint Rn => (_value >> 0) & 0xF; + public readonly uint Rm => (_value >> 8) & 0xF; + public readonly uint Rdlo => (_value >> 12) & 0xF; + public readonly uint Rdhi => (_value >> 16) & 0xF; + public readonly uint S => (_value >> 20) & 0x1; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstRnb16w4Rdlob12w4Rdhib8w4Rmb0w4 + { + private readonly uint _value; + public InstRnb16w4Rdlob12w4Rdhib8w4Rmb0w4(uint value) => _value = value; + public readonly uint Rm => (_value >> 0) & 0xF; + public readonly uint Rdhi => (_value >> 8) & 0xF; + public readonly uint Rdlo => (_value >> 12) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + } + + readonly struct InstCondb28w4Rdhib16w4Rdlob12w4Rmb8w4Mb6w1Nb5w1Rnb0w4 + { + private readonly uint _value; + public InstCondb28w4Rdhib16w4Rdlob12w4Rmb8w4Mb6w1Nb5w1Rnb0w4(uint value) => _value = value; + public readonly uint Rn => (_value >> 0) & 0xF; + public readonly uint N => (_value >> 5) & 0x1; + public readonly uint M => (_value >> 6) & 0x1; + public readonly uint Rm => (_value >> 8) & 0xF; + public readonly uint Rdlo => (_value >> 12) & 0xF; + public readonly uint Rdhi => (_value >> 16) & 0xF; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstRnb16w4Rdlob12w4Rdhib8w4Nb5w1Mb4w1Rmb0w4 + { + private readonly uint _value; + public InstRnb16w4Rdlob12w4Rdhib8w4Nb5w1Mb4w1Rmb0w4(uint value) => _value = value; + public readonly uint Rm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 4) & 0x1; + public readonly uint N => (_value >> 5) & 0x1; + public readonly uint Rdhi => (_value >> 8) & 0xF; + public readonly uint Rdlo => (_value >> 12) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + } + + readonly struct InstCondb28w4Rdhib16w4Rdlob12w4Rmb8w4Mb5w1Rnb0w4 + { + private readonly uint _value; + public InstCondb28w4Rdhib16w4Rdlob12w4Rmb8w4Mb5w1Rnb0w4(uint value) => _value = value; + public readonly uint Rn => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Rm => (_value >> 8) & 0xF; + public readonly uint Rdlo => (_value >> 12) & 0xF; + public readonly uint Rdhi => (_value >> 16) & 0xF; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstRnb16w4Rdlob12w4Rdhib8w4Mb4w1Rmb0w4 + { + private readonly uint _value; + public InstRnb16w4Rdlob12w4Rdhib8w4Mb4w1Rmb0w4(uint value) => _value = value; + public readonly uint Rm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 4) & 0x1; + public readonly uint Rdhi => (_value >> 8) & 0xF; + public readonly uint Rdlo => (_value >> 12) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + } + + readonly struct InstCondb28w4Rdb16w4Rab12w4Rmb8w4Mb6w1Rnb0w4 + { + private readonly uint _value; + public InstCondb28w4Rdb16w4Rab12w4Rmb8w4Mb6w1Rnb0w4(uint value) => _value = value; + public readonly uint Rn => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 6) & 0x1; + public readonly uint Rm => (_value >> 8) & 0xF; + public readonly uint Ra => (_value >> 12) & 0xF; + public readonly uint Rd => (_value >> 16) & 0xF; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstCondb28w4Rdb16w4Rab12w4Rmb8w4Rb5w1Rnb0w4 + { + private readonly uint _value; + public InstCondb28w4Rdb16w4Rab12w4Rmb8w4Rb5w1Rnb0w4(uint value) => _value = value; + public readonly uint Rn => (_value >> 0) & 0xF; + public readonly uint R => (_value >> 5) & 0x1; + public readonly uint Rm => (_value >> 8) & 0xF; + public readonly uint Ra => (_value >> 12) & 0xF; + public readonly uint Rd => (_value >> 16) & 0xF; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstRnb16w4Rab12w4Rdb8w4Rb4w1Rmb0w4 + { + private readonly uint _value; + public InstRnb16w4Rab12w4Rdb8w4Rb4w1Rmb0w4(uint value) => _value = value; + public readonly uint Rm => (_value >> 0) & 0xF; + public readonly uint R => (_value >> 4) & 0x1; + public readonly uint Rd => (_value >> 8) & 0xF; + public readonly uint Ra => (_value >> 12) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + } + + readonly struct InstCondb28w4Rdb16w4Rmb8w4Rb5w1Rnb0w4 + { + private readonly uint _value; + public InstCondb28w4Rdb16w4Rmb8w4Rb5w1Rnb0w4(uint value) => _value = value; + public readonly uint Rn => (_value >> 0) & 0xF; + public readonly uint R => (_value >> 5) & 0x1; + public readonly uint Rm => (_value >> 8) & 0xF; + public readonly uint Rd => (_value >> 16) & 0xF; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstRnb16w4Rdb8w4Rb4w1Rmb0w4 + { + private readonly uint _value; + public InstRnb16w4Rdb8w4Rb4w1Rmb0w4(uint value) => _value = value; + public readonly uint Rm => (_value >> 0) & 0xF; + public readonly uint R => (_value >> 4) & 0x1; + public readonly uint Rd => (_value >> 8) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + } + + readonly struct InstCondb28w4Rdb16w4Rmb8w4Mb5w1Rnb0w4 + { + private readonly uint _value; + public InstCondb28w4Rdb16w4Rmb8w4Mb5w1Rnb0w4(uint value) => _value = value; + public readonly uint Rn => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Rm => (_value >> 8) & 0xF; + public readonly uint Rd => (_value >> 16) & 0xF; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstRnb16w4Rdb8w4Mb4w1Rmb0w4 + { + private readonly uint _value; + public InstRnb16w4Rdb8w4Mb4w1Rmb0w4(uint value) => _value = value; + public readonly uint Rm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 4) & 0x1; + public readonly uint Rd => (_value >> 8) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + } + + readonly struct InstCondb28w4Rdb16w4Rmb8w4Mb6w1Nb5w1Rnb0w4 + { + private readonly uint _value; + public InstCondb28w4Rdb16w4Rmb8w4Mb6w1Nb5w1Rnb0w4(uint value) => _value = value; + public readonly uint Rn => (_value >> 0) & 0xF; + public readonly uint N => (_value >> 5) & 0x1; + public readonly uint M => (_value >> 6) & 0x1; + public readonly uint Rm => (_value >> 8) & 0xF; + public readonly uint Rd => (_value >> 16) & 0xF; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstRnb16w4Rdb8w4Nb5w1Mb4w1Rmb0w4 + { + private readonly uint _value; + public InstRnb16w4Rdb8w4Nb5w1Mb4w1Rmb0w4(uint value) => _value = value; + public readonly uint Rm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 4) & 0x1; + public readonly uint N => (_value >> 5) & 0x1; + public readonly uint Rd => (_value >> 8) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + } + + readonly struct InstCondb28w4Rdb16w4Rmb8w4Mb6w1Rnb0w4 + { + private readonly uint _value; + public InstCondb28w4Rdb16w4Rmb8w4Mb6w1Rnb0w4(uint value) => _value = value; + public readonly uint Rn => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 6) & 0x1; + public readonly uint Rm => (_value >> 8) & 0xF; + public readonly uint Rd => (_value >> 16) & 0xF; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstCondb28w4SatImmb16w5Rdb12w4Imm5b7w5Shb6w1Rnb0w4 + { + private readonly uint _value; + public InstCondb28w4SatImmb16w5Rdb12w4Imm5b7w5Shb6w1Rnb0w4(uint value) => _value = value; + public readonly uint Rn => (_value >> 0) & 0xF; + public readonly uint Sh => (_value >> 6) & 0x1; + public readonly uint Imm5 => (_value >> 7) & 0x1F; + public readonly uint Rd => (_value >> 12) & 0xF; + public readonly uint SatImm => (_value >> 16) & 0x1F; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstShb21w1Rnb16w4Imm3b12w3Rdb8w4Imm2b6w2SatImmb0w5 + { + private readonly uint _value; + public InstShb21w1Rnb16w4Imm3b12w3Rdb8w4Imm2b6w2SatImmb0w5(uint value) => _value = value; + public readonly uint SatImm => (_value >> 0) & 0x1F; + public readonly uint Imm2 => (_value >> 6) & 0x3; + public readonly uint Rd => (_value >> 8) & 0xF; + public readonly uint Imm3 => (_value >> 12) & 0x7; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint Sh => (_value >> 21) & 0x1; + } + + readonly struct InstCondb28w4SatImmb16w4Rdb12w4Rnb0w4 + { + private readonly uint _value; + public InstCondb28w4SatImmb16w4Rdb12w4Rnb0w4(uint value) => _value = value; + public readonly uint Rn => (_value >> 0) & 0xF; + public readonly uint Rd => (_value >> 12) & 0xF; + public readonly uint SatImm => (_value >> 16) & 0xF; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstRnb16w4Rdb8w4SatImmb0w4 + { + private readonly uint _value; + public InstRnb16w4Rdb8w4SatImmb0w4(uint value) => _value = value; + public readonly uint SatImm => (_value >> 0) & 0xF; + public readonly uint Rd => (_value >> 8) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + } + + readonly struct InstCondb28w4Rnb16w4Rtb0w4 + { + private readonly uint _value; + public InstCondb28w4Rnb16w4Rtb0w4(uint value) => _value = value; + public readonly uint Rt => (_value >> 0) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstCondb28w4Rnb16w4Rdb12w4Rtb0w4 + { + private readonly uint _value; + public InstCondb28w4Rnb16w4Rdb12w4Rtb0w4(uint value) => _value = value; + public readonly uint Rt => (_value >> 0) & 0xF; + public readonly uint Rd => (_value >> 12) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstRnb16w4Rtb12w4Rdb0w4 + { + private readonly uint _value; + public InstRnb16w4Rtb12w4Rdb0w4(uint value) => _value = value; + public readonly uint Rd => (_value >> 0) & 0xF; + public readonly uint Rt => (_value >> 12) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + } + + readonly struct InstRnb16w4Rtb12w4Rt2b8w4Rdb0w4 + { + private readonly uint _value; + public InstRnb16w4Rtb12w4Rt2b8w4Rdb0w4(uint value) => _value = value; + public readonly uint Rd => (_value >> 0) & 0xF; + public readonly uint Rt2 => (_value >> 8) & 0xF; + public readonly uint Rt => (_value >> 12) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + } + + readonly struct InstWb21w1Rnb16w4Mb14w1RegisterListb0w14 + { + private readonly uint _value; + public InstWb21w1Rnb16w4Mb14w1RegisterListb0w14(uint value) => _value = value; + public readonly uint RegisterList => (_value >> 0) & 0x3FFF; + public readonly uint M => (_value >> 14) & 0x1; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint W => (_value >> 21) & 0x1; + } + + readonly struct InstRnb16w4Rtb12w4Rdb8w4Imm8b0w8 + { + private readonly uint _value; + public InstRnb16w4Rtb12w4Rdb8w4Imm8b0w8(uint value) => _value = value; + public readonly uint Imm8 => (_value >> 0) & 0xFF; + public readonly uint Rd => (_value >> 8) & 0xF; + public readonly uint Rt => (_value >> 12) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + } + + readonly struct InstCondb28w4Rnb16w4Rdb12w4Rotateb10w2Rmb0w4 + { + private readonly uint _value; + public InstCondb28w4Rnb16w4Rdb12w4Rotateb10w2Rmb0w4(uint value) => _value = value; + public readonly uint Rm => (_value >> 0) & 0xF; + public readonly uint Rotate => (_value >> 10) & 0x3; + public readonly uint Rd => (_value >> 12) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstRnb16w4Rdb8w4Rotateb4w2Rmb0w4 + { + private readonly uint _value; + public InstRnb16w4Rdb8w4Rotateb4w2Rmb0w4(uint value) => _value = value; + public readonly uint Rm => (_value >> 0) & 0xF; + public readonly uint Rotate => (_value >> 4) & 0x3; + public readonly uint Rd => (_value >> 8) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + } + + readonly struct InstCondb28w4Rdb12w4Rotateb10w2Rmb0w4 + { + private readonly uint _value; + public InstCondb28w4Rdb12w4Rotateb10w2Rmb0w4(uint value) => _value = value; + public readonly uint Rm => (_value >> 0) & 0xF; + public readonly uint Rotate => (_value >> 10) & 0x3; + public readonly uint Rd => (_value >> 12) & 0xF; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstRdb8w4Rotateb4w2Rmb0w4 + { + private readonly uint _value; + public InstRdb8w4Rotateb4w2Rmb0w4(uint value) => _value = value; + public readonly uint Rm => (_value >> 0) & 0xF; + public readonly uint Rotate => (_value >> 4) & 0x3; + public readonly uint Rd => (_value >> 8) & 0xF; + } + + readonly struct InstRnb16w4Hb4w1Rmb0w4 + { + private readonly uint _value; + public InstRnb16w4Hb4w1Rmb0w4(uint value) => _value = value; + public readonly uint Rm => (_value >> 0) & 0xF; + public readonly uint H => (_value >> 4) & 0x1; + public readonly uint Rn => (_value >> 16) & 0xF; + } + + readonly struct InstImm12b8w12Imm4b0w4 + { + private readonly uint _value; + public InstImm12b8w12Imm4b0w4(uint value) => _value = value; + public readonly uint Imm4 => (_value >> 0) & 0xF; + public readonly uint Imm12 => (_value >> 8) & 0xFFF; + } + + readonly struct InstImm4b16w4Imm12b0w12 + { + private readonly uint _value; + public InstImm4b16w4Imm12b0w12(uint value) => _value = value; + public readonly uint Imm12 => (_value >> 0) & 0xFFF; + public readonly uint Imm4 => (_value >> 16) & 0xF; + } + + readonly struct InstCondb28w4Rdhib16w4Rdlob12w4Rmb8w4Rnb0w4 + { + private readonly uint _value; + public InstCondb28w4Rdhib16w4Rdlob12w4Rmb8w4Rnb0w4(uint value) => _value = value; + public readonly uint Rn => (_value >> 0) & 0xF; + public readonly uint Rm => (_value >> 8) & 0xF; + public readonly uint Rdlo => (_value >> 12) & 0xF; + public readonly uint Rdhi => (_value >> 16) & 0xF; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Q => (_value >> 6) & 0x1; + public readonly uint N => (_value >> 7) & 0x1; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Vn => (_value >> 16) & 0xF; + public readonly uint Size => (_value >> 20) & 0x3; + public readonly uint D => (_value >> 22) & 0x1; + public readonly uint U => (_value >> 24) & 0x1; + } + + readonly struct InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Q => (_value >> 6) & 0x1; + public readonly uint N => (_value >> 7) & 0x1; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Vn => (_value >> 16) & 0xF; + public readonly uint Size => (_value >> 20) & 0x3; + public readonly uint D => (_value >> 22) & 0x1; + public readonly uint U => (_value >> 28) & 0x1; + } + + readonly struct InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint N => (_value >> 7) & 0x1; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Vn => (_value >> 16) & 0xF; + public readonly uint Size => (_value >> 20) & 0x3; + public readonly uint D => (_value >> 22) & 0x1; + public readonly uint U => (_value >> 24) & 0x1; + } + + readonly struct InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint N => (_value >> 7) & 0x1; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Vn => (_value >> 16) & 0xF; + public readonly uint Size => (_value >> 20) & 0x3; + public readonly uint D => (_value >> 22) & 0x1; + public readonly uint U => (_value >> 28) & 0x1; + } + + readonly struct InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Q => (_value >> 6) & 0x1; + public readonly uint N => (_value >> 7) & 0x1; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Vn => (_value >> 16) & 0xF; + public readonly uint Sz => (_value >> 20) & 0x1; + public readonly uint D => (_value >> 22) & 0x1; + } + + readonly struct InstDb22w1Sizeb18w2Vdb12w4Fb10w1Qb6w1Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstDb22w1Sizeb18w2Vdb12w4Fb10w1Qb6w1Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Q => (_value >> 6) & 0x1; + public readonly uint F => (_value >> 10) & 0x1; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Size => (_value >> 18) & 0x3; + public readonly uint D => (_value >> 22) & 0x1; + } + + readonly struct InstCondb28w4Db22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstCondb28w4Db22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Size => (_value >> 8) & 0x3; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint D => (_value >> 22) & 0x1; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstDb22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstDb22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Size => (_value >> 8) & 0x3; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint D => (_value >> 22) & 0x1; + } + + readonly struct InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint N => (_value >> 7) & 0x1; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Vn => (_value >> 16) & 0xF; + public readonly uint Size => (_value >> 20) & 0x3; + public readonly uint D => (_value >> 22) & 0x1; + } + + readonly struct InstCondb28w4Db22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstCondb28w4Db22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint N => (_value >> 7) & 0x1; + public readonly uint Size => (_value >> 8) & 0x3; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Vn => (_value >> 16) & 0xF; + public readonly uint D => (_value >> 22) & 0x1; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstDb22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstDb22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint N => (_value >> 7) & 0x1; + public readonly uint Size => (_value >> 8) & 0x3; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Vn => (_value >> 16) & 0xF; + public readonly uint D => (_value >> 22) & 0x1; + } + + readonly struct InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Q => (_value >> 6) & 0x1; + public readonly uint N => (_value >> 7) & 0x1; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Vn => (_value >> 16) & 0xF; + public readonly uint Size => (_value >> 20) & 0x3; + public readonly uint D => (_value >> 22) & 0x1; + } + + readonly struct InstIb24w1Db22w1Imm3b16w3Vdb12w4Qb6w1Imm4b0w4 + { + private readonly uint _value; + public InstIb24w1Db22w1Imm3b16w3Vdb12w4Qb6w1Imm4b0w4(uint value) => _value = value; + public readonly uint Imm4 => (_value >> 0) & 0xF; + public readonly uint Q => (_value >> 6) & 0x1; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Imm3 => (_value >> 16) & 0x7; + public readonly uint D => (_value >> 22) & 0x1; + public readonly uint I => (_value >> 24) & 0x1; + } + + readonly struct InstIb28w1Db22w1Imm3b16w3Vdb12w4Qb6w1Imm4b0w4 + { + private readonly uint _value; + public InstIb28w1Db22w1Imm3b16w3Vdb12w4Qb6w1Imm4b0w4(uint value) => _value = value; + public readonly uint Imm4 => (_value >> 0) & 0xF; + public readonly uint Q => (_value >> 6) & 0x1; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Imm3 => (_value >> 16) & 0x7; + public readonly uint D => (_value >> 22) & 0x1; + public readonly uint I => (_value >> 28) & 0x1; + } + + readonly struct InstRotb24w1Db22w1Sb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstRotb24w1Db22w1Sb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Q => (_value >> 6) & 0x1; + public readonly uint N => (_value >> 7) & 0x1; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Vn => (_value >> 16) & 0xF; + public readonly uint S => (_value >> 20) & 0x1; + public readonly uint D => (_value >> 22) & 0x1; + public readonly uint Rot => (_value >> 24) & 0x1; + } + + readonly struct InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Q => (_value >> 6) & 0x1; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Size => (_value >> 18) & 0x3; + public readonly uint D => (_value >> 22) & 0x1; + } + + readonly struct InstRotb23w2Db22w1Sb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstRotb23w2Db22w1Sb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Q => (_value >> 6) & 0x1; + public readonly uint N => (_value >> 7) & 0x1; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Vn => (_value >> 16) & 0xF; + public readonly uint S => (_value >> 20) & 0x1; + public readonly uint D => (_value >> 22) & 0x1; + public readonly uint Rot => (_value >> 23) & 0x3; + } + + readonly struct InstSb23w1Db22w1Rotb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstSb23w1Db22w1Rotb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Q => (_value >> 6) & 0x1; + public readonly uint N => (_value >> 7) & 0x1; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Vn => (_value >> 16) & 0xF; + public readonly uint Rot => (_value >> 20) & 0x3; + public readonly uint D => (_value >> 22) & 0x1; + public readonly uint S => (_value >> 23) & 0x1; + } + + readonly struct InstCondb28w4Db22w1Vdb12w4Sizeb8w2 + { + private readonly uint _value; + public InstCondb28w4Db22w1Vdb12w4Sizeb8w2(uint value) => _value = value; + public readonly uint Size => (_value >> 8) & 0x3; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint D => (_value >> 22) & 0x1; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstDb22w1Vdb12w4Sizeb8w2 + { + private readonly uint _value; + public InstDb22w1Vdb12w4Sizeb8w2(uint value) => _value = value; + public readonly uint Size => (_value >> 8) & 0x3; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint D => (_value >> 22) & 0x1; + } + + readonly struct InstDb22w1Sizeb18w2Vdb12w4Opb7w1Qb6w1Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstDb22w1Sizeb18w2Vdb12w4Opb7w1Qb6w1Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Q => (_value >> 6) & 0x1; + public readonly uint Op => (_value >> 7) & 0x1; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Size => (_value >> 18) & 0x3; + public readonly uint D => (_value >> 22) & 0x1; + } + + readonly struct InstDb22w1Vdb12w4Sizeb8w2Opb7w1Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstDb22w1Vdb12w4Sizeb8w2Opb7w1Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Op => (_value >> 7) & 0x1; + public readonly uint Size => (_value >> 8) & 0x3; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint D => (_value >> 22) & 0x1; + } + + readonly struct InstCondb28w4Db22w1Opb16w1Vdb12w4Szb8w1Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstCondb28w4Db22w1Opb16w1Vdb12w4Szb8w1Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Sz => (_value >> 8) & 0x1; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Op => (_value >> 16) & 0x1; + public readonly uint D => (_value >> 22) & 0x1; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstDb22w1Opb16w1Vdb12w4Szb8w1Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstDb22w1Opb16w1Vdb12w4Szb8w1Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Sz => (_value >> 8) & 0x1; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Op => (_value >> 16) & 0x1; + public readonly uint D => (_value >> 22) & 0x1; + } + + readonly struct InstCondb28w4Db22w1Vdb12w4Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstCondb28w4Db22w1Vdb12w4Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint D => (_value >> 22) & 0x1; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstDb22w1Vdb12w4Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstDb22w1Vdb12w4Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint D => (_value >> 22) & 0x1; + } + + readonly struct InstDb22w1Sizeb18w2Vdb12w4Opb8w1Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstDb22w1Sizeb18w2Vdb12w4Opb8w1Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Op => (_value >> 8) & 0x1; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Size => (_value >> 18) & 0x3; + public readonly uint D => (_value >> 22) & 0x1; + } + + readonly struct InstDb22w1Sizeb18w2Vdb12w4Opb7w2Qb6w1Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstDb22w1Sizeb18w2Vdb12w4Opb7w2Qb6w1Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Q => (_value >> 6) & 0x1; + public readonly uint Op => (_value >> 7) & 0x3; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Size => (_value >> 18) & 0x3; + public readonly uint D => (_value >> 22) & 0x1; + } + + readonly struct InstCondb28w4Db22w1Vdb12w4Sizeb8w2Opb7w1Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstCondb28w4Db22w1Vdb12w4Sizeb8w2Opb7w1Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Op => (_value >> 7) & 0x1; + public readonly uint Size => (_value >> 8) & 0x3; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint D => (_value >> 22) & 0x1; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstUb24w1Db22w1Imm6b16w6Vdb12w4Opb8w2Qb6w1Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstUb24w1Db22w1Imm6b16w6Vdb12w4Opb8w2Qb6w1Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Q => (_value >> 6) & 0x1; + public readonly uint Op => (_value >> 8) & 0x3; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Imm6 => (_value >> 16) & 0x3F; + public readonly uint D => (_value >> 22) & 0x1; + public readonly uint U => (_value >> 24) & 0x1; + } + + readonly struct InstUb28w1Db22w1Imm6b16w6Vdb12w4Opb8w2Qb6w1Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstUb28w1Db22w1Imm6b16w6Vdb12w4Opb8w2Qb6w1Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Q => (_value >> 6) & 0x1; + public readonly uint Op => (_value >> 8) & 0x3; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Imm6 => (_value >> 16) & 0x3F; + public readonly uint D => (_value >> 22) & 0x1; + public readonly uint U => (_value >> 28) & 0x1; + } + + readonly struct InstCondb28w4Db22w1Opb18w1Ub16w1Vdb12w4Sfb8w2Sxb7w1Ib5w1Imm4b0w4 + { + private readonly uint _value; + public InstCondb28w4Db22w1Opb18w1Ub16w1Vdb12w4Sfb8w2Sxb7w1Ib5w1Imm4b0w4(uint value) => _value = value; + public readonly uint Imm4 => (_value >> 0) & 0xF; + public readonly uint I => (_value >> 5) & 0x1; + public readonly uint Sx => (_value >> 7) & 0x1; + public readonly uint Sf => (_value >> 8) & 0x3; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint U => (_value >> 16) & 0x1; + public readonly uint Op => (_value >> 18) & 0x1; + public readonly uint D => (_value >> 22) & 0x1; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstDb22w1Opb18w1Ub16w1Vdb12w4Sfb8w2Sxb7w1Ib5w1Imm4b0w4 + { + private readonly uint _value; + public InstDb22w1Opb18w1Ub16w1Vdb12w4Sfb8w2Sxb7w1Ib5w1Imm4b0w4(uint value) => _value = value; + public readonly uint Imm4 => (_value >> 0) & 0xF; + public readonly uint I => (_value >> 5) & 0x1; + public readonly uint Sx => (_value >> 7) & 0x1; + public readonly uint Sf => (_value >> 8) & 0x3; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint U => (_value >> 16) & 0x1; + public readonly uint Op => (_value >> 18) & 0x1; + public readonly uint D => (_value >> 22) & 0x1; + } + + readonly struct InstCondb28w4Bb22w1Qb21w1Vdb16w4Rtb12w4Db7w1Eb5w1 + { + private readonly uint _value; + public InstCondb28w4Bb22w1Qb21w1Vdb16w4Rtb12w4Db7w1Eb5w1(uint value) => _value = value; + public readonly uint E => (_value >> 5) & 0x1; + public readonly uint D => (_value >> 7) & 0x1; + public readonly uint Rt => (_value >> 12) & 0xF; + public readonly uint Vd => (_value >> 16) & 0xF; + public readonly uint Q => (_value >> 21) & 0x1; + public readonly uint B => (_value >> 22) & 0x1; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstBb22w1Qb21w1Vdb16w4Rtb12w4Db7w1Eb5w1 + { + private readonly uint _value; + public InstBb22w1Qb21w1Vdb16w4Rtb12w4Db7w1Eb5w1(uint value) => _value = value; + public readonly uint E => (_value >> 5) & 0x1; + public readonly uint D => (_value >> 7) & 0x1; + public readonly uint Rt => (_value >> 12) & 0xF; + public readonly uint Vd => (_value >> 16) & 0xF; + public readonly uint Q => (_value >> 21) & 0x1; + public readonly uint B => (_value >> 22) & 0x1; + } + + readonly struct InstDb22w1Imm4b16w4Vdb12w4Qb6w1Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstDb22w1Imm4b16w4Vdb12w4Qb6w1Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Q => (_value >> 6) & 0x1; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Imm4 => (_value >> 16) & 0xF; + public readonly uint D => (_value >> 22) & 0x1; + } + + readonly struct InstDb22w1Vnb16w4Vdb12w4Imm4b8w4Nb7w1Qb6w1Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstDb22w1Vnb16w4Vdb12w4Imm4b8w4Nb7w1Qb6w1Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Q => (_value >> 6) & 0x1; + public readonly uint N => (_value >> 7) & 0x1; + public readonly uint Imm4 => (_value >> 8) & 0xF; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Vn => (_value >> 16) & 0xF; + public readonly uint D => (_value >> 22) & 0x1; + } + + readonly struct InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 + { + private readonly uint _value; + public InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4(uint value) => _value = value; + public readonly uint Rm => (_value >> 0) & 0xF; + public readonly uint IndexAlign => (_value >> 4) & 0xF; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint D => (_value >> 22) & 0x1; + } + + readonly struct InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Tb5w1Ab4w1Rmb0w4 + { + private readonly uint _value; + public InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Tb5w1Ab4w1Rmb0w4(uint value) => _value = value; + public readonly uint Rm => (_value >> 0) & 0xF; + public readonly uint A => (_value >> 4) & 0x1; + public readonly uint T => (_value >> 5) & 0x1; + public readonly uint Size => (_value >> 6) & 0x3; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint D => (_value >> 22) & 0x1; + } + + readonly struct InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 + { + private readonly uint _value; + public InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4(uint value) => _value = value; + public readonly uint Rm => (_value >> 0) & 0xF; + public readonly uint Align => (_value >> 4) & 0x3; + public readonly uint Size => (_value >> 6) & 0x3; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint D => (_value >> 22) & 0x1; + } + + readonly struct InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Tb5w1Rmb0w4 + { + private readonly uint _value; + public InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Tb5w1Rmb0w4(uint value) => _value = value; + public readonly uint Rm => (_value >> 0) & 0xF; + public readonly uint T => (_value >> 5) & 0x1; + public readonly uint Size => (_value >> 6) & 0x3; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint D => (_value >> 22) & 0x1; + } + + readonly struct InstCondb28w4Pb24w1Ub23w1Db22w1Wb21w1Rnb16w4Vdb12w4Imm8b0w8 + { + private readonly uint _value; + public InstCondb28w4Pb24w1Ub23w1Db22w1Wb21w1Rnb16w4Vdb12w4Imm8b0w8(uint value) => _value = value; + public readonly uint Imm8 => (_value >> 0) & 0xFF; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint W => (_value >> 21) & 0x1; + public readonly uint D => (_value >> 22) & 0x1; + public readonly uint U => (_value >> 23) & 0x1; + public readonly uint P => (_value >> 24) & 0x1; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstPb24w1Ub23w1Db22w1Wb21w1Rnb16w4Vdb12w4Imm8b0w8 + { + private readonly uint _value; + public InstPb24w1Ub23w1Db22w1Wb21w1Rnb16w4Vdb12w4Imm8b0w8(uint value) => _value = value; + public readonly uint Imm8 => (_value >> 0) & 0xFF; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint W => (_value >> 21) & 0x1; + public readonly uint D => (_value >> 22) & 0x1; + public readonly uint U => (_value >> 23) & 0x1; + public readonly uint P => (_value >> 24) & 0x1; + } + + readonly struct InstCondb28w4Ub23w1Db22w1Rnb16w4Vdb12w4Sizeb8w2Imm8b0w8 + { + private readonly uint _value; + public InstCondb28w4Ub23w1Db22w1Rnb16w4Vdb12w4Sizeb8w2Imm8b0w8(uint value) => _value = value; + public readonly uint Imm8 => (_value >> 0) & 0xFF; + public readonly uint Size => (_value >> 8) & 0x3; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint D => (_value >> 22) & 0x1; + public readonly uint U => (_value >> 23) & 0x1; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstUb23w1Db22w1Rnb16w4Vdb12w4Sizeb8w2Imm8b0w8 + { + private readonly uint _value; + public InstUb23w1Db22w1Rnb16w4Vdb12w4Sizeb8w2Imm8b0w8(uint value) => _value = value; + public readonly uint Imm8 => (_value >> 0) & 0xFF; + public readonly uint Size => (_value >> 8) & 0x3; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Rn => (_value >> 16) & 0xF; + public readonly uint D => (_value >> 22) & 0x1; + public readonly uint U => (_value >> 23) & 0x1; + } + + readonly struct InstCondb28w4Ub23w1Db22w1Vdb12w4Sizeb8w2Imm8b0w8 + { + private readonly uint _value; + public InstCondb28w4Ub23w1Db22w1Vdb12w4Sizeb8w2Imm8b0w8(uint value) => _value = value; + public readonly uint Imm8 => (_value >> 0) & 0xFF; + public readonly uint Size => (_value >> 8) & 0x3; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint D => (_value >> 22) & 0x1; + public readonly uint U => (_value >> 23) & 0x1; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstUb23w1Db22w1Vdb12w4Sizeb8w2Imm8b0w8 + { + private readonly uint _value; + public InstUb23w1Db22w1Vdb12w4Sizeb8w2Imm8b0w8(uint value) => _value = value; + public readonly uint Imm8 => (_value >> 0) & 0xFF; + public readonly uint Size => (_value >> 8) & 0x3; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint D => (_value >> 22) & 0x1; + public readonly uint U => (_value >> 23) & 0x1; + } + + readonly struct InstQb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Fb8w1Nb7w1Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstQb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Fb8w1Nb7w1Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint N => (_value >> 7) & 0x1; + public readonly uint F => (_value >> 8) & 0x1; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Vn => (_value >> 16) & 0xF; + public readonly uint Size => (_value >> 20) & 0x3; + public readonly uint D => (_value >> 22) & 0x1; + public readonly uint Q => (_value >> 24) & 0x1; + } + + readonly struct InstQb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Fb8w1Nb7w1Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstQb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Fb8w1Nb7w1Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint N => (_value >> 7) & 0x1; + public readonly uint F => (_value >> 8) & 0x1; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Vn => (_value >> 16) & 0xF; + public readonly uint Size => (_value >> 20) & 0x3; + public readonly uint D => (_value >> 22) & 0x1; + public readonly uint Q => (_value >> 28) & 0x1; + } + + readonly struct InstDb22w1Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstDb22w1Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint N => (_value >> 7) & 0x1; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Vn => (_value >> 16) & 0xF; + public readonly uint D => (_value >> 22) & 0x1; + } + + readonly struct InstUb24w1Db22w1Imm3hb19w3Vdb12w4Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstUb24w1Db22w1Imm3hb19w3Vdb12w4Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Imm3h => (_value >> 19) & 0x7; + public readonly uint D => (_value >> 22) & 0x1; + public readonly uint U => (_value >> 24) & 0x1; + } + + readonly struct InstUb28w1Db22w1Imm3hb19w3Vdb12w4Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstUb28w1Db22w1Imm3hb19w3Vdb12w4Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Imm3h => (_value >> 19) & 0x7; + public readonly uint D => (_value >> 22) & 0x1; + public readonly uint U => (_value >> 28) & 0x1; + } + + readonly struct InstCondb28w4Opb20w1Rt2b16w4Rtb12w4Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstCondb28w4Opb20w1Rt2b16w4Rtb12w4Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Rt => (_value >> 12) & 0xF; + public readonly uint Rt2 => (_value >> 16) & 0xF; + public readonly uint Op => (_value >> 20) & 0x1; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstOpb20w1Rt2b16w4Rtb12w4Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstOpb20w1Rt2b16w4Rtb12w4Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Rt => (_value >> 12) & 0xF; + public readonly uint Rt2 => (_value >> 16) & 0xF; + public readonly uint Op => (_value >> 20) & 0x1; + } + + readonly struct InstCondb28w4Opb20w1Vnb16w4Rtb12w4Nb7w1 + { + private readonly uint _value; + public InstCondb28w4Opb20w1Vnb16w4Rtb12w4Nb7w1(uint value) => _value = value; + public readonly uint N => (_value >> 7) & 0x1; + public readonly uint Rt => (_value >> 12) & 0xF; + public readonly uint Vn => (_value >> 16) & 0xF; + public readonly uint Op => (_value >> 20) & 0x1; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstOpb20w1Vnb16w4Rtb12w4Nb7w1 + { + private readonly uint _value; + public InstOpb20w1Vnb16w4Rtb12w4Nb7w1(uint value) => _value = value; + public readonly uint N => (_value >> 7) & 0x1; + public readonly uint Rt => (_value >> 12) & 0xF; + public readonly uint Vn => (_value >> 16) & 0xF; + public readonly uint Op => (_value >> 20) & 0x1; + } + + readonly struct InstCondb28w4Db22w1Imm4hb16w4Vdb12w4Sizeb8w2Imm4lb0w4 + { + private readonly uint _value; + public InstCondb28w4Db22w1Imm4hb16w4Vdb12w4Sizeb8w2Imm4lb0w4(uint value) => _value = value; + public readonly uint Imm4l => (_value >> 0) & 0xF; + public readonly uint Size => (_value >> 8) & 0x3; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Imm4h => (_value >> 16) & 0xF; + public readonly uint D => (_value >> 22) & 0x1; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstDb22w1Imm4hb16w4Vdb12w4Sizeb8w2Imm4lb0w4 + { + private readonly uint _value; + public InstDb22w1Imm4hb16w4Vdb12w4Sizeb8w2Imm4lb0w4(uint value) => _value = value; + public readonly uint Imm4l => (_value >> 0) & 0xF; + public readonly uint Size => (_value >> 8) & 0x3; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Imm4h => (_value >> 16) & 0xF; + public readonly uint D => (_value >> 22) & 0x1; + } + + readonly struct InstCondb28w4Opc1b21w2Vdb16w4Rtb12w4Db7w1Opc2b5w2 + { + private readonly uint _value; + public InstCondb28w4Opc1b21w2Vdb16w4Rtb12w4Db7w1Opc2b5w2(uint value) => _value = value; + public readonly uint Opc2 => (_value >> 5) & 0x3; + public readonly uint D => (_value >> 7) & 0x1; + public readonly uint Rt => (_value >> 12) & 0xF; + public readonly uint Vd => (_value >> 16) & 0xF; + public readonly uint Opc1 => (_value >> 21) & 0x3; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstOpc1b21w2Vdb16w4Rtb12w4Db7w1Opc2b5w2 + { + private readonly uint _value; + public InstOpc1b21w2Vdb16w4Rtb12w4Db7w1Opc2b5w2(uint value) => _value = value; + public readonly uint Opc2 => (_value >> 5) & 0x3; + public readonly uint D => (_value >> 7) & 0x1; + public readonly uint Rt => (_value >> 12) & 0xF; + public readonly uint Vd => (_value >> 16) & 0xF; + public readonly uint Opc1 => (_value >> 21) & 0x3; + } + + readonly struct InstCondb28w4Ub23w1Opc1b21w2Vnb16w4Rtb12w4Nb7w1Opc2b5w2 + { + private readonly uint _value; + public InstCondb28w4Ub23w1Opc1b21w2Vnb16w4Rtb12w4Nb7w1Opc2b5w2(uint value) => _value = value; + public readonly uint Opc2 => (_value >> 5) & 0x3; + public readonly uint N => (_value >> 7) & 0x1; + public readonly uint Rt => (_value >> 12) & 0xF; + public readonly uint Vn => (_value >> 16) & 0xF; + public readonly uint Opc1 => (_value >> 21) & 0x3; + public readonly uint U => (_value >> 23) & 0x1; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstUb23w1Opc1b21w2Vnb16w4Rtb12w4Nb7w1Opc2b5w2 + { + private readonly uint _value; + public InstUb23w1Opc1b21w2Vnb16w4Rtb12w4Nb7w1Opc2b5w2(uint value) => _value = value; + public readonly uint Opc2 => (_value >> 5) & 0x3; + public readonly uint N => (_value >> 7) & 0x1; + public readonly uint Rt => (_value >> 12) & 0xF; + public readonly uint Vn => (_value >> 16) & 0xF; + public readonly uint Opc1 => (_value >> 21) & 0x3; + public readonly uint U => (_value >> 23) & 0x1; + } + + readonly struct InstCondb28w4Regb16w4Rtb12w4 + { + private readonly uint _value; + public InstCondb28w4Regb16w4Rtb12w4(uint value) => _value = value; + public readonly uint Rt => (_value >> 12) & 0xF; + public readonly uint Reg => (_value >> 16) & 0xF; + public readonly uint Cond => (_value >> 28) & 0xF; + } + + readonly struct InstRegb16w4Rtb12w4 + { + private readonly uint _value; + public InstRegb16w4Rtb12w4(uint value) => _value = value; + public readonly uint Rt => (_value >> 12) & 0xF; + public readonly uint Reg => (_value >> 16) & 0xF; + } + + readonly struct InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Opb9w1Nb7w1Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Opb9w1Nb7w1Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint N => (_value >> 7) & 0x1; + public readonly uint Op => (_value >> 9) & 0x1; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Vn => (_value >> 16) & 0xF; + public readonly uint Size => (_value >> 20) & 0x3; + public readonly uint D => (_value >> 22) & 0x1; + public readonly uint U => (_value >> 24) & 0x1; + } + + readonly struct InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Opb9w1Nb7w1Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Opb9w1Nb7w1Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint N => (_value >> 7) & 0x1; + public readonly uint Op => (_value >> 9) & 0x1; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Vn => (_value >> 16) & 0xF; + public readonly uint Size => (_value >> 20) & 0x3; + public readonly uint D => (_value >> 22) & 0x1; + public readonly uint U => (_value >> 28) & 0x1; + } + + readonly struct InstOpb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstOpb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Q => (_value >> 6) & 0x1; + public readonly uint N => (_value >> 7) & 0x1; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Vn => (_value >> 16) & 0xF; + public readonly uint Size => (_value >> 20) & 0x3; + public readonly uint D => (_value >> 22) & 0x1; + public readonly uint Op => (_value >> 24) & 0x1; + } + + readonly struct InstOpb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstOpb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Q => (_value >> 6) & 0x1; + public readonly uint N => (_value >> 7) & 0x1; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Vn => (_value >> 16) & 0xF; + public readonly uint Size => (_value >> 20) & 0x3; + public readonly uint D => (_value >> 22) & 0x1; + public readonly uint Op => (_value >> 28) & 0x1; + } + + readonly struct InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint N => (_value >> 7) & 0x1; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Vn => (_value >> 16) & 0xF; + public readonly uint Sz => (_value >> 20) & 0x1; + public readonly uint D => (_value >> 22) & 0x1; + } + + readonly struct InstQb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstQb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint N => (_value >> 7) & 0x1; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Vn => (_value >> 16) & 0xF; + public readonly uint Size => (_value >> 20) & 0x3; + public readonly uint D => (_value >> 22) & 0x1; + public readonly uint Q => (_value >> 24) & 0x1; + } + + readonly struct InstQb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstQb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint N => (_value >> 7) & 0x1; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Vn => (_value >> 16) & 0xF; + public readonly uint Size => (_value >> 20) & 0x3; + public readonly uint D => (_value >> 22) & 0x1; + public readonly uint Q => (_value >> 28) & 0x1; + } + + readonly struct InstDb22w1Sizeb18w2Vdb12w4Opb6w2Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstDb22w1Sizeb18w2Vdb12w4Opb6w2Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Op => (_value >> 6) & 0x3; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Size => (_value >> 18) & 0x3; + public readonly uint D => (_value >> 22) & 0x1; + } + + readonly struct InstUb24w1Db22w1Imm6b16w6Vdb12w4Opb8w1Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstUb24w1Db22w1Imm6b16w6Vdb12w4Opb8w1Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Op => (_value >> 8) & 0x1; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Imm6 => (_value >> 16) & 0x3F; + public readonly uint D => (_value >> 22) & 0x1; + public readonly uint U => (_value >> 24) & 0x1; + } + + readonly struct InstUb28w1Db22w1Imm6b16w6Vdb12w4Opb8w1Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstUb28w1Db22w1Imm6b16w6Vdb12w4Opb8w1Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Op => (_value >> 8) & 0x1; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Imm6 => (_value >> 16) & 0x3F; + public readonly uint D => (_value >> 22) & 0x1; + public readonly uint U => (_value >> 28) & 0x1; + } + + readonly struct InstUb24w1Db22w1Imm6b16w6Vdb12w4Opb8w1Lb7w1Qb6w1Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstUb24w1Db22w1Imm6b16w6Vdb12w4Opb8w1Lb7w1Qb6w1Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Q => (_value >> 6) & 0x1; + public readonly uint L => (_value >> 7) & 0x1; + public readonly uint Op => (_value >> 8) & 0x1; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Imm6 => (_value >> 16) & 0x3F; + public readonly uint D => (_value >> 22) & 0x1; + public readonly uint U => (_value >> 24) & 0x1; + } + + readonly struct InstUb28w1Db22w1Imm6b16w6Vdb12w4Opb8w1Lb7w1Qb6w1Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstUb28w1Db22w1Imm6b16w6Vdb12w4Opb8w1Lb7w1Qb6w1Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Q => (_value >> 6) & 0x1; + public readonly uint L => (_value >> 7) & 0x1; + public readonly uint Op => (_value >> 8) & 0x1; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Imm6 => (_value >> 16) & 0x3F; + public readonly uint D => (_value >> 22) & 0x1; + public readonly uint U => (_value >> 28) & 0x1; + } + + readonly struct InstDb22w1Sizeb18w2Vdb12w4Fb8w1Qb6w1Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstDb22w1Sizeb18w2Vdb12w4Fb8w1Qb6w1Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Q => (_value >> 6) & 0x1; + public readonly uint F => (_value >> 8) & 0x1; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Size => (_value >> 18) & 0x3; + public readonly uint D => (_value >> 22) & 0x1; + } + + readonly struct InstUb24w1Db22w1Imm6b16w6Vdb12w4Lb7w1Qb6w1Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstUb24w1Db22w1Imm6b16w6Vdb12w4Lb7w1Qb6w1Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Q => (_value >> 6) & 0x1; + public readonly uint L => (_value >> 7) & 0x1; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Imm6 => (_value >> 16) & 0x3F; + public readonly uint D => (_value >> 22) & 0x1; + public readonly uint U => (_value >> 24) & 0x1; + } + + readonly struct InstUb28w1Db22w1Imm6b16w6Vdb12w4Lb7w1Qb6w1Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstUb28w1Db22w1Imm6b16w6Vdb12w4Lb7w1Qb6w1Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Q => (_value >> 6) & 0x1; + public readonly uint L => (_value >> 7) & 0x1; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Imm6 => (_value >> 16) & 0x3F; + public readonly uint D => (_value >> 22) & 0x1; + public readonly uint U => (_value >> 28) & 0x1; + } + + readonly struct InstDb22w1Imm6b16w6Vdb12w4Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstDb22w1Imm6b16w6Vdb12w4Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Imm6 => (_value >> 16) & 0x3F; + public readonly uint D => (_value >> 22) & 0x1; + } + + readonly struct InstDb22w1Ccb20w2Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstDb22w1Ccb20w2Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint N => (_value >> 7) & 0x1; + public readonly uint Size => (_value >> 8) & 0x3; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Vn => (_value >> 16) & 0xF; + public readonly uint Cc => (_value >> 20) & 0x3; + public readonly uint D => (_value >> 22) & 0x1; + } + + readonly struct InstUb24w1Db22w1Imm6b16w6Vdb12w4Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstUb24w1Db22w1Imm6b16w6Vdb12w4Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Imm6 => (_value >> 16) & 0x3F; + public readonly uint D => (_value >> 22) & 0x1; + public readonly uint U => (_value >> 24) & 0x1; + } + + readonly struct InstUb28w1Db22w1Imm6b16w6Vdb12w4Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstUb28w1Db22w1Imm6b16w6Vdb12w4Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Imm6 => (_value >> 16) & 0x3F; + public readonly uint D => (_value >> 22) & 0x1; + public readonly uint U => (_value >> 28) & 0x1; + } + + readonly struct InstDb22w1Imm6b16w6Vdb12w4Lb7w1Qb6w1Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstDb22w1Imm6b16w6Vdb12w4Lb7w1Qb6w1Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Q => (_value >> 6) & 0x1; + public readonly uint L => (_value >> 7) & 0x1; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Imm6 => (_value >> 16) & 0x3F; + public readonly uint D => (_value >> 22) & 0x1; + } + + readonly struct InstDb22w1Vdb12w4Qb6w1Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstDb22w1Vdb12w4Qb6w1Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Q => (_value >> 6) & 0x1; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint D => (_value >> 22) & 0x1; + } + + readonly struct InstDb22w1Vnb16w4Vdb12w4Lenb8w2Nb7w1Opb6w1Mb5w1Vmb0w4 + { + private readonly uint _value; + public InstDb22w1Vnb16w4Vdb12w4Lenb8w2Nb7w1Opb6w1Mb5w1Vmb0w4(uint value) => _value = value; + public readonly uint Vm => (_value >> 0) & 0xF; + public readonly uint M => (_value >> 5) & 0x1; + public readonly uint Op => (_value >> 6) & 0x1; + public readonly uint N => (_value >> 7) & 0x1; + public readonly uint Len => (_value >> 8) & 0x3; + public readonly uint Vd => (_value >> 12) & 0xF; + public readonly uint Vn => (_value >> 16) & 0xF; + public readonly uint D => (_value >> 22) & 0x1; + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/InstFlags.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/InstFlags.cs new file mode 100644 index 000000000..a1937e088 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/InstFlags.cs @@ -0,0 +1,63 @@ +using System; + +namespace Ryujinx.Cpu.LightningJit.Arm32 +{ + [Flags] + enum InstFlags + { + None = 0, + Cond = 1 << 0, + Rd = 1 << 1, + RdLo = 1 << 2, + RdHi = 1 << 3, + Rdn = 1 << 4, + Dn = 1 << 5, + Rt = 1 << 6, + Rt2 = 1 << 7, + Rlist = 1 << 8, + Rd16 = 1 << 9, + ReadRd = 1 << 10, + WBack = 1 << 11, + Thumb16 = 1 << 12, + + RdnDn = Rdn | Dn, + RdRd16 = Rd | Rd16, + RtRt2 = Rt | Rt2, + RdLoRdHi = RdLo | RdHi, + RdLoHi = Rd | RdHi, + RdRtRead = Rd | RtRead, + RdRtReadRd16 = Rd | RtRead | Rd16, + RdRt2Read = Rd | Rt2 | RtRead, + RdRt2ReadRd16 = Rd | Rt2 | RtRead | Rd16, + RtRd16 = Rt | Rd16, + RtWBack = Rt | WBack, + Rt2WBack = Rt2 | RtWBack, + RtRead = Rt | ReadRd, + RtReadRd16 = Rt | ReadRd | Rd16, + Rt2Read = Rt2 | RtRead, + RtReadWBack = RtRead | WBack, + Rt2ReadWBack = Rt2 | RtReadWBack, + RlistWBack = Rlist | WBack, + RlistRead = Rlist | ReadRd, + RlistReadWBack = Rlist | ReadRd | WBack, + + CondRd = Cond | Rd, + CondRdLoHi = Cond | Rd | RdHi, + CondRt = Cond | Rt, + CondRt2 = Cond | Rt | Rt2, + CondRd16 = Cond | Rd | Rd16, + CondWBack = Cond | WBack, + CondRdRtRead = Cond | Rd | RtRead, + CondRdRt2Read = Cond | Rd | Rt2 | RtRead, + CondRtWBack = Cond | RtWBack, + CondRt2WBack = Cond | Rt2 | RtWBack, + CondRtRead = Cond | RtRead, + CondRt2Read = Cond | Rt2 | RtRead, + CondRtReadWBack = Cond | RtReadWBack, + CondRt2ReadWBack = Cond | Rt2 | RtReadWBack, + CondRlist = Cond | Rlist, + CondRlistWBack = Cond | Rlist | WBack, + CondRlistRead = Cond | Rlist | ReadRd, + CondRlistReadWBack = Cond | Rlist | ReadRd | WBack, + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/InstInfo.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/InstInfo.cs new file mode 100644 index 000000000..80481ec69 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/InstInfo.cs @@ -0,0 +1,20 @@ +using System; + +namespace Ryujinx.Cpu.LightningJit.Arm32 +{ + readonly struct InstInfo + { + public readonly uint Encoding; + public readonly InstName Name; + public readonly Action EmitFunc; + public readonly InstFlags Flags; + + public InstInfo(uint encoding, InstName name, Action emitFunc, InstFlags flags) + { + Encoding = encoding; + Name = name; + EmitFunc = emitFunc; + Flags = flags; + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/InstInfoForTable.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/InstInfoForTable.cs new file mode 100644 index 000000000..25739d564 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/InstInfoForTable.cs @@ -0,0 +1,79 @@ +using Ryujinx.Cpu.LightningJit.Table; +using System; + +namespace Ryujinx.Cpu.LightningJit.Arm32 +{ + readonly struct InstInfoForTable : IInstInfo + { + public uint Encoding { get; } + public uint EncodingMask { get; } + public InstEncoding[] Constraints { get; } + public InstMeta Meta { get; } + public IsaVersion Version => Meta.Version; + public IsaFeature Feature => Meta.Feature; + + public InstInfoForTable( + uint encoding, + uint encodingMask, + InstEncoding[] constraints, + InstName name, + Action emitFunc, + IsaVersion isaVersion, + IsaFeature isaFeature, + InstFlags flags) + { + Encoding = encoding; + EncodingMask = encodingMask; + Constraints = constraints; + Meta = new(name, emitFunc, isaVersion, isaFeature, flags); + } + + public InstInfoForTable( + uint encoding, + uint encodingMask, + InstEncoding[] constraints, + InstName name, + Action emitFunc, + IsaVersion isaVersion, + InstFlags flags) : this(encoding, encodingMask, constraints, name, emitFunc, isaVersion, IsaFeature.None, flags) + { + } + + public InstInfoForTable( + uint encoding, + uint encodingMask, + InstName name, + Action emitFunc, + IsaVersion isaVersion, + IsaFeature isaFeature, + InstFlags flags) : this(encoding, encodingMask, null, name, emitFunc, isaVersion, isaFeature, flags) + { + } + + public InstInfoForTable( + uint encoding, + uint encodingMask, + InstName name, + Action emitFunc, + IsaVersion isaVersion, + InstFlags flags) : this(encoding, encodingMask, null, name, emitFunc, isaVersion, IsaFeature.None, flags) + { + } + + public bool IsConstrained(uint encoding) + { + if (Constraints != null) + { + foreach (InstEncoding constraint in Constraints) + { + if ((encoding & constraint.EncodingMask) == constraint.Encoding) + { + return true; + } + } + } + + return false; + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/InstMeta.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/InstMeta.cs new file mode 100644 index 000000000..64eb41bb7 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/InstMeta.cs @@ -0,0 +1,22 @@ +using System; + +namespace Ryujinx.Cpu.LightningJit.Arm32 +{ + readonly struct InstMeta + { + public readonly InstName Name; + public readonly Action EmitFunc; + public readonly IsaVersion Version; + public readonly IsaFeature Feature; + public readonly InstFlags Flags; + + public InstMeta(InstName name, Action emitFunc, IsaVersion isaVersion, IsaFeature isaFeature, InstFlags flags) + { + Name = name; + EmitFunc = emitFunc; + Version = isaVersion; + Feature = isaFeature; + Flags = flags; + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/InstName.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/InstName.cs new file mode 100644 index 000000000..2ee67aa0a --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/InstName.cs @@ -0,0 +1,562 @@ +namespace Ryujinx.Cpu.LightningJit.Arm32 +{ + enum InstName + { + AdcI, + AdcR, + AdcRr, + AddI, + AddR, + AddRr, + AddSpI, + AddSpR, + Adr, + Aesd, + Aese, + Aesimc, + Aesmc, + AndI, + AndR, + AndRr, + B, + Bfc, + Bfi, + BicI, + BicR, + BicRr, + Bkpt, + BlxR, + BlI, + Bx, + Bxj, + Cbnz, + Clrbhb, + Clrex, + Clz, + CmnI, + CmnR, + CmnRr, + CmpI, + CmpR, + CmpRr, + Cps, + Crc32, + Crc32c, + Csdb, + Dbg, + Dcps1, + Dcps2, + Dcps3, + Dmb, + Dsb, + EorI, + EorR, + EorRr, + Eret, + Esb, + Fldmx, + Fstmx, + Hlt, + Hvc, + Isb, + It, + Lda, + Ldab, + Ldaex, + Ldaexb, + Ldaexd, + Ldaexh, + Ldah, + LdcI, + LdcL, + Ldm, + Ldmda, + Ldmdb, + Ldmib, + LdmE, + LdmU, + Ldrbt, + LdrbI, + LdrbL, + LdrbR, + LdrdI, + LdrdL, + LdrdR, + Ldrex, + Ldrexb, + Ldrexd, + Ldrexh, + Ldrht, + LdrhI, + LdrhL, + LdrhR, + Ldrsbt, + LdrsbI, + LdrsbL, + LdrsbR, + Ldrsht, + LdrshI, + LdrshL, + LdrshR, + Ldrt, + LdrI, + LdrL, + LdrR, + Mcr, + Mcrr, + Mla, + Mls, + Movt, + MovI, + MovR, + MovRr, + Mrc, + Mrrc, + Mrs, + MrsBr, + MsrBr, + MsrI, + MsrR, + Mul, + MvnI, + MvnR, + MvnRr, + Nop, + OrnI, + OrnR, + OrrI, + OrrR, + OrrRr, + Pkh, + PldI, + PldL, + PldR, + PliI, + PliR, + Pop, + Pssbb, + Push, + Qadd, + Qadd16, + Qadd8, + Qasx, + Qdadd, + Qdsub, + Qsax, + Qsub, + Qsub16, + Qsub8, + Rbit, + Rev, + Rev16, + Revsh, + Rfe, + RsbI, + RsbR, + RsbRr, + RscI, + RscR, + RscRr, + Sadd16, + Sadd8, + Sasx, + Sb, + SbcI, + SbcR, + SbcRr, + Sbfx, + Sdiv, + Sel, + Setend, + Setpan, + Sev, + Sevl, + Sha1c, + Sha1h, + Sha1m, + Sha1p, + Sha1su0, + Sha1su1, + Sha256h, + Sha256h2, + Sha256su0, + Sha256su1, + Shadd16, + Shadd8, + Shasx, + Shsax, + Shsub16, + Shsub8, + Smc, + Smlabb, + Smlad, + Smlal, + Smlalbb, + Smlald, + Smlawb, + Smlsd, + Smlsld, + Smmla, + Smmls, + Smmul, + Smuad, + Smulbb, + Smull, + Smulwb, + Smusd, + Srs, + Ssat, + Ssat16, + Ssax, + Ssbb, + Ssub16, + Ssub8, + Stc, + Stl, + Stlb, + Stlex, + Stlexb, + Stlexd, + Stlexh, + Stlh, + Stm, + Stmda, + Stmdb, + Stmib, + StmU, + Strbt, + StrbI, + StrbR, + StrdI, + StrdR, + Strex, + Strexb, + Strexd, + Strexh, + Strht, + StrhI, + StrhR, + Strt, + StrI, + StrR, + SubI, + SubR, + SubRr, + SubSpI, + SubSpR, + Svc, + Sxtab, + Sxtab16, + Sxtah, + Sxtb, + Sxtb16, + Sxth, + Tbb, + TeqI, + TeqR, + TeqRr, + Tsb, + TstI, + TstR, + TstRr, + Uadd16, + Uadd8, + Uasx, + Ubfx, + Udf, + Udiv, + Uhadd16, + Uhadd8, + Uhasx, + Uhsax, + Uhsub16, + Uhsub8, + Umaal, + Umlal, + Umull, + Uqadd16, + Uqadd8, + Uqasx, + Uqsax, + Uqsub16, + Uqsub8, + Usad8, + Usada8, + Usat, + Usat16, + Usax, + Usub16, + Usub8, + Uxtab, + Uxtab16, + Uxtah, + Uxtb, + Uxtb16, + Uxth, + Vaba, + Vabal, + VabdlI, + VabdF, + VabdI, + Vabs, + Vacge, + Vacgt, + Vaddhn, + Vaddl, + Vaddw, + VaddF, + VaddI, + VandR, + VbicI, + VbicR, + Vbif, + Vbit, + Vbsl, + Vcadd, + VceqI, + VceqR, + VcgeI, + VcgeR, + VcgtI, + VcgtR, + VcleI, + Vcls, + VcltI, + Vclz, + Vcmla, + VcmlaS, + Vcmp, + Vcmpe, + Vcnt, + VcvtaAsimd, + VcvtaVfp, + Vcvtb, + VcvtbBfs, + VcvtmAsimd, + VcvtmVfp, + VcvtnAsimd, + VcvtnVfp, + VcvtpAsimd, + VcvtpVfp, + VcvtrIv, + Vcvtt, + VcvttBfs, + VcvtBfs, + VcvtDs, + VcvtHs, + VcvtIs, + VcvtIv, + VcvtVi, + VcvtXs, + VcvtXv, + Vdiv, + Vdot, + VdotS, + VdupR, + VdupS, + Veor, + Vext, + Vfma, + Vfmal, + VfmalS, + VfmaBf, + VfmaBfs, + Vfms, + Vfmsl, + VfmslS, + Vfnma, + Vfnms, + Vhadd, + Vhsub, + Vins, + Vjcvt, + Vld11, + Vld1A, + Vld1M, + Vld21, + Vld2A, + Vld2M, + Vld31, + Vld3A, + Vld3M, + Vld41, + Vld4A, + Vld4M, + Vldm, + VldrI, + VldrL, + Vmaxnm, + VmaxF, + VmaxI, + Vminnm, + VminF, + VminI, + VmlalI, + VmlalS, + VmlaF, + VmlaI, + VmlaS, + VmlslI, + VmlslS, + VmlsF, + VmlsI, + VmlsS, + Vmmla, + Vmovl, + Vmovn, + Vmovx, + VmovD, + VmovH, + VmovI, + VmovR, + VmovRs, + VmovS, + VmovSr, + VmovSs, + Vmrs, + Vmsr, + VmullI, + VmullS, + VmulF, + VmulI, + VmulS, + VmvnI, + VmvnR, + Vneg, + Vnmla, + Vnmls, + Vnmul, + VornR, + VorrI, + VorrR, + Vpadal, + Vpaddl, + VpaddF, + VpaddI, + VpmaxF, + VpmaxI, + VpminF, + VpminI, + Vqabs, + Vqadd, + Vqdmlal, + Vqdmlsl, + Vqdmulh, + Vqdmull, + Vqmovn, + Vqneg, + Vqrdmlah, + Vqrdmlsh, + Vqrdmulh, + Vqrshl, + Vqrshrn, + VqshlI, + VqshlR, + Vqshrn, + Vqsub, + Vraddhn, + Vrecpe, + Vrecps, + Vrev16, + Vrev32, + Vrev64, + Vrhadd, + VrintaAsimd, + VrintaVfp, + VrintmAsimd, + VrintmVfp, + VrintnAsimd, + VrintnVfp, + VrintpAsimd, + VrintpVfp, + VrintrVfp, + VrintxAsimd, + VrintxVfp, + VrintzAsimd, + VrintzVfp, + Vrshl, + Vrshr, + Vrshrn, + Vrsqrte, + Vrsqrts, + Vrsra, + Vrsubhn, + Vsdot, + VsdotS, + Vsel, + Vshll, + VshlI, + VshlR, + Vshr, + Vshrn, + Vsli, + Vsmmla, + Vsqrt, + Vsra, + Vsri, + Vst11, + Vst1M, + Vst21, + Vst2M, + Vst31, + Vst3M, + Vst41, + Vst4M, + Vstm, + Vstr, + Vsubhn, + Vsubl, + Vsubw, + VsubF, + VsubI, + VsudotS, + Vswp, + Vtbl, + Vtrn, + Vtst, + Vudot, + VudotS, + Vummla, + Vusdot, + VusdotS, + Vusmmla, + Vuzp, + Vzip, + Wfe, + Wfi, + Yield, + } + + static class InstNameExtensions + { + public static bool IsCall(this InstName name) + { + return name == InstName.BlI || name == InstName.BlxR; + } + + public static bool IsSystem(this InstName name) + { + switch (name) + { + case InstName.Mcr: + case InstName.Mcrr: + case InstName.Mrc: + case InstName.Mrs: + case InstName.MrsBr: + case InstName.MsrBr: + case InstName.MsrI: + case InstName.MsrR: + case InstName.Mrrc: + case InstName.Svc: + return true; + } + + return false; + } + + public static bool IsSystemOrCall(this InstName name) + { + return name.IsSystem() || name.IsCall(); + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/InstTableA32.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/InstTableA32.cs new file mode 100644 index 000000000..2168c0b9f --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/InstTableA32.cs @@ -0,0 +1,1194 @@ +using Ryujinx.Cpu.LightningJit.Table; +using System.Collections.Generic; + +namespace Ryujinx.Cpu.LightningJit.Arm32 +{ + static class InstTableA32 where T : IInstEmit + { + private static readonly InstTableLevel _table; + + static InstTableA32() + { + InstEncoding[] condConstraints = new InstEncoding[] + { + new(0xF0000000, 0xF0000000), + }; + + InstEncoding[] condRnsRnConstraints = new InstEncoding[] + { + new(0xF0000000, 0xF0000000), + new(0x000F0000, 0x001F0000), + new(0x000D0000, 0x000F0000), + }; + + InstEncoding[] condRnConstraints = new InstEncoding[] + { + new(0xF0000000, 0xF0000000), + new(0x000D0000, 0x000F0000), + }; + + InstEncoding[] vdVmConstraints = new InstEncoding[] + { + new(0x00001000, 0x00001000), + new(0x00000001, 0x00000001), + }; + + InstEncoding[] condRnConstraints2 = new InstEncoding[] + { + new(0xF0000000, 0xF0000000), + new(0x0000000F, 0x0000000F), + }; + + InstEncoding[] optionConstraints = new InstEncoding[] + { + new(0x00000000, 0x0000000F), + }; + + InstEncoding[] condPuwPwPuwPuwConstraints = new InstEncoding[] + { + new(0xF0000000, 0xF0000000), + new(0x00000000, 0x01A00000), + new(0x01000000, 0x01200000), + new(0x00200000, 0x01A00000), + new(0x01A00000, 0x01A00000), + }; + + InstEncoding[] condRnPuwConstraints = new InstEncoding[] + { + new(0xF0000000, 0xF0000000), + new(0x000F0000, 0x000F0000), + new(0x00000000, 0x01A00000), + }; + + InstEncoding[] condPuwConstraints = new InstEncoding[] + { + new(0xF0000000, 0xF0000000), + new(0x00000000, 0x01A00000), + }; + + InstEncoding[] condRnPwConstraints = new InstEncoding[] + { + new(0xF0000000, 0xF0000000), + new(0x000F0000, 0x000F0000), + new(0x00200000, 0x01200000), + }; + + InstEncoding[] condPwConstraints = new InstEncoding[] + { + new(0xF0000000, 0xF0000000), + new(0x00200000, 0x01200000), + }; + + InstEncoding[] condRnConstraints3 = new InstEncoding[] + { + new(0xF0000000, 0xF0000000), + new(0x000F0000, 0x000F0000), + }; + + InstEncoding[] condMaskrConstraints = new InstEncoding[] + { + new(0xF0000000, 0xF0000000), + new(0x00000000, 0x004F0000), + }; + + InstEncoding[] rnConstraints = new InstEncoding[] + { + new(0x000F0000, 0x000F0000), + }; + + InstEncoding[] vdVnVmConstraints = new InstEncoding[] + { + new(0x00001000, 0x00001000), + new(0x00010000, 0x00010000), + new(0x00000001, 0x00000001), + }; + + InstEncoding[] condRaConstraints = new InstEncoding[] + { + new(0xF0000000, 0xF0000000), + new(0x0000F000, 0x0000F000), + }; + + InstEncoding[] sizeQvdQvnQvmConstraints = new InstEncoding[] + { + new(0x00300000, 0x00300000), + new(0x00001040, 0x00001040), + new(0x00010040, 0x00010040), + new(0x00000041, 0x00000041), + }; + + InstEncoding[] sizeVdConstraints = new InstEncoding[] + { + new(0x00300000, 0x00300000), + new(0x00001000, 0x00001000), + }; + + InstEncoding[] qvdQvnQvmConstraints = new InstEncoding[] + { + new(0x00001040, 0x00001040), + new(0x00010040, 0x00010040), + new(0x00000041, 0x00000041), + }; + + InstEncoding[] sizeQvdQvmConstraints = new InstEncoding[] + { + new(0x000C0000, 0x000C0000), + new(0x00001040, 0x00001040), + new(0x00000041, 0x00000041), + }; + + InstEncoding[] sizeVnVmConstraints = new InstEncoding[] + { + new(0x00300000, 0x00300000), + new(0x00010000, 0x00010000), + new(0x00000001, 0x00000001), + }; + + InstEncoding[] sizeVdOpvnConstraints = new InstEncoding[] + { + new(0x00300000, 0x00300000), + new(0x00001000, 0x00001000), + new(0x00010100, 0x00010100), + }; + + InstEncoding[] cmodeCmodeQvdConstraints = new InstEncoding[] + { + new(0x00000000, 0x00000100), + new(0x00000C00, 0x00000C00), + new(0x00001040, 0x00001040), + }; + + InstEncoding[] qvdQvnQvmOpConstraints = new InstEncoding[] + { + new(0x00001040, 0x00001040), + new(0x00010040, 0x00010040), + new(0x00000041, 0x00000041), + new(0x00000000, 0x00300000), + }; + + InstEncoding[] qvdQvnQvmSizeConstraints = new InstEncoding[] + { + new(0x00001040, 0x00001040), + new(0x00010040, 0x00010040), + new(0x00000041, 0x00000041), + new(0x00300000, 0x00300000), + }; + + InstEncoding[] qvdQvnConstraints = new InstEncoding[] + { + new(0x00001040, 0x00001040), + new(0x00010040, 0x00010040), + }; + + InstEncoding[] qvdQvmConstraints = new InstEncoding[] + { + new(0x00001040, 0x00001040), + new(0x00000041, 0x00000041), + }; + + InstEncoding[] sizeConstraints = new InstEncoding[] + { + new(0x00000000, 0x00000300), + }; + + InstEncoding[] vmConstraints = new InstEncoding[] + { + new(0x00000001, 0x00000001), + }; + + InstEncoding[] opvdOpvmConstraints = new InstEncoding[] + { + new(0x00001100, 0x00001100), + new(0x00000001, 0x00000101), + }; + + InstEncoding[] imm6Opimm6Imm6QvdQvmConstraints = new InstEncoding[] + { + new(0x00000000, 0x00380000), + new(0x00200000, 0x00300200), + new(0x00000000, 0x00200000), + new(0x00001040, 0x00001040), + new(0x00000041, 0x00000041), + }; + + InstEncoding[] condQvdEbConstraints = new InstEncoding[] + { + new(0xF0000000, 0xF0000000), + new(0x00210000, 0x00210000), + new(0x00400020, 0x00400020), + }; + + InstEncoding[] imm4QvdConstraints = new InstEncoding[] + { + new(0x00000000, 0x00070000), + new(0x00001040, 0x00001040), + }; + + InstEncoding[] qvdQvnQvmQimm4Constraints = new InstEncoding[] + { + new(0x00001040, 0x00001040), + new(0x00010040, 0x00010040), + new(0x00000041, 0x00000041), + new(0x00000800, 0x00000840), + }; + + InstEncoding[] qvdConstraints = new InstEncoding[] + { + new(0x00001040, 0x00001040), + }; + + InstEncoding[] vdVnConstraints = new InstEncoding[] + { + new(0x00001000, 0x00001000), + new(0x00010000, 0x00010000), + }; + + InstEncoding[] sizeConstraints2 = new InstEncoding[] + { + new(0x00000C00, 0x00000C00), + }; + + InstEncoding[] sizeIndexAlignIndexAlignConstraints = new InstEncoding[] + { + new(0x00000C00, 0x00000C00), + new(0x00000010, 0x00000030), + new(0x00000020, 0x00000030), + }; + + InstEncoding[] sizeSizeaConstraints = new InstEncoding[] + { + new(0x000000C0, 0x000000C0), + new(0x00000010, 0x000000D0), + }; + + InstEncoding[] alignConstraints = new InstEncoding[] + { + new(0x00000020, 0x00000020), + }; + + InstEncoding[] alignConstraints2 = new InstEncoding[] + { + new(0x00000030, 0x00000030), + }; + + InstEncoding[] sizeConstraints3 = new InstEncoding[] + { + new(0x000000C0, 0x000000C0), + }; + + InstEncoding[] alignSizeConstraints = new InstEncoding[] + { + new(0x00000030, 0x00000030), + new(0x000000C0, 0x000000C0), + }; + + InstEncoding[] sizeAConstraints = new InstEncoding[] + { + new(0x000000C0, 0x000000C0), + new(0x00000010, 0x00000010), + }; + + InstEncoding[] sizeAlignConstraints = new InstEncoding[] + { + new(0x000000C0, 0x000000C0), + new(0x00000020, 0x00000020), + }; + + InstEncoding[] sizeIndexAlignConstraints = new InstEncoding[] + { + new(0x00000C00, 0x00000C00), + new(0x00000030, 0x00000030), + }; + + InstEncoding[] sizeaConstraints = new InstEncoding[] + { + new(0x000000C0, 0x000000D0), + }; + + InstEncoding[] sizeSizeVdConstraints = new InstEncoding[] + { + new(0x00300000, 0x00300000), + new(0x00000000, 0x00300000), + new(0x00001000, 0x00001000), + }; + + InstEncoding[] sizeQvdQvnConstraints = new InstEncoding[] + { + new(0x00300000, 0x00300000), + new(0x01001000, 0x01001000), + new(0x01010000, 0x01010000), + }; + + InstEncoding[] imm3hImm3hImm3hImm3hImm3hVdConstraints = new InstEncoding[] + { + new(0x00000000, 0x00380000), + new(0x00180000, 0x00380000), + new(0x00280000, 0x00380000), + new(0x00300000, 0x00380000), + new(0x00380000, 0x00380000), + new(0x00001000, 0x00001000), + }; + + InstEncoding[] sizeVmConstraints = new InstEncoding[] + { + new(0x000C0000, 0x000C0000), + new(0x00000001, 0x00000001), + }; + + InstEncoding[] condOpc1opc2Constraints = new InstEncoding[] + { + new(0xF0000000, 0xF0000000), + new(0x00000040, 0x00400060), + }; + + InstEncoding[] condUopc1opc2Uopc1opc2Constraints = new InstEncoding[] + { + new(0xF0000000, 0xF0000000), + new(0x00800000, 0x00C00060), + new(0x00000040, 0x00400060), + }; + + InstEncoding[] sizeOpuOpsizeVdConstraints = new InstEncoding[] + { + new(0x00300000, 0x00300000), + new(0x01000200, 0x01000200), + new(0x00100200, 0x00300200), + new(0x00001000, 0x00001000), + }; + + InstEncoding[] sizeOpsizeOpsizeQvdQvnQvmConstraints = new InstEncoding[] + { + new(0x00300000, 0x00300000), + new(0x01100000, 0x01300000), + new(0x01200000, 0x01300000), + new(0x00001040, 0x00001040), + new(0x00010040, 0x00010040), + new(0x00000041, 0x00000041), + }; + + InstEncoding[] cmodeQvdConstraints = new InstEncoding[] + { + new(0x00000E00, 0x00000E00), + new(0x00001040, 0x00001040), + }; + + InstEncoding[] qConstraints = new InstEncoding[] + { + new(0x00000040, 0x00000040), + }; + + InstEncoding[] sizeQConstraints = new InstEncoding[] + { + new(0x00300000, 0x00300000), + new(0x00000040, 0x00000040), + }; + + InstEncoding[] sizeConstraints4 = new InstEncoding[] + { + new(0x00300000, 0x00300000), + }; + + InstEncoding[] qvdQvnQvmSizeSizeConstraints = new InstEncoding[] + { + new(0x00001040, 0x00001040), + new(0x00010040, 0x00010040), + new(0x00000041, 0x00000041), + new(0x00000000, 0x00300000), + new(0x00300000, 0x00300000), + }; + + InstEncoding[] sizeSizeQvdQvnConstraints = new InstEncoding[] + { + new(0x00300000, 0x00300000), + new(0x00000000, 0x00300000), + new(0x01001000, 0x01001000), + new(0x01010000, 0x01010000), + }; + + InstEncoding[] opSizeVmConstraints = new InstEncoding[] + { + new(0x00000000, 0x000000C0), + new(0x000C0000, 0x000C0000), + new(0x00000001, 0x00000001), + }; + + InstEncoding[] qvdQvmQvnConstraints = new InstEncoding[] + { + new(0x00001040, 0x00001040), + new(0x00000041, 0x00000041), + new(0x00010040, 0x00010040), + }; + + InstEncoding[] imm6UopVmConstraints = new InstEncoding[] + { + new(0x00000000, 0x00380000), + new(0x00000000, 0x01000100), + new(0x00000001, 0x00000001), + }; + + InstEncoding[] imm6lUopQvdQvmConstraints = new InstEncoding[] + { + new(0x00000000, 0x00380080), + new(0x00000000, 0x01000100), + new(0x00001040, 0x00001040), + new(0x00000041, 0x00000041), + }; + + InstEncoding[] qvdQvmSizeSizeConstraints = new InstEncoding[] + { + new(0x00001040, 0x00001040), + new(0x00000041, 0x00000041), + new(0x00000000, 0x000C0000), + new(0x000C0000, 0x000C0000), + }; + + InstEncoding[] sizeSizeSizeQvdQvmConstraints = new InstEncoding[] + { + new(0x00040000, 0x000C0000), + new(0x00080000, 0x000C0000), + new(0x000C0000, 0x000C0000), + new(0x00001040, 0x00001040), + new(0x00000041, 0x00000041), + }; + + InstEncoding[] sizeSizeQvdQvmConstraints = new InstEncoding[] + { + new(0x00080000, 0x000C0000), + new(0x000C0000, 0x000C0000), + new(0x00001040, 0x00001040), + new(0x00000041, 0x00000041), + }; + + InstEncoding[] imm6lQvdQvmConstraints = new InstEncoding[] + { + new(0x00000000, 0x00380080), + new(0x00001040, 0x00001040), + new(0x00000041, 0x00000041), + }; + + InstEncoding[] imm6VmConstraints = new InstEncoding[] + { + new(0x00000000, 0x00380000), + new(0x00000001, 0x00000001), + }; + + InstEncoding[] imm6VdImm6Imm6Imm6Constraints = new InstEncoding[] + { + new(0x00000000, 0x00380000), + new(0x00001000, 0x00001000), + new(0x00080000, 0x003F0000), + new(0x00100000, 0x003F0000), + new(0x00200000, 0x003F0000), + }; + + InstEncoding[] sizeVdConstraints2 = new InstEncoding[] + { + new(0x000C0000, 0x000C0000), + new(0x00001000, 0x00001000), + }; + + InstEncoding[] sizeQsizeQvdQvmConstraints = new InstEncoding[] + { + new(0x000C0000, 0x000C0000), + new(0x00080000, 0x000C0040), + new(0x00001040, 0x00001040), + new(0x00000041, 0x00000041), + }; + + List insts = new() + { + new(0x02A00000, 0x0FE00000, condConstraints, InstName.AdcI, T.AdcIA1, IsaVersion.v80, InstFlags.CondRd), + new(0x00A00000, 0x0FE00010, condConstraints, InstName.AdcR, T.AdcRA1, IsaVersion.v80, InstFlags.CondRd), + new(0x00A00010, 0x0FE00090, condConstraints, InstName.AdcRr, T.AdcRrA1, IsaVersion.v80, InstFlags.CondRd), + new(0x02800000, 0x0FE00000, condRnsRnConstraints, InstName.AddI, T.AddIA1, IsaVersion.v80, InstFlags.CondRd), + new(0x00800000, 0x0FE00010, condRnConstraints, InstName.AddR, T.AddRA1, IsaVersion.v80, InstFlags.CondRd), + new(0x00800010, 0x0FE00090, condConstraints, InstName.AddRr, T.AddRrA1, IsaVersion.v80, InstFlags.CondRd), + new(0x028D0000, 0x0FEF0000, condConstraints, InstName.AddSpI, T.AddSpIA1, IsaVersion.v80, InstFlags.CondRd), + new(0x008D0000, 0x0FEF0010, condConstraints, InstName.AddSpR, T.AddSpRA1, IsaVersion.v80, InstFlags.CondRd), + new(0x028F0000, 0x0FFF0000, condConstraints, InstName.Adr, T.AdrA1, IsaVersion.v80, InstFlags.CondRd), + new(0x024F0000, 0x0FFF0000, condConstraints, InstName.Adr, T.AdrA2, IsaVersion.v80, InstFlags.CondRd), + new(0xF3B00340, 0xFFBF0FD0, vdVmConstraints, InstName.Aesd, T.AesdA1, IsaVersion.v80, IsaFeature.FeatAes, InstFlags.None), + new(0xF3B00300, 0xFFBF0FD0, vdVmConstraints, InstName.Aese, T.AeseA1, IsaVersion.v80, IsaFeature.FeatAes, InstFlags.None), + new(0xF3B003C0, 0xFFBF0FD0, vdVmConstraints, InstName.Aesimc, T.AesimcA1, IsaVersion.v80, IsaFeature.FeatAes, InstFlags.None), + new(0xF3B00380, 0xFFBF0FD0, vdVmConstraints, InstName.Aesmc, T.AesmcA1, IsaVersion.v80, IsaFeature.FeatAes, InstFlags.None), + new(0x02000000, 0x0FE00000, condConstraints, InstName.AndI, T.AndIA1, IsaVersion.v80, InstFlags.CondRd), + new(0x00000000, 0x0FE00010, condConstraints, InstName.AndR, T.AndRA1, IsaVersion.v80, InstFlags.CondRd), + new(0x00000010, 0x0FE00090, condConstraints, InstName.AndRr, T.AndRrA1, IsaVersion.v80, InstFlags.CondRd), + new(0x0A000000, 0x0F000000, condConstraints, InstName.B, T.BA1, IsaVersion.v80, InstFlags.Cond), + new(0x07C0001F, 0x0FE0007F, condConstraints, InstName.Bfc, T.BfcA1, IsaVersion.v80, InstFlags.CondRd), + new(0x07C00010, 0x0FE00070, condRnConstraints2, InstName.Bfi, T.BfiA1, IsaVersion.v80, InstFlags.CondRd), + new(0x03C00000, 0x0FE00000, condConstraints, InstName.BicI, T.BicIA1, IsaVersion.v80, InstFlags.CondRd), + new(0x01C00000, 0x0FE00010, condConstraints, InstName.BicR, T.BicRA1, IsaVersion.v80, InstFlags.CondRd), + new(0x01C00010, 0x0FE00090, condConstraints, InstName.BicRr, T.BicRrA1, IsaVersion.v80, InstFlags.CondRd), + new(0x01200070, 0x0FF000F0, condConstraints, InstName.Bkpt, T.BkptA1, IsaVersion.v80, InstFlags.Cond), + new(0x012FFF30, 0x0FFFFFF0, condConstraints, InstName.BlxR, T.BlxRA1, IsaVersion.v80, InstFlags.Cond), + new(0x0B000000, 0x0F000000, condConstraints, InstName.BlI, T.BlIA1, IsaVersion.v80, InstFlags.Cond), + new(0xFA000000, 0xFE000000, InstName.BlI, T.BlIA2, IsaVersion.v80, InstFlags.None), + new(0x012FFF10, 0x0FFFFFF0, condConstraints, InstName.Bx, T.BxA1, IsaVersion.v80, InstFlags.Cond), + new(0x012FFF20, 0x0FFFFFF0, condConstraints, InstName.Bxj, T.BxjA1, IsaVersion.v80, InstFlags.Cond), + new(0x0320F016, 0x0FFFFFFF, condConstraints, InstName.Clrbhb, T.ClrbhbA1, IsaVersion.v89, IsaFeature.FeatClrbhb, InstFlags.Cond), + new(0xF57FF01F, 0xFFFFFFFF, InstName.Clrex, T.ClrexA1, IsaVersion.v80, InstFlags.None), + new(0x016F0F10, 0x0FFF0FF0, condConstraints, InstName.Clz, T.ClzA1, IsaVersion.v80, InstFlags.CondRd), + new(0x03700000, 0x0FF0F000, condConstraints, InstName.CmnI, T.CmnIA1, IsaVersion.v80, InstFlags.Cond), + new(0x01700000, 0x0FF0F010, condConstraints, InstName.CmnR, T.CmnRA1, IsaVersion.v80, InstFlags.Cond), + new(0x01700010, 0x0FF0F090, condConstraints, InstName.CmnRr, T.CmnRrA1, IsaVersion.v80, InstFlags.Cond), + new(0x03500000, 0x0FF0F000, condConstraints, InstName.CmpI, T.CmpIA1, IsaVersion.v80, InstFlags.Cond), + new(0x01500000, 0x0FF0F010, condConstraints, InstName.CmpR, T.CmpRA1, IsaVersion.v80, InstFlags.Cond), + new(0x01500010, 0x0FF0F090, condConstraints, InstName.CmpRr, T.CmpRrA1, IsaVersion.v80, InstFlags.Cond), + new(0xF1000000, 0xFFF1FE20, InstName.Cps, T.CpsA1, IsaVersion.v80, InstFlags.None), + new(0x01000040, 0x0F900FF0, condConstraints, InstName.Crc32, T.Crc32A1, IsaVersion.v80, IsaFeature.FeatCrc32, InstFlags.CondRd), + new(0x01000240, 0x0F900FF0, condConstraints, InstName.Crc32c, T.Crc32cA1, IsaVersion.v80, IsaFeature.FeatCrc32, InstFlags.CondRd), + new(0x0320F014, 0x0FFFFFFF, condConstraints, InstName.Csdb, T.CsdbA1, IsaVersion.v80, InstFlags.Cond), + new(0x0320F0F0, 0x0FFFFFF0, condConstraints, InstName.Dbg, T.DbgA1, IsaVersion.v80, InstFlags.Cond), + new(0xF57FF050, 0xFFFFFFF0, InstName.Dmb, T.DmbA1, IsaVersion.v80, InstFlags.None), + new(0xF57FF040, 0xFFFFFFF0, optionConstraints, InstName.Dsb, T.DsbA1, IsaVersion.v80, InstFlags.None), + new(0x02200000, 0x0FE00000, condConstraints, InstName.EorI, T.EorIA1, IsaVersion.v80, InstFlags.CondRd), + new(0x00200000, 0x0FE00010, condConstraints, InstName.EorR, T.EorRA1, IsaVersion.v80, InstFlags.CondRd), + new(0x00200010, 0x0FE00090, condConstraints, InstName.EorRr, T.EorRrA1, IsaVersion.v80, InstFlags.CondRd), + new(0x0160006E, 0x0FFFFFFF, condConstraints, InstName.Eret, T.EretA1, IsaVersion.v80, InstFlags.Cond), + new(0x0320F010, 0x0FFFFFFF, condConstraints, InstName.Esb, T.EsbA1, IsaVersion.v82, IsaFeature.FeatRas, InstFlags.Cond), + new(0x0C100B01, 0x0E100F01, condPuwPwPuwPuwConstraints, InstName.Fldmx, T.FldmxA1, IsaVersion.v80, InstFlags.CondWBack), + new(0x0C000B01, 0x0E100F01, condPuwPwPuwPuwConstraints, InstName.Fstmx, T.FstmxA1, IsaVersion.v80, InstFlags.CondWBack), + new(0x01000070, 0x0FF000F0, condConstraints, InstName.Hlt, T.HltA1, IsaVersion.v80, InstFlags.Cond), + new(0x01400070, 0x0FF000F0, condConstraints, InstName.Hvc, T.HvcA1, IsaVersion.v80, InstFlags.Cond), + new(0xF57FF060, 0xFFFFFFF0, InstName.Isb, T.IsbA1, IsaVersion.v80, InstFlags.None), + new(0x01900C9F, 0x0FF00FFF, condConstraints, InstName.Lda, T.LdaA1, IsaVersion.v80, InstFlags.CondRt), + new(0x01D00C9F, 0x0FF00FFF, condConstraints, InstName.Ldab, T.LdabA1, IsaVersion.v80, InstFlags.CondRt), + new(0x01900E9F, 0x0FF00FFF, condConstraints, InstName.Ldaex, T.LdaexA1, IsaVersion.v80, InstFlags.CondRt), + new(0x01D00E9F, 0x0FF00FFF, condConstraints, InstName.Ldaexb, T.LdaexbA1, IsaVersion.v80, InstFlags.CondRt), + new(0x01B00E9F, 0x0FF00FFF, condConstraints, InstName.Ldaexd, T.LdaexdA1, IsaVersion.v80, InstFlags.CondRt2), + new(0x01F00E9F, 0x0FF00FFF, condConstraints, InstName.Ldaexh, T.LdaexhA1, IsaVersion.v80, InstFlags.CondRt), + new(0x01F00C9F, 0x0FF00FFF, condConstraints, InstName.Ldah, T.LdahA1, IsaVersion.v80, InstFlags.CondRt), + new(0x0C105E00, 0x0E50FF00, condRnPuwConstraints, InstName.LdcI, T.LdcIA1, IsaVersion.v80, InstFlags.CondWBack), + new(0x0C1F5E00, 0x0E5FFF00, condPuwConstraints, InstName.LdcL, T.LdcLA1, IsaVersion.v80, InstFlags.CondWBack), + new(0x08900000, 0x0FD00000, condConstraints, InstName.Ldm, T.LdmA1, IsaVersion.v80, InstFlags.CondRlistWBack), + new(0x08100000, 0x0FD00000, condConstraints, InstName.Ldmda, T.LdmdaA1, IsaVersion.v80, InstFlags.CondRlistWBack), + new(0x09100000, 0x0FD00000, condConstraints, InstName.Ldmdb, T.LdmdbA1, IsaVersion.v80, InstFlags.CondRlistWBack), + new(0x09900000, 0x0FD00000, condConstraints, InstName.Ldmib, T.LdmibA1, IsaVersion.v80, InstFlags.CondRlistWBack), + new(0x08508000, 0x0E508000, condConstraints, InstName.LdmE, T.LdmEA1, IsaVersion.v80, InstFlags.CondRlistWBack), + new(0x08500000, 0x0E708000, condConstraints, InstName.LdmU, T.LdmUA1, IsaVersion.v80, InstFlags.CondRlist), + new(0x04700000, 0x0F700000, condConstraints, InstName.Ldrbt, T.LdrbtA1, IsaVersion.v80, InstFlags.CondRt), + new(0x06700000, 0x0F700010, condConstraints, InstName.Ldrbt, T.LdrbtA2, IsaVersion.v80, InstFlags.CondRt), + new(0x04500000, 0x0E500000, condRnPwConstraints, InstName.LdrbI, T.LdrbIA1, IsaVersion.v80, InstFlags.CondRtWBack), + new(0x045F0000, 0x0E5F0000, condPwConstraints, InstName.LdrbL, T.LdrbLA1, IsaVersion.v80, InstFlags.CondRtWBack), + new(0x06500000, 0x0E500010, condPwConstraints, InstName.LdrbR, T.LdrbRA1, IsaVersion.v80, InstFlags.CondRtWBack), + new(0x004000D0, 0x0E5000F0, condRnConstraints3, InstName.LdrdI, T.LdrdIA1, IsaVersion.v80, InstFlags.CondRt2WBack), + new(0x014F00D0, 0x0F7F00F0, condConstraints, InstName.LdrdL, T.LdrdLA1, IsaVersion.v80, InstFlags.CondRt2), + new(0x000000D0, 0x0E500FF0, condConstraints, InstName.LdrdR, T.LdrdRA1, IsaVersion.v80, InstFlags.CondRt2WBack), + new(0x01900F9F, 0x0FF00FFF, condConstraints, InstName.Ldrex, T.LdrexA1, IsaVersion.v80, InstFlags.CondRt), + new(0x01D00F9F, 0x0FF00FFF, condConstraints, InstName.Ldrexb, T.LdrexbA1, IsaVersion.v80, InstFlags.CondRt), + new(0x01B00F9F, 0x0FF00FFF, condConstraints, InstName.Ldrexd, T.LdrexdA1, IsaVersion.v80, InstFlags.CondRt2), + new(0x01F00F9F, 0x0FF00FFF, condConstraints, InstName.Ldrexh, T.LdrexhA1, IsaVersion.v80, InstFlags.CondRt), + new(0x007000B0, 0x0F7000F0, condConstraints, InstName.Ldrht, T.LdrhtA1, IsaVersion.v80, InstFlags.CondRt), + new(0x003000B0, 0x0F700FF0, condConstraints, InstName.Ldrht, T.LdrhtA2, IsaVersion.v80, InstFlags.CondRt), + new(0x005000B0, 0x0E5000F0, condRnPwConstraints, InstName.LdrhI, T.LdrhIA1, IsaVersion.v80, InstFlags.CondRtWBack), + new(0x005F00B0, 0x0E5F00F0, condPwConstraints, InstName.LdrhL, T.LdrhLA1, IsaVersion.v80, InstFlags.CondRtWBack), + new(0x001000B0, 0x0E500FF0, condPwConstraints, InstName.LdrhR, T.LdrhRA1, IsaVersion.v80, InstFlags.CondRtWBack), + new(0x007000D0, 0x0F7000F0, condConstraints, InstName.Ldrsbt, T.LdrsbtA1, IsaVersion.v80, InstFlags.CondRt), + new(0x003000D0, 0x0F700FF0, condConstraints, InstName.Ldrsbt, T.LdrsbtA2, IsaVersion.v80, InstFlags.CondRt), + new(0x005000D0, 0x0E5000F0, condRnPwConstraints, InstName.LdrsbI, T.LdrsbIA1, IsaVersion.v80, InstFlags.CondRtWBack), + new(0x005F00D0, 0x0E5F00F0, condPwConstraints, InstName.LdrsbL, T.LdrsbLA1, IsaVersion.v80, InstFlags.CondRtWBack), + new(0x001000D0, 0x0E500FF0, condPwConstraints, InstName.LdrsbR, T.LdrsbRA1, IsaVersion.v80, InstFlags.CondRtWBack), + new(0x007000F0, 0x0F7000F0, condConstraints, InstName.Ldrsht, T.LdrshtA1, IsaVersion.v80, InstFlags.CondRt), + new(0x003000F0, 0x0F700FF0, condConstraints, InstName.Ldrsht, T.LdrshtA2, IsaVersion.v80, InstFlags.CondRt), + new(0x005000F0, 0x0E5000F0, condRnPwConstraints, InstName.LdrshI, T.LdrshIA1, IsaVersion.v80, InstFlags.CondRtWBack), + new(0x005F00F0, 0x0E5F00F0, condPwConstraints, InstName.LdrshL, T.LdrshLA1, IsaVersion.v80, InstFlags.CondRtWBack), + new(0x001000F0, 0x0E500FF0, condPwConstraints, InstName.LdrshR, T.LdrshRA1, IsaVersion.v80, InstFlags.CondRtWBack), + new(0x04300000, 0x0F700000, condConstraints, InstName.Ldrt, T.LdrtA1, IsaVersion.v80, InstFlags.CondRt), + new(0x06300000, 0x0F700010, condConstraints, InstName.Ldrt, T.LdrtA2, IsaVersion.v80, InstFlags.CondRt), + new(0x04100000, 0x0E500000, condRnPwConstraints, InstName.LdrI, T.LdrIA1, IsaVersion.v80, InstFlags.CondRtWBack), + new(0x041F0000, 0x0E5F0000, condPwConstraints, InstName.LdrL, T.LdrLA1, IsaVersion.v80, InstFlags.CondRtWBack), + new(0x06100000, 0x0E500010, condPwConstraints, InstName.LdrR, T.LdrRA1, IsaVersion.v80, InstFlags.CondRtWBack), + new(0x0E000E10, 0x0F100E10, condConstraints, InstName.Mcr, T.McrA1, IsaVersion.v80, InstFlags.CondRt), + new(0x0C400E00, 0x0FF00E00, condConstraints, InstName.Mcrr, T.McrrA1, IsaVersion.v80, InstFlags.CondRt), + new(0x00200090, 0x0FE000F0, condConstraints, InstName.Mla, T.MlaA1, IsaVersion.v80, InstFlags.CondRd16), + new(0x00600090, 0x0FF000F0, condConstraints, InstName.Mls, T.MlsA1, IsaVersion.v80, InstFlags.CondRd16), + new(0x03400000, 0x0FF00000, condConstraints, InstName.Movt, T.MovtA1, IsaVersion.v80, InstFlags.CondRd), + new(0x03A00000, 0x0FEF0000, condConstraints, InstName.MovI, T.MovIA1, IsaVersion.v80, InstFlags.CondRd), + new(0x03000000, 0x0FF00000, condConstraints, InstName.MovI, T.MovIA2, IsaVersion.v80, InstFlags.CondRd), + new(0x01A00000, 0x0FEF0010, condConstraints, InstName.MovR, T.MovRA1, IsaVersion.v80, InstFlags.CondRd), + new(0x01A00010, 0x0FEF0090, condConstraints, InstName.MovRr, T.MovRrA1, IsaVersion.v80, InstFlags.CondRd), + new(0x0E100E10, 0x0F100E10, condConstraints, InstName.Mrc, T.MrcA1, IsaVersion.v80, InstFlags.CondRt), + new(0x0C500E00, 0x0FF00E00, condConstraints, InstName.Mrrc, T.MrrcA1, IsaVersion.v80, InstFlags.CondRt), + new(0x010F0000, 0x0FBF0FFF, condConstraints, InstName.Mrs, T.MrsA1, IsaVersion.v80, InstFlags.CondRd), + new(0x01000200, 0x0FB00EFF, condConstraints, InstName.MrsBr, T.MrsBrA1, IsaVersion.v80, InstFlags.CondRd), + new(0x0120F200, 0x0FB0FEF0, condConstraints, InstName.MsrBr, T.MsrBrA1, IsaVersion.v80, InstFlags.Cond), + new(0x0320F000, 0x0FB0F000, condMaskrConstraints, InstName.MsrI, T.MsrIA1, IsaVersion.v80, InstFlags.Cond), + new(0x0120F000, 0x0FB0FFF0, condConstraints, InstName.MsrR, T.MsrRA1, IsaVersion.v80, InstFlags.Cond), + new(0x00000090, 0x0FE0F0F0, condConstraints, InstName.Mul, T.MulA1, IsaVersion.v80, InstFlags.CondRd16), + new(0x03E00000, 0x0FEF0000, condConstraints, InstName.MvnI, T.MvnIA1, IsaVersion.v80, InstFlags.CondRd), + new(0x01E00000, 0x0FEF0010, condConstraints, InstName.MvnR, T.MvnRA1, IsaVersion.v80, InstFlags.CondRd), + new(0x01E00010, 0x0FEF0090, condConstraints, InstName.MvnRr, T.MvnRrA1, IsaVersion.v80, InstFlags.CondRd), + new(0x0320F000, 0x0FFFFFFF, condConstraints, InstName.Nop, T.NopA1, IsaVersion.v80, InstFlags.Cond), + new(0x03800000, 0x0FE00000, condConstraints, InstName.OrrI, T.OrrIA1, IsaVersion.v80, InstFlags.CondRd), + new(0x01800000, 0x0FE00010, condConstraints, InstName.OrrR, T.OrrRA1, IsaVersion.v80, InstFlags.CondRd), + new(0x01800010, 0x0FE00090, condConstraints, InstName.OrrRr, T.OrrRrA1, IsaVersion.v80, InstFlags.CondRd), + new(0x06800010, 0x0FF00030, condConstraints, InstName.Pkh, T.PkhA1, IsaVersion.v80, InstFlags.CondRd), + new(0xF510F000, 0xFF30F000, rnConstraints, InstName.PldI, T.PldIA1, IsaVersion.v80, InstFlags.None), + new(0xF55FF000, 0xFF7FF000, InstName.PldL, T.PldLA1, IsaVersion.v80, InstFlags.None), + new(0xF710F000, 0xFF30F010, InstName.PldR, T.PldRA1, IsaVersion.v80, InstFlags.None), + new(0xF450F000, 0xFF70F000, InstName.PliI, T.PliIA1, IsaVersion.v80, InstFlags.None), + new(0xF650F000, 0xFF70F010, InstName.PliR, T.PliRA1, IsaVersion.v80, InstFlags.None), + new(0xF57FF044, 0xFFFFFFFF, InstName.Pssbb, T.PssbbA1, IsaVersion.v80, InstFlags.None), + new(0x01000050, 0x0FF00FF0, condConstraints, InstName.Qadd, T.QaddA1, IsaVersion.v80, InstFlags.CondRd), + new(0x06200F10, 0x0FF00FF0, condConstraints, InstName.Qadd16, T.Qadd16A1, IsaVersion.v80, InstFlags.CondRd), + new(0x06200F90, 0x0FF00FF0, condConstraints, InstName.Qadd8, T.Qadd8A1, IsaVersion.v80, InstFlags.CondRd), + new(0x06200F30, 0x0FF00FF0, condConstraints, InstName.Qasx, T.QasxA1, IsaVersion.v80, InstFlags.CondRd), + new(0x01400050, 0x0FF00FF0, condConstraints, InstName.Qdadd, T.QdaddA1, IsaVersion.v80, InstFlags.CondRd), + new(0x01600050, 0x0FF00FF0, condConstraints, InstName.Qdsub, T.QdsubA1, IsaVersion.v80, InstFlags.CondRd), + new(0x06200F50, 0x0FF00FF0, condConstraints, InstName.Qsax, T.QsaxA1, IsaVersion.v80, InstFlags.CondRd), + new(0x01200050, 0x0FF00FF0, condConstraints, InstName.Qsub, T.QsubA1, IsaVersion.v80, InstFlags.CondRd), + new(0x06200F70, 0x0FF00FF0, condConstraints, InstName.Qsub16, T.Qsub16A1, IsaVersion.v80, InstFlags.CondRd), + new(0x06200FF0, 0x0FF00FF0, condConstraints, InstName.Qsub8, T.Qsub8A1, IsaVersion.v80, InstFlags.CondRd), + new(0x06FF0F30, 0x0FFF0FF0, condConstraints, InstName.Rbit, T.RbitA1, IsaVersion.v80, InstFlags.CondRd), + new(0x06BF0F30, 0x0FFF0FF0, condConstraints, InstName.Rev, T.RevA1, IsaVersion.v80, InstFlags.CondRd), + new(0x06BF0FB0, 0x0FFF0FF0, condConstraints, InstName.Rev16, T.Rev16A1, IsaVersion.v80, InstFlags.CondRd), + new(0x06FF0FB0, 0x0FFF0FF0, condConstraints, InstName.Revsh, T.RevshA1, IsaVersion.v80, InstFlags.CondRd), + new(0xF8100A00, 0xFE50FFFF, InstName.Rfe, T.RfeA1, IsaVersion.v80, InstFlags.WBack), + new(0x02600000, 0x0FE00000, condConstraints, InstName.RsbI, T.RsbIA1, IsaVersion.v80, InstFlags.CondRd), + new(0x00600000, 0x0FE00010, condConstraints, InstName.RsbR, T.RsbRA1, IsaVersion.v80, InstFlags.CondRd), + new(0x00600010, 0x0FE00090, condConstraints, InstName.RsbRr, T.RsbRrA1, IsaVersion.v80, InstFlags.CondRd), + new(0x02E00000, 0x0FE00000, condConstraints, InstName.RscI, T.RscIA1, IsaVersion.v80, InstFlags.CondRd), + new(0x00E00000, 0x0FE00010, condConstraints, InstName.RscR, T.RscRA1, IsaVersion.v80, InstFlags.CondRd), + new(0x00E00010, 0x0FE00090, condConstraints, InstName.RscRr, T.RscRrA1, IsaVersion.v80, InstFlags.CondRd), + new(0x06100F10, 0x0FF00FF0, condConstraints, InstName.Sadd16, T.Sadd16A1, IsaVersion.v80, InstFlags.CondRd), + new(0x06100F90, 0x0FF00FF0, condConstraints, InstName.Sadd8, T.Sadd8A1, IsaVersion.v80, InstFlags.CondRd), + new(0x06100F30, 0x0FF00FF0, condConstraints, InstName.Sasx, T.SasxA1, IsaVersion.v80, InstFlags.CondRd), + new(0xF57FF070, 0xFFFFFFFF, InstName.Sb, T.SbA1, IsaVersion.v85, IsaFeature.FeatSb, InstFlags.None), + new(0x02C00000, 0x0FE00000, condConstraints, InstName.SbcI, T.SbcIA1, IsaVersion.v80, InstFlags.CondRd), + new(0x00C00000, 0x0FE00010, condConstraints, InstName.SbcR, T.SbcRA1, IsaVersion.v80, InstFlags.CondRd), + new(0x00C00010, 0x0FE00090, condConstraints, InstName.SbcRr, T.SbcRrA1, IsaVersion.v80, InstFlags.CondRd), + new(0x07A00050, 0x0FE00070, condConstraints, InstName.Sbfx, T.SbfxA1, IsaVersion.v80, InstFlags.CondRd), + new(0x0710F010, 0x0FF0F0F0, condConstraints, InstName.Sdiv, T.SdivA1, IsaVersion.v80, InstFlags.CondRd16), + new(0x06800FB0, 0x0FF00FF0, condConstraints, InstName.Sel, T.SelA1, IsaVersion.v80, InstFlags.CondRd), + new(0xF1010000, 0xFFFFFDFF, InstName.Setend, T.SetendA1, IsaVersion.v80, InstFlags.None), + new(0xF1100000, 0xFFFFFDFF, InstName.Setpan, T.SetpanA1, IsaVersion.v81, IsaFeature.FeatPan, InstFlags.None), + new(0x0320F004, 0x0FFFFFFF, condConstraints, InstName.Sev, T.SevA1, IsaVersion.v80, InstFlags.Cond), + new(0x0320F005, 0x0FFFFFFF, condConstraints, InstName.Sevl, T.SevlA1, IsaVersion.v80, InstFlags.Cond), + new(0xF2000C40, 0xFFB00F50, vdVnVmConstraints, InstName.Sha1c, T.Sha1cA1, IsaVersion.v80, IsaFeature.FeatSha1, InstFlags.None), + new(0xF3B902C0, 0xFFBF0FD0, vdVmConstraints, InstName.Sha1h, T.Sha1hA1, IsaVersion.v80, IsaFeature.FeatSha1, InstFlags.None), + new(0xF2200C40, 0xFFB00F50, vdVnVmConstraints, InstName.Sha1m, T.Sha1mA1, IsaVersion.v80, IsaFeature.FeatSha1, InstFlags.None), + new(0xF2100C40, 0xFFB00F50, vdVnVmConstraints, InstName.Sha1p, T.Sha1pA1, IsaVersion.v80, IsaFeature.FeatSha1, InstFlags.None), + new(0xF2300C40, 0xFFB00F50, vdVnVmConstraints, InstName.Sha1su0, T.Sha1su0A1, IsaVersion.v80, IsaFeature.FeatSha1, InstFlags.None), + new(0xF3BA0380, 0xFFBF0FD0, vdVmConstraints, InstName.Sha1su1, T.Sha1su1A1, IsaVersion.v80, IsaFeature.FeatSha1, InstFlags.None), + new(0xF3000C40, 0xFFB00F50, vdVnVmConstraints, InstName.Sha256h, T.Sha256hA1, IsaVersion.v80, IsaFeature.FeatSha256, InstFlags.None), + new(0xF3100C40, 0xFFB00F50, vdVnVmConstraints, InstName.Sha256h2, T.Sha256h2A1, IsaVersion.v80, IsaFeature.FeatSha256, InstFlags.None), + new(0xF3BA03C0, 0xFFBF0FD0, vdVmConstraints, InstName.Sha256su0, T.Sha256su0A1, IsaVersion.v80, IsaFeature.FeatSha256, InstFlags.None), + new(0xF3200C40, 0xFFB00F50, vdVnVmConstraints, InstName.Sha256su1, T.Sha256su1A1, IsaVersion.v80, IsaFeature.FeatSha256, InstFlags.None), + new(0x06300F10, 0x0FF00FF0, condConstraints, InstName.Shadd16, T.Shadd16A1, IsaVersion.v80, InstFlags.CondRd), + new(0x06300F90, 0x0FF00FF0, condConstraints, InstName.Shadd8, T.Shadd8A1, IsaVersion.v80, InstFlags.CondRd), + new(0x06300F30, 0x0FF00FF0, condConstraints, InstName.Shasx, T.ShasxA1, IsaVersion.v80, InstFlags.CondRd), + new(0x06300F50, 0x0FF00FF0, condConstraints, InstName.Shsax, T.ShsaxA1, IsaVersion.v80, InstFlags.CondRd), + new(0x06300F70, 0x0FF00FF0, condConstraints, InstName.Shsub16, T.Shsub16A1, IsaVersion.v80, InstFlags.CondRd), + new(0x06300FF0, 0x0FF00FF0, condConstraints, InstName.Shsub8, T.Shsub8A1, IsaVersion.v80, InstFlags.CondRd), + new(0x01600070, 0x0FFFFFF0, condConstraints, InstName.Smc, T.SmcA1, IsaVersion.v80, InstFlags.Cond), + new(0x01000080, 0x0FF00090, condConstraints, InstName.Smlabb, T.SmlabbA1, IsaVersion.v80, InstFlags.CondRd16), + new(0x07000010, 0x0FF000D0, condRaConstraints, InstName.Smlad, T.SmladA1, IsaVersion.v80, InstFlags.CondRd16), + new(0x00E00090, 0x0FE000F0, condConstraints, InstName.Smlal, T.SmlalA1, IsaVersion.v80, InstFlags.CondRdLoHi), + new(0x01400080, 0x0FF00090, condConstraints, InstName.Smlalbb, T.SmlalbbA1, IsaVersion.v80, InstFlags.CondRdLoHi), + new(0x07400010, 0x0FF000D0, condConstraints, InstName.Smlald, T.SmlaldA1, IsaVersion.v80, InstFlags.CondRdLoHi), + new(0x01200080, 0x0FF000B0, condConstraints, InstName.Smlawb, T.SmlawbA1, IsaVersion.v80, InstFlags.CondRd16), + new(0x07000050, 0x0FF000D0, condRaConstraints, InstName.Smlsd, T.SmlsdA1, IsaVersion.v80, InstFlags.CondRd16), + new(0x07400050, 0x0FF000D0, condConstraints, InstName.Smlsld, T.SmlsldA1, IsaVersion.v80, InstFlags.CondRdLoHi), + new(0x07500010, 0x0FF000D0, condRaConstraints, InstName.Smmla, T.SmmlaA1, IsaVersion.v80, InstFlags.CondRd16), + new(0x075000D0, 0x0FF000D0, condConstraints, InstName.Smmls, T.SmmlsA1, IsaVersion.v80, InstFlags.CondRd16), + new(0x0750F010, 0x0FF0F0D0, condConstraints, InstName.Smmul, T.SmmulA1, IsaVersion.v80, InstFlags.CondRd16), + new(0x0700F010, 0x0FF0F0D0, condConstraints, InstName.Smuad, T.SmuadA1, IsaVersion.v80, InstFlags.CondRd16), + new(0x01600080, 0x0FF0F090, condConstraints, InstName.Smulbb, T.SmulbbA1, IsaVersion.v80, InstFlags.CondRd16), + new(0x00C00090, 0x0FE000F0, condConstraints, InstName.Smull, T.SmullA1, IsaVersion.v80, InstFlags.CondRdLoHi), + new(0x012000A0, 0x0FF0F0B0, condConstraints, InstName.Smulwb, T.SmulwbA1, IsaVersion.v80, InstFlags.CondRd16), + new(0x0700F050, 0x0FF0F0D0, condConstraints, InstName.Smusd, T.SmusdA1, IsaVersion.v80, InstFlags.CondRd16), + new(0xF84D0500, 0xFE5FFFE0, InstName.Srs, T.SrsA1, IsaVersion.v80, InstFlags.WBack), + new(0x06A00010, 0x0FE00030, condConstraints, InstName.Ssat, T.SsatA1, IsaVersion.v80, InstFlags.CondRd), + new(0x06A00F30, 0x0FF00FF0, condConstraints, InstName.Ssat16, T.Ssat16A1, IsaVersion.v80, InstFlags.CondRd), + new(0x06100F50, 0x0FF00FF0, condConstraints, InstName.Ssax, T.SsaxA1, IsaVersion.v80, InstFlags.CondRd), + new(0xF57FF040, 0xFFFFFFFF, InstName.Ssbb, T.SsbbA1, IsaVersion.v80, InstFlags.None), + new(0x06100F70, 0x0FF00FF0, condConstraints, InstName.Ssub16, T.Ssub16A1, IsaVersion.v80, InstFlags.CondRd), + new(0x06100FF0, 0x0FF00FF0, condConstraints, InstName.Ssub8, T.Ssub8A1, IsaVersion.v80, InstFlags.CondRd), + new(0x0C005E00, 0x0E50FF00, condPuwConstraints, InstName.Stc, T.StcA1, IsaVersion.v80, InstFlags.CondWBack), + new(0x0180FC90, 0x0FF0FFF0, condConstraints, InstName.Stl, T.StlA1, IsaVersion.v80, InstFlags.CondRtRead), + new(0x01C0FC90, 0x0FF0FFF0, condConstraints, InstName.Stlb, T.StlbA1, IsaVersion.v80, InstFlags.CondRtRead), + new(0x01800E90, 0x0FF00FF0, condConstraints, InstName.Stlex, T.StlexA1, IsaVersion.v80, InstFlags.CondRdRtRead), + new(0x01C00E90, 0x0FF00FF0, condConstraints, InstName.Stlexb, T.StlexbA1, IsaVersion.v80, InstFlags.CondRdRtRead), + new(0x01A00E90, 0x0FF00FF0, condConstraints, InstName.Stlexd, T.StlexdA1, IsaVersion.v80, InstFlags.CondRdRt2Read), + new(0x01E00E90, 0x0FF00FF0, condConstraints, InstName.Stlexh, T.StlexhA1, IsaVersion.v80, InstFlags.CondRdRtRead), + new(0x01E0FC90, 0x0FF0FFF0, condConstraints, InstName.Stlh, T.StlhA1, IsaVersion.v80, InstFlags.CondRtRead), + new(0x08800000, 0x0FD00000, condConstraints, InstName.Stm, T.StmA1, IsaVersion.v80, InstFlags.CondRlistReadWBack), + new(0x08000000, 0x0FD00000, condConstraints, InstName.Stmda, T.StmdaA1, IsaVersion.v80, InstFlags.CondRlistReadWBack), + new(0x09000000, 0x0FD00000, condConstraints, InstName.Stmdb, T.StmdbA1, IsaVersion.v80, InstFlags.CondRlistReadWBack), + new(0x09800000, 0x0FD00000, condConstraints, InstName.Stmib, T.StmibA1, IsaVersion.v80, InstFlags.CondRlistReadWBack), + new(0x08400000, 0x0E700000, condConstraints, InstName.StmU, T.StmUA1, IsaVersion.v80, InstFlags.CondRlistRead), + new(0x04600000, 0x0F700000, condConstraints, InstName.Strbt, T.StrbtA1, IsaVersion.v80, InstFlags.CondRtRead), + new(0x06600000, 0x0F700010, condConstraints, InstName.Strbt, T.StrbtA2, IsaVersion.v80, InstFlags.CondRtRead), + new(0x04400000, 0x0E500000, condPwConstraints, InstName.StrbI, T.StrbIA1, IsaVersion.v80, InstFlags.CondRtReadWBack), + new(0x06400000, 0x0E500010, condPwConstraints, InstName.StrbR, T.StrbRA1, IsaVersion.v80, InstFlags.CondRtReadWBack), + new(0x004000F0, 0x0E5000F0, condConstraints, InstName.StrdI, T.StrdIA1, IsaVersion.v80, InstFlags.CondRt2ReadWBack), + new(0x000000F0, 0x0E500FF0, condConstraints, InstName.StrdR, T.StrdRA1, IsaVersion.v80, InstFlags.CondRt2ReadWBack), + new(0x01800F90, 0x0FF00FF0, condConstraints, InstName.Strex, T.StrexA1, IsaVersion.v80, InstFlags.CondRdRtRead), + new(0x01C00F90, 0x0FF00FF0, condConstraints, InstName.Strexb, T.StrexbA1, IsaVersion.v80, InstFlags.CondRdRtRead), + new(0x01A00F90, 0x0FF00FF0, condConstraints, InstName.Strexd, T.StrexdA1, IsaVersion.v80, InstFlags.CondRdRt2Read), + new(0x01E00F90, 0x0FF00FF0, condConstraints, InstName.Strexh, T.StrexhA1, IsaVersion.v80, InstFlags.CondRdRtRead), + new(0x006000B0, 0x0F7000F0, condConstraints, InstName.Strht, T.StrhtA1, IsaVersion.v80, InstFlags.CondRtRead), + new(0x002000B0, 0x0F700FF0, condConstraints, InstName.Strht, T.StrhtA2, IsaVersion.v80, InstFlags.CondRtRead), + new(0x004000B0, 0x0E5000F0, condPwConstraints, InstName.StrhI, T.StrhIA1, IsaVersion.v80, InstFlags.CondRtReadWBack), + new(0x000000B0, 0x0E500FF0, condPwConstraints, InstName.StrhR, T.StrhRA1, IsaVersion.v80, InstFlags.CondRtReadWBack), + new(0x04200000, 0x0F700000, condConstraints, InstName.Strt, T.StrtA1, IsaVersion.v80, InstFlags.CondRtRead), + new(0x06200000, 0x0F700010, condConstraints, InstName.Strt, T.StrtA2, IsaVersion.v80, InstFlags.CondRtRead), + new(0x04000000, 0x0E500000, condPwConstraints, InstName.StrI, T.StrIA1, IsaVersion.v80, InstFlags.CondRtReadWBack), + new(0x06000000, 0x0E500010, condPwConstraints, InstName.StrR, T.StrRA1, IsaVersion.v80, InstFlags.CondRtReadWBack), + new(0x02400000, 0x0FE00000, condRnsRnConstraints, InstName.SubI, T.SubIA1, IsaVersion.v80, InstFlags.CondRd), + new(0x00400000, 0x0FE00010, condRnConstraints, InstName.SubR, T.SubRA1, IsaVersion.v80, InstFlags.CondRd), + new(0x00400010, 0x0FE00090, condConstraints, InstName.SubRr, T.SubRrA1, IsaVersion.v80, InstFlags.CondRd), + new(0x024D0000, 0x0FEF0000, condConstraints, InstName.SubSpI, T.SubSpIA1, IsaVersion.v80, InstFlags.CondRd), + new(0x004D0000, 0x0FEF0010, condConstraints, InstName.SubSpR, T.SubSpRA1, IsaVersion.v80, InstFlags.CondRd), + new(0x0F000000, 0x0F000000, condConstraints, InstName.Svc, T.SvcA1, IsaVersion.v80, InstFlags.Cond), + new(0x06A00070, 0x0FF003F0, condRnConstraints3, InstName.Sxtab, T.SxtabA1, IsaVersion.v80, InstFlags.CondRd), + new(0x06800070, 0x0FF003F0, condRnConstraints3, InstName.Sxtab16, T.Sxtab16A1, IsaVersion.v80, InstFlags.CondRd), + new(0x06B00070, 0x0FF003F0, condRnConstraints3, InstName.Sxtah, T.SxtahA1, IsaVersion.v80, InstFlags.CondRd), + new(0x06AF0070, 0x0FFF03F0, condConstraints, InstName.Sxtb, T.SxtbA1, IsaVersion.v80, InstFlags.CondRd), + new(0x068F0070, 0x0FFF03F0, condConstraints, InstName.Sxtb16, T.Sxtb16A1, IsaVersion.v80, InstFlags.CondRd), + new(0x06BF0070, 0x0FFF03F0, condConstraints, InstName.Sxth, T.SxthA1, IsaVersion.v80, InstFlags.CondRd), + new(0x03300000, 0x0FF0F000, condConstraints, InstName.TeqI, T.TeqIA1, IsaVersion.v80, InstFlags.Cond), + new(0x01300000, 0x0FF0F010, condConstraints, InstName.TeqR, T.TeqRA1, IsaVersion.v80, InstFlags.Cond), + new(0x01300010, 0x0FF0F090, condConstraints, InstName.TeqRr, T.TeqRrA1, IsaVersion.v80, InstFlags.Cond), + new(0x0320F012, 0x0FFFFFFF, condConstraints, InstName.Tsb, T.TsbA1, IsaVersion.v84, IsaFeature.FeatTrf, InstFlags.Cond), + new(0x03100000, 0x0FF0F000, condConstraints, InstName.TstI, T.TstIA1, IsaVersion.v80, InstFlags.Cond), + new(0x01100000, 0x0FF0F010, condConstraints, InstName.TstR, T.TstRA1, IsaVersion.v80, InstFlags.Cond), + new(0x01100010, 0x0FF0F090, condConstraints, InstName.TstRr, T.TstRrA1, IsaVersion.v80, InstFlags.Cond), + new(0x06500F10, 0x0FF00FF0, condConstraints, InstName.Uadd16, T.Uadd16A1, IsaVersion.v80, InstFlags.CondRd), + new(0x06500F90, 0x0FF00FF0, condConstraints, InstName.Uadd8, T.Uadd8A1, IsaVersion.v80, InstFlags.CondRd), + new(0x06500F30, 0x0FF00FF0, condConstraints, InstName.Uasx, T.UasxA1, IsaVersion.v80, InstFlags.CondRd), + new(0x07E00050, 0x0FE00070, condConstraints, InstName.Ubfx, T.UbfxA1, IsaVersion.v80, InstFlags.CondRd), + new(0xE7F000F0, 0xFFF000F0, InstName.Udf, T.UdfA1, IsaVersion.v80, InstFlags.None), + new(0x0730F010, 0x0FF0F0F0, condConstraints, InstName.Udiv, T.UdivA1, IsaVersion.v80, InstFlags.CondRd16), + new(0x06700F10, 0x0FF00FF0, condConstraints, InstName.Uhadd16, T.Uhadd16A1, IsaVersion.v80, InstFlags.CondRd), + new(0x06700F90, 0x0FF00FF0, condConstraints, InstName.Uhadd8, T.Uhadd8A1, IsaVersion.v80, InstFlags.CondRd), + new(0x06700F30, 0x0FF00FF0, condConstraints, InstName.Uhasx, T.UhasxA1, IsaVersion.v80, InstFlags.CondRd), + new(0x06700F50, 0x0FF00FF0, condConstraints, InstName.Uhsax, T.UhsaxA1, IsaVersion.v80, InstFlags.CondRd), + new(0x06700F70, 0x0FF00FF0, condConstraints, InstName.Uhsub16, T.Uhsub16A1, IsaVersion.v80, InstFlags.CondRd), + new(0x06700FF0, 0x0FF00FF0, condConstraints, InstName.Uhsub8, T.Uhsub8A1, IsaVersion.v80, InstFlags.CondRd), + new(0x00400090, 0x0FF000F0, condConstraints, InstName.Umaal, T.UmaalA1, IsaVersion.v80, InstFlags.CondRdLoHi), + new(0x00A00090, 0x0FE000F0, condConstraints, InstName.Umlal, T.UmlalA1, IsaVersion.v80, InstFlags.CondRdLoHi), + new(0x00800090, 0x0FE000F0, condConstraints, InstName.Umull, T.UmullA1, IsaVersion.v80, InstFlags.CondRdLoHi), + new(0x06600F10, 0x0FF00FF0, condConstraints, InstName.Uqadd16, T.Uqadd16A1, IsaVersion.v80, InstFlags.CondRd), + new(0x06600F90, 0x0FF00FF0, condConstraints, InstName.Uqadd8, T.Uqadd8A1, IsaVersion.v80, InstFlags.CondRd), + new(0x06600F30, 0x0FF00FF0, condConstraints, InstName.Uqasx, T.UqasxA1, IsaVersion.v80, InstFlags.CondRd), + new(0x06600F50, 0x0FF00FF0, condConstraints, InstName.Uqsax, T.UqsaxA1, IsaVersion.v80, InstFlags.CondRd), + new(0x06600F70, 0x0FF00FF0, condConstraints, InstName.Uqsub16, T.Uqsub16A1, IsaVersion.v80, InstFlags.CondRd), + new(0x06600FF0, 0x0FF00FF0, condConstraints, InstName.Uqsub8, T.Uqsub8A1, IsaVersion.v80, InstFlags.CondRd), + new(0x0780F010, 0x0FF0F0F0, condConstraints, InstName.Usad8, T.Usad8A1, IsaVersion.v80, InstFlags.CondRd16), + new(0x07800010, 0x0FF000F0, condRaConstraints, InstName.Usada8, T.Usada8A1, IsaVersion.v80, InstFlags.CondRd16), + new(0x06E00010, 0x0FE00030, condConstraints, InstName.Usat, T.UsatA1, IsaVersion.v80, InstFlags.CondRd), + new(0x06E00F30, 0x0FF00FF0, condConstraints, InstName.Usat16, T.Usat16A1, IsaVersion.v80, InstFlags.CondRd), + new(0x06500F50, 0x0FF00FF0, condConstraints, InstName.Usax, T.UsaxA1, IsaVersion.v80, InstFlags.CondRd), + new(0x06500F70, 0x0FF00FF0, condConstraints, InstName.Usub16, T.Usub16A1, IsaVersion.v80, InstFlags.CondRd), + new(0x06500FF0, 0x0FF00FF0, condConstraints, InstName.Usub8, T.Usub8A1, IsaVersion.v80, InstFlags.CondRd), + new(0x06E00070, 0x0FF003F0, condRnConstraints3, InstName.Uxtab, T.UxtabA1, IsaVersion.v80, InstFlags.CondRd), + new(0x06C00070, 0x0FF003F0, condRnConstraints3, InstName.Uxtab16, T.Uxtab16A1, IsaVersion.v80, InstFlags.CondRd), + new(0x06F00070, 0x0FF003F0, condRnConstraints3, InstName.Uxtah, T.UxtahA1, IsaVersion.v80, InstFlags.CondRd), + new(0x06EF0070, 0x0FFF03F0, condConstraints, InstName.Uxtb, T.UxtbA1, IsaVersion.v80, InstFlags.CondRd), + new(0x06CF0070, 0x0FFF03F0, condConstraints, InstName.Uxtb16, T.Uxtb16A1, IsaVersion.v80, InstFlags.CondRd), + new(0x06FF0070, 0x0FFF03F0, condConstraints, InstName.Uxth, T.UxthA1, IsaVersion.v80, InstFlags.CondRd), + new(0xF2000710, 0xFE800F10, sizeQvdQvnQvmConstraints, InstName.Vaba, T.VabaA1, IsaVersion.v80, InstFlags.None), + new(0xF2800500, 0xFE800F50, sizeVdConstraints, InstName.Vabal, T.VabalA1, IsaVersion.v80, InstFlags.None), + new(0xF2800700, 0xFE800F50, sizeVdConstraints, InstName.VabdlI, T.VabdlIA1, IsaVersion.v80, InstFlags.None), + new(0xF3200D00, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VabdF, T.VabdFA1, IsaVersion.v80, InstFlags.None), + new(0xF3300D00, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VabdF, T.VabdFA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xF2000700, 0xFE800F10, sizeQvdQvnQvmConstraints, InstName.VabdI, T.VabdIA1, IsaVersion.v80, InstFlags.None), + new(0xF3B10300, 0xFFB30F90, sizeQvdQvmConstraints, InstName.Vabs, T.VabsA1, IsaVersion.v80, InstFlags.None), + new(0xF3B90700, 0xFFBB0F90, sizeQvdQvmConstraints, InstName.Vabs, T.VabsA1, IsaVersion.v80, InstFlags.None), + new(0xF3B50700, 0xFFBF0F90, sizeQvdQvmConstraints, InstName.Vabs, T.VabsA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0x0EB00AC0, 0x0FBF0ED0, condConstraints, InstName.Vabs, T.VabsA2, IsaVersion.v80, InstFlags.Cond), + new(0x0EB009C0, 0x0FBF0FD0, condConstraints, InstName.Vabs, T.VabsA2, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.Cond), + new(0xF3000E10, 0xFFB00F10, qvdQvnQvmConstraints, InstName.Vacge, T.VacgeA1, IsaVersion.v80, InstFlags.None), + new(0xF3100E10, 0xFFB00F10, qvdQvnQvmConstraints, InstName.Vacge, T.VacgeA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xF3200E10, 0xFFB00F10, qvdQvnQvmConstraints, InstName.Vacgt, T.VacgtA1, IsaVersion.v80, InstFlags.None), + new(0xF3300E10, 0xFFB00F10, qvdQvnQvmConstraints, InstName.Vacgt, T.VacgtA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xF2800400, 0xFF800F50, sizeVnVmConstraints, InstName.Vaddhn, T.VaddhnA1, IsaVersion.v80, InstFlags.None), + new(0xF2800000, 0xFE800F50, sizeVdOpvnConstraints, InstName.Vaddl, T.VaddlA1, IsaVersion.v80, InstFlags.None), + new(0xF2800100, 0xFE800F50, sizeVdOpvnConstraints, InstName.Vaddw, T.VaddwA1, IsaVersion.v80, InstFlags.None), + new(0xF2000D00, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VaddF, T.VaddFA1, IsaVersion.v80, InstFlags.None), + new(0xF2100D00, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VaddF, T.VaddFA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0x0E300A00, 0x0FB00E50, condConstraints, InstName.VaddF, T.VaddFA2, IsaVersion.v80, InstFlags.Cond), + new(0x0E300900, 0x0FB00F50, condConstraints, InstName.VaddF, T.VaddFA2, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.Cond), + new(0xF2000800, 0xFF800F10, qvdQvnQvmConstraints, InstName.VaddI, T.VaddIA1, IsaVersion.v80, InstFlags.None), + new(0xF2000110, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VandR, T.VandRA1, IsaVersion.v80, InstFlags.None), + new(0xF2800130, 0xFEB809B0, cmodeCmodeQvdConstraints, InstName.VbicI, T.VbicIA1, IsaVersion.v80, InstFlags.None), + new(0xF2800930, 0xFEB80DB0, cmodeCmodeQvdConstraints, InstName.VbicI, T.VbicIA2, IsaVersion.v80, InstFlags.None), + new(0xF2100110, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VbicR, T.VbicRA1, IsaVersion.v80, InstFlags.None), + new(0xF3300110, 0xFFB00F10, qvdQvnQvmOpConstraints, InstName.Vbif, T.VbifA1, IsaVersion.v80, InstFlags.None), + new(0xF3200110, 0xFFB00F10, qvdQvnQvmOpConstraints, InstName.Vbit, T.VbitA1, IsaVersion.v80, InstFlags.None), + new(0xF3100110, 0xFFB00F10, qvdQvnQvmOpConstraints, InstName.Vbsl, T.VbslA1, IsaVersion.v80, InstFlags.None), + new(0xFC900800, 0xFEB00F10, qvdQvnQvmConstraints, InstName.Vcadd, T.VcaddA1, IsaVersion.v83, IsaFeature.FeatFcma, InstFlags.None), + new(0xFC800800, 0xFEB00F10, qvdQvnQvmConstraints, InstName.Vcadd, T.VcaddA1, IsaVersion.v83, IsaFeature.FeatFcma | IsaFeature.FeatFp16, InstFlags.None), + new(0xF3B10100, 0xFFB30F90, sizeQvdQvmConstraints, InstName.VceqI, T.VceqIA1, IsaVersion.v80, InstFlags.None), + new(0xF3B90500, 0xFFBB0F90, sizeQvdQvmConstraints, InstName.VceqI, T.VceqIA1, IsaVersion.v80, InstFlags.None), + new(0xF3B50500, 0xFFBF0F90, sizeQvdQvmConstraints, InstName.VceqI, T.VceqIA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xF3000810, 0xFF800F10, qvdQvnQvmSizeConstraints, InstName.VceqR, T.VceqRA1, IsaVersion.v80, InstFlags.None), + new(0xF2000E00, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VceqR, T.VceqRA2, IsaVersion.v80, InstFlags.None), + new(0xF2100E00, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VceqR, T.VceqRA2, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xF3B10080, 0xFFB30F90, sizeQvdQvmConstraints, InstName.VcgeI, T.VcgeIA1, IsaVersion.v80, InstFlags.None), + new(0xF3B90480, 0xFFBB0F90, sizeQvdQvmConstraints, InstName.VcgeI, T.VcgeIA1, IsaVersion.v80, InstFlags.None), + new(0xF3B50480, 0xFFBF0F90, sizeQvdQvmConstraints, InstName.VcgeI, T.VcgeIA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xF2000310, 0xFE800F10, qvdQvnQvmSizeConstraints, InstName.VcgeR, T.VcgeRA1, IsaVersion.v80, InstFlags.None), + new(0xF3000E00, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VcgeR, T.VcgeRA2, IsaVersion.v80, InstFlags.None), + new(0xF3100E00, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VcgeR, T.VcgeRA2, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xF3B10000, 0xFFB30F90, sizeQvdQvmConstraints, InstName.VcgtI, T.VcgtIA1, IsaVersion.v80, InstFlags.None), + new(0xF3B90400, 0xFFBB0F90, sizeQvdQvmConstraints, InstName.VcgtI, T.VcgtIA1, IsaVersion.v80, InstFlags.None), + new(0xF3B50400, 0xFFBF0F90, sizeQvdQvmConstraints, InstName.VcgtI, T.VcgtIA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xF2000300, 0xFE800F10, qvdQvnQvmSizeConstraints, InstName.VcgtR, T.VcgtRA1, IsaVersion.v80, InstFlags.None), + new(0xF3200E00, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VcgtR, T.VcgtRA2, IsaVersion.v80, InstFlags.None), + new(0xF3300E00, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VcgtR, T.VcgtRA2, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xF3B10180, 0xFFB30F90, sizeQvdQvmConstraints, InstName.VcleI, T.VcleIA1, IsaVersion.v80, InstFlags.None), + new(0xF3B90580, 0xFFBB0F90, sizeQvdQvmConstraints, InstName.VcleI, T.VcleIA1, IsaVersion.v80, InstFlags.None), + new(0xF3B50580, 0xFFBF0F90, sizeQvdQvmConstraints, InstName.VcleI, T.VcleIA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xF3B00400, 0xFFB30F90, sizeQvdQvmConstraints, InstName.Vcls, T.VclsA1, IsaVersion.v80, InstFlags.None), + new(0xF3B10200, 0xFFB30F90, sizeQvdQvmConstraints, InstName.VcltI, T.VcltIA1, IsaVersion.v80, InstFlags.None), + new(0xF3B90600, 0xFFBB0F90, sizeQvdQvmConstraints, InstName.VcltI, T.VcltIA1, IsaVersion.v80, InstFlags.None), + new(0xF3B50600, 0xFFBF0F90, sizeQvdQvmConstraints, InstName.VcltI, T.VcltIA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xF3B00480, 0xFFB30F90, sizeQvdQvmConstraints, InstName.Vclz, T.VclzA1, IsaVersion.v80, InstFlags.None), + new(0xFC200800, 0xFE200F10, qvdQvnQvmConstraints, InstName.Vcmla, T.VcmlaA1, IsaVersion.v83, IsaFeature.FeatFcma, InstFlags.None), + new(0xFE000800, 0xFF000F10, qvdQvnConstraints, InstName.VcmlaS, T.VcmlaSA1, IsaVersion.v83, IsaFeature.FeatFcma, InstFlags.None), + new(0x0EB40A40, 0x0FBF0ED0, condConstraints, InstName.Vcmp, T.VcmpA1, IsaVersion.v80, InstFlags.Cond), + new(0x0EB40940, 0x0FBF0FD0, condConstraints, InstName.Vcmp, T.VcmpA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.Cond), + new(0x0EB50A40, 0x0FBF0EFF, condConstraints, InstName.Vcmp, T.VcmpA2, IsaVersion.v80, InstFlags.Cond), + new(0x0EB50940, 0x0FBF0FFF, condConstraints, InstName.Vcmp, T.VcmpA2, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.Cond), + new(0x0EB40AC0, 0x0FBF0ED0, condConstraints, InstName.Vcmpe, T.VcmpeA1, IsaVersion.v80, InstFlags.Cond), + new(0x0EB409C0, 0x0FBF0FD0, condConstraints, InstName.Vcmpe, T.VcmpeA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.Cond), + new(0x0EB50AC0, 0x0FBF0EFF, condConstraints, InstName.Vcmpe, T.VcmpeA2, IsaVersion.v80, InstFlags.Cond), + new(0x0EB509C0, 0x0FBF0FFF, condConstraints, InstName.Vcmpe, T.VcmpeA2, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.Cond), + new(0xF3B00500, 0xFFBF0F90, qvdQvmConstraints, InstName.Vcnt, T.VcntA1, IsaVersion.v80, InstFlags.None), + new(0xF3BB0000, 0xFFBF0F10, qvdQvmConstraints, InstName.VcvtaAsimd, T.VcvtaAsimdA1, IsaVersion.v80, InstFlags.None), + new(0xF3B70000, 0xFFBF0F10, qvdQvmConstraints, InstName.VcvtaAsimd, T.VcvtaAsimdA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xFEBC0A40, 0xFFBF0E50, sizeConstraints, InstName.VcvtaVfp, T.VcvtaVfpA1, IsaVersion.v80, InstFlags.None), + new(0xFEBC0940, 0xFFBF0F50, sizeConstraints, InstName.VcvtaVfp, T.VcvtaVfpA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0x0EB20A40, 0x0FBE0ED0, condConstraints, InstName.Vcvtb, T.VcvtbA1, IsaVersion.v80, InstFlags.Cond), + new(0x0EB30940, 0x0FBF0FD0, condConstraints, InstName.VcvtbBfs, T.VcvtbBfsA1, IsaVersion.v86, IsaFeature.FeatAa32bf16, InstFlags.Cond), + new(0xF3BB0300, 0xFFBF0F10, qvdQvmConstraints, InstName.VcvtmAsimd, T.VcvtmAsimdA1, IsaVersion.v80, InstFlags.None), + new(0xF3B70300, 0xFFBF0F10, qvdQvmConstraints, InstName.VcvtmAsimd, T.VcvtmAsimdA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xFEBF0A40, 0xFFBF0E50, sizeConstraints, InstName.VcvtmVfp, T.VcvtmVfpA1, IsaVersion.v80, InstFlags.None), + new(0xFEBF0940, 0xFFBF0F50, sizeConstraints, InstName.VcvtmVfp, T.VcvtmVfpA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xF3BB0100, 0xFFBF0F10, qvdQvmConstraints, InstName.VcvtnAsimd, T.VcvtnAsimdA1, IsaVersion.v80, InstFlags.None), + new(0xF3B70100, 0xFFBF0F10, qvdQvmConstraints, InstName.VcvtnAsimd, T.VcvtnAsimdA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xFEBD0A40, 0xFFBF0E50, sizeConstraints, InstName.VcvtnVfp, T.VcvtnVfpA1, IsaVersion.v80, InstFlags.None), + new(0xFEBD0940, 0xFFBF0F50, sizeConstraints, InstName.VcvtnVfp, T.VcvtnVfpA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xF3BB0200, 0xFFBF0F10, qvdQvmConstraints, InstName.VcvtpAsimd, T.VcvtpAsimdA1, IsaVersion.v80, InstFlags.None), + new(0xF3B70200, 0xFFBF0F10, qvdQvmConstraints, InstName.VcvtpAsimd, T.VcvtpAsimdA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xFEBE0A40, 0xFFBF0E50, sizeConstraints, InstName.VcvtpVfp, T.VcvtpVfpA1, IsaVersion.v80, InstFlags.None), + new(0xFEBE0940, 0xFFBF0F50, sizeConstraints, InstName.VcvtpVfp, T.VcvtpVfpA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0x0EBC0A40, 0x0FBE0ED0, condConstraints, InstName.VcvtrIv, T.VcvtrIvA1, IsaVersion.v80, InstFlags.Cond), + new(0x0EBC0940, 0x0FBE0FD0, condConstraints, InstName.VcvtrIv, T.VcvtrIvA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.Cond), + new(0x0EB20AC0, 0x0FBE0ED0, condConstraints, InstName.Vcvtt, T.VcvttA1, IsaVersion.v80, InstFlags.Cond), + new(0x0EB309C0, 0x0FBF0FD0, condConstraints, InstName.VcvttBfs, T.VcvttBfsA1, IsaVersion.v86, IsaFeature.FeatAa32bf16, InstFlags.Cond), + new(0xF3B60640, 0xFFBF0FD0, vmConstraints, InstName.VcvtBfs, T.VcvtBfsA1, IsaVersion.v86, IsaFeature.FeatAa32bf16, InstFlags.None), + new(0x0EB70AC0, 0x0FBF0ED0, condConstraints, InstName.VcvtDs, T.VcvtDsA1, IsaVersion.v80, InstFlags.Cond), + new(0xF3B60600, 0xFFBF0ED0, opvdOpvmConstraints, InstName.VcvtHs, T.VcvtHsA1, IsaVersion.v80, InstFlags.None), + new(0xF3BB0600, 0xFFBF0E10, qvdQvmConstraints, InstName.VcvtIs, T.VcvtIsA1, IsaVersion.v80, InstFlags.None), + new(0xF3B70600, 0xFFBF0E10, qvdQvmConstraints, InstName.VcvtIs, T.VcvtIsA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0x0EBC0AC0, 0x0FBE0ED0, condConstraints, InstName.VcvtIv, T.VcvtIvA1, IsaVersion.v80, InstFlags.Cond), + new(0x0EBC09C0, 0x0FBE0FD0, condConstraints, InstName.VcvtIv, T.VcvtIvA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.Cond), + new(0x0EB80A40, 0x0FBF0E50, condConstraints, InstName.VcvtVi, T.VcvtViA1, IsaVersion.v80, InstFlags.Cond), + new(0x0EB80940, 0x0FBF0F50, condConstraints, InstName.VcvtVi, T.VcvtViA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.Cond), + new(0xF2800E10, 0xFE800E90, imm6Opimm6Imm6QvdQvmConstraints, InstName.VcvtXs, T.VcvtXsA1, IsaVersion.v80, InstFlags.None), + new(0xF2800C10, 0xFE800E90, imm6Opimm6Imm6QvdQvmConstraints, InstName.VcvtXs, T.VcvtXsA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0x0EBA0A40, 0x0FBA0E50, condConstraints, InstName.VcvtXv, T.VcvtXvA1, IsaVersion.v80, InstFlags.Cond), + new(0x0EBA0940, 0x0FBA0F50, condConstraints, InstName.VcvtXv, T.VcvtXvA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.Cond), + new(0x0E800A00, 0x0FB00E50, condConstraints, InstName.Vdiv, T.VdivA1, IsaVersion.v80, InstFlags.Cond), + new(0x0E800900, 0x0FB00F50, condConstraints, InstName.Vdiv, T.VdivA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.Cond), + new(0xFC000D00, 0xFFB00F10, qvdQvnQvmConstraints, InstName.Vdot, T.VdotA1, IsaVersion.v86, IsaFeature.FeatAa32bf16, InstFlags.None), + new(0xFE000D00, 0xFFB00F10, qvdQvnConstraints, InstName.VdotS, T.VdotSA1, IsaVersion.v86, IsaFeature.FeatAa32bf16, InstFlags.None), + new(0x0E800B10, 0x0F900F5F, condQvdEbConstraints, InstName.VdupR, T.VdupRA1, IsaVersion.v80, InstFlags.CondRtRead), + new(0xF3B00C00, 0xFFB00F90, imm4QvdConstraints, InstName.VdupS, T.VdupSA1, IsaVersion.v80, InstFlags.None), + new(0xF3000110, 0xFFB00F10, qvdQvnQvmConstraints, InstName.Veor, T.VeorA1, IsaVersion.v80, InstFlags.None), + new(0xF2B00000, 0xFFB00010, qvdQvnQvmQimm4Constraints, InstName.Vext, T.VextA1, IsaVersion.v80, InstFlags.None), + new(0xF2000C10, 0xFFB00F10, qvdQvnQvmConstraints, InstName.Vfma, T.VfmaA1, IsaVersion.v80, InstFlags.None), + new(0xF2100C10, 0xFFB00F10, qvdQvnQvmConstraints, InstName.Vfma, T.VfmaA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0x0EA00A00, 0x0FB00E50, condConstraints, InstName.Vfma, T.VfmaA2, IsaVersion.v80, InstFlags.Cond), + new(0x0EA00900, 0x0FB00F50, condConstraints, InstName.Vfma, T.VfmaA2, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.Cond), + new(0xFC200810, 0xFFB00F10, qvdConstraints, InstName.Vfmal, T.VfmalA1, IsaVersion.v82, IsaFeature.FeatFhm, InstFlags.None), + new(0xFE000810, 0xFFB00F10, qvdConstraints, InstName.VfmalS, T.VfmalSA1, IsaVersion.v82, IsaFeature.FeatFhm, InstFlags.None), + new(0xFC300810, 0xFFB00F10, vdVnVmConstraints, InstName.VfmaBf, T.VfmaBfA1, IsaVersion.v86, IsaFeature.FeatAa32bf16, InstFlags.None), + new(0xFE300810, 0xFFB00F10, vdVnConstraints, InstName.VfmaBfs, T.VfmaBfsA1, IsaVersion.v86, IsaFeature.FeatAa32bf16, InstFlags.None), + new(0xF2200C10, 0xFFB00F10, qvdQvnQvmConstraints, InstName.Vfms, T.VfmsA1, IsaVersion.v80, InstFlags.None), + new(0xF2300C10, 0xFFB00F10, qvdQvnQvmConstraints, InstName.Vfms, T.VfmsA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0x0EA00A40, 0x0FB00E50, condConstraints, InstName.Vfms, T.VfmsA2, IsaVersion.v80, InstFlags.Cond), + new(0x0EA00940, 0x0FB00F50, condConstraints, InstName.Vfms, T.VfmsA2, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.Cond), + new(0xFCA00810, 0xFFB00F10, qvdConstraints, InstName.Vfmsl, T.VfmslA1, IsaVersion.v82, IsaFeature.FeatFhm, InstFlags.None), + new(0xFE100810, 0xFFB00F10, qvdConstraints, InstName.VfmslS, T.VfmslSA1, IsaVersion.v82, IsaFeature.FeatFhm, InstFlags.None), + new(0x0E900A40, 0x0FB00E50, condConstraints, InstName.Vfnma, T.VfnmaA1, IsaVersion.v80, InstFlags.Cond), + new(0x0E900940, 0x0FB00F50, condConstraints, InstName.Vfnma, T.VfnmaA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.Cond), + new(0x0E900A00, 0x0FB00E50, condConstraints, InstName.Vfnms, T.VfnmsA1, IsaVersion.v80, InstFlags.Cond), + new(0x0E900900, 0x0FB00F50, condConstraints, InstName.Vfnms, T.VfnmsA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.Cond), + new(0xF2000000, 0xFE800F10, qvdQvnQvmSizeConstraints, InstName.Vhadd, T.VhaddA1, IsaVersion.v80, InstFlags.None), + new(0xF2000200, 0xFE800F10, qvdQvnQvmSizeConstraints, InstName.Vhsub, T.VhsubA1, IsaVersion.v80, InstFlags.None), + new(0xFEB00AC0, 0xFFBF0FD0, InstName.Vins, T.VinsA1, IsaVersion.v82, IsaFeature.FeatFp16, InstFlags.None), + new(0x0EB90BC0, 0x0FBF0FD0, condConstraints, InstName.Vjcvt, T.VjcvtA1, IsaVersion.v83, IsaFeature.FeatJscvt, InstFlags.Cond), + new(0xF4A00000, 0xFFB00F10, sizeConstraints2, InstName.Vld11, T.Vld11A1, IsaVersion.v80, InstFlags.None), + new(0xF4A00400, 0xFFB00F20, sizeConstraints2, InstName.Vld11, T.Vld11A2, IsaVersion.v80, InstFlags.None), + new(0xF4A00800, 0xFFB00F40, sizeIndexAlignIndexAlignConstraints, InstName.Vld11, T.Vld11A3, IsaVersion.v80, InstFlags.None), + new(0xF4A00C00, 0xFFB00F00, sizeSizeaConstraints, InstName.Vld1A, T.Vld1AA1, IsaVersion.v80, InstFlags.None), + new(0xF4200700, 0xFFB00F00, alignConstraints, InstName.Vld1M, T.Vld1MA1, IsaVersion.v80, InstFlags.None), + new(0xF4200A00, 0xFFB00F00, alignConstraints2, InstName.Vld1M, T.Vld1MA2, IsaVersion.v80, InstFlags.None), + new(0xF4200600, 0xFFB00F00, alignConstraints, InstName.Vld1M, T.Vld1MA3, IsaVersion.v80, InstFlags.None), + new(0xF4200200, 0xFFB00F00, InstName.Vld1M, T.Vld1MA4, IsaVersion.v80, InstFlags.None), + new(0xF4A00100, 0xFFB00F00, sizeConstraints2, InstName.Vld21, T.Vld21A1, IsaVersion.v80, InstFlags.None), + new(0xF4A00500, 0xFFB00F00, sizeConstraints2, InstName.Vld21, T.Vld21A2, IsaVersion.v80, InstFlags.None), + new(0xF4A00900, 0xFFB00F20, sizeConstraints2, InstName.Vld21, T.Vld21A3, IsaVersion.v80, InstFlags.None), + new(0xF4A00D00, 0xFFB00F00, sizeConstraints3, InstName.Vld2A, T.Vld2AA1, IsaVersion.v80, InstFlags.None), + new(0xF4200800, 0xFFB00E00, alignSizeConstraints, InstName.Vld2M, T.Vld2MA1, IsaVersion.v80, InstFlags.None), + new(0xF4200300, 0xFFB00F00, sizeConstraints3, InstName.Vld2M, T.Vld2MA2, IsaVersion.v80, InstFlags.None), + new(0xF4A00200, 0xFFB00F10, sizeConstraints2, InstName.Vld31, T.Vld31A1, IsaVersion.v80, InstFlags.None), + new(0xF4A00600, 0xFFB00F10, sizeConstraints2, InstName.Vld31, T.Vld31A2, IsaVersion.v80, InstFlags.None), + new(0xF4A00A00, 0xFFB00F30, sizeConstraints2, InstName.Vld31, T.Vld31A3, IsaVersion.v80, InstFlags.None), + new(0xF4A00E00, 0xFFB00F10, sizeAConstraints, InstName.Vld3A, T.Vld3AA1, IsaVersion.v80, InstFlags.None), + new(0xF4200400, 0xFFB00E00, sizeAlignConstraints, InstName.Vld3M, T.Vld3MA1, IsaVersion.v80, InstFlags.None), + new(0xF4A00300, 0xFFB00F00, sizeConstraints2, InstName.Vld41, T.Vld41A1, IsaVersion.v80, InstFlags.None), + new(0xF4A00700, 0xFFB00F00, sizeConstraints2, InstName.Vld41, T.Vld41A2, IsaVersion.v80, InstFlags.None), + new(0xF4A00B00, 0xFFB00F00, sizeIndexAlignConstraints, InstName.Vld41, T.Vld41A3, IsaVersion.v80, InstFlags.None), + new(0xF4A00F00, 0xFFB00F00, sizeaConstraints, InstName.Vld4A, T.Vld4AA1, IsaVersion.v80, InstFlags.None), + new(0xF4200000, 0xFFB00E00, sizeConstraints3, InstName.Vld4M, T.Vld4MA1, IsaVersion.v80, InstFlags.None), + new(0x0C100B00, 0x0E100F01, condPuwPwPuwPuwConstraints, InstName.Vldm, T.VldmA1, IsaVersion.v80, InstFlags.CondWBack), + new(0x0C100A00, 0x0E100F00, condPuwPwPuwPuwConstraints, InstName.Vldm, T.VldmA2, IsaVersion.v80, InstFlags.CondWBack), + new(0x0D100A00, 0x0F300E00, condRnConstraints3, InstName.VldrI, T.VldrIA1, IsaVersion.v80, InstFlags.Cond), + new(0x0D100900, 0x0F300F00, condRnConstraints3, InstName.VldrI, T.VldrIA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.Cond), + new(0x0D1F0A00, 0x0F3F0E00, condConstraints, InstName.VldrL, T.VldrLA1, IsaVersion.v80, InstFlags.Cond), + new(0x0D1F0900, 0x0F3F0F00, condConstraints, InstName.VldrL, T.VldrLA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.Cond), + new(0xF3000F10, 0xFFB00F10, qvdQvnQvmConstraints, InstName.Vmaxnm, T.VmaxnmA1, IsaVersion.v80, InstFlags.None), + new(0xF3100F10, 0xFFB00F10, qvdQvnQvmConstraints, InstName.Vmaxnm, T.VmaxnmA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xFE800A00, 0xFFB00E50, sizeConstraints, InstName.Vmaxnm, T.VmaxnmA2, IsaVersion.v80, InstFlags.None), + new(0xFE800900, 0xFFB00F50, sizeConstraints, InstName.Vmaxnm, T.VmaxnmA2, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xF2000F00, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VmaxF, T.VmaxFA1, IsaVersion.v80, InstFlags.None), + new(0xF2100F00, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VmaxF, T.VmaxFA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xF2000600, 0xFE800F10, qvdQvnQvmSizeConstraints, InstName.VmaxI, T.VmaxIA1, IsaVersion.v80, InstFlags.None), + new(0xF3200F10, 0xFFB00F10, qvdQvnQvmConstraints, InstName.Vminnm, T.VminnmA1, IsaVersion.v80, InstFlags.None), + new(0xF3300F10, 0xFFB00F10, qvdQvnQvmConstraints, InstName.Vminnm, T.VminnmA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xFE800A40, 0xFFB00E50, sizeConstraints, InstName.Vminnm, T.VminnmA2, IsaVersion.v80, InstFlags.None), + new(0xFE800940, 0xFFB00F50, sizeConstraints, InstName.Vminnm, T.VminnmA2, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xF2200F00, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VminF, T.VminFA1, IsaVersion.v80, InstFlags.None), + new(0xF2300F00, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VminF, T.VminFA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xF2000610, 0xFE800F10, qvdQvnQvmSizeConstraints, InstName.VminI, T.VminIA1, IsaVersion.v80, InstFlags.None), + new(0xF2800800, 0xFE800F50, sizeVdConstraints, InstName.VmlalI, T.VmlalIA1, IsaVersion.v80, InstFlags.None), + new(0xF2800240, 0xFE800F50, sizeSizeVdConstraints, InstName.VmlalS, T.VmlalSA1, IsaVersion.v80, InstFlags.None), + new(0xF2000D10, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VmlaF, T.VmlaFA1, IsaVersion.v80, InstFlags.None), + new(0xF2100D10, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VmlaF, T.VmlaFA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0x0E000A00, 0x0FB00E50, condConstraints, InstName.VmlaF, T.VmlaFA2, IsaVersion.v80, InstFlags.Cond), + new(0x0E000900, 0x0FB00F50, condConstraints, InstName.VmlaF, T.VmlaFA2, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.Cond), + new(0xF2000900, 0xFF800F10, sizeQvdQvnQvmConstraints, InstName.VmlaI, T.VmlaIA1, IsaVersion.v80, InstFlags.None), + new(0xF2A00040, 0xFEA00E50, sizeQvdQvnConstraints, InstName.VmlaS, T.VmlaSA1, IsaVersion.v80, InstFlags.None), + new(0xF2900040, 0xFEB00F50, sizeQvdQvnConstraints, InstName.VmlaS, T.VmlaSA1, IsaVersion.v80, InstFlags.None), + new(0xF2900140, 0xFEB00F50, sizeQvdQvnConstraints, InstName.VmlaS, T.VmlaSA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xF2800A00, 0xFE800F50, sizeVdConstraints, InstName.VmlslI, T.VmlslIA1, IsaVersion.v80, InstFlags.None), + new(0xF2800640, 0xFE800F50, sizeSizeVdConstraints, InstName.VmlslS, T.VmlslSA1, IsaVersion.v80, InstFlags.None), + new(0xF2200D10, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VmlsF, T.VmlsFA1, IsaVersion.v80, InstFlags.None), + new(0xF2300D10, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VmlsF, T.VmlsFA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0x0E000A40, 0x0FB00E50, condConstraints, InstName.VmlsF, T.VmlsFA2, IsaVersion.v80, InstFlags.Cond), + new(0x0E000940, 0x0FB00F50, condConstraints, InstName.VmlsF, T.VmlsFA2, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.Cond), + new(0xF3000900, 0xFF800F10, sizeQvdQvnQvmConstraints, InstName.VmlsI, T.VmlsIA1, IsaVersion.v80, InstFlags.None), + new(0xF2A00440, 0xFEA00E50, sizeQvdQvnConstraints, InstName.VmlsS, T.VmlsSA1, IsaVersion.v80, InstFlags.None), + new(0xF2900440, 0xFEB00F50, sizeQvdQvnConstraints, InstName.VmlsS, T.VmlsSA1, IsaVersion.v80, InstFlags.None), + new(0xF2900540, 0xFEB00F50, sizeQvdQvnConstraints, InstName.VmlsS, T.VmlsSA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xFC000C40, 0xFFB00F50, vdVnVmConstraints, InstName.Vmmla, T.VmmlaA1, IsaVersion.v86, IsaFeature.FeatAa32bf16, InstFlags.None), + new(0xF2800A10, 0xFE870FD0, imm3hImm3hImm3hImm3hImm3hVdConstraints, InstName.Vmovl, T.VmovlA1, IsaVersion.v80, InstFlags.None), + new(0xF3B20200, 0xFFB30FD0, sizeVmConstraints, InstName.Vmovn, T.VmovnA1, IsaVersion.v80, InstFlags.None), + new(0xFEB00A40, 0xFFBF0FD0, InstName.Vmovx, T.VmovxA1, IsaVersion.v82, IsaFeature.FeatFp16, InstFlags.None), + new(0x0C400B10, 0x0FE00FD0, condConstraints, InstName.VmovD, T.VmovDA1, IsaVersion.v80, InstFlags.CondRt2Read), + new(0x0E000910, 0x0FE00F7F, condConstraints, InstName.VmovH, T.VmovHA1, IsaVersion.v82, IsaFeature.FeatFp16, InstFlags.CondRt), + new(0xF2800010, 0xFEB809B0, qvdConstraints, InstName.VmovI, T.VmovIA1, IsaVersion.v80, InstFlags.None), + new(0x0EB00A00, 0x0FB00EF0, condConstraints, InstName.VmovI, T.VmovIA2, IsaVersion.v80, InstFlags.Cond), + new(0x0EB00900, 0x0FB00FF0, condConstraints, InstName.VmovI, T.VmovIA2, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.Cond), + new(0xF2800810, 0xFEB80DB0, qvdConstraints, InstName.VmovI, T.VmovIA3, IsaVersion.v80, InstFlags.None), + new(0xF2800C10, 0xFEB80CB0, qvdConstraints, InstName.VmovI, T.VmovIA4, IsaVersion.v80, InstFlags.None), + new(0xF2800E30, 0xFEB80FB0, qvdConstraints, InstName.VmovI, T.VmovIA5, IsaVersion.v80, InstFlags.None), + new(0x0EB00A40, 0x0FBF0ED0, condConstraints, InstName.VmovR, T.VmovRA2, IsaVersion.v80, InstFlags.Cond), + new(0x0E000B10, 0x0F900F1F, condOpc1opc2Constraints, InstName.VmovRs, T.VmovRsA1, IsaVersion.v80, InstFlags.CondRtRead), + new(0x0E000A10, 0x0FE00F7F, condConstraints, InstName.VmovS, T.VmovSA1, IsaVersion.v80, InstFlags.CondRtRead), + new(0x0E100B10, 0x0F100F1F, condUopc1opc2Uopc1opc2Constraints, InstName.VmovSr, T.VmovSrA1, IsaVersion.v80, InstFlags.CondRt), + new(0x0C400A10, 0x0FE00FD0, condConstraints, InstName.VmovSs, T.VmovSsA1, IsaVersion.v80, InstFlags.CondRt2Read), + new(0x0EF00A10, 0x0FF00FFF, condConstraints, InstName.Vmrs, T.VmrsA1, IsaVersion.v80, InstFlags.CondRt), + new(0x0EE00A10, 0x0FF00FFF, condConstraints, InstName.Vmsr, T.VmsrA1, IsaVersion.v80, InstFlags.CondRtRead), + new(0xF2800C00, 0xFE800D50, sizeOpuOpsizeVdConstraints, InstName.VmullI, T.VmullIA1, IsaVersion.v80, InstFlags.None), + new(0xF2800A40, 0xFE800F50, sizeSizeVdConstraints, InstName.VmullS, T.VmullSA1, IsaVersion.v80, InstFlags.None), + new(0xF3000D10, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VmulF, T.VmulFA1, IsaVersion.v80, InstFlags.None), + new(0xF3100D10, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VmulF, T.VmulFA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0x0E200A00, 0x0FB00E50, condConstraints, InstName.VmulF, T.VmulFA2, IsaVersion.v80, InstFlags.Cond), + new(0x0E200900, 0x0FB00F50, condConstraints, InstName.VmulF, T.VmulFA2, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.Cond), + new(0xF2000910, 0xFE800F10, sizeOpsizeOpsizeQvdQvnQvmConstraints, InstName.VmulI, T.VmulIA1, IsaVersion.v80, InstFlags.None), + new(0xF2A00840, 0xFEA00E50, sizeQvdQvnConstraints, InstName.VmulS, T.VmulSA1, IsaVersion.v80, InstFlags.None), + new(0xF2900840, 0xFEB00F50, sizeQvdQvnConstraints, InstName.VmulS, T.VmulSA1, IsaVersion.v80, InstFlags.None), + new(0xF2900940, 0xFEB00F50, sizeQvdQvnConstraints, InstName.VmulS, T.VmulSA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xF2800030, 0xFEB809B0, cmodeQvdConstraints, InstName.VmvnI, T.VmvnIA1, IsaVersion.v80, InstFlags.None), + new(0xF2800830, 0xFEB80DB0, cmodeQvdConstraints, InstName.VmvnI, T.VmvnIA2, IsaVersion.v80, InstFlags.None), + new(0xF2800C30, 0xFEB80EB0, cmodeQvdConstraints, InstName.VmvnI, T.VmvnIA3, IsaVersion.v80, InstFlags.None), + new(0xF3B00580, 0xFFBF0F90, qvdQvmConstraints, InstName.VmvnR, T.VmvnRA1, IsaVersion.v80, InstFlags.None), + new(0xF3B10380, 0xFFB30F90, sizeQvdQvmConstraints, InstName.Vneg, T.VnegA1, IsaVersion.v80, InstFlags.None), + new(0xF3B90780, 0xFFBB0F90, sizeQvdQvmConstraints, InstName.Vneg, T.VnegA1, IsaVersion.v80, InstFlags.None), + new(0xF3B50780, 0xFFBF0F90, sizeQvdQvmConstraints, InstName.Vneg, T.VnegA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0x0EB10A40, 0x0FBF0ED0, condConstraints, InstName.Vneg, T.VnegA2, IsaVersion.v80, InstFlags.Cond), + new(0x0EB10940, 0x0FBF0FD0, condConstraints, InstName.Vneg, T.VnegA2, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.Cond), + new(0x0E100A40, 0x0FB00E50, condConstraints, InstName.Vnmla, T.VnmlaA1, IsaVersion.v80, InstFlags.Cond), + new(0x0E100940, 0x0FB00F50, condConstraints, InstName.Vnmla, T.VnmlaA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.Cond), + new(0x0E100A00, 0x0FB00E50, condConstraints, InstName.Vnmls, T.VnmlsA1, IsaVersion.v80, InstFlags.Cond), + new(0x0E100900, 0x0FB00F50, condConstraints, InstName.Vnmls, T.VnmlsA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.Cond), + new(0x0E200A40, 0x0FB00E50, condConstraints, InstName.Vnmul, T.VnmulA1, IsaVersion.v80, InstFlags.Cond), + new(0x0E200940, 0x0FB00F50, condConstraints, InstName.Vnmul, T.VnmulA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.Cond), + new(0xF2300110, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VornR, T.VornRA1, IsaVersion.v80, InstFlags.None), + new(0xF2800110, 0xFEB809B0, cmodeCmodeQvdConstraints, InstName.VorrI, T.VorrIA1, IsaVersion.v80, InstFlags.None), + new(0xF2800910, 0xFEB80DB0, cmodeCmodeQvdConstraints, InstName.VorrI, T.VorrIA2, IsaVersion.v80, InstFlags.None), + new(0xF2200110, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VorrR, T.VorrRA1, IsaVersion.v80, InstFlags.None), + new(0xF3B00600, 0xFFB30F10, sizeQvdQvmConstraints, InstName.Vpadal, T.VpadalA1, IsaVersion.v80, InstFlags.None), + new(0xF3B00200, 0xFFB30F10, sizeQvdQvmConstraints, InstName.Vpaddl, T.VpaddlA1, IsaVersion.v80, InstFlags.None), + new(0xF3000D00, 0xFFB00F10, qConstraints, InstName.VpaddF, T.VpaddFA1, IsaVersion.v80, InstFlags.None), + new(0xF3100D00, 0xFFB00F10, qConstraints, InstName.VpaddF, T.VpaddFA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xF2000B10, 0xFF800F10, sizeQConstraints, InstName.VpaddI, T.VpaddIA1, IsaVersion.v80, InstFlags.None), + new(0xF3000F00, 0xFFB00F50, InstName.VpmaxF, T.VpmaxFA1, IsaVersion.v80, InstFlags.None), + new(0xF3100F00, 0xFFB00F50, InstName.VpmaxF, T.VpmaxFA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xF2000A00, 0xFE800F50, sizeConstraints4, InstName.VpmaxI, T.VpmaxIA1, IsaVersion.v80, InstFlags.None), + new(0xF3200F00, 0xFFB00F50, InstName.VpminF, T.VpminFA1, IsaVersion.v80, InstFlags.None), + new(0xF3300F00, 0xFFB00F50, InstName.VpminF, T.VpminFA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xF2000A10, 0xFE800F50, sizeConstraints4, InstName.VpminI, T.VpminIA1, IsaVersion.v80, InstFlags.None), + new(0xF3B00700, 0xFFB30F90, sizeQvdQvmConstraints, InstName.Vqabs, T.VqabsA1, IsaVersion.v80, InstFlags.None), + new(0xF2000010, 0xFE800F10, qvdQvnQvmConstraints, InstName.Vqadd, T.VqaddA1, IsaVersion.v80, InstFlags.None), + new(0xF2800900, 0xFF800F50, sizeSizeVdConstraints, InstName.Vqdmlal, T.VqdmlalA1, IsaVersion.v80, InstFlags.None), + new(0xF2800340, 0xFF800F50, sizeSizeVdConstraints, InstName.Vqdmlal, T.VqdmlalA2, IsaVersion.v80, InstFlags.None), + new(0xF2800B00, 0xFF800F50, sizeSizeVdConstraints, InstName.Vqdmlsl, T.VqdmlslA1, IsaVersion.v80, InstFlags.None), + new(0xF2800740, 0xFF800F50, sizeSizeVdConstraints, InstName.Vqdmlsl, T.VqdmlslA2, IsaVersion.v80, InstFlags.None), + new(0xF2000B00, 0xFF800F10, qvdQvnQvmSizeSizeConstraints, InstName.Vqdmulh, T.VqdmulhA1, IsaVersion.v80, InstFlags.None), + new(0xF2800C40, 0xFE800F50, sizeSizeQvdQvnConstraints, InstName.Vqdmulh, T.VqdmulhA2, IsaVersion.v80, InstFlags.None), + new(0xF2800D00, 0xFF800F50, sizeSizeVdConstraints, InstName.Vqdmull, T.VqdmullA1, IsaVersion.v80, InstFlags.None), + new(0xF2800B40, 0xFF800F50, sizeSizeVdConstraints, InstName.Vqdmull, T.VqdmullA2, IsaVersion.v80, InstFlags.None), + new(0xF3B20200, 0xFFB30F10, opSizeVmConstraints, InstName.Vqmovn, T.VqmovnA1, IsaVersion.v80, InstFlags.None), + new(0xF3B00780, 0xFFB30F90, sizeQvdQvmConstraints, InstName.Vqneg, T.VqnegA1, IsaVersion.v80, InstFlags.None), + new(0xF3000B10, 0xFF800F10, qvdQvnQvmSizeSizeConstraints, InstName.Vqrdmlah, T.VqrdmlahA1, IsaVersion.v81, IsaFeature.FeatRdm, InstFlags.None), + new(0xF2800E40, 0xFE800F50, sizeSizeQvdQvnConstraints, InstName.Vqrdmlah, T.VqrdmlahA2, IsaVersion.v81, IsaFeature.FeatRdm, InstFlags.None), + new(0xF3000C10, 0xFF800F10, qvdQvnQvmSizeSizeConstraints, InstName.Vqrdmlsh, T.VqrdmlshA1, IsaVersion.v81, IsaFeature.FeatRdm, InstFlags.None), + new(0xF2800F40, 0xFE800F50, sizeSizeQvdQvnConstraints, InstName.Vqrdmlsh, T.VqrdmlshA2, IsaVersion.v81, IsaFeature.FeatRdm, InstFlags.None), + new(0xF3000B00, 0xFF800F10, qvdQvnQvmSizeSizeConstraints, InstName.Vqrdmulh, T.VqrdmulhA1, IsaVersion.v80, InstFlags.None), + new(0xF2800D40, 0xFE800F50, sizeSizeQvdQvnConstraints, InstName.Vqrdmulh, T.VqrdmulhA2, IsaVersion.v80, InstFlags.None), + new(0xF2000510, 0xFE800F10, qvdQvmQvnConstraints, InstName.Vqrshl, T.VqrshlA1, IsaVersion.v80, InstFlags.None), + new(0xF2800850, 0xFE800ED0, imm6UopVmConstraints, InstName.Vqrshrn, T.VqrshrnA1, IsaVersion.v80, InstFlags.None), + new(0xF2800610, 0xFE800E10, imm6lUopQvdQvmConstraints, InstName.VqshlI, T.VqshlIA1, IsaVersion.v80, InstFlags.None), + new(0xF2000410, 0xFE800F10, qvdQvmQvnConstraints, InstName.VqshlR, T.VqshlRA1, IsaVersion.v80, InstFlags.None), + new(0xF2800810, 0xFE800ED0, imm6UopVmConstraints, InstName.Vqshrn, T.VqshrnA1, IsaVersion.v80, InstFlags.None), + new(0xF2000210, 0xFE800F10, qvdQvnQvmConstraints, InstName.Vqsub, T.VqsubA1, IsaVersion.v80, InstFlags.None), + new(0xF3800400, 0xFF800F50, sizeVnVmConstraints, InstName.Vraddhn, T.VraddhnA1, IsaVersion.v80, InstFlags.None), + new(0xF3B30400, 0xFFB30E90, qvdQvmSizeSizeConstraints, InstName.Vrecpe, T.VrecpeA1, IsaVersion.v80, InstFlags.None), + new(0xF2000F10, 0xFFB00F10, qvdQvnQvmConstraints, InstName.Vrecps, T.VrecpsA1, IsaVersion.v80, InstFlags.None), + new(0xF2100F10, 0xFFB00F10, qvdQvnQvmConstraints, InstName.Vrecps, T.VrecpsA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xF3B00100, 0xFFB30F90, sizeSizeSizeQvdQvmConstraints, InstName.Vrev16, T.Vrev16A1, IsaVersion.v80, InstFlags.None), + new(0xF3B00080, 0xFFB30F90, sizeSizeQvdQvmConstraints, InstName.Vrev32, T.Vrev32A1, IsaVersion.v80, InstFlags.None), + new(0xF3B00000, 0xFFB30F90, sizeQvdQvmConstraints, InstName.Vrev64, T.Vrev64A1, IsaVersion.v80, InstFlags.None), + new(0xF2000100, 0xFE800F10, qvdQvnQvmSizeConstraints, InstName.Vrhadd, T.VrhaddA1, IsaVersion.v80, InstFlags.None), + new(0xF3BA0500, 0xFFBF0F90, qvdQvmConstraints, InstName.VrintaAsimd, T.VrintaAsimdA1, IsaVersion.v80, InstFlags.None), + new(0xF3B60500, 0xFFBF0F90, qvdQvmConstraints, InstName.VrintaAsimd, T.VrintaAsimdA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xFEB80A40, 0xFFBF0ED0, sizeConstraints, InstName.VrintaVfp, T.VrintaVfpA1, IsaVersion.v80, InstFlags.None), + new(0xFEB80940, 0xFFBF0FD0, sizeConstraints, InstName.VrintaVfp, T.VrintaVfpA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xF3BA0680, 0xFFBF0F90, qvdQvmConstraints, InstName.VrintmAsimd, T.VrintmAsimdA1, IsaVersion.v80, InstFlags.None), + new(0xF3B60680, 0xFFBF0F90, qvdQvmConstraints, InstName.VrintmAsimd, T.VrintmAsimdA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xFEBB0A40, 0xFFBF0ED0, sizeConstraints, InstName.VrintmVfp, T.VrintmVfpA1, IsaVersion.v80, InstFlags.None), + new(0xFEBB0940, 0xFFBF0FD0, sizeConstraints, InstName.VrintmVfp, T.VrintmVfpA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xF3BA0400, 0xFFBF0F90, qvdQvmConstraints, InstName.VrintnAsimd, T.VrintnAsimdA1, IsaVersion.v80, InstFlags.None), + new(0xF3B60400, 0xFFBF0F90, qvdQvmConstraints, InstName.VrintnAsimd, T.VrintnAsimdA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xFEB90A40, 0xFFBF0ED0, sizeConstraints, InstName.VrintnVfp, T.VrintnVfpA1, IsaVersion.v80, InstFlags.None), + new(0xFEB90940, 0xFFBF0FD0, sizeConstraints, InstName.VrintnVfp, T.VrintnVfpA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xF3BA0780, 0xFFBF0F90, qvdQvmConstraints, InstName.VrintpAsimd, T.VrintpAsimdA1, IsaVersion.v80, InstFlags.None), + new(0xF3B60780, 0xFFBF0F90, qvdQvmConstraints, InstName.VrintpAsimd, T.VrintpAsimdA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xFEBA0A40, 0xFFBF0ED0, sizeConstraints, InstName.VrintpVfp, T.VrintpVfpA1, IsaVersion.v80, InstFlags.None), + new(0xFEBA0940, 0xFFBF0FD0, sizeConstraints, InstName.VrintpVfp, T.VrintpVfpA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0x0EB60A40, 0x0FBF0ED0, condConstraints, InstName.VrintrVfp, T.VrintrVfpA1, IsaVersion.v80, InstFlags.Cond), + new(0x0EB60940, 0x0FBF0FD0, condConstraints, InstName.VrintrVfp, T.VrintrVfpA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.Cond), + new(0xF3BA0480, 0xFFBF0F90, qvdQvmConstraints, InstName.VrintxAsimd, T.VrintxAsimdA1, IsaVersion.v80, InstFlags.None), + new(0xF3B60480, 0xFFBF0F90, qvdQvmConstraints, InstName.VrintxAsimd, T.VrintxAsimdA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0x0EB70A40, 0x0FBF0ED0, condConstraints, InstName.VrintxVfp, T.VrintxVfpA1, IsaVersion.v80, InstFlags.Cond), + new(0x0EB70940, 0x0FBF0FD0, condConstraints, InstName.VrintxVfp, T.VrintxVfpA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.Cond), + new(0xF3BA0580, 0xFFBF0F90, qvdQvmConstraints, InstName.VrintzAsimd, T.VrintzAsimdA1, IsaVersion.v80, InstFlags.None), + new(0xF3B60580, 0xFFBF0F90, qvdQvmConstraints, InstName.VrintzAsimd, T.VrintzAsimdA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0x0EB60AC0, 0x0FBF0ED0, condConstraints, InstName.VrintzVfp, T.VrintzVfpA1, IsaVersion.v80, InstFlags.Cond), + new(0x0EB609C0, 0x0FBF0FD0, condConstraints, InstName.VrintzVfp, T.VrintzVfpA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.Cond), + new(0xF2000500, 0xFE800F10, qvdQvmQvnConstraints, InstName.Vrshl, T.VrshlA1, IsaVersion.v80, InstFlags.None), + new(0xF2800210, 0xFE800F10, imm6lQvdQvmConstraints, InstName.Vrshr, T.VrshrA1, IsaVersion.v80, InstFlags.None), + new(0xF2800850, 0xFF800FD0, imm6VmConstraints, InstName.Vrshrn, T.VrshrnA1, IsaVersion.v80, InstFlags.None), + new(0xF3B30480, 0xFFB30E90, qvdQvmSizeSizeConstraints, InstName.Vrsqrte, T.VrsqrteA1, IsaVersion.v80, InstFlags.None), + new(0xF2200F10, 0xFFB00F10, qvdQvnQvmConstraints, InstName.Vrsqrts, T.VrsqrtsA1, IsaVersion.v80, InstFlags.None), + new(0xF2300F10, 0xFFB00F10, qvdQvnQvmConstraints, InstName.Vrsqrts, T.VrsqrtsA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xF2800310, 0xFE800F10, imm6lQvdQvmConstraints, InstName.Vrsra, T.VrsraA1, IsaVersion.v80, InstFlags.None), + new(0xF3800600, 0xFF800F50, sizeVnVmConstraints, InstName.Vrsubhn, T.VrsubhnA1, IsaVersion.v80, InstFlags.None), + new(0xFC200D00, 0xFFB00F10, qvdQvnQvmConstraints, InstName.Vsdot, T.VsdotA1, IsaVersion.v82, IsaFeature.FeatDotprod, InstFlags.None), + new(0xFE200D00, 0xFFB00F10, qvdQvnConstraints, InstName.VsdotS, T.VsdotSA1, IsaVersion.v82, IsaFeature.FeatDotprod, InstFlags.None), + new(0xFE000A00, 0xFF800E50, sizeConstraints, InstName.Vsel, T.VselA1, IsaVersion.v80, InstFlags.None), + new(0xFE000900, 0xFF800F50, sizeConstraints, InstName.Vsel, T.VselA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xF2800A10, 0xFE800FD0, imm6VdImm6Imm6Imm6Constraints, InstName.Vshll, T.VshllA1, IsaVersion.v80, InstFlags.None), + new(0xF3B20300, 0xFFB30FD0, sizeVdConstraints2, InstName.Vshll, T.VshllA2, IsaVersion.v80, InstFlags.None), + new(0xF2800510, 0xFF800F10, imm6lQvdQvmConstraints, InstName.VshlI, T.VshlIA1, IsaVersion.v80, InstFlags.None), + new(0xF2000400, 0xFE800F10, qvdQvmQvnConstraints, InstName.VshlR, T.VshlRA1, IsaVersion.v80, InstFlags.None), + new(0xF2800010, 0xFE800F10, imm6lQvdQvmConstraints, InstName.Vshr, T.VshrA1, IsaVersion.v80, InstFlags.None), + new(0xF2800810, 0xFF800FD0, imm6VmConstraints, InstName.Vshrn, T.VshrnA1, IsaVersion.v80, InstFlags.None), + new(0xF3800510, 0xFF800F10, imm6lQvdQvmConstraints, InstName.Vsli, T.VsliA1, IsaVersion.v80, InstFlags.None), + new(0xFC200C40, 0xFFB00F50, vdVnVmConstraints, InstName.Vsmmla, T.VsmmlaA1, IsaVersion.v82, IsaFeature.FeatAa32i8mm, InstFlags.None), + new(0x0EB10AC0, 0x0FBF0ED0, condConstraints, InstName.Vsqrt, T.VsqrtA1, IsaVersion.v80, InstFlags.Cond), + new(0x0EB109C0, 0x0FBF0FD0, condConstraints, InstName.Vsqrt, T.VsqrtA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.Cond), + new(0xF2800110, 0xFE800F10, imm6lQvdQvmConstraints, InstName.Vsra, T.VsraA1, IsaVersion.v80, InstFlags.None), + new(0xF3800410, 0xFF800F10, imm6lQvdQvmConstraints, InstName.Vsri, T.VsriA1, IsaVersion.v80, InstFlags.None), + new(0xF4800000, 0xFFB00F10, sizeConstraints2, InstName.Vst11, T.Vst11A1, IsaVersion.v80, InstFlags.None), + new(0xF4800400, 0xFFB00F20, sizeConstraints2, InstName.Vst11, T.Vst11A2, IsaVersion.v80, InstFlags.None), + new(0xF4800800, 0xFFB00F40, sizeIndexAlignIndexAlignConstraints, InstName.Vst11, T.Vst11A3, IsaVersion.v80, InstFlags.None), + new(0xF4000700, 0xFFB00F00, alignConstraints, InstName.Vst1M, T.Vst1MA1, IsaVersion.v80, InstFlags.None), + new(0xF4000A00, 0xFFB00F00, alignConstraints2, InstName.Vst1M, T.Vst1MA2, IsaVersion.v80, InstFlags.None), + new(0xF4000600, 0xFFB00F00, alignConstraints, InstName.Vst1M, T.Vst1MA3, IsaVersion.v80, InstFlags.None), + new(0xF4000200, 0xFFB00F00, InstName.Vst1M, T.Vst1MA4, IsaVersion.v80, InstFlags.None), + new(0xF4800100, 0xFFB00F00, sizeConstraints2, InstName.Vst21, T.Vst21A1, IsaVersion.v80, InstFlags.None), + new(0xF4800500, 0xFFB00F00, sizeConstraints2, InstName.Vst21, T.Vst21A2, IsaVersion.v80, InstFlags.None), + new(0xF4800900, 0xFFB00F20, sizeConstraints2, InstName.Vst21, T.Vst21A3, IsaVersion.v80, InstFlags.None), + new(0xF4000800, 0xFFB00E00, alignSizeConstraints, InstName.Vst2M, T.Vst2MA1, IsaVersion.v80, InstFlags.None), + new(0xF4000300, 0xFFB00F00, sizeConstraints3, InstName.Vst2M, T.Vst2MA2, IsaVersion.v80, InstFlags.None), + new(0xF4800200, 0xFFB00F10, sizeConstraints2, InstName.Vst31, T.Vst31A1, IsaVersion.v80, InstFlags.None), + new(0xF4800600, 0xFFB00F10, sizeConstraints2, InstName.Vst31, T.Vst31A2, IsaVersion.v80, InstFlags.None), + new(0xF4800A00, 0xFFB00F30, sizeConstraints2, InstName.Vst31, T.Vst31A3, IsaVersion.v80, InstFlags.None), + new(0xF4000400, 0xFFB00E00, sizeAlignConstraints, InstName.Vst3M, T.Vst3MA1, IsaVersion.v80, InstFlags.None), + new(0xF4800300, 0xFFB00F00, sizeConstraints2, InstName.Vst41, T.Vst41A1, IsaVersion.v80, InstFlags.None), + new(0xF4800700, 0xFFB00F00, sizeConstraints2, InstName.Vst41, T.Vst41A2, IsaVersion.v80, InstFlags.None), + new(0xF4800B00, 0xFFB00F00, sizeIndexAlignConstraints, InstName.Vst41, T.Vst41A3, IsaVersion.v80, InstFlags.None), + new(0xF4000000, 0xFFB00E00, sizeConstraints3, InstName.Vst4M, T.Vst4MA1, IsaVersion.v80, InstFlags.None), + new(0x0C000B00, 0x0E100F01, condPuwPwPuwPuwConstraints, InstName.Vstm, T.VstmA1, IsaVersion.v80, InstFlags.CondWBack), + new(0x0C000A00, 0x0E100F00, condPuwPwPuwPuwConstraints, InstName.Vstm, T.VstmA2, IsaVersion.v80, InstFlags.CondWBack), + new(0x0D000A00, 0x0F300E00, condConstraints, InstName.Vstr, T.VstrA1, IsaVersion.v80, InstFlags.Cond), + new(0x0D000900, 0x0F300F00, condConstraints, InstName.Vstr, T.VstrA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.Cond), + new(0xF2800600, 0xFF800F50, sizeVnVmConstraints, InstName.Vsubhn, T.VsubhnA1, IsaVersion.v80, InstFlags.None), + new(0xF2800200, 0xFE800F50, sizeVdOpvnConstraints, InstName.Vsubl, T.VsublA1, IsaVersion.v80, InstFlags.None), + new(0xF2800300, 0xFE800F50, sizeVdOpvnConstraints, InstName.Vsubw, T.VsubwA1, IsaVersion.v80, InstFlags.None), + new(0xF2200D00, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VsubF, T.VsubFA1, IsaVersion.v80, InstFlags.None), + new(0xF2300D00, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VsubF, T.VsubFA1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0x0E300A40, 0x0FB00E50, condConstraints, InstName.VsubF, T.VsubFA2, IsaVersion.v80, InstFlags.Cond), + new(0x0E300940, 0x0FB00F50, condConstraints, InstName.VsubF, T.VsubFA2, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.Cond), + new(0xF3000800, 0xFF800F10, qvdQvnQvmConstraints, InstName.VsubI, T.VsubIA1, IsaVersion.v80, InstFlags.None), + new(0xFE800D10, 0xFFB00F10, qvdQvnConstraints, InstName.VsudotS, T.VsudotSA1, IsaVersion.v82, IsaFeature.FeatAa32i8mm, InstFlags.None), + new(0xF3B20000, 0xFFBF0F90, qvdQvmConstraints, InstName.Vswp, T.VswpA1, IsaVersion.v80, InstFlags.None), + new(0xF3B00800, 0xFFB00C10, InstName.Vtbl, T.VtblA1, IsaVersion.v80, InstFlags.None), + new(0xF3B20080, 0xFFB30F90, sizeQvdQvmConstraints, InstName.Vtrn, T.VtrnA1, IsaVersion.v80, InstFlags.None), + new(0xF2000810, 0xFF800F10, qvdQvnQvmSizeConstraints, InstName.Vtst, T.VtstA1, IsaVersion.v80, InstFlags.None), + new(0xFC200D10, 0xFFB00F10, qvdQvnQvmConstraints, InstName.Vudot, T.VudotA1, IsaVersion.v82, IsaFeature.FeatDotprod, InstFlags.None), + new(0xFE200D10, 0xFFB00F10, qvdQvnConstraints, InstName.VudotS, T.VudotSA1, IsaVersion.v82, IsaFeature.FeatDotprod, InstFlags.None), + new(0xFC200C50, 0xFFB00F50, vdVnVmConstraints, InstName.Vummla, T.VummlaA1, IsaVersion.v82, IsaFeature.FeatAa32i8mm, InstFlags.None), + new(0xFCA00D00, 0xFFB00F10, qvdQvnQvmConstraints, InstName.Vusdot, T.VusdotA1, IsaVersion.v82, IsaFeature.FeatAa32i8mm, InstFlags.None), + new(0xFE800D00, 0xFFB00F10, qvdQvnConstraints, InstName.VusdotS, T.VusdotSA1, IsaVersion.v82, IsaFeature.FeatAa32i8mm, InstFlags.None), + new(0xFCA00C40, 0xFFB00F50, vdVnVmConstraints, InstName.Vusmmla, T.VusmmlaA1, IsaVersion.v82, IsaFeature.FeatAa32i8mm, InstFlags.None), + new(0xF3B20100, 0xFFB30F90, sizeQsizeQvdQvmConstraints, InstName.Vuzp, T.VuzpA1, IsaVersion.v80, InstFlags.None), + new(0xF3B20180, 0xFFB30F90, sizeQsizeQvdQvmConstraints, InstName.Vzip, T.VzipA1, IsaVersion.v80, InstFlags.None), + new(0x0320F002, 0x0FFFFFFF, condConstraints, InstName.Wfe, T.WfeA1, IsaVersion.v80, InstFlags.Cond), + new(0x0320F003, 0x0FFFFFFF, condConstraints, InstName.Wfi, T.WfiA1, IsaVersion.v80, InstFlags.Cond), + new(0x0320F001, 0x0FFFFFFF, condConstraints, InstName.Yield, T.YieldA1, IsaVersion.v80, InstFlags.Cond), + }; + + _table = new(insts); + } + + public static InstMeta GetMeta(uint encoding, IsaVersion version, IsaFeature features) + { + if (_table.TryFind(encoding, version, features, out InstInfoForTable info)) + { + return info.Meta; + } + + return new(InstName.Udf, T.UdfA1, IsaVersion.v80, IsaFeature.None, InstFlags.None); + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/InstTableT16.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/InstTableT16.cs new file mode 100644 index 000000000..7ff5f6c90 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/InstTableT16.cs @@ -0,0 +1,146 @@ +using Ryujinx.Cpu.LightningJit.Table; +using System.Collections.Generic; + +namespace Ryujinx.Cpu.LightningJit.Arm32 +{ + static class InstTableT16 where T : IInstEmit + { + private static readonly InstTableLevel _table; + + static InstTableT16() + { + InstEncoding[] rmRdndnConstraints = new InstEncoding[] + { + new(0x00680000, 0x00780000), + new(0x00850000, 0x00870000), + }; + + InstEncoding[] rmConstraints = new InstEncoding[] + { + new(0x00680000, 0x00780000), + }; + + InstEncoding[] condCondConstraints = new InstEncoding[] + { + new(0x0E000000, 0x0F000000), + new(0x0F000000, 0x0F000000), + }; + + InstEncoding[] maskConstraints = new InstEncoding[] + { + new(0x00000000, 0x000F0000), + }; + + InstEncoding[] opConstraints = new InstEncoding[] + { + new(0x18000000, 0x18000000), + }; + + InstEncoding[] opOpOpOpConstraints = new InstEncoding[] + { + new(0x00000000, 0x03C00000), + new(0x00400000, 0x03C00000), + new(0x01400000, 0x03C00000), + new(0x01800000, 0x03C00000), + }; + + List insts = new() + { + new(0x41400000, 0xFFC00000, InstName.AdcR, T.AdcRT1, IsaVersion.v80, InstFlags.Rdn), + new(0x1C000000, 0xFE000000, InstName.AddI, T.AddIT1, IsaVersion.v80, InstFlags.Rd), + new(0x30000000, 0xF8000000, InstName.AddI, T.AddIT2, IsaVersion.v80, InstFlags.Rdn), + new(0x18000000, 0xFE000000, InstName.AddR, T.AddRT1, IsaVersion.v80, InstFlags.Rd), + new(0x44000000, 0xFF000000, rmRdndnConstraints, InstName.AddR, T.AddRT2, IsaVersion.v80, InstFlags.RdnDn), + new(0xA8000000, 0xF8000000, InstName.AddSpI, T.AddSpIT1, IsaVersion.v80, InstFlags.RdRd16), + new(0xB0000000, 0xFF800000, InstName.AddSpI, T.AddSpIT2, IsaVersion.v80, InstFlags.None), + new(0x44680000, 0xFF780000, InstName.AddSpR, T.AddSpRT1, IsaVersion.v80, InstFlags.None), + new(0x44850000, 0xFF870000, rmConstraints, InstName.AddSpR, T.AddSpRT2, IsaVersion.v80, InstFlags.None), + new(0xA0000000, 0xF8000000, InstName.Adr, T.AdrT1, IsaVersion.v80, InstFlags.RdRd16), + new(0x40000000, 0xFFC00000, InstName.AndR, T.AndRT1, IsaVersion.v80, InstFlags.Rdn), + new(0xD0000000, 0xF0000000, condCondConstraints, InstName.B, T.BT1, IsaVersion.v80, InstFlags.Cond), + new(0xE0000000, 0xF8000000, InstName.B, T.BT2, IsaVersion.v80, InstFlags.None), + new(0x43800000, 0xFFC00000, InstName.BicR, T.BicRT1, IsaVersion.v80, InstFlags.Rdn), + new(0xBE000000, 0xFF000000, InstName.Bkpt, T.BkptT1, IsaVersion.v80, InstFlags.None), + new(0x47800000, 0xFF870000, InstName.BlxR, T.BlxRT1, IsaVersion.v80, InstFlags.None), + new(0x47000000, 0xFF870000, InstName.Bx, T.BxT1, IsaVersion.v80, InstFlags.None), + new(0xB1000000, 0xF5000000, InstName.Cbnz, T.CbnzT1, IsaVersion.v80, InstFlags.None), + new(0x42C00000, 0xFFC00000, InstName.CmnR, T.CmnRT1, IsaVersion.v80, InstFlags.None), + new(0x28000000, 0xF8000000, InstName.CmpI, T.CmpIT1, IsaVersion.v80, InstFlags.None), + new(0x42800000, 0xFFC00000, InstName.CmpR, T.CmpRT1, IsaVersion.v80, InstFlags.None), + new(0x45000000, 0xFF000000, InstName.CmpR, T.CmpRT2, IsaVersion.v80, InstFlags.None), + new(0xB6600000, 0xFFE80000, InstName.Cps, T.CpsT1, IsaVersion.v80, InstFlags.None), + new(0x40400000, 0xFFC00000, InstName.EorR, T.EorRT1, IsaVersion.v80, InstFlags.Rdn), + new(0xBA800000, 0xFFC00000, InstName.Hlt, T.HltT1, IsaVersion.v80, InstFlags.None), + new(0xBF000000, 0xFF000000, maskConstraints, InstName.It, T.ItT1, IsaVersion.v80, InstFlags.None), + new(0xC8000000, 0xF8000000, InstName.Ldm, T.LdmT1, IsaVersion.v80, InstFlags.Rlist), + new(0x78000000, 0xF8000000, InstName.LdrbI, T.LdrbIT1, IsaVersion.v80, InstFlags.Rt), + new(0x5C000000, 0xFE000000, InstName.LdrbR, T.LdrbRT1, IsaVersion.v80, InstFlags.Rt), + new(0x88000000, 0xF8000000, InstName.LdrhI, T.LdrhIT1, IsaVersion.v80, InstFlags.Rt), + new(0x5A000000, 0xFE000000, InstName.LdrhR, T.LdrhRT1, IsaVersion.v80, InstFlags.Rt), + new(0x56000000, 0xFE000000, InstName.LdrsbR, T.LdrsbRT1, IsaVersion.v80, InstFlags.Rt), + new(0x5E000000, 0xFE000000, InstName.LdrshR, T.LdrshRT1, IsaVersion.v80, InstFlags.Rt), + new(0x68000000, 0xF8000000, InstName.LdrI, T.LdrIT1, IsaVersion.v80, InstFlags.Rt), + new(0x98000000, 0xF8000000, InstName.LdrI, T.LdrIT2, IsaVersion.v80, InstFlags.RtRd16), + new(0x48000000, 0xF8000000, InstName.LdrL, T.LdrLT1, IsaVersion.v80, InstFlags.RtRd16), + new(0x58000000, 0xFE000000, InstName.LdrR, T.LdrRT1, IsaVersion.v80, InstFlags.Rt), + new(0x20000000, 0xF8000000, InstName.MovI, T.MovIT1, IsaVersion.v80, InstFlags.RdRd16), + new(0x46000000, 0xFF000000, InstName.MovR, T.MovRT1, IsaVersion.v80, InstFlags.Rd), + new(0x00000000, 0xE0000000, opConstraints, InstName.MovR, T.MovRT2, IsaVersion.v80, InstFlags.Rd), + new(0x40000000, 0xFE000000, opOpOpOpConstraints, InstName.MovRr, T.MovRrT1, IsaVersion.v80, InstFlags.None), + new(0x43400000, 0xFFC00000, InstName.Mul, T.MulT1, IsaVersion.v80, InstFlags.None), + new(0x43C00000, 0xFFC00000, InstName.MvnR, T.MvnRT1, IsaVersion.v80, InstFlags.Rd), + new(0xBF000000, 0xFFFF0000, InstName.Nop, T.NopT1, IsaVersion.v80, InstFlags.None), + new(0x43000000, 0xFFC00000, InstName.OrrR, T.OrrRT1, IsaVersion.v80, InstFlags.Rdn), + new(0xBC000000, 0xFE000000, InstName.Pop, T.PopT1, IsaVersion.v80, InstFlags.Rlist), + new(0xB4000000, 0xFE000000, InstName.Push, T.PushT1, IsaVersion.v80, InstFlags.RlistRead), + new(0xBA000000, 0xFFC00000, InstName.Rev, T.RevT1, IsaVersion.v80, InstFlags.Rd), + new(0xBA400000, 0xFFC00000, InstName.Rev16, T.Rev16T1, IsaVersion.v80, InstFlags.Rd), + new(0xBAC00000, 0xFFC00000, InstName.Revsh, T.RevshT1, IsaVersion.v80, InstFlags.Rd), + new(0x42400000, 0xFFC00000, InstName.RsbI, T.RsbIT1, IsaVersion.v80, InstFlags.Rd), + new(0x41800000, 0xFFC00000, InstName.SbcR, T.SbcRT1, IsaVersion.v80, InstFlags.Rdn), + new(0xB6500000, 0xFFF70000, InstName.Setend, T.SetendT1, IsaVersion.v80, InstFlags.None), + new(0xB6100000, 0xFFF70000, InstName.Setpan, T.SetpanT1, IsaVersion.v81, IsaFeature.FeatPan, InstFlags.None), + new(0xBF400000, 0xFFFF0000, InstName.Sev, T.SevT1, IsaVersion.v80, InstFlags.None), + new(0xBF500000, 0xFFFF0000, InstName.Sevl, T.SevlT1, IsaVersion.v80, InstFlags.None), + new(0xC0000000, 0xF8000000, InstName.Stm, T.StmT1, IsaVersion.v80, InstFlags.RlistRead), + new(0x70000000, 0xF8000000, InstName.StrbI, T.StrbIT1, IsaVersion.v80, InstFlags.RtRead), + new(0x54000000, 0xFE000000, InstName.StrbR, T.StrbRT1, IsaVersion.v80, InstFlags.RtRead), + new(0x80000000, 0xF8000000, InstName.StrhI, T.StrhIT1, IsaVersion.v80, InstFlags.RtRead), + new(0x52000000, 0xFE000000, InstName.StrhR, T.StrhRT1, IsaVersion.v80, InstFlags.RtRead), + new(0x60000000, 0xF8000000, InstName.StrI, T.StrIT1, IsaVersion.v80, InstFlags.RtRead), + new(0x90000000, 0xF8000000, InstName.StrI, T.StrIT2, IsaVersion.v80, InstFlags.RtReadRd16), + new(0x50000000, 0xFE000000, InstName.StrR, T.StrRT1, IsaVersion.v80, InstFlags.RtRead), + new(0x1E000000, 0xFE000000, InstName.SubI, T.SubIT1, IsaVersion.v80, InstFlags.Rd), + new(0x38000000, 0xF8000000, InstName.SubI, T.SubIT2, IsaVersion.v80, InstFlags.Rdn), + new(0x1A000000, 0xFE000000, InstName.SubR, T.SubRT1, IsaVersion.v80, InstFlags.Rd), + new(0xB0800000, 0xFF800000, InstName.SubSpI, T.SubSpIT1, IsaVersion.v80, InstFlags.None), + new(0xDF000000, 0xFF000000, InstName.Svc, T.SvcT1, IsaVersion.v80, InstFlags.None), + new(0xB2400000, 0xFFC00000, InstName.Sxtb, T.SxtbT1, IsaVersion.v80, InstFlags.Rd), + new(0xB2000000, 0xFFC00000, InstName.Sxth, T.SxthT1, IsaVersion.v80, InstFlags.Rd), + new(0x42000000, 0xFFC00000, InstName.TstR, T.TstRT1, IsaVersion.v80, InstFlags.None), + new(0xDE000000, 0xFF000000, InstName.Udf, T.UdfT1, IsaVersion.v80, InstFlags.None), + new(0xB2C00000, 0xFFC00000, InstName.Uxtb, T.UxtbT1, IsaVersion.v80, InstFlags.Rd), + new(0xB2800000, 0xFFC00000, InstName.Uxth, T.UxthT1, IsaVersion.v80, InstFlags.Rd), + new(0xBF200000, 0xFFFF0000, InstName.Wfe, T.WfeT1, IsaVersion.v80, InstFlags.None), + new(0xBF300000, 0xFFFF0000, InstName.Wfi, T.WfiT1, IsaVersion.v80, InstFlags.None), + new(0xBF100000, 0xFFFF0000, InstName.Yield, T.YieldT1, IsaVersion.v80, InstFlags.None), + }; + + _table = new(insts); + } + + public static bool TryGetMeta(uint encoding, IsaVersion version, IsaFeature features, out InstMeta meta) + { + if (_table.TryFind(encoding, version, features, out InstInfoForTable info)) + { + meta = info.Meta; + + return true; + } + + meta = new(InstName.Udf, T.UdfA1, IsaVersion.v80, IsaFeature.None, InstFlags.None); + + return false; + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/InstTableT32.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/InstTableT32.cs new file mode 100644 index 000000000..4a11effdb --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/InstTableT32.cs @@ -0,0 +1,1212 @@ +using Ryujinx.Cpu.LightningJit.Table; +using System.Collections.Generic; + +namespace Ryujinx.Cpu.LightningJit.Arm32 +{ + static class InstTableT32 where T : IInstEmit + { + private static readonly InstTableLevel _table; + + static InstTableT32() + { + InstEncoding[] rnRdsConstraints = new InstEncoding[] + { + new(0x000D0000, 0x000F0000), + new(0x00100F00, 0x00100F00), + }; + + InstEncoding[] rnRnConstraints = new InstEncoding[] + { + new(0x000D0000, 0x000F0000), + new(0x000F0000, 0x000F0000), + }; + + InstEncoding[] rdsConstraints = new InstEncoding[] + { + new(0x00100F00, 0x00100F00), + }; + + InstEncoding[] vdVmConstraints = new InstEncoding[] + { + new(0x00001000, 0x00001000), + new(0x00000001, 0x00000001), + }; + + InstEncoding[] condCondCondConstraints = new InstEncoding[] + { + new(0x03800000, 0x03C00000), + new(0x03C00000, 0x03C00000), + new(0x03800000, 0x03800000), + }; + + InstEncoding[] rnConstraints = new InstEncoding[] + { + new(0x000F0000, 0x000F0000), + }; + + InstEncoding[] hConstraints = new InstEncoding[] + { + new(0x00000001, 0x00000001), + }; + + InstEncoding[] imodmConstraints = new InstEncoding[] + { + new(0x00000000, 0x00000700), + }; + + InstEncoding[] optionConstraints = new InstEncoding[] + { + new(0x00000000, 0x0000000F), + }; + + InstEncoding[] puwPwPuwPuwConstraints = new InstEncoding[] + { + new(0x00000000, 0x01A00000), + new(0x01000000, 0x01200000), + new(0x00200000, 0x01A00000), + new(0x01A00000, 0x01A00000), + }; + + InstEncoding[] rnPuwConstraints = new InstEncoding[] + { + new(0x000F0000, 0x000F0000), + new(0x00000000, 0x01A00000), + }; + + InstEncoding[] puwConstraints = new InstEncoding[] + { + new(0x00000000, 0x01A00000), + }; + + InstEncoding[] rnRtConstraints = new InstEncoding[] + { + new(0x000F0000, 0x000F0000), + new(0x0000F000, 0x0000F000), + }; + + InstEncoding[] rnRtpuwPuwPwConstraints = new InstEncoding[] + { + new(0x000F0000, 0x000F0000), + new(0x0000F400, 0x0000F700), + new(0x00000600, 0x00000700), + new(0x00000000, 0x00000500), + }; + + InstEncoding[] rtConstraints = new InstEncoding[] + { + new(0x0000F000, 0x0000F000), + }; + + InstEncoding[] rnPwConstraints = new InstEncoding[] + { + new(0x000F0000, 0x000F0000), + new(0x00000000, 0x01200000), + }; + + InstEncoding[] pwConstraints = new InstEncoding[] + { + new(0x00000000, 0x01200000), + }; + + InstEncoding[] rnPuwPwConstraints = new InstEncoding[] + { + new(0x000F0000, 0x000F0000), + new(0x00000600, 0x00000700), + new(0x00000000, 0x00000500), + }; + + InstEncoding[] raConstraints = new InstEncoding[] + { + new(0x0000F000, 0x0000F000), + }; + + InstEncoding[] sTConstraints = new InstEncoding[] + { + new(0x00100000, 0x00100000), + new(0x00000010, 0x00000010), + }; + + InstEncoding[] vdVnVmConstraints = new InstEncoding[] + { + new(0x00001000, 0x00001000), + new(0x00010000, 0x00010000), + new(0x00000001, 0x00000001), + }; + + InstEncoding[] shimm2imm3Constraints = new InstEncoding[] + { + new(0x00200000, 0x002070C0), + }; + + InstEncoding[] rnimm8Constraints = new InstEncoding[] + { + new(0x000E0000, 0x000F00FF), + }; + + InstEncoding[] sizeQvdQvnQvmConstraints = new InstEncoding[] + { + new(0x00300000, 0x00300000), + new(0x00001040, 0x00001040), + new(0x00010040, 0x00010040), + new(0x00000041, 0x00000041), + }; + + InstEncoding[] sizeVdConstraints = new InstEncoding[] + { + new(0x00300000, 0x00300000), + new(0x00001000, 0x00001000), + }; + + InstEncoding[] qvdQvnQvmConstraints = new InstEncoding[] + { + new(0x00001040, 0x00001040), + new(0x00010040, 0x00010040), + new(0x00000041, 0x00000041), + }; + + InstEncoding[] sizeQvdQvmConstraints = new InstEncoding[] + { + new(0x000C0000, 0x000C0000), + new(0x00001040, 0x00001040), + new(0x00000041, 0x00000041), + }; + + InstEncoding[] sizeVnVmConstraints = new InstEncoding[] + { + new(0x00300000, 0x00300000), + new(0x00010000, 0x00010000), + new(0x00000001, 0x00000001), + }; + + InstEncoding[] sizeVdOpvnConstraints = new InstEncoding[] + { + new(0x00300000, 0x00300000), + new(0x00001000, 0x00001000), + new(0x00010100, 0x00010100), + }; + + InstEncoding[] cmodeCmodeQvdConstraints = new InstEncoding[] + { + new(0x00000000, 0x00000100), + new(0x00000C00, 0x00000C00), + new(0x00001040, 0x00001040), + }; + + InstEncoding[] qvdQvnQvmOpConstraints = new InstEncoding[] + { + new(0x00001040, 0x00001040), + new(0x00010040, 0x00010040), + new(0x00000041, 0x00000041), + new(0x00000000, 0x00300000), + }; + + InstEncoding[] qvdQvnQvmSizeConstraints = new InstEncoding[] + { + new(0x00001040, 0x00001040), + new(0x00010040, 0x00010040), + new(0x00000041, 0x00000041), + new(0x00300000, 0x00300000), + }; + + InstEncoding[] qvdQvnConstraints = new InstEncoding[] + { + new(0x00001040, 0x00001040), + new(0x00010040, 0x00010040), + }; + + InstEncoding[] qvdQvmConstraints = new InstEncoding[] + { + new(0x00001040, 0x00001040), + new(0x00000041, 0x00000041), + }; + + InstEncoding[] sizeConstraints = new InstEncoding[] + { + new(0x00000000, 0x00000300), + }; + + InstEncoding[] vmConstraints = new InstEncoding[] + { + new(0x00000001, 0x00000001), + }; + + InstEncoding[] opvdOpvmConstraints = new InstEncoding[] + { + new(0x00001100, 0x00001100), + new(0x00000001, 0x00000101), + }; + + InstEncoding[] imm6Opimm6Imm6QvdQvmConstraints = new InstEncoding[] + { + new(0x00000000, 0x00380000), + new(0x00200000, 0x00300200), + new(0x00000000, 0x00200000), + new(0x00001040, 0x00001040), + new(0x00000041, 0x00000041), + }; + + InstEncoding[] qvdEbConstraints = new InstEncoding[] + { + new(0x00210000, 0x00210000), + new(0x00400020, 0x00400020), + }; + + InstEncoding[] imm4QvdConstraints = new InstEncoding[] + { + new(0x00000000, 0x00070000), + new(0x00001040, 0x00001040), + }; + + InstEncoding[] qvdQvnQvmQimm4Constraints = new InstEncoding[] + { + new(0x00001040, 0x00001040), + new(0x00010040, 0x00010040), + new(0x00000041, 0x00000041), + new(0x00000800, 0x00000840), + }; + + InstEncoding[] qvdConstraints = new InstEncoding[] + { + new(0x00001040, 0x00001040), + }; + + InstEncoding[] vdVnConstraints = new InstEncoding[] + { + new(0x00001000, 0x00001000), + new(0x00010000, 0x00010000), + }; + + InstEncoding[] sizeConstraints2 = new InstEncoding[] + { + new(0x00000C00, 0x00000C00), + }; + + InstEncoding[] sizeIndexAlignIndexAlignConstraints = new InstEncoding[] + { + new(0x00000C00, 0x00000C00), + new(0x00000010, 0x00000030), + new(0x00000020, 0x00000030), + }; + + InstEncoding[] sizeSizeaConstraints = new InstEncoding[] + { + new(0x000000C0, 0x000000C0), + new(0x00000010, 0x000000D0), + }; + + InstEncoding[] alignConstraints = new InstEncoding[] + { + new(0x00000020, 0x00000020), + }; + + InstEncoding[] alignConstraints2 = new InstEncoding[] + { + new(0x00000030, 0x00000030), + }; + + InstEncoding[] sizeConstraints3 = new InstEncoding[] + { + new(0x000000C0, 0x000000C0), + }; + + InstEncoding[] alignSizeConstraints = new InstEncoding[] + { + new(0x00000030, 0x00000030), + new(0x000000C0, 0x000000C0), + }; + + InstEncoding[] sizeAConstraints = new InstEncoding[] + { + new(0x000000C0, 0x000000C0), + new(0x00000010, 0x00000010), + }; + + InstEncoding[] sizeAlignConstraints = new InstEncoding[] + { + new(0x000000C0, 0x000000C0), + new(0x00000020, 0x00000020), + }; + + InstEncoding[] sizeIndexAlignConstraints = new InstEncoding[] + { + new(0x00000C00, 0x00000C00), + new(0x00000030, 0x00000030), + }; + + InstEncoding[] sizeaConstraints = new InstEncoding[] + { + new(0x000000C0, 0x000000D0), + }; + + InstEncoding[] sizeSizeVdConstraints = new InstEncoding[] + { + new(0x00300000, 0x00300000), + new(0x00000000, 0x00300000), + new(0x00001000, 0x00001000), + }; + + InstEncoding[] sizeQvdQvnConstraints = new InstEncoding[] + { + new(0x00300000, 0x00300000), + new(0x10001000, 0x10001000), + new(0x10010000, 0x10010000), + }; + + InstEncoding[] imm3hImm3hImm3hImm3hImm3hVdConstraints = new InstEncoding[] + { + new(0x00000000, 0x00380000), + new(0x00180000, 0x00380000), + new(0x00280000, 0x00380000), + new(0x00300000, 0x00380000), + new(0x00380000, 0x00380000), + new(0x00001000, 0x00001000), + }; + + InstEncoding[] sizeVmConstraints = new InstEncoding[] + { + new(0x000C0000, 0x000C0000), + new(0x00000001, 0x00000001), + }; + + InstEncoding[] opc1opc2Constraints = new InstEncoding[] + { + new(0x00000040, 0x00400060), + }; + + InstEncoding[] uopc1opc2Uopc1opc2Constraints = new InstEncoding[] + { + new(0x00800000, 0x00C00060), + new(0x00000040, 0x00400060), + }; + + InstEncoding[] sizeOpuOpsizeVdConstraints = new InstEncoding[] + { + new(0x00300000, 0x00300000), + new(0x10000200, 0x10000200), + new(0x00100200, 0x00300200), + new(0x00001000, 0x00001000), + }; + + InstEncoding[] sizeOpsizeOpsizeQvdQvnQvmConstraints = new InstEncoding[] + { + new(0x00300000, 0x00300000), + new(0x10100000, 0x10300000), + new(0x10200000, 0x10300000), + new(0x00001040, 0x00001040), + new(0x00010040, 0x00010040), + new(0x00000041, 0x00000041), + }; + + InstEncoding[] cmodeQvdConstraints = new InstEncoding[] + { + new(0x00000E00, 0x00000E00), + new(0x00001040, 0x00001040), + }; + + InstEncoding[] qConstraints = new InstEncoding[] + { + new(0x00000040, 0x00000040), + }; + + InstEncoding[] sizeQConstraints = new InstEncoding[] + { + new(0x00300000, 0x00300000), + new(0x00000040, 0x00000040), + }; + + InstEncoding[] sizeConstraints4 = new InstEncoding[] + { + new(0x00300000, 0x00300000), + }; + + InstEncoding[] qvdQvnQvmSizeSizeConstraints = new InstEncoding[] + { + new(0x00001040, 0x00001040), + new(0x00010040, 0x00010040), + new(0x00000041, 0x00000041), + new(0x00000000, 0x00300000), + new(0x00300000, 0x00300000), + }; + + InstEncoding[] sizeSizeQvdQvnConstraints = new InstEncoding[] + { + new(0x00300000, 0x00300000), + new(0x00000000, 0x00300000), + new(0x10001000, 0x10001000), + new(0x10010000, 0x10010000), + }; + + InstEncoding[] opSizeVmConstraints = new InstEncoding[] + { + new(0x00000000, 0x000000C0), + new(0x000C0000, 0x000C0000), + new(0x00000001, 0x00000001), + }; + + InstEncoding[] qvdQvmQvnConstraints = new InstEncoding[] + { + new(0x00001040, 0x00001040), + new(0x00000041, 0x00000041), + new(0x00010040, 0x00010040), + }; + + InstEncoding[] imm6UopVmConstraints = new InstEncoding[] + { + new(0x00000000, 0x00380000), + new(0x00000000, 0x10000100), + new(0x00000001, 0x00000001), + }; + + InstEncoding[] imm6lUopQvdQvmConstraints = new InstEncoding[] + { + new(0x00000000, 0x00380080), + new(0x00000000, 0x10000100), + new(0x00001040, 0x00001040), + new(0x00000041, 0x00000041), + }; + + InstEncoding[] qvdQvmSizeSizeConstraints = new InstEncoding[] + { + new(0x00001040, 0x00001040), + new(0x00000041, 0x00000041), + new(0x00000000, 0x000C0000), + new(0x000C0000, 0x000C0000), + }; + + InstEncoding[] sizeSizeSizeQvdQvmConstraints = new InstEncoding[] + { + new(0x00040000, 0x000C0000), + new(0x00080000, 0x000C0000), + new(0x000C0000, 0x000C0000), + new(0x00001040, 0x00001040), + new(0x00000041, 0x00000041), + }; + + InstEncoding[] sizeSizeQvdQvmConstraints = new InstEncoding[] + { + new(0x00080000, 0x000C0000), + new(0x000C0000, 0x000C0000), + new(0x00001040, 0x00001040), + new(0x00000041, 0x00000041), + }; + + InstEncoding[] imm6lQvdQvmConstraints = new InstEncoding[] + { + new(0x00000000, 0x00380080), + new(0x00001040, 0x00001040), + new(0x00000041, 0x00000041), + }; + + InstEncoding[] imm6VmConstraints = new InstEncoding[] + { + new(0x00000000, 0x00380000), + new(0x00000001, 0x00000001), + }; + + InstEncoding[] imm6VdImm6Imm6Imm6Constraints = new InstEncoding[] + { + new(0x00000000, 0x00380000), + new(0x00001000, 0x00001000), + new(0x00080000, 0x003F0000), + new(0x00100000, 0x003F0000), + new(0x00200000, 0x003F0000), + }; + + InstEncoding[] sizeVdConstraints2 = new InstEncoding[] + { + new(0x000C0000, 0x000C0000), + new(0x00001000, 0x00001000), + }; + + InstEncoding[] sizeQsizeQvdQvmConstraints = new InstEncoding[] + { + new(0x000C0000, 0x000C0000), + new(0x00080000, 0x000C0040), + new(0x00001040, 0x00001040), + new(0x00000041, 0x00000041), + }; + + List insts = new() + { + new(0xF1400000, 0xFBE08000, InstName.AdcI, T.AdcIT1, IsaVersion.v80, InstFlags.Rd), + new(0xEB400000, 0xFFE08000, InstName.AdcR, T.AdcRT2, IsaVersion.v80, InstFlags.Rd), + new(0xF1000000, 0xFBE08000, rnRdsConstraints, InstName.AddI, T.AddIT3, IsaVersion.v80, InstFlags.Rd), + new(0xF2000000, 0xFBF08000, rnRnConstraints, InstName.AddI, T.AddIT4, IsaVersion.v80, InstFlags.Rd), + new(0xEB000000, 0xFFE08000, rnRdsConstraints, InstName.AddR, T.AddRT3, IsaVersion.v80, InstFlags.Rd), + new(0xF10D0000, 0xFBEF8000, rdsConstraints, InstName.AddSpI, T.AddSpIT3, IsaVersion.v80, InstFlags.Rd), + new(0xF20D0000, 0xFBFF8000, InstName.AddSpI, T.AddSpIT4, IsaVersion.v80, InstFlags.Rd), + new(0xEB0D0000, 0xFFEF8000, rdsConstraints, InstName.AddSpR, T.AddSpRT3, IsaVersion.v80, InstFlags.Rd), + new(0xF2AF0000, 0xFBFF8000, InstName.Adr, T.AdrT2, IsaVersion.v80, InstFlags.Rd), + new(0xF20F0000, 0xFBFF8000, InstName.Adr, T.AdrT3, IsaVersion.v80, InstFlags.Rd), + new(0xFFB00340, 0xFFBF0FD0, vdVmConstraints, InstName.Aesd, T.AesdT1, IsaVersion.v80, IsaFeature.FeatAes, InstFlags.None), + new(0xFFB00300, 0xFFBF0FD0, vdVmConstraints, InstName.Aese, T.AeseT1, IsaVersion.v80, IsaFeature.FeatAes, InstFlags.None), + new(0xFFB003C0, 0xFFBF0FD0, vdVmConstraints, InstName.Aesimc, T.AesimcT1, IsaVersion.v80, IsaFeature.FeatAes, InstFlags.None), + new(0xFFB00380, 0xFFBF0FD0, vdVmConstraints, InstName.Aesmc, T.AesmcT1, IsaVersion.v80, IsaFeature.FeatAes, InstFlags.None), + new(0xF0000000, 0xFBE08000, rdsConstraints, InstName.AndI, T.AndIT1, IsaVersion.v80, InstFlags.Rd), + new(0xEA000000, 0xFFE08000, rdsConstraints, InstName.AndR, T.AndRT2, IsaVersion.v80, InstFlags.Rd), + new(0xF0008000, 0xF800D000, condCondCondConstraints, InstName.B, T.BT3, IsaVersion.v80, InstFlags.Cond), + new(0xF0009000, 0xF800D000, InstName.B, T.BT4, IsaVersion.v80, InstFlags.None), + new(0xF36F0000, 0xFFFF8020, InstName.Bfc, T.BfcT1, IsaVersion.v80, InstFlags.Rd), + new(0xF3600000, 0xFFF08020, rnConstraints, InstName.Bfi, T.BfiT1, IsaVersion.v80, InstFlags.Rd), + new(0xF0200000, 0xFBE08000, InstName.BicI, T.BicIT1, IsaVersion.v80, InstFlags.Rd), + new(0xEA200000, 0xFFE08000, InstName.BicR, T.BicRT2, IsaVersion.v80, InstFlags.Rd), + new(0xF000D000, 0xF800D000, InstName.BlI, T.BlIT1, IsaVersion.v80, InstFlags.None), + new(0xF000C000, 0xF800D000, hConstraints, InstName.BlI, T.BlIT2, IsaVersion.v80, InstFlags.None), + new(0xF3C08F00, 0xFFF0FFFF, InstName.Bxj, T.BxjT1, IsaVersion.v80, InstFlags.None), + new(0xF3AF8016, 0xFFFFFFFF, InstName.Clrbhb, T.ClrbhbT1, IsaVersion.v89, IsaFeature.FeatClrbhb, InstFlags.None), + new(0xF3BF8F2F, 0xFFFFFFFF, InstName.Clrex, T.ClrexT1, IsaVersion.v80, InstFlags.None), + new(0xFAB0F080, 0xFFF0F0F0, InstName.Clz, T.ClzT1, IsaVersion.v80, InstFlags.Rd), + new(0xF1100F00, 0xFBF08F00, InstName.CmnI, T.CmnIT1, IsaVersion.v80, InstFlags.None), + new(0xEB100F00, 0xFFF08F00, InstName.CmnR, T.CmnRT2, IsaVersion.v80, InstFlags.None), + new(0xF1B00F00, 0xFBF08F00, InstName.CmpI, T.CmpIT2, IsaVersion.v80, InstFlags.None), + new(0xEBB00F00, 0xFFF08F00, InstName.CmpR, T.CmpRT3, IsaVersion.v80, InstFlags.None), + new(0xF3AF8000, 0xFFFFF800, imodmConstraints, InstName.Cps, T.CpsT2, IsaVersion.v80, InstFlags.None), + new(0xFAC0F080, 0xFFF0F0C0, InstName.Crc32, T.Crc32T1, IsaVersion.v80, IsaFeature.FeatCrc32, InstFlags.Rd), + new(0xFAD0F080, 0xFFF0F0C0, InstName.Crc32c, T.Crc32cT1, IsaVersion.v80, IsaFeature.FeatCrc32, InstFlags.Rd), + new(0xF3AF8014, 0xFFFFFFFF, InstName.Csdb, T.CsdbT1, IsaVersion.v80, InstFlags.None), + new(0xF3AF80F0, 0xFFFFFFF0, InstName.Dbg, T.DbgT1, IsaVersion.v80, InstFlags.None), + new(0xF78F8001, 0xFFFFFFFF, InstName.Dcps1, T.Dcps1T1, IsaVersion.v80, InstFlags.None), + new(0xF78F8002, 0xFFFFFFFF, InstName.Dcps2, T.Dcps2T1, IsaVersion.v80, InstFlags.None), + new(0xF78F8003, 0xFFFFFFFF, InstName.Dcps3, T.Dcps3T1, IsaVersion.v80, InstFlags.None), + new(0xF3BF8F50, 0xFFFFFFF0, InstName.Dmb, T.DmbT1, IsaVersion.v80, InstFlags.None), + new(0xF3BF8F40, 0xFFFFFFF0, optionConstraints, InstName.Dsb, T.DsbT1, IsaVersion.v80, InstFlags.None), + new(0xF0800000, 0xFBE08000, rdsConstraints, InstName.EorI, T.EorIT1, IsaVersion.v80, InstFlags.Rd), + new(0xEA800000, 0xFFE08000, rdsConstraints, InstName.EorR, T.EorRT2, IsaVersion.v80, InstFlags.Rd), + new(0xF3DE8F00, 0xFFFFFFFF, InstName.Eret, T.EretT1, IsaVersion.v80, InstFlags.None), + new(0xF3AF8010, 0xFFFFFFFF, InstName.Esb, T.EsbT1, IsaVersion.v82, IsaFeature.FeatRas, InstFlags.None), + new(0xEC100B01, 0xFE100F01, puwPwPuwPuwConstraints, InstName.Fldmx, T.FldmxT1, IsaVersion.v80, InstFlags.WBack), + new(0xEC000B01, 0xFE100F01, puwPwPuwPuwConstraints, InstName.Fstmx, T.FstmxT1, IsaVersion.v80, InstFlags.WBack), + new(0xF7E08000, 0xFFF0F000, InstName.Hvc, T.HvcT1, IsaVersion.v80, InstFlags.None), + new(0xF3BF8F60, 0xFFFFFFF0, InstName.Isb, T.IsbT1, IsaVersion.v80, InstFlags.None), + new(0xE8D00FAF, 0xFFF00FFF, InstName.Lda, T.LdaT1, IsaVersion.v80, InstFlags.Rt), + new(0xE8D00F8F, 0xFFF00FFF, InstName.Ldab, T.LdabT1, IsaVersion.v80, InstFlags.Rt), + new(0xE8D00FEF, 0xFFF00FFF, InstName.Ldaex, T.LdaexT1, IsaVersion.v80, InstFlags.Rt), + new(0xE8D00FCF, 0xFFF00FFF, InstName.Ldaexb, T.LdaexbT1, IsaVersion.v80, InstFlags.Rt), + new(0xE8D000FF, 0xFFF000FF, InstName.Ldaexd, T.LdaexdT1, IsaVersion.v80, InstFlags.RtRt2), + new(0xE8D00FDF, 0xFFF00FFF, InstName.Ldaexh, T.LdaexhT1, IsaVersion.v80, InstFlags.Rt), + new(0xE8D00F9F, 0xFFF00FFF, InstName.Ldah, T.LdahT1, IsaVersion.v80, InstFlags.Rt), + new(0xEC105E00, 0xFE50FF00, rnPuwConstraints, InstName.LdcI, T.LdcIT1, IsaVersion.v80, InstFlags.WBack), + new(0xEC1F5E00, 0xFE5FFF00, puwConstraints, InstName.LdcL, T.LdcLT1, IsaVersion.v80, InstFlags.WBack), + new(0xE8900000, 0xFFD00000, InstName.Ldm, T.LdmT2, IsaVersion.v80, InstFlags.RlistWBack), + new(0xE9100000, 0xFFD00000, InstName.Ldmdb, T.LdmdbT1, IsaVersion.v80, InstFlags.RlistWBack), + new(0xF8100E00, 0xFFF00F00, rnConstraints, InstName.Ldrbt, T.LdrbtT1, IsaVersion.v80, InstFlags.Rt), + new(0xF8900000, 0xFFF00000, rnRtConstraints, InstName.LdrbI, T.LdrbIT2, IsaVersion.v80, InstFlags.Rt), + new(0xF8100800, 0xFFF00800, rnRtpuwPuwPwConstraints, InstName.LdrbI, T.LdrbIT3, IsaVersion.v80, InstFlags.RtWBack), + new(0xF81F0000, 0xFF7F0000, rtConstraints, InstName.LdrbL, T.LdrbLT1, IsaVersion.v80, InstFlags.Rt), + new(0xF8100000, 0xFFF00FC0, rnRtConstraints, InstName.LdrbR, T.LdrbRT2, IsaVersion.v80, InstFlags.Rt), + new(0xE8500000, 0xFE500000, rnPwConstraints, InstName.LdrdI, T.LdrdIT1, IsaVersion.v80, InstFlags.Rt2WBack), + new(0xE85F0000, 0xFE5F0000, pwConstraints, InstName.LdrdL, T.LdrdLT1, IsaVersion.v80, InstFlags.Rt2WBack), + new(0xE8500F00, 0xFFF00F00, InstName.Ldrex, T.LdrexT1, IsaVersion.v80, InstFlags.Rt), + new(0xE8D00F4F, 0xFFF00FFF, InstName.Ldrexb, T.LdrexbT1, IsaVersion.v80, InstFlags.Rt), + new(0xE8D0007F, 0xFFF000FF, InstName.Ldrexd, T.LdrexdT1, IsaVersion.v80, InstFlags.RtRt2), + new(0xE8D00F5F, 0xFFF00FFF, InstName.Ldrexh, T.LdrexhT1, IsaVersion.v80, InstFlags.Rt), + new(0xF8300E00, 0xFFF00F00, rnConstraints, InstName.Ldrht, T.LdrhtT1, IsaVersion.v80, InstFlags.Rt), + new(0xF8B00000, 0xFFF00000, rnRtConstraints, InstName.LdrhI, T.LdrhIT2, IsaVersion.v80, InstFlags.Rt), + new(0xF8300800, 0xFFF00800, rnRtpuwPuwPwConstraints, InstName.LdrhI, T.LdrhIT3, IsaVersion.v80, InstFlags.RtWBack), + new(0xF83F0000, 0xFF7F0000, rtConstraints, InstName.LdrhL, T.LdrhLT1, IsaVersion.v80, InstFlags.Rt), + new(0xF8300000, 0xFFF00FC0, rnRtConstraints, InstName.LdrhR, T.LdrhRT2, IsaVersion.v80, InstFlags.Rt), + new(0xF9100E00, 0xFFF00F00, rnConstraints, InstName.Ldrsbt, T.LdrsbtT1, IsaVersion.v80, InstFlags.Rt), + new(0xF9900000, 0xFFF00000, rnRtConstraints, InstName.LdrsbI, T.LdrsbIT1, IsaVersion.v80, InstFlags.Rt), + new(0xF9100800, 0xFFF00800, rnRtpuwPuwPwConstraints, InstName.LdrsbI, T.LdrsbIT2, IsaVersion.v80, InstFlags.RtWBack), + new(0xF91F0000, 0xFF7F0000, rtConstraints, InstName.LdrsbL, T.LdrsbLT1, IsaVersion.v80, InstFlags.Rt), + new(0xF9100000, 0xFFF00FC0, rnRtConstraints, InstName.LdrsbR, T.LdrsbRT2, IsaVersion.v80, InstFlags.Rt), + new(0xF9300E00, 0xFFF00F00, rnConstraints, InstName.Ldrsht, T.LdrshtT1, IsaVersion.v80, InstFlags.Rt), + new(0xF9B00000, 0xFFF00000, rnRtConstraints, InstName.LdrshI, T.LdrshIT1, IsaVersion.v80, InstFlags.Rt), + new(0xF9300800, 0xFFF00800, rnRtpuwPuwPwConstraints, InstName.LdrshI, T.LdrshIT2, IsaVersion.v80, InstFlags.RtWBack), + new(0xF93F0000, 0xFF7F0000, rtConstraints, InstName.LdrshL, T.LdrshLT1, IsaVersion.v80, InstFlags.Rt), + new(0xF9300000, 0xFFF00FC0, rnRtConstraints, InstName.LdrshR, T.LdrshRT2, IsaVersion.v80, InstFlags.Rt), + new(0xF8500E00, 0xFFF00F00, rnConstraints, InstName.Ldrt, T.LdrtT1, IsaVersion.v80, InstFlags.Rt), + new(0xF8D00000, 0xFFF00000, rnConstraints, InstName.LdrI, T.LdrIT3, IsaVersion.v80, InstFlags.Rt), + new(0xF8500800, 0xFFF00800, rnPuwPwConstraints, InstName.LdrI, T.LdrIT4, IsaVersion.v80, InstFlags.RtWBack), + new(0xF85F0000, 0xFF7F0000, InstName.LdrL, T.LdrLT2, IsaVersion.v80, InstFlags.Rt), + new(0xF8500000, 0xFFF00FC0, rnConstraints, InstName.LdrR, T.LdrRT2, IsaVersion.v80, InstFlags.Rt), + new(0xEE000E10, 0xFF100E10, InstName.Mcr, T.McrT1, IsaVersion.v80, InstFlags.Rt), + new(0xEC400E00, 0xFFF00E00, InstName.Mcrr, T.McrrT1, IsaVersion.v80, InstFlags.Rt), + new(0xFB000000, 0xFFF000F0, raConstraints, InstName.Mla, T.MlaT1, IsaVersion.v80, InstFlags.Rd), + new(0xFB000010, 0xFFF000F0, InstName.Mls, T.MlsT1, IsaVersion.v80, InstFlags.Rd), + new(0xF2C00000, 0xFBF08000, InstName.Movt, T.MovtT1, IsaVersion.v80, InstFlags.Rd), + new(0xF04F0000, 0xFBEF8000, InstName.MovI, T.MovIT2, IsaVersion.v80, InstFlags.Rd), + new(0xF2400000, 0xFBF08000, InstName.MovI, T.MovIT3, IsaVersion.v80, InstFlags.Rd), + new(0xEA4F0000, 0xFFEF8000, InstName.MovR, T.MovRT3, IsaVersion.v80, InstFlags.Rd), + new(0xFA00F000, 0xFF80F0F0, InstName.MovRr, T.MovRrT2, IsaVersion.v80, InstFlags.Rd), + new(0xEE100E10, 0xFF100E10, InstName.Mrc, T.MrcT1, IsaVersion.v80, InstFlags.Rt), + new(0xEC500E00, 0xFFF00E00, InstName.Mrrc, T.MrrcT1, IsaVersion.v80, InstFlags.Rt), + new(0xF3EF8000, 0xFFEFF0FF, InstName.Mrs, T.MrsT1, IsaVersion.v80, InstFlags.Rd), + new(0xF3E08020, 0xFFE0F0EF, InstName.MrsBr, T.MrsBrT1, IsaVersion.v80, InstFlags.Rd), + new(0xF3808020, 0xFFE0F0EF, InstName.MsrBr, T.MsrBrT1, IsaVersion.v80, InstFlags.None), + new(0xF3808000, 0xFFE0F0FF, InstName.MsrR, T.MsrRT1, IsaVersion.v80, InstFlags.None), + new(0xFB00F000, 0xFFF0F0F0, InstName.Mul, T.MulT2, IsaVersion.v80, InstFlags.Rd), + new(0xF06F0000, 0xFBEF8000, InstName.MvnI, T.MvnIT1, IsaVersion.v80, InstFlags.Rd), + new(0xEA6F0000, 0xFFEF8000, InstName.MvnR, T.MvnRT2, IsaVersion.v80, InstFlags.Rd), + new(0xF3AF8000, 0xFFFFFFFF, InstName.Nop, T.NopT2, IsaVersion.v80, InstFlags.None), + new(0xF0600000, 0xFBE08000, rnConstraints, InstName.OrnI, T.OrnIT1, IsaVersion.v80, InstFlags.Rd), + new(0xEA600000, 0xFFE08000, rnConstraints, InstName.OrnR, T.OrnRT1, IsaVersion.v80, InstFlags.Rd), + new(0xF0400000, 0xFBE08000, rnConstraints, InstName.OrrI, T.OrrIT1, IsaVersion.v80, InstFlags.Rd), + new(0xEA400000, 0xFFE08000, rnConstraints, InstName.OrrR, T.OrrRT2, IsaVersion.v80, InstFlags.Rd), + new(0xEAC00000, 0xFFF08010, sTConstraints, InstName.Pkh, T.PkhT1, IsaVersion.v80, InstFlags.Rd), + new(0xF890F000, 0xFFD0F000, rnConstraints, InstName.PldI, T.PldIT1, IsaVersion.v80, InstFlags.WBack), + new(0xF810FC00, 0xFFD0FF00, rnConstraints, InstName.PldI, T.PldIT2, IsaVersion.v80, InstFlags.WBack), + new(0xF81FF000, 0xFF7FF000, InstName.PldL, T.PldLT1, IsaVersion.v80, InstFlags.None), + new(0xF810F000, 0xFFD0FFC0, rnConstraints, InstName.PldR, T.PldRT1, IsaVersion.v80, InstFlags.WBack), + new(0xF990F000, 0xFFF0F000, rnConstraints, InstName.PliI, T.PliIT1, IsaVersion.v80, InstFlags.None), + new(0xF910FC00, 0xFFF0FF00, rnConstraints, InstName.PliI, T.PliIT2, IsaVersion.v80, InstFlags.None), + new(0xF91FF000, 0xFF7FF000, InstName.PliI, T.PliIT3, IsaVersion.v80, InstFlags.None), + new(0xF910F000, 0xFFF0FFC0, rnConstraints, InstName.PliR, T.PliRT1, IsaVersion.v80, InstFlags.None), + new(0xF3BF8F44, 0xFFFFFFFF, InstName.Pssbb, T.PssbbT1, IsaVersion.v80, InstFlags.None), + new(0xFA80F080, 0xFFF0F0F0, InstName.Qadd, T.QaddT1, IsaVersion.v80, InstFlags.Rd), + new(0xFA90F010, 0xFFF0F0F0, InstName.Qadd16, T.Qadd16T1, IsaVersion.v80, InstFlags.Rd), + new(0xFA80F010, 0xFFF0F0F0, InstName.Qadd8, T.Qadd8T1, IsaVersion.v80, InstFlags.Rd), + new(0xFAA0F010, 0xFFF0F0F0, InstName.Qasx, T.QasxT1, IsaVersion.v80, InstFlags.Rd), + new(0xFA80F090, 0xFFF0F0F0, InstName.Qdadd, T.QdaddT1, IsaVersion.v80, InstFlags.Rd), + new(0xFA80F0B0, 0xFFF0F0F0, InstName.Qdsub, T.QdsubT1, IsaVersion.v80, InstFlags.Rd), + new(0xFAE0F010, 0xFFF0F0F0, InstName.Qsax, T.QsaxT1, IsaVersion.v80, InstFlags.Rd), + new(0xFA80F0A0, 0xFFF0F0F0, InstName.Qsub, T.QsubT1, IsaVersion.v80, InstFlags.Rd), + new(0xFAD0F010, 0xFFF0F0F0, InstName.Qsub16, T.Qsub16T1, IsaVersion.v80, InstFlags.Rd), + new(0xFAC0F010, 0xFFF0F0F0, InstName.Qsub8, T.Qsub8T1, IsaVersion.v80, InstFlags.Rd), + new(0xFA90F0A0, 0xFFF0F0F0, InstName.Rbit, T.RbitT1, IsaVersion.v80, InstFlags.Rd), + new(0xFA90F080, 0xFFF0F0F0, InstName.Rev, T.RevT2, IsaVersion.v80, InstFlags.Rd), + new(0xFA90F090, 0xFFF0F0F0, InstName.Rev16, T.Rev16T2, IsaVersion.v80, InstFlags.Rd), + new(0xFA90F0B0, 0xFFF0F0F0, InstName.Revsh, T.RevshT2, IsaVersion.v80, InstFlags.Rd), + new(0xE810C000, 0xFFD0FFFF, InstName.Rfe, T.RfeT1, IsaVersion.v80, InstFlags.WBack), + new(0xE990C000, 0xFFD0FFFF, InstName.Rfe, T.RfeT2, IsaVersion.v80, InstFlags.WBack), + new(0xF1C00000, 0xFBE08000, InstName.RsbI, T.RsbIT2, IsaVersion.v80, InstFlags.Rd), + new(0xEBC00000, 0xFFE08000, InstName.RsbR, T.RsbRT1, IsaVersion.v80, InstFlags.Rd), + new(0xFA90F000, 0xFFF0F0F0, InstName.Sadd16, T.Sadd16T1, IsaVersion.v80, InstFlags.Rd), + new(0xFA80F000, 0xFFF0F0F0, InstName.Sadd8, T.Sadd8T1, IsaVersion.v80, InstFlags.Rd), + new(0xFAA0F000, 0xFFF0F0F0, InstName.Sasx, T.SasxT1, IsaVersion.v80, InstFlags.Rd), + new(0xF3BF8F70, 0xFFFFFFFF, InstName.Sb, T.SbT1, IsaVersion.v85, IsaFeature.FeatSb, InstFlags.None), + new(0xF1600000, 0xFBE08000, InstName.SbcI, T.SbcIT1, IsaVersion.v80, InstFlags.Rd), + new(0xEB600000, 0xFFE08000, InstName.SbcR, T.SbcRT2, IsaVersion.v80, InstFlags.Rd), + new(0xF3400000, 0xFFF08020, InstName.Sbfx, T.SbfxT1, IsaVersion.v80, InstFlags.Rd), + new(0xFB90F0F0, 0xFFF0F0F0, InstName.Sdiv, T.SdivT1, IsaVersion.v80, InstFlags.Rd), + new(0xFAA0F080, 0xFFF0F0F0, InstName.Sel, T.SelT1, IsaVersion.v80, InstFlags.Rd), + new(0xF3AF8004, 0xFFFFFFFF, InstName.Sev, T.SevT2, IsaVersion.v80, InstFlags.None), + new(0xF3AF8005, 0xFFFFFFFF, InstName.Sevl, T.SevlT2, IsaVersion.v80, InstFlags.None), + new(0xEF000C40, 0xFFB00F50, vdVnVmConstraints, InstName.Sha1c, T.Sha1cT1, IsaVersion.v80, IsaFeature.FeatSha1, InstFlags.None), + new(0xFFB902C0, 0xFFBF0FD0, vdVmConstraints, InstName.Sha1h, T.Sha1hT1, IsaVersion.v80, IsaFeature.FeatSha1, InstFlags.None), + new(0xEF200C40, 0xFFB00F50, vdVnVmConstraints, InstName.Sha1m, T.Sha1mT1, IsaVersion.v80, IsaFeature.FeatSha1, InstFlags.None), + new(0xEF100C40, 0xFFB00F50, vdVnVmConstraints, InstName.Sha1p, T.Sha1pT1, IsaVersion.v80, IsaFeature.FeatSha1, InstFlags.None), + new(0xEF300C40, 0xFFB00F50, vdVnVmConstraints, InstName.Sha1su0, T.Sha1su0T1, IsaVersion.v80, IsaFeature.FeatSha1, InstFlags.None), + new(0xFFBA0380, 0xFFBF0FD0, vdVmConstraints, InstName.Sha1su1, T.Sha1su1T1, IsaVersion.v80, IsaFeature.FeatSha1, InstFlags.None), + new(0xFF000C40, 0xFFB00F50, vdVnVmConstraints, InstName.Sha256h, T.Sha256hT1, IsaVersion.v80, IsaFeature.FeatSha256, InstFlags.None), + new(0xFF100C40, 0xFFB00F50, vdVnVmConstraints, InstName.Sha256h2, T.Sha256h2T1, IsaVersion.v80, IsaFeature.FeatSha256, InstFlags.None), + new(0xFFBA03C0, 0xFFBF0FD0, vdVmConstraints, InstName.Sha256su0, T.Sha256su0T1, IsaVersion.v80, IsaFeature.FeatSha256, InstFlags.None), + new(0xFF200C40, 0xFFB00F50, vdVnVmConstraints, InstName.Sha256su1, T.Sha256su1T1, IsaVersion.v80, IsaFeature.FeatSha256, InstFlags.None), + new(0xFA90F020, 0xFFF0F0F0, InstName.Shadd16, T.Shadd16T1, IsaVersion.v80, InstFlags.Rd), + new(0xFA80F020, 0xFFF0F0F0, InstName.Shadd8, T.Shadd8T1, IsaVersion.v80, InstFlags.Rd), + new(0xFAA0F020, 0xFFF0F0F0, InstName.Shasx, T.ShasxT1, IsaVersion.v80, InstFlags.Rd), + new(0xFAE0F020, 0xFFF0F0F0, InstName.Shsax, T.ShsaxT1, IsaVersion.v80, InstFlags.Rd), + new(0xFAD0F020, 0xFFF0F0F0, InstName.Shsub16, T.Shsub16T1, IsaVersion.v80, InstFlags.Rd), + new(0xFAC0F020, 0xFFF0F0F0, InstName.Shsub8, T.Shsub8T1, IsaVersion.v80, InstFlags.Rd), + new(0xF7F08000, 0xFFF0FFFF, InstName.Smc, T.SmcT1, IsaVersion.v80, InstFlags.None), + new(0xFB100000, 0xFFF000C0, raConstraints, InstName.Smlabb, T.SmlabbT1, IsaVersion.v80, InstFlags.Rd), + new(0xFB200000, 0xFFF000E0, raConstraints, InstName.Smlad, T.SmladT1, IsaVersion.v80, InstFlags.Rd), + new(0xFBC00000, 0xFFF000F0, InstName.Smlal, T.SmlalT1, IsaVersion.v80, InstFlags.RdLoRdHi), + new(0xFBC00080, 0xFFF000C0, InstName.Smlalbb, T.SmlalbbT1, IsaVersion.v80, InstFlags.RdLoRdHi), + new(0xFBC000C0, 0xFFF000E0, InstName.Smlald, T.SmlaldT1, IsaVersion.v80, InstFlags.RdLoRdHi), + new(0xFB300000, 0xFFF000E0, raConstraints, InstName.Smlawb, T.SmlawbT1, IsaVersion.v80, InstFlags.Rd), + new(0xFB400000, 0xFFF000E0, raConstraints, InstName.Smlsd, T.SmlsdT1, IsaVersion.v80, InstFlags.Rd), + new(0xFBD000C0, 0xFFF000E0, InstName.Smlsld, T.SmlsldT1, IsaVersion.v80, InstFlags.RdLoRdHi), + new(0xFB500000, 0xFFF000E0, raConstraints, InstName.Smmla, T.SmmlaT1, IsaVersion.v80, InstFlags.Rd), + new(0xFB600000, 0xFFF000E0, InstName.Smmls, T.SmmlsT1, IsaVersion.v80, InstFlags.Rd), + new(0xFB50F000, 0xFFF0F0E0, InstName.Smmul, T.SmmulT1, IsaVersion.v80, InstFlags.Rd), + new(0xFB20F000, 0xFFF0F0E0, InstName.Smuad, T.SmuadT1, IsaVersion.v80, InstFlags.Rd), + new(0xFB10F000, 0xFFF0F0C0, InstName.Smulbb, T.SmulbbT1, IsaVersion.v80, InstFlags.Rd), + new(0xFB800000, 0xFFF000F0, InstName.Smull, T.SmullT1, IsaVersion.v80, InstFlags.RdLoRdHi), + new(0xFB30F000, 0xFFF0F0E0, InstName.Smulwb, T.SmulwbT1, IsaVersion.v80, InstFlags.Rd), + new(0xFB40F000, 0xFFF0F0E0, InstName.Smusd, T.SmusdT1, IsaVersion.v80, InstFlags.Rd), + new(0xE80DC000, 0xFFDFFFE0, InstName.Srs, T.SrsT1, IsaVersion.v80, InstFlags.WBack), + new(0xE98DC000, 0xFFDFFFE0, InstName.Srs, T.SrsT2, IsaVersion.v80, InstFlags.WBack), + new(0xF3000000, 0xFFD08020, shimm2imm3Constraints, InstName.Ssat, T.SsatT1, IsaVersion.v80, InstFlags.Rd), + new(0xF3200000, 0xFFF0F0F0, InstName.Ssat16, T.Ssat16T1, IsaVersion.v80, InstFlags.Rd), + new(0xFAE0F000, 0xFFF0F0F0, InstName.Ssax, T.SsaxT1, IsaVersion.v80, InstFlags.Rd), + new(0xF3BF8F40, 0xFFFFFFFF, InstName.Ssbb, T.SsbbT1, IsaVersion.v80, InstFlags.None), + new(0xFAD0F000, 0xFFF0F0F0, InstName.Ssub16, T.Ssub16T1, IsaVersion.v80, InstFlags.Rd), + new(0xFAC0F000, 0xFFF0F0F0, InstName.Ssub8, T.Ssub8T1, IsaVersion.v80, InstFlags.Rd), + new(0xEC005E00, 0xFE50FF00, puwConstraints, InstName.Stc, T.StcT1, IsaVersion.v80, InstFlags.WBack), + new(0xE8C00FAF, 0xFFF00FFF, InstName.Stl, T.StlT1, IsaVersion.v80, InstFlags.RtRead), + new(0xE8C00F8F, 0xFFF00FFF, InstName.Stlb, T.StlbT1, IsaVersion.v80, InstFlags.RtRead), + new(0xE8C00FE0, 0xFFF00FF0, InstName.Stlex, T.StlexT1, IsaVersion.v80, InstFlags.RdRtReadRd16), + new(0xE8C00FC0, 0xFFF00FF0, InstName.Stlexb, T.StlexbT1, IsaVersion.v80, InstFlags.RdRtReadRd16), + new(0xE8C000F0, 0xFFF000F0, InstName.Stlexd, T.StlexdT1, IsaVersion.v80, InstFlags.RdRt2ReadRd16), + new(0xE8C00FD0, 0xFFF00FF0, InstName.Stlexh, T.StlexhT1, IsaVersion.v80, InstFlags.RdRtReadRd16), + new(0xE8C00F9F, 0xFFF00FFF, InstName.Stlh, T.StlhT1, IsaVersion.v80, InstFlags.RtRead), + new(0xE8800000, 0xFFD08000, InstName.Stm, T.StmT2, IsaVersion.v80, InstFlags.RlistReadWBack), + new(0xE9000000, 0xFFD08000, InstName.Stmdb, T.StmdbT1, IsaVersion.v80, InstFlags.RlistReadWBack), + new(0xF8000E00, 0xFFF00F00, rnConstraints, InstName.Strbt, T.StrbtT1, IsaVersion.v80, InstFlags.RtRead), + new(0xF8800000, 0xFFF00000, rnConstraints, InstName.StrbI, T.StrbIT2, IsaVersion.v80, InstFlags.RtRead), + new(0xF8000800, 0xFFF00800, rnPuwPwConstraints, InstName.StrbI, T.StrbIT3, IsaVersion.v80, InstFlags.RtReadWBack), + new(0xF8000000, 0xFFF00FC0, rnConstraints, InstName.StrbR, T.StrbRT2, IsaVersion.v80, InstFlags.RtRead), + new(0xE8400000, 0xFE500000, rnPwConstraints, InstName.StrdI, T.StrdIT1, IsaVersion.v80, InstFlags.Rt2ReadWBack), + new(0xE8400000, 0xFFF00000, InstName.Strex, T.StrexT1, IsaVersion.v80, InstFlags.RdRtRead), + new(0xE8C00F40, 0xFFF00FF0, InstName.Strexb, T.StrexbT1, IsaVersion.v80, InstFlags.RdRtReadRd16), + new(0xE8C00070, 0xFFF000F0, InstName.Strexd, T.StrexdT1, IsaVersion.v80, InstFlags.RdRt2ReadRd16), + new(0xE8C00F50, 0xFFF00FF0, InstName.Strexh, T.StrexhT1, IsaVersion.v80, InstFlags.RdRtReadRd16), + new(0xF8200E00, 0xFFF00F00, rnConstraints, InstName.Strht, T.StrhtT1, IsaVersion.v80, InstFlags.RtRead), + new(0xF8A00000, 0xFFF00000, rnConstraints, InstName.StrhI, T.StrhIT2, IsaVersion.v80, InstFlags.RtRead), + new(0xF8200800, 0xFFF00800, rnPuwPwConstraints, InstName.StrhI, T.StrhIT3, IsaVersion.v80, InstFlags.RtReadWBack), + new(0xF8200000, 0xFFF00FC0, rnConstraints, InstName.StrhR, T.StrhRT2, IsaVersion.v80, InstFlags.RtRead), + new(0xF8400E00, 0xFFF00F00, rnConstraints, InstName.Strt, T.StrtT1, IsaVersion.v80, InstFlags.RtRead), + new(0xF8C00000, 0xFFF00000, rnConstraints, InstName.StrI, T.StrIT3, IsaVersion.v80, InstFlags.RtRead), + new(0xF8400800, 0xFFF00800, rnPuwPwConstraints, InstName.StrI, T.StrIT4, IsaVersion.v80, InstFlags.RtReadWBack), + new(0xF8400000, 0xFFF00FC0, rnConstraints, InstName.StrR, T.StrRT2, IsaVersion.v80, InstFlags.RtRead), + new(0xF1A00000, 0xFBE08000, rnRdsConstraints, InstName.SubI, T.SubIT3, IsaVersion.v80, InstFlags.Rd), + new(0xF2A00000, 0xFBF08000, rnRnConstraints, InstName.SubI, T.SubIT4, IsaVersion.v80, InstFlags.Rd), + new(0xF3D08F00, 0xFFF0FF00, rnimm8Constraints, InstName.SubI, T.SubIT5, IsaVersion.v80, InstFlags.None), + new(0xEBA00000, 0xFFE08000, rnRdsConstraints, InstName.SubR, T.SubRT2, IsaVersion.v80, InstFlags.Rd), + new(0xF1AD0000, 0xFBEF8000, rdsConstraints, InstName.SubSpI, T.SubSpIT2, IsaVersion.v80, InstFlags.Rd), + new(0xF2AD0000, 0xFBFF8000, InstName.SubSpI, T.SubSpIT3, IsaVersion.v80, InstFlags.Rd), + new(0xEBAD0000, 0xFFEF8000, rdsConstraints, InstName.SubSpR, T.SubSpRT1, IsaVersion.v80, InstFlags.Rd), + new(0xFA40F080, 0xFFF0F0C0, rnConstraints, InstName.Sxtab, T.SxtabT1, IsaVersion.v80, InstFlags.Rd), + new(0xFA20F080, 0xFFF0F0C0, rnConstraints, InstName.Sxtab16, T.Sxtab16T1, IsaVersion.v80, InstFlags.Rd), + new(0xFA00F080, 0xFFF0F0C0, rnConstraints, InstName.Sxtah, T.SxtahT1, IsaVersion.v80, InstFlags.Rd), + new(0xFA4FF080, 0xFFFFF0C0, InstName.Sxtb, T.SxtbT2, IsaVersion.v80, InstFlags.Rd), + new(0xFA2FF080, 0xFFFFF0C0, InstName.Sxtb16, T.Sxtb16T1, IsaVersion.v80, InstFlags.Rd), + new(0xFA0FF080, 0xFFFFF0C0, InstName.Sxth, T.SxthT2, IsaVersion.v80, InstFlags.Rd), + new(0xE8D0F000, 0xFFF0FFE0, InstName.Tbb, T.TbbT1, IsaVersion.v80, InstFlags.None), + new(0xF0900F00, 0xFBF08F00, InstName.TeqI, T.TeqIT1, IsaVersion.v80, InstFlags.None), + new(0xEA900F00, 0xFFF08F00, InstName.TeqR, T.TeqRT1, IsaVersion.v80, InstFlags.None), + new(0xF3AF8012, 0xFFFFFFFF, InstName.Tsb, T.TsbT1, IsaVersion.v84, IsaFeature.FeatTrf, InstFlags.None), + new(0xF0100F00, 0xFBF08F00, InstName.TstI, T.TstIT1, IsaVersion.v80, InstFlags.None), + new(0xEA100F00, 0xFFF08F00, InstName.TstR, T.TstRT2, IsaVersion.v80, InstFlags.None), + new(0xFA90F040, 0xFFF0F0F0, InstName.Uadd16, T.Uadd16T1, IsaVersion.v80, InstFlags.Rd), + new(0xFA80F040, 0xFFF0F0F0, InstName.Uadd8, T.Uadd8T1, IsaVersion.v80, InstFlags.Rd), + new(0xFAA0F040, 0xFFF0F0F0, InstName.Uasx, T.UasxT1, IsaVersion.v80, InstFlags.Rd), + new(0xF3C00000, 0xFFF08020, InstName.Ubfx, T.UbfxT1, IsaVersion.v80, InstFlags.Rd), + new(0xF7F0A000, 0xFFF0F000, InstName.Udf, T.UdfT2, IsaVersion.v80, InstFlags.None), + new(0xFBB0F0F0, 0xFFF0F0F0, InstName.Udiv, T.UdivT1, IsaVersion.v80, InstFlags.Rd), + new(0xFA90F060, 0xFFF0F0F0, InstName.Uhadd16, T.Uhadd16T1, IsaVersion.v80, InstFlags.Rd), + new(0xFA80F060, 0xFFF0F0F0, InstName.Uhadd8, T.Uhadd8T1, IsaVersion.v80, InstFlags.Rd), + new(0xFAA0F060, 0xFFF0F0F0, InstName.Uhasx, T.UhasxT1, IsaVersion.v80, InstFlags.Rd), + new(0xFAE0F060, 0xFFF0F0F0, InstName.Uhsax, T.UhsaxT1, IsaVersion.v80, InstFlags.Rd), + new(0xFAD0F060, 0xFFF0F0F0, InstName.Uhsub16, T.Uhsub16T1, IsaVersion.v80, InstFlags.Rd), + new(0xFAC0F060, 0xFFF0F0F0, InstName.Uhsub8, T.Uhsub8T1, IsaVersion.v80, InstFlags.Rd), + new(0xFBE00060, 0xFFF000F0, InstName.Umaal, T.UmaalT1, IsaVersion.v80, InstFlags.RdLoRdHi), + new(0xFBE00000, 0xFFF000F0, InstName.Umlal, T.UmlalT1, IsaVersion.v80, InstFlags.RdLoRdHi), + new(0xFBA00000, 0xFFF000F0, InstName.Umull, T.UmullT1, IsaVersion.v80, InstFlags.RdLoRdHi), + new(0xFA90F050, 0xFFF0F0F0, InstName.Uqadd16, T.Uqadd16T1, IsaVersion.v80, InstFlags.Rd), + new(0xFA80F050, 0xFFF0F0F0, InstName.Uqadd8, T.Uqadd8T1, IsaVersion.v80, InstFlags.Rd), + new(0xFAA0F050, 0xFFF0F0F0, InstName.Uqasx, T.UqasxT1, IsaVersion.v80, InstFlags.Rd), + new(0xFAE0F050, 0xFFF0F0F0, InstName.Uqsax, T.UqsaxT1, IsaVersion.v80, InstFlags.Rd), + new(0xFAD0F050, 0xFFF0F0F0, InstName.Uqsub16, T.Uqsub16T1, IsaVersion.v80, InstFlags.Rd), + new(0xFAC0F050, 0xFFF0F0F0, InstName.Uqsub8, T.Uqsub8T1, IsaVersion.v80, InstFlags.Rd), + new(0xFB70F000, 0xFFF0F0F0, InstName.Usad8, T.Usad8T1, IsaVersion.v80, InstFlags.Rd), + new(0xFB700000, 0xFFF000F0, raConstraints, InstName.Usada8, T.Usada8T1, IsaVersion.v80, InstFlags.Rd), + new(0xF3800000, 0xFFD08020, shimm2imm3Constraints, InstName.Usat, T.UsatT1, IsaVersion.v80, InstFlags.Rd), + new(0xF3A00000, 0xFFF0F0F0, InstName.Usat16, T.Usat16T1, IsaVersion.v80, InstFlags.Rd), + new(0xFAE0F040, 0xFFF0F0F0, InstName.Usax, T.UsaxT1, IsaVersion.v80, InstFlags.Rd), + new(0xFAD0F040, 0xFFF0F0F0, InstName.Usub16, T.Usub16T1, IsaVersion.v80, InstFlags.Rd), + new(0xFAC0F040, 0xFFF0F0F0, InstName.Usub8, T.Usub8T1, IsaVersion.v80, InstFlags.Rd), + new(0xFA50F080, 0xFFF0F0C0, rnConstraints, InstName.Uxtab, T.UxtabT1, IsaVersion.v80, InstFlags.Rd), + new(0xFA30F080, 0xFFF0F0C0, rnConstraints, InstName.Uxtab16, T.Uxtab16T1, IsaVersion.v80, InstFlags.Rd), + new(0xFA10F080, 0xFFF0F0C0, rnConstraints, InstName.Uxtah, T.UxtahT1, IsaVersion.v80, InstFlags.Rd), + new(0xFA5FF080, 0xFFFFF0C0, InstName.Uxtb, T.UxtbT2, IsaVersion.v80, InstFlags.Rd), + new(0xFA3FF080, 0xFFFFF0C0, InstName.Uxtb16, T.Uxtb16T1, IsaVersion.v80, InstFlags.Rd), + new(0xFA1FF080, 0xFFFFF0C0, InstName.Uxth, T.UxthT2, IsaVersion.v80, InstFlags.Rd), + new(0xEF000710, 0xEF800F10, sizeQvdQvnQvmConstraints, InstName.Vaba, T.VabaT1, IsaVersion.v80, InstFlags.None), + new(0xEF800500, 0xEF800F50, sizeVdConstraints, InstName.Vabal, T.VabalT1, IsaVersion.v80, InstFlags.None), + new(0xEF800700, 0xEF800F50, sizeVdConstraints, InstName.VabdlI, T.VabdlIT1, IsaVersion.v80, InstFlags.None), + new(0xFF200D00, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VabdF, T.VabdFT1, IsaVersion.v80, InstFlags.None), + new(0xFF300D00, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VabdF, T.VabdFT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEF000700, 0xEF800F10, sizeQvdQvnQvmConstraints, InstName.VabdI, T.VabdIT1, IsaVersion.v80, InstFlags.None), + new(0xFFB10300, 0xFFB30F90, sizeQvdQvmConstraints, InstName.Vabs, T.VabsT1, IsaVersion.v80, InstFlags.None), + new(0xFFB90700, 0xFFBB0F90, sizeQvdQvmConstraints, InstName.Vabs, T.VabsT1, IsaVersion.v80, InstFlags.None), + new(0xFFB50700, 0xFFBF0F90, sizeQvdQvmConstraints, InstName.Vabs, T.VabsT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEEB00AC0, 0xFFBF0ED0, InstName.Vabs, T.VabsT2, IsaVersion.v80, InstFlags.None), + new(0xEEB009C0, 0xFFBF0FD0, InstName.Vabs, T.VabsT2, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xFF000E10, 0xFFB00F10, qvdQvnQvmConstraints, InstName.Vacge, T.VacgeT1, IsaVersion.v80, InstFlags.None), + new(0xFF100E10, 0xFFB00F10, qvdQvnQvmConstraints, InstName.Vacge, T.VacgeT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xFF200E10, 0xFFB00F10, qvdQvnQvmConstraints, InstName.Vacgt, T.VacgtT1, IsaVersion.v80, InstFlags.None), + new(0xFF300E10, 0xFFB00F10, qvdQvnQvmConstraints, InstName.Vacgt, T.VacgtT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEF800400, 0xFF800F50, sizeVnVmConstraints, InstName.Vaddhn, T.VaddhnT1, IsaVersion.v80, InstFlags.None), + new(0xEF800000, 0xEF800F50, sizeVdOpvnConstraints, InstName.Vaddl, T.VaddlT1, IsaVersion.v80, InstFlags.None), + new(0xEF800100, 0xEF800F50, sizeVdOpvnConstraints, InstName.Vaddw, T.VaddwT1, IsaVersion.v80, InstFlags.None), + new(0xEF000D00, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VaddF, T.VaddFT1, IsaVersion.v80, InstFlags.None), + new(0xEF100D00, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VaddF, T.VaddFT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEE300A00, 0xFFB00E50, InstName.VaddF, T.VaddFT2, IsaVersion.v80, InstFlags.None), + new(0xEE300900, 0xFFB00F50, InstName.VaddF, T.VaddFT2, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEF000800, 0xFF800F10, qvdQvnQvmConstraints, InstName.VaddI, T.VaddIT1, IsaVersion.v80, InstFlags.None), + new(0xEF000110, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VandR, T.VandRT1, IsaVersion.v80, InstFlags.None), + new(0xEF800130, 0xEFB809B0, cmodeCmodeQvdConstraints, InstName.VbicI, T.VbicIT1, IsaVersion.v80, InstFlags.None), + new(0xEF800930, 0xEFB80DB0, cmodeCmodeQvdConstraints, InstName.VbicI, T.VbicIT2, IsaVersion.v80, InstFlags.None), + new(0xEF100110, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VbicR, T.VbicRT1, IsaVersion.v80, InstFlags.None), + new(0xFF300110, 0xFFB00F10, qvdQvnQvmOpConstraints, InstName.Vbif, T.VbifT1, IsaVersion.v80, InstFlags.None), + new(0xFF200110, 0xFFB00F10, qvdQvnQvmOpConstraints, InstName.Vbit, T.VbitT1, IsaVersion.v80, InstFlags.None), + new(0xFF100110, 0xFFB00F10, qvdQvnQvmOpConstraints, InstName.Vbsl, T.VbslT1, IsaVersion.v80, InstFlags.None), + new(0xFC900800, 0xFEB00F10, qvdQvnQvmConstraints, InstName.Vcadd, T.VcaddT1, IsaVersion.v83, IsaFeature.FeatFcma, InstFlags.None), + new(0xFC800800, 0xFEB00F10, qvdQvnQvmConstraints, InstName.Vcadd, T.VcaddT1, IsaVersion.v83, IsaFeature.FeatFcma | IsaFeature.FeatFp16, InstFlags.None), + new(0xFFB10100, 0xFFB30F90, sizeQvdQvmConstraints, InstName.VceqI, T.VceqIT1, IsaVersion.v80, InstFlags.None), + new(0xFFB90500, 0xFFBB0F90, sizeQvdQvmConstraints, InstName.VceqI, T.VceqIT1, IsaVersion.v80, InstFlags.None), + new(0xFFB50500, 0xFFBF0F90, sizeQvdQvmConstraints, InstName.VceqI, T.VceqIT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xFF000810, 0xFF800F10, qvdQvnQvmSizeConstraints, InstName.VceqR, T.VceqRT1, IsaVersion.v80, InstFlags.None), + new(0xEF000E00, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VceqR, T.VceqRT2, IsaVersion.v80, InstFlags.None), + new(0xEF100E00, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VceqR, T.VceqRT2, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xFFB10080, 0xFFB30F90, sizeQvdQvmConstraints, InstName.VcgeI, T.VcgeIT1, IsaVersion.v80, InstFlags.None), + new(0xFFB90480, 0xFFBB0F90, sizeQvdQvmConstraints, InstName.VcgeI, T.VcgeIT1, IsaVersion.v80, InstFlags.None), + new(0xFFB50480, 0xFFBF0F90, sizeQvdQvmConstraints, InstName.VcgeI, T.VcgeIT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEF000310, 0xEF800F10, qvdQvnQvmSizeConstraints, InstName.VcgeR, T.VcgeRT1, IsaVersion.v80, InstFlags.None), + new(0xFF000E00, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VcgeR, T.VcgeRT2, IsaVersion.v80, InstFlags.None), + new(0xFF100E00, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VcgeR, T.VcgeRT2, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xFFB10000, 0xFFB30F90, sizeQvdQvmConstraints, InstName.VcgtI, T.VcgtIT1, IsaVersion.v80, InstFlags.None), + new(0xFFB90400, 0xFFBB0F90, sizeQvdQvmConstraints, InstName.VcgtI, T.VcgtIT1, IsaVersion.v80, InstFlags.None), + new(0xFFB50400, 0xFFBF0F90, sizeQvdQvmConstraints, InstName.VcgtI, T.VcgtIT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEF000300, 0xEF800F10, qvdQvnQvmSizeConstraints, InstName.VcgtR, T.VcgtRT1, IsaVersion.v80, InstFlags.None), + new(0xFF200E00, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VcgtR, T.VcgtRT2, IsaVersion.v80, InstFlags.None), + new(0xFF300E00, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VcgtR, T.VcgtRT2, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xFFB10180, 0xFFB30F90, sizeQvdQvmConstraints, InstName.VcleI, T.VcleIT1, IsaVersion.v80, InstFlags.None), + new(0xFFB90580, 0xFFBB0F90, sizeQvdQvmConstraints, InstName.VcleI, T.VcleIT1, IsaVersion.v80, InstFlags.None), + new(0xFFB50580, 0xFFBF0F90, sizeQvdQvmConstraints, InstName.VcleI, T.VcleIT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xFFB00400, 0xFFB30F90, sizeQvdQvmConstraints, InstName.Vcls, T.VclsT1, IsaVersion.v80, InstFlags.None), + new(0xFFB10200, 0xFFB30F90, sizeQvdQvmConstraints, InstName.VcltI, T.VcltIT1, IsaVersion.v80, InstFlags.None), + new(0xFFB90600, 0xFFBB0F90, sizeQvdQvmConstraints, InstName.VcltI, T.VcltIT1, IsaVersion.v80, InstFlags.None), + new(0xFFB50600, 0xFFBF0F90, sizeQvdQvmConstraints, InstName.VcltI, T.VcltIT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xFFB00480, 0xFFB30F90, sizeQvdQvmConstraints, InstName.Vclz, T.VclzT1, IsaVersion.v80, InstFlags.None), + new(0xFC200800, 0xFE200F10, qvdQvnQvmConstraints, InstName.Vcmla, T.VcmlaT1, IsaVersion.v83, IsaFeature.FeatFcma, InstFlags.None), + new(0xFE000800, 0xFF000F10, qvdQvnConstraints, InstName.VcmlaS, T.VcmlaST1, IsaVersion.v83, IsaFeature.FeatFcma, InstFlags.None), + new(0xEEB40A40, 0xFFBF0ED0, InstName.Vcmp, T.VcmpT1, IsaVersion.v80, InstFlags.None), + new(0xEEB40940, 0xFFBF0FD0, InstName.Vcmp, T.VcmpT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEEB50A40, 0xFFBF0EFF, InstName.Vcmp, T.VcmpT2, IsaVersion.v80, InstFlags.None), + new(0xEEB50940, 0xFFBF0FFF, InstName.Vcmp, T.VcmpT2, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEEB40AC0, 0xFFBF0ED0, InstName.Vcmpe, T.VcmpeT1, IsaVersion.v80, InstFlags.None), + new(0xEEB409C0, 0xFFBF0FD0, InstName.Vcmpe, T.VcmpeT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEEB50AC0, 0xFFBF0EFF, InstName.Vcmpe, T.VcmpeT2, IsaVersion.v80, InstFlags.None), + new(0xEEB509C0, 0xFFBF0FFF, InstName.Vcmpe, T.VcmpeT2, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xFFB00500, 0xFFBF0F90, qvdQvmConstraints, InstName.Vcnt, T.VcntT1, IsaVersion.v80, InstFlags.None), + new(0xFFBB0000, 0xFFBF0F10, qvdQvmConstraints, InstName.VcvtaAsimd, T.VcvtaAsimdT1, IsaVersion.v80, InstFlags.None), + new(0xFFB70000, 0xFFBF0F10, qvdQvmConstraints, InstName.VcvtaAsimd, T.VcvtaAsimdT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xFEBC0A40, 0xFFBF0E50, sizeConstraints, InstName.VcvtaVfp, T.VcvtaVfpT1, IsaVersion.v80, InstFlags.None), + new(0xFEBC0940, 0xFFBF0F50, sizeConstraints, InstName.VcvtaVfp, T.VcvtaVfpT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEEB20A40, 0xFFBE0ED0, InstName.Vcvtb, T.VcvtbT1, IsaVersion.v80, InstFlags.None), + new(0xEEB30940, 0xFFBF0FD0, InstName.VcvtbBfs, T.VcvtbBfsT1, IsaVersion.v86, IsaFeature.FeatAa32bf16, InstFlags.None), + new(0xFFBB0300, 0xFFBF0F10, qvdQvmConstraints, InstName.VcvtmAsimd, T.VcvtmAsimdT1, IsaVersion.v80, InstFlags.None), + new(0xFFB70300, 0xFFBF0F10, qvdQvmConstraints, InstName.VcvtmAsimd, T.VcvtmAsimdT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xFEBF0A40, 0xFFBF0E50, sizeConstraints, InstName.VcvtmVfp, T.VcvtmVfpT1, IsaVersion.v80, InstFlags.None), + new(0xFEBF0940, 0xFFBF0F50, sizeConstraints, InstName.VcvtmVfp, T.VcvtmVfpT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xFFBB0100, 0xFFBF0F10, qvdQvmConstraints, InstName.VcvtnAsimd, T.VcvtnAsimdT1, IsaVersion.v80, InstFlags.None), + new(0xFFB70100, 0xFFBF0F10, qvdQvmConstraints, InstName.VcvtnAsimd, T.VcvtnAsimdT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xFEBD0A40, 0xFFBF0E50, sizeConstraints, InstName.VcvtnVfp, T.VcvtnVfpT1, IsaVersion.v80, InstFlags.None), + new(0xFEBD0940, 0xFFBF0F50, sizeConstraints, InstName.VcvtnVfp, T.VcvtnVfpT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xFFBB0200, 0xFFBF0F10, qvdQvmConstraints, InstName.VcvtpAsimd, T.VcvtpAsimdT1, IsaVersion.v80, InstFlags.None), + new(0xFFB70200, 0xFFBF0F10, qvdQvmConstraints, InstName.VcvtpAsimd, T.VcvtpAsimdT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xFEBE0A40, 0xFFBF0E50, sizeConstraints, InstName.VcvtpVfp, T.VcvtpVfpT1, IsaVersion.v80, InstFlags.None), + new(0xFEBE0940, 0xFFBF0F50, sizeConstraints, InstName.VcvtpVfp, T.VcvtpVfpT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEEBC0A40, 0xFFBE0ED0, InstName.VcvtrIv, T.VcvtrIvT1, IsaVersion.v80, InstFlags.None), + new(0xEEBC0940, 0xFFBE0FD0, InstName.VcvtrIv, T.VcvtrIvT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEEB20AC0, 0xFFBE0ED0, InstName.Vcvtt, T.VcvttT1, IsaVersion.v80, InstFlags.None), + new(0xEEB309C0, 0xFFBF0FD0, InstName.VcvttBfs, T.VcvttBfsT1, IsaVersion.v86, IsaFeature.FeatAa32bf16, InstFlags.None), + new(0xFFB60640, 0xFFBF0FD0, vmConstraints, InstName.VcvtBfs, T.VcvtBfsT1, IsaVersion.v86, IsaFeature.FeatAa32bf16, InstFlags.None), + new(0xEEB70AC0, 0xFFBF0ED0, InstName.VcvtDs, T.VcvtDsT1, IsaVersion.v80, InstFlags.None), + new(0xFFB60600, 0xFFBF0ED0, opvdOpvmConstraints, InstName.VcvtHs, T.VcvtHsT1, IsaVersion.v80, InstFlags.None), + new(0xFFBB0600, 0xFFBF0E10, qvdQvmConstraints, InstName.VcvtIs, T.VcvtIsT1, IsaVersion.v80, InstFlags.None), + new(0xFFB70600, 0xFFBF0E10, qvdQvmConstraints, InstName.VcvtIs, T.VcvtIsT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEEBC0AC0, 0xFFBE0ED0, InstName.VcvtIv, T.VcvtIvT1, IsaVersion.v80, InstFlags.None), + new(0xEEBC09C0, 0xFFBE0FD0, InstName.VcvtIv, T.VcvtIvT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEEB80A40, 0xFFBF0E50, InstName.VcvtVi, T.VcvtViT1, IsaVersion.v80, InstFlags.None), + new(0xEEB80940, 0xFFBF0F50, InstName.VcvtVi, T.VcvtViT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEF800E10, 0xEF800E90, imm6Opimm6Imm6QvdQvmConstraints, InstName.VcvtXs, T.VcvtXsT1, IsaVersion.v80, InstFlags.None), + new(0xEF800C10, 0xEF800E90, imm6Opimm6Imm6QvdQvmConstraints, InstName.VcvtXs, T.VcvtXsT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEEBA0A40, 0xFFBA0E50, InstName.VcvtXv, T.VcvtXvT1, IsaVersion.v80, InstFlags.None), + new(0xEEBA0940, 0xFFBA0F50, InstName.VcvtXv, T.VcvtXvT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEE800A00, 0xFFB00E50, InstName.Vdiv, T.VdivT1, IsaVersion.v80, InstFlags.None), + new(0xEE800900, 0xFFB00F50, InstName.Vdiv, T.VdivT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xFC000D00, 0xFFB00F10, qvdQvnQvmConstraints, InstName.Vdot, T.VdotT1, IsaVersion.v86, IsaFeature.FeatAa32bf16, InstFlags.None), + new(0xFE000D00, 0xFFB00F10, qvdQvnConstraints, InstName.VdotS, T.VdotST1, IsaVersion.v86, IsaFeature.FeatAa32bf16, InstFlags.None), + new(0xEE800B10, 0xFF900F5F, qvdEbConstraints, InstName.VdupR, T.VdupRT1, IsaVersion.v80, InstFlags.RtRead), + new(0xFFB00C00, 0xFFB00F90, imm4QvdConstraints, InstName.VdupS, T.VdupST1, IsaVersion.v80, InstFlags.None), + new(0xFF000110, 0xFFB00F10, qvdQvnQvmConstraints, InstName.Veor, T.VeorT1, IsaVersion.v80, InstFlags.None), + new(0xEFB00000, 0xFFB00010, qvdQvnQvmQimm4Constraints, InstName.Vext, T.VextT1, IsaVersion.v80, InstFlags.None), + new(0xEF000C10, 0xFFB00F10, qvdQvnQvmConstraints, InstName.Vfma, T.VfmaT1, IsaVersion.v80, InstFlags.None), + new(0xEF100C10, 0xFFB00F10, qvdQvnQvmConstraints, InstName.Vfma, T.VfmaT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEEA00A00, 0xFFB00E50, InstName.Vfma, T.VfmaT2, IsaVersion.v80, InstFlags.None), + new(0xEEA00900, 0xFFB00F50, InstName.Vfma, T.VfmaT2, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xFC200810, 0xFFB00F10, qvdConstraints, InstName.Vfmal, T.VfmalT1, IsaVersion.v82, IsaFeature.FeatFhm, InstFlags.None), + new(0xFE000810, 0xFFB00F10, qvdConstraints, InstName.VfmalS, T.VfmalST1, IsaVersion.v82, IsaFeature.FeatFhm, InstFlags.None), + new(0xFC300810, 0xFFB00F10, vdVnVmConstraints, InstName.VfmaBf, T.VfmaBfT1, IsaVersion.v86, IsaFeature.FeatAa32bf16, InstFlags.None), + new(0xFE300810, 0xFFB00F10, vdVnConstraints, InstName.VfmaBfs, T.VfmaBfsT1, IsaVersion.v86, IsaFeature.FeatAa32bf16, InstFlags.None), + new(0xEF200C10, 0xFFB00F10, qvdQvnQvmConstraints, InstName.Vfms, T.VfmsT1, IsaVersion.v80, InstFlags.None), + new(0xEF300C10, 0xFFB00F10, qvdQvnQvmConstraints, InstName.Vfms, T.VfmsT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEEA00A40, 0xFFB00E50, InstName.Vfms, T.VfmsT2, IsaVersion.v80, InstFlags.None), + new(0xEEA00940, 0xFFB00F50, InstName.Vfms, T.VfmsT2, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xFCA00810, 0xFFB00F10, qvdConstraints, InstName.Vfmsl, T.VfmslT1, IsaVersion.v82, IsaFeature.FeatFhm, InstFlags.None), + new(0xFE100810, 0xFFB00F10, qvdConstraints, InstName.VfmslS, T.VfmslST1, IsaVersion.v82, IsaFeature.FeatFhm, InstFlags.None), + new(0xEE900A40, 0xFFB00E50, InstName.Vfnma, T.VfnmaT1, IsaVersion.v80, InstFlags.None), + new(0xEE900940, 0xFFB00F50, InstName.Vfnma, T.VfnmaT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEE900A00, 0xFFB00E50, InstName.Vfnms, T.VfnmsT1, IsaVersion.v80, InstFlags.None), + new(0xEE900900, 0xFFB00F50, InstName.Vfnms, T.VfnmsT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEF000000, 0xEF800F10, qvdQvnQvmSizeConstraints, InstName.Vhadd, T.VhaddT1, IsaVersion.v80, InstFlags.None), + new(0xEF000200, 0xEF800F10, qvdQvnQvmSizeConstraints, InstName.Vhsub, T.VhsubT1, IsaVersion.v80, InstFlags.None), + new(0xFEB00AC0, 0xFFBF0FD0, InstName.Vins, T.VinsT1, IsaVersion.v82, IsaFeature.FeatFp16, InstFlags.None), + new(0xEEB90BC0, 0xFFBF0FD0, InstName.Vjcvt, T.VjcvtT1, IsaVersion.v83, IsaFeature.FeatJscvt, InstFlags.None), + new(0xF9A00000, 0xFFB00F10, sizeConstraints2, InstName.Vld11, T.Vld11T1, IsaVersion.v80, InstFlags.None), + new(0xF9A00400, 0xFFB00F20, sizeConstraints2, InstName.Vld11, T.Vld11T2, IsaVersion.v80, InstFlags.None), + new(0xF9A00800, 0xFFB00F40, sizeIndexAlignIndexAlignConstraints, InstName.Vld11, T.Vld11T3, IsaVersion.v80, InstFlags.None), + new(0xF9A00C00, 0xFFB00F00, sizeSizeaConstraints, InstName.Vld1A, T.Vld1AT1, IsaVersion.v80, InstFlags.None), + new(0xF9200700, 0xFFB00F00, alignConstraints, InstName.Vld1M, T.Vld1MT1, IsaVersion.v80, InstFlags.None), + new(0xF9200A00, 0xFFB00F00, alignConstraints2, InstName.Vld1M, T.Vld1MT2, IsaVersion.v80, InstFlags.None), + new(0xF9200600, 0xFFB00F00, alignConstraints, InstName.Vld1M, T.Vld1MT3, IsaVersion.v80, InstFlags.None), + new(0xF9200200, 0xFFB00F00, InstName.Vld1M, T.Vld1MT4, IsaVersion.v80, InstFlags.None), + new(0xF9A00100, 0xFFB00F00, sizeConstraints2, InstName.Vld21, T.Vld21T1, IsaVersion.v80, InstFlags.None), + new(0xF9A00500, 0xFFB00F00, sizeConstraints2, InstName.Vld21, T.Vld21T2, IsaVersion.v80, InstFlags.None), + new(0xF9A00900, 0xFFB00F20, sizeConstraints2, InstName.Vld21, T.Vld21T3, IsaVersion.v80, InstFlags.None), + new(0xF9A00D00, 0xFFB00F00, sizeConstraints3, InstName.Vld2A, T.Vld2AT1, IsaVersion.v80, InstFlags.None), + new(0xF9200800, 0xFFB00E00, alignSizeConstraints, InstName.Vld2M, T.Vld2MT1, IsaVersion.v80, InstFlags.None), + new(0xF9200300, 0xFFB00F00, sizeConstraints3, InstName.Vld2M, T.Vld2MT2, IsaVersion.v80, InstFlags.None), + new(0xF9A00200, 0xFFB00F10, sizeConstraints2, InstName.Vld31, T.Vld31T1, IsaVersion.v80, InstFlags.None), + new(0xF9A00600, 0xFFB00F10, sizeConstraints2, InstName.Vld31, T.Vld31T2, IsaVersion.v80, InstFlags.None), + new(0xF9A00A00, 0xFFB00F30, sizeConstraints2, InstName.Vld31, T.Vld31T3, IsaVersion.v80, InstFlags.None), + new(0xF9A00E00, 0xFFB00F10, sizeAConstraints, InstName.Vld3A, T.Vld3AT1, IsaVersion.v80, InstFlags.None), + new(0xF9200400, 0xFFB00E00, sizeAlignConstraints, InstName.Vld3M, T.Vld3MT1, IsaVersion.v80, InstFlags.None), + new(0xF9A00300, 0xFFB00F00, sizeConstraints2, InstName.Vld41, T.Vld41T1, IsaVersion.v80, InstFlags.None), + new(0xF9A00700, 0xFFB00F00, sizeConstraints2, InstName.Vld41, T.Vld41T2, IsaVersion.v80, InstFlags.None), + new(0xF9A00B00, 0xFFB00F00, sizeIndexAlignConstraints, InstName.Vld41, T.Vld41T3, IsaVersion.v80, InstFlags.None), + new(0xF9A00F00, 0xFFB00F00, sizeaConstraints, InstName.Vld4A, T.Vld4AT1, IsaVersion.v80, InstFlags.None), + new(0xF9200000, 0xFFB00E00, sizeConstraints3, InstName.Vld4M, T.Vld4MT1, IsaVersion.v80, InstFlags.None), + new(0xEC100B00, 0xFE100F01, puwPwPuwPuwConstraints, InstName.Vldm, T.VldmT1, IsaVersion.v80, InstFlags.WBack), + new(0xEC100A00, 0xFE100F00, puwPwPuwPuwConstraints, InstName.Vldm, T.VldmT2, IsaVersion.v80, InstFlags.WBack), + new(0xED100A00, 0xFF300E00, rnConstraints, InstName.VldrI, T.VldrIT1, IsaVersion.v80, InstFlags.None), + new(0xED100900, 0xFF300F00, rnConstraints, InstName.VldrI, T.VldrIT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xED1F0A00, 0xFF3F0E00, InstName.VldrL, T.VldrLT1, IsaVersion.v80, InstFlags.None), + new(0xED1F0900, 0xFF3F0F00, InstName.VldrL, T.VldrLT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xFF000F10, 0xFFB00F10, qvdQvnQvmConstraints, InstName.Vmaxnm, T.VmaxnmT1, IsaVersion.v80, InstFlags.None), + new(0xFF100F10, 0xFFB00F10, qvdQvnQvmConstraints, InstName.Vmaxnm, T.VmaxnmT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xFE800A00, 0xFFB00E50, sizeConstraints, InstName.Vmaxnm, T.VmaxnmT2, IsaVersion.v80, InstFlags.None), + new(0xFE800900, 0xFFB00F50, sizeConstraints, InstName.Vmaxnm, T.VmaxnmT2, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEF000F00, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VmaxF, T.VmaxFT1, IsaVersion.v80, InstFlags.None), + new(0xEF100F00, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VmaxF, T.VmaxFT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEF000600, 0xEF800F10, qvdQvnQvmSizeConstraints, InstName.VmaxI, T.VmaxIT1, IsaVersion.v80, InstFlags.None), + new(0xFF200F10, 0xFFB00F10, qvdQvnQvmConstraints, InstName.Vminnm, T.VminnmT1, IsaVersion.v80, InstFlags.None), + new(0xFF300F10, 0xFFB00F10, qvdQvnQvmConstraints, InstName.Vminnm, T.VminnmT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xFE800A40, 0xFFB00E50, sizeConstraints, InstName.Vminnm, T.VminnmT2, IsaVersion.v80, InstFlags.None), + new(0xFE800940, 0xFFB00F50, sizeConstraints, InstName.Vminnm, T.VminnmT2, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEF200F00, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VminF, T.VminFT1, IsaVersion.v80, InstFlags.None), + new(0xEF300F00, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VminF, T.VminFT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEF000610, 0xEF800F10, qvdQvnQvmSizeConstraints, InstName.VminI, T.VminIT1, IsaVersion.v80, InstFlags.None), + new(0xEF800800, 0xEF800F50, sizeVdConstraints, InstName.VmlalI, T.VmlalIT1, IsaVersion.v80, InstFlags.None), + new(0xEF800240, 0xEF800F50, sizeSizeVdConstraints, InstName.VmlalS, T.VmlalST1, IsaVersion.v80, InstFlags.None), + new(0xEF000D10, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VmlaF, T.VmlaFT1, IsaVersion.v80, InstFlags.None), + new(0xEF100D10, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VmlaF, T.VmlaFT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEE000A00, 0xFFB00E50, InstName.VmlaF, T.VmlaFT2, IsaVersion.v80, InstFlags.None), + new(0xEE000900, 0xFFB00F50, InstName.VmlaF, T.VmlaFT2, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEF000900, 0xFF800F10, sizeQvdQvnQvmConstraints, InstName.VmlaI, T.VmlaIT1, IsaVersion.v80, InstFlags.None), + new(0xEFA00040, 0xEFA00E50, sizeQvdQvnConstraints, InstName.VmlaS, T.VmlaST1, IsaVersion.v80, InstFlags.None), + new(0xEF900040, 0xEFB00F50, sizeQvdQvnConstraints, InstName.VmlaS, T.VmlaST1, IsaVersion.v80, InstFlags.None), + new(0xEF900140, 0xEFB00F50, sizeQvdQvnConstraints, InstName.VmlaS, T.VmlaST1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEF800A00, 0xEF800F50, sizeVdConstraints, InstName.VmlslI, T.VmlslIT1, IsaVersion.v80, InstFlags.None), + new(0xEF800640, 0xEF800F50, sizeSizeVdConstraints, InstName.VmlslS, T.VmlslST1, IsaVersion.v80, InstFlags.None), + new(0xEF200D10, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VmlsF, T.VmlsFT1, IsaVersion.v80, InstFlags.None), + new(0xEF300D10, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VmlsF, T.VmlsFT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEE000A40, 0xFFB00E50, InstName.VmlsF, T.VmlsFT2, IsaVersion.v80, InstFlags.None), + new(0xEE000940, 0xFFB00F50, InstName.VmlsF, T.VmlsFT2, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xFF000900, 0xFF800F10, sizeQvdQvnQvmConstraints, InstName.VmlsI, T.VmlsIT1, IsaVersion.v80, InstFlags.None), + new(0xEFA00440, 0xEFA00E50, sizeQvdQvnConstraints, InstName.VmlsS, T.VmlsST1, IsaVersion.v80, InstFlags.None), + new(0xEF900440, 0xEFB00F50, sizeQvdQvnConstraints, InstName.VmlsS, T.VmlsST1, IsaVersion.v80, InstFlags.None), + new(0xEF900540, 0xEFB00F50, sizeQvdQvnConstraints, InstName.VmlsS, T.VmlsST1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xFC000C40, 0xFFB00F50, vdVnVmConstraints, InstName.Vmmla, T.VmmlaT1, IsaVersion.v86, IsaFeature.FeatAa32bf16, InstFlags.None), + new(0xEF800A10, 0xEF870FD0, imm3hImm3hImm3hImm3hImm3hVdConstraints, InstName.Vmovl, T.VmovlT1, IsaVersion.v80, InstFlags.None), + new(0xFFB20200, 0xFFB30FD0, sizeVmConstraints, InstName.Vmovn, T.VmovnT1, IsaVersion.v80, InstFlags.None), + new(0xFEB00A40, 0xFFBF0FD0, InstName.Vmovx, T.VmovxT1, IsaVersion.v82, IsaFeature.FeatFp16, InstFlags.None), + new(0xEC400B10, 0xFFE00FD0, InstName.VmovD, T.VmovDT1, IsaVersion.v80, InstFlags.Rt2Read), + new(0xEE000910, 0xFFE00F7F, InstName.VmovH, T.VmovHT1, IsaVersion.v82, IsaFeature.FeatFp16, InstFlags.Rt), + new(0xEF800010, 0xEFB809B0, qvdConstraints, InstName.VmovI, T.VmovIT1, IsaVersion.v80, InstFlags.None), + new(0xEEB00A00, 0xFFB00EF0, InstName.VmovI, T.VmovIT2, IsaVersion.v80, InstFlags.None), + new(0xEEB00900, 0xFFB00FF0, InstName.VmovI, T.VmovIT2, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEF800810, 0xEFB80DB0, qvdConstraints, InstName.VmovI, T.VmovIT3, IsaVersion.v80, InstFlags.None), + new(0xEF800C10, 0xEFB80CB0, qvdConstraints, InstName.VmovI, T.VmovIT4, IsaVersion.v80, InstFlags.None), + new(0xEF800E30, 0xEFB80FB0, qvdConstraints, InstName.VmovI, T.VmovIT5, IsaVersion.v80, InstFlags.None), + new(0xEEB00A40, 0xFFBF0ED0, InstName.VmovR, T.VmovRT2, IsaVersion.v80, InstFlags.None), + new(0xEE000B10, 0xFF900F1F, opc1opc2Constraints, InstName.VmovRs, T.VmovRsT1, IsaVersion.v80, InstFlags.RtRead), + new(0xEE000A10, 0xFFE00F7F, InstName.VmovS, T.VmovST1, IsaVersion.v80, InstFlags.RtRead), + new(0xEE100B10, 0xFF100F1F, uopc1opc2Uopc1opc2Constraints, InstName.VmovSr, T.VmovSrT1, IsaVersion.v80, InstFlags.Rt), + new(0xEC400A10, 0xFFE00FD0, InstName.VmovSs, T.VmovSsT1, IsaVersion.v80, InstFlags.Rt2Read), + new(0xEEF00A10, 0xFFF00FFF, InstName.Vmrs, T.VmrsT1, IsaVersion.v80, InstFlags.Rt), + new(0xEEE00A10, 0xFFF00FFF, InstName.Vmsr, T.VmsrT1, IsaVersion.v80, InstFlags.RtRead), + new(0xEF800C00, 0xEF800D50, sizeOpuOpsizeVdConstraints, InstName.VmullI, T.VmullIT1, IsaVersion.v80, InstFlags.None), + new(0xEF800A40, 0xEF800F50, sizeSizeVdConstraints, InstName.VmullS, T.VmullST1, IsaVersion.v80, InstFlags.None), + new(0xFF000D10, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VmulF, T.VmulFT1, IsaVersion.v80, InstFlags.None), + new(0xFF100D10, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VmulF, T.VmulFT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEE200A00, 0xFFB00E50, InstName.VmulF, T.VmulFT2, IsaVersion.v80, InstFlags.None), + new(0xEE200900, 0xFFB00F50, InstName.VmulF, T.VmulFT2, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEF000910, 0xEF800F10, sizeOpsizeOpsizeQvdQvnQvmConstraints, InstName.VmulI, T.VmulIT1, IsaVersion.v80, InstFlags.None), + new(0xEFA00840, 0xEFA00E50, sizeQvdQvnConstraints, InstName.VmulS, T.VmulST1, IsaVersion.v80, InstFlags.None), + new(0xEF900840, 0xEFB00F50, sizeQvdQvnConstraints, InstName.VmulS, T.VmulST1, IsaVersion.v80, InstFlags.None), + new(0xEF900940, 0xEFB00F50, sizeQvdQvnConstraints, InstName.VmulS, T.VmulST1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEF800030, 0xEFB809B0, cmodeQvdConstraints, InstName.VmvnI, T.VmvnIT1, IsaVersion.v80, InstFlags.None), + new(0xEF800830, 0xEFB80DB0, cmodeQvdConstraints, InstName.VmvnI, T.VmvnIT2, IsaVersion.v80, InstFlags.None), + new(0xEF800C30, 0xEFB80EB0, cmodeQvdConstraints, InstName.VmvnI, T.VmvnIT3, IsaVersion.v80, InstFlags.None), + new(0xFFB00580, 0xFFBF0F90, qvdQvmConstraints, InstName.VmvnR, T.VmvnRT1, IsaVersion.v80, InstFlags.None), + new(0xFFB10380, 0xFFB30F90, sizeQvdQvmConstraints, InstName.Vneg, T.VnegT1, IsaVersion.v80, InstFlags.None), + new(0xFFB90780, 0xFFBB0F90, sizeQvdQvmConstraints, InstName.Vneg, T.VnegT1, IsaVersion.v80, InstFlags.None), + new(0xFFB50780, 0xFFBF0F90, sizeQvdQvmConstraints, InstName.Vneg, T.VnegT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEEB10A40, 0xFFBF0ED0, InstName.Vneg, T.VnegT2, IsaVersion.v80, InstFlags.None), + new(0xEEB10940, 0xFFBF0FD0, InstName.Vneg, T.VnegT2, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEE100A40, 0xFFB00E50, InstName.Vnmla, T.VnmlaT1, IsaVersion.v80, InstFlags.None), + new(0xEE100940, 0xFFB00F50, InstName.Vnmla, T.VnmlaT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEE100A00, 0xFFB00E50, InstName.Vnmls, T.VnmlsT1, IsaVersion.v80, InstFlags.None), + new(0xEE100900, 0xFFB00F50, InstName.Vnmls, T.VnmlsT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEE200A40, 0xFFB00E50, InstName.Vnmul, T.VnmulT1, IsaVersion.v80, InstFlags.None), + new(0xEE200940, 0xFFB00F50, InstName.Vnmul, T.VnmulT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEF300110, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VornR, T.VornRT1, IsaVersion.v80, InstFlags.None), + new(0xEF800110, 0xEFB809B0, cmodeCmodeQvdConstraints, InstName.VorrI, T.VorrIT1, IsaVersion.v80, InstFlags.None), + new(0xEF800910, 0xEFB80DB0, cmodeCmodeQvdConstraints, InstName.VorrI, T.VorrIT2, IsaVersion.v80, InstFlags.None), + new(0xEF200110, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VorrR, T.VorrRT1, IsaVersion.v80, InstFlags.None), + new(0xFFB00600, 0xFFB30F10, sizeQvdQvmConstraints, InstName.Vpadal, T.VpadalT1, IsaVersion.v80, InstFlags.None), + new(0xFFB00200, 0xFFB30F10, sizeQvdQvmConstraints, InstName.Vpaddl, T.VpaddlT1, IsaVersion.v80, InstFlags.None), + new(0xFF000D00, 0xFFB00F10, qConstraints, InstName.VpaddF, T.VpaddFT1, IsaVersion.v80, InstFlags.None), + new(0xFF100D00, 0xFFB00F10, qConstraints, InstName.VpaddF, T.VpaddFT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEF000B10, 0xFF800F10, sizeQConstraints, InstName.VpaddI, T.VpaddIT1, IsaVersion.v80, InstFlags.None), + new(0xFF000F00, 0xFFB00F50, InstName.VpmaxF, T.VpmaxFT1, IsaVersion.v80, InstFlags.None), + new(0xFF100F00, 0xFFB00F50, InstName.VpmaxF, T.VpmaxFT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEF000A00, 0xEF800F50, sizeConstraints4, InstName.VpmaxI, T.VpmaxIT1, IsaVersion.v80, InstFlags.None), + new(0xFF200F00, 0xFFB00F50, InstName.VpminF, T.VpminFT1, IsaVersion.v80, InstFlags.None), + new(0xFF300F00, 0xFFB00F50, InstName.VpminF, T.VpminFT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEF000A10, 0xEF800F50, sizeConstraints4, InstName.VpminI, T.VpminIT1, IsaVersion.v80, InstFlags.None), + new(0xFFB00700, 0xFFB30F90, sizeQvdQvmConstraints, InstName.Vqabs, T.VqabsT1, IsaVersion.v80, InstFlags.None), + new(0xEF000010, 0xEF800F10, qvdQvnQvmConstraints, InstName.Vqadd, T.VqaddT1, IsaVersion.v80, InstFlags.None), + new(0xEF800900, 0xFF800F50, sizeSizeVdConstraints, InstName.Vqdmlal, T.VqdmlalT1, IsaVersion.v80, InstFlags.None), + new(0xEF800340, 0xFF800F50, sizeSizeVdConstraints, InstName.Vqdmlal, T.VqdmlalT2, IsaVersion.v80, InstFlags.None), + new(0xEF800B00, 0xFF800F50, sizeSizeVdConstraints, InstName.Vqdmlsl, T.VqdmlslT1, IsaVersion.v80, InstFlags.None), + new(0xEF800740, 0xFF800F50, sizeSizeVdConstraints, InstName.Vqdmlsl, T.VqdmlslT2, IsaVersion.v80, InstFlags.None), + new(0xEF000B00, 0xFF800F10, qvdQvnQvmSizeSizeConstraints, InstName.Vqdmulh, T.VqdmulhT1, IsaVersion.v80, InstFlags.None), + new(0xEF800C40, 0xEF800F50, sizeSizeQvdQvnConstraints, InstName.Vqdmulh, T.VqdmulhT2, IsaVersion.v80, InstFlags.None), + new(0xEF800D00, 0xFF800F50, sizeSizeVdConstraints, InstName.Vqdmull, T.VqdmullT1, IsaVersion.v80, InstFlags.None), + new(0xEF800B40, 0xFF800F50, sizeSizeVdConstraints, InstName.Vqdmull, T.VqdmullT2, IsaVersion.v80, InstFlags.None), + new(0xFFB20200, 0xFFB30F10, opSizeVmConstraints, InstName.Vqmovn, T.VqmovnT1, IsaVersion.v80, InstFlags.None), + new(0xFFB00780, 0xFFB30F90, sizeQvdQvmConstraints, InstName.Vqneg, T.VqnegT1, IsaVersion.v80, InstFlags.None), + new(0xFF000B10, 0xFF800F10, qvdQvnQvmSizeSizeConstraints, InstName.Vqrdmlah, T.VqrdmlahT1, IsaVersion.v81, IsaFeature.FeatRdm, InstFlags.None), + new(0xEF800E40, 0xEF800F50, sizeSizeQvdQvnConstraints, InstName.Vqrdmlah, T.VqrdmlahT2, IsaVersion.v81, IsaFeature.FeatRdm, InstFlags.None), + new(0xFF000C10, 0xFF800F10, qvdQvnQvmSizeSizeConstraints, InstName.Vqrdmlsh, T.VqrdmlshT1, IsaVersion.v81, IsaFeature.FeatRdm, InstFlags.None), + new(0xEF800F40, 0xEF800F50, sizeSizeQvdQvnConstraints, InstName.Vqrdmlsh, T.VqrdmlshT2, IsaVersion.v81, IsaFeature.FeatRdm, InstFlags.None), + new(0xFF000B00, 0xFF800F10, qvdQvnQvmSizeSizeConstraints, InstName.Vqrdmulh, T.VqrdmulhT1, IsaVersion.v80, InstFlags.None), + new(0xEF800D40, 0xEF800F50, sizeSizeQvdQvnConstraints, InstName.Vqrdmulh, T.VqrdmulhT2, IsaVersion.v80, InstFlags.None), + new(0xEF000510, 0xEF800F10, qvdQvmQvnConstraints, InstName.Vqrshl, T.VqrshlT1, IsaVersion.v80, InstFlags.None), + new(0xEF800850, 0xEF800ED0, imm6UopVmConstraints, InstName.Vqrshrn, T.VqrshrnT1, IsaVersion.v80, InstFlags.None), + new(0xEF800610, 0xEF800E10, imm6lUopQvdQvmConstraints, InstName.VqshlI, T.VqshlIT1, IsaVersion.v80, InstFlags.None), + new(0xEF000410, 0xEF800F10, qvdQvmQvnConstraints, InstName.VqshlR, T.VqshlRT1, IsaVersion.v80, InstFlags.None), + new(0xEF800810, 0xEF800ED0, imm6UopVmConstraints, InstName.Vqshrn, T.VqshrnT1, IsaVersion.v80, InstFlags.None), + new(0xEF000210, 0xEF800F10, qvdQvnQvmConstraints, InstName.Vqsub, T.VqsubT1, IsaVersion.v80, InstFlags.None), + new(0xFF800400, 0xFF800F50, sizeVnVmConstraints, InstName.Vraddhn, T.VraddhnT1, IsaVersion.v80, InstFlags.None), + new(0xFFB30400, 0xFFB30E90, qvdQvmSizeSizeConstraints, InstName.Vrecpe, T.VrecpeT1, IsaVersion.v80, InstFlags.None), + new(0xEF000F10, 0xFFB00F10, qvdQvnQvmConstraints, InstName.Vrecps, T.VrecpsT1, IsaVersion.v80, InstFlags.None), + new(0xEF100F10, 0xFFB00F10, qvdQvnQvmConstraints, InstName.Vrecps, T.VrecpsT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xFFB00100, 0xFFB30F90, sizeSizeSizeQvdQvmConstraints, InstName.Vrev16, T.Vrev16T1, IsaVersion.v80, InstFlags.None), + new(0xFFB00080, 0xFFB30F90, sizeSizeQvdQvmConstraints, InstName.Vrev32, T.Vrev32T1, IsaVersion.v80, InstFlags.None), + new(0xFFB00000, 0xFFB30F90, sizeQvdQvmConstraints, InstName.Vrev64, T.Vrev64T1, IsaVersion.v80, InstFlags.None), + new(0xEF000100, 0xEF800F10, qvdQvnQvmSizeConstraints, InstName.Vrhadd, T.VrhaddT1, IsaVersion.v80, InstFlags.None), + new(0xFFBA0500, 0xFFBF0F90, qvdQvmConstraints, InstName.VrintaAsimd, T.VrintaAsimdT1, IsaVersion.v80, InstFlags.None), + new(0xFFB60500, 0xFFBF0F90, qvdQvmConstraints, InstName.VrintaAsimd, T.VrintaAsimdT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xFEB80A40, 0xFFBF0ED0, sizeConstraints, InstName.VrintaVfp, T.VrintaVfpT1, IsaVersion.v80, InstFlags.None), + new(0xFEB80940, 0xFFBF0FD0, sizeConstraints, InstName.VrintaVfp, T.VrintaVfpT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xFFBA0680, 0xFFBF0F90, qvdQvmConstraints, InstName.VrintmAsimd, T.VrintmAsimdT1, IsaVersion.v80, InstFlags.None), + new(0xFFB60680, 0xFFBF0F90, qvdQvmConstraints, InstName.VrintmAsimd, T.VrintmAsimdT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xFEBB0A40, 0xFFBF0ED0, sizeConstraints, InstName.VrintmVfp, T.VrintmVfpT1, IsaVersion.v80, InstFlags.None), + new(0xFEBB0940, 0xFFBF0FD0, sizeConstraints, InstName.VrintmVfp, T.VrintmVfpT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xFFBA0400, 0xFFBF0F90, qvdQvmConstraints, InstName.VrintnAsimd, T.VrintnAsimdT1, IsaVersion.v80, InstFlags.None), + new(0xFFB60400, 0xFFBF0F90, qvdQvmConstraints, InstName.VrintnAsimd, T.VrintnAsimdT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xFEB90A40, 0xFFBF0ED0, sizeConstraints, InstName.VrintnVfp, T.VrintnVfpT1, IsaVersion.v80, InstFlags.None), + new(0xFEB90940, 0xFFBF0FD0, sizeConstraints, InstName.VrintnVfp, T.VrintnVfpT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xFFBA0780, 0xFFBF0F90, qvdQvmConstraints, InstName.VrintpAsimd, T.VrintpAsimdT1, IsaVersion.v80, InstFlags.None), + new(0xFFB60780, 0xFFBF0F90, qvdQvmConstraints, InstName.VrintpAsimd, T.VrintpAsimdT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xFEBA0A40, 0xFFBF0ED0, sizeConstraints, InstName.VrintpVfp, T.VrintpVfpT1, IsaVersion.v80, InstFlags.None), + new(0xFEBA0940, 0xFFBF0FD0, sizeConstraints, InstName.VrintpVfp, T.VrintpVfpT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEEB60A40, 0xFFBF0ED0, InstName.VrintrVfp, T.VrintrVfpT1, IsaVersion.v80, InstFlags.None), + new(0xEEB60940, 0xFFBF0FD0, InstName.VrintrVfp, T.VrintrVfpT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xFFBA0480, 0xFFBF0F90, qvdQvmConstraints, InstName.VrintxAsimd, T.VrintxAsimdT1, IsaVersion.v80, InstFlags.None), + new(0xFFB60480, 0xFFBF0F90, qvdQvmConstraints, InstName.VrintxAsimd, T.VrintxAsimdT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEEB70A40, 0xFFBF0ED0, InstName.VrintxVfp, T.VrintxVfpT1, IsaVersion.v80, InstFlags.None), + new(0xEEB70940, 0xFFBF0FD0, InstName.VrintxVfp, T.VrintxVfpT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xFFBA0580, 0xFFBF0F90, qvdQvmConstraints, InstName.VrintzAsimd, T.VrintzAsimdT1, IsaVersion.v80, InstFlags.None), + new(0xFFB60580, 0xFFBF0F90, qvdQvmConstraints, InstName.VrintzAsimd, T.VrintzAsimdT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEEB60AC0, 0xFFBF0ED0, InstName.VrintzVfp, T.VrintzVfpT1, IsaVersion.v80, InstFlags.None), + new(0xEEB609C0, 0xFFBF0FD0, InstName.VrintzVfp, T.VrintzVfpT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEF000500, 0xEF800F10, qvdQvmQvnConstraints, InstName.Vrshl, T.VrshlT1, IsaVersion.v80, InstFlags.None), + new(0xEF800210, 0xEF800F10, imm6lQvdQvmConstraints, InstName.Vrshr, T.VrshrT1, IsaVersion.v80, InstFlags.None), + new(0xEF800850, 0xFF800FD0, imm6VmConstraints, InstName.Vrshrn, T.VrshrnT1, IsaVersion.v80, InstFlags.None), + new(0xFFB30480, 0xFFB30E90, qvdQvmSizeSizeConstraints, InstName.Vrsqrte, T.VrsqrteT1, IsaVersion.v80, InstFlags.None), + new(0xEF200F10, 0xFFB00F10, qvdQvnQvmConstraints, InstName.Vrsqrts, T.VrsqrtsT1, IsaVersion.v80, InstFlags.None), + new(0xEF300F10, 0xFFB00F10, qvdQvnQvmConstraints, InstName.Vrsqrts, T.VrsqrtsT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEF800310, 0xEF800F10, imm6lQvdQvmConstraints, InstName.Vrsra, T.VrsraT1, IsaVersion.v80, InstFlags.None), + new(0xFF800600, 0xFF800F50, sizeVnVmConstraints, InstName.Vrsubhn, T.VrsubhnT1, IsaVersion.v80, InstFlags.None), + new(0xFC200D00, 0xFFB00F10, qvdQvnQvmConstraints, InstName.Vsdot, T.VsdotT1, IsaVersion.v82, IsaFeature.FeatDotprod, InstFlags.None), + new(0xFE200D00, 0xFFB00F10, qvdQvnConstraints, InstName.VsdotS, T.VsdotST1, IsaVersion.v82, IsaFeature.FeatDotprod, InstFlags.None), + new(0xFE000A00, 0xFF800E50, sizeConstraints, InstName.Vsel, T.VselT1, IsaVersion.v80, InstFlags.None), + new(0xFE000900, 0xFF800F50, sizeConstraints, InstName.Vsel, T.VselT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEF800A10, 0xEF800FD0, imm6VdImm6Imm6Imm6Constraints, InstName.Vshll, T.VshllT1, IsaVersion.v80, InstFlags.None), + new(0xFFB20300, 0xFFB30FD0, sizeVdConstraints2, InstName.Vshll, T.VshllT2, IsaVersion.v80, InstFlags.None), + new(0xEF800510, 0xFF800F10, imm6lQvdQvmConstraints, InstName.VshlI, T.VshlIT1, IsaVersion.v80, InstFlags.None), + new(0xEF000400, 0xEF800F10, qvdQvmQvnConstraints, InstName.VshlR, T.VshlRT1, IsaVersion.v80, InstFlags.None), + new(0xEF800010, 0xEF800F10, imm6lQvdQvmConstraints, InstName.Vshr, T.VshrT1, IsaVersion.v80, InstFlags.None), + new(0xEF800810, 0xFF800FD0, imm6VmConstraints, InstName.Vshrn, T.VshrnT1, IsaVersion.v80, InstFlags.None), + new(0xFF800510, 0xFF800F10, imm6lQvdQvmConstraints, InstName.Vsli, T.VsliT1, IsaVersion.v80, InstFlags.None), + new(0xFC200C40, 0xFFB00F50, vdVnVmConstraints, InstName.Vsmmla, T.VsmmlaT1, IsaVersion.v82, IsaFeature.FeatAa32i8mm, InstFlags.None), + new(0xEEB10AC0, 0xFFBF0ED0, InstName.Vsqrt, T.VsqrtT1, IsaVersion.v80, InstFlags.None), + new(0xEEB109C0, 0xFFBF0FD0, InstName.Vsqrt, T.VsqrtT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEF800110, 0xEF800F10, imm6lQvdQvmConstraints, InstName.Vsra, T.VsraT1, IsaVersion.v80, InstFlags.None), + new(0xFF800410, 0xFF800F10, imm6lQvdQvmConstraints, InstName.Vsri, T.VsriT1, IsaVersion.v80, InstFlags.None), + new(0xF9800000, 0xFFB00F10, sizeConstraints2, InstName.Vst11, T.Vst11T1, IsaVersion.v80, InstFlags.None), + new(0xF9800400, 0xFFB00F20, sizeConstraints2, InstName.Vst11, T.Vst11T2, IsaVersion.v80, InstFlags.None), + new(0xF9800800, 0xFFB00F40, sizeIndexAlignIndexAlignConstraints, InstName.Vst11, T.Vst11T3, IsaVersion.v80, InstFlags.None), + new(0xF9000700, 0xFFB00F00, alignConstraints, InstName.Vst1M, T.Vst1MT1, IsaVersion.v80, InstFlags.None), + new(0xF9000A00, 0xFFB00F00, alignConstraints2, InstName.Vst1M, T.Vst1MT2, IsaVersion.v80, InstFlags.None), + new(0xF9000600, 0xFFB00F00, alignConstraints, InstName.Vst1M, T.Vst1MT3, IsaVersion.v80, InstFlags.None), + new(0xF9000200, 0xFFB00F00, InstName.Vst1M, T.Vst1MT4, IsaVersion.v80, InstFlags.None), + new(0xF9800100, 0xFFB00F00, sizeConstraints2, InstName.Vst21, T.Vst21T1, IsaVersion.v80, InstFlags.None), + new(0xF9800500, 0xFFB00F00, sizeConstraints2, InstName.Vst21, T.Vst21T2, IsaVersion.v80, InstFlags.None), + new(0xF9800900, 0xFFB00F20, sizeConstraints2, InstName.Vst21, T.Vst21T3, IsaVersion.v80, InstFlags.None), + new(0xF9000800, 0xFFB00E00, alignSizeConstraints, InstName.Vst2M, T.Vst2MT1, IsaVersion.v80, InstFlags.None), + new(0xF9000300, 0xFFB00F00, sizeConstraints3, InstName.Vst2M, T.Vst2MT2, IsaVersion.v80, InstFlags.None), + new(0xF9800200, 0xFFB00F10, sizeConstraints2, InstName.Vst31, T.Vst31T1, IsaVersion.v80, InstFlags.None), + new(0xF9800600, 0xFFB00F10, sizeConstraints2, InstName.Vst31, T.Vst31T2, IsaVersion.v80, InstFlags.None), + new(0xF9800A00, 0xFFB00F30, sizeConstraints2, InstName.Vst31, T.Vst31T3, IsaVersion.v80, InstFlags.None), + new(0xF9000400, 0xFFB00E00, sizeAlignConstraints, InstName.Vst3M, T.Vst3MT1, IsaVersion.v80, InstFlags.None), + new(0xF9800300, 0xFFB00F00, sizeConstraints2, InstName.Vst41, T.Vst41T1, IsaVersion.v80, InstFlags.None), + new(0xF9800700, 0xFFB00F00, sizeConstraints2, InstName.Vst41, T.Vst41T2, IsaVersion.v80, InstFlags.None), + new(0xF9800B00, 0xFFB00F00, sizeIndexAlignConstraints, InstName.Vst41, T.Vst41T3, IsaVersion.v80, InstFlags.None), + new(0xF9000000, 0xFFB00E00, sizeConstraints3, InstName.Vst4M, T.Vst4MT1, IsaVersion.v80, InstFlags.None), + new(0xEC000B00, 0xFE100F01, puwPwPuwPuwConstraints, InstName.Vstm, T.VstmT1, IsaVersion.v80, InstFlags.WBack), + new(0xEC000A00, 0xFE100F00, puwPwPuwPuwConstraints, InstName.Vstm, T.VstmT2, IsaVersion.v80, InstFlags.WBack), + new(0xED000A00, 0xFF300E00, InstName.Vstr, T.VstrT1, IsaVersion.v80, InstFlags.None), + new(0xED000900, 0xFF300F00, InstName.Vstr, T.VstrT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEF800600, 0xFF800F50, sizeVnVmConstraints, InstName.Vsubhn, T.VsubhnT1, IsaVersion.v80, InstFlags.None), + new(0xEF800200, 0xEF800F50, sizeVdOpvnConstraints, InstName.Vsubl, T.VsublT1, IsaVersion.v80, InstFlags.None), + new(0xEF800300, 0xEF800F50, sizeVdOpvnConstraints, InstName.Vsubw, T.VsubwT1, IsaVersion.v80, InstFlags.None), + new(0xEF200D00, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VsubF, T.VsubFT1, IsaVersion.v80, InstFlags.None), + new(0xEF300D00, 0xFFB00F10, qvdQvnQvmConstraints, InstName.VsubF, T.VsubFT1, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xEE300A40, 0xFFB00E50, InstName.VsubF, T.VsubFT2, IsaVersion.v80, InstFlags.None), + new(0xEE300940, 0xFFB00F50, InstName.VsubF, T.VsubFT2, IsaVersion.v80, IsaFeature.FeatFp16, InstFlags.None), + new(0xFF000800, 0xFF800F10, qvdQvnQvmConstraints, InstName.VsubI, T.VsubIT1, IsaVersion.v80, InstFlags.None), + new(0xFE800D10, 0xFFB00F10, qvdQvnConstraints, InstName.VsudotS, T.VsudotST1, IsaVersion.v82, IsaFeature.FeatAa32i8mm, InstFlags.None), + new(0xFFB20000, 0xFFBF0F90, qvdQvmConstraints, InstName.Vswp, T.VswpT1, IsaVersion.v80, InstFlags.None), + new(0xFFB00800, 0xFFB00C10, InstName.Vtbl, T.VtblT1, IsaVersion.v80, InstFlags.None), + new(0xFFB20080, 0xFFB30F90, sizeQvdQvmConstraints, InstName.Vtrn, T.VtrnT1, IsaVersion.v80, InstFlags.None), + new(0xEF000810, 0xFF800F10, qvdQvnQvmSizeConstraints, InstName.Vtst, T.VtstT1, IsaVersion.v80, InstFlags.None), + new(0xFC200D10, 0xFFB00F10, qvdQvnQvmConstraints, InstName.Vudot, T.VudotT1, IsaVersion.v82, IsaFeature.FeatDotprod, InstFlags.None), + new(0xFE200D10, 0xFFB00F10, qvdQvnConstraints, InstName.VudotS, T.VudotST1, IsaVersion.v82, IsaFeature.FeatDotprod, InstFlags.None), + new(0xFC200C50, 0xFFB00F50, vdVnVmConstraints, InstName.Vummla, T.VummlaT1, IsaVersion.v82, IsaFeature.FeatAa32i8mm, InstFlags.None), + new(0xFCA00D00, 0xFFB00F10, qvdQvnQvmConstraints, InstName.Vusdot, T.VusdotT1, IsaVersion.v82, IsaFeature.FeatAa32i8mm, InstFlags.None), + new(0xFE800D00, 0xFFB00F10, qvdQvnConstraints, InstName.VusdotS, T.VusdotST1, IsaVersion.v82, IsaFeature.FeatAa32i8mm, InstFlags.None), + new(0xFCA00C40, 0xFFB00F50, vdVnVmConstraints, InstName.Vusmmla, T.VusmmlaT1, IsaVersion.v82, IsaFeature.FeatAa32i8mm, InstFlags.None), + new(0xFFB20100, 0xFFB30F90, sizeQsizeQvdQvmConstraints, InstName.Vuzp, T.VuzpT1, IsaVersion.v80, InstFlags.None), + new(0xFFB20180, 0xFFB30F90, sizeQsizeQvdQvmConstraints, InstName.Vzip, T.VzipT1, IsaVersion.v80, InstFlags.None), + new(0xF3AF8002, 0xFFFFFFFF, InstName.Wfe, T.WfeT2, IsaVersion.v80, InstFlags.None), + new(0xF3AF8003, 0xFFFFFFFF, InstName.Wfi, T.WfiT2, IsaVersion.v80, InstFlags.None), + new(0xF3AF8001, 0xFFFFFFFF, InstName.Yield, T.YieldT2, IsaVersion.v80, InstFlags.None), + }; + + _table = new(insts); + } + + public static bool TryGetMeta(uint encoding, IsaVersion version, IsaFeature features, out InstMeta meta) + { + if (_table.TryFind(encoding, version, features, out InstInfoForTable info)) + { + meta = info.Meta; + + return true; + } + + meta = new(InstName.Udf, T.UdfA1, IsaVersion.v80, IsaFeature.None, InstFlags.None); + + return false; + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/MultiBlock.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/MultiBlock.cs new file mode 100644 index 000000000..ca25057fe --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/MultiBlock.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; + +namespace Ryujinx.Cpu.LightningJit.Arm32 +{ + class MultiBlock + { + public readonly List Blocks; + public readonly bool HasHostCall; + public readonly bool HasHostCallSkipContext; + public readonly bool IsTruncated; + + public MultiBlock(List blocks) + { + Blocks = blocks; + + Block block = blocks[0]; + + HasHostCall = block.HasHostCall; + HasHostCallSkipContext = block.HasHostCallSkipContext; + + for (int index = 1; index < blocks.Count; index++) + { + block = blocks[index]; + + HasHostCall |= block.HasHostCall; + HasHostCallSkipContext |= block.HasHostCallSkipContext; + } + + block = blocks[^1]; + + IsTruncated = block.IsTruncated; + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/PendingBranch.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/PendingBranch.cs new file mode 100644 index 000000000..8f48cd076 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/PendingBranch.cs @@ -0,0 +1,20 @@ +namespace Ryujinx.Cpu.LightningJit.Arm32 +{ + readonly struct PendingBranch + { + public readonly BranchType BranchType; + public readonly uint TargetAddress; + public readonly uint NextAddress; + public readonly InstName Name; + public readonly int WriterPointer; + + public PendingBranch(BranchType branchType, uint targetAddress, uint nextAddress, InstName name, int writerPointer) + { + BranchType = branchType; + TargetAddress = targetAddress; + NextAddress = nextAddress; + Name = name; + WriterPointer = writerPointer; + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/RegisterAllocator.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/RegisterAllocator.cs new file mode 100644 index 000000000..4a3f03b8a --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/RegisterAllocator.cs @@ -0,0 +1,170 @@ +using Ryujinx.Cpu.LightningJit.CodeGen; +using Ryujinx.Cpu.LightningJit.CodeGen.Arm64; +using System; +using System.Numerics; + +namespace Ryujinx.Cpu.LightningJit.Arm32 +{ + class RegisterAllocator + { + public const int MaxTemps = 1; + + private uint _gprMask; + private uint _fpSimdMask; + + public int FixedContextRegister { get; } + public int FixedPageTableRegister { get; } + + public uint UsedGprsMask { get; private set; } + public uint UsedFpSimdMask { get; private set; } + + public RegisterAllocator() + { + _gprMask = ushort.MaxValue; + _fpSimdMask = ushort.MaxValue; + + FixedContextRegister = AllocateTempRegisterWithPreferencing(); + FixedPageTableRegister = AllocateTempRegisterWithPreferencing(); + } + + public void MarkGprAsUsed(int index) + { + UsedGprsMask |= 1u << index; + } + + public void MarkFpSimdAsUsed(int index) + { + UsedFpSimdMask |= 1u << index; + } + + public void MarkFpSimdRangeAsUsed(int index, int count) + { + UsedFpSimdMask |= (uint.MaxValue >> (32 - count)) << index; + } + + public Operand RemapGprRegister(int index) + { + MarkGprAsUsed(index); + + return new Operand(OperandKind.Register, OperandType.I32, (ulong)index); + } + + public Operand RemapFpRegister(int index, bool isFP32) + { + MarkFpSimdAsUsed(index); + + return new Operand(OperandKind.Register, isFP32 ? OperandType.FP32 : OperandType.FP64, (ulong)index); + } + + public Operand RemapSimdRegister(int index) + { + MarkFpSimdAsUsed(index); + + return new Operand(OperandKind.Register, OperandType.V128, (ulong)index); + } + + public Operand RemapSimdRegister(int index, int count) + { + MarkFpSimdRangeAsUsed(index, count); + + return new Operand(OperandKind.Register, OperandType.V128, (ulong)index); + } + + public void EnsureTempGprRegisters(int count) + { + if (count != 0) + { + Span registers = stackalloc int[count]; + + for (int index = 0; index < count; index++) + { + registers[index] = AllocateTempGprRegister(); + } + + for (int index = 0; index < count; index++) + { + FreeTempGprRegister(registers[index]); + } + } + } + + public int AllocateTempGprRegister() + { + int index = AllocateTempRegister(ref _gprMask, AbiConstants.ReservedRegsMask); + + MarkGprAsUsed(index); + + return index; + } + + private int AllocateTempRegisterWithPreferencing() + { + int firstCalleeSaved = BitOperations.TrailingZeroCount(~_gprMask & AbiConstants.GprCalleeSavedRegsMask); + if (firstCalleeSaved < 32) + { + uint regMask = 1u << firstCalleeSaved; + if ((regMask & AbiConstants.ReservedRegsMask) == 0) + { + _gprMask |= regMask; + UsedGprsMask |= regMask; + + return firstCalleeSaved; + } + } + + return AllocateTempRegister(ref _gprMask, AbiConstants.ReservedRegsMask); + } + + public int AllocateTempFpSimdRegister() + { + int index = AllocateTempRegister(ref _fpSimdMask, 0); + + MarkFpSimdAsUsed(index); + + return index; + } + + public ScopedRegister AllocateTempGprRegisterScoped() + { + return new(this, new(OperandKind.Register, OperandType.I32, (ulong)AllocateTempGprRegister())); + } + + public ScopedRegister AllocateTempFpRegisterScoped(bool isFP32) + { + return new(this, new(OperandKind.Register, isFP32 ? OperandType.FP32 : OperandType.FP64, (ulong)AllocateTempFpSimdRegister())); + } + + public ScopedRegister AllocateTempSimdRegisterScoped() + { + return new(this, new(OperandKind.Register, OperandType.V128, (ulong)AllocateTempFpSimdRegister())); + } + + public void FreeTempGprRegister(int index) + { + FreeTempRegister(ref _gprMask, index); + } + + public void FreeTempFpSimdRegister(int index) + { + FreeTempRegister(ref _fpSimdMask, index); + } + + private static int AllocateTempRegister(ref uint mask, uint reservedMask) + { + int index = BitOperations.TrailingZeroCount(~(mask | reservedMask)); + if (index == sizeof(uint) * 8) + { + throw new InvalidOperationException("No free registers."); + } + + mask |= 1u << index; + + return index; + } + + private static void FreeTempRegister(ref uint mask, int index) + { + mask &= ~(1u << index); + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/RegisterUtils.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/RegisterUtils.cs new file mode 100644 index 000000000..8fbdeb731 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/RegisterUtils.cs @@ -0,0 +1,109 @@ +using System; + +namespace Ryujinx.Cpu.LightningJit.Arm32 +{ + static class RegisterUtils + { + public const int SpRegister = 13; + public const int LrRegister = 14; + public const int PcRegister = 15; + + private const int RmBit = 0; + private const int RdRtBit = 12; + private const int RdHiRnBit = 16; + + private const int RdRtT16Bit = 16; + private const int RdRtT16AltBit = 24; + + private const int RdRt2RdHiT32Bit = 8; + private const int RdT32AltBit = 0; + private const int RtRdLoT32Bit = 12; + + public static int ExtractRt(uint encoding) + { + return (int)(encoding >> RdRtBit) & 0xf; + } + + public static int ExtractRt2(uint encoding) + { + return (int)GetRt2((uint)ExtractRt(encoding)); + } + + public static int ExtractRd(InstFlags flags, uint encoding) + { + return flags.HasFlag(InstFlags.Rd16) ? ExtractRn(encoding) : ExtractRd(encoding); + } + + public static int ExtractRd(uint encoding) + { + return (int)(encoding >> RdRtBit) & 0xf; + } + + public static int ExtractRdHi(uint encoding) + { + return (int)(encoding >> RdHiRnBit) & 0xf; + } + + public static int ExtractRn(uint encoding) + { + return (int)(encoding >> RdHiRnBit) & 0xf; + } + + public static int ExtractRm(uint encoding) + { + return (int)(encoding >> RmBit) & 0xf; + } + + public static uint GetRt2(uint rt) + { + return Math.Min(rt + 1, PcRegister); + } + + public static int ExtractRdn(InstFlags flags, uint encoding) + { + if (flags.HasFlag(InstFlags.Dn)) + { + return ((int)(encoding >> RdRtT16Bit) & 7) | (int)((encoding >> 4) & 8); + } + else + { + return ExtractRdT16(flags, encoding); + } + } + + public static int ExtractRdT16(InstFlags flags, uint encoding) + { + return flags.HasFlag(InstFlags.Rd16) ? (int)(encoding >> RdRtT16AltBit) & 7 : (int)(encoding >> RdRtT16Bit) & 7; + } + + public static int ExtractRtT16(InstFlags flags, uint encoding) + { + return flags.HasFlag(InstFlags.Rd16) ? (int)(encoding >> RdRtT16AltBit) & 7 : (int)(encoding >> RdRtT16Bit) & 7; + } + + public static int ExtractRdT32(InstFlags flags, uint encoding) + { + return flags.HasFlag(InstFlags.Rd16) ? (int)(encoding >> RdT32AltBit) & 0xf : (int)(encoding >> RdRt2RdHiT32Bit) & 0xf; + } + + public static int ExtractRdLoT32(uint encoding) + { + return (int)(encoding >> RtRdLoT32Bit) & 0xf; + } + + public static int ExtractRdHiT32(uint encoding) + { + return (int)(encoding >> RdRt2RdHiT32Bit) & 0xf; + } + + public static int ExtractRtT32(uint encoding) + { + return (int)(encoding >> RtRdLoT32Bit) & 0xf; + } + + public static int ExtractRt2T32(uint encoding) + { + return (int)(encoding >> RdRt2RdHiT32Bit) & 0xf; + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/ScopedRegister.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/ScopedRegister.cs new file mode 100644 index 000000000..18b1416ea --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/ScopedRegister.cs @@ -0,0 +1,39 @@ +using Ryujinx.Cpu.LightningJit.CodeGen; +using System; + +namespace Ryujinx.Cpu.LightningJit.Arm32 +{ + readonly struct ScopedRegister : IDisposable + { + private readonly RegisterAllocator _registerAllocator; + private readonly Operand _operand; + private readonly bool _isAllocated; + + public readonly Operand Operand => _operand; + public readonly bool IsAllocated => _isAllocated; + + public ScopedRegister(RegisterAllocator registerAllocator, Operand operand, bool isAllocated = true) + { + _registerAllocator = registerAllocator; + _operand = operand; + _isAllocated = isAllocated; + } + + public readonly void Dispose() + { + if (!_isAllocated) + { + return; + } + + if (_operand.Type.IsInteger()) + { + _registerAllocator.FreeTempGprRegister(_operand.AsInt32()); + } + else + { + _registerAllocator.FreeTempFpSimdRegister(_operand.AsInt32()); + } + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/Compiler.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/Compiler.cs new file mode 100644 index 000000000..a668b5777 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/Compiler.cs @@ -0,0 +1,808 @@ +using ARMeilleure.Common; +using ARMeilleure.Memory; +using Ryujinx.Cpu.LightningJit.CodeGen; +using Ryujinx.Cpu.LightningJit.CodeGen.Arm64; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Numerics; + +namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 +{ + static class Compiler + { + public const uint UsableGprsMask = 0x7fff; + public const uint UsableFpSimdMask = 0xffff; + public const uint UsablePStateMask = 0xf0000000; + + private const int Encodable26BitsOffsetLimit = 0x2000000; + + private readonly struct Context + { + public readonly CodeWriter Writer; + public readonly RegisterAllocator RegisterAllocator; + public readonly MemoryManagerType MemoryManagerType; + public readonly TailMerger TailMerger; + public readonly AddressTable FuncTable; + public readonly IntPtr DispatchStubPointer; + + private readonly RegisterSaveRestore _registerSaveRestore; + private readonly IntPtr _pageTablePointer; + + public Context( + CodeWriter writer, + RegisterAllocator registerAllocator, + MemoryManagerType mmType, + TailMerger tailMerger, + AddressTable funcTable, + RegisterSaveRestore registerSaveRestore, + IntPtr dispatchStubPointer, + IntPtr pageTablePointer) + { + Writer = writer; + RegisterAllocator = registerAllocator; + MemoryManagerType = mmType; + TailMerger = tailMerger; + FuncTable = funcTable; + _registerSaveRestore = registerSaveRestore; + DispatchStubPointer = dispatchStubPointer; + _pageTablePointer = pageTablePointer; + } + + public readonly int GetReservedStackOffset() + { + return _registerSaveRestore.GetReservedStackOffset(); + } + + public readonly void WritePrologueAt(int instructionPointer) + { + CodeWriter writer = new(); + Assembler asm = new(writer); + + _registerSaveRestore.WritePrologue(ref asm); + + // If needed, set up the fixed registers with the pointers we will use. + // First one is the context pointer (passed as first argument), + // second one is the page table or address space base, it is at a fixed memory location and considered constant. + + if (RegisterAllocator.FixedContextRegister != 0) + { + asm.Mov(Register(RegisterAllocator.FixedContextRegister), Register(0)); + } + + asm.Mov(Register(RegisterAllocator.FixedPageTableRegister), (ulong)_pageTablePointer); + + LoadFromContext(ref asm); + + // Write the prologue at the specified position in our writer. + Writer.WriteInstructionsAt(instructionPointer, writer); + } + + public readonly void WriteEpilogueWithoutContext() + { + Assembler asm = new(Writer); + + _registerSaveRestore.WriteEpilogue(ref asm); + } + + public void LoadFromContext() + { + Assembler asm = new(Writer); + + LoadFromContext(ref asm); + } + + private void LoadFromContext(ref Assembler asm) + { + LoadGprFromContext(ref asm, RegisterAllocator.UsedGprsMask & UsableGprsMask, NativeContextOffsets.GprBaseOffset); + LoadFpSimdFromContext(ref asm, RegisterAllocator.UsedFpSimdMask & UsableFpSimdMask, NativeContextOffsets.FpSimdBaseOffset); + LoadPStateFromContext(ref asm, UsablePStateMask, NativeContextOffsets.FlagsBaseOffset); + } + + public void StoreToContext() + { + Assembler asm = new(Writer); + + StoreToContext(ref asm); + } + + private void StoreToContext(ref Assembler asm) + { + StoreGprToContext(ref asm, RegisterAllocator.UsedGprsMask & UsableGprsMask, NativeContextOffsets.GprBaseOffset); + StoreFpSimdToContext(ref asm, RegisterAllocator.UsedFpSimdMask & UsableFpSimdMask, NativeContextOffsets.FpSimdBaseOffset); + StorePStateToContext(ref asm, UsablePStateMask, NativeContextOffsets.FlagsBaseOffset); + } + + private void LoadGprFromContext(ref Assembler asm, uint mask, int baseOffset) + { + Operand contextPtr = Register(RegisterAllocator.FixedContextRegister); + + while (mask != 0) + { + int reg = BitOperations.TrailingZeroCount(mask); + int offset = baseOffset + reg * 8; + + if (reg < 31 && (mask & (2u << reg)) != 0 && offset < RegisterSaveRestore.Encodable9BitsOffsetLimit) + { + mask &= ~(3u << reg); + + asm.LdpRiUn(Register(reg), Register(reg + 1), contextPtr, offset); + } + else + { + mask &= ~(1u << reg); + + asm.LdrRiUn(Register(reg), contextPtr, offset); + } + } + } + + private void LoadFpSimdFromContext(ref Assembler asm, uint mask, int baseOffset) + { + Operand contextPtr = Register(RegisterAllocator.FixedContextRegister); + + while (mask != 0) + { + int reg = BitOperations.TrailingZeroCount(mask); + int offset = baseOffset + reg * 16; + + mask &= ~(1u << reg); + + asm.LdrRiUn(Register(reg, OperandType.V128), contextPtr, offset); + } + } + + private void LoadPStateFromContext(ref Assembler asm, uint mask, int baseOffset) + { + if (mask == 0) + { + return; + } + + Operand contextPtr = Register(RegisterAllocator.FixedContextRegister); + + using ScopedRegister tempRegister = RegisterAllocator.AllocateTempGprRegisterScoped(); + + asm.LdrRiUn(tempRegister.Operand, contextPtr, baseOffset); + asm.MsrNzcv(tempRegister.Operand); + } + + private void StoreGprToContext(ref Assembler asm, uint mask, int baseOffset) + { + Operand contextPtr = Register(RegisterAllocator.FixedContextRegister); + + while (mask != 0) + { + int reg = BitOperations.TrailingZeroCount(mask); + int offset = baseOffset + reg * 8; + + if (reg < 31 && (mask & (2u << reg)) != 0 && offset < RegisterSaveRestore.Encodable9BitsOffsetLimit) + { + mask &= ~(3u << reg); + + asm.StpRiUn(Register(reg), Register(reg + 1), contextPtr, offset); + } + else + { + mask &= ~(1u << reg); + + asm.StrRiUn(Register(reg), contextPtr, offset); + } + } + } + + private void StoreFpSimdToContext(ref Assembler asm, uint mask, int baseOffset) + { + Operand contextPtr = Register(RegisterAllocator.FixedContextRegister); + + while (mask != 0) + { + int reg = BitOperations.TrailingZeroCount(mask); + int offset = baseOffset + reg * 16; + + mask &= ~(1u << reg); + + asm.StrRiUn(Register(reg, OperandType.V128), contextPtr, offset); + } + } + + private void StorePStateToContext(ref Assembler asm, uint mask, int baseOffset) + { + if (mask == 0) + { + return; + } + + Operand contextPtr = Register(RegisterAllocator.FixedContextRegister); + + using ScopedRegister tempRegister = RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister tempRegister2 = RegisterAllocator.AllocateTempGprRegisterScoped(); + + asm.LdrRiUn(tempRegister.Operand, contextPtr, baseOffset); + asm.MrsNzcv(tempRegister2.Operand); + asm.And(tempRegister.Operand, tempRegister.Operand, InstEmitCommon.Const(0xfffffff)); + asm.Orr(tempRegister.Operand, tempRegister.Operand, tempRegister2.Operand); + asm.StrRiUn(tempRegister.Operand, contextPtr, baseOffset); + } + } + + public static CompiledFunction Compile(CpuPreset cpuPreset, IMemoryManager memoryManager, ulong address, AddressTable funcTable, IntPtr dispatchStubPtr, bool isThumb) + { + MultiBlock multiBlock = Decoder.DecodeMulti(cpuPreset, memoryManager, address, isThumb); + + Dictionary targets = new(); + + CodeWriter writer = new(); + RegisterAllocator regAlloc = new(); + Assembler asm = new(writer); + CodeGenContext cgContext = new(writer, asm, regAlloc, memoryManager.Type, isThumb); + ArmCondition lastCondition = ArmCondition.Al; + int lastConditionIp = 0; + + // Required for load/store to context. + regAlloc.EnsureTempGprRegisters(2); + + ulong pc = address; + + for (int blockIndex = 0; blockIndex < multiBlock.Blocks.Count; blockIndex++) + { + Block block = multiBlock.Blocks[blockIndex]; + + Debug.Assert(block.Address == pc); + + targets.Add(pc, writer.InstructionPointer); + + for (int index = 0; index < block.Instructions.Count; index++) + { + InstInfo instInfo = block.Instructions[index]; + + if (index < block.Instructions.Count - 1) + { + cgContext.SetNextInstruction(block.Instructions[index + 1]); + } + else + { + cgContext.SetNextInstruction(default); + } + + SetConditionalStart(cgContext, ref lastCondition, ref lastConditionIp, instInfo.Name, instInfo.Flags, instInfo.Encoding); + + if (block.IsLoopEnd && index == block.Instructions.Count - 1) + { + // If this is a loop, the code might run for a long time uninterrupted. + // We insert a "sync point" here to ensure the loop can be interrupted if needed. + + cgContext.AddPendingSyncPoint(); + + asm.B(0); + } + + cgContext.SetPc((uint)pc); + + instInfo.EmitFunc(cgContext, instInfo.Encoding); + + if (cgContext.ConsumeNzcvModified()) + { + ForceConditionalEnd(cgContext, ref lastCondition, lastConditionIp); + } + + cgContext.UpdateItState(); + + pc += instInfo.Flags.HasFlag(InstFlags.Thumb16) ? 2UL : 4UL; + } + + if (Decoder.WritesToPC(block.Instructions[^1].Encoding, block.Instructions[^1].Name, block.Instructions[^1].Flags, block.IsThumb)) + { + // If the block ends with a PC register write, then we have a branch from register. + + InstEmitCommon.SetThumbFlag(cgContext, regAlloc.RemapGprRegister(RegisterUtils.PcRegister)); + + cgContext.AddPendingIndirectBranch(block.Instructions[^1].Name, RegisterUtils.PcRegister); + + asm.B(0); + } + + ForceConditionalEnd(cgContext, ref lastCondition, lastConditionIp); + } + + int reservedStackSize = 0; + + if (multiBlock.HasHostCall) + { + reservedStackSize = CalculateStackSizeForCallSpill(regAlloc.UsedGprsMask, regAlloc.UsedFpSimdMask, UsablePStateMask); + } + else if (multiBlock.HasHostCallSkipContext) + { + reservedStackSize = 2 * sizeof(ulong); // Context and page table pointers. + } + + RegisterSaveRestore rsr = new( + regAlloc.UsedGprsMask & AbiConstants.GprCalleeSavedRegsMask, + regAlloc.UsedFpSimdMask & AbiConstants.FpSimdCalleeSavedRegsMask, + OperandType.FP64, + multiBlock.HasHostCall || multiBlock.HasHostCallSkipContext, + reservedStackSize); + + TailMerger tailMerger = new(); + + Context context = new(writer, regAlloc, memoryManager.Type, tailMerger, funcTable, rsr, dispatchStubPtr, memoryManager.PageTablePointer); + + InstInfo lastInstruction = multiBlock.Blocks[^1].Instructions[^1]; + bool lastInstIsConditional = GetCondition(lastInstruction, isThumb) != ArmCondition.Al; + + if (multiBlock.IsTruncated || lastInstIsConditional || lastInstruction.Name.IsCall() || IsConditionalBranch(lastInstruction)) + { + WriteTailCallConstant(context, ref asm, (uint)pc); + } + + IEnumerable pendingBranches = cgContext.GetPendingBranches(); + + foreach (PendingBranch pendingBranch in pendingBranches) + { + RewriteBranchInstructionWithTarget(context, pendingBranch, targets); + } + + tailMerger.WriteReturn(writer, context.WriteEpilogueWithoutContext); + + context.WritePrologueAt(0); + + return new(writer.AsByteSpan(), (int)(pc - address)); + } + + private static int CalculateStackSizeForCallSpill(uint gprUseMask, uint fpSimdUseMask, uint pStateUseMask) + { + // Note that we don't discard callee saved FP/SIMD register because only the lower 64 bits is callee saved, + // so if the function is using the full register, that won't be enough. + // We could do better, but it's likely not worth it since this case happens very rarely in practice. + + return BitOperations.PopCount(gprUseMask & ~AbiConstants.GprCalleeSavedRegsMask) * 8 + + BitOperations.PopCount(fpSimdUseMask) * 16 + + (pStateUseMask != 0 ? 8 : 0); + } + + private static void SetConditionalStart( + CodeGenContext context, + ref ArmCondition condition, + ref int instructionPointer, + InstName name, + InstFlags flags, + uint encoding) + { + if (!context.ConsumeItCondition(out ArmCondition currentCond)) + { + currentCond = GetCondition(name, flags, encoding, context.IsThumb); + } + + if (currentCond != condition) + { + WriteConditionalEnd(context, condition, instructionPointer); + + condition = currentCond; + + if (currentCond != ArmCondition.Al) + { + instructionPointer = context.CodeWriter.InstructionPointer; + context.Arm64Assembler.B(currentCond.Invert(), 0); + } + } + } + + private static bool IsConditionalBranch(in InstInfo instInfo) + { + return instInfo.Name == InstName.B && (ArmCondition)(instInfo.Encoding >> 28) != ArmCondition.Al; + } + + private static ArmCondition GetCondition(in InstInfo instInfo, bool isThumb) + { + return GetCondition(instInfo.Name, instInfo.Flags, instInfo.Encoding, isThumb); + } + + private static ArmCondition GetCondition(InstName name, InstFlags flags, uint encoding, bool isThumb) + { + // For branch, we handle conditional execution on the instruction itself. + bool hasCond = flags.HasFlag(InstFlags.Cond) && !CanHandleConditionalInstruction(name, encoding, isThumb); + + return hasCond ? (ArmCondition)(encoding >> 28) : ArmCondition.Al; + } + + private static bool CanHandleConditionalInstruction(InstName name, uint encoding, bool isThumb) + { + if (name == InstName.B) + { + return true; + } + + // We can use CSEL for conditional MOV from registers, as long the instruction is not setting flags. + // We don't handle thumb right now because the condition comes from the IT block which would be more complicated to handle. + if (name == InstName.MovR && !isThumb && (encoding & (1u << 20)) == 0) + { + return true; + } + + return false; + } + + private static void ForceConditionalEnd(CodeGenContext context, ref ArmCondition condition, int instructionPointer) + { + WriteConditionalEnd(context, condition, instructionPointer); + + condition = ArmCondition.Al; + } + + private static void WriteConditionalEnd(CodeGenContext context, ArmCondition condition, int instructionPointer) + { + if (condition != ArmCondition.Al) + { + int delta = context.CodeWriter.InstructionPointer - instructionPointer; + uint branchInst = context.CodeWriter.ReadInstructionAt(instructionPointer) | (((uint)delta & 0x7ffff) << 5); + Debug.Assert((int)((branchInst & ~0x1fu) << 8) >> 11 == delta * 4); + + context.CodeWriter.WriteInstructionAt(instructionPointer, branchInst); + } + } + + private static void RewriteBranchInstructionWithTarget(in Context context, in PendingBranch pendingBranch, Dictionary targets) + { + switch (pendingBranch.BranchType) + { + case BranchType.Branch: + RewriteBranchInstructionWithTarget(context, pendingBranch.Name, pendingBranch.TargetAddress, pendingBranch.WriterPointer, targets); + break; + case BranchType.Call: + RewriteCallInstructionWithTarget(context, pendingBranch.TargetAddress, pendingBranch.NextAddress, pendingBranch.WriterPointer); + break; + case BranchType.IndirectBranch: + RewriteIndirectBranchInstructionWithTarget(context, pendingBranch.Name, pendingBranch.TargetAddress, pendingBranch.WriterPointer); + break; + case BranchType.TableBranchByte: + case BranchType.TableBranchHalfword: + RewriteTableBranchInstructionWithTarget( + context, + pendingBranch.BranchType == BranchType.TableBranchHalfword, + pendingBranch.TargetAddress, + pendingBranch.NextAddress, + pendingBranch.WriterPointer); + break; + case BranchType.IndirectCall: + RewriteIndirectCallInstructionWithTarget(context, pendingBranch.TargetAddress, pendingBranch.NextAddress, pendingBranch.WriterPointer); + break; + case BranchType.SyncPoint: + case BranchType.SoftwareInterrupt: + case BranchType.ReadCntpct: + RewriteHostCall(context, pendingBranch.Name, pendingBranch.BranchType, pendingBranch.TargetAddress, pendingBranch.NextAddress, pendingBranch.WriterPointer); + break; + default: + Debug.Fail($"Invalid branch type '{pendingBranch.BranchType}'"); + break; + } + } + + private static void RewriteBranchInstructionWithTarget(in Context context, InstName name, uint targetAddress, int branchIndex, Dictionary targets) + { + CodeWriter writer = context.Writer; + Assembler asm = new(writer); + + int delta; + int targetIndex; + uint encoding = writer.ReadInstructionAt(branchIndex); + + if (encoding == 0x14000000) + { + // Unconditional branch. + + if (targets.TryGetValue(targetAddress, out targetIndex)) + { + delta = targetIndex - branchIndex; + + if (delta >= -Encodable26BitsOffsetLimit && delta < Encodable26BitsOffsetLimit) + { + writer.WriteInstructionAt(branchIndex, encoding | (uint)(delta & 0x3ffffff)); + + return; + } + } + + targetIndex = writer.InstructionPointer; + delta = targetIndex - branchIndex; + + writer.WriteInstructionAt(branchIndex, encoding | (uint)(delta & 0x3ffffff)); + WriteTailCallConstant(context, ref asm, targetAddress); + } + else + { + // Conditional branch. + + uint branchMask = 0x7ffff; + int branchMax = (int)(branchMask + 1) / 2; + + if (targets.TryGetValue(targetAddress, out targetIndex)) + { + delta = targetIndex - branchIndex; + + if (delta >= -branchMax && delta < branchMax) + { + writer.WriteInstructionAt(branchIndex, encoding | (uint)((delta & branchMask) << 5)); + + return; + } + } + + targetIndex = writer.InstructionPointer; + delta = targetIndex - branchIndex; + + if (delta >= -branchMax && delta < branchMax) + { + writer.WriteInstructionAt(branchIndex, encoding | (uint)((delta & branchMask) << 5)); + WriteTailCallConstant(context, ref asm, targetAddress); + } + else + { + // If the branch target is too far away, we use a regular unconditional branch + // instruction instead which has a much higher range. + // We branch directly to the end of the function, where we put the conditional branch, + // and then branch back to the next instruction or return the branch target depending + // on the branch being taken or not. + + uint branchInst = 0x14000000u | ((uint)delta & 0x3ffffff); + Debug.Assert((int)(branchInst << 6) >> 4 == delta * 4); + + writer.WriteInstructionAt(branchIndex, branchInst); + + int movedBranchIndex = writer.InstructionPointer; + + writer.WriteInstruction(0u); // Placeholder + asm.B((branchIndex + 1 - writer.InstructionPointer) * 4); + + delta = writer.InstructionPointer - movedBranchIndex; + + writer.WriteInstructionAt(movedBranchIndex, encoding | (uint)((delta & branchMask) << 5)); + WriteTailCallConstant(context, ref asm, targetAddress); + } + } + + Debug.Assert(name == InstName.B || name == InstName.Cbnz, $"Unknown branch instruction \"{name}\"."); + } + + private static void RewriteCallInstructionWithTarget(in Context context, uint targetAddress, uint nextAddress, int branchIndex) + { + CodeWriter writer = context.Writer; + Assembler asm = new(writer); + + WriteBranchToCurrentPosition(context, branchIndex); + + asm.Mov(context.RegisterAllocator.RemapGprRegister(RegisterUtils.LrRegister), nextAddress); + + context.StoreToContext(); + InstEmitFlow.WriteCallWithGuestAddress( + writer, + ref asm, + context.RegisterAllocator, + context.TailMerger, + context.WriteEpilogueWithoutContext, + context.FuncTable, + context.DispatchStubPointer, + context.GetReservedStackOffset(), + nextAddress, + InstEmitCommon.Const((int)targetAddress)); + context.LoadFromContext(); + + // Branch back to the next instruction (after the call). + asm.B((branchIndex + 1 - writer.InstructionPointer) * 4); + } + + private static void RewriteIndirectBranchInstructionWithTarget(in Context context, InstName name, uint targetRegister, int branchIndex) + { + CodeWriter writer = context.Writer; + Assembler asm = new(writer); + + WriteBranchToCurrentPosition(context, branchIndex); + + using ScopedRegister target = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + asm.And(target.Operand, context.RegisterAllocator.RemapGprRegister((int)targetRegister), InstEmitCommon.Const(~1)); + + context.StoreToContext(); + + if ((name == InstName.Bx && targetRegister == RegisterUtils.LrRegister) || + name == InstName.Ldm || + name == InstName.Ldmda || + name == InstName.Ldmdb || + name == InstName.Ldmib || + name == InstName.Pop) + { + // Arm32 does not have a return instruction, instead returns are implemented + // either using BX LR (for leaf functions), or POP { ... PC }. + + asm.Mov(Register(0), target.Operand); + + context.TailMerger.AddUnconditionalReturn(writer, asm); + } + else + { + InstEmitFlow.WriteCallWithGuestAddress( + writer, + ref asm, + context.RegisterAllocator, + context.TailMerger, + context.WriteEpilogueWithoutContext, + context.FuncTable, + context.DispatchStubPointer, + context.GetReservedStackOffset(), + 0u, + target.Operand, + isTail: true); + } + } + + private static void RewriteTableBranchInstructionWithTarget(in Context context, bool halfword, uint rn, uint rm, int branchIndex) + { + CodeWriter writer = context.Writer; + Assembler asm = new(writer); + + WriteBranchToCurrentPosition(context, branchIndex); + + using ScopedRegister target = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + asm.Add( + target.Operand, + context.RegisterAllocator.RemapGprRegister((int)rn), + context.RegisterAllocator.RemapGprRegister((int)rm), + ArmShiftType.Lsl, + halfword ? 1 : 0); + + InstEmitMemory.WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, asm, target.Operand, target.Operand); + + if (halfword) + { + asm.LdrhRiUn(target.Operand, target.Operand, 0); + } + else + { + asm.LdrbRiUn(target.Operand, target.Operand, 0); + } + + asm.Add(target.Operand, context.RegisterAllocator.RemapGprRegister(RegisterUtils.PcRegister), target.Operand, ArmShiftType.Lsl, 1); + + context.StoreToContext(); + + InstEmitFlow.WriteCallWithGuestAddress( + writer, + ref asm, + context.RegisterAllocator, + context.TailMerger, + context.WriteEpilogueWithoutContext, + context.FuncTable, + context.DispatchStubPointer, + context.GetReservedStackOffset(), + 0u, + target.Operand, + isTail: true); + } + + private static void RewriteIndirectCallInstructionWithTarget(in Context context, uint targetRegister, uint nextAddress, int branchIndex) + { + CodeWriter writer = context.Writer; + Assembler asm = new(writer); + + WriteBranchToCurrentPosition(context, branchIndex); + + using ScopedRegister target = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + asm.And(target.Operand, context.RegisterAllocator.RemapGprRegister((int)targetRegister), InstEmitCommon.Const(~1)); + asm.Mov(context.RegisterAllocator.RemapGprRegister(RegisterUtils.LrRegister), nextAddress); + + context.StoreToContext(); + InstEmitFlow.WriteCallWithGuestAddress( + writer, + ref asm, + context.RegisterAllocator, + context.TailMerger, + context.WriteEpilogueWithoutContext, + context.FuncTable, + context.DispatchStubPointer, + context.GetReservedStackOffset(), + nextAddress & ~1u, + target.Operand); + context.LoadFromContext(); + + // Branch back to the next instruction (after the call). + asm.B((branchIndex + 1 - writer.InstructionPointer) * 4); + } + + private static void RewriteHostCall(in Context context, InstName name, BranchType type, uint imm, uint pc, int branchIndex) + { + CodeWriter writer = context.Writer; + Assembler asm = new(writer); + + uint encoding = writer.ReadInstructionAt(branchIndex); + int targetIndex = writer.InstructionPointer; + int delta = targetIndex - branchIndex; + + writer.WriteInstructionAt(branchIndex, encoding | (uint)(delta & 0x3ffffff)); + + switch (type) + { + case BranchType.SyncPoint: + InstEmitSystem.WriteSyncPoint( + context.Writer, + ref asm, + context.RegisterAllocator, + context.TailMerger, + context.GetReservedStackOffset(), + context.StoreToContext, + context.LoadFromContext); + break; + case BranchType.SoftwareInterrupt: + context.StoreToContext(); + switch (name) + { + case InstName.Bkpt: + InstEmitSystem.WriteBkpt(context.Writer, context.RegisterAllocator, context.TailMerger, context.GetReservedStackOffset(), pc, imm); + break; + case InstName.Svc: + InstEmitSystem.WriteSvc(context.Writer, context.RegisterAllocator, context.TailMerger, context.GetReservedStackOffset(), pc, imm); + break; + case InstName.Udf: + InstEmitSystem.WriteUdf(context.Writer, context.RegisterAllocator, context.TailMerger, context.GetReservedStackOffset(), pc, imm); + break; + } + context.LoadFromContext(); + break; + case BranchType.ReadCntpct: + InstEmitSystem.WriteReadCntpct(context.Writer, context.RegisterAllocator, context.GetReservedStackOffset(), (int)imm, (int)pc); + break; + default: + Debug.Fail($"Invalid branch type '{type}'"); + break; + } + + // Branch back to the next instruction. + asm.B((branchIndex + 1 - writer.InstructionPointer) * 4); + } + + private static void WriteBranchToCurrentPosition(in Context context, int branchIndex) + { + CodeWriter writer = context.Writer; + + int targetIndex = writer.InstructionPointer; + + if (branchIndex + 1 == targetIndex) + { + writer.RemoveLastInstruction(); + } + else + { + uint encoding = writer.ReadInstructionAt(branchIndex); + int delta = targetIndex - branchIndex; + + writer.WriteInstructionAt(branchIndex, encoding | (uint)(delta & 0x3ffffff)); + } + } + + private static void WriteTailCallConstant(in Context context, ref Assembler asm, uint address) + { + context.StoreToContext(); + InstEmitFlow.WriteCallWithGuestAddress( + context.Writer, + ref asm, + context.RegisterAllocator, + context.TailMerger, + context.WriteEpilogueWithoutContext, + context.FuncTable, + context.DispatchStubPointer, + context.GetReservedStackOffset(), + 0u, + InstEmitCommon.Const((int)address), + isTail: true); + } + + private static Operand Register(int register, OperandType type = OperandType.I64) + { + return new Operand(register, RegisterType.Integer, type); + } + + public static void PrintStats() + { + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmit.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmit.cs new file mode 100644 index 000000000..488919325 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmit.cs @@ -0,0 +1,8502 @@ +using Ryujinx.Cpu.LightningJit.CodeGen.Arm64; +using System; + +namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 +{ + class InstEmit : IInstEmit + { + public static void AdcIA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Sb20w1Rnb16w4Rdb12w4Imm12b0w12 inst = new(encoding); + + InstEmitAlu.AdcI(context, inst.Rd, inst.Rn, ImmUtils.ExpandImm(inst.Imm12), inst.S != 0); + } + + public static void AdcIT1(CodeGenContext context, uint encoding) + { + InstIb26w1Sb20w1Rnb16w4Imm3b12w3Rdb8w4Imm8b0w8 inst = new(encoding); + + InstEmitAlu.AdcI(context, inst.Rd, inst.Rn, ImmUtils.ExpandImm(inst.Imm8, inst.Imm3, inst.I), inst.S != 0); + } + + public static void AdcRA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Sb20w1Rnb16w4Rdb12w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding); + + InstEmitAlu.AdcR(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, inst.Imm5, inst.S != 0); + } + + public static void AdcRT1(CodeGenContext context, uint encoding) + { + InstRmb19w3Rdnb16w3 inst = new(encoding); + + InstEmitAlu.AdcR(context, inst.Rdn, inst.Rdn, inst.Rm, 0, 0, !context.InITBlock); + } + + public static void AdcRT2(CodeGenContext context, uint encoding) + { + InstSb20w1Rnb16w4Imm3b12w3Rdb8w4Imm2b6w2Stypeb4w2Rmb0w4 inst = new(encoding); + + InstEmitAlu.AdcR(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3), inst.S != 0); + } + + public static void AdcRrA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Sb20w1Rnb16w4Rdb12w4Rsb8w4Stypeb5w2Rmb0w4 inst = new(encoding); + + InstEmitAlu.AdcRr(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, inst.Rs, inst.S != 0); + } + + public static void AddIA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Sb20w1Rnb16w4Rdb12w4Imm12b0w12 inst = new(encoding); + + InstEmitAlu.AddI(context, inst.Rd, inst.Rn, ImmUtils.ExpandImm(inst.Imm12), inst.S != 0); + } + + public static void AddIT1(CodeGenContext context, uint encoding) + { + InstImm3b22w3Rnb19w3Rdb16w3 inst = new(encoding); + + InstEmitAlu.AddI(context, inst.Rd, inst.Rn, inst.Imm3, !context.InITBlock); + } + + public static void AddIT2(CodeGenContext context, uint encoding) + { + InstRdnb24w3Imm8b16w8 inst = new(encoding); + + InstEmitAlu.AddI(context, inst.Rdn, inst.Rdn, inst.Imm8, !context.InITBlock); + } + + public static void AddIT3(CodeGenContext context, uint encoding) + { + InstIb26w1Sb20w1Rnb16w4Imm3b12w3Rdb8w4Imm8b0w8 inst = new(encoding); + + InstEmitAlu.AddI(context, inst.Rd, inst.Rn, ImmUtils.ExpandImm(inst.Imm8, inst.Imm3, inst.I), inst.S != 0); + } + + public static void AddIT4(CodeGenContext context, uint encoding) + { + InstIb26w1Rnb16w4Imm3b12w3Rdb8w4Imm8b0w8 inst = new(encoding); + + InstEmitAlu.AddI(context, inst.Rd, inst.Rn, ImmUtils.CombineImmU12(inst.Imm8, inst.Imm3, inst.I), false); + } + + public static void AddRA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Sb20w1Rnb16w4Rdb12w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding); + + InstEmitAlu.AddR(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, inst.Imm5, inst.S != 0); + } + + public static void AddRT1(CodeGenContext context, uint encoding) + { + InstRmb22w3Rnb19w3Rdb16w3 inst = new(encoding); + + InstEmitAlu.AddR(context, inst.Rd, inst.Rn, inst.Rm, 0, 0, !context.InITBlock); + } + + public static void AddRT2(CodeGenContext context, uint encoding) + { + InstDnb23w1Rmb19w4Rdnb16w3 inst = new(encoding); + + uint rdn = (inst.Dn << 3) | inst.Rdn; + + InstEmitAlu.AddR(context, rdn, rdn, inst.Rm, 0, 0, false); + } + + public static void AddRT3(CodeGenContext context, uint encoding) + { + InstSb20w1Rnb16w4Imm3b12w3Rdb8w4Imm2b6w2Stypeb4w2Rmb0w4 inst = new(encoding); + + InstEmitAlu.AddR(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3), inst.S != 0); + } + + public static void AddRrA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Sb20w1Rnb16w4Rdb12w4Rsb8w4Stypeb5w2Rmb0w4 inst = new(encoding); + + InstEmitAlu.AddRr(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, inst.Rs, inst.S != 0); + } + + public static void AddSpIA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Sb20w1Rdb12w4Imm12b0w12 inst = new(encoding); + + InstEmitAlu.AddI(context, inst.Rd, RegisterUtils.SpRegister, ImmUtils.ExpandImm(inst.Imm12), inst.S != 0); + } + + public static void AddSpIT1(CodeGenContext context, uint encoding) + { + InstRdb24w3Imm8b16w8 inst = new(encoding); + + InstEmitAlu.AddI(context, inst.Rd, RegisterUtils.SpRegister, inst.Imm8 << 2, false); + } + + public static void AddSpIT2(CodeGenContext context, uint encoding) + { + InstImm7b16w7 inst = new(encoding); + + InstEmitAlu.AddI(context, RegisterUtils.SpRegister, RegisterUtils.SpRegister, inst.Imm7 << 2, false); + } + + public static void AddSpIT3(CodeGenContext context, uint encoding) + { + InstIb26w1Sb20w1Imm3b12w3Rdb8w4Imm8b0w8 inst = new(encoding); + + InstEmitAlu.AddI(context, inst.Rd, RegisterUtils.SpRegister, ImmUtils.ExpandImm(inst.Imm8, inst.Imm3, inst.I), inst.S != 0); + } + + public static void AddSpIT4(CodeGenContext context, uint encoding) + { + InstIb26w1Imm3b12w3Rdb8w4Imm8b0w8 inst = new(encoding); + + InstEmitAlu.AddI(context, inst.Rd, RegisterUtils.SpRegister, ImmUtils.CombineImmU12(inst.Imm8, inst.Imm3, inst.I), false); + } + + public static void AddSpRA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Sb20w1Rdb12w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding); + + InstEmitAlu.AddR(context, inst.Rd, RegisterUtils.SpRegister, inst.Rm, inst.Stype, inst.Imm5, inst.S != 0); + } + + public static void AddSpRT1(CodeGenContext context, uint encoding) + { + InstDmb23w1Rdmb16w3 inst = new(encoding); + + uint rdm = inst.Rdm | (inst.Dm << 3); + + InstEmitAlu.AddR(context, rdm, RegisterUtils.SpRegister, rdm, 0, 0, false); + } + + public static void AddSpRT2(CodeGenContext context, uint encoding) + { + InstRmb19w4 inst = new(encoding); + + InstEmitAlu.AddR(context, RegisterUtils.SpRegister, RegisterUtils.SpRegister, inst.Rm, 0, 0, false); + } + + public static void AddSpRT3(CodeGenContext context, uint encoding) + { + InstSb20w1Imm3b12w3Rdb8w4Imm2b6w2Stypeb4w2Rmb0w4 inst = new(encoding); + + InstEmitAlu.AddR(context, inst.Rd, RegisterUtils.SpRegister, inst.Rm, inst.Stype, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3), inst.S != 0); + } + + public static void AdrA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rdb12w4Imm12b0w12 inst = new(encoding); + + InstEmitAlu.Adr(context, inst.Rd, ImmUtils.ExpandImm(inst.Imm12), true); + } + + public static void AdrA2(CodeGenContext context, uint encoding) + { + InstCondb28w4Rdb12w4Imm12b0w12 inst = new(encoding); + + InstEmitAlu.Adr(context, inst.Rd, ImmUtils.ExpandImm(inst.Imm12), false); + } + + public static void AdrT1(CodeGenContext context, uint encoding) + { + InstRdb24w3Imm8b16w8 inst = new(encoding); + + InstEmitAlu.Adr(context, inst.Rd, inst.Imm8 << 2, true); + } + + public static void AdrT2(CodeGenContext context, uint encoding) + { + InstIb26w1Imm3b12w3Rdb8w4Imm8b0w8 inst = new(encoding); + + InstEmitAlu.Adr(context, inst.Rd, ImmUtils.CombineImmU12(inst.Imm8, inst.Imm3, inst.I), false); + } + + public static void AdrT3(CodeGenContext context, uint encoding) + { + InstIb26w1Imm3b12w3Rdb8w4Imm8b0w8 inst = new(encoding); + + InstEmitAlu.Adr(context, inst.Rd, ImmUtils.CombineImmU12(inst.Imm8, inst.Imm3, inst.I), true); + } + + public static void AesdA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonCrypto.Aesd(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size); + } + + public static void AesdT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonCrypto.Aesd(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size); + } + + public static void AeseA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonCrypto.Aese(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size); + } + + public static void AeseT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonCrypto.Aese(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size); + } + + public static void AesimcA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonCrypto.Aesimc(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size); + } + + public static void AesimcT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonCrypto.Aesimc(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size); + } + + public static void AesmcA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonCrypto.Aesmc(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size); + } + + public static void AesmcT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonCrypto.Aesmc(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size); + } + + public static void AndIA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Sb20w1Rnb16w4Rdb12w4Imm12b0w12 inst = new(encoding); + + InstEmitAlu.AndI(context, inst.Rd, inst.Rn, ImmUtils.ExpandImm(inst.Imm12), ImmUtils.ExpandedImmRotated(inst.Imm12), inst.S != 0); + } + + public static void AndIT1(CodeGenContext context, uint encoding) + { + InstIb26w1Sb20w1Rnb16w4Imm3b12w3Rdb8w4Imm8b0w8 inst = new(encoding); + + InstEmitAlu.AndI(context, inst.Rd, inst.Rn, ImmUtils.ExpandImm(inst.Imm8, inst.Imm3, inst.I), ImmUtils.ExpandedImmRotated(inst.Imm8, inst.Imm3, inst.I), inst.S != 0); + } + + public static void AndRA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Sb20w1Rnb16w4Rdb12w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding); + + InstEmitAlu.AndR(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, inst.Imm5, inst.S != 0); + } + + public static void AndRT1(CodeGenContext context, uint encoding) + { + InstRmb19w3Rdnb16w3 inst = new(encoding); + + InstEmitAlu.AndR(context, inst.Rdn, inst.Rdn, inst.Rm, 0, 0, !context.InITBlock); + } + + public static void AndRT2(CodeGenContext context, uint encoding) + { + InstSb20w1Rnb16w4Imm3b12w3Rdb8w4Imm2b6w2Stypeb4w2Rmb0w4 inst = new(encoding); + + InstEmitAlu.AndR(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3), inst.S != 0); + } + + public static void AndRrA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Sb20w1Rnb16w4Rdb12w4Rsb8w4Stypeb5w2Rmb0w4 inst = new(encoding); + + InstEmitAlu.AndRr(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, inst.Rs, inst.S != 0); + } + + public static void BA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Imm24b0w24 inst = new(encoding); + + InstEmitFlow.B(context, ImmUtils.ExtractSImm24Times4(inst.Imm24), (ArmCondition)inst.Cond); + } + + public static void BT1(CodeGenContext context, uint encoding) + { + InstCondb24w4Imm8b16w8 inst = new(encoding); + + InstEmitFlow.B(context, ImmUtils.ExtractT16SImm8Times2(inst.Imm8), (ArmCondition)inst.Cond); + } + + public static void BT2(CodeGenContext context, uint encoding) + { + InstImm11b16w11 inst = new(encoding); + + InstEmitFlow.B(context, ImmUtils.ExtractT16SImm11Times2(inst.Imm11), ArmCondition.Al); + } + + public static void BT3(CodeGenContext context, uint encoding) + { + InstSb26w1Condb22w4Imm6b16w6J1b13w1J2b11w1Imm11b0w11 inst = new(encoding); + + InstEmitFlow.B(context, ImmUtils.CombineSImm20Times2(inst.Imm11, inst.Imm6, inst.J1, inst.J2, inst.S), (ArmCondition)inst.Cond); + } + + public static void BT4(CodeGenContext context, uint encoding) + { + InstSb26w1Imm10b16w10J1b13w1J2b11w1Imm11b0w11 inst = new(encoding); + + InstEmitFlow.B(context, ImmUtils.CombineSImm24Times2(inst.Imm11, inst.Imm10, inst.J1, inst.J2, inst.S), ArmCondition.Al); + } + + public static void BfcA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Msbb16w5Rdb12w4Lsbb7w5 inst = new(encoding); + + InstEmitBit.Bfc(context, inst.Rd, inst.Lsb, inst.Msb); + } + + public static void BfcT1(CodeGenContext context, uint encoding) + { + InstImm3b12w3Rdb8w4Imm2b6w2Msbb0w5 inst = new(encoding); + + InstEmitBit.Bfc(context, inst.Rd, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3), inst.Msb); + } + + public static void BfiA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Msbb16w5Rdb12w4Lsbb7w5Rnb0w4 inst = new(encoding); + + InstEmitBit.Bfi(context, inst.Rd, inst.Rn, inst.Lsb, inst.Msb); + } + + public static void BfiT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Imm3b12w3Rdb8w4Imm2b6w2Msbb0w5 inst = new(encoding); + + InstEmitBit.Bfi(context, inst.Rd, inst.Rn, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3), inst.Msb); + } + + public static void BicIA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Sb20w1Rnb16w4Rdb12w4Imm12b0w12 inst = new(encoding); + + InstEmitAlu.BicI(context, inst.Rd, inst.Rn, ImmUtils.ExpandImm(inst.Imm12), ImmUtils.ExpandedImmRotated(inst.Imm12), inst.S != 0); + } + + public static void BicIT1(CodeGenContext context, uint encoding) + { + InstIb26w1Sb20w1Rnb16w4Imm3b12w3Rdb8w4Imm8b0w8 inst = new(encoding); + + InstEmitAlu.BicI(context, inst.Rd, inst.Rn, ImmUtils.ExpandImm(inst.Imm8, inst.Imm3, inst.I), ImmUtils.ExpandedImmRotated(inst.Imm8, inst.Imm3, inst.I), inst.S != 0); + } + + public static void BicRA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Sb20w1Rnb16w4Rdb12w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding); + + InstEmitAlu.BicR(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, inst.Imm5, inst.S != 0); + } + + public static void BicRT1(CodeGenContext context, uint encoding) + { + InstRmb19w3Rdnb16w3 inst = new(encoding); + + InstEmitAlu.BicR(context, inst.Rdn, inst.Rdn, inst.Rm, 0, 0, !context.InITBlock); + } + + public static void BicRT2(CodeGenContext context, uint encoding) + { + InstSb20w1Rnb16w4Imm3b12w3Rdb8w4Imm2b6w2Stypeb4w2Rmb0w4 inst = new(encoding); + + InstEmitAlu.BicR(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3), inst.S != 0); + } + + public static void BicRrA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Sb20w1Rnb16w4Rdb12w4Rsb8w4Stypeb5w2Rmb0w4 inst = new(encoding); + + InstEmitAlu.BicRr(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, inst.Rs, inst.S != 0); + } + + public static void BkptA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Imm12b8w12Imm4b0w4 inst = new(encoding); + + InstEmitSystem.Bkpt(context, ImmUtils.CombineImmU16(inst.Imm12, inst.Imm4)); + } + + public static void BkptT1(CodeGenContext context, uint encoding) + { + InstImm8b16w8 inst = new(encoding); + + InstEmitSystem.Bkpt(context, inst.Imm8); + } + + public static void BlxRA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rmb0w4 inst = new(encoding); + + InstEmitFlow.Blx(context, inst.Rm, false); + } + + public static void BlxRT1(CodeGenContext context, uint encoding) + { + InstRmb19w4 inst = new(encoding); + + InstEmitFlow.Blx(context, inst.Rm, true); + } + + public static void BlIA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Imm24b0w24 inst = new(encoding); + + InstEmitFlow.Bl(context, ImmUtils.ExtractSImm24Times4(inst.Imm24), false, false); + } + + public static void BlIA2(CodeGenContext context, uint encoding) + { + InstHb24w1Imm24b0w24 inst = new(encoding); + + InstEmitFlow.Bl(context, ImmUtils.ExtractSImm24Times4(inst.Imm24) | ((int)inst.H << 1), false, true); + } + + public static void BlIT1(CodeGenContext context, uint encoding) + { + InstSb26w1Imm10b16w10J1b13w1J2b11w1Imm11b0w11 inst = new(encoding); + + InstEmitFlow.Bl(context, ImmUtils.CombineSImm24Times2(inst.Imm11, inst.Imm10, inst.J1, inst.J2, inst.S), true, true); + } + + public static void BlIT2(CodeGenContext context, uint encoding) + { + InstSb26w1Imm10hb16w10J1b13w1J2b11w1Imm10lb1w10Hb0w1 inst = new(encoding); + + InstEmitFlow.Bl(context, ImmUtils.CombineSImm24Times4(inst.Imm10l, inst.Imm10h, inst.J1, inst.J2, inst.S), true, false); + } + + public static void BxA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rmb0w4 inst = new(encoding); + + InstEmitFlow.Bx(context, inst.Rm); + } + + public static void BxT1(CodeGenContext context, uint encoding) + { + InstRmb19w4 inst = new(encoding); + + InstEmitFlow.Bx(context, inst.Rm); + } + + public static void BxjA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rmb0w4 inst = new(encoding); + + InstEmitFlow.Bx(context, inst.Rm); + } + + public static void BxjT1(CodeGenContext context, uint encoding) + { + InstRmb16w4 inst = new(encoding); + + InstEmitFlow.Bx(context, inst.Rm); + } + + public static void CbnzT1(CodeGenContext context, uint encoding) + { + InstOpb27w1Ib25w1Imm5b19w5Rnb16w3 inst = new(encoding); + + InstEmitFlow.Cbnz(context, inst.Rn, (int)((inst.Imm5 << 1) | (inst.I << 6)), inst.Op != 0); + } + + public static void ClrbhbA1(CodeGenContext context, uint encoding) + { + _ = new InstCondb28w4(encoding); + + throw new NotImplementedException(); + } + + public static void ClrbhbT1(CodeGenContext context, uint encoding) + { + throw new NotImplementedException(); + } + + public static void ClrexA1(CodeGenContext context, uint encoding) + { + context.Arm64Assembler.Clrex(); + } + + public static void ClrexT1(CodeGenContext context, uint encoding) + { + context.Arm64Assembler.Clrex(); + } + + public static void ClzA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rdb12w4Rmb0w4 inst = new(encoding); + + InstEmitBit.Clz(context, inst.Rd, inst.Rm); + } + + public static void ClzT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitBit.Clz(context, inst.Rd, inst.Rm); + } + + public static void CmnIA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Imm12b0w12 inst = new(encoding); + + InstEmitAlu.CmnI(context, inst.Rn, ImmUtils.ExpandImm(inst.Imm12)); + } + + public static void CmnIT1(CodeGenContext context, uint encoding) + { + InstIb26w1Rnb16w4Imm3b12w3Imm8b0w8 inst = new(encoding); + + InstEmitAlu.CmnI(context, inst.Rn, ImmUtils.ExpandImm(inst.Imm8, inst.Imm3, inst.I)); + } + + public static void CmnRA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding); + + InstEmitAlu.CmnR(context, inst.Rn, inst.Rm, inst.Stype, inst.Imm5); + } + + public static void CmnRT1(CodeGenContext context, uint encoding) + { + InstRmb19w3Rnb16w3 inst = new(encoding); + + InstEmitAlu.CmnR(context, inst.Rn, inst.Rm, 0, 0); + } + + public static void CmnRT2(CodeGenContext context, uint encoding) + { + InstRnb16w4Imm3b12w3Imm2b6w2Stypeb4w2Rmb0w4 inst = new(encoding); + + InstEmitAlu.CmnR(context, inst.Rn, inst.Rm, inst.Stype, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3)); + } + + public static void CmnRrA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rsb8w4Stypeb5w2Rmb0w4 inst = new(encoding); + + InstEmitAlu.CmnRr(context, inst.Rn, inst.Rm, inst.Stype, inst.Rs); + } + + public static void CmpIA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Imm12b0w12 inst = new(encoding); + + InstEmitAlu.CmpI(context, inst.Rn, ImmUtils.ExpandImm(inst.Imm12)); + } + + public static void CmpIT1(CodeGenContext context, uint encoding) + { + InstRnb24w3Imm8b16w8 inst = new(encoding); + + InstEmitAlu.CmpI(context, inst.Rn, inst.Imm8); + } + + public static void CmpIT2(CodeGenContext context, uint encoding) + { + InstIb26w1Rnb16w4Imm3b12w3Imm8b0w8 inst = new(encoding); + + InstEmitAlu.CmpI(context, inst.Rn, ImmUtils.ExpandImm(inst.Imm8, inst.Imm3, inst.I)); + } + + public static void CmpRA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding); + + InstEmitAlu.CmpR(context, inst.Rn, inst.Rm, inst.Stype, inst.Imm5); + } + + public static void CmpRT1(CodeGenContext context, uint encoding) + { + InstRmb19w3Rnb16w3 inst = new(encoding); + + InstEmitAlu.CmpR(context, inst.Rn, inst.Rm, 0, 0); + } + + public static void CmpRT2(CodeGenContext context, uint encoding) + { + InstNb23w1Rmb19w4Rnb16w3 inst = new(encoding); + + InstEmitAlu.CmpR(context, inst.Rn | (inst.N << 3), inst.Rm, 0, 0); + } + + public static void CmpRT3(CodeGenContext context, uint encoding) + { + InstRnb16w4Imm3b12w3Imm2b6w2Stypeb4w2Rmb0w4 inst = new(encoding); + + InstEmitAlu.CmpR(context, inst.Rn, inst.Rm, inst.Stype, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3)); + } + + public static void CmpRrA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rsb8w4Stypeb5w2Rmb0w4 inst = new(encoding); + + InstEmitAlu.CmpRr(context, inst.Rn, inst.Rm, inst.Stype, inst.Rs); + } + + public static void CpsA1(CodeGenContext context, uint encoding) + { + InstImodb18w2Mb17w1Ab8w1Ib7w1Fb6w1Modeb0w5 inst = new(encoding); + + InstEmitSystem.Cps(context, inst.Imod, inst.M, inst.A, inst.I, inst.F, inst.Mode); + } + + public static void CpsT1(CodeGenContext context, uint encoding) + { + InstImb20w1Ab18w1Ib17w1Fb16w1 inst = new(encoding); + + InstEmitSystem.Cps(context, inst.Im, 0, inst.A, inst.I, inst.F, 0); + } + + public static void CpsT2(CodeGenContext context, uint encoding) + { + InstImodb9w2Mb8w1Ab7w1Ib6w1Fb5w1Modeb0w5 inst = new(encoding); + + InstEmitSystem.Cps(context, inst.Imod, inst.M, inst.A, inst.I, inst.F, inst.Mode); + } + + public static void Crc32A1(CodeGenContext context, uint encoding) + { + InstCondb28w4Szb21w2Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding); + + InstEmitCrc32.Crc32(context, inst.Rd, inst.Rn, inst.Rm, inst.Sz); + } + + public static void Crc32T1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Szb4w2Rmb0w4 inst = new(encoding); + + InstEmitCrc32.Crc32(context, inst.Rd, inst.Rn, inst.Rm, inst.Sz); + } + + public static void Crc32cA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Szb21w2Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding); + + InstEmitCrc32.Crc32c(context, inst.Rd, inst.Rn, inst.Rm, inst.Sz); + } + + public static void Crc32cT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Szb4w2Rmb0w4 inst = new(encoding); + + InstEmitCrc32.Crc32c(context, inst.Rd, inst.Rn, inst.Rm, inst.Sz); + } + + public static void CsdbA1(CodeGenContext context, uint encoding) + { + context.Arm64Assembler.Csdb(); + } + + public static void CsdbT1(CodeGenContext context, uint encoding) + { + context.Arm64Assembler.Csdb(); + } + + public static void DbgA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Optionb0w4 inst = new(encoding); + + InstEmitSystem.Dbg(context, inst.Option); + } + + public static void DbgT1(CodeGenContext context, uint encoding) + { + InstOptionb0w4 inst = new(encoding); + + InstEmitSystem.Dbg(context, inst.Option); + } + + public static void Dcps1T1(CodeGenContext context, uint encoding) + { + InstEmitSystem.PrivilegedInstruction(context, encoding); + } + + public static void Dcps2T1(CodeGenContext context, uint encoding) + { + InstEmitSystem.PrivilegedInstruction(context, encoding); + } + + public static void Dcps3T1(CodeGenContext context, uint encoding) + { + InstEmitSystem.PrivilegedInstruction(context, encoding); + } + + public static void DmbA1(CodeGenContext context, uint encoding) + { + InstOptionb0w4 inst = new(encoding); + + context.Arm64Assembler.Dmb(inst.Option); + } + + public static void DmbT1(CodeGenContext context, uint encoding) + { + InstOptionb0w4 inst = new(encoding); + + context.Arm64Assembler.Dmb(inst.Option); + } + + public static void DsbA1(CodeGenContext context, uint encoding) + { + InstOptionb0w4 inst = new(encoding); + + context.Arm64Assembler.Dsb(inst.Option); + } + + public static void DsbT1(CodeGenContext context, uint encoding) + { + InstOptionb0w4 inst = new(encoding); + + context.Arm64Assembler.Dsb(inst.Option); + } + + public static void EorIA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Sb20w1Rnb16w4Rdb12w4Imm12b0w12 inst = new(encoding); + + InstEmitAlu.EorI(context, inst.Rd, inst.Rn, ImmUtils.ExpandImm(inst.Imm12), ImmUtils.ExpandedImmRotated(inst.Imm12), inst.S != 0); + } + + public static void EorIT1(CodeGenContext context, uint encoding) + { + InstIb26w1Sb20w1Rnb16w4Imm3b12w3Rdb8w4Imm8b0w8 inst = new(encoding); + + InstEmitAlu.EorI(context, inst.Rd, inst.Rn, ImmUtils.ExpandImm(inst.Imm8, inst.Imm3, inst.I), ImmUtils.ExpandedImmRotated(inst.Imm8, inst.Imm3, inst.I), inst.S != 0); + } + + public static void EorRA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Sb20w1Rnb16w4Rdb12w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding); + + InstEmitAlu.EorR(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, inst.Imm5, inst.S != 0); + } + + public static void EorRT1(CodeGenContext context, uint encoding) + { + InstRmb19w3Rdnb16w3 inst = new(encoding); + + InstEmitAlu.EorR(context, inst.Rdn, inst.Rdn, inst.Rm, 0, 0, !context.InITBlock); + } + + public static void EorRT2(CodeGenContext context, uint encoding) + { + InstSb20w1Rnb16w4Imm3b12w3Rdb8w4Imm2b6w2Stypeb4w2Rmb0w4 inst = new(encoding); + + InstEmitAlu.EorR(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3), inst.S != 0); + } + + public static void EorRrA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Sb20w1Rnb16w4Rdb12w4Rsb8w4Stypeb5w2Rmb0w4 inst = new(encoding); + + InstEmitAlu.EorRr(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, inst.Rs, inst.S != 0); + } + + public static void EretA1(CodeGenContext context, uint encoding) + { + InstEmitSystem.PrivilegedInstruction(context, encoding); + } + + public static void EretT1(CodeGenContext context, uint encoding) + { + InstEmitSystem.PrivilegedInstruction(context, encoding); + } + + public static void EsbA1(CodeGenContext context, uint encoding) + { + context.Arm64Assembler.Esb(); + } + + public static void EsbT1(CodeGenContext context, uint encoding) + { + context.Arm64Assembler.Esb(); + } + + public static void FldmxA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Pb24w1Ub23w1Db22w1Wb21w1Rnb16w4Vdb12w4Imm871b1w7 inst = new(encoding); + + InstEmitNeonMemory.Vldm(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Imm871, inst.U != 0, inst.W != 0, singleRegs: false); + } + + public static void FldmxT1(CodeGenContext context, uint encoding) + { + InstPb24w1Ub23w1Db22w1Wb21w1Rnb16w4Vdb12w4Imm871b1w7 inst = new(encoding); + + InstEmitNeonMemory.Vldm(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Imm871, inst.U != 0, inst.W != 0, singleRegs: false); + } + + public static void FstmxA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Pb24w1Ub23w1Db22w1Wb21w1Rnb16w4Vdb12w4Imm871b1w7 inst = new(encoding); + + InstEmitNeonMemory.Vstm(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Imm871, inst.U != 0, inst.W != 0, singleRegs: false); + } + + public static void FstmxT1(CodeGenContext context, uint encoding) + { + InstPb24w1Ub23w1Db22w1Wb21w1Rnb16w4Vdb12w4Imm871b1w7 inst = new(encoding); + + InstEmitNeonMemory.Vstm(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Imm871, inst.U != 0, inst.W != 0, singleRegs: false); + } + + public static void HltA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Imm12b8w12Imm4b0w4 inst = new(encoding); + + InstEmitSystem.Hlt(context, ImmUtils.CombineImmU16(inst.Imm12, inst.Imm4)); + } + + public static void HltT1(CodeGenContext context, uint encoding) + { + InstImm6b16w6 inst = new(encoding); + + InstEmitSystem.Hlt(context, inst.Imm6); + } + + public static void HvcA1(CodeGenContext context, uint encoding) + { + InstEmitSystem.PrivilegedInstruction(context, encoding); + } + + public static void HvcT1(CodeGenContext context, uint encoding) + { + InstEmitSystem.PrivilegedInstruction(context, encoding); + } + + public static void IsbA1(CodeGenContext context, uint encoding) + { + InstOptionb0w4 inst = new(encoding); + + context.Arm64Assembler.Isb(inst.Option); + } + + public static void IsbT1(CodeGenContext context, uint encoding) + { + InstOptionb0w4 inst = new(encoding); + + context.Arm64Assembler.Isb(inst.Option); + } + + public static void ItT1(CodeGenContext context, uint encoding) + { + InstFirstcondb20w4Maskb16w4 inst = new(encoding); + + InstEmitFlow.It(context, inst.Firstcond, inst.Mask); + } + + public static void LdaA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rtb12w4 inst = new(encoding); + + InstEmitMemory.Lda(context, inst.Rt, inst.Rn); + } + + public static void LdaT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4 inst = new(encoding); + + InstEmitMemory.Lda(context, inst.Rt, inst.Rn); + } + + public static void LdabA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rtb12w4 inst = new(encoding); + + InstEmitMemory.Ldab(context, inst.Rt, inst.Rn); + } + + public static void LdabT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4 inst = new(encoding); + + InstEmitMemory.Ldab(context, inst.Rt, inst.Rn); + } + + public static void LdaexA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rtb12w4 inst = new(encoding); + + InstEmitMemory.Ldaex(context, inst.Rt, inst.Rn); + } + + public static void LdaexT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4 inst = new(encoding); + + InstEmitMemory.Ldaex(context, inst.Rt, inst.Rn); + } + + public static void LdaexbA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rtb12w4 inst = new(encoding); + + InstEmitMemory.Ldaexb(context, inst.Rt, inst.Rn); + } + + public static void LdaexbT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4 inst = new(encoding); + + InstEmitMemory.Ldaexb(context, inst.Rt, inst.Rn); + } + + public static void LdaexdA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rtb12w4 inst = new(encoding); + + InstEmitMemory.Ldaexd(context, inst.Rt, RegisterUtils.GetRt2(inst.Rt), inst.Rn); + } + + public static void LdaexdT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4Rt2b8w4 inst = new(encoding); + + InstEmitMemory.Ldaexd(context, inst.Rt, inst.Rt2, inst.Rn); + } + + public static void LdaexhA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rtb12w4 inst = new(encoding); + + InstEmitMemory.Ldaexh(context, inst.Rt, inst.Rn); + } + + public static void LdaexhT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4 inst = new(encoding); + + InstEmitMemory.Ldaexh(context, inst.Rt, inst.Rn); + } + + public static void LdahA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rtb12w4 inst = new(encoding); + + InstEmitMemory.Ldah(context, inst.Rt, inst.Rn); + } + + public static void LdahT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4 inst = new(encoding); + + InstEmitMemory.Ldah(context, inst.Rt, inst.Rn); + } + + public static void LdcIA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Imm8b0w8 inst = new(encoding); + + InstEmitMemory.LdcI(context, inst.Rn, (int)inst.Imm8 << 2, inst.P != 0, inst.U != 0, inst.W != 0); + } + + public static void LdcIT1(CodeGenContext context, uint encoding) + { + InstPb24w1Ub23w1Wb21w1Rnb16w4Imm8b0w8 inst = new(encoding); + + InstEmitMemory.LdcI(context, inst.Rn, (int)inst.Imm8 << 2, inst.P != 0, inst.U != 0, inst.W != 0); + } + + public static void LdcLA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Pb24w1Ub23w1Wb21w1Imm8b0w8 inst = new(encoding); + + InstEmitMemory.LdcL(context, inst.Imm8 << 2, inst.P != 0, inst.U != 0, inst.W != 0); + } + + public static void LdcLT1(CodeGenContext context, uint encoding) + { + InstPb24w1Ub23w1Wb21w1Imm8b0w8 inst = new(encoding); + + InstEmitMemory.LdcL(context, inst.Imm8 << 2, inst.P != 0, inst.U != 0, inst.W != 0); + } + + public static void LdmA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Wb21w1Rnb16w4RegisterListb0w16 inst = new(encoding); + + InstEmitMemory.Ldm(context, inst.Rn, inst.RegisterList, inst.W != 0); + } + + public static void LdmT1(CodeGenContext context, uint encoding) + { + InstRnb24w3RegisterListb16w8 inst = new(encoding); + + InstEmitMemory.Ldm(context, inst.Rn, inst.RegisterList, false); + } + + public static void LdmT2(CodeGenContext context, uint encoding) + { + InstWb21w1Rnb16w4Pb15w1Mb14w1RegisterListb0w14 inst = new(encoding); + + InstEmitMemory.Ldm(context, inst.Rn, ImmUtils.CombineRegisterList(inst.RegisterList, inst.M, inst.P), inst.W != 0); + } + + public static void LdmdaA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Wb21w1Rnb16w4RegisterListb0w16 inst = new(encoding); + + InstEmitMemory.Ldmda(context, inst.Rn, inst.RegisterList, inst.W != 0); + } + + public static void LdmdbA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Wb21w1Rnb16w4RegisterListb0w16 inst = new(encoding); + + InstEmitMemory.Ldmdb(context, inst.Rn, inst.RegisterList, inst.W != 0); + } + + public static void LdmdbT1(CodeGenContext context, uint encoding) + { + InstWb21w1Rnb16w4Pb15w1Mb14w1RegisterListb0w14 inst = new(encoding); + + InstEmitMemory.Ldmdb(context, inst.Rn, ImmUtils.CombineRegisterList(inst.RegisterList, inst.M, inst.P), inst.W != 0); + } + + public static void LdmibA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Wb21w1Rnb16w4RegisterListb0w16 inst = new(encoding); + + InstEmitMemory.Ldmib(context, inst.Rn, inst.RegisterList, inst.W != 0); + } + + public static void LdmEA1(CodeGenContext context, uint encoding) + { + InstEmitSystem.PrivilegedInstruction(context, encoding); + } + + public static void LdmUA1(CodeGenContext context, uint encoding) + { + InstEmitSystem.PrivilegedInstruction(context, encoding); + } + + public static void LdrbtA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Ub23w1Rnb16w4Rtb12w4Imm12b0w12 inst = new(encoding); + + InstEmitMemory.LdrbtI(context, inst.Rt, inst.Rn, (int)inst.Imm12, postIndex: true, inst.U != 0); + } + + public static void LdrbtA2(CodeGenContext context, uint encoding) + { + InstCondb28w4Ub23w1Rnb16w4Rtb12w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding); + + InstEmitMemory.LdrbtR(context, inst.Rt, inst.Rn, inst.Rm, inst.Stype, inst.Imm5, postIndex: true, inst.U != 0); + } + + public static void LdrbtT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4Imm8b0w8 inst = new(encoding); + + InstEmitMemory.LdrbtI(context, inst.Rt, inst.Rn, (int)inst.Imm8, postIndex: false, true); + } + + public static void LdrbIA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Imm12b0w12 inst = new(encoding); + + InstEmitMemory.LdrbI(context, inst.Rt, inst.Rn, (int)inst.Imm12, inst.P != 0, inst.U != 0, inst.W != 0); + } + + public static void LdrbIT1(CodeGenContext context, uint encoding) + { + InstImm5b22w5Rnb19w3Rtb16w3 inst = new(encoding); + + InstEmitMemory.LdrbI(context, inst.Rt, inst.Rn, (int)inst.Imm5, true, true, false); + } + + public static void LdrbIT2(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4Imm12b0w12 inst = new(encoding); + + InstEmitMemory.LdrbI(context, inst.Rt, inst.Rn, (int)inst.Imm12, true, true, false); + } + + public static void LdrbIT3(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4Pb10w1Ub9w1Wb8w1Imm8b0w8 inst = new(encoding); + + InstEmitMemory.LdrbI(context, inst.Rt, inst.Rn, (int)inst.Imm8, inst.P != 0, inst.U != 0, inst.W != 0); + } + + public static void LdrbLA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Pb24w1Ub23w1Wb21w1Rtb12w4Imm12b0w12 inst = new(encoding); + + InstEmitMemory.LdrbL(context, inst.Rt, inst.Imm12, inst.P != 0, inst.U != 0, inst.W != 0); + } + + public static void LdrbLT1(CodeGenContext context, uint encoding) + { + InstUb23w1Rtb12w4Imm12b0w12 inst = new(encoding); + + InstEmitMemory.LdrbL(context, inst.Rt, inst.Imm12, true, inst.U != 0, false); + } + + public static void LdrbRA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding); + + InstEmitMemory.LdrbR(context, inst.Rt, inst.Rn, inst.Rm, inst.Stype, inst.Imm5, inst.P != 0, inst.U != 0, inst.W != 0); + } + + public static void LdrbRT1(CodeGenContext context, uint encoding) + { + InstRmb22w3Rnb19w3Rtb16w3 inst = new(encoding); + + InstEmitMemory.LdrbR(context, inst.Rt, inst.Rn, inst.Rm, 0, 0, true, true, false); + } + + public static void LdrbRT2(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4Imm2b4w2Rmb0w4 inst = new(encoding); + + InstEmitMemory.LdrbR(context, inst.Rt, inst.Rn, inst.Rm, 0, inst.Imm2, true, true, false); + } + + public static void LdrdIA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Imm4hb8w4Imm4lb0w4 inst = new(encoding); + + InstEmitMemory.LdrdI(context, inst.Rt, RegisterUtils.GetRt2(inst.Rt), inst.Rn, ImmUtils.CombineImmU8(inst.Imm4l, inst.Imm4h), inst.P != 0, inst.U != 0, inst.W != 0); + } + + public static void LdrdIT1(CodeGenContext context, uint encoding) + { + InstPb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Rt2b8w4Imm8b0w8 inst = new(encoding); + + InstEmitMemory.LdrdI(context, inst.Rt, inst.Rt2, inst.Rn, inst.Imm8 << 2, inst.P != 0, inst.U != 0, inst.W != 0); + } + + public static void LdrdLA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Ub23w1Rtb12w4Imm4hb8w4Imm4lb0w4 inst = new(encoding); + + InstEmitMemory.LdrdL(context, inst.Rt, RegisterUtils.GetRt2(inst.Rt), ImmUtils.CombineImmU8(inst.Imm4l, inst.Imm4h), true, inst.U != 0, false); + } + + public static void LdrdLT1(CodeGenContext context, uint encoding) + { + InstPb24w1Ub23w1Wb21w1Rtb12w4Rt2b8w4Imm8b0w8 inst = new(encoding); + + InstEmitMemory.LdrdL(context, inst.Rt, inst.Rt2, inst.Imm8, inst.P != 0, inst.U != 0, inst.W != 0); + } + + public static void LdrdRA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Rmb0w4 inst = new(encoding); + + InstEmitMemory.LdrdR(context, inst.Rt, RegisterUtils.GetRt2(inst.Rt), inst.Rn, inst.Rm, inst.P != 0, inst.U != 0, inst.W != 0); + } + + public static void LdrexA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rtb12w4 inst = new(encoding); + + InstEmitMemory.Ldrex(context, inst.Rt, inst.Rn); + } + + public static void LdrexT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4Imm8b0w8 inst = new(encoding); + + InstEmitMemory.Ldrex(context, inst.Rt, inst.Rn); + } + + public static void LdrexbA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rtb12w4 inst = new(encoding); + + InstEmitMemory.Ldrexb(context, inst.Rt, inst.Rn); + } + + public static void LdrexbT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4 inst = new(encoding); + + InstEmitMemory.Ldrexb(context, inst.Rt, inst.Rn); + } + + public static void LdrexdA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rtb12w4 inst = new(encoding); + + InstEmitMemory.Ldrexd(context, inst.Rt, RegisterUtils.GetRt2(inst.Rt), inst.Rn); + } + + public static void LdrexdT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4Rt2b8w4 inst = new(encoding); + + InstEmitMemory.Ldrexd(context, inst.Rt, inst.Rt2, inst.Rn); + } + + public static void LdrexhA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rtb12w4 inst = new(encoding); + + InstEmitMemory.Ldrexh(context, inst.Rt, inst.Rn); + } + + public static void LdrexhT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4 inst = new(encoding); + + InstEmitMemory.Ldrexh(context, inst.Rt, inst.Rn); + } + + public static void LdrhtA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Ub23w1Rnb16w4Rtb12w4Imm4hb8w4Imm4lb0w4 inst = new(encoding); + + InstEmitMemory.LdrhtI(context, inst.Rt, inst.Rn, (int)ImmUtils.CombineImmU8(inst.Imm4l, inst.Imm4h), postIndex: true, inst.U != 0); + } + + public static void LdrhtA2(CodeGenContext context, uint encoding) + { + InstCondb28w4Ub23w1Rnb16w4Rtb12w4Rmb0w4 inst = new(encoding); + + InstEmitMemory.LdrhtR(context, inst.Rt, inst.Rn, inst.Rm, postIndex: true, inst.U != 0); + } + + public static void LdrhtT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4Imm8b0w8 inst = new(encoding); + + InstEmitMemory.LdrhtI(context, inst.Rt, inst.Rn, (int)inst.Imm8, postIndex: false, true); + } + + public static void LdrhIA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Imm4hb8w4Imm4lb0w4 inst = new(encoding); + + InstEmitMemory.LdrhI(context, inst.Rt, inst.Rn, (int)ImmUtils.CombineImmU8(inst.Imm4l, inst.Imm4h), inst.P != 0, inst.U != 0, inst.W != 0); + } + + public static void LdrhIT1(CodeGenContext context, uint encoding) + { + InstImm5b22w5Rnb19w3Rtb16w3 inst = new(encoding); + + InstEmitMemory.LdrhI(context, inst.Rt, inst.Rn, (int)inst.Imm5 << 1, true, true, false); + } + + public static void LdrhIT2(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4Imm12b0w12 inst = new(encoding); + + InstEmitMemory.LdrhI(context, inst.Rt, inst.Rn, (int)inst.Imm12, true, true, false); + } + + public static void LdrhIT3(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4Pb10w1Ub9w1Wb8w1Imm8b0w8 inst = new(encoding); + + InstEmitMemory.LdrhI(context, inst.Rt, inst.Rn, (int)inst.Imm8, inst.P != 0, inst.U != 0, inst.W != 0); + } + + public static void LdrhLA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Pb24w1Ub23w1Wb21w1Rtb12w4Imm4hb8w4Imm4lb0w4 inst = new(encoding); + + InstEmitMemory.LdrhL(context, inst.Rt, ImmUtils.CombineImmU8(inst.Imm4l, inst.Imm4h), inst.P != 0, inst.U != 0, inst.W != 0); + } + + public static void LdrhLT1(CodeGenContext context, uint encoding) + { + InstUb23w1Rtb12w4Imm12b0w12 inst = new(encoding); + + InstEmitMemory.LdrhL(context, inst.Rt, inst.Imm12, true, inst.U != 0, false); + } + + public static void LdrhRA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Rmb0w4 inst = new(encoding); + + InstEmitMemory.LdrhR(context, inst.Rt, inst.Rn, inst.Rm, 0, 0, inst.P != 0, inst.U != 0, inst.W != 0); + } + + public static void LdrhRT1(CodeGenContext context, uint encoding) + { + InstRmb22w3Rnb19w3Rtb16w3 inst = new(encoding); + + InstEmitMemory.LdrhR(context, inst.Rt, inst.Rn, inst.Rm, 0, 0, true, true, false); + } + + public static void LdrhRT2(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4Imm2b4w2Rmb0w4 inst = new(encoding); + + InstEmitMemory.LdrhR(context, inst.Rt, inst.Rn, inst.Rm, 0, inst.Imm2, true, true, false); + } + + public static void LdrsbtA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Ub23w1Rnb16w4Rtb12w4Imm4hb8w4Imm4lb0w4 inst = new(encoding); + + InstEmitMemory.LdrsbtI(context, inst.Rt, inst.Rn, (int)ImmUtils.CombineImmU8(inst.Imm4l, inst.Imm4h), postIndex: true, inst.U != 0); + } + + public static void LdrsbtA2(CodeGenContext context, uint encoding) + { + InstCondb28w4Ub23w1Rnb16w4Rtb12w4Rmb0w4 inst = new(encoding); + + InstEmitMemory.LdrsbtR(context, inst.Rt, inst.Rn, inst.Rm, postIndex: true, inst.U != 0); + } + + public static void LdrsbtT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4Imm8b0w8 inst = new(encoding); + + InstEmitMemory.LdrsbtI(context, inst.Rt, inst.Rn, (int)inst.Imm8, postIndex: false, true); + } + + public static void LdrsbIA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Imm4hb8w4Imm4lb0w4 inst = new(encoding); + + InstEmitMemory.LdrsbI(context, inst.Rt, inst.Rn, (int)ImmUtils.CombineImmU8(inst.Imm4l, inst.Imm4h), inst.P != 0, inst.U != 0, inst.W != 0); + } + + public static void LdrsbIT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4Imm12b0w12 inst = new(encoding); + + InstEmitMemory.LdrsbI(context, inst.Rt, inst.Rn, (int)inst.Imm12, true, true, false); + } + + public static void LdrsbIT2(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4Pb10w1Ub9w1Wb8w1Imm8b0w8 inst = new(encoding); + + InstEmitMemory.LdrsbI(context, inst.Rt, inst.Rn, (int)inst.Imm8, inst.P != 0, inst.U != 0, inst.W != 0); + } + + public static void LdrsbLA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Pb24w1Ub23w1Wb21w1Rtb12w4Imm4hb8w4Imm4lb0w4 inst = new(encoding); + + InstEmitMemory.LdrsbL(context, inst.Rt, ImmUtils.CombineImmU8(inst.Imm4l, inst.Imm4h), inst.P != 0, inst.U != 0, inst.W != 0); + } + + public static void LdrsbLT1(CodeGenContext context, uint encoding) + { + InstUb23w1Rtb12w4Imm12b0w12 inst = new(encoding); + + InstEmitMemory.LdrsbL(context, inst.Rt, inst.Imm12, true, inst.U != 0, false); + } + + public static void LdrsbRA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Rmb0w4 inst = new(encoding); + + InstEmitMemory.LdrsbR(context, inst.Rt, inst.Rn, inst.Rm, 0, 0, inst.P != 0, inst.U != 0, inst.W != 0); + } + + public static void LdrsbRT1(CodeGenContext context, uint encoding) + { + InstRmb22w3Rnb19w3Rtb16w3 inst = new(encoding); + + InstEmitMemory.LdrsbR(context, inst.Rt, inst.Rn, inst.Rm, 0, 0, true, true, false); + } + + public static void LdrsbRT2(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4Imm2b4w2Rmb0w4 inst = new(encoding); + + InstEmitMemory.LdrsbR(context, inst.Rt, inst.Rn, inst.Rm, 0, inst.Imm2, true, true, false); + } + + public static void LdrshtA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Ub23w1Rnb16w4Rtb12w4Imm4hb8w4Imm4lb0w4 inst = new(encoding); + + InstEmitMemory.LdrshtI(context, inst.Rt, inst.Rn, (int)ImmUtils.CombineImmU8(inst.Imm4l, inst.Imm4h), postIndex: true, inst.U != 0); + } + + public static void LdrshtA2(CodeGenContext context, uint encoding) + { + InstCondb28w4Ub23w1Rnb16w4Rtb12w4Rmb0w4 inst = new(encoding); + + InstEmitMemory.LdrshtR(context, inst.Rt, inst.Rn, inst.Rm, postIndex: true, inst.U != 0); + } + + public static void LdrshtT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4Imm8b0w8 inst = new(encoding); + + InstEmitMemory.LdrshtI(context, inst.Rt, inst.Rn, (int)inst.Imm8, postIndex: false, true); + } + + public static void LdrshIA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Imm4hb8w4Imm4lb0w4 inst = new(encoding); + + InstEmitMemory.LdrshI(context, inst.Rt, inst.Rn, (int)ImmUtils.CombineImmU8(inst.Imm4l, inst.Imm4h), inst.P != 0, inst.U != 0, inst.W != 0); + } + + public static void LdrshIT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4Imm12b0w12 inst = new(encoding); + + InstEmitMemory.LdrshI(context, inst.Rt, inst.Rn, (int)inst.Imm12, true, true, false); + } + + public static void LdrshIT2(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4Pb10w1Ub9w1Wb8w1Imm8b0w8 inst = new(encoding); + + InstEmitMemory.LdrshI(context, inst.Rt, inst.Rn, (int)inst.Imm8, inst.P != 0, inst.U != 0, inst.W != 0); + } + + public static void LdrshLA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Pb24w1Ub23w1Wb21w1Rtb12w4Imm4hb8w4Imm4lb0w4 inst = new(encoding); + + InstEmitMemory.LdrshL(context, inst.Rt, ImmUtils.CombineImmU8(inst.Imm4l, inst.Imm4h), inst.P != 0, inst.U != 0, inst.W != 0); + } + + public static void LdrshLT1(CodeGenContext context, uint encoding) + { + InstUb23w1Rtb12w4Imm12b0w12 inst = new(encoding); + + InstEmitMemory.LdrshL(context, inst.Rt, inst.Imm12, true, inst.U != 0, false); + } + + public static void LdrshRA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Rmb0w4 inst = new(encoding); + + InstEmitMemory.LdrshR(context, inst.Rt, inst.Rn, inst.Rm, 0, 0, inst.P != 0, inst.U != 0, inst.W != 0); + } + + public static void LdrshRT1(CodeGenContext context, uint encoding) + { + InstRmb22w3Rnb19w3Rtb16w3 inst = new(encoding); + + InstEmitMemory.LdrshR(context, inst.Rt, inst.Rn, inst.Rm, 0, 0, true, true, false); + } + + public static void LdrshRT2(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4Imm2b4w2Rmb0w4 inst = new(encoding); + + InstEmitMemory.LdrshR(context, inst.Rt, inst.Rn, inst.Rm, 0, inst.Imm2, true, true, false); + } + + public static void LdrtA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Ub23w1Rnb16w4Rtb12w4Imm12b0w12 inst = new(encoding); + + InstEmitMemory.LdrtI(context, inst.Rt, inst.Rn, (int)inst.Imm12, postIndex: true, inst.U != 0); + } + + public static void LdrtA2(CodeGenContext context, uint encoding) + { + InstCondb28w4Ub23w1Rnb16w4Rtb12w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding); + + InstEmitMemory.LdrtR(context, inst.Rt, inst.Rn, inst.Rm, inst.Stype, inst.Imm5, postIndex: true, inst.U != 0); + } + + public static void LdrtT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4Imm8b0w8 inst = new(encoding); + + InstEmitMemory.LdrtI(context, inst.Rt, inst.Rn, (int)inst.Imm8, postIndex: false, true); + } + + public static void LdrIA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Imm12b0w12 inst = new(encoding); + + InstEmitMemory.LdrI(context, inst.Rt, inst.Rn, (int)inst.Imm12, inst.P != 0, inst.U != 0, inst.W != 0); + } + + public static void LdrIT1(CodeGenContext context, uint encoding) + { + InstImm5b22w5Rnb19w3Rtb16w3 inst = new(encoding); + + InstEmitMemory.LdrI(context, inst.Rt, inst.Rn, (int)inst.Imm5 << 2, true, true, false); + } + + public static void LdrIT2(CodeGenContext context, uint encoding) + { + InstRtb24w3Imm8b16w8 inst = new(encoding); + + InstEmitMemory.LdrI(context, inst.Rt, RegisterUtils.SpRegister, (int)inst.Imm8 << 2, true, true, false); + } + + public static void LdrIT3(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4Imm12b0w12 inst = new(encoding); + + InstEmitMemory.LdrI(context, inst.Rt, inst.Rn, (int)inst.Imm12, true, true, false); + } + + public static void LdrIT4(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4Pb10w1Ub9w1Wb8w1Imm8b0w8 inst = new(encoding); + + InstEmitMemory.LdrI(context, inst.Rt, inst.Rn, (int)inst.Imm8, inst.P != 0, inst.U != 0, inst.W != 0); + } + + public static void LdrLA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Pb24w1Ub23w1Wb21w1Rtb12w4Imm12b0w12 inst = new(encoding); + + InstEmitMemory.LdrL(context, inst.Rt, inst.Imm12, inst.P != 0, inst.U != 0, inst.W != 0); + } + + public static void LdrLT1(CodeGenContext context, uint encoding) + { + InstRtb24w3Imm8b16w8 inst = new(encoding); + + InstEmitMemory.LdrL(context, inst.Rt, inst.Imm8 << 2, true, true, false); + } + + public static void LdrLT2(CodeGenContext context, uint encoding) + { + InstUb23w1Rtb12w4Imm12b0w12 inst = new(encoding); + + InstEmitMemory.LdrL(context, inst.Rt, inst.Imm12, true, inst.U != 0, false); + } + + public static void LdrRA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding); + + InstEmitMemory.LdrR(context, inst.Rt, inst.Rn, inst.Rm, inst.Stype, inst.Imm5, inst.P != 0, inst.U != 0, inst.W != 0); + } + + public static void LdrRT1(CodeGenContext context, uint encoding) + { + InstRmb22w3Rnb19w3Rtb16w3 inst = new(encoding); + + InstEmitMemory.LdrR(context, inst.Rt, inst.Rn, inst.Rm, 0, 0, true, true, false); + } + + public static void LdrRT2(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4Imm2b4w2Rmb0w4 inst = new(encoding); + + InstEmitMemory.LdrR(context, inst.Rt, inst.Rn, inst.Rm, 0, inst.Imm2, true, true, false); + } + + public static void McrA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Opc1b21w3Crnb16w4Rtb12w4Coproc0b8w1Opc2b5w3Crmb0w4 inst = new(encoding); + + InstEmitSystem.Mcr(context, encoding, inst.Coproc0 | 0xe, inst.Opc1, inst.Rt, inst.Crn, inst.Crm, inst.Opc2); + } + + public static void McrT1(CodeGenContext context, uint encoding) + { + InstOpc1b21w3Crnb16w4Rtb12w4Coproc0b8w1Opc2b5w3Crmb0w4 inst = new(encoding); + + InstEmitSystem.Mcr(context, encoding, inst.Coproc0 | 0xe, inst.Opc1, inst.Rt, inst.Crn, inst.Crm, inst.Opc2); + } + + public static void McrrA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rt2b16w4Rtb12w4Coproc0b8w1Opc1b4w4Crmb0w4 inst = new(encoding); + + InstEmitSystem.Mcrr(context, encoding, inst.Coproc0 | 0xe, inst.Opc1, inst.Rt, inst.Crm); + } + + public static void McrrT1(CodeGenContext context, uint encoding) + { + InstRt2b16w4Rtb12w4Coproc0b8w1Opc1b4w4Crmb0w4 inst = new(encoding); + + InstEmitSystem.Mcrr(context, encoding, inst.Coproc0 | 0xe, inst.Opc1, inst.Rt, inst.Crm); + } + + public static void MlaA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Sb20w1Rdb16w4Rab12w4Rmb8w4Rnb0w4 inst = new(encoding); + + InstEmitMultiply.Mla(context, inst.Rd, inst.Rn, inst.Rm, inst.Ra); + } + + public static void MlaT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rab12w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitMultiply.Mla(context, inst.Rd, inst.Rn, inst.Rm, inst.Ra); + } + + public static void MlsA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rdb16w4Rab12w4Rmb8w4Rnb0w4 inst = new(encoding); + + InstEmitMultiply.Mls(context, inst.Rd, inst.Rn, inst.Rm, inst.Ra); + } + + public static void MlsT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rab12w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitMultiply.Mls(context, inst.Rd, inst.Rn, inst.Rm, inst.Ra); + } + + public static void MovtA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Imm4b16w4Rdb12w4Imm12b0w12 inst = new(encoding); + + InstEmitMove.Movt(context, inst.Rd, ImmUtils.CombineImmU16(inst.Imm12, inst.Imm4)); + } + + public static void MovtT1(CodeGenContext context, uint encoding) + { + InstIb26w1Imm4b16w4Imm3b12w3Rdb8w4Imm8b0w8 inst = new(encoding); + + InstEmitMove.Movt(context, inst.Rd, ImmUtils.CombineImmU16(inst.Imm8, inst.Imm3, inst.I, inst.Imm4)); + } + + public static void MovIA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Sb20w1Rdb12w4Imm12b0w12 inst = new(encoding); + + InstEmitMove.MovI(context, inst.Rd, ImmUtils.ExpandImm(inst.Imm12), ImmUtils.ExpandedImmRotated(inst.Imm12), inst.S != 0); + } + + public static void MovIA2(CodeGenContext context, uint encoding) + { + InstCondb28w4Imm4b16w4Rdb12w4Imm12b0w12 inst = new(encoding); + + InstEmitMove.MovI(context, inst.Rd, ImmUtils.CombineImmU16(inst.Imm12, inst.Imm4), false, false); + } + + public static void MovIT1(CodeGenContext context, uint encoding) + { + InstRdb24w3Imm8b16w8 inst = new(encoding); + + InstEmitMove.MovI(context, inst.Rd, inst.Imm8, false, !context.InITBlock); + } + + public static void MovIT2(CodeGenContext context, uint encoding) + { + InstIb26w1Sb20w1Imm3b12w3Rdb8w4Imm8b0w8 inst = new(encoding); + + InstEmitMove.MovI(context, inst.Rd, ImmUtils.ExpandImm(inst.Imm8, inst.Imm3, inst.I), ImmUtils.ExpandedImmRotated(inst.Imm8, inst.Imm3, inst.I), inst.S != 0); + } + + public static void MovIT3(CodeGenContext context, uint encoding) + { + InstIb26w1Imm4b16w4Imm3b12w3Rdb8w4Imm8b0w8 inst = new(encoding); + + InstEmitMove.MovI(context, inst.Rd, ImmUtils.CombineImmU16(inst.Imm8, inst.Imm3, inst.I, inst.Imm4), false, false); + } + + public static void MovRA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Sb20w1Rdb12w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding); + + InstEmitMove.MovR(context, inst.Cond, inst.Rd, inst.Rm, inst.Stype, inst.Imm5, inst.S != 0); + } + + public static void MovRT1(CodeGenContext context, uint encoding) + { + InstDb23w1Rmb19w4Rdb16w3 inst = new(encoding); + + InstEmitMove.MovR(context, inst.Rd | (inst.D << 3), inst.Rm, 0, 0, false); + } + + public static void MovRT2(CodeGenContext context, uint encoding) + { + InstOpb27w2Imm5b22w5Rmb19w3Rdb16w3 inst = new(encoding); + + InstEmitMove.MovR(context, inst.Rd, inst.Rm, inst.Op, inst.Imm5, !context.InITBlock); + } + + public static void MovRT3(CodeGenContext context, uint encoding) + { + InstSb20w1Imm3b12w3Rdb8w4Imm2b6w2Stypeb4w2Rmb0w4 inst = new(encoding); + + InstEmitMove.MovR(context, inst.Rd, inst.Rm, inst.Stype, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3), inst.S != 0); + } + + public static void MovRrA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Sb20w1Rdb12w4Rsb8w4Stypeb5w2Rmb0w4 inst = new(encoding); + + InstEmitMove.MovRr(context, inst.Rd, inst.Rm, inst.Stype, inst.Rs, inst.S != 0); + } + + public static void MovRrT1(CodeGenContext context, uint encoding) + { + InstRsb19w3Rdmb16w3 inst = new(encoding); + + InstEmitMove.MovRr(context, inst.Rdm, inst.Rdm, ((encoding >> 7) & 2) | ((encoding >> 6) & 1), inst.Rs, !context.InITBlock); + } + + public static void MovRrT2(CodeGenContext context, uint encoding) + { + InstStypeb21w2Sb20w1Rmb16w4Rdb8w4Rsb0w4 inst = new(encoding); + + InstEmitMove.MovRr(context, inst.Rd, inst.Rm, inst.Stype, inst.Rs, inst.S != 0); + } + + public static void MrcA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Opc1b21w3Crnb16w4Rtb12w4Coproc0b8w1Opc2b5w3Crmb0w4 inst = new(encoding); + + InstEmitSystem.Mrc(context, encoding, inst.Coproc0 | 0xe, inst.Opc1, inst.Rt, inst.Crn, inst.Crm, inst.Opc2); + } + + public static void MrcT1(CodeGenContext context, uint encoding) + { + InstOpc1b21w3Crnb16w4Rtb12w4Coproc0b8w1Opc2b5w3Crmb0w4 inst = new(encoding); + + InstEmitSystem.Mrc(context, encoding, inst.Coproc0 | 0xe, inst.Opc1, inst.Rt, inst.Crn, inst.Crm, inst.Opc2); + } + + public static void MrrcA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rt2b16w4Rtb12w4Coproc0b8w1Opc1b4w4Crmb0w4 inst = new(encoding); + + InstEmitSystem.Mrrc(context, encoding, inst.Coproc0 | 0xe, inst.Opc1, inst.Rt, inst.Rt2, inst.Crm); + } + + public static void MrrcT1(CodeGenContext context, uint encoding) + { + InstRt2b16w4Rtb12w4Coproc0b8w1Opc1b4w4Crmb0w4 inst = new(encoding); + + InstEmitSystem.Mrrc(context, encoding, inst.Coproc0 | 0xe, inst.Opc1, inst.Rt, inst.Rt2, inst.Crm); + } + + public static void MrsA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rb22w1Rdb12w4 inst = new(encoding); + + InstEmitSystem.Mrs(context, inst.Rd, inst.R != 0); + } + + public static void MrsT1(CodeGenContext context, uint encoding) + { + InstRb20w1Rdb8w4 inst = new(encoding); + + InstEmitSystem.Mrs(context, inst.Rd, inst.R != 0); + } + + public static void MrsBrA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rb22w1M1b16w4Rdb12w4Mb8w1 inst = new(encoding); + + InstEmitSystem.MrsBr(context, inst.Rd, inst.M1 | (inst.M << 4), inst.R != 0); + } + + public static void MrsBrT1(CodeGenContext context, uint encoding) + { + InstRb20w1M1b16w4Rdb8w4Mb4w1 inst = new(encoding); + + InstEmitSystem.MrsBr(context, inst.Rd, inst.M1 | (inst.M << 4), inst.R != 0); + } + + public static void MsrBrA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rb22w1M1b16w4Mb8w1Rnb0w4 inst = new(encoding); + + InstEmitSystem.MsrBr(context, inst.Rn, inst.M1 | (inst.M << 4), inst.R != 0); + } + + public static void MsrBrT1(CodeGenContext context, uint encoding) + { + InstRb20w1Rnb16w4M1b8w4Mb4w1 inst = new(encoding); + + InstEmitSystem.MsrBr(context, inst.Rn, inst.M1 | (inst.M << 4), inst.R != 0); + } + + public static void MsrIA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rb22w1Maskb16w4Imm12b0w12 inst = new(encoding); + + InstEmitSystem.MsrI(context, inst.Imm12, inst.Mask, inst.R != 0); + } + + public static void MsrRA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rb22w1Maskb16w4Rnb0w4 inst = new(encoding); + + InstEmitSystem.MsrR(context, inst.Rn, inst.Mask, inst.R != 0); + } + + public static void MsrRT1(CodeGenContext context, uint encoding) + { + InstRb20w1Rnb16w4Maskb8w4 inst = new(encoding); + + InstEmitSystem.MsrR(context, inst.Rn, inst.Mask, inst.R != 0); + } + + public static void MulA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Sb20w1Rdb16w4Rmb8w4Rnb0w4 inst = new(encoding); + + InstEmitMultiply.Mul(context, inst.Rd, inst.Rn, inst.Rm, inst.S != 0); + } + + public static void MulT1(CodeGenContext context, uint encoding) + { + InstRnb19w3Rdmb16w3 inst = new(encoding); + + InstEmitMultiply.Mul(context, inst.Rdm, inst.Rn, inst.Rdm, !context.InITBlock); + } + + public static void MulT2(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitMultiply.Mul(context, inst.Rd, inst.Rn, inst.Rm, false); + } + + public static void MvnIA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Sb20w1Rdb12w4Imm12b0w12 inst = new(encoding); + + InstEmitMove.MvnI(context, inst.Rd, ImmUtils.ExpandImm(inst.Imm12), ImmUtils.ExpandedImmRotated(inst.Imm12), inst.S != 0); + } + + public static void MvnIT1(CodeGenContext context, uint encoding) + { + InstIb26w1Sb20w1Imm3b12w3Rdb8w4Imm8b0w8 inst = new(encoding); + + InstEmitMove.MvnI(context, inst.Rd, ImmUtils.ExpandImm(inst.Imm8, inst.Imm3, inst.I), ImmUtils.ExpandedImmRotated(inst.Imm8, inst.Imm3, inst.I), inst.S != 0); + } + + public static void MvnRA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Sb20w1Rdb12w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding); + + InstEmitMove.MvnR(context, inst.Rd, inst.Rm, inst.Stype, inst.Imm5, inst.S != 0); + } + + public static void MvnRT1(CodeGenContext context, uint encoding) + { + InstRmb19w3Rdb16w3 inst = new(encoding); + + InstEmitMove.MvnR(context, inst.Rd, inst.Rm, 0, 0, !context.InITBlock); + } + + public static void MvnRT2(CodeGenContext context, uint encoding) + { + InstSb20w1Imm3b12w3Rdb8w4Imm2b6w2Stypeb4w2Rmb0w4 inst = new(encoding); + + InstEmitMove.MvnR(context, inst.Rd, inst.Rm, inst.Stype, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3), inst.S != 0); + } + + public static void MvnRrA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Sb20w1Rdb12w4Rsb8w4Stypeb5w2Rmb0w4 inst = new(encoding); + + InstEmitMove.MvnRr(context, inst.Rd, inst.Rm, inst.Stype, inst.Rs, inst.S != 0); + } + + public static void NopA1(CodeGenContext context, uint encoding) + { + } + + public static void NopT1(CodeGenContext context, uint encoding) + { + } + + public static void NopT2(CodeGenContext context, uint encoding) + { + } + + public static void OrnIT1(CodeGenContext context, uint encoding) + { + InstIb26w1Sb20w1Rnb16w4Imm3b12w3Rdb8w4Imm8b0w8 inst = new(encoding); + + InstEmitAlu.OrnI(context, inst.Rd, inst.Rn, ImmUtils.ExpandImm(inst.Imm8, inst.Imm3, inst.I), ImmUtils.ExpandedImmRotated(inst.Imm8, inst.Imm3, inst.I), inst.S != 0); + } + + public static void OrnRT1(CodeGenContext context, uint encoding) + { + InstSb20w1Rnb16w4Imm3b12w3Rdb8w4Imm2b6w2Stypeb4w2Rmb0w4 inst = new(encoding); + + InstEmitAlu.OrnR(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3), inst.S != 0); + } + + public static void OrrIA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Sb20w1Rnb16w4Rdb12w4Imm12b0w12 inst = new(encoding); + + InstEmitAlu.OrrI(context, inst.Rd, inst.Rn, ImmUtils.ExpandImm(inst.Imm12), ImmUtils.ExpandedImmRotated(inst.Imm12), inst.S != 0); + } + + public static void OrrIT1(CodeGenContext context, uint encoding) + { + InstIb26w1Sb20w1Rnb16w4Imm3b12w3Rdb8w4Imm8b0w8 inst = new(encoding); + + InstEmitAlu.OrrI(context, inst.Rd, inst.Rn, ImmUtils.ExpandImm(inst.Imm8, inst.Imm3, inst.I), ImmUtils.ExpandedImmRotated(inst.Imm8, inst.Imm3, inst.I), inst.S != 0); + } + + public static void OrrRA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Sb20w1Rnb16w4Rdb12w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding); + + InstEmitAlu.OrrR(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, inst.Imm5, inst.S != 0); + } + + public static void OrrRT1(CodeGenContext context, uint encoding) + { + InstRmb19w3Rdnb16w3 inst = new(encoding); + + InstEmitAlu.OrrR(context, inst.Rdn, inst.Rdn, inst.Rm, 0, 0, !context.InITBlock); + } + + public static void OrrRT2(CodeGenContext context, uint encoding) + { + InstSb20w1Rnb16w4Imm3b12w3Rdb8w4Imm2b6w2Stypeb4w2Rmb0w4 inst = new(encoding); + + InstEmitAlu.OrrR(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3), inst.S != 0); + } + + public static void OrrRrA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Sb20w1Rnb16w4Rdb12w4Rsb8w4Stypeb5w2Rmb0w4 inst = new(encoding); + + InstEmitAlu.OrrRr(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, inst.Rs, inst.S != 0); + } + + public static void PkhA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Imm5b7w5Tbb6w1Rmb0w4 inst = new(encoding); + + InstEmitMove.Pkh(context, inst.Rd, inst.Rn, inst.Rm, inst.Tb != 0, inst.Imm5); + } + + public static void PkhT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Imm3b12w3Rdb8w4Imm2b6w2Tbb5w1Rmb0w4 inst = new(encoding); + + InstEmitMove.Pkh(context, inst.Rd, inst.Rn, inst.Rm, inst.Tb != 0, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3)); + } + + public static void PldIA1(CodeGenContext context, uint encoding) + { + InstUb23w1Rb22w1Rnb16w4Imm12b0w12 inst = new(encoding); + + InstEmitMemory.PldI(context, inst.Rn, inst.Imm12, inst.U != 0, inst.R != 0); + } + + public static void PldIT1(CodeGenContext context, uint encoding) + { + InstWb21w1Rnb16w4Imm12b0w12 inst = new(encoding); + + InstEmitMemory.PldI(context, inst.Rn, inst.Imm12, true, inst.W == 0); + } + + public static void PldIT2(CodeGenContext context, uint encoding) + { + InstWb21w1Rnb16w4Imm8b0w8 inst = new(encoding); + + InstEmitMemory.PldI(context, inst.Rn, inst.Imm8, false, inst.W == 0); + } + + public static void PldLA1(CodeGenContext context, uint encoding) + { + InstUb23w1Imm12b0w12 inst = new(encoding); + + InstEmitMemory.PldL(context, inst.Imm12, inst.U != 0); + } + + public static void PldLT1(CodeGenContext context, uint encoding) + { + InstUb23w1Imm12b0w12 inst = new(encoding); + + InstEmitMemory.PldL(context, inst.Imm12, inst.U != 0); + } + + public static void PldRA1(CodeGenContext context, uint encoding) + { + InstUb23w1Rb22w1Rnb16w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding); + + InstEmitMemory.PldR(context, inst.Rn, inst.Rm, inst.Stype, inst.Imm5, inst.U != 0, inst.R != 0); + } + + public static void PldRT1(CodeGenContext context, uint encoding) + { + InstWb21w1Rnb16w4Imm2b4w2Rmb0w4 inst = new(encoding); + + InstEmitMemory.PldR(context, inst.Rn, inst.Rm, 0, inst.Imm2, true, inst.W == 0); + } + + public static void PliIA1(CodeGenContext context, uint encoding) + { + InstUb23w1Rnb16w4Imm12b0w12 inst = new(encoding); + + InstEmitMemory.PliI(context, inst.Rn, inst.Imm12, inst.U != 0); + } + + public static void PliIT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Imm12b0w12 inst = new(encoding); + + InstEmitMemory.PliI(context, inst.Rn, inst.Imm12, true); + } + + public static void PliIT2(CodeGenContext context, uint encoding) + { + InstRnb16w4Imm8b0w8 inst = new(encoding); + + InstEmitMemory.PliI(context, inst.Rn, inst.Imm8, false); + } + + public static void PliIT3(CodeGenContext context, uint encoding) + { + InstUb23w1Imm12b0w12 inst = new(encoding); + + InstEmitMemory.PliL(context, inst.Imm12, inst.U != 0); + } + + public static void PliRA1(CodeGenContext context, uint encoding) + { + InstUb23w1Rnb16w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding); + + InstEmitMemory.PliR(context, inst.Rn, inst.Rm, inst.Stype, inst.Imm5, inst.U != 0); + } + + public static void PliRT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Imm2b4w2Rmb0w4 inst = new(encoding); + + InstEmitMemory.PliR(context, inst.Rn, inst.Rm, 0, inst.Imm2, true); + } + + public static void PopT1(CodeGenContext context, uint encoding) + { + InstPb24w1RegisterListb16w8 inst = new(encoding); + + InstEmitMemory.Ldm(context, RegisterUtils.SpRegister, inst.RegisterList | (inst.P << RegisterUtils.PcRegister), true); + } + + public static void PssbbA1(CodeGenContext context, uint encoding) + { + throw new NotImplementedException(); + } + + public static void PssbbT1(CodeGenContext context, uint encoding) + { + throw new NotImplementedException(); + } + + public static void PushT1(CodeGenContext context, uint encoding) + { + InstMb24w1RegisterListb16w8 inst = new(encoding); + + InstEmitMemory.Stmdb(context, RegisterUtils.SpRegister, inst.RegisterList | (inst.M << RegisterUtils.LrRegister), true); + } + + public static void QaddA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding); + + InstEmitSaturate.Qadd(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void QaddT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitSaturate.Qadd(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void Qadd16A1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding); + + InstEmitSaturate.Qadd16(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void Qadd16T1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitSaturate.Qadd16(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void Qadd8A1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding); + + InstEmitSaturate.Qadd8(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void Qadd8T1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitSaturate.Qadd8(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void QasxA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding); + + InstEmitSaturate.Qasx(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void QasxT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitSaturate.Qasx(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void QdaddA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding); + + InstEmitSaturate.Qdadd(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void QdaddT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitSaturate.Qdadd(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void QdsubA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding); + + InstEmitSaturate.Qdsub(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void QdsubT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitSaturate.Qdsub(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void QsaxA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding); + + InstEmitSaturate.Qsax(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void QsaxT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitSaturate.Qsax(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void QsubA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding); + + InstEmitSaturate.Qsub(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void QsubT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitSaturate.Qsub(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void Qsub16A1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding); + + InstEmitSaturate.Qsub16(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void Qsub16T1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitSaturate.Qsub16(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void Qsub8A1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding); + + InstEmitSaturate.Qsub8(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void Qsub8T1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitSaturate.Qsub8(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void RbitA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rdb12w4Rmb0w4 inst = new(encoding); + + InstEmitBit.Rbit(context, inst.Rd, inst.Rm); + } + + public static void RbitT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitBit.Rbit(context, inst.Rd, inst.Rm); + } + + public static void RevA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rdb12w4Rmb0w4 inst = new(encoding); + + InstEmitBit.Rev(context, inst.Rd, inst.Rm); + } + + public static void RevT1(CodeGenContext context, uint encoding) + { + InstRmb19w3Rdb16w3 inst = new(encoding); + + InstEmitBit.Rev(context, inst.Rd, inst.Rm); + } + + public static void RevT2(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitBit.Rev(context, inst.Rd, inst.Rm); + } + + public static void Rev16A1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rdb12w4Rmb0w4 inst = new(encoding); + + InstEmitBit.Rev16(context, inst.Rd, inst.Rm); + } + + public static void Rev16T1(CodeGenContext context, uint encoding) + { + InstRmb19w3Rdb16w3 inst = new(encoding); + + InstEmitBit.Rev16(context, inst.Rd, inst.Rm); + } + + public static void Rev16T2(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitBit.Rev16(context, inst.Rd, inst.Rm); + } + + public static void RevshA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rdb12w4Rmb0w4 inst = new(encoding); + + InstEmitBit.Revsh(context, inst.Rd, inst.Rm); + } + + public static void RevshT1(CodeGenContext context, uint encoding) + { + InstRmb19w3Rdb16w3 inst = new(encoding); + + InstEmitBit.Revsh(context, inst.Rd, inst.Rm); + } + + public static void RevshT2(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitBit.Revsh(context, inst.Rd, inst.Rm); + } + + public static void RfeA1(CodeGenContext context, uint encoding) + { + InstEmitSystem.PrivilegedInstruction(context, encoding); + } + + public static void RfeT1(CodeGenContext context, uint encoding) + { + InstEmitSystem.PrivilegedInstruction(context, encoding); + } + + public static void RfeT2(CodeGenContext context, uint encoding) + { + InstEmitSystem.PrivilegedInstruction(context, encoding); + } + + public static void RsbIA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Sb20w1Rnb16w4Rdb12w4Imm12b0w12 inst = new(encoding); + + InstEmitAlu.RsbI(context, inst.Rd, inst.Rn, ImmUtils.ExpandImm(inst.Imm12), inst.S != 0); + } + + public static void RsbIT1(CodeGenContext context, uint encoding) + { + InstRnb19w3Rdb16w3 inst = new(encoding); + + InstEmitAlu.RsbI(context, inst.Rd, inst.Rn, 0, !context.InITBlock); + } + + public static void RsbIT2(CodeGenContext context, uint encoding) + { + InstIb26w1Sb20w1Rnb16w4Imm3b12w3Rdb8w4Imm8b0w8 inst = new(encoding); + + InstEmitAlu.RsbI(context, inst.Rd, inst.Rn, ImmUtils.ExpandImm(inst.Imm8, inst.Imm3, inst.I), inst.S != 0); + } + + public static void RsbRA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Sb20w1Rnb16w4Rdb12w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding); + + InstEmitAlu.RsbR(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, inst.Imm5, inst.S != 0); + } + + public static void RsbRT1(CodeGenContext context, uint encoding) + { + InstSb20w1Rnb16w4Imm3b12w3Rdb8w4Imm2b6w2Stypeb4w2Rmb0w4 inst = new(encoding); + + InstEmitAlu.RsbR(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3), inst.S != 0); + } + + public static void RsbRrA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Sb20w1Rnb16w4Rdb12w4Rsb8w4Stypeb5w2Rmb0w4 inst = new(encoding); + + InstEmitAlu.RsbRr(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, inst.Rs, inst.S != 0); + } + + public static void RscIA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Sb20w1Rnb16w4Rdb12w4Imm12b0w12 inst = new(encoding); + + InstEmitAlu.RscI(context, inst.Rd, inst.Rn, ImmUtils.ExpandImm(inst.Imm12), inst.S != 0); + } + + public static void RscRA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Sb20w1Rnb16w4Rdb12w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding); + + InstEmitAlu.RscR(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, inst.Imm5, inst.S != 0); + } + + public static void RscRrA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Sb20w1Rnb16w4Rdb12w4Rsb8w4Stypeb5w2Rmb0w4 inst = new(encoding); + + InstEmitAlu.RscRr(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, inst.Rs, inst.S != 0); + } + + public static void Sadd16A1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding); + + InstEmitGE.Sadd16(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void Sadd16T1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitGE.Sadd16(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void Sadd8A1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding); + + InstEmitGE.Sadd8(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void Sadd8T1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitGE.Sadd8(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void SasxA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding); + + InstEmitGE.Sasx(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void SasxT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitGE.Sasx(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void SbA1(CodeGenContext context, uint encoding) + { + throw new NotImplementedException(); + } + + public static void SbT1(CodeGenContext context, uint encoding) + { + throw new NotImplementedException(); + } + + public static void SbcIA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Sb20w1Rnb16w4Rdb12w4Imm12b0w12 inst = new(encoding); + + InstEmitAlu.SbcI(context, inst.Rd, inst.Rn, ImmUtils.ExpandImm(inst.Imm12), inst.S != 0); + } + + public static void SbcIT1(CodeGenContext context, uint encoding) + { + InstIb26w1Sb20w1Rnb16w4Imm3b12w3Rdb8w4Imm8b0w8 inst = new(encoding); + + InstEmitAlu.SbcI(context, inst.Rd, inst.Rn, ImmUtils.ExpandImm(inst.Imm8, inst.Imm3, inst.I), inst.S != 0); + } + + public static void SbcRA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Sb20w1Rnb16w4Rdb12w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding); + + InstEmitAlu.SbcR(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, inst.Imm5, inst.S != 0); + } + + public static void SbcRT1(CodeGenContext context, uint encoding) + { + InstRmb19w3Rdnb16w3 inst = new(encoding); + + InstEmitAlu.SbcR(context, inst.Rdn, inst.Rdn, inst.Rm, 0, 0, !context.InITBlock); + } + + public static void SbcRT2(CodeGenContext context, uint encoding) + { + InstSb20w1Rnb16w4Imm3b12w3Rdb8w4Imm2b6w2Stypeb4w2Rmb0w4 inst = new(encoding); + + InstEmitAlu.SbcR(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3), inst.S != 0); + } + + public static void SbcRrA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Sb20w1Rnb16w4Rdb12w4Rsb8w4Stypeb5w2Rmb0w4 inst = new(encoding); + + InstEmitAlu.SbcRr(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, inst.Rs, inst.S != 0); + } + + public static void SbfxA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Widthm1b16w5Rdb12w4Lsbb7w5Rnb0w4 inst = new(encoding); + + InstEmitBit.Sbfx(context, inst.Rd, inst.Rn, inst.Lsb, inst.Widthm1); + } + + public static void SbfxT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Imm3b12w3Rdb8w4Imm2b6w2Widthm1b0w5 inst = new(encoding); + + InstEmitBit.Sbfx(context, inst.Rd, inst.Rn, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3), inst.Widthm1); + } + + public static void SdivA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rdb16w4Rmb8w4Rnb0w4 inst = new(encoding); + + InstEmitDivide.Sdiv(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void SdivT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitDivide.Sdiv(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void SelA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding); + + InstEmitGE.Sel(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void SelT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitGE.Sel(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void SetendA1(CodeGenContext context, uint encoding) + { + InstEb9w1 inst = new(encoding); + + InstEmitSystem.Setend(context, inst.E != 0); + } + + public static void SetendT1(CodeGenContext context, uint encoding) + { + InstEb19w1 inst = new(encoding); + + InstEmitSystem.Setend(context, inst.E != 0); + } + + public static void SetpanA1(CodeGenContext context, uint encoding) + { + _ = new InstImm1b9w1(encoding); + + throw new NotImplementedException(); + } + + public static void SetpanT1(CodeGenContext context, uint encoding) + { + _ = new InstImm1b19w1(encoding); + + throw new NotImplementedException(); + } + + public static void SevA1(CodeGenContext context, uint encoding) + { + context.Arm64Assembler.Sev(); + } + + public static void SevT1(CodeGenContext context, uint encoding) + { + context.Arm64Assembler.Sev(); + } + + public static void SevT2(CodeGenContext context, uint encoding) + { + context.Arm64Assembler.Sev(); + } + + public static void SevlA1(CodeGenContext context, uint encoding) + { + context.Arm64Assembler.Sevl(); + } + + public static void SevlT1(CodeGenContext context, uint encoding) + { + context.Arm64Assembler.Sevl(); + } + + public static void SevlT2(CodeGenContext context, uint encoding) + { + context.Arm64Assembler.Sevl(); + } + + public static void Sha1cA1(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonHash.Sha1c(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q); + } + + public static void Sha1cT1(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonHash.Sha1c(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q); + } + + public static void Sha1hA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonHash.Sha1h(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size); + } + + public static void Sha1hT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonHash.Sha1h(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size); + } + + public static void Sha1mA1(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonHash.Sha1m(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q); + } + + public static void Sha1mT1(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonHash.Sha1m(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q); + } + + public static void Sha1pA1(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonHash.Sha1p(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q); + } + + public static void Sha1pT1(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonHash.Sha1p(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q); + } + + public static void Sha1su0A1(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonHash.Sha1su0(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q); + } + + public static void Sha1su0T1(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonHash.Sha1su0(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q); + } + + public static void Sha1su1A1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonHash.Sha1su1(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size); + } + + public static void Sha1su1T1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonHash.Sha1su1(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size); + } + + public static void Sha256hA1(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonHash.Sha256h(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q); + } + + public static void Sha256hT1(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonHash.Sha256h(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q); + } + + public static void Sha256h2A1(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonHash.Sha256h2(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q); + } + + public static void Sha256h2T1(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonHash.Sha256h2(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q); + } + + public static void Sha256su0A1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonHash.Sha256su0(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size); + } + + public static void Sha256su0T1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonHash.Sha256su0(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size); + } + + public static void Sha256su1A1(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonHash.Sha256su1(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q); + } + + public static void Sha256su1T1(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonHash.Sha256su1(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q); + } + + public static void Shadd16A1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding); + + InstEmitHalve.Shadd16(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void Shadd16T1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitHalve.Shadd16(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void Shadd8A1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding); + + InstEmitHalve.Shadd8(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void Shadd8T1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitHalve.Shadd8(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void ShasxA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding); + + InstEmitHalve.Shasx(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void ShasxT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitHalve.Shasx(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void ShsaxA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding); + + InstEmitHalve.Shsax(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void ShsaxT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitHalve.Shsax(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void Shsub16A1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding); + + InstEmitHalve.Shsub16(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void Shsub16T1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitHalve.Shsub16(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void Shsub8A1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding); + + InstEmitHalve.Shsub8(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void Shsub8T1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitHalve.Shsub8(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void SmcA1(CodeGenContext context, uint encoding) + { + InstEmitSystem.PrivilegedInstruction(context, encoding); + } + + public static void SmcT1(CodeGenContext context, uint encoding) + { + InstEmitSystem.PrivilegedInstruction(context, encoding); + } + + public static void SmlabbA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rdb16w4Rab12w4Rmb8w4Mb6w1Nb5w1Rnb0w4 inst = new(encoding); + + InstEmitMultiply.Smlabb(context, inst.Rd, inst.Rn, inst.Rm, inst.Ra, inst.N != 0, inst.M != 0); + } + + public static void SmlabbT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rab12w4Rdb8w4Nb5w1Mb4w1Rmb0w4 inst = new(encoding); + + InstEmitMultiply.Smlabb(context, inst.Rd, inst.Rn, inst.Rm, inst.Ra, inst.N != 0, inst.M != 0); + } + + public static void SmladA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rdb16w4Rab12w4Rmb8w4Mb5w1Rnb0w4 inst = new(encoding); + + InstEmitMultiply.Smlad(context, inst.Rd, inst.Rn, inst.Rm, inst.Ra, inst.M != 0); + } + + public static void SmladT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rab12w4Rdb8w4Mb4w1Rmb0w4 inst = new(encoding); + + InstEmitMultiply.Smlad(context, inst.Rd, inst.Rn, inst.Rm, inst.Ra, inst.M != 0); + } + + public static void SmlalA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Sb20w1Rdhib16w4Rdlob12w4Rmb8w4Rnb0w4 inst = new(encoding); + + InstEmitMultiply.Smlal(context, inst.Rdlo, inst.Rdhi, inst.Rn, inst.Rm, inst.S != 0); + } + + public static void SmlalT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdlob12w4Rdhib8w4Rmb0w4 inst = new(encoding); + + InstEmitMultiply.Smlal(context, inst.Rdlo, inst.Rdhi, inst.Rn, inst.Rm, false); + } + + public static void SmlalbbA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rdhib16w4Rdlob12w4Rmb8w4Mb6w1Nb5w1Rnb0w4 inst = new(encoding); + + InstEmitMultiply.Smlalbb(context, inst.Rdlo, inst.Rdhi, inst.Rn, inst.Rm, inst.N != 0, inst.M != 0); + } + + public static void SmlalbbT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdlob12w4Rdhib8w4Nb5w1Mb4w1Rmb0w4 inst = new(encoding); + + InstEmitMultiply.Smlalbb(context, inst.Rdlo, inst.Rdhi, inst.Rn, inst.Rm, inst.N != 0, inst.M != 0); + } + + public static void SmlaldA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rdhib16w4Rdlob12w4Rmb8w4Mb5w1Rnb0w4 inst = new(encoding); + + InstEmitMultiply.Smlald(context, inst.Rdlo, inst.Rdhi, inst.Rn, inst.Rm, inst.M != 0); + } + + public static void SmlaldT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdlob12w4Rdhib8w4Mb4w1Rmb0w4 inst = new(encoding); + + InstEmitMultiply.Smlald(context, inst.Rdlo, inst.Rdhi, inst.Rn, inst.Rm, inst.M != 0); + } + + public static void SmlawbA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rdb16w4Rab12w4Rmb8w4Mb6w1Rnb0w4 inst = new(encoding); + + InstEmitMultiply.Smlawb(context, inst.Rd, inst.Rn, inst.Rm, inst.Ra, inst.M != 0); + } + + public static void SmlawbT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rab12w4Rdb8w4Mb4w1Rmb0w4 inst = new(encoding); + + InstEmitMultiply.Smlawb(context, inst.Rd, inst.Rn, inst.Rm, inst.Ra, inst.M != 0); + } + + public static void SmlsdA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rdb16w4Rab12w4Rmb8w4Mb5w1Rnb0w4 inst = new(encoding); + + InstEmitMultiply.Smlsd(context, inst.Rd, inst.Rn, inst.Rm, inst.Ra, inst.M != 0); + } + + public static void SmlsdT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rab12w4Rdb8w4Mb4w1Rmb0w4 inst = new(encoding); + + InstEmitMultiply.Smlsd(context, inst.Rd, inst.Rn, inst.Rm, inst.Ra, inst.M != 0); + } + + public static void SmlsldA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rdhib16w4Rdlob12w4Rmb8w4Mb5w1Rnb0w4 inst = new(encoding); + + InstEmitMultiply.Smlsld(context, inst.Rdlo, inst.Rdhi, inst.Rn, inst.Rm, inst.M != 0); + } + + public static void SmlsldT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdlob12w4Rdhib8w4Mb4w1Rmb0w4 inst = new(encoding); + + InstEmitMultiply.Smlsld(context, inst.Rdlo, inst.Rdhi, inst.Rn, inst.Rm, inst.M != 0); + } + + public static void SmmlaA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rdb16w4Rab12w4Rmb8w4Rb5w1Rnb0w4 inst = new(encoding); + + InstEmitMultiply.Smmla(context, inst.Rd, inst.Rn, inst.Rm, inst.Ra, inst.R != 0); + } + + public static void SmmlaT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rab12w4Rdb8w4Rb4w1Rmb0w4 inst = new(encoding); + + InstEmitMultiply.Smmla(context, inst.Rd, inst.Rn, inst.Rm, inst.Ra, inst.R != 0); + } + + public static void SmmlsA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rdb16w4Rab12w4Rmb8w4Rb5w1Rnb0w4 inst = new(encoding); + + InstEmitMultiply.Smmls(context, inst.Rd, inst.Rn, inst.Rm, inst.Ra, inst.R != 0); + } + + public static void SmmlsT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rab12w4Rdb8w4Rb4w1Rmb0w4 inst = new(encoding); + + InstEmitMultiply.Smmls(context, inst.Rd, inst.Rn, inst.Rm, inst.Ra, inst.R != 0); + } + + public static void SmmulA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rdb16w4Rmb8w4Rb5w1Rnb0w4 inst = new(encoding); + + InstEmitMultiply.Smmul(context, inst.Rd, inst.Rn, inst.Rm, inst.R != 0); + } + + public static void SmmulT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rb4w1Rmb0w4 inst = new(encoding); + + InstEmitMultiply.Smmul(context, inst.Rd, inst.Rn, inst.Rm, inst.R != 0); + } + + public static void SmuadA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rdb16w4Rmb8w4Mb5w1Rnb0w4 inst = new(encoding); + + InstEmitMultiply.Smuad(context, inst.Rd, inst.Rn, inst.Rm, inst.M != 0); + } + + public static void SmuadT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Mb4w1Rmb0w4 inst = new(encoding); + + InstEmitMultiply.Smuad(context, inst.Rd, inst.Rn, inst.Rm, inst.M != 0); + } + + public static void SmulbbA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rdb16w4Rmb8w4Mb6w1Nb5w1Rnb0w4 inst = new(encoding); + + InstEmitMultiply.Smulbb(context, inst.Rd, inst.Rn, inst.Rm, inst.N != 0, inst.M != 0); + } + + public static void SmulbbT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Nb5w1Mb4w1Rmb0w4 inst = new(encoding); + + InstEmitMultiply.Smulbb(context, inst.Rd, inst.Rn, inst.Rm, inst.N != 0, inst.M != 0); + } + + public static void SmullA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Sb20w1Rdhib16w4Rdlob12w4Rmb8w4Rnb0w4 inst = new(encoding); + + InstEmitMultiply.Smull(context, inst.Rdlo, inst.Rdhi, inst.Rn, inst.Rm, inst.S != 0); + } + + public static void SmullT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdlob12w4Rdhib8w4Rmb0w4 inst = new(encoding); + + InstEmitMultiply.Smull(context, inst.Rdlo, inst.Rdhi, inst.Rn, inst.Rm, false); + } + + public static void SmulwbA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rdb16w4Rmb8w4Mb6w1Rnb0w4 inst = new(encoding); + + InstEmitMultiply.Smulwb(context, inst.Rd, inst.Rn, inst.Rm, inst.M != 0); + } + + public static void SmulwbT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Mb4w1Rmb0w4 inst = new(encoding); + + InstEmitMultiply.Smulwb(context, inst.Rd, inst.Rn, inst.Rm, inst.M != 0); + } + + public static void SmusdA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rdb16w4Rmb8w4Mb5w1Rnb0w4 inst = new(encoding); + + InstEmitMultiply.Smusd(context, inst.Rd, inst.Rn, inst.Rm, inst.M != 0); + } + + public static void SmusdT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Mb4w1Rmb0w4 inst = new(encoding); + + InstEmitMultiply.Smusd(context, inst.Rd, inst.Rn, inst.Rm, inst.M != 0); + } + + public static void SrsA1(CodeGenContext context, uint encoding) + { + InstEmitSystem.PrivilegedInstruction(context, encoding); + } + + public static void SrsT1(CodeGenContext context, uint encoding) + { + InstEmitSystem.PrivilegedInstruction(context, encoding); + } + + public static void SrsT2(CodeGenContext context, uint encoding) + { + InstEmitSystem.PrivilegedInstruction(context, encoding); + } + + public static void SsatA1(CodeGenContext context, uint encoding) + { + InstCondb28w4SatImmb16w5Rdb12w4Imm5b7w5Shb6w1Rnb0w4 inst = new(encoding); + + InstEmitSaturate.Ssat(context, inst.Rd, inst.SatImm, inst.Rn, inst.Sh != 0, inst.Imm5); + } + + public static void SsatT1(CodeGenContext context, uint encoding) + { + InstShb21w1Rnb16w4Imm3b12w3Rdb8w4Imm2b6w2SatImmb0w5 inst = new(encoding); + + InstEmitSaturate.Ssat(context, inst.Rd, inst.SatImm, inst.Rn, inst.Sh != 0, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3)); + } + + public static void Ssat16A1(CodeGenContext context, uint encoding) + { + InstCondb28w4SatImmb16w4Rdb12w4Rnb0w4 inst = new(encoding); + + InstEmitSaturate.Ssat16(context, inst.Rd, inst.SatImm, inst.Rn); + } + + public static void Ssat16T1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4SatImmb0w4 inst = new(encoding); + + InstEmitSaturate.Ssat16(context, inst.Rd, inst.SatImm, inst.Rn); + } + + public static void SsaxA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding); + + InstEmitGE.Ssax(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void SsaxT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitGE.Ssax(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void SsbbA1(CodeGenContext context, uint encoding) + { + throw new NotImplementedException(); + } + + public static void SsbbT1(CodeGenContext context, uint encoding) + { + throw new NotImplementedException(); + } + + public static void Ssub16A1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding); + + InstEmitGE.Ssub16(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void Ssub16T1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitGE.Ssub16(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void Ssub8A1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding); + + InstEmitGE.Ssub8(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void Ssub8T1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitGE.Ssub8(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void StcA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Imm8b0w8 inst = new(encoding); + + InstEmitMemory.Stc(context, inst.Rn, (int)inst.Imm8 << 2, inst.P != 0, inst.U != 0, inst.W != 0); + } + + public static void StcT1(CodeGenContext context, uint encoding) + { + InstPb24w1Ub23w1Wb21w1Rnb16w4Imm8b0w8 inst = new(encoding); + + InstEmitMemory.Stc(context, inst.Rn, (int)inst.Imm8 << 2, inst.P != 0, inst.U != 0, inst.W != 0); + } + + public static void StlA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rtb0w4 inst = new(encoding); + + InstEmitMemory.Stl(context, inst.Rt, inst.Rn); + } + + public static void StlT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4 inst = new(encoding); + + InstEmitMemory.Stl(context, inst.Rt, inst.Rn); + } + + public static void StlbA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rtb0w4 inst = new(encoding); + + InstEmitMemory.Stlb(context, inst.Rt, inst.Rn); + } + + public static void StlbT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4 inst = new(encoding); + + InstEmitMemory.Stlb(context, inst.Rt, inst.Rn); + } + + public static void StlexA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rtb0w4 inst = new(encoding); + + InstEmitMemory.Stlex(context, inst.Rd, inst.Rt, inst.Rn); + } + + public static void StlexT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4Rdb0w4 inst = new(encoding); + + InstEmitMemory.Stlex(context, inst.Rd, inst.Rt, inst.Rn); + } + + public static void StlexbA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rtb0w4 inst = new(encoding); + + InstEmitMemory.Stlexb(context, inst.Rd, inst.Rt, inst.Rn); + } + + public static void StlexbT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4Rdb0w4 inst = new(encoding); + + InstEmitMemory.Stlexb(context, inst.Rd, inst.Rt, inst.Rn); + } + + public static void StlexdA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rtb0w4 inst = new(encoding); + + InstEmitMemory.Stlexd(context, inst.Rd, inst.Rt, RegisterUtils.GetRt2(inst.Rt), inst.Rn); + } + + public static void StlexdT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4Rt2b8w4Rdb0w4 inst = new(encoding); + + InstEmitMemory.Stlexd(context, inst.Rd, inst.Rt, inst.Rt2, inst.Rn); + } + + public static void StlexhA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rtb0w4 inst = new(encoding); + + InstEmitMemory.Stlexh(context, inst.Rd, inst.Rt, inst.Rn); + } + + public static void StlexhT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4Rdb0w4 inst = new(encoding); + + InstEmitMemory.Stlexh(context, inst.Rd, inst.Rt, inst.Rn); + } + + public static void StlhA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rtb0w4 inst = new(encoding); + + InstEmitMemory.Stlh(context, inst.Rt, inst.Rn); + } + + public static void StlhT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4 inst = new(encoding); + + InstEmitMemory.Stlh(context, inst.Rt, inst.Rn); + } + + public static void StmA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Wb21w1Rnb16w4RegisterListb0w16 inst = new(encoding); + + InstEmitMemory.Stm(context, inst.Rn, inst.RegisterList, inst.W != 0); + } + + public static void StmT1(CodeGenContext context, uint encoding) + { + InstRnb24w3RegisterListb16w8 inst = new(encoding); + + InstEmitMemory.Stm(context, inst.Rn, inst.RegisterList, false); + } + + public static void StmT2(CodeGenContext context, uint encoding) + { + InstWb21w1Rnb16w4Mb14w1RegisterListb0w14 inst = new(encoding); + + InstEmitMemory.Stm(context, inst.Rn, ImmUtils.CombineRegisterList(inst.RegisterList, inst.M), inst.W != 0); + } + + public static void StmdaA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Wb21w1Rnb16w4RegisterListb0w16 inst = new(encoding); + + InstEmitMemory.Stmda(context, inst.Rn, inst.RegisterList, inst.W != 0); + } + + public static void StmdbA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Wb21w1Rnb16w4RegisterListb0w16 inst = new(encoding); + + InstEmitMemory.Stmdb(context, inst.Rn, inst.RegisterList, inst.W != 0); + } + + public static void StmdbT1(CodeGenContext context, uint encoding) + { + InstWb21w1Rnb16w4Mb14w1RegisterListb0w14 inst = new(encoding); + + InstEmitMemory.Stmdb(context, inst.Rn, ImmUtils.CombineRegisterList(inst.RegisterList, inst.M), inst.W != 0); + } + + public static void StmibA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Wb21w1Rnb16w4RegisterListb0w16 inst = new(encoding); + + InstEmitMemory.Stmib(context, inst.Rn, inst.RegisterList, inst.W != 0); + } + + public static void StmUA1(CodeGenContext context, uint encoding) + { + InstEmitSystem.PrivilegedInstruction(context, encoding); + } + + public static void StrbtA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Ub23w1Rnb16w4Rtb12w4Imm12b0w12 inst = new(encoding); + + InstEmitMemory.StrbtI(context, inst.Rt, inst.Rn, (int)inst.Imm12, postIndex: true, inst.U != 0); + } + + public static void StrbtA2(CodeGenContext context, uint encoding) + { + InstCondb28w4Ub23w1Rnb16w4Rtb12w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding); + + InstEmitMemory.StrbtR(context, inst.Rt, inst.Rn, inst.Rm, inst.Stype, inst.Imm5, postIndex: true, inst.U != 0); + } + + public static void StrbtT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4Imm8b0w8 inst = new(encoding); + + InstEmitMemory.StrbtI(context, inst.Rt, inst.Rn, (int)inst.Imm8, postIndex: false, true); + } + + public static void StrbIA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Imm12b0w12 inst = new(encoding); + + InstEmitMemory.StrbI(context, inst.Rt, inst.Rn, (int)inst.Imm12, inst.P != 0, inst.U != 0, inst.W != 0); + } + + public static void StrbIT1(CodeGenContext context, uint encoding) + { + InstImm5b22w5Rnb19w3Rtb16w3 inst = new(encoding); + + InstEmitMemory.StrbI(context, inst.Rt, inst.Rn, (int)inst.Imm5, true, true, false); + } + + public static void StrbIT2(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4Imm12b0w12 inst = new(encoding); + + InstEmitMemory.StrbI(context, inst.Rt, inst.Rn, (int)inst.Imm12, true, true, false); + } + + public static void StrbIT3(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4Pb10w1Ub9w1Wb8w1Imm8b0w8 inst = new(encoding); + + InstEmitMemory.StrbI(context, inst.Rt, inst.Rn, (int)inst.Imm8, inst.P != 0, inst.U != 0, inst.W != 0); + } + + public static void StrbRA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding); + + InstEmitMemory.StrbR(context, inst.Rt, inst.Rn, inst.Rm, inst.Stype, inst.Imm5, inst.P != 0, inst.U != 0, inst.W != 0); + } + + public static void StrbRT1(CodeGenContext context, uint encoding) + { + InstRmb22w3Rnb19w3Rtb16w3 inst = new(encoding); + + InstEmitMemory.StrbR(context, inst.Rt, inst.Rn, inst.Rm, 0, 0, true, true, false); + } + + public static void StrbRT2(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4Imm2b4w2Rmb0w4 inst = new(encoding); + + InstEmitMemory.StrbR(context, inst.Rt, inst.Rn, inst.Rm, 0, inst.Imm2, true, true, false); + } + + public static void StrdIA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Imm4hb8w4Imm4lb0w4 inst = new(encoding); + + InstEmitMemory.StrdI(context, inst.Rt, RegisterUtils.GetRt2(inst.Rt), inst.Rn, ImmUtils.CombineImmU8(inst.Imm4l, inst.Imm4h), inst.P != 0, inst.U != 0, inst.W != 0); + } + + public static void StrdIT1(CodeGenContext context, uint encoding) + { + InstPb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Rt2b8w4Imm8b0w8 inst = new(encoding); + + InstEmitMemory.StrdI(context, inst.Rt, inst.Rt2, inst.Rn, inst.Imm8 << 2, inst.P != 0, inst.U != 0, inst.W != 0); + } + + public static void StrdRA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Rmb0w4 inst = new(encoding); + + InstEmitMemory.StrdR(context, inst.Rt, RegisterUtils.GetRt2(inst.Rt), inst.Rn, inst.Rm, inst.P != 0, inst.U != 0, inst.W != 0); + } + + public static void StrexA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rtb0w4 inst = new(encoding); + + InstEmitMemory.Strex(context, inst.Rd, inst.Rt, inst.Rn); + } + + public static void StrexT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4Rdb8w4Imm8b0w8 inst = new(encoding); + + InstEmitMemory.Strex(context, inst.Rd, inst.Rt, inst.Rn); + } + + public static void StrexbA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rtb0w4 inst = new(encoding); + + InstEmitMemory.Strexb(context, inst.Rd, inst.Rt, inst.Rn); + } + + public static void StrexbT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4Rdb0w4 inst = new(encoding); + + InstEmitMemory.Strexb(context, inst.Rd, inst.Rt, inst.Rn); + } + + public static void StrexdA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rtb0w4 inst = new(encoding); + + InstEmitMemory.Strexd(context, inst.Rd, inst.Rt, RegisterUtils.GetRt2(inst.Rt), inst.Rn); + } + + public static void StrexdT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4Rt2b8w4Rdb0w4 inst = new(encoding); + + InstEmitMemory.Strexd(context, inst.Rd, inst.Rt, inst.Rt2, inst.Rn); + } + + public static void StrexhA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rtb0w4 inst = new(encoding); + + InstEmitMemory.Strexh(context, inst.Rd, inst.Rt, inst.Rn); + } + + public static void StrexhT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4Rdb0w4 inst = new(encoding); + + InstEmitMemory.Strexh(context, inst.Rd, inst.Rt, inst.Rn); + } + + public static void StrhtA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Ub23w1Rnb16w4Rtb12w4Imm4hb8w4Imm4lb0w4 inst = new(encoding); + + InstEmitMemory.StrhtI(context, inst.Rt, inst.Rn, (int)ImmUtils.CombineImmU8(inst.Imm4l, inst.Imm4h), postIndex: true, inst.U != 0); + } + + public static void StrhtA2(CodeGenContext context, uint encoding) + { + InstCondb28w4Ub23w1Rnb16w4Rtb12w4Rmb0w4 inst = new(encoding); + + InstEmitMemory.StrhtR(context, inst.Rt, inst.Rn, inst.Rm, postIndex: true, inst.U != 0); + } + + public static void StrhtT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4Imm8b0w8 inst = new(encoding); + + InstEmitMemory.StrhtI(context, inst.Rt, inst.Rn, (int)inst.Imm8, postIndex: false, true); + } + + public static void StrhIA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Imm4hb8w4Imm4lb0w4 inst = new(encoding); + + InstEmitMemory.StrhI(context, inst.Rt, inst.Rn, (int)ImmUtils.CombineImmU8(inst.Imm4l, inst.Imm4h), inst.P != 0, inst.U != 0, inst.W != 0); + } + + public static void StrhIT1(CodeGenContext context, uint encoding) + { + InstImm5b22w5Rnb19w3Rtb16w3 inst = new(encoding); + + InstEmitMemory.StrhI(context, inst.Rt, inst.Rn, (int)inst.Imm5 << 1, true, true, false); + } + + public static void StrhIT2(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4Imm12b0w12 inst = new(encoding); + + InstEmitMemory.StrhI(context, inst.Rt, inst.Rn, (int)inst.Imm12, true, true, false); + } + + public static void StrhIT3(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4Pb10w1Ub9w1Wb8w1Imm8b0w8 inst = new(encoding); + + InstEmitMemory.StrhI(context, inst.Rt, inst.Rn, (int)inst.Imm8, inst.P != 0, inst.U != 0, inst.W != 0); + } + + public static void StrhRA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Rmb0w4 inst = new(encoding); + + InstEmitMemory.StrhR(context, inst.Rt, inst.Rn, inst.Rm, 0, 0, inst.P != 0, inst.U != 0, inst.W != 0); + } + + public static void StrhRT1(CodeGenContext context, uint encoding) + { + InstRmb22w3Rnb19w3Rtb16w3 inst = new(encoding); + + InstEmitMemory.StrhR(context, inst.Rt, inst.Rn, inst.Rm, 0, 0, true, true, false); + } + + public static void StrhRT2(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4Imm2b4w2Rmb0w4 inst = new(encoding); + + InstEmitMemory.StrhR(context, inst.Rt, inst.Rn, inst.Rm, 0, inst.Imm2, true, true, false); + } + + public static void StrtA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Ub23w1Rnb16w4Rtb12w4Imm12b0w12 inst = new(encoding); + + InstEmitMemory.StrtI(context, inst.Rt, inst.Rn, (int)inst.Imm12, postIndex: true, inst.U != 0); + } + + public static void StrtA2(CodeGenContext context, uint encoding) + { + InstCondb28w4Ub23w1Rnb16w4Rtb12w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding); + + InstEmitMemory.StrtR(context, inst.Rt, inst.Rn, inst.Rm, inst.Stype, inst.Imm5, postIndex: true, inst.U != 0); + } + + public static void StrtT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4Imm8b0w8 inst = new(encoding); + + InstEmitMemory.StrtI(context, inst.Rt, inst.Rn, (int)inst.Imm8, postIndex: false, true); + } + + public static void StrIA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Imm12b0w12 inst = new(encoding); + + InstEmitMemory.StrI(context, inst.Rt, inst.Rn, (int)inst.Imm12, inst.P != 0, inst.U != 0, inst.W != 0); + } + + public static void StrIT1(CodeGenContext context, uint encoding) + { + InstImm5b22w5Rnb19w3Rtb16w3 inst = new(encoding); + + InstEmitMemory.StrI(context, inst.Rt, inst.Rn, (int)inst.Imm5 << 2, true, true, false); + } + + public static void StrIT2(CodeGenContext context, uint encoding) + { + InstRtb24w3Imm8b16w8 inst = new(encoding); + + InstEmitMemory.StrI(context, inst.Rt, RegisterUtils.SpRegister, (int)inst.Imm8 << 2, true, true, false); + } + + public static void StrIT3(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4Imm12b0w12 inst = new(encoding); + + InstEmitMemory.StrI(context, inst.Rt, inst.Rn, (int)inst.Imm12, true, true, false); + } + + public static void StrIT4(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4Pb10w1Ub9w1Wb8w1Imm8b0w8 inst = new(encoding); + + InstEmitMemory.StrI(context, inst.Rt, inst.Rn, (int)inst.Imm8, inst.P != 0, inst.U != 0, inst.W != 0); + } + + public static void StrRA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Pb24w1Ub23w1Wb21w1Rnb16w4Rtb12w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding); + + InstEmitMemory.StrR(context, inst.Rt, inst.Rn, inst.Rm, inst.Stype, inst.Imm5, inst.P != 0, inst.U != 0, inst.W != 0); + } + + public static void StrRT1(CodeGenContext context, uint encoding) + { + InstRmb22w3Rnb19w3Rtb16w3 inst = new(encoding); + + InstEmitMemory.StrR(context, inst.Rt, inst.Rn, inst.Rm, 0, 0, true, true, false); + } + + public static void StrRT2(CodeGenContext context, uint encoding) + { + InstRnb16w4Rtb12w4Imm2b4w2Rmb0w4 inst = new(encoding); + + InstEmitMemory.StrR(context, inst.Rt, inst.Rn, inst.Rm, 0, inst.Imm2, true, true, false); + } + + public static void SubIA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Sb20w1Rnb16w4Rdb12w4Imm12b0w12 inst = new(encoding); + + InstEmitAlu.SubI(context, inst.Rd, inst.Rn, ImmUtils.ExpandImm(inst.Imm12), inst.S != 0); + } + + public static void SubIT1(CodeGenContext context, uint encoding) + { + InstImm3b22w3Rnb19w3Rdb16w3 inst = new(encoding); + + InstEmitAlu.SubI(context, inst.Rd, inst.Rn, inst.Imm3, !context.InITBlock); + } + + public static void SubIT2(CodeGenContext context, uint encoding) + { + InstRdnb24w3Imm8b16w8 inst = new(encoding); + + InstEmitAlu.SubI(context, inst.Rdn, inst.Rdn, inst.Imm8, !context.InITBlock); + } + + public static void SubIT3(CodeGenContext context, uint encoding) + { + InstIb26w1Sb20w1Rnb16w4Imm3b12w3Rdb8w4Imm8b0w8 inst = new(encoding); + + InstEmitAlu.SubI(context, inst.Rd, inst.Rn, ImmUtils.ExpandImm(inst.Imm8, inst.Imm3, inst.I), inst.S != 0); + } + + public static void SubIT4(CodeGenContext context, uint encoding) + { + InstIb26w1Rnb16w4Imm3b12w3Rdb8w4Imm8b0w8 inst = new(encoding); + + InstEmitAlu.SubI(context, inst.Rd, inst.Rn, ImmUtils.CombineImmU12(inst.Imm8, inst.Imm3, inst.I), false); + } + + public static void SubIT5(CodeGenContext context, uint encoding) + { + InstRnb16w4Imm8b0w8 inst = new(encoding); + + InstEmitAlu.SubI(context, RegisterUtils.PcRegister, inst.Rn, inst.Imm8, true); + } + + public static void SubRA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Sb20w1Rnb16w4Rdb12w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding); + + InstEmitAlu.SubR(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, inst.Imm5, inst.S != 0); + } + + public static void SubRT1(CodeGenContext context, uint encoding) + { + InstRmb22w3Rnb19w3Rdb16w3 inst = new(encoding); + + InstEmitAlu.SubR(context, inst.Rd, inst.Rn, inst.Rm, 0, 0, !context.InITBlock); + } + + public static void SubRT2(CodeGenContext context, uint encoding) + { + InstSb20w1Rnb16w4Imm3b12w3Rdb8w4Imm2b6w2Stypeb4w2Rmb0w4 inst = new(encoding); + + InstEmitAlu.SubR(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3), !context.InITBlock); + } + + public static void SubRrA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Sb20w1Rnb16w4Rdb12w4Rsb8w4Stypeb5w2Rmb0w4 inst = new(encoding); + + InstEmitAlu.SubRr(context, inst.Rd, inst.Rn, inst.Rm, inst.Stype, inst.Rs, inst.S != 0); + } + + public static void SubSpIA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Sb20w1Rdb12w4Imm12b0w12 inst = new(encoding); + + InstEmitAlu.SubI(context, inst.Rd, RegisterUtils.SpRegister, ImmUtils.ExpandImm(inst.Imm12), inst.S != 0); + } + + public static void SubSpIT1(CodeGenContext context, uint encoding) + { + InstImm7b16w7 inst = new(encoding); + + InstEmitAlu.SubI(context, RegisterUtils.SpRegister, RegisterUtils.SpRegister, inst.Imm7 << 2, false); + } + + public static void SubSpIT2(CodeGenContext context, uint encoding) + { + InstIb26w1Sb20w1Imm3b12w3Rdb8w4Imm8b0w8 inst = new(encoding); + + InstEmitAlu.SubI(context, inst.Rd, RegisterUtils.SpRegister, ImmUtils.ExpandImm(inst.Imm8, inst.Imm3, inst.I), inst.S != 0); + } + + public static void SubSpIT3(CodeGenContext context, uint encoding) + { + InstIb26w1Imm3b12w3Rdb8w4Imm8b0w8 inst = new(encoding); + + InstEmitAlu.SubI(context, inst.Rd, RegisterUtils.SpRegister, ImmUtils.CombineImmU12(inst.Imm8, inst.Imm3, inst.I), false); + } + + public static void SubSpRA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Sb20w1Rdb12w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding); + + InstEmitAlu.SubR(context, inst.Rd, RegisterUtils.SpRegister, inst.Rm, inst.Stype, inst.Imm5, inst.S != 0); + } + + public static void SubSpRT1(CodeGenContext context, uint encoding) + { + InstSb20w1Imm3b12w3Rdb8w4Imm2b6w2Stypeb4w2Rmb0w4 inst = new(encoding); + + InstEmitAlu.SubR(context, inst.Rd, RegisterUtils.SpRegister, inst.Rm, inst.Stype, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3), inst.S != 0); + } + + public static void SvcA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Imm24b0w24 inst = new(encoding); + + InstEmitSystem.Svc(context, inst.Imm24); + } + + public static void SvcT1(CodeGenContext context, uint encoding) + { + InstImm8b16w8 inst = new(encoding); + + InstEmitSystem.Svc(context, inst.Imm8); + } + + public static void SxtabA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rotateb10w2Rmb0w4 inst = new(encoding); + + InstEmitExtension.Sxtab(context, inst.Rd, inst.Rn, inst.Rm, inst.Rotate); + } + + public static void SxtabT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rotateb4w2Rmb0w4 inst = new(encoding); + + InstEmitExtension.Sxtab(context, inst.Rd, inst.Rn, inst.Rm, inst.Rotate); + } + + public static void Sxtab16A1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rotateb10w2Rmb0w4 inst = new(encoding); + + InstEmitExtension.Sxtab16(context, inst.Rd, inst.Rn, inst.Rm, inst.Rotate); + } + + public static void Sxtab16T1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rotateb4w2Rmb0w4 inst = new(encoding); + + InstEmitExtension.Sxtab16(context, inst.Rd, inst.Rn, inst.Rm, inst.Rotate); + } + + public static void SxtahA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rotateb10w2Rmb0w4 inst = new(encoding); + + InstEmitExtension.Sxtah(context, inst.Rd, inst.Rn, inst.Rm, inst.Rotate); + } + + public static void SxtahT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rotateb4w2Rmb0w4 inst = new(encoding); + + InstEmitExtension.Sxtah(context, inst.Rd, inst.Rn, inst.Rm, inst.Rotate); + } + + public static void SxtbA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rdb12w4Rotateb10w2Rmb0w4 inst = new(encoding); + + InstEmitExtension.Sxtb(context, inst.Rd, inst.Rm, inst.Rotate); + } + + public static void SxtbT1(CodeGenContext context, uint encoding) + { + InstRmb19w3Rdb16w3 inst = new(encoding); + + InstEmitExtension.Sxtb(context, inst.Rd, inst.Rm, 0); + } + + public static void SxtbT2(CodeGenContext context, uint encoding) + { + InstRdb8w4Rotateb4w2Rmb0w4 inst = new(encoding); + + InstEmitExtension.Sxtb(context, inst.Rd, inst.Rm, inst.Rotate); + } + + public static void Sxtb16A1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rdb12w4Rotateb10w2Rmb0w4 inst = new(encoding); + + InstEmitExtension.Sxtb16(context, inst.Rd, inst.Rm, inst.Rotate); + } + + public static void Sxtb16T1(CodeGenContext context, uint encoding) + { + InstRdb8w4Rotateb4w2Rmb0w4 inst = new(encoding); + + InstEmitExtension.Sxtb16(context, inst.Rd, inst.Rm, inst.Rotate); + } + + public static void SxthA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rdb12w4Rotateb10w2Rmb0w4 inst = new(encoding); + + InstEmitExtension.Sxth(context, inst.Rd, inst.Rm, inst.Rotate); + } + + public static void SxthT1(CodeGenContext context, uint encoding) + { + InstRmb19w3Rdb16w3 inst = new(encoding); + + InstEmitExtension.Sxth(context, inst.Rd, inst.Rm, 0); + } + + public static void SxthT2(CodeGenContext context, uint encoding) + { + InstRdb8w4Rotateb4w2Rmb0w4 inst = new(encoding); + + InstEmitExtension.Sxth(context, inst.Rd, inst.Rm, inst.Rotate); + } + + public static void TbbT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Hb4w1Rmb0w4 inst = new(encoding); + + InstEmitFlow.Tbb(context, inst.Rn, inst.Rm, inst.H != 0); + } + + public static void TeqIA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Imm12b0w12 inst = new(encoding); + + InstEmitAlu.TeqI(context, inst.Rn, ImmUtils.ExpandImm(inst.Imm12), ImmUtils.ExpandedImmRotated(inst.Imm12)); + } + + public static void TeqIT1(CodeGenContext context, uint encoding) + { + InstIb26w1Rnb16w4Imm3b12w3Imm8b0w8 inst = new(encoding); + + InstEmitAlu.TeqI(context, inst.Rn, ImmUtils.ExpandImm(inst.Imm8, inst.Imm3, inst.I), ImmUtils.ExpandedImmRotated(inst.Imm8, inst.Imm3, inst.I)); + } + + public static void TeqRA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding); + + InstEmitAlu.TeqR(context, inst.Rn, inst.Rm, inst.Stype, inst.Imm5); + } + + public static void TeqRT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Imm3b12w3Imm2b6w2Stypeb4w2Rmb0w4 inst = new(encoding); + + InstEmitAlu.TeqR(context, inst.Rn, inst.Rm, inst.Stype, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3)); + } + + public static void TeqRrA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rsb8w4Stypeb5w2Rmb0w4 inst = new(encoding); + + InstEmitAlu.TeqRr(context, inst.Rn, inst.Rm, inst.Stype, inst.Rs); + } + + public static void TsbA1(CodeGenContext context, uint encoding) + { + context.Arm64Assembler.Tsb(); + } + + public static void TsbT1(CodeGenContext context, uint encoding) + { + context.Arm64Assembler.Tsb(); + } + + public static void TstIA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Imm12b0w12 inst = new(encoding); + + InstEmitAlu.TstI(context, inst.Rn, ImmUtils.ExpandImm(inst.Imm12), ImmUtils.ExpandedImmRotated(inst.Imm12)); + } + + public static void TstIT1(CodeGenContext context, uint encoding) + { + InstIb26w1Rnb16w4Imm3b12w3Imm8b0w8 inst = new(encoding); + + InstEmitAlu.TstI(context, inst.Rn, ImmUtils.ExpandImm(inst.Imm8, inst.Imm3, inst.I), ImmUtils.ExpandedImmRotated(inst.Imm8, inst.Imm3, inst.I)); + } + + public static void TstRA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Imm5b7w5Stypeb5w2Rmb0w4 inst = new(encoding); + + InstEmitAlu.TstR(context, inst.Rn, inst.Rm, inst.Stype, inst.Imm5); + } + + public static void TstRT1(CodeGenContext context, uint encoding) + { + InstRmb19w3Rnb16w3 inst = new(encoding); + + InstEmitAlu.TstR(context, inst.Rn, inst.Rm, 0, 0); + } + + public static void TstRT2(CodeGenContext context, uint encoding) + { + InstRnb16w4Imm3b12w3Imm2b6w2Stypeb4w2Rmb0w4 inst = new(encoding); + + InstEmitAlu.TstR(context, inst.Rn, inst.Rm, inst.Stype, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3)); + } + + public static void TstRrA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rsb8w4Stypeb5w2Rmb0w4 inst = new(encoding); + + InstEmitAlu.TstRr(context, inst.Rn, inst.Rm, inst.Stype, inst.Rs); + } + + public static void Uadd16A1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding); + + InstEmitGE.Uadd16(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void Uadd16T1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitGE.Uadd16(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void Uadd8A1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding); + + InstEmitGE.Uadd8(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void Uadd8T1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitGE.Uadd8(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void UasxA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding); + + InstEmitGE.Uasx(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void UasxT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitGE.Uasx(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void UbfxA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Widthm1b16w5Rdb12w4Lsbb7w5Rnb0w4 inst = new(encoding); + + InstEmitBit.Ubfx(context, inst.Rd, inst.Rn, inst.Lsb, inst.Widthm1); + } + + public static void UbfxT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Imm3b12w3Rdb8w4Imm2b6w2Widthm1b0w5 inst = new(encoding); + + InstEmitBit.Ubfx(context, inst.Rd, inst.Rn, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3), inst.Widthm1); + } + + public static void UdfA1(CodeGenContext context, uint encoding) + { + InstImm12b8w12Imm4b0w4 inst = new(encoding); + + InstEmitSystem.Udf(context, encoding, ImmUtils.CombineImmU16(inst.Imm12, inst.Imm4)); + } + + public static void UdfT1(CodeGenContext context, uint encoding) + { + InstImm8b16w8 inst = new(encoding); + + InstEmitSystem.Udf(context, encoding, inst.Imm8); + } + + public static void UdfT2(CodeGenContext context, uint encoding) + { + InstImm4b16w4Imm12b0w12 inst = new(encoding); + + InstEmitSystem.Udf(context, encoding, ImmUtils.CombineImmU16(inst.Imm12, inst.Imm4)); + } + + public static void UdivA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rdb16w4Rmb8w4Rnb0w4 inst = new(encoding); + + InstEmitDivide.Udiv(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void UdivT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitDivide.Udiv(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void Uhadd16A1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding); + + InstEmitHalve.Uhadd16(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void Uhadd16T1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitHalve.Uhadd16(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void Uhadd8A1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding); + + InstEmitHalve.Uhadd8(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void Uhadd8T1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitHalve.Uhadd8(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void UhasxA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding); + + InstEmitHalve.Uhasx(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void UhasxT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitHalve.Uhasx(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void UhsaxA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding); + + InstEmitHalve.Uhsax(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void UhsaxT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitHalve.Uhsax(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void Uhsub16A1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding); + + InstEmitHalve.Uhsub16(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void Uhsub16T1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitHalve.Uhsub16(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void Uhsub8A1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding); + + InstEmitHalve.Uhsub8(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void Uhsub8T1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitHalve.Uhsub8(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void UmaalA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rdhib16w4Rdlob12w4Rmb8w4Rnb0w4 inst = new(encoding); + + InstEmitMultiply.Umaal(context, inst.Rdlo, inst.Rdhi, inst.Rn, inst.Rm); + } + + public static void UmaalT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdlob12w4Rdhib8w4Rmb0w4 inst = new(encoding); + + InstEmitMultiply.Umaal(context, inst.Rdlo, inst.Rdhi, inst.Rn, inst.Rm); + } + + public static void UmlalA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Sb20w1Rdhib16w4Rdlob12w4Rmb8w4Rnb0w4 inst = new(encoding); + + InstEmitMultiply.Umlal(context, inst.Rdlo, inst.Rdhi, inst.Rn, inst.Rm, inst.S != 0); + } + + public static void UmlalT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdlob12w4Rdhib8w4Rmb0w4 inst = new(encoding); + + InstEmitMultiply.Umlal(context, inst.Rdlo, inst.Rdhi, inst.Rn, inst.Rm, false); + } + + public static void UmullA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Sb20w1Rdhib16w4Rdlob12w4Rmb8w4Rnb0w4 inst = new(encoding); + + InstEmitMultiply.Umull(context, inst.Rdlo, inst.Rdhi, inst.Rn, inst.Rm, inst.S != 0); + } + + public static void UmullT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdlob12w4Rdhib8w4Rmb0w4 inst = new(encoding); + + InstEmitMultiply.Umull(context, inst.Rdlo, inst.Rdhi, inst.Rn, inst.Rm, false); + } + + public static void Uqadd16A1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding); + + InstEmitSaturate.Uqadd16(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void Uqadd16T1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitSaturate.Uqadd16(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void Uqadd8A1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding); + + InstEmitSaturate.Uqadd8(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void Uqadd8T1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitSaturate.Uqadd8(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void UqasxA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding); + + InstEmitSaturate.Uqasx(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void UqasxT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitSaturate.Uqasx(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void UqsaxA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding); + + InstEmitSaturate.Uqsax(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void UqsaxT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitSaturate.Uqsax(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void Uqsub16A1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding); + + InstEmitSaturate.Uqsub16(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void Uqsub16T1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitSaturate.Uqsub16(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void Uqsub8A1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding); + + InstEmitSaturate.Uqsub8(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void Uqsub8T1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitSaturate.Uqsub8(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void Usad8A1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rdb16w4Rmb8w4Rnb0w4 inst = new(encoding); + + InstEmitAbsDiff.Usad8(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void Usad8T1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitAbsDiff.Usad8(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void Usada8A1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rdb16w4Rab12w4Rmb8w4Rnb0w4 inst = new(encoding); + + InstEmitAbsDiff.Usada8(context, inst.Rd, inst.Rn, inst.Rm, inst.Ra); + } + + public static void Usada8T1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rab12w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitAbsDiff.Usada8(context, inst.Rd, inst.Rn, inst.Rm, inst.Ra); + } + + public static void UsatA1(CodeGenContext context, uint encoding) + { + InstCondb28w4SatImmb16w5Rdb12w4Imm5b7w5Shb6w1Rnb0w4 inst = new(encoding); + + InstEmitSaturate.Usat(context, inst.Rd, inst.SatImm, inst.Rn, inst.Sh != 0, inst.Imm5); + } + + public static void UsatT1(CodeGenContext context, uint encoding) + { + InstShb21w1Rnb16w4Imm3b12w3Rdb8w4Imm2b6w2SatImmb0w5 inst = new(encoding); + + InstEmitSaturate.Usat(context, inst.Rd, inst.SatImm, inst.Rn, inst.Sh != 0, ImmUtils.CombineImmU5(inst.Imm2, inst.Imm3)); + } + + public static void Usat16A1(CodeGenContext context, uint encoding) + { + InstCondb28w4SatImmb16w4Rdb12w4Rnb0w4 inst = new(encoding); + + InstEmitSaturate.Usat16(context, inst.Rd, inst.SatImm, inst.Rn); + } + + public static void Usat16T1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4SatImmb0w4 inst = new(encoding); + + InstEmitSaturate.Usat16(context, inst.Rd, inst.SatImm, inst.Rn); + } + + public static void UsaxA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding); + + InstEmitGE.Usax(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void UsaxT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitGE.Usax(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void Usub16A1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding); + + InstEmitGE.Usub16(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void Usub16T1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitGE.Usub16(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void Usub8A1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rmb0w4 inst = new(encoding); + + InstEmitGE.Usub8(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void Usub8T1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rmb0w4 inst = new(encoding); + + InstEmitGE.Usub8(context, inst.Rd, inst.Rn, inst.Rm); + } + + public static void UxtabA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rotateb10w2Rmb0w4 inst = new(encoding); + + InstEmitExtension.Uxtab(context, inst.Rd, inst.Rn, inst.Rm, inst.Rotate); + } + + public static void UxtabT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rotateb4w2Rmb0w4 inst = new(encoding); + + InstEmitExtension.Uxtab(context, inst.Rd, inst.Rn, inst.Rm, inst.Rotate); + } + + public static void Uxtab16A1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rotateb10w2Rmb0w4 inst = new(encoding); + + InstEmitExtension.Uxtab16(context, inst.Rd, inst.Rn, inst.Rm, inst.Rotate); + } + + public static void Uxtab16T1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rotateb4w2Rmb0w4 inst = new(encoding); + + InstEmitExtension.Uxtab16(context, inst.Rd, inst.Rn, inst.Rm, inst.Rotate); + } + + public static void UxtahA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rnb16w4Rdb12w4Rotateb10w2Rmb0w4 inst = new(encoding); + + InstEmitExtension.Uxtah(context, inst.Rd, inst.Rn, inst.Rm, inst.Rotate); + } + + public static void UxtahT1(CodeGenContext context, uint encoding) + { + InstRnb16w4Rdb8w4Rotateb4w2Rmb0w4 inst = new(encoding); + + InstEmitExtension.Uxtah(context, inst.Rd, inst.Rn, inst.Rm, inst.Rotate); + } + + public static void UxtbA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rdb12w4Rotateb10w2Rmb0w4 inst = new(encoding); + + InstEmitExtension.Uxtb(context, inst.Rd, inst.Rm, inst.Rotate); + } + + public static void UxtbT1(CodeGenContext context, uint encoding) + { + InstRmb19w3Rdb16w3 inst = new(encoding); + + InstEmitExtension.Uxtb(context, inst.Rd, inst.Rm, 0); + } + + public static void UxtbT2(CodeGenContext context, uint encoding) + { + InstRdb8w4Rotateb4w2Rmb0w4 inst = new(encoding); + + InstEmitExtension.Uxtb(context, inst.Rd, inst.Rm, inst.Rotate); + } + + public static void Uxtb16A1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rdb12w4Rotateb10w2Rmb0w4 inst = new(encoding); + + InstEmitExtension.Uxtb16(context, inst.Rd, inst.Rm, inst.Rotate); + } + + public static void Uxtb16T1(CodeGenContext context, uint encoding) + { + InstRdb8w4Rotateb4w2Rmb0w4 inst = new(encoding); + + InstEmitExtension.Uxtb16(context, inst.Rd, inst.Rm, inst.Rotate); + } + + public static void UxthA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Rdb12w4Rotateb10w2Rmb0w4 inst = new(encoding); + + InstEmitExtension.Uxth(context, inst.Rd, inst.Rm, inst.Rotate); + } + + public static void UxthT1(CodeGenContext context, uint encoding) + { + InstRmb19w3Rdb16w3 inst = new(encoding); + + InstEmitExtension.Uxth(context, inst.Rd, inst.Rm, 0); + } + + public static void UxthT2(CodeGenContext context, uint encoding) + { + InstRdb8w4Rotateb4w2Rmb0w4 inst = new(encoding); + + InstEmitExtension.Uxth(context, inst.Rd, inst.Rm, inst.Rotate); + } + + public static void VabaA1(CodeGenContext context, uint encoding) + { + InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.Vaba(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q); + } + + public static void VabaT1(CodeGenContext context, uint encoding) + { + InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.Vaba(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q); + } + + public static void VabalA1(CodeGenContext context, uint encoding) + { + InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.Vabal(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size); + } + + public static void VabalT1(CodeGenContext context, uint encoding) + { + InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.Vabal(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size); + } + + public static void VabdlIA1(CodeGenContext context, uint encoding) + { + InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.Vabdl(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size); + } + + public static void VabdlIT1(CodeGenContext context, uint encoding) + { + InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.Vabdl(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size); + } + + public static void VabdFA1(CodeGenContext context, uint encoding) + { + InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VabdF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q); + } + + public static void VabdFT1(CodeGenContext context, uint encoding) + { + InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VabdF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q); + } + + public static void VabdIA1(CodeGenContext context, uint encoding) + { + InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VabdI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q); + } + + public static void VabdIT1(CodeGenContext context, uint encoding) + { + InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VabdI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q); + } + + public static void VabsA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Fb10w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.Vabs(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.F != 0, inst.Size, inst.Q); + } + + public static void VabsA2(CodeGenContext context, uint encoding) + { + InstCondb28w4Db22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpArithmetic.VabsF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VabsT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Fb10w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.Vabs(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.F != 0, inst.Size, inst.Q); + } + + public static void VabsT2(CodeGenContext context, uint encoding) + { + InstDb22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpArithmetic.VabsF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VacgeA1(CodeGenContext context, uint encoding) + { + InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonCompare.Vacge(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q); + } + + public static void VacgeT1(CodeGenContext context, uint encoding) + { + InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonCompare.Vacge(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q); + } + + public static void VacgtA1(CodeGenContext context, uint encoding) + { + InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonCompare.Vacgt(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q); + } + + public static void VacgtT1(CodeGenContext context, uint encoding) + { + InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonCompare.Vacgt(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q); + } + + public static void VaddhnA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.Vaddhn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size); + } + + public static void VaddhnT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.Vaddhn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size); + } + + public static void VaddlA1(CodeGenContext context, uint encoding) + { + InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.Vaddl(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size); + } + + public static void VaddlT1(CodeGenContext context, uint encoding) + { + InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.Vaddl(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size); + } + + public static void VaddwA1(CodeGenContext context, uint encoding) + { + InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.Vaddw(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size); + } + + public static void VaddwT1(CodeGenContext context, uint encoding) + { + InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.Vaddw(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size); + } + + public static void VaddFA1(CodeGenContext context, uint encoding) + { + InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VaddF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q); + } + + public static void VaddFA2(CodeGenContext context, uint encoding) + { + InstCondb28w4Db22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpArithmetic.VaddF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VaddFT1(CodeGenContext context, uint encoding) + { + InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VaddF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q); + } + + public static void VaddFT2(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpArithmetic.VaddF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VaddIA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VaddI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VaddIT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VaddI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VandRA1(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonLogical.VandR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q); + } + + public static void VandRT1(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonLogical.VandR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q); + } + + public static void VbicIA1(CodeGenContext context, uint encoding) + { + InstIb24w1Db22w1Imm3b16w3Vdb12w4Qb6w1Imm4b0w4 inst = new(encoding); + + InstEmitNeonLogical.VbicI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), (encoding >> 8) & 0xf, ImmUtils.CombineImmU8(inst.Imm4, inst.Imm3, inst.I), inst.Q); + } + + public static void VbicIA2(CodeGenContext context, uint encoding) + { + InstIb24w1Db22w1Imm3b16w3Vdb12w4Qb6w1Imm4b0w4 inst = new(encoding); + + InstEmitNeonLogical.VbicI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), (encoding >> 8) & 0xf, ImmUtils.CombineImmU8(inst.Imm4, inst.Imm3, inst.I), inst.Q); + } + + public static void VbicIT1(CodeGenContext context, uint encoding) + { + InstIb28w1Db22w1Imm3b16w3Vdb12w4Qb6w1Imm4b0w4 inst = new(encoding); + + InstEmitNeonLogical.VbicI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), (encoding >> 8) & 0xf, ImmUtils.CombineImmU8(inst.Imm4, inst.Imm3, inst.I), inst.Q); + } + + public static void VbicIT2(CodeGenContext context, uint encoding) + { + InstIb28w1Db22w1Imm3b16w3Vdb12w4Qb6w1Imm4b0w4 inst = new(encoding); + + InstEmitNeonLogical.VbicI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), (encoding >> 8) & 0xf, ImmUtils.CombineImmU8(inst.Imm4, inst.Imm3, inst.I), inst.Q); + } + + public static void VbicRA1(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonLogical.VbicR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q); + } + + public static void VbicRT1(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonLogical.VbicR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q); + } + + public static void VbifA1(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonLogical.VbifR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q); + } + + public static void VbifT1(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonLogical.VbifR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q); + } + + public static void VbitA1(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonLogical.VbitR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q); + } + + public static void VbitT1(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonLogical.VbitR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q); + } + + public static void VbslA1(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonLogical.VbslR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q); + } + + public static void VbslT1(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonLogical.VbslR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q); + } + + public static void VcaddA1(CodeGenContext context, uint encoding) + { + _ = new InstRotb24w1Db22w1Sb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VcaddT1(CodeGenContext context, uint encoding) + { + _ = new InstRotb24w1Db22w1Sb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VceqIA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Fb10w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonCompare.VceqI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.F != 0, inst.Size, inst.Q); + } + + public static void VceqIT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Fb10w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonCompare.VceqI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.F != 0, inst.Size, inst.Q); + } + + public static void VceqRA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonCompare.VceqR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VceqRA2(CodeGenContext context, uint encoding) + { + InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonCompare.VceqFR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q); + } + + public static void VceqRT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonCompare.VceqR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VceqRT2(CodeGenContext context, uint encoding) + { + InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonCompare.VceqFR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q); + } + + public static void VcgeIA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Fb10w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonCompare.VcgeI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.F != 0, inst.Size, inst.Q); + } + + public static void VcgeIT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Fb10w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonCompare.VcgeI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.F != 0, inst.Size, inst.Q); + } + + public static void VcgeRA1(CodeGenContext context, uint encoding) + { + InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonCompare.VcgeR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q); + } + + public static void VcgeRA2(CodeGenContext context, uint encoding) + { + InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonCompare.VcgeFR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q); + } + + public static void VcgeRT1(CodeGenContext context, uint encoding) + { + InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonCompare.VcgeR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q); + } + + public static void VcgeRT2(CodeGenContext context, uint encoding) + { + InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonCompare.VcgeFR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q); + } + + public static void VcgtIA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Fb10w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonCompare.VcgtI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.F != 0, inst.Size, inst.Q); + } + + public static void VcgtIT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Fb10w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonCompare.VcgtI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.F != 0, inst.Size, inst.Q); + } + + public static void VcgtRA1(CodeGenContext context, uint encoding) + { + InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonCompare.VcgtR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q); + } + + public static void VcgtRA2(CodeGenContext context, uint encoding) + { + InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonCompare.VcgtFR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q); + } + + public static void VcgtRT1(CodeGenContext context, uint encoding) + { + InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonCompare.VcgtR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q); + } + + public static void VcgtRT2(CodeGenContext context, uint encoding) + { + InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonCompare.VcgtFR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q); + } + + public static void VcleIA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Fb10w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonCompare.VcleI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.F != 0, inst.Size, inst.Q); + } + + public static void VcleIT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Fb10w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonCompare.VcleI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.F != 0, inst.Size, inst.Q); + } + + public static void VclsA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonBit.Vcls(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VclsT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonBit.Vcls(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VcltIA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Fb10w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonCompare.VcltI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.F != 0, inst.Size, inst.Q); + } + + public static void VcltIT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Fb10w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonCompare.VcltI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.F != 0, inst.Size, inst.Q); + } + + public static void VclzA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonBit.Vclz(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VclzT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonBit.Vclz(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VcmlaA1(CodeGenContext context, uint encoding) + { + _ = new InstRotb23w2Db22w1Sb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VcmlaT1(CodeGenContext context, uint encoding) + { + _ = new InstRotb23w2Db22w1Sb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VcmlaSA1(CodeGenContext context, uint encoding) + { + _ = new InstSb23w1Db22w1Rotb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VcmlaST1(CodeGenContext context, uint encoding) + { + _ = new InstSb23w1Db22w1Rotb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VcmpA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Db22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpCompare.VcmpR(context, inst.Cond, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VcmpA2(CodeGenContext context, uint encoding) + { + InstCondb28w4Db22w1Vdb12w4Sizeb8w2 inst = new(encoding); + + InstEmitVfpCompare.VcmpI(context, inst.Cond, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), inst.Size); + } + + public static void VcmpT1(CodeGenContext context, uint encoding) + { + InstDb22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpCompare.VcmpR(context, 0xe, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VcmpT2(CodeGenContext context, uint encoding) + { + InstDb22w1Vdb12w4Sizeb8w2 inst = new(encoding); + + InstEmitVfpCompare.VcmpI(context, 0xe, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), inst.Size); + } + + public static void VcmpeA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Db22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpCompare.VcmpeR(context, inst.Cond, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VcmpeA2(CodeGenContext context, uint encoding) + { + InstCondb28w4Db22w1Vdb12w4Sizeb8w2 inst = new(encoding); + + InstEmitVfpCompare.VcmpeI(context, inst.Cond, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), inst.Size); + } + + public static void VcmpeT1(CodeGenContext context, uint encoding) + { + InstDb22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpCompare.VcmpeR(context, 0xe, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VcmpeT2(CodeGenContext context, uint encoding) + { + InstDb22w1Vdb12w4Sizeb8w2 inst = new(encoding); + + InstEmitVfpCompare.VcmpeI(context, 0xe, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), inst.Size); + } + + public static void VcntA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonBit.Vcnt(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VcntT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonBit.Vcnt(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VcvtaAsimdA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Opb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonConvert.Vcvta(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op != 0, inst.Size, inst.Q); + } + + public static void VcvtaAsimdT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Opb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonConvert.Vcvta(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op != 0, inst.Size, inst.Q); + } + + public static void VcvtaVfpA1(CodeGenContext context, uint encoding) + { + InstDb22w1Vdb12w4Sizeb8w2Opb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpConvert.Vcvta(context, InstEmitCommon.CombineVF(inst.D, inst.Vd), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Op != 0, inst.Size); + } + + public static void VcvtaVfpT1(CodeGenContext context, uint encoding) + { + InstDb22w1Vdb12w4Sizeb8w2Opb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpConvert.Vcvta(context, InstEmitCommon.CombineVF(inst.D, inst.Vd), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Op != 0, inst.Size); + } + + public static void VcvtbA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Db22w1Opb16w1Vdb12w4Szb8w1Mb5w1Vmb0w4 inst = new(encoding); + + uint dSize = inst.Sz == 1 && inst.Op == 0 ? 3u : 2u; + uint mSize = inst.Sz == 1 && inst.Op == 1 ? 3u : 2u; + + InstEmitVfpConvert.Vcvtb(context, InstEmitCommon.CombineV(inst.Vd, inst.D, dSize), InstEmitCommon.CombineV(inst.Vm, inst.M, mSize), inst.Sz, inst.Op); + } + + public static void VcvtbT1(CodeGenContext context, uint encoding) + { + InstDb22w1Opb16w1Vdb12w4Szb8w1Mb5w1Vmb0w4 inst = new(encoding); + + uint dSize = inst.Sz == 1 && inst.Op == 0 ? 3u : 2u; + uint mSize = inst.Sz == 1 && inst.Op == 1 ? 3u : 2u; + + InstEmitVfpConvert.Vcvtb(context, InstEmitCommon.CombineV(inst.Vd, inst.D, dSize), InstEmitCommon.CombineV(inst.Vm, inst.M, mSize), inst.Sz, inst.Op); + } + + public static void VcvtbBfsA1(CodeGenContext context, uint encoding) + { + _ = new InstCondb28w4Db22w1Vdb12w4Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VcvtbBfsT1(CodeGenContext context, uint encoding) + { + _ = new InstDb22w1Vdb12w4Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VcvtmAsimdA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Opb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonConvert.Vcvtm(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op != 0, inst.Size, inst.Q); + } + + public static void VcvtmAsimdT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Opb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonConvert.Vcvtm(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op != 0, inst.Size, inst.Q); + } + + public static void VcvtmVfpA1(CodeGenContext context, uint encoding) + { + InstDb22w1Vdb12w4Sizeb8w2Opb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpConvert.Vcvtm(context, InstEmitCommon.CombineVF(inst.D, inst.Vd), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Op != 0, inst.Size); + } + + public static void VcvtmVfpT1(CodeGenContext context, uint encoding) + { + InstDb22w1Vdb12w4Sizeb8w2Opb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpConvert.Vcvtm(context, InstEmitCommon.CombineVF(inst.D, inst.Vd), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Op != 0, inst.Size); + } + + public static void VcvtnAsimdA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Opb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonConvert.Vcvtn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op != 0, inst.Size, inst.Q); + } + + public static void VcvtnAsimdT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Opb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonConvert.Vcvtn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op != 0, inst.Size, inst.Q); + } + + public static void VcvtnVfpA1(CodeGenContext context, uint encoding) + { + InstDb22w1Vdb12w4Sizeb8w2Opb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpConvert.Vcvtn(context, InstEmitCommon.CombineVF(inst.D, inst.Vd), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Op != 0, inst.Size); + } + + public static void VcvtnVfpT1(CodeGenContext context, uint encoding) + { + InstDb22w1Vdb12w4Sizeb8w2Opb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpConvert.Vcvtn(context, InstEmitCommon.CombineVF(inst.D, inst.Vd), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Op != 0, inst.Size); + } + + public static void VcvtpAsimdA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Opb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonConvert.Vcvtp(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op != 0, inst.Size, inst.Q); + } + + public static void VcvtpAsimdT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Opb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonConvert.Vcvtp(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op != 0, inst.Size, inst.Q); + } + + public static void VcvtpVfpA1(CodeGenContext context, uint encoding) + { + InstDb22w1Vdb12w4Sizeb8w2Opb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpConvert.Vcvtp(context, InstEmitCommon.CombineVF(inst.D, inst.Vd), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Op != 0, inst.Size); + } + + public static void VcvtpVfpT1(CodeGenContext context, uint encoding) + { + InstDb22w1Vdb12w4Sizeb8w2Opb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpConvert.Vcvtp(context, InstEmitCommon.CombineVF(inst.D, inst.Vd), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Op != 0, inst.Size); + } + + public static void VcvtrIvA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Db22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpConvert.VcvtrIv(context, InstEmitCommon.CombineVF(inst.D, inst.Vd), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), (encoding >> 16) & 7, inst.Size); + } + + public static void VcvtrIvT1(CodeGenContext context, uint encoding) + { + InstDb22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpConvert.VcvtrIv(context, InstEmitCommon.CombineVF(inst.D, inst.Vd), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), (encoding >> 16) & 7, inst.Size); + } + + public static void VcvttA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Db22w1Opb16w1Vdb12w4Szb8w1Mb5w1Vmb0w4 inst = new(encoding); + + uint dSize = inst.Sz == 1 && inst.Op == 0 ? 3u : 2u; + uint mSize = inst.Sz == 1 && inst.Op == 1 ? 3u : 2u; + + InstEmitVfpConvert.Vcvtt(context, InstEmitCommon.CombineV(inst.Vd, inst.D, dSize), InstEmitCommon.CombineV(inst.Vm, inst.M, mSize), inst.Sz, inst.Op); + } + + public static void VcvttT1(CodeGenContext context, uint encoding) + { + InstDb22w1Opb16w1Vdb12w4Szb8w1Mb5w1Vmb0w4 inst = new(encoding); + + uint dSize = inst.Sz == 1 && inst.Op == 0 ? 3u : 2u; + uint mSize = inst.Sz == 1 && inst.Op == 1 ? 3u : 2u; + + InstEmitVfpConvert.Vcvtt(context, InstEmitCommon.CombineV(inst.Vd, inst.D, dSize), InstEmitCommon.CombineV(inst.Vm, inst.M, mSize), inst.Sz, inst.Op); + } + + public static void VcvttBfsA1(CodeGenContext context, uint encoding) + { + _ = new InstCondb28w4Db22w1Vdb12w4Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VcvttBfsT1(CodeGenContext context, uint encoding) + { + _ = new InstDb22w1Vdb12w4Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VcvtBfsA1(CodeGenContext context, uint encoding) + { + _ = new InstDb22w1Vdb12w4Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VcvtBfsT1(CodeGenContext context, uint encoding) + { + _ = new InstDb22w1Vdb12w4Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VcvtDsA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Db22w1Vdb12w4Mb5w1Vmb0w4 inst = new(encoding); + + uint size = (encoding >> 8) & 3; + + InstEmitVfpConvert.VcvtDs(context, InstEmitCommon.CombineV(inst.Vd, inst.D, size ^ 1u), InstEmitCommon.CombineV(inst.Vm, inst.M, size), size); + } + + public static void VcvtDsT1(CodeGenContext context, uint encoding) + { + InstDb22w1Vdb12w4Mb5w1Vmb0w4 inst = new(encoding); + + uint size = (encoding >> 8) & 3; + + InstEmitVfpConvert.VcvtDs(context, InstEmitCommon.CombineV(inst.Vd, inst.D, size ^ 1u), InstEmitCommon.CombineV(inst.Vm, inst.M, size), size); + } + + public static void VcvtHsA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Opb8w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonConvert.VcvtHs(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op != 0); + } + + public static void VcvtHsT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Opb8w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonConvert.VcvtHs(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op != 0); + } + + public static void VcvtIsA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Opb7w2Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonConvert.VcvtIs(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op, inst.Size, inst.Q); + } + + public static void VcvtIsT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Opb7w2Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonConvert.VcvtIs(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op, inst.Size, inst.Q); + } + + public static void VcvtIvA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Db22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpConvert.VcvtIv(context, InstEmitCommon.CombineVF(inst.D, inst.Vd), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), (encoding & (1u << 16)) == 0, inst.Size); + } + + public static void VcvtIvT1(CodeGenContext context, uint encoding) + { + InstDb22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpConvert.VcvtIv(context, InstEmitCommon.CombineVF(inst.D, inst.Vd), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), (encoding & (1u << 16)) == 0, inst.Size); + } + + public static void VcvtViA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Db22w1Vdb12w4Sizeb8w2Opb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpConvert.VcvtVi(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineVF(inst.M, inst.Vm), inst.Op == 0, inst.Size); + } + + public static void VcvtViT1(CodeGenContext context, uint encoding) + { + InstDb22w1Vdb12w4Sizeb8w2Opb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpConvert.VcvtVi(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineVF(inst.M, inst.Vm), inst.Op == 0, inst.Size); + } + + public static void VcvtXsA1(CodeGenContext context, uint encoding) + { + InstUb24w1Db22w1Imm6b16w6Vdb12w4Opb8w2Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonConvert.VcvtXs(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Imm6, inst.Op, inst.U != 0, inst.Q); + } + + public static void VcvtXsT1(CodeGenContext context, uint encoding) + { + InstUb28w1Db22w1Imm6b16w6Vdb12w4Opb8w2Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonConvert.VcvtXs(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Imm6, inst.Op, inst.U != 0, inst.Q); + } + + public static void VcvtXvA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Db22w1Opb18w1Ub16w1Vdb12w4Sfb8w2Sxb7w1Ib5w1Imm4b0w4 inst = new(encoding); + + InstEmitVfpConvert.VcvtXv(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Sf), ImmUtils.CombineImmU5IImm4(inst.I, inst.Imm4), inst.Sx != 0, inst.Sf, inst.Op, inst.U != 0); + } + + public static void VcvtXvT1(CodeGenContext context, uint encoding) + { + InstDb22w1Opb18w1Ub16w1Vdb12w4Sfb8w2Sxb7w1Ib5w1Imm4b0w4 inst = new(encoding); + + InstEmitVfpConvert.VcvtXv(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Sf), ImmUtils.CombineImmU5IImm4(inst.I, inst.Imm4), inst.Sx != 0, inst.Sf, inst.Op, inst.U != 0); + } + + public static void VdivA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Db22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpArithmetic.VdivF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VdivT1(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpArithmetic.VdivF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VdotA1(CodeGenContext context, uint encoding) + { + _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VdotT1(CodeGenContext context, uint encoding) + { + _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VdotSA1(CodeGenContext context, uint encoding) + { + _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VdotST1(CodeGenContext context, uint encoding) + { + _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VdupRA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Bb22w1Qb21w1Vdb16w4Rtb12w4Db7w1Eb5w1 inst = new(encoding); + + InstEmitNeonMove.VdupR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rt, inst.B, inst.E, inst.Q); + } + + public static void VdupRT1(CodeGenContext context, uint encoding) + { + InstBb22w1Qb21w1Vdb16w4Rtb12w4Db7w1Eb5w1 inst = new(encoding); + + InstEmitNeonMove.VdupR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rt, inst.B, inst.E, inst.Q); + } + + public static void VdupSA1(CodeGenContext context, uint encoding) + { + InstDb22w1Imm4b16w4Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonMove.VdupS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Imm4, inst.Q); + } + + public static void VdupST1(CodeGenContext context, uint encoding) + { + InstDb22w1Imm4b16w4Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonMove.VdupS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Imm4, inst.Q); + } + + public static void VeorA1(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonLogical.VeorR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q); + } + + public static void VeorT1(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonLogical.VeorR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q); + } + + public static void VextA1(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Imm4b8w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonMove.Vext(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Imm4, inst.Q); + } + + public static void VextT1(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Imm4b8w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonMove.Vext(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Imm4, inst.Q); + } + + public static void VfmaA1(CodeGenContext context, uint encoding) + { + InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VfmaF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q); + } + + public static void VfmaA2(CodeGenContext context, uint encoding) + { + InstCondb28w4Db22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpArithmetic.VfmaF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VfmaT1(CodeGenContext context, uint encoding) + { + InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VfmaF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q); + } + + public static void VfmaT2(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpArithmetic.VfmaF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VfmalA1(CodeGenContext context, uint encoding) + { + _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VfmalT1(CodeGenContext context, uint encoding) + { + _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VfmalSA1(CodeGenContext context, uint encoding) + { + _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VfmalST1(CodeGenContext context, uint encoding) + { + _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VfmaBfA1(CodeGenContext context, uint encoding) + { + _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VfmaBfT1(CodeGenContext context, uint encoding) + { + _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VfmaBfsA1(CodeGenContext context, uint encoding) + { + _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VfmaBfsT1(CodeGenContext context, uint encoding) + { + _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VfmsA1(CodeGenContext context, uint encoding) + { + InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VfmsF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q); + } + + public static void VfmsA2(CodeGenContext context, uint encoding) + { + InstCondb28w4Db22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpArithmetic.VfmsF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VfmsT1(CodeGenContext context, uint encoding) + { + InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VfmsF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q); + } + + public static void VfmsT2(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpArithmetic.VfmsF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VfmslA1(CodeGenContext context, uint encoding) + { + _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VfmslT1(CodeGenContext context, uint encoding) + { + _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VfmslSA1(CodeGenContext context, uint encoding) + { + _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VfmslST1(CodeGenContext context, uint encoding) + { + _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VfnmaA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Db22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpArithmetic.VfnmaF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VfnmaT1(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpArithmetic.VfnmaF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VfnmsA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Db22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpArithmetic.VfnmsF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VfnmsT1(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpArithmetic.VfnmsF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VhaddA1(CodeGenContext context, uint encoding) + { + InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.Vhadd(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q); + } + + public static void VhaddT1(CodeGenContext context, uint encoding) + { + InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.Vhadd(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q); + } + + public static void VhsubA1(CodeGenContext context, uint encoding) + { + InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.Vhsub(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q); + } + + public static void VhsubT1(CodeGenContext context, uint encoding) + { + InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.Vhsub(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q); + } + + public static void VinsA1(CodeGenContext context, uint encoding) + { + _ = new InstDb22w1Vdb12w4Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VinsT1(CodeGenContext context, uint encoding) + { + _ = new InstDb22w1Vdb12w4Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VjcvtA1(CodeGenContext context, uint encoding) + { + _ = new InstCondb28w4Db22w1Vdb12w4Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VjcvtT1(CodeGenContext context, uint encoding) + { + _ = new InstDb22w1Vdb12w4Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void Vld11A1(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vld11(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 0); + } + + public static void Vld11A2(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vld11(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 1); + } + + public static void Vld11A3(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vld11(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 2); + } + + public static void Vld11T1(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vld11(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 0); + } + + public static void Vld11T2(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vld11(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 1); + } + + public static void Vld11T3(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vld11(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 2); + } + + public static void Vld1AA1(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Tb5w1Ab4w1Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vld1A(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.A, inst.T, inst.Size); + } + + public static void Vld1AT1(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Tb5w1Ab4w1Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vld1A(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.A, inst.T, inst.Size); + } + + public static void Vld1MA1(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vld1M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, 1, inst.Align, inst.Size); + } + + public static void Vld1MA2(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vld1M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, 2, inst.Align, inst.Size); + } + + public static void Vld1MA3(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vld1M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, 3, inst.Align, inst.Size); + } + + public static void Vld1MA4(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vld1M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, 4, inst.Align, inst.Size); + } + + public static void Vld1MT1(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vld1M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, 1, inst.Align, inst.Size); + } + + public static void Vld1MT2(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vld1M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, 2, inst.Align, inst.Size); + } + + public static void Vld1MT3(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vld1M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, 3, inst.Align, inst.Size); + } + + public static void Vld1MT4(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vld1M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, 4, inst.Align, inst.Size); + } + + public static void Vld21A1(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vld21(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 0); + } + + public static void Vld21A2(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vld21(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 1); + } + + public static void Vld21A3(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vld21(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 2); + } + + public static void Vld21T1(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vld21(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 0); + } + + public static void Vld21T2(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vld21(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 1); + } + + public static void Vld21T3(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vld21(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 2); + } + + public static void Vld2AA1(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Tb5w1Ab4w1Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vld2A(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.A, inst.T, inst.Size); + } + + public static void Vld2AT1(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Tb5w1Ab4w1Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vld2A(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.A, inst.T, inst.Size); + } + + public static void Vld2MA1(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vld2M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, (encoding >> 8) & 0xf, inst.Align, inst.Size); + } + + public static void Vld2MA2(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vld2M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.Align, inst.Size); + } + + public static void Vld2MT1(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vld2M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, (encoding >> 8) & 0xf, inst.Align, inst.Size); + } + + public static void Vld2MT2(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vld2M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.Align, inst.Size); + } + + public static void Vld31A1(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vld31(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 0); + } + + public static void Vld31A2(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vld31(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 1); + } + + public static void Vld31A3(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vld31(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 2); + } + + public static void Vld31T1(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vld31(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 0); + } + + public static void Vld31T2(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vld31(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 1); + } + + public static void Vld31T3(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vld31(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 2); + } + + public static void Vld3AA1(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Tb5w1Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vld3A(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, 0, inst.T, inst.Size); + } + + public static void Vld3AT1(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Tb5w1Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vld3A(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, 0, inst.T, inst.Size); + } + + public static void Vld3MA1(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vld3M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, (encoding >> 8) & 0xf, inst.Align, inst.Size); + } + + public static void Vld3MT1(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vld3M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, (encoding >> 8) & 0xf, inst.Align, inst.Size); + } + + public static void Vld41A1(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vld41(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 0); + } + + public static void Vld41A2(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vld41(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 1); + } + + public static void Vld41A3(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vld41(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 2); + } + + public static void Vld41T1(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vld41(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 0); + } + + public static void Vld41T2(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vld41(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 1); + } + + public static void Vld41T3(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vld41(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 2); + } + + public static void Vld4AA1(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Tb5w1Ab4w1Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vld4A(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.A, inst.T, inst.Size); + } + + public static void Vld4AT1(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Tb5w1Ab4w1Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vld4A(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.A, inst.T, inst.Size); + } + + public static void Vld4MA1(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vld4M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, (encoding >> 8) & 0xf, inst.Align, inst.Size); + } + + public static void Vld4MT1(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vld4M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, (encoding >> 8) & 0xf, inst.Align, inst.Size); + } + + public static void VldmA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Pb24w1Ub23w1Db22w1Wb21w1Rnb16w4Vdb12w4Imm871b1w7 inst = new(encoding); + + InstEmitNeonMemory.Vldm(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Imm871, inst.U != 0, inst.W != 0, singleRegs: false); + } + + public static void VldmA2(CodeGenContext context, uint encoding) + { + InstCondb28w4Pb24w1Ub23w1Db22w1Wb21w1Rnb16w4Vdb12w4Imm8b0w8 inst = new(encoding); + + InstEmitNeonMemory.Vldm(context, InstEmitCommon.CombineVF(inst.D, inst.Vd), inst.Rn, inst.Imm8, inst.U != 0, inst.W != 0, singleRegs: true); + } + + public static void VldmT1(CodeGenContext context, uint encoding) + { + InstPb24w1Ub23w1Db22w1Wb21w1Rnb16w4Vdb12w4Imm871b1w7 inst = new(encoding); + + InstEmitNeonMemory.Vldm(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Imm871, inst.U != 0, inst.W != 0, singleRegs: false); + } + + public static void VldmT2(CodeGenContext context, uint encoding) + { + InstPb24w1Ub23w1Db22w1Wb21w1Rnb16w4Vdb12w4Imm8b0w8 inst = new(encoding); + + InstEmitNeonMemory.Vldm(context, InstEmitCommon.CombineVF(inst.D, inst.Vd), inst.Rn, inst.Imm8, inst.U != 0, inst.W != 0, singleRegs: true); + } + + public static void VldrIA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Ub23w1Db22w1Rnb16w4Vdb12w4Sizeb8w2Imm8b0w8 inst = new(encoding); + + InstEmitNeonMemory.Vldr(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), inst.Rn, inst.Imm8, inst.U != 0, inst.Size); + } + + public static void VldrIT1(CodeGenContext context, uint encoding) + { + InstUb23w1Db22w1Rnb16w4Vdb12w4Sizeb8w2Imm8b0w8 inst = new(encoding); + + InstEmitNeonMemory.Vldr(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), inst.Rn, inst.Imm8, inst.U != 0, inst.Size); + } + + public static void VldrLA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Ub23w1Db22w1Vdb12w4Sizeb8w2Imm8b0w8 inst = new(encoding); + + InstEmitNeonMemory.Vldr(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), RegisterUtils.PcRegister, inst.Imm8, inst.U != 0, inst.Size); + } + + public static void VldrLT1(CodeGenContext context, uint encoding) + { + InstUb23w1Db22w1Vdb12w4Sizeb8w2Imm8b0w8 inst = new(encoding); + + InstEmitNeonMemory.Vldr(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), RegisterUtils.PcRegister, inst.Imm8, inst.U != 0, inst.Size); + } + + public static void VmaxnmA1(CodeGenContext context, uint encoding) + { + InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.Vmaxnm(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q); + } + + public static void VmaxnmA2(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpArithmetic.Vmaxnm(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VmaxnmT1(CodeGenContext context, uint encoding) + { + InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.Vmaxnm(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q); + } + + public static void VmaxnmT2(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpArithmetic.Vmaxnm(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VmaxFA1(CodeGenContext context, uint encoding) + { + InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VmaxF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q); + } + + public static void VmaxFT1(CodeGenContext context, uint encoding) + { + InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VmaxF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q); + } + + public static void VmaxIA1(CodeGenContext context, uint encoding) + { + InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VmaxI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q); + } + + public static void VmaxIT1(CodeGenContext context, uint encoding) + { + InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VmaxI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q); + } + + public static void VminnmA1(CodeGenContext context, uint encoding) + { + InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.Vminnm(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q); + } + + public static void VminnmA2(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpArithmetic.Vminnm(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VminnmT1(CodeGenContext context, uint encoding) + { + InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.Vminnm(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q); + } + + public static void VminnmT2(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpArithmetic.Vminnm(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VminFA1(CodeGenContext context, uint encoding) + { + InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VminF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q); + } + + public static void VminFT1(CodeGenContext context, uint encoding) + { + InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VminF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q); + } + + public static void VminIA1(CodeGenContext context, uint encoding) + { + InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VminI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q); + } + + public static void VminIT1(CodeGenContext context, uint encoding) + { + InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VminI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q); + } + + public static void VmlalIA1(CodeGenContext context, uint encoding) + { + InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VmlalI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size); + } + + public static void VmlalIT1(CodeGenContext context, uint encoding) + { + InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VmlalI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size); + } + + public static void VmlalSA1(CodeGenContext context, uint encoding) + { + InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VmlalS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size); + } + + public static void VmlalST1(CodeGenContext context, uint encoding) + { + InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VmlalS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size); + } + + public static void VmlaFA1(CodeGenContext context, uint encoding) + { + InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VmlaF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q); + } + + public static void VmlaFA2(CodeGenContext context, uint encoding) + { + InstCondb28w4Db22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpArithmetic.VmlaF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VmlaFT1(CodeGenContext context, uint encoding) + { + InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VmlaF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q); + } + + public static void VmlaFT2(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpArithmetic.VmlaF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VmlaIA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VmlaI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VmlaIT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VmlaI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VmlaSA1(CodeGenContext context, uint encoding) + { + InstQb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Fb8w1Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VmlaS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.F != 0, inst.Size, inst.Q); + } + + public static void VmlaST1(CodeGenContext context, uint encoding) + { + InstQb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Fb8w1Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VmlaS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.F != 0, inst.Size, inst.Q); + } + + public static void VmlslIA1(CodeGenContext context, uint encoding) + { + InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VmlslI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size); + } + + public static void VmlslIT1(CodeGenContext context, uint encoding) + { + InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VmlslI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size); + } + + public static void VmlslSA1(CodeGenContext context, uint encoding) + { + InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VmlslS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size); + } + + public static void VmlslST1(CodeGenContext context, uint encoding) + { + InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VmlslS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size); + } + + public static void VmlsFA1(CodeGenContext context, uint encoding) + { + InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VmlsF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q); + } + + public static void VmlsFA2(CodeGenContext context, uint encoding) + { + InstCondb28w4Db22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpArithmetic.VmlsF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VmlsFT1(CodeGenContext context, uint encoding) + { + InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VmlsF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q); + } + + public static void VmlsFT2(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpArithmetic.VmlsF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VmlsIA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VmlsI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VmlsIT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VmlsI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VmlsSA1(CodeGenContext context, uint encoding) + { + InstQb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Fb8w1Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VmlsS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.F != 0, inst.Size, inst.Q); + } + + public static void VmlsST1(CodeGenContext context, uint encoding) + { + InstQb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Fb8w1Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VmlsS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.F != 0, inst.Size, inst.Q); + } + + public static void VmmlaA1(CodeGenContext context, uint encoding) + { + _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VmmlaT1(CodeGenContext context, uint encoding) + { + _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VmovlA1(CodeGenContext context, uint encoding) + { + InstUb24w1Db22w1Imm3hb19w3Vdb12w4Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonMove.Vmovl(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Imm3h); + } + + public static void VmovlT1(CodeGenContext context, uint encoding) + { + InstUb28w1Db22w1Imm3hb19w3Vdb12w4Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonMove.Vmovl(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Imm3h); + } + + public static void VmovnA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonMove.Vmovn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size); + } + + public static void VmovnT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonMove.Vmovn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size); + } + + public static void VmovxA1(CodeGenContext context, uint encoding) + { + InstDb22w1Vdb12w4Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonMove.Vmovx(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M)); + } + + public static void VmovxT1(CodeGenContext context, uint encoding) + { + InstDb22w1Vdb12w4Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonMove.Vmovx(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M)); + } + + public static void VmovDA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Opb20w1Rt2b16w4Rtb12w4Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonMove.VmovD(context, inst.Rt, inst.Rt2, InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op != 0); + } + + public static void VmovDT1(CodeGenContext context, uint encoding) + { + InstOpb20w1Rt2b16w4Rtb12w4Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonMove.VmovD(context, inst.Rt, inst.Rt2, InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op != 0); + } + + public static void VmovHA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Opb20w1Vnb16w4Rtb12w4Nb7w1 inst = new(encoding); + + InstEmitNeonMove.VmovH(context, inst.Rt, InstEmitCommon.CombineVF(inst.N, inst.Vn), inst.Op != 0); + } + + public static void VmovHT1(CodeGenContext context, uint encoding) + { + InstOpb20w1Vnb16w4Rtb12w4Nb7w1 inst = new(encoding); + + InstEmitNeonMove.VmovH(context, inst.Rt, InstEmitCommon.CombineVF(inst.N, inst.Vn), inst.Op != 0); + } + + public static void VmovIA1(CodeGenContext context, uint encoding) + { + InstIb24w1Db22w1Imm3b16w3Vdb12w4Qb6w1Imm4b0w4 inst = new(encoding); + + InstEmitNeonMove.VmovI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), 0, (encoding >> 8) & 0xf, ImmUtils.CombineImmU8(inst.Imm4, inst.Imm3, inst.I), inst.Q); + } + + public static void VmovIA2(CodeGenContext context, uint encoding) + { + InstCondb28w4Db22w1Imm4hb16w4Vdb12w4Sizeb8w2Imm4lb0w4 inst = new(encoding); + + InstEmitNeonMove.VmovFI(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), ImmUtils.CombineImmU8(inst.Imm4l, inst.Imm4h), inst.Size); + } + + public static void VmovIA3(CodeGenContext context, uint encoding) + { + InstIb24w1Db22w1Imm3b16w3Vdb12w4Qb6w1Imm4b0w4 inst = new(encoding); + + InstEmitNeonMove.VmovI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), 0, (encoding >> 8) & 0xf, ImmUtils.CombineImmU8(inst.Imm4, inst.Imm3, inst.I), inst.Q); + } + + public static void VmovIA4(CodeGenContext context, uint encoding) + { + InstIb24w1Db22w1Imm3b16w3Vdb12w4Qb6w1Imm4b0w4 inst = new(encoding); + + InstEmitNeonMove.VmovI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), 0, (encoding >> 8) & 0xf, ImmUtils.CombineImmU8(inst.Imm4, inst.Imm3, inst.I), inst.Q); + } + + public static void VmovIA5(CodeGenContext context, uint encoding) + { + InstIb24w1Db22w1Imm3b16w3Vdb12w4Qb6w1Imm4b0w4 inst = new(encoding); + + InstEmitNeonMove.VmovI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), 1, (encoding >> 8) & 0xf, ImmUtils.CombineImmU8(inst.Imm4, inst.Imm3, inst.I), inst.Q); + } + + public static void VmovIT1(CodeGenContext context, uint encoding) + { + InstIb28w1Db22w1Imm3b16w3Vdb12w4Qb6w1Imm4b0w4 inst = new(encoding); + + InstEmitNeonMove.VmovI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), 0, (encoding >> 8) & 0xf, ImmUtils.CombineImmU8(inst.Imm4, inst.Imm3, inst.I), inst.Q); + } + + public static void VmovIT2(CodeGenContext context, uint encoding) + { + InstDb22w1Imm4hb16w4Vdb12w4Sizeb8w2Imm4lb0w4 inst = new(encoding); + + InstEmitNeonMove.VmovFI(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), ImmUtils.CombineImmU8(inst.Imm4l, inst.Imm4h), inst.Size); + } + + public static void VmovIT3(CodeGenContext context, uint encoding) + { + InstIb28w1Db22w1Imm3b16w3Vdb12w4Qb6w1Imm4b0w4 inst = new(encoding); + + InstEmitNeonMove.VmovI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), 0, (encoding >> 8) & 0xf, ImmUtils.CombineImmU8(inst.Imm4, inst.Imm3, inst.I), inst.Q); + } + + public static void VmovIT4(CodeGenContext context, uint encoding) + { + InstIb28w1Db22w1Imm3b16w3Vdb12w4Qb6w1Imm4b0w4 inst = new(encoding); + + InstEmitNeonMove.VmovI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), 0, (encoding >> 8) & 0xf, ImmUtils.CombineImmU8(inst.Imm4, inst.Imm3, inst.I), inst.Q); + } + + public static void VmovIT5(CodeGenContext context, uint encoding) + { + InstIb28w1Db22w1Imm3b16w3Vdb12w4Qb6w1Imm4b0w4 inst = new(encoding); + + InstEmitNeonMove.VmovI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), 1, (encoding >> 8) & 0xf, ImmUtils.CombineImmU8(inst.Imm4, inst.Imm3, inst.I), inst.Q); + } + + public static void VmovRA2(CodeGenContext context, uint encoding) + { + InstCondb28w4Db22w1Vdb12w4Mb5w1Vmb0w4 inst = new(encoding); + + uint size = (encoding >> 8) & 3; + + InstEmitNeonMove.VmovR(context, InstEmitCommon.CombineV(inst.Vd, inst.D, size), InstEmitCommon.CombineV(inst.Vm, inst.M, size), size); + } + + public static void VmovRT2(CodeGenContext context, uint encoding) + { + InstDb22w1Vdb12w4Mb5w1Vmb0w4 inst = new(encoding); + + uint size = (encoding >> 8) & 3; + + InstEmitNeonMove.VmovR(context, InstEmitCommon.CombineV(inst.Vd, inst.D, size), InstEmitCommon.CombineV(inst.Vm, inst.M, size), size); + } + + public static void VmovRsA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Opc1b21w2Vdb16w4Rtb12w4Db7w1Opc2b5w2 inst = new(encoding); + + InstEmitNeonMove.VmovRs(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rt, inst.Opc1, inst.Opc2); + } + + public static void VmovRsT1(CodeGenContext context, uint encoding) + { + InstOpc1b21w2Vdb16w4Rtb12w4Db7w1Opc2b5w2 inst = new(encoding); + + InstEmitNeonMove.VmovRs(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rt, inst.Opc1, inst.Opc2); + } + + public static void VmovSA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Opb20w1Vnb16w4Rtb12w4Nb7w1 inst = new(encoding); + + InstEmitNeonMove.VmovS(context, inst.Rt, InstEmitCommon.CombineVF(inst.N, inst.Vn), inst.Op != 0); + } + + public static void VmovST1(CodeGenContext context, uint encoding) + { + InstOpb20w1Vnb16w4Rtb12w4Nb7w1 inst = new(encoding); + + InstEmitNeonMove.VmovS(context, inst.Rt, InstEmitCommon.CombineVF(inst.N, inst.Vn), inst.Op != 0); + } + + public static void VmovSrA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Ub23w1Opc1b21w2Vnb16w4Rtb12w4Nb7w1Opc2b5w2 inst = new(encoding); + + InstEmitNeonMove.VmovSr(context, inst.Rt, InstEmitCommon.CombineV(inst.Vn, inst.N), inst.U != 0, inst.Opc1, inst.Opc2); + } + + public static void VmovSrT1(CodeGenContext context, uint encoding) + { + InstUb23w1Opc1b21w2Vnb16w4Rtb12w4Nb7w1Opc2b5w2 inst = new(encoding); + + InstEmitNeonMove.VmovSr(context, inst.Rt, InstEmitCommon.CombineV(inst.Vn, inst.N), inst.U != 0, inst.Opc1, inst.Opc2); + } + + public static void VmovSsA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Opb20w1Rt2b16w4Rtb12w4Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonMove.VmovSs(context, inst.Rt, inst.Rt2, InstEmitCommon.CombineVF(inst.M, inst.Vm), inst.Op != 0); + } + + public static void VmovSsT1(CodeGenContext context, uint encoding) + { + InstOpb20w1Rt2b16w4Rtb12w4Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonMove.VmovSs(context, inst.Rt, inst.Rt2, InstEmitCommon.CombineVF(inst.M, inst.Vm), inst.Op != 0); + } + + public static void VmrsA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Regb16w4Rtb12w4 inst = new(encoding); + + InstEmitNeonSystem.Vmrs(context, inst.Rt, inst.Reg); + } + + public static void VmrsT1(CodeGenContext context, uint encoding) + { + InstRegb16w4Rtb12w4 inst = new(encoding); + + InstEmitNeonSystem.Vmrs(context, inst.Rt, inst.Reg); + } + + public static void VmsrA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Regb16w4Rtb12w4 inst = new(encoding); + + InstEmitNeonSystem.Vmsr(context, inst.Rt, inst.Reg); + } + + public static void VmsrT1(CodeGenContext context, uint encoding) + { + InstRegb16w4Rtb12w4 inst = new(encoding); + + InstEmitNeonSystem.Vmsr(context, inst.Rt, inst.Reg); + } + + public static void VmullIA1(CodeGenContext context, uint encoding) + { + InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Opb9w1Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VmullI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op != 0, inst.U != 0, inst.Size); + } + + public static void VmullIT1(CodeGenContext context, uint encoding) + { + InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Opb9w1Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VmullI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op != 0, inst.U != 0, inst.Size); + } + + public static void VmullSA1(CodeGenContext context, uint encoding) + { + InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VmullS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size); + } + + public static void VmullST1(CodeGenContext context, uint encoding) + { + InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VmullS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size); + } + + public static void VmulFA1(CodeGenContext context, uint encoding) + { + InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VmulF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q); + } + + public static void VmulFA2(CodeGenContext context, uint encoding) + { + InstCondb28w4Db22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpArithmetic.VmulF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VmulFT1(CodeGenContext context, uint encoding) + { + InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VmulF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q); + } + + public static void VmulFT2(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpArithmetic.VmulF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VmulIA1(CodeGenContext context, uint encoding) + { + InstOpb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VmulI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op != 0, inst.Size, inst.Q); + } + + public static void VmulIT1(CodeGenContext context, uint encoding) + { + InstOpb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VmulI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op != 0, inst.Size, inst.Q); + } + + public static void VmulSA1(CodeGenContext context, uint encoding) + { + InstQb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Fb8w1Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VmulS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.F != 0, inst.Size, inst.Q); + } + + public static void VmulST1(CodeGenContext context, uint encoding) + { + InstQb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Fb8w1Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VmulS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.F != 0, inst.Size, inst.Q); + } + + public static void VmvnIA1(CodeGenContext context, uint encoding) + { + InstIb24w1Db22w1Imm3b16w3Vdb12w4Qb6w1Imm4b0w4 inst = new(encoding); + + InstEmitNeonMove.VmvnI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), (encoding >> 8) & 0xf, ImmUtils.CombineImmU8(inst.Imm4, inst.Imm3, inst.I), inst.Q); + } + + public static void VmvnIA2(CodeGenContext context, uint encoding) + { + InstIb24w1Db22w1Imm3b16w3Vdb12w4Qb6w1Imm4b0w4 inst = new(encoding); + + InstEmitNeonMove.VmvnI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), (encoding >> 8) & 0xf, ImmUtils.CombineImmU8(inst.Imm4, inst.Imm3, inst.I), inst.Q); + } + + public static void VmvnIA3(CodeGenContext context, uint encoding) + { + InstIb24w1Db22w1Imm3b16w3Vdb12w4Qb6w1Imm4b0w4 inst = new(encoding); + + InstEmitNeonMove.VmvnI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), (encoding >> 8) & 0xf, ImmUtils.CombineImmU8(inst.Imm4, inst.Imm3, inst.I), inst.Q); + } + + public static void VmvnIT1(CodeGenContext context, uint encoding) + { + InstIb28w1Db22w1Imm3b16w3Vdb12w4Qb6w1Imm4b0w4 inst = new(encoding); + + InstEmitNeonMove.VmvnI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), (encoding >> 8) & 0xf, ImmUtils.CombineImmU8(inst.Imm4, inst.Imm3, inst.I), inst.Q); + } + + public static void VmvnIT2(CodeGenContext context, uint encoding) + { + InstIb28w1Db22w1Imm3b16w3Vdb12w4Qb6w1Imm4b0w4 inst = new(encoding); + + InstEmitNeonMove.VmvnI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), (encoding >> 8) & 0xf, ImmUtils.CombineImmU8(inst.Imm4, inst.Imm3, inst.I), inst.Q); + } + + public static void VmvnIT3(CodeGenContext context, uint encoding) + { + InstIb28w1Db22w1Imm3b16w3Vdb12w4Qb6w1Imm4b0w4 inst = new(encoding); + + InstEmitNeonMove.VmvnI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), (encoding >> 8) & 0xf, ImmUtils.CombineImmU8(inst.Imm4, inst.Imm3, inst.I), inst.Q); + } + + public static void VmvnRA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonMove.VmvnR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VmvnRT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonMove.VmvnR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VnegA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Fb10w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.Vneg(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.F != 0, inst.Size, inst.Q); + } + + public static void VnegA2(CodeGenContext context, uint encoding) + { + InstCondb28w4Db22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpArithmetic.VnegF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VnegT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Fb10w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.Vneg(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.F != 0, inst.Size, inst.Q); + } + + public static void VnegT2(CodeGenContext context, uint encoding) + { + InstDb22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpArithmetic.VnegF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VnmlaA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Db22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpArithmetic.VnmlaF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VnmlaT1(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpArithmetic.VnmlaF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VnmlsA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Db22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpArithmetic.VnmlsF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VnmlsT1(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpArithmetic.VnmlsF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VnmulA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Db22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpArithmetic.VnmulF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VnmulT1(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpArithmetic.VnmulF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VornRA1(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonLogical.VornR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q); + } + + public static void VornRT1(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonLogical.VornR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q); + } + + public static void VorrIA1(CodeGenContext context, uint encoding) + { + InstIb24w1Db22w1Imm3b16w3Vdb12w4Qb6w1Imm4b0w4 inst = new(encoding); + + InstEmitNeonLogical.VorrI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), (encoding >> 8) & 0xf, ImmUtils.CombineImmU8(inst.Imm4, inst.Imm3, inst.I), inst.Q); + } + + public static void VorrIA2(CodeGenContext context, uint encoding) + { + InstIb24w1Db22w1Imm3b16w3Vdb12w4Qb6w1Imm4b0w4 inst = new(encoding); + + InstEmitNeonLogical.VorrI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), (encoding >> 8) & 0xf, ImmUtils.CombineImmU8(inst.Imm4, inst.Imm3, inst.I), inst.Q); + } + + public static void VorrIT1(CodeGenContext context, uint encoding) + { + InstIb28w1Db22w1Imm3b16w3Vdb12w4Qb6w1Imm4b0w4 inst = new(encoding); + + InstEmitNeonLogical.VorrI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), (encoding >> 8) & 0xf, ImmUtils.CombineImmU8(inst.Imm4, inst.Imm3, inst.I), inst.Q); + } + + public static void VorrIT2(CodeGenContext context, uint encoding) + { + InstIb28w1Db22w1Imm3b16w3Vdb12w4Qb6w1Imm4b0w4 inst = new(encoding); + + InstEmitNeonLogical.VorrI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), (encoding >> 8) & 0xf, ImmUtils.CombineImmU8(inst.Imm4, inst.Imm3, inst.I), inst.Q); + } + + public static void VorrRA1(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonLogical.VorrR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q); + } + + public static void VorrRT1(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonLogical.VorrR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q); + } + + public static void VpadalA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Opb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.Vpadal(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op != 0, inst.Size, inst.Q); + } + + public static void VpadalT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Opb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.Vpadal(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op != 0, inst.Size, inst.Q); + } + + public static void VpaddlA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Opb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.Vpaddl(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op != 0, inst.Size, inst.Q); + } + + public static void VpaddlT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Opb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.Vpaddl(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op != 0, inst.Size, inst.Q); + } + + public static void VpaddFA1(CodeGenContext context, uint encoding) + { + InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VpaddF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q); + } + + public static void VpaddFT1(CodeGenContext context, uint encoding) + { + InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VpaddF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q); + } + + public static void VpaddIA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VpaddI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VpaddIT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VpaddI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VpmaxFA1(CodeGenContext context, uint encoding) + { + InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VpmaxF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, 0); + } + + public static void VpmaxFT1(CodeGenContext context, uint encoding) + { + InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VpmaxF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, 0); + } + + public static void VpmaxIA1(CodeGenContext context, uint encoding) + { + InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VpmaxI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, 0); + } + + public static void VpmaxIT1(CodeGenContext context, uint encoding) + { + InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VpmaxI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, 0); + } + + public static void VpminFA1(CodeGenContext context, uint encoding) + { + InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VpminF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, 0); + } + + public static void VpminFT1(CodeGenContext context, uint encoding) + { + InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VpminF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, 0); + } + + public static void VpminIA1(CodeGenContext context, uint encoding) + { + InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VpminI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, 0); + } + + public static void VpminIT1(CodeGenContext context, uint encoding) + { + InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VpminI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, 0); + } + + public static void VqabsA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonSaturate.Vqabs(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VqabsT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonSaturate.Vqabs(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VqaddA1(CodeGenContext context, uint encoding) + { + InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonSaturate.Vqadd(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q); + } + + public static void VqaddT1(CodeGenContext context, uint encoding) + { + InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonSaturate.Vqadd(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q); + } + + public static void VqdmlalA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonSaturate.Vqdmlal(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size); + } + + public static void VqdmlalA2(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonSaturate.VqdmlalS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size); + } + + public static void VqdmlalT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonSaturate.Vqdmlal(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size); + } + + public static void VqdmlalT2(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonSaturate.VqdmlalS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size); + } + + public static void VqdmlslA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonSaturate.Vqdmlsl(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size); + } + + public static void VqdmlslA2(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonSaturate.VqdmlslS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size); + } + + public static void VqdmlslT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonSaturate.Vqdmlsl(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size); + } + + public static void VqdmlslT2(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonSaturate.VqdmlslS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size); + } + + public static void VqdmulhA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonSaturate.Vqdmulh(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VqdmulhA2(CodeGenContext context, uint encoding) + { + InstQb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonSaturate.VqdmulhS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VqdmulhT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonSaturate.Vqdmulh(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VqdmulhT2(CodeGenContext context, uint encoding) + { + InstQb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonSaturate.VqdmulhS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VqdmullA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonSaturate.Vqdmull(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size); + } + + public static void VqdmullA2(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonSaturate.VqdmullS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size); + } + + public static void VqdmullT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonSaturate.Vqdmull(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size); + } + + public static void VqdmullT2(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonSaturate.VqdmullS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size); + } + + public static void VqmovnA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Opb6w2Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonSaturate.Vqmovn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op, inst.Size); + } + + public static void VqmovnT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Opb6w2Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonSaturate.Vqmovn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op, inst.Size); + } + + public static void VqnegA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonSaturate.Vqneg(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VqnegT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonSaturate.Vqneg(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VqrdmlahA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonSaturate.Vqrdmlah(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VqrdmlahA2(CodeGenContext context, uint encoding) + { + InstQb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonSaturate.VqrdmlahS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VqrdmlahT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonSaturate.Vqrdmlah(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VqrdmlahT2(CodeGenContext context, uint encoding) + { + InstQb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonSaturate.VqrdmlahS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VqrdmlshA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonSaturate.Vqrdmlsh(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VqrdmlshA2(CodeGenContext context, uint encoding) + { + InstQb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonSaturate.VqrdmlshS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VqrdmlshT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonSaturate.Vqrdmlsh(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VqrdmlshT2(CodeGenContext context, uint encoding) + { + InstQb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonSaturate.VqrdmlshS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VqrdmulhA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonSaturate.Vqrdmulh(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VqrdmulhA2(CodeGenContext context, uint encoding) + { + InstQb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonSaturate.VqrdmulhS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VqrdmulhT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonSaturate.Vqrdmulh(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VqrdmulhT2(CodeGenContext context, uint encoding) + { + InstQb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonSaturate.VqrdmulhS(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VqrshlA1(CodeGenContext context, uint encoding) + { + InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonSaturate.Vqrshl(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VqrshlT1(CodeGenContext context, uint encoding) + { + InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonSaturate.Vqrshl(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VqrshrnA1(CodeGenContext context, uint encoding) + { + InstUb24w1Db22w1Imm6b16w6Vdb12w4Opb8w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonSaturate.Vqrshrn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Op, inst.Imm6); + } + + public static void VqrshrnT1(CodeGenContext context, uint encoding) + { + InstUb28w1Db22w1Imm6b16w6Vdb12w4Opb8w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonSaturate.Vqrshrn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Op, inst.Imm6); + } + + public static void VqshlIA1(CodeGenContext context, uint encoding) + { + InstUb24w1Db22w1Imm6b16w6Vdb12w4Opb8w1Lb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonSaturate.VqshlI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Op, inst.L, inst.Imm6, inst.Q); + } + + public static void VqshlIT1(CodeGenContext context, uint encoding) + { + InstUb28w1Db22w1Imm6b16w6Vdb12w4Opb8w1Lb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonSaturate.VqshlI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Op, inst.L, inst.Imm6, inst.Q); + } + + public static void VqshlRA1(CodeGenContext context, uint encoding) + { + InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonSaturate.VqshlR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q); + } + + public static void VqshlRT1(CodeGenContext context, uint encoding) + { + InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonSaturate.VqshlR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q); + } + + public static void VqshrnA1(CodeGenContext context, uint encoding) + { + InstUb24w1Db22w1Imm6b16w6Vdb12w4Opb8w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonSaturate.Vqshrn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Op, inst.Imm6); + } + + public static void VqshrnT1(CodeGenContext context, uint encoding) + { + InstUb28w1Db22w1Imm6b16w6Vdb12w4Opb8w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonSaturate.Vqshrn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Op, inst.Imm6); + } + + public static void VqsubA1(CodeGenContext context, uint encoding) + { + InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonSaturate.Vqsub(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q); + } + + public static void VqsubT1(CodeGenContext context, uint encoding) + { + InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonSaturate.Vqsub(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q); + } + + public static void VraddhnA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonRound.Vraddhn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size); + } + + public static void VraddhnT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonRound.Vraddhn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size); + } + + public static void VrecpeA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Fb8w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.Vrecpe(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.F != 0, inst.Size, inst.Q); + } + + public static void VrecpeT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Fb8w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.Vrecpe(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.F != 0, inst.Size, inst.Q); + } + + public static void VrecpsA1(CodeGenContext context, uint encoding) + { + InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.Vrecps(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q); + } + + public static void VrecpsT1(CodeGenContext context, uint encoding) + { + InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.Vrecps(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q); + } + + public static void Vrev16A1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonBit.Vrev16(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void Vrev16T1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonBit.Vrev16(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void Vrev32A1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonBit.Vrev32(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void Vrev32T1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonBit.Vrev32(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void Vrev64A1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonBit.Vrev64(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void Vrev64T1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonBit.Vrev64(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VrhaddA1(CodeGenContext context, uint encoding) + { + InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonRound.Vrhadd(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q); + } + + public static void VrhaddT1(CodeGenContext context, uint encoding) + { + InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonRound.Vrhadd(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q); + } + + public static void VrintaAsimdA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonRound.Vrinta(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VrintaAsimdT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonRound.Vrinta(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VrintaVfpA1(CodeGenContext context, uint encoding) + { + InstDb22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpRound.Vrinta(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VrintaVfpT1(CodeGenContext context, uint encoding) + { + InstDb22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpRound.Vrinta(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VrintmAsimdA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonRound.Vrintm(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VrintmAsimdT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonRound.Vrintm(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VrintmVfpA1(CodeGenContext context, uint encoding) + { + InstDb22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpRound.Vrintm(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VrintmVfpT1(CodeGenContext context, uint encoding) + { + InstDb22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpRound.Vrintm(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VrintnAsimdA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonRound.Vrintn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VrintnAsimdT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonRound.Vrintn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VrintnVfpA1(CodeGenContext context, uint encoding) + { + InstDb22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpRound.Vrintn(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VrintnVfpT1(CodeGenContext context, uint encoding) + { + InstDb22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpRound.Vrintn(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VrintpAsimdA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonRound.Vrintp(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VrintpAsimdT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonRound.Vrintp(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VrintpVfpA1(CodeGenContext context, uint encoding) + { + InstDb22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpRound.Vrintp(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VrintpVfpT1(CodeGenContext context, uint encoding) + { + InstDb22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpRound.Vrintp(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VrintrVfpA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Db22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpRound.Vrintr(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VrintrVfpT1(CodeGenContext context, uint encoding) + { + InstDb22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpRound.Vrintr(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VrintxAsimdA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonRound.Vrintx(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VrintxAsimdT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonRound.Vrintx(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VrintxVfpA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Db22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpRound.Vrintx(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VrintxVfpT1(CodeGenContext context, uint encoding) + { + InstDb22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpRound.Vrintx(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VrintzAsimdA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonRound.Vrintz(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VrintzAsimdT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonRound.Vrintz(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VrintzVfpA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Db22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpRound.Vrintz(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VrintzVfpT1(CodeGenContext context, uint encoding) + { + InstDb22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpRound.Vrintz(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VrshlA1(CodeGenContext context, uint encoding) + { + InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonRound.Vrshl(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q); + } + + public static void VrshlT1(CodeGenContext context, uint encoding) + { + InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonRound.Vrshl(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q); + } + + public static void VrshrA1(CodeGenContext context, uint encoding) + { + InstUb24w1Db22w1Imm6b16w6Vdb12w4Lb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonRound.Vrshr(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.L, inst.Imm6, inst.Q); + } + + public static void VrshrT1(CodeGenContext context, uint encoding) + { + InstUb28w1Db22w1Imm6b16w6Vdb12w4Lb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonRound.Vrshr(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.L, inst.Imm6, inst.Q); + } + + public static void VrshrnA1(CodeGenContext context, uint encoding) + { + InstDb22w1Imm6b16w6Vdb12w4Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonRound.Vrshrn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Imm6); + } + + public static void VrshrnT1(CodeGenContext context, uint encoding) + { + InstDb22w1Imm6b16w6Vdb12w4Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonRound.Vrshrn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Imm6); + } + + public static void VrsqrteA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Fb8w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.Vrsqrte(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.F != 0, inst.Size, inst.Q); + } + + public static void VrsqrteT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Fb8w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.Vrsqrte(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.F != 0, inst.Size, inst.Q); + } + + public static void VrsqrtsA1(CodeGenContext context, uint encoding) + { + InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.Vrsqrts(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q); + } + + public static void VrsqrtsT1(CodeGenContext context, uint encoding) + { + InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.Vrsqrts(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q); + } + + public static void VrsraA1(CodeGenContext context, uint encoding) + { + InstUb24w1Db22w1Imm6b16w6Vdb12w4Lb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonRound.Vrsra(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.L, inst.Imm6, inst.Q); + } + + public static void VrsraT1(CodeGenContext context, uint encoding) + { + InstUb28w1Db22w1Imm6b16w6Vdb12w4Lb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonRound.Vrsra(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.L, inst.Imm6, inst.Q); + } + + public static void VrsubhnA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonRound.Vrsubhn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size); + } + + public static void VrsubhnT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonRound.Vrsubhn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size); + } + + public static void VsdotA1(CodeGenContext context, uint encoding) + { + _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VsdotT1(CodeGenContext context, uint encoding) + { + _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VsdotSA1(CodeGenContext context, uint encoding) + { + _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VsdotST1(CodeGenContext context, uint encoding) + { + _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VselA1(CodeGenContext context, uint encoding) + { + InstDb22w1Ccb20w2Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpMove.Vsel(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Cc, inst.Size); + } + + public static void VselT1(CodeGenContext context, uint encoding) + { + InstDb22w1Ccb20w2Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpMove.Vsel(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Cc, inst.Size); + } + + public static void VshllA1(CodeGenContext context, uint encoding) + { + InstUb24w1Db22w1Imm6b16w6Vdb12w4Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonShift.Vshll(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Imm6, inst.U != 0); + } + + public static void VshllA2(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonShift.Vshll2(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size); + } + + public static void VshllT1(CodeGenContext context, uint encoding) + { + InstUb28w1Db22w1Imm6b16w6Vdb12w4Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonShift.Vshll(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Imm6, inst.U != 0); + } + + public static void VshllT2(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonShift.Vshll2(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size); + } + + public static void VshlIA1(CodeGenContext context, uint encoding) + { + InstDb22w1Imm6b16w6Vdb12w4Lb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonShift.VshlI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.L, inst.Imm6, inst.Q); + } + + public static void VshlIT1(CodeGenContext context, uint encoding) + { + InstDb22w1Imm6b16w6Vdb12w4Lb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonShift.VshlI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.L, inst.Imm6, inst.Q); + } + + public static void VshlRA1(CodeGenContext context, uint encoding) + { + InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonShift.VshlR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q); + } + + public static void VshlRT1(CodeGenContext context, uint encoding) + { + InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonShift.VshlR(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size, inst.Q); + } + + public static void VshrA1(CodeGenContext context, uint encoding) + { + InstUb24w1Db22w1Imm6b16w6Vdb12w4Lb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonShift.Vshr(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.L, inst.Imm6, inst.Q); + } + + public static void VshrT1(CodeGenContext context, uint encoding) + { + InstUb28w1Db22w1Imm6b16w6Vdb12w4Lb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonShift.Vshr(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.L, inst.Imm6, inst.Q); + } + + public static void VshrnA1(CodeGenContext context, uint encoding) + { + InstDb22w1Imm6b16w6Vdb12w4Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonShift.Vshrn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Imm6); + } + + public static void VshrnT1(CodeGenContext context, uint encoding) + { + InstDb22w1Imm6b16w6Vdb12w4Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonShift.Vshrn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Imm6); + } + + public static void VsliA1(CodeGenContext context, uint encoding) + { + InstDb22w1Imm6b16w6Vdb12w4Lb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonShift.Vsli(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.L, inst.Imm6, inst.Q); + } + + public static void VsliT1(CodeGenContext context, uint encoding) + { + InstDb22w1Imm6b16w6Vdb12w4Lb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonShift.Vsli(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.L, inst.Imm6, inst.Q); + } + + public static void VsmmlaA1(CodeGenContext context, uint encoding) + { + _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VsmmlaT1(CodeGenContext context, uint encoding) + { + _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VsqrtA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Db22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpArithmetic.VsqrtF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VsqrtT1(CodeGenContext context, uint encoding) + { + InstDb22w1Vdb12w4Sizeb8w2Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpArithmetic.VsqrtF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VsraA1(CodeGenContext context, uint encoding) + { + InstUb24w1Db22w1Imm6b16w6Vdb12w4Lb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonShift.Vsra(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.L, inst.Imm6, inst.Q); + } + + public static void VsraT1(CodeGenContext context, uint encoding) + { + InstUb28w1Db22w1Imm6b16w6Vdb12w4Lb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonShift.Vsra(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.L, inst.Imm6, inst.Q); + } + + public static void VsriA1(CodeGenContext context, uint encoding) + { + InstDb22w1Imm6b16w6Vdb12w4Lb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonShift.Vsri(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.L, inst.Imm6, inst.Q); + } + + public static void VsriT1(CodeGenContext context, uint encoding) + { + InstDb22w1Imm6b16w6Vdb12w4Lb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonShift.Vsri(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.L, inst.Imm6, inst.Q); + } + + public static void Vst11A1(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vst11(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 0); + } + + public static void Vst11A2(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vst11(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 1); + } + + public static void Vst11A3(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vst11(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 2); + } + + public static void Vst11T1(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vst11(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 0); + } + + public static void Vst11T2(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vst11(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 1); + } + + public static void Vst11T3(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vst11(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 2); + } + + public static void Vst1MA1(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vst1M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, 1, inst.Align, inst.Size); + } + + public static void Vst1MA2(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vst1M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, 2, inst.Align, inst.Size); + } + + public static void Vst1MA3(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vst1M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, 3, inst.Align, inst.Size); + } + + public static void Vst1MA4(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vst1M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, 4, inst.Align, inst.Size); + } + + public static void Vst1MT1(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vst1M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, 1, inst.Align, inst.Size); + } + + public static void Vst1MT2(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vst1M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, 2, inst.Align, inst.Size); + } + + public static void Vst1MT3(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vst1M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, 3, inst.Align, inst.Size); + } + + public static void Vst1MT4(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vst1M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, 4, inst.Align, inst.Size); + } + + public static void Vst21A1(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vst21(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 0); + } + + public static void Vst21A2(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vst21(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 1); + } + + public static void Vst21A3(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vst21(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 2); + } + + public static void Vst21T1(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vst21(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 0); + } + + public static void Vst21T2(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vst21(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 1); + } + + public static void Vst21T3(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vst21(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 2); + } + + public static void Vst2MA1(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vst2M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, (encoding >> 8) & 0xf, inst.Align, inst.Size); + } + + public static void Vst2MA2(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vst2M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.Align, inst.Size); + } + + public static void Vst2MT1(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vst2M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, (encoding >> 8) & 0xf, inst.Align, inst.Size); + } + + public static void Vst2MT2(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vst2M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.Align, inst.Size); + } + + public static void Vst31A1(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vst31(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 0); + } + + public static void Vst31A2(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vst31(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 1); + } + + public static void Vst31A3(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vst31(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 2); + } + + public static void Vst31T1(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vst31(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 0); + } + + public static void Vst31T2(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vst31(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 1); + } + + public static void Vst31T3(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vst31(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 2); + } + + public static void Vst3MA1(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vst3M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, (encoding >> 8) & 0xf, inst.Align, inst.Size); + } + + public static void Vst3MT1(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vst3M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, (encoding >> 8) & 0xf, inst.Align, inst.Size); + } + + public static void Vst41A1(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vst41(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 0); + } + + public static void Vst41A2(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vst41(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 1); + } + + public static void Vst41A3(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vst41(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 2); + } + + public static void Vst41T1(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vst41(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 0); + } + + public static void Vst41T2(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vst41(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 1); + } + + public static void Vst41T3(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4IndexAlignb4w4Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vst41(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, inst.IndexAlign, 2); + } + + public static void Vst4MA1(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vst4M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, (encoding >> 8) & 0xf, inst.Align, inst.Size); + } + + public static void Vst4MT1(CodeGenContext context, uint encoding) + { + InstDb22w1Rnb16w4Vdb12w4Sizeb6w2Alignb4w2Rmb0w4 inst = new(encoding); + + InstEmitNeonMemory.Vst4M(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Rm, (encoding >> 8) & 0xf, inst.Align, inst.Size); + } + + public static void VstmA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Pb24w1Ub23w1Db22w1Wb21w1Rnb16w4Vdb12w4Imm871b1w7 inst = new(encoding); + + InstEmitNeonMemory.Vstm(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Imm871, inst.U != 0, inst.W != 0, singleRegs: false); + } + + public static void VstmA2(CodeGenContext context, uint encoding) + { + InstCondb28w4Pb24w1Ub23w1Db22w1Wb21w1Rnb16w4Vdb12w4Imm8b0w8 inst = new(encoding); + + InstEmitNeonMemory.Vstm(context, InstEmitCommon.CombineVF(inst.D, inst.Vd), inst.Rn, inst.Imm8, inst.U != 0, inst.W != 0, singleRegs: true); + } + + public static void VstmT1(CodeGenContext context, uint encoding) + { + InstPb24w1Ub23w1Db22w1Wb21w1Rnb16w4Vdb12w4Imm871b1w7 inst = new(encoding); + + InstEmitNeonMemory.Vstm(context, InstEmitCommon.CombineV(inst.Vd, inst.D), inst.Rn, inst.Imm871, inst.U != 0, inst.W != 0, singleRegs: false); + } + + public static void VstmT2(CodeGenContext context, uint encoding) + { + InstPb24w1Ub23w1Db22w1Wb21w1Rnb16w4Vdb12w4Imm8b0w8 inst = new(encoding); + + InstEmitNeonMemory.Vstm(context, InstEmitCommon.CombineVF(inst.D, inst.Vd), inst.Rn, inst.Imm8, inst.U != 0, inst.W != 0, singleRegs: true); + } + + public static void VstrA1(CodeGenContext context, uint encoding) + { + InstCondb28w4Ub23w1Db22w1Rnb16w4Vdb12w4Sizeb8w2Imm8b0w8 inst = new(encoding); + + InstEmitNeonMemory.Vstr(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), inst.Rn, inst.Imm8, inst.U != 0, inst.Size); + } + + public static void VstrT1(CodeGenContext context, uint encoding) + { + InstUb23w1Db22w1Rnb16w4Vdb12w4Sizeb8w2Imm8b0w8 inst = new(encoding); + + InstEmitNeonMemory.Vstr(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), inst.Rn, inst.Imm8, inst.U != 0, inst.Size); + } + + public static void VsubhnA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.Vsubhn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size); + } + + public static void VsubhnT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.Vsubhn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size); + } + + public static void VsublA1(CodeGenContext context, uint encoding) + { + InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.Vsubl(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size); + } + + public static void VsublT1(CodeGenContext context, uint encoding) + { + InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.Vsubl(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size); + } + + public static void VsubwA1(CodeGenContext context, uint encoding) + { + InstUb24w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.Vsubw(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size); + } + + public static void VsubwT1(CodeGenContext context, uint encoding) + { + InstUb28w1Db22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.Vsubw(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.U != 0, inst.Size); + } + + public static void VsubFA1(CodeGenContext context, uint encoding) + { + InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VsubF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q); + } + + public static void VsubFA2(CodeGenContext context, uint encoding) + { + InstCondb28w4Db22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpArithmetic.VsubF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VsubFT1(CodeGenContext context, uint encoding) + { + InstDb22w1Szb20w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VsubF(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Sz, inst.Q); + } + + public static void VsubFT2(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Sizeb8w2Nb7w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitVfpArithmetic.VsubF(context, InstEmitCommon.CombineV(inst.Vd, inst.D, inst.Size), InstEmitCommon.CombineV(inst.Vn, inst.N, inst.Size), InstEmitCommon.CombineV(inst.Vm, inst.M, inst.Size), inst.Size); + } + + public static void VsubIA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VsubI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VsubIT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonArithmetic.VsubI(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VsudotSA1(CodeGenContext context, uint encoding) + { + _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VsudotST1(CodeGenContext context, uint encoding) + { + _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VswpA1(CodeGenContext context, uint encoding) + { + InstDb22w1Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonMove.Vswp(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q); + } + + public static void VswpT1(CodeGenContext context, uint encoding) + { + InstDb22w1Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonMove.Vswp(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Q); + } + + public static void VtblA1(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Lenb8w2Nb7w1Opb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonMove.Vtbl(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op != 0, inst.Len); + } + + public static void VtblT1(CodeGenContext context, uint encoding) + { + InstDb22w1Vnb16w4Vdb12w4Lenb8w2Nb7w1Opb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonMove.Vtbl(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Op != 0, inst.Len); + } + + public static void VtrnA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonMove.Vtrn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VtrnT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonMove.Vtrn(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VtstA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonCompare.Vtst(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VtstT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb20w2Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonCompare.Vtst(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vn, inst.N), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VudotA1(CodeGenContext context, uint encoding) + { + _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VudotT1(CodeGenContext context, uint encoding) + { + _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VudotSA1(CodeGenContext context, uint encoding) + { + _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VudotST1(CodeGenContext context, uint encoding) + { + _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VummlaA1(CodeGenContext context, uint encoding) + { + _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VummlaT1(CodeGenContext context, uint encoding) + { + _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VusdotA1(CodeGenContext context, uint encoding) + { + _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VusdotT1(CodeGenContext context, uint encoding) + { + _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VusdotSA1(CodeGenContext context, uint encoding) + { + _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VusdotST1(CodeGenContext context, uint encoding) + { + _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Qb6w1Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VusmmlaA1(CodeGenContext context, uint encoding) + { + _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VusmmlaT1(CodeGenContext context, uint encoding) + { + _ = new InstDb22w1Vnb16w4Vdb12w4Nb7w1Mb5w1Vmb0w4(encoding); + + throw new NotImplementedException(); + } + + public static void VuzpA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonMove.Vuzp(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VuzpT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonMove.Vuzp(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VzipA1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonMove.Vzip(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void VzipT1(CodeGenContext context, uint encoding) + { + InstDb22w1Sizeb18w2Vdb12w4Qb6w1Mb5w1Vmb0w4 inst = new(encoding); + + InstEmitNeonMove.Vzip(context, InstEmitCommon.CombineV(inst.Vd, inst.D), InstEmitCommon.CombineV(inst.Vm, inst.M), inst.Size, inst.Q); + } + + public static void WfeA1(CodeGenContext context, uint encoding) + { + context.Arm64Assembler.Wfe(); + } + + public static void WfeT1(CodeGenContext context, uint encoding) + { + context.Arm64Assembler.Wfe(); + } + + public static void WfeT2(CodeGenContext context, uint encoding) + { + context.Arm64Assembler.Wfe(); + } + + public static void WfiA1(CodeGenContext context, uint encoding) + { + context.Arm64Assembler.Wfi(); + } + + public static void WfiT1(CodeGenContext context, uint encoding) + { + context.Arm64Assembler.Wfi(); + } + + public static void WfiT2(CodeGenContext context, uint encoding) + { + context.Arm64Assembler.Wfi(); + } + + public static void YieldA1(CodeGenContext context, uint encoding) + { + context.Arm64Assembler.Yield(); + } + + public static void YieldT1(CodeGenContext context, uint encoding) + { + context.Arm64Assembler.Yield(); + } + + public static void YieldT2(CodeGenContext context, uint encoding) + { + context.Arm64Assembler.Yield(); + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitAbsDiff.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitAbsDiff.cs new file mode 100644 index 000000000..f8100503d --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitAbsDiff.cs @@ -0,0 +1,87 @@ +using Ryujinx.Cpu.LightningJit.CodeGen; +using Ryujinx.Cpu.LightningJit.CodeGen.Arm64; + +namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 +{ + static class InstEmitAbsDiff + { + public static void Usad8(CodeGenContext context, uint rd, uint rn, uint rm) + { + using ScopedRegister tempD = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister tempD2 = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister tempN = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister tempM = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + + for (int b = 0; b < 4; b++) + { + context.Arm64Assembler.Ubfx(tempN.Operand, rnOperand, b * 8, 8); + context.Arm64Assembler.Ubfx(tempM.Operand, rmOperand, b * 8, 8); + + Operand dest = b == 0 ? tempD.Operand : tempD2.Operand; + + context.Arm64Assembler.Sub(dest, tempN.Operand, tempM.Operand); + + EmitAbs(context, dest); + + if (b > 0) + { + if (b < 3) + { + context.Arm64Assembler.Add(tempD.Operand, tempD.Operand, dest); + } + else + { + context.Arm64Assembler.Add(rdOperand, tempD.Operand, dest); + } + } + } + } + + public static void Usada8(CodeGenContext context, uint rd, uint rn, uint rm, uint ra) + { + using ScopedRegister tempD = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister tempD2 = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister tempN = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister tempM = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + Operand raOperand = InstEmitCommon.GetInputGpr(context, ra); + + for (int b = 0; b < 4; b++) + { + context.Arm64Assembler.Ubfx(tempN.Operand, rnOperand, b * 8, 8); + context.Arm64Assembler.Ubfx(tempM.Operand, rmOperand, b * 8, 8); + + Operand dest = b == 0 ? tempD.Operand : tempD2.Operand; + + context.Arm64Assembler.Sub(dest, tempN.Operand, tempM.Operand); + + EmitAbs(context, dest); + + if (b > 0) + { + context.Arm64Assembler.Add(tempD.Operand, tempD.Operand, dest); + } + } + + context.Arm64Assembler.Add(rdOperand, tempD.Operand, raOperand); + } + + private static void EmitAbs(CodeGenContext context, Operand value) + { + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + // r = (value + ((int)value >> 31)) ^ ((int)value >> 31). + // Subtracts 1 and then inverts the value if the sign bit is set, same as a conditional negation. + + context.Arm64Assembler.Add(tempRegister.Operand, value, value, ArmShiftType.Asr, 31); + context.Arm64Assembler.Eor(value, tempRegister.Operand, value, ArmShiftType.Asr, 31); + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitAlu.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitAlu.cs new file mode 100644 index 000000000..c0762819e --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitAlu.cs @@ -0,0 +1,1105 @@ +using Ryujinx.Cpu.LightningJit.CodeGen; +using Ryujinx.Cpu.LightningJit.CodeGen.Arm64; +using System; +using System.Diagnostics; + +namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 +{ + static class InstEmitAlu + { + private const uint Imm12Limit = 0x1000; + + public static void AdcI(CodeGenContext context, uint rd, uint rn, uint imm, bool s) + { + EmitI(context, s ? context.Arm64Assembler.Adcs : context.Arm64Assembler.Adc, rd, rn, imm, s); + } + + public static void AdcR(CodeGenContext context, uint rd, uint rn, uint rm, uint sType, uint imm5, bool s) + { + EmitR(context, s ? context.Arm64Assembler.Adcs : context.Arm64Assembler.Adc, rd, rn, rm, sType, imm5, s); + } + + public static void AdcRr(CodeGenContext context, uint rd, uint rn, uint rm, uint sType, uint rs, bool s) + { + EmitRr(context, s ? context.Arm64Assembler.Adcs : context.Arm64Assembler.Adc, rd, rn, rm, sType, rs, s); + } + + public static void AddI(CodeGenContext context, uint rd, uint rn, uint imm, bool s) + { + EmitArithmeticI(context, s ? context.Arm64Assembler.Adds : context.Arm64Assembler.Add, rd, rn, imm, s); + } + + public static void AddR(CodeGenContext context, uint rd, uint rn, uint rm, uint sType, uint imm5, bool s) + { + EmitArithmeticR(context, s ? context.Arm64Assembler.Adds : context.Arm64Assembler.Add, rd, rn, rm, sType, imm5, s); + } + + public static void AddRr(CodeGenContext context, uint rd, uint rn, uint rm, uint sType, uint rs, bool s) + { + EmitRr(context, s ? context.Arm64Assembler.Adds : context.Arm64Assembler.Add, rd, rn, rm, sType, rs, s); + } + + public static void Adr(CodeGenContext context, uint rd, uint imm, bool add) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + + uint pc = context.Pc & ~3u; + + if (add) + { + pc += imm; + } + else + { + pc -= imm; + } + + context.Arm64Assembler.Mov(rdOperand, pc); + } + + public static void AndI(CodeGenContext context, uint rd, uint rn, uint imm, bool immRotated, bool s) + { + EmitLogicalI(context, s ? context.Arm64Assembler.Ands : context.Arm64Assembler.And, rd, rn, imm, immRotated, s); + } + + public static void AndR(CodeGenContext context, uint rd, uint rn, uint rm, uint sType, uint imm5, bool s) + { + EmitLogicalR(context, s ? context.Arm64Assembler.Ands : context.Arm64Assembler.And, rd, rn, rm, sType, imm5, s); + } + + public static void AndRr(CodeGenContext context, uint rd, uint rn, uint rm, uint sType, uint rs, bool s) + { + EmitLogicalRr(context, s ? context.Arm64Assembler.Ands : context.Arm64Assembler.And, rd, rn, rm, sType, rs, s); + } + + public static void BicI(CodeGenContext context, uint rd, uint rn, uint imm, bool immRotated, bool s) + { + if (!s && CodeGenCommon.TryEncodeBitMask(OperandType.I32, ~imm, out _, out _, out _)) + { + AndI(context, rd, rn, ~imm, immRotated, s); + } + else + { + EmitLogicalI(context, s ? context.Arm64Assembler.Bics : context.Arm64Assembler.Bic, rd, rn, imm, immRotated, s, immForm: false); + } + } + + public static void BicR(CodeGenContext context, uint rd, uint rn, uint rm, uint sType, uint imm5, bool s) + { + EmitLogicalR(context, s ? context.Arm64Assembler.Bics : context.Arm64Assembler.Bic, rd, rn, rm, sType, imm5, s); + } + + public static void BicRr(CodeGenContext context, uint rd, uint rn, uint rm, uint sType, uint rs, bool s) + { + EmitLogicalRr(context, s ? context.Arm64Assembler.Bics : context.Arm64Assembler.Bic, rd, rn, rm, sType, rs, s); + } + + public static void CmnI(CodeGenContext context, uint rn, uint imm) + { + EmitCompareI(context, context.Arm64Assembler.Cmn, rn, imm); + } + + public static void CmnR(CodeGenContext context, uint rn, uint rm, uint sType, uint imm5) + { + EmitCompareR(context, context.Arm64Assembler.Cmn, rn, rm, sType, imm5); + } + + public static void CmnRr(CodeGenContext context, uint rn, uint rm, uint sType, uint rs) + { + EmitCompareRr(context, context.Arm64Assembler.Cmn, rn, rm, sType, rs); + } + + public static void CmpI(CodeGenContext context, uint rn, uint imm) + { + EmitCompareI(context, context.Arm64Assembler.Cmp, rn, imm); + } + + public static void CmpR(CodeGenContext context, uint rn, uint rm, uint sType, uint imm5) + { + EmitCompareR(context, context.Arm64Assembler.Cmp, rn, rm, sType, imm5); + } + + public static void CmpRr(CodeGenContext context, uint rn, uint rm, uint sType, uint rs) + { + EmitCompareRr(context, context.Arm64Assembler.Cmp, rn, rm, sType, rs); + } + + public static void EorI(CodeGenContext context, uint rd, uint rn, uint imm, bool immRotated, bool s) + { + EmitLogicalI(context, s ? context.Arm64Assembler.Eors : context.Arm64Assembler.Eor, rd, rn, imm, immRotated, s); + } + + public static void EorR(CodeGenContext context, uint rd, uint rn, uint rm, uint sType, uint imm5, bool s) + { + EmitLogicalR(context, s ? context.Arm64Assembler.Eors : context.Arm64Assembler.Eor, rd, rn, rm, sType, imm5, s); + } + + public static void EorRr(CodeGenContext context, uint rd, uint rn, uint rm, uint sType, uint rs, bool s) + { + EmitLogicalRr(context, s ? context.Arm64Assembler.Eors : context.Arm64Assembler.Eor, rd, rn, rm, sType, rs, s); + } + + public static void OrnI(CodeGenContext context, uint rd, uint rn, uint imm, bool immRotated, bool s) + { + if (!s && CodeGenCommon.TryEncodeBitMask(OperandType.I32, ~imm, out _, out _, out _)) + { + OrrI(context, rd, rn, ~imm, immRotated, s); + } + else + { + EmitLogicalI(context, s ? context.Arm64Assembler.Orns : context.Arm64Assembler.Orn, rd, rn, imm, immRotated, s, immForm: false); + } + } + + public static void OrnR(CodeGenContext context, uint rd, uint rn, uint rm, uint sType, uint imm5, bool s) + { + EmitLogicalR(context, s ? context.Arm64Assembler.Orns : context.Arm64Assembler.Orn, rd, rn, rm, sType, imm5, s); + } + + public static void OrrI(CodeGenContext context, uint rd, uint rn, uint imm, bool immRotated, bool s) + { + EmitLogicalI(context, s ? context.Arm64Assembler.Orrs : context.Arm64Assembler.Orr, rd, rn, imm, immRotated, s); + } + + public static void OrrR(CodeGenContext context, uint rd, uint rn, uint rm, uint sType, uint imm5, bool s) + { + EmitLogicalR(context, s ? context.Arm64Assembler.Orrs : context.Arm64Assembler.Orr, rd, rn, rm, sType, imm5, s); + } + + public static void OrrRr(CodeGenContext context, uint rd, uint rn, uint rm, uint sType, uint rs, bool s) + { + EmitLogicalRr(context, s ? context.Arm64Assembler.Orrs : context.Arm64Assembler.Orr, rd, rn, rm, sType, rs, s); + } + + public static void RsbI(CodeGenContext context, uint rd, uint rn, uint imm, bool s) + { + if (imm == 0) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + + if (s) + { + context.Arm64Assembler.Negs(rdOperand, rnOperand); + context.SetNzcvModified(); + } + else + { + context.Arm64Assembler.Neg(rdOperand, rnOperand); + } + } + else + { + EmitI(context, s ? context.Arm64Assembler.Subs : context.Arm64Assembler.Sub, rd, rn, imm, s, reverse: true); + } + } + + public static void RsbR(CodeGenContext context, uint rd, uint rn, uint rm, uint sType, uint imm5, bool s) + { + EmitR(context, s ? context.Arm64Assembler.Subs : context.Arm64Assembler.Sub, rd, rn, rm, sType, imm5, s, reverse: true); + } + + public static void RsbRr(CodeGenContext context, uint rd, uint rn, uint rm, uint sType, uint rs, bool s) + { + EmitRr(context, s ? context.Arm64Assembler.Subs : context.Arm64Assembler.Sub, rd, rn, rm, sType, rs, s, reverse: true); + } + + public static void RscI(CodeGenContext context, uint rd, uint rn, uint imm, bool s) + { + EmitI(context, s ? context.Arm64Assembler.Sbcs : context.Arm64Assembler.Sbc, rd, rn, imm, s, reverse: true); + } + + public static void RscR(CodeGenContext context, uint rd, uint rn, uint rm, uint sType, uint imm5, bool s) + { + EmitR(context, s ? context.Arm64Assembler.Sbcs : context.Arm64Assembler.Sbc, rd, rn, rm, sType, imm5, s, reverse: true); + } + + public static void RscRr(CodeGenContext context, uint rd, uint rn, uint rm, uint sType, uint rs, bool s) + { + EmitRr(context, s ? context.Arm64Assembler.Sbcs : context.Arm64Assembler.Sbc, rd, rn, rm, sType, rs, s, reverse: true); + } + + public static void SbcI(CodeGenContext context, uint rd, uint rn, uint imm, bool s) + { + EmitI(context, s ? context.Arm64Assembler.Sbcs : context.Arm64Assembler.Sbc, rd, rn, imm, s); + } + + public static void SbcR(CodeGenContext context, uint rd, uint rn, uint rm, uint sType, uint imm5, bool s) + { + EmitR(context, s ? context.Arm64Assembler.Sbcs : context.Arm64Assembler.Sbc, rd, rn, rm, sType, imm5, s); + } + + public static void SbcRr(CodeGenContext context, uint rd, uint rn, uint rm, uint sType, uint rs, bool s) + { + EmitRr(context, s ? context.Arm64Assembler.Sbcs : context.Arm64Assembler.Sbc, rd, rn, rm, sType, rs, s); + } + + public static void SubI(CodeGenContext context, uint rd, uint rn, uint imm, bool s) + { + EmitArithmeticI(context, s ? context.Arm64Assembler.Subs : context.Arm64Assembler.Sub, rd, rn, imm, s); + } + + public static void SubR(CodeGenContext context, uint rd, uint rn, uint rm, uint sType, uint imm5, bool s) + { + EmitArithmeticR(context, s ? context.Arm64Assembler.Subs : context.Arm64Assembler.Sub, rd, rn, rm, sType, imm5, s); + } + + public static void SubRr(CodeGenContext context, uint rd, uint rn, uint rm, uint sType, uint rs, bool s) + { + EmitRr(context, s ? context.Arm64Assembler.Subs : context.Arm64Assembler.Sub, rd, rn, rm, sType, rs, s); + } + + public static void TeqI(CodeGenContext context, uint rn, uint imm, bool immRotated) + { + EmitLogicalI(context, (rnOperand, rmOperand) => EmitTeq(context, rnOperand, rmOperand), rn, imm, immRotated); + } + + public static void TeqR(CodeGenContext context, uint rn, uint rm, uint sType, uint imm5) + { + EmitLogicalR(context, (rnOperand, rmOperand) => EmitTeq(context, rnOperand, rmOperand), rn, rm, sType, imm5); + } + + public static void TeqRr(CodeGenContext context, uint rn, uint rm, uint sType, uint rs) + { + EmitLogicalRr(context, (rnOperand, rmOperand) => EmitTeq(context, rnOperand, rmOperand), rn, rm, sType, rs); + } + + public static void TstI(CodeGenContext context, uint rn, uint imm, bool immRotated) + { + EmitLogicalI(context, context.Arm64Assembler.Tst, rn, imm, immRotated); + } + + public static void TstR(CodeGenContext context, uint rn, uint rm, uint sType, uint imm5) + { + EmitLogicalR(context, context.Arm64Assembler.Tst, rn, rm, sType, imm5); + } + + public static void TstRr(CodeGenContext context, uint rn, uint rm, uint sType, uint rs) + { + EmitLogicalRr(context, context.Arm64Assembler.Tst, rn, rm, sType, rs); + } + + private static void EmitArithmeticI(CodeGenContext context, Action action, uint rd, uint rn, uint imm, bool s) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + + if (imm < Imm12Limit) + { + Operand rmOperand = new(OperandKind.Constant, OperandType.I32, imm); + + action(rdOperand, rnOperand, rmOperand); + } + else + { + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + context.Arm64Assembler.Mov(tempRegister.Operand, imm); + + action(rdOperand, rnOperand, tempRegister.Operand); + } + + if (s) + { + context.SetNzcvModified(); + } + } + + private static void EmitArithmeticR( + CodeGenContext context, + Action action, + uint rd, + uint rn, + uint rm, + uint sType, + uint imm5, + bool s) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + + if (CanShiftArithmetic(sType, imm5)) + { + action(rdOperand, rnOperand, rmOperand, (ArmShiftType)sType, (int)imm5); + } + else + { + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + rmOperand = GetMShiftedByImmediate(context, tempRegister.Operand, rmOperand, imm5, sType); + + action(rdOperand, rnOperand, rmOperand, ArmShiftType.Lsl, 0); + } + + if (s) + { + context.SetNzcvModified(); + } + } + + private static void EmitCompareI(CodeGenContext context, Action action, uint rn, uint imm) + { + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + + if (imm < Imm12Limit) + { + Operand rmOperand = new(OperandKind.Constant, OperandType.I32, imm); + + action(rnOperand, rmOperand); + } + else + { + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + context.Arm64Assembler.Mov(tempRegister.Operand, imm); + + action(rnOperand, tempRegister.Operand); + } + + context.SetNzcvModified(); + } + + private static void EmitCompareR( + CodeGenContext context, + Action action, + uint rn, + uint rm, + uint sType, + uint imm5) + { + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + + if (CanShiftArithmetic(sType, imm5)) + { + action(rnOperand, rmOperand, (ArmShiftType)sType, (int)imm5); + } + else + { + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + rmOperand = GetMShiftedByImmediate(context, tempRegister.Operand, rmOperand, imm5, sType); + + action(rnOperand, rmOperand, ArmShiftType.Lsl, 0); + } + + context.SetNzcvModified(); + } + + private static void EmitCompareRr(CodeGenContext context, Action action, uint rn, uint rm, uint sType, uint rs) + { + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + Operand rsOperand = InstEmitCommon.GetInputGpr(context, rs); + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + rmOperand = GetMShiftedByReg(context, tempRegister.Operand, rmOperand, rsOperand, sType); + + action(rnOperand, rmOperand); + + context.SetNzcvModified(); + } + + private static void EmitI(CodeGenContext context, Action action, uint rd, uint rn, uint imm, bool s, bool reverse = false) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + context.Arm64Assembler.Mov(tempRegister.Operand, imm); + + if (reverse) + { + action(rdOperand, tempRegister.Operand, rnOperand); + } + else + { + action(rdOperand, rnOperand, tempRegister.Operand); + } + + if (s) + { + context.SetNzcvModified(); + } + } + + private static void EmitR(CodeGenContext context, Action action, uint rd, uint rn, uint rm, uint sType, uint imm5, bool s, bool reverse = false) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + rmOperand = GetMShiftedByImmediate(context, tempRegister.Operand, rmOperand, imm5, sType); + + if (reverse) + { + action(rdOperand, rmOperand, rnOperand); + } + else + { + action(rdOperand, rnOperand, rmOperand); + } + + if (s) + { + context.SetNzcvModified(); + } + } + + private static void EmitRr(CodeGenContext context, Action action, uint rd, uint rn, uint rm, uint sType, uint rs, bool s, bool reverse = false) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + Operand rsOperand = InstEmitCommon.GetInputGpr(context, rs); + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + rmOperand = GetMShiftedByReg(context, tempRegister.Operand, rmOperand, rsOperand, sType); + + if (reverse) + { + action(rdOperand, rmOperand, rnOperand); + } + else + { + action(rdOperand, rnOperand, rmOperand); + } + + if (s) + { + context.SetNzcvModified(); + } + } + + private static void EmitLogicalI(CodeGenContext context, Action action, uint rn, uint imm, bool immRotated) + { + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + + using ScopedRegister flagsRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + InstEmitCommon.GetCurrentFlags(context, flagsRegister.Operand); + + if (immRotated) + { + if ((imm & (1u << 31)) != 0) + { + context.Arm64Assembler.Orr(flagsRegister.Operand, flagsRegister.Operand, InstEmitCommon.Const(2)); + } + else + { + context.Arm64Assembler.Bfc(flagsRegister.Operand, 1, 1); + } + } + + if (CodeGenCommon.TryEncodeBitMask(OperandType.I32, imm, out _, out _, out _)) + { + action(rnOperand, InstEmitCommon.Const((int)imm)); + } + else + { + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + context.Arm64Assembler.Mov(tempRegister.Operand, imm); + + action(rnOperand, tempRegister.Operand); + } + + InstEmitCommon.RestoreCvFlags(context, flagsRegister.Operand); + + context.SetNzcvModified(); + } + + private static void EmitLogicalI( + CodeGenContext context, + Action action, + uint rd, + uint rn, + uint imm, + bool immRotated, + bool s, + bool immForm = true) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + + ScopedRegister flagsRegister = default; + + if (s) + { + flagsRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + InstEmitCommon.GetCurrentFlags(context, flagsRegister.Operand); + + if (immRotated) + { + if ((imm & (1u << 31)) != 0) + { + context.Arm64Assembler.Orr(flagsRegister.Operand, flagsRegister.Operand, InstEmitCommon.Const(2)); + } + else + { + context.Arm64Assembler.Bfc(flagsRegister.Operand, 1, 1); + } + } + } + + if (imm == 0 || (immForm && CodeGenCommon.TryEncodeBitMask(OperandType.I32, imm, out _, out _, out _))) + { + action(rdOperand, rnOperand, InstEmitCommon.Const((int)imm)); + } + else + { + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + context.Arm64Assembler.Mov(tempRegister.Operand, imm); + + action(rdOperand, rnOperand, tempRegister.Operand); + } + + if (s) + { + InstEmitCommon.RestoreCvFlags(context, flagsRegister.Operand); + + flagsRegister.Dispose(); + + context.SetNzcvModified(); + } + } + + private static void EmitLogicalR(CodeGenContext context, Action action, uint rn, uint rm, uint sType, uint imm5) + { + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister flagsRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + InstEmitCommon.GetCurrentFlags(context, flagsRegister.Operand); + + rmOperand = GetMShiftedByImmediate(context, tempRegister.Operand, rmOperand, imm5, sType, flagsRegister.Operand); + + action(rnOperand, rmOperand); + + InstEmitCommon.RestoreCvFlags(context, flagsRegister.Operand); + + context.SetNzcvModified(); + } + + private static void EmitLogicalR(CodeGenContext context, Action action, uint rd, uint rn, uint rm, uint sType, uint imm5, bool s) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + + if (CanShift(sType, imm5) && !s) + { + action(rdOperand, rnOperand, rmOperand, (ArmShiftType)sType, (int)imm5); + } + else + { + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + ScopedRegister flagsRegister = default; + + if (s) + { + flagsRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + InstEmitCommon.GetCurrentFlags(context, flagsRegister.Operand); + + rmOperand = GetMShiftedByImmediate(context, tempRegister.Operand, rmOperand, imm5, sType, flagsRegister.Operand); + } + else + { + rmOperand = GetMShiftedByImmediate(context, tempRegister.Operand, rmOperand, imm5, sType, null); + } + + action(rdOperand, rnOperand, rmOperand, ArmShiftType.Lsl, 0); + + if (s) + { + InstEmitCommon.RestoreCvFlags(context, flagsRegister.Operand); + + flagsRegister.Dispose(); + + context.SetNzcvModified(); + } + } + } + + private static void EmitLogicalRr(CodeGenContext context, Action action, uint rn, uint rm, uint sType, uint rs) + { + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + Operand rsOperand = InstEmitCommon.GetInputGpr(context, rs); + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister flagsRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + InstEmitCommon.GetCurrentFlags(context, flagsRegister.Operand); + + rmOperand = GetMShiftedByReg(context, tempRegister.Operand, rmOperand, rsOperand, sType, flagsRegister.Operand); + + action(rnOperand, rmOperand); + + InstEmitCommon.RestoreCvFlags(context, flagsRegister.Operand); + + context.SetNzcvModified(); + } + + private static void EmitLogicalRr(CodeGenContext context, Action action, uint rd, uint rn, uint rm, uint sType, uint rs, bool s) + { + if (s) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + Operand rsOperand = InstEmitCommon.GetInputGpr(context, rs); + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister flagsRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + InstEmitCommon.GetCurrentFlags(context, flagsRegister.Operand); + + rmOperand = GetMShiftedByReg(context, tempRegister.Operand, rmOperand, rsOperand, sType, flagsRegister.Operand); + + action(rdOperand, rnOperand, rmOperand); + + InstEmitCommon.RestoreCvFlags(context, flagsRegister.Operand); + + context.SetNzcvModified(); + } + else + { + EmitRr(context, action, rd, rn, rm, sType, rs, s); + } + } + + public static bool CanShiftArithmetic(uint sType, uint imm5) + { + // We can't encode ROR or RRX. + + return sType != 3 && (sType == 0 || imm5 != 0); + } + + public static bool CanShift(uint sType, uint imm5) + { + // We can encode all shift types directly, except RRX. + + return imm5 != 0 || sType == 0; + } + + public static Operand GetMShiftedByImmediate(CodeGenContext context, Operand dest, Operand m, uint imm, uint sType, Operand? carryOut = null) + { + int shift = (int)imm; + + if (shift == 0) + { + switch ((ArmShiftType)sType) + { + case ArmShiftType.Lsr: + shift = 32; + break; + case ArmShiftType.Asr: + shift = 32; + break; + case ArmShiftType.Ror: + shift = 1; + break; + } + } + + if (shift != 0) + { + switch ((ArmShiftType)sType) + { + case ArmShiftType.Lsl: + m = GetLslC(context, dest, m, carryOut, shift); + break; + case ArmShiftType.Lsr: + m = GetLsrC(context, dest, m, carryOut, shift); + break; + case ArmShiftType.Asr: + m = GetAsrC(context, dest, m, carryOut, shift); + break; + case ArmShiftType.Ror: + if (imm != 0) + { + m = GetRorC(context, dest, m, carryOut, shift); + } + else + { + m = GetRrxC(context, dest, m, carryOut); + } + break; + } + } + + return m; + } + + public static Operand GetMShiftedByReg(CodeGenContext context, Operand dest, Operand m, Operand s, uint sType, Operand? carryOut = null) + { + Operand shiftResult = m; + + switch ((ArmShiftType)sType) + { + case ArmShiftType.Lsl: + shiftResult = EmitLslC(context, dest, m, carryOut, s); + break; + case ArmShiftType.Lsr: + shiftResult = EmitLsrC(context, dest, m, carryOut, s); + break; + case ArmShiftType.Asr: + shiftResult = EmitAsrC(context, dest, m, carryOut, s); + break; + case ArmShiftType.Ror: + shiftResult = EmitRorC(context, dest, m, carryOut, s); + break; + } + + return shiftResult; + } + + private static void EmitIfHelper(CodeGenContext context, Operand boolValue, Action action, bool expected = true) + { + Debug.Assert(boolValue.Type == OperandType.I32); + + int branchInstructionPointer = context.CodeWriter.InstructionPointer; + + if (expected) + { + context.Arm64Assembler.Cbnz(boolValue, 0); + } + else + { + context.Arm64Assembler.Cbz(boolValue, 0); + } + + action(); + + int offset = context.CodeWriter.InstructionPointer - branchInstructionPointer; + Debug.Assert(offset >= 0); + Debug.Assert((offset << 13) >> 13 == offset); + uint branchInst = context.CodeWriter.ReadInstructionAt(branchInstructionPointer); + context.CodeWriter.WriteInstructionAt(branchInstructionPointer, branchInst | (uint)(offset << 5)); + } + + private static Operand EmitLslC(CodeGenContext context, Operand dest, Operand m, Operand? carryOut, Operand shift) + { + Debug.Assert(m.Type == OperandType.I32 && shift.Type == OperandType.I32); + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + Operand mask = tempRegister.Operand; + context.Arm64Assembler.Uxtb(mask, shift); + context.Arm64Assembler.Sub(mask, mask, InstEmitCommon.Const(32)); + context.Arm64Assembler.Asr(mask, mask, InstEmitCommon.Const(31)); + + Operand dest64 = new(OperandKind.Register, OperandType.I64, dest.Value); + + if (carryOut.HasValue) + { + context.Arm64Assembler.Lslv(dest64, m, shift); + } + else + { + context.Arm64Assembler.Lslv(dest, m, shift); + } + + // If shift >= 32, force the result to 0. + context.Arm64Assembler.And(dest, dest, mask); + + if (carryOut.HasValue) + { + EmitIfHelper(context, shift, () => + { + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + context.Arm64Assembler.Uxtb(mask, shift); + context.Arm64Assembler.Sub(mask, mask, InstEmitCommon.Const(33)); + context.Arm64Assembler.Lsr(mask, mask, InstEmitCommon.Const(31)); + context.Arm64Assembler.Lsr(tempRegister.Operand, dest64, InstEmitCommon.Const(32)); + context.Arm64Assembler.And(tempRegister.Operand, tempRegister.Operand, mask); + + UpdateCarryFlag(context, tempRegister.Operand, carryOut.Value); + }, false); + } + + return dest; + } + + private static Operand GetLslC(CodeGenContext context, Operand dest, Operand m, Operand? carryOut, int shift) + { + Debug.Assert(m.Type == OperandType.I32); + + if ((uint)shift > 32) + { + return GetShiftByMoreThan32(context, carryOut); + } + else if (shift == 32) + { + if (carryOut.HasValue) + { + SetCarryMLsb(context, m, carryOut.Value); + } + + return InstEmitCommon.Const(0); + } + else + { + if (carryOut.HasValue) + { + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + context.Arm64Assembler.Lsr(tempRegister.Operand, m, InstEmitCommon.Const(32 - shift)); + + UpdateCarryFlag(context, tempRegister.Operand, carryOut.Value); + } + + context.Arm64Assembler.Lsl(dest, m, InstEmitCommon.Const(shift)); + + return dest; + } + } + + private static Operand EmitLsrC(CodeGenContext context, Operand dest, Operand m, Operand? carryOut, Operand shift) + { + Debug.Assert(m.Type == OperandType.I32 && shift.Type == OperandType.I32); + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + Operand mask = tempRegister.Operand; + context.Arm64Assembler.Uxtb(mask, shift); + context.Arm64Assembler.Sub(mask, mask, InstEmitCommon.Const(32)); + context.Arm64Assembler.Asr(mask, mask, InstEmitCommon.Const(31)); + + context.Arm64Assembler.Lsrv(dest, m, shift); + + // If shift >= 32, force the result to 0. + context.Arm64Assembler.And(dest, dest, mask); + + if (carryOut.HasValue) + { + EmitIfHelper(context, shift, () => + { + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + context.Arm64Assembler.Uxtb(mask, shift); + context.Arm64Assembler.Sub(mask, mask, InstEmitCommon.Const(33)); + context.Arm64Assembler.Lsr(mask, mask, InstEmitCommon.Const(31)); + context.Arm64Assembler.Sub(tempRegister.Operand, shift, InstEmitCommon.Const(1)); + context.Arm64Assembler.Lsrv(tempRegister.Operand, m, tempRegister.Operand); + context.Arm64Assembler.And(tempRegister.Operand, tempRegister.Operand, mask); + + UpdateCarryFlag(context, tempRegister.Operand, carryOut.Value); + }, false); + } + + return dest; + } + + public static Operand GetLsrC(CodeGenContext context, Operand dest, Operand m, Operand? carryOut, int shift) + { + Debug.Assert(m.Type == OperandType.I32); + + if ((uint)shift > 32) + { + return GetShiftByMoreThan32(context, carryOut); + } + else if (shift == 32) + { + if (carryOut.HasValue) + { + SetCarryMMsb(context, m, carryOut.Value); + } + + return InstEmitCommon.Const(0); + } + else + { + if (carryOut.HasValue) + { + SetCarryMShrOut(context, m, shift, carryOut.Value); + } + + context.Arm64Assembler.Lsr(dest, m, InstEmitCommon.Const(shift)); + + return dest; + } + } + + private static Operand GetShiftByMoreThan32(CodeGenContext context, Operand? carryOut) + { + if (carryOut.HasValue) + { + // Clear carry flag. + + context.Arm64Assembler.Bfc(carryOut.Value, 1, 1); + } + + return InstEmitCommon.Const(0); + } + + private static Operand EmitAsrC(CodeGenContext context, Operand dest, Operand m, Operand? carryOut, Operand shift) + { + Debug.Assert(m.Type == OperandType.I32 && shift.Type == OperandType.I32); + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + Operand mask = tempRegister.Operand; + context.Arm64Assembler.Uxtb(mask, shift); + context.Arm64Assembler.Sub(mask, mask, InstEmitCommon.Const(31)); + context.Arm64Assembler.Orn(mask, shift, mask, ArmShiftType.Asr, 31); + + context.Arm64Assembler.Asrv(dest, m, mask); + + if (carryOut.HasValue) + { + EmitIfHelper(context, shift, () => + { + // If shift >= 32, carry should be equal to the MSB of Rm. + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + context.Arm64Assembler.Sub(tempRegister.Operand, mask, InstEmitCommon.Const(1)); + context.Arm64Assembler.Orr(tempRegister.Operand, tempRegister.Operand, mask, ArmShiftType.Asr, 31); + context.Arm64Assembler.Lsrv(tempRegister.Operand, m, tempRegister.Operand); + + UpdateCarryFlag(context, tempRegister.Operand, carryOut.Value); + }, false); + } + + return dest; + } + + private static Operand GetAsrC(CodeGenContext context, Operand dest, Operand m, Operand? carryOut, int shift) + { + Debug.Assert(m.Type == OperandType.I32); + + if ((uint)shift >= 32) + { + context.Arm64Assembler.Asr(dest, m, InstEmitCommon.Const(31)); + + if (carryOut.HasValue) + { + SetCarryMLsb(context, dest, carryOut.Value); + } + + return dest; + } + else + { + if (carryOut.HasValue) + { + SetCarryMShrOut(context, m, shift, carryOut.Value); + } + + context.Arm64Assembler.Asr(dest, m, InstEmitCommon.Const(shift)); + + return dest; + } + } + + private static Operand EmitRorC(CodeGenContext context, Operand dest, Operand m, Operand? carryOut, Operand shift) + { + Debug.Assert(m.Type == OperandType.I32 && shift.Type == OperandType.I32); + + context.Arm64Assembler.Rorv(dest, m, shift); + + if (carryOut.HasValue) + { + EmitIfHelper(context, shift, () => + { + SetCarryMMsb(context, m, carryOut.Value); + }, false); + } + + return dest; + } + + private static Operand GetRorC(CodeGenContext context, Operand dest, Operand m, Operand? carryOut, int shift) + { + Debug.Assert(m.Type == OperandType.I32); + + shift &= 0x1f; + + context.Arm64Assembler.Ror(dest, m, InstEmitCommon.Const(shift)); + + if (carryOut.HasValue) + { + SetCarryMMsb(context, dest, carryOut.Value); + } + + return dest; + } + + private static Operand GetRrxC(CodeGenContext context, Operand dest, Operand m, Operand? carryOut) + { + Debug.Assert(m.Type == OperandType.I32); + + // Rotate right by 1 with carry. + + if (carryOut.HasValue) + { + SetCarryMLsb(context, m, carryOut.Value); + } + + context.Arm64Assembler.Mov(dest, m); + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + context.Arm64Assembler.MrsNzcv(tempRegister.Operand); + context.Arm64Assembler.Bfxil(dest, tempRegister.Operand, 29, 1); + context.Arm64Assembler.Ror(dest, dest, InstEmitCommon.Const(1)); + + return dest; + } + + private static void SetCarryMLsb(CodeGenContext context, Operand m, Operand carryOut) + { + Debug.Assert(m.Type == OperandType.I32); + + UpdateCarryFlag(context, m, carryOut); + } + + private static void SetCarryMMsb(CodeGenContext context, Operand m, Operand carryOut) + { + Debug.Assert(m.Type == OperandType.I32); + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + context.Arm64Assembler.Lsr(tempRegister.Operand, m, InstEmitCommon.Const(31)); + + UpdateCarryFlag(context, tempRegister.Operand, carryOut); + } + + private static void SetCarryMShrOut(CodeGenContext context, Operand m, int shift, Operand carryOut) + { + Debug.Assert(m.Type == OperandType.I32); + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + context.Arm64Assembler.Lsr(tempRegister.Operand, m, InstEmitCommon.Const(shift - 1)); + + UpdateCarryFlag(context, tempRegister.Operand, carryOut); + } + + private static void UpdateCarryFlag(CodeGenContext context, Operand value, Operand carryOut) + { + context.Arm64Assembler.Bfi(carryOut, value, 1, 1); + } + + private static void EmitTeq(CodeGenContext context, Operand rnOperand, Operand rmOperand) + { + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + context.Arm64Assembler.Eors(tempRegister.Operand, rnOperand, rmOperand); + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitBit.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitBit.cs new file mode 100644 index 000000000..3f91d45f2 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitBit.cs @@ -0,0 +1,103 @@ +using Ryujinx.Cpu.LightningJit.CodeGen; + +namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 +{ + static class InstEmitBit + { + public static void Bfc(CodeGenContext context, uint rd, uint lsb, uint msb) + { + // This is documented as "unpredictable". + if (msb < lsb) + { + return; + } + + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + + context.Arm64Assembler.Bfc(rdOperand, (int)lsb, (int)(msb - lsb + 1)); + } + + public static void Bfi(CodeGenContext context, uint rd, uint rn, uint lsb, uint msb) + { + // This is documented as "unpredictable". + if (msb < lsb) + { + return; + } + + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + + context.Arm64Assembler.Bfi(rdOperand, rnOperand, (int)lsb, (int)(msb - lsb + 1)); + } + + public static void Clz(CodeGenContext context, uint rd, uint rm) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + + context.Arm64Assembler.Clz(rdOperand, rmOperand); + } + + public static void Rbit(CodeGenContext context, uint rd, uint rm) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + + context.Arm64Assembler.Rbit(rdOperand, rmOperand); + } + + public static void Rev(CodeGenContext context, uint rd, uint rm) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + + context.Arm64Assembler.Rev(rdOperand, rmOperand); + } + + public static void Rev16(CodeGenContext context, uint rd, uint rm) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + + context.Arm64Assembler.Rev16(rdOperand, rmOperand); + } + + public static void Revsh(CodeGenContext context, uint rd, uint rm) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + + context.Arm64Assembler.Rev16(rdOperand, rmOperand); + context.Arm64Assembler.Sxth(rdOperand, rdOperand); + } + + public static void Sbfx(CodeGenContext context, uint rd, uint rn, uint lsb, uint widthMinus1) + { + // This is documented as "unpredictable". + if (lsb + widthMinus1 > 31) + { + return; + } + + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + + context.Arm64Assembler.Sbfx(rdOperand, rnOperand, (int)lsb, (int)widthMinus1 + 1); + } + + public static void Ubfx(CodeGenContext context, uint rd, uint rn, uint lsb, uint widthMinus1) + { + // This is documented as "unpredictable". + if (lsb + widthMinus1 > 31) + { + return; + } + + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + + context.Arm64Assembler.Ubfx(rdOperand, rnOperand, (int)lsb, (int)widthMinus1 + 1); + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitCommon.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitCommon.cs new file mode 100644 index 000000000..1ec4c807e --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitCommon.cs @@ -0,0 +1,263 @@ +using Ryujinx.Cpu.LightningJit.CodeGen; +using Ryujinx.Cpu.LightningJit.CodeGen.Arm64; +using System; + +namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 +{ + static class InstEmitCommon + { + public static Operand Const(int value) + { + return new(OperandKind.Constant, OperandType.I32, (uint)value); + } + + public static Operand GetInputGpr(CodeGenContext context, uint register) + { + Operand operand = context.RegisterAllocator.RemapGprRegister((int)register); + + if (register == RegisterUtils.PcRegister) + { + context.Arm64Assembler.Mov(operand, context.Pc); + } + + return operand; + } + + public static Operand GetOutputGpr(CodeGenContext context, uint register) + { + return context.RegisterAllocator.RemapGprRegister((int)register); + } + + public static void GetCurrentFlags(CodeGenContext context, Operand flagsOut) + { + context.Arm64Assembler.MrsNzcv(flagsOut); + context.Arm64Assembler.Lsr(flagsOut, flagsOut, Const(28)); + } + + public static void RestoreNzcvFlags(CodeGenContext context, Operand nzcvFlags) + { + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + context.Arm64Assembler.Lsl(tempRegister.Operand, nzcvFlags, Const(28)); + context.Arm64Assembler.MsrNzcv(tempRegister.Operand); + } + + public static void RestoreCvFlags(CodeGenContext context, Operand cvFlags) + { + // Arm64 zeros the carry and overflow flags for logical operations, but Arm32 keeps them unchanged. + // This will restore carry and overflow after a operation has zeroed them. + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + context.Arm64Assembler.MrsNzcv(tempRegister.Operand); + context.Arm64Assembler.Bfi(tempRegister.Operand, cvFlags, 28, 2); + context.Arm64Assembler.MsrNzcv(tempRegister.Operand); + } + + public static void SetThumbFlag(CodeGenContext context) + { + Operand ctx = InstEmitSystem.Register(context.RegisterAllocator.FixedContextRegister); + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + context.Arm64Assembler.LdrRiUn(tempRegister.Operand, ctx, NativeContextOffsets.FlagsBaseOffset); + context.Arm64Assembler.Orr(tempRegister.Operand, tempRegister.Operand, Const(1 << 5)); + context.Arm64Assembler.StrRiUn(tempRegister.Operand, ctx, NativeContextOffsets.FlagsBaseOffset); + } + + public static void SetThumbFlag(CodeGenContext context, Operand value) + { + Operand ctx = InstEmitSystem.Register(context.RegisterAllocator.FixedContextRegister); + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + context.Arm64Assembler.LdrRiUn(tempRegister.Operand, ctx, NativeContextOffsets.FlagsBaseOffset); + context.Arm64Assembler.Bfi(tempRegister.Operand, value, 5, 1); + context.Arm64Assembler.StrRiUn(tempRegister.Operand, ctx, NativeContextOffsets.FlagsBaseOffset); + } + + public static void ClearThumbFlag(CodeGenContext context) + { + Operand ctx = InstEmitSystem.Register(context.RegisterAllocator.FixedContextRegister); + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + context.Arm64Assembler.LdrRiUn(tempRegister.Operand, ctx, NativeContextOffsets.FlagsBaseOffset); + context.Arm64Assembler.Bfc(tempRegister.Operand, 5, 1); + context.Arm64Assembler.StrRiUn(tempRegister.Operand, ctx, NativeContextOffsets.FlagsBaseOffset); + } + + public static void EmitSigned16BitPair(CodeGenContext context, uint rd, uint rn, Action elementAction) + { + using ScopedRegister tempD = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister tempD2 = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister tempN = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + Operand rdOperand = GetOutputGpr(context, rd); + Operand rnOperand = GetInputGpr(context, rn); + + context.Arm64Assembler.Sxth(tempN.Operand, rnOperand); + elementAction(tempD.Operand, tempN.Operand); + context.Arm64Assembler.Uxth(tempD2.Operand, tempD.Operand); + + context.Arm64Assembler.Asr(tempN.Operand, rnOperand, Const(16)); + elementAction(tempD.Operand, tempN.Operand); + context.Arm64Assembler.Orr(rdOperand, tempD2.Operand, tempD.Operand, ArmShiftType.Lsl, 16); + } + + public static void EmitSigned16BitPair(CodeGenContext context, uint rd, uint rn, uint rm, Action elementAction) + { + using ScopedRegister tempD = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister tempD2 = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister tempN = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister tempM = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + Operand rdOperand = GetOutputGpr(context, rd); + Operand rnOperand = GetInputGpr(context, rn); + Operand rmOperand = GetInputGpr(context, rm); + + context.Arm64Assembler.Sxth(tempN.Operand, rnOperand); + context.Arm64Assembler.Sxth(tempM.Operand, rmOperand); + elementAction(tempD.Operand, tempN.Operand, tempM.Operand); + context.Arm64Assembler.Uxth(tempD2.Operand, tempD.Operand); + + context.Arm64Assembler.Asr(tempN.Operand, rnOperand, Const(16)); + context.Arm64Assembler.Asr(tempM.Operand, rmOperand, Const(16)); + elementAction(tempD.Operand, tempN.Operand, tempM.Operand); + context.Arm64Assembler.Orr(rdOperand, tempD2.Operand, tempD.Operand, ArmShiftType.Lsl, 16); + } + + public static void EmitSigned16BitXPair(CodeGenContext context, uint rd, uint rn, uint rm, Action elementAction) + { + using ScopedRegister tempD = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister tempD2 = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister tempN = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister tempM = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + Operand rdOperand = GetOutputGpr(context, rd); + Operand rnOperand = GetInputGpr(context, rn); + Operand rmOperand = GetInputGpr(context, rm); + + context.Arm64Assembler.Sxth(tempN.Operand, rnOperand); + context.Arm64Assembler.Asr(tempM.Operand, rmOperand, Const(16)); + elementAction(tempD.Operand, tempN.Operand, tempM.Operand, 0); + context.Arm64Assembler.Uxth(tempD2.Operand, tempD.Operand); + + context.Arm64Assembler.Asr(tempN.Operand, rnOperand, Const(16)); + context.Arm64Assembler.Sxth(tempM.Operand, rmOperand); + elementAction(tempD.Operand, tempN.Operand, tempM.Operand, 1); + context.Arm64Assembler.Orr(rdOperand, tempD2.Operand, tempD.Operand, ArmShiftType.Lsl, 16); + } + + public static void EmitSigned8BitPair(CodeGenContext context, uint rd, uint rn, uint rm, Action elementAction) + { + Emit8BitPair(context, rd, rn, rm, elementAction, unsigned: false); + } + + public static void EmitUnsigned16BitPair(CodeGenContext context, uint rd, uint rn, uint rm, Action elementAction) + { + using ScopedRegister tempD = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister tempD2 = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister tempN = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister tempM = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + Operand rdOperand = GetOutputGpr(context, rd); + Operand rnOperand = GetInputGpr(context, rn); + Operand rmOperand = GetInputGpr(context, rm); + + context.Arm64Assembler.Uxth(tempN.Operand, rnOperand); + context.Arm64Assembler.Uxth(tempM.Operand, rmOperand); + elementAction(tempD.Operand, tempN.Operand, tempM.Operand); + context.Arm64Assembler.Uxth(tempD2.Operand, tempD.Operand); + + context.Arm64Assembler.Lsr(tempN.Operand, rnOperand, Const(16)); + context.Arm64Assembler.Lsr(tempM.Operand, rmOperand, Const(16)); + elementAction(tempD.Operand, tempN.Operand, tempM.Operand); + context.Arm64Assembler.Orr(rdOperand, tempD2.Operand, tempD.Operand, ArmShiftType.Lsl, 16); + } + + public static void EmitUnsigned16BitXPair(CodeGenContext context, uint rd, uint rn, uint rm, Action elementAction) + { + using ScopedRegister tempD = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister tempD2 = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister tempN = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister tempM = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + Operand rdOperand = GetOutputGpr(context, rd); + Operand rnOperand = GetInputGpr(context, rn); + Operand rmOperand = GetInputGpr(context, rm); + + context.Arm64Assembler.Uxth(tempN.Operand, rnOperand); + context.Arm64Assembler.Lsr(tempM.Operand, rmOperand, Const(16)); + elementAction(tempD.Operand, tempN.Operand, tempM.Operand, 0); + context.Arm64Assembler.Uxth(tempD2.Operand, tempD.Operand); + + context.Arm64Assembler.Lsr(tempN.Operand, rnOperand, Const(16)); + context.Arm64Assembler.Uxth(tempM.Operand, rmOperand); + elementAction(tempD.Operand, tempN.Operand, tempM.Operand, 1); + context.Arm64Assembler.Orr(rdOperand, tempD2.Operand, tempD.Operand, ArmShiftType.Lsl, 16); + } + + public static void EmitUnsigned8BitPair(CodeGenContext context, uint rd, uint rn, uint rm, Action elementAction) + { + Emit8BitPair(context, rd, rn, rm, elementAction, unsigned: true); + } + + private static void Emit8BitPair(CodeGenContext context, uint rd, uint rn, uint rm, Action elementAction, bool unsigned) + { + using ScopedRegister tempD = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister tempD2 = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister tempN = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister tempM = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + Operand rdOperand = GetOutputGpr(context, rd); + Operand rnOperand = GetInputGpr(context, rn); + Operand rmOperand = GetInputGpr(context, rm); + + for (int b = 0; b < 4; b++) + { + if (unsigned) + { + context.Arm64Assembler.Ubfx(tempN.Operand, rnOperand, b * 8, 8); + context.Arm64Assembler.Ubfx(tempM.Operand, rmOperand, b * 8, 8); + } + else + { + context.Arm64Assembler.Sbfx(tempN.Operand, rnOperand, b * 8, 8); + context.Arm64Assembler.Sbfx(tempM.Operand, rmOperand, b * 8, 8); + } + + elementAction(tempD.Operand, tempN.Operand, tempM.Operand); + + if (b == 0) + { + context.Arm64Assembler.Uxtb(tempD2.Operand, tempD.Operand); + } + else if (b < 3) + { + context.Arm64Assembler.Uxtb(tempD.Operand, tempD.Operand); + context.Arm64Assembler.Orr(tempD2.Operand, tempD2.Operand, tempD.Operand, ArmShiftType.Lsl, b * 8); + } + else + { + context.Arm64Assembler.Orr(rdOperand, tempD2.Operand, tempD.Operand, ArmShiftType.Lsl, 24); + } + } + } + + public static uint CombineV(uint low4, uint high1, uint size) + { + return size == 3 ? CombineV(low4, high1) : CombineVF(high1, low4); + } + + public static uint CombineV(uint low4, uint high1) + { + return low4 | (high1 << 4); + } + + public static uint CombineVF(uint low1, uint high4) + { + return low1 | (high4 << 1); + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitCrc32.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitCrc32.cs new file mode 100644 index 000000000..ee6341880 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitCrc32.cs @@ -0,0 +1,26 @@ +using Ryujinx.Cpu.LightningJit.CodeGen; +using System; + +namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 +{ + static class InstEmitCrc32 + { + public static void Crc32(CodeGenContext context, uint rd, uint rn, uint rm, uint sz) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + + context.Arm64Assembler.Crc32(rdOperand, rnOperand, rmOperand, Math.Min(2, sz)); + } + + public static void Crc32c(CodeGenContext context, uint rd, uint rn, uint rm, uint sz) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + + context.Arm64Assembler.Crc32c(rdOperand, rnOperand, rmOperand, Math.Min(2, sz)); + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitDivide.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitDivide.cs new file mode 100644 index 000000000..31c96dc80 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitDivide.cs @@ -0,0 +1,25 @@ +using Ryujinx.Cpu.LightningJit.CodeGen; + +namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 +{ + static class InstEmitDivide + { + public static void Sdiv(CodeGenContext context, uint rd, uint rn, uint rm) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + + context.Arm64Assembler.Sdiv(rdOperand, rnOperand, rmOperand); + } + + public static void Udiv(CodeGenContext context, uint rd, uint rn, uint rm) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + + context.Arm64Assembler.Udiv(rdOperand, rnOperand, rmOperand); + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitExtension.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitExtension.cs new file mode 100644 index 000000000..dafe2974e --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitExtension.cs @@ -0,0 +1,191 @@ +using Ryujinx.Cpu.LightningJit.CodeGen; +using Ryujinx.Cpu.LightningJit.CodeGen.Arm64; +using System; + +namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 +{ + static class InstEmitExtension + { + public static void Sxtab(CodeGenContext context, uint rd, uint rn, uint rm, uint rotate) + { + EmitRotated(context, ArmExtensionType.Sxtb, rd, rn, rm, rotate); + } + + public static void Sxtab16(CodeGenContext context, uint rd, uint rn, uint rm, uint rotate) + { + EmitExtendAccumulate8(context, rd, rn, rm, rotate, unsigned: false); + } + + public static void Sxtah(CodeGenContext context, uint rd, uint rn, uint rm, uint rotate) + { + EmitRotated(context, ArmExtensionType.Sxth, rd, rn, rm, rotate); + } + + public static void Sxtb(CodeGenContext context, uint rd, uint rm, uint rotate) + { + EmitRotated(context, context.Arm64Assembler.Sxtb, rd, rm, rotate); + } + + public static void Sxtb16(CodeGenContext context, uint rd, uint rm, uint rotate) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister tempRegister2 = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + if (rotate != 0) + { + context.Arm64Assembler.Ror(tempRegister.Operand, rmOperand, InstEmitCommon.Const((int)rotate * 8)); + context.Arm64Assembler.And(rdOperand, tempRegister.Operand, InstEmitCommon.Const(0xff00ff)); + } + else + { + context.Arm64Assembler.And(rdOperand, rmOperand, InstEmitCommon.Const(0xff00ff)); + } + + // Sign-extend by broadcasting sign bits. + context.Arm64Assembler.And(tempRegister.Operand, rdOperand, InstEmitCommon.Const(0x800080)); + context.Arm64Assembler.Lsl(tempRegister2.Operand, tempRegister.Operand, InstEmitCommon.Const(9)); + context.Arm64Assembler.Sub(tempRegister.Operand, tempRegister2.Operand, tempRegister.Operand); + context.Arm64Assembler.Orr(rdOperand, rdOperand, tempRegister.Operand); + } + + public static void Sxth(CodeGenContext context, uint rd, uint rm, uint rotate) + { + EmitRotated(context, context.Arm64Assembler.Sxth, rd, rm, rotate); + } + + public static void Uxtab(CodeGenContext context, uint rd, uint rn, uint rm, uint rotate) + { + EmitRotated(context, ArmExtensionType.Uxtb, rd, rn, rm, rotate); + } + + public static void Uxtab16(CodeGenContext context, uint rd, uint rn, uint rm, uint rotate) + { + EmitExtendAccumulate8(context, rd, rn, rm, rotate, unsigned: true); + } + + public static void Uxtah(CodeGenContext context, uint rd, uint rn, uint rm, uint rotate) + { + EmitRotated(context, ArmExtensionType.Uxth, rd, rn, rm, rotate); + } + + public static void Uxtb(CodeGenContext context, uint rd, uint rm, uint rotate) + { + EmitRotated(context, context.Arm64Assembler.Uxtb, rd, rm, rotate); + } + + public static void Uxtb16(CodeGenContext context, uint rd, uint rm, uint rotate) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + + if (rotate != 0) + { + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + context.Arm64Assembler.Ror(tempRegister.Operand, rmOperand, InstEmitCommon.Const((int)rotate * 8)); + context.Arm64Assembler.And(rdOperand, tempRegister.Operand, InstEmitCommon.Const(0xff00ff)); + } + else + { + context.Arm64Assembler.And(rdOperand, rmOperand, InstEmitCommon.Const(0xff00ff)); + } + } + + public static void Uxth(CodeGenContext context, uint rd, uint rm, uint rotate) + { + EmitRotated(context, context.Arm64Assembler.Uxth, rd, rm, rotate); + } + + private static void EmitRotated(CodeGenContext context, Action action, uint rd, uint rm, uint rotate) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + + if (rotate != 0) + { + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + context.Arm64Assembler.Ror(tempRegister.Operand, rmOperand, InstEmitCommon.Const((int)rotate * 8)); + action(rdOperand, tempRegister.Operand); + } + else + { + action(rdOperand, rmOperand); + } + } + + private static void EmitRotated(CodeGenContext context, ArmExtensionType extensionType, uint rd, uint rn, uint rm, uint rotate) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + + if (rotate != 0) + { + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + context.Arm64Assembler.Ror(tempRegister.Operand, rmOperand, InstEmitCommon.Const((int)rotate * 8)); + context.Arm64Assembler.Add(rdOperand, rnOperand, tempRegister.Operand, extensionType); + } + else + { + context.Arm64Assembler.Add(rdOperand, rnOperand, rmOperand, extensionType); + } + } + + private static void EmitExtendAccumulate8(CodeGenContext context, uint rd, uint rn, uint rm, uint rotate, bool unsigned) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + + if (rotate != 0) + { + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + context.Arm64Assembler.Ror(tempRegister.Operand, rmOperand, InstEmitCommon.Const((int)rotate * 8)); + + EmitExtendAccumulate8Core(context, rdOperand, rnOperand, tempRegister.Operand, unsigned); + } + else + { + EmitExtendAccumulate8Core(context, rdOperand, rnOperand, rmOperand, unsigned); + } + } + + private static void EmitExtendAccumulate8Core(CodeGenContext context, Operand rd, Operand rn, Operand rm, bool unsigned) + { + using ScopedRegister tempD = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister tempD2 = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister tempN = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + if (unsigned) + { + context.Arm64Assembler.Uxth(tempN.Operand, rn); + } + else + { + context.Arm64Assembler.Sxth(tempN.Operand, rn); + } + + context.Arm64Assembler.Add(tempD.Operand, tempN.Operand, rm, unsigned ? ArmExtensionType.Uxtb : ArmExtensionType.Sxtb); + context.Arm64Assembler.Uxth(tempD2.Operand, tempD.Operand); + + if (unsigned) + { + context.Arm64Assembler.Lsr(tempN.Operand, rn, InstEmitCommon.Const(16)); + } + else + { + context.Arm64Assembler.Asr(tempN.Operand, rn, InstEmitCommon.Const(16)); + } + + context.Arm64Assembler.Lsr(tempD.Operand, rm, InstEmitCommon.Const(16)); + context.Arm64Assembler.Add(tempD.Operand, tempN.Operand, tempD.Operand, unsigned ? ArmExtensionType.Uxtb : ArmExtensionType.Sxtb); + context.Arm64Assembler.Orr(rd, tempD2.Operand, tempD.Operand, ArmShiftType.Lsl, 16); + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitFlow.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitFlow.cs new file mode 100644 index 000000000..3b1ff5a2a --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitFlow.cs @@ -0,0 +1,256 @@ +using ARMeilleure.Common; +using Ryujinx.Cpu.LightningJit.CodeGen; +using Ryujinx.Cpu.LightningJit.CodeGen.Arm64; +using System; +using System.Diagnostics; +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 +{ + static class InstEmitFlow + { + private const int SpIndex = 31; + + public static void B(CodeGenContext context, int imm, ArmCondition condition) + { + context.AddPendingBranch(InstName.B, imm); + + if (condition == ArmCondition.Al) + { + context.Arm64Assembler.B(0); + } + else + { + context.Arm64Assembler.B(condition, 0); + } + } + + public static void Bl(CodeGenContext context, int imm, bool sourceIsThumb, bool targetIsThumb) + { + uint nextAddress = sourceIsThumb ? context.Pc | 1u : context.Pc - 4; + uint targetAddress = targetIsThumb ? context.Pc + (uint)imm : (context.Pc & ~3u) + (uint)imm; + + if (sourceIsThumb != targetIsThumb) + { + if (targetIsThumb) + { + InstEmitCommon.SetThumbFlag(context); + } + else + { + InstEmitCommon.ClearThumbFlag(context); + } + } + + context.AddPendingCall(targetAddress, nextAddress); + + context.Arm64Assembler.B(0); + } + + public static void Blx(CodeGenContext context, uint rm, bool sourceIsThumb) + { + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + + InstEmitCommon.SetThumbFlag(context, rmOperand); + + uint nextAddress = sourceIsThumb ? (context.Pc - 2) | 1u : context.Pc - 4; + + context.AddPendingIndirectCall(rm, nextAddress); + + context.Arm64Assembler.B(0); + } + + public static void Bx(CodeGenContext context, uint rm) + { + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + + InstEmitCommon.SetThumbFlag(context, rmOperand); + + context.AddPendingIndirectBranch(InstName.Bx, rm); + + context.Arm64Assembler.B(0); + } + + public static void Cbnz(CodeGenContext context, uint rn, int imm, bool op) + { + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + + context.AddPendingBranch(InstName.Cbnz, imm); + + if (op) + { + context.Arm64Assembler.Cbnz(rnOperand, 0); + } + else + { + context.Arm64Assembler.Cbz(rnOperand, 0); + } + } + + public static void It(CodeGenContext context, uint firstCond, uint mask) + { + Debug.Assert(mask != 0); + + int instCount = 4 - BitOperations.TrailingZeroCount(mask); + + Span conditions = stackalloc ArmCondition[instCount]; + + int i = 0; + + for (int index = 5 - instCount; index < 4; index++) + { + bool invert = (mask & (1u << index)) != 0; + + if (invert) + { + conditions[i++] = ((ArmCondition)firstCond).Invert(); + } + else + { + conditions[i++] = (ArmCondition)firstCond; + } + } + + conditions[i] = (ArmCondition)firstCond; + + context.SetItBlockStart(conditions); + } + + public static void Tbb(CodeGenContext context, uint rn, uint rm, bool h) + { + context.Arm64Assembler.Mov(context.RegisterAllocator.RemapGprRegister(RegisterUtils.PcRegister), context.Pc); + + context.AddPendingTableBranch(rn, rm, h); + + context.Arm64Assembler.B(0); + } + + public unsafe static void WriteCallWithGuestAddress( + CodeWriter writer, + ref Assembler asm, + RegisterAllocator regAlloc, + TailMerger tailMerger, + Action writeEpilogue, + AddressTable funcTable, + IntPtr funcPtr, + int spillBaseOffset, + uint nextAddress, + Operand guestAddress, + bool isTail = false) + { + int tempRegister; + + if (guestAddress.Kind == OperandKind.Constant) + { + tempRegister = regAlloc.AllocateTempGprRegister(); + + asm.Mov(Register(tempRegister), guestAddress.Value); + asm.StrRiUn(Register(tempRegister), Register(regAlloc.FixedContextRegister), NativeContextOffsets.DispatchAddressOffset); + + regAlloc.FreeTempGprRegister(tempRegister); + } + else + { + asm.StrRiUn(guestAddress, Register(regAlloc.FixedContextRegister), NativeContextOffsets.DispatchAddressOffset); + } + + tempRegister = regAlloc.FixedContextRegister == 1 ? 2 : 1; + + if (!isTail) + { + WriteSpillSkipContext(ref asm, regAlloc, spillBaseOffset); + } + + Operand rn = Register(tempRegister); + + if (regAlloc.FixedContextRegister != 0) + { + asm.Mov(Register(0), Register(regAlloc.FixedContextRegister)); + } + + if (guestAddress.Kind == OperandKind.Constant && funcTable != null) + { + ulong funcPtrLoc = (ulong)Unsafe.AsPointer(ref funcTable.GetValue(guestAddress.Value)); + + asm.Mov(rn, funcPtrLoc & ~0xfffUL); + asm.LdrRiUn(rn, rn, (int)(funcPtrLoc & 0xfffUL)); + } + else + { + asm.Mov(rn, (ulong)funcPtr); + } + + if (isTail) + { + writeEpilogue(); + asm.Br(rn); + } + else + { + asm.Blr(rn); + + asm.Mov(rn, nextAddress); + asm.Cmp(Register(0), rn); + + tailMerger.AddConditionalReturn(writer, asm, ArmCondition.Ne); + + WriteFillSkipContext(ref asm, regAlloc, spillBaseOffset); + } + } + + public static void WriteSpillSkipContext(ref Assembler asm, RegisterAllocator regAlloc, int spillOffset) + { + WriteSpillOrFillSkipContext(ref asm, regAlloc, spillOffset, spill: true); + } + + public static void WriteFillSkipContext(ref Assembler asm, RegisterAllocator regAlloc, int spillOffset) + { + WriteSpillOrFillSkipContext(ref asm, regAlloc, spillOffset, spill: false); + } + + private static void WriteSpillOrFillSkipContext(ref Assembler asm, RegisterAllocator regAlloc, int spillOffset, bool spill) + { + uint gprMask = regAlloc.UsedGprsMask & ((1u << regAlloc.FixedContextRegister) | (1u << regAlloc.FixedPageTableRegister)); + + while (gprMask != 0) + { + int reg = BitOperations.TrailingZeroCount(gprMask); + + if (reg < 31 && (gprMask & (2u << reg)) != 0 && spillOffset < RegisterSaveRestore.Encodable9BitsOffsetLimit) + { + if (spill) + { + asm.StpRiUn(Register(reg), Register(reg + 1), Register(SpIndex), spillOffset); + } + else + { + asm.LdpRiUn(Register(reg), Register(reg + 1), Register(SpIndex), spillOffset); + } + + gprMask &= ~(3u << reg); + spillOffset += 16; + } + else + { + if (spill) + { + asm.StrRiUn(Register(reg), Register(SpIndex), spillOffset); + } + else + { + asm.LdrRiUn(Register(reg), Register(SpIndex), spillOffset); + } + + gprMask &= ~(1u << reg); + spillOffset += 8; + } + } + } + + private static Operand Register(int register, OperandType type = OperandType.I64) + { + return new Operand(register, RegisterType.Integer, type); + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitGE.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitGE.cs new file mode 100644 index 000000000..dffcc511e --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitGE.cs @@ -0,0 +1,265 @@ +using Ryujinx.Cpu.LightningJit.CodeGen; +using Ryujinx.Cpu.LightningJit.CodeGen.Arm64; + +namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 +{ + static class InstEmitGE + { + public static void Sadd16(CodeGenContext context, uint rd, uint rn, uint rm) + { + EmitAddSub(context, rd, rn, rm, is16Bit: true, add: true, unsigned: false); + } + + public static void Sadd8(CodeGenContext context, uint rd, uint rn, uint rm) + { + EmitAddSub(context, rd, rn, rm, is16Bit: false, add: true, unsigned: false); + } + + public static void Sasx(CodeGenContext context, uint rd, uint rn, uint rm) + { + EmitAsxSax(context, rd, rn, rm, isAsx: true, unsigned: false); + } + + public static void Sel(CodeGenContext context, uint rd, uint rn, uint rm) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + + using ScopedRegister geFlags = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + ExtractGEFlags(context, geFlags.Operand); + + // Broadcast compact GE flags (one bit to one byte, 0b1111 -> 0x1010101). + context.Arm64Assembler.Mov(tempRegister.Operand, 0x204081u); + context.Arm64Assembler.Mul(geFlags.Operand, geFlags.Operand, tempRegister.Operand); + context.Arm64Assembler.And(geFlags.Operand, geFlags.Operand, InstEmitCommon.Const(0x1010101)); + + // Build mask from expanded flags (0x1010101 -> 0xFFFFFFFF). + context.Arm64Assembler.Lsl(tempRegister.Operand, geFlags.Operand, InstEmitCommon.Const(8)); + context.Arm64Assembler.Sub(geFlags.Operand, tempRegister.Operand, geFlags.Operand); + + // Result = (n & mask) | (m & ~mask). + context.Arm64Assembler.And(tempRegister.Operand, geFlags.Operand, rnOperand); + context.Arm64Assembler.Bic(rdOperand, rmOperand, geFlags.Operand); + context.Arm64Assembler.Orr(rdOperand, rdOperand, tempRegister.Operand); + } + + public static void Ssax(CodeGenContext context, uint rd, uint rn, uint rm) + { + EmitAsxSax(context, rd, rn, rm, isAsx: false, unsigned: false); + } + + public static void Ssub16(CodeGenContext context, uint rd, uint rn, uint rm) + { + EmitAddSub(context, rd, rn, rm, is16Bit: true, add: false, unsigned: false); + } + + public static void Ssub8(CodeGenContext context, uint rd, uint rn, uint rm) + { + EmitAddSub(context, rd, rn, rm, is16Bit: false, add: false, unsigned: false); + } + + public static void Uadd16(CodeGenContext context, uint rd, uint rn, uint rm) + { + EmitAddSub(context, rd, rn, rm, is16Bit: true, add: true, unsigned: true); + } + + public static void Uadd8(CodeGenContext context, uint rd, uint rn, uint rm) + { + EmitAddSub(context, rd, rn, rm, is16Bit: false, add: true, unsigned: true); + } + + public static void Uasx(CodeGenContext context, uint rd, uint rn, uint rm) + { + EmitAsxSax(context, rd, rn, rm, isAsx: true, unsigned: true); + } + + public static void Usax(CodeGenContext context, uint rd, uint rn, uint rm) + { + EmitAsxSax(context, rd, rn, rm, isAsx: false, unsigned: true); + } + + public static void Usub16(CodeGenContext context, uint rd, uint rn, uint rm) + { + EmitAddSub(context, rd, rn, rm, is16Bit: true, add: false, unsigned: true); + } + + public static void Usub8(CodeGenContext context, uint rd, uint rn, uint rm) + { + EmitAddSub(context, rd, rn, rm, is16Bit: false, add: false, unsigned: true); + } + + private static void EmitAddSub(CodeGenContext context, uint rd, uint rn, uint rm, bool is16Bit, bool add, bool unsigned) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + + using ScopedRegister geFlags = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + int e = 0; + + void Emit(Operand d, Operand n, Operand m) + { + if (add) + { + context.Arm64Assembler.Add(d, n, m); + } + else + { + context.Arm64Assembler.Sub(d, n, m); + } + + if (unsigned && add) + { + if (e == 0) + { + context.Arm64Assembler.Lsr(geFlags.Operand, d, InstEmitCommon.Const(is16Bit ? 16 : 8)); + } + else + { + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + context.Arm64Assembler.Lsr(tempRegister.Operand, d, InstEmitCommon.Const(is16Bit ? 16 : 8)); + context.Arm64Assembler.Orr(geFlags.Operand, geFlags.Operand, tempRegister.Operand, ArmShiftType.Lsl, e); + } + } + else + { + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + context.Arm64Assembler.Mvn(tempRegister.Operand, d); + + if (e == 0) + { + context.Arm64Assembler.Lsr(geFlags.Operand, tempRegister.Operand, InstEmitCommon.Const(31)); + } + else + { + context.Arm64Assembler.Lsr(tempRegister.Operand, tempRegister.Operand, InstEmitCommon.Const(31)); + context.Arm64Assembler.Orr(geFlags.Operand, geFlags.Operand, tempRegister.Operand, ArmShiftType.Lsl, e); + } + } + + e += is16Bit ? 2 : 1; + } + + if (is16Bit) + { + if (unsigned) + { + InstEmitCommon.EmitUnsigned16BitPair(context, rd, rn, rm, Emit); + } + else + { + InstEmitCommon.EmitSigned16BitPair(context, rd, rn, rm, Emit); + } + + // Duplicate bits. + context.Arm64Assembler.Orr(geFlags.Operand, geFlags.Operand, geFlags.Operand, ArmShiftType.Lsl, 1); + } + else + { + if (unsigned) + { + InstEmitCommon.EmitUnsigned8BitPair(context, rd, rn, rm, Emit); + } + else + { + InstEmitCommon.EmitSigned8BitPair(context, rd, rn, rm, Emit); + } + } + + UpdateGEFlags(context, geFlags.Operand); + } + + private static void EmitAsxSax(CodeGenContext context, uint rd, uint rn, uint rm, bool isAsx, bool unsigned) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + + using ScopedRegister geFlags = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + void Emit(Operand d, Operand n, Operand m, int e) + { + bool add = e == (isAsx ? 1 : 0); + + if (add) + { + context.Arm64Assembler.Add(d, n, m); + } + else + { + context.Arm64Assembler.Sub(d, n, m); + } + + if (unsigned && add) + { + if (e == 0) + { + context.Arm64Assembler.Lsr(geFlags.Operand, d, InstEmitCommon.Const(16)); + } + else + { + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + context.Arm64Assembler.Lsr(tempRegister.Operand, d, InstEmitCommon.Const(16)); + context.Arm64Assembler.Orr(geFlags.Operand, geFlags.Operand, tempRegister.Operand, ArmShiftType.Lsl, e * 2); + } + } + else + { + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + context.Arm64Assembler.Mvn(tempRegister.Operand, d); + + if (e == 0) + { + context.Arm64Assembler.Lsr(geFlags.Operand, tempRegister.Operand, InstEmitCommon.Const(31)); + } + else + { + context.Arm64Assembler.Lsr(tempRegister.Operand, tempRegister.Operand, InstEmitCommon.Const(31)); + context.Arm64Assembler.Orr(geFlags.Operand, geFlags.Operand, tempRegister.Operand, ArmShiftType.Lsl, e * 2); + } + } + } + + if (unsigned) + { + InstEmitCommon.EmitUnsigned16BitXPair(context, rd, rn, rm, Emit); + } + else + { + InstEmitCommon.EmitSigned16BitXPair(context, rd, rn, rm, Emit); + } + + // Duplicate bits. + context.Arm64Assembler.Orr(geFlags.Operand, geFlags.Operand, geFlags.Operand, ArmShiftType.Lsl, 1); + + UpdateGEFlags(context, geFlags.Operand); + } + + public static void UpdateGEFlags(CodeGenContext context, Operand flags) + { + Operand ctx = InstEmitSystem.Register(context.RegisterAllocator.FixedContextRegister); + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + context.Arm64Assembler.LdrRiUn(tempRegister.Operand, ctx, NativeContextOffsets.FlagsBaseOffset); + context.Arm64Assembler.Bfi(tempRegister.Operand, flags, 16, 4); + context.Arm64Assembler.StrRiUn(tempRegister.Operand, ctx, NativeContextOffsets.FlagsBaseOffset); + } + + public static void ExtractGEFlags(CodeGenContext context, Operand flags) + { + Operand ctx = InstEmitSystem.Register(context.RegisterAllocator.FixedContextRegister); + + context.Arm64Assembler.LdrRiUn(flags, ctx, NativeContextOffsets.FlagsBaseOffset); + context.Arm64Assembler.Ubfx(flags, flags, 16, 4); + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitHalve.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitHalve.cs new file mode 100644 index 000000000..567acfbf1 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitHalve.cs @@ -0,0 +1,178 @@ +using Ryujinx.Cpu.LightningJit.CodeGen; + +namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 +{ + static class InstEmitHalve + { + public static void Shadd16(CodeGenContext context, uint rd, uint rn, uint rm) + { + EmitHadd(context, rd, rn, rm, 0x7fff7fff, unsigned: false); + } + + public static void Shadd8(CodeGenContext context, uint rd, uint rn, uint rm) + { + EmitHadd(context, rd, rn, rm, 0x7f7f7f7f, unsigned: false); + } + + public static void Shsub16(CodeGenContext context, uint rd, uint rn, uint rm) + { + EmitHsub(context, rd, rn, rm, 0x7fff7fff, unsigned: false); + } + + public static void Shsub8(CodeGenContext context, uint rd, uint rn, uint rm) + { + EmitHsub(context, rd, rn, rm, 0x7f7f7f7f, unsigned: false); + } + + public static void Shasx(CodeGenContext context, uint rd, uint rn, uint rm) + { + InstEmitCommon.EmitSigned16BitXPair(context, rd, rn, rm, (d, n, m, e) => + { + if (e == 0) + { + context.Arm64Assembler.Sub(d, n, m); + } + else + { + context.Arm64Assembler.Add(d, n, m); + } + + context.Arm64Assembler.Lsr(d, d, InstEmitCommon.Const(1)); + }); + } + + public static void Shsax(CodeGenContext context, uint rd, uint rn, uint rm) + { + InstEmitCommon.EmitSigned16BitXPair(context, rd, rn, rm, (d, n, m, e) => + { + if (e == 0) + { + context.Arm64Assembler.Add(d, n, m); + } + else + { + context.Arm64Assembler.Sub(d, n, m); + } + + context.Arm64Assembler.Lsr(d, d, InstEmitCommon.Const(1)); + }); + } + + public static void Uhadd16(CodeGenContext context, uint rd, uint rn, uint rm) + { + EmitHadd(context, rd, rn, rm, 0x7fff7fff, unsigned: true); + } + + public static void Uhadd8(CodeGenContext context, uint rd, uint rn, uint rm) + { + EmitHadd(context, rd, rn, rm, 0x7f7f7f7f, unsigned: true); + } + + public static void Uhasx(CodeGenContext context, uint rd, uint rn, uint rm) + { + InstEmitCommon.EmitUnsigned16BitXPair(context, rd, rn, rm, (d, n, m, e) => + { + if (e == 0) + { + context.Arm64Assembler.Sub(d, n, m); + } + else + { + context.Arm64Assembler.Add(d, n, m); + } + + context.Arm64Assembler.Lsr(d, d, InstEmitCommon.Const(1)); + }); + } + + public static void Uhsax(CodeGenContext context, uint rd, uint rn, uint rm) + { + InstEmitCommon.EmitUnsigned16BitXPair(context, rd, rn, rm, (d, n, m, e) => + { + if (e == 0) + { + context.Arm64Assembler.Add(d, n, m); + } + else + { + context.Arm64Assembler.Sub(d, n, m); + } + + context.Arm64Assembler.Lsr(d, d, InstEmitCommon.Const(1)); + }); + } + + public static void Uhsub16(CodeGenContext context, uint rd, uint rn, uint rm) + { + EmitHsub(context, rd, rn, rm, 0x7fff7fff, unsigned: true); + } + + public static void Uhsub8(CodeGenContext context, uint rd, uint rn, uint rm) + { + EmitHsub(context, rd, rn, rm, 0x7f7f7f7f, unsigned: true); + } + + private static void EmitHadd(CodeGenContext context, uint rd, uint rn, uint rm, int mask, bool unsigned) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + + using ScopedRegister res = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister carry = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + // This relies on the equality x+y == ((x&y) << 1) + (x^y). + // Note that x^y always contains the LSB of the result. + // Since we want to calculate (x+y)/2, we can instead calculate (x&y) + ((x^y)>>1). + // We mask by 0x7F/0x7FFF to remove the LSB so that it doesn't leak into the field below. + + context.Arm64Assembler.And(res.Operand, rmOperand, rnOperand); + context.Arm64Assembler.Eor(carry.Operand, rmOperand, rnOperand); + context.Arm64Assembler.Lsr(rdOperand, carry.Operand, InstEmitCommon.Const(1)); + context.Arm64Assembler.And(rdOperand, rdOperand, InstEmitCommon.Const(mask)); + context.Arm64Assembler.Add(rdOperand, rdOperand, res.Operand); + + if (!unsigned) + { + // Propagates the sign bit from (x^y)>>1 upwards by one. + context.Arm64Assembler.And(carry.Operand, carry.Operand, InstEmitCommon.Const(~mask)); + context.Arm64Assembler.Eor(rdOperand, rdOperand, carry.Operand); + } + } + + private static void EmitHsub(CodeGenContext context, uint rd, uint rn, uint rm, int mask, bool unsigned) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + + using ScopedRegister carry = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister left = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister right = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + // This relies on the equality x-y == (x^y) - (((x^y)&y) << 1). + // Note that x^y always contains the LSB of the result. + // Since we want to calculate (x+y)/2, we can instead calculate ((x^y)>>1) - ((x^y)&y). + + context.Arm64Assembler.Eor(carry.Operand, rmOperand, rnOperand); + context.Arm64Assembler.Lsr(left.Operand, carry.Operand, InstEmitCommon.Const(1)); + context.Arm64Assembler.And(right.Operand, carry.Operand, rmOperand); + + // We must now perform a partitioned subtraction. + // We can do this because minuend contains 7/15 bit fields. + // We use the extra bit in minuend as a bit to borrow from; we set this bit. + // We invert this bit at the end as this tells us if that bit was borrowed from. + + context.Arm64Assembler.Orr(rdOperand, left.Operand, InstEmitCommon.Const(~mask)); + context.Arm64Assembler.Sub(rdOperand, rdOperand, right.Operand); + context.Arm64Assembler.Eor(rdOperand, rdOperand, InstEmitCommon.Const(~mask)); + + if (!unsigned) + { + // We then sign extend the result into this bit. + context.Arm64Assembler.And(carry.Operand, carry.Operand, InstEmitCommon.Const(~mask)); + context.Arm64Assembler.Eor(rdOperand, rdOperand, carry.Operand); + } + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitMemory.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitMemory.cs new file mode 100644 index 000000000..6ab4b9495 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitMemory.cs @@ -0,0 +1,1172 @@ +using ARMeilleure.Memory; +using Ryujinx.Cpu.LightningJit.CodeGen; +using Ryujinx.Cpu.LightningJit.CodeGen.Arm64; +using System; +using System.Diagnostics; +using System.Numerics; + +namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 +{ + static class InstEmitMemory + { + private enum PrefetchType : uint + { + Pld = 0, + Pli = 1, + Pst = 2, + } + + public static void Lda(CodeGenContext context, uint rt, uint rn) + { + EmitMemoryInstruction(context, rt, rn, isStore: false, context.Arm64Assembler.Ldar); + } + + public static void Ldab(CodeGenContext context, uint rt, uint rn) + { + EmitMemoryInstruction(context, rt, rn, isStore: false, context.Arm64Assembler.Ldarb); + } + + public static void Ldaex(CodeGenContext context, uint rt, uint rn) + { + EmitMemoryInstruction(context, rt, rn, isStore: false, context.Arm64Assembler.Ldaxr); + } + + public static void Ldaexb(CodeGenContext context, uint rt, uint rn) + { + EmitMemoryInstruction(context, rt, rn, isStore: false, context.Arm64Assembler.Ldaxrb); + } + + public static void Ldaexd(CodeGenContext context, uint rt, uint rt2, uint rn) + { + EmitMemoryDWordInstruction(context, rt, rt2, rn, isStore: false, context.Arm64Assembler.Ldaxp); + } + + public static void Ldaexh(CodeGenContext context, uint rt, uint rn) + { + EmitMemoryInstruction(context, rt, rn, isStore: false, context.Arm64Assembler.Ldaxrh); + } + + public static void Ldah(CodeGenContext context, uint rt, uint rn) + { + EmitMemoryInstruction(context, rt, rn, isStore: false, context.Arm64Assembler.Ldarh); + } + + public static void LdcI(CodeGenContext context, uint rn, int imm, bool p, bool u, bool w) + { + // TODO. + } + + public static void LdcL(CodeGenContext context, uint imm, bool p, bool u, bool w) + { + // TODO. + } + + public static void Ldm(CodeGenContext context, uint rn, uint registerList, bool w) + { + Operand baseAddress = InstEmitCommon.GetInputGpr(context, rn); + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, context.Arm64Assembler, tempRegister.Operand, baseAddress); + + EmitMemoryMultipleInstructionCore( + context, + tempRegister.Operand, + registerList, + isStore: false, + context.Arm64Assembler.LdrRiUn, + context.Arm64Assembler.LdpRiUn); + + if (w) + { + Operand offset = InstEmitCommon.Const(BitOperations.PopCount(registerList) * 4); + + WriteAddShiftOffset(context.Arm64Assembler, baseAddress, baseAddress, offset, true, ArmShiftType.Lsl, 0); + } + } + + public static void Ldmda(CodeGenContext context, uint rn, uint registerList, bool w) + { + EmitMemoryMultipleDaInstruction(context, rn, registerList, w, isStore: false, context.Arm64Assembler.LdrRiUn, context.Arm64Assembler.LdpRiUn); + } + + public static void Ldmdb(CodeGenContext context, uint rn, uint registerList, bool w) + { + EmitMemoryMultipleDbInstruction(context, rn, registerList, w, isStore: false, context.Arm64Assembler.LdrRiUn, context.Arm64Assembler.LdpRiUn); + } + + public static void Ldmib(CodeGenContext context, uint rn, uint registerList, bool w) + { + EmitMemoryMultipleIbInstruction(context, rn, registerList, w, isStore: false, context.Arm64Assembler.LdrRiUn, context.Arm64Assembler.LdpRiUn); + } + + public static void LdrI(CodeGenContext context, uint rt, uint rn, int imm, bool p, bool u, bool w) + { + EmitMemoryInstruction(context, rt, rn, imm, 2, p, u, w, isStore: false, context.Arm64Assembler.LdrRiUn, context.Arm64Assembler.Ldur); + } + + public static void LdrL(CodeGenContext context, uint rt, uint imm, bool p, bool u, bool w) + { + EmitMemoryLiteralInstruction(context, rt, imm, 2, p, u, w, context.Arm64Assembler.LdrRiUn); + } + + public static void LdrR(CodeGenContext context, uint rt, uint rn, uint rm, uint sType, uint imm5, bool p, bool u, bool w) + { + EmitMemoryInstruction(context, rt, rn, rm, sType, imm5, p, u, w, isStore: false, context.Arm64Assembler.LdrRiUn, context.Arm64Assembler.Ldur); + } + + public static void LdrbI(CodeGenContext context, uint rt, uint rn, int imm, bool p, bool u, bool w) + { + EmitMemoryInstruction(context, rt, rn, imm, 0, p, u, w, isStore: false, context.Arm64Assembler.LdrbRiUn, context.Arm64Assembler.Ldurb); + } + + public static void LdrbL(CodeGenContext context, uint rt, uint imm, bool p, bool u, bool w) + { + EmitMemoryLiteralInstruction(context, rt, imm, 0, p, u, w, context.Arm64Assembler.LdrbRiUn); + } + + public static void LdrbR(CodeGenContext context, uint rt, uint rn, uint rm, uint sType, uint imm5, bool p, bool u, bool w) + { + EmitMemoryInstruction(context, rt, rn, rm, sType, imm5, p, u, w, isStore: false, context.Arm64Assembler.LdrbRiUn, context.Arm64Assembler.Ldurb); + } + + public static void LdrbtI(CodeGenContext context, uint rt, uint rn, int imm, bool postIndex, bool u) + { + EmitMemoryInstruction(context, rt, rn, imm, 0, !postIndex, u, false, isStore: false, context.Arm64Assembler.LdrbRiUn, context.Arm64Assembler.Ldurb); + } + + public static void LdrbtR(CodeGenContext context, uint rt, uint rn, uint rm, uint sType, uint imm5, bool postIndex, bool u) + { + EmitMemoryInstruction(context, rt, rn, rm, sType, imm5, !postIndex, u, false, isStore: false, context.Arm64Assembler.LdrbRiUn, context.Arm64Assembler.Ldurb); + } + + public static void LdrdI(CodeGenContext context, uint rt, uint rt2, uint rn, uint imm, bool p, bool u, bool w) + { + EmitMemoryDWordInstructionI(context, rt, rt2, rn, imm, p, u, w, isStore: false, context.Arm64Assembler.LdpRiUn); + } + + public static void LdrdL(CodeGenContext context, uint rt, uint rt2, uint imm, bool p, bool u, bool w) + { + EmitMemoryDWordLiteralInstruction(context, rt, rt2, imm, p, u, w, context.Arm64Assembler.LdpRiUn); + } + + public static void LdrdR(CodeGenContext context, uint rt, uint rt2, uint rn, uint rm, bool p, bool u, bool w) + { + EmitMemoryDWordInstructionR(context, rt, rt2, rn, rm, p, u, w, isStore: false, context.Arm64Assembler.LdpRiUn); + } + + public static void Ldrex(CodeGenContext context, uint rt, uint rn) + { + EmitMemoryInstruction(context, rt, rn, isStore: false, context.Arm64Assembler.Ldaxr); + } + + public static void Ldrexb(CodeGenContext context, uint rt, uint rn) + { + EmitMemoryInstruction(context, rt, rn, isStore: false, context.Arm64Assembler.Ldaxrb); + } + + public static void Ldrexd(CodeGenContext context, uint rt, uint rt2, uint rn) + { + EmitMemoryDWordInstruction(context, rt, rt2, rn, isStore: false, context.Arm64Assembler.Ldaxp); + } + + public static void Ldrexh(CodeGenContext context, uint rt, uint rn) + { + EmitMemoryInstruction(context, rt, rn, isStore: false, context.Arm64Assembler.Ldaxrh); + } + + public static void LdrhI(CodeGenContext context, uint rt, uint rn, int imm, bool p, bool u, bool w) + { + EmitMemoryInstruction(context, rt, rn, imm, 1, p, u, w, isStore: false, context.Arm64Assembler.LdrhRiUn, context.Arm64Assembler.Ldurh); + } + + public static void LdrhL(CodeGenContext context, uint rt, uint imm, bool p, bool u, bool w) + { + EmitMemoryLiteralInstruction(context, rt, imm, 1, p, u, w, context.Arm64Assembler.LdrhRiUn); + } + + public static void LdrhR(CodeGenContext context, uint rt, uint rn, uint rm, uint sType, uint imm5, bool p, bool u, bool w) + { + EmitMemoryInstruction(context, rt, rn, rm, sType, imm5, p, u, w, isStore: false, context.Arm64Assembler.LdrhRiUn, context.Arm64Assembler.Ldurh); + } + + public static void LdrhtI(CodeGenContext context, uint rt, uint rn, int imm, bool postIndex, bool u) + { + EmitMemoryInstruction(context, rt, rn, imm, 1, !postIndex, u, false, isStore: false, context.Arm64Assembler.LdrhRiUn, context.Arm64Assembler.Ldurh); + } + + public static void LdrhtR(CodeGenContext context, uint rt, uint rn, uint rm, bool postIndex, bool u) + { + EmitMemoryInstruction(context, rt, rn, rm, 0, 0, !postIndex, u, false, isStore: false, context.Arm64Assembler.LdrhRiUn, context.Arm64Assembler.Ldurh); + } + + public static void LdrsbI(CodeGenContext context, uint rt, uint rn, int imm, bool p, bool u, bool w) + { + EmitMemoryInstruction(context, rt, rn, imm, 0, p, u, w, isStore: false, context.Arm64Assembler.LdrsbRiUn, context.Arm64Assembler.Ldursb); + } + + public static void LdrsbL(CodeGenContext context, uint rt, uint imm, bool p, bool u, bool w) + { + EmitMemoryLiteralInstruction(context, rt, imm, 0, p, u, w, context.Arm64Assembler.LdrsbRiUn); + } + + public static void LdrsbR(CodeGenContext context, uint rt, uint rn, uint rm, uint sType, uint imm5, bool p, bool u, bool w) + { + EmitMemoryInstruction(context, rt, rn, rm, sType, imm5, p, u, w, isStore: false, context.Arm64Assembler.LdrsbRiUn, context.Arm64Assembler.Ldursb); + } + + public static void LdrsbtI(CodeGenContext context, uint rt, uint rn, int imm, bool postIndex, bool u) + { + EmitMemoryInstruction(context, rt, rn, imm, 0, !postIndex, u, false, isStore: false, context.Arm64Assembler.LdrsbRiUn, context.Arm64Assembler.Ldursb); + } + + public static void LdrsbtR(CodeGenContext context, uint rt, uint rn, uint rm, bool postIndex, bool u) + { + EmitMemoryInstruction(context, rt, rn, rm, 0, 0, !postIndex, u, false, isStore: false, context.Arm64Assembler.LdrsbRiUn, context.Arm64Assembler.Ldursb); + } + + public static void LdrshI(CodeGenContext context, uint rt, uint rn, int imm, bool p, bool u, bool w) + { + EmitMemoryInstruction(context, rt, rn, imm, 1, p, u, w, isStore: false, context.Arm64Assembler.LdrshRiUn, context.Arm64Assembler.Ldursh); + } + + public static void LdrshL(CodeGenContext context, uint rt, uint imm, bool p, bool u, bool w) + { + EmitMemoryLiteralInstruction(context, rt, imm, 1, p, u, w, context.Arm64Assembler.LdrshRiUn); + } + + public static void LdrshR(CodeGenContext context, uint rt, uint rn, uint rm, uint sType, uint imm5, bool p, bool u, bool w) + { + EmitMemoryInstruction(context, rt, rn, rm, sType, imm5, p, u, w, isStore: false, context.Arm64Assembler.LdrshRiUn, context.Arm64Assembler.Ldursh); + } + + public static void LdrshtI(CodeGenContext context, uint rt, uint rn, int imm, bool postIndex, bool u) + { + EmitMemoryInstruction(context, rt, rn, imm, 1, !postIndex, u, false, isStore: false, context.Arm64Assembler.LdrshRiUn, context.Arm64Assembler.Ldursh); + } + + public static void LdrshtR(CodeGenContext context, uint rt, uint rn, uint rm, bool postIndex, bool u) + { + EmitMemoryInstruction(context, rt, rn, rm, 0, 0, !postIndex, u, false, isStore: false, context.Arm64Assembler.LdrshRiUn, context.Arm64Assembler.Ldursh); + } + + public static void LdrtI(CodeGenContext context, uint rt, uint rn, int imm, bool postIndex, bool u) + { + EmitMemoryInstruction(context, rt, rn, imm, 2, !postIndex, u, false, isStore: false, context.Arm64Assembler.LdrRiUn, context.Arm64Assembler.Ldur); + } + + public static void LdrtR(CodeGenContext context, uint rt, uint rn, uint rm, uint sType, uint imm5, bool postIndex, bool u) + { + EmitMemoryInstruction(context, rt, rn, rm, sType, imm5, !postIndex, u, false, isStore: false, context.Arm64Assembler.LdrRiUn, context.Arm64Assembler.Ldur); + } + + public static void PldI(CodeGenContext context, uint rn, uint imm, bool u, bool r) + { + EmitMemoryPrefetchInstruction(context, rn, imm, u, r ? PrefetchType.Pld : PrefetchType.Pst); + } + + public static void PldL(CodeGenContext context, uint imm, bool u) + { + EmitMemoryPrefetchLiteralInstruction(context, imm, u, PrefetchType.Pld); + } + + public static void PldR(CodeGenContext context, uint rn, uint rm, uint sType, uint imm5, bool u, bool r) + { + EmitMemoryPrefetchInstruction(context, rn, rm, u, sType, imm5, r ? PrefetchType.Pld : PrefetchType.Pst); + } + + public static void PliI(CodeGenContext context, uint rn, uint imm, bool u) + { + EmitMemoryPrefetchInstruction(context, rn, imm, u, PrefetchType.Pli); + } + + public static void PliL(CodeGenContext context, uint imm, bool u) + { + EmitMemoryPrefetchLiteralInstruction(context, imm, u, PrefetchType.Pli); + } + + public static void PliR(CodeGenContext context, uint rn, uint rm, uint sType, uint imm5, bool u) + { + EmitMemoryPrefetchInstruction(context, rn, rm, u, sType, imm5, PrefetchType.Pli); + } + + public static void Stc(CodeGenContext context, uint rn, int imm, bool p, bool u, bool w) + { + // TODO. + } + + public static void Stl(CodeGenContext context, uint rt, uint rn) + { + EmitMemoryInstruction(context, rt, rn, isStore: true, context.Arm64Assembler.Stlr); + } + + public static void Stlb(CodeGenContext context, uint rt, uint rn) + { + EmitMemoryInstruction(context, rt, rn, isStore: true, context.Arm64Assembler.Stlrb); + } + + public static void Stlex(CodeGenContext context, uint rd, uint rt, uint rn) + { + EmitMemoryStrexInstruction(context, rd, rt, rn, context.Arm64Assembler.Stlxr); + } + + public static void Stlexb(CodeGenContext context, uint rd, uint rt, uint rn) + { + EmitMemoryStrexInstruction(context, rd, rt, rn, context.Arm64Assembler.Stlxrb); + } + + public static void Stlexd(CodeGenContext context, uint rd, uint rt, uint rt2, uint rn) + { + EmitMemoryDWordStrexInstruction(context, rd, rt, rt2, rn, context.Arm64Assembler.Stlxp); + } + + public static void Stlexh(CodeGenContext context, uint rd, uint rt, uint rn) + { + EmitMemoryStrexInstruction(context, rd, rt, rn, context.Arm64Assembler.Stlxrh); + } + + public static void Stlh(CodeGenContext context, uint rt, uint rn) + { + EmitMemoryInstruction(context, rt, rn, isStore: true, context.Arm64Assembler.Stlrh); + } + + public static void Stm(CodeGenContext context, uint rn, uint registerList, bool w) + { + Operand baseAddress = InstEmitCommon.GetInputGpr(context, rn); + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, context.Arm64Assembler, tempRegister.Operand, baseAddress); + + EmitMemoryMultipleInstructionCore( + context, + tempRegister.Operand, + registerList, + isStore: true, + context.Arm64Assembler.StrRiUn, + context.Arm64Assembler.StpRiUn); + + if (w) + { + Operand offset = InstEmitCommon.Const(BitOperations.PopCount(registerList) * 4); + + WriteAddShiftOffset(context.Arm64Assembler, baseAddress, baseAddress, offset, true, ArmShiftType.Lsl, 0); + } + } + + public static void Stmda(CodeGenContext context, uint rn, uint registerList, bool w) + { + EmitMemoryMultipleDaInstruction(context, rn, registerList, w, isStore: true, context.Arm64Assembler.StrRiUn, context.Arm64Assembler.StpRiUn); + } + + public static void Stmdb(CodeGenContext context, uint rn, uint registerList, bool w) + { + EmitMemoryMultipleDbInstruction(context, rn, registerList, w, isStore: true, context.Arm64Assembler.StrRiUn, context.Arm64Assembler.StpRiUn); + } + + public static void Stmib(CodeGenContext context, uint rn, uint registerList, bool w) + { + EmitMemoryMultipleIbInstruction(context, rn, registerList, w, isStore: true, context.Arm64Assembler.StrRiUn, context.Arm64Assembler.StpRiUn); + } + + public static void StrI(CodeGenContext context, uint rt, uint rn, int imm, bool p, bool u, bool w) + { + EmitMemoryInstruction(context, rt, rn, imm, 2, p, u, w, isStore: true, context.Arm64Assembler.StrRiUn, context.Arm64Assembler.Stur); + } + + public static void StrR(CodeGenContext context, uint rt, uint rn, uint rm, uint sType, uint imm5, bool p, bool u, bool w) + { + EmitMemoryInstruction(context, rt, rn, rm, sType, imm5, p, u, w, isStore: true, context.Arm64Assembler.StrRiUn, context.Arm64Assembler.Stur); + } + + public static void StrbI(CodeGenContext context, uint rt, uint rn, int imm, bool p, bool u, bool w) + { + EmitMemoryInstruction(context, rt, rn, imm, 0, p, u, w, isStore: true, context.Arm64Assembler.StrbRiUn, context.Arm64Assembler.Sturb); + } + + public static void StrbR(CodeGenContext context, uint rt, uint rn, uint rm, uint sType, uint imm5, bool p, bool u, bool w) + { + EmitMemoryInstruction(context, rt, rn, rm, sType, imm5, p, u, w, isStore: true, context.Arm64Assembler.StrbRiUn, context.Arm64Assembler.Sturb); + } + + public static void StrbtI(CodeGenContext context, uint rt, uint rn, int imm, bool postIndex, bool u) + { + EmitMemoryInstruction(context, rt, rn, imm, 0, !postIndex, u, false, isStore: true, context.Arm64Assembler.StrbRiUn, context.Arm64Assembler.Sturb); + } + + public static void StrbtR(CodeGenContext context, uint rt, uint rn, uint rm, uint sType, uint imm5, bool postIndex, bool u) + { + EmitMemoryInstruction(context, rt, rn, rm, sType, imm5, !postIndex, u, false, isStore: true, context.Arm64Assembler.StrbRiUn, context.Arm64Assembler.Sturb); + } + + public static void StrdI(CodeGenContext context, uint rt, uint rt2, uint rn, uint imm, bool p, bool u, bool w) + { + EmitMemoryDWordInstructionI(context, rt, rt2, rn, imm, p, u, w, isStore: true, context.Arm64Assembler.StpRiUn); + } + + public static void StrdR(CodeGenContext context, uint rt, uint rt2, uint rn, uint rm, bool p, bool u, bool w) + { + EmitMemoryDWordInstructionR(context, rt, rt2, rn, rm, p, u, w, isStore: true, context.Arm64Assembler.StpRiUn); + } + + public static void Strex(CodeGenContext context, uint rd, uint rt, uint rn) + { + EmitMemoryStrexInstruction(context, rd, rt, rn, context.Arm64Assembler.Stlxr); + } + + public static void Strexb(CodeGenContext context, uint rd, uint rt, uint rn) + { + EmitMemoryStrexInstruction(context, rd, rt, rn, context.Arm64Assembler.Stlxrb); + } + + public static void Strexd(CodeGenContext context, uint rd, uint rt, uint rt2, uint rn) + { + EmitMemoryDWordStrexInstruction(context, rd, rt, rt2, rn, context.Arm64Assembler.Stlxp); + } + + public static void Strexh(CodeGenContext context, uint rd, uint rt, uint rn) + { + EmitMemoryStrexInstruction(context, rd, rt, rn, context.Arm64Assembler.Stlxrh); + } + + public static void StrhI(CodeGenContext context, uint rt, uint rn, int imm, bool p, bool u, bool w) + { + EmitMemoryInstruction(context, rt, rn, imm, 1, p, u, w, isStore: true, context.Arm64Assembler.StrhRiUn, context.Arm64Assembler.Sturh); + } + + public static void StrhR(CodeGenContext context, uint rt, uint rn, uint rm, uint sType, uint imm5, bool p, bool u, bool w) + { + EmitMemoryInstruction(context, rt, rn, rm, sType, imm5, p, u, w, isStore: true, context.Arm64Assembler.StrhRiUn, context.Arm64Assembler.Sturh); + } + + public static void StrhtI(CodeGenContext context, uint rt, uint rn, int imm, bool postIndex, bool u) + { + EmitMemoryInstruction(context, rt, rn, imm, 1, !postIndex, u, false, isStore: true, context.Arm64Assembler.StrhRiUn, context.Arm64Assembler.Sturh); + } + + public static void StrhtR(CodeGenContext context, uint rt, uint rn, uint rm, bool postIndex, bool u) + { + EmitMemoryInstruction(context, rt, rn, rm, 0, 0, !postIndex, u, false, isStore: true, context.Arm64Assembler.StrhRiUn, context.Arm64Assembler.Sturh); + } + + public static void StrtI(CodeGenContext context, uint rt, uint rn, int imm, bool postIndex, bool u) + { + EmitMemoryInstruction(context, rt, rn, imm, 2, !postIndex, u, false, isStore: true, context.Arm64Assembler.StrRiUn, context.Arm64Assembler.Stur); + } + + public static void StrtR(CodeGenContext context, uint rt, uint rn, uint rm, uint sType, uint imm5, bool postIndex, bool u) + { + EmitMemoryInstruction(context, rt, rn, rm, sType, imm5, !postIndex, u, false, isStore: true, context.Arm64Assembler.StrRiUn, context.Arm64Assembler.Stur); + } + + private static void EmitMemoryMultipleDaInstruction( + CodeGenContext context, + uint rn, + uint registerList, + bool w, + bool isStore, + Action writeInst, + Action writeInstPair) + { + Operand baseAddress = InstEmitCommon.GetInputGpr(context, rn); + Operand offset; + + if (registerList != 0) + { + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + offset = InstEmitCommon.Const(BitOperations.PopCount(registerList) * 4 - 4); + + WriteAddShiftOffset(context.Arm64Assembler, tempRegister.Operand, baseAddress, offset, false, ArmShiftType.Lsl, 0); + WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, context.Arm64Assembler, tempRegister.Operand, tempRegister.Operand); + + EmitMemoryMultipleInstructionCore( + context, + tempRegister.Operand, + registerList, + isStore, + writeInst, + writeInstPair); + } + + if (w) + { + offset = InstEmitCommon.Const(BitOperations.PopCount(registerList) * 4); + + WriteAddShiftOffset(context.Arm64Assembler, baseAddress, baseAddress, offset, false, ArmShiftType.Lsl, 0); + } + } + + private static void EmitMemoryMultipleDbInstruction( + CodeGenContext context, + uint rn, + uint registerList, + bool w, + bool isStore, + Action writeInst, + Action writeInstPair) + { + Operand baseAddress = InstEmitCommon.GetInputGpr(context, rn); + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + Operand offset = InstEmitCommon.Const(BitOperations.PopCount(registerList) * 4); + + bool writesToRn = (registerList & (1u << (int)rn)) != 0; + + if (w && !writesToRn) + { + WriteAddShiftOffset(context.Arm64Assembler, baseAddress, baseAddress, offset, false, ArmShiftType.Lsl, 0); + WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, context.Arm64Assembler, tempRegister.Operand, baseAddress); + } + else + { + WriteAddShiftOffset(context.Arm64Assembler, tempRegister.Operand, baseAddress, offset, false, ArmShiftType.Lsl, 0); + WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, context.Arm64Assembler, tempRegister.Operand, tempRegister.Operand); + } + + EmitMemoryMultipleInstructionCore( + context, + tempRegister.Operand, + registerList, + isStore, + writeInst, + writeInstPair); + + if (w && writesToRn) + { + WriteAddShiftOffset(context.Arm64Assembler, baseAddress, baseAddress, offset, false, ArmShiftType.Lsl, 0); + } + } + + private static void EmitMemoryMultipleIbInstruction( + CodeGenContext context, + uint rn, + uint registerList, + bool w, + bool isStore, + Action writeInst, + Action writeInstPair) + { + Operand baseAddress = InstEmitCommon.GetInputGpr(context, rn); + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + Operand offset = InstEmitCommon.Const(4); + + WriteAddShiftOffset(context.Arm64Assembler, tempRegister.Operand, baseAddress, offset, true, ArmShiftType.Lsl, 0); + WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, context.Arm64Assembler, tempRegister.Operand, tempRegister.Operand); + + EmitMemoryMultipleInstructionCore( + context, + tempRegister.Operand, + registerList, + isStore, + writeInst, + writeInstPair); + + if (w) + { + offset = InstEmitCommon.Const(BitOperations.PopCount(registerList) * 4); + + WriteAddShiftOffset(context.Arm64Assembler, baseAddress, baseAddress, offset, true, ArmShiftType.Lsl, 0); + } + } + + private static void EmitMemoryMultipleInstructionCore( + CodeGenContext context, + Operand baseAddress, + uint registerList, + bool isStore, + Action writeInst, + Action writeInstPair) + { + uint registers = registerList; + int offs = 0; + + while (registers != 0) + { + int regIndex = BitOperations.TrailingZeroCount(registers); + + registers &= ~(1u << regIndex); + + Operand rt = isStore + ? InstEmitCommon.GetInputGpr(context, (uint)regIndex) + : InstEmitCommon.GetOutputGpr(context, (uint)regIndex); + + int regIndex2 = BitOperations.TrailingZeroCount(registers); + if (regIndex2 < 32) + { + registers &= ~(1u << regIndex2); + + Operand rt2 = isStore + ? InstEmitCommon.GetInputGpr(context, (uint)regIndex2) + : InstEmitCommon.GetOutputGpr(context, (uint)regIndex2); + + writeInstPair(rt, rt2, baseAddress, offs); + + offs += 8; + } + else + { + writeInst(rt, baseAddress, offs); + + offs += 4; + } + } + } + + private static void EmitMemoryInstruction( + CodeGenContext context, + uint rt, + uint rn, + int imm, + int scale, + bool p, + bool u, + bool w, + bool isStore, + Action writeInst, + Action writeInstUnscaled) + { + Operand rtOperand = isStore ? InstEmitCommon.GetInputGpr(context, rt) : InstEmitCommon.GetOutputGpr(context, rt); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + Operand offset = InstEmitCommon.Const(imm); + + EmitMemoryInstruction(context, writeInst, writeInstUnscaled, rtOperand, rnOperand, offset, scale, p, u, w); + } + + private static void EmitMemoryInstruction( + CodeGenContext context, + uint rt, + uint rn, + uint rm, + uint sType, + uint imm5, + bool p, + bool u, + bool w, + bool isStore, + Action writeInst, + Action writeInstUnscaled) + { + Operand rtOperand = isStore ? InstEmitCommon.GetInputGpr(context, rt) : InstEmitCommon.GetOutputGpr(context, rt); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + + EmitMemoryInstruction(context, writeInst, writeInstUnscaled, rtOperand, rnOperand, rmOperand, 0, p, u, w, (ArmShiftType)sType, (int)imm5); + } + + private static void EmitMemoryInstruction(CodeGenContext context, uint rt, uint rn, bool isStore, Action action) + { + Operand rtOperand = isStore ? InstEmitCommon.GetInputGpr(context, rt) : InstEmitCommon.GetOutputGpr(context, rt); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, context.Arm64Assembler, tempRegister.Operand, rnOperand); + + action(rtOperand, tempRegister.Operand); + } + + private static void EmitMemoryDWordInstruction(CodeGenContext context, uint rt, uint rt2, uint rn, bool isStore, Action action) + { + Operand rtOperand = isStore ? InstEmitCommon.GetInputGpr(context, rt) : InstEmitCommon.GetOutputGpr(context, rt); + Operand rt2Operand = isStore ? InstEmitCommon.GetInputGpr(context, rt2) : InstEmitCommon.GetOutputGpr(context, rt2); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, context.Arm64Assembler, tempRegister.Operand, rnOperand); + + action(rtOperand, rt2Operand, tempRegister.Operand); + } + + private static void EmitMemoryDWordInstructionI( + CodeGenContext context, + uint rt, + uint rt2, + uint rn, + uint imm, + bool p, + bool u, + bool w, + bool isStore, + Action action) + { + Operand rtOperand = isStore ? InstEmitCommon.GetInputGpr(context, rt) : InstEmitCommon.GetOutputGpr(context, rt); + Operand rt2Operand = isStore ? InstEmitCommon.GetInputGpr(context, rt2) : InstEmitCommon.GetOutputGpr(context, rt2); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + Operand offset = InstEmitCommon.Const((int)imm); + + EmitMemoryDWordInstruction(context, rtOperand, rt2Operand, rnOperand, offset, p, u, w, action); + } + + private static void EmitMemoryDWordInstructionR( + CodeGenContext context, + uint rt, + uint rt2, + uint rn, + uint rm, + bool p, + bool u, + bool w, + bool isStore, + Action action) + { + Operand rtOperand = isStore ? InstEmitCommon.GetInputGpr(context, rt) : InstEmitCommon.GetOutputGpr(context, rt); + Operand rt2Operand = isStore ? InstEmitCommon.GetInputGpr(context, rt2) : InstEmitCommon.GetOutputGpr(context, rt2); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + + EmitMemoryDWordInstruction(context, rtOperand, rt2Operand, rnOperand, rmOperand, p, u, w, action); + } + + private static void EmitMemoryDWordInstruction( + CodeGenContext context, + Operand rt, + Operand rt2, + Operand baseAddress, + Operand offset, + bool index, + bool add, + bool wBack, + Action action) + { + Assembler asm = context.Arm64Assembler; + RegisterAllocator regAlloc = context.RegisterAllocator; + + if (index && !wBack) + { + // Offset. + + using ScopedRegister tempRegister = regAlloc.AllocateTempGprRegisterScoped(); + + int signedOffs = add ? offset.AsInt32() : -offset.AsInt32(); + int offs = 0; + + if (offset.Kind == OperandKind.Constant && offset.Value == 0) + { + WriteAddressTranslation(context.MemoryManagerType, regAlloc, asm, tempRegister.Operand, baseAddress); + } + else if (offset.Kind == OperandKind.Constant && CanFoldDWordOffset(context.MemoryManagerType, signedOffs)) + { + WriteAddressTranslation(context.MemoryManagerType, regAlloc, asm, tempRegister.Operand, baseAddress); + offs = signedOffs; + } + else + { + WriteAddShiftOffset(asm, tempRegister.Operand, baseAddress, offset, add, ArmShiftType.Lsl, 0); + WriteAddressTranslation(context.MemoryManagerType, regAlloc, asm, tempRegister.Operand, tempRegister.Operand); + } + + action(rt, rt2, tempRegister.Operand, offs); + } + else if (context.IsThumb ? !index && wBack : !index && !wBack) + { + // Post-indexed. + + using ScopedRegister tempRegister = regAlloc.AllocateTempGprRegisterScoped(); + + WriteAddressTranslation(context.MemoryManagerType, regAlloc, asm, tempRegister.Operand, baseAddress); + + action(rt, rt2, tempRegister.Operand, 0); + + WriteAddShiftOffset(asm, baseAddress, baseAddress, offset, add, ArmShiftType.Lsl, 0); + } + else if (index && wBack) + { + // Pre-indexed. + + using ScopedRegister tempRegister = regAlloc.AllocateTempGprRegisterScoped(); + + if (rt.Value == baseAddress.Value) + { + // If Rt and Rn are the same register, ensure we perform the write back after the read/write. + + WriteAddShiftOffset(asm, tempRegister.Operand, baseAddress, offset, add, ArmShiftType.Lsl, 0); + WriteAddressTranslation(context.MemoryManagerType, regAlloc, asm, tempRegister.Operand, tempRegister.Operand); + + action(rt, rt2, tempRegister.Operand, 0); + + context.Arm64Assembler.Mov(baseAddress, tempRegister.Operand); + } + else + { + WriteAddShiftOffset(asm, baseAddress, baseAddress, offset, add, ArmShiftType.Lsl, 0); + WriteAddressTranslation(context.MemoryManagerType, regAlloc, asm, tempRegister.Operand, baseAddress); + + action(rt, rt2, tempRegister.Operand, 0); + } + } + } + + private static void EmitMemoryStrexInstruction(CodeGenContext context, uint rd, uint rt, uint rn, Action action) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rtOperand = InstEmitCommon.GetInputGpr(context, rt); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, context.Arm64Assembler, tempRegister.Operand, rnOperand); + + action(rdOperand, rtOperand, tempRegister.Operand); + } + + private static void EmitMemoryDWordStrexInstruction(CodeGenContext context, uint rd, uint rt, uint rt2, uint rn, Action action) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rtOperand = InstEmitCommon.GetInputGpr(context, rt); + Operand rt2Operand = InstEmitCommon.GetInputGpr(context, rt2); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, context.Arm64Assembler, tempRegister.Operand, rnOperand); + + action(rdOperand, rtOperand, rt2Operand, tempRegister.Operand); + } + + private static void EmitMemoryInstruction( + CodeGenContext context, + Action writeInst, + Action writeInstUnscaled, + Operand rt, + Operand baseAddress, + Operand offset, + int scale, + bool index, + bool add, + bool wBack, + ArmShiftType shiftType = ArmShiftType.Lsl, + int shift = 0) + { + Assembler asm = context.Arm64Assembler; + RegisterAllocator regAlloc = context.RegisterAllocator; + + if (index && !wBack) + { + // Offset. + + using ScopedRegister tempRegister = regAlloc.AllocateTempGprRegisterScoped(); + + int signedOffs = add ? offset.AsInt32() : -offset.AsInt32(); + int offs = 0; + bool unscaled = false; + + if (offset.Kind == OperandKind.Constant && offset.Value == 0) + { + WriteAddressTranslation(context.MemoryManagerType, regAlloc, asm, tempRegister.Operand, baseAddress); + } + else if (offset.Kind == OperandKind.Constant && shift == 0 && CanFoldOffset(context.MemoryManagerType, signedOffs, scale, writeInstUnscaled != null, out unscaled)) + { + WriteAddressTranslation(context.MemoryManagerType, regAlloc, asm, tempRegister.Operand, baseAddress); + offs = signedOffs; + } + else + { + WriteAddShiftOffset(asm, tempRegister.Operand, baseAddress, offset, add, shiftType, shift); + WriteAddressTranslation(context.MemoryManagerType, regAlloc, asm, tempRegister.Operand, tempRegister.Operand); + } + + if (unscaled) + { + writeInstUnscaled(rt, tempRegister.Operand, offs); + } + else + { + writeInst(rt, tempRegister.Operand, offs); + } + } + else if (context.IsThumb ? !index && wBack : !index && !wBack) + { + // Post-indexed. + + if (rt.Type == offset.Type && rt.Value == offset.Value) + { + // If Rt and Rm are the same register, we must ensure we add the register offset (Rm) + // before the value is loaded, otherwise we will be adding the wrong value. + + if (rt.Type != baseAddress.Type || rt.Value != baseAddress.Value) + { + using ScopedRegister tempRegister = regAlloc.AllocateTempGprRegisterScoped(); + + WriteAddressTranslation(context.MemoryManagerType, regAlloc, asm, tempRegister.Operand, baseAddress); + WriteAddShiftOffset(asm, baseAddress, baseAddress, offset, add, shiftType, shift); + + writeInst(rt, tempRegister.Operand, 0); + } + else + { + using ScopedRegister tempRegister = regAlloc.AllocateTempGprRegisterScoped(); + using ScopedRegister tempRegister2 = regAlloc.AllocateTempGprRegisterScoped(); + + WriteAddressTranslation(context.MemoryManagerType, regAlloc, asm, tempRegister.Operand, baseAddress); + WriteAddShiftOffset(asm, tempRegister2.Operand, baseAddress, offset, add, shiftType, shift); + + writeInst(rt, tempRegister.Operand, 0); + + asm.Mov(baseAddress, tempRegister2.Operand); + } + } + else + { + using ScopedRegister tempRegister = regAlloc.AllocateTempGprRegisterScoped(); + + WriteAddressTranslation(context.MemoryManagerType, regAlloc, asm, tempRegister.Operand, baseAddress); + + writeInst(rt, tempRegister.Operand, 0); + + WriteAddShiftOffset(asm, baseAddress, baseAddress, offset, add, shiftType, shift); + } + } + else if (index && wBack) + { + // Pre-indexed. + + using ScopedRegister tempRegister = regAlloc.AllocateTempGprRegisterScoped(); + + if (rt.Value == baseAddress.Value) + { + // If Rt and Rn are the same register, ensure we perform the write back after the read/write. + + WriteAddShiftOffset(asm, tempRegister.Operand, baseAddress, offset, add, shiftType, shift); + WriteAddressTranslation(context.MemoryManagerType, regAlloc, asm, tempRegister.Operand, tempRegister.Operand); + + writeInst(rt, tempRegister.Operand, 0); + + context.Arm64Assembler.Mov(baseAddress, tempRegister.Operand); + } + else + { + WriteAddShiftOffset(asm, baseAddress, baseAddress, offset, add, shiftType, shift); + WriteAddressTranslation(context.MemoryManagerType, regAlloc, asm, tempRegister.Operand, baseAddress); + + writeInst(rt, tempRegister.Operand, 0); + } + } + else + { + Debug.Fail($"Invalid pre-index and write-back combination."); + } + } + + private static void EmitMemoryLiteralInstruction(CodeGenContext context, uint rt, uint imm, int scale, bool p, bool u, bool w, Action action) + { + if (!p || w) + { + EmitMemoryInstruction(context, rt, RegisterUtils.PcRegister, (int)imm, scale, p, u, w, isStore: false, action, null); + + return; + } + + Operand rtOperand = InstEmitCommon.GetOutputGpr(context, rt); + uint targetAddress = context.Pc & ~3u; + + if (u) + { + targetAddress += imm; + } + else + { + targetAddress -= imm; + } + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, context.Arm64Assembler, tempRegister.Operand, targetAddress); + + action(rtOperand, tempRegister.Operand, 0); + } + + private static void EmitMemoryDWordLiteralInstruction(CodeGenContext context, uint rt, uint rt2, uint imm, bool p, bool u, bool w, Action action) + { + if (!p || w) + { + EmitMemoryDWordInstructionI(context, rt, rt2, RegisterUtils.PcRegister, imm, p, u, w, isStore: false, action); + + return; + } + + Operand rtOperand = InstEmitCommon.GetOutputGpr(context, rt); + Operand rt2Operand = InstEmitCommon.GetOutputGpr(context, rt2); + uint targetAddress = context.Pc & ~3u; + + if (u) + { + targetAddress += imm; + } + else + { + targetAddress -= imm; + } + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, context.Arm64Assembler, tempRegister.Operand, targetAddress); + + action(rtOperand, rt2Operand, tempRegister.Operand, 0); + } + + private static void EmitMemoryPrefetchInstruction(CodeGenContext context, uint rn, uint imm, bool u, PrefetchType type) + { + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + int signedOffs = u ? (int)imm : -(int)imm; + int offs = 0; + bool unscaled = false; + + if (imm == 0) + { + WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, context.Arm64Assembler, tempRegister.Operand, rnOperand); + } + else if (CanFoldOffset(context.MemoryManagerType, signedOffs, 3, true, out unscaled)) + { + WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, context.Arm64Assembler, tempRegister.Operand, rnOperand); + offs = signedOffs; + } + else + { + WriteAddShiftOffset(context.Arm64Assembler, tempRegister.Operand, rnOperand, InstEmitCommon.Const((int)imm), u, ArmShiftType.Lsl, 0); + WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, context.Arm64Assembler, tempRegister.Operand, tempRegister.Operand); + } + + if (unscaled) + { + context.Arm64Assembler.Prfum(tempRegister.Operand, offs, (uint)type, 0, 0); + } + else + { + context.Arm64Assembler.PrfmI(tempRegister.Operand, offs, (uint)type, 0, 0); + } + } + + private static void EmitMemoryPrefetchInstruction(CodeGenContext context, uint rn, uint rm, bool u, uint sType, uint shift, PrefetchType type) + { + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + WriteAddShiftOffset(context.Arm64Assembler, tempRegister.Operand, rnOperand, rmOperand, u, (ArmShiftType)sType, (int)shift); + WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, context.Arm64Assembler, tempRegister.Operand, tempRegister.Operand); + + context.Arm64Assembler.PrfmI(tempRegister.Operand, 0, (uint)type, 0, 0); + } + + private static void EmitMemoryPrefetchLiteralInstruction(CodeGenContext context, uint imm, bool u, PrefetchType type) + { + uint targetAddress = context.Pc & ~3u; + + if (u) + { + targetAddress += imm; + } + else + { + targetAddress -= imm; + } + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, context.Arm64Assembler, tempRegister.Operand, targetAddress); + + context.Arm64Assembler.PrfmI(tempRegister.Operand, 0, (uint)type, 0, 0); + } + + public static bool CanFoldOffset(MemoryManagerType mmType, int offset, int scale, bool hasUnscaled, out bool unscaled) + { + if (mmType != MemoryManagerType.HostMappedUnsafe) + { + unscaled = false; + + return false; + } + + int mask = (1 << scale) - 1; + + if ((offset & mask) == 0 && offset >= 0 && offset < 0x1000) + { + // We can use the unsigned, scaled encoding. + + unscaled = false; + + return true; + } + + // Check if we can use the signed, unscaled encoding. + + unscaled = hasUnscaled && offset >= -0x100 && offset < 0x100; + + return unscaled; + } + + private static bool CanFoldDWordOffset(MemoryManagerType mmType, int offset) + { + if (mmType != MemoryManagerType.HostMappedUnsafe) + { + return false; + } + + return offset >= 0 && offset < 0x40 && (offset & 3) == 0; + } + + private static void WriteAddressTranslation(MemoryManagerType mmType, RegisterAllocator regAlloc, in Assembler asm, Operand destination, uint guestAddress) + { + asm.Mov(destination, guestAddress); + + WriteAddressTranslation(mmType, regAlloc, asm, destination, destination); + } + + public static void WriteAddressTranslation(MemoryManagerType mmType, RegisterAllocator regAlloc, in Assembler asm, Operand destination, Operand guestAddress) + { + Operand destination64 = new(destination.Kind, OperandType.I64, destination.Value); + Operand basePointer = new(regAlloc.FixedPageTableRegister, RegisterType.Integer, OperandType.I64); + + if (mmType == MemoryManagerType.HostMapped || mmType == MemoryManagerType.HostMappedUnsafe) + { + // We don't need to mask the address for the safe mode, since it is already naturally limited to 32-bit + // and can never reach out of the guest address space. + + asm.Add(destination64, basePointer, guestAddress); + } + else + { + throw new NotImplementedException(mmType.ToString()); + } + } + + public static void WriteAddShiftOffset(in Assembler asm, Operand rd, Operand rn, Operand offset, bool add, ArmShiftType shiftType, int shift) + { + Debug.Assert(offset.Kind != OperandKind.Constant || offset.AsInt32() >= 0); + + if (shiftType == ArmShiftType.Ror) + { + asm.Ror(rd, rn, InstEmitCommon.Const(shift & 31)); + + if (add) + { + asm.Add(rd, rd, offset, ArmShiftType.Lsl, 0); + } + else + { + asm.Sub(rd, rd, offset, ArmShiftType.Lsl, 0); + } + } + else + { + if (add) + { + asm.Add(rd, rn, offset, shiftType, shift); + } + else + { + asm.Sub(rd, rn, offset, shiftType, shift); + } + } + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitMove.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitMove.cs new file mode 100644 index 000000000..88850cb33 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitMove.cs @@ -0,0 +1,350 @@ +using Ryujinx.Cpu.LightningJit.CodeGen; +using Ryujinx.Cpu.LightningJit.CodeGen.Arm64; +using System.Diagnostics; + +namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 +{ + static class InstEmitMove + { + public static void MvnI(CodeGenContext context, uint rd, uint imm, bool immRotated, bool s) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + + if (s) + { + using ScopedRegister flagsRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + InstEmitCommon.GetCurrentFlags(context, flagsRegister.Operand); + + if (immRotated) + { + if ((imm & (1u << 31)) != 0) + { + context.Arm64Assembler.Orr(flagsRegister.Operand, flagsRegister.Operand, InstEmitCommon.Const(1 << 29)); + } + else + { + context.Arm64Assembler.Bfc(flagsRegister.Operand, 29, 1); + } + } + + context.Arm64Assembler.Mov(rdOperand, ~imm); + context.Arm64Assembler.Tst(rdOperand, rdOperand); + + InstEmitCommon.RestoreCvFlags(context, flagsRegister.Operand); + + context.SetNzcvModified(); + } + else + { + context.Arm64Assembler.Mov(rdOperand, ~imm); + } + } + + public static void MvnR(CodeGenContext context, uint rd, uint rm, uint sType, uint imm5, bool s) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + ScopedRegister flagsRegister = default; + + if (s) + { + flagsRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + InstEmitCommon.GetCurrentFlags(context, flagsRegister.Operand); + + rmOperand = InstEmitAlu.GetMShiftedByImmediate(context, tempRegister.Operand, rmOperand, imm5, sType, flagsRegister.Operand); + } + else + { + rmOperand = InstEmitAlu.GetMShiftedByImmediate(context, tempRegister.Operand, rmOperand, imm5, sType); + } + + context.Arm64Assembler.Mvn(rdOperand, rmOperand); + + if (s) + { + InstEmitCommon.RestoreCvFlags(context, flagsRegister.Operand); + + flagsRegister.Dispose(); + + context.SetNzcvModified(); + } + } + + public static void MvnRr(CodeGenContext context, uint rd, uint rm, uint sType, uint rs, bool s) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + Operand rsOperand = InstEmitCommon.GetInputGpr(context, rs); + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + ScopedRegister flagsRegister = default; + + if (s) + { + flagsRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + InstEmitCommon.GetCurrentFlags(context, flagsRegister.Operand); + + rmOperand = InstEmitAlu.GetMShiftedByReg(context, tempRegister.Operand, rmOperand, rsOperand, sType, flagsRegister.Operand); + } + else + { + rmOperand = InstEmitAlu.GetMShiftedByReg(context, tempRegister.Operand, rmOperand, rsOperand, sType); + } + + context.Arm64Assembler.Mvn(rdOperand, rmOperand); + + if (s) + { + InstEmitCommon.RestoreCvFlags(context, flagsRegister.Operand); + + flagsRegister.Dispose(); + + context.SetNzcvModified(); + } + } + + public static void MovI(CodeGenContext context, uint rd, uint imm, bool immRotated, bool s) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + + if (s) + { + using ScopedRegister flagsRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + InstEmitCommon.GetCurrentFlags(context, flagsRegister.Operand); + + if (immRotated) + { + if ((imm & (1u << 31)) != 0) + { + context.Arm64Assembler.Orr(flagsRegister.Operand, flagsRegister.Operand, InstEmitCommon.Const(2)); + } + else + { + context.Arm64Assembler.Bfc(flagsRegister.Operand, 1, 1); + } + } + + context.Arm64Assembler.Mov(rdOperand, imm); + context.Arm64Assembler.Tst(rdOperand, rdOperand); + + InstEmitCommon.RestoreCvFlags(context, flagsRegister.Operand); + + context.SetNzcvModified(); + } + else + { + context.Arm64Assembler.Mov(rdOperand, imm); + } + } + + public static void MovR(CodeGenContext context, uint rd, uint rm, uint sType, uint imm5, bool s) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + + if (InstEmitAlu.CanShift(sType, imm5) && !s) + { + if (imm5 != 0) + { + switch ((ArmShiftType)sType) + { + case ArmShiftType.Lsl: + context.Arm64Assembler.Lsl(rdOperand, rmOperand, InstEmitCommon.Const((int)imm5)); + break; + case ArmShiftType.Lsr: + context.Arm64Assembler.Lsr(rdOperand, rmOperand, InstEmitCommon.Const((int)imm5)); + break; + case ArmShiftType.Asr: + context.Arm64Assembler.Asr(rdOperand, rmOperand, InstEmitCommon.Const((int)imm5)); + break; + case ArmShiftType.Ror: + context.Arm64Assembler.Ror(rdOperand, rmOperand, InstEmitCommon.Const((int)imm5)); + break; + } + } + else + { + context.Arm64Assembler.Mov(rdOperand, rmOperand); + } + } + else + { + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + ScopedRegister flagsRegister = default; + + if (s) + { + flagsRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + InstEmitCommon.GetCurrentFlags(context, flagsRegister.Operand); + + rmOperand = InstEmitAlu.GetMShiftedByImmediate(context, tempRegister.Operand, rmOperand, imm5, sType, flagsRegister.Operand); + } + else + { + rmOperand = InstEmitAlu.GetMShiftedByImmediate(context, tempRegister.Operand, rmOperand, imm5, sType, null); + } + + context.Arm64Assembler.Mov(rdOperand, rmOperand); + + if (s) + { + context.Arm64Assembler.Tst(rdOperand, rdOperand); + + InstEmitCommon.RestoreCvFlags(context, flagsRegister.Operand); + + flagsRegister.Dispose(); + + context.SetNzcvModified(); + } + } + } + + public static void MovR(CodeGenContext context, uint cond, uint rd, uint rm, uint sType, uint imm5, bool s) + { + if (context.ConsumeSkipNextInstruction()) + { + return; + } + + if ((ArmCondition)cond >= ArmCondition.Al || s) + { + MovR(context, rd, rm, sType, imm5, s); + + return; + } + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + + if (InstEmitAlu.CanShift(sType, imm5)) + { + if (imm5 != 0) + { + switch ((ArmShiftType)sType) + { + case ArmShiftType.Lsl: + context.Arm64Assembler.Lsl(tempRegister.Operand, rmOperand, InstEmitCommon.Const((int)imm5)); + break; + case ArmShiftType.Lsr: + context.Arm64Assembler.Lsr(tempRegister.Operand, rmOperand, InstEmitCommon.Const((int)imm5)); + break; + case ArmShiftType.Asr: + context.Arm64Assembler.Asr(tempRegister.Operand, rmOperand, InstEmitCommon.Const((int)imm5)); + break; + case ArmShiftType.Ror: + context.Arm64Assembler.Ror(tempRegister.Operand, rmOperand, InstEmitCommon.Const((int)imm5)); + break; + } + + context.Arm64Assembler.Csel(rdOperand, tempRegister.Operand, rdOperand, (ArmCondition)cond); + } + else + { + Operand other = rdOperand; + + InstInfo nextInstruction = context.PeekNextInstruction(); + + if (nextInstruction.Name == InstName.MovR) + { + // If this instruction is followed by another move with the inverse condition, + // we can just put it into the second operand of the CSEL instruction and skip the next move. + + InstCondb28w4Sb20w1Rdb12w4Imm5b7w5Stypeb5w2Rmb0w4 nextInst = new(nextInstruction.Encoding); + + if (nextInst.Rd == rd && + nextInst.S == 0 && + nextInst.Stype == 0 && + nextInst.Imm5 == 0 && + nextInst.Cond == (cond ^ 1u) && + nextInst.Rm != RegisterUtils.PcRegister) + { + other = InstEmitCommon.GetInputGpr(context, nextInst.Rm); + context.SetSkipNextInstruction(); + } + } + + context.Arm64Assembler.Csel(rdOperand, rmOperand, other, (ArmCondition)cond); + } + } + else + { + rmOperand = InstEmitAlu.GetMShiftedByImmediate(context, tempRegister.Operand, rmOperand, imm5, sType, null); + + context.Arm64Assembler.Csel(rdOperand, rmOperand, rdOperand, (ArmCondition)cond); + } + } + + public static void MovRr(CodeGenContext context, uint rd, uint rm, uint sType, uint rs, bool s) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + Operand rsOperand = InstEmitCommon.GetInputGpr(context, rs); + + if (!s) + { + InstEmitAlu.GetMShiftedByReg(context, rdOperand, rmOperand, rsOperand, sType); + } + else + { + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister flagsRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + InstEmitCommon.GetCurrentFlags(context, flagsRegister.Operand); + + rmOperand = InstEmitAlu.GetMShiftedByReg(context, tempRegister.Operand, rmOperand, rsOperand, sType, flagsRegister.Operand); + + context.Arm64Assembler.Mov(rdOperand, rmOperand); + context.Arm64Assembler.Tst(rdOperand, rdOperand); + + InstEmitCommon.RestoreCvFlags(context, flagsRegister.Operand); + + context.SetNzcvModified(); + } + } + + public static void Movt(CodeGenContext context, uint rd, uint imm) + { + Operand rdOperand = InstEmitCommon.GetInputGpr(context, rd); + + context.Arm64Assembler.Movk(rdOperand, (int)imm, 1); + } + + public static void Pkh(CodeGenContext context, uint rd, uint rn, uint rm, bool tb, uint imm5) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + + if (!tb && imm5 == 0) + { + context.Arm64Assembler.Extr(rdOperand, rnOperand, rmOperand, 16); + } + else + { + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + if (tb) + { + context.Arm64Assembler.Asr(tempRegister.Operand, rmOperand, InstEmitCommon.Const(imm5 == 0 ? 31 : (int)imm5)); + context.Arm64Assembler.Extr(rdOperand, tempRegister.Operand, rnOperand, 16); + } + else + { + context.Arm64Assembler.Lsl(tempRegister.Operand, rmOperand, InstEmitCommon.Const((int)imm5)); + context.Arm64Assembler.Extr(rdOperand, rnOperand, tempRegister.Operand, 16); + } + } + + context.Arm64Assembler.Ror(rdOperand, rdOperand, InstEmitCommon.Const(16)); + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitMultiply.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitMultiply.cs new file mode 100644 index 000000000..042ab8157 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitMultiply.cs @@ -0,0 +1,603 @@ +using Ryujinx.Cpu.LightningJit.CodeGen; +using System; + +namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 +{ + static class InstEmitMultiply + { + public static void Mla(CodeGenContext context, uint rd, uint rn, uint rm, uint ra) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + Operand raOperand = InstEmitCommon.GetInputGpr(context, ra); + + context.Arm64Assembler.Madd(rdOperand, rnOperand, rmOperand, raOperand); + } + + public static void Mls(CodeGenContext context, uint rd, uint rn, uint rm, uint ra) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + Operand raOperand = InstEmitCommon.GetInputGpr(context, ra); + + context.Arm64Assembler.Msub(rdOperand, rnOperand, rmOperand, raOperand); + } + + public static void Mul(CodeGenContext context, uint rd, uint rn, uint rm, bool s) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + + if (s) + { + using ScopedRegister flagsRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + InstEmitCommon.GetCurrentFlags(context, flagsRegister.Operand); + + context.Arm64Assembler.Mul(rdOperand, rnOperand, rmOperand); + context.Arm64Assembler.Tst(rdOperand, rdOperand); + + InstEmitCommon.RestoreCvFlags(context, flagsRegister.Operand); + + context.SetNzcvModified(); + } + else + { + context.Arm64Assembler.Mul(rdOperand, rnOperand, rmOperand); + } + } + + public static void Smlabb(CodeGenContext context, uint rd, uint rn, uint rm, uint ra, bool nHigh, bool mHigh) + { + using ScopedRegister tempN = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister tempM = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister tempA = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + Operand tempM64 = new(OperandKind.Register, OperandType.I64, tempM.Operand.Value); + Operand tempA64 = new(OperandKind.Register, OperandType.I64, tempA.Operand.Value); + + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + Operand raOperand = InstEmitCommon.GetInputGpr(context, ra); + + SelectSignedHalfword(context, tempN.Operand, rnOperand, nHigh); + SelectSignedHalfword(context, tempM.Operand, rmOperand, mHigh); + + context.Arm64Assembler.Sxtw(tempA64, raOperand); + context.Arm64Assembler.Smaddl(tempN.Operand, tempN.Operand, tempM.Operand, tempA64); + + CheckResultOverflow(context, tempM64, tempN.Operand); + + context.Arm64Assembler.Mov(rdOperand, tempN.Operand); + } + + public static void Smlad(CodeGenContext context, uint rd, uint rn, uint rm, uint ra, bool x) + { + EmitSmladSmlsd(context, rd, rn, rm, ra, x, add: true); + } + + public static void Smlal(CodeGenContext context, uint rdLo, uint rdHi, uint rn, uint rm, bool s) + { + EmitMultiplyAddLong(context, context.Arm64Assembler.Smaddl, rdLo, rdHi, rn, rm, s); + } + + public static void Smlalbb(CodeGenContext context, uint rdLo, uint rdHi, uint rn, uint rm, bool nHigh, bool mHigh) + { + Operand rdLoOperand = InstEmitCommon.GetOutputGpr(context, rdLo); + Operand rdHiOperand = InstEmitCommon.GetOutputGpr(context, rdHi); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + + Operand rdLoOperand64 = new(OperandKind.Register, OperandType.I64, rdLoOperand.Value); + Operand rdHiOperand64 = new(OperandKind.Register, OperandType.I64, rdHiOperand.Value); + + using ScopedRegister tempN = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister tempM = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister tempA = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + SelectSignedHalfword(context, tempN.Operand, rnOperand, nHigh); + SelectSignedHalfword(context, tempM.Operand, rmOperand, mHigh); + + Operand tempA64 = new(OperandKind.Register, OperandType.I64, tempA.Operand.Value); + + context.Arm64Assembler.Lsl(tempA64, rdHiOperand64, InstEmitCommon.Const(32)); + context.Arm64Assembler.Orr(tempA64, tempA64, rdLoOperand); + + context.Arm64Assembler.Smaddl(rdLoOperand64, tempN.Operand, tempM.Operand, tempA64); + + if (rdLo != rdHi) + { + context.Arm64Assembler.Lsr(rdHiOperand64, rdLoOperand64, InstEmitCommon.Const(32)); + } + + context.Arm64Assembler.Mov(rdLoOperand, rdLoOperand); // Zero-extend. + } + + public static void Smlald(CodeGenContext context, uint rdLo, uint rdHi, uint rn, uint rm, bool x) + { + EmitSmlaldSmlsld(context, rdLo, rdHi, rn, rm, x, add: true); + } + + public static void Smlawb(CodeGenContext context, uint rd, uint rn, uint rm, uint ra, bool mHigh) + { + using ScopedRegister tempN = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister tempM = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister tempA = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + Operand tempN64 = new(OperandKind.Register, OperandType.I64, tempN.Operand.Value); + Operand tempM64 = new(OperandKind.Register, OperandType.I64, tempM.Operand.Value); + Operand tempA64 = new(OperandKind.Register, OperandType.I64, tempA.Operand.Value); + + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + Operand raOperand = InstEmitCommon.GetInputGpr(context, ra); + + SelectSignedHalfword(context, tempM.Operand, rmOperand, mHigh); + + context.Arm64Assembler.Sxtw(tempA64, raOperand); + context.Arm64Assembler.Lsl(tempA64, tempA64, InstEmitCommon.Const(16)); + context.Arm64Assembler.Smaddl(tempN.Operand, rnOperand, tempM.Operand, tempA64); + context.Arm64Assembler.Asr(tempN64, tempN64, InstEmitCommon.Const(16)); + + CheckResultOverflow(context, tempM64, tempN.Operand); + + context.Arm64Assembler.Mov(rdOperand, tempN.Operand); + } + + public static void Smlsd(CodeGenContext context, uint rd, uint rn, uint rm, uint ra, bool x) + { + EmitSmladSmlsd(context, rd, rn, rm, ra, x, add: false); + } + + public static void Smlsld(CodeGenContext context, uint rdLo, uint rdHi, uint rn, uint rm, bool x) + { + EmitSmlaldSmlsld(context, rdLo, rdHi, rn, rm, x, add: false); + } + + public static void Smmla(CodeGenContext context, uint rd, uint rn, uint rm, uint ra, bool r) + { + EmitSmmlaSmmls(context, rd, rn, rm, ra, r, add: true); + } + + public static void Smmls(CodeGenContext context, uint rd, uint rn, uint rm, uint ra, bool r) + { + EmitSmmlaSmmls(context, rd, rn, rm, ra, r, add: false); + } + + public static void Smmul(CodeGenContext context, uint rd, uint rn, uint rm, bool r) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + + Operand rdOperand64 = new(OperandKind.Register, OperandType.I64, rdOperand.Value); + + context.Arm64Assembler.Smull(rdOperand64, rnOperand, rmOperand); + + if (r) + { + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + context.Arm64Assembler.Mov(tempRegister.Operand, 0x80000000u); + context.Arm64Assembler.Add(rdOperand64, rdOperand64, tempRegister.Operand); + } + + context.Arm64Assembler.Lsr(rdOperand64, rdOperand64, InstEmitCommon.Const(32)); + } + + public static void Smuad(CodeGenContext context, uint rd, uint rn, uint rm, bool x) + { + EmitSmuadSmusd(context, rd, rn, rm, x, add: true); + } + + public static void Smulbb(CodeGenContext context, uint rd, uint rn, uint rm, bool nHigh, bool mHigh) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + + Operand rdOperand64 = new(OperandKind.Register, OperandType.I64, rdOperand.Value); + + using ScopedRegister tempN = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister tempM = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + SelectSignedHalfword(context, tempN.Operand, rnOperand, nHigh); + SelectSignedHalfword(context, tempM.Operand, rmOperand, mHigh); + + context.Arm64Assembler.Smull(rdOperand64, tempN.Operand, tempM.Operand); + + context.Arm64Assembler.Mov(rdOperand, rdOperand); // Zero-extend. + } + + public static void Smull(CodeGenContext context, uint rdLo, uint rdHi, uint rn, uint rm, bool s) + { + EmitMultiplyLong(context, context.Arm64Assembler.Smull, rdLo, rdHi, rn, rm, s); + } + + public static void Smulwb(CodeGenContext context, uint rd, uint rn, uint rm, bool mHigh) + { + using ScopedRegister tempN = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister tempM = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + Operand tempN64 = new(OperandKind.Register, OperandType.I64, tempN.Operand.Value); + Operand tempM64 = new(OperandKind.Register, OperandType.I64, tempM.Operand.Value); + + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + + SelectSignedHalfword(context, tempM.Operand, rmOperand, mHigh); + + context.Arm64Assembler.Smull(tempN.Operand, rnOperand, tempM.Operand); + context.Arm64Assembler.Asr(tempN64, tempN64, InstEmitCommon.Const(16)); + + CheckResultOverflow(context, tempM64, tempN.Operand); + + context.Arm64Assembler.Mov(rdOperand, tempN.Operand); + } + + public static void Smusd(CodeGenContext context, uint rd, uint rn, uint rm, bool x) + { + EmitSmuadSmusd(context, rd, rn, rm, x, add: false); + } + + public static void Umaal(CodeGenContext context, uint rdLo, uint rdHi, uint rn, uint rm) + { + Operand rdLoOperand = InstEmitCommon.GetOutputGpr(context, rdLo); + Operand rdHiOperand = InstEmitCommon.GetOutputGpr(context, rdHi); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + + Operand rdLoOperand64 = new(OperandKind.Register, OperandType.I64, rdLoOperand.Value); + Operand rdHiOperand64 = new(OperandKind.Register, OperandType.I64, rdHiOperand.Value); + + if (rdLo == rdHi) + { + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + Operand tempRegister64 = new(OperandKind.Register, OperandType.I64, tempRegister.Operand.Value); + + context.Arm64Assembler.Umaddl(tempRegister64, rnOperand, rmOperand, rdLoOperand64); + context.Arm64Assembler.Add(rdLoOperand64, tempRegister64, rdHiOperand64); + } + else + { + context.Arm64Assembler.Umaddl(rdLoOperand64, rnOperand, rmOperand, rdLoOperand64); + context.Arm64Assembler.Add(rdLoOperand64, rdLoOperand64, rdHiOperand64); + } + + if (rdLo != rdHi) + { + context.Arm64Assembler.Lsr(rdHiOperand64, rdLoOperand64, InstEmitCommon.Const(32)); + } + + context.Arm64Assembler.Mov(rdLoOperand, rdLoOperand); // Zero-extend. + } + + public static void Umlal(CodeGenContext context, uint rdLo, uint rdHi, uint rn, uint rm, bool s) + { + EmitMultiplyAddLong(context, context.Arm64Assembler.Umaddl, rdLo, rdHi, rn, rm, s); + } + + public static void Umull(CodeGenContext context, uint rdLo, uint rdHi, uint rn, uint rm, bool s) + { + EmitMultiplyLong(context, context.Arm64Assembler.Umull, rdLo, rdHi, rn, rm, s); + } + + private static void EmitMultiplyLong(CodeGenContext context, Action action, uint rdLo, uint rdHi, uint rn, uint rm, bool s) + { + Operand rdLoOperand = InstEmitCommon.GetOutputGpr(context, rdLo); + Operand rdHiOperand = InstEmitCommon.GetOutputGpr(context, rdHi); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + + Operand rdLoOperand64 = new(OperandKind.Register, OperandType.I64, rdLoOperand.Value); + Operand rdHiOperand64 = new(OperandKind.Register, OperandType.I64, rdHiOperand.Value); + + if (s) + { + using ScopedRegister flagsRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + InstEmitCommon.GetCurrentFlags(context, flagsRegister.Operand); + + action(rdLoOperand64, rnOperand, rmOperand); + context.Arm64Assembler.Tst(rdLoOperand64, rdLoOperand64); + + InstEmitCommon.RestoreCvFlags(context, flagsRegister.Operand); + } + else + { + action(rdLoOperand64, rnOperand, rmOperand); + } + + if (rdLo != rdHi) + { + context.Arm64Assembler.Lsr(rdHiOperand64, rdLoOperand64, InstEmitCommon.Const(32)); + } + + context.Arm64Assembler.Mov(rdLoOperand, rdLoOperand); // Zero-extend. + } + + private static void EmitMultiplyAddLong(CodeGenContext context, Action action, uint rdLo, uint rdHi, uint rn, uint rm, bool s) + { + Operand rdLoOperand = InstEmitCommon.GetOutputGpr(context, rdLo); + Operand rdHiOperand = InstEmitCommon.GetOutputGpr(context, rdHi); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + + Operand rdLoOperand64 = new(OperandKind.Register, OperandType.I64, rdLoOperand.Value); + Operand rdHiOperand64 = new(OperandKind.Register, OperandType.I64, rdHiOperand.Value); + + using ScopedRegister raRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + Operand raOperand64 = new(OperandKind.Register, OperandType.I64, raRegister.Operand.Value); + + context.Arm64Assembler.Lsl(raOperand64, rdHiOperand64, InstEmitCommon.Const(32)); + context.Arm64Assembler.Orr(raOperand64, raOperand64, rdLoOperand); + + if (s) + { + using ScopedRegister flagsRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + InstEmitCommon.GetCurrentFlags(context, flagsRegister.Operand); + + action(rdLoOperand64, rnOperand, rmOperand, raOperand64); + context.Arm64Assembler.Tst(rdLoOperand64, rdLoOperand64); + + InstEmitCommon.RestoreCvFlags(context, flagsRegister.Operand); + + context.SetNzcvModified(); + } + else + { + action(rdLoOperand64, rnOperand, rmOperand, raOperand64); + } + + if (rdLo != rdHi) + { + context.Arm64Assembler.Lsr(rdHiOperand64, rdLoOperand64, InstEmitCommon.Const(32)); + } + + context.Arm64Assembler.Mov(rdLoOperand, rdLoOperand); // Zero-extend. + } + + private static void EmitSmladSmlsd(CodeGenContext context, uint rd, uint rn, uint rm, uint ra, bool x, bool add) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + Operand raOperand = InstEmitCommon.GetInputGpr(context, ra); + + Operand rdOperand64 = new(OperandKind.Register, OperandType.I64, rdOperand.Value); + + using ScopedRegister tempN = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister tempM = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister tempA = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + Operand tempN64 = new(OperandKind.Register, OperandType.I64, tempN.Operand.Value); + Operand tempM64 = new(OperandKind.Register, OperandType.I64, tempM.Operand.Value); + Operand tempA64 = new(OperandKind.Register, OperandType.I64, tempA.Operand.Value); + + ScopedRegister swapTemp = default; + + if (x) + { + swapTemp = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + context.Arm64Assembler.Ror(swapTemp.Operand, rmOperand, InstEmitCommon.Const(16)); + + rmOperand = swapTemp.Operand; + } + + context.Arm64Assembler.Sxth(tempN64, rnOperand); + context.Arm64Assembler.Sxth(tempM64, rmOperand); + context.Arm64Assembler.Sxtw(tempA64, raOperand); + + context.Arm64Assembler.Mul(rdOperand64, tempN64, tempM64); + + context.Arm64Assembler.Asr(tempN.Operand, rnOperand, InstEmitCommon.Const(16)); + context.Arm64Assembler.Asr(tempM.Operand, rmOperand, InstEmitCommon.Const(16)); + + if (add) + { + context.Arm64Assembler.Smaddl(rdOperand64, tempN.Operand, tempM.Operand, rdOperand64); + } + else + { + context.Arm64Assembler.Smsubl(rdOperand64, tempN.Operand, tempM.Operand, rdOperand64); + } + + context.Arm64Assembler.Add(rdOperand64, rdOperand64, tempA64); + + CheckResultOverflow(context, tempM64, rdOperand64); + + context.Arm64Assembler.Mov(rdOperand, rdOperand); // Zero-extend. + + if (x) + { + swapTemp.Dispose(); + } + } + + private static void EmitSmlaldSmlsld(CodeGenContext context, uint rdLo, uint rdHi, uint rn, uint rm, bool x, bool add) + { + Operand rdLoOperand = InstEmitCommon.GetOutputGpr(context, rdLo); + Operand rdHiOperand = InstEmitCommon.GetOutputGpr(context, rdHi); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + + Operand rdLoOperand64 = new(OperandKind.Register, OperandType.I64, rdLoOperand.Value); + Operand rdHiOperand64 = new(OperandKind.Register, OperandType.I64, rdHiOperand.Value); + + using ScopedRegister tempN = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister tempM = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister tempA = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + Operand tempN64 = new(OperandKind.Register, OperandType.I64, tempN.Operand.Value); + Operand tempM64 = new(OperandKind.Register, OperandType.I64, tempM.Operand.Value); + Operand tempA64 = new(OperandKind.Register, OperandType.I64, tempA.Operand.Value); + + ScopedRegister swapTemp = default; + + if (x) + { + swapTemp = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + context.Arm64Assembler.Ror(swapTemp.Operand, rmOperand, InstEmitCommon.Const(16)); + + rmOperand = swapTemp.Operand; + } + + context.Arm64Assembler.Sxth(tempN64, rnOperand); + context.Arm64Assembler.Sxth(tempM64, rmOperand); + + context.Arm64Assembler.Mul(rdLoOperand64, tempN64, tempM64); + + context.Arm64Assembler.Asr(tempN.Operand, rnOperand, InstEmitCommon.Const(16)); + context.Arm64Assembler.Asr(tempM.Operand, rmOperand, InstEmitCommon.Const(16)); + + if (add) + { + context.Arm64Assembler.Smaddl(rdLoOperand64, tempN.Operand, tempM.Operand, rdLoOperand64); + } + else + { + context.Arm64Assembler.Smsubl(rdLoOperand64, tempN.Operand, tempM.Operand, rdLoOperand64); + } + + context.Arm64Assembler.Lsl(tempA64, rdHiOperand64, InstEmitCommon.Const(32)); + context.Arm64Assembler.Orr(tempA64, tempA64, rdLoOperand); + + context.Arm64Assembler.Add(rdLoOperand64, rdLoOperand64, tempA64); + + if (rdLo != rdHi) + { + context.Arm64Assembler.Lsr(rdHiOperand64, rdLoOperand64, InstEmitCommon.Const(32)); + } + + context.Arm64Assembler.Mov(rdLoOperand, rdLoOperand); // Zero-extend. + + if (x) + { + swapTemp.Dispose(); + } + } + + private static void EmitSmmlaSmmls(CodeGenContext context, uint rd, uint rn, uint rm, uint ra, bool r, bool add) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + Operand raOperand = InstEmitCommon.GetInputGpr(context, ra); + + Operand rdOperand64 = new(OperandKind.Register, OperandType.I64, rdOperand.Value); + Operand raOperand64 = new(OperandKind.Register, OperandType.I64, raOperand.Value); + + using ScopedRegister tempA = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + Operand tempA64 = new(OperandKind.Register, OperandType.I64, tempA.Operand.Value); + + context.Arm64Assembler.Lsl(tempA64, raOperand64, InstEmitCommon.Const(32)); + + if (add) + { + context.Arm64Assembler.Smaddl(rdOperand64, rnOperand, rmOperand, tempA64); + } + else + { + context.Arm64Assembler.Smsubl(rdOperand64, rnOperand, rmOperand, tempA64); + } + + if (r) + { + context.Arm64Assembler.Mov(tempA.Operand, 0x80000000u); + context.Arm64Assembler.Add(rdOperand64, rdOperand64, tempA64); + } + + context.Arm64Assembler.Lsr(rdOperand64, rdOperand64, InstEmitCommon.Const(32)); + } + + private static void EmitSmuadSmusd(CodeGenContext context, uint rd, uint rn, uint rm, bool x, bool add) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + + Operand rdOperand64 = new(OperandKind.Register, OperandType.I64, rdOperand.Value); + + using ScopedRegister tempN = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister tempM = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + Operand tempN64 = new(OperandKind.Register, OperandType.I64, tempN.Operand.Value); + Operand tempM64 = new(OperandKind.Register, OperandType.I64, tempM.Operand.Value); + + ScopedRegister swapTemp = default; + + if (x) + { + swapTemp = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + context.Arm64Assembler.Ror(swapTemp.Operand, rmOperand, InstEmitCommon.Const(16)); + + rmOperand = swapTemp.Operand; + } + + context.Arm64Assembler.Sxth(tempN64, rnOperand); + context.Arm64Assembler.Sxth(tempM64, rmOperand); + + context.Arm64Assembler.Mul(rdOperand64, tempN64, tempM64); + + context.Arm64Assembler.Asr(tempN.Operand, rnOperand, InstEmitCommon.Const(16)); + context.Arm64Assembler.Asr(tempM.Operand, rmOperand, InstEmitCommon.Const(16)); + + if (add) + { + context.Arm64Assembler.Smaddl(rdOperand64, tempN.Operand, tempM.Operand, rdOperand64); + } + else + { + context.Arm64Assembler.Smsubl(rdOperand64, tempN.Operand, tempM.Operand, rdOperand64); + } + + context.Arm64Assembler.Mov(rdOperand, rdOperand); // Zero-extend. + + if (x) + { + swapTemp.Dispose(); + } + } + + private static void SelectSignedHalfword(CodeGenContext context, Operand dest, Operand source, bool high) + { + if (high) + { + context.Arm64Assembler.Asr(dest, source, InstEmitCommon.Const(16)); + } + else + { + context.Arm64Assembler.Sxth(dest, source); + } + } + + private static void CheckResultOverflow(CodeGenContext context, Operand temp64, Operand result) + { + context.Arm64Assembler.Sxtw(temp64, result); + context.Arm64Assembler.Sub(temp64, temp64, result); + + int branchIndex = context.CodeWriter.InstructionPointer; + + context.Arm64Assembler.Cbz(temp64, 0); + + // Set Q flag if we had an overflow. + InstEmitSaturate.SetQFlag(context); + + int delta = context.CodeWriter.InstructionPointer - branchIndex; + context.CodeWriter.WriteInstructionAt(branchIndex, context.CodeWriter.ReadInstructionAt(branchIndex) | (uint)((delta & 0x7ffff) << 5)); + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonArithmetic.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonArithmetic.cs new file mode 100644 index 000000000..a59f00fc3 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonArithmetic.cs @@ -0,0 +1,344 @@ +using System; + +namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 +{ + static class InstEmitNeonArithmetic + { + public static void Vaba(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size, uint q) + { + InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, size, q, u ? context.Arm64Assembler.Uaba : context.Arm64Assembler.Saba, null); + } + + public static void Vabal(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size) + { + InstEmitNeonCommon.EmitVectorBinaryLong(context, rd, rn, rm, size, u ? context.Arm64Assembler.Uabal : context.Arm64Assembler.Sabal); + } + + public static void VabdF(CodeGenContext context, uint rd, uint rn, uint rm, uint sz, uint q) + { + InstEmitNeonCommon.EmitVectorBinaryF(context, rd, rn, rm, sz, q, context.Arm64Assembler.FabdV, context.Arm64Assembler.FabdVH); + } + + public static void VabdI(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size, uint q) + { + InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, size, q, u ? context.Arm64Assembler.Uabd : context.Arm64Assembler.Sabd, null); + } + + public static void Vabdl(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size) + { + InstEmitNeonCommon.EmitVectorBinaryLong(context, rd, rn, rm, size, u ? context.Arm64Assembler.Uabdl : context.Arm64Assembler.Sabdl); + } + + public static void Vabs(CodeGenContext context, uint rd, uint rm, bool f, uint size, uint q) + { + if (f) + { + InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FabsSingleAndDouble, context.Arm64Assembler.FabsHalf); + } + else + { + InstEmitNeonCommon.EmitVectorUnary(context, rd, rm, size, q, context.Arm64Assembler.AbsV); + } + } + + public static void VaddF(CodeGenContext context, uint rd, uint rn, uint rm, uint sz, uint q) + { + InstEmitNeonCommon.EmitVectorBinaryF(context, rd, rn, rm, sz, q, context.Arm64Assembler.FaddSingleAndDouble, context.Arm64Assembler.FaddHalf); + } + + public static void VaddI(CodeGenContext context, uint rd, uint rn, uint rm, uint size, uint q) + { + InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, size, q, context.Arm64Assembler.AddV, context.Arm64Assembler.AddS); + } + + public static void Vaddhn(CodeGenContext context, uint rd, uint rn, uint rm, uint size) + { + InstEmitNeonCommon.EmitVectorBinaryNarrow(context, rd, rn, rm, size, context.Arm64Assembler.Addhn); + } + + public static void Vaddl(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size) + { + InstEmitNeonCommon.EmitVectorBinaryLong(context, rd, rn, rm, size, u ? context.Arm64Assembler.Uaddl : context.Arm64Assembler.Saddl); + } + + public static void Vaddw(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size) + { + InstEmitNeonCommon.EmitVectorBinaryWide(context, rd, rn, rm, size, u ? context.Arm64Assembler.Uaddw : context.Arm64Assembler.Saddw); + } + + public static void VfmaF(CodeGenContext context, uint rd, uint rn, uint rm, uint sz, uint q) + { + InstEmitNeonCommon.EmitVectorTernaryRdF(context, rd, rn, rm, sz, q, context.Arm64Assembler.FmlaVecSingleAndDouble, context.Arm64Assembler.FmlaVecHalf); + } + + public static void VfmsF(CodeGenContext context, uint rd, uint rn, uint rm, uint sz, uint q) + { + InstEmitNeonCommon.EmitVectorTernaryRdF(context, rd, rn, rm, sz, q, context.Arm64Assembler.FmlsVecSingleAndDouble, context.Arm64Assembler.FmlsVecHalf); + } + + public static void Vhadd(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size, uint q) + { + InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, size, q, u ? context.Arm64Assembler.Uhadd : context.Arm64Assembler.Shadd, null); + } + + public static void Vhsub(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size, uint q) + { + InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, size, q, u ? context.Arm64Assembler.Uhsub : context.Arm64Assembler.Shsub, null); + } + + public static void Vmaxnm(CodeGenContext context, uint rd, uint rn, uint rm, uint sz, uint q) + { + InstEmitNeonCommon.EmitVectorBinaryF(context, rd, rn, rm, sz, q, context.Arm64Assembler.FmaxnmSingleAndDouble, context.Arm64Assembler.FmaxnmHalf); + } + + public static void VmaxF(CodeGenContext context, uint rd, uint rn, uint rm, uint sz, uint q) + { + InstEmitNeonCommon.EmitVectorBinaryF(context, rd, rn, rm, sz, q, context.Arm64Assembler.FmaxSingleAndDouble, context.Arm64Assembler.FmaxHalf); + } + + public static void VmaxI(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size, uint q) + { + InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, size, q, u ? context.Arm64Assembler.Umax : context.Arm64Assembler.Smax, null); + } + + public static void Vminnm(CodeGenContext context, uint rd, uint rn, uint rm, uint sz, uint q) + { + InstEmitNeonCommon.EmitVectorBinaryF(context, rd, rn, rm, sz, q, context.Arm64Assembler.FminnmSingleAndDouble, context.Arm64Assembler.FminnmHalf); + } + + public static void VminF(CodeGenContext context, uint rd, uint rn, uint rm, uint sz, uint q) + { + InstEmitNeonCommon.EmitVectorBinaryF(context, rd, rn, rm, sz, q, context.Arm64Assembler.FminSingleAndDouble, context.Arm64Assembler.FminHalf); + } + + public static void VminI(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size, uint q) + { + InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, size, q, u ? context.Arm64Assembler.Umin : context.Arm64Assembler.Smin, null); + } + + public static void VmlaF(CodeGenContext context, uint rd, uint rn, uint rm, uint sz, uint q) + { + InstEmitNeonCommon.EmitVectorTernaryMulNegRdF(context, rd, rn, rm, sz, q, negProduct: false); + } + + public static void VmlaI(CodeGenContext context, uint rd, uint rn, uint rm, uint size, uint q) + { + InstEmitNeonCommon.EmitVectorTernaryRd(context, rd, rn, rm, size, q, context.Arm64Assembler.MlaVec); + } + + public static void VmlaS(CodeGenContext context, uint rd, uint rn, uint rm, bool f, uint size, uint q) + { + if (f) + { + InstEmitNeonCommon.EmitVectorTernaryMulNegRdByScalarAnyF(context, rd, rn, rm, size, q, negProduct: false); + } + else + { + InstEmitNeonCommon.EmitVectorTernaryRdByScalar(context, rd, rn, rm, size, q, context.Arm64Assembler.MlaElt); + } + } + + public static void VmlalI(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size) + { + InstEmitNeonCommon.EmitVectorTernaryRdLong(context, rd, rn, rm, size, u ? context.Arm64Assembler.UmlalVec : context.Arm64Assembler.SmlalVec); + } + + public static void VmlalS(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size) + { + InstEmitNeonCommon.EmitVectorTernaryRdLongByScalar(context, rd, rn, rm, size, u ? context.Arm64Assembler.UmlalElt : context.Arm64Assembler.SmlalElt); + } + + public static void VmlsF(CodeGenContext context, uint rd, uint rn, uint rm, uint sz, uint q) + { + InstEmitNeonCommon.EmitVectorTernaryMulNegRdF(context, rd, rn, rm, sz, q, negProduct: true); + } + + public static void VmlsI(CodeGenContext context, uint rd, uint rn, uint rm, uint size, uint q) + { + InstEmitNeonCommon.EmitVectorTernaryRd(context, rd, rn, rm, size, q, context.Arm64Assembler.MlsVec); + } + + public static void VmlsS(CodeGenContext context, uint rd, uint rn, uint rm, bool f, uint size, uint q) + { + if (f) + { + InstEmitNeonCommon.EmitVectorTernaryMulNegRdByScalarAnyF(context, rd, rn, rm, size, q, negProduct: true); + } + else + { + InstEmitNeonCommon.EmitVectorTernaryRdByScalar(context, rd, rn, rm, size, q, context.Arm64Assembler.MlsElt); + } + } + + public static void VmlslI(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size) + { + InstEmitNeonCommon.EmitVectorTernaryRdLong(context, rd, rn, rm, size, u ? context.Arm64Assembler.UmlslVec : context.Arm64Assembler.SmlslVec); + } + + public static void VmlslS(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size) + { + InstEmitNeonCommon.EmitVectorTernaryRdLongByScalar(context, rd, rn, rm, size, u ? context.Arm64Assembler.UmlslElt : context.Arm64Assembler.SmlslElt); + } + + public static void VmulF(CodeGenContext context, uint rd, uint rn, uint rm, uint sz, uint q) + { + InstEmitNeonCommon.EmitVectorBinaryF(context, rd, rn, rm, sz, q, context.Arm64Assembler.FmulVecSingleAndDouble, context.Arm64Assembler.FmulVecHalf); + } + + public static void VmulI(CodeGenContext context, uint rd, uint rn, uint rm, bool op, uint size, uint q) + { + if (op) + { + // TODO: Feature check, emulation if not supported. + + InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, size, q, context.Arm64Assembler.Pmul, null); + } + else + { + InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, size, q, context.Arm64Assembler.MulVec, null); + } + } + + public static void VmulS(CodeGenContext context, uint rd, uint rn, uint rm, bool f, uint size, uint q) + { + if (f) + { + InstEmitNeonCommon.EmitVectorBinaryByScalarAnyF(context, rd, rn, rm, size, q, context.Arm64Assembler.FmulElt2regElementSingleAndDouble, context.Arm64Assembler.FmulElt2regElementHalf); + } + else + { + InstEmitNeonCommon.EmitVectorBinaryByScalar(context, rd, rn, rm, size, q, context.Arm64Assembler.MulElt); + } + } + + public static void VmullI(CodeGenContext context, uint rd, uint rn, uint rm, bool op, bool u, uint size) + { + if (op) + { + // TODO: Feature check, emulation if not supported. + + InstEmitNeonCommon.EmitVectorBinaryLong(context, rd, rn, rm, size == 2 ? 3 : size, context.Arm64Assembler.Pmull); + } + else + { + InstEmitNeonCommon.EmitVectorBinaryLong(context, rd, rn, rm, size, u ? context.Arm64Assembler.UmullVec : context.Arm64Assembler.SmullVec); + } + } + + public static void VmullS(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size) + { + InstEmitNeonCommon.EmitVectorBinaryLongByScalar(context, rd, rn, rm, size, u ? context.Arm64Assembler.UmullElt : context.Arm64Assembler.SmullElt); + } + + public static void Vneg(CodeGenContext context, uint rd, uint rm, bool f, uint size, uint q) + { + if (f) + { + InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FnegSingleAndDouble, context.Arm64Assembler.FnegHalf); + } + else + { + InstEmitNeonCommon.EmitVectorUnary(context, rd, rm, size, q, context.Arm64Assembler.NegV); + } + } + + public static void Vpadal(CodeGenContext context, uint rd, uint rm, bool op, uint size, uint q) + { + InstEmitNeonCommon.EmitVectorBinaryRd(context, rd, rm, size, q, op ? context.Arm64Assembler.Uadalp : context.Arm64Assembler.Sadalp); + } + + public static void VpaddF(CodeGenContext context, uint rd, uint rn, uint rm, uint sz, uint q) + { + InstEmitNeonCommon.EmitVectorBinaryF(context, rd, rn, rm, sz, q, context.Arm64Assembler.FaddpVecSingleAndDouble, context.Arm64Assembler.FaddpVecHalf); + } + + public static void VpaddI(CodeGenContext context, uint rd, uint rn, uint rm, uint size, uint q) + { + InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, size, q, context.Arm64Assembler.AddpVec, null); + } + + public static void Vpaddl(CodeGenContext context, uint rd, uint rm, bool op, uint size, uint q) + { + InstEmitNeonCommon.EmitVectorUnary(context, rd, rm, size, q, op ? context.Arm64Assembler.Uaddlp : context.Arm64Assembler.Saddlp); + } + + public static void VpmaxF(CodeGenContext context, uint rd, uint rn, uint rm, uint sz, uint q) + { + InstEmitNeonCommon.EmitVectorBinaryF(context, rd, rn, rm, sz, q, context.Arm64Assembler.FmaxpVecSingleAndDouble, context.Arm64Assembler.FmaxpVecHalf); + } + + public static void VpmaxI(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size, uint q) + { + InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, size, q, u ? context.Arm64Assembler.Umaxp : context.Arm64Assembler.Smaxp, null); + } + + public static void VpminF(CodeGenContext context, uint rd, uint rn, uint rm, uint sz, uint q) + { + InstEmitNeonCommon.EmitVectorBinaryF(context, rd, rn, rm, sz, q, context.Arm64Assembler.FminpVecSingleAndDouble, context.Arm64Assembler.FminpVecHalf); + } + + public static void VpminI(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size, uint q) + { + InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, size, q, u ? context.Arm64Assembler.Uminp : context.Arm64Assembler.Sminp, null); + } + + public static void Vrecpe(CodeGenContext context, uint rd, uint rm, bool f, uint size, uint q) + { + if (f) + { + InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FrecpeV, context.Arm64Assembler.FrecpeVH); + } + else + { + throw new NotImplementedException(); + } + } + + public static void Vrecps(CodeGenContext context, uint rd, uint rn, uint rm, uint sz, uint q) + { + InstEmitNeonCommon.EmitVectorBinaryF(context, rd, rn, rm, sz, q, context.Arm64Assembler.FrecpsV, context.Arm64Assembler.FrecpsVH); + } + + public static void Vrsqrte(CodeGenContext context, uint rd, uint rm, bool f, uint size, uint q) + { + if (f) + { + InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FrsqrteV, context.Arm64Assembler.FrsqrteVH); + } + else + { + throw new NotImplementedException(); + } + } + + public static void Vrsqrts(CodeGenContext context, uint rd, uint rn, uint rm, uint sz, uint q) + { + InstEmitNeonCommon.EmitVectorBinaryF(context, rd, rn, rm, sz, q, context.Arm64Assembler.FrsqrtsV, context.Arm64Assembler.FrsqrtsVH); + } + + public static void VsubF(CodeGenContext context, uint rd, uint rn, uint rm, uint sz, uint q) + { + InstEmitNeonCommon.EmitVectorBinaryF(context, rd, rn, rm, sz, q, context.Arm64Assembler.FsubSingleAndDouble, context.Arm64Assembler.FsubHalf); + } + + public static void VsubI(CodeGenContext context, uint rd, uint rn, uint rm, uint size, uint q) + { + InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, size, q, context.Arm64Assembler.SubV, context.Arm64Assembler.SubS); + } + + public static void Vsubhn(CodeGenContext context, uint rd, uint rn, uint rm, uint size) + { + InstEmitNeonCommon.EmitVectorBinaryNarrow(context, rd, rn, rm, size, context.Arm64Assembler.Subhn); + } + + public static void Vsubl(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size) + { + InstEmitNeonCommon.EmitVectorBinaryLong(context, rd, rn, rm, size, u ? context.Arm64Assembler.Usubl : context.Arm64Assembler.Ssubl); + } + + public static void Vsubw(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size) + { + InstEmitNeonCommon.EmitVectorBinaryWide(context, rd, rn, rm, size, u ? context.Arm64Assembler.Usubw : context.Arm64Assembler.Ssubw); + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonBit.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonBit.cs new file mode 100644 index 000000000..9601f4c27 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonBit.cs @@ -0,0 +1,35 @@ +namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 +{ + static class InstEmitNeonBit + { + public static void Vcls(CodeGenContext context, uint rd, uint rm, uint size, uint q) + { + InstEmitNeonCommon.EmitVectorUnary(context, rd, rm, size, q, context.Arm64Assembler.Cls); + } + + public static void Vclz(CodeGenContext context, uint rd, uint rm, uint size, uint q) + { + InstEmitNeonCommon.EmitVectorUnary(context, rd, rm, size, q, context.Arm64Assembler.Clz); + } + + public static void Vcnt(CodeGenContext context, uint rd, uint rm, uint size, uint q) + { + InstEmitNeonCommon.EmitVectorUnary(context, rd, rm, size, q, context.Arm64Assembler.Cnt); + } + + public static void Vrev16(CodeGenContext context, uint rd, uint rm, uint size, uint q) + { + InstEmitNeonCommon.EmitVectorUnary(context, rd, rm, size, q, context.Arm64Assembler.Rev16); + } + + public static void Vrev32(CodeGenContext context, uint rd, uint rm, uint size, uint q) + { + InstEmitNeonCommon.EmitVectorUnary(context, rd, rm, size, q, context.Arm64Assembler.Rev32); + } + + public static void Vrev64(CodeGenContext context, uint rd, uint rm, uint size, uint q) + { + InstEmitNeonCommon.EmitVectorUnary(context, rd, rm, size, q, context.Arm64Assembler.Rev64); + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonCommon.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonCommon.cs new file mode 100644 index 000000000..dce6556e4 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonCommon.cs @@ -0,0 +1,1513 @@ + +using Ryujinx.Cpu.LightningJit.CodeGen; +using System; +using System.Diagnostics; + +namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 +{ + static class InstEmitNeonCommon + { + public static ScopedRegister MoveScalarToSide(CodeGenContext context, uint srcReg, bool isFP32, bool forceAllocation = false) + { + int shift = isFP32 ? 2 : 1; + uint mask = isFP32 ? 3u : 1u; + uint elt = srcReg & mask; + + if (elt == 0 && !forceAllocation) + { + return new ScopedRegister(context.RegisterAllocator, context.RegisterAllocator.RemapFpRegister((int)(srcReg >> shift), isFP32), false); + } + + Operand source = context.RegisterAllocator.RemapSimdRegister((int)(srcReg >> shift)); + ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempFpRegisterScoped(isFP32); + + uint imm5 = GetImm5ForElementIndex(elt, isFP32); + + context.Arm64Assembler.DupEltScalarFromElement(tempRegister.Operand, source, imm5); + + return tempRegister; + } + + public static ScopedRegister Move16BitScalarToSide(CodeGenContext context, uint srcReg, bool top = false) + { + uint elt = srcReg & 3; + + Operand source = context.RegisterAllocator.RemapSimdRegister((int)(srcReg >> 2)); + ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempFpRegisterScoped(true); + + uint imm5 = GetImm5ForElementIndex((elt << 1) | (top ? 1u : 0u), 1); + + context.Arm64Assembler.DupEltScalarFromElement(tempRegister.Operand, source, imm5); + + return tempRegister; + } + + public static void MoveScalarToSide(CodeGenContext context, Operand dest, uint srcReg, bool isFP32) + { + int shift = isFP32 ? 2 : 1; + uint mask = isFP32 ? 3u : 1u; + uint elt = srcReg & mask; + + Operand source = context.RegisterAllocator.RemapSimdRegister((int)(srcReg >> shift)); + + uint imm5 = GetImm5ForElementIndex(elt, isFP32); + + context.Arm64Assembler.DupEltScalarFromElement(dest, source, imm5); + } + + public static ScopedRegister MoveScalarToSideIntoGpr(CodeGenContext context, uint srcReg, bool isFP32) + { + int shift = isFP32 ? 2 : 1; + uint mask = isFP32 ? 3u : 1u; + uint elt = srcReg & mask; + + Operand source = context.RegisterAllocator.RemapSimdRegister((int)(srcReg >> shift)); + ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + context.Arm64Assembler.Umov(tempRegister.Operand, source, (int)elt, isFP32 ? 2 : 3); + + return tempRegister; + } + + public static void InsertResult(CodeGenContext context, Operand source, uint dstReg, bool isFP32) + { + int shift = isFP32 ? 2 : 1; + uint mask = isFP32 ? 3u : 1u; + uint elt = dstReg & mask; + + uint imm5 = GetImm5ForElementIndex(elt, isFP32); + + Operand dest = context.RegisterAllocator.RemapSimdRegister((int)(dstReg >> shift)); + + context.Arm64Assembler.InsElt(dest, source, 0, imm5); + } + + public static void Insert16BitResult(CodeGenContext context, Operand source, uint dstReg, bool top = false) + { + uint elt = dstReg & 3u; + + uint imm5 = GetImm5ForElementIndex((elt << 1) | (top ? 1u : 0u), 1); + + Operand dest = context.RegisterAllocator.RemapSimdRegister((int)(dstReg >> 2)); + + context.Arm64Assembler.InsElt(dest, source, 0, imm5); + } + + public static void InsertResultFromGpr(CodeGenContext context, Operand source, uint dstReg, bool isFP32) + { + int shift = isFP32 ? 2 : 1; + uint mask = isFP32 ? 3u : 1u; + uint elt = dstReg & mask; + + uint imm5 = GetImm5ForElementIndex(elt, isFP32); + + Operand dest = context.RegisterAllocator.RemapSimdRegister((int)(dstReg >> shift)); + + context.Arm64Assembler.InsGen(dest, source, imm5); + } + + public static uint GetImm5ForElementIndex(uint elt, bool isFP32) + { + return isFP32 ? (4u | (elt << 3)) : (8u | (elt << 4)); + } + + public static uint GetImm5ForElementIndex(uint elt, uint size) + { + return (1u << (int)size) | (elt << ((int)size + 1)); + } + + public static void EmitScalarUnaryF(CodeGenContext context, uint rd, uint rm, uint size, Action action) + { + Debug.Assert(size == 1 || size == 2 || size == 3); + + bool singleRegs = size != 3; + + using ScopedRegister rmReg = MoveScalarToSide(context, rm, singleRegs); + + using ScopedRegister tempRegister = PickSimdRegister(context.RegisterAllocator, rmReg); + + action(tempRegister.Operand, rmReg.Operand, size ^ 2u); + + InsertResult(context, tempRegister.Operand, rd, singleRegs); + } + + public static void EmitScalarUnaryF(CodeGenContext context, uint rd, uint rm, uint size, Action action, Action actionHalf) + { + Debug.Assert(size == 1 || size == 2 || size == 3); + + bool singleRegs = size != 3; + + using ScopedRegister rmReg = MoveScalarToSide(context, rm, singleRegs); + + using ScopedRegister tempRegister = PickSimdRegister(context.RegisterAllocator, rmReg); + + if (size == 1) + { + actionHalf(tempRegister.Operand, rmReg.Operand); + } + else + { + action(tempRegister.Operand, rmReg.Operand, size & 1); + } + + InsertResult(context, tempRegister.Operand, rd, singleRegs); + } + + public static void EmitScalarUnaryToGprTempF( + CodeGenContext context, + uint rd, + uint rm, + uint size, + uint sf, + Action action) + { + Debug.Assert(size == 1 || size == 2 || size == 3); + + bool singleRegs = size != 3; + + using ScopedRegister rmReg = MoveScalarToSide(context, rm, singleRegs); + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + action(tempRegister.Operand, rmReg.Operand, size ^ 2u, sf); + + InsertResultFromGpr(context, tempRegister.Operand, rd, sf == 0); + } + + public static void EmitScalarUnaryFromGprTempF( + CodeGenContext context, + uint rd, + uint rm, + uint size, + uint sf, + Action action) + { + Debug.Assert(size == 1 || size == 2 || size == 3); + + bool singleRegs = size != 3; + + using ScopedRegister rmReg = MoveScalarToSideIntoGpr(context, rm, sf == 0); + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped(); + + action(tempRegister.Operand, rmReg.Operand, size ^ 2u, sf); + + InsertResult(context, tempRegister.Operand, rd, singleRegs); + } + + public static void EmitScalarUnaryFixedF(CodeGenContext context, uint rd, uint rm, uint fbits, uint size, bool is16Bit, Action action) + { + Debug.Assert(size == 1 || size == 2 || size == 3); + + bool singleRegs = size != 3; + + (uint immb, uint immh) = GetImmbImmh(fbits, size); + + using ScopedRegister rmReg = is16Bit ? Move16BitScalarToSide(context, rm) : MoveScalarToSide(context, rm, singleRegs); + + using ScopedRegister tempRegister = PickSimdRegister(context.RegisterAllocator, rmReg); + + action(tempRegister.Operand, rmReg.Operand, immb, immh); + + InsertResult(context, tempRegister.Operand, rd, singleRegs); + } + + public static void EmitScalarBinaryF(CodeGenContext context, uint rd, uint rn, uint rm, uint size, Action action) + { + Debug.Assert(size == 1 || size == 2 || size == 3); + + bool singleRegs = size != 3; + + using ScopedRegister rnReg = MoveScalarToSide(context, rn, singleRegs); + using ScopedRegister rmReg = MoveScalarToSide(context, rm, singleRegs); + + using ScopedRegister tempRegister = PickSimdRegister(context.RegisterAllocator, rnReg, rmReg); + + action(tempRegister.Operand, rnReg.Operand, rmReg.Operand, size ^ 2u); + + InsertResult(context, tempRegister.Operand, rd, singleRegs); + } + + public static void EmitScalarBinaryShift( + CodeGenContext context, + uint rd, + uint rm, + uint shift, + uint size, + bool isShl, + Action action) + { + bool singleRegs = size != 3; + + (uint immb, uint immh) = GetImmbImmhForShift(shift, size, isShl); + + using ScopedRegister rmReg = MoveScalarToSide(context, rm, singleRegs); + + using ScopedRegister tempRegister = PickSimdRegister(context.RegisterAllocator, rmReg); + + action(tempRegister.Operand, rmReg.Operand, immb, immh); + + InsertResult(context, tempRegister.Operand, rd, singleRegs); + } + + public static void EmitScalarTernaryRdF(CodeGenContext context, uint rd, uint rn, uint rm, uint size, Action action) + { + Debug.Assert(size == 1 || size == 2 || size == 3); + + bool singleRegs = size != 3; + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped(); + + MoveScalarToSide(context, tempRegister.Operand, rd, singleRegs); + + using ScopedRegister rnReg = MoveScalarToSide(context, rn, singleRegs); + using ScopedRegister rmReg = MoveScalarToSide(context, rm, singleRegs); + + action(tempRegister.Operand, rnReg.Operand, rmReg.Operand, size ^ 2u); + + InsertResult(context, tempRegister.Operand, rd, singleRegs); + } + + public static void EmitScalarTernaryRdF( + CodeGenContext context, + uint rd, + uint rn, + uint rm, + uint size, + Action action) + { + Debug.Assert(size == 1 || size == 2 || size == 3); + + bool singleRegs = size != 3; + + using ScopedRegister rdReg = MoveScalarToSide(context, rd, singleRegs); + using ScopedRegister rnReg = MoveScalarToSide(context, rn, singleRegs); + using ScopedRegister rmReg = MoveScalarToSide(context, rm, singleRegs); + + using ScopedRegister tempRegister = PickSimdRegister(context.RegisterAllocator, rdReg, rnReg, rmReg); + + action(tempRegister.Operand, rnReg.Operand, rmReg.Operand, rdReg.Operand, size ^ 2u); + + InsertResult(context, tempRegister.Operand, rd, singleRegs); + } + + public static void EmitScalarTernaryMulNegRdF( + CodeGenContext context, + uint rd, + uint rn, + uint rm, + uint size, + bool negD, + bool negProduct) + { + Debug.Assert(size == 1 || size == 2 || size == 3); + + bool singleRegs = size != 3; + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped(); + + MoveScalarToSide(context, tempRegister.Operand, rd, singleRegs); + + using ScopedRegister rnReg = MoveScalarToSide(context, rn, singleRegs); + using ScopedRegister rmReg = MoveScalarToSide(context, rm, singleRegs); + + using ScopedRegister productRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped(); + + uint ftype = size ^ 2u; + + context.Arm64Assembler.FmulFloat(productRegister.Operand, rnReg.Operand, rmReg.Operand, ftype); + + if (negD) + { + context.Arm64Assembler.FnegFloat(tempRegister.Operand, tempRegister.Operand, ftype); + } + + if (negProduct) + { + context.Arm64Assembler.FnegFloat(productRegister.Operand, productRegister.Operand, ftype); + } + + context.Arm64Assembler.FaddFloat(tempRegister.Operand, tempRegister.Operand, productRegister.Operand, ftype); + + InsertResult(context, tempRegister.Operand, rd, singleRegs); + } + + public static void EmitVectorUnary(CodeGenContext context, uint rd, uint rm, Action action) + { + Debug.Assert(((rd | rm) & 1) == 0); + + Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1)); + Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1)); + + action(rdOperand, rmOperand); + } + + public static void EmitVectorUnary(CodeGenContext context, uint rd, uint rm, uint q, Action action) + { + if (q == 0) + { + using ScopedRegister rmReg = MoveScalarToSide(context, rm, false); + + using ScopedRegister tempRegister = PickSimdRegister(context.RegisterAllocator, rmReg); + + action(tempRegister.Operand, rmReg.Operand, q); + + InsertResult(context, tempRegister.Operand, rd, false); + } + else + { + Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1)); + Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1)); + + action(rdOperand, rmOperand, q); + } + } + + public static void EmitVectorUnary(CodeGenContext context, uint rd, uint rm, uint size, uint q, Action action) + { + Debug.Assert(size < 3); + + if (q == 0) + { + using ScopedRegister rmReg = MoveScalarToSide(context, rm, false); + + using ScopedRegister tempRegister = PickSimdRegister(context.RegisterAllocator, rmReg); + + action(tempRegister.Operand, rmReg.Operand, size, q); + + InsertResult(context, tempRegister.Operand, rd, false); + } + else + { + Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1)); + Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1)); + + action(rdOperand, rmOperand, size, q); + } + } + + public static void EmitVectorUnaryLong(CodeGenContext context, uint rd, uint rm, uint size, Action action) + { + Debug.Assert((rd & 1) == 0); + + Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1)); + Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1)); + + uint q = rm & 1; + + action(rdOperand, rmOperand, size, q); + } + + public static void EmitVectorUnaryNarrow(CodeGenContext context, uint rd, uint rm, uint size, Action action) + { + Debug.Assert((rm & 1) == 0); + + Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1)); + Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1)); + + uint q = rd & 1; + + if (q == 0) + { + // Writing to the lower half would clear the higher bits, we don't want that, so use a temp register and move the element. + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped(); + + action(tempRegister.Operand, rmOperand, size, q); + + InsertResult(context, tempRegister.Operand, rd, false); + } + else + { + action(rdOperand, rmOperand, size, q); + } + } + + public static void EmitVectorBinary(CodeGenContext context, uint rd, uint rn, uint rm, Action action) + { + Debug.Assert(((rd | rn | rm) & 1) == 0); + + Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1)); + Operand rnOperand = context.RegisterAllocator.RemapSimdRegister((int)(rn >> 1)); + Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1)); + + action(rdOperand, rnOperand, rmOperand); + } + + public static void EmitVectorBinary(CodeGenContext context, uint rd, uint rn, uint rm, uint q, Action action) + { + if (q == 0) + { + using ScopedRegister rnReg = MoveScalarToSide(context, rn, false); + using ScopedRegister rmReg = MoveScalarToSide(context, rm, false); + + using ScopedRegister tempRegister = PickSimdRegister(context.RegisterAllocator, rnReg, rmReg); + + action(tempRegister.Operand, rnReg.Operand, rmReg.Operand, q); + + InsertResult(context, tempRegister.Operand, rd, false); + } + else + { + Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1)); + Operand rnOperand = context.RegisterAllocator.RemapSimdRegister((int)(rn >> 1)); + Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1)); + + action(rdOperand, rnOperand, rmOperand, q); + } + } + + public static void EmitVectorBinary( + CodeGenContext context, + uint rd, + uint rn, + uint rm, + uint size, + uint q, + Action action, + Action actionScalar) + { + Debug.Assert(size <= 3); + + if (q == 0) + { + using ScopedRegister rnReg = MoveScalarToSide(context, rn, false); + using ScopedRegister rmReg = MoveScalarToSide(context, rm, false); + + using ScopedRegister tempRegister = PickSimdRegister(context.RegisterAllocator, rnReg, rmReg); + + if (size == 3) + { + actionScalar(tempRegister.Operand, rnReg.Operand, rmReg.Operand, size); + } + else + { + action(tempRegister.Operand, rnReg.Operand, rmReg.Operand, size, q); + } + + InsertResult(context, tempRegister.Operand, rd, false); + } + else + { + Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1)); + Operand rnOperand = context.RegisterAllocator.RemapSimdRegister((int)(rn >> 1)); + Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1)); + + action(rdOperand, rnOperand, rmOperand, size, q); + } + } + + public static void EmitVectorBinaryRd(CodeGenContext context, uint rd, uint rm, uint size, uint q, Action action) + { + Debug.Assert(size < 3); + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped(); + + MoveScalarToSide(context, tempRegister.Operand, rd, false); + + using ScopedRegister rmReg = MoveScalarToSide(context, rm, false); + + action(tempRegister.Operand, rmReg.Operand, size, q); + + InsertResult(context, tempRegister.Operand, rd, false); + } + + public static void EmitVectorBinaryShift( + CodeGenContext context, + uint rd, + uint rm, + uint shift, + uint size, + uint q, + bool isShl, + Action action, + Action actionScalar) + { + (uint immb, uint immh) = GetImmbImmhForShift(shift, size, isShl); + + if (q == 0) + { + using ScopedRegister rmReg = MoveScalarToSide(context, rm, false); + + using ScopedRegister tempRegister = PickSimdRegister(context.RegisterAllocator, rmReg); + + if (size == 3) + { + actionScalar(tempRegister.Operand, rmReg.Operand, immb, immh); + } + else + { + action(tempRegister.Operand, rmReg.Operand, immb, immh, q); + } + + InsertResult(context, tempRegister.Operand, rd, false); + } + else + { + Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1)); + Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1)); + + action(rdOperand, rmOperand, immb, immh, q); + } + } + + public static void EmitVectorBinaryLong(CodeGenContext context, uint rd, uint rn, uint rm, uint size, Action action) + { + Debug.Assert((rd & 1) == 0); + + Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1)); + + if ((rn & 1) == (rm & 1)) + { + // Both inputs are on the same side of the vector, so we can use the variant that selects the half. + + Operand rnOperand = context.RegisterAllocator.RemapSimdRegister((int)(rn >> 1)); + Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1)); + + uint q = rn & 1; + + action(rdOperand, rnOperand, rmOperand, size, q); + } + else + { + // Inputs are on different sides of the vector, we have to move them. + + using ScopedRegister rnReg = MoveScalarToSide(context, rn, false); + using ScopedRegister rmReg = MoveScalarToSide(context, rm, false); + + action(rdOperand, rnReg.Operand, rmReg.Operand, size, 0); + } + } + + public static void EmitVectorBinaryLongShift( + CodeGenContext context, + uint rd, + uint rn, + uint shift, + uint size, + bool isShl, + Action action) + { + (uint immb, uint immh) = GetImmbImmhForShift(shift, size, isShl); + + Debug.Assert((rd & 1) == 0); + + Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1)); + Operand rnOperand = context.RegisterAllocator.RemapSimdRegister((int)(rn >> 1)); + + uint q = rn & 1; + + action(rdOperand, rnOperand, immb, immh, q); + } + + public static void EmitVectorBinaryLongByScalar( + CodeGenContext context, + uint rd, + uint rn, + uint rm, + uint size, + Action action) + { + Debug.Assert((rd & 1) == 0); + + (uint h, uint l, uint m) = GetIndexForReg(ref rm, size); + + Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1)); + Operand rnOperand = context.RegisterAllocator.RemapSimdRegister((int)(rn >> 1)); + Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1)); + + uint q = rn & 1; + + action(rdOperand, rnOperand, h, rmOperand, m, l, size, q); + } + + public static void EmitVectorBinaryNarrow( + CodeGenContext context, + uint rd, + uint rn, + uint rm, + uint size, + Action action) + { + Debug.Assert((rn & 1) == 0); + Debug.Assert((rm & 1) == 0); + + Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1)); + Operand rnOperand = context.RegisterAllocator.RemapSimdRegister((int)(rn >> 1)); + Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1)); + + uint q = rd & 1; + + if (q == 0) + { + // Writing to the lower half would clear the higher bits, we don't want that, so use a temp register and move the element. + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped(); + + action(tempRegister.Operand, rnOperand, rmOperand, size, q); + + InsertResult(context, tempRegister.Operand, rd, false); + } + else + { + action(rdOperand, rnOperand, rmOperand, size, q); + } + } + + public static void EmitVectorBinaryNarrowShift( + CodeGenContext context, + uint rd, + uint rm, + uint shift, + uint size, + bool isShl, + Action action) + { + (uint immb, uint immh) = GetImmbImmhForShift(shift, size, isShl); + + Debug.Assert((rm & 1) == 0); + + Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1)); + Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1)); + + uint q = rd & 1; + + if (q == 0) + { + // Writing to the lower half would clear the higher bits, we don't want that, so use a temp register and move the element. + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped(); + + action(tempRegister.Operand, rmOperand, immb, immh, q); + + InsertResult(context, tempRegister.Operand, rd, false); + } + else + { + action(rdOperand, rmOperand, immb, immh, q); + } + } + + public static void EmitVectorBinaryWide(CodeGenContext context, uint rd, uint rn, uint rm, uint size, Action action) + { + Debug.Assert(((rd | rn) & 1) == 0); + + Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1)); + Operand rnOperand = context.RegisterAllocator.RemapSimdRegister((int)(rn >> 1)); + Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1)); + + uint q = rm & 1; + + action(rdOperand, rnOperand, rmOperand, size, q); + } + + public static void EmitVectorBinaryByScalar( + CodeGenContext context, + uint rd, + uint rn, + uint rm, + uint size, + uint q, + Action action) + { + EmitVectorByScalarCore(context, rd, rn, rm, size, q, action, isTernary: false); + } + + public static void EmitVectorTernaryRd(CodeGenContext context, uint rd, uint rn, uint rm, uint q, Action action) + { + if (q == 0) + { + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped(); + + MoveScalarToSide(context, tempRegister.Operand, rd, false); + + using ScopedRegister rnReg = MoveScalarToSide(context, rn, false); + using ScopedRegister rmReg = MoveScalarToSide(context, rm, false); + + action(tempRegister.Operand, rnReg.Operand, rmReg.Operand, q); + + InsertResult(context, tempRegister.Operand, rd, false); + } + else + { + Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1)); + Operand rnOperand = context.RegisterAllocator.RemapSimdRegister((int)(rn >> 1)); + Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1)); + + action(rdOperand, rnOperand, rmOperand, q); + } + } + + public static void EmitVectorTernaryRd(CodeGenContext context, uint rd, uint rn, uint rm, uint size, uint q, Action action) + { + if (q == 0) + { + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped(); + + MoveScalarToSide(context, tempRegister.Operand, rd, false); + + using ScopedRegister rnReg = MoveScalarToSide(context, rn, false); + using ScopedRegister rmReg = MoveScalarToSide(context, rm, false); + + action(tempRegister.Operand, rnReg.Operand, rmReg.Operand, size, q); + + InsertResult(context, tempRegister.Operand, rd, false); + } + else + { + Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1)); + Operand rnOperand = context.RegisterAllocator.RemapSimdRegister((int)(rn >> 1)); + Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1)); + + action(rdOperand, rnOperand, rmOperand, size, q); + } + } + + public static void EmitVectorTernaryRdLong(CodeGenContext context, uint rd, uint rn, uint rm, uint size, Action action) + { + Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1)); + + if ((rn & 1) == (rm & 1)) + { + // Both inputs are on the same side of the vector, so we can use the variant that selects the half. + + Operand rnOperand = context.RegisterAllocator.RemapSimdRegister((int)(rn >> 1)); + Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1)); + + uint q = rn & 1; + + action(rdOperand, rnOperand, rmOperand, size, q); + } + else + { + // Inputs are on different sides of the vector, we have to move them. + + using ScopedRegister rnReg = MoveScalarToSide(context, rn, false); + using ScopedRegister rmReg = MoveScalarToSide(context, rm, false); + + action(rdOperand, rnReg.Operand, rmReg.Operand, size, 0); + } + } + + public static void EmitVectorTernaryRdLongByScalar( + CodeGenContext context, + uint rd, + uint rn, + uint rm, + uint size, + Action action) + { + (uint h, uint l, uint m) = GetIndexForReg(ref rm, size); + + Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1)); + Operand rnOperand = context.RegisterAllocator.RemapSimdRegister((int)(rn >> 1)); + Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1)); + + uint q = rn & 1; + + action(rdOperand, rnOperand, h, rmOperand, m, l, size, q); + } + + public static void EmitVectorTernaryRdShift( + CodeGenContext context, + uint rd, + uint rm, + uint shift, + uint size, + uint q, + bool isShl, + Action action, + Action actionScalar) + { + (uint immb, uint immh) = GetImmbImmhForShift(shift, size, isShl); + + if (q == 0) + { + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped(); + + MoveScalarToSide(context, tempRegister.Operand, rd, false); + + using ScopedRegister rmReg = MoveScalarToSide(context, rm, false); + + if (size == 3) + { + actionScalar(tempRegister.Operand, rmReg.Operand, immb, immh); + } + else + { + action(tempRegister.Operand, rmReg.Operand, immb, immh, q); + } + + InsertResult(context, tempRegister.Operand, rd, false); + } + else + { + Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1)); + Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1)); + + action(rdOperand, rmOperand, immb, immh, q); + } + } + + public static void EmitVectorTernaryRdByScalar( + CodeGenContext context, + uint rd, + uint rn, + uint rm, + uint size, + uint q, + Action action) + { + EmitVectorByScalarCore(context, rd, rn, rm, size, q, action, isTernary: true); + } + + private static void EmitVectorByScalarCore( + CodeGenContext context, + uint rd, + uint rn, + uint rm, + uint size, + uint q, + Action action, + bool isTernary) + { + (uint h, uint l, uint m) = GetIndexForReg(ref rm, size); + + Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1)); + + if (q == 0) + { + if (isTernary) + { + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped(); + + MoveScalarToSide(context, tempRegister.Operand, rd, false); + + using ScopedRegister rnReg = MoveScalarToSide(context, rn, false); + + action(tempRegister.Operand, rnReg.Operand, h, rmOperand, m, l, size, q); + + InsertResult(context, tempRegister.Operand, rd, false); + } + else + { + using ScopedRegister rnReg = MoveScalarToSide(context, rn, false); + + using ScopedRegister tempRegister = PickSimdRegister(context.RegisterAllocator, rnReg); + + action(tempRegister.Operand, rnReg.Operand, h, rmOperand, m, l, size, q); + + InsertResult(context, tempRegister.Operand, rd, false); + } + } + else + { + Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1)); + Operand rnOperand = context.RegisterAllocator.RemapSimdRegister((int)(rn >> 1)); + + action(rdOperand, rnOperand, h, rmOperand, m, l, size, q); + } + } + + public static void EmitVectorUnaryF( + CodeGenContext context, + uint rd, + uint rm, + uint sz, + uint q, + Action action, + Action actionHalf) + { + Debug.Assert(sz == 0 || sz == 1); + + if (q == 0) + { + using ScopedRegister rmReg = MoveScalarToSide(context, rm, false); + + using ScopedRegister tempRegister = PickSimdRegister(context.RegisterAllocator, rmReg); + + if (sz == 1) + { + actionHalf(tempRegister.Operand, rmReg.Operand, q); + } + else + { + action(tempRegister.Operand, rmReg.Operand, 0, q); + } + + InsertResult(context, tempRegister.Operand, rd, false); + } + else + { + Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1)); + Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1)); + + if (sz == 1) + { + actionHalf(rdOperand, rmOperand, q); + } + else + { + action(rdOperand, rmOperand, 0, q); + } + } + } + + public static void EmitVectorUnaryAnyF( + CodeGenContext context, + uint rd, + uint rm, + uint size, + uint q, + Action action, + Action actionHalf) + { + Debug.Assert(size == 1 || size == 2 || size == 3); + Debug.Assert(size != 3 || q == 1); + + if (q == 0) + { + using ScopedRegister rmReg = MoveScalarToSide(context, rm, false); + + using ScopedRegister tempRegister = PickSimdRegister(context.RegisterAllocator, rmReg); + + if (size == 1) + { + actionHalf(tempRegister.Operand, rmReg.Operand, q); + } + else + { + action(tempRegister.Operand, rmReg.Operand, size ^ 2u, q); + } + + InsertResult(context, tempRegister.Operand, rd, false); + } + else + { + Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1)); + Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1)); + + if (size == 1) + { + actionHalf(rdOperand, rmOperand, q); + } + else + { + action(rdOperand, rmOperand, size ^ 2u, q); + } + } + } + + public static void EmitVectorUnaryFixedAnyF( + CodeGenContext context, + uint rd, + uint rm, + uint fbits, + uint size, + uint q, + Action action) + { + Debug.Assert(size == 1 || size == 2 || size == 3); + Debug.Assert(size != 3 || q == 1); + + (uint immb, uint immh) = GetImmbImmh(fbits, size); + + if (q == 0) + { + using ScopedRegister rmReg = MoveScalarToSide(context, rm, false); + using ScopedRegister tempRegister = PickSimdRegister(context.RegisterAllocator, rmReg); + + action(tempRegister.Operand, rmReg.Operand, immb, immh, q); + + InsertResult(context, tempRegister.Operand, rd, false); + } + else + { + Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1)); + Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1)); + + action(rdOperand, rmOperand, immb, immh, q); + } + } + + public static void EmitVectorBinaryF( + CodeGenContext context, + uint rd, + uint rn, + uint rm, + uint sz, + uint q, + Action action, + Action actionHalf) + { + Debug.Assert(sz == 0 || sz == 1); + + if (q == 0) + { + using ScopedRegister rnReg = MoveScalarToSide(context, rn, false); + using ScopedRegister rmReg = MoveScalarToSide(context, rm, false); + + using ScopedRegister tempRegister = PickSimdRegister(context.RegisterAllocator, rnReg, rmReg); + + if (sz == 1) + { + actionHalf(tempRegister.Operand, rnReg.Operand, rmReg.Operand, q); + } + else + { + action(tempRegister.Operand, rnReg.Operand, rmReg.Operand, 0, q); + } + + InsertResult(context, tempRegister.Operand, rd, false); + } + else + { + Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1)); + Operand rnOperand = context.RegisterAllocator.RemapSimdRegister((int)(rn >> 1)); + Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1)); + + if (sz == 1) + { + actionHalf(rdOperand, rnOperand, rmOperand, q); + } + else + { + action(rdOperand, rnOperand, rmOperand, 0, q); + } + } + } + + public static void EmitVectorBinaryByScalarAnyF( + CodeGenContext context, + uint rd, + uint rn, + uint rm, + uint size, + uint q, + Action action, + Action actionHalf) + { + EmitVectorByScalarAnyFCore(context, rd, rn, rm, size, q, action, actionHalf, isTernary: false); + } + + public static void EmitVectorTernaryRdF( + CodeGenContext context, + uint rd, + uint rn, + uint rm, + uint sz, + uint q, + Action action, + Action actionHalf) + { + Debug.Assert(sz == 0 || sz == 1); + + if (q == 0) + { + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped(); + + MoveScalarToSide(context, tempRegister.Operand, rd, false); + + using ScopedRegister rnReg = MoveScalarToSide(context, rn, false); + using ScopedRegister rmReg = MoveScalarToSide(context, rm, false); + + if (sz == 1) + { + actionHalf(tempRegister.Operand, rnReg.Operand, rmReg.Operand, q); + } + else + { + action(tempRegister.Operand, rnReg.Operand, rmReg.Operand, 0, q); + } + + InsertResult(context, tempRegister.Operand, rd, false); + } + else + { + Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1)); + Operand rnOperand = context.RegisterAllocator.RemapSimdRegister((int)(rn >> 1)); + Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1)); + + if (sz == 1) + { + actionHalf(rdOperand, rnOperand, rmOperand, q); + } + else + { + action(rdOperand, rnOperand, rmOperand, 0, q); + } + } + } + + public static void EmitVectorTernaryMulNegRdF( + CodeGenContext context, + uint rd, + uint rn, + uint rm, + uint sz, + uint q, + bool negProduct) + { + Debug.Assert(sz == 0 || sz == 1); + + if (q == 0) + { + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped(); + + MoveScalarToSide(context, tempRegister.Operand, rd, false); + + using ScopedRegister rnReg = MoveScalarToSide(context, rn, false); + using ScopedRegister rmReg = MoveScalarToSide(context, rm, false); + + EmitMulNegVector(context, tempRegister.Operand, rnReg.Operand, rmReg.Operand, sz, q, negProduct); + + InsertResult(context, tempRegister.Operand, rd, false); + } + else + { + Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1)); + Operand rnOperand = context.RegisterAllocator.RemapSimdRegister((int)(rn >> 1)); + Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1)); + + EmitMulNegVector(context, rdOperand, rnOperand, rmOperand, sz, q, negProduct); + } + } + + private static void EmitMulNegVector( + CodeGenContext context, + Operand rd, + Operand rn, + Operand rm, + uint sz, + uint q, + bool negProduct) + { + using ScopedRegister productRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped(); + + if (sz == 1) + { + context.Arm64Assembler.FmulVecHalf(productRegister.Operand, rn, rm, q); + + if (negProduct) + { + context.Arm64Assembler.FnegHalf(productRegister.Operand, productRegister.Operand, q); + } + + context.Arm64Assembler.FaddHalf(rd, rd, productRegister.Operand, q); + } + else + { + context.Arm64Assembler.FmulVecSingleAndDouble(productRegister.Operand, rn, rm, 0, q); + + if (negProduct) + { + context.Arm64Assembler.FnegSingleAndDouble(productRegister.Operand, productRegister.Operand, 0, q); + } + + context.Arm64Assembler.FaddSingleAndDouble(rd, rd, productRegister.Operand, 0, q); + } + } + + public static void EmitVectorTernaryRdByScalarAnyF( + CodeGenContext context, + uint rd, + uint rn, + uint rm, + uint size, + uint q, + Action action, + Action actionHalf) + { + EmitVectorByScalarAnyFCore(context, rd, rn, rm, size, q, action, actionHalf, isTernary: true); + } + + private static void EmitVectorByScalarAnyFCore( + CodeGenContext context, + uint rd, + uint rn, + uint rm, + uint size, + uint q, + Action action, + Action actionHalf, + bool isTernary) + { + (uint h, uint l, uint m) = GetIndexForReg(ref rm, size); + + Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1)); + + if (q == 0) + { + if (isTernary) + { + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped(); + + MoveScalarToSide(context, tempRegister.Operand, rd, false); + + using ScopedRegister rnReg = MoveScalarToSide(context, rn, false); + + if (size == 1) + { + actionHalf(tempRegister.Operand, rnReg.Operand, h, rmOperand, m, l, q); + } + else + { + action(tempRegister.Operand, rnReg.Operand, h, rmOperand, m, l, 0, q); + } + + InsertResult(context, tempRegister.Operand, rd, false); + } + else + { + using ScopedRegister rnReg = MoveScalarToSide(context, rn, false); + + using ScopedRegister tempRegister = PickSimdRegister(context.RegisterAllocator, rnReg); + + if (size == 1) + { + actionHalf(tempRegister.Operand, rnReg.Operand, h, rmOperand, m, l, q); + } + else + { + action(tempRegister.Operand, rnReg.Operand, h, rmOperand, m, l, 0, q); + } + + InsertResult(context, tempRegister.Operand, rd, false); + } + } + else + { + Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1)); + Operand rnOperand = context.RegisterAllocator.RemapSimdRegister((int)(rn >> 1)); + + if (size == 1) + { + actionHalf(rdOperand, rnOperand, h, rmOperand, m, l, q); + } + else + { + action(rdOperand, rnOperand, h, rmOperand, m, l, 0, q); + } + } + } + + public static void EmitVectorTernaryMulNegRdByScalarAnyF( + CodeGenContext context, + uint rd, + uint rn, + uint rm, + uint size, + uint q, + bool negProduct) + { + (uint h, uint l, uint m) = GetIndexForReg(ref rm, size); + + Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1)); + + if (q == 0) + { + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped(); + + MoveScalarToSide(context, tempRegister.Operand, rd, false); + + using ScopedRegister rnReg = MoveScalarToSide(context, rn, false); + + EmitMulNegVectorByScalar(context, tempRegister.Operand, rnReg.Operand, rmOperand, h, l, m, size, q, negProduct); + + InsertResult(context, tempRegister.Operand, rd, false); + } + else + { + Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1)); + Operand rnOperand = context.RegisterAllocator.RemapSimdRegister((int)(rn >> 1)); + + EmitMulNegVectorByScalar(context, rdOperand, rnOperand, rmOperand, h, l, m, size, q, negProduct); + } + } + + private static void EmitMulNegVectorByScalar( + CodeGenContext context, + Operand rd, + Operand rn, + Operand rm, + uint h, + uint l, + uint m, + uint sz, + uint q, + bool negProduct) + { + using ScopedRegister productRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped(); + + if (sz == 1) + { + context.Arm64Assembler.FmulElt2regElementHalf(productRegister.Operand, rn, h, rm, m, l, q); + + if (negProduct) + { + context.Arm64Assembler.FnegHalf(productRegister.Operand, productRegister.Operand, q); + } + + context.Arm64Assembler.FaddHalf(rd, rd, productRegister.Operand, q); + } + else + { + context.Arm64Assembler.FmulElt2regElementSingleAndDouble(productRegister.Operand, rn, h, rm, m, l, 0, q); + + if (negProduct) + { + context.Arm64Assembler.FnegSingleAndDouble(productRegister.Operand, productRegister.Operand, 0, q); + } + + context.Arm64Assembler.FaddSingleAndDouble(rd, rd, productRegister.Operand, 0, q); + } + } + + private static (uint, uint, uint) GetIndexForReg(ref uint reg, uint size) + { + int shift = (int)(size + 2); + uint index = reg >> shift; + reg &= (1u << shift) - 1; + index |= (reg & 1) << (5 - shift); + + uint h, l, m; + + if (size == 1) + { + Debug.Assert((index >> 3) == 0); + + m = index & 1; + l = (index >> 1) & 1; + h = index >> 2; + } + else + { + Debug.Assert(size == 2); + Debug.Assert((index >> 2) == 0); + + m = 0; + l = index & 1; + h = (index >> 1) & 1; + } + + return (h, l, m); + } + + private static (uint, uint) GetImmbImmh(uint value, uint size) + { + Debug.Assert(value > 0 && value <= (8u << (int)size)); + + uint imm = (8u << (int)size) | ((8u << (int)size) - value); + + Debug.Assert((imm >> 7) == 0); + + uint immb = imm & 7; + uint immh = imm >> 3; + + return (immb, immh); + } + + public static (uint, uint) GetImmbImmhForShift(uint value, uint size, bool isShl) + { + if (isShl) + { + Debug.Assert(value >= 0 && value < (8u << (int)size)); + + uint imm = (8u << (int)size) | (value & (0x3fu >> (int)(3 - size))); + + Debug.Assert((imm >> 7) == 0); + + uint immb = imm & 7; + uint immh = imm >> 3; + + return (immb, immh); + } + else + { + return GetImmbImmh(value, size); + } + } + + public static uint GetSizeFromImm6(uint imm6) + { + if ((imm6 & 0b100000) != 0) + { + return 2; + } + else if ((imm6 & 0b10000) != 0) + { + return 1; + } + else + { + Debug.Assert((imm6 & 0b1000) != 0); + + return 0; + } + } + + public static uint GetSizeFromImm7(uint imm7) + { + if ((imm7 & 0b1000000) != 0) + { + return 3; + } + else if ((imm7 & 0b100000) != 0) + { + return 2; + } + else if ((imm7 & 0b10000) != 0) + { + return 1; + } + else + { + Debug.Assert((imm7 & 0b1000) != 0); + + return 0; + } + } + + public static ScopedRegister PickSimdRegister(RegisterAllocator registerAllocator, ScopedRegister option1) + { + if (option1.IsAllocated) + { + return option1; + } + + return registerAllocator.AllocateTempSimdRegisterScoped(); + } + + public static ScopedRegister PickSimdRegister(RegisterAllocator registerAllocator, ScopedRegister option1, ScopedRegister option2) + { + if (option1.IsAllocated) + { + return option1; + } + else if (option2.IsAllocated) + { + return option2; + } + + return registerAllocator.AllocateTempSimdRegisterScoped(); + } + + public static ScopedRegister PickSimdRegister(RegisterAllocator registerAllocator, ScopedRegister option1, ScopedRegister option2, ScopedRegister option3) + { + if (option1.IsAllocated) + { + return option1; + } + else if (option2.IsAllocated) + { + return option2; + } + else if (option3.IsAllocated) + { + return option3; + } + + return registerAllocator.AllocateTempSimdRegisterScoped(); + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonCompare.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonCompare.cs new file mode 100644 index 000000000..8da993854 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonCompare.cs @@ -0,0 +1,126 @@ +namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 +{ + static class InstEmitNeonCompare + { + public static void Vacge(CodeGenContext context, uint rd, uint rn, uint rm, uint sz, uint q) + { + InstEmitNeonCommon.EmitVectorBinaryF(context, rd, rn, rm, sz, q, context.Arm64Assembler.FacgeV, context.Arm64Assembler.FacgeVH); + } + + public static void Vacgt(CodeGenContext context, uint rd, uint rn, uint rm, uint sz, uint q) + { + InstEmitNeonCommon.EmitVectorBinaryF(context, rd, rn, rm, sz, q, context.Arm64Assembler.FacgtV, context.Arm64Assembler.FacgtVH); + } + + public static void VceqI(CodeGenContext context, uint rd, uint rm, bool f, uint size, uint q) + { + if (f) + { + InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FcmeqZeroV, context.Arm64Assembler.FcmeqZeroVH); + } + else + { + InstEmitNeonCommon.EmitVectorUnary(context, rd, rm, size, q, context.Arm64Assembler.CmeqZeroV); + } + } + + public static void VceqR(CodeGenContext context, uint rd, uint rn, uint rm, uint size, uint q) + { + InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, size, q, context.Arm64Assembler.CmeqRegV, context.Arm64Assembler.CmeqRegS); + } + + public static void VceqFR(CodeGenContext context, uint rd, uint rn, uint rm, uint sz, uint q) + { + InstEmitNeonCommon.EmitVectorBinaryF(context, rd, rn, rm, sz, q, context.Arm64Assembler.FcmeqRegV, context.Arm64Assembler.FcmeqRegVH); + } + + public static void VcgeI(CodeGenContext context, uint rd, uint rm, bool f, uint size, uint q) + { + if (f) + { + InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FcmgeZeroV, context.Arm64Assembler.FcmgeZeroVH); + } + else + { + InstEmitNeonCommon.EmitVectorUnary(context, rd, rm, size, q, context.Arm64Assembler.CmgeZeroV); + } + } + + public static void VcgeR(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size, uint q) + { + InstEmitNeonCommon.EmitVectorBinary( + context, + rd, + rn, + rm, + size, + q, + u ? context.Arm64Assembler.CmhsV : context.Arm64Assembler.CmgeRegV, + u ? context.Arm64Assembler.CmhsS : context.Arm64Assembler.CmgeRegS); + } + + public static void VcgeFR(CodeGenContext context, uint rd, uint rn, uint rm, uint sz, uint q) + { + InstEmitNeonCommon.EmitVectorBinaryF(context, rd, rn, rm, sz, q, context.Arm64Assembler.FcmgeRegV, context.Arm64Assembler.FcmgeRegVH); + } + + public static void VcgtI(CodeGenContext context, uint rd, uint rm, bool f, uint size, uint q) + { + if (f) + { + InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FcmgtZeroV, context.Arm64Assembler.FcmgtZeroVH); + } + else + { + InstEmitNeonCommon.EmitVectorUnary(context, rd, rm, size, q, context.Arm64Assembler.CmgtZeroV); + } + } + + public static void VcgtR(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size, uint q) + { + InstEmitNeonCommon.EmitVectorBinary( + context, + rd, + rn, + rm, + size, + q, + u ? context.Arm64Assembler.CmhiV : context.Arm64Assembler.CmgtRegV, + u ? context.Arm64Assembler.CmhiS : context.Arm64Assembler.CmgtRegS); + } + + public static void VcgtFR(CodeGenContext context, uint rd, uint rn, uint rm, uint sz, uint q) + { + InstEmitNeonCommon.EmitVectorBinaryF(context, rd, rn, rm, sz, q, context.Arm64Assembler.FcmgtRegV, context.Arm64Assembler.FcmgtRegVH); + } + + public static void VcleI(CodeGenContext context, uint rd, uint rm, bool f, uint size, uint q) + { + if (f) + { + InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FcmleV, context.Arm64Assembler.FcmleVH); + } + else + { + InstEmitNeonCommon.EmitVectorUnary(context, rd, rm, size, q, context.Arm64Assembler.CmleV); + } + } + + public static void VcltI(CodeGenContext context, uint rd, uint rm, bool f, uint size, uint q) + { + if (f) + { + InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FcmltV, context.Arm64Assembler.FcmltVH); + } + else + { + InstEmitNeonCommon.EmitVectorUnary(context, rd, rm, size, q, context.Arm64Assembler.CmltV); + } + } + + public static void Vtst(CodeGenContext context, uint rd, uint rn, uint rm, uint size, uint q) + { + InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, size, q, context.Arm64Assembler.CmtstV, context.Arm64Assembler.CmtstS); + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonConvert.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonConvert.cs new file mode 100644 index 000000000..81fce678d --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonConvert.cs @@ -0,0 +1,137 @@ +using System; +using System.Diagnostics; + +namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 +{ + static class InstEmitNeonConvert + { + public static void Vcvta(CodeGenContext context, uint rd, uint rm, bool op, uint size, uint q) + { + if (op) + { + InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FcvtauV, context.Arm64Assembler.FcvtauVH); + } + else + { + InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FcvtasV, context.Arm64Assembler.FcvtasVH); + } + } + + public static void Vcvtm(CodeGenContext context, uint rd, uint rm, bool op, uint size, uint q) + { + if (op) + { + InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FcvtmuV, context.Arm64Assembler.FcvtmuVH); + } + else + { + InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FcvtmsV, context.Arm64Assembler.FcvtmsVH); + } + } + + public static void Vcvtn(CodeGenContext context, uint rd, uint rm, bool op, uint size, uint q) + { + if (op) + { + InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FcvtnuV, context.Arm64Assembler.FcvtnuVH); + } + else + { + InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FcvtnsV, context.Arm64Assembler.FcvtnsVH); + } + } + + public static void Vcvtp(CodeGenContext context, uint rd, uint rm, bool op, uint size, uint q) + { + if (op) + { + InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FcvtpuV, context.Arm64Assembler.FcvtpuVH); + } + else + { + InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FcvtpsV, context.Arm64Assembler.FcvtpsVH); + } + } + + public static void VcvtHs(CodeGenContext context, uint rd, uint rm, bool op) + { + bool halfToSingle = op; + if (halfToSingle) + { + // Half to single. + + InstEmitNeonCommon.EmitVectorUnaryLong(context, rd, rm, 0, context.Arm64Assembler.Fcvtl); + } + else + { + // Single to half. + + InstEmitNeonCommon.EmitVectorUnaryNarrow(context, rd, rm, 0, context.Arm64Assembler.Fcvtn); + } + } + + public static void VcvtIs(CodeGenContext context, uint rd, uint rm, uint op, uint size, uint q) + { + Debug.Assert(op >> 2 == 0); + + bool unsigned = (op & 1) != 0; + bool toInteger = (op >> 1) != 0; + + if (toInteger) + { + if (unsigned) + { + InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FcvtzuIntV, context.Arm64Assembler.FcvtzuIntVH); + } + else + { + InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FcvtzsIntV, context.Arm64Assembler.FcvtzsIntVH); + } + } + else + { + if (unsigned) + { + InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.UcvtfIntV, context.Arm64Assembler.UcvtfIntVH); + } + else + { + InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.ScvtfIntV, context.Arm64Assembler.ScvtfIntVH); + } + } + } + + public static void VcvtXs(CodeGenContext context, uint rd, uint rm, uint imm6, uint op, bool u, uint q) + { + Debug.Assert(op >> 2 == 0); + + bool unsigned = u; + bool toFixed = (op & 1) != 0; + uint size = 1 + (op >> 1); + uint fbits = Math.Clamp(64u - imm6, 1, 8u << (int)size); + + if (toFixed) + { + if (unsigned) + { + InstEmitNeonCommon.EmitVectorUnaryFixedAnyF(context, rd, rm, fbits, size, q, context.Arm64Assembler.FcvtzuFixV); + } + else + { + InstEmitNeonCommon.EmitVectorUnaryFixedAnyF(context, rd, rm, fbits, size, q, context.Arm64Assembler.FcvtzsFixV); + } + } + else + { + if (unsigned) + { + InstEmitNeonCommon.EmitVectorUnaryFixedAnyF(context, rd, rm, fbits, size, q, context.Arm64Assembler.UcvtfFixV); + } + else + { + InstEmitNeonCommon.EmitVectorUnaryFixedAnyF(context, rd, rm, fbits, size, q, context.Arm64Assembler.ScvtfFixV); + } + } + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonCrypto.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonCrypto.cs new file mode 100644 index 000000000..a36ae82c6 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonCrypto.cs @@ -0,0 +1,43 @@ +using System.Diagnostics; + +namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 +{ + static class InstEmitNeonCrypto + { + public static void Aesd(CodeGenContext context, uint rd, uint rm, uint size) + { + // TODO: Feature check, emulation if not supported. + + Debug.Assert(size == 0); + + InstEmitNeonCommon.EmitVectorUnary(context, rd, rm, context.Arm64Assembler.Aesd); + } + + public static void Aese(CodeGenContext context, uint rd, uint rm, uint size) + { + // TODO: Feature check, emulation if not supported. + + Debug.Assert(size == 0); + + InstEmitNeonCommon.EmitVectorUnary(context, rd, rm, context.Arm64Assembler.Aese); + } + + public static void Aesimc(CodeGenContext context, uint rd, uint rm, uint size) + { + // TODO: Feature check, emulation if not supported. + + Debug.Assert(size == 0); + + InstEmitNeonCommon.EmitVectorUnary(context, rd, rm, context.Arm64Assembler.Aesimc); + } + + public static void Aesmc(CodeGenContext context, uint rd, uint rm, uint size) + { + // TODO: Feature check, emulation if not supported. + + Debug.Assert(size == 0); + + InstEmitNeonCommon.EmitVectorUnary(context, rd, rm, context.Arm64Assembler.Aesmc); + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonHash.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonHash.cs new file mode 100644 index 000000000..57090ac8f --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonHash.cs @@ -0,0 +1,97 @@ +using System.Diagnostics; + +namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 +{ + static class InstEmitNeonHash + { + public static void Sha1c(CodeGenContext context, uint rd, uint rn, uint rm, uint q) + { + // TODO: Feature check, emulation if not supported. + + Debug.Assert(q == 1); + + InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, context.Arm64Assembler.Sha1c); + } + + public static void Sha1h(CodeGenContext context, uint rd, uint rm, uint size) + { + // TODO: Feature check, emulation if not supported. + + Debug.Assert(size == 2); + + InstEmitNeonCommon.EmitVectorUnary(context, rd, rm, context.Arm64Assembler.Sha1h); + } + + public static void Sha1m(CodeGenContext context, uint rd, uint rn, uint rm, uint q) + { + // TODO: Feature check, emulation if not supported. + + Debug.Assert(q == 1); + + InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, context.Arm64Assembler.Sha1m); + } + + public static void Sha1p(CodeGenContext context, uint rd, uint rn, uint rm, uint q) + { + // TODO: Feature check, emulation if not supported. + + Debug.Assert(q == 1); + + InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, context.Arm64Assembler.Sha1p); + } + + public static void Sha1su0(CodeGenContext context, uint rd, uint rn, uint rm, uint q) + { + // TODO: Feature check, emulation if not supported. + + Debug.Assert(q == 1); + + InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, context.Arm64Assembler.Sha1su0); + } + + public static void Sha1su1(CodeGenContext context, uint rd, uint rm, uint size) + { + // TODO: Feature check, emulation if not supported. + + Debug.Assert(size == 2); + + InstEmitNeonCommon.EmitVectorUnary(context, rd, rm, context.Arm64Assembler.Sha1su1); + } + + public static void Sha256h(CodeGenContext context, uint rd, uint rn, uint rm, uint q) + { + // TODO: Feature check, emulation if not supported. + + Debug.Assert(q == 1); + + InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, context.Arm64Assembler.Sha256h); + } + + public static void Sha256h2(CodeGenContext context, uint rd, uint rn, uint rm, uint q) + { + // TODO: Feature check, emulation if not supported. + + Debug.Assert(q == 1); + + InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, context.Arm64Assembler.Sha256h2); + } + + public static void Sha256su0(CodeGenContext context, uint rd, uint rm, uint size) + { + // TODO: Feature check, emulation if not supported. + + Debug.Assert(size == 2); + + InstEmitNeonCommon.EmitVectorUnary(context, rd, rm, context.Arm64Assembler.Sha256su0); + } + + public static void Sha256su1(CodeGenContext context, uint rd, uint rn, uint rm, uint q) + { + // TODO: Feature check, emulation if not supported. + + Debug.Assert(q == 1); + + InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, context.Arm64Assembler.Sha256su1); + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonLogical.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonLogical.cs new file mode 100644 index 000000000..af2e54cc8 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonLogical.cs @@ -0,0 +1,79 @@ +using Ryujinx.Cpu.LightningJit.CodeGen; + +namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 +{ + static class InstEmitNeonLogical + { + public static void VandR(CodeGenContext context, uint rd, uint rn, uint rm, uint q) + { + InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, q, context.Arm64Assembler.And); + } + + public static void VbicI(CodeGenContext context, uint rd, uint cmode, uint imm8, uint q) + { + EmitMovi(context, rd, cmode, imm8, 1, q); + } + + public static void VbicR(CodeGenContext context, uint rd, uint rn, uint rm, uint q) + { + InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, q, context.Arm64Assembler.BicReg); + } + + public static void VbifR(CodeGenContext context, uint rd, uint rn, uint rm, uint q) + { + InstEmitNeonCommon.EmitVectorTernaryRd(context, rd, rn, rm, q, context.Arm64Assembler.Bif); + } + + public static void VbitR(CodeGenContext context, uint rd, uint rn, uint rm, uint q) + { + InstEmitNeonCommon.EmitVectorTernaryRd(context, rd, rn, rm, q, context.Arm64Assembler.Bit); + } + + public static void VbslR(CodeGenContext context, uint rd, uint rn, uint rm, uint q) + { + InstEmitNeonCommon.EmitVectorTernaryRd(context, rd, rn, rm, q, context.Arm64Assembler.Bsl); + } + + public static void VeorR(CodeGenContext context, uint rd, uint rn, uint rm, uint q) + { + InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, q, context.Arm64Assembler.Eor); + } + + public static void VornR(CodeGenContext context, uint rd, uint rn, uint rm, uint q) + { + InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, q, context.Arm64Assembler.Orn); + } + + public static void VorrI(CodeGenContext context, uint rd, uint cmode, uint imm8, uint q) + { + EmitMovi(context, rd, cmode, imm8, 0, q); + } + + public static void VorrR(CodeGenContext context, uint rd, uint rn, uint rm, uint q) + { + InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, q, context.Arm64Assembler.OrrReg); + } + + private static void EmitMovi(CodeGenContext context, uint rd, uint cmode, uint imm8, uint op, uint q) + { + (uint a, uint b, uint c, uint d, uint e, uint f, uint g, uint h) = InstEmitNeonMove.Split(imm8); + + if (q == 0) + { + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped(); + + InstEmitNeonCommon.MoveScalarToSide(context, tempRegister.Operand, rd, false); + + context.Arm64Assembler.Movi(tempRegister.Operand, h, g, f, e, d, cmode, c, b, a, op, q); + + InstEmitNeonCommon.InsertResult(context, tempRegister.Operand, rd, false); + } + else + { + Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1)); + + context.Arm64Assembler.Movi(rdOperand, h, g, f, e, d, cmode, c, b, a, op, q); + } + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonMemory.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonMemory.cs new file mode 100644 index 000000000..e77dc0a29 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonMemory.cs @@ -0,0 +1,797 @@ +using Ryujinx.Cpu.LightningJit.CodeGen; +using Ryujinx.Cpu.LightningJit.CodeGen.Arm64; +using System; +using System.Diagnostics; + +namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 +{ + static class InstEmitNeonMemory + { + public static void Vld11(CodeGenContext context, uint rd, uint rn, uint rm, uint indexAlign, uint size) + { + uint index = indexAlign >> ((int)size + 1); + + EmitMemory1234InstructionCore(context, rn, rm, 1 << (int)size, (address) => + { + EmitMemoryLoad1234SingleInstruction(context, address, rd, index, size, 1, 1, context.Arm64Assembler.Ld1SnglAsNoPostIndex); + }); + } + + public static void Vld1A(CodeGenContext context, uint rd, uint rn, uint rm, uint a, uint t, uint size) + { + EmitMemory1234InstructionCore(context, rn, rm, 1 << (int)size, (address) => + { + EmitMemoryLoad1SingleReplicateInstruction(context, address, rd, size, t + 1, 1, context.Arm64Assembler.Ld1rAsNoPostIndex); + }); + } + + public static void Vld1M(CodeGenContext context, uint rd, uint rn, uint rm, uint registersCount, uint align, uint size) + { + EmitMemory1234InstructionCore(context, rn, rm, 8 * (int)registersCount, (address) => + { + EmitMemoryLoad1234MultipleInstruction(context, address, rd, size, registersCount, 1, context.Arm64Assembler.Ld1MultAsNoPostIndex); + }); + } + + public static void Vld21(CodeGenContext context, uint rd, uint rn, uint rm, uint indexAlign, uint size) + { + uint index = indexAlign >> ((int)size + 1); + uint step = size > 0 && (indexAlign & (1u << (int)size)) != 0 ? 2u : 1u; + + EmitMemory1234InstructionCore(context, rn, rm, 2 * (1 << (int)size), (address) => + { + EmitMemoryLoad1234SingleInstruction(context, address, rd, index, size, 2, step, context.Arm64Assembler.Ld2SnglAsNoPostIndex); + }); + } + + public static void Vld2A(CodeGenContext context, uint rd, uint rn, uint rm, uint a, uint t, uint size) + { + EmitMemory1234InstructionCore(context, rn, rm, 2 * (1 << (int)size), (address) => + { + EmitMemoryLoad234SingleReplicateInstruction(context, address, rd, size, 2, t + 1, context.Arm64Assembler.Ld2rAsNoPostIndex); + }); + } + + public static void Vld2M(CodeGenContext context, uint rd, uint rn, uint rm, uint type, uint align, uint size) + { + uint step = (type & 1) + 1; + + EmitMemory1234InstructionCore(context, rn, rm, 16, (address) => + { + EmitMemoryLoad1234MultipleInstruction(context, address, rd, size, 2, step, context.Arm64Assembler.Ld2MultAsNoPostIndex); + }); + } + + public static void Vld2M(CodeGenContext context, uint rd, uint rn, uint rm, uint align, uint size) + { + EmitMemory1234InstructionCore(context, rn, rm, 32, (address) => + { + EmitMemoryLoad1234Multiple2x2Instruction(context, address, rd, size, context.Arm64Assembler.Ld2MultAsNoPostIndex); + }); + } + + public static void Vld31(CodeGenContext context, uint rd, uint rn, uint rm, uint indexAlign, uint size) + { + uint index = indexAlign >> ((int)size + 1); + uint step = size > 0 && (indexAlign & (1u << (int)size)) != 0 ? 2u : 1u; + + EmitMemory1234InstructionCore(context, rn, rm, 3 * (1 << (int)size), (address) => + { + EmitMemoryLoad1234SingleInstruction(context, address, rd, index, size, 3, step, context.Arm64Assembler.Ld3SnglAsNoPostIndex); + }); + } + + public static void Vld3A(CodeGenContext context, uint rd, uint rn, uint rm, uint a, uint t, uint size) + { + EmitMemory1234InstructionCore(context, rn, rm, 3 * (1 << (int)size), (address) => + { + EmitMemoryLoad234SingleReplicateInstruction(context, address, rd, size, 3, t + 1, context.Arm64Assembler.Ld3rAsNoPostIndex); + }); + } + + public static void Vld3M(CodeGenContext context, uint rd, uint rn, uint rm, uint type, uint align, uint size) + { + uint step = (type & 1) + 1; + + EmitMemory1234InstructionCore(context, rn, rm, 24, (address) => + { + EmitMemoryLoad1234MultipleInstruction(context, address, rd, size, 3, step, context.Arm64Assembler.Ld3MultAsNoPostIndex); + }); + } + + public static void Vld41(CodeGenContext context, uint rd, uint rn, uint rm, uint indexAlign, uint size) + { + uint index = indexAlign >> ((int)size + 1); + uint step = size > 0 && (indexAlign & (1u << (int)size)) != 0 ? 2u : 1u; + + EmitMemory1234InstructionCore(context, rn, rm, 4 * (1 << (int)size), (address) => + { + EmitMemoryLoad1234SingleInstruction(context, address, rd, index, size, 4, step, context.Arm64Assembler.Ld4SnglAsNoPostIndex); + }); + } + + public static void Vld4A(CodeGenContext context, uint rd, uint rn, uint rm, uint a, uint t, uint size) + { + EmitMemory1234InstructionCore(context, rn, rm, 4 * (1 << (int)size), (address) => + { + EmitMemoryLoad234SingleReplicateInstruction(context, address, rd, size, 4, t + 1, context.Arm64Assembler.Ld4rAsNoPostIndex); + }); + } + + public static void Vld4M(CodeGenContext context, uint rd, uint rn, uint rm, uint type, uint align, uint size) + { + uint step = (type & 1) + 1; + + EmitMemory1234InstructionCore(context, rn, rm, 32, (address) => + { + EmitMemoryLoad1234MultipleInstruction(context, address, rd, size, 4, step, context.Arm64Assembler.Ld4MultAsNoPostIndex); + }); + } + + public static void Vldm(CodeGenContext context, uint rd, uint rn, uint registerCount, bool u, bool w, bool singleRegs) + { + EmitMemoryMultipleInstruction(context, rd, rn, registerCount, u, w, singleRegs, isStore: false); + } + + public static void Vldr(CodeGenContext context, uint rd, uint rn, uint imm8, bool u, uint size) + { + EmitMemoryInstruction(context, rd, rn, imm8, u, size, isStore: false); + } + + public static void Vst11(CodeGenContext context, uint rd, uint rn, uint rm, uint indexAlign, uint size) + { + uint index = indexAlign >> ((int)size + 1); + + EmitMemory1234InstructionCore(context, rn, rm, 1 << (int)size, (address) => + { + EmitMemoryStore1234SingleInstruction(context, address, rd, index, size, 1, 1, context.Arm64Assembler.St1SnglAsNoPostIndex); + }); + } + + public static void Vst1M(CodeGenContext context, uint rd, uint rn, uint rm, uint registersCount, uint align, uint size) + { + EmitMemory1234InstructionCore(context, rn, rm, 8 * (int)registersCount, (address) => + { + EmitMemoryStore1234MultipleInstruction(context, address, rd, size, registersCount, 1, context.Arm64Assembler.St1MultAsNoPostIndex); + }); + } + + public static void Vst21(CodeGenContext context, uint rd, uint rn, uint rm, uint indexAlign, uint size) + { + uint index = indexAlign >> ((int)size + 1); + uint step = size > 0 && (indexAlign & (1u << (int)size)) != 0 ? 2u : 1u; + + EmitMemory1234InstructionCore(context, rn, rm, 2 * (1 << (int)size), (address) => + { + EmitMemoryStore1234SingleInstruction(context, address, rd, index, size, 2, step, context.Arm64Assembler.St2SnglAsNoPostIndex); + }); + } + + public static void Vst2M(CodeGenContext context, uint rd, uint rn, uint rm, uint type, uint align, uint size) + { + uint step = (type & 1) + 1; + + EmitMemory1234InstructionCore(context, rn, rm, 16, (address) => + { + EmitMemoryStore1234MultipleInstruction(context, address, rd, size, 2, step, context.Arm64Assembler.St2MultAsNoPostIndex); + }); + } + + public static void Vst2M(CodeGenContext context, uint rd, uint rn, uint rm, uint align, uint size) + { + EmitMemory1234InstructionCore(context, rn, rm, 32, (address) => + { + EmitMemoryStore1234Multiple2x2Instruction(context, address, rd, size, context.Arm64Assembler.St2MultAsNoPostIndex); + }); + } + + public static void Vst31(CodeGenContext context, uint rd, uint rn, uint rm, uint indexAlign, uint size) + { + uint index = indexAlign >> ((int)size + 1); + uint step = size > 0 && (indexAlign & (1u << (int)size)) != 0 ? 2u : 1u; + + EmitMemory1234InstructionCore(context, rn, rm, 3 * (1 << (int)size), (address) => + { + EmitMemoryStore1234SingleInstruction(context, address, rd, index, size, 3, step, context.Arm64Assembler.St3SnglAsNoPostIndex); + }); + } + + public static void Vst3M(CodeGenContext context, uint rd, uint rn, uint rm, uint type, uint align, uint size) + { + uint step = (type & 1) + 1; + + EmitMemory1234InstructionCore(context, rn, rm, 24, (address) => + { + EmitMemoryStore1234MultipleInstruction(context, address, rd, size, 3, step, context.Arm64Assembler.St3MultAsNoPostIndex); + }); + } + + public static void Vst41(CodeGenContext context, uint rd, uint rn, uint rm, uint indexAlign, uint size) + { + uint index = indexAlign >> ((int)size + 1); + uint step = size > 0 && (indexAlign & (1u << (int)size)) != 0 ? 2u : 1u; + + EmitMemory1234InstructionCore(context, rn, rm, 4 * (1 << (int)size), (address) => + { + EmitMemoryStore1234SingleInstruction(context, address, rd, index, size, 4, step, context.Arm64Assembler.St4SnglAsNoPostIndex); + }); + } + + public static void Vst4M(CodeGenContext context, uint rd, uint rn, uint rm, uint type, uint align, uint size) + { + uint step = (type & 1) + 1; + + EmitMemory1234InstructionCore(context, rn, rm, 32, (address) => + { + EmitMemoryStore1234MultipleInstruction(context, address, rd, size, 4, step, context.Arm64Assembler.St4MultAsNoPostIndex); + }); + } + + public static void Vstm(CodeGenContext context, uint rd, uint rn, uint registerCount, bool u, bool w, bool singleRegs) + { + EmitMemoryMultipleInstruction(context, rd, rn, registerCount, u, w, singleRegs, isStore: true); + } + + public static void Vstr(CodeGenContext context, uint rd, uint rn, uint imm8, bool u, uint size) + { + EmitMemoryInstruction(context, rd, rn, imm8, u, size, isStore: true); + } + + private static void EmitMemoryMultipleInstruction( + CodeGenContext context, + uint rd, + uint rn, + uint registerCount, + bool add, + bool wBack, + bool singleRegs, + bool isStore) + { + Operand baseAddress = InstEmitCommon.GetInputGpr(context, rn); + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + Operand offset = InstEmitCommon.Const((int)registerCount * (singleRegs ? 4 : 8)); + + if (!add) + { + if (wBack) + { + InstEmitMemory.WriteAddShiftOffset(context.Arm64Assembler, baseAddress, baseAddress, offset, false, ArmShiftType.Lsl, 0); + InstEmitMemory.WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, context.Arm64Assembler, tempRegister.Operand, baseAddress); + } + else + { + InstEmitMemory.WriteAddShiftOffset(context.Arm64Assembler, tempRegister.Operand, baseAddress, offset, false, ArmShiftType.Lsl, 0); + InstEmitMemory.WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, context.Arm64Assembler, tempRegister.Operand, tempRegister.Operand); + } + } + else + { + InstEmitMemory.WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, context.Arm64Assembler, tempRegister.Operand, baseAddress); + } + + EmitMemoryMultipleInstructionCore(context, tempRegister.Operand, rd, registerCount, singleRegs, isStore); + + if (add && wBack) + { + context.Arm64Assembler.Add(baseAddress, baseAddress, offset); + } + } + + private static void EmitMemoryMultipleInstructionCore(CodeGenContext context, Operand baseAddress, uint rd, uint registerCount, bool singleRegs, bool isStore) + { + int offs = 0; + uint r = rd; + uint upperBound = Math.Min(rd + registerCount, 32u); + uint regMask = singleRegs ? 3u : 1u; + + // Read/write misaligned elements first. + + for (; (r & regMask) != 0 && r < upperBound; r++) + { + EmitMemoryInstruction(context, baseAddress, r, offs, singleRegs, isStore); + + offs += singleRegs ? 4 : 8; + } + + // Read/write aligned, full vectors. + + while (upperBound - r >= (singleRegs ? 4 : 2)) + { + int qIndex = (int)(r >> (singleRegs ? 2 : 1)); + + Operand rtOperand = context.RegisterAllocator.RemapSimdRegister(qIndex); + + if (upperBound - r >= (singleRegs ? 8 : 4) && (offs & 0xf) == 0) + { + Operand rt2Operand = context.RegisterAllocator.RemapSimdRegister(qIndex + 1); + + if (isStore) + { + context.Arm64Assembler.StpRiUn(rtOperand, rt2Operand, baseAddress, offs); + } + else + { + context.Arm64Assembler.LdpRiUn(rtOperand, rt2Operand, baseAddress, offs); + } + + r += singleRegs ? 8u : 4u; + offs += 32; + } + else + { + if ((offs & 0xf) == 0) + { + if (isStore) + { + context.Arm64Assembler.StrRiUn(rtOperand, baseAddress, offs); + } + else + { + context.Arm64Assembler.LdrRiUn(rtOperand, baseAddress, offs); + } + } + else + { + if (isStore) + { + context.Arm64Assembler.Stur(rtOperand, baseAddress, offs); + } + else + { + context.Arm64Assembler.Ldur(rtOperand, baseAddress, offs); + } + } + + r += singleRegs ? 4u : 2u; + offs += 16; + } + } + + // Read/write last misaligned elements. + + for (; r < upperBound; r++) + { + EmitMemoryInstruction(context, baseAddress, r, offs, singleRegs, isStore); + + offs += singleRegs ? 4 : 8; + } + } + + private static void EmitMemoryInstruction(CodeGenContext context, Operand baseAddress, uint r, int offs, bool singleRegs, bool isStore) + { + if (isStore) + { + using ScopedRegister tempRegister = InstEmitNeonCommon.MoveScalarToSide(context, r, singleRegs); + + context.Arm64Assembler.StrRiUn(tempRegister.Operand, baseAddress, offs); + } + else + { + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempFpRegisterScoped(singleRegs); + + context.Arm64Assembler.LdrRiUn(tempRegister.Operand, baseAddress, offs); + + InstEmitNeonCommon.InsertResult(context, tempRegister.Operand, r, singleRegs); + } + } + + private static void EmitMemoryInstruction(CodeGenContext context, uint rd, uint rn, uint imm8, bool add, uint size, bool isStore) + { + bool singleRegs = size != 3; + int offs = (int)imm8; + + if (size == 1) + { + offs <<= 1; + } + else + { + offs <<= 2; + } + + using ScopedRegister address = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + if (rn == RegisterUtils.PcRegister) + { + if (!add) + { + offs = -offs; + } + + context.Arm64Assembler.Mov(address.Operand, (context.Pc & ~3u) + (uint)offs); + + InstEmitMemory.WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, context.Arm64Assembler, address.Operand, address.Operand); + + offs = 0; + } + else + { + Operand rnOperand = context.RegisterAllocator.RemapGprRegister((int)rn); + + if (InstEmitMemory.CanFoldOffset(context.MemoryManagerType, add ? offs : -offs, (int)size, true, out _)) + { + InstEmitMemory.WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, context.Arm64Assembler, address.Operand, rnOperand); + + if (!add) + { + offs = -offs; + } + } + else + { + InstEmitMemory.WriteAddShiftOffset(context.Arm64Assembler, address.Operand, rnOperand, InstEmitCommon.Const(offs), add, ArmShiftType.Lsl, 0); + InstEmitMemory.WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, context.Arm64Assembler, address.Operand, address.Operand); + + offs = 0; + } + } + + if ((size == 3 && (offs & 7) != 0) || offs < 0) + { + if (isStore) + { + using ScopedRegister tempRegister = InstEmitNeonCommon.MoveScalarToSide(context, rd, singleRegs); + + context.Arm64Assembler.Stur(tempRegister.Operand, address.Operand, offs, size); + } + else + { + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempFpRegisterScoped(singleRegs); + + context.Arm64Assembler.Ldur(tempRegister.Operand, address.Operand, offs, size); + + InstEmitNeonCommon.InsertResult(context, tempRegister.Operand, rd, singleRegs); + } + } + else + { + if (isStore) + { + using ScopedRegister tempRegister = InstEmitNeonCommon.MoveScalarToSide(context, rd, singleRegs); + + context.Arm64Assembler.StrRiUn(tempRegister.Operand, address.Operand, offs, size); + } + else + { + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempFpRegisterScoped(singleRegs); + + context.Arm64Assembler.LdrRiUn(tempRegister.Operand, address.Operand, offs, size); + + InstEmitNeonCommon.InsertResult(context, tempRegister.Operand, rd, singleRegs); + } + } + } + + private static void EmitMemory1234InstructionCore(CodeGenContext context, uint rn, uint rm, int bytes, Action callback) + { + bool wBack = rm != RegisterUtils.PcRegister; + bool registerIndex = rm != RegisterUtils.PcRegister && rm != RegisterUtils.SpRegister; + + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + + using ScopedRegister address = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + InstEmitMemory.WriteAddressTranslation(context.MemoryManagerType, context.RegisterAllocator, context.Arm64Assembler, address.Operand, rnOperand); + + callback(address.Operand); + + if (wBack) + { + if (registerIndex) + { + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + + context.Arm64Assembler.Add(rnOperand, rnOperand, rmOperand); + } + else + { + context.Arm64Assembler.Add(rnOperand, rnOperand, InstEmitCommon.Const(bytes)); + } + } + } + + private static void EmitMemoryLoad1234SingleInstruction( + CodeGenContext context, + Operand baseAddress, + uint rd, + uint index, + uint size, + uint registerCount, + uint step, + Action action) + { + ScopedRegister[] tempRegisters = AllocateSequentialRegisters(context, (int)registerCount); + + MoveDoublewordsToQuadwordsLower(context, rd, registerCount, step, tempRegisters); + + action(tempRegisters[0].Operand, baseAddress, index, size); + + MoveQuadwordsLowerToDoublewords(context, rd, registerCount, step, tempRegisters); + + FreeSequentialRegisters(tempRegisters); + } + + private static void EmitMemoryLoad1SingleReplicateInstruction( + CodeGenContext context, + Operand baseAddress, + uint rd, + uint size, + uint registerCount, + uint step, + Action action) + { + if ((rd & 1) == 0 && registerCount == 2) + { + action(context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1)), baseAddress, size, 1); + } + else + { + uint vecsCount = (registerCount + 1) >> 1; + + ScopedRegister[] tempRegisters = AllocateSequentialRegisters(context, (int)vecsCount); + + action(tempRegisters[0].Operand, baseAddress, size, registerCount > 1 ? 1u : 0u); + + MoveQuadwordsToDoublewords(context, rd, registerCount, step, tempRegisters); + + FreeSequentialRegisters(tempRegisters); + } + } + + private static void EmitMemoryLoad234SingleReplicateInstruction( + CodeGenContext context, + Operand baseAddress, + uint rd, + uint size, + uint registerCount, + uint step, + Action action) + { + ScopedRegister[] tempRegisters = AllocateSequentialRegisters(context, (int)registerCount); + + action(tempRegisters[0].Operand, baseAddress, size, 0u); + + MoveQuadwordsLowerToDoublewords(context, rd, registerCount, step, tempRegisters); + + FreeSequentialRegisters(tempRegisters); + } + + private static void EmitMemoryLoad1234MultipleInstruction( + CodeGenContext context, + Operand baseAddress, + uint rd, + uint size, + uint registerCount, + uint step, + Action action) + { + ScopedRegister[] tempRegisters = AllocateSequentialRegisters(context, (int)registerCount); + + action(tempRegisters[0].Operand, baseAddress, size, 0); + + MoveQuadwordsLowerToDoublewords(context, rd, registerCount, step, tempRegisters); + + FreeSequentialRegisters(tempRegisters); + } + + private static void EmitMemoryLoad1234MultipleInstruction( + CodeGenContext context, + Operand baseAddress, + uint rd, + uint size, + uint registerCount, + uint step, + Action action) + { + ScopedRegister[] tempRegisters = AllocateSequentialRegisters(context, (int)registerCount); + + action(tempRegisters[0].Operand, baseAddress, registerCount, size, 0); + + MoveQuadwordsLowerToDoublewords(context, rd, registerCount, step, tempRegisters); + + FreeSequentialRegisters(tempRegisters); + } + + private static void EmitMemoryLoad1234Multiple2x2Instruction( + CodeGenContext context, + Operand baseAddress, + uint rd, + uint size, + Action action) + { + if ((rd & 1) == 0) + { + action(context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1), 2), baseAddress, size, 1); + } + else + { + ScopedRegister[] tempRegisters = AllocateSequentialRegisters(context, 2); + + action(tempRegisters[0].Operand, baseAddress, size, 1); + + MoveQuadwordsToDoublewords2x2(context, rd, tempRegisters); + + FreeSequentialRegisters(tempRegisters); + } + } + + private static void EmitMemoryStore1234SingleInstruction( + CodeGenContext context, + Operand baseAddress, + uint rd, + uint index, + uint size, + uint registerCount, + uint step, + Action action) + { + ScopedRegister[] tempRegisters = AllocateSequentialRegisters(context, (int)registerCount); + + MoveDoublewordsToQuadwordsLower(context, rd, registerCount, step, tempRegisters); + + action(tempRegisters[0].Operand, baseAddress, index, size); + + FreeSequentialRegisters(tempRegisters); + } + + private static void EmitMemoryStore1234MultipleInstruction( + CodeGenContext context, + Operand baseAddress, + uint rd, + uint size, + uint registerCount, + uint step, + Action action) + { + ScopedRegister[] tempRegisters = AllocateSequentialRegisters(context, (int)registerCount); + + MoveDoublewordsToQuadwordsLower(context, rd, registerCount, step, tempRegisters); + + action(tempRegisters[0].Operand, baseAddress, size, 0); + + FreeSequentialRegisters(tempRegisters); + } + + private static void EmitMemoryStore1234MultipleInstruction( + CodeGenContext context, + Operand baseAddress, + uint rd, + uint size, + uint registerCount, + uint step, + Action action) + { + ScopedRegister[] tempRegisters = AllocateSequentialRegisters(context, (int)registerCount); + + MoveDoublewordsToQuadwordsLower(context, rd, registerCount, step, tempRegisters); + + action(tempRegisters[0].Operand, baseAddress, registerCount, size, 0); + + FreeSequentialRegisters(tempRegisters); + } + + private static void EmitMemoryStore1234Multiple2x2Instruction( + CodeGenContext context, + Operand baseAddress, + uint rd, + uint size, + Action action) + { + if ((rd & 1) == 0) + { + action(context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1), 2), baseAddress, size, 1); + } + else + { + ScopedRegister[] tempRegisters = AllocateSequentialRegisters(context, 2); + + MoveDoublewordsToQuadwords2x2(context, rd, tempRegisters); + + action(tempRegisters[0].Operand, baseAddress, size, 1); + + FreeSequentialRegisters(tempRegisters); + } + } + + private static ScopedRegister[] AllocateSequentialRegisters(CodeGenContext context, int count) + { + ScopedRegister[] registers = new ScopedRegister[count]; + + for (int index = 0; index < count; index++) + { + registers[index] = context.RegisterAllocator.AllocateTempSimdRegisterScoped(); + } + + AssertSequentialRegisters(registers); + + return registers; + } + + private static void FreeSequentialRegisters(ReadOnlySpan registers) + { + for (int index = 0; index < registers.Length; index++) + { + registers[index].Dispose(); + } + } + + [Conditional("DEBUG")] + private static void AssertSequentialRegisters(ReadOnlySpan registers) + { + for (int index = 1; index < registers.Length; index++) + { + Debug.Assert(registers[index].Operand.GetRegister().Index == registers[0].Operand.GetRegister().Index + index); + } + } + + private static void MoveQuadwordsLowerToDoublewords(CodeGenContext context, uint rd, uint registerCount, uint step, ReadOnlySpan registers) + { + for (int index = 0; index < registerCount; index++) + { + uint r = rd + (uint)index * step; + + Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(r >> 1)); + uint imm5 = InstEmitNeonCommon.GetImm5ForElementIndex(r & 1u, false); + context.Arm64Assembler.InsElt(rdOperand, registers[index].Operand, 0, imm5); + } + } + + private static void MoveDoublewordsToQuadwordsLower(CodeGenContext context, uint rd, uint registerCount, uint step, ReadOnlySpan registers) + { + for (int index = 0; index < registerCount; index++) + { + uint r = rd + (uint)index * step; + + InstEmitNeonCommon.MoveScalarToSide(context, registers[index].Operand, r, false); + } + } + + private static void MoveDoublewordsToQuadwords2x2(CodeGenContext context, uint rd, ReadOnlySpan registers) + { + for (int index = 0; index < 2; index++) + { + uint r = rd + (uint)index * 2; + uint r2 = r + 1; + + Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(r >> 1)); + uint imm5 = InstEmitNeonCommon.GetImm5ForElementIndex(0, false); + context.Arm64Assembler.InsElt(registers[index].Operand, rdOperand, (r & 1u) << 3, imm5); + + rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(r2 >> 1)); + imm5 = InstEmitNeonCommon.GetImm5ForElementIndex(1, false); + context.Arm64Assembler.InsElt(registers[index].Operand, rdOperand, (r2 & 1u) << 3, imm5); + } + } + + private static void MoveQuadwordsToDoublewords(CodeGenContext context, uint rd, uint registerCount, uint step, ReadOnlySpan registers) + { + for (int index = 0; index < registerCount; index++) + { + uint r = rd + (uint)index * step; + + Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(r >> 1)); + uint imm5 = InstEmitNeonCommon.GetImm5ForElementIndex(r & 1u, false); + context.Arm64Assembler.InsElt(rdOperand, registers[index >> 1].Operand, ((uint)index & 1u) << 3, imm5); + } + } + + private static void MoveQuadwordsToDoublewords2x2(CodeGenContext context, uint rd, ReadOnlySpan registers) + { + for (int index = 0; index < 2; index++) + { + uint r = rd + (uint)index * 2; + uint r2 = r + 1; + + Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(r >> 1)); + uint imm5 = InstEmitNeonCommon.GetImm5ForElementIndex(r & 1u, false); + context.Arm64Assembler.InsElt(rdOperand, registers[index].Operand, 0, imm5); + + rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(r2 >> 1)); + imm5 = InstEmitNeonCommon.GetImm5ForElementIndex(r2 & 1u, false); + context.Arm64Assembler.InsElt(rdOperand, registers[index].Operand, 1u << 3, imm5); + } + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonMove.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonMove.cs new file mode 100644 index 000000000..08a0673aa --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonMove.cs @@ -0,0 +1,665 @@ +using Ryujinx.Cpu.LightningJit.CodeGen; +using System; +using System.Diagnostics; +using System.Numerics; + +namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 +{ + static class InstEmitNeonMove + { + public static void VdupR(CodeGenContext context, uint rd, uint rt, uint b, uint e, uint q) + { + uint size = 2 - (e | (b << 1)); + + Debug.Assert(size < 3); + + Operand rtOperand = InstEmitCommon.GetInputGpr(context, rt); + + uint imm5 = InstEmitNeonCommon.GetImm5ForElementIndex(0, size); + + if (q == 0) + { + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped(); + + context.Arm64Assembler.DupGen(tempRegister.Operand, rtOperand, imm5, q); + + InstEmitNeonCommon.InsertResult(context, tempRegister.Operand, rd, false); + } + else + { + Debug.Assert((rd & 1) == 0); + + Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1)); + + context.Arm64Assembler.DupGen(rdOperand, rtOperand, imm5, q); + } + } + + public static void VdupS(CodeGenContext context, uint rd, uint rm, uint imm4, uint q) + { + uint size = (uint)BitOperations.TrailingZeroCount(imm4); + + Debug.Assert(size < 3); + + uint index = imm4 >> (int)(size + 1); + + Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1)); + + uint imm5 = InstEmitNeonCommon.GetImm5ForElementIndex(index | ((rm & 1) << (int)(3 - size)), size); + + if (q == 0) + { + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped(); + + context.Arm64Assembler.DupEltVectorFromElement(tempRegister.Operand, rmOperand, imm5, q); + + InstEmitNeonCommon.InsertResult(context, tempRegister.Operand, rd, false); + } + else + { + Debug.Assert((rd & 1) == 0); + + Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1)); + + context.Arm64Assembler.DupEltVectorFromElement(rdOperand, rmOperand, imm5, q); + } + } + + public static void Vext(CodeGenContext context, uint rd, uint rn, uint rm, uint imm4, uint q) + { + if (q == 0) + { + using ScopedRegister rnReg = InstEmitNeonCommon.MoveScalarToSide(context, rn, false); + using ScopedRegister rmReg = InstEmitNeonCommon.MoveScalarToSide(context, rm, false); + + using ScopedRegister tempRegister = InstEmitNeonCommon.PickSimdRegister(context.RegisterAllocator, rnReg, rmReg); + + context.Arm64Assembler.Ext(tempRegister.Operand, rnReg.Operand, imm4, rmReg.Operand, q); + + InstEmitNeonCommon.InsertResult(context, tempRegister.Operand, rd, false); + } + else + { + Debug.Assert(((rd | rn | rm) & 1) == 0); + + Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1)); + Operand rnOperand = context.RegisterAllocator.RemapSimdRegister((int)(rn >> 1)); + Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1)); + + context.Arm64Assembler.Ext(rdOperand, rnOperand, imm4, rmOperand, q); + } + } + + public static void Vmovl(CodeGenContext context, uint rd, uint rm, bool u, uint imm3h) + { + uint size = (uint)BitOperations.TrailingZeroCount(imm3h); + Debug.Assert(size < 3); + + InstEmitNeonCommon.EmitVectorBinaryLongShift( + context, + rd, + rm, + 0, + size, + isShl: true, + u ? context.Arm64Assembler.Ushll : context.Arm64Assembler.Sshll); + } + + public static void Vmovn(CodeGenContext context, uint rd, uint rm, uint size) + { + Debug.Assert(size < 3); + + InstEmitNeonCommon.EmitVectorUnaryNarrow(context, rd, rm, size, context.Arm64Assembler.Xtn); + } + + public static void Vmovx(CodeGenContext context, uint rd, uint rm) + { + InstEmitNeonCommon.EmitScalarBinaryShift(context, rd, rm, 16, 2, isShl: false, context.Arm64Assembler.UshrS); + } + + public static void VmovD(CodeGenContext context, uint rt, uint rt2, uint rm, bool op) + { + Operand rmReg = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1)); + + uint top = rm & 1; + uint ftype = top + 1; + + if (op) + { + Operand rtOperand = InstEmitCommon.GetOutputGpr(context, rt); + Operand rt2Operand = InstEmitCommon.GetOutputGpr(context, rt2); + + Operand rtOperand64 = new(OperandKind.Register, OperandType.I64, rtOperand.Value); + Operand rt2Operand64 = new(OperandKind.Register, OperandType.I64, rt2Operand.Value); + + context.Arm64Assembler.FmovFloatGen(rtOperand64, rmReg, ftype, 1, 0, top); + + context.Arm64Assembler.Lsr(rt2Operand64, rtOperand64, InstEmitCommon.Const(32)); + context.Arm64Assembler.Mov(rtOperand, rtOperand); // Zero-extend. + } + else + { + Operand rtOperand = InstEmitCommon.GetInputGpr(context, rt); + Operand rt2Operand = InstEmitCommon.GetInputGpr(context, rt2); + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + Operand tempRegister64 = new(OperandKind.Register, OperandType.I64, tempRegister.Operand.Value); + + context.Arm64Assembler.Lsl(tempRegister64, rt2Operand, InstEmitCommon.Const(32)); + context.Arm64Assembler.Orr(tempRegister64, tempRegister64, rtOperand); + + if (top == 0) + { + // Doing FMOV on Rm directly would clear the high bits if we are moving to the bottom. + + using ScopedRegister tempRegister2 = context.RegisterAllocator.AllocateTempSimdRegisterScoped(); + + context.Arm64Assembler.FmovFloatGen(tempRegister2.Operand, tempRegister64, ftype, 1, 1, top); + + InstEmitNeonCommon.InsertResult(context, tempRegister2.Operand, rm, false); + } + else + { + context.Arm64Assembler.FmovFloatGen(rmReg, tempRegister64, ftype, 1, 1, top); + } + } + } + + public static void VmovH(CodeGenContext context, uint rt, uint rn, bool op) + { + if (op) + { + Operand rtOperand = InstEmitCommon.GetOutputGpr(context, rt); + + using ScopedRegister tempRegister = InstEmitNeonCommon.MoveScalarToSide(context, rn, true); + + context.Arm64Assembler.FmovFloatGen(rtOperand, tempRegister.Operand, 3, 0, 0, 0); + } + else + { + Operand rtOperand = InstEmitCommon.GetInputGpr(context, rt); + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped(); + + context.Arm64Assembler.FmovFloatGen(tempRegister.Operand, rtOperand, 3, 0, 1, 0); + + InstEmitNeonCommon.InsertResult(context, tempRegister.Operand, rn, true); + } + } + + public static void VmovI(CodeGenContext context, uint rd, uint op, uint cmode, uint imm8, uint q) + { + (uint a, uint b, uint c, uint d, uint e, uint f, uint g, uint h) = Split(imm8); + + if (q == 0) + { + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped(); + + context.Arm64Assembler.Movi(tempRegister.Operand, h, g, f, e, d, cmode, c, b, a, op, q); + + InstEmitNeonCommon.InsertResult(context, tempRegister.Operand, rd, false); + } + else + { + Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1)); + + context.Arm64Assembler.Movi(rdOperand, h, g, f, e, d, cmode, c, b, a, op, q); + } + } + + public static void VmovFI(CodeGenContext context, uint rd, uint imm8, uint size) + { + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped(); + + context.Arm64Assembler.FmovFloatImm(tempRegister.Operand, imm8, size ^ 2u); + + InstEmitNeonCommon.InsertResult(context, tempRegister.Operand, rd, size != 3); + } + + public static void VmovR(CodeGenContext context, uint rd, uint rm, uint size) + { + bool singleRegister = size == 2; + + int shift = singleRegister ? 2 : 1; + uint mask = singleRegister ? 3u : 1u; + uint dstElt = rd & mask; + uint srcElt = rm & mask; + + uint imm4 = srcElt << (singleRegister ? 2 : 3); + uint imm5 = InstEmitNeonCommon.GetImm5ForElementIndex(dstElt, singleRegister); + + Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> shift)); + Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> shift)); + + context.Arm64Assembler.InsElt(rdOperand, rmOperand, imm4, imm5); + } + + public static void VmovRs(CodeGenContext context, uint rd, uint rt, uint opc1, uint opc2) + { + uint index; + uint size; + + if ((opc1 & 2u) != 0) + { + index = opc2 | ((opc1 & 1u) << 2); + size = 0; + } + else if ((opc2 & 1u) != 0) + { + index = (opc2 >> 1) | ((opc1 & 1u) << 1); + size = 1; + } + else + { + Debug.Assert(opc1 == 0 || opc1 == 1); + Debug.Assert(opc2 == 0); + + index = opc1 & 1u; + size = 2; + } + + index |= (rd & 1u) << (int)(3 - size); + + Operand rtOperand = InstEmitCommon.GetInputGpr(context, rt); + + Operand rdReg = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1)); + + context.Arm64Assembler.InsGen(rdReg, rtOperand, InstEmitNeonCommon.GetImm5ForElementIndex(index, size)); + } + + public static void VmovS(CodeGenContext context, uint rt, uint rn, bool op) + { + if (op) + { + Operand rtOperand = InstEmitCommon.GetOutputGpr(context, rt); + + using ScopedRegister tempRegister = InstEmitNeonCommon.MoveScalarToSide(context, rn, true); + + context.Arm64Assembler.FmovFloatGen(rtOperand, tempRegister.Operand, 0, 0, 0, 0); + } + else + { + Operand rtOperand = InstEmitCommon.GetInputGpr(context, rt); + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped(); + + context.Arm64Assembler.FmovFloatGen(tempRegister.Operand, rtOperand, 0, 0, 1, 0); + + InstEmitNeonCommon.InsertResult(context, tempRegister.Operand, rn, true); + } + } + + public static void VmovSr(CodeGenContext context, uint rt, uint rn, bool u, uint opc1, uint opc2) + { + uint index; + uint size; + + if ((opc1 & 2u) != 0) + { + index = opc2 | ((opc1 & 1u) << 2); + size = 0; + } + else if ((opc2 & 1u) != 0) + { + index = (opc2 >> 1) | ((opc1 & 1u) << 1); + size = 1; + } + else + { + Debug.Assert(opc1 == 0 || opc1 == 1); + Debug.Assert(opc2 == 0); + Debug.Assert(!u); + + index = opc1 & 1u; + size = 2; + } + + index |= (rn & 1u) << (int)(3 - size); + + Operand rtOperand = InstEmitCommon.GetOutputGpr(context, rt); + + Operand rnReg = context.RegisterAllocator.RemapSimdRegister((int)(rn >> 1)); + + if (u || size > 1) + { + context.Arm64Assembler.Umov(rtOperand, rnReg, (int)index, (int)size); + } + else + { + context.Arm64Assembler.Smov(rtOperand, rnReg, (int)index, (int)size); + } + } + + public static void VmovSs(CodeGenContext context, uint rt, uint rt2, uint rm, bool op) + { + if ((rm & 1) == 0) + { + // If we are moving an aligned pair of single-precision registers, + // we can just move a single double-precision register. + + VmovD(context, rt, rt2, rm >> 1, op); + + return; + } + + if (op) + { + Operand rtOperand = InstEmitCommon.GetOutputGpr(context, rt); + Operand rt2Operand = InstEmitCommon.GetOutputGpr(context, rt2); + + using ScopedRegister rmReg = InstEmitNeonCommon.MoveScalarToSide(context, rm, true); + using ScopedRegister rmReg2 = InstEmitNeonCommon.MoveScalarToSide(context, rm + 1, true); + + context.Arm64Assembler.FmovFloatGen(rtOperand, rmReg.Operand, 0, 0, 0, 0); + context.Arm64Assembler.FmovFloatGen(rt2Operand, rmReg2.Operand, 0, 0, 0, 0); + } + else + { + Operand rtOperand = InstEmitCommon.GetInputGpr(context, rt); + Operand rt2Operand = InstEmitCommon.GetInputGpr(context, rt2); + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped(); + + context.Arm64Assembler.FmovFloatGen(tempRegister.Operand, rtOperand, 0, 0, 1, 0); + InstEmitNeonCommon.InsertResult(context, tempRegister.Operand, rm, true); + + context.Arm64Assembler.FmovFloatGen(tempRegister.Operand, rt2Operand, 0, 0, 1, 0); + InstEmitNeonCommon.InsertResult(context, tempRegister.Operand, rm + 1, true); + } + } + + public static void VmvnI(CodeGenContext context, uint rd, uint cmode, uint imm8, uint q) + { + (uint a, uint b, uint c, uint d, uint e, uint f, uint g, uint h) = Split(imm8); + + if (q == 0) + { + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped(); + + context.Arm64Assembler.Mvni(tempRegister.Operand, h, g, f, e, d, cmode, c, b, a, q); + + InstEmitNeonCommon.InsertResult(context, tempRegister.Operand, rd, false); + } + else + { + Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1)); + + context.Arm64Assembler.Mvni(rdOperand, h, g, f, e, d, cmode, c, b, a, q); + } + } + + public static void VmvnR(CodeGenContext context, uint rd, uint rm, uint size, uint q) + { + InstEmitNeonCommon.EmitVectorUnary(context, rd, rm, q, context.Arm64Assembler.Not); + } + + public static void Vswp(CodeGenContext context, uint rd, uint rm, uint q) + { + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped(); + + if (q == 0) + { + InstEmitNeonCommon.MoveScalarToSide(context, tempRegister.Operand, rd, false); + using ScopedRegister rmReg = InstEmitNeonCommon.MoveScalarToSide(context, rm, false); + + InstEmitNeonCommon.InsertResult(context, rmReg.Operand, rd, false); + InstEmitNeonCommon.InsertResult(context, tempRegister.Operand, rm, false); + } + else + { + Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1)); + Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1)); + + context.Arm64Assembler.Orr(tempRegister.Operand, rdOperand, rdOperand); // Temp = Rd + context.Arm64Assembler.Orr(rdOperand, rmOperand, rmOperand); // Rd = Rm + context.Arm64Assembler.Orr(rmOperand, tempRegister.Operand, tempRegister.Operand); // Rm = Temp + } + } + + public static void Vtbl(CodeGenContext context, uint rd, uint rn, uint rm, bool op, uint len) + { + // On AArch64, TBL/TBX works with 128-bit vectors, while on AArch32 it works with 64-bit vectors. + // We must combine the 64-bit vectors into a larger 128-bit one in some cases. + + // TODO: Peephole optimization to combine adjacent TBL instructions? + + Debug.Assert(len <= 3); + + bool isTbl = !op; + + len = Math.Min(len, 31 - rn); + + bool rangeMismatch = !isTbl && (len & 1) == 0; + + using ScopedRegister indicesReg = InstEmitNeonCommon.MoveScalarToSide(context, rm, false, rangeMismatch); + + if (rangeMismatch) + { + // Force any index >= 8 * regs to be the maximum value, since on AArch64 we are working with a full vector, + // and the out of range value is 16 * regs, not 8 * regs. + + Debug.Assert(indicesReg.IsAllocated); + + using ScopedRegister tempRegister2 = context.RegisterAllocator.AllocateTempSimdRegisterScoped(); + + if (len == 0) + { + (uint immb, uint immh) = InstEmitNeonCommon.GetImmbImmhForShift(3, 0, isShl: false); + + context.Arm64Assembler.UshrV(tempRegister2.Operand, indicesReg.Operand, immb, immh, 0); + context.Arm64Assembler.CmeqZeroV(tempRegister2.Operand, tempRegister2.Operand, 0, 0); + context.Arm64Assembler.Orn(indicesReg.Operand, indicesReg.Operand, tempRegister2.Operand, 0); + } + else + { + (uint a, uint b, uint c, uint d, uint e, uint f, uint g, uint h) = Split(8u * (len + 1)); + + context.Arm64Assembler.Movi(tempRegister2.Operand, h, g, f, e, d, 0xe, c, b, a, 0, 0); + context.Arm64Assembler.CmgeRegV(tempRegister2.Operand, indicesReg.Operand, tempRegister2.Operand, 0, 0); + context.Arm64Assembler.OrrReg(indicesReg.Operand, indicesReg.Operand, tempRegister2.Operand, 0); + } + } + + ScopedRegister tableReg1 = default; + ScopedRegister tableReg2 = default; + + switch (len) + { + case 0: + tableReg1 = MoveHalfToSideZeroUpper(context, rn); + break; + case 1: + tableReg1 = MoveDoublewords(context, rn, rn + 1); + break; + case 2: + tableReg1 = MoveDoublewords(context, rn, rn + 1, isOdd: true); + tableReg2 = MoveHalfToSideZeroUpper(context, rn + 2); + break; + case 3: + tableReg1 = MoveDoublewords(context, rn, rn + 1); + tableReg2 = MoveDoublewords(context, rn + 2, rn + 3); + break; + } + + // TBL works with consecutive registers, it is assumed that two consecutive calls to the register allocator + // will return consecutive registers. + + Debug.Assert(len < 2 || tableReg1.Operand.GetRegister().Index + 1 == tableReg2.Operand.GetRegister().Index); + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped(); + + if (isTbl) + { + context.Arm64Assembler.Tbl(tempRegister.Operand, tableReg1.Operand, len >> 1, indicesReg.Operand, 0); + } + else + { + InstEmitNeonCommon.MoveScalarToSide(context, tempRegister.Operand, rd, false); + + context.Arm64Assembler.Tbx(tempRegister.Operand, tableReg1.Operand, len >> 1, indicesReg.Operand, 0); + } + + InstEmitNeonCommon.InsertResult(context, tempRegister.Operand, rd, false); + + tableReg1.Dispose(); + + if (len > 1) + { + tableReg2.Dispose(); + } + } + + public static void Vtrn(CodeGenContext context, uint rd, uint rm, uint size, uint q) + { + EmitVectorBinaryInterleavedTrn(context, rd, rm, size, q, context.Arm64Assembler.Trn1, context.Arm64Assembler.Trn2); + } + + public static void Vuzp(CodeGenContext context, uint rd, uint rm, uint size, uint q) + { + EmitVectorBinaryInterleaved(context, rd, rm, size, q, context.Arm64Assembler.Uzp1, context.Arm64Assembler.Uzp2); + } + + public static void Vzip(CodeGenContext context, uint rd, uint rm, uint size, uint q) + { + EmitVectorBinaryInterleaved(context, rd, rm, size, q, context.Arm64Assembler.Zip1, context.Arm64Assembler.Zip2); + } + + public static (uint, uint, uint, uint, uint, uint, uint, uint) Split(uint imm8) + { + uint a = (imm8 >> 7) & 1; + uint b = (imm8 >> 6) & 1; + uint c = (imm8 >> 5) & 1; + uint d = (imm8 >> 4) & 1; + uint e = (imm8 >> 3) & 1; + uint f = (imm8 >> 2) & 1; + uint g = (imm8 >> 1) & 1; + uint h = imm8 & 1; + + return (a, b, c, d, e, f, g, h); + } + + private static ScopedRegister MoveHalfToSideZeroUpper(CodeGenContext context, uint srcReg) + { + uint elt = srcReg & 1u; + + Operand source = context.RegisterAllocator.RemapSimdRegister((int)(srcReg >> 1)); + ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempFpRegisterScoped(false); + + uint imm5 = InstEmitNeonCommon.GetImm5ForElementIndex(elt, false); + + context.Arm64Assembler.DupEltScalarFromElement(tempRegister.Operand, source, imm5); + + return tempRegister; + } + + private static ScopedRegister MoveDoublewords(CodeGenContext context, uint lowerReg, uint upperReg, bool isOdd = false) + { + if ((lowerReg & 1) == 0 && upperReg == lowerReg + 1 && !isOdd) + { + return new ScopedRegister(context.RegisterAllocator, context.RegisterAllocator.RemapSimdRegister((int)(lowerReg >> 1)), false); + } + + Operand lowerSrc = context.RegisterAllocator.RemapSimdRegister((int)(lowerReg >> 1)); + Operand upperSrc = context.RegisterAllocator.RemapSimdRegister((int)(upperReg >> 1)); + ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempFpRegisterScoped(false); + + uint imm5 = InstEmitNeonCommon.GetImm5ForElementIndex(lowerReg & 1u, false); + + context.Arm64Assembler.DupEltScalarFromElement(tempRegister.Operand, lowerSrc, imm5); + + imm5 = InstEmitNeonCommon.GetImm5ForElementIndex(1, false); + + context.Arm64Assembler.InsElt(tempRegister.Operand, upperSrc, (upperReg & 1u) << 3, imm5); + + return tempRegister; + } + + private static void EmitVectorBinaryInterleavedTrn( + CodeGenContext context, + uint rd, + uint rm, + uint size, + uint q, + Action action1, + Action action2) + { + if (rd == rm) + { + // The behaviour when the registers are the same is "unpredictable" according to the manual. + + if (q == 0) + { + using ScopedRegister rdReg = InstEmitNeonCommon.MoveScalarToSide(context, rd, false); + using ScopedRegister rmReg = InstEmitNeonCommon.MoveScalarToSide(context, rm, false); + + using ScopedRegister tempRegister1 = context.RegisterAllocator.AllocateTempSimdRegisterScoped(); + using ScopedRegister tempRegister2 = InstEmitNeonCommon.PickSimdRegister(context.RegisterAllocator, rdReg, rmReg); + + action1(tempRegister1.Operand, rdReg.Operand, rmReg.Operand, size, q); + action2(tempRegister2.Operand, rdReg.Operand, tempRegister1.Operand, size, q); + + InstEmitNeonCommon.InsertResult(context, tempRegister2.Operand, rd, false); + } + else + { + Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1)); + Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1)); + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped(); + + action1(tempRegister.Operand, rdOperand, rmOperand, size, q); + action2(rmOperand, rdOperand, tempRegister.Operand, size, q); + } + } + else + { + EmitVectorBinaryInterleaved(context, rd, rm, size, q, action1, action2); + } + } + + private static void EmitVectorBinaryInterleaved( + CodeGenContext context, + uint rd, + uint rm, + uint size, + uint q, + Action action1, + Action action2) + { + if (q == 0) + { + using ScopedRegister rdReg = InstEmitNeonCommon.MoveScalarToSide(context, rd, false); + using ScopedRegister rmReg = InstEmitNeonCommon.MoveScalarToSide(context, rm, false); + + using ScopedRegister tempRegister1 = context.RegisterAllocator.AllocateTempSimdRegisterScoped(); + using ScopedRegister tempRegister2 = InstEmitNeonCommon.PickSimdRegister(context.RegisterAllocator, rdReg, rmReg); + + action1(tempRegister1.Operand, rdReg.Operand, rmReg.Operand, size, q); + action2(tempRegister2.Operand, rdReg.Operand, rmReg.Operand, size, q); + + if (rd != rm) + { + InstEmitNeonCommon.InsertResult(context, tempRegister1.Operand, rd, false); + } + + InstEmitNeonCommon.InsertResult(context, tempRegister2.Operand, rm, false); + } + else + { + Operand rdOperand = context.RegisterAllocator.RemapSimdRegister((int)(rd >> 1)); + Operand rmOperand = context.RegisterAllocator.RemapSimdRegister((int)(rm >> 1)); + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped(); + + action1(tempRegister.Operand, rdOperand, rmOperand, size, q); + action2(rmOperand, rdOperand, rmOperand, size, q); + + if (rd != rm) + { + context.Arm64Assembler.OrrReg(rdOperand, tempRegister.Operand, tempRegister.Operand, 1); + } + } + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonRound.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonRound.cs new file mode 100644 index 000000000..3c6ca65d0 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonRound.cs @@ -0,0 +1,105 @@ +namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 +{ + static class InstEmitNeonRound + { + public static void Vraddhn(CodeGenContext context, uint rd, uint rn, uint rm, uint size) + { + InstEmitNeonCommon.EmitVectorBinaryNarrow(context, rd, rn, rm, size, context.Arm64Assembler.Raddhn); + } + + public static void Vrhadd(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size, uint q) + { + InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, size, q, u ? context.Arm64Assembler.Urhadd : context.Arm64Assembler.Srhadd, null); + } + + public static void Vrshl(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size, uint q) + { + InstEmitNeonCommon.EmitVectorBinary( + context, + rd, + rm, + rn, + size, + q, + u ? context.Arm64Assembler.UrshlV : context.Arm64Assembler.SrshlV, + u ? context.Arm64Assembler.UrshlS : context.Arm64Assembler.SrshlS); + } + + public static void Vrshr(CodeGenContext context, uint rd, uint rm, bool u, uint l, uint imm6, uint q) + { + uint size = InstEmitNeonCommon.GetSizeFromImm7(imm6 | (l << 6)); + uint shift = InstEmitNeonShift.GetShiftRight(imm6, size); + + InstEmitNeonCommon.EmitVectorBinaryShift( + context, + rd, + rm, + shift, + size, + q, + isShl: false, + u ? context.Arm64Assembler.UrshrV : context.Arm64Assembler.SrshrV, + u ? context.Arm64Assembler.UrshrS : context.Arm64Assembler.SrshrS); + } + + public static void Vrshrn(CodeGenContext context, uint rd, uint rm, uint imm6) + { + uint size = InstEmitNeonCommon.GetSizeFromImm6(imm6); + uint shift = InstEmitNeonShift.GetShiftRight(imm6, size); + + InstEmitNeonCommon.EmitVectorBinaryNarrowShift(context, rd, rm, shift, size, isShl: false, context.Arm64Assembler.Rshrn); + } + + public static void Vrsra(CodeGenContext context, uint rd, uint rm, bool u, uint l, uint imm6, uint q) + { + uint size = InstEmitNeonCommon.GetSizeFromImm7(imm6 | (l << 6)); + uint shift = InstEmitNeonShift.GetShiftRight(imm6, size); + + InstEmitNeonCommon.EmitVectorTernaryRdShift( + context, + rd, + rm, + shift, + size, + q, + isShl: false, + u ? context.Arm64Assembler.UrsraV : context.Arm64Assembler.SrsraV, + u ? context.Arm64Assembler.UrsraS : context.Arm64Assembler.SrsraS); + } + + public static void Vrsubhn(CodeGenContext context, uint rd, uint rn, uint rm, uint size) + { + InstEmitNeonCommon.EmitVectorBinaryNarrow(context, rd, rn, rm, size, context.Arm64Assembler.Rsubhn); + } + + public static void Vrinta(CodeGenContext context, uint rd, uint rm, uint size, uint q) + { + InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FrintaSingleAndDouble, context.Arm64Assembler.FrintaHalf); + } + + public static void Vrintm(CodeGenContext context, uint rd, uint rm, uint size, uint q) + { + InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FrintmSingleAndDouble, context.Arm64Assembler.FrintmHalf); + } + + public static void Vrintn(CodeGenContext context, uint rd, uint rm, uint size, uint q) + { + InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FrintnSingleAndDouble, context.Arm64Assembler.FrintnHalf); + } + + public static void Vrintp(CodeGenContext context, uint rd, uint rm, uint size, uint q) + { + InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FrintpSingleAndDouble, context.Arm64Assembler.FrintpHalf); + } + + public static void Vrintx(CodeGenContext context, uint rd, uint rm, uint size, uint q) + { + InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FrintxSingleAndDouble, context.Arm64Assembler.FrintxHalf); + } + + public static void Vrintz(CodeGenContext context, uint rd, uint rm, uint size, uint q) + { + InstEmitNeonCommon.EmitVectorUnaryAnyF(context, rd, rm, size, q, context.Arm64Assembler.FrintzSingleAndDouble, context.Arm64Assembler.FrintzHalf); + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonSaturate.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonSaturate.cs new file mode 100644 index 000000000..aeab726a3 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonSaturate.cs @@ -0,0 +1,205 @@ +using System.Diagnostics; + +namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 +{ + static class InstEmitNeonSaturate + { + public static void Vqabs(CodeGenContext context, uint rd, uint rm, uint size, uint q) + { + InstEmitNeonCommon.EmitVectorUnary(context, rd, rm, size, q, context.Arm64Assembler.SqabsV); + } + + public static void Vqadd(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size, uint q) + { + InstEmitNeonCommon.EmitVectorBinary( + context, + rd, + rn, + rm, + size, + q, + u ? context.Arm64Assembler.UqaddV : context.Arm64Assembler.SqaddV, + u ? context.Arm64Assembler.UqaddS : context.Arm64Assembler.SqaddS); + } + + public static void Vqdmlal(CodeGenContext context, uint rd, uint rn, uint rm, uint size) + { + InstEmitNeonCommon.EmitVectorBinaryLong(context, rd, rn, rm, size, context.Arm64Assembler.SqdmlalVecV); + } + + public static void VqdmlalS(CodeGenContext context, uint rd, uint rn, uint rm, uint size) + { + InstEmitNeonCommon.EmitVectorBinaryLongByScalar(context, rd, rn, rm, size, context.Arm64Assembler.SqdmlalElt2regElement); + } + + public static void Vqdmlsl(CodeGenContext context, uint rd, uint rn, uint rm, uint size) + { + InstEmitNeonCommon.EmitVectorBinaryLong(context, rd, rn, rm, size, context.Arm64Assembler.SqdmlslVecV); + } + + public static void VqdmlslS(CodeGenContext context, uint rd, uint rn, uint rm, uint size) + { + InstEmitNeonCommon.EmitVectorBinaryLongByScalar(context, rd, rn, rm, size, context.Arm64Assembler.SqdmlslElt2regElement); + } + + public static void Vqdmulh(CodeGenContext context, uint rd, uint rn, uint rm, uint size, uint q) + { + InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, size, q, context.Arm64Assembler.SqdmulhVecV, context.Arm64Assembler.SqdmulhVecS); + } + + public static void VqdmulhS(CodeGenContext context, uint rd, uint rn, uint rm, uint size, uint q) + { + InstEmitNeonCommon.EmitVectorBinaryByScalar(context, rd, rn, rm, size, q, context.Arm64Assembler.SqdmulhElt2regElement); + } + + public static void Vqdmull(CodeGenContext context, uint rd, uint rn, uint rm, uint size) + { + InstEmitNeonCommon.EmitVectorBinaryLong(context, rd, rn, rm, size, context.Arm64Assembler.SqdmullVecV); + } + + public static void VqdmullS(CodeGenContext context, uint rd, uint rn, uint rm, uint size) + { + InstEmitNeonCommon.EmitVectorBinaryLongByScalar(context, rd, rn, rm, size, context.Arm64Assembler.SqdmullElt2regElement); + } + + public static void Vqmovn(CodeGenContext context, uint rd, uint rm, uint op, uint size) + { + if (op == 3) + { + InstEmitNeonCommon.EmitVectorUnaryNarrow(context, rd, rm, size, context.Arm64Assembler.UqxtnV); + } + else + { + InstEmitNeonCommon.EmitVectorUnaryNarrow(context, rd, rm, size, op == 1 ? context.Arm64Assembler.SqxtunV : context.Arm64Assembler.SqxtnV); + } + } + + public static void Vqneg(CodeGenContext context, uint rd, uint rm, uint size, uint q) + { + InstEmitNeonCommon.EmitVectorUnary(context, rd, rm, size, q, context.Arm64Assembler.SqnegV); + } + + public static void Vqrdmlah(CodeGenContext context, uint rd, uint rn, uint rm, uint size, uint q) + { + InstEmitNeonCommon.EmitVectorTernaryRd(context, rd, rn, rm, size, q, context.Arm64Assembler.SqrdmlahVecV); + } + + public static void VqrdmlahS(CodeGenContext context, uint rd, uint rn, uint rm, uint size, uint q) + { + InstEmitNeonCommon.EmitVectorTernaryRdByScalar(context, rd, rn, rm, size, q, context.Arm64Assembler.SqrdmlahElt2regElement); + } + + public static void Vqrdmlsh(CodeGenContext context, uint rd, uint rn, uint rm, uint size, uint q) + { + InstEmitNeonCommon.EmitVectorTernaryRd(context, rd, rn, rm, size, q, context.Arm64Assembler.SqrdmlshVecV); + } + + public static void VqrdmlshS(CodeGenContext context, uint rd, uint rn, uint rm, uint size, uint q) + { + InstEmitNeonCommon.EmitVectorTernaryRdByScalar(context, rd, rn, rm, size, q, context.Arm64Assembler.SqrdmlshElt2regElement); + } + + public static void Vqrdmulh(CodeGenContext context, uint rd, uint rn, uint rm, uint size, uint q) + { + InstEmitNeonCommon.EmitVectorBinary(context, rd, rn, rm, size, q, context.Arm64Assembler.SqrdmulhVecV, context.Arm64Assembler.SqrdmulhVecS); + } + + public static void VqrdmulhS(CodeGenContext context, uint rd, uint rn, uint rm, uint size, uint q) + { + InstEmitNeonCommon.EmitVectorBinaryByScalar(context, rd, rn, rm, size, q, context.Arm64Assembler.SqrdmulhElt2regElement); + } + + public static void Vqrshl(CodeGenContext context, uint rd, uint rn, uint rm, uint size, uint q) + { + InstEmitNeonCommon.EmitVectorBinary(context, rd, rm, rn, size, q, context.Arm64Assembler.SqrshlV, context.Arm64Assembler.SqrshlS); + } + + public static void Vqrshrn(CodeGenContext context, uint rd, uint rm, bool u, uint op, uint imm6) + { + uint size = InstEmitNeonCommon.GetSizeFromImm6(imm6); + uint shift = InstEmitNeonShift.GetShiftRight(imm6, size); + + if (u && op == 0) + { + InstEmitNeonCommon.EmitVectorBinaryNarrowShift(context, rd, rm, shift, size, isShl: false, context.Arm64Assembler.SqrshrunV); + } + else if (!u && op == 1) + { + InstEmitNeonCommon.EmitVectorBinaryNarrowShift(context, rd, rm, shift, size, isShl: false, context.Arm64Assembler.SqrshrnV); + } + else + { + Debug.Assert(u && op == 1); // !u && op == 0 is the encoding for another instruction. + + InstEmitNeonCommon.EmitVectorBinaryNarrowShift(context, rd, rm, shift, size, isShl: false, context.Arm64Assembler.UqrshrnV); + } + } + + public static void VqshlI(CodeGenContext context, uint rd, uint rm, bool u, uint op, uint l, uint imm6, uint q) + { + uint size = InstEmitNeonCommon.GetSizeFromImm7(imm6 | (l << 6)); + uint shift = InstEmitNeonShift.GetShiftLeft(imm6, size); + + if (u && op == 0) + { + InstEmitNeonCommon.EmitVectorBinaryShift(context, rd, rm, shift, size, q, isShl: true, context.Arm64Assembler.SqshluV, context.Arm64Assembler.SqshluS); + } + else if (!u && op == 1) + { + InstEmitNeonCommon.EmitVectorBinaryShift(context, rd, rm, shift, size, q, isShl: true, context.Arm64Assembler.SqshlImmV, context.Arm64Assembler.SqshlImmS); + } + else + { + Debug.Assert(u && op == 1); // !u && op == 0 is the encoding for another instruction. + + InstEmitNeonCommon.EmitVectorBinaryShift(context, rd, rm, shift, size, q, isShl: true, context.Arm64Assembler.UqshlImmV, context.Arm64Assembler.UqshlImmS); + } + } + + public static void VqshlR(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size, uint q) + { + if (u) + { + InstEmitNeonCommon.EmitVectorBinary(context, rd, rm, rn, size, q, context.Arm64Assembler.UqshlRegV, context.Arm64Assembler.UqshlRegS); + } + else + { + InstEmitNeonCommon.EmitVectorBinary(context, rd, rm, rn, size, q, context.Arm64Assembler.SqshlRegV, context.Arm64Assembler.SqshlRegS); + } + } + + public static void Vqshrn(CodeGenContext context, uint rd, uint rm, bool u, uint op, uint imm6) + { + uint size = InstEmitNeonCommon.GetSizeFromImm6(imm6); + uint shift = InstEmitNeonShift.GetShiftRight(imm6, size); + + if (u && op == 0) + { + InstEmitNeonCommon.EmitVectorBinaryNarrowShift(context, rd, rm, shift, size, isShl: false, context.Arm64Assembler.SqshrunV); + } + else if (!u && op == 1) + { + InstEmitNeonCommon.EmitVectorBinaryNarrowShift(context, rd, rm, shift, size, isShl: false, context.Arm64Assembler.SqshrnV); + } + else + { + Debug.Assert(u && op == 1); // !u && op == 0 is the encoding for another instruction. + + InstEmitNeonCommon.EmitVectorBinaryNarrowShift(context, rd, rm, shift, size, isShl: false, context.Arm64Assembler.UqshrnV); + } + } + + public static void Vqsub(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size, uint q) + { + InstEmitNeonCommon.EmitVectorBinary( + context, + rd, + rn, + rm, + size, + q, + u ? context.Arm64Assembler.UqsubV : context.Arm64Assembler.SqsubV, + u ? context.Arm64Assembler.UqsubS : context.Arm64Assembler.SqsubS); + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonShift.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonShift.cs new file mode 100644 index 000000000..9f8d0bdef --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonShift.cs @@ -0,0 +1,123 @@ +namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 +{ + static class InstEmitNeonShift + { + public static void Vshll(CodeGenContext context, uint rd, uint rm, uint imm6, bool u) + { + uint size = InstEmitNeonCommon.GetSizeFromImm7(imm6); + uint shift = GetShiftLeft(imm6, size); + + InstEmitNeonCommon.EmitVectorBinaryLongShift(context, rd, rm, shift, size, isShl: true, u ? context.Arm64Assembler.Ushll : context.Arm64Assembler.Sshll); + } + + public static void Vshll2(CodeGenContext context, uint rd, uint rm, uint size) + { + // Shift can't be encoded, so shift by value - 1 first, then first again by 1. + // Doesn't matter if we do a signed or unsigned shift in this case since all sign bits will be shifted out. + + uint shift = 8u << (int)size; + + InstEmitNeonCommon.EmitVectorBinaryLongShift(context, rd, rm, shift - 1, size, isShl: true, context.Arm64Assembler.Sshll); + InstEmitNeonCommon.EmitVectorBinaryLongShift(context, rd, rd, 1, size, isShl: true, context.Arm64Assembler.Sshll); + } + + public static void VshlI(CodeGenContext context, uint rd, uint rm, uint l, uint imm6, uint q) + { + uint size = InstEmitNeonCommon.GetSizeFromImm7(imm6 | (l << 6)); + uint shift = GetShiftLeft(imm6, size); + + InstEmitNeonCommon.EmitVectorBinaryShift(context, rd, rm, shift, size, q, isShl: true, context.Arm64Assembler.ShlV, context.Arm64Assembler.ShlS); + } + + public static void VshlR(CodeGenContext context, uint rd, uint rn, uint rm, bool u, uint size, uint q) + { + InstEmitNeonCommon.EmitVectorBinary( + context, + rd, + rm, + rn, + size, + q, + u ? context.Arm64Assembler.UshlV : context.Arm64Assembler.SshlV, + u ? context.Arm64Assembler.UshlS : context.Arm64Assembler.SshlS); + } + + public static void Vshr(CodeGenContext context, uint rd, uint rm, bool u, uint l, uint imm6, uint q) + { + uint size = InstEmitNeonCommon.GetSizeFromImm7(imm6 | (l << 6)); + uint shift = GetShiftRight(imm6, size); + + InstEmitNeonCommon.EmitVectorBinaryShift( + context, + rd, + rm, + shift, + size, + q, + isShl: false, + u ? context.Arm64Assembler.UshrV : context.Arm64Assembler.SshrV, + u ? context.Arm64Assembler.UshrS : context.Arm64Assembler.SshrS); + } + + public static void Vshrn(CodeGenContext context, uint rd, uint rm, uint imm6) + { + uint size = InstEmitNeonCommon.GetSizeFromImm6(imm6); + uint shift = GetShiftRight(imm6, size); + + InstEmitNeonCommon.EmitVectorBinaryNarrowShift(context, rd, rm, shift, size, isShl: false, context.Arm64Assembler.Shrn); + } + + public static void Vsli(CodeGenContext context, uint rd, uint rm, uint l, uint imm6, uint q) + { + uint size = InstEmitNeonCommon.GetSizeFromImm7(imm6 | (l << 6)); + uint shift = GetShiftLeft(imm6, size); + + InstEmitNeonCommon.EmitVectorBinaryShift( + context, + rd, + rm, + shift, + size, + q, + isShl: true, + context.Arm64Assembler.SliV, + context.Arm64Assembler.SliS); + } + + public static void Vsra(CodeGenContext context, uint rd, uint rm, bool u, uint l, uint imm6, uint q) + { + uint size = InstEmitNeonCommon.GetSizeFromImm7(imm6 | (l << 6)); + uint shift = GetShiftRight(imm6, size); + + InstEmitNeonCommon.EmitVectorTernaryRdShift( + context, + rd, + rm, + shift, + size, + q, + isShl: false, + u ? context.Arm64Assembler.UsraV : context.Arm64Assembler.SsraV, + u ? context.Arm64Assembler.UsraS : context.Arm64Assembler.SsraS); + } + + public static void Vsri(CodeGenContext context, uint rd, uint rm, uint l, uint imm6, uint q) + { + uint size = InstEmitNeonCommon.GetSizeFromImm7(imm6 | (l << 6)); + uint shift = GetShiftRight(imm6, size); + + InstEmitNeonCommon.EmitVectorBinaryShift(context, rd, rm, shift, size, q, isShl: false, context.Arm64Assembler.SriV, context.Arm64Assembler.SriS); + } + + public static uint GetShiftLeft(uint imm6, uint size) + { + return size < 3 ? imm6 - (8u << (int)size) : imm6; + } + + public static uint GetShiftRight(uint imm6, uint size) + { + return (size == 3 ? 64u : (16u << (int)size)) - imm6; + ; + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonSystem.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonSystem.cs new file mode 100644 index 000000000..8c7bf91d5 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitNeonSystem.cs @@ -0,0 +1,77 @@ +using Ryujinx.Cpu.LightningJit.CodeGen; + +namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 +{ + static class InstEmitNeonSystem + { + public static void Vmrs(CodeGenContext context, uint rt, uint reg) + { + if (context.ConsumeSkipNextInstruction()) + { + // This case means that we managed to combine a VCMP and VMRS instruction, + // so we have nothing to do here as FCMP/FCMPE already set PSTATE.NZCV. + context.SetNzcvModified(); + + return; + } + + if (reg == 1) + { + // FPSCR + + Operand ctx = InstEmitSystem.Register(context.RegisterAllocator.FixedContextRegister); + + if (rt == RegisterUtils.PcRegister) + { + using ScopedRegister fpsrRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + context.Arm64Assembler.LdrRiUn(fpsrRegister.Operand, ctx, NativeContextOffsets.FpFlagsBaseOffset); + context.Arm64Assembler.Lsr(fpsrRegister.Operand, fpsrRegister.Operand, InstEmitCommon.Const(28)); + + InstEmitCommon.RestoreNzcvFlags(context, fpsrRegister.Operand); + + context.SetNzcvModified(); + } + else + { + // FPSCR is a combination of the FPCR and FPSR registers. + // We also need to set the FPSR NZCV bits that no longer exist on AArch64. + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + Operand rtOperand = InstEmitCommon.GetOutputGpr(context, rt); + + context.Arm64Assembler.MrsFpsr(rtOperand); + context.Arm64Assembler.MrsFpcr(tempRegister.Operand); + context.Arm64Assembler.Orr(rtOperand, rtOperand, tempRegister.Operand); + context.Arm64Assembler.LdrRiUn(tempRegister.Operand, ctx, NativeContextOffsets.FpFlagsBaseOffset); + context.Arm64Assembler.Bfc(tempRegister.Operand, 0, 28); + context.Arm64Assembler.Orr(rtOperand, rtOperand, tempRegister.Operand); + } + } + else + { + Operand rtOperand = InstEmitCommon.GetOutputGpr(context, rt); + + context.Arm64Assembler.Mov(rtOperand, 0u); + } + } + + public static void Vmsr(CodeGenContext context, uint rt, uint reg) + { + if (reg == 1) + { + // FPSCR + + // TODO: Do not set bits related to features that are not supported (like FP16)? + + Operand ctx = InstEmitSystem.Register(context.RegisterAllocator.FixedContextRegister); + Operand rtOperand = InstEmitCommon.GetInputGpr(context, rt); + + context.Arm64Assembler.MsrFpcr(rtOperand); + context.Arm64Assembler.MsrFpsr(rtOperand); + context.Arm64Assembler.StrRiUn(rtOperand, ctx, NativeContextOffsets.FpFlagsBaseOffset); + } + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitSaturate.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitSaturate.cs new file mode 100644 index 000000000..e2354f448 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitSaturate.cs @@ -0,0 +1,452 @@ +using Ryujinx.Cpu.LightningJit.CodeGen; +using Ryujinx.Cpu.LightningJit.CodeGen.Arm64; +using System.Diagnostics; + +namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 +{ + static class InstEmitSaturate + { + public static void Qadd(CodeGenContext context, uint rd, uint rn, uint rm) + { + EmitAddSubSaturate(context, rd, rn, rm, doubling: false, add: true); + } + + public static void Qadd16(CodeGenContext context, uint rd, uint rn, uint rm) + { + InstEmitCommon.EmitSigned16BitPair(context, rd, rn, rm, (d, n, m) => + { + context.Arm64Assembler.Add(d, n, m); + EmitSaturateRange(context, d, d, 16, unsigned: false, setQ: false); + }); + } + + public static void Qadd8(CodeGenContext context, uint rd, uint rn, uint rm) + { + InstEmitCommon.EmitSigned8BitPair(context, rd, rn, rm, (d, n, m) => + { + context.Arm64Assembler.Add(d, n, m); + EmitSaturateRange(context, d, d, 8, unsigned: false, setQ: false); + }); + } + + public static void Qasx(CodeGenContext context, uint rd, uint rn, uint rm) + { + InstEmitCommon.EmitSigned16BitXPair(context, rd, rn, rm, (d, n, m, e) => + { + if (e == 0) + { + context.Arm64Assembler.Sub(d, n, m); + } + else + { + context.Arm64Assembler.Add(d, n, m); + } + + EmitSaturateRange(context, d, d, 16, unsigned: false, setQ: false); + }); + } + + public static void Qdadd(CodeGenContext context, uint rd, uint rn, uint rm) + { + EmitAddSubSaturate(context, rd, rn, rm, doubling: true, add: true); + } + + public static void Qdsub(CodeGenContext context, uint rd, uint rn, uint rm) + { + EmitAddSubSaturate(context, rd, rn, rm, doubling: true, add: false); + } + + public static void Qsax(CodeGenContext context, uint rd, uint rn, uint rm) + { + InstEmitCommon.EmitSigned16BitXPair(context, rd, rn, rm, (d, n, m, e) => + { + if (e == 0) + { + context.Arm64Assembler.Add(d, n, m); + } + else + { + context.Arm64Assembler.Sub(d, n, m); + } + + EmitSaturateRange(context, d, d, 16, unsigned: false, setQ: false); + }); + } + + public static void Qsub(CodeGenContext context, uint rd, uint rn, uint rm) + { + EmitAddSubSaturate(context, rd, rn, rm, doubling: false, add: false); + } + + public static void Qsub16(CodeGenContext context, uint rd, uint rn, uint rm) + { + InstEmitCommon.EmitSigned16BitPair(context, rd, rn, rm, (d, n, m) => + { + context.Arm64Assembler.Sub(d, n, m); + EmitSaturateRange(context, d, d, 16, unsigned: false, setQ: false); + }); + } + + public static void Qsub8(CodeGenContext context, uint rd, uint rn, uint rm) + { + InstEmitCommon.EmitSigned8BitPair(context, rd, rn, rm, (d, n, m) => + { + context.Arm64Assembler.Sub(d, n, m); + EmitSaturateRange(context, d, d, 8, unsigned: false, setQ: false); + }); + } + + public static void Ssat(CodeGenContext context, uint rd, uint imm, uint rn, bool sh, uint shift) + { + EmitSaturate(context, rd, imm + 1, rn, sh, shift, unsigned: false); + } + + public static void Ssat16(CodeGenContext context, uint rd, uint imm, uint rn) + { + InstEmitCommon.EmitSigned16BitPair(context, rd, rn, (d, n) => + { + EmitSaturateRange(context, d, n, imm + 1, unsigned: false); + }); + } + + public static void Uqadd16(CodeGenContext context, uint rd, uint rn, uint rm) + { + InstEmitCommon.EmitUnsigned16BitPair(context, rd, rn, rm, (d, n, m) => + { + context.Arm64Assembler.Add(d, n, m); + EmitSaturateUnsignedRange(context, d, 16); + }); + } + + public static void Uqadd8(CodeGenContext context, uint rd, uint rn, uint rm) + { + InstEmitCommon.EmitUnsigned8BitPair(context, rd, rn, rm, (d, n, m) => + { + context.Arm64Assembler.Add(d, n, m); + EmitSaturateUnsignedRange(context, d, 8); + }); + } + + public static void Uqasx(CodeGenContext context, uint rd, uint rn, uint rm) + { + InstEmitCommon.EmitUnsigned16BitXPair(context, rd, rn, rm, (d, n, m, e) => + { + if (e == 0) + { + context.Arm64Assembler.Sub(d, n, m); + } + else + { + context.Arm64Assembler.Add(d, n, m); + } + + EmitSaturateUnsignedRange(context, d, 16); + }); + } + + public static void Uqsax(CodeGenContext context, uint rd, uint rn, uint rm) + { + InstEmitCommon.EmitUnsigned16BitXPair(context, rd, rn, rm, (d, n, m, e) => + { + if (e == 0) + { + context.Arm64Assembler.Add(d, n, m); + } + else + { + context.Arm64Assembler.Sub(d, n, m); + } + + EmitSaturateUnsignedRange(context, d, 16); + }); + } + + public static void Uqsub16(CodeGenContext context, uint rd, uint rn, uint rm) + { + InstEmitCommon.EmitSigned16BitPair(context, rd, rn, rm, (d, n, m) => + { + context.Arm64Assembler.Sub(d, n, m); + EmitSaturateUnsignedRange(context, d, 16); + }); + } + + public static void Uqsub8(CodeGenContext context, uint rd, uint rn, uint rm) + { + InstEmitCommon.EmitSigned8BitPair(context, rd, rn, rm, (d, n, m) => + { + context.Arm64Assembler.Sub(d, n, m); + EmitSaturateUnsignedRange(context, d, 8); + }); + } + + public static void Usat(CodeGenContext context, uint rd, uint imm, uint rn, bool sh, uint shift) + { + EmitSaturate(context, rd, imm, rn, sh, shift, unsigned: true); + } + + public static void Usat16(CodeGenContext context, uint rd, uint imm, uint rn) + { + InstEmitCommon.EmitSigned16BitPair(context, rd, rn, (d, n) => + { + EmitSaturateRange(context, d, n, imm, unsigned: true); + }); + } + + private static void EmitAddSubSaturate(CodeGenContext context, uint rd, uint rn, uint rm, bool doubling, bool add) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + Operand rmOperand = InstEmitCommon.GetInputGpr(context, rm); + + using ScopedRegister tempN = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister tempM = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + Operand tempN64 = new(OperandKind.Register, OperandType.I64, tempN.Operand.Value); + Operand tempM64 = new(OperandKind.Register, OperandType.I64, tempM.Operand.Value); + + context.Arm64Assembler.Sxtw(tempN64, rnOperand); + context.Arm64Assembler.Sxtw(tempM64, rmOperand); + + if (doubling) + { + context.Arm64Assembler.Lsl(tempN64, tempN64, InstEmitCommon.Const(1)); + + EmitSaturateLongToInt(context, tempN64, tempN64); + } + + if (add) + { + context.Arm64Assembler.Add(tempN64, tempN64, tempM64); + } + else + { + context.Arm64Assembler.Sub(tempN64, tempN64, tempM64); + } + + EmitSaturateLongToInt(context, rdOperand, tempN64); + } + + private static void EmitSaturate(CodeGenContext context, uint rd, uint imm, uint rn, bool sh, uint shift, bool unsigned) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + + if (sh && shift == 0) + { + shift = 31; + } + + if (shift != 0) + { + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + if (sh) + { + context.Arm64Assembler.Asr(tempRegister.Operand, rnOperand, InstEmitCommon.Const((int)shift)); + } + else + { + context.Arm64Assembler.Lsl(tempRegister.Operand, rnOperand, InstEmitCommon.Const((int)shift)); + } + + EmitSaturateRange(context, rdOperand, tempRegister.Operand, imm, unsigned); + } + else + { + EmitSaturateRange(context, rdOperand, rnOperand, imm, unsigned); + } + } + + private static void EmitSaturateRange(CodeGenContext context, Operand result, Operand value, uint saturateTo, bool unsigned, bool setQ = true) + { + Debug.Assert(saturateTo <= 32); + Debug.Assert(!unsigned || saturateTo < 32); + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + ScopedRegister tempValue = default; + + bool resultValueOverlap = result.Value == value.Value; + + if (!unsigned && saturateTo == 32) + { + // No saturation possible for this case. + + if (!resultValueOverlap) + { + context.Arm64Assembler.Mov(result, value); + } + + return; + } + else if (saturateTo == 0) + { + // Result is always zero if we saturate 0 bits. + + context.Arm64Assembler.Mov(result, 0u); + + return; + } + + if (resultValueOverlap) + { + tempValue = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + context.Arm64Assembler.Mov(tempValue.Operand, value); + value = tempValue.Operand; + } + + if (unsigned) + { + // Negative values always saturate (to zero). + // So we must always ignore the sign bit when masking, so that the truncated value will differ from the original one. + + context.Arm64Assembler.And(result, value, InstEmitCommon.Const((int)(uint.MaxValue >> (32 - (int)saturateTo)))); + } + else + { + context.Arm64Assembler.Sbfx(result, value, 0, (int)saturateTo); + } + + context.Arm64Assembler.Sub(tempRegister.Operand, value, result); + + int branchIndex = context.CodeWriter.InstructionPointer; + + // If the result is 0, the values are equal and we don't need saturation. + context.Arm64Assembler.Cbz(tempRegister.Operand, 0); + + // Saturate and set Q flag. + if (unsigned) + { + if (saturateTo == 31) + { + // Only saturation case possible when going from 32 bits signed to 32 or 31 bits unsigned + // is when the signed input is negative, as all positive values are representable on a 31 bits range. + + context.Arm64Assembler.Mov(result, 0u); + } + else + { + context.Arm64Assembler.Asr(result, value, InstEmitCommon.Const(31)); + context.Arm64Assembler.Mvn(result, result); + context.Arm64Assembler.Lsr(result, result, InstEmitCommon.Const(32 - (int)saturateTo)); + } + } + else + { + if (saturateTo == 1) + { + context.Arm64Assembler.Asr(result, value, InstEmitCommon.Const(31)); + } + else + { + context.Arm64Assembler.Mov(result, uint.MaxValue >> (33 - (int)saturateTo)); + context.Arm64Assembler.Eor(result, result, value, ArmShiftType.Asr, 31); + } + } + + if (setQ) + { + SetQFlag(context); + } + + int delta = context.CodeWriter.InstructionPointer - branchIndex; + context.CodeWriter.WriteInstructionAt(branchIndex, context.CodeWriter.ReadInstructionAt(branchIndex) | (uint)((delta & 0x7ffff) << 5)); + + if (resultValueOverlap) + { + tempValue.Dispose(); + } + } + + private static void EmitSaturateUnsignedRange(CodeGenContext context, Operand value, uint saturateTo) + { + Debug.Assert(saturateTo <= 32); + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + if (saturateTo == 32) + { + // No saturation possible for this case. + + return; + } + else if (saturateTo == 0) + { + // Result is always zero if we saturate 0 bits. + + context.Arm64Assembler.Mov(value, 0u); + + return; + } + + context.Arm64Assembler.Lsr(tempRegister.Operand, value, InstEmitCommon.Const(32 - (int)saturateTo)); + + int branchIndex = context.CodeWriter.InstructionPointer; + + // If the result is 0, the values are equal and we don't need saturation. + context.Arm64Assembler.Cbz(tempRegister.Operand, 0); + + // Saturate. + context.Arm64Assembler.Mov(value, uint.MaxValue >> (32 - (int)saturateTo)); + + int delta = context.CodeWriter.InstructionPointer - branchIndex; + context.CodeWriter.WriteInstructionAt(branchIndex, context.CodeWriter.ReadInstructionAt(branchIndex) | (uint)((delta & 0x7ffff) << 5)); + } + + private static void EmitSaturateLongToInt(CodeGenContext context, Operand result, Operand value) + { + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + ScopedRegister tempValue = default; + + bool resultValueOverlap = result.Value == value.Value; + + if (resultValueOverlap) + { + tempValue = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + Operand tempValue64 = new(OperandKind.Register, OperandType.I64, tempValue.Operand.Value); + + context.Arm64Assembler.Mov(tempValue64, value); + value = tempValue64; + } + + Operand temp64 = new(OperandKind.Register, OperandType.I64, tempRegister.Operand.Value); + Operand result64 = new(OperandKind.Register, OperandType.I64, result.Value); + + context.Arm64Assembler.Sxtw(result64, value); + context.Arm64Assembler.Sub(temp64, value, result64); + + int branchIndex = context.CodeWriter.InstructionPointer; + + // If the result is 0, the values are equal and we don't need saturation. + context.Arm64Assembler.Cbz(temp64, 0); + + // Saturate and set Q flag. + context.Arm64Assembler.Mov(result, uint.MaxValue >> 1); + context.Arm64Assembler.Eor(result64, result64, value, ArmShiftType.Asr, 63); + + SetQFlag(context); + + int delta = context.CodeWriter.InstructionPointer - branchIndex; + context.CodeWriter.WriteInstructionAt(branchIndex, context.CodeWriter.ReadInstructionAt(branchIndex) | (uint)((delta & 0x7ffff) << 5)); + + context.Arm64Assembler.Mov(result, result); // Zero-extend. + + if (resultValueOverlap) + { + tempValue.Dispose(); + } + } + + public static void SetQFlag(CodeGenContext context) + { + Operand ctx = InstEmitSystem.Register(context.RegisterAllocator.FixedContextRegister); + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + context.Arm64Assembler.LdrRiUn(tempRegister.Operand, ctx, NativeContextOffsets.FlagsBaseOffset); + context.Arm64Assembler.Orr(tempRegister.Operand, tempRegister.Operand, InstEmitCommon.Const(1 << 27)); + context.Arm64Assembler.StrRiUn(tempRegister.Operand, ctx, NativeContextOffsets.FlagsBaseOffset); + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitSystem.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitSystem.cs new file mode 100644 index 000000000..07f9f86a8 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitSystem.cs @@ -0,0 +1,660 @@ +using Ryujinx.Cpu.LightningJit.CodeGen; +using Ryujinx.Cpu.LightningJit.CodeGen.Arm64; +using System; +using System.Diagnostics; +using System.Numerics; +using System.Runtime.InteropServices; + +namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 +{ + static class InstEmitSystem + { + private delegate void SoftwareInterruptHandler(ulong address, int imm); + private delegate ulong Get64(); + private delegate bool GetBool(); + + private const int SpIndex = 31; + + public static void Bkpt(CodeGenContext context, uint imm) + { + context.AddPendingBkpt(imm); + + context.Arm64Assembler.B(0); + } + + public static void Cps(CodeGenContext context, uint imod, uint m, uint a, uint i, uint f, uint mode) + { + // NOP in user mode. + } + + public static void Dbg(CodeGenContext context, uint option) + { + // NOP in ARMv8. + } + + public static void Hlt(CodeGenContext context, uint imm) + { + } + + public static void Mcr(CodeGenContext context, uint encoding, uint coproc, uint opc1, uint rt, uint crn, uint crm, uint opc2) + { + if (coproc != 15 || opc1 != 0) + { + Udf(context, encoding, 0); + + return; + } + + Operand ctx = Register(context.RegisterAllocator.FixedContextRegister); + Operand rtOperand = InstEmitCommon.GetInputGpr(context, rt); + + switch (crn) + { + case 13: // Process and Thread Info. + if (crm == 0) + { + switch (opc2) + { + case 2: + context.Arm64Assembler.StrRiUn(rtOperand, ctx, NativeContextOffsets.TpidrEl0Offset); + return; + } + } + break; + } + } + + public static void Mcrr(CodeGenContext context, uint encoding, uint coproc, uint opc1, uint rt, uint crm) + { + if (coproc != 15 || opc1 != 0) + { + Udf(context, encoding, 0); + + return; + } + + // We don't have any system register that needs to be modified using a 64-bit value. + } + + public static void Mrc(CodeGenContext context, uint encoding, uint coproc, uint opc1, uint rt, uint crn, uint crm, uint opc2) + { + if (coproc != 15 || opc1 != 0) + { + Udf(context, encoding, 0); + + return; + } + + Operand ctx = Register(context.RegisterAllocator.FixedContextRegister); + Operand rtOperand = InstEmitCommon.GetInputGpr(context, rt); + bool hasValue = false; + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + Operand dest = rt == RegisterUtils.PcRegister ? tempRegister.Operand : rtOperand; + + switch (crn) + { + case 13: // Process and Thread Info. + if (crm == 0) + { + switch (opc2) + { + case 2: + context.Arm64Assembler.LdrRiUn(dest, ctx, NativeContextOffsets.TpidrEl0Offset); + hasValue = true; + break; + case 3: + context.Arm64Assembler.LdrRiUn(dest, ctx, NativeContextOffsets.TpidrroEl0Offset); + hasValue = true; + break; + } + } + break; + } + + if (rt == RegisterUtils.PcRegister) + { + context.Arm64Assembler.MsrNzcv(dest); + context.SetNzcvModified(); + } + else if (!hasValue) + { + context.Arm64Assembler.Mov(dest, 0u); + } + } + + public static void Mrrc(CodeGenContext context, uint encoding, uint coproc, uint opc1, uint rt, uint rt2, uint crm) + { + if (coproc != 15) + { + Udf(context, encoding, 0); + + return; + } + + switch (crm) + { + case 14: + switch (opc1) + { + case 0: + context.AddPendingReadCntpct(rt, rt2); + context.Arm64Assembler.B(0); + return; + } + break; + } + + // Unsupported system register. + context.Arm64Assembler.Mov(InstEmitCommon.GetOutputGpr(context, rt), 0u); + context.Arm64Assembler.Mov(InstEmitCommon.GetOutputGpr(context, rt2), 0u); + } + + public static void Mrs(CodeGenContext context, uint rd, bool r) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + + if (r) + { + // Reads SPSR, unpredictable in user mode. + + context.Arm64Assembler.Mov(rdOperand, 0u); + } + else + { + Operand ctx = Register(context.RegisterAllocator.FixedContextRegister); + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + context.Arm64Assembler.LdrRiUn(tempRegister.Operand, ctx, NativeContextOffsets.FlagsBaseOffset); + + // Copy GE flags to destination register. + context.Arm64Assembler.Ubfx(rdOperand, tempRegister.Operand, 16, 4); + + // Insert Q flag. + context.Arm64Assembler.And(tempRegister.Operand, tempRegister.Operand, InstEmitCommon.Const(1 << 27)); + context.Arm64Assembler.Orr(rdOperand, rdOperand, tempRegister.Operand); + + // Insert NZCV flags. + context.Arm64Assembler.MrsNzcv(tempRegister.Operand); + context.Arm64Assembler.Orr(rdOperand, rdOperand, tempRegister.Operand); + + // All other flags can't be accessed in user mode or have "unknown" values. + } + } + + public static void MrsBr(CodeGenContext context, uint rd, uint m1, bool r) + { + Operand rdOperand = InstEmitCommon.GetOutputGpr(context, rd); + + // Reads banked register, unpredictable in user mode. + + context.Arm64Assembler.Mov(rdOperand, 0u); + } + + public static void MsrBr(CodeGenContext context, uint rn, uint m1, bool r) + { + // Writes banked register, unpredictable in user mode. + } + + public static void MsrI(CodeGenContext context, uint imm, uint mask, bool r) + { + if (r) + { + // Writes SPSR, unpredictable in user mode. + } + else + { + Operand ctx = Register(context.RegisterAllocator.FixedContextRegister); + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister tempRegister2 = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + context.Arm64Assembler.LdrRiUn(tempRegister.Operand, ctx, NativeContextOffsets.FlagsBaseOffset); + + if ((mask & 2) != 0) + { + // Endian flag. + + context.Arm64Assembler.Mov(tempRegister2.Operand, (imm >> 9) & 1); + context.Arm64Assembler.Bfi(tempRegister.Operand, tempRegister2.Operand, 9, 1); + } + + if ((mask & 4) != 0) + { + // GE flags. + + context.Arm64Assembler.Mov(tempRegister2.Operand, (imm >> 16) & 0xf); + context.Arm64Assembler.Bfi(tempRegister.Operand, tempRegister2.Operand, 16, 4); + } + + if ((mask & 8) != 0) + { + // NZCVQ flags. + + context.Arm64Assembler.Mov(tempRegister2.Operand, (imm >> 27) & 0x1f); + context.Arm64Assembler.Bfi(tempRegister.Operand, tempRegister2.Operand, 27, 5); + context.Arm64Assembler.Mov(tempRegister2.Operand, (imm >> 28) & 0xf); + InstEmitCommon.RestoreNzcvFlags(context, tempRegister2.Operand); + context.SetNzcvModified(); + } + } + } + + public static void MsrR(CodeGenContext context, uint rn, uint mask, bool r) + { + Operand rnOperand = InstEmitCommon.GetInputGpr(context, rn); + + if (r) + { + // Writes SPSR, unpredictable in user mode. + } + else + { + Operand ctx = Register(context.RegisterAllocator.FixedContextRegister); + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister tempRegister2 = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + context.Arm64Assembler.LdrRiUn(tempRegister.Operand, ctx, NativeContextOffsets.FlagsBaseOffset); + + if ((mask & 2) != 0) + { + // Endian flag. + + context.Arm64Assembler.Lsr(tempRegister2.Operand, rnOperand, InstEmitCommon.Const(9)); + context.Arm64Assembler.Bfi(tempRegister.Operand, tempRegister2.Operand, 9, 1); + } + + if ((mask & 4) != 0) + { + // GE flags. + + context.Arm64Assembler.Lsr(tempRegister2.Operand, rnOperand, InstEmitCommon.Const(16)); + context.Arm64Assembler.Bfi(tempRegister.Operand, tempRegister2.Operand, 16, 4); + } + + if ((mask & 8) != 0) + { + // NZCVQ flags. + + context.Arm64Assembler.Lsr(tempRegister2.Operand, rnOperand, InstEmitCommon.Const(27)); + context.Arm64Assembler.Bfi(tempRegister.Operand, tempRegister2.Operand, 27, 5); + context.Arm64Assembler.Lsr(tempRegister2.Operand, rnOperand, InstEmitCommon.Const(28)); + InstEmitCommon.RestoreNzcvFlags(context, tempRegister2.Operand); + context.SetNzcvModified(); + } + } + } + + public static void Setend(CodeGenContext context, bool e) + { + Operand ctx = Register(context.RegisterAllocator.FixedContextRegister); + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + context.Arm64Assembler.LdrRiUn(tempRegister.Operand, ctx, NativeContextOffsets.FlagsBaseOffset); + + if (e) + { + context.Arm64Assembler.Orr(tempRegister.Operand, tempRegister.Operand, InstEmitCommon.Const(1 << 9)); + } + else + { + context.Arm64Assembler.Bfc(tempRegister.Operand, 9, 1); + } + + context.Arm64Assembler.StrRiUn(tempRegister.Operand, ctx, NativeContextOffsets.FlagsBaseOffset); + } + + public static void Svc(CodeGenContext context, uint imm) + { + context.AddPendingSvc(imm); + context.Arm64Assembler.B(0); + } + + public static void Udf(CodeGenContext context, uint encoding, uint imm) + { + context.AddPendingUdf(encoding); + context.Arm64Assembler.B(0); + } + + public static void PrivilegedInstruction(CodeGenContext context, uint encoding) + { + Udf(context, encoding, 0); + } + + private static IntPtr GetBkptHandlerPtr() + { + return Marshal.GetFunctionPointerForDelegate(NativeInterface.Break); + } + + private static IntPtr GetSvcHandlerPtr() + { + return Marshal.GetFunctionPointerForDelegate(NativeInterface.SupervisorCall); + } + + private static IntPtr GetUdfHandlerPtr() + { + return Marshal.GetFunctionPointerForDelegate(NativeInterface.Undefined); + } + + private static IntPtr GetCntpctEl0Ptr() + { + return Marshal.GetFunctionPointerForDelegate(NativeInterface.GetCntpctEl0); + } + + private static IntPtr CheckSynchronizationPtr() + { + return Marshal.GetFunctionPointerForDelegate(NativeInterface.CheckSynchronization); + } + + public static bool NeedsCall(InstName name) + { + // All instructions that might do a host call should be included here. + // That is required to reserve space on the stack for caller saved registers. + + return name == InstName.Mrrc; + } + + public static bool NeedsCallSkipContext(InstName name) + { + // All instructions that might do a host call should be included here. + // That is required to reserve space on the stack for caller saved registers. + + switch (name) + { + case InstName.Mcr: + case InstName.Mrc: + case InstName.Svc: + case InstName.Udf: + return true; + } + + return false; + } + + public static void WriteBkpt(CodeWriter writer, RegisterAllocator regAlloc, TailMerger tailMerger, int spillBaseOffset, uint pc, uint imm) + { + Assembler asm = new(writer); + + WriteCall(ref asm, regAlloc, GetBkptHandlerPtr(), skipContext: true, spillBaseOffset, null, pc, imm); + WriteSyncPoint(writer, ref asm, regAlloc, tailMerger, spillBaseOffset); + } + + public static void WriteSvc(CodeWriter writer, RegisterAllocator regAlloc, TailMerger tailMerger, int spillBaseOffset, uint pc, uint svcId) + { + Assembler asm = new(writer); + + WriteCall(ref asm, regAlloc, GetSvcHandlerPtr(), skipContext: true, spillBaseOffset, null, pc, svcId); + WriteSyncPoint(writer, ref asm, regAlloc, tailMerger, spillBaseOffset); + } + + public static void WriteUdf(CodeWriter writer, RegisterAllocator regAlloc, TailMerger tailMerger, int spillBaseOffset, uint pc, uint imm) + { + Assembler asm = new(writer); + + WriteCall(ref asm, regAlloc, GetUdfHandlerPtr(), skipContext: true, spillBaseOffset, null, pc, imm); + WriteSyncPoint(writer, ref asm, regAlloc, tailMerger, spillBaseOffset); + } + + public static void WriteReadCntpct(CodeWriter writer, RegisterAllocator regAlloc, int spillBaseOffset, int rt, int rt2) + { + Assembler asm = new(writer); + + uint resultMask = (1u << rt) | (1u << rt2); + int tempRegister = 0; + + while ((resultMask & (1u << tempRegister)) != 0 && tempRegister < 32) + { + tempRegister++; + } + + Debug.Assert(tempRegister < 32); + + WriteSpill(ref asm, regAlloc, resultMask, skipContext: false, spillBaseOffset, tempRegister); + + Operand rn = Register(tempRegister); + + asm.Mov(rn, (ulong)GetCntpctEl0Ptr()); + asm.Blr(rn); + + if (rt != rt2) + { + asm.Lsr(Register(rt2), Register(0), InstEmitCommon.Const(32)); + } + + asm.Mov(Register(rt, OperandType.I32), Register(0, OperandType.I32)); // Zero-extend. + + WriteFill(ref asm, regAlloc, resultMask, skipContext: false, spillBaseOffset, tempRegister); + } + + public static void WriteSyncPoint( + CodeWriter writer, + ref Assembler asm, + RegisterAllocator regAlloc, + TailMerger tailMerger, + int spillBaseOffset, + Action storeToContext = null, + Action loadFromContext = null) + { + int tempRegister = regAlloc.AllocateTempGprRegister(); + + Operand rt = Register(tempRegister, OperandType.I32); + + asm.LdrRiUn(rt, Register(regAlloc.FixedContextRegister), NativeContextOffsets.CounterOffset); + + int branchIndex = writer.InstructionPointer; + asm.Cbnz(rt, 0); + + storeToContext?.Invoke(); + WriteSpill(ref asm, regAlloc, 1u << tempRegister, skipContext: true, spillBaseOffset, tempRegister); + + Operand rn = Register(tempRegister == 0 ? 1 : 0); + + asm.Mov(rn, (ulong)CheckSynchronizationPtr()); + asm.Blr(rn); + + tailMerger.AddConditionalZeroReturn(writer, asm, Register(0, OperandType.I32)); + + WriteFill(ref asm, regAlloc, 1u << tempRegister, skipContext: true, spillBaseOffset, tempRegister); + loadFromContext?.Invoke(); + + asm.LdrRiUn(rt, Register(regAlloc.FixedContextRegister), NativeContextOffsets.CounterOffset); + + uint branchInst = writer.ReadInstructionAt(branchIndex); + writer.WriteInstructionAt(branchIndex, branchInst | (((uint)(writer.InstructionPointer - branchIndex) & 0x7ffff) << 5)); + + asm.Sub(rt, rt, new Operand(OperandKind.Constant, OperandType.I32, 1)); + asm.StrRiUn(rt, Register(regAlloc.FixedContextRegister), NativeContextOffsets.CounterOffset); + + regAlloc.FreeTempGprRegister(tempRegister); + } + + private static void WriteCall( + ref Assembler asm, + RegisterAllocator regAlloc, + IntPtr funcPtr, + bool skipContext, + int spillBaseOffset, + int? resultRegister, + params ulong[] callArgs) + { + uint resultMask = 0u; + + if (resultRegister.HasValue) + { + resultMask = 1u << resultRegister.Value; + } + + int tempRegister = callArgs.Length; + + if (resultRegister.HasValue && tempRegister == resultRegister.Value) + { + tempRegister++; + } + + WriteSpill(ref asm, regAlloc, resultMask, skipContext, spillBaseOffset, tempRegister); + + // We only support up to 7 arguments right now. + // ABI defines the first 8 integer arguments to be passed on registers X0-X7. + // We need at least one register to put the function address on, so that reduces the number of + // registers we can use for that by one. + + Debug.Assert(callArgs.Length < 8); + + for (int index = 0; index < callArgs.Length; index++) + { + asm.Mov(Register(index), callArgs[index]); + } + + Operand rn = Register(tempRegister); + + asm.Mov(rn, (ulong)funcPtr); + asm.Blr(rn); + + if (resultRegister.HasValue && resultRegister.Value != 0) + { + asm.Mov(Register(resultRegister.Value), Register(0)); + } + + WriteFill(ref asm, regAlloc, resultMask, skipContext, spillBaseOffset, tempRegister); + } + + private static void WriteSpill(ref Assembler asm, RegisterAllocator regAlloc, uint exceptMask, bool skipContext, int spillOffset, int tempRegister) + { + if (skipContext) + { + InstEmitFlow.WriteSpillSkipContext(ref asm, regAlloc, spillOffset); + } + else + { + WriteSpillOrFill(ref asm, regAlloc, exceptMask, spillOffset, tempRegister, spill: true); + } + } + + private static void WriteFill(ref Assembler asm, RegisterAllocator regAlloc, uint exceptMask, bool skipContext, int spillOffset, int tempRegister) + { + if (skipContext) + { + InstEmitFlow.WriteFillSkipContext(ref asm, regAlloc, spillOffset); + } + else + { + WriteSpillOrFill(ref asm, regAlloc, exceptMask, spillOffset, tempRegister, spill: false); + } + } + + private static void WriteSpillOrFill( + ref Assembler asm, + RegisterAllocator regAlloc, + uint exceptMask, + int spillOffset, + int tempRegister, + bool spill) + { + uint gprMask = regAlloc.UsedGprsMask & ~(AbiConstants.GprCalleeSavedRegsMask | exceptMask); + + if (!spill) + { + // We must reload the status register before reloading the GPRs, + // since we might otherwise trash one of them by using it as temp register. + + Operand rt = Register(tempRegister, OperandType.I32); + + asm.LdrRiUn(rt, Register(SpIndex), spillOffset + BitOperations.PopCount(gprMask) * 8); + asm.MsrNzcv(rt); + } + + while (gprMask != 0) + { + int reg = BitOperations.TrailingZeroCount(gprMask); + + if (reg < 31 && (gprMask & (2u << reg)) != 0 && spillOffset < RegisterSaveRestore.Encodable9BitsOffsetLimit) + { + if (spill) + { + asm.StpRiUn(Register(reg), Register(reg + 1), Register(SpIndex), spillOffset); + } + else + { + asm.LdpRiUn(Register(reg), Register(reg + 1), Register(SpIndex), spillOffset); + } + + gprMask &= ~(3u << reg); + spillOffset += 16; + } + else + { + if (spill) + { + asm.StrRiUn(Register(reg), Register(SpIndex), spillOffset); + } + else + { + asm.LdrRiUn(Register(reg), Register(SpIndex), spillOffset); + } + + gprMask &= ~(1u << reg); + spillOffset += 8; + } + } + + if (spill) + { + Operand rt = Register(tempRegister, OperandType.I32); + + asm.MrsNzcv(rt); + asm.StrRiUn(rt, Register(SpIndex), spillOffset); + } + + spillOffset += 8; + + if ((spillOffset & 8) != 0) + { + spillOffset += 8; + } + + uint fpSimdMask = regAlloc.UsedFpSimdMask; + + while (fpSimdMask != 0) + { + int reg = BitOperations.TrailingZeroCount(fpSimdMask); + + if (reg < 31 && (fpSimdMask & (2u << reg)) != 0 && spillOffset < RegisterSaveRestore.Encodable9BitsOffsetLimit) + { + if (spill) + { + asm.StpRiUn(Register(reg, OperandType.V128), Register(reg + 1, OperandType.V128), Register(SpIndex), spillOffset); + } + else + { + asm.LdpRiUn(Register(reg, OperandType.V128), Register(reg + 1, OperandType.V128), Register(SpIndex), spillOffset); + } + + fpSimdMask &= ~(3u << reg); + spillOffset += 32; + } + else + { + if (spill) + { + asm.StrRiUn(Register(reg, OperandType.V128), Register(SpIndex), spillOffset); + } + else + { + asm.LdrRiUn(Register(reg, OperandType.V128), Register(SpIndex), spillOffset); + } + + fpSimdMask &= ~(1u << reg); + spillOffset += 16; + } + } + } + + public static Operand Register(int register, OperandType type = OperandType.I64) + { + return new Operand(register, RegisterType.Integer, type); + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitVfpArithmetic.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitVfpArithmetic.cs new file mode 100644 index 000000000..efb2fc6b4 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitVfpArithmetic.cs @@ -0,0 +1,95 @@ +namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 +{ + static class InstEmitVfpArithmetic + { + public static void VabsF(CodeGenContext context, uint rd, uint rm, uint size) + { + InstEmitNeonCommon.EmitScalarUnaryF(context, rd, rm, size, context.Arm64Assembler.FabsFloat); + } + + public static void VaddF(CodeGenContext context, uint rd, uint rn, uint rm, uint size) + { + InstEmitNeonCommon.EmitScalarBinaryF(context, rd, rn, rm, size, context.Arm64Assembler.FaddFloat); + } + + public static void VdivF(CodeGenContext context, uint rd, uint rn, uint rm, uint size) + { + InstEmitNeonCommon.EmitScalarBinaryF(context, rd, rn, rm, size, context.Arm64Assembler.FdivFloat); + } + + public static void VfmaF(CodeGenContext context, uint rd, uint rn, uint rm, uint size) + { + InstEmitNeonCommon.EmitScalarTernaryRdF(context, rd, rn, rm, size, context.Arm64Assembler.FmaddFloat); + } + + public static void VfmsF(CodeGenContext context, uint rd, uint rn, uint rm, uint size) + { + InstEmitNeonCommon.EmitScalarTernaryRdF(context, rd, rn, rm, size, context.Arm64Assembler.FmsubFloat); + } + + public static void VfnmaF(CodeGenContext context, uint rd, uint rn, uint rm, uint size) + { + InstEmitNeonCommon.EmitScalarTernaryRdF(context, rd, rn, rm, size, context.Arm64Assembler.FnmaddFloat); + } + + public static void VfnmsF(CodeGenContext context, uint rd, uint rn, uint rm, uint size) + { + InstEmitNeonCommon.EmitScalarTernaryRdF(context, rd, rn, rm, size, context.Arm64Assembler.FnmsubFloat); + } + + public static void Vmaxnm(CodeGenContext context, uint rd, uint rn, uint rm, uint size) + { + InstEmitNeonCommon.EmitScalarBinaryF(context, rd, rn, rm, size, context.Arm64Assembler.FmaxnmFloat); + } + + public static void Vminnm(CodeGenContext context, uint rd, uint rn, uint rm, uint size) + { + InstEmitNeonCommon.EmitScalarBinaryF(context, rd, rn, rm, size, context.Arm64Assembler.FminnmFloat); + } + + public static void VmlaF(CodeGenContext context, uint rd, uint rn, uint rm, uint size) + { + InstEmitNeonCommon.EmitScalarTernaryMulNegRdF(context, rd, rn, rm, size, negD: false, negProduct: false); + } + + public static void VmlsF(CodeGenContext context, uint rd, uint rn, uint rm, uint size) + { + InstEmitNeonCommon.EmitScalarTernaryMulNegRdF(context, rd, rn, rm, size, negD: false, negProduct: true); + } + + public static void VmulF(CodeGenContext context, uint rd, uint rn, uint rm, uint size) + { + InstEmitNeonCommon.EmitScalarBinaryF(context, rd, rn, rm, size, context.Arm64Assembler.FmulFloat); + } + + public static void VnegF(CodeGenContext context, uint rd, uint rm, uint size) + { + InstEmitNeonCommon.EmitScalarUnaryF(context, rd, rm, size, context.Arm64Assembler.FnegFloat); + } + + public static void VnmlaF(CodeGenContext context, uint rd, uint rn, uint rm, uint size) + { + InstEmitNeonCommon.EmitScalarTernaryMulNegRdF(context, rd, rn, rm, size, negD: true, negProduct: true); + } + + public static void VnmlsF(CodeGenContext context, uint rd, uint rn, uint rm, uint size) + { + InstEmitNeonCommon.EmitScalarTernaryMulNegRdF(context, rd, rn, rm, size, negD: true, negProduct: false); + } + + public static void VnmulF(CodeGenContext context, uint rd, uint rn, uint rm, uint size) + { + InstEmitNeonCommon.EmitScalarBinaryF(context, rd, rn, rm, size, context.Arm64Assembler.FnmulFloat); + } + + public static void VsqrtF(CodeGenContext context, uint rd, uint rm, uint size) + { + InstEmitNeonCommon.EmitScalarUnaryF(context, rd, rm, size, context.Arm64Assembler.FsqrtFloat); + } + + public static void VsubF(CodeGenContext context, uint rd, uint rn, uint rm, uint size) + { + InstEmitNeonCommon.EmitScalarBinaryF(context, rd, rn, rm, size, context.Arm64Assembler.FsubFloat); + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitVfpCompare.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitVfpCompare.cs new file mode 100644 index 000000000..f5f306099 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitVfpCompare.cs @@ -0,0 +1,133 @@ +using Ryujinx.Cpu.LightningJit.CodeGen; +using System; +using System.Diagnostics; + +namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 +{ + static class InstEmitVfpCompare + { + public static void VcmpI(CodeGenContext context, uint cond, uint rd, uint size) + { + EmitVcmpVcmpe(context, cond, rd, 0, size, zero: true, e: false); + } + + public static void VcmpR(CodeGenContext context, uint cond, uint rd, uint rm, uint size) + { + EmitVcmpVcmpe(context, cond, rd, rm, size, zero: false, e: false); + } + + public static void VcmpeI(CodeGenContext context, uint cond, uint rd, uint size) + { + EmitVcmpVcmpe(context, cond, rd, 0, size, zero: true, e: true); + } + + public static void VcmpeR(CodeGenContext context, uint cond, uint rd, uint rm, uint size) + { + EmitVcmpVcmpe(context, cond, rd, rm, size, zero: false, e: true); + } + + private static void EmitVcmpVcmpe(CodeGenContext context, uint cond, uint rd, uint rm, uint size, bool zero, bool e) + { + Debug.Assert(size == 1 || size == 2 || size == 3); + + bool singleRegs = size != 3; + uint ftype = size ^ 2u; + uint opc = zero ? 1u : 0u; + + using ScopedRegister rdReg = InstEmitNeonCommon.MoveScalarToSide(context, rd, singleRegs); + ScopedRegister rmReg; + Operand rmOrZero; + + if (zero) + { + rmReg = default; + rmOrZero = new Operand(0, RegisterType.Vector, OperandType.V128); + } + else + { + rmReg = InstEmitNeonCommon.MoveScalarToSide(context, rm, singleRegs); + rmOrZero = rmReg.Operand; + } + + using ScopedRegister oldFlags = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + bool canPeepholeOptimize = CanFuseVcmpVmrs(context, cond); + if (!canPeepholeOptimize) + { + InstEmitCommon.GetCurrentFlags(context, oldFlags.Operand); + } + + if (e) + { + context.Arm64Assembler.FcmpeFloat(rdReg.Operand, rmOrZero, opc, ftype); + } + else + { + context.Arm64Assembler.FcmpFloat(rdReg.Operand, rmOrZero, opc, ftype); + } + + // Save result flags from the FCMP operation on FPSCR register, then restore the old flags if needed. + + WriteUpdateFpsrNzcv(context); + + if (!canPeepholeOptimize) + { + InstEmitCommon.RestoreNzcvFlags(context, oldFlags.Operand); + } + + if (!zero) + { + rmReg.Dispose(); + } + } + + private static void WriteUpdateFpsrNzcv(CodeGenContext context) + { + using ScopedRegister fpsrRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + using ScopedRegister flagsRegister = context.RegisterAllocator.AllocateTempGprRegisterScoped(); + + Operand ctx = InstEmitSystem.Register(context.RegisterAllocator.FixedContextRegister); + + context.Arm64Assembler.LdrRiUn(fpsrRegister.Operand, ctx, NativeContextOffsets.FpFlagsBaseOffset); + + InstEmitCommon.GetCurrentFlags(context, flagsRegister.Operand); + + context.Arm64Assembler.Bfi(fpsrRegister.Operand, flagsRegister.Operand, 28, 4); + context.Arm64Assembler.StrRiUn(fpsrRegister.Operand, ctx, NativeContextOffsets.FpFlagsBaseOffset); + } + + private static bool CanFuseVcmpVmrs(CodeGenContext context, uint vcmpCond) + { + // Conditions might be different for the VCMP and VMRS instructions if they are inside a IT block, + // we don't bother to check right now, so just always skip if inside an IT block. + if (context.InITBlock) + { + return false; + } + + InstInfo nextInfo = context.PeekNextInstruction(); + + // We're looking for a VMRS instructions. + if (nextInfo.Name != InstName.Vmrs) + { + return false; + } + + // Conditions must match. + if (vcmpCond != (nextInfo.Encoding >> 28)) + { + return false; + } + + // Reg must be 1, Rt must be PC indicating VMRS to PSTATE.NZCV. + if (((nextInfo.Encoding >> 16) & 0xf) != 1 || ((nextInfo.Encoding >> 12) & 0xf) != RegisterUtils.PcRegister) + { + return false; + } + + context.SetSkipNextInstruction(); + + return true; + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitVfpConvert.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitVfpConvert.cs new file mode 100644 index 000000000..8e4886950 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitVfpConvert.cs @@ -0,0 +1,305 @@ +using System; +using System.Diagnostics; + +namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 +{ + static class InstEmitVfpConvert + { + public static void Vcvta(CodeGenContext context, uint rd, uint rm, bool op, uint size) + { + if (size == 3) + { + // F64 -> S32/U32 conversion on SIMD is not supported, so we convert it to a GPR, then insert it back into the SIMD register. + + if (op) + { + InstEmitNeonCommon.EmitScalarUnaryToGprTempF(context, rd, rm, size, 0, context.Arm64Assembler.FcvtasFloat); + } + else + { + InstEmitNeonCommon.EmitScalarUnaryToGprTempF(context, rd, rm, size, 0, context.Arm64Assembler.FcvtauFloat); + } + } + else if (op) + { + InstEmitNeonCommon.EmitScalarUnaryF(context, rd, rm, size, context.Arm64Assembler.FcvtasS, context.Arm64Assembler.FcvtasSH); + } + else + { + InstEmitNeonCommon.EmitScalarUnaryF(context, rd, rm, size, context.Arm64Assembler.FcvtauS, context.Arm64Assembler.FcvtauSH); + } + } + + public static void Vcvtb(CodeGenContext context, uint rd, uint rm, uint sz, uint op) + { + EmitVcvtbVcvtt(context, rd, rm, sz, op, top: false); + } + + public static void Vcvtm(CodeGenContext context, uint rd, uint rm, bool op, uint size) + { + if (size == 3) + { + // F64 -> S32/U32 conversion on SIMD is not supported, so we convert it to a GPR, then insert it back into the SIMD register. + + if (op) + { + InstEmitNeonCommon.EmitScalarUnaryToGprTempF(context, rd, rm, size, 0, context.Arm64Assembler.FcvtmsFloat); + } + else + { + InstEmitNeonCommon.EmitScalarUnaryToGprTempF(context, rd, rm, size, 0, context.Arm64Assembler.FcvtmuFloat); + } + } + else if (op) + { + InstEmitNeonCommon.EmitScalarUnaryF(context, rd, rm, size, context.Arm64Assembler.FcvtmsS, context.Arm64Assembler.FcvtmsSH); + } + else + { + InstEmitNeonCommon.EmitScalarUnaryF(context, rd, rm, size, context.Arm64Assembler.FcvtmuS, context.Arm64Assembler.FcvtmuSH); + } + } + + public static void Vcvtn(CodeGenContext context, uint rd, uint rm, bool op, uint size) + { + if (size == 3) + { + // F64 -> S32/U32 conversion on SIMD is not supported, so we convert it to a GPR, then insert it back into the SIMD register. + + if (op) + { + InstEmitNeonCommon.EmitScalarUnaryToGprTempF(context, rd, rm, size, 0, context.Arm64Assembler.FcvtnsFloat); + } + else + { + InstEmitNeonCommon.EmitScalarUnaryToGprTempF(context, rd, rm, size, 0, context.Arm64Assembler.FcvtnuFloat); + } + } + else if (op) + { + InstEmitNeonCommon.EmitScalarUnaryF(context, rd, rm, size, context.Arm64Assembler.FcvtnsS, context.Arm64Assembler.FcvtnsSH); + } + else + { + InstEmitNeonCommon.EmitScalarUnaryF(context, rd, rm, size, context.Arm64Assembler.FcvtnuS, context.Arm64Assembler.FcvtnuSH); + } + } + + public static void Vcvtp(CodeGenContext context, uint rd, uint rm, bool op, uint size) + { + if (size == 3) + { + // F64 -> S32/U32 conversion on SIMD is not supported, so we convert it to a GPR, then insert it back into the SIMD register. + + if (op) + { + InstEmitNeonCommon.EmitScalarUnaryToGprTempF(context, rd, rm, size, 0, context.Arm64Assembler.FcvtpsFloat); + } + else + { + InstEmitNeonCommon.EmitScalarUnaryToGprTempF(context, rd, rm, size, 0, context.Arm64Assembler.FcvtpuFloat); + } + } + else if (op) + { + InstEmitNeonCommon.EmitScalarUnaryF(context, rd, rm, size, context.Arm64Assembler.FcvtpsS, context.Arm64Assembler.FcvtpsSH); + } + else + { + InstEmitNeonCommon.EmitScalarUnaryF(context, rd, rm, size, context.Arm64Assembler.FcvtpuS, context.Arm64Assembler.FcvtpuSH); + } + } + + public static void VcvtDs(CodeGenContext context, uint rd, uint rm, uint size) + { + bool doubleToSingle = size == 3; + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped(); + + if (doubleToSingle) + { + // Double to single. + + using ScopedRegister rmReg = InstEmitNeonCommon.MoveScalarToSide(context, rm, false); + + context.Arm64Assembler.FcvtFloat(tempRegister.Operand, rmReg.Operand, 0, 1); + + InstEmitNeonCommon.InsertResult(context, tempRegister.Operand, rd, true); + } + else + { + // Single to double. + + using ScopedRegister rmReg = InstEmitNeonCommon.MoveScalarToSide(context, rm, true); + + context.Arm64Assembler.FcvtFloat(tempRegister.Operand, rmReg.Operand, 1, 0); + + InstEmitNeonCommon.InsertResult(context, tempRegister.Operand, rd, false); + } + } + + public static void VcvtIv(CodeGenContext context, uint rd, uint rm, bool unsigned, uint size) + { + if (size == 3) + { + // F64 -> S32/U32 conversion on SIMD is not supported, so we convert it to a GPR, then insert it back into the SIMD register. + + if (unsigned) + { + InstEmitNeonCommon.EmitScalarUnaryToGprTempF(context, rd, rm, size, 0, context.Arm64Assembler.FcvtzuFloatInt); + } + else + { + InstEmitNeonCommon.EmitScalarUnaryToGprTempF(context, rd, rm, size, 0, context.Arm64Assembler.FcvtzsFloatInt); + } + } + else + { + if (unsigned) + { + InstEmitNeonCommon.EmitScalarUnaryF(context, rd, rm, size, context.Arm64Assembler.FcvtzuIntS, context.Arm64Assembler.FcvtzuIntSH); + } + else + { + InstEmitNeonCommon.EmitScalarUnaryF(context, rd, rm, size, context.Arm64Assembler.FcvtzsIntS, context.Arm64Assembler.FcvtzsIntSH); + } + } + } + + public static void VcvtVi(CodeGenContext context, uint rd, uint rm, bool unsigned, uint size) + { + if (size == 3) + { + // S32/U32 -> F64 conversion on SIMD is not supported, so we convert it to a GPR, then insert it back into the SIMD register. + + if (unsigned) + { + InstEmitNeonCommon.EmitScalarUnaryFromGprTempF(context, rd, rm, size, 0, context.Arm64Assembler.UcvtfFloatInt); + } + else + { + InstEmitNeonCommon.EmitScalarUnaryFromGprTempF(context, rd, rm, size, 0, context.Arm64Assembler.ScvtfFloatInt); + } + } + else + { + if (unsigned) + { + InstEmitNeonCommon.EmitScalarUnaryF(context, rd, rm, size, context.Arm64Assembler.UcvtfIntS, context.Arm64Assembler.UcvtfIntSH); + } + else + { + InstEmitNeonCommon.EmitScalarUnaryF(context, rd, rm, size, context.Arm64Assembler.ScvtfIntS, context.Arm64Assembler.ScvtfIntSH); + } + } + } + + public static void VcvtXv(CodeGenContext context, uint rd, uint imm5, bool sx, uint sf, uint op, bool u) + { + Debug.Assert(op >> 1 == 0); + + bool unsigned = u; + bool toFixed = op == 1; + uint size = sf; + uint fbits = Math.Clamp((sx ? 32u : 16u) - imm5, 1, 8u << (int)size); + + if (toFixed) + { + if (unsigned) + { + InstEmitNeonCommon.EmitScalarUnaryFixedF(context, rd, rd, fbits, size, is16Bit: false, context.Arm64Assembler.FcvtzuFixS); + } + else + { + InstEmitNeonCommon.EmitScalarUnaryFixedF(context, rd, rd, fbits, size, is16Bit: false, context.Arm64Assembler.FcvtzsFixS); + } + } + else + { + if (unsigned) + { + InstEmitNeonCommon.EmitScalarUnaryFixedF(context, rd, rd, fbits, size, is16Bit: !sx, context.Arm64Assembler.UcvtfFixS); + } + else + { + InstEmitNeonCommon.EmitScalarUnaryFixedF(context, rd, rd, fbits, size, is16Bit: !sx, context.Arm64Assembler.ScvtfFixS); + } + } + } + + public static void VcvtrIv(CodeGenContext context, uint rd, uint rm, uint op, uint size) + { + bool unsigned = (op & 1) == 0; + + Debug.Assert(size == 1 || size == 2 || size == 3); + + bool singleRegs = size != 3; + + using ScopedRegister rmReg = InstEmitNeonCommon.MoveScalarToSide(context, rm, singleRegs); + + using ScopedRegister tempRegister = InstEmitNeonCommon.PickSimdRegister(context.RegisterAllocator, rmReg); + + // Round using the FPCR rounding mode first, since the FCVTZ instructions will use the round to zero mode. + context.Arm64Assembler.FrintiFloat(tempRegister.Operand, rmReg.Operand, size ^ 2u); + + if (unsigned) + { + if (size == 1) + { + context.Arm64Assembler.FcvtzuIntSH(tempRegister.Operand, tempRegister.Operand); + } + else + { + context.Arm64Assembler.FcvtzuIntS(tempRegister.Operand, tempRegister.Operand, size & 1); + } + } + else + { + if (size == 1) + { + context.Arm64Assembler.FcvtzsIntSH(tempRegister.Operand, tempRegister.Operand); + } + else + { + context.Arm64Assembler.FcvtzsIntS(tempRegister.Operand, tempRegister.Operand, size & 1); + } + } + + InstEmitNeonCommon.InsertResult(context, tempRegister.Operand, rd, singleRegs); + } + + public static void Vcvtt(CodeGenContext context, uint rd, uint rm, uint sz, uint op) + { + EmitVcvtbVcvtt(context, rd, rm, sz, op, top: true); + } + + public static void EmitVcvtbVcvtt(CodeGenContext context, uint rd, uint rm, uint sz, uint op, bool top) + { + bool usesDouble = sz == 1; + bool convertFromHalf = op == 0; + + using ScopedRegister tempRegister = context.RegisterAllocator.AllocateTempSimdRegisterScoped(); + + if (convertFromHalf) + { + // Half to single/double. + + using ScopedRegister rmReg = InstEmitNeonCommon.Move16BitScalarToSide(context, rm, top); + + context.Arm64Assembler.FcvtFloat(tempRegister.Operand, rmReg.Operand, usesDouble ? 1u : 0u, 3u); + + InstEmitNeonCommon.InsertResult(context, tempRegister.Operand, rd, !usesDouble); + } + else + { + // Single/double to half. + + using ScopedRegister rmReg = InstEmitNeonCommon.MoveScalarToSide(context, rm, !usesDouble); + + context.Arm64Assembler.FcvtFloat(tempRegister.Operand, rmReg.Operand, 3u, usesDouble ? 1u : 0u); + + InstEmitNeonCommon.Insert16BitResult(context, tempRegister.Operand, rd, top); + } + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitVfpMove.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitVfpMove.cs new file mode 100644 index 000000000..5c1eefacf --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitVfpMove.cs @@ -0,0 +1,22 @@ +using Ryujinx.Cpu.LightningJit.CodeGen; + +namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 +{ + static class InstEmitVfpMove + { + public static void Vsel(CodeGenContext context, uint rd, uint rn, uint rm, uint cc, uint size) + { + bool singleRegs = size != 3; + uint cond = (cc << 2) | ((cc & 2) ^ ((cc << 1) & 2)); + + using ScopedRegister rnReg = InstEmitNeonCommon.MoveScalarToSide(context, rn, singleRegs); + using ScopedRegister rmReg = InstEmitNeonCommon.MoveScalarToSide(context, rm, singleRegs); + + using ScopedRegister tempRegister = InstEmitNeonCommon.PickSimdRegister(context.RegisterAllocator, rnReg, rmReg); + + context.Arm64Assembler.FcselFloat(tempRegister.Operand, rnReg.Operand, cond, rmReg.Operand, size ^ 2u); + + InstEmitNeonCommon.InsertResult(context, tempRegister.Operand, rd, singleRegs); + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitVfpRound.cs b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitVfpRound.cs new file mode 100644 index 000000000..2826fa642 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm32/Target/Arm64/InstEmitVfpRound.cs @@ -0,0 +1,40 @@ +namespace Ryujinx.Cpu.LightningJit.Arm32.Target.Arm64 +{ + static class InstEmitVfpRound + { + public static void Vrinta(CodeGenContext context, uint rd, uint rm, uint size) + { + InstEmitNeonCommon.EmitScalarUnaryF(context, rd, rm, size, context.Arm64Assembler.FrintaFloat); + } + + public static void Vrintm(CodeGenContext context, uint rd, uint rm, uint size) + { + InstEmitNeonCommon.EmitScalarUnaryF(context, rd, rm, size, context.Arm64Assembler.FrintmFloat); + } + + public static void Vrintn(CodeGenContext context, uint rd, uint rm, uint size) + { + InstEmitNeonCommon.EmitScalarUnaryF(context, rd, rm, size, context.Arm64Assembler.FrintnFloat); + } + + public static void Vrintp(CodeGenContext context, uint rd, uint rm, uint size) + { + InstEmitNeonCommon.EmitScalarUnaryF(context, rd, rm, size, context.Arm64Assembler.FrintpFloat); + } + + public static void Vrintr(CodeGenContext context, uint rd, uint rm, uint size) + { + InstEmitNeonCommon.EmitScalarUnaryF(context, rd, rm, size, context.Arm64Assembler.FrintiFloat); + } + + public static void Vrintx(CodeGenContext context, uint rd, uint rm, uint size) + { + InstEmitNeonCommon.EmitScalarUnaryF(context, rd, rm, size, context.Arm64Assembler.FrintxFloat); + } + + public static void Vrintz(CodeGenContext context, uint rd, uint rm, uint size) + { + InstEmitNeonCommon.EmitScalarUnaryF(context, rd, rm, size, context.Arm64Assembler.FrintzFloat); + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm64/A64Compiler.cs b/src/Ryujinx.Cpu/LightningJit/Arm64/A64Compiler.cs new file mode 100644 index 000000000..b46ae3b0c --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm64/A64Compiler.cs @@ -0,0 +1,29 @@ +using ARMeilleure.Common; +using ARMeilleure.Memory; +using Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64; +using System; +using System.Runtime.InteropServices; + +namespace Ryujinx.Cpu.LightningJit.Arm64 +{ + static class A64Compiler + { + public static CompiledFunction Compile( + CpuPreset cpuPreset, + IMemoryManager memoryManager, + ulong address, + AddressTable funcTable, + IntPtr dispatchStubPtr, + Architecture targetArch) + { + if (targetArch == Architecture.Arm64) + { + return Compiler.Compile(cpuPreset, memoryManager, address, funcTable, dispatchStubPtr); + } + else + { + throw new PlatformNotSupportedException(); + } + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm64/Block.cs b/src/Ryujinx.Cpu/LightningJit/Arm64/Block.cs new file mode 100644 index 000000000..188630a1c --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm64/Block.cs @@ -0,0 +1,138 @@ +using Ryujinx.Cpu.LightningJit.Graph; +using System.Collections.Generic; +using System.Diagnostics; + +namespace Ryujinx.Cpu.LightningJit.Arm64 +{ + class Block : IBlock + { + public int Index { get; private set; } + + private readonly List _predecessors; + private readonly List _successors; + + public int PredecessorsCount => _predecessors.Count; + public int SuccessorsCount => _successors.Count; + + public readonly ulong Address; + public readonly ulong EndAddress; + public readonly List Instructions; + public readonly bool EndsWithBranch; + public readonly bool IsTruncated; + public readonly bool IsLoopEnd; + + public Block(ulong address, ulong endAddress, List instructions, bool endsWithBranch, bool isTruncated, bool isLoopEnd) + { + Debug.Assert((int)((endAddress - address) / 4) == instructions.Count); + + _predecessors = new(); + _successors = new(); + Address = address; + EndAddress = endAddress; + Instructions = instructions; + EndsWithBranch = endsWithBranch; + IsTruncated = isTruncated; + IsLoopEnd = isLoopEnd; + } + + public (Block, Block) SplitAtAddress(ulong address) + { + int splitIndex = (int)((address - Address) / 4); + int splitCount = Instructions.Count - splitIndex; + + // Technically those are valid, but we don't want to create empty blocks. + Debug.Assert(splitIndex != 0); + Debug.Assert(splitCount != 0); + + Block leftBlock = new( + Address, + address, + Instructions.GetRange(0, splitIndex), + false, + false, + false); + + Block rightBlock = new( + address, + EndAddress, + Instructions.GetRange(splitIndex, splitCount), + EndsWithBranch, + IsTruncated, + IsLoopEnd); + + return (leftBlock, rightBlock); + } + + public void Number(int index) + { + Index = index; + } + + public void AddSuccessor(Block block) + { + if (!_successors.Contains(block)) + { + _successors.Add(block); + } + } + + public void AddPredecessor(Block block) + { + if (!_predecessors.Contains(block)) + { + _predecessors.Add(block); + } + } + + public IBlock GetSuccessor(int index) + { + return _successors[index]; + } + + public IBlock GetPredecessor(int index) + { + return _predecessors[index]; + } + + public RegisterUse ComputeUseMasks() + { + if (Instructions.Count == 0) + { + return new(0u, 0u, 0u, 0u, 0u, 0u); + } + + RegisterUse use = Instructions[0].RegisterUse; + + for (int index = 1; index < Instructions.Count; index++) + { + RegisterUse currentUse = Instructions[index].RegisterUse; + + use = new(use.Read | (currentUse.Read & ~use.Write), use.Write | currentUse.Write); + } + + return use; + } + + public bool EndsWithContextLoad() + { + return !IsTruncated && EndsWithContextStoreAndLoad(); + } + + public bool EndsWithContextStore() + { + return EndsWithContextStoreAndLoad(); + } + + private bool EndsWithContextStoreAndLoad() + { + if (Instructions.Count == 0) + { + return false; + } + + InstName lastInstructionName = Instructions[^1].Name; + + return lastInstructionName.IsCall() || lastInstructionName.IsException(); + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm64/ImmUtils.cs b/src/Ryujinx.Cpu/LightningJit/Arm64/ImmUtils.cs new file mode 100644 index 000000000..8a12756b9 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm64/ImmUtils.cs @@ -0,0 +1,20 @@ +namespace Ryujinx.Cpu.LightningJit.Arm64 +{ + static class ImmUtils + { + public static int ExtractSImm14Times4(uint encoding) + { + return ((int)(encoding >> 5) << 18) >> 16; + } + + public static int ExtractSImm19Times4(uint encoding) + { + return ((int)(encoding >> 5) << 13) >> 11; + } + + public static int ExtractSImm26Times4(uint encoding) + { + return (int)(encoding << 6) >> 4; + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm64/InstFlags.cs b/src/Ryujinx.Cpu/LightningJit/Arm64/InstFlags.cs new file mode 100644 index 000000000..5a6c3eb04 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm64/InstFlags.cs @@ -0,0 +1,108 @@ +using System; + +namespace Ryujinx.Cpu.LightningJit.Arm64 +{ + [Flags] + enum InstFlags + { + None = 0, + Rd = 1 << 0, + RdSP = Rd | (1 << 1), + ReadRd = 1 << 2, + Rt = 1 << 3, + RtSeq = Rt | (1 << 4), + ReadRt = 1 << 5, + Rt2 = 1 << 6, + Rn = 1 << 7, + RnSeq = Rn | (1 << 8), + RnSP = Rn | (1 << 9), + Rm = 1 << 10, + Rs = 1 << 11, + Ra = 1 << 12, + Nzcv = 1 << 13, + C = 1 << 14, + S = 1 << 15, + Qc = 1 << 16, + FpSimd = 1 << 17, + FpSimdFromGpr = FpSimd | (1 << 18), + FpSimdToGpr = FpSimd | (1 << 19), + FpSimdFromToGpr = FpSimdFromGpr | FpSimdToGpr, + Memory = 1 << 20, + MemWBack = 1 << 21, + + RdFpSimd = Rd | FpSimd, + RdReadRd = Rd | ReadRd, + RdReadRdRn = Rd | ReadRd | Rn, + RdReadRdRnFpSimd = Rd | ReadRd | Rn | FpSimd, + RdReadRdRnFpSimdFromGpr = Rd | ReadRd | Rn | FpSimdFromGpr, + RdReadRdRnQcFpSimd = Rd | ReadRd | Rn | Qc | FpSimd, + RdReadRdRnRmFpSimd = Rd | ReadRd | Rn | Rm | FpSimd, + RdReadRdRnRmQcFpSimd = Rd | ReadRd | Rn | Rm | Qc | FpSimd, + RdRn = Rd | Rn, + RdRnFpSimd = Rd | Rn | FpSimd, + RdRnFpSimdFromGpr = Rd | Rn | FpSimdFromGpr, + RdRnFpSimdToGpr = Rd | Rn | FpSimdToGpr, + RdRnQcFpSimd = Rd | Rn | Qc | FpSimd, + RdRnRm = Rd | Rn | Rm, + RdRnRmC = Rd | Rn | Rm | C, + RdRnRmCS = Rd | Rn | Rm | C | S, + RdRnRmFpSimd = Rd | Rn | Rm | FpSimd, + RdRnRmNzcv = Rd | Rn | Rm | Nzcv, + RdRnRmNzcvFpSimd = Rd | Rn | Rm | Nzcv | FpSimd, + RdRnRmQcFpSimd = Rd | Rn | Rm | Qc | FpSimd, + RdRnRmRa = Rd | Rn | Rm | Ra, + RdRnRmRaFpSimd = Rd | Rn | Rm | Ra | FpSimd, + RdRnRmS = Rd | Rn | Rm | S, + RdRnRsS = Rd | Rn | Rs | S, + RdRnS = Rd | Rn | S, + RdRnSeqRmFpSimd = Rd | RnSeq | Rm | FpSimd, + RdRnSFpSimd = Rd | Rn | S | FpSimd, + RdRnSFpSimdFromToGpr = Rd | Rn | S | FpSimdFromToGpr, + RdRnSP = Rd | RnSP, + RdRnSPRmS = Rd | RnSP | Rm | S, + RdRnSPS = Rd | RnSP | S, + RdSPRn = RdSP | Rn, + RdSPRnSP = RdSP | RnSP, + RdSPRnSPRm = RdSP | RnSP | Rm, + RnC = Rn | C, + RnNzcvS = Rn | Nzcv | S, + RnRm = Rn | Rm, + RnRmNzcvS = Rn | Rm | Nzcv | S, + RnRmNzcvSFpSimd = Rn | Rm | Nzcv | S | FpSimd, + RnRmSFpSimd = Rn | Rm | S | FpSimd, + RnSPRm = RnSP | Rm, + RtFpSimd = Rt | FpSimd, + RtReadRt = Rt | ReadRt, + RtReadRtRnSP = Rt | ReadRt | RnSP, + RtReadRtRnSPFpSimd = Rt | ReadRt | RnSP | FpSimd, + RtReadRtRnSPFpSimdMemWBack = Rt | ReadRt | RnSP | FpSimd | MemWBack, + RtReadRtRnSPMemWBack = Rt | ReadRt | RnSP | MemWBack, + RtReadRtRnSPRm = Rt | ReadRt | RnSP | Rm, + RtReadRtRnSPRmFpSimd = Rt | ReadRt | RnSP | Rm | FpSimd, + RtReadRtRnSPRmFpSimdMemWBack = Rt | ReadRt | RnSP | Rm | FpSimd | MemWBack, + RtReadRtRnSPRs = Rt | ReadRt | RnSP | Rs, + RtReadRtRnSPRsS = Rt | ReadRt | RnSP | Rs | S, + RtReadRtRt2RnSP = Rt | ReadRt | Rt2 | RnSP, + RtReadRtRt2RnSPFpSimd = Rt | ReadRt | Rt2 | RnSP | FpSimd, + RtReadRtRt2RnSPFpSimdMemWBack = Rt | ReadRt | Rt2 | RnSP | FpSimd | MemWBack, + RtReadRtRt2RnSPMemWBack = Rt | ReadRt | Rt2 | RnSP | MemWBack, + RtReadRtRt2RnSPRs = Rt | ReadRt | Rt2 | RnSP | Rs, + RtReadRtRt2RnSPS = Rt | ReadRt | Rt2 | RnSP | S, + RtRnSP = Rt | RnSP, + RtRnSPFpSimd = Rt | RnSP | FpSimd, + RtRnSPFpSimdMemWBack = Rt | RnSP | FpSimd | MemWBack, + RtRnSPMemWBack = Rt | RnSP | MemWBack, + RtRnSPRm = Rt | RnSP | Rm, + RtRnSPRmFpSimd = Rt | RnSP | Rm | FpSimd, + RtRnSPRmFpSimdMemWBack = Rt | RnSP | Rm | FpSimd | MemWBack, + RtRnSPRs = Rt | RnSP | Rs, + RtRt2RnSP = Rt | Rt2 | RnSP, + RtRt2RnSPFpSimd = Rt | Rt2 | RnSP | FpSimd, + RtRt2RnSPFpSimdMemWBack = Rt | Rt2 | RnSP | FpSimd | MemWBack, + RtRt2RnSPMemWBack = Rt | Rt2 | RnSP | MemWBack, + RtSeqReadRtRnSPFpSimd = RtSeq | ReadRt | RnSP | FpSimd, + RtSeqReadRtRnSPRmFpSimdMemWBack = RtSeq | ReadRt | RnSP | Rm | FpSimd | MemWBack, + RtSeqRnSPFpSimd = RtSeq | RnSP | FpSimd, + RtSeqRnSPRmFpSimdMemWBack = RtSeq | RnSP | Rm | FpSimd | MemWBack, + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm64/InstInfo.cs b/src/Ryujinx.Cpu/LightningJit/Arm64/InstInfo.cs new file mode 100644 index 000000000..031a36577 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm64/InstInfo.cs @@ -0,0 +1,22 @@ +using Ryujinx.Cpu.LightningJit.Graph; + +namespace Ryujinx.Cpu.LightningJit.Arm64 +{ + readonly struct InstInfo + { + public readonly uint Encoding; + public readonly InstName Name; + public readonly InstFlags Flags; + public readonly AddressForm AddressForm; + public readonly RegisterUse RegisterUse; + + public InstInfo(uint encoding, InstName name, InstFlags flags, AddressForm addressForm, in RegisterUse registerUse) + { + Encoding = encoding; + Name = name; + Flags = flags; + AddressForm = addressForm; + RegisterUse = registerUse; + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm64/InstName.cs b/src/Ryujinx.Cpu/LightningJit/Arm64/InstName.cs new file mode 100644 index 000000000..58d78ae6e --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm64/InstName.cs @@ -0,0 +1,1134 @@ +namespace Ryujinx.Cpu.LightningJit.Arm64 +{ + enum InstName + { + Abs, + AbsAdvsimdS, + AbsAdvsimdV, + Adc, + Adcs, + AddAddsubExt, + AddAddsubImm, + AddAddsubShift, + AddAdvsimdS, + AddAdvsimdV, + Addg, + AddhnAdvsimd, + AddpAdvsimdPair, + AddpAdvsimdVec, + AddsAddsubExt, + AddsAddsubImm, + AddsAddsubShift, + AddvAdvsimd, + Adr, + Adrp, + AesdAdvsimd, + AeseAdvsimd, + AesimcAdvsimd, + AesmcAdvsimd, + AndAdvsimd, + AndLogImm, + AndLogShift, + AndsLogImm, + AndsLogShift, + Asrv, + Autda, + Autdb, + AutiaGeneral, + AutiaSystem, + AutibGeneral, + AutibSystem, + Axflag, + BcaxAdvsimd, + BcCond, + BCond, + BfcvtFloat, + BfcvtnAdvsimd, + BfdotAdvsimdElt, + BfdotAdvsimdVec, + Bfm, + BfmlalAdvsimdElt, + BfmlalAdvsimdVec, + BfmmlaAdvsimd, + BicAdvsimdImm, + BicAdvsimdReg, + BicLogShift, + Bics, + BifAdvsimd, + BitAdvsimd, + Bl, + Blr, + Blra, + Br, + Bra, + Brk, + BslAdvsimd, + Bti, + BUncond, + Cas, + Casb, + Cash, + Casp, + Cbnz, + Cbz, + CcmnImm, + CcmnReg, + CcmpImm, + CcmpReg, + Cfinv, + Chkfeat, + Clrbhb, + Clrex, + ClsAdvsimd, + ClsInt, + ClzAdvsimd, + ClzInt, + CmeqAdvsimdRegS, + CmeqAdvsimdRegV, + CmeqAdvsimdZeroS, + CmeqAdvsimdZeroV, + CmgeAdvsimdRegS, + CmgeAdvsimdRegV, + CmgeAdvsimdZeroS, + CmgeAdvsimdZeroV, + CmgtAdvsimdRegS, + CmgtAdvsimdRegV, + CmgtAdvsimdZeroS, + CmgtAdvsimdZeroV, + CmhiAdvsimdS, + CmhiAdvsimdV, + CmhsAdvsimdS, + CmhsAdvsimdV, + CmleAdvsimdS, + CmleAdvsimdV, + CmltAdvsimdS, + CmltAdvsimdV, + CmtstAdvsimdS, + CmtstAdvsimdV, + Cnt, + CntAdvsimd, + Cpyfp, + Cpyfpn, + Cpyfprn, + Cpyfprt, + Cpyfprtn, + Cpyfprtrn, + Cpyfprtwn, + Cpyfpt, + Cpyfptn, + Cpyfptrn, + Cpyfptwn, + Cpyfpwn, + Cpyfpwt, + Cpyfpwtn, + Cpyfpwtrn, + Cpyfpwtwn, + Cpyp, + Cpypn, + Cpyprn, + Cpyprt, + Cpyprtn, + Cpyprtrn, + Cpyprtwn, + Cpypt, + Cpyptn, + Cpyptrn, + Cpyptwn, + Cpypwn, + Cpypwt, + Cpypwtn, + Cpypwtrn, + Cpypwtwn, + Crc32, + Crc32c, + Csdb, + Csel, + Csinc, + Csinv, + Csneg, + Ctz, + Dcps1, + Dcps2, + Dcps3, + Dgh, + Dmb, + Drps, + DsbDsbMemory, + DsbDsbNxs, + DupAdvsimdEltScalarFromElement, + DupAdvsimdEltVectorFromElement, + DupAdvsimdGen, + Eon, + Eor3Advsimd, + EorAdvsimd, + EorLogImm, + EorLogShift, + Eret, + Ereta, + Esb, + ExtAdvsimd, + Extr, + FabdAdvsimdS, + FabdAdvsimdSH, + FabdAdvsimdV, + FabdAdvsimdVH, + FabsAdvsimdHalf, + FabsAdvsimdSingleAndDouble, + FabsFloat, + FacgeAdvsimdS, + FacgeAdvsimdSH, + FacgeAdvsimdV, + FacgeAdvsimdVH, + FacgtAdvsimdS, + FacgtAdvsimdSH, + FacgtAdvsimdV, + FacgtAdvsimdVH, + FaddAdvsimdHalf, + FaddAdvsimdSingleAndDouble, + FaddFloat, + FaddpAdvsimdPairHalf, + FaddpAdvsimdPairSingleAndDouble, + FaddpAdvsimdVecHalf, + FaddpAdvsimdVecSingleAndDouble, + FcaddAdvsimdVec, + FccmpeFloat, + FccmpFloat, + FcmeqAdvsimdRegS, + FcmeqAdvsimdRegSH, + FcmeqAdvsimdRegV, + FcmeqAdvsimdRegVH, + FcmeqAdvsimdZeroS, + FcmeqAdvsimdZeroSH, + FcmeqAdvsimdZeroV, + FcmeqAdvsimdZeroVH, + FcmgeAdvsimdRegS, + FcmgeAdvsimdRegSH, + FcmgeAdvsimdRegV, + FcmgeAdvsimdRegVH, + FcmgeAdvsimdZeroS, + FcmgeAdvsimdZeroSH, + FcmgeAdvsimdZeroV, + FcmgeAdvsimdZeroVH, + FcmgtAdvsimdRegS, + FcmgtAdvsimdRegSH, + FcmgtAdvsimdRegV, + FcmgtAdvsimdRegVH, + FcmgtAdvsimdZeroS, + FcmgtAdvsimdZeroSH, + FcmgtAdvsimdZeroV, + FcmgtAdvsimdZeroVH, + FcmlaAdvsimdElt, + FcmlaAdvsimdVec, + FcmleAdvsimdS, + FcmleAdvsimdSH, + FcmleAdvsimdV, + FcmleAdvsimdVH, + FcmltAdvsimdS, + FcmltAdvsimdSH, + FcmltAdvsimdV, + FcmltAdvsimdVH, + FcmpeFloat, + FcmpFloat, + FcselFloat, + FcvtasAdvsimdS, + FcvtasAdvsimdSH, + FcvtasAdvsimdV, + FcvtasAdvsimdVH, + FcvtasFloat, + FcvtauAdvsimdS, + FcvtauAdvsimdSH, + FcvtauAdvsimdV, + FcvtauAdvsimdVH, + FcvtauFloat, + FcvtFloat, + FcvtlAdvsimd, + FcvtmsAdvsimdS, + FcvtmsAdvsimdSH, + FcvtmsAdvsimdV, + FcvtmsAdvsimdVH, + FcvtmsFloat, + FcvtmuAdvsimdS, + FcvtmuAdvsimdSH, + FcvtmuAdvsimdV, + FcvtmuAdvsimdVH, + FcvtmuFloat, + FcvtnAdvsimd, + FcvtnsAdvsimdS, + FcvtnsAdvsimdSH, + FcvtnsAdvsimdV, + FcvtnsAdvsimdVH, + FcvtnsFloat, + FcvtnuAdvsimdS, + FcvtnuAdvsimdSH, + FcvtnuAdvsimdV, + FcvtnuAdvsimdVH, + FcvtnuFloat, + FcvtpsAdvsimdS, + FcvtpsAdvsimdSH, + FcvtpsAdvsimdV, + FcvtpsAdvsimdVH, + FcvtpsFloat, + FcvtpuAdvsimdS, + FcvtpuAdvsimdSH, + FcvtpuAdvsimdV, + FcvtpuAdvsimdVH, + FcvtpuFloat, + FcvtxnAdvsimdS, + FcvtxnAdvsimdV, + FcvtzsAdvsimdFixS, + FcvtzsAdvsimdFixV, + FcvtzsAdvsimdIntS, + FcvtzsAdvsimdIntSH, + FcvtzsAdvsimdIntV, + FcvtzsAdvsimdIntVH, + FcvtzsFloatFix, + FcvtzsFloatInt, + FcvtzuAdvsimdFixS, + FcvtzuAdvsimdFixV, + FcvtzuAdvsimdIntS, + FcvtzuAdvsimdIntSH, + FcvtzuAdvsimdIntV, + FcvtzuAdvsimdIntVH, + FcvtzuFloatFix, + FcvtzuFloatInt, + FdivAdvsimdHalf, + FdivAdvsimdSingleAndDouble, + FdivFloat, + Fjcvtzs, + FmaddFloat, + FmaxAdvsimdHalf, + FmaxAdvsimdSingleAndDouble, + FmaxFloat, + FmaxnmAdvsimdHalf, + FmaxnmAdvsimdSingleAndDouble, + FmaxnmFloat, + FmaxnmpAdvsimdPairHalf, + FmaxnmpAdvsimdPairSingleAndDouble, + FmaxnmpAdvsimdVecHalf, + FmaxnmpAdvsimdVecSingleAndDouble, + FmaxnmvAdvsimdHalf, + FmaxnmvAdvsimdSingleAndDouble, + FmaxpAdvsimdPairHalf, + FmaxpAdvsimdPairSingleAndDouble, + FmaxpAdvsimdVecHalf, + FmaxpAdvsimdVecSingleAndDouble, + FmaxvAdvsimdHalf, + FmaxvAdvsimdSingleAndDouble, + FminAdvsimdHalf, + FminAdvsimdSingleAndDouble, + FminFloat, + FminnmAdvsimdHalf, + FminnmAdvsimdSingleAndDouble, + FminnmFloat, + FminnmpAdvsimdPairHalf, + FminnmpAdvsimdPairSingleAndDouble, + FminnmpAdvsimdVecHalf, + FminnmpAdvsimdVecSingleAndDouble, + FminnmvAdvsimdHalf, + FminnmvAdvsimdSingleAndDouble, + FminpAdvsimdPairHalf, + FminpAdvsimdPairSingleAndDouble, + FminpAdvsimdVecHalf, + FminpAdvsimdVecSingleAndDouble, + FminvAdvsimdHalf, + FminvAdvsimdSingleAndDouble, + FmlaAdvsimdElt2regElementHalf, + FmlaAdvsimdElt2regElementSingleAndDouble, + FmlaAdvsimdElt2regScalarHalf, + FmlaAdvsimdElt2regScalarSingleAndDouble, + FmlaAdvsimdVecHalf, + FmlaAdvsimdVecSingleAndDouble, + FmlalAdvsimdEltFmlal, + FmlalAdvsimdEltFmlal2, + FmlalAdvsimdVecFmlal, + FmlalAdvsimdVecFmlal2, + FmlsAdvsimdElt2regElementHalf, + FmlsAdvsimdElt2regElementSingleAndDouble, + FmlsAdvsimdElt2regScalarHalf, + FmlsAdvsimdElt2regScalarSingleAndDouble, + FmlsAdvsimdVecHalf, + FmlsAdvsimdVecSingleAndDouble, + FmlslAdvsimdEltFmlsl, + FmlslAdvsimdEltFmlsl2, + FmlslAdvsimdVecFmlsl, + FmlslAdvsimdVecFmlsl2, + FmovAdvsimdPerHalf, + FmovAdvsimdSingleAndDouble, + FmovFloat, + FmovFloatGen, + FmovFloatImm, + FmsubFloat, + FmulAdvsimdElt2regElementHalf, + FmulAdvsimdElt2regElementSingleAndDouble, + FmulAdvsimdElt2regScalarHalf, + FmulAdvsimdElt2regScalarSingleAndDouble, + FmulAdvsimdVecHalf, + FmulAdvsimdVecSingleAndDouble, + FmulFloat, + FmulxAdvsimdElt2regElementHalf, + FmulxAdvsimdElt2regElementSingleAndDouble, + FmulxAdvsimdElt2regScalarHalf, + FmulxAdvsimdElt2regScalarSingleAndDouble, + FmulxAdvsimdVecS, + FmulxAdvsimdVecSH, + FmulxAdvsimdVecV, + FmulxAdvsimdVecVH, + FnegAdvsimdHalf, + FnegAdvsimdSingleAndDouble, + FnegFloat, + FnmaddFloat, + FnmsubFloat, + FnmulFloat, + FrecpeAdvsimdS, + FrecpeAdvsimdSH, + FrecpeAdvsimdV, + FrecpeAdvsimdVH, + FrecpsAdvsimdS, + FrecpsAdvsimdSH, + FrecpsAdvsimdV, + FrecpsAdvsimdVH, + FrecpxAdvsimdHalf, + FrecpxAdvsimdSingleAndDouble, + Frint32xAdvsimd, + Frint32xFloat, + Frint32zAdvsimd, + Frint32zFloat, + Frint64xAdvsimd, + Frint64xFloat, + Frint64zAdvsimd, + Frint64zFloat, + FrintaAdvsimdHalf, + FrintaAdvsimdSingleAndDouble, + FrintaFloat, + FrintiAdvsimdHalf, + FrintiAdvsimdSingleAndDouble, + FrintiFloat, + FrintmAdvsimdHalf, + FrintmAdvsimdSingleAndDouble, + FrintmFloat, + FrintnAdvsimdHalf, + FrintnAdvsimdSingleAndDouble, + FrintnFloat, + FrintpAdvsimdHalf, + FrintpAdvsimdSingleAndDouble, + FrintpFloat, + FrintxAdvsimdHalf, + FrintxAdvsimdSingleAndDouble, + FrintxFloat, + FrintzAdvsimdHalf, + FrintzAdvsimdSingleAndDouble, + FrintzFloat, + FrsqrteAdvsimdS, + FrsqrteAdvsimdSH, + FrsqrteAdvsimdV, + FrsqrteAdvsimdVH, + FrsqrtsAdvsimdS, + FrsqrtsAdvsimdSH, + FrsqrtsAdvsimdV, + FrsqrtsAdvsimdVH, + FsqrtAdvsimdHalf, + FsqrtAdvsimdSingleAndDouble, + FsqrtFloat, + FsubAdvsimdHalf, + FsubAdvsimdSingleAndDouble, + FsubFloat, + Gcsb, + Gcsstr, + Gcssttr, + Gmi, + Hint, + Hlt, + Hvc, + InsAdvsimdElt, + InsAdvsimdGen, + Irg, + Isb, + Ld1AdvsimdMultAsNoPostIndex, + Ld1AdvsimdMultAsPostIndex, + Ld1AdvsimdSnglAsNoPostIndex, + Ld1AdvsimdSnglAsPostIndex, + Ld1rAdvsimdAsNoPostIndex, + Ld1rAdvsimdAsPostIndex, + Ld2AdvsimdMultAsNoPostIndex, + Ld2AdvsimdMultAsPostIndex, + Ld2AdvsimdSnglAsNoPostIndex, + Ld2AdvsimdSnglAsPostIndex, + Ld2rAdvsimdAsNoPostIndex, + Ld2rAdvsimdAsPostIndex, + Ld3AdvsimdMultAsNoPostIndex, + Ld3AdvsimdMultAsPostIndex, + Ld3AdvsimdSnglAsNoPostIndex, + Ld3AdvsimdSnglAsPostIndex, + Ld3rAdvsimdAsNoPostIndex, + Ld3rAdvsimdAsPostIndex, + Ld4AdvsimdMultAsNoPostIndex, + Ld4AdvsimdMultAsPostIndex, + Ld4AdvsimdSnglAsNoPostIndex, + Ld4AdvsimdSnglAsPostIndex, + Ld4rAdvsimdAsNoPostIndex, + Ld4rAdvsimdAsPostIndex, + Ld64b, + Ldadd, + Ldaddb, + Ldaddh, + Ldap1AdvsimdSngl, + Ldaprb, + LdaprBaseRegister, + Ldaprh, + LdaprPostIndexed, + Ldapurb, + LdapurFpsimd, + LdapurGen, + Ldapurh, + Ldapursb, + Ldapursh, + Ldapursw, + Ldar, + Ldarb, + Ldarh, + Ldaxp, + Ldaxr, + Ldaxrb, + Ldaxrh, + Ldclr, + Ldclrb, + Ldclrh, + Ldclrp, + Ldeor, + Ldeorb, + Ldeorh, + Ldg, + Ldgm, + Ldiapp, + Ldlar, + Ldlarb, + Ldlarh, + LdnpFpsimd, + LdnpGen, + LdpFpsimdPostIndexed, + LdpFpsimdPreIndexed, + LdpFpsimdSignedScaledOffset, + LdpGenPostIndexed, + LdpGenPreIndexed, + LdpGenSignedScaledOffset, + LdpswPostIndexed, + LdpswPreIndexed, + LdpswSignedScaledOffset, + Ldra, + LdrbImmPostIndexed, + LdrbImmPreIndexed, + LdrbImmUnsignedScaledOffset, + LdrbReg, + LdrhImmPostIndexed, + LdrhImmPreIndexed, + LdrhImmUnsignedScaledOffset, + LdrhReg, + LdrImmFpsimdPostIndexed, + LdrImmFpsimdPreIndexed, + LdrImmFpsimdUnsignedScaledOffset, + LdrImmGenPostIndexed, + LdrImmGenPreIndexed, + LdrImmGenUnsignedScaledOffset, + LdrLitFpsimd, + LdrLitGen, + LdrRegFpsimd, + LdrRegGen, + LdrsbImmPostIndexed, + LdrsbImmPreIndexed, + LdrsbImmUnsignedScaledOffset, + LdrsbReg, + LdrshImmPostIndexed, + LdrshImmPreIndexed, + LdrshImmUnsignedScaledOffset, + LdrshReg, + LdrswImmPostIndexed, + LdrswImmPreIndexed, + LdrswImmUnsignedScaledOffset, + LdrswLit, + LdrswReg, + Ldset, + Ldsetb, + Ldseth, + Ldsetp, + Ldsmax, + Ldsmaxb, + Ldsmaxh, + Ldsmin, + Ldsminb, + Ldsminh, + Ldtr, + Ldtrb, + Ldtrh, + Ldtrsb, + Ldtrsh, + Ldtrsw, + Ldumax, + Ldumaxb, + Ldumaxh, + Ldumin, + Lduminb, + Lduminh, + Ldurb, + LdurFpsimd, + LdurGen, + Ldurh, + Ldursb, + Ldursh, + Ldursw, + Ldxp, + Ldxr, + Ldxrb, + Ldxrh, + Lslv, + Lsrv, + Madd, + MlaAdvsimdElt, + MlaAdvsimdVec, + MlsAdvsimdElt, + MlsAdvsimdVec, + MoviAdvsimd, + Movk, + Movn, + Movz, + Mrrs, + Mrs, + MsrImm, + Msrr, + MsrReg, + Msub, + MulAdvsimdElt, + MulAdvsimdVec, + MvniAdvsimd, + NegAdvsimdS, + NegAdvsimdV, + Nop, + NotAdvsimd, + OrnAdvsimd, + OrnLogShift, + OrrAdvsimdImm, + OrrAdvsimdReg, + OrrLogImm, + OrrLogShift, + Pacda, + Pacdb, + Pacga, + PaciaGeneral, + PaciaSystem, + PacibGeneral, + PacibSystem, + PmulAdvsimd, + PmullAdvsimd, + PrfmImm, + PrfmLit, + PrfmReg, + Prfum, + Psb, + RaddhnAdvsimd, + Rax1Advsimd, + RbitAdvsimd, + RbitInt, + Rcwcas, + Rcwcasp, + Rcwclr, + Rcwclrp, + Rcwscas, + Rcwscasp, + Rcwsclr, + Rcwsclrp, + Rcwset, + Rcwsetp, + Rcwsset, + Rcwssetp, + Rcwsswp, + Rcwsswpp, + Rcwswp, + Rcwswpp, + Ret, + Reta, + Rev, + Rev16Advsimd, + Rev16Int, + Rev32Advsimd, + Rev32Int, + Rev64Advsimd, + Rmif, + Rorv, + RprfmReg, + RshrnAdvsimd, + RsubhnAdvsimd, + SabaAdvsimd, + SabalAdvsimd, + SabdAdvsimd, + SabdlAdvsimd, + SadalpAdvsimd, + SaddlAdvsimd, + SaddlpAdvsimd, + SaddlvAdvsimd, + SaddwAdvsimd, + Sb, + Sbc, + Sbcs, + Sbfm, + ScvtfAdvsimdFixS, + ScvtfAdvsimdFixV, + ScvtfAdvsimdIntS, + ScvtfAdvsimdIntSH, + ScvtfAdvsimdIntV, + ScvtfAdvsimdIntVH, + ScvtfFloatFix, + ScvtfFloatInt, + Sdiv, + SdotAdvsimdElt, + SdotAdvsimdVec, + Setf, + Setgp, + Setgpn, + Setgpt, + Setgptn, + Setp, + Setpn, + Setpt, + Setptn, + Sev, + Sevl, + Sha1cAdvsimd, + Sha1hAdvsimd, + Sha1mAdvsimd, + Sha1pAdvsimd, + Sha1su0Advsimd, + Sha1su1Advsimd, + Sha256h2Advsimd, + Sha256hAdvsimd, + Sha256su0Advsimd, + Sha256su1Advsimd, + Sha512h2Advsimd, + Sha512hAdvsimd, + Sha512su0Advsimd, + Sha512su1Advsimd, + ShaddAdvsimd, + ShlAdvsimdS, + ShlAdvsimdV, + ShllAdvsimd, + ShrnAdvsimd, + ShsubAdvsimd, + SliAdvsimdS, + SliAdvsimdV, + Sm3partw1Advsimd, + Sm3partw2Advsimd, + Sm3ss1Advsimd, + Sm3tt1aAdvsimd, + Sm3tt1bAdvsimd, + Sm3tt2aAdvsimd, + Sm3tt2bAdvsimd, + Sm4eAdvsimd, + Sm4ekeyAdvsimd, + Smaddl, + SmaxAdvsimd, + SmaxImm, + SmaxpAdvsimd, + SmaxReg, + SmaxvAdvsimd, + Smc, + SminAdvsimd, + SminImm, + SminpAdvsimd, + SminReg, + SminvAdvsimd, + SmlalAdvsimdElt, + SmlalAdvsimdVec, + SmlslAdvsimdElt, + SmlslAdvsimdVec, + SmmlaAdvsimdVec, + SmovAdvsimd, + Smsubl, + Smulh, + SmullAdvsimdElt, + SmullAdvsimdVec, + SqabsAdvsimdS, + SqabsAdvsimdV, + SqaddAdvsimdS, + SqaddAdvsimdV, + SqdmlalAdvsimdElt2regElement, + SqdmlalAdvsimdElt2regScalar, + SqdmlalAdvsimdVecS, + SqdmlalAdvsimdVecV, + SqdmlslAdvsimdElt2regElement, + SqdmlslAdvsimdElt2regScalar, + SqdmlslAdvsimdVecS, + SqdmlslAdvsimdVecV, + SqdmulhAdvsimdElt2regElement, + SqdmulhAdvsimdElt2regScalar, + SqdmulhAdvsimdVecS, + SqdmulhAdvsimdVecV, + SqdmullAdvsimdElt2regElement, + SqdmullAdvsimdElt2regScalar, + SqdmullAdvsimdVecS, + SqdmullAdvsimdVecV, + SqnegAdvsimdS, + SqnegAdvsimdV, + SqrdmlahAdvsimdElt2regElement, + SqrdmlahAdvsimdElt2regScalar, + SqrdmlahAdvsimdVecS, + SqrdmlahAdvsimdVecV, + SqrdmlshAdvsimdElt2regElement, + SqrdmlshAdvsimdElt2regScalar, + SqrdmlshAdvsimdVecS, + SqrdmlshAdvsimdVecV, + SqrdmulhAdvsimdElt2regElement, + SqrdmulhAdvsimdElt2regScalar, + SqrdmulhAdvsimdVecS, + SqrdmulhAdvsimdVecV, + SqrshlAdvsimdS, + SqrshlAdvsimdV, + SqrshrnAdvsimdS, + SqrshrnAdvsimdV, + SqrshrunAdvsimdS, + SqrshrunAdvsimdV, + SqshlAdvsimdImmS, + SqshlAdvsimdImmV, + SqshlAdvsimdRegS, + SqshlAdvsimdRegV, + SqshluAdvsimdS, + SqshluAdvsimdV, + SqshrnAdvsimdS, + SqshrnAdvsimdV, + SqshrunAdvsimdS, + SqshrunAdvsimdV, + SqsubAdvsimdS, + SqsubAdvsimdV, + SqxtnAdvsimdS, + SqxtnAdvsimdV, + SqxtunAdvsimdS, + SqxtunAdvsimdV, + SrhaddAdvsimd, + SriAdvsimdS, + SriAdvsimdV, + SrshlAdvsimdS, + SrshlAdvsimdV, + SrshrAdvsimdS, + SrshrAdvsimdV, + SrsraAdvsimdS, + SrsraAdvsimdV, + SshlAdvsimdS, + SshlAdvsimdV, + SshllAdvsimd, + SshrAdvsimdS, + SshrAdvsimdV, + SsraAdvsimdS, + SsraAdvsimdV, + SsublAdvsimd, + SsubwAdvsimd, + St1AdvsimdMultAsNoPostIndex, + St1AdvsimdMultAsPostIndex, + St1AdvsimdSnglAsNoPostIndex, + St1AdvsimdSnglAsPostIndex, + St2AdvsimdMultAsNoPostIndex, + St2AdvsimdMultAsPostIndex, + St2AdvsimdSnglAsNoPostIndex, + St2AdvsimdSnglAsPostIndex, + St2gPostIndexed, + St2gPreIndexed, + St2gSignedScaledOffset, + St3AdvsimdMultAsNoPostIndex, + St3AdvsimdMultAsPostIndex, + St3AdvsimdSnglAsNoPostIndex, + St3AdvsimdSnglAsPostIndex, + St4AdvsimdMultAsNoPostIndex, + St4AdvsimdMultAsPostIndex, + St4AdvsimdSnglAsNoPostIndex, + St4AdvsimdSnglAsPostIndex, + St64b, + St64bv, + St64bv0, + Stgm, + StgPostIndexed, + StgpPostIndexed, + StgpPreIndexed, + StgPreIndexed, + StgpSignedScaledOffset, + StgSignedScaledOffset, + Stilp, + Stl1AdvsimdSngl, + Stllr, + Stllrb, + Stllrh, + Stlrb, + StlrBaseRegister, + Stlrh, + StlrPreIndexed, + Stlurb, + StlurFpsimd, + StlurGen, + Stlurh, + Stlxp, + Stlxr, + Stlxrb, + Stlxrh, + StnpFpsimd, + StnpGen, + StpFpsimdPostIndexed, + StpFpsimdPreIndexed, + StpFpsimdSignedScaledOffset, + StpGenPostIndexed, + StpGenPreIndexed, + StpGenSignedScaledOffset, + StrbImmPostIndexed, + StrbImmPreIndexed, + StrbImmUnsignedScaledOffset, + StrbReg, + StrhImmPostIndexed, + StrhImmPreIndexed, + StrhImmUnsignedScaledOffset, + StrhReg, + StrImmFpsimdPostIndexed, + StrImmFpsimdPreIndexed, + StrImmFpsimdUnsignedScaledOffset, + StrImmGenPostIndexed, + StrImmGenPreIndexed, + StrImmGenUnsignedScaledOffset, + StrRegFpsimd, + StrRegGen, + Sttr, + Sttrb, + Sttrh, + Sturb, + SturFpsimd, + SturGen, + Sturh, + Stxp, + Stxr, + Stxrb, + Stxrh, + Stz2gPostIndexed, + Stz2gPreIndexed, + Stz2gSignedScaledOffset, + Stzgm, + StzgPostIndexed, + StzgPreIndexed, + StzgSignedScaledOffset, + SubAddsubExt, + SubAddsubImm, + SubAddsubShift, + SubAdvsimdS, + SubAdvsimdV, + Subg, + SubhnAdvsimd, + Subp, + Subps, + SubsAddsubExt, + SubsAddsubImm, + SubsAddsubShift, + SudotAdvsimdElt, + SuqaddAdvsimdS, + SuqaddAdvsimdV, + Svc, + Swp, + Swpb, + Swph, + Swpp, + Sys, + Sysl, + Sysp, + TblAdvsimd, + Tbnz, + TbxAdvsimd, + Tbz, + Tcancel, + Tcommit, + Trn1Advsimd, + Trn2Advsimd, + Tsb, + Tstart, + Ttest, + UabaAdvsimd, + UabalAdvsimd, + UabdAdvsimd, + UabdlAdvsimd, + UadalpAdvsimd, + UaddlAdvsimd, + UaddlpAdvsimd, + UaddlvAdvsimd, + UaddwAdvsimd, + Ubfm, + UcvtfAdvsimdFixS, + UcvtfAdvsimdFixV, + UcvtfAdvsimdIntS, + UcvtfAdvsimdIntSH, + UcvtfAdvsimdIntV, + UcvtfAdvsimdIntVH, + UcvtfFloatFix, + UcvtfFloatInt, + UdfPermUndef, + Udiv, + UdotAdvsimdElt, + UdotAdvsimdVec, + UhaddAdvsimd, + UhsubAdvsimd, + Umaddl, + UmaxAdvsimd, + UmaxImm, + UmaxpAdvsimd, + UmaxReg, + UmaxvAdvsimd, + UminAdvsimd, + UminImm, + UminpAdvsimd, + UminReg, + UminvAdvsimd, + UmlalAdvsimdElt, + UmlalAdvsimdVec, + UmlslAdvsimdElt, + UmlslAdvsimdVec, + UmmlaAdvsimdVec, + UmovAdvsimd, + Umsubl, + Umulh, + UmullAdvsimdElt, + UmullAdvsimdVec, + UqaddAdvsimdS, + UqaddAdvsimdV, + UqrshlAdvsimdS, + UqrshlAdvsimdV, + UqrshrnAdvsimdS, + UqrshrnAdvsimdV, + UqshlAdvsimdImmS, + UqshlAdvsimdImmV, + UqshlAdvsimdRegS, + UqshlAdvsimdRegV, + UqshrnAdvsimdS, + UqshrnAdvsimdV, + UqsubAdvsimdS, + UqsubAdvsimdV, + UqxtnAdvsimdS, + UqxtnAdvsimdV, + UrecpeAdvsimd, + UrhaddAdvsimd, + UrshlAdvsimdS, + UrshlAdvsimdV, + UrshrAdvsimdS, + UrshrAdvsimdV, + UrsqrteAdvsimd, + UrsraAdvsimdS, + UrsraAdvsimdV, + UsdotAdvsimdElt, + UsdotAdvsimdVec, + UshlAdvsimdS, + UshlAdvsimdV, + UshllAdvsimd, + UshrAdvsimdS, + UshrAdvsimdV, + UsmmlaAdvsimdVec, + UsqaddAdvsimdS, + UsqaddAdvsimdV, + UsraAdvsimdS, + UsraAdvsimdV, + UsublAdvsimd, + UsubwAdvsimd, + Uzp1Advsimd, + Uzp2Advsimd, + Wfe, + Wfet, + Wfi, + Wfit, + Xaflag, + XarAdvsimd, + XpacGeneral, + XpacSystem, + XtnAdvsimd, + Yield, + Zip1Advsimd, + Zip2Advsimd, + } + + static class InstNameExtensions + { + public static bool IsCall(this InstName name) + { + return name == InstName.Bl || name == InstName.Blr; + } + + public static bool IsControlFlowOrException(this InstName name) + { + switch (name) + { + case InstName.BUncond: + case InstName.BCond: + case InstName.Bl: + case InstName.Blr: + case InstName.Br: + case InstName.Brk: + case InstName.Cbnz: + case InstName.Cbz: + case InstName.Ret: + case InstName.Tbnz: + case InstName.Tbz: + case InstName.Svc: + case InstName.UdfPermUndef: + return true; + } + + return false; + } + + public static bool IsException(this InstName name) + { + switch (name) + { + case InstName.Brk: + case InstName.Svc: + case InstName.UdfPermUndef: + return true; + } + + return false; + } + + public static bool IsSystem(this InstName name) + { + switch (name) + { + case InstName.Mrs: + case InstName.MsrImm: + case InstName.MsrReg: + return true; + } + + return name.IsException(); + } + + public static bool IsSystemOrCall(this InstName name) + { + switch (name) + { + case InstName.Bl: + case InstName.Blr: + case InstName.Svc: + case InstName.Mrs: + case InstName.MsrImm: + case InstName.MsrReg: + return true; + } + + return false; + } + + public static bool IsPrivileged(this InstName name) + { + switch (name) + { + case InstName.Dcps1: + case InstName.Dcps2: + case InstName.Dcps3: + case InstName.Drps: + case InstName.Eret: + case InstName.Ereta: + case InstName.Hvc: + case InstName.MsrImm: + case InstName.Smc: + return true; + } + + return false; + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm64/MultiBlock.cs b/src/Ryujinx.Cpu/LightningJit/Arm64/MultiBlock.cs new file mode 100644 index 000000000..8ac65059a --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm64/MultiBlock.cs @@ -0,0 +1,64 @@ +using Ryujinx.Cpu.LightningJit.Graph; +using System; +using System.Collections.Generic; + +namespace Ryujinx.Cpu.LightningJit.Arm64 +{ + class MultiBlock : IBlockList + { + public readonly List Blocks; + public readonly RegisterMask[] ReadMasks; + public readonly RegisterMask[] WriteMasks; + public readonly RegisterMask GlobalUseMask; + public readonly bool HasHostCall; + public readonly bool HasMemoryInstruction; + public readonly bool IsTruncated; + + public int Count => Blocks.Count; + + public IBlock this[int index] => Blocks[index]; + + public MultiBlock(List blocks, RegisterMask globalUseMask, bool hasHostCall, bool hasMemoryInstruction) + { + Blocks = blocks; + + (ReadMasks, WriteMasks) = DataFlow.GetGlobalUses(this); + + GlobalUseMask = globalUseMask; + HasHostCall = hasHostCall; + HasMemoryInstruction = hasMemoryInstruction; + IsTruncated = blocks[^1].IsTruncated; + } + + public void PrintDebugInfo() + { + foreach (Block block in Blocks) + { + Console.WriteLine($"bb {block.Index}"); + + List predList = new(); + List succList = new(); + + for (int index = 0; index < block.PredecessorsCount; index++) + { + predList.Add(block.GetPredecessor(index).Index); + } + + for (int index = 0; index < block.SuccessorsCount; index++) + { + succList.Add(block.GetSuccessor(index).Index); + } + + Console.WriteLine($" predecessors: {string.Join(' ', predList)}"); + Console.WriteLine($" successors: {string.Join(' ', succList)}"); + Console.WriteLine($" gpr read mask: 0x{ReadMasks[block.Index].GprMask:X} 0x{block.ComputeUseMasks().Read.GprMask:X}"); + Console.WriteLine($" gpr write mask: 0x{WriteMasks[block.Index].GprMask:X}"); + + for (int index = 0; index < block.Instructions.Count; index++) + { + Console.WriteLine($" {index} 0x{block.Instructions[index].Encoding:X8} {block.Instructions[index].Name}"); + } + } + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm64/RegisterAllocator.cs b/src/Ryujinx.Cpu/LightningJit/Arm64/RegisterAllocator.cs new file mode 100644 index 000000000..c9a932093 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm64/RegisterAllocator.cs @@ -0,0 +1,154 @@ +using Ryujinx.Cpu.LightningJit.CodeGen.Arm64; +using System; +using System.Diagnostics; +using System.Numerics; + +namespace Ryujinx.Cpu.LightningJit.Arm64 +{ + class RegisterAllocator + { + public const int MaxTemps = 1; + public const int MaxTempsInclFixed = MaxTemps + 2; + + private uint _gprMask; + private readonly uint _fpSimdMask; + private readonly uint _pStateMask; + + private uint _tempGprsMask; + + private readonly int[] _registerMap; + + public int FixedContextRegister { get; } + public int FixedPageTableRegister { get; } + + public uint AllGprMask => (_gprMask & ~RegisterUtils.ReservedRegsMask) | _tempGprsMask; + public uint AllFpSimdMask => _fpSimdMask; + public uint AllPStateMask => _pStateMask; + + public RegisterAllocator(uint gprMask, uint fpSimdMask, uint pStateMask, bool hasHostCall) + { + _gprMask = gprMask; + _fpSimdMask = fpSimdMask; + _pStateMask = pStateMask; + + if (hasHostCall) + { + // If the function has calls, we can avoid the need to spill those registers across + // calls by puting them on callee saved registers. + + FixedContextRegister = AllocateAndMarkTempGprRegisterWithPreferencing(); + FixedPageTableRegister = AllocateAndMarkTempGprRegisterWithPreferencing(); + } + else + { + FixedContextRegister = AllocateAndMarkTempGprRegister(); + FixedPageTableRegister = AllocateAndMarkTempGprRegister(); + } + + _tempGprsMask = (1u << FixedContextRegister) | (1u << FixedPageTableRegister); + + _registerMap = new int[32]; + + for (int index = 0; index < _registerMap.Length; index++) + { + _registerMap[index] = index; + } + + BuildRegisterMap(_registerMap); + + Span tempRegisters = stackalloc int[MaxTemps]; + + for (int index = 0; index < tempRegisters.Length; index++) + { + tempRegisters[index] = AllocateAndMarkTempGprRegister(); + } + + for (int index = 0; index < tempRegisters.Length; index++) + { + FreeTempGprRegister(tempRegisters[index]); + } + } + + private void BuildRegisterMap(Span map) + { + uint mask = _gprMask & RegisterUtils.ReservedRegsMask; + + while (mask != 0) + { + int index = BitOperations.TrailingZeroCount(mask); + int remapIndex = AllocateAndMarkTempGprRegister(); + + map[index] = remapIndex; + _tempGprsMask |= 1u << remapIndex; + + mask &= ~(1u << index); + } + } + + public int RemapReservedGprRegister(int index) + { + return _registerMap[index]; + } + + private int AllocateAndMarkTempGprRegister() + { + int index = AllocateTempGprRegister(); + _tempGprsMask |= 1u << index; + + return index; + } + + private int AllocateAndMarkTempGprRegisterWithPreferencing() + { + int index = AllocateTempRegisterWithPreferencing(); + _tempGprsMask |= 1u << index; + + return index; + } + + public int AllocateTempGprRegister() + { + return AllocateTempRegister(ref _gprMask); + } + + public void FreeTempGprRegister(int index) + { + FreeTempRegister(ref _gprMask, index); + } + + private int AllocateTempRegisterWithPreferencing() + { + int firstCalleeSaved = BitOperations.TrailingZeroCount(~_gprMask & AbiConstants.GprCalleeSavedRegsMask); + if (firstCalleeSaved < 32) + { + uint regMask = 1u << firstCalleeSaved; + if ((regMask & RegisterUtils.ReservedRegsMask) == 0) + { + _gprMask |= regMask; + + return firstCalleeSaved; + } + } + + return AllocateTempRegister(ref _gprMask); + } + + private static int AllocateTempRegister(ref uint mask) + { + int index = BitOperations.TrailingZeroCount(~(mask | RegisterUtils.ReservedRegsMask)); + if (index == sizeof(uint) * 8) + { + throw new InvalidOperationException("No free registers."); + } + + mask |= 1u << index; + + return index; + } + + private static void FreeTempRegister(ref uint mask, int index) + { + mask &= ~(1u << index); + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm64/RegisterUtils.cs b/src/Ryujinx.Cpu/LightningJit/Arm64/RegisterUtils.cs new file mode 100644 index 000000000..eb3fc229f --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm64/RegisterUtils.cs @@ -0,0 +1,495 @@ +using System.Diagnostics; + +namespace Ryujinx.Cpu.LightningJit.Arm64 +{ + static class RegisterUtils + { + private const int RdRtBit = 0; + private const int RnBit = 5; + private const int RmRsBit = 16; + private const int RaRt2Bit = 10; + + // Some of those register have specific roles and can't be used as general purpose registers. + // X18 - Reserved for platform specific usage. + // X29 - Frame pointer. + // X30 - Return address. + // X31 - Not an actual register, in some cases maps to SP, and in others to ZR. + public const uint ReservedRegsMask = (1u << 18) | (1u << 29) | (1u << 30) | (1u << 31); + + public const int LrIndex = 30; + public const int SpIndex = 31; + public const int ZrIndex = 31; + public const int SpecialZrIndex = 32; + + public static uint RemapRegisters(RegisterAllocator regAlloc, InstFlags flags, uint encoding) + { + if (flags.HasFlag(InstFlags.Rd) && (!flags.HasFlag(InstFlags.FpSimd) || IsFpToGpr(flags, encoding))) + { + encoding = ReplaceGprRegister(regAlloc, encoding, RdRtBit, flags.HasFlag(InstFlags.RdSP)); + } + + if (flags.HasFlag(InstFlags.Rn) && (!flags.HasFlag(InstFlags.FpSimd) || IsFpFromGpr(flags, encoding) || flags.HasFlag(InstFlags.Memory))) + { + encoding = ReplaceGprRegister(regAlloc, encoding, RnBit, flags.HasFlag(InstFlags.RnSP)); + } + + if (!flags.HasFlag(InstFlags.FpSimd)) + { + if (flags.HasFlag(InstFlags.Rm) || flags.HasFlag(InstFlags.Rs)) + { + encoding = ReplaceGprRegister(regAlloc, encoding, RmRsBit); + } + + if (flags.HasFlag(InstFlags.Ra) || flags.HasFlag(InstFlags.Rt2)) + { + encoding = ReplaceGprRegister(regAlloc, encoding, RaRt2Bit); + } + + if (flags.HasFlag(InstFlags.Rt)) + { + encoding = ReplaceGprRegister(regAlloc, encoding, RdRtBit); + } + } + else if (flags.HasFlag(InstFlags.Rm) && flags.HasFlag(InstFlags.Memory)) + { + encoding = ReplaceGprRegister(regAlloc, encoding, RmRsBit); + } + + return encoding; + } + + public static uint ReplaceRt(uint encoding, int newIndex) + { + return ReplaceRegister(encoding, newIndex, RdRtBit); + } + + public static uint ReplaceRn(uint encoding, int newIndex) + { + return ReplaceRegister(encoding, newIndex, RnBit); + } + + private static uint ReplaceRegister(uint encoding, int newIndex, int bit) + { + encoding &= ~(0x1fu << bit); + encoding |= (uint)newIndex << bit; + + return encoding; + } + + private static uint ReplaceGprRegister(RegisterAllocator regAlloc, uint encoding, int bit, bool hasSP = false) + { + int oldIndex = (int)(encoding >> bit) & 0x1f; + if (oldIndex == ZrIndex && !hasSP) + { + return encoding; + } + + int newIndex = regAlloc.RemapReservedGprRegister(oldIndex); + + encoding &= ~(0x1fu << bit); + encoding |= (uint)newIndex << bit; + + return encoding; + } + + public static (uint, uint) PopulateReadMasks(InstName name, InstFlags flags, uint encoding) + { + uint gprMask = 0; + uint fpSimdMask = 0; + + if (flags.HasFlag(InstFlags.FpSimd)) + { + if (flags.HasFlag(InstFlags.Rd) && flags.HasFlag(InstFlags.ReadRd)) + { + uint mask = MaskFromIndex(ExtractRd(flags, encoding)); + + if (IsFpToGpr(flags, encoding)) + { + gprMask |= mask; + } + else + { + fpSimdMask |= mask; + } + } + + if (flags.HasFlag(InstFlags.Rn)) + { + uint mask = MaskFromIndex(ExtractRn(flags, encoding)); + + if (flags.HasFlag(InstFlags.RnSeq)) + { + int count = GetRnSequenceCount(encoding); + + for (int index = 0; index < count; index++, mask <<= 1) + { + fpSimdMask |= mask; + } + } + else if (IsFpFromGpr(flags, encoding) || flags.HasFlag(InstFlags.Memory)) + { + gprMask |= mask; + } + else + { + fpSimdMask |= mask; + } + } + + if (flags.HasFlag(InstFlags.Rm)) + { + uint mask = MaskFromIndex(ExtractRm(flags, encoding)); + + if (flags.HasFlag(InstFlags.Memory)) + { + gprMask |= mask; + } + else + { + fpSimdMask |= mask; + } + } + + if (flags.HasFlag(InstFlags.Ra)) + { + fpSimdMask |= MaskFromIndex(ExtractRa(flags, encoding)); + } + + if (flags.HasFlag(InstFlags.ReadRt)) + { + if (flags.HasFlag(InstFlags.Rt)) + { + uint mask = MaskFromIndex(ExtractRt(flags, encoding)); + + if (flags.HasFlag(InstFlags.RtSeq)) + { + int count = GetRtSequenceCount(name, encoding); + + for (int index = 0; index < count; index++, mask <<= 1) + { + fpSimdMask |= mask; + } + } + else + { + fpSimdMask |= mask; + } + } + + if (flags.HasFlag(InstFlags.Rt2)) + { + fpSimdMask |= MaskFromIndex(ExtractRt2(flags, encoding)); + } + } + } + else + { + if (flags.HasFlag(InstFlags.Rd) && flags.HasFlag(InstFlags.ReadRd)) + { + gprMask |= MaskFromIndex(ExtractRd(flags, encoding)); + } + + if (flags.HasFlag(InstFlags.Rn)) + { + gprMask |= MaskFromIndex(ExtractRn(flags, encoding)); + } + + if (flags.HasFlag(InstFlags.Rm)) + { + gprMask |= MaskFromIndex(ExtractRm(flags, encoding)); + } + + if (flags.HasFlag(InstFlags.Ra)) + { + gprMask |= MaskFromIndex(ExtractRa(flags, encoding)); + } + + if (flags.HasFlag(InstFlags.ReadRt)) + { + if (flags.HasFlag(InstFlags.Rt)) + { + gprMask |= MaskFromIndex(ExtractRt(flags, encoding)); + } + + if (flags.HasFlag(InstFlags.Rt2)) + { + gprMask |= MaskFromIndex(ExtractRt2(flags, encoding)); + } + } + } + + return (gprMask, fpSimdMask); + } + + public static (uint, uint) PopulateWriteMasks(InstName name, InstFlags flags, uint encoding) + { + uint gprMask = 0; + uint fpSimdMask = 0; + + if (flags.HasFlag(InstFlags.MemWBack)) + { + gprMask |= MaskFromIndex(ExtractRn(flags, encoding)); + } + + if (flags.HasFlag(InstFlags.FpSimd)) + { + if (flags.HasFlag(InstFlags.Rd)) + { + uint mask = MaskFromIndex(ExtractRd(flags, encoding)); + + if (IsFpToGpr(flags, encoding)) + { + gprMask |= mask; + } + else + { + fpSimdMask |= mask; + } + } + + if (!flags.HasFlag(InstFlags.ReadRt)) + { + if (flags.HasFlag(InstFlags.Rt)) + { + uint mask = MaskFromIndex(ExtractRt(flags, encoding)); + + if (flags.HasFlag(InstFlags.RtSeq)) + { + int count = GetRtSequenceCount(name, encoding); + + for (int index = 0; index < count; index++, mask <<= 1) + { + fpSimdMask |= mask; + } + } + else + { + fpSimdMask |= mask; + } + } + + if (flags.HasFlag(InstFlags.Rt2)) + { + fpSimdMask |= MaskFromIndex(ExtractRt2(flags, encoding)); + } + } + } + else + { + if (flags.HasFlag(InstFlags.Rd)) + { + gprMask |= MaskFromIndex(ExtractRd(flags, encoding)); + } + + if (!flags.HasFlag(InstFlags.ReadRt)) + { + if (flags.HasFlag(InstFlags.Rt)) + { + gprMask |= MaskFromIndex(ExtractRt(flags, encoding)); + } + + if (flags.HasFlag(InstFlags.Rt2)) + { + gprMask |= MaskFromIndex(ExtractRt2(flags, encoding)); + } + } + + if (flags.HasFlag(InstFlags.Rs)) + { + gprMask |= MaskFromIndex(ExtractRs(flags, encoding)); + } + } + + return (gprMask, fpSimdMask); + } + + private static uint MaskFromIndex(int index) + { + if (index < SpecialZrIndex) + { + return 1u << index; + } + + return 0u; + } + + private static bool IsFpFromGpr(InstFlags flags, uint encoding) + { + InstFlags bothFlags = InstFlags.FpSimdFromGpr | InstFlags.FpSimdToGpr; + + if ((flags & bothFlags) == bothFlags) // FMOV (general) + { + return (encoding & (1u << 16)) != 0; + } + + return flags.HasFlag(InstFlags.FpSimdFromGpr); + } + + private static bool IsFpToGpr(InstFlags flags, uint encoding) + { + InstFlags bothFlags = InstFlags.FpSimdFromGpr | InstFlags.FpSimdToGpr; + + if ((flags & bothFlags) == bothFlags) // FMOV (general) + { + return (encoding & (1u << 16)) == 0; + } + + return flags.HasFlag(InstFlags.FpSimdToGpr); + } + + private static int GetRtSequenceCount(InstName name, uint encoding) + { + switch (name) + { + case InstName.Ld1AdvsimdMultAsNoPostIndex: + case InstName.Ld1AdvsimdMultAsPostIndex: + case InstName.St1AdvsimdMultAsNoPostIndex: + case InstName.St1AdvsimdMultAsPostIndex: + return ((encoding >> 12) & 0xf) switch + { + 0b0000 => 4, + 0b0010 => 4, + 0b0100 => 3, + 0b0110 => 3, + 0b0111 => 1, + 0b1000 => 2, + 0b1010 => 2, + _ => 1, + }; + case InstName.Ld1rAdvsimdAsNoPostIndex: + case InstName.Ld1rAdvsimdAsPostIndex: + case InstName.Ld1AdvsimdSnglAsNoPostIndex: + case InstName.Ld1AdvsimdSnglAsPostIndex: + case InstName.St1AdvsimdSnglAsNoPostIndex: + case InstName.St1AdvsimdSnglAsPostIndex: + return 1; + case InstName.Ld2rAdvsimdAsNoPostIndex: + case InstName.Ld2rAdvsimdAsPostIndex: + case InstName.Ld2AdvsimdMultAsNoPostIndex: + case InstName.Ld2AdvsimdMultAsPostIndex: + case InstName.Ld2AdvsimdSnglAsNoPostIndex: + case InstName.Ld2AdvsimdSnglAsPostIndex: + case InstName.St2AdvsimdMultAsNoPostIndex: + case InstName.St2AdvsimdMultAsPostIndex: + case InstName.St2AdvsimdSnglAsNoPostIndex: + case InstName.St2AdvsimdSnglAsPostIndex: + return 2; + case InstName.Ld3rAdvsimdAsNoPostIndex: + case InstName.Ld3rAdvsimdAsPostIndex: + case InstName.Ld3AdvsimdMultAsNoPostIndex: + case InstName.Ld3AdvsimdMultAsPostIndex: + case InstName.Ld3AdvsimdSnglAsNoPostIndex: + case InstName.Ld3AdvsimdSnglAsPostIndex: + case InstName.St3AdvsimdMultAsNoPostIndex: + case InstName.St3AdvsimdMultAsPostIndex: + case InstName.St3AdvsimdSnglAsNoPostIndex: + case InstName.St3AdvsimdSnglAsPostIndex: + return 3; + case InstName.Ld4rAdvsimdAsNoPostIndex: + case InstName.Ld4rAdvsimdAsPostIndex: + case InstName.Ld4AdvsimdMultAsNoPostIndex: + case InstName.Ld4AdvsimdMultAsPostIndex: + case InstName.Ld4AdvsimdSnglAsNoPostIndex: + case InstName.Ld4AdvsimdSnglAsPostIndex: + case InstName.St4AdvsimdMultAsNoPostIndex: + case InstName.St4AdvsimdMultAsPostIndex: + case InstName.St4AdvsimdSnglAsNoPostIndex: + case InstName.St4AdvsimdSnglAsPostIndex: + return 4; + } + + return 1; + } + + private static int GetRnSequenceCount(uint encoding) + { + return ((int)(encoding >> 13) & 3) + 1; + } + + public static int ExtractRd(InstFlags flags, uint encoding) + { + Debug.Assert(flags.HasFlag(InstFlags.Rd)); + int index = (int)(encoding >> RdRtBit) & 0x1f; + + if (!flags.HasFlag(InstFlags.RdSP) && index == ZrIndex) + { + return SpecialZrIndex; + } + + return index; + } + + public static int ExtractRn(uint encoding) + { + return (int)(encoding >> RnBit) & 0x1f; + } + + public static int ExtractRn(InstFlags flags, uint encoding) + { + Debug.Assert(flags.HasFlag(InstFlags.Rn)); + int index = ExtractRn(encoding); + + if (!flags.HasFlag(InstFlags.RnSP) && index == ZrIndex) + { + return SpecialZrIndex; + } + + return index; + } + + public static int ExtractRm(uint encoding) + { + return (int)(encoding >> RmRsBit) & 0x1f; + } + + public static int ExtractRm(InstFlags flags, uint encoding) + { + Debug.Assert(flags.HasFlag(InstFlags.Rm)); + int index = ExtractRm(encoding); + + return index == ZrIndex ? SpecialZrIndex : index; + } + + public static int ExtractRs(uint encoding) + { + return (int)(encoding >> RmRsBit) & 0x1f; + } + + public static int ExtractRs(InstFlags flags, uint encoding) + { + Debug.Assert(flags.HasFlag(InstFlags.Rs)); + int index = ExtractRs(encoding); + + return index == ZrIndex ? SpecialZrIndex : index; + } + + public static int ExtractRa(InstFlags flags, uint encoding) + { + Debug.Assert(flags.HasFlag(InstFlags.Ra)); + int index = (int)(encoding >> RaRt2Bit) & 0x1f; + + return index == ZrIndex ? SpecialZrIndex : index; + } + + public static int ExtractRt(uint encoding) + { + return (int)(encoding >> RdRtBit) & 0x1f; + } + + public static int ExtractRt(InstFlags flags, uint encoding) + { + Debug.Assert(flags.HasFlag(InstFlags.Rt)); + int index = ExtractRt(encoding); + + return index == ZrIndex ? SpecialZrIndex : index; + } + + public static int ExtractRt2(InstFlags flags, uint encoding) + { + Debug.Assert(flags.HasFlag(InstFlags.Rt2)); + int index = (int)(encoding >> RaRt2Bit) & 0x1f; + + return index == ZrIndex ? SpecialZrIndex : index; + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/Compiler.cs b/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/Compiler.cs new file mode 100644 index 000000000..7ef3bf49b --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/Compiler.cs @@ -0,0 +1,743 @@ +using ARMeilleure.Common; +using ARMeilleure.Memory; +using Ryujinx.Cpu.LightningJit.CodeGen; +using Ryujinx.Cpu.LightningJit.CodeGen.Arm64; +using Ryujinx.Cpu.LightningJit.Graph; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Numerics; + +namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64 +{ + static class Compiler + { + private const int Encodable26BitsOffsetLimit = 0x2000000; + + private readonly struct Context + { + public readonly CodeWriter Writer; + public readonly RegisterAllocator RegisterAllocator; + public readonly TailMerger TailMerger; + public readonly AddressTable FuncTable; + public readonly IntPtr DispatchStubPointer; + + private readonly MultiBlock _multiBlock; + private readonly RegisterSaveRestore _registerSaveRestore; + private readonly IntPtr _pageTablePointer; + + public Context( + CodeWriter writer, + RegisterAllocator registerAllocator, + TailMerger tailMerger, + RegisterSaveRestore registerSaveRestore, + MultiBlock multiBlock, + AddressTable funcTable, + IntPtr dispatchStubPointer, + IntPtr pageTablePointer) + { + Writer = writer; + RegisterAllocator = registerAllocator; + TailMerger = tailMerger; + _registerSaveRestore = registerSaveRestore; + _multiBlock = multiBlock; + FuncTable = funcTable; + DispatchStubPointer = dispatchStubPointer; + _pageTablePointer = pageTablePointer; + } + + public readonly int GetLrRegisterIndex() + { + return RemapGprRegister(RegisterUtils.LrIndex); + } + + public readonly int RemapGprRegister(int index) + { + return RegisterAllocator.RemapReservedGprRegister(index); + } + + public readonly int GetReservedStackOffset() + { + return _registerSaveRestore.GetReservedStackOffset(); + } + + public readonly void WritePrologue() + { + Assembler asm = new(Writer); + + _registerSaveRestore.WritePrologue(ref asm); + + // If needed, set up the fixed registers with the pointers we will use. + // First one is the context pointer (passed as first argument), + // second one is the page table or address space base, it is at a fixed memory location and considered constant. + + if (RegisterAllocator.FixedContextRegister != 0) + { + asm.Mov(Register(RegisterAllocator.FixedContextRegister), Register(0)); + } + + if (_multiBlock.HasMemoryInstruction) + { + asm.Mov(Register(RegisterAllocator.FixedPageTableRegister), (ulong)_pageTablePointer); + } + + // This assumes that the block with the index 0 is always the entry block. + LoadFromContext(ref asm, _multiBlock.ReadMasks[0]); + } + + public readonly void WriteEpilogueWithoutContext() + { + Assembler asm = new(Writer); + + _registerSaveRestore.WriteEpilogue(ref asm); + } + + public void LoadFromContextAfterCall(int blockIndex) + { + Block block = _multiBlock.Blocks[blockIndex]; + + if (block.SuccessorsCount != 0) + { + Assembler asm = new(Writer); + + RegisterMask readMask = _multiBlock.ReadMasks[block.GetSuccessor(0).Index]; + + for (int sIndex = 1; sIndex < block.SuccessorsCount; sIndex++) + { + IBlock successor = block.GetSuccessor(sIndex); + + readMask |= _multiBlock.ReadMasks[successor.Index]; + } + + LoadFromContext(ref asm, readMask); + } + } + + private void LoadFromContext(ref Assembler asm, RegisterMask readMask) + { + LoadGprFromContext(ref asm, readMask.GprMask, NativeContextOffsets.GprBaseOffset); + LoadFpSimdFromContext(ref asm, readMask.FpSimdMask, NativeContextOffsets.FpSimdBaseOffset); + LoadPStateFromContext(ref asm, readMask.PStateMask, NativeContextOffsets.FlagsBaseOffset); + } + + public void StoreToContextBeforeCall(int blockIndex, ulong? newLrValue = null) + { + Assembler asm = new(Writer); + + StoreToContext(ref asm, _multiBlock.WriteMasks[blockIndex], newLrValue); + } + + private void StoreToContext(ref Assembler asm, RegisterMask writeMask, ulong? newLrValue) + { + StoreGprToContext(ref asm, writeMask.GprMask, NativeContextOffsets.GprBaseOffset, newLrValue); + StoreFpSimdToContext(ref asm, writeMask.FpSimdMask, NativeContextOffsets.FpSimdBaseOffset); + StorePStateToContext(ref asm, writeMask.PStateMask, NativeContextOffsets.FlagsBaseOffset); + } + + private void LoadGprFromContext(ref Assembler asm, uint mask, int baseOffset) + { + Operand contextPtr = Register(RegisterAllocator.FixedContextRegister); + + while (mask != 0) + { + int reg = BitOperations.TrailingZeroCount(mask); + int offset = baseOffset + reg * 8; + + if (reg < 31 && (mask & (2u << reg)) != 0 && offset < RegisterSaveRestore.Encodable9BitsOffsetLimit) + { + mask &= ~(3u << reg); + + asm.LdpRiUn( + Register(RegisterAllocator.RemapReservedGprRegister(reg)), + Register(RegisterAllocator.RemapReservedGprRegister(reg + 1)), + contextPtr, + offset); + } + else + { + mask &= ~(1u << reg); + + asm.LdrRiUn(Register(RegisterAllocator.RemapReservedGprRegister(reg)), contextPtr, offset); + } + } + } + + private void LoadFpSimdFromContext(ref Assembler asm, uint mask, int baseOffset) + { + Operand contextPtr = Register(RegisterAllocator.FixedContextRegister); + + while (mask != 0) + { + int reg = BitOperations.TrailingZeroCount(mask); + int offset = baseOffset + reg * 16; + + mask &= ~(1u << reg); + + asm.LdrRiUn(Register(reg, OperandType.V128), contextPtr, offset); + } + } + + private void LoadPStateFromContext(ref Assembler asm, uint mask, int baseOffset) + { + if (mask == 0) + { + return; + } + + Operand contextPtr = Register(RegisterAllocator.FixedContextRegister); + + int tempRegister = RegisterAllocator.AllocateTempGprRegister(); + + Operand rt = Register(tempRegister, OperandType.I32); + + asm.LdrRiUn(rt, contextPtr, baseOffset); + asm.MsrNzcv(rt); + + RegisterAllocator.FreeTempGprRegister(tempRegister); + } + + private void StoreGprToContext(ref Assembler asm, uint mask, int baseOffset, ulong? newLrValue) + { + Operand contextPtr = Register(RegisterAllocator.FixedContextRegister); + + int tempRegister = -1; + + if (newLrValue.HasValue) + { + // This is required for BLR X30 instructions, where we need to get the target address + // before it is overwritten with the return address that the call would write there. + + tempRegister = RegisterAllocator.AllocateTempGprRegister(); + + asm.Mov(Register(tempRegister), newLrValue.Value); + } + + while (mask != 0) + { + int reg = BitOperations.TrailingZeroCount(mask); + int offset = baseOffset + reg * 8; + + if (reg < 31 && (mask & (2u << reg)) != 0 && offset < RegisterSaveRestore.Encodable9BitsOffsetLimit) + { + mask &= ~(3u << reg); + + asm.StpRiUn( + Register(RemapReservedGprRegister(reg, tempRegister)), + Register(RemapReservedGprRegister(reg + 1, tempRegister)), + contextPtr, + offset); + } + else + { + mask &= ~(1u << reg); + + asm.StrRiUn(Register(RemapReservedGprRegister(reg, tempRegister)), contextPtr, offset); + } + } + + if (tempRegister >= 0) + { + RegisterAllocator.FreeTempGprRegister(tempRegister); + } + } + + private int RemapReservedGprRegister(int index, int tempRegister) + { + if (tempRegister >= 0 && index == RegisterUtils.LrIndex) + { + return tempRegister; + } + + return RegisterAllocator.RemapReservedGprRegister(index); + } + + private void StoreFpSimdToContext(ref Assembler asm, uint mask, int baseOffset) + { + Operand contextPtr = Register(RegisterAllocator.FixedContextRegister); + + while (mask != 0) + { + int reg = BitOperations.TrailingZeroCount(mask); + int offset = baseOffset + reg * 16; + + mask &= ~(1u << reg); + + asm.StrRiUn(Register(reg, OperandType.V128), contextPtr, offset); + } + } + + private void StorePStateToContext(ref Assembler asm, uint mask, int baseOffset) + { + if (mask == 0) + { + return; + } + + Operand contextPtr = Register(RegisterAllocator.FixedContextRegister); + + int tempRegister = RegisterAllocator.AllocateTempGprRegister(); + + Operand rt = Register(tempRegister, OperandType.I32); + + asm.MrsNzcv(rt); + asm.StrRiUn(rt, contextPtr, baseOffset); + + RegisterAllocator.FreeTempGprRegister(tempRegister); + } + } + + private readonly struct PendingBranch + { + public readonly int BlockIndex; + public readonly ulong Pc; + public readonly InstName Name; + public readonly uint Encoding; + public readonly int WriterPointer; + + public PendingBranch(int blockIndex, ulong pc, InstName name, uint encoding, int writerPointer) + { + BlockIndex = blockIndex; + Pc = pc; + Name = name; + Encoding = encoding; + WriterPointer = writerPointer; + } + } + + public static CompiledFunction Compile(CpuPreset cpuPreset, IMemoryManager memoryManager, ulong address, AddressTable funcTable, IntPtr dispatchStubPtr) + { + MultiBlock multiBlock = Decoder.DecodeMulti(cpuPreset, memoryManager, address); + + Dictionary targets = new(); + List pendingBranches = new(); + + uint gprUseMask = multiBlock.GlobalUseMask.GprMask; + uint fpSimdUseMask = multiBlock.GlobalUseMask.FpSimdMask; + uint pStateUseMask = multiBlock.GlobalUseMask.PStateMask; + + CodeWriter writer = new(); + RegisterAllocator regAlloc = new(gprUseMask, fpSimdUseMask, pStateUseMask, multiBlock.HasHostCall); + RegisterSaveRestore rsr = new( + regAlloc.AllGprMask & AbiConstants.GprCalleeSavedRegsMask, + regAlloc.AllFpSimdMask & AbiConstants.FpSimdCalleeSavedRegsMask, + OperandType.FP64, + multiBlock.HasHostCall, + multiBlock.HasHostCall ? CalculateStackSizeForCallSpill(regAlloc.AllGprMask, regAlloc.AllFpSimdMask, regAlloc.AllPStateMask) : 0); + + TailMerger tailMerger = new(); + + Context context = new(writer, regAlloc, tailMerger, rsr, multiBlock, funcTable, dispatchStubPtr, memoryManager.PageTablePointer); + + context.WritePrologue(); + + ulong pc = address; + + for (int blockIndex = 0; blockIndex < multiBlock.Blocks.Count; blockIndex++) + { + Block block = multiBlock.Blocks[blockIndex]; + + Debug.Assert(block.Address == pc); + + targets.Add(pc, writer.InstructionPointer); + + int instCount = block.EndsWithBranch ? block.Instructions.Count - 1 : block.Instructions.Count; + + for (int index = 0; index < instCount; index++) + { + InstInfo instInfo = block.Instructions[index]; + + uint encoding = RegisterUtils.RemapRegisters(regAlloc, instInfo.Flags, instInfo.Encoding); + + if (instInfo.AddressForm != AddressForm.None) + { + InstEmitMemory.RewriteInstruction( + memoryManager.AddressSpaceBits, + memoryManager.Type, + writer, + regAlloc, + instInfo.Name, + instInfo.Flags, + instInfo.AddressForm, + pc, + encoding); + } + else if (instInfo.Name == InstName.Sys) + { + InstEmitMemory.RewriteSysInstruction(memoryManager.AddressSpaceBits, memoryManager.Type, writer, regAlloc, encoding); + } + else if (instInfo.Name.IsSystem()) + { + bool needsContextStoreLoad = InstEmitSystem.NeedsContextStoreLoad(instInfo.Name); + + if (needsContextStoreLoad) + { + context.StoreToContextBeforeCall(blockIndex); + } + + InstEmitSystem.RewriteInstruction(writer, regAlloc, tailMerger, instInfo.Name, pc, encoding, rsr.GetReservedStackOffset()); + + if (needsContextStoreLoad) + { + context.LoadFromContextAfterCall(blockIndex); + } + } + else + { + writer.WriteInstruction(encoding); + } + + pc += 4UL; + } + + if (block.IsLoopEnd) + { + // If this is a loop, the code might run for a long time uninterrupted. + // We insert a "sync point" here to ensure the loop can be interrupted if needed. + + InstEmitSystem.WriteSyncPoint(writer, context.RegisterAllocator, tailMerger, context.GetReservedStackOffset()); + } + + if (blockIndex < multiBlock.Blocks.Count - 1) + { + InstInfo lastInstructionInfo = block.Instructions[^1]; + InstName lastInstructionName = lastInstructionInfo.Name; + InstFlags lastInstructionFlags = lastInstructionInfo.Flags; + uint lastInstructionEncoding = lastInstructionInfo.Encoding; + + lastInstructionEncoding = RegisterUtils.RemapRegisters(regAlloc, lastInstructionFlags, lastInstructionEncoding); + + if (lastInstructionName.IsCall()) + { + context.StoreToContextBeforeCall(blockIndex, pc + 4UL); + + InstEmitSystem.RewriteCallInstruction( + writer, + regAlloc, + tailMerger, + context.WriteEpilogueWithoutContext, + funcTable, + dispatchStubPtr, + lastInstructionName, + pc, + lastInstructionEncoding, + context.GetReservedStackOffset()); + + context.LoadFromContextAfterCall(blockIndex); + + pc += 4UL; + } + else if (lastInstructionName == InstName.Ret) + { + RewriteBranchInstruction(context, blockIndex, lastInstructionName, pc, lastInstructionEncoding); + + pc += 4UL; + } + else if (block.EndsWithBranch) + { + pendingBranches.Add(new(blockIndex, pc, lastInstructionName, lastInstructionEncoding, writer.InstructionPointer)); + writer.WriteInstruction(0u); // Placeholder. + + pc += 4UL; + } + } + } + + int lastBlockIndex = multiBlock.Blocks[^1].Index; + + if (multiBlock.IsTruncated) + { + Assembler asm = new(writer); + + WriteTailCallConstant(context, ref asm, lastBlockIndex, pc); + } + else + { + InstInfo lastInstructionInfo = multiBlock.Blocks[^1].Instructions[^1]; + InstName lastInstructionName = lastInstructionInfo.Name; + InstFlags lastInstructionFlags = lastInstructionInfo.Flags; + uint lastInstructionEncoding = lastInstructionInfo.Encoding; + + lastInstructionEncoding = RegisterUtils.RemapRegisters(regAlloc, lastInstructionFlags, lastInstructionEncoding); + + RewriteBranchInstruction(context, lastBlockIndex, lastInstructionName, pc, lastInstructionEncoding); + + pc += 4; + } + + foreach (PendingBranch pendingBranch in pendingBranches) + { + RewriteBranchInstructionWithTarget( + context, + pendingBranch.BlockIndex, + pendingBranch.Name, + pendingBranch.Pc, + pendingBranch.Encoding, + pendingBranch.WriterPointer, + targets); + } + + tailMerger.WriteReturn(writer, context.WriteEpilogueWithoutContext); + + return new(writer.AsByteSpan(), (int)(pc - address)); + } + + private static int CalculateStackSizeForCallSpill(uint gprUseMask, uint fpSimdUseMask, uint pStateUseMask) + { + // Note that we don't discard callee saved FP/SIMD register because only the lower 64 bits is callee saved, + // so if the function is using the full register, that won't be enough. + // We could do better, but it's likely not worth it since this case happens very rarely in practice. + + return BitOperations.PopCount(gprUseMask & ~AbiConstants.GprCalleeSavedRegsMask) * 8 + + BitOperations.PopCount(fpSimdUseMask) * 16 + + (pStateUseMask != 0 ? 8 : 0); + } + + private static void RewriteBranchInstruction(in Context context, int blockIndex, InstName name, ulong pc, uint encoding) + { + CodeWriter writer = context.Writer; + Assembler asm = new(writer); + + int originalOffset; + ulong nextAddress = pc + 4UL; + ulong targetAddress; + + switch (name) + { + case InstName.BUncond: + originalOffset = ImmUtils.ExtractSImm26Times4(encoding); + targetAddress = pc + (ulong)originalOffset; + + WriteTailCallConstant(context, ref asm, blockIndex, targetAddress); + break; + + case InstName.Bl: + case InstName.Blr: + case InstName.Br: + if (name == InstName.Bl) + { + asm.Mov(Register(context.GetLrRegisterIndex()), nextAddress); + + int imm = ImmUtils.ExtractSImm26Times4(encoding); + + WriteTailCallConstant(context, ref asm, blockIndex, pc + (ulong)imm); + } + else + { + bool isCall = name == InstName.Blr; + if (isCall) + { + context.StoreToContextBeforeCall(blockIndex, nextAddress); + } + else + { + context.StoreToContextBeforeCall(blockIndex); + } + + InstEmitSystem.RewriteCallInstruction( + context.Writer, + context.RegisterAllocator, + context.TailMerger, + context.WriteEpilogueWithoutContext, + context.FuncTable, + context.DispatchStubPointer, + name, + pc, + encoding, + context.GetReservedStackOffset(), + isTail: true); + } + break; + + case InstName.Ret: + int rnIndex = RegisterUtils.ExtractRn(encoding); + if (rnIndex == RegisterUtils.ZrIndex) + { + WriteTailCallConstant(context, ref asm, blockIndex, 0UL); + } + else + { + rnIndex = context.RemapGprRegister(rnIndex); + context.StoreToContextBeforeCall(blockIndex); + + if (rnIndex != 0) + { + asm.Mov(Register(0), Register(rnIndex)); + } + + context.TailMerger.AddUnconditionalReturn(writer, asm); + } + break; + + case InstName.BCond: + case InstName.Cbnz: + case InstName.Cbz: + case InstName.Tbnz: + case InstName.Tbz: + uint branchMask; + + if (name == InstName.Tbnz || name == InstName.Tbz) + { + originalOffset = ImmUtils.ExtractSImm14Times4(encoding); + branchMask = 0x3fff; + } + else + { + originalOffset = ImmUtils.ExtractSImm19Times4(encoding); + branchMask = 0x7ffff; + } + + targetAddress = pc + (ulong)originalOffset; + + int branchIndex = writer.InstructionPointer; + + writer.WriteInstruction(0u); // Reserved for branch. + WriteTailCallConstant(context, ref asm, blockIndex, nextAddress); + + int targetIndex = writer.InstructionPointer; + + writer.WriteInstructionAt(branchIndex, (encoding & ~(branchMask << 5)) | (uint)(((targetIndex - branchIndex) & branchMask) << 5)); + WriteTailCallConstant(context, ref asm, blockIndex, targetAddress); + break; + + default: + Debug.Fail($"Unknown branch instruction \"{name}\"."); + break; + } + } + + private static void RewriteBranchInstructionWithTarget( + in Context context, + int blockIndex, + InstName name, + ulong pc, + uint encoding, + int branchIndex, + Dictionary targets) + { + CodeWriter writer = context.Writer; + Assembler asm = new(writer); + + int delta; + int targetIndex; + int originalOffset; + ulong targetAddress; + + switch (name) + { + case InstName.BUncond: + originalOffset = ImmUtils.ExtractSImm26Times4(encoding); + targetAddress = pc + (ulong)originalOffset; + + if (targets.TryGetValue(targetAddress, out targetIndex)) + { + delta = targetIndex - branchIndex; + + if (delta >= -Encodable26BitsOffsetLimit && delta < Encodable26BitsOffsetLimit) + { + writer.WriteInstructionAt(branchIndex, (encoding & ~0x3ffffffu) | (uint)(delta & 0x3ffffff)); + break; + } + } + + targetIndex = writer.InstructionPointer; + delta = targetIndex - branchIndex; + + writer.WriteInstructionAt(branchIndex, (encoding & ~0x3ffffffu) | (uint)(delta & 0x3ffffff)); + WriteTailCallConstant(context, ref asm, blockIndex, targetAddress); + break; + + case InstName.BCond: + case InstName.Cbnz: + case InstName.Cbz: + case InstName.Tbnz: + case InstName.Tbz: + uint branchMask; + + if (name == InstName.Tbnz || name == InstName.Tbz) + { + originalOffset = ImmUtils.ExtractSImm14Times4(encoding); + branchMask = 0x3fff; + } + else + { + originalOffset = ImmUtils.ExtractSImm19Times4(encoding); + branchMask = 0x7ffff; + } + + int branchMax = (int)(branchMask + 1) / 2; + + targetAddress = pc + (ulong)originalOffset; + + if (targets.TryGetValue(targetAddress, out targetIndex)) + { + delta = targetIndex - branchIndex; + + if (delta >= -branchMax && delta < branchMax) + { + writer.WriteInstructionAt(branchIndex, (encoding & ~(branchMask << 5)) | (uint)((delta & branchMask) << 5)); + break; + } + } + + targetIndex = writer.InstructionPointer; + delta = targetIndex - branchIndex; + + if (delta >= -branchMax && delta < branchMax) + { + writer.WriteInstructionAt(branchIndex, (encoding & ~(branchMask << 5)) | (uint)((delta & branchMask) << 5)); + WriteTailCallConstant(context, ref asm, blockIndex, targetAddress); + } + else + { + // If the branch target is too far away, we use a regular unconditional branch + // instruction instead which has a much higher range. + // We branch directly to the end of the function, where we put the conditional branch, + // and then branch back to the next instruction or return the branch target depending + // on the branch being taken or not. + + uint branchInst = 0x14000000u | ((uint)delta & 0x3ffffff); + Debug.Assert(ImmUtils.ExtractSImm26Times4(branchInst) == delta * 4); + + writer.WriteInstructionAt(branchIndex, branchInst); + + int movedBranchIndex = writer.InstructionPointer; + + writer.WriteInstruction(0u); // Placeholder + asm.B((branchIndex + 1 - writer.InstructionPointer) * 4); + + delta = writer.InstructionPointer - movedBranchIndex; + + writer.WriteInstructionAt(movedBranchIndex, (encoding & ~(branchMask << 5)) | (uint)((delta & branchMask) << 5)); + WriteTailCallConstant(context, ref asm, blockIndex, targetAddress); + } + break; + + default: + Debug.Fail($"Unknown branch instruction \"{name}\"."); + break; + } + } + + private static void WriteTailCallConstant(in Context context, ref Assembler asm, int blockIndex, ulong address) + { + context.StoreToContextBeforeCall(blockIndex); + InstEmitSystem.WriteCallWithGuestAddress( + context.Writer, + ref asm, + context.RegisterAllocator, + context.TailMerger, + context.WriteEpilogueWithoutContext, + context.FuncTable, + context.DispatchStubPointer, + context.GetReservedStackOffset(), + 0UL, + new Operand(OperandKind.Constant, OperandType.I64, address), + isTail: true); + } + + private static Operand Register(int register, OperandType type = OperandType.I64) + { + return new Operand(register, RegisterType.Integer, type); + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/Decoder.cs b/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/Decoder.cs new file mode 100644 index 000000000..738b8a32d --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/Decoder.cs @@ -0,0 +1,384 @@ +using ARMeilleure.Memory; +using Ryujinx.Cpu.LightningJit.Graph; +using System.Collections.Generic; +using System.Diagnostics; +using System.Numerics; + +namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64 +{ + static class Decoder + { + private const int MaxInstructionsPerBlock = 1000; + + private const uint NzcvFlags = 0xfu << 28; + private const uint CFlag = 0x1u << 29; + + public static MultiBlock DecodeMulti(CpuPreset cpuPreset, IMemoryManager memoryManager, ulong address) + { + List blocks = new(); + List branchTargets = new(); + + RegisterMask useMask = RegisterMask.Zero; + + bool hasHostCall = false; + bool hasMemoryInstruction = false; + + while (true) + { + Block block = Decode(cpuPreset, memoryManager, address, ref useMask, ref hasHostCall, ref hasMemoryInstruction); + + if (!block.IsTruncated && TryGetBranchTarget(block, out ulong targetAddress)) + { + branchTargets.Add(targetAddress); + } + + blocks.Add(block); + + if (block.IsTruncated || !HasNextBlock(block, block.EndAddress - 4UL, branchTargets)) + { + break; + } + + address = block.EndAddress; + } + + branchTargets.Sort(); + SplitBlocks(blocks, branchTargets); + NumberAndLinkBlocks(blocks); + + return new(blocks, useMask, hasHostCall, hasMemoryInstruction); + } + + private static bool TryGetBranchTarget(Block block, out ulong targetAddress) + { + return TryGetBranchTarget(block.Instructions[^1].Name, block.EndAddress - 4UL, block.Instructions[^1].Encoding, out targetAddress); + } + + private static bool TryGetBranchTarget(InstName name, ulong pc, uint encoding, out ulong targetAddress) + { + int originalOffset; + + switch (name) + { + case InstName.BUncond: + originalOffset = ImmUtils.ExtractSImm26Times4(encoding); + targetAddress = pc + (ulong)originalOffset; + + return true; + + case InstName.BCond: + case InstName.Cbnz: + case InstName.Cbz: + case InstName.Tbnz: + case InstName.Tbz: + if (name == InstName.Tbnz || name == InstName.Tbz) + { + originalOffset = ImmUtils.ExtractSImm14Times4(encoding); + } + else + { + originalOffset = ImmUtils.ExtractSImm19Times4(encoding); + } + + targetAddress = pc + (ulong)originalOffset; + + return true; + } + + targetAddress = 0; + + return false; + } + + private static void SplitBlocks(List blocks, List branchTargets) + { + int btIndex = 0; + + while (btIndex < branchTargets.Count) + { + for (int blockIndex = 0; blockIndex < blocks.Count && btIndex < branchTargets.Count; blockIndex++) + { + Block block = blocks[blockIndex]; + ulong currentBranchTarget = branchTargets[btIndex]; + + while (currentBranchTarget >= block.Address && currentBranchTarget < block.EndAddress) + { + if (block.Address != currentBranchTarget) + { + (Block leftBlock, Block rightBlock) = block.SplitAtAddress(currentBranchTarget); + + blocks.Insert(blockIndex, leftBlock); + blocks[blockIndex + 1] = rightBlock; + + block = leftBlock; + } + + btIndex++; + + while (btIndex < branchTargets.Count && branchTargets[btIndex] == currentBranchTarget) + { + btIndex++; + } + + if (btIndex >= branchTargets.Count) + { + break; + } + + currentBranchTarget = branchTargets[btIndex]; + } + } + + Debug.Assert(btIndex < int.MaxValue); + btIndex++; + } + } + + private static void NumberAndLinkBlocks(List blocks) + { + Dictionary blocksByAddress = new(); + + for (int blockIndex = 0; blockIndex < blocks.Count; blockIndex++) + { + Block block = blocks[blockIndex]; + + blocksByAddress.Add(block.Address, block); + } + + for (int blockIndex = 0; blockIndex < blocks.Count; blockIndex++) + { + Block block = blocks[blockIndex]; + + block.Number(blockIndex); + + if (!block.IsTruncated) + { + bool hasNext = !block.EndsWithBranch; + bool hasBranch = false; + + switch (block.Instructions[^1].Name) + { + case InstName.BUncond: + hasBranch = true; + break; + + case InstName.BCond: + case InstName.Cbnz: + case InstName.Cbz: + case InstName.Tbnz: + case InstName.Tbz: + hasNext = true; + hasBranch = true; + break; + + case InstName.Bl: + case InstName.Blr: + hasNext = true; + break; + + case InstName.Ret: + hasNext = false; + hasBranch = false; + break; + } + + if (hasNext && blocksByAddress.TryGetValue(block.EndAddress, out Block nextBlock)) + { + block.AddSuccessor(nextBlock); + nextBlock.AddPredecessor(block); + } + + if (hasBranch && + TryGetBranchTarget(block, out ulong targetAddress) && + blocksByAddress.TryGetValue(targetAddress, out Block branchBlock)) + { + block.AddSuccessor(branchBlock); + branchBlock.AddPredecessor(block); + } + } + } + } + + private static bool HasNextBlock(in Block block, ulong pc, List branchTargets) + { + switch (block.Instructions[^1].Name) + { + case InstName.BUncond: + return branchTargets.Contains(pc + 4UL) || + (TryGetBranchTarget(block, out ulong targetAddress) && targetAddress >= pc && targetAddress < pc + 0x1000); + + case InstName.BCond: + case InstName.Bl: + case InstName.Blr: + case InstName.Cbnz: + case InstName.Cbz: + case InstName.Tbnz: + case InstName.Tbz: + return true; + + case InstName.Br: + return false; + + case InstName.Ret: + return branchTargets.Contains(pc + 4UL); + } + + return !block.EndsWithBranch; + } + + private static Block Decode( + CpuPreset cpuPreset, + IMemoryManager memoryManager, + ulong address, + ref RegisterMask useMask, + ref bool hasHostCall, + ref bool hasMemoryInstruction) + { + ulong startAddress = address; + + List insts = new(); + + uint gprUseMask = useMask.GprMask; + uint fpSimdUseMask = useMask.FpSimdMask; + uint pStateUseMask = useMask.PStateMask; + + uint encoding; + InstName name; + InstFlags flags; + bool isControlFlow; + bool isTruncated = false; + + do + { + encoding = memoryManager.Read(address); + address += 4UL; + + (name, flags, AddressForm addressForm) = InstTable.GetInstNameAndFlags(encoding, cpuPreset.Version, cpuPreset.Features); + + if (name.IsPrivileged()) + { + name = InstName.UdfPermUndef; + flags = InstFlags.None; + addressForm = AddressForm.None; + } + + (uint instGprReadMask, uint instFpSimdReadMask) = RegisterUtils.PopulateReadMasks(name, flags, encoding); + (uint instGprWriteMask, uint instFpSimdWriteMask) = RegisterUtils.PopulateWriteMasks(name, flags, encoding); + + if (name.IsCall()) + { + instGprWriteMask |= 1u << RegisterUtils.LrIndex; + } + + uint tempGprUseMask = gprUseMask | instGprReadMask | instGprWriteMask; + + if (CalculateAvailableTemps(tempGprUseMask) < CalculateRequiredGprTemps(tempGprUseMask) || insts.Count >= MaxInstructionsPerBlock) + { + isTruncated = true; + address -= 4UL; + + break; + } + + gprUseMask = tempGprUseMask; + + uint instPStateReadMask = 0; + uint instPStateWriteMask = 0; + + if (flags.HasFlag(InstFlags.Nzcv) || IsMrsNzcv(encoding)) + { + instPStateReadMask = NzcvFlags; + } + else if (flags.HasFlag(InstFlags.C)) + { + instPStateReadMask = CFlag; + } + + if (flags.HasFlag(InstFlags.S) || IsMsrNzcv(encoding)) + { + instPStateWriteMask = NzcvFlags; + } + + if (flags.HasFlag(InstFlags.Memory) || name == InstName.Sys) + { + hasMemoryInstruction = true; + } + + fpSimdUseMask |= instFpSimdReadMask | instFpSimdWriteMask; + pStateUseMask |= instPStateReadMask | instPStateWriteMask; + + if (name.IsSystemOrCall() && !hasHostCall) + { + hasHostCall = name.IsCall() || InstEmitSystem.NeedsCall(encoding); + } + + isControlFlow = name.IsControlFlowOrException(); + + RegisterUse registerUse = new( + instGprReadMask, + instGprWriteMask, + instFpSimdReadMask, + instFpSimdWriteMask, + instPStateReadMask, + instPStateWriteMask); + + insts.Add(new(encoding, name, flags, addressForm, registerUse)); + } + while (!isControlFlow); + + bool isLoopEnd = false; + + if (!isTruncated && IsBackwardsBranch(name, encoding)) + { + hasHostCall = true; + isLoopEnd = true; + } + + useMask = new(gprUseMask, fpSimdUseMask, pStateUseMask); + + return new(startAddress, address, insts, !isTruncated && !name.IsException(), isTruncated, isLoopEnd); + } + + private static bool IsMrsNzcv(uint encoding) + { + return (encoding & ~0x1fu) == 0xd53b4200u; + } + + private static bool IsMsrNzcv(uint encoding) + { + return (encoding & ~0x1fu) == 0xd51b4200u; + } + + private static bool IsBackwardsBranch(InstName name, uint encoding) + { + switch (name) + { + case InstName.BUncond: + return ImmUtils.ExtractSImm26Times4(encoding) < 0; + + case InstName.BCond: + case InstName.Cbnz: + case InstName.Cbz: + case InstName.Tbnz: + case InstName.Tbz: + int imm = name == InstName.Tbnz || name == InstName.Tbz + ? ImmUtils.ExtractSImm14Times4(encoding) + : ImmUtils.ExtractSImm19Times4(encoding); + + return imm < 0; + } + + return false; + } + + private static int CalculateRequiredGprTemps(uint gprUseMask) + { + return BitOperations.PopCount(gprUseMask & RegisterUtils.ReservedRegsMask) + RegisterAllocator.MaxTempsInclFixed; + } + + private static int CalculateAvailableTemps(uint gprUseMask) + { + return BitOperations.PopCount(~(gprUseMask | RegisterUtils.ReservedRegsMask)); + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/InstEmitMemory.cs b/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/InstEmitMemory.cs new file mode 100644 index 000000000..ece1520fd --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/InstEmitMemory.cs @@ -0,0 +1,593 @@ +using ARMeilleure.Memory; +using Ryujinx.Cpu.LightningJit.CodeGen; +using Ryujinx.Cpu.LightningJit.CodeGen.Arm64; +using System; +using System.Diagnostics; + +namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64 +{ + static class InstEmitMemory + { + private const uint XMask = 0x3f808000u; + private const uint XValue = 0x8000000u; + + public static void RewriteSysInstruction(int asBits, MemoryManagerType mmType, CodeWriter writer, RegisterAllocator regAlloc, uint encoding) + { + int rtIndex = RegisterUtils.ExtractRt(encoding); + if (rtIndex == RegisterUtils.ZrIndex) + { + writer.WriteInstruction(encoding); + + return; + } + + int tempRegister = regAlloc.AllocateTempGprRegister(); + Operand rt = new(tempRegister, RegisterType.Integer, OperandType.I64); + Operand guestAddress = new(rtIndex, RegisterType.Integer, OperandType.I64); + + Assembler asm = new(writer); + + WriteAddressTranslation(asBits, mmType, regAlloc, ref asm, rt, guestAddress); + + encoding = RegisterUtils.ReplaceRt(encoding, tempRegister); + + writer.WriteInstruction(encoding); + + regAlloc.FreeTempGprRegister(tempRegister); + } + + public static void RewriteInstruction( + int asBits, + MemoryManagerType mmType, + CodeWriter writer, + RegisterAllocator regAlloc, + InstName name, + InstFlags flags, + AddressForm addressForm, + ulong pc, + uint encoding) + { + switch (addressForm) + { + case AddressForm.OffsetReg: + RewriteOffsetRegMemoryInstruction(asBits, mmType, writer, regAlloc, flags, encoding); + break; + case AddressForm.PostIndexed: + RewritePostIndexedMemoryInstruction(asBits, mmType, writer, regAlloc, flags, encoding); + break; + case AddressForm.PreIndexed: + RewritePreIndexedMemoryInstruction(asBits, mmType, writer, regAlloc, flags, encoding); + break; + case AddressForm.SignedScaled: + RewriteSignedScaledMemoryInstruction(asBits, mmType, writer, regAlloc, flags, encoding); + break; + case AddressForm.UnsignedScaled: + RewriteUnsignedScaledMemoryInstruction(asBits, mmType, writer, regAlloc, flags, encoding); + break; + case AddressForm.BaseRegister: + // Some applications uses unordered memory instructions in places where + // it does need proper ordering, and only work on some CPUs. + // To work around this, make all exclusive access operations ordered. + + if ((encoding & XMask) == XValue) + { + // Set ordered flag. + encoding |= 1u << 15; + } + + RewriteBaseRegisterMemoryInstruction(asBits, mmType, writer, regAlloc, encoding); + break; + case AddressForm.StructNoOffset: + RewriteBaseRegisterMemoryInstruction(asBits, mmType, writer, regAlloc, encoding); + break; + case AddressForm.BasePlusOffset: + RewriteBasePlusOffsetMemoryInstruction(asBits, mmType, writer, regAlloc, encoding); + break; + case AddressForm.Literal: + RewriteLiteralMemoryInstruction(asBits, mmType, writer, regAlloc, name, pc, encoding); + break; + case AddressForm.StructPostIndexedReg: + RewriteStructPostIndexedRegMemoryInstruction(asBits, mmType, writer, regAlloc, encoding); + break; + default: + writer.WriteInstruction(encoding); + break; + } + } + + private static void RewriteOffsetRegMemoryInstruction(int asBits, MemoryManagerType mmType, CodeWriter writer, RegisterAllocator regAlloc, InstFlags flags, uint encoding) + { + // TODO: Some unallocated encoding cases. + + ArmExtensionType extensionType = (ArmExtensionType)((encoding >> 13) & 7); + + uint size = encoding >> 30; + + if (flags.HasFlag(InstFlags.FpSimd)) + { + size |= (encoding >> 21) & 4u; + } + + int shift = (encoding & (1u << 12)) != 0 ? (int)size : 0; + + int tempRegister = regAlloc.AllocateTempGprRegister(); + Operand rn = new(tempRegister, RegisterType.Integer, OperandType.I64); + Operand guestAddress = new(RegisterUtils.ExtractRn(encoding), RegisterType.Integer, OperandType.I64); + Operand guestOffset = new(RegisterUtils.ExtractRm(encoding), RegisterType.Integer, OperandType.I64); + + Assembler asm = new(writer); + + asm.Add(rn, guestAddress, guestOffset, extensionType, shift); + + WriteAddressTranslation(asBits, mmType, regAlloc, ref asm, rn, rn); + + encoding = RegisterUtils.ReplaceRn(encoding, tempRegister); + encoding = (encoding & ~(0xfffu << 10)) | (1u << 24); // Register -> Unsigned offset + + writer.WriteInstruction(encoding); + + regAlloc.FreeTempGprRegister(tempRegister); + } + + private static void RewritePostIndexedMemoryInstruction(int asBits, MemoryManagerType mmType, CodeWriter writer, RegisterAllocator regAlloc, InstFlags flags, uint encoding) + { + bool isPair = flags.HasFlag(InstFlags.Rt2); + int imm = isPair ? ExtractSImm7Scaled(flags, encoding) : ExtractSImm9(encoding); + + int tempRegister = regAlloc.AllocateTempGprRegister(); + Operand rn = new(tempRegister, RegisterType.Integer, OperandType.I64); + Operand guestAddress = new(RegisterUtils.ExtractRn(encoding), RegisterType.Integer, OperandType.I64); + + Assembler asm = new(writer); + + WriteAddressTranslation(asBits, mmType, regAlloc, ref asm, rn, guestAddress); + + encoding = RegisterUtils.ReplaceRn(encoding, tempRegister); + + if (isPair) + { + // Post-index -> Signed offset + encoding &= ~(0x7fu << 15); + encoding ^= 3u << 23; + } + else + { + // Post-index -> Unsigned offset + encoding = (encoding & ~(0xfffu << 10)) | (1u << 24); + } + + writer.WriteInstruction(encoding); + + WriteAddConstant(ref asm, guestAddress, guestAddress, imm); + + regAlloc.FreeTempGprRegister(tempRegister); + } + + private static void RewritePreIndexedMemoryInstruction(int asBits, MemoryManagerType mmType, CodeWriter writer, RegisterAllocator regAlloc, InstFlags flags, uint encoding) + { + bool isPair = flags.HasFlag(InstFlags.Rt2); + int imm = isPair ? ExtractSImm7Scaled(flags, encoding) : ExtractSImm9(encoding); + + int tempRegister = regAlloc.AllocateTempGprRegister(); + Operand rn = new(tempRegister, RegisterType.Integer, OperandType.I64); + Operand guestAddress = new(RegisterUtils.ExtractRn(encoding), RegisterType.Integer, OperandType.I64); + + Assembler asm = new(writer); + + WriteAddConstant(ref asm, guestAddress, guestAddress, imm); + WriteAddressTranslation(asBits, mmType, regAlloc, ref asm, rn, guestAddress); + + encoding = RegisterUtils.ReplaceRn(encoding, tempRegister); + + if (isPair) + { + // Pre-index -> Signed offset + encoding &= ~(0x7fu << 15); + encoding &= ~(1u << 23); + } + else + { + // Pre-index -> Unsigned offset + encoding = (encoding & ~(0xfffu << 10)) | (1u << 24); + } + + writer.WriteInstruction(encoding); + + regAlloc.FreeTempGprRegister(tempRegister); + } + + private static void RewriteSignedScaledMemoryInstruction(int asBits, MemoryManagerType mmType, CodeWriter writer, RegisterAllocator regAlloc, InstFlags flags, uint encoding) + { + RewriteMemoryInstruction(asBits, mmType, writer, regAlloc, encoding, ExtractSImm7Scaled(flags, encoding), 0x7fu << 15); + } + + private static void RewriteUnsignedScaledMemoryInstruction(int asBits, MemoryManagerType mmType, CodeWriter writer, RegisterAllocator regAlloc, InstFlags flags, uint encoding) + { + RewriteMemoryInstruction(asBits, mmType, writer, regAlloc, encoding, ExtractUImm12Scaled(flags, encoding), 0xfffu << 10); + } + + private static void RewriteBaseRegisterMemoryInstruction(int asBits, MemoryManagerType mmType, CodeWriter writer, RegisterAllocator regAlloc, uint encoding) + { + RewriteMemoryInstruction(asBits, mmType, writer, regAlloc, encoding, 0, 0u); + } + + private static void RewriteBasePlusOffsetMemoryInstruction(int asBits, MemoryManagerType mmType, CodeWriter writer, RegisterAllocator regAlloc, uint encoding) + { + RewriteMemoryInstruction(asBits, mmType, writer, regAlloc, encoding, ExtractSImm9(encoding), 0x1ffu << 12); + } + + private static void RewriteMemoryInstruction(int asBits, MemoryManagerType mmType, CodeWriter writer, RegisterAllocator regAlloc, uint encoding, int imm, uint immMask) + { + int tempRegister = regAlloc.AllocateTempGprRegister(); + Operand rn = new(tempRegister, RegisterType.Integer, OperandType.I64); + Operand guestAddress = new(RegisterUtils.ExtractRn(encoding), RegisterType.Integer, OperandType.I64); + + Assembler asm = new(writer); + + bool canFoldOffset = CanFoldOffset(mmType, imm); + if (canFoldOffset) + { + imm = 0; + } + + WriteAddressTranslation(asBits, mmType, regAlloc, ref asm, rn, guestAddress, imm); + + encoding = RegisterUtils.ReplaceRn(encoding, tempRegister); + + if (!canFoldOffset) + { + encoding &= ~immMask; // Clear offset + } + + writer.WriteInstruction(encoding); + + regAlloc.FreeTempGprRegister(tempRegister); + } + + private static void RewriteLiteralMemoryInstruction(int asBits, MemoryManagerType mmType, CodeWriter writer, RegisterAllocator regAlloc, InstName name, ulong pc, uint encoding) + { + Assembler asm = new(writer); + + ulong targetAddress; + long imm; + int rtIndex = (int)(encoding & 0x1f); + + if (rtIndex == RegisterUtils.ZrIndex && name != InstName.PrfmLit) + { + return; + } + + Operand rt; + + if (name == InstName.LdrLitFpsimd) + { + uint opc = encoding >> 30; + + // TODO: Undefined if opc is invalid? + + rt = new(rtIndex, RegisterType.Vector, opc switch + { + 0 => OperandType.FP32, + 1 => OperandType.FP64, + _ => OperandType.V128, + }); + } + else + { + rt = new(rtIndex, RegisterType.Integer, OperandType.I64); + } + + switch (name) + { + case InstName.Adr: + case InstName.Adrp: + imm = ((long)(encoding >> 29) & 3) | ((long)(encoding >> 3) & 0x1ffffc); + imm <<= 43; + + if (name == InstName.Adrp) + { + imm >>= 31; + targetAddress = (pc & ~0xfffUL) + (ulong)imm; + } + else + { + imm >>= 43; + targetAddress = pc + (ulong)imm; + } + + asm.Mov(rt, targetAddress); + break; + case InstName.LdrLitGen: + case InstName.LdrswLit: + case InstName.LdrLitFpsimd: + case InstName.PrfmLit: + imm = encoding & ~0x1fu; + imm <<= 40; + imm >>= 43; + targetAddress = pc + (ulong)imm; + + int tempRegister = regAlloc.AllocateTempGprRegister(); + Operand rn = new(tempRegister, RegisterType.Integer, OperandType.I64); + + WriteAddressTranslation(asBits, mmType, regAlloc, ref asm, rn, targetAddress); + + switch (name) + { + case InstName.LdrLitGen: + case InstName.LdrLitFpsimd: + asm.LdrRiUn(rt, rn, 0); + break; + case InstName.LdrswLit: + asm.LdrswRiUn(rt, rn, 0); + break; + case InstName.PrfmLit: + asm.PrfmR(rt, rn); + break; + } + + regAlloc.FreeTempGprRegister(tempRegister); + break; + default: + Debug.Fail($"Invalid literal memory instruction '{name}'."); + break; + } + } + + private static void RewriteStructPostIndexedRegMemoryInstruction(int asBits, MemoryManagerType mmType, CodeWriter writer, RegisterAllocator regAlloc, uint encoding) + { + // TODO: Some unallocated encoding cases. + + int tempRegister = regAlloc.AllocateTempGprRegister(); + Operand rn = new(tempRegister, RegisterType.Integer, OperandType.I64); + Operand guestAddress = new(RegisterUtils.ExtractRn(encoding), RegisterType.Integer, OperandType.I64); + + int rmIndex = RegisterUtils.ExtractRm(encoding); + + Assembler asm = new(writer); + + WriteAddressTranslation(asBits, mmType, regAlloc, ref asm, rn, guestAddress); + + encoding = RegisterUtils.ReplaceRn(encoding, tempRegister); + encoding &= ~((0x1fu << 16) | (1u << 23)); // Post-index -> No offset + + writer.WriteInstruction(encoding); + + if (rmIndex == RegisterUtils.ZrIndex) + { + bool isSingleStruct = (encoding & (1u << 24)) != 0; + int offset; + + if (isSingleStruct) + { + int sElems = (int)(((encoding >> 12) & 2u) | ((encoding >> 21) & 1u)) + 1; + + int size = (int)(encoding >> 10) & 3; + int s = (int)(encoding >> 12) & 1; + int scale = (int)(encoding >> 14) & 3; + int l = (int)(encoding >> 22) & 1; + + switch (scale) + { + case 1: + if ((size & 1) != 0) + { + // Undef. + } + + break; + + case 2: + if ((size & 2) != 0 || + ((size & 1) != 0 && s != 0)) + { + // Undef. + } + + if ((size & 1) != 0) + { + scale = 3; + } + + break; + + case 3: + if (l == 0 || s != 0) + { + // Undef. + } + + scale = size; + + break; + } + + int eBytes = 1 << scale; + + offset = eBytes * sElems; + } + else + { + int reps; + int sElems; + + switch ((encoding >> 12) & 0xf) + { + case 0b0000: + reps = 1; + sElems = 4; + break; + case 0b0010: + reps = 4; + sElems = 1; + break; + case 0b0100: + reps = 1; + sElems = 3; + break; + case 0b0110: + reps = 3; + sElems = 1; + break; + case 0b0111: + reps = 1; + sElems = 1; + break; + case 0b1000: + reps = 1; + sElems = 2; + break; + case 0b1010: + reps = 2; + sElems = 1; + break; + + default: + // Undef. + reps = 0; + sElems = 0; + break; + } + + int size = (int)(encoding >> 10) & 3; + bool q = (encoding & (1u << 30)) != 0; + + if (!q && size == 3 && sElems != 1) + { + // Undef. + } + + offset = reps * (q ? 16 : 8) * sElems; + } + + asm.Add(guestAddress, guestAddress, new Operand(OperandKind.Constant, OperandType.I32, (ulong)offset)); + } + else + { + Operand guestOffset = new(rmIndex, RegisterType.Integer, OperandType.I64); + + asm.Add(guestAddress, guestAddress, guestOffset); + } + + regAlloc.FreeTempGprRegister(tempRegister); + } + + private static void WriteAddressTranslation( + int asBits, + MemoryManagerType mmType, + RegisterAllocator regAlloc, + ref Assembler asm, + Operand destination, + Operand guestAddress, + int offset) + { + if (offset != 0) + { + // They are assumed to be on different registers, otherwise this operation will thrash the address. + Debug.Assert(destination.Value != guestAddress.Value); + + if (Math.Abs(offset) >= 0x1000) + { + // Too high to encode as 12-bit immediate, do a separate move. + asm.Mov(destination, (ulong)offset); + asm.Add(destination, destination, guestAddress); + } + else + { + // Encode as 12-bit immediate. + WriteAddConstant(ref asm, destination, guestAddress, offset); + } + + guestAddress = destination; + } + + WriteAddressTranslation(asBits, mmType, regAlloc, ref asm, destination, guestAddress); + } + + private static void WriteAddressTranslation(int asBits, MemoryManagerType mmType, RegisterAllocator regAlloc, ref Assembler asm, Operand destination, ulong guestAddress) + { + asm.Mov(destination, guestAddress); + + WriteAddressTranslation(asBits, mmType, regAlloc, ref asm, destination, destination); + } + + private static void WriteAddressTranslation(int asBits, MemoryManagerType mmType, RegisterAllocator regAlloc, ref Assembler asm, Operand destination, Operand guestAddress) + { + Operand basePointer = new(regAlloc.FixedPageTableRegister, RegisterType.Integer, OperandType.I64); + + if (mmType == MemoryManagerType.HostMapped || mmType == MemoryManagerType.HostMappedUnsafe) + { + if (mmType == MemoryManagerType.HostMapped) + { + asm.And(destination, guestAddress, new Operand(OperandKind.Constant, OperandType.I64, ulong.MaxValue >> (64 - asBits))); + guestAddress = destination; + } + + asm.Add(destination, basePointer, guestAddress); + } + else + { + throw new NotImplementedException(mmType.ToString()); + } + } + + private static void WriteAddConstant(ref Assembler asm, Operand rd, Operand rn, int value) + { + if (value < 0) + { + asm.Sub(rd, rn, new Operand(OperandKind.Constant, OperandType.I32, (ulong)-value)); + } + else + { + asm.Add(rd, rn, new Operand(OperandKind.Constant, OperandType.I32, (ulong)value)); + } + } + + private static bool CanFoldOffset(MemoryManagerType mmType, int offset) + { + return mmType == MemoryManagerType.HostMappedUnsafe; + } + + private static int ExtractSImm7Scaled(InstFlags flags, uint encoding) + { + uint opc = flags.HasFlag(InstFlags.FpSimd) ? encoding >> 30 : encoding >> 31; + return ExtractSImm7(encoding) << (int)(2 + opc); + } + + private static int ExtractSImm7(uint encoding) + { + int imm = (int)(encoding >> 15); + + imm <<= 25; + imm >>= 25; + + return imm; + } + + private static int ExtractSImm9(uint encoding) + { + int imm = (int)(encoding >> 12); + + imm <<= 23; + imm >>= 23; + + return imm; + } + + private static int ExtractUImm12Scaled(InstFlags flags, uint encoding) + { + uint size = encoding >> 30; + + if (flags.HasFlag(InstFlags.FpSimd)) + { + size |= (encoding >> 21) & 4u; + } + + return ExtractUImm12(encoding) << (int)size; + } + + private static int ExtractUImm12(uint encoding) + { + return (int)(encoding >> 10) & 0xfff; + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/InstEmitSystem.cs b/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/InstEmitSystem.cs new file mode 100644 index 000000000..3d4204fc1 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/InstEmitSystem.cs @@ -0,0 +1,610 @@ +using ARMeilleure.Common; +using Ryujinx.Cpu.LightningJit.CodeGen; +using Ryujinx.Cpu.LightningJit.CodeGen.Arm64; +using System; +using System.Diagnostics; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64 +{ + static class InstEmitSystem + { + private delegate void SoftwareInterruptHandler(ulong address, int imm); + private delegate ulong Get64(); + private delegate bool GetBool(); + + public static void RewriteInstruction( + CodeWriter writer, + RegisterAllocator regAlloc, + TailMerger tailMerger, + InstName name, + ulong pc, + uint encoding, + int spillBaseOffset) + { + if (name == InstName.Brk) + { + Assembler asm = new(writer); + + WriteCall(ref asm, regAlloc, GetBrkHandlerPtr(), spillBaseOffset, null, pc, encoding); + WriteSyncPoint(writer, ref asm, regAlloc, tailMerger, spillBaseOffset); + } + else if (name == InstName.Svc) + { + uint svcId = (ushort)(encoding >> 5); + + Assembler asm = new(writer); + + WriteCall(ref asm, regAlloc, GetSvcHandlerPtr(), spillBaseOffset, null, pc, svcId); + WriteSyncPoint(writer, ref asm, regAlloc, tailMerger, spillBaseOffset); + } + else if (name == InstName.UdfPermUndef) + { + Assembler asm = new(writer); + + WriteCall(ref asm, regAlloc, GetUdfHandlerPtr(), spillBaseOffset, null, pc, encoding); + WriteSyncPoint(writer, ref asm, regAlloc, tailMerger, spillBaseOffset); + } + else if ((encoding & ~0x1f) == 0xd53bd060) // mrs x0, tpidrro_el0 + { + uint rd = encoding & 0x1f; + + if (rd != RegisterUtils.ZrIndex) + { + Assembler asm = new(writer); + + asm.LdrRiUn(Register((int)rd), Register(regAlloc.FixedContextRegister), NativeContextOffsets.TpidrroEl0Offset); + } + } + else if ((encoding & ~0x1f) == 0xd53bd040) // mrs x0, tpidr_el0 + { + uint rd = encoding & 0x1f; + + if (rd != RegisterUtils.ZrIndex) + { + Assembler asm = new(writer); + + asm.LdrRiUn(Register((int)rd), Register(regAlloc.FixedContextRegister), NativeContextOffsets.TpidrEl0Offset); + } + } + else if ((encoding & ~0x1f) == 0xd53b0020 && IsAppleOS()) // mrs x0, ctr_el0 + { + uint rd = encoding & 0x1f; + + if (rd != RegisterUtils.ZrIndex) + { + Assembler asm = new(writer); + + // TODO: Use host value? But that register can't be accessed on macOS... + asm.Mov(Register((int)rd, OperandType.I32), 0x8444c004); + } + } + else if ((encoding & ~0x1f) == 0xd53be020) // mrs x0, cntpct_el0 + { + uint rd = encoding & 0x1f; + + if (rd != RegisterUtils.ZrIndex) + { + Assembler asm = new(writer); + + WriteCall(ref asm, regAlloc, GetCntpctEl0Ptr(), spillBaseOffset, (int)rd); + } + } + else if ((encoding & ~0x1f) == 0xd51bd040) // msr tpidr_el0, x0 + { + uint rd = encoding & 0x1f; + + if (rd != RegisterUtils.ZrIndex) + { + Assembler asm = new(writer); + + asm.StrRiUn(Register((int)rd), Register(regAlloc.FixedContextRegister), NativeContextOffsets.TpidrEl0Offset); + } + } + else + { + writer.WriteInstruction(encoding); + } + } + + public static bool NeedsCall(uint encoding) + { + if ((encoding & ~(0xffffu << 5)) == 0xd4000001u) // svc #0 + { + return true; + } + else if ((encoding & ~0x1f) == 0xd53b0020 && IsAppleOS()) // mrs x0, ctr_el0 + { + return true; + } + else if ((encoding & ~0x1f) == 0xd53be020) // mrs x0, cntpct_el0 + { + return true; + } + + return false; + } + + private static bool IsAppleOS() + { + return OperatingSystem.IsMacOS() || OperatingSystem.IsIOS(); + } + + public static bool NeedsContextStoreLoad(InstName name) + { + return name == InstName.Svc; + } + + private static IntPtr GetBrkHandlerPtr() + { + return Marshal.GetFunctionPointerForDelegate(NativeInterface.Break); + } + + private static IntPtr GetSvcHandlerPtr() + { + return Marshal.GetFunctionPointerForDelegate(NativeInterface.SupervisorCall); + } + + private static IntPtr GetUdfHandlerPtr() + { + return Marshal.GetFunctionPointerForDelegate(NativeInterface.Undefined); + } + + private static IntPtr GetCntpctEl0Ptr() + { + return Marshal.GetFunctionPointerForDelegate(NativeInterface.GetCntpctEl0); + } + + private static IntPtr CheckSynchronizationPtr() + { + return Marshal.GetFunctionPointerForDelegate(NativeInterface.CheckSynchronization); + } + + public static void WriteSyncPoint(CodeWriter writer, RegisterAllocator regAlloc, TailMerger tailMerger, int spillBaseOffset) + { + Assembler asm = new(writer); + + WriteSyncPoint(writer, ref asm, regAlloc, tailMerger, spillBaseOffset); + } + + private static void WriteSyncPoint(CodeWriter writer, ref Assembler asm, RegisterAllocator regAlloc, TailMerger tailMerger, int spillBaseOffset) + { + int tempRegister = regAlloc.AllocateTempGprRegister(); + + Operand rt = Register(tempRegister, OperandType.I32); + + asm.LdrRiUn(rt, Register(regAlloc.FixedContextRegister), NativeContextOffsets.CounterOffset); + + int branchIndex = writer.InstructionPointer; + asm.Cbnz(rt, 0); + + WriteSpill(ref asm, regAlloc, 1u << tempRegister, spillBaseOffset, tempRegister); + + Operand rn = Register(tempRegister == 0 ? 1 : 0); + + asm.Mov(rn, (ulong)CheckSynchronizationPtr()); + asm.Blr(rn); + + tailMerger.AddConditionalZeroReturn(writer, asm, Register(0, OperandType.I32)); + + WriteFill(ref asm, regAlloc, 1u << tempRegister, spillBaseOffset, tempRegister); + + asm.LdrRiUn(rt, Register(regAlloc.FixedContextRegister), NativeContextOffsets.CounterOffset); + + uint branchInst = writer.ReadInstructionAt(branchIndex); + writer.WriteInstructionAt(branchIndex, branchInst | (((uint)(writer.InstructionPointer - branchIndex) & 0x7ffff) << 5)); + + asm.Sub(rt, rt, new Operand(OperandKind.Constant, OperandType.I32, 1)); + asm.StrRiUn(rt, Register(regAlloc.FixedContextRegister), NativeContextOffsets.CounterOffset); + + regAlloc.FreeTempGprRegister(tempRegister); + } + + public static void RewriteCallInstruction( + CodeWriter writer, + RegisterAllocator regAlloc, + TailMerger tailMerger, + Action writeEpilogue, + AddressTable funcTable, + IntPtr dispatchStubPtr, + InstName name, + ulong pc, + uint encoding, + int spillBaseOffset, + bool isTail = false) + { + Assembler asm = new(writer); + + switch (name) + { + case InstName.BUncond: + case InstName.Bl: + case InstName.Blr: + case InstName.Br: + if (name == InstName.BUncond || name == InstName.Bl) + { + int imm = ImmUtils.ExtractSImm26Times4(encoding); + + WriteCallWithGuestAddress( + writer, + ref asm, + regAlloc, + tailMerger, + writeEpilogue, + funcTable, + dispatchStubPtr, + spillBaseOffset, + pc, + new(OperandKind.Constant, OperandType.I64, pc + (ulong)imm), + isTail); + } + else + { + int rnIndex = RegisterUtils.ExtractRn(encoding); + if (rnIndex == RegisterUtils.ZrIndex) + { + WriteCallWithGuestAddress( + writer, + ref asm, + regAlloc, + tailMerger, + writeEpilogue, + funcTable, + dispatchStubPtr, + spillBaseOffset, + pc, + new(OperandKind.Constant, OperandType.I64, 0UL), + isTail); + } + else + { + rnIndex = regAlloc.RemapReservedGprRegister(rnIndex); + + WriteCallWithGuestAddress( + writer, + ref asm, + regAlloc, + tailMerger, + writeEpilogue, + funcTable, + dispatchStubPtr, + spillBaseOffset, + pc, + Register(rnIndex), + isTail); + } + } + break; + + default: + Debug.Fail($"Unknown branch instruction \"{name}\"."); + break; + } + } + + public unsafe static void WriteCallWithGuestAddress( + CodeWriter writer, + ref Assembler asm, + RegisterAllocator regAlloc, + TailMerger tailMerger, + Action writeEpilogue, + AddressTable funcTable, + IntPtr funcPtr, + int spillBaseOffset, + ulong pc, + Operand guestAddress, + bool isTail = false) + { + int tempRegister; + + if (guestAddress.Kind == OperandKind.Constant) + { + tempRegister = regAlloc.AllocateTempGprRegister(); + + asm.Mov(Register(tempRegister), guestAddress.Value); + asm.StrRiUn(Register(tempRegister), Register(regAlloc.FixedContextRegister), NativeContextOffsets.DispatchAddressOffset); + + regAlloc.FreeTempGprRegister(tempRegister); + } + else + { + asm.StrRiUn(guestAddress, Register(regAlloc.FixedContextRegister), NativeContextOffsets.DispatchAddressOffset); + } + + tempRegister = regAlloc.FixedContextRegister == 1 ? 2 : 1; + + if (!isTail) + { + WriteSpillSkipContext(ref asm, regAlloc, spillBaseOffset); + } + + Operand rn = Register(tempRegister); + + if (regAlloc.FixedContextRegister != 0) + { + asm.Mov(Register(0), Register(regAlloc.FixedContextRegister)); + } + + if (guestAddress.Kind == OperandKind.Constant && funcTable != null) + { + ulong funcPtrLoc = (ulong)Unsafe.AsPointer(ref funcTable.GetValue(guestAddress.Value)); + + asm.Mov(rn, funcPtrLoc & ~0xfffUL); + asm.LdrRiUn(rn, rn, (int)(funcPtrLoc & 0xfffUL)); + } + else + { + asm.Mov(rn, (ulong)funcPtr); + } + + if (isTail) + { + writeEpilogue(); + asm.Br(rn); + } + else + { + asm.Blr(rn); + + ulong nextAddress = pc + 4UL; + + asm.Mov(rn, nextAddress); + asm.Cmp(Register(0), rn); + + tailMerger.AddConditionalReturn(writer, asm, ArmCondition.Ne); + + WriteFillSkipContext(ref asm, regAlloc, spillBaseOffset); + } + } + + private static void WriteCall( + ref Assembler asm, + RegisterAllocator regAlloc, + IntPtr funcPtr, + int spillBaseOffset, + int? resultRegister, + params ulong[] callArgs) + { + uint resultMask = 0u; + + if (resultRegister.HasValue) + { + resultMask = 1u << resultRegister.Value; + } + + int tempRegister = callArgs.Length; + + if (resultRegister.HasValue && tempRegister == resultRegister.Value) + { + tempRegister++; + } + + WriteSpill(ref asm, regAlloc, resultMask, spillBaseOffset, tempRegister); + + // We only support up to 7 arguments right now. + // ABI defines the first 8 integer arguments to be passed on registers X0-X7. + // We need at least one register to put the function address on, so that reduces the number of + // registers we can use for that by one. + + Debug.Assert(callArgs.Length < 8); + + for (int index = 0; index < callArgs.Length; index++) + { + asm.Mov(Register(index), callArgs[index]); + } + + Operand rn = Register(tempRegister); + + asm.Mov(rn, (ulong)funcPtr); + asm.Blr(rn); + + if (resultRegister.HasValue && resultRegister.Value != 0) + { + asm.Mov(Register(resultRegister.Value), Register(0)); + } + + WriteFill(ref asm, regAlloc, resultMask, spillBaseOffset, tempRegister); + } + + private static void WriteSpill(ref Assembler asm, RegisterAllocator regAlloc, uint exceptMask, int spillOffset, int tempRegister) + { + WriteSpillOrFill(ref asm, regAlloc, exceptMask, spillOffset, tempRegister, spill: true); + } + + private static void WriteFill(ref Assembler asm, RegisterAllocator regAlloc, uint exceptMask, int spillOffset, int tempRegister) + { + WriteSpillOrFill(ref asm, regAlloc, exceptMask, spillOffset, tempRegister, spill: false); + } + + private static void WriteSpillOrFill( + ref Assembler asm, + RegisterAllocator regAlloc, + uint exceptMask, + int spillOffset, + int tempRegister, + bool spill) + { + uint gprMask = regAlloc.AllGprMask & ~(AbiConstants.GprCalleeSavedRegsMask | exceptMask); + + if (regAlloc.AllPStateMask != 0 && !spill) + { + // We must reload the status register before reloading the GPRs, + // since we might otherwise trash one of them by using it as temp register. + + Operand rt = Register(tempRegister, OperandType.I32); + + asm.LdrRiUn(rt, Register(RegisterUtils.SpIndex), spillOffset + BitOperations.PopCount(gprMask) * 8); + asm.MsrNzcv(rt); + } + + while (gprMask != 0) + { + int reg = BitOperations.TrailingZeroCount(gprMask); + + if (reg < 31 && (gprMask & (2u << reg)) != 0 && spillOffset < RegisterSaveRestore.Encodable9BitsOffsetLimit) + { + if (spill) + { + asm.StpRiUn( + Register(regAlloc.RemapReservedGprRegister(reg)), + Register(regAlloc.RemapReservedGprRegister(reg + 1)), + Register(RegisterUtils.SpIndex), + spillOffset); + } + else + { + asm.LdpRiUn( + Register(regAlloc.RemapReservedGprRegister(reg)), + Register(regAlloc.RemapReservedGprRegister(reg + 1)), + Register(RegisterUtils.SpIndex), + spillOffset); + } + + gprMask &= ~(3u << reg); + spillOffset += 16; + } + else + { + if (spill) + { + asm.StrRiUn(Register(regAlloc.RemapReservedGprRegister(reg)), Register(RegisterUtils.SpIndex), spillOffset); + } + else + { + asm.LdrRiUn(Register(regAlloc.RemapReservedGprRegister(reg)), Register(RegisterUtils.SpIndex), spillOffset); + } + + gprMask &= ~(1u << reg); + spillOffset += 8; + } + } + + if (regAlloc.AllPStateMask != 0) + { + if (spill) + { + Operand rt = Register(tempRegister, OperandType.I32); + + asm.MrsNzcv(rt); + asm.StrRiUn(rt, Register(RegisterUtils.SpIndex), spillOffset); + } + + spillOffset += 8; + } + + if ((spillOffset & 8) != 0) + { + spillOffset += 8; + } + + uint fpSimdMask = regAlloc.AllFpSimdMask; + + while (fpSimdMask != 0) + { + int reg = BitOperations.TrailingZeroCount(fpSimdMask); + + if (reg < 31 && (fpSimdMask & (2u << reg)) != 0 && spillOffset < RegisterSaveRestore.Encodable9BitsOffsetLimit) + { + if (spill) + { + asm.StpRiUn( + Register(reg, OperandType.V128), + Register(reg + 1, OperandType.V128), + Register(RegisterUtils.SpIndex), + spillOffset); + } + else + { + asm.LdpRiUn( + Register(reg, OperandType.V128), + Register(reg + 1, OperandType.V128), + Register(RegisterUtils.SpIndex), + spillOffset); + } + + fpSimdMask &= ~(3u << reg); + spillOffset += 32; + } + else + { + if (spill) + { + asm.StrRiUn(Register(reg, OperandType.V128), Register(RegisterUtils.SpIndex), spillOffset); + } + else + { + asm.LdrRiUn(Register(reg, OperandType.V128), Register(RegisterUtils.SpIndex), spillOffset); + } + + fpSimdMask &= ~(1u << reg); + spillOffset += 16; + } + } + } + + private static void WriteSpillSkipContext(ref Assembler asm, RegisterAllocator regAlloc, int spillOffset) + { + WriteSpillOrFillSkipContext(ref asm, regAlloc, spillOffset, spill: true); + } + + private static void WriteFillSkipContext(ref Assembler asm, RegisterAllocator regAlloc, int spillOffset) + { + WriteSpillOrFillSkipContext(ref asm, regAlloc, spillOffset, spill: false); + } + + private static void WriteSpillOrFillSkipContext(ref Assembler asm, RegisterAllocator regAlloc, int spillOffset, bool spill) + { + uint gprMask = regAlloc.AllGprMask & ((1u << regAlloc.FixedContextRegister) | (1u << regAlloc.FixedPageTableRegister)); + gprMask &= ~AbiConstants.GprCalleeSavedRegsMask; + + while (gprMask != 0) + { + int reg = BitOperations.TrailingZeroCount(gprMask); + + if (reg < 31 && (gprMask & (2u << reg)) != 0 && spillOffset < RegisterSaveRestore.Encodable9BitsOffsetLimit) + { + if (spill) + { + asm.StpRiUn( + Register(regAlloc.RemapReservedGprRegister(reg)), + Register(regAlloc.RemapReservedGprRegister(reg + 1)), + Register(RegisterUtils.SpIndex), + spillOffset); + } + else + { + asm.LdpRiUn( + Register(regAlloc.RemapReservedGprRegister(reg)), + Register(regAlloc.RemapReservedGprRegister(reg + 1)), + Register(RegisterUtils.SpIndex), + spillOffset); + } + + gprMask &= ~(3u << reg); + spillOffset += 16; + } + else + { + if (spill) + { + asm.StrRiUn(Register(regAlloc.RemapReservedGprRegister(reg)), Register(RegisterUtils.SpIndex), spillOffset); + } + else + { + asm.LdrRiUn(Register(regAlloc.RemapReservedGprRegister(reg)), Register(RegisterUtils.SpIndex), spillOffset); + } + + gprMask &= ~(1u << reg); + spillOffset += 8; + } + } + } + + private static Operand Register(int register, OperandType type = OperandType.I64) + { + return new Operand(register, RegisterType.Integer, type); + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/InstTable.cs b/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/InstTable.cs new file mode 100644 index 000000000..88718afb1 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Arm64/Target/Arm64/InstTable.cs @@ -0,0 +1,1605 @@ +using Ryujinx.Cpu.LightningJit.Table; +using System.Collections.Generic; + +namespace Ryujinx.Cpu.LightningJit.Arm64.Target.Arm64 +{ + static class InstTable + { + private static readonly InstTableLevel _table; + + private readonly struct InstInfo : IInstInfo + { + public uint Encoding { get; } + public uint EncodingMask { get; } + public InstEncoding[] Constraints { get; } + public InstName Name { get; } + public IsaVersion Version { get; } + public IsaFeature Feature { get; } + public InstFlags Flags { get; } + public AddressForm AddressForm { get; } + + public InstInfo( + uint encoding, + uint encodingMask, + InstEncoding[] constraints, + InstName name, + IsaVersion isaVersion, + IsaFeature isaFeature, + InstFlags flags, + AddressForm addressForm = AddressForm.None) + { + if (addressForm != AddressForm.None) + { + flags |= InstFlags.Memory; + } + + Encoding = encoding; + EncodingMask = encodingMask; + Constraints = constraints; + Name = name; + Version = isaVersion; + Feature = isaFeature; + Flags = flags; + AddressForm = addressForm; + } + + public InstInfo( + uint encoding, + uint encodingMask, + InstEncoding[] constraints, + InstName name, + IsaVersion isaVersion, + InstFlags flags, + AddressForm addressForm = AddressForm.None) : this(encoding, encodingMask, constraints, name, isaVersion, IsaFeature.None, flags, addressForm) + { + } + + public InstInfo( + uint encoding, + uint encodingMask, + InstName name, + IsaVersion isaVersion, + IsaFeature isaFeature, + InstFlags flags, + AddressForm addressForm = AddressForm.None) : this(encoding, encodingMask, null, name, isaVersion, isaFeature, flags, addressForm) + { + } + + public InstInfo( + uint encoding, + uint encodingMask, + InstName name, + IsaVersion isaVersion, + InstFlags flags, + AddressForm addressForm = AddressForm.None) : this(encoding, encodingMask, null, name, isaVersion, IsaFeature.None, flags, addressForm) + { + } + + public bool IsConstrained(uint encoding) + { + if (Constraints != null) + { + foreach (InstEncoding constraint in Constraints) + { + if ((encoding & constraint.EncodingMask) == constraint.Encoding) + { + return true; + } + } + } + + return false; + } + } + + static InstTable() + { + InstEncoding[] qsizeConstraints = new InstEncoding[] + { + new(0x00C00000, 0x40C00000), + }; + + InstEncoding[] sizeConstraints = new InstEncoding[] + { + new(0x00C00000, 0x00C00000), + }; + + InstEncoding[] opuOpuOpuConstraints = new InstEncoding[] + { + new(0x00001400, 0x00001C00), + new(0x00001800, 0x00001C00), + new(0x00001C00, 0x00001C00), + }; + + InstEncoding[] shiftSfimm6Constraints = new InstEncoding[] + { + new(0x00C00000, 0x00C00000), + new(0x00008000, 0x80008000), + }; + + InstEncoding[] qsizeSizeConstraints = new InstEncoding[] + { + new(0x00800000, 0x40C00000), + new(0x00C00000, 0x00C00000), + }; + + InstEncoding[] nimmsNimmsNimmsNimmsNimmsNimmsNimmsNimmsSfnConstraints = new InstEncoding[] + { + new(0x0040FC00, 0x0040FC00), + new(0x00007C00, 0x0040FC00), + new(0x0000BC00, 0x0040FC00), + new(0x0000DC00, 0x0040FC00), + new(0x0000EC00, 0x0040FC00), + new(0x0000F400, 0x0040FC00), + new(0x0000F800, 0x0040FC00), + new(0x0000FC00, 0x0040FC00), + new(0x00400000, 0x80400000), + }; + + InstEncoding[] sfimm6Constraints = new InstEncoding[] + { + new(0x00008000, 0x80008000), + }; + + InstEncoding[] sfnSfnSfimmr5Sfimms5Constraints = new InstEncoding[] + { + new(0x80000000, 0x80400000), + new(0x00400000, 0x80400000), + new(0x00200000, 0x80200000), + new(0x00008000, 0x80008000), + }; + + InstEncoding[] cmodeopqConstraints = new InstEncoding[] + { + new(0x2000F000, 0x6000F000), + }; + + InstEncoding[] rsRtConstraints = new InstEncoding[] + { + new(0x00010000, 0x00010000), + new(0x00000001, 0x00000001), + }; + + InstEncoding[] sfszSfszSfszSfszConstraints = new InstEncoding[] + { + new(0x80000000, 0x80000C00), + new(0x80000400, 0x80000C00), + new(0x80000800, 0x80000C00), + new(0x00000C00, 0x80000C00), + }; + + InstEncoding[] imm5Constraints = new InstEncoding[] + { + new(0x00000000, 0x000F0000), + }; + + InstEncoding[] imm5Imm5qConstraints = new InstEncoding[] + { + new(0x00000000, 0x000F0000), + new(0x00080000, 0x400F0000), + }; + + InstEncoding[] nsfNsfSfimmsConstraints = new InstEncoding[] + { + new(0x00400000, 0x80400000), + new(0x80000000, 0x80400000), + new(0x00008000, 0x80008000), + }; + + InstEncoding[] qimm4Constraints = new InstEncoding[] + { + new(0x00004000, 0x40004000), + }; + + InstEncoding[] qszConstraints = new InstEncoding[] + { + new(0x00400000, 0x40400000), + }; + + InstEncoding[] euacEuacEuacConstraints = new InstEncoding[] + { + new(0x00000800, 0x20800800), + new(0x00800000, 0x20800800), + new(0x00800800, 0x20800800), + }; + + InstEncoding[] qszEuacEuacEuacConstraints = new InstEncoding[] + { + new(0x00400000, 0x40400000), + new(0x00000800, 0x20800800), + new(0x00800000, 0x20800800), + new(0x00800800, 0x20800800), + }; + + InstEncoding[] szConstraints = new InstEncoding[] + { + new(0x00400000, 0x00400000), + }; + + InstEncoding[] sizeQsizeConstraints = new InstEncoding[] + { + new(0x00000000, 0x00C00000), + new(0x00C00000, 0x40C00000), + }; + + InstEncoding[] sizeSizeSizelSizeqSizehqConstraints = new InstEncoding[] + { + new(0x00000000, 0x00C00000), + new(0x00C00000, 0x00C00000), + new(0x00A00000, 0x00E00000), + new(0x00800000, 0x40C00000), + new(0x00400800, 0x40C00800), + }; + + InstEncoding[] szConstraints2 = new InstEncoding[] + { + new(0x00000000, 0x00400000), + }; + + InstEncoding[] immhConstraints = new InstEncoding[] + { + new(0x00000000, 0x00780000), + }; + + InstEncoding[] immhQimmhConstraints = new InstEncoding[] + { + new(0x00000000, 0x00780000), + new(0x00400000, 0x40400000), + }; + + InstEncoding[] sfscaleConstraints = new InstEncoding[] + { + new(0x00000000, 0x80008000), + }; + + InstEncoding[] ftypeopcFtypeopcFtypeopcFtypeopcFtypeOpcConstraints = new InstEncoding[] + { + new(0x00000000, 0x00C18000), + new(0x00408000, 0x00C18000), + new(0x00810000, 0x00C18000), + new(0x00C18000, 0x00C18000), + new(0x00800000, 0x00C00000), + new(0x00010000, 0x00018000), + }; + + InstEncoding[] szlConstraints = new InstEncoding[] + { + new(0x00600000, 0x00600000), + }; + + InstEncoding[] szlQszConstraints = new InstEncoding[] + { + new(0x00600000, 0x00600000), + new(0x00400000, 0x40400000), + }; + + InstEncoding[] qConstraints = new InstEncoding[] + { + new(0x00000000, 0x40000000), + }; + + InstEncoding[] sfftypermodeSfftypermodeConstraints = new InstEncoding[] + { + new(0x00400000, 0x80C80000), + new(0x80000000, 0x80C80000), + }; + + InstEncoding[] uo1o2Constraints = new InstEncoding[] + { + new(0x20800000, 0x20801000), + }; + + InstEncoding[] qszUo1o2Constraints = new InstEncoding[] + { + new(0x00400000, 0x40400000), + new(0x20800000, 0x20801000), + }; + + InstEncoding[] sConstraints = new InstEncoding[] + { + new(0x00001000, 0x00001000), + }; + + InstEncoding[] opcodesizeOpcodesizeOpcodesizesOpcodesizeConstraints = new InstEncoding[] + { + new(0x00004400, 0x0000C400), + new(0x00008800, 0x0000C800), + new(0x00009400, 0x0000D400), + new(0x0000C000, 0x0000C000), + }; + + InstEncoding[] qsizeConstraints2 = new InstEncoding[] + { + new(0x00000C00, 0x40000C00), + }; + + InstEncoding[] rtRtConstraints = new InstEncoding[] + { + new(0x00000018, 0x00000018), + new(0x00000001, 0x00000001), + }; + + InstEncoding[] opc1sizeOpc1sizeOpc1sizeConstraints = new InstEncoding[] + { + new(0x40800000, 0xC0800000), + new(0x80800000, 0xC0800000), + new(0xC0800000, 0xC0800000), + }; + + InstEncoding[] rtRt2Constraints = new InstEncoding[] + { + new(0x0000001F, 0x0000001F), + new(0x001F0000, 0x001F0000), + }; + + InstEncoding[] opcConstraints = new InstEncoding[] + { + new(0xC0000000, 0xC0000000), + }; + + InstEncoding[] opcConstraints2 = new InstEncoding[] + { + new(0x40000000, 0x40000000), + }; + + InstEncoding[] opclOpcConstraints = new InstEncoding[] + { + new(0x40000000, 0x40400000), + new(0xC0000000, 0xC0000000), + }; + + InstEncoding[] optionConstraints = new InstEncoding[] + { + new(0x00000000, 0x00004000), + }; + + InstEncoding[] opc1sizeOpc1sizeOpc1sizeOptionConstraints = new InstEncoding[] + { + new(0x40800000, 0xC0800000), + new(0x80800000, 0xC0800000), + new(0xC0800000, 0xC0800000), + new(0x00000000, 0x00004000), + }; + + InstEncoding[] sizeSizeConstraints = new InstEncoding[] + { + new(0x00000000, 0x00C00000), + new(0x00C00000, 0x00C00000), + }; + + InstEncoding[] sfhwConstraints = new InstEncoding[] + { + new(0x00400000, 0x80400000), + }; + + InstEncoding[] rtConstraints = new InstEncoding[] + { + new(0x00000001, 0x00000001), + }; + + InstEncoding[] usizeUsizeUsizeSizeConstraints = new InstEncoding[] + { + new(0x20400000, 0x20C00000), + new(0x20800000, 0x20C00000), + new(0x20C00000, 0x20C00000), + new(0x00C00000, 0x00C00000), + }; + + InstEncoding[] sizeSizeConstraints2 = new InstEncoding[] + { + new(0x00400000, 0x00C00000), + new(0x00800000, 0x00C00000), + }; + + InstEncoding[] rtConstraints2 = new InstEncoding[] + { + new(0x00000018, 0x00000018), + }; + + InstEncoding[] sfopcConstraints = new InstEncoding[] + { + new(0x00000400, 0x80000400), + }; + + InstEncoding[] sizeSizeSizeConstraints = new InstEncoding[] + { + new(0x00400000, 0x00C00000), + new(0x00800000, 0x00C00000), + new(0x00C00000, 0x00C00000), + }; + + InstEncoding[] sizeSizeConstraints3 = new InstEncoding[] + { + new(0x00800000, 0x00C00000), + new(0x00C00000, 0x00C00000), + }; + + InstEncoding[] sfConstraints = new InstEncoding[] + { + new(0x00000000, 0x80000000), + }; + + InstEncoding[] immhImmhConstraints = new InstEncoding[] + { + new(0x00000000, 0x00780000), + new(0x00400000, 0x00400000), + }; + + InstEncoding[] sizeSizeConstraints4 = new InstEncoding[] + { + new(0x00C00000, 0x00C00000), + new(0x00000000, 0x00C00000), + }; + + InstEncoding[] ssizeSsizeSsizeConstraints = new InstEncoding[] + { + new(0x00000000, 0x00C00800), + new(0x00400000, 0x00C00800), + new(0x00800000, 0x00C00800), + }; + + InstEncoding[] immhOpuConstraints = new InstEncoding[] + { + new(0x00000000, 0x00780000), + new(0x00000000, 0x20001000), + }; + + InstEncoding[] immhQimmhOpuConstraints = new InstEncoding[] + { + new(0x00000000, 0x00780000), + new(0x00400000, 0x40400000), + new(0x00000000, 0x20001000), + }; + + List insts = new() + { + new(0x5AC02000, 0x7FFFFC00, InstName.Abs, IsaVersion.v89, InstFlags.RdRn), + new(0x5EE0B800, 0xFFFFFC00, InstName.AbsAdvsimdS, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x0E20B800, 0xBF3FFC00, qsizeConstraints, InstName.AbsAdvsimdV, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x1A000000, 0x7FE0FC00, InstName.Adc, IsaVersion.v80, InstFlags.RdRnRmC), + new(0x3A000000, 0x7FE0FC00, InstName.Adcs, IsaVersion.v80, InstFlags.RdRnRmCS), + new(0x91800000, 0xFFC0C000, InstName.Addg, IsaVersion.v85, InstFlags.None), + new(0x0E204000, 0xBF20FC00, sizeConstraints, InstName.AddhnAdvsimd, IsaVersion.v80, InstFlags.RdReadRdRnRmFpSimd), + new(0x5EF1B800, 0xFFFFFC00, InstName.AddpAdvsimdPair, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x0E20BC00, 0xBF20FC00, qsizeConstraints, InstName.AddpAdvsimdVec, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x2B200000, 0x7FE00000, opuOpuOpuConstraints, InstName.AddsAddsubExt, IsaVersion.v80, InstFlags.RdRnSPRmS), + new(0x31000000, 0x7F800000, InstName.AddsAddsubImm, IsaVersion.v80, InstFlags.RdRnSPS), + new(0x2B000000, 0x7F200000, shiftSfimm6Constraints, InstName.AddsAddsubShift, IsaVersion.v80, InstFlags.RdRnRmS), + new(0x0E31B800, 0xBF3FFC00, qsizeSizeConstraints, InstName.AddvAdvsimd, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x0B200000, 0x7FE00000, opuOpuOpuConstraints, InstName.AddAddsubExt, IsaVersion.v80, InstFlags.RdSPRnSPRm), + new(0x11000000, 0x7F800000, InstName.AddAddsubImm, IsaVersion.v80, InstFlags.RdSPRnSP), + new(0x0B000000, 0x7F200000, shiftSfimm6Constraints, InstName.AddAddsubShift, IsaVersion.v80, InstFlags.RdRnRm), + new(0x5EE08400, 0xFFE0FC00, InstName.AddAdvsimdS, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x0E208400, 0xBF20FC00, qsizeConstraints, InstName.AddAdvsimdV, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x10000000, 0x9F000000, InstName.Adr, IsaVersion.v80, InstFlags.Rd, AddressForm.Literal), + new(0x90000000, 0x9F000000, InstName.Adrp, IsaVersion.v80, InstFlags.Rd, AddressForm.Literal), + new(0x4E285800, 0xFFFFFC00, InstName.AesdAdvsimd, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x4E284800, 0xFFFFFC00, InstName.AeseAdvsimd, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x4E287800, 0xFFFFFC00, InstName.AesimcAdvsimd, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x4E286800, 0xFFFFFC00, InstName.AesmcAdvsimd, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x72000000, 0x7F800000, nimmsNimmsNimmsNimmsNimmsNimmsNimmsNimmsSfnConstraints, InstName.AndsLogImm, IsaVersion.v80, InstFlags.RdRnS), + new(0x6A000000, 0x7F200000, sfimm6Constraints, InstName.AndsLogShift, IsaVersion.v80, InstFlags.RdRnRmS), + new(0x0E201C00, 0xBFE0FC00, InstName.AndAdvsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x12000000, 0x7F800000, nimmsNimmsNimmsNimmsNimmsNimmsNimmsNimmsSfnConstraints, InstName.AndLogImm, IsaVersion.v80, InstFlags.RdSPRn), + new(0x0A000000, 0x7F200000, sfimm6Constraints, InstName.AndLogShift, IsaVersion.v80, InstFlags.RdRnRm), + new(0x1AC02800, 0x7FE0FC00, InstName.Asrv, IsaVersion.v80, InstFlags.RdRnRm), + new(0xDAC11800, 0xFFFFDC00, InstName.Autda, IsaVersion.v83, InstFlags.RdRnSP), + new(0xDAC11C00, 0xFFFFDC00, InstName.Autdb, IsaVersion.v83, InstFlags.RdRnSP), + new(0xDAC11000, 0xFFFFDC00, InstName.AutiaGeneral, IsaVersion.v83, InstFlags.RdRnSP), + new(0xD503219F, 0xFFFFFDDF, InstName.AutiaSystem, IsaVersion.v83, InstFlags.None), + new(0xDAC11400, 0xFFFFDC00, InstName.AutibGeneral, IsaVersion.v83, InstFlags.RdRnSP), + new(0xD50321DF, 0xFFFFFDDF, InstName.AutibSystem, IsaVersion.v83, InstFlags.None), + new(0xD500405F, 0xFFFFFFFF, InstName.Axflag, IsaVersion.v85, InstFlags.C), + new(0xCE200000, 0xFFE08000, InstName.BcaxAdvsimd, IsaVersion.v82, InstFlags.RdRnRmRaFpSimd), + new(0x54000010, 0xFF000010, InstName.BcCond, IsaVersion.v88, InstFlags.Nzcv), + new(0x0EA16800, 0xBFFFFC00, InstName.BfcvtnAdvsimd, IsaVersion.v86, InstFlags.RdRnFpSimd), + new(0x1E634000, 0xFFFFFC00, InstName.BfcvtFloat, IsaVersion.v86, InstFlags.RdRnFpSimd), + new(0x0F40F000, 0xBFC0F400, InstName.BfdotAdvsimdElt, IsaVersion.v86, InstFlags.RdReadRdRnRmFpSimd), + new(0x2E40FC00, 0xBFE0FC00, InstName.BfdotAdvsimdVec, IsaVersion.v86, InstFlags.RdReadRdRnRmFpSimd), + new(0x33000000, 0x7F800000, sfnSfnSfimmr5Sfimms5Constraints, InstName.Bfm, IsaVersion.v80, InstFlags.RdReadRdRn), + new(0x0FC0F000, 0xBFC0F400, InstName.BfmlalAdvsimdElt, IsaVersion.v86, InstFlags.RdRnRmFpSimd), + new(0x2EC0FC00, 0xBFE0FC00, InstName.BfmlalAdvsimdVec, IsaVersion.v86, InstFlags.RdRnRmFpSimd), + new(0x6E40EC00, 0xFFE0FC00, InstName.BfmmlaAdvsimd, IsaVersion.v86, InstFlags.RdRnRmFpSimd), + new(0x6A200000, 0x7F200000, sfimm6Constraints, InstName.Bics, IsaVersion.v80, InstFlags.RdRnRmS), + new(0x2F001400, 0xBFF81C00, cmodeopqConstraints, InstName.BicAdvsimdImm, IsaVersion.v80, InstFlags.RdFpSimd), + new(0x0E601C00, 0xBFE0FC00, InstName.BicAdvsimdReg, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x0A200000, 0x7F200000, sfimm6Constraints, InstName.BicLogShift, IsaVersion.v80, InstFlags.RdRnRm), + new(0x2EE01C00, 0xBFE0FC00, InstName.BifAdvsimd, IsaVersion.v80, InstFlags.RdReadRdRnRmFpSimd), + new(0x2EA01C00, 0xBFE0FC00, InstName.BitAdvsimd, IsaVersion.v80, InstFlags.RdReadRdRnRmFpSimd), + new(0x94000000, 0xFC000000, InstName.Bl, IsaVersion.v80, InstFlags.None), + new(0xD63F0000, 0xFFFFFC1F, InstName.Blr, IsaVersion.v80, InstFlags.Rn), + new(0xD63F0800, 0xFEFFF800, InstName.Blra, IsaVersion.v83, InstFlags.RnRm), + new(0xD61F0000, 0xFFFFFC1F, InstName.Br, IsaVersion.v80, InstFlags.Rn), + new(0xD61F0800, 0xFEFFF800, InstName.Bra, IsaVersion.v83, InstFlags.RnRm), + new(0xD4200000, 0xFFE0001F, InstName.Brk, IsaVersion.v80, InstFlags.None), + new(0x2E601C00, 0xBFE0FC00, InstName.BslAdvsimd, IsaVersion.v80, InstFlags.RdReadRdRnRmFpSimd), + new(0xD503241F, 0xFFFFFF3F, InstName.Bti, IsaVersion.v85, InstFlags.None), + new(0x54000000, 0xFF000010, InstName.BCond, IsaVersion.v80, InstFlags.Nzcv), + new(0x14000000, 0xFC000000, InstName.BUncond, IsaVersion.v80, InstFlags.None), + new(0x88A07C00, 0xBFA07C00, InstName.Cas, IsaVersion.v81, InstFlags.RtReadRtRnSPRs, AddressForm.BaseRegister), + new(0x08A07C00, 0xFFA07C00, InstName.Casb, IsaVersion.v81, InstFlags.RtReadRtRnSPRs, AddressForm.BaseRegister), + new(0x48A07C00, 0xFFA07C00, InstName.Cash, IsaVersion.v81, InstFlags.RtReadRtRnSPRs, AddressForm.BaseRegister), + new(0x08207C00, 0xBFA07C00, rsRtConstraints, InstName.Casp, IsaVersion.v81, InstFlags.RtReadRtRnSPRs, AddressForm.BaseRegister), + new(0x35000000, 0x7F000000, InstName.Cbnz, IsaVersion.v80, InstFlags.RtReadRt), + new(0x34000000, 0x7F000000, InstName.Cbz, IsaVersion.v80, InstFlags.RtReadRt), + new(0x3A400800, 0x7FE00C10, InstName.CcmnImm, IsaVersion.v80, InstFlags.RnNzcvS), + new(0x3A400000, 0x7FE00C10, InstName.CcmnReg, IsaVersion.v80, InstFlags.RnRmNzcvS), + new(0x7A400800, 0x7FE00C10, InstName.CcmpImm, IsaVersion.v80, InstFlags.RnNzcvS), + new(0x7A400000, 0x7FE00C10, InstName.CcmpReg, IsaVersion.v80, InstFlags.RnRmNzcvS), + new(0xD500401F, 0xFFFFFFFF, InstName.Cfinv, IsaVersion.v84, InstFlags.C), + new(0xD503251F, 0xFFFFFFFF, InstName.Chkfeat, IsaVersion.None, InstFlags.None), + new(0xD50322DF, 0xFFFFFFFF, InstName.Clrbhb, IsaVersion.v89, InstFlags.None), + new(0xD503305F, 0xFFFFF0FF, InstName.Clrex, IsaVersion.v80, InstFlags.None), + new(0x0E204800, 0xBF3FFC00, sizeConstraints, InstName.ClsAdvsimd, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x5AC01400, 0x7FFFFC00, InstName.ClsInt, IsaVersion.v80, InstFlags.RdRn), + new(0x2E204800, 0xBF3FFC00, sizeConstraints, InstName.ClzAdvsimd, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x5AC01000, 0x7FFFFC00, InstName.ClzInt, IsaVersion.v80, InstFlags.RdRn), + new(0x7EE08C00, 0xFFE0FC00, InstName.CmeqAdvsimdRegS, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x2E208C00, 0xBF20FC00, qsizeConstraints, InstName.CmeqAdvsimdRegV, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x5EE09800, 0xFFFFFC00, InstName.CmeqAdvsimdZeroS, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x0E209800, 0xBF3FFC00, qsizeConstraints, InstName.CmeqAdvsimdZeroV, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x5EE03C00, 0xFFE0FC00, InstName.CmgeAdvsimdRegS, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x0E203C00, 0xBF20FC00, qsizeConstraints, InstName.CmgeAdvsimdRegV, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x7EE08800, 0xFFFFFC00, InstName.CmgeAdvsimdZeroS, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x2E208800, 0xBF3FFC00, qsizeConstraints, InstName.CmgeAdvsimdZeroV, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x5EE03400, 0xFFE0FC00, InstName.CmgtAdvsimdRegS, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x0E203400, 0xBF20FC00, qsizeConstraints, InstName.CmgtAdvsimdRegV, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x5EE08800, 0xFFFFFC00, InstName.CmgtAdvsimdZeroS, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x0E208800, 0xBF3FFC00, qsizeConstraints, InstName.CmgtAdvsimdZeroV, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x7EE03400, 0xFFE0FC00, InstName.CmhiAdvsimdS, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x2E203400, 0xBF20FC00, qsizeConstraints, InstName.CmhiAdvsimdV, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x7EE03C00, 0xFFE0FC00, InstName.CmhsAdvsimdS, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x2E203C00, 0xBF20FC00, qsizeConstraints, InstName.CmhsAdvsimdV, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x7EE09800, 0xFFFFFC00, InstName.CmleAdvsimdS, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x2E209800, 0xBF3FFC00, qsizeConstraints, InstName.CmleAdvsimdV, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x5EE0A800, 0xFFFFFC00, InstName.CmltAdvsimdS, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x0E20A800, 0xBF3FFC00, qsizeConstraints, InstName.CmltAdvsimdV, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x5EE08C00, 0xFFE0FC00, InstName.CmtstAdvsimdS, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x0E208C00, 0xBF20FC00, qsizeConstraints, InstName.CmtstAdvsimdV, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x5AC01C00, 0x7FFFFC00, InstName.Cnt, IsaVersion.v89, InstFlags.RdRn), + new(0x0E205800, 0xBFFFFC00, InstName.CntAdvsimd, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x19000400, 0x3F20FC00, InstName.Cpyfp, IsaVersion.v88, InstFlags.RdRnRsS), + new(0x1900C400, 0x3F20FC00, InstName.Cpyfpn, IsaVersion.v88, InstFlags.RdRnRsS), + new(0x19008400, 0x3F20FC00, InstName.Cpyfprn, IsaVersion.v88, InstFlags.RdRnRsS), + new(0x19002400, 0x3F20FC00, InstName.Cpyfprt, IsaVersion.v88, InstFlags.RdRnRsS), + new(0x1900E400, 0x3F20FC00, InstName.Cpyfprtn, IsaVersion.v88, InstFlags.RdRnRsS), + new(0x1900A400, 0x3F20FC00, InstName.Cpyfprtrn, IsaVersion.v88, InstFlags.RdRnRsS), + new(0x19006400, 0x3F20FC00, InstName.Cpyfprtwn, IsaVersion.v88, InstFlags.RdRnRsS), + new(0x19003400, 0x3F20FC00, InstName.Cpyfpt, IsaVersion.v88, InstFlags.RdRnRsS), + new(0x1900F400, 0x3F20FC00, InstName.Cpyfptn, IsaVersion.v88, InstFlags.RdRnRsS), + new(0x1900B400, 0x3F20FC00, InstName.Cpyfptrn, IsaVersion.v88, InstFlags.RdRnRsS), + new(0x19007400, 0x3F20FC00, InstName.Cpyfptwn, IsaVersion.v88, InstFlags.RdRnRsS), + new(0x19004400, 0x3F20FC00, InstName.Cpyfpwn, IsaVersion.v88, InstFlags.RdRnRsS), + new(0x19001400, 0x3F20FC00, InstName.Cpyfpwt, IsaVersion.v88, InstFlags.RdRnRsS), + new(0x1900D400, 0x3F20FC00, InstName.Cpyfpwtn, IsaVersion.v88, InstFlags.RdRnRsS), + new(0x19009400, 0x3F20FC00, InstName.Cpyfpwtrn, IsaVersion.v88, InstFlags.RdRnRsS), + new(0x19005400, 0x3F20FC00, InstName.Cpyfpwtwn, IsaVersion.v88, InstFlags.RdRnRsS), + new(0x1D000400, 0x3F20FC00, InstName.Cpyp, IsaVersion.v88, InstFlags.RdRnRsS), + new(0x1D00C400, 0x3F20FC00, InstName.Cpypn, IsaVersion.v88, InstFlags.RdRnRsS), + new(0x1D008400, 0x3F20FC00, InstName.Cpyprn, IsaVersion.v88, InstFlags.RdRnRsS), + new(0x1D002400, 0x3F20FC00, InstName.Cpyprt, IsaVersion.v88, InstFlags.RdRnRsS), + new(0x1D00E400, 0x3F20FC00, InstName.Cpyprtn, IsaVersion.v88, InstFlags.RdRnRsS), + new(0x1D00A400, 0x3F20FC00, InstName.Cpyprtrn, IsaVersion.v88, InstFlags.RdRnRsS), + new(0x1D006400, 0x3F20FC00, InstName.Cpyprtwn, IsaVersion.v88, InstFlags.RdRnRsS), + new(0x1D003400, 0x3F20FC00, InstName.Cpypt, IsaVersion.v88, InstFlags.RdRnRsS), + new(0x1D00F400, 0x3F20FC00, InstName.Cpyptn, IsaVersion.v88, InstFlags.RdRnRsS), + new(0x1D00B400, 0x3F20FC00, InstName.Cpyptrn, IsaVersion.v88, InstFlags.RdRnRsS), + new(0x1D007400, 0x3F20FC00, InstName.Cpyptwn, IsaVersion.v88, InstFlags.RdRnRsS), + new(0x1D004400, 0x3F20FC00, InstName.Cpypwn, IsaVersion.v88, InstFlags.RdRnRsS), + new(0x1D001400, 0x3F20FC00, InstName.Cpypwt, IsaVersion.v88, InstFlags.RdRnRsS), + new(0x1D00D400, 0x3F20FC00, InstName.Cpypwtn, IsaVersion.v88, InstFlags.RdRnRsS), + new(0x1D009400, 0x3F20FC00, InstName.Cpypwtrn, IsaVersion.v88, InstFlags.RdRnRsS), + new(0x1D005400, 0x3F20FC00, InstName.Cpypwtwn, IsaVersion.v88, InstFlags.RdRnRsS), + new(0x1AC04000, 0x7FE0F000, sfszSfszSfszSfszConstraints, InstName.Crc32, IsaVersion.v80, InstFlags.RdRnRm), + new(0x1AC05000, 0x7FE0F000, sfszSfszSfszSfszConstraints, InstName.Crc32c, IsaVersion.v80, InstFlags.RdRnRm), + new(0xD503229F, 0xFFFFFFFF, InstName.Csdb, IsaVersion.v80, InstFlags.None), + new(0x1A800000, 0x7FE00C00, InstName.Csel, IsaVersion.v80, InstFlags.RdRnRmNzcv), + new(0x1A800400, 0x7FE00C00, InstName.Csinc, IsaVersion.v80, InstFlags.RdRnRmNzcv), + new(0x5A800000, 0x7FE00C00, InstName.Csinv, IsaVersion.v80, InstFlags.RdRnRmNzcv), + new(0x5A800400, 0x7FE00C00, InstName.Csneg, IsaVersion.v80, InstFlags.RdRnRmNzcv), + new(0x5AC01800, 0x7FFFFC00, InstName.Ctz, IsaVersion.v89, InstFlags.RdRn), + new(0xD4A00001, 0xFFE0001F, InstName.Dcps1, IsaVersion.v80, InstFlags.None), + new(0xD4A00002, 0xFFE0001F, InstName.Dcps2, IsaVersion.v80, InstFlags.None), + new(0xD4A00003, 0xFFE0001F, InstName.Dcps3, IsaVersion.v80, InstFlags.None), + new(0xD50320DF, 0xFFFFFFFF, InstName.Dgh, IsaVersion.v84, InstFlags.None), + new(0xD50330BF, 0xFFFFF0FF, InstName.Dmb, IsaVersion.v80, InstFlags.None), + new(0xD6BF03E0, 0xFFFFFFFF, InstName.Drps, IsaVersion.v80, InstFlags.None), + new(0xD503309F, 0xFFFFF0FF, InstName.DsbDsbMemory, IsaVersion.v80, InstFlags.None), + new(0xD503323F, 0xFFFFF3FF, InstName.DsbDsbNxs, IsaVersion.v87, InstFlags.None), + new(0x5E000400, 0xFFE0FC00, imm5Constraints, InstName.DupAdvsimdEltScalarFromElement, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x0E000400, 0xBFE0FC00, imm5Imm5qConstraints, InstName.DupAdvsimdEltVectorFromElement, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x0E000C00, 0xBFE0FC00, imm5Imm5qConstraints, InstName.DupAdvsimdGen, IsaVersion.v80, InstFlags.RdRnFpSimdFromGpr), + new(0x4A200000, 0x7F200000, sfimm6Constraints, InstName.Eon, IsaVersion.v80, InstFlags.RdRnRm), + new(0xCE000000, 0xFFE08000, InstName.Eor3Advsimd, IsaVersion.v82, InstFlags.RdRnRmRaFpSimd), + new(0x2E201C00, 0xBFE0FC00, InstName.EorAdvsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x52000000, 0x7F800000, nimmsNimmsNimmsNimmsNimmsNimmsNimmsNimmsSfnConstraints, InstName.EorLogImm, IsaVersion.v80, InstFlags.RdSPRn), + new(0x4A000000, 0x7F200000, sfimm6Constraints, InstName.EorLogShift, IsaVersion.v80, InstFlags.RdRnRm), + new(0xD69F03E0, 0xFFFFFFFF, InstName.Eret, IsaVersion.v80, InstFlags.None), + new(0xD69F0BFF, 0xFFFFFBFF, InstName.Ereta, IsaVersion.v83, InstFlags.None), + new(0xD503221F, 0xFFFFFFFF, InstName.Esb, IsaVersion.v82, InstFlags.None), + new(0x13800000, 0x7FA00000, nsfNsfSfimmsConstraints, InstName.Extr, IsaVersion.v80, InstFlags.RdRnRm), + new(0x2E000000, 0xBFE08400, qimm4Constraints, InstName.ExtAdvsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x7EC01400, 0xFFE0FC00, InstName.FabdAdvsimdSH, IsaVersion.v82, InstFlags.RdRnRmFpSimd), + new(0x7EA0D400, 0xFFA0FC00, InstName.FabdAdvsimdS, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x2EC01400, 0xBFE0FC00, InstName.FabdAdvsimdVH, IsaVersion.v82, InstFlags.RdRnRmFpSimd), + new(0x2EA0D400, 0xBFA0FC00, qszConstraints, InstName.FabdAdvsimdV, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x0EF8F800, 0xBFFFFC00, InstName.FabsAdvsimdHalf, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x0EA0F800, 0xBFBFFC00, qszConstraints, InstName.FabsAdvsimdSingleAndDouble, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x1E20C000, 0xFFBFFC00, InstName.FabsFloat, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x1EE0C000, 0xFFFFFC00, InstName.FabsFloat, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x7E402C00, 0xFFE0FC00, euacEuacEuacConstraints, InstName.FacgeAdvsimdSH, IsaVersion.v82, InstFlags.RdRnRmFpSimd), + new(0x7E20EC00, 0xFFA0FC00, euacEuacEuacConstraints, InstName.FacgeAdvsimdS, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x2E402C00, 0xBFE0FC00, euacEuacEuacConstraints, InstName.FacgeAdvsimdVH, IsaVersion.v82, InstFlags.RdRnRmFpSimd), + new(0x2E20EC00, 0xBFA0FC00, qszEuacEuacEuacConstraints, InstName.FacgeAdvsimdV, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x7EC02C00, 0xFFE0FC00, euacEuacEuacConstraints, InstName.FacgtAdvsimdSH, IsaVersion.v82, InstFlags.RdRnRmFpSimd), + new(0x7EA0EC00, 0xFFA0FC00, euacEuacEuacConstraints, InstName.FacgtAdvsimdS, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x2EC02C00, 0xBFE0FC00, euacEuacEuacConstraints, InstName.FacgtAdvsimdVH, IsaVersion.v82, InstFlags.RdRnRmFpSimd), + new(0x2EA0EC00, 0xBFA0FC00, qszEuacEuacEuacConstraints, InstName.FacgtAdvsimdV, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x5E30D800, 0xFFBFFC00, szConstraints, InstName.FaddpAdvsimdPairHalf, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x7E30D800, 0xFFBFFC00, InstName.FaddpAdvsimdPairSingleAndDouble, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x2E401400, 0xBFE0FC00, InstName.FaddpAdvsimdVecHalf, IsaVersion.v82, InstFlags.RdRnRmFpSimd), + new(0x2E20D400, 0xBFA0FC00, qszConstraints, InstName.FaddpAdvsimdVecSingleAndDouble, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x0E401400, 0xBFE0FC00, InstName.FaddAdvsimdHalf, IsaVersion.v82, InstFlags.RdRnRmFpSimd), + new(0x0E20D400, 0xBFA0FC00, qszConstraints, InstName.FaddAdvsimdSingleAndDouble, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x1E202800, 0xFFA0FC00, InstName.FaddFloat, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x1EE02800, 0xFFE0FC00, InstName.FaddFloat, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x2E80E400, 0xBFA0EC00, sizeQsizeConstraints, InstName.FcaddAdvsimdVec, IsaVersion.v83, InstFlags.RdRnRmFpSimd), + new(0x2E40E400, 0xBFE0EC00, sizeQsizeConstraints, InstName.FcaddAdvsimdVec, IsaVersion.v83, InstFlags.RdRnRmFpSimd), + new(0x1E200410, 0xFFA00C10, InstName.FccmpeFloat, IsaVersion.v80, InstFlags.RnRmNzcvSFpSimd), + new(0x1EE00410, 0xFFE00C10, InstName.FccmpeFloat, IsaVersion.v80, InstFlags.RnRmNzcvSFpSimd), + new(0x1E200400, 0xFFA00C10, InstName.FccmpFloat, IsaVersion.v80, InstFlags.RnRmNzcvSFpSimd), + new(0x1EE00400, 0xFFE00C10, InstName.FccmpFloat, IsaVersion.v80, InstFlags.RnRmNzcvSFpSimd), + new(0x5E402400, 0xFFE0FC00, euacEuacEuacConstraints, InstName.FcmeqAdvsimdRegSH, IsaVersion.v82, InstFlags.RdRnRmFpSimd), + new(0x5E20E400, 0xFFA0FC00, euacEuacEuacConstraints, InstName.FcmeqAdvsimdRegS, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x0E402400, 0xBFE0FC00, euacEuacEuacConstraints, InstName.FcmeqAdvsimdRegVH, IsaVersion.v82, InstFlags.RdRnRmFpSimd), + new(0x0E20E400, 0xBFA0FC00, qszEuacEuacEuacConstraints, InstName.FcmeqAdvsimdRegV, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x5EF8D800, 0xFFFFFC00, InstName.FcmeqAdvsimdZeroSH, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x5EA0D800, 0xFFBFFC00, InstName.FcmeqAdvsimdZeroS, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x0EF8D800, 0xBFFFFC00, InstName.FcmeqAdvsimdZeroVH, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x0EA0D800, 0xBFBFFC00, qszConstraints, InstName.FcmeqAdvsimdZeroV, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x7E402400, 0xFFE0FC00, euacEuacEuacConstraints, InstName.FcmgeAdvsimdRegSH, IsaVersion.v82, InstFlags.RdRnRmFpSimd), + new(0x7E20E400, 0xFFA0FC00, euacEuacEuacConstraints, InstName.FcmgeAdvsimdRegS, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x2E402400, 0xBFE0FC00, euacEuacEuacConstraints, InstName.FcmgeAdvsimdRegVH, IsaVersion.v82, InstFlags.RdRnRmFpSimd), + new(0x2E20E400, 0xBFA0FC00, qszEuacEuacEuacConstraints, InstName.FcmgeAdvsimdRegV, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x7EF8C800, 0xFFFFFC00, InstName.FcmgeAdvsimdZeroSH, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x7EA0C800, 0xFFBFFC00, InstName.FcmgeAdvsimdZeroS, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x2EF8C800, 0xBFFFFC00, InstName.FcmgeAdvsimdZeroVH, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x2EA0C800, 0xBFBFFC00, qszConstraints, InstName.FcmgeAdvsimdZeroV, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x7EC02400, 0xFFE0FC00, euacEuacEuacConstraints, InstName.FcmgtAdvsimdRegSH, IsaVersion.v82, InstFlags.RdRnRmFpSimd), + new(0x7EA0E400, 0xFFA0FC00, euacEuacEuacConstraints, InstName.FcmgtAdvsimdRegS, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x2EC02400, 0xBFE0FC00, euacEuacEuacConstraints, InstName.FcmgtAdvsimdRegVH, IsaVersion.v82, InstFlags.RdRnRmFpSimd), + new(0x2EA0E400, 0xBFA0FC00, qszEuacEuacEuacConstraints, InstName.FcmgtAdvsimdRegV, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x5EF8C800, 0xFFFFFC00, InstName.FcmgtAdvsimdZeroSH, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x5EA0C800, 0xFFBFFC00, InstName.FcmgtAdvsimdZeroS, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x0EF8C800, 0xBFFFFC00, InstName.FcmgtAdvsimdZeroVH, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x0EA0C800, 0xBFBFFC00, qszConstraints, InstName.FcmgtAdvsimdZeroV, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x2F801000, 0xBF809400, sizeSizeSizelSizeqSizehqConstraints, InstName.FcmlaAdvsimdElt, IsaVersion.v83, InstFlags.RdReadRdRnRmFpSimd), + new(0x2F401000, 0xBFC09400, sizeSizeSizelSizeqSizehqConstraints, InstName.FcmlaAdvsimdElt, IsaVersion.v83, InstFlags.RdReadRdRnRmFpSimd), + new(0x2E80C400, 0xBFA0E400, sizeQsizeConstraints, InstName.FcmlaAdvsimdVec, IsaVersion.v83, InstFlags.RdReadRdRnRmFpSimd), + new(0x2E40C400, 0xBFE0E400, sizeQsizeConstraints, InstName.FcmlaAdvsimdVec, IsaVersion.v83, InstFlags.RdReadRdRnRmFpSimd), + new(0x7EF8D800, 0xFFFFFC00, InstName.FcmleAdvsimdSH, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x7EA0D800, 0xFFBFFC00, InstName.FcmleAdvsimdS, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x2EF8D800, 0xBFFFFC00, InstName.FcmleAdvsimdVH, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x2EA0D800, 0xBFBFFC00, qszConstraints, InstName.FcmleAdvsimdV, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x5EF8E800, 0xFFFFFC00, InstName.FcmltAdvsimdSH, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x5EA0E800, 0xFFBFFC00, InstName.FcmltAdvsimdS, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x0EF8E800, 0xBFFFFC00, InstName.FcmltAdvsimdVH, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x0EA0E800, 0xBFBFFC00, qszConstraints, InstName.FcmltAdvsimdV, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x1E202010, 0xFFA0FC17, InstName.FcmpeFloat, IsaVersion.v80, InstFlags.RnRmSFpSimd), + new(0x1EE02010, 0xFFE0FC17, InstName.FcmpeFloat, IsaVersion.v80, InstFlags.RnRmSFpSimd), + new(0x1E202000, 0xFFA0FC17, InstName.FcmpFloat, IsaVersion.v80, InstFlags.RnRmSFpSimd), + new(0x1EE02000, 0xFFE0FC17, InstName.FcmpFloat, IsaVersion.v80, InstFlags.RnRmSFpSimd), + new(0x1E200C00, 0xFFA00C00, InstName.FcselFloat, IsaVersion.v80, InstFlags.RdRnRmNzcvFpSimd), + new(0x1EE00C00, 0xFFE00C00, InstName.FcselFloat, IsaVersion.v80, InstFlags.RdRnRmNzcvFpSimd), + new(0x5E79C800, 0xFFFFFC00, InstName.FcvtasAdvsimdSH, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x5E21C800, 0xFFBFFC00, InstName.FcvtasAdvsimdS, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x0E79C800, 0xBFFFFC00, InstName.FcvtasAdvsimdVH, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x0E21C800, 0xBFBFFC00, qszConstraints, InstName.FcvtasAdvsimdV, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x1E240000, 0x7FBFFC00, InstName.FcvtasFloat, IsaVersion.v80, InstFlags.RdRnFpSimdToGpr), + new(0x1EE40000, 0x7FFFFC00, InstName.FcvtasFloat, IsaVersion.v80, InstFlags.RdRnFpSimdToGpr), + new(0x7E79C800, 0xFFFFFC00, InstName.FcvtauAdvsimdSH, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x7E21C800, 0xFFBFFC00, InstName.FcvtauAdvsimdS, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x2E79C800, 0xBFFFFC00, InstName.FcvtauAdvsimdVH, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x2E21C800, 0xBFBFFC00, qszConstraints, InstName.FcvtauAdvsimdV, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x1E250000, 0x7FBFFC00, InstName.FcvtauFloat, IsaVersion.v80, InstFlags.RdRnFpSimdToGpr), + new(0x1EE50000, 0x7FFFFC00, InstName.FcvtauFloat, IsaVersion.v80, InstFlags.RdRnFpSimdToGpr), + new(0x0E217800, 0xBFBFFC00, InstName.FcvtlAdvsimd, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x5E79B800, 0xFFFFFC00, InstName.FcvtmsAdvsimdSH, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x5E21B800, 0xFFBFFC00, InstName.FcvtmsAdvsimdS, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x0E79B800, 0xBFFFFC00, InstName.FcvtmsAdvsimdVH, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x0E21B800, 0xBFBFFC00, qszConstraints, InstName.FcvtmsAdvsimdV, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x1E300000, 0x7FBFFC00, InstName.FcvtmsFloat, IsaVersion.v80, InstFlags.RdRnFpSimdToGpr), + new(0x1EF00000, 0x7FFFFC00, InstName.FcvtmsFloat, IsaVersion.v80, InstFlags.RdRnFpSimdToGpr), + new(0x7E79B800, 0xFFFFFC00, InstName.FcvtmuAdvsimdSH, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x7E21B800, 0xFFBFFC00, InstName.FcvtmuAdvsimdS, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x2E79B800, 0xBFFFFC00, InstName.FcvtmuAdvsimdVH, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x2E21B800, 0xBFBFFC00, qszConstraints, InstName.FcvtmuAdvsimdV, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x1E310000, 0x7FBFFC00, InstName.FcvtmuFloat, IsaVersion.v80, InstFlags.RdRnFpSimdToGpr), + new(0x1EF10000, 0x7FFFFC00, InstName.FcvtmuFloat, IsaVersion.v80, InstFlags.RdRnFpSimdToGpr), + new(0x5E79A800, 0xFFFFFC00, InstName.FcvtnsAdvsimdSH, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x5E21A800, 0xFFBFFC00, InstName.FcvtnsAdvsimdS, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x0E79A800, 0xBFFFFC00, InstName.FcvtnsAdvsimdVH, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x0E21A800, 0xBFBFFC00, qszConstraints, InstName.FcvtnsAdvsimdV, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x1E200000, 0x7FBFFC00, InstName.FcvtnsFloat, IsaVersion.v80, InstFlags.RdRnFpSimdToGpr), + new(0x1EE00000, 0x7FFFFC00, InstName.FcvtnsFloat, IsaVersion.v80, InstFlags.RdRnFpSimdToGpr), + new(0x7E79A800, 0xFFFFFC00, InstName.FcvtnuAdvsimdSH, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x7E21A800, 0xFFBFFC00, InstName.FcvtnuAdvsimdS, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x2E79A800, 0xBFFFFC00, InstName.FcvtnuAdvsimdVH, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x2E21A800, 0xBFBFFC00, qszConstraints, InstName.FcvtnuAdvsimdV, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x1E210000, 0x7FBFFC00, InstName.FcvtnuFloat, IsaVersion.v80, InstFlags.RdRnFpSimdToGpr), + new(0x1EE10000, 0x7FFFFC00, InstName.FcvtnuFloat, IsaVersion.v80, InstFlags.RdRnFpSimdToGpr), + new(0x0E216800, 0xBFBFFC00, InstName.FcvtnAdvsimd, IsaVersion.v80, InstFlags.RdReadRdRnFpSimd), + new(0x5EF9A800, 0xFFFFFC00, InstName.FcvtpsAdvsimdSH, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x5EA1A800, 0xFFBFFC00, InstName.FcvtpsAdvsimdS, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x0EF9A800, 0xBFFFFC00, InstName.FcvtpsAdvsimdVH, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x0EA1A800, 0xBFBFFC00, qszConstraints, InstName.FcvtpsAdvsimdV, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x1E280000, 0x7FBFFC00, InstName.FcvtpsFloat, IsaVersion.v80, InstFlags.RdRnFpSimdToGpr), + new(0x1EE80000, 0x7FFFFC00, InstName.FcvtpsFloat, IsaVersion.v80, InstFlags.RdRnFpSimdToGpr), + new(0x7EF9A800, 0xFFFFFC00, InstName.FcvtpuAdvsimdSH, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x7EA1A800, 0xFFBFFC00, InstName.FcvtpuAdvsimdS, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x2EF9A800, 0xBFFFFC00, InstName.FcvtpuAdvsimdVH, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x2EA1A800, 0xBFBFFC00, qszConstraints, InstName.FcvtpuAdvsimdV, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x1E290000, 0x7FBFFC00, InstName.FcvtpuFloat, IsaVersion.v80, InstFlags.RdRnFpSimdToGpr), + new(0x1EE90000, 0x7FFFFC00, InstName.FcvtpuFloat, IsaVersion.v80, InstFlags.RdRnFpSimdToGpr), + new(0x7E216800, 0xFFBFFC00, szConstraints2, InstName.FcvtxnAdvsimdS, IsaVersion.v80, InstFlags.RdReadRdRnFpSimd), + new(0x2E216800, 0xBFBFFC00, szConstraints2, InstName.FcvtxnAdvsimdV, IsaVersion.v80, InstFlags.RdReadRdRnFpSimd), + new(0x5F40FC00, 0xFFC0FC00, immhConstraints, InstName.FcvtzsAdvsimdFixS, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x5F10FC00, 0xFFF0FC00, immhConstraints, InstName.FcvtzsAdvsimdFixS, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x5F20FC00, 0xFFE0FC00, immhConstraints, InstName.FcvtzsAdvsimdFixS, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x0F40FC00, 0xBFC0FC00, immhQimmhConstraints, InstName.FcvtzsAdvsimdFixV, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x0F10FC00, 0xBFF0FC00, immhQimmhConstraints, InstName.FcvtzsAdvsimdFixV, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x0F20FC00, 0xBFE0FC00, immhQimmhConstraints, InstName.FcvtzsAdvsimdFixV, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x5EF9B800, 0xFFFFFC00, InstName.FcvtzsAdvsimdIntSH, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x5EA1B800, 0xFFBFFC00, InstName.FcvtzsAdvsimdIntS, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x0EF9B800, 0xBFFFFC00, InstName.FcvtzsAdvsimdIntVH, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x0EA1B800, 0xBFBFFC00, qszConstraints, InstName.FcvtzsAdvsimdIntV, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x1E180000, 0x7FBF0000, sfscaleConstraints, InstName.FcvtzsFloatFix, IsaVersion.v80, InstFlags.RdRnFpSimdToGpr), + new(0x1ED80000, 0x7FFF0000, sfscaleConstraints, InstName.FcvtzsFloatFix, IsaVersion.v80, InstFlags.RdRnFpSimdToGpr), + new(0x1E380000, 0x7FBFFC00, InstName.FcvtzsFloatInt, IsaVersion.v80, InstFlags.RdRnFpSimdToGpr), + new(0x1EF80000, 0x7FFFFC00, InstName.FcvtzsFloatInt, IsaVersion.v80, InstFlags.RdRnFpSimdToGpr), + new(0x7F40FC00, 0xFFC0FC00, immhConstraints, InstName.FcvtzuAdvsimdFixS, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x7F10FC00, 0xFFF0FC00, immhConstraints, InstName.FcvtzuAdvsimdFixS, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x7F20FC00, 0xFFE0FC00, immhConstraints, InstName.FcvtzuAdvsimdFixS, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x2F40FC00, 0xBFC0FC00, immhQimmhConstraints, InstName.FcvtzuAdvsimdFixV, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x2F10FC00, 0xBFF0FC00, immhQimmhConstraints, InstName.FcvtzuAdvsimdFixV, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x2F20FC00, 0xBFE0FC00, immhQimmhConstraints, InstName.FcvtzuAdvsimdFixV, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x7EF9B800, 0xFFFFFC00, InstName.FcvtzuAdvsimdIntSH, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x7EA1B800, 0xFFBFFC00, InstName.FcvtzuAdvsimdIntS, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x2EF9B800, 0xBFFFFC00, InstName.FcvtzuAdvsimdIntVH, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x2EA1B800, 0xBFBFFC00, qszConstraints, InstName.FcvtzuAdvsimdIntV, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x1E190000, 0x7FBF0000, sfscaleConstraints, InstName.FcvtzuFloatFix, IsaVersion.v80, InstFlags.RdRnFpSimdToGpr), + new(0x1ED90000, 0x7FFF0000, sfscaleConstraints, InstName.FcvtzuFloatFix, IsaVersion.v80, InstFlags.RdRnFpSimdToGpr), + new(0x1E390000, 0x7FBFFC00, InstName.FcvtzuFloatInt, IsaVersion.v80, InstFlags.RdRnFpSimdToGpr), + new(0x1EF90000, 0x7FFFFC00, InstName.FcvtzuFloatInt, IsaVersion.v80, InstFlags.RdRnFpSimdToGpr), + new(0x1E224000, 0xFF3E7C00, ftypeopcFtypeopcFtypeopcFtypeopcFtypeOpcConstraints, InstName.FcvtFloat, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x2E403C00, 0xBFE0FC00, InstName.FdivAdvsimdHalf, IsaVersion.v82, InstFlags.RdRnRmFpSimd), + new(0x2E20FC00, 0xBFA0FC00, qszConstraints, InstName.FdivAdvsimdSingleAndDouble, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x1E201800, 0xFFA0FC00, InstName.FdivFloat, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x1EE01800, 0xFFE0FC00, InstName.FdivFloat, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x1E7E0000, 0xFFFFFC00, InstName.Fjcvtzs, IsaVersion.v83, InstFlags.RdRnSFpSimd), + new(0x1F000000, 0xFFA08000, InstName.FmaddFloat, IsaVersion.v80, InstFlags.RdRnRmRaFpSimd), + new(0x1FC00000, 0xFFE08000, InstName.FmaddFloat, IsaVersion.v80, InstFlags.RdRnRmRaFpSimd), + new(0x5E30C800, 0xFFBFFC00, szConstraints, InstName.FmaxnmpAdvsimdPairHalf, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x7E30C800, 0xFFBFFC00, InstName.FmaxnmpAdvsimdPairSingleAndDouble, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x2E400400, 0xBFE0FC00, InstName.FmaxnmpAdvsimdVecHalf, IsaVersion.v82, InstFlags.RdRnRmFpSimd), + new(0x2E20C400, 0xBFA0FC00, qszConstraints, InstName.FmaxnmpAdvsimdVecSingleAndDouble, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x0E30C800, 0xBFFFFC00, InstName.FmaxnmvAdvsimdHalf, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x6E30C800, 0xFFFFFC00, InstName.FmaxnmvAdvsimdSingleAndDouble, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x0E400400, 0xBFE0FC00, InstName.FmaxnmAdvsimdHalf, IsaVersion.v82, InstFlags.RdRnRmFpSimd), + new(0x0E20C400, 0xBFA0FC00, qszConstraints, InstName.FmaxnmAdvsimdSingleAndDouble, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x1E206800, 0xFFA0FC00, InstName.FmaxnmFloat, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x1EE06800, 0xFFE0FC00, InstName.FmaxnmFloat, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x5E30F800, 0xFFBFFC00, szConstraints, InstName.FmaxpAdvsimdPairHalf, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x7E30F800, 0xFFBFFC00, InstName.FmaxpAdvsimdPairSingleAndDouble, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x2E403400, 0xBFE0FC00, InstName.FmaxpAdvsimdVecHalf, IsaVersion.v82, InstFlags.RdRnRmFpSimd), + new(0x2E20F400, 0xBFA0FC00, qszConstraints, InstName.FmaxpAdvsimdVecSingleAndDouble, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x0E30F800, 0xBFFFFC00, InstName.FmaxvAdvsimdHalf, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x6E30F800, 0xFFFFFC00, InstName.FmaxvAdvsimdSingleAndDouble, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x0E403400, 0xBFE0FC00, InstName.FmaxAdvsimdHalf, IsaVersion.v82, InstFlags.RdRnRmFpSimd), + new(0x0E20F400, 0xBFA0FC00, qszConstraints, InstName.FmaxAdvsimdSingleAndDouble, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x1E204800, 0xFFA0FC00, InstName.FmaxFloat, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x1EE04800, 0xFFE0FC00, InstName.FmaxFloat, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x5EB0C800, 0xFFBFFC00, szConstraints, InstName.FminnmpAdvsimdPairHalf, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x7EB0C800, 0xFFBFFC00, InstName.FminnmpAdvsimdPairSingleAndDouble, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x2EC00400, 0xBFE0FC00, InstName.FminnmpAdvsimdVecHalf, IsaVersion.v82, InstFlags.RdRnRmFpSimd), + new(0x2EA0C400, 0xBFA0FC00, qszConstraints, InstName.FminnmpAdvsimdVecSingleAndDouble, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x0EB0C800, 0xBFFFFC00, InstName.FminnmvAdvsimdHalf, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x6EB0C800, 0xFFFFFC00, InstName.FminnmvAdvsimdSingleAndDouble, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x0EC00400, 0xBFE0FC00, InstName.FminnmAdvsimdHalf, IsaVersion.v82, InstFlags.RdRnRmFpSimd), + new(0x0EA0C400, 0xBFA0FC00, qszConstraints, InstName.FminnmAdvsimdSingleAndDouble, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x1E207800, 0xFFA0FC00, InstName.FminnmFloat, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x1EE07800, 0xFFE0FC00, InstName.FminnmFloat, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x5EB0F800, 0xFFBFFC00, szConstraints, InstName.FminpAdvsimdPairHalf, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x7EB0F800, 0xFFBFFC00, InstName.FminpAdvsimdPairSingleAndDouble, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x2EC03400, 0xBFE0FC00, InstName.FminpAdvsimdVecHalf, IsaVersion.v82, InstFlags.RdRnRmFpSimd), + new(0x2EA0F400, 0xBFA0FC00, qszConstraints, InstName.FminpAdvsimdVecSingleAndDouble, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x0EB0F800, 0xBFFFFC00, InstName.FminvAdvsimdHalf, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x6EB0F800, 0xFFFFFC00, InstName.FminvAdvsimdSingleAndDouble, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x0EC03400, 0xBFE0FC00, InstName.FminAdvsimdHalf, IsaVersion.v82, InstFlags.RdRnRmFpSimd), + new(0x0EA0F400, 0xBFA0FC00, qszConstraints, InstName.FminAdvsimdSingleAndDouble, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x1E205800, 0xFFA0FC00, InstName.FminFloat, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x1EE05800, 0xFFE0FC00, InstName.FminFloat, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x0F800000, 0xBFC0F400, szConstraints, InstName.FmlalAdvsimdEltFmlal, IsaVersion.v82, InstFlags.RdReadRdRnRmFpSimd), + new(0x2F808000, 0xBFC0F400, szConstraints, InstName.FmlalAdvsimdEltFmlal2, IsaVersion.v82, InstFlags.RdReadRdRnRmFpSimd), + new(0x0E20EC00, 0xBFE0FC00, szConstraints, InstName.FmlalAdvsimdVecFmlal, IsaVersion.v82, InstFlags.RdReadRdRnRmFpSimd), + new(0x2E20CC00, 0xBFE0FC00, szConstraints, InstName.FmlalAdvsimdVecFmlal2, IsaVersion.v82, InstFlags.RdReadRdRnRmFpSimd), + new(0x5F001000, 0xFFC0F400, InstName.FmlaAdvsimdElt2regScalarHalf, IsaVersion.v82, InstFlags.RdReadRdRnRmFpSimd), + new(0x5F801000, 0xFF80F400, szlConstraints, InstName.FmlaAdvsimdElt2regScalarSingleAndDouble, IsaVersion.v80, InstFlags.RdReadRdRnRmFpSimd), + new(0x0F001000, 0xBFC0F400, InstName.FmlaAdvsimdElt2regElementHalf, IsaVersion.v82, InstFlags.RdReadRdRnRmFpSimd), + new(0x0F801000, 0xBF80F400, szlQszConstraints, InstName.FmlaAdvsimdElt2regElementSingleAndDouble, IsaVersion.v80, InstFlags.RdReadRdRnRmFpSimd), + new(0x0E400C00, 0xBFE0FC00, InstName.FmlaAdvsimdVecHalf, IsaVersion.v82, InstFlags.RdReadRdRnRmFpSimd), + new(0x0E20CC00, 0xBFA0FC00, qszConstraints, InstName.FmlaAdvsimdVecSingleAndDouble, IsaVersion.v80, InstFlags.RdReadRdRnRmFpSimd), + new(0x0F804000, 0xBFC0F400, szConstraints, InstName.FmlslAdvsimdEltFmlsl, IsaVersion.v82, InstFlags.RdReadRdRnRmFpSimd), + new(0x2F80C000, 0xBFC0F400, szConstraints, InstName.FmlslAdvsimdEltFmlsl2, IsaVersion.v82, InstFlags.RdReadRdRnRmFpSimd), + new(0x0EA0EC00, 0xBFE0FC00, szConstraints, InstName.FmlslAdvsimdVecFmlsl, IsaVersion.v82, InstFlags.RdReadRdRnRmFpSimd), + new(0x2EA0CC00, 0xBFE0FC00, szConstraints, InstName.FmlslAdvsimdVecFmlsl2, IsaVersion.v82, InstFlags.RdReadRdRnRmFpSimd), + new(0x5F005000, 0xFFC0F400, InstName.FmlsAdvsimdElt2regScalarHalf, IsaVersion.v82, InstFlags.RdReadRdRnRmFpSimd), + new(0x5F805000, 0xFF80F400, szlConstraints, InstName.FmlsAdvsimdElt2regScalarSingleAndDouble, IsaVersion.v80, InstFlags.RdReadRdRnRmFpSimd), + new(0x0F005000, 0xBFC0F400, InstName.FmlsAdvsimdElt2regElementHalf, IsaVersion.v82, InstFlags.RdReadRdRnRmFpSimd), + new(0x0F805000, 0xBF80F400, szlQszConstraints, InstName.FmlsAdvsimdElt2regElementSingleAndDouble, IsaVersion.v80, InstFlags.RdReadRdRnRmFpSimd), + new(0x0EC00C00, 0xBFE0FC00, InstName.FmlsAdvsimdVecHalf, IsaVersion.v82, InstFlags.RdReadRdRnRmFpSimd), + new(0x0EA0CC00, 0xBFA0FC00, qszConstraints, InstName.FmlsAdvsimdVecSingleAndDouble, IsaVersion.v80, InstFlags.RdReadRdRnRmFpSimd), + new(0x0F00FC00, 0xBFF8FC00, InstName.FmovAdvsimdPerHalf, IsaVersion.v82, InstFlags.RdFpSimd), + new(0x0F00F400, 0x9FF8FC00, qConstraints, InstName.FmovAdvsimdSingleAndDouble, IsaVersion.v80, InstFlags.RdFpSimd), + new(0x1E204000, 0xFFBFFC00, InstName.FmovFloat, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x1EE04000, 0xFFFFFC00, InstName.FmovFloat, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x1E260000, 0xFFFEFC00, sfftypermodeSfftypermodeConstraints, InstName.FmovFloatGen, IsaVersion.v80, InstFlags.RdRnSFpSimdFromToGpr), + new(0x9E660000, 0xFFFEFC00, sfftypermodeSfftypermodeConstraints, InstName.FmovFloatGen, IsaVersion.v80, InstFlags.RdRnSFpSimdFromToGpr), + new(0x9EAE0000, 0xFFFEFC00, sfftypermodeSfftypermodeConstraints, InstName.FmovFloatGen, IsaVersion.v80, InstFlags.RdRnSFpSimdFromToGpr), + new(0x1EE60000, 0x7FFEFC00, sfftypermodeSfftypermodeConstraints, InstName.FmovFloatGen, IsaVersion.v80, InstFlags.RdRnSFpSimdFromToGpr), + new(0x1E201000, 0xFFA01FE0, InstName.FmovFloatImm, IsaVersion.v80, InstFlags.RdFpSimd), + new(0x1EE01000, 0xFFE01FE0, InstName.FmovFloatImm, IsaVersion.v80, InstFlags.RdFpSimd), + new(0x1F008000, 0xFFA08000, InstName.FmsubFloat, IsaVersion.v80, InstFlags.RdRnRmRaFpSimd), + new(0x1FC08000, 0xFFE08000, InstName.FmsubFloat, IsaVersion.v80, InstFlags.RdRnRmRaFpSimd), + new(0x7F009000, 0xFFC0F400, InstName.FmulxAdvsimdElt2regScalarHalf, IsaVersion.v82, InstFlags.RdRnRmFpSimd), + new(0x7F809000, 0xFF80F400, szlConstraints, InstName.FmulxAdvsimdElt2regScalarSingleAndDouble, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x2F009000, 0xBFC0F400, InstName.FmulxAdvsimdElt2regElementHalf, IsaVersion.v82, InstFlags.RdRnRmFpSimd), + new(0x2F809000, 0xBF80F400, szlQszConstraints, InstName.FmulxAdvsimdElt2regElementSingleAndDouble, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x5E401C00, 0xFFE0FC00, InstName.FmulxAdvsimdVecSH, IsaVersion.v82, InstFlags.RdRnRmFpSimd), + new(0x5E20DC00, 0xFFA0FC00, InstName.FmulxAdvsimdVecS, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x0E401C00, 0xBFE0FC00, InstName.FmulxAdvsimdVecVH, IsaVersion.v82, InstFlags.RdRnRmFpSimd), + new(0x0E20DC00, 0xBFA0FC00, qszConstraints, InstName.FmulxAdvsimdVecV, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x5F009000, 0xFFC0F400, InstName.FmulAdvsimdElt2regScalarHalf, IsaVersion.v82, InstFlags.RdRnRmFpSimd), + new(0x5F809000, 0xFF80F400, szlConstraints, InstName.FmulAdvsimdElt2regScalarSingleAndDouble, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x0F009000, 0xBFC0F400, InstName.FmulAdvsimdElt2regElementHalf, IsaVersion.v82, InstFlags.RdRnRmFpSimd), + new(0x0F809000, 0xBF80F400, szlQszConstraints, InstName.FmulAdvsimdElt2regElementSingleAndDouble, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x2E401C00, 0xBFE0FC00, InstName.FmulAdvsimdVecHalf, IsaVersion.v82, InstFlags.RdRnRmFpSimd), + new(0x2E20DC00, 0xBFA0FC00, qszConstraints, InstName.FmulAdvsimdVecSingleAndDouble, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x1E200800, 0xFFA0FC00, InstName.FmulFloat, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x1EE00800, 0xFFE0FC00, InstName.FmulFloat, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x2EF8F800, 0xBFFFFC00, InstName.FnegAdvsimdHalf, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x2EA0F800, 0xBFBFFC00, qszConstraints, InstName.FnegAdvsimdSingleAndDouble, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x1E214000, 0xFFBFFC00, InstName.FnegFloat, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x1EE14000, 0xFFFFFC00, InstName.FnegFloat, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x1F200000, 0xFFA08000, InstName.FnmaddFloat, IsaVersion.v80, InstFlags.RdRnRmRaFpSimd), + new(0x1FE00000, 0xFFE08000, InstName.FnmaddFloat, IsaVersion.v80, InstFlags.RdRnRmRaFpSimd), + new(0x1F208000, 0xFFA08000, InstName.FnmsubFloat, IsaVersion.v80, InstFlags.RdRnRmRaFpSimd), + new(0x1FE08000, 0xFFE08000, InstName.FnmsubFloat, IsaVersion.v80, InstFlags.RdRnRmRaFpSimd), + new(0x1E208800, 0xFFA0FC00, InstName.FnmulFloat, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x1EE08800, 0xFFE0FC00, InstName.FnmulFloat, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x5EF9D800, 0xFFFFFC00, InstName.FrecpeAdvsimdSH, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x5EA1D800, 0xFFBFFC00, InstName.FrecpeAdvsimdS, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x0EF9D800, 0xBFFFFC00, InstName.FrecpeAdvsimdVH, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x0EA1D800, 0xBFBFFC00, qszConstraints, InstName.FrecpeAdvsimdV, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x5E403C00, 0xFFE0FC00, InstName.FrecpsAdvsimdSH, IsaVersion.v82, InstFlags.RdRnRmFpSimd), + new(0x5E20FC00, 0xFFA0FC00, InstName.FrecpsAdvsimdS, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x0E403C00, 0xBFE0FC00, InstName.FrecpsAdvsimdVH, IsaVersion.v82, InstFlags.RdRnRmFpSimd), + new(0x0E20FC00, 0xBFA0FC00, qszConstraints, InstName.FrecpsAdvsimdV, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x5EF9F800, 0xFFFFFC00, InstName.FrecpxAdvsimdHalf, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x5EA1F800, 0xFFBFFC00, InstName.FrecpxAdvsimdSingleAndDouble, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x2E21E800, 0xBFBFFC00, qszConstraints, InstName.Frint32xAdvsimd, IsaVersion.v85, InstFlags.RdRnFpSimd), + new(0x1E28C000, 0xFFBFFC00, InstName.Frint32xFloat, IsaVersion.v85, InstFlags.RdRnFpSimd), + new(0x0E21E800, 0xBFBFFC00, qszConstraints, InstName.Frint32zAdvsimd, IsaVersion.v85, InstFlags.RdRnFpSimd), + new(0x1E284000, 0xFFBFFC00, InstName.Frint32zFloat, IsaVersion.v85, InstFlags.RdRnFpSimd), + new(0x2E21F800, 0xBFBFFC00, qszConstraints, InstName.Frint64xAdvsimd, IsaVersion.v85, InstFlags.RdRnFpSimd), + new(0x1E29C000, 0xFFBFFC00, InstName.Frint64xFloat, IsaVersion.v85, InstFlags.RdRnFpSimd), + new(0x0E21F800, 0xBFBFFC00, qszConstraints, InstName.Frint64zAdvsimd, IsaVersion.v85, InstFlags.RdRnFpSimd), + new(0x1E294000, 0xFFBFFC00, InstName.Frint64zFloat, IsaVersion.v85, InstFlags.RdRnFpSimd), + new(0x2E798800, 0xBFFFFC00, uo1o2Constraints, InstName.FrintaAdvsimdHalf, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x2E218800, 0xBFBFFC00, qszUo1o2Constraints, InstName.FrintaAdvsimdSingleAndDouble, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x1E264000, 0xFFBFFC00, InstName.FrintaFloat, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x1EE64000, 0xFFFFFC00, InstName.FrintaFloat, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x2EF99800, 0xBFFFFC00, uo1o2Constraints, InstName.FrintiAdvsimdHalf, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x2EA19800, 0xBFBFFC00, qszUo1o2Constraints, InstName.FrintiAdvsimdSingleAndDouble, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x1E27C000, 0xFFBFFC00, InstName.FrintiFloat, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x1EE7C000, 0xFFFFFC00, InstName.FrintiFloat, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x0E799800, 0xBFFFFC00, uo1o2Constraints, InstName.FrintmAdvsimdHalf, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x0E219800, 0xBFBFFC00, qszUo1o2Constraints, InstName.FrintmAdvsimdSingleAndDouble, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x1E254000, 0xFFBFFC00, InstName.FrintmFloat, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x1EE54000, 0xFFFFFC00, InstName.FrintmFloat, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x0E798800, 0xBFFFFC00, uo1o2Constraints, InstName.FrintnAdvsimdHalf, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x0E218800, 0xBFBFFC00, qszUo1o2Constraints, InstName.FrintnAdvsimdSingleAndDouble, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x1E244000, 0xFFBFFC00, InstName.FrintnFloat, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x1EE44000, 0xFFFFFC00, InstName.FrintnFloat, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x0EF98800, 0xBFFFFC00, uo1o2Constraints, InstName.FrintpAdvsimdHalf, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x0EA18800, 0xBFBFFC00, qszUo1o2Constraints, InstName.FrintpAdvsimdSingleAndDouble, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x1E24C000, 0xFFBFFC00, InstName.FrintpFloat, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x1EE4C000, 0xFFFFFC00, InstName.FrintpFloat, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x2E799800, 0xBFFFFC00, uo1o2Constraints, InstName.FrintxAdvsimdHalf, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x2E219800, 0xBFBFFC00, qszUo1o2Constraints, InstName.FrintxAdvsimdSingleAndDouble, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x1E274000, 0xFFBFFC00, InstName.FrintxFloat, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x1EE74000, 0xFFFFFC00, InstName.FrintxFloat, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x0EF99800, 0xBFFFFC00, uo1o2Constraints, InstName.FrintzAdvsimdHalf, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x0EA19800, 0xBFBFFC00, qszUo1o2Constraints, InstName.FrintzAdvsimdSingleAndDouble, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x1E25C000, 0xFFBFFC00, InstName.FrintzFloat, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x1EE5C000, 0xFFFFFC00, InstName.FrintzFloat, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x7EF9D800, 0xFFFFFC00, InstName.FrsqrteAdvsimdSH, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x7EA1D800, 0xFFBFFC00, InstName.FrsqrteAdvsimdS, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x2EF9D800, 0xBFFFFC00, InstName.FrsqrteAdvsimdVH, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x2EA1D800, 0xBFBFFC00, qszConstraints, InstName.FrsqrteAdvsimdV, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x5EC03C00, 0xFFE0FC00, InstName.FrsqrtsAdvsimdSH, IsaVersion.v82, InstFlags.RdRnRmFpSimd), + new(0x5EA0FC00, 0xFFA0FC00, InstName.FrsqrtsAdvsimdS, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x0EC03C00, 0xBFE0FC00, InstName.FrsqrtsAdvsimdVH, IsaVersion.v82, InstFlags.RdRnRmFpSimd), + new(0x0EA0FC00, 0xBFA0FC00, qszConstraints, InstName.FrsqrtsAdvsimdV, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x2EF9F800, 0xBFFFFC00, InstName.FsqrtAdvsimdHalf, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x2EA1F800, 0xBFBFFC00, qszConstraints, InstName.FsqrtAdvsimdSingleAndDouble, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x1E21C000, 0xFFBFFC00, InstName.FsqrtFloat, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x1EE1C000, 0xFFFFFC00, InstName.FsqrtFloat, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x0EC01400, 0xBFE0FC00, InstName.FsubAdvsimdHalf, IsaVersion.v82, InstFlags.RdRnRmFpSimd), + new(0x0EA0D400, 0xBFA0FC00, qszConstraints, InstName.FsubAdvsimdSingleAndDouble, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x1E203800, 0xFFA0FC00, InstName.FsubFloat, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x1EE03800, 0xFFE0FC00, InstName.FsubFloat, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0xD503227F, 0xFFFFFFFF, InstName.Gcsb, IsaVersion.None, InstFlags.None), + new(0xD91F0C00, 0xFFFFFC00, InstName.Gcsstr, IsaVersion.None, InstFlags.RtReadRtRnSP), + new(0xD91F1C00, 0xFFFFFC00, InstName.Gcssttr, IsaVersion.None, InstFlags.RtReadRtRnSP), + new(0x9AC01400, 0xFFE0FC00, InstName.Gmi, IsaVersion.v85, InstFlags.None), + new(0xD503201F, 0xFFFFF01F, InstName.Hint, IsaVersion.v80, InstFlags.None), + new(0xD4400000, 0xFFE0001F, InstName.Hlt, IsaVersion.v80, InstFlags.None), + new(0xD4000002, 0xFFE0001F, InstName.Hvc, IsaVersion.v80, InstFlags.None), + new(0x6E000400, 0xFFE08400, imm5Constraints, InstName.InsAdvsimdElt, IsaVersion.v80, InstFlags.RdReadRdRnFpSimd), + new(0x4E001C00, 0xFFE0FC00, imm5Constraints, InstName.InsAdvsimdGen, IsaVersion.v80, InstFlags.RdReadRdRnFpSimdFromGpr), + new(0x9AC01000, 0xFFE0FC00, InstName.Irg, IsaVersion.v85, InstFlags.None), + new(0xD50330DF, 0xFFFFF0FF, InstName.Isb, IsaVersion.v80, InstFlags.None), + new(0x0D40C000, 0xBFFFF000, sConstraints, InstName.Ld1rAdvsimdAsNoPostIndex, IsaVersion.v80, InstFlags.RtRnSPFpSimd, AddressForm.StructNoOffset), + new(0x0DC0C000, 0xBFE0F000, sConstraints, InstName.Ld1rAdvsimdAsPostIndex, IsaVersion.v80, InstFlags.RtRnSPRmFpSimdMemWBack, AddressForm.StructPostIndexedReg), + new(0x0C402000, 0xBFFFF000, InstName.Ld1AdvsimdMultAsNoPostIndex, IsaVersion.v80, InstFlags.RtSeqRnSPFpSimd, AddressForm.StructNoOffset), + new(0x0C406000, 0xBFFFF000, InstName.Ld1AdvsimdMultAsNoPostIndex, IsaVersion.v80, InstFlags.RtSeqRnSPFpSimd, AddressForm.StructNoOffset), + new(0x0C407000, 0xBFFFF000, InstName.Ld1AdvsimdMultAsNoPostIndex, IsaVersion.v80, InstFlags.RtSeqRnSPFpSimd, AddressForm.StructNoOffset), + new(0x0C40A000, 0xBFFFF000, InstName.Ld1AdvsimdMultAsNoPostIndex, IsaVersion.v80, InstFlags.RtSeqRnSPFpSimd, AddressForm.StructNoOffset), + new(0x0C406000, 0xBFFFF000, InstName.Ld1AdvsimdMultAsNoPostIndex, IsaVersion.v80, InstFlags.RtSeqRnSPFpSimd, AddressForm.StructNoOffset), + new(0x0C407000, 0xBFFFF000, InstName.Ld1AdvsimdMultAsNoPostIndex, IsaVersion.v80, InstFlags.RtSeqRnSPFpSimd, AddressForm.StructNoOffset), + new(0x0C40A000, 0xBFFFF000, InstName.Ld1AdvsimdMultAsNoPostIndex, IsaVersion.v80, InstFlags.RtSeqRnSPFpSimd, AddressForm.StructNoOffset), + new(0x0CC02000, 0xBFE0F000, InstName.Ld1AdvsimdMultAsPostIndex, IsaVersion.v80, InstFlags.RtSeqRnSPRmFpSimdMemWBack, AddressForm.StructPostIndexedReg), + new(0x0CC06000, 0xBFE0F000, InstName.Ld1AdvsimdMultAsPostIndex, IsaVersion.v80, InstFlags.RtSeqRnSPRmFpSimdMemWBack, AddressForm.StructPostIndexedReg), + new(0x0CC07000, 0xBFE0F000, InstName.Ld1AdvsimdMultAsPostIndex, IsaVersion.v80, InstFlags.RtSeqRnSPRmFpSimdMemWBack, AddressForm.StructPostIndexedReg), + new(0x0CC0A000, 0xBFE0F000, InstName.Ld1AdvsimdMultAsPostIndex, IsaVersion.v80, InstFlags.RtSeqRnSPRmFpSimdMemWBack, AddressForm.StructPostIndexedReg), + new(0x0CC06000, 0xBFE0F000, InstName.Ld1AdvsimdMultAsPostIndex, IsaVersion.v80, InstFlags.RtSeqRnSPRmFpSimdMemWBack, AddressForm.StructPostIndexedReg), + new(0x0CC07000, 0xBFE0F000, InstName.Ld1AdvsimdMultAsPostIndex, IsaVersion.v80, InstFlags.RtSeqRnSPRmFpSimdMemWBack, AddressForm.StructPostIndexedReg), + new(0x0CC0A000, 0xBFE0F000, InstName.Ld1AdvsimdMultAsPostIndex, IsaVersion.v80, InstFlags.RtSeqRnSPRmFpSimdMemWBack, AddressForm.StructPostIndexedReg), + new(0x0D400000, 0xBFFF2000, opcodesizeOpcodesizeOpcodesizesOpcodesizeConstraints, InstName.Ld1AdvsimdSnglAsNoPostIndex, IsaVersion.v80, InstFlags.RtReadRtRnSPFpSimd, AddressForm.StructNoOffset), + new(0x0DC00000, 0xBFE02000, opcodesizeOpcodesizeOpcodesizesOpcodesizeConstraints, InstName.Ld1AdvsimdSnglAsPostIndex, IsaVersion.v80, InstFlags.RtReadRtRnSPRmFpSimdMemWBack, AddressForm.StructPostIndexedReg), + new(0x0D60C000, 0xBFFFF000, sConstraints, InstName.Ld2rAdvsimdAsNoPostIndex, IsaVersion.v80, InstFlags.RtSeqRnSPFpSimd, AddressForm.StructNoOffset), + new(0x0DE0C000, 0xBFE0F000, sConstraints, InstName.Ld2rAdvsimdAsPostIndex, IsaVersion.v80, InstFlags.RtSeqRnSPRmFpSimdMemWBack, AddressForm.StructPostIndexedReg), + new(0x0C408000, 0xBFFFF000, qsizeConstraints2, InstName.Ld2AdvsimdMultAsNoPostIndex, IsaVersion.v80, InstFlags.RtSeqRnSPFpSimd, AddressForm.StructNoOffset), + new(0x0CC08000, 0xBFE0F000, qsizeConstraints2, InstName.Ld2AdvsimdMultAsPostIndex, IsaVersion.v80, InstFlags.RtSeqRnSPRmFpSimdMemWBack, AddressForm.StructPostIndexedReg), + new(0x0D600000, 0xBFFF2000, opcodesizeOpcodesizeOpcodesizesOpcodesizeConstraints, InstName.Ld2AdvsimdSnglAsNoPostIndex, IsaVersion.v80, InstFlags.RtSeqReadRtRnSPFpSimd, AddressForm.StructNoOffset), + new(0x0DE00000, 0xBFE02000, opcodesizeOpcodesizeOpcodesizesOpcodesizeConstraints, InstName.Ld2AdvsimdSnglAsPostIndex, IsaVersion.v80, InstFlags.RtSeqReadRtRnSPRmFpSimdMemWBack, AddressForm.StructPostIndexedReg), + new(0x0D40E000, 0xBFFFF000, sConstraints, InstName.Ld3rAdvsimdAsNoPostIndex, IsaVersion.v80, InstFlags.RtSeqRnSPFpSimd, AddressForm.StructNoOffset), + new(0x0DC0E000, 0xBFE0F000, sConstraints, InstName.Ld3rAdvsimdAsPostIndex, IsaVersion.v80, InstFlags.RtSeqRnSPRmFpSimdMemWBack, AddressForm.StructPostIndexedReg), + new(0x0C404000, 0xBFFFF000, qsizeConstraints2, InstName.Ld3AdvsimdMultAsNoPostIndex, IsaVersion.v80, InstFlags.RtSeqRnSPFpSimd, AddressForm.StructNoOffset), + new(0x0CC04000, 0xBFE0F000, qsizeConstraints2, InstName.Ld3AdvsimdMultAsPostIndex, IsaVersion.v80, InstFlags.RtSeqRnSPRmFpSimdMemWBack, AddressForm.StructPostIndexedReg), + new(0x0D402000, 0xBFFF2000, opcodesizeOpcodesizeOpcodesizesOpcodesizeConstraints, InstName.Ld3AdvsimdSnglAsNoPostIndex, IsaVersion.v80, InstFlags.RtSeqReadRtRnSPFpSimd, AddressForm.StructNoOffset), + new(0x0DC02000, 0xBFE02000, opcodesizeOpcodesizeOpcodesizesOpcodesizeConstraints, InstName.Ld3AdvsimdSnglAsPostIndex, IsaVersion.v80, InstFlags.RtSeqReadRtRnSPRmFpSimdMemWBack, AddressForm.StructPostIndexedReg), + new(0x0D60E000, 0xBFFFF000, sConstraints, InstName.Ld4rAdvsimdAsNoPostIndex, IsaVersion.v80, InstFlags.RtSeqRnSPFpSimd, AddressForm.StructNoOffset), + new(0x0DE0E000, 0xBFE0F000, sConstraints, InstName.Ld4rAdvsimdAsPostIndex, IsaVersion.v80, InstFlags.RtSeqRnSPRmFpSimdMemWBack, AddressForm.StructPostIndexedReg), + new(0x0C400000, 0xBFFFF000, qsizeConstraints2, InstName.Ld4AdvsimdMultAsNoPostIndex, IsaVersion.v80, InstFlags.RtSeqRnSPFpSimd, AddressForm.StructNoOffset), + new(0x0CC00000, 0xBFE0F000, qsizeConstraints2, InstName.Ld4AdvsimdMultAsPostIndex, IsaVersion.v80, InstFlags.RtSeqRnSPRmFpSimdMemWBack, AddressForm.StructPostIndexedReg), + new(0x0D602000, 0xBFFF2000, opcodesizeOpcodesizeOpcodesizesOpcodesizeConstraints, InstName.Ld4AdvsimdSnglAsNoPostIndex, IsaVersion.v80, InstFlags.RtSeqReadRtRnSPFpSimd, AddressForm.StructNoOffset), + new(0x0DE02000, 0xBFE02000, opcodesizeOpcodesizeOpcodesizesOpcodesizeConstraints, InstName.Ld4AdvsimdSnglAsPostIndex, IsaVersion.v80, InstFlags.RtSeqReadRtRnSPRmFpSimdMemWBack, AddressForm.StructPostIndexedReg), + new(0xF83FD000, 0xFFFFFC00, rtRtConstraints, InstName.Ld64b, IsaVersion.v87, InstFlags.RtRnSP), + new(0xB8200000, 0xBF20FC00, InstName.Ldadd, IsaVersion.v81, InstFlags.RtRnSPRs), + new(0x38200000, 0xFF20FC00, InstName.Ldaddb, IsaVersion.v81, InstFlags.RtRnSPRs), + new(0x78200000, 0xFF20FC00, InstName.Ldaddh, IsaVersion.v81, InstFlags.RtRnSPRs), + new(0x0D418400, 0xBFFFFC00, opcodesizeOpcodesizeOpcodesizesOpcodesizeConstraints, InstName.Ldap1AdvsimdSngl, IsaVersion.v82, InstFlags.RtReadRtRnSPFpSimd, AddressForm.StructNoOffset), + new(0xB8BFC000, 0xBFFFFC00, InstName.LdaprBaseRegister, IsaVersion.v83, InstFlags.RtRnSP, AddressForm.BaseRegister), + new(0x99C00800, 0xBFFFFC00, InstName.LdaprPostIndexed, IsaVersion.v82, InstFlags.RtRnSPMemWBack, AddressForm.PostIndexed), + new(0x38BFC000, 0xFFFFFC00, InstName.Ldaprb, IsaVersion.v83, InstFlags.RtRnSP), + new(0x78BFC000, 0xFFFFFC00, InstName.Ldaprh, IsaVersion.v83, InstFlags.RtRnSP), + new(0x19400000, 0xFFE00C00, InstName.Ldapurb, IsaVersion.v84, InstFlags.RtRnSP, AddressForm.BasePlusOffset), + new(0x59400000, 0xFFE00C00, InstName.Ldapurh, IsaVersion.v84, InstFlags.RtRnSP, AddressForm.BasePlusOffset), + new(0x19800000, 0xFFA00C00, InstName.Ldapursb, IsaVersion.v84, InstFlags.RtRnSP, AddressForm.BasePlusOffset), + new(0x59800000, 0xFFA00C00, InstName.Ldapursh, IsaVersion.v84, InstFlags.RtRnSP, AddressForm.BasePlusOffset), + new(0x99800000, 0xFFE00C00, InstName.Ldapursw, IsaVersion.v84, InstFlags.RtRnSP, AddressForm.BasePlusOffset), + new(0x1D400800, 0x3F600C00, opc1sizeOpc1sizeOpc1sizeConstraints, InstName.LdapurFpsimd, IsaVersion.v82, InstFlags.RtRnSPFpSimd, AddressForm.BasePlusOffset), + new(0x99400000, 0xBFE00C00, InstName.LdapurGen, IsaVersion.v84, InstFlags.RtRnSP, AddressForm.BasePlusOffset), + new(0x88DFFC00, 0xBFFFFC00, InstName.Ldar, IsaVersion.v80, InstFlags.RtRnSP, AddressForm.BaseRegister), + new(0x08DFFC00, 0xFFFFFC00, InstName.Ldarb, IsaVersion.v80, InstFlags.RtRnSP, AddressForm.BaseRegister), + new(0x48DFFC00, 0xFFFFFC00, InstName.Ldarh, IsaVersion.v80, InstFlags.RtRnSP, AddressForm.BaseRegister), + new(0x887F8000, 0xBFFF8000, InstName.Ldaxp, IsaVersion.v80, InstFlags.RtRt2RnSP, AddressForm.BaseRegister), + new(0x885FFC00, 0xBFFFFC00, InstName.Ldaxr, IsaVersion.v80, InstFlags.RtRnSP, AddressForm.BaseRegister), + new(0x085FFC00, 0xFFFFFC00, InstName.Ldaxrb, IsaVersion.v80, InstFlags.RtRnSP, AddressForm.BaseRegister), + new(0x485FFC00, 0xFFFFFC00, InstName.Ldaxrh, IsaVersion.v80, InstFlags.RtRnSP, AddressForm.BaseRegister), + new(0xB8201000, 0xBF20FC00, InstName.Ldclr, IsaVersion.v81, InstFlags.RtRnSPRs), + new(0x38201000, 0xFF20FC00, InstName.Ldclrb, IsaVersion.v81, InstFlags.RtRnSPRs), + new(0x78201000, 0xFF20FC00, InstName.Ldclrh, IsaVersion.v81, InstFlags.RtRnSPRs), + new(0x19201000, 0xFF20FC00, rtRt2Constraints, InstName.Ldclrp, IsaVersion.None, InstFlags.RtRt2RnSP), + new(0xB8202000, 0xBF20FC00, InstName.Ldeor, IsaVersion.v81, InstFlags.RtRnSPRs), + new(0x38202000, 0xFF20FC00, InstName.Ldeorb, IsaVersion.v81, InstFlags.RtRnSPRs), + new(0x78202000, 0xFF20FC00, InstName.Ldeorh, IsaVersion.v81, InstFlags.RtRnSPRs), + new(0xD9600000, 0xFFE00C00, InstName.Ldg, IsaVersion.v85, InstFlags.None), + new(0xD9E00000, 0xFFFFFC00, InstName.Ldgm, IsaVersion.v85, InstFlags.None), + new(0x99400800, 0xBFE0EC00, InstName.Ldiapp, IsaVersion.v82, InstFlags.RtRt2RnSP), + new(0x88DF7C00, 0xBFFFFC00, InstName.Ldlar, IsaVersion.v81, InstFlags.RtRnSP, AddressForm.BaseRegister), + new(0x08DF7C00, 0xFFFFFC00, InstName.Ldlarb, IsaVersion.v81, InstFlags.RtRnSP, AddressForm.BaseRegister), + new(0x48DF7C00, 0xFFFFFC00, InstName.Ldlarh, IsaVersion.v81, InstFlags.RtRnSP, AddressForm.BaseRegister), + new(0x2C400000, 0x3FC00000, opcConstraints, InstName.LdnpFpsimd, IsaVersion.v80, InstFlags.RtRt2RnSPFpSimd, AddressForm.SignedScaled), + new(0x28400000, 0x7FC00000, opcConstraints2, InstName.LdnpGen, IsaVersion.v80, InstFlags.RtRt2RnSP, AddressForm.SignedScaled), + new(0x68C00000, 0xFFC00000, InstName.LdpswPostIndexed, IsaVersion.v80, InstFlags.RtRt2RnSPMemWBack, AddressForm.PostIndexed), + new(0x69C00000, 0xFFC00000, InstName.LdpswPreIndexed, IsaVersion.v80, InstFlags.RtRt2RnSPMemWBack, AddressForm.PreIndexed), + new(0x69400000, 0xFFC00000, InstName.LdpswSignedScaledOffset, IsaVersion.v80, InstFlags.RtRt2RnSP, AddressForm.SignedScaled), + new(0x2CC00000, 0x3FC00000, opcConstraints, InstName.LdpFpsimdPostIndexed, IsaVersion.v80, InstFlags.RtRt2RnSPFpSimdMemWBack, AddressForm.PostIndexed), + new(0x2DC00000, 0x3FC00000, opcConstraints, InstName.LdpFpsimdPreIndexed, IsaVersion.v80, InstFlags.RtRt2RnSPFpSimdMemWBack, AddressForm.PreIndexed), + new(0x2D400000, 0x3FC00000, opcConstraints, InstName.LdpFpsimdSignedScaledOffset, IsaVersion.v80, InstFlags.RtRt2RnSPFpSimd, AddressForm.SignedScaled), + new(0x28C00000, 0x7FC00000, opclOpcConstraints, InstName.LdpGenPostIndexed, IsaVersion.v80, InstFlags.RtRt2RnSPMemWBack, AddressForm.PostIndexed), + new(0x29C00000, 0x7FC00000, opclOpcConstraints, InstName.LdpGenPreIndexed, IsaVersion.v80, InstFlags.RtRt2RnSPMemWBack, AddressForm.PreIndexed), + new(0x29400000, 0x7FC00000, opclOpcConstraints, InstName.LdpGenSignedScaledOffset, IsaVersion.v80, InstFlags.RtRt2RnSP, AddressForm.SignedScaled), + new(0xF8200400, 0xFF200400, InstName.Ldra, IsaVersion.v83, InstFlags.RtRnSP, AddressForm.BasePlusOffset), + new(0x38400400, 0xFFE00C00, InstName.LdrbImmPostIndexed, IsaVersion.v80, InstFlags.RtRnSPMemWBack, AddressForm.PostIndexed), + new(0x38400C00, 0xFFE00C00, InstName.LdrbImmPreIndexed, IsaVersion.v80, InstFlags.RtRnSPMemWBack, AddressForm.PreIndexed), + new(0x39400000, 0xFFC00000, InstName.LdrbImmUnsignedScaledOffset, IsaVersion.v80, InstFlags.RtRnSP, AddressForm.UnsignedScaled), + new(0x38600800, 0xFFE00C00, optionConstraints, InstName.LdrbReg, IsaVersion.v80, InstFlags.RtRnSPRm, AddressForm.OffsetReg), + new(0x78400400, 0xFFE00C00, InstName.LdrhImmPostIndexed, IsaVersion.v80, InstFlags.RtRnSPMemWBack, AddressForm.PostIndexed), + new(0x78400C00, 0xFFE00C00, InstName.LdrhImmPreIndexed, IsaVersion.v80, InstFlags.RtRnSPMemWBack, AddressForm.PreIndexed), + new(0x79400000, 0xFFC00000, InstName.LdrhImmUnsignedScaledOffset, IsaVersion.v80, InstFlags.RtRnSP, AddressForm.UnsignedScaled), + new(0x78600800, 0xFFE00C00, optionConstraints, InstName.LdrhReg, IsaVersion.v80, InstFlags.RtRnSPRm, AddressForm.OffsetReg), + new(0x38800400, 0xFFA00C00, InstName.LdrsbImmPostIndexed, IsaVersion.v80, InstFlags.RtRnSPMemWBack, AddressForm.PostIndexed), + new(0x38800C00, 0xFFA00C00, InstName.LdrsbImmPreIndexed, IsaVersion.v80, InstFlags.RtRnSPMemWBack, AddressForm.PreIndexed), + new(0x39800000, 0xFF800000, InstName.LdrsbImmUnsignedScaledOffset, IsaVersion.v80, InstFlags.RtRnSP, AddressForm.UnsignedScaled), + new(0x38A00800, 0xFFA00C00, optionConstraints, InstName.LdrsbReg, IsaVersion.v80, InstFlags.RtRnSPRm, AddressForm.OffsetReg), + new(0x78800400, 0xFFA00C00, InstName.LdrshImmPostIndexed, IsaVersion.v80, InstFlags.RtRnSPMemWBack, AddressForm.PostIndexed), + new(0x78800C00, 0xFFA00C00, InstName.LdrshImmPreIndexed, IsaVersion.v80, InstFlags.RtRnSPMemWBack, AddressForm.PreIndexed), + new(0x79800000, 0xFF800000, InstName.LdrshImmUnsignedScaledOffset, IsaVersion.v80, InstFlags.RtRnSP, AddressForm.UnsignedScaled), + new(0x78A00800, 0xFFA00C00, optionConstraints, InstName.LdrshReg, IsaVersion.v80, InstFlags.RtRnSPRm, AddressForm.OffsetReg), + new(0xB8800400, 0xFFE00C00, InstName.LdrswImmPostIndexed, IsaVersion.v80, InstFlags.RtRnSPMemWBack, AddressForm.PostIndexed), + new(0xB8800C00, 0xFFE00C00, InstName.LdrswImmPreIndexed, IsaVersion.v80, InstFlags.RtRnSPMemWBack, AddressForm.PreIndexed), + new(0xB9800000, 0xFFC00000, InstName.LdrswImmUnsignedScaledOffset, IsaVersion.v80, InstFlags.RtRnSP, AddressForm.UnsignedScaled), + new(0x98000000, 0xFF000000, InstName.LdrswLit, IsaVersion.v80, InstFlags.Rt, AddressForm.Literal), + new(0xB8A00800, 0xFFE00C00, optionConstraints, InstName.LdrswReg, IsaVersion.v80, InstFlags.RtRnSPRm, AddressForm.OffsetReg), + new(0x3C400400, 0x3F600C00, opc1sizeOpc1sizeOpc1sizeConstraints, InstName.LdrImmFpsimdPostIndexed, IsaVersion.v80, InstFlags.RtRnSPFpSimdMemWBack, AddressForm.PostIndexed), + new(0x3C400C00, 0x3F600C00, opc1sizeOpc1sizeOpc1sizeConstraints, InstName.LdrImmFpsimdPreIndexed, IsaVersion.v80, InstFlags.RtRnSPFpSimdMemWBack, AddressForm.PreIndexed), + new(0x3D400000, 0x3F400000, opc1sizeOpc1sizeOpc1sizeConstraints, InstName.LdrImmFpsimdUnsignedScaledOffset, IsaVersion.v80, InstFlags.RtRnSPFpSimd, AddressForm.UnsignedScaled), + new(0xB8400400, 0xBFE00C00, InstName.LdrImmGenPostIndexed, IsaVersion.v80, InstFlags.RtRnSPMemWBack, AddressForm.PostIndexed), + new(0xB8400C00, 0xBFE00C00, InstName.LdrImmGenPreIndexed, IsaVersion.v80, InstFlags.RtRnSPMemWBack, AddressForm.PreIndexed), + new(0xB9400000, 0xBFC00000, InstName.LdrImmGenUnsignedScaledOffset, IsaVersion.v80, InstFlags.RtRnSP, AddressForm.UnsignedScaled), + new(0x1C000000, 0x3F000000, opcConstraints, InstName.LdrLitFpsimd, IsaVersion.v80, InstFlags.RtFpSimd, AddressForm.Literal), + new(0x18000000, 0xBF000000, InstName.LdrLitGen, IsaVersion.v80, InstFlags.Rt, AddressForm.Literal), + new(0x3C600800, 0x3F600C00, opc1sizeOpc1sizeOpc1sizeOptionConstraints, InstName.LdrRegFpsimd, IsaVersion.v80, InstFlags.RtRnSPRmFpSimd, AddressForm.OffsetReg), + new(0xB8600800, 0xBFE00C00, optionConstraints, InstName.LdrRegGen, IsaVersion.v80, InstFlags.RtRnSPRm, AddressForm.OffsetReg), + new(0xB8203000, 0xBF20FC00, InstName.Ldset, IsaVersion.v81, InstFlags.RtRnSPRs), + new(0x38203000, 0xFF20FC00, InstName.Ldsetb, IsaVersion.v81, InstFlags.RtRnSPRs), + new(0x78203000, 0xFF20FC00, InstName.Ldseth, IsaVersion.v81, InstFlags.RtRnSPRs), + new(0x19203000, 0xFF20FC00, rtRt2Constraints, InstName.Ldsetp, IsaVersion.None, InstFlags.RtRt2RnSP), + new(0xB8204000, 0xBF20FC00, InstName.Ldsmax, IsaVersion.v81, InstFlags.RtRnSPRs), + new(0x38204000, 0xFF20FC00, InstName.Ldsmaxb, IsaVersion.v81, InstFlags.RtRnSPRs), + new(0x78204000, 0xFF20FC00, InstName.Ldsmaxh, IsaVersion.v81, InstFlags.RtRnSPRs), + new(0xB8205000, 0xBF20FC00, InstName.Ldsmin, IsaVersion.v81, InstFlags.RtRnSPRs), + new(0x38205000, 0xFF20FC00, InstName.Ldsminb, IsaVersion.v81, InstFlags.RtRnSPRs), + new(0x78205000, 0xFF20FC00, InstName.Ldsminh, IsaVersion.v81, InstFlags.RtRnSPRs), + new(0xB8400800, 0xBFE00C00, InstName.Ldtr, IsaVersion.v80, InstFlags.RtRnSP, AddressForm.BasePlusOffset), + new(0x38400800, 0xFFE00C00, InstName.Ldtrb, IsaVersion.v80, InstFlags.RtRnSP, AddressForm.BasePlusOffset), + new(0x78400800, 0xFFE00C00, InstName.Ldtrh, IsaVersion.v80, InstFlags.RtRnSP, AddressForm.BasePlusOffset), + new(0x38800800, 0xFFA00C00, InstName.Ldtrsb, IsaVersion.v80, InstFlags.RtRnSP, AddressForm.BasePlusOffset), + new(0x78800800, 0xFFA00C00, InstName.Ldtrsh, IsaVersion.v80, InstFlags.RtRnSP, AddressForm.BasePlusOffset), + new(0xB8800800, 0xFFE00C00, InstName.Ldtrsw, IsaVersion.v80, InstFlags.RtRnSP, AddressForm.BasePlusOffset), + new(0xB8206000, 0xBF20FC00, InstName.Ldumax, IsaVersion.v81, InstFlags.RtRnSPRs), + new(0x38206000, 0xFF20FC00, InstName.Ldumaxb, IsaVersion.v81, InstFlags.RtRnSPRs), + new(0x78206000, 0xFF20FC00, InstName.Ldumaxh, IsaVersion.v81, InstFlags.RtRnSPRs), + new(0xB8207000, 0xBF20FC00, InstName.Ldumin, IsaVersion.v81, InstFlags.RtRnSPRs), + new(0x38207000, 0xFF20FC00, InstName.Lduminb, IsaVersion.v81, InstFlags.RtRnSPRs), + new(0x78207000, 0xFF20FC00, InstName.Lduminh, IsaVersion.v81, InstFlags.RtRnSPRs), + new(0x38400000, 0xFFE00C00, InstName.Ldurb, IsaVersion.v80, InstFlags.RtRnSP, AddressForm.BasePlusOffset), + new(0x78400000, 0xFFE00C00, InstName.Ldurh, IsaVersion.v80, InstFlags.RtRnSP, AddressForm.BasePlusOffset), + new(0x38800000, 0xFFA00C00, InstName.Ldursb, IsaVersion.v80, InstFlags.RtRnSP, AddressForm.BasePlusOffset), + new(0x78800000, 0xFFA00C00, InstName.Ldursh, IsaVersion.v80, InstFlags.RtRnSP, AddressForm.BasePlusOffset), + new(0xB8800000, 0xFFE00C00, InstName.Ldursw, IsaVersion.v80, InstFlags.RtRnSP, AddressForm.BasePlusOffset), + new(0x3C400000, 0x3F600C00, opc1sizeOpc1sizeOpc1sizeConstraints, InstName.LdurFpsimd, IsaVersion.v80, InstFlags.RtRnSPFpSimd, AddressForm.BasePlusOffset), + new(0xB8400000, 0xBFE00C00, InstName.LdurGen, IsaVersion.v80, InstFlags.RtRnSP, AddressForm.BasePlusOffset), + new(0x887F0000, 0xBFFF8000, InstName.Ldxp, IsaVersion.v80, InstFlags.RtRt2RnSP, AddressForm.BaseRegister), + new(0x885F7C00, 0xBFFFFC00, InstName.Ldxr, IsaVersion.v80, InstFlags.RtRnSP, AddressForm.BaseRegister), + new(0x085F7C00, 0xFFFFFC00, InstName.Ldxrb, IsaVersion.v80, InstFlags.RtRnSP, AddressForm.BaseRegister), + new(0x485F7C00, 0xFFFFFC00, InstName.Ldxrh, IsaVersion.v80, InstFlags.RtRnSP, AddressForm.BaseRegister), + new(0x1AC02000, 0x7FE0FC00, InstName.Lslv, IsaVersion.v80, InstFlags.RdRnRm), + new(0x1AC02400, 0x7FE0FC00, InstName.Lsrv, IsaVersion.v80, InstFlags.RdRnRm), + new(0x1B000000, 0x7FE08000, InstName.Madd, IsaVersion.v80, InstFlags.RdRnRmRa), + new(0x2F000000, 0xBF00F400, sizeSizeConstraints, InstName.MlaAdvsimdElt, IsaVersion.v80, InstFlags.RdReadRdRnRmFpSimd), + new(0x0E209400, 0xBF20FC00, sizeConstraints, InstName.MlaAdvsimdVec, IsaVersion.v80, InstFlags.RdReadRdRnRmFpSimd), + new(0x2F004000, 0xBF00F400, sizeSizeConstraints, InstName.MlsAdvsimdElt, IsaVersion.v80, InstFlags.RdReadRdRnRmFpSimd), + new(0x2E209400, 0xBF20FC00, sizeConstraints, InstName.MlsAdvsimdVec, IsaVersion.v80, InstFlags.RdReadRdRnRmFpSimd), + new(0x0F000400, 0x9FF80C00, cmodeopqConstraints, InstName.MoviAdvsimd, IsaVersion.v80, InstFlags.RdFpSimd), + new(0x72800000, 0x7F800000, sfhwConstraints, InstName.Movk, IsaVersion.v80, InstFlags.RdReadRd), + new(0x12800000, 0x7F800000, sfhwConstraints, InstName.Movn, IsaVersion.v80, InstFlags.Rd), + new(0x52800000, 0x7F800000, sfhwConstraints, InstName.Movz, IsaVersion.v80, InstFlags.Rd), + new(0xD5700000, 0xFFF00000, rtConstraints, InstName.Mrrs, IsaVersion.None, InstFlags.RtReadRt), + new(0xD5300000, 0xFFF00000, InstName.Mrs, IsaVersion.v80, InstFlags.Rt), + new(0xD5500000, 0xFFF00000, rtConstraints, InstName.Msrr, IsaVersion.None, InstFlags.RtReadRt), + new(0xD500401F, 0xFFF8F01F, InstName.MsrImm, IsaVersion.v80, InstFlags.None), + new(0xD5100000, 0xFFF00000, InstName.MsrReg, IsaVersion.v80, InstFlags.RtReadRt), + new(0x1B008000, 0x7FE08000, InstName.Msub, IsaVersion.v80, InstFlags.RdRnRmRa), + new(0x0F008000, 0xBF00F400, sizeSizeConstraints, InstName.MulAdvsimdElt, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x0E209C00, 0xBF20FC00, usizeUsizeUsizeSizeConstraints, InstName.MulAdvsimdVec, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x2F000400, 0xBFF80C00, cmodeopqConstraints, InstName.MvniAdvsimd, IsaVersion.v80, InstFlags.RdFpSimd), + new(0x7EE0B800, 0xFFFFFC00, InstName.NegAdvsimdS, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x2E20B800, 0xBF3FFC00, qsizeConstraints, InstName.NegAdvsimdV, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0xD503201F, 0xFFFFFFFF, InstName.Nop, IsaVersion.v80, InstFlags.None), + new(0x2E205800, 0xBFFFFC00, InstName.NotAdvsimd, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x0EE01C00, 0xBFE0FC00, InstName.OrnAdvsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x2A200000, 0x7F200000, sfimm6Constraints, InstName.OrnLogShift, IsaVersion.v80, InstFlags.RdRnRm), + new(0x0F001400, 0xBFF81C00, InstName.OrrAdvsimdImm, IsaVersion.v80, InstFlags.RdFpSimd), + new(0x0EA01C00, 0xBFE0FC00, InstName.OrrAdvsimdReg, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x32000000, 0x7F800000, nimmsNimmsNimmsNimmsNimmsNimmsNimmsNimmsSfnConstraints, InstName.OrrLogImm, IsaVersion.v80, InstFlags.RdSPRn), + new(0x2A000000, 0x7F200000, sfimm6Constraints, InstName.OrrLogShift, IsaVersion.v80, InstFlags.RdRnRm), + new(0xDAC10800, 0xFFFFDC00, InstName.Pacda, IsaVersion.v83, InstFlags.RdRnSP), + new(0xDAC10C00, 0xFFFFDC00, InstName.Pacdb, IsaVersion.v83, InstFlags.RdRnSP), + new(0x9AC03000, 0xFFE0FC00, InstName.Pacga, IsaVersion.v83, InstFlags.RdRnRm), + new(0xDAC10000, 0xFFFFDC00, InstName.PaciaGeneral, IsaVersion.v83, InstFlags.RdRnSP), + new(0xD503211F, 0xFFFFFDDF, InstName.PaciaSystem, IsaVersion.v83, InstFlags.None), + new(0xDAC10400, 0xFFFFDC00, InstName.PacibGeneral, IsaVersion.v83, InstFlags.RdRnSP), + new(0xD503215F, 0xFFFFFDDF, InstName.PacibSystem, IsaVersion.v83, InstFlags.None), + new(0x0E20E000, 0xBFE0FC00, sizeSizeConstraints2, InstName.PmullAdvsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x0EE0E000, 0xBFE0FC00, sizeSizeConstraints2, InstName.PmullAdvsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x2E209C00, 0xBF20FC00, usizeUsizeUsizeSizeConstraints, InstName.PmulAdvsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0xF9800000, 0xFFC00000, InstName.PrfmImm, IsaVersion.v80, InstFlags.RnSP, AddressForm.UnsignedScaled), + new(0xD8000000, 0xFF000000, InstName.PrfmLit, IsaVersion.v80, InstFlags.None, AddressForm.Literal), + new(0xF8A04800, 0xFFE04C00, rtConstraints2, InstName.PrfmReg, IsaVersion.v80, InstFlags.RnSPRm, AddressForm.OffsetReg), + new(0xF8800000, 0xFFE00C00, InstName.Prfum, IsaVersion.v80, InstFlags.RnSP, AddressForm.BasePlusOffset), + new(0xD503223F, 0xFFFFFFFF, InstName.Psb, IsaVersion.v82, InstFlags.None), + new(0x2E204000, 0xBF20FC00, sizeConstraints, InstName.RaddhnAdvsimd, IsaVersion.v80, InstFlags.RdReadRdRnRmFpSimd), + new(0xCE608C00, 0xFFE0FC00, InstName.Rax1Advsimd, IsaVersion.v82, InstFlags.RdRnRmFpSimd), + new(0x2E605800, 0xBFFFFC00, InstName.RbitAdvsimd, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x5AC00000, 0x7FFFFC00, InstName.RbitInt, IsaVersion.v80, InstFlags.RdRn), + new(0x19200800, 0xFF20FC00, InstName.Rcwcas, IsaVersion.v89, InstFlags.RtReadRtRnSPRsS), + new(0x19200C00, 0xFF20FC00, rsRtConstraints, InstName.Rcwcasp, IsaVersion.None, InstFlags.RtReadRtRnSPRsS), + new(0x38209000, 0xFF20FC00, InstName.Rcwclr, IsaVersion.v89, InstFlags.RtReadRtRnSPRsS), + new(0x19209000, 0xFF20FC00, rtRt2Constraints, InstName.Rcwclrp, IsaVersion.None, InstFlags.RtReadRtRt2RnSPS), + new(0x59200800, 0xFF20FC00, InstName.Rcwscas, IsaVersion.v89, InstFlags.RtReadRtRnSPRsS), + new(0x59200C00, 0xFF20FC00, rsRtConstraints, InstName.Rcwscasp, IsaVersion.None, InstFlags.RtReadRtRnSPRsS), + new(0x78209000, 0xFF20FC00, InstName.Rcwsclr, IsaVersion.v89, InstFlags.RtReadRtRnSPRsS), + new(0x59209000, 0xFF20FC00, rtRt2Constraints, InstName.Rcwsclrp, IsaVersion.None, InstFlags.RtReadRtRt2RnSPS), + new(0x3820B000, 0xFF20FC00, InstName.Rcwset, IsaVersion.v89, InstFlags.RtReadRtRnSPRsS), + new(0x1920B000, 0xFF20FC00, rtRt2Constraints, InstName.Rcwsetp, IsaVersion.None, InstFlags.RtReadRtRt2RnSPS), + new(0x7820B000, 0xFF20FC00, InstName.Rcwsset, IsaVersion.v89, InstFlags.RtReadRtRnSPRsS), + new(0x5920B000, 0xFF20FC00, rtRt2Constraints, InstName.Rcwssetp, IsaVersion.None, InstFlags.RtReadRtRt2RnSPS), + new(0x7820A000, 0xFF20FC00, InstName.Rcwsswp, IsaVersion.v89, InstFlags.RtReadRtRnSPRsS), + new(0x5920A000, 0xFF20FC00, rtRt2Constraints, InstName.Rcwsswpp, IsaVersion.None, InstFlags.RtReadRtRt2RnSPS), + new(0x3820A000, 0xFF20FC00, InstName.Rcwswp, IsaVersion.v89, InstFlags.RtReadRtRnSPRsS), + new(0x1920A000, 0xFF20FC00, rtRt2Constraints, InstName.Rcwswpp, IsaVersion.None, InstFlags.RtReadRtRt2RnSPS), + new(0xD65F0000, 0xFFFFFC1F, InstName.Ret, IsaVersion.v80, InstFlags.Rn), + new(0xD65F0BFF, 0xFFFFFBFF, InstName.Reta, IsaVersion.v83, InstFlags.None), + new(0x5AC00800, 0x7FFFF800, sfopcConstraints, InstName.Rev, IsaVersion.v80, InstFlags.RdRn), + new(0x0E201800, 0xBF3FFC00, sizeSizeSizeConstraints, InstName.Rev16Advsimd, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x5AC00400, 0x7FFFFC00, InstName.Rev16Int, IsaVersion.v80, InstFlags.RdRn), + new(0x2E200800, 0xBF3FFC00, sizeSizeConstraints3, InstName.Rev32Advsimd, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0xDAC00800, 0xFFFFFC00, sfConstraints, InstName.Rev32Int, IsaVersion.v80, InstFlags.RdRn), + new(0x0E200800, 0xBF3FFC00, sizeConstraints, InstName.Rev64Advsimd, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0xBA000400, 0xFFE07C10, InstName.Rmif, IsaVersion.v84, InstFlags.RnC), + new(0x1AC02C00, 0x7FE0FC00, InstName.Rorv, IsaVersion.v80, InstFlags.RdRnRm), + new(0xF8A04818, 0xFFE04C18, InstName.RprfmReg, IsaVersion.v80, InstFlags.RnSPRm, AddressForm.OffsetReg), + new(0x0F008C00, 0xBF80FC00, immhImmhConstraints, InstName.RshrnAdvsimd, IsaVersion.v80, InstFlags.RdReadRdRnFpSimd), + new(0x2E206000, 0xBF20FC00, sizeConstraints, InstName.RsubhnAdvsimd, IsaVersion.v80, InstFlags.RdReadRdRnRmFpSimd), + new(0x0E205000, 0xBF20FC00, sizeConstraints, InstName.SabalAdvsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x0E207C00, 0xBF20FC00, sizeConstraints, InstName.SabaAdvsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x0E207000, 0xBF20FC00, sizeConstraints, InstName.SabdlAdvsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x0E207400, 0xBF20FC00, sizeConstraints, InstName.SabdAdvsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x0E206800, 0xBF3FFC00, sizeConstraints, InstName.SadalpAdvsimd, IsaVersion.v80, InstFlags.RdReadRdRnFpSimd), + new(0x0E202800, 0xBF3FFC00, sizeConstraints, InstName.SaddlpAdvsimd, IsaVersion.v80, InstFlags.RdReadRdRnFpSimd), + new(0x0E303800, 0xBF3FFC00, qsizeSizeConstraints, InstName.SaddlvAdvsimd, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x0E200000, 0xBF20FC00, sizeConstraints, InstName.SaddlAdvsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x0E201000, 0xBF20FC00, sizeConstraints, InstName.SaddwAdvsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0xD50330FF, 0xFFFFFFFF, InstName.Sb, IsaVersion.v85, InstFlags.None), + new(0x5A000000, 0x7FE0FC00, InstName.Sbc, IsaVersion.v80, InstFlags.RdRnRmC), + new(0x7A000000, 0x7FE0FC00, InstName.Sbcs, IsaVersion.v80, InstFlags.RdRnRmCS), + new(0x13000000, 0x7F800000, sfnSfnSfimmr5Sfimms5Constraints, InstName.Sbfm, IsaVersion.v80, InstFlags.RdRn), + new(0x5F40E400, 0xFFC0FC00, immhConstraints, InstName.ScvtfAdvsimdFixS, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x5F10E400, 0xFFF0FC00, immhConstraints, InstName.ScvtfAdvsimdFixS, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x5F20E400, 0xFFE0FC00, immhConstraints, InstName.ScvtfAdvsimdFixS, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x0F40E400, 0xBFC0FC00, immhQimmhConstraints, InstName.ScvtfAdvsimdFixV, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x0F10E400, 0xBFF0FC00, immhQimmhConstraints, InstName.ScvtfAdvsimdFixV, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x0F20E400, 0xBFE0FC00, immhQimmhConstraints, InstName.ScvtfAdvsimdFixV, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x5E79D800, 0xFFFFFC00, InstName.ScvtfAdvsimdIntSH, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x5E21D800, 0xFFBFFC00, InstName.ScvtfAdvsimdIntS, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x0E79D800, 0xBFFFFC00, InstName.ScvtfAdvsimdIntVH, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x0E21D800, 0xBFBFFC00, qszConstraints, InstName.ScvtfAdvsimdIntV, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x1E020000, 0x7FBF0000, sfscaleConstraints, InstName.ScvtfFloatFix, IsaVersion.v80, InstFlags.RdRnFpSimdFromGpr), + new(0x1EC20000, 0x7FFF0000, sfscaleConstraints, InstName.ScvtfFloatFix, IsaVersion.v80, InstFlags.RdRnFpSimdFromGpr), + new(0x1E220000, 0x7FBFFC00, InstName.ScvtfFloatInt, IsaVersion.v80, InstFlags.RdRnFpSimdFromGpr), + new(0x1EE20000, 0x7FFFFC00, InstName.ScvtfFloatInt, IsaVersion.v80, InstFlags.RdRnFpSimdFromGpr), + new(0x1AC00C00, 0x7FE0FC00, InstName.Sdiv, IsaVersion.v80, InstFlags.RdRnRm), + new(0x0F80E000, 0xBFC0F400, InstName.SdotAdvsimdElt, IsaVersion.v82, InstFlags.RdReadRdRnRmFpSimd), + new(0x0E809400, 0xBFE0FC00, InstName.SdotAdvsimdVec, IsaVersion.v82, InstFlags.RdReadRdRnRmFpSimd), + new(0x3A00080D, 0xFFFFBC1F, InstName.Setf, IsaVersion.v84, InstFlags.RnC), + new(0x1DC00400, 0x3FE03C00, InstName.Setgp, IsaVersion.v88, InstFlags.RdRnRsS), + new(0x1DC02400, 0x3FE03C00, InstName.Setgpn, IsaVersion.v88, InstFlags.RdRnRsS), + new(0x1DC01400, 0x3FE03C00, InstName.Setgpt, IsaVersion.v88, InstFlags.RdRnRsS), + new(0x1DC03400, 0x3FE03C00, InstName.Setgptn, IsaVersion.v88, InstFlags.RdRnRsS), + new(0x19C00400, 0x3FE03C00, InstName.Setp, IsaVersion.v88, InstFlags.RdRnRsS), + new(0x19C02400, 0x3FE03C00, InstName.Setpn, IsaVersion.v88, InstFlags.RdRnRsS), + new(0x19C01400, 0x3FE03C00, InstName.Setpt, IsaVersion.v88, InstFlags.RdRnRsS), + new(0x19C03400, 0x3FE03C00, InstName.Setptn, IsaVersion.v88, InstFlags.RdRnRsS), + new(0xD503209F, 0xFFFFFFFF, InstName.Sev, IsaVersion.v80, InstFlags.None), + new(0xD50320BF, 0xFFFFFFFF, InstName.Sevl, IsaVersion.v80, InstFlags.None), + new(0x5E000000, 0xFFE0FC00, InstName.Sha1cAdvsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x5E280800, 0xFFFFFC00, InstName.Sha1hAdvsimd, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x5E002000, 0xFFE0FC00, InstName.Sha1mAdvsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x5E001000, 0xFFE0FC00, InstName.Sha1pAdvsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x5E003000, 0xFFE0FC00, InstName.Sha1su0Advsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x5E281800, 0xFFFFFC00, InstName.Sha1su1Advsimd, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x5E005000, 0xFFE0FC00, InstName.Sha256h2Advsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x5E004000, 0xFFE0FC00, InstName.Sha256hAdvsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x5E282800, 0xFFFFFC00, InstName.Sha256su0Advsimd, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x5E006000, 0xFFE0FC00, InstName.Sha256su1Advsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0xCE608400, 0xFFE0FC00, InstName.Sha512h2Advsimd, IsaVersion.v82, InstFlags.RdRnRmFpSimd), + new(0xCE608000, 0xFFE0FC00, InstName.Sha512hAdvsimd, IsaVersion.v82, InstFlags.RdRnRmFpSimd), + new(0xCEC08000, 0xFFFFFC00, InstName.Sha512su0Advsimd, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0xCE608800, 0xFFE0FC00, InstName.Sha512su1Advsimd, IsaVersion.v82, InstFlags.RdRnRmFpSimd), + new(0x0E200400, 0xBF20FC00, sizeConstraints, InstName.ShaddAdvsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x2E213800, 0xBF3FFC00, sizeConstraints, InstName.ShllAdvsimd, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x5F405400, 0xFFC0FC00, immhConstraints, InstName.ShlAdvsimdS, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x0F005400, 0xBF80FC00, immhQimmhConstraints, InstName.ShlAdvsimdV, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x0F008400, 0xBF80FC00, immhImmhConstraints, InstName.ShrnAdvsimd, IsaVersion.v80, InstFlags.RdReadRdRnFpSimd), + new(0x0E202400, 0xBF20FC00, sizeConstraints, InstName.ShsubAdvsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x7F405400, 0xFFC0FC00, immhConstraints, InstName.SliAdvsimdS, IsaVersion.v80, InstFlags.RdReadRdRnFpSimd), + new(0x2F005400, 0xBF80FC00, immhQimmhConstraints, InstName.SliAdvsimdV, IsaVersion.v80, InstFlags.RdReadRdRnFpSimd), + new(0xCE60C000, 0xFFE0FC00, InstName.Sm3partw1Advsimd, IsaVersion.v82, InstFlags.RdRnRmFpSimd), + new(0xCE60C400, 0xFFE0FC00, InstName.Sm3partw2Advsimd, IsaVersion.v82, InstFlags.RdRnRmFpSimd), + new(0xCE400000, 0xFFE08000, InstName.Sm3ss1Advsimd, IsaVersion.v82, InstFlags.RdRnRmRaFpSimd), + new(0xCE408000, 0xFFE0CC00, InstName.Sm3tt1aAdvsimd, IsaVersion.v82, InstFlags.RdRnRmFpSimd), + new(0xCE408400, 0xFFE0CC00, InstName.Sm3tt1bAdvsimd, IsaVersion.v82, InstFlags.RdRnRmFpSimd), + new(0xCE408800, 0xFFE0CC00, InstName.Sm3tt2aAdvsimd, IsaVersion.v82, InstFlags.RdRnRmFpSimd), + new(0xCE408C00, 0xFFE0CC00, InstName.Sm3tt2bAdvsimd, IsaVersion.v82, InstFlags.RdRnRmFpSimd), + new(0xCE60C800, 0xFFE0FC00, InstName.Sm4ekeyAdvsimd, IsaVersion.v82, InstFlags.RdRnRmFpSimd), + new(0xCEC08400, 0xFFFFFC00, InstName.Sm4eAdvsimd, IsaVersion.v82, InstFlags.RdReadRdRnFpSimd), + new(0x9B200000, 0xFFE08000, InstName.Smaddl, IsaVersion.v80, InstFlags.RdRnRmRa), + new(0x0E20A400, 0xBF20FC00, sizeConstraints, InstName.SmaxpAdvsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x0E30A800, 0xBF3FFC00, qsizeSizeConstraints, InstName.SmaxvAdvsimd, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x0E206400, 0xBF20FC00, sizeConstraints, InstName.SmaxAdvsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x11C00000, 0x7FFC0000, InstName.SmaxImm, IsaVersion.v89, InstFlags.RdRn), + new(0x1AC06000, 0x7FE0FC00, InstName.SmaxReg, IsaVersion.v89, InstFlags.RdRnRm), + new(0xD4000003, 0xFFE0001F, InstName.Smc, IsaVersion.v80, InstFlags.None), + new(0x0E20AC00, 0xBF20FC00, sizeConstraints, InstName.SminpAdvsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x0E31A800, 0xBF3FFC00, qsizeSizeConstraints, InstName.SminvAdvsimd, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x0E206C00, 0xBF20FC00, sizeConstraints, InstName.SminAdvsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x11C80000, 0x7FFC0000, InstName.SminImm, IsaVersion.v89, InstFlags.RdRn), + new(0x1AC06800, 0x7FE0FC00, InstName.SminReg, IsaVersion.v89, InstFlags.RdRnRm), + new(0x0F002000, 0xBF00F400, sizeSizeConstraints, InstName.SmlalAdvsimdElt, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x0E208000, 0xBF20FC00, sizeConstraints, InstName.SmlalAdvsimdVec, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x0F006000, 0xBF00F400, sizeSizeConstraints, InstName.SmlslAdvsimdElt, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x0E20A000, 0xBF20FC00, sizeConstraints, InstName.SmlslAdvsimdVec, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x4E80A400, 0xFFE0FC00, InstName.SmmlaAdvsimdVec, IsaVersion.v86, InstFlags.RdRnRmFpSimd), + new(0x0E012C00, 0xBFE1FC00, InstName.SmovAdvsimd, IsaVersion.v80, InstFlags.RdRnFpSimdToGpr), + new(0x0E022C00, 0xBFE3FC00, InstName.SmovAdvsimd, IsaVersion.v80, InstFlags.RdRnFpSimdToGpr), + new(0x4E042C00, 0xFFE7FC00, InstName.SmovAdvsimd, IsaVersion.v80, InstFlags.RdRnFpSimdToGpr), + new(0x9B208000, 0xFFE08000, InstName.Smsubl, IsaVersion.v80, InstFlags.RdRnRmRa), + new(0x9B407C00, 0xFFE0FC00, InstName.Smulh, IsaVersion.v80, InstFlags.RdRnRm), + new(0x0F00A000, 0xBF00F400, sizeSizeConstraints, InstName.SmullAdvsimdElt, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x0E20C000, 0xBF20FC00, sizeConstraints, InstName.SmullAdvsimdVec, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x5E207800, 0xFF3FFC00, InstName.SqabsAdvsimdS, IsaVersion.v80, InstFlags.RdRnQcFpSimd), + new(0x0E207800, 0xBF3FFC00, qsizeConstraints, InstName.SqabsAdvsimdV, IsaVersion.v80, InstFlags.RdRnQcFpSimd), + new(0x5E200C00, 0xFF20FC00, InstName.SqaddAdvsimdS, IsaVersion.v80, InstFlags.RdRnRmQcFpSimd), + new(0x0E200C00, 0xBF20FC00, qsizeConstraints, InstName.SqaddAdvsimdV, IsaVersion.v80, InstFlags.RdRnRmQcFpSimd), + new(0x5F003000, 0xFF00F400, sizeSizeConstraints, InstName.SqdmlalAdvsimdElt2regScalar, IsaVersion.v80, InstFlags.RdRnRmQcFpSimd), + new(0x0F003000, 0xBF00F400, sizeSizeConstraints, InstName.SqdmlalAdvsimdElt2regElement, IsaVersion.v80, InstFlags.RdRnRmQcFpSimd), + new(0x5E209000, 0xFF20FC00, sizeSizeConstraints, InstName.SqdmlalAdvsimdVecS, IsaVersion.v80, InstFlags.RdRnRmQcFpSimd), + new(0x0E209000, 0xBF20FC00, sizeSizeConstraints, InstName.SqdmlalAdvsimdVecV, IsaVersion.v80, InstFlags.RdRnRmQcFpSimd), + new(0x5F007000, 0xFF00F400, sizeSizeConstraints, InstName.SqdmlslAdvsimdElt2regScalar, IsaVersion.v80, InstFlags.RdRnRmQcFpSimd), + new(0x0F007000, 0xBF00F400, sizeSizeConstraints, InstName.SqdmlslAdvsimdElt2regElement, IsaVersion.v80, InstFlags.RdRnRmQcFpSimd), + new(0x5E20B000, 0xFF20FC00, sizeSizeConstraints, InstName.SqdmlslAdvsimdVecS, IsaVersion.v80, InstFlags.RdRnRmQcFpSimd), + new(0x0E20B000, 0xBF20FC00, sizeSizeConstraints, InstName.SqdmlslAdvsimdVecV, IsaVersion.v80, InstFlags.RdRnRmQcFpSimd), + new(0x5F00C000, 0xFF00F400, sizeSizeConstraints, InstName.SqdmulhAdvsimdElt2regScalar, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x0F00C000, 0xBF00F400, sizeSizeConstraints, InstName.SqdmulhAdvsimdElt2regElement, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x5E20B400, 0xFF20FC00, sizeSizeConstraints4, InstName.SqdmulhAdvsimdVecS, IsaVersion.v80, InstFlags.RdRnRmQcFpSimd), + new(0x0E20B400, 0xBF20FC00, sizeSizeConstraints4, InstName.SqdmulhAdvsimdVecV, IsaVersion.v80, InstFlags.RdRnRmQcFpSimd), + new(0x5F00B000, 0xFF00F400, sizeSizeConstraints, InstName.SqdmullAdvsimdElt2regScalar, IsaVersion.v80, InstFlags.RdRnRmQcFpSimd), + new(0x0F00B000, 0xBF00F400, sizeSizeConstraints, InstName.SqdmullAdvsimdElt2regElement, IsaVersion.v80, InstFlags.RdRnRmQcFpSimd), + new(0x5E20D000, 0xFF20FC00, sizeSizeConstraints, InstName.SqdmullAdvsimdVecS, IsaVersion.v80, InstFlags.RdRnRmQcFpSimd), + new(0x0E20D000, 0xBF20FC00, sizeSizeConstraints, InstName.SqdmullAdvsimdVecV, IsaVersion.v80, InstFlags.RdRnRmQcFpSimd), + new(0x7E207800, 0xFF3FFC00, InstName.SqnegAdvsimdS, IsaVersion.v80, InstFlags.RdRnQcFpSimd), + new(0x2E207800, 0xBF3FFC00, qsizeConstraints, InstName.SqnegAdvsimdV, IsaVersion.v80, InstFlags.RdRnQcFpSimd), + new(0x7F00D000, 0xFF00F400, sizeSizeConstraints, InstName.SqrdmlahAdvsimdElt2regScalar, IsaVersion.v81, InstFlags.RdReadRdRnRmQcFpSimd), + new(0x2F00D000, 0xBF00F400, sizeSizeConstraints, InstName.SqrdmlahAdvsimdElt2regElement, IsaVersion.v81, InstFlags.RdReadRdRnRmQcFpSimd), + new(0x7E008400, 0xFF20FC00, sizeSizeConstraints4, InstName.SqrdmlahAdvsimdVecS, IsaVersion.v81, InstFlags.RdReadRdRnRmQcFpSimd), + new(0x2E008400, 0xBF20FC00, sizeSizeConstraints4, InstName.SqrdmlahAdvsimdVecV, IsaVersion.v81, InstFlags.RdReadRdRnRmQcFpSimd), + new(0x7F00F000, 0xFF00F400, sizeSizeConstraints, InstName.SqrdmlshAdvsimdElt2regScalar, IsaVersion.v81, InstFlags.RdReadRdRnRmQcFpSimd), + new(0x2F00F000, 0xBF00F400, sizeSizeConstraints, InstName.SqrdmlshAdvsimdElt2regElement, IsaVersion.v81, InstFlags.RdReadRdRnRmQcFpSimd), + new(0x7E008C00, 0xFF20FC00, sizeSizeConstraints4, InstName.SqrdmlshAdvsimdVecS, IsaVersion.v81, InstFlags.RdReadRdRnRmQcFpSimd), + new(0x2E008C00, 0xBF20FC00, sizeSizeConstraints4, InstName.SqrdmlshAdvsimdVecV, IsaVersion.v81, InstFlags.RdReadRdRnRmQcFpSimd), + new(0x5F00D000, 0xFF00F400, sizeSizeConstraints, InstName.SqrdmulhAdvsimdElt2regScalar, IsaVersion.v80, InstFlags.RdRnRmQcFpSimd), + new(0x0F00D000, 0xBF00F400, sizeSizeConstraints, InstName.SqrdmulhAdvsimdElt2regElement, IsaVersion.v80, InstFlags.RdRnRmQcFpSimd), + new(0x7E20B400, 0xFF20FC00, sizeSizeConstraints4, InstName.SqrdmulhAdvsimdVecS, IsaVersion.v80, InstFlags.RdRnRmQcFpSimd), + new(0x2E20B400, 0xBF20FC00, sizeSizeConstraints4, InstName.SqrdmulhAdvsimdVecV, IsaVersion.v80, InstFlags.RdRnRmQcFpSimd), + new(0x5E205C00, 0xFF20FC00, ssizeSsizeSsizeConstraints, InstName.SqrshlAdvsimdS, IsaVersion.v80, InstFlags.RdRnRmQcFpSimd), + new(0x0E205C00, 0xBF20FC00, qsizeConstraints, InstName.SqrshlAdvsimdV, IsaVersion.v80, InstFlags.RdRnRmQcFpSimd), + new(0x5F009C00, 0xFF80FC00, immhImmhConstraints, InstName.SqrshrnAdvsimdS, IsaVersion.v80, InstFlags.RdReadRdRnQcFpSimd), + new(0x0F009C00, 0xBF80FC00, immhImmhConstraints, InstName.SqrshrnAdvsimdV, IsaVersion.v80, InstFlags.RdReadRdRnQcFpSimd), + new(0x7F008C00, 0xFF80FC00, immhImmhConstraints, InstName.SqrshrunAdvsimdS, IsaVersion.v80, InstFlags.RdReadRdRnQcFpSimd), + new(0x2F008C00, 0xBF80FC00, immhImmhConstraints, InstName.SqrshrunAdvsimdV, IsaVersion.v80, InstFlags.RdReadRdRnQcFpSimd), + new(0x7F006400, 0xFF80FC00, immhOpuConstraints, InstName.SqshluAdvsimdS, IsaVersion.v80, InstFlags.RdRnQcFpSimd), + new(0x2F006400, 0xBF80FC00, immhQimmhOpuConstraints, InstName.SqshluAdvsimdV, IsaVersion.v80, InstFlags.RdRnQcFpSimd), + new(0x5F007400, 0xFF80FC00, immhOpuConstraints, InstName.SqshlAdvsimdImmS, IsaVersion.v80, InstFlags.RdRnQcFpSimd), + new(0x0F007400, 0xBF80FC00, immhQimmhOpuConstraints, InstName.SqshlAdvsimdImmV, IsaVersion.v80, InstFlags.RdRnQcFpSimd), + new(0x5E204C00, 0xFF20FC00, ssizeSsizeSsizeConstraints, InstName.SqshlAdvsimdRegS, IsaVersion.v80, InstFlags.RdRnRmQcFpSimd), + new(0x0E204C00, 0xBF20FC00, qsizeConstraints, InstName.SqshlAdvsimdRegV, IsaVersion.v80, InstFlags.RdRnRmQcFpSimd), + new(0x5F009400, 0xFF80FC00, immhImmhConstraints, InstName.SqshrnAdvsimdS, IsaVersion.v80, InstFlags.RdReadRdRnQcFpSimd), + new(0x0F009400, 0xBF80FC00, immhImmhConstraints, InstName.SqshrnAdvsimdV, IsaVersion.v80, InstFlags.RdReadRdRnQcFpSimd), + new(0x7F008400, 0xFF80FC00, immhImmhConstraints, InstName.SqshrunAdvsimdS, IsaVersion.v80, InstFlags.RdReadRdRnQcFpSimd), + new(0x2F008400, 0xBF80FC00, immhImmhConstraints, InstName.SqshrunAdvsimdV, IsaVersion.v80, InstFlags.RdReadRdRnQcFpSimd), + new(0x5E202C00, 0xFF20FC00, InstName.SqsubAdvsimdS, IsaVersion.v80, InstFlags.RdRnRmQcFpSimd), + new(0x0E202C00, 0xBF20FC00, qsizeConstraints, InstName.SqsubAdvsimdV, IsaVersion.v80, InstFlags.RdRnRmQcFpSimd), + new(0x5E214800, 0xFF3FFC00, sizeConstraints, InstName.SqxtnAdvsimdS, IsaVersion.v80, InstFlags.RdReadRdRnQcFpSimd), + new(0x0E214800, 0xBF3FFC00, sizeConstraints, InstName.SqxtnAdvsimdV, IsaVersion.v80, InstFlags.RdReadRdRnQcFpSimd), + new(0x7E212800, 0xFF3FFC00, sizeConstraints, InstName.SqxtunAdvsimdS, IsaVersion.v80, InstFlags.RdReadRdRnQcFpSimd), + new(0x2E212800, 0xBF3FFC00, sizeConstraints, InstName.SqxtunAdvsimdV, IsaVersion.v80, InstFlags.RdReadRdRnQcFpSimd), + new(0x0E201400, 0xBF20FC00, sizeConstraints, InstName.SrhaddAdvsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x7F404400, 0xFFC0FC00, immhConstraints, InstName.SriAdvsimdS, IsaVersion.v80, InstFlags.RdReadRdRnFpSimd), + new(0x2F004400, 0xBF80FC00, immhQimmhConstraints, InstName.SriAdvsimdV, IsaVersion.v80, InstFlags.RdReadRdRnFpSimd), + new(0x5E205400, 0xFF20FC00, ssizeSsizeSsizeConstraints, InstName.SrshlAdvsimdS, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x0E205400, 0xBF20FC00, qsizeConstraints, InstName.SrshlAdvsimdV, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x5F402400, 0xFFC0FC00, immhConstraints, InstName.SrshrAdvsimdS, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x0F002400, 0xBF80FC00, immhQimmhConstraints, InstName.SrshrAdvsimdV, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x5F403400, 0xFFC0FC00, immhConstraints, InstName.SrsraAdvsimdS, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x0F003400, 0xBF80FC00, immhQimmhConstraints, InstName.SrsraAdvsimdV, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x0F00A400, 0xBF80FC00, immhImmhConstraints, InstName.SshllAdvsimd, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x5E204400, 0xFF20FC00, ssizeSsizeSsizeConstraints, InstName.SshlAdvsimdS, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x0E204400, 0xBF20FC00, qsizeConstraints, InstName.SshlAdvsimdV, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x5F400400, 0xFFC0FC00, immhConstraints, InstName.SshrAdvsimdS, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x0F000400, 0xBF80FC00, immhQimmhConstraints, InstName.SshrAdvsimdV, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x5F401400, 0xFFC0FC00, immhConstraints, InstName.SsraAdvsimdS, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x0F001400, 0xBF80FC00, immhQimmhConstraints, InstName.SsraAdvsimdV, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x0E202000, 0xBF20FC00, sizeConstraints, InstName.SsublAdvsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x0E203000, 0xBF20FC00, sizeConstraints, InstName.SsubwAdvsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x0C002000, 0xBFFFF000, InstName.St1AdvsimdMultAsNoPostIndex, IsaVersion.v80, InstFlags.RtSeqReadRtRnSPFpSimd, AddressForm.StructNoOffset), + new(0x0C006000, 0xBFFFF000, InstName.St1AdvsimdMultAsNoPostIndex, IsaVersion.v80, InstFlags.RtSeqReadRtRnSPFpSimd, AddressForm.StructNoOffset), + new(0x0C007000, 0xBFFFF000, InstName.St1AdvsimdMultAsNoPostIndex, IsaVersion.v80, InstFlags.RtSeqReadRtRnSPFpSimd, AddressForm.StructNoOffset), + new(0x0C00A000, 0xBFFFF000, InstName.St1AdvsimdMultAsNoPostIndex, IsaVersion.v80, InstFlags.RtSeqReadRtRnSPFpSimd, AddressForm.StructNoOffset), + new(0x0C006000, 0xBFFFF000, InstName.St1AdvsimdMultAsNoPostIndex, IsaVersion.v80, InstFlags.RtSeqReadRtRnSPFpSimd, AddressForm.StructNoOffset), + new(0x0C007000, 0xBFFFF000, InstName.St1AdvsimdMultAsNoPostIndex, IsaVersion.v80, InstFlags.RtSeqReadRtRnSPFpSimd, AddressForm.StructNoOffset), + new(0x0C00A000, 0xBFFFF000, InstName.St1AdvsimdMultAsNoPostIndex, IsaVersion.v80, InstFlags.RtSeqReadRtRnSPFpSimd, AddressForm.StructNoOffset), + new(0x0C802000, 0xBFE0F000, InstName.St1AdvsimdMultAsPostIndex, IsaVersion.v80, InstFlags.RtSeqReadRtRnSPRmFpSimdMemWBack, AddressForm.StructPostIndexedReg), + new(0x0C806000, 0xBFE0F000, InstName.St1AdvsimdMultAsPostIndex, IsaVersion.v80, InstFlags.RtSeqReadRtRnSPRmFpSimdMemWBack, AddressForm.StructPostIndexedReg), + new(0x0C807000, 0xBFE0F000, InstName.St1AdvsimdMultAsPostIndex, IsaVersion.v80, InstFlags.RtSeqReadRtRnSPRmFpSimdMemWBack, AddressForm.StructPostIndexedReg), + new(0x0C80A000, 0xBFE0F000, InstName.St1AdvsimdMultAsPostIndex, IsaVersion.v80, InstFlags.RtSeqReadRtRnSPRmFpSimdMemWBack, AddressForm.StructPostIndexedReg), + new(0x0C806000, 0xBFE0F000, InstName.St1AdvsimdMultAsPostIndex, IsaVersion.v80, InstFlags.RtSeqReadRtRnSPRmFpSimdMemWBack, AddressForm.StructPostIndexedReg), + new(0x0C807000, 0xBFE0F000, InstName.St1AdvsimdMultAsPostIndex, IsaVersion.v80, InstFlags.RtSeqReadRtRnSPRmFpSimdMemWBack, AddressForm.StructPostIndexedReg), + new(0x0C80A000, 0xBFE0F000, InstName.St1AdvsimdMultAsPostIndex, IsaVersion.v80, InstFlags.RtSeqReadRtRnSPRmFpSimdMemWBack, AddressForm.StructPostIndexedReg), + new(0x0D000000, 0xBFFF2000, opcodesizeOpcodesizeOpcodesizesOpcodesizeConstraints, InstName.St1AdvsimdSnglAsNoPostIndex, IsaVersion.v80, InstFlags.RtReadRtRnSPFpSimd, AddressForm.StructNoOffset), + new(0x0D800000, 0xBFE02000, opcodesizeOpcodesizeOpcodesizesOpcodesizeConstraints, InstName.St1AdvsimdSnglAsPostIndex, IsaVersion.v80, InstFlags.RtReadRtRnSPRmFpSimdMemWBack, AddressForm.StructPostIndexedReg), + new(0xD9A00400, 0xFFE00C00, InstName.St2gPostIndexed, IsaVersion.v85, InstFlags.MemWBack, AddressForm.PostIndexed), + new(0xD9A00C00, 0xFFE00C00, InstName.St2gPreIndexed, IsaVersion.v85, InstFlags.MemWBack, AddressForm.PreIndexed), + new(0xD9A00800, 0xFFE00C00, InstName.St2gSignedScaledOffset, IsaVersion.v85, InstFlags.None, AddressForm.SignedScaled), + new(0x0C008000, 0xBFFFF000, qsizeConstraints2, InstName.St2AdvsimdMultAsNoPostIndex, IsaVersion.v80, InstFlags.RtSeqReadRtRnSPFpSimd, AddressForm.StructNoOffset), + new(0x0C808000, 0xBFE0F000, qsizeConstraints2, InstName.St2AdvsimdMultAsPostIndex, IsaVersion.v80, InstFlags.RtSeqReadRtRnSPRmFpSimdMemWBack, AddressForm.StructPostIndexedReg), + new(0x0D200000, 0xBFFF2000, opcodesizeOpcodesizeOpcodesizesOpcodesizeConstraints, InstName.St2AdvsimdSnglAsNoPostIndex, IsaVersion.v80, InstFlags.RtSeqReadRtRnSPFpSimd, AddressForm.StructNoOffset), + new(0x0DA00000, 0xBFE02000, opcodesizeOpcodesizeOpcodesizesOpcodesizeConstraints, InstName.St2AdvsimdSnglAsPostIndex, IsaVersion.v80, InstFlags.RtSeqReadRtRnSPRmFpSimdMemWBack, AddressForm.StructPostIndexedReg), + new(0x0C004000, 0xBFFFF000, qsizeConstraints2, InstName.St3AdvsimdMultAsNoPostIndex, IsaVersion.v80, InstFlags.RtSeqReadRtRnSPFpSimd, AddressForm.StructNoOffset), + new(0x0C804000, 0xBFE0F000, qsizeConstraints2, InstName.St3AdvsimdMultAsPostIndex, IsaVersion.v80, InstFlags.RtSeqReadRtRnSPRmFpSimdMemWBack, AddressForm.StructPostIndexedReg), + new(0x0D002000, 0xBFFF2000, opcodesizeOpcodesizeOpcodesizesOpcodesizeConstraints, InstName.St3AdvsimdSnglAsNoPostIndex, IsaVersion.v80, InstFlags.RtSeqReadRtRnSPFpSimd, AddressForm.StructNoOffset), + new(0x0D802000, 0xBFE02000, opcodesizeOpcodesizeOpcodesizesOpcodesizeConstraints, InstName.St3AdvsimdSnglAsPostIndex, IsaVersion.v80, InstFlags.RtSeqReadRtRnSPRmFpSimdMemWBack, AddressForm.StructPostIndexedReg), + new(0x0C000000, 0xBFFFF000, qsizeConstraints2, InstName.St4AdvsimdMultAsNoPostIndex, IsaVersion.v80, InstFlags.RtSeqReadRtRnSPFpSimd, AddressForm.StructNoOffset), + new(0x0C800000, 0xBFE0F000, qsizeConstraints2, InstName.St4AdvsimdMultAsPostIndex, IsaVersion.v80, InstFlags.RtSeqReadRtRnSPRmFpSimdMemWBack, AddressForm.StructPostIndexedReg), + new(0x0D202000, 0xBFFF2000, opcodesizeOpcodesizeOpcodesizesOpcodesizeConstraints, InstName.St4AdvsimdSnglAsNoPostIndex, IsaVersion.v80, InstFlags.RtSeqReadRtRnSPFpSimd, AddressForm.StructNoOffset), + new(0x0DA02000, 0xBFE02000, opcodesizeOpcodesizeOpcodesizesOpcodesizeConstraints, InstName.St4AdvsimdSnglAsPostIndex, IsaVersion.v80, InstFlags.RtSeqReadRtRnSPRmFpSimdMemWBack, AddressForm.StructPostIndexedReg), + new(0xF83F9000, 0xFFFFFC00, rtRtConstraints, InstName.St64b, IsaVersion.v87, InstFlags.RtReadRtRnSP), + new(0xF820B000, 0xFFE0FC00, rtRtConstraints, InstName.St64bv, IsaVersion.v87, InstFlags.RtReadRtRnSPRs), + new(0xF820A000, 0xFFE0FC00, rtRtConstraints, InstName.St64bv0, IsaVersion.v87, InstFlags.RtReadRtRnSPRs), + new(0xD9200400, 0xFFE00C00, InstName.StgPostIndexed, IsaVersion.v85, InstFlags.MemWBack, AddressForm.PostIndexed), + new(0xD9200C00, 0xFFE00C00, InstName.StgPreIndexed, IsaVersion.v85, InstFlags.MemWBack, AddressForm.PreIndexed), + new(0xD9200800, 0xFFE00C00, InstName.StgSignedScaledOffset, IsaVersion.v85, InstFlags.None, AddressForm.SignedScaled), + new(0xD9A00000, 0xFFFFFC00, InstName.Stgm, IsaVersion.v85, InstFlags.None), + new(0x68800000, 0xFFC00000, InstName.StgpPostIndexed, IsaVersion.v85, InstFlags.MemWBack, AddressForm.PostIndexed), + new(0x69800000, 0xFFC00000, InstName.StgpPreIndexed, IsaVersion.v85, InstFlags.MemWBack, AddressForm.PreIndexed), + new(0x69000000, 0xFFC00000, InstName.StgpSignedScaledOffset, IsaVersion.v85, InstFlags.None, AddressForm.SignedScaled), + new(0x99000800, 0xBFE0EC00, InstName.Stilp, IsaVersion.v82, InstFlags.RtReadRtRt2RnSP), + new(0x0D018400, 0xBFFFFC00, opcodesizeOpcodesizeOpcodesizesOpcodesizeConstraints, InstName.Stl1AdvsimdSngl, IsaVersion.v82, InstFlags.RtReadRtRnSPFpSimd, AddressForm.StructNoOffset), + new(0x889F7C00, 0xBFFFFC00, InstName.Stllr, IsaVersion.v81, InstFlags.RtReadRtRnSP, AddressForm.BaseRegister), + new(0x089F7C00, 0xFFFFFC00, InstName.Stllrb, IsaVersion.v81, InstFlags.RtReadRtRnSP, AddressForm.BaseRegister), + new(0x489F7C00, 0xFFFFFC00, InstName.Stllrh, IsaVersion.v81, InstFlags.RtReadRtRnSP, AddressForm.BaseRegister), + new(0x889FFC00, 0xBFFFFC00, InstName.StlrBaseRegister, IsaVersion.v80, InstFlags.RtReadRtRnSP, AddressForm.BaseRegister), + new(0x99800800, 0xBFFFFC00, InstName.StlrPreIndexed, IsaVersion.v82, InstFlags.RtReadRtRnSPMemWBack, AddressForm.PreIndexed), + new(0x089FFC00, 0xFFFFFC00, InstName.Stlrb, IsaVersion.v80, InstFlags.RtReadRtRnSP, AddressForm.BaseRegister), + new(0x489FFC00, 0xFFFFFC00, InstName.Stlrh, IsaVersion.v80, InstFlags.RtReadRtRnSP, AddressForm.BaseRegister), + new(0x19000000, 0xFFE00C00, InstName.Stlurb, IsaVersion.v84, InstFlags.RtReadRtRnSP, AddressForm.BasePlusOffset), + new(0x59000000, 0xFFE00C00, InstName.Stlurh, IsaVersion.v84, InstFlags.RtReadRtRnSP, AddressForm.BasePlusOffset), + new(0x1D000800, 0x3F600C00, opc1sizeOpc1sizeOpc1sizeConstraints, InstName.StlurFpsimd, IsaVersion.v82, InstFlags.RtReadRtRnSPFpSimd, AddressForm.BasePlusOffset), + new(0x99000000, 0xBFE00C00, InstName.StlurGen, IsaVersion.v84, InstFlags.RtReadRtRnSP, AddressForm.BasePlusOffset), + new(0x88208000, 0xBFE08000, InstName.Stlxp, IsaVersion.v80, InstFlags.RtReadRtRt2RnSPRs, AddressForm.BaseRegister), + new(0x8800FC00, 0xBFE0FC00, InstName.Stlxr, IsaVersion.v80, InstFlags.RtReadRtRnSPRs, AddressForm.BaseRegister), + new(0x0800FC00, 0xFFE0FC00, InstName.Stlxrb, IsaVersion.v80, InstFlags.RtReadRtRnSPRs, AddressForm.BaseRegister), + new(0x4800FC00, 0xFFE0FC00, InstName.Stlxrh, IsaVersion.v80, InstFlags.RtReadRtRnSPRs, AddressForm.BaseRegister), + new(0x2C000000, 0x3FC00000, opcConstraints, InstName.StnpFpsimd, IsaVersion.v80, InstFlags.RtReadRtRt2RnSPFpSimd, AddressForm.SignedScaled), + new(0x28000000, 0x7FC00000, opcConstraints2, InstName.StnpGen, IsaVersion.v80, InstFlags.RtReadRtRt2RnSP, AddressForm.SignedScaled), + new(0x2C800000, 0x3FC00000, opcConstraints, InstName.StpFpsimdPostIndexed, IsaVersion.v80, InstFlags.RtReadRtRt2RnSPFpSimdMemWBack, AddressForm.PostIndexed), + new(0x2D800000, 0x3FC00000, opcConstraints, InstName.StpFpsimdPreIndexed, IsaVersion.v80, InstFlags.RtReadRtRt2RnSPFpSimdMemWBack, AddressForm.PreIndexed), + new(0x2D000000, 0x3FC00000, opcConstraints, InstName.StpFpsimdSignedScaledOffset, IsaVersion.v80, InstFlags.RtReadRtRt2RnSPFpSimd, AddressForm.SignedScaled), + new(0x28800000, 0x7FC00000, opclOpcConstraints, InstName.StpGenPostIndexed, IsaVersion.v80, InstFlags.RtReadRtRt2RnSPMemWBack, AddressForm.PostIndexed), + new(0x29800000, 0x7FC00000, opclOpcConstraints, InstName.StpGenPreIndexed, IsaVersion.v80, InstFlags.RtReadRtRt2RnSPMemWBack, AddressForm.PreIndexed), + new(0x29000000, 0x7FC00000, opclOpcConstraints, InstName.StpGenSignedScaledOffset, IsaVersion.v80, InstFlags.RtReadRtRt2RnSP, AddressForm.SignedScaled), + new(0x38000400, 0xFFE00C00, InstName.StrbImmPostIndexed, IsaVersion.v80, InstFlags.RtReadRtRnSPMemWBack, AddressForm.PostIndexed), + new(0x38000C00, 0xFFE00C00, InstName.StrbImmPreIndexed, IsaVersion.v80, InstFlags.RtReadRtRnSPMemWBack, AddressForm.PreIndexed), + new(0x39000000, 0xFFC00000, InstName.StrbImmUnsignedScaledOffset, IsaVersion.v80, InstFlags.RtReadRtRnSP, AddressForm.UnsignedScaled), + new(0x38200800, 0xFFE00C00, optionConstraints, InstName.StrbReg, IsaVersion.v80, InstFlags.RtReadRtRnSPRm, AddressForm.OffsetReg), + new(0x78000400, 0xFFE00C00, InstName.StrhImmPostIndexed, IsaVersion.v80, InstFlags.RtReadRtRnSPMemWBack, AddressForm.PostIndexed), + new(0x78000C00, 0xFFE00C00, InstName.StrhImmPreIndexed, IsaVersion.v80, InstFlags.RtReadRtRnSPMemWBack, AddressForm.PreIndexed), + new(0x79000000, 0xFFC00000, InstName.StrhImmUnsignedScaledOffset, IsaVersion.v80, InstFlags.RtReadRtRnSP, AddressForm.UnsignedScaled), + new(0x78200800, 0xFFE00C00, optionConstraints, InstName.StrhReg, IsaVersion.v80, InstFlags.RtReadRtRnSPRm, AddressForm.OffsetReg), + new(0x3C000400, 0x3F600C00, opc1sizeOpc1sizeOpc1sizeConstraints, InstName.StrImmFpsimdPostIndexed, IsaVersion.v80, InstFlags.RtReadRtRnSPFpSimdMemWBack, AddressForm.PostIndexed), + new(0x3C000C00, 0x3F600C00, opc1sizeOpc1sizeOpc1sizeConstraints, InstName.StrImmFpsimdPreIndexed, IsaVersion.v80, InstFlags.RtReadRtRnSPFpSimdMemWBack, AddressForm.PreIndexed), + new(0x3D000000, 0x3F400000, opc1sizeOpc1sizeOpc1sizeConstraints, InstName.StrImmFpsimdUnsignedScaledOffset, IsaVersion.v80, InstFlags.RtReadRtRnSPFpSimd, AddressForm.UnsignedScaled), + new(0xB8000400, 0xBFE00C00, InstName.StrImmGenPostIndexed, IsaVersion.v80, InstFlags.RtReadRtRnSPMemWBack, AddressForm.PostIndexed), + new(0xB8000C00, 0xBFE00C00, InstName.StrImmGenPreIndexed, IsaVersion.v80, InstFlags.RtReadRtRnSPMemWBack, AddressForm.PreIndexed), + new(0xB9000000, 0xBFC00000, InstName.StrImmGenUnsignedScaledOffset, IsaVersion.v80, InstFlags.RtReadRtRnSP, AddressForm.UnsignedScaled), + new(0x3C200800, 0x3F600C00, opc1sizeOpc1sizeOpc1sizeOptionConstraints, InstName.StrRegFpsimd, IsaVersion.v80, InstFlags.RtReadRtRnSPRmFpSimd, AddressForm.OffsetReg), + new(0xB8200800, 0xBFE00C00, optionConstraints, InstName.StrRegGen, IsaVersion.v80, InstFlags.RtReadRtRnSPRm, AddressForm.OffsetReg), + new(0xB8000800, 0xBFE00C00, InstName.Sttr, IsaVersion.v80, InstFlags.RtReadRtRnSP, AddressForm.BasePlusOffset), + new(0x38000800, 0xFFE00C00, InstName.Sttrb, IsaVersion.v80, InstFlags.RtReadRtRnSP, AddressForm.BasePlusOffset), + new(0x78000800, 0xFFE00C00, InstName.Sttrh, IsaVersion.v80, InstFlags.RtReadRtRnSP, AddressForm.BasePlusOffset), + new(0x38000000, 0xFFE00C00, InstName.Sturb, IsaVersion.v80, InstFlags.RtReadRtRnSP, AddressForm.BasePlusOffset), + new(0x78000000, 0xFFE00C00, InstName.Sturh, IsaVersion.v80, InstFlags.RtReadRtRnSP, AddressForm.BasePlusOffset), + new(0x3C000000, 0x3F600C00, opc1sizeOpc1sizeOpc1sizeConstraints, InstName.SturFpsimd, IsaVersion.v80, InstFlags.RtReadRtRnSPFpSimd, AddressForm.BasePlusOffset), + new(0xB8000000, 0xBFE00C00, InstName.SturGen, IsaVersion.v80, InstFlags.RtReadRtRnSP, AddressForm.BasePlusOffset), + new(0x88200000, 0xBFE08000, InstName.Stxp, IsaVersion.v80, InstFlags.RtReadRtRt2RnSPRs, AddressForm.BaseRegister), + new(0x88007C00, 0xBFE0FC00, InstName.Stxr, IsaVersion.v80, InstFlags.RtReadRtRnSPRs, AddressForm.BaseRegister), + new(0x08007C00, 0xFFE0FC00, InstName.Stxrb, IsaVersion.v80, InstFlags.RtReadRtRnSPRs, AddressForm.BaseRegister), + new(0x48007C00, 0xFFE0FC00, InstName.Stxrh, IsaVersion.v80, InstFlags.RtReadRtRnSPRs, AddressForm.BaseRegister), + new(0xD9E00400, 0xFFE00C00, InstName.Stz2gPostIndexed, IsaVersion.v85, InstFlags.MemWBack, AddressForm.PostIndexed), + new(0xD9E00C00, 0xFFE00C00, InstName.Stz2gPreIndexed, IsaVersion.v85, InstFlags.MemWBack, AddressForm.PreIndexed), + new(0xD9E00800, 0xFFE00C00, InstName.Stz2gSignedScaledOffset, IsaVersion.v85, InstFlags.None, AddressForm.SignedScaled), + new(0xD9600400, 0xFFE00C00, InstName.StzgPostIndexed, IsaVersion.v85, InstFlags.MemWBack, AddressForm.PostIndexed), + new(0xD9600C00, 0xFFE00C00, InstName.StzgPreIndexed, IsaVersion.v85, InstFlags.MemWBack, AddressForm.PreIndexed), + new(0xD9600800, 0xFFE00C00, InstName.StzgSignedScaledOffset, IsaVersion.v85, InstFlags.None, AddressForm.SignedScaled), + new(0xD9200000, 0xFFFFFC00, InstName.Stzgm, IsaVersion.v85, InstFlags.None), + new(0xD1800000, 0xFFC0C000, InstName.Subg, IsaVersion.v85, InstFlags.None), + new(0x0E206000, 0xBF20FC00, sizeConstraints, InstName.SubhnAdvsimd, IsaVersion.v80, InstFlags.RdReadRdRnRmFpSimd), + new(0x9AC00000, 0xFFE0FC00, InstName.Subp, IsaVersion.v85, InstFlags.None), + new(0xBAC00000, 0xFFE0FC00, InstName.Subps, IsaVersion.v85, InstFlags.S), + new(0x6B200000, 0x7FE00000, opuOpuOpuConstraints, InstName.SubsAddsubExt, IsaVersion.v80, InstFlags.RdRnSPRmS), + new(0x71000000, 0x7F800000, InstName.SubsAddsubImm, IsaVersion.v80, InstFlags.RdRnSPS), + new(0x6B000000, 0x7F200000, shiftSfimm6Constraints, InstName.SubsAddsubShift, IsaVersion.v80, InstFlags.RdRnRmS), + new(0x4B200000, 0x7FE00000, opuOpuOpuConstraints, InstName.SubAddsubExt, IsaVersion.v80, InstFlags.RdSPRnSPRm), + new(0x51000000, 0x7F800000, InstName.SubAddsubImm, IsaVersion.v80, InstFlags.RdSPRnSP), + new(0x4B000000, 0x7F200000, shiftSfimm6Constraints, InstName.SubAddsubShift, IsaVersion.v80, InstFlags.RdRnRm), + new(0x7EE08400, 0xFFE0FC00, InstName.SubAdvsimdS, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x2E208400, 0xBF20FC00, qsizeConstraints, InstName.SubAdvsimdV, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x0F00F000, 0xBFC0F400, InstName.SudotAdvsimdElt, IsaVersion.v86, InstFlags.RdReadRdRnRmFpSimd), + new(0x5E203800, 0xFF3FFC00, InstName.SuqaddAdvsimdS, IsaVersion.v80, InstFlags.RdReadRdRnQcFpSimd), + new(0x0E203800, 0xBF3FFC00, qsizeConstraints, InstName.SuqaddAdvsimdV, IsaVersion.v80, InstFlags.RdReadRdRnQcFpSimd), + new(0xD4000001, 0xFFE0001F, InstName.Svc, IsaVersion.v80, InstFlags.None), + new(0xB8208000, 0xBF20FC00, InstName.Swp, IsaVersion.v81, InstFlags.RtReadRtRnSPRs), + new(0x38208000, 0xFF20FC00, InstName.Swpb, IsaVersion.v81, InstFlags.RtReadRtRnSPRs), + new(0x78208000, 0xFF20FC00, InstName.Swph, IsaVersion.v81, InstFlags.RtReadRtRnSPRs), + new(0x19208000, 0xFF20FC00, rtRt2Constraints, InstName.Swpp, IsaVersion.None, InstFlags.RtReadRtRt2RnSP), + new(0xD5080000, 0xFFF80000, InstName.Sys, IsaVersion.v80, InstFlags.RtReadRt), + new(0xD5280000, 0xFFF80000, InstName.Sysl, IsaVersion.v80, InstFlags.Rt), + new(0xD5480000, 0xFFF80000, InstName.Sysp, IsaVersion.None, InstFlags.RtReadRt), + new(0x0E000000, 0xBFE09C00, InstName.TblAdvsimd, IsaVersion.v80, InstFlags.RdRnSeqRmFpSimd), + new(0x37000000, 0x7F000000, InstName.Tbnz, IsaVersion.v80, InstFlags.RtReadRt), + new(0x0E001000, 0xBFE09C00, InstName.TbxAdvsimd, IsaVersion.v80, InstFlags.RdRnSeqRmFpSimd), + new(0x36000000, 0x7F000000, InstName.Tbz, IsaVersion.v80, InstFlags.RtReadRt), + new(0xD4600000, 0xFFE0001F, InstName.Tcancel, IsaVersion.None, InstFlags.None), + new(0xD503307F, 0xFFFFFFFF, InstName.Tcommit, IsaVersion.None, InstFlags.None), + new(0x0E002800, 0xBF20FC00, qsizeConstraints, InstName.Trn1Advsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x0E006800, 0xBF20FC00, qsizeConstraints, InstName.Trn2Advsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0xD503225F, 0xFFFFFFFF, InstName.Tsb, IsaVersion.v84, InstFlags.None), + new(0xD5233060, 0xFFFFFFE0, InstName.Tstart, IsaVersion.None, InstFlags.RtReadRt), + new(0xD5233160, 0xFFFFFFE0, InstName.Ttest, IsaVersion.None, InstFlags.RtReadRt), + new(0x2E205000, 0xBF20FC00, sizeConstraints, InstName.UabalAdvsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x2E207C00, 0xBF20FC00, sizeConstraints, InstName.UabaAdvsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x2E207000, 0xBF20FC00, sizeConstraints, InstName.UabdlAdvsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x2E207400, 0xBF20FC00, sizeConstraints, InstName.UabdAdvsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x2E206800, 0xBF3FFC00, sizeConstraints, InstName.UadalpAdvsimd, IsaVersion.v80, InstFlags.RdReadRdRnFpSimd), + new(0x2E202800, 0xBF3FFC00, sizeConstraints, InstName.UaddlpAdvsimd, IsaVersion.v80, InstFlags.RdReadRdRnFpSimd), + new(0x2E303800, 0xBF3FFC00, qsizeSizeConstraints, InstName.UaddlvAdvsimd, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x2E200000, 0xBF20FC00, sizeConstraints, InstName.UaddlAdvsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x2E201000, 0xBF20FC00, sizeConstraints, InstName.UaddwAdvsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x53000000, 0x7F800000, sfnSfnSfimmr5Sfimms5Constraints, InstName.Ubfm, IsaVersion.v80, InstFlags.RdRn), + new(0x7F40E400, 0xFFC0FC00, immhConstraints, InstName.UcvtfAdvsimdFixS, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x7F10E400, 0xFFF0FC00, immhConstraints, InstName.UcvtfAdvsimdFixS, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x7F20E400, 0xFFE0FC00, immhConstraints, InstName.UcvtfAdvsimdFixS, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x2F40E400, 0xBFC0FC00, immhQimmhConstraints, InstName.UcvtfAdvsimdFixV, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x2F10E400, 0xBFF0FC00, immhQimmhConstraints, InstName.UcvtfAdvsimdFixV, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x2F20E400, 0xBFE0FC00, immhQimmhConstraints, InstName.UcvtfAdvsimdFixV, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x7E79D800, 0xFFFFFC00, InstName.UcvtfAdvsimdIntSH, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x7E21D800, 0xFFBFFC00, InstName.UcvtfAdvsimdIntS, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x2E79D800, 0xBFFFFC00, InstName.UcvtfAdvsimdIntVH, IsaVersion.v82, InstFlags.RdRnFpSimd), + new(0x2E21D800, 0xBFBFFC00, qszConstraints, InstName.UcvtfAdvsimdIntV, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x1E030000, 0x7FBF0000, sfscaleConstraints, InstName.UcvtfFloatFix, IsaVersion.v80, InstFlags.RdRnFpSimdFromGpr), + new(0x1EC30000, 0x7FFF0000, sfscaleConstraints, InstName.UcvtfFloatFix, IsaVersion.v80, InstFlags.RdRnFpSimdFromGpr), + new(0x1E230000, 0x7FBFFC00, InstName.UcvtfFloatInt, IsaVersion.v80, InstFlags.RdRnFpSimdFromGpr), + new(0x1EE30000, 0x7FFFFC00, InstName.UcvtfFloatInt, IsaVersion.v80, InstFlags.RdRnFpSimdFromGpr), + new(0x00000000, 0xFFFF0000, InstName.UdfPermUndef, IsaVersion.v80, InstFlags.None), + new(0x1AC00800, 0x7FE0FC00, InstName.Udiv, IsaVersion.v80, InstFlags.RdRnRm), + new(0x2F80E000, 0xBFC0F400, InstName.UdotAdvsimdElt, IsaVersion.v82, InstFlags.RdReadRdRnRmFpSimd), + new(0x2E809400, 0xBFE0FC00, InstName.UdotAdvsimdVec, IsaVersion.v82, InstFlags.RdReadRdRnRmFpSimd), + new(0x2E200400, 0xBF20FC00, sizeConstraints, InstName.UhaddAdvsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x2E202400, 0xBF20FC00, sizeConstraints, InstName.UhsubAdvsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x9BA00000, 0xFFE08000, InstName.Umaddl, IsaVersion.v80, InstFlags.RdRnRmRa), + new(0x2E20A400, 0xBF20FC00, sizeConstraints, InstName.UmaxpAdvsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x2E30A800, 0xBF3FFC00, qsizeSizeConstraints, InstName.UmaxvAdvsimd, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x2E206400, 0xBF20FC00, sizeConstraints, InstName.UmaxAdvsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x11C40000, 0x7FFC0000, InstName.UmaxImm, IsaVersion.v89, InstFlags.RdRn), + new(0x1AC06400, 0x7FE0FC00, InstName.UmaxReg, IsaVersion.v89, InstFlags.RdRnRm), + new(0x2E20AC00, 0xBF20FC00, sizeConstraints, InstName.UminpAdvsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x2E31A800, 0xBF3FFC00, qsizeSizeConstraints, InstName.UminvAdvsimd, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x2E206C00, 0xBF20FC00, sizeConstraints, InstName.UminAdvsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x11CC0000, 0x7FFC0000, InstName.UminImm, IsaVersion.v89, InstFlags.RdRn), + new(0x1AC06C00, 0x7FE0FC00, InstName.UminReg, IsaVersion.v89, InstFlags.RdRnRm), + new(0x2F002000, 0xBF00F400, sizeSizeConstraints, InstName.UmlalAdvsimdElt, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x2E208000, 0xBF20FC00, sizeConstraints, InstName.UmlalAdvsimdVec, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x2F006000, 0xBF00F400, sizeSizeConstraints, InstName.UmlslAdvsimdElt, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x2E20A000, 0xBF20FC00, sizeConstraints, InstName.UmlslAdvsimdVec, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x6E80A400, 0xFFE0FC00, InstName.UmmlaAdvsimdVec, IsaVersion.v86, InstFlags.RdRnRmFpSimd), + new(0x0E013C00, 0xFFE1FC00, InstName.UmovAdvsimd, IsaVersion.v80, InstFlags.RdRnFpSimdToGpr), + new(0x0E023C00, 0xFFE3FC00, InstName.UmovAdvsimd, IsaVersion.v80, InstFlags.RdRnFpSimdToGpr), + new(0x0E043C00, 0xFFE7FC00, InstName.UmovAdvsimd, IsaVersion.v80, InstFlags.RdRnFpSimdToGpr), + new(0x4E083C00, 0xFFEFFC00, InstName.UmovAdvsimd, IsaVersion.v80, InstFlags.RdRnFpSimdToGpr), + new(0x9BA08000, 0xFFE08000, InstName.Umsubl, IsaVersion.v80, InstFlags.RdRnRmRa), + new(0x9BC07C00, 0xFFE0FC00, InstName.Umulh, IsaVersion.v80, InstFlags.RdRnRm), + new(0x2F00A000, 0xBF00F400, sizeSizeConstraints, InstName.UmullAdvsimdElt, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x2E20C000, 0xBF20FC00, sizeConstraints, InstName.UmullAdvsimdVec, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x7E200C00, 0xFF20FC00, InstName.UqaddAdvsimdS, IsaVersion.v80, InstFlags.RdRnRmQcFpSimd), + new(0x2E200C00, 0xBF20FC00, qsizeConstraints, InstName.UqaddAdvsimdV, IsaVersion.v80, InstFlags.RdRnRmQcFpSimd), + new(0x7E205C00, 0xFF20FC00, ssizeSsizeSsizeConstraints, InstName.UqrshlAdvsimdS, IsaVersion.v80, InstFlags.RdRnRmQcFpSimd), + new(0x2E205C00, 0xBF20FC00, qsizeConstraints, InstName.UqrshlAdvsimdV, IsaVersion.v80, InstFlags.RdRnRmQcFpSimd), + new(0x7F009C00, 0xFF80FC00, immhImmhConstraints, InstName.UqrshrnAdvsimdS, IsaVersion.v80, InstFlags.RdReadRdRnQcFpSimd), + new(0x2F009C00, 0xBF80FC00, immhImmhConstraints, InstName.UqrshrnAdvsimdV, IsaVersion.v80, InstFlags.RdReadRdRnQcFpSimd), + new(0x7F007400, 0xFF80FC00, immhOpuConstraints, InstName.UqshlAdvsimdImmS, IsaVersion.v80, InstFlags.RdRnQcFpSimd), + new(0x2F007400, 0xBF80FC00, immhQimmhOpuConstraints, InstName.UqshlAdvsimdImmV, IsaVersion.v80, InstFlags.RdRnQcFpSimd), + new(0x7E204C00, 0xFF20FC00, ssizeSsizeSsizeConstraints, InstName.UqshlAdvsimdRegS, IsaVersion.v80, InstFlags.RdRnRmQcFpSimd), + new(0x2E204C00, 0xBF20FC00, qsizeConstraints, InstName.UqshlAdvsimdRegV, IsaVersion.v80, InstFlags.RdRnRmQcFpSimd), + new(0x7F009400, 0xFF80FC00, immhImmhConstraints, InstName.UqshrnAdvsimdS, IsaVersion.v80, InstFlags.RdReadRdRnQcFpSimd), + new(0x2F009400, 0xBF80FC00, immhImmhConstraints, InstName.UqshrnAdvsimdV, IsaVersion.v80, InstFlags.RdReadRdRnQcFpSimd), + new(0x7E202C00, 0xFF20FC00, InstName.UqsubAdvsimdS, IsaVersion.v80, InstFlags.RdRnRmQcFpSimd), + new(0x2E202C00, 0xBF20FC00, qsizeConstraints, InstName.UqsubAdvsimdV, IsaVersion.v80, InstFlags.RdRnRmQcFpSimd), + new(0x7E214800, 0xFF3FFC00, sizeConstraints, InstName.UqxtnAdvsimdS, IsaVersion.v80, InstFlags.RdReadRdRnQcFpSimd), + new(0x2E214800, 0xBF3FFC00, sizeConstraints, InstName.UqxtnAdvsimdV, IsaVersion.v80, InstFlags.RdReadRdRnQcFpSimd), + new(0x0EA1C800, 0xBFBFFC00, szConstraints, InstName.UrecpeAdvsimd, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x2E201400, 0xBF20FC00, sizeConstraints, InstName.UrhaddAdvsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x7E205400, 0xFF20FC00, ssizeSsizeSsizeConstraints, InstName.UrshlAdvsimdS, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x2E205400, 0xBF20FC00, qsizeConstraints, InstName.UrshlAdvsimdV, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x7F402400, 0xFFC0FC00, immhConstraints, InstName.UrshrAdvsimdS, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x2F002400, 0xBF80FC00, immhQimmhConstraints, InstName.UrshrAdvsimdV, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x2EA1C800, 0xBFBFFC00, szConstraints, InstName.UrsqrteAdvsimd, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x7F403400, 0xFFC0FC00, immhConstraints, InstName.UrsraAdvsimdS, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x2F003400, 0xBF80FC00, immhQimmhConstraints, InstName.UrsraAdvsimdV, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x0F80F000, 0xBFC0F400, InstName.UsdotAdvsimdElt, IsaVersion.v86, InstFlags.RdReadRdRnRmFpSimd), + new(0x0E809C00, 0xBFE0FC00, InstName.UsdotAdvsimdVec, IsaVersion.v86, InstFlags.RdReadRdRnRmFpSimd), + new(0x2F00A400, 0xBF80FC00, immhImmhConstraints, InstName.UshllAdvsimd, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x7E204400, 0xFF20FC00, ssizeSsizeSsizeConstraints, InstName.UshlAdvsimdS, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x2E204400, 0xBF20FC00, qsizeConstraints, InstName.UshlAdvsimdV, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x7F400400, 0xFFC0FC00, immhConstraints, InstName.UshrAdvsimdS, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x2F000400, 0xBF80FC00, immhQimmhConstraints, InstName.UshrAdvsimdV, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x4E80AC00, 0xFFE0FC00, InstName.UsmmlaAdvsimdVec, IsaVersion.v86, InstFlags.RdRnRmFpSimd), + new(0x7E203800, 0xFF3FFC00, InstName.UsqaddAdvsimdS, IsaVersion.v80, InstFlags.RdReadRdRnQcFpSimd), + new(0x2E203800, 0xBF3FFC00, qsizeConstraints, InstName.UsqaddAdvsimdV, IsaVersion.v80, InstFlags.RdReadRdRnQcFpSimd), + new(0x7F401400, 0xFFC0FC00, immhConstraints, InstName.UsraAdvsimdS, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x2F001400, 0xBF80FC00, immhQimmhConstraints, InstName.UsraAdvsimdV, IsaVersion.v80, InstFlags.RdRnFpSimd), + new(0x2E202000, 0xBF20FC00, sizeConstraints, InstName.UsublAdvsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x2E203000, 0xBF20FC00, sizeConstraints, InstName.UsubwAdvsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x0E001800, 0xBF20FC00, qsizeConstraints, InstName.Uzp1Advsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x0E005800, 0xBF20FC00, qsizeConstraints, InstName.Uzp2Advsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0xD503205F, 0xFFFFFFFF, InstName.Wfe, IsaVersion.v80, InstFlags.None), + new(0xD5031000, 0xFFFFFFE0, InstName.Wfet, IsaVersion.v87, InstFlags.Rd), + new(0xD503207F, 0xFFFFFFFF, InstName.Wfi, IsaVersion.v80, InstFlags.None), + new(0xD5031020, 0xFFFFFFE0, InstName.Wfit, IsaVersion.v87, InstFlags.Rd), + new(0xD500403F, 0xFFFFFFFF, InstName.Xaflag, IsaVersion.v85, InstFlags.C), + new(0xCE800000, 0xFFE00000, InstName.XarAdvsimd, IsaVersion.v82, InstFlags.RdRnRmFpSimd), + new(0xDAC143E0, 0xFFFFFBE0, InstName.XpacGeneral, IsaVersion.v83, InstFlags.Rd), + new(0xD50320FF, 0xFFFFFFFF, InstName.XpacSystem, IsaVersion.v83, InstFlags.None), + new(0x0E212800, 0xBF3FFC00, sizeConstraints, InstName.XtnAdvsimd, IsaVersion.v80, InstFlags.RdReadRdRnFpSimd), + new(0xD503203F, 0xFFFFFFFF, InstName.Yield, IsaVersion.v80, InstFlags.None), + new(0x0E003800, 0xBF20FC00, qsizeConstraints, InstName.Zip1Advsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + new(0x0E007800, 0xBF20FC00, qsizeConstraints, InstName.Zip2Advsimd, IsaVersion.v80, InstFlags.RdRnRmFpSimd), + }; + + _table = new(insts); + } + + public static (InstName, InstFlags, AddressForm) GetInstNameAndFlags(uint encoding, IsaVersion version, IsaFeature features) + { + if (_table.TryFind(encoding, version, features, out InstInfo info)) + { + return (info.Name, info.Flags, info.AddressForm); + } + + return new(InstName.UdfPermUndef, InstFlags.None, AddressForm.None); + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Cache/CacheEntry.cs b/src/Ryujinx.Cpu/LightningJit/Cache/CacheEntry.cs new file mode 100644 index 000000000..0249e24b8 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Cache/CacheEntry.cs @@ -0,0 +1,22 @@ +using System; +using System.Diagnostics.CodeAnalysis; + +namespace Ryujinx.Cpu.LightningJit.Cache +{ + readonly struct CacheEntry : IComparable + { + public int Offset { get; } + public int Size { get; } + + public CacheEntry(int offset, int size) + { + Offset = offset; + Size = size; + } + + public int CompareTo([AllowNull] CacheEntry other) + { + return Offset.CompareTo(other.Offset); + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Cache/CacheMemoryAllocator.cs b/src/Ryujinx.Cpu/LightningJit/Cache/CacheMemoryAllocator.cs new file mode 100644 index 000000000..8ba3a6dcd --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Cache/CacheMemoryAllocator.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; + +namespace Ryujinx.Cpu.LightningJit.Cache +{ + class CacheMemoryAllocator + { + private readonly struct MemoryBlock : IComparable + { + public int Offset { get; } + public int Size { get; } + + public MemoryBlock(int offset, int size) + { + Offset = offset; + Size = size; + } + + public int CompareTo([AllowNull] MemoryBlock other) + { + return Offset.CompareTo(other.Offset); + } + } + + private readonly List _blocks = new(); + + public CacheMemoryAllocator(int capacity) + { + _blocks.Add(new MemoryBlock(0, capacity)); + } + + public int Allocate(int size) + { + for (int i = 0; i < _blocks.Count; i++) + { + MemoryBlock block = _blocks[i]; + + if (block.Size > size) + { + _blocks[i] = new(block.Offset + size, block.Size - size); + return block.Offset; + } + else if (block.Size == size) + { + _blocks.RemoveAt(i); + return block.Offset; + } + } + + // We don't have enough free memory to perform the allocation. + return -1; + } + + public void ForceAllocation(int offset, int size) + { + int index = _blocks.BinarySearch(new(offset, size)); + + if (index < 0) + { + index = ~index; + } + + int endOffset = offset + size; + + MemoryBlock block = _blocks[index]; + + Debug.Assert(block.Offset <= offset && block.Offset + block.Size >= endOffset); + + if (offset > block.Offset && endOffset < block.Offset + block.Size) + { + _blocks[index] = new(block.Offset, offset - block.Offset); + _blocks.Insert(index + 1, new(endOffset, (block.Offset + block.Size) - endOffset)); + } + else if (offset > block.Offset) + { + _blocks[index] = new(block.Offset, offset - block.Offset); + } + else if (endOffset < block.Offset + block.Size) + { + _blocks[index] = new(endOffset, (block.Offset + block.Size) - endOffset); + } + else + { + _blocks.RemoveAt(index); + } + } + + public void Free(int offset, int size) + { + Insert(new MemoryBlock(offset, size)); + } + + private void Insert(MemoryBlock block) + { + int index = _blocks.BinarySearch(block); + + if (index < 0) + { + index = ~index; + } + + if (index < _blocks.Count) + { + MemoryBlock next = _blocks[index]; + + int endOffs = block.Offset + block.Size; + + if (next.Offset == endOffs) + { + block = new MemoryBlock(block.Offset, block.Size + next.Size); + _blocks.RemoveAt(index); + } + } + + if (index > 0) + { + MemoryBlock prev = _blocks[index - 1]; + + if (prev.Offset + prev.Size == block.Offset) + { + block = new MemoryBlock(block.Offset - prev.Size, block.Size + prev.Size); + _blocks.RemoveAt(--index); + } + } + + _blocks.Insert(index, block); + } + + public void Clear() + { + _blocks.Clear(); + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Cache/JitCache.cs b/src/Ryujinx.Cpu/LightningJit/Cache/JitCache.cs new file mode 100644 index 000000000..6f1191ca5 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Cache/JitCache.cs @@ -0,0 +1,197 @@ +using ARMeilleure.Memory; +using Ryujinx.Memory; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Runtime.Versioning; + +namespace Ryujinx.Cpu.LightningJit.Cache +{ + static partial class JitCache + { + private static readonly int _pageSize = (int)MemoryBlock.GetPageSize(); + private static readonly int _pageMask = _pageSize - 1; + + private const int CodeAlignment = 4; // Bytes. + private const int CacheSize = 2047 * 1024 * 1024; + + private static ReservedRegion _jitRegion; + private static JitCacheInvalidation _jitCacheInvalidator; + + private static CacheMemoryAllocator _cacheAllocator; + + private static readonly List _cacheEntries = new(); + + private static readonly object _lock = new(); + private static bool _initialized; + + [SupportedOSPlatform("windows")] + [LibraryImport("kernel32.dll", SetLastError = true)] + public static partial IntPtr FlushInstructionCache(IntPtr hProcess, IntPtr lpAddress, UIntPtr dwSize); + + public static void Initialize(IJitMemoryAllocator allocator) + { + if (_initialized) + { + return; + } + + lock (_lock) + { + if (_initialized) + { + return; + } + + _jitRegion = new ReservedRegion(allocator, CacheSize); + + if (!OperatingSystem.IsWindows() && !OperatingSystem.IsMacOS()) + { + _jitCacheInvalidator = new JitCacheInvalidation(allocator); + } + + _cacheAllocator = new CacheMemoryAllocator(CacheSize); + + _initialized = true; + } + } + + public unsafe static IntPtr Map(ReadOnlySpan code) + { + lock (_lock) + { + Debug.Assert(_initialized); + + int funcOffset = Allocate(code.Length); + + IntPtr funcPtr = _jitRegion.Pointer + funcOffset; + + if (OperatingSystem.IsMacOS() && RuntimeInformation.ProcessArchitecture == Architecture.Arm64) + { + unsafe + { + fixed (byte* codePtr = code) + { + JitSupportDarwin.Copy(funcPtr, (IntPtr)codePtr, (ulong)code.Length); + } + } + } + else + { + ReprotectAsWritable(funcOffset, code.Length); + code.CopyTo(new Span((void*)funcPtr, code.Length)); + ReprotectAsExecutable(funcOffset, code.Length); + + if (OperatingSystem.IsWindows() && RuntimeInformation.ProcessArchitecture == Architecture.Arm64) + { + FlushInstructionCache(Process.GetCurrentProcess().Handle, funcPtr, (UIntPtr)code.Length); + } + else + { + _jitCacheInvalidator?.Invalidate(funcPtr, (ulong)code.Length); + } + } + + Add(funcOffset, code.Length); + + return funcPtr; + } + } + + public static void Unmap(IntPtr pointer) + { + lock (_lock) + { + Debug.Assert(_initialized); + + int funcOffset = (int)(pointer.ToInt64() - _jitRegion.Pointer.ToInt64()); + + if (TryFind(funcOffset, out CacheEntry entry, out int entryIndex) && entry.Offset == funcOffset) + { + _cacheAllocator.Free(funcOffset, AlignCodeSize(entry.Size)); + _cacheEntries.RemoveAt(entryIndex); + } + } + } + + private static void ReprotectAsWritable(int offset, int size) + { + int endOffs = offset + size; + + int regionStart = offset & ~_pageMask; + int regionEnd = (endOffs + _pageMask) & ~_pageMask; + + _jitRegion.Block.MapAsRwx((ulong)regionStart, (ulong)(regionEnd - regionStart)); + } + + private static void ReprotectAsExecutable(int offset, int size) + { + int endOffs = offset + size; + + int regionStart = offset & ~_pageMask; + int regionEnd = (endOffs + _pageMask) & ~_pageMask; + + _jitRegion.Block.MapAsRx((ulong)regionStart, (ulong)(regionEnd - regionStart)); + } + + private static int Allocate(int codeSize) + { + codeSize = AlignCodeSize(codeSize); + + int allocOffset = _cacheAllocator.Allocate(codeSize); + + if (allocOffset < 0) + { + throw new OutOfMemoryException("JIT Cache exhausted."); + } + + _jitRegion.ExpandIfNeeded((ulong)allocOffset + (ulong)codeSize); + + return allocOffset; + } + + private static int AlignCodeSize(int codeSize) + { + return checked(codeSize + (CodeAlignment - 1)) & ~(CodeAlignment - 1); + } + + private static void Add(int offset, int size) + { + CacheEntry entry = new(offset, size); + + int index = _cacheEntries.BinarySearch(entry); + + if (index < 0) + { + index = ~index; + } + + _cacheEntries.Insert(index, entry); + } + + public static bool TryFind(int offset, out CacheEntry entry, out int entryIndex) + { + lock (_lock) + { + int index = _cacheEntries.BinarySearch(new CacheEntry(offset, 0)); + + if (index < 0) + { + index = ~index - 1; + } + + if (index >= 0) + { + entry = _cacheEntries[index]; + entryIndex = index; + return true; + } + } + + entry = default; + entryIndex = 0; + return false; + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Cache/JitCacheInvalidation.cs b/src/Ryujinx.Cpu/LightningJit/Cache/JitCacheInvalidation.cs new file mode 100644 index 000000000..cd5f3ede4 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Cache/JitCacheInvalidation.cs @@ -0,0 +1,79 @@ +using ARMeilleure.Memory; +using System; +using System.Runtime.InteropServices; + +namespace Ryujinx.Cpu.LightningJit.Cache +{ + class JitCacheInvalidation + { + private static readonly int[] _invalidationCode = new int[] + { + unchecked((int)0xd53b0022), // mrs x2, ctr_el0 + unchecked((int)0xd3504c44), // ubfx x4, x2, #16, #4 + unchecked((int)0x52800083), // mov w3, #0x4 + unchecked((int)0x12000c45), // and w5, w2, #0xf + unchecked((int)0x1ac42064), // lsl w4, w3, w4 + unchecked((int)0x51000482), // sub w2, w4, #0x1 + unchecked((int)0x8a220002), // bic x2, x0, x2 + unchecked((int)0x1ac52063), // lsl w3, w3, w5 + unchecked((int)0xeb01005f), // cmp x2, x1 + unchecked((int)0x93407c84), // sxtw x4, w4 + unchecked((int)0x540000a2), // b.cs 3c + unchecked((int)0xd50b7b22), // dc cvau, x2 + unchecked((int)0x8b040042), // add x2, x2, x4 + unchecked((int)0xeb02003f), // cmp x1, x2 + unchecked((int)0x54ffffa8), // b.hi 2c + unchecked((int)0xd5033b9f), // dsb ish + unchecked((int)0x51000462), // sub w2, w3, #0x1 + unchecked((int)0x93407c63), // sxtw x3, w3 + unchecked((int)0x8a220000), // bic x0, x0, x2 + unchecked((int)0xeb00003f), // cmp x1, x0 + unchecked((int)0x540000a9), // b.ls 64 + unchecked((int)0xd50b7520), // ic ivau, x0 + unchecked((int)0x8b030000), // add x0, x0, x3 + unchecked((int)0xeb00003f), // cmp x1, x0 + unchecked((int)0x54ffffa8), // b.hi 54 + unchecked((int)0xd5033b9f), // dsb ish + unchecked((int)0xd5033fdf), // isb + unchecked((int)0xd65f03c0), // ret + }; + + private delegate void InvalidateCache(ulong start, ulong end); + + private readonly InvalidateCache _invalidateCache; + private readonly ReservedRegion _invalidateCacheCodeRegion; + + private readonly bool _needsInvalidation; + + public JitCacheInvalidation(IJitMemoryAllocator allocator) + { + // On macOS and Windows, a different path is used to write to the JIT cache, which does the invalidation. + if (RuntimeInformation.ProcessArchitecture == Architecture.Arm64) + { + ulong size = (ulong)_invalidationCode.Length * sizeof(int); + ulong mask = (ulong)ReservedRegion.DefaultGranularity - 1; + + size = (size + mask) & ~mask; + + _invalidateCacheCodeRegion = new ReservedRegion(allocator, size); + _invalidateCacheCodeRegion.ExpandIfNeeded(size); + + Marshal.Copy(_invalidationCode, 0, _invalidateCacheCodeRegion.Pointer, _invalidationCode.Length); + + _invalidateCacheCodeRegion.Block.MapAsRx(0, size); + + _invalidateCache = Marshal.GetDelegateForFunctionPointer(_invalidateCacheCodeRegion.Pointer); + + _needsInvalidation = true; + } + } + + public void Invalidate(IntPtr basePointer, ulong size) + { + if (_needsInvalidation) + { + _invalidateCache((ulong)basePointer, (ulong)basePointer + size); + } + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Cache/JitSupportDarwin.cs b/src/Ryujinx.Cpu/LightningJit/Cache/JitSupportDarwin.cs new file mode 100644 index 000000000..06c81045d --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Cache/JitSupportDarwin.cs @@ -0,0 +1,16 @@ +using System; +using System.Runtime.InteropServices; +using System.Runtime.Versioning; + +namespace Ryujinx.Cpu.LightningJit.Cache +{ + [SupportedOSPlatform("macos")] + static partial class JitSupportDarwin + { + [LibraryImport("libarmeilleure-jitsupport", EntryPoint = "armeilleure_jit_memcpy")] + public static partial void Copy(IntPtr dst, IntPtr src, ulong n); + + [LibraryImport("libc", EntryPoint = "sys_icache_invalidate", SetLastError = true)] + public static partial void SysIcacheInvalidate(IntPtr start, IntPtr len); + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Cache/NoWxCache.cs b/src/Ryujinx.Cpu/LightningJit/Cache/NoWxCache.cs new file mode 100644 index 000000000..a71074995 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Cache/NoWxCache.cs @@ -0,0 +1,340 @@ +using ARMeilleure.Memory; +using Ryujinx.Common; +using Ryujinx.Memory; +using System; +using System.Collections.Generic; +using System.Diagnostics; + +namespace Ryujinx.Cpu.LightningJit.Cache +{ + class NoWxCache : IDisposable + { + private const int CodeAlignment = 4; // Bytes. + private const int SharedCacheSize = 2047 * 1024 * 1024; + private const int LocalCacheSize = 128 * 1024 * 1024; + + // How many calls to the same function we allow until we pad the shared cache to force the function to become available there + // and allow the guest to take the fast path. + private const int MinCallsForPad = 8; + + private class MemoryCache : IDisposable + { + private readonly ReservedRegion _region; + private readonly CacheMemoryAllocator _cacheAllocator; + + public CacheMemoryAllocator Allocator => _cacheAllocator; + public IntPtr Pointer => _region.Block.Pointer; + + public MemoryCache(IJitMemoryAllocator allocator, ulong size) + { + _region = new(allocator, size); + _cacheAllocator = new((int)size); + } + + public int Allocate(int codeSize) + { + codeSize = AlignCodeSize(codeSize); + + int allocOffset = _cacheAllocator.Allocate(codeSize); + + if (allocOffset < 0) + { + throw new OutOfMemoryException("JIT Cache exhausted."); + } + + _region.ExpandIfNeeded((ulong)allocOffset + (ulong)codeSize); + + return allocOffset; + } + + public void Free(int offset, int size) + { + _cacheAllocator.Free(offset, size); + } + + public void ReprotectAsRw(int offset, int size) + { + Debug.Assert(offset >= 0 && (offset & (int)(MemoryBlock.GetPageSize() - 1)) == 0); + Debug.Assert(size > 0 && (size & (int)(MemoryBlock.GetPageSize() - 1)) == 0); + + _region.Block.MapAsRw((ulong)offset, (ulong)size); + } + + public void ReprotectAsRx(int offset, int size) + { + Debug.Assert(offset >= 0 && (offset & (int)(MemoryBlock.GetPageSize() - 1)) == 0); + Debug.Assert(size > 0 && (size & (int)(MemoryBlock.GetPageSize() - 1)) == 0); + + _region.Block.MapAsRx((ulong)offset, (ulong)size); + + if (OperatingSystem.IsMacOS() || OperatingSystem.IsIOS()) + { + JitSupportDarwin.SysIcacheInvalidate(_region.Block.Pointer + offset, size); + } + else + { + throw new PlatformNotSupportedException(); + } + } + + private static int AlignCodeSize(int codeSize) + { + return checked(codeSize + (CodeAlignment - 1)) & ~(CodeAlignment - 1); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + _region.Dispose(); + _cacheAllocator.Clear(); + } + } + + public void Dispose() + { + // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + } + + private readonly IStackWalker _stackWalker; + private readonly Translator _translator; + private readonly MemoryCache _sharedCache; + private readonly MemoryCache _localCache; + private readonly PageAlignedRangeList _pendingMap; + private readonly object _lock; + + class ThreadLocalCacheEntry + { + public readonly int Offset; + public readonly int Size; + public readonly IntPtr FuncPtr; + private int _useCount; + + public ThreadLocalCacheEntry(int offset, int size, IntPtr funcPtr) + { + Offset = offset; + Size = size; + FuncPtr = funcPtr; + _useCount = 0; + } + + public int IncrementUseCount() + { + return ++_useCount; + } + } + + [ThreadStatic] + private static Dictionary _threadLocalCache; + + public NoWxCache(IJitMemoryAllocator allocator, IStackWalker stackWalker, Translator translator) + { + _stackWalker = stackWalker; + _translator = translator; + _sharedCache = new(allocator, SharedCacheSize); + _localCache = new(allocator, LocalCacheSize); + _pendingMap = new(_sharedCache.ReprotectAsRx, RegisterFunction); + _lock = new(); + } + + public unsafe IntPtr Map(IntPtr framePointer, ReadOnlySpan code, ulong guestAddress, ulong guestSize) + { + if (TryGetThreadLocalFunction(guestAddress, out IntPtr funcPtr)) + { + return funcPtr; + } + + lock (_lock) + { + if (!_pendingMap.Has(guestAddress) && !_translator.Functions.ContainsKey(guestAddress)) + { + int funcOffset = _sharedCache.Allocate(code.Length); + + funcPtr = _sharedCache.Pointer + funcOffset; + code.CopyTo(new Span((void*)funcPtr, code.Length)); + + TranslatedFunction function = new(funcPtr, guestSize); + + _pendingMap.Add(funcOffset, code.Length, guestAddress, function); + } + + ClearThreadLocalCache(framePointer); + + return AddThreadLocalFunction(code, guestAddress); + } + } + + public unsafe IntPtr MapPageAligned(ReadOnlySpan code) + { + lock (_lock) + { + // Ensure we will get an aligned offset from the allocator. + _pendingMap.Pad(_sharedCache.Allocator); + + int sizeAligned = BitUtils.AlignUp(code.Length, (int)MemoryBlock.GetPageSize()); + int funcOffset = _sharedCache.Allocate(sizeAligned); + + Debug.Assert((funcOffset & ((int)MemoryBlock.GetPageSize() - 1)) == 0); + + IntPtr funcPtr = _sharedCache.Pointer + funcOffset; + code.CopyTo(new Span((void*)funcPtr, code.Length)); + + _sharedCache.ReprotectAsRx(funcOffset, sizeAligned); + + return funcPtr; + } + } + + private bool TryGetThreadLocalFunction(ulong guestAddress, out IntPtr funcPtr) + { + if ((_threadLocalCache ??= new()).TryGetValue(guestAddress, out var entry)) + { + if (entry.IncrementUseCount() >= MinCallsForPad) + { + // Function is being called often, let's make it available in the shared cache so that the guest code + // can take the fast path and stop calling the emulator to get the function from the thread local cache. + // To do that we pad all "pending" function until they complete a page of memory, allowing us to reprotect them as RX. + + lock (_lock) + { + _pendingMap.Pad(_sharedCache.Allocator); + } + } + + funcPtr = entry.FuncPtr; + + return true; + } + + funcPtr = IntPtr.Zero; + + return false; + } + + private void ClearThreadLocalCache(IntPtr framePointer) + { + // Try to delete functions that are already on the shared cache + // and no longer being executed. + + if (_threadLocalCache == null) + { + return; + } + + IEnumerable callStack = _stackWalker.GetCallStack( + framePointer, + _localCache.Pointer, + LocalCacheSize, + _sharedCache.Pointer, + SharedCacheSize); + + List<(ulong, ThreadLocalCacheEntry)> toDelete = new(); + + foreach ((ulong address, ThreadLocalCacheEntry entry) in _threadLocalCache) + { + // We only want to delete if the function is already on the shared cache, + // otherwise we will keep translating the same function over and over again. + bool canDelete = !_pendingMap.Has(address); + if (!canDelete) + { + continue; + } + + // We can only delete if the function is not part of the current thread call stack, + // otherwise we will crash the program when the thread returns to it. + foreach (ulong funcAddress in callStack) + { + if (funcAddress >= (ulong)entry.FuncPtr && funcAddress < (ulong)entry.FuncPtr + (ulong)entry.Size) + { + canDelete = false; + break; + } + } + + if (canDelete) + { + toDelete.Add((address, entry)); + } + } + + int pageSize = (int)MemoryBlock.GetPageSize(); + + foreach ((ulong address, ThreadLocalCacheEntry entry) in toDelete) + { + _threadLocalCache.Remove(address); + + int sizeAligned = BitUtils.AlignUp(entry.Size, pageSize); + + _localCache.Free(entry.Offset, sizeAligned); + _localCache.ReprotectAsRw(entry.Offset, sizeAligned); + } + } + + public void ClearEntireThreadLocalCache() + { + // Thread is exiting, delete everything. + + if (_threadLocalCache == null) + { + return; + } + + int pageSize = (int)MemoryBlock.GetPageSize(); + + foreach ((_, ThreadLocalCacheEntry entry) in _threadLocalCache) + { + int sizeAligned = BitUtils.AlignUp(entry.Size, pageSize); + + _localCache.Free(entry.Offset, sizeAligned); + _localCache.ReprotectAsRw(entry.Offset, sizeAligned); + } + + _threadLocalCache.Clear(); + _threadLocalCache = null; + } + + private unsafe IntPtr AddThreadLocalFunction(ReadOnlySpan code, ulong guestAddress) + { + int alignedSize = BitUtils.AlignUp(code.Length, (int)MemoryBlock.GetPageSize()); + int funcOffset = _localCache.Allocate(alignedSize); + + Debug.Assert((funcOffset & (int)(MemoryBlock.GetPageSize() - 1)) == 0); + + IntPtr funcPtr = _localCache.Pointer + funcOffset; + code.CopyTo(new Span((void*)funcPtr, code.Length)); + + (_threadLocalCache ??= new()).Add(guestAddress, new(funcOffset, code.Length, funcPtr)); + + _localCache.ReprotectAsRx(funcOffset, alignedSize); + + return funcPtr; + } + + private void RegisterFunction(ulong address, TranslatedFunction func) + { + TranslatedFunction oldFunc = _translator.Functions.GetOrAdd(address, func.GuestSize, func); + + Debug.Assert(oldFunc == func); + + _translator.RegisterFunction(address, func); + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + _localCache.Dispose(); + _sharedCache.Dispose(); + } + } + + public void Dispose() + { + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Cache/PageAlignedRangeList.cs b/src/Ryujinx.Cpu/LightningJit/Cache/PageAlignedRangeList.cs new file mode 100644 index 000000000..b6b386714 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Cache/PageAlignedRangeList.cs @@ -0,0 +1,218 @@ +using Ryujinx.Common; +using Ryujinx.Memory; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; + +namespace Ryujinx.Cpu.LightningJit.Cache +{ + class PageAlignedRangeList + { + private readonly struct Range : IComparable + { + public int Offset { get; } + public int Size { get; } + + public Range(int offset, int size) + { + Offset = offset; + Size = size; + } + + public int CompareTo([AllowNull] Range other) + { + return Offset.CompareTo(other.Offset); + } + } + + private readonly Action _alignedRangeAction; + private readonly Action _alignedFunctionAction; + private readonly List<(Range, ulong, TranslatedFunction)> _pendingFunctions; + private readonly List _ranges; + + public PageAlignedRangeList(Action alignedRangeAction, Action alignedFunctionAction) + { + _alignedRangeAction = alignedRangeAction; + _alignedFunctionAction = alignedFunctionAction; + _pendingFunctions = new(); + _ranges = new(); + } + + public bool Has(ulong address) + { + foreach ((_, ulong guestAddress, _) in _pendingFunctions) + { + if (guestAddress == address) + { + return true; + } + } + + return false; + } + + public void Add(int offset, int size, ulong address, TranslatedFunction function) + { + Range range = new(offset, size); + + Insert(range); + _pendingFunctions.Add((range, address, function)); + ProcessAlignedRanges(); + } + + public void Pad(CacheMemoryAllocator allocator) + { + int pageSize = (int)MemoryBlock.GetPageSize(); + + for (int index = 0; index < _ranges.Count; index++) + { + Range range = _ranges[index]; + + int endOffset = range.Offset + range.Size; + + int alignedStart = BitUtils.AlignDown(range.Offset, pageSize); + int alignedEnd = BitUtils.AlignUp(endOffset, pageSize); + int alignedSize = alignedEnd - alignedStart; + + if (alignedStart < range.Offset) + { + allocator.ForceAllocation(alignedStart, range.Offset - alignedStart); + } + + if (alignedEnd > endOffset) + { + allocator.ForceAllocation(endOffset, alignedEnd - endOffset); + } + + _alignedRangeAction(alignedStart, alignedSize); + _ranges.RemoveAt(index--); + ProcessPendingFunctions(index, alignedEnd); + } + } + + private void ProcessAlignedRanges() + { + int pageSize = (int)MemoryBlock.GetPageSize(); + + for (int index = 0; index < _ranges.Count; index++) + { + Range range = _ranges[index]; + + int alignedStart = BitUtils.AlignUp(range.Offset, pageSize); + int alignedEnd = BitUtils.AlignDown(range.Offset + range.Size, pageSize); + int alignedSize = alignedEnd - alignedStart; + + if (alignedSize <= 0) + { + continue; + } + + _alignedRangeAction(alignedStart, alignedSize); + SplitAt(ref index, alignedStart, alignedEnd); + ProcessPendingFunctions(index, alignedEnd); + } + } + + private void ProcessPendingFunctions(int rangeIndex, int alignedEnd) + { + if ((rangeIndex > 0 && rangeIndex == _ranges.Count) || + (rangeIndex >= 0 && rangeIndex < _ranges.Count && _ranges[rangeIndex].Offset >= alignedEnd)) + { + rangeIndex--; + } + + int alignedStart; + + if (rangeIndex >= 0) + { + alignedStart = _ranges[rangeIndex].Offset + _ranges[rangeIndex].Size; + } + else + { + alignedStart = 0; + } + + if (rangeIndex < _ranges.Count - 1) + { + alignedEnd = _ranges[rangeIndex + 1].Offset; + } + else + { + alignedEnd = int.MaxValue; + } + + for (int index = 0; index < _pendingFunctions.Count; index++) + { + (Range range, ulong address, TranslatedFunction function) = _pendingFunctions[index]; + + if (range.Offset >= alignedStart && range.Offset + range.Size <= alignedEnd) + { + _alignedFunctionAction(address, function); + _pendingFunctions.RemoveAt(index--); + } + } + } + + private void Insert(Range range) + { + int index = _ranges.BinarySearch(range); + + if (index < 0) + { + index = ~index; + } + + if (index < _ranges.Count) + { + Range next = _ranges[index]; + + int endOffs = range.Offset + range.Size; + + if (next.Offset == endOffs) + { + range = new Range(range.Offset, range.Size + next.Size); + _ranges.RemoveAt(index); + } + } + + if (index > 0) + { + Range prev = _ranges[index - 1]; + + if (prev.Offset + prev.Size == range.Offset) + { + range = new Range(range.Offset - prev.Size, range.Size + prev.Size); + _ranges.RemoveAt(--index); + } + } + + _ranges.Insert(index, range); + } + + private void SplitAt(ref int index, int alignedStart, int alignedEnd) + { + Range range = _ranges[index]; + + if (range.Offset < alignedStart) + { + _ranges[index++] = new(range.Offset, alignedStart - range.Offset); + + if (range.Offset + range.Size > alignedEnd) + { + _ranges.Insert(index, new(alignedEnd, (range.Offset + range.Size) - alignedEnd)); + } + } + else if (range.Offset + range.Size > alignedEnd) + { + _ranges[index] = new(alignedEnd, (range.Offset + range.Size) - alignedEnd); + } + else if (range.Offset == alignedStart && range.Offset + range.Size == alignedEnd) + { + Debug.Assert(range.Offset == alignedStart && range.Offset + range.Size == alignedEnd); + + _ranges.RemoveAt(index--); + } + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/CodeGen/Arm64/AbiConstants.cs b/src/Ryujinx.Cpu/LightningJit/CodeGen/Arm64/AbiConstants.cs new file mode 100644 index 000000000..24a646ca9 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/CodeGen/Arm64/AbiConstants.cs @@ -0,0 +1,15 @@ +namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64 +{ + static class AbiConstants + { + // Some of those register have specific roles and can't be used as general purpose registers. + // X18 - Reserved for platform specific usage. + // X29 - Frame pointer. + // X30 - Return address. + // X31 - Not an actual register, in some cases maps to SP, and in others to ZR. + public const uint ReservedRegsMask = (1u << 18) | (1u << 29) | (1u << 30) | (1u << 31); + + public const uint GprCalleeSavedRegsMask = 0x1ff80000; // X19 to X28 + public const uint FpSimdCalleeSavedRegsMask = 0xff00; // D8 to D15 + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/CodeGen/Arm64/ArmCondition.cs b/src/Ryujinx.Cpu/LightningJit/CodeGen/Arm64/ArmCondition.cs new file mode 100644 index 000000000..caa2e593b --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/CodeGen/Arm64/ArmCondition.cs @@ -0,0 +1,30 @@ +namespace Ryujinx.Cpu.LightningJit.CodeGen.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, + } + + static class ArmConditionExtensions + { + public static ArmCondition Invert(this ArmCondition condition) + { + return (ArmCondition)((int)condition ^ 1); + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/CodeGen/Arm64/ArmExtensionType.cs b/src/Ryujinx.Cpu/LightningJit/CodeGen/Arm64/ArmExtensionType.cs new file mode 100644 index 000000000..abcf76785 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/CodeGen/Arm64/ArmExtensionType.cs @@ -0,0 +1,14 @@ +namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64 +{ + enum ArmExtensionType + { + Uxtb = 0, + Uxth = 1, + Uxtw = 2, + Uxtx = 3, + Sxtb = 4, + Sxth = 5, + Sxtw = 6, + Sxtx = 7, + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/CodeGen/Arm64/ArmShiftType.cs b/src/Ryujinx.Cpu/LightningJit/CodeGen/Arm64/ArmShiftType.cs new file mode 100644 index 000000000..348edd483 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/CodeGen/Arm64/ArmShiftType.cs @@ -0,0 +1,11 @@ + +namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64 +{ + enum ArmShiftType + { + Lsl = 0, + Lsr = 1, + Asr = 2, + Ror = 3, + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/CodeGen/Arm64/Assembler.cs b/src/Ryujinx.Cpu/LightningJit/CodeGen/Arm64/Assembler.cs new file mode 100644 index 000000000..28539707f --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/CodeGen/Arm64/Assembler.cs @@ -0,0 +1,4777 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; + +namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64 +{ + struct Assembler + { + private const uint SfFlag = 1u << 31; + + public const int SpRegister = 31; + public const int ZrRegister = 31; + + private readonly List _code; + + private class LabelState + { + public int BranchIndex; + public int TargetIndex; + public bool HasBranch; + public bool HasTarget; + } + + private readonly List _labels; + + public Assembler(CodeWriter writer) + { + _code = writer.GetList(); + _labels = new List(); + } + + public readonly Operand CreateLabel() + { + int labelIndex = _labels.Count; + _labels.Add(new LabelState()); + + return new Operand(OperandKind.Label, OperandType.None, (ulong)labelIndex); + } + + public readonly void MarkLabel(Operand label) + { + int targetIndex = _code.Count; + + var state = _labels[label.AsInt32()]; + + state.TargetIndex = targetIndex; + state.HasTarget = true; + + if (state.HasBranch) + { + int imm = (targetIndex - state.BranchIndex) * sizeof(uint); + uint code = _code[state.BranchIndex]; + + if ((code & 0xfc000000u) == 0x14000000u) + { + _code[state.BranchIndex] = code | EncodeSImm26_2(imm); + } + else + { + _code[state.BranchIndex] = code | (EncodeSImm19_2(imm) << 5); + } + } + } + + // Base + + public readonly void B(Operand label, ArmCondition condition = ArmCondition.Al) + { + int branchIndex = _code.Count; + + var state = _labels[label.AsInt32()]; + + state.BranchIndex = branchIndex; + state.HasBranch = true; + + int imm = 0; + + if (state.HasTarget) + { + imm = (state.TargetIndex - branchIndex) * sizeof(uint); + } + + if (condition == ArmCondition.Al) + { + B(imm); + } + else + { + B(condition, imm); + } + } + + public readonly void Cbz(Operand rt, Operand label) + { + int branchIndex = _code.Count; + + var state = _labels[label.AsInt32()]; + + state.BranchIndex = branchIndex; + state.HasBranch = true; + + int imm = 0; + + if (state.HasTarget) + { + imm = (state.TargetIndex - branchIndex) * sizeof(uint); + } + + Cbz(rt, imm); + } + + public readonly void Cbnz(Operand rt, Operand label) + { + int branchIndex = _code.Count; + + var state = _labels[label.AsInt32()]; + + state.BranchIndex = branchIndex; + state.HasBranch = true; + + int imm = 0; + + if (state.HasTarget) + { + imm = (state.TargetIndex - branchIndex) * sizeof(uint); + } + + Cbnz(rt, imm); + } + + public readonly void Adc(Operand rd, Operand rn, Operand rm) + { + WriteInstructionRm16(0x1a000000u, rd, rn, rm); + } + + public readonly void Adcs(Operand rd, Operand rn, Operand rm) + { + WriteInstructionRm16(0x3a000000u, rd, rn, rm); + } + + public readonly void Add(Operand rd, Operand rn, Operand rm, ArmExtensionType extensionType, int shiftAmount = 0) + { + WriteInstructionAuto(0x0b200000u, rd, rn, rm, extensionType, shiftAmount); + } + + public readonly void Add(Operand rd, Operand rn, Operand rm) + { + Add(rd, rn, rm, ArmShiftType.Lsl, 0); + } + + public readonly void Add(Operand rd, Operand rn, Operand rm, ArmShiftType shiftType, int shiftAmount) + { + Add(rd, rn, rm, shiftType, shiftAmount, false); + } + + public readonly void Add(Operand rd, Operand rn, Operand rm, ArmShiftType shiftType, int shiftAmount, bool immForm) + { + WriteInstructionAuto(0x11000000u, 0x0b000000u, rd, rn, rm, shiftType, shiftAmount, immForm); + } + + public readonly void Adds(Operand rd, Operand rn, Operand rm) + { + Adds(rd, rn, rm, ArmShiftType.Lsl, 0); + } + + public readonly void Adds(Operand rd, Operand rn, Operand rm, ArmShiftType shiftType, int shiftAmount) + { + Adds(rd, rn, rm, shiftType, shiftAmount, false); + } + + public readonly void Adds(Operand rd, Operand rn, Operand rm, ArmShiftType shiftType, int shiftAmount, bool immForm) + { + WriteInstructionAuto(0x31000000u, 0x2b000000u, rd, rn, rm, shiftType, shiftAmount, immForm); + } + + public readonly void And(Operand rd, Operand rn, Operand rm) + { + And(rd, rn, rm, ArmShiftType.Lsl, 0); + } + + public readonly void And(Operand rd, Operand rn, Operand rm, ArmShiftType shiftType, int shiftAmount) + { + WriteInstructionBitwiseAuto(0x12000000u, 0x0a000000u, rd, rn, rm, shiftType, shiftAmount); + } + + public readonly void Ands(Operand rd, Operand rn, Operand rm) + { + Ands(rd, rn, rm, ArmShiftType.Lsl, 0); + } + + public readonly void Ands(Operand rd, Operand rn, Operand rm, ArmShiftType shiftType, int shiftAmount) + { + WriteInstructionBitwiseAuto(0x72000000u, 0x6a000000u, rd, rn, rm, shiftType, shiftAmount); + } + + public readonly void Asr(Operand rd, Operand rn, Operand rm) + { + if (rm.Kind == OperandKind.Constant) + { + int shift = rm.AsInt32(); + int mask = rd.Type == OperandType.I64 ? 63 : 31; + shift &= mask; + Sbfm(rd, rn, shift, mask); + } + else + { + Asrv(rd, rn, rm); + } + } + + public readonly void Asrv(Operand rd, Operand rn, Operand rm) + { + WriteInstructionBitwiseAuto(0x1ac02800u, rd, rn, rm); + } + + public readonly void B(int imm) + { + WriteUInt32(0x14000000u | EncodeSImm26_2(imm)); + } + + public readonly void B(ArmCondition condition, int imm) + { + WriteUInt32(0x54000000u | (uint)condition | (EncodeSImm19_2(imm) << 5)); + } + + public readonly void Bfc(Operand rd, int lsb, int width) + { + Bfi(rd, new Operand(ZrRegister, RegisterType.Integer, OperandType.I32), lsb, width); + } + + public readonly void Bfi(Operand rd, Operand rn, int lsb, int width) + { + Bfm(rd, rn, -lsb & 31, width - 1); + } + + public readonly void Bfm(Operand rd, Operand rn, int immr, int imms) + { + WriteInstruction(0x33000000u | (EncodeUImm6(imms) << 10) | (EncodeUImm6(immr) << 16), rd, rn); + } + + public readonly void Bfxil(Operand rd, Operand rn, int lsb, int width) + { + Bfm(rd, rn, lsb, lsb + width - 1); + } + + public readonly void Bic(Operand rd, Operand rn, Operand rm) + { + Bic(rd, rn, rm, ArmShiftType.Lsl, 0); + } + + public readonly void Bic(Operand rd, Operand rn, Operand rm, ArmShiftType shiftType, int shiftAmount) + { + WriteInstructionAuto(0x0a200000u, rd, rn, rm, shiftType, shiftAmount); + } + + public readonly void Bics(Operand rd, Operand rn, Operand rm) + { + Bics(rd, rn, rm, ArmShiftType.Lsl, 0); + } + + public readonly void Bics(Operand rd, Operand rn, Operand rm, ArmShiftType shiftType, int shiftAmount) + { + WriteInstructionAuto(0x6a200000u, rd, rn, rm, shiftType, shiftAmount); + } + + public readonly void Blr(Operand rn) + { + WriteUInt32(0xd63f0000u | (EncodeReg(rn) << 5)); + } + + public readonly void Br(Operand rn) + { + WriteUInt32(0xd61f0000u | (EncodeReg(rn) << 5)); + } + + public readonly void Brk() + { + WriteUInt32(0xd4200000u); + } + + public readonly void Cbz(Operand rt, int imm) + { + WriteInstructionAuto(0x34000000u | (EncodeSImm19_2(imm) << 5), rt); + } + + public readonly void Cbnz(Operand rt, int imm) + { + WriteInstructionAuto(0x35000000u | (EncodeSImm19_2(imm) << 5), rt); + } + + public readonly void Crc32(Operand rd, Operand rn, Operand rm, uint sz) + { + Debug.Assert(sz <= 3); + WriteInstructionRm16(0x1ac04000u | (sz << 10), rd, rn, rm); + } + + public readonly void Crc32c(Operand rd, Operand rn, Operand rm, uint sz) + { + Debug.Assert(sz <= 3); + WriteInstructionRm16(0x1ac05000u | (sz << 10), rd, rn, rm); + } + + public readonly void Clrex(int crm = 15) + { + WriteUInt32(0xd503305fu | (EncodeUImm4(crm) << 8)); + } + + public readonly void Clz(Operand rd, Operand rn) + { + WriteInstructionAuto(0x5ac01000u, rd, rn); + } + + public readonly void Cmn(Operand rn, Operand rm) + { + Cmn(rn, rm, ArmShiftType.Lsl, 0); + } + + public readonly void Cmn(Operand rn, Operand rm, ArmShiftType shiftType, int shiftAmount) + { + Adds(new Operand(ZrRegister, RegisterType.Integer, rn.Type), rn, rm, shiftType, shiftAmount); + } + + public readonly void Cmp(Operand rn, Operand rm) + { + Cmp(rn, rm, ArmShiftType.Lsl, 0); + } + + public readonly void Cmp(Operand rn, Operand rm, ArmShiftType shiftType, int shiftAmount) + { + Subs(new Operand(ZrRegister, RegisterType.Integer, rn.Type), rn, rm, shiftType, shiftAmount); + } + + public readonly void Csdb() + { + WriteUInt32(0xd503229fu); + } + + public readonly void Csel(Operand rd, Operand rn, Operand rm, ArmCondition condition) + { + WriteInstructionBitwiseAuto(0x1a800000u | ((uint)condition << 12), rd, rn, rm); + } + + public readonly void Cset(Operand rd, ArmCondition condition) + { + var zr = new Operand(ZrRegister, RegisterType.Integer, rd.Type); + Csinc(rd, zr, zr, (ArmCondition)((int)condition ^ 1)); + } + + public readonly void Csinc(Operand rd, Operand rn, Operand rm, ArmCondition condition) + { + WriteInstructionBitwiseAuto(0x1a800400u | ((uint)condition << 12), rd, rn, rm); + } + + public readonly void Dmb(uint option) + { + WriteUInt32(0xd50330bfu | (option << 8)); + } + + public readonly void Dsb(uint option) + { + WriteUInt32(0xd503309fu | (option << 8)); + } + + public readonly void Eor(Operand rd, Operand rn, Operand rm) + { + Eor(rd, rn, rm, ArmShiftType.Lsl, 0); + } + + public readonly void Eor(Operand rd, Operand rn, Operand rm, ArmShiftType shiftType, int shiftAmount) + { + WriteInstructionBitwiseAuto(0x52000000u, 0x4a000000u, rd, rn, rm, shiftType, shiftAmount); + } + + public readonly void Eors(Operand rd, Operand rn, Operand rm) + { + Eors(rd, rn, rm, ArmShiftType.Lsl, 0); + } + + public readonly void Eors(Operand rd, Operand rn, Operand rm, ArmShiftType shiftType, int shiftAmount) + { + Eor(rd, rn, rm, shiftType, shiftAmount); + Tst(rd, rd); + } + + public readonly void Esb() + { + WriteUInt32(0xd503221fu); + } + + public readonly void Extr(Operand rd, Operand rn, Operand rm, int imms) + { + uint n = rd.Type == OperandType.I64 ? 1u << 22 : 0u; + WriteInstructionBitwiseAuto(0x13800000u | n | (EncodeUImm6(imms) << 10), rd, rn, rm); + } + + public readonly void Isb(uint option) + { + WriteUInt32(0xd50330dfu | (option << 8)); + } + + public readonly void Ldar(Operand rt, Operand rn) + { + WriteInstruction(0x88dffc00u | ((rt.Type == OperandType.I64 ? 3u : 2u) << 30), rt, rn); + } + + public readonly void Ldarb(Operand rt, Operand rn) + { + WriteInstruction(0x08dffc00u, rt, rn); + } + + public readonly void Ldarh(Operand rt, Operand rn) + { + WriteInstruction(0x48dffc00u, rt, rn); + } + + public readonly void Ldaxp(Operand rt, Operand rt2, Operand rn) + { + WriteInstruction(0x887f8000u | ((rt.Type == OperandType.I64 ? 3u : 2u) << 30), rt, rn, rt2); + } + + public readonly void Ldaxr(Operand rt, Operand rn) + { + WriteInstruction(0x885ffc00u | ((rt.Type == OperandType.I64 ? 3u : 2u) << 30), rt, rn); + } + + public readonly void Ldaxrb(Operand rt, Operand rn) + { + WriteInstruction(0x085ffc00u, rt, rn); + } + + public readonly void Ldaxrh(Operand rt, Operand rn) + { + WriteInstruction(0x485ffc00u, rt, rn); + } + + public readonly void LdpRiPost(Operand rt, Operand rt2, Operand rn, int imm) + { + uint instruction = GetLdpStpInstruction(0x28c00000u, 0x2cc00000u, imm, rt.Type); + WriteInstruction(instruction, rt, rn, rt2); + } + + public readonly void LdpRiPre(Operand rt, Operand rt2, Operand rn, int imm) + { + uint instruction = GetLdpStpInstruction(0x29c00000u, 0x2dc00000u, imm, rt.Type); + WriteInstruction(instruction, rt, rn, rt2); + } + + public readonly void LdpRiUn(Operand rt, Operand rt2, Operand rn, int imm) + { + uint instruction = GetLdpStpInstruction(0x29400000u, 0x2d400000u, imm, rt.Type); + WriteInstruction(instruction, rt, rn, rt2); + } + + public readonly void LdrLit(Operand rt, int offset) + { + uint instruction = 0x18000000u | (EncodeSImm19_2(offset) << 5); + + if (rt.Type == OperandType.I64) + { + instruction |= 1u << 30; + } + + WriteInstruction(instruction, rt); + } + + public readonly void LdrRiPost(Operand rt, Operand rn, int imm) + { + uint instruction = GetLdrStrInstruction(0xb8400400u, 0x3c400400u, rt.Type) | (EncodeSImm9(imm) << 12); + WriteInstruction(instruction, rt, rn); + } + + public readonly void LdrRiPre(Operand rt, Operand rn, int imm) + { + uint instruction = GetLdrStrInstruction(0xb8400c00u, 0x3c400c00u, rt.Type) | (EncodeSImm9(imm) << 12); + WriteInstruction(instruction, rt, rn); + } + + public readonly void LdrRiUn(Operand rt, Operand rn, int imm) + { + uint instruction = GetLdrStrInstruction(0xb9400000u, 0x3d400000u, rt.Type) | (EncodeUImm12(imm, rt.Type) << 10); + WriteInstruction(instruction, rt, rn); + } + + public readonly void LdrRiUn(Operand rt, Operand rn, int imm, uint size) + { + uint instruction = GetLdrStrInstruction(0xb9400000u, 0x3d400000u, rt.Type, size) | (EncodeUImm12(imm, (int)size) << 10); + WriteInstruction(instruction, rt, rn); + } + + public readonly void LdrRr(Operand rt, Operand rn, Operand rm, ArmExtensionType extensionType, bool shift) + { + uint instruction = GetLdrStrInstruction(0xb8600800u, 0x3ce00800u, rt.Type); + WriteInstructionLdrStrAuto(instruction, rt, rn, rm, extensionType, shift); + } + + public readonly void LdrbRiPost(Operand rt, Operand rn, int imm) + { + uint instruction = 0x38400400u | (EncodeSImm9(imm) << 12); + WriteInstruction(instruction, rt, rn); + } + + public readonly void LdrbRiPre(Operand rt, Operand rn, int imm) + { + uint instruction = 0x38400c00u | (EncodeSImm9(imm) << 12); + WriteInstruction(instruction, rt, rn); + } + + public readonly void LdrbRiUn(Operand rt, Operand rn, int imm) + { + uint instruction = 0x39400000u | (EncodeUImm12(imm, 0) << 10); + WriteInstruction(instruction, rt, rn); + } + + public readonly void LdrhRiPost(Operand rt, Operand rn, int imm) + { + uint instruction = 0x78400400u | (EncodeSImm9(imm) << 12); + WriteInstruction(instruction, rt, rn); + } + + public readonly void LdrhRiPre(Operand rt, Operand rn, int imm) + { + uint instruction = 0x78400c00u | (EncodeSImm9(imm) << 12); + WriteInstruction(instruction, rt, rn); + } + + public readonly void LdrhRiUn(Operand rt, Operand rn, int imm) + { + uint instruction = 0x79400000u | (EncodeUImm12(imm, 1) << 10); + WriteInstruction(instruction, rt, rn); + } + + public readonly void LdrsbRiPost(Operand rt, Operand rn, int imm) + { + WriteInstruction(0x38800400u | (EncodeSImm9(imm) << 12), rt, rn); + } + + public readonly void LdrsbRiPre(Operand rt, Operand rn, int imm) + { + WriteInstruction(0x38800c00u | (EncodeSImm9(imm) << 12), rt, rn); + } + + public readonly void LdrsbRiUn(Operand rt, Operand rn, int imm) + { + WriteInstruction(0x39800000u | (EncodeUImm12(imm, 0) << 10), rt, rn); + } + + public readonly void LdrshRiPost(Operand rt, Operand rn, int imm) + { + WriteInstruction(0x78800400u | (EncodeSImm9(imm) << 12), rt, rn); + } + + public readonly void LdrshRiPre(Operand rt, Operand rn, int imm) + { + WriteInstruction(0x78800c00u | (EncodeSImm9(imm) << 12), rt, rn); + } + + public readonly void LdrshRiUn(Operand rt, Operand rn, int imm) + { + WriteInstruction(0x79800000u | (EncodeUImm12(imm, 1) << 10), rt, rn); + } + + public readonly void LdrswRiPost(Operand rt, Operand rn, int imm) + { + WriteInstruction(0xb8800400u | (EncodeSImm9(imm) << 12), rt, rn); + } + + public readonly void LdrswRiPre(Operand rt, Operand rn, int imm) + { + WriteInstruction(0xb8800c00u | (EncodeSImm9(imm) << 12), rt, rn); + } + + public readonly void LdrswRiUn(Operand rt, Operand rn, int imm) + { + WriteInstruction(0xb9800000u | (EncodeUImm12(imm, 2) << 10), rt, rn); + } + + public readonly void Ldur(Operand rt, Operand rn, int imm) + { + uint instruction = GetLdrStrInstruction(0xb8400000u, 0x3c400000u, rt.Type) | (EncodeSImm9(imm) << 12); + WriteInstruction(instruction, rt, rn); + } + + public readonly void Ldur(Operand rt, Operand rn, int imm, uint size) + { + uint instruction = GetLdrStrInstruction(0xb8400000u, 0x3c400000u, rt.Type, size) | (EncodeSImm9(imm) << 12); + WriteInstruction(instruction, rt, rn); + } + + public readonly void Ldurb(Operand rt, Operand rn, int imm) + { + uint instruction = 0x38400000u | (EncodeSImm9(imm) << 12); + WriteInstruction(instruction, rt, rn); + } + + public readonly void Ldurh(Operand rt, Operand rn, int imm) + { + uint instruction = 0x78400000u | (EncodeSImm9(imm) << 12); + WriteInstruction(instruction, rt, rn); + } + + public readonly void Ldursb(Operand rt, Operand rn, int imm) + { + uint instruction = 0x38800000u | (EncodeSImm9(imm) << 12); + WriteInstruction(instruction, rt, rn); + } + + public readonly void Ldursh(Operand rt, Operand rn, int imm) + { + uint instruction = 0x78800000u | (EncodeSImm9(imm) << 12); + WriteInstruction(instruction, rt, rn); + } + + public readonly void Ldursw(Operand rt, Operand rn, int imm) + { + uint instruction = 0xb8800000u | (EncodeSImm9(imm) << 12); + WriteInstruction(instruction, rt, rn); + } + + public readonly void Lsl(Operand rd, Operand rn, Operand rm) + { + if (rm.Kind == OperandKind.Constant) + { + int shift = rm.AsInt32(); + int mask = rd.Type == OperandType.I64 ? 63 : 31; + shift &= mask; + Ubfm(rd, rn, -shift & mask, mask - shift); + } + else + { + Lslv(rd, rn, rm); + } + } + + public readonly void Lslv(Operand rd, Operand rn, Operand rm) + { + WriteInstructionBitwiseAuto(0x1ac02000u, rd, rn, rm); + } + + public readonly void Lsr(Operand rd, Operand rn, Operand rm) + { + if (rm.Kind == OperandKind.Constant) + { + int shift = rm.AsInt32(); + int mask = rd.Type == OperandType.I64 ? 63 : 31; + shift &= mask; + Ubfm(rd, rn, shift, mask); + } + else + { + Lsrv(rd, rn, rm); + } + } + + public readonly void Lsrv(Operand rd, Operand rn, Operand rm) + { + WriteInstructionBitwiseAuto(0x1ac02400u, rd, rn, rm); + } + + public readonly void Madd(Operand rd, Operand rn, Operand rm, Operand ra) + { + WriteInstructionAuto(0x1b000000u, rd, rn, rm, ra); + } + + public readonly void Msub(Operand rd, Operand rn, Operand rm, Operand ra) + { + WriteInstructionAuto(0x1b008000u, rd, rn, rm, ra); + } + + public readonly void Mul(Operand rd, Operand rn, Operand rm) + { + Madd(rd, rn, rm, new Operand(ZrRegister, RegisterType.Integer, rd.Type)); + } + + public readonly void Mov(Operand rd, Operand rn) + { + Debug.Assert(rd.Type.IsInteger()); + Orr(rd, new Operand(ZrRegister, RegisterType.Integer, rd.Type), rn); + } + + public readonly void MovSp(Operand rd, Operand rn) + { + if (rd.GetRegister().Index == SpRegister || + rn.GetRegister().Index == SpRegister) + { + Add(rd, rn, new Operand(rd.Type, 0), ArmShiftType.Lsl, 0, immForm: true); + } + else + { + Mov(rd, rn); + } + } + + public readonly void Mov(Operand rd, ulong value) + { + if (value == 0) + { + Mov(rd, new Operand(ZrRegister, RegisterType.Integer, rd.Type)); + } + else if (CodeGenCommon.TryEncodeBitMask(rd.Type, value, out _, out _, out _)) + { + Orr(rd, new Operand(ZrRegister, RegisterType.Integer, rd.Type), new Operand(OperandKind.Constant, rd.Type, value)); + } + else if (value == ulong.MaxValue || (value == uint.MaxValue && rd.Type == OperandType.I32)) + { + Mvn(rd, new Operand(ZrRegister, RegisterType.Integer, rd.Type)); + } + else + { + int hw = 0; + bool first = true; + + while (value != 0) + { + int valueLow = (ushort)value; + if (valueLow != 0) + { + if (first) + { + Movz(rd, valueLow, hw); + first = false; + } + else + { + Movk(rd, valueLow, hw); + } + } + + hw++; + value >>= 16; + } + } + } + + public readonly void Mov(Operand rd, int imm) + { + Movz(rd, imm, 0); + } + + public readonly void Movz(Operand rd, int imm, int hw) + { + Debug.Assert((hw & (rd.Type == OperandType.I64 ? 3 : 1)) == hw); + WriteInstructionAuto(0x52800000u | (EncodeUImm16(imm) << 5) | ((uint)hw << 21), rd); + } + + public readonly void Movk(Operand rd, int imm, int hw) + { + Debug.Assert((hw & (rd.Type == OperandType.I64 ? 3 : 1)) == hw); + WriteInstructionAuto(0x72800000u | (EncodeUImm16(imm) << 5) | ((uint)hw << 21), rd); + } + + public readonly void Mrs(Operand rt, uint o0, uint op1, uint crn, uint crm, uint op2) + { + WriteSysRegInstruction(0xd5300000u, rt, o0, op1, crn, crm, op2); + } + + public readonly void MrsNzcv(Operand rt) + { + WriteInstruction(0xd53b4200u, rt); + } + + public readonly void MrsFpcr(Operand rt) + { + WriteInstruction(0xd53b4400u, rt); + } + + public readonly void MrsFpsr(Operand rt) + { + WriteInstruction(0xd53b4420u, rt); + } + + public readonly void MrsTpidrEl0(Operand rt) + { + WriteInstruction(0xd53bd040u, rt); + } + + public readonly void MrsTpidrroEl0(Operand rt) + { + WriteInstruction(0xd53bd060u, rt); + } + + public readonly void Msr(Operand rt, uint o0, uint op1, uint crn, uint crm, uint op2) + { + WriteSysRegInstruction(0xd5100000u, rt, o0, op1, crn, crm, op2); + } + + public readonly void MsrNzcv(Operand rt) + { + WriteInstruction(0xd51b4200u, rt); + } + + public readonly void MsrFpcr(Operand rt) + { + WriteInstruction(0xd51b4400, rt); + } + + public readonly void MsrFpsr(Operand rt) + { + WriteInstruction(0xd51b4420, rt); + } + + public readonly void Mvn(Operand rd, Operand rn, ArmShiftType shiftType = ArmShiftType.Lsl, int shiftAmount = 0) + { + Orn(rd, new Operand(ZrRegister, RegisterType.Integer, rd.Type), rn, shiftType, shiftAmount); + } + + public readonly void Neg(Operand rd, Operand rn, ArmShiftType shiftType = ArmShiftType.Lsl, int shiftAmount = 0) + { + Sub(rd, new Operand(ZrRegister, RegisterType.Integer, rd.Type), rn, shiftType, shiftAmount); + } + + public readonly void Negs(Operand rd, Operand rn, ArmShiftType shiftType = ArmShiftType.Lsl, int shiftAmount = 0) + { + Subs(rd, new Operand(ZrRegister, RegisterType.Integer, rd.Type), rn, shiftType, shiftAmount); + } + + public readonly void Orn(Operand rd, Operand rn, Operand rm) + { + Orn(rd, rn, rm, ArmShiftType.Lsl, 0); + } + + public readonly void Orn(Operand rd, Operand rn, Operand rm, ArmShiftType shiftType, int shiftAmount) + { + WriteInstructionBitwiseAuto(0x2a200000u, rd, rn, rm, shiftType, shiftAmount); + } + + public readonly void Orns(Operand rd, Operand rn, Operand rm) + { + Orns(rd, rn, rm, ArmShiftType.Lsl, 0); + } + + public readonly void Orns(Operand rd, Operand rn, Operand rm, ArmShiftType shiftType, int shiftAmount) + { + Orn(rd, rn, rm, shiftType, shiftAmount); + Tst(rd, rd); + } + + public readonly void Orr(Operand rd, Operand rn, Operand rm) + { + Orr(rd, rn, rm, ArmShiftType.Lsl, 0); + } + + public readonly void Orr(Operand rd, Operand rn, Operand rm, ArmShiftType shiftType, int shiftAmount) + { + WriteInstructionBitwiseAuto(0x32000000u, 0x2a000000u, rd, rn, rm, shiftType, shiftAmount); + } + + public readonly void Orrs(Operand rd, Operand rn, Operand rm) + { + Orrs(rd, rn, rm, ArmShiftType.Lsl, 0); + } + + public readonly void Orrs(Operand rd, Operand rn, Operand rm, ArmShiftType shiftType, int shiftAmount) + { + Orr(rd, rn, rm, shiftType, shiftAmount); + Tst(rd, rd); + } + + public readonly void PrfmI(Operand rn, int imm, uint type, uint target, uint policy) + { + Operand rt = new Operand((int)EncodeTypeTargetPolicy(type, target, policy), RegisterType.Integer, OperandType.I32); + WriteInstruction(0xf9800000u | (EncodeUImm12(imm, 3) << 10), rt, rn); + } + + public readonly void PrfmR(Operand rt, Operand rn) + { + WriteInstruction(0xf8a04800u, rt, rn); + } + + public readonly void Prfum(Operand rn, int imm, uint type, uint target, uint policy) + { + Operand rt = new Operand((int)EncodeTypeTargetPolicy(type, target, policy), RegisterType.Integer, OperandType.I32); + WriteInstruction(0xf8800000u | (EncodeSImm9(imm) << 12), rt, rn); + } + + public readonly void Rbit(Operand rd, Operand rn) + { + WriteInstructionAuto(0x5ac00000u, rd, rn); + } + + public readonly void Ret() + { + Ret(new Operand(30, RegisterType.Integer, OperandType.I64)); + } + + public readonly void Ret(Operand rn) + { + WriteUInt32(0xd65f0000u | (EncodeReg(rn) << 5)); + } + + public readonly void Rev(Operand rd, Operand rn) + { + uint opc0 = rd.Type == OperandType.I64 ? 1u << 10 : 0u; + WriteInstructionAuto(0x5ac00800u | opc0, rd, rn); + } + + public readonly void Rev16(Operand rd, Operand rn) + { + WriteInstructionAuto(0x5ac00400u, rd, rn); + } + + public readonly void Rev32(Operand rd, Operand rn) + { + WriteInstructionAuto(0xdac00800u, rd, rn); + } + + public readonly void Ror(Operand rd, Operand rn, Operand rm) + { + if (rm.Kind == OperandKind.Constant) + { + int shift = rm.AsInt32(); + int mask = rd.Type == OperandType.I64 ? 63 : 31; + shift &= mask; + Extr(rd, rn, rn, shift); + } + else + { + Rorv(rd, rn, rm); + } + } + + public readonly void Rorv(Operand rd, Operand rn, Operand rm) + { + WriteInstructionBitwiseAuto(0x1ac02c00u, rd, rn, rm); + } + + public readonly void Sbc(Operand rd, Operand rn, Operand rm) + { + WriteInstructionRm16(0x5a000000u, rd, rn, rm); + } + + public readonly void Sbcs(Operand rd, Operand rn, Operand rm) + { + WriteInstructionRm16(0x7a000000u, rd, rn, rm); + } + + public readonly void Sbfm(Operand rd, Operand rn, int immr, int imms) + { + uint n = rd.Type == OperandType.I64 ? 1u << 22 : 0u; + WriteInstructionAuto(0x13000000u | n | (EncodeUImm6(imms) << 10) | (EncodeUImm6(immr) << 16), rd, rn); + } + + public readonly void Sbfx(Operand rd, Operand rn, int lsb, int width) + { + Sbfm(rd, rn, lsb, lsb + width - 1); + } + + public readonly void Sdiv(Operand rd, Operand rn, Operand rm) + { + WriteInstructionRm16Auto(0x1ac00c00u, rd, rn, rm); + } + + public readonly void Sev() + { + WriteUInt32(0xd503209fu); + } + + public readonly void Sevl() + { + WriteUInt32(0xd50320bfu); + } + + public readonly void Smaddl(Operand rd, Operand rn, Operand rm, Operand ra) + { + WriteInstruction(0x9b200000u, rd, rn, rm, ra); + } + + public readonly void Smsubl(Operand rd, Operand rn, Operand rm, Operand ra) + { + WriteInstruction(0x9b208000u, rd, rn, rm, ra); + } + + public readonly void Smulh(Operand rd, Operand rn, Operand rm) + { + WriteInstructionRm16(0x9b407c00u, rd, rn, rm); + } + + public readonly void Smull(Operand rd, Operand rn, Operand rm) + { + Smaddl(rd, rn, rm, new Operand(ZrRegister, RegisterType.Integer, rd.Type)); + } + + public readonly void Stlr(Operand rt, Operand rn) + { + WriteInstruction(0x889ffc00u | ((rt.Type == OperandType.I64 ? 3u : 2u) << 30), rt, rn); + } + + public readonly void Stlrb(Operand rt, Operand rn) + { + WriteInstruction(0x089ffc00u, rt, rn); + } + + public readonly void Stlrh(Operand rt, Operand rn) + { + WriteInstruction(0x489ffc00u, rt, rn); + } + + public readonly void Stlxp(Operand rs, Operand rt, Operand rt2, Operand rn) + { + WriteInstruction(0x88208000u | ((rt.Type == OperandType.I64 ? 3u : 2u) << 30), rt, rn, rs, rt2); + } + + public readonly void Stlxr(Operand rs, Operand rt, Operand rn) + { + WriteInstructionRm16(0x8800fc00u | ((rt.Type == OperandType.I64 ? 3u : 2u) << 30), rt, rn, rs); + } + + public readonly void Stlxrb(Operand rs, Operand rt, Operand rn) + { + WriteInstructionRm16(0x0800fc00u, rt, rn, rs); + } + + public readonly void Stlxrh(Operand rs, Operand rt, Operand rn) + { + WriteInstructionRm16(0x4800fc00u, rt, rn, rs); + } + + public readonly void StpRiPost(Operand rt, Operand rt2, Operand rn, int imm) + { + uint instruction = GetLdpStpInstruction(0x28800000u, 0x2c800000u, imm, rt.Type); + WriteInstruction(instruction, rt, rn, rt2); + } + + public readonly void StpRiPre(Operand rt, Operand rt2, Operand rn, int imm) + { + uint instruction = GetLdpStpInstruction(0x29800000u, 0x2d800000u, imm, rt.Type); + WriteInstruction(instruction, rt, rn, rt2); + } + + public readonly void StpRiUn(Operand rt, Operand rt2, Operand rn, int imm) + { + uint instruction = GetLdpStpInstruction(0x29000000u, 0x2d000000u, imm, rt.Type); + WriteInstruction(instruction, rt, rn, rt2); + } + + public readonly void StrRiPost(Operand rt, Operand rn, int imm) + { + uint instruction = GetLdrStrInstruction(0xb8000400u, 0x3c000400u, rt.Type) | (EncodeSImm9(imm) << 12); + WriteInstruction(instruction, rt, rn); + } + + public readonly void StrRiPre(Operand rt, Operand rn, int imm) + { + uint instruction = GetLdrStrInstruction(0xb8000c00u, 0x3c000c00u, rt.Type) | (EncodeSImm9(imm) << 12); + WriteInstruction(instruction, rt, rn); + } + + public readonly void StrRiUn(Operand rt, Operand rn, int imm) + { + uint instruction = GetLdrStrInstruction(0xb9000000u, 0x3d000000u, rt.Type) | (EncodeUImm12(imm, rt.Type) << 10); + WriteInstruction(instruction, rt, rn); + } + + public readonly void StrRiUn(Operand rt, Operand rn, int imm, uint size) + { + uint instruction = GetLdrStrInstruction(0xb9000000u, 0x3d000000u, rt.Type, size) | (EncodeUImm12(imm, (int)size) << 10); + WriteInstruction(instruction, rt, rn); + } + + public readonly void StrRr(Operand rt, Operand rn, Operand rm, ArmExtensionType extensionType, bool shift) + { + uint instruction = GetLdrStrInstruction(0xb8200800u, 0x3ca00800u, rt.Type); + WriteInstructionLdrStrAuto(instruction, rt, rn, rm, extensionType, shift); + } + + public readonly void StrbRiPost(Operand rt, Operand rn, int imm) + { + uint instruction = 0x38000400u | (EncodeSImm9(imm) << 12); + WriteInstruction(instruction, rt, rn); + } + + public readonly void StrbRiPre(Operand rt, Operand rn, int imm) + { + uint instruction = 0x38000c00u | (EncodeSImm9(imm) << 12); + WriteInstruction(instruction, rt, rn); + } + + public readonly void StrbRiUn(Operand rt, Operand rn, int imm) + { + uint instruction = 0x39000000u | (EncodeUImm12(imm, 0) << 10); + WriteInstruction(instruction, rt, rn); + } + + public readonly void StrhRiPost(Operand rt, Operand rn, int imm) + { + uint instruction = 0x78000400u | (EncodeSImm9(imm) << 12); + WriteInstruction(instruction, rt, rn); + } + + public readonly void StrhRiPre(Operand rt, Operand rn, int imm) + { + uint instruction = 0x78000c00u | (EncodeSImm9(imm) << 12); + WriteInstruction(instruction, rt, rn); + } + + public readonly void StrhRiUn(Operand rt, Operand rn, int imm) + { + uint instruction = 0x79000000u | (EncodeUImm12(imm, 1) << 10); + WriteInstruction(instruction, rt, rn); + } + + public readonly void Stur(Operand rt, Operand rn, int imm) + { + uint instruction = GetLdrStrInstruction(0xb8000000u, 0x3c000000u, rt.Type) | (EncodeSImm9(imm) << 12); + WriteInstruction(instruction, rt, rn); + } + + public readonly void Stur(Operand rt, Operand rn, int imm, uint size) + { + uint instruction = GetLdrStrInstruction(0xb8000000u, 0x3c000000u, rt.Type, size) | (EncodeSImm9(imm) << 12); + WriteInstruction(instruction, rt, rn); + } + + public readonly void Sturb(Operand rt, Operand rn, int imm) + { + uint instruction = 0x38000000u | (EncodeSImm9(imm) << 12); + WriteInstruction(instruction, rt, rn); + } + + public readonly void Sturh(Operand rt, Operand rn, int imm) + { + uint instruction = 0x78000000u | (EncodeSImm9(imm) << 12); + WriteInstruction(instruction, rt, rn); + } + + public readonly void Sub(Operand rd, Operand rn, Operand rm, ArmExtensionType extensionType, int shiftAmount = 0) + { + WriteInstructionAuto(0x4b200000u, rd, rn, rm, extensionType, shiftAmount); + } + + public readonly void Sub(Operand rd, Operand rn, Operand rm) + { + Sub(rd, rn, rm, ArmShiftType.Lsl, 0); + } + + public readonly void Sub(Operand rd, Operand rn, Operand rm, ArmShiftType shiftType, int shiftAmount) + { + WriteInstructionAuto(0x51000000u, 0x4b000000u, rd, rn, rm, shiftType, shiftAmount); + } + + public readonly void Subs(Operand rd, Operand rn, Operand rm) + { + Subs(rd, rn, rm, ArmShiftType.Lsl, 0); + } + + public readonly void Subs(Operand rd, Operand rn, Operand rm, ArmShiftType shiftType, int shiftAmount) + { + WriteInstructionAuto(0x71000000u, 0x6b000000u, rd, rn, rm, shiftType, shiftAmount); + } + + public readonly void Sxtb(Operand rd, Operand rn) + { + Sbfm(rd, rn, 0, 7); + } + + public readonly void Sxth(Operand rd, Operand rn) + { + Sbfm(rd, rn, 0, 15); + } + + public readonly void Sxtw(Operand rd, Operand rn) + { + Sbfm(rd, rn, 0, 31); + } + + public readonly void Tsb() + { + WriteUInt32(0xd503225fu); + } + + public readonly void Tst(Operand rn, Operand rm) + { + Tst(rn, rm, ArmShiftType.Lsl, 0); + } + + public readonly void Tst(Operand rn, Operand rm, ArmShiftType shiftType, int shiftAmount) + { + Ands(new Operand(ZrRegister, RegisterType.Integer, rn.Type), rn, rm, shiftType, shiftAmount); + } + + public readonly void Ubfm(Operand rd, Operand rn, int immr, int imms) + { + uint n = rd.Type == OperandType.I64 ? 1u << 22 : 0u; + WriteInstructionAuto(0x53000000u | n | (EncodeUImm6(imms) << 10) | (EncodeUImm6(immr) << 16), rd, rn); + } + + public readonly void Ubfx(Operand rd, Operand rn, int lsb, int width) + { + Ubfm(rd, rn, lsb, lsb + width - 1); + } + + public readonly void Udiv(Operand rd, Operand rn, Operand rm) + { + WriteInstructionRm16Auto(0x1ac00800u, rd, rn, rm); + } + + public readonly void Umaddl(Operand rd, Operand rn, Operand rm, Operand ra) + { + WriteInstructionAuto(0x9ba00000u, rd, rn, rm, ra); + } + + public readonly void Umulh(Operand rd, Operand rn, Operand rm) + { + WriteInstructionRm16(0x9bc07c00u, rd, rn, rm); + } + + public readonly void Umull(Operand rd, Operand rn, Operand rm) + { + Umaddl(rd, rn, rm, new Operand(ZrRegister, RegisterType.Integer, rd.Type)); + } + + public readonly void Uxtb(Operand rd, Operand rn) + { + Ubfm(rd, rn, 0, 7); + } + + public readonly void Uxth(Operand rd, Operand rn) + { + Ubfm(rd, rn, 0, 15); + } + + // FP & SIMD + + public readonly void AbsS(Operand rd, Operand rn, uint size) + { + WriteInstruction(0x5e20b800u | (size << 22), rd, rn); + } + + public readonly void AbsV(Operand rd, Operand rn, uint size, uint q) + { + WriteInstruction(0x0e20b800u | (size << 22) | (q << 30), rd, rn); + } + + public readonly void Addhn(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0e204000u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void AddpPair(Operand rd, Operand rn, uint size) + { + WriteInstruction(0x5e31b800u | (size << 22), rd, rn); + } + + public readonly void AddpVec(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0e20bc00u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void Addv(Operand rd, Operand rn, uint size, uint q) + { + WriteInstruction(0x0e31b800u | (size << 22) | (q << 30), rd, rn); + } + + public readonly void AddS(Operand rd, Operand rn, Operand rm, uint size) + { + WriteInstructionRm16(0x5e208400u | (size << 22), rd, rn, rm); + } + + public readonly void AddV(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0e208400u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void Aesd(Operand rd, Operand rn) + { + WriteInstruction(0x4e285800u, rd, rn); + } + + public readonly void Aese(Operand rd, Operand rn) + { + WriteInstruction(0x4e284800u, rd, rn); + } + + public readonly void Aesimc(Operand rd, Operand rn) + { + WriteInstruction(0x4e287800u, rd, rn); + } + + public readonly void Aesmc(Operand rd, Operand rn) + { + WriteInstruction(0x4e286800u, rd, rn); + } + + public readonly void And(Operand rd, Operand rn, Operand rm, uint q) + { + WriteInstructionRm16(0x0e201c00u | (q << 30), rd, rn, rm); + } + + public readonly void Bcax(Operand rd, Operand rn, Operand rm, Operand ra) + { + WriteInstruction(0xce200000u, rd, rn, rm, ra); + } + + public readonly void Bfcvtn(Operand rd, Operand rn, uint q) + { + WriteInstruction(0x0ea16800u | (q << 30), rd, rn); + } + + public readonly void BfcvtFloat(Operand rd, Operand rn) + { + WriteInstruction(0x1e634000u, rd, rn); + } + + public readonly void BfdotElt(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l, uint q) + { + WriteInstructionRm16(0x0f40f000u | (h << 11) | (m << 20) | (l << 21) | (q << 30), rd, rn, rm); + } + + public readonly void BfdotVec(Operand rd, Operand rn, Operand rm, uint q) + { + WriteInstructionRm16(0x2e40fc00u | (q << 30), rd, rn, rm); + } + + public readonly void BfmlalElt(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l, uint q) + { + WriteInstructionRm16(0x0fc0f000u | (h << 11) | (m << 20) | (l << 21) | (q << 30), rd, rn, rm); + } + + public readonly void BfmlalVec(Operand rd, Operand rn, Operand rm, uint q) + { + WriteInstructionRm16(0x2ec0fc00u | (q << 30), rd, rn, rm); + } + + public readonly void Bfmmla(Operand rd, Operand rn, Operand rm) + { + WriteInstructionRm16(0x6e40ec00u, rd, rn, rm); + } + + public readonly void BicImm(Operand rd, uint h, uint g, uint f, uint e, uint d, uint c, uint b, uint a, uint q) + { + WriteInstruction(0x2f001400u | (h << 5) | (g << 6) | (f << 7) | (e << 8) | (d << 9) | (c << 16) | (b << 17) | (a << 18) | (q << 30), rd); + } + + public readonly void BicReg(Operand rd, Operand rn, Operand rm, uint q) + { + WriteInstructionRm16(0x0e601c00u | (q << 30), rd, rn, rm); + } + + public readonly void Bif(Operand rd, Operand rn, Operand rm, uint q) + { + WriteInstructionRm16(0x2ee01c00u | (q << 30), rd, rn, rm); + } + + public readonly void Bit(Operand rd, Operand rn, Operand rm, uint q) + { + WriteInstructionRm16(0x2ea01c00u | (q << 30), rd, rn, rm); + } + + public readonly void Bsl(Operand rd, Operand rn, Operand rm, uint q) + { + WriteInstructionRm16(0x2e601c00u | (q << 30), rd, rn, rm); + } + + public readonly void Cls(Operand rd, Operand rn, uint size, uint q) + { + WriteInstruction(0x0e204800u | (size << 22) | (q << 30), rd, rn); + } + + public readonly void Clz(Operand rd, Operand rn, uint size, uint q) + { + WriteInstruction(0x2e204800u | (size << 22) | (q << 30), rd, rn); + } + + public readonly void CmeqRegS(Operand rd, Operand rn, Operand rm, uint size) + { + WriteInstructionRm16(0x7e208c00u | (size << 22), rd, rn, rm); + } + + public readonly void CmeqRegV(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x2e208c00u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void CmeqZeroS(Operand rd, Operand rn, uint size) + { + WriteInstruction(0x5e209800u | (size << 22), rd, rn); + } + + public readonly void CmeqZeroV(Operand rd, Operand rn, uint size, uint q) + { + WriteInstruction(0x0e209800u | (size << 22) | (q << 30), rd, rn); + } + + public readonly void CmgeRegS(Operand rd, Operand rn, Operand rm, uint size) + { + WriteInstructionRm16(0x5e203c00u | (size << 22), rd, rn, rm); + } + + public readonly void CmgeRegV(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0e203c00u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void CmgeZeroS(Operand rd, Operand rn, uint size) + { + WriteInstruction(0x7e208800u | (size << 22), rd, rn); + } + + public readonly void CmgeZeroV(Operand rd, Operand rn, uint size, uint q) + { + WriteInstruction(0x2e208800u | (size << 22) | (q << 30), rd, rn); + } + + public readonly void CmgtRegS(Operand rd, Operand rn, Operand rm, uint size) + { + WriteInstructionRm16(0x5e203400u | (size << 22), rd, rn, rm); + } + + public readonly void CmgtRegV(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0e203400u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void CmgtZeroS(Operand rd, Operand rn, uint size) + { + WriteInstruction(0x5e208800u | (size << 22), rd, rn); + } + + public readonly void CmgtZeroV(Operand rd, Operand rn, uint size, uint q) + { + WriteInstruction(0x0e208800u | (size << 22) | (q << 30), rd, rn); + } + + public readonly void CmhiS(Operand rd, Operand rn, Operand rm, uint size) + { + WriteInstructionRm16(0x7e203400u | (size << 22), rd, rn, rm); + } + + public readonly void CmhiV(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x2e203400u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void CmhsS(Operand rd, Operand rn, Operand rm, uint size) + { + WriteInstructionRm16(0x7e203c00u | (size << 22), rd, rn, rm); + } + + public readonly void CmhsV(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x2e203c00u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void CmleS(Operand rd, Operand rn, uint size) + { + WriteInstruction(0x7e209800u | (size << 22), rd, rn); + } + + public readonly void CmleV(Operand rd, Operand rn, uint size, uint q) + { + WriteInstruction(0x2e209800u | (size << 22) | (q << 30), rd, rn); + } + + public readonly void CmltS(Operand rd, Operand rn, uint size) + { + WriteInstruction(0x5e20a800u | (size << 22), rd, rn); + } + + public readonly void CmltV(Operand rd, Operand rn, uint size, uint q) + { + WriteInstruction(0x0e20a800u | (size << 22) | (q << 30), rd, rn); + } + + public readonly void CmtstS(Operand rd, Operand rn, Operand rm, uint size) + { + WriteInstructionRm16(0x5e208c00u | (size << 22), rd, rn, rm); + } + + public readonly void CmtstV(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0e208c00u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void Cnt(Operand rd, Operand rn, uint size, uint q) + { + WriteInstruction(0x0e205800u | (size << 22) | (q << 30), rd, rn); + } + + public readonly void DupEltScalarFromElement(Operand rd, Operand rn, uint imm5) + { + WriteInstruction(0x5e000400u | (imm5 << 16), rd, rn); + } + + public readonly void DupEltVectorFromElement(Operand rd, Operand rn, uint imm5, uint q) + { + WriteInstruction(0x0e000400u | (imm5 << 16) | (q << 30), rd, rn); + } + + public readonly void DupGen(Operand rd, Operand rn, uint imm5, uint q) + { + WriteInstruction(0x0e000c00u | (imm5 << 16) | (q << 30), rd, rn); + } + + public readonly void Eor3(Operand rd, Operand rn, Operand rm, Operand ra) + { + WriteInstruction(0xce000000u, rd, rn, rm, ra); + } + + public readonly void Eor(Operand rd, Operand rn, Operand rm, uint q) + { + WriteInstructionRm16(0x2e201c00u | (q << 30), rd, rn, rm); + } + + public readonly void Ext(Operand rd, Operand rn, uint imm4, Operand rm, uint q) + { + WriteInstructionRm16(0x2e000000u | (imm4 << 11) | (q << 30), rd, rn, rm); + } + + public readonly void FabdSH(Operand rd, Operand rn, Operand rm) + { + WriteInstructionRm16(0x7ec01400u, rd, rn, rm); + } + + public readonly void FabdS(Operand rd, Operand rn, Operand rm, uint sz) + { + WriteInstructionRm16(0x7ea0d400u | (sz << 22), rd, rn, rm); + } + + public readonly void FabdVH(Operand rd, Operand rn, Operand rm, uint q) + { + WriteInstructionRm16(0x2ec01400u | (q << 30), rd, rn, rm); + } + + public readonly void FabdV(Operand rd, Operand rn, Operand rm, uint sz, uint q) + { + WriteInstructionRm16(0x2ea0d400u | (sz << 22) | (q << 30), rd, rn, rm); + } + + public readonly void FabsHalf(Operand rd, Operand rn, uint q) + { + WriteInstruction(0x0ef8f800u | (q << 30), rd, rn); + } + + public readonly void FabsSingleAndDouble(Operand rd, Operand rn, uint sz, uint q) + { + WriteInstruction(0x0ea0f800u | (sz << 22) | (q << 30), rd, rn); + } + + public readonly void FabsFloat(Operand rd, Operand rn, uint ftype) + { + WriteInstruction(0x1e20c000u | (ftype << 22), rd, rn); + } + + public readonly void FacgeSH(Operand rd, Operand rn, Operand rm) + { + WriteInstructionRm16(0x7e402c00u, rd, rn, rm); + } + + public readonly void FacgeS(Operand rd, Operand rn, Operand rm, uint sz) + { + WriteInstructionRm16(0x7e20ec00u | (sz << 22), rd, rn, rm); + } + + public readonly void FacgeVH(Operand rd, Operand rn, Operand rm, uint q) + { + WriteInstructionRm16(0x2e402c00u | (q << 30), rd, rn, rm); + } + + public readonly void FacgeV(Operand rd, Operand rn, Operand rm, uint sz, uint q) + { + WriteInstructionRm16(0x2e20ec00u | (sz << 22) | (q << 30), rd, rn, rm); + } + + public readonly void FacgtSH(Operand rd, Operand rn, Operand rm) + { + WriteInstructionRm16(0x7ec02c00u, rd, rn, rm); + } + + public readonly void FacgtS(Operand rd, Operand rn, Operand rm, uint sz) + { + WriteInstructionRm16(0x7ea0ec00u | (sz << 22), rd, rn, rm); + } + + public readonly void FacgtVH(Operand rd, Operand rn, Operand rm, uint q) + { + WriteInstructionRm16(0x2ec02c00u | (q << 30), rd, rn, rm); + } + + public readonly void FacgtV(Operand rd, Operand rn, Operand rm, uint sz, uint q) + { + WriteInstructionRm16(0x2ea0ec00u | (sz << 22) | (q << 30), rd, rn, rm); + } + + public readonly void FaddpPairHalf(Operand rd, Operand rn, uint sz) + { + WriteInstruction(0x5e30d800u | (sz << 22), rd, rn); + } + + public readonly void FaddpPairSingleAndDouble(Operand rd, Operand rn, uint sz) + { + WriteInstruction(0x7e30d800u | (sz << 22), rd, rn); + } + + public readonly void FaddpVecHalf(Operand rd, Operand rn, Operand rm, uint q) + { + WriteInstructionRm16(0x2e401400u | (q << 30), rd, rn, rm); + } + + public readonly void FaddpVecSingleAndDouble(Operand rd, Operand rn, Operand rm, uint sz, uint q) + { + WriteInstructionRm16(0x2e20d400u | (sz << 22) | (q << 30), rd, rn, rm); + } + + public readonly void FaddHalf(Operand rd, Operand rn, Operand rm, uint q) + { + WriteInstructionRm16(0x0e401400u | (q << 30), rd, rn, rm); + } + + public readonly void FaddSingleAndDouble(Operand rd, Operand rn, Operand rm, uint sz, uint q) + { + WriteInstructionRm16(0x0e20d400u | (sz << 22) | (q << 30), rd, rn, rm); + } + + public readonly void FaddFloat(Operand rd, Operand rn, Operand rm, uint ftype) + { + WriteInstructionRm16(0x1e202800u | (ftype << 22), rd, rn, rm); + } + + public readonly void FcaddVec(Operand rd, Operand rn, uint rot, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x2e00e400u | (rot << 12) | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void FccmpeFloat(uint nzcv, Operand rn, uint cond, Operand rm, uint ftype) + { + WriteInstructionRm16(0x1e200410u | (nzcv << 0) | (cond << 12) | (ftype << 22), rn, rm); + } + + public readonly void FccmpFloat(uint nzcv, Operand rn, uint cond, Operand rm, uint ftype) + { + WriteInstructionRm16(0x1e200400u | (nzcv << 0) | (cond << 12) | (ftype << 22), rn, rm); + } + + public readonly void FcmeqRegSH(Operand rd, Operand rn, Operand rm) + { + WriteInstructionRm16(0x5e402400u, rd, rn, rm); + } + + public readonly void FcmeqRegS(Operand rd, Operand rn, Operand rm, uint sz) + { + WriteInstructionRm16(0x5e20e400u | (sz << 22), rd, rn, rm); + } + + public readonly void FcmeqRegVH(Operand rd, Operand rn, Operand rm, uint q) + { + WriteInstructionRm16(0x0e402400u | (q << 30), rd, rn, rm); + } + + public readonly void FcmeqRegV(Operand rd, Operand rn, Operand rm, uint sz, uint q) + { + WriteInstructionRm16(0x0e20e400u | (sz << 22) | (q << 30), rd, rn, rm); + } + + public readonly void FcmeqZeroSH(Operand rd, Operand rn) + { + WriteInstruction(0x5ef8d800u, rd, rn); + } + + public readonly void FcmeqZeroS(Operand rd, Operand rn, uint sz) + { + WriteInstruction(0x5ea0d800u | (sz << 22), rd, rn); + } + + public readonly void FcmeqZeroVH(Operand rd, Operand rn, uint q) + { + WriteInstruction(0x0ef8d800u | (q << 30), rd, rn); + } + + public readonly void FcmeqZeroV(Operand rd, Operand rn, uint sz, uint q) + { + WriteInstruction(0x0ea0d800u | (sz << 22) | (q << 30), rd, rn); + } + + public readonly void FcmgeRegSH(Operand rd, Operand rn, Operand rm) + { + WriteInstructionRm16(0x7e402400u, rd, rn, rm); + } + + public readonly void FcmgeRegS(Operand rd, Operand rn, Operand rm, uint sz) + { + WriteInstructionRm16(0x7e20e400u | (sz << 22), rd, rn, rm); + } + + public readonly void FcmgeRegVH(Operand rd, Operand rn, Operand rm, uint q) + { + WriteInstructionRm16(0x2e402400u | (q << 30), rd, rn, rm); + } + + public readonly void FcmgeRegV(Operand rd, Operand rn, Operand rm, uint sz, uint q) + { + WriteInstructionRm16(0x2e20e400u | (sz << 22) | (q << 30), rd, rn, rm); + } + + public readonly void FcmgeZeroSH(Operand rd, Operand rn) + { + WriteInstruction(0x7ef8c800u, rd, rn); + } + + public readonly void FcmgeZeroS(Operand rd, Operand rn, uint sz) + { + WriteInstruction(0x7ea0c800u | (sz << 22), rd, rn); + } + + public readonly void FcmgeZeroVH(Operand rd, Operand rn, uint q) + { + WriteInstruction(0x2ef8c800u | (q << 30), rd, rn); + } + + public readonly void FcmgeZeroV(Operand rd, Operand rn, uint sz, uint q) + { + WriteInstruction(0x2ea0c800u | (sz << 22) | (q << 30), rd, rn); + } + + public readonly void FcmgtRegSH(Operand rd, Operand rn, Operand rm) + { + WriteInstructionRm16(0x7ec02400u, rd, rn, rm); + } + + public readonly void FcmgtRegS(Operand rd, Operand rn, Operand rm, uint sz) + { + WriteInstructionRm16(0x7ea0e400u | (sz << 22), rd, rn, rm); + } + + public readonly void FcmgtRegVH(Operand rd, Operand rn, Operand rm, uint q) + { + WriteInstructionRm16(0x2ec02400u | (q << 30), rd, rn, rm); + } + + public readonly void FcmgtRegV(Operand rd, Operand rn, Operand rm, uint sz, uint q) + { + WriteInstructionRm16(0x2ea0e400u | (sz << 22) | (q << 30), rd, rn, rm); + } + + public readonly void FcmgtZeroSH(Operand rd, Operand rn) + { + WriteInstruction(0x5ef8c800u, rd, rn); + } + + public readonly void FcmgtZeroS(Operand rd, Operand rn, uint sz) + { + WriteInstruction(0x5ea0c800u | (sz << 22), rd, rn); + } + + public readonly void FcmgtZeroVH(Operand rd, Operand rn, uint q) + { + WriteInstruction(0x0ef8c800u | (q << 30), rd, rn); + } + + public readonly void FcmgtZeroV(Operand rd, Operand rn, uint sz, uint q) + { + WriteInstruction(0x0ea0c800u | (sz << 22) | (q << 30), rd, rn); + } + + public readonly void FcmlaElt(Operand rd, Operand rn, uint h, uint rot, Operand rm, uint m, uint l, uint size, uint q) + { + WriteInstructionRm16(0x2f001000u | (h << 11) | (rot << 13) | (m << 20) | (l << 21) | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void FcmlaVec(Operand rd, Operand rn, uint rot, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x2e00c400u | (rot << 11) | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void FcmleSH(Operand rd, Operand rn) + { + WriteInstruction(0x7ef8d800u, rd, rn); + } + + public readonly void FcmleS(Operand rd, Operand rn, uint sz) + { + WriteInstruction(0x7ea0d800u | (sz << 22), rd, rn); + } + + public readonly void FcmleVH(Operand rd, Operand rn, uint q) + { + WriteInstruction(0x2ef8d800u | (q << 30), rd, rn); + } + + public readonly void FcmleV(Operand rd, Operand rn, uint sz, uint q) + { + WriteInstruction(0x2ea0d800u | (sz << 22) | (q << 30), rd, rn); + } + + public readonly void FcmltSH(Operand rd, Operand rn) + { + WriteInstruction(0x5ef8e800u, rd, rn); + } + + public readonly void FcmltS(Operand rd, Operand rn, uint sz) + { + WriteInstruction(0x5ea0e800u | (sz << 22), rd, rn); + } + + public readonly void FcmltVH(Operand rd, Operand rn, uint q) + { + WriteInstruction(0x0ef8e800u | (q << 30), rd, rn); + } + + public readonly void FcmltV(Operand rd, Operand rn, uint sz, uint q) + { + WriteInstruction(0x0ea0e800u | (sz << 22) | (q << 30), rd, rn); + } + + public readonly void FcmpeFloat(Operand rn, Operand rm, uint opc, uint ftype) + { + WriteInstructionRm16(0x1e202010u | (opc << 3) | (ftype << 22), rn, rm); + } + + public readonly void FcmpFloat(Operand rn, Operand rm, uint opc, uint ftype) + { + WriteInstructionRm16(0x1e202000u | (opc << 3) | (ftype << 22), rn, rm); + } + + public readonly void FcselFloat(Operand rd, Operand rn, uint cond, Operand rm, uint ftype) + { + WriteInstructionRm16(0x1e200c00u | (cond << 12) | (ftype << 22), rd, rn, rm); + } + + public readonly void FcvtasSH(Operand rd, Operand rn) + { + WriteInstruction(0x5e79c800u, rd, rn); + } + + public readonly void FcvtasS(Operand rd, Operand rn, uint sz) + { + WriteInstruction(0x5e21c800u | (sz << 22), rd, rn); + } + + public readonly void FcvtasVH(Operand rd, Operand rn, uint q) + { + WriteInstruction(0x0e79c800u | (q << 30), rd, rn); + } + + public readonly void FcvtasV(Operand rd, Operand rn, uint sz, uint q) + { + WriteInstruction(0x0e21c800u | (sz << 22) | (q << 30), rd, rn); + } + + public readonly void FcvtasFloat(Operand rd, Operand rn, uint ftype, uint sf) + { + WriteInstruction(0x1e240000u | (ftype << 22) | (sf << 31), rd, rn); + } + + public readonly void FcvtauSH(Operand rd, Operand rn) + { + WriteInstruction(0x7e79c800u, rd, rn); + } + + public readonly void FcvtauS(Operand rd, Operand rn, uint sz) + { + WriteInstruction(0x7e21c800u | (sz << 22), rd, rn); + } + + public readonly void FcvtauVH(Operand rd, Operand rn, uint q) + { + WriteInstruction(0x2e79c800u | (q << 30), rd, rn); + } + + public readonly void FcvtauV(Operand rd, Operand rn, uint sz, uint q) + { + WriteInstruction(0x2e21c800u | (sz << 22) | (q << 30), rd, rn); + } + + public readonly void FcvtauFloat(Operand rd, Operand rn, uint ftype, uint sf) + { + WriteInstruction(0x1e250000u | (ftype << 22) | (sf << 31), rd, rn); + } + + public readonly void Fcvtl(Operand rd, Operand rn, uint sz, uint q) + { + WriteInstruction(0x0e217800u | (sz << 22) | (q << 30), rd, rn); + } + + public readonly void FcvtmsSH(Operand rd, Operand rn) + { + WriteInstruction(0x5e79b800u, rd, rn); + } + + public readonly void FcvtmsS(Operand rd, Operand rn, uint sz) + { + WriteInstruction(0x5e21b800u | (sz << 22), rd, rn); + } + + public readonly void FcvtmsVH(Operand rd, Operand rn, uint q) + { + WriteInstruction(0x0e79b800u | (q << 30), rd, rn); + } + + public readonly void FcvtmsV(Operand rd, Operand rn, uint sz, uint q) + { + WriteInstruction(0x0e21b800u | (sz << 22) | (q << 30), rd, rn); + } + + public readonly void FcvtmsFloat(Operand rd, Operand rn, uint ftype, uint sf) + { + WriteInstruction(0x1e300000u | (ftype << 22) | (sf << 31), rd, rn); + } + + public readonly void FcvtmuSH(Operand rd, Operand rn) + { + WriteInstruction(0x7e79b800u, rd, rn); + } + + public readonly void FcvtmuS(Operand rd, Operand rn, uint sz) + { + WriteInstruction(0x7e21b800u | (sz << 22), rd, rn); + } + + public readonly void FcvtmuVH(Operand rd, Operand rn, uint q) + { + WriteInstruction(0x2e79b800u | (q << 30), rd, rn); + } + + public readonly void FcvtmuV(Operand rd, Operand rn, uint sz, uint q) + { + WriteInstruction(0x2e21b800u | (sz << 22) | (q << 30), rd, rn); + } + + public readonly void FcvtmuFloat(Operand rd, Operand rn, uint ftype, uint sf) + { + WriteInstruction(0x1e310000u | (ftype << 22) | (sf << 31), rd, rn); + } + + public readonly void FcvtnsSH(Operand rd, Operand rn) + { + WriteInstruction(0x5e79a800u, rd, rn); + } + + public readonly void FcvtnsS(Operand rd, Operand rn, uint sz) + { + WriteInstruction(0x5e21a800u | (sz << 22), rd, rn); + } + + public readonly void FcvtnsVH(Operand rd, Operand rn, uint q) + { + WriteInstruction(0x0e79a800u | (q << 30), rd, rn); + } + + public readonly void FcvtnsV(Operand rd, Operand rn, uint sz, uint q) + { + WriteInstruction(0x0e21a800u | (sz << 22) | (q << 30), rd, rn); + } + + public readonly void FcvtnsFloat(Operand rd, Operand rn, uint ftype, uint sf) + { + WriteInstruction(0x1e200000u | (ftype << 22) | (sf << 31), rd, rn); + } + + public readonly void FcvtnuSH(Operand rd, Operand rn) + { + WriteInstruction(0x7e79a800u, rd, rn); + } + + public readonly void FcvtnuS(Operand rd, Operand rn, uint sz) + { + WriteInstruction(0x7e21a800u | (sz << 22), rd, rn); + } + + public readonly void FcvtnuVH(Operand rd, Operand rn, uint q) + { + WriteInstruction(0x2e79a800u | (q << 30), rd, rn); + } + + public readonly void FcvtnuV(Operand rd, Operand rn, uint sz, uint q) + { + WriteInstruction(0x2e21a800u | (sz << 22) | (q << 30), rd, rn); + } + + public readonly void FcvtnuFloat(Operand rd, Operand rn, uint ftype, uint sf) + { + WriteInstruction(0x1e210000u | (ftype << 22) | (sf << 31), rd, rn); + } + + public readonly void Fcvtn(Operand rd, Operand rn, uint sz, uint q) + { + WriteInstruction(0x0e216800u | (sz << 22) | (q << 30), rd, rn); + } + + public readonly void FcvtpsSH(Operand rd, Operand rn) + { + WriteInstruction(0x5ef9a800u, rd, rn); + } + + public readonly void FcvtpsS(Operand rd, Operand rn, uint sz) + { + WriteInstruction(0x5ea1a800u | (sz << 22), rd, rn); + } + + public readonly void FcvtpsVH(Operand rd, Operand rn, uint q) + { + WriteInstruction(0x0ef9a800u | (q << 30), rd, rn); + } + + public readonly void FcvtpsV(Operand rd, Operand rn, uint sz, uint q) + { + WriteInstruction(0x0ea1a800u | (sz << 22) | (q << 30), rd, rn); + } + + public readonly void FcvtpsFloat(Operand rd, Operand rn, uint ftype, uint sf) + { + WriteInstruction(0x1e280000u | (ftype << 22) | (sf << 31), rd, rn); + } + + public readonly void FcvtpuSH(Operand rd, Operand rn) + { + WriteInstruction(0x7ef9a800u, rd, rn); + } + + public readonly void FcvtpuS(Operand rd, Operand rn, uint sz) + { + WriteInstruction(0x7ea1a800u | (sz << 22), rd, rn); + } + + public readonly void FcvtpuVH(Operand rd, Operand rn, uint q) + { + WriteInstruction(0x2ef9a800u | (q << 30), rd, rn); + } + + public readonly void FcvtpuV(Operand rd, Operand rn, uint sz, uint q) + { + WriteInstruction(0x2ea1a800u | (sz << 22) | (q << 30), rd, rn); + } + + public readonly void FcvtpuFloat(Operand rd, Operand rn, uint ftype, uint sf) + { + WriteInstruction(0x1e290000u | (ftype << 22) | (sf << 31), rd, rn); + } + + public readonly void FcvtxnS(Operand rd, Operand rn, uint sz) + { + WriteInstruction(0x7e216800u | (sz << 22), rd, rn); + } + + public readonly void FcvtxnV(Operand rd, Operand rn, uint sz, uint q) + { + WriteInstruction(0x2e216800u | (sz << 22) | (q << 30), rd, rn); + } + + public readonly void FcvtzsFixS(Operand rd, Operand rn, uint immb, uint immh) + { + WriteInstruction(0x5f00fc00u | (immb << 16) | (immh << 19), rd, rn); + } + + public readonly void FcvtzsFixV(Operand rd, Operand rn, uint immb, uint immh, uint q) + { + WriteInstruction(0x0f00fc00u | (immb << 16) | (immh << 19) | (q << 30), rd, rn); + } + + public readonly void FcvtzsIntSH(Operand rd, Operand rn) + { + WriteInstruction(0x5ef9b800u, rd, rn); + } + + public readonly void FcvtzsIntS(Operand rd, Operand rn, uint sz) + { + WriteInstruction(0x5ea1b800u | (sz << 22), rd, rn); + } + + public readonly void FcvtzsIntVH(Operand rd, Operand rn, uint q) + { + WriteInstruction(0x0ef9b800u | (q << 30), rd, rn); + } + + public readonly void FcvtzsIntV(Operand rd, Operand rn, uint sz, uint q) + { + WriteInstruction(0x0ea1b800u | (sz << 22) | (q << 30), rd, rn); + } + + public readonly void FcvtzsFloatFix(Operand rd, Operand rn, uint scale, uint ftype, uint sf) + { + WriteInstruction(0x1e180000u | (scale << 10) | (ftype << 22) | (sf << 31), rd, rn); + } + + public readonly void FcvtzsFloatInt(Operand rd, Operand rn, uint ftype, uint sf) + { + WriteInstruction(0x1e380000u | (ftype << 22) | (sf << 31), rd, rn); + } + + public readonly void FcvtzuFixS(Operand rd, Operand rn, uint immb, uint immh) + { + WriteInstruction(0x7f00fc00u | (immb << 16) | (immh << 19), rd, rn); + } + + public readonly void FcvtzuFixV(Operand rd, Operand rn, uint immb, uint immh, uint q) + { + WriteInstruction(0x2f00fc00u | (immb << 16) | (immh << 19) | (q << 30), rd, rn); + } + + public readonly void FcvtzuIntSH(Operand rd, Operand rn) + { + WriteInstruction(0x7ef9b800u, rd, rn); + } + + public readonly void FcvtzuIntS(Operand rd, Operand rn, uint sz) + { + WriteInstruction(0x7ea1b800u | (sz << 22), rd, rn); + } + + public readonly void FcvtzuIntVH(Operand rd, Operand rn, uint q) + { + WriteInstruction(0x2ef9b800u | (q << 30), rd, rn); + } + + public readonly void FcvtzuIntV(Operand rd, Operand rn, uint sz, uint q) + { + WriteInstruction(0x2ea1b800u | (sz << 22) | (q << 30), rd, rn); + } + + public readonly void FcvtzuFloatFix(Operand rd, Operand rn, uint scale, uint ftype, uint sf) + { + WriteInstruction(0x1e190000u | (scale << 10) | (ftype << 22) | (sf << 31), rd, rn); + } + + public readonly void FcvtzuFloatInt(Operand rd, Operand rn, uint ftype, uint sf) + { + WriteInstruction(0x1e390000u | (ftype << 22) | (sf << 31), rd, rn); + } + + public readonly void FcvtFloat(Operand rd, Operand rn, uint opc, uint ftype) + { + WriteInstruction(0x1e224000u | (opc << 15) | (ftype << 22), rd, rn); + } + + public readonly void FdivHalf(Operand rd, Operand rn, Operand rm, uint q) + { + WriteInstructionRm16(0x2e403c00u | (q << 30), rd, rn, rm); + } + + public readonly void FdivSingleAndDouble(Operand rd, Operand rn, Operand rm, uint sz, uint q) + { + WriteInstructionRm16(0x2e20fc00u | (sz << 22) | (q << 30), rd, rn, rm); + } + + public readonly void FdivFloat(Operand rd, Operand rn, Operand rm, uint ftype) + { + WriteInstructionRm16(0x1e201800u | (ftype << 22), rd, rn, rm); + } + + public readonly void Fjcvtzs(Operand rd, Operand rn) + { + WriteInstruction(0x1e7e0000u, rd, rn); + } + + public readonly void FmaddFloat(Operand rd, Operand rn, Operand rm, Operand ra, uint ftype) + { + WriteInstruction(0x1f000000u | (ftype << 22), rd, rn, rm, ra); + } + + public readonly void FmaxnmpPairHalf(Operand rd, Operand rn, uint sz) + { + WriteInstruction(0x5e30c800u | (sz << 22), rd, rn); + } + + public readonly void FmaxnmpPairSingleAndDouble(Operand rd, Operand rn, uint sz) + { + WriteInstruction(0x7e30c800u | (sz << 22), rd, rn); + } + + public readonly void FmaxnmpVecHalf(Operand rd, Operand rn, Operand rm, uint q) + { + WriteInstructionRm16(0x2e400400u | (q << 30), rd, rn, rm); + } + + public readonly void FmaxnmpVecSingleAndDouble(Operand rd, Operand rn, Operand rm, uint sz, uint q) + { + WriteInstructionRm16(0x2e20c400u | (sz << 22) | (q << 30), rd, rn, rm); + } + + public readonly void FmaxnmvHalf(Operand rd, Operand rn, uint q) + { + WriteInstruction(0x0e30c800u | (q << 30), rd, rn); + } + + public readonly void FmaxnmvSingleAndDouble(Operand rd, Operand rn, uint sz, uint q) + { + WriteInstruction(0x2e30c800u | (sz << 22) | (q << 30), rd, rn); + } + + public readonly void FmaxnmHalf(Operand rd, Operand rn, Operand rm, uint q) + { + WriteInstructionRm16(0x0e400400u | (q << 30), rd, rn, rm); + } + + public readonly void FmaxnmSingleAndDouble(Operand rd, Operand rn, Operand rm, uint sz, uint q) + { + WriteInstructionRm16(0x0e20c400u | (sz << 22) | (q << 30), rd, rn, rm); + } + + public readonly void FmaxnmFloat(Operand rd, Operand rn, Operand rm, uint ftype) + { + WriteInstructionRm16(0x1e206800u | (ftype << 22), rd, rn, rm); + } + + public readonly void FmaxpPairHalf(Operand rd, Operand rn, uint sz) + { + WriteInstruction(0x5e30f800u | (sz << 22), rd, rn); + } + + public readonly void FmaxpPairSingleAndDouble(Operand rd, Operand rn, uint sz) + { + WriteInstruction(0x7e30f800u | (sz << 22), rd, rn); + } + + public readonly void FmaxpVecHalf(Operand rd, Operand rn, Operand rm, uint q) + { + WriteInstructionRm16(0x2e403400u | (q << 30), rd, rn, rm); + } + + public readonly void FmaxpVecSingleAndDouble(Operand rd, Operand rn, Operand rm, uint sz, uint q) + { + WriteInstructionRm16(0x2e20f400u | (sz << 22) | (q << 30), rd, rn, rm); + } + + public readonly void FmaxvHalf(Operand rd, Operand rn, uint q) + { + WriteInstruction(0x0e30f800u | (q << 30), rd, rn); + } + + public readonly void FmaxvSingleAndDouble(Operand rd, Operand rn, uint sz, uint q) + { + WriteInstruction(0x2e30f800u | (sz << 22) | (q << 30), rd, rn); + } + + public readonly void FmaxHalf(Operand rd, Operand rn, Operand rm, uint q) + { + WriteInstructionRm16(0x0e403400u | (q << 30), rd, rn, rm); + } + + public readonly void FmaxSingleAndDouble(Operand rd, Operand rn, Operand rm, uint sz, uint q) + { + WriteInstructionRm16(0x0e20f400u | (sz << 22) | (q << 30), rd, rn, rm); + } + + public readonly void FmaxFloat(Operand rd, Operand rn, Operand rm, uint ftype) + { + WriteInstructionRm16(0x1e204800u | (ftype << 22), rd, rn, rm); + } + + public readonly void FminnmpPairHalf(Operand rd, Operand rn, uint sz) + { + WriteInstruction(0x5eb0c800u | (sz << 22), rd, rn); + } + + public readonly void FminnmpPairSingleAndDouble(Operand rd, Operand rn, uint sz) + { + WriteInstruction(0x7eb0c800u | (sz << 22), rd, rn); + } + + public readonly void FminnmpVecHalf(Operand rd, Operand rn, Operand rm, uint q) + { + WriteInstructionRm16(0x2ec00400u | (q << 30), rd, rn, rm); + } + + public readonly void FminnmpVecSingleAndDouble(Operand rd, Operand rn, Operand rm, uint sz, uint q) + { + WriteInstructionRm16(0x2ea0c400u | (sz << 22) | (q << 30), rd, rn, rm); + } + + public readonly void FminnmvHalf(Operand rd, Operand rn, uint q) + { + WriteInstruction(0x0eb0c800u | (q << 30), rd, rn); + } + + public readonly void FminnmvSingleAndDouble(Operand rd, Operand rn, uint sz, uint q) + { + WriteInstruction(0x2eb0c800u | (sz << 22) | (q << 30), rd, rn); + } + + public readonly void FminnmHalf(Operand rd, Operand rn, Operand rm, uint q) + { + WriteInstructionRm16(0x0ec00400u | (q << 30), rd, rn, rm); + } + + public readonly void FminnmSingleAndDouble(Operand rd, Operand rn, Operand rm, uint sz, uint q) + { + WriteInstructionRm16(0x0ea0c400u | (sz << 22) | (q << 30), rd, rn, rm); + } + + public readonly void FminnmFloat(Operand rd, Operand rn, Operand rm, uint ftype) + { + WriteInstructionRm16(0x1e207800u | (ftype << 22), rd, rn, rm); + } + + public readonly void FminpPairHalf(Operand rd, Operand rn, uint sz) + { + WriteInstruction(0x5eb0f800u | (sz << 22), rd, rn); + } + + public readonly void FminpPairSingleAndDouble(Operand rd, Operand rn, uint sz) + { + WriteInstruction(0x7eb0f800u | (sz << 22), rd, rn); + } + + public readonly void FminpVecHalf(Operand rd, Operand rn, Operand rm, uint q) + { + WriteInstructionRm16(0x2ec03400u | (q << 30), rd, rn, rm); + } + + public readonly void FminpVecSingleAndDouble(Operand rd, Operand rn, Operand rm, uint sz, uint q) + { + WriteInstructionRm16(0x2ea0f400u | (sz << 22) | (q << 30), rd, rn, rm); + } + + public readonly void FminvHalf(Operand rd, Operand rn, uint q) + { + WriteInstruction(0x0eb0f800u | (q << 30), rd, rn); + } + + public readonly void FminvSingleAndDouble(Operand rd, Operand rn, uint sz, uint q) + { + WriteInstruction(0x2eb0f800u | (sz << 22) | (q << 30), rd, rn); + } + + public readonly void FminHalf(Operand rd, Operand rn, Operand rm, uint q) + { + WriteInstructionRm16(0x0ec03400u | (q << 30), rd, rn, rm); + } + + public readonly void FminSingleAndDouble(Operand rd, Operand rn, Operand rm, uint sz, uint q) + { + WriteInstructionRm16(0x0ea0f400u | (sz << 22) | (q << 30), rd, rn, rm); + } + + public readonly void FminFloat(Operand rd, Operand rn, Operand rm, uint ftype) + { + WriteInstructionRm16(0x1e205800u | (ftype << 22), rd, rn, rm); + } + + public readonly void FmlalEltFmlal(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l, uint q) + { + WriteInstructionRm16(0x0f800000u | (h << 11) | (m << 20) | (l << 21) | (q << 30), rd, rn, rm); + } + + public readonly void FmlalEltFmlal2(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l, uint q) + { + WriteInstructionRm16(0x2f808000u | (h << 11) | (m << 20) | (l << 21) | (q << 30), rd, rn, rm); + } + + public readonly void FmlalVecFmlal(Operand rd, Operand rn, Operand rm, uint q) + { + WriteInstructionRm16(0x0e20ec00u | (q << 30), rd, rn, rm); + } + + public readonly void FmlalVecFmlal2(Operand rd, Operand rn, Operand rm, uint q) + { + WriteInstructionRm16(0x2e20cc00u | (q << 30), rd, rn, rm); + } + + public readonly void FmlaElt2regScalarHalf(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l) + { + WriteInstructionRm16(0x5f001000u | (h << 11) | (m << 20) | (l << 21), rd, rn, rm); + } + + public readonly void FmlaElt2regScalarSingleAndDouble(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l, uint sz) + { + WriteInstructionRm16(0x5f801000u | (h << 11) | (m << 20) | (l << 21) | (sz << 22), rd, rn, rm); + } + + public readonly void FmlaElt2regElementHalf(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l, uint q) + { + WriteInstructionRm16(0x0f001000u | (h << 11) | (m << 20) | (l << 21) | (q << 30), rd, rn, rm); + } + + public readonly void FmlaElt2regElementSingleAndDouble(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l, uint sz, uint q) + { + WriteInstructionRm16(0x0f801000u | (h << 11) | (m << 20) | (l << 21) | (sz << 22) | (q << 30), rd, rn, rm); + } + + public readonly void FmlaVecHalf(Operand rd, Operand rn, Operand rm, uint q) + { + WriteInstructionRm16(0x0e400c00u | (q << 30), rd, rn, rm); + } + + public readonly void FmlaVecSingleAndDouble(Operand rd, Operand rn, Operand rm, uint sz, uint q) + { + WriteInstructionRm16(0x0e20cc00u | (sz << 22) | (q << 30), rd, rn, rm); + } + + public readonly void FmlslEltFmlsl(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l, uint q) + { + WriteInstructionRm16(0x0f804000u | (h << 11) | (m << 20) | (l << 21) | (q << 30), rd, rn, rm); + } + + public readonly void FmlslEltFmlsl2(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l, uint q) + { + WriteInstructionRm16(0x2f80c000u | (h << 11) | (m << 20) | (l << 21) | (q << 30), rd, rn, rm); + } + + public readonly void FmlslVecFmlsl(Operand rd, Operand rn, Operand rm, uint q) + { + WriteInstructionRm16(0x0ea0ec00u | (q << 30), rd, rn, rm); + } + + public readonly void FmlslVecFmlsl2(Operand rd, Operand rn, Operand rm, uint q) + { + WriteInstructionRm16(0x2ea0cc00u | (q << 30), rd, rn, rm); + } + + public readonly void FmlsElt2regScalarHalf(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l) + { + WriteInstructionRm16(0x5f005000u | (h << 11) | (m << 20) | (l << 21), rd, rn, rm); + } + + public readonly void FmlsElt2regScalarSingleAndDouble(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l, uint sz) + { + WriteInstructionRm16(0x5f805000u | (h << 11) | (m << 20) | (l << 21) | (sz << 22), rd, rn, rm); + } + + public readonly void FmlsElt2regElementHalf(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l, uint q) + { + WriteInstructionRm16(0x0f005000u | (h << 11) | (m << 20) | (l << 21) | (q << 30), rd, rn, rm); + } + + public readonly void FmlsElt2regElementSingleAndDouble(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l, uint sz, uint q) + { + WriteInstructionRm16(0x0f805000u | (h << 11) | (m << 20) | (l << 21) | (sz << 22) | (q << 30), rd, rn, rm); + } + + public readonly void FmlsVecHalf(Operand rd, Operand rn, Operand rm, uint q) + { + WriteInstructionRm16(0x0ec00c00u | (q << 30), rd, rn, rm); + } + + public readonly void FmlsVecSingleAndDouble(Operand rd, Operand rn, Operand rm, uint sz, uint q) + { + WriteInstructionRm16(0x0ea0cc00u | (sz << 22) | (q << 30), rd, rn, rm); + } + + public readonly void FmovPerHalf(Operand rd, uint h, uint g, uint f, uint e, uint d, uint c, uint b, uint a, uint q) + { + WriteInstruction(0x0f00fc00u | (h << 5) | (g << 6) | (f << 7) | (e << 8) | (d << 9) | (c << 16) | (b << 17) | (a << 18) | (q << 30), rd); + } + + public readonly void FmovSingleAndDouble(Operand rd, uint h, uint g, uint f, uint e, uint d, uint c, uint b, uint a, uint op, uint q) + { + WriteInstruction(0x0f00f400u | (h << 5) | (g << 6) | (f << 7) | (e << 8) | (d << 9) | (c << 16) | (b << 17) | (a << 18) | (op << 29) | (q << 30), rd); + } + + public readonly void FmovFloat(Operand rd, Operand rn, uint ftype) + { + WriteInstruction(0x1e204000u | (ftype << 22), rd, rn); + } + + public readonly void FmovFloatGen(Operand rd, Operand rn, uint ftype, uint sf, uint dir, uint top) + { + WriteInstruction(0x1e260000u | (dir << 16) | (top << 19) | (ftype << 22) | (sf << 31), rd, rn); + } + + public readonly void FmovFloatImm(Operand rd, uint imm8, uint ftype) + { + WriteInstruction(0x1e201000u | (imm8 << 13) | (ftype << 22), rd); + } + + public readonly void FmsubFloat(Operand rd, Operand rn, Operand rm, Operand ra, uint ftype) + { + WriteInstruction(0x1f008000u | (ftype << 22), rd, rn, rm, ra); + } + + public readonly void FmulxElt2regScalarHalf(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l) + { + WriteInstructionRm16(0x7f009000u | (h << 11) | (m << 20) | (l << 21), rd, rn, rm); + } + + public readonly void FmulxElt2regScalarSingleAndDouble(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l, uint sz) + { + WriteInstructionRm16(0x7f809000u | (h << 11) | (m << 20) | (l << 21) | (sz << 22), rd, rn, rm); + } + + public readonly void FmulxElt2regElementHalf(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l, uint q) + { + WriteInstructionRm16(0x2f009000u | (h << 11) | (m << 20) | (l << 21) | (q << 30), rd, rn, rm); + } + + public readonly void FmulxElt2regElementSingleAndDouble(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l, uint sz, uint q) + { + WriteInstructionRm16(0x2f809000u | (h << 11) | (m << 20) | (l << 21) | (sz << 22) | (q << 30), rd, rn, rm); + } + + public readonly void FmulxVecSH(Operand rd, Operand rn, Operand rm) + { + WriteInstructionRm16(0x5e401c00u, rd, rn, rm); + } + + public readonly void FmulxVecS(Operand rd, Operand rn, Operand rm, uint sz) + { + WriteInstructionRm16(0x5e20dc00u | (sz << 22), rd, rn, rm); + } + + public readonly void FmulxVecVH(Operand rd, Operand rn, Operand rm, uint q) + { + WriteInstructionRm16(0x0e401c00u | (q << 30), rd, rn, rm); + } + + public readonly void FmulxVecV(Operand rd, Operand rn, Operand rm, uint sz, uint q) + { + WriteInstructionRm16(0x0e20dc00u | (sz << 22) | (q << 30), rd, rn, rm); + } + + public readonly void FmulElt2regScalarHalf(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l) + { + WriteInstructionRm16(0x5f009000u | (h << 11) | (m << 20) | (l << 21), rd, rn, rm); + } + + public readonly void FmulElt2regScalarSingleAndDouble(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l, uint sz) + { + WriteInstructionRm16(0x5f809000u | (h << 11) | (m << 20) | (l << 21) | (sz << 22), rd, rn, rm); + } + + public readonly void FmulElt2regElementHalf(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l, uint q) + { + WriteInstructionRm16(0x0f009000u | (h << 11) | (m << 20) | (l << 21) | (q << 30), rd, rn, rm); + } + + public readonly void FmulElt2regElementSingleAndDouble(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l, uint sz, uint q) + { + WriteInstructionRm16(0x0f809000u | (h << 11) | (m << 20) | (l << 21) | (sz << 22) | (q << 30), rd, rn, rm); + } + + public readonly void FmulVecHalf(Operand rd, Operand rn, Operand rm, uint q) + { + WriteInstructionRm16(0x2e401c00u | (q << 30), rd, rn, rm); + } + + public readonly void FmulVecSingleAndDouble(Operand rd, Operand rn, Operand rm, uint sz, uint q) + { + WriteInstructionRm16(0x2e20dc00u | (sz << 22) | (q << 30), rd, rn, rm); + } + + public readonly void FmulFloat(Operand rd, Operand rn, Operand rm, uint ftype) + { + WriteInstructionRm16(0x1e200800u | (ftype << 22), rd, rn, rm); + } + + public readonly void FnegHalf(Operand rd, Operand rn, uint q) + { + WriteInstruction(0x2ef8f800u | (q << 30), rd, rn); + } + + public readonly void FnegSingleAndDouble(Operand rd, Operand rn, uint sz, uint q) + { + WriteInstruction(0x2ea0f800u | (sz << 22) | (q << 30), rd, rn); + } + + public readonly void FnegFloat(Operand rd, Operand rn, uint ftype) + { + WriteInstruction(0x1e214000u | (ftype << 22), rd, rn); + } + + public readonly void FnmaddFloat(Operand rd, Operand rn, Operand rm, Operand ra, uint ftype) + { + WriteInstruction(0x1f200000u | (ftype << 22), rd, rn, rm, ra); + } + + public readonly void FnmsubFloat(Operand rd, Operand rn, Operand rm, Operand ra, uint ftype) + { + WriteInstruction(0x1f208000u | (ftype << 22), rd, rn, rm, ra); + } + + public readonly void FnmulFloat(Operand rd, Operand rn, Operand rm, uint ftype) + { + WriteInstructionRm16(0x1e208800u | (ftype << 22), rd, rn, rm); + } + + public readonly void FrecpeSH(Operand rd, Operand rn) + { + WriteInstruction(0x5ef9d800u, rd, rn); + } + + public readonly void FrecpeS(Operand rd, Operand rn, uint sz) + { + WriteInstruction(0x5ea1d800u | (sz << 22), rd, rn); + } + + public readonly void FrecpeVH(Operand rd, Operand rn, uint q) + { + WriteInstruction(0x0ef9d800u | (q << 30), rd, rn); + } + + public readonly void FrecpeV(Operand rd, Operand rn, uint sz, uint q) + { + WriteInstruction(0x0ea1d800u | (sz << 22) | (q << 30), rd, rn); + } + + public readonly void FrecpsSH(Operand rd, Operand rn, Operand rm) + { + WriteInstructionRm16(0x5e403c00u, rd, rn, rm); + } + + public readonly void FrecpsS(Operand rd, Operand rn, Operand rm, uint sz) + { + WriteInstructionRm16(0x5e20fc00u | (sz << 22), rd, rn, rm); + } + + public readonly void FrecpsVH(Operand rd, Operand rn, Operand rm, uint q) + { + WriteInstructionRm16(0x0e403c00u | (q << 30), rd, rn, rm); + } + + public readonly void FrecpsV(Operand rd, Operand rn, Operand rm, uint sz, uint q) + { + WriteInstructionRm16(0x0e20fc00u | (sz << 22) | (q << 30), rd, rn, rm); + } + + public readonly void FrecpxHalf(Operand rd, Operand rn) + { + WriteInstruction(0x5ef9f800u, rd, rn); + } + + public readonly void FrecpxSingleAndDouble(Operand rd, Operand rn, uint sz) + { + WriteInstruction(0x5ea1f800u | (sz << 22), rd, rn); + } + + public readonly void Frint32x(Operand rd, Operand rn, uint sz, uint q) + { + WriteInstruction(0x2e21e800u | (sz << 22) | (q << 30), rd, rn); + } + + public readonly void Frint32xFloat(Operand rd, Operand rn) + { + WriteInstruction(0x1e28c000u, rd, rn); + } + + public readonly void Frint32z(Operand rd, Operand rn, uint sz, uint q) + { + WriteInstruction(0x0e21e800u | (sz << 22) | (q << 30), rd, rn); + } + + public readonly void Frint32zFloat(Operand rd, Operand rn) + { + WriteInstruction(0x1e284000u, rd, rn); + } + + public readonly void Frint64x(Operand rd, Operand rn, uint sz, uint q) + { + WriteInstruction(0x2e21f800u | (sz << 22) | (q << 30), rd, rn); + } + + public readonly void Frint64xFloat(Operand rd, Operand rn) + { + WriteInstruction(0x1e29c000u, rd, rn); + } + + public readonly void Frint64z(Operand rd, Operand rn, uint sz, uint q) + { + WriteInstruction(0x0e21f800u | (sz << 22) | (q << 30), rd, rn); + } + + public readonly void Frint64zFloat(Operand rd, Operand rn) + { + WriteInstruction(0x1e294000u, rd, rn); + } + + public readonly void FrintaHalf(Operand rd, Operand rn, uint q) + { + WriteInstruction(0x2e798800u | (q << 30), rd, rn); + } + + public readonly void FrintaSingleAndDouble(Operand rd, Operand rn, uint sz, uint q) + { + WriteInstruction(0x2e218800u | (sz << 22) | (q << 30), rd, rn); + } + + public readonly void FrintaFloat(Operand rd, Operand rn, uint ftype) + { + WriteInstruction(0x1e264000u | (ftype << 22), rd, rn); + } + + public readonly void FrintiHalf(Operand rd, Operand rn, uint q) + { + WriteInstruction(0x2ef99800u | (q << 30), rd, rn); + } + + public readonly void FrintiSingleAndDouble(Operand rd, Operand rn, uint sz, uint q) + { + WriteInstruction(0x2ea19800u | (sz << 22) | (q << 30), rd, rn); + } + + public readonly void FrintiFloat(Operand rd, Operand rn, uint ftype) + { + WriteInstruction(0x1e27c000u | (ftype << 22), rd, rn); + } + + public readonly void FrintmHalf(Operand rd, Operand rn, uint q) + { + WriteInstruction(0x0e799800u | (q << 30), rd, rn); + } + + public readonly void FrintmSingleAndDouble(Operand rd, Operand rn, uint sz, uint q) + { + WriteInstruction(0x0e219800u | (sz << 22) | (q << 30), rd, rn); + } + + public readonly void FrintmFloat(Operand rd, Operand rn, uint ftype) + { + WriteInstruction(0x1e254000u | (ftype << 22), rd, rn); + } + + public readonly void FrintnHalf(Operand rd, Operand rn, uint q) + { + WriteInstruction(0x0e798800u | (q << 30), rd, rn); + } + + public readonly void FrintnSingleAndDouble(Operand rd, Operand rn, uint sz, uint q) + { + WriteInstruction(0x0e218800u | (sz << 22) | (q << 30), rd, rn); + } + + public readonly void FrintnFloat(Operand rd, Operand rn, uint ftype) + { + WriteInstruction(0x1e244000u | (ftype << 22), rd, rn); + } + + public readonly void FrintpHalf(Operand rd, Operand rn, uint q) + { + WriteInstruction(0x0ef98800u | (q << 30), rd, rn); + } + + public readonly void FrintpSingleAndDouble(Operand rd, Operand rn, uint sz, uint q) + { + WriteInstruction(0x0ea18800u | (sz << 22) | (q << 30), rd, rn); + } + + public readonly void FrintpFloat(Operand rd, Operand rn, uint ftype) + { + WriteInstruction(0x1e24c000u | (ftype << 22), rd, rn); + } + + public readonly void FrintxHalf(Operand rd, Operand rn, uint q) + { + WriteInstruction(0x2e799800u | (q << 30), rd, rn); + } + + public readonly void FrintxSingleAndDouble(Operand rd, Operand rn, uint sz, uint q) + { + WriteInstruction(0x2e219800u | (sz << 22) | (q << 30), rd, rn); + } + + public readonly void FrintxFloat(Operand rd, Operand rn, uint ftype) + { + WriteInstruction(0x1e274000u | (ftype << 22), rd, rn); + } + + public readonly void FrintzHalf(Operand rd, Operand rn, uint q) + { + WriteInstruction(0x0ef99800u | (q << 30), rd, rn); + } + + public readonly void FrintzSingleAndDouble(Operand rd, Operand rn, uint sz, uint q) + { + WriteInstruction(0x0ea19800u | (sz << 22) | (q << 30), rd, rn); + } + + public readonly void FrintzFloat(Operand rd, Operand rn, uint ftype) + { + WriteInstruction(0x1e25c000u | (ftype << 22), rd, rn); + } + + public readonly void FrsqrteSH(Operand rd, Operand rn) + { + WriteInstruction(0x7ef9d800u, rd, rn); + } + + public readonly void FrsqrteS(Operand rd, Operand rn, uint sz) + { + WriteInstruction(0x7ea1d800u | (sz << 22), rd, rn); + } + + public readonly void FrsqrteVH(Operand rd, Operand rn, uint q) + { + WriteInstruction(0x2ef9d800u | (q << 30), rd, rn); + } + + public readonly void FrsqrteV(Operand rd, Operand rn, uint sz, uint q) + { + WriteInstruction(0x2ea1d800u | (sz << 22) | (q << 30), rd, rn); + } + + public readonly void FrsqrtsSH(Operand rd, Operand rn, Operand rm) + { + WriteInstructionRm16(0x5ec03c00u, rd, rn, rm); + } + + public readonly void FrsqrtsS(Operand rd, Operand rn, Operand rm, uint sz) + { + WriteInstructionRm16(0x5ea0fc00u | (sz << 22), rd, rn, rm); + } + + public readonly void FrsqrtsVH(Operand rd, Operand rn, Operand rm, uint q) + { + WriteInstructionRm16(0x0ec03c00u | (q << 30), rd, rn, rm); + } + + public readonly void FrsqrtsV(Operand rd, Operand rn, Operand rm, uint sz, uint q) + { + WriteInstructionRm16(0x0ea0fc00u | (sz << 22) | (q << 30), rd, rn, rm); + } + + public readonly void FsqrtHalf(Operand rd, Operand rn, uint q) + { + WriteInstruction(0x2ef9f800u | (q << 30), rd, rn); + } + + public readonly void FsqrtSingleAndDouble(Operand rd, Operand rn, uint sz, uint q) + { + WriteInstruction(0x2ea1f800u | (sz << 22) | (q << 30), rd, rn); + } + + public readonly void FsqrtFloat(Operand rd, Operand rn, uint ftype) + { + WriteInstruction(0x1e21c000u | (ftype << 22), rd, rn); + } + + public readonly void FsubHalf(Operand rd, Operand rn, Operand rm, uint q) + { + WriteInstructionRm16(0x0ec01400u | (q << 30), rd, rn, rm); + } + + public readonly void FsubSingleAndDouble(Operand rd, Operand rn, Operand rm, uint sz, uint q) + { + WriteInstructionRm16(0x0ea0d400u | (sz << 22) | (q << 30), rd, rn, rm); + } + + public readonly void FsubFloat(Operand rd, Operand rn, Operand rm, uint ftype) + { + WriteInstructionRm16(0x1e203800u | (ftype << 22), rd, rn, rm); + } + + public readonly void InsElt(Operand rd, Operand rn, uint imm4, uint imm5) + { + WriteInstruction(0x6e000400u | (imm4 << 11) | (imm5 << 16), rd, rn); + } + + public readonly void InsGen(Operand rd, Operand rn, uint imm5) + { + WriteInstruction(0x4e001c00u | (imm5 << 16), rd, rn); + } + + public readonly void Ld1rAsNoPostIndex(Operand rt, Operand rn, uint size, uint q) + { + WriteInstruction(0x0d40c000u | (size << 10) | (q << 30), rt, rn); + } + + public readonly void Ld1rAsPostIndex(Operand rt, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0dc0c000u | (size << 10) | (q << 30), rt, rn, rm); + } + + public readonly void Ld1MultAsNoPostIndex(Operand rt, Operand rn, uint registersCount, uint size, uint q) + { + WriteInstruction(0x0c402000u | (size << 10) | (EncodeLdSt1MultOpcode(registersCount) << 12) | (q << 30), rt, rn); + } + + public readonly void Ld1MultAsPostIndex(Operand rt, Operand rn, Operand rm, uint registersCount, uint size, uint q) + { + WriteInstructionRm16(0x0cc02000u | (size << 10) | (EncodeLdSt1MultOpcode(registersCount) << 12) | (q << 30), rt, rn, rm); + } + + public readonly void Ld1SnglAsNoPostIndex(Operand rt, Operand rn, uint index, uint size) + { + WriteInstruction(EncodeIndexSizeSngl(0x0d400000u, index, size), rt, rn); + } + + public readonly void Ld1SnglAsPostIndex(Operand rt, Operand rn, Operand rm, uint index, uint size) + { + WriteInstructionRm16(EncodeIndexSizeSngl(0x0dc00000u, index, size), rt, rn, rm); + } + + public readonly void Ld2rAsNoPostIndex(Operand rt, Operand rn, uint size, uint q) + { + WriteInstruction(0x0d60c000u | (size << 10) | (q << 30), rt, rn); + } + + public readonly void Ld2rAsPostIndex(Operand rt, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0de0c000u | (size << 10) | (q << 30), rt, rn, rm); + } + + public readonly void Ld2MultAsNoPostIndex(Operand rt, Operand rn, uint size, uint q) + { + WriteInstruction(0x0c408000u | (size << 10) | (q << 30), rt, rn); + } + + public readonly void Ld2MultAsPostIndex(Operand rt, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0cc08000u | (size << 10) | (q << 30), rt, rn, rm); + } + + public readonly void Ld2SnglAsNoPostIndex(Operand rt, Operand rn, uint index, uint size) + { + WriteInstruction(EncodeIndexSizeSngl(0x0d600000u, index, size), rt, rn); + } + + public readonly void Ld2SnglAsPostIndex(Operand rt, Operand rn, Operand rm, uint index, uint size) + { + WriteInstructionRm16(EncodeIndexSizeSngl(0x0de00000u, index, size), rt, rn, rm); + } + + public readonly void Ld3rAsNoPostIndex(Operand rt, Operand rn, uint size, uint q) + { + WriteInstruction(0x0d40e000u | (size << 10) | (q << 30), rt, rn); + } + + public readonly void Ld3rAsPostIndex(Operand rt, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0dc0e000u | (size << 10) | (q << 30), rt, rn, rm); + } + + public readonly void Ld3MultAsNoPostIndex(Operand rt, Operand rn, uint size, uint q) + { + WriteInstruction(0x0c404000u | (size << 10) | (q << 30), rt, rn); + } + + public readonly void Ld3MultAsPostIndex(Operand rt, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0cc04000u | (size << 10) | (q << 30), rt, rn, rm); + } + + public readonly void Ld3SnglAsNoPostIndex(Operand rt, Operand rn, uint index, uint size) + { + WriteInstruction(EncodeIndexSizeSngl(0x0d402000u, index, size), rt, rn); + } + + public readonly void Ld3SnglAsPostIndex(Operand rt, Operand rn, Operand rm, uint index, uint size) + { + WriteInstructionRm16(EncodeIndexSizeSngl(0x0dc02000u, index, size), rt, rn, rm); + } + + public readonly void Ld4rAsNoPostIndex(Operand rt, Operand rn, uint size, uint q) + { + WriteInstruction(0x0d60e000u | (size << 10) | (q << 30), rt, rn); + } + + public readonly void Ld4rAsPostIndex(Operand rt, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0de0e000u | (size << 10) | (q << 30), rt, rn, rm); + } + + public readonly void Ld4MultAsNoPostIndex(Operand rt, Operand rn, uint size, uint q) + { + WriteInstruction(0x0c400000u | (size << 10) | (q << 30), rt, rn); + } + + public readonly void Ld4MultAsPostIndex(Operand rt, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0cc00000u | (size << 10) | (q << 30), rt, rn, rm); + } + + public readonly void Ld4SnglAsNoPostIndex(Operand rt, Operand rn, uint index, uint size) + { + WriteInstruction(EncodeIndexSizeSngl(0x0d602000u, index, size), rt, rn); + } + + public readonly void Ld4SnglAsPostIndex(Operand rt, Operand rn, Operand rm, uint index, uint size) + { + WriteInstructionRm16(EncodeIndexSizeSngl(0x0de02000u, index, size), rt, rn, rm); + } + + public readonly void Ldap1Sngl(Operand rt, Operand rn, uint q) + { + WriteInstruction(0x0d418400u | (q << 30), rt, rn); + } + + public readonly void Ldra(Operand rt, Operand rn, uint w, uint imm9, uint s, uint m) + { + WriteInstruction(0xf8200400u | (w << 11) | (imm9 << 12) | (s << 22) | (m << 23), rt, rn); + } + + public readonly void MlaElt(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l, uint size, uint q) + { + WriteInstructionRm16(0x2f000000u | (h << 11) | (m << 20) | (l << 21) | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void MlaVec(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0e209400u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void MlsElt(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l, uint size, uint q) + { + WriteInstructionRm16(0x2f004000u | (h << 11) | (m << 20) | (l << 21) | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void MlsVec(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x2e209400u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void Movi(Operand rd, uint h, uint g, uint f, uint e, uint d, uint cmode, uint c, uint b, uint a, uint op, uint q) + { + WriteInstruction(0x0f000400u | (h << 5) | (g << 6) | (f << 7) | (e << 8) | (d << 9) | (cmode << 12) | (c << 16) | (b << 17) | (a << 18) | (op << 29) | (q << 30), rd); + } + + public readonly void MulElt(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l, uint size, uint q) + { + WriteInstructionRm16(0x0f008000u | (h << 11) | (m << 20) | (l << 21) | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void MulVec(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0e209c00u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void Mvni(Operand rd, uint h, uint g, uint f, uint e, uint d, uint cmode, uint c, uint b, uint a, uint q) + { + WriteInstruction(0x2f000400u | (h << 5) | (g << 6) | (f << 7) | (e << 8) | (d << 9) | (cmode << 12) | (c << 16) | (b << 17) | (a << 18) | (q << 30), rd); + } + + public readonly void NegS(Operand rd, Operand rn, uint size) + { + WriteInstruction(0x7e20b800u | (size << 22), rd, rn); + } + + public readonly void NegV(Operand rd, Operand rn, uint size, uint q) + { + WriteInstruction(0x2e20b800u | (size << 22) | (q << 30), rd, rn); + } + + public readonly void Not(Operand rd, Operand rn, uint q) + { + WriteInstruction(0x2e205800u | (q << 30), rd, rn); + } + + public readonly void Orn(Operand rd, Operand rn, Operand rm, uint q) + { + WriteInstructionRm16(0x0ee01c00u | (q << 30), rd, rn, rm); + } + + public readonly void OrrImm(Operand rd, uint h, uint g, uint f, uint e, uint d, uint c, uint b, uint a, uint q) + { + WriteInstruction(0x0f001400u | (h << 5) | (g << 6) | (f << 7) | (e << 8) | (d << 9) | (c << 16) | (b << 17) | (a << 18) | (q << 30), rd); + } + + public readonly void OrrReg(Operand rd, Operand rn, Operand rm, uint q) + { + WriteInstructionRm16(0x0ea01c00u | (q << 30), rd, rn, rm); + } + + public readonly void Pmull(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0e20e000u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void Pmul(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x2e209c00u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void Raddhn(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x2e204000u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void Rax1(Operand rd, Operand rn, Operand rm) + { + WriteInstructionRm16(0xce608c00u, rd, rn, rm); + } + + public readonly void Rbit(Operand rd, Operand rn, uint q) + { + WriteInstruction(0x2e605800u | (q << 30), rd, rn); + } + + public readonly void Rev16(Operand rd, Operand rn, uint size, uint q) + { + WriteInstruction(0x0e201800u | (size << 22) | (q << 30), rd, rn); + } + + public readonly void Rev32(Operand rd, Operand rn, uint size, uint q) + { + WriteInstruction(0x2e200800u | (size << 22) | (q << 30), rd, rn); + } + + public readonly void Rev64(Operand rd, Operand rn, uint size, uint q) + { + WriteInstruction(0x0e200800u | (size << 22) | (q << 30), rd, rn); + } + + public readonly void Rshrn(Operand rd, Operand rn, uint immb, uint immh, uint q) + { + WriteInstruction(0x0f008c00u | (immb << 16) | (immh << 19) | (q << 30), rd, rn); + } + + public readonly void Rsubhn(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x2e206000u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void Sabal(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0e205000u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void Saba(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0e207c00u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void Sabdl(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0e207000u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void Sabd(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0e207400u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void Sadalp(Operand rd, Operand rn, uint size, uint q) + { + WriteInstruction(0x0e206800u | (size << 22) | (q << 30), rd, rn); + } + + public readonly void Saddlp(Operand rd, Operand rn, uint size, uint q) + { + WriteInstruction(0x0e202800u | (size << 22) | (q << 30), rd, rn); + } + + public readonly void Saddlv(Operand rd, Operand rn, uint size, uint q) + { + WriteInstruction(0x0e303800u | (size << 22) | (q << 30), rd, rn); + } + + public readonly void Saddl(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0e200000u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void Saddw(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0e201000u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void ScvtfFixS(Operand rd, Operand rn, uint immb, uint immh) + { + WriteInstruction(0x5f00e400u | (immb << 16) | (immh << 19), rd, rn); + } + + public readonly void ScvtfFixV(Operand rd, Operand rn, uint immb, uint immh, uint q) + { + WriteInstruction(0x0f00e400u | (immb << 16) | (immh << 19) | (q << 30), rd, rn); + } + + public readonly void ScvtfIntSH(Operand rd, Operand rn) + { + WriteInstruction(0x5e79d800u, rd, rn); + } + + public readonly void ScvtfIntS(Operand rd, Operand rn, uint sz) + { + WriteInstruction(0x5e21d800u | (sz << 22), rd, rn); + } + + public readonly void ScvtfIntVH(Operand rd, Operand rn, uint q) + { + WriteInstruction(0x0e79d800u | (q << 30), rd, rn); + } + + public readonly void ScvtfIntV(Operand rd, Operand rn, uint sz, uint q) + { + WriteInstruction(0x0e21d800u | (sz << 22) | (q << 30), rd, rn); + } + + public readonly void ScvtfFloatFix(Operand rd, Operand rn, uint scale, uint ftype, uint sf) + { + WriteInstruction(0x1e020000u | (scale << 10) | (ftype << 22) | (sf << 31), rd, rn); + } + + public readonly void ScvtfFloatInt(Operand rd, Operand rn, uint ftype, uint sf) + { + WriteInstruction(0x1e220000u | (ftype << 22) | (sf << 31), rd, rn); + } + + public readonly void SdotElt(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l, uint size, uint q) + { + WriteInstructionRm16(0x0f00e000u | (h << 11) | (m << 20) | (l << 21) | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void SdotVec(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0e009400u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void Sha1c(Operand rd, Operand rn, Operand rm) + { + WriteInstructionRm16(0x5e000000u, rd, rn, rm); + } + + public readonly void Sha1h(Operand rd, Operand rn) + { + WriteInstruction(0x5e280800u, rd, rn); + } + + public readonly void Sha1m(Operand rd, Operand rn, Operand rm) + { + WriteInstructionRm16(0x5e002000u, rd, rn, rm); + } + + public readonly void Sha1p(Operand rd, Operand rn, Operand rm) + { + WriteInstructionRm16(0x5e001000u, rd, rn, rm); + } + + public readonly void Sha1su0(Operand rd, Operand rn, Operand rm) + { + WriteInstructionRm16(0x5e003000u, rd, rn, rm); + } + + public readonly void Sha1su1(Operand rd, Operand rn) + { + WriteInstruction(0x5e281800u, rd, rn); + } + + public readonly void Sha256h2(Operand rd, Operand rn, Operand rm) + { + WriteInstructionRm16(0x5e005000u, rd, rn, rm); + } + + public readonly void Sha256h(Operand rd, Operand rn, Operand rm) + { + WriteInstructionRm16(0x5e004000u, rd, rn, rm); + } + + public readonly void Sha256su0(Operand rd, Operand rn) + { + WriteInstruction(0x5e282800u, rd, rn); + } + + public readonly void Sha256su1(Operand rd, Operand rn, Operand rm) + { + WriteInstructionRm16(0x5e006000u, rd, rn, rm); + } + + public readonly void Sha512h2(Operand rd, Operand rn, Operand rm) + { + WriteInstructionRm16(0xce608400u, rd, rn, rm); + } + + public readonly void Sha512h(Operand rd, Operand rn, Operand rm) + { + WriteInstructionRm16(0xce608000u, rd, rn, rm); + } + + public readonly void Sha512su0(Operand rd, Operand rn) + { + WriteInstruction(0xcec08000u, rd, rn); + } + + public readonly void Sha512su1(Operand rd, Operand rn, Operand rm) + { + WriteInstructionRm16(0xce608800u, rd, rn, rm); + } + + public readonly void Shadd(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0e200400u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void Shll(Operand rd, Operand rn, uint size, uint q) + { + WriteInstruction(0x2e213800u | (size << 22) | (q << 30), rd, rn); + } + + public readonly void ShlS(Operand rd, Operand rn, uint immb, uint immh) + { + WriteInstruction(0x5f005400u | (immb << 16) | (immh << 19), rd, rn); + } + + public readonly void ShlV(Operand rd, Operand rn, uint immb, uint immh, uint q) + { + WriteInstruction(0x0f005400u | (immb << 16) | (immh << 19) | (q << 30), rd, rn); + } + + public readonly void Shrn(Operand rd, Operand rn, uint immb, uint immh, uint q) + { + WriteInstruction(0x0f008400u | (immb << 16) | (immh << 19) | (q << 30), rd, rn); + } + + public readonly void Shsub(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0e202400u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void SliS(Operand rd, Operand rn, uint immb, uint immh) + { + WriteInstruction(0x7f005400u | (immb << 16) | (immh << 19), rd, rn); + } + + public readonly void SliV(Operand rd, Operand rn, uint immb, uint immh, uint q) + { + WriteInstruction(0x2f005400u | (immb << 16) | (immh << 19) | (q << 30), rd, rn); + } + + public readonly void Sm3partw1(Operand rd, Operand rn, Operand rm) + { + WriteInstructionRm16(0xce60c000u, rd, rn, rm); + } + + public readonly void Sm3partw2(Operand rd, Operand rn, Operand rm) + { + WriteInstructionRm16(0xce60c400u, rd, rn, rm); + } + + public readonly void Sm3ss1(Operand rd, Operand rn, Operand rm, Operand ra) + { + WriteInstruction(0xce400000u, rd, rn, rm, ra); + } + + public readonly void Sm3tt1a(Operand rd, Operand rn, uint imm2, Operand rm) + { + WriteInstructionRm16(0xce408000u | (imm2 << 12), rd, rn, rm); + } + + public readonly void Sm3tt1b(Operand rd, Operand rn, uint imm2, Operand rm) + { + WriteInstructionRm16(0xce408400u | (imm2 << 12), rd, rn, rm); + } + + public readonly void Sm3tt2a(Operand rd, Operand rn, uint imm2, Operand rm) + { + WriteInstructionRm16(0xce408800u | (imm2 << 12), rd, rn, rm); + } + + public readonly void Sm3tt2b(Operand rd, Operand rn, uint imm2, Operand rm) + { + WriteInstructionRm16(0xce408c00u | (imm2 << 12), rd, rn, rm); + } + + public readonly void Sm4ekey(Operand rd, Operand rn, Operand rm) + { + WriteInstructionRm16(0xce60c800u, rd, rn, rm); + } + + public readonly void Sm4e(Operand rd, Operand rn) + { + WriteInstruction(0xcec08400u, rd, rn); + } + + public readonly void Smaxp(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0e20a400u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void Smaxv(Operand rd, Operand rn, uint size, uint q) + { + WriteInstruction(0x0e30a800u | (size << 22) | (q << 30), rd, rn); + } + + public readonly void Smax(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0e206400u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void Sminp(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0e20ac00u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void Sminv(Operand rd, Operand rn, uint size, uint q) + { + WriteInstruction(0x0e31a800u | (size << 22) | (q << 30), rd, rn); + } + + public readonly void Smin(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0e206c00u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void SmlalElt(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l, uint size, uint q) + { + WriteInstructionRm16(0x0f002000u | (h << 11) | (m << 20) | (l << 21) | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void SmlalVec(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0e208000u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void SmlslElt(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l, uint size, uint q) + { + WriteInstructionRm16(0x0f006000u | (h << 11) | (m << 20) | (l << 21) | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void SmlslVec(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0e20a000u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void SmmlaVec(Operand rd, Operand rn, Operand rm) + { + WriteInstructionRm16(0x4e80a400u, rd, rn, rm); + } + + public readonly void Smov(Operand rd, Operand rn, int index, int size) + { + uint q = size == 2 ? 1u << 30 : 0u; + WriteInstruction(0x0e002c00u | (EncodeIndexSizeImm5(index, size) << 16) | q, rd, rn); + } + + public readonly void SmullElt(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l, uint size, uint q) + { + WriteInstructionRm16(0x0f00a000u | (h << 11) | (m << 20) | (l << 21) | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void SmullVec(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0e20c000u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void SqabsS(Operand rd, Operand rn, uint size) + { + WriteInstruction(0x5e207800u | (size << 22), rd, rn); + } + + public readonly void SqabsV(Operand rd, Operand rn, uint size, uint q) + { + WriteInstruction(0x0e207800u | (size << 22) | (q << 30), rd, rn); + } + + public readonly void SqaddS(Operand rd, Operand rn, Operand rm, uint size) + { + WriteInstructionRm16(0x5e200c00u | (size << 22), rd, rn, rm); + } + + public readonly void SqaddV(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0e200c00u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void SqdmlalElt2regScalar(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l, uint size) + { + WriteInstructionRm16(0x5f003000u | (h << 11) | (m << 20) | (l << 21) | (size << 22), rd, rn, rm); + } + + public readonly void SqdmlalElt2regElement(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l, uint size, uint q) + { + WriteInstructionRm16(0x0f003000u | (h << 11) | (m << 20) | (l << 21) | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void SqdmlalVecS(Operand rd, Operand rn, Operand rm, uint size) + { + WriteInstructionRm16(0x5e209000u | (size << 22), rd, rn, rm); + } + + public readonly void SqdmlalVecV(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0e209000u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void SqdmlslElt2regScalar(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l, uint size) + { + WriteInstructionRm16(0x5f007000u | (h << 11) | (m << 20) | (l << 21) | (size << 22), rd, rn, rm); + } + + public readonly void SqdmlslElt2regElement(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l, uint size, uint q) + { + WriteInstructionRm16(0x0f007000u | (h << 11) | (m << 20) | (l << 21) | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void SqdmlslVecS(Operand rd, Operand rn, Operand rm, uint size) + { + WriteInstructionRm16(0x5e20b000u | (size << 22), rd, rn, rm); + } + + public readonly void SqdmlslVecV(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0e20b000u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void SqdmulhElt2regScalar(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l, uint size) + { + WriteInstructionRm16(0x5f00c000u | (h << 11) | (m << 20) | (l << 21) | (size << 22), rd, rn, rm); + } + + public readonly void SqdmulhElt2regElement(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l, uint size, uint q) + { + WriteInstructionRm16(0x0f00c000u | (h << 11) | (m << 20) | (l << 21) | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void SqdmulhVecS(Operand rd, Operand rn, Operand rm, uint size) + { + WriteInstructionRm16(0x5e20b400u | (size << 22), rd, rn, rm); + } + + public readonly void SqdmulhVecV(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0e20b400u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void SqdmullElt2regScalar(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l, uint size) + { + WriteInstructionRm16(0x5f00b000u | (h << 11) | (m << 20) | (l << 21) | (size << 22), rd, rn, rm); + } + + public readonly void SqdmullElt2regElement(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l, uint size, uint q) + { + WriteInstructionRm16(0x0f00b000u | (h << 11) | (m << 20) | (l << 21) | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void SqdmullVecS(Operand rd, Operand rn, Operand rm, uint size) + { + WriteInstructionRm16(0x5e20d000u | (size << 22), rd, rn, rm); + } + + public readonly void SqdmullVecV(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0e20d000u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void SqnegS(Operand rd, Operand rn, uint size) + { + WriteInstruction(0x7e207800u | (size << 22), rd, rn); + } + + public readonly void SqnegV(Operand rd, Operand rn, uint size, uint q) + { + WriteInstruction(0x2e207800u | (size << 22) | (q << 30), rd, rn); + } + + public readonly void SqrdmlahElt2regScalar(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l, uint size) + { + WriteInstructionRm16(0x7f00d000u | (h << 11) | (m << 20) | (l << 21) | (size << 22), rd, rn, rm); + } + + public readonly void SqrdmlahElt2regElement(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l, uint size, uint q) + { + WriteInstructionRm16(0x2f00d000u | (h << 11) | (m << 20) | (l << 21) | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void SqrdmlahVecS(Operand rd, Operand rn, Operand rm, uint size) + { + WriteInstructionRm16(0x7e008400u | (size << 22), rd, rn, rm); + } + + public readonly void SqrdmlahVecV(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x2e008400u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void SqrdmlshElt2regScalar(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l, uint size) + { + WriteInstructionRm16(0x7f00f000u | (h << 11) | (m << 20) | (l << 21) | (size << 22), rd, rn, rm); + } + + public readonly void SqrdmlshElt2regElement(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l, uint size, uint q) + { + WriteInstructionRm16(0x2f00f000u | (h << 11) | (m << 20) | (l << 21) | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void SqrdmlshVecS(Operand rd, Operand rn, Operand rm, uint size) + { + WriteInstructionRm16(0x7e008c00u | (size << 22), rd, rn, rm); + } + + public readonly void SqrdmlshVecV(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x2e008c00u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void SqrdmulhElt2regScalar(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l, uint size) + { + WriteInstructionRm16(0x5f00d000u | (h << 11) | (m << 20) | (l << 21) | (size << 22), rd, rn, rm); + } + + public readonly void SqrdmulhElt2regElement(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l, uint size, uint q) + { + WriteInstructionRm16(0x0f00d000u | (h << 11) | (m << 20) | (l << 21) | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void SqrdmulhVecS(Operand rd, Operand rn, Operand rm, uint size) + { + WriteInstructionRm16(0x7e20b400u | (size << 22), rd, rn, rm); + } + + public readonly void SqrdmulhVecV(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x2e20b400u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void SqrshlS(Operand rd, Operand rn, Operand rm, uint size) + { + WriteInstructionRm16(0x5e205c00u | (size << 22), rd, rn, rm); + } + + public readonly void SqrshlV(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0e205c00u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void SqrshrnS(Operand rd, Operand rn, uint immb, uint immh) + { + WriteInstruction(0x5f009c00u | (immb << 16) | (immh << 19), rd, rn); + } + + public readonly void SqrshrnV(Operand rd, Operand rn, uint immb, uint immh, uint q) + { + WriteInstruction(0x0f009c00u | (immb << 16) | (immh << 19) | (q << 30), rd, rn); + } + + public readonly void SqrshrunS(Operand rd, Operand rn, uint immb, uint immh) + { + WriteInstruction(0x7f008c00u | (immb << 16) | (immh << 19), rd, rn); + } + + public readonly void SqrshrunV(Operand rd, Operand rn, uint immb, uint immh, uint q) + { + WriteInstruction(0x2f008c00u | (immb << 16) | (immh << 19) | (q << 30), rd, rn); + } + + public readonly void SqshluS(Operand rd, Operand rn, uint immb, uint immh) + { + WriteInstruction(0x7f006400u | (immb << 16) | (immh << 19), rd, rn); + } + + public readonly void SqshluV(Operand rd, Operand rn, uint immb, uint immh, uint q) + { + WriteInstruction(0x2f006400u | (immb << 16) | (immh << 19) | (q << 30), rd, rn); + } + + public readonly void SqshlImmS(Operand rd, Operand rn, uint immb, uint immh) + { + WriteInstruction(0x5f007400u | (immb << 16) | (immh << 19), rd, rn); + } + + public readonly void SqshlImmV(Operand rd, Operand rn, uint immb, uint immh, uint q) + { + WriteInstruction(0x0f007400u | (immb << 16) | (immh << 19) | (q << 30), rd, rn); + } + + public readonly void SqshlRegS(Operand rd, Operand rn, Operand rm, uint size) + { + WriteInstructionRm16(0x5e204c00u | (size << 22), rd, rn, rm); + } + + public readonly void SqshlRegV(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0e204c00u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void SqshrnS(Operand rd, Operand rn, uint immb, uint immh) + { + WriteInstruction(0x5f009400u | (immb << 16) | (immh << 19), rd, rn); + } + + public readonly void SqshrnV(Operand rd, Operand rn, uint immb, uint immh, uint q) + { + WriteInstruction(0x0f009400u | (immb << 16) | (immh << 19) | (q << 30), rd, rn); + } + + public readonly void SqshrunS(Operand rd, Operand rn, uint immb, uint immh) + { + WriteInstruction(0x7f008400u | (immb << 16) | (immh << 19), rd, rn); + } + + public readonly void SqshrunV(Operand rd, Operand rn, uint immb, uint immh, uint q) + { + WriteInstruction(0x2f008400u | (immb << 16) | (immh << 19) | (q << 30), rd, rn); + } + + public readonly void SqsubS(Operand rd, Operand rn, Operand rm, uint size) + { + WriteInstructionRm16(0x5e202c00u | (size << 22), rd, rn, rm); + } + + public readonly void SqsubV(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0e202c00u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void SqxtnS(Operand rd, Operand rn, uint size) + { + WriteInstruction(0x5e214800u | (size << 22), rd, rn); + } + + public readonly void SqxtnV(Operand rd, Operand rn, uint size, uint q) + { + WriteInstruction(0x0e214800u | (size << 22) | (q << 30), rd, rn); + } + + public readonly void SqxtunS(Operand rd, Operand rn, uint size) + { + WriteInstruction(0x7e212800u | (size << 22), rd, rn); + } + + public readonly void SqxtunV(Operand rd, Operand rn, uint size, uint q) + { + WriteInstruction(0x2e212800u | (size << 22) | (q << 30), rd, rn); + } + + public readonly void Srhadd(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0e201400u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void SriS(Operand rd, Operand rn, uint immb, uint immh) + { + WriteInstruction(0x7f004400u | (immb << 16) | (immh << 19), rd, rn); + } + + public readonly void SriV(Operand rd, Operand rn, uint immb, uint immh, uint q) + { + WriteInstruction(0x2f004400u | (immb << 16) | (immh << 19) | (q << 30), rd, rn); + } + + public readonly void SrshlS(Operand rd, Operand rn, Operand rm, uint size) + { + WriteInstructionRm16(0x5e205400u | (size << 22), rd, rn, rm); + } + + public readonly void SrshlV(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0e205400u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void SrshrS(Operand rd, Operand rn, uint immb, uint immh) + { + WriteInstruction(0x5f002400u | (immb << 16) | (immh << 19), rd, rn); + } + + public readonly void SrshrV(Operand rd, Operand rn, uint immb, uint immh, uint q) + { + WriteInstruction(0x0f002400u | (immb << 16) | (immh << 19) | (q << 30), rd, rn); + } + + public readonly void SrsraS(Operand rd, Operand rn, uint immb, uint immh) + { + WriteInstruction(0x5f003400u | (immb << 16) | (immh << 19), rd, rn); + } + + public readonly void SrsraV(Operand rd, Operand rn, uint immb, uint immh, uint q) + { + WriteInstruction(0x0f003400u | (immb << 16) | (immh << 19) | (q << 30), rd, rn); + } + + public readonly void Sshll(Operand rd, Operand rn, uint immb, uint immh, uint q) + { + WriteInstruction(0x0f00a400u | (immb << 16) | (immh << 19) | (q << 30), rd, rn); + } + + public readonly void SshlS(Operand rd, Operand rn, Operand rm, uint size) + { + WriteInstructionRm16(0x5e204400u | (size << 22), rd, rn, rm); + } + + public readonly void SshlV(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0e204400u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void SshrS(Operand rd, Operand rn, uint immb, uint immh) + { + WriteInstruction(0x5f000400u | (immb << 16) | (immh << 19), rd, rn); + } + + public readonly void SshrV(Operand rd, Operand rn, uint immb, uint immh, uint q) + { + WriteInstruction(0x0f000400u | (immb << 16) | (immh << 19) | (q << 30), rd, rn); + } + + public readonly void SsraS(Operand rd, Operand rn, uint immb, uint immh) + { + WriteInstruction(0x5f001400u | (immb << 16) | (immh << 19), rd, rn); + } + + public readonly void SsraV(Operand rd, Operand rn, uint immb, uint immh, uint q) + { + WriteInstruction(0x0f001400u | (immb << 16) | (immh << 19) | (q << 30), rd, rn); + } + + public readonly void Ssubl(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0e202000u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void Ssubw(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0e203000u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void St1MultAsNoPostIndex(Operand rt, Operand rn, uint registersCount, uint size, uint q) + { + WriteInstruction(0x0c002000u | (size << 10) | (EncodeLdSt1MultOpcode(registersCount) << 12) | (q << 30), rt, rn); + } + + public readonly void St1MultAsPostIndex(Operand rt, Operand rn, Operand rm, uint registersCount, uint size, uint q) + { + WriteInstructionRm16(0x0c802000u | (size << 10) | (EncodeLdSt1MultOpcode(registersCount) << 12) | (q << 30), rt, rn, rm); + } + + public readonly void St1SnglAsNoPostIndex(Operand rt, Operand rn, uint index, uint size) + { + WriteInstruction(EncodeIndexSizeSngl(0x0d000000u, index, size), rt, rn); + } + + public readonly void St1SnglAsPostIndex(Operand rt, Operand rn, Operand rm, uint index, uint size) + { + WriteInstructionRm16(EncodeIndexSizeSngl(0x0d800000u, index, size), rt, rn, rm); + } + + public readonly void St2MultAsNoPostIndex(Operand rt, Operand rn, uint size, uint q) + { + WriteInstruction(0x0c008000u | (size << 10) | (q << 30), rt, rn); + } + + public readonly void St2MultAsPostIndex(Operand rt, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0c808000u | (size << 10) | (q << 30), rt, rn, rm); + } + + public readonly void St2SnglAsNoPostIndex(Operand rt, Operand rn, uint index, uint size) + { + WriteInstruction(EncodeIndexSizeSngl(0x0d200000u, index, size), rt, rn); + } + + public readonly void St2SnglAsPostIndex(Operand rt, Operand rn, Operand rm, uint index, uint size) + { + WriteInstructionRm16(EncodeIndexSizeSngl(0x0da00000u, index, size), rt, rn, rm); + } + + public readonly void St3MultAsNoPostIndex(Operand rt, Operand rn, uint size, uint q) + { + WriteInstruction(0x0c004000u | (size << 10) | (q << 30), rt, rn); + } + + public readonly void St3MultAsPostIndex(Operand rt, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0c804000u | (size << 10) | (q << 30), rt, rn, rm); + } + + public readonly void St3SnglAsNoPostIndex(Operand rt, Operand rn, uint index, uint size) + { + WriteInstruction(EncodeIndexSizeSngl(0x0d002000u, index, size), rt, rn); + } + + public readonly void St3SnglAsPostIndex(Operand rt, Operand rn, Operand rm, uint index, uint size) + { + WriteInstructionRm16(EncodeIndexSizeSngl(0x0d802000u, index, size), rt, rn, rm); + } + + public readonly void St4MultAsNoPostIndex(Operand rt, Operand rn, uint size, uint q) + { + WriteInstruction(0x0c000000u | (size << 10) | (q << 30), rt, rn); + } + + public readonly void St4MultAsPostIndex(Operand rt, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0c800000u | (size << 10) | (q << 30), rt, rn, rm); + } + + public readonly void St4SnglAsNoPostIndex(Operand rt, Operand rn, uint index, uint size) + { + WriteInstruction(EncodeIndexSizeSngl(0x0d202000u, index, size), rt, rn); + } + + public readonly void St4SnglAsPostIndex(Operand rt, Operand rn, Operand rm, uint index, uint size) + { + WriteInstructionRm16(EncodeIndexSizeSngl(0x0da02000u, index, size), rt, rn, rm); + } + + public readonly void Stl1Sngl(Operand rt, Operand rn, uint q) + { + WriteInstruction(0x0d018400u | (q << 30), rt, rn); + } + + public readonly void Subhn(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0e206000u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void SubS(Operand rd, Operand rn, Operand rm, uint size) + { + WriteInstructionRm16(0x7e208400u | (size << 22), rd, rn, rm); + } + + public readonly void SubV(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x2e208400u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void SudotElt(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l, uint q) + { + WriteInstructionRm16(0x0f00f000u | (h << 11) | (m << 20) | (l << 21) | (q << 30), rd, rn, rm); + } + + public readonly void SuqaddS(Operand rd, Operand rn, uint size) + { + WriteInstruction(0x5e203800u | (size << 22), rd, rn); + } + + public readonly void SuqaddV(Operand rd, Operand rn, uint size, uint q) + { + WriteInstruction(0x0e203800u | (size << 22) | (q << 30), rd, rn); + } + + public readonly void Tbl(Operand rd, Operand rn, uint len, Operand rm, uint q) + { + WriteInstructionRm16(0x0e000000u | (len << 13) | (q << 30), rd, rn, rm); + } + + public readonly void Tbx(Operand rd, Operand rn, uint len, Operand rm, uint q) + { + WriteInstructionRm16(0x0e001000u | (len << 13) | (q << 30), rd, rn, rm); + } + + public readonly void Trn1(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0e002800u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void Trn2(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0e006800u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void Uabal(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x2e205000u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void Uaba(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x2e207c00u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void Uabdl(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x2e207000u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void Uabd(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x2e207400u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void Uadalp(Operand rd, Operand rn, uint size, uint q) + { + WriteInstruction(0x2e206800u | (size << 22) | (q << 30), rd, rn); + } + + public readonly void Uaddlp(Operand rd, Operand rn, uint size, uint q) + { + WriteInstruction(0x2e202800u | (size << 22) | (q << 30), rd, rn); + } + + public readonly void Uaddlv(Operand rd, Operand rn, uint size, uint q) + { + WriteInstruction(0x2e303800u | (size << 22) | (q << 30), rd, rn); + } + + public readonly void Uaddl(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x2e200000u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void Uaddw(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x2e201000u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void UcvtfFixS(Operand rd, Operand rn, uint immb, uint immh) + { + WriteInstruction(0x7f00e400u | (immb << 16) | (immh << 19), rd, rn); + } + + public readonly void UcvtfFixV(Operand rd, Operand rn, uint immb, uint immh, uint q) + { + WriteInstruction(0x2f00e400u | (immb << 16) | (immh << 19) | (q << 30), rd, rn); + } + + public readonly void UcvtfIntSH(Operand rd, Operand rn) + { + WriteInstruction(0x7e79d800u, rd, rn); + } + + public readonly void UcvtfIntS(Operand rd, Operand rn, uint sz) + { + WriteInstruction(0x7e21d800u | (sz << 22), rd, rn); + } + + public readonly void UcvtfIntVH(Operand rd, Operand rn, uint q) + { + WriteInstruction(0x2e79d800u | (q << 30), rd, rn); + } + + public readonly void UcvtfIntV(Operand rd, Operand rn, uint sz, uint q) + { + WriteInstruction(0x2e21d800u | (sz << 22) | (q << 30), rd, rn); + } + + public readonly void UcvtfFloatFix(Operand rd, Operand rn, uint scale, uint ftype, uint sf) + { + WriteInstruction(0x1e030000u | (scale << 10) | (ftype << 22) | (sf << 31), rd, rn); + } + + public readonly void UcvtfFloatInt(Operand rd, Operand rn, uint ftype, uint sf) + { + WriteInstruction(0x1e230000u | (ftype << 22) | (sf << 31), rd, rn); + } + + public readonly void UdotElt(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l, uint size, uint q) + { + WriteInstructionRm16(0x2f00e000u | (h << 11) | (m << 20) | (l << 21) | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void UdotVec(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x2e009400u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void Uhadd(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x2e200400u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void Uhsub(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x2e202400u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void Umaxp(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x2e20a400u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void Umaxv(Operand rd, Operand rn, uint size, uint q) + { + WriteInstruction(0x2e30a800u | (size << 22) | (q << 30), rd, rn); + } + + public readonly void Umax(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x2e206400u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void Uminp(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x2e20ac00u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void Uminv(Operand rd, Operand rn, uint size, uint q) + { + WriteInstruction(0x2e31a800u | (size << 22) | (q << 30), rd, rn); + } + + public readonly void Umin(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x2e206c00u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void UmlalElt(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l, uint size, uint q) + { + WriteInstructionRm16(0x2f002000u | (h << 11) | (m << 20) | (l << 21) | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void UmlalVec(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x2e208000u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void UmlslElt(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l, uint size, uint q) + { + WriteInstructionRm16(0x2f006000u | (h << 11) | (m << 20) | (l << 21) | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void UmlslVec(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x2e20a000u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void UmmlaVec(Operand rd, Operand rn, Operand rm) + { + WriteInstructionRm16(0x6e80a400u, rd, rn, rm); + } + + public readonly void Umov(Operand rd, Operand rn, int index, int size) + { + uint q = size == 3 ? 1u << 30 : 0u; + WriteInstruction(0x0e003c00u | (EncodeIndexSizeImm5(index, size) << 16) | q, rd, rn); + } + + public readonly void UmullElt(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l, uint size, uint q) + { + WriteInstructionRm16(0x2f00a000u | (h << 11) | (m << 20) | (l << 21) | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void UmullVec(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x2e20c000u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void UqaddS(Operand rd, Operand rn, Operand rm, uint size) + { + WriteInstructionRm16(0x7e200c00u | (size << 22), rd, rn, rm); + } + + public readonly void UqaddV(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x2e200c00u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void UqrshlS(Operand rd, Operand rn, Operand rm, uint size) + { + WriteInstructionRm16(0x7e205c00u | (size << 22), rd, rn, rm); + } + + public readonly void UqrshlV(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x2e205c00u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void UqrshrnS(Operand rd, Operand rn, uint immb, uint immh) + { + WriteInstruction(0x7f009c00u | (immb << 16) | (immh << 19), rd, rn); + } + + public readonly void UqrshrnV(Operand rd, Operand rn, uint immb, uint immh, uint q) + { + WriteInstruction(0x2f009c00u | (immb << 16) | (immh << 19) | (q << 30), rd, rn); + } + + public readonly void UqshlImmS(Operand rd, Operand rn, uint immb, uint immh) + { + WriteInstruction(0x7f007400u | (immb << 16) | (immh << 19), rd, rn); + } + + public readonly void UqshlImmV(Operand rd, Operand rn, uint immb, uint immh, uint q) + { + WriteInstruction(0x2f007400u | (immb << 16) | (immh << 19) | (q << 30), rd, rn); + } + + public readonly void UqshlRegS(Operand rd, Operand rn, Operand rm, uint size) + { + WriteInstructionRm16(0x7e204c00u | (size << 22), rd, rn, rm); + } + + public readonly void UqshlRegV(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x2e204c00u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void UqshrnS(Operand rd, Operand rn, uint immb, uint immh) + { + WriteInstruction(0x7f009400u | (immb << 16) | (immh << 19), rd, rn); + } + + public readonly void UqshrnV(Operand rd, Operand rn, uint immb, uint immh, uint q) + { + WriteInstruction(0x2f009400u | (immb << 16) | (immh << 19) | (q << 30), rd, rn); + } + + public readonly void UqsubS(Operand rd, Operand rn, Operand rm, uint size) + { + WriteInstructionRm16(0x7e202c00u | (size << 22), rd, rn, rm); + } + + public readonly void UqsubV(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x2e202c00u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void UqxtnS(Operand rd, Operand rn, uint size) + { + WriteInstruction(0x7e214800u | (size << 22), rd, rn); + } + + public readonly void UqxtnV(Operand rd, Operand rn, uint size, uint q) + { + WriteInstruction(0x2e214800u | (size << 22) | (q << 30), rd, rn); + } + + public readonly void Urecpe(Operand rd, Operand rn, uint sz, uint q) + { + WriteInstruction(0x0ea1c800u | (sz << 22) | (q << 30), rd, rn); + } + + public readonly void Urhadd(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x2e201400u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void UrshlS(Operand rd, Operand rn, Operand rm, uint size) + { + WriteInstructionRm16(0x7e205400u | (size << 22), rd, rn, rm); + } + + public readonly void UrshlV(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x2e205400u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void UrshrS(Operand rd, Operand rn, uint immb, uint immh) + { + WriteInstruction(0x7f002400u | (immb << 16) | (immh << 19), rd, rn); + } + + public readonly void UrshrV(Operand rd, Operand rn, uint immb, uint immh, uint q) + { + WriteInstruction(0x2f002400u | (immb << 16) | (immh << 19) | (q << 30), rd, rn); + } + + public readonly void Ursqrte(Operand rd, Operand rn, uint sz, uint q) + { + WriteInstruction(0x2ea1c800u | (sz << 22) | (q << 30), rd, rn); + } + + public readonly void UrsraS(Operand rd, Operand rn, uint immb, uint immh) + { + WriteInstruction(0x7f003400u | (immb << 16) | (immh << 19), rd, rn); + } + + public readonly void UrsraV(Operand rd, Operand rn, uint immb, uint immh, uint q) + { + WriteInstruction(0x2f003400u | (immb << 16) | (immh << 19) | (q << 30), rd, rn); + } + + public readonly void UsdotElt(Operand rd, Operand rn, uint h, Operand rm, uint m, uint l, uint q) + { + WriteInstructionRm16(0x0f80f000u | (h << 11) | (m << 20) | (l << 21) | (q << 30), rd, rn, rm); + } + + public readonly void UsdotVec(Operand rd, Operand rn, Operand rm, uint q) + { + WriteInstructionRm16(0x0e809c00u | (q << 30), rd, rn, rm); + } + + public readonly void Ushll(Operand rd, Operand rn, uint immb, uint immh, uint q) + { + WriteInstruction(0x2f00a400u | (immb << 16) | (immh << 19) | (q << 30), rd, rn); + } + + public readonly void UshlS(Operand rd, Operand rn, Operand rm, uint size) + { + WriteInstructionRm16(0x7e204400u | (size << 22), rd, rn, rm); + } + + public readonly void UshlV(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x2e204400u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void UshrS(Operand rd, Operand rn, uint immb, uint immh) + { + WriteInstruction(0x7f000400u | (immb << 16) | (immh << 19), rd, rn); + } + + public readonly void UshrV(Operand rd, Operand rn, uint immb, uint immh, uint q) + { + WriteInstruction(0x2f000400u | (immb << 16) | (immh << 19) | (q << 30), rd, rn); + } + + public readonly void UsmmlaVec(Operand rd, Operand rn, Operand rm) + { + WriteInstructionRm16(0x4e80ac00u, rd, rn, rm); + } + + public readonly void UsqaddS(Operand rd, Operand rn, uint size) + { + WriteInstruction(0x7e203800u | (size << 22), rd, rn); + } + + public readonly void UsqaddV(Operand rd, Operand rn, uint size, uint q) + { + WriteInstruction(0x2e203800u | (size << 22) | (q << 30), rd, rn); + } + + public readonly void UsraS(Operand rd, Operand rn, uint immb, uint immh) + { + WriteInstruction(0x7f001400u | (immb << 16) | (immh << 19), rd, rn); + } + + public readonly void UsraV(Operand rd, Operand rn, uint immb, uint immh, uint q) + { + WriteInstruction(0x2f001400u | (immb << 16) | (immh << 19) | (q << 30), rd, rn); + } + + public readonly void Usubl(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x2e202000u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void Usubw(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x2e203000u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void Uzp1(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0e001800u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void Uzp2(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0e005800u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void Wfe() + { + WriteUInt32(0xd503205fu); + } + + public readonly void Wfi() + { + WriteUInt32(0xd503207fu); + } + + public readonly void Xar(Operand rd, Operand rn, uint imm6, Operand rm) + { + WriteInstructionRm16(0xce800000u | (imm6 << 10), rd, rn, rm); + } + + public readonly void Xtn(Operand rd, Operand rn, uint size, uint q) + { + WriteInstruction(0x0e212800u | (size << 22) | (q << 30), rd, rn); + } + + public readonly void Yield() + { + WriteUInt32(0xd503203fu); + } + + public readonly void Zip1(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0e003800u | (size << 22) | (q << 30), rd, rn, rm); + } + + public readonly void Zip2(Operand rd, Operand rn, Operand rm, uint size, uint q) + { + WriteInstructionRm16(0x0e007800u | (size << 22) | (q << 30), rd, rn, rm); + } + + // Utility + + public readonly void WriteSysRegInstruction(uint inst, Operand rt, uint o0, uint op1, uint crn, uint crm, uint op2) + { + inst |= (op2 & 7) << 5; + inst |= (crm & 15) << 8; + inst |= (crn & 15) << 12; + inst |= (op1 & 7) << 16; + inst |= (o0 & 1) << 19; + + WriteInstruction(inst, rt); + } + + private readonly void WriteInstructionAuto( + uint instI, + uint instR, + Operand rd, + Operand rn, + Operand rm, + ArmShiftType shiftType = ArmShiftType.Lsl, + int shiftAmount = 0, + bool immForm = false) + { + if (rm.Kind == OperandKind.Constant && (rm.Value != 0 || immForm)) + { + Debug.Assert(shiftAmount == 0); + int imm = rm.AsInt32(); + Debug.Assert((uint)imm == rm.Value); + if (imm != 0 && (imm & 0xfff) == 0) + { + instI |= 1 << 22; // sh flag + imm >>= 12; + } + WriteInstructionAuto(instI | (EncodeUImm12(imm, 0) << 10), rd, rn); + } + else + { + Debug.Assert((uint)shiftType < 3); // ROR shift is a reserved encoding for ADD and SUB. + instR |= EncodeUImm6(shiftAmount) << 10; + instR |= (uint)shiftType << 22; + + WriteInstructionRm16Auto(instR, rd, rn, rm); + } + } + + private readonly void WriteInstructionAuto( + uint instR, + Operand rd, + Operand rn, + Operand rm, + ArmShiftType shiftType = ArmShiftType.Lsl, + int shiftAmount = 0) + { + instR |= EncodeUImm6(shiftAmount) << 10; + instR |= (uint)shiftType << 22; + + WriteInstructionRm16Auto(instR, rd, rn, rm); + } + + private readonly void WriteInstructionAuto( + uint instruction, + Operand rd, + Operand rn, + Operand rm, + ArmExtensionType extensionType, + int shiftAmount = 0) + { + Debug.Assert((uint)shiftAmount <= 4); + + instruction |= (uint)shiftAmount << 10; + instruction |= (uint)extensionType << 13; + + WriteInstructionRm16Auto(instruction, rd, rn, rm); + } + + private readonly void WriteInstructionBitwiseAuto( + uint instI, + uint instR, + Operand rd, + Operand rn, + Operand rm, + ArmShiftType shiftType = ArmShiftType.Lsl, + int shiftAmount = 0) + { + if (rm.Kind == OperandKind.Constant && rm.Value != 0) + { + Debug.Assert(shiftAmount == 0); + bool canEncode = CodeGenCommon.TryEncodeBitMask(rm, out int immN, out int immS, out int immR); + Debug.Assert(canEncode); + uint instruction = instI | ((uint)immS << 10) | ((uint)immR << 16) | ((uint)immN << 22); + + WriteInstructionAuto(instruction, rd, rn); + } + else + { + WriteInstructionBitwiseAuto(instR, rd, rn, rm, shiftType, shiftAmount); + } + } + + private readonly void WriteInstructionBitwiseAuto( + uint instruction, + Operand rd, + Operand rn, + Operand rm, + ArmShiftType shiftType = ArmShiftType.Lsl, + int shiftAmount = 0) + { + if (rd.Type == OperandType.I64) + { + instruction |= SfFlag; + } + + instruction |= EncodeUImm6(shiftAmount) << 10; + instruction |= (uint)shiftType << 22; + + WriteInstructionRm16(instruction, rd, rn, rm); + } + + private readonly void WriteInstructionLdrStrAuto( + uint instruction, + Operand rd, + Operand rn, + Operand rm, + ArmExtensionType extensionType, + bool shift) + { + if (shift) + { + instruction |= 1u << 12; + } + + instruction |= (uint)extensionType << 13; + + if (rd.Type == OperandType.I64) + { + instruction |= 1u << 30; + } + + WriteInstructionRm16(instruction, rd, rn, rm); + } + + private readonly void WriteInstructionAuto(uint instruction, Operand rd) + { + if (rd.Type == OperandType.I64) + { + instruction |= SfFlag; + } + + WriteInstruction(instruction, rd); + } + + public readonly void WriteInstructionAuto(uint instruction, Operand rd, Operand rn) + { + if (rd.Type == OperandType.I64) + { + instruction |= SfFlag; + } + + WriteInstruction(instruction, rd, rn); + } + + private readonly void WriteInstructionAuto(uint instruction, Operand rd, Operand rn, Operand rm, Operand ra) + { + if (rd.Type == OperandType.I64) + { + instruction |= SfFlag; + } + + WriteInstruction(instruction, rd, rn, rm, ra); + } + + public readonly void WriteInstruction(uint instruction, Operand rd) + { + WriteUInt32(instruction | EncodeReg(rd)); + } + + public readonly void WriteInstruction(uint instruction, Operand rd, Operand rn) + { + WriteUInt32(instruction | EncodeReg(rd) | (EncodeReg(rn) << 5)); + } + + public readonly void WriteInstruction(uint instruction, Operand rd, Operand rn, Operand rm) + { + WriteUInt32(instruction | EncodeReg(rd) | (EncodeReg(rn) << 5) | (EncodeReg(rm) << 10)); + } + + public readonly void WriteInstruction(uint instruction, Operand rd, Operand rn, Operand rm, Operand ra) + { + WriteUInt32(instruction | EncodeReg(rd) | (EncodeReg(rn) << 5) | (EncodeReg(ra) << 10) | (EncodeReg(rm) << 16)); + } + + private readonly void WriteInstructionRm16Auto(uint instruction, Operand rd, Operand rn, Operand rm) + { + if (rd.Type == OperandType.I64) + { + instruction |= SfFlag; + } + + WriteInstructionRm16(instruction, rd, rn, rm); + } + + public readonly void WriteInstructionRm16(uint instruction, Operand rn, Operand rm) + { + WriteUInt32(instruction | (EncodeReg(rn) << 5) | (EncodeReg(rm) << 16)); + } + + public readonly void WriteInstructionRm16(uint instruction, Operand rd, Operand rn, Operand rm) + { + WriteUInt32(instruction | EncodeReg(rd) | (EncodeReg(rn) << 5) | (EncodeReg(rm) << 16)); + } + + private static uint GetLdpStpInstruction(uint intInst, uint vecInst, int imm, OperandType type) + { + uint instruction; + int scale; + + if (type.IsInteger()) + { + instruction = intInst; + + if (type == OperandType.I64) + { + instruction |= SfFlag; + scale = 3; + } + else + { + scale = 2; + } + } + else + { + int opc = type switch + { + OperandType.FP32 => 0, + OperandType.FP64 => 1, + _ => 2, + }; + + instruction = vecInst | ((uint)opc << 30); + scale = 2 + opc; + } + + instruction |= (EncodeSImm7(imm, scale) << 15); + + return instruction; + } + + private static uint GetLdrStrInstruction(uint intInst, uint vecInst, OperandType type) + { + uint instruction; + + if (type.IsInteger()) + { + instruction = intInst; + + if (type == OperandType.I64) + { + instruction |= 1 << 30; + } + } + else + { + instruction = vecInst; + + if (type == OperandType.V128) + { + instruction |= 1u << 23; + } + else + { + instruction |= type == OperandType.FP32 ? 2u << 30 : 3u << 30; + } + } + + return instruction; + } + + private static uint GetLdrStrInstruction(uint intInst, uint vecInst, OperandType type, uint size) + { + uint instruction; + + if (type.IsInteger()) + { + instruction = intInst; + + if (type == OperandType.I64) + { + instruction |= 1 << 30; + } + } + else + { + instruction = vecInst; + + if (type == OperandType.V128) + { + instruction |= 1u << 23; + } + else + { + instruction |= size << 30; + } + } + + return instruction; + } + + private static uint EncodeIndexSizeImm5(int index, int size) + { + Debug.Assert((uint)size < 4); + Debug.Assert((uint)index < (16u >> size), $"Invalid index {index} and size {size} combination."); + return ((uint)index << (size + 1)) | (1u << size); + } + + private static uint EncodeSImm7(int value, int scale) + { + uint imm = (uint)(value >> scale) & 0x7f; + Debug.Assert(((int)imm << 25) >> (25 - scale) == value, $"Failed to encode constant 0x{value:X} with scale {scale}."); + return imm; + } + + private static uint EncodeSImm9(int value) + { + uint imm = (uint)value & 0x1ff; + Debug.Assert(((int)imm << 23) >> 23 == value, $"Failed to encode constant 0x{value:X}."); + return imm; + } + + private static uint EncodeSImm19_2(int value) + { + uint imm = (uint)(value >> 2) & 0x7ffff; + Debug.Assert(((int)imm << 13) >> 11 == value, $"Failed to encode constant 0x{value:X}."); + return imm; + } + + 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; + } + + private static uint EncodeUImm4(int value) + { + uint imm = (uint)value & 0xf; + Debug.Assert((int)imm == value, $"Failed to encode constant 0x{value:X}."); + return imm; + } + + private static uint EncodeUImm6(int value) + { + uint imm = (uint)value & 0x3f; + Debug.Assert((int)imm == value, $"Failed to encode constant 0x{value:X}."); + return imm; + } + + private static uint EncodeUImm12(int value, OperandType type) + { + return EncodeUImm12(value, GetScaleForType(type)); + } + + private static uint EncodeUImm12(int value, int scale) + { + uint imm = (uint)(value >> scale) & 0xfff; + Debug.Assert((int)imm << scale == value, $"Failed to encode constant 0x{value:X} with scale {scale}."); + return imm; + } + + private static uint EncodeUImm16(int value) + { + uint imm = (uint)value & 0xffff; + Debug.Assert((int)imm == value, $"Failed to encode constant 0x{value:X}."); + return imm; + } + + private static uint EncodeReg(Operand reg) + { + if (reg.Kind == OperandKind.Constant && reg.Value == 0) + { + return ZrRegister; + } + + uint regIndex = (uint)reg.GetRegister().Index; + Debug.Assert(reg.Kind == OperandKind.Register); + Debug.Assert(regIndex < 32); + return regIndex; + } + + private static uint EncodeTypeTargetPolicy(uint type, uint target, uint policy) + { + Debug.Assert(type <= 2); + Debug.Assert(target <= 2); + Debug.Assert(policy <= 1); + + return (type << 3) | (target << 1) | policy; + } + + private static uint EncodeIndexSizeSngl(uint inst, uint index, uint size) + { + uint opcode = Math.Min(2u, size) << 1; + + index <<= (int)size; + + if (size == 3) + { + index |= 1u; + } + + size = index & 3; + uint s = (index >> 2) & 1; + uint q = index >> 3; + + Debug.Assert(q <= 1); + + return inst | (size << 10) | (s << 12) | (opcode << 13) | (q << 30); + } + + private static uint EncodeLdSt1MultOpcode(uint registersCount) + { + return registersCount switch + { + 2 => 0b1010, + 3 => 0b0110, + 4 => 0b0010, + _ => 0b0111, + }; + } + + private static int GetScaleForType(OperandType type) + { + return type switch + { + OperandType.I32 => 2, + OperandType.I64 => 3, + OperandType.FP32 => 2, + OperandType.FP64 => 3, + OperandType.V128 => 4, + _ => throw new ArgumentException($"Invalid type {type}."), + }; + } + + private readonly void WriteUInt32(uint value) + { + _code.Add(value); + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/CodeGen/Arm64/CodeGenCommon.cs b/src/Ryujinx.Cpu/LightningJit/CodeGen/Arm64/CodeGenCommon.cs new file mode 100644 index 000000000..db6a71593 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/CodeGen/Arm64/CodeGenCommon.cs @@ -0,0 +1,67 @@ +using System.Numerics; + +namespace Ryujinx.Cpu.LightningJit.CodeGen.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 &= uint.MaxValue; + 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; + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/CodeGen/Arm64/RegisterSaveRestore.cs b/src/Ryujinx.Cpu/LightningJit/CodeGen/Arm64/RegisterSaveRestore.cs new file mode 100644 index 000000000..b4b8bb524 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/CodeGen/Arm64/RegisterSaveRestore.cs @@ -0,0 +1,252 @@ +using System.Numerics; + +namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64 +{ + readonly struct RegisterSaveRestore + { + private const int FpRegister = 29; + private const int LrRegister = 30; + + public const int Encodable9BitsOffsetLimit = 0x100; + + private readonly uint _gprMask; + private readonly uint _fpSimdMask; + private readonly OperandType _fpSimdType; + private readonly int _reservedStackSize; + private readonly bool _hasCall; + + public RegisterSaveRestore( + uint gprMask, + uint fpSimdMask = 0, + OperandType fpSimdType = OperandType.FP64, + bool hasCall = false, + int reservedStackSize = 0) + { + _gprMask = gprMask; + _fpSimdMask = fpSimdMask; + _fpSimdType = fpSimdType; + _reservedStackSize = reservedStackSize; + _hasCall = hasCall; + } + + public int GetReservedStackOffset() + { + int gprCalleeSavedRegsCount = BitOperations.PopCount(_gprMask); + int fpSimdCalleeSavedRegsCount = BitOperations.PopCount(_fpSimdMask); + + return (_hasCall ? 16 : 0) + Align16(gprCalleeSavedRegsCount * 8 + fpSimdCalleeSavedRegsCount * _fpSimdType.GetSizeInBytes()); + } + + public void WritePrologue(ref Assembler asm) + { + uint gprMask = _gprMask; + uint fpSimdMask = _fpSimdMask; + + int gprCalleeSavedRegsCount = BitOperations.PopCount(gprMask); + int fpSimdCalleeSavedRegsCount = BitOperations.PopCount(fpSimdMask); + + int reservedStackSize = Align16(_reservedStackSize); + int calleeSaveRegionSize = Align16(gprCalleeSavedRegsCount * 8 + fpSimdCalleeSavedRegsCount * _fpSimdType.GetSizeInBytes()) + reservedStackSize; + int offset = 0; + + WritePrologueCalleeSavesPreIndexed(ref asm, ref gprMask, ref offset, calleeSaveRegionSize, OperandType.I64); + + if (_fpSimdType == OperandType.V128 && (gprCalleeSavedRegsCount & 1) != 0) + { + offset += 8; + } + + WritePrologueCalleeSavesPreIndexed(ref asm, ref fpSimdMask, ref offset, calleeSaveRegionSize, _fpSimdType); + + if (_hasCall) + { + Operand rsp = Register(Assembler.SpRegister); + + if (offset != 0 || calleeSaveRegionSize + 16 < Encodable9BitsOffsetLimit) + { + asm.StpRiPre(Register(FpRegister), Register(LrRegister), rsp, offset == 0 ? -(calleeSaveRegionSize + 16) : -16); + } + else + { + asm.Sub(rsp, rsp, new Operand(OperandKind.Constant, OperandType.I64, (ulong)calleeSaveRegionSize)); + asm.StpRiPre(Register(FpRegister), Register(LrRegister), rsp, -16); + } + + asm.MovSp(Register(FpRegister), rsp); + } + } + + private static void WritePrologueCalleeSavesPreIndexed( + ref Assembler asm, + ref uint mask, + ref int offset, + int calleeSaveRegionSize, + OperandType type) + { + if ((BitOperations.PopCount(mask) & 1) != 0) + { + int reg = BitOperations.TrailingZeroCount(mask); + + mask &= ~(1u << 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 &= ~(1u << reg); + + int reg2 = BitOperations.TrailingZeroCount(mask); + + mask &= ~(1u << 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(ref Assembler asm) + { + uint gprMask = _gprMask; + uint fpSimdMask = _fpSimdMask; + + int gprCalleeSavedRegsCount = BitOperations.PopCount(gprMask); + int fpSimdCalleeSavedRegsCount = BitOperations.PopCount(fpSimdMask); + + bool misalignedVector = _fpSimdType == OperandType.V128 && (gprCalleeSavedRegsCount & 1) != 0; + + int offset = gprCalleeSavedRegsCount * 8 + fpSimdCalleeSavedRegsCount * _fpSimdType.GetSizeInBytes(); + + if (misalignedVector) + { + offset += 8; + } + + int calleeSaveRegionSize = Align16(offset) + Align16(_reservedStackSize); + + if (_hasCall) + { + Operand rsp = Register(Assembler.SpRegister); + + if (offset != 0 || calleeSaveRegionSize + 16 < Encodable9BitsOffsetLimit) + { + asm.LdpRiPost(Register(FpRegister), Register(LrRegister), rsp, offset == 0 ? calleeSaveRegionSize + 16 : 16); + } + else + { + asm.LdpRiPost(Register(FpRegister), Register(LrRegister), rsp, 16); + asm.Add(rsp, rsp, new Operand(OperandKind.Constant, OperandType.I64, (ulong)calleeSaveRegionSize)); + } + } + + WriteEpilogueCalleeSavesPostIndexed(ref asm, ref fpSimdMask, ref offset, calleeSaveRegionSize, _fpSimdType); + + if (misalignedVector) + { + offset -= 8; + } + + WriteEpilogueCalleeSavesPostIndexed(ref asm, ref gprMask, ref offset, calleeSaveRegionSize, OperandType.I64); + } + + private static void WriteEpilogueCalleeSavesPostIndexed( + ref Assembler asm, + ref uint mask, + ref int offset, + int calleeSaveRegionSize, + OperandType type) + { + while (mask != 0) + { + int reg = HighestBitSet(mask); + + mask &= ~(1u << reg); + + if (mask != 0) + { + int reg2 = HighestBitSet(mask); + + mask &= ~(1u << 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(uint value) + { + return 31 - BitOperations.LeadingZeroCount(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; + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/CodeGen/Arm64/StackWalker.cs b/src/Ryujinx.Cpu/LightningJit/CodeGen/Arm64/StackWalker.cs new file mode 100644 index 000000000..3b01e674b --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/CodeGen/Arm64/StackWalker.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; + +namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64 +{ + class StackWalker : IStackWalker + { + public IEnumerable GetCallStack(IntPtr framePointer, IntPtr codeRegionStart, int codeRegionSize, IntPtr codeRegion2Start, int codeRegion2Size) + { + List functionPointers = new(); + + while (true) + { + IntPtr functionPointer = Marshal.ReadIntPtr(framePointer, IntPtr.Size); + + if ((functionPointer < codeRegionStart || functionPointer >= codeRegionStart + codeRegionSize) && + (functionPointer < codeRegion2Start || functionPointer >= codeRegion2Start + codeRegion2Size)) + { + break; + } + + functionPointers.Add((ulong)functionPointer - 4); + framePointer = Marshal.ReadIntPtr(framePointer); + } + + return functionPointers; + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/CodeGen/Arm64/TailMerger.cs b/src/Ryujinx.Cpu/LightningJit/CodeGen/Arm64/TailMerger.cs new file mode 100644 index 000000000..e042af126 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/CodeGen/Arm64/TailMerger.cs @@ -0,0 +1,120 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; + +namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64 +{ + class TailMerger + { + private enum BranchType + { + Conditional, + Unconditional, + } + + private readonly List<(BranchType, int)> _branchPointers; + + public TailMerger() + { + _branchPointers = new(); + } + + public void AddConditionalReturn(CodeWriter writer, in Assembler asm, ArmCondition returnCondition) + { + _branchPointers.Add((BranchType.Conditional, writer.InstructionPointer)); + asm.B(returnCondition, 0); + } + + public void AddConditionalZeroReturn(CodeWriter writer, in Assembler asm, Operand value) + { + _branchPointers.Add((BranchType.Conditional, writer.InstructionPointer)); + asm.Cbz(value, 0); + } + + public void AddUnconditionalReturn(CodeWriter writer, in Assembler asm) + { + _branchPointers.Add((BranchType.Unconditional, writer.InstructionPointer)); + asm.B(0); + } + + public void WriteReturn(CodeWriter writer, Action writeEpilogue) + { + if (_branchPointers.Count == 0) + { + return; + } + + int targetIndex = writer.InstructionPointer; + int startIndex = _branchPointers.Count - 1; + + if (startIndex >= 0 && + _branchPointers[startIndex].Item1 == BranchType.Unconditional && + _branchPointers[startIndex].Item2 == targetIndex - 1) + { + // Remove the last branch if it is redundant. + writer.RemoveLastInstruction(); + startIndex--; + targetIndex--; + } + + Assembler asm = new(writer); + + writeEpilogue(); + asm.Ret(); + + for (int i = startIndex; i >= 0; i--) + { + (BranchType type, int branchIndex) = _branchPointers[i]; + + uint encoding = writer.ReadInstructionAt(branchIndex); + int delta = targetIndex - branchIndex; + + if (type == BranchType.Conditional) + { + uint branchMask = 0x7ffff; + int branchMax = (int)(branchMask + 1) / 2; + + if (delta >= -branchMax && delta < branchMax) + { + writer.WriteInstructionAt(branchIndex, (encoding & ~(branchMask << 5)) | (uint)((delta & branchMask) << 5)); + } + else + { + // If the branch target is too far away, we use a regular unconditional branch + // instruction instead which has a much higher range. + // We branch directly to the end of the function, where we put the conditional branch, + // and then branch back to the next instruction or return the branch target depending + // on the branch being taken or not. + + delta = writer.InstructionPointer - branchIndex; + + uint branchInst = 0x14000000u | ((uint)delta & 0x3ffffff); + Debug.Assert(ExtractSImm26Times4(branchInst) == delta * 4); + + writer.WriteInstructionAt(branchIndex, branchInst); + + int movedBranchIndex = writer.InstructionPointer; + + writer.WriteInstruction(0u); // Placeholder + asm.B((branchIndex + 1 - writer.InstructionPointer) * 4); + + delta = targetIndex - movedBranchIndex; + + writer.WriteInstructionAt(movedBranchIndex, (encoding & ~(branchMask << 5)) | (uint)((delta & branchMask) << 5)); + } + } + else + { + Debug.Assert(type == BranchType.Unconditional); + + writer.WriteInstructionAt(branchIndex, (encoding & ~0x3ffffffu) | (uint)(delta & 0x3ffffff)); + } + } + } + + private static int ExtractSImm26Times4(uint encoding) + { + return (int)(encoding << 6) >> 4; + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/CodeGen/Operand.cs b/src/Ryujinx.Cpu/LightningJit/CodeGen/Operand.cs new file mode 100644 index 000000000..8bf340304 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/CodeGen/Operand.cs @@ -0,0 +1,38 @@ +using System.Diagnostics; + +namespace Ryujinx.Cpu.LightningJit.CodeGen +{ + readonly 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) + { + } + + 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; + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/CodeGen/OperandKind.cs b/src/Ryujinx.Cpu/LightningJit/CodeGen/OperandKind.cs new file mode 100644 index 000000000..4f31763ba --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/CodeGen/OperandKind.cs @@ -0,0 +1,10 @@ +namespace Ryujinx.Cpu.LightningJit.CodeGen +{ + enum OperandKind + { + None, + Constant, + Label, + Register, + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/CodeGen/OperandType.cs b/src/Ryujinx.Cpu/LightningJit/CodeGen/OperandType.cs new file mode 100644 index 000000000..6191f791b --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/CodeGen/OperandType.cs @@ -0,0 +1,35 @@ +using System; + +namespace Ryujinx.Cpu.LightningJit.CodeGen +{ + 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}\"."), + }; + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/CodeGen/Register.cs b/src/Ryujinx.Cpu/LightningJit/CodeGen/Register.cs new file mode 100644 index 000000000..8b96c9164 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/CodeGen/Register.cs @@ -0,0 +1,42 @@ +using System; + +namespace Ryujinx.Cpu.LightningJit.CodeGen +{ + readonly struct Register : IEquatable + { + 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; + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/CodeGen/RegisterType.cs b/src/Ryujinx.Cpu/LightningJit/CodeGen/RegisterType.cs new file mode 100644 index 000000000..c4a726bc9 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/CodeGen/RegisterType.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.Cpu.LightningJit.CodeGen +{ + enum RegisterType + { + Integer, + Vector, + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/CodeWriter.cs b/src/Ryujinx.Cpu/LightningJit/CodeWriter.cs new file mode 100644 index 000000000..ac4b22ff1 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/CodeWriter.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; + +namespace Ryujinx.Cpu.LightningJit +{ + class CodeWriter + { + private readonly List _instructions; + + public int InstructionPointer => _instructions.Count; + + public CodeWriter() + { + _instructions = new(); + } + + public void WriteInstruction(uint instruction) + { + _instructions.Add(instruction); + } + + public void WriteInstructionAt(int index, uint instruction) + { + _instructions[index] = instruction; + } + + public void WriteInstructionsAt(int index, CodeWriter writer) + { + _instructions.InsertRange(index, writer._instructions); + } + + public uint ReadInstructionAt(int index) + { + return _instructions[index]; + } + + public List GetList() + { + return _instructions; + } + + public void RemoveLastInstruction() + { + if (_instructions.Count > 0) + { + _instructions.RemoveAt(_instructions.Count - 1); + } + } + + public ReadOnlySpan AsSpan() + { + return CollectionsMarshal.AsSpan(_instructions); + } + + public ReadOnlySpan AsByteSpan() + { + return MemoryMarshal.Cast(AsSpan()); + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/CompiledFunction.cs b/src/Ryujinx.Cpu/LightningJit/CompiledFunction.cs new file mode 100644 index 000000000..ed375f220 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/CompiledFunction.cs @@ -0,0 +1,16 @@ +using System; + +namespace Ryujinx.Cpu.LightningJit +{ + readonly ref struct CompiledFunction + { + public readonly ReadOnlySpan Code; + public readonly int GuestCodeLength; + + public CompiledFunction(ReadOnlySpan code, int guestCodeLength) + { + Code = code; + GuestCodeLength = guestCodeLength; + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/CpuPreset.cs b/src/Ryujinx.Cpu/LightningJit/CpuPreset.cs new file mode 100644 index 000000000..e5af69b3f --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/CpuPreset.cs @@ -0,0 +1,14 @@ +namespace Ryujinx.Cpu.LightningJit +{ + public readonly struct CpuPreset + { + public readonly IsaVersion Version; + public readonly IsaFeature Features; + + public CpuPreset(IsaVersion version, IsaFeature features) + { + Version = version; + Features = features; + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/CpuPresets.cs b/src/Ryujinx.Cpu/LightningJit/CpuPresets.cs new file mode 100644 index 000000000..7798fbfc7 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/CpuPresets.cs @@ -0,0 +1,13 @@ +namespace Ryujinx.Cpu.LightningJit +{ + public static class CpuPresets + { + public static CpuPreset CortexA57 => new( + IsaVersion.v80, + IsaFeature.FeatAes | + IsaFeature.FeatCrc32 | + IsaFeature.FeatSha1 | + IsaFeature.FeatSha256 | + IsaFeature.FeatPmull); + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Graph/DataFlow.cs b/src/Ryujinx.Cpu/LightningJit/Graph/DataFlow.cs new file mode 100644 index 000000000..e5b369d66 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Graph/DataFlow.cs @@ -0,0 +1,171 @@ +namespace Ryujinx.Cpu.LightningJit.Graph +{ + static class DataFlow + { + public static (RegisterMask[], RegisterMask[]) GetGlobalUses(IBlockList blocks) + { + // Compute local register inputs and outputs used inside blocks. + RegisterMask[] localInputs = new RegisterMask[blocks.Count]; + RegisterMask[] localOutputs = new RegisterMask[blocks.Count]; + + for (int index = 0; index < blocks.Count; index++) + { + IBlock block = blocks[index]; + + RegisterUse use = block.ComputeUseMasks(); + + localInputs[block.Index] = use.Read; + localOutputs[block.Index] = use.Write; + } + + // Compute global register inputs and outputs used across blocks. + RegisterMask[] globalInputs = new RegisterMask[blocks.Count]; + RegisterMask[] globalOutputs = new RegisterMask[blocks.Count]; + + bool modified; + + // Compute register outputs. + do + { + modified = false; + + for (int index = 0; index < blocks.Count; index++) + { + IBlock block = blocks[index]; + + int firstPIndex = GetFirstPredecessorIndex(block); + if (firstPIndex >= 0) + { + IBlock predecessor = block.GetPredecessor(firstPIndex); + + RegisterMask outputs = globalOutputs[predecessor.Index]; + + for (int pIndex = firstPIndex + 1; pIndex < block.PredecessorsCount; pIndex++) + { + predecessor = block.GetPredecessor(pIndex); + + if (predecessor.EndsWithContextStore()) + { + // If a block ended with a context store, then we don't need to care + // about any of it's outputs, as they have already been saved to the context. + // Common outputs must be reset as doing a context stores indicates we will + // do a function call and wipe all register values. + + continue; + } + + outputs |= globalOutputs[predecessor.Index]; + } + + outputs |= localOutputs[block.Index]; + modified |= Exchange(globalOutputs, block.Index, globalOutputs[block.Index] | outputs); + } + else + { + modified |= Exchange(globalOutputs, block.Index, localOutputs[block.Index]); + } + } + } + while (modified); + + // Compute register inputs. + do + { + modified = false; + + for (int index = blocks.Count - 1; index >= 0; index--) + { + IBlock block = blocks[index]; + + RegisterMask cmnOutputs = RegisterMask.Zero; + RegisterMask allOutputs = RegisterMask.Zero; + + int firstPIndex = GetFirstPredecessorIndex(block); + if (firstPIndex == 0) + { + IBlock predecessor = block.GetPredecessor(0); + + // Assumes that block index 0 is the entry block. + cmnOutputs = block.Index != 0 ? globalOutputs[predecessor.Index] : RegisterMask.Zero; + allOutputs = globalOutputs[predecessor.Index]; + + for (int pIndex = 1; pIndex < block.PredecessorsCount; pIndex++) + { + predecessor = block.GetPredecessor(pIndex); + + if (!predecessor.EndsWithContextStore()) + { + RegisterMask outputs = globalOutputs[predecessor.Index]; + + cmnOutputs &= outputs; + allOutputs |= outputs; + } + else + { + cmnOutputs = RegisterMask.Zero; + } + } + } + else if (firstPIndex > 0) + { + IBlock predecessor = block.GetPredecessor(firstPIndex); + + allOutputs = globalOutputs[predecessor.Index]; + + for (int pIndex = firstPIndex + 1; pIndex < block.PredecessorsCount; pIndex++) + { + predecessor = block.GetPredecessor(pIndex); + + if (!predecessor.EndsWithContextStore()) + { + allOutputs |= globalOutputs[predecessor.Index]; + } + } + } + + RegisterMask inputs = localInputs[block.Index]; + + // If this block will load from context at the end, + // we don't need to care about what comes next. + if (!block.EndsWithContextLoad()) + { + for (int sIndex = 0; sIndex < block.SuccessorsCount; sIndex++) + { + inputs |= globalInputs[block.GetSuccessor(sIndex).Index] & ~localOutputs[block.Index]; + } + } + + inputs |= allOutputs & ~localOutputs[block.Index]; + inputs &= ~cmnOutputs; + + modified |= Exchange(globalInputs, block.Index, globalInputs[block.Index] | inputs); + } + } + while (modified); + + return (globalInputs, globalOutputs); + } + + private static bool Exchange(RegisterMask[] masks, int blkIndex, RegisterMask value) + { + ref RegisterMask curValue = ref masks[blkIndex]; + bool changed = curValue != value; + curValue = value; + + return changed; + } + + private static int GetFirstPredecessorIndex(IBlock block) + { + for (int pIndex = 0; pIndex < block.PredecessorsCount; pIndex++) + { + if (!block.GetPredecessor(pIndex).EndsWithContextStore()) + { + return pIndex; + } + } + + return -1; + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Graph/IBlock.cs b/src/Ryujinx.Cpu/LightningJit/Graph/IBlock.cs new file mode 100644 index 000000000..2e5d71322 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Graph/IBlock.cs @@ -0,0 +1,17 @@ +namespace Ryujinx.Cpu.LightningJit.Graph +{ + interface IBlock + { + int Index { get; } + + int PredecessorsCount { get; } + int SuccessorsCount { get; } + + IBlock GetSuccessor(int index); + IBlock GetPredecessor(int index); + + RegisterUse ComputeUseMasks(); + bool EndsWithContextLoad(); + bool EndsWithContextStore(); + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Graph/IBlockList.cs b/src/Ryujinx.Cpu/LightningJit/Graph/IBlockList.cs new file mode 100644 index 000000000..aeec799cb --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Graph/IBlockList.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.Cpu.LightningJit.Graph +{ + interface IBlockList + { + int Count { get; } + + IBlock this[int index] { get; } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Graph/RegisterMask.cs b/src/Ryujinx.Cpu/LightningJit/Graph/RegisterMask.cs new file mode 100644 index 000000000..cde324d5c --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Graph/RegisterMask.cs @@ -0,0 +1,60 @@ +using System; + +namespace Ryujinx.Cpu.LightningJit.Graph +{ + readonly struct RegisterMask : IEquatable + { + public readonly uint GprMask; + public readonly uint FpSimdMask; + public readonly uint PStateMask; + + public static RegisterMask Zero => new(0u, 0u, 0u); + + public RegisterMask(uint gprMask, uint fpSimdMask, uint pStateMask) + { + GprMask = gprMask; + FpSimdMask = fpSimdMask; + PStateMask = pStateMask; + } + + public static RegisterMask operator &(RegisterMask x, RegisterMask y) + { + return new(x.GprMask & y.GprMask, x.FpSimdMask & y.FpSimdMask, x.PStateMask & y.PStateMask); + } + + public static RegisterMask operator |(RegisterMask x, RegisterMask y) + { + return new(x.GprMask | y.GprMask, x.FpSimdMask | y.FpSimdMask, x.PStateMask | y.PStateMask); + } + + public static RegisterMask operator ~(RegisterMask x) + { + return new(~x.GprMask, ~x.FpSimdMask, ~x.PStateMask); + } + + public static bool operator ==(RegisterMask x, RegisterMask y) + { + return x.Equals(y); + } + + public static bool operator !=(RegisterMask x, RegisterMask y) + { + return !x.Equals(y); + } + + public override bool Equals(object obj) + { + return obj is RegisterMask regMask && Equals(regMask); + } + + public bool Equals(RegisterMask other) + { + return GprMask == other.GprMask && FpSimdMask == other.FpSimdMask && PStateMask == other.PStateMask; + } + + public override int GetHashCode() + { + return HashCode.Combine(GprMask, FpSimdMask, PStateMask); + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Graph/RegisterUse.cs b/src/Ryujinx.Cpu/LightningJit/Graph/RegisterUse.cs new file mode 100644 index 000000000..83ef4192c --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Graph/RegisterUse.cs @@ -0,0 +1,24 @@ +namespace Ryujinx.Cpu.LightningJit.Graph +{ + readonly struct RegisterUse + { + public readonly RegisterMask Read; + public readonly RegisterMask Write; + + public RegisterUse(RegisterMask read, RegisterMask write) + { + Read = read; + Write = write; + } + + public RegisterUse( + uint gprReadMask, + uint gprWriteMask, + uint fpSimdReadMask, + uint fpSimdWriteMask, + uint pStateReadMask, + uint pStateWriteMask) : this(new(gprReadMask, fpSimdReadMask, pStateReadMask), new(gprWriteMask, fpSimdWriteMask, pStateWriteMask)) + { + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/IStackWalker.cs b/src/Ryujinx.Cpu/LightningJit/IStackWalker.cs new file mode 100644 index 000000000..2fddef659 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/IStackWalker.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; + +namespace Ryujinx.Cpu.LightningJit +{ + interface IStackWalker + { + IEnumerable GetCallStack(IntPtr framePointer, IntPtr codeRegionStart, int codeRegionSize, IntPtr codeRegion2Start, int codeRegion2Size); + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/IsaFeature.cs b/src/Ryujinx.Cpu/LightningJit/IsaFeature.cs new file mode 100644 index 000000000..c1f799d28 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/IsaFeature.cs @@ -0,0 +1,65 @@ +using System; + +namespace Ryujinx.Cpu.LightningJit +{ + [Flags] + public enum IsaFeature : ulong + { + None = 0, + FeatAa32bf16 = 1UL << 0, + FeatAa32i8mm = 1UL << 1, + FeatAes = 1UL << 2, + FeatBf16 = 1UL << 3, + FeatBti = 1UL << 4, + FeatChk = 1UL << 5, + FeatClrbhb = 1UL << 6, + FeatCrc32 = 1UL << 7, + FeatCssc = 1UL << 8, + FeatD128 = 1UL << 9, + FeatDgh = 1UL << 10, + FeatDotprod = 1UL << 11, + FeatFcma = 1UL << 12, + FeatFhm = 1UL << 13, + FeatFlagm = 1UL << 14, + FeatFlagm2 = 1UL << 15, + FeatFp16 = 1UL << 16, + FeatFrintts = 1UL << 17, + FeatGcs = 1UL << 18, + FeatHbc = 1UL << 19, + FeatI8mm = 1UL << 20, + FeatJscvt = 1UL << 21, + FeatLor = 1UL << 22, + FeatLrcpc = 1UL << 23, + FeatLrcpc2 = 1UL << 24, + FeatLrcpc3 = 1UL << 25, + FeatLs64 = 1UL << 26, + FeatLs64Accdata = 1UL << 27, + FeatLs64V = 1UL << 28, + FeatLse = 1UL << 29, + FeatLse128 = 1UL << 30, + FeatMops = 1UL << 31, + FeatMte = 1UL << 32, + FeatMte2 = 1UL << 33, + FeatPan = 1UL << 34, + FeatPauth = 1UL << 35, + FeatPmull = 1UL << 36, + FeatRas = 1UL << 37, + FeatRdm = 1UL << 38, + FeatRprfm = 1UL << 39, + FeatSb = 1UL << 40, + FeatSha1 = 1UL << 41, + FeatSha256 = 1UL << 42, + FeatSha3 = 1UL << 43, + FeatSha512 = 1UL << 44, + FeatSm3 = 1UL << 45, + FeatSm4 = 1UL << 46, + FeatSpe = 1UL << 47, + FeatSysinstr128 = 1UL << 48, + FeatSysreg128 = 1UL << 49, + FeatThe = 1UL << 50, + FeatTme = 1UL << 51, + FeatTrf = 1UL << 52, + FeatWfxt = 1UL << 53, + FeatXs = 1UL << 54, + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/IsaVersion.cs b/src/Ryujinx.Cpu/LightningJit/IsaVersion.cs new file mode 100644 index 000000000..5923eede4 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/IsaVersion.cs @@ -0,0 +1,17 @@ +namespace Ryujinx.Cpu.LightningJit +{ + public enum IsaVersion + { + None, + v80, + v81, + v82, + v83, + v84, + v85, + v86, + v87, + v88, + v89, + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/LightningJitCpuContext.cs b/src/Ryujinx.Cpu/LightningJit/LightningJitCpuContext.cs new file mode 100644 index 000000000..b63636e39 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/LightningJitCpuContext.cs @@ -0,0 +1,58 @@ +using ARMeilleure.Memory; +using Ryujinx.Cpu.Jit; +using Ryujinx.Cpu.LightningJit.State; + +namespace Ryujinx.Cpu.LightningJit +{ + class LightningJitCpuContext : ICpuContext + { + private readonly ITickSource _tickSource; + private readonly Translator _translator; + + public LightningJitCpuContext(ITickSource tickSource, IMemoryManager memory, bool for64Bit) + { + _tickSource = tickSource; + _translator = new Translator(memory, for64Bit); + memory.UnmapEvent += UnmapHandler; + } + + private void UnmapHandler(ulong address, ulong size) + { + _translator.InvalidateJitCacheRegion(address, size); + } + + /// + public IExecutionContext CreateExecutionContext(ExceptionCallbacks exceptionCallbacks) + { + return new ExecutionContext(new JitMemoryAllocator(), _tickSource, exceptionCallbacks); + } + + /// + public void Execute(IExecutionContext context, ulong address) + { + _translator.Execute((ExecutionContext)context, address); + } + + /// + public void InvalidateCacheRegion(ulong address, ulong size) + { + _translator.InvalidateJitCacheRegion(address, size); + } + + /// + public IDiskCacheLoadState LoadDiskCache(string titleIdText, string displayVersion, bool enabled) + { + return new DummyDiskCacheLoadState(); + } + + /// + public void PrepareCodeRange(ulong address, ulong size) + { + } + + public void Dispose() + { + _translator.Dispose(); + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/LightningJitEngine.cs b/src/Ryujinx.Cpu/LightningJit/LightningJitEngine.cs new file mode 100644 index 000000000..c97ddc7c7 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/LightningJitEngine.cs @@ -0,0 +1,20 @@ +using ARMeilleure.Memory; + +namespace Ryujinx.Cpu.LightningJit +{ + public class LightningJitEngine : ICpuEngine + { + private readonly ITickSource _tickSource; + + public LightningJitEngine(ITickSource tickSource) + { + _tickSource = tickSource; + } + + /// + public ICpuContext CreateCpuContext(IMemoryManager memoryManager, bool for64Bit) + { + return new LightningJitCpuContext(_tickSource, memoryManager, for64Bit); + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/NativeContextOffsets.cs b/src/Ryujinx.Cpu/LightningJit/NativeContextOffsets.cs new file mode 100644 index 000000000..8a3a968d0 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/NativeContextOffsets.cs @@ -0,0 +1,17 @@ +using Ryujinx.Cpu.LightningJit.State; + +namespace Ryujinx.Cpu.LightningJit +{ + class NativeContextOffsets + { + public static int GprBaseOffset => NativeContext.GetXOffset(); + public static int FpSimdBaseOffset => NativeContext.GetVOffset(); + public static int FlagsBaseOffset => NativeContext.GetFlagsOffset(); + public static int FpFlagsBaseOffset => NativeContext.GetFpFlagsOffset(); + public static int TpidrEl0Offset => NativeContext.GetTpidrEl0Offset(); + public static int TpidrroEl0Offset => NativeContext.GetTpidrroEl0Offset(); + public static int RunningOffset => NativeContext.GetRunningOffset(); + public static int CounterOffset => NativeContext.GetCounterOffset(); + public static int DispatchAddressOffset => NativeContext.GetDispatchAddressOffset(); + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/NativeInterface.cs b/src/Ryujinx.Cpu/LightningJit/NativeInterface.cs new file mode 100644 index 000000000..da3ad9832 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/NativeInterface.cs @@ -0,0 +1,93 @@ +using ARMeilleure.Memory; +using Ryujinx.Cpu.LightningJit.State; +using System; + +namespace Ryujinx.Cpu.LightningJit +{ + static class NativeInterface + { + private const int DczSizeLog2 = 4; // Log2 size in words + private const int DczSizeInBytes = 4 << DczSizeLog2; + + private class ThreadContext + { + public ExecutionContext Context { get; } + public IMemoryManager Memory { get; } + public Translator Translator { get; } + + public ThreadContext(ExecutionContext context, IMemoryManager memory, Translator translator) + { + Context = context; + Memory = memory; + Translator = translator; + } + } + + [ThreadStatic] + private static ThreadContext Context; + + public static void RegisterThread(ExecutionContext context, IMemoryManager memory, Translator translator) + { + Context = new ThreadContext(context, memory, translator); + } + + public static void UnregisterThread() + { + Context = null; + } + + public static void Break(ulong address, int imm) + { + GetContext().OnBreak(address, imm); + } + + public static void SupervisorCall(ulong address, int imm) + { + GetContext().OnSupervisorCall(address, imm); + } + + public static void Undefined(ulong address, int opCode) + { + GetContext().OnUndefined(address, opCode); + } + + public static ulong GetCntfrqEl0() + { + return GetContext().CntfrqEl0; + } + + public static ulong GetCntpctEl0() + { + return GetContext().CntpctEl0; + } + + public static ulong GetFunctionAddress(IntPtr framePointer, ulong address) + { + return (ulong)Context.Translator.GetOrTranslatePointer(framePointer, address, GetContext().ExecutionMode); + } + + public static void InvalidateCacheLine(ulong address) + { + Context.Translator.InvalidateJitCacheRegion(address, DczSizeInBytes); + } + + public static bool CheckSynchronization() + { + ExecutionContext context = GetContext(); + + context.CheckInterrupt(); + + return context.Running; + } + + public static ExecutionContext GetContext() + { + return Context.Context; + } + + public static IMemoryManager GetMemoryManager() + { + return Context.Memory; + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/State/ExecutionContext.cs b/src/Ryujinx.Cpu/LightningJit/State/ExecutionContext.cs new file mode 100644 index 000000000..facb9142f --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/State/ExecutionContext.cs @@ -0,0 +1,153 @@ +using ARMeilleure.Memory; +using ARMeilleure.State; +using System; + +namespace Ryujinx.Cpu.LightningJit.State +{ + public class ExecutionContext : IExecutionContext + { + private const int MinCountForCheck = 4000; + + private readonly NativeContext _nativeContext; + + internal IntPtr NativeContextPtr => _nativeContext.BasePtr; + + private bool _interrupted; + private readonly ICounter _counter; + + public ulong Pc => _nativeContext.GetPc(); + + public ulong CntfrqEl0 => _counter.Frequency; + public ulong CntpctEl0 => _counter.Counter; + + public long TpidrEl0 + { + get => _nativeContext.GetTpidrEl0(); + set => _nativeContext.SetTpidrEl0(value); + } + + public long TpidrroEl0 + { + get => _nativeContext.GetTpidrroEl0(); + set => _nativeContext.SetTpidrroEl0(value); + } + + public uint Pstate + { + get => _nativeContext.GetPstate(); + set => _nativeContext.SetPstate(value); + } + + public uint Fpsr + { + get => _nativeContext.GetFPState((uint)FPSR.Mask); + set => _nativeContext.SetFPState(value, (uint)FPSR.Mask); + } + + public uint Fpcr + { + get => _nativeContext.GetFPState((uint)FPCR.Mask); + set => _nativeContext.SetFPState(value, (uint)FPCR.Mask); + } + + public bool IsAarch32 { get; set; } + + internal ExecutionMode ExecutionMode + { + get + { + if (IsAarch32) + { + return (Pstate & (1u << 5)) != 0 + ? ExecutionMode.Aarch32Thumb + : ExecutionMode.Aarch32Arm; + } + else + { + return ExecutionMode.Aarch64; + } + } + } + + public bool Running + { + get => _nativeContext.GetRunning(); + private set => _nativeContext.SetRunning(value); + } + + private readonly ExceptionCallbackNoArgs _interruptCallback; + private readonly ExceptionCallback _breakCallback; + private readonly ExceptionCallback _supervisorCallback; + private readonly ExceptionCallback _undefinedCallback; + + public ExecutionContext(IJitMemoryAllocator allocator, ICounter counter, ExceptionCallbacks exceptionCallbacks) + { + _nativeContext = new NativeContext(allocator); + _counter = counter; + _interruptCallback = exceptionCallbacks.InterruptCallback; + _breakCallback = exceptionCallbacks.BreakCallback; + _supervisorCallback = exceptionCallbacks.SupervisorCallback; + _undefinedCallback = exceptionCallbacks.UndefinedCallback; + + Running = true; + + _nativeContext.SetCounter(MinCountForCheck); + } + + public ulong GetX(int index) => _nativeContext.GetX(index); + public void SetX(int index, ulong value) => _nativeContext.SetX(index, value); + + public V128 GetV(int index) => _nativeContext.GetV(index); + public void SetV(int index, V128 value) => _nativeContext.SetV(index, value); + + internal void CheckInterrupt() + { + if (_interrupted) + { + _interrupted = false; + + _interruptCallback?.Invoke(this); + } + + _nativeContext.SetCounter(MinCountForCheck); + } + + public void RequestInterrupt() + { + _interrupted = true; + } + + internal void OnBreak(ulong address, int imm) + { + _breakCallback?.Invoke(this, address, imm); + } + + internal void OnSupervisorCall(ulong address, int imm) + { + _supervisorCallback?.Invoke(this, address, imm); + } + + internal void OnUndefined(ulong address, int opCode) + { + _undefinedCallback?.Invoke(this, address, opCode); + } + + public void StopRunning() + { + Running = false; + + _nativeContext.SetCounter(0); + } + + protected virtual void Dispose(bool disposing) + { + _nativeContext.Dispose(); + } + + public void Dispose() + { + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/State/ExecutionMode.cs b/src/Ryujinx.Cpu/LightningJit/State/ExecutionMode.cs new file mode 100644 index 000000000..0602bc9af --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/State/ExecutionMode.cs @@ -0,0 +1,9 @@ +namespace Ryujinx.Cpu.LightningJit.State +{ + enum ExecutionMode + { + Aarch32Arm = 0, + Aarch32Thumb = 1, + Aarch64 = 2, + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/State/NativeContext.cs b/src/Ryujinx.Cpu/LightningJit/State/NativeContext.cs new file mode 100644 index 000000000..fdb8793de --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/State/NativeContext.cs @@ -0,0 +1,173 @@ +using ARMeilleure.Memory; +using ARMeilleure.State; +using System; +using System.Runtime.CompilerServices; + +namespace Ryujinx.Cpu.LightningJit.State +{ + class NativeContext : IDisposable + { + private unsafe struct NativeCtxStorage + { + public fixed ulong X[32]; + public fixed ulong V[64]; + public uint Flags; + public uint FpFlags; + public long TpidrEl0; + public long TpidrroEl0; + public int Counter; + public uint HostFpFlags; + public ulong DispatchAddress; + public int Running; + } + + private static NativeCtxStorage _dummyStorage = new(); + + private readonly IJitMemoryBlock _block; + + public IntPtr BasePtr => _block.Pointer; + + public NativeContext(IJitMemoryAllocator allocator) + { + _block = allocator.Allocate((ulong)Unsafe.SizeOf()); + } + + public ulong GetPc() + { + // TODO: More precise tracking of PC value. + return GetStorage().DispatchAddress; + } + + public unsafe ulong GetX(int index) + { + if ((uint)index >= 32) + { + throw new ArgumentOutOfRangeException(nameof(index)); + } + + return GetStorage().X[index]; + } + + public unsafe void SetX(int index, ulong value) + { + if ((uint)index >= 32) + { + throw new ArgumentOutOfRangeException(nameof(index)); + } + + GetStorage().X[index] = value; + } + + public unsafe V128 GetV(int index) + { + if ((uint)index >= 32) + { + throw new ArgumentOutOfRangeException(nameof(index)); + } + + return new V128(GetStorage().V[index * 2 + 0], GetStorage().V[index * 2 + 1]); + } + + public unsafe void SetV(int index, V128 value) + { + if ((uint)index >= 32) + { + throw new ArgumentOutOfRangeException(nameof(index)); + } + + GetStorage().V[index * 2 + 0] = value.Extract(0); + GetStorage().V[index * 2 + 1] = value.Extract(1); + } + + public unsafe uint GetPstate() + { + return GetStorage().Flags; + } + + public unsafe void SetPstate(uint value) + { + GetStorage().Flags = value; + } + + public unsafe uint GetFPState(uint mask = uint.MaxValue) + { + return GetStorage().FpFlags & mask; + } + + public unsafe void SetFPState(uint value, uint mask = uint.MaxValue) + { + GetStorage().FpFlags = (value & mask) | (GetStorage().FpFlags & ~mask); + } + + public long GetTpidrEl0() => GetStorage().TpidrEl0; + public void SetTpidrEl0(long value) => GetStorage().TpidrEl0 = value; + + public long GetTpidrroEl0() => GetStorage().TpidrroEl0; + public void SetTpidrroEl0(long value) => GetStorage().TpidrroEl0 = value; + + public int GetCounter() => GetStorage().Counter; + public void SetCounter(int value) => GetStorage().Counter = value; + + public bool GetRunning() => GetStorage().Running != 0; + public void SetRunning(bool value) => GetStorage().Running = value ? 1 : 0; + + public unsafe static int GetXOffset() + { + return StorageOffset(ref _dummyStorage, ref _dummyStorage.X[0]); + } + + public unsafe static int GetVOffset() + { + return StorageOffset(ref _dummyStorage, ref _dummyStorage.V[0]); + } + + public static int GetFlagsOffset() + { + return StorageOffset(ref _dummyStorage, ref _dummyStorage.Flags); + } + + public static int GetFpFlagsOffset() + { + return StorageOffset(ref _dummyStorage, ref _dummyStorage.FpFlags); + } + + 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 GetCounterOffset() + { + return StorageOffset(ref _dummyStorage, ref _dummyStorage.Counter); + } + + public static int GetHostFpFlagsOffset() + { + return StorageOffset(ref _dummyStorage, ref _dummyStorage.HostFpFlags); + } + + public static int GetDispatchAddressOffset() + { + return StorageOffset(ref _dummyStorage, ref _dummyStorage.DispatchAddress); + } + + public static int GetRunningOffset() + { + return StorageOffset(ref _dummyStorage, ref _dummyStorage.Running); + } + + private static int StorageOffset(ref NativeCtxStorage storage, ref T target) + { + return (int)Unsafe.ByteOffset(ref Unsafe.As(ref storage), ref target); + } + + private unsafe ref NativeCtxStorage GetStorage() => ref Unsafe.AsRef((void*)_block.Pointer); + + public void Dispose() => _block.Dispose(); + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Table/IInstInfo.cs b/src/Ryujinx.Cpu/LightningJit/Table/IInstInfo.cs new file mode 100644 index 000000000..a51fe37b2 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Table/IInstInfo.cs @@ -0,0 +1,12 @@ +namespace Ryujinx.Cpu.LightningJit.Table +{ + interface IInstInfo + { + public uint Encoding { get; } + public uint EncodingMask { get; } + public IsaVersion Version { get; } + public IsaFeature Feature { get; } + + bool IsConstrained(uint encoding); + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Table/InstEncoding.cs b/src/Ryujinx.Cpu/LightningJit/Table/InstEncoding.cs new file mode 100644 index 000000000..32250b03f --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Table/InstEncoding.cs @@ -0,0 +1,14 @@ +namespace Ryujinx.Cpu.LightningJit.Table +{ + readonly struct InstEncoding + { + public readonly uint Encoding; + public readonly uint EncodingMask; + + public InstEncoding(uint encoding, uint encodingMask) + { + Encoding = encoding; + EncodingMask = encodingMask; + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Table/InstTableLevel.cs b/src/Ryujinx.Cpu/LightningJit/Table/InstTableLevel.cs new file mode 100644 index 000000000..6567efeef --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Table/InstTableLevel.cs @@ -0,0 +1,96 @@ +using System.Collections.Generic; +using System.Numerics; + +namespace Ryujinx.Cpu.LightningJit.Table +{ + class InstTableLevel where T : IInstInfo + { + private readonly int _shift; + private readonly uint _mask; + private readonly InstTableLevel[] _childs; + private readonly List _insts; + + private InstTableLevel(List insts, uint baseMask) + { + uint commonEncodingMask = baseMask; + + foreach (T info in insts) + { + commonEncodingMask &= info.EncodingMask; + } + + if (commonEncodingMask != 0) + { + _shift = BitOperations.TrailingZeroCount(commonEncodingMask); + int bits = BitOperations.TrailingZeroCount(~(commonEncodingMask >> _shift)); + int count = 1 << bits; + _mask = uint.MaxValue >> (32 - bits); + + _childs = new InstTableLevel[count]; + + List[] splitList = new List[count]; + + for (int index = 0; index < insts.Count; index++) + { + int splitIndex = (int)((insts[index].Encoding >> _shift) & _mask); + + (splitList[splitIndex] ??= new()).Add(insts[index]); + } + + for (int index = 0; index < count; index++) + { + if (splitList[index] == null) + { + continue; + } + + _childs[index] = new InstTableLevel(splitList[index], baseMask & ~commonEncodingMask); + } + } + else + { + _insts = insts; + } + } + + public InstTableLevel(List insts) : this(insts, uint.MaxValue) + { + } + + public bool TryFind(uint encoding, IsaVersion version, IsaFeature features, out T value) + { + if (_childs != null) + { + int index = (int)((encoding >> _shift) & _mask); + + if (_childs[index] == null) + { + value = default; + + return false; + } + + return _childs[index].TryFind(encoding, version, features, out value); + } + else + { + foreach (T info in _insts) + { + if ((encoding & info.EncodingMask) == info.Encoding && + !info.IsConstrained(encoding) && + info.Version <= version && + (info.Feature & features) == info.Feature) + { + value = info; + + return true; + } + } + + value = default; + + return false; + } + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/TranslatedFunction.cs b/src/Ryujinx.Cpu/LightningJit/TranslatedFunction.cs new file mode 100644 index 000000000..a4e2c7b93 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/TranslatedFunction.cs @@ -0,0 +1,16 @@ +using System; + +namespace Ryujinx.Cpu.LightningJit +{ + class TranslatedFunction + { + public IntPtr FuncPointer { get; } + public ulong GuestSize { get; } + + public TranslatedFunction(IntPtr funcPointer, ulong guestSize) + { + FuncPointer = funcPointer; + GuestSize = guestSize; + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/Translator.cs b/src/Ryujinx.Cpu/LightningJit/Translator.cs new file mode 100644 index 000000000..c883c1d60 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/Translator.cs @@ -0,0 +1,227 @@ +using ARMeilleure.Common; +using ARMeilleure.Memory; +using Ryujinx.Cpu.Jit; +using Ryujinx.Cpu.LightningJit.Cache; +using Ryujinx.Cpu.LightningJit.CodeGen.Arm64; +using Ryujinx.Cpu.LightningJit.State; +using Ryujinx.Cpu.Signal; +using Ryujinx.Memory; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Threading; + +namespace Ryujinx.Cpu.LightningJit +{ + class Translator : IDisposable + { + // Should be enabled on platforms that enforce W^X. + private static bool IsNoWxPlatform => false; + + private static readonly AddressTable.Level[] _levels64Bit = + new AddressTable.Level[] + { + new(31, 17), + new(23, 8), + new(15, 8), + new( 7, 8), + new( 2, 5), + }; + + private static readonly AddressTable.Level[] _levels32Bit = + new AddressTable.Level[] + { + new(23, 9), + new(15, 8), + new( 7, 8), + new( 1, 6), + }; + + private readonly ConcurrentQueue> _oldFuncs; + private readonly NoWxCache _noWxCache; + private bool _disposed; + + internal TranslatorCache Functions { get; } + internal AddressTable FunctionTable { get; } + internal TranslatorStubs Stubs { get; } + internal IMemoryManager Memory { get; } + + public Translator(IMemoryManager memory, bool for64Bits) + { + Memory = memory; + + _oldFuncs = new ConcurrentQueue>(); + + if (IsNoWxPlatform) + { + _noWxCache = new(new JitMemoryAllocator(), CreateStackWalker(), this); + } + else + { + JitCache.Initialize(new JitMemoryAllocator(forJit: true)); + } + + Functions = new TranslatorCache(); + FunctionTable = new AddressTable(for64Bits ? _levels64Bit : _levels32Bit); + Stubs = new TranslatorStubs(FunctionTable, _noWxCache); + + FunctionTable.Fill = (ulong)Stubs.SlowDispatchStub; + + if (memory.Type.IsHostMapped()) + { + NativeSignalHandler.InitializeSignalHandler(MemoryBlock.GetPageSize()); + } + } + + private static IStackWalker CreateStackWalker() + { + if (RuntimeInformation.ProcessArchitecture == Architecture.Arm64) + { + return new StackWalker(); + } + else + { + throw new PlatformNotSupportedException(); + } + } + + public void Execute(State.ExecutionContext context, ulong address) + { + ObjectDisposedException.ThrowIf(_disposed, this); + + NativeInterface.RegisterThread(context, Memory, this); + + Stubs.DispatchLoop(context.NativeContextPtr, address); + + NativeInterface.UnregisterThread(); + _noWxCache?.ClearEntireThreadLocalCache(); + } + + internal IntPtr GetOrTranslatePointer(IntPtr framePointer, ulong address, ExecutionMode mode) + { + if (_noWxCache != null) + { + CompiledFunction func = Compile(address, mode); + + return _noWxCache.Map(framePointer, func.Code, address, (ulong)func.GuestCodeLength); + } + + return GetOrTranslate(address, mode).FuncPointer; + } + + private TranslatedFunction GetOrTranslate(ulong address, ExecutionMode mode) + { + if (!Functions.TryGetValue(address, out TranslatedFunction func)) + { + func = Translate(address, mode); + + TranslatedFunction oldFunc = Functions.GetOrAdd(address, func.GuestSize, func); + + if (oldFunc != func) + { + JitCache.Unmap(func.FuncPointer); + func = oldFunc; + } + + RegisterFunction(address, func); + } + + return func; + } + + internal void RegisterFunction(ulong guestAddress, TranslatedFunction func) + { + if (FunctionTable.IsValid(guestAddress)) + { + Volatile.Write(ref FunctionTable.GetValue(guestAddress), (ulong)func.FuncPointer); + } + } + + private TranslatedFunction Translate(ulong address, ExecutionMode mode) + { + CompiledFunction func = Compile(address, mode); + IntPtr funcPointer = JitCache.Map(func.Code); + + return new TranslatedFunction(funcPointer, (ulong)func.GuestCodeLength); + } + + private CompiledFunction Compile(ulong address, ExecutionMode mode) + { + return AarchCompiler.Compile(CpuPresets.CortexA57, Memory, address, FunctionTable, Stubs.DispatchStub, mode, RuntimeInformation.ProcessArchitecture); + } + + public void InvalidateJitCacheRegion(ulong address, ulong size) + { + ulong[] overlapAddresses = Array.Empty(); + + int overlapsCount = Functions.GetOverlaps(address, size, ref overlapAddresses); + + for (int index = 0; index < overlapsCount; index++) + { + ulong overlapAddress = overlapAddresses[index]; + + if (Functions.TryGetValue(overlapAddress, out TranslatedFunction overlap)) + { + Functions.Remove(overlapAddress); + Volatile.Write(ref FunctionTable.GetValue(overlapAddress), FunctionTable.Fill); + EnqueueForDeletion(overlapAddress, overlap); + } + } + + // TODO: Remove overlapping functions from the JitCache aswell. + // This should be done safely, with a mechanism to ensure the function is not being executed. + } + + private void EnqueueForDeletion(ulong guestAddress, TranslatedFunction func) + { + _oldFuncs.Enqueue(new(guestAddress, func)); + } + + private void ClearJitCache() + { + List functions = Functions.AsList(); + + foreach (var func in functions) + { + JitCache.Unmap(func.FuncPointer); + } + + Functions.Clear(); + + while (_oldFuncs.TryDequeue(out var kv)) + { + JitCache.Unmap(kv.Value.FuncPointer); + } + } + + protected virtual void Dispose(bool disposing) + { + if (!_disposed) + { + if (disposing) + { + if (_noWxCache != null) + { + _noWxCache.Dispose(); + } + else + { + ClearJitCache(); + } + + Stubs.Dispose(); + FunctionTable.Dispose(); + } + + _disposed = true; + } + } + + public void Dispose() + { + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/TranslatorCache.cs b/src/Ryujinx.Cpu/LightningJit/TranslatorCache.cs new file mode 100644 index 000000000..60e13de9f --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/TranslatorCache.cs @@ -0,0 +1,96 @@ +using ARMeilleure.Translation; +using System; +using System.Collections.Generic; +using System.Threading; + +namespace Ryujinx.Cpu.LightningJit +{ + internal class TranslatorCache + { + private readonly IntervalTree _tree; + private readonly ReaderWriterLockSlim _treeLock; + + public int Count => _tree.Count; + + public TranslatorCache() + { + _tree = new IntervalTree(); + _treeLock = new ReaderWriterLockSlim(); + } + + public bool TryAdd(ulong address, ulong size, T value) + { + return AddOrUpdate(address, size, value, null); + } + + public bool AddOrUpdate(ulong address, ulong size, T value, Func updateFactoryCallback) + { + _treeLock.EnterWriteLock(); + bool result = _tree.AddOrUpdate(address, address + size, value, updateFactoryCallback); + _treeLock.ExitWriteLock(); + + return result; + } + + public T GetOrAdd(ulong address, ulong size, T value) + { + _treeLock.EnterWriteLock(); + value = _tree.GetOrAdd(address, address + size, value); + _treeLock.ExitWriteLock(); + + return value; + } + + public bool Remove(ulong address) + { + _treeLock.EnterWriteLock(); + bool removed = _tree.Remove(address) != 0; + _treeLock.ExitWriteLock(); + + return removed; + } + + public void Clear() + { + _treeLock.EnterWriteLock(); + _tree.Clear(); + _treeLock.ExitWriteLock(); + } + + public bool ContainsKey(ulong address) + { + _treeLock.EnterReadLock(); + bool result = _tree.ContainsKey(address); + _treeLock.ExitReadLock(); + + return result; + } + + public bool TryGetValue(ulong address, out T value) + { + _treeLock.EnterReadLock(); + bool result = _tree.TryGet(address, out value); + _treeLock.ExitReadLock(); + + return result; + } + + public int GetOverlaps(ulong address, ulong size, ref ulong[] overlaps) + { + _treeLock.EnterReadLock(); + int count = _tree.Get(address, address + size, ref overlaps); + _treeLock.ExitReadLock(); + + return count; + } + + public List AsList() + { + _treeLock.EnterReadLock(); + List list = _tree.AsList(); + _treeLock.ExitReadLock(); + + return list; + } + } +} diff --git a/src/Ryujinx.Cpu/LightningJit/TranslatorStubs.cs b/src/Ryujinx.Cpu/LightningJit/TranslatorStubs.cs new file mode 100644 index 000000000..914712bb1 --- /dev/null +++ b/src/Ryujinx.Cpu/LightningJit/TranslatorStubs.cs @@ -0,0 +1,380 @@ +using ARMeilleure.Common; +using Ryujinx.Cpu.LightningJit.Cache; +using Ryujinx.Cpu.LightningJit.CodeGen; +using Ryujinx.Cpu.LightningJit.CodeGen.Arm64; +using Ryujinx.Cpu.LightningJit.State; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace Ryujinx.Cpu.LightningJit +{ + delegate void DispatcherFunction(IntPtr nativeContext, ulong startAddress); + + /// + /// Represents a stub manager. + /// + class TranslatorStubs : IDisposable + { + private delegate ulong GetFunctionAddressDelegate(IntPtr framePointer, ulong address); + + private readonly Lazy _slowDispatchStub; + + private bool _disposed; + + private readonly AddressTable _functionTable; + private readonly NoWxCache _noWxCache; + private readonly GetFunctionAddressDelegate _getFunctionAddressRef; + private readonly IntPtr _getFunctionAddress; + private readonly Lazy _dispatchStub; + private readonly Lazy _dispatchLoop; + + /// + /// Gets the dispatch stub. + /// + /// instance was disposed + public IntPtr DispatchStub + { + get + { + ObjectDisposedException.ThrowIf(_disposed, this); + + return _dispatchStub.Value; + } + } + + /// + /// Gets the slow dispatch stub. + /// + /// instance was disposed + public IntPtr SlowDispatchStub + { + get + { + ObjectDisposedException.ThrowIf(_disposed, this); + + return _slowDispatchStub.Value; + } + } + + /// + /// Gets the dispatch loop function. + /// + /// instance was disposed + public DispatcherFunction DispatchLoop + { + get + { + ObjectDisposedException.ThrowIf(_disposed, this); + + return _dispatchLoop.Value; + } + } + + /// + /// Initializes a new instance of the class with the specified + /// instance. + /// + /// Function table used to store pointers to the functions that the guest code will call + /// Cache used on platforms that enforce W^X, otherwise should be null + /// is null + public TranslatorStubs(AddressTable functionTable, NoWxCache noWxCache) + { + ArgumentNullException.ThrowIfNull(functionTable); + + _functionTable = functionTable; + _noWxCache = noWxCache; + _getFunctionAddressRef = NativeInterface.GetFunctionAddress; + _getFunctionAddress = Marshal.GetFunctionPointerForDelegate(_getFunctionAddressRef); + _slowDispatchStub = new(GenerateSlowDispatchStub, isThreadSafe: true); + _dispatchStub = new(GenerateDispatchStub, isThreadSafe: true); + _dispatchLoop = new(GenerateDispatchLoop, isThreadSafe: true); + } + + /// + /// Releases all resources used by the instance. + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Releases all unmanaged and optionally managed resources used by the instance. + /// + /// to dispose managed resources also; otherwise just unmanaged resouces + protected virtual void Dispose(bool disposing) + { + if (!_disposed) + { + if (_noWxCache == null) + { + if (_dispatchStub.IsValueCreated) + { + JitCache.Unmap(_dispatchStub.Value); + } + + if (_dispatchLoop.IsValueCreated) + { + JitCache.Unmap(Marshal.GetFunctionPointerForDelegate(_dispatchLoop.Value)); + } + } + + _disposed = true; + } + } + + /// + /// Frees resources used by the instance. + /// + ~TranslatorStubs() + { + Dispose(false); + } + + /// + /// Generates a . + /// + /// Generated + private IntPtr GenerateDispatchStub() + { + List branchToFallbackOffsets = new(); + + CodeWriter writer = new(); + + if (RuntimeInformation.ProcessArchitecture == Architecture.Arm64) + { + Assembler asm = new(writer); + RegisterSaveRestore rsr = new((1u << 19) | (1u << 21) | (1u << 22), hasCall: true); + + rsr.WritePrologue(ref asm); + + Operand context = Register(19); + asm.Mov(context, Register(0)); + + // Load the target guest address from the native context. + Operand guestAddress = Register(16); + + asm.LdrRiUn(guestAddress, context, NativeContext.GetDispatchAddressOffset()); + + // Check if guest address is within range of the AddressTable. + asm.And(Register(17), guestAddress, Const(~_functionTable.Mask)); + + branchToFallbackOffsets.Add(writer.InstructionPointer); + + asm.Cbnz(Register(17), 0); + + Operand page = Register(17); + Operand index = Register(21); + Operand mask = Register(22); + + asm.Mov(page, (ulong)_functionTable.Base); + + for (int i = 0; i < _functionTable.Levels.Length; i++) + { + ref var level = ref _functionTable.Levels[i]; + + asm.Mov(mask, level.Mask >> level.Index); + asm.And(index, mask, guestAddress, ArmShiftType.Lsr, level.Index); + + if (i < _functionTable.Levels.Length - 1) + { + asm.LdrRr(page, page, index, ArmExtensionType.Uxtx, true); + + branchToFallbackOffsets.Add(writer.InstructionPointer); + + asm.Cbz(page, 0); + } + } + + asm.LdrRr(page, page, index, ArmExtensionType.Uxtx, true); + + rsr.WriteEpilogue(ref asm); + + asm.Br(page); + + foreach (int branchOffset in branchToFallbackOffsets) + { + uint branchInst = writer.ReadInstructionAt(branchOffset); + Debug.Assert(writer.InstructionPointer > branchOffset); + writer.WriteInstructionAt(branchOffset, branchInst | ((uint)(writer.InstructionPointer - branchOffset) << 5)); + } + + // Fallback. + asm.Mov(Register(0), Register(29)); + asm.Mov(Register(1), guestAddress); + asm.Mov(Register(16), (ulong)_getFunctionAddress); + asm.Blr(Register(16)); + asm.Mov(Register(16), Register(0)); + asm.Mov(Register(0), Register(19)); + + rsr.WriteEpilogue(ref asm); + + asm.Br(Register(16)); + } + else + { + throw new PlatformNotSupportedException(); + } + + return Map(writer.AsByteSpan()); + } + + /// + /// Generates a . + /// + /// Generated + private IntPtr GenerateSlowDispatchStub() + { + CodeWriter writer = new(); + + if (RuntimeInformation.ProcessArchitecture == Architecture.Arm64) + { + Assembler asm = new(writer); + RegisterSaveRestore rsr = new(1u << 19, hasCall: true); + + rsr.WritePrologue(ref asm); + + Operand context = Register(19); + asm.Mov(context, Register(0)); + + // Load the target guest address from the native context. + asm.Mov(Register(0), Register(29)); + asm.LdrRiUn(Register(1), context, NativeContext.GetDispatchAddressOffset()); + asm.Mov(Register(16), (ulong)_getFunctionAddress); + asm.Blr(Register(16)); + asm.Mov(Register(16), Register(0)); + asm.Mov(Register(0), Register(19)); + + rsr.WriteEpilogue(ref asm); + + asm.Br(Register(16)); + } + else + { + throw new PlatformNotSupportedException(); + } + + return Map(writer.AsByteSpan()); + } + + /// + /// Emits code that syncs FP state before executing guest code, or returns it to normal. + /// + /// Assembler + /// Pointer to the native context + /// First temporary register + /// Second temporary register + /// True if entering guest code, false otherwise + private static void EmitSyncFpContext(ref Assembler asm, Operand context, Operand tempRegister, Operand tempRegister2, bool enter) + { + if (enter) + { + EmitSwapFpFlags(ref asm, context, tempRegister, tempRegister2, NativeContext.GetFpFlagsOffset(), NativeContext.GetHostFpFlagsOffset()); + } + else + { + EmitSwapFpFlags(ref asm, context, tempRegister, tempRegister2, NativeContext.GetHostFpFlagsOffset(), NativeContext.GetFpFlagsOffset()); + } + } + + /// + /// Swaps the FPCR and FPSR values with values stored in the native context. + /// + /// Assembler + /// Pointer to the native context + /// First temporary register + /// Second temporary register + /// Offset of the new flags that will be loaded + /// Offset where the current flags should be saved + private static void EmitSwapFpFlags(ref Assembler asm, Operand context, Operand tempRegister, Operand tempRegister2, int loadOffset, int storeOffset) + { + asm.MrsFpcr(tempRegister); + asm.MrsFpsr(tempRegister2); + asm.Orr(tempRegister, tempRegister, tempRegister2); + + asm.StrRiUn(tempRegister, context, storeOffset); + + asm.LdrRiUn(tempRegister, context, loadOffset); + asm.MsrFpcr(tempRegister); + asm.MsrFpsr(tempRegister2); + } + + /// + /// Generates a function. + /// + /// function + private DispatcherFunction GenerateDispatchLoop() + { + CodeWriter writer = new(); + + if (RuntimeInformation.ProcessArchitecture == Architecture.Arm64) + { + Assembler asm = new(writer); + RegisterSaveRestore rsr = new(1u << 19, hasCall: true); + + rsr.WritePrologue(ref asm); + + Operand context = Register(19); + asm.Mov(context, Register(0)); + + EmitSyncFpContext(ref asm, context, Register(16, OperandType.I32), Register(17, OperandType.I32), true); + + // Load the target guest address from the native context. + Operand guestAddress = Register(16); + + asm.Mov(guestAddress, Register(1)); + + int loopStartIndex = writer.InstructionPointer; + + asm.StrRiUn(guestAddress, context, NativeContext.GetDispatchAddressOffset()); + asm.Mov(Register(0), context); + asm.Mov(Register(17), (ulong)DispatchStub); + asm.Blr(Register(17)); + asm.Mov(guestAddress, Register(0)); + asm.Cbz(guestAddress, 16); + asm.LdrRiUn(Register(17), context, NativeContext.GetRunningOffset()); + asm.Cbz(Register(17), 8); + asm.B((loopStartIndex - writer.InstructionPointer) * 4); + + EmitSyncFpContext(ref asm, context, Register(16, OperandType.I32), Register(17, OperandType.I32), false); + + rsr.WriteEpilogue(ref asm); + + asm.Ret(); + } + else + { + throw new PlatformNotSupportedException(); + } + + IntPtr pointer = Map(writer.AsByteSpan()); + + return Marshal.GetDelegateForFunctionPointer(pointer); + } + + private IntPtr Map(ReadOnlySpan code) + { + if (_noWxCache != null) + { + return _noWxCache.MapPageAligned(code); + } + else + { + return JitCache.Map(code); + } + } + + private static Operand Register(int register, OperandType type = OperandType.I64) + { + return new Operand(register, RegisterType.Integer, type); + } + + private static Operand Const(ulong value) + { + return new(OperandKind.Constant, OperandType.I64, value); + } + } +} diff --git a/src/Ryujinx.Cpu/MemoryEhMeilleure.cs b/src/Ryujinx.Cpu/MemoryEhMeilleure.cs index 54e232d9c..f3a5b056b 100644 --- a/src/Ryujinx.Cpu/MemoryEhMeilleure.cs +++ b/src/Ryujinx.Cpu/MemoryEhMeilleure.cs @@ -1,4 +1,4 @@ -using ARMeilleure.Signal; +using Ryujinx.Cpu.Signal; using Ryujinx.Memory; using Ryujinx.Memory.Tracking; using System; diff --git a/src/Ryujinx.Cpu/Signal/NativeSignalHandler.cs b/src/Ryujinx.Cpu/Signal/NativeSignalHandler.cs new file mode 100644 index 000000000..5a9d92cc4 --- /dev/null +++ b/src/Ryujinx.Cpu/Signal/NativeSignalHandler.cs @@ -0,0 +1,179 @@ +using ARMeilleure.Signal; +using Ryujinx.Common; +using Ryujinx.Memory; +using System; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Ryujinx.Cpu.Signal +{ + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct SignalHandlerRange + { + public int IsActive; + public nuint RangeAddress; + public nuint RangeEndAddress; + public IntPtr ActionPointer; + } + + [InlineArray(NativeSignalHandlerGenerator.MaxTrackedRanges)] + struct SignalHandlerRangeArray + { + public SignalHandlerRange Range0; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct SignalHandlerConfig + { + /// + /// The byte offset of the faulting address in the SigInfo or ExceptionRecord struct. + /// + public int StructAddressOffset; + + /// + /// The byte offset of the write flag in the SigInfo or ExceptionRecord struct. + /// + public int StructWriteOffset; + + /// + /// The sigaction handler that was registered before this one. (unix only) + /// + public nuint UnixOldSigaction; + + /// + /// The type of the previous sigaction. True for the 3 argument variant. (unix only) + /// + public int UnixOldSigaction3Arg; + + /// + /// Fixed size array of tracked ranges. + /// + public SignalHandlerRangeArray Ranges; + } + + static class NativeSignalHandler + { + private static readonly IntPtr _handlerConfig; + private static IntPtr _signalHandlerPtr; + + private static MemoryBlock _codeBlock; + + private static readonly object _lock = new(); + private static bool _initialized; + + static NativeSignalHandler() + { + _handlerConfig = Marshal.AllocHGlobal(Unsafe.SizeOf()); + ref SignalHandlerConfig config = ref GetConfigRef(); + + config = new SignalHandlerConfig(); + } + + public static void InitializeSignalHandler(ulong pageSize, Func customSignalHandlerFactory = null) + { + if (_initialized) + { + return; + } + + lock (_lock) + { + if (_initialized) + { + return; + } + + int rangeStructSize = Unsafe.SizeOf(); + + ref SignalHandlerConfig config = ref GetConfigRef(); + + if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS()) + { + _signalHandlerPtr = MapCode(NativeSignalHandlerGenerator.GenerateUnixSignalHandler(_handlerConfig, rangeStructSize, pageSize)); + + if (customSignalHandlerFactory != null) + { + _signalHandlerPtr = customSignalHandlerFactory(UnixSignalHandlerRegistration.GetSegfaultExceptionHandler().sa_handler, _signalHandlerPtr); + } + + var old = UnixSignalHandlerRegistration.RegisterExceptionHandler(_signalHandlerPtr); + + config.UnixOldSigaction = (nuint)(ulong)old.sa_handler; + config.UnixOldSigaction3Arg = old.sa_flags & 4; + } + else + { + config.StructAddressOffset = 40; // ExceptionInformation1 + config.StructWriteOffset = 32; // ExceptionInformation0 + + _signalHandlerPtr = MapCode(NativeSignalHandlerGenerator.GenerateWindowsSignalHandler(_handlerConfig, rangeStructSize, pageSize)); + + if (customSignalHandlerFactory != null) + { + _signalHandlerPtr = customSignalHandlerFactory(IntPtr.Zero, _signalHandlerPtr); + } + + WindowsSignalHandlerRegistration.RegisterExceptionHandler(_signalHandlerPtr); + } + + _initialized = true; + } + } + + private static IntPtr MapCode(ReadOnlySpan code) + { + Debug.Assert(_codeBlock == null); + + ulong codeSizeAligned = BitUtils.AlignUp((ulong)code.Length, MemoryBlock.GetPageSize()); + + _codeBlock = new MemoryBlock(codeSizeAligned); + _codeBlock.Write(0, code); + _codeBlock.Reprotect(0, codeSizeAligned, MemoryPermission.ReadAndExecute); + + return _codeBlock.Pointer; + } + + private static unsafe ref SignalHandlerConfig GetConfigRef() + { + return ref Unsafe.AsRef((void*)_handlerConfig); + } + + public static bool AddTrackedRegion(nuint address, nuint endAddress, IntPtr action) + { + Span ranges = GetConfigRef().Ranges; + + for (int i = 0; i < NativeSignalHandlerGenerator.MaxTrackedRanges; i++) + { + if (ranges[i].IsActive == 0) + { + ranges[i].RangeAddress = address; + ranges[i].RangeEndAddress = endAddress; + ranges[i].ActionPointer = action; + ranges[i].IsActive = 1; + + return true; + } + } + + return false; + } + + public static bool RemoveTrackedRegion(nuint address) + { + Span ranges = GetConfigRef().Ranges; + + for (int i = 0; i < NativeSignalHandlerGenerator.MaxTrackedRanges; i++) + { + if (ranges[i].IsActive == 1 && ranges[i].RangeAddress == address) + { + ranges[i].IsActive = 0; + + return true; + } + } + + return false; + } + } +} diff --git a/src/ARMeilleure/Signal/UnixSignalHandlerRegistration.cs b/src/Ryujinx.Cpu/Signal/UnixSignalHandlerRegistration.cs similarity index 98% rename from src/ARMeilleure/Signal/UnixSignalHandlerRegistration.cs rename to src/Ryujinx.Cpu/Signal/UnixSignalHandlerRegistration.cs index 70e9f2204..e88a6c0f6 100644 --- a/src/ARMeilleure/Signal/UnixSignalHandlerRegistration.cs +++ b/src/Ryujinx.Cpu/Signal/UnixSignalHandlerRegistration.cs @@ -1,7 +1,7 @@ using System; using System.Runtime.InteropServices; -namespace ARMeilleure.Signal +namespace Ryujinx.Cpu.Signal { static partial class UnixSignalHandlerRegistration { diff --git a/src/Ryujinx.Cpu/Signal/WindowsSignalHandlerRegistration.cs b/src/Ryujinx.Cpu/Signal/WindowsSignalHandlerRegistration.cs new file mode 100644 index 000000000..1fbce0f72 --- /dev/null +++ b/src/Ryujinx.Cpu/Signal/WindowsSignalHandlerRegistration.cs @@ -0,0 +1,24 @@ +using System; +using System.Runtime.InteropServices; + +namespace Ryujinx.Cpu.Signal +{ + static partial class WindowsSignalHandlerRegistration + { + [LibraryImport("kernel32.dll")] + private static partial IntPtr AddVectoredExceptionHandler(uint first, IntPtr handler); + + [LibraryImport("kernel32.dll")] + private static partial ulong RemoveVectoredExceptionHandler(IntPtr handle); + + public static IntPtr RegisterExceptionHandler(IntPtr action) + { + return AddVectoredExceptionHandler(1, action); + } + + public static bool RemoveExceptionHandler(IntPtr handle) + { + return RemoveVectoredExceptionHandler(handle) != 0; + } + } +} diff --git a/src/Ryujinx.Graphics.Device/DeviceMemoryManager.cs b/src/Ryujinx.Graphics.Device/DeviceMemoryManager.cs new file mode 100644 index 000000000..d64ed3095 --- /dev/null +++ b/src/Ryujinx.Graphics.Device/DeviceMemoryManager.cs @@ -0,0 +1,395 @@ +using Ryujinx.Memory; +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Ryujinx.Graphics.Device +{ + /// + /// Device memory manager. + /// + public class DeviceMemoryManager : IWritableBlock + { + private const int PtLvl0Bits = 10; + private const int PtLvl1Bits = 10; + public const int PtPageBits = 12; + + private const ulong PtLvl0Size = 1UL << PtLvl0Bits; + private const ulong PtLvl1Size = 1UL << PtLvl1Bits; + public const ulong PageSize = 1UL << PtPageBits; + + private const ulong PtLvl0Mask = PtLvl0Size - 1; + private const ulong PtLvl1Mask = PtLvl1Size - 1; + public const ulong PageMask = PageSize - 1; + + private const int PtLvl0Bit = PtPageBits + PtLvl1Bits; + private const int PtLvl1Bit = PtPageBits; + private const int AddressSpaceBits = PtPageBits + PtLvl1Bits + PtLvl0Bits; + + public const ulong PteUnmapped = ulong.MaxValue; + + private readonly ulong[][] _pageTable; + + private readonly IVirtualMemoryManager _physical; + + /// + /// Creates a new instance of the GPU memory manager. + /// + /// Physical memory that this memory manager will map into + public DeviceMemoryManager(IVirtualMemoryManager physicalMemory) + { + _physical = physicalMemory; + _pageTable = new ulong[PtLvl0Size][]; + } + + /// + /// Reads data from GPU mapped memory. + /// + /// Type of the data + /// GPU virtual address where the data is located + /// The data at the specified memory location + public T Read(ulong va) where T : unmanaged + { + int size = Unsafe.SizeOf(); + + if (IsContiguous(va, size)) + { + return _physical.Read(Translate(va)); + } + else + { + Span data = new byte[size]; + + ReadImpl(va, data); + + return MemoryMarshal.Cast(data)[0]; + } + } + + /// + /// Gets a read-only span of data from GPU mapped memory. + /// + /// GPU virtual address where the data is located + /// Size of the data + /// The span of the data at the specified memory location + public ReadOnlySpan GetSpan(ulong va, int size) + { + if (IsContiguous(va, size)) + { + return _physical.GetSpan(Translate(va), size); + } + else + { + Span data = new byte[size]; + + ReadImpl(va, data); + + return data; + } + } + + /// + /// Reads data from a possibly non-contiguous region of GPU mapped memory. + /// + /// GPU virtual address of the data + /// Span to write the read data into + private void ReadImpl(ulong va, Span data) + { + if (data.Length == 0) + { + return; + } + + int offset = 0, size; + + if ((va & PageMask) != 0) + { + ulong pa = Translate(va); + + size = Math.Min(data.Length, (int)PageSize - (int)(va & PageMask)); + + if (pa != PteUnmapped && _physical.IsMapped(pa)) + { + _physical.GetSpan(pa, size).CopyTo(data[..size]); + } + + offset += size; + } + + for (; offset < data.Length; offset += size) + { + ulong pa = Translate(va + (ulong)offset); + + size = Math.Min(data.Length - offset, (int)PageSize); + + if (pa != PteUnmapped && _physical.IsMapped(pa)) + { + _physical.GetSpan(pa, size).CopyTo(data.Slice(offset, size)); + } + } + } + + /// + /// Gets a writable region from GPU mapped memory. + /// + /// Start address of the range + /// Size in bytes to be range + /// A writable region with the data at the specified memory location + public WritableRegion GetWritableRegion(ulong va, int size) + { + if (IsContiguous(va, size)) + { + return _physical.GetWritableRegion(Translate(va), size, tracked: true); + } + else + { + Memory memory = new byte[size]; + + GetSpan(va, size).CopyTo(memory.Span); + + return new WritableRegion(this, va, memory, tracked: true); + } + } + + /// + /// Writes data to GPU mapped memory. + /// + /// Type of the data + /// GPU virtual address to write the value into + /// The value to be written + public void Write(ulong va, T value) where T : unmanaged + { + Write(va, MemoryMarshal.Cast(MemoryMarshal.CreateSpan(ref value, 1))); + } + + /// + /// Writes data to GPU mapped memory. + /// + /// GPU virtual address to write the data into + /// The data to be written + public void Write(ulong va, ReadOnlySpan data) + { + if (IsContiguous(va, data.Length)) + { + _physical.Write(Translate(va), data); + } + else + { + int offset = 0, size; + + if ((va & PageMask) != 0) + { + ulong pa = Translate(va); + + size = Math.Min(data.Length, (int)PageSize - (int)(va & PageMask)); + + if (pa != PteUnmapped && _physical.IsMapped(pa)) + { + _physical.Write(pa, data[..size]); + } + + offset += size; + } + + for (; offset < data.Length; offset += size) + { + ulong pa = Translate(va + (ulong)offset); + + size = Math.Min(data.Length - offset, (int)PageSize); + + if (pa != PteUnmapped && _physical.IsMapped(pa)) + { + _physical.Write(pa, data.Slice(offset, size)); + } + } + } + } + + /// + /// Writes data to GPU mapped memory without write tracking. + /// + /// GPU virtual address to write the data into + /// The data to be written + public void WriteUntracked(ulong va, ReadOnlySpan data) + { + throw new NotSupportedException(); + } + + /// + /// Maps a given range of pages to the specified CPU virtual address. + /// + /// + /// All addresses and sizes must be page aligned. + /// + /// CPU virtual address to map into + /// GPU virtual address to be mapped + /// Kind of the resource located at the mapping + public void Map(ulong pa, ulong va, ulong size) + { + lock (_pageTable) + { + for (ulong offset = 0; offset < size; offset += PageSize) + { + SetPte(va + offset, PackPte(pa + offset)); + } + } + } + + /// + /// Unmaps a given range of pages at the specified GPU virtual memory region. + /// + /// GPU virtual address to unmap + /// Size in bytes of the region being unmapped + public void Unmap(ulong va, ulong size) + { + lock (_pageTable) + { + for (ulong offset = 0; offset < size; offset += PageSize) + { + SetPte(va + offset, PteUnmapped); + } + } + } + + /// + /// Checks if a region of GPU mapped memory is contiguous. + /// + /// GPU virtual address of the region + /// Size of the region + /// True if the region is contiguous, false otherwise + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool IsContiguous(ulong va, int size) + { + if (!ValidateAddress(va) || GetPte(va) == PteUnmapped) + { + return false; + } + + ulong endVa = (va + (ulong)size + PageMask) & ~PageMask; + + va &= ~PageMask; + + int pages = (int)((endVa - va) / PageSize); + + for (int page = 0; page < pages - 1; page++) + { + if (!ValidateAddress(va + PageSize) || GetPte(va + PageSize) == PteUnmapped) + { + return false; + } + + if (Translate(va) + PageSize != Translate(va + PageSize)) + { + return false; + } + + va += PageSize; + } + + return true; + } + + /// + /// Validates a GPU virtual address. + /// + /// Address to validate + /// True if the address is valid, false otherwise + private static bool ValidateAddress(ulong va) + { + return va < (1UL << AddressSpaceBits); + } + + /// + /// Checks if a given page is mapped. + /// + /// GPU virtual address of the page to check + /// True if the page is mapped, false otherwise + public bool IsMapped(ulong va) + { + return Translate(va) != PteUnmapped; + } + + /// + /// Translates a GPU virtual address to a CPU virtual address. + /// + /// GPU virtual address to be translated + /// CPU virtual address, or if unmapped + public ulong Translate(ulong va) + { + if (!ValidateAddress(va)) + { + return PteUnmapped; + } + + ulong pte = GetPte(va); + + if (pte == PteUnmapped) + { + return PteUnmapped; + } + + return UnpackPaFromPte(pte) + (va & PageMask); + } + + /// + /// Gets the Page Table entry for a given GPU virtual address. + /// + /// GPU virtual address + /// Page table entry (CPU virtual address) + private ulong GetPte(ulong va) + { + ulong l0 = (va >> PtLvl0Bit) & PtLvl0Mask; + ulong l1 = (va >> PtLvl1Bit) & PtLvl1Mask; + + if (_pageTable[l0] == null) + { + return PteUnmapped; + } + + return _pageTable[l0][l1]; + } + + /// + /// Sets a Page Table entry at a given GPU virtual address. + /// + /// GPU virtual address + /// Page table entry (CPU virtual address) + private void SetPte(ulong va, ulong pte) + { + ulong l0 = (va >> PtLvl0Bit) & PtLvl0Mask; + ulong l1 = (va >> PtLvl1Bit) & PtLvl1Mask; + + if (_pageTable[l0] == null) + { + _pageTable[l0] = new ulong[PtLvl1Size]; + + for (ulong index = 0; index < PtLvl1Size; index++) + { + _pageTable[l0][index] = PteUnmapped; + } + } + + _pageTable[l0][l1] = pte; + } + + /// + /// Creates a page table entry from a physical address and kind. + /// + /// Physical address + /// Page table entry + private static ulong PackPte(ulong pa) + { + return pa; + } + + /// + /// Unpacks physical address from a page table entry. + /// + /// Page table entry + /// Physical address + private static ulong UnpackPaFromPte(ulong pte) + { + return pte; + } + } +} diff --git a/src/Ryujinx.Graphics.Device/ISynchronizationManager.cs b/src/Ryujinx.Graphics.Device/ISynchronizationManager.cs new file mode 100644 index 000000000..2a8d1d9b7 --- /dev/null +++ b/src/Ryujinx.Graphics.Device/ISynchronizationManager.cs @@ -0,0 +1,39 @@ +using Ryujinx.Common.Logging; +using System; +using System.Threading; + +namespace Ryujinx.Graphics.Device +{ + /// + /// Synchronization manager interface. + /// + public interface ISynchronizationManager + { + /// + /// Increment the value of a syncpoint with a given id. + /// + /// The id of the syncpoint + /// Thrown when id >= MaxHardwareSyncpoints + /// The incremented value of the syncpoint + uint IncrementSyncpoint(uint id); + + /// + /// Get the value of a syncpoint with a given id. + /// + /// The id of the syncpoint + /// Thrown when id >= MaxHardwareSyncpoints + /// The value of the syncpoint + uint GetSyncpointValue(uint id); + + /// + /// Wait on a syncpoint with a given id at a target threshold. + /// The callback will be called once the threshold is reached and will automatically be unregistered. + /// + /// The id of the syncpoint + /// The target threshold + /// The timeout + /// Thrown when id >= MaxHardwareSyncpoints + /// True if timed out + bool WaitOnSyncpoint(uint id, uint threshold, TimeSpan timeout); + } +} diff --git a/src/Ryujinx.Graphics.Device/Ryujinx.Graphics.Device.csproj b/src/Ryujinx.Graphics.Device/Ryujinx.Graphics.Device.csproj index ae2821edb..973a9e260 100644 --- a/src/Ryujinx.Graphics.Device/Ryujinx.Graphics.Device.csproj +++ b/src/Ryujinx.Graphics.Device/Ryujinx.Graphics.Device.csproj @@ -4,4 +4,8 @@ net8.0 + + + + diff --git a/src/Ryujinx.Graphics.GAL/Format.cs b/src/Ryujinx.Graphics.GAL/Format.cs index 99c89dcec..035543560 100644 --- a/src/Ryujinx.Graphics.GAL/Format.cs +++ b/src/Ryujinx.Graphics.GAL/Format.cs @@ -147,6 +147,7 @@ namespace Ryujinx.Graphics.GAL A1B5G5R5Unorm, B8G8R8A8Unorm, B8G8R8A8Srgb, + B10G10R10A2Unorm, } public static class FormatExtensions @@ -260,6 +261,7 @@ namespace Ryujinx.Graphics.GAL case Format.R10G10B10A2Sint: case Format.R10G10B10A2Uscaled: case Format.R10G10B10A2Sscaled: + case Format.B10G10R10A2Unorm: return 4; case Format.S8Uint: @@ -451,6 +453,7 @@ namespace Ryujinx.Graphics.GAL case Format.R32G32Uint: case Format.B8G8R8A8Unorm: case Format.B8G8R8A8Srgb: + case Format.B10G10R10A2Unorm: case Format.R10G10B10A2Unorm: case Format.R10G10B10A2Uint: case Format.R8G8B8A8Unorm: @@ -611,6 +614,7 @@ namespace Ryujinx.Graphics.GAL case Format.B5G5R5A1Unorm: case Format.B8G8R8A8Unorm: case Format.B8G8R8A8Srgb: + case Format.B10G10R10A2Unorm: return true; } diff --git a/src/Ryujinx.Graphics.GAL/HardwareInfo.cs b/src/Ryujinx.Graphics.GAL/HardwareInfo.cs index d8f7d1f71..c2546fa46 100644 --- a/src/Ryujinx.Graphics.GAL/HardwareInfo.cs +++ b/src/Ryujinx.Graphics.GAL/HardwareInfo.cs @@ -4,11 +4,13 @@ namespace Ryujinx.Graphics.GAL { public string GpuVendor { get; } public string GpuModel { get; } + public string GpuDriver { get; } - public HardwareInfo(string gpuVendor, string gpuModel) + public HardwareInfo(string gpuVendor, string gpuModel, string gpuDriver) { GpuVendor = gpuVendor; GpuModel = gpuModel; + GpuDriver = gpuDriver; } } } diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Dma/DmaClass.cs b/src/Ryujinx.Graphics.Gpu/Engine/Dma/DmaClass.cs index 6dae829ff..de395d574 100644 --- a/src/Ryujinx.Graphics.Gpu/Engine/Dma/DmaClass.cs +++ b/src/Ryujinx.Graphics.Gpu/Engine/Dma/DmaClass.cs @@ -277,6 +277,14 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma ReadOnlySpan srcSpan = memoryManager.GetSpan(srcGpuVa + (ulong)srcBaseOffset, srcSize, true); + // If remapping is disabled, we always copy the components directly, in order. + // If it's enabled, but the mapping is just XYZW, we also copy them in order. + bool isIdentityRemap = !remap || + (_state.State.SetRemapComponentsDstX == SetRemapComponentsDst.SrcX && + (dstComponents < 2 || _state.State.SetRemapComponentsDstY == SetRemapComponentsDst.SrcY) && + (dstComponents < 3 || _state.State.SetRemapComponentsDstZ == SetRemapComponentsDst.SrcZ) && + (dstComponents < 4 || _state.State.SetRemapComponentsDstW == SetRemapComponentsDst.SrcW)); + bool completeSource = IsTextureCopyComplete(src, srcLinear, srcBpp, srcStride, xCount, yCount); bool completeDest = IsTextureCopyComplete(dst, dstLinear, dstBpp, dstStride, xCount, yCount); @@ -284,7 +292,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma // but only if we are doing a complete copy, // and not for block linear to linear copies, since those are typically accessed from the CPU. - if (completeSource && completeDest && !(dstLinear && !srcLinear)) + if (completeSource && completeDest && !(dstLinear && !srcLinear) && isIdentityRemap) { var target = memoryManager.Physical.TextureCache.FindTexture( memoryManager, @@ -353,14 +361,6 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma TextureParams srcParams = new(srcRegionX, srcRegionY, srcBaseOffset, srcBpp, srcLinear, srcCalculator); TextureParams dstParams = new(dstRegionX, dstRegionY, dstBaseOffset, dstBpp, dstLinear, dstCalculator); - // If remapping is enabled, we always copy the components directly, in order. - // If it's enabled, but the mapping is just XYZW, we also copy them in order. - bool isIdentityRemap = !remap || - (_state.State.SetRemapComponentsDstX == SetRemapComponentsDst.SrcX && - (dstComponents < 2 || _state.State.SetRemapComponentsDstY == SetRemapComponentsDst.SrcY) && - (dstComponents < 3 || _state.State.SetRemapComponentsDstZ == SetRemapComponentsDst.SrcZ) && - (dstComponents < 4 || _state.State.SetRemapComponentsDstW == SetRemapComponentsDst.SrcW)); - if (isIdentityRemap) { // The order of the components doesn't change, so we can just copy directly diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs b/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs index 2b65b4560..6b4ea89f3 100644 --- a/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs +++ b/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs @@ -26,6 +26,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed public const int PrimitiveRestartStateIndex = 12; public const int RenderTargetStateIndex = 27; + // Vertex buffers larger than this size will be clamped to the mapped size. + private const ulong VertexBufferSizeToMappedSizeThreshold = 256 * 1024 * 1024; // 256 MB + private readonly GpuContext _context; private readonly GpuChannel _channel; private readonly DeviceStateWithShadow _state; @@ -1144,6 +1147,14 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed size = Math.Min(size, maxVertexBufferSize); } + else if (size > VertexBufferSizeToMappedSizeThreshold) + { + // Make sure we have a sane vertex buffer size, since in some cases applications + // might set the "end address" of the vertex buffer to the end of the GPU address space, + // which would result in a several GBs large buffer. + + size = _channel.MemoryManager.GetMappedSize(address, size); + } } else { diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Types/ColorFormat.cs b/src/Ryujinx.Graphics.Gpu/Engine/Types/ColorFormat.cs index c798384f0..273438a67 100644 --- a/src/Ryujinx.Graphics.Gpu/Engine/Types/ColorFormat.cs +++ b/src/Ryujinx.Graphics.Gpu/Engine/Types/ColorFormat.cs @@ -37,6 +37,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Types R16G16Sint = 0xdc, R16G16Uint = 0xdd, R16G16Float = 0xde, + B10G10R10A2Unorm = 0xdf, R11G11B10Float = 0xe0, R32Sint = 0xe3, R32Uint = 0xe4, @@ -104,6 +105,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Types ColorFormat.R16G16Sint => new FormatInfo(Format.R16G16Sint, 1, 1, 4, 2), ColorFormat.R16G16Uint => new FormatInfo(Format.R16G16Uint, 1, 1, 4, 2), ColorFormat.R16G16Float => new FormatInfo(Format.R16G16Float, 1, 1, 4, 2), + ColorFormat.B10G10R10A2Unorm => new FormatInfo(Format.B10G10R10A2Unorm, 1, 1, 4, 4), ColorFormat.R11G11B10Float => new FormatInfo(Format.R11G11B10Float, 1, 1, 4, 3), ColorFormat.R32Sint => new FormatInfo(Format.R32Sint, 1, 1, 4, 1), ColorFormat.R32Uint => new FormatInfo(Format.R32Uint, 1, 1, 4, 1), diff --git a/src/Ryujinx.Graphics.Gpu/GpuContext.cs b/src/Ryujinx.Graphics.Gpu/GpuContext.cs index a50852b05..aa0084fdc 100644 --- a/src/Ryujinx.Graphics.Gpu/GpuContext.cs +++ b/src/Ryujinx.Graphics.Gpu/GpuContext.cs @@ -1,4 +1,5 @@ using Ryujinx.Common; +using Ryujinx.Graphics.Device; using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.Gpu.Engine.GPFifo; using Ryujinx.Graphics.Gpu.Memory; @@ -106,6 +107,8 @@ namespace Ryujinx.Graphics.Gpu private long _modifiedSequence; private readonly ulong _firstTimestamp; + private readonly ManualResetEvent _gpuReadyEvent; + /// /// Creates a new instance of the GPU emulation context. /// @@ -121,6 +124,7 @@ namespace Ryujinx.Graphics.Gpu Window = new Window(this); HostInitalized = new ManualResetEvent(false); + _gpuReadyEvent = new ManualResetEvent(false); SyncActions = new List(); SyncpointActions = new List(); @@ -160,6 +164,22 @@ namespace Ryujinx.Graphics.Gpu return new MemoryManager(physicalMemory); } + /// + /// Creates a new device memory manager. + /// + /// ID of the process that owns the memory manager + /// The memory manager + /// Thrown when is invalid + public DeviceMemoryManager CreateDeviceMemoryManager(ulong pid) + { + if (!PhysicalMemoryRegistry.TryGetValue(pid, out var physicalMemory)) + { + throw new ArgumentException("The PID is invalid or the process was not registered", nameof(pid)); + } + + return physicalMemory.CreateDeviceMemoryManager(); + } + /// /// Registers virtual memory used by a process for GPU memory access, caching and read/write tracking. /// @@ -216,7 +236,7 @@ namespace Ryujinx.Graphics.Gpu /// Gets a sequence number for resource modification ordering. This increments on each call. /// /// A sequence number for resource modification ordering - public long GetModifiedSequence() + internal long GetModifiedSequence() { return _modifiedSequence++; } @@ -225,7 +245,7 @@ namespace Ryujinx.Graphics.Gpu /// Gets the value of the GPU timer. /// /// The current GPU timestamp - public ulong GetTimestamp() + internal ulong GetTimestamp() { // Guest timestamp will start at 0, instead of host value. ulong ticks = ConvertNanosecondsToTicks((ulong)PerformanceCounter.ElapsedNanoseconds) - _firstTimestamp; @@ -262,6 +282,16 @@ namespace Ryujinx.Graphics.Gpu { physicalMemory.ShaderCache.Initialize(cancellationToken); } + + _gpuReadyEvent.Set(); + } + + /// + /// Waits until the GPU is ready to receive commands. + /// + public void WaitUntilGpuReady() + { + _gpuReadyEvent.WaitOne(); } /// @@ -399,6 +429,7 @@ namespace Ryujinx.Graphics.Gpu { GPFifo.Dispose(); HostInitalized.Dispose(); + _gpuReadyEvent.Dispose(); // Has to be disposed before processing deferred actions, as it will produce some. foreach (var physicalMemory in PhysicalMemoryRegistry.Values) diff --git a/src/Ryujinx.Graphics.Gpu/Image/TextureCache.cs b/src/Ryujinx.Graphics.Gpu/Image/TextureCache.cs index 6b92c0aaf..5743c89c0 100644 --- a/src/Ryujinx.Graphics.Gpu/Image/TextureCache.cs +++ b/src/Ryujinx.Graphics.Gpu/Image/TextureCache.cs @@ -790,8 +790,12 @@ namespace Ryujinx.Graphics.Gpu.Image texture = new Texture(_context, _physicalMemory, info, sizeInfo, range.Value, scaleMode); + // If the new texture is larger than the existing one, we need to fill the remaining space with CPU data, + // otherwise we only need the data that is copied from the existing texture, without loading the CPU data. + bool updateNewTexture = texture.Width > overlap.Width || texture.Height > overlap.Height; + texture.InitializeGroup(true, true, new List()); - texture.InitializeData(false, false); + texture.InitializeData(false, updateNewTexture); overlap.SynchronizeMemory(); overlap.CreateCopyDependency(texture, oInfo.FirstLayer, oInfo.FirstLevel, true); diff --git a/src/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs b/src/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs index 0fb4f1be7..fb2097444 100644 --- a/src/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs +++ b/src/Ryujinx.Graphics.Gpu/Image/TextureGroup.cs @@ -1630,12 +1630,6 @@ namespace Ryujinx.Graphics.Gpu.Image return; } - // If size is zero, we have nothing to flush. - if (size == 0) - { - return; - } - // There is a small gap here where the action is removed but _actionRegistered is still 1. // In this case it will skip registering the action, but here we are already handling it, // so there shouldn't be any issue as it's the same handler for all actions. diff --git a/src/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs b/src/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs index 5e19bddc3..74d527051 100644 --- a/src/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs +++ b/src/Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs @@ -329,49 +329,6 @@ namespace Ryujinx.Graphics.Gpu.Memory } } - /// - /// Writes data to GPU mapped memory, stopping at the first unmapped page at the memory region, if any. - /// - /// GPU virtual address to write the data into - /// The data to be written - public void WriteMapped(ulong va, ReadOnlySpan data) - { - if (IsContiguous(va, data.Length)) - { - Physical.Write(Translate(va), data); - } - else - { - int offset = 0, size; - - if ((va & PageMask) != 0) - { - ulong pa = Translate(va); - - size = Math.Min(data.Length, (int)PageSize - (int)(va & PageMask)); - - if (pa != PteUnmapped && Physical.IsMapped(pa)) - { - Physical.Write(pa, data[..size]); - } - - offset += size; - } - - for (; offset < data.Length; offset += size) - { - ulong pa = Translate(va + (ulong)offset); - - size = Math.Min(data.Length - offset, (int)PageSize); - - if (pa != PteUnmapped && Physical.IsMapped(pa)) - { - Physical.Write(pa, data.Slice(offset, size)); - } - } - } - } - /// /// Runs remap actions that are added to an unmap event. /// These must run after the mapping completes. diff --git a/src/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs b/src/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs index 1ca6071bd..69a3054a4 100644 --- a/src/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs +++ b/src/Ryujinx.Graphics.Gpu/Memory/PhysicalMemory.cs @@ -1,4 +1,5 @@ using Ryujinx.Cpu; +using Ryujinx.Graphics.Device; using Ryujinx.Graphics.Gpu.Image; using Ryujinx.Graphics.Gpu.Shader; using Ryujinx.Memory; @@ -82,6 +83,15 @@ namespace Ryujinx.Graphics.Gpu.Memory } } + /// + /// Creates a new device memory manager. + /// + /// The memory manager + public DeviceMemoryManager CreateDeviceMemoryManager() + { + return new DeviceMemoryManager(_cpuMemory); + } + /// /// Gets a host pointer for a given range of application memory. /// If the memory region is not a single contiguous block, this method returns 0. diff --git a/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs b/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs index 125ab8993..c5763b025 100644 --- a/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs +++ b/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs @@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache private const ushort FileFormatVersionMajor = 1; private const ushort FileFormatVersionMinor = 2; private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor; - private const uint CodeGenVersion = 5958; + private const uint CodeGenVersion = 6253; private const string SharedTocFileName = "shared.toc"; private const string SharedDataFileName = "shared.data"; diff --git a/src/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs b/src/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs index af682e422..0b17af8b2 100644 --- a/src/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs +++ b/src/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs @@ -161,7 +161,8 @@ namespace Ryujinx.Graphics.Gpu.Shader _graphicsShaderCache, _computeShaderCache, _diskCacheHostStorage, - ShaderCacheStateUpdate, cancellationToken); + ShaderCacheStateUpdate, + cancellationToken); loader.LoadShaders(); diff --git a/src/Ryujinx.Graphics.Gpu/Synchronization/SynchronizationManager.cs b/src/Ryujinx.Graphics.Gpu/Synchronization/SynchronizationManager.cs index c2fa4c248..1042a4db8 100644 --- a/src/Ryujinx.Graphics.Gpu/Synchronization/SynchronizationManager.cs +++ b/src/Ryujinx.Graphics.Gpu/Synchronization/SynchronizationManager.cs @@ -1,4 +1,5 @@ using Ryujinx.Common.Logging; +using Ryujinx.Graphics.Device; using System; using System.Threading; @@ -7,7 +8,7 @@ namespace Ryujinx.Graphics.Gpu.Synchronization /// /// GPU synchronization manager. /// - public class SynchronizationManager + public class SynchronizationManager : ISynchronizationManager { /// /// The maximum number of syncpoints supported by the GM20B. @@ -29,12 +30,7 @@ namespace Ryujinx.Graphics.Gpu.Synchronization } } - /// - /// Increment the value of a syncpoint with a given id. - /// - /// The id of the syncpoint - /// Thrown when id >= MaxHardwareSyncpoints - /// The incremented value of the syncpoint + /// public uint IncrementSyncpoint(uint id) { ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(id, (uint)MaxHardwareSyncpoints); @@ -42,12 +38,7 @@ namespace Ryujinx.Graphics.Gpu.Synchronization return _syncpoints[id].Increment(); } - /// - /// Get the value of a syncpoint with a given id. - /// - /// The id of the syncpoint - /// Thrown when id >= MaxHardwareSyncpoints - /// The value of the syncpoint + /// public uint GetSyncpointValue(uint id) { ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(id, (uint)MaxHardwareSyncpoints); @@ -84,15 +75,7 @@ namespace Ryujinx.Graphics.Gpu.Synchronization _syncpoints[id].UnregisterCallback(waiterInformation); } - /// - /// Wait on a syncpoint with a given id at a target threshold. - /// The callback will be called once the threshold is reached and will automatically be unregistered. - /// - /// The id of the syncpoint - /// The target threshold - /// The timeout - /// Thrown when id >= MaxHardwareSyncpoints - /// True if timed out + /// public bool WaitOnSyncpoint(uint id, uint threshold, TimeSpan timeout) { ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(id, (uint)MaxHardwareSyncpoints); diff --git a/src/Ryujinx.Graphics.Host1x/Host1xClass.cs b/src/Ryujinx.Graphics.Host1x/Host1xClass.cs index 4327b93c2..3ffc87ba5 100644 --- a/src/Ryujinx.Graphics.Host1x/Host1xClass.cs +++ b/src/Ryujinx.Graphics.Host1x/Host1xClass.cs @@ -1,5 +1,4 @@ using Ryujinx.Graphics.Device; -using Ryujinx.Graphics.Gpu.Synchronization; using System.Collections.Generic; using System.Threading; @@ -7,10 +6,10 @@ namespace Ryujinx.Graphics.Host1x { public class Host1xClass : IDeviceState { - private readonly SynchronizationManager _syncMgr; + private readonly ISynchronizationManager _syncMgr; private readonly DeviceState _state; - public Host1xClass(SynchronizationManager syncMgr) + public Host1xClass(ISynchronizationManager syncMgr) { _syncMgr = syncMgr; _state = new DeviceState(new Dictionary diff --git a/src/Ryujinx.Graphics.Host1x/Host1xDevice.cs b/src/Ryujinx.Graphics.Host1x/Host1xDevice.cs index 6733b32aa..2db74ce5e 100644 --- a/src/Ryujinx.Graphics.Host1x/Host1xDevice.cs +++ b/src/Ryujinx.Graphics.Host1x/Host1xDevice.cs @@ -1,7 +1,6 @@ using Ryujinx.Common; using Ryujinx.Common.Logging; using Ryujinx.Graphics.Device; -using Ryujinx.Graphics.Gpu.Synchronization; using System; using System.Numerics; @@ -35,7 +34,7 @@ namespace Ryujinx.Graphics.Host1x private int _mask; private bool _incrementing; - public Host1xDevice(SynchronizationManager syncMgr) + public Host1xDevice(ISynchronizationManager syncMgr) { _syncptIncrMgr = new SyncptIncrManager(syncMgr); _commandQueue = new AsyncWorkQueue(Process, "Ryujinx.Host1xProcessor"); diff --git a/src/Ryujinx.Graphics.Host1x/Ryujinx.Graphics.Host1x.csproj b/src/Ryujinx.Graphics.Host1x/Ryujinx.Graphics.Host1x.csproj index 22959fad8..d631d039f 100644 --- a/src/Ryujinx.Graphics.Host1x/Ryujinx.Graphics.Host1x.csproj +++ b/src/Ryujinx.Graphics.Host1x/Ryujinx.Graphics.Host1x.csproj @@ -6,7 +6,6 @@ - diff --git a/src/Ryujinx.Graphics.Host1x/SyncptIncrManager.cs b/src/Ryujinx.Graphics.Host1x/SyncptIncrManager.cs index 164d15ec2..a5ee1198c 100644 --- a/src/Ryujinx.Graphics.Host1x/SyncptIncrManager.cs +++ b/src/Ryujinx.Graphics.Host1x/SyncptIncrManager.cs @@ -1,11 +1,11 @@ -using Ryujinx.Graphics.Gpu.Synchronization; +using Ryujinx.Graphics.Device; using System.Collections.Generic; namespace Ryujinx.Graphics.Host1x { class SyncptIncrManager { - private readonly SynchronizationManager _syncMgr; + private readonly ISynchronizationManager _syncMgr; private readonly struct SyncptIncr { @@ -27,7 +27,7 @@ namespace Ryujinx.Graphics.Host1x private uint _currentId; - public SyncptIncrManager(SynchronizationManager syncMgr) + public SyncptIncrManager(ISynchronizationManager syncMgr) { _syncMgr = syncMgr; } diff --git a/src/Ryujinx.Graphics.Nvdec/H264Decoder.cs b/src/Ryujinx.Graphics.Nvdec/H264Decoder.cs index ef8ab9086..6058f72d6 100644 --- a/src/Ryujinx.Graphics.Nvdec/H264Decoder.cs +++ b/src/Ryujinx.Graphics.Nvdec/H264Decoder.cs @@ -12,10 +12,10 @@ namespace Ryujinx.Graphics.Nvdec public static void Decode(NvdecDecoderContext context, ResourceManager rm, ref NvdecRegisters state) { - PictureInfo pictureInfo = rm.Gmm.DeviceRead(state.SetDrvPicSetupOffset); + PictureInfo pictureInfo = rm.MemoryManager.DeviceRead(state.SetDrvPicSetupOffset); H264PictureInfo info = pictureInfo.Convert(); - ReadOnlySpan bitstream = rm.Gmm.DeviceGetSpan(state.SetInBufBaseOffset, (int)pictureInfo.BitstreamSize); + ReadOnlySpan bitstream = rm.MemoryManager.DeviceGetSpan(state.SetInBufBaseOffset, (int)pictureInfo.BitstreamSize); int width = (int)pictureInfo.PicWidthInMbs * MbSizeInPixels; int height = (int)pictureInfo.PicHeightInMbs * MbSizeInPixels; @@ -34,7 +34,7 @@ namespace Ryujinx.Graphics.Nvdec if (outputSurface.Field == FrameField.Progressive) { SurfaceWriter.Write( - rm.Gmm, + rm.MemoryManager, outputSurface, lumaOffset + pictureInfo.LumaFrameOffset, chromaOffset + pictureInfo.ChromaFrameOffset); @@ -42,7 +42,7 @@ namespace Ryujinx.Graphics.Nvdec else { SurfaceWriter.WriteInterlaced( - rm.Gmm, + rm.MemoryManager, outputSurface, lumaOffset + pictureInfo.LumaTopFieldOffset, chromaOffset + pictureInfo.ChromaTopFieldOffset, diff --git a/src/Ryujinx.Graphics.Nvdec/Image/SurfaceCache.cs b/src/Ryujinx.Graphics.Nvdec/Image/SurfaceCache.cs index 4a4e1a3f6..7359b3309 100644 --- a/src/Ryujinx.Graphics.Nvdec/Image/SurfaceCache.cs +++ b/src/Ryujinx.Graphics.Nvdec/Image/SurfaceCache.cs @@ -1,4 +1,4 @@ -using Ryujinx.Graphics.Gpu.Memory; +using Ryujinx.Graphics.Device; using Ryujinx.Graphics.Video; using System; using System.Diagnostics; @@ -27,11 +27,11 @@ namespace Ryujinx.Graphics.Nvdec.Image private readonly CacheItem[] _pool = new CacheItem[MaxItems]; - private readonly MemoryManager _gmm; + private readonly DeviceMemoryManager _mm; - public SurfaceCache(MemoryManager gmm) + public SurfaceCache(DeviceMemoryManager mm) { - _gmm = gmm; + _mm = mm; } public ISurface Get(IDecoder decoder, uint lumaOffset, uint chromaOffset, int width, int height) @@ -77,7 +77,7 @@ namespace Ryujinx.Graphics.Nvdec.Image if ((lumaOffset | chromaOffset) != 0) { - SurfaceReader.Read(_gmm, surface, lumaOffset, chromaOffset); + SurfaceReader.Read(_mm, surface, lumaOffset, chromaOffset); } MoveToFront(i); @@ -100,7 +100,7 @@ namespace Ryujinx.Graphics.Nvdec.Image if ((lumaOffset | chromaOffset) != 0) { - SurfaceReader.Read(_gmm, surface, lumaOffset, chromaOffset); + SurfaceReader.Read(_mm, surface, lumaOffset, chromaOffset); } MoveToFront(MaxItems - 1); diff --git a/src/Ryujinx.Graphics.Nvdec/Image/SurfaceReader.cs b/src/Ryujinx.Graphics.Nvdec/Image/SurfaceReader.cs index e87956852..f510c128d 100644 --- a/src/Ryujinx.Graphics.Nvdec/Image/SurfaceReader.cs +++ b/src/Ryujinx.Graphics.Nvdec/Image/SurfaceReader.cs @@ -1,5 +1,5 @@ using Ryujinx.Common; -using Ryujinx.Graphics.Gpu.Memory; +using Ryujinx.Graphics.Device; using Ryujinx.Graphics.Texture; using Ryujinx.Graphics.Video; using System; @@ -11,13 +11,13 @@ namespace Ryujinx.Graphics.Nvdec.Image { static class SurfaceReader { - public static void Read(MemoryManager gmm, ISurface surface, uint lumaOffset, uint chromaOffset) + public static void Read(DeviceMemoryManager mm, ISurface surface, uint lumaOffset, uint chromaOffset) { int width = surface.Width; int height = surface.Height; int stride = surface.Stride; - ReadOnlySpan luma = gmm.DeviceGetSpan(lumaOffset, GetBlockLinearSize(width, height, 1)); + ReadOnlySpan luma = mm.DeviceGetSpan(lumaOffset, GetBlockLinearSize(width, height, 1)); ReadLuma(surface.YPlane.AsSpan(), luma, stride, width, height); @@ -25,7 +25,7 @@ namespace Ryujinx.Graphics.Nvdec.Image int uvHeight = surface.UvHeight; int uvStride = surface.UvStride; - ReadOnlySpan chroma = gmm.DeviceGetSpan(chromaOffset, GetBlockLinearSize(uvWidth, uvHeight, 2)); + ReadOnlySpan chroma = mm.DeviceGetSpan(chromaOffset, GetBlockLinearSize(uvWidth, uvHeight, 2)); ReadChroma(surface.UPlane.AsSpan(), surface.VPlane.AsSpan(), chroma, uvStride, uvWidth, uvHeight); } diff --git a/src/Ryujinx.Graphics.Nvdec/Image/SurfaceWriter.cs b/src/Ryujinx.Graphics.Nvdec/Image/SurfaceWriter.cs index b4f028998..043be1f2b 100644 --- a/src/Ryujinx.Graphics.Nvdec/Image/SurfaceWriter.cs +++ b/src/Ryujinx.Graphics.Nvdec/Image/SurfaceWriter.cs @@ -1,5 +1,5 @@ using Ryujinx.Common; -using Ryujinx.Graphics.Gpu.Memory; +using Ryujinx.Graphics.Device; using Ryujinx.Graphics.Texture; using Ryujinx.Graphics.Video; using System; @@ -12,11 +12,11 @@ namespace Ryujinx.Graphics.Nvdec.Image { static class SurfaceWriter { - public static void Write(MemoryManager gmm, ISurface surface, uint lumaOffset, uint chromaOffset) + public static void Write(DeviceMemoryManager mm, ISurface surface, uint lumaOffset, uint chromaOffset) { int lumaSize = GetBlockLinearSize(surface.Width, surface.Height, 1); - using var luma = gmm.GetWritableRegion(ExtendOffset(lumaOffset), lumaSize); + using var luma = mm.GetWritableRegion(ExtendOffset(lumaOffset), lumaSize); WriteLuma( luma.Memory.Span, @@ -27,7 +27,7 @@ namespace Ryujinx.Graphics.Nvdec.Image int chromaSize = GetBlockLinearSize(surface.UvWidth, surface.UvHeight, 2); - using var chroma = gmm.GetWritableRegion(ExtendOffset(chromaOffset), chromaSize); + using var chroma = mm.GetWritableRegion(ExtendOffset(chromaOffset), chromaSize); WriteChroma( chroma.Memory.Span, @@ -39,7 +39,7 @@ namespace Ryujinx.Graphics.Nvdec.Image } public static void WriteInterlaced( - MemoryManager gmm, + DeviceMemoryManager mm, ISurface surface, uint lumaTopOffset, uint chromaTopOffset, @@ -48,8 +48,8 @@ namespace Ryujinx.Graphics.Nvdec.Image { int lumaSize = GetBlockLinearSize(surface.Width, surface.Height / 2, 1); - using var lumaTop = gmm.GetWritableRegion(ExtendOffset(lumaTopOffset), lumaSize); - using var lumaBottom = gmm.GetWritableRegion(ExtendOffset(lumaBottomOffset), lumaSize); + using var lumaTop = mm.GetWritableRegion(ExtendOffset(lumaTopOffset), lumaSize); + using var lumaBottom = mm.GetWritableRegion(ExtendOffset(lumaBottomOffset), lumaSize); WriteLuma( lumaTop.Memory.Span, @@ -67,8 +67,8 @@ namespace Ryujinx.Graphics.Nvdec.Image int chromaSize = GetBlockLinearSize(surface.UvWidth, surface.UvHeight / 2, 2); - using var chromaTop = gmm.GetWritableRegion(ExtendOffset(chromaTopOffset), chromaSize); - using var chromaBottom = gmm.GetWritableRegion(ExtendOffset(chromaBottomOffset), chromaSize); + using var chromaTop = mm.GetWritableRegion(ExtendOffset(chromaTopOffset), chromaSize); + using var chromaBottom = mm.GetWritableRegion(ExtendOffset(chromaBottomOffset), chromaSize); WriteChroma( chromaTop.Memory.Span, diff --git a/src/Ryujinx.Graphics.Nvdec/MemoryExtensions.cs b/src/Ryujinx.Graphics.Nvdec/MemoryExtensions.cs index 28d42a8b4..1477ed914 100644 --- a/src/Ryujinx.Graphics.Nvdec/MemoryExtensions.cs +++ b/src/Ryujinx.Graphics.Nvdec/MemoryExtensions.cs @@ -1,23 +1,23 @@ -using Ryujinx.Graphics.Gpu.Memory; +using Ryujinx.Graphics.Device; using System; namespace Ryujinx.Graphics.Nvdec { static class MemoryExtensions { - public static T DeviceRead(this MemoryManager gmm, uint offset) where T : unmanaged + public static T DeviceRead(this DeviceMemoryManager gmm, uint offset) where T : unmanaged { - return gmm.Read((ulong)offset << 8); + return gmm.Read(ExtendOffset(offset)); } - public static ReadOnlySpan DeviceGetSpan(this MemoryManager gmm, uint offset, int size) + public static ReadOnlySpan DeviceGetSpan(this DeviceMemoryManager gmm, uint offset, int size) { - return gmm.GetSpan((ulong)offset << 8, size); + return gmm.GetSpan(ExtendOffset(offset), size); } - public static void DeviceWrite(this MemoryManager gmm, uint offset, ReadOnlySpan data) + public static void DeviceWrite(this DeviceMemoryManager gmm, uint offset, ReadOnlySpan data) { - gmm.Write((ulong)offset << 8, data); + gmm.Write(ExtendOffset(offset), data); } public static ulong ExtendOffset(uint offset) diff --git a/src/Ryujinx.Graphics.Nvdec/NvdecDevice.cs b/src/Ryujinx.Graphics.Nvdec/NvdecDevice.cs index 77e295544..29e260d63 100644 --- a/src/Ryujinx.Graphics.Nvdec/NvdecDevice.cs +++ b/src/Ryujinx.Graphics.Nvdec/NvdecDevice.cs @@ -1,6 +1,5 @@ using Ryujinx.Common.Logging; using Ryujinx.Graphics.Device; -using Ryujinx.Graphics.Gpu.Memory; using Ryujinx.Graphics.Nvdec.Image; using System.Collections.Concurrent; using System.Collections.Generic; @@ -17,9 +16,9 @@ namespace Ryujinx.Graphics.Nvdec private readonly ConcurrentDictionary _contexts; private NvdecDecoderContext _currentContext; - public NvdecDevice(MemoryManager gmm) + public NvdecDevice(DeviceMemoryManager mm) { - _rm = new ResourceManager(gmm, new SurfaceCache(gmm)); + _rm = new ResourceManager(mm, new SurfaceCache(mm)); _state = new DeviceState(new Dictionary { { nameof(NvdecRegisters.Execute), new RwCallback(Execute, null) }, diff --git a/src/Ryujinx.Graphics.Nvdec/ResourceManager.cs b/src/Ryujinx.Graphics.Nvdec/ResourceManager.cs index 200d3a1bd..da0ded912 100644 --- a/src/Ryujinx.Graphics.Nvdec/ResourceManager.cs +++ b/src/Ryujinx.Graphics.Nvdec/ResourceManager.cs @@ -1,16 +1,16 @@ -using Ryujinx.Graphics.Gpu.Memory; +using Ryujinx.Graphics.Device; using Ryujinx.Graphics.Nvdec.Image; namespace Ryujinx.Graphics.Nvdec { readonly struct ResourceManager { - public MemoryManager Gmm { get; } + public DeviceMemoryManager MemoryManager { get; } public SurfaceCache Cache { get; } - public ResourceManager(MemoryManager gmm, SurfaceCache cache) + public ResourceManager(DeviceMemoryManager mm, SurfaceCache cache) { - Gmm = gmm; + MemoryManager = mm; Cache = cache; } } diff --git a/src/Ryujinx.Graphics.Nvdec/Ryujinx.Graphics.Nvdec.csproj b/src/Ryujinx.Graphics.Nvdec/Ryujinx.Graphics.Nvdec.csproj index fd49a7c80..6c00e9a7c 100644 --- a/src/Ryujinx.Graphics.Nvdec/Ryujinx.Graphics.Nvdec.csproj +++ b/src/Ryujinx.Graphics.Nvdec/Ryujinx.Graphics.Nvdec.csproj @@ -8,7 +8,6 @@ - diff --git a/src/Ryujinx.Graphics.Nvdec/Vp8Decoder.cs b/src/Ryujinx.Graphics.Nvdec/Vp8Decoder.cs index 0a7d5840e..3d2543c49 100644 --- a/src/Ryujinx.Graphics.Nvdec/Vp8Decoder.cs +++ b/src/Ryujinx.Graphics.Nvdec/Vp8Decoder.cs @@ -10,8 +10,8 @@ namespace Ryujinx.Graphics.Nvdec { public static void Decode(NvdecDecoderContext context, ResourceManager rm, ref NvdecRegisters state) { - PictureInfo pictureInfo = rm.Gmm.DeviceRead(state.SetDrvPicSetupOffset); - ReadOnlySpan bitstream = rm.Gmm.DeviceGetSpan(state.SetInBufBaseOffset, (int)pictureInfo.VLDBufferSize); + PictureInfo pictureInfo = rm.MemoryManager.DeviceRead(state.SetDrvPicSetupOffset); + ReadOnlySpan bitstream = rm.MemoryManager.DeviceGetSpan(state.SetInBufBaseOffset, (int)pictureInfo.VLDBufferSize); Decoder decoder = context.GetVp8Decoder(); @@ -24,7 +24,7 @@ namespace Ryujinx.Graphics.Nvdec if (decoder.Decode(ref info, outputSurface, bitstream)) { - SurfaceWriter.Write(rm.Gmm, outputSurface, lumaOffset, chromaOffset); + SurfaceWriter.Write(rm.MemoryManager, outputSurface, lumaOffset, chromaOffset); } rm.Cache.Put(outputSurface); diff --git a/src/Ryujinx.Graphics.Nvdec/Vp9Decoder.cs b/src/Ryujinx.Graphics.Nvdec/Vp9Decoder.cs index 037950562..5ed508647 100644 --- a/src/Ryujinx.Graphics.Nvdec/Vp9Decoder.cs +++ b/src/Ryujinx.Graphics.Nvdec/Vp9Decoder.cs @@ -1,5 +1,5 @@ using Ryujinx.Common; -using Ryujinx.Graphics.Gpu.Memory; +using Ryujinx.Graphics.Device; using Ryujinx.Graphics.Nvdec.Image; using Ryujinx.Graphics.Nvdec.Types.Vp9; using Ryujinx.Graphics.Nvdec.Vp9; @@ -17,8 +17,8 @@ namespace Ryujinx.Graphics.Nvdec public unsafe static void Decode(ResourceManager rm, ref NvdecRegisters state) { - PictureInfo pictureInfo = rm.Gmm.DeviceRead(state.SetDrvPicSetupOffset); - EntropyProbs entropy = rm.Gmm.DeviceRead(state.Vp9SetProbTabBufOffset); + PictureInfo pictureInfo = rm.MemoryManager.DeviceRead(state.SetDrvPicSetupOffset); + EntropyProbs entropy = rm.MemoryManager.DeviceRead(state.Vp9SetProbTabBufOffset); ISurface Rent(uint lumaOffset, uint chromaOffset, FrameSize size) { @@ -38,19 +38,19 @@ namespace Ryujinx.Graphics.Nvdec entropy.Convert(ref info.Entropy); - ReadOnlySpan bitstream = rm.Gmm.DeviceGetSpan(state.SetInBufBaseOffset, (int)pictureInfo.BitstreamSize); + ReadOnlySpan bitstream = rm.MemoryManager.DeviceGetSpan(state.SetInBufBaseOffset, (int)pictureInfo.BitstreamSize); ReadOnlySpan mvsIn = ReadOnlySpan.Empty; if (info.UsePrevInFindMvRefs) { - mvsIn = GetMvsInput(rm.Gmm, pictureInfo.CurrentFrameSize, state.Vp9SetColMvReadBufOffset); + mvsIn = GetMvsInput(rm.MemoryManager, pictureInfo.CurrentFrameSize, state.Vp9SetColMvReadBufOffset); } int miCols = BitUtils.DivRoundUp(pictureInfo.CurrentFrameSize.Width, 8); int miRows = BitUtils.DivRoundUp(pictureInfo.CurrentFrameSize.Height, 8); - using var mvsRegion = rm.Gmm.GetWritableRegion(ExtendOffset(state.Vp9SetColMvWriteBufOffset), miRows * miCols * 16); + using var mvsRegion = rm.MemoryManager.GetWritableRegion(ExtendOffset(state.Vp9SetColMvWriteBufOffset), miRows * miCols * 16); Span mvsOut = MemoryMarshal.Cast(mvsRegion.Memory.Span); @@ -59,10 +59,10 @@ namespace Ryujinx.Graphics.Nvdec if (_decoder.Decode(ref info, currentSurface, bitstream, mvsIn, mvsOut)) { - SurfaceWriter.Write(rm.Gmm, currentSurface, lumaOffset, chromaOffset); + SurfaceWriter.Write(rm.MemoryManager, currentSurface, lumaOffset, chromaOffset); } - WriteBackwardUpdates(rm.Gmm, state.Vp9SetCtxCounterBufOffset, ref info.BackwardUpdateCounts); + WriteBackwardUpdates(rm.MemoryManager, state.Vp9SetCtxCounterBufOffset, ref info.BackwardUpdateCounts); rm.Cache.Put(lastSurface); rm.Cache.Put(goldenSurface); @@ -70,17 +70,17 @@ namespace Ryujinx.Graphics.Nvdec rm.Cache.Put(currentSurface); } - private static ReadOnlySpan GetMvsInput(MemoryManager gmm, FrameSize size, uint offset) + private static ReadOnlySpan GetMvsInput(DeviceMemoryManager mm, FrameSize size, uint offset) { int miCols = BitUtils.DivRoundUp(size.Width, 8); int miRows = BitUtils.DivRoundUp(size.Height, 8); - return MemoryMarshal.Cast(gmm.DeviceGetSpan(offset, miRows * miCols * 16)); + return MemoryMarshal.Cast(mm.DeviceGetSpan(offset, miRows * miCols * 16)); } - private static void WriteBackwardUpdates(MemoryManager gmm, uint offset, ref Vp9BackwardUpdates counts) + private static void WriteBackwardUpdates(DeviceMemoryManager mm, uint offset, ref Vp9BackwardUpdates counts) { - using var backwardUpdatesRegion = gmm.GetWritableRegion(ExtendOffset(offset), Unsafe.SizeOf()); + using var backwardUpdatesRegion = mm.GetWritableRegion(ExtendOffset(offset), Unsafe.SizeOf()); ref var backwardUpdates = ref MemoryMarshal.Cast(backwardUpdatesRegion.Memory.Span)[0]; diff --git a/src/Ryujinx.Graphics.OpenGL/BackgroundContextWorker.cs b/src/Ryujinx.Graphics.OpenGL/BackgroundContextWorker.cs index ae647e388..f22e0df57 100644 --- a/src/Ryujinx.Graphics.OpenGL/BackgroundContextWorker.cs +++ b/src/Ryujinx.Graphics.OpenGL/BackgroundContextWorker.cs @@ -30,6 +30,8 @@ namespace Ryujinx.Graphics.OpenGL _thread.Start(); } + public bool HasContext() => _backgroundContext.HasContext(); + private void Run() { InBackground = true; diff --git a/src/Ryujinx.Graphics.OpenGL/FormatTable.cs b/src/Ryujinx.Graphics.OpenGL/FormatTable.cs index 3dac33b94..c7e3e4e28 100644 --- a/src/Ryujinx.Graphics.OpenGL/FormatTable.cs +++ b/src/Ryujinx.Graphics.OpenGL/FormatTable.cs @@ -161,6 +161,7 @@ namespace Ryujinx.Graphics.OpenGL Add(Format.A1B5G5R5Unorm, new FormatInfo(4, true, false, All.Rgb5A1, PixelFormat.Rgba, PixelType.UnsignedShort5551)); Add(Format.B8G8R8A8Unorm, new FormatInfo(4, true, false, All.Rgba8, PixelFormat.Rgba, PixelType.UnsignedByte)); Add(Format.B8G8R8A8Srgb, new FormatInfo(4, false, false, All.Srgb8Alpha8, PixelFormat.Rgba, PixelType.UnsignedByte)); + Add(Format.B10G10R10A2Unorm, new FormatInfo(4, false, false, All.Rgb10A2, PixelFormat.Rgba, PixelType.UnsignedInt2101010Reversed)); Add(Format.R8Unorm, SizedInternalFormat.R8); Add(Format.R8Uint, SizedInternalFormat.R8ui); diff --git a/src/Ryujinx.Graphics.OpenGL/IOpenGLContext.cs b/src/Ryujinx.Graphics.OpenGL/IOpenGLContext.cs index a11b9cb29..525418d74 100644 --- a/src/Ryujinx.Graphics.OpenGL/IOpenGLContext.cs +++ b/src/Ryujinx.Graphics.OpenGL/IOpenGLContext.cs @@ -7,21 +7,6 @@ namespace Ryujinx.Graphics.OpenGL { void MakeCurrent(); - // TODO: Support more APIs per platform. - static bool HasContext() - { - if (OperatingSystem.IsWindows()) - { - return WGLHelper.GetCurrentContext() != IntPtr.Zero; - } - else if (OperatingSystem.IsLinux()) - { - return GLXHelper.GetCurrentContext() != IntPtr.Zero; - } - else - { - return false; - } - } + bool HasContext(); } } diff --git a/src/Ryujinx.Graphics.OpenGL/OpenGLRenderer.cs b/src/Ryujinx.Graphics.OpenGL/OpenGLRenderer.cs index 64ba4e3ee..eabcb3c10 100644 --- a/src/Ryujinx.Graphics.OpenGL/OpenGLRenderer.cs +++ b/src/Ryujinx.Graphics.OpenGL/OpenGLRenderer.cs @@ -121,7 +121,7 @@ namespace Ryujinx.Graphics.OpenGL public HardwareInfo GetHardwareInfo() { - return new HardwareInfo(GpuVendor, GpuRenderer); + return new HardwareInfo(GpuVendor, GpuRenderer, GpuVendor); // OpenGL does not provide a driver name, vendor name is closest analogue. } public PinnedSpan GetBufferData(BufferHandle buffer, int offset, int size) @@ -248,7 +248,7 @@ namespace Ryujinx.Graphics.OpenGL { // alwaysBackground is ignored, since we cannot switch from the current context. - if (IOpenGLContext.HasContext()) + if (_window.BackgroundContext.HasContext()) { action(); // We have a context already - use that (assuming it is the main one). } diff --git a/src/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs b/src/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs index 55f7d5778..06daa26a0 100644 --- a/src/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs +++ b/src/Ryujinx.Graphics.Shader/Instructions/InstEmitTexture.cs @@ -578,12 +578,7 @@ namespace Ryujinx.Graphics.Shader.Instructions type = SamplerType.Texture2D; flags = TextureFlags.Gather; - if (tld4sOp.Dc) - { - sourcesList.Add(Rb()); - - type |= SamplerType.Shadow; - } + int depthCompareIndex = sourcesList.Count; if (tld4sOp.Aoffi) { @@ -592,7 +587,16 @@ namespace Ryujinx.Graphics.Shader.Instructions flags |= TextureFlags.Offset; } - sourcesList.Add(Const((int)tld4sOp.TexComp)); + if (tld4sOp.Dc) + { + sourcesList.Insert(depthCompareIndex, Rb()); + + type |= SamplerType.Shadow; + } + else + { + sourcesList.Add(Const((int)tld4sOp.TexComp)); + } } else { diff --git a/src/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs b/src/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs index f1dffb351..e1157eea4 100644 --- a/src/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs +++ b/src/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs @@ -80,9 +80,10 @@ namespace Ryujinx.Graphics.Shader.Translation return; } - if (TranslatorContext.Definitions.Stage == ShaderStage.Vertex && TranslatorContext.Options.TargetApi == TargetApi.Vulkan) + // Vulkan requires the point size to be always written on the shader if the primitive topology is points. + // OpenGL requires the point size to be always written on the shader if PROGRAM_POINT_SIZE is set. + if (TranslatorContext.Definitions.Stage == ShaderStage.Vertex) { - // Vulkan requires the point size to be always written on the shader if the primitive topology is points. this.Store(StorageKind.Output, IoVariable.PointSize, null, ConstF(TranslatorContext.Definitions.PointSize)); } diff --git a/src/Ryujinx.Graphics.Vic/Image/SurfaceReader.cs b/src/Ryujinx.Graphics.Vic/Image/SurfaceReader.cs index 8a9acd912..83f00f345 100644 --- a/src/Ryujinx.Graphics.Vic/Image/SurfaceReader.cs +++ b/src/Ryujinx.Graphics.Vic/Image/SurfaceReader.cs @@ -454,7 +454,7 @@ namespace Ryujinx.Graphics.Vic.Image int srcStride = GetPitch(width, bytesPerPixel); int inSize = srcStride * height; - ReadOnlySpan src = rm.Gmm.GetSpan(ExtendOffset(offset), inSize); + ReadOnlySpan src = rm.MemoryManager.GetSpan(ExtendOffset(offset), inSize); int outSize = dstStride * height; int bufferIndex = rm.BufferPool.RentMinimum(outSize, out byte[] buffer); @@ -481,7 +481,7 @@ namespace Ryujinx.Graphics.Vic.Image { int inSize = GetBlockLinearSize(width, height, bytesPerPixel, gobBlocksInY); - ReadOnlySpan src = rm.Gmm.GetSpan(ExtendOffset(offset), inSize); + ReadOnlySpan src = rm.MemoryManager.GetSpan(ExtendOffset(offset), inSize); int outSize = dstStride * height; int bufferIndex = rm.BufferPool.RentMinimum(outSize, out byte[] buffer); diff --git a/src/Ryujinx.Graphics.Vic/Image/SurfaceWriter.cs b/src/Ryujinx.Graphics.Vic/Image/SurfaceWriter.cs index b06640499..b5008b7b5 100644 --- a/src/Ryujinx.Graphics.Vic/Image/SurfaceWriter.cs +++ b/src/Ryujinx.Graphics.Vic/Image/SurfaceWriter.cs @@ -636,7 +636,7 @@ namespace Ryujinx.Graphics.Vic.Image { if (linear) { - rm.Gmm.WriteMapped(ExtendOffset(offset), src); + rm.MemoryManager.Write(ExtendOffset(offset), src); return; } @@ -659,7 +659,7 @@ namespace Ryujinx.Graphics.Vic.Image LayoutConverter.ConvertLinearToBlockLinear(dst, width, height, dstStride, bytesPerPixel, gobBlocksInY, src); - rm.Gmm.WriteMapped(ExtendOffset(offset), dst); + rm.MemoryManager.Write(ExtendOffset(offset), dst); rm.BufferPool.Return(dstIndex); } diff --git a/src/Ryujinx.Graphics.Vic/ResourceManager.cs b/src/Ryujinx.Graphics.Vic/ResourceManager.cs index b0ff8e10e..e7d7ef74a 100644 --- a/src/Ryujinx.Graphics.Vic/ResourceManager.cs +++ b/src/Ryujinx.Graphics.Vic/ResourceManager.cs @@ -1,17 +1,17 @@ -using Ryujinx.Graphics.Gpu.Memory; +using Ryujinx.Graphics.Device; using Ryujinx.Graphics.Vic.Image; namespace Ryujinx.Graphics.Vic { readonly struct ResourceManager { - public MemoryManager Gmm { get; } + public DeviceMemoryManager MemoryManager { get; } public BufferPool SurfacePool { get; } public BufferPool BufferPool { get; } - public ResourceManager(MemoryManager gmm, BufferPool surfacePool, BufferPool bufferPool) + public ResourceManager(DeviceMemoryManager mm, BufferPool surfacePool, BufferPool bufferPool) { - Gmm = gmm; + MemoryManager = mm; SurfacePool = surfacePool; BufferPool = bufferPool; } diff --git a/src/Ryujinx.Graphics.Vic/Ryujinx.Graphics.Vic.csproj b/src/Ryujinx.Graphics.Vic/Ryujinx.Graphics.Vic.csproj index cfebcfa2a..a6c4fb2bb 100644 --- a/src/Ryujinx.Graphics.Vic/Ryujinx.Graphics.Vic.csproj +++ b/src/Ryujinx.Graphics.Vic/Ryujinx.Graphics.Vic.csproj @@ -8,8 +8,6 @@ - - diff --git a/src/Ryujinx.Graphics.Vic/VicDevice.cs b/src/Ryujinx.Graphics.Vic/VicDevice.cs index 2ddb94a4e..2b25a74c8 100644 --- a/src/Ryujinx.Graphics.Vic/VicDevice.cs +++ b/src/Ryujinx.Graphics.Vic/VicDevice.cs @@ -1,5 +1,4 @@ using Ryujinx.Graphics.Device; -using Ryujinx.Graphics.Gpu.Memory; using Ryujinx.Graphics.Vic.Image; using Ryujinx.Graphics.Vic.Types; using System; @@ -9,14 +8,14 @@ namespace Ryujinx.Graphics.Vic { public class VicDevice : IDeviceState { - private readonly MemoryManager _gmm; + private readonly DeviceMemoryManager _mm; private readonly ResourceManager _rm; private readonly DeviceState _state; - public VicDevice(MemoryManager gmm) + public VicDevice(DeviceMemoryManager mm) { - _gmm = gmm; - _rm = new ResourceManager(gmm, new BufferPool(), new BufferPool()); + _mm = mm; + _rm = new ResourceManager(mm, new BufferPool(), new BufferPool()); _state = new DeviceState(new Dictionary { { nameof(VicRegisters.Execute), new RwCallback(Execute, null) }, @@ -68,7 +67,7 @@ namespace Ryujinx.Graphics.Vic private T ReadIndirect(uint offset) where T : unmanaged { - return _gmm.Read((ulong)offset << 8); + return _mm.Read((ulong)offset << 8); } } } diff --git a/src/Ryujinx.Graphics.Vulkan/BufferHolder.cs b/src/Ryujinx.Graphics.Vulkan/BufferHolder.cs index b54ff3ab6..3673ee5a1 100644 --- a/src/Ryujinx.Graphics.Vulkan/BufferHolder.cs +++ b/src/Ryujinx.Graphics.Vulkan/BufferHolder.cs @@ -4,6 +4,7 @@ using Silk.NET.Vulkan; using System; using System.Collections.Generic; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using System.Threading; using VkBuffer = Silk.NET.Vulkan.Buffer; using VkFormat = Silk.NET.Vulkan.Format; @@ -384,7 +385,7 @@ namespace Ryujinx.Graphics.Vulkan var baseData = new Span((void*)(_map + offset), size); var modData = _pendingData.AsSpan(offset, size); - StagingBufferReserved? newMirror = _gd.BufferManager.StagingBuffer.TryReserveData(cbs, size, (int)_gd.Capabilities.MinResourceAlignment); + StagingBufferReserved? newMirror = _gd.BufferManager.StagingBuffer.TryReserveData(cbs, size); if (newMirror != null) { @@ -520,7 +521,7 @@ namespace Ryujinx.Graphics.Vulkan if (_gd.PipelineInternal.CurrentCommandBuffer.CommandBuffer.Handle == cbs.CommandBuffer.Handle) { - SetData(rangeOffset, _pendingData.AsSpan(rangeOffset, rangeSize), cbs, _gd.PipelineInternal.EndRenderPass, false); + SetData(rangeOffset, _pendingData.AsSpan(rangeOffset, rangeSize), cbs, _gd.PipelineInternal.EndRenderPassDelegate, false); } else { @@ -838,6 +839,11 @@ namespace Ryujinx.Graphics.Vulkan } } + public unsafe void SetDataUnchecked(int offset, ReadOnlySpan data) where T : unmanaged + { + SetDataUnchecked(offset, MemoryMarshal.AsBytes(data)); + } + public void SetDataInline(CommandBufferScoped cbs, Action endRenderPass, int dstOffset, ReadOnlySpan data) { if (!TryPushData(cbs, endRenderPass, dstOffset, data)) diff --git a/src/Ryujinx.Graphics.Vulkan/BufferManager.cs b/src/Ryujinx.Graphics.Vulkan/BufferManager.cs index e9ac98847..33289a0e0 100644 --- a/src/Ryujinx.Graphics.Vulkan/BufferManager.cs +++ b/src/Ryujinx.Graphics.Vulkan/BufferManager.cs @@ -9,6 +9,36 @@ using VkFormat = Silk.NET.Vulkan.Format; namespace Ryujinx.Graphics.Vulkan { + readonly struct ScopedTemporaryBuffer : IDisposable + { + private readonly BufferManager _bufferManager; + private readonly bool _isReserved; + + public readonly BufferRange Range; + public readonly BufferHolder Holder; + + public BufferHandle Handle => Range.Handle; + public int Offset => Range.Offset; + + public ScopedTemporaryBuffer(BufferManager bufferManager, BufferHolder holder, BufferHandle handle, int offset, int size, bool isReserved) + { + _bufferManager = bufferManager; + + Range = new BufferRange(handle, offset, size); + Holder = holder; + + _isReserved = isReserved; + } + + public void Dispose() + { + if (!_isReserved) + { + _bufferManager.Delete(Range.Handle); + } + } + } + class BufferManager : IDisposable { public const MemoryPropertyFlags DefaultBufferMemoryFlags = @@ -238,6 +268,23 @@ namespace Ryujinx.Graphics.Vulkan return Unsafe.As(ref handle64); } + public ScopedTemporaryBuffer ReserveOrCreate(VulkanRenderer gd, CommandBufferScoped cbs, int size) + { + StagingBufferReserved? result = StagingBuffer.TryReserveData(cbs, size); + + if (result.HasValue) + { + return new ScopedTemporaryBuffer(this, result.Value.Buffer, StagingBuffer.Handle, result.Value.Offset, result.Value.Size, true); + } + else + { + // Create a temporary buffer. + BufferHandle handle = CreateWithHandle(gd, size, out BufferHolder holder); + + return new ScopedTemporaryBuffer(this, holder, handle, 0, size, false); + } + } + public unsafe MemoryRequirements GetHostImportedUsageRequirements(VulkanRenderer gd) { var usage = HostImportedBufferUsageFlags; @@ -635,13 +682,14 @@ namespace Ryujinx.Graphics.Vulkan { if (disposing) { + StagingBuffer.Dispose(); + foreach (BufferHolder buffer in _buffers) { buffer.Dispose(); } _buffers.Clear(); - StagingBuffer.Dispose(); } } diff --git a/src/Ryujinx.Graphics.Vulkan/DescriptorSetTemplate.cs b/src/Ryujinx.Graphics.Vulkan/DescriptorSetTemplate.cs new file mode 100644 index 000000000..0c0004b95 --- /dev/null +++ b/src/Ryujinx.Graphics.Vulkan/DescriptorSetTemplate.cs @@ -0,0 +1,145 @@ +using Ryujinx.Graphics.GAL; +using Silk.NET.Vulkan; +using System; +using System.Runtime.CompilerServices; + +namespace Ryujinx.Graphics.Vulkan +{ + class DescriptorSetTemplate : IDisposable + { + private readonly VulkanRenderer _gd; + private readonly Device _device; + + public readonly DescriptorUpdateTemplate Template; + public readonly int Size; + + public unsafe DescriptorSetTemplate(VulkanRenderer gd, Device device, ResourceBindingSegment[] segments, PipelineLayoutCacheEntry plce, PipelineBindPoint pbp, int setIndex) + { + _gd = gd; + _device = device; + + // Create a template from the set usages. Assumes the descriptor set is updated in segment order then binding order. + + DescriptorUpdateTemplateEntry* entries = stackalloc DescriptorUpdateTemplateEntry[segments.Length]; + nuint structureOffset = 0; + + for (int seg = 0; seg < segments.Length; seg++) + { + ResourceBindingSegment segment = segments[seg]; + + int binding = segment.Binding; + int count = segment.Count; + + if (setIndex == PipelineBase.UniformSetIndex) + { + entries[seg] = new DescriptorUpdateTemplateEntry() + { + DescriptorType = DescriptorType.UniformBuffer, + DstBinding = (uint)binding, + DescriptorCount = (uint)count, + Offset = structureOffset, + Stride = (nuint)Unsafe.SizeOf() + }; + + structureOffset += (nuint)(Unsafe.SizeOf() * count); + } + else if (setIndex == PipelineBase.StorageSetIndex) + { + entries[seg] = new DescriptorUpdateTemplateEntry() + { + DescriptorType = DescriptorType.StorageBuffer, + DstBinding = (uint)binding, + DescriptorCount = (uint)count, + Offset = structureOffset, + Stride = (nuint)Unsafe.SizeOf() + }; + + structureOffset += (nuint)(Unsafe.SizeOf() * count); + } + else if (setIndex == PipelineBase.TextureSetIndex) + { + if (segment.Type != ResourceType.BufferTexture) + { + entries[seg] = new DescriptorUpdateTemplateEntry() + { + DescriptorType = DescriptorType.CombinedImageSampler, + DstBinding = (uint)binding, + DescriptorCount = (uint)count, + Offset = structureOffset, + Stride = (nuint)Unsafe.SizeOf() + }; + + structureOffset += (nuint)(Unsafe.SizeOf() * count); + } + else + { + entries[seg] = new DescriptorUpdateTemplateEntry() + { + DescriptorType = DescriptorType.UniformTexelBuffer, + DstBinding = (uint)binding, + DescriptorCount = (uint)count, + Offset = structureOffset, + Stride = (nuint)Unsafe.SizeOf() + }; + + structureOffset += (nuint)(Unsafe.SizeOf() * count); + } + } + else if (setIndex == PipelineBase.ImageSetIndex) + { + if (segment.Type != ResourceType.BufferImage) + { + entries[seg] = new DescriptorUpdateTemplateEntry() + { + DescriptorType = DescriptorType.StorageImage, + DstBinding = (uint)binding, + DescriptorCount = (uint)count, + Offset = structureOffset, + Stride = (nuint)Unsafe.SizeOf() + }; + + structureOffset += (nuint)(Unsafe.SizeOf() * count); + } + else + { + entries[seg] = new DescriptorUpdateTemplateEntry() + { + DescriptorType = DescriptorType.StorageTexelBuffer, + DstBinding = (uint)binding, + DescriptorCount = (uint)count, + Offset = structureOffset, + Stride = (nuint)Unsafe.SizeOf() + }; + + structureOffset += (nuint)(Unsafe.SizeOf() * count); + } + } + } + + Size = (int)structureOffset; + + var info = new DescriptorUpdateTemplateCreateInfo() + { + SType = StructureType.DescriptorUpdateTemplateCreateInfo, + DescriptorUpdateEntryCount = (uint)segments.Length, + PDescriptorUpdateEntries = entries, + + TemplateType = DescriptorUpdateTemplateType.DescriptorSet, + DescriptorSetLayout = plce.DescriptorSetLayouts[setIndex], + PipelineBindPoint = pbp, + PipelineLayout = plce.PipelineLayout, + Set = (uint)setIndex, + }; + + DescriptorUpdateTemplate result; + gd.Api.CreateDescriptorUpdateTemplate(device, &info, null, &result).ThrowOnError(); + + Template = result; + } + + public unsafe void Dispose() + { + _gd.Api.DestroyDescriptorUpdateTemplate(_device, Template, null); + } + } +} diff --git a/src/Ryujinx.Graphics.Vulkan/DescriptorSetTemplateUpdater.cs b/src/Ryujinx.Graphics.Vulkan/DescriptorSetTemplateUpdater.cs new file mode 100644 index 000000000..1eb9dce75 --- /dev/null +++ b/src/Ryujinx.Graphics.Vulkan/DescriptorSetTemplateUpdater.cs @@ -0,0 +1,65 @@ +using Ryujinx.Common; +using Silk.NET.Vulkan; +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Ryujinx.Graphics.Vulkan +{ + ref struct DescriptorSetTemplateWriter + { + private Span _data; + + public DescriptorSetTemplateWriter(Span data) + { + _data = data; + } + + public void Push(ReadOnlySpan values) where T : unmanaged + { + Span target = MemoryMarshal.Cast(_data); + + values.CopyTo(target); + + _data = _data[(Unsafe.SizeOf() * values.Length)..]; + } + } + + unsafe class DescriptorSetTemplateUpdater : IDisposable + { + private const int SizeGranularity = 512; + + private DescriptorSetTemplate _activeTemplate; + private NativeArray _data; + + private void EnsureSize(int size) + { + if (_data == null || _data.Length < size) + { + _data?.Dispose(); + + int dataSize = BitUtils.AlignUp(size, SizeGranularity); + _data = new NativeArray(dataSize); + } + } + + public DescriptorSetTemplateWriter Begin(DescriptorSetTemplate template) + { + _activeTemplate = template; + + EnsureSize(template.Size); + + return new DescriptorSetTemplateWriter(new Span(_data.Pointer, template.Size)); + } + + public void Commit(VulkanRenderer gd, Device device, DescriptorSet set) + { + gd.Api.UpdateDescriptorSetWithTemplate(device, set, _activeTemplate.Template, _data.Pointer); + } + + public void Dispose() + { + _data?.Dispose(); + } + } +} diff --git a/src/Ryujinx.Graphics.Vulkan/DescriptorSetUpdater.cs b/src/Ryujinx.Graphics.Vulkan/DescriptorSetUpdater.cs index e0fe5d89a..6615d8ce0 100644 --- a/src/Ryujinx.Graphics.Vulkan/DescriptorSetUpdater.cs +++ b/src/Ryujinx.Graphics.Vulkan/DescriptorSetUpdater.cs @@ -35,6 +35,7 @@ namespace Ryujinx.Graphics.Vulkan } private readonly VulkanRenderer _gd; + private readonly Device _device; private readonly PipelineBase _pipeline; private ShaderCollection _program; @@ -54,6 +55,8 @@ namespace Ryujinx.Graphics.Vulkan private readonly BufferView[] _bufferTextures; private readonly BufferView[] _bufferImages; + private readonly DescriptorSetTemplateUpdater _templateUpdater; + private BitMapStruct> _uniformSet; private BitMapStruct> _storageSet; private BitMapStruct> _uniformMirrored; @@ -78,9 +81,10 @@ namespace Ryujinx.Graphics.Vulkan private readonly TextureView _dummyTexture; private readonly SamplerHolder _dummySampler; - public DescriptorSetUpdater(VulkanRenderer gd, PipelineBase pipeline) + public DescriptorSetUpdater(VulkanRenderer gd, Device device, PipelineBase pipeline) { _gd = gd; + _device = device; _pipeline = pipeline; // Some of the bindings counts needs to be multiplied by 2 because we have buffer and @@ -152,6 +156,8 @@ namespace Ryujinx.Graphics.Vulkan 0, 0, 1f)); + + _templateUpdater = new(); } public void Initialize() @@ -509,6 +515,10 @@ namespace Ryujinx.Graphics.Vulkan } } + DescriptorSetTemplate template = program.Templates[setIndex]; + + DescriptorSetTemplateWriter tu = _templateUpdater.Begin(template); + foreach (ResourceBindingSegment segment in bindingSegments) { int binding = segment.Binding; @@ -531,7 +541,8 @@ namespace Ryujinx.Graphics.Vulkan } ReadOnlySpan uniformBuffers = _uniformBuffers; - dsc.UpdateBuffers(0, binding, uniformBuffers.Slice(binding, count), DescriptorType.UniformBuffer); + + tu.Push(uniformBuffers.Slice(binding, count)); } else if (setIndex == PipelineBase.StorageSetIndex) { @@ -556,7 +567,8 @@ namespace Ryujinx.Graphics.Vulkan } ReadOnlySpan storageBuffers = _storageBuffers; - dsc.UpdateBuffers(0, binding, storageBuffers.Slice(binding, count), DescriptorType.StorageBuffer); + + tu.Push(storageBuffers.Slice(binding, count)); } else if (setIndex == PipelineBase.TextureSetIndex) { @@ -582,7 +594,7 @@ namespace Ryujinx.Graphics.Vulkan } } - dsc.UpdateImages(0, binding, textures[..count], DescriptorType.CombinedImageSampler); + tu.Push(textures[..count]); } else { @@ -593,7 +605,7 @@ namespace Ryujinx.Graphics.Vulkan bufferTextures[i] = _bufferTextureRefs[binding + i]?.GetBufferView(cbs, false) ?? default; } - dsc.UpdateBufferImages(0, binding, bufferTextures[..count], DescriptorType.UniformTexelBuffer); + tu.Push(bufferTextures[..count]); } } else if (setIndex == PipelineBase.ImageSetIndex) @@ -607,7 +619,7 @@ namespace Ryujinx.Graphics.Vulkan images[i].ImageView = _imageRefs[binding + i]?.Get(cbs).Value ?? default; } - dsc.UpdateImages(0, binding, images[..count], DescriptorType.StorageImage); + tu.Push(images[..count]); } else { @@ -618,12 +630,13 @@ namespace Ryujinx.Graphics.Vulkan bufferImages[i] = _bufferImageRefs[binding + i]?.GetBufferView(cbs, _bufferImageFormats[binding + i], true) ?? default; } - dsc.UpdateBufferImages(0, binding, bufferImages[..count], DescriptorType.StorageTexelBuffer); + tu.Push(bufferImages[..count]); } } } var sets = dsc.GetSets(); + _templateUpdater.Commit(_gd, _device, sets[0]); _gd.Api.CmdBindDescriptorSets(cbs.CommandBuffer, pbp, _program.PipelineLayout, (uint)setIndex, 1, sets, 0, ReadOnlySpan.Empty); } @@ -736,6 +749,7 @@ namespace Ryujinx.Graphics.Vulkan { _dummyTexture.Dispose(); _dummySampler.Dispose(); + _templateUpdater.Dispose(); } } diff --git a/src/Ryujinx.Graphics.Vulkan/Effects/FsrScalingFilter.cs b/src/Ryujinx.Graphics.Vulkan/Effects/FsrScalingFilter.cs index 23acdcf8f..5c0fc468b 100644 --- a/src/Ryujinx.Graphics.Vulkan/Effects/FsrScalingFilter.cs +++ b/src/Ryujinx.Graphics.Vulkan/Effects/FsrScalingFilter.cs @@ -142,19 +142,18 @@ namespace Ryujinx.Graphics.Vulkan.Effects }; int rangeSize = dimensionsBuffer.Length * sizeof(float); - var bufferHandle = _renderer.BufferManager.CreateWithHandle(_renderer, rangeSize); - _renderer.BufferManager.SetData(bufferHandle, 0, dimensionsBuffer); + using var buffer = _renderer.BufferManager.ReserveOrCreate(_renderer, cbs, rangeSize); + buffer.Holder.SetDataUnchecked(buffer.Offset, dimensionsBuffer); - ReadOnlySpan sharpeningBuffer = stackalloc float[] { 1.5f - (Level * 0.01f * 1.5f) }; - var sharpeningBufferHandle = _renderer.BufferManager.CreateWithHandle(_renderer, sizeof(float)); - _renderer.BufferManager.SetData(sharpeningBufferHandle, 0, sharpeningBuffer); + ReadOnlySpan sharpeningBufferData = stackalloc float[] { 1.5f - (Level * 0.01f * 1.5f) }; + using var sharpeningBuffer = _renderer.BufferManager.ReserveOrCreate(_renderer, cbs, sizeof(float)); + sharpeningBuffer.Holder.SetDataUnchecked(sharpeningBuffer.Offset, sharpeningBufferData); int threadGroupWorkRegionDim = 16; int dispatchX = (width + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim; int dispatchY = (height + (threadGroupWorkRegionDim - 1)) / threadGroupWorkRegionDim; - var bufferRanges = new BufferRange(bufferHandle, 0, rangeSize); - _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, bufferRanges) }); + _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, buffer.Range) }); _pipeline.SetImage(0, _intermediaryTexture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)); _pipeline.DispatchCompute(dispatchX, dispatchY, 1); _pipeline.ComputeBarrier(); @@ -162,16 +161,12 @@ namespace Ryujinx.Graphics.Vulkan.Effects // Sharpening pass _pipeline.SetProgram(_sharpeningProgram); _pipeline.SetTextureAndSampler(ShaderStage.Compute, 1, _intermediaryTexture, _sampler); - var sharpeningRange = new BufferRange(sharpeningBufferHandle, 0, sizeof(float)); - _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(4, sharpeningRange) }); + _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(4, sharpeningBuffer.Range) }); _pipeline.SetImage(0, destinationTexture); _pipeline.DispatchCompute(dispatchX, dispatchY, 1); _pipeline.ComputeBarrier(); _pipeline.Finish(); - - _renderer.BufferManager.Delete(bufferHandle); - _renderer.BufferManager.Delete(sharpeningBufferHandle); } } } diff --git a/src/Ryujinx.Graphics.Vulkan/Effects/FxaaPostProcessingEffect.cs b/src/Ryujinx.Graphics.Vulkan/Effects/FxaaPostProcessingEffect.cs index 67e461e51..a7dd8eee8 100644 --- a/src/Ryujinx.Graphics.Vulkan/Effects/FxaaPostProcessingEffect.cs +++ b/src/Ryujinx.Graphics.Vulkan/Effects/FxaaPostProcessingEffect.cs @@ -66,12 +66,11 @@ namespace Ryujinx.Graphics.Vulkan.Effects ReadOnlySpan resolutionBuffer = stackalloc float[] { view.Width, view.Height }; int rangeSize = resolutionBuffer.Length * sizeof(float); - var bufferHandle = _renderer.BufferManager.CreateWithHandle(_renderer, rangeSize); + using var buffer = _renderer.BufferManager.ReserveOrCreate(_renderer, cbs, rangeSize); - _renderer.BufferManager.SetData(bufferHandle, 0, resolutionBuffer); + buffer.Holder.SetDataUnchecked(buffer.Offset, resolutionBuffer); - var bufferRanges = new BufferRange(bufferHandle, 0, rangeSize); - _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, bufferRanges) }); + _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, buffer.Range) }); var dispatchX = BitUtils.DivRoundUp(view.Width, IPostProcessingEffect.LocalGroupSize); var dispatchY = BitUtils.DivRoundUp(view.Height, IPostProcessingEffect.LocalGroupSize); @@ -79,7 +78,6 @@ namespace Ryujinx.Graphics.Vulkan.Effects _pipeline.SetImage(0, _texture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)); _pipeline.DispatchCompute(dispatchX, dispatchY, 1); - _renderer.BufferManager.Delete(bufferHandle); _pipeline.ComputeBarrier(); _pipeline.Finish(); diff --git a/src/Ryujinx.Graphics.Vulkan/Effects/SmaaPostProcessingEffect.cs b/src/Ryujinx.Graphics.Vulkan/Effects/SmaaPostProcessingEffect.cs index c521f2273..be392fe0e 100644 --- a/src/Ryujinx.Graphics.Vulkan/Effects/SmaaPostProcessingEffect.cs +++ b/src/Ryujinx.Graphics.Vulkan/Effects/SmaaPostProcessingEffect.cs @@ -215,11 +215,10 @@ namespace Ryujinx.Graphics.Vulkan.Effects ReadOnlySpan resolutionBuffer = stackalloc float[] { view.Width, view.Height }; int rangeSize = resolutionBuffer.Length * sizeof(float); - var bufferHandle = _renderer.BufferManager.CreateWithHandle(_renderer, rangeSize); + using var buffer = _renderer.BufferManager.ReserveOrCreate(_renderer, cbs, rangeSize); - _renderer.BufferManager.SetData(bufferHandle, 0, resolutionBuffer); - var bufferRanges = new BufferRange(bufferHandle, 0, rangeSize); - _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, bufferRanges) }); + buffer.Holder.SetDataUnchecked(buffer.Offset, resolutionBuffer); + _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(2, buffer.Range) }); _pipeline.SetImage(0, _edgeOutputTexture, FormatTable.ConvertRgba8SrgbToUnorm(view.Info.Format)); _pipeline.DispatchCompute(dispatchX, dispatchY, 1); _pipeline.ComputeBarrier(); @@ -245,8 +244,6 @@ namespace Ryujinx.Graphics.Vulkan.Effects _pipeline.Finish(); - _renderer.BufferManager.Delete(bufferHandle); - return _outputTexture; } @@ -260,7 +257,7 @@ namespace Ryujinx.Graphics.Vulkan.Effects scissors[0] = new Rectangle(0, 0, texture.Width, texture.Height); - _pipeline.SetRenderTarget(texture.GetImageViewForAttachment(), (uint)texture.Width, (uint)texture.Height, false, texture.VkFormat); + _pipeline.SetRenderTarget(texture, (uint)texture.Width, (uint)texture.Height); _pipeline.SetRenderTargetColorMasks(colorMasks); _pipeline.SetScissors(scissors); _pipeline.ClearRenderTargetColor(0, 0, 1, new ColorF(0f, 0f, 0f, 1f)); diff --git a/src/Ryujinx.Graphics.Vulkan/FormatTable.cs b/src/Ryujinx.Graphics.Vulkan/FormatTable.cs index 5f767df16..596a665fc 100644 --- a/src/Ryujinx.Graphics.Vulkan/FormatTable.cs +++ b/src/Ryujinx.Graphics.Vulkan/FormatTable.cs @@ -1,5 +1,6 @@ using Ryujinx.Graphics.GAL; using System; +using System.Collections.Generic; using VkFormat = Silk.NET.Vulkan.Format; namespace Ryujinx.Graphics.Vulkan @@ -7,10 +8,12 @@ namespace Ryujinx.Graphics.Vulkan static class FormatTable { private static readonly VkFormat[] _table; + private static readonly Dictionary _reverseMap; static FormatTable() { _table = new VkFormat[Enum.GetNames(typeof(Format)).Length]; + _reverseMap = new Dictionary(); #pragma warning disable IDE0055 // Disable formatting Add(Format.R8Unorm, VkFormat.R8Unorm); @@ -158,12 +161,14 @@ namespace Ryujinx.Graphics.Vulkan Add(Format.A1B5G5R5Unorm, VkFormat.R5G5B5A1UnormPack16); Add(Format.B8G8R8A8Unorm, VkFormat.B8G8R8A8Unorm); Add(Format.B8G8R8A8Srgb, VkFormat.B8G8R8A8Srgb); + Add(Format.B10G10R10A2Unorm, VkFormat.A2R10G10B10UnormPack32); #pragma warning restore IDE0055 } private static void Add(Format format, VkFormat vkFormat) { _table[(int)format] = vkFormat; + _reverseMap[vkFormat] = format; } public static VkFormat GetFormat(Format format) @@ -171,6 +176,16 @@ namespace Ryujinx.Graphics.Vulkan return _table[(int)format]; } + public static Format GetFormat(VkFormat format) + { + if (!_reverseMap.TryGetValue(format, out Format result)) + { + return Format.B8G8R8A8Unorm; + } + + return result; + } + public static Format ConvertRgba8SrgbToUnorm(Format format) { return format switch diff --git a/src/Ryujinx.Graphics.Vulkan/FramebufferParams.cs b/src/Ryujinx.Graphics.Vulkan/FramebufferParams.cs index 458a16464..af22f2656 100644 --- a/src/Ryujinx.Graphics.Vulkan/FramebufferParams.cs +++ b/src/Ryujinx.Graphics.Vulkan/FramebufferParams.cs @@ -12,6 +12,8 @@ namespace Ryujinx.Graphics.Vulkan private readonly Auto[] _attachments; private readonly TextureView[] _colors; private readonly TextureView _depthStencil; + private readonly TextureView[] _colorsCanonical; + private readonly TextureView _baseAttachment; private readonly uint _validColorAttachments; public uint Width { get; } @@ -28,25 +30,31 @@ namespace Ryujinx.Graphics.Vulkan public bool HasDepthStencil { get; } public int ColorAttachmentsCount => AttachmentsCount - (HasDepthStencil ? 1 : 0); - public FramebufferParams( - Device device, - Auto view, - uint width, - uint height, - uint samples, - bool isDepthStencil, - VkFormat format) + public FramebufferParams(Device device, TextureView view, uint width, uint height) { + bool isDepthStencil = view.Info.Format.IsDepthOrStencil(); + _device = device; - _attachments = new[] { view }; + _attachments = new[] { view.GetImageViewForAttachment() }; _validColorAttachments = isDepthStencil ? 0u : 1u; + _baseAttachment = view; + + if (isDepthStencil) + { + _depthStencil = view; + } + else + { + _colors = new TextureView[] { view }; + _colorsCanonical = _colors; + } Width = width; Height = height; Layers = 1; - AttachmentSamples = new[] { samples }; - AttachmentFormats = new[] { format }; + AttachmentSamples = new[] { (uint)view.Info.Samples }; + AttachmentFormats = new[] { view.VkFormat }; AttachmentIndices = isDepthStencil ? Array.Empty() : new[] { 0 }; AttachmentsCount = 1; @@ -64,6 +72,7 @@ namespace Ryujinx.Graphics.Vulkan _attachments = new Auto[count]; _colors = new TextureView[colorsCount]; + _colorsCanonical = colors.Select(color => color is TextureView view && view.Valid ? view : null).ToArray(); AttachmentSamples = new uint[count]; AttachmentFormats = new VkFormat[count]; @@ -86,6 +95,7 @@ namespace Ryujinx.Graphics.Vulkan _attachments[index] = texture.GetImageViewForAttachment(); _colors[index] = texture; _validColorAttachments |= 1u << bindIndex; + _baseAttachment = texture; AttachmentSamples[index] = (uint)texture.Info.Samples; AttachmentFormats[index] = texture.VkFormat; @@ -115,6 +125,7 @@ namespace Ryujinx.Graphics.Vulkan { _attachments[count - 1] = dsTexture.GetImageViewForAttachment(); _depthStencil = dsTexture; + _baseAttachment ??= dsTexture; AttachmentSamples[count - 1] = (uint)dsTexture.Info.Samples; AttachmentFormats[count - 1] = dsTexture.VkFormat; @@ -251,19 +262,11 @@ namespace Ryujinx.Graphics.Vulkan public void InsertClearBarrier(CommandBufferScoped cbs, int index) { - if (_colors != null) - { - int realIndex = Array.IndexOf(AttachmentIndices, index); - - if (realIndex != -1) - { - _colors[realIndex].Storage?.InsertReadToWriteBarrier( - cbs, - AccessFlags.ColorAttachmentWriteBit, - PipelineStageFlags.ColorAttachmentOutputBit, - insideRenderPass: true); - } - } + _colorsCanonical?[index]?.Storage?.InsertReadToWriteBarrier( + cbs, + AccessFlags.ColorAttachmentWriteBit, + PipelineStageFlags.ColorAttachmentOutputBit, + insideRenderPass: true); } public void InsertClearBarrierDS(CommandBufferScoped cbs) @@ -274,5 +277,61 @@ namespace Ryujinx.Graphics.Vulkan PipelineStageFlags.LateFragmentTestsBit, insideRenderPass: true); } + + public TextureView[] GetAttachmentViews() + { + var result = new TextureView[_attachments.Length]; + + _colors?.CopyTo(result, 0); + + if (_depthStencil != null) + { + result[^1] = _depthStencil; + } + + return result; + } + + public RenderPassCacheKey GetRenderPassCacheKey() + { + return new RenderPassCacheKey(_depthStencil, _colorsCanonical); + } + + public void InsertLoadOpBarriers(CommandBufferScoped cbs) + { + if (_colors != null) + { + foreach (var color in _colors) + { + // If Clear or DontCare were used, this would need to be write bit. + color.Storage?.InsertWriteToReadBarrier(cbs, AccessFlags.ColorAttachmentReadBit, PipelineStageFlags.ColorAttachmentOutputBit); + color.Storage?.SetModification(AccessFlags.ColorAttachmentWriteBit, PipelineStageFlags.ColorAttachmentOutputBit); + } + } + + if (_depthStencil != null) + { + _depthStencil.Storage?.InsertWriteToReadBarrier(cbs, AccessFlags.DepthStencilAttachmentReadBit, PipelineStageFlags.EarlyFragmentTestsBit); + _depthStencil.Storage?.SetModification(AccessFlags.DepthStencilAttachmentWriteBit, PipelineStageFlags.LateFragmentTestsBit); + } + } + + public (Auto renderPass, Auto framebuffer) GetPassAndFramebuffer( + VulkanRenderer gd, + Device device, + CommandBufferScoped cbs) + { + return _baseAttachment.GetPassAndFramebuffer(gd, device, cbs, this); + } + + public TextureView GetColorView(int index) + { + return _colorsCanonical[index]; + } + + public TextureView GetDepthStencilView() + { + return _depthStencil; + } } } diff --git a/src/Ryujinx.Graphics.Vulkan/HashTableSlim.cs b/src/Ryujinx.Graphics.Vulkan/HashTableSlim.cs index ff4eb7890..3796e3c52 100644 --- a/src/Ryujinx.Graphics.Vulkan/HashTableSlim.cs +++ b/src/Ryujinx.Graphics.Vulkan/HashTableSlim.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Runtime.CompilerServices; namespace Ryujinx.Graphics.Vulkan { @@ -20,20 +21,29 @@ namespace Ryujinx.Graphics.Vulkan public TValue Value; } - private readonly Entry[][] _hashTable = new Entry[TotalBuckets][]; + private struct Bucket + { + public int Length; + public Entry[] Entries; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Span AsSpan() + { + return Entries == null ? Span.Empty : Entries.AsSpan(0, Length); + } + } + + private readonly Bucket[] _hashTable = new Bucket[TotalBuckets]; public IEnumerable Keys { get { - foreach (Entry[] bucket in _hashTable) + foreach (Bucket bucket in _hashTable) { - if (bucket != null) + for (int i = 0; i < bucket.Length; i++) { - foreach (Entry entry in bucket) - { - yield return entry.Key; - } + yield return bucket.Entries[i].Key; } } } @@ -43,14 +53,11 @@ namespace Ryujinx.Graphics.Vulkan { get { - foreach (Entry[] bucket in _hashTable) + foreach (Bucket bucket in _hashTable) { - if (bucket != null) + for (int i = 0; i < bucket.Length; i++) { - foreach (Entry entry in bucket) - { - yield return entry.Value; - } + yield return bucket.Entries[i].Value; } } } @@ -68,40 +75,64 @@ namespace Ryujinx.Graphics.Vulkan int hashCode = key.GetHashCode(); int bucketIndex = hashCode & TotalBucketsMask; - var bucket = _hashTable[bucketIndex]; - if (bucket != null) + ref var bucket = ref _hashTable[bucketIndex]; + if (bucket.Entries != null) { int index = bucket.Length; - Array.Resize(ref _hashTable[bucketIndex], index + 1); + if (index >= bucket.Entries.Length) + { + Array.Resize(ref bucket.Entries, index + 1); + } - _hashTable[bucketIndex][index] = entry; + bucket.Entries[index] = entry; } else { - _hashTable[bucketIndex] = new[] + bucket.Entries = new[] { entry, }; } + + bucket.Length++; + } + + public bool Remove(ref TKey key) + { + int hashCode = key.GetHashCode(); + + ref var bucket = ref _hashTable[hashCode & TotalBucketsMask]; + var entries = bucket.AsSpan(); + for (int i = 0; i < entries.Length; i++) + { + ref var entry = ref entries[i]; + + if (entry.Hash == hashCode && entry.Key.Equals(ref key)) + { + entries[(i + 1)..].CopyTo(entries[i..]); + bucket.Length--; + + return true; + } + } + + return false; } public bool TryGetValue(ref TKey key, out TValue value) { int hashCode = key.GetHashCode(); - var bucket = _hashTable[hashCode & TotalBucketsMask]; - if (bucket != null) + var entries = _hashTable[hashCode & TotalBucketsMask].AsSpan(); + for (int i = 0; i < entries.Length; i++) { - for (int i = 0; i < bucket.Length; i++) - { - ref var entry = ref bucket[i]; + ref var entry = ref entries[i]; - if (entry.Hash == hashCode && entry.Key.Equals(ref key)) - { - value = entry.Value; - return true; - } + if (entry.Hash == hashCode && entry.Key.Equals(ref key)) + { + value = entry.Value; + return true; } } diff --git a/src/Ryujinx.Graphics.Vulkan/HelperShader.cs b/src/Ryujinx.Graphics.Vulkan/HelperShader.cs index deaf81625..c0ded5b3b 100644 --- a/src/Ryujinx.Graphics.Vulkan/HelperShader.cs +++ b/src/Ryujinx.Graphics.Vulkan/HelperShader.cs @@ -256,17 +256,8 @@ namespace Ryujinx.Graphics.Vulkan using var cbs = gd.CommandBufferPool.Rent(); - var dstFormat = dst.VkFormat; - var dstSamples = dst.Info.Samples; - for (int l = 0; l < levels; l++) { - int srcWidth = Math.Max(1, src.Width >> l); - int srcHeight = Math.Max(1, src.Height >> l); - - int dstWidth = Math.Max(1, dst.Width >> l); - int dstHeight = Math.Max(1, dst.Height >> l); - var mipSrcRegion = new Extents2D( srcRegion.X1 >> l, srcRegion.Y1 >> l, @@ -290,11 +281,7 @@ namespace Ryujinx.Graphics.Vulkan gd, cbs, srcView, - dst.GetImageViewForAttachment(), - dstWidth, - dstHeight, - dstSamples, - dstFormat, + dstView, mipSrcRegion, mipDstRegion); } @@ -304,12 +291,7 @@ namespace Ryujinx.Graphics.Vulkan gd, cbs, srcView, - dst.GetImageViewForAttachment(), - dstWidth, - dstHeight, - dstSamples, - dstFormat, - false, + dstView, mipSrcRegion, mipDstRegion, linearFilter, @@ -367,12 +349,7 @@ namespace Ryujinx.Graphics.Vulkan gd, cbs, srcView, - dstView.GetImageViewForAttachment(), - dstView.Width, - dstView.Height, - dstView.Info.Samples, - dstView.VkFormat, - dstView.Info.Format.IsDepthOrStencil(), + dstView, extents, extents, false); @@ -394,12 +371,7 @@ namespace Ryujinx.Graphics.Vulkan VulkanRenderer gd, CommandBufferScoped cbs, TextureView src, - Auto dst, - int dstWidth, - int dstHeight, - int dstSamples, - VkFormat dstFormat, - bool dstIsDepthOrStencil, + TextureView dst, Extents2D srcRegion, Extents2D dstRegion, bool linearFilter, @@ -430,11 +402,11 @@ namespace Ryujinx.Graphics.Vulkan (region[2], region[3]) = (region[3], region[2]); } - var bufferHandle = gd.BufferManager.CreateWithHandle(gd, RegionBufferSize); + using var buffer = gd.BufferManager.ReserveOrCreate(gd, cbs, RegionBufferSize); - gd.BufferManager.SetData(bufferHandle, 0, region); + buffer.Holder.SetDataUnchecked(buffer.Offset, region); - _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(1, new BufferRange(bufferHandle, 0, RegionBufferSize)) }); + _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(1, buffer.Range) }); Span viewports = stackalloc Viewport[1]; @@ -453,6 +425,8 @@ namespace Ryujinx.Graphics.Vulkan 0f, 1f); + bool dstIsDepthOrStencil = dst.Info.Format.IsDepthOrStencil(); + if (dstIsDepthOrStencil) { _pipeline.SetProgram(src.Info.Target.IsMultisample() ? _programDepthBlitMs : _programDepthBlit); @@ -471,7 +445,10 @@ namespace Ryujinx.Graphics.Vulkan _pipeline.SetProgram(_programColorBlit); } - _pipeline.SetRenderTarget(dst, (uint)dstWidth, (uint)dstHeight, (uint)dstSamples, dstIsDepthOrStencil, dstFormat); + int dstWidth = dst.Width; + int dstHeight = dst.Height; + + _pipeline.SetRenderTarget(dst, (uint)dstWidth, (uint)dstHeight); _pipeline.SetRenderTargetColorMasks(new uint[] { 0xf }); _pipeline.SetScissors(stackalloc Rectangle[] { new Rectangle(0, 0, dstWidth, dstHeight) }); @@ -490,19 +467,13 @@ namespace Ryujinx.Graphics.Vulkan } _pipeline.Finish(gd, cbs); - - gd.BufferManager.Delete(bufferHandle); } private void BlitDepthStencil( VulkanRenderer gd, CommandBufferScoped cbs, TextureView src, - Auto dst, - int dstWidth, - int dstHeight, - int dstSamples, - VkFormat dstFormat, + TextureView dst, Extents2D srcRegion, Extents2D dstRegion) { @@ -527,11 +498,11 @@ namespace Ryujinx.Graphics.Vulkan (region[2], region[3]) = (region[3], region[2]); } - var bufferHandle = gd.BufferManager.CreateWithHandle(gd, RegionBufferSize); + using var buffer = gd.BufferManager.ReserveOrCreate(gd, cbs, RegionBufferSize); - gd.BufferManager.SetData(bufferHandle, 0, region); + buffer.Holder.SetDataUnchecked(buffer.Offset, region); - _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(1, new BufferRange(bufferHandle, 0, RegionBufferSize)) }); + _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(1, buffer.Range) }); Span viewports = stackalloc Viewport[1]; @@ -550,7 +521,10 @@ namespace Ryujinx.Graphics.Vulkan 0f, 1f); - _pipeline.SetRenderTarget(dst, (uint)dstWidth, (uint)dstHeight, (uint)dstSamples, true, dstFormat); + int dstWidth = dst.Width; + int dstHeight = dst.Height; + + _pipeline.SetRenderTarget(dst, (uint)dstWidth, (uint)dstHeight); _pipeline.SetScissors(stackalloc Rectangle[] { new Rectangle(0, 0, dstWidth, dstHeight) }); _pipeline.SetViewports(viewports); _pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip); @@ -582,8 +556,6 @@ namespace Ryujinx.Graphics.Vulkan } _pipeline.Finish(gd, cbs); - - gd.BufferManager.Delete(bufferHandle); } private static TextureView CreateDepthOrStencilView(TextureView depthStencilTexture, DepthStencilMode depthStencilMode) @@ -664,12 +636,11 @@ namespace Ryujinx.Graphics.Vulkan public void Clear( VulkanRenderer gd, - Auto dst, + TextureView dst, ReadOnlySpan clearColor, uint componentMask, int dstWidth, int dstHeight, - VkFormat dstFormat, ComponentType type, Rectangle scissor) { @@ -681,11 +652,11 @@ namespace Ryujinx.Graphics.Vulkan _pipeline.SetCommandBuffer(cbs); - var bufferHandle = gd.BufferManager.CreateWithHandle(gd, ClearColorBufferSize); + using var buffer = gd.BufferManager.ReserveOrCreate(gd, cbs, ClearColorBufferSize); - gd.BufferManager.SetData(bufferHandle, 0, clearColor); + buffer.Holder.SetDataUnchecked(buffer.Offset, clearColor); - _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(1, new BufferRange(bufferHandle, 0, ClearColorBufferSize)) }); + _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(1, buffer.Range) }); Span viewports = stackalloc Viewport[1]; @@ -714,20 +685,18 @@ namespace Ryujinx.Graphics.Vulkan } _pipeline.SetProgram(program); - _pipeline.SetRenderTarget(dst, (uint)dstWidth, (uint)dstHeight, false, dstFormat); + _pipeline.SetRenderTarget(dst, (uint)dstWidth, (uint)dstHeight); _pipeline.SetRenderTargetColorMasks(new[] { componentMask }); _pipeline.SetViewports(viewports); _pipeline.SetScissors(stackalloc Rectangle[] { scissor }); _pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip); _pipeline.Draw(4, 1, 0, 0); _pipeline.Finish(); - - gd.BufferManager.Delete(bufferHandle); } public void Clear( VulkanRenderer gd, - Auto dst, + TextureView dst, float depthValue, bool depthMask, int stencilValue, @@ -745,11 +714,11 @@ namespace Ryujinx.Graphics.Vulkan _pipeline.SetCommandBuffer(cbs); - var bufferHandle = gd.BufferManager.CreateWithHandle(gd, ClearColorBufferSize); + using var buffer = gd.BufferManager.ReserveOrCreate(gd, cbs, ClearColorBufferSize); - gd.BufferManager.SetData(bufferHandle, 0, stackalloc float[] { depthValue }); + buffer.Holder.SetDataUnchecked(buffer.Offset, stackalloc float[] { depthValue }); - _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(1, new BufferRange(bufferHandle, 0, ClearColorBufferSize)) }); + _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(1, buffer.Range) }); Span viewports = stackalloc Viewport[1]; @@ -763,7 +732,7 @@ namespace Ryujinx.Graphics.Vulkan 1f); _pipeline.SetProgram(_programDepthStencilClear); - _pipeline.SetRenderTarget(dst, (uint)dstWidth, (uint)dstHeight, true, dstFormat); + _pipeline.SetRenderTarget(dst, (uint)dstWidth, (uint)dstHeight); _pipeline.SetViewports(viewports); _pipeline.SetScissors(stackalloc Rectangle[] { scissor }); _pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip); @@ -771,8 +740,6 @@ namespace Ryujinx.Graphics.Vulkan _pipeline.SetStencilTest(CreateStencilTestDescriptor(stencilMask != 0, stencilValue, 0xff, stencilMask)); _pipeline.Draw(4, 1, 0, 0); _pipeline.Finish(); - - gd.BufferManager.Delete(bufferHandle); } public void DrawTexture( @@ -878,13 +845,13 @@ namespace Ryujinx.Graphics.Vulkan shaderParams[2] = size; shaderParams[3] = srcOffset; - var bufferHandle = gd.BufferManager.CreateWithHandle(gd, ParamsBufferSize); + using var buffer = gd.BufferManager.ReserveOrCreate(gd, cbs, ParamsBufferSize); - gd.BufferManager.SetData(bufferHandle, 0, shaderParams); + buffer.Holder.SetDataUnchecked(buffer.Offset, shaderParams); _pipeline.SetCommandBuffer(cbs); - _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, new BufferRange(bufferHandle, 0, ParamsBufferSize)) }); + _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, buffer.Range) }); Span> sbRanges = new Auto[2]; @@ -896,8 +863,6 @@ namespace Ryujinx.Graphics.Vulkan _pipeline.SetProgram(_programStrideChange); _pipeline.DispatchCompute(1 + elems / ConvertElementsPerWorkgroup, 1, 1); - gd.BufferManager.Delete(bufferHandle); - _pipeline.Finish(gd, cbs); } else @@ -1025,7 +990,7 @@ namespace Ryujinx.Graphics.Vulkan { const int ParamsBufferSize = 4; - Span shaderParams = stackalloc int[sizeof(int)]; + Span shaderParams = stackalloc int[ParamsBufferSize / sizeof(int)]; int srcBpp = src.Info.BytesPerPixel; int dstBpp = dst.Info.BytesPerPixel; @@ -1034,9 +999,9 @@ namespace Ryujinx.Graphics.Vulkan shaderParams[0] = BitOperations.Log2((uint)ratio); - var bufferHandle = gd.BufferManager.CreateWithHandle(gd, ParamsBufferSize); + using var buffer = gd.BufferManager.ReserveOrCreate(gd, cbs, ParamsBufferSize); - gd.BufferManager.SetData(bufferHandle, 0, shaderParams); + buffer.Holder.SetDataUnchecked(buffer.Offset, shaderParams); TextureView.InsertImageBarrier( gd.Api, @@ -1064,7 +1029,7 @@ namespace Ryujinx.Graphics.Vulkan var srcFormat = GetFormat(componentSize, srcBpp / componentSize); var dstFormat = GetFormat(componentSize, dstBpp / componentSize); - _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, new BufferRange(bufferHandle, 0, ParamsBufferSize)) }); + _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, buffer.Range) }); for (int l = 0; l < levels; l++) { @@ -1093,8 +1058,6 @@ namespace Ryujinx.Graphics.Vulkan } } - gd.BufferManager.Delete(bufferHandle); - _pipeline.Finish(gd, cbs); TextureView.InsertImageBarrier( @@ -1128,9 +1091,9 @@ namespace Ryujinx.Graphics.Vulkan (shaderParams[0], shaderParams[1]) = GetSampleCountXYLog2(samples); (shaderParams[2], shaderParams[3]) = GetSampleCountXYLog2((int)TextureStorage.ConvertToSampleCountFlags(gd.Capabilities.SupportedSampleCounts, (uint)samples)); - var bufferHandle = gd.BufferManager.CreateWithHandle(gd, ParamsBufferSize); + using var buffer = gd.BufferManager.ReserveOrCreate(gd, cbs, ParamsBufferSize); - gd.BufferManager.SetData(bufferHandle, 0, shaderParams); + buffer.Holder.SetDataUnchecked(buffer.Offset, shaderParams); TextureView.InsertImageBarrier( gd.Api, @@ -1147,7 +1110,7 @@ namespace Ryujinx.Graphics.Vulkan 1); _pipeline.SetCommandBuffer(cbs); - _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, new BufferRange(bufferHandle, 0, ParamsBufferSize)) }); + _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, buffer.Range) }); if (isDepthOrStencil) { @@ -1175,12 +1138,7 @@ namespace Ryujinx.Graphics.Vulkan var srcView = Create2DLayerView(src, srcLayer + z, 0); var dstView = Create2DLayerView(dst, dstLayer + z, 0); - _pipeline.SetRenderTarget( - dstView.GetImageViewForAttachment(), - (uint)dst.Width, - (uint)dst.Height, - true, - dst.VkFormat); + _pipeline.SetRenderTarget(dstView, (uint)dst.Width, (uint)dst.Height); CopyMSDraw(srcView, aspectFlags, fromMS: true); @@ -1226,8 +1184,6 @@ namespace Ryujinx.Graphics.Vulkan } } - gd.BufferManager.Delete(bufferHandle); - _pipeline.Finish(gd, cbs); TextureView.InsertImageBarrier( @@ -1261,9 +1217,9 @@ namespace Ryujinx.Graphics.Vulkan (shaderParams[0], shaderParams[1]) = GetSampleCountXYLog2(samples); (shaderParams[2], shaderParams[3]) = GetSampleCountXYLog2((int)TextureStorage.ConvertToSampleCountFlags(gd.Capabilities.SupportedSampleCounts, (uint)samples)); - var bufferHandle = gd.BufferManager.CreateWithHandle(gd, ParamsBufferSize); + using var buffer = gd.BufferManager.ReserveOrCreate(gd, cbs, ParamsBufferSize); - gd.BufferManager.SetData(bufferHandle, 0, shaderParams); + buffer.Holder.SetDataUnchecked(buffer.Offset, shaderParams); TextureView.InsertImageBarrier( gd.Api, @@ -1299,7 +1255,7 @@ namespace Ryujinx.Graphics.Vulkan _pipeline.SetViewports(viewports); _pipeline.SetPrimitiveTopology(PrimitiveTopology.TriangleStrip); - _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, new BufferRange(bufferHandle, 0, ParamsBufferSize)) }); + _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, buffer.Range) }); if (isDepthOrStencil) { @@ -1308,13 +1264,7 @@ namespace Ryujinx.Graphics.Vulkan var srcView = Create2DLayerView(src, srcLayer + z, 0); var dstView = Create2DLayerView(dst, dstLayer + z, 0); - _pipeline.SetRenderTarget( - dstView.GetImageViewForAttachment(), - (uint)dst.Width, - (uint)dst.Height, - (uint)samples, - true, - dst.VkFormat); + _pipeline.SetRenderTarget(dstView, (uint)dst.Width, (uint)dst.Height); CopyMSDraw(srcView, aspectFlags, fromMS: false); @@ -1342,13 +1292,7 @@ namespace Ryujinx.Graphics.Vulkan var dstView = Create2DLayerView(dst, dstLayer + z, 0); _pipeline.SetTextureAndSamplerIdentitySwizzle(ShaderStage.Fragment, 0, srcView, null); - _pipeline.SetRenderTarget( - dstView.GetView(format).GetImageViewForAttachment(), - (uint)dst.Width, - (uint)dst.Height, - (uint)samples, - false, - vkFormat); + _pipeline.SetRenderTarget(dstView.GetView(format), (uint)dst.Width, (uint)dst.Height); _pipeline.Draw(4, 1, 0, 0); @@ -1364,8 +1308,6 @@ namespace Ryujinx.Graphics.Vulkan } } - gd.BufferManager.Delete(bufferHandle); - _pipeline.Finish(gd, cbs); TextureView.InsertImageBarrier( @@ -1487,9 +1429,9 @@ namespace Ryujinx.Graphics.Vulkan }; var info = new TextureCreateInfo( - from.Info.Width, - from.Info.Height, - from.Info.Depth, + Math.Max(1, from.Info.Width >> level), + Math.Max(1, from.Info.Height >> level), + 1, 1, from.Info.Samples, from.Info.BlockWidth, @@ -1616,10 +1558,11 @@ namespace Ryujinx.Graphics.Vulkan pattern.OffsetIndex.CopyTo(shaderParams[..pattern.OffsetIndex.Length]); - var patternBufferHandle = gd.BufferManager.CreateWithHandle(gd, ParamsBufferSize, out var patternBuffer); + using var patternScoped = gd.BufferManager.ReserveOrCreate(gd, cbs, ParamsBufferSize); + var patternBuffer = patternScoped.Holder; var patternBufferAuto = patternBuffer.GetBuffer(); - gd.BufferManager.SetData(patternBufferHandle, 0, shaderParams); + patternBuffer.SetDataUnchecked(patternScoped.Offset, shaderParams); _pipeline.SetCommandBuffer(cbs); @@ -1635,7 +1578,8 @@ namespace Ryujinx.Graphics.Vulkan indirectDataSize); _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, drawCountBufferAligned) }); - _pipeline.SetStorageBuffers(1, new[] { srcIndirectBuffer.GetBuffer(), dstIndirectBuffer.GetBuffer(), patternBuffer.GetBuffer() }); + _pipeline.SetStorageBuffers(1, new[] { srcIndirectBuffer.GetBuffer(), dstIndirectBuffer.GetBuffer() }); + _pipeline.SetStorageBuffers(stackalloc[] { new BufferAssignment(3, patternScoped.Range) }); _pipeline.SetProgram(_programConvertIndirectData); _pipeline.DispatchCompute(1, 1, 1); @@ -1643,12 +1587,12 @@ namespace Ryujinx.Graphics.Vulkan BufferHolder.InsertBufferBarrier( gd, cbs.CommandBuffer, - patternBufferAuto.Get(cbs, ParamsIndirectDispatchOffset, ParamsIndirectDispatchSize).Value, + patternBufferAuto.Get(cbs, patternScoped.Offset + ParamsIndirectDispatchOffset, ParamsIndirectDispatchSize).Value, AccessFlags.ShaderWriteBit, AccessFlags.IndirectCommandReadBit, PipelineStageFlags.ComputeShaderBit, PipelineStageFlags.DrawIndirectBit, - ParamsIndirectDispatchOffset, + patternScoped.Offset + ParamsIndirectDispatchOffset, ParamsIndirectDispatchSize); BufferHolder.InsertBufferBarrier( @@ -1662,11 +1606,11 @@ namespace Ryujinx.Graphics.Vulkan 0, convertedCount * outputIndexSize); - _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, new BufferRange(patternBufferHandle, 0, ParamsBufferSize)) }); + _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, new BufferRange(patternScoped.Handle, patternScoped.Offset, ParamsBufferSize)) }); _pipeline.SetStorageBuffers(1, new[] { srcIndexBuffer.GetBuffer(), dstIndexBuffer.GetBuffer() }); _pipeline.SetProgram(_programConvertIndexBuffer); - _pipeline.DispatchComputeIndirect(patternBufferAuto, ParamsIndirectDispatchOffset); + _pipeline.DispatchComputeIndirect(patternBufferAuto, patternScoped.Offset + ParamsIndirectDispatchOffset); BufferHolder.InsertBufferBarrier( gd, @@ -1679,8 +1623,6 @@ namespace Ryujinx.Graphics.Vulkan 0, convertedCount * outputIndexSize); - gd.BufferManager.Delete(patternBufferHandle); - _pipeline.Finish(gd, cbs); } @@ -1726,13 +1668,13 @@ namespace Ryujinx.Graphics.Vulkan shaderParams[0] = pixelCount; shaderParams[1] = dstOffset; - var bufferHandle = gd.BufferManager.CreateWithHandle(gd, ParamsBufferSize); + using var buffer = gd.BufferManager.ReserveOrCreate(gd, cbs, ParamsBufferSize); - gd.BufferManager.SetData(bufferHandle, 0, shaderParams); + buffer.Holder.SetDataUnchecked(buffer.Offset, shaderParams); _pipeline.SetCommandBuffer(cbs); - _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, new BufferRange(bufferHandle, 0, ParamsBufferSize)) }); + _pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, buffer.Range) }); Span> sbRanges = new Auto[2]; @@ -1744,8 +1686,6 @@ namespace Ryujinx.Graphics.Vulkan _pipeline.SetProgram(_programConvertD32S8ToD24S8); _pipeline.DispatchCompute(1 + inSize / ConvertElementsPerWorkgroup, 1, 1); - gd.BufferManager.Delete(bufferHandle); - _pipeline.Finish(gd, cbs); BufferHolder.InsertBufferBarrier( diff --git a/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs b/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs index 28d05a526..3aef1317a 100644 --- a/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs +++ b/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs @@ -30,10 +30,12 @@ namespace Ryujinx.Graphics.Vulkan public readonly PipelineCache PipelineCache; public readonly AutoFlushCounter AutoFlush; + public readonly Action EndRenderPassDelegate; protected PipelineDynamicState DynamicState; private PipelineState _newState; - private bool _stateDirty; + private bool _graphicsStateDirty; + private bool _computeStateDirty; private PrimitiveTopology _topology; private ulong _currentPipelineHandle; @@ -53,6 +55,7 @@ namespace Ryujinx.Graphics.Vulkan protected FramebufferParams FramebufferParams; private Auto _framebuffer; private Auto _renderPass; + private RenderPassHolder _nullRenderPass; private int _writtenAttachmentCount; private bool _framebufferUsingColorWriteMask; @@ -92,6 +95,7 @@ namespace Ryujinx.Graphics.Vulkan Device = device; AutoFlush = new AutoFlushCounter(gd); + EndRenderPassDelegate = EndRenderPass; var pipelineCacheCreateInfo = new PipelineCacheCreateInfo { @@ -100,7 +104,7 @@ namespace Ryujinx.Graphics.Vulkan gd.Api.CreatePipelineCache(device, pipelineCacheCreateInfo, null, out PipelineCache).ThrowOnError(); - _descriptorSetUpdater = new DescriptorSetUpdater(gd, this); + _descriptorSetUpdater = new DescriptorSetUpdater(gd, device, this); _vertexBufferUpdater = new VertexBufferUpdater(gd); _transformFeedbackBuffers = new BufferState[Constants.MaxTransformFeedbackBuffers]; @@ -351,7 +355,7 @@ namespace Ryujinx.Graphics.Vulkan } EndRenderPass(); - RecreatePipelineIfNeeded(PipelineBindPoint.Compute); + RecreateComputePipelineIfNeeded(); Gd.Api.CmdDispatch(CommandBuffer, (uint)groupsX, (uint)groupsY, (uint)groupsZ); } @@ -364,19 +368,23 @@ namespace Ryujinx.Graphics.Vulkan } EndRenderPass(); - RecreatePipelineIfNeeded(PipelineBindPoint.Compute); + RecreateComputePipelineIfNeeded(); Gd.Api.CmdDispatchIndirect(CommandBuffer, indirectBuffer.Get(Cbs, indirectBufferOffset, 12).Value, (ulong)indirectBufferOffset); } public void Draw(int vertexCount, int instanceCount, int firstVertex, int firstInstance) { - if (!_program.IsLinked || vertexCount == 0) + if (vertexCount == 0) + { + return; + } + + if (!RecreateGraphicsPipelineIfNeeded()) { return; } - RecreatePipelineIfNeeded(PipelineBindPoint.Graphics); BeginRenderPass(); DrawCount++; @@ -435,13 +443,18 @@ namespace Ryujinx.Graphics.Vulkan public void DrawIndexed(int indexCount, int instanceCount, int firstIndex, int firstVertex, int firstInstance) { - if (!_program.IsLinked || indexCount == 0) + if (indexCount == 0) { return; } UpdateIndexBufferPattern(); - RecreatePipelineIfNeeded(PipelineBindPoint.Graphics); + + if (!RecreateGraphicsPipelineIfNeeded()) + { + return; + } + BeginRenderPass(); DrawCount++; @@ -474,17 +487,17 @@ namespace Ryujinx.Graphics.Vulkan public void DrawIndexedIndirect(BufferRange indirectBuffer) { - if (!_program.IsLinked) - { - return; - } - var buffer = Gd.BufferManager .GetBuffer(CommandBuffer, indirectBuffer.Handle, indirectBuffer.Offset, indirectBuffer.Size, false) .Get(Cbs, indirectBuffer.Offset, indirectBuffer.Size).Value; UpdateIndexBufferPattern(); - RecreatePipelineIfNeeded(PipelineBindPoint.Graphics); + + if (!RecreateGraphicsPipelineIfNeeded()) + { + return; + } + BeginRenderPass(); DrawCount++; @@ -520,11 +533,6 @@ namespace Ryujinx.Graphics.Vulkan public void DrawIndexedIndirectCount(BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride) { - if (!_program.IsLinked) - { - return; - } - var countBuffer = Gd.BufferManager .GetBuffer(CommandBuffer, parameterBuffer.Handle, parameterBuffer.Offset, parameterBuffer.Size, false) .Get(Cbs, parameterBuffer.Offset, parameterBuffer.Size).Value; @@ -534,7 +542,12 @@ namespace Ryujinx.Graphics.Vulkan .Get(Cbs, indirectBuffer.Offset, indirectBuffer.Size).Value; UpdateIndexBufferPattern(); - RecreatePipelineIfNeeded(PipelineBindPoint.Graphics); + + if (!RecreateGraphicsPipelineIfNeeded()) + { + return; + } + BeginRenderPass(); DrawCount++; @@ -612,18 +625,17 @@ namespace Ryujinx.Graphics.Vulkan public void DrawIndirect(BufferRange indirectBuffer) { - if (!_program.IsLinked) - { - return; - } - // TODO: Support quads and other unsupported topologies. var buffer = Gd.BufferManager .GetBuffer(CommandBuffer, indirectBuffer.Handle, indirectBuffer.Offset, indirectBuffer.Size, false) .Get(Cbs, indirectBuffer.Offset, indirectBuffer.Size, false).Value; - RecreatePipelineIfNeeded(PipelineBindPoint.Graphics); + if (!RecreateGraphicsPipelineIfNeeded()) + { + return; + } + BeginRenderPass(); ResumeTransformFeedbackInternal(); DrawCount++; @@ -639,11 +651,6 @@ namespace Ryujinx.Graphics.Vulkan throw new NotSupportedException(); } - if (!_program.IsLinked) - { - return; - } - var buffer = Gd.BufferManager .GetBuffer(CommandBuffer, indirectBuffer.Handle, indirectBuffer.Offset, indirectBuffer.Size, false) .Get(Cbs, indirectBuffer.Offset, indirectBuffer.Size, false).Value; @@ -654,7 +661,11 @@ namespace Ryujinx.Graphics.Vulkan // TODO: Support quads and other unsupported topologies. - RecreatePipelineIfNeeded(PipelineBindPoint.Graphics); + if (!RecreateGraphicsPipelineIfNeeded()) + { + return; + } + BeginRenderPass(); ResumeTransformFeedbackInternal(); DrawCount++; @@ -1478,106 +1489,43 @@ namespace Ryujinx.Graphics.Vulkan protected unsafe void CreateRenderPass() { - const int MaxAttachments = Constants.MaxRenderTargets + 1; - - AttachmentDescription[] attachmentDescs = null; - - var subpass = new SubpassDescription - { - PipelineBindPoint = PipelineBindPoint.Graphics, - }; - - AttachmentReference* attachmentReferences = stackalloc AttachmentReference[MaxAttachments]; - var hasFramebuffer = FramebufferParams != null; - if (hasFramebuffer && FramebufferParams.AttachmentsCount != 0) - { - attachmentDescs = new AttachmentDescription[FramebufferParams.AttachmentsCount]; - - for (int i = 0; i < FramebufferParams.AttachmentsCount; i++) - { - attachmentDescs[i] = new AttachmentDescription( - 0, - FramebufferParams.AttachmentFormats[i], - TextureStorage.ConvertToSampleCountFlags(Gd.Capabilities.SupportedSampleCounts, FramebufferParams.AttachmentSamples[i]), - AttachmentLoadOp.Load, - AttachmentStoreOp.Store, - AttachmentLoadOp.Load, - AttachmentStoreOp.Store, - ImageLayout.General, - ImageLayout.General); - } - - int colorAttachmentsCount = FramebufferParams.ColorAttachmentsCount; - - if (colorAttachmentsCount > MaxAttachments - 1) - { - colorAttachmentsCount = MaxAttachments - 1; - } - - if (colorAttachmentsCount != 0) - { - int maxAttachmentIndex = FramebufferParams.MaxColorAttachmentIndex; - subpass.ColorAttachmentCount = (uint)maxAttachmentIndex + 1; - subpass.PColorAttachments = &attachmentReferences[0]; - - // Fill with VK_ATTACHMENT_UNUSED to cover any gaps. - for (int i = 0; i <= maxAttachmentIndex; i++) - { - subpass.PColorAttachments[i] = new AttachmentReference(Vk.AttachmentUnused, ImageLayout.Undefined); - } - - for (int i = 0; i < colorAttachmentsCount; i++) - { - int bindIndex = FramebufferParams.AttachmentIndices[i]; - - subpass.PColorAttachments[bindIndex] = new AttachmentReference((uint)i, ImageLayout.General); - } - } - - if (FramebufferParams.HasDepthStencil) - { - uint dsIndex = (uint)FramebufferParams.AttachmentsCount - 1; - - subpass.PDepthStencilAttachment = &attachmentReferences[MaxAttachments - 1]; - *subpass.PDepthStencilAttachment = new AttachmentReference(dsIndex, ImageLayout.General); - } - } - - var subpassDependency = PipelineConverter.CreateSubpassDependency(); - - fixed (AttachmentDescription* pAttachmentDescs = attachmentDescs) - { - var renderPassCreateInfo = new RenderPassCreateInfo - { - SType = StructureType.RenderPassCreateInfo, - PAttachments = pAttachmentDescs, - AttachmentCount = attachmentDescs != null ? (uint)attachmentDescs.Length : 0, - PSubpasses = &subpass, - SubpassCount = 1, - PDependencies = &subpassDependency, - DependencyCount = 1, - }; - - Gd.Api.CreateRenderPass(Device, renderPassCreateInfo, null, out var renderPass).ThrowOnError(); - - _renderPass?.Dispose(); - _renderPass = new Auto(new DisposableRenderPass(Gd.Api, Device, renderPass)); - } - EndRenderPass(); - _framebuffer?.Dispose(); - _framebuffer = hasFramebuffer ? FramebufferParams.Create(Gd.Api, Cbs, _renderPass) : null; + if (!hasFramebuffer || FramebufferParams.AttachmentsCount == 0) + { + // Use the null framebuffer. + _nullRenderPass ??= new RenderPassHolder(Gd, Device, new RenderPassCacheKey(), FramebufferParams); + + _renderPass = _nullRenderPass.GetRenderPass(); + _framebuffer = _nullRenderPass.GetFramebuffer(Gd, Cbs, FramebufferParams); + } + else + { + (_renderPass, _framebuffer) = FramebufferParams.GetPassAndFramebuffer(Gd, Device, Cbs); + } } protected void SignalStateChange() { - _stateDirty = true; + _graphicsStateDirty = true; + _computeStateDirty = true; } - private void RecreatePipelineIfNeeded(PipelineBindPoint pbp) + private void RecreateComputePipelineIfNeeded() + { + if (_computeStateDirty || Pbp != PipelineBindPoint.Compute) + { + CreatePipeline(PipelineBindPoint.Compute); + _computeStateDirty = false; + Pbp = PipelineBindPoint.Compute; + } + + _descriptorSetUpdater.UpdateAndBindDescriptorSets(Cbs, PipelineBindPoint.Compute); + } + + private bool RecreateGraphicsPipelineIfNeeded() { if (AutoFlush.ShouldFlushDraw(DrawCount)) { @@ -1618,17 +1566,23 @@ namespace Ryujinx.Graphics.Vulkan _vertexBufferUpdater.Commit(Cbs); } - if (_stateDirty || Pbp != pbp) + if (_graphicsStateDirty || Pbp != PipelineBindPoint.Graphics) { - CreatePipeline(pbp); - _stateDirty = false; - Pbp = pbp; + if (!CreatePipeline(PipelineBindPoint.Graphics)) + { + return false; + } + + _graphicsStateDirty = false; + Pbp = PipelineBindPoint.Graphics; } - _descriptorSetUpdater.UpdateAndBindDescriptorSets(Cbs, pbp); + _descriptorSetUpdater.UpdateAndBindDescriptorSets(Cbs, PipelineBindPoint.Graphics); + + return true; } - private void CreatePipeline(PipelineBindPoint pbp) + private bool CreatePipeline(PipelineBindPoint pbp) { // We can only create a pipeline if the have the shader stages set. if (_newState.Stages != null) @@ -1638,10 +1592,25 @@ namespace Ryujinx.Graphics.Vulkan CreateRenderPass(); } + if (!_program.IsLinked) + { + // Background compile failed, we likely can't create the pipeline because the shader is broken + // or the driver failed to compile it. + + return false; + } + var pipeline = pbp == PipelineBindPoint.Compute ? _newState.CreateComputePipeline(Gd, Device, _program, PipelineCache) : _newState.CreateGraphicsPipeline(Gd, Device, _program, PipelineCache, _renderPass.Get(Cbs).Value); + if (pipeline == null) + { + // Host failed to create the pipeline, likely due to driver bugs. + + return false; + } + ulong pipelineHandle = pipeline.GetUnsafe().Value.Handle; if (_currentPipelineHandle != pipelineHandle) @@ -1653,6 +1622,8 @@ namespace Ryujinx.Graphics.Vulkan Gd.Api.CmdBindPipeline(CommandBuffer, pbp, Pipeline.Get(Cbs).Value); } } + + return true; } private unsafe void BeginRenderPass() @@ -1724,8 +1695,7 @@ namespace Ryujinx.Graphics.Vulkan { if (disposing) { - _renderPass?.Dispose(); - _framebuffer?.Dispose(); + _nullRenderPass?.Dispose(); _newState.Dispose(); _descriptorSetUpdater.Dispose(); _vertexBufferUpdater.Dispose(); diff --git a/src/Ryujinx.Graphics.Vulkan/PipelineFull.cs b/src/Ryujinx.Graphics.Vulkan/PipelineFull.cs index 24ca715fe..6c4419cd2 100644 --- a/src/Ryujinx.Graphics.Vulkan/PipelineFull.cs +++ b/src/Ryujinx.Graphics.Vulkan/PipelineFull.cs @@ -51,7 +51,7 @@ namespace Ryujinx.Graphics.Vulkan { // We can't use CmdClearAttachments if not writing all components, // because on Vulkan, the pipeline state does not affect clears. - var dstTexture = FramebufferParams.GetAttachment(index); + var dstTexture = FramebufferParams.GetColorView(index); if (dstTexture == null) { return; @@ -71,7 +71,6 @@ namespace Ryujinx.Graphics.Vulkan componentMask, (int)FramebufferParams.Width, (int)FramebufferParams.Height, - FramebufferParams.AttachmentFormats[index], FramebufferParams.GetAttachmentComponentType(index), ClearScissor); } @@ -92,7 +91,7 @@ namespace Ryujinx.Graphics.Vulkan { // We can't use CmdClearAttachments if not clearing all (mask is all ones, 0xFF) or none (mask is 0) of the stencil bits, // because on Vulkan, the pipeline state does not affect clears. - var dstTexture = FramebufferParams.GetDepthStencilAttachment(); + var dstTexture = FramebufferParams.GetDepthStencilView(); if (dstTexture == null) { return; @@ -246,7 +245,10 @@ namespace Ryujinx.Graphics.Vulkan SignalCommandBufferChange(); - DynamicState.ReplayIfDirty(Gd.Api, CommandBuffer); + if (Pipeline != null && Pbp == PipelineBindPoint.Graphics) + { + DynamicState.ReplayIfDirty(Gd.Api, CommandBuffer); + } } public void FlushCommandsImpl() diff --git a/src/Ryujinx.Graphics.Vulkan/PipelineHelperShader.cs b/src/Ryujinx.Graphics.Vulkan/PipelineHelperShader.cs index 0a871a5c8..dfbf19013 100644 --- a/src/Ryujinx.Graphics.Vulkan/PipelineHelperShader.cs +++ b/src/Ryujinx.Graphics.Vulkan/PipelineHelperShader.cs @@ -9,21 +9,16 @@ namespace Ryujinx.Graphics.Vulkan { } - public void SetRenderTarget(Auto view, uint width, uint height, bool isDepthStencil, VkFormat format) + public void SetRenderTarget(TextureView view, uint width, uint height) { - SetRenderTarget(view, width, height, 1u, isDepthStencil, format); - } - - public void SetRenderTarget(Auto view, uint width, uint height, uint samples, bool isDepthStencil, VkFormat format) - { - CreateFramebuffer(view, width, height, samples, isDepthStencil, format); + CreateFramebuffer(view, width, height); CreateRenderPass(); SignalStateChange(); } - private void CreateFramebuffer(Auto view, uint width, uint height, uint samples, bool isDepthStencil, VkFormat format) + private void CreateFramebuffer(TextureView view, uint width, uint height) { - FramebufferParams = new FramebufferParams(Device, view, width, height, samples, isDepthStencil, format); + FramebufferParams = new FramebufferParams(Device, view, width, height); UpdatePipelineAttachmentFormats(); } diff --git a/src/Ryujinx.Graphics.Vulkan/PipelineState.cs b/src/Ryujinx.Graphics.Vulkan/PipelineState.cs index 11f532510..25fd7168f 100644 --- a/src/Ryujinx.Graphics.Vulkan/PipelineState.cs +++ b/src/Ryujinx.Graphics.Vulkan/PipelineState.cs @@ -312,7 +312,6 @@ namespace Ryujinx.Graphics.Vulkan } public NativeArray Stages; - public NativeArray StageRequiredSubgroupSizes; public PipelineLayout PipelineLayout; public SpecData SpecializationData; @@ -321,16 +320,6 @@ namespace Ryujinx.Graphics.Vulkan public void Initialize() { Stages = new NativeArray(Constants.MaxShaderStages); - StageRequiredSubgroupSizes = new NativeArray(Constants.MaxShaderStages); - - for (int index = 0; index < Constants.MaxShaderStages; index++) - { - StageRequiredSubgroupSizes[index] = new PipelineShaderStageRequiredSubgroupSizeCreateInfoEXT - { - SType = StructureType.PipelineShaderStageRequiredSubgroupSizeCreateInfoExt, - RequiredSubgroupSize = RequiredSubgroupSize, - }; - } AdvancedBlendSrcPreMultiplied = true; AdvancedBlendDstPreMultiplied = true; @@ -397,7 +386,8 @@ namespace Ryujinx.Graphics.Vulkan Device device, ShaderCollection program, PipelineCache cache, - RenderPass renderPass) + RenderPass renderPass, + bool throwOnError = false) { if (program.TryGetGraphicsPipeline(ref Internal, out var pipeline)) { @@ -630,7 +620,18 @@ namespace Ryujinx.Graphics.Vulkan BasePipelineIndex = -1, }; - gd.Api.CreateGraphicsPipelines(device, cache, 1, &pipelineCreateInfo, null, &pipelineHandle).ThrowOnError(); + Result result = gd.Api.CreateGraphicsPipelines(device, cache, 1, &pipelineCreateInfo, null, &pipelineHandle); + + if (throwOnError) + { + result.ThrowOnError(); + } + else if (result.IsError()) + { + program.AddGraphicsPipeline(ref Internal, null); + + return null; + } // Restore previous blend enable values if we changed it. while (blendEnables != 0) @@ -708,7 +709,6 @@ namespace Ryujinx.Graphics.Vulkan public readonly void Dispose() { Stages.Dispose(); - StageRequiredSubgroupSizes.Dispose(); } } } diff --git a/src/Ryujinx.Graphics.Vulkan/Queries/CounterQueue.cs b/src/Ryujinx.Graphics.Vulkan/Queries/CounterQueue.cs index 3984e2826..0d133e50e 100644 --- a/src/Ryujinx.Graphics.Vulkan/Queries/CounterQueue.cs +++ b/src/Ryujinx.Graphics.Vulkan/Queries/CounterQueue.cs @@ -67,9 +67,18 @@ namespace Ryujinx.Graphics.Vulkan.Queries lock (_queryPool) { count = Math.Min(count, _queryPool.Count); - for (int i = 0; i < count; i++) + + if (count > 0) { - _queryPool.ElementAt(i).PoolReset(cmd, ResetSequence); + foreach (BufferedQuery query in _queryPool) + { + query.PoolReset(cmd, ResetSequence); + + if (--count == 0) + { + break; + } + } } } } diff --git a/src/Ryujinx.Graphics.Vulkan/RenderPassCacheKey.cs b/src/Ryujinx.Graphics.Vulkan/RenderPassCacheKey.cs new file mode 100644 index 000000000..7c57b8feb --- /dev/null +++ b/src/Ryujinx.Graphics.Vulkan/RenderPassCacheKey.cs @@ -0,0 +1,43 @@ +using System; +using System.Linq; + +namespace Ryujinx.Graphics.Vulkan +{ + internal readonly struct RenderPassCacheKey : IRefEquatable + { + private readonly TextureView _depthStencil; + private readonly TextureView[] _colors; + + public RenderPassCacheKey(TextureView depthStencil, TextureView[] colors) + { + _depthStencil = depthStencil; + _colors = colors; + } + + public override int GetHashCode() + { + HashCode hc = new(); + + hc.Add(_depthStencil); + + if (_colors != null) + { + foreach (var color in _colors) + { + hc.Add(color); + } + } + + return hc.ToHashCode(); + } + + public bool Equals(ref RenderPassCacheKey other) + { + bool colorsNull = _colors == null; + bool otherNull = other._colors == null; + return other._depthStencil == _depthStencil && + colorsNull == otherNull && + (colorsNull || other._colors.SequenceEqual(_colors)); + } + } +} diff --git a/src/Ryujinx.Graphics.Vulkan/RenderPassHolder.cs b/src/Ryujinx.Graphics.Vulkan/RenderPassHolder.cs new file mode 100644 index 000000000..3d883b2d5 --- /dev/null +++ b/src/Ryujinx.Graphics.Vulkan/RenderPassHolder.cs @@ -0,0 +1,180 @@ +using Silk.NET.Vulkan; +using System; + +namespace Ryujinx.Graphics.Vulkan +{ + internal class RenderPassHolder + { + private readonly struct FramebufferCacheKey : IRefEquatable + { + private readonly uint _width; + private readonly uint _height; + private readonly uint _layers; + + public FramebufferCacheKey(uint width, uint height, uint layers) + { + _width = width; + _height = height; + _layers = layers; + } + + public override int GetHashCode() + { + return HashCode.Combine(_width, _height, _layers); + } + + public bool Equals(ref FramebufferCacheKey other) + { + return other._width == _width && other._height == _height && other._layers == _layers; + } + } + + private readonly TextureView[] _textures; + private readonly Auto _renderPass; + private readonly HashTableSlim> _framebuffers; + private readonly RenderPassCacheKey _key; + + public unsafe RenderPassHolder(VulkanRenderer gd, Device device, RenderPassCacheKey key, FramebufferParams fb) + { + // Create render pass using framebuffer params. + + const int MaxAttachments = Constants.MaxRenderTargets + 1; + + AttachmentDescription[] attachmentDescs = null; + + var subpass = new SubpassDescription + { + PipelineBindPoint = PipelineBindPoint.Graphics, + }; + + AttachmentReference* attachmentReferences = stackalloc AttachmentReference[MaxAttachments]; + + var hasFramebuffer = fb != null; + + if (hasFramebuffer && fb.AttachmentsCount != 0) + { + attachmentDescs = new AttachmentDescription[fb.AttachmentsCount]; + + for (int i = 0; i < fb.AttachmentsCount; i++) + { + attachmentDescs[i] = new AttachmentDescription( + 0, + fb.AttachmentFormats[i], + TextureStorage.ConvertToSampleCountFlags(gd.Capabilities.SupportedSampleCounts, fb.AttachmentSamples[i]), + AttachmentLoadOp.Load, + AttachmentStoreOp.Store, + AttachmentLoadOp.Load, + AttachmentStoreOp.Store, + ImageLayout.General, + ImageLayout.General); + } + + int colorAttachmentsCount = fb.ColorAttachmentsCount; + + if (colorAttachmentsCount > MaxAttachments - 1) + { + colorAttachmentsCount = MaxAttachments - 1; + } + + if (colorAttachmentsCount != 0) + { + int maxAttachmentIndex = fb.MaxColorAttachmentIndex; + subpass.ColorAttachmentCount = (uint)maxAttachmentIndex + 1; + subpass.PColorAttachments = &attachmentReferences[0]; + + // Fill with VK_ATTACHMENT_UNUSED to cover any gaps. + for (int i = 0; i <= maxAttachmentIndex; i++) + { + subpass.PColorAttachments[i] = new AttachmentReference(Vk.AttachmentUnused, ImageLayout.Undefined); + } + + for (int i = 0; i < colorAttachmentsCount; i++) + { + int bindIndex = fb.AttachmentIndices[i]; + + subpass.PColorAttachments[bindIndex] = new AttachmentReference((uint)i, ImageLayout.General); + } + } + + if (fb.HasDepthStencil) + { + uint dsIndex = (uint)fb.AttachmentsCount - 1; + + subpass.PDepthStencilAttachment = &attachmentReferences[MaxAttachments - 1]; + *subpass.PDepthStencilAttachment = new AttachmentReference(dsIndex, ImageLayout.General); + } + } + + var subpassDependency = PipelineConverter.CreateSubpassDependency(); + + fixed (AttachmentDescription* pAttachmentDescs = attachmentDescs) + { + var renderPassCreateInfo = new RenderPassCreateInfo + { + SType = StructureType.RenderPassCreateInfo, + PAttachments = pAttachmentDescs, + AttachmentCount = attachmentDescs != null ? (uint)attachmentDescs.Length : 0, + PSubpasses = &subpass, + SubpassCount = 1, + PDependencies = &subpassDependency, + DependencyCount = 1, + }; + + gd.Api.CreateRenderPass(device, renderPassCreateInfo, null, out var renderPass).ThrowOnError(); + + _renderPass?.Dispose(); + _renderPass = new Auto(new DisposableRenderPass(gd.Api, device, renderPass)); + } + + _framebuffers = new HashTableSlim>(); + + // Register this render pass with all render target views. + + var textures = fb.GetAttachmentViews(); + + foreach (var texture in textures) + { + texture.AddRenderPass(key, this); + } + + _textures = textures; + _key = key; + } + + public Auto GetFramebuffer(VulkanRenderer gd, CommandBufferScoped cbs, FramebufferParams fb) + { + var key = new FramebufferCacheKey(fb.Width, fb.Height, fb.Layers); + + if (!_framebuffers.TryGetValue(ref key, out Auto result)) + { + result = fb.Create(gd.Api, cbs, _renderPass); + + _framebuffers.Add(ref key, result); + } + + return result; + } + + public Auto GetRenderPass() + { + return _renderPass; + } + + public void Dispose() + { + // Dispose all framebuffers + + foreach (var fb in _framebuffers.Values) + { + fb.Dispose(); + } + + // Notify all texture views that this render pass has been disposed. + + foreach (var texture in _textures) + { + texture.RemoveRenderPass(_key); + } + } + } +} diff --git a/src/Ryujinx.Graphics.Vulkan/ShaderCollection.cs b/src/Ryujinx.Graphics.Vulkan/ShaderCollection.cs index d01eebf3a..7c25c6d14 100644 --- a/src/Ryujinx.Graphics.Vulkan/ShaderCollection.cs +++ b/src/Ryujinx.Graphics.Vulkan/ShaderCollection.cs @@ -26,6 +26,7 @@ namespace Ryujinx.Graphics.Vulkan public ResourceBindingSegment[][] ClearSegments { get; } public ResourceBindingSegment[][] BindingSegments { get; } + public DescriptorSetTemplate[] Templates { get; } public ProgramLinkStatus LinkStatus { get; private set; } @@ -118,6 +119,7 @@ namespace Ryujinx.Graphics.Vulkan ClearSegments = BuildClearSegments(resourceLayout.Sets); BindingSegments = BuildBindingSegments(resourceLayout.SetUsages); + Templates = BuildTemplates(); _compileTask = Task.CompletedTask; _firstBackgroundUse = false; @@ -241,6 +243,23 @@ namespace Ryujinx.Graphics.Vulkan return segments; } + private DescriptorSetTemplate[] BuildTemplates() + { + var templates = new DescriptorSetTemplate[BindingSegments.Length]; + + for (int setIndex = 0; setIndex < BindingSegments.Length; setIndex++) + { + ResourceBindingSegment[] segments = BindingSegments[setIndex]; + + if (segments != null && segments.Length > 0) + { + templates[setIndex] = new DescriptorSetTemplate(_gd, _device, segments, _plce, IsCompute ? PipelineBindPoint.Compute : PipelineBindPoint.Graphics, setIndex); + } + } + + return templates; + } + private async Task BackgroundCompilation() { await Task.WhenAll(_shaders.Select(shader => shader.CompileTask)); @@ -355,7 +374,7 @@ namespace Ryujinx.Graphics.Vulkan pipeline.StagesCount = (uint)_shaders.Length; pipeline.PipelineLayout = PipelineLayout; - pipeline.CreateGraphicsPipeline(_gd, _device, this, (_gd.Pipeline as PipelineBase).PipelineCache, renderPass.Value); + pipeline.CreateGraphicsPipeline(_gd, _device, this, (_gd.Pipeline as PipelineBase).PipelineCache, renderPass.Value, throwOnError: true); pipeline.Dispose(); } @@ -492,7 +511,7 @@ namespace Ryujinx.Graphics.Vulkan { foreach (Auto pipeline in _graphicsPipelineCache.Values) { - pipeline.Dispose(); + pipeline?.Dispose(); } } @@ -504,6 +523,11 @@ namespace Ryujinx.Graphics.Vulkan } } + for (int i = 0; i < Templates.Length; i++) + { + Templates[i]?.Dispose(); + } + if (_dummyRenderPass.Value.Handle != 0) { _dummyRenderPass.Dispose(); diff --git a/src/Ryujinx.Graphics.Vulkan/StagingBuffer.cs b/src/Ryujinx.Graphics.Vulkan/StagingBuffer.cs index 3a02a28dc..90a47bb67 100644 --- a/src/Ryujinx.Graphics.Vulkan/StagingBuffer.cs +++ b/src/Ryujinx.Graphics.Vulkan/StagingBuffer.cs @@ -1,5 +1,6 @@ using Ryujinx.Common; using Ryujinx.Common.Logging; +using Ryujinx.Graphics.GAL; using System; using System.Collections.Generic; using System.Diagnostics; @@ -29,6 +30,9 @@ namespace Ryujinx.Graphics.Vulkan private readonly VulkanRenderer _gd; private readonly BufferHolder _buffer; + private readonly int _resourceAlignment; + + public readonly BufferHandle Handle; private readonly struct PendingCopy { @@ -48,9 +52,10 @@ namespace Ryujinx.Graphics.Vulkan public StagingBuffer(VulkanRenderer gd, BufferManager bufferManager) { _gd = gd; - _buffer = bufferManager.Create(gd, BufferSize); + Handle = bufferManager.CreateWithHandle(gd, BufferSize, out _buffer); _pendingCopies = new Queue(); _freeSize = BufferSize; + _resourceAlignment = (int)gd.Capabilities.MinResourceAlignment; } public void PushData(CommandBufferPool cbp, CommandBufferScoped? cbs, Action endRenderPass, BufferHolder dst, int dstOffset, ReadOnlySpan data) @@ -197,7 +202,7 @@ namespace Ryujinx.Graphics.Vulkan /// Reserve a range on the staging buffer for the current command buffer and upload data to it. /// /// Command buffer to reserve the data on - /// The data to upload + /// The minimum size the reserved data requires /// The required alignment for the buffer offset /// The reserved range of the staging buffer public unsafe StagingBufferReserved? TryReserveData(CommandBufferScoped cbs, int size, int alignment) @@ -223,6 +228,18 @@ namespace Ryujinx.Graphics.Vulkan return ReserveDataImpl(cbs, size, alignment); } + /// + /// Reserve a range on the staging buffer for the current command buffer and upload data to it. + /// Uses the most permissive byte alignment. + /// + /// Command buffer to reserve the data on + /// The minimum size the reserved data requires + /// The reserved range of the staging buffer + public unsafe StagingBufferReserved? TryReserveData(CommandBufferScoped cbs, int size) + { + return TryReserveData(cbs, size, _resourceAlignment); + } + private bool WaitFreeCompleted(CommandBufferPool cbp) { if (_pendingCopies.TryPeek(out var pc)) @@ -263,7 +280,7 @@ namespace Ryujinx.Graphics.Vulkan { if (disposing) { - _buffer.Dispose(); + _gd.BufferManager.Delete(Handle); while (_pendingCopies.TryDequeue(out var pc)) { diff --git a/src/Ryujinx.Graphics.Vulkan/TextureView.cs b/src/Ryujinx.Graphics.Vulkan/TextureView.cs index f5b80f948..ef511565c 100644 --- a/src/Ryujinx.Graphics.Vulkan/TextureView.cs +++ b/src/Ryujinx.Graphics.Vulkan/TextureView.cs @@ -3,6 +3,7 @@ using Ryujinx.Graphics.GAL; using Silk.NET.Vulkan; using System; using System.Collections.Generic; +using System.Linq; using Format = Ryujinx.Graphics.GAL.Format; using VkBuffer = Silk.NET.Vulkan.Buffer; using VkFormat = Silk.NET.Vulkan.Format; @@ -23,6 +24,8 @@ namespace Ryujinx.Graphics.Vulkan private readonly TextureCreateInfo _info; + private HashTableSlim _renderPasses; + public TextureCreateInfo Info => _info; public TextureStorage Storage { get; } @@ -158,6 +161,26 @@ namespace Ryujinx.Graphics.Vulkan Valid = true; } + /// + /// Create a texture view for an existing swapchain image view. + /// Does not set storage, so only appropriate for swapchain use. + /// + /// Do not use this for normal textures, and make sure uses do not try to read storage. + public TextureView(VulkanRenderer gd, Device device, DisposableImageView view, TextureCreateInfo info, VkFormat format) + { + _gd = gd; + _device = device; + + _imageView = new Auto(view); + _imageViewDraw = _imageView; + _imageViewIdentity = _imageView; + _info = info; + + VkFormat = format; + + Valid = true; + } + public Auto GetImage() { return Storage.GetImage(); @@ -816,7 +839,9 @@ namespace Ryujinx.Graphics.Vulkan for (int level = 0; level < levels; level++) { - int mipSize = GetBufferDataLength(Info.GetMipSize2D(dstLevel + level) * dstLayers); + int mipSize = GetBufferDataLength(is3D && !singleSlice + ? Info.GetMipSize(dstLevel + level) + : Info.GetMipSize2D(dstLevel + level) * dstLayers); int endOffset = offset + mipSize; @@ -939,6 +964,34 @@ namespace Ryujinx.Graphics.Vulkan throw new NotImplementedException(); } + public (Auto renderPass, Auto framebuffer) GetPassAndFramebuffer( + VulkanRenderer gd, + Device device, + CommandBufferScoped cbs, + FramebufferParams fb) + { + var key = fb.GetRenderPassCacheKey(); + + if (_renderPasses == null || !_renderPasses.TryGetValue(ref key, out RenderPassHolder rpHolder)) + { + rpHolder = new RenderPassHolder(gd, device, key, fb); + } + + return (rpHolder.GetRenderPass(), rpHolder.GetFramebuffer(gd, cbs, fb)); + } + + public void AddRenderPass(RenderPassCacheKey key, RenderPassHolder renderPass) + { + _renderPasses ??= new HashTableSlim(); + + _renderPasses.Add(ref key, renderPass); + } + + public void RemoveRenderPass(RenderPassCacheKey key) + { + _renderPasses.Remove(ref key); + } + protected virtual void Dispose(bool disposing) { if (disposing) @@ -948,15 +1001,29 @@ namespace Ryujinx.Graphics.Vulkan if (_gd.Textures.Remove(this)) { _imageView.Dispose(); - _imageViewIdentity.Dispose(); _imageView2dArray?.Dispose(); + if (_imageViewIdentity != _imageView) + { + _imageViewIdentity.Dispose(); + } + if (_imageViewDraw != _imageViewIdentity) { _imageViewDraw.Dispose(); } Storage.DecrementViewsCount(); + + if (_renderPasses != null) + { + var renderPasses = _renderPasses.Values.ToArray(); + + foreach (var pass in renderPasses) + { + pass.Dispose(); + } + } } } } diff --git a/src/Ryujinx.Graphics.Vulkan/VulkanException.cs b/src/Ryujinx.Graphics.Vulkan/VulkanException.cs index 0d4036802..e203a3a21 100644 --- a/src/Ryujinx.Graphics.Vulkan/VulkanException.cs +++ b/src/Ryujinx.Graphics.Vulkan/VulkanException.cs @@ -6,10 +6,16 @@ namespace Ryujinx.Graphics.Vulkan { static class ResultExtensions { + public static bool IsError(this Result result) + { + // Only negative result codes are errors. + return result < Result.Success; + } + public static void ThrowOnError(this Result result) { // Only negative result codes are errors. - if ((int)result < (int)Result.Success) + if (result.IsError()) { throw new VulkanException(result); } diff --git a/src/Ryujinx.Graphics.Vulkan/VulkanPhysicalDevice.cs b/src/Ryujinx.Graphics.Vulkan/VulkanPhysicalDevice.cs index 547f36543..3bee1e9d8 100644 --- a/src/Ryujinx.Graphics.Vulkan/VulkanPhysicalDevice.cs +++ b/src/Ryujinx.Graphics.Vulkan/VulkanPhysicalDevice.cs @@ -58,6 +58,33 @@ namespace Ryujinx.Graphics.Vulkan public bool IsDeviceExtensionPresent(string extension) => DeviceExtensions.Contains(extension); + public unsafe bool TryGetPhysicalDeviceDriverPropertiesKHR(Vk api, out PhysicalDeviceDriverPropertiesKHR res) + { + if (!IsDeviceExtensionPresent("VK_KHR_driver_properties")) + { + res = default; + + return false; + } + + PhysicalDeviceDriverPropertiesKHR physicalDeviceDriverProperties = new() + { + SType = StructureType.PhysicalDeviceDriverPropertiesKhr + }; + + PhysicalDeviceProperties2 physicalDeviceProperties2 = new() + { + SType = StructureType.PhysicalDeviceProperties2, + PNext = &physicalDeviceDriverProperties + }; + + api.GetPhysicalDeviceProperties2(PhysicalDevice, &physicalDeviceProperties2); + + res = physicalDeviceDriverProperties; + + return true; + } + public DeviceInfo ToDeviceInfo() { return new DeviceInfo( diff --git a/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs b/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs index 893ecf1a9..48f05fa19 100644 --- a/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs +++ b/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs @@ -84,6 +84,7 @@ namespace Ryujinx.Graphics.Vulkan internal bool IsTBDR { get; private set; } internal bool IsSharedMemory { get; private set; } public string GpuVendor { get; private set; } + public string GpuDriver { get; private set; } public string GpuRenderer { get; private set; } public string GpuVersion { get; private set; } @@ -636,7 +637,7 @@ namespace Ryujinx.Graphics.Vulkan public HardwareInfo GetHardwareInfo() { - return new HardwareInfo(GpuVendor, GpuRenderer); + return new HardwareInfo(GpuVendor, GpuRenderer, GpuDriver); } /// @@ -693,6 +694,8 @@ namespace Ryujinx.Graphics.Vulkan { var properties = _physicalDevice.PhysicalDeviceProperties; + var hasDriverProperties = _physicalDevice.TryGetPhysicalDeviceDriverPropertiesKHR(Api, out var driverProperties); + string vendorName = VendorUtils.GetNameFromId(properties.VendorID); Vendor = VendorUtils.FromId(properties.VendorID); @@ -707,6 +710,7 @@ namespace Ryujinx.Graphics.Vulkan Vendor == Vendor.ImgTec; GpuVendor = vendorName; + GpuDriver = hasDriverProperties ? Marshal.PtrToStringAnsi((IntPtr)driverProperties.DriverName) : vendorName; // Fall back to vendor name if driver name isn't available. GpuRenderer = Marshal.PtrToStringAnsi((IntPtr)properties.DeviceName); GpuVersion = $"Vulkan v{ParseStandardVulkanVersion(properties.ApiVersion)}, Driver v{ParseDriverVersion(ref properties)}"; @@ -784,7 +788,7 @@ namespace Ryujinx.Graphics.Vulkan public void SetBufferData(BufferHandle buffer, int offset, ReadOnlySpan data) { - BufferManager.SetData(buffer, offset, data, _pipeline.CurrentCommandBuffer, _pipeline.EndRenderPass); + BufferManager.SetData(buffer, offset, data, _pipeline.CurrentCommandBuffer, _pipeline.EndRenderPassDelegate); } public void UpdateCounters() diff --git a/src/Ryujinx.Graphics.Vulkan/Window.cs b/src/Ryujinx.Graphics.Vulkan/Window.cs index 2c5764a99..5ddb6eeda 100644 --- a/src/Ryujinx.Graphics.Vulkan/Window.cs +++ b/src/Ryujinx.Graphics.Vulkan/Window.cs @@ -20,7 +20,7 @@ namespace Ryujinx.Graphics.Vulkan private SwapchainKHR _swapchain; private Image[] _swapchainImages; - private Auto[] _swapchainImageViews; + private TextureView[] _swapchainImageViews; private Semaphore[] _imageAvailableSemaphores; private Semaphore[] _renderFinishedSemaphores; @@ -143,6 +143,23 @@ namespace Ryujinx.Graphics.Vulkan Clipped = true, }; + var textureCreateInfo = new TextureCreateInfo( + _width, + _height, + 1, + 1, + 1, + 1, + 1, + 1, + FormatTable.GetFormat(surfaceFormat.Format), + DepthStencilMode.Depth, + Target.Texture2D, + SwizzleComponent.Red, + SwizzleComponent.Green, + SwizzleComponent.Blue, + SwizzleComponent.Alpha); + _gd.SwapchainApi.CreateSwapchain(_device, swapchainCreateInfo, null, out _swapchain).ThrowOnError(); _gd.SwapchainApi.GetSwapchainImages(_device, _swapchain, &imageCount, null); @@ -154,11 +171,11 @@ namespace Ryujinx.Graphics.Vulkan _gd.SwapchainApi.GetSwapchainImages(_device, _swapchain, &imageCount, pSwapchainImages); } - _swapchainImageViews = new Auto[imageCount]; + _swapchainImageViews = new TextureView[imageCount]; for (int i = 0; i < _swapchainImageViews.Length; i++) { - _swapchainImageViews[i] = CreateSwapchainImageView(_swapchainImages[i], surfaceFormat.Format); + _swapchainImageViews[i] = CreateSwapchainImageView(_swapchainImages[i], surfaceFormat.Format, textureCreateInfo); } var semaphoreCreateInfo = new SemaphoreCreateInfo @@ -181,7 +198,7 @@ namespace Ryujinx.Graphics.Vulkan } } - private unsafe Auto CreateSwapchainImageView(Image swapchainImage, VkFormat format) + private unsafe TextureView CreateSwapchainImageView(Image swapchainImage, VkFormat format, TextureCreateInfo info) { var componentMapping = new ComponentMapping( ComponentSwizzle.R, @@ -204,7 +221,8 @@ namespace Ryujinx.Graphics.Vulkan }; _gd.Api.CreateImageView(_device, imageCreateInfo, null, out var imageView).ThrowOnError(); - return new Auto(new DisposableImageView(_gd.Api, _device, imageView)); + + return new TextureView(_gd, _device, new DisposableImageView(_gd.Api, _device, imageView), info, format); } private static SurfaceFormatKHR ChooseSwapSurfaceFormat(SurfaceFormatKHR[] availableFormats, bool colorSpacePassthroughEnabled) @@ -406,7 +424,7 @@ namespace Ryujinx.Graphics.Vulkan _scalingFilter.Run( view, cbs, - _swapchainImageViews[nextImage], + _swapchainImageViews[nextImage].GetImageViewForAttachment(), _format, _width, _height, @@ -421,11 +439,6 @@ namespace Ryujinx.Graphics.Vulkan cbs, view, _swapchainImageViews[nextImage], - _width, - _height, - 1, - _format, - false, new Extents2D(srcX0, srcY0, srcX1, srcY1), new Extents2D(dstX0, dstY1, dstX1, dstY0), _isLinear, diff --git a/src/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs b/src/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs index 43bd27761..0827266a1 100644 --- a/src/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs +++ b/src/Ryujinx.HLE/FileSystem/VirtualFileSystem.cs @@ -186,7 +186,12 @@ namespace Ryujinx.HLE.FileSystem public void InitializeFsServer(LibHac.Horizon horizon, out HorizonClient fsServerClient) { - LocalFileSystem serverBaseFs = new(AppDataManager.BaseDirPath); + LocalFileSystem serverBaseFs = new(useUnixTimeStamps: true); + Result result = serverBaseFs.Initialize(AppDataManager.BaseDirPath, LocalFileSystem.PathMode.DefaultCaseSensitivity, ensurePathExists: true); + if (result.IsFailure()) + { + throw new HorizonResultException(result, "Error creating LocalFileSystem."); + } fsServerClient = horizon.CreatePrivilegedHorizonClient(); var fsServer = new FileSystemServer(fsServerClient); diff --git a/src/Ryujinx.HLE/HLEConfiguration.cs b/src/Ryujinx.HLE/HLEConfiguration.cs index f589bfdda..955fee4b5 100644 --- a/src/Ryujinx.HLE/HLEConfiguration.cs +++ b/src/Ryujinx.HLE/HLEConfiguration.cs @@ -7,7 +7,7 @@ using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.HOS; using Ryujinx.HLE.HOS.Services.Account.Acc; using Ryujinx.HLE.HOS.SystemState; -using Ryujinx.HLE.Ui; +using Ryujinx.HLE.UI; using System; namespace Ryujinx.HLE @@ -63,7 +63,7 @@ namespace Ryujinx.HLE /// The handler for various UI related operations needed outside of HLE. /// /// This cannot be changed after instantiation. - internal readonly IHostUiHandler HostUiHandler; + internal readonly IHostUIHandler HostUIHandler; /// /// Control the memory configuration used by the emulation context. @@ -177,7 +177,7 @@ namespace Ryujinx.HLE IRenderer gpuRenderer, IHardwareDeviceDriver audioDeviceDriver, MemoryConfiguration memoryConfiguration, - IHostUiHandler hostUiHandler, + IHostUIHandler hostUIHandler, SystemLanguage systemLanguage, RegionCode region, bool enableVsync, @@ -204,7 +204,7 @@ namespace Ryujinx.HLE GpuRenderer = gpuRenderer; AudioDeviceDriver = audioDeviceDriver; MemoryConfiguration = memoryConfiguration; - HostUiHandler = hostUiHandler; + HostUIHandler = hostUIHandler; SystemLanguage = systemLanguage; Region = region; EnableVsync = enableVsync; diff --git a/src/Ryujinx.HLE/HOS/Applets/Controller/ControllerApplet.cs b/src/Ryujinx.HLE/HOS/Applets/Controller/ControllerApplet.cs index 867202178..5ec9d4b08 100644 --- a/src/Ryujinx.HLE/HOS/Applets/Controller/ControllerApplet.cs +++ b/src/Ryujinx.HLE/HOS/Applets/Controller/ControllerApplet.cs @@ -86,7 +86,7 @@ namespace Ryujinx.HLE.HOS.Applets PlayerIndex primaryIndex; while (!_system.Device.Hid.Npads.Validate(playerMin, playerMax, (ControllerType)privateArg.NpadStyleSet, out configuredCount, out primaryIndex)) { - ControllerAppletUiArgs uiArgs = new() + ControllerAppletUIArgs uiArgs = new() { PlayerCountMin = playerMin, PlayerCountMax = playerMax, @@ -95,7 +95,7 @@ namespace Ryujinx.HLE.HOS.Applets IsDocked = _system.State.DockedMode, }; - if (!_system.Device.UiHandler.DisplayMessageDialog(uiArgs)) + if (!_system.Device.UIHandler.DisplayMessageDialog(uiArgs)) { break; } diff --git a/src/Ryujinx.HLE/HOS/Applets/Controller/ControllerAppletUiArgs.cs b/src/Ryujinx.HLE/HOS/Applets/Controller/ControllerAppletUIArgs.cs similarity index 88% rename from src/Ryujinx.HLE/HOS/Applets/Controller/ControllerAppletUiArgs.cs rename to src/Ryujinx.HLE/HOS/Applets/Controller/ControllerAppletUIArgs.cs index bf440515b..10cba58ba 100644 --- a/src/Ryujinx.HLE/HOS/Applets/Controller/ControllerAppletUiArgs.cs +++ b/src/Ryujinx.HLE/HOS/Applets/Controller/ControllerAppletUIArgs.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; namespace Ryujinx.HLE.HOS.Applets { - public struct ControllerAppletUiArgs + public struct ControllerAppletUIArgs { public int PlayerCountMin; public int PlayerCountMax; diff --git a/src/Ryujinx.HLE/HOS/Applets/Error/ErrorApplet.cs b/src/Ryujinx.HLE/HOS/Applets/Error/ErrorApplet.cs index 5c474f229..7ee9b9e90 100644 --- a/src/Ryujinx.HLE/HOS/Applets/Error/ErrorApplet.cs +++ b/src/Ryujinx.HLE/HOS/Applets/Error/ErrorApplet.cs @@ -166,13 +166,13 @@ namespace Ryujinx.HLE.HOS.Applets.Error string[] buttons = GetButtonsText(module, description, "DlgBtn"); - bool showDetails = _horizon.Device.UiHandler.DisplayErrorAppletDialog($"Error Code: {module}-{description:0000}", "\n" + message, buttons); + bool showDetails = _horizon.Device.UIHandler.DisplayErrorAppletDialog($"Error Code: {module}-{description:0000}", "\n" + message, buttons); if (showDetails) { message = GetMessageText(module, description, "FlvMsg"); buttons = GetButtonsText(module, description, "FlvBtn"); - _horizon.Device.UiHandler.DisplayErrorAppletDialog($"Details: {module}-{description:0000}", "\n" + message, buttons); + _horizon.Device.UIHandler.DisplayErrorAppletDialog($"Details: {module}-{description:0000}", "\n" + message, buttons); } } @@ -200,12 +200,12 @@ namespace Ryujinx.HLE.HOS.Applets.Error buttons.Add("OK"); - bool showDetails = _horizon.Device.UiHandler.DisplayErrorAppletDialog($"Error Number: {applicationErrorArg.ErrorNumber}", "\n" + messageText, buttons.ToArray()); + bool showDetails = _horizon.Device.UIHandler.DisplayErrorAppletDialog($"Error Number: {applicationErrorArg.ErrorNumber}", "\n" + messageText, buttons.ToArray()); if (showDetails) { buttons.RemoveAt(0); - _horizon.Device.UiHandler.DisplayErrorAppletDialog($"Error Number: {applicationErrorArg.ErrorNumber} (Details)", "\n" + detailsText, buttons.ToArray()); + _horizon.Device.UIHandler.DisplayErrorAppletDialog($"Error Number: {applicationErrorArg.ErrorNumber} (Details)", "\n" + detailsText, buttons.ToArray()); } } diff --git a/src/Ryujinx.HLE/HOS/Applets/IApplet.cs b/src/Ryujinx.HLE/HOS/Applets/IApplet.cs index 5ccf3994f..985887c47 100644 --- a/src/Ryujinx.HLE/HOS/Applets/IApplet.cs +++ b/src/Ryujinx.HLE/HOS/Applets/IApplet.cs @@ -1,5 +1,5 @@ using Ryujinx.HLE.HOS.Services.Am.AppletAE; -using Ryujinx.HLE.Ui; +using Ryujinx.HLE.UI; using Ryujinx.Memory; using System; using System.Runtime.InteropServices; diff --git a/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardApplet.cs b/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardApplet.cs index 432bf6a8a..0462a5b00 100644 --- a/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardApplet.cs +++ b/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardApplet.cs @@ -4,8 +4,8 @@ using Ryujinx.Common.Logging; using Ryujinx.HLE.HOS.Applets.SoftwareKeyboard; using Ryujinx.HLE.HOS.Services.Am.AppletAE; using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad; -using Ryujinx.HLE.Ui; -using Ryujinx.HLE.Ui.Input; +using Ryujinx.HLE.UI; +using Ryujinx.HLE.UI.Input; using Ryujinx.Memory; using System; using System.Diagnostics; @@ -92,14 +92,14 @@ namespace Ryujinx.HLE.HOS.Applets _keyboardBackgroundInitialize = MemoryMarshal.Read(keyboardConfig); _backgroundState = InlineKeyboardState.Uninitialized; - if (_device.UiHandler == null) + if (_device.UIHandler == null) { Logger.Error?.Print(LogClass.ServiceAm, "GUI Handler is not set, software keyboard applet will not work properly"); } else { // Create a text handler that converts keyboard strokes to strings. - _dynamicTextInputHandler = _device.UiHandler.CreateDynamicTextInputHandler(); + _dynamicTextInputHandler = _device.UIHandler.CreateDynamicTextInputHandler(); _dynamicTextInputHandler.TextChangedEvent += HandleTextChangedEvent; _dynamicTextInputHandler.KeyPressedEvent += HandleKeyPressedEvent; @@ -107,7 +107,7 @@ namespace Ryujinx.HLE.HOS.Applets _npads.NpadButtonDownEvent += HandleNpadButtonDownEvent; _npads.NpadButtonUpEvent += HandleNpadButtonUpEvent; - _keyboardRenderer = new SoftwareKeyboardRenderer(_device.UiHandler.HostUiTheme); + _keyboardRenderer = new SoftwareKeyboardRenderer(_device.UIHandler.HostUITheme); } return ResultCode.Success; @@ -199,7 +199,7 @@ namespace Ryujinx.HLE.HOS.Applets _keyboardForegroundConfig.StringLengthMax = 100; } - if (_device.UiHandler == null) + if (_device.UIHandler == null) { Logger.Warning?.Print(LogClass.Application, "GUI Handler is not set. Falling back to default"); @@ -209,7 +209,7 @@ namespace Ryujinx.HLE.HOS.Applets else { // Call the configured GUI handler to get user's input. - var args = new SoftwareKeyboardUiArgs + var args = new SoftwareKeyboardUIArgs { KeyboardMode = _keyboardForegroundConfig.Mode, HeaderText = StripUnicodeControlCodes(_keyboardForegroundConfig.HeaderText), @@ -222,7 +222,7 @@ namespace Ryujinx.HLE.HOS.Applets InitialText = initialText, }; - _lastResult = _device.UiHandler.DisplayInputDialog(args, out _textValue) ? KeyboardResult.Accept : KeyboardResult.Cancel; + _lastResult = _device.UIHandler.DisplayInputDialog(args, out _textValue) ? KeyboardResult.Accept : KeyboardResult.Cancel; _textValue ??= initialText ?? DefaultInputText; } diff --git a/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardRenderer.cs b/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardRenderer.cs index f76cce295..3f7516e6a 100644 --- a/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardRenderer.cs +++ b/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardRenderer.cs @@ -1,4 +1,4 @@ -using Ryujinx.HLE.Ui; +using Ryujinx.HLE.UI; using Ryujinx.Memory; using System; using System.Threading; @@ -15,13 +15,13 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard private readonly object _stateLock = new(); - private readonly SoftwareKeyboardUiState _state = new(); + private readonly SoftwareKeyboardUIState _state = new(); private readonly SoftwareKeyboardRendererBase _renderer; private readonly TimedAction _textBoxBlinkTimedAction = new(); private readonly TimedAction _renderAction = new(); - public SoftwareKeyboardRenderer(IHostUiTheme uiTheme) + public SoftwareKeyboardRenderer(IHostUITheme uiTheme) { _renderer = new SoftwareKeyboardRendererBase(uiTheme); @@ -29,7 +29,7 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard StartRenderer(_renderAction, _renderer, _state, _stateLock); } - private static void StartTextBoxBlinker(TimedAction timedAction, SoftwareKeyboardUiState state, object stateLock) + private static void StartTextBoxBlinker(TimedAction timedAction, SoftwareKeyboardUIState state, object stateLock) { timedAction.Reset(() => { @@ -45,9 +45,9 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard }, TextBoxBlinkSleepMilliseconds); } - private static void StartRenderer(TimedAction timedAction, SoftwareKeyboardRendererBase renderer, SoftwareKeyboardUiState state, object stateLock) + private static void StartRenderer(TimedAction timedAction, SoftwareKeyboardRendererBase renderer, SoftwareKeyboardUIState state, object stateLock) { - SoftwareKeyboardUiState internalState = new(); + SoftwareKeyboardUIState internalState = new(); bool canCreateSurface = false; bool needsUpdate = true; diff --git a/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardRendererBase.cs b/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardRendererBase.cs index 3971a33be..75c648ff1 100644 --- a/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardRendererBase.cs +++ b/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardRendererBase.cs @@ -1,4 +1,4 @@ -using Ryujinx.HLE.Ui; +using Ryujinx.HLE.UI; using Ryujinx.Memory; using SixLabors.Fonts; using SixLabors.ImageSharp; @@ -63,7 +63,7 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard private Point _logoPosition; private float _messagePositionY; - public SoftwareKeyboardRendererBase(IHostUiTheme uiTheme) + public SoftwareKeyboardRendererBase(IHostUITheme uiTheme) { int ryujinxLogoSize = 32; @@ -205,7 +205,7 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard }); } - public void DrawMutableElements(SoftwareKeyboardUiState state) + public void DrawMutableElements(SoftwareKeyboardUIState state) { if (_surface == null) { @@ -322,7 +322,7 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard return new RectangleF(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height); } - private void DrawTextBox(IImageProcessingContext context, SoftwareKeyboardUiState state) + private void DrawTextBox(IImageProcessingContext context, SoftwareKeyboardUIState state) { var inputTextRectangle = MeasureString(state.InputText, _inputTextFont); diff --git a/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardUiArgs.cs b/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardUIArgs.cs similarity index 90% rename from src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardUiArgs.cs rename to src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardUIArgs.cs index 52fa7ed85..854f04a3b 100644 --- a/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardUiArgs.cs +++ b/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardUIArgs.cs @@ -2,7 +2,7 @@ using Ryujinx.HLE.HOS.Applets.SoftwareKeyboard; namespace Ryujinx.HLE.HOS.Applets { - public struct SoftwareKeyboardUiArgs + public struct SoftwareKeyboardUIArgs { public KeyboardMode KeyboardMode; public string HeaderText; diff --git a/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardUiState.cs b/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardUIState.cs similarity index 89% rename from src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardUiState.cs rename to src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardUIState.cs index 608d51f32..6199ff666 100644 --- a/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardUiState.cs +++ b/src/Ryujinx.HLE/HOS/Applets/SoftwareKeyboard/SoftwareKeyboardUIState.cs @@ -1,11 +1,11 @@ -using Ryujinx.HLE.Ui; +using Ryujinx.HLE.UI; namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard { /// /// TODO /// - internal class SoftwareKeyboardUiState + internal class SoftwareKeyboardUIState { public string InputText = ""; public int CursorBegin = 0; diff --git a/src/Ryujinx.HLE/HOS/ArmProcessContext.cs b/src/Ryujinx.HLE/HOS/ArmProcessContext.cs index ff2185464..fde489ab7 100644 --- a/src/Ryujinx.HLE/HOS/ArmProcessContext.cs +++ b/src/Ryujinx.HLE/HOS/ArmProcessContext.cs @@ -57,6 +57,8 @@ namespace Ryujinx.HLE.HOS public void Execute(IExecutionContext context, ulong codeAddress) { + // We must wait until shader cache is loaded, among other things, before executing CPU code. + _gpuContext.WaitUntilGpuReady(); _cpuContext.Execute(context, codeAddress); } @@ -85,6 +87,8 @@ namespace Ryujinx.HLE.HOS _memoryManager = null; _gpuContext.UnregisterProcess(_pid); } + + _cpuContext.Dispose(); } } } diff --git a/src/Ryujinx.HLE/HOS/ArmProcessContextFactory.cs b/src/Ryujinx.HLE/HOS/ArmProcessContextFactory.cs index bec2722ef..06b8fd345 100644 --- a/src/Ryujinx.HLE/HOS/ArmProcessContextFactory.cs +++ b/src/Ryujinx.HLE/HOS/ArmProcessContextFactory.cs @@ -3,6 +3,7 @@ using Ryujinx.Common.Logging; using Ryujinx.Cpu; using Ryujinx.Cpu.AppleHv; using Ryujinx.Cpu.Jit; +using Ryujinx.Cpu.LightningJit; using Ryujinx.Graphics.Gpu; using Ryujinx.HLE.HOS.Kernel; using Ryujinx.HLE.HOS.Kernel.Process; @@ -46,7 +47,9 @@ namespace Ryujinx.HLE.HOS { IArmProcessContext processContext; - if (OperatingSystem.IsMacOS() && RuntimeInformation.ProcessArchitecture == Architecture.Arm64 && for64Bit && context.Device.Configuration.UseHypervisor) + bool isArm64Host = RuntimeInformation.ProcessArchitecture == Architecture.Arm64; + + if (OperatingSystem.IsMacOS() && isArm64Host && for64Bit && context.Device.Configuration.UseHypervisor) { var cpuEngine = new HvEngine(_tickSource); var memoryManager = new HvMemoryManager(context.Memory, addressSpaceSize, invalidAccessHandler); @@ -63,7 +66,9 @@ namespace Ryujinx.HLE.HOS mode = MemoryManagerMode.SoftwarePageTable; } - var cpuEngine = new JitEngine(_tickSource); + ICpuEngine cpuEngine = isArm64Host && (mode == MemoryManagerMode.HostMapped || mode == MemoryManagerMode.HostMappedUnsafe) + ? new LightningJitEngine(_tickSource) + : new JitEngine(_tickSource); AddressSpace addressSpace = null; diff --git a/src/Ryujinx.HLE/HOS/Horizon.cs b/src/Ryujinx.HLE/HOS/Horizon.cs index 1a402240f..cd1719580 100644 --- a/src/Ryujinx.HLE/HOS/Horizon.cs +++ b/src/Ryujinx.HLE/HOS/Horizon.cs @@ -330,7 +330,7 @@ namespace Ryujinx.HLE.HOS HorizonFsClient fsClient = new(this); ServiceTable = new ServiceTable(); - var services = ServiceTable.GetServices(new HorizonOptions(Device.Configuration.IgnoreMissingServices, LibHacHorizonManager.BcatClient, fsClient)); + var services = ServiceTable.GetServices(new HorizonOptions(Device.Configuration.IgnoreMissingServices, LibHacHorizonManager.BcatClient, fsClient, AccountManager)); foreach (var service in services) { diff --git a/src/Ryujinx.HLE/HOS/ModLoader.cs b/src/Ryujinx.HLE/HOS/ModLoader.cs index 834bc0595..8ae529655 100644 --- a/src/Ryujinx.HLE/HOS/ModLoader.cs +++ b/src/Ryujinx.HLE/HOS/ModLoader.cs @@ -7,6 +7,7 @@ using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem.RomFs; using Ryujinx.Common.Configuration; using Ryujinx.Common.Logging; +using Ryujinx.Common.Utilities; using Ryujinx.HLE.HOS.Kernel.Process; using Ryujinx.HLE.Loaders.Executables; using Ryujinx.HLE.Loaders.Mods; @@ -17,6 +18,7 @@ using System.Collections.Specialized; using System.Globalization; using System.IO; using System.Linq; +using LazyFile = Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy.LazyFile; using Path = System.IO.Path; namespace Ryujinx.HLE.HOS @@ -37,15 +39,19 @@ namespace Ryujinx.HLE.HOS private const string AmsNroPatchDir = "nro_patches"; private const string AmsKipPatchDir = "kip_patches"; + private static readonly ModMetadataJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions()); + public readonly struct Mod where T : FileSystemInfo { public readonly string Name; public readonly T Path; + public readonly bool Enabled; - public Mod(string name, T path) + public Mod(string name, T path, bool enabled) { Name = name; Path = path; + Enabled = enabled; } } @@ -67,7 +73,7 @@ namespace Ryujinx.HLE.HOS } } - // Title dependent mods + // Application dependent mods public class ModCache { public List> RomfsContainers { get; } @@ -88,7 +94,7 @@ namespace Ryujinx.HLE.HOS } } - // Title independent mods + // Application independent mods private class PatchCache { public List> NsoPatches { get; } @@ -107,7 +113,7 @@ namespace Ryujinx.HLE.HOS } } - private readonly Dictionary _appMods; // key is TitleId + private readonly Dictionary _appMods; // key is ApplicationId private PatchCache _patches; private static readonly EnumerationOptions _dirEnumOptions; @@ -153,26 +159,52 @@ namespace Ryujinx.HLE.HOS return modsDir.FullName; } - private static DirectoryInfo FindTitleDir(DirectoryInfo contentsDir, string titleId) - => contentsDir.EnumerateDirectories(titleId, _dirEnumOptions).FirstOrDefault(); + private static DirectoryInfo FindApplicationDir(DirectoryInfo contentsDir, string applicationId) + => contentsDir.EnumerateDirectories(applicationId, _dirEnumOptions).FirstOrDefault(); - private static void AddModsFromDirectory(ModCache mods, DirectoryInfo dir, string titleId) + private static void AddModsFromDirectory(ModCache mods, DirectoryInfo dir, ModMetadata modMetadata) { System.Text.StringBuilder types = new(); foreach (var modDir in dir.EnumerateDirectories()) { types.Clear(); - Mod mod = new("", null); + Mod mod = new("", null, true); if (StrEquals(RomfsDir, modDir.Name)) { - mods.RomfsDirs.Add(mod = new Mod(dir.Name, modDir)); + bool enabled; + + try + { + var modData = modMetadata.Mods.Find(x => modDir.FullName.Contains(x.Path)); + enabled = modData.Enabled; + } + catch + { + // Mod is not in the list yet. New mods should be enabled by default. + enabled = true; + } + + mods.RomfsDirs.Add(mod = new Mod(dir.Name, modDir, enabled)); types.Append('R'); } else if (StrEquals(ExefsDir, modDir.Name)) { - mods.ExefsDirs.Add(mod = new Mod(dir.Name, modDir)); + bool enabled; + + try + { + var modData = modMetadata.Mods.Find(x => modDir.FullName.Contains(x.Path)); + enabled = modData.Enabled; + } + catch + { + // Mod is not in the list yet. New mods should be enabled by default. + enabled = true; + } + + mods.ExefsDirs.Add(mod = new Mod(dir.Name, modDir, enabled)); types.Append('E'); } else if (StrEquals(CheatDir, modDir.Name)) @@ -181,7 +213,7 @@ namespace Ryujinx.HLE.HOS } else { - AddModsFromDirectory(mods, modDir, titleId); + AddModsFromDirectory(mods, modDir, modMetadata); } if (types.Length > 0) @@ -191,18 +223,18 @@ namespace Ryujinx.HLE.HOS } } - public static string GetTitleDir(string modsBasePath, string titleId) + public static string GetApplicationDir(string modsBasePath, string applicationId) { var contentsDir = new DirectoryInfo(Path.Combine(modsBasePath, AmsContentsDir)); - var titleModsPath = FindTitleDir(contentsDir, titleId); + var applicationModsPath = FindApplicationDir(contentsDir, applicationId); - if (titleModsPath == null) + if (applicationModsPath == null) { - Logger.Info?.Print(LogClass.ModLoader, $"Creating mods directory for Title {titleId.ToUpper()}"); - titleModsPath = contentsDir.CreateSubdirectory(titleId); + Logger.Info?.Print(LogClass.ModLoader, $"Creating mods directory for Application {applicationId.ToUpper()}"); + applicationModsPath = contentsDir.CreateSubdirectory(applicationId); } - return titleModsPath.FullName; + return applicationModsPath.FullName; } // Static Query Methods @@ -238,47 +270,68 @@ namespace Ryujinx.HLE.HOS foreach (var modDir in patchDir.EnumerateDirectories()) { - patches.Add(new Mod(modDir.Name, modDir)); + patches.Add(new Mod(modDir.Name, modDir, true)); Logger.Info?.Print(LogClass.ModLoader, $"Found {type} patch '{modDir.Name}'"); } } - private static void QueryTitleDir(ModCache mods, DirectoryInfo titleDir) + private static void QueryApplicationDir(ModCache mods, DirectoryInfo applicationDir, ulong applicationId) { - if (!titleDir.Exists) + if (!applicationDir.Exists) { return; } - var fsFile = new FileInfo(Path.Combine(titleDir.FullName, RomfsContainer)); - if (fsFile.Exists) + string modJsonPath = Path.Combine(AppDataManager.GamesDirPath, applicationId.ToString("x16"), "mods.json"); + ModMetadata modMetadata = new(); + + if (File.Exists(modJsonPath)) { - mods.RomfsContainers.Add(new Mod($"<{titleDir.Name} RomFs>", fsFile)); + try + { + modMetadata = JsonHelper.DeserializeFromFile(modJsonPath, _serializerContext.ModMetadata); + } + catch + { + Logger.Warning?.Print(LogClass.ModLoader, $"Failed to deserialize mod data for {applicationId:X16} at {modJsonPath}"); + } } - fsFile = new FileInfo(Path.Combine(titleDir.FullName, ExefsContainer)); + var fsFile = new FileInfo(Path.Combine(applicationDir.FullName, RomfsContainer)); if (fsFile.Exists) { - mods.ExefsContainers.Add(new Mod($"<{titleDir.Name} ExeFs>", fsFile)); + var modData = modMetadata.Mods.Find(x => fsFile.FullName.Contains(x.Path)); + var enabled = modData == null || modData.Enabled; + + mods.RomfsContainers.Add(new Mod($"<{applicationDir.Name} RomFs>", fsFile, enabled)); } - AddModsFromDirectory(mods, titleDir, titleDir.Name); + fsFile = new FileInfo(Path.Combine(applicationDir.FullName, ExefsContainer)); + if (fsFile.Exists) + { + var modData = modMetadata.Mods.Find(x => fsFile.FullName.Contains(x.Path)); + var enabled = modData == null || modData.Enabled; + + mods.ExefsContainers.Add(new Mod($"<{applicationDir.Name} ExeFs>", fsFile, enabled)); + } + + AddModsFromDirectory(mods, applicationDir, modMetadata); } - public static void QueryContentsDir(ModCache mods, DirectoryInfo contentsDir, ulong titleId) + public static void QueryContentsDir(ModCache mods, DirectoryInfo contentsDir, ulong applicationId) { if (!contentsDir.Exists) { return; } - Logger.Info?.Print(LogClass.ModLoader, $"Searching mods for {((titleId & 0x1000) != 0 ? "DLC" : "Title")} {titleId:X16}"); + Logger.Info?.Print(LogClass.ModLoader, $"Searching mods for {((applicationId & 0x1000) != 0 ? "DLC" : "Application")} {applicationId:X16} in \"{contentsDir.FullName}\""); - var titleDir = FindTitleDir(contentsDir, $"{titleId:x16}"); + var applicationDir = FindApplicationDir(contentsDir, $"{applicationId:x16}"); - if (titleDir != null) + if (applicationDir != null) { - QueryTitleDir(mods, titleDir); + QueryApplicationDir(mods, applicationDir, applicationId); } } @@ -387,9 +440,9 @@ namespace Ryujinx.HLE.HOS { if (IsContentsDir(searchDir.Name)) { - foreach ((ulong titleId, ModCache cache) in modCaches) + foreach ((ulong applicationId, ModCache cache) in modCaches) { - QueryContentsDir(cache, searchDir, titleId); + QueryContentsDir(cache, searchDir, applicationId); } return true; @@ -410,7 +463,7 @@ namespace Ryujinx.HLE.HOS if (!searchDir.Exists) { Logger.Warning?.Print(LogClass.ModLoader, $"Mod Search Dir '{searchDir.FullName}' doesn't exist"); - continue; + return; } if (!TryQuery(searchDir, patches, modCaches)) @@ -425,21 +478,21 @@ namespace Ryujinx.HLE.HOS patches.Initialized = true; } - public void CollectMods(IEnumerable titles, params string[] searchDirPaths) + public void CollectMods(IEnumerable applications, params string[] searchDirPaths) { Clear(); - foreach (ulong titleId in titles) + foreach (ulong applicationId in applications) { - _appMods[titleId] = new ModCache(); + _appMods[applicationId] = new ModCache(); } CollectMods(_appMods, _patches, searchDirPaths); } - internal IStorage ApplyRomFsMods(ulong titleId, IStorage baseStorage) + internal IStorage ApplyRomFsMods(ulong applicationId, IStorage baseStorage) { - if (!_appMods.TryGetValue(titleId, out ModCache mods) || mods.RomfsDirs.Count + mods.RomfsContainers.Count == 0) + if (!_appMods.TryGetValue(applicationId, out ModCache mods) || mods.RomfsDirs.Count + mods.RomfsContainers.Count == 0) { return baseStorage; } @@ -448,14 +501,19 @@ namespace Ryujinx.HLE.HOS var builder = new RomFsBuilder(); int count = 0; - Logger.Info?.Print(LogClass.ModLoader, $"Applying RomFS mods for Title {titleId:X16}"); + Logger.Info?.Print(LogClass.ModLoader, $"Applying RomFS mods for Application {applicationId:X16}"); // Prioritize loose files first foreach (var mod in mods.RomfsDirs) { + if (!mod.Enabled) + { + continue; + } + using (IFileSystem fs = new LocalFileSystem(mod.Path.FullName)) { - AddFiles(fs, mod.Name, fileSet, builder); + AddFiles(fs, mod.Name, mod.Path.FullName, fileSet, builder); } count++; } @@ -463,10 +521,15 @@ namespace Ryujinx.HLE.HOS // Then files inside images foreach (var mod in mods.RomfsContainers) { - Logger.Info?.Print(LogClass.ModLoader, $"Found 'romfs.bin' for Title {titleId:X16}"); + if (!mod.Enabled) + { + continue; + } + + Logger.Info?.Print(LogClass.ModLoader, $"Found 'romfs.bin' for Application {applicationId:X16}"); using (IFileSystem fs = new RomFsFileSystem(mod.Path.OpenRead().AsStorage())) { - AddFiles(fs, mod.Name, fileSet, builder); + AddFiles(fs, mod.Name, mod.Path.FullName, fileSet, builder); } count++; } @@ -499,18 +562,18 @@ namespace Ryujinx.HLE.HOS return newStorage; } - private static void AddFiles(IFileSystem fs, string modName, ISet fileSet, RomFsBuilder builder) + private static void AddFiles(IFileSystem fs, string modName, string rootPath, ISet fileSet, RomFsBuilder builder) { foreach (var entry in fs.EnumerateEntries() + .AsParallel() .Where(f => f.Type == DirectoryEntryType.File) .OrderBy(f => f.FullPath, StringComparer.Ordinal)) { - using var file = new UniqueRef(); + var file = new LazyFile(entry.FullPath, rootPath, fs); - fs.OpenFile(ref file.Ref, entry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); if (fileSet.Add(entry.FullPath)) { - builder.AddFile(entry.FullPath, file.Release()); + builder.AddFile(entry.FullPath, file); } else { @@ -519,9 +582,9 @@ namespace Ryujinx.HLE.HOS } } - internal bool ReplaceExefsPartition(ulong titleId, ref IFileSystem exefs) + internal bool ReplaceExefsPartition(ulong applicationId, ref IFileSystem exefs) { - if (!_appMods.TryGetValue(titleId, out ModCache mods) || mods.ExefsContainers.Count == 0) + if (!_appMods.TryGetValue(applicationId, out ModCache mods) || mods.ExefsContainers.Count == 0) { return false; } @@ -549,7 +612,7 @@ namespace Ryujinx.HLE.HOS public bool Modified => (Stubs.Data | Replaces.Data) != 0; } - internal ModLoadResult ApplyExefsMods(ulong titleId, NsoExecutable[] nsos) + internal ModLoadResult ApplyExefsMods(ulong applicationId, NsoExecutable[] nsos) { ModLoadResult modLoadResult = new() { @@ -557,7 +620,7 @@ namespace Ryujinx.HLE.HOS Replaces = new BitVector32(), }; - if (!_appMods.TryGetValue(titleId, out ModCache mods) || mods.ExefsDirs.Count == 0) + if (!_appMods.TryGetValue(applicationId, out ModCache mods) || mods.ExefsDirs.Count == 0) { return modLoadResult; } @@ -571,6 +634,11 @@ namespace Ryujinx.HLE.HOS foreach (var mod in exeMods) { + if (!mod.Enabled) + { + continue; + } + for (int i = 0; i < ProcessConst.ExeFsPrefixes.Length; ++i) { var nsoName = ProcessConst.ExeFsPrefixes[i]; @@ -637,11 +705,11 @@ namespace Ryujinx.HLE.HOS ApplyProgramPatches(nroPatches, 0, nro); } - internal bool ApplyNsoPatches(ulong titleId, params IExecutable[] programs) + internal bool ApplyNsoPatches(ulong applicationId, params IExecutable[] programs) { IEnumerable> nsoMods = _patches.NsoPatches; - if (_appMods.TryGetValue(titleId, out ModCache mods)) + if (_appMods.TryGetValue(applicationId, out ModCache mods)) { nsoMods = nsoMods.Concat(mods.ExefsDirs); } @@ -651,7 +719,7 @@ namespace Ryujinx.HLE.HOS return ApplyProgramPatches(nsoMods, 0x100, programs); } - internal void LoadCheats(ulong titleId, ProcessTamperInfo tamperInfo, TamperMachine tamperMachine) + internal void LoadCheats(ulong applicationId, ProcessTamperInfo tamperInfo, TamperMachine tamperMachine) { if (tamperInfo?.BuildIds == null || tamperInfo.CodeAddresses == null) { @@ -660,9 +728,9 @@ namespace Ryujinx.HLE.HOS return; } - Logger.Info?.Print(LogClass.ModLoader, $"Build ids found for title {titleId:X16}:\n {String.Join("\n ", tamperInfo.BuildIds)}"); + Logger.Info?.Print(LogClass.ModLoader, $"Build ids found for application {applicationId:X16}:\n {String.Join("\n ", tamperInfo.BuildIds)}"); - if (!_appMods.TryGetValue(titleId, out ModCache mods) || mods.Cheats.Count == 0) + if (!_appMods.TryGetValue(applicationId, out ModCache mods) || mods.Cheats.Count == 0) { return; } @@ -687,12 +755,12 @@ namespace Ryujinx.HLE.HOS tamperMachine.InstallAtmosphereCheat(cheat.Name, cheatId, cheat.Instructions, tamperInfo, exeAddress); } - EnableCheats(titleId, tamperMachine); + EnableCheats(applicationId, tamperMachine); } - internal static void EnableCheats(ulong titleId, TamperMachine tamperMachine) + internal static void EnableCheats(ulong applicationId, TamperMachine tamperMachine) { - var contentDirectory = FindTitleDir(new DirectoryInfo(Path.Combine(GetModsBasePath(), AmsContentsDir)), $"{titleId:x16}"); + var contentDirectory = FindApplicationDir(new DirectoryInfo(Path.Combine(GetModsBasePath(), AmsContentsDir)), $"{applicationId:x16}"); string enabledCheatsPath = Path.Combine(contentDirectory.FullName, CheatDir, "enabled.txt"); if (File.Exists(enabledCheatsPath)) @@ -724,6 +792,11 @@ namespace Ryujinx.HLE.HOS // Collect patches foreach (var mod in mods) { + if (!mod.Enabled) + { + continue; + } + var patchDir = mod.Path; foreach (var patchFile in patchDir.EnumerateFiles()) { diff --git a/src/Ryujinx.HLE/HOS/Services/Account/Acc/AccountManager.cs b/src/Ryujinx.HLE/HOS/Services/Account/Acc/AccountManager.cs index 924ac3fb9..c724660ea 100644 --- a/src/Ryujinx.HLE/HOS/Services/Account/Acc/AccountManager.cs +++ b/src/Ryujinx.HLE/HOS/Services/Account/Acc/AccountManager.cs @@ -4,6 +4,7 @@ using LibHac.Fs; using LibHac.Fs.Shim; using Ryujinx.Common; using Ryujinx.Common.Logging; +using Ryujinx.Horizon.Sdk.Account; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -11,7 +12,7 @@ using System.Linq; namespace Ryujinx.HLE.HOS.Services.Account.Acc { - public class AccountManager + public class AccountManager : IEmulatorAccountManager { public static readonly UserId DefaultUserId = new("00000000000000010000000000000000"); @@ -106,6 +107,11 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc _accountSaveDataManager.Save(_profiles); } + public void OpenUserOnlinePlay(Uid userId) + { + OpenUserOnlinePlay(new UserId((long)userId.Low, (long)userId.High)); + } + public void OpenUserOnlinePlay(UserId userId) { if (_profiles.TryGetValue(userId.ToString(), out UserProfile profile)) @@ -127,6 +133,11 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc _accountSaveDataManager.Save(_profiles); } + public void CloseUserOnlinePlay(Uid userId) + { + CloseUserOnlinePlay(new UserId((long)userId.Low, (long)userId.High)); + } + public void CloseUserOnlinePlay(UserId userId) { if (_profiles.TryGetValue(userId.ToString(), out UserProfile profile)) diff --git a/src/Ryujinx.HLE/HOS/Services/Account/Acc/AccountService/ManagerServer.cs b/src/Ryujinx.HLE/HOS/Services/Account/Acc/AccountService/ManagerServer.cs index ec7fa5c4f..75bad0e3f 100644 --- a/src/Ryujinx.HLE/HOS/Services/Account/Acc/AccountService/ManagerServer.cs +++ b/src/Ryujinx.HLE/HOS/Services/Account/Acc/AccountService/ManagerServer.cs @@ -22,6 +22,9 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc.AccountService private readonly UserId _userId; #pragma warning restore IDE0052 + private byte[] _cachedTokenData; + private DateTime _cachedTokenExpiry; + public ManagerServer(UserId userId) { _userId = userId; @@ -144,7 +147,13 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc.AccountService } */ - byte[] tokenData = Encoding.ASCII.GetBytes(GenerateIdToken()); + if (_cachedTokenData == null || DateTime.UtcNow > _cachedTokenExpiry) + { + _cachedTokenExpiry = DateTime.UtcNow + TimeSpan.FromHours(3); + _cachedTokenData = Encoding.ASCII.GetBytes(GenerateIdToken()); + } + + byte[] tokenData = _cachedTokenData; context.Memory.Write(bufferPosition, tokenData); context.ResponseData.Write(tokenData.Length); diff --git a/src/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs b/src/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs index 271d00605..9a7fdcc16 100644 --- a/src/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs +++ b/src/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs @@ -97,7 +97,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati if (titleId == 0) { - context.Device.UiHandler.ExecuteProgram(context.Device, ProgramSpecifyKind.RestartProgram, titleId); + context.Device.UIHandler.ExecuteProgram(context.Device, ProgramSpecifyKind.RestartProgram, titleId); } else { @@ -524,7 +524,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati Logger.Stub?.PrintStub(LogClass.ServiceAm, new { kind, value }); - context.Device.UiHandler.ExecuteProgram(context.Device, kind, value); + context.Device.UIHandler.ExecuteProgram(context.Device, kind, value); return ResultCode.Success; } diff --git a/src/Ryujinx.HLE/HOS/Services/Arp/IReader.cs b/src/Ryujinx.HLE/HOS/Services/Arp/IReader.cs deleted file mode 100644 index 611310421..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Arp/IReader.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Arp -{ - [Service("arp:r")] - class IReader : IpcService - { - public IReader(ServiceCtx context) { } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Arp/IWriter.cs b/src/Ryujinx.HLE/HOS/Services/Arp/IWriter.cs deleted file mode 100644 index 22d081b9b..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Arp/IWriter.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Arp -{ - [Service("arp:w")] - class IWriter : IpcService - { - public IWriter(ServiceCtx context) { } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Friend/IServiceCreator.cs b/src/Ryujinx.HLE/HOS/Services/Friend/IServiceCreator.cs deleted file mode 100644 index 3f15f3fc6..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Friend/IServiceCreator.cs +++ /dev/null @@ -1,55 +0,0 @@ -using Ryujinx.Common; -using Ryujinx.HLE.HOS.Services.Account.Acc; -using Ryujinx.HLE.HOS.Services.Friend.ServiceCreator; - -namespace Ryujinx.HLE.HOS.Services.Friend -{ - [Service("friend:a", FriendServicePermissionLevel.Administrator)] - [Service("friend:m", FriendServicePermissionLevel.Manager)] - [Service("friend:s", FriendServicePermissionLevel.System)] - [Service("friend:u", FriendServicePermissionLevel.User)] - [Service("friend:v", FriendServicePermissionLevel.Viewer)] - class IServiceCreator : IpcService - { - private readonly FriendServicePermissionLevel _permissionLevel; - - public IServiceCreator(ServiceCtx context, FriendServicePermissionLevel permissionLevel) - { - _permissionLevel = permissionLevel; - } - - [CommandCmif(0)] - // CreateFriendService() -> object - public ResultCode CreateFriendService(ServiceCtx context) - { - MakeObject(context, new IFriendService(_permissionLevel)); - - return ResultCode.Success; - } - - [CommandCmif(1)] // 2.0.0+ - // CreateNotificationService(nn::account::Uid userId) -> object - public ResultCode CreateNotificationService(ServiceCtx context) - { - UserId userId = context.RequestData.ReadStruct(); - - if (userId.IsNull) - { - return ResultCode.InvalidArgument; - } - - MakeObject(context, new INotificationService(context, userId, _permissionLevel)); - - return ResultCode.Success; - } - - [CommandCmif(2)] // 4.0.0+ - // CreateDaemonSuspendSessionService() -> object - public ResultCode CreateDaemonSuspendSessionService(ServiceCtx context) - { - MakeObject(context, new IDaemonSuspendSessionService(_permissionLevel)); - - return ResultCode.Success; - } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Friend/ResultCode.cs b/src/Ryujinx.HLE/HOS/Services/Friend/ResultCode.cs deleted file mode 100644 index 9f612059c..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Friend/ResultCode.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Friend -{ - enum ResultCode - { - ModuleId = 121, - ErrorCodeShift = 9, - - Success = 0, - - InvalidArgument = (2 << ErrorCodeShift) | ModuleId, - InternetRequestDenied = (6 << ErrorCodeShift) | ModuleId, - NotificationQueueEmpty = (15 << ErrorCodeShift) | ModuleId, - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/Friend.cs b/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/Friend.cs deleted file mode 100644 index 28745c3f2..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/Friend.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Ryujinx.HLE.HOS.Services.Account.Acc; -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService -{ - [StructLayout(LayoutKind.Sequential, Pack = 0x8, Size = 0x200, CharSet = CharSet.Ansi)] - struct Friend - { - public UserId UserId; - public long NetworkUserId; - - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x21)] - public string Nickname; - - public UserPresence presence; - - [MarshalAs(UnmanagedType.I1)] - public bool IsFavourite; - - [MarshalAs(UnmanagedType.I1)] - public bool IsNew; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x6)] - readonly char[] Unknown; - - [MarshalAs(UnmanagedType.I1)] - public bool IsValid; - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/FriendFilter.cs b/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/FriendFilter.cs deleted file mode 100644 index 5f13f3136..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/FriendFilter.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService -{ - [StructLayout(LayoutKind.Sequential)] - struct FriendFilter - { - public PresenceStatusFilter PresenceStatus; - - [MarshalAs(UnmanagedType.I1)] - public bool IsFavoriteOnly; - - [MarshalAs(UnmanagedType.I1)] - public bool IsSameAppPresenceOnly; - - [MarshalAs(UnmanagedType.I1)] - public bool IsSameAppPlayedOnly; - - [MarshalAs(UnmanagedType.I1)] - public bool IsArbitraryAppPlayedOnly; - - public long PresenceGroupId; - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/UserPresence.cs b/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/UserPresence.cs deleted file mode 100644 index 80d142059..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/UserPresence.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Ryujinx.Common.Memory; -using Ryujinx.HLE.HOS.Services.Account.Acc; -using System; -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService -{ - [StructLayout(LayoutKind.Sequential, Pack = 0x8)] - struct UserPresence - { - public UserId UserId; - public long LastTimeOnlineTimestamp; - public PresenceStatus Status; - - [MarshalAs(UnmanagedType.I1)] - public bool SamePresenceGroupApplication; - - public Array3 Unknown; - private AppKeyValueStorageHolder _appKeyValueStorage; - - public Span AppKeyValueStorage => MemoryMarshal.Cast(MemoryMarshal.CreateSpan(ref _appKeyValueStorage, AppKeyValueStorageHolder.Size)); - - [StructLayout(LayoutKind.Sequential, Pack = 0x1, Size = Size)] - private struct AppKeyValueStorageHolder - { - public const int Size = 0xC0; - } - - public readonly override string ToString() - { - return $"UserPresence {{ UserId: {UserId}, LastTimeOnlineTimestamp: {LastTimeOnlineTimestamp}, Status: {Status} }}"; - } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IDaemonSuspendSessionService.cs b/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IDaemonSuspendSessionService.cs deleted file mode 100644 index 3b1601abb..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IDaemonSuspendSessionService.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator -{ - class IDaemonSuspendSessionService : IpcService - { -#pragma warning disable IDE0052 // Remove unread private member - private readonly FriendServicePermissionLevel _permissionLevel; -#pragma warning restore IDE0052 - - public IDaemonSuspendSessionService(FriendServicePermissionLevel permissionLevel) - { - _permissionLevel = permissionLevel; - } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IFriendService.cs b/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IFriendService.cs deleted file mode 100644 index 54d23e88c..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/IFriendService.cs +++ /dev/null @@ -1,374 +0,0 @@ -using LibHac.Ns; -using Ryujinx.Common; -using Ryujinx.Common.Logging; -using Ryujinx.Common.Memory; -using Ryujinx.Common.Utilities; -using Ryujinx.HLE.HOS.Ipc; -using Ryujinx.HLE.HOS.Kernel.Threading; -using Ryujinx.HLE.HOS.Services.Account.Acc; -using Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService; -using Ryujinx.Horizon.Common; -using System; -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator -{ - class IFriendService : IpcService - { -#pragma warning disable IDE0052 // Remove unread private member - private readonly FriendServicePermissionLevel _permissionLevel; -#pragma warning restore IDE0052 - private KEvent _completionEvent; - - public IFriendService(FriendServicePermissionLevel permissionLevel) - { - _permissionLevel = permissionLevel; - } - - [CommandCmif(0)] - // GetCompletionEvent() -> handle - public ResultCode GetCompletionEvent(ServiceCtx context) - { - _completionEvent ??= new KEvent(context.Device.System.KernelContext); - - if (context.Process.HandleTable.GenerateHandle(_completionEvent.ReadableEvent, out int completionEventHandle) != Result.Success) - { - throw new InvalidOperationException("Out of handles!"); - } - - _completionEvent.WritableEvent.Signal(); - - context.Response.HandleDesc = IpcHandleDesc.MakeCopy(completionEventHandle); - - return ResultCode.Success; - } - - [CommandCmif(1)] - // nn::friends::Cancel() - public ResultCode Cancel(ServiceCtx context) - { - // TODO: Original service sets an internal field to 1 here. Determine usage. - Logger.Stub?.PrintStub(LogClass.ServiceFriend); - - return ResultCode.Success; - } - - [CommandCmif(10100)] - // nn::friends::GetFriendListIds(int offset, nn::account::Uid userId, nn::friends::detail::ipc::SizedFriendFilter friendFilter, ulong pidPlaceHolder, pid) - // -> int outCount, array - public ResultCode GetFriendListIds(ServiceCtx context) - { - int offset = context.RequestData.ReadInt32(); - - // Padding - context.RequestData.ReadInt32(); - - UserId userId = context.RequestData.ReadStruct(); - FriendFilter filter = context.RequestData.ReadStruct(); - - // Pid placeholder - context.RequestData.ReadInt64(); - - if (userId.IsNull) - { - return ResultCode.InvalidArgument; - } - - // There are no friends online, so we return 0 because the nn::account::NetworkServiceAccountId array is empty. - context.ResponseData.Write(0); - - Logger.Stub?.PrintStub(LogClass.ServiceFriend, new - { - UserId = userId.ToString(), - offset, - filter.PresenceStatus, - filter.IsFavoriteOnly, - filter.IsSameAppPresenceOnly, - filter.IsSameAppPlayedOnly, - filter.IsArbitraryAppPlayedOnly, - filter.PresenceGroupId, - }); - - return ResultCode.Success; - } - - [CommandCmif(10101)] - // nn::friends::GetFriendList(int offset, nn::account::Uid userId, nn::friends::detail::ipc::SizedFriendFilter friendFilter, ulong pidPlaceHolder, pid) - // -> int outCount, array - public ResultCode GetFriendList(ServiceCtx context) - { - int offset = context.RequestData.ReadInt32(); - - // Padding - context.RequestData.ReadInt32(); - - UserId userId = context.RequestData.ReadStruct(); - FriendFilter filter = context.RequestData.ReadStruct(); - - // Pid placeholder - context.RequestData.ReadInt64(); - - if (userId.IsNull) - { - return ResultCode.InvalidArgument; - } - - // There are no friends online, so we return 0 because the nn::account::NetworkServiceAccountId array is empty. - context.ResponseData.Write(0); - - Logger.Stub?.PrintStub(LogClass.ServiceFriend, new - { - UserId = userId.ToString(), - offset, - filter.PresenceStatus, - filter.IsFavoriteOnly, - filter.IsSameAppPresenceOnly, - filter.IsSameAppPlayedOnly, - filter.IsArbitraryAppPlayedOnly, - filter.PresenceGroupId, - }); - - return ResultCode.Success; - } - - [CommandCmif(10120)] // 10.0.0+ - // nn::friends::IsFriendListCacheAvailable(nn::account::Uid userId) -> bool - public ResultCode IsFriendListCacheAvailable(ServiceCtx context) - { - UserId userId = context.RequestData.ReadStruct(); - - if (userId.IsNull) - { - return ResultCode.InvalidArgument; - } - - // TODO: Service mount the friends:/ system savedata and try to load friend.cache file, returns true if exists, false otherwise. - // NOTE: If no cache is available, guest then calls nn::friends::EnsureFriendListAvailable, we can avoid that by faking the cache check. - context.ResponseData.Write(true); - - // TODO: Since we don't support friend features, it's fine to stub it for now. - Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { UserId = userId.ToString() }); - - return ResultCode.Success; - } - - [CommandCmif(10121)] // 10.0.0+ - // nn::friends::EnsureFriendListAvailable(nn::account::Uid userId) - public ResultCode EnsureFriendListAvailable(ServiceCtx context) - { - UserId userId = context.RequestData.ReadStruct(); - - if (userId.IsNull) - { - return ResultCode.InvalidArgument; - } - - // TODO: Service mount the friends:/ system savedata and create a friend.cache file for the given user id. - // Since we don't support friend features, it's fine to stub it for now. - Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { UserId = userId.ToString() }); - - return ResultCode.Success; - } - - [CommandCmif(10400)] - // nn::friends::GetBlockedUserListIds(int offset, nn::account::Uid userId) -> (u32, buffer) - public ResultCode GetBlockedUserListIds(ServiceCtx context) - { - int offset = context.RequestData.ReadInt32(); - - // Padding - context.RequestData.ReadInt32(); - - UserId userId = context.RequestData.ReadStruct(); - - // There are no friends blocked, so we return 0 because the nn::account::NetworkServiceAccountId array is empty. - context.ResponseData.Write(0); - - Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { offset, UserId = userId.ToString() }); - - return ResultCode.Success; - } - - [CommandCmif(10420)] - // nn::friends::CheckBlockedUserListAvailability(nn::account::Uid userId) -> bool - public ResultCode CheckBlockedUserListAvailability(ServiceCtx context) - { - UserId userId = context.RequestData.ReadStruct(); - - // Yes, it is available. - context.ResponseData.Write(true); - - Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { UserId = userId.ToString() }); - - return ResultCode.Success; - } - - [CommandCmif(10600)] - // nn::friends::DeclareOpenOnlinePlaySession(nn::account::Uid userId) - public ResultCode DeclareOpenOnlinePlaySession(ServiceCtx context) - { - UserId userId = context.RequestData.ReadStruct(); - - if (userId.IsNull) - { - return ResultCode.InvalidArgument; - } - - context.Device.System.AccountManager.OpenUserOnlinePlay(userId); - - Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { UserId = userId.ToString() }); - - return ResultCode.Success; - } - - [CommandCmif(10601)] - // nn::friends::DeclareCloseOnlinePlaySession(nn::account::Uid userId) - public ResultCode DeclareCloseOnlinePlaySession(ServiceCtx context) - { - UserId userId = context.RequestData.ReadStruct(); - - if (userId.IsNull) - { - return ResultCode.InvalidArgument; - } - - context.Device.System.AccountManager.CloseUserOnlinePlay(userId); - - Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { UserId = userId.ToString() }); - - return ResultCode.Success; - } - - [CommandCmif(10610)] - // nn::friends::UpdateUserPresence(nn::account::Uid, u64, pid, buffer) - public ResultCode UpdateUserPresence(ServiceCtx context) - { - UserId uuid = context.RequestData.ReadStruct(); - - // Pid placeholder - context.RequestData.ReadInt64(); - - ulong position = context.Request.PtrBuff[0].Position; - ulong size = context.Request.PtrBuff[0].Size; - - ReadOnlySpan userPresenceInputArray = MemoryMarshal.Cast(context.Memory.GetSpan(position, (int)size)); - - if (uuid.IsNull) - { - return ResultCode.InvalidArgument; - } - - Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { UserId = uuid.ToString(), userPresenceInputArray = userPresenceInputArray.ToArray() }); - - return ResultCode.Success; - } - - [CommandCmif(10700)] - // nn::friends::GetPlayHistoryRegistrationKey(b8 unknown, nn::account::Uid) -> buffer - public ResultCode GetPlayHistoryRegistrationKey(ServiceCtx context) - { - bool unknownBool = context.RequestData.ReadBoolean(); - UserId userId = context.RequestData.ReadStruct(); - - context.Response.PtrBuff[0] = context.Response.PtrBuff[0].WithSize(0x40UL); - - ulong bufferPosition = context.Request.RecvListBuff[0].Position; - - if (userId.IsNull) - { - return ResultCode.InvalidArgument; - } - - // NOTE: Calls nn::friends::detail::service::core::PlayHistoryManager::GetInstance and stores the instance. - - byte[] randomBytes = new byte[8]; - - Random.Shared.NextBytes(randomBytes); - - // NOTE: Calls nn::friends::detail::service::core::UuidManager::GetInstance and stores the instance. - // Then call nn::friends::detail::service::core::AccountStorageManager::GetInstance and store the instance. - // Then it checks if an Uuid is already stored for the UserId, if not it generates a random Uuid. - // And store it in the savedata 8000000000000080 in the friends:/uid.bin file. - - Array16 randomGuid = new(); - - Guid.NewGuid().ToByteArray().AsSpan().CopyTo(randomGuid.AsSpan()); - - PlayHistoryRegistrationKey playHistoryRegistrationKey = new() - { - Type = 0x101, - KeyIndex = (byte)(randomBytes[0] & 7), - UserIdBool = 0, // TODO: Find it. - UnknownBool = (byte)(unknownBool ? 1 : 0), // TODO: Find it. - Reserved = new Array11(), - Uuid = randomGuid, - }; - - ReadOnlySpan playHistoryRegistrationKeyBuffer = SpanHelpers.AsByteSpan(ref playHistoryRegistrationKey); - - /* - - NOTE: The service uses the KeyIndex to get a random key from a keys buffer (since the key index is stored in the returned buffer). - We currently don't support play history and online services so we can use a blank key for now. - Code for reference: - - byte[] hmacKey = new byte[0x20]; - - HMACSHA256 hmacSha256 = new HMACSHA256(hmacKey); - byte[] hmacHash = hmacSha256.ComputeHash(playHistoryRegistrationKeyBuffer); - - */ - - context.Memory.Write(bufferPosition, playHistoryRegistrationKeyBuffer); - context.Memory.Write(bufferPosition + 0x20, new byte[0x20]); // HmacHash - - return ResultCode.Success; - } - - [CommandCmif(10702)] - // nn::friends::AddPlayHistory(nn::account::Uid, u64, pid, buffer, buffer, buffer) - public ResultCode AddPlayHistory(ServiceCtx context) - { - UserId userId = context.RequestData.ReadStruct(); - - // Pid placeholder - context.RequestData.ReadInt64(); -#pragma warning disable IDE0059 // Remove unnecessary value assignment - ulong pid = context.Request.HandleDesc.PId; - - ulong playHistoryRegistrationKeyPosition = context.Request.PtrBuff[0].Position; - ulong playHistoryRegistrationKeySize = context.Request.PtrBuff[0].Size; - - ulong inAppScreenName1Position = context.Request.PtrBuff[1].Position; -#pragma warning restore IDE0059 - ulong inAppScreenName1Size = context.Request.PtrBuff[1].Size; - -#pragma warning disable IDE0059 // Remove unnecessary value assignment - ulong inAppScreenName2Position = context.Request.PtrBuff[2].Position; -#pragma warning restore IDE0059 - ulong inAppScreenName2Size = context.Request.PtrBuff[2].Size; - - if (userId.IsNull || inAppScreenName1Size > 0x48 || inAppScreenName2Size > 0x48) - { - return ResultCode.InvalidArgument; - } - - // TODO: Call nn::arp::GetApplicationControlProperty here when implemented. -#pragma warning disable IDE0059 // Remove unnecessary value assignment - ApplicationControlProperty controlProperty = context.Device.Processes.ActiveApplication.ApplicationControlProperties; -#pragma warning restore IDE0059 - - /* - - NOTE: The service calls nn::friends::detail::service::core::PlayHistoryManager to store informations using the registration key computed in GetPlayHistoryRegistrationKey. - Then calls nn::friends::detail::service::core::FriendListManager to update informations on the friend list. - We currently don't support play history and online services so it's fine to do nothing. - - */ - - Logger.Stub?.PrintStub(LogClass.ServiceFriend); - - return ResultCode.Success; - } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/INotificationService.cs b/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/INotificationService.cs deleted file mode 100644 index 8fc7a4609..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/INotificationService.cs +++ /dev/null @@ -1,178 +0,0 @@ -using Ryujinx.Common; -using Ryujinx.HLE.HOS.Ipc; -using Ryujinx.HLE.HOS.Kernel.Threading; -using Ryujinx.HLE.HOS.Services.Account.Acc; -using Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.NotificationService; -using Ryujinx.Horizon.Common; -using System; -using System.Collections.Generic; - -namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator -{ - class INotificationService : DisposableIpcService - { - private readonly UserId _userId; - private readonly FriendServicePermissionLevel _permissionLevel; - - private readonly object _lock = new(); - - private readonly KEvent _notificationEvent; - private int _notificationEventHandle = 0; - - private readonly LinkedList _notifications; - - private bool _hasNewFriendRequest; - private bool _hasFriendListUpdate; - - public INotificationService(ServiceCtx context, UserId userId, FriendServicePermissionLevel permissionLevel) - { - _userId = userId; - _permissionLevel = permissionLevel; - _notifications = new LinkedList(); - _notificationEvent = new KEvent(context.Device.System.KernelContext); - - _hasNewFriendRequest = false; - _hasFriendListUpdate = false; - - NotificationEventHandler.Instance.RegisterNotificationService(this); - } - - [CommandCmif(0)] //2.0.0+ - // nn::friends::detail::ipc::INotificationService::GetEvent() -> handle - public ResultCode GetEvent(ServiceCtx context) - { - if (_notificationEventHandle == 0) - { - if (context.Process.HandleTable.GenerateHandle(_notificationEvent.ReadableEvent, out _notificationEventHandle) != Result.Success) - { - throw new InvalidOperationException("Out of handles!"); - } - } - - context.Response.HandleDesc = IpcHandleDesc.MakeCopy(_notificationEventHandle); - - return ResultCode.Success; - } - - [CommandCmif(1)] //2.0.0+ - // nn::friends::detail::ipc::INotificationService::Clear() - public ResultCode Clear(ServiceCtx context) - { - lock (_lock) - { - _hasNewFriendRequest = false; - _hasFriendListUpdate = false; - - _notifications.Clear(); - } - - return ResultCode.Success; - } - - [CommandCmif(2)] // 2.0.0+ - // nn::friends::detail::ipc::INotificationService::Pop() -> nn::friends::detail::ipc::SizedNotificationInfo - public ResultCode Pop(ServiceCtx context) - { - lock (_lock) - { - if (_notifications.Count >= 1) - { - NotificationInfo notificationInfo = _notifications.First.Value; - _notifications.RemoveFirst(); - - if (notificationInfo.Type == NotificationEventType.FriendListUpdate) - { - _hasFriendListUpdate = false; - } - else if (notificationInfo.Type == NotificationEventType.NewFriendRequest) - { - _hasNewFriendRequest = false; - } - - context.ResponseData.WriteStruct(notificationInfo); - - return ResultCode.Success; - } - } - - return ResultCode.NotificationQueueEmpty; - } - - public void SignalFriendListUpdate(UserId targetId) - { - lock (_lock) - { - if (_userId == targetId) - { - if (!_hasFriendListUpdate) - { - NotificationInfo friendListNotification = new(); - - if (_notifications.Count != 0) - { - friendListNotification = _notifications.First.Value; - _notifications.RemoveFirst(); - } - - friendListNotification.Type = NotificationEventType.FriendListUpdate; - _hasFriendListUpdate = true; - - if (_hasNewFriendRequest) - { - NotificationInfo newFriendRequestNotification = new(); - - if (_notifications.Count != 0) - { - newFriendRequestNotification = _notifications.First.Value; - _notifications.RemoveFirst(); - } - - newFriendRequestNotification.Type = NotificationEventType.NewFriendRequest; - _notifications.AddFirst(newFriendRequestNotification); - } - - // We defer this to make sure we are on top of the queue. - _notifications.AddFirst(friendListNotification); - } - - _notificationEvent.ReadableEvent.Signal(); - } - } - } - - public void SignalNewFriendRequest(UserId targetId) - { - lock (_lock) - { - if ((_permissionLevel & FriendServicePermissionLevel.ViewerMask) != 0 && _userId == targetId) - { - if (!_hasNewFriendRequest) - { - if (_notifications.Count == 100) - { - SignalFriendListUpdate(targetId); - } - - NotificationInfo newFriendRequestNotification = new() - { - Type = NotificationEventType.NewFriendRequest, - }; - - _notifications.AddLast(newFriendRequestNotification); - _hasNewFriendRequest = true; - } - - _notificationEvent.ReadableEvent.Signal(); - } - } - } - - protected override void Dispose(bool isDisposing) - { - if (isDisposing) - { - NotificationEventHandler.Instance.UnregisterNotificationService(this); - } - } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/NotificationService/NotificationEventHandler.cs b/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/NotificationService/NotificationEventHandler.cs deleted file mode 100644 index 88627fd78..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/NotificationService/NotificationEventHandler.cs +++ /dev/null @@ -1,74 +0,0 @@ -using Ryujinx.HLE.HOS.Services.Account.Acc; - -namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.NotificationService -{ - public sealed class NotificationEventHandler - { - private static NotificationEventHandler _instance; - private static readonly object _instanceLock = new(); - - private readonly INotificationService[] _registry; - - public static NotificationEventHandler Instance - { - get - { - lock (_instanceLock) - { - _instance ??= new NotificationEventHandler(); - - return _instance; - } - } - } - - NotificationEventHandler() - { - _registry = new INotificationService[0x20]; - } - - internal void RegisterNotificationService(INotificationService service) - { - // NOTE: in case there isn't space anymore in the registry array, Nintendo doesn't return any errors. - for (int i = 0; i < _registry.Length; i++) - { - if (_registry[i] == null) - { - _registry[i] = service; - break; - } - } - } - - internal void UnregisterNotificationService(INotificationService service) - { - // NOTE: in case there isn't the entry in the registry array, Nintendo doesn't return any errors. - for (int i = 0; i < _registry.Length; i++) - { - if (_registry[i] == service) - { - _registry[i] = null; - break; - } - } - } - - // TODO: Use this when we will have enough things to go online. - public void SignalFriendListUpdate(UserId targetId) - { - for (int i = 0; i < _registry.Length; i++) - { - _registry[i]?.SignalFriendListUpdate(targetId); - } - } - - // TODO: Use this when we will have enough things to go online. - public void SignalNewFriendRequest(UserId targetId) - { - for (int i = 0; i < _registry.Length; i++) - { - _registry[i]?.SignalNewFriendRequest(targetId); - } - } - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/NotificationService/Types/NotificationInfo.cs b/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/NotificationService/Types/NotificationInfo.cs deleted file mode 100644 index aa58433d8..000000000 --- a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/NotificationService/Types/NotificationInfo.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Ryujinx.Common.Memory; -using System.Runtime.InteropServices; - -namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.NotificationService -{ - [StructLayout(LayoutKind.Sequential, Size = 0x10)] - struct NotificationInfo - { - public NotificationEventType Type; - private Array4 _padding; - public long NetworkUserIdPlaceholder; - } -} diff --git a/src/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IFileSystem.cs b/src/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IFileSystem.cs index 66020d57b..e19d17912 100644 --- a/src/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IFileSystem.cs +++ b/src/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/IFileSystem.cs @@ -2,6 +2,7 @@ using LibHac; using LibHac.Common; using LibHac.Fs; using LibHac.Fs.Fsa; +using Ryujinx.Common.Logging; using Path = LibHac.FsSrv.Sf.Path; namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy @@ -149,7 +150,13 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy // Commit() public ResultCode Commit(ServiceCtx context) { - return (ResultCode)_fileSystem.Get.Commit().Value; + ResultCode resultCode = (ResultCode)_fileSystem.Get.Commit().Value; + if (resultCode == ResultCode.PathAlreadyInUse) + { + Logger.Warning?.Print(LogClass.ServiceFs, "The file system is already in use by another process."); + } + + return resultCode; } [CommandCmif(11)] diff --git a/src/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/LazyFile.cs b/src/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/LazyFile.cs new file mode 100644 index 000000000..a179e8e38 --- /dev/null +++ b/src/Ryujinx.HLE/HOS/Services/Fs/FileSystemProxy/LazyFile.cs @@ -0,0 +1,65 @@ +using LibHac; +using LibHac.Common; +using LibHac.Fs; +using System; +using System.IO; + +namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy +{ + class LazyFile : LibHac.Fs.Fsa.IFile + { + private readonly LibHac.Fs.Fsa.IFileSystem _fs; + private readonly string _filePath; + private readonly UniqueRef _fileReference = new(); + private readonly FileInfo _fileInfo; + + public LazyFile(string filePath, string prefix, LibHac.Fs.Fsa.IFileSystem fs) + { + _fs = fs; + _filePath = filePath; + _fileInfo = new FileInfo(prefix + "/" + filePath); + } + + private void PrepareFile() + { + if (_fileReference.Get == null) + { + _fs.OpenFile(ref _fileReference.Ref, _filePath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); + } + } + + protected override Result DoRead(out long bytesRead, long offset, Span destination, in ReadOption option) + { + PrepareFile(); + + return _fileReference.Get!.Read(out bytesRead, offset, destination); + } + + protected override Result DoWrite(long offset, ReadOnlySpan source, in WriteOption option) + { + throw new NotSupportedException(); + } + + protected override Result DoFlush() + { + throw new NotSupportedException(); + } + + protected override Result DoSetSize(long size) + { + throw new NotSupportedException(); + } + + protected override Result DoGetSize(out long size) + { + size = _fileInfo.Length; + + return Result.Success; + } + + protected override Result DoOperateRange(Span outBuffer, OperationId operationId, long offset, long size, ReadOnlySpan inBuffer) + { + throw new NotSupportedException(); + } + } +} diff --git a/src/Ryujinx.HLE/HOS/Services/Nv/Host1xContext.cs b/src/Ryujinx.HLE/HOS/Services/Nv/Host1xContext.cs index 371edbecd..7c7ebf22d 100644 --- a/src/Ryujinx.HLE/HOS/Services/Nv/Host1xContext.cs +++ b/src/Ryujinx.HLE/HOS/Services/Nv/Host1xContext.cs @@ -1,4 +1,4 @@ -using Ryujinx.Graphics.Gpu.Memory; +using Ryujinx.Graphics.Device; using Ryujinx.Graphics.Host1x; using Ryujinx.Graphics.Nvdec; using Ryujinx.Graphics.Vic; @@ -9,7 +9,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv { class Host1xContext : IDisposable { - public MemoryManager Smmu { get; } + public DeviceMemoryManager Smmu { get; } public NvMemoryAllocator MemoryAllocator { get; } public Host1xDevice Host1x { get; } @@ -17,7 +17,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv { MemoryAllocator = new NvMemoryAllocator(); Host1x = new Host1xDevice(gpu.Synchronization); - Smmu = gpu.CreateMemoryManager(pid); + Smmu = gpu.CreateDeviceMemoryManager(pid); var nvdec = new NvdecDevice(Smmu); var vic = new VicDevice(Smmu); Host1x.RegisterDevice(ClassId.Nvdec, nvdec); diff --git a/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/NvHostAsGpuDeviceFile.cs b/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/NvHostAsGpuDeviceFile.cs index 03c4ed860..ff9a67644 100644 --- a/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/NvHostAsGpuDeviceFile.cs +++ b/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/NvHostAsGpuDeviceFile.cs @@ -266,7 +266,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu if (size == 0) { - size = (uint)map.Size; + size = map.Size; } NvInternalResult result = NvInternalResult.Success; diff --git a/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostChannelDeviceFile.cs b/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostChannelDeviceFile.cs index 53db5eca4..bc70b05cf 100644 --- a/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostChannelDeviceFile.cs +++ b/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostChannel/NvHostChannelDeviceFile.cs @@ -250,12 +250,12 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostChannel { if (map.DmaMapAddress == 0) { - ulong va = _host1xContext.MemoryAllocator.GetFreeAddress((ulong)map.Size, out ulong freeAddressStartPosition, 1, MemoryManager.PageSize); + ulong va = _host1xContext.MemoryAllocator.GetFreeAddress(map.Size, out ulong freeAddressStartPosition, 1, MemoryManager.PageSize); - if (va != NvMemoryAllocator.PteUnmapped && va <= uint.MaxValue && (va + (uint)map.Size) <= uint.MaxValue) + if (va != NvMemoryAllocator.PteUnmapped && va <= uint.MaxValue && (va + map.Size) <= uint.MaxValue) { - _host1xContext.MemoryAllocator.AllocateRange(va, (uint)map.Size, freeAddressStartPosition); - _host1xContext.Smmu.Map(map.Address, va, (uint)map.Size, PteKind.Pitch); // FIXME: This should not use the GMMU. + _host1xContext.MemoryAllocator.AllocateRange(va, map.Size, freeAddressStartPosition); + _host1xContext.Smmu.Map(map.Address, va, map.Size); map.DmaMapAddress = va; } else diff --git a/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/NvMapDeviceFile.cs b/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/NvMapDeviceFile.cs index abe0a4de8..6a0ac58bd 100644 --- a/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/NvMapDeviceFile.cs +++ b/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/NvMapDeviceFile.cs @@ -69,7 +69,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap return NvInternalResult.InvalidInput; } - int size = BitUtils.AlignUp(arguments.Size, (int)MemoryManager.PageSize); + uint size = BitUtils.AlignUp(arguments.Size, (uint)MemoryManager.PageSize); arguments.Handle = CreateHandleFromMap(new NvMapHandle(size)); @@ -128,7 +128,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap map.Align = arguments.Align; map.Kind = (byte)arguments.Kind; - int size = BitUtils.AlignUp(map.Size, (int)MemoryManager.PageSize); + uint size = BitUtils.AlignUp(map.Size, (uint)MemoryManager.PageSize); ulong address = arguments.Address; @@ -191,7 +191,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap switch (arguments.Param) { case NvMapHandleParam.Size: - arguments.Result = map.Size; + arguments.Result = (int)map.Size; break; case NvMapHandleParam.Align: arguments.Result = map.Align; diff --git a/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapCreate.cs b/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapCreate.cs index 5380c45c7..f4047497a 100644 --- a/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapCreate.cs +++ b/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapCreate.cs @@ -5,7 +5,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap [StructLayout(LayoutKind.Sequential)] struct NvMapCreate { - public int Size; + public uint Size; public int Handle; } } diff --git a/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapFree.cs b/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapFree.cs index b0b3fa2d6..ce93e9e5e 100644 --- a/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapFree.cs +++ b/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapFree.cs @@ -8,7 +8,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap public int Handle; public int Padding; public ulong Address; - public int Size; + public uint Size; public int Flags; } } diff --git a/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapHandle.cs b/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapHandle.cs index 301179747..e821b571d 100644 --- a/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapHandle.cs +++ b/src/Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvMap/Types/NvMapHandle.cs @@ -8,7 +8,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap public int Handle; public int Id; #pragma warning restore CS0649 - public int Size; + public uint Size; public int Align; public int Kind; public ulong Address; @@ -22,7 +22,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvMap _dupes = 1; } - public NvMapHandle(int size) : this() + public NvMapHandle(uint size) : this() { Size = size; } diff --git a/src/Ryujinx.HLE/HOS/Services/Pctl/ParentalControlServiceFactory/IParentalControlService.cs b/src/Ryujinx.HLE/HOS/Services/Pctl/ParentalControlServiceFactory/IParentalControlService.cs index cf8c1f78d..9b026a1c3 100644 --- a/src/Ryujinx.HLE/HOS/Services/Pctl/ParentalControlServiceFactory/IParentalControlService.cs +++ b/src/Ryujinx.HLE/HOS/Services/Pctl/ParentalControlServiceFactory/IParentalControlService.cs @@ -159,9 +159,7 @@ namespace Ryujinx.HLE.HOS.Services.Pctl.ParentalControlServiceFactory } else { -#pragma warning disable CS0162 // Unreachable code return ResultCode.StereoVisionRestrictionConfigurableDisabled; -#pragma warning restore CS0162 } } diff --git a/src/Ryujinx.HLE/HOS/Services/ServerBase.cs b/src/Ryujinx.HLE/HOS/Services/ServerBase.cs index e892d6ab6..5e18d7981 100644 --- a/src/Ryujinx.HLE/HOS/Services/ServerBase.cs +++ b/src/Ryujinx.HLE/HOS/Services/ServerBase.cs @@ -287,6 +287,10 @@ namespace Ryujinx.HLE.HOS.Services _wakeEvent.WritableEvent.Clear(); } } + else if (rc == KernelResult.PortRemoteClosed && signaledIndex >= 0 && SmObjectFactory != null) + { + DestroySession(handles[signaledIndex]); + } _selfProcess.CpuMemory.Write(messagePtr + 0x0, 0); _selfProcess.CpuMemory.Write(messagePtr + 0x4, 2 << 10); @@ -299,6 +303,16 @@ namespace Ryujinx.HLE.HOS.Services Dispose(); } + private void DestroySession(int serverSessionHandle) + { + _context.Syscall.CloseHandle(serverSessionHandle); + + if (RemoveSessionObj(serverSessionHandle, out var session)) + { + (session as IDisposable)?.Dispose(); + } + } + private bool Process(int serverSessionHandle, ulong recvListAddr) { IpcMessage request = ReadRequest(); @@ -360,7 +374,7 @@ namespace Ryujinx.HLE.HOS.Services response.RawData = _responseDataStream.ToArray(); } else if (request.Type == IpcMessageType.CmifControl || - request.Type == IpcMessageType.CmifControlWithContext) + request.Type == IpcMessageType.CmifControlWithContext) { #pragma warning disable IDE0059 // Remove unnecessary value assignment uint magic = (uint)_requestDataReader.ReadUInt64(); @@ -412,11 +426,7 @@ namespace Ryujinx.HLE.HOS.Services } else if (request.Type == IpcMessageType.CmifCloseSession || request.Type == IpcMessageType.TipcCloseSession) { - _context.Syscall.CloseHandle(serverSessionHandle); - if (RemoveSessionObj(serverSessionHandle, out var session)) - { - (session as IDisposable)?.Dispose(); - } + DestroySession(serverSessionHandle); shouldReply = false; } // If the type is past 0xF, we are using TIPC diff --git a/src/Ryujinx.HLE/HOS/Services/Sockets/Bsd/IClient.cs b/src/Ryujinx.HLE/HOS/Services/Sockets/Bsd/IClient.cs index 870a6b36c..1e8a90051 100644 --- a/src/Ryujinx.HLE/HOS/Services/Sockets/Bsd/IClient.cs +++ b/src/Ryujinx.HLE/HOS/Services/Sockets/Bsd/IClient.cs @@ -121,7 +121,14 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd { IPEndPoint endPoint = isRemote ? socket.RemoteEndPoint : socket.LocalEndPoint; - context.Memory.Write(bufferPosition, BsdSockAddr.FromIPEndPoint(endPoint)); + if (endPoint != null) + { + context.Memory.Write(bufferPosition, BsdSockAddr.FromIPEndPoint(endPoint)); + } + else + { + context.Memory.Write(bufferPosition, new BsdSockAddr()); + } } [CommandCmif(0)] diff --git a/src/Ryujinx.HLE/HOS/Services/Ssl/SslService/SslManagedSocketConnection.cs b/src/Ryujinx.HLE/HOS/Services/Ssl/SslService/SslManagedSocketConnection.cs index 4dd6367ed..8cc761baf 100644 --- a/src/Ryujinx.HLE/HOS/Services/Ssl/SslService/SslManagedSocketConnection.cs +++ b/src/Ryujinx.HLE/HOS/Services/Ssl/SslService/SslManagedSocketConnection.cs @@ -3,6 +3,7 @@ using Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl; using Ryujinx.HLE.HOS.Services.Ssl.Types; using System; using System.IO; +using System.Net; using System.Net.Security; using System.Net.Sockets; using System.Security.Authentication; @@ -83,10 +84,40 @@ namespace Ryujinx.HLE.HOS.Services.Ssl.SslService } #pragma warning restore SYSLIB0039 + /// + /// Retrieve the hostname of the current remote in case the provided hostname is null or empty. + /// + /// The current hostname + /// Either the resolved or provided hostname + /// + /// This is done to avoid getting an + /// as the remote certificate will be rejected with RemoteCertificateNameMismatch due to an empty hostname. + /// This is not what the switch does! + /// It might just skip remote hostname verification if the hostname wasn't set with before. + /// TODO: Remove this as soon as we know how the switch deals with empty hostnames + /// + private string RetrieveHostName(string hostName) + { + if (!string.IsNullOrEmpty(hostName)) + { + return hostName; + } + + try + { + return Dns.GetHostEntry(Socket.RemoteEndPoint.Address).HostName; + } + catch (SocketException) + { + return hostName; + } + } + public ResultCode Handshake(string hostName) { StartSslOperation(); _stream = new SslStream(new NetworkStream(((ManagedSocket)Socket).Socket, false), false, null, null); + hostName = RetrieveHostName(hostName); _stream.AuthenticateAsClient(hostName, null, TranslateSslVersion(_sslVersion), false); EndSslOperation(); diff --git a/src/Ryujinx.HLE/HOS/Services/Vi/RootService/IApplicationDisplayService.cs b/src/Ryujinx.HLE/HOS/Services/Vi/RootService/IApplicationDisplayService.cs index 143e21661..b6988f08d 100644 --- a/src/Ryujinx.HLE/HOS/Services/Vi/RootService/IApplicationDisplayService.cs +++ b/src/Ryujinx.HLE/HOS/Services/Vi/RootService/IApplicationDisplayService.cs @@ -7,7 +7,7 @@ using Ryujinx.HLE.HOS.Services.SurfaceFlinger; using Ryujinx.HLE.HOS.Services.Vi.RootService.ApplicationDisplayService; using Ryujinx.HLE.HOS.Services.Vi.RootService.ApplicationDisplayService.Types; using Ryujinx.HLE.HOS.Services.Vi.Types; -using Ryujinx.HLE.Ui; +using Ryujinx.HLE.UI; using Ryujinx.Horizon.Common; using System; using System.Collections.Generic; diff --git a/src/Ryujinx.HLE/Loaders/Processes/Extensions/FileSystemExtensions.cs b/src/Ryujinx.HLE/Loaders/Processes/Extensions/FileSystemExtensions.cs index 28f6fcff4..3904d660e 100644 --- a/src/Ryujinx.HLE/Loaders/Processes/Extensions/FileSystemExtensions.cs +++ b/src/Ryujinx.HLE/Loaders/Processes/Extensions/FileSystemExtensions.cs @@ -34,7 +34,7 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions return metaLoader; } - public static ProcessResult Load(this IFileSystem exeFs, Switch device, BlitStruct nacpData, MetaLoader metaLoader, bool isHomebrew = false) + public static ProcessResult Load(this IFileSystem exeFs, Switch device, BlitStruct nacpData, MetaLoader metaLoader, byte programIndex, bool isHomebrew = false) { ulong programId = metaLoader.GetProgramId(); @@ -119,6 +119,7 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions true, programName, metaLoader.GetProgramId(), + programIndex, null, nsoExecutables); diff --git a/src/Ryujinx.HLE/Loaders/Processes/Extensions/LocalFileSystemExtensions.cs b/src/Ryujinx.HLE/Loaders/Processes/Extensions/LocalFileSystemExtensions.cs index 798a9261e..6c2415e46 100644 --- a/src/Ryujinx.HLE/Loaders/Processes/Extensions/LocalFileSystemExtensions.cs +++ b/src/Ryujinx.HLE/Loaders/Processes/Extensions/LocalFileSystemExtensions.cs @@ -16,17 +16,14 @@ namespace Ryujinx.HLE.Loaders.Processes var nacpData = new BlitStruct(1); ulong programId = metaLoader.GetProgramId(); - device.Configuration.VirtualFileSystem.ModLoader.CollectMods( - new[] { programId }, - ModLoader.GetModsBasePath(), - ModLoader.GetSdModsBasePath()); + device.Configuration.VirtualFileSystem.ModLoader.CollectMods(new[] { programId }); if (programId != 0) { ProcessLoaderHelper.EnsureSaveData(device, new ApplicationId(programId), nacpData); } - ProcessResult processResult = exeFs.Load(device, nacpData, metaLoader); + ProcessResult processResult = exeFs.Load(device, nacpData, metaLoader, 0); // Load RomFS. if (!string.IsNullOrEmpty(romFsPath)) diff --git a/src/Ryujinx.HLE/Loaders/Processes/Extensions/NcaExtensions.cs b/src/Ryujinx.HLE/Loaders/Processes/Extensions/NcaExtensions.cs index e369f4b04..e70fcb6fc 100644 --- a/src/Ryujinx.HLE/Loaders/Processes/Extensions/NcaExtensions.cs +++ b/src/Ryujinx.HLE/Loaders/Processes/Extensions/NcaExtensions.cs @@ -61,7 +61,7 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions */ - ProcessResult processResult = exeFs.Load(device, nacpData, metaLoader); + ProcessResult processResult = exeFs.Load(device, nacpData, metaLoader, (byte)nca.GetProgramIndex()); // Load RomFS. if (romFs == null) diff --git a/src/Ryujinx.HLE/Loaders/Processes/ProcessLoader.cs b/src/Ryujinx.HLE/Loaders/Processes/ProcessLoader.cs index efeb9f613..e5056c89a 100644 --- a/src/Ryujinx.HLE/Loaders/Processes/ProcessLoader.cs +++ b/src/Ryujinx.HLE/Loaders/Processes/ProcessLoader.cs @@ -77,7 +77,7 @@ namespace Ryujinx.HLE.Loaders.Processes if (processResult.ProcessId == 0) { // This is not a normal NSP, it's actually a ExeFS as a NSP - processResult = partitionFileSystem.Load(_device, new BlitStruct(1), partitionFileSystem.GetNpdm(), true); + processResult = partitionFileSystem.Load(_device, new BlitStruct(1), partitionFileSystem.GetNpdm(), 0, true); } if (processResult.ProcessId != 0 && _processesByPid.TryAdd(processResult.ProcessId, processResult)) @@ -198,7 +198,7 @@ namespace Ryujinx.HLE.Loaders.Processes } else { - programName = System.IO.Path.GetFileNameWithoutExtension(path); + programName = Path.GetFileNameWithoutExtension(path); executable = new NsoExecutable(new LocalStorage(path, FileAccess.Read), programName); } @@ -215,6 +215,7 @@ namespace Ryujinx.HLE.Loaders.Processes allowCodeMemoryForJit: true, programName, programId, + 0, null, executable); diff --git a/src/Ryujinx.HLE/Loaders/Processes/ProcessLoaderHelper.cs b/src/Ryujinx.HLE/Loaders/Processes/ProcessLoaderHelper.cs index a6a1d87e0..fe2aaac6d 100644 --- a/src/Ryujinx.HLE/Loaders/Processes/ProcessLoaderHelper.cs +++ b/src/Ryujinx.HLE/Loaders/Processes/ProcessLoaderHelper.cs @@ -19,6 +19,7 @@ using Ryujinx.HLE.HOS.Kernel.Process; using Ryujinx.HLE.Loaders.Executables; using Ryujinx.HLE.Loaders.Processes.Extensions; using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Arp; using System; using System.Linq; using System.Runtime.InteropServices; @@ -229,6 +230,7 @@ namespace Ryujinx.HLE.Loaders.Processes bool allowCodeMemoryForJit, string name, ulong programId, + byte programIndex, byte[] arguments = null, params IExecutable[] executables) { @@ -421,7 +423,7 @@ namespace Ryujinx.HLE.Loaders.Processes // Once everything is loaded, we can load cheats. device.Configuration.VirtualFileSystem.ModLoader.LoadCheats(programId, tamperInfo, device.TamperMachine); - return new ProcessResult( + ProcessResult processResult = new( metaLoader, applicationControlProperties, diskCacheEnabled, @@ -431,6 +433,25 @@ namespace Ryujinx.HLE.Loaders.Processes meta.MainThreadPriority, meta.MainThreadStackSize, device.System.State.DesiredTitleLanguage); + + // Register everything in arp service. + device.System.ServiceTable.ArpWriter.AcquireRegistrar(out IRegistrar registrar); + registrar.SetApplicationControlProperty(MemoryMarshal.Cast(applicationControlProperties.ByteSpan)[0]); + // TODO: Handle Version and StorageId when it will be needed. + registrar.SetApplicationLaunchProperty(new ApplicationLaunchProperty() + { + ApplicationId = new Horizon.Sdk.Ncm.ApplicationId(programId), + Version = 0x00, + Storage = Horizon.Sdk.Ncm.StorageId.BuiltInUser, + PatchStorage = Horizon.Sdk.Ncm.StorageId.None, + ApplicationKind = ApplicationKind.Application, + }); + + device.System.ServiceTable.ArpReader.GetApplicationInstanceId(out ulong applicationInstanceId, process.Pid); + device.System.ServiceTable.ArpWriter.AcquireApplicationProcessPropertyUpdater(out IUpdater updater, applicationInstanceId); + updater.SetApplicationProcessProperty(process.Pid, new ApplicationProcessProperty() { ProgramIndex = programIndex }); + + return processResult; } public static Result LoadIntoMemory(KProcess process, IExecutable image, ulong baseAddress) diff --git a/src/Ryujinx.HLE/Switch.cs b/src/Ryujinx.HLE/Switch.cs index ae063a47d..498714dcd 100644 --- a/src/Ryujinx.HLE/Switch.cs +++ b/src/Ryujinx.HLE/Switch.cs @@ -7,7 +7,7 @@ using Ryujinx.HLE.HOS; using Ryujinx.HLE.HOS.Services.Apm; using Ryujinx.HLE.HOS.Services.Hid; using Ryujinx.HLE.Loaders.Processes; -using Ryujinx.HLE.Ui; +using Ryujinx.HLE.UI; using Ryujinx.Memory; using System; @@ -25,7 +25,7 @@ namespace Ryujinx.HLE public PerformanceStatistics Statistics { get; } public Hid Hid { get; } public TamperMachine TamperMachine { get; } - public IHostUiHandler UiHandler { get; } + public IHostUIHandler UIHandler { get; } public bool EnableDeviceVsync { get; set; } = true; @@ -39,7 +39,7 @@ namespace Ryujinx.HLE Configuration = configuration; FileSystem = Configuration.VirtualFileSystem; - UiHandler = Configuration.HostUiHandler; + UIHandler = Configuration.HostUIHandler; MemoryAllocationFlags memoryAllocationFlags = configuration.MemoryManagerMode == MemoryManagerMode.SoftwarePageTable ? MemoryAllocationFlags.Reserve diff --git a/src/Ryujinx.HLE/Ui/DynamicTextChangedHandler.cs b/src/Ryujinx.HLE/UI/DynamicTextChangedHandler.cs similarity index 82% rename from src/Ryujinx.HLE/Ui/DynamicTextChangedHandler.cs rename to src/Ryujinx.HLE/UI/DynamicTextChangedHandler.cs index cb9ca0dec..c0945259b 100644 --- a/src/Ryujinx.HLE/Ui/DynamicTextChangedHandler.cs +++ b/src/Ryujinx.HLE/UI/DynamicTextChangedHandler.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.HLE.Ui +namespace Ryujinx.HLE.UI { public delegate void DynamicTextChangedHandler(string text, int cursorBegin, int cursorEnd, bool overwriteMode); } diff --git a/src/Ryujinx.HLE/Ui/IDynamicTextInputHandler.cs b/src/Ryujinx.HLE/UI/IDynamicTextInputHandler.cs similarity index 94% rename from src/Ryujinx.HLE/Ui/IDynamicTextInputHandler.cs rename to src/Ryujinx.HLE/UI/IDynamicTextInputHandler.cs index e530d2c4e..1ff451d10 100644 --- a/src/Ryujinx.HLE/Ui/IDynamicTextInputHandler.cs +++ b/src/Ryujinx.HLE/UI/IDynamicTextInputHandler.cs @@ -1,6 +1,6 @@ using System; -namespace Ryujinx.HLE.Ui +namespace Ryujinx.HLE.UI { public interface IDynamicTextInputHandler : IDisposable { diff --git a/src/Ryujinx.HLE/Ui/IHostUiHandler.cs b/src/Ryujinx.HLE/UI/IHostUIHandler.cs similarity index 89% rename from src/Ryujinx.HLE/Ui/IHostUiHandler.cs rename to src/Ryujinx.HLE/UI/IHostUIHandler.cs index 68f78f22d..3b3a430ee 100644 --- a/src/Ryujinx.HLE/Ui/IHostUiHandler.cs +++ b/src/Ryujinx.HLE/UI/IHostUIHandler.cs @@ -1,16 +1,16 @@ using Ryujinx.HLE.HOS.Applets; using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types; -namespace Ryujinx.HLE.Ui +namespace Ryujinx.HLE.UI { - public interface IHostUiHandler + public interface IHostUIHandler { /// /// Displays an Input Dialog box to the user and blocks until text is entered. /// /// Text that the user entered. Set to `null` on internal errors /// True when OK is pressed, False otherwise. Also returns True on internal errors - bool DisplayInputDialog(SoftwareKeyboardUiArgs args, out string userText); + bool DisplayInputDialog(SoftwareKeyboardUIArgs args, out string userText); /// /// Displays a Message Dialog box to the user and blocks until it is closed. @@ -22,7 +22,7 @@ namespace Ryujinx.HLE.Ui /// Displays a Message Dialog box specific to Controller Applet and blocks until it is closed. /// /// True when OK is pressed, False otherwise. - bool DisplayMessageDialog(ControllerAppletUiArgs args); + bool DisplayMessageDialog(ControllerAppletUIArgs args); /// /// Tell the UI that we need to transisition to another program. @@ -46,6 +46,6 @@ namespace Ryujinx.HLE.Ui /// /// Gets fonts and colors used by the host. /// - IHostUiTheme HostUiTheme { get; } + IHostUITheme HostUITheme { get; } } } diff --git a/src/Ryujinx.HLE/Ui/IHostUiTheme.cs b/src/Ryujinx.HLE/UI/IHostUITheme.cs similarity index 83% rename from src/Ryujinx.HLE/Ui/IHostUiTheme.cs rename to src/Ryujinx.HLE/UI/IHostUITheme.cs index 11d82361a..3b0544004 100644 --- a/src/Ryujinx.HLE/Ui/IHostUiTheme.cs +++ b/src/Ryujinx.HLE/UI/IHostUITheme.cs @@ -1,6 +1,6 @@ -namespace Ryujinx.HLE.Ui +namespace Ryujinx.HLE.UI { - public interface IHostUiTheme + public interface IHostUITheme { string FontFamily { get; } diff --git a/src/Ryujinx.HLE/Ui/Input/NpadButtonHandler.cs b/src/Ryujinx.HLE/UI/Input/NpadButtonHandler.cs similarity index 81% rename from src/Ryujinx.HLE/Ui/Input/NpadButtonHandler.cs rename to src/Ryujinx.HLE/UI/Input/NpadButtonHandler.cs index 2d1c1c491..73c306614 100644 --- a/src/Ryujinx.HLE/Ui/Input/NpadButtonHandler.cs +++ b/src/Ryujinx.HLE/UI/Input/NpadButtonHandler.cs @@ -1,6 +1,6 @@ using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad; -namespace Ryujinx.HLE.Ui.Input +namespace Ryujinx.HLE.UI.Input { delegate void NpadButtonHandler(int npadIndex, NpadButton button); } diff --git a/src/Ryujinx.HLE/Ui/Input/NpadReader.cs b/src/Ryujinx.HLE/UI/Input/NpadReader.cs similarity index 99% rename from src/Ryujinx.HLE/Ui/Input/NpadReader.cs rename to src/Ryujinx.HLE/UI/Input/NpadReader.cs index 8fc95dc94..8276d6160 100644 --- a/src/Ryujinx.HLE/Ui/Input/NpadReader.cs +++ b/src/Ryujinx.HLE/UI/Input/NpadReader.cs @@ -1,7 +1,7 @@ using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common; using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad; -namespace Ryujinx.HLE.Ui.Input +namespace Ryujinx.HLE.UI.Input { /// /// Class that converts Hid entries for the Npad into pressed / released events. diff --git a/src/Ryujinx.HLE/Ui/KeyPressedHandler.cs b/src/Ryujinx.HLE/UI/KeyPressedHandler.cs similarity index 79% rename from src/Ryujinx.HLE/Ui/KeyPressedHandler.cs rename to src/Ryujinx.HLE/UI/KeyPressedHandler.cs index 31e754377..6feb11bd8 100644 --- a/src/Ryujinx.HLE/Ui/KeyPressedHandler.cs +++ b/src/Ryujinx.HLE/UI/KeyPressedHandler.cs @@ -1,6 +1,6 @@ using Ryujinx.Common.Configuration.Hid; -namespace Ryujinx.HLE.Ui +namespace Ryujinx.HLE.UI { public delegate bool KeyPressedHandler(Key key); } diff --git a/src/Ryujinx.HLE/Ui/KeyReleasedHandler.cs b/src/Ryujinx.HLE/UI/KeyReleasedHandler.cs similarity index 79% rename from src/Ryujinx.HLE/Ui/KeyReleasedHandler.cs rename to src/Ryujinx.HLE/UI/KeyReleasedHandler.cs index d5b6d2019..3de89d0c7 100644 --- a/src/Ryujinx.HLE/Ui/KeyReleasedHandler.cs +++ b/src/Ryujinx.HLE/UI/KeyReleasedHandler.cs @@ -1,6 +1,6 @@ using Ryujinx.Common.Configuration.Hid; -namespace Ryujinx.HLE.Ui +namespace Ryujinx.HLE.UI { public delegate bool KeyReleasedHandler(Key key); } diff --git a/src/Ryujinx.HLE/Ui/RenderingSurfaceInfo.cs b/src/Ryujinx.HLE/UI/RenderingSurfaceInfo.cs similarity index 98% rename from src/Ryujinx.HLE/Ui/RenderingSurfaceInfo.cs rename to src/Ryujinx.HLE/UI/RenderingSurfaceInfo.cs index 0b3d0a909..af0a0d44e 100644 --- a/src/Ryujinx.HLE/Ui/RenderingSurfaceInfo.cs +++ b/src/Ryujinx.HLE/UI/RenderingSurfaceInfo.cs @@ -1,7 +1,7 @@ using Ryujinx.HLE.HOS.Services.SurfaceFlinger; using System; -namespace Ryujinx.HLE.Ui +namespace Ryujinx.HLE.UI { /// /// Information about the indirect layer that is being drawn to. diff --git a/src/Ryujinx.HLE/Ui/ThemeColor.cs b/src/Ryujinx.HLE/UI/ThemeColor.cs similarity index 93% rename from src/Ryujinx.HLE/Ui/ThemeColor.cs rename to src/Ryujinx.HLE/UI/ThemeColor.cs index 23657ed2b..c5cfb1474 100644 --- a/src/Ryujinx.HLE/Ui/ThemeColor.cs +++ b/src/Ryujinx.HLE/UI/ThemeColor.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.HLE.Ui +namespace Ryujinx.HLE.UI { public readonly struct ThemeColor { diff --git a/src/Ryujinx.Headless.SDL2/HeadlessDynamicTextInputHandler.cs b/src/Ryujinx.Headless.SDL2/HeadlessDynamicTextInputHandler.cs index aae01a0ce..503874ff1 100644 --- a/src/Ryujinx.Headless.SDL2/HeadlessDynamicTextInputHandler.cs +++ b/src/Ryujinx.Headless.SDL2/HeadlessDynamicTextInputHandler.cs @@ -1,4 +1,4 @@ -using Ryujinx.HLE.Ui; +using Ryujinx.HLE.UI; using System.Threading; using System.Threading.Tasks; diff --git a/src/Ryujinx.Headless.SDL2/HeadlessHostUiTheme.cs b/src/Ryujinx.Headless.SDL2/HeadlessHostUiTheme.cs index a2df6f3ee..78cd43ae5 100644 --- a/src/Ryujinx.Headless.SDL2/HeadlessHostUiTheme.cs +++ b/src/Ryujinx.Headless.SDL2/HeadlessHostUiTheme.cs @@ -1,8 +1,8 @@ -using Ryujinx.HLE.Ui; +using Ryujinx.HLE.UI; namespace Ryujinx.Headless.SDL2 { - internal class HeadlessHostUiTheme : IHostUiTheme + internal class HeadlessHostUiTheme : IHostUITheme { public string FontFamily => "sans-serif"; diff --git a/src/Ryujinx.Headless.SDL2/OpenGL/OpenGLWindow.cs b/src/Ryujinx.Headless.SDL2/OpenGL/OpenGLWindow.cs index 3fb93a0ec..7ea6e1481 100644 --- a/src/Ryujinx.Headless.SDL2/OpenGL/OpenGLWindow.cs +++ b/src/Ryujinx.Headless.SDL2/OpenGL/OpenGLWindow.cs @@ -96,6 +96,8 @@ namespace Ryujinx.Headless.SDL2.OpenGL } } + public bool HasContext() => SDL_GL_GetCurrentContext() != IntPtr.Zero; + public void Dispose() { SDL_GL_DeleteContext(_context); diff --git a/src/Ryujinx.Headless.SDL2/Program.cs b/src/Ryujinx.Headless.SDL2/Program.cs index 7e3c79f54..85aff6712 100644 --- a/src/Ryujinx.Headless.SDL2/Program.cs +++ b/src/Ryujinx.Headless.SDL2/Program.cs @@ -1,4 +1,3 @@ -using ARMeilleure.Translation; using CommandLine; using LibHac.Tools.FsSystem; using Ryujinx.Audio.Backends.SDL2; @@ -62,7 +61,7 @@ namespace Ryujinx.Headless.SDL2 static void Main(string[] args) { - Version = ReleaseInformation.GetVersion(); + Version = ReleaseInformation.Version; // Make process DPI aware for proper window sizing on high-res screens. ForceDpiAware.Windows(); @@ -428,11 +427,26 @@ namespace Ryujinx.Headless.SDL2 if (!option.DisableFileLog) { - Logger.AddTarget(new AsyncLogTargetWrapper( - new FileLogTarget(ReleaseInformation.GetBaseApplicationDirectory(), "file"), - 1000, - AsyncLogTargetOverflowAction.Block - )); + string logDir = AppDataManager.LogsDirPath; + FileStream logFile = null; + + if (!string.IsNullOrEmpty(logDir)) + { + logFile = FileLogTarget.PrepareLogFile(logDir); + } + + if (logFile != null) + { + Logger.AddTarget(new AsyncLogTargetWrapper( + new FileLogTarget("file", logFile), + 1000, + AsyncLogTargetOverflowAction.Block + )); + } + else + { + Logger.Error?.Print(LogClass.Application, "No writable log directory available. Make sure either the Logs directory, Application Data, or the Ryujinx directory is writable."); + } } // Setup graphics configuration @@ -710,9 +724,6 @@ namespace Ryujinx.Headless.SDL2 } SetupProgressHandler(); - - Translator.IsReadyForTranslation.Reset(); - ExecutionEntrypoint(); return true; diff --git a/src/Ryujinx.Headless.SDL2/Ryujinx.Headless.SDL2.csproj b/src/Ryujinx.Headless.SDL2/Ryujinx.Headless.SDL2.csproj index 7b13df736..cc5a36518 100644 --- a/src/Ryujinx.Headless.SDL2/Ryujinx.Headless.SDL2.csproj +++ b/src/Ryujinx.Headless.SDL2/Ryujinx.Headless.SDL2.csproj @@ -34,7 +34,7 @@ - + @@ -48,7 +48,7 @@ - + Always diff --git a/src/Ryujinx.Headless.SDL2/WindowBase.cs b/src/Ryujinx.Headless.SDL2/WindowBase.cs index adab07641..8768913f5 100644 --- a/src/Ryujinx.Headless.SDL2/WindowBase.cs +++ b/src/Ryujinx.Headless.SDL2/WindowBase.cs @@ -1,4 +1,3 @@ -using ARMeilleure.Translation; using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Logging; @@ -8,7 +7,7 @@ using Ryujinx.Graphics.Gpu; using Ryujinx.Graphics.OpenGL; using Ryujinx.HLE.HOS.Applets; using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types; -using Ryujinx.HLE.Ui; +using Ryujinx.HLE.UI; using Ryujinx.Input; using Ryujinx.Input.HLE; using Ryujinx.SDL2.Common; @@ -26,7 +25,7 @@ using Switch = Ryujinx.HLE.Switch; namespace Ryujinx.Headless.SDL2 { - abstract partial class WindowBase : IHostUiHandler, IDisposable + abstract partial class WindowBase : IHostUIHandler, IDisposable { protected const int DefaultWidth = 1280; protected const int DefaultHeight = 720; @@ -54,7 +53,7 @@ namespace Ryujinx.Headless.SDL2 protected IntPtr WindowHandle { get; set; } - public IHostUiTheme HostUiTheme { get; } + public IHostUITheme HostUITheme { get; } public int Width { get; private set; } public int Height { get; private set; } public int DisplayId { get; set; } @@ -81,7 +80,7 @@ namespace Ryujinx.Headless.SDL2 private bool _isStopped; private uint _windowId; - private string _gpuVendorName; + private string _gpuDriverName; private readonly AspectRatio _aspectRatio; private readonly bool _enableMouse; @@ -107,7 +106,7 @@ namespace Ryujinx.Headless.SDL2 _gpuDoneEvent = new ManualResetEvent(false); _aspectRatio = aspectRatio; _enableMouse = enableMouse; - HostUiTheme = new HeadlessHostUiTheme(); + HostUITheme = new HeadlessHostUiTheme(); SDL2Driver.Instance.Initialize(); } @@ -242,9 +241,9 @@ namespace Ryujinx.Headless.SDL2 public abstract SDL_WindowFlags GetWindowFlags(); - private string GetGpuVendorName() + private string GetGpuDriverName() { - return Renderer.GetHardwareInfo().GpuVendor; + return Renderer.GetHardwareInfo().GpuDriver; } private void SetAntiAliasing() @@ -270,13 +269,12 @@ namespace Ryujinx.Headless.SDL2 SetScalingFilter(); - _gpuVendorName = GetGpuVendorName(); + _gpuDriverName = GetGpuDriverName(); Device.Gpu.Renderer.RunLoop(() => { Device.Gpu.SetGpuThread(); Device.Gpu.InitializeShaderCache(_gpuCancellationTokenSource.Token); - Translator.IsReadyForTranslation.Set(); while (_isActive) { @@ -316,7 +314,7 @@ namespace Ryujinx.Headless.SDL2 Device.Configuration.AspectRatio.ToText(), $"Game: {Device.Statistics.GetGameFrameRate():00.00} FPS ({Device.Statistics.GetGameFrameTime():00.00} ms)", $"FIFO: {Device.Statistics.GetFifoPercent():0.00} %", - $"GPU: {_gpuVendorName}")); + $"GPU: {_gpuDriverName}")); _ticks = Math.Min(_ticks - _ticksPerFrame, _ticksPerFrame); } @@ -467,7 +465,7 @@ namespace Ryujinx.Headless.SDL2 Exit(); } - public bool DisplayInputDialog(SoftwareKeyboardUiArgs args, out string userText) + public bool DisplayInputDialog(SoftwareKeyboardUIArgs args, out string userText) { // SDL2 doesn't support input dialogs userText = "Ryujinx"; @@ -482,7 +480,7 @@ namespace Ryujinx.Headless.SDL2 return true; } - public bool DisplayMessageDialog(ControllerAppletUiArgs args) + public bool DisplayMessageDialog(ControllerAppletUIArgs args) { string playerCount = args.PlayerCountMin == args.PlayerCountMax ? $"exactly {args.PlayerCountMin}" : $"{args.PlayerCountMin}-{args.PlayerCountMax}"; diff --git a/src/Ryujinx.Horizon/Arp/ArpIpcServer.cs b/src/Ryujinx.Horizon/Arp/ArpIpcServer.cs new file mode 100644 index 000000000..6080b4750 --- /dev/null +++ b/src/Ryujinx.Horizon/Arp/ArpIpcServer.cs @@ -0,0 +1,61 @@ +using Ryujinx.Horizon.Arp.Ipc; +using Ryujinx.Horizon.Sdk.Arp; +using Ryujinx.Horizon.Sdk.Arp.Detail; +using Ryujinx.Horizon.Sdk.Sf.Hipc; +using Ryujinx.Horizon.Sdk.Sm; + +namespace Ryujinx.Horizon.Arp +{ + class ArpIpcServer + { + private const int ArpRMaxSessionsCount = 16; + private const int ArpWMaxSessionsCount = 8; + private const int MaxSessionsCount = ArpRMaxSessionsCount + ArpWMaxSessionsCount; + + private const int PointerBufferSize = 0x1000; + private const int MaxDomains = 24; + private const int MaxDomainObjects = 32; + private const int MaxPortsCount = 2; + + private static readonly ManagerOptions _managerOptions = new(PointerBufferSize, MaxDomains, MaxDomainObjects, false); + + private SmApi _sm; + private ServerManager _serverManager; + private ApplicationInstanceManager _applicationInstanceManager; + + public IReader Reader { get; private set; } + public IWriter Writer { get; private set; } + + public void Initialize() + { + HeapAllocator allocator = new(); + + _sm = new SmApi(); + _sm.Initialize().AbortOnFailure(); + + _serverManager = new ServerManager(allocator, _sm, MaxPortsCount, _managerOptions, MaxSessionsCount); + + _applicationInstanceManager = new ApplicationInstanceManager(); + + Reader reader = new(_applicationInstanceManager); + Reader = reader; + + Writer writer = new(_applicationInstanceManager); + Writer = writer; + + _serverManager.RegisterObjectForServer(reader, ServiceName.Encode("arp:r"), ArpRMaxSessionsCount); + _serverManager.RegisterObjectForServer(writer, ServiceName.Encode("arp:w"), ArpWMaxSessionsCount); + } + + public void ServiceRequests() + { + _serverManager.ServiceRequests(); + } + + public void Shutdown() + { + _applicationInstanceManager.Dispose(); + _serverManager.Dispose(); + } + } +} diff --git a/src/Ryujinx.Horizon/Arp/ArpMain.cs b/src/Ryujinx.Horizon/Arp/ArpMain.cs new file mode 100644 index 000000000..a28baa71a --- /dev/null +++ b/src/Ryujinx.Horizon/Arp/ArpMain.cs @@ -0,0 +1,20 @@ +namespace Ryujinx.Horizon.Arp +{ + class ArpMain : IService + { + public static void Main(ServiceTable serviceTable) + { + ArpIpcServer arpIpcServer = new(); + + arpIpcServer.Initialize(); + + serviceTable.ArpReader = arpIpcServer.Reader; + serviceTable.ArpWriter = arpIpcServer.Writer; + + serviceTable.SignalServiceReady(); + + arpIpcServer.ServiceRequests(); + arpIpcServer.Shutdown(); + } + } +} diff --git a/src/Ryujinx.Horizon/Arp/Ipc/Reader.cs b/src/Ryujinx.Horizon/Arp/Ipc/Reader.cs new file mode 100644 index 000000000..de99c2ade --- /dev/null +++ b/src/Ryujinx.Horizon/Arp/Ipc/Reader.cs @@ -0,0 +1,135 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Arp; +using Ryujinx.Horizon.Sdk.Arp.Detail; +using Ryujinx.Horizon.Sdk.Ns; +using Ryujinx.Horizon.Sdk.Sf; +using Ryujinx.Horizon.Sdk.Sf.Hipc; +using System; + +namespace Ryujinx.Horizon.Arp.Ipc +{ + partial class Reader : IReader, IServiceObject + { + private readonly ApplicationInstanceManager _applicationInstanceManager; + + public Reader(ApplicationInstanceManager applicationInstanceManager) + { + _applicationInstanceManager = applicationInstanceManager; + } + + [CmifCommand(0)] + public Result GetApplicationLaunchProperty(out ApplicationLaunchProperty applicationLaunchProperty, ulong applicationInstanceId) + { + if (_applicationInstanceManager.Entries[applicationInstanceId] == null || !_applicationInstanceManager.Entries[applicationInstanceId].LaunchProperty.HasValue) + { + applicationLaunchProperty = default; + + return ArpResult.InvalidInstanceId; + } + + applicationLaunchProperty = _applicationInstanceManager.Entries[applicationInstanceId].LaunchProperty.Value; + + return Result.Success; + } + + [CmifCommand(1)] + public Result GetApplicationControlProperty([Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias, 0x4000)] out ApplicationControlProperty applicationControlProperty, ulong applicationInstanceId) + { + if (_applicationInstanceManager.Entries[applicationInstanceId] == null || !_applicationInstanceManager.Entries[applicationInstanceId].ControlProperty.HasValue) + { + applicationControlProperty = default; + + return ArpResult.InvalidInstanceId; + } + + applicationControlProperty = _applicationInstanceManager.Entries[applicationInstanceId].ControlProperty.Value; + + return Result.Success; + } + + [CmifCommand(2)] + public Result GetApplicationProcessProperty(out ApplicationProcessProperty applicationProcessProperty, ulong applicationInstanceId) + { + if (_applicationInstanceManager.Entries[applicationInstanceId] == null || !_applicationInstanceManager.Entries[applicationInstanceId].ProcessProperty.HasValue) + { + applicationProcessProperty = default; + + return ArpResult.InvalidInstanceId; + } + + applicationProcessProperty = _applicationInstanceManager.Entries[applicationInstanceId].ProcessProperty.Value; + + return Result.Success; + } + + [CmifCommand(3)] + public Result GetApplicationInstanceId(out ulong applicationInstanceId, ulong pid) + { + applicationInstanceId = 0; + + if (pid == 0) + { + return ArpResult.InvalidPid; + } + + for (int i = 0; i < _applicationInstanceManager.Entries.Length; i++) + { + if (_applicationInstanceManager.Entries[i] != null && _applicationInstanceManager.Entries[i].Pid == pid) + { + applicationInstanceId = (ulong)i; + + return Result.Success; + } + } + + return ArpResult.InvalidPid; + } + + [CmifCommand(4)] + public Result GetApplicationInstanceUnregistrationNotifier(out IUnregistrationNotifier unregistrationNotifier) + { + unregistrationNotifier = new UnregistrationNotifier(_applicationInstanceManager); + + return Result.Success; + } + + [CmifCommand(5)] + public Result ListApplicationInstanceId(out int count, [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span applicationInstanceIdList) + { + count = 0; + + if (_applicationInstanceManager.Entries[0] != null) + { + applicationInstanceIdList[count++] = 0; + } + + if (_applicationInstanceManager.Entries[1] != null) + { + applicationInstanceIdList[count++] = 1; + } + + return Result.Success; + } + + [CmifCommand(6)] + public Result GetMicroApplicationInstanceId(out ulong microApplicationInstanceId, [ClientProcessId] ulong pid) + { + return GetApplicationInstanceId(out microApplicationInstanceId, pid); + } + + [CmifCommand(7)] + public Result GetApplicationCertificate([Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias | HipcBufferFlags.FixedSize, 0x528)] out ApplicationCertificate applicationCertificate, ulong applicationInstanceId) + { + if (_applicationInstanceManager.Entries[applicationInstanceId] == null) + { + applicationCertificate = default; + + return ArpResult.InvalidInstanceId; + } + + applicationCertificate = _applicationInstanceManager.Entries[applicationInstanceId].Certificate.Value; + + return Result.Success; + } + } +} diff --git a/src/Ryujinx.Horizon/Arp/Ipc/Registrar.cs b/src/Ryujinx.Horizon/Arp/Ipc/Registrar.cs new file mode 100644 index 000000000..841ab7601 --- /dev/null +++ b/src/Ryujinx.Horizon/Arp/Ipc/Registrar.cs @@ -0,0 +1,52 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Arp; +using Ryujinx.Horizon.Sdk.Arp.Detail; +using Ryujinx.Horizon.Sdk.Ns; +using Ryujinx.Horizon.Sdk.Sf; +using Ryujinx.Horizon.Sdk.Sf.Hipc; +using System; + +namespace Ryujinx.Horizon.Arp.Ipc +{ + partial class Registrar : IRegistrar, IServiceObject + { + private readonly ApplicationInstance _applicationInstance; + + public Registrar(ApplicationInstance applicationInstance) + { + _applicationInstance = applicationInstance; + } + + [CmifCommand(0)] + public Result Issue(out ulong applicationInstanceId) + { + throw new NotImplementedException(); + } + + [CmifCommand(1)] + public Result SetApplicationLaunchProperty(ApplicationLaunchProperty applicationLaunchProperty) + { + if (_applicationInstance.LaunchProperty != null) + { + return ArpResult.DataAlreadyBound; + } + + _applicationInstance.LaunchProperty = applicationLaunchProperty; + + return Result.Success; + } + + [CmifCommand(2)] + public Result SetApplicationControlProperty([Buffer(HipcBufferFlags.In | HipcBufferFlags.MapAlias | HipcBufferFlags.FixedSize, 0x4000)] in ApplicationControlProperty applicationControlProperty) + { + if (_applicationInstance.ControlProperty != null) + { + return ArpResult.DataAlreadyBound; + } + + _applicationInstance.ControlProperty = applicationControlProperty; + + return Result.Success; + } + } +} diff --git a/src/Ryujinx.Horizon/Arp/Ipc/UnregistrationNotifier.cs b/src/Ryujinx.Horizon/Arp/Ipc/UnregistrationNotifier.cs new file mode 100644 index 000000000..49f2b1cce --- /dev/null +++ b/src/Ryujinx.Horizon/Arp/Ipc/UnregistrationNotifier.cs @@ -0,0 +1,25 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Arp; +using Ryujinx.Horizon.Sdk.Arp.Detail; +using Ryujinx.Horizon.Sdk.Sf; + +namespace Ryujinx.Horizon.Arp.Ipc +{ + partial class UnregistrationNotifier : IUnregistrationNotifier, IServiceObject + { + private readonly ApplicationInstanceManager _applicationInstanceManager; + + public UnregistrationNotifier(ApplicationInstanceManager applicationInstanceManager) + { + _applicationInstanceManager = applicationInstanceManager; + } + + [CmifCommand(0)] + public Result GetReadableHandle([CopyHandle] out int readableHandle) + { + readableHandle = _applicationInstanceManager.EventHandle; + + return Result.Success; + } + } +} diff --git a/src/Ryujinx.Horizon/Arp/Ipc/Updater.cs b/src/Ryujinx.Horizon/Arp/Ipc/Updater.cs new file mode 100644 index 000000000..f7531d712 --- /dev/null +++ b/src/Ryujinx.Horizon/Arp/Ipc/Updater.cs @@ -0,0 +1,74 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Arp; +using Ryujinx.Horizon.Sdk.Arp.Detail; +using Ryujinx.Horizon.Sdk.Sf; +using Ryujinx.Horizon.Sdk.Sf.Hipc; +using System; + +namespace Ryujinx.Horizon.Arp.Ipc +{ + partial class Updater : IUpdater, IServiceObject + { + private readonly ApplicationInstanceManager _applicationInstanceManager; + private readonly ulong _applicationInstanceId; + private readonly bool _forCertificate; + + public Updater(ApplicationInstanceManager applicationInstanceManager, ulong applicationInstanceId, bool forCertificate) + { + _applicationInstanceManager = applicationInstanceManager; + _applicationInstanceId = applicationInstanceId; + _forCertificate = forCertificate; + } + + [CmifCommand(0)] + public Result Issue() + { + throw new NotImplementedException(); + } + + [CmifCommand(1)] + public Result SetApplicationProcessProperty(ulong pid, ApplicationProcessProperty applicationProcessProperty) + { + if (_forCertificate) + { + return ArpResult.DataAlreadyBound; + } + + if (pid == 0) + { + return ArpResult.InvalidPid; + } + + _applicationInstanceManager.Entries[_applicationInstanceId].Pid = pid; + _applicationInstanceManager.Entries[_applicationInstanceId].ProcessProperty = applicationProcessProperty; + + return Result.Success; + } + + [CmifCommand(2)] + public Result DeleteApplicationProcessProperty() + { + if (_forCertificate) + { + return ArpResult.DataAlreadyBound; + } + + _applicationInstanceManager.Entries[_applicationInstanceId].ProcessProperty = new ApplicationProcessProperty(); + + return Result.Success; + } + + [CmifCommand(3)] + public Result SetApplicationCertificate([Buffer(HipcBufferFlags.In | HipcBufferFlags.AutoSelect)] ApplicationCertificate applicationCertificate) + { + if (!_forCertificate) + { + return ArpResult.DataAlreadyBound; + } + + _applicationInstanceManager.Entries[_applicationInstanceId].Certificate = applicationCertificate; + + return Result.Success; + } + } +} diff --git a/src/Ryujinx.Horizon/Arp/Ipc/Writer.cs b/src/Ryujinx.Horizon/Arp/Ipc/Writer.cs new file mode 100644 index 000000000..29c98b779 --- /dev/null +++ b/src/Ryujinx.Horizon/Arp/Ipc/Writer.cs @@ -0,0 +1,75 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Arp; +using Ryujinx.Horizon.Sdk.Arp.Detail; +using Ryujinx.Horizon.Sdk.OsTypes; +using Ryujinx.Horizon.Sdk.Sf; + +namespace Ryujinx.Horizon.Arp.Ipc +{ + partial class Writer : IWriter, IServiceObject + { + private readonly ApplicationInstanceManager _applicationInstanceManager; + + public Writer(ApplicationInstanceManager applicationInstanceManager) + { + _applicationInstanceManager = applicationInstanceManager; + } + + [CmifCommand(0)] + public Result AcquireRegistrar(out IRegistrar registrar) + { + if (_applicationInstanceManager.Entries[0] != null) + { + if (_applicationInstanceManager.Entries[1] != null) + { + registrar = null; + + return ArpResult.NoFreeInstance; + } + else + { + _applicationInstanceManager.Entries[1] = new ApplicationInstance(); + + registrar = new Registrar(_applicationInstanceManager.Entries[1]); + } + } + else + { + _applicationInstanceManager.Entries[0] = new ApplicationInstance(); + + registrar = new Registrar(_applicationInstanceManager.Entries[0]); + } + + return Result.Success; + } + + [CmifCommand(1)] + public Result UnregisterApplicationInstance(ulong applicationInstanceId) + { + if (_applicationInstanceManager.Entries[applicationInstanceId] != null) + { + _applicationInstanceManager.Entries[applicationInstanceId] = null; + } + + Os.SignalSystemEvent(ref _applicationInstanceManager.SystemEvent); + + return Result.Success; + } + + [CmifCommand(2)] + public Result AcquireApplicationProcessPropertyUpdater(out IUpdater updater, ulong applicationInstanceId) + { + updater = new Updater(_applicationInstanceManager, applicationInstanceId, false); + + return Result.Success; + } + + [CmifCommand(3)] + public Result AcquireApplicationCertificateUpdater(out IUpdater updater, ulong applicationInstanceId) + { + updater = new Updater(_applicationInstanceManager, applicationInstanceId, true); + + return Result.Success; + } + } +} diff --git a/src/Ryujinx.Horizon/Friends/FriendsIpcServer.cs b/src/Ryujinx.Horizon/Friends/FriendsIpcServer.cs new file mode 100644 index 000000000..523c617a8 --- /dev/null +++ b/src/Ryujinx.Horizon/Friends/FriendsIpcServer.cs @@ -0,0 +1,49 @@ +using Ryujinx.Horizon.Sdk.Sf.Hipc; +using Ryujinx.Horizon.Sdk.Sm; + +namespace Ryujinx.Horizon.Friends +{ + class FriendsIpcServer + { + private const int MaxSessionsCount = 8; + private const int TotalMaxSessionsCount = MaxSessionsCount * 5; + + private const int PointerBufferSize = 0xA00; + private const int MaxDomains = 64; + private const int MaxDomainObjects = 16; + private const int MaxPortsCount = 5; + + private static readonly ManagerOptions _managerOptions = new(PointerBufferSize, MaxDomains, MaxDomainObjects, false); + + private SmApi _sm; + private FriendsServerManager _serverManager; + + public void Initialize() + { + HeapAllocator allocator = new(); + + _sm = new SmApi(); + _sm.Initialize().AbortOnFailure(); + + _serverManager = new FriendsServerManager(allocator, _sm, MaxPortsCount, _managerOptions, TotalMaxSessionsCount); + +#pragma warning disable IDE0055 // Disable formatting + _serverManager.RegisterServer((int)FriendsPortIndex.Admin, ServiceName.Encode("friend:a"), MaxSessionsCount); + _serverManager.RegisterServer((int)FriendsPortIndex.User, ServiceName.Encode("friend:u"), MaxSessionsCount); + _serverManager.RegisterServer((int)FriendsPortIndex.Viewer, ServiceName.Encode("friend:v"), MaxSessionsCount); + _serverManager.RegisterServer((int)FriendsPortIndex.Manager, ServiceName.Encode("friend:m"), MaxSessionsCount); + _serverManager.RegisterServer((int)FriendsPortIndex.System, ServiceName.Encode("friend:s"), MaxSessionsCount); +#pragma warning restore IDE0055 + } + + public void ServiceRequests() + { + _serverManager.ServiceRequests(); + } + + public void Shutdown() + { + _serverManager.Dispose(); + } + } +} diff --git a/src/Ryujinx.Horizon/Friends/FriendsMain.cs b/src/Ryujinx.Horizon/Friends/FriendsMain.cs new file mode 100644 index 000000000..0f119cf01 --- /dev/null +++ b/src/Ryujinx.Horizon/Friends/FriendsMain.cs @@ -0,0 +1,17 @@ +namespace Ryujinx.Horizon.Friends +{ + class FriendsMain : IService + { + public static void Main(ServiceTable serviceTable) + { + FriendsIpcServer ipcServer = new(); + + ipcServer.Initialize(); + + serviceTable.SignalServiceReady(); + + ipcServer.ServiceRequests(); + ipcServer.Shutdown(); + } + } +} diff --git a/src/Ryujinx.Horizon/Friends/FriendsPortIndex.cs b/src/Ryujinx.Horizon/Friends/FriendsPortIndex.cs new file mode 100644 index 000000000..f567db302 --- /dev/null +++ b/src/Ryujinx.Horizon/Friends/FriendsPortIndex.cs @@ -0,0 +1,11 @@ +namespace Ryujinx.Horizon.Friends +{ + enum FriendsPortIndex + { + Admin, + User, + Viewer, + Manager, + System, + } +} diff --git a/src/Ryujinx.Horizon/Friends/FriendsServerManager.cs b/src/Ryujinx.Horizon/Friends/FriendsServerManager.cs new file mode 100644 index 000000000..5026206b7 --- /dev/null +++ b/src/Ryujinx.Horizon/Friends/FriendsServerManager.cs @@ -0,0 +1,36 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Account; +using Ryujinx.Horizon.Sdk.Friends.Detail.Ipc; +using Ryujinx.Horizon.Sdk.Sf.Hipc; +using Ryujinx.Horizon.Sdk.Sm; +using System; + +namespace Ryujinx.Horizon.Friends +{ + class FriendsServerManager : ServerManager + { + private readonly IEmulatorAccountManager _accountManager; + private readonly NotificationEventHandler _notificationEventHandler; + + public FriendsServerManager(HeapAllocator allocator, SmApi sm, int maxPorts, ManagerOptions options, int maxSessions) : base(allocator, sm, maxPorts, options, maxSessions) + { + _accountManager = HorizonStatic.Options.AccountManager; + _notificationEventHandler = new(); + } + + protected override Result OnNeedsToAccept(int portIndex, Server server) + { + return (FriendsPortIndex)portIndex switch + { +#pragma warning disable IDE0055 // Disable formatting + FriendsPortIndex.Admin => AcceptImpl(server, new ServiceCreator(_accountManager, _notificationEventHandler, FriendsServicePermissionLevel.Admin)), + FriendsPortIndex.User => AcceptImpl(server, new ServiceCreator(_accountManager, _notificationEventHandler, FriendsServicePermissionLevel.User)), + FriendsPortIndex.Viewer => AcceptImpl(server, new ServiceCreator(_accountManager, _notificationEventHandler, FriendsServicePermissionLevel.Viewer)), + FriendsPortIndex.Manager => AcceptImpl(server, new ServiceCreator(_accountManager, _notificationEventHandler, FriendsServicePermissionLevel.Manager)), + FriendsPortIndex.System => AcceptImpl(server, new ServiceCreator(_accountManager, _notificationEventHandler, FriendsServicePermissionLevel.System)), + _ => throw new ArgumentOutOfRangeException(nameof(portIndex)), +#pragma warning restore IDE0055 + }; + } + } +} diff --git a/src/Ryujinx.Horizon/HorizonOptions.cs b/src/Ryujinx.Horizon/HorizonOptions.cs index e3c862da4..794620569 100644 --- a/src/Ryujinx.Horizon/HorizonOptions.cs +++ b/src/Ryujinx.Horizon/HorizonOptions.cs @@ -1,4 +1,5 @@ using LibHac; +using Ryujinx.Horizon.Sdk.Account; using Ryujinx.Horizon.Sdk.Fs; namespace Ryujinx.Horizon @@ -10,13 +11,15 @@ namespace Ryujinx.Horizon public HorizonClient BcatClient { get; } public IFsClient FsClient { get; } + public IEmulatorAccountManager AccountManager { get; } - public HorizonOptions(bool ignoreMissingServices, HorizonClient bcatClient, IFsClient fsClient) + public HorizonOptions(bool ignoreMissingServices, HorizonClient bcatClient, IFsClient fsClient, IEmulatorAccountManager accountManager) { IgnoreMissingServices = ignoreMissingServices; ThrowOnInvalidCommandIds = true; BcatClient = bcatClient; FsClient = fsClient; + AccountManager = accountManager; } } } diff --git a/src/Ryujinx.Horizon/Prepo/Ipc/PrepoService.cs b/src/Ryujinx.Horizon/Prepo/Ipc/PrepoService.cs index c165f46fa..4ed7dd48e 100644 --- a/src/Ryujinx.Horizon/Prepo/Ipc/PrepoService.cs +++ b/src/Ryujinx.Horizon/Prepo/Ipc/PrepoService.cs @@ -5,6 +5,7 @@ using Ryujinx.Common.Utilities; using Ryujinx.Horizon.Common; using Ryujinx.Horizon.Prepo.Types; using Ryujinx.Horizon.Sdk.Account; +using Ryujinx.Horizon.Sdk.Arp; using Ryujinx.Horizon.Sdk.Prepo; using Ryujinx.Horizon.Sdk.Sf; using Ryujinx.Horizon.Sdk.Sf.Hipc; @@ -22,14 +23,16 @@ namespace Ryujinx.Horizon.Prepo.Ipc System, } + private readonly ArpApi _arp; private readonly PrepoServicePermissionLevel _permissionLevel; private ulong _systemSessionId; private bool _immediateTransmissionEnabled; private bool _userAgreementCheckEnabled = true; - public PrepoService(PrepoServicePermissionLevel permissionLevel) + public PrepoService(ArpApi arp, PrepoServicePermissionLevel permissionLevel) { + _arp = arp; _permissionLevel = permissionLevel; } @@ -165,7 +168,7 @@ namespace Ryujinx.Horizon.Prepo.Ipc return PrepoResult.PermissionDenied; } - private static Result ProcessPlayReport(PlayReportKind playReportKind, ReadOnlySpan gameRoomBuffer, ReadOnlySpan reportBuffer, ulong pid, Uid userId, bool withUserId = false, ApplicationId applicationId = default) + private Result ProcessPlayReport(PlayReportKind playReportKind, ReadOnlySpan gameRoomBuffer, ReadOnlySpan reportBuffer, ulong pid, Uid userId, bool withUserId = false, ApplicationId applicationId = default) { if (withUserId) { @@ -199,8 +202,8 @@ namespace Ryujinx.Horizon.Prepo.Ipc builder.AppendLine("PlayReport log:"); builder.AppendLine($" Kind: {playReportKind}"); - // NOTE: The service calls arp:r using the pid to get the application id, if it fails PrepoResult.InvalidPid is returned. - // Reports are stored internally and an event is signaled to transmit them. + // NOTE: Reports are stored internally and an event is signaled to transmit them. + if (pid != 0) { builder.AppendLine($" Pid: {pid}"); @@ -210,6 +213,16 @@ namespace Ryujinx.Horizon.Prepo.Ipc builder.AppendLine($" ApplicationId: {applicationId}"); } + Result result = _arp.GetApplicationInstanceId(out ulong applicationInstanceId, pid); + if (result.IsFailure) + { + return PrepoResult.InvalidPid; + } + + _arp.GetApplicationLaunchProperty(out ApplicationLaunchProperty applicationLaunchProperty, applicationInstanceId).AbortOnFailure(); + + builder.AppendLine($" ApplicationVersion: {applicationLaunchProperty.Version}"); + if (!userId.IsNull) { builder.AppendLine($" UserId: {userId}"); diff --git a/src/Ryujinx.Horizon/Prepo/PrepoIpcServer.cs b/src/Ryujinx.Horizon/Prepo/PrepoIpcServer.cs index fd3f86ff9..1902cde23 100644 --- a/src/Ryujinx.Horizon/Prepo/PrepoIpcServer.cs +++ b/src/Ryujinx.Horizon/Prepo/PrepoIpcServer.cs @@ -1,4 +1,5 @@ using Ryujinx.Horizon.Prepo.Types; +using Ryujinx.Horizon.Sdk.Arp; using Ryujinx.Horizon.Sdk.Sf.Hipc; using Ryujinx.Horizon.Sdk.Sm; @@ -17,16 +18,19 @@ namespace Ryujinx.Horizon.Prepo private static readonly ManagerOptions _managerOptions = new(PointerBufferSize, MaxDomains, MaxDomainObjects, false); private SmApi _sm; + private ArpApi _arp; private PrepoServerManager _serverManager; public void Initialize() { HeapAllocator allocator = new(); + _arp = new ArpApi(allocator); + _sm = new SmApi(); _sm.Initialize().AbortOnFailure(); - _serverManager = new PrepoServerManager(allocator, _sm, MaxPortsCount, _managerOptions, TotalMaxSessionsCount); + _serverManager = new PrepoServerManager(allocator, _sm, _arp, MaxPortsCount, _managerOptions, TotalMaxSessionsCount); #pragma warning disable IDE0055 // Disable formatting _serverManager.RegisterServer((int)PrepoPortIndex.Admin, ServiceName.Encode("prepo:a"), MaxSessionsCount); // 1.0.0-5.1.0 @@ -45,6 +49,7 @@ namespace Ryujinx.Horizon.Prepo public void Shutdown() { + _arp.Dispose(); _serverManager.Dispose(); } } diff --git a/src/Ryujinx.Horizon/Prepo/PrepoServerManager.cs b/src/Ryujinx.Horizon/Prepo/PrepoServerManager.cs index 0c1c782f6..8cac44c8f 100644 --- a/src/Ryujinx.Horizon/Prepo/PrepoServerManager.cs +++ b/src/Ryujinx.Horizon/Prepo/PrepoServerManager.cs @@ -1,6 +1,7 @@ using Ryujinx.Horizon.Common; using Ryujinx.Horizon.Prepo.Ipc; using Ryujinx.Horizon.Prepo.Types; +using Ryujinx.Horizon.Sdk.Arp; using Ryujinx.Horizon.Sdk.Sf.Hipc; using Ryujinx.Horizon.Sdk.Sm; using System; @@ -9,8 +10,11 @@ namespace Ryujinx.Horizon.Prepo { class PrepoServerManager : ServerManager { - public PrepoServerManager(HeapAllocator allocator, SmApi sm, int maxPorts, ManagerOptions options, int maxSessions) : base(allocator, sm, maxPorts, options, maxSessions) + private readonly ArpApi _arp; + + public PrepoServerManager(HeapAllocator allocator, SmApi sm, ArpApi arp, int maxPorts, ManagerOptions options, int maxSessions) : base(allocator, sm, maxPorts, options, maxSessions) { + _arp = arp; } protected override Result OnNeedsToAccept(int portIndex, Server server) @@ -18,12 +22,12 @@ namespace Ryujinx.Horizon.Prepo return (PrepoPortIndex)portIndex switch { #pragma warning disable IDE0055 // Disable formatting - PrepoPortIndex.Admin => AcceptImpl(server, new PrepoService(PrepoServicePermissionLevel.Admin)), - PrepoPortIndex.Admin2 => AcceptImpl(server, new PrepoService(PrepoServicePermissionLevel.Admin)), - PrepoPortIndex.Manager => AcceptImpl(server, new PrepoService(PrepoServicePermissionLevel.Manager)), - PrepoPortIndex.User => AcceptImpl(server, new PrepoService(PrepoServicePermissionLevel.User)), - PrepoPortIndex.System => AcceptImpl(server, new PrepoService(PrepoServicePermissionLevel.System)), - PrepoPortIndex.Debug => AcceptImpl(server, new PrepoService(PrepoServicePermissionLevel.Debug)), + PrepoPortIndex.Admin => AcceptImpl(server, new PrepoService(_arp, PrepoServicePermissionLevel.Admin)), + PrepoPortIndex.Admin2 => AcceptImpl(server, new PrepoService(_arp, PrepoServicePermissionLevel.Admin)), + PrepoPortIndex.Manager => AcceptImpl(server, new PrepoService(_arp, PrepoServicePermissionLevel.Manager)), + PrepoPortIndex.User => AcceptImpl(server, new PrepoService(_arp, PrepoServicePermissionLevel.User)), + PrepoPortIndex.System => AcceptImpl(server, new PrepoService(_arp, PrepoServicePermissionLevel.System)), + PrepoPortIndex.Debug => AcceptImpl(server, new PrepoService(_arp, PrepoServicePermissionLevel.Debug)), _ => throw new ArgumentOutOfRangeException(nameof(portIndex)), #pragma warning restore IDE0055 }; diff --git a/src/Ryujinx.Horizon/Sdk/Account/IEmulatorAccountManager.cs b/src/Ryujinx.Horizon/Sdk/Account/IEmulatorAccountManager.cs new file mode 100644 index 000000000..af02cc8eb --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Account/IEmulatorAccountManager.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.Horizon.Sdk.Account +{ + public interface IEmulatorAccountManager + { + void OpenUserOnlinePlay(Uid userId); + void CloseUserOnlinePlay(Uid userId); + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Account/NetworkServiceAccountId.cs b/src/Ryujinx.Horizon/Sdk/Account/NetworkServiceAccountId.cs new file mode 100644 index 000000000..2512975e3 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Account/NetworkServiceAccountId.cs @@ -0,0 +1,20 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Account +{ + [StructLayout(LayoutKind.Sequential, Size = 0x8, Pack = 0x8)] + readonly record struct NetworkServiceAccountId + { + public readonly ulong Id; + + public NetworkServiceAccountId(ulong id) + { + Id = id; + } + + public override readonly string ToString() + { + return Id.ToString("x16"); + } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Account/Nickname.cs b/src/Ryujinx.Horizon/Sdk/Account/Nickname.cs new file mode 100644 index 000000000..1f351ee3a --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Account/Nickname.cs @@ -0,0 +1,29 @@ +using Ryujinx.Common.Memory; +using System; +using System.Runtime.InteropServices; +using System.Text; + +namespace Ryujinx.Horizon.Sdk.Account +{ + [StructLayout(LayoutKind.Sequential, Size = 0x21, Pack = 0x1)] + readonly struct Nickname + { + public readonly Array33 Name; + + public Nickname(in Array33 name) + { + Name = name; + } + + public override string ToString() + { + int length = ((ReadOnlySpan)Name.AsSpan()).IndexOf((byte)0); + if (length < 0) + { + length = 33; + } + + return Encoding.UTF8.GetString(Name.AsSpan()[..length]); + } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Account/Uid.cs b/src/Ryujinx.Horizon/Sdk/Account/Uid.cs index a76e6d256..ada2c02ba 100644 --- a/src/Ryujinx.Horizon/Sdk/Account/Uid.cs +++ b/src/Ryujinx.Horizon/Sdk/Account/Uid.cs @@ -6,16 +6,16 @@ using System.Runtime.InteropServices; namespace Ryujinx.Horizon.Sdk.Account { [StructLayout(LayoutKind.Sequential)] - readonly record struct Uid + public readonly record struct Uid { - public readonly long High; - public readonly long Low; + public readonly ulong High; + public readonly ulong Low; public bool IsNull => (Low | High) == 0; public static Uid Null => new(0, 0); - public Uid(long low, long high) + public Uid(ulong low, ulong high) { Low = low; High = high; @@ -23,8 +23,8 @@ namespace Ryujinx.Horizon.Sdk.Account public Uid(byte[] bytes) { - High = BitConverter.ToInt64(bytes, 0); - Low = BitConverter.ToInt64(bytes, 8); + High = BitConverter.ToUInt64(bytes, 0); + Low = BitConverter.ToUInt64(bytes, 8); } public Uid(string hex) @@ -34,8 +34,8 @@ namespace Ryujinx.Horizon.Sdk.Account throw new ArgumentException("Invalid Hex value!", nameof(hex)); } - Low = Convert.ToInt64(hex[16..], 16); - High = Convert.ToInt64(hex[..16], 16); + Low = Convert.ToUInt64(hex[16..], 16); + High = Convert.ToUInt64(hex[..16], 16); } public void Write(BinaryWriter binaryWriter) diff --git a/src/Ryujinx.Horizon/Sdk/Arp/ApplicationCertificate.cs b/src/Ryujinx.Horizon/Sdk/Arp/ApplicationCertificate.cs new file mode 100644 index 000000000..d60d337d3 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Arp/ApplicationCertificate.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Arp +{ + [StructLayout(LayoutKind.Sequential, Size = 0x528)] + public struct ApplicationCertificate + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Arp/ApplicationKind.cs b/src/Ryujinx.Horizon/Sdk/Arp/ApplicationKind.cs new file mode 100644 index 000000000..586e6a98a --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Arp/ApplicationKind.cs @@ -0,0 +1,8 @@ +namespace Ryujinx.Horizon.Sdk.Arp +{ + public enum ApplicationKind : byte + { + Application, + MicroApplication, + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Arp/ApplicationLaunchProperty.cs b/src/Ryujinx.Horizon/Sdk/Arp/ApplicationLaunchProperty.cs new file mode 100644 index 000000000..00b818321 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Arp/ApplicationLaunchProperty.cs @@ -0,0 +1,14 @@ +using Ryujinx.Horizon.Sdk.Ncm; + +namespace Ryujinx.Horizon.Sdk.Arp +{ + public struct ApplicationLaunchProperty + { + public ApplicationId ApplicationId; + public uint Version; + public StorageId Storage; + public StorageId PatchStorage; + public ApplicationKind ApplicationKind; + public byte Padding; + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Arp/ApplicationProcessProperty.cs b/src/Ryujinx.Horizon/Sdk/Arp/ApplicationProcessProperty.cs new file mode 100644 index 000000000..13d222a12 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Arp/ApplicationProcessProperty.cs @@ -0,0 +1,10 @@ +using Ryujinx.Common.Memory; + +namespace Ryujinx.Horizon.Sdk.Arp +{ + public struct ApplicationProcessProperty + { + public byte ProgramIndex; + public Array15 Unknown; + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Arp/ArpApi.cs b/src/Ryujinx.Horizon/Sdk/Arp/ArpApi.cs new file mode 100644 index 000000000..b0acc0062 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Arp/ArpApi.cs @@ -0,0 +1,130 @@ +using Ryujinx.Common.Memory; +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Ns; +using Ryujinx.Horizon.Sdk.Sf.Cmif; +using Ryujinx.Horizon.Sdk.Sf.Hipc; +using Ryujinx.Horizon.Sdk.Sm; +using System; +using System.Runtime.CompilerServices; + +namespace Ryujinx.Horizon.Sdk.Arp +{ + class ArpApi : IDisposable + { + private const string ArpRName = "arp:r"; + + private readonly HeapAllocator _allocator; + private int _sessionHandle; + + public ArpApi(HeapAllocator allocator) + { + _allocator = allocator; + } + + private void InitializeArpRService() + { + if (_sessionHandle == 0) + { + using var smApi = new SmApi(); + + smApi.Initialize(); + smApi.GetServiceHandle(out _sessionHandle, ServiceName.Encode(ArpRName)).AbortOnFailure(); + } + } + + public Result GetApplicationInstanceId(out ulong applicationInstanceId, ulong applicationPid) + { + Span data = stackalloc byte[8]; + SpanWriter writer = new(data); + + writer.Write(applicationPid); + + InitializeArpRService(); + + Result result = ServiceUtil.SendRequest(out CmifResponse response, _sessionHandle, 3, sendPid: false, data); + if (result.IsFailure) + { + applicationInstanceId = 0; + + return result; + } + + SpanReader reader = new(response.Data); + + applicationInstanceId = reader.Read(); + + return Result.Success; + } + + public Result GetApplicationLaunchProperty(out ApplicationLaunchProperty applicationLaunchProperty, ulong applicationInstanceId) + { + applicationLaunchProperty = default; + + Span data = stackalloc byte[8]; + SpanWriter writer = new(data); + + writer.Write(applicationInstanceId); + + InitializeArpRService(); + + Result result = ServiceUtil.SendRequest(out CmifResponse response, _sessionHandle, 0, sendPid: false, data); + if (result.IsFailure) + { + return result; + } + + SpanReader reader = new(response.Data); + + applicationLaunchProperty = reader.Read(); + + return Result.Success; + } + + public Result GetApplicationControlProperty(out ApplicationControlProperty applicationControlProperty, ulong applicationInstanceId) + { + applicationControlProperty = default; + + Span data = stackalloc byte[8]; + SpanWriter writer = new(data); + + writer.Write(applicationInstanceId); + + ulong bufferSize = (ulong)Unsafe.SizeOf(); + ulong bufferAddress = _allocator.Allocate(bufferSize); + + InitializeArpRService(); + + Result result = ServiceUtil.SendRequest( + out CmifResponse response, + _sessionHandle, + 1, + sendPid: false, + data, + stackalloc[] { HipcBufferFlags.Out | HipcBufferFlags.MapAlias | HipcBufferFlags.FixedSize }, + stackalloc[] { new PointerAndSize(bufferAddress, bufferSize) }); + + if (result.IsFailure) + { + return result; + } + + applicationControlProperty = HorizonStatic.AddressSpace.Read(bufferAddress); + + _allocator.Free(bufferAddress, bufferSize); + + return Result.Success; + } + + public void Dispose() + { + if (_sessionHandle != 0) + { + HorizonStatic.Syscall.CloseHandle(_sessionHandle); + + _sessionHandle = 0; + } + + GC.SuppressFinalize(this); + } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Arp/ArpResult.cs b/src/Ryujinx.Horizon/Sdk/Arp/ArpResult.cs new file mode 100644 index 000000000..5de07871d --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Arp/ArpResult.cs @@ -0,0 +1,17 @@ +using Ryujinx.Horizon.Common; + +namespace Ryujinx.Horizon.Sdk.Arp +{ + static class ArpResult + { + private const int ModuleId = 157; + + public static Result InvalidArgument => new(ModuleId, 30); + public static Result InvalidPid => new(ModuleId, 31); + public static Result InvalidPointer => new(ModuleId, 32); + public static Result DataAlreadyBound => new(ModuleId, 42); + public static Result AllocationFailed => new(ModuleId, 63); + public static Result NoFreeInstance => new(ModuleId, 101); + public static Result InvalidInstanceId => new(ModuleId, 102); + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Arp/Detail/ApplicationInstance.cs b/src/Ryujinx.Horizon/Sdk/Arp/Detail/ApplicationInstance.cs new file mode 100644 index 000000000..5eb0ab184 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Arp/Detail/ApplicationInstance.cs @@ -0,0 +1,13 @@ +using Ryujinx.Horizon.Sdk.Ns; + +namespace Ryujinx.Horizon.Sdk.Arp.Detail +{ + class ApplicationInstance + { + public ulong Pid { get; set; } + public ApplicationLaunchProperty? LaunchProperty { get; set; } + public ApplicationProcessProperty? ProcessProperty { get; set; } + public ApplicationControlProperty? ControlProperty { get; set; } + public ApplicationCertificate? Certificate { get; set; } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Arp/Detail/ApplicationInstanceManager.cs b/src/Ryujinx.Horizon/Sdk/Arp/Detail/ApplicationInstanceManager.cs new file mode 100644 index 000000000..18c993ce4 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Arp/Detail/ApplicationInstanceManager.cs @@ -0,0 +1,31 @@ +using Ryujinx.Horizon.Sdk.OsTypes; +using System; +using System.Threading; + +namespace Ryujinx.Horizon.Sdk.Arp.Detail +{ + class ApplicationInstanceManager : IDisposable + { + private int _disposalState; + + public SystemEventType SystemEvent; + public int EventHandle; + + public readonly ApplicationInstance[] Entries = new ApplicationInstance[2]; + + public ApplicationInstanceManager() + { + Os.CreateSystemEvent(out SystemEvent, EventClearMode.ManualClear, true).AbortOnFailure(); + + EventHandle = Os.GetReadableHandleOfSystemEvent(ref SystemEvent); + } + + public void Dispose() + { + if (EventHandle != 0 && Interlocked.Exchange(ref _disposalState, 1) == 0) + { + Os.DestroySystemEvent(ref SystemEvent); + } + } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Arp/IReader.cs b/src/Ryujinx.Horizon/Sdk/Arp/IReader.cs new file mode 100644 index 000000000..ef78f7fd6 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Arp/IReader.cs @@ -0,0 +1,18 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Ns; +using System; + +namespace Ryujinx.Horizon.Sdk.Arp +{ + public interface IReader + { + public Result GetApplicationLaunchProperty(out ApplicationLaunchProperty applicationLaunchProperty, ulong applicationInstanceId); + public Result GetApplicationControlProperty(out ApplicationControlProperty applicationControlProperty, ulong applicationInstanceId); + public Result GetApplicationProcessProperty(out ApplicationProcessProperty applicationControlProperty, ulong applicationInstanceId); + public Result GetApplicationInstanceId(out ulong applicationInstanceId, ulong pid); + public Result GetApplicationInstanceUnregistrationNotifier(out IUnregistrationNotifier unregistrationNotifier); + public Result ListApplicationInstanceId(out int count, Span applicationInstanceIdList); + public Result GetMicroApplicationInstanceId(out ulong MicroApplicationInstanceId, ulong pid); + public Result GetApplicationCertificate(out ApplicationCertificate applicationCertificate, ulong applicationInstanceId); + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Arp/IRegistrar.cs b/src/Ryujinx.Horizon/Sdk/Arp/IRegistrar.cs new file mode 100644 index 000000000..467f3dbd3 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Arp/IRegistrar.cs @@ -0,0 +1,12 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Ns; + +namespace Ryujinx.Horizon.Sdk.Arp +{ + public interface IRegistrar + { + public Result Issue(out ulong applicationInstanceId); + public Result SetApplicationLaunchProperty(ApplicationLaunchProperty applicationLaunchProperty); + public Result SetApplicationControlProperty(in ApplicationControlProperty applicationControlProperty); + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Arp/IUnregistrationNotifier.cs b/src/Ryujinx.Horizon/Sdk/Arp/IUnregistrationNotifier.cs new file mode 100644 index 000000000..24b9807d8 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Arp/IUnregistrationNotifier.cs @@ -0,0 +1,9 @@ +using Ryujinx.Horizon.Common; + +namespace Ryujinx.Horizon.Sdk.Arp +{ + public interface IUnregistrationNotifier + { + public Result GetReadableHandle(out int readableHandle); + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Arp/IUpdater.cs b/src/Ryujinx.Horizon/Sdk/Arp/IUpdater.cs new file mode 100644 index 000000000..f9beeb690 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Arp/IUpdater.cs @@ -0,0 +1,12 @@ +using Ryujinx.Horizon.Common; + +namespace Ryujinx.Horizon.Sdk.Arp +{ + public interface IUpdater + { + public Result Issue(); + public Result SetApplicationProcessProperty(ulong pid, ApplicationProcessProperty applicationProcessProperty); + public Result DeleteApplicationProcessProperty(); + public Result SetApplicationCertificate(ApplicationCertificate applicationCertificate); + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Arp/IWriter.cs b/src/Ryujinx.Horizon/Sdk/Arp/IWriter.cs new file mode 100644 index 000000000..b3e000e1e --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Arp/IWriter.cs @@ -0,0 +1,12 @@ +using Ryujinx.Horizon.Common; + +namespace Ryujinx.Horizon.Sdk.Arp +{ + public interface IWriter + { + public Result AcquireRegistrar(out IRegistrar registrar); + public Result UnregisterApplicationInstance(ulong applicationInstanceId); + public Result AcquireApplicationProcessPropertyUpdater(out IUpdater updater, ulong applicationInstanceId); + public Result AcquireApplicationCertificateUpdater(out IUpdater updater, ulong applicationInstanceId); + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/ApplicationInfo.cs b/src/Ryujinx.Horizon/Sdk/Friends/ApplicationInfo.cs new file mode 100644 index 000000000..23bad3d13 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/ApplicationInfo.cs @@ -0,0 +1,12 @@ +using Ryujinx.Horizon.Sdk.Ncm; +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends +{ + [StructLayout(LayoutKind.Sequential, Size = 0x10, Pack = 0x8)] + struct ApplicationInfo + { + public ApplicationId ApplicationId; + public ulong PresenceGroupId; + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/BlockedUserImpl.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/BlockedUserImpl.cs new file mode 100644 index 000000000..d5f8a0313 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/BlockedUserImpl.cs @@ -0,0 +1,8 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail +{ + struct BlockedUserImpl + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendCandidateImpl.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendCandidateImpl.cs new file mode 100644 index 000000000..21e99c754 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendCandidateImpl.cs @@ -0,0 +1,8 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail +{ + struct FriendCandidateImpl + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendDetailedInfoImpl.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendDetailedInfoImpl.cs new file mode 100644 index 000000000..1b46dccd5 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendDetailedInfoImpl.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail +{ + [StructLayout(LayoutKind.Sequential, Size = 0x800)] + struct FriendDetailedInfoImpl + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendImpl.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendImpl.cs new file mode 100644 index 000000000..d22ca4b90 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendImpl.cs @@ -0,0 +1,19 @@ +using Ryujinx.Common.Memory; +using Ryujinx.Horizon.Sdk.Account; +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail +{ + [StructLayout(LayoutKind.Sequential, Size = 0x200, Pack = 0x8)] + struct FriendImpl + { + public Uid UserId; + public NetworkServiceAccountId NetworkUserId; + public Nickname Nickname; + public UserPresenceImpl Presence; + public bool IsFavourite; + public bool IsNew; + public Array6 Unknown; + public bool IsValid; + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendInvitationForViewerImpl.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendInvitationForViewerImpl.cs new file mode 100644 index 000000000..416ba3655 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendInvitationForViewerImpl.cs @@ -0,0 +1,8 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail +{ + struct FriendInvitationForViewerImpl + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendInvitationGroupImpl.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendInvitationGroupImpl.cs new file mode 100644 index 000000000..ef9238347 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendInvitationGroupImpl.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail +{ + [StructLayout(LayoutKind.Sequential, Size = 0x1400)] + struct FriendInvitationGroupImpl + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendRequestImpl.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendRequestImpl.cs new file mode 100644 index 000000000..ba5671692 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendRequestImpl.cs @@ -0,0 +1,8 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail +{ + struct FriendRequestImpl + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendSettingImpl.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendSettingImpl.cs new file mode 100644 index 000000000..f711d31fd --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/FriendSettingImpl.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail +{ + [StructLayout(LayoutKind.Sequential, Size = 0x40)] + struct FriendSettingImpl + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/DaemonSuspendSessionService.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/DaemonSuspendSessionService.cs new file mode 100644 index 000000000..aaf88ed03 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/DaemonSuspendSessionService.cs @@ -0,0 +1,7 @@ +namespace Ryujinx.Horizon.Sdk.Friends.Detail.Ipc +{ + partial class DaemonSuspendSessionService : IDaemonSuspendSessionService + { + // NOTE: This service has no commands. + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/FriendService.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/FriendService.cs new file mode 100644 index 000000000..1b4c8c309 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/FriendService.cs @@ -0,0 +1,1015 @@ +using Ryujinx.Common.Logging; +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Account; +using Ryujinx.Horizon.Sdk.OsTypes; +using Ryujinx.Horizon.Sdk.Settings; +using Ryujinx.Horizon.Sdk.Sf; +using Ryujinx.Horizon.Sdk.Sf.Hipc; +using System; +using System.Runtime.InteropServices; +using System.Text; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail.Ipc +{ + partial class FriendService : IFriendService, IDisposable + { + private readonly IEmulatorAccountManager _accountManager; + private SystemEventType _completionEvent; + + public FriendService(IEmulatorAccountManager accountManager, FriendsServicePermissionLevel permissionLevel) + { + _accountManager = accountManager; + + Os.CreateSystemEvent(out _completionEvent, EventClearMode.ManualClear, interProcess: true).AbortOnFailure(); + Os.SignalSystemEvent(ref _completionEvent); // TODO: Figure out where we are supposed to signal this. + } + + [CmifCommand(0)] + public Result GetCompletionEvent([CopyHandle] out int completionEventHandle) + { + completionEventHandle = Os.GetReadableHandleOfSystemEvent(ref _completionEvent); + + return Result.Success; + } + + [CmifCommand(1)] + public Result Cancel() + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend); + + return Result.Success; + } + + [CmifCommand(10100)] + public Result GetFriendListIds( + out int count, + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.Pointer)] Span friendIds, + Uid userId, + int offset, + SizedFriendFilter filter, + ulong pidPlaceholder, + [ClientProcessId] ulong pid) + { + count = 0; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, offset, filter, pidPlaceholder, pid }); + + if (userId.IsNull) + { + return FriendResult.InvalidArgument; + } + + return Result.Success; + } + + [CmifCommand(10101)] + public Result GetFriendList( + out int count, + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span friendList, + Uid userId, + int offset, + SizedFriendFilter filter, + ulong pidPlaceholder, + [ClientProcessId] ulong pid) + { + count = 0; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, offset, filter, pidPlaceholder, pid }); + + if (userId.IsNull) + { + return FriendResult.InvalidArgument; + } + + return Result.Success; + } + + [CmifCommand(10102)] + public Result UpdateFriendInfo( + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span info, + Uid userId, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer)] ReadOnlySpan friendIds, + ulong pidPlaceholder, + [ClientProcessId] ulong pid) + { + string friendIdList = string.Join(", ", friendIds.ToArray()); + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendIdList, pidPlaceholder, pid }); + + return Result.Success; + } + + [CmifCommand(10110)] + public Result GetFriendProfileImage( + out int size, + Uid userId, + NetworkServiceAccountId friendId, + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span profileImage) + { + size = 0; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendId }); + + return Result.Success; + } + + [CmifCommand(10120)] + public Result CheckFriendListAvailability(out bool listAvailable, Uid userId) + { + listAvailable = true; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + [CmifCommand(10121)] + public Result EnsureFriendListAvailable(Uid userId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + [CmifCommand(10200)] + public Result SendFriendRequestForApplication( + Uid userId, + NetworkServiceAccountId friendId, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer, 0x48)] in InAppScreenName arg2, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer, 0x48)] in InAppScreenName arg3, + ulong pidPlaceholder, + [ClientProcessId] ulong pid) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendId, arg2, arg3, pidPlaceholder, pid }); + + return Result.Success; + } + + [CmifCommand(10211)] + public Result AddFacedFriendRequestForApplication( + Uid userId, + FacedFriendRequestRegistrationKey key, + Nickname nickname, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.MapAlias)] ReadOnlySpan arg3, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer, 0x48)] in InAppScreenName arg4, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer, 0x48)] in InAppScreenName arg5, + ulong pidPlaceholder, + [ClientProcessId] ulong pid) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, key, nickname, arg4, arg5, pidPlaceholder, pid }); + + return Result.Success; + } + + [CmifCommand(10400)] + public Result GetBlockedUserListIds( + out int count, + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.Pointer)] Span blockedIds, + Uid userId, + int offset) + { + count = 0; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, offset }); + + return Result.Success; + } + + [CmifCommand(10420)] + public Result CheckBlockedUserListAvailability(out bool listAvailable, Uid userId) + { + listAvailable = true; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + [CmifCommand(10421)] + public Result EnsureBlockedUserListAvailable(Uid userId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + [CmifCommand(10500)] + public Result GetProfileList( + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span profileList, + Uid userId, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer)] ReadOnlySpan friendIds) + { + string friendIdList = string.Join(", ", friendIds.ToArray()); + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendIdList }); + + return Result.Success; + } + + [CmifCommand(10600)] + public Result DeclareOpenOnlinePlaySession(Uid userId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + if (userId.IsNull) + { + return FriendResult.InvalidArgument; + } + + _accountManager.OpenUserOnlinePlay(userId); + + return Result.Success; + } + + [CmifCommand(10601)] + public Result DeclareCloseOnlinePlaySession(Uid userId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + if (userId.IsNull) + { + return FriendResult.InvalidArgument; + } + + _accountManager.CloseUserOnlinePlay(userId); + + return Result.Success; + } + + [CmifCommand(10610)] + public Result UpdateUserPresence( + Uid userId, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer, 0xE0)] in UserPresenceImpl userPresence, + ulong pidPlaceholder, + [ClientProcessId] ulong pid) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, userPresence, pidPlaceholder, pid }); + + return Result.Success; + } + + [CmifCommand(10700)] + public Result GetPlayHistoryRegistrationKey( + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.Pointer, 0x40)] out PlayHistoryRegistrationKey registrationKey, + Uid userId, + bool arg2) + { + if (userId.IsNull) + { + registrationKey = default; + + return FriendResult.InvalidArgument; + } + + // NOTE: Calls nn::friends::detail::service::core::PlayHistoryManager::GetInstance and stores the instance. + + // NOTE: Calls nn::friends::detail::service::core::UuidManager::GetInstance and stores the instance. + // Then calls nn::friends::detail::service::core::AccountStorageManager::GetInstance and stores the instance. + // Then it checks if an Uuid is already stored for the UserId, if not it generates a random Uuid, + // and stores it in the savedata 8000000000000080 in the friends:/uid.bin file. + + /* + + NOTE: The service uses the KeyIndex to get a random key from a keys buffer (since the key index is stored in the returned buffer). + We currently don't support play history and online services so we can use a blank key for now. + Code for reference: + + byte[] hmacKey = new byte[0x20]; + + HMACSHA256 hmacSha256 = new HMACSHA256(hmacKey); + byte[] hmacHash = hmacSha256.ComputeHash(playHistoryRegistrationKeyBuffer); + + */ + + Uid randomGuid = new(); + + Guid.NewGuid().TryWriteBytes(MemoryMarshal.AsBytes(MemoryMarshal.CreateSpan(ref randomGuid, 1))); + + registrationKey = new() + { + Type = 0x101, + KeyIndex = (byte)(Random.Shared.Next() & 7), + UserIdBool = 0, // TODO: Find it. + UnknownBool = (byte)(arg2 ? 1 : 0), // TODO: Find it. + Reserved = new(), + Uuid = randomGuid, + HmacHash = new(), + }; + + return Result.Success; + } + + [CmifCommand(10701)] + public Result GetPlayHistoryRegistrationKeyWithNetworkServiceAccountId( + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.Pointer, 0x40)] out PlayHistoryRegistrationKey registrationKey, + NetworkServiceAccountId friendId, + bool arg2) + { + registrationKey = default; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { friendId, arg2 }); + + return Result.Success; + } + + [CmifCommand(10702)] + public Result AddPlayHistory( + Uid userId, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer, 0x40)] in PlayHistoryRegistrationKey registrationKey, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer, 0x48)] in InAppScreenName arg2, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer, 0x48)] in InAppScreenName arg3, + ulong pidPlaceholder, + [ClientProcessId] ulong pid) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, registrationKey, arg2, arg3, pidPlaceholder, pid }); + + return Result.Success; + } + + [CmifCommand(11000)] + public Result GetProfileImageUrl(out Url imageUrl, Url url, int arg2) + { + imageUrl = default; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { url, arg2 }); + + return Result.Success; + } + + [CmifCommand(20100)] + public Result GetFriendCount(out int count, Uid userId, SizedFriendFilter filter, ulong pidPlaceholder, [ClientProcessId] ulong pid) + { + count = 0; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, filter, pidPlaceholder, pid }); + + return Result.Success; + } + + [CmifCommand(20101)] + public Result GetNewlyFriendCount(out int count, Uid userId) + { + count = 0; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + [CmifCommand(20102)] + public Result GetFriendDetailedInfo( + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.Pointer, 0x800)] out FriendDetailedInfoImpl detailedInfo, + Uid userId, + NetworkServiceAccountId friendId) + { + detailedInfo = default; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendId }); + + return Result.Success; + } + + [CmifCommand(20103)] + public Result SyncFriendList(Uid userId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + [CmifCommand(20104)] + public Result RequestSyncFriendList(Uid userId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + [CmifCommand(20110)] + public Result LoadFriendSetting( + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.Pointer, 0x40)] out FriendSettingImpl friendSetting, + Uid userId, + NetworkServiceAccountId friendId) + { + friendSetting = default; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendId }); + + return Result.Success; + } + + [CmifCommand(20200)] + public Result GetReceivedFriendRequestCount(out int count, out int count2, Uid userId) + { + count = 0; + count2 = 0; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + [CmifCommand(20201)] + public Result GetFriendRequestList( + out int count, + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span requestList, + Uid userId, + int arg3, + int arg4) + { + count = 0; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, arg3, arg4 }); + + return Result.Success; + } + + [CmifCommand(20300)] + public Result GetFriendCandidateList( + out int count, + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span candidateList, + Uid userId, + int arg3) + { + count = 0; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, arg3 }); + + return Result.Success; + } + + [CmifCommand(20301)] + public Result GetNintendoNetworkIdInfo( + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.Pointer, 0x38)] out NintendoNetworkIdUserInfo networkIdInfo, + out int arg1, + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span friendInfo, + Uid userId, + int arg4) + { + networkIdInfo = default; + arg1 = 0; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, arg4 }); + + return Result.Success; + } + + [CmifCommand(20302)] + public Result GetSnsAccountLinkage(out SnsAccountLinkage accountLinkage, Uid userId) + { + accountLinkage = default; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + [CmifCommand(20303)] + public Result GetSnsAccountProfile( + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.Pointer, 0x380)] out SnsAccountProfile accountProfile, + Uid userId, + NetworkServiceAccountId friendId, + int arg3) + { + accountProfile = default; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendId, arg3 }); + + return Result.Success; + } + + [CmifCommand(20304)] + public Result GetSnsAccountFriendList( + out int count, + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span friendList, + Uid userId, + int arg3) + { + count = 0; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, arg3 }); + + return Result.Success; + } + + [CmifCommand(20400)] + public Result GetBlockedUserList( + out int count, + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span blockedUsers, + Uid userId, + int arg3) + { + count = 0; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, arg3 }); + + return Result.Success; + } + + [CmifCommand(20401)] + public Result SyncBlockedUserList(Uid userId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + [CmifCommand(20500)] + public Result GetProfileExtraList( + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span extraList, + Uid userId, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer)] ReadOnlySpan friendIds) + { + string friendIdList = string.Join(", ", friendIds.ToArray()); + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendIdList }); + + return Result.Success; + } + + [CmifCommand(20501)] + public Result GetRelationship(out Relationship relationship, Uid userId, NetworkServiceAccountId friendId) + { + relationship = default; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendId }); + + return Result.Success; + } + + [CmifCommand(20600)] + public Result GetUserPresenceView([Buffer(HipcBufferFlags.Out | HipcBufferFlags.Pointer, 0xE0)] out UserPresenceViewImpl userPresenceView, Uid userId) + { + userPresenceView = default; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + [CmifCommand(20700)] + public Result GetPlayHistoryList(out int count, [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span playHistoryList, Uid userId, int arg3) + { + count = 0; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, arg3 }); + + return Result.Success; + } + + [CmifCommand(20701)] + public Result GetPlayHistoryStatistics(out PlayHistoryStatistics statistics, Uid userId) + { + statistics = default; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + [CmifCommand(20800)] + public Result LoadUserSetting([Buffer(HipcBufferFlags.Out | HipcBufferFlags.Pointer, 0x800)] out UserSettingImpl userSetting, Uid userId) + { + userSetting = default; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + [CmifCommand(20801)] + public Result SyncUserSetting(Uid userId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + [CmifCommand(20900)] + public Result RequestListSummaryOverlayNotification() + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend); + + return Result.Success; + } + + [CmifCommand(21000)] + public Result GetExternalApplicationCatalog( + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.Pointer, 0x4B8)] out ExternalApplicationCatalog catalog, + ExternalApplicationCatalogId catalogId, + LanguageCode language) + { + catalog = default; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { catalogId, language }); + + return Result.Success; + } + + [CmifCommand(22000)] + public Result GetReceivedFriendInvitationList( + out int count, + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span invitationList, + Uid userId) + { + count = 0; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + [CmifCommand(22001)] + public Result GetReceivedFriendInvitationDetailedInfo( + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias, 0x1400)] out FriendInvitationGroupImpl invicationGroup, + Uid userId, + FriendInvitationGroupId groupId) + { + invicationGroup = default; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, groupId }); + + return Result.Success; + } + + [CmifCommand(22010)] + public Result GetReceivedFriendInvitationCountCache(out int count, Uid userId) + { + count = 0; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + [CmifCommand(30100)] + public Result DropFriendNewlyFlags(Uid userId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + [CmifCommand(30101)] + public Result DeleteFriend(Uid userId, NetworkServiceAccountId friendId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendId }); + + return Result.Success; + } + + [CmifCommand(30110)] + public Result DropFriendNewlyFlag(Uid userId, NetworkServiceAccountId friendId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendId }); + + return Result.Success; + } + + [CmifCommand(30120)] + public Result ChangeFriendFavoriteFlag(Uid userId, NetworkServiceAccountId friendId, bool favoriteFlag) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendId, favoriteFlag }); + + return Result.Success; + } + + [CmifCommand(30121)] + public Result ChangeFriendOnlineNotificationFlag(Uid userId, NetworkServiceAccountId friendId, bool onlineNotificationFlag) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendId, onlineNotificationFlag }); + + return Result.Success; + } + + [CmifCommand(30200)] + public Result SendFriendRequest(Uid userId, NetworkServiceAccountId friendId, int arg2) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendId, arg2 }); + + return Result.Success; + } + + [CmifCommand(30201)] + public Result SendFriendRequestWithApplicationInfo( + Uid userId, + NetworkServiceAccountId friendId, + int arg2, + ApplicationInfo applicationInfo, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer, 0x48)] in InAppScreenName arg4, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer, 0x48)] in InAppScreenName arg5) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendId, arg2, applicationInfo, arg4, arg5 }); + + return Result.Success; + } + + [CmifCommand(30202)] + public Result CancelFriendRequest(Uid userId, RequestId requestId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, requestId }); + + return Result.Success; + } + + [CmifCommand(30203)] + public Result AcceptFriendRequest(Uid userId, RequestId requestId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, requestId }); + + return Result.Success; + } + + [CmifCommand(30204)] + public Result RejectFriendRequest(Uid userId, RequestId requestId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, requestId }); + + return Result.Success; + } + + [CmifCommand(30205)] + public Result ReadFriendRequest(Uid userId, RequestId requestId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, requestId }); + + return Result.Success; + } + + [CmifCommand(30210)] + public Result GetFacedFriendRequestRegistrationKey(out FacedFriendRequestRegistrationKey registrationKey, Uid userId) + { + registrationKey = default; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + [CmifCommand(30211)] + public Result AddFacedFriendRequest( + Uid userId, + FacedFriendRequestRegistrationKey registrationKey, + Nickname nickname, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.MapAlias)] ReadOnlySpan arg3) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, registrationKey, nickname }); + + return Result.Success; + } + + [CmifCommand(30212)] + public Result CancelFacedFriendRequest(Uid userId, NetworkServiceAccountId friendId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendId }); + + return Result.Success; + } + + [CmifCommand(30213)] + public Result GetFacedFriendRequestProfileImage( + out int size, + Uid userId, + NetworkServiceAccountId friendId, + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span profileImage) + { + size = 0; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendId }); + + return Result.Success; + } + + [CmifCommand(30214)] + public Result GetFacedFriendRequestProfileImageFromPath( + out int size, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer)] ReadOnlySpan path, + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias)] Span profileImage) + { + size = 0; + + string pathString = Encoding.UTF8.GetString(path); + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { pathString }); + + return Result.Success; + } + + [CmifCommand(30215)] + public Result SendFriendRequestWithExternalApplicationCatalogId( + Uid userId, + NetworkServiceAccountId friendId, + int arg2, + ExternalApplicationCatalogId catalogId, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer, 0x48)] in InAppScreenName arg4, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer, 0x48)] in InAppScreenName arg5) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendId, arg2, catalogId, arg4, arg5 }); + + return Result.Success; + } + + [CmifCommand(30216)] + public Result ResendFacedFriendRequest(Uid userId, NetworkServiceAccountId friendId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendId }); + + return Result.Success; + } + + [CmifCommand(30217)] + public Result SendFriendRequestWithNintendoNetworkIdInfo( + Uid userId, + NetworkServiceAccountId friendId, + int arg2, + MiiName arg3, + MiiImageUrlParam arg4, + MiiName arg5, + MiiImageUrlParam arg6) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendId, arg2, arg3, arg4, arg5, arg6 }); + + return Result.Success; + } + + [CmifCommand(30300)] + public Result GetSnsAccountLinkPageUrl([Buffer(HipcBufferFlags.Out | HipcBufferFlags.MapAlias, 0x1000)] out WebPageUrl url, Uid userId, int arg2) + { + url = default; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, arg2 }); + + return Result.Success; + } + + [CmifCommand(30301)] + public Result UnlinkSnsAccount(Uid userId, int arg1) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, arg1 }); + + return Result.Success; + } + + [CmifCommand(30400)] + public Result BlockUser(Uid userId, NetworkServiceAccountId friendId, int arg2) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendId, arg2 }); + + return Result.Success; + } + + [CmifCommand(30401)] + public Result BlockUserWithApplicationInfo( + Uid userId, + NetworkServiceAccountId friendId, + int arg2, + ApplicationInfo applicationInfo, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer, 0x48)] in InAppScreenName arg4) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendId, arg2, applicationInfo, arg4 }); + + return Result.Success; + } + + [CmifCommand(30402)] + public Result UnblockUser(Uid userId, NetworkServiceAccountId friendId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendId }); + + return Result.Success; + } + + [CmifCommand(30500)] + public Result GetProfileExtraFromFriendCode( + [Buffer(HipcBufferFlags.Out | HipcBufferFlags.Pointer, 0x400)] out ProfileExtraImpl profileExtra, + Uid userId, + FriendCode friendCode) + { + profileExtra = default; + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendCode }); + + return Result.Success; + } + + [CmifCommand(30700)] + public Result DeletePlayHistory(Uid userId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + [CmifCommand(30810)] + public Result ChangePresencePermission(Uid userId, int permission) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, permission }); + + return Result.Success; + } + + [CmifCommand(30811)] + public Result ChangeFriendRequestReception(Uid userId, bool reception) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, reception }); + + return Result.Success; + } + + [CmifCommand(30812)] + public Result ChangePlayLogPermission(Uid userId, int permission) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, permission }); + + return Result.Success; + } + + [CmifCommand(30820)] + public Result IssueFriendCode(Uid userId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + [CmifCommand(30830)] + public Result ClearPlayLog(Uid userId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + [CmifCommand(30900)] + public Result SendFriendInvitation( + Uid userId, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer)] ReadOnlySpan friendIds, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.MapAlias, 0xC00)] in FriendInvitationGameModeDescription description, + ApplicationInfo applicationInfo, + [Buffer(HipcBufferFlags.In | HipcBufferFlags.MapAlias)] ReadOnlySpan arg4, + bool arg5) + { + string friendIdList = string.Join(", ", friendIds.ToArray()); + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, friendIdList, description, applicationInfo, arg5 }); + + return Result.Success; + } + + [CmifCommand(30910)] + public Result ReadFriendInvitation(Uid userId, [Buffer(HipcBufferFlags.In | HipcBufferFlags.Pointer)] ReadOnlySpan invitationIds) + { + string invitationIdList = string.Join(", ", invitationIds.ToArray()); + + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId, invitationIdList }); + + return Result.Success; + } + + [CmifCommand(30911)] + public Result ReadAllFriendInvitations(Uid userId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + [CmifCommand(40100)] + public Result DeleteFriendListCache(Uid userId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + [CmifCommand(40400)] + public Result DeleteBlockedUserListCache(Uid userId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + [CmifCommand(49900)] + public Result DeleteNetworkServiceAccountCache(Uid userId) + { + Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { userId }); + + return Result.Success; + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + Os.DestroySystemEvent(ref _completionEvent); + } + } + + public void Dispose() + { + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + } +} diff --git a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/Types/FriendServicePermissionLevel.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/FriendsServicePermissionLevel.cs similarity index 64% rename from src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/Types/FriendServicePermissionLevel.cs rename to src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/FriendsServicePermissionLevel.cs index 7902d9c53..f4bbe100f 100644 --- a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/Types/FriendServicePermissionLevel.cs +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/FriendsServicePermissionLevel.cs @@ -1,16 +1,13 @@ -using System; - -namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator +namespace Ryujinx.Horizon.Sdk.Friends.Detail.Ipc { - [Flags] - enum FriendServicePermissionLevel + enum FriendsServicePermissionLevel { UserMask = 1, ViewerMask = 2, ManagerMask = 4, SystemMask = 8, - Administrator = -1, + Admin = -1, User = UserMask, Viewer = UserMask | ViewerMask, Manager = UserMask | ViewerMask | ManagerMask, diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/IDaemonSuspendSessionService.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/IDaemonSuspendSessionService.cs new file mode 100644 index 000000000..2bb0434e8 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/IDaemonSuspendSessionService.cs @@ -0,0 +1,9 @@ +using Ryujinx.Horizon.Sdk.Sf; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail.Ipc +{ + interface IDaemonSuspendSessionService : IServiceObject + { + // NOTE: This service has no commands. + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/IFriendService.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/IFriendService.cs new file mode 100644 index 000000000..c19d0b788 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/IFriendService.cs @@ -0,0 +1,97 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Account; +using Ryujinx.Horizon.Sdk.Settings; +using Ryujinx.Horizon.Sdk.Sf; +using System; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail.Ipc +{ + interface IFriendService : IServiceObject + { + Result GetCompletionEvent(out int completionEventHandle); + Result Cancel(); + Result GetFriendListIds(out int count, Span friendIds, Uid userId, int offset, SizedFriendFilter filter, ulong pidPlaceholder, ulong pid); + Result GetFriendList(out int count, Span friendList, Uid userId, int offset, SizedFriendFilter filter, ulong pidPlaceholder, ulong pid); + Result UpdateFriendInfo(Span info, Uid userId, ReadOnlySpan friendIds, ulong pidPlaceholder, ulong pid); + Result GetFriendProfileImage(out int size, Uid userId, NetworkServiceAccountId friendId, Span profileImage); + Result CheckFriendListAvailability(out bool listAvailable, Uid userId); + Result EnsureFriendListAvailable(Uid userId); + Result SendFriendRequestForApplication(Uid userId, NetworkServiceAccountId friendId, in InAppScreenName arg2, in InAppScreenName arg3, ulong pidPlaceholder, ulong pid); + Result AddFacedFriendRequestForApplication(Uid userId, FacedFriendRequestRegistrationKey key, Nickname nickname, ReadOnlySpan arg3, in InAppScreenName arg4, in InAppScreenName arg5, ulong pidPlaceholder, ulong pid); + Result GetBlockedUserListIds(out int count, Span blockedIds, Uid userId, int offset); + Result CheckBlockedUserListAvailability(out bool listAvailable, Uid userId); + Result EnsureBlockedUserListAvailable(Uid userId); + Result GetProfileList(Span profileList, Uid userId, ReadOnlySpan friendIds); + Result DeclareOpenOnlinePlaySession(Uid userId); + Result DeclareCloseOnlinePlaySession(Uid userId); + Result UpdateUserPresence(Uid userId, in UserPresenceImpl userPresence, ulong pidPlaceholder, ulong pid); + Result GetPlayHistoryRegistrationKey(out PlayHistoryRegistrationKey registrationKey, Uid userId, bool arg2); + Result GetPlayHistoryRegistrationKeyWithNetworkServiceAccountId(out PlayHistoryRegistrationKey registrationKey, NetworkServiceAccountId friendId, bool arg2); + Result AddPlayHistory(Uid userId, in PlayHistoryRegistrationKey registrationKey, in InAppScreenName arg2, in InAppScreenName arg3, ulong pidPlaceholder, ulong pid); + Result GetProfileImageUrl(out Url imageUrl, Url url, int arg2); + Result GetFriendCount(out int count, Uid userId, SizedFriendFilter filter, ulong pidPlaceholder, ulong pid); + Result GetNewlyFriendCount(out int count, Uid userId); + Result GetFriendDetailedInfo(out FriendDetailedInfoImpl detailedInfo, Uid userId, NetworkServiceAccountId friendId); + Result SyncFriendList(Uid userId); + Result RequestSyncFriendList(Uid userId); + Result LoadFriendSetting(out FriendSettingImpl friendSetting, Uid userId, NetworkServiceAccountId friendId); + Result GetReceivedFriendRequestCount(out int count, out int count2, Uid userId); + Result GetFriendRequestList(out int count, Span requestList, Uid userId, int arg3, int arg4); + Result GetFriendCandidateList(out int count, Span candidateList, Uid userId, int arg3); + Result GetNintendoNetworkIdInfo(out NintendoNetworkIdUserInfo networkIdInfo, out int arg1, Span friendInfo, Uid userId, int arg4); + Result GetSnsAccountLinkage(out SnsAccountLinkage accountLinkage, Uid userId); + Result GetSnsAccountProfile(out SnsAccountProfile accountProfile, Uid userId, NetworkServiceAccountId friendId, int arg3); + Result GetSnsAccountFriendList(out int count, Span friendList, Uid userId, int arg3); + Result GetBlockedUserList(out int count, Span blockedUsers, Uid userId, int arg3); + Result SyncBlockedUserList(Uid userId); + Result GetProfileExtraList(Span extraList, Uid userId, ReadOnlySpan friendIds); + Result GetRelationship(out Relationship relationship, Uid userId, NetworkServiceAccountId friendId); + Result GetUserPresenceView(out UserPresenceViewImpl userPresenceView, Uid userId); + Result GetPlayHistoryList(out int count, Span playHistoryList, Uid userId, int arg3); + Result GetPlayHistoryStatistics(out PlayHistoryStatistics statistics, Uid userId); + Result LoadUserSetting(out UserSettingImpl userSetting, Uid userId); + Result SyncUserSetting(Uid userId); + Result RequestListSummaryOverlayNotification(); + Result GetExternalApplicationCatalog(out ExternalApplicationCatalog catalog, ExternalApplicationCatalogId catalogId, LanguageCode language); + Result GetReceivedFriendInvitationList(out int count, Span invitationList, Uid userId); + Result GetReceivedFriendInvitationDetailedInfo(out FriendInvitationGroupImpl invicationGroup, Uid userId, FriendInvitationGroupId groupId); + Result GetReceivedFriendInvitationCountCache(out int count, Uid userId); + Result DropFriendNewlyFlags(Uid userId); + Result DeleteFriend(Uid userId, NetworkServiceAccountId friendId); + Result DropFriendNewlyFlag(Uid userId, NetworkServiceAccountId friendId); + Result ChangeFriendFavoriteFlag(Uid userId, NetworkServiceAccountId friendId, bool favoriteFlag); + Result ChangeFriendOnlineNotificationFlag(Uid userId, NetworkServiceAccountId friendId, bool onlineNotificationFlag); + Result SendFriendRequest(Uid userId, NetworkServiceAccountId friendId, int arg2); + Result SendFriendRequestWithApplicationInfo(Uid userId, NetworkServiceAccountId friendId, int arg2, ApplicationInfo applicationInfo, in InAppScreenName arg4, in InAppScreenName arg5); + Result CancelFriendRequest(Uid userId, RequestId requestId); + Result AcceptFriendRequest(Uid userId, RequestId requestId); + Result RejectFriendRequest(Uid userId, RequestId requestId); + Result ReadFriendRequest(Uid userId, RequestId requestId); + Result GetFacedFriendRequestRegistrationKey(out FacedFriendRequestRegistrationKey registrationKey, Uid userId); + Result AddFacedFriendRequest(Uid userId, FacedFriendRequestRegistrationKey registrationKey, Nickname nickname, ReadOnlySpan arg3); + Result CancelFacedFriendRequest(Uid userId, NetworkServiceAccountId friendId); + Result GetFacedFriendRequestProfileImage(out int size, Uid userId, NetworkServiceAccountId friendId, Span profileImage); + Result GetFacedFriendRequestProfileImageFromPath(out int size, ReadOnlySpan path, Span profileImage); + Result SendFriendRequestWithExternalApplicationCatalogId(Uid userId, NetworkServiceAccountId friendId, int arg2, ExternalApplicationCatalogId catalogId, in InAppScreenName arg4, in InAppScreenName arg5); + Result ResendFacedFriendRequest(Uid userId, NetworkServiceAccountId friendId); + Result SendFriendRequestWithNintendoNetworkIdInfo(Uid userId, NetworkServiceAccountId friendId, int arg2, MiiName arg3, MiiImageUrlParam arg4, MiiName arg5, MiiImageUrlParam arg6); + Result GetSnsAccountLinkPageUrl(out WebPageUrl url, Uid userId, int arg2); + Result UnlinkSnsAccount(Uid userId, int arg1); + Result BlockUser(Uid userId, NetworkServiceAccountId friendId, int arg2); + Result BlockUserWithApplicationInfo(Uid userId, NetworkServiceAccountId friendId, int arg2, ApplicationInfo applicationInfo, in InAppScreenName arg4); + Result UnblockUser(Uid userId, NetworkServiceAccountId friendId); + Result GetProfileExtraFromFriendCode(out ProfileExtraImpl profileExtra, Uid userId, FriendCode friendCode); + Result DeletePlayHistory(Uid userId); + Result ChangePresencePermission(Uid userId, int permission); + Result ChangeFriendRequestReception(Uid userId, bool reception); + Result ChangePlayLogPermission(Uid userId, int permission); + Result IssueFriendCode(Uid userId); + Result ClearPlayLog(Uid userId); + Result SendFriendInvitation(Uid userId, ReadOnlySpan friendIds, in FriendInvitationGameModeDescription description, ApplicationInfo applicationInfo, ReadOnlySpan arg4, bool arg5); + Result ReadFriendInvitation(Uid userId, ReadOnlySpan invitationIds); + Result ReadAllFriendInvitations(Uid userId); + Result DeleteFriendListCache(Uid userId); + Result DeleteBlockedUserListCache(Uid userId); + Result DeleteNetworkServiceAccountCache(Uid userId); + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/INotificationService.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/INotificationService.cs new file mode 100644 index 000000000..a3a28e8ce --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/INotificationService.cs @@ -0,0 +1,12 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Sf; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail.Ipc +{ + interface INotificationService : IServiceObject + { + Result GetEvent(out int eventHandle); + Result Clear(); + Result Pop(out SizedNotificationInfo sizedNotificationInfo); + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/IServiceCreator.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/IServiceCreator.cs new file mode 100644 index 000000000..58e2569bb --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/IServiceCreator.cs @@ -0,0 +1,13 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Account; +using Ryujinx.Horizon.Sdk.Sf; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail.Ipc +{ + interface IServiceCreator : IServiceObject + { + Result CreateFriendService(out IFriendService friendService); + Result CreateNotificationService(out INotificationService notificationService, Uid userId); + Result CreateDaemonSuspendSessionService(out IDaemonSuspendSessionService daemonSuspendSessionService); + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/NotificationEventHandler.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/NotificationEventHandler.cs new file mode 100644 index 000000000..61c692a6e --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/NotificationEventHandler.cs @@ -0,0 +1,58 @@ +using Ryujinx.Horizon.Sdk.Account; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail.Ipc +{ + sealed class NotificationEventHandler + { + private readonly NotificationService[] _registry; + + public NotificationEventHandler() + { + _registry = new NotificationService[0x20]; + } + + public void RegisterNotificationService(NotificationService service) + { + // NOTE: When there's no enough space in the registry array, Nintendo doesn't return any errors. + for (int i = 0; i < _registry.Length; i++) + { + if (_registry[i] == null) + { + _registry[i] = service; + break; + } + } + } + + public void UnregisterNotificationService(NotificationService service) + { + // NOTE: When there's no enough space in the registry array, Nintendo doesn't return any errors. + for (int i = 0; i < _registry.Length; i++) + { + if (_registry[i] == service) + { + _registry[i] = null; + break; + } + } + } + + // TODO: Use this when we have enough things to go online. + public void SignalFriendListUpdate(Uid targetId) + { + for (int i = 0; i < _registry.Length; i++) + { + _registry[i]?.SignalFriendListUpdate(targetId); + } + } + + // TODO: Use this when we have enough things to go online. + public void SignalNewFriendRequest(Uid targetId) + { + for (int i = 0; i < _registry.Length; i++) + { + _registry[i]?.SignalNewFriendRequest(targetId); + } + } + } +} diff --git a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/NotificationService/Types/NotificationEventType.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/NotificationEventType.cs similarity index 64% rename from src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/NotificationService/Types/NotificationEventType.cs rename to src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/NotificationEventType.cs index 363e03eaf..e46fc9b7a 100644 --- a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/NotificationService/Types/NotificationEventType.cs +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/NotificationEventType.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.NotificationService +namespace Ryujinx.Horizon.Sdk.Friends.Detail.Ipc { enum NotificationEventType : uint { diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/NotificationService.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/NotificationService.cs new file mode 100644 index 000000000..534bf63ed --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/NotificationService.cs @@ -0,0 +1,172 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Account; +using Ryujinx.Horizon.Sdk.OsTypes; +using Ryujinx.Horizon.Sdk.Sf; +using System; +using System.Collections.Generic; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail.Ipc +{ + partial class NotificationService : INotificationService, IDisposable + { + private readonly NotificationEventHandler _notificationEventHandler; + private readonly Uid _userId; + private readonly FriendsServicePermissionLevel _permissionLevel; + + private readonly object _lock = new(); + + private SystemEventType _notificationEvent; + + private readonly LinkedList _notifications; + + private bool _hasNewFriendRequest; + private bool _hasFriendListUpdate; + + public NotificationService(NotificationEventHandler notificationEventHandler, Uid userId, FriendsServicePermissionLevel permissionLevel) + { + _notificationEventHandler = notificationEventHandler; + _userId = userId; + _permissionLevel = permissionLevel; + _notifications = new LinkedList(); + Os.CreateSystemEvent(out _notificationEvent, EventClearMode.AutoClear, interProcess: true).AbortOnFailure(); + + _hasNewFriendRequest = false; + _hasFriendListUpdate = false; + + notificationEventHandler.RegisterNotificationService(this); + } + + [CmifCommand(0)] + public Result GetEvent([CopyHandle] out int eventHandle) + { + eventHandle = Os.GetReadableHandleOfSystemEvent(ref _notificationEvent); + + return Result.Success; + } + + [CmifCommand(1)] + public Result Clear() + { + lock (_lock) + { + _hasNewFriendRequest = false; + _hasFriendListUpdate = false; + + _notifications.Clear(); + } + + return Result.Success; + } + + [CmifCommand(2)] + public Result Pop(out SizedNotificationInfo sizedNotificationInfo) + { + lock (_lock) + { + if (_notifications.Count >= 1) + { + sizedNotificationInfo = _notifications.First.Value; + _notifications.RemoveFirst(); + + if (sizedNotificationInfo.Type == NotificationEventType.FriendListUpdate) + { + _hasFriendListUpdate = false; + } + else if (sizedNotificationInfo.Type == NotificationEventType.NewFriendRequest) + { + _hasNewFriendRequest = false; + } + + return Result.Success; + } + } + + sizedNotificationInfo = default; + + return FriendResult.NotificationQueueEmpty; + } + + public void SignalFriendListUpdate(Uid targetId) + { + lock (_lock) + { + if (_userId == targetId) + { + if (!_hasFriendListUpdate) + { + SizedNotificationInfo friendListNotification = new(); + + if (_notifications.Count != 0) + { + friendListNotification = _notifications.First.Value; + _notifications.RemoveFirst(); + } + + friendListNotification.Type = NotificationEventType.FriendListUpdate; + _hasFriendListUpdate = true; + + if (_hasNewFriendRequest) + { + SizedNotificationInfo newFriendRequestNotification = new(); + + if (_notifications.Count != 0) + { + newFriendRequestNotification = _notifications.First.Value; + _notifications.RemoveFirst(); + } + + newFriendRequestNotification.Type = NotificationEventType.NewFriendRequest; + _notifications.AddFirst(newFriendRequestNotification); + } + + // We defer this to make sure we are on top of the queue. + _notifications.AddFirst(friendListNotification); + } + + Os.SignalSystemEvent(ref _notificationEvent); + } + } + } + + public void SignalNewFriendRequest(Uid targetId) + { + lock (_lock) + { + if (_permissionLevel.HasFlag(FriendsServicePermissionLevel.ViewerMask) && _userId == targetId) + { + if (!_hasNewFriendRequest) + { + if (_notifications.Count == 100) + { + SignalFriendListUpdate(targetId); + } + + SizedNotificationInfo newFriendRequestNotification = new() + { + Type = NotificationEventType.NewFriendRequest, + }; + + _notifications.AddLast(newFriendRequestNotification); + _hasNewFriendRequest = true; + } + + Os.SignalSystemEvent(ref _notificationEvent); + } + } + } + + protected virtual void Dispose(bool disposing) + { + if (disposing) + { + _notificationEventHandler.UnregisterNotificationService(this); + } + } + + public void Dispose() + { + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + } +} diff --git a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/PresenceStatusFilter.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/PresenceStatusFilter.cs similarity index 64% rename from src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/PresenceStatusFilter.cs rename to src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/PresenceStatusFilter.cs index c9a54250f..3ea105872 100644 --- a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/PresenceStatusFilter.cs +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/PresenceStatusFilter.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService +namespace Ryujinx.Horizon.Sdk.Friends.Detail.Ipc { enum PresenceStatusFilter : uint { diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/ServiceCreator.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/ServiceCreator.cs new file mode 100644 index 000000000..1be804dfd --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/ServiceCreator.cs @@ -0,0 +1,51 @@ +using Ryujinx.Horizon.Common; +using Ryujinx.Horizon.Sdk.Account; +using Ryujinx.Horizon.Sdk.Sf; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail.Ipc +{ + partial class ServiceCreator : IServiceCreator + { + private readonly IEmulatorAccountManager _accountManager; + private readonly NotificationEventHandler _notificationEventHandler; + private readonly FriendsServicePermissionLevel _permissionLevel; + + public ServiceCreator(IEmulatorAccountManager accountManager, NotificationEventHandler notificationEventHandler, FriendsServicePermissionLevel permissionLevel) + { + _accountManager = accountManager; + _notificationEventHandler = notificationEventHandler; + _permissionLevel = permissionLevel; + } + + [CmifCommand(0)] + public Result CreateFriendService(out IFriendService friendService) + { + friendService = new FriendService(_accountManager, _permissionLevel); + + return Result.Success; + } + + [CmifCommand(1)] // 2.0.0+ + public Result CreateNotificationService(out INotificationService notificationService, Uid userId) + { + if (userId.IsNull) + { + notificationService = null; + + return FriendResult.InvalidArgument; + } + + notificationService = new NotificationService(_notificationEventHandler, userId, _permissionLevel); + + return Result.Success; + } + + [CmifCommand(2)] // 4.0.0+ + public Result CreateDaemonSuspendSessionService(out IDaemonSuspendSessionService daemonSuspendSessionService) + { + daemonSuspendSessionService = new DaemonSuspendSessionService(); + + return Result.Success; + } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/SizedFriendFilter.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/SizedFriendFilter.cs new file mode 100644 index 000000000..d93a2ae29 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/SizedFriendFilter.cs @@ -0,0 +1,25 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail.Ipc +{ + [StructLayout(LayoutKind.Sequential, Size = 0x10, Pack = 0x8)] + struct SizedFriendFilter + { + public PresenceStatusFilter PresenceStatus; + public bool IsFavoriteOnly; + public bool IsSameAppPresenceOnly; + public bool IsSameAppPlayedOnly; + public bool IsArbitraryAppPlayedOnly; + public ulong PresenceGroupId; + + public readonly override string ToString() + { + return $"{{ PresenceStatus: {PresenceStatus}, " + + $"IsFavoriteOnly: {IsFavoriteOnly}, " + + $"IsSameAppPresenceOnly: {IsSameAppPresenceOnly}, " + + $"IsSameAppPlayedOnly: {IsSameAppPlayedOnly}, " + + $"IsArbitraryAppPlayedOnly: {IsArbitraryAppPlayedOnly}, " + + $"PresenceGroupId: {PresenceGroupId} }}"; + } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/SizedNotificationInfo.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/SizedNotificationInfo.cs new file mode 100644 index 000000000..0da26a1ae --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/Ipc/SizedNotificationInfo.cs @@ -0,0 +1,13 @@ +using Ryujinx.Horizon.Sdk.Account; +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail.Ipc +{ + [StructLayout(LayoutKind.Sequential, Size = 0x10, Pack = 0x8)] + struct SizedNotificationInfo + { + public NotificationEventType Type; + public uint Padding; + public NetworkServiceAccountId NetworkUserIdPlaceholder; + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/NintendoNetworkIdFriendImpl.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/NintendoNetworkIdFriendImpl.cs new file mode 100644 index 000000000..66d61e4c1 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/NintendoNetworkIdFriendImpl.cs @@ -0,0 +1,8 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail +{ + struct NintendoNetworkIdFriendImpl + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/PlayHistoryImpl.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/PlayHistoryImpl.cs new file mode 100644 index 000000000..9f90f0c8f --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/PlayHistoryImpl.cs @@ -0,0 +1,8 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail +{ + struct PlayHistoryImpl + { + } +} diff --git a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/PresenceStatus.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/PresenceStatus.cs similarity index 58% rename from src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/PresenceStatus.cs rename to src/Ryujinx.Horizon/Sdk/Friends/Detail/PresenceStatus.cs index 7930aff0b..5ddbe14ea 100644 --- a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/FriendService/Types/PresenceStatus.cs +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/PresenceStatus.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService +namespace Ryujinx.Horizon.Sdk.Friends.Detail { enum PresenceStatus : uint { diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/ProfileExtraImpl.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/ProfileExtraImpl.cs new file mode 100644 index 000000000..1548d725f --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/ProfileExtraImpl.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail +{ + [StructLayout(LayoutKind.Sequential, Size = 0x400)] + struct ProfileExtraImpl + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/ProfileImpl.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/ProfileImpl.cs new file mode 100644 index 000000000..f779d93cf --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/ProfileImpl.cs @@ -0,0 +1,8 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail +{ + struct ProfileImpl + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/SnsAccountFriendImpl.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/SnsAccountFriendImpl.cs new file mode 100644 index 000000000..dc6adf03a --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/SnsAccountFriendImpl.cs @@ -0,0 +1,8 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail +{ + struct SnsAccountFriendImpl + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/UserPresenceImpl.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/UserPresenceImpl.cs new file mode 100644 index 000000000..cf4520cf4 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/UserPresenceImpl.cs @@ -0,0 +1,29 @@ +using Ryujinx.Common.Memory; +using Ryujinx.Horizon.Sdk.Account; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail +{ + [StructLayout(LayoutKind.Sequential, Size = 0xE0)] + struct UserPresenceImpl + { + public Uid UserId; + public long LastTimeOnlineTimestamp; + public PresenceStatus Status; + public bool SamePresenceGroupApplication; + public Array3 Unknown; + public AppKeyValueStorageHolder AppKeyValueStorage; + + [InlineArray(0xC0)] + public struct AppKeyValueStorageHolder + { + public byte Value; + } + + public readonly override string ToString() + { + return $"{{ UserId: {UserId}, LastTimeOnlineTimestamp: {LastTimeOnlineTimestamp}, Status: {Status} }}"; + } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/UserPresenceViewImpl.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/UserPresenceViewImpl.cs new file mode 100644 index 000000000..04c092600 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/UserPresenceViewImpl.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail +{ + [StructLayout(LayoutKind.Sequential, Size = 0xE0)] + struct UserPresenceViewImpl + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Detail/UserSettingImpl.cs b/src/Ryujinx.Horizon/Sdk/Friends/Detail/UserSettingImpl.cs new file mode 100644 index 000000000..9d057fb1e --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Detail/UserSettingImpl.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends.Detail +{ + [StructLayout(LayoutKind.Sequential, Size = 0x800)] + struct UserSettingImpl + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/ExternalApplicationCatalog.cs b/src/Ryujinx.Horizon/Sdk/Friends/ExternalApplicationCatalog.cs new file mode 100644 index 000000000..0d9c157d3 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/ExternalApplicationCatalog.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends +{ + [StructLayout(LayoutKind.Sequential, Size = 0x4B8)] + struct ExternalApplicationCatalog + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/ExternalApplicationCatalogId.cs b/src/Ryujinx.Horizon/Sdk/Friends/ExternalApplicationCatalogId.cs new file mode 100644 index 000000000..7ed36cd9d --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/ExternalApplicationCatalogId.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends +{ + [StructLayout(LayoutKind.Sequential, Size = 0x10, Pack = 0x8)] + struct ExternalApplicationCatalogId + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/FacedFriendRequestRegistrationKey.cs b/src/Ryujinx.Horizon/Sdk/Friends/FacedFriendRequestRegistrationKey.cs new file mode 100644 index 000000000..6b5812f64 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/FacedFriendRequestRegistrationKey.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends +{ + [StructLayout(LayoutKind.Sequential, Size = 0x40, Pack = 0x1)] + struct FacedFriendRequestRegistrationKey + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/FriendCode.cs b/src/Ryujinx.Horizon/Sdk/Friends/FriendCode.cs new file mode 100644 index 000000000..d78497a18 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/FriendCode.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends +{ + [StructLayout(LayoutKind.Sequential, Size = 0x20, Pack = 0x1)] + struct FriendCode + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/FriendInvitationGameModeDescription.cs b/src/Ryujinx.Horizon/Sdk/Friends/FriendInvitationGameModeDescription.cs new file mode 100644 index 000000000..29b4a0974 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/FriendInvitationGameModeDescription.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends +{ + [StructLayout(LayoutKind.Sequential, Size = 0xC00)] + struct FriendInvitationGameModeDescription + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/FriendInvitationGroupId.cs b/src/Ryujinx.Horizon/Sdk/Friends/FriendInvitationGroupId.cs new file mode 100644 index 000000000..ef53882b3 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/FriendInvitationGroupId.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends +{ + [StructLayout(LayoutKind.Sequential, Size = 0x8, Pack = 0x8)] + struct FriendInvitationGroupId + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/FriendInvitationId.cs b/src/Ryujinx.Horizon/Sdk/Friends/FriendInvitationId.cs new file mode 100644 index 000000000..7be19d574 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/FriendInvitationId.cs @@ -0,0 +1,8 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends +{ + struct FriendInvitationId + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/FriendResult.cs b/src/Ryujinx.Horizon/Sdk/Friends/FriendResult.cs new file mode 100644 index 000000000..5965d508d --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/FriendResult.cs @@ -0,0 +1,13 @@ +using Ryujinx.Horizon.Common; + +namespace Ryujinx.Horizon.Sdk.Friends +{ + static class FriendResult + { + private const int ModuleId = 121; + + public static Result InvalidArgument => new(ModuleId, 2); + public static Result InternetRequestDenied => new(ModuleId, 6); + public static Result NotificationQueueEmpty => new(ModuleId, 15); + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/InAppScreenName.cs b/src/Ryujinx.Horizon/Sdk/Friends/InAppScreenName.cs new file mode 100644 index 000000000..22574a5cc --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/InAppScreenName.cs @@ -0,0 +1,26 @@ +using Ryujinx.Common.Memory; +using Ryujinx.Horizon.Sdk.Settings; +using System; +using System.Runtime.InteropServices; +using System.Text; + +namespace Ryujinx.Horizon.Sdk.Friends +{ + [StructLayout(LayoutKind.Sequential, Size = 0x48)] + struct InAppScreenName + { + public Array64 Name; + public LanguageCode LanguageCode; + + public override readonly string ToString() + { + int length = Name.AsSpan().IndexOf((byte)0); + if (length < 0) + { + length = 64; + } + + return Encoding.UTF8.GetString(Name.AsSpan()[..length]); + } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/MiiImageUrlParam.cs b/src/Ryujinx.Horizon/Sdk/Friends/MiiImageUrlParam.cs new file mode 100644 index 000000000..8790bb931 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/MiiImageUrlParam.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends +{ + [StructLayout(LayoutKind.Sequential, Size = 0x10, Pack = 0x1)] + struct MiiImageUrlParam + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/MiiName.cs b/src/Ryujinx.Horizon/Sdk/Friends/MiiName.cs new file mode 100644 index 000000000..e73c0d833 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/MiiName.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends +{ + [StructLayout(LayoutKind.Sequential, Size = 0x20, Pack = 0x1)] + struct MiiName + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/NintendoNetworkIdUserInfo.cs b/src/Ryujinx.Horizon/Sdk/Friends/NintendoNetworkIdUserInfo.cs new file mode 100644 index 000000000..a2a9e046f --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/NintendoNetworkIdUserInfo.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends +{ + [StructLayout(LayoutKind.Sequential, Size = 0x38)] + struct NintendoNetworkIdUserInfo + { + } +} diff --git a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/Types/PlayHistoryRegistrationKey.cs b/src/Ryujinx.Horizon/Sdk/Friends/PlayHistoryRegistrationKey.cs similarity index 59% rename from src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/Types/PlayHistoryRegistrationKey.cs rename to src/Ryujinx.Horizon/Sdk/Friends/PlayHistoryRegistrationKey.cs index 9687c5478..bb672a795 100644 --- a/src/Ryujinx.HLE/HOS/Services/Friend/ServiceCreator/Types/PlayHistoryRegistrationKey.cs +++ b/src/Ryujinx.Horizon/Sdk/Friends/PlayHistoryRegistrationKey.cs @@ -1,9 +1,10 @@ using Ryujinx.Common.Memory; +using Ryujinx.Horizon.Sdk.Account; using System.Runtime.InteropServices; -namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator +namespace Ryujinx.Horizon.Sdk.Friends { - [StructLayout(LayoutKind.Sequential, Size = 0x20)] + [StructLayout(LayoutKind.Sequential, Size = 0x40)] struct PlayHistoryRegistrationKey { public ushort Type; @@ -11,6 +12,7 @@ namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator public byte UserIdBool; public byte UnknownBool; public Array11 Reserved; - public Array16 Uuid; + public Uid Uuid; + public Array32 HmacHash; } } diff --git a/src/Ryujinx.Horizon/Sdk/Friends/PlayHistoryStatistics.cs b/src/Ryujinx.Horizon/Sdk/Friends/PlayHistoryStatistics.cs new file mode 100644 index 000000000..ea3e3d997 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/PlayHistoryStatistics.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends +{ + [StructLayout(LayoutKind.Sequential, Size = 0x10, Pack = 0x8)] + struct PlayHistoryStatistics + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Relationship.cs b/src/Ryujinx.Horizon/Sdk/Friends/Relationship.cs new file mode 100644 index 000000000..efba09a8f --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Relationship.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends +{ + [StructLayout(LayoutKind.Sequential, Size = 0x8, Pack = 0x1)] + struct Relationship + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/RequestId.cs b/src/Ryujinx.Horizon/Sdk/Friends/RequestId.cs new file mode 100644 index 000000000..3236a1d7d --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/RequestId.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends +{ + [StructLayout(LayoutKind.Sequential, Size = 0x8, Pack = 0x8)] + struct RequestId + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/SnsAccountLinkage.cs b/src/Ryujinx.Horizon/Sdk/Friends/SnsAccountLinkage.cs new file mode 100644 index 000000000..b4660d9e7 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/SnsAccountLinkage.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends +{ + [StructLayout(LayoutKind.Sequential, Size = 0x8, Pack = 0x1)] + struct SnsAccountLinkage + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/SnsAccountProfile.cs b/src/Ryujinx.Horizon/Sdk/Friends/SnsAccountProfile.cs new file mode 100644 index 000000000..d872b3dac --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/SnsAccountProfile.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends +{ + [StructLayout(LayoutKind.Sequential, Size = 0x380)] + struct SnsAccountProfile + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/Url.cs b/src/Ryujinx.Horizon/Sdk/Friends/Url.cs new file mode 100644 index 000000000..833ee1230 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/Url.cs @@ -0,0 +1,30 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Text; + +namespace Ryujinx.Horizon.Sdk.Friends +{ + [StructLayout(LayoutKind.Sequential, Size = 0xA0, Pack = 0x1)] + struct Url + { + public UrlStorage Path; + + [InlineArray(0xA0)] + public struct UrlStorage + { + public byte Value; + } + + public override readonly string ToString() + { + int length = ((ReadOnlySpan)Path).IndexOf((byte)0); + if (length < 0) + { + length = 33; + } + + return Encoding.UTF8.GetString(((ReadOnlySpan)Path)[..length]); + } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Friends/WebPageUrl.cs b/src/Ryujinx.Horizon/Sdk/Friends/WebPageUrl.cs new file mode 100644 index 000000000..85488af61 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Friends/WebPageUrl.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Friends +{ + [StructLayout(LayoutKind.Sequential, Size = 0x1000)] + struct WebPageUrl + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Ncm/ApplicationId.cs b/src/Ryujinx.Horizon/Sdk/Ncm/ApplicationId.cs index 4c5e76e6f..24b7d9cab 100644 --- a/src/Ryujinx.Horizon/Sdk/Ncm/ApplicationId.cs +++ b/src/Ryujinx.Horizon/Sdk/Ncm/ApplicationId.cs @@ -1,6 +1,6 @@ namespace Ryujinx.Horizon.Sdk.Ncm { - readonly struct ApplicationId + public readonly struct ApplicationId { public readonly ulong Id; diff --git a/src/Ryujinx.Horizon/Sdk/Ncm/StorageId.cs b/src/Ryujinx.Horizon/Sdk/Ncm/StorageId.cs new file mode 100644 index 000000000..e2fb32505 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Ncm/StorageId.cs @@ -0,0 +1,13 @@ +namespace Ryujinx.Horizon.Sdk.Ncm +{ + public enum StorageId : byte + { + None, + Host, + GameCard, + BuiltInSystem, + BuiltInUser, + SdCard, + Any, + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Ns/ApplicationControlProperty.cs b/src/Ryujinx.Horizon/Sdk/Ns/ApplicationControlProperty.cs new file mode 100644 index 000000000..12c19168d --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Ns/ApplicationControlProperty.cs @@ -0,0 +1,309 @@ +using Ryujinx.Common.Memory; +using Ryujinx.Horizon.Sdk.Arp.Detail; +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Text; + +namespace Ryujinx.Horizon.Sdk.Ns +{ + public struct ApplicationControlProperty + { + public Array16 Title; + public Array37 Isbn; + public StartupUserAccountValue StartupUserAccount; + public UserAccountSwitchLockValue UserAccountSwitchLock; + public AddOnContentRegistrationTypeValue AddOnContentRegistrationType; + public AttributeFlagValue AttributeFlag; + public uint SupportedLanguageFlag; + public ParentalControlFlagValue ParentalControlFlag; + public ScreenshotValue Screenshot; + public VideoCaptureValue VideoCapture; + public DataLossConfirmationValue DataLossConfirmation; + public PlayLogPolicyValue PlayLogPolicy; + public ulong PresenceGroupId; + public Array32 RatingAge; + public Array16 DisplayVersion; + public ulong AddOnContentBaseId; + public ulong SaveDataOwnerId; + public long UserAccountSaveDataSize; + public long UserAccountSaveDataJournalSize; + public long DeviceSaveDataSize; + public long DeviceSaveDataJournalSize; + public long BcatDeliveryCacheStorageSize; + public Array8 ApplicationErrorCodeCategory; + public Array8 LocalCommunicationId; + public LogoTypeValue LogoType; + public LogoHandlingValue LogoHandling; + public RuntimeAddOnContentInstallValue RuntimeAddOnContentInstall; + public RuntimeParameterDeliveryValue RuntimeParameterDelivery; + public Array2 Reserved30F4; + public CrashReportValue CrashReport; + public HdcpValue Hdcp; + public ulong SeedForPseudoDeviceId; + public Array65 BcatPassphrase; + public StartupUserAccountOptionFlagValue StartupUserAccountOption; + public Array6 ReservedForUserAccountSaveDataOperation; + public long UserAccountSaveDataSizeMax; + public long UserAccountSaveDataJournalSizeMax; + public long DeviceSaveDataSizeMax; + public long DeviceSaveDataJournalSizeMax; + public long TemporaryStorageSize; + public long CacheStorageSize; + public long CacheStorageJournalSize; + public long CacheStorageDataAndJournalSizeMax; + public ushort CacheStorageIndexMax; + public byte Reserved318A; + public byte RuntimeUpgrade; + public uint SupportingLimitedLicenses; + public Array16 PlayLogQueryableApplicationId; + public PlayLogQueryCapabilityValue PlayLogQueryCapability; + public RepairFlagValue RepairFlag; + public byte ProgramIndex; + public RequiredNetworkServiceLicenseOnLaunchValue RequiredNetworkServiceLicenseOnLaunchFlag; + public Array4 Reserved3214; + public ApplicationNeighborDetectionClientConfiguration NeighborDetectionClientConfiguration; + public ApplicationJitConfiguration JitConfiguration; + public RequiredAddOnContentsSetBinaryDescriptor RequiredAddOnContentsSetBinaryDescriptors; + public PlayReportPermissionValue PlayReportPermission; + public CrashScreenshotForProdValue CrashScreenshotForProd; + public CrashScreenshotForDevValue CrashScreenshotForDev; + public byte ContentsAvailabilityTransitionPolicy; + public Array4 Reserved3404; + public AccessibleLaunchRequiredVersionValue AccessibleLaunchRequiredVersion; + public ByteArray3000 Reserved3448; + + public readonly string IsbnString => Encoding.UTF8.GetString(Isbn.AsSpan()).TrimEnd('\0'); + public readonly string DisplayVersionString => Encoding.UTF8.GetString(DisplayVersion.AsSpan()).TrimEnd('\0'); + public readonly string ApplicationErrorCodeCategoryString => Encoding.UTF8.GetString(ApplicationErrorCodeCategory.AsSpan()).TrimEnd('\0'); + public readonly string BcatPassphraseString => Encoding.UTF8.GetString(BcatPassphrase.AsSpan()).TrimEnd('\0'); + + public struct ApplicationTitle + { + public ByteArray512 Name; + public Array256 Publisher; + + public readonly string NameString => Encoding.UTF8.GetString(Name.AsSpan()).TrimEnd('\0'); + public readonly string PublisherString => Encoding.UTF8.GetString(Publisher.AsSpan()).TrimEnd('\0'); + } + + public struct ApplicationNeighborDetectionClientConfiguration + { + public ApplicationNeighborDetectionGroupConfiguration SendGroupConfiguration; + public Array16 ReceivableGroupConfigurations; + } + + public struct ApplicationNeighborDetectionGroupConfiguration + { + public ulong GroupId; + public Array16 Key; + } + + public struct ApplicationJitConfiguration + { + public JitConfigurationFlag Flags; + public long MemorySize; + } + + public struct RequiredAddOnContentsSetBinaryDescriptor + { + public Array32 Descriptors; + } + + public struct AccessibleLaunchRequiredVersionValue + { + public Array8 ApplicationId; + } + + public enum Language + { + AmericanEnglish = 0, + BritishEnglish = 1, + Japanese = 2, + French = 3, + German = 4, + LatinAmericanSpanish = 5, + Spanish = 6, + Italian = 7, + Dutch = 8, + CanadianFrench = 9, + Portuguese = 10, + Russian = 11, + Korean = 12, + TraditionalChinese = 13, + SimplifiedChinese = 14, + BrazilianPortuguese = 15, + } + + public enum Organization + { + CERO = 0, + GRACGCRB = 1, + GSRMR = 2, + ESRB = 3, + ClassInd = 4, + USK = 5, + PEGI = 6, + PEGIPortugal = 7, + PEGIBBFC = 8, + Russian = 9, + ACB = 10, + OFLC = 11, + IARCGeneric = 12, + } + + public enum StartupUserAccountValue : byte + { + None = 0, + Required = 1, + RequiredWithNetworkServiceAccountAvailable = 2, + } + + public enum UserAccountSwitchLockValue : byte + { + Disable = 0, + Enable = 1, + } + + public enum AddOnContentRegistrationTypeValue : byte + { + AllOnLaunch = 0, + OnDemand = 1, + } + + [Flags] + public enum AttributeFlagValue + { + None = 0, + Demo = 1 << 0, + RetailInteractiveDisplay = 1 << 1, + } + + public enum ParentalControlFlagValue + { + None = 0, + FreeCommunication = 1, + } + + public enum ScreenshotValue : byte + { + Allow = 0, + Deny = 1, + } + + public enum VideoCaptureValue : byte + { + Disable = 0, + Manual = 1, + Enable = 2, + } + + public enum DataLossConfirmationValue : byte + { + None = 0, + Required = 1, + } + + public enum PlayLogPolicyValue : byte + { + Open = 0, + LogOnly = 1, + None = 2, + Closed = 3, + All = Open, + } + + public enum LogoTypeValue : byte + { + LicensedByNintendo = 0, + DistributedByNintendo = 1, + Nintendo = 2, + } + + public enum LogoHandlingValue : byte + { + Auto = 0, + Manual = 1, + } + + public enum RuntimeAddOnContentInstallValue : byte + { + Deny = 0, + AllowAppend = 1, + AllowAppendButDontDownloadWhenUsingNetwork = 2, + } + + public enum RuntimeParameterDeliveryValue : byte + { + Always = 0, + AlwaysIfUserStateMatched = 1, + OnRestart = 2, + } + + public enum CrashReportValue : byte + { + Deny = 0, + Allow = 1, + } + + public enum HdcpValue : byte + { + None = 0, + Required = 1, + } + + [Flags] + public enum StartupUserAccountOptionFlagValue : byte + { + None = 0, + IsOptional = 1 << 0, + } + + public enum PlayLogQueryCapabilityValue : byte + { + None = 0, + WhiteList = 1, + All = 2, + } + + [Flags] + public enum RepairFlagValue : byte + { + None = 0, + SuppressGameCardAccess = 1 << 0, + } + + [Flags] + public enum RequiredNetworkServiceLicenseOnLaunchValue : byte + { + None = 0, + Common = 1 << 0, + } + + [Flags] + public enum JitConfigurationFlag : ulong + { + None = 0, + Enabled = 1 << 0, + } + + [Flags] + public enum PlayReportPermissionValue : byte + { + None = 0, + TargetMarketing = 1 << 0, + } + + public enum CrashScreenshotForProdValue : byte + { + Deny = 0, + Allow = 1, + } + + public enum CrashScreenshotForDevValue : byte + { + Deny = 0, + Allow = 1, + } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/ServiceUtil.cs b/src/Ryujinx.Horizon/Sdk/ServiceUtil.cs index ccd6c93a6..5527c1e35 100644 --- a/src/Ryujinx.Horizon/Sdk/ServiceUtil.cs +++ b/src/Ryujinx.Horizon/Sdk/ServiceUtil.cs @@ -35,5 +35,254 @@ namespace Ryujinx.Horizon.Sdk return CmifMessage.ParseResponse(out response, HorizonStatic.AddressSpace.GetWritableRegion(tlsAddress, tlsSize).Memory.Span, false, 0); } + + public static Result SendRequest( + out CmifResponse response, + int sessionHandle, + uint requestId, + bool sendPid, + scoped ReadOnlySpan data, + ReadOnlySpan bufferFlags, + ReadOnlySpan buffers) + { + ulong tlsAddress = HorizonStatic.ThreadContext.TlsAddress; + int tlsSize = Api.TlsMessageBufferSize; + + using (var tlsRegion = HorizonStatic.AddressSpace.GetWritableRegion(tlsAddress, tlsSize)) + { + CmifRequestFormat format = new() + { + DataSize = data.Length, + RequestId = requestId, + SendPid = sendPid, + }; + + for (int index = 0; index < bufferFlags.Length; index++) + { + FormatProcessBuffer(ref format, bufferFlags[index]); + } + + CmifRequest request = CmifMessage.CreateRequest(tlsRegion.Memory.Span, format); + + for (int index = 0; index < buffers.Length; index++) + { + RequestProcessBuffer(ref request, buffers[index], bufferFlags[index]); + } + + data.CopyTo(request.Data); + } + + Result result = HorizonStatic.Syscall.SendSyncRequest(sessionHandle); + + if (result.IsFailure) + { + response = default; + + return result; + } + + return CmifMessage.ParseResponse(out response, HorizonStatic.AddressSpace.GetWritableRegion(tlsAddress, tlsSize).Memory.Span, false, 0); + } + + private static void FormatProcessBuffer(ref CmifRequestFormat format, HipcBufferFlags flags) + { + if (flags == 0) + { + return; + } + + bool isIn = flags.HasFlag(HipcBufferFlags.In); + bool isOut = flags.HasFlag(HipcBufferFlags.Out); + + if (flags.HasFlag(HipcBufferFlags.AutoSelect)) + { + if (isIn) + { + format.InAutoBuffersCount++; + } + + if (isOut) + { + format.OutAutoBuffersCount++; + } + } + else if (flags.HasFlag(HipcBufferFlags.Pointer)) + { + if (isIn) + { + format.InPointersCount++; + } + + if (isOut) + { + if (flags.HasFlag(HipcBufferFlags.FixedSize)) + { + format.OutFixedPointersCount++; + } + else + { + format.OutPointersCount++; + } + } + } + else if (flags.HasFlag(HipcBufferFlags.MapAlias)) + { + if (isIn && isOut) + { + format.InOutBuffersCount++; + } + else if (isIn) + { + format.InBuffersCount++; + } + else + { + format.OutBuffersCount++; + } + } + } + + private static void RequestProcessBuffer(ref CmifRequest request, PointerAndSize buffer, HipcBufferFlags flags) + { + if (flags == 0) + { + return; + } + + bool isIn = flags.HasFlag(HipcBufferFlags.In); + bool isOut = flags.HasFlag(HipcBufferFlags.Out); + + if (flags.HasFlag(HipcBufferFlags.AutoSelect)) + { + HipcBufferMode mode = HipcBufferMode.Normal; + + if (flags.HasFlag(HipcBufferFlags.MapTransferAllowsNonSecure)) + { + mode = HipcBufferMode.NonSecure; + } + + if (flags.HasFlag(HipcBufferFlags.MapTransferAllowsNonDevice)) + { + mode = HipcBufferMode.NonDevice; + } + + if (isIn) + { + RequestInAutoBuffer(ref request, buffer.Address, buffer.Size, mode); + } + + if (isOut) + { + RequestOutAutoBuffer(ref request, buffer.Address, buffer.Size, mode); + } + } + else if (flags.HasFlag(HipcBufferFlags.Pointer)) + { + if (isIn) + { + RequestInPointer(ref request, buffer.Address, buffer.Size); + } + + if (isOut) + { + if (flags.HasFlag(HipcBufferFlags.FixedSize)) + { + RequestOutFixedPointer(ref request, buffer.Address, buffer.Size); + } + else + { + RequestOutPointer(ref request, buffer.Address, buffer.Size); + } + } + } + else if (flags.HasFlag(HipcBufferFlags.MapAlias)) + { + HipcBufferMode mode = HipcBufferMode.Normal; + + if (flags.HasFlag(HipcBufferFlags.MapTransferAllowsNonSecure)) + { + mode = HipcBufferMode.NonSecure; + } + + if (flags.HasFlag(HipcBufferFlags.MapTransferAllowsNonDevice)) + { + mode = HipcBufferMode.NonDevice; + } + + if (isIn && isOut) + { + RequestInOutBuffer(ref request, buffer.Address, buffer.Size, mode); + } + else if (isIn) + { + RequestInBuffer(ref request, buffer.Address, buffer.Size, mode); + } + else + { + RequestOutBuffer(ref request, buffer.Address, buffer.Size, mode); + } + } + } + + private static void RequestInAutoBuffer(ref CmifRequest request, ulong bufferAddress, ulong bufferSize, HipcBufferMode mode) + { + if (request.ServerPointerSize != 0 && bufferSize <= (ulong)request.ServerPointerSize) + { + RequestInPointer(ref request, bufferAddress, bufferSize); + RequestInBuffer(ref request, 0UL, 0UL, mode); + } + else + { + RequestInPointer(ref request, 0UL, 0UL); + RequestInBuffer(ref request, bufferAddress, bufferSize, mode); + } + } + + private static void RequestOutAutoBuffer(ref CmifRequest request, ulong bufferAddress, ulong bufferSize, HipcBufferMode mode) + { + if (request.ServerPointerSize != 0 && bufferSize <= (ulong)request.ServerPointerSize) + { + RequestOutPointer(ref request, bufferAddress, bufferSize); + RequestOutBuffer(ref request, 0UL, 0UL, mode); + } + else + { + RequestOutPointer(ref request, 0UL, 0UL); + RequestOutBuffer(ref request, bufferAddress, bufferSize, mode); + } + } + + private static void RequestInBuffer(ref CmifRequest request, ulong bufferAddress, ulong bufferSize, HipcBufferMode mode) + { + request.Hipc.SendBuffers[request.SendBufferIndex++] = new HipcBufferDescriptor(bufferAddress, bufferSize, mode); + } + + private static void RequestOutBuffer(ref CmifRequest request, ulong bufferAddress, ulong bufferSize, HipcBufferMode mode) + { + request.Hipc.ReceiveBuffers[request.RecvBufferIndex++] = new HipcBufferDescriptor(bufferAddress, bufferSize, mode); + } + + private static void RequestInOutBuffer(ref CmifRequest request, ulong bufferAddress, ulong bufferSize, HipcBufferMode mode) + { + request.Hipc.ExchangeBuffers[request.ExchBufferIndex++] = new HipcBufferDescriptor(bufferAddress, bufferSize, mode); + } + + private static void RequestInPointer(ref CmifRequest request, ulong bufferAddress, ulong bufferSize) + { + request.Hipc.SendStatics[request.SendStaticIndex++] = new HipcStaticDescriptor(bufferAddress, (ushort)bufferSize, request.CurrentInPointerId++); + request.ServerPointerSize -= (int)bufferSize; + } + + private static void RequestOutFixedPointer(ref CmifRequest request, ulong bufferAddress, ulong bufferSize) + { + request.Hipc.ReceiveList[request.RecvListIndex++] = new HipcReceiveListEntry(bufferAddress, (ushort)bufferSize); + request.ServerPointerSize -= (int)bufferSize; + } + + private static void RequestOutPointer(ref CmifRequest request, ulong bufferAddress, ulong bufferSize) + { + RequestOutFixedPointer(ref request, bufferAddress, bufferSize); + request.OutPointerSizes[request.OutPointerSizeIndex++] = (ushort)bufferSize; + } } } diff --git a/src/Ryujinx.Horizon/Sdk/Settings/BatteryLot.cs b/src/Ryujinx.Horizon/Sdk/Settings/BatteryLot.cs new file mode 100644 index 000000000..71185fcd0 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/BatteryLot.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings +{ + [StructLayout(LayoutKind.Sequential, Size = 0x18, Pack = 0x1)] + struct BatteryLot + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/AccelerometerOffset.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/AccelerometerOffset.cs new file mode 100644 index 000000000..292a368f1 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/AccelerometerOffset.cs @@ -0,0 +1,12 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x6, Pack = 0x2)] + struct AccelerometerOffset + { + public ushort X; + public ushort Y; + public ushort Z; + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/AccelerometerScale.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/AccelerometerScale.cs new file mode 100644 index 000000000..ef9d17ef9 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/AccelerometerScale.cs @@ -0,0 +1,12 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x6, Pack = 0x2)] + struct AccelerometerScale + { + public ushort X; + public ushort Y; + public ushort Z; + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/AmiiboEcdsaCertificate.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/AmiiboEcdsaCertificate.cs new file mode 100644 index 000000000..7cbab2f09 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/AmiiboEcdsaCertificate.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x74, Pack = 0x4)] + struct AmiiboEcdsaCertificate + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/AmiiboEcqvBlsCertificate.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/AmiiboEcqvBlsCertificate.cs new file mode 100644 index 000000000..8d16b51b1 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/AmiiboEcqvBlsCertificate.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x24, Pack = 0x4)] + struct AmiiboEcqvBlsCertificate + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/AmiiboEcqvBlsKey.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/AmiiboEcqvBlsKey.cs new file mode 100644 index 000000000..da6ca53bc --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/AmiiboEcqvBlsKey.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x48, Pack = 0x4)] + struct AmiiboEcqvBlsKey + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/AmiiboEcqvBlsRootCertificate.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/AmiiboEcqvBlsRootCertificate.cs new file mode 100644 index 000000000..e69e38a1a --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/AmiiboEcqvBlsRootCertificate.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x94, Pack = 0x4)] + struct AmiiboEcqvBlsRootCertificate + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/AmiiboEcqvCertificate.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/AmiiboEcqvCertificate.cs new file mode 100644 index 000000000..43742fbb7 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/AmiiboEcqvCertificate.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x18, Pack = 0x4)] + struct AmiiboEcqvCertificate + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/AmiiboKey.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/AmiiboKey.cs new file mode 100644 index 000000000..43ffccb00 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/AmiiboKey.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x58, Pack = 0x4)] + struct AmiiboKey + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/AnalogStickFactoryCalibration.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/AnalogStickFactoryCalibration.cs new file mode 100644 index 000000000..3fe6f3223 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/AnalogStickFactoryCalibration.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x9, Pack = 0x1)] + struct AnalogStickFactoryCalibration + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/AnalogStickModelParameter.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/AnalogStickModelParameter.cs new file mode 100644 index 000000000..a442032c7 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/AnalogStickModelParameter.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x12, Pack = 0x1)] + struct AnalogStickModelParameter + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/BdAddress.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/BdAddress.cs new file mode 100644 index 000000000..519d72e8f --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/BdAddress.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x6, Pack = 0x1)] + struct BdAddress + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/ConfigurationId1.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/ConfigurationId1.cs new file mode 100644 index 000000000..40565805f --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/ConfigurationId1.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x1E, Pack = 0x1)] + struct ConfigurationId1 + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/ConsoleSixAxisSensorHorizontalOffset.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/ConsoleSixAxisSensorHorizontalOffset.cs new file mode 100644 index 000000000..c5503edc5 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/ConsoleSixAxisSensorHorizontalOffset.cs @@ -0,0 +1,12 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x6, Pack = 0x2)] + struct ConsoleSixAxisSensorHorizontalOffset + { + public ushort X; + public ushort Y; + public ushort Z; + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/CountryCode.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/CountryCode.cs new file mode 100644 index 000000000..daf2ba3b8 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/CountryCode.cs @@ -0,0 +1,8 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + struct CountryCode + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/EccB233DeviceCertificate.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/EccB233DeviceCertificate.cs new file mode 100644 index 000000000..727408ed5 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/EccB233DeviceCertificate.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x180)] + struct EccB233DeviceCertificate + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/EccB233DeviceKey.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/EccB233DeviceKey.cs new file mode 100644 index 000000000..a0481f4dc --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/EccB233DeviceKey.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x58, Pack = 0x4)] + struct EccB233DeviceKey + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/GameCardCertificate.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/GameCardCertificate.cs new file mode 100644 index 000000000..ce3908afe --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/GameCardCertificate.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x400)] + struct GameCardCertificate + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/GameCardKey.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/GameCardKey.cs new file mode 100644 index 000000000..81144ac48 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/GameCardKey.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x138)] + struct GameCardKey + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/GyroscopeOffset.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/GyroscopeOffset.cs new file mode 100644 index 000000000..801d117cb --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/GyroscopeOffset.cs @@ -0,0 +1,12 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x6, Pack = 0x2)] + struct GyroscopeOffset + { + public ushort X; + public ushort Y; + public ushort Z; + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/GyroscopeScale.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/GyroscopeScale.cs new file mode 100644 index 000000000..7812281f8 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/GyroscopeScale.cs @@ -0,0 +1,12 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x6, Pack = 0x2)] + struct GyroscopeScale + { + public ushort X; + public ushort Y; + public ushort Z; + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/MacAddress.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/MacAddress.cs new file mode 100644 index 000000000..65e222ee5 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/MacAddress.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x6, Pack = 0x1)] + struct MacAddress + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/Rsa2048DeviceCertificate.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/Rsa2048DeviceCertificate.cs new file mode 100644 index 000000000..57217059f --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/Rsa2048DeviceCertificate.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x240)] + struct Rsa2048DeviceCertificate + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/Rsa2048DeviceKey.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/Rsa2048DeviceKey.cs new file mode 100644 index 000000000..d2fd51cf7 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/Rsa2048DeviceKey.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x248)] + struct Rsa2048DeviceKey + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/SerialNumber.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/SerialNumber.cs new file mode 100644 index 000000000..af664cdc5 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/SerialNumber.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x18, Pack = 0x1)] + struct SerialNumber + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/SpeakerParameter.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/SpeakerParameter.cs new file mode 100644 index 000000000..f147f66ff --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/SpeakerParameter.cs @@ -0,0 +1,32 @@ +using Ryujinx.Common.Memory; +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x5A, Pack = 0x2)] + struct SpeakerParameter + { + public ushort Version; + public Array34 Reserved; + public ushort SpeakerHpf2A1; + public ushort SpeakerHpf2A2; + public ushort SpeakerHpf2H0; + public ushort SpeakerEqInputVolume; + public ushort SpeakerEqOutputVolume; + public ushort SpeakerEqCtrl1; + public ushort SpeakerEqCtrl2; + public ushort SpeakerDrcAgcCtrl2; + public ushort SpeakerDrcAgcCtrl3; + public ushort SpeakerDrcAgcCtrl1; + public ushort SpeakerAnalogVolume; + public ushort HeadphoneAnalogVolume; + public ushort SpeakerDigitalVolumeMin; + public ushort SpeakerDigitalVolumeMax; + public ushort HeadphoneDigitalVolumeMin; + public ushort HeadphoneDigitalVolumeMax; + public ushort MicFixedGain; + public ushort MicVariableVolumeMin; + public ushort MicVariableVolumeMax; + public Array16 Reserved2; + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/SslCertificate.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/SslCertificate.cs new file mode 100644 index 000000000..5d8252164 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/SslCertificate.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x804)] + struct SslCertificate + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Factory/SslKey.cs b/src/Ryujinx.Horizon/Sdk/Settings/Factory/SslKey.cs new file mode 100644 index 000000000..7d4b41369 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Factory/SslKey.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.Factory +{ + [StructLayout(LayoutKind.Sequential, Size = 0x138)] + struct SslKey + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/Language.cs b/src/Ryujinx.Horizon/Sdk/Settings/Language.cs new file mode 100644 index 000000000..4ffc66fec --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/Language.cs @@ -0,0 +1,24 @@ +namespace Ryujinx.Horizon.Sdk.Settings +{ + enum Language : uint + { + Japanese, + AmericanEnglish, + French, + German, + Italian, + Spanish, + Chinese, + Korean, + Dutch, + Portuguese, + Russian, + Taiwanese, + BritishEnglish, + CanadianFrench, + LatinAmericanSpanish, + SimplifiedChinese, + TraditionalChinese, + BrazilianPortuguese, + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/LanguageCode.cs b/src/Ryujinx.Horizon/Sdk/Settings/LanguageCode.cs new file mode 100644 index 000000000..dc9712692 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/LanguageCode.cs @@ -0,0 +1,63 @@ +using Ryujinx.Common.Memory; +using System; +using System.Runtime.InteropServices; +using System.Text; + +namespace Ryujinx.Horizon.Sdk.Settings +{ + [StructLayout(LayoutKind.Sequential, Size = 0x8, Pack = 0x1)] + struct LanguageCode + { + private static readonly string[] _languageCodes = new string[] + { + "ja", + "en-US", + "fr", + "de", + "it", + "es", + "zh-CN", + "ko", + "nl", + "pt", + "ru", + "zh-TW", + "en-GB", + "fr-CA", + "es-419", + "zh-Hans", + "zh-Hant", + "pt-BR" + }; + + public Array8 Value; + + public bool IsValid() + { + int length = Value.AsSpan().IndexOf((byte)0); + if (length < 0) + { + return false; + } + + string str = Encoding.ASCII.GetString(Value.AsSpan()[..length]); + + return _languageCodes.AsSpan().Contains(str); + } + + public LanguageCode(Language language) + { + if ((uint)language >= _languageCodes.Length) + { + throw new ArgumentOutOfRangeException(nameof(language)); + } + + Value = new LanguageCode(_languageCodes[(int)language]).Value; + } + + public LanguageCode(string strCode) + { + Encoding.ASCII.GetBytes(strCode, Value.AsSpan()); + } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/SettingsItemKey.cs b/src/Ryujinx.Horizon/Sdk/Settings/SettingsItemKey.cs new file mode 100644 index 000000000..661184103 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/SettingsItemKey.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings +{ + [StructLayout(LayoutKind.Sequential, Size = 0x48)] + struct SettingsItemKey + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/SettingsName.cs b/src/Ryujinx.Horizon/Sdk/Settings/SettingsName.cs new file mode 100644 index 000000000..6864b8cd6 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/SettingsName.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings +{ + [StructLayout(LayoutKind.Sequential, Size = 0x48)] + struct SettingsName + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/AccountNotificationSettings.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/AccountNotificationSettings.cs new file mode 100644 index 000000000..a2cbad6a6 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/AccountNotificationSettings.cs @@ -0,0 +1,15 @@ +using Ryujinx.Horizon.Sdk.Account; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + struct AccountNotificationSettings + { +#pragma warning disable CS0649 // Field is never assigned to + public Uid UserId; + public uint Flags; + public byte FriendPresenceOverlayPermission; + public byte FriendInvitationOverlayPermission; + public ushort Reserved; +#pragma warning restore CS0649 + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/AccountOnlineStorageSettings.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/AccountOnlineStorageSettings.cs new file mode 100644 index 000000000..3ed77e52b --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/AccountOnlineStorageSettings.cs @@ -0,0 +1,6 @@ +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + struct AccountOnlineStorageSettings + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/AccountSettings.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/AccountSettings.cs new file mode 100644 index 000000000..bd27ea0bf --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/AccountSettings.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x4, Pack = 0x4)] + struct AccountSettings + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/AllowedSslHost.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/AllowedSslHost.cs new file mode 100644 index 000000000..cb90daf18 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/AllowedSslHost.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x100)] + struct AllowedSslHost + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/AnalogStickUserCalibration.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/AnalogStickUserCalibration.cs new file mode 100644 index 000000000..36023da9c --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/AnalogStickUserCalibration.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x10, Pack = 0x4)] + struct AnalogStickUserCalibration + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/AppletLaunchFlag.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/AppletLaunchFlag.cs new file mode 100644 index 000000000..00d6f4d06 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/AppletLaunchFlag.cs @@ -0,0 +1,9 @@ +using System; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [Flags] + enum AppletLaunchFlag : uint + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/AudioVolume.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/AudioVolume.cs new file mode 100644 index 000000000..d246bc2b9 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/AudioVolume.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x8, Pack = 0x4)] + struct AudioVolume + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/BacklightSettings.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/BacklightSettings.cs new file mode 100644 index 000000000..00de6869c --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/BacklightSettings.cs @@ -0,0 +1,22 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x28, Pack = 0x4)] + struct BacklightSettings + { + // TODO: Determine field names. + public uint Unknown0x00; + public float Unknown0x04; + // 1st group + public float Unknown0x08; + public float Unknown0x0C; + public float Unknown0x10; + // 2nd group + public float Unknown0x14; + public float Unknown0x18; + public float Unknown0x1C; + public float Unknown0x20; + public float Unknown0x24; + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/BacklightSettingsEx.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/BacklightSettingsEx.cs new file mode 100644 index 000000000..347afdfe3 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/BacklightSettingsEx.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x2C, Pack = 0x4)] + struct BacklightSettingsEx + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/BlePairingSettings.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/BlePairingSettings.cs new file mode 100644 index 000000000..d9b01f9ff --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/BlePairingSettings.cs @@ -0,0 +1,6 @@ +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + struct BlePairingSettings + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/BluetoothDevicesSettings.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/BluetoothDevicesSettings.cs new file mode 100644 index 000000000..ec5c97c5a --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/BluetoothDevicesSettings.cs @@ -0,0 +1,29 @@ +using Ryujinx.Common.Memory; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + struct BluetoothDevicesSettings + { +#pragma warning disable CS0649 // Field is never assigned to + public Array6 BdAddr; + public Array32 DeviceName; + public Array3 ClassOfDevice; + public Array16 LinkKey; + public bool LinkKeyPresent; + public ushort Version; + public uint TrustedServices; + public ushort Vid; + public ushort Pid; + public byte SubClass; + public byte AttributeMask; + public ushort DescriptorLength; + public Array128 Descriptor; + public byte KeyType; + public byte DeviceType; + public ushort BrrSize; + public Array9 Brr; + public Array256 Reserved; + public Array43 Reserved2; +#pragma warning restore CS0649 + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/ButtonConfigRegisteredSettings.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/ButtonConfigRegisteredSettings.cs new file mode 100644 index 000000000..8bd4924e9 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/ButtonConfigRegisteredSettings.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x5C8)] + struct ButtonConfigRegisteredSettings + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/ButtonConfigSettings.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/ButtonConfigSettings.cs new file mode 100644 index 000000000..2f06e32e1 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/ButtonConfigSettings.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x5A8)] + struct ButtonConfigSettings + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/ConsoleSixAxisSensorAccelerationBias.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/ConsoleSixAxisSensorAccelerationBias.cs new file mode 100644 index 000000000..c70d4ff28 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/ConsoleSixAxisSensorAccelerationBias.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0xC, Pack = 0x4)] + struct ConsoleSixAxisSensorAccelerationBias + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/ConsoleSixAxisSensorAccelerationGain.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/ConsoleSixAxisSensorAccelerationGain.cs new file mode 100644 index 000000000..0803beb87 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/ConsoleSixAxisSensorAccelerationGain.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x24, Pack = 0x4)] + struct ConsoleSixAxisSensorAccelerationGain + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/ConsoleSixAxisSensorAngularAcceleration.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/ConsoleSixAxisSensorAngularAcceleration.cs new file mode 100644 index 000000000..831e44bd5 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/ConsoleSixAxisSensorAngularAcceleration.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x24, Pack = 0x4)] + struct ConsoleSixAxisSensorAngularAcceleration + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/ConsoleSixAxisSensorAngularVelocityBias.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/ConsoleSixAxisSensorAngularVelocityBias.cs new file mode 100644 index 000000000..83d1faa8d --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/ConsoleSixAxisSensorAngularVelocityBias.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0xC, Pack = 0x4)] + struct ConsoleSixAxisSensorAngularVelocityBias + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/ConsoleSixAxisSensorAngularVelocityGain.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/ConsoleSixAxisSensorAngularVelocityGain.cs new file mode 100644 index 000000000..68e0c614a --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/ConsoleSixAxisSensorAngularVelocityGain.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x24, Pack = 0x4)] + struct ConsoleSixAxisSensorAngularVelocityGain + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/ConsoleSixAxisSensorAngularVelocityTimeBias.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/ConsoleSixAxisSensorAngularVelocityTimeBias.cs new file mode 100644 index 000000000..47f3d951c --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/ConsoleSixAxisSensorAngularVelocityTimeBias.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0xC, Pack = 0x4)] + struct ConsoleSixAxisSensorAngularVelocityTimeBias + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/DataDeletionSettings.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/DataDeletionSettings.cs new file mode 100644 index 000000000..a10a265d1 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/DataDeletionSettings.cs @@ -0,0 +1,18 @@ +using System; +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [Flags] + enum DataDeletionFlag : uint + { + AutomaticDeletionFlag = 1 << 0, + } + + [StructLayout(LayoutKind.Sequential, Size = 0x8, Pack = 0x4)] + struct DataDeletionSettings + { + public DataDeletionFlag Flags; + public uint UseCount; + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/DeviceNickName.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/DeviceNickName.cs new file mode 100644 index 000000000..99c9f9817 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/DeviceNickName.cs @@ -0,0 +1,25 @@ +using Ryujinx.Common.Memory; +using System.Runtime.InteropServices; +using System.Text; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x80)] + struct DeviceNickName + { + public Array128 Value; + + public DeviceNickName(string value) + { + int bytesWritten = Encoding.ASCII.GetBytes(value, Value.AsSpan()); + if (bytesWritten < 128) + { + Value[bytesWritten] = 0; + } + else + { + Value[127] = 0; + } + } + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/Edid.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/Edid.cs new file mode 100644 index 000000000..3ff566854 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/Edid.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x200)] + struct Edid + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/EulaVersion.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/EulaVersion.cs new file mode 100644 index 000000000..65905b1ba --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/EulaVersion.cs @@ -0,0 +1,6 @@ +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + struct EulaVersion + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/FatalDirtyFlag.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/FatalDirtyFlag.cs new file mode 100644 index 000000000..6be941151 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/FatalDirtyFlag.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x10, Pack = 0x8)] + struct FatalDirtyFlag + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/FirmwareVersion.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/FirmwareVersion.cs new file mode 100644 index 000000000..39825e010 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/FirmwareVersion.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x100)] + struct FirmwareVersion + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/FirmwareVersionDigest.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/FirmwareVersionDigest.cs new file mode 100644 index 000000000..0027d7ef1 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/FirmwareVersionDigest.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x40, Pack = 0x1)] + struct FirmwareVersionDigest + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/HomeMenuScheme.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/HomeMenuScheme.cs new file mode 100644 index 000000000..cc7b317be --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/HomeMenuScheme.cs @@ -0,0 +1,14 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x14, Pack = 0x1)] + struct HomeMenuScheme + { + public uint Main; + public uint Back; + public uint Sub; + public uint Bezel; + public uint Extra; + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/HostFsMountPoint.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/HostFsMountPoint.cs new file mode 100644 index 000000000..1a66abac9 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/HostFsMountPoint.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x100)] + struct HostFsMountPoint + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/InitialLaunchSettings.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/InitialLaunchSettings.cs new file mode 100644 index 000000000..b3989de75 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/InitialLaunchSettings.cs @@ -0,0 +1,14 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x20, Pack = 0x8)] + struct InitialLaunchSettings + { + public uint Flags; + public uint Reserved; + public ulong TimeStamp1; + public ulong TimeStamp2; + public ulong TimeStamp3; + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/NetworkSettings.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/NetworkSettings.cs new file mode 100644 index 000000000..a0101b626 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/NetworkSettings.cs @@ -0,0 +1,6 @@ +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + struct NetworkSettings + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/NotificationSettings.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/NotificationSettings.cs new file mode 100644 index 000000000..2ce56c4df --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/NotificationSettings.cs @@ -0,0 +1,38 @@ +using System; +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [Flags] + enum NotificationFlag : uint + { + RingtoneFlag = 1 << 0, + DownloadCompletionFlag = 1 << 1, + EnablesNews = 1 << 8, + IncomingLampFlag = 1 << 9, + } + + enum NotificationVolume : uint + { + Mute, + Low, + High, + } + + struct NotificationTime + { +#pragma warning disable CS0649 // Field is never assigned to + public uint Hour; + public uint Minute; +#pragma warning restore CS0649 + } + + [StructLayout(LayoutKind.Sequential, Size = 0x18, Pack = 0x4)] + struct NotificationSettings + { + public NotificationFlag Flag; + public NotificationVolume Volume; + public NotificationTime HeadTime; + public NotificationTime TailTime; + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/NxControllerLegacySettings.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/NxControllerLegacySettings.cs new file mode 100644 index 000000000..845715df2 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/NxControllerLegacySettings.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x29)] + struct NxControllerLegacySettings + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/NxControllerSettings.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/NxControllerSettings.cs new file mode 100644 index 000000000..c8f81cecb --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/NxControllerSettings.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x42C)] + struct NxControllerSettings + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/PtmFuelGaugeParameter.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/PtmFuelGaugeParameter.cs new file mode 100644 index 000000000..b843bcd64 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/PtmFuelGaugeParameter.cs @@ -0,0 +1,20 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x18, Pack = 0x4)] + struct PtmFuelGaugeParameter + { + public ushort Rcomp0; + public ushort TempCo; + public ushort FullCap; + public ushort FullCapNom; + public ushort IavgEmpty; + public ushort QrTable00; + public ushort QrTable10; + public ushort QrTable20; + public ushort QrTable30; + public ushort Reserved; + public uint Cycles; + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/RebootlessSystemUpdateVersion.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/RebootlessSystemUpdateVersion.cs new file mode 100644 index 000000000..b4e9b8b28 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/RebootlessSystemUpdateVersion.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x40, Pack = 0x4)] + struct RebootlessSystemUpdateVersion + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/SerialNumber.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/SerialNumber.cs new file mode 100644 index 000000000..22ddb85ce --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/SerialNumber.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x18, Pack = 0x1)] + struct SerialNumber + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/ServiceDiscoveryControlSettings.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/ServiceDiscoveryControlSettings.cs new file mode 100644 index 000000000..7c7b625a2 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/ServiceDiscoveryControlSettings.cs @@ -0,0 +1,10 @@ +using System; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [Flags] + enum ServiceDiscoveryControlSettings : uint + { + IsChangeEnvironmentIdentifierDisabled = 1 << 0, + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/SleepSettings.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/SleepSettings.cs new file mode 100644 index 000000000..7493c677c --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/SleepSettings.cs @@ -0,0 +1,40 @@ +using System; +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [Flags] + enum SleepFlag : uint + { + SleepsWhilePlayingMedia = 1 << 0, + WakesAtPowerStateChange = 1 << 1, + } + + enum HandheldSleepPlan : uint + { + At1Min, + At3Min, + At5Min, + At10Min, + At30Min, + Never, + } + + enum ConsoleSleepPlan : uint + { + At1Hour, + At2Hour, + At3Hour, + At6Hour, + At12Hour, + Never, + } + + [StructLayout(LayoutKind.Sequential, Size = 0xC, Pack = 0x4)] + struct SleepSettings + { + public SleepFlag Flags; + public HandheldSleepPlan HandheldSleepPlan; + public ConsoleSleepPlan ConsoleSleepPlan; + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/TelemetryDirtyFlag.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/TelemetryDirtyFlag.cs new file mode 100644 index 000000000..46ec2d767 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/TelemetryDirtyFlag.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x10, Pack = 0x8)] + struct TelemetryDirtyFlag + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/ThemeId.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/ThemeId.cs new file mode 100644 index 000000000..886ec8721 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/ThemeId.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x80, Pack = 0x8)] + struct ThemeId + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/ThemeSettings.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/ThemeSettings.cs new file mode 100644 index 000000000..ac36bcd80 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/ThemeSettings.cs @@ -0,0 +1,9 @@ +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [StructLayout(LayoutKind.Sequential, Size = 0x8, Pack = 0x8)] + struct ThemeSettings + { + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Settings/System/TvSettings.cs b/src/Ryujinx.Horizon/Sdk/Settings/System/TvSettings.cs new file mode 100644 index 000000000..5ee0b85d9 --- /dev/null +++ b/src/Ryujinx.Horizon/Sdk/Settings/System/TvSettings.cs @@ -0,0 +1,59 @@ +using System; +using System.Runtime.InteropServices; + +namespace Ryujinx.Horizon.Sdk.Settings.System +{ + [Flags] + enum TvFlag : uint + { + Allows4k = 1 << 0, + Allows3d = 1 << 1, + AllowsCec = 1 << 2, + PreventsScreenBurnIn = 1 << 3, + } + + enum TvResolution : uint + { + Auto, + At1080p, + At720p, + At480p, + } + + enum HdmiContentType : uint + { + None, + Graphics, + Cinema, + Photo, + Game, + } + + enum RgbRange : uint + { + Auto, + Full, + Limited, + } + + enum CmuMode : uint + { + None, + ColorInvert, + HighContrast, + GrayScale, + } + + [StructLayout(LayoutKind.Sequential, Size = 0x20, Pack = 0x4)] + struct TvSettings + { + public TvFlag Flags; + public TvResolution TvResolution; + public HdmiContentType HdmiContentType; + public RgbRange RgbRange; + public CmuMode CmuMode; + public float TvUnderscan; + public float TvGamma; + public float ContrastRatio; + } +} diff --git a/src/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifRequest.cs b/src/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifRequest.cs index d409be5b3..62c15baa6 100644 --- a/src/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifRequest.cs +++ b/src/Ryujinx.Horizon/Sdk/Sf/Cmif/CmifRequest.cs @@ -10,5 +10,12 @@ namespace Ryujinx.Horizon.Sdk.Sf.Cmif public Span OutPointerSizes; public Span Objects; public int ServerPointerSize; + public int CurrentInPointerId; + public int SendBufferIndex; + public int RecvBufferIndex; + public int ExchBufferIndex; + public int SendStaticIndex; + public int RecvListIndex; + public int OutPointerSizeIndex; } } diff --git a/src/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcBufferDescriptor.cs b/src/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcBufferDescriptor.cs index 03ef6d3fc..4e9628947 100644 --- a/src/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcBufferDescriptor.cs +++ b/src/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcBufferDescriptor.cs @@ -11,5 +11,12 @@ namespace Ryujinx.Horizon.Sdk.Sf.Hipc public ulong Address => _addressLow | (((ulong)_word2 << 4) & 0xf00000000UL) | (((ulong)_word2 << 34) & 0x7000000000UL); public ulong Size => _sizeLow | ((ulong)_word2 << 8) & 0xf00000000UL; public HipcBufferMode Mode => (HipcBufferMode)(_word2 & 3); + + public HipcBufferDescriptor(ulong address, ulong size, HipcBufferMode mode) + { + _sizeLow = (uint)size; + _addressLow = (uint)address; + _word2 = (uint)mode | ((uint)(address >> 34) & 0x1c) | ((uint)(size >> 32) << 24) | ((uint)(address >> 4) & 0xf0000000); + } } } diff --git a/src/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMessage.cs b/src/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMessage.cs index 887c82eb8..73321a891 100644 --- a/src/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMessage.cs +++ b/src/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMessage.cs @@ -181,6 +181,7 @@ namespace Ryujinx.Horizon.Sdk.Sf.Hipc } Span dataWords = Span.Empty; + Span dataWordsPadded = Span.Empty; if (meta.DataWordsCount != 0) { @@ -189,6 +190,7 @@ namespace Ryujinx.Horizon.Sdk.Sf.Hipc int padding = (dataOffsetAligned - dataOffset) / sizeof(uint); dataWords = MemoryMarshal.Cast(data)[padding..meta.DataWordsCount]; + dataWordsPadded = MemoryMarshal.Cast(data)[..meta.DataWordsCount]; data = data[(meta.DataWordsCount * sizeof(uint))..]; } @@ -209,6 +211,7 @@ namespace Ryujinx.Horizon.Sdk.Sf.Hipc ReceiveBuffers = receiveBuffers, ExchangeBuffers = exchangeBuffers, DataWords = dataWords, + DataWordsPadded = dataWordsPadded, ReceiveList = receiveList, CopyHandles = copyHandles, MoveHandles = moveHandles, diff --git a/src/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMessageData.cs b/src/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMessageData.cs index 548f12e8b..0d45d756f 100644 --- a/src/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMessageData.cs +++ b/src/Ryujinx.Horizon/Sdk/Sf/Hipc/HipcMessageData.cs @@ -9,6 +9,7 @@ namespace Ryujinx.Horizon.Sdk.Sf.Hipc public Span ReceiveBuffers; public Span ExchangeBuffers; public Span DataWords; + public Span DataWordsPadded; public Span ReceiveList; public Span CopyHandles; public Span MoveHandles; diff --git a/src/Ryujinx.Horizon/Sdk/Sf/HipcCommandProcessor.cs b/src/Ryujinx.Horizon/Sdk/Sf/HipcCommandProcessor.cs index bb9b37e28..f7694a74d 100644 --- a/src/Ryujinx.Horizon/Sdk/Sf/HipcCommandProcessor.cs +++ b/src/Ryujinx.Horizon/Sdk/Sf/HipcCommandProcessor.cs @@ -206,7 +206,7 @@ namespace Ryujinx.Horizon.Sdk.Sf } else { - var data = MemoryMarshal.Cast(context.Request.Data.DataWords); + var data = MemoryMarshal.Cast(context.Request.Data.DataWordsPadded); var recvPointerSizes = MemoryMarshal.Cast(data[runtimeMetadata.UnfixedOutPointerSizeOffset..]); size = recvPointerSizes[unfixedRecvPointerIndex++]; diff --git a/src/Ryujinx.Horizon/ServiceTable.cs b/src/Ryujinx.Horizon/ServiceTable.cs index c79328a96..f3fe51940 100644 --- a/src/Ryujinx.Horizon/ServiceTable.cs +++ b/src/Ryujinx.Horizon/ServiceTable.cs @@ -1,4 +1,6 @@ +using Ryujinx.Horizon.Arp; using Ryujinx.Horizon.Bcat; +using Ryujinx.Horizon.Friends; using Ryujinx.Horizon.Hshl; using Ryujinx.Horizon.Ins; using Ryujinx.Horizon.Lbl; @@ -8,6 +10,7 @@ using Ryujinx.Horizon.Ngc; using Ryujinx.Horizon.Ovln; using Ryujinx.Horizon.Prepo; using Ryujinx.Horizon.Psc; +using Ryujinx.Horizon.Sdk.Arp; using Ryujinx.Horizon.Srepo; using Ryujinx.Horizon.Usb; using Ryujinx.Horizon.Wlan; @@ -23,6 +26,9 @@ namespace Ryujinx.Horizon private readonly ManualResetEvent _servicesReadyEvent = new(false); + public IReader ArpReader { get; internal set; } + public IWriter ArpWriter { get; internal set; } + public IEnumerable GetServices(HorizonOptions options) { List entries = new(); @@ -32,7 +38,9 @@ namespace Ryujinx.Horizon entries.Add(new ServiceEntry(T.Main, this, options)); } + RegisterService(); RegisterService(); + RegisterService(); RegisterService(); RegisterService(); RegisterService(); diff --git a/src/Ryujinx.Input.SDL2/SDL2GamepadDriver.cs b/src/Ryujinx.Input.SDL2/SDL2GamepadDriver.cs index 0e3a13011..c741493c1 100644 --- a/src/Ryujinx.Input.SDL2/SDL2GamepadDriver.cs +++ b/src/Ryujinx.Input.SDL2/SDL2GamepadDriver.cs @@ -9,8 +9,18 @@ namespace Ryujinx.Input.SDL2 { private readonly Dictionary _gamepadsInstanceIdsMapping; private readonly List _gamepadsIds; + private readonly object _lock = new object(); - public ReadOnlySpan GamepadsIds => _gamepadsIds.ToArray(); + public ReadOnlySpan GamepadsIds + { + get + { + lock (_lock) + { + return _gamepadsIds.ToArray(); + } + } + } public string DriverName => "SDL2"; @@ -35,28 +45,39 @@ namespace Ryujinx.Input.SDL2 } } - private static string GenerateGamepadId(int joystickIndex) + private string GenerateGamepadId(int joystickIndex) { Guid guid = SDL_JoystickGetDeviceGUID(joystickIndex); + // Add a unique identifier to the start of the GUID in case of duplicates. + if (guid == Guid.Empty) { return null; } - return joystickIndex + "-" + guid; - } + string id; - private static int GetJoystickIndexByGamepadId(string id) - { - string[] data = id.Split("-"); - - if (data.Length != 6 || !int.TryParse(data[0], out int joystickIndex)) + lock (_lock) { - return -1; + int guidIndex = 0; + id = guidIndex + "-" + guid; + + while (_gamepadsIds.Contains(id)) + { + id = (++guidIndex) + "-" + guid; + } } - return joystickIndex; + return id; + } + + private int GetJoystickIndexByGamepadId(string id) + { + lock (_lock) + { + return _gamepadsIds.IndexOf(id); + } } private void HandleJoyStickDisconnected(int joystickInstanceId) @@ -64,7 +85,11 @@ namespace Ryujinx.Input.SDL2 if (_gamepadsInstanceIdsMapping.TryGetValue(joystickInstanceId, out string id)) { _gamepadsInstanceIdsMapping.Remove(joystickInstanceId); - _gamepadsIds.Remove(id); + + lock (_lock) + { + _gamepadsIds.Remove(id); + } OnGamepadDisconnected?.Invoke(id); } @@ -74,6 +99,13 @@ namespace Ryujinx.Input.SDL2 { if (SDL_IsGameController(joystickDeviceId) == SDL_bool.SDL_TRUE) { + if (_gamepadsInstanceIdsMapping.ContainsKey(joystickInstanceId)) + { + // Sometimes a JoyStick connected event fires after the app starts even though it was connected before + // so it is rejected to avoid doubling the entries. + return; + } + string id = GenerateGamepadId(joystickDeviceId); if (id == null) @@ -81,16 +113,12 @@ namespace Ryujinx.Input.SDL2 return; } - // Sometimes a JoyStick connected event fires after the app starts even though it was connected before - // so it is rejected to avoid doubling the entries. - if (_gamepadsIds.Contains(id)) - { - return; - } - if (_gamepadsInstanceIdsMapping.TryAdd(joystickInstanceId, id)) { - _gamepadsIds.Add(id); + lock (_lock) + { + _gamepadsIds.Add(id); + } OnGamepadConnected?.Invoke(id); } @@ -110,7 +138,10 @@ namespace Ryujinx.Input.SDL2 OnGamepadDisconnected?.Invoke(id); } - _gamepadsIds.Clear(); + lock (_lock) + { + _gamepadsIds.Clear(); + } SDL2Driver.Instance.Dispose(); } @@ -131,11 +162,6 @@ namespace Ryujinx.Input.SDL2 return null; } - if (id != GenerateGamepadId(joystickIndex)) - { - return null; - } - IntPtr gamepadHandle = SDL_GameControllerOpen(joystickIndex); if (gamepadHandle == IntPtr.Zero) diff --git a/src/Ryujinx.Input/HLE/NpadManager.cs b/src/Ryujinx.Input/HLE/NpadManager.cs index 25887748f..5ae73bda1 100644 --- a/src/Ryujinx.Input/HLE/NpadManager.cs +++ b/src/Ryujinx.Input/HLE/NpadManager.cs @@ -5,6 +5,7 @@ using Ryujinx.HLE.HOS.Services.Hid; using System; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using System.Runtime.CompilerServices; using CemuHookClient = Ryujinx.Input.Motion.CemuHook.Client; using ControllerType = Ryujinx.Common.Configuration.Hid.ControllerType; @@ -69,7 +70,20 @@ namespace Ryujinx.Input.HLE private void HandleOnGamepadDisconnected(string obj) { // Force input reload - ReloadConfiguration(_inputConfig, _enableKeyboard, _enableMouse); + lock (_lock) + { + // Forcibly disconnect any controllers with this ID. + for (int i = 0; i < _controllers.Length; i++) + { + if (_controllers[i]?.Id == obj) + { + _controllers[i]?.Dispose(); + _controllers[i] = null; + } + } + + ReloadConfiguration(_inputConfig, _enableKeyboard, _enableMouse); + } } private void HandleOnGamepadConnected(string id) @@ -106,31 +120,48 @@ namespace Ryujinx.Input.HLE { lock (_lock) { - for (int i = 0; i < _controllers.Length; i++) - { - _controllers[i]?.Dispose(); - _controllers[i] = null; - } + NpadController[] oldControllers = _controllers.ToArray(); List validInputs = new(); foreach (InputConfig inputConfigEntry in inputConfig) { - NpadController controller = new(_cemuHookClient); + NpadController controller; + int index = (int)inputConfigEntry.PlayerIndex; + + if (oldControllers[index] != null) + { + // Try reuse the existing controller. + controller = oldControllers[index]; + oldControllers[index] = null; + } + else + { + controller = new(_cemuHookClient); + } bool isValid = DriverConfigurationUpdate(ref controller, inputConfigEntry); if (!isValid) { + _controllers[index] = null; controller.Dispose(); } else { - _controllers[(int)inputConfigEntry.PlayerIndex] = controller; + _controllers[index] = controller; validInputs.Add(inputConfigEntry); } } + for (int i = 0; i < oldControllers.Length; i++) + { + // Disconnect any controllers that weren't reused by the new configuration. + + oldControllers[i]?.Dispose(); + oldControllers[i] = null; + } + _inputConfig = inputConfig; _enableKeyboard = enableKeyboard; _enableMouse = enableMouse; diff --git a/src/Ryujinx.SDL2.Common/SDL2Driver.cs b/src/Ryujinx.SDL2.Common/SDL2Driver.cs index db1a85e3a..ed6d94190 100644 --- a/src/Ryujinx.SDL2.Common/SDL2Driver.cs +++ b/src/Ryujinx.SDL2.Common/SDL2Driver.cs @@ -1,4 +1,4 @@ -using Ryujinx.Common; +using Ryujinx.Common.Configuration; using Ryujinx.Common.Logging; using System; using System.Collections.Concurrent; @@ -13,8 +13,6 @@ namespace Ryujinx.SDL2.Common { private static SDL2Driver _instance; - public static bool IsInitialized => _instance != null; - public static SDL2Driver Instance { get @@ -96,7 +94,7 @@ namespace Ryujinx.SDL2.Common SDL_EventState(SDL_EventType.SDL_CONTROLLERSENSORUPDATE, SDL_DISABLE); - string gamepadDbPath = Path.Combine(ReleaseInformation.GetBaseApplicationDirectory(), "SDL_GameControllerDB.txt"); + string gamepadDbPath = Path.Combine(AppDataManager.BaseDirPath, "SDL_GameControllerDB.txt"); if (File.Exists(gamepadDbPath)) { diff --git a/src/Ryujinx.Tests/Cpu/CpuTest.cs b/src/Ryujinx.Tests/Cpu/CpuTest.cs index 35158c0b4..da0f03e6b 100644 --- a/src/Ryujinx.Tests/Cpu/CpuTest.cs +++ b/src/Ryujinx.Tests/Cpu/CpuTest.cs @@ -61,7 +61,6 @@ namespace Ryujinx.Tests.Cpu _memory.Map(DataBaseAddress, Size, Size, MemoryMapFlags.Private); _context = CpuContext.CreateExecutionContext(); - Translator.IsReadyForTranslation.Set(); _cpuContext = new CpuContext(_memory, for64Bit: true); diff --git a/src/Ryujinx.Tests/Cpu/CpuTest32.cs b/src/Ryujinx.Tests/Cpu/CpuTest32.cs index f5eb94fa9..6a690834f 100644 --- a/src/Ryujinx.Tests/Cpu/CpuTest32.cs +++ b/src/Ryujinx.Tests/Cpu/CpuTest32.cs @@ -56,7 +56,6 @@ namespace Ryujinx.Tests.Cpu _context = CpuContext.CreateExecutionContext(); _context.IsAarch32 = true; - Translator.IsReadyForTranslation.Set(); _cpuContext = new CpuContext(_memory, for64Bit: false); diff --git a/src/Ryujinx.Tests/Cpu/CpuTestSimdCvt32.cs b/src/Ryujinx.Tests/Cpu/CpuTestSimdCvt32.cs index 5b24432bb..ba201a480 100644 --- a/src/Ryujinx.Tests/Cpu/CpuTestSimdCvt32.cs +++ b/src/Ryujinx.Tests/Cpu/CpuTestSimdCvt32.cs @@ -511,6 +511,45 @@ namespace Ryujinx.Tests.Cpu CompareAgainstUnicorn(); } + + [Test, Pairwise, Description("VRINTR.F , ")] + [Platform(Exclude = "Linux,MacOsX")] // Instruction isn't testable due to Unicorn. + public void Vrintr([Values(0u, 1u)] uint rd, + [Values(0u, 1u)] uint rm, + [Values(2u, 3u)] uint size, + [ValueSource(nameof(_1D_F_))] ulong s0, + [ValueSource(nameof(_1D_F_))] ulong s1, + [ValueSource(nameof(_1D_F_))] ulong s2, + [Values(RMode.Rn, RMode.Rm, RMode.Rp)] RMode rMode) + { + uint opcode = 0xEEB60A40; + + V128 v0, v1, v2; + + if (size == 2) + { + opcode |= ((rm & 0x1e) >> 1) | ((rm & 0x1) << 5); + opcode |= ((rd & 0x1e) << 11) | ((rd & 0x1) << 22); + v0 = MakeVectorE0E1((uint)BitConverter.SingleToInt32Bits(s0), (uint)BitConverter.SingleToInt32Bits(s0)); + v1 = MakeVectorE0E1((uint)BitConverter.SingleToInt32Bits(s1), (uint)BitConverter.SingleToInt32Bits(s0)); + v2 = MakeVectorE0E1((uint)BitConverter.SingleToInt32Bits(s2), (uint)BitConverter.SingleToInt32Bits(s1)); + } + else + { + opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1); + opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18); + v0 = MakeVectorE0E1((uint)BitConverter.DoubleToInt64Bits(s0), (uint)BitConverter.DoubleToInt64Bits(s0)); + v1 = MakeVectorE0E1((uint)BitConverter.DoubleToInt64Bits(s1), (uint)BitConverter.DoubleToInt64Bits(s0)); + v2 = MakeVectorE0E1((uint)BitConverter.DoubleToInt64Bits(s2), (uint)BitConverter.DoubleToInt64Bits(s1)); + } + + opcode |= ((size & 3) << 8); + + int fpscr = (int)rMode << (int)Fpcr.RMode; + SingleOpcode(opcode, v0: v0, v1: v1, v2: v2, fpscr: fpscr); + + CompareAgainstUnicorn(); + } #endif } } diff --git a/src/Ryujinx.Tests/Cpu/CpuTestSimdReg32.cs b/src/Ryujinx.Tests/Cpu/CpuTestSimdReg32.cs index 9d9606bba..38e08bf89 100644 --- a/src/Ryujinx.Tests/Cpu/CpuTestSimdReg32.cs +++ b/src/Ryujinx.Tests/Cpu/CpuTestSimdReg32.cs @@ -908,6 +908,44 @@ namespace Ryujinx.Tests.Cpu CompareAgainstUnicorn(); } + + [Test, Pairwise] + public void Vp_Add_Long_Accumulate([Values(0u, 2u, 4u, 8u)] uint rd, + [Values(0u, 2u, 4u, 8u)] uint rm, + [Values(0u, 1u, 2u)] uint size, + [Random(RndCnt)] ulong z, + [Random(RndCnt)] ulong a, + [Random(RndCnt)] ulong b, + [Values] bool q, + [Values] bool unsigned) + { + uint opcode = 0xF3B00600; // VPADAL.S8 D0, Q0 + + if (q) + { + opcode |= 1 << 6; + rm <<= 1; + rd <<= 1; + } + + if (unsigned) + { + opcode |= 1 << 7; + } + + opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1); + opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18); + + opcode |= size << 18; + + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, z); + V128 v2 = MakeVectorE0E1(b, z); + + SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); + + CompareAgainstUnicorn(); + } #endif } } diff --git a/src/Ryujinx.Tests/Cpu/CpuTestSimdShImm.cs b/src/Ryujinx.Tests/Cpu/CpuTestSimdShImm.cs index fbac54c8c..9816bc2cc 100644 --- a/src/Ryujinx.Tests/Cpu/CpuTestSimdShImm.cs +++ b/src/Ryujinx.Tests/Cpu/CpuTestSimdShImm.cs @@ -311,6 +311,46 @@ namespace Ryujinx.Tests.Cpu }; } + private static uint[] _ShlImm_S_D_() + { + return new[] + { + 0x5F407400u, // SQSHL D0, D0, #0 + }; + } + + private static uint[] _ShlImm_V_8B_16B_() + { + return new[] + { + 0x0F087400u, // SQSHL V0.8B, V0.8B, #0 + }; + } + + private static uint[] _ShlImm_V_4H_8H_() + { + return new[] + { + 0x0F107400u, // SQSHL V0.4H, V0.4H, #0 + }; + } + + private static uint[] _ShlImm_V_2S_4S_() + { + return new[] + { + 0x0F207400u, // SQSHL V0.2S, V0.2S, #0 + }; + } + + private static uint[] _ShlImm_V_2D_() + { + return new[] + { + 0x4F407400u, // SQSHL V0.2D, V0.2D, #0 + }; + } + private static uint[] _ShrImm_Sri_S_D_() { return new[] @@ -813,6 +853,117 @@ namespace Ryujinx.Tests.Cpu CompareAgainstUnicorn(); } + [Test, Pairwise] + public void ShlImm_S_D([ValueSource(nameof(_ShlImm_S_D_))] uint opcodes, + [Values(0u)] uint rd, + [Values(1u, 0u)] uint rn, + [ValueSource(nameof(_1D_))] ulong z, + [ValueSource(nameof(_1D_))] ulong a, + [Values(1u, 64u)] uint shift) + { + uint immHb = (64 + shift) & 0x7F; + + opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); + opcodes |= (immHb << 16); + + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0(a); + + SingleOpcode(opcodes, v0: v0, v1: v1); + + CompareAgainstUnicorn(); + } + + [Test, Pairwise] + public void ShlImm_V_8B_16B([ValueSource(nameof(_ShlImm_V_8B_16B_))] uint opcodes, + [Values(0u)] uint rd, + [Values(1u, 0u)] uint rn, + [ValueSource(nameof(_8B_))] ulong z, + [ValueSource(nameof(_8B_))] ulong a, + [Values(1u, 8u)] uint shift, + [Values(0b0u, 0b1u)] uint q) // <8B, 16B> + { + uint immHb = (8 + shift) & 0x7F; + + opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); + opcodes |= (immHb << 16); + opcodes |= ((q & 1) << 30); + + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a * q); + + SingleOpcode(opcodes, v0: v0, v1: v1); + + CompareAgainstUnicorn(); + } + + [Test, Pairwise] + public void ShlImm_V_4H_8H([ValueSource(nameof(_ShlImm_V_4H_8H_))] uint opcodes, + [Values(0u)] uint rd, + [Values(1u, 0u)] uint rn, + [ValueSource(nameof(_4H_))] ulong z, + [ValueSource(nameof(_4H_))] ulong a, + [Values(1u, 16u)] uint shift, + [Values(0b0u, 0b1u)] uint q) // <4H, 8H> + { + uint immHb = (16 + shift) & 0x7F; + + opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); + opcodes |= (immHb << 16); + opcodes |= ((q & 1) << 30); + + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a * q); + + SingleOpcode(opcodes, v0: v0, v1: v1); + + CompareAgainstUnicorn(); + } + + [Test, Pairwise] + public void ShlImm_V_2S_4S([ValueSource(nameof(_ShlImm_V_2S_4S_))] uint opcodes, + [Values(0u)] uint rd, + [Values(1u, 0u)] uint rn, + [ValueSource(nameof(_2S_))] ulong z, + [ValueSource(nameof(_2S_))] ulong a, + [Values(1u, 32u)] uint shift, + [Values(0b0u, 0b1u)] uint q) // <2S, 4S> + { + uint immHb = (32 + shift) & 0x7F; + + opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); + opcodes |= (immHb << 16); + opcodes |= (((q | (immHb >> 6)) & 1) << 30); + + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a * q); + + SingleOpcode(opcodes, v0: v0, v1: v1); + + CompareAgainstUnicorn(); + } + + [Test, Pairwise] + public void ShlImm_V_2D([ValueSource(nameof(_ShlImm_V_2D_))] uint opcodes, + [Values(0u)] uint rd, + [Values(1u, 0u)] uint rn, + [ValueSource(nameof(_1D_))] ulong z, + [ValueSource(nameof(_1D_))] ulong a, + [Values(1u, 64u)] uint shift) + { + uint immHb = (64 + shift) & 0x7F; + + opcodes |= ((rn & 31) << 5) | ((rd & 31) << 0); + opcodes |= (immHb << 16); + + V128 v0 = MakeVectorE0E1(z, z); + V128 v1 = MakeVectorE0E1(a, a); + + SingleOpcode(opcodes, v0: v0, v1: v1); + + CompareAgainstUnicorn(); + } + [Test, Pairwise] public void ShrImm_Sri_S_D([ValueSource(nameof(_ShrImm_Sri_S_D_))] uint opcodes, [Values(0u)] uint rd, diff --git a/src/Ryujinx.Ui.Common/App/ApplicationAddedEventArgs.cs b/src/Ryujinx.UI.Common/App/ApplicationAddedEventArgs.cs similarity index 81% rename from src/Ryujinx.Ui.Common/App/ApplicationAddedEventArgs.cs rename to src/Ryujinx.UI.Common/App/ApplicationAddedEventArgs.cs index 01e20276e..58e066b9d 100644 --- a/src/Ryujinx.Ui.Common/App/ApplicationAddedEventArgs.cs +++ b/src/Ryujinx.UI.Common/App/ApplicationAddedEventArgs.cs @@ -1,6 +1,6 @@ using System; -namespace Ryujinx.Ui.App.Common +namespace Ryujinx.UI.App.Common { public class ApplicationAddedEventArgs : EventArgs { diff --git a/src/Ryujinx.Ui.Common/App/ApplicationCountUpdatedEventArgs.cs b/src/Ryujinx.UI.Common/App/ApplicationCountUpdatedEventArgs.cs similarity index 85% rename from src/Ryujinx.Ui.Common/App/ApplicationCountUpdatedEventArgs.cs rename to src/Ryujinx.UI.Common/App/ApplicationCountUpdatedEventArgs.cs index ca54ddf7a..5ed7baf19 100644 --- a/src/Ryujinx.Ui.Common/App/ApplicationCountUpdatedEventArgs.cs +++ b/src/Ryujinx.UI.Common/App/ApplicationCountUpdatedEventArgs.cs @@ -1,6 +1,6 @@ using System; -namespace Ryujinx.Ui.App.Common +namespace Ryujinx.UI.App.Common { public class ApplicationCountUpdatedEventArgs : EventArgs { diff --git a/src/Ryujinx.Ui.Common/App/ApplicationData.cs b/src/Ryujinx.UI.Common/App/ApplicationData.cs similarity index 98% rename from src/Ryujinx.Ui.Common/App/ApplicationData.cs rename to src/Ryujinx.UI.Common/App/ApplicationData.cs index bd844805b..8cc7238e9 100644 --- a/src/Ryujinx.Ui.Common/App/ApplicationData.cs +++ b/src/Ryujinx.UI.Common/App/ApplicationData.cs @@ -9,11 +9,11 @@ using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem.NcaUtils; using Ryujinx.Common.Logging; using Ryujinx.HLE.FileSystem; -using Ryujinx.Ui.Common.Helper; +using Ryujinx.UI.Common.Helper; using System; using System.IO; -namespace Ryujinx.Ui.App.Common +namespace Ryujinx.UI.App.Common { public class ApplicationData { diff --git a/src/Ryujinx.Ui.Common/App/ApplicationJsonSerializerContext.cs b/src/Ryujinx.UI.Common/App/ApplicationJsonSerializerContext.cs similarity index 88% rename from src/Ryujinx.Ui.Common/App/ApplicationJsonSerializerContext.cs rename to src/Ryujinx.UI.Common/App/ApplicationJsonSerializerContext.cs index 9a7b3eddf..ada7cc346 100644 --- a/src/Ryujinx.Ui.Common/App/ApplicationJsonSerializerContext.cs +++ b/src/Ryujinx.UI.Common/App/ApplicationJsonSerializerContext.cs @@ -1,6 +1,6 @@ using System.Text.Json.Serialization; -namespace Ryujinx.Ui.App.Common +namespace Ryujinx.UI.App.Common { [JsonSourceGenerationOptions(WriteIndented = true)] [JsonSerializable(typeof(ApplicationMetadata))] diff --git a/src/Ryujinx.Ui.Common/App/ApplicationLibrary.cs b/src/Ryujinx.UI.Common/App/ApplicationLibrary.cs similarity index 97% rename from src/Ryujinx.Ui.Common/App/ApplicationLibrary.cs rename to src/Ryujinx.UI.Common/App/ApplicationLibrary.cs index 950eb55b4..65cf7a9e6 100644 --- a/src/Ryujinx.Ui.Common/App/ApplicationLibrary.cs +++ b/src/Ryujinx.UI.Common/App/ApplicationLibrary.cs @@ -8,14 +8,15 @@ using LibHac.Ns; using LibHac.Tools.Fs; using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem.NcaUtils; +using Ryujinx.Common; using Ryujinx.Common.Configuration; using Ryujinx.Common.Logging; using Ryujinx.Common.Utilities; using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.HOS.SystemState; using Ryujinx.HLE.Loaders.Npdm; -using Ryujinx.Ui.Common.Configuration; -using Ryujinx.Ui.Common.Configuration.System; +using Ryujinx.UI.Common.Configuration; +using Ryujinx.UI.Common.Configuration.System; using System; using System.Collections.Generic; using System.Globalization; @@ -28,7 +29,7 @@ using System.Threading; using Path = System.IO.Path; using TimeSpan = System.TimeSpan; -namespace Ryujinx.Ui.App.Common +namespace Ryujinx.UI.App.Common { public class ApplicationLibrary { @@ -52,11 +53,11 @@ namespace Ryujinx.Ui.App.Common { _virtualFileSystem = virtualFileSystem; - _nspIcon = GetResourceBytes("Ryujinx.Ui.Common.Resources.Icon_NSP.png"); - _xciIcon = GetResourceBytes("Ryujinx.Ui.Common.Resources.Icon_XCI.png"); - _ncaIcon = GetResourceBytes("Ryujinx.Ui.Common.Resources.Icon_NCA.png"); - _nroIcon = GetResourceBytes("Ryujinx.Ui.Common.Resources.Icon_NRO.png"); - _nsoIcon = GetResourceBytes("Ryujinx.Ui.Common.Resources.Icon_NSO.png"); + _nspIcon = GetResourceBytes("Ryujinx.UI.Common.Resources.Icon_NSP.png"); + _xciIcon = GetResourceBytes("Ryujinx.UI.Common.Resources.Icon_XCI.png"); + _ncaIcon = GetResourceBytes("Ryujinx.UI.Common.Resources.Icon_NCA.png"); + _nroIcon = GetResourceBytes("Ryujinx.UI.Common.Resources.Icon_NRO.png"); + _nsoIcon = GetResourceBytes("Ryujinx.UI.Common.Resources.Icon_NSO.png"); } private static byte[] GetResourceBytes(string resourceName) @@ -105,7 +106,7 @@ namespace Ryujinx.Ui.App.Common if (!Directory.Exists(appDir)) { - Logger.Warning?.Print(LogClass.Application, $"The \"game_dirs\" section in \"Config.json\" contains an invalid directory: \"{appDir}\""); + Logger.Warning?.Print(LogClass.Application, $"The \"game_dirs\" section in \"{ReleaseInformation.ConfigName}\" contains an invalid directory: \"{appDir}\""); continue; } @@ -115,12 +116,12 @@ namespace Ryujinx.Ui.App.Common IEnumerable files = Directory.EnumerateFiles(appDir, "*", SearchOption.AllDirectories).Where(file => { return - (Path.GetExtension(file).ToLower() is ".nsp" && ConfigurationState.Instance.Ui.ShownFileTypes.NSP.Value) || - (Path.GetExtension(file).ToLower() is ".pfs0" && ConfigurationState.Instance.Ui.ShownFileTypes.PFS0.Value) || - (Path.GetExtension(file).ToLower() is ".xci" && ConfigurationState.Instance.Ui.ShownFileTypes.XCI.Value) || - (Path.GetExtension(file).ToLower() is ".nca" && ConfigurationState.Instance.Ui.ShownFileTypes.NCA.Value) || - (Path.GetExtension(file).ToLower() is ".nro" && ConfigurationState.Instance.Ui.ShownFileTypes.NRO.Value) || - (Path.GetExtension(file).ToLower() is ".nso" && ConfigurationState.Instance.Ui.ShownFileTypes.NSO.Value); + (Path.GetExtension(file).ToLower() is ".nsp" && ConfigurationState.Instance.UI.ShownFileTypes.NSP.Value) || + (Path.GetExtension(file).ToLower() is ".pfs0" && ConfigurationState.Instance.UI.ShownFileTypes.PFS0.Value) || + (Path.GetExtension(file).ToLower() is ".xci" && ConfigurationState.Instance.UI.ShownFileTypes.XCI.Value) || + (Path.GetExtension(file).ToLower() is ".nca" && ConfigurationState.Instance.UI.ShownFileTypes.NCA.Value) || + (Path.GetExtension(file).ToLower() is ".nro" && ConfigurationState.Instance.UI.ShownFileTypes.NRO.Value) || + (Path.GetExtension(file).ToLower() is ".nso" && ConfigurationState.Instance.UI.ShownFileTypes.NSO.Value); }); foreach (string app in files) diff --git a/src/Ryujinx.Ui.Common/App/ApplicationMetadata.cs b/src/Ryujinx.UI.Common/App/ApplicationMetadata.cs similarity index 98% rename from src/Ryujinx.Ui.Common/App/ApplicationMetadata.cs rename to src/Ryujinx.UI.Common/App/ApplicationMetadata.cs index 43647feef..81193c5b3 100644 --- a/src/Ryujinx.Ui.Common/App/ApplicationMetadata.cs +++ b/src/Ryujinx.UI.Common/App/ApplicationMetadata.cs @@ -1,7 +1,7 @@ using System; using System.Text.Json.Serialization; -namespace Ryujinx.Ui.App.Common +namespace Ryujinx.UI.App.Common { public class ApplicationMetadata { diff --git a/src/Ryujinx.Ui.Common/Configuration/AudioBackend.cs b/src/Ryujinx.UI.Common/Configuration/AudioBackend.cs similarity index 85% rename from src/Ryujinx.Ui.Common/Configuration/AudioBackend.cs rename to src/Ryujinx.UI.Common/Configuration/AudioBackend.cs index dc0a5ac61..a952e7ac0 100644 --- a/src/Ryujinx.Ui.Common/Configuration/AudioBackend.cs +++ b/src/Ryujinx.UI.Common/Configuration/AudioBackend.cs @@ -1,7 +1,7 @@ using Ryujinx.Common.Utilities; using System.Text.Json.Serialization; -namespace Ryujinx.Ui.Common.Configuration +namespace Ryujinx.UI.Common.Configuration { [JsonConverter(typeof(TypedStringEnumConverter))] public enum AudioBackend diff --git a/src/Ryujinx.Ui.Common/Configuration/ConfigurationFileFormat.cs b/src/Ryujinx.UI.Common/Configuration/ConfigurationFileFormat.cs similarity index 99% rename from src/Ryujinx.Ui.Common/Configuration/ConfigurationFileFormat.cs rename to src/Ryujinx.UI.Common/Configuration/ConfigurationFileFormat.cs index 8a4db1fe7..0ee51d830 100644 --- a/src/Ryujinx.Ui.Common/Configuration/ConfigurationFileFormat.cs +++ b/src/Ryujinx.UI.Common/Configuration/ConfigurationFileFormat.cs @@ -3,12 +3,12 @@ using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Configuration.Multiplayer; using Ryujinx.Common.Logging; using Ryujinx.Common.Utilities; -using Ryujinx.Ui.Common.Configuration.System; -using Ryujinx.Ui.Common.Configuration.Ui; +using Ryujinx.UI.Common.Configuration.System; +using Ryujinx.UI.Common.Configuration.UI; using System.Collections.Generic; using System.Text.Json.Nodes; -namespace Ryujinx.Ui.Common.Configuration +namespace Ryujinx.UI.Common.Configuration { public class ConfigurationFileFormat { diff --git a/src/Ryujinx.Ui.Common/Configuration/ConfigurationFileFormatSettings.cs b/src/Ryujinx.UI.Common/Configuration/ConfigurationFileFormatSettings.cs similarity index 85% rename from src/Ryujinx.Ui.Common/Configuration/ConfigurationFileFormatSettings.cs rename to src/Ryujinx.UI.Common/Configuration/ConfigurationFileFormatSettings.cs index 9a1841fc5..9861ebf1f 100644 --- a/src/Ryujinx.Ui.Common/Configuration/ConfigurationFileFormatSettings.cs +++ b/src/Ryujinx.UI.Common/Configuration/ConfigurationFileFormatSettings.cs @@ -1,6 +1,6 @@ using Ryujinx.Common.Utilities; -namespace Ryujinx.Ui.Common.Configuration +namespace Ryujinx.UI.Common.Configuration { internal static class ConfigurationFileFormatSettings { diff --git a/src/Ryujinx.Ui.Common/Configuration/ConfigurationJsonSerializerContext.cs b/src/Ryujinx.UI.Common/Configuration/ConfigurationJsonSerializerContext.cs similarity index 85% rename from src/Ryujinx.Ui.Common/Configuration/ConfigurationJsonSerializerContext.cs rename to src/Ryujinx.UI.Common/Configuration/ConfigurationJsonSerializerContext.cs index 03989edec..3c3e3f20d 100644 --- a/src/Ryujinx.Ui.Common/Configuration/ConfigurationJsonSerializerContext.cs +++ b/src/Ryujinx.UI.Common/Configuration/ConfigurationJsonSerializerContext.cs @@ -1,6 +1,6 @@ using System.Text.Json.Serialization; -namespace Ryujinx.Ui.Common.Configuration +namespace Ryujinx.UI.Common.Configuration { [JsonSourceGenerationOptions(WriteIndented = true)] [JsonSerializable(typeof(ConfigurationFileFormat))] diff --git a/src/Ryujinx.Ui.Common/Configuration/ConfigurationState.cs b/src/Ryujinx.UI.Common/Configuration/ConfigurationState.cs similarity index 90% rename from src/Ryujinx.Ui.Common/Configuration/ConfigurationState.cs rename to src/Ryujinx.UI.Common/Configuration/ConfigurationState.cs index b017d384c..1d6934ce3 100644 --- a/src/Ryujinx.Ui.Common/Configuration/ConfigurationState.cs +++ b/src/Ryujinx.UI.Common/Configuration/ConfigurationState.cs @@ -6,21 +6,21 @@ using Ryujinx.Common.Configuration.Hid.Keyboard; using Ryujinx.Common.Configuration.Multiplayer; using Ryujinx.Common.Logging; using Ryujinx.Graphics.Vulkan; -using Ryujinx.Ui.Common.Configuration.System; -using Ryujinx.Ui.Common.Configuration.Ui; -using Ryujinx.Ui.Common.Helper; +using Ryujinx.UI.Common.Configuration.System; +using Ryujinx.UI.Common.Configuration.UI; +using Ryujinx.UI.Common.Helper; using System; using System.Collections.Generic; using System.Text.Json.Nodes; -namespace Ryujinx.Ui.Common.Configuration +namespace Ryujinx.UI.Common.Configuration { public class ConfigurationState { /// /// UI configuration section /// - public class UiSection + public class UISection { public class Columns { @@ -186,7 +186,7 @@ namespace Ryujinx.Ui.Common.Configuration /// public ReactiveObject IsAscendingOrder { get; private set; } - public UiSection() + public UISection() { GuiColumns = new Columns(); ColumnSort = new ColumnSortSettings(); @@ -582,9 +582,9 @@ namespace Ryujinx.Ui.Common.Configuration public static ConfigurationState Instance { get; private set; } /// - /// The Ui section + /// The UI section /// - public UiSection Ui { get; private set; } + public UISection UI { get; private set; } /// /// The Logger section @@ -633,7 +633,7 @@ namespace Ryujinx.Ui.Common.Configuration private ConfigurationState() { - Ui = new UiSection(); + UI = new UISection(); Logger = new LoggerSection(); System = new SystemSection(); Graphics = new GraphicsSection(); @@ -696,51 +696,51 @@ namespace Ryujinx.Ui.Common.Configuration UseHypervisor = System.UseHypervisor, GuiColumns = new GuiColumns { - FavColumn = Ui.GuiColumns.FavColumn, - IconColumn = Ui.GuiColumns.IconColumn, - AppColumn = Ui.GuiColumns.AppColumn, - DevColumn = Ui.GuiColumns.DevColumn, - VersionColumn = Ui.GuiColumns.VersionColumn, - TimePlayedColumn = Ui.GuiColumns.TimePlayedColumn, - LastPlayedColumn = Ui.GuiColumns.LastPlayedColumn, - FileExtColumn = Ui.GuiColumns.FileExtColumn, - FileSizeColumn = Ui.GuiColumns.FileSizeColumn, - PathColumn = Ui.GuiColumns.PathColumn, + FavColumn = UI.GuiColumns.FavColumn, + IconColumn = UI.GuiColumns.IconColumn, + AppColumn = UI.GuiColumns.AppColumn, + DevColumn = UI.GuiColumns.DevColumn, + VersionColumn = UI.GuiColumns.VersionColumn, + TimePlayedColumn = UI.GuiColumns.TimePlayedColumn, + LastPlayedColumn = UI.GuiColumns.LastPlayedColumn, + FileExtColumn = UI.GuiColumns.FileExtColumn, + FileSizeColumn = UI.GuiColumns.FileSizeColumn, + PathColumn = UI.GuiColumns.PathColumn, }, ColumnSort = new ColumnSort { - SortColumnId = Ui.ColumnSort.SortColumnId, - SortAscending = Ui.ColumnSort.SortAscending, + SortColumnId = UI.ColumnSort.SortColumnId, + SortAscending = UI.ColumnSort.SortAscending, }, - GameDirs = Ui.GameDirs, + GameDirs = UI.GameDirs, ShownFileTypes = new ShownFileTypes { - NSP = Ui.ShownFileTypes.NSP, - PFS0 = Ui.ShownFileTypes.PFS0, - XCI = Ui.ShownFileTypes.XCI, - NCA = Ui.ShownFileTypes.NCA, - NRO = Ui.ShownFileTypes.NRO, - NSO = Ui.ShownFileTypes.NSO, + NSP = UI.ShownFileTypes.NSP, + PFS0 = UI.ShownFileTypes.PFS0, + XCI = UI.ShownFileTypes.XCI, + NCA = UI.ShownFileTypes.NCA, + NRO = UI.ShownFileTypes.NRO, + NSO = UI.ShownFileTypes.NSO, }, WindowStartup = new WindowStartup { - WindowSizeWidth = Ui.WindowStartup.WindowSizeWidth, - WindowSizeHeight = Ui.WindowStartup.WindowSizeHeight, - WindowPositionX = Ui.WindowStartup.WindowPositionX, - WindowPositionY = Ui.WindowStartup.WindowPositionY, - WindowMaximized = Ui.WindowStartup.WindowMaximized, + WindowSizeWidth = UI.WindowStartup.WindowSizeWidth, + WindowSizeHeight = UI.WindowStartup.WindowSizeHeight, + WindowPositionX = UI.WindowStartup.WindowPositionX, + WindowPositionY = UI.WindowStartup.WindowPositionY, + WindowMaximized = UI.WindowStartup.WindowMaximized, }, - LanguageCode = Ui.LanguageCode, - EnableCustomTheme = Ui.EnableCustomTheme, - CustomThemePath = Ui.CustomThemePath, - BaseStyle = Ui.BaseStyle, - GameListViewMode = Ui.GameListViewMode, - ShowNames = Ui.ShowNames, - GridSize = Ui.GridSize, - ApplicationSort = Ui.ApplicationSort, - IsAscendingOrder = Ui.IsAscendingOrder, - StartFullscreen = Ui.StartFullscreen, - ShowConsole = Ui.ShowConsole, + LanguageCode = UI.LanguageCode, + EnableCustomTheme = UI.EnableCustomTheme, + CustomThemePath = UI.CustomThemePath, + BaseStyle = UI.BaseStyle, + GameListViewMode = UI.GameListViewMode, + ShowNames = UI.ShowNames, + GridSize = UI.GridSize, + ApplicationSort = UI.ApplicationSort, + IsAscendingOrder = UI.IsAscendingOrder, + StartFullscreen = UI.StartFullscreen, + ShowConsole = UI.ShowConsole, EnableKeyboard = Hid.EnableKeyboard, EnableMouse = Hid.EnableMouse, Hotkeys = Hid.Hotkeys, @@ -806,41 +806,41 @@ namespace Ryujinx.Ui.Common.Configuration System.UseHypervisor.Value = true; Multiplayer.LanInterfaceId.Value = "0"; Multiplayer.Mode.Value = MultiplayerMode.Disabled; - Ui.GuiColumns.FavColumn.Value = true; - Ui.GuiColumns.IconColumn.Value = true; - Ui.GuiColumns.AppColumn.Value = true; - Ui.GuiColumns.DevColumn.Value = true; - Ui.GuiColumns.VersionColumn.Value = true; - Ui.GuiColumns.TimePlayedColumn.Value = true; - Ui.GuiColumns.LastPlayedColumn.Value = true; - Ui.GuiColumns.FileExtColumn.Value = true; - Ui.GuiColumns.FileSizeColumn.Value = true; - Ui.GuiColumns.PathColumn.Value = true; - Ui.ColumnSort.SortColumnId.Value = 0; - Ui.ColumnSort.SortAscending.Value = false; - Ui.GameDirs.Value = new List(); - Ui.ShownFileTypes.NSP.Value = true; - Ui.ShownFileTypes.PFS0.Value = true; - Ui.ShownFileTypes.XCI.Value = true; - Ui.ShownFileTypes.NCA.Value = true; - Ui.ShownFileTypes.NRO.Value = true; - Ui.ShownFileTypes.NSO.Value = true; - Ui.EnableCustomTheme.Value = true; - Ui.LanguageCode.Value = "en_US"; - Ui.CustomThemePath.Value = ""; - Ui.BaseStyle.Value = "Dark"; - Ui.GameListViewMode.Value = 0; - Ui.ShowNames.Value = true; - Ui.GridSize.Value = 2; - Ui.ApplicationSort.Value = 0; - Ui.IsAscendingOrder.Value = true; - Ui.StartFullscreen.Value = false; - Ui.ShowConsole.Value = true; - Ui.WindowStartup.WindowSizeWidth.Value = 1280; - Ui.WindowStartup.WindowSizeHeight.Value = 760; - Ui.WindowStartup.WindowPositionX.Value = 0; - Ui.WindowStartup.WindowPositionY.Value = 0; - Ui.WindowStartup.WindowMaximized.Value = false; + UI.GuiColumns.FavColumn.Value = true; + UI.GuiColumns.IconColumn.Value = true; + UI.GuiColumns.AppColumn.Value = true; + UI.GuiColumns.DevColumn.Value = true; + UI.GuiColumns.VersionColumn.Value = true; + UI.GuiColumns.TimePlayedColumn.Value = true; + UI.GuiColumns.LastPlayedColumn.Value = true; + UI.GuiColumns.FileExtColumn.Value = true; + UI.GuiColumns.FileSizeColumn.Value = true; + UI.GuiColumns.PathColumn.Value = true; + UI.ColumnSort.SortColumnId.Value = 0; + UI.ColumnSort.SortAscending.Value = false; + UI.GameDirs.Value = new List(); + UI.ShownFileTypes.NSP.Value = true; + UI.ShownFileTypes.PFS0.Value = true; + UI.ShownFileTypes.XCI.Value = true; + UI.ShownFileTypes.NCA.Value = true; + UI.ShownFileTypes.NRO.Value = true; + UI.ShownFileTypes.NSO.Value = true; + UI.EnableCustomTheme.Value = true; + UI.LanguageCode.Value = "en_US"; + UI.CustomThemePath.Value = ""; + UI.BaseStyle.Value = "Dark"; + UI.GameListViewMode.Value = 0; + UI.ShowNames.Value = true; + UI.GridSize.Value = 2; + UI.ApplicationSort.Value = 0; + UI.IsAscendingOrder.Value = true; + UI.StartFullscreen.Value = false; + UI.ShowConsole.Value = true; + UI.WindowStartup.WindowSizeWidth.Value = 1280; + UI.WindowStartup.WindowSizeHeight.Value = 760; + UI.WindowStartup.WindowPositionX.Value = 0; + UI.WindowStartup.WindowPositionY.Value = 0; + UI.WindowStartup.WindowMaximized.Value = false; Hid.EnableKeyboard.Value = false; Hid.EnableMouse.Value = false; Hid.Hotkeys.Value = new KeyboardHotkeys @@ -848,7 +848,7 @@ namespace Ryujinx.Ui.Common.Configuration ToggleVsync = Key.F1, ToggleMute = Key.F2, Screenshot = Key.F8, - ShowUi = Key.F4, + ShowUI = Key.F4, Pause = Key.F5, ResScaleUp = Key.Unbound, ResScaleDown = Key.Unbound, @@ -1185,7 +1185,7 @@ namespace Ryujinx.Ui.Common.Configuration { ToggleVsync = Key.F1, Screenshot = Key.F8, - ShowUi = Key.F4, + ShowUI = Key.F4, }; configurationFileUpdated = true; @@ -1228,7 +1228,7 @@ namespace Ryujinx.Ui.Common.Configuration { ToggleVsync = configurationFileFormat.Hotkeys.ToggleVsync, Screenshot = configurationFileFormat.Hotkeys.Screenshot, - ShowUi = configurationFileFormat.Hotkeys.ShowUi, + ShowUI = configurationFileFormat.Hotkeys.ShowUI, Pause = Key.F5, }; @@ -1243,7 +1243,7 @@ namespace Ryujinx.Ui.Common.Configuration { ToggleVsync = configurationFileFormat.Hotkeys.ToggleVsync, Screenshot = configurationFileFormat.Hotkeys.Screenshot, - ShowUi = configurationFileFormat.Hotkeys.ShowUi, + ShowUI = configurationFileFormat.Hotkeys.ShowUI, Pause = configurationFileFormat.Hotkeys.Pause, ToggleMute = Key.F2, }; @@ -1317,7 +1317,7 @@ namespace Ryujinx.Ui.Common.Configuration { ToggleVsync = configurationFileFormat.Hotkeys.ToggleVsync, Screenshot = configurationFileFormat.Hotkeys.Screenshot, - ShowUi = configurationFileFormat.Hotkeys.ShowUi, + ShowUI = configurationFileFormat.Hotkeys.ShowUI, Pause = configurationFileFormat.Hotkeys.Pause, ToggleMute = configurationFileFormat.Hotkeys.ToggleMute, ResScaleUp = Key.Unbound, @@ -1344,7 +1344,7 @@ namespace Ryujinx.Ui.Common.Configuration { ToggleVsync = configurationFileFormat.Hotkeys.ToggleVsync, Screenshot = configurationFileFormat.Hotkeys.Screenshot, - ShowUi = configurationFileFormat.Hotkeys.ShowUi, + ShowUI = configurationFileFormat.Hotkeys.ShowUI, Pause = configurationFileFormat.Hotkeys.Pause, ToggleMute = configurationFileFormat.Hotkeys.ToggleMute, ResScaleUp = configurationFileFormat.Hotkeys.ResScaleUp, @@ -1476,41 +1476,41 @@ namespace Ryujinx.Ui.Common.Configuration System.ExpandRam.Value = configurationFileFormat.ExpandRam; System.IgnoreMissingServices.Value = configurationFileFormat.IgnoreMissingServices; System.UseHypervisor.Value = configurationFileFormat.UseHypervisor; - Ui.GuiColumns.FavColumn.Value = configurationFileFormat.GuiColumns.FavColumn; - Ui.GuiColumns.IconColumn.Value = configurationFileFormat.GuiColumns.IconColumn; - Ui.GuiColumns.AppColumn.Value = configurationFileFormat.GuiColumns.AppColumn; - Ui.GuiColumns.DevColumn.Value = configurationFileFormat.GuiColumns.DevColumn; - Ui.GuiColumns.VersionColumn.Value = configurationFileFormat.GuiColumns.VersionColumn; - Ui.GuiColumns.TimePlayedColumn.Value = configurationFileFormat.GuiColumns.TimePlayedColumn; - Ui.GuiColumns.LastPlayedColumn.Value = configurationFileFormat.GuiColumns.LastPlayedColumn; - Ui.GuiColumns.FileExtColumn.Value = configurationFileFormat.GuiColumns.FileExtColumn; - Ui.GuiColumns.FileSizeColumn.Value = configurationFileFormat.GuiColumns.FileSizeColumn; - Ui.GuiColumns.PathColumn.Value = configurationFileFormat.GuiColumns.PathColumn; - Ui.ColumnSort.SortColumnId.Value = configurationFileFormat.ColumnSort.SortColumnId; - Ui.ColumnSort.SortAscending.Value = configurationFileFormat.ColumnSort.SortAscending; - Ui.GameDirs.Value = configurationFileFormat.GameDirs; - Ui.ShownFileTypes.NSP.Value = configurationFileFormat.ShownFileTypes.NSP; - Ui.ShownFileTypes.PFS0.Value = configurationFileFormat.ShownFileTypes.PFS0; - Ui.ShownFileTypes.XCI.Value = configurationFileFormat.ShownFileTypes.XCI; - Ui.ShownFileTypes.NCA.Value = configurationFileFormat.ShownFileTypes.NCA; - Ui.ShownFileTypes.NRO.Value = configurationFileFormat.ShownFileTypes.NRO; - Ui.ShownFileTypes.NSO.Value = configurationFileFormat.ShownFileTypes.NSO; - Ui.EnableCustomTheme.Value = configurationFileFormat.EnableCustomTheme; - Ui.LanguageCode.Value = configurationFileFormat.LanguageCode; - Ui.CustomThemePath.Value = configurationFileFormat.CustomThemePath; - Ui.BaseStyle.Value = configurationFileFormat.BaseStyle; - Ui.GameListViewMode.Value = configurationFileFormat.GameListViewMode; - Ui.ShowNames.Value = configurationFileFormat.ShowNames; - Ui.IsAscendingOrder.Value = configurationFileFormat.IsAscendingOrder; - Ui.GridSize.Value = configurationFileFormat.GridSize; - Ui.ApplicationSort.Value = configurationFileFormat.ApplicationSort; - Ui.StartFullscreen.Value = configurationFileFormat.StartFullscreen; - Ui.ShowConsole.Value = configurationFileFormat.ShowConsole; - Ui.WindowStartup.WindowSizeWidth.Value = configurationFileFormat.WindowStartup.WindowSizeWidth; - Ui.WindowStartup.WindowSizeHeight.Value = configurationFileFormat.WindowStartup.WindowSizeHeight; - Ui.WindowStartup.WindowPositionX.Value = configurationFileFormat.WindowStartup.WindowPositionX; - Ui.WindowStartup.WindowPositionY.Value = configurationFileFormat.WindowStartup.WindowPositionY; - Ui.WindowStartup.WindowMaximized.Value = configurationFileFormat.WindowStartup.WindowMaximized; + UI.GuiColumns.FavColumn.Value = configurationFileFormat.GuiColumns.FavColumn; + UI.GuiColumns.IconColumn.Value = configurationFileFormat.GuiColumns.IconColumn; + UI.GuiColumns.AppColumn.Value = configurationFileFormat.GuiColumns.AppColumn; + UI.GuiColumns.DevColumn.Value = configurationFileFormat.GuiColumns.DevColumn; + UI.GuiColumns.VersionColumn.Value = configurationFileFormat.GuiColumns.VersionColumn; + UI.GuiColumns.TimePlayedColumn.Value = configurationFileFormat.GuiColumns.TimePlayedColumn; + UI.GuiColumns.LastPlayedColumn.Value = configurationFileFormat.GuiColumns.LastPlayedColumn; + UI.GuiColumns.FileExtColumn.Value = configurationFileFormat.GuiColumns.FileExtColumn; + UI.GuiColumns.FileSizeColumn.Value = configurationFileFormat.GuiColumns.FileSizeColumn; + UI.GuiColumns.PathColumn.Value = configurationFileFormat.GuiColumns.PathColumn; + UI.ColumnSort.SortColumnId.Value = configurationFileFormat.ColumnSort.SortColumnId; + UI.ColumnSort.SortAscending.Value = configurationFileFormat.ColumnSort.SortAscending; + UI.GameDirs.Value = configurationFileFormat.GameDirs; + UI.ShownFileTypes.NSP.Value = configurationFileFormat.ShownFileTypes.NSP; + UI.ShownFileTypes.PFS0.Value = configurationFileFormat.ShownFileTypes.PFS0; + UI.ShownFileTypes.XCI.Value = configurationFileFormat.ShownFileTypes.XCI; + UI.ShownFileTypes.NCA.Value = configurationFileFormat.ShownFileTypes.NCA; + UI.ShownFileTypes.NRO.Value = configurationFileFormat.ShownFileTypes.NRO; + UI.ShownFileTypes.NSO.Value = configurationFileFormat.ShownFileTypes.NSO; + UI.EnableCustomTheme.Value = configurationFileFormat.EnableCustomTheme; + UI.LanguageCode.Value = configurationFileFormat.LanguageCode; + UI.CustomThemePath.Value = configurationFileFormat.CustomThemePath; + UI.BaseStyle.Value = configurationFileFormat.BaseStyle; + UI.GameListViewMode.Value = configurationFileFormat.GameListViewMode; + UI.ShowNames.Value = configurationFileFormat.ShowNames; + UI.IsAscendingOrder.Value = configurationFileFormat.IsAscendingOrder; + UI.GridSize.Value = configurationFileFormat.GridSize; + UI.ApplicationSort.Value = configurationFileFormat.ApplicationSort; + UI.StartFullscreen.Value = configurationFileFormat.StartFullscreen; + UI.ShowConsole.Value = configurationFileFormat.ShowConsole; + UI.WindowStartup.WindowSizeWidth.Value = configurationFileFormat.WindowStartup.WindowSizeWidth; + UI.WindowStartup.WindowSizeHeight.Value = configurationFileFormat.WindowStartup.WindowSizeHeight; + UI.WindowStartup.WindowPositionX.Value = configurationFileFormat.WindowStartup.WindowPositionX; + UI.WindowStartup.WindowPositionY.Value = configurationFileFormat.WindowStartup.WindowPositionY; + UI.WindowStartup.WindowMaximized.Value = configurationFileFormat.WindowStartup.WindowMaximized; Hid.EnableKeyboard.Value = configurationFileFormat.EnableKeyboard; Hid.EnableMouse.Value = configurationFileFormat.EnableMouse; Hid.Hotkeys.Value = configurationFileFormat.Hotkeys; diff --git a/src/Ryujinx.Ui.Common/Configuration/FileTypes.cs b/src/Ryujinx.UI.Common/Configuration/FileTypes.cs similarity index 81% rename from src/Ryujinx.Ui.Common/Configuration/FileTypes.cs rename to src/Ryujinx.UI.Common/Configuration/FileTypes.cs index 9d2f63864..1974207b6 100644 --- a/src/Ryujinx.Ui.Common/Configuration/FileTypes.cs +++ b/src/Ryujinx.UI.Common/Configuration/FileTypes.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.Ui.Common +namespace Ryujinx.UI.Common { public enum FileTypes { diff --git a/src/Ryujinx.Ui.Common/Configuration/LoggerModule.cs b/src/Ryujinx.UI.Common/Configuration/LoggerModule.cs similarity index 81% rename from src/Ryujinx.Ui.Common/Configuration/LoggerModule.cs rename to src/Ryujinx.UI.Common/Configuration/LoggerModule.cs index 54ad20dd7..9cb283593 100644 --- a/src/Ryujinx.Ui.Common/Configuration/LoggerModule.cs +++ b/src/Ryujinx.UI.Common/Configuration/LoggerModule.cs @@ -1,9 +1,11 @@ using Ryujinx.Common; +using Ryujinx.Common.Configuration; using Ryujinx.Common.Logging; using Ryujinx.Common.Logging.Targets; using System; +using System.IO; -namespace Ryujinx.Ui.Common.Configuration +namespace Ryujinx.UI.Common.Configuration { public static class LoggerModule { @@ -80,8 +82,24 @@ namespace Ryujinx.Ui.Common.Configuration { if (e.NewValue) { + string logDir = AppDataManager.LogsDirPath; + FileStream logFile = null; + + if (!string.IsNullOrEmpty(logDir)) + { + logFile = FileLogTarget.PrepareLogFile(logDir); + } + + if (logFile == null) + { + Logger.Error?.Print(LogClass.Application, "No writable log directory available. Make sure either the Logs directory, Application Data, or the Ryujinx directory is writable."); + Logger.RemoveTarget("file"); + + return; + } + Logger.AddTarget(new AsyncLogTargetWrapper( - new FileLogTarget(ReleaseInformation.GetBaseApplicationDirectory(), "file"), + new FileLogTarget("file", logFile), 1000, AsyncLogTargetOverflowAction.Block )); diff --git a/src/Ryujinx.Ui.Common/Configuration/System/Language.cs b/src/Ryujinx.UI.Common/Configuration/System/Language.cs similarity index 91% rename from src/Ryujinx.Ui.Common/Configuration/System/Language.cs rename to src/Ryujinx.UI.Common/Configuration/System/Language.cs index 72416bfe7..d1d395b00 100644 --- a/src/Ryujinx.Ui.Common/Configuration/System/Language.cs +++ b/src/Ryujinx.UI.Common/Configuration/System/Language.cs @@ -1,7 +1,7 @@ using Ryujinx.Common.Utilities; using System.Text.Json.Serialization; -namespace Ryujinx.Ui.Common.Configuration.System +namespace Ryujinx.UI.Common.Configuration.System { [JsonConverter(typeof(TypedStringEnumConverter))] public enum Language diff --git a/src/Ryujinx.Ui.Common/Configuration/System/Region.cs b/src/Ryujinx.UI.Common/Configuration/System/Region.cs similarity index 85% rename from src/Ryujinx.Ui.Common/Configuration/System/Region.cs rename to src/Ryujinx.UI.Common/Configuration/System/Region.cs index 2478b40f9..6087c70e5 100644 --- a/src/Ryujinx.Ui.Common/Configuration/System/Region.cs +++ b/src/Ryujinx.UI.Common/Configuration/System/Region.cs @@ -1,7 +1,7 @@ using Ryujinx.Common.Utilities; using System.Text.Json.Serialization; -namespace Ryujinx.Ui.Common.Configuration.System +namespace Ryujinx.UI.Common.Configuration.System { [JsonConverter(typeof(TypedStringEnumConverter))] public enum Region diff --git a/src/Ryujinx.Ui.Common/Configuration/Ui/ColumnSort.cs b/src/Ryujinx.UI.Common/Configuration/UI/ColumnSort.cs similarity index 75% rename from src/Ryujinx.Ui.Common/Configuration/Ui/ColumnSort.cs rename to src/Ryujinx.UI.Common/Configuration/UI/ColumnSort.cs index 88cf7cdac..44e98c407 100644 --- a/src/Ryujinx.Ui.Common/Configuration/Ui/ColumnSort.cs +++ b/src/Ryujinx.UI.Common/Configuration/UI/ColumnSort.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.Ui.Common.Configuration.Ui +namespace Ryujinx.UI.Common.Configuration.UI { public struct ColumnSort { diff --git a/src/Ryujinx.Ui.Common/Configuration/Ui/GuiColumns.cs b/src/Ryujinx.UI.Common/Configuration/UI/GuiColumns.cs similarity index 91% rename from src/Ryujinx.Ui.Common/Configuration/Ui/GuiColumns.cs rename to src/Ryujinx.UI.Common/Configuration/UI/GuiColumns.cs index 7e944015b..c778ef1f1 100644 --- a/src/Ryujinx.Ui.Common/Configuration/Ui/GuiColumns.cs +++ b/src/Ryujinx.UI.Common/Configuration/UI/GuiColumns.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.Ui.Common.Configuration.Ui +namespace Ryujinx.UI.Common.Configuration.UI { public struct GuiColumns { diff --git a/src/Ryujinx.Ui.Common/Configuration/Ui/ShownFileTypes.cs b/src/Ryujinx.UI.Common/Configuration/UI/ShownFileTypes.cs similarity index 86% rename from src/Ryujinx.Ui.Common/Configuration/Ui/ShownFileTypes.cs rename to src/Ryujinx.UI.Common/Configuration/UI/ShownFileTypes.cs index 1b14fd467..6c72a6930 100644 --- a/src/Ryujinx.Ui.Common/Configuration/Ui/ShownFileTypes.cs +++ b/src/Ryujinx.UI.Common/Configuration/UI/ShownFileTypes.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.Ui.Common.Configuration.Ui +namespace Ryujinx.UI.Common.Configuration.UI { public struct ShownFileTypes { diff --git a/src/Ryujinx.Ui.Common/Configuration/Ui/WindowStartup.cs b/src/Ryujinx.UI.Common/Configuration/UI/WindowStartup.cs similarity index 86% rename from src/Ryujinx.Ui.Common/Configuration/Ui/WindowStartup.cs rename to src/Ryujinx.UI.Common/Configuration/UI/WindowStartup.cs index ce0dde6aa..0df459134 100644 --- a/src/Ryujinx.Ui.Common/Configuration/Ui/WindowStartup.cs +++ b/src/Ryujinx.UI.Common/Configuration/UI/WindowStartup.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.Ui.Common.Configuration.Ui +namespace Ryujinx.UI.Common.Configuration.UI { public struct WindowStartup { diff --git a/src/Ryujinx.Ui.Common/DiscordIntegrationModule.cs b/src/Ryujinx.UI.Common/DiscordIntegrationModule.cs similarity index 97% rename from src/Ryujinx.Ui.Common/DiscordIntegrationModule.cs rename to src/Ryujinx.UI.Common/DiscordIntegrationModule.cs index edc634aa5..0b9439eaa 100644 --- a/src/Ryujinx.Ui.Common/DiscordIntegrationModule.cs +++ b/src/Ryujinx.UI.Common/DiscordIntegrationModule.cs @@ -1,8 +1,8 @@ using DiscordRPC; using Ryujinx.Common; -using Ryujinx.Ui.Common.Configuration; +using Ryujinx.UI.Common.Configuration; -namespace Ryujinx.Ui.Common +namespace Ryujinx.UI.Common { public static class DiscordIntegrationModule { diff --git a/src/Ryujinx.Ui.Common/Extensions/FileTypeExtensions.cs b/src/Ryujinx.UI.Common/Extensions/FileTypeExtensions.cs similarity index 91% rename from src/Ryujinx.Ui.Common/Extensions/FileTypeExtensions.cs rename to src/Ryujinx.UI.Common/Extensions/FileTypeExtensions.cs index c827f750e..7e71ba7a4 100644 --- a/src/Ryujinx.Ui.Common/Extensions/FileTypeExtensions.cs +++ b/src/Ryujinx.UI.Common/Extensions/FileTypeExtensions.cs @@ -1,7 +1,7 @@ using System; -using static Ryujinx.Ui.Common.Configuration.ConfigurationState.UiSection; +using static Ryujinx.UI.Common.Configuration.ConfigurationState.UISection; -namespace Ryujinx.Ui.Common +namespace Ryujinx.UI.Common { public static class FileTypesExtensions { diff --git a/src/Ryujinx.Ui.Common/Helper/CommandLineState.cs b/src/Ryujinx.UI.Common/Helper/CommandLineState.cs similarity index 98% rename from src/Ryujinx.Ui.Common/Helper/CommandLineState.cs rename to src/Ryujinx.UI.Common/Helper/CommandLineState.cs index 714cf2f0a..c3c5bd37e 100644 --- a/src/Ryujinx.Ui.Common/Helper/CommandLineState.cs +++ b/src/Ryujinx.UI.Common/Helper/CommandLineState.cs @@ -1,7 +1,7 @@ using Ryujinx.Common.Logging; using System.Collections.Generic; -namespace Ryujinx.Ui.Common.Helper +namespace Ryujinx.UI.Common.Helper { public static class CommandLineState { diff --git a/src/Ryujinx.Ui.Common/Helper/ConsoleHelper.cs b/src/Ryujinx.UI.Common/Helper/ConsoleHelper.cs similarity index 97% rename from src/Ryujinx.Ui.Common/Helper/ConsoleHelper.cs rename to src/Ryujinx.UI.Common/Helper/ConsoleHelper.cs index 65155641f..208ff5c9d 100644 --- a/src/Ryujinx.Ui.Common/Helper/ConsoleHelper.cs +++ b/src/Ryujinx.UI.Common/Helper/ConsoleHelper.cs @@ -3,7 +3,7 @@ using System; using System.Runtime.InteropServices; using System.Runtime.Versioning; -namespace Ryujinx.Ui.Common.Helper +namespace Ryujinx.UI.Common.Helper { public static partial class ConsoleHelper { diff --git a/src/Ryujinx.Ui.Common/Helper/FileAssociationHelper.cs b/src/Ryujinx.UI.Common/Helper/FileAssociationHelper.cs similarity index 97% rename from src/Ryujinx.Ui.Common/Helper/FileAssociationHelper.cs rename to src/Ryujinx.UI.Common/Helper/FileAssociationHelper.cs index 570fb91e2..7ed020319 100644 --- a/src/Ryujinx.Ui.Common/Helper/FileAssociationHelper.cs +++ b/src/Ryujinx.UI.Common/Helper/FileAssociationHelper.cs @@ -7,7 +7,7 @@ using System.IO; using System.Runtime.InteropServices; using System.Runtime.Versioning; -namespace Ryujinx.Ui.Common.Helper +namespace Ryujinx.UI.Common.Helper { public static partial class FileAssociationHelper { @@ -22,7 +22,7 @@ namespace Ryujinx.Ui.Common.Helper [LibraryImport("shell32.dll", SetLastError = true)] public static partial void SHChangeNotify(uint wEventId, uint uFlags, IntPtr dwItem1, IntPtr dwItem2); - public static bool IsTypeAssociationSupported => (OperatingSystem.IsLinux() || OperatingSystem.IsWindows()) && !ReleaseInformation.IsFlatHubBuild(); + public static bool IsTypeAssociationSupported => (OperatingSystem.IsLinux() || OperatingSystem.IsWindows()) && !ReleaseInformation.IsFlatHubBuild; [SupportedOSPlatform("linux")] private static bool AreMimeTypesRegisteredLinux() => File.Exists(Path.Combine(_mimeDbPath, "packages", "Ryujinx.xml")); @@ -34,7 +34,7 @@ namespace Ryujinx.Ui.Common.Helper if ((uninstall && AreMimeTypesRegisteredLinux()) || (!uninstall && !AreMimeTypesRegisteredLinux())) { - string mimeTypesFile = Path.Combine(ReleaseInformation.GetBaseApplicationDirectory(), "mime", "Ryujinx.xml"); + string mimeTypesFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "mime", "Ryujinx.xml"); string additionalArgs = !uninstall ? "--novendor" : ""; using Process mimeProcess = new(); diff --git a/src/Ryujinx.Ui.Common/Helper/LinuxHelper.cs b/src/Ryujinx.UI.Common/Helper/LinuxHelper.cs similarity index 98% rename from src/Ryujinx.Ui.Common/Helper/LinuxHelper.cs rename to src/Ryujinx.UI.Common/Helper/LinuxHelper.cs index bf647719a..b57793791 100644 --- a/src/Ryujinx.Ui.Common/Helper/LinuxHelper.cs +++ b/src/Ryujinx.UI.Common/Helper/LinuxHelper.cs @@ -3,7 +3,7 @@ using System.Diagnostics; using System.IO; using System.Runtime.Versioning; -namespace Ryujinx.Ui.Common.Helper +namespace Ryujinx.UI.Common.Helper { [SupportedOSPlatform("linux")] public static class LinuxHelper diff --git a/src/Ryujinx.Ui.Common/Helper/ObjectiveC.cs b/src/Ryujinx.UI.Common/Helper/ObjectiveC.cs similarity index 99% rename from src/Ryujinx.Ui.Common/Helper/ObjectiveC.cs rename to src/Ryujinx.UI.Common/Helper/ObjectiveC.cs index af8723e2f..6aba377a3 100644 --- a/src/Ryujinx.Ui.Common/Helper/ObjectiveC.cs +++ b/src/Ryujinx.UI.Common/Helper/ObjectiveC.cs @@ -2,7 +2,7 @@ using System; using System.Runtime.InteropServices; using System.Runtime.Versioning; -namespace Ryujinx.Ui.Common.Helper +namespace Ryujinx.UI.Common.Helper { [SupportedOSPlatform("macos")] public static partial class ObjectiveC diff --git a/src/Ryujinx.Ui.Common/Helper/OpenHelper.cs b/src/Ryujinx.UI.Common/Helper/OpenHelper.cs similarity index 99% rename from src/Ryujinx.Ui.Common/Helper/OpenHelper.cs rename to src/Ryujinx.UI.Common/Helper/OpenHelper.cs index 04ebbf3b0..af6170afe 100644 --- a/src/Ryujinx.Ui.Common/Helper/OpenHelper.cs +++ b/src/Ryujinx.UI.Common/Helper/OpenHelper.cs @@ -4,7 +4,7 @@ using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; -namespace Ryujinx.Ui.Common.Helper +namespace Ryujinx.UI.Common.Helper { public static partial class OpenHelper { diff --git a/src/Ryujinx.Ui.Common/Helper/SetupValidator.cs b/src/Ryujinx.UI.Common/Helper/SetupValidator.cs similarity index 99% rename from src/Ryujinx.Ui.Common/Helper/SetupValidator.cs rename to src/Ryujinx.UI.Common/Helper/SetupValidator.cs index 65c38d7b8..a954be26f 100644 --- a/src/Ryujinx.Ui.Common/Helper/SetupValidator.cs +++ b/src/Ryujinx.UI.Common/Helper/SetupValidator.cs @@ -3,7 +3,7 @@ using Ryujinx.HLE.FileSystem; using System; using System.IO; -namespace Ryujinx.Ui.Common.Helper +namespace Ryujinx.UI.Common.Helper { /// /// Ensure installation validity diff --git a/src/Ryujinx.Ui.Common/Helper/ShortcutHelper.cs b/src/Ryujinx.UI.Common/Helper/ShortcutHelper.cs similarity index 86% rename from src/Ryujinx.Ui.Common/Helper/ShortcutHelper.cs rename to src/Ryujinx.UI.Common/Helper/ShortcutHelper.cs index 97b9853db..c2085b28c 100644 --- a/src/Ryujinx.Ui.Common/Helper/ShortcutHelper.cs +++ b/src/Ryujinx.UI.Common/Helper/ShortcutHelper.cs @@ -2,17 +2,15 @@ using Ryujinx.Common; using Ryujinx.Common.Configuration; using ShellLink; using SixLabors.ImageSharp; +using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; using System; using System.Collections.Generic; -using System.Drawing; -using System.Drawing.Drawing2D; -using System.Drawing.Imaging; using System.IO; using System.Runtime.Versioning; -using Image = System.Drawing.Image; -namespace Ryujinx.Ui.Common.Helper +namespace Ryujinx.UI.Common.Helper { public static class ShortcutHelper { @@ -23,12 +21,9 @@ namespace Ryujinx.Ui.Common.Helper iconPath += ".ico"; MemoryStream iconDataStream = new(iconData); - using Image image = Image.FromStream(iconDataStream); - using Bitmap bitmap = new(128, 128); - using System.Drawing.Graphics graphic = System.Drawing.Graphics.FromImage(bitmap); - graphic.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphic.DrawImage(image, 0, 0, 128, 128); - SaveBitmapAsIcon(bitmap, iconPath); + var image = Image.Load(iconDataStream); + image.Mutate(x => x.Resize(128, 128)); + SaveBitmapAsIcon(image, iconPath); var shortcut = Shortcut.CreateShortcut(basePath, GetArgsString(applicationFilePath), iconPath, 0); shortcut.StringData.NameString = cleanedAppName; @@ -39,10 +34,10 @@ namespace Ryujinx.Ui.Common.Helper private static void CreateShortcutLinux(string applicationFilePath, byte[] iconData, string iconPath, string desktopPath, string cleanedAppName) { string basePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Ryujinx.sh"); - var desktopFile = EmbeddedResources.ReadAllText("Ryujinx.Ui.Common/shortcut-template.desktop"); + var desktopFile = EmbeddedResources.ReadAllText("Ryujinx.UI.Common/shortcut-template.desktop"); iconPath += ".png"; - var image = SixLabors.ImageSharp.Image.Load(iconData); + var image = Image.Load(iconData); image.SaveAsPng(iconPath); using StreamWriter outputFile = new(Path.Combine(desktopPath, cleanedAppName + ".desktop")); @@ -53,7 +48,8 @@ namespace Ryujinx.Ui.Common.Helper private static void CreateShortcutMacos(string appFilePath, byte[] iconData, string desktopPath, string cleanedAppName) { string basePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Ryujinx"); - var plistFile = EmbeddedResources.ReadAllText("Ryujinx.Ui.Common/shortcut-template.plist"); + var plistFile = EmbeddedResources.ReadAllText("Ryujinx.UI.Common/shortcut-template.plist"); + var shortcutScript = EmbeddedResources.ReadAllText("Ryujinx.UI.Common/shortcut-launch-script.sh"); // Macos .App folder string contentFolderPath = Path.Combine("/Applications", cleanedAppName + ".app", "Contents"); string scriptFolderPath = Path.Combine(contentFolderPath, "MacOS"); @@ -68,8 +64,7 @@ namespace Ryujinx.Ui.Common.Helper string scriptPath = Path.Combine(scriptFolderPath, ScriptName); using StreamWriter scriptFile = new(scriptPath); - scriptFile.WriteLine("#!/bin/sh"); - scriptFile.WriteLine($"{basePath} {GetArgsString(appFilePath)}"); + scriptFile.Write(shortcutScript, basePath, GetArgsString(appFilePath)); // Set execute permission FileInfo fileInfo = new(scriptPath); @@ -83,7 +78,7 @@ namespace Ryujinx.Ui.Common.Helper } const string IconName = "icon.png"; - var image = SixLabors.ImageSharp.Image.Load(iconData); + var image = Image.Load(iconData); image.SaveAsPng(Path.Combine(resourceFolderPath, IconName)); // plist file @@ -147,7 +142,7 @@ namespace Ryujinx.Ui.Common.Helper /// The source bitmap image that will be saved as an .ico file /// The location that the new .ico file will be saved too (Make sure to include '.ico' in the path). [SupportedOSPlatform("windows")] - private static void SaveBitmapAsIcon(Bitmap source, string filePath) + private static void SaveBitmapAsIcon(Image source, string filePath) { // Code Modified From https://stackoverflow.com/a/11448060/368354 by Benlitz byte[] header = { 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 32, 0, 0, 0, 0, 0, 22, 0, 0, 0 }; @@ -155,7 +150,7 @@ namespace Ryujinx.Ui.Common.Helper fs.Write(header); // Writing actual data - source.Save(fs, ImageFormat.Png); + source.Save(fs, PngFormat.Instance); // Getting data length (file length minus header) long dataLength = fs.Length - header.Length; // Write it in the correct place diff --git a/src/Ryujinx.Ui.Common/Helper/TitleHelper.cs b/src/Ryujinx.UI.Common/Helper/TitleHelper.cs similarity index 96% rename from src/Ryujinx.Ui.Common/Helper/TitleHelper.cs rename to src/Ryujinx.UI.Common/Helper/TitleHelper.cs index 089b52154..8b47ac38b 100644 --- a/src/Ryujinx.Ui.Common/Helper/TitleHelper.cs +++ b/src/Ryujinx.UI.Common/Helper/TitleHelper.cs @@ -1,7 +1,7 @@ using Ryujinx.HLE.Loaders.Processes; using System; -namespace Ryujinx.Ui.Common.Helper +namespace Ryujinx.UI.Common.Helper { public static class TitleHelper { diff --git a/src/Ryujinx.Ui.Common/Helper/ValueFormatUtils.cs b/src/Ryujinx.UI.Common/Helper/ValueFormatUtils.cs similarity index 99% rename from src/Ryujinx.Ui.Common/Helper/ValueFormatUtils.cs rename to src/Ryujinx.UI.Common/Helper/ValueFormatUtils.cs index b1597a7cc..8ea3e721f 100644 --- a/src/Ryujinx.Ui.Common/Helper/ValueFormatUtils.cs +++ b/src/Ryujinx.UI.Common/Helper/ValueFormatUtils.cs @@ -2,7 +2,7 @@ using System; using System.Globalization; using System.Linq; -namespace Ryujinx.Ui.Common.Helper +namespace Ryujinx.UI.Common.Helper { public static class ValueFormatUtils { diff --git a/src/Ryujinx.Ui.Common/Models/Amiibo/AmiiboApi.cs b/src/Ryujinx.UI.Common/Models/Amiibo/AmiiboApi.cs similarity index 97% rename from src/Ryujinx.Ui.Common/Models/Amiibo/AmiiboApi.cs rename to src/Ryujinx.UI.Common/Models/Amiibo/AmiiboApi.cs index ff0b80c46..7989f0f1a 100644 --- a/src/Ryujinx.Ui.Common/Models/Amiibo/AmiiboApi.cs +++ b/src/Ryujinx.UI.Common/Models/Amiibo/AmiiboApi.cs @@ -2,7 +2,7 @@ using System; using System.Collections.Generic; using System.Text.Json.Serialization; -namespace Ryujinx.Ui.Common.Models.Amiibo +namespace Ryujinx.UI.Common.Models.Amiibo { public struct AmiiboApi : IEquatable { diff --git a/src/Ryujinx.Ui.Common/Models/Amiibo/AmiiboApiGamesSwitch.cs b/src/Ryujinx.UI.Common/Models/Amiibo/AmiiboApiGamesSwitch.cs similarity index 90% rename from src/Ryujinx.Ui.Common/Models/Amiibo/AmiiboApiGamesSwitch.cs rename to src/Ryujinx.UI.Common/Models/Amiibo/AmiiboApiGamesSwitch.cs index 3c62b7cc4..40e635bf0 100644 --- a/src/Ryujinx.Ui.Common/Models/Amiibo/AmiiboApiGamesSwitch.cs +++ b/src/Ryujinx.UI.Common/Models/Amiibo/AmiiboApiGamesSwitch.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using System.Text.Json.Serialization; -namespace Ryujinx.Ui.Common.Models.Amiibo +namespace Ryujinx.UI.Common.Models.Amiibo { public class AmiiboApiGamesSwitch { diff --git a/src/Ryujinx.Ui.Common/Models/Amiibo/AmiiboApiUsage.cs b/src/Ryujinx.UI.Common/Models/Amiibo/AmiiboApiUsage.cs similarity index 85% rename from src/Ryujinx.Ui.Common/Models/Amiibo/AmiiboApiUsage.cs rename to src/Ryujinx.UI.Common/Models/Amiibo/AmiiboApiUsage.cs index 3c774fd56..4f8d292b1 100644 --- a/src/Ryujinx.Ui.Common/Models/Amiibo/AmiiboApiUsage.cs +++ b/src/Ryujinx.UI.Common/Models/Amiibo/AmiiboApiUsage.cs @@ -1,6 +1,6 @@ using System.Text.Json.Serialization; -namespace Ryujinx.Ui.Common.Models.Amiibo +namespace Ryujinx.UI.Common.Models.Amiibo { public class AmiiboApiUsage { diff --git a/src/Ryujinx.Ui.Common/Models/Amiibo/AmiiboJson.cs b/src/Ryujinx.UI.Common/Models/Amiibo/AmiiboJson.cs similarity index 88% rename from src/Ryujinx.Ui.Common/Models/Amiibo/AmiiboJson.cs rename to src/Ryujinx.UI.Common/Models/Amiibo/AmiiboJson.cs index c9d91c50a..15083f505 100644 --- a/src/Ryujinx.Ui.Common/Models/Amiibo/AmiiboJson.cs +++ b/src/Ryujinx.UI.Common/Models/Amiibo/AmiiboJson.cs @@ -2,7 +2,7 @@ using System; using System.Collections.Generic; using System.Text.Json.Serialization; -namespace Ryujinx.Ui.Common.Models.Amiibo +namespace Ryujinx.UI.Common.Models.Amiibo { public struct AmiiboJson { diff --git a/src/Ryujinx.Ui.Common/Models/Amiibo/AmiiboJsonSerializerContext.cs b/src/Ryujinx.UI.Common/Models/Amiibo/AmiiboJsonSerializerContext.cs similarity index 80% rename from src/Ryujinx.Ui.Common/Models/Amiibo/AmiiboJsonSerializerContext.cs rename to src/Ryujinx.UI.Common/Models/Amiibo/AmiiboJsonSerializerContext.cs index 4906c6524..bc3f1303c 100644 --- a/src/Ryujinx.Ui.Common/Models/Amiibo/AmiiboJsonSerializerContext.cs +++ b/src/Ryujinx.UI.Common/Models/Amiibo/AmiiboJsonSerializerContext.cs @@ -1,6 +1,6 @@ using System.Text.Json.Serialization; -namespace Ryujinx.Ui.Common.Models.Amiibo +namespace Ryujinx.UI.Common.Models.Amiibo { [JsonSerializable(typeof(AmiiboJson))] public partial class AmiiboJsonSerializerContext : JsonSerializerContext diff --git a/src/Ryujinx.Ui.Common/Models/Github/GithubReleaseAssetJsonResponse.cs b/src/Ryujinx.UI.Common/Models/Github/GithubReleaseAssetJsonResponse.cs similarity index 82% rename from src/Ryujinx.Ui.Common/Models/Github/GithubReleaseAssetJsonResponse.cs rename to src/Ryujinx.UI.Common/Models/Github/GithubReleaseAssetJsonResponse.cs index 67d238d24..8f528dc0b 100644 --- a/src/Ryujinx.Ui.Common/Models/Github/GithubReleaseAssetJsonResponse.cs +++ b/src/Ryujinx.UI.Common/Models/Github/GithubReleaseAssetJsonResponse.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.Ui.Common.Models.Github +namespace Ryujinx.UI.Common.Models.Github { public class GithubReleaseAssetJsonResponse { diff --git a/src/Ryujinx.Ui.Common/Models/Github/GithubReleasesJsonResponse.cs b/src/Ryujinx.UI.Common/Models/Github/GithubReleasesJsonResponse.cs similarity index 83% rename from src/Ryujinx.Ui.Common/Models/Github/GithubReleasesJsonResponse.cs rename to src/Ryujinx.UI.Common/Models/Github/GithubReleasesJsonResponse.cs index 0f83e32cc..0250e1094 100644 --- a/src/Ryujinx.Ui.Common/Models/Github/GithubReleasesJsonResponse.cs +++ b/src/Ryujinx.UI.Common/Models/Github/GithubReleasesJsonResponse.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; -namespace Ryujinx.Ui.Common.Models.Github +namespace Ryujinx.UI.Common.Models.Github { public class GithubReleasesJsonResponse { diff --git a/src/Ryujinx.Ui.Common/Models/Github/GithubReleasesJsonSerializerContext.cs b/src/Ryujinx.UI.Common/Models/Github/GithubReleasesJsonSerializerContext.cs similarity index 85% rename from src/Ryujinx.Ui.Common/Models/Github/GithubReleasesJsonSerializerContext.cs rename to src/Ryujinx.UI.Common/Models/Github/GithubReleasesJsonSerializerContext.cs index 8a19277b3..71864257c 100644 --- a/src/Ryujinx.Ui.Common/Models/Github/GithubReleasesJsonSerializerContext.cs +++ b/src/Ryujinx.UI.Common/Models/Github/GithubReleasesJsonSerializerContext.cs @@ -1,6 +1,6 @@ using System.Text.Json.Serialization; -namespace Ryujinx.Ui.Common.Models.Github +namespace Ryujinx.UI.Common.Models.Github { [JsonSerializable(typeof(GithubReleasesJsonResponse), GenerationMode = JsonSourceGenerationMode.Metadata)] public partial class GithubReleasesJsonSerializerContext : JsonSerializerContext diff --git a/src/Ryujinx.Ui.Common/Resources/Controller_JoyConLeft.svg b/src/Ryujinx.UI.Common/Resources/Controller_JoyConLeft.svg similarity index 100% rename from src/Ryujinx.Ui.Common/Resources/Controller_JoyConLeft.svg rename to src/Ryujinx.UI.Common/Resources/Controller_JoyConLeft.svg diff --git a/src/Ryujinx.Ui.Common/Resources/Controller_JoyConPair.svg b/src/Ryujinx.UI.Common/Resources/Controller_JoyConPair.svg similarity index 100% rename from src/Ryujinx.Ui.Common/Resources/Controller_JoyConPair.svg rename to src/Ryujinx.UI.Common/Resources/Controller_JoyConPair.svg diff --git a/src/Ryujinx.Ui.Common/Resources/Controller_JoyConRight.svg b/src/Ryujinx.UI.Common/Resources/Controller_JoyConRight.svg similarity index 100% rename from src/Ryujinx.Ui.Common/Resources/Controller_JoyConRight.svg rename to src/Ryujinx.UI.Common/Resources/Controller_JoyConRight.svg diff --git a/src/Ryujinx.Ui.Common/Resources/Controller_ProCon.svg b/src/Ryujinx.UI.Common/Resources/Controller_ProCon.svg similarity index 100% rename from src/Ryujinx.Ui.Common/Resources/Controller_ProCon.svg rename to src/Ryujinx.UI.Common/Resources/Controller_ProCon.svg diff --git a/src/Ryujinx.Ui.Common/Resources/Icon_NCA.png b/src/Ryujinx.UI.Common/Resources/Icon_NCA.png similarity index 100% rename from src/Ryujinx.Ui.Common/Resources/Icon_NCA.png rename to src/Ryujinx.UI.Common/Resources/Icon_NCA.png diff --git a/src/Ryujinx.Ui.Common/Resources/Icon_NRO.png b/src/Ryujinx.UI.Common/Resources/Icon_NRO.png similarity index 100% rename from src/Ryujinx.Ui.Common/Resources/Icon_NRO.png rename to src/Ryujinx.UI.Common/Resources/Icon_NRO.png diff --git a/src/Ryujinx.Ui.Common/Resources/Icon_NSO.png b/src/Ryujinx.UI.Common/Resources/Icon_NSO.png similarity index 100% rename from src/Ryujinx.Ui.Common/Resources/Icon_NSO.png rename to src/Ryujinx.UI.Common/Resources/Icon_NSO.png diff --git a/src/Ryujinx.Ui.Common/Resources/Icon_NSP.png b/src/Ryujinx.UI.Common/Resources/Icon_NSP.png similarity index 100% rename from src/Ryujinx.Ui.Common/Resources/Icon_NSP.png rename to src/Ryujinx.UI.Common/Resources/Icon_NSP.png diff --git a/src/Ryujinx.Ui.Common/Resources/Icon_XCI.png b/src/Ryujinx.UI.Common/Resources/Icon_XCI.png similarity index 100% rename from src/Ryujinx.Ui.Common/Resources/Icon_XCI.png rename to src/Ryujinx.UI.Common/Resources/Icon_XCI.png diff --git a/src/Ryujinx.Ui.Common/Resources/Logo_Amiibo.png b/src/Ryujinx.UI.Common/Resources/Logo_Amiibo.png similarity index 100% rename from src/Ryujinx.Ui.Common/Resources/Logo_Amiibo.png rename to src/Ryujinx.UI.Common/Resources/Logo_Amiibo.png diff --git a/src/Ryujinx.Ui.Common/Resources/Logo_Discord_Dark.png b/src/Ryujinx.UI.Common/Resources/Logo_Discord_Dark.png similarity index 100% rename from src/Ryujinx.Ui.Common/Resources/Logo_Discord_Dark.png rename to src/Ryujinx.UI.Common/Resources/Logo_Discord_Dark.png diff --git a/src/Ryujinx.Ui.Common/Resources/Logo_Discord_Light.png b/src/Ryujinx.UI.Common/Resources/Logo_Discord_Light.png similarity index 100% rename from src/Ryujinx.Ui.Common/Resources/Logo_Discord_Light.png rename to src/Ryujinx.UI.Common/Resources/Logo_Discord_Light.png diff --git a/src/Ryujinx.Ui.Common/Resources/Logo_GitHub_Dark.png b/src/Ryujinx.UI.Common/Resources/Logo_GitHub_Dark.png similarity index 100% rename from src/Ryujinx.Ui.Common/Resources/Logo_GitHub_Dark.png rename to src/Ryujinx.UI.Common/Resources/Logo_GitHub_Dark.png diff --git a/src/Ryujinx.Ui.Common/Resources/Logo_GitHub_Light.png b/src/Ryujinx.UI.Common/Resources/Logo_GitHub_Light.png similarity index 100% rename from src/Ryujinx.Ui.Common/Resources/Logo_GitHub_Light.png rename to src/Ryujinx.UI.Common/Resources/Logo_GitHub_Light.png diff --git a/src/Ryujinx.Ui.Common/Resources/Logo_Patreon_Dark.png b/src/Ryujinx.UI.Common/Resources/Logo_Patreon_Dark.png similarity index 100% rename from src/Ryujinx.Ui.Common/Resources/Logo_Patreon_Dark.png rename to src/Ryujinx.UI.Common/Resources/Logo_Patreon_Dark.png diff --git a/src/Ryujinx.Ui.Common/Resources/Logo_Patreon_Light.png b/src/Ryujinx.UI.Common/Resources/Logo_Patreon_Light.png similarity index 100% rename from src/Ryujinx.Ui.Common/Resources/Logo_Patreon_Light.png rename to src/Ryujinx.UI.Common/Resources/Logo_Patreon_Light.png diff --git a/src/Ryujinx.Ui.Common/Resources/Logo_Ryujinx.png b/src/Ryujinx.UI.Common/Resources/Logo_Ryujinx.png similarity index 100% rename from src/Ryujinx.Ui.Common/Resources/Logo_Ryujinx.png rename to src/Ryujinx.UI.Common/Resources/Logo_Ryujinx.png diff --git a/src/Ryujinx.Ui.Common/Resources/Logo_Twitter_Dark.png b/src/Ryujinx.UI.Common/Resources/Logo_Twitter_Dark.png similarity index 100% rename from src/Ryujinx.Ui.Common/Resources/Logo_Twitter_Dark.png rename to src/Ryujinx.UI.Common/Resources/Logo_Twitter_Dark.png diff --git a/src/Ryujinx.Ui.Common/Resources/Logo_Twitter_Light.png b/src/Ryujinx.UI.Common/Resources/Logo_Twitter_Light.png similarity index 100% rename from src/Ryujinx.Ui.Common/Resources/Logo_Twitter_Light.png rename to src/Ryujinx.UI.Common/Resources/Logo_Twitter_Light.png diff --git a/src/Ryujinx.Ui.Common/Ryujinx.Ui.Common.csproj b/src/Ryujinx.UI.Common/Ryujinx.UI.Common.csproj similarity index 94% rename from src/Ryujinx.Ui.Common/Ryujinx.Ui.Common.csproj rename to src/Ryujinx.UI.Common/Ryujinx.UI.Common.csproj index 74331fdef..387e998b0 100644 --- a/src/Ryujinx.Ui.Common/Ryujinx.Ui.Common.csproj +++ b/src/Ryujinx.UI.Common/Ryujinx.UI.Common.csproj @@ -45,18 +45,18 @@ - + + - diff --git a/src/Ryujinx.Ui.Common/SystemInfo/LinuxSystemInfo.cs b/src/Ryujinx.UI.Common/SystemInfo/LinuxSystemInfo.cs similarity index 98% rename from src/Ryujinx.Ui.Common/SystemInfo/LinuxSystemInfo.cs rename to src/Ryujinx.UI.Common/SystemInfo/LinuxSystemInfo.cs index 5f1ab5416..c7fe05a09 100644 --- a/src/Ryujinx.Ui.Common/SystemInfo/LinuxSystemInfo.cs +++ b/src/Ryujinx.UI.Common/SystemInfo/LinuxSystemInfo.cs @@ -5,7 +5,7 @@ using System.Globalization; using System.IO; using System.Runtime.Versioning; -namespace Ryujinx.Ui.Common.SystemInfo +namespace Ryujinx.UI.Common.SystemInfo { [SupportedOSPlatform("linux")] class LinuxSystemInfo : SystemInfo diff --git a/src/Ryujinx.Ui.Common/SystemInfo/MacOSSystemInfo.cs b/src/Ryujinx.UI.Common/SystemInfo/MacOSSystemInfo.cs similarity index 99% rename from src/Ryujinx.Ui.Common/SystemInfo/MacOSSystemInfo.cs rename to src/Ryujinx.UI.Common/SystemInfo/MacOSSystemInfo.cs index 3508ae3a4..36deaf35f 100644 --- a/src/Ryujinx.Ui.Common/SystemInfo/MacOSSystemInfo.cs +++ b/src/Ryujinx.UI.Common/SystemInfo/MacOSSystemInfo.cs @@ -5,7 +5,7 @@ using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text; -namespace Ryujinx.Ui.Common.SystemInfo +namespace Ryujinx.UI.Common.SystemInfo { [SupportedOSPlatform("macos")] partial class MacOSSystemInfo : SystemInfo diff --git a/src/Ryujinx.Ui.Common/SystemInfo/SystemInfo.cs b/src/Ryujinx.UI.Common/SystemInfo/SystemInfo.cs similarity index 97% rename from src/Ryujinx.Ui.Common/SystemInfo/SystemInfo.cs rename to src/Ryujinx.UI.Common/SystemInfo/SystemInfo.cs index e78db8af7..38728b9cf 100644 --- a/src/Ryujinx.Ui.Common/SystemInfo/SystemInfo.cs +++ b/src/Ryujinx.UI.Common/SystemInfo/SystemInfo.cs @@ -1,11 +1,11 @@ using Ryujinx.Common.Logging; -using Ryujinx.Ui.Common.Helper; +using Ryujinx.UI.Common.Helper; using System; using System.Runtime.InteropServices; using System.Runtime.Intrinsics.X86; using System.Text; -namespace Ryujinx.Ui.Common.SystemInfo +namespace Ryujinx.UI.Common.SystemInfo { public class SystemInfo { diff --git a/src/Ryujinx.Ui.Common/SystemInfo/WindowsSystemInfo.cs b/src/Ryujinx.UI.Common/SystemInfo/WindowsSystemInfo.cs similarity index 98% rename from src/Ryujinx.Ui.Common/SystemInfo/WindowsSystemInfo.cs rename to src/Ryujinx.UI.Common/SystemInfo/WindowsSystemInfo.cs index 9bb0fbf74..bf49c2a66 100644 --- a/src/Ryujinx.Ui.Common/SystemInfo/WindowsSystemInfo.cs +++ b/src/Ryujinx.UI.Common/SystemInfo/WindowsSystemInfo.cs @@ -4,7 +4,7 @@ using System.Management; using System.Runtime.InteropServices; using System.Runtime.Versioning; -namespace Ryujinx.Ui.Common.SystemInfo +namespace Ryujinx.UI.Common.SystemInfo { [SupportedOSPlatform("windows")] partial class WindowsSystemInfo : SystemInfo diff --git a/src/Ryujinx.Ui.Common/UserError.cs b/src/Ryujinx.UI.Common/UserError.cs similarity index 96% rename from src/Ryujinx.Ui.Common/UserError.cs rename to src/Ryujinx.UI.Common/UserError.cs index 832aae9d6..706971efa 100644 --- a/src/Ryujinx.Ui.Common/UserError.cs +++ b/src/Ryujinx.UI.Common/UserError.cs @@ -1,4 +1,4 @@ -namespace Ryujinx.Ui.Common +namespace Ryujinx.UI.Common { /// /// Represent a common error that could be reported to the user by the emulator. diff --git a/src/Ryujinx.Ui.LocaleGenerator/LocaleGenerator.cs b/src/Ryujinx.UI.LocaleGenerator/LocaleGenerator.cs similarity index 97% rename from src/Ryujinx.Ui.LocaleGenerator/LocaleGenerator.cs rename to src/Ryujinx.UI.LocaleGenerator/LocaleGenerator.cs index 27573a8fb..bb4918d55 100644 --- a/src/Ryujinx.Ui.LocaleGenerator/LocaleGenerator.cs +++ b/src/Ryujinx.UI.LocaleGenerator/LocaleGenerator.cs @@ -2,7 +2,7 @@ using Microsoft.CodeAnalysis; using System.Linq; using System.Text; -namespace Ryujinx.Ui.LocaleGenerator +namespace Ryujinx.UI.LocaleGenerator { [Generator] public class LocaleGenerator : IIncrementalGenerator diff --git a/src/Ryujinx.Ui.LocaleGenerator/Ryujinx.Ui.LocaleGenerator.csproj b/src/Ryujinx.UI.LocaleGenerator/Ryujinx.UI.LocaleGenerator.csproj similarity index 100% rename from src/Ryujinx.Ui.LocaleGenerator/Ryujinx.Ui.LocaleGenerator.csproj rename to src/Ryujinx.UI.LocaleGenerator/Ryujinx.UI.LocaleGenerator.csproj diff --git a/src/Ryujinx/Modules/Updater/UpdateDialog.cs b/src/Ryujinx/Modules/Updater/UpdateDialog.cs index 695634374..ec24cdc89 100644 --- a/src/Ryujinx/Modules/Updater/UpdateDialog.cs +++ b/src/Ryujinx/Modules/Updater/UpdateDialog.cs @@ -1,9 +1,10 @@ using Gdk; using Gtk; using Ryujinx.Common; -using Ryujinx.Ui; -using Ryujinx.Ui.Common.Configuration; -using Ryujinx.Ui.Common.Helper; +using Ryujinx.Common.Configuration; +using Ryujinx.UI; +using Ryujinx.UI.Common.Configuration; +using Ryujinx.UI.Common.Helper; using System; using System.Diagnostics; using System.Reflection; @@ -33,7 +34,7 @@ namespace Ryujinx.Modules _mainWindow = mainWindow; _buildUrl = buildUrl; - Icon = new Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png"); + Icon = new Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.UI.Common.Resources.Logo_Ryujinx.png"); MainText.Text = "Do you want to update Ryujinx to the latest version?"; SecondaryText.Text = $"{Program.Version} -> {newVersion}"; @@ -52,7 +53,7 @@ namespace Ryujinx.Modules ProcessStartInfo processStart = new(ryuName) { UseShellExecute = true, - WorkingDirectory = ReleaseInformation.GetBaseApplicationDirectory(), + WorkingDirectory = AppDomain.CurrentDomain.BaseDirectory }; foreach (string argument in CommandLineState.Arguments) diff --git a/src/Ryujinx/Modules/Updater/Updater.cs b/src/Ryujinx/Modules/Updater/Updater.cs index f8ce4c0b9..16fbc36ae 100644 --- a/src/Ryujinx/Modules/Updater/Updater.cs +++ b/src/Ryujinx/Modules/Updater/Updater.cs @@ -5,9 +5,9 @@ using ICSharpCode.SharpZipLib.Zip; using Ryujinx.Common; using Ryujinx.Common.Logging; using Ryujinx.Common.Utilities; -using Ryujinx.Ui; -using Ryujinx.Ui.Common.Models.Github; -using Ryujinx.Ui.Widgets; +using Ryujinx.UI; +using Ryujinx.UI.Common.Models.Github; +using Ryujinx.UI.Widgets; using System; using System.Collections.Generic; using System.IO; @@ -532,7 +532,7 @@ namespace Ryujinx.Modules return false; } - if (Program.Version.Contains("dirty") || !ReleaseInformation.IsValid()) + if (Program.Version.Contains("dirty") || !ReleaseInformation.IsValid) { if (showWarnings) { @@ -546,7 +546,7 @@ namespace Ryujinx.Modules #else if (showWarnings) { - if (ReleaseInformation.IsFlatHubBuild()) + if (ReleaseInformation.IsFlatHubBuild) { GtkDialog.CreateWarningDialog("Updater Disabled!", "Please update Ryujinx via FlatHub."); } diff --git a/src/Ryujinx/Program.cs b/src/Ryujinx/Program.cs index 597d00f30..1845c512e 100644 --- a/src/Ryujinx/Program.cs +++ b/src/Ryujinx/Program.cs @@ -6,12 +6,12 @@ using Ryujinx.Common.Logging; using Ryujinx.Common.SystemInterop; using Ryujinx.Modules; using Ryujinx.SDL2.Common; -using Ryujinx.Ui; -using Ryujinx.Ui.Common; -using Ryujinx.Ui.Common.Configuration; -using Ryujinx.Ui.Common.Helper; -using Ryujinx.Ui.Common.SystemInfo; -using Ryujinx.Ui.Widgets; +using Ryujinx.UI; +using Ryujinx.UI.Common; +using Ryujinx.UI.Common.Configuration; +using Ryujinx.UI.Common.Helper; +using Ryujinx.UI.Common.SystemInfo; +using Ryujinx.UI.Widgets; using SixLabors.ImageSharp.Formats.Jpeg; using System; using System.Collections.Generic; @@ -71,7 +71,7 @@ namespace Ryujinx static void Main(string[] args) { - Version = ReleaseInformation.GetVersion(); + Version = ReleaseInformation.Version; if (OperatingSystem.IsWindows() && !OperatingSystem.IsWindowsVersionAtLeast(10, 0, 17134)) { @@ -167,8 +167,8 @@ namespace Ryujinx Quality = 100, }); - string localConfigurationPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json"); - string appDataConfigurationPath = Path.Combine(AppDataManager.BaseDirPath, "Config.json"); + string localConfigurationPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ReleaseInformation.ConfigName); + string appDataConfigurationPath = Path.Combine(AppDataManager.BaseDirPath, ReleaseInformation.ConfigName); // Now load the configuration as the other subsystems are now registered ConfigurationPath = File.Exists(localConfigurationPath) diff --git a/src/Ryujinx/Ryujinx.csproj b/src/Ryujinx/Ryujinx.csproj index 9890b761b..68bf98981 100644 --- a/src/Ryujinx/Ryujinx.csproj +++ b/src/Ryujinx/Ryujinx.csproj @@ -21,11 +21,11 @@ - + - - + + @@ -45,11 +45,11 @@ - + - + Always alsoft.ini @@ -63,7 +63,7 @@ - + Always @@ -80,24 +80,24 @@ - - - - - - - + + + + + + + - - - - - - - + + + + + + + diff --git a/src/Ryujinx/Ui/Applet/ErrorAppletDialog.cs b/src/Ryujinx/UI/Applet/ErrorAppletDialog.cs similarity index 85% rename from src/Ryujinx/Ui/Applet/ErrorAppletDialog.cs rename to src/Ryujinx/UI/Applet/ErrorAppletDialog.cs index c6bcf3f28..7f8cc0e95 100644 --- a/src/Ryujinx/Ui/Applet/ErrorAppletDialog.cs +++ b/src/Ryujinx/UI/Applet/ErrorAppletDialog.cs @@ -1,14 +1,14 @@ using Gtk; -using Ryujinx.Ui.Common.Configuration; +using Ryujinx.UI.Common.Configuration; using System.Reflection; -namespace Ryujinx.Ui.Applet +namespace Ryujinx.UI.Applet { internal class ErrorAppletDialog : MessageDialog { public ErrorAppletDialog(Window parentWindow, DialogFlags dialogFlags, MessageType messageType, string[] buttons) : base(parentWindow, dialogFlags, messageType, ButtonsType.None, null) { - Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png"); + Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.UI.Common.Resources.Logo_Ryujinx.png"); int responseId = 0; diff --git a/src/Ryujinx/Ui/Applet/GtkDynamicTextInputHandler.cs b/src/Ryujinx/UI/Applet/GtkDynamicTextInputHandler.cs similarity index 97% rename from src/Ryujinx/Ui/Applet/GtkDynamicTextInputHandler.cs rename to src/Ryujinx/UI/Applet/GtkDynamicTextInputHandler.cs index 3a3da4650..0e560b789 100644 --- a/src/Ryujinx/Ui/Applet/GtkDynamicTextInputHandler.cs +++ b/src/Ryujinx/UI/Applet/GtkDynamicTextInputHandler.cs @@ -1,10 +1,10 @@ using Gtk; -using Ryujinx.HLE.Ui; +using Ryujinx.HLE.UI; using Ryujinx.Input.GTK3; -using Ryujinx.Ui.Widgets; +using Ryujinx.UI.Widgets; using System.Threading; -namespace Ryujinx.Ui.Applet +namespace Ryujinx.UI.Applet { /// /// Class that forwards key events to a GTK Entry so they can be processed into text. diff --git a/src/Ryujinx/Ui/Applet/GtkHostUiHandler.cs b/src/Ryujinx/UI/Applet/GtkHostUIHandler.cs similarity index 93% rename from src/Ryujinx/Ui/Applet/GtkHostUiHandler.cs rename to src/Ryujinx/UI/Applet/GtkHostUIHandler.cs index 241e5e6cf..1d918d21b 100644 --- a/src/Ryujinx/Ui/Applet/GtkHostUiHandler.cs +++ b/src/Ryujinx/UI/Applet/GtkHostUIHandler.cs @@ -1,27 +1,27 @@ using Gtk; using Ryujinx.HLE.HOS.Applets; using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types; -using Ryujinx.HLE.Ui; -using Ryujinx.Ui.Widgets; +using Ryujinx.HLE.UI; +using Ryujinx.UI.Widgets; using System; using System.Threading; -namespace Ryujinx.Ui.Applet +namespace Ryujinx.UI.Applet { - internal class GtkHostUiHandler : IHostUiHandler + internal class GtkHostUIHandler : IHostUIHandler { private readonly Window _parent; - public IHostUiTheme HostUiTheme { get; } + public IHostUITheme HostUITheme { get; } - public GtkHostUiHandler(Window parent) + public GtkHostUIHandler(Window parent) { _parent = parent; - HostUiTheme = new GtkHostUiTheme(parent); + HostUITheme = new GtkHostUITheme(parent); } - public bool DisplayMessageDialog(ControllerAppletUiArgs args) + public bool DisplayMessageDialog(ControllerAppletUIArgs args) { string playerCount = args.PlayerCountMin == args.PlayerCountMax ? $"exactly {args.PlayerCountMin}" : $"{args.PlayerCountMin}-{args.PlayerCountMax}"; @@ -81,7 +81,7 @@ namespace Ryujinx.Ui.Applet return okPressed; } - public bool DisplayInputDialog(SoftwareKeyboardUiArgs args, out string userText) + public bool DisplayInputDialog(SoftwareKeyboardUIArgs args, out string userText) { ManualResetEvent dialogCloseEvent = new(false); diff --git a/src/Ryujinx/Ui/Applet/GtkHostUiTheme.cs b/src/Ryujinx/UI/Applet/GtkHostUITheme.cs similarity index 96% rename from src/Ryujinx/Ui/Applet/GtkHostUiTheme.cs rename to src/Ryujinx/UI/Applet/GtkHostUITheme.cs index 1bc010591..52d1123bb 100644 --- a/src/Ryujinx/Ui/Applet/GtkHostUiTheme.cs +++ b/src/Ryujinx/UI/Applet/GtkHostUITheme.cs @@ -1,10 +1,10 @@ using Gtk; -using Ryujinx.HLE.Ui; +using Ryujinx.HLE.UI; using System.Diagnostics; -namespace Ryujinx.Ui.Applet +namespace Ryujinx.UI.Applet { - internal class GtkHostUiTheme : IHostUiTheme + internal class GtkHostUITheme : IHostUITheme { private const int RenderSurfaceWidth = 32; private const int RenderSurfaceHeight = 32; @@ -17,7 +17,7 @@ namespace Ryujinx.Ui.Applet public ThemeColor SelectionBackgroundColor { get; } public ThemeColor SelectionForegroundColor { get; } - public GtkHostUiTheme(Window parent) + public GtkHostUITheme(Window parent) { Entry entry = new(); entry.SetStateFlags(StateFlags.Selected, true); diff --git a/src/Ryujinx/Ui/Applet/SwkbdAppletDialog.cs b/src/Ryujinx/UI/Applet/SwkbdAppletDialog.cs similarity index 99% rename from src/Ryujinx/Ui/Applet/SwkbdAppletDialog.cs rename to src/Ryujinx/UI/Applet/SwkbdAppletDialog.cs index c1f3d77c1..8045da91e 100644 --- a/src/Ryujinx/Ui/Applet/SwkbdAppletDialog.cs +++ b/src/Ryujinx/UI/Applet/SwkbdAppletDialog.cs @@ -3,7 +3,7 @@ using Ryujinx.HLE.HOS.Applets.SoftwareKeyboard; using System; using System.Linq; -namespace Ryujinx.Ui.Applet +namespace Ryujinx.UI.Applet { public class SwkbdAppletDialog : MessageDialog { diff --git a/src/Ryujinx/Ui/Helper/MetalHelper.cs b/src/Ryujinx/UI/Helper/MetalHelper.cs similarity index 99% rename from src/Ryujinx/Ui/Helper/MetalHelper.cs rename to src/Ryujinx/UI/Helper/MetalHelper.cs index a7af2aed2..c2c32d3ae 100644 --- a/src/Ryujinx/Ui/Helper/MetalHelper.cs +++ b/src/Ryujinx/UI/Helper/MetalHelper.cs @@ -3,7 +3,7 @@ using System; using System.Runtime.InteropServices; using System.Runtime.Versioning; -namespace Ryujinx.Ui.Helper +namespace Ryujinx.UI.Helper { public delegate void UpdateBoundsCallbackDelegate(Window window); diff --git a/src/Ryujinx/Ui/Helper/SortHelper.cs b/src/Ryujinx/UI/Helper/SortHelper.cs similarity index 94% rename from src/Ryujinx/Ui/Helper/SortHelper.cs rename to src/Ryujinx/UI/Helper/SortHelper.cs index 4e625f922..3e3fbeaae 100644 --- a/src/Ryujinx/Ui/Helper/SortHelper.cs +++ b/src/Ryujinx/UI/Helper/SortHelper.cs @@ -1,8 +1,8 @@ using Gtk; -using Ryujinx.Ui.Common.Helper; +using Ryujinx.UI.Common.Helper; using System; -namespace Ryujinx.Ui.Helper +namespace Ryujinx.UI.Helper { static class SortHelper { diff --git a/src/Ryujinx/Ui/Helper/ThemeHelper.cs b/src/Ryujinx/UI/Helper/ThemeHelper.cs similarity index 54% rename from src/Ryujinx/Ui/Helper/ThemeHelper.cs rename to src/Ryujinx/UI/Helper/ThemeHelper.cs index 67962cb6c..e1fed1c4d 100644 --- a/src/Ryujinx/Ui/Helper/ThemeHelper.cs +++ b/src/Ryujinx/UI/Helper/ThemeHelper.cs @@ -1,33 +1,34 @@ using Gtk; +using Ryujinx.Common; using Ryujinx.Common.Logging; -using Ryujinx.Ui.Common.Configuration; +using Ryujinx.UI.Common.Configuration; using System.IO; -namespace Ryujinx.Ui.Helper +namespace Ryujinx.UI.Helper { static class ThemeHelper { public static void ApplyTheme() { - if (!ConfigurationState.Instance.Ui.EnableCustomTheme) + if (!ConfigurationState.Instance.UI.EnableCustomTheme) { return; } - if (File.Exists(ConfigurationState.Instance.Ui.CustomThemePath) && (Path.GetExtension(ConfigurationState.Instance.Ui.CustomThemePath) == ".css")) + if (File.Exists(ConfigurationState.Instance.UI.CustomThemePath) && (Path.GetExtension(ConfigurationState.Instance.UI.CustomThemePath) == ".css")) { CssProvider cssProvider = new(); - cssProvider.LoadFromPath(ConfigurationState.Instance.Ui.CustomThemePath); + cssProvider.LoadFromPath(ConfigurationState.Instance.UI.CustomThemePath); StyleContext.AddProviderForScreen(Gdk.Screen.Default, cssProvider, 800); } else { - Logger.Warning?.Print(LogClass.Application, $"The \"custom_theme_path\" section in \"Config.json\" contains an invalid path: \"{ConfigurationState.Instance.Ui.CustomThemePath}\"."); + Logger.Warning?.Print(LogClass.Application, $"The \"custom_theme_path\" section in \"{ReleaseInformation.ConfigName}\" contains an invalid path: \"{ConfigurationState.Instance.UI.CustomThemePath}\"."); - ConfigurationState.Instance.Ui.CustomThemePath.Value = ""; - ConfigurationState.Instance.Ui.EnableCustomTheme.Value = false; + ConfigurationState.Instance.UI.CustomThemePath.Value = ""; + ConfigurationState.Instance.UI.EnableCustomTheme.Value = false; ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath); } } diff --git a/src/Ryujinx/Ui/MainWindow.cs b/src/Ryujinx/UI/MainWindow.cs similarity index 93% rename from src/Ryujinx/Ui/MainWindow.cs rename to src/Ryujinx/UI/MainWindow.cs index 2a088f561..2908f1a8d 100644 --- a/src/Ryujinx/Ui/MainWindow.cs +++ b/src/Ryujinx/UI/MainWindow.cs @@ -1,4 +1,3 @@ -using ARMeilleure.Translation; using Gtk; using LibHac.Common; using LibHac.Common.Keys; @@ -27,14 +26,14 @@ using Ryujinx.Input.GTK3; using Ryujinx.Input.HLE; using Ryujinx.Input.SDL2; using Ryujinx.Modules; -using Ryujinx.Ui.App.Common; -using Ryujinx.Ui.Applet; -using Ryujinx.Ui.Common; -using Ryujinx.Ui.Common.Configuration; -using Ryujinx.Ui.Common.Helper; -using Ryujinx.Ui.Helper; -using Ryujinx.Ui.Widgets; -using Ryujinx.Ui.Windows; +using Ryujinx.UI.App.Common; +using Ryujinx.UI.Applet; +using Ryujinx.UI.Common; +using Ryujinx.UI.Common.Configuration; +using Ryujinx.UI.Common.Helper; +using Ryujinx.UI.Helper; +using Ryujinx.UI.Widgets; +using Ryujinx.UI.Windows; using Silk.NET.Vulkan; using SPB.Graphics.Vulkan; using System; @@ -46,7 +45,7 @@ using System.Threading.Tasks; using GUI = Gtk.Builder.ObjectAttribute; using ShaderCacheLoadingState = Ryujinx.Graphics.Gpu.Shader.ShaderCacheState; -namespace Ryujinx.Ui +namespace Ryujinx.UI { public class MainWindow : Window { @@ -62,7 +61,7 @@ namespace Ryujinx.Ui private WindowsMultimediaTimerResolution _windowsMultimediaTimerResolution; private readonly ApplicationLibrary _applicationLibrary; - private readonly GtkHostUiHandler _uiHandler; + private readonly GtkHostUIHandler _uiHandler; private readonly AutoResetEvent _deviceExitStatus; private readonly ListStore _tableStore; @@ -100,7 +99,7 @@ namespace Ryujinx.Ui [GUI] MenuItem _simulateWakeUpMessage; [GUI] MenuItem _scanAmiibo; [GUI] MenuItem _takeScreenshot; - [GUI] MenuItem _hideUi; + [GUI] MenuItem _hideUI; [GUI] MenuItem _fullScreen; [GUI] CheckMenuItem _startFullScreen; [GUI] CheckMenuItem _showConsole; @@ -144,7 +143,7 @@ namespace Ryujinx.Ui #pragma warning restore CS0649, IDE0044, CS0169, IDE0051 - public MainWindow() : this(new Builder("Ryujinx.Ui.MainWindow.glade")) { } + public MainWindow() : this(new Builder("Ryujinx.UI.MainWindow.glade")) { } private MainWindow(Builder builder) : base(builder.GetRawOwnedObject("_mainWin")) { @@ -155,7 +154,7 @@ namespace Ryujinx.Ui SetWindowSizePosition(); - Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png"); + Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.UI.Common.Resources.Logo_Ryujinx.png"); Title = $"Ryujinx {Program.Version}"; // Hide emulation context status bar. @@ -183,7 +182,7 @@ namespace Ryujinx.Ui // Instantiate GUI objects. _applicationLibrary = new ApplicationLibrary(_virtualFileSystem); - _uiHandler = new GtkHostUiHandler(this); + _uiHandler = new GtkHostUIHandler(this); _deviceExitStatus = new AutoResetEvent(false); WindowStateEvent += WindowStateEvent_Changed; @@ -211,24 +210,24 @@ namespace Ryujinx.Ui ConfigurationState.Instance.Multiplayer.Mode.Event += UpdateMultiplayerMode; ConfigurationState.Instance.Multiplayer.LanInterfaceId.Event += UpdateMultiplayerLanInterfaceId; - if (ConfigurationState.Instance.Ui.StartFullscreen) + if (ConfigurationState.Instance.UI.StartFullscreen) { _startFullScreen.Active = true; } - _showConsole.Active = ConfigurationState.Instance.Ui.ShowConsole.Value; + _showConsole.Active = ConfigurationState.Instance.UI.ShowConsole.Value; _showConsole.Visible = ConsoleHelper.SetConsoleWindowStateSupported; _actionMenu.Sensitive = false; _pauseEmulation.Sensitive = false; _resumeEmulation.Sensitive = false; - _nspShown.Active = ConfigurationState.Instance.Ui.ShownFileTypes.NSP.Value; - _pfs0Shown.Active = ConfigurationState.Instance.Ui.ShownFileTypes.PFS0.Value; - _xciShown.Active = ConfigurationState.Instance.Ui.ShownFileTypes.XCI.Value; - _ncaShown.Active = ConfigurationState.Instance.Ui.ShownFileTypes.NCA.Value; - _nroShown.Active = ConfigurationState.Instance.Ui.ShownFileTypes.NRO.Value; - _nsoShown.Active = ConfigurationState.Instance.Ui.ShownFileTypes.NSO.Value; + _nspShown.Active = ConfigurationState.Instance.UI.ShownFileTypes.NSP.Value; + _pfs0Shown.Active = ConfigurationState.Instance.UI.ShownFileTypes.PFS0.Value; + _xciShown.Active = ConfigurationState.Instance.UI.ShownFileTypes.XCI.Value; + _ncaShown.Active = ConfigurationState.Instance.UI.ShownFileTypes.NCA.Value; + _nroShown.Active = ConfigurationState.Instance.UI.ShownFileTypes.NRO.Value; + _nsoShown.Active = ConfigurationState.Instance.UI.ShownFileTypes.NSO.Value; _nspShown.Toggled += NSP_Shown_Toggled; _pfs0Shown.Toggled += PFS0_Shown_Toggled; @@ -239,43 +238,43 @@ namespace Ryujinx.Ui _fileTypesSubMenu.Visible = FileAssociationHelper.IsTypeAssociationSupported; - if (ConfigurationState.Instance.Ui.GuiColumns.FavColumn) + if (ConfigurationState.Instance.UI.GuiColumns.FavColumn) { _favToggle.Active = true; } - if (ConfigurationState.Instance.Ui.GuiColumns.IconColumn) + if (ConfigurationState.Instance.UI.GuiColumns.IconColumn) { _iconToggle.Active = true; } - if (ConfigurationState.Instance.Ui.GuiColumns.AppColumn) + if (ConfigurationState.Instance.UI.GuiColumns.AppColumn) { _appToggle.Active = true; } - if (ConfigurationState.Instance.Ui.GuiColumns.DevColumn) + if (ConfigurationState.Instance.UI.GuiColumns.DevColumn) { _developerToggle.Active = true; } - if (ConfigurationState.Instance.Ui.GuiColumns.VersionColumn) + if (ConfigurationState.Instance.UI.GuiColumns.VersionColumn) { _versionToggle.Active = true; } - if (ConfigurationState.Instance.Ui.GuiColumns.TimePlayedColumn) + if (ConfigurationState.Instance.UI.GuiColumns.TimePlayedColumn) { _timePlayedToggle.Active = true; } - if (ConfigurationState.Instance.Ui.GuiColumns.LastPlayedColumn) + if (ConfigurationState.Instance.UI.GuiColumns.LastPlayedColumn) { _lastPlayedToggle.Active = true; } - if (ConfigurationState.Instance.Ui.GuiColumns.FileExtColumn) + if (ConfigurationState.Instance.UI.GuiColumns.FileExtColumn) { _fileExtToggle.Active = true; } - if (ConfigurationState.Instance.Ui.GuiColumns.FileSizeColumn) + if (ConfigurationState.Instance.UI.GuiColumns.FileSizeColumn) { _fileSizeToggle.Active = true; } - if (ConfigurationState.Instance.Ui.GuiColumns.PathColumn) + if (ConfigurationState.Instance.UI.GuiColumns.PathColumn) { _pathToggle.Active = true; } @@ -308,8 +307,8 @@ namespace Ryujinx.Ui _tableStore.SetSortFunc(6, SortHelper.LastPlayedSort); _tableStore.SetSortFunc(8, SortHelper.FileSizeSort); - int columnId = ConfigurationState.Instance.Ui.ColumnSort.SortColumnId; - bool ascending = ConfigurationState.Instance.Ui.ColumnSort.SortAscending; + int columnId = ConfigurationState.Instance.UI.ColumnSort.SortColumnId; + bool ascending = ConfigurationState.Instance.UI.ColumnSort.SortAscending; _tableStore.SetSortColumnId(columnId, ascending ? SortType.Ascending : SortType.Descending); @@ -317,12 +316,12 @@ namespace Ryujinx.Ui _gameTable.SearchColumn = 2; _gameTable.SearchEqualFunc = (model, col, key, iter) => !((string)model.GetValue(iter, col)).Contains(key, StringComparison.InvariantCultureIgnoreCase); - _hideUi.Label = _hideUi.Label.Replace("SHOWUIKEY", ConfigurationState.Instance.Hid.Hotkeys.Value.ShowUi.ToString()); + _hideUI.Label = _hideUI.Label.Replace("SHOWUIKEY", ConfigurationState.Instance.Hid.Hotkeys.Value.ShowUI.ToString()); UpdateColumns(); UpdateGameTable(); - ConfigurationState.Instance.Ui.GameDirs.Event += (sender, args) => + ConfigurationState.Instance.UI.GameDirs.Event += (sender, args) => { if (args.OldValue != args.NewValue) { @@ -402,43 +401,43 @@ namespace Ryujinx.Ui CellRendererToggle favToggle = new(); favToggle.Toggled += FavToggle_Toggled; - if (ConfigurationState.Instance.Ui.GuiColumns.FavColumn) + if (ConfigurationState.Instance.UI.GuiColumns.FavColumn) { _gameTable.AppendColumn("Fav", favToggle, "active", 0); } - if (ConfigurationState.Instance.Ui.GuiColumns.IconColumn) + if (ConfigurationState.Instance.UI.GuiColumns.IconColumn) { _gameTable.AppendColumn("Icon", new CellRendererPixbuf(), "pixbuf", 1); } - if (ConfigurationState.Instance.Ui.GuiColumns.AppColumn) + if (ConfigurationState.Instance.UI.GuiColumns.AppColumn) { _gameTable.AppendColumn("Application", new CellRendererText(), "text", 2); } - if (ConfigurationState.Instance.Ui.GuiColumns.DevColumn) + if (ConfigurationState.Instance.UI.GuiColumns.DevColumn) { _gameTable.AppendColumn("Developer", new CellRendererText(), "text", 3); } - if (ConfigurationState.Instance.Ui.GuiColumns.VersionColumn) + if (ConfigurationState.Instance.UI.GuiColumns.VersionColumn) { _gameTable.AppendColumn("Version", new CellRendererText(), "text", 4); } - if (ConfigurationState.Instance.Ui.GuiColumns.TimePlayedColumn) + if (ConfigurationState.Instance.UI.GuiColumns.TimePlayedColumn) { _gameTable.AppendColumn("Time Played", new CellRendererText(), "text", 5); } - if (ConfigurationState.Instance.Ui.GuiColumns.LastPlayedColumn) + if (ConfigurationState.Instance.UI.GuiColumns.LastPlayedColumn) { _gameTable.AppendColumn("Last Played", new CellRendererText(), "text", 6); } - if (ConfigurationState.Instance.Ui.GuiColumns.FileExtColumn) + if (ConfigurationState.Instance.UI.GuiColumns.FileExtColumn) { _gameTable.AppendColumn("File Ext", new CellRendererText(), "text", 7); } - if (ConfigurationState.Instance.Ui.GuiColumns.FileSizeColumn) + if (ConfigurationState.Instance.UI.GuiColumns.FileSizeColumn) { _gameTable.AppendColumn("File Size", new CellRendererText(), "text", 8); } - if (ConfigurationState.Instance.Ui.GuiColumns.PathColumn) + if (ConfigurationState.Instance.UI.GuiColumns.PathColumn) { _gameTable.AppendColumn("Path", new CellRendererText(), "text", 9); } @@ -680,7 +679,7 @@ namespace Ryujinx.Ui return new SurfaceKHR((ulong)((VulkanRenderer)RendererWidget).CreateWindowSurface(instance.Handle)); } - private void SetupProgressUiHandlers() + private void SetupProgressUIHandlers() { if (_emulationContext.Processes.ActiveApplication.DiskCacheLoadState != null) { @@ -733,7 +732,7 @@ namespace Ryujinx.Ui Thread applicationLibraryThread = new(() => { - _applicationLibrary.LoadApplications(ConfigurationState.Instance.Ui.GameDirs, ConfigurationState.Instance.System.Language); + _applicationLibrary.LoadApplications(ConfigurationState.Instance.UI.GameDirs, ConfigurationState.Instance.System.Language); _updatingGameTable = false; }) @@ -925,14 +924,12 @@ namespace Ryujinx.Ui return; } - SetupProgressUiHandlers(); + SetupProgressUIHandlers(); _currentEmulatedGamePath = path; _deviceExitStatus.Reset(); - Translator.IsReadyForTranslation.Reset(); - Thread windowThread = new(CreateGameWindow) { Name = "GUI.WindowThread", @@ -984,7 +981,7 @@ namespace Ryujinx.Ui { ToggleExtraWidgets(false); } - else if (startFullscreen || ConfigurationState.Instance.Ui.StartFullscreen.Value) + else if (startFullscreen || ConfigurationState.Instance.UI.StartFullscreen.Value) { FullScreen_Toggled(null, null); } @@ -1246,8 +1243,8 @@ namespace Ryujinx.Ui { TreeViewColumn column = (TreeViewColumn)sender; - ConfigurationState.Instance.Ui.ColumnSort.SortColumnId.Value = column.SortColumnId; - ConfigurationState.Instance.Ui.ColumnSort.SortAscending.Value = column.SortOrder == SortType.Ascending; + ConfigurationState.Instance.UI.ColumnSort.SortColumnId.Value = column.SortColumnId; + ConfigurationState.Instance.UI.ColumnSort.SortAscending.Value = column.SortOrder == SortType.Ascending; SaveConfig(); } @@ -1379,11 +1376,11 @@ namespace Ryujinx.Ui private void OpenLogsFolder_Pressed(object sender, EventArgs args) { - string logPath = System.IO.Path.Combine(ReleaseInformation.GetBaseApplicationDirectory(), "Logs"); - - new DirectoryInfo(logPath).Create(); - - OpenHelper.OpenFolder(logPath); + string logPath = AppDataManager.GetOrCreateLogsDir(); + if (!string.IsNullOrEmpty(logPath)) + { + OpenHelper.OpenFolder(logPath); + } } private void Exit_Pressed(object sender, EventArgs args) @@ -1410,12 +1407,12 @@ namespace Ryujinx.Ui private void SetWindowSizePosition() { - DefaultWidth = ConfigurationState.Instance.Ui.WindowStartup.WindowSizeWidth; - DefaultHeight = ConfigurationState.Instance.Ui.WindowStartup.WindowSizeHeight; + DefaultWidth = ConfigurationState.Instance.UI.WindowStartup.WindowSizeWidth; + DefaultHeight = ConfigurationState.Instance.UI.WindowStartup.WindowSizeHeight; - Move(ConfigurationState.Instance.Ui.WindowStartup.WindowPositionX, ConfigurationState.Instance.Ui.WindowStartup.WindowPositionY); + Move(ConfigurationState.Instance.UI.WindowStartup.WindowPositionX, ConfigurationState.Instance.UI.WindowStartup.WindowPositionY); - if (ConfigurationState.Instance.Ui.WindowStartup.WindowMaximized) + if (ConfigurationState.Instance.UI.WindowStartup.WindowMaximized) { Maximize(); } @@ -1426,11 +1423,11 @@ namespace Ryujinx.Ui GetSize(out int windowWidth, out int windowHeight); GetPosition(out int windowXPos, out int windowYPos); - ConfigurationState.Instance.Ui.WindowStartup.WindowMaximized.Value = IsMaximized; - ConfigurationState.Instance.Ui.WindowStartup.WindowSizeWidth.Value = windowWidth; - ConfigurationState.Instance.Ui.WindowStartup.WindowSizeHeight.Value = windowHeight; - ConfigurationState.Instance.Ui.WindowStartup.WindowPositionX.Value = windowXPos; - ConfigurationState.Instance.Ui.WindowStartup.WindowPositionY.Value = windowYPos; + ConfigurationState.Instance.UI.WindowStartup.WindowMaximized.Value = IsMaximized; + ConfigurationState.Instance.UI.WindowStartup.WindowSizeWidth.Value = windowWidth; + ConfigurationState.Instance.UI.WindowStartup.WindowSizeHeight.Value = windowHeight; + ConfigurationState.Instance.UI.WindowStartup.WindowPositionX.Value = windowXPos; + ConfigurationState.Instance.UI.WindowStartup.WindowPositionY.Value = windowYPos; SaveConfig(); } @@ -1680,14 +1677,14 @@ namespace Ryujinx.Ui private void StartFullScreen_Toggled(object sender, EventArgs args) { - ConfigurationState.Instance.Ui.StartFullscreen.Value = _startFullScreen.Active; + ConfigurationState.Instance.UI.StartFullscreen.Value = _startFullScreen.Active; SaveConfig(); } private void ShowConsole_Toggled(object sender, EventArgs args) { - ConfigurationState.Instance.Ui.ShowConsole.Value = _showConsole.Active; + ConfigurationState.Instance.UI.ShowConsole.Value = _showConsole.Active; SaveConfig(); } @@ -1705,7 +1702,7 @@ namespace Ryujinx.Ui settingsWindow.Show(); } - private void HideUi_Pressed(object sender, EventArgs args) + private void HideUI_Pressed(object sender, EventArgs args) { ToggleExtraWidgets(false); } @@ -1810,7 +1807,7 @@ namespace Ryujinx.Ui private void Fav_Toggled(object sender, EventArgs args) { - ConfigurationState.Instance.Ui.GuiColumns.FavColumn.Value = _favToggle.Active; + ConfigurationState.Instance.UI.GuiColumns.FavColumn.Value = _favToggle.Active; SaveConfig(); UpdateColumns(); @@ -1818,7 +1815,7 @@ namespace Ryujinx.Ui private void Icon_Toggled(object sender, EventArgs args) { - ConfigurationState.Instance.Ui.GuiColumns.IconColumn.Value = _iconToggle.Active; + ConfigurationState.Instance.UI.GuiColumns.IconColumn.Value = _iconToggle.Active; SaveConfig(); UpdateColumns(); @@ -1826,7 +1823,7 @@ namespace Ryujinx.Ui private void App_Toggled(object sender, EventArgs args) { - ConfigurationState.Instance.Ui.GuiColumns.AppColumn.Value = _appToggle.Active; + ConfigurationState.Instance.UI.GuiColumns.AppColumn.Value = _appToggle.Active; SaveConfig(); UpdateColumns(); @@ -1834,7 +1831,7 @@ namespace Ryujinx.Ui private void Developer_Toggled(object sender, EventArgs args) { - ConfigurationState.Instance.Ui.GuiColumns.DevColumn.Value = _developerToggle.Active; + ConfigurationState.Instance.UI.GuiColumns.DevColumn.Value = _developerToggle.Active; SaveConfig(); UpdateColumns(); @@ -1842,7 +1839,7 @@ namespace Ryujinx.Ui private void Version_Toggled(object sender, EventArgs args) { - ConfigurationState.Instance.Ui.GuiColumns.VersionColumn.Value = _versionToggle.Active; + ConfigurationState.Instance.UI.GuiColumns.VersionColumn.Value = _versionToggle.Active; SaveConfig(); UpdateColumns(); @@ -1850,7 +1847,7 @@ namespace Ryujinx.Ui private void TimePlayed_Toggled(object sender, EventArgs args) { - ConfigurationState.Instance.Ui.GuiColumns.TimePlayedColumn.Value = _timePlayedToggle.Active; + ConfigurationState.Instance.UI.GuiColumns.TimePlayedColumn.Value = _timePlayedToggle.Active; SaveConfig(); UpdateColumns(); @@ -1858,7 +1855,7 @@ namespace Ryujinx.Ui private void LastPlayed_Toggled(object sender, EventArgs args) { - ConfigurationState.Instance.Ui.GuiColumns.LastPlayedColumn.Value = _lastPlayedToggle.Active; + ConfigurationState.Instance.UI.GuiColumns.LastPlayedColumn.Value = _lastPlayedToggle.Active; SaveConfig(); UpdateColumns(); @@ -1866,7 +1863,7 @@ namespace Ryujinx.Ui private void FileExt_Toggled(object sender, EventArgs args) { - ConfigurationState.Instance.Ui.GuiColumns.FileExtColumn.Value = _fileExtToggle.Active; + ConfigurationState.Instance.UI.GuiColumns.FileExtColumn.Value = _fileExtToggle.Active; SaveConfig(); UpdateColumns(); @@ -1874,7 +1871,7 @@ namespace Ryujinx.Ui private void FileSize_Toggled(object sender, EventArgs args) { - ConfigurationState.Instance.Ui.GuiColumns.FileSizeColumn.Value = _fileSizeToggle.Active; + ConfigurationState.Instance.UI.GuiColumns.FileSizeColumn.Value = _fileSizeToggle.Active; SaveConfig(); UpdateColumns(); @@ -1882,7 +1879,7 @@ namespace Ryujinx.Ui private void Path_Toggled(object sender, EventArgs args) { - ConfigurationState.Instance.Ui.GuiColumns.PathColumn.Value = _pathToggle.Active; + ConfigurationState.Instance.UI.GuiColumns.PathColumn.Value = _pathToggle.Active; SaveConfig(); UpdateColumns(); @@ -1890,7 +1887,7 @@ namespace Ryujinx.Ui private void NSP_Shown_Toggled(object sender, EventArgs args) { - ConfigurationState.Instance.Ui.ShownFileTypes.NSP.Value = _nspShown.Active; + ConfigurationState.Instance.UI.ShownFileTypes.NSP.Value = _nspShown.Active; SaveConfig(); UpdateGameTable(); @@ -1898,7 +1895,7 @@ namespace Ryujinx.Ui private void PFS0_Shown_Toggled(object sender, EventArgs args) { - ConfigurationState.Instance.Ui.ShownFileTypes.PFS0.Value = _pfs0Shown.Active; + ConfigurationState.Instance.UI.ShownFileTypes.PFS0.Value = _pfs0Shown.Active; SaveConfig(); UpdateGameTable(); @@ -1906,7 +1903,7 @@ namespace Ryujinx.Ui private void XCI_Shown_Toggled(object sender, EventArgs args) { - ConfigurationState.Instance.Ui.ShownFileTypes.XCI.Value = _xciShown.Active; + ConfigurationState.Instance.UI.ShownFileTypes.XCI.Value = _xciShown.Active; SaveConfig(); UpdateGameTable(); @@ -1914,7 +1911,7 @@ namespace Ryujinx.Ui private void NCA_Shown_Toggled(object sender, EventArgs args) { - ConfigurationState.Instance.Ui.ShownFileTypes.NCA.Value = _ncaShown.Active; + ConfigurationState.Instance.UI.ShownFileTypes.NCA.Value = _ncaShown.Active; SaveConfig(); UpdateGameTable(); @@ -1922,7 +1919,7 @@ namespace Ryujinx.Ui private void NRO_Shown_Toggled(object sender, EventArgs args) { - ConfigurationState.Instance.Ui.ShownFileTypes.NRO.Value = _nroShown.Active; + ConfigurationState.Instance.UI.ShownFileTypes.NRO.Value = _nroShown.Active; SaveConfig(); UpdateGameTable(); @@ -1930,7 +1927,7 @@ namespace Ryujinx.Ui private void NSO_Shown_Toggled(object sender, EventArgs args) { - ConfigurationState.Instance.Ui.ShownFileTypes.NSO.Value = _nsoShown.Active; + ConfigurationState.Instance.UI.ShownFileTypes.NSO.Value = _nsoShown.Active; SaveConfig(); UpdateGameTable(); diff --git a/src/Ryujinx/Ui/MainWindow.glade b/src/Ryujinx/UI/MainWindow.glade similarity index 99% rename from src/Ryujinx/Ui/MainWindow.glade rename to src/Ryujinx/UI/MainWindow.glade index 58d5d9558..d1b6872a9 100644 --- a/src/Ryujinx/Ui/MainWindow.glade +++ b/src/Ryujinx/UI/MainWindow.glade @@ -437,12 +437,12 @@ - + True False Hide UI (SHOWUIKEY to show) True - + diff --git a/src/Ryujinx/Ui/OpenGLRenderer.cs b/src/Ryujinx/UI/OpenGLRenderer.cs similarity index 96% rename from src/Ryujinx/Ui/OpenGLRenderer.cs rename to src/Ryujinx/UI/OpenGLRenderer.cs index d10445b00..1fdabc754 100644 --- a/src/Ryujinx/Ui/OpenGLRenderer.cs +++ b/src/Ryujinx/UI/OpenGLRenderer.cs @@ -12,7 +12,7 @@ using SPB.Windowing; using System; using System.Runtime.InteropServices; -namespace Ryujinx.Ui +namespace Ryujinx.UI { public partial class OpenGLRenderer : RendererWidgetBase { @@ -120,7 +120,7 @@ namespace Ryujinx.Ui } catch (ContextException e) { - Logger.Warning?.Print(LogClass.Ui, $"Failed to bind OpenGL context: {e}"); + Logger.Warning?.Print(LogClass.UI, $"Failed to bind OpenGL context: {e}"); } Device?.DisposeGpu(); @@ -133,7 +133,7 @@ namespace Ryujinx.Ui } catch (ContextException e) { - Logger.Warning?.Print(LogClass.Ui, $"Failed to unbind OpenGL context: {e}"); + Logger.Warning?.Print(LogClass.UI, $"Failed to unbind OpenGL context: {e}"); } _openGLContext?.Dispose(); diff --git a/src/Ryujinx/Ui/OpenToolkitBindingsContext.cs b/src/Ryujinx/UI/OpenToolkitBindingsContext.cs similarity index 95% rename from src/Ryujinx/Ui/OpenToolkitBindingsContext.cs rename to src/Ryujinx/UI/OpenToolkitBindingsContext.cs index 49dd5da8e..1224ccfe0 100644 --- a/src/Ryujinx/Ui/OpenToolkitBindingsContext.cs +++ b/src/Ryujinx/UI/OpenToolkitBindingsContext.cs @@ -1,7 +1,7 @@ using SPB.Graphics; using System; -namespace Ryujinx.Ui +namespace Ryujinx.UI { public class OpenToolkitBindingsContext : OpenTK.IBindingsContext { diff --git a/src/Ryujinx/Ui/RendererWidgetBase.cs b/src/Ryujinx/UI/RendererWidgetBase.cs similarity index 97% rename from src/Ryujinx/Ui/RendererWidgetBase.cs rename to src/Ryujinx/UI/RendererWidgetBase.cs index 6ae122a0a..e27d06044 100644 --- a/src/Ryujinx/Ui/RendererWidgetBase.cs +++ b/src/Ryujinx/UI/RendererWidgetBase.cs @@ -1,4 +1,3 @@ -using ARMeilleure.Translation; using Gdk; using Gtk; using Ryujinx.Common; @@ -10,9 +9,9 @@ using Ryujinx.Graphics.Gpu; using Ryujinx.Input; using Ryujinx.Input.GTK3; using Ryujinx.Input.HLE; -using Ryujinx.Ui.Common.Configuration; -using Ryujinx.Ui.Common.Helper; -using Ryujinx.Ui.Widgets; +using Ryujinx.UI.Common.Configuration; +using Ryujinx.UI.Common.Helper; +using Ryujinx.UI.Widgets; using SixLabors.ImageSharp; using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.PixelFormats; @@ -27,7 +26,7 @@ using Key = Ryujinx.Input.Key; using ScalingFilter = Ryujinx.Graphics.GAL.ScalingFilter; using Switch = Ryujinx.HLE.Switch; -namespace Ryujinx.Ui +namespace Ryujinx.UI { public abstract class RendererWidgetBase : DrawingArea { @@ -78,7 +77,7 @@ namespace Ryujinx.Ui private readonly IKeyboard _keyboardInterface; private readonly GraphicsDebugLevel _glLogLevel; private string _gpuBackendName; - private string _gpuVendorName; + private string _gpuDriverName; private bool _isMouseInClient; public RendererWidgetBase(InputManager inputManager, GraphicsDebugLevel glLogLevel) @@ -142,9 +141,9 @@ namespace Ryujinx.Ui protected abstract string GetGpuBackendName(); - private string GetGpuVendorName() + private string GetGpuDriverName() { - return Renderer.GetHardwareInfo().GpuVendor; + return Renderer.GetHardwareInfo().GpuDriver; } private void HideCursorStateChanged(object sender, ReactiveEventArgs state) @@ -444,13 +443,12 @@ namespace Ryujinx.Ui Renderer.Window.SetScalingFilterLevel(ConfigurationState.Instance.Graphics.ScalingFilterLevel.Value); _gpuBackendName = GetGpuBackendName(); - _gpuVendorName = GetGpuVendorName(); + _gpuDriverName = GetGpuDriverName(); Device.Gpu.Renderer.RunLoop(() => { Device.Gpu.SetGpuThread(); Device.Gpu.InitializeShaderCache(_gpuCancellationTokenSource.Token); - Translator.IsReadyForTranslation.Set(); Renderer.Window.ChangeVSyncMode(Device.EnableDeviceVsync); @@ -496,7 +494,7 @@ namespace Ryujinx.Ui ConfigurationState.Instance.Graphics.AspectRatio.Value.ToText(), $"Game: {Device.Statistics.GetGameFrameRate():00.00} FPS ({Device.Statistics.GetGameFrameTime():00.00} ms)", $"FIFO: {Device.Statistics.GetFifoPercent():0.00} %", - $"GPU: {_gpuVendorName}")); + $"GPU: {_gpuDriverName}")); _ticks = Math.Min(_ticks - _ticksPerFrame, _ticksPerFrame); } @@ -661,8 +659,8 @@ namespace Ryujinx.Ui Renderer.Screenshot(); } - if (currentHotkeyState.HasFlag(KeyboardHotkeyState.ShowUi) && - !_prevHotkeyState.HasFlag(KeyboardHotkeyState.ShowUi)) + if (currentHotkeyState.HasFlag(KeyboardHotkeyState.ShowUI) && + !_prevHotkeyState.HasFlag(KeyboardHotkeyState.ShowUI)) { (Toplevel as MainWindow).ToggleExtraWidgets(true); } @@ -741,7 +739,7 @@ namespace Ryujinx.Ui None = 0, ToggleVSync = 1 << 0, Screenshot = 1 << 1, - ShowUi = 1 << 2, + ShowUI = 1 << 2, Pause = 1 << 3, ToggleMute = 1 << 4, ResScaleUp = 1 << 5, @@ -764,9 +762,9 @@ namespace Ryujinx.Ui state |= KeyboardHotkeyState.Screenshot; } - if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.ShowUi)) + if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.ShowUI)) { - state |= KeyboardHotkeyState.ShowUi; + state |= KeyboardHotkeyState.ShowUI; } if (_keyboardInterface.IsPressed((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Pause)) diff --git a/src/Ryujinx/Ui/SPBOpenGLContext.cs b/src/Ryujinx/UI/SPBOpenGLContext.cs similarity index 94% rename from src/Ryujinx/Ui/SPBOpenGLContext.cs rename to src/Ryujinx/UI/SPBOpenGLContext.cs index 6f2db697a..97feb4345 100644 --- a/src/Ryujinx/Ui/SPBOpenGLContext.cs +++ b/src/Ryujinx/UI/SPBOpenGLContext.cs @@ -5,7 +5,7 @@ using SPB.Graphics.OpenGL; using SPB.Platform; using SPB.Windowing; -namespace Ryujinx.Ui +namespace Ryujinx.UI { class SPBOpenGLContext : IOpenGLContext { @@ -29,6 +29,8 @@ namespace Ryujinx.Ui _context.MakeCurrent(_window); } + public bool HasContext() => _context.IsCurrent; + public static SPBOpenGLContext CreateBackgroundContext(OpenGLContextBase sharedContext) { OpenGLContextBase context = PlatformHelper.CreateOpenGLContext(FramebufferFormat.Default, 3, 3, OpenGLContextFlags.Compat, true, sharedContext); diff --git a/src/Ryujinx/Ui/StatusUpdatedEventArgs.cs b/src/Ryujinx/UI/StatusUpdatedEventArgs.cs similarity index 97% rename from src/Ryujinx/Ui/StatusUpdatedEventArgs.cs rename to src/Ryujinx/UI/StatusUpdatedEventArgs.cs index 72e7d7f5b..db467ebfc 100644 --- a/src/Ryujinx/Ui/StatusUpdatedEventArgs.cs +++ b/src/Ryujinx/UI/StatusUpdatedEventArgs.cs @@ -1,6 +1,6 @@ using System; -namespace Ryujinx.Ui +namespace Ryujinx.UI { public class StatusUpdatedEventArgs : EventArgs { diff --git a/src/Ryujinx/Ui/VulkanRenderer.cs b/src/Ryujinx/UI/VulkanRenderer.cs similarity index 98% rename from src/Ryujinx/Ui/VulkanRenderer.cs rename to src/Ryujinx/UI/VulkanRenderer.cs index e1aae0965..eefc56999 100644 --- a/src/Ryujinx/Ui/VulkanRenderer.cs +++ b/src/Ryujinx/UI/VulkanRenderer.cs @@ -1,7 +1,7 @@ using Gdk; using Ryujinx.Common.Configuration; using Ryujinx.Input.HLE; -using Ryujinx.Ui.Helper; +using Ryujinx.UI.Helper; using SPB.Graphics.Vulkan; using SPB.Platform.Metal; using SPB.Platform.Win32; @@ -10,7 +10,7 @@ using SPB.Windowing; using System; using System.Runtime.InteropServices; -namespace Ryujinx.Ui +namespace Ryujinx.UI { public partial class VulkanRenderer : RendererWidgetBase { diff --git a/src/Ryujinx/Ui/Widgets/GameTableContextMenu.Designer.cs b/src/Ryujinx/UI/Widgets/GameTableContextMenu.Designer.cs similarity index 96% rename from src/Ryujinx/Ui/Widgets/GameTableContextMenu.Designer.cs rename to src/Ryujinx/UI/Widgets/GameTableContextMenu.Designer.cs index 734437eea..8ee1cd2f3 100644 --- a/src/Ryujinx/Ui/Widgets/GameTableContextMenu.Designer.cs +++ b/src/Ryujinx/UI/Widgets/GameTableContextMenu.Designer.cs @@ -1,6 +1,7 @@ using Gtk; +using System; -namespace Ryujinx.Ui.Widgets +namespace Ryujinx.UI.Widgets { public partial class GameTableContextMenu : Menu { @@ -193,7 +194,7 @@ namespace Ryujinx.Ui.Widgets // _createShortcutMenuItem = new MenuItem("Create Application Shortcut") { - TooltipText = "Create a Desktop Shortcut that launches the selected Application." + TooltipText = OperatingSystem.IsMacOS() ? "Create a shortcut in macOS's Applications folder that launches the selected Application" : "Create a Desktop Shortcut that launches the selected Application." }; _createShortcutMenuItem.Activated += CreateShortcut_Clicked; diff --git a/src/Ryujinx/Ui/Widgets/GameTableContextMenu.cs b/src/Ryujinx/UI/Widgets/GameTableContextMenu.cs similarity index 98% rename from src/Ryujinx/Ui/Widgets/GameTableContextMenu.cs rename to src/Ryujinx/UI/Widgets/GameTableContextMenu.cs index eb048b00d..dc0dd4c50 100644 --- a/src/Ryujinx/Ui/Widgets/GameTableContextMenu.cs +++ b/src/Ryujinx/UI/Widgets/GameTableContextMenu.cs @@ -16,10 +16,10 @@ using Ryujinx.Common.Logging; using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.HOS; using Ryujinx.HLE.HOS.Services.Account.Acc; -using Ryujinx.Ui.App.Common; -using Ryujinx.Ui.Common.Configuration; -using Ryujinx.Ui.Common.Helper; -using Ryujinx.Ui.Windows; +using Ryujinx.UI.App.Common; +using Ryujinx.UI.Common.Configuration; +using Ryujinx.UI.Common.Helper; +using Ryujinx.UI.Windows; using System; using System.Buffers; using System.Collections.Generic; @@ -28,7 +28,7 @@ using System.IO; using System.Reflection; using System.Threading; -namespace Ryujinx.Ui.Widgets +namespace Ryujinx.UI.Widgets { public partial class GameTableContextMenu : Menu { @@ -78,7 +78,7 @@ namespace Ryujinx.Ui.Widgets _extractExeFsMenuItem.Sensitive = hasNca; _extractLogoMenuItem.Sensitive = hasNca; - _createShortcutMenuItem.Sensitive = !ReleaseInformation.IsFlatHubBuild(); + _createShortcutMenuItem.Sensitive = !ReleaseInformation.IsFlatHubBuild; PopupAtPointer(null); } @@ -189,7 +189,7 @@ namespace Ryujinx.Ui.Widgets _dialog = new MessageDialog(null, DialogFlags.DestroyWithParent, MessageType.Info, ButtonsType.Cancel, null) { Title = "Ryujinx - NCA Section Extractor", - Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png"), + Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.UI.Common.Resources.Logo_Ryujinx.png"), SecondaryText = $"Extracting {ncaSectionType} section from {System.IO.Path.GetFileName(_titleFilePath)}...", WindowPosition = WindowPosition.Center, }; @@ -320,7 +320,7 @@ namespace Ryujinx.Ui.Widgets MessageDialog dialog = new(null, DialogFlags.DestroyWithParent, MessageType.Info, ButtonsType.Ok, null) { Title = "Ryujinx - NCA Section Extractor", - Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png"), + Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.UI.Common.Resources.Logo_Ryujinx.png"), SecondaryText = "Extraction completed successfully.", WindowPosition = WindowPosition.Center, }; @@ -497,7 +497,7 @@ namespace Ryujinx.Ui.Widgets private void OpenTitleModDir_Clicked(object sender, EventArgs args) { string modsBasePath = ModLoader.GetModsBasePath(); - string titleModsPath = ModLoader.GetTitleDir(modsBasePath, _titleIdText); + string titleModsPath = ModLoader.GetApplicationDir(modsBasePath, _titleIdText); OpenHelper.OpenFolder(titleModsPath); } @@ -505,7 +505,7 @@ namespace Ryujinx.Ui.Widgets private void OpenTitleSdModDir_Clicked(object sender, EventArgs args) { string sdModsBasePath = ModLoader.GetSdModsBasePath(); - string titleModsPath = ModLoader.GetTitleDir(sdModsBasePath, _titleIdText); + string titleModsPath = ModLoader.GetApplicationDir(sdModsBasePath, _titleIdText); OpenHelper.OpenFolder(titleModsPath); } diff --git a/src/Ryujinx/Ui/Widgets/GtkDialog.cs b/src/Ryujinx/UI/Widgets/GtkDialog.cs similarity index 96% rename from src/Ryujinx/Ui/Widgets/GtkDialog.cs rename to src/Ryujinx/UI/Widgets/GtkDialog.cs index 51e777fa1..567f9ad67 100644 --- a/src/Ryujinx/Ui/Widgets/GtkDialog.cs +++ b/src/Ryujinx/UI/Widgets/GtkDialog.cs @@ -1,10 +1,10 @@ using Gtk; using Ryujinx.Common.Logging; -using Ryujinx.Ui.Common.Configuration; +using Ryujinx.UI.Common.Configuration; using System.Collections.Generic; using System.Reflection; -namespace Ryujinx.Ui.Widgets +namespace Ryujinx.UI.Widgets { internal class GtkDialog : MessageDialog { @@ -14,7 +14,7 @@ namespace Ryujinx.Ui.Widgets : base(null, DialogFlags.Modal, messageType, buttonsType, null) { Title = title; - Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png"); + Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.UI.Common.Resources.Logo_Ryujinx.png"); Text = mainText; SecondaryText = secondaryText; WindowPosition = WindowPosition.Center; diff --git a/src/Ryujinx/Ui/Widgets/GtkInputDialog.cs b/src/Ryujinx/UI/Widgets/GtkInputDialog.cs similarity index 97% rename from src/Ryujinx/Ui/Widgets/GtkInputDialog.cs rename to src/Ryujinx/UI/Widgets/GtkInputDialog.cs index 622980921..fd85248b7 100644 --- a/src/Ryujinx/Ui/Widgets/GtkInputDialog.cs +++ b/src/Ryujinx/UI/Widgets/GtkInputDialog.cs @@ -1,6 +1,6 @@ using Gtk; -namespace Ryujinx.Ui.Widgets +namespace Ryujinx.UI.Widgets { public class GtkInputDialog : MessageDialog { diff --git a/src/Ryujinx/Ui/Widgets/ProfileDialog.cs b/src/Ryujinx/UI/Widgets/ProfileDialog.cs similarity index 89% rename from src/Ryujinx/Ui/Widgets/ProfileDialog.cs rename to src/Ryujinx/UI/Widgets/ProfileDialog.cs index 0731b37a1..f8aa6345f 100644 --- a/src/Ryujinx/Ui/Widgets/ProfileDialog.cs +++ b/src/Ryujinx/UI/Widgets/ProfileDialog.cs @@ -1,10 +1,10 @@ using Gtk; -using Ryujinx.Ui.Common.Configuration; +using Ryujinx.UI.Common.Configuration; using System; using System.Reflection; using GUI = Gtk.Builder.ObjectAttribute; -namespace Ryujinx.Ui.Widgets +namespace Ryujinx.UI.Widgets { public class ProfileDialog : Dialog { @@ -15,12 +15,12 @@ namespace Ryujinx.Ui.Widgets [GUI] Label _errorMessage; #pragma warning restore CS0649, IDE0044 - public ProfileDialog() : this(new Builder("Ryujinx.Ui.Widgets.ProfileDialog.glade")) { } + public ProfileDialog() : this(new Builder("Ryujinx.UI.Widgets.ProfileDialog.glade")) { } private ProfileDialog(Builder builder) : base(builder.GetRawOwnedObject("_profileDialog")) { builder.Autoconnect(this); - Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png"); + Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.UI.Common.Resources.Logo_Ryujinx.png"); } private void OkToggle_Activated(object sender, EventArgs args) diff --git a/src/Ryujinx/Ui/Widgets/ProfileDialog.glade b/src/Ryujinx/UI/Widgets/ProfileDialog.glade similarity index 100% rename from src/Ryujinx/Ui/Widgets/ProfileDialog.glade rename to src/Ryujinx/UI/Widgets/ProfileDialog.glade diff --git a/src/Ryujinx/Ui/Widgets/RawInputToTextEntry.cs b/src/Ryujinx/UI/Widgets/RawInputToTextEntry.cs similarity index 95% rename from src/Ryujinx/Ui/Widgets/RawInputToTextEntry.cs rename to src/Ryujinx/UI/Widgets/RawInputToTextEntry.cs index e82a3d492..6470790e8 100644 --- a/src/Ryujinx/Ui/Widgets/RawInputToTextEntry.cs +++ b/src/Ryujinx/UI/Widgets/RawInputToTextEntry.cs @@ -1,6 +1,6 @@ using Gtk; -namespace Ryujinx.Ui.Widgets +namespace Ryujinx.UI.Widgets { public class RawInputToTextEntry : Entry { diff --git a/src/Ryujinx/Ui/Widgets/UserErrorDialog.cs b/src/Ryujinx/UI/Widgets/UserErrorDialog.cs similarity index 97% rename from src/Ryujinx/Ui/Widgets/UserErrorDialog.cs rename to src/Ryujinx/UI/Widgets/UserErrorDialog.cs index 63a280e6d..f0b55cd8b 100644 --- a/src/Ryujinx/Ui/Widgets/UserErrorDialog.cs +++ b/src/Ryujinx/UI/Widgets/UserErrorDialog.cs @@ -1,8 +1,8 @@ using Gtk; -using Ryujinx.Ui.Common; -using Ryujinx.Ui.Common.Helper; +using Ryujinx.UI.Common; +using Ryujinx.UI.Common.Helper; -namespace Ryujinx.Ui.Widgets +namespace Ryujinx.UI.Widgets { internal class UserErrorDialog : MessageDialog { diff --git a/src/Ryujinx/Ui/Windows/AboutWindow.Designer.cs b/src/Ryujinx/UI/Windows/AboutWindow.Designer.cs similarity index 97% rename from src/Ryujinx/Ui/Windows/AboutWindow.Designer.cs rename to src/Ryujinx/UI/Windows/AboutWindow.Designer.cs index 345026334..fd912ef9a 100644 --- a/src/Ryujinx/Ui/Windows/AboutWindow.Designer.cs +++ b/src/Ryujinx/UI/Windows/AboutWindow.Designer.cs @@ -1,9 +1,9 @@ using Gtk; using Pango; -using Ryujinx.Ui.Common.Configuration; +using Ryujinx.UI.Common.Configuration; using System.Reflection; -namespace Ryujinx.Ui.Windows +namespace Ryujinx.UI.Windows { public partial class AboutWindow : Window { @@ -88,7 +88,7 @@ namespace Ryujinx.Ui.Windows // // _ryujinxLogo // - _ryujinxLogo = new Image(new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png", 100, 100)) + _ryujinxLogo = new Image(new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.UI.Common.Resources.Logo_Ryujinx.png", 100, 100)) { Margin = 10, MarginStart = 15, @@ -223,7 +223,7 @@ namespace Ryujinx.Ui.Windows // // _patreonLogo // - _patreonLogo = new Image(new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Patreon_Light.png", 30, 30)) + _patreonLogo = new Image(new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.UI.Common.Resources.Logo_Patreon_Light.png", 30, 30)) { Margin = 10, }; @@ -253,7 +253,7 @@ namespace Ryujinx.Ui.Windows // // _githubLogo // - _githubLogo = new Image(new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_GitHub_Light.png", 30, 30)) + _githubLogo = new Image(new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.UI.Common.Resources.Logo_GitHub_Light.png", 30, 30)) { Margin = 10, }; @@ -283,7 +283,7 @@ namespace Ryujinx.Ui.Windows // // _discordLogo // - _discordLogo = new Image(new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Discord_Light.png", 30, 30)) + _discordLogo = new Image(new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.UI.Common.Resources.Logo_Discord_Light.png", 30, 30)) { Margin = 10, }; @@ -313,7 +313,7 @@ namespace Ryujinx.Ui.Windows // // _twitterLogo // - _twitterLogo = new Image(new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Twitter_Light.png", 30, 30)) + _twitterLogo = new Image(new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.UI.Common.Resources.Logo_Twitter_Light.png", 30, 30)) { Margin = 10, }; diff --git a/src/Ryujinx/Ui/Windows/AboutWindow.cs b/src/Ryujinx/UI/Windows/AboutWindow.cs similarity index 95% rename from src/Ryujinx/Ui/Windows/AboutWindow.cs rename to src/Ryujinx/UI/Windows/AboutWindow.cs index ba12bb68b..f4bb533c3 100644 --- a/src/Ryujinx/Ui/Windows/AboutWindow.cs +++ b/src/Ryujinx/UI/Windows/AboutWindow.cs @@ -1,18 +1,18 @@ using Gtk; using Ryujinx.Common.Utilities; -using Ryujinx.Ui.Common.Helper; +using Ryujinx.UI.Common.Helper; using System.Net.Http; using System.Net.NetworkInformation; using System.Reflection; using System.Threading.Tasks; -namespace Ryujinx.Ui.Windows +namespace Ryujinx.UI.Windows { public partial class AboutWindow : Window { public AboutWindow() : base($"Ryujinx {Program.Version} - About") { - Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(OpenHelper)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png"); + Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(OpenHelper)), "Ryujinx.UI.Common.Resources.Logo_Ryujinx.png"); InitializeComponent(); _ = DownloadPatronsJson(); diff --git a/src/Ryujinx/Ui/Windows/AmiiboWindow.Designer.cs b/src/Ryujinx/UI/Windows/AmiiboWindow.Designer.cs similarity index 99% rename from src/Ryujinx/Ui/Windows/AmiiboWindow.Designer.cs rename to src/Ryujinx/UI/Windows/AmiiboWindow.Designer.cs index cb27c34cb..3bf73318f 100644 --- a/src/Ryujinx/Ui/Windows/AmiiboWindow.Designer.cs +++ b/src/Ryujinx/UI/Windows/AmiiboWindow.Designer.cs @@ -1,6 +1,6 @@ using Gtk; -namespace Ryujinx.Ui.Windows +namespace Ryujinx.UI.Windows { public partial class AmiiboWindow : Window { diff --git a/src/Ryujinx/Ui/Windows/AmiiboWindow.cs b/src/Ryujinx/UI/Windows/AmiiboWindow.cs similarity index 98% rename from src/Ryujinx/Ui/Windows/AmiiboWindow.cs rename to src/Ryujinx/UI/Windows/AmiiboWindow.cs index a2a5bce6f..d8c0b0c0d 100644 --- a/src/Ryujinx/Ui/Windows/AmiiboWindow.cs +++ b/src/Ryujinx/UI/Windows/AmiiboWindow.cs @@ -4,9 +4,9 @@ using Ryujinx.Common; using Ryujinx.Common.Configuration; using Ryujinx.Common.Logging; using Ryujinx.Common.Utilities; -using Ryujinx.Ui.Common.Configuration; -using Ryujinx.Ui.Common.Models.Amiibo; -using Ryujinx.Ui.Widgets; +using Ryujinx.UI.Common.Configuration; +using Ryujinx.UI.Common.Models.Amiibo; +using Ryujinx.UI.Widgets; using System; using System.Collections.Generic; using System.IO; @@ -18,7 +18,7 @@ using System.Text.Json; using System.Threading.Tasks; using Window = Gtk.Window; -namespace Ryujinx.Ui.Windows +namespace Ryujinx.UI.Windows { public partial class AmiiboWindow : Window { @@ -52,7 +52,7 @@ namespace Ryujinx.Ui.Windows public AmiiboWindow() : base($"Ryujinx {Program.Version} - Amiibo") { - Icon = new Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png"); + Icon = new Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.UI.Common.Resources.Logo_Ryujinx.png"); InitializeComponent(); @@ -66,7 +66,7 @@ namespace Ryujinx.Ui.Windows _amiiboJsonPath = System.IO.Path.Join(AppDataManager.BaseDirPath, "system", "amiibo", "Amiibo.json"); _amiiboList = new List(); - _amiiboLogoBytes = EmbeddedResources.Read("Ryujinx.Ui.Common/Resources/Logo_Amiibo.png"); + _amiiboLogoBytes = EmbeddedResources.Read("Ryujinx.UI.Common/Resources/Logo_Amiibo.png"); _amiiboImage.Pixbuf = new Pixbuf(_amiiboLogoBytes); _scanButton.Sensitive = false; diff --git a/src/Ryujinx/Ui/Windows/AvatarWindow.cs b/src/Ryujinx/UI/Windows/AvatarWindow.cs similarity index 98% rename from src/Ryujinx/Ui/Windows/AvatarWindow.cs rename to src/Ryujinx/UI/Windows/AvatarWindow.cs index 3d3ff7c3c..7cddc362b 100644 --- a/src/Ryujinx/Ui/Windows/AvatarWindow.cs +++ b/src/Ryujinx/UI/Windows/AvatarWindow.cs @@ -8,7 +8,7 @@ using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem.NcaUtils; using Ryujinx.Common.Memory; using Ryujinx.HLE.FileSystem; -using Ryujinx.Ui.Common.Configuration; +using Ryujinx.UI.Common.Configuration; using SixLabors.ImageSharp; using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.PixelFormats; @@ -20,7 +20,7 @@ using System.IO; using System.Reflection; using Image = SixLabors.ImageSharp.Image; -namespace Ryujinx.Ui.Windows +namespace Ryujinx.UI.Windows { public class AvatarWindow : Window { @@ -36,7 +36,7 @@ namespace Ryujinx.Ui.Windows public AvatarWindow() : base($"Ryujinx {Program.Version} - Manage Accounts - Avatar") { - Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png"); + Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.UI.Common.Resources.Logo_Ryujinx.png"); CanFocus = false; Resizable = false; diff --git a/src/Ryujinx/Ui/Windows/CheatWindow.cs b/src/Ryujinx/UI/Windows/CheatWindow.cs similarity index 96% rename from src/Ryujinx/Ui/Windows/CheatWindow.cs rename to src/Ryujinx/UI/Windows/CheatWindow.cs index 1eca732b2..73ee870cd 100644 --- a/src/Ryujinx/Ui/Windows/CheatWindow.cs +++ b/src/Ryujinx/UI/Windows/CheatWindow.cs @@ -1,14 +1,14 @@ using Gtk; using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.HOS; -using Ryujinx.Ui.App.Common; +using Ryujinx.UI.App.Common; using System; using System.Collections.Generic; using System.IO; using System.Linq; using GUI = Gtk.Builder.ObjectAttribute; -namespace Ryujinx.Ui.Windows +namespace Ryujinx.UI.Windows { public class CheatWindow : Window { @@ -22,7 +22,7 @@ namespace Ryujinx.Ui.Windows [GUI] Button _saveButton; #pragma warning restore CS0649, IDE0044 - public CheatWindow(VirtualFileSystem virtualFileSystem, ulong titleId, string titleName, string titlePath) : this(new Builder("Ryujinx.Ui.Windows.CheatWindow.glade"), virtualFileSystem, titleId, titleName, titlePath) { } + public CheatWindow(VirtualFileSystem virtualFileSystem, ulong titleId, string titleName, string titlePath) : this(new Builder("Ryujinx.UI.Windows.CheatWindow.glade"), virtualFileSystem, titleId, titleName, titlePath) { } private CheatWindow(Builder builder, VirtualFileSystem virtualFileSystem, ulong titleId, string titleName, string titlePath) : base(builder.GetRawOwnedObject("_cheatWindow")) { @@ -31,7 +31,7 @@ namespace Ryujinx.Ui.Windows _buildIdTextView.Buffer.Text = $"BuildId: {ApplicationData.GetApplicationBuildId(virtualFileSystem, titlePath)}"; string modsBasePath = ModLoader.GetModsBasePath(); - string titleModsPath = ModLoader.GetTitleDir(modsBasePath, titleId.ToString("X16")); + string titleModsPath = ModLoader.GetApplicationDir(modsBasePath, titleId.ToString("X16")); _enabledCheatsPath = System.IO.Path.Combine(titleModsPath, "cheats", "enabled.txt"); diff --git a/src/Ryujinx/Ui/Windows/CheatWindow.glade b/src/Ryujinx/UI/Windows/CheatWindow.glade similarity index 100% rename from src/Ryujinx/Ui/Windows/CheatWindow.glade rename to src/Ryujinx/UI/Windows/CheatWindow.glade diff --git a/src/Ryujinx/Ui/Windows/ControllerWindow.cs b/src/Ryujinx/UI/Windows/ControllerWindow.cs similarity index 99% rename from src/Ryujinx/Ui/Windows/ControllerWindow.cs rename to src/Ryujinx/UI/Windows/ControllerWindow.cs index ebf22ab60..954113443 100644 --- a/src/Ryujinx/Ui/Windows/ControllerWindow.cs +++ b/src/Ryujinx/UI/Windows/ControllerWindow.cs @@ -9,8 +9,8 @@ using Ryujinx.Common.Utilities; using Ryujinx.Input; using Ryujinx.Input.Assigner; using Ryujinx.Input.GTK3; -using Ryujinx.Ui.Common.Configuration; -using Ryujinx.Ui.Widgets; +using Ryujinx.UI.Common.Configuration; +using Ryujinx.UI.Widgets; using System; using System.Collections.Generic; using System.IO; @@ -22,7 +22,7 @@ using ConfigStickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInpu using GUI = Gtk.Builder.ObjectAttribute; using Key = Ryujinx.Common.Configuration.Hid.Key; -namespace Ryujinx.Ui.Windows +namespace Ryujinx.UI.Windows { public class ControllerWindow : Window { @@ -117,7 +117,7 @@ namespace Ryujinx.Ui.Windows private static readonly InputConfigJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions()); - public ControllerWindow(MainWindow mainWindow, PlayerIndex controllerId) : this(mainWindow, new Builder("Ryujinx.Ui.Windows.ControllerWindow.glade"), controllerId) { } + public ControllerWindow(MainWindow mainWindow, PlayerIndex controllerId) : this(mainWindow, new Builder("Ryujinx.UI.Windows.ControllerWindow.glade"), controllerId) { } private ControllerWindow(MainWindow mainWindow, Builder builder, PlayerIndex controllerId) : base(builder.GetRawOwnedObject("_controllerWin")) { @@ -127,7 +127,7 @@ namespace Ryujinx.Ui.Windows // NOTE: To get input in this window, we need to bind a custom keyboard driver instead of using the InputManager one as the main window isn't focused... _gtk3KeyboardDriver = new GTK3KeyboardDriver(this); - Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png"); + Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.UI.Common.Resources.Logo_Ryujinx.png"); builder.Autoconnect(this); @@ -377,10 +377,10 @@ namespace Ryujinx.Ui.Windows { _controllerImage.Pixbuf = _controllerType.ActiveId switch { - "ProController" => new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Controller_ProCon.svg", 400, 400), - "JoyconLeft" => new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Controller_JoyConLeft.svg", 400, 500), - "JoyconRight" => new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Controller_JoyConRight.svg", 400, 500), - _ => new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Controller_JoyConPair.svg", 400, 500), + "ProController" => new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.UI.Common.Resources.Controller_ProCon.svg", 400, 400), + "JoyconLeft" => new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.UI.Common.Resources.Controller_JoyConLeft.svg", 400, 500), + "JoyconRight" => new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.UI.Common.Resources.Controller_JoyConRight.svg", 400, 500), + _ => new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.UI.Common.Resources.Controller_JoyConPair.svg", 400, 500), }; } } diff --git a/src/Ryujinx/Ui/Windows/ControllerWindow.glade b/src/Ryujinx/UI/Windows/ControllerWindow.glade similarity index 100% rename from src/Ryujinx/Ui/Windows/ControllerWindow.glade rename to src/Ryujinx/UI/Windows/ControllerWindow.glade diff --git a/src/Ryujinx/Ui/Windows/DlcWindow.cs b/src/Ryujinx/UI/Windows/DlcWindow.cs similarity index 98% rename from src/Ryujinx/Ui/Windows/DlcWindow.cs rename to src/Ryujinx/UI/Windows/DlcWindow.cs index 9f7179467..aed1a015d 100644 --- a/src/Ryujinx/Ui/Windows/DlcWindow.cs +++ b/src/Ryujinx/UI/Windows/DlcWindow.cs @@ -9,13 +9,13 @@ using LibHac.Tools.FsSystem.NcaUtils; using Ryujinx.Common.Configuration; using Ryujinx.Common.Utilities; using Ryujinx.HLE.FileSystem; -using Ryujinx.Ui.Widgets; +using Ryujinx.UI.Widgets; using System; using System.Collections.Generic; using System.IO; using GUI = Gtk.Builder.ObjectAttribute; -namespace Ryujinx.Ui.Windows +namespace Ryujinx.UI.Windows { public class DlcWindow : Window { @@ -32,7 +32,7 @@ namespace Ryujinx.Ui.Windows [GUI] TreeSelection _dlcTreeSelection; #pragma warning restore CS0649, IDE0044 - public DlcWindow(VirtualFileSystem virtualFileSystem, string titleId, string titleName) : this(new Builder("Ryujinx.Ui.Windows.DlcWindow.glade"), virtualFileSystem, titleId, titleName) { } + public DlcWindow(VirtualFileSystem virtualFileSystem, string titleId, string titleName) : this(new Builder("Ryujinx.UI.Windows.DlcWindow.glade"), virtualFileSystem, titleId, titleName) { } private DlcWindow(Builder builder, VirtualFileSystem virtualFileSystem, string titleId, string titleName) : base(builder.GetRawOwnedObject("_dlcWindow")) { diff --git a/src/Ryujinx/Ui/Windows/DlcWindow.glade b/src/Ryujinx/UI/Windows/DlcWindow.glade similarity index 100% rename from src/Ryujinx/Ui/Windows/DlcWindow.glade rename to src/Ryujinx/UI/Windows/DlcWindow.glade diff --git a/src/Ryujinx/Ui/Windows/SettingsWindow.cs b/src/Ryujinx/UI/Windows/SettingsWindow.cs similarity index 98% rename from src/Ryujinx/Ui/Windows/SettingsWindow.cs rename to src/Ryujinx/UI/Windows/SettingsWindow.cs index dabef14dd..270a8ad4a 100644 --- a/src/Ryujinx/Ui/Windows/SettingsWindow.cs +++ b/src/Ryujinx/UI/Windows/SettingsWindow.cs @@ -9,10 +9,10 @@ using Ryujinx.Common.Configuration.Multiplayer; using Ryujinx.Common.GraphicsDriver; using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.HOS.Services.Time.TimeZone; -using Ryujinx.Ui.Common.Configuration; -using Ryujinx.Ui.Common.Configuration.System; -using Ryujinx.Ui.Helper; -using Ryujinx.Ui.Widgets; +using Ryujinx.UI.Common.Configuration; +using Ryujinx.UI.Common.Configuration.System; +using Ryujinx.UI.Helper; +using Ryujinx.UI.Widgets; using System; using System.Collections.Generic; using System.Globalization; @@ -23,7 +23,7 @@ using System.Text.RegularExpressions; using System.Threading.Tasks; using GUI = Gtk.Builder.ObjectAttribute; -namespace Ryujinx.Ui.Windows +namespace Ryujinx.UI.Windows { public class SettingsWindow : Window { @@ -120,11 +120,11 @@ namespace Ryujinx.Ui.Windows #pragma warning restore CS0649, IDE0044 - public SettingsWindow(MainWindow parent, VirtualFileSystem virtualFileSystem, ContentManager contentManager) : this(parent, new Builder("Ryujinx.Ui.Windows.SettingsWindow.glade"), virtualFileSystem, contentManager) { } + public SettingsWindow(MainWindow parent, VirtualFileSystem virtualFileSystem, ContentManager contentManager) : this(parent, new Builder("Ryujinx.UI.Windows.SettingsWindow.glade"), virtualFileSystem, contentManager) { } private SettingsWindow(MainWindow parent, Builder builder, VirtualFileSystem virtualFileSystem, ContentManager contentManager) : base(builder.GetRawOwnedObject("_settingsWin")) { - Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png"); + Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.UI.Common.Resources.Logo_Ryujinx.png"); _parent = parent; @@ -311,7 +311,7 @@ namespace Ryujinx.Ui.Windows _directMouseAccess.Click(); } - if (ConfigurationState.Instance.Ui.EnableCustomTheme) + if (ConfigurationState.Instance.UI.EnableCustomTheme) { _custThemeToggle.Click(); } @@ -366,7 +366,7 @@ namespace Ryujinx.Ui.Windows _multiLanSelect.SetActiveId(ConfigurationState.Instance.Multiplayer.LanInterfaceId.Value); _multiModeSelect.SetActiveId(ConfigurationState.Instance.Multiplayer.Mode.Value.ToString()); - _custThemePath.Buffer.Text = ConfigurationState.Instance.Ui.CustomThemePath; + _custThemePath.Buffer.Text = ConfigurationState.Instance.UI.CustomThemePath; _resScaleText.Buffer.Text = ConfigurationState.Instance.Graphics.ResScaleCustom.Value.ToString(); _scalingFilterLevel.Value = ConfigurationState.Instance.Graphics.ScalingFilterLevel.Value; _resScaleText.Visible = _resScaleCombo.ActiveId == "-1"; @@ -379,7 +379,7 @@ namespace Ryujinx.Ui.Windows _gameDirsBoxStore = new ListStore(typeof(string)); _gameDirsBox.Model = _gameDirsBoxStore; - foreach (string gameDir in ConfigurationState.Instance.Ui.GameDirs.Value) + foreach (string gameDir in ConfigurationState.Instance.UI.GameDirs.Value) { _gameDirsBoxStore.AppendValues(gameDir); } @@ -568,7 +568,7 @@ namespace Ryujinx.Ui.Windows _gameDirsBoxStore.IterNext(ref treeIter); } - ConfigurationState.Instance.Ui.GameDirs.Value = gameDirs; + ConfigurationState.Instance.UI.GameDirs.Value = gameDirs; _directoryChanged = false; } @@ -640,11 +640,11 @@ namespace Ryujinx.Ui.Windows ConfigurationState.Instance.System.IgnoreMissingServices.Value = _ignoreToggle.Active; ConfigurationState.Instance.Hid.EnableKeyboard.Value = _directKeyboardAccess.Active; ConfigurationState.Instance.Hid.EnableMouse.Value = _directMouseAccess.Active; - ConfigurationState.Instance.Ui.EnableCustomTheme.Value = _custThemeToggle.Active; + ConfigurationState.Instance.UI.EnableCustomTheme.Value = _custThemeToggle.Active; ConfigurationState.Instance.System.Language.Value = Enum.Parse(_systemLanguageSelect.ActiveId); ConfigurationState.Instance.System.Region.Value = Enum.Parse(_systemRegionSelect.ActiveId); ConfigurationState.Instance.System.SystemTimeOffset.Value = _systemTimeOffset; - ConfigurationState.Instance.Ui.CustomThemePath.Value = _custThemePath.Buffer.Text; + ConfigurationState.Instance.UI.CustomThemePath.Value = _custThemePath.Buffer.Text; ConfigurationState.Instance.Graphics.ShadersDumpPath.Value = _graphicsShadersDumpPath.Buffer.Text; ConfigurationState.Instance.System.FsGlobalAccessLogMode.Value = (int)_fsLogSpinAdjustment.Value; ConfigurationState.Instance.Graphics.MaxAnisotropy.Value = float.Parse(_anisotropy.ActiveId, CultureInfo.InvariantCulture); diff --git a/src/Ryujinx/Ui/Windows/SettingsWindow.glade b/src/Ryujinx/UI/Windows/SettingsWindow.glade similarity index 100% rename from src/Ryujinx/Ui/Windows/SettingsWindow.glade rename to src/Ryujinx/UI/Windows/SettingsWindow.glade diff --git a/src/Ryujinx/Ui/Windows/TitleUpdateWindow.cs b/src/Ryujinx/UI/Windows/TitleUpdateWindow.cs similarity index 98% rename from src/Ryujinx/Ui/Windows/TitleUpdateWindow.cs rename to src/Ryujinx/UI/Windows/TitleUpdateWindow.cs index 51918eeab..1df929336 100644 --- a/src/Ryujinx/Ui/Windows/TitleUpdateWindow.cs +++ b/src/Ryujinx/UI/Windows/TitleUpdateWindow.cs @@ -9,8 +9,8 @@ using LibHac.Tools.FsSystem.NcaUtils; using Ryujinx.Common.Configuration; using Ryujinx.Common.Utilities; using Ryujinx.HLE.FileSystem; -using Ryujinx.Ui.App.Common; -using Ryujinx.Ui.Widgets; +using Ryujinx.UI.App.Common; +using Ryujinx.UI.Widgets; using System; using System.Collections.Generic; using System.IO; @@ -18,7 +18,7 @@ using System.Linq; using GUI = Gtk.Builder.ObjectAttribute; using SpanHelpers = LibHac.Common.SpanHelpers; -namespace Ryujinx.Ui.Windows +namespace Ryujinx.UI.Windows { public class TitleUpdateWindow : Window { @@ -38,7 +38,7 @@ namespace Ryujinx.Ui.Windows [GUI] RadioButton _noUpdateRadioButton; #pragma warning restore CS0649, IDE0044 - public TitleUpdateWindow(MainWindow parent, VirtualFileSystem virtualFileSystem, string titleId, string titleName) : this(new Builder("Ryujinx.Ui.Windows.TitleUpdateWindow.glade"), parent, virtualFileSystem, titleId, titleName) { } + public TitleUpdateWindow(MainWindow parent, VirtualFileSystem virtualFileSystem, string titleId, string titleName) : this(new Builder("Ryujinx.UI.Windows.TitleUpdateWindow.glade"), parent, virtualFileSystem, titleId, titleName) { } private TitleUpdateWindow(Builder builder, MainWindow parent, VirtualFileSystem virtualFileSystem, string titleId, string titleName) : base(builder.GetRawOwnedObject("_titleUpdateWindow")) { diff --git a/src/Ryujinx/Ui/Windows/TitleUpdateWindow.glade b/src/Ryujinx/UI/Windows/TitleUpdateWindow.glade similarity index 100% rename from src/Ryujinx/Ui/Windows/TitleUpdateWindow.glade rename to src/Ryujinx/UI/Windows/TitleUpdateWindow.glade diff --git a/src/Ryujinx/Ui/Windows/UserProfilesManagerWindow.Designer.cs b/src/Ryujinx/UI/Windows/UserProfilesManagerWindow.Designer.cs similarity index 99% rename from src/Ryujinx/Ui/Windows/UserProfilesManagerWindow.Designer.cs rename to src/Ryujinx/UI/Windows/UserProfilesManagerWindow.Designer.cs index 804bd3fb0..bc5a18f95 100644 --- a/src/Ryujinx/Ui/Windows/UserProfilesManagerWindow.Designer.cs +++ b/src/Ryujinx/UI/Windows/UserProfilesManagerWindow.Designer.cs @@ -2,7 +2,7 @@ using Pango; using System; -namespace Ryujinx.Ui.Windows +namespace Ryujinx.UI.Windows { public partial class UserProfilesManagerWindow : Window { diff --git a/src/Ryujinx/Ui/Windows/UserProfilesManagerWindow.cs b/src/Ryujinx/UI/Windows/UserProfilesManagerWindow.cs similarity index 98% rename from src/Ryujinx/Ui/Windows/UserProfilesManagerWindow.cs rename to src/Ryujinx/UI/Windows/UserProfilesManagerWindow.cs index 3d503f64e..d1e5fa9fc 100644 --- a/src/Ryujinx/Ui/Windows/UserProfilesManagerWindow.cs +++ b/src/Ryujinx/UI/Windows/UserProfilesManagerWindow.cs @@ -2,8 +2,8 @@ using Gtk; using Ryujinx.Common.Memory; using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.HOS.Services.Account.Acc; -using Ryujinx.Ui.Common.Configuration; -using Ryujinx.Ui.Widgets; +using Ryujinx.UI.Common.Configuration; +using Ryujinx.UI.Widgets; using SixLabors.ImageSharp; using SixLabors.ImageSharp.Processing; using System; @@ -14,7 +14,7 @@ using System.Threading; using System.Threading.Tasks; using Image = SixLabors.ImageSharp.Image; -namespace Ryujinx.Ui.Windows +namespace Ryujinx.UI.Windows { public partial class UserProfilesManagerWindow : Window { @@ -32,7 +32,7 @@ namespace Ryujinx.Ui.Windows public UserProfilesManagerWindow(AccountManager accountManager, ContentManager contentManager, VirtualFileSystem virtualFileSystem) : base($"Ryujinx {Program.Version} - Manage User Profiles") { - Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.Ui.Common.Resources.Logo_Ryujinx.png"); + Icon = new Gdk.Pixbuf(Assembly.GetAssembly(typeof(ConfigurationState)), "Ryujinx.UI.Common.Resources.Logo_Ryujinx.png"); InitializeComponent();