Compare commits
222 Commits
Author | SHA1 | Date | |
---|---|---|---|
b994dafe7a | |||
54421760c3 | |||
88a0e720cb | |||
53cc9e0561 | |||
7defc59b9d | |||
951700fdd8 | |||
eb6430f103 | |||
80a879cb44 | |||
2197f41506 | |||
c8f9292bab | |||
0ec933a615 | |||
2135b6a51a | |||
00e35d9bf6 | |||
6dfb6ccf8c | |||
e87e8b012c | |||
e8f1ca8427 | |||
ad47bd2d4e | |||
a5ff0024fb | |||
f9661a54d2 | |||
66e7fdb871 | |||
2bb9b33da1 | |||
1080f64df9 | |||
c48a75979f | |||
842cb26ba5 | |||
e235d5e7bb | |||
ed0b10c81f | |||
f92650fcff | |||
712361f6e1 | |||
2232e4ae87 | |||
14ce9e1567 | |||
952d013c67 | |||
46c8129bf5 | |||
8cfec5de4b | |||
37b6e081da | |||
3c3bcd82fe | |||
a00c59a46c | |||
1825bd87b4 | |||
62f8ceb60b | |||
1a888ae087 | |||
84d0ca5645 | |||
31b8d413d5 | |||
6e02cac952 | |||
3a3380fa25 | |||
2d252db0a7 | |||
7f8a3541eb | |||
b34de74f81 | |||
5811d121df | |||
6eb85e846f | |||
c5bddfeab8 | |||
70ec5def9c | |||
7853faa334 | |||
b7fb474bfe | |||
2fa6413ed8 | |||
4523a73f75 | |||
f4c47f3c9a | |||
7d9a5feccb | |||
14ae4e276f | |||
3af42d6c7e | |||
bccf5e8b5a | |||
d86a116e1e | |||
4c2ab880ef | |||
bc5bb4459e | |||
55e97959b9 | |||
f7ef6364b7 | |||
b46b63e06a | |||
594246ea47 | |||
d21b403886 | |||
5afd521c5a | |||
0c66d71fe8 | |||
bdc4fa81f2 | |||
625f5fb88a | |||
2382717600 | |||
30ee70a9bc | |||
232b1012b0 | |||
e747f5cd83 | |||
8aff17a93c | |||
f2a41b7a1c | |||
c881cd2d14 | |||
68f9091870 | |||
99ffc061d3 | |||
d987cacfb7 | |||
851f56b08a | |||
b1bd6a50b5 | |||
70895bdb04 | |||
830cbf91bb | |||
9a9349f0f4 | |||
46cc7b55f0 | |||
dd8f97ab9e | |||
633c5ec330 | |||
a3e7bb8eb4 | |||
2073ba2919 | |||
d03124a992 | |||
59490d54b5 | |||
e546e5933f | |||
0c87bf9ea4 | |||
9827dc35e1 | |||
448723d3b3 | |||
89294b7772 | |||
7b9c4757dd | |||
b8fc97adf2 | |||
c1a7b5bcdb | |||
be1c375589 | |||
378d19f87a | |||
f59f65ec4f | |||
7bc4971cf9 | |||
3551c18902 | |||
deb99d2cae | |||
9ba73ffbe5 | |||
43b4b34376 | |||
92ca1cb0cb | |||
50d7ecf76d | |||
42a2a80b87 | |||
54deded929 | |||
39bdf6d41e | |||
074190e03c | |||
256514c7c9 | |||
556be08c4e | |||
1cbca5eecb | |||
95017b8c66 | |||
4a892fbdc9 | |||
9eb5b7a10d | |||
d64594ec74 | |||
6a1a03566a | |||
13f5294aa3 | |||
9444b4a647 | |||
610fc84f3e | |||
247d26b4b5 | |||
43ebd7a9bb | |||
26a881176e | |||
e44a43c7e1 | |||
3139a85a2b | |||
a4e8bea866 | |||
6a9e9b5360 | |||
952f6f8a65 | |||
d04ba51bb0 | |||
55ee261363 | |||
4e3a34412e | |||
3f4fb8f73a | |||
56c56aa34d | |||
d4b960d348 | |||
b2a225558d | |||
0ef0fc044a | |||
04bd87ed5a | |||
5158cdb308 | |||
1402d8391d | |||
e3b36db71c | |||
ba0171d054 | |||
d1146a5af2 | |||
79408b68c3 | |||
d461d4f68b | |||
b45d30acf8 | |||
df70442c46 | |||
e2ffa5a125 | |||
73feac5819 | |||
e5ad1dfa48 | |||
79becc4b78 | |||
223172ac0b | |||
8c9633d72f | |||
1f93fd52d9 | |||
aac7bbd378 | |||
bed516bfda | |||
69b05f9918 | |||
fb7c80e928 | |||
bb2f9df0a1 | |||
54bfaa125d | |||
7af9fcbc06 | |||
ee174be57c | |||
0bcbe32367 | |||
b97ff4da5e | |||
747081d2c7 | |||
497199bb50 | |||
bd9ac0fdaa | |||
ac21abbb9d | |||
a3dd04deef | |||
3705c20668 | |||
7b35ebc64a | |||
0a24aa6af2 | |||
c9c65af59e | |||
dc063eac83 | |||
ccf23fc629 | |||
f1460d5494 | |||
644b497df1 | |||
fb935fd201 | |||
f2087ca29e | |||
92d166ecb7 | |||
72e543e946 | |||
98c838b24c | |||
63c9c64196 | |||
a113ed0811 | |||
747876dc67 | |||
95cc18a7b4 | |||
c017c77365 | |||
98e05ee4b7 | |||
868919e101 | |||
9ca040c0ff | |||
7e9011673b | |||
741db8e43d | |||
3bd357045f | |||
ab5d77c0c4 | |||
7bfb5f79b8 | |||
8cc2479825 | |||
8f35345729 | |||
ce71f9144e | |||
f861f0bca2 | |||
571496d243 | |||
c3c3914ed3 | |||
6dffe0fad4 | |||
86b37d0ff7 | |||
863c581190 | |||
5c3112aaeb | |||
88d3ffb97c | |||
222b1ad7da | |||
d317cfd639 | |||
76b9041adf | |||
b944941733 | |||
0dddcd012c | |||
bd412afb9f | |||
20ce37dee6 | |||
c52158b733 | |||
fd6d3ec88f | |||
0a0a95fd81 | |||
26019c7d06 |
22
.github/workflows/build.yml
vendored
22
.github/workflows/build.yml
vendored
@ -39,13 +39,14 @@ jobs:
|
|||||||
|
|
||||||
- os: windows-latest
|
- os: windows-latest
|
||||||
OS_NAME: Windows x64
|
OS_NAME: Windows x64
|
||||||
DOTNET_RUNTIME_IDENTIFIER: win-x64
|
DOTNET_RUNTIME_IDENTIFIER: win10-x64
|
||||||
RELEASE_ZIP_OS_NAME: win_x64
|
RELEASE_ZIP_OS_NAME: win_x64
|
||||||
|
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
env:
|
env:
|
||||||
POWERSHELL_TELEMETRY_OPTOUT: 1
|
POWERSHELL_TELEMETRY_OPTOUT: 1
|
||||||
DOTNET_CLI_TELEMETRY_OPTOUT: 1
|
DOTNET_CLI_TELEMETRY_OPTOUT: 1
|
||||||
|
RYUJINX_BASE_VERSION: "1.1.0"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- uses: actions/setup-dotnet@v1
|
- uses: actions/setup-dotnet@v1
|
||||||
@ -59,24 +60,33 @@ jobs:
|
|||||||
- name: Clear
|
- name: Clear
|
||||||
run: dotnet clean && dotnet nuget locals all --clear
|
run: dotnet clean && dotnet nuget locals all --clear
|
||||||
- name: Build
|
- name: Build
|
||||||
run: dotnet build -c "${{ matrix.configuration }}" /p:Version="1.1.0" /p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" /p:ExtraDefineConstants=DISABLE_UPDATER
|
run: dotnet build -c "${{ matrix.configuration }}" /p:Version="${{ env.RYUJINX_BASE_VERSION }}" /p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" /p:ExtraDefineConstants=DISABLE_UPDATER
|
||||||
- name: Test
|
- name: Test
|
||||||
run: dotnet test -c "${{ matrix.configuration }}"
|
run: dotnet test -c "${{ matrix.configuration }}"
|
||||||
- name: Publish Ryujinx
|
- name: Publish Ryujinx
|
||||||
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish /p:Version="1.1.0" /p:DebugType=embedded /p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" /p:ExtraDefineConstants=DISABLE_UPDATER Ryujinx --self-contained
|
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 Ryujinx --self-contained
|
||||||
if: github.event_name == 'pull_request'
|
if: github.event_name == 'pull_request'
|
||||||
- name: Publish Ryujinx.Headless.SDL2
|
- name: Publish Ryujinx.Headless.SDL2
|
||||||
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_sdl2_headless /p:Version="1.1.0" /p:DebugType=embedded /p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" /p:ExtraDefineConstants=DISABLE_UPDATER Ryujinx.Headless.SDL2 --self-contained
|
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 Ryujinx.Headless.SDL2 --self-contained
|
||||||
|
if: github.event_name == 'pull_request'
|
||||||
|
- name: Publish Ryujinx.Ava
|
||||||
|
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.DOTNET_RUNTIME_IDENTIFIER }}" -o ./publish_ava /p:Version="1.0.0" /p:DebugType=embedded /p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" /p:ExtraDefineConstants=DISABLE_UPDATER Ryujinx.Ava
|
||||||
if: github.event_name == 'pull_request'
|
if: github.event_name == 'pull_request'
|
||||||
- name: Upload Ryujinx artifact
|
- name: Upload Ryujinx artifact
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: ryujinx-${{ matrix.configuration }}-1.0.0+${{ 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.RELEASE_ZIP_OS_NAME }}
|
||||||
path: publish
|
path: publish
|
||||||
if: github.event_name == 'pull_request'
|
if: github.event_name == 'pull_request'
|
||||||
- name: Upload Ryujinx.Headless.SDL2 artifact
|
- name: Upload Ryujinx.Headless.SDL2 artifact
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: ryujinx-headless-sdl2-${{ matrix.configuration }}-1.0.0+${{ 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.RELEASE_ZIP_OS_NAME }}
|
||||||
path: publish_sdl2_headless
|
path: publish_sdl2_headless
|
||||||
if: github.event_name == 'pull_request'
|
if: github.event_name == 'pull_request'
|
||||||
|
- name: Upload Ryujinx.Ava artifact
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: ava-ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.RELEASE_ZIP_OS_NAME }}
|
||||||
|
path: publish_ava
|
||||||
|
if: github.event_name == 'pull_request'
|
||||||
|
14
.github/workflows/nightly_pr_comment.yml
vendored
14
.github/workflows/nightly_pr_comment.yml
vendored
@ -36,15 +36,25 @@ jobs:
|
|||||||
return core.error(`No artifacts found`);
|
return core.error(`No artifacts found`);
|
||||||
}
|
}
|
||||||
let body = `Download the artifacts for this pull request:\n`;
|
let body = `Download the artifacts for this pull request:\n`;
|
||||||
|
let hidden_avalonia_artifacts = `\n\n <details><summary>Experimental GUI (Avalonia)</summary>\n`;
|
||||||
|
let hidden_headless_artifacts = `\n\n <details><summary>GUI-less (SDL2)</summary>\n`;
|
||||||
let hidden_debug_artifacts = `\n\n <details><summary>Only for Developers</summary>\n`;
|
let hidden_debug_artifacts = `\n\n <details><summary>Only for Developers</summary>\n`;
|
||||||
for (const art of artifacts) {
|
for (const art of artifacts) {
|
||||||
if(art.name.includes('Debug')){
|
if(art.name.includes('Debug')) {
|
||||||
hidden_debug_artifacts += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
|
hidden_debug_artifacts += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
|
||||||
}else{
|
} else if(art.name.includes('ava-ryujinx')) {
|
||||||
|
hidden_avalonia_artifacts += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
|
||||||
|
} else if(art.name.includes('sdl2-ryujinx-headless')) {
|
||||||
|
hidden_headless_artifacts += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
|
||||||
|
} else {
|
||||||
body += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
|
body += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
hidden_avalonia_artifacts += `\n</details>`;
|
||||||
|
hidden_headless_artifacts += `\n</details>`;
|
||||||
hidden_debug_artifacts += `\n</details>`;
|
hidden_debug_artifacts += `\n</details>`;
|
||||||
|
body += hidden_avalonia_artifacts;
|
||||||
|
body += hidden_headless_artifacts;
|
||||||
body += hidden_debug_artifacts;
|
body += hidden_debug_artifacts;
|
||||||
|
|
||||||
const {data: comments} = await github.issues.listComments({repo, owner, issue_number});
|
const {data: comments} = await github.issues.listComments({repo, owner, issue_number});
|
||||||
|
18
.github/workflows/release.yml
vendored
18
.github/workflows/release.yml
vendored
@ -51,8 +51,9 @@ jobs:
|
|||||||
run: "mkdir release_output"
|
run: "mkdir release_output"
|
||||||
- name: Publish Windows
|
- name: Publish Windows
|
||||||
run: |
|
run: |
|
||||||
dotnet publish -c Release -r win-x64 -o ./publish_windows/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx --self-contained
|
dotnet publish -c Release -r win10-x64 -o ./publish_windows/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx --self-contained
|
||||||
dotnet publish -c Release -r win-x64 -o ./publish_windows_sdl2_headless/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx.Headless.SDL2 --self-contained
|
dotnet publish -c Release -r win10-x64 -o ./publish_windows_sdl2_headless/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx.Headless.SDL2 --self-contained
|
||||||
|
dotnet publish -c Release -r win10-x64 -o ./publish_windows_ava/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx.Ava --self-contained
|
||||||
- name: Packing Windows builds
|
- name: Packing Windows builds
|
||||||
run: |
|
run: |
|
||||||
pushd publish_windows
|
pushd publish_windows
|
||||||
@ -60,7 +61,11 @@ jobs:
|
|||||||
popd
|
popd
|
||||||
|
|
||||||
pushd publish_windows_sdl2_headless
|
pushd publish_windows_sdl2_headless
|
||||||
7z a ../release_output/ryujinx-headless-sdl2-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish
|
7z a ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish
|
||||||
|
popd
|
||||||
|
|
||||||
|
pushd publish_windows_ava
|
||||||
|
7z a ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip publish
|
||||||
popd
|
popd
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
@ -68,6 +73,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
dotnet publish -c Release -r linux-x64 -o ./publish_linux/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx --self-contained
|
dotnet publish -c Release -r linux-x64 -o ./publish_linux/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx --self-contained
|
||||||
dotnet publish -c Release -r linux-x64 -o ./publish_linux_sdl2_headless/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx.Headless.SDL2 --self-contained
|
dotnet publish -c Release -r linux-x64 -o ./publish_linux_sdl2_headless/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx.Headless.SDL2 --self-contained
|
||||||
|
dotnet publish -c Release -r linux-x64 -o ./publish_linux_ava/publish /p:Version="${{ steps.version_info.outputs.build_version }}" /p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" /p:DebugType=embedded Ryujinx.Ava --self-contained
|
||||||
|
|
||||||
- name: Packing Linux builds
|
- name: Packing Linux builds
|
||||||
run: |
|
run: |
|
||||||
@ -76,7 +82,11 @@ jobs:
|
|||||||
popd
|
popd
|
||||||
|
|
||||||
pushd publish_linux_sdl2_headless
|
pushd publish_linux_sdl2_headless
|
||||||
tar -czvf ../release_output/ryujinx-headless-sdl2-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish
|
tar -czvf ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish
|
||||||
|
popd
|
||||||
|
|
||||||
|
pushd publish_linux_ava
|
||||||
|
tar -czvf ../release_output/test-ava-ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz publish
|
||||||
popd
|
popd
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -74,6 +74,9 @@ _TeamCity*
|
|||||||
# DotCover is a Code Coverage Tool
|
# DotCover is a Code Coverage Tool
|
||||||
*.dotCover
|
*.dotCover
|
||||||
|
|
||||||
|
# Rider is a Visual Studio alternative
|
||||||
|
.idea/*
|
||||||
|
|
||||||
# NCrunch
|
# NCrunch
|
||||||
*.ncrunch*
|
*.ncrunch*
|
||||||
.*crunch*.local.xml
|
.*crunch*.local.xml
|
||||||
|
@ -58,7 +58,6 @@ namespace ARMeilleure.CodeGen.Linking
|
|||||||
/// <param name="a">First instance</param>
|
/// <param name="a">First instance</param>
|
||||||
/// <param name="b">Second instance</param>
|
/// <param name="b">Second instance</param>
|
||||||
/// <returns><see langword="true"/> if not equal; otherwise <see langword="false"/></returns>
|
/// <returns><see langword="true"/> if not equal; otherwise <see langword="false"/></returns>
|
||||||
/// <inheritdoc/>
|
|
||||||
public static bool operator !=(Symbol a, Symbol b)
|
public static bool operator !=(Symbol a, Symbol b)
|
||||||
{
|
{
|
||||||
return !(a == b);
|
return !(a == b);
|
||||||
|
@ -59,7 +59,7 @@ namespace ARMeilleure.CodeGen.Optimizations
|
|||||||
BasicBlock fromPred = from.Predecessors.Count == 1 ? from.Predecessors[0] : null;
|
BasicBlock fromPred = from.Predecessors.Count == 1 ? from.Predecessors[0] : null;
|
||||||
|
|
||||||
// If the block is empty, we can try to append to the predecessor and avoid unnecessary jumps.
|
// If the block is empty, we can try to append to the predecessor and avoid unnecessary jumps.
|
||||||
if (from.Operations.Count == 0 && fromPred != null)
|
if (from.Operations.Count == 0 && fromPred != null && fromPred.SuccessorsCount == 1)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < fromPred.SuccessorsCount; i++)
|
for (int i = 0; i < fromPred.SuccessorsCount; i++)
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
using ARMeilleure.Common;
|
|
||||||
using ARMeilleure.IntermediateRepresentation;
|
using ARMeilleure.IntermediateRepresentation;
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace ARMeilleure.CodeGen.RegisterAllocators
|
namespace ARMeilleure.CodeGen.RegisterAllocators
|
||||||
{
|
{
|
||||||
|
@ -4,6 +4,11 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
{
|
{
|
||||||
partial class Assembler
|
partial class Assembler
|
||||||
{
|
{
|
||||||
|
public static bool SupportsVexPrefix(X86Instruction inst)
|
||||||
|
{
|
||||||
|
return _instTable[(int)inst].Flags.HasFlag(InstructionFlags.Vex);
|
||||||
|
}
|
||||||
|
|
||||||
private const int BadOp = 0;
|
private const int BadOp = 0;
|
||||||
|
|
||||||
[Flags]
|
[Flags]
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace ARMeilleure.CodeGen.X86
|
namespace ARMeilleure.CodeGen.X86
|
||||||
{
|
{
|
||||||
|
@ -1297,11 +1297,15 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
{
|
{
|
||||||
if (IsIntrinsic(operation.Instruction))
|
if (IsIntrinsic(operation.Instruction))
|
||||||
{
|
{
|
||||||
|
IntrinsicInfo info = IntrinsicTable.GetInfo(operation.Intrinsic);
|
||||||
|
|
||||||
|
bool hasVex = HardwareCapabilities.SupportsVexEncoding && Assembler.SupportsVexPrefix(info.Inst);
|
||||||
|
|
||||||
bool isUnary = operation.SourcesCount < 2;
|
bool isUnary = operation.SourcesCount < 2;
|
||||||
|
|
||||||
bool hasVecDest = operation.Destination != default && operation.Destination.Type == OperandType.V128;
|
bool hasVecDest = operation.Destination != default && operation.Destination.Type == OperandType.V128;
|
||||||
|
|
||||||
return !HardwareCapabilities.SupportsVexEncoding && !isUnary && hasVecDest;
|
return !hasVex && !isUnary && hasVecDest;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -9,13 +9,17 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
{
|
{
|
||||||
static class X86Optimizer
|
static class X86Optimizer
|
||||||
{
|
{
|
||||||
|
private const int MaxConstantUses = 10000;
|
||||||
|
|
||||||
public static void RunPass(ControlFlowGraph cfg)
|
public static void RunPass(ControlFlowGraph cfg)
|
||||||
{
|
{
|
||||||
var constants = new Dictionary<ulong, Operand>();
|
var constants = new Dictionary<ulong, Operand>();
|
||||||
|
|
||||||
Operand GetConstantCopy(BasicBlock block, Operation operation, Operand source)
|
Operand GetConstantCopy(BasicBlock block, Operation operation, Operand source)
|
||||||
{
|
{
|
||||||
if (!constants.TryGetValue(source.Value, out var constant))
|
// If the constant has many uses, we also force a new constant mov to be added, in order
|
||||||
|
// to avoid overflow of the counts field (that is limited to 16 bits).
|
||||||
|
if (!constants.TryGetValue(source.Value, out var constant) || constant.UsesCount > MaxConstantUses)
|
||||||
{
|
{
|
||||||
constant = Local(source.Type);
|
constant = Local(source.Type);
|
||||||
|
|
||||||
@ -23,7 +27,7 @@ namespace ARMeilleure.CodeGen.X86
|
|||||||
|
|
||||||
block.Operations.AddBefore(operation, copyOp);
|
block.Operations.AddBefore(operation, copyOp);
|
||||||
|
|
||||||
constants.Add(source.Value, constant);
|
constants[source.Value] = constant;
|
||||||
}
|
}
|
||||||
|
|
||||||
return constant;
|
return constant;
|
||||||
|
@ -206,7 +206,7 @@ namespace ARMeilleure.Common
|
|||||||
/// <typeparam name="T">Type of elements</typeparam>
|
/// <typeparam name="T">Type of elements</typeparam>
|
||||||
/// <param name="length">Number of elements</param>
|
/// <param name="length">Number of elements</param>
|
||||||
/// <param name="fill">Fill value</param>
|
/// <param name="fill">Fill value</param>
|
||||||
/// <param name="leaf"><see langword="true"/> if leaf; otherwise <see langword=""="false"/></param>
|
/// <param name="leaf"><see langword="true"/> if leaf; otherwise <see langword="false"/></param>
|
||||||
/// <returns>Allocated block</returns>
|
/// <returns>Allocated block</returns>
|
||||||
private IntPtr Allocate<T>(int length, T fill, bool leaf) where T : unmanaged
|
private IntPtr Allocate<T>(int length, T fill, bool leaf) where T : unmanaged
|
||||||
{
|
{
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace ARMeilleure.Common
|
namespace ARMeilleure.Common
|
||||||
{
|
{
|
||||||
|
@ -9,6 +9,9 @@ namespace ARMeilleure.Common
|
|||||||
class Counter<T> : IDisposable where T : unmanaged
|
class Counter<T> : IDisposable where T : unmanaged
|
||||||
{
|
{
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
|
/// <summary>
|
||||||
|
/// Index in the <see cref="EntryTable{T}"/>
|
||||||
|
/// </summary>
|
||||||
private readonly int _index;
|
private readonly int _index;
|
||||||
private readonly EntryTable<T> _countTable;
|
private readonly EntryTable<T> _countTable;
|
||||||
|
|
||||||
@ -17,7 +20,6 @@ namespace ARMeilleure.Common
|
|||||||
/// <see cref="EntryTable{T}"/> instance and index.
|
/// <see cref="EntryTable{T}"/> instance and index.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="countTable"><see cref="EntryTable{T}"/> instance</param>
|
/// <param name="countTable"><see cref="EntryTable{T}"/> instance</param>
|
||||||
/// <param name="index">Index in the <see cref="EntryTable{T}"/></param>
|
|
||||||
/// <exception cref="ArgumentNullException"><paramref name="countTable"/> is <see langword="null"/></exception>
|
/// <exception cref="ArgumentNullException"><paramref name="countTable"/> is <see langword="null"/></exception>
|
||||||
/// <exception cref="ArgumentException"><typeparamref name="T"/> is unsupported</exception>
|
/// <exception cref="ArgumentException"><typeparamref name="T"/> is unsupported</exception>
|
||||||
public Counter(EntryTable<T> countTable)
|
public Counter(EntryTable<T> countTable)
|
||||||
@ -68,7 +70,7 @@ namespace ARMeilleure.Common
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Releases all unmanaged and optionally managed resources used by the <see cref="Counter{T}"/> instance.
|
/// Releases all unmanaged and optionally managed resources used by the <see cref="Counter{T}"/> instance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="disposing"><see langword="true"/> to dispose managed resources also; otherwise just unmanaged resouces</param>
|
/// <param name="disposing"><see langword="true"/> to dispose managed resources also; otherwise just unmanaged resources</param>
|
||||||
protected virtual void Dispose(bool disposing)
|
protected virtual void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
if (!_disposed)
|
if (!_disposed)
|
||||||
|
@ -18,7 +18,7 @@ namespace ARMeilleure.Decoders
|
|||||||
// For lower code quality translation, we set a lower limit since we're blocking execution.
|
// For lower code quality translation, we set a lower limit since we're blocking execution.
|
||||||
private const int MaxInstsPerFunctionLowCq = 500;
|
private const int MaxInstsPerFunctionLowCq = 500;
|
||||||
|
|
||||||
public static Block[] Decode(IMemoryManager memory, ulong address, ExecutionMode mode, bool highCq, bool singleBlock)
|
public static Block[] Decode(IMemoryManager memory, ulong address, ExecutionMode mode, bool highCq, DecoderMode dMode)
|
||||||
{
|
{
|
||||||
List<Block> blocks = new List<Block>();
|
List<Block> blocks = new List<Block>();
|
||||||
|
|
||||||
@ -38,7 +38,7 @@ namespace ARMeilleure.Decoders
|
|||||||
{
|
{
|
||||||
block = new Block(blkAddress);
|
block = new Block(blkAddress);
|
||||||
|
|
||||||
if ((singleBlock && visited.Count >= 1) || opsCount > instructionLimit || !memory.IsMapped(blkAddress))
|
if ((dMode != DecoderMode.MultipleBlocks && visited.Count >= 1) || opsCount > instructionLimit || !memory.IsMapped(blkAddress))
|
||||||
{
|
{
|
||||||
block.Exit = true;
|
block.Exit = true;
|
||||||
block.EndAddress = blkAddress;
|
block.EndAddress = blkAddress;
|
||||||
@ -96,6 +96,12 @@ namespace ARMeilleure.Decoders
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dMode == DecoderMode.SingleInstruction)
|
||||||
|
{
|
||||||
|
// Only read at most one instruction
|
||||||
|
limitAddress = currBlock.Address + 1;
|
||||||
|
}
|
||||||
|
|
||||||
FillBlock(memory, mode, currBlock, limitAddress);
|
FillBlock(memory, mode, currBlock, limitAddress);
|
||||||
|
|
||||||
opsCount += currBlock.OpCodes.Count;
|
opsCount += currBlock.OpCodes.Count;
|
||||||
@ -115,7 +121,7 @@ namespace ARMeilleure.Decoders
|
|||||||
currBlock.Branch = GetBlock((ulong)op.Immediate);
|
currBlock.Branch = GetBlock((ulong)op.Immediate);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsUnconditionalBranch(lastOp) || isCall)
|
if (isCall || !(IsUnconditionalBranch(lastOp) || IsTrap(lastOp)))
|
||||||
{
|
{
|
||||||
currBlock.Next = GetBlock(currBlock.EndAddress);
|
currBlock.Next = GetBlock(currBlock.EndAddress);
|
||||||
}
|
}
|
||||||
@ -143,7 +149,7 @@ namespace ARMeilleure.Decoders
|
|||||||
throw new InvalidOperationException($"Decoded a single empty exit block. Entry point = 0x{address:X}.");
|
throw new InvalidOperationException($"Decoded a single empty exit block. Entry point = 0x{address:X}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!singleBlock)
|
if (dMode == DecoderMode.MultipleBlocks)
|
||||||
{
|
{
|
||||||
return TailCallRemover.RunPass(address, blocks);
|
return TailCallRemover.RunPass(address, blocks);
|
||||||
}
|
}
|
||||||
@ -195,12 +201,13 @@ namespace ARMeilleure.Decoders
|
|||||||
ulong limitAddress)
|
ulong limitAddress)
|
||||||
{
|
{
|
||||||
ulong address = block.Address;
|
ulong address = block.Address;
|
||||||
|
int itBlockSize = 0;
|
||||||
|
|
||||||
OpCode opCode;
|
OpCode opCode;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
if (address >= limitAddress)
|
if (address >= limitAddress && itBlockSize == 0)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -210,6 +217,15 @@ namespace ARMeilleure.Decoders
|
|||||||
block.OpCodes.Add(opCode);
|
block.OpCodes.Add(opCode);
|
||||||
|
|
||||||
address += (ulong)opCode.OpCodeSizeInBytes;
|
address += (ulong)opCode.OpCodeSizeInBytes;
|
||||||
|
|
||||||
|
if (opCode is OpCodeT16IfThen it)
|
||||||
|
{
|
||||||
|
itBlockSize = it.IfThenBlockSize;
|
||||||
|
}
|
||||||
|
else if (itBlockSize > 0)
|
||||||
|
{
|
||||||
|
itBlockSize--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
while (!(IsBranch(opCode) || IsException(opCode)));
|
while (!(IsBranch(opCode) || IsException(opCode)));
|
||||||
|
|
||||||
@ -247,6 +263,11 @@ namespace ARMeilleure.Decoders
|
|||||||
// so we must consider such operations as a branch in potential aswell.
|
// so we must consider such operations as a branch in potential aswell.
|
||||||
if (opCode is IOpCode32Alu opAlu && opAlu.Rd == RegisterAlias.Aarch32Pc)
|
if (opCode is IOpCode32Alu opAlu && opAlu.Rd == RegisterAlias.Aarch32Pc)
|
||||||
{
|
{
|
||||||
|
if (opCode is OpCodeT32)
|
||||||
|
{
|
||||||
|
return opCode.Instruction.Name != InstName.Tst && opCode.Instruction.Name != InstName.Teq &&
|
||||||
|
opCode.Instruction.Name != InstName.Cmp && opCode.Instruction.Name != InstName.Cmn;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -308,9 +329,13 @@ namespace ARMeilleure.Decoders
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static bool IsException(OpCode opCode)
|
private static bool IsException(OpCode opCode)
|
||||||
|
{
|
||||||
|
return IsTrap(opCode) || opCode.Instruction.Name == InstName.Svc;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsTrap(OpCode opCode)
|
||||||
{
|
{
|
||||||
return opCode.Instruction.Name == InstName.Brk ||
|
return opCode.Instruction.Name == InstName.Brk ||
|
||||||
opCode.Instruction.Name == InstName.Svc ||
|
|
||||||
opCode.Instruction.Name == InstName.Trap ||
|
opCode.Instruction.Name == InstName.Trap ||
|
||||||
opCode.Instruction.Name == InstName.Und;
|
opCode.Instruction.Name == InstName.Und;
|
||||||
}
|
}
|
||||||
@ -345,7 +370,14 @@ namespace ARMeilleure.Decoders
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return new OpCode(inst, address, opCode);
|
if (mode == ExecutionMode.Aarch32Thumb)
|
||||||
|
{
|
||||||
|
return new OpCodeT16(inst, address, opCode);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new OpCode(inst, address, opCode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
9
ARMeilleure/Decoders/DecoderMode.cs
Normal file
9
ARMeilleure/Decoders/DecoderMode.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
enum DecoderMode
|
||||||
|
{
|
||||||
|
MultipleBlocks,
|
||||||
|
SingleBlock,
|
||||||
|
SingleInstruction,
|
||||||
|
}
|
||||||
|
}
|
9
ARMeilleure/Decoders/IOpCode32Adr.cs
Normal file
9
ARMeilleure/Decoders/IOpCode32Adr.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
interface IOpCode32Adr
|
||||||
|
{
|
||||||
|
int Rd { get; }
|
||||||
|
|
||||||
|
int Immediate { get; }
|
||||||
|
}
|
||||||
|
}
|
@ -1,10 +1,8 @@
|
|||||||
namespace ARMeilleure.Decoders
|
namespace ARMeilleure.Decoders
|
||||||
{
|
{
|
||||||
interface IOpCode32Alu : IOpCode32
|
interface IOpCode32Alu : IOpCode32, IOpCode32HasSetFlags
|
||||||
{
|
{
|
||||||
int Rd { get; }
|
int Rd { get; }
|
||||||
int Rn { get; }
|
int Rn { get; }
|
||||||
|
|
||||||
bool SetFlags { get; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
9
ARMeilleure/Decoders/IOpCode32AluImm.cs
Normal file
9
ARMeilleure/Decoders/IOpCode32AluImm.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
interface IOpCode32AluImm : IOpCode32Alu
|
||||||
|
{
|
||||||
|
int Immediate { get; }
|
||||||
|
|
||||||
|
bool IsRotated { get; }
|
||||||
|
}
|
||||||
|
}
|
10
ARMeilleure/Decoders/IOpCode32AluRsImm.cs
Normal file
10
ARMeilleure/Decoders/IOpCode32AluRsImm.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
interface IOpCode32AluRsImm : IOpCode32Alu
|
||||||
|
{
|
||||||
|
int Rm { get; }
|
||||||
|
int Immediate { get; }
|
||||||
|
|
||||||
|
ShiftType ShiftType { get; }
|
||||||
|
}
|
||||||
|
}
|
10
ARMeilleure/Decoders/IOpCode32AluRsReg.cs
Normal file
10
ARMeilleure/Decoders/IOpCode32AluRsReg.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
interface IOpCode32AluRsReg : IOpCode32Alu
|
||||||
|
{
|
||||||
|
int Rm { get; }
|
||||||
|
int Rs { get; }
|
||||||
|
|
||||||
|
ShiftType ShiftType { get; }
|
||||||
|
}
|
||||||
|
}
|
6
ARMeilleure/Decoders/IOpCode32Exception.cs
Normal file
6
ARMeilleure/Decoders/IOpCode32Exception.cs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
namespace ARMeilleure.Decoders;
|
||||||
|
|
||||||
|
interface IOpCode32Exception
|
||||||
|
{
|
||||||
|
int Id { get; }
|
||||||
|
}
|
7
ARMeilleure/Decoders/IOpCode32HasSetFlags.cs
Normal file
7
ARMeilleure/Decoders/IOpCode32HasSetFlags.cs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
interface IOpCode32HasSetFlags
|
||||||
|
{
|
||||||
|
bool? SetFlags { get; }
|
||||||
|
}
|
||||||
|
}
|
@ -7,5 +7,9 @@ namespace ARMeilleure.Decoders
|
|||||||
|
|
||||||
bool WBack { get; }
|
bool WBack { get; }
|
||||||
bool IsLoad { get; }
|
bool IsLoad { get; }
|
||||||
|
bool Index { get; }
|
||||||
|
bool Add { get; }
|
||||||
|
|
||||||
|
int Immediate { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -9,5 +9,7 @@ namespace ARMeilleure.Decoders
|
|||||||
int PostOffset { get; }
|
int PostOffset { get; }
|
||||||
|
|
||||||
bool IsLoad { get; }
|
bool IsLoad { get; }
|
||||||
|
|
||||||
|
int Offset { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
7
ARMeilleure/Decoders/IOpCode32MemReg.cs
Normal file
7
ARMeilleure/Decoders/IOpCode32MemReg.cs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
interface IOpCode32MemReg : IOpCode32Mem
|
||||||
|
{
|
||||||
|
int Rm { get; }
|
||||||
|
}
|
||||||
|
}
|
@ -18,10 +18,9 @@ namespace ARMeilleure.Decoders
|
|||||||
|
|
||||||
public OpCode(InstDescriptor inst, ulong address, int opCode)
|
public OpCode(InstDescriptor inst, ulong address, int opCode)
|
||||||
{
|
{
|
||||||
Address = address;
|
|
||||||
RawOpCode = opCode;
|
|
||||||
|
|
||||||
Instruction = inst;
|
Instruction = inst;
|
||||||
|
Address = address;
|
||||||
|
RawOpCode = opCode;
|
||||||
|
|
||||||
RegisterSize = RegisterSize.Int64;
|
RegisterSize = RegisterSize.Int64;
|
||||||
}
|
}
|
||||||
|
@ -13,11 +13,25 @@ namespace ARMeilleure.Decoders
|
|||||||
Cond = (Condition)((uint)opCode >> 28);
|
Cond = (Condition)((uint)opCode >> 28);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsThumb()
|
||||||
|
{
|
||||||
|
return this is OpCodeT16 || this is OpCodeT32;
|
||||||
|
}
|
||||||
|
|
||||||
public uint GetPc()
|
public uint GetPc()
|
||||||
{
|
{
|
||||||
// Due to backwards compatibility and legacy behavior of ARMv4 CPUs pipeline,
|
// Due to backwards compatibility and legacy behavior of ARMv4 CPUs pipeline,
|
||||||
// the PC actually points 2 instructions ahead.
|
// the PC actually points 2 instructions ahead.
|
||||||
return (uint)Address + (uint)OpCodeSizeInBytes * 2;
|
if (IsThumb())
|
||||||
|
{
|
||||||
|
// PC is ahead by 4 in thumb mode whether or not the current instruction
|
||||||
|
// is 16 or 32 bit.
|
||||||
|
return (uint)Address + 4u;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return (uint)Address + 8u;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -5,7 +5,7 @@ namespace ARMeilleure.Decoders
|
|||||||
public int Rd { get; }
|
public int Rd { get; }
|
||||||
public int Rn { get; }
|
public int Rn { get; }
|
||||||
|
|
||||||
public bool SetFlags { get; }
|
public bool? SetFlags { get; }
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32Alu(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32Alu(inst, address, opCode);
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ using ARMeilleure.Common;
|
|||||||
|
|
||||||
namespace ARMeilleure.Decoders
|
namespace ARMeilleure.Decoders
|
||||||
{
|
{
|
||||||
class OpCode32AluImm : OpCode32Alu
|
class OpCode32AluImm : OpCode32Alu, IOpCode32AluImm
|
||||||
{
|
{
|
||||||
public int Immediate { get; }
|
public int Immediate { get; }
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
public bool NHigh { get; }
|
public bool NHigh { get; }
|
||||||
public bool MHigh { get; }
|
public bool MHigh { get; }
|
||||||
public bool R { get; }
|
public bool R { get; }
|
||||||
public bool SetFlags { get; }
|
public bool? SetFlags { get; }
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32AluMla(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32AluMla(inst, address, opCode);
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
namespace ARMeilleure.Decoders
|
namespace ARMeilleure.Decoders
|
||||||
{
|
{
|
||||||
class OpCode32AluRsImm : OpCode32Alu
|
class OpCode32AluRsImm : OpCode32Alu, IOpCode32AluRsImm
|
||||||
{
|
{
|
||||||
public int Rm { get; }
|
public int Rm { get; }
|
||||||
public int Immediate { get; }
|
public int Immediate { get; }
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
namespace ARMeilleure.Decoders
|
namespace ARMeilleure.Decoders
|
||||||
{
|
{
|
||||||
class OpCode32AluRsReg : OpCode32Alu
|
class OpCode32AluRsReg : OpCode32Alu, IOpCode32AluRsReg
|
||||||
{
|
{
|
||||||
public int Rm { get; }
|
public int Rm { get; }
|
||||||
public int Rs { get; }
|
public int Rs { get; }
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
namespace ARMeilleure.Decoders
|
namespace ARMeilleure.Decoders
|
||||||
{
|
{
|
||||||
class OpCode32AluUmull : OpCode32
|
class OpCode32AluUmull : OpCode32, IOpCode32HasSetFlags
|
||||||
{
|
{
|
||||||
public int RdLo { get; }
|
public int RdLo { get; }
|
||||||
public int RdHi { get; }
|
public int RdHi { get; }
|
||||||
@ -10,7 +10,7 @@
|
|||||||
public bool NHigh { get; }
|
public bool NHigh { get; }
|
||||||
public bool MHigh { get; }
|
public bool MHigh { get; }
|
||||||
|
|
||||||
public bool SetFlags { get; }
|
public bool? SetFlags { get; }
|
||||||
public DataOp DataOp { get; }
|
public DataOp DataOp { get; }
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32AluUmull(inst, address, opCode);
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32AluUmull(inst, address, opCode);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
namespace ARMeilleure.Decoders
|
namespace ARMeilleure.Decoders
|
||||||
{
|
{
|
||||||
class OpCode32Exception : OpCode32
|
class OpCode32Exception : OpCode32, IOpCode32Exception
|
||||||
{
|
{
|
||||||
public int Id { get; }
|
public int Id { get; }
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
namespace ARMeilleure.Decoders
|
namespace ARMeilleure.Decoders
|
||||||
{
|
{
|
||||||
class OpCode32MemReg : OpCode32Mem
|
class OpCode32MemReg : OpCode32Mem, IOpCode32MemReg
|
||||||
{
|
{
|
||||||
public int Rm { get; }
|
public int Rm { get; }
|
||||||
|
|
||||||
|
16
ARMeilleure/Decoders/OpCode32Mrs.cs
Normal file
16
ARMeilleure/Decoders/OpCode32Mrs.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCode32Mrs : OpCode32
|
||||||
|
{
|
||||||
|
public bool R { get; }
|
||||||
|
public int Rd { get; }
|
||||||
|
|
||||||
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCode32Mrs(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCode32Mrs(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
R = ((opCode >> 22) & 1) != 0;
|
||||||
|
Rd = (opCode >> 12) & 0xf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
24
ARMeilleure/Decoders/OpCodeT16AddSubImm3.cs
Normal file
24
ARMeilleure/Decoders/OpCodeT16AddSubImm3.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT16AddSubImm3: OpCodeT16, IOpCode32AluImm
|
||||||
|
{
|
||||||
|
public int Rd { get; }
|
||||||
|
public int Rn { get; }
|
||||||
|
|
||||||
|
public bool? SetFlags => null;
|
||||||
|
|
||||||
|
public int Immediate { get; }
|
||||||
|
|
||||||
|
public bool IsRotated { get; }
|
||||||
|
|
||||||
|
public static new OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16AddSubImm3(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT16AddSubImm3(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Rd = (opCode >> 0) & 0x7;
|
||||||
|
Rn = (opCode >> 3) & 0x7;
|
||||||
|
Immediate = (opCode >> 6) & 0x7;
|
||||||
|
IsRotated = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
ARMeilleure/Decoders/OpCodeT16AddSubReg.cs
Normal file
20
ARMeilleure/Decoders/OpCodeT16AddSubReg.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT16AddSubReg : OpCodeT16, IOpCode32AluReg
|
||||||
|
{
|
||||||
|
public int Rm { get; }
|
||||||
|
public int Rd { get; }
|
||||||
|
public int Rn { get; }
|
||||||
|
|
||||||
|
public bool? SetFlags => null;
|
||||||
|
|
||||||
|
public static new OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16AddSubReg(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT16AddSubReg(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Rd = (opCode >> 0) & 0x7;
|
||||||
|
Rn = (opCode >> 3) & 0x7;
|
||||||
|
Rm = (opCode >> 6) & 0x7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
23
ARMeilleure/Decoders/OpCodeT16AddSubSp.cs
Normal file
23
ARMeilleure/Decoders/OpCodeT16AddSubSp.cs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
using ARMeilleure.State;
|
||||||
|
|
||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT16AddSubSp : OpCodeT16, IOpCode32AluImm
|
||||||
|
{
|
||||||
|
public int Rd => RegisterAlias.Aarch32Sp;
|
||||||
|
public int Rn => RegisterAlias.Aarch32Sp;
|
||||||
|
|
||||||
|
public bool? SetFlags => false;
|
||||||
|
|
||||||
|
public int Immediate { get; }
|
||||||
|
|
||||||
|
public bool IsRotated => false;
|
||||||
|
|
||||||
|
public static new OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16AddSubSp(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT16AddSubSp(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Immediate = ((opCode >> 0) & 0x7f) << 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
ARMeilleure/Decoders/OpCodeT16Adr.cs
Normal file
20
ARMeilleure/Decoders/OpCodeT16Adr.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT16Adr : OpCodeT16, IOpCode32Adr
|
||||||
|
{
|
||||||
|
public int Rd { get; }
|
||||||
|
|
||||||
|
public bool Add => true;
|
||||||
|
public int Immediate { get; }
|
||||||
|
|
||||||
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16Adr(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT16Adr(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Rd = (opCode >> 8) & 7;
|
||||||
|
|
||||||
|
int imm = (opCode & 0xff) << 2;
|
||||||
|
Immediate = (int)(GetPc() & 0xfffffffc) + imm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,22 +1,24 @@
|
|||||||
namespace ARMeilleure.Decoders
|
namespace ARMeilleure.Decoders
|
||||||
{
|
{
|
||||||
class OpCodeT16AluImm8 : OpCodeT16, IOpCode32Alu
|
class OpCodeT16AluImm8 : OpCodeT16, IOpCode32AluImm
|
||||||
{
|
{
|
||||||
private int _rdn;
|
public int Rd { get; }
|
||||||
|
public int Rn { get; }
|
||||||
|
|
||||||
public int Rd => _rdn;
|
public bool? SetFlags => null;
|
||||||
public int Rn => _rdn;
|
|
||||||
|
|
||||||
public bool SetFlags => false;
|
|
||||||
|
|
||||||
public int Immediate { get; }
|
public int Immediate { get; }
|
||||||
|
|
||||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16AluImm8(inst, address, opCode);
|
public bool IsRotated { get; }
|
||||||
|
|
||||||
|
public static new OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16AluImm8(inst, address, opCode);
|
||||||
|
|
||||||
public OpCodeT16AluImm8(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCodeT16AluImm8(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
{
|
{
|
||||||
|
Rd = (opCode >> 8) & 0x7;
|
||||||
|
Rn = (opCode >> 8) & 0x7;
|
||||||
Immediate = (opCode >> 0) & 0xff;
|
Immediate = (opCode >> 0) & 0xff;
|
||||||
_rdn = (opCode >> 8) & 0x7;
|
IsRotated = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
24
ARMeilleure/Decoders/OpCodeT16AluImmZero.cs
Normal file
24
ARMeilleure/Decoders/OpCodeT16AluImmZero.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT16AluImmZero : OpCodeT16, IOpCode32AluImm
|
||||||
|
{
|
||||||
|
public int Rd { get; }
|
||||||
|
public int Rn { get; }
|
||||||
|
|
||||||
|
public bool? SetFlags => null;
|
||||||
|
|
||||||
|
public int Immediate { get; }
|
||||||
|
|
||||||
|
public bool IsRotated { get; }
|
||||||
|
|
||||||
|
public static new OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16AluImmZero(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT16AluImmZero(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Rd = (opCode >> 0) & 0x7;
|
||||||
|
Rn = (opCode >> 3) & 0x7;
|
||||||
|
Immediate = 0;
|
||||||
|
IsRotated = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
ARMeilleure/Decoders/OpCodeT16AluRegHigh.cs
Normal file
20
ARMeilleure/Decoders/OpCodeT16AluRegHigh.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT16AluRegHigh : OpCodeT16, IOpCode32AluReg
|
||||||
|
{
|
||||||
|
public int Rm { get; }
|
||||||
|
public int Rd { get; }
|
||||||
|
public int Rn { get; }
|
||||||
|
|
||||||
|
public bool? SetFlags => false;
|
||||||
|
|
||||||
|
public static new OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16AluRegHigh(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT16AluRegHigh(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Rd = ((opCode >> 0) & 0x7) | ((opCode >> 4) & 0x8);
|
||||||
|
Rn = ((opCode >> 0) & 0x7) | ((opCode >> 4) & 0x8);
|
||||||
|
Rm = (opCode >> 3) & 0xf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
ARMeilleure/Decoders/OpCodeT16AluRegLow.cs
Normal file
20
ARMeilleure/Decoders/OpCodeT16AluRegLow.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT16AluRegLow : OpCodeT16, IOpCode32AluReg
|
||||||
|
{
|
||||||
|
public int Rm { get; }
|
||||||
|
public int Rd { get; }
|
||||||
|
public int Rn { get; }
|
||||||
|
|
||||||
|
public bool? SetFlags => null;
|
||||||
|
|
||||||
|
public static new OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16AluRegLow(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT16AluRegLow(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Rd = (opCode >> 0) & 0x7;
|
||||||
|
Rn = (opCode >> 0) & 0x7;
|
||||||
|
Rm = (opCode >> 3) & 0x7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
22
ARMeilleure/Decoders/OpCodeT16AluUx.cs
Normal file
22
ARMeilleure/Decoders/OpCodeT16AluUx.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT16AluUx : OpCodeT16, IOpCode32AluUx
|
||||||
|
{
|
||||||
|
public int Rm { get; }
|
||||||
|
public int Rd { get; }
|
||||||
|
public int Rn { get; }
|
||||||
|
|
||||||
|
public bool? SetFlags => false;
|
||||||
|
|
||||||
|
public int RotateBits => 0;
|
||||||
|
public bool Add => false;
|
||||||
|
|
||||||
|
public static new OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16AluUx(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT16AluUx(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Rd = (opCode >> 0) & 0x7;
|
||||||
|
Rm = (opCode >> 3) & 0x7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
15
ARMeilleure/Decoders/OpCodeT16BImm11.cs
Normal file
15
ARMeilleure/Decoders/OpCodeT16BImm11.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT16BImm11 : OpCodeT16, IOpCode32BImm
|
||||||
|
{
|
||||||
|
public long Immediate { get; }
|
||||||
|
|
||||||
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16BImm11(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT16BImm11(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
int imm = (opCode << 21) >> 20;
|
||||||
|
Immediate = GetPc() + imm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
ARMeilleure/Decoders/OpCodeT16BImm8.cs
Normal file
17
ARMeilleure/Decoders/OpCodeT16BImm8.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT16BImm8 : OpCodeT16, IOpCode32BImm
|
||||||
|
{
|
||||||
|
public long Immediate { get; }
|
||||||
|
|
||||||
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16BImm8(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT16BImm8(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Cond = (Condition)((opCode >> 8) & 0xf);
|
||||||
|
|
||||||
|
int imm = (opCode << 24) >> 23;
|
||||||
|
Immediate = GetPc() + imm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
19
ARMeilleure/Decoders/OpCodeT16BImmCmp.cs
Normal file
19
ARMeilleure/Decoders/OpCodeT16BImmCmp.cs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT16BImmCmp : OpCodeT16
|
||||||
|
{
|
||||||
|
public int Rn { get; }
|
||||||
|
|
||||||
|
public int Immediate { get; }
|
||||||
|
|
||||||
|
public static new OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16BImmCmp(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT16BImmCmp(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Rn = (opCode >> 0) & 0x7;
|
||||||
|
|
||||||
|
int imm = ((opCode >> 2) & 0x3e) | ((opCode >> 3) & 0x40);
|
||||||
|
Immediate = (int)GetPc() + imm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
namespace ARMeilleure.Decoders
|
namespace ARMeilleure.Decoders
|
||||||
{
|
{
|
||||||
class OpCodeT16BReg : OpCodeT16, IOpCode32BReg
|
class OpCodeT16BReg : OpCodeT16, IOpCode32BReg
|
||||||
{
|
{
|
||||||
@ -11,4 +11,4 @@ namespace ARMeilleure.Decoders
|
|||||||
Rm = (opCode >> 3) & 0xf;
|
Rm = (opCode >> 3) & 0xf;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
14
ARMeilleure/Decoders/OpCodeT16Exception.cs
Normal file
14
ARMeilleure/Decoders/OpCodeT16Exception.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT16Exception : OpCodeT16, IOpCode32Exception
|
||||||
|
{
|
||||||
|
public int Id { get; }
|
||||||
|
|
||||||
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16Exception(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT16Exception(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Id = opCode & 0xFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
33
ARMeilleure/Decoders/OpCodeT16IfThen.cs
Normal file
33
ARMeilleure/Decoders/OpCodeT16IfThen.cs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT16IfThen : OpCodeT16
|
||||||
|
{
|
||||||
|
public Condition[] IfThenBlockConds { get; }
|
||||||
|
|
||||||
|
public int IfThenBlockSize { get { return IfThenBlockConds.Length; } }
|
||||||
|
|
||||||
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16IfThen(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT16IfThen(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
List<Condition> conds = new();
|
||||||
|
|
||||||
|
int cond = (opCode >> 4) & 0xf;
|
||||||
|
int mask = opCode & 0xf;
|
||||||
|
|
||||||
|
conds.Add((Condition)cond);
|
||||||
|
|
||||||
|
while ((mask & 7) != 0)
|
||||||
|
{
|
||||||
|
int newLsb = (mask >> 3) & 1;
|
||||||
|
cond = (cond & 0xe) | newLsb;
|
||||||
|
mask <<= 1;
|
||||||
|
conds.Add((Condition)cond);
|
||||||
|
}
|
||||||
|
|
||||||
|
IfThenBlockConds = conds.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
58
ARMeilleure/Decoders/OpCodeT16MemImm5.cs
Normal file
58
ARMeilleure/Decoders/OpCodeT16MemImm5.cs
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
using ARMeilleure.Instructions;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT16MemImm5 : OpCodeT16, IOpCode32Mem
|
||||||
|
{
|
||||||
|
public int Rt { get; }
|
||||||
|
public int Rn { get; }
|
||||||
|
|
||||||
|
public bool WBack => false;
|
||||||
|
public bool IsLoad { get; }
|
||||||
|
public bool Index => true;
|
||||||
|
public bool Add => true;
|
||||||
|
|
||||||
|
public int Immediate { get; }
|
||||||
|
|
||||||
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16MemImm5(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT16MemImm5(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Rt = (opCode >> 0) & 7;
|
||||||
|
Rn = (opCode >> 3) & 7;
|
||||||
|
|
||||||
|
switch (inst.Name)
|
||||||
|
{
|
||||||
|
case InstName.Ldr:
|
||||||
|
case InstName.Ldrb:
|
||||||
|
case InstName.Ldrh:
|
||||||
|
IsLoad = true;
|
||||||
|
break;
|
||||||
|
case InstName.Str:
|
||||||
|
case InstName.Strb:
|
||||||
|
case InstName.Strh:
|
||||||
|
IsLoad = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (inst.Name)
|
||||||
|
{
|
||||||
|
case InstName.Str:
|
||||||
|
case InstName.Ldr:
|
||||||
|
Immediate = ((opCode >> 6) & 0x1f) << 2;
|
||||||
|
break;
|
||||||
|
case InstName.Strb:
|
||||||
|
case InstName.Ldrb:
|
||||||
|
Immediate = ((opCode >> 6) & 0x1f);
|
||||||
|
break;
|
||||||
|
case InstName.Strh:
|
||||||
|
case InstName.Ldrh:
|
||||||
|
Immediate = ((opCode >> 6) & 0x1f) << 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
26
ARMeilleure/Decoders/OpCodeT16MemLit.cs
Normal file
26
ARMeilleure/Decoders/OpCodeT16MemLit.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
using ARMeilleure.State;
|
||||||
|
|
||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT16MemLit : OpCodeT16, IOpCode32Mem
|
||||||
|
{
|
||||||
|
public int Rt { get; }
|
||||||
|
public int Rn => RegisterAlias.Aarch32Pc;
|
||||||
|
|
||||||
|
public bool WBack => false;
|
||||||
|
public bool IsLoad => true;
|
||||||
|
public bool Index => true;
|
||||||
|
public bool Add => true;
|
||||||
|
|
||||||
|
public int Immediate { get; }
|
||||||
|
|
||||||
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16MemLit(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT16MemLit(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Rt = (opCode >> 8) & 7;
|
||||||
|
|
||||||
|
Immediate = (opCode & 0xff) << 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
34
ARMeilleure/Decoders/OpCodeT16MemMult.cs
Normal file
34
ARMeilleure/Decoders/OpCodeT16MemMult.cs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
using ARMeilleure.Instructions;
|
||||||
|
using System;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT16MemMult : OpCodeT16, IOpCode32MemMult
|
||||||
|
{
|
||||||
|
public int Rn { get; }
|
||||||
|
public int RegisterMask { get; }
|
||||||
|
public int PostOffset { get; }
|
||||||
|
public bool IsLoad { get; }
|
||||||
|
public int Offset { get; }
|
||||||
|
|
||||||
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16MemMult(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT16MemMult(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
RegisterMask = opCode & 0xff;
|
||||||
|
Rn = (opCode >> 8) & 7;
|
||||||
|
|
||||||
|
int regCount = BitOperations.PopCount((uint)RegisterMask);
|
||||||
|
|
||||||
|
Offset = 0;
|
||||||
|
PostOffset = 4 * regCount;
|
||||||
|
IsLoad = inst.Name switch
|
||||||
|
{
|
||||||
|
InstName.Ldm => true,
|
||||||
|
InstName.Stm => false,
|
||||||
|
_ => throw new InvalidOperationException()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
27
ARMeilleure/Decoders/OpCodeT16MemReg.cs
Normal file
27
ARMeilleure/Decoders/OpCodeT16MemReg.cs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT16MemReg : OpCodeT16, IOpCode32MemReg
|
||||||
|
{
|
||||||
|
public int Rm { get; }
|
||||||
|
public int Rt { get; }
|
||||||
|
public int Rn { get; }
|
||||||
|
|
||||||
|
public bool WBack => false;
|
||||||
|
public bool IsLoad { get; }
|
||||||
|
public bool Index => true;
|
||||||
|
public bool Add => true;
|
||||||
|
|
||||||
|
public int Immediate => throw new System.InvalidOperationException();
|
||||||
|
|
||||||
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16MemReg(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT16MemReg(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Rt = (opCode >> 0) & 7;
|
||||||
|
Rn = (opCode >> 3) & 7;
|
||||||
|
Rm = (opCode >> 6) & 7;
|
||||||
|
|
||||||
|
IsLoad = ((opCode >> 9) & 7) >= 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
28
ARMeilleure/Decoders/OpCodeT16MemSp.cs
Normal file
28
ARMeilleure/Decoders/OpCodeT16MemSp.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
using ARMeilleure.State;
|
||||||
|
|
||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT16MemSp : OpCodeT16, IOpCode32Mem
|
||||||
|
{
|
||||||
|
public int Rt { get; }
|
||||||
|
public int Rn => RegisterAlias.Aarch32Sp;
|
||||||
|
|
||||||
|
public bool WBack => false;
|
||||||
|
public bool IsLoad { get; }
|
||||||
|
public bool Index => true;
|
||||||
|
public bool Add => true;
|
||||||
|
|
||||||
|
public int Immediate { get; }
|
||||||
|
|
||||||
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16MemSp(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT16MemSp(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Rt = (opCode >> 8) & 7;
|
||||||
|
|
||||||
|
IsLoad = ((opCode >> 11) & 1) != 0;
|
||||||
|
|
||||||
|
Immediate = ((opCode >> 0) & 0xff) << 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
42
ARMeilleure/Decoders/OpCodeT16MemStack.cs
Normal file
42
ARMeilleure/Decoders/OpCodeT16MemStack.cs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
using ARMeilleure.Instructions;
|
||||||
|
using ARMeilleure.State;
|
||||||
|
using System;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT16MemStack : OpCodeT16, IOpCode32MemMult
|
||||||
|
{
|
||||||
|
public int Rn => RegisterAlias.Aarch32Sp;
|
||||||
|
public int RegisterMask { get; }
|
||||||
|
public int PostOffset { get; }
|
||||||
|
public bool IsLoad { get; }
|
||||||
|
public int Offset { get; }
|
||||||
|
|
||||||
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16MemStack(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT16MemStack(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
int extra = (opCode >> 8) & 1;
|
||||||
|
int regCount = BitOperations.PopCount((uint)opCode & 0x1ff);
|
||||||
|
|
||||||
|
switch (inst.Name)
|
||||||
|
{
|
||||||
|
case InstName.Push:
|
||||||
|
RegisterMask = (opCode & 0xff) | (extra << 14);
|
||||||
|
IsLoad = false;
|
||||||
|
Offset = -4 * regCount;
|
||||||
|
PostOffset = -4 * regCount;
|
||||||
|
break;
|
||||||
|
case InstName.Pop:
|
||||||
|
RegisterMask = (opCode & 0xff) | (extra << 15);
|
||||||
|
IsLoad = true;
|
||||||
|
Offset = 0;
|
||||||
|
PostOffset = 4 * regCount;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
24
ARMeilleure/Decoders/OpCodeT16ShiftImm.cs
Normal file
24
ARMeilleure/Decoders/OpCodeT16ShiftImm.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT16ShiftImm : OpCodeT16, IOpCode32AluRsImm
|
||||||
|
{
|
||||||
|
public int Rd { get; }
|
||||||
|
public int Rn { get; }
|
||||||
|
public int Rm { get; }
|
||||||
|
|
||||||
|
public int Immediate { get; }
|
||||||
|
public ShiftType ShiftType { get; }
|
||||||
|
|
||||||
|
public bool? SetFlags => null;
|
||||||
|
|
||||||
|
public static new OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16ShiftImm(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT16ShiftImm(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Rd = (opCode >> 0) & 0x7;
|
||||||
|
Rm = (opCode >> 3) & 0x7;
|
||||||
|
Immediate = (opCode >> 6) & 0x1F;
|
||||||
|
ShiftType = (ShiftType)((opCode >> 11) & 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
27
ARMeilleure/Decoders/OpCodeT16ShiftReg.cs
Normal file
27
ARMeilleure/Decoders/OpCodeT16ShiftReg.cs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT16ShiftReg : OpCodeT16, IOpCode32AluRsReg
|
||||||
|
{
|
||||||
|
public int Rm { get; }
|
||||||
|
public int Rs { get; }
|
||||||
|
public int Rd { get; }
|
||||||
|
|
||||||
|
public int Rn { get; }
|
||||||
|
|
||||||
|
public ShiftType ShiftType { get; }
|
||||||
|
|
||||||
|
public bool? SetFlags => null;
|
||||||
|
|
||||||
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16ShiftReg(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT16ShiftReg(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Rd = (opCode >> 0) & 7;
|
||||||
|
Rm = (opCode >> 0) & 7;
|
||||||
|
Rn = (opCode >> 3) & 7;
|
||||||
|
Rs = (opCode >> 3) & 7;
|
||||||
|
|
||||||
|
ShiftType = (ShiftType)(((opCode >> 6) & 1) | ((opCode >> 7) & 2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
24
ARMeilleure/Decoders/OpCodeT16SpRel.cs
Normal file
24
ARMeilleure/Decoders/OpCodeT16SpRel.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
using ARMeilleure.State;
|
||||||
|
|
||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT16SpRel : OpCodeT16, IOpCode32AluImm
|
||||||
|
{
|
||||||
|
public int Rd { get; }
|
||||||
|
public int Rn => RegisterAlias.Aarch32Sp;
|
||||||
|
|
||||||
|
public bool? SetFlags => false;
|
||||||
|
|
||||||
|
public int Immediate { get; }
|
||||||
|
|
||||||
|
public bool IsRotated => false;
|
||||||
|
|
||||||
|
public static new OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16SpRel(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT16SpRel(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Rd = (opCode >> 8) & 0x7;
|
||||||
|
Immediate = ((opCode >> 0) & 0xff) << 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
14
ARMeilleure/Decoders/OpCodeT32.cs
Normal file
14
ARMeilleure/Decoders/OpCodeT32.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT32 : OpCode32
|
||||||
|
{
|
||||||
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT32(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT32(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Cond = Condition.Al;
|
||||||
|
|
||||||
|
OpCodeSizeInBytes = 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
ARMeilleure/Decoders/OpCodeT32Alu.cs
Normal file
20
ARMeilleure/Decoders/OpCodeT32Alu.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT32Alu : OpCodeT32, IOpCode32Alu
|
||||||
|
{
|
||||||
|
public int Rd { get; }
|
||||||
|
public int Rn { get; }
|
||||||
|
|
||||||
|
public bool? SetFlags { get; }
|
||||||
|
|
||||||
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT32Alu(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT32Alu(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Rd = (opCode >> 8) & 0xf;
|
||||||
|
Rn = (opCode >> 16) & 0xf;
|
||||||
|
|
||||||
|
SetFlags = ((opCode >> 20) & 1) != 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
38
ARMeilleure/Decoders/OpCodeT32AluImm.cs
Normal file
38
ARMeilleure/Decoders/OpCodeT32AluImm.cs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
using ARMeilleure.Common;
|
||||||
|
using System.Runtime.Intrinsics;
|
||||||
|
|
||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT32AluImm : OpCodeT32Alu, IOpCode32AluImm
|
||||||
|
{
|
||||||
|
public int Immediate { get; }
|
||||||
|
|
||||||
|
public bool IsRotated { get; }
|
||||||
|
|
||||||
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT32AluImm(inst, address, opCode);
|
||||||
|
|
||||||
|
private static readonly Vector128<int> _factor = Vector128.Create(1, 0x00010001, 0x01000100, 0x01010101);
|
||||||
|
|
||||||
|
public OpCodeT32AluImm(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
int imm8 = (opCode >> 0) & 0xff;
|
||||||
|
int imm3 = (opCode >> 12) & 7;
|
||||||
|
int imm1 = (opCode >> 26) & 1;
|
||||||
|
|
||||||
|
int imm12 = imm8 | (imm3 << 8) | (imm1 << 11);
|
||||||
|
|
||||||
|
if ((imm12 >> 10) == 0)
|
||||||
|
{
|
||||||
|
Immediate = imm8 * _factor.GetElement((imm12 >> 8) & 3);
|
||||||
|
IsRotated = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int shift = imm12 >> 7;
|
||||||
|
|
||||||
|
Immediate = BitUtils.RotateRight(0x80 | (imm12 & 0x7f), shift, 32);
|
||||||
|
IsRotated = shift != 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
ARMeilleure/Decoders/OpCodeT32AluRsImm.cs
Normal file
20
ARMeilleure/Decoders/OpCodeT32AluRsImm.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT32AluRsImm : OpCodeT32Alu, IOpCode32AluRsImm
|
||||||
|
{
|
||||||
|
public int Rm { get; }
|
||||||
|
public int Immediate { get; }
|
||||||
|
|
||||||
|
public ShiftType ShiftType { get; }
|
||||||
|
|
||||||
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT32AluRsImm(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT32AluRsImm(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Rm = (opCode >> 0) & 0xf;
|
||||||
|
Immediate = ((opCode >> 6) & 3) | ((opCode >> 10) & 0x1c);
|
||||||
|
|
||||||
|
ShiftType = (ShiftType)((opCode >> 4) & 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
27
ARMeilleure/Decoders/OpCodeT32BImm20.cs
Normal file
27
ARMeilleure/Decoders/OpCodeT32BImm20.cs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT32BImm20 : OpCodeT32, IOpCode32BImm
|
||||||
|
{
|
||||||
|
public long Immediate { get; }
|
||||||
|
|
||||||
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT32BImm20(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT32BImm20(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
uint pc = GetPc();
|
||||||
|
|
||||||
|
int imm11 = (opCode >> 0) & 0x7ff;
|
||||||
|
int j2 = (opCode >> 11) & 1;
|
||||||
|
int j1 = (opCode >> 13) & 1;
|
||||||
|
int imm6 = (opCode >> 16) & 0x3f;
|
||||||
|
int s = (opCode >> 26) & 1;
|
||||||
|
|
||||||
|
int imm32 = imm11 | (imm6 << 11) | (j1 << 17) | (j2 << 18) | (s << 19);
|
||||||
|
imm32 = (imm32 << 13) >> 12;
|
||||||
|
|
||||||
|
Immediate = pc + imm32;
|
||||||
|
|
||||||
|
Cond = (Condition)((opCode >> 22) & 0xf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
35
ARMeilleure/Decoders/OpCodeT32BImm24.cs
Normal file
35
ARMeilleure/Decoders/OpCodeT32BImm24.cs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
using ARMeilleure.Instructions;
|
||||||
|
|
||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT32BImm24 : OpCodeT32, IOpCode32BImm
|
||||||
|
{
|
||||||
|
public long Immediate { get; }
|
||||||
|
|
||||||
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT32BImm24(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT32BImm24(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
uint pc = GetPc();
|
||||||
|
|
||||||
|
if (inst.Name == InstName.Blx)
|
||||||
|
{
|
||||||
|
pc &= ~3u;
|
||||||
|
}
|
||||||
|
|
||||||
|
int imm11 = (opCode >> 0) & 0x7ff;
|
||||||
|
int j2 = (opCode >> 11) & 1;
|
||||||
|
int j1 = (opCode >> 13) & 1;
|
||||||
|
int imm10 = (opCode >> 16) & 0x3ff;
|
||||||
|
int s = (opCode >> 26) & 1;
|
||||||
|
|
||||||
|
int i1 = j1 ^ s ^ 1;
|
||||||
|
int i2 = j2 ^ s ^ 1;
|
||||||
|
|
||||||
|
int imm32 = imm11 | (imm10 << 11) | (i2 << 21) | (i1 << 22) | (s << 23);
|
||||||
|
imm32 = (imm32 << 9) >> 8;
|
||||||
|
|
||||||
|
Immediate = pc + imm32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
25
ARMeilleure/Decoders/OpCodeT32MemImm12.cs
Normal file
25
ARMeilleure/Decoders/OpCodeT32MemImm12.cs
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT32MemImm12 : OpCodeT32, IOpCode32Mem
|
||||||
|
{
|
||||||
|
public int Rt { get; }
|
||||||
|
public int Rn { get; }
|
||||||
|
public bool WBack => false;
|
||||||
|
public bool IsLoad { get; }
|
||||||
|
public bool Index => true;
|
||||||
|
public bool Add => true;
|
||||||
|
public int Immediate { get; }
|
||||||
|
|
||||||
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT32MemImm12(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT32MemImm12(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Rt = (opCode >> 12) & 0xf;
|
||||||
|
Rn = (opCode >> 16) & 0xf;
|
||||||
|
|
||||||
|
Immediate = opCode & 0xfff;
|
||||||
|
|
||||||
|
IsLoad = ((opCode >> 20) & 1) != 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
29
ARMeilleure/Decoders/OpCodeT32MemImm8.cs
Normal file
29
ARMeilleure/Decoders/OpCodeT32MemImm8.cs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
namespace ARMeilleure.Decoders
|
||||||
|
{
|
||||||
|
class OpCodeT32MemImm8 : OpCodeT32, IOpCode32Mem
|
||||||
|
{
|
||||||
|
public int Rt { get; }
|
||||||
|
public int Rn { get; }
|
||||||
|
public bool WBack { get; }
|
||||||
|
public bool IsLoad { get; }
|
||||||
|
public bool Index { get; }
|
||||||
|
public bool Add { get; }
|
||||||
|
public int Immediate { get; }
|
||||||
|
|
||||||
|
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT32MemImm8(inst, address, opCode);
|
||||||
|
|
||||||
|
public OpCodeT32MemImm8(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
|
{
|
||||||
|
Rt = (opCode >> 12) & 0xf;
|
||||||
|
Rn = (opCode >> 16) & 0xf;
|
||||||
|
|
||||||
|
Index = ((opCode >> 10) & 1) != 0;
|
||||||
|
Add = ((opCode >> 9) & 1) != 0;
|
||||||
|
WBack = ((opCode >> 8) & 1) != 0;
|
||||||
|
|
||||||
|
Immediate = opCode & 0xff;
|
||||||
|
|
||||||
|
IsLoad = ((opCode >> 20) & 1) != 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
using ARMeilleure.Instructions;
|
using ARMeilleure.Instructions;
|
||||||
using ARMeilleure.State;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Numerics;
|
||||||
|
|
||||||
namespace ARMeilleure.Decoders
|
namespace ARMeilleure.Decoders
|
||||||
{
|
{
|
||||||
@ -29,9 +29,9 @@ namespace ARMeilleure.Decoders
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<InstInfo> AllInstA32 = new List<InstInfo>();
|
private static List<InstInfo> AllInstA32 = new();
|
||||||
private static List<InstInfo> AllInstT32 = new List<InstInfo>();
|
private static List<InstInfo> AllInstT32 = new();
|
||||||
private static List<InstInfo> AllInstA64 = new List<InstInfo>();
|
private static List<InstInfo> AllInstA64 = new();
|
||||||
|
|
||||||
private static InstInfo[][] InstA32FastLookup = new InstInfo[FastLookupSize][];
|
private static InstInfo[][] InstA32FastLookup = new InstInfo[FastLookupSize][];
|
||||||
private static InstInfo[][] InstT32FastLookup = new InstInfo[FastLookupSize][];
|
private static InstInfo[][] InstT32FastLookup = new InstInfo[FastLookupSize][];
|
||||||
@ -628,7 +628,7 @@ namespace ARMeilleure.Decoders
|
|||||||
SetA64("0>001110<<0xxxxx011110xxxxxxxxxx", InstName.Zip2_V, InstEmit.Zip2_V, OpCodeSimdReg.Create);
|
SetA64("0>001110<<0xxxxx011110xxxxxxxxxx", InstName.Zip2_V, InstEmit.Zip2_V, OpCodeSimdReg.Create);
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region "OpCode Table (AArch32)"
|
#region "OpCode Table (AArch32, A32)"
|
||||||
// Base
|
// Base
|
||||||
SetA32("<<<<0010101xxxxxxxxxxxxxxxxxxxxx", InstName.Adc, InstEmit32.Adc, OpCode32AluImm.Create);
|
SetA32("<<<<0010101xxxxxxxxxxxxxxxxxxxxx", InstName.Adc, InstEmit32.Adc, OpCode32AluImm.Create);
|
||||||
SetA32("<<<<0000101xxxxxxxxxxxxxxxx0xxxx", InstName.Adc, InstEmit32.Adc, OpCode32AluRsImm.Create);
|
SetA32("<<<<0000101xxxxxxxxxxxxxxxx0xxxx", InstName.Adc, InstEmit32.Adc, OpCode32AluRsImm.Create);
|
||||||
@ -649,11 +649,11 @@ namespace ARMeilleure.Decoders
|
|||||||
SetA32("1111101xxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Blx, InstEmit32.Blx, OpCode32BImm.Create);
|
SetA32("1111101xxxxxxxxxxxxxxxxxxxxxxxxx", InstName.Blx, InstEmit32.Blx, OpCode32BImm.Create);
|
||||||
SetA32("<<<<000100101111111111110011xxxx", InstName.Blx, InstEmit32.Blxr, OpCode32BReg.Create);
|
SetA32("<<<<000100101111111111110011xxxx", InstName.Blx, InstEmit32.Blxr, OpCode32BReg.Create);
|
||||||
SetA32("<<<<000100101111111111110001xxxx", InstName.Bx, InstEmit32.Bx, OpCode32BReg.Create);
|
SetA32("<<<<000100101111111111110001xxxx", InstName.Bx, InstEmit32.Bx, OpCode32BReg.Create);
|
||||||
SetT32("xxxxxxxxxxxxxxxx010001110xxxx000", InstName.Bx, InstEmit32.Bx, OpCodeT16BReg.Create);
|
|
||||||
SetA32("11110101011111111111000000011111", InstName.Clrex, InstEmit32.Clrex, OpCode32.Create);
|
SetA32("11110101011111111111000000011111", InstName.Clrex, InstEmit32.Clrex, OpCode32.Create);
|
||||||
SetA32("<<<<000101101111xxxx11110001xxxx", InstName.Clz, InstEmit32.Clz, OpCode32AluReg.Create);
|
SetA32("<<<<000101101111xxxx11110001xxxx", InstName.Clz, InstEmit32.Clz, OpCode32AluReg.Create);
|
||||||
SetA32("<<<<00110111xxxx0000xxxxxxxxxxxx", InstName.Cmn, InstEmit32.Cmn, OpCode32AluImm.Create);
|
SetA32("<<<<00110111xxxx0000xxxxxxxxxxxx", InstName.Cmn, InstEmit32.Cmn, OpCode32AluImm.Create);
|
||||||
SetA32("<<<<00010111xxxx0000xxxxxxx0xxxx", InstName.Cmn, InstEmit32.Cmn, OpCode32AluRsImm.Create);
|
SetA32("<<<<00010111xxxx0000xxxxxxx0xxxx", InstName.Cmn, InstEmit32.Cmn, OpCode32AluRsImm.Create);
|
||||||
|
SetA32("<<<<00010111xxxx0000xxxx0xx1xxxx", InstName.Cmn, InstEmit32.Cmn, OpCode32AluRsReg.Create);
|
||||||
SetA32("<<<<00110101xxxx0000xxxxxxxxxxxx", InstName.Cmp, InstEmit32.Cmp, OpCode32AluImm.Create);
|
SetA32("<<<<00110101xxxx0000xxxxxxxxxxxx", InstName.Cmp, InstEmit32.Cmp, OpCode32AluImm.Create);
|
||||||
SetA32("<<<<00010101xxxx0000xxxxxxx0xxxx", InstName.Cmp, InstEmit32.Cmp, OpCode32AluRsImm.Create);
|
SetA32("<<<<00010101xxxx0000xxxxxxx0xxxx", InstName.Cmp, InstEmit32.Cmp, OpCode32AluRsImm.Create);
|
||||||
SetA32("<<<<00010101xxxx0000xxxx0xx1xxxx", InstName.Cmp, InstEmit32.Cmp, OpCode32AluRsReg.Create);
|
SetA32("<<<<00010101xxxx0000xxxx0xx1xxxx", InstName.Cmp, InstEmit32.Cmp, OpCode32AluRsReg.Create);
|
||||||
@ -701,10 +701,10 @@ namespace ARMeilleure.Decoders
|
|||||||
SetA32("<<<<0001101x0000xxxxxxxxxxx0xxxx", InstName.Mov, InstEmit32.Mov, OpCode32AluRsImm.Create);
|
SetA32("<<<<0001101x0000xxxxxxxxxxx0xxxx", InstName.Mov, InstEmit32.Mov, OpCode32AluRsImm.Create);
|
||||||
SetA32("<<<<0001101x0000xxxxxxxx0xx1xxxx", InstName.Mov, InstEmit32.Mov, OpCode32AluRsReg.Create);
|
SetA32("<<<<0001101x0000xxxxxxxx0xx1xxxx", InstName.Mov, InstEmit32.Mov, OpCode32AluRsReg.Create);
|
||||||
SetA32("<<<<00110000xxxxxxxxxxxxxxxxxxxx", InstName.Mov, InstEmit32.Mov, OpCode32AluImm16.Create);
|
SetA32("<<<<00110000xxxxxxxxxxxxxxxxxxxx", InstName.Mov, InstEmit32.Mov, OpCode32AluImm16.Create);
|
||||||
SetT32("xxxxxxxxxxxxxxxx00100xxxxxxxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT16AluImm8.Create);
|
|
||||||
SetA32("<<<<00110100xxxxxxxxxxxxxxxxxxxx", InstName.Movt, InstEmit32.Movt, OpCode32AluImm16.Create);
|
SetA32("<<<<00110100xxxxxxxxxxxxxxxxxxxx", InstName.Movt, InstEmit32.Movt, OpCode32AluImm16.Create);
|
||||||
SetA32("<<<<1110xxx1xxxxxxxx111xxxx1xxxx", InstName.Mrc, InstEmit32.Mrc, OpCode32System.Create);
|
SetA32("<<<<1110xxx1xxxxxxxx111xxxx1xxxx", InstName.Mrc, InstEmit32.Mrc, OpCode32System.Create);
|
||||||
SetA32("<<<<11000101xxxxxxxx111xxxxxxxxx", InstName.Mrrc, InstEmit32.Mrrc, OpCode32System.Create);
|
SetA32("<<<<11000101xxxxxxxx111xxxxxxxxx", InstName.Mrrc, InstEmit32.Mrrc, OpCode32System.Create);
|
||||||
|
SetA32("<<<<00010x001111xxxx000000000000", InstName.Mrs, InstEmit32.Mrs, OpCode32Mrs.Create);
|
||||||
SetA32("<<<<00010x10xxxx111100000000xxxx", InstName.Msr, InstEmit32.Msr, OpCode32MsrReg.Create);
|
SetA32("<<<<00010x10xxxx111100000000xxxx", InstName.Msr, InstEmit32.Msr, OpCode32MsrReg.Create);
|
||||||
SetA32("<<<<0000000xxxxx0000xxxx1001xxxx", InstName.Mul, InstEmit32.Mul, OpCode32AluMla.Create);
|
SetA32("<<<<0000000xxxxx0000xxxx1001xxxx", InstName.Mul, InstEmit32.Mul, OpCode32AluMla.Create);
|
||||||
SetA32("<<<<0011111x0000xxxxxxxxxxxxxxxx", InstName.Mvn, InstEmit32.Mvn, OpCode32AluImm.Create);
|
SetA32("<<<<0011111x0000xxxxxxxxxxxxxxxx", InstName.Mvn, InstEmit32.Mvn, OpCode32AluImm.Create);
|
||||||
@ -732,6 +732,8 @@ namespace ARMeilleure.Decoders
|
|||||||
SetA32("<<<<0000110xxxxxxxxxxxxx0xx1xxxx", InstName.Sbc, InstEmit32.Sbc, OpCode32AluRsReg.Create);
|
SetA32("<<<<0000110xxxxxxxxxxxxx0xx1xxxx", InstName.Sbc, InstEmit32.Sbc, OpCode32AluRsReg.Create);
|
||||||
SetA32("<<<<0111101xxxxxxxxxxxxxx101xxxx", InstName.Sbfx, InstEmit32.Sbfx, OpCode32AluBf.Create);
|
SetA32("<<<<0111101xxxxxxxxxxxxxx101xxxx", InstName.Sbfx, InstEmit32.Sbfx, OpCode32AluBf.Create);
|
||||||
SetA32("<<<<01110001xxxx1111xxxx0001xxxx", InstName.Sdiv, InstEmit32.Sdiv, OpCode32AluMla.Create);
|
SetA32("<<<<01110001xxxx1111xxxx0001xxxx", InstName.Sdiv, InstEmit32.Sdiv, OpCode32AluMla.Create);
|
||||||
|
SetA32("<<<<01100011xxxxxxxx11111001xxxx", InstName.Shadd8, InstEmit32.Shadd8, OpCode32AluReg.Create);
|
||||||
|
SetA32("<<<<01100011xxxxxxxx11111111xxxx", InstName.Shsub8, InstEmit32.Shsub8, OpCode32AluReg.Create);
|
||||||
SetA32("<<<<00010000xxxxxxxxxxxx1xx0xxxx", InstName.Smla__, InstEmit32.Smla__, OpCode32AluMla.Create);
|
SetA32("<<<<00010000xxxxxxxxxxxx1xx0xxxx", InstName.Smla__, InstEmit32.Smla__, OpCode32AluMla.Create);
|
||||||
SetA32("<<<<0000111xxxxxxxxxxxxx1001xxxx", InstName.Smlal, InstEmit32.Smlal, OpCode32AluUmull.Create);
|
SetA32("<<<<0000111xxxxxxxxxxxxx1001xxxx", InstName.Smlal, InstEmit32.Smlal, OpCode32AluUmull.Create);
|
||||||
SetA32("<<<<00010100xxxxxxxxxxxx1xx0xxxx", InstName.Smlal__, InstEmit32.Smlal__, OpCode32AluUmull.Create);
|
SetA32("<<<<00010100xxxxxxxxxxxx1xx0xxxx", InstName.Smlal__, InstEmit32.Smlal__, OpCode32AluUmull.Create);
|
||||||
@ -780,6 +782,7 @@ namespace ARMeilleure.Decoders
|
|||||||
SetA32("<<<<0111111xxxxxxxxxxxxxx101xxxx", InstName.Ubfx, InstEmit32.Ubfx, OpCode32AluBf.Create);
|
SetA32("<<<<0111111xxxxxxxxxxxxxx101xxxx", InstName.Ubfx, InstEmit32.Ubfx, OpCode32AluBf.Create);
|
||||||
SetA32("<<<<01110011xxxx1111xxxx0001xxxx", InstName.Udiv, InstEmit32.Udiv, OpCode32AluMla.Create);
|
SetA32("<<<<01110011xxxx1111xxxx0001xxxx", InstName.Udiv, InstEmit32.Udiv, OpCode32AluMla.Create);
|
||||||
SetA32("<<<<01100111xxxxxxxx11111001xxxx", InstName.Uhadd8, InstEmit32.Uhadd8, OpCode32AluReg.Create);
|
SetA32("<<<<01100111xxxxxxxx11111001xxxx", InstName.Uhadd8, InstEmit32.Uhadd8, OpCode32AluReg.Create);
|
||||||
|
SetA32("<<<<01100111xxxxxxxx11111111xxxx", InstName.Uhsub8, InstEmit32.Uhsub8, OpCode32AluReg.Create);
|
||||||
SetA32("<<<<00000100xxxxxxxxxxxx1001xxxx", InstName.Umaal, InstEmit32.Umaal, OpCode32AluUmull.Create);
|
SetA32("<<<<00000100xxxxxxxxxxxx1001xxxx", InstName.Umaal, InstEmit32.Umaal, OpCode32AluUmull.Create);
|
||||||
SetA32("<<<<0000101xxxxxxxxxxxxx1001xxxx", InstName.Umlal, InstEmit32.Umlal, OpCode32AluUmull.Create);
|
SetA32("<<<<0000101xxxxxxxxxxxxx1001xxxx", InstName.Umlal, InstEmit32.Umlal, OpCode32AluUmull.Create);
|
||||||
SetA32("<<<<0000100xxxxxxxxxxxxx1001xxxx", InstName.Umull, InstEmit32.Umull, OpCode32AluUmull.Create);
|
SetA32("<<<<0000100xxxxxxxxxxxxx1001xxxx", InstName.Umull, InstEmit32.Umull, OpCode32AluUmull.Create);
|
||||||
@ -790,193 +793,335 @@ namespace ARMeilleure.Decoders
|
|||||||
SetA32("<<<<01101111xxxxxxxxxx000111xxxx", InstName.Uxth, InstEmit32.Uxth, OpCode32AluUx.Create);
|
SetA32("<<<<01101111xxxxxxxxxx000111xxxx", InstName.Uxth, InstEmit32.Uxth, OpCode32AluUx.Create);
|
||||||
|
|
||||||
// FP & SIMD
|
// FP & SIMD
|
||||||
SetA32("111100111x110000xxx0001101x0xxx0", InstName.Aesd_V, InstEmit32.Aesd_V, OpCode32Simd.Create);
|
SetA32("111100111x110000xxx0001101x0xxx0", InstName.Aesd_V, InstEmit32.Aesd_V, OpCode32Simd.Create);
|
||||||
SetA32("111100111x110000xxx0001100x0xxx0", InstName.Aese_V, InstEmit32.Aese_V, OpCode32Simd.Create);
|
SetA32("111100111x110000xxx0001100x0xxx0", InstName.Aese_V, InstEmit32.Aese_V, OpCode32Simd.Create);
|
||||||
SetA32("111100111x110000xxx0001111x0xxx0", InstName.Aesimc_V, InstEmit32.Aesimc_V, OpCode32Simd.Create);
|
SetA32("111100111x110000xxx0001111x0xxx0", InstName.Aesimc_V, InstEmit32.Aesimc_V, OpCode32Simd.Create);
|
||||||
SetA32("111100111x110000xxx0001110x0xxx0", InstName.Aesmc_V, InstEmit32.Aesmc_V, OpCode32Simd.Create);
|
SetA32("111100111x110000xxx0001110x0xxx0", InstName.Aesmc_V, InstEmit32.Aesmc_V, OpCode32Simd.Create);
|
||||||
SetA32("1111001x0x<<xxxxxxxx0111xxx0xxxx", InstName.Vabd, InstEmit32.Vabd_I, OpCode32SimdReg.Create);
|
SetA32("111100110x00xxx0xxx01100x1x0xxx0", InstName.Sha256h_V, InstEmit32.Sha256h_V, OpCode32SimdReg.Create);
|
||||||
SetA32("1111001x1x<<xxxxxxxx0111x0x0xxxx", InstName.Vabdl, InstEmit32.Vabdl_I, OpCode32SimdRegLong.Create);
|
SetA32("111100110x01xxx0xxx01100x1x0xxx0", InstName.Sha256h2_V, InstEmit32.Sha256h2_V, OpCode32SimdReg.Create);
|
||||||
SetA32("<<<<11101x110000xxxx101x11x0xxxx", InstName.Vabs, InstEmit32.Vabs_S, OpCode32SimdS.Create);
|
SetA32("111100111x111010xxx0001111x0xxx0", InstName.Sha256su0_V, InstEmit32.Sha256su0_V, OpCode32Simd.Create);
|
||||||
SetA32("111100111x11<<01xxxx00110xx0xxxx", InstName.Vabs, InstEmit32.Vabs_V, OpCode32SimdCmpZ.Create);
|
SetA32("111100110x10xxx0xxx01100x1x0xxx0", InstName.Sha256su1_V, InstEmit32.Sha256su1_V, OpCode32SimdReg.Create);
|
||||||
SetA32("111100111x111001xxxx01110xx0xxxx", InstName.Vabs, InstEmit32.Vabs_V, OpCode32SimdCmpZ.Create);
|
SetA32("1111001x0x<<xxxxxxxx0111xxx0xxxx", InstName.Vabd, InstEmit32.Vabd_I, OpCode32SimdReg.Create);
|
||||||
SetA32("111100100xxxxxxxxxxx1000xxx0xxxx", InstName.Vadd, InstEmit32.Vadd_I, OpCode32SimdReg.Create);
|
SetA32("1111001x1x<<xxxxxxxx0111x0x0xxxx", InstName.Vabdl, InstEmit32.Vabdl_I, OpCode32SimdRegLong.Create);
|
||||||
SetA32("<<<<11100x11xxxxxxxx101xx0x0xxxx", InstName.Vadd, InstEmit32.Vadd_S, OpCode32SimdRegS.Create);
|
SetA32("<<<<11101x110000xxxx101x11x0xxxx", InstName.Vabs, InstEmit32.Vabs_S, OpCode32SimdS.Create);
|
||||||
SetA32("111100100x00xxxxxxxx1101xxx0xxxx", InstName.Vadd, InstEmit32.Vadd_V, OpCode32SimdReg.Create);
|
SetA32("111100111x11<<01xxxx00110xx0xxxx", InstName.Vabs, InstEmit32.Vabs_V, OpCode32SimdCmpZ.Create);
|
||||||
SetA32("1111001x1x<<xxxxxxxx0000x0x0xxxx", InstName.Vaddl, InstEmit32.Vaddl_I, OpCode32SimdRegLong.Create);
|
SetA32("111100111x111001xxxx01110xx0xxxx", InstName.Vabs, InstEmit32.Vabs_V, OpCode32SimdCmpZ.Create);
|
||||||
SetA32("1111001x1x<<xxxxxxxx0001x0x0xxxx", InstName.Vaddw, InstEmit32.Vaddw_I, OpCode32SimdRegWide.Create);
|
SetA32("111100100xxxxxxxxxxx1000xxx0xxxx", InstName.Vadd, InstEmit32.Vadd_I, OpCode32SimdReg.Create);
|
||||||
SetA32("111100100x00xxxxxxxx0001xxx1xxxx", InstName.Vand, InstEmit32.Vand_I, OpCode32SimdBinary.Create);
|
SetA32("<<<<11100x11xxxxxxxx101xx0x0xxxx", InstName.Vadd, InstEmit32.Vadd_S, OpCode32SimdRegS.Create);
|
||||||
SetA32("111100100x01xxxxxxxx0001xxx1xxxx", InstName.Vbic, InstEmit32.Vbic_I, OpCode32SimdBinary.Create);
|
SetA32("111100100x00xxxxxxxx1101xxx0xxxx", InstName.Vadd, InstEmit32.Vadd_V, OpCode32SimdReg.Create);
|
||||||
SetA32("1111001x1x000xxxxxxx<<x10x11xxxx", InstName.Vbic, InstEmit32.Vbic_II, OpCode32SimdImm.Create);
|
SetA32("1111001x1x<<xxxxxxxx0000x0x0xxxx", InstName.Vaddl, InstEmit32.Vaddl_I, OpCode32SimdRegLong.Create);
|
||||||
SetA32("111100110x11xxxxxxxx0001xxx1xxxx", InstName.Vbif, InstEmit32.Vbif, OpCode32SimdBinary.Create);
|
SetA32("1111001x1x<<xxxxxxxx0001x0x0xxxx", InstName.Vaddw, InstEmit32.Vaddw_I, OpCode32SimdRegWide.Create);
|
||||||
SetA32("111100110x10xxxxxxxx0001xxx1xxxx", InstName.Vbit, InstEmit32.Vbit, OpCode32SimdBinary.Create);
|
SetA32("111100100x00xxxxxxxx0001xxx1xxxx", InstName.Vand, InstEmit32.Vand_I, OpCode32SimdBinary.Create);
|
||||||
SetA32("111100110x01xxxxxxxx0001xxx1xxxx", InstName.Vbsl, InstEmit32.Vbsl, OpCode32SimdBinary.Create);
|
SetA32("111100100x01xxxxxxxx0001xxx1xxxx", InstName.Vbic, InstEmit32.Vbic_I, OpCode32SimdBinary.Create);
|
||||||
SetA32("111100110x<<xxxxxxxx1000xxx1xxxx", InstName.Vceq, InstEmit32.Vceq_I, OpCode32SimdReg.Create);
|
SetA32("1111001x1x000xxxxxxx<<x10x11xxxx", InstName.Vbic, InstEmit32.Vbic_II, OpCode32SimdImm.Create);
|
||||||
SetA32("111100100x00xxxxxxxx1110xxx0xxxx", InstName.Vceq, InstEmit32.Vceq_V, OpCode32SimdReg.Create);
|
SetA32("111100110x11xxxxxxxx0001xxx1xxxx", InstName.Vbif, InstEmit32.Vbif, OpCode32SimdBinary.Create);
|
||||||
SetA32("111100111x11xx01xxxx0x010xx0xxxx", InstName.Vceq, InstEmit32.Vceq_Z, OpCode32SimdCmpZ.Create);
|
SetA32("111100110x10xxxxxxxx0001xxx1xxxx", InstName.Vbit, InstEmit32.Vbit, OpCode32SimdBinary.Create);
|
||||||
SetA32("1111001x0x<<xxxxxxxx0011xxx1xxxx", InstName.Vcge, InstEmit32.Vcge_I, OpCode32SimdReg.Create);
|
SetA32("111100110x01xxxxxxxx0001xxx1xxxx", InstName.Vbsl, InstEmit32.Vbsl, OpCode32SimdBinary.Create);
|
||||||
SetA32("111100110x00xxxxxxxx1110xxx0xxxx", InstName.Vcge, InstEmit32.Vcge_V, OpCode32SimdReg.Create);
|
SetA32("111100110x<<xxxxxxxx1000xxx1xxxx", InstName.Vceq, InstEmit32.Vceq_I, OpCode32SimdReg.Create);
|
||||||
SetA32("111100111x11xx01xxxx0x001xx0xxxx", InstName.Vcge, InstEmit32.Vcge_Z, OpCode32SimdCmpZ.Create);
|
SetA32("111100100x00xxxxxxxx1110xxx0xxxx", InstName.Vceq, InstEmit32.Vceq_V, OpCode32SimdReg.Create);
|
||||||
SetA32("1111001x0x<<xxxxxxxx0011xxx0xxxx", InstName.Vcgt, InstEmit32.Vcgt_I, OpCode32SimdReg.Create);
|
SetA32("111100111x11xx01xxxx0x010xx0xxxx", InstName.Vceq, InstEmit32.Vceq_Z, OpCode32SimdCmpZ.Create);
|
||||||
SetA32("111100110x10xxxxxxxx1110xxx0xxxx", InstName.Vcgt, InstEmit32.Vcgt_V, OpCode32SimdReg.Create);
|
SetA32("1111001x0x<<xxxxxxxx0011xxx1xxxx", InstName.Vcge, InstEmit32.Vcge_I, OpCode32SimdReg.Create);
|
||||||
SetA32("111100111x11xx01xxxx0x000xx0xxxx", InstName.Vcgt, InstEmit32.Vcgt_Z, OpCode32SimdCmpZ.Create);
|
SetA32("111100110x00xxxxxxxx1110xxx0xxxx", InstName.Vcge, InstEmit32.Vcge_V, OpCode32SimdReg.Create);
|
||||||
SetA32("111100111x11xx01xxxx0x011xx0xxxx", InstName.Vcle, InstEmit32.Vcle_Z, OpCode32SimdCmpZ.Create);
|
SetA32("111100111x11xx01xxxx0x001xx0xxxx", InstName.Vcge, InstEmit32.Vcge_Z, OpCode32SimdCmpZ.Create);
|
||||||
SetA32("111100111x11xx01xxxx0x100xx0xxxx", InstName.Vclt, InstEmit32.Vclt_Z, OpCode32SimdCmpZ.Create);
|
SetA32("1111001x0x<<xxxxxxxx0011xxx0xxxx", InstName.Vcgt, InstEmit32.Vcgt_I, OpCode32SimdReg.Create);
|
||||||
SetA32("<<<<11101x11010xxxxx101x01x0xxxx", InstName.Vcmp, InstEmit32.Vcmp, OpCode32SimdS.Create);
|
SetA32("111100110x10xxxxxxxx1110xxx0xxxx", InstName.Vcgt, InstEmit32.Vcgt_V, OpCode32SimdReg.Create);
|
||||||
SetA32("<<<<11101x11010xxxxx101x11x0xxxx", InstName.Vcmpe, InstEmit32.Vcmpe, OpCode32SimdS.Create);
|
SetA32("111100111x11xx01xxxx0x000xx0xxxx", InstName.Vcgt, InstEmit32.Vcgt_Z, OpCode32SimdCmpZ.Create);
|
||||||
SetA32("111100111x110000xxxx01010xx0xxxx", InstName.Vcnt, InstEmit32.Vcnt, OpCode32SimdCmpZ.Create);
|
SetA32("111100111x11xx01xxxx0x011xx0xxxx", InstName.Vcle, InstEmit32.Vcle_Z, OpCode32SimdCmpZ.Create);
|
||||||
SetA32("<<<<11101x110111xxxx101x11x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_FD, OpCode32SimdS.Create); // FP 32 and 64, scalar.
|
SetA32("111100111x11xx01xxxx0x100xx0xxxx", InstName.Vclt, InstEmit32.Vclt_Z, OpCode32SimdCmpZ.Create);
|
||||||
SetA32("<<<<11101x11110xxxxx101x11x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_FI, OpCode32SimdCvtFI.Create); // FP32 to int.
|
SetA32("<<<<11101x11010xxxxx101x01x0xxxx", InstName.Vcmp, InstEmit32.Vcmp, OpCode32SimdS.Create);
|
||||||
SetA32("<<<<11101x111000xxxx101xx1x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_FI, OpCode32SimdCvtFI.Create); // Int to FP32.
|
SetA32("<<<<11101x11010xxxxx101x11x0xxxx", InstName.Vcmpe, InstEmit32.Vcmpe, OpCode32SimdS.Create);
|
||||||
SetA32("111111101x1111xxxxxx101xx1x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_RM, OpCode32SimdCvtFI.Create); // The many FP32 to int encodings (fp).
|
SetA32("111100111x110000xxxx01010xx0xxxx", InstName.Vcnt, InstEmit32.Vcnt, OpCode32SimdCmpZ.Create);
|
||||||
SetA32("111100111x111011xxxx011xxxx0xxxx", InstName.Vcvt, InstEmit32.Vcvt_V, OpCode32SimdCmpZ.Create); // FP and integer, vector.
|
SetA32("<<<<11101x110111xxxx101x11x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_FD, OpCode32SimdS.Create); // FP 32 and 64, scalar.
|
||||||
SetA32("<<<<11101x00xxxxxxxx101xx0x0xxxx", InstName.Vdiv, InstEmit32.Vdiv_S, OpCode32SimdRegS.Create);
|
SetA32("<<<<11101x11110xxxxx101x11x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_FI, OpCode32SimdCvtFI.Create); // FP32 to int.
|
||||||
SetA32("<<<<11101xx0xxxxxxxx1011x0x10000", InstName.Vdup, InstEmit32.Vdup, OpCode32SimdDupGP.Create);
|
SetA32("<<<<11101x111000xxxx101xx1x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_FI, OpCode32SimdCvtFI.Create); // Int to FP32.
|
||||||
SetA32("111100111x11xxxxxxxx11000xx0xxxx", InstName.Vdup, InstEmit32.Vdup_1, OpCode32SimdDupElem.Create);
|
SetA32("111111101x1111xxxxxx101xx1x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_RM, OpCode32SimdCvtFI.Create); // The many FP32 to int encodings (fp).
|
||||||
SetA32("111100110x00xxxxxxxx0001xxx1xxxx", InstName.Veor, InstEmit32.Veor_I, OpCode32SimdBinary.Create);
|
SetA32("111100111x111011xxxx011xxxx0xxxx", InstName.Vcvt, InstEmit32.Vcvt_V, OpCode32SimdCmpZ.Create); // FP and integer, vector.
|
||||||
SetA32("111100101x11xxxxxxxxxxxxxxx0xxxx", InstName.Vext, InstEmit32.Vext, OpCode32SimdExt.Create);
|
SetA32("<<<<11101x00xxxxxxxx101xx0x0xxxx", InstName.Vdiv, InstEmit32.Vdiv_S, OpCode32SimdRegS.Create);
|
||||||
SetA32("<<<<11101x10xxxxxxxx101xx0x0xxxx", InstName.Vfma, InstEmit32.Vfma_S, OpCode32SimdRegS.Create);
|
SetA32("<<<<11101xx0xxxxxxxx1011x0x10000", InstName.Vdup, InstEmit32.Vdup, OpCode32SimdDupGP.Create);
|
||||||
SetA32("111100100x00xxxxxxxx1100xxx1xxxx", InstName.Vfma, InstEmit32.Vfma_V, OpCode32SimdReg.Create);
|
SetA32("111100111x11xxxxxxxx11000xx0xxxx", InstName.Vdup, InstEmit32.Vdup_1, OpCode32SimdDupElem.Create);
|
||||||
SetA32("<<<<11101x10xxxxxxxx101xx1x0xxxx", InstName.Vfms, InstEmit32.Vfms_S, OpCode32SimdRegS.Create);
|
SetA32("111100110x00xxxxxxxx0001xxx1xxxx", InstName.Veor, InstEmit32.Veor_I, OpCode32SimdBinary.Create);
|
||||||
SetA32("111100100x10xxxxxxxx1100xxx1xxxx", InstName.Vfms, InstEmit32.Vfms_V, OpCode32SimdReg.Create);
|
SetA32("111100101x11xxxxxxxxxxxxxxx0xxxx", InstName.Vext, InstEmit32.Vext, OpCode32SimdExt.Create);
|
||||||
SetA32("<<<<11101x01xxxxxxxx101xx1x0xxxx", InstName.Vfnma, InstEmit32.Vfnma_S, OpCode32SimdRegS.Create);
|
SetA32("<<<<11101x10xxxxxxxx101xx0x0xxxx", InstName.Vfma, InstEmit32.Vfma_S, OpCode32SimdRegS.Create);
|
||||||
SetA32("<<<<11101x01xxxxxxxx101xx0x0xxxx", InstName.Vfnms, InstEmit32.Vfnms_S, OpCode32SimdRegS.Create);
|
SetA32("111100100x00xxxxxxxx1100xxx1xxxx", InstName.Vfma, InstEmit32.Vfma_V, OpCode32SimdReg.Create);
|
||||||
SetA32("1111001x0x<<xxxxxxxx0000xxx0xxxx", InstName.Vhadd, InstEmit32.Vhadd, OpCode32SimdReg.Create);
|
SetA32("<<<<11101x10xxxxxxxx101xx1x0xxxx", InstName.Vfms, InstEmit32.Vfms_S, OpCode32SimdRegS.Create);
|
||||||
SetA32("111101001x10xxxxxxxxxx00xxxxxxxx", InstName.Vld1, InstEmit32.Vld1, OpCode32SimdMemSingle.Create);
|
SetA32("111100100x10xxxxxxxx1100xxx1xxxx", InstName.Vfms, InstEmit32.Vfms_V, OpCode32SimdReg.Create);
|
||||||
SetA32("111101000x10xxxxxxxx0111xxxxxxxx", InstName.Vld1, InstEmit32.Vld1, OpCode32SimdMemPair.Create); // Regs = 1.
|
SetA32("<<<<11101x01xxxxxxxx101xx1x0xxxx", InstName.Vfnma, InstEmit32.Vfnma_S, OpCode32SimdRegS.Create);
|
||||||
SetA32("111101000x10xxxxxxxx1010xxxxxxxx", InstName.Vld1, InstEmit32.Vld1, OpCode32SimdMemPair.Create); // Regs = 2.
|
SetA32("<<<<11101x01xxxxxxxx101xx0x0xxxx", InstName.Vfnms, InstEmit32.Vfnms_S, OpCode32SimdRegS.Create);
|
||||||
SetA32("111101000x10xxxxxxxx0110xxxxxxxx", InstName.Vld1, InstEmit32.Vld1, OpCode32SimdMemPair.Create); // Regs = 3.
|
SetA32("1111001x0x<<xxxxxxxx0000xxx0xxxx", InstName.Vhadd, InstEmit32.Vhadd, OpCode32SimdReg.Create);
|
||||||
SetA32("111101000x10xxxxxxxx0010xxxxxxxx", InstName.Vld1, InstEmit32.Vld1, OpCode32SimdMemPair.Create); // Regs = 4.
|
SetA32("111101001x10xxxxxxxxxx00xxxxxxxx", InstName.Vld1, InstEmit32.Vld1, OpCode32SimdMemSingle.Create);
|
||||||
SetA32("111101001x10xxxxxxxxxx01xxxxxxxx", InstName.Vld2, InstEmit32.Vld2, OpCode32SimdMemSingle.Create);
|
SetA32("111101000x10xxxxxxxx0111xxxxxxxx", InstName.Vld1, InstEmit32.Vld1, OpCode32SimdMemPair.Create); // Regs = 1.
|
||||||
SetA32("111101000x10xxxxxxxx100xxxxxxxxx", InstName.Vld2, InstEmit32.Vld2, OpCode32SimdMemPair.Create); // Regs = 1, inc = 1/2 (itype).
|
SetA32("111101000x10xxxxxxxx1010xxxxxxxx", InstName.Vld1, InstEmit32.Vld1, OpCode32SimdMemPair.Create); // Regs = 2.
|
||||||
SetA32("111101000x10xxxxxxxx0011xxxxxxxx", InstName.Vld2, InstEmit32.Vld2, OpCode32SimdMemPair.Create); // Regs = 2, inc = 2.
|
SetA32("111101000x10xxxxxxxx0110xxxxxxxx", InstName.Vld1, InstEmit32.Vld1, OpCode32SimdMemPair.Create); // Regs = 3.
|
||||||
SetA32("111101001x10xxxxxxxxxx10xxxxxxxx", InstName.Vld3, InstEmit32.Vld3, OpCode32SimdMemSingle.Create);
|
SetA32("111101000x10xxxxxxxx0010xxxxxxxx", InstName.Vld1, InstEmit32.Vld1, OpCode32SimdMemPair.Create); // Regs = 4.
|
||||||
SetA32("111101000x10xxxxxxxx010xxxxxxxxx", InstName.Vld3, InstEmit32.Vld3, OpCode32SimdMemPair.Create); // Inc = 1/2 (itype).
|
SetA32("111101001x10xxxxxxxxxx01xxxxxxxx", InstName.Vld2, InstEmit32.Vld2, OpCode32SimdMemSingle.Create);
|
||||||
SetA32("111101001x10xxxxxxxxxx11xxxxxxxx", InstName.Vld4, InstEmit32.Vld4, OpCode32SimdMemSingle.Create);
|
SetA32("111101000x10xxxxxxxx100xxxxxxxxx", InstName.Vld2, InstEmit32.Vld2, OpCode32SimdMemPair.Create); // Regs = 1, inc = 1/2 (itype).
|
||||||
SetA32("111101000x10xxxxxxxx000xxxxxxxxx", InstName.Vld4, InstEmit32.Vld4, OpCode32SimdMemPair.Create); // Inc = 1/2 (itype).
|
SetA32("111101000x10xxxxxxxx0011xxxxxxxx", InstName.Vld2, InstEmit32.Vld2, OpCode32SimdMemPair.Create); // Regs = 2, inc = 2.
|
||||||
SetA32("<<<<11001x01xxxxxxxx1011xxxxxxx0", InstName.Vldm, InstEmit32.Vldm, OpCode32SimdMemMult.Create);
|
SetA32("111101001x10xxxxxxxxxx10xxxxxxxx", InstName.Vld3, InstEmit32.Vld3, OpCode32SimdMemSingle.Create);
|
||||||
SetA32("<<<<11001x11xxxxxxxx1011xxxxxxx0", InstName.Vldm, InstEmit32.Vldm, OpCode32SimdMemMult.Create);
|
SetA32("111101000x10xxxxxxxx010xxxxxxxxx", InstName.Vld3, InstEmit32.Vld3, OpCode32SimdMemPair.Create); // Inc = 1/2 (itype).
|
||||||
SetA32("<<<<11010x11xxxxxxxx1011xxxxxxx0", InstName.Vldm, InstEmit32.Vldm, OpCode32SimdMemMult.Create);
|
SetA32("111101001x10xxxxxxxxxx11xxxxxxxx", InstName.Vld4, InstEmit32.Vld4, OpCode32SimdMemSingle.Create);
|
||||||
SetA32("<<<<11001x01xxxxxxxx1010xxxxxxxx", InstName.Vldm, InstEmit32.Vldm, OpCode32SimdMemMult.Create);
|
SetA32("111101000x10xxxxxxxx000xxxxxxxxx", InstName.Vld4, InstEmit32.Vld4, OpCode32SimdMemPair.Create); // Inc = 1/2 (itype).
|
||||||
SetA32("<<<<11001x11xxxxxxxx1010xxxxxxxx", InstName.Vldm, InstEmit32.Vldm, OpCode32SimdMemMult.Create);
|
SetA32("<<<<11001x01xxxxxxxx1011xxxxxxx0", InstName.Vldm, InstEmit32.Vldm, OpCode32SimdMemMult.Create);
|
||||||
SetA32("<<<<11010x11xxxxxxxx1010xxxxxxxx", InstName.Vldm, InstEmit32.Vldm, OpCode32SimdMemMult.Create);
|
SetA32("<<<<11001x11xxxxxxxx1011xxxxxxx0", InstName.Vldm, InstEmit32.Vldm, OpCode32SimdMemMult.Create);
|
||||||
SetA32("<<<<1101xx01xxxxxxxx101xxxxxxxxx", InstName.Vldr, InstEmit32.Vldr, OpCode32SimdMemImm.Create);
|
SetA32("<<<<11010x11xxxxxxxx1011xxxxxxx0", InstName.Vldm, InstEmit32.Vldm, OpCode32SimdMemMult.Create);
|
||||||
SetA32("1111001x0x<<xxxxxxxx0110xxx0xxxx", InstName.Vmax, InstEmit32.Vmax_I, OpCode32SimdReg.Create);
|
SetA32("<<<<11001x01xxxxxxxx1010xxxxxxxx", InstName.Vldm, InstEmit32.Vldm, OpCode32SimdMemMult.Create);
|
||||||
SetA32("111100100x00xxxxxxxx1111xxx0xxxx", InstName.Vmax, InstEmit32.Vmax_V, OpCode32SimdReg.Create);
|
SetA32("<<<<11001x11xxxxxxxx1010xxxxxxxx", InstName.Vldm, InstEmit32.Vldm, OpCode32SimdMemMult.Create);
|
||||||
SetA32("1111001x0x<<xxxxxxxx0110xxx1xxxx", InstName.Vmin, InstEmit32.Vmin_I, OpCode32SimdReg.Create);
|
SetA32("<<<<11010x11xxxxxxxx1010xxxxxxxx", InstName.Vldm, InstEmit32.Vldm, OpCode32SimdMemMult.Create);
|
||||||
SetA32("111100100x10xxxxxxxx1111xxx0xxxx", InstName.Vmin, InstEmit32.Vmin_V, OpCode32SimdReg.Create);
|
SetA32("<<<<1101xx01xxxxxxxx101xxxxxxxxx", InstName.Vldr, InstEmit32.Vldr, OpCode32SimdMemImm.Create);
|
||||||
SetA32("111111101x00xxxxxxxx10>>x0x0xxxx", InstName.Vmaxnm, InstEmit32.Vmaxnm_S, OpCode32SimdRegS.Create);
|
SetA32("1111001x0x<<xxxxxxxx0110xxx0xxxx", InstName.Vmax, InstEmit32.Vmax_I, OpCode32SimdReg.Create);
|
||||||
SetA32("111100110x0xxxxxxxxx1111xxx1xxxx", InstName.Vmaxnm, InstEmit32.Vmaxnm_V, OpCode32SimdReg.Create);
|
SetA32("111100100x00xxxxxxxx1111xxx0xxxx", InstName.Vmax, InstEmit32.Vmax_V, OpCode32SimdReg.Create);
|
||||||
SetA32("111111101x00xxxxxxxx10>>x1x0xxxx", InstName.Vminnm, InstEmit32.Vminnm_S, OpCode32SimdRegS.Create);
|
SetA32("1111001x0x<<xxxxxxxx0110xxx1xxxx", InstName.Vmin, InstEmit32.Vmin_I, OpCode32SimdReg.Create);
|
||||||
SetA32("111100110x1xxxxxxxxx1111xxx1xxxx", InstName.Vminnm, InstEmit32.Vminnm_V, OpCode32SimdReg.Create);
|
SetA32("111100100x10xxxxxxxx1111xxx0xxxx", InstName.Vmin, InstEmit32.Vmin_V, OpCode32SimdReg.Create);
|
||||||
SetA32("1111001x1x<<xxxxxxxx000xx1x0xxxx", InstName.Vmla, InstEmit32.Vmla_1, OpCode32SimdRegElem.Create);
|
SetA32("111111101x00xxxxxxxx10>>x0x0xxxx", InstName.Vmaxnm, InstEmit32.Vmaxnm_S, OpCode32SimdRegS.Create);
|
||||||
SetA32("111100100xxxxxxxxxxx1001xxx0xxxx", InstName.Vmla, InstEmit32.Vmla_I, OpCode32SimdReg.Create);
|
SetA32("111100110x0xxxxxxxxx1111xxx1xxxx", InstName.Vmaxnm, InstEmit32.Vmaxnm_V, OpCode32SimdReg.Create);
|
||||||
SetA32("<<<<11100x00xxxxxxxx101xx0x0xxxx", InstName.Vmla, InstEmit32.Vmla_S, OpCode32SimdRegS.Create);
|
SetA32("111111101x00xxxxxxxx10>>x1x0xxxx", InstName.Vminnm, InstEmit32.Vminnm_S, OpCode32SimdRegS.Create);
|
||||||
SetA32("111100100x00xxxxxxxx1101xxx1xxxx", InstName.Vmla, InstEmit32.Vmla_V, OpCode32SimdReg.Create);
|
SetA32("111100110x1xxxxxxxxx1111xxx1xxxx", InstName.Vminnm, InstEmit32.Vminnm_V, OpCode32SimdReg.Create);
|
||||||
SetA32("1111001x1x<<xxxxxxxx010xx1x0xxxx", InstName.Vmls, InstEmit32.Vmls_1, OpCode32SimdRegElem.Create);
|
SetA32("1111001x1x<<xxxxxxxx000xx1x0xxxx", InstName.Vmla, InstEmit32.Vmla_1, OpCode32SimdRegElem.Create);
|
||||||
SetA32("<<<<11100x00xxxxxxxx101xx1x0xxxx", InstName.Vmls, InstEmit32.Vmls_S, OpCode32SimdRegS.Create);
|
SetA32("111100100xxxxxxxxxxx1001xxx0xxxx", InstName.Vmla, InstEmit32.Vmla_I, OpCode32SimdReg.Create);
|
||||||
SetA32("111100100x10xxxxxxxx1101xxx1xxxx", InstName.Vmls, InstEmit32.Vmls_V, OpCode32SimdReg.Create);
|
SetA32("<<<<11100x00xxxxxxxx101xx0x0xxxx", InstName.Vmla, InstEmit32.Vmla_S, OpCode32SimdRegS.Create);
|
||||||
SetA32("111100110xxxxxxxxxxx1001xxx0xxxx", InstName.Vmls, InstEmit32.Vmls_I, OpCode32SimdReg.Create);
|
SetA32("111100100x00xxxxxxxx1101xxx1xxxx", InstName.Vmla, InstEmit32.Vmla_V, OpCode32SimdReg.Create);
|
||||||
SetA32("1111001x1x<<xxxxxxx01010x0x0xxxx", InstName.Vmlsl, InstEmit32.Vmlsl_I, OpCode32SimdRegLong.Create);
|
SetA32("1111001x1x<<xxxxxxxx010xx1x0xxxx", InstName.Vmls, InstEmit32.Vmls_1, OpCode32SimdRegElem.Create);
|
||||||
SetA32("<<<<11100xx0xxxxxxxx1011xxx10000", InstName.Vmov, InstEmit32.Vmov_G1, OpCode32SimdMovGpElem.Create); // From gen purpose.
|
SetA32("<<<<11100x00xxxxxxxx101xx1x0xxxx", InstName.Vmls, InstEmit32.Vmls_S, OpCode32SimdRegS.Create);
|
||||||
SetA32("<<<<1110xxx1xxxxxxxx1011xxx10000", InstName.Vmov, InstEmit32.Vmov_G1, OpCode32SimdMovGpElem.Create); // To gen purpose.
|
SetA32("111100100x10xxxxxxxx1101xxx1xxxx", InstName.Vmls, InstEmit32.Vmls_V, OpCode32SimdReg.Create);
|
||||||
SetA32("<<<<1100010xxxxxxxxx101000x1xxxx", InstName.Vmov, InstEmit32.Vmov_G2, OpCode32SimdMovGpDouble.Create); // To/from gen purpose x2 and single precision x2.
|
SetA32("111100110xxxxxxxxxxx1001xxx0xxxx", InstName.Vmls, InstEmit32.Vmls_I, OpCode32SimdReg.Create);
|
||||||
SetA32("<<<<1100010xxxxxxxxx101100x1xxxx", InstName.Vmov, InstEmit32.Vmov_GD, OpCode32SimdMovGpDouble.Create); // To/from gen purpose x2 and double precision.
|
SetA32("1111001x1x<<xxxxxxx01010x0x0xxxx", InstName.Vmlsl, InstEmit32.Vmlsl_I, OpCode32SimdRegLong.Create);
|
||||||
SetA32("<<<<1110000xxxxxxxxx1010x0010000", InstName.Vmov, InstEmit32.Vmov_GS, OpCode32SimdMovGp.Create); // To/from gen purpose and single precision.
|
SetA32("<<<<11100xx0xxxxxxxx1011xxx10000", InstName.Vmov, InstEmit32.Vmov_G1, OpCode32SimdMovGpElem.Create); // From gen purpose.
|
||||||
SetA32("1111001x1x000xxxxxxx0xx00x01xxxx", InstName.Vmov, InstEmit32.Vmov_I, OpCode32SimdImm.Create); // D/Q vector I32.
|
SetA32("<<<<1110xxx1xxxxxxxx1011xxx10000", InstName.Vmov, InstEmit32.Vmov_G1, OpCode32SimdMovGpElem.Create); // To gen purpose.
|
||||||
SetA32("<<<<11101x11xxxxxxxx101x0000xxxx", InstName.Vmov, InstEmit32.Vmov_I, OpCode32SimdImm44.Create); // Scalar f16/32/64 based on size 01 10 11.
|
SetA32("<<<<1100010xxxxxxxxx101000x1xxxx", InstName.Vmov, InstEmit32.Vmov_G2, OpCode32SimdMovGpDouble.Create); // To/from gen purpose x2 and single precision x2.
|
||||||
SetA32("1111001x1x000xxxxxxx10x00x01xxxx", InstName.Vmov, InstEmit32.Vmov_I, OpCode32SimdImm.Create); // D/Q I16.
|
SetA32("<<<<1100010xxxxxxxxx101100x1xxxx", InstName.Vmov, InstEmit32.Vmov_GD, OpCode32SimdMovGpDouble.Create); // To/from gen purpose x2 and double precision.
|
||||||
SetA32("1111001x1x000xxxxxxx11xx0x01xxxx", InstName.Vmov, InstEmit32.Vmov_I, OpCode32SimdImm.Create); // D/Q (dt - from cmode).
|
SetA32("<<<<1110000xxxxxxxxx1010x0010000", InstName.Vmov, InstEmit32.Vmov_GS, OpCode32SimdMovGp.Create); // To/from gen purpose and single precision.
|
||||||
SetA32("1111001x1x000xxxxxxx11100x11xxxx", InstName.Vmov, InstEmit32.Vmov_I, OpCode32SimdImm.Create); // D/Q I64.
|
SetA32("1111001x1x000xxxxxxx0xx00x01xxxx", InstName.Vmov, InstEmit32.Vmov_I, OpCode32SimdImm.Create); // D/Q vector I32.
|
||||||
SetA32("<<<<11101x110000xxxx101x01x0xxxx", InstName.Vmov, InstEmit32.Vmov_S, OpCode32SimdS.Create);
|
SetA32("<<<<11101x11xxxxxxxx101x0000xxxx", InstName.Vmov, InstEmit32.Vmov_I, OpCode32SimdImm44.Create); // Scalar f16/32/64 based on size 01 10 11.
|
||||||
SetA32("1111001x1x001000xxx0101000x1xxxx", InstName.Vmovl, InstEmit32.Vmovl, OpCode32SimdLong.Create);
|
SetA32("1111001x1x000xxxxxxx10x00x01xxxx", InstName.Vmov, InstEmit32.Vmov_I, OpCode32SimdImm.Create); // D/Q I16.
|
||||||
SetA32("1111001x1x010000xxx0101000x1xxxx", InstName.Vmovl, InstEmit32.Vmovl, OpCode32SimdLong.Create);
|
SetA32("1111001x1x000xxxxxxx11xx0x01xxxx", InstName.Vmov, InstEmit32.Vmov_I, OpCode32SimdImm.Create); // D/Q (dt - from cmode).
|
||||||
SetA32("1111001x1x100000xxx0101000x1xxxx", InstName.Vmovl, InstEmit32.Vmovl, OpCode32SimdLong.Create);
|
SetA32("1111001x1x000xxxxxxx11100x11xxxx", InstName.Vmov, InstEmit32.Vmov_I, OpCode32SimdImm.Create); // D/Q I64.
|
||||||
SetA32("111100111x11xx10xxxx001000x0xxx0", InstName.Vmovn, InstEmit32.Vmovn, OpCode32SimdCmpZ.Create);
|
SetA32("<<<<11101x110000xxxx101x01x0xxxx", InstName.Vmov, InstEmit32.Vmov_S, OpCode32SimdS.Create);
|
||||||
SetA32("<<<<11101111xxxxxxxx101000010000", InstName.Vmrs, InstEmit32.Vmrs, OpCode32SimdSpecial.Create);
|
SetA32("1111001x1x001000xxx0101000x1xxxx", InstName.Vmovl, InstEmit32.Vmovl, OpCode32SimdLong.Create);
|
||||||
SetA32("<<<<11101110xxxxxxxx101000010000", InstName.Vmsr, InstEmit32.Vmsr, OpCode32SimdSpecial.Create);
|
SetA32("1111001x1x010000xxx0101000x1xxxx", InstName.Vmovl, InstEmit32.Vmovl, OpCode32SimdLong.Create);
|
||||||
SetA32("1111001x1x<<xxxxxxxx100xx1x0xxxx", InstName.Vmul, InstEmit32.Vmul_1, OpCode32SimdRegElem.Create);
|
SetA32("1111001x1x100000xxx0101000x1xxxx", InstName.Vmovl, InstEmit32.Vmovl, OpCode32SimdLong.Create);
|
||||||
SetA32("111100100x<<xxxxxxxx1001xxx1xxxx", InstName.Vmul, InstEmit32.Vmul_I, OpCode32SimdReg.Create);
|
SetA32("111100111x11xx10xxxx001000x0xxx0", InstName.Vmovn, InstEmit32.Vmovn, OpCode32SimdCmpZ.Create);
|
||||||
SetA32("111100110x00xxxxxxxx1001xxx1xxxx", InstName.Vmul, InstEmit32.Vmul_I, OpCode32SimdReg.Create);
|
SetA32("<<<<11101111xxxxxxxx101000010000", InstName.Vmrs, InstEmit32.Vmrs, OpCode32SimdSpecial.Create);
|
||||||
SetA32("<<<<11100x10xxxxxxxx101xx0x0xxxx", InstName.Vmul, InstEmit32.Vmul_S, OpCode32SimdRegS.Create);
|
SetA32("<<<<11101110xxxxxxxx101000010000", InstName.Vmsr, InstEmit32.Vmsr, OpCode32SimdSpecial.Create);
|
||||||
SetA32("111100110x00xxxxxxxx1101xxx1xxxx", InstName.Vmul, InstEmit32.Vmul_V, OpCode32SimdReg.Create);
|
SetA32("1111001x1x<<xxxxxxxx100xx1x0xxxx", InstName.Vmul, InstEmit32.Vmul_1, OpCode32SimdRegElem.Create);
|
||||||
SetA32("1111001x1x<<xxxxxxx01010x1x0xxxx", InstName.Vmull, InstEmit32.Vmull_1, OpCode32SimdRegElemLong.Create);
|
SetA32("111100100x<<xxxxxxxx1001xxx1xxxx", InstName.Vmul, InstEmit32.Vmul_I, OpCode32SimdReg.Create);
|
||||||
SetA32("1111001x1x<<xxxxxxx01100x0x0xxxx", InstName.Vmull, InstEmit32.Vmull_I, OpCode32SimdRegLong.Create);
|
SetA32("111100110x00xxxxxxxx1001xxx1xxxx", InstName.Vmul, InstEmit32.Vmul_I, OpCode32SimdReg.Create);
|
||||||
SetA32("111100101xx0xxxxxxx01110x0x0xxxx", InstName.Vmull, InstEmit32.Vmull_I, OpCode32SimdRegLong.Create); // P8/P64
|
SetA32("<<<<11100x10xxxxxxxx101xx0x0xxxx", InstName.Vmul, InstEmit32.Vmul_S, OpCode32SimdRegS.Create);
|
||||||
SetA32("111100111x110000xxxx01011xx0xxxx", InstName.Vmvn, InstEmit32.Vmvn_I, OpCode32SimdBinary.Create);
|
SetA32("111100110x00xxxxxxxx1101xxx1xxxx", InstName.Vmul, InstEmit32.Vmul_V, OpCode32SimdReg.Create);
|
||||||
SetA32("1111001x1x000xxxxxxx0xx00x11xxxx", InstName.Vmvn, InstEmit32.Vmvn_II, OpCode32SimdImm.Create); // D/Q vector I32.
|
SetA32("1111001x1x<<xxxxxxx01010x1x0xxxx", InstName.Vmull, InstEmit32.Vmull_1, OpCode32SimdRegElemLong.Create);
|
||||||
SetA32("1111001x1x000xxxxxxx10x00x11xxxx", InstName.Vmvn, InstEmit32.Vmvn_II, OpCode32SimdImm.Create);
|
SetA32("1111001x1x<<xxxxxxx01100x0x0xxxx", InstName.Vmull, InstEmit32.Vmull_I, OpCode32SimdRegLong.Create);
|
||||||
SetA32("1111001x1x000xxxxxxx110x0x11xxxx", InstName.Vmvn, InstEmit32.Vmvn_II, OpCode32SimdImm.Create);
|
SetA32("111100101xx0xxxxxxx01110x0x0xxxx", InstName.Vmull, InstEmit32.Vmull_I, OpCode32SimdRegLong.Create); // P8/P64
|
||||||
SetA32("<<<<11101x110001xxxx101x01x0xxxx", InstName.Vneg, InstEmit32.Vneg_S, OpCode32SimdS.Create);
|
SetA32("111100111x110000xxxx01011xx0xxxx", InstName.Vmvn, InstEmit32.Vmvn_I, OpCode32SimdBinary.Create);
|
||||||
SetA32("111100111x11<<01xxxx00111xx0xxxx", InstName.Vneg, InstEmit32.Vneg_V, OpCode32SimdCmpZ.Create);
|
SetA32("1111001x1x000xxxxxxx0xx00x11xxxx", InstName.Vmvn, InstEmit32.Vmvn_II, OpCode32SimdImm.Create); // D/Q vector I32.
|
||||||
SetA32("111100111x111001xxxx01111xx0xxxx", InstName.Vneg, InstEmit32.Vneg_V, OpCode32SimdCmpZ.Create);
|
SetA32("1111001x1x000xxxxxxx10x00x11xxxx", InstName.Vmvn, InstEmit32.Vmvn_II, OpCode32SimdImm.Create);
|
||||||
SetA32("<<<<11100x01xxxxxxxx101xx1x0xxxx", InstName.Vnmla, InstEmit32.Vnmla_S, OpCode32SimdRegS.Create);
|
SetA32("1111001x1x000xxxxxxx110x0x11xxxx", InstName.Vmvn, InstEmit32.Vmvn_II, OpCode32SimdImm.Create);
|
||||||
SetA32("<<<<11100x01xxxxxxxx101xx0x0xxxx", InstName.Vnmls, InstEmit32.Vnmls_S, OpCode32SimdRegS.Create);
|
SetA32("<<<<11101x110001xxxx101x01x0xxxx", InstName.Vneg, InstEmit32.Vneg_S, OpCode32SimdS.Create);
|
||||||
SetA32("<<<<11100x10xxxxxxxx101xx1x0xxxx", InstName.Vnmul, InstEmit32.Vnmul_S, OpCode32SimdRegS.Create);
|
SetA32("111100111x11<<01xxxx00111xx0xxxx", InstName.Vneg, InstEmit32.Vneg_V, OpCode32SimdCmpZ.Create);
|
||||||
SetA32("111100100x11xxxxxxxx0001xxx1xxxx", InstName.Vorn, InstEmit32.Vorn_I, OpCode32SimdBinary.Create);
|
SetA32("111100111x111001xxxx01111xx0xxxx", InstName.Vneg, InstEmit32.Vneg_V, OpCode32SimdCmpZ.Create);
|
||||||
SetA32("111100100x10xxxxxxxx0001xxx1xxxx", InstName.Vorr, InstEmit32.Vorr_I, OpCode32SimdBinary.Create);
|
SetA32("<<<<11100x01xxxxxxxx101xx1x0xxxx", InstName.Vnmla, InstEmit32.Vnmla_S, OpCode32SimdRegS.Create);
|
||||||
SetA32("1111001x1x000xxxxxxx<<x10x01xxxx", InstName.Vorr, InstEmit32.Vorr_II, OpCode32SimdImm.Create);
|
SetA32("<<<<11100x01xxxxxxxx101xx0x0xxxx", InstName.Vnmls, InstEmit32.Vnmls_S, OpCode32SimdRegS.Create);
|
||||||
SetA32("111100100x<<xxxxxxxx1011x0x1xxxx", InstName.Vpadd, InstEmit32.Vpadd_I, OpCode32SimdReg.Create);
|
SetA32("<<<<11100x10xxxxxxxx101xx1x0xxxx", InstName.Vnmul, InstEmit32.Vnmul_S, OpCode32SimdRegS.Create);
|
||||||
SetA32("111100110x00xxxxxxxx1101x0x0xxxx", InstName.Vpadd, InstEmit32.Vpadd_V, OpCode32SimdReg.Create);
|
SetA32("111100100x11xxxxxxxx0001xxx1xxxx", InstName.Vorn, InstEmit32.Vorn_I, OpCode32SimdBinary.Create);
|
||||||
SetA32("1111001x0x<<xxxxxxxx1010x0x0xxxx", InstName.Vpmax, InstEmit32.Vpmax_I, OpCode32SimdReg.Create);
|
SetA32("111100100x10xxxxxxxx0001xxx1xxxx", InstName.Vorr, InstEmit32.Vorr_I, OpCode32SimdBinary.Create);
|
||||||
SetA32("111100110x00xxxxxxxx1111x0x0xxxx", InstName.Vpmax, InstEmit32.Vpmax_V, OpCode32SimdReg.Create);
|
SetA32("1111001x1x000xxxxxxx<<x10x01xxxx", InstName.Vorr, InstEmit32.Vorr_II, OpCode32SimdImm.Create);
|
||||||
SetA32("1111001x0x<<xxxxxxxx1010x0x1xxxx", InstName.Vpmin, InstEmit32.Vpmin_I, OpCode32SimdReg.Create);
|
SetA32("111100100x<<xxxxxxxx1011x0x1xxxx", InstName.Vpadd, InstEmit32.Vpadd_I, OpCode32SimdReg.Create);
|
||||||
SetA32("111100110x10xxxxxxxx1111x0x0xxxx", InstName.Vpmin, InstEmit32.Vpmin_V, OpCode32SimdReg.Create);
|
SetA32("111100110x00xxxxxxxx1101x0x0xxxx", InstName.Vpadd, InstEmit32.Vpadd_V, OpCode32SimdReg.Create);
|
||||||
SetA32("1111001x1x>>>xxxxxxx100101x1xxx0", InstName.Vqrshrn, InstEmit32.Vqrshrn, OpCode32SimdShImmNarrow.Create);
|
SetA32("1111001x0x<<xxxxxxxx1010x0x0xxxx", InstName.Vpmax, InstEmit32.Vpmax_I, OpCode32SimdReg.Create);
|
||||||
SetA32("111100111x>>>xxxxxxx100001x1xxx0", InstName.Vqrshrun, InstEmit32.Vqrshrun, OpCode32SimdShImmNarrow.Create);
|
SetA32("111100110x00xxxxxxxx1111x0x0xxxx", InstName.Vpmax, InstEmit32.Vpmax_V, OpCode32SimdReg.Create);
|
||||||
SetA32("1111001x1x>>>xxxxxxx100100x1xxx0", InstName.Vqshrn, InstEmit32.Vqshrn, OpCode32SimdShImmNarrow.Create);
|
SetA32("1111001x0x<<xxxxxxxx1010x0x1xxxx", InstName.Vpmin, InstEmit32.Vpmin_I, OpCode32SimdReg.Create);
|
||||||
SetA32("111100111x111011xxxx010x0xx0xxxx", InstName.Vrecpe, InstEmit32.Vrecpe, OpCode32SimdSqrte.Create);
|
SetA32("111100110x10xxxxxxxx1111x0x0xxxx", InstName.Vpmin, InstEmit32.Vpmin_V, OpCode32SimdReg.Create);
|
||||||
SetA32("111100100x00xxxxxxxx1111xxx1xxxx", InstName.Vrecps, InstEmit32.Vrecps, OpCode32SimdReg.Create);
|
SetA32("1111001x1x>>>xxxxxxx100101x1xxx0", InstName.Vqrshrn, InstEmit32.Vqrshrn, OpCode32SimdShImmNarrow.Create);
|
||||||
SetA32("111100111x11xx00xxxx000<<xx0xxxx", InstName.Vrev, InstEmit32.Vrev, OpCode32SimdRev.Create);
|
SetA32("111100111x>>>xxxxxxx100001x1xxx0", InstName.Vqrshrun, InstEmit32.Vqrshrun, OpCode32SimdShImmNarrow.Create);
|
||||||
SetA32("111111101x1110xxxxxx101x01x0xxxx", InstName.Vrint, InstEmit32.Vrint_RM, OpCode32SimdS.Create);
|
SetA32("1111001x1x>>>xxxxxxx100100x1xxx0", InstName.Vqshrn, InstEmit32.Vqshrn, OpCode32SimdShImmNarrow.Create);
|
||||||
SetA32("<<<<11101x110110xxxx101x11x0xxxx", InstName.Vrint, InstEmit32.Vrint_Z, OpCode32SimdS.Create);
|
SetA32("111100111x111011xxxx010x0xx0xxxx", InstName.Vrecpe, InstEmit32.Vrecpe, OpCode32SimdSqrte.Create);
|
||||||
SetA32("<<<<11101x110111xxxx101x01x0xxxx", InstName.Vrintx, InstEmit32.Vrintx_S, OpCode32SimdS.Create);
|
SetA32("111100100x00xxxxxxxx1111xxx1xxxx", InstName.Vrecps, InstEmit32.Vrecps, OpCode32SimdReg.Create);
|
||||||
SetA32("1111001x1x>>>xxxxxxx0010>xx1xxxx", InstName.Vrshr, InstEmit32.Vrshr, OpCode32SimdShImm.Create);
|
SetA32("111100111x11xx00xxxx000<<xx0xxxx", InstName.Vrev, InstEmit32.Vrev, OpCode32SimdRev.Create);
|
||||||
SetA32("111100111x111011xxxx010x1xx0xxxx", InstName.Vrsqrte, InstEmit32.Vrsqrte, OpCode32SimdSqrte.Create);
|
SetA32("111111101x1110xxxxxx101x01x0xxxx", InstName.Vrint, InstEmit32.Vrint_RM, OpCode32SimdS.Create);
|
||||||
SetA32("111100100x10xxxxxxxx1111xxx1xxxx", InstName.Vrsqrts, InstEmit32.Vrsqrts, OpCode32SimdReg.Create);
|
SetA32("<<<<11101x110110xxxx101x11x0xxxx", InstName.Vrint, InstEmit32.Vrint_Z, OpCode32SimdS.Create);
|
||||||
SetA32("111111100xxxxxxxxxxx101xx0x0xxxx", InstName.Vsel, InstEmit32.Vsel, OpCode32SimdSel.Create);
|
SetA32("<<<<11101x110111xxxx101x01x0xxxx", InstName.Vrintx, InstEmit32.Vrintx_S, OpCode32SimdS.Create);
|
||||||
SetA32("111100101x>>>xxxxxxx0101>xx1xxxx", InstName.Vshl, InstEmit32.Vshl, OpCode32SimdShImm.Create);
|
SetA32("1111001x1x>>>xxxxxxx0010>xx1xxxx", InstName.Vrshr, InstEmit32.Vrshr, OpCode32SimdShImm.Create);
|
||||||
SetA32("1111001x0xxxxxxxxxxx0100xxx0xxxx", InstName.Vshl, InstEmit32.Vshl_I, OpCode32SimdReg.Create);
|
SetA32("111100111x111011xxxx010x1xx0xxxx", InstName.Vrsqrte, InstEmit32.Vrsqrte, OpCode32SimdSqrte.Create);
|
||||||
SetA32("1111001x1x>>>xxxxxxx101000x1xxxx", InstName.Vshll, InstEmit32.Vshll, OpCode32SimdShImmLong.Create); // A1 encoding.
|
SetA32("111100100x10xxxxxxxx1111xxx1xxxx", InstName.Vrsqrts, InstEmit32.Vrsqrts, OpCode32SimdReg.Create);
|
||||||
SetA32("1111001x1x>>>xxxxxxx0000>xx1xxxx", InstName.Vshr, InstEmit32.Vshr, OpCode32SimdShImm.Create);
|
SetA32("111111100xxxxxxxxxxx101xx0x0xxxx", InstName.Vsel, InstEmit32.Vsel, OpCode32SimdSel.Create);
|
||||||
SetA32("111100101x>>>xxxxxxx100000x1xxx0", InstName.Vshrn, InstEmit32.Vshrn, OpCode32SimdShImmNarrow.Create);
|
SetA32("111100101x>>>xxxxxxx0101>xx1xxxx", InstName.Vshl, InstEmit32.Vshl, OpCode32SimdShImm.Create);
|
||||||
SetA32("<<<<11101x110001xxxx101x11x0xxxx", InstName.Vsqrt, InstEmit32.Vsqrt_S, OpCode32SimdS.Create);
|
SetA32("1111001x0xxxxxxxxxxx0100xxx0xxxx", InstName.Vshl, InstEmit32.Vshl_I, OpCode32SimdReg.Create);
|
||||||
SetA32("1111001x1x>>>xxxxxxx0001>xx1xxxx", InstName.Vsra, InstEmit32.Vsra, OpCode32SimdShImm.Create);
|
SetA32("1111001x1x>>>xxxxxxx101000x1xxxx", InstName.Vshll, InstEmit32.Vshll, OpCode32SimdShImmLong.Create); // A1 encoding.
|
||||||
SetA32("111101001x00xxxxxxxx<<00xxxxxxxx", InstName.Vst1, InstEmit32.Vst1, OpCode32SimdMemSingle.Create);
|
SetA32("1111001x1x>>>xxxxxxx0000>xx1xxxx", InstName.Vshr, InstEmit32.Vshr, OpCode32SimdShImm.Create);
|
||||||
SetA32("111101000x00xxxxxxxx0111xxxxxxxx", InstName.Vst1, InstEmit32.Vst1, OpCode32SimdMemPair.Create); // Regs = 1.
|
SetA32("111100101x>>>xxxxxxx100000x1xxx0", InstName.Vshrn, InstEmit32.Vshrn, OpCode32SimdShImmNarrow.Create);
|
||||||
SetA32("111101000x00xxxxxxxx1010xxxxxxxx", InstName.Vst1, InstEmit32.Vst1, OpCode32SimdMemPair.Create); // Regs = 2.
|
SetA32("<<<<11101x110001xxxx101x11x0xxxx", InstName.Vsqrt, InstEmit32.Vsqrt_S, OpCode32SimdS.Create);
|
||||||
SetA32("111101000x00xxxxxxxx0110xxxxxxxx", InstName.Vst1, InstEmit32.Vst1, OpCode32SimdMemPair.Create); // Regs = 3.
|
SetA32("1111001x1x>>>xxxxxxx0001>xx1xxxx", InstName.Vsra, InstEmit32.Vsra, OpCode32SimdShImm.Create);
|
||||||
SetA32("111101000x00xxxxxxxx0010xxxxxxxx", InstName.Vst1, InstEmit32.Vst1, OpCode32SimdMemPair.Create); // Regs = 4.
|
SetA32("111101001x00xxxxxxxx<<00xxxxxxxx", InstName.Vst1, InstEmit32.Vst1, OpCode32SimdMemSingle.Create);
|
||||||
SetA32("111101001x00xxxxxxxx<<01xxxxxxxx", InstName.Vst2, InstEmit32.Vst2, OpCode32SimdMemSingle.Create);
|
SetA32("111101000x00xxxxxxxx0111xxxxxxxx", InstName.Vst1, InstEmit32.Vst1, OpCode32SimdMemPair.Create); // Regs = 1.
|
||||||
SetA32("111101000x00xxxxxxxx100xxxxxxxxx", InstName.Vst2, InstEmit32.Vst2, OpCode32SimdMemPair.Create); // Regs = 1, inc = 1/2 (itype).
|
SetA32("111101000x00xxxxxxxx1010xxxxxxxx", InstName.Vst1, InstEmit32.Vst1, OpCode32SimdMemPair.Create); // Regs = 2.
|
||||||
SetA32("111101000x00xxxxxxxx0011xxxxxxxx", InstName.Vst2, InstEmit32.Vst2, OpCode32SimdMemPair.Create); // Regs = 2, inc = 2.
|
SetA32("111101000x00xxxxxxxx0110xxxxxxxx", InstName.Vst1, InstEmit32.Vst1, OpCode32SimdMemPair.Create); // Regs = 3.
|
||||||
SetA32("111101001x00xxxxxxxx<<10xxxxxxxx", InstName.Vst3, InstEmit32.Vst3, OpCode32SimdMemSingle.Create);
|
SetA32("111101000x00xxxxxxxx0010xxxxxxxx", InstName.Vst1, InstEmit32.Vst1, OpCode32SimdMemPair.Create); // Regs = 4.
|
||||||
SetA32("111101000x00xxxxxxxx010xxxxxxxxx", InstName.Vst3, InstEmit32.Vst3, OpCode32SimdMemPair.Create); // Inc = 1/2 (itype).
|
SetA32("111101001x00xxxxxxxx<<01xxxxxxxx", InstName.Vst2, InstEmit32.Vst2, OpCode32SimdMemSingle.Create);
|
||||||
SetA32("111101001x00xxxxxxxx<<11xxxxxxxx", InstName.Vst4, InstEmit32.Vst4, OpCode32SimdMemSingle.Create);
|
SetA32("111101000x00xxxxxxxx100xxxxxxxxx", InstName.Vst2, InstEmit32.Vst2, OpCode32SimdMemPair.Create); // Regs = 1, inc = 1/2 (itype).
|
||||||
SetA32("111101000x00xxxxxxxx000xxxxxxxxx", InstName.Vst4, InstEmit32.Vst4, OpCode32SimdMemPair.Create); // Inc = 1/2 (itype).
|
SetA32("111101000x00xxxxxxxx0011xxxxxxxx", InstName.Vst2, InstEmit32.Vst2, OpCode32SimdMemPair.Create); // Regs = 2, inc = 2.
|
||||||
SetA32("<<<<11001x00xxxxxxxx1011xxxxxxx0", InstName.Vstm, InstEmit32.Vstm, OpCode32SimdMemMult.Create);
|
SetA32("111101001x00xxxxxxxx<<10xxxxxxxx", InstName.Vst3, InstEmit32.Vst3, OpCode32SimdMemSingle.Create);
|
||||||
SetA32("<<<<11001x10xxxxxxxx1011xxxxxxx0", InstName.Vstm, InstEmit32.Vstm, OpCode32SimdMemMult.Create);
|
SetA32("111101000x00xxxxxxxx010xxxxxxxxx", InstName.Vst3, InstEmit32.Vst3, OpCode32SimdMemPair.Create); // Inc = 1/2 (itype).
|
||||||
SetA32("<<<<11010x10xxxxxxxx1011xxxxxxx0", InstName.Vstm, InstEmit32.Vstm, OpCode32SimdMemMult.Create);
|
SetA32("111101001x00xxxxxxxx<<11xxxxxxxx", InstName.Vst4, InstEmit32.Vst4, OpCode32SimdMemSingle.Create);
|
||||||
SetA32("<<<<11001x00xxxxxxxx1010xxxxxxxx", InstName.Vstm, InstEmit32.Vstm, OpCode32SimdMemMult.Create);
|
SetA32("111101000x00xxxxxxxx000xxxxxxxxx", InstName.Vst4, InstEmit32.Vst4, OpCode32SimdMemPair.Create); // Inc = 1/2 (itype).
|
||||||
SetA32("<<<<11001x10xxxxxxxx1010xxxxxxxx", InstName.Vstm, InstEmit32.Vstm, OpCode32SimdMemMult.Create);
|
SetA32("<<<<11001x00xxxxxxxx1011xxxxxxx0", InstName.Vstm, InstEmit32.Vstm, OpCode32SimdMemMult.Create);
|
||||||
SetA32("<<<<11010x10xxxxxxxx1010xxxxxxxx", InstName.Vstm, InstEmit32.Vstm, OpCode32SimdMemMult.Create);
|
SetA32("<<<<11001x10xxxxxxxx1011xxxxxxx0", InstName.Vstm, InstEmit32.Vstm, OpCode32SimdMemMult.Create);
|
||||||
SetA32("<<<<1101xx00xxxxxxxx101xxxxxxxxx", InstName.Vstr, InstEmit32.Vstr, OpCode32SimdMemImm.Create);
|
SetA32("<<<<11010x10xxxxxxxx1011xxxxxxx0", InstName.Vstm, InstEmit32.Vstm, OpCode32SimdMemMult.Create);
|
||||||
SetA32("111100110xxxxxxxxxxx1000xxx0xxxx", InstName.Vsub, InstEmit32.Vsub_I, OpCode32SimdReg.Create);
|
SetA32("<<<<11001x00xxxxxxxx1010xxxxxxxx", InstName.Vstm, InstEmit32.Vstm, OpCode32SimdMemMult.Create);
|
||||||
SetA32("<<<<11100x11xxxxxxxx101xx1x0xxxx", InstName.Vsub, InstEmit32.Vsub_S, OpCode32SimdRegS.Create);
|
SetA32("<<<<11001x10xxxxxxxx1010xxxxxxxx", InstName.Vstm, InstEmit32.Vstm, OpCode32SimdMemMult.Create);
|
||||||
SetA32("111100100x10xxxxxxxx1101xxx0xxxx", InstName.Vsub, InstEmit32.Vsub_V, OpCode32SimdReg.Create);
|
SetA32("<<<<11010x10xxxxxxxx1010xxxxxxxx", InstName.Vstm, InstEmit32.Vstm, OpCode32SimdMemMult.Create);
|
||||||
SetA32("1111001x1x<<xxxxxxxx0011x0x0xxxx", InstName.Vsubw, InstEmit32.Vsubw_I, OpCode32SimdRegWide.Create);
|
SetA32("<<<<1101xx00xxxxxxxx101xxxxxxxxx", InstName.Vstr, InstEmit32.Vstr, OpCode32SimdMemImm.Create);
|
||||||
SetA32("111100111x11xxxxxxxx10xxxxx0xxxx", InstName.Vtbl, InstEmit32.Vtbl, OpCode32SimdTbl.Create);
|
SetA32("111100110xxxxxxxxxxx1000xxx0xxxx", InstName.Vsub, InstEmit32.Vsub_I, OpCode32SimdReg.Create);
|
||||||
SetA32("111100111x11<<10xxxx00001xx0xxxx", InstName.Vtrn, InstEmit32.Vtrn, OpCode32SimdCmpZ.Create);
|
SetA32("<<<<11100x11xxxxxxxx101xx1x0xxxx", InstName.Vsub, InstEmit32.Vsub_S, OpCode32SimdRegS.Create);
|
||||||
SetA32("111100100x<<xxxxxxxx1000xxx1xxxx", InstName.Vtst, InstEmit32.Vtst, OpCode32SimdReg.Create);
|
SetA32("111100100x10xxxxxxxx1101xxx0xxxx", InstName.Vsub, InstEmit32.Vsub_V, OpCode32SimdReg.Create);
|
||||||
SetA32("111100111x11<<10xxxx00010xx0xxxx", InstName.Vuzp, InstEmit32.Vuzp, OpCode32SimdCmpZ.Create);
|
SetA32("1111001x1x<<xxxxxxxx0011x0x0xxxx", InstName.Vsubw, InstEmit32.Vsubw_I, OpCode32SimdRegWide.Create);
|
||||||
SetA32("111100111x11<<10xxxx00011xx0xxxx", InstName.Vzip, InstEmit32.Vzip, OpCode32SimdCmpZ.Create);
|
SetA32("111100111x11xxxxxxxx10xxxxx0xxxx", InstName.Vtbl, InstEmit32.Vtbl, OpCode32SimdTbl.Create);
|
||||||
|
SetA32("111100111x11<<10xxxx00001xx0xxxx", InstName.Vtrn, InstEmit32.Vtrn, OpCode32SimdCmpZ.Create);
|
||||||
|
SetA32("111100100x<<xxxxxxxx1000xxx1xxxx", InstName.Vtst, InstEmit32.Vtst, OpCode32SimdReg.Create);
|
||||||
|
SetA32("111100111x11<<10xxxx00010xx0xxxx", InstName.Vuzp, InstEmit32.Vuzp, OpCode32SimdCmpZ.Create);
|
||||||
|
SetA32("111100111x11<<10xxxx00011xx0xxxx", InstName.Vzip, InstEmit32.Vzip, OpCode32SimdCmpZ.Create);
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
FillFastLookupTable(InstA32FastLookup, AllInstA32);
|
#region "OpCode Table (AArch32, T16)"
|
||||||
FillFastLookupTable(InstT32FastLookup, AllInstT32);
|
SetT16("000<<xxxxxxxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT16ShiftImm.Create);
|
||||||
FillFastLookupTable(InstA64FastLookup, AllInstA64);
|
SetT16("0001100xxxxxxxxx", InstName.Add, InstEmit32.Add, OpCodeT16AddSubReg.Create);
|
||||||
|
SetT16("0001101xxxxxxxxx", InstName.Sub, InstEmit32.Sub, OpCodeT16AddSubReg.Create);
|
||||||
|
SetT16("0001110xxxxxxxxx", InstName.Add, InstEmit32.Add, OpCodeT16AddSubImm3.Create);
|
||||||
|
SetT16("0001111xxxxxxxxx", InstName.Sub, InstEmit32.Sub, OpCodeT16AddSubImm3.Create);
|
||||||
|
SetT16("00100xxxxxxxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT16AluImm8.Create);
|
||||||
|
SetT16("00101xxxxxxxxxxx", InstName.Cmp, InstEmit32.Cmp, OpCodeT16AluImm8.Create);
|
||||||
|
SetT16("00110xxxxxxxxxxx", InstName.Add, InstEmit32.Add, OpCodeT16AluImm8.Create);
|
||||||
|
SetT16("00111xxxxxxxxxxx", InstName.Sub, InstEmit32.Sub, OpCodeT16AluImm8.Create);
|
||||||
|
SetT16("0100000000xxxxxx", InstName.And, InstEmit32.And, OpCodeT16AluRegLow.Create);
|
||||||
|
SetT16("0100000001xxxxxx", InstName.Eor, InstEmit32.Eor, OpCodeT16AluRegLow.Create);
|
||||||
|
SetT16("0100000010xxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT16ShiftReg.Create);
|
||||||
|
SetT16("0100000011xxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT16ShiftReg.Create);
|
||||||
|
SetT16("0100000100xxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT16ShiftReg.Create);
|
||||||
|
SetT16("0100000101xxxxxx", InstName.Adc, InstEmit32.Adc, OpCodeT16AluRegLow.Create);
|
||||||
|
SetT16("0100000110xxxxxx", InstName.Sbc, InstEmit32.Sbc, OpCodeT16AluRegLow.Create);
|
||||||
|
SetT16("0100000111xxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT16ShiftReg.Create);
|
||||||
|
SetT16("0100001000xxxxxx", InstName.Tst, InstEmit32.Tst, OpCodeT16AluRegLow.Create);
|
||||||
|
SetT16("0100001001xxxxxx", InstName.Rsb, InstEmit32.Rsb, OpCodeT16AluImmZero.Create);
|
||||||
|
SetT16("0100001010xxxxxx", InstName.Cmp, InstEmit32.Cmp, OpCodeT16AluRegLow.Create);
|
||||||
|
SetT16("0100001011xxxxxx", InstName.Cmn, InstEmit32.Cmn, OpCodeT16AluRegLow.Create);
|
||||||
|
SetT16("0100001100xxxxxx", InstName.Orr, InstEmit32.Orr, OpCodeT16AluRegLow.Create);
|
||||||
|
SetT16("0100001101xxxxxx", InstName.Mul, InstEmit32.Mul, OpCodeT16AluRegLow.Create);
|
||||||
|
SetT16("0100001110xxxxxx", InstName.Bic, InstEmit32.Bic, OpCodeT16AluRegLow.Create);
|
||||||
|
SetT16("0100001111xxxxxx", InstName.Mvn, InstEmit32.Mvn, OpCodeT16AluRegLow.Create);
|
||||||
|
SetT16("01000100xxxxxxxx", InstName.Add, InstEmit32.Add, OpCodeT16AluRegHigh.Create);
|
||||||
|
SetT16("01000101xxxxxxxx", InstName.Cmp, InstEmit32.Cmp, OpCodeT16AluRegHigh.Create);
|
||||||
|
SetT16("01000110xxxxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT16AluRegHigh.Create);
|
||||||
|
SetT16("010001110xxxx000", InstName.Bx, InstEmit32.Bx, OpCodeT16BReg.Create);
|
||||||
|
SetT16("010001111xxxx000", InstName.Blx, InstEmit32.Blx, OpCodeT16BReg.Create);
|
||||||
|
SetT16("01001xxxxxxxxxxx", InstName.Ldr, InstEmit32.Ldr, OpCodeT16MemLit.Create);
|
||||||
|
SetT16("0101000xxxxxxxxx", InstName.Str, InstEmit32.Str, OpCodeT16MemReg.Create);
|
||||||
|
SetT16("0101001xxxxxxxxx", InstName.Strh, InstEmit32.Strh, OpCodeT16MemReg.Create);
|
||||||
|
SetT16("0101010xxxxxxxxx", InstName.Strb, InstEmit32.Strb, OpCodeT16MemReg.Create);
|
||||||
|
SetT16("0101011xxxxxxxxx", InstName.Ldrsb, InstEmit32.Ldrsb, OpCodeT16MemReg.Create);
|
||||||
|
SetT16("0101100xxxxxxxxx", InstName.Ldr, InstEmit32.Ldr, OpCodeT16MemReg.Create);
|
||||||
|
SetT16("0101101xxxxxxxxx", InstName.Ldrh, InstEmit32.Ldrh, OpCodeT16MemReg.Create);
|
||||||
|
SetT16("0101110xxxxxxxxx", InstName.Ldrb, InstEmit32.Ldrb, OpCodeT16MemReg.Create);
|
||||||
|
SetT16("0101111xxxxxxxxx", InstName.Ldrsh, InstEmit32.Ldrsh, OpCodeT16MemReg.Create);
|
||||||
|
SetT16("01100xxxxxxxxxxx", InstName.Str, InstEmit32.Str, OpCodeT16MemImm5.Create);
|
||||||
|
SetT16("01101xxxxxxxxxxx", InstName.Ldr, InstEmit32.Ldr, OpCodeT16MemImm5.Create);
|
||||||
|
SetT16("01110xxxxxxxxxxx", InstName.Strb, InstEmit32.Strb, OpCodeT16MemImm5.Create);
|
||||||
|
SetT16("01111xxxxxxxxxxx", InstName.Ldrb, InstEmit32.Ldrb, OpCodeT16MemImm5.Create);
|
||||||
|
SetT16("10000xxxxxxxxxxx", InstName.Strh, InstEmit32.Strh, OpCodeT16MemImm5.Create);
|
||||||
|
SetT16("10001xxxxxxxxxxx", InstName.Ldrh, InstEmit32.Ldrh, OpCodeT16MemImm5.Create);
|
||||||
|
SetT16("10010xxxxxxxxxxx", InstName.Str, InstEmit32.Str, OpCodeT16MemSp.Create);
|
||||||
|
SetT16("10011xxxxxxxxxxx", InstName.Ldr, InstEmit32.Ldr, OpCodeT16MemSp.Create);
|
||||||
|
SetT16("10100xxxxxxxxxxx", InstName.Adr, InstEmit32.Adr, OpCodeT16Adr.Create);
|
||||||
|
SetT16("10101xxxxxxxxxxx", InstName.Add, InstEmit32.Add, OpCodeT16SpRel.Create);
|
||||||
|
SetT16("101100000xxxxxxx", InstName.Add, InstEmit32.Add, OpCodeT16AddSubSp.Create);
|
||||||
|
SetT16("101100001xxxxxxx", InstName.Sub, InstEmit32.Sub, OpCodeT16AddSubSp.Create);
|
||||||
|
SetT16("1011001000xxxxxx", InstName.Sxth, InstEmit32.Sxth, OpCodeT16AluUx.Create);
|
||||||
|
SetT16("1011001001xxxxxx", InstName.Sxtb, InstEmit32.Sxtb, OpCodeT16AluUx.Create);
|
||||||
|
SetT16("1011001010xxxxxx", InstName.Uxth, InstEmit32.Uxth, OpCodeT16AluUx.Create);
|
||||||
|
SetT16("1011001011xxxxxx", InstName.Uxtb, InstEmit32.Uxtb, OpCodeT16AluUx.Create);
|
||||||
|
SetT16("101100x1xxxxxxxx", InstName.Cbz, InstEmit32.Cbz, OpCodeT16BImmCmp.Create);
|
||||||
|
SetT16("1011010xxxxxxxxx", InstName.Push, InstEmit32.Stm, OpCodeT16MemStack.Create);
|
||||||
|
SetT16("1011101000xxxxxx", InstName.Rev, InstEmit32.Rev, OpCodeT16AluRegLow.Create);
|
||||||
|
SetT16("1011101001xxxxxx", InstName.Rev16, InstEmit32.Rev16, OpCodeT16AluRegLow.Create);
|
||||||
|
SetT16("1011101011xxxxxx", InstName.Revsh, InstEmit32.Revsh, OpCodeT16AluRegLow.Create);
|
||||||
|
SetT16("101110x1xxxxxxxx", InstName.Cbnz, InstEmit32.Cbnz, OpCodeT16BImmCmp.Create);
|
||||||
|
SetT16("1011110xxxxxxxxx", InstName.Pop, InstEmit32.Ldm, OpCodeT16MemStack.Create);
|
||||||
|
SetT16("10111111xxxx0000", InstName.Nop, InstEmit32.Nop, OpCodeT16.Create);
|
||||||
|
SetT16("10111111xxxx>>>>", InstName.It, InstEmit32.It, OpCodeT16IfThen.Create);
|
||||||
|
SetT16("11000xxxxxxxxxxx", InstName.Stm, InstEmit32.Stm, OpCodeT16MemMult.Create);
|
||||||
|
SetT16("11001xxxxxxxxxxx", InstName.Ldm, InstEmit32.Ldm, OpCodeT16MemMult.Create);
|
||||||
|
SetT16("1101<<<xxxxxxxxx", InstName.B, InstEmit32.B, OpCodeT16BImm8.Create);
|
||||||
|
SetT16("11011111xxxxxxxx", InstName.Svc, InstEmit32.Svc, OpCodeT16Exception.Create);
|
||||||
|
SetT16("11100xxxxxxxxxxx", InstName.B, InstEmit32.B, OpCodeT16BImm11.Create);
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region "OpCode Table (AArch32, T32)"
|
||||||
|
// Base
|
||||||
|
SetT32("11101011010xxxxx0xxxxxxxxxxxxxxx", InstName.Adc, InstEmit32.Adc, OpCodeT32AluRsImm.Create);
|
||||||
|
SetT32("11110x01010xxxxx0xxxxxxxxxxxxxxx", InstName.Adc, InstEmit32.Adc, OpCodeT32AluImm.Create);
|
||||||
|
SetT32("11101011000<xxxx0xxx<<<<xxxxxxxx", InstName.Add, InstEmit32.Add, OpCodeT32AluRsImm.Create);
|
||||||
|
SetT32("11110x01000<xxxx0xxx<<<<xxxxxxxx", InstName.Add, InstEmit32.Add, OpCodeT32AluImm.Create);
|
||||||
|
SetT32("11101010000<xxxx0xxx<<<<xxxxxxxx", InstName.And, InstEmit32.And, OpCodeT32AluRsImm.Create);
|
||||||
|
SetT32("11110x00000<xxxx0xxx<<<<xxxxxxxx", InstName.And, InstEmit32.And, OpCodeT32AluImm.Create);
|
||||||
|
SetT32("11110x<<<xxxxxxx10x0xxxxxxxxxxxx", InstName.B, InstEmit32.B, OpCodeT32BImm20.Create);
|
||||||
|
SetT32("11110xxxxxxxxxxx10x1xxxxxxxxxxxx", InstName.B, InstEmit32.B, OpCodeT32BImm24.Create);
|
||||||
|
SetT32("11101010001xxxxx0xxxxxxxxxxxxxxx", InstName.Bic, InstEmit32.Bic, OpCodeT32AluRsImm.Create);
|
||||||
|
SetT32("11110x00001xxxxx0xxxxxxxxxxxxxxx", InstName.Bic, InstEmit32.Bic, OpCodeT32AluImm.Create);
|
||||||
|
SetT32("11110xxxxxxxxxxx11x1xxxxxxxxxxxx", InstName.Bl, InstEmit32.Bl, OpCodeT32BImm24.Create);
|
||||||
|
SetT32("11110xxxxxxxxxxx11x0xxxxxxxxxxx0", InstName.Blx, InstEmit32.Blx, OpCodeT32BImm24.Create);
|
||||||
|
SetT32("111010110001xxxx0xxx1111xxxxxxxx", InstName.Cmn, InstEmit32.Cmn, OpCodeT32AluRsImm.Create);
|
||||||
|
SetT32("11110x010001xxxx0xxx1111xxxxxxxx", InstName.Cmn, InstEmit32.Cmn, OpCodeT32AluImm.Create);
|
||||||
|
SetT32("111010111011xxxx0xxx1111xxxxxxxx", InstName.Cmp, InstEmit32.Cmp, OpCodeT32AluRsImm.Create);
|
||||||
|
SetT32("11110x011011xxxx0xxx1111xxxxxxxx", InstName.Cmp, InstEmit32.Cmp, OpCodeT32AluImm.Create);
|
||||||
|
SetT32("11101010100<xxxx0xxx<<<<xxxxxxxx", InstName.Eor, InstEmit32.Eor, OpCodeT32AluRsImm.Create);
|
||||||
|
SetT32("11110x00100<xxxx0xxx<<<<xxxxxxxx", InstName.Eor, InstEmit32.Eor, OpCodeT32AluImm.Create);
|
||||||
|
SetT32("111110000101xxxx<<<<10x1xxxxxxxx", InstName.Ldr, InstEmit32.Ldr, OpCodeT32MemImm8.Create);
|
||||||
|
SetT32("111110000101xxxx<<<<1100xxxxxxxx", InstName.Ldr, InstEmit32.Ldr, OpCodeT32MemImm8.Create);
|
||||||
|
SetT32("111110000101xxxx<<<<11x1xxxxxxxx", InstName.Ldr, InstEmit32.Ldr, OpCodeT32MemImm8.Create);
|
||||||
|
SetT32("111110001101xxxxxxxxxxxxxxxxxxxx", InstName.Ldr, InstEmit32.Ldr, OpCodeT32MemImm12.Create);
|
||||||
|
SetT32("111110000001xxxx<<<<10x1xxxxxxxx", InstName.Ldrb, InstEmit32.Ldrb, OpCodeT32MemImm8.Create);
|
||||||
|
SetT32("111110000001xxxx<<<<1100xxxxxxxx", InstName.Ldrb, InstEmit32.Ldrb, OpCodeT32MemImm8.Create);
|
||||||
|
SetT32("111110000001xxxx<<<<11x1xxxxxxxx", InstName.Ldrb, InstEmit32.Ldrb, OpCodeT32MemImm8.Create);
|
||||||
|
SetT32("111110001001xxxxxxxxxxxxxxxxxxxx", InstName.Ldrb, InstEmit32.Ldrb, OpCodeT32MemImm12.Create);
|
||||||
|
SetT32("111110000011xxxx<<<<10x1xxxxxxxx", InstName.Ldrh, InstEmit32.Ldrh, OpCodeT32MemImm8.Create);
|
||||||
|
SetT32("111110000011xxxx<<<<1100xxxxxxxx", InstName.Ldrh, InstEmit32.Ldrh, OpCodeT32MemImm8.Create);
|
||||||
|
SetT32("111110000011xxxx<<<<11x1xxxxxxxx", InstName.Ldrh, InstEmit32.Ldrh, OpCodeT32MemImm8.Create);
|
||||||
|
SetT32("111110001011xxxxxxxxxxxxxxxxxxxx", InstName.Ldrh, InstEmit32.Ldrh, OpCodeT32MemImm12.Create);
|
||||||
|
SetT32("111110010001xxxx<<<<10x1xxxxxxxx", InstName.Ldrsb, InstEmit32.Ldrsb, OpCodeT32MemImm8.Create);
|
||||||
|
SetT32("111110010001xxxx<<<<1100xxxxxxxx", InstName.Ldrsb, InstEmit32.Ldrsb, OpCodeT32MemImm8.Create);
|
||||||
|
SetT32("111110010001xxxx<<<<11x1xxxxxxxx", InstName.Ldrsb, InstEmit32.Ldrsb, OpCodeT32MemImm8.Create);
|
||||||
|
SetT32("111110011001xxxxxxxxxxxxxxxxxxxx", InstName.Ldrsb, InstEmit32.Ldrsb, OpCodeT32MemImm12.Create);
|
||||||
|
SetT32("111110010011xxxx<<<<10x1xxxxxxxx", InstName.Ldrsh, InstEmit32.Ldrsh, OpCodeT32MemImm8.Create);
|
||||||
|
SetT32("111110010011xxxx<<<<1100xxxxxxxx", InstName.Ldrsh, InstEmit32.Ldrsh, OpCodeT32MemImm8.Create);
|
||||||
|
SetT32("111110010011xxxx<<<<11x1xxxxxxxx", InstName.Ldrsh, InstEmit32.Ldrsh, OpCodeT32MemImm8.Create);
|
||||||
|
SetT32("111110011011xxxxxxxxxxxxxxxxxxxx", InstName.Ldrsh, InstEmit32.Ldrsh, OpCodeT32MemImm12.Create);
|
||||||
|
SetT32("11101010010x11110xxxxxxxxxxxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT32AluRsImm.Create);
|
||||||
|
SetT32("11110x00010x11110xxxxxxxxxxxxxxx", InstName.Mov, InstEmit32.Mov, OpCodeT32AluImm.Create);
|
||||||
|
SetT32("11101010011x11110xxxxxxxxxxxxxxx", InstName.Mvn, InstEmit32.Mvn, OpCodeT32AluRsImm.Create);
|
||||||
|
SetT32("11110x00011x11110xxxxxxxxxxxxxxx", InstName.Mvn, InstEmit32.Mvn, OpCodeT32AluImm.Create);
|
||||||
|
SetT32("11101010011x<<<<0xxxxxxxxxxxxxxx", InstName.Orn, InstEmit32.Orn, OpCodeT32AluRsImm.Create);
|
||||||
|
SetT32("11110x00011x<<<<0xxxxxxxxxxxxxxx", InstName.Orn, InstEmit32.Orn, OpCodeT32AluImm.Create);
|
||||||
|
SetT32("11101010010x<<<<0xxxxxxxxxxxxxxx", InstName.Orr, InstEmit32.Orr, OpCodeT32AluRsImm.Create);
|
||||||
|
SetT32("11110x00010x<<<<0xxxxxxxxxxxxxxx", InstName.Orr, InstEmit32.Orr, OpCodeT32AluImm.Create);
|
||||||
|
SetT32("11101011110xxxxx0xxxxxxxxxxxxxxx", InstName.Rsb, InstEmit32.Rsb, OpCodeT32AluRsImm.Create);
|
||||||
|
SetT32("11110x01110xxxxx0xxxxxxxxxxxxxxx", InstName.Rsb, InstEmit32.Rsb, OpCodeT32AluImm.Create);
|
||||||
|
SetT32("11101011011xxxxx0xxxxxxxxxxxxxxx", InstName.Sbc, InstEmit32.Sbc, OpCodeT32AluRsImm.Create);
|
||||||
|
SetT32("11110x01011xxxxx0xxxxxxxxxxxxxxx", InstName.Sbc, InstEmit32.Sbc, OpCodeT32AluImm.Create);
|
||||||
|
SetT32("111110000100xxxxxxxx1<<>xxxxxxxx", InstName.Str, InstEmit32.Str, OpCodeT32MemImm8.Create);
|
||||||
|
SetT32("111110001100xxxxxxxxxxxxxxxxxxxx", InstName.Str, InstEmit32.Str, OpCodeT32MemImm12.Create);
|
||||||
|
SetT32("111110000000xxxxxxxx1<<>xxxxxxxx", InstName.Strb, InstEmit32.Strb, OpCodeT32MemImm8.Create);
|
||||||
|
SetT32("111110001000xxxxxxxxxxxxxxxxxxxx", InstName.Strb, InstEmit32.Strb, OpCodeT32MemImm12.Create);
|
||||||
|
SetT32("111110000010xxxxxxxx1<<>xxxxxxxx", InstName.Strh, InstEmit32.Strh, OpCodeT32MemImm8.Create);
|
||||||
|
SetT32("111110001010xxxxxxxxxxxxxxxxxxxx", InstName.Strh, InstEmit32.Strh, OpCodeT32MemImm12.Create);
|
||||||
|
SetT32("11101011101<xxxx0xxx<<<<xxxxxxxx", InstName.Sub, InstEmit32.Sub, OpCodeT32AluRsImm.Create);
|
||||||
|
SetT32("11110x01101<xxxx0xxx<<<<xxxxxxxx", InstName.Sub, InstEmit32.Sub, OpCodeT32AluImm.Create);
|
||||||
|
SetT32("111010101001xxxx0xxx1111xxxxxxxx", InstName.Teq, InstEmit32.Teq, OpCodeT32AluRsImm.Create);
|
||||||
|
SetT32("11110x001001xxxx0xxx1111xxxxxxxx", InstName.Teq, InstEmit32.Teq, OpCodeT32AluImm.Create);
|
||||||
|
SetT32("111010100001xxxx0xxx1111xxxxxxxx", InstName.Tst, InstEmit32.Tst, OpCodeT32AluRsImm.Create);
|
||||||
|
SetT32("11110x000001xxxx0xxx1111xxxxxxxx", InstName.Tst, InstEmit32.Tst, OpCodeT32AluImm.Create);
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
FillFastLookupTable(InstA32FastLookup, AllInstA32, ToFastLookupIndexA);
|
||||||
|
FillFastLookupTable(InstT32FastLookup, AllInstT32, ToFastLookupIndexT);
|
||||||
|
FillFastLookupTable(InstA64FastLookup, AllInstA64, ToFastLookupIndexA);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void FillFastLookupTable(InstInfo[][] table, List<InstInfo> allInsts)
|
private static void FillFastLookupTable(InstInfo[][] table, List<InstInfo> allInsts, Func<int, int> ToFastLookupIndex)
|
||||||
{
|
{
|
||||||
List<InstInfo>[] temp = new List<InstInfo>[FastLookupSize];
|
List<InstInfo>[] temp = new List<InstInfo>[FastLookupSize];
|
||||||
|
|
||||||
@ -1007,20 +1152,30 @@ namespace ARMeilleure.Decoders
|
|||||||
|
|
||||||
private static void SetA32(string encoding, InstName name, InstEmitter emitter, MakeOp makeOp)
|
private static void SetA32(string encoding, InstName name, InstEmitter emitter, MakeOp makeOp)
|
||||||
{
|
{
|
||||||
Set(encoding, ExecutionMode.Aarch32Arm, new InstDescriptor(name, emitter), makeOp);
|
Set(encoding, AllInstA32, new InstDescriptor(name, emitter), makeOp);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void SetT16(string encoding, InstName name, InstEmitter emitter, MakeOp makeOp)
|
||||||
|
{
|
||||||
|
encoding = "xxxxxxxxxxxxxxxx" + encoding;
|
||||||
|
Set(encoding, AllInstT32, new InstDescriptor(name, emitter), makeOp);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void SetT32(string encoding, InstName name, InstEmitter emitter, MakeOp makeOp)
|
private static void SetT32(string encoding, InstName name, InstEmitter emitter, MakeOp makeOp)
|
||||||
{
|
{
|
||||||
Set(encoding, ExecutionMode.Aarch32Thumb, new InstDescriptor(name, emitter), makeOp);
|
string reversedEncoding = encoding.Substring(16) + encoding.Substring(0, 16);
|
||||||
|
MakeOp reversedMakeOp =
|
||||||
|
(InstDescriptor inst, ulong address, int opCode)
|
||||||
|
=> makeOp(inst, address, (int)BitOperations.RotateRight((uint)opCode, 16));
|
||||||
|
Set(reversedEncoding, AllInstT32, new InstDescriptor(name, emitter), reversedMakeOp);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void SetA64(string encoding, InstName name, InstEmitter emitter, MakeOp makeOp)
|
private static void SetA64(string encoding, InstName name, InstEmitter emitter, MakeOp makeOp)
|
||||||
{
|
{
|
||||||
Set(encoding, ExecutionMode.Aarch64, new InstDescriptor(name, emitter), makeOp);
|
Set(encoding, AllInstA64, new InstDescriptor(name, emitter), makeOp);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void Set(string encoding, ExecutionMode mode, InstDescriptor inst, MakeOp makeOp)
|
private static void Set(string encoding, List<InstInfo> list, InstDescriptor inst, MakeOp makeOp)
|
||||||
{
|
{
|
||||||
int bit = encoding.Length - 1;
|
int bit = encoding.Length - 1;
|
||||||
int value = 0;
|
int value = 0;
|
||||||
@ -1069,7 +1224,7 @@ namespace ARMeilleure.Decoders
|
|||||||
|
|
||||||
if (xBits == 0)
|
if (xBits == 0)
|
||||||
{
|
{
|
||||||
InsertInst(new InstInfo(xMask, value, inst, makeOp), mode);
|
list.Add(new InstInfo(xMask, value, inst, makeOp));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1085,34 +1240,24 @@ namespace ARMeilleure.Decoders
|
|||||||
|
|
||||||
if (mask != blacklisted)
|
if (mask != blacklisted)
|
||||||
{
|
{
|
||||||
InsertInst(new InstInfo(xMask, value | mask, inst, makeOp), mode);
|
list.Add(new InstInfo(xMask, value | mask, inst, makeOp));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void InsertInst(InstInfo info, ExecutionMode mode)
|
|
||||||
{
|
|
||||||
switch (mode)
|
|
||||||
{
|
|
||||||
case ExecutionMode.Aarch32Arm: AllInstA32.Add(info); break;
|
|
||||||
case ExecutionMode.Aarch32Thumb: AllInstT32.Add(info); break;
|
|
||||||
case ExecutionMode.Aarch64: AllInstA64.Add(info); break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static (InstDescriptor inst, MakeOp makeOp) GetInstA32(int opCode)
|
public static (InstDescriptor inst, MakeOp makeOp) GetInstA32(int opCode)
|
||||||
{
|
{
|
||||||
return GetInstFromList(InstA32FastLookup[ToFastLookupIndex(opCode)], opCode);
|
return GetInstFromList(InstA32FastLookup[ToFastLookupIndexA(opCode)], opCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static (InstDescriptor inst, MakeOp makeOp) GetInstT32(int opCode)
|
public static (InstDescriptor inst, MakeOp makeOp) GetInstT32(int opCode)
|
||||||
{
|
{
|
||||||
return GetInstFromList(InstT32FastLookup[ToFastLookupIndex(opCode)], opCode);
|
return GetInstFromList(InstT32FastLookup[ToFastLookupIndexT(opCode)], opCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static (InstDescriptor inst, MakeOp makeOp) GetInstA64(int opCode)
|
public static (InstDescriptor inst, MakeOp makeOp) GetInstA64(int opCode)
|
||||||
{
|
{
|
||||||
return GetInstFromList(InstA64FastLookup[ToFastLookupIndex(opCode)], opCode);
|
return GetInstFromList(InstA64FastLookup[ToFastLookupIndexA(opCode)], opCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static (InstDescriptor inst, MakeOp makeOp) GetInstFromList(InstInfo[] insts, int opCode)
|
private static (InstDescriptor inst, MakeOp makeOp) GetInstFromList(InstInfo[] insts, int opCode)
|
||||||
@ -1128,9 +1273,14 @@ namespace ARMeilleure.Decoders
|
|||||||
return (new InstDescriptor(InstName.Und, InstEmit.Und), null);
|
return (new InstDescriptor(InstName.Und, InstEmit.Und), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int ToFastLookupIndex(int value)
|
private static int ToFastLookupIndexA(int value)
|
||||||
{
|
{
|
||||||
return ((value >> 10) & 0x00F) | ((value >> 18) & 0xFF0);
|
return ((value >> 10) & 0x00F) | ((value >> 18) & 0xFF0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int ToFastLookupIndexT(int value)
|
||||||
|
{
|
||||||
|
return (value >> 4) & 0xFFF;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
// https://www.intel.com/content/dam/doc/white-paper/advanced-encryption-standard-new-instructions-set-paper.pdf
|
// https://www.intel.com/content/dam/doc/white-paper/advanced-encryption-standard-new-instructions-set-paper.pdf
|
||||||
|
|
||||||
using ARMeilleure.State;
|
using ARMeilleure.State;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace ARMeilleure.Instructions
|
namespace ARMeilleure.Instructions
|
||||||
{
|
{
|
||||||
static class CryptoHelper
|
static class CryptoHelper
|
||||||
{
|
{
|
||||||
#region "LookUp Tables"
|
#region "LookUp Tables"
|
||||||
private static readonly byte[] _sBox = new byte[]
|
private static ReadOnlySpan<byte> _sBox => new byte[]
|
||||||
{
|
{
|
||||||
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
|
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
|
||||||
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
|
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
|
||||||
@ -27,7 +28,7 @@ namespace ARMeilleure.Instructions
|
|||||||
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
|
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly byte[] _invSBox = new byte[]
|
private static ReadOnlySpan<byte> _invSBox => new byte[]
|
||||||
{
|
{
|
||||||
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
|
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
|
||||||
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
|
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
|
||||||
@ -47,7 +48,7 @@ namespace ARMeilleure.Instructions
|
|||||||
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
|
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly byte[] _gfMul02 = new byte[]
|
private static ReadOnlySpan<byte> _gfMul02 => new byte[]
|
||||||
{
|
{
|
||||||
0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
|
0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
|
||||||
0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e,
|
0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e,
|
||||||
@ -67,7 +68,7 @@ namespace ARMeilleure.Instructions
|
|||||||
0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5
|
0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly byte[] _gfMul03 = new byte[]
|
private static ReadOnlySpan<byte> _gfMul03 => new byte[]
|
||||||
{
|
{
|
||||||
0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11,
|
0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11,
|
||||||
0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39, 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21,
|
0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39, 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21,
|
||||||
@ -87,7 +88,7 @@ namespace ARMeilleure.Instructions
|
|||||||
0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, 0x1f, 0x1c, 0x19, 0x1a
|
0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, 0x1f, 0x1c, 0x19, 0x1a
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly byte[] _gfMul09 = new byte[]
|
private static ReadOnlySpan<byte> _gfMul09 => new byte[]
|
||||||
{
|
{
|
||||||
0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77,
|
0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77,
|
||||||
0x90, 0x99, 0x82, 0x8b, 0xb4, 0xbd, 0xa6, 0xaf, 0xd8, 0xd1, 0xca, 0xc3, 0xfc, 0xf5, 0xee, 0xe7,
|
0x90, 0x99, 0x82, 0x8b, 0xb4, 0xbd, 0xa6, 0xaf, 0xd8, 0xd1, 0xca, 0xc3, 0xfc, 0xf5, 0xee, 0xe7,
|
||||||
@ -107,7 +108,7 @@ namespace ARMeilleure.Instructions
|
|||||||
0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e, 0x79, 0x70, 0x6b, 0x62, 0x5d, 0x54, 0x4f, 0x46
|
0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e, 0x79, 0x70, 0x6b, 0x62, 0x5d, 0x54, 0x4f, 0x46
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly byte[] _gfMul0B = new byte[]
|
private static ReadOnlySpan<byte> _gfMul0B => new byte[]
|
||||||
{
|
{
|
||||||
0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31, 0x58, 0x53, 0x4e, 0x45, 0x74, 0x7f, 0x62, 0x69,
|
0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31, 0x58, 0x53, 0x4e, 0x45, 0x74, 0x7f, 0x62, 0x69,
|
||||||
0xb0, 0xbb, 0xa6, 0xad, 0x9c, 0x97, 0x8a, 0x81, 0xe8, 0xe3, 0xfe, 0xf5, 0xc4, 0xcf, 0xd2, 0xd9,
|
0xb0, 0xbb, 0xa6, 0xad, 0x9c, 0x97, 0x8a, 0x81, 0xe8, 0xe3, 0xfe, 0xf5, 0xc4, 0xcf, 0xd2, 0xd9,
|
||||||
@ -127,7 +128,7 @@ namespace ARMeilleure.Instructions
|
|||||||
0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb, 0x92, 0x99, 0x84, 0x8f, 0xbe, 0xb5, 0xa8, 0xa3
|
0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb, 0x92, 0x99, 0x84, 0x8f, 0xbe, 0xb5, 0xa8, 0xa3
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly byte[] _gfMul0D = new byte[]
|
private static ReadOnlySpan<byte> _gfMul0D => new byte[]
|
||||||
{
|
{
|
||||||
0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23, 0x68, 0x65, 0x72, 0x7f, 0x5c, 0x51, 0x46, 0x4b,
|
0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23, 0x68, 0x65, 0x72, 0x7f, 0x5c, 0x51, 0x46, 0x4b,
|
||||||
0xd0, 0xdd, 0xca, 0xc7, 0xe4, 0xe9, 0xfe, 0xf3, 0xb8, 0xb5, 0xa2, 0xaf, 0x8c, 0x81, 0x96, 0x9b,
|
0xd0, 0xdd, 0xca, 0xc7, 0xe4, 0xe9, 0xfe, 0xf3, 0xb8, 0xb5, 0xa2, 0xaf, 0x8c, 0x81, 0x96, 0x9b,
|
||||||
@ -147,7 +148,7 @@ namespace ARMeilleure.Instructions
|
|||||||
0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff, 0xb4, 0xb9, 0xae, 0xa3, 0x80, 0x8d, 0x9a, 0x97
|
0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff, 0xb4, 0xb9, 0xae, 0xa3, 0x80, 0x8d, 0x9a, 0x97
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly byte[] _gfMul0E = new byte[]
|
private static ReadOnlySpan<byte> _gfMul0E => new byte[]
|
||||||
{
|
{
|
||||||
0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a, 0x70, 0x7e, 0x6c, 0x62, 0x48, 0x46, 0x54, 0x5a,
|
0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a, 0x70, 0x7e, 0x6c, 0x62, 0x48, 0x46, 0x54, 0x5a,
|
||||||
0xe0, 0xee, 0xfc, 0xf2, 0xd8, 0xd6, 0xc4, 0xca, 0x90, 0x9e, 0x8c, 0x82, 0xa8, 0xa6, 0xb4, 0xba,
|
0xe0, 0xee, 0xfc, 0xf2, 0xd8, 0xd6, 0xc4, 0xca, 0x90, 0x9e, 0x8c, 0x82, 0xa8, 0xa6, 0xb4, 0xba,
|
||||||
@ -167,12 +168,12 @@ namespace ARMeilleure.Instructions
|
|||||||
0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd, 0xa7, 0xa9, 0xbb, 0xb5, 0x9f, 0x91, 0x83, 0x8d
|
0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd, 0xa7, 0xa9, 0xbb, 0xb5, 0x9f, 0x91, 0x83, 0x8d
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly byte[] _srPerm = new byte[]
|
private static ReadOnlySpan<byte> _srPerm => new byte[]
|
||||||
{
|
{
|
||||||
0, 13, 10, 7, 4, 1, 14, 11, 8, 5, 2, 15, 12, 9, 6, 3
|
0, 13, 10, 7, 4, 1, 14, 11, 8, 5, 2, 15, 12, 9, 6, 3
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly byte[] _isrPerm = new byte[]
|
private static ReadOnlySpan<byte> _isrPerm => new byte[]
|
||||||
{
|
{
|
||||||
0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, 1, 6, 11
|
0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, 1, 6, 11
|
||||||
};
|
};
|
||||||
|
@ -20,7 +20,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
Operand res = context.Add(n, m);
|
Operand res = context.Add(n, m);
|
||||||
|
|
||||||
if (op.SetFlags)
|
if (ShouldSetFlags(context))
|
||||||
{
|
{
|
||||||
EmitNZFlagsCheck(context, res);
|
EmitNZFlagsCheck(context, res);
|
||||||
|
|
||||||
@ -44,7 +44,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
res = context.Add(res, carry);
|
res = context.Add(res, carry);
|
||||||
|
|
||||||
if (op.SetFlags)
|
if (ShouldSetFlags(context))
|
||||||
{
|
{
|
||||||
EmitNZFlagsCheck(context, res);
|
EmitNZFlagsCheck(context, res);
|
||||||
|
|
||||||
@ -64,7 +64,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
Operand res = context.BitwiseAnd(n, m);
|
Operand res = context.BitwiseAnd(n, m);
|
||||||
|
|
||||||
if (op.SetFlags)
|
if (ShouldSetFlags(context))
|
||||||
{
|
{
|
||||||
EmitNZFlagsCheck(context, res);
|
EmitNZFlagsCheck(context, res);
|
||||||
}
|
}
|
||||||
@ -110,7 +110,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
Operand res = context.BitwiseAnd(n, context.BitwiseNot(m));
|
Operand res = context.BitwiseAnd(n, context.BitwiseNot(m));
|
||||||
|
|
||||||
if (op.SetFlags)
|
if (ShouldSetFlags(context))
|
||||||
{
|
{
|
||||||
EmitNZFlagsCheck(context, res);
|
EmitNZFlagsCheck(context, res);
|
||||||
}
|
}
|
||||||
@ -161,7 +161,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
Operand res = context.BitwiseExclusiveOr(n, m);
|
Operand res = context.BitwiseExclusiveOr(n, m);
|
||||||
|
|
||||||
if (op.SetFlags)
|
if (ShouldSetFlags(context))
|
||||||
{
|
{
|
||||||
EmitNZFlagsCheck(context, res);
|
EmitNZFlagsCheck(context, res);
|
||||||
}
|
}
|
||||||
@ -175,7 +175,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
Operand m = GetAluM(context);
|
Operand m = GetAluM(context);
|
||||||
|
|
||||||
if (op.SetFlags)
|
if (ShouldSetFlags(context))
|
||||||
{
|
{
|
||||||
EmitNZFlagsCheck(context, m);
|
EmitNZFlagsCheck(context, m);
|
||||||
}
|
}
|
||||||
@ -204,7 +204,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
Operand res = context.Multiply(n, m);
|
Operand res = context.Multiply(n, m);
|
||||||
|
|
||||||
if (op.SetFlags)
|
if (ShouldSetFlags(context))
|
||||||
{
|
{
|
||||||
EmitNZFlagsCheck(context, res);
|
EmitNZFlagsCheck(context, res);
|
||||||
}
|
}
|
||||||
@ -219,7 +219,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
Operand res = context.BitwiseNot(m);
|
Operand res = context.BitwiseNot(m);
|
||||||
|
|
||||||
if (op.SetFlags)
|
if (ShouldSetFlags(context))
|
||||||
{
|
{
|
||||||
EmitNZFlagsCheck(context, res);
|
EmitNZFlagsCheck(context, res);
|
||||||
}
|
}
|
||||||
@ -236,7 +236,24 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
Operand res = context.BitwiseOr(n, m);
|
Operand res = context.BitwiseOr(n, m);
|
||||||
|
|
||||||
if (op.SetFlags)
|
if (ShouldSetFlags(context))
|
||||||
|
{
|
||||||
|
EmitNZFlagsCheck(context, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
EmitAluStore(context, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Orn(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
IOpCode32Alu op = (IOpCode32Alu)context.CurrOp;
|
||||||
|
|
||||||
|
Operand n = GetAluN(context);
|
||||||
|
Operand m = GetAluM(context);
|
||||||
|
|
||||||
|
Operand res = context.BitwiseOr(n, context.BitwiseNot(m));
|
||||||
|
|
||||||
|
if (ShouldSetFlags(context))
|
||||||
{
|
{
|
||||||
EmitNZFlagsCheck(context, res);
|
EmitNZFlagsCheck(context, res);
|
||||||
}
|
}
|
||||||
@ -315,7 +332,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
res = context.Subtract(res, borrow);
|
res = context.Subtract(res, borrow);
|
||||||
|
|
||||||
if (op.SetFlags)
|
if (ShouldSetFlags(context))
|
||||||
{
|
{
|
||||||
EmitNZFlagsCheck(context, res);
|
EmitNZFlagsCheck(context, res);
|
||||||
|
|
||||||
@ -335,7 +352,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
Operand res = context.Subtract(m, n);
|
Operand res = context.Subtract(m, n);
|
||||||
|
|
||||||
if (op.SetFlags)
|
if (ShouldSetFlags(context))
|
||||||
{
|
{
|
||||||
EmitNZFlagsCheck(context, res);
|
EmitNZFlagsCheck(context, res);
|
||||||
|
|
||||||
@ -359,7 +376,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
res = context.Subtract(res, borrow);
|
res = context.Subtract(res, borrow);
|
||||||
|
|
||||||
if (op.SetFlags)
|
if (ShouldSetFlags(context))
|
||||||
{
|
{
|
||||||
EmitNZFlagsCheck(context, res);
|
EmitNZFlagsCheck(context, res);
|
||||||
|
|
||||||
@ -387,6 +404,16 @@ namespace ARMeilleure.Instructions
|
|||||||
EmitDiv(context, false);
|
EmitDiv(context, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Shadd8(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
EmitHadd8(context, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Shsub8(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
EmitHsub8(context, false);
|
||||||
|
}
|
||||||
|
|
||||||
public static void Ssat(ArmEmitterContext context)
|
public static void Ssat(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
OpCode32Sat op = (OpCode32Sat)context.CurrOp;
|
OpCode32Sat op = (OpCode32Sat)context.CurrOp;
|
||||||
@ -410,7 +437,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
Operand res = context.Subtract(n, m);
|
Operand res = context.Subtract(n, m);
|
||||||
|
|
||||||
if (op.SetFlags)
|
if (ShouldSetFlags(context))
|
||||||
{
|
{
|
||||||
EmitNZFlagsCheck(context, res);
|
EmitNZFlagsCheck(context, res);
|
||||||
|
|
||||||
@ -474,20 +501,12 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
public static void Uhadd8(ArmEmitterContext context)
|
public static void Uhadd8(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
OpCode32AluReg op = (OpCode32AluReg)context.CurrOp;
|
EmitHadd8(context, true);
|
||||||
|
}
|
||||||
|
|
||||||
Operand m = GetIntA32(context, op.Rm);
|
public static void Uhsub8(ArmEmitterContext context)
|
||||||
Operand n = GetIntA32(context, op.Rn);
|
{
|
||||||
|
EmitHsub8(context, true);
|
||||||
Operand xor, res;
|
|
||||||
|
|
||||||
res = context.BitwiseAnd(m, n);
|
|
||||||
xor = context.BitwiseExclusiveOr(m, n);
|
|
||||||
xor = context.ShiftRightUI(xor, Const(1));
|
|
||||||
xor = context.BitwiseAnd(xor, Const(0x7F7F7F7Fu));
|
|
||||||
res = context.Add(res, xor);
|
|
||||||
|
|
||||||
SetIntA32(context, op.Rd, res);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Usat(ArmEmitterContext context)
|
public static void Usat(ArmEmitterContext context)
|
||||||
@ -659,6 +678,71 @@ namespace ARMeilleure.Instructions
|
|||||||
context.MarkLabel(lblEnd);
|
context.MarkLabel(lblEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void EmitHadd8(ArmEmitterContext context, bool unsigned)
|
||||||
|
{
|
||||||
|
OpCode32AluReg op = (OpCode32AluReg)context.CurrOp;
|
||||||
|
|
||||||
|
Operand m = GetIntA32(context, op.Rm);
|
||||||
|
Operand n = GetIntA32(context, op.Rn);
|
||||||
|
|
||||||
|
Operand xor, res, carry;
|
||||||
|
|
||||||
|
// 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 to remove the LSB so that it doesn't leak into the field below.
|
||||||
|
|
||||||
|
res = context.BitwiseAnd(m, n);
|
||||||
|
carry = context.BitwiseExclusiveOr(m, n);
|
||||||
|
xor = context.ShiftRightUI(carry, Const(1));
|
||||||
|
xor = context.BitwiseAnd(xor, Const(0x7F7F7F7Fu));
|
||||||
|
res = context.Add(res, xor);
|
||||||
|
|
||||||
|
if (!unsigned)
|
||||||
|
{
|
||||||
|
// Propagates the sign bit from (x^y)>>1 upwards by one.
|
||||||
|
carry = context.BitwiseAnd(carry, Const(0x80808080u));
|
||||||
|
res = context.BitwiseExclusiveOr(res, carry);
|
||||||
|
}
|
||||||
|
|
||||||
|
SetIntA32(context, op.Rd, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void EmitHsub8(ArmEmitterContext context, bool unsigned)
|
||||||
|
{
|
||||||
|
OpCode32AluReg op = (OpCode32AluReg)context.CurrOp;
|
||||||
|
|
||||||
|
Operand m = GetIntA32(context, op.Rm);
|
||||||
|
Operand n = GetIntA32(context, op.Rn);
|
||||||
|
Operand left, right, carry, res;
|
||||||
|
|
||||||
|
// 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).
|
||||||
|
|
||||||
|
carry = context.BitwiseExclusiveOr(m, n);
|
||||||
|
left = context.ShiftRightUI(carry, Const(1));
|
||||||
|
right = context.BitwiseAnd(carry, m);
|
||||||
|
|
||||||
|
// We must now perform a partitioned subtraction.
|
||||||
|
// We can do this because minuend contains 7 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.
|
||||||
|
|
||||||
|
res = context.BitwiseOr(left, Const(0x80808080));
|
||||||
|
res = context.Subtract(res, right);
|
||||||
|
res = context.BitwiseExclusiveOr(res, Const(0x80808080));
|
||||||
|
|
||||||
|
if (!unsigned)
|
||||||
|
{
|
||||||
|
// We then sign extend the result into this bit.
|
||||||
|
carry = context.BitwiseAnd(carry, Const(0x80808080));
|
||||||
|
res = context.BitwiseExclusiveOr(res, carry);
|
||||||
|
}
|
||||||
|
|
||||||
|
SetIntA32(context, op.Rd, res);
|
||||||
|
}
|
||||||
|
|
||||||
private static void EmitSat(ArmEmitterContext context, int intMin, int intMax)
|
private static void EmitSat(ArmEmitterContext context, int intMin, int intMax)
|
||||||
{
|
{
|
||||||
OpCode32Sat op = (OpCode32Sat)context.CurrOp;
|
OpCode32Sat op = (OpCode32Sat)context.CurrOp;
|
||||||
@ -769,7 +853,7 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
IOpCode32Alu op = (IOpCode32Alu)context.CurrOp;
|
IOpCode32Alu op = (IOpCode32Alu)context.CurrOp;
|
||||||
|
|
||||||
EmitGenericAluStoreA32(context, op.Rd, op.SetFlags, value);
|
EmitGenericAluStoreA32(context, op.Rd, ShouldSetFlags(context), value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,18 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
static class InstEmitAluHelper
|
static class InstEmitAluHelper
|
||||||
{
|
{
|
||||||
|
public static bool ShouldSetFlags(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
IOpCode32HasSetFlags op = (IOpCode32HasSetFlags)context.CurrOp;
|
||||||
|
|
||||||
|
if (op.SetFlags == null)
|
||||||
|
{
|
||||||
|
return !context.IsInIfThenBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
return op.SetFlags.Value;
|
||||||
|
}
|
||||||
|
|
||||||
public static void EmitNZFlagsCheck(ArmEmitterContext context, Operand d)
|
public static void EmitNZFlagsCheck(ArmEmitterContext context, Operand d)
|
||||||
{
|
{
|
||||||
SetFlag(context, PState.NFlag, context.ICompareLess (d, Const(d.Type, 0)));
|
SetFlag(context, PState.NFlag, context.ICompareLess (d, Const(d.Type, 0)));
|
||||||
@ -116,7 +128,7 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
Debug.Assert(value.Type == OperandType.I32);
|
Debug.Assert(value.Type == OperandType.I32);
|
||||||
|
|
||||||
if (IsThumb(context.CurrOp))
|
if (((OpCode32)context.CurrOp).IsThumb())
|
||||||
{
|
{
|
||||||
bool isReturn = IsA32Return(context);
|
bool isReturn = IsA32Return(context);
|
||||||
if (!isReturn)
|
if (!isReturn)
|
||||||
@ -183,9 +195,9 @@ namespace ARMeilleure.Instructions
|
|||||||
switch (context.CurrOp)
|
switch (context.CurrOp)
|
||||||
{
|
{
|
||||||
// ARM32.
|
// ARM32.
|
||||||
case OpCode32AluImm op:
|
case IOpCode32AluImm op:
|
||||||
{
|
{
|
||||||
if (op.SetFlags && op.IsRotated)
|
if (ShouldSetFlags(context) && op.IsRotated && setCarry)
|
||||||
{
|
{
|
||||||
SetFlag(context, PState.CFlag, Const((uint)op.Immediate >> 31));
|
SetFlag(context, PState.CFlag, Const((uint)op.Immediate >> 31));
|
||||||
}
|
}
|
||||||
@ -195,10 +207,8 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
case OpCode32AluImm16 op: return Const(op.Immediate);
|
case OpCode32AluImm16 op: return Const(op.Immediate);
|
||||||
|
|
||||||
case OpCode32AluRsImm op: return GetMShiftedByImmediate(context, op, setCarry);
|
case IOpCode32AluRsImm op: return GetMShiftedByImmediate(context, op, setCarry);
|
||||||
case OpCode32AluRsReg op: return GetMShiftedByReg(context, op, setCarry);
|
case IOpCode32AluRsReg op: return GetMShiftedByReg(context, op, setCarry);
|
||||||
|
|
||||||
case OpCodeT16AluImm8 op: return Const(op.Immediate);
|
|
||||||
|
|
||||||
case IOpCode32AluReg op: return GetIntA32(context, op.Rm);
|
case IOpCode32AluReg op: return GetIntA32(context, op.Rm);
|
||||||
|
|
||||||
@ -249,7 +259,7 @@ namespace ARMeilleure.Instructions
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ARM32 helpers.
|
// ARM32 helpers.
|
||||||
public static Operand GetMShiftedByImmediate(ArmEmitterContext context, OpCode32AluRsImm op, bool setCarry)
|
public static Operand GetMShiftedByImmediate(ArmEmitterContext context, IOpCode32AluRsImm op, bool setCarry)
|
||||||
{
|
{
|
||||||
Operand m = GetIntA32(context, op.Rm);
|
Operand m = GetIntA32(context, op.Rm);
|
||||||
|
|
||||||
@ -267,7 +277,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
if (shift != 0)
|
if (shift != 0)
|
||||||
{
|
{
|
||||||
setCarry &= op.SetFlags;
|
setCarry &= ShouldSetFlags(context);
|
||||||
|
|
||||||
switch (op.ShiftType)
|
switch (op.ShiftType)
|
||||||
{
|
{
|
||||||
@ -305,7 +315,7 @@ namespace ARMeilleure.Instructions
|
|||||||
return shift;
|
return shift;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Operand GetMShiftedByReg(ArmEmitterContext context, OpCode32AluRsReg op, bool setCarry)
|
public static Operand GetMShiftedByReg(ArmEmitterContext context, IOpCode32AluRsReg op, bool setCarry)
|
||||||
{
|
{
|
||||||
Operand m = GetIntA32(context, op.Rm);
|
Operand m = GetIntA32(context, op.Rm);
|
||||||
Operand s = context.ZeroExtend8(OperandType.I32, GetIntA32(context, op.Rs));
|
Operand s = context.ZeroExtend8(OperandType.I32, GetIntA32(context, op.Rs));
|
||||||
@ -314,7 +324,7 @@ namespace ARMeilleure.Instructions
|
|||||||
Operand zeroResult = m;
|
Operand zeroResult = m;
|
||||||
Operand shiftResult = m;
|
Operand shiftResult = m;
|
||||||
|
|
||||||
setCarry &= op.SetFlags;
|
setCarry &= ShouldSetFlags(context);
|
||||||
|
|
||||||
switch (op.ShiftType)
|
switch (op.ShiftType)
|
||||||
{
|
{
|
||||||
|
@ -9,18 +9,25 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
public static void Brk(ArmEmitterContext context)
|
public static void Brk(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
EmitExceptionCall(context, nameof(NativeInterface.Break));
|
OpCodeException op = (OpCodeException)context.CurrOp;
|
||||||
|
|
||||||
|
string name = nameof(NativeInterface.Break);
|
||||||
|
|
||||||
|
context.StoreToContext();
|
||||||
|
|
||||||
|
context.Call(typeof(NativeInterface).GetMethod(name), Const(op.Address), Const(op.Id));
|
||||||
|
|
||||||
|
context.LoadFromContext();
|
||||||
|
|
||||||
|
context.Return(Const(op.Address));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Svc(ArmEmitterContext context)
|
public static void Svc(ArmEmitterContext context)
|
||||||
{
|
|
||||||
EmitExceptionCall(context, nameof(NativeInterface.SupervisorCall));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void EmitExceptionCall(ArmEmitterContext context, string name)
|
|
||||||
{
|
{
|
||||||
OpCodeException op = (OpCodeException)context.CurrOp;
|
OpCodeException op = (OpCodeException)context.CurrOp;
|
||||||
|
|
||||||
|
string name = nameof(NativeInterface.SupervisorCall);
|
||||||
|
|
||||||
context.StoreToContext();
|
context.StoreToContext();
|
||||||
|
|
||||||
context.Call(typeof(NativeInterface).GetMethod(name), Const(op.Address), Const(op.Id));
|
context.Call(typeof(NativeInterface).GetMethod(name), Const(op.Address), Const(op.Id));
|
||||||
@ -41,6 +48,8 @@ namespace ARMeilleure.Instructions
|
|||||||
context.Call(typeof(NativeInterface).GetMethod(name), Const(op.Address), Const(op.RawOpCode));
|
context.Call(typeof(NativeInterface).GetMethod(name), Const(op.Address), Const(op.RawOpCode));
|
||||||
|
|
||||||
context.LoadFromContext();
|
context.LoadFromContext();
|
||||||
|
|
||||||
|
context.Return(Const(op.Address));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,7 +1,5 @@
|
|||||||
using ARMeilleure.Decoders;
|
using ARMeilleure.Decoders;
|
||||||
using ARMeilleure.Translation;
|
using ARMeilleure.Translation;
|
||||||
|
|
||||||
using static ARMeilleure.Instructions.InstEmitFlowHelper;
|
|
||||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
||||||
|
|
||||||
namespace ARMeilleure.Instructions
|
namespace ARMeilleure.Instructions
|
||||||
@ -10,25 +8,32 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
public static void Svc(ArmEmitterContext context)
|
public static void Svc(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
EmitExceptionCall(context, nameof(NativeInterface.SupervisorCall));
|
IOpCode32Exception op = (IOpCode32Exception)context.CurrOp;
|
||||||
}
|
|
||||||
|
|
||||||
public static void Trap(ArmEmitterContext context)
|
string name = nameof(NativeInterface.SupervisorCall);
|
||||||
{
|
|
||||||
EmitExceptionCall(context, nameof(NativeInterface.Break));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void EmitExceptionCall(ArmEmitterContext context, string name)
|
|
||||||
{
|
|
||||||
OpCode32Exception op = (OpCode32Exception)context.CurrOp;
|
|
||||||
|
|
||||||
context.StoreToContext();
|
context.StoreToContext();
|
||||||
|
|
||||||
context.Call(typeof(NativeInterface).GetMethod(name), Const(op.Address), Const(op.Id));
|
context.Call(typeof(NativeInterface).GetMethod(name), Const(((IOpCode)op).Address), Const(op.Id));
|
||||||
|
|
||||||
context.LoadFromContext();
|
context.LoadFromContext();
|
||||||
|
|
||||||
Translator.EmitSynchronization(context);
|
Translator.EmitSynchronization(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Trap(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
IOpCode32Exception op = (IOpCode32Exception)context.CurrOp;
|
||||||
|
|
||||||
|
string name = nameof(NativeInterface.Break);
|
||||||
|
|
||||||
|
context.StoreToContext();
|
||||||
|
|
||||||
|
context.Call(typeof(NativeInterface).GetMethod(name), Const(((IOpCode)op).Address), Const(op.Id));
|
||||||
|
|
||||||
|
context.LoadFromContext();
|
||||||
|
|
||||||
|
context.Return(Const(context.CurrOp.Address));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
uint pc = op.GetPc();
|
uint pc = op.GetPc();
|
||||||
|
|
||||||
bool isThumb = IsThumb(context.CurrOp);
|
bool isThumb = ((OpCode32)context.CurrOp).IsThumb();
|
||||||
|
|
||||||
uint currentPc = isThumb
|
uint currentPc = isThumb
|
||||||
? pc | 1
|
? pc | 1
|
||||||
@ -61,17 +61,17 @@ namespace ARMeilleure.Instructions
|
|||||||
Operand addr = context.Copy(GetIntA32(context, op.Rm));
|
Operand addr = context.Copy(GetIntA32(context, op.Rm));
|
||||||
Operand bitOne = context.BitwiseAnd(addr, Const(1));
|
Operand bitOne = context.BitwiseAnd(addr, Const(1));
|
||||||
|
|
||||||
bool isThumb = IsThumb(context.CurrOp);
|
bool isThumb = ((OpCode32)context.CurrOp).IsThumb();
|
||||||
|
|
||||||
uint currentPc = isThumb
|
uint currentPc = isThumb
|
||||||
? pc | 1
|
? (pc - 2) | 1
|
||||||
: pc - 4;
|
: pc - 4;
|
||||||
|
|
||||||
SetIntA32(context, GetBankedRegisterAlias(context.Mode, RegisterAlias.Aarch32Lr), Const(currentPc));
|
SetIntA32(context, GetBankedRegisterAlias(context.Mode, RegisterAlias.Aarch32Lr), Const(currentPc));
|
||||||
|
|
||||||
SetFlag(context, PState.TFlag, bitOne);
|
SetFlag(context, PState.TFlag, bitOne);
|
||||||
|
|
||||||
EmitVirtualCall(context, addr);
|
EmitBxWritePc(context, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Bx(ArmEmitterContext context)
|
public static void Bx(ArmEmitterContext context)
|
||||||
@ -80,5 +80,32 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
EmitBxWritePc(context, GetIntA32(context, op.Rm), op.Rm);
|
EmitBxWritePc(context, GetIntA32(context, op.Rm), op.Rm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Cbnz(ArmEmitterContext context) => EmitCb(context, onNotZero: true);
|
||||||
|
public static void Cbz(ArmEmitterContext context) => EmitCb(context, onNotZero: false);
|
||||||
|
|
||||||
|
private static void EmitCb(ArmEmitterContext context, bool onNotZero)
|
||||||
|
{
|
||||||
|
OpCodeT16BImmCmp op = (OpCodeT16BImmCmp)context.CurrOp;
|
||||||
|
|
||||||
|
Operand value = GetIntOrZR(context, op.Rn);
|
||||||
|
Operand lblTarget = context.GetLabel((ulong)op.Immediate);
|
||||||
|
|
||||||
|
if (onNotZero)
|
||||||
|
{
|
||||||
|
context.BranchIfTrue(lblTarget, value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
context.BranchIfFalse(lblTarget, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void It(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
OpCodeT16IfThen op = (OpCodeT16IfThen)context.CurrOp;
|
||||||
|
|
||||||
|
context.SetIfThenBlockState(op.IfThenBlockConds);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -10,11 +10,6 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
static class InstEmitHelper
|
static class InstEmitHelper
|
||||||
{
|
{
|
||||||
public static bool IsThumb(OpCode op)
|
|
||||||
{
|
|
||||||
return op is OpCodeT16;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Operand GetExtendedM(ArmEmitterContext context, int rm, IntType type)
|
public static Operand GetExtendedM(ArmEmitterContext context, int rm, IntType type)
|
||||||
{
|
{
|
||||||
Operand value = GetIntOrZR(context, rm);
|
Operand value = GetIntOrZR(context, rm);
|
||||||
@ -47,6 +42,20 @@ namespace ARMeilleure.Instructions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Operand GetIntA32AlignedPC(ArmEmitterContext context, int regIndex)
|
||||||
|
{
|
||||||
|
if (regIndex == RegisterAlias.Aarch32Pc)
|
||||||
|
{
|
||||||
|
OpCode32 op = (OpCode32)context.CurrOp;
|
||||||
|
|
||||||
|
return Const((int)(op.GetPc() & 0xfffffffc));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Register(GetRegisterAlias(context.Mode, regIndex), RegisterType.Integer, OperandType.I32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static Operand GetVecA32(int regIndex)
|
public static Operand GetVecA32(int regIndex)
|
||||||
{
|
{
|
||||||
return Register(regIndex, RegisterType.Vector, OperandType.V128);
|
return Register(regIndex, RegisterType.Vector, OperandType.V128);
|
||||||
@ -172,7 +181,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
SetFlag(context, PState.TFlag, mode);
|
SetFlag(context, PState.TFlag, mode);
|
||||||
|
|
||||||
Operand addr = context.ConditionalSelect(mode, pc, context.BitwiseAnd(pc, Const(~3)));
|
Operand addr = context.ConditionalSelect(mode, context.BitwiseAnd(pc, Const(~1)), context.BitwiseAnd(pc, Const(~3)));
|
||||||
|
|
||||||
InstEmitFlowHelper.EmitVirtualJump(context, addr, isReturn);
|
InstEmitFlowHelper.EmitVirtualJump(context, addr, isReturn);
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
public static void Ldm(ArmEmitterContext context)
|
public static void Ldm(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
OpCode32MemMult op = (OpCode32MemMult)context.CurrOp;
|
IOpCode32MemMult op = (IOpCode32MemMult)context.CurrOp;
|
||||||
|
|
||||||
Operand n = GetIntA32(context, op.Rn);
|
Operand n = GetIntA32(context, op.Rn);
|
||||||
|
|
||||||
@ -95,7 +95,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
public static void Stm(ArmEmitterContext context)
|
public static void Stm(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
OpCode32MemMult op = (OpCode32MemMult)context.CurrOp;
|
IOpCode32MemMult op = (IOpCode32MemMult)context.CurrOp;
|
||||||
|
|
||||||
Operand n = context.Copy(GetIntA32(context, op.Rn));
|
Operand n = context.Copy(GetIntA32(context, op.Rn));
|
||||||
|
|
||||||
@ -151,9 +151,9 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
private static void EmitLoadOrStore(ArmEmitterContext context, int size, AccessType accType)
|
private static void EmitLoadOrStore(ArmEmitterContext context, int size, AccessType accType)
|
||||||
{
|
{
|
||||||
OpCode32Mem op = (OpCode32Mem)context.CurrOp;
|
IOpCode32Mem op = (IOpCode32Mem)context.CurrOp;
|
||||||
|
|
||||||
Operand n = context.Copy(GetIntA32(context, op.Rn));
|
Operand n = context.Copy(GetIntA32AlignedPC(context, op.Rn));
|
||||||
Operand m = GetMemM(context, setCarry: false);
|
Operand m = GetMemM(context, setCarry: false);
|
||||||
|
|
||||||
Operand temp = default;
|
Operand temp = default;
|
||||||
@ -255,5 +255,11 @@ namespace ARMeilleure.Instructions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Adr(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
IOpCode32Adr op = (IOpCode32Adr)context.CurrOp;
|
||||||
|
SetIntA32(context, op.Rd, Const(op.Immediate));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -130,11 +130,6 @@ namespace ARMeilleure.Instructions
|
|||||||
bool ordered = (accType & AccessType.Ordered) != 0;
|
bool ordered = (accType & AccessType.Ordered) != 0;
|
||||||
bool exclusive = (accType & AccessType.Exclusive) != 0;
|
bool exclusive = (accType & AccessType.Exclusive) != 0;
|
||||||
|
|
||||||
if (ordered)
|
|
||||||
{
|
|
||||||
EmitBarrier(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
Operand address = context.Copy(GetIntOrSP(context, op.Rn));
|
Operand address = context.Copy(GetIntOrSP(context, op.Rn));
|
||||||
|
|
||||||
Operand t = GetIntOrZR(context, op.Rt);
|
Operand t = GetIntOrZR(context, op.Rt);
|
||||||
@ -163,6 +158,11 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
EmitStoreExclusive(context, address, t, exclusive, op.Size, op.Rs, a32: false);
|
EmitStoreExclusive(context, address, t, exclusive, op.Size, op.Rs, a32: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ordered)
|
||||||
|
{
|
||||||
|
EmitBarrier(context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void EmitBarrier(ArmEmitterContext context)
|
private static void EmitBarrier(ArmEmitterContext context)
|
||||||
|
@ -146,13 +146,13 @@ namespace ARMeilleure.Instructions
|
|||||||
var exclusive = (accType & AccessType.Exclusive) != 0;
|
var exclusive = (accType & AccessType.Exclusive) != 0;
|
||||||
var ordered = (accType & AccessType.Ordered) != 0;
|
var ordered = (accType & AccessType.Ordered) != 0;
|
||||||
|
|
||||||
if (ordered)
|
|
||||||
{
|
|
||||||
EmitBarrier(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((accType & AccessType.Load) != 0)
|
if ((accType & AccessType.Load) != 0)
|
||||||
{
|
{
|
||||||
|
if (ordered)
|
||||||
|
{
|
||||||
|
EmitBarrier(context);
|
||||||
|
}
|
||||||
|
|
||||||
if (size == DWordSizeLog2)
|
if (size == DWordSizeLog2)
|
||||||
{
|
{
|
||||||
// Keep loads atomic - make the call to get the whole region and then decompose it into parts
|
// Keep loads atomic - make the call to get the whole region and then decompose it into parts
|
||||||
@ -219,6 +219,11 @@ namespace ARMeilleure.Instructions
|
|||||||
Operand value = context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Rt));
|
Operand value = context.ZeroExtend32(OperandType.I64, GetIntA32(context, op.Rt));
|
||||||
EmitStoreExclusive(context, address, value, exclusive, size, op.Rd, a32: true);
|
EmitStoreExclusive(context, address, value, exclusive, size, op.Rd, a32: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ordered)
|
||||||
|
{
|
||||||
|
EmitBarrier(context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -549,9 +549,9 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
case OpCode32MemRsImm op: return GetMShiftedByImmediate(context, op, setCarry);
|
case OpCode32MemRsImm op: return GetMShiftedByImmediate(context, op, setCarry);
|
||||||
|
|
||||||
case OpCode32MemReg op: return GetIntA32(context, op.Rm);
|
case IOpCode32MemReg op: return GetIntA32(context, op.Rm);
|
||||||
|
|
||||||
case OpCode32Mem op: return Const(op.Immediate);
|
case IOpCode32Mem op: return Const(op.Immediate);
|
||||||
|
|
||||||
case OpCode32SimdMemImm op: return Const(op.Immediate);
|
case OpCode32SimdMemImm op: return Const(op.Immediate);
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
Operand res = context.Add(a, context.Multiply(n, m));
|
Operand res = context.Add(a, context.Multiply(n, m));
|
||||||
|
|
||||||
if (op.SetFlags)
|
if (ShouldSetFlags(context))
|
||||||
{
|
{
|
||||||
EmitNZFlagsCheck(context, res);
|
EmitNZFlagsCheck(context, res);
|
||||||
}
|
}
|
||||||
@ -250,13 +250,13 @@ namespace ARMeilleure.Instructions
|
|||||||
Operand hi = context.ConvertI64ToI32(context.ShiftRightUI(res, Const(32)));
|
Operand hi = context.ConvertI64ToI32(context.ShiftRightUI(res, Const(32)));
|
||||||
Operand lo = context.ConvertI64ToI32(res);
|
Operand lo = context.ConvertI64ToI32(res);
|
||||||
|
|
||||||
if (op.SetFlags)
|
if (ShouldSetFlags(context))
|
||||||
{
|
{
|
||||||
EmitNZFlagsCheck(context, res);
|
EmitNZFlagsCheck(context, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
EmitGenericAluStoreA32(context, op.RdHi, op.SetFlags, hi);
|
EmitGenericAluStoreA32(context, op.RdHi, ShouldSetFlags(context), hi);
|
||||||
EmitGenericAluStoreA32(context, op.RdLo, op.SetFlags, lo);
|
EmitGenericAluStoreA32(context, op.RdLo, ShouldSetFlags(context), lo);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Smulw_(ArmEmitterContext context)
|
public static void Smulw_(ArmEmitterContext context)
|
||||||
@ -320,13 +320,13 @@ namespace ARMeilleure.Instructions
|
|||||||
Operand hi = context.ConvertI64ToI32(context.ShiftRightUI(res, Const(32)));
|
Operand hi = context.ConvertI64ToI32(context.ShiftRightUI(res, Const(32)));
|
||||||
Operand lo = context.ConvertI64ToI32(res);
|
Operand lo = context.ConvertI64ToI32(res);
|
||||||
|
|
||||||
if (op.SetFlags)
|
if (ShouldSetFlags(context))
|
||||||
{
|
{
|
||||||
EmitNZFlagsCheck(context, res);
|
EmitNZFlagsCheck(context, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
EmitGenericAluStoreA32(context, op.RdHi, op.SetFlags, hi);
|
EmitGenericAluStoreA32(context, op.RdHi, ShouldSetFlags(context), hi);
|
||||||
EmitGenericAluStoreA32(context, op.RdLo, op.SetFlags, lo);
|
EmitGenericAluStoreA32(context, op.RdLo, ShouldSetFlags(context), lo);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void EmitMlal(ArmEmitterContext context, bool signed)
|
private static void EmitMlal(ArmEmitterContext context, bool signed)
|
||||||
@ -356,13 +356,13 @@ namespace ARMeilleure.Instructions
|
|||||||
Operand hi = context.ConvertI64ToI32(context.ShiftRightUI(res, Const(32)));
|
Operand hi = context.ConvertI64ToI32(context.ShiftRightUI(res, Const(32)));
|
||||||
Operand lo = context.ConvertI64ToI32(res);
|
Operand lo = context.ConvertI64ToI32(res);
|
||||||
|
|
||||||
if (op.SetFlags)
|
if (ShouldSetFlags(context))
|
||||||
{
|
{
|
||||||
EmitNZFlagsCheck(context, res);
|
EmitNZFlagsCheck(context, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
EmitGenericAluStoreA32(context, op.RdHi, op.SetFlags, hi);
|
EmitGenericAluStoreA32(context, op.RdHi, ShouldSetFlags(context), hi);
|
||||||
EmitGenericAluStoreA32(context, op.RdLo, op.SetFlags, lo);
|
EmitGenericAluStoreA32(context, op.RdLo, ShouldSetFlags(context), lo);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void UpdateQFlag(ArmEmitterContext context, Operand q)
|
private static void UpdateQFlag(ArmEmitterContext context, Operand q)
|
||||||
|
@ -3613,7 +3613,7 @@ namespace ARMeilleure.Instructions
|
|||||||
Operand masked = context.AddIntrinsic(Intrinsic.X86Pand, value, expMask);
|
Operand masked = context.AddIntrinsic(Intrinsic.X86Pand, value, expMask);
|
||||||
Operand isNaNInf = context.AddIntrinsic(Intrinsic.X86Pcmpeqd, masked, expMask);
|
Operand isNaNInf = context.AddIntrinsic(Intrinsic.X86Pcmpeqd, masked, expMask);
|
||||||
|
|
||||||
value = context.AddIntrinsic(Intrinsic.X86Paddw, value, roundMask);
|
value = context.AddIntrinsic(Intrinsic.X86Paddd, value, roundMask);
|
||||||
value = context.AddIntrinsic(Intrinsic.X86Pand, value, truncMask);
|
value = context.AddIntrinsic(Intrinsic.X86Pand, value, truncMask);
|
||||||
|
|
||||||
return context.AddIntrinsic(Intrinsic.X86Blendvps, value, oValue, isNaNInf);
|
return context.AddIntrinsic(Intrinsic.X86Blendvps, value, oValue, isNaNInf);
|
||||||
|
@ -2,8 +2,6 @@
|
|||||||
using ARMeilleure.IntermediateRepresentation;
|
using ARMeilleure.IntermediateRepresentation;
|
||||||
using ARMeilleure.Translation;
|
using ARMeilleure.Translation;
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
|
||||||
|
|
||||||
using static ARMeilleure.Instructions.InstEmitFlowHelper;
|
using static ARMeilleure.Instructions.InstEmitFlowHelper;
|
||||||
using static ARMeilleure.Instructions.InstEmitHelper;
|
using static ARMeilleure.Instructions.InstEmitHelper;
|
||||||
using static ARMeilleure.Instructions.InstEmitSimdHelper;
|
using static ARMeilleure.Instructions.InstEmitSimdHelper;
|
||||||
|
@ -105,11 +105,48 @@ namespace ARMeilleure.Instructions
|
|||||||
}
|
}
|
||||||
else if (op.Size == 1 && op.Opc == 3) // Double -> Half.
|
else if (op.Size == 1 && op.Opc == 3) // Double -> Half.
|
||||||
{
|
{
|
||||||
throw new NotImplementedException("Double-precision to half-precision.");
|
if (Optimizations.UseF16c)
|
||||||
|
{
|
||||||
|
Debug.Assert(!Optimizations.ForceLegacySse);
|
||||||
|
|
||||||
|
Operand n = GetVec(op.Rn);
|
||||||
|
|
||||||
|
Operand res = context.AddIntrinsic(Intrinsic.X86Cvtsd2ss, context.VectorZero(), n);
|
||||||
|
res = context.AddIntrinsic(Intrinsic.X86Vcvtps2ph, res, Const(X86GetRoundControl(FPRoundingMode.ToNearest)));
|
||||||
|
|
||||||
|
context.Copy(GetVec(op.Rd), res);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Operand ne = context.VectorExtract(OperandType.FP64, GetVec(op.Rn), 0);
|
||||||
|
|
||||||
|
Operand res = context.Call(typeof(SoftFloat64_16).GetMethod(nameof(SoftFloat64_16.FPConvert)), ne);
|
||||||
|
|
||||||
|
res = context.ZeroExtend16(OperandType.I64, res);
|
||||||
|
|
||||||
|
context.Copy(GetVec(op.Rd), EmitVectorInsert(context, context.VectorZero(), res, 0, 1));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (op.Size == 3 && op.Opc == 1) // Double -> Half.
|
else if (op.Size == 3 && op.Opc == 1) // Half -> Double.
|
||||||
{
|
{
|
||||||
throw new NotImplementedException("Half-precision to double-precision.");
|
if (Optimizations.UseF16c)
|
||||||
|
{
|
||||||
|
Operand n = GetVec(op.Rn);
|
||||||
|
|
||||||
|
Operand res = context.AddIntrinsic(Intrinsic.X86Vcvtph2ps, GetVec(op.Rn));
|
||||||
|
res = context.AddIntrinsic(Intrinsic.X86Cvtss2sd, context.VectorZero(), res);
|
||||||
|
res = context.VectorZeroUpper64(res);
|
||||||
|
|
||||||
|
context.Copy(GetVec(op.Rd), res);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Operand ne = EmitVectorExtractZx(context, op.Rn, 0, 1);
|
||||||
|
|
||||||
|
Operand res = context.Call(typeof(SoftFloat16_64).GetMethod(nameof(SoftFloat16_64.FPConvert)), ne);
|
||||||
|
|
||||||
|
context.Copy(GetVec(op.Rd), context.VectorInsert(context.VectorZero(), res, 0));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else // Invalid encoding.
|
else // Invalid encoding.
|
||||||
{
|
{
|
||||||
|
64
ARMeilleure/Instructions/InstEmitSimdHash32.cs
Normal file
64
ARMeilleure/Instructions/InstEmitSimdHash32.cs
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
using ARMeilleure.Decoders;
|
||||||
|
using ARMeilleure.IntermediateRepresentation;
|
||||||
|
using ARMeilleure.Translation;
|
||||||
|
|
||||||
|
using static ARMeilleure.Instructions.InstEmitHelper;
|
||||||
|
|
||||||
|
namespace ARMeilleure.Instructions
|
||||||
|
{
|
||||||
|
static partial class InstEmit32
|
||||||
|
{
|
||||||
|
#region "Sha256"
|
||||||
|
public static void Sha256h_V(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
|
||||||
|
|
||||||
|
Operand d = GetVecA32(op.Qd);
|
||||||
|
Operand n = GetVecA32(op.Qn);
|
||||||
|
Operand m = GetVecA32(op.Qm);
|
||||||
|
|
||||||
|
Operand res = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashLower)), d, n, m);
|
||||||
|
|
||||||
|
context.Copy(GetVecA32(op.Qd), res);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Sha256h2_V(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
|
||||||
|
|
||||||
|
Operand d = GetVecA32(op.Qd);
|
||||||
|
Operand n = GetVecA32(op.Qn);
|
||||||
|
Operand m = GetVecA32(op.Qm);
|
||||||
|
|
||||||
|
Operand res = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashUpper)), d, n, m);
|
||||||
|
|
||||||
|
context.Copy(GetVecA32(op.Qd), res);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Sha256su0_V(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
OpCode32Simd op = (OpCode32Simd)context.CurrOp;
|
||||||
|
|
||||||
|
Operand d = GetVecA32(op.Qd);
|
||||||
|
Operand m = GetVecA32(op.Qm);
|
||||||
|
|
||||||
|
Operand res = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha256SchedulePart1)), d, m);
|
||||||
|
|
||||||
|
context.Copy(GetVecA32(op.Qd), res);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Sha256su1_V(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
|
||||||
|
|
||||||
|
Operand d = GetVecA32(op.Qd);
|
||||||
|
Operand n = GetVecA32(op.Qn);
|
||||||
|
Operand m = GetVecA32(op.Qm);
|
||||||
|
|
||||||
|
Operand res = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha256SchedulePart2)), d, n, m);
|
||||||
|
|
||||||
|
context.Copy(GetVecA32(op.Qd), res);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
@ -12,7 +12,8 @@ namespace ARMeilleure.Instructions
|
|||||||
{
|
{
|
||||||
static partial class InstEmit
|
static partial class InstEmit
|
||||||
{
|
{
|
||||||
private const int DczSizeLog2 = 4;
|
private const int DczSizeLog2 = 4; // Log2 size in words
|
||||||
|
public const int DczSizeInBytes = 4 << DczSizeLog2;
|
||||||
|
|
||||||
public static void Hint(ArmEmitterContext context)
|
public static void Hint(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
@ -32,13 +33,13 @@ namespace ARMeilleure.Instructions
|
|||||||
|
|
||||||
switch (GetPackedId(op))
|
switch (GetPackedId(op))
|
||||||
{
|
{
|
||||||
case 0b11_011_0000_0000_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCtrEl0)); break;
|
case 0b11_011_0000_0000_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCtrEl0)); break;
|
||||||
case 0b11_011_0000_0000_111: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetDczidEl0)); break;
|
case 0b11_011_0000_0000_111: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetDczidEl0)); break;
|
||||||
case 0b11_011_0100_0010_000: EmitGetNzcv(context); return;
|
case 0b11_011_0100_0010_000: EmitGetNzcv(context); return;
|
||||||
case 0b11_011_0100_0100_000: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpcr)); break;
|
case 0b11_011_0100_0100_000: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpcr)); break;
|
||||||
case 0b11_011_0100_0100_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpsr)); break;
|
case 0b11_011_0100_0100_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpsr)); break;
|
||||||
case 0b11_011_1101_0000_010: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrEl0)); break;
|
case 0b11_011_1101_0000_010: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrEl0)); break;
|
||||||
case 0b11_011_1101_0000_011: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidr)); break;
|
case 0b11_011_1101_0000_011: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrroEl0)); break;
|
||||||
case 0b11_011_1110_0000_000: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntfrqEl0)); break;
|
case 0b11_011_1110_0000_000: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntfrqEl0)); break;
|
||||||
case 0b11_011_1110_0000_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntpctEl0)); break;
|
case 0b11_011_1110_0000_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntpctEl0)); break;
|
||||||
case 0b11_011_1110_0000_010: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntvctEl0)); break;
|
case 0b11_011_1110_0000_010: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntvctEl0)); break;
|
||||||
@ -87,7 +88,7 @@ namespace ARMeilleure.Instructions
|
|||||||
// DC ZVA
|
// DC ZVA
|
||||||
Operand t = GetIntOrZR(context, op.Rt);
|
Operand t = GetIntOrZR(context, op.Rt);
|
||||||
|
|
||||||
for (long offset = 0; offset < (4 << DczSizeLog2); offset += 8)
|
for (long offset = 0; offset < DczSizeInBytes; offset += 8)
|
||||||
{
|
{
|
||||||
Operand address = context.Add(t, Const(offset));
|
Operand address = context.Add(t, Const(offset));
|
||||||
|
|
||||||
@ -98,7 +99,12 @@ namespace ARMeilleure.Instructions
|
|||||||
}
|
}
|
||||||
|
|
||||||
// No-op
|
// No-op
|
||||||
case 0b11_011_0111_1110_001: //DC CIVAC
|
case 0b11_011_0111_1110_001: // DC CIVAC
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0b11_011_0111_0101_001: // IC IVAU
|
||||||
|
Operand target = Register(op.Rt, RegisterType.Integer, OperandType.I64);
|
||||||
|
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.InvalidateCacheLine)), target);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -169,6 +169,31 @@ namespace ARMeilleure.Instructions
|
|||||||
SetIntA32(context, op.CRn, context.ConvertI64ToI32(context.ShiftRightUI(result, Const(32))));
|
SetIntA32(context, op.CRn, context.ConvertI64ToI32(context.ShiftRightUI(result, Const(32))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Mrs(ArmEmitterContext context)
|
||||||
|
{
|
||||||
|
OpCode32Mrs op = (OpCode32Mrs)context.CurrOp;
|
||||||
|
|
||||||
|
if (op.R)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException("SPSR");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Operand vSh = context.ShiftLeft(GetFlag(PState.VFlag), Const((int)PState.VFlag));
|
||||||
|
Operand cSh = context.ShiftLeft(GetFlag(PState.CFlag), Const((int)PState.CFlag));
|
||||||
|
Operand zSh = context.ShiftLeft(GetFlag(PState.ZFlag), Const((int)PState.ZFlag));
|
||||||
|
Operand nSh = context.ShiftLeft(GetFlag(PState.NFlag), Const((int)PState.NFlag));
|
||||||
|
Operand qSh = context.ShiftLeft(GetFlag(PState.QFlag), Const((int)PState.QFlag));
|
||||||
|
|
||||||
|
Operand spsr = context.BitwiseOr(context.BitwiseOr(nSh, zSh), context.BitwiseOr(cSh, vSh));
|
||||||
|
spsr = context.BitwiseOr(spsr, qSh);
|
||||||
|
|
||||||
|
// TODO: Remaining flags.
|
||||||
|
|
||||||
|
SetIntA32(context, op.Rd, spsr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void Msr(ArmEmitterContext context)
|
public static void Msr(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
OpCode32MsrReg op = (OpCode32MsrReg)context.CurrOp;
|
OpCode32MsrReg op = (OpCode32MsrReg)context.CurrOp;
|
||||||
|
@ -48,6 +48,7 @@ namespace ARMeilleure.Instructions
|
|||||||
Extr,
|
Extr,
|
||||||
Hint,
|
Hint,
|
||||||
Isb,
|
Isb,
|
||||||
|
It,
|
||||||
Ldar,
|
Ldar,
|
||||||
Ldaxp,
|
Ldaxp,
|
||||||
Ldaxr,
|
Ldaxr,
|
||||||
@ -80,6 +81,7 @@ namespace ARMeilleure.Instructions
|
|||||||
Sbcs,
|
Sbcs,
|
||||||
Sbfm,
|
Sbfm,
|
||||||
Sdiv,
|
Sdiv,
|
||||||
|
Shsub8,
|
||||||
Smaddl,
|
Smaddl,
|
||||||
Smsubl,
|
Smsubl,
|
||||||
Smulh,
|
Smulh,
|
||||||
@ -511,11 +513,14 @@ namespace ARMeilleure.Instructions
|
|||||||
Mvn,
|
Mvn,
|
||||||
Pkh,
|
Pkh,
|
||||||
Pld,
|
Pld,
|
||||||
|
Pop,
|
||||||
|
Push,
|
||||||
Rev,
|
Rev,
|
||||||
Revsh,
|
Revsh,
|
||||||
Rsb,
|
Rsb,
|
||||||
Rsc,
|
Rsc,
|
||||||
Sbfx,
|
Sbfx,
|
||||||
|
Shadd8,
|
||||||
Smla__,
|
Smla__,
|
||||||
Smlal,
|
Smlal,
|
||||||
Smlal__,
|
Smlal__,
|
||||||
@ -545,6 +550,7 @@ namespace ARMeilleure.Instructions
|
|||||||
Tst,
|
Tst,
|
||||||
Ubfx,
|
Ubfx,
|
||||||
Uhadd8,
|
Uhadd8,
|
||||||
|
Uhsub8,
|
||||||
Umaal,
|
Umaal,
|
||||||
Umlal,
|
Umlal,
|
||||||
Umull,
|
Umull,
|
||||||
|
@ -2,8 +2,6 @@ using ARMeilleure.Memory;
|
|||||||
using ARMeilleure.State;
|
using ARMeilleure.State;
|
||||||
using ARMeilleure.Translation;
|
using ARMeilleure.Translation;
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace ARMeilleure.Instructions
|
namespace ARMeilleure.Instructions
|
||||||
{
|
{
|
||||||
@ -107,14 +105,14 @@ namespace ARMeilleure.Instructions
|
|||||||
return (uint)GetContext().TpidrEl0;
|
return (uint)GetContext().TpidrEl0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ulong GetTpidr()
|
public static ulong GetTpidrroEl0()
|
||||||
{
|
{
|
||||||
return (ulong)GetContext().Tpidr;
|
return (ulong)GetContext().TpidrroEl0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static uint GetTpidr32()
|
public static uint GetTpidr32()
|
||||||
{
|
{
|
||||||
return (uint)GetContext().Tpidr;
|
return (uint)GetContext().TpidrroEl0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ulong GetCntfrqEl0()
|
public static ulong GetCntfrqEl0()
|
||||||
@ -242,6 +240,11 @@ namespace ARMeilleure.Instructions
|
|||||||
return (ulong)function.FuncPtr.ToInt64();
|
return (ulong)function.FuncPtr.ToInt64();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void InvalidateCacheLine(ulong address)
|
||||||
|
{
|
||||||
|
Context.Translator.InvalidateJitCacheRegion(address, InstEmit.DczSizeInBytes);
|
||||||
|
}
|
||||||
|
|
||||||
public static bool CheckSynchronization()
|
public static bool CheckSynchronization()
|
||||||
{
|
{
|
||||||
Statistics.PauseTimer();
|
Statistics.PauseTimer();
|
||||||
|
@ -824,7 +824,7 @@ namespace ARMeilleure.Instructions
|
|||||||
return (ulong)(size - 1);
|
return (ulong)(size - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly byte[] ClzNibbleTbl = { 4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 };
|
private static ReadOnlySpan<byte> ClzNibbleTbl => new byte[] { 4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||||
|
|
||||||
public static ulong CountLeadingZeros(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.).
|
public static ulong CountLeadingZeros(ulong value, int size) // size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.).
|
||||||
{
|
{
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -14,10 +14,11 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||||||
public byte Kind;
|
public byte Kind;
|
||||||
public byte Type;
|
public byte Type;
|
||||||
public byte SymbolType;
|
public byte SymbolType;
|
||||||
|
public byte Padding; // Unused space.
|
||||||
public ushort AssignmentsCount;
|
public ushort AssignmentsCount;
|
||||||
public ushort AssignmentsCapacity;
|
public ushort AssignmentsCapacity;
|
||||||
public ushort UsesCount;
|
public uint UsesCount;
|
||||||
public ushort UsesCapacity;
|
public uint UsesCapacity;
|
||||||
public Operation* Assignments;
|
public Operation* Assignments;
|
||||||
public Operation* Uses;
|
public Operation* Uses;
|
||||||
public ulong Value;
|
public ulong Value;
|
||||||
@ -84,11 +85,11 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||||||
{
|
{
|
||||||
Debug.Assert(Kind != OperandKind.Memory);
|
Debug.Assert(Kind != OperandKind.Memory);
|
||||||
|
|
||||||
return new ReadOnlySpan<Operation>(_data->Uses, _data->UsesCount);
|
return new ReadOnlySpan<Operation>(_data->Uses, (int)_data->UsesCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int UsesCount => _data->UsesCount;
|
public int UsesCount => (int)_data->UsesCount;
|
||||||
public int AssignmentsCount => _data->AssignmentsCount;
|
public int AssignmentsCount => _data->AssignmentsCount;
|
||||||
|
|
||||||
public bool Relocatable => Symbol.Type != SymbolType.None;
|
public bool Relocatable => Symbol.Type != SymbolType.None;
|
||||||
@ -178,7 +179,7 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||||||
{
|
{
|
||||||
Add(operation, ref addr._data->Assignments, ref addr._data->AssignmentsCount, ref addr._data->AssignmentsCapacity);
|
Add(operation, ref addr._data->Assignments, ref addr._data->AssignmentsCount, ref addr._data->AssignmentsCapacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index != default)
|
if (index != default)
|
||||||
{
|
{
|
||||||
Add(operation, ref index._data->Assignments, ref index._data->AssignmentsCount, ref index._data->AssignmentsCapacity);
|
Add(operation, ref index._data->Assignments, ref index._data->AssignmentsCount, ref index._data->AssignmentsCapacity);
|
||||||
@ -265,6 +266,13 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||||||
data = Allocators.References.Allocate<T>(initialCapacity);
|
data = Allocators.References.Allocate<T>(initialCapacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void New<T>(ref T* data, ref uint count, ref uint capacity, uint initialCapacity) where T : unmanaged
|
||||||
|
{
|
||||||
|
count = 0;
|
||||||
|
capacity = initialCapacity;
|
||||||
|
data = Allocators.References.Allocate<T>(initialCapacity);
|
||||||
|
}
|
||||||
|
|
||||||
private static void Add<T>(T item, ref T* data, ref ushort count, ref ushort capacity) where T : unmanaged
|
private static void Add<T>(T item, ref T* data, ref ushort count, ref ushort capacity) where T : unmanaged
|
||||||
{
|
{
|
||||||
if (count < capacity)
|
if (count < capacity)
|
||||||
@ -294,6 +302,40 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void Add<T>(T item, ref T* data, ref uint count, ref uint capacity) where T : unmanaged
|
||||||
|
{
|
||||||
|
if (count < capacity)
|
||||||
|
{
|
||||||
|
data[count++] = item;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Could not add item in the fast path, fallback onto the slow path.
|
||||||
|
ExpandAdd(item, ref data, ref count, ref capacity);
|
||||||
|
|
||||||
|
static void ExpandAdd(T item, ref T* data, ref uint count, ref uint capacity)
|
||||||
|
{
|
||||||
|
uint newCount = checked(count + 1);
|
||||||
|
uint newCapacity = (uint)Math.Min(capacity * 2, int.MaxValue);
|
||||||
|
|
||||||
|
if (newCapacity <= capacity)
|
||||||
|
{
|
||||||
|
throw new OverflowException();
|
||||||
|
}
|
||||||
|
|
||||||
|
var oldSpan = new Span<T>(data, (int)count);
|
||||||
|
|
||||||
|
capacity = newCapacity;
|
||||||
|
data = Allocators.References.Allocate<T>(capacity);
|
||||||
|
|
||||||
|
oldSpan.CopyTo(new Span<T>(data, (int)count));
|
||||||
|
|
||||||
|
data[count] = item;
|
||||||
|
count = newCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static void Remove<T>(in T item, ref T* data, ref ushort count) where T : unmanaged
|
private static void Remove<T>(in T item, ref T* data, ref ushort count) where T : unmanaged
|
||||||
{
|
{
|
||||||
var span = new Span<T>(data, count);
|
var span = new Span<T>(data, count);
|
||||||
@ -314,6 +356,26 @@ namespace ARMeilleure.IntermediateRepresentation
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void Remove<T>(in T item, ref T* data, ref uint count) where T : unmanaged
|
||||||
|
{
|
||||||
|
var span = new Span<T>(data, (int)count);
|
||||||
|
|
||||||
|
for (int i = 0; i < span.Length; i++)
|
||||||
|
{
|
||||||
|
if (EqualityComparer<T>.Default.Equals(span[i], item))
|
||||||
|
{
|
||||||
|
if (i + 1 < count)
|
||||||
|
{
|
||||||
|
span.Slice(i + 1).CopyTo(span.Slice(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
count--;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override int GetHashCode()
|
public override int GetHashCode()
|
||||||
{
|
{
|
||||||
if (Kind == OperandKind.LocalVariable)
|
if (Kind == OperandKind.LocalVariable)
|
||||||
|
@ -103,7 +103,7 @@ namespace ARMeilleure.Signal
|
|||||||
// Unix siginfo struct locations.
|
// Unix siginfo struct locations.
|
||||||
// NOTE: These are incredibly likely to be different between kernel version and architectures.
|
// NOTE: These are incredibly likely to be different between kernel version and architectures.
|
||||||
|
|
||||||
config.StructAddressOffset = 16; // si_addr
|
config.StructAddressOffset = OperatingSystem.IsMacOS() ? 24 : 16; // si_addr
|
||||||
config.StructWriteOffset = 8; // si_code
|
config.StructWriteOffset = 8; // si_code
|
||||||
|
|
||||||
_signalHandlerPtr = Marshal.GetFunctionPointerForDelegate(GenerateUnixSignalHandler(_handlerConfig));
|
_signalHandlerPtr = Marshal.GetFunctionPointerForDelegate(GenerateUnixSignalHandler(_handlerConfig));
|
||||||
@ -191,18 +191,35 @@ namespace ARMeilleure.Signal
|
|||||||
// Is the fault address within this tracked region?
|
// Is the fault address within this tracked region?
|
||||||
Operand inRange = context.BitwiseAnd(
|
Operand inRange = context.BitwiseAnd(
|
||||||
context.ICompare(faultAddress, rangeAddress, Comparison.GreaterOrEqualUI),
|
context.ICompare(faultAddress, rangeAddress, Comparison.GreaterOrEqualUI),
|
||||||
context.ICompare(faultAddress, rangeEndAddress, Comparison.Less)
|
context.ICompare(faultAddress, rangeEndAddress, Comparison.LessUI)
|
||||||
);
|
);
|
||||||
|
|
||||||
// Only call tracking if in range.
|
// Only call tracking if in range.
|
||||||
context.BranchIfFalse(nextLabel, inRange, BasicBlockFrequency.Cold);
|
context.BranchIfFalse(nextLabel, inRange, BasicBlockFrequency.Cold);
|
||||||
|
|
||||||
context.Copy(inRegionLocal, Const(1));
|
|
||||||
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.
|
// 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));
|
Operand trackingActionPtr = context.Load(OperandType.I64, Const((ulong)signalStructPtr + rangeBaseOffset + 20));
|
||||||
context.Call(trackingActionPtr, OperandType.I32, offset, Const(PageSize), isWrite, Const(0));
|
|
||||||
|
context.Copy(inRegionLocal, Const(0));
|
||||||
|
|
||||||
|
Operand skipActionLabel = Label();
|
||||||
|
|
||||||
|
// 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, Const(0));
|
||||||
|
context.Copy(inRegionLocal, result);
|
||||||
|
|
||||||
|
context.MarkLabel(skipActionLabel);
|
||||||
|
|
||||||
|
// If the tracking action returns false or does not exist, it might be an invalid access due to a partial overlap on Windows.
|
||||||
|
if (OperatingSystem.IsWindows())
|
||||||
|
{
|
||||||
|
context.BranchIfTrue(endLabel, inRegionLocal);
|
||||||
|
|
||||||
|
context.Copy(inRegionLocal, WindowsPartialUnmapHandler.EmitRetryFromAccessViolation(context));
|
||||||
|
}
|
||||||
|
|
||||||
context.Branch(endLabel);
|
context.Branch(endLabel);
|
||||||
|
|
||||||
|
84
ARMeilleure/Signal/TestMethods.cs
Normal file
84
ARMeilleure/Signal/TestMethods.cs
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
using ARMeilleure.IntermediateRepresentation;
|
||||||
|
using ARMeilleure.Translation;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
||||||
|
|
||||||
|
namespace ARMeilleure.Signal
|
||||||
|
{
|
||||||
|
public struct NativeWriteLoopState
|
||||||
|
{
|
||||||
|
public int Running;
|
||||||
|
public int Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TestMethods
|
||||||
|
{
|
||||||
|
public delegate bool DebugPartialUnmap();
|
||||||
|
public delegate int DebugThreadLocalMapGetOrReserve(int threadId, int initialState);
|
||||||
|
public delegate void DebugNativeWriteLoop(IntPtr nativeWriteLoopPtr, IntPtr writePtr);
|
||||||
|
|
||||||
|
public static DebugPartialUnmap GenerateDebugPartialUnmap()
|
||||||
|
{
|
||||||
|
EmitterContext context = new EmitterContext();
|
||||||
|
|
||||||
|
var result = WindowsPartialUnmapHandler.EmitRetryFromAccessViolation(context);
|
||||||
|
|
||||||
|
context.Return(result);
|
||||||
|
|
||||||
|
// Compile and return the function.
|
||||||
|
|
||||||
|
ControlFlowGraph cfg = context.GetControlFlowGraph();
|
||||||
|
|
||||||
|
OperandType[] argTypes = new OperandType[] { OperandType.I64 };
|
||||||
|
|
||||||
|
return Compiler.Compile(cfg, argTypes, OperandType.I32, CompilerOptions.HighCq).Map<DebugPartialUnmap>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DebugThreadLocalMapGetOrReserve GenerateDebugThreadLocalMapGetOrReserve(IntPtr structPtr)
|
||||||
|
{
|
||||||
|
EmitterContext context = new EmitterContext();
|
||||||
|
|
||||||
|
var result = WindowsPartialUnmapHandler.EmitThreadLocalMapIntGetOrReserve(context, structPtr, context.LoadArgument(OperandType.I32, 0), context.LoadArgument(OperandType.I32, 1));
|
||||||
|
|
||||||
|
context.Return(result);
|
||||||
|
|
||||||
|
// Compile and return the function.
|
||||||
|
|
||||||
|
ControlFlowGraph cfg = context.GetControlFlowGraph();
|
||||||
|
|
||||||
|
OperandType[] argTypes = new OperandType[] { OperandType.I64 };
|
||||||
|
|
||||||
|
return Compiler.Compile(cfg, argTypes, OperandType.I32, CompilerOptions.HighCq).Map<DebugThreadLocalMapGetOrReserve>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DebugNativeWriteLoop GenerateDebugNativeWriteLoop()
|
||||||
|
{
|
||||||
|
EmitterContext context = new EmitterContext();
|
||||||
|
|
||||||
|
// Loop a write to the target address until "running" is false.
|
||||||
|
|
||||||
|
Operand structPtr = context.Copy(context.LoadArgument(OperandType.I64, 0));
|
||||||
|
Operand writePtr = context.Copy(context.LoadArgument(OperandType.I64, 1));
|
||||||
|
|
||||||
|
Operand loopLabel = Label();
|
||||||
|
context.MarkLabel(loopLabel);
|
||||||
|
|
||||||
|
context.Store(writePtr, Const(12345));
|
||||||
|
|
||||||
|
Operand running = context.Load(OperandType.I32, structPtr);
|
||||||
|
|
||||||
|
context.BranchIfTrue(loopLabel, running);
|
||||||
|
|
||||||
|
context.Return();
|
||||||
|
|
||||||
|
// Compile and return the function.
|
||||||
|
|
||||||
|
ControlFlowGraph cfg = context.GetControlFlowGraph();
|
||||||
|
|
||||||
|
OperandType[] argTypes = new OperandType[] { OperandType.I64 };
|
||||||
|
|
||||||
|
return Compiler.Compile(cfg, argTypes, OperandType.None, CompilerOptions.HighCq).Map<DebugNativeWriteLoop>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -21,6 +21,7 @@ namespace ARMeilleure.Signal
|
|||||||
static class UnixSignalHandlerRegistration
|
static class UnixSignalHandlerRegistration
|
||||||
{
|
{
|
||||||
private const int SIGSEGV = 11;
|
private const int SIGSEGV = 11;
|
||||||
|
private const int SIGBUS = 10;
|
||||||
private const int SA_SIGINFO = 0x00000004;
|
private const int SA_SIGINFO = 0x00000004;
|
||||||
|
|
||||||
[DllImport("libc", SetLastError = true)]
|
[DllImport("libc", SetLastError = true)]
|
||||||
@ -43,7 +44,17 @@ namespace ARMeilleure.Signal
|
|||||||
|
|
||||||
if (result != 0)
|
if (result != 0)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException($"Could not register sigaction. Error: {result}");
|
throw new InvalidOperationException($"Could not register SIGSEGV sigaction. Error: {result}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (OperatingSystem.IsMacOS())
|
||||||
|
{
|
||||||
|
result = sigaction(SIGBUS, ref sig, out SigAction oldb);
|
||||||
|
|
||||||
|
if (result != 0)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Could not register SIGBUS sigaction. Error: {result}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return old;
|
return old;
|
||||||
@ -51,7 +62,7 @@ namespace ARMeilleure.Signal
|
|||||||
|
|
||||||
public static bool RestoreExceptionHandler(SigAction oldAction)
|
public static bool RestoreExceptionHandler(SigAction oldAction)
|
||||||
{
|
{
|
||||||
return sigaction(SIGSEGV, ref oldAction, out SigAction _) == 0;
|
return sigaction(SIGSEGV, ref oldAction, out SigAction _) == 0 && (!OperatingSystem.IsMacOS() || sigaction(SIGBUS, ref oldAction, out SigAction _) == 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
186
ARMeilleure/Signal/WindowsPartialUnmapHandler.cs
Normal file
186
ARMeilleure/Signal/WindowsPartialUnmapHandler.cs
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
using ARMeilleure.IntermediateRepresentation;
|
||||||
|
using ARMeilleure.Translation;
|
||||||
|
using Ryujinx.Common.Memory.PartialUnmaps;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
||||||
|
|
||||||
|
namespace ARMeilleure.Signal
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Methods to handle signals caused by partial unmaps. See the structs for C# implementations of the methods.
|
||||||
|
/// </summary>
|
||||||
|
internal static class WindowsPartialUnmapHandler
|
||||||
|
{
|
||||||
|
public static Operand EmitRetryFromAccessViolation(EmitterContext context)
|
||||||
|
{
|
||||||
|
IntPtr partialRemapStatePtr = PartialUnmapState.GlobalState;
|
||||||
|
IntPtr localCountsPtr = IntPtr.Add(partialRemapStatePtr, PartialUnmapState.LocalCountsOffset);
|
||||||
|
|
||||||
|
// Get the lock first.
|
||||||
|
EmitNativeReaderLockAcquire(context, IntPtr.Add(partialRemapStatePtr, PartialUnmapState.PartialUnmapLockOffset));
|
||||||
|
|
||||||
|
IntPtr getCurrentThreadId = WindowsSignalHandlerRegistration.GetCurrentThreadIdFunc();
|
||||||
|
Operand threadId = context.Call(Const((ulong)getCurrentThreadId), OperandType.I32);
|
||||||
|
Operand threadIndex = EmitThreadLocalMapIntGetOrReserve(context, localCountsPtr, threadId, Const(0));
|
||||||
|
|
||||||
|
Operand endLabel = Label();
|
||||||
|
Operand retry = context.AllocateLocal(OperandType.I32);
|
||||||
|
Operand threadIndexValidLabel = Label();
|
||||||
|
|
||||||
|
context.BranchIfFalse(threadIndexValidLabel, context.ICompareEqual(threadIndex, Const(-1)));
|
||||||
|
|
||||||
|
context.Copy(retry, Const(1)); // Always retry when thread local cannot be allocated.
|
||||||
|
|
||||||
|
context.Branch(endLabel);
|
||||||
|
|
||||||
|
context.MarkLabel(threadIndexValidLabel);
|
||||||
|
|
||||||
|
Operand threadLocalPartialUnmapsPtr = EmitThreadLocalMapIntGetValuePtr(context, localCountsPtr, threadIndex);
|
||||||
|
Operand threadLocalPartialUnmaps = context.Load(OperandType.I32, threadLocalPartialUnmapsPtr);
|
||||||
|
Operand partialUnmapsCount = context.Load(OperandType.I32, Const((ulong)IntPtr.Add(partialRemapStatePtr, PartialUnmapState.PartialUnmapsCountOffset)));
|
||||||
|
|
||||||
|
context.Copy(retry, context.ICompareNotEqual(threadLocalPartialUnmaps, partialUnmapsCount));
|
||||||
|
|
||||||
|
Operand noRetryLabel = Label();
|
||||||
|
|
||||||
|
context.BranchIfFalse(noRetryLabel, retry);
|
||||||
|
|
||||||
|
// if (retry) {
|
||||||
|
|
||||||
|
context.Store(threadLocalPartialUnmapsPtr, partialUnmapsCount);
|
||||||
|
|
||||||
|
context.Branch(endLabel);
|
||||||
|
|
||||||
|
context.MarkLabel(noRetryLabel);
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
context.MarkLabel(endLabel);
|
||||||
|
|
||||||
|
// Finally, release the lock and return the retry value.
|
||||||
|
EmitNativeReaderLockRelease(context, IntPtr.Add(partialRemapStatePtr, PartialUnmapState.PartialUnmapLockOffset));
|
||||||
|
|
||||||
|
return retry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Operand EmitThreadLocalMapIntGetOrReserve(EmitterContext context, IntPtr threadLocalMapPtr, Operand threadId, Operand initialState)
|
||||||
|
{
|
||||||
|
Operand idsPtr = Const((ulong)IntPtr.Add(threadLocalMapPtr, ThreadLocalMap<int>.ThreadIdsOffset));
|
||||||
|
|
||||||
|
Operand i = context.AllocateLocal(OperandType.I32);
|
||||||
|
|
||||||
|
context.Copy(i, Const(0));
|
||||||
|
|
||||||
|
// (Loop 1) Check all slots for a matching Thread ID (while also trying to allocate)
|
||||||
|
|
||||||
|
Operand endLabel = Label();
|
||||||
|
|
||||||
|
Operand loopLabel = Label();
|
||||||
|
context.MarkLabel(loopLabel);
|
||||||
|
|
||||||
|
Operand offset = context.Multiply(i, Const(sizeof(int)));
|
||||||
|
Operand idPtr = context.Add(idsPtr, context.SignExtend32(OperandType.I64, offset));
|
||||||
|
|
||||||
|
// Check that this slot has the thread ID.
|
||||||
|
Operand existingId = context.CompareAndSwap(idPtr, threadId, threadId);
|
||||||
|
|
||||||
|
// If it was already the thread ID, then we just need to return i.
|
||||||
|
context.BranchIfTrue(endLabel, context.ICompareEqual(existingId, threadId));
|
||||||
|
|
||||||
|
context.Copy(i, context.Add(i, Const(1)));
|
||||||
|
|
||||||
|
context.BranchIfTrue(loopLabel, context.ICompareLess(i, Const(ThreadLocalMap<int>.MapSize)));
|
||||||
|
|
||||||
|
// (Loop 2) Try take a slot that is 0 with our Thread ID.
|
||||||
|
|
||||||
|
context.Copy(i, Const(0)); // Reset i.
|
||||||
|
|
||||||
|
Operand loop2Label = Label();
|
||||||
|
context.MarkLabel(loop2Label);
|
||||||
|
|
||||||
|
Operand offset2 = context.Multiply(i, Const(sizeof(int)));
|
||||||
|
Operand idPtr2 = context.Add(idsPtr, context.SignExtend32(OperandType.I64, offset2));
|
||||||
|
|
||||||
|
// Try and swap in the thread id on top of 0.
|
||||||
|
Operand existingId2 = context.CompareAndSwap(idPtr2, Const(0), threadId);
|
||||||
|
|
||||||
|
Operand idNot0Label = Label();
|
||||||
|
|
||||||
|
// If it was 0, then we need to initialize the struct entry and return i.
|
||||||
|
context.BranchIfFalse(idNot0Label, context.ICompareEqual(existingId2, Const(0)));
|
||||||
|
|
||||||
|
Operand structsPtr = Const((ulong)IntPtr.Add(threadLocalMapPtr, ThreadLocalMap<int>.StructsOffset));
|
||||||
|
Operand structPtr = context.Add(structsPtr, context.SignExtend32(OperandType.I64, offset2));
|
||||||
|
context.Store(structPtr, initialState);
|
||||||
|
|
||||||
|
context.Branch(endLabel);
|
||||||
|
|
||||||
|
context.MarkLabel(idNot0Label);
|
||||||
|
|
||||||
|
context.Copy(i, context.Add(i, Const(1)));
|
||||||
|
|
||||||
|
context.BranchIfTrue(loop2Label, context.ICompareLess(i, Const(ThreadLocalMap<int>.MapSize)));
|
||||||
|
|
||||||
|
context.Copy(i, Const(-1)); // Could not place the thread in the list.
|
||||||
|
|
||||||
|
context.MarkLabel(endLabel);
|
||||||
|
|
||||||
|
return context.Copy(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Operand EmitThreadLocalMapIntGetValuePtr(EmitterContext context, IntPtr threadLocalMapPtr, Operand index)
|
||||||
|
{
|
||||||
|
Operand offset = context.Multiply(index, Const(sizeof(int)));
|
||||||
|
Operand structsPtr = Const((ulong)IntPtr.Add(threadLocalMapPtr, ThreadLocalMap<int>.StructsOffset));
|
||||||
|
|
||||||
|
return context.Add(structsPtr, context.SignExtend32(OperandType.I64, offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
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<int>.ThreadIdsOffset));
|
||||||
|
Operand idPtr = context.Add(idsPtr, context.SignExtend32(OperandType.I64, offset));
|
||||||
|
|
||||||
|
context.CompareAndSwap(idPtr, threadId, Const(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void EmitAtomicAddI32(EmitterContext context, Operand ptr, Operand additive)
|
||||||
|
{
|
||||||
|
Operand loop = Label();
|
||||||
|
context.MarkLabel(loop);
|
||||||
|
|
||||||
|
Operand initial = context.Load(OperandType.I32, ptr);
|
||||||
|
Operand newValue = context.Add(initial, additive);
|
||||||
|
|
||||||
|
Operand replaced = context.CompareAndSwap(ptr, initial, newValue);
|
||||||
|
|
||||||
|
context.BranchIfFalse(loop, context.ICompareEqual(initial, replaced));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void EmitNativeReaderLockAcquire(EmitterContext context, IntPtr nativeReaderLockPtr)
|
||||||
|
{
|
||||||
|
Operand writeLockPtr = Const((ulong)IntPtr.Add(nativeReaderLockPtr, NativeReaderWriterLock.WriteLockOffset));
|
||||||
|
|
||||||
|
// Spin until we can acquire the write lock.
|
||||||
|
Operand spinLabel = Label();
|
||||||
|
context.MarkLabel(spinLabel);
|
||||||
|
|
||||||
|
// Old value must be 0 to continue (we gained the write lock)
|
||||||
|
context.BranchIfTrue(spinLabel, context.CompareAndSwap(writeLockPtr, Const(0), Const(1)));
|
||||||
|
|
||||||
|
// Increment reader count.
|
||||||
|
EmitAtomicAddI32(context, Const((ulong)IntPtr.Add(nativeReaderLockPtr, NativeReaderWriterLock.ReaderCountOffset)), Const(1));
|
||||||
|
|
||||||
|
// Release write lock.
|
||||||
|
context.CompareAndSwap(writeLockPtr, Const(1), Const(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void EmitNativeReaderLockRelease(EmitterContext context, IntPtr nativeReaderLockPtr)
|
||||||
|
{
|
||||||
|
// Decrement reader count.
|
||||||
|
EmitAtomicAddI32(context, Const((ulong)IntPtr.Add(nativeReaderLockPtr, NativeReaderWriterLock.ReaderCountOffset)), Const(-1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,7 @@ using System.Runtime.InteropServices;
|
|||||||
|
|
||||||
namespace ARMeilleure.Signal
|
namespace ARMeilleure.Signal
|
||||||
{
|
{
|
||||||
class WindowsSignalHandlerRegistration
|
unsafe class WindowsSignalHandlerRegistration
|
||||||
{
|
{
|
||||||
[DllImport("kernel32.dll")]
|
[DllImport("kernel32.dll")]
|
||||||
private static extern IntPtr AddVectoredExceptionHandler(uint first, IntPtr handler);
|
private static extern IntPtr AddVectoredExceptionHandler(uint first, IntPtr handler);
|
||||||
@ -11,6 +11,14 @@ namespace ARMeilleure.Signal
|
|||||||
[DllImport("kernel32.dll")]
|
[DllImport("kernel32.dll")]
|
||||||
private static extern ulong RemoveVectoredExceptionHandler(IntPtr handle);
|
private static extern ulong RemoveVectoredExceptionHandler(IntPtr handle);
|
||||||
|
|
||||||
|
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Ansi)]
|
||||||
|
static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string lpFileName);
|
||||||
|
|
||||||
|
[DllImport("kernel32.dll", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
|
||||||
|
private static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
|
||||||
|
|
||||||
|
private static IntPtr _getCurrentThreadIdPtr;
|
||||||
|
|
||||||
public static IntPtr RegisterExceptionHandler(IntPtr action)
|
public static IntPtr RegisterExceptionHandler(IntPtr action)
|
||||||
{
|
{
|
||||||
return AddVectoredExceptionHandler(1, action);
|
return AddVectoredExceptionHandler(1, action);
|
||||||
@ -20,5 +28,17 @@ namespace ARMeilleure.Signal
|
|||||||
{
|
{
|
||||||
return RemoveVectoredExceptionHandler(handle) != 0;
|
return RemoveVectoredExceptionHandler(handle) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static IntPtr GetCurrentThreadIdFunc()
|
||||||
|
{
|
||||||
|
if (_getCurrentThreadIdPtr == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
IntPtr handle = LoadLibrary("kernel32.dll");
|
||||||
|
|
||||||
|
_getCurrentThreadIdPtr = GetProcAddress(handle, "GetCurrentThreadId");
|
||||||
|
}
|
||||||
|
|
||||||
|
return _getCurrentThreadIdPtr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
5
ARMeilleure/State/ExceptionCallback.cs
Normal file
5
ARMeilleure/State/ExceptionCallback.cs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
namespace ARMeilleure.State
|
||||||
|
{
|
||||||
|
public delegate void ExceptionCallbackNoArgs(ExecutionContext context);
|
||||||
|
public delegate void ExceptionCallback(ExecutionContext context, ulong address, int id);
|
||||||
|
}
|
@ -1,6 +1,5 @@
|
|||||||
using ARMeilleure.Memory;
|
using ARMeilleure.Memory;
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
|
||||||
|
|
||||||
namespace ARMeilleure.State
|
namespace ARMeilleure.State
|
||||||
{
|
{
|
||||||
@ -14,34 +13,28 @@ namespace ARMeilleure.State
|
|||||||
|
|
||||||
private bool _interrupted;
|
private bool _interrupted;
|
||||||
|
|
||||||
private static Stopwatch _tickCounter;
|
private readonly ICounter _counter;
|
||||||
|
|
||||||
private static double _hostTickFreq;
|
public ulong Pc => _nativeContext.GetPc();
|
||||||
|
|
||||||
public uint CtrEl0 => 0x8444c004;
|
public uint CtrEl0 => 0x8444c004;
|
||||||
public uint DczidEl0 => 0x00000004;
|
public uint DczidEl0 => 0x00000004;
|
||||||
|
|
||||||
public ulong CntfrqEl0 { get; set; }
|
public ulong CntfrqEl0 => _counter.Frequency;
|
||||||
public ulong CntpctEl0
|
public ulong CntpctEl0 => _counter.Counter;
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
double ticks = _tickCounter.ElapsedTicks * _hostTickFreq;
|
|
||||||
|
|
||||||
return (ulong)(ticks * CntfrqEl0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// CNTVCT_EL0 = CNTPCT_EL0 - CNTVOFF_EL2
|
// CNTVCT_EL0 = CNTPCT_EL0 - CNTVOFF_EL2
|
||||||
// Since EL2 isn't implemented, CNTVOFF_EL2 = 0
|
// Since EL2 isn't implemented, CNTVOFF_EL2 = 0
|
||||||
public ulong CntvctEl0 => CntpctEl0;
|
public ulong CntvctEl0 => CntpctEl0;
|
||||||
|
|
||||||
public static TimeSpan ElapsedTime => _tickCounter.Elapsed;
|
|
||||||
public static long ElapsedTicks => _tickCounter.ElapsedTicks;
|
|
||||||
public static double TickFrequency => _hostTickFreq;
|
|
||||||
|
|
||||||
public long TpidrEl0 { get; set; }
|
public long TpidrEl0 { get; set; }
|
||||||
public long Tpidr { get; set; }
|
public long TpidrroEl0 { get; set; }
|
||||||
|
|
||||||
|
public uint Pstate
|
||||||
|
{
|
||||||
|
get => _nativeContext.GetPstate();
|
||||||
|
set => _nativeContext.SetPstate(value);
|
||||||
|
}
|
||||||
|
|
||||||
public FPCR Fpcr { get; set; }
|
public FPCR Fpcr { get; set; }
|
||||||
public FPSR Fpsr { get; set; }
|
public FPSR Fpsr { get; set; }
|
||||||
@ -72,35 +65,38 @@ namespace ARMeilleure.State
|
|||||||
private set => _nativeContext.SetRunning(value);
|
private set => _nativeContext.SetRunning(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public event EventHandler<EventArgs> Interrupt;
|
private readonly ExceptionCallbackNoArgs _interruptCallback;
|
||||||
public event EventHandler<InstExceptionEventArgs> Break;
|
private readonly ExceptionCallback _breakCallback;
|
||||||
public event EventHandler<InstExceptionEventArgs> SupervisorCall;
|
private readonly ExceptionCallback _supervisorCallback;
|
||||||
public event EventHandler<InstUndefinedEventArgs> Undefined;
|
private readonly ExceptionCallback _undefinedCallback;
|
||||||
|
|
||||||
static ExecutionContext()
|
public ExecutionContext(
|
||||||
{
|
IJitMemoryAllocator allocator,
|
||||||
_hostTickFreq = 1.0 / Stopwatch.Frequency;
|
ICounter counter,
|
||||||
|
ExceptionCallbackNoArgs interruptCallback = null,
|
||||||
_tickCounter = new Stopwatch();
|
ExceptionCallback breakCallback = null,
|
||||||
_tickCounter.Start();
|
ExceptionCallback supervisorCallback = null,
|
||||||
}
|
ExceptionCallback undefinedCallback = null)
|
||||||
|
|
||||||
public ExecutionContext(IJitMemoryAllocator allocator)
|
|
||||||
{
|
{
|
||||||
_nativeContext = new NativeContext(allocator);
|
_nativeContext = new NativeContext(allocator);
|
||||||
|
_counter = counter;
|
||||||
|
_interruptCallback = interruptCallback;
|
||||||
|
_breakCallback = breakCallback;
|
||||||
|
_supervisorCallback = supervisorCallback;
|
||||||
|
_undefinedCallback = undefinedCallback;
|
||||||
|
|
||||||
Running = true;
|
Running = true;
|
||||||
|
|
||||||
_nativeContext.SetCounter(MinCountForCheck);
|
_nativeContext.SetCounter(MinCountForCheck);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ulong GetX(int index) => _nativeContext.GetX(index);
|
public ulong GetX(int index) => _nativeContext.GetX(index);
|
||||||
public void SetX(int index, ulong value) => _nativeContext.SetX(index, value);
|
public void SetX(int index, ulong value) => _nativeContext.SetX(index, value);
|
||||||
|
|
||||||
public V128 GetV(int index) => _nativeContext.GetV(index);
|
public V128 GetV(int index) => _nativeContext.GetV(index);
|
||||||
public void SetV(int index, V128 value) => _nativeContext.SetV(index, value);
|
public void SetV(int index, V128 value) => _nativeContext.SetV(index, value);
|
||||||
|
|
||||||
public bool GetPstateFlag(PState flag) => _nativeContext.GetPstateFlag(flag);
|
public bool GetPstateFlag(PState flag) => _nativeContext.GetPstateFlag(flag);
|
||||||
public void SetPstateFlag(PState flag, bool value) => _nativeContext.SetPstateFlag(flag, value);
|
public void SetPstateFlag(PState flag, bool value) => _nativeContext.SetPstateFlag(flag, value);
|
||||||
|
|
||||||
public bool GetFPstateFlag(FPState flag) => _nativeContext.GetFPStateFlag(flag);
|
public bool GetFPstateFlag(FPState flag) => _nativeContext.GetFPStateFlag(flag);
|
||||||
@ -112,7 +108,7 @@ namespace ARMeilleure.State
|
|||||||
{
|
{
|
||||||
_interrupted = false;
|
_interrupted = false;
|
||||||
|
|
||||||
Interrupt?.Invoke(this, EventArgs.Empty);
|
_interruptCallback?.Invoke(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
_nativeContext.SetCounter(MinCountForCheck);
|
_nativeContext.SetCounter(MinCountForCheck);
|
||||||
@ -125,17 +121,17 @@ namespace ARMeilleure.State
|
|||||||
|
|
||||||
internal void OnBreak(ulong address, int imm)
|
internal void OnBreak(ulong address, int imm)
|
||||||
{
|
{
|
||||||
Break?.Invoke(this, new InstExceptionEventArgs(address, imm));
|
_breakCallback?.Invoke(this, address, imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void OnSupervisorCall(ulong address, int imm)
|
internal void OnSupervisorCall(ulong address, int imm)
|
||||||
{
|
{
|
||||||
SupervisorCall?.Invoke(this, new InstExceptionEventArgs(address, imm));
|
_supervisorCallback?.Invoke(this, address, imm);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void OnUndefined(ulong address, int opCode)
|
internal void OnUndefined(ulong address, int opCode)
|
||||||
{
|
{
|
||||||
Undefined?.Invoke(this, new InstUndefinedEventArgs(address, opCode));
|
_undefinedCallback?.Invoke(this, address, opCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StopRunning()
|
public void StopRunning()
|
||||||
@ -145,16 +141,6 @@ namespace ARMeilleure.State
|
|||||||
_nativeContext.SetCounter(0);
|
_nativeContext.SetCounter(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SuspendCounter()
|
|
||||||
{
|
|
||||||
_tickCounter.Stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void ResumeCounter()
|
|
||||||
{
|
|
||||||
_tickCounter.Start();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
_nativeContext.Dispose();
|
_nativeContext.Dispose();
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user