mirror of
https://github.com/ptitSeb/box64.git
synced 2026-11-08 17:39:19 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
81c56d7155 | ||
|
|
524bf21011 | ||
|
|
6fbb827955 | ||
|
|
80610037cd | ||
|
|
bbd22d76be | ||
|
|
256632ea4c | ||
|
|
f5eff13acc | ||
|
|
7b66c024f0 | ||
|
|
af437fa354 | ||
|
|
2a559622c9 | ||
|
|
494428dbbe | ||
|
|
a40b6d49cb | ||
|
|
a5b3c0af5e | ||
|
|
276e67f329 | ||
|
|
56684a2f67 | ||
|
|
56b4de3b84 | ||
|
|
275c25a048 | ||
|
|
0a0228eae2 | ||
|
|
65b6f716d5 | ||
|
|
70ab16a6d6 | ||
|
|
74d4db051b | ||
|
|
41f61cf702 | ||
|
|
f0eab197be | ||
|
|
6250f03b09 | ||
|
|
535798a730 | ||
|
|
89e5c644d0 | ||
|
|
2ae7402fd7 | ||
|
|
18d95a4627 | ||
|
|
b6c9cc93fb | ||
|
|
4cc74f45eb | ||
|
|
9892089325 | ||
|
|
a029fca7bd | ||
|
|
3cfe54f8cf | ||
|
|
297dc34799 | ||
|
|
c0ec7eb2bf | ||
|
|
c33e39bd25 | ||
|
|
1dd9b23022 | ||
|
|
63592011fe | ||
|
|
73238883cb | ||
|
|
73aed7fd0e | ||
|
|
e8ed70905c | ||
|
|
f9aa5651cc | ||
|
|
b1c10d5ccd | ||
|
|
7bf2caa5c4 | ||
|
|
6ae0524da6 | ||
|
|
5768989e54 | ||
|
|
c4c9f1b8cd | ||
|
|
d547fe4d37 | ||
|
|
118f4cf3b4 | ||
|
|
5ac53d6be2 | ||
|
|
a02873b9ee | ||
|
|
ba9731838e | ||
|
|
7c064ef16c | ||
|
|
84756e1ada | ||
|
|
a37f7d1800 | ||
|
|
86dde8c1f7 | ||
|
|
e48881715a | ||
|
|
79e3d00e35 | ||
|
|
9b2bef153b | ||
|
|
4d7e9ccf51 | ||
|
|
8f5613055d | ||
|
|
501e8a77ec | ||
|
|
0e90b94272 | ||
|
|
7889934ffa | ||
|
|
3dfd5bf4b0 | ||
|
|
c605e4630e | ||
|
|
bad4d13c09 | ||
|
|
5bfb27d3fa | ||
|
|
0d355aaf01 | ||
|
|
220b1e6dad | ||
|
|
78833500c8 | ||
|
|
1a58da4315 | ||
|
|
0f4e298142 | ||
|
|
c5981dd11c | ||
|
|
24c15e148d | ||
|
|
ea48f2b823 | ||
|
|
85b07f7441 | ||
|
|
c4f5b7c062 | ||
|
|
04c1998f1c | ||
|
|
775c1c19ec | ||
|
|
f077b28459 | ||
|
|
c08fb5d53d | ||
|
|
365b6d57df | ||
|
|
ef117f726c | ||
|
|
52fe2485ae | ||
|
|
2c6816be8f | ||
|
|
965e2c93eb | ||
|
|
fe343190d8 | ||
|
|
e514f75c8e | ||
|
|
1dbb057dec | ||
|
|
5bd7b24be3 | ||
|
|
f216fda9c1 | ||
|
|
93fc3be3df | ||
|
|
d509261f81 | ||
|
|
7862e8a3d5 | ||
|
|
7acdd87198 | ||
|
|
4fb9c658a1 | ||
|
|
c6bb8b335a | ||
|
|
464fdc3ebe | ||
|
|
6b9ed18286 | ||
|
|
dca2b99c91 | ||
|
|
6f144aa429 | ||
|
|
e5c1e3a2a2 | ||
|
|
e7d2cf5538 | ||
|
|
427f1b8c55 | ||
|
|
f639357591 | ||
|
|
49b69ad122 | ||
|
|
1ef35d5d8b | ||
|
|
65b7909f6e | ||
|
|
c8c707e7cc | ||
|
|
6440aac9e1 | ||
|
|
4edba2e67a | ||
|
|
6b41f28e2b | ||
|
|
5e02758713 | ||
|
|
ff9b2a235b | ||
|
|
be2f566fbf | ||
|
|
08944bc7ca | ||
|
|
ade6843d3a | ||
|
|
2de6058c6a | ||
|
|
986e271280 | ||
|
|
578009cccf | ||
|
|
94c40d99f6 | ||
|
|
28d07f9bf0 | ||
|
|
994ce41adc | ||
|
|
d890527281 | ||
|
|
470b8664d2 | ||
|
|
b31e522eb2 | ||
|
|
cb3cfa991f | ||
|
|
4b6766c84b | ||
|
|
5e5c972cec | ||
|
|
e5556e90df | ||
|
|
1edd0eb47d | ||
|
|
f46987b6af | ||
|
|
2af7492cf8 | ||
|
|
1b2515cd49 | ||
|
|
197f962543 | ||
|
|
373d778f6a | ||
|
|
fcd1aacef0 | ||
|
|
56ae4a35e1 | ||
|
|
1141516226 | ||
|
|
b57cafd93d | ||
|
|
60ff412d60 | ||
|
|
87064c15ec | ||
|
|
67d6501f54 | ||
|
|
d0ce4ef913 | ||
|
|
e863acf0a8 | ||
|
|
3fe020572d | ||
|
|
234f6f2b14 | ||
|
|
bdb4aa5dc6 | ||
|
|
cf626c580d | ||
|
|
485447850c | ||
|
|
709a526217 | ||
|
|
1cddcad20a | ||
|
|
aa30e665ff | ||
|
|
9effd3f711 | ||
|
|
d71200de69 | ||
|
|
8579ef84bd | ||
|
|
747882cb4e | ||
|
|
e76570ad7b | ||
|
|
e964b45894 | ||
|
|
b8526c7920 | ||
|
|
2a525b4eb2 | ||
|
|
cb2c29c5f9 | ||
|
|
3b0977eee1 | ||
|
|
893ffe8205 | ||
|
|
82a91e717a | ||
|
|
031d3def2d | ||
|
|
7c32cb24a0 | ||
|
|
cea8f94358 | ||
|
|
d476217f4c | ||
|
|
34e789484a | ||
|
|
6a6af076dd | ||
|
|
5327489f39 | ||
|
|
392255594b | ||
|
|
8d94d21716 | ||
|
|
44448774a7 | ||
|
|
a280884f09 | ||
|
|
7435006b7c | ||
|
|
1c2e763ffb | ||
|
|
5f144d8ddd | ||
|
|
0a53d2223a | ||
|
|
fe2930cbe3 | ||
|
|
bf6c1533b3 | ||
|
|
167217c76b | ||
|
|
f615a10fe1 | ||
|
|
2d60c8c5b9 | ||
|
|
270ce3750e | ||
|
|
83e2427bfe | ||
|
|
3815c28bfe | ||
|
|
5144a2e286 | ||
|
|
febaf31b93 | ||
|
|
af057e309a | ||
|
|
db864b6aa6 | ||
|
|
3793e595f0 | ||
|
|
abe29cc0ba | ||
|
|
c4e50cdbb1 | ||
|
|
dce81673af | ||
|
|
df2e4f941f | ||
|
|
efd01c1126 | ||
|
|
197e5e440d | ||
|
|
eff93582a7 | ||
|
|
1535907f2d | ||
|
|
9eb1642ec8 | ||
|
|
c85072e4d3 | ||
|
|
e1b6976528 | ||
|
|
a9aff45bf2 | ||
|
|
c59b9f2686 | ||
|
|
98431d8cf5 | ||
|
|
a083025565 | ||
|
|
309dad99b4 | ||
|
|
c2c5d3b836 | ||
|
|
87baa884d2 | ||
|
|
442d6a262b | ||
|
|
47dbadb4d4 | ||
|
|
676efe4032 | ||
|
|
dd7b99ffd1 | ||
|
|
f82c5440b7 | ||
|
|
c9d5e8bfc3 | ||
|
|
7e5598d0db | ||
|
|
9d5b2f3cc5 | ||
|
|
1eba5b1af6 | ||
|
|
daeff6fc41 | ||
|
|
368f14b4ce | ||
|
|
f480ae4459 | ||
|
|
bfb2d14fee | ||
|
|
bef83b6c03 | ||
|
|
f4cd829c82 | ||
|
|
7b0ecf9f6c | ||
|
|
c769330d92 | ||
|
|
afe466b051 | ||
|
|
4bb4e45836 | ||
|
|
cbd1f487c7 | ||
|
|
926176c1b5 | ||
|
|
aac7345603 | ||
|
|
0dc9f8cb62 | ||
|
|
cb0b274c27 | ||
|
|
ebac583441 | ||
|
|
6221b01976 | ||
|
|
caac35cc1e | ||
|
|
f7302ecb1b | ||
|
|
4c30838448 | ||
|
|
ded60bbabd | ||
|
|
c2805b0f9b | ||
|
|
7e9775de94 | ||
|
|
ae0ac5a1d0 | ||
|
|
ea804a5261 | ||
|
|
a17811f4a6 | ||
|
|
d2c77ddb01 | ||
|
|
6c438a5e65 | ||
|
|
6da5698c02 | ||
|
|
ecbe739f52 | ||
|
|
27312d7a15 | ||
|
|
d19a3d987b | ||
|
|
d33706065d | ||
|
|
97a78f2d98 | ||
|
|
ec0e1077c9 | ||
|
|
127d72da17 | ||
|
|
f2baa6ed35 | ||
|
|
5fd843750f | ||
|
|
8180cb3218 | ||
|
|
68e16f5154 | ||
|
|
0fd5d67fe3 | ||
|
|
f628c37a61 | ||
|
|
0734efea39 | ||
|
|
f43a221ffc | ||
|
|
397399fd30 | ||
|
|
3e9f394228 | ||
|
|
32e2112ab0 | ||
|
|
f0866438fc | ||
|
|
ec2edd5b3a | ||
|
|
4a625db27a | ||
|
|
32cebc6137 | ||
|
|
b02b9174e0 | ||
|
|
5b3f675c0d | ||
|
|
a908ce881d | ||
|
|
49cc5eabcb | ||
|
|
bf429a1dcf | ||
|
|
e1c1303d28 | ||
|
|
4a8a373662 | ||
|
|
fff274b45f | ||
|
|
8e1e299395 | ||
|
|
b8d40a8d71 | ||
|
|
a3cad12d66 | ||
|
|
c4521b3772 | ||
|
|
729fbb24d5 | ||
|
|
6740ca196e | ||
|
|
7b755bb6a2 | ||
|
|
5f7da532c4 | ||
|
|
fc1b149fed | ||
|
|
ea16e05142 | ||
|
|
3e74454cf4 | ||
|
|
f3a748ae8f | ||
|
|
5d90fe95e4 | ||
|
|
8271d37539 | ||
|
|
206e3cd561 | ||
|
|
5d2a99307e | ||
|
|
a55cece387 | ||
|
|
ca24435b92 | ||
|
|
0e97b105fe | ||
|
|
2d164c89e2 | ||
|
|
48ae536d95 | ||
|
|
b2225e26b1 | ||
|
|
484dc1365e | ||
|
|
c9a41ee3ac | ||
|
|
7f6d18930c | ||
|
|
17ea04766e | ||
|
|
b1613be0f0 | ||
|
|
cdaffe0c1f | ||
|
|
7fb315c356 | ||
|
|
a960e98394 | ||
|
|
ef2f960d4b | ||
|
|
e829cad612 | ||
|
|
609ff66c2c | ||
|
|
1a4bfc2feb | ||
|
|
e5329d6864 | ||
|
|
37b1d9ea85 | ||
|
|
98f2460c46 | ||
|
|
7a4583699b | ||
|
|
26851574ad | ||
|
|
179cba7a28 | ||
|
|
0a59321106 | ||
|
|
ce08e8e27f | ||
|
|
6960cfa56f | ||
|
|
c558bdcb69 | ||
|
|
0674e546e1 | ||
|
|
2a10ddc75b | ||
|
|
8ed08b3bbc | ||
|
|
cf5241ceb3 | ||
|
|
78460724ea | ||
|
|
6ea020eb54 | ||
|
|
968594ee63 | ||
|
|
3ac62c64d8 | ||
|
|
5596b9ae3f | ||
|
|
64efac63c0 | ||
|
|
6da287f59f | ||
|
|
1c65cdc7cb | ||
|
|
efa6ee7275 | ||
|
|
1ac4cdeae9 | ||
|
|
4bb1bc9ea8 | ||
|
|
614d142205 | ||
|
|
aeec79ec00 | ||
|
|
b1971c8ef3 | ||
|
|
1ed7609fe9 | ||
|
|
04396f421e | ||
|
|
b4d43748e5 | ||
|
|
549b384c3c | ||
|
|
60ea78729d | ||
|
|
ab9b88091c | ||
|
|
a0fb28ac55 | ||
|
|
9d92aac4f5 | ||
|
|
5923a9089f | ||
|
|
e274abf13d | ||
|
|
e327799e62 | ||
|
|
d56464d01d | ||
|
|
accbbe83e2 | ||
|
|
44ff3375df | ||
|
|
dacc294340 | ||
|
|
569b7471f9 | ||
|
|
74710cbf6a | ||
|
|
54ea4859ec | ||
|
|
2278438462 | ||
|
|
a942cef1ee | ||
|
|
f6773b2489 | ||
|
|
614c8035ef | ||
|
|
b01a0ccbb4 | ||
|
|
c6eaae8760 | ||
|
|
4a447e7f94 | ||
|
|
c8c2b84287 | ||
|
|
2ce7bdf321 | ||
|
|
2302adcbb9 | ||
|
|
f6bb7310bb | ||
|
|
d57416f4fb | ||
|
|
e75234c83d | ||
|
|
42b98f77ce | ||
|
|
bb253f3708 | ||
|
|
0c87fbd42c | ||
|
|
bc210752ab | ||
|
|
c274475c47 | ||
|
|
48a1b11281 | ||
|
|
3698763bbe | ||
|
|
d67bc08d2d | ||
|
|
e2b9776860 | ||
|
|
208a84bebb | ||
|
|
6a6ad9748a | ||
|
|
70ee5f0c83 | ||
|
|
266bb4aa88 | ||
|
|
82016ae44f | ||
|
|
f470fdcc90 | ||
|
|
09e39704ae | ||
|
|
f14fa2f2ce | ||
|
|
7962aacc7f | ||
|
|
9195bc2d4a | ||
|
|
5e9972f2d3 | ||
|
|
acc0d451bb | ||
|
|
1f5ce7ec18 | ||
|
|
f8314ffb2b | ||
|
|
9b6ff79c9c | ||
|
|
4eabf07385 | ||
|
|
0d02532dab | ||
|
|
8ae0b6e181 | ||
|
|
f6d9caf0d1 | ||
|
|
c66630da49 | ||
|
|
0cc58732fb | ||
|
|
dcb47b7df8 | ||
|
|
d6c08a7511 | ||
|
|
f1e8841030 | ||
|
|
cfdc733e2f | ||
|
|
168fe67904 | ||
|
|
58f4cc352e | ||
|
|
b840606105 | ||
|
|
f88c864fce | ||
|
|
41a914fa5e | ||
|
|
1f710620fc | ||
|
|
eb110bf213 | ||
|
|
42c0f891e3 | ||
|
|
725316a538 | ||
|
|
cc9ed70837 | ||
|
|
c96c1ad5dd | ||
|
|
71220b7fef | ||
|
|
ae0c91dce0 | ||
|
|
ab6deeb319 | ||
|
|
c1785a93ab | ||
|
|
924903e8d2 | ||
|
|
d9925eb46a | ||
|
|
01e997a4da | ||
|
|
51db3f1f9a | ||
|
|
73dfc35c99 | ||
|
|
038835c81e | ||
|
|
decec260b2 | ||
|
|
ae6ec48623 | ||
|
|
9d93770a84 | ||
|
|
3b53d2dac7 | ||
|
|
a3d153caf0 | ||
|
|
3f7d726c17 | ||
|
|
0dedfd03a6 | ||
|
|
099b9c2aaf | ||
|
|
2d740c91d2 | ||
|
|
926a59803d | ||
|
|
db24d5ddb7 | ||
|
|
217c0fa4e9 | ||
|
|
abe3e1c4f8 | ||
|
|
ffbb0a400e | ||
|
|
0d10035ffd | ||
|
|
9cacc44125 | ||
|
|
3f757df028 | ||
|
|
e0ef328402 | ||
|
|
e0067667f7 | ||
|
|
44669935da | ||
|
|
e2f22310f4 | ||
|
|
347f90f975 | ||
|
|
cc6d5eb0d9 | ||
|
|
4029d52a75 | ||
|
|
d0dd1c4d4f | ||
|
|
5ebdab90ea | ||
|
|
d1f8458f58 | ||
|
|
12d6d14ae2 | ||
|
|
bfd0e1700b | ||
|
|
0ae6083730 | ||
|
|
64080cea81 | ||
|
|
ab5c42f0dc | ||
|
|
b19dc0db89 | ||
|
|
d886cf1d98 | ||
|
|
e427c6e9cd | ||
|
|
caba957426 | ||
|
|
873be3cf87 | ||
|
|
685afa2302 | ||
|
|
d3f0d1c30f | ||
|
|
7de8687a79 | ||
|
|
4fc5885d74 | ||
|
|
4539eccd40 |
No files matched your search
+151
-26
@@ -1,6 +1,9 @@
|
||||
### Auto build Box64 and release its binary with Github Action
|
||||
name: Build and Release Box64
|
||||
|
||||
permissions:
|
||||
actions: 'write'
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
release:
|
||||
@@ -22,12 +25,17 @@ on:
|
||||
- "CMakeLists.txt"
|
||||
- "**/*.yml"
|
||||
|
||||
defaults:
|
||||
run:
|
||||
# needed on container images which could default to sh
|
||||
shell: bash
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [X64, RISCV, RK3588, ARM64, ANDROID, TERMUX, LARCH64, ANDROID_GLIBC, WOW64]
|
||||
platform: [X64, RISCV, RK3588, ARM64, ANDROID, TERMUX, LARCH64, ANDROID_GLIBC, WOW64, ARM64-GCC-8]
|
||||
type: [Release, Trace, StaticBuild, Box32]
|
||||
os: [ubuntu-latest, ubuntu-22.04-arm]
|
||||
exclude:
|
||||
@@ -65,17 +73,103 @@ jobs:
|
||||
type: StaticBuild
|
||||
- platform: WOW64
|
||||
type: Box32
|
||||
- platform: ARM64-GCC-8
|
||||
os: ubuntu-latest
|
||||
- platform: ARM64-GCC-8
|
||||
type: Trace
|
||||
- platform: ARM64-GCC-8
|
||||
type: StaticBuild
|
||||
- platform: ANDROID
|
||||
type: Trace
|
||||
- platform: TERMUX
|
||||
type: Trace
|
||||
- platform: LARCH64
|
||||
type: Trace
|
||||
include:
|
||||
- platform: ARM64-GCC-8
|
||||
image: arm64v8/ubuntu:18.04
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
container:
|
||||
image: ${{ matrix.image || '' }}
|
||||
steps:
|
||||
- name: "Checkout Box64 Repository"
|
||||
if: ${{ matrix.platform != 'ARM64-GCC-8' }}
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: "Environment preparation"
|
||||
- name: "Checkout Box64 Repository (No NodeJS)"
|
||||
if: ${{ matrix.platform == 'ARM64-GCC-8' }}
|
||||
uses: taiki-e/checkout-action@v1
|
||||
|
||||
- name: Get all the unique changed directory names
|
||||
id: changed-files-dir-names
|
||||
if: ${{ matrix.platform != 'ARM64-GCC-8' }}
|
||||
uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c # v46
|
||||
with:
|
||||
dir_names: "true"
|
||||
|
||||
- name: Early exit other jobs if this is a ARM64-only change
|
||||
id: early-exit-arm64
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
if: steps.changed-files-dir-names.outputs.all_modified_files == 'src/dynarec/arm64'
|
||||
continue-on-error: true
|
||||
run: |
|
||||
sudo apt-get update
|
||||
if [[ ${{ matrix.platform }} != 'RISCV' && ${{ matrix.platform }} != 'LARCH64' && ${{ matrix.platform }} != 'X64' ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Early exit other jobs if this is a LA64-only change
|
||||
id: early-exit-la64
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
if: steps.changed-files-dir-names.outputs.all_modified_files == 'src/dynarec/la64'
|
||||
continue-on-error: true
|
||||
run: |
|
||||
if [[ ${{ matrix.platform }} == 'LARCH64' ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Early exit other jobs if this is a RV64-only change
|
||||
id: early-exit-rv64
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
if: steps.changed-files-dir-names.outputs.all_modified_files == 'src/dynarec/rv64'
|
||||
continue-on-error: true
|
||||
run: |
|
||||
if [[ ${{ matrix.platform }} == 'RISCV' ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Do not early exit otherwise
|
||||
id: early-exit-never
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
DIRS: ${{ steps.changed-files-dir-names.outputs.all_modified_files }}
|
||||
if: env.DIRS != 'src/dynarec/arm64' && env.DIRS != 'src/dynarec/la64' && env.DIRS != 'src/dynarec/rv64'
|
||||
continue-on-error: true
|
||||
run: exit 1
|
||||
|
||||
- name: Merge early exit conditions
|
||||
id: early-exit
|
||||
if: steps.early-exit-arm64.outcome == 'failure' || steps.early-exit-la64.outcome == 'failure' || steps.early-exit-rv64.outcome == 'failure' || steps.early-exit-never.outcome == 'failure'
|
||||
continue-on-error: true
|
||||
run: exit 1
|
||||
|
||||
# Use `steps.early-exit.outcome == 'failure'` to check whether the current step should be processed.
|
||||
|
||||
- name: "Environment preparation"
|
||||
if: steps.early-exit.outcome == 'failure'
|
||||
run: |
|
||||
if [[ ${{ matrix.platform }} == 'ARM64-GCC-8' ]]; then
|
||||
apt-get update
|
||||
apt install -y sudo
|
||||
else
|
||||
sudo apt-get update
|
||||
zydis_package=libzydis-dev
|
||||
fi
|
||||
if [[ ${{ matrix.platform }} != 'X64' && ${{ matrix.platform }} != 'RISCV' && ${{ matrix.platform }} != 'LARCH64' ]]; then
|
||||
sudo apt-get -y install git cmake make python3 patchelf
|
||||
sudo apt-get -y install git cmake make python3 patchelf $zydis_package
|
||||
if [[ ${{ matrix.platform }} == 'ANDROID' || ${{ matrix.platform }} == 'TERMUX' ]]; then
|
||||
sudo apt-get -y install p7zip
|
||||
wget -q https://dl.google.com/android/repository/android-ndk-r26b-linux.zip
|
||||
@@ -98,14 +192,26 @@ jobs:
|
||||
wget -q https://github.com/mstorsjo/llvm-mingw/releases/download/${LLVM_MINGW_VERSION}/llvm-mingw-${LLVM_MINGW_VERSION}-ucrt-ubuntu-22.04-aarch64.tar.xz
|
||||
tar -xf llvm-mingw-${LLVM_MINGW_VERSION}-ucrt-ubuntu-22.04-aarch64.tar.xz
|
||||
echo "MINGW_COMPILER_PATH=$PWD/llvm-mingw-${LLVM_MINGW_VERSION}-ucrt-ubuntu-22.04-aarch64/bin" >> $GITHUB_ENV
|
||||
elif [[ ${{ matrix.platform }} == 'ARM64-GCC-8' ]]; then
|
||||
# some of these dependencies may be unnecessary to explicitly install depending on the image
|
||||
sudo apt-get -y install git software-properties-common lsb-release \
|
||||
wget curl build-essential autoconf automake \
|
||||
pkg-config ca-certificates \
|
||||
python3 make gettext zstd \
|
||||
gcc-8 g++-8
|
||||
sudo add-apt-repository ppa:theofficialgman/cmake-bionic -y
|
||||
sudo apt update
|
||||
sudo apt install -y cmake
|
||||
echo "BOX64_PLATFORM_MARCRO=-DARM64=1" >> $GITHUB_ENV
|
||||
echo "BOX64_COMPILER=aarch64-linux-gnu-gcc-8" >> $GITHUB_ENV
|
||||
else
|
||||
sudo apt-get -y install git gcc-aarch64-linux-gnu
|
||||
echo "BOX64_PLATFORM_MARCRO=-D${{ matrix.platform }}=1" >> $GITHUB_ENV
|
||||
echo "BOX64_COMPILER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
|
||||
fi
|
||||
if [[ ${{ matrix.platform }} == 'TERMUX' ]]; then
|
||||
wget https://packages.termux.dev/apt/termux-main/pool/main/liba/libandroid-sysv-semaphore/libandroid-sysv-semaphore_0.1_aarch64.deb
|
||||
7z x libandroid-sysv-semaphore_0.1_aarch64.deb
|
||||
wget https://packages.termux.dev/apt/termux-main/pool/main/liba/libandroid-sysv-semaphore/libandroid-sysv-semaphore_0.1-1_aarch64.deb
|
||||
7z x libandroid-sysv-semaphore_0.1-1_aarch64.deb
|
||||
tar -xf data.tar.xz
|
||||
sudo cp -rf data /
|
||||
sudo chmod 755 -R /data
|
||||
@@ -120,14 +226,14 @@ jobs:
|
||||
if [[ ${{ matrix.platform }} == 'X64' ]]; then
|
||||
echo "BOX64_PLATFORM_MARCRO=-DLD80BITS=1 -DNOALIGN=1" >> $GITHUB_ENV
|
||||
echo "BOX64_COMPILER=gcc" >> $GITHUB_ENV
|
||||
sudo apt-get -y install git cmake make python3
|
||||
sudo apt-get -y install git cmake make python3 libzydis-dev
|
||||
elif [[ ${{ matrix.platform }} == 'RISCV' ]]; then
|
||||
echo BOX64_PLATFORM_MARCRO="-DRV64=ON" >> $GITHUB_ENV
|
||||
echo "BOX64_COMPILER=riscv64-linux-gnu-gcc" >> $GITHUB_ENV
|
||||
sudo apt-get -y install git gcc-riscv64-linux-gnu cmake make python3 ninja-build libglib2.0-dev
|
||||
echo "BOX64_COMPILER=riscv64-linux-gnu-gcc-14" >> $GITHUB_ENV
|
||||
sudo apt-get -y install git gcc-14-riscv64-linux-gnu cmake make python3 ninja-build libglib2.0-dev libzydis-dev
|
||||
elif [[ ${{ matrix.platform }} == 'LARCH64' ]]; then
|
||||
sudo mkdir /usr/local/larch
|
||||
wget -O- -q https://github.com/loongson/build-tools/releases/download/2023.08.08/CLFS-loongarch64-8.1-x86_64-cross-tools-gcc-glibc.tar.xz | sudo tar -C /usr/local/larch --strip-components=1 --xz -xf -
|
||||
wget -O- -q https://github.com/loongson/build-tools/releases/download/2025.02.21/x86_64-cross-tools-loongarch64-binutils_2.44-gcc_14.2.0-glibc_2.41.tar.xz | sudo tar -C /usr/local/larch --strip-components=1 --xz -xf -
|
||||
sudo ln -sf /usr/local/larch/target /usr/loongarch64-linux-gnu
|
||||
sudo cp -r /usr/local/larch/loongarch64-unknown-linux-gnu/lib/* /usr/loongarch64-linux-gnu/lib64/
|
||||
for i in objdump objcopy strip; do
|
||||
@@ -139,11 +245,11 @@ jobs:
|
||||
|
||||
echo BOX64_PLATFORM_MARCRO="-DLARCH64=ON" >> $GITHUB_ENV
|
||||
echo "BOX64_COMPILER=loongarch64-linux-gnu-gcc" >> $GITHUB_ENV
|
||||
sudo apt-get -y install git cmake make python3
|
||||
sudo apt-get -y install git cmake make python3 libzydis-dev
|
||||
else
|
||||
echo BOX64_PLATFORM_MARCRO="-DARM_DYNAREC=ON" >> $GITHUB_ENV
|
||||
echo "BOX64_COMPILER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
|
||||
sudo apt-get -y install git gcc-aarch64-linux-gnu cmake make python3
|
||||
sudo apt-get -y install git gcc-aarch64-linux-gnu cmake make python3 libzydis-dev
|
||||
fi
|
||||
fi
|
||||
if [[ ${{ matrix.type }} == 'Release' ]]; then
|
||||
@@ -167,15 +273,20 @@ jobs:
|
||||
echo BOX64_STATICBUILD=0 >> $GITHUB_ENV
|
||||
echo BOX64_BOX32=0 >> $GITHUB_ENV
|
||||
fi
|
||||
if [[ ${{ matrix.os }} == 'ubuntu-22.04-arm' ]]; then
|
||||
echo "BOX64_ZYDIS3=1" >> $GITHUB_ENV
|
||||
else
|
||||
echo "BOX64_ZYDIS3=0" >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
- name: "Get XuanTie QEMU Cache Key"
|
||||
if: matrix.platform == 'RISCV'
|
||||
if: matrix.platform == 'RISCV' && steps.early-exit.outcome == 'failure'
|
||||
id: get-xuantie-qemu-cache-key
|
||||
run: |
|
||||
echo "key=f2dfdd13014d51f957c7172acc2e791cb42dc400" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: "Cache XuanTie QEMU"
|
||||
if: matrix.platform == 'RISCV'
|
||||
if: matrix.platform == 'RISCV' && steps.early-exit.outcome == 'failure'
|
||||
id: cache-xuantie-qemu
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
@@ -183,7 +294,7 @@ jobs:
|
||||
key: ${{ runner.os }}-${{ steps.get-xuantie-qemu-cache-key.outputs.key }}-xuantie-qemu
|
||||
|
||||
- name: "Checkout XuanTie QEMU"
|
||||
if: matrix.platform == 'RISCV' && steps.cache-xuantie-qemu.outputs.cache-hit != 'true'
|
||||
if: matrix.platform == 'RISCV' && steps.cache-xuantie-qemu.outputs.cache-hit != 'true' && steps.early-exit.outcome == 'failure'
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: revyos/qemu
|
||||
@@ -191,7 +302,7 @@ jobs:
|
||||
ref: f2dfdd13014d51f957c7172acc2e791cb42dc400
|
||||
|
||||
- name: "Build XuanTie QEMU for XTheadVector"
|
||||
if: matrix.platform == 'RISCV' && steps.cache-xuantie-qemu.outputs.cache-hit != 'true'
|
||||
if: matrix.platform == 'RISCV' && steps.cache-xuantie-qemu.outputs.cache-hit != 'true' && steps.early-exit.outcome == 'failure'
|
||||
run: |
|
||||
cd xuantie_qemu
|
||||
./configure --prefix=$GITHUB_WORKSPACE/xuantie_qemu_install --target-list=riscv64-linux-user --disable-system
|
||||
@@ -199,6 +310,7 @@ jobs:
|
||||
make install
|
||||
|
||||
- name: "Display Build info"
|
||||
if: steps.early-exit.outcome == 'failure'
|
||||
run: |
|
||||
echo "CMake Platform Macro: ${{ env.BOX64_PLATFORM_MARCRO }}"
|
||||
echo "CMake C Compiler: ${{ env.BOX64_COMPILER }}"
|
||||
@@ -208,6 +320,7 @@ jobs:
|
||||
echo "Box32 Enabled: ${{ env.BOX64_BOX32 }}"
|
||||
|
||||
- name: "Build Box64"
|
||||
if: steps.early-exit.outcome == 'failure'
|
||||
run: |
|
||||
export PATH=$PATH:${{ env.MINGW_COMPILER_PATH }}
|
||||
mkdir build
|
||||
@@ -217,6 +330,7 @@ jobs:
|
||||
${{ env.BOX64_PLATFORM_MARCRO }}\
|
||||
-DCMAKE_BUILD_TYPE=${{ env.BOX64_BUILD_TYPE }}\
|
||||
-DHAVE_TRACE=${{ env.BOX64_HAVE_TRACE }}\
|
||||
-DZYDIS3=${{ env.BOX64_ZYDIS3 }}\
|
||||
-DSTATICBUILD=${{ env.BOX64_STATICBUILD }}\
|
||||
-DBOX32=${{ env.BOX64_BOX32 }}\
|
||||
-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON\
|
||||
@@ -224,19 +338,23 @@ jobs:
|
||||
make -j$(nproc) VERBOSE=1
|
||||
|
||||
- name: "Test Box64"
|
||||
if: steps.early-exit.outcome == 'failure'
|
||||
run: |
|
||||
if [[ ${{ matrix.platform }} != 'X64' ]]; then
|
||||
mkdir qemu9
|
||||
wget -O- -q https://archive.archlinux.org/packages/q/qemu-user-static/qemu-user-static-9.0.2-1-x86_64.pkg.tar.zst | tar -I zstd -C qemu9 -xf -
|
||||
sudo cp qemu9/usr/bin/* /usr/bin/
|
||||
mkdir qemu10
|
||||
wget -O- -q https://archive.archlinux.org/packages/q/qemu-user-static/qemu-user-static-10.0.0-7-x86_64.pkg.tar.zst | tar -I zstd -C qemu10 -xf -
|
||||
sudo cp qemu10/usr/bin/* /usr/bin/
|
||||
fi
|
||||
|
||||
cd build
|
||||
export CTEST_OPTIONS="-j$(nproc) --timeout 120 --output-on-failure --repeat until-pass:20"
|
||||
export CTEST_OPTIONS="-j$(nproc) --timeout 300 --output-on-failure --repeat until-pass:20"
|
||||
if [[ ${{ matrix.platform }} == 'RISCV' ]]; then
|
||||
export INTERPRETER=qemu-riscv64-static
|
||||
export QEMU_LD_PREFIX=/usr/riscv64-linux-gnu/
|
||||
|
||||
if [[ ${{ env.BOX64_BOX32 }} == '1' ]]; then
|
||||
export BOX32_PERSONA32BITS=1 # hack to disable personality setting
|
||||
fi
|
||||
ctest $CTEST_OPTIONS
|
||||
QEMU_CPU=rv64,v=false BOX64_DYNAREC=0 ctest $CTEST_OPTIONS
|
||||
QEMU_CPU=rv64,v=false,zba=true,zbb=true,zbc=true,zbs=true ctest $CTEST_OPTIONS
|
||||
@@ -257,9 +375,14 @@ jobs:
|
||||
export INTERPRETER=qemu-loongarch64-static
|
||||
export QEMU_LD_PREFIX=/usr/loongarch64-linux-gnu/
|
||||
|
||||
if [[ ${{ env.BOX64_BOX32 }} == '1' ]]; then
|
||||
export BOX32_PERSONA32BITS=1 # hack to disable personality setting
|
||||
fi
|
||||
ctest $CTEST_OPTIONS -E nocosim
|
||||
BOX64_DYNAREC_LA64NOEXT=1 ctest $CTEST_OPTIONS -E nocosim
|
||||
BOX64_DYNAREC=0 ctest $CTEST_OPTIONS -E nocosim
|
||||
|
||||
BOX64_DYNAREC_TEST=1 ctest $CTEST_OPTIONS -E nocosim
|
||||
BOX64_DYNAREC_TEST=1 BOX64_DYNAREC_LA64NOEXT=1 ctest $CTEST_OPTIONS -E nocosim
|
||||
elif [[ ${{ matrix.platform }} == 'ANDROID' ]]; then
|
||||
export INTERPRETER=qemu-aarch64-static
|
||||
@@ -282,13 +405,15 @@ jobs:
|
||||
|
||||
- name: "Get short Git commit"
|
||||
id: git-info
|
||||
if: steps.early-exit.outcome == 'failure'
|
||||
run: echo "SHORT_COMMIT=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
|
||||
|
||||
- name: "Get Box64 Version"
|
||||
if: steps.early-exit.outcome == 'failure'
|
||||
run: echo "BOX64_VERSION=$(cat src/box64version.h | grep BOX64_MAJOR | cut -d " " -f 3).$(cat src/box64version.h | grep BOX64_MINOR | cut -d " " -f 3).$(cat src/box64version.h | grep BOX64_REVISION | cut -d " " -f 3)" >> $GITHUB_ENV
|
||||
|
||||
- name: "Packaging WCP file for Winlator"
|
||||
if: matrix.platform == 'ANDROID_GLIBC' && matrix.type != 'StaticBuild'
|
||||
if: matrix.platform == 'ANDROID_GLIBC' && matrix.type != 'StaticBuild' && steps.early-exit.outcome == 'failure'
|
||||
run: |
|
||||
cd build
|
||||
cat <<EOF > profile.json
|
||||
@@ -309,7 +434,7 @@ jobs:
|
||||
tar --zstd -cf box64-latest.wcp box64 profile.json
|
||||
|
||||
- name: "Package Rat File for MiceWine"
|
||||
if: matrix.platform == 'ANDROID' && matrix.type != 'StaticBuild'
|
||||
if: matrix.platform == 'ANDROID' && matrix.type != 'StaticBuild' && steps.early-exit.outcome == 'failure'
|
||||
run: |
|
||||
cd build
|
||||
|
||||
@@ -326,22 +451,22 @@ jobs:
|
||||
7z -tzip -mx=5 a box64-latest.rat files pkg-header
|
||||
|
||||
- name: "Upload WCP file"
|
||||
if: matrix.platform == 'ANDROID_GLIBC' && matrix.type != 'StaticBuild'
|
||||
if: matrix.platform == 'ANDROID_GLIBC' && matrix.type == 'Release' && steps.early-exit.outcome == 'failure'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: box64-latest-${{ matrix.type }}-wcp
|
||||
path: build/box64-latest.wcp
|
||||
|
||||
- name: "Upload Rat File"
|
||||
if: matrix.platform == 'ANDROID' && matrix.type != 'StaticBuild'
|
||||
if: matrix.platform == 'ANDROID' && matrix.type == 'Release' && steps.early-exit.outcome == 'failure'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: box64-MiceWine-${{ matrix.type }}
|
||||
path: build/box64-latest.rat
|
||||
|
||||
- name: "Upload WowBox64 file"
|
||||
if: matrix.platform == 'WOW64' && matrix.type == 'Release'
|
||||
if: matrix.platform == 'WOW64' && matrix.type == 'Release' && steps.early-exit.outcome == 'failure'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: wowbox64-${{ matrix.type }}
|
||||
path: build/wowbox64-prefix/src/wowbox64-build/wowbox64.dll
|
||||
path: build/wowbox64-prefix/src/wowbox64-build/wowbox64.dll
|
||||
-24
@@ -1,24 +0,0 @@
|
||||
language: c
|
||||
arch:
|
||||
- amd64
|
||||
- arm64-graviton2
|
||||
os: linux
|
||||
dist: focal
|
||||
|
||||
compiler:
|
||||
- gcc
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- python3
|
||||
|
||||
#Build steps
|
||||
before_script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- if [ "$TRAVIS_CPU_ARCH" = "arm64" ]; then cmake .. -DRK3399=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo ; else cmake .. -DLD80BITS=1 -DNOALIGN=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo ; fi
|
||||
|
||||
script:
|
||||
- make
|
||||
- ctest --output-on-failure
|
||||
+48
-14
@@ -32,7 +32,8 @@ option(ANDROID "Set to ON if targeting an Android device" ${ANDROID})
|
||||
option(TERMUX "Set to ON if targeting an Android device with Termux" ${TERMUX})
|
||||
option(WINLATOR_GLIBC "Set to ON if targeting an Android device with Winlator Glibc" ${WINLATOR_GLIBC})
|
||||
option(USE_CCACHE "Set to ON to use ccache if present in the system" ${USE_CCACHE})
|
||||
option(HAVE_TRACE "Set to ON to have Trace ability (needs ZydisInfo library)" ${HAVE_TRACE})
|
||||
option(HAVE_TRACE "Set to ON to have Trace ability (needs libzydis-dev)" ${HAVE_TRACE})
|
||||
option(ZYDIS3 "Set to ON if you have trace and an old libzydis v3.x" ${ZYDIS3})
|
||||
option(SAVE_MEM "Set to ON to build dynarec with some slower memory saving optimizations" ${SAVE_MEM})
|
||||
option(NOLOADADDR "Set to ON to avoid fixing the load address of Box64" OFF)
|
||||
option(NOGIT "Set to ON if not building from a git clone repo (like when building from a zip download from github)" ${NOGIT})
|
||||
@@ -50,6 +51,15 @@ if(TERMUX)
|
||||
set(TERMUX_PATH "/data/data/com.termux/files")
|
||||
set(ANDROID ON CACHE BOOL "")
|
||||
endif()
|
||||
|
||||
# Hack: limit the optimization level to -O1 for some platforms
|
||||
if(TERMUX OR ANDROID)
|
||||
set(CMAKE_C_FLAGS_RELEASE "-O1")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-O1")
|
||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O1 -g")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O1 -g")
|
||||
endif()
|
||||
|
||||
if(LARCH64)
|
||||
set(LD80BITS OFF CACHE BOOL "")
|
||||
set(NOALIGN OFF CACHE BOOL "")
|
||||
@@ -294,6 +304,10 @@ if(HAVE_TRACE)
|
||||
add_definitions(-DHAVE_TRACE)
|
||||
endif()
|
||||
|
||||
if(ZYDIS3)
|
||||
add_definitions(-DZYDIS3)
|
||||
endif()
|
||||
|
||||
if(ARM_DYNAREC)
|
||||
add_definitions(-DDYNAREC)
|
||||
add_definitions(-DARM64)
|
||||
@@ -350,6 +364,8 @@ set_source_files_properties(
|
||||
set(OS_LINUX_SRC
|
||||
"${BOX64_ROOT}/src/os/backtrace.c"
|
||||
"${BOX64_ROOT}/src/os/emit_signals_linux.c"
|
||||
"${BOX64_ROOT}/src/os/hostext_common.c"
|
||||
"${BOX64_ROOT}/src/os/hostext_linux.c"
|
||||
"${BOX64_ROOT}/src/os/freq_linux.c"
|
||||
"${BOX64_ROOT}/src/os/os_linux.c"
|
||||
"${BOX64_ROOT}/src/os/perfmap.c"
|
||||
@@ -455,23 +471,13 @@ endif()
|
||||
set(INTERPRETER
|
||||
"${BOX64_ROOT}/src/emu/x64run.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run0f.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run64.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run66.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run660f.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run66f20f.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run66f30f.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run6664.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run66d9.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run66dd.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run66f0.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run67.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run6764.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run67avx.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run67_32.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run6764_32.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run670f.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run6766.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run67660f.c"
|
||||
"${BOX64_ROOT}/src/emu/x64rund8.c"
|
||||
"${BOX64_ROOT}/src/emu/x64rund9.c"
|
||||
"${BOX64_ROOT}/src/emu/x64runda.c"
|
||||
@@ -521,6 +527,7 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedayatanaappindicator3.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedbz2.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedcap.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedcuda.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedcairo.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedcairogobject.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedcrashhandler.c"
|
||||
@@ -581,6 +588,7 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibavcodec58.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibavformat58.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibavutil56.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibblas.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibbsd.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibc.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibcmusl.c"
|
||||
@@ -600,6 +608,7 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibharfbuzz.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibibus.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibice.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedliblapack.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibm.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibncurses.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibncurses6.c"
|
||||
@@ -911,6 +920,7 @@ if(DYNAREC)
|
||||
"${BOX64_ROOT}/src/dynarec/dynablock.c"
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec_native.c"
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec_native_functions.c"
|
||||
"${BOX64_ROOT}/src/dynarec/dynacache_reloc.c"
|
||||
"${BOX64_ROOT}/src/emu/x64test.c"
|
||||
)
|
||||
endif()
|
||||
@@ -924,6 +934,8 @@ if(ARM_DYNAREC)
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/arm64_immenc.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/arm64_printer.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_jmpnext.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_consts.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/updateflags_arm64.c"
|
||||
)
|
||||
set(DYNAREC_ASM
|
||||
${DYNAREC_ASM}
|
||||
@@ -947,6 +959,7 @@ if(ARM_DYNAREC)
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_67.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_67_32.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_67_avx.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_6764.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_6764_32.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_d8.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_d9.c"
|
||||
@@ -975,6 +988,8 @@ if(ARM_DYNAREC)
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_avx_f2_0f38.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_avx_f2_0f3a.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_avx_f3_0f38.c"
|
||||
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/updateflags_arm64_pass.c"
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -986,7 +1001,7 @@ if(RV64_DYNAREC)
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_arch.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/rv64_printer.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_jmpnext.c"
|
||||
"${BOX64_ROOT}/src/rv64detect.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_consts.c"
|
||||
)
|
||||
set(DYNAREC_ASM
|
||||
${DYNAREC_ASM}
|
||||
@@ -1036,6 +1051,11 @@ if(RV64_DYNAREC)
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_f30f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_f30f_vector.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx_0f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx_66_0f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx_66_0f38.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx_66_0f3a.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx_f2_0f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx_f3_0f.c"
|
||||
)
|
||||
endif()
|
||||
@@ -1047,6 +1067,7 @@ if(LARCH64_DYNAREC)
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_functions.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/la64_printer.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_jmpnext.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_consts.c"
|
||||
)
|
||||
set(DYNAREC_ASM
|
||||
${DYNAREC_ASM}
|
||||
@@ -1075,6 +1096,17 @@ if(LARCH64_DYNAREC)
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_f0.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_f20f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_f30f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_avx.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_avx_0f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_avx_0f38.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_avx_66_0f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_avx_66_0f38.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_avx_66_0f3a.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_avx_f2_0f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_avx_f2_0f38.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_avx_f2_0f3a.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_avx_f3_0f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_avx_f3_0f38.c"
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -1185,6 +1217,7 @@ else()
|
||||
endif()
|
||||
else()
|
||||
set_property(TARGET ${BOX64} APPEND_STRING PROPERTY LINK_FLAGS "-Wl,--no-as-needed -lc -lm -ldl -lrt -lpthread -lresolv -lutil -Wl,--as-needed -pthread ")
|
||||
target_link_libraries(${BOX64} c m dl pthread resolv util c)
|
||||
endif()
|
||||
endif()
|
||||
if(DYNAREC)
|
||||
@@ -1341,12 +1374,13 @@ if(WOW64 AND ARM_DYNAREC)
|
||||
include(ExternalProject)
|
||||
ExternalProject_Add(
|
||||
wowbox64
|
||||
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/wow64"
|
||||
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/wine/wow64"
|
||||
CMAKE_ARGS
|
||||
-DCMAKE_TOOLCHAIN_FILE=${CMAKE_CURRENT_SOURCE_DIR}/wow64/toolchain_mingw.cmake
|
||||
-DCMAKE_TOOLCHAIN_FILE=${CMAKE_CURRENT_SOURCE_DIR}/wine/toolchain_mingw.cmake
|
||||
-DDYNAREC_PASS_STR=${DYNAREC_PASS_STR}
|
||||
-DDYNAREC_ASM_STR=${DYNAREC_ASM_STR}
|
||||
-DINTERPRETER_STR=${INTERPRETER_STR}
|
||||
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
|
||||
INSTALL_COMMAND ""
|
||||
TEST_COMMAND ""
|
||||
BUILD_ALWAYS ON
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# Box64: Linux Userspace x86-64 Emulator with a Twist
|
||||
|
||||
[Changelog](https://github.com/ptitSeb/box64/blob/main/docs/CHANGELOG.md) | [中文](https://github.com/ptitSeb/box64/blob/main/README_CN.md) | [Українська](https://github.com/ptitSeb/box64/blob/main/README_UK.md) | [Report an Error](https://github.com/ptitSeb/box64/issues/new)
|
||||
[Website](https://box86.org/) | [Changelog](https://github.com/ptitSeb/box64/blob/main/docs/CHANGELOG.md) | [中文](https://github.com/ptitSeb/box64/blob/main/README_CN.md) | [Українська](https://github.com/ptitSeb/box64/blob/main/README_UK.md) | [Report an Error](https://github.com/ptitSeb/box64/issues/new)
|
||||
|
||||
     
|
||||
|
||||
@@ -27,7 +27,12 @@ _Logo and icon by @grayduck - Thank you!_
|
||||
|
||||
## 📖 Usage
|
||||
|
||||
Box64 offers environment variables to control its behavior. For details, see [Usage Documentation](docs/USAGE.md).
|
||||
- `$ box64 ./program [args]` to run Linux x86_64 programs.
|
||||
- `$ box64 -k` to kill all the emulated processes.
|
||||
- `$ box64-bash` to have a x86_64 bash environment.
|
||||
- Want to use wine? see [Wine Documentation](docs/WINE.md).
|
||||
|
||||
Box64 also offers environment variables and rcfile to control its behavior. For details, see [Usage Documentation](docs/USAGE.md).
|
||||
|
||||
---
|
||||
|
||||
@@ -35,7 +40,7 @@ Box64 offers environment variables to control its behavior. For details, see [Us
|
||||
|
||||
- [Compilation Instructions](https://github.com/ptitSeb/box64/blob/main/docs/COMPILE.md)
|
||||
- [Bundle x86 Libraries](https://github.com/ptitSeb/box64/blob/main/docs/BUNDLE-X86-LIBS.md)
|
||||
- [Wine Installation for Box64](https://github.com/ptitSeb/box64/blob/main/docs/X64WINE.md)
|
||||
- [Wine Installation for Box64](https://github.com/ptitSeb/box64/blob/main/docs/WINE.md)
|
||||
|
||||
---
|
||||
|
||||
@@ -47,7 +52,7 @@ See the [Changelog](docs/CHANGELOG.md) for version updates.
|
||||
|
||||
## 🖥️ Platform Compatibility Notes
|
||||
|
||||
Box64 requires 64-bit libraries on the host system, as it directly translates x86_64 function calls. For 32-bit binaries, use Box86.
|
||||
Box64 requires 64-bit libraries on the host system, as it directly translates x86_64 function calls. For 32-bit binaries, use Box86 or Box32.
|
||||
|
||||
**Notes**
|
||||
|
||||
@@ -62,6 +67,8 @@ Box64 has configuration files located in `/etc/box64.box64rc` and `~/.box64rc`,
|
||||
|
||||
Settings priority: `~/.box64rc` > `/etc/box64.box64rc` > Command line.
|
||||
|
||||
For more information, check [Usage Documentation](docs/USAGE.md).
|
||||
|
||||
---
|
||||
|
||||
## 📄 Additional Platform-Specific Notes
|
||||
@@ -76,9 +83,9 @@ Settings priority: `~/.box64rc` > `/etc/box64.box64rc` > Command line.
|
||||
|
||||
Box64 wraps GTK libraries, supporting both gtk2 and gtk3.
|
||||
|
||||
### Steam
|
||||
### Linux Steam
|
||||
|
||||
Steam requires Box86 due to its 32-bit client app, but uses 64-bit local server binaries. Systems with less than 6GB RAM may need a swap file for optimal performance.
|
||||
Linux Steam requires Box86 or Box32 due to its 32-bit client app, but uses 64-bit local server binaries. Systems with less than 6GB RAM may need a swap file for optimal performance.
|
||||
|
||||
### Wine
|
||||
|
||||
@@ -86,6 +93,8 @@ Box64 supports Wine64 and Proton. For 32-bit components, Box86 is required. Syst
|
||||
|
||||
**Note**: You can use Wine WOW64 build to run x86 Windows programs in Box64-only environments, this is still experimental, but it works in most cases.
|
||||
|
||||
For more information, check [Wine Documentation](docs/WINE.md).
|
||||
|
||||
### Vulkan
|
||||
|
||||
Box64 wraps Vulkan libraries.
|
||||
|
||||
+15
-6
@@ -2,7 +2,7 @@
|
||||
|
||||
# Box64:Linux 用户空间 x86-64 模拟器(支持原生库)
|
||||
|
||||
[更新日志](https://github.com/ptitSeb/box64/blob/main/docs/CHANGELOG.md) | [English](https://github.com/ptitSeb/box64/blob/main/README.md) | [Українська](https://github.com/ptitSeb/box64/blob/main/README_UK.md) | [Report an Error](https://github.com/ptitSeb/box64/issues/new)
|
||||
[官网](https://box86.org/) | [更新日志](https://github.com/ptitSeb/box64/blob/main/docs/CHANGELOG.md) | [English](https://github.com/ptitSeb/box64/blob/main/README.md) | [Українська](https://github.com/ptitSeb/box64/blob/main/README_UK.md) | [Report an Error](https://github.com/ptitSeb/box64/issues/new)
|
||||
|
||||
     
|
||||
|
||||
@@ -27,14 +27,19 @@ _Logo 由 @grayduck 制作,感谢!_
|
||||
|
||||
## 📖 使用方法
|
||||
|
||||
Box64 提供了环境变量来控制其行为。有关详细信息请参阅[使用文档](docs/USAGE.md)。
|
||||
- `$ box64 ./program [args]` 运行 Linux x86_64 程序。
|
||||
- `$ box64 -k` 杀死所有模拟的进程。
|
||||
- `$ box64-bash` 进入 x86_64 bash 环境。
|
||||
- 想要使用 wine?请参阅 [Wine 使用说明](docs/WINE.md)。
|
||||
|
||||
Box64 还提供了环境变量和 Rc 文件来控制其行为。有关详细信息请参阅[使用文档](docs/USAGE.md)。
|
||||
|
||||
---
|
||||
|
||||
## 🚀 编译和安装
|
||||
|
||||
- [编译说明](https://github.com/ptitSeb/box64/blob/main/docs/COMPILE.md)
|
||||
- [安装 Wine](https://github.com/ptitSeb/box64/blob/main/docs/X64WINE.md)
|
||||
- [安装 Wine](https://github.com/ptitSeb/box64/blob/main/docs/WINE.md)
|
||||
|
||||
---
|
||||
|
||||
@@ -46,7 +51,7 @@ Box64 提供了环境变量来控制其行为。有关详细信息请参阅[使
|
||||
|
||||
## 🖥️ 平台兼容性说明
|
||||
|
||||
Box64 直接转换 x86_64 函数调用到本机原生库,因此需要主机系统上的 64 位库。对于 32 位二进制文件,请使用 Box86。
|
||||
Box64 直接转换 x86_64 函数调用到本机原生库,因此需要主机系统上的 64 位库。对于 32 位二进制文件,请使用 Box86 或 Box32。
|
||||
|
||||
**注意事项**
|
||||
|
||||
@@ -61,6 +66,8 @@ Box64 的配置文件位于 `/etc/box64.box64rc` 和 `~/.box64rc`,均为 `.ini
|
||||
|
||||
配置项的优先级:`~/.box64rc` > `/etc/box64.box64rc` > 命令行。
|
||||
|
||||
更多信息,请参阅[使用文档](docs/USAGE.md)。
|
||||
|
||||
---
|
||||
|
||||
## 📄 特定平台的其他说明
|
||||
@@ -74,9 +81,9 @@ Box64 的配置文件位于 `/etc/box64.box64rc` 和 `~/.box64rc`,均为 `.ini
|
||||
|
||||
Box64 包装了 GTK 库,支持 gtk2 和 gtk3。
|
||||
|
||||
### Steam
|
||||
### Linux Steam
|
||||
|
||||
由于 Steam 客户端应用是 32 位的,需要使用 Box86,但其本地服务器是 64 位的二进制文件。对于内存少于 6GB 的系统,可能需要使用交换文件以获得最佳性能。
|
||||
由于 Linux Steam 客户端应用是 32 位的,需要使用 Box86 或 Box32,但其本地服务器是 64 位的二进制文件。对于内存少于 6GB 的系统,可能需要使用交换文件以获得最佳性能。
|
||||
|
||||
### Wine
|
||||
|
||||
@@ -84,6 +91,8 @@ Box64 支持 Wine64 和 Proton。对于 32 位组件,需要 Box86。配备 Box
|
||||
|
||||
**提示**:您可以使用 Wine WOW64 版本在仅限 Box64 的环境中运行 x86 Windows 程序,这项支持仍处于实验阶段,但在大多数情况下都可以工作。
|
||||
|
||||
有关更多信息,请参阅 [Wine 使用说明](docs/WINE.md)。
|
||||
|
||||
### Vulkan
|
||||
|
||||
Box64 包装了 Vulkan 库。
|
||||
|
||||
+1
-1
@@ -37,7 +37,7 @@ Box64 інтегрується з DynaRec (динамічний рекомпіл
|
||||
Компіляція/Встановлення
|
||||
----
|
||||
> Інструкцію зі складання Box64 можна знайти [тут](docs/COMPILE.md).\
|
||||
> Інструкцію з встановлення Wine для Box64 можна знайти [тут](docs/X64WINE.md).
|
||||
> Інструкцію з встановлення Wine для Box64 можна знайти [тут](docs/WINE.md).
|
||||
|
||||
----
|
||||
Історія версій/Журнал змін
|
||||
|
||||
+70
-60
@@ -1,66 +1,76 @@
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/bluez-libs-5.72-2.el9.i686.rpm,af1aba8e6fa5ccf33032d58a3acc59368c07d532293396db205fb9a4bc1241ae
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/bluez-libs-5.72-2.el9.x86_64.rpm,49c273813b4616240acdae8dae893192658c7541482f9bbb2c46dfe19b61877d
|
||||
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/fribidi-1.0.10-6.el9.2.i686.rpm,75f808f0f5f93aceb4e477aa5f302edbed07a605a0644f0ea929d4ea609e36a0
|
||||
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/fribidi-1.0.10-6.el9.2.x86_64.rpm,b4763ca410f8479b2775efb55ba09e6722948af7526180a56309e3e090c27010
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/gmp-6.2.0-13.el9.i686.rpm,fe352f7d197ebdf2c92bbd6e548f9f6b7ac9e69e7a9d6c9861a6274482e79d73
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/gmp-6.2.0-13.el9.x86_64.rpm,babe0b1385e723476a216d5f4b72453e031c3d683b19344786c2bddf7203cb04
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/gnutls-3.8.3-4.el9_4.i686.rpm,64cf0b0136d3f9b80b07ce2d4b8ce6a4ab86617e8ef9baf560bdfa5edef825ea
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/gnutls-3.8.3-4.el9_4.x86_64.rpm,16c48c504fe62f8e19cac7c6442d3e08bba487f610c2f533116dac32357cda86
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/harfbuzz-2.7.4-10.el9.i686.rpm,5157daf2ab0a03b403d37c60b150b8f0f866754714f81e3d96368e06a16339ce
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/harfbuzz-2.7.4-10.el9.x86_64.rpm,1f81073019abe4176d4496723a89b55a349c31f507e96397a0b3efa7cea0ff61
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libblkid-2.37.4-20.el9.i686.rpm,f9e62d2768c31948b53268b7de51bd1c7342cdf39a328a0d89d933b4aa0c5dd1
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libblkid-2.37.4-20.el9.x86_64.rpm,ed02d978a36488b38bad62af21d4045367c1f0b00d00c90ded01e2fc8e190536
|
||||
https://archive.debian.org/debian/pool/main/c/curl/libcurl3-gnutls_7.74.0-1.3+deb11u7~bpo11+1_amd64.deb,d5ae55e3a9838d12358530cd03218cc0d18127a84e9cfc73bdf79dacd40b25e4
|
||||
https://archive.debian.org/debian/pool/main/c/curl/libcurl3-gnutls_7.74.0-1.3+deb11u7~bpo11+1_i386.deb,625e5189304d4d3bfb27cb821e257816c5ce761b1696b5da5ca4fa1035c48463
|
||||
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libepoxy-1.5.5-4.el9.i686.rpm,fe35e8de9b68c8d7e7b6b525580fc36cf9c86412cdb2b022dc01f95801771981
|
||||
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libepoxy-1.5.5-4.el9.x86_64.rpm,b6d1e7f1c832882ceb05187cbc2d8fe1f459bcd88c7160487ee6f734e1a5d017
|
||||
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libffi-devel-3.4.2-8.el9.i686.rpm,0c6f2ecc324680c6424bee4b1dbbdad2863f0f7f3130b196fc6e2b2823f07bc4
|
||||
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libffi-devel-3.4.2-8.el9.x86_64.rpm,483e4c58cb8af94143a0ff4b3e49b62cb7d6896766c8c0d9fe3659e68945b50e
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libgomp-11.5.0-2.el9.alma.1.i686.rpm,686ac26afe2073a3607f26fd1592a8ccd9b78f6eec6e872528634b43c4e04dd7
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libgomp-11.5.0-2.el9.alma.1.x86_64.rpm,9a2bdc6807b22ffb6294b30dcc13e20198abe5facaeefcf1bfacec3e1013e3c2
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libgpg-error-1.42-5.el9.i686.rpm,23f828674bc30752687452dacf4a25ca8c25ef0d25e3e6953d0714b5b33cef08
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libgpg-error-1.42-5.el9.x86_64.rpm,f28fabeb02add41b8156c394427da9dbf99882d8c42055367f872130ee424c97
|
||||
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libICE-1.0.10-8.el9.i686.rpm,d9c44bb34c990fdcc6987feefacfc9e1e7997ca25f1e0a59c9adc9c16f2266d1
|
||||
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libICE-1.0.10-8.el9.x86_64.rpm,d0b867203384942985c3c4ad6fc9ec0000fcc9965408451a6cdef8df06a3833c
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libidn2-2.3.0-7.el9.i686.rpm,4458e2d416b5e6714ec664c4f88791eee7d1e707026a5854d948a6159911465b
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libidn2-2.3.0-7.el9.x86_64.rpm,c3ff43237c05258ee0dd77c28540fc8d0d824f1567b115ddfd555b78d2ee0e7a
|
||||
https://cdn.getsol.us/repo/shannon/libj/libjpeg-turbo/libjpeg-turbo-32bit-3.0.3-21-1-x86_64.eopkg,5624990281f6520026aa2252c711f02d4916099aeac63accc83bd2135b9d3220
|
||||
https://cdn.getsol.us/repo/shannon/libj/libjpeg-turbo/libjpeg-turbo-3.0.3-21-1-x86_64.eopkg,c92f19d446b4c2450306f13b1a908f2552400da09301996fe349fee243d964d2
|
||||
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libogg-1.3.4-6.el9.i686.rpm,9e4ff6fa0251c5357ae8f648b3e396d0043d5b3f2fb28d23325f5bd592c67aee
|
||||
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libogg-1.3.4-6.el9.x86_64.rpm,83b4b333e335654674032d1cda4d7deb328b5a409f95e3952c3dc482b684fd8f
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libpng-1.6.37-12.el9.i686.rpm,66bf967e84f0d8e7a0059f2b7dda33482ff5e4fe088d0e3bc86dc54e6c7c97be
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libpng-1.6.37-12.el9.x86_64.rpm,ebb3e927dfafa0b199e00e2bef4c10c85fc82a70c359faf9aeb599eda70bfa5e
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libbrotli-1.0.9-7.el9_5.i686.rpm,d18c20fccbb9497222059d475161a55c0c6279344f214fe551b8b0f87d3c054a
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libbrotli-1.0.9-7.el9_5.x86_64.rpm,77906ae44bcd42a9f6646d814874768e8befaabf413133d44f71a95ac6c6d68c
|
||||
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libsigc%2B%2B20-2.10.7-2.el9.i686.rpm,7c33f4c18cbd51dc0a7c9ae0190b1a27d0540ce2fd92ced4776dde66162d1a88
|
||||
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libsigc%2B%2B20-2.10.7-2.el9.x86_64.rpm,8600132b9e4efadfe23d3125e90287f5a7114165fd9ecb064d9930fcca446ef2
|
||||
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libSM-1.2.3-10.el9.i686.rpm,ec68b3def828ba442248f3cff495f42c4af3dd58f38c8daad07dfddc109d999a
|
||||
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libSM-1.2.3-10.el9.x86_64.rpm,d00318843a50138829b470a97b8db1a00723b10bca23c16a8386d9ab670e4c64
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libstdc%2B%2B-11.5.0-5.el9_5.alma.1.i686.rpm,05fd29569c312a661374aa69e28ed5cad20812822070a3138265c92a446e2c80
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libstdc%2B%2B-11.5.0-5.el9_5.alma.1.x86_64.rpm,7efb1ded0ec2763589dd3bc6a9d52fa9f898cc1f3db6e8761e1d223ce4506424
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libtasn1-4.16.0-8.el9_1.i686.rpm,9cbd11277e89bd0d4a80900bee01ca71b0c582c9cb5744f5035135b2ed907c85
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libtasn1-4.16.0-8.el9_1.x86_64.rpm,2dd3a1ad2785df642cb03dfed6dfbeec929ff8b14e52e61272ca7e89f86ba3cd
|
||||
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libtheora-1.1.1-31.el9.i686.rpm,2155c688b516ab359d0c47be6d73e51d3c65f199ed5591f7bb7ce6d5d9799977
|
||||
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libtheora-1.1.1-31.el9.x86_64.rpm,25ab4a8ad997b450b4a34a777f5a0678eea72ca1665944a7a461ac63de4b25bf
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libunistring-0.9.10-15.el9.i686.rpm,792600a879fbd94ce4bf249713b0cb3a166c147cfad397e8a15e6b4f01c75997
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libunistring-0.9.10-15.el9.x86_64.rpm,d2f86fbee729a4900a433a6c52a3cb95d9b52b1d79c9e719ee3ef509813eb6d9
|
||||
https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/34/Everything/x86_64/os/Packages/l/libunwind-1.4.0-5.fc34.i686.rpm,eb518e9d073c36fd29862c7afd00a8a7cb186074a0e162983f18fb6c9dc71d2c
|
||||
https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/34/Everything/x86_64/os/Packages/l/libunwind-1.4.0-5.fc34.x86_64.rpm,0f44e37e4eb472508e0dba8505ebbb04c2c1390c6a43970a6af80aad886037e3
|
||||
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libvorbis-1.3.7-5.el9.i686.rpm,e38c5185fea611330ea253db020315dd564507bf95c48a81dbe7db186ce4214b
|
||||
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libvorbis-1.3.7-5.el9.x86_64.rpm,3c340337a073975636d198a282503f32a54bf85fb5345522a2c22e530b8d6c9e
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libzstd-1.5.1-2.el9.i686.rpm,e98f253d6f5f9acf2ded628cd98f50a54a031e354bf7bb2efc3fe39f9899fe49
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libzstd-1.5.1-2.el9.x86_64.rpm,2e5215e225cec2db43d92c3b3380812a6f8684e881ed415670299e1e0fe7d1ce
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/lz4-libs-1.9.3-5.el9.i686.rpm,c308ba7380a3b5c5337c919150f0234342b64c1ea696d6207c2b790b82ba4669
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/lz4-libs-1.9.3-5.el9.x86_64.rpm,439e701491af6a957ac4d7dc69cccee1a945333f19d8bfcbd896b5119af01aab
|
||||
https://archives.fedoraproject.org/pub/archive/fedora/linux/updates/40/Everything/x86_64/Packages/s/SDL3-3.2.12-1.fc40.i686.rpm,4a3bce6e6358ddd05ed2941e7b8fcc4c8cc02df20741d3f0f9295facbc687769
|
||||
https://archives.fedoraproject.org/pub/archive/fedora/linux/updates/40/Everything/x86_64/Packages/s/SDL3-3.2.12-1.fc40.x86_64.rpm,9524803ef42d80dc1b15190d5bb5925200995d5a6152eca04471383ff891af17
|
||||
https://cdn.getsol.us/repo/shannon/libj/libjpeg-turbo/libjpeg-turbo-3.0.3-21-1-x86_64.eopkg,c92f19d446b4c2450306f13b1a908f2552400da09301996fe349fee243d964d2
|
||||
https://cdn.getsol.us/repo/shannon/libj/libjpeg-turbo/libjpeg-turbo-32bit-3.0.3-21-1-x86_64.eopkg,5624990281f6520026aa2252c711f02d4916099aeac63accc83bd2135b9d3220
|
||||
https://repo.almalinux.org/almalinux/8.10/BaseOS/x86_64/os/Packages/nettle-3.4.1-7.el8.i686.rpm,13bc8758355c3ec885f414e0e86efad29a7fe82c0999cdb3754d666949c06cc5
|
||||
https://repo.almalinux.org/almalinux/8.10/BaseOS/x86_64/os/Packages/nettle-3.4.1-7.el8.x86_64.rpm,fb4aaa22b2e2f2fc0c451b87ac464e8746d240397d64e79f6bfd38f4e9128a5a
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/nettle-3.9.1-1.el9.i686.rpm,e5610fe3b25cfca1616440e1a8a7489fd37b0852f182fdda87ab8e196d981970
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/nettle-3.9.1-1.el9.x86_64.rpm,9786b6610d17aa495fb640ba6d046bf73704915b82d12e6d8339090ff4891de5
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/p11-kit-0.25.3-3.el9_5.i686.rpm,abe4ab924b405c236eaf3fa067fed50ac66d15d0ef42c782a745788c1a9c5b91
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/p11-kit-0.25.3-3.el9_5.x86_64.rpm,0e1bd97e697a9fa3b4e508b945cf352b73b06e4e8218c14ac5fb912b0022c646
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/pam-1.5.1-22.el9_5.i686.rpm,f2ae4441fc667cdcb930e7a2cfe90f7342e7d1c8848d6d18cb350ba68e025862
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/pam-1.5.1-22.el9_5.x86_64.rpm,15bfe177d3c10982c75e81d7b274883a9fb53322011c8d829667c983ee419b18
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/pciutils-libs-3.7.0-5.el9.i686.rpm,2cf468da5ecf307cc325c9a5da0a288aafd25dec0951af2b4d0954a77bdf900d
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/pciutils-libs-3.7.0-5.el9.x86_64.rpm,308bd897d8f9a36020d70edc79089a3595b22b149200d67c37e2d4e6147a9f75
|
||||
https://dl.fedoraproject.org/pub/fedora/linux/updates/40/Everything/x86_64/Packages/s/SDL3-3.2.4-1.fc40.i686.rpm,f4776f6f56a8d3e62e95c06fb885832e22116323c0c2e0f57f918cd4b92e16a2
|
||||
https://dl.fedoraproject.org/pub/fedora/linux/updates/40/Everything/x86_64/Packages/s/SDL3-3.2.4-1.fc40.x86_64.rpm,96f52b7cf293ce335e2bf726c8b6aefd82ed76fbe9d9f0db1fe603780477c2d0
|
||||
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/fribidi-1.0.10-6.el9.2.i686.rpm,75f808f0f5f93aceb4e477aa5f302edbed07a605a0644f0ea929d4ea609e36a0
|
||||
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/fribidi-1.0.10-6.el9.2.x86_64.rpm,b4763ca410f8479b2775efb55ba09e6722948af7526180a56309e3e090c27010
|
||||
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libICE-1.0.10-8.el9.i686.rpm,d9c44bb34c990fdcc6987feefacfc9e1e7997ca25f1e0a59c9adc9c16f2266d1
|
||||
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libICE-1.0.10-8.el9.x86_64.rpm,d0b867203384942985c3c4ad6fc9ec0000fcc9965408451a6cdef8df06a3833c
|
||||
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libSM-1.2.3-10.el9.i686.rpm,ec68b3def828ba442248f3cff495f42c4af3dd58f38c8daad07dfddc109d999a
|
||||
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libSM-1.2.3-10.el9.x86_64.rpm,d00318843a50138829b470a97b8db1a00723b10bca23c16a8386d9ab670e4c64
|
||||
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libepoxy-1.5.5-4.el9.i686.rpm,fe35e8de9b68c8d7e7b6b525580fc36cf9c86412cdb2b022dc01f95801771981
|
||||
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libepoxy-1.5.5-4.el9.x86_64.rpm,b6d1e7f1c832882ceb05187cbc2d8fe1f459bcd88c7160487ee6f734e1a5d017
|
||||
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libogg-1.3.4-6.el9.i686.rpm,9e4ff6fa0251c5357ae8f648b3e396d0043d5b3f2fb28d23325f5bd592c67aee
|
||||
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libogg-1.3.4-6.el9.x86_64.rpm,83b4b333e335654674032d1cda4d7deb328b5a409f95e3952c3dc482b684fd8f
|
||||
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libsigc%2B%2B20-2.10.7-2.el9.i686.rpm,7c33f4c18cbd51dc0a7c9ae0190b1a27d0540ce2fd92ced4776dde66162d1a88
|
||||
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libsigc%2B%2B20-2.10.7-2.el9.x86_64.rpm,8600132b9e4efadfe23d3125e90287f5a7114165fd9ecb064d9930fcca446ef2
|
||||
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libtheora-1.1.1-31.el9.i686.rpm,2155c688b516ab359d0c47be6d73e51d3c65f199ed5591f7bb7ce6d5d9799977
|
||||
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libtheora-1.1.1-31.el9.x86_64.rpm,25ab4a8ad997b450b4a34a777f5a0678eea72ca1665944a7a461ac63de4b25bf
|
||||
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libvorbis-1.3.7-5.el9.i686.rpm,e38c5185fea611330ea253db020315dd564507bf95c48a81dbe7db186ce4214b
|
||||
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libvorbis-1.3.7-5.el9.x86_64.rpm,3c340337a073975636d198a282503f32a54bf85fb5345522a2c22e530b8d6c9e
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/bluez-libs-5.72-2.el9.i686.rpm,af1aba8e6fa5ccf33032d58a3acc59368c07d532293396db205fb9a4bc1241ae
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/bluez-libs-5.72-2.el9.x86_64.rpm,49c273813b4616240acdae8dae893192658c7541482f9bbb2c46dfe19b61877d
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/glibc-2.34-125.el9_5.8.alma.1.i686.rpm,28bc1088e39483d145849e8804c5a0f2524faeb4f76631ae46c41100f40e08b9
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/glibc-2.34-125.el9_5.8.alma.1.x86_64.rpm,1848b9ced2dfec6c206791b23a5a8a6356939c5ed0492fc91c86bf1d3a255c1d
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/gmp-6.2.0-13.el9.i686.rpm,fe352f7d197ebdf2c92bbd6e548f9f6b7ac9e69e7a9d6c9861a6274482e79d73
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/gmp-6.2.0-13.el9.x86_64.rpm,babe0b1385e723476a216d5f4b72453e031c3d683b19344786c2bddf7203cb04
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/gnutls-3.8.3-4.el9_4.i686.rpm,64cf0b0136d3f9b80b07ce2d4b8ce6a4ab86617e8ef9baf560bdfa5edef825ea
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/gnutls-3.8.3-4.el9_4.x86_64.rpm,16c48c504fe62f8e19cac7c6442d3e08bba487f610c2f533116dac32357cda86
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/harfbuzz-2.7.4-10.el9.i686.rpm,5157daf2ab0a03b403d37c60b150b8f0f866754714f81e3d96368e06a16339ce
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/harfbuzz-2.7.4-10.el9.x86_64.rpm,1f81073019abe4176d4496723a89b55a349c31f507e96397a0b3efa7cea0ff61
|
||||
https://archives.fedoraproject.org/pub/archive/fedora/linux/updates/34/Everything/x86_64/Packages/h/hidapi-0.11.2-2.fc34.i686.rpm,386040fc502e2f02b4b072e0cd90c034dc0a30831fbd2ddb116d17c080b6f9a4
|
||||
https://archives.fedoraproject.org/pub/archive/fedora/linux/updates/34/Everything/x86_64/Packages/h/hidapi-0.11.2-2.fc34.x86_64.rpm,2a13461c7d5fcf72ffd682b3eb04833aea8306d61c3b8bdeb42a5081d96d5478
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libblkid-2.37.4-20.el9.i686.rpm,f9e62d2768c31948b53268b7de51bd1c7342cdf39a328a0d89d933b4aa0c5dd1
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libblkid-2.37.4-20.el9.x86_64.rpm,ed02d978a36488b38bad62af21d4045367c1f0b00d00c90ded01e2fc8e190536
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libbrotli-1.0.9-7.el9_5.i686.rpm,d18c20fccbb9497222059d475161a55c0c6279344f214fe551b8b0f87d3c054a
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libbrotli-1.0.9-7.el9_5.x86_64.rpm,77906ae44bcd42a9f6646d814874768e8befaabf413133d44f71a95ac6c6d68c
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libffi-3.4.2-8.el9.i686.rpm,70daa216ed2a6540e41c455efc95d2b5671db164137f854bceae07e348f58645
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libffi-3.4.2-8.el9.x86_64.rpm,1cf2d122e5c423681394c1bc599ee2281d2eafff5a3749842bc93c37db4bed5e
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libgomp-11.5.0-2.el9.alma.1.i686.rpm,686ac26afe2073a3607f26fd1592a8ccd9b78f6eec6e872528634b43c4e04dd7
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libgomp-11.5.0-2.el9.alma.1.x86_64.rpm,9a2bdc6807b22ffb6294b30dcc13e20198abe5facaeefcf1bfacec3e1013e3c2
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libgpg-error-1.42-5.el9.i686.rpm,23f828674bc30752687452dacf4a25ca8c25ef0d25e3e6953d0714b5b33cef08
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libgpg-error-1.42-5.el9.x86_64.rpm,f28fabeb02add41b8156c394427da9dbf99882d8c42055367f872130ee424c97
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libidn2-2.3.0-7.el9.i686.rpm,4458e2d416b5e6714ec664c4f88791eee7d1e707026a5854d948a6159911465b
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libidn2-2.3.0-7.el9.x86_64.rpm,c3ff43237c05258ee0dd77c28540fc8d0d824f1567b115ddfd555b78d2ee0e7a
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libnsl-2.34-125.el9_5.8.alma.1.i686.rpm,7f4d1552b6036c49028db959f82fc0bc30773cd7ed0a62c3906da0e2388f4dc5
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libnsl-2.34-125.el9_5.8.alma.1.x86_64.rpm,7d0e521ab087807ee71d79da66a2829b827bf5080bb5d080dfab108e31cf218b
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libpng-1.6.37-12.el9.i686.rpm,66bf967e84f0d8e7a0059f2b7dda33482ff5e4fe088d0e3bc86dc54e6c7c97be
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libpng-1.6.37-12.el9.x86_64.rpm,ebb3e927dfafa0b199e00e2bef4c10c85fc82a70c359faf9aeb599eda70bfa5e
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libstdc%2B%2B-11.5.0-5.el9_5.alma.1.i686.rpm,05fd29569c312a661374aa69e28ed5cad20812822070a3138265c92a446e2c80
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libstdc%2B%2B-11.5.0-5.el9_5.alma.1.x86_64.rpm,7efb1ded0ec2763589dd3bc6a9d52fa9f898cc1f3db6e8761e1d223ce4506424
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libtasn1-4.16.0-8.el9_1.i686.rpm,9cbd11277e89bd0d4a80900bee01ca71b0c582c9cb5744f5035135b2ed907c85
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libtasn1-4.16.0-8.el9_1.x86_64.rpm,2dd3a1ad2785df642cb03dfed6dfbeec929ff8b14e52e61272ca7e89f86ba3cd
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libunistring-0.9.10-15.el9.i686.rpm,792600a879fbd94ce4bf249713b0cb3a166c147cfad397e8a15e6b4f01c75997
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libunistring-0.9.10-15.el9.x86_64.rpm,d2f86fbee729a4900a433a6c52a3cb95d9b52b1d79c9e719ee3ef509813eb6d9
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libzstd-1.5.1-2.el9.i686.rpm,e98f253d6f5f9acf2ded628cd98f50a54a031e354bf7bb2efc3fe39f9899fe49
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libzstd-1.5.1-2.el9.x86_64.rpm,2e5215e225cec2db43d92c3b3380812a6f8684e881ed415670299e1e0fe7d1ce
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/lz4-libs-1.9.3-5.el9.i686.rpm,c308ba7380a3b5c5337c919150f0234342b64c1ea696d6207c2b790b82ba4669
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/lz4-libs-1.9.3-5.el9.x86_64.rpm,439e701491af6a957ac4d7dc69cccee1a945333f19d8bfcbd896b5119af01aab
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/ncurses-libs-6.2-10.20210508.el9.i686.rpm,285db6dc6f610f75ef6863dcb0a383eae394c2b33bff283189cb49ac7fae4c58
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/ncurses-libs-6.2-10.20210508.el9.x86_64.rpm,d06b0e491481a345faf21a69666cbdc302d19b54fb29ae1aa78fa6b205f9e604
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/nettle-3.9.1-1.el9.i686.rpm,e5610fe3b25cfca1616440e1a8a7489fd37b0852f182fdda87ab8e196d981970
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/nettle-3.9.1-1.el9.x86_64.rpm,9786b6610d17aa495fb640ba6d046bf73704915b82d12e6d8339090ff4891de5
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/p11-kit-0.25.3-3.el9_5.i686.rpm,abe4ab924b405c236eaf3fa067fed50ac66d15d0ef42c782a745788c1a9c5b91
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/p11-kit-0.25.3-3.el9_5.x86_64.rpm,0e1bd97e697a9fa3b4e508b945cf352b73b06e4e8218c14ac5fb912b0022c646
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/pam-1.5.1-22.el9_5.i686.rpm,f2ae4441fc667cdcb930e7a2cfe90f7342e7d1c8848d6d18cb350ba68e025862
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/pam-1.5.1-22.el9_5.x86_64.rpm,15bfe177d3c10982c75e81d7b274883a9fb53322011c8d829667c983ee419b18
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/pciutils-libs-3.7.0-5.el9.i686.rpm,2cf468da5ecf307cc325c9a5da0a288aafd25dec0951af2b4d0954a77bdf900d
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/pciutils-libs-3.7.0-5.el9.x86_64.rpm,308bd897d8f9a36020d70edc79089a3595b22b149200d67c37e2d4e6147a9f75
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/sqlite-libs-3.34.1-7.el9_3.i686.rpm,dc6946a8344b8f4f476fef9479d1786c86fdcd045e988ab5d85fef7780e1fae4
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/sqlite-libs-3.34.1-7.el9_3.x86_64.rpm,e7f87444f24a03b37caa02942082b6d4283067ecbbd3f7798f882d22b55713cf
|
||||
|
+113
-81
@@ -1,96 +1,128 @@
|
||||
#!/bin/bash
|
||||
#!/bin/sh
|
||||
|
||||
set -x
|
||||
set -ex
|
||||
|
||||
extract_pkg_auto() {
|
||||
# Example x86_64 package name: libcurl3-gnutls_7.74.0-1.3+deb11u7~bpo11+1_amd64.deb
|
||||
# Example x86 package name: libcurl3-gnutls_7.74.0-1.3+deb11u7~bpo11+1_i386.deb
|
||||
if echo "${1}" | grep -q -P ".deb$"; then
|
||||
echo "DEB (Debian) package detected."
|
||||
ar x "$(basename "${1}")"
|
||||
tar --extract --file data.tar*
|
||||
# Example x86_64 package name: curl-gnutls-8.1.2-44-1-x86_64.eopkg
|
||||
# Example x86 package name: curl-gnutls-32bit-8.1.2-44-1-x86_64.eopkg
|
||||
elif echo "${1}" | grep -q -P ".eopkg$"; then
|
||||
echo "EOPKG (Solus Linux) package detected."
|
||||
unzip -o "$(basename "${1}")"
|
||||
tar --extract --file install.tar.xz
|
||||
# Example x86_64 package name: bluez-libs-5.63-1.el8.x86_64.rpm
|
||||
# Example x86 package name: bluez-libs-5.63-1.el8.i686.rpm
|
||||
elif echo "${1}" | grep -q -P ".rpm$"; then
|
||||
echo "RPM (Fedora) detected."
|
||||
rpm2cpio "$(basename "${1}")" | cpio -idmv
|
||||
# Example x86_64 package name: libjpeg-turbo-3.0.1_1.x86_64.xbps
|
||||
# Example x86 package name: libjpeg-turbo-32bit-3.0.1_1.x86_64.xbps
|
||||
elif echo "${1}" | grep -q -P ".xbps$"; then
|
||||
echo "XBPS (Void Linux) package detected."
|
||||
tar --extract --file "$(basename "${1}")"
|
||||
else
|
||||
echo "Unsupported package type detected."
|
||||
exit 1
|
||||
fi
|
||||
trap cleanup_exit INT TERM EXIT
|
||||
|
||||
cleanup_exit()
|
||||
{
|
||||
echo "Running cleanup_exit..."
|
||||
rm -rf /tmp/box64-bundle.*
|
||||
}
|
||||
|
||||
box64_dir=$(pwd)
|
||||
dir_tmp_local="$(mktemp --directory)"
|
||||
cd "${dir_tmp_local}"
|
||||
# we must have few tools
|
||||
awk=$(which awk) || { echo "E: You must have awk" && exit 1; }
|
||||
cpio=$(which cpio) || { echo "E: You must have cpio" && exit 1; }
|
||||
curl=$(which curl) || { echo "E: You must have curl" && exit 1; }
|
||||
curl_cmd="${curl} --connect-timeout 5 --retry 5 --retry-delay 1 --create-dirs -fsSLo"
|
||||
rpm2cpio=$(which rpm2cpio) || { echo "E: You must have rpm2cpio" && exit 1; }
|
||||
sha256sum=$(which sha256sum) || { echo "E: You must have sha256sum" && exit 1; }
|
||||
unzip=$(which unzip) || { echo "E: You must have unzip" && exit 1; }
|
||||
|
||||
for line in $(cat "${box64_dir}/box64-bundle-x86-libs.csv");
|
||||
do pkg_url="$(echo "${line}" | cut -d, -f1)"
|
||||
pkg_checksum_expected="$(echo "${line}" | cut -d, -f2)"
|
||||
pkg_name="$(basename "${pkg_url}")"
|
||||
curl --silent --location --remote-name "${pkg_url}"
|
||||
pkg_checksum_actual="$(sha256sum ${pkg_name} | awk '{print $1}')"
|
||||
if [[ "${pkg_checksum_expected}" -ne "${pkg_checksum_actual}" ]];
|
||||
then echo "Invalid checksum for ${pkg_name}"
|
||||
echo "Expected: ${pkg_checksum_expected}"
|
||||
echo "Actual: ${pkg_checksum_actual}"
|
||||
current_dir=$(pwd)
|
||||
dir_tmp="$(mktemp -d /tmp/box64-bundle.XXXXXX)"
|
||||
|
||||
# download the packages
|
||||
while IFS= read -r line; do
|
||||
# shellcheck disable=SC2016
|
||||
pkg_url=$(echo "${line}" | ${awk} -F',' '{print$(NF-1)}')
|
||||
# shellcheck disable=SC2016
|
||||
pkg_checksum=$(echo "${line}" | ${awk} -F',' '{print$(NF)}')
|
||||
# shellcheck disable=SC2016
|
||||
pkg_name=$(echo "${pkg_url}" | ${awk} -F'/' '{print$(NF)}')
|
||||
${curl_cmd} "${dir_tmp}/bundle-pkgs/${pkg_name}" "${pkg_url}"
|
||||
checksum="$(${sha256sum} "${dir_tmp}/bundle-pkgs/${pkg_name}" | awk '{print $1}')"
|
||||
if [ "${pkg_checksum}" != "${checksum}" ]; then
|
||||
echo "E: Invalid checksum for ${pkg_name}"
|
||||
echo "Expected: ${pkg_checksum}"
|
||||
echo "Computed: ${checksum}"
|
||||
exit 1
|
||||
fi
|
||||
extract_pkg_auto "${pkg_name}"
|
||||
done < box64-bundle-x86-libs.csv
|
||||
|
||||
# generate the bundle packages archive
|
||||
tar -C "${dir_tmp}"/bundle-pkgs -czvf "${current_dir}"/box64-bundle-x86-pkgs.tar.gz .
|
||||
|
||||
# extract the packages
|
||||
cd "${dir_tmp}"/bundle-pkgs
|
||||
for file in *.deb *.eopkg *.rpm *.xbps; do
|
||||
# handle the case of no files, e.g. xbps
|
||||
[ -e "${dir_tmp}"/bundle-pkgs/"${file}" ] || break
|
||||
# shellcheck disable=SC2016
|
||||
extension=$(echo "${file}" | ${awk} -F'.' '{print$(NF)}')
|
||||
mkdir -p "${dir_tmp}"/bundle-libs
|
||||
cd "${dir_tmp}"/bundle-libs
|
||||
case "${extension}" in
|
||||
deb)
|
||||
echo "I: DEB (Debian) package detected (${file})"
|
||||
ar x "${dir_tmp}"/bundle-pkgs/"${file}"
|
||||
tar -xf data.tar*
|
||||
;;
|
||||
eopkg)
|
||||
echo "I: EOPKG (Solus Linux) package detected (${file})"
|
||||
${unzip} -o "${dir_tmp}"/bundle-pkgs/"${file}"
|
||||
tar -xf install.tar.xz
|
||||
;;
|
||||
rpm)
|
||||
echo "I: RPM (Fedora) detected (${file})"
|
||||
${rpm2cpio} "${dir_tmp}"/bundle-pkgs/"${file}" | ${cpio} -idmv
|
||||
;;
|
||||
xbps)
|
||||
echo "I: XBPS (Void Linux) package detected (${file})"
|
||||
tar -xf "${dir_tmp}"/bundle-pkgs/"${file}"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Start preperation of bundles.
|
||||
mkdir -p \
|
||||
"${dir_tmp_local}/bundle-libs/usr/lib/box64-i386-linux-gnu" \
|
||||
"${dir_tmp_local}/bundle-libs/usr/lib/box64-x86_64-linux-gnu" \
|
||||
"${dir_tmp_local}/bundle-pkgs" \
|
||||
# reorganize the files
|
||||
cd "${dir_tmp}"/bundle-libs
|
||||
mkdir -p "${dir_tmp}"/bundle-libs/box64-i386-linux-gnu
|
||||
mv lib/*.so* usr/lib/*.so* usr/lib/i386-linux-gnu/*.so* usr/lib32/*.so* \
|
||||
"${dir_tmp}"/bundle-libs/box64-i386-linux-gnu
|
||||
mkdir -p "${dir_tmp}"/bundle-libs/box64-x86_64-linux-gnu
|
||||
mv lib64/*.so* usr/lib/x86_64-linux-gnu/*.so* usr/lib64/*.so* \
|
||||
"${dir_tmp}"/bundle-libs/box64-x86_64-linux-gnu
|
||||
rm -f ./*.tar.* debian-binary files.xml metadata.xml
|
||||
rm -rf ./lib* etc run sbin usr var
|
||||
mkdir -p usr/lib
|
||||
mv box64-*-linux-gnu usr/lib
|
||||
|
||||
# Copy Debian family libraries.
|
||||
cp --archive "${dir_tmp_local}"/usr/lib/i386-linux-gnu/*.so* "${dir_tmp_local}/bundle-libs/usr/lib/box64-i386-linux-gnu"
|
||||
cp --archive "${dir_tmp_local}"/usr/lib/x86_64-linux-gnu/*.so* "${dir_tmp_local}/bundle-libs/usr/lib/box64-x86_64-linux-gnu"
|
||||
# Copy Fedora family libraries.
|
||||
cp --archive "${dir_tmp_local}"/usr/lib/*.so* "${dir_tmp_local}/bundle-libs/usr/lib/box64-i386-linux-gnu"
|
||||
cp --archive "${dir_tmp_local}"/usr/lib64/*.so* "${dir_tmp_local}/bundle-libs/usr/lib/box64-x86_64-linux-gnu"
|
||||
## This location is used by a few special packages such as "glibc".
|
||||
cp --archive "${dir_tmp_local}"/lib/*.so* "${dir_tmp_local}/bundle-libs/usr/lib/box64-i386-linux-gnu"
|
||||
cp --archive "${dir_tmp_local}"/lib64/*.so* "${dir_tmp_local}/bundle-libs/usr/lib/box64-x86_64-linux-gnu"
|
||||
# Copy Solus and Void Linux family libraries.
|
||||
cp --archive "${dir_tmp_local}"/usr/lib32/*.so* "${dir_tmp_local}/bundle-libs/usr/lib/box64-i386-linux-gnu"
|
||||
# remove libraries that cannot be emulated
|
||||
# https://github.com/ptitSeb/box64/blob/v0.3.6/src/librarian/library.c#L433
|
||||
set -- libc libpthread librt libGL libX11 libasound libdl libm libbsd libutil \
|
||||
libresolv libXxf86vm libXinerama libXrandr libXext libXfixes libXcursor \
|
||||
libXrender libXft libXi libXss libXpm libXau libXdmcp libX11-xcb libxcb \
|
||||
libxcb-xfixes libxcb-shape libxcb-shm libxcb-randr libxcb-image \
|
||||
libxcb-keysyms libxcb-xtest libxcb-glx libxcb-dri2 libxcb-dri3 libXtst libXt \
|
||||
libXcomposite libXdamage libXmu libxkbcommon libxkbcommon-x11 \
|
||||
libpulse-simple libpulse libvulkan ld-linux-x86-64 crashhandler \
|
||||
libtcmalloc_minimal libanl ld-linux libthread_db
|
||||
for file in "$@"; do
|
||||
rm -f "${dir_tmp}"/bundle-libs/usr/lib/box64-*-linux-gnu/"${file}".so*
|
||||
done
|
||||
|
||||
# Create "<LIBRARY_FILE>.so" symlinks.
|
||||
for dir_lib in \
|
||||
"${dir_tmp_local}/bundle-libs/usr/lib/box64-i386-linux-gnu" \
|
||||
"${dir_tmp_local}/bundle-libs/usr/lib/box64-x86_64-linux-gnu"
|
||||
# If two or more libraries of the same name exist, this will symlink the oldest version.
|
||||
# Pipe this into a reverse sort `| sort -r` to symlink the newest version.
|
||||
do for lib in $(ls -1 "${dir_lib}")
|
||||
# Example output: libbluetooth.so
|
||||
do lib_base="$(echo "${lib}" | cut -d. -f1,2)"
|
||||
if ! ls "${dir_lib}/${lib_base}" 2> /dev/null
|
||||
then ln -s "${lib}" "${dir_lib}/${lib_base}"
|
||||
# check broken symlinks
|
||||
if find "${dir_tmp}"/bundle-libs -type l ! -exec test -e {} \; -print | grep bundle-libs; then
|
||||
echo "E: Broken symlinks found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# create shared libraries (.so) symlinks
|
||||
# if multiple libraries of the same name exist, it will symlink the oldest version
|
||||
# e.g. libcurl-gnutls soname with versioned symbols (CURL_GNUTLS_3, CURL_GNUTLS_4)
|
||||
# libcurl-gnutls.so -> libcurl-gnutls.so.3
|
||||
# libcurl-gnutls.so.3 -> libcurl-gnutls.so.4
|
||||
# libcurl-gnutls.so.4 -> libcurl-gnutls.so.4.7.0
|
||||
# libcurl-gnutls.so.4.7.0
|
||||
for dir_lib in "${dir_tmp}"/bundle-libs/usr/lib/box64-*-linux-gnu; do
|
||||
cd "${dir_lib}"
|
||||
for lib in lib*.so*; do
|
||||
lib_base="$(echo "${lib}" | awk -F'.' '{print $1"."$2}')"
|
||||
if ! ls "${dir_lib}/${lib_base}" 2> /dev/null; then
|
||||
ln -s "${lib}" "${lib_base}"
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
mv "${dir_tmp_local}"/*.deb "${dir_tmp_local}/bundle-pkgs/"
|
||||
mv "${dir_tmp_local}"/*.eopkg "${dir_tmp_local}/bundle-pkgs/"
|
||||
mv "${dir_tmp_local}"/*.rpm "${dir_tmp_local}/bundle-pkgs/"
|
||||
mv "${dir_tmp_local}"/*.xbps "${dir_tmp_local}/bundle-pkgs/"
|
||||
|
||||
tar --directory "${dir_tmp_local}/bundle-libs" --create --file "${box64_dir}/box64-bundle-x86-libs.tar.gz" .
|
||||
tar --directory "${dir_tmp_local}/bundle-pkgs" --create --file "${box64_dir}/box64-bundle-x86-pkgs.tar.gz" .
|
||||
|
||||
# Clean up.
|
||||
cd -
|
||||
rm -r -f "${dir_tmp_local}"
|
||||
# generate the bundle libraries archive
|
||||
tar -C "${dir_tmp}"/bundle-libs -czvf "${current_dir}"/box64-bundle-x86-libs.tar.gz .
|
||||
Vendored
+12
@@ -1,3 +1,15 @@
|
||||
box64 (0.3.8) unstable; urgency=low
|
||||
|
||||
This version introduce DynaCache, a disk cache for the generated native code. It's not enabled by default for now (but it will use cache file if present by default). It can dramaticaly speedup the load of program (try with linux factorio for example). This version also improve in the volatile metadata handling. There is a massive compatiblity improvment for box32 and on all dynarec in general too. And few more function wrapping...
|
||||
|
||||
=> DynaCache for faster loading of program, and avoid runtime hicups
|
||||
=> Batter box32 compatibility (much less "Out of Memory" error)
|
||||
=> Unity3D games on Wayland are working now
|
||||
=> Volatile Metadata fully supported and handled, making games like Starfield to just work.
|
||||
=> More work on AVX support for RV64 & LA64. LA64 almost there, while RV64 has Scalar only support (no hardware vector support yet for AVX)
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Mon, 10 Oct 2025 10:30:33 -0100
|
||||
|
||||
box64 (0.3.6) unstable; urgency=low
|
||||
|
||||
This version introduces wowbox64.dll for Hangover; the ability to use the Volatile Metadata of Windows executables for x64 wine; and some better x87/SSE/AVX handling
|
||||
|
||||
+11
-6
@@ -8,14 +8,19 @@ The script `box64-bundle-x86-libs.sh` is provided to download, extract, and re-b
|
||||
|
||||
Install required dependencies for the bundle script.
|
||||
|
||||
- Arch Linux
|
||||
```
|
||||
sudo pacman -S -y -u
|
||||
sudo pacman -S binutils coreutils curl rpm-tools tar zstd
|
||||
```
|
||||
- Debian
|
||||
```
|
||||
sudo apt-get update
|
||||
sudo apt-get install coreutils curl binutils rpm2cpio tar zstd
|
||||
sudo apt-get install binutils coreutils curl rpm2cpio tar zstd
|
||||
```
|
||||
- Fedora
|
||||
```
|
||||
sudo dnf install coreutils curl binutils tar zstd
|
||||
sudo dnf install binutils coreutils curl tar zstd
|
||||
```
|
||||
|
||||
Run `box64-bundle-x86-libs.sh`. This will create two archives:
|
||||
@@ -25,7 +30,7 @@ Run `box64-bundle-x86-libs.sh`. This will create two archives:
|
||||
Extract the library archive. Box will automatically search these paths for library files to emulate.
|
||||
|
||||
```
|
||||
sudo tar --extract --file box64-bundle-x86-libs.tar.gz --directory /
|
||||
sudo tar --extract --no-same-owner --file box64-bundle-x86-libs.tar.gz --directory /
|
||||
```
|
||||
|
||||
### Developer
|
||||
@@ -45,9 +50,9 @@ Preference of operating system packages that provide a library:
|
||||
4. XBPS from Void Linux provide updated variants of obscure 32-bit libraries.
|
||||
5. Other (whereever a library is packaged)
|
||||
|
||||
Some essential library files will never be emulated (only wrapped) and should not be bundled. This includes glibc, OpenGL, Vulkan, and X11/Xorg libraries. The full list can be found [here](https://github.com/ptitSeb/box64/blob/v0.3.2/src/librarian/library.c#L427). Other libraries with lots of dependencies, such as GTK, require all dependencies to be installed for emulation to work. This becomes dependency hell and should be avoided.
|
||||
Some essential library files will never be emulated (only wrapped) and should not be bundled. This includes glibc, OpenGL, Vulkan, and X11/Xorg libraries. The full list can be found [in the library source code](https://github.com/ptitSeb/box64/blob/v0.3.6/src/librarian/library.c#L433). Other libraries with lots of dependencies, such as GTK, require all dependencies to be installed for emulation to work. This becomes dependency hell and should be avoided.
|
||||
|
||||
For finding package names that contian a specific library file, use the [pkgs.org](https://pkgs.org/) website. Otherwise, use one of these package manager commands on a x86_64 Linux distribution:
|
||||
For finding package names that contian a specific library file, use the [pkgs.org website](https://pkgs.org/). Otherwise, use one of these package manager commands on a x86_64 Linux distribution:
|
||||
- DEB
|
||||
- `apt-file <LIBRARY_FILE>`
|
||||
- EOPKG
|
||||
@@ -70,4 +75,4 @@ Once the package name is found, find the exact URL for downloading it.
|
||||
|
||||
Download the package and then find the checksum with the `sha256sum` command.
|
||||
|
||||
Major Linux distributions such as AlmaLinux and Debian provide archives of packages. Rolling distributions such as Solus and Void Linux do not. In those cases, use the [Internet Archive](https://web.archive.org/) to archive any rolling release package used by Box by using the "Save Page Now" feature. If the error "Save Page Now browser crashed" appears, it can be safely ignored. The archive will still have been saved.
|
||||
Major Linux distributions such as AlmaLinux and Debian provide archives of packages. Most rolling distributions such as Solus and Void Linux do not (one exception is Arch Linux which has the [Arch Linux Archive (ALA)](https://wiki.archlinux.org/title/Arch_Linux_Archive)). In those cases, use the [Internet Archive](https://web.archive.org/) to archive any rolling release package used by Box by using the "Save Page Now" feature. If the error "Save Page Now browser crashed" appears, it can be safely ignored. The archive will still have been saved.
|
||||
@@ -1,3 +1,48 @@
|
||||
v0.3.8
|
||||
======
|
||||
|
||||
Highlights:
|
||||
|
||||
* This version introduce DynaCache, a disk cache for the generated native code. It's not enabled by default for now (but it will use cache file if present by default). It can dramaticaly speedup the load of program (try with linux factorio for example). This version also improve in the volatile metadata handling. There is a massive compatiblity improvment for box32 and on all dynarec in general too. And few more function wrapping...
|
||||
|
||||
=> DynaCache for faster loading of program, and avoid runtime hicups
|
||||
=> Batter box32 compatibility (much less "Out of Memory" error)
|
||||
=> Unity3D games on Wayland are working now
|
||||
=> Volatile Metadata fully supported and handled, making games like Starfield to just work.
|
||||
=> More work on AVX support for RV64 & LA64. LA64 almost there, while RV64 has Scalar only support (no hardware vector support yet for AVX)
|
||||
|
||||
Version summary:
|
||||
|
||||
* Improved and fixed memory tracking
|
||||
* Improved volatile metadata handling, and some light refactor on StrongMem emulation
|
||||
* Improved handling of TF flag
|
||||
* DynaCache: Introducing a way to cache on disk native generated code for faster startup time on subsequent release
|
||||
* DynaCache: Support for all 3 backends ARM64, RV64 & LA64
|
||||
* Interpreter: refactor opcodes decoding to have prefixes handled in a generic way
|
||||
* Interpreter: many small fixes
|
||||
* Dynarec: some optimisations in the jump table, to remove one memory fetch on each jump
|
||||
* Dynarec: create infrastructure to be able to change easily the reg mapping
|
||||
* Dynarec: optimised defered flag handling to limit cases where UpdateFlags is needed
|
||||
* Dynarec: Introduced BOX64_DYNAREC_NOHOTPAGE to disable detection of hotpages
|
||||
* Dynarec: ARM64: A few more opcode added
|
||||
* Dynarec: ARM64: Some small fixes and better handling of undefined behavior in opcodes, as well as undefined opcodes
|
||||
* Dynarec: ARM64: Implemented a Dynarec version of UpdateFlags, for improved performances
|
||||
* Dynarec; ARM64: Fixes/Improved SSE_FLUSHTO0 support
|
||||
* Dynarec: LA64: Added support for AVX (& friends) opcodes. Still need some debugging so AVX still disabled by default on LA64
|
||||
* Dynarec: LA64: Changed register mapping to be closer to the x86_64 ABI
|
||||
* Dynarec: LA64: RV64: Added limited support to SSE_FLUSHTO0
|
||||
* Dynarec: RV64: Many fixes and improvments for MMX opcodes
|
||||
* Dynarec: RV64: many Scalar version of AVX opcodes added
|
||||
* Dynarec: Many fixes to various OpCodes, on all 3 backends
|
||||
* WowBox64: Added minimal runtime, improved overall stability
|
||||
* BOX32: Wrapper: many new functions added, plus many fixes
|
||||
* BOX32: Improved memory hadnling, using 32bits personality and other tunning to get more reliable 32bits memory allocations
|
||||
* BOX64: Wrapper: some more wrapped functions added, including wayland (for Unity games on Wayland) and vulkan (more extensions)
|
||||
* BOX64: Wrapper: improved handling of some VarArg wrapped functions on non-ARM64 backend
|
||||
* RCFILE: Fixed MAXCPU not working properly with Wine programs
|
||||
* RCFILE: Generic Setup profile refined, and more games profile added
|
||||
* Trace: Added support for current libZydis
|
||||
|
||||
v0.3.6
|
||||
======
|
||||
|
||||
|
||||
+20
-7
@@ -1,11 +1,11 @@
|
||||
Compiling/Installing
|
||||
----
|
||||
|
||||
If you don't want to compile box64 yourself and prefer to use third-party pre-build version, go to the [end of the document](#pre-build-packages) for alternatives.
|
||||
If you don't want to compile box64 yourself and prefer to use third-party pre-build version, go to the [end of the document](#pre-built-packages) for alternatives.
|
||||
|
||||
You can also generate your own package using the [instructions below](https://github.com/ptitSeb/box64/blob/main/docs/COMPILE.md#debian-packaging).
|
||||
|
||||
Additional installation steps may be necessary when copying only the box64 executable file without running make install in cross-build environments. See [Cross-compiling](https://github.com/ptitSeb/box64/blob/main/docs/COMPILE.md#Cross-compiling)
|
||||
Additional installation steps may be necessary when copying only the box64 executable file without running make install in cross-build environments. See [Cross-Compiling](https://github.com/ptitSeb/box64/blob/main/docs/COMPILE.md#Cross-Compiling)
|
||||
|
||||
## Per-platform compiling instructions
|
||||
|
||||
@@ -260,7 +260,7 @@ Add `-DCMAKE_BUILD_TYPE=RelWithDebInfo` option for an optimized build with debug
|
||||
|
||||
#### Build with trace
|
||||
|
||||
To have a trace enabled build (***the interpreter will be slightly slower***), add `-DHAVE_TRACE=1`. You will need the [Zydis library](https://github.com/zyantific/zydis) in your `LD_LIBRARY_PATH` or in the system library folders at runtime to get x86 trace. Use version v3.2.1, as later versions have changed the API and no longer work with box64.
|
||||
To have a trace enabled build (***the interpreter will be slightly slower***), add `-DHAVE_TRACE=1`. You will need the [Zydis library](https://github.com/zyantific/zydis) devel package installed (`apt install libzydis-dev` on Debian for example).
|
||||
|
||||
#### Build DynaRec
|
||||
|
||||
@@ -334,7 +334,7 @@ sudo apt update
|
||||
sudo apt install box64-generic-arm -y
|
||||
```
|
||||
|
||||
## Cross-compiling
|
||||
## Cross-Compiling
|
||||
----
|
||||
### Set Up the Cross-Compiler
|
||||
For example, to compile Box64 for RISC-V on an x86 machine, you can get prebuilt GNU toolchain from the [riscv-gnu-toolchain](https://github.com/riscv-collab/riscv-gnu-toolchain/releases)
|
||||
@@ -346,6 +346,9 @@ In particular, you must specify the cross-compiler. For example:
|
||||
-DCMAKE_C_COMPILER=riscv64-unknown-linux-gnu-gcc # Or whichever cross-compiler you use
|
||||
```
|
||||
|
||||
Be aware of potential glibc capability errors when choosing a cross-compiler.
|
||||
To avoid this, run `ldd --version` on your target machine to check its glibc version.
|
||||
|
||||
### Running tests with QEMU (optional)
|
||||
To do a quick check, run:
|
||||
```
|
||||
@@ -361,6 +364,16 @@ ctest -j$(nproc)
|
||||
### Installing on the Target Machine
|
||||
After successfully cross-compiling, copy the box64 executable to your RISC-V device. Note that simply copying the binary does not automatically install Box64’s shared libraries. Because `make install` does not run on the target during cross-compilation, libraries required for emulation may be missing.
|
||||
|
||||
To fix this, copy the shared libraries folder from the Box64 repository (`x64lib` or `x86lib`) to your target. Place them into the proper library search paths, for example:
|
||||
- `/usr/lib/box64-x86_64-linux-gnu/` (for x86_64)
|
||||
- `/usr/lib/box64-i386-linux-gnu/` (for i386)
|
||||
To resolve this, copy the shared libraries folder from the Box64 repository (`x64lib` or `x86lib`) to your target device, then rename it and place it in the appropriate library search path (e.g., `/usr/lib`).
|
||||
|
||||
For `x86_64`:
|
||||
```shell
|
||||
$ mv x64lib box64-x86_64-linux-gnu
|
||||
$ mv box64-x86_64-linux-gnu /usr/lib
|
||||
```
|
||||
For `i386`:
|
||||
```shell
|
||||
$ mv x86lib box64-i386-linux-gnu
|
||||
$ mv box64-i386-linux-gnu /usr/lib
|
||||
```
|
||||
|
||||
+179
-149
@@ -43,6 +43,180 @@ This configuration will apply the specified settings application-wide to any exe
|
||||
|
||||
----
|
||||
|
||||
## Performance
|
||||
|
||||
### BOX64_DYNAREC
|
||||
|
||||
Enable/disable the Dynamic Recompiler (a.k.a DynaRec). This option defaults to 1 if it's enabled in the build options for a supported architecture. Availble in WowBox64.
|
||||
|
||||
* 0: Disable DynaRec.
|
||||
* 1: Enable DynaRec.
|
||||
|
||||
### BOX64_DYNAREC_ALIGNED_ATOMICS
|
||||
|
||||
Generate aligned atomics only (only available on Arm64 for now). Availble in WowBox64.
|
||||
|
||||
* 0: Generate unaligned atomics handling code. [Default]
|
||||
* 1: Generate aligned atomics only, which is faster and smaller code size, but will cause SIGBUS for LOCK prefixed opcodes operating on unaligned data addresses.
|
||||
|
||||
### BOX64_DYNAREC_BIGBLOCK
|
||||
|
||||
Enable building bigger DynaRec code blocks for better performance. Availble in WowBox64.
|
||||
|
||||
* 0: Do not try to build block as big as possible, suitable for programs using lots of threads and JIT, like Unity.
|
||||
* 1: Build Dynarec block as big as possible.
|
||||
* 2: Build Dynarec block bigger, do not stop when block overlaps, but only for blocks in elf memory. [Default]
|
||||
* 3: Build Dynarec block bigger, do not stop when block overlaps, for all type of memory, useful for wine programs.
|
||||
|
||||
### BOX64_DYNAREC_CALLRET
|
||||
|
||||
Optimize CALL/RET opcodes. Availble in WowBox64.
|
||||
|
||||
* 0: Do not optimize CALL/RET, use jump table. [Default]
|
||||
* 1: Try to optimize CALL/RET, skipping the jump table when possible.
|
||||
* 2: Try to optimize CALL/RET, skipping the jump table when possible, adding code to handle return to dirty/modified block. Does not work on WowBox64.
|
||||
|
||||
### BOX64_DYNAREC_DF
|
||||
|
||||
Enable or disable the use of deferred flags. Availble in WowBox64.
|
||||
|
||||
* 0: Disable the use of deferred flags.
|
||||
* 1: Enable the use of deferred flags. [Default]
|
||||
|
||||
### BOX64_DYNAREC_DIRTY
|
||||
|
||||
Allow continue running a block that is unprotected and potentially dirty.
|
||||
|
||||
* 0: Do not allow continue running a block that is unprotected and potentially dirty. [Default]
|
||||
* 1: Allow continue to run a dynablock that write data in the same page as code. It can gets faster in loading time of some game but can also get unexpected crashes.
|
||||
* 2: Will also, when it detect an HotPage, flag that page as NEVERCLEAN, and so it will not be write protected but Block build from that page will always be tested. It can be faster that way (but soem SMC case might not be trapped).
|
||||
|
||||
### BOX64_DYNAREC_NOHOTPAGE
|
||||
|
||||
Disable detection of hot page (where code is executed and data written at the same time).
|
||||
|
||||
* 0: Detect hot page [Default]
|
||||
* 1: Do not detect hot page
|
||||
|
||||
### BOX64_DYNAREC_FASTNAN
|
||||
|
||||
Enable or disable fast NaN handling. Availble in WowBox64.
|
||||
|
||||
* 0: Precisely emulate the -NaN generation like on x86.
|
||||
* 1: Do not do anything special with -NAN generation, faster. [Default]
|
||||
|
||||
### BOX64_DYNAREC_FASTROUND
|
||||
|
||||
Enable or disable fast rounding. Availble in WowBox64.
|
||||
|
||||
* 0: Generate float/double -> int rounding and use current rounding mode for float/double computation like on x86.
|
||||
* 1: Do not do anything special with edge case rounding, faster. [Default]
|
||||
* 2: Generate float/double -> int rounding using current rounding mode for float/double computation like on x86, but use fast int -> float/double conversion.
|
||||
|
||||
### BOX64_DYNAREC_FORWARD
|
||||
|
||||
Define max allowed forward value when building block. Availble in WowBox64.
|
||||
|
||||
* 0: No forward value. When current block ends, do not try to go further even if there are previous forward jumps.
|
||||
* 128: Allow up to 128 bytes of gap between end of the block and the next forward jump. [Default]
|
||||
* XXXX: Allow up to XXXX bytes of gap between end of the block and the next forward jump.
|
||||
|
||||
### BOX64_DYNAREC_NATIVEFLAGS
|
||||
|
||||
Enable or disable the use of native flags. Availble in WowBox64.
|
||||
|
||||
* 0: Do not use native flags.
|
||||
* 1: Use native flags when possible. [Default]
|
||||
|
||||
### BOX64_DYNAREC_PAUSE
|
||||
|
||||
Enable x86 PAUSE emulation, may help the performance of spinlocks. Availble in WowBox64.
|
||||
|
||||
* 0: Ignore x86 PAUSE instruction. [Default]
|
||||
* 1: Use YIELD to emulate x86 PAUSE instruction.
|
||||
* 2: Use WFI to emulate x86 PAUSE instruction.
|
||||
* 3: Use SEVL+WFE to emulate x86 PAUSE instruction.
|
||||
|
||||
### BOX64_DYNAREC_SAFEFLAGS
|
||||
|
||||
Behaviour of flags emulation on CALL/RET opcodes and other edge cases. Availble in WowBox64.
|
||||
|
||||
* 0: Treat CALL/RET as if it never needs any flags.
|
||||
* 1: Most of RETs will need flags, most of CALLs will not. [Default]
|
||||
* 2: All CALL/RET will need flags. All edge cases are also handled.
|
||||
|
||||
### BOX64_DYNAREC_STRONGMEM
|
||||
|
||||
Enable the emulation of x86 strong memory model. Availble in WowBox64.
|
||||
|
||||
* 0: Do not try anything special. [Default]
|
||||
* 1: Enable some memory barriers when writing to memory to emulate the x86 strong memory model in a limited way.
|
||||
* 2: All in 1, plus memory barriers on SIMD instructions.
|
||||
* 3: All in 2, plus more memory barriers on a regular basis.
|
||||
|
||||
### BOX64_DYNAREC_VOLATILE_METADATA
|
||||
|
||||
Use volatile metadata parsed from PE files, only valid for 64bit Windows games.
|
||||
|
||||
* 0: Do not use volatile metadata.
|
||||
* 1: Use volatile metadata, which will guide Box64 for better strong memory emulation. [Default]
|
||||
|
||||
### BOX64_DYNAREC_WAIT
|
||||
|
||||
Wait or not for the building of a DynaRec code block to be ready. Availble in WowBox64.
|
||||
|
||||
* 0: Do not wait and use interpreter instead, might speedup a bit on massive multithread or JIT programs.
|
||||
* 1: Wait for a DynaRec code block to be ready. [Default]
|
||||
|
||||
### BOX64_DYNAREC_WEAKBARRIER
|
||||
|
||||
Tweak the memory barriers to reduce the performance impact by strong memory emualtion. Availble in WowBox64.
|
||||
|
||||
* 0: Use regular safe barrier.
|
||||
* 1: Use weak barriers to have more performance boost. [Default]
|
||||
* 2: All in 1, plus disabled the last write barriers.
|
||||
|
||||
### BOX64_DYNACACHE
|
||||
|
||||
Enable/disable the Dynamic Recompiler Cache (a.k.a DynaCache). This option defaults to 2 (to read cache if present but not generate any). DynaCache write file to home folder by default, and can grow without limit.
|
||||
|
||||
* 0: Disable DynaCache.
|
||||
* 1: Enable DynaCache.
|
||||
* 2: Use DynaCache files if present, but do not generate new one. [Default]
|
||||
|
||||
### BOX64_DYNACACHE_FOLDER
|
||||
|
||||
Set the folder for DynaCache files. Default is $XDG_CACHE_HOME/box64 or $HOME/.cache/box64 if $XDG_CACHE_HOME is not set.
|
||||
|
||||
* XXXX: Use folder XXXX for DynaCache files.
|
||||
|
||||
### BOX64_DYNACACHE_MIN
|
||||
|
||||
Minimum size, in KB, for a DynaCache to be written to disk. Default size is 350KB
|
||||
|
||||
* XXXX: Set a minimum size of XXXX KB of Dynarec code to write the dynacache to disk. Will not be saved to disk else.
|
||||
* 350: A size of 350 KB is the default value. [Default]
|
||||
|
||||
### BOX64_MMAP32
|
||||
|
||||
Force 32-bit compatible memory mappings on 64-bit programs that run 32-bit code (like Wine WOW64), can improve performance.
|
||||
|
||||
* 0: Do not force 32-bit memory mappings.
|
||||
* 1: Force 32-bit memory mappings. [Default]
|
||||
|
||||
### BOX64_NODYNAREC
|
||||
|
||||
Forbid dynablock creation in the address range specified, helpful for debugging behaviour difference between Dynarec and Interpreter. Availble in WowBox64.
|
||||
|
||||
* 0xXXXXXXXX-0xYYYYYYYY: Define the range where dynablock creation is forbidden (inclusive-exclusive).
|
||||
|
||||
### BOX64_RDTSC_1GHZ
|
||||
|
||||
Use hardware counter for rdtsc if available.
|
||||
|
||||
* 0: Use hardware counter for rdtsc opcode if available. [Default]
|
||||
* 1: Use hardware counter for rdtsc if and only if precision is at least 1GHz.
|
||||
|
||||
## Libraries
|
||||
|
||||
### BOX64_ADDLIBS
|
||||
@@ -213,7 +387,7 @@ Detect MonoBleedingEdge and apply conservative settings.
|
||||
|
||||
Enable or disable the generation of division-by-zero exception. Availble in WowBox64.
|
||||
|
||||
* 0: Do not generate thr division-by-zero exception. [Default]
|
||||
* 0: Do not generate the division-by-zero exception. [Default]
|
||||
* 1: Generate the division-by-zero exception.
|
||||
|
||||
### BOX64_DYNAREC_TBB
|
||||
@@ -323,10 +497,10 @@ Expose SHAEXT (a.k.a. SHA_NI) capabilities.
|
||||
|
||||
### BOX64_SSE_FLUSHTO0
|
||||
|
||||
Behaviour of SSE Flush to 0 flags. Availble in WowBox64.
|
||||
Behaviour of SSE Flush to 0 flags. Also tracking SSE exception flags Availble in WowBox64.
|
||||
|
||||
* 0: Just track the flag. [Default]
|
||||
* 1: Apply SSE Flush to 0 flag directly.
|
||||
* 1: Apply SSE Flush to 0 flag directly. Also reflect SSE exception flags in Dynarec (if available)
|
||||
|
||||
### BOX64_SSE42
|
||||
|
||||
@@ -551,6 +725,8 @@ Same as BOX64_TRACE but starts the trace immediately.
|
||||
|
||||
* 0: Disable trace output. [Default]
|
||||
* 1: Enable trace output. Trace starts before the initialization of dependencies.
|
||||
* symbolname: Enable trace output for `symbolname` only. Trace starts before the initialization of dependencies.
|
||||
* 0xXXXXXXX-0xYYYYYYY: Enable trace output for the range of address (inclusive-exclusive). Trace starts before the initialization of dependencies.
|
||||
|
||||
### BOX64_TRACE_START
|
||||
|
||||
@@ -576,152 +752,6 @@ Only available on box64 build with trace. Adds trace of all instructions execute
|
||||
* symbolname: Enable trace output for `symbolname` only.
|
||||
* 0xXXXXXXX-0xYYYYYYY: Enable trace output for the range of address (inclusive-exclusive).
|
||||
|
||||
## Performance
|
||||
|
||||
### BOX64_DYNAREC
|
||||
|
||||
Enable/disable the Dynamic Recompiler (a.k.a DynaRec). This option defaults to 1 if it's enabled in the build options for a supported architecture. Availble in WowBox64.
|
||||
|
||||
* 0: Disable DynaRec.
|
||||
* 1: Enable DynaRec.
|
||||
|
||||
### BOX64_DYNAREC_ALIGNED_ATOMICS
|
||||
|
||||
Generate aligned atomics only (only available on Arm64 for now). Availble in WowBox64.
|
||||
|
||||
* 0: Generate unaligned atomics handling code. [Default]
|
||||
* 1: Generate aligned atomics only, which is faster and smaller code size, but will cause SIGBUS for LOCK prefixed opcodes operating on aligned data addresses.
|
||||
|
||||
### BOX64_DYNAREC_BIGBLOCK
|
||||
|
||||
Enable building bigger DynaRec code blocks for better performance. Availble in WowBox64.
|
||||
|
||||
* 0: Do not try to build block as big as possible, suitable for programs using lots of threads and JIT, like Unity.
|
||||
* 1: Build Dynarec block as big as possible.
|
||||
* 2: Build Dynarec block bigger, do not stop when block overlaps, but only for blocks in elf memory. [Default]
|
||||
* 3: Build Dynarec block bigger, do not stop when block overlaps, for all type of memory, useful for wine programs.
|
||||
|
||||
### BOX64_DYNAREC_CALLRET
|
||||
|
||||
Optimize CALL/RET opcodes. Availble in WowBox64.
|
||||
|
||||
* 0: Do not optimize CALL/RET, use jump table. [Default]
|
||||
* 1: Try to optimize CALL/RET, skipping the jump table when possible.
|
||||
* 2: Try to optimize CALL/RET, skipping the jump table when possible, adding code to handle return to dirty/modified block. Does not work on WowBox64.
|
||||
|
||||
### BOX64_DYNAREC_DF
|
||||
|
||||
Enable or disable the use of deferred flags. Availble in WowBox64.
|
||||
|
||||
* 0: Disable the use of deferred flags.
|
||||
* 1: Enable the use of deferred flags. [Default]
|
||||
|
||||
### BOX64_DYNAREC_DIRTY
|
||||
|
||||
Allow continue running a block that is unprotected and potentially dirty.
|
||||
|
||||
* 0: Do not allow continue running a block that is unprotected and potentially dirty. [Default]
|
||||
* 1: Allow continue to run a dynablock that write data in the same page as code. It can gets faster in loading time of some game but can also get unexpected crashes.
|
||||
* 2: Will also, when it detect an HotPage, flag that page as NEVERCLEAN, and so it will not be write protected but Block build from that page will always be tested. It can be faster that way (but soem SMC case might not be trapped).
|
||||
|
||||
### BOX64_DYNAREC_FASTNAN
|
||||
|
||||
Enable or disable fast NaN handling. Availble in WowBox64.
|
||||
|
||||
* 0: Precisely emulate the -NaN generation like on x86.
|
||||
* 1: Do not do anything special with -NAN generation, faster. [Default]
|
||||
|
||||
### BOX64_DYNAREC_FASTROUND
|
||||
|
||||
Enable or disable fast rounding. Availble in WowBox64.
|
||||
|
||||
* 0: Generate float/double -> int rounding and use current rounding mode for float/double computation like on x86.
|
||||
* 1: Do not do anything special with edge case rounding, faster. [Default]
|
||||
* 2: Generate float/double -> int rounding using current rounding mode for float/double computation like on x86, but use fast int -> float/double conversion.
|
||||
|
||||
### BOX64_DYNAREC_FORWARD
|
||||
|
||||
Define max allowed forward value when building block. Availble in WowBox64.
|
||||
|
||||
* 0: No forward value. When current block ends, do not try to go further even if there are previous forward jumps.
|
||||
* 128: Allow up to 128 bytes of gap between end of the block and the next forward jump. [Default]
|
||||
* XXXX: Allow up to XXXX bytes of gap between end of the block and the next forward jump.
|
||||
|
||||
### BOX64_DYNAREC_NATIVEFLAGS
|
||||
|
||||
Enable or disable the use of native flags. Availble in WowBox64.
|
||||
|
||||
* 0: Do not use native flags.
|
||||
* 1: Use native flags when possible. [Default]
|
||||
|
||||
### BOX64_DYNAREC_PAUSE
|
||||
|
||||
Enable x86 PAUSE emulation, may help the performance of spinlocks. Availble in WowBox64.
|
||||
|
||||
* 0: Ignore x86 PAUSE instruction. [Default]
|
||||
* 1: Use YIELD to emulate x86 PAUSE instruction.
|
||||
* 2: Use WFI to emulate x86 PAUSE instruction.
|
||||
* 3: Use SEVL+WFE to emulate x86 PAUSE instruction.
|
||||
|
||||
### BOX64_DYNAREC_SAFEFLAGS
|
||||
|
||||
Behaviour of flags emulation on CALL/RET opcodes. Availble in WowBox64.
|
||||
|
||||
* 0: Treat CALL/RET as if it never needs any flags.
|
||||
* 1: Most of RETs will need flags, most of CALLs will not. [Default]
|
||||
* 2: All CALL/RET will need flags.
|
||||
|
||||
### BOX64_DYNAREC_STRONGMEM
|
||||
|
||||
Enable the emulation of x86 strong memory model. Availble in WowBox64.
|
||||
|
||||
* 0: Do not try anything special. [Default]
|
||||
* 1: Enable some memory barriers when writing to memory to emulate the x86 strong memory model in a limited way.
|
||||
* 2: All in 1, plus memory barriers on SIMD instructions.
|
||||
* 3: All in 2, plus more memory barriers on a regular basis.
|
||||
|
||||
### BOX64_DYNAREC_VOLATILE_METADATA
|
||||
|
||||
Use volatile metadata parsed from PE files, only valid for 64bit Windows games.
|
||||
|
||||
* 0: Do not use volatile metadata.
|
||||
* 1: Use volatile metadata, which will guide Box64 for better strong memory emulation. [Default]
|
||||
|
||||
### BOX64_DYNAREC_WAIT
|
||||
|
||||
Wait or not for the building of a DynaRec code block to be ready. Availble in WowBox64.
|
||||
|
||||
* 0: Do not wait and use interpreter instead, might speedup a bit on massive multithread or JIT programs.
|
||||
* 1: Wait for a DynaRec code block to be ready. [Default]
|
||||
|
||||
### BOX64_DYNAREC_WEAKBARRIER
|
||||
|
||||
Tweak the memory barriers to reduce the performance impact by strong memory emualtion. Availble in WowBox64.
|
||||
|
||||
* 0: Use regular safe barrier.
|
||||
* 1: Use weak barriers to have more performance boost. [Default]
|
||||
* 2: All in 1, plus disabled the last write barriers.
|
||||
|
||||
### BOX64_MMAP32
|
||||
|
||||
Force 32-bit compatible memory mappings on 64-bit programs that run 32-bit code (like Wine WOW64), can improve performance.
|
||||
|
||||
* 0: Do not force 32-bit memory mappings.
|
||||
* 1: Force 32-bit memory mappings. [Default]
|
||||
|
||||
### BOX64_NODYNAREC
|
||||
|
||||
Forbid dynablock creation in the address range specified, helpful for debugging behaviour difference between Dynarec and Interpreter. Availble in WowBox64.
|
||||
|
||||
* 0xXXXXXXXX-0xYYYYYYYY: Define the range where dynablock creation is forbidden (inclusive-exclusive).
|
||||
|
||||
### BOX64_RDTSC_1GHZ
|
||||
|
||||
Use hardware counter for rdtsc if available.
|
||||
|
||||
* 0: Use hardware counter for rdtsc opcode if available. [Default]
|
||||
* 1: Use hardware counter for rdtsc if and only if precision is at least 1GHz.
|
||||
|
||||
## Environment
|
||||
|
||||
### BOX64_ENV
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
# The guide on using Wine with Box64
|
||||
|
||||
<ins>W</ins>ine <ins>I</ins>s <ins>N</ins>ot an <ins>E</ins>mulator, but Box64 is. Box64 supports Wine in multiple ways. Before continuing reading, you should have a basic understanding of Wine.
|
||||
|
||||
## Wine variants
|
||||
|
||||
Wine ships in multiple forms:
|
||||
|
||||
|
||||
1. **x86 Wine**
|
||||
|
||||
The executable architecture of **x86 Wine** is x86, and it runs x32 Windows executables.
|
||||
|
||||
**x86 Wine** requires a 32-bit environment (read 32-bit Linux libraries), which is usually available on x86_64 machines because of the nature of the architecture.
|
||||
|
||||
However, when you try to run it via an emulator on RISC architectures, the situation is a bit different. For Arm64, there is armhf, which is a 32-bit environment, and there is also Box86, which is made for armhf, so you can use Box86 to run **x86 Wine**.
|
||||
|
||||
However, for RISC-V 64, LoongArch64, and many newer Arm64 cores, a 32-bit environment is not available. Box64 introduced a new mode called Box32, which can be enabled at compile time via a CMake option `BOX32`. It essentially emulates a 32-bit environment using the 64-bit environment, so it can be used to run **x86 Wine**. But be aware that Box32 is still highly experimental and unstable.
|
||||
|
||||
2. **x86_64 Wine**
|
||||
|
||||
The executable architecture of **x86_64 Wine** is x86_64, and it runs x64 Windows executables.
|
||||
|
||||
It can be used with Box64. Note that **x86_64 Wine** usually ships with **x86 Wine** included. So you can use a combination of Box86 + Box64 or Box64 alone with Box32 enabled to run both x32 and x64 executables seamlessly.
|
||||
|
||||
3. **x86_64 Wine WOW64**
|
||||
|
||||
The executable architecture of **x86_64 Wine WOW64** is x86_64, and it runs both x32 and x64 Windows executables.
|
||||
|
||||
What's great about **x86_64 Wine WOW64** is that it does not require a 32-bit environment for x32 Windows executable, as the 32-bit environment emulation is taken care of by Wine WOW64 itself.
|
||||
|
||||
That means you can just use Box64 (without Box32) to run x32 Windows executables. However, the downside is that the performance of WineD3D is pretty bad for 32-bit (use DXVK!).
|
||||
|
||||
4. **Arm64 Wine WOW64**
|
||||
|
||||
The executable architecture of **Arm64 Wine WOW64** is Arm64, and it runs
|
||||
x32, x64, Arm32, Arm64 Windows executables.
|
||||
|
||||
However, to run x32 and x64 ones, a cpu.dll is required, known as the
|
||||
WOW64 (for 32-bit) and Arm64EC (for 64-bit).
|
||||
|
||||
Box64 now supports 32-bit WOW64 DLL. You can have it compiled by enabling the `WOW64` CMake option. And we plan to support Arm64EC in the future.
|
||||
|
||||
## Wine installation
|
||||
|
||||
For x86 Wines, there are plenty of places to download, to name a few:
|
||||
|
||||
- https://github.com/Kron4ek/Wine-Builds (Wine \[WOW64\])
|
||||
- https://github.com/GloriousEggroll/proton-ge-custom (Proton, known as the Valve-optimized Wine)
|
||||
|
||||
After the download, just add the `bin` folder to your path in any way you like; Wine should work with Box64 just fine.
|
||||
|
||||
To install components like DXVK, d3dcompiler_xx, or cjkfonts, it's recommended to use Winetricks: https://github.com/Winetricks/winetricks
|
||||
|
||||
For Arm64 Wines, use of Hangover is recommended: https://github.com/AndreRH/hangover.
|
||||
-177
@@ -1,177 +0,0 @@
|
||||
# Installing Wine64
|
||||
Running Wine64/Wine with Box64/Box86 allows x64/x86 Windows programs to run on 64-bit ARM Linux devices.
|
||||
- Box64 needs `wine-amd64` to be installed **manually** on ARM64 (aarch64) devices. This will run 64-bit Windows programs (aka x86_64).
|
||||
- Box86 needs `wine-i386` to be installed **manually** on ARM32 (armhf) devices (or on ARM64 with multiarch or chroot). This will run 32-bit Windows programs (aka x86).
|
||||
- _Note that `wine:arm64` and `wine:armhf` will not work with Box64/Box86. Your device's package manager might try to install those if you ask it to install wine._
|
||||
|
||||
See installation steps below (in the [Examples](#examples) section).
|
||||
|
||||
## Overview
|
||||
The general procedure for installing Wine64 & Wine for Box64 & Box86 is to...
|
||||
- Download all the install files for the version of Wine you wish to install
|
||||
- Unzip or dpkg the install files into one folder
|
||||
- Move that folder to the directory that you wish Wine to run from (often `~/wine/` by default)
|
||||
- Go to `/usr/local/bin` and make symlinks or scripts that will point to your main wine binaries.
|
||||
- Boot wine to create a new wineprefix.
|
||||
- Download winetricks (which is just a complicated bash script), make it executable, then copy it to `/usr/local/bin`.
|
||||
|
||||
## Examples
|
||||
### Installing Wine64 & Wine for Box64 & Box86 on Raspberry Pi OS from WineHQ .deb files
|
||||
_Links from the [WineHQ repo](https://dl.winehq.org/wine-builds/debian/dists/)_
|
||||
|
||||
This install method allows you to install different versions of Wine64/Wine. You may install any version/branch of Wine that you wish.
|
||||
```
|
||||
# NOTE: Can only run on aarch64 (since box64 can only run on aarch64)
|
||||
# box64 runs wine-amd64, box86 runs wine-i386.
|
||||
|
||||
### User-defined Wine version variables ################
|
||||
# - Replace the variables below with your system's info.
|
||||
# - Note that we need the amd64 version for Box64 even though we're installing it on our ARM processor.
|
||||
# - Note that we need the i386 version for Box86 even though we're installing it on our ARM processor.
|
||||
# - Wine download links from WineHQ: https://dl.winehq.org/wine-builds/
|
||||
|
||||
local branch="devel" #example: devel, staging, or stable (wine-staging 4.5+ requires libfaudio0:i386)
|
||||
local version="7.1" #example: "7.1"
|
||||
local id="debian" #example: debian, ubuntu
|
||||
local dist="bullseye" #example (for debian): bullseye, buster, jessie, wheezy, ${VERSION_CODENAME}, etc
|
||||
local tag="-1" #example: -1 (some wine .deb files have -1 tag on the end and some don't)
|
||||
|
||||
########################################################
|
||||
|
||||
# Clean up any old wine instances
|
||||
wineserver -k # stop any old wine installations from running
|
||||
rm -rf ~/.cache/wine # remove any old wine-mono/wine-gecko install files
|
||||
rm -rf ~/.local/share/applications/wine # remove any old program shortcuts
|
||||
|
||||
# Backup any old wine installs
|
||||
rm -rf ~/wine-old 2>/dev/null; mv ~/wine ~/wine-old 2>/dev/null
|
||||
rm -rf ~/.wine-old 2>/dev/null; mv ~/.wine ~/.wine-old 2>/dev/null
|
||||
sudo mv /usr/local/bin/wine /usr/local/bin/wine-old 2>/dev/null
|
||||
sudo mv /usr/local/bin/wine64 /usr/local/bin/wine-old 2>/dev/null
|
||||
sudo mv /usr/local/bin/wineboot /usr/local/bin/wineboot-old 2>/dev/null
|
||||
sudo mv /usr/local/bin/winecfg /usr/local/bin/winecfg-old 2>/dev/null
|
||||
sudo mv /usr/local/bin/wineserver /usr/local/bin/wineserver-old 2>/dev/null
|
||||
|
||||
# Wine download links from WineHQ: https://dl.winehq.org/wine-builds/
|
||||
LNKA="https://dl.winehq.org/wine-builds/${id}/dists/${dist}/main/binary-amd64/" #amd64-wine links
|
||||
DEB_A1="wine-${branch}-amd64_${version}~${dist}${tag}_amd64.deb" #wine64 main bin
|
||||
DEB_A2="wine-${branch}_${version}~${dist}${tag}_amd64.deb" #wine64 support files (required for wine64 / can work alongside wine_i386 main bin)
|
||||
#DEB_A3="winehq-${branch}_${version}~${dist}${tag}_amd64.deb" #shortcuts & docs
|
||||
LNKB="https://dl.winehq.org/wine-builds/${id}/dists/${dist}/main/binary-i386/" #i386-wine links
|
||||
DEB_B1="wine-${branch}-i386_${version}~${dist}${tag}_i386.deb" #wine_i386 main bin
|
||||
DEB_B2="wine-${branch}_${version}~${dist}${tag}_i386.deb" #wine_i386 support files (required for wine_i386 if no wine64 / CONFLICTS WITH wine64 support files)
|
||||
#DEB_B3="winehq-${branch}_${version}~${dist}${tag}_i386.deb" #shortcuts & docs
|
||||
|
||||
# Install amd64-wine (64-bit) alongside i386-wine (32-bit)
|
||||
echo -e "Downloading wine . . ."
|
||||
wget -q ${LNKA}${DEB_A1}
|
||||
wget -q ${LNKA}${DEB_A2}
|
||||
wget -q ${LNKB}${DEB_B1}
|
||||
echo -e "Extracting wine . . ."
|
||||
dpkg-deb -x ${DEB_A1} wine-installer
|
||||
dpkg-deb -x ${DEB_A2} wine-installer
|
||||
dpkg-deb -x ${DEB_B1} wine-installer
|
||||
echo -e "Installing wine . . ."
|
||||
mv wine-installer/opt/wine* ~/wine
|
||||
|
||||
# Download wine dependencies
|
||||
# - these packages are needed for running box86/wine-i386 on a 64-bit RPiOS via multiarch
|
||||
sudo dpkg --add-architecture armhf && sudo apt-get update # enable multi-arch
|
||||
sudo apt-get install -y libasound2:armhf libc6:armhf libglib2.0-0:armhf libgphoto2-6:armhf libgphoto2-port12:armhf \
|
||||
libgstreamer-plugins-base1.0-0:armhf libgstreamer1.0-0:armhf libldap-2.4-2:armhf libopenal1:armhf libpcap0.8:armhf \
|
||||
libpulse0:armhf libsane1:armhf libudev1:armhf libusb-1.0-0:armhf libvkd3d1:armhf libx11-6:armhf libxext6:armhf \
|
||||
libasound2-plugins:armhf ocl-icd-libopencl1:armhf libncurses6:armhf libncurses5:armhf libcap2-bin:armhf libcups2:armhf \
|
||||
libdbus-1-3:armhf libfontconfig1:armhf libfreetype6:armhf libglu1-mesa:armhf libglu1:armhf libgnutls30:armhf \
|
||||
libgssapi-krb5-2:armhf libkrb5-3:armhf libodbc1:armhf libosmesa6:armhf libsdl2-2.0-0:armhf libv4l-0:armhf \
|
||||
libxcomposite1:armhf libxcursor1:armhf libxfixes3:armhf libxi6:armhf libxinerama1:armhf libxrandr2:armhf \
|
||||
libxrender1:armhf libxxf86vm1 libc6:armhf libcap2-bin:armhf # to run wine-i386 through box86:armhf on aarch64
|
||||
# This list found by downloading...
|
||||
# wget https://dl.winehq.org/wine-builds/debian/dists/bullseye/main/binary-i386/wine-devel-i386_7.1~bullseye-1_i386.deb
|
||||
# wget https://dl.winehq.org/wine-builds/debian/dists/bullseye/main/binary-i386/winehq-devel_7.1~bullseye-1_i386.deb
|
||||
# wget https://dl.winehq.org/wine-builds/debian/dists/bullseye/main/binary-i386/wine-devel_7.1~bullseye-1_i386.deb
|
||||
# then `dpkg-deb -I package.deb`. Read output, add `:armhf` to packages in dep list, then try installing them on Pi aarch64.
|
||||
|
||||
# - these packages are needed for running box64/wine-amd64 on RPiOS (box64 only runs on 64-bit OS's)
|
||||
sudo apt-get install -y libasound2:arm64 libc6:arm64 libglib2.0-0:arm64 libgphoto2-6:arm64 libgphoto2-port12:arm64 \
|
||||
libgstreamer-plugins-base1.0-0:arm64 libgstreamer1.0-0:arm64 libldap-2.4-2:arm64 libopenal1:arm64 libpcap0.8:arm64 \
|
||||
libpulse0:arm64 libsane1:arm64 libudev1:arm64 libunwind8:arm64 libusb-1.0-0:arm64 libvkd3d1:arm64 libx11-6:arm64 libxext6:arm64 \
|
||||
ocl-icd-libopencl1:arm64 libasound2-plugins:arm64 libncurses6:arm64 libncurses5:arm64 libcups2:arm64 \
|
||||
libdbus-1-3:arm64 libfontconfig1:arm64 libfreetype6:arm64 libglu1-mesa:arm64 libgnutls30:arm64 \
|
||||
libgssapi-krb5-2:arm64 libjpeg62-turbo:arm64 libkrb5-3:arm64 libodbc1:arm64 libosmesa6:arm64 libsdl2-2.0-0:arm64 libv4l-0:arm64 \
|
||||
libxcomposite1:arm64 libxcursor1:arm64 libxfixes3:arm64 libxi6:arm64 libxinerama1:arm64 libxrandr2:arm64 \
|
||||
libxrender1:arm64 libxxf86vm1:arm64 libc6:arm64 libcap2-bin:arm64
|
||||
# This list found by downloading...
|
||||
# wget https://dl.winehq.org/wine-builds/debian/dists/bullseye/main/binary-amd64/wine-devel_7.1~bullseye-1_amd64.deb
|
||||
# wget https://dl.winehq.org/wine-builds/debian/dists/bullseye/main/binary-amd64/wine-devel-amd64_7.1~bullseye-1_amd64.deb
|
||||
# then `dpkg-deb -I package.deb`. Read output, add `:arm64` to packages in dep list, then try installing them on Pi aarch64.
|
||||
|
||||
# These packages are needed for running wine-staging on RPiOS (Credits: chills340)
|
||||
sudo apt install libstb0 -y
|
||||
cd ~/Downloads
|
||||
wget -r -l1 -np -nd -A "libfaudio0_*~bpo10+1_i386.deb" http://ftp.us.debian.org/debian/pool/main/f/faudio/ # Download libfaudio i386 no matter its version number
|
||||
dpkg-deb -xv libfaudio0_*~bpo10+1_i386.deb libfaudio
|
||||
sudo cp -TRv libfaudio/usr/ /usr/
|
||||
rm libfaudio0_*~bpo10+1_i386.deb # clean up
|
||||
rm -rf libfaudio # clean up
|
||||
|
||||
# Install symlinks
|
||||
sudo ln -s ~/wine/bin/wine /usr/local/bin/wine
|
||||
sudo ln -s ~/wine/bin/wine64 /usr/local/bin/wine64
|
||||
sudo ln -s ~/wine/bin/wineboot /usr/local/bin/wineboot
|
||||
sudo ln -s ~/wine/bin/winecfg /usr/local/bin/winecfg
|
||||
sudo ln -s ~/wine/bin/wineserver /usr/local/bin/wineserver
|
||||
sudo chmod +x /usr/local/bin/wine /usr/local/bin/wine64 /usr/local/bin/wineboot /usr/local/bin/winecfg /usr/local/bin/wineserver
|
||||
```
|
||||
|
||||
## Installing winetricks
|
||||
Winetricks is a bash script which makes it easier to install & configure any desired Windows core system software packages which may be dependencies for certain Windows programs. You can either install it with `apt`, or manually using the steps below.
|
||||
|
||||
```
|
||||
sudo apt-get install cabextract -y # winetricks needs this installed
|
||||
sudo mv /usr/local/bin/winetricks /usr/local/bin/winetricks-old # Backup old winetricks
|
||||
cd ~/Downloads && wget https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks # Download
|
||||
sudo chmod +x winetricks && sudo mv winetricks /usr/local/bin/ # Install
|
||||
```
|
||||
|
||||
Whenever we run winetricks, we must tell Box86 to supress its info banner, otherwise winetricks will crash. Box86's info banner can be suppressed using the `BOX86_NOBANNER=1` environment variable before invoking winetricks (example: `BOX86_NOBANNER=1 winetricks`).
|
||||
|
||||
If `apt` installed a desktop menu shortcut for winetricks (or if you make your own desktop shortcut for winetricks) then you may need to edit that shortcut to include Box86's BOX86_NOBANNER=1 env var. With your favorite text editor, edit `/usr/share/applications/winetricks.desktop` and change `Exec=winetricks --gui` to `Exec=env BOX86_NOBANNER=1 winetricks --gui`.
|
||||
|
||||
## Example commands
|
||||
Creating a 64-bit wineprefix:
|
||||
`wine64 wineboot` or `wine wineboot` (wineprefix is created in `~/.wine/`)
|
||||
`WINEPREFIX="$HOME/prefix64" wine wineboot` (wineprefix is created in `~/prefix64/`) _Note: You will need to invoke `WINEPREFIX="$HOME/prefix64"` before every command to use this wineprefix._
|
||||
|
||||
Creating a 32-bit wineprefix:
|
||||
`WINEARCH=win32 wine wineboot` (wineprefix is created in `~/.wine/`)
|
||||
|
||||
Fore-quitting wine:
|
||||
`wineserver -k`
|
||||
|
||||
Running Wine Configuration:
|
||||
`winecfg`
|
||||
|
||||
Using winetricks:
|
||||
`winetricks -q corefonts vcrun2010 dotnet20sp1`
|
||||
_This command will silently install three packages in series: Windows core fonts, VC++ 2010 Runtimes, and .NET 2.0 SP1. `-q` is the "install silent/quiet" command._
|
||||
|
||||
Invoking Box86's logging features (with `BOX86_LOG=1` or similar) will cause winetricks to crash.
|
||||
|
||||
For a list of all the different Windows packages & libraries that winetricks can help you install, run `winetricks list-all`
|
||||
|
||||
## Other notes
|
||||
|
||||
### Wineprefixes (and Wine initialization)
|
||||
When you first run or boot Wine (`wine wineboot`), Wine will create a new user environment within which to install Windows software. This user environment is called a "wineprefix" (or "wine bottle") and is located (by default) in `~/.wine` (note that Linux folders with a `.` in front of them are "hidden" folders). Think of a wineprefix as Wine's virtual 'harddrive' where it installs software and saves settings. Wineprefixes are portable and deletable. For more Wine documentation, see [WineHQ](https://www.winehq.org/documentation).
|
||||
|
||||
If you at any point corrupt something inside your default wineprefix, you can start "fresh" by deleting your `~/.wine` directory (with the `rm -rf ~/.wine` command) and boot wine again to create a new default wineprefix.
|
||||
|
||||
### Transplanting wineprefixes
|
||||
If software isn't installing in Wine with Box86, but is installing for you in Wine on a regular x86 Linux computer, you can copy a wineprefix from your x86 Linux computer to the device you're running Box86 on. This is most easily done by tarring the `~/.wine` folder on your x86 Linux computer (`tar -cvf winebottle.tar ~/.wine`), transferring the tar file to your device, then un-tarring the tar file (`tar -xf winebottle.tar`) on your device running Box86 & Wine. Tarring the wineprefix preserves any symlinks that are inside it.
|
||||
|
||||
### Swapping out different versions of Wine
|
||||
Some versions of Wine work better with certain software. It is best to install a version of Wine that is known to work with the software you would like to run. There are three main development branches of Wine you can pick from, referred to as wine-stable, wine-devel, and wine-staging. _Note that the wine-staging branch requires extra installation steps on Raspberry Pi._
|
||||
|
||||
Your entire Wine installation can reside within a single folder on your Linux computer. TwisterOS assumes that your Wine installation is located inside the `~/wine/` directory. The actual directory where you put your `wine` folder doesn't matter as long as you have symlinks within the `/usr/local/bin/` directory which point to the `wine` folder so that Linux can find Wine when you type `wine` into the terminal).
|
||||
|
||||
You can change which version of Wine you are running simply by renaming your old `wine` and `.wine` folders to something else, then putting a new `wine` folder (containing your new version of Wine) in its place. Running `wine wineboot` again will migrate a wineprefix from an older version of Wine to be usable by the newer version of Wine you just installed. You can check which version of Wine you're running with the `wine --version` command.
|
||||
+41
-7
@@ -150,7 +150,7 @@ Enable/disable the Dynamic Recompiler (a.k.a DynaRec). This option defaults to 1
|
||||
Generate aligned atomics only (only available on Arm64 for now). Availble in WowBox64.
|
||||
|
||||
* 0 : Generate unaligned atomics handling code. [Default]
|
||||
* 1 : Generate aligned atomics only, which is faster and smaller code size, but will cause SIGBUS for LOCK prefixed opcodes operating on aligned data addresses.
|
||||
* 1 : Generate aligned atomics only, which is faster and smaller code size, but will cause SIGBUS for LOCK prefixed opcodes operating on unaligned data addresses.
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_BIGBLOCK> =I<0|1|2|3>
|
||||
@@ -197,11 +197,19 @@ Allow continue running a block that is unprotected and potentially dirty.
|
||||
* 2 : Will also, when it detect an HotPage, flag that page as NEVERCLEAN, and so it will not be write protected but Block build from that page will always be tested. It can be faster that way (but soem SMC case might not be trapped).
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_NOHOTPAGE> =I<0|1>
|
||||
|
||||
Disable detection of hot page (where code is executed and data written at the same time).
|
||||
|
||||
* 0 : Detect hot page [Default]
|
||||
* 1 : Do not detect hot page
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_DIV0> =I<0|1>
|
||||
|
||||
Enable or disable the generation of division-by-zero exception. Availble in WowBox64.
|
||||
|
||||
* 0 : Do not generate thr division-by-zero exception. [Default]
|
||||
* 0 : Do not generate the division-by-zero exception. [Default]
|
||||
* 1 : Generate the division-by-zero exception.
|
||||
|
||||
|
||||
@@ -305,11 +313,11 @@ Generate map file for Linux perf tool.
|
||||
|
||||
=item B<BOX64_DYNAREC_SAFEFLAGS> =I<0|1|2>
|
||||
|
||||
Behaviour of flags emulation on CALL/RET opcodes. Availble in WowBox64.
|
||||
Behaviour of flags emulation on CALL/RET opcodes and other edge cases. Availble in WowBox64.
|
||||
|
||||
* 0 : Treat CALL/RET as if it never needs any flags.
|
||||
* 1 : Most of RETs will need flags, most of CALLs will not. [Default]
|
||||
* 2 : All CALL/RET will need flags.
|
||||
* 2 : All CALL/RET will need flags. All edge cases are also handled.
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_STRONGMEM> =I<0|1|2|3>
|
||||
@@ -381,6 +389,30 @@ Force the use of float/double for x87 emulation. Availble in WowBox64.
|
||||
* 2 : Check Precision Control low precision on x87 emulation.
|
||||
|
||||
|
||||
=item B<BOX64_DYNACACHE> =I<0|1|2>
|
||||
|
||||
Enable/disable the Dynamic Recompiler Cache (a.k.a DynaCache). This option defaults to 2 (to read cache if present but not generate any). DynaCache write file to home folder by default, and can grow without limit.
|
||||
|
||||
* 0 : Disable DynaCache.
|
||||
* 1 : Enable DynaCache.
|
||||
* 2 : Use DynaCache files if present, but do not generate new one. [Default]
|
||||
|
||||
|
||||
=item B<BOX64_DYNACACHE_FOLDER> =I<XXXX>
|
||||
|
||||
Set the folder for DynaCache files. Default is $XDG_CACHE_HOME/box64 or $HOME/.cache/box64 if $XDG_CACHE_HOME is not set.
|
||||
|
||||
* XXXX : Use folder XXXX for DynaCache files.
|
||||
|
||||
|
||||
=item B<BOX64_DYNACACHE_MIN> =I<XXXX|350>
|
||||
|
||||
Minimum size, in KB, for a DynaCache to be written to disk. Default size is 350KB
|
||||
|
||||
* XXXX : Set a minimum size of XXXX KB of Dynarec code to write the dynacache to disk. Will not be saved to disk else.
|
||||
* 350 : A size of 350 KB is the default value. [Default]
|
||||
|
||||
|
||||
=item B<BOX64_EMULATED_LIBS> =I<XXXX|XXXX:YYYY:ZZZZ>
|
||||
|
||||
Force the use of emulated libraries.
|
||||
@@ -694,10 +726,10 @@ Always show SIGSEGV signal detailes.
|
||||
|
||||
=item B<BOX64_SSE_FLUSHTO0> =I<0|1>
|
||||
|
||||
Behaviour of SSE Flush to 0 flags. Availble in WowBox64.
|
||||
Behaviour of SSE Flush to 0 flags. Also tracking SSE exception flags Availble in WowBox64.
|
||||
|
||||
* 0 : Just track the flag. [Default]
|
||||
* 1 : Apply SSE Flush to 0 flag directly.
|
||||
* 1 : Apply SSE Flush to 0 flag directly. Also reflect SSE exception flags in Dynarec (if available)
|
||||
|
||||
|
||||
=item B<BOX64_SSE42> =I<0|1>
|
||||
@@ -741,12 +773,14 @@ Send all log and trace to a file instead of `stdout`.
|
||||
* stderr : Send all log and trace to `stderr`.
|
||||
|
||||
|
||||
=item B<BOX64_TRACE_INIT> =I<0|1>
|
||||
=item B<BOX64_TRACE_INIT> =I<0|1|symbolname|0xXXXXXXX-0xYYYYYYY>
|
||||
|
||||
Same as BOX64_TRACE but starts the trace immediately.
|
||||
|
||||
* 0 : Disable trace output. [Default]
|
||||
* 1 : Enable trace output. Trace starts before the initialization of dependencies.
|
||||
* symbolname : Enable trace output for `symbolname` only. Trace starts before the initialization of dependencies.
|
||||
* 0xXXXXXXX-0xYYYYYYY : Enable trace output for the range of address (inclusive-exclusive). Trace starts before the initialization of dependencies.
|
||||
|
||||
|
||||
=item B<BOX64_TRACE_START> =I<0|1|XXXX>
|
||||
|
||||
+3
-1
@@ -63,7 +63,9 @@ This configuration will apply the specified settings application-wide to any exe
|
||||
for entry in data:
|
||||
categories[entry["category"]].append(entry)
|
||||
|
||||
for category, entries in categories.items():
|
||||
# Put "Performance" at the top
|
||||
sorted_categories = sorted(categories.items(), key=lambda x: x[0] != "Performance")
|
||||
for category, entries in sorted_categories:
|
||||
md_file.write(f"## {category}\n\n")
|
||||
for entry in entries:
|
||||
md_file.write(f"### {entry['name']}\n\n{entry['description']}{' Availble in WowBox64.' if entry['wine'] else ''}\n\n")
|
||||
|
||||
+88
-6
@@ -228,7 +228,7 @@
|
||||
},
|
||||
{
|
||||
"key": "1",
|
||||
"description": "Generate aligned atomics only, which is faster and smaller code size, but will cause SIGBUS for LOCK prefixed opcodes operating on aligned data addresses.",
|
||||
"description": "Generate aligned atomics only, which is faster and smaller code size, but will cause SIGBUS for LOCK prefixed opcodes operating on unaligned data addresses.",
|
||||
"default": false
|
||||
}
|
||||
]
|
||||
@@ -343,6 +343,24 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BOX64_DYNAREC_NOHOTPAGE",
|
||||
"description": "Disable detection of hot page (where code is executed and data written at the same time).",
|
||||
"category": "Performance",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
"description": "Detect hot page",
|
||||
"default": true
|
||||
},
|
||||
{
|
||||
"key": "1",
|
||||
"description": "Do not detect hot page",
|
||||
"default": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BOX64_DYNAREC_DIV0",
|
||||
"description": "Enable or disable the generation of division-by-zero exception.",
|
||||
@@ -351,7 +369,7 @@
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
"description": "Do not generate thr division-by-zero exception.",
|
||||
"description": "Do not generate the division-by-zero exception.",
|
||||
"default": true
|
||||
},
|
||||
{
|
||||
@@ -611,7 +629,7 @@
|
||||
},
|
||||
{
|
||||
"name": "BOX64_DYNAREC_SAFEFLAGS",
|
||||
"description": "Behaviour of flags emulation on CALL/RET opcodes.",
|
||||
"description": "Behaviour of flags emulation on CALL/RET opcodes and other edge cases.",
|
||||
"category": "Performance",
|
||||
"wine": true,
|
||||
"options": [
|
||||
@@ -627,7 +645,7 @@
|
||||
},
|
||||
{
|
||||
"key": "2",
|
||||
"description": "All CALL/RET will need flags.",
|
||||
"description": "All CALL/RET will need flags. All edge cases are also handled.",
|
||||
"default": false
|
||||
}
|
||||
]
|
||||
@@ -801,6 +819,60 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BOX64_DYNACACHE",
|
||||
"description": "Enable/disable the Dynamic Recompiler Cache (a.k.a DynaCache). This option defaults to 2 (to read cache if present but not generate any). DynaCache write file to home folder by default, and can grow without limit.",
|
||||
"category": "Performance",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
"description": "Disable DynaCache.",
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"key": "1",
|
||||
"description": "Enable DynaCache.",
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"key": "2",
|
||||
"description": "Use DynaCache files if present, but do not generate new one.",
|
||||
"default": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BOX64_DYNACACHE_FOLDER",
|
||||
"description": "Set the folder for DynaCache files. Default is $XDG_CACHE_HOME/box64 or $HOME/.cache/box64 if $XDG_CACHE_HOME is not set.",
|
||||
"category": "Performance",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "XXXX",
|
||||
"description": "Use folder XXXX for DynaCache files.",
|
||||
"default": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BOX64_DYNACACHE_MIN",
|
||||
"description": "Minimum size, in KB, for a DynaCache to be written to disk. Default size is 350KB",
|
||||
"category": "Performance",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "XXXX",
|
||||
"description": "Set a minimum size of XXXX KB of Dynarec code to write the dynacache to disk. Will not be saved to disk else.",
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"key": "350",
|
||||
"description": "A size of 350 KB is the default value.",
|
||||
"default": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BOX64_EMULATED_LIBS",
|
||||
"description": "Force the use of emulated libraries.",
|
||||
@@ -1500,7 +1572,7 @@
|
||||
},
|
||||
{
|
||||
"name": "BOX64_SSE_FLUSHTO0",
|
||||
"description": "Behaviour of SSE Flush to 0 flags.",
|
||||
"description": "Behaviour of SSE Flush to 0 flags. Also tracking SSE exception flags",
|
||||
"category": "Compatibility",
|
||||
"wine": true,
|
||||
"options": [
|
||||
@@ -1511,7 +1583,7 @@
|
||||
},
|
||||
{
|
||||
"key": "1",
|
||||
"description": "Apply SSE Flush to 0 flag directly.",
|
||||
"description": "Apply SSE Flush to 0 flag directly. Also reflect SSE exception flags in Dynarec (if available)",
|
||||
"default": false
|
||||
}
|
||||
]
|
||||
@@ -1626,6 +1698,16 @@
|
||||
"key": "1",
|
||||
"description": "Enable trace output. Trace starts before the initialization of dependencies.",
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"key": "symbolname",
|
||||
"description": "Enable trace output for `symbolname` only. Trace starts before the initialization of dependencies.",
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"key": "0xXXXXXXX-0xYYYYYYY",
|
||||
"description": "Enable trace output for the range of address (inclusive-exclusive). Trace starts before the initialization of dependencies.",
|
||||
"default": false
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -21,6 +21,7 @@ cd ../ && rm -rf ./tmp/
|
||||
echo '#!/bin/bash
|
||||
export STEAMOS=1
|
||||
export STEAM_RUNTIME=1
|
||||
export PROTON_USE_WOW64=1
|
||||
export DBUS_FATAL_WARNINGS=0
|
||||
~/steam/bin/steam $@' > steam
|
||||
|
||||
|
||||
+3
-11
@@ -149,10 +149,6 @@ static void atfork_child_box64context(void)
|
||||
void freeCycleLog(box64context_t* ctx)
|
||||
{
|
||||
if(BOX64ENV(rolling_log)) {
|
||||
for(int i=0; i<BOX64ENV(rolling_log); ++i) {
|
||||
box_free(ctx->log_call[i]);
|
||||
box_free(ctx->log_ret[i]);
|
||||
}
|
||||
box_free(ctx->log_call);
|
||||
box_free(ctx->log_ret);
|
||||
ctx->log_call = NULL;
|
||||
@@ -162,12 +158,8 @@ void freeCycleLog(box64context_t* ctx)
|
||||
void initCycleLog(box64context_t* context)
|
||||
{
|
||||
if(context && BOX64ENV(rolling_log)) {
|
||||
context->log_call = (char**)box_calloc(BOX64ENV(rolling_log), sizeof(char*));
|
||||
context->log_ret = (char**)box_calloc(BOX64ENV(rolling_log), sizeof(char*));
|
||||
for(int i=0; i<BOX64ENV(rolling_log); ++i) {
|
||||
context->log_call[i] = (char*)box_calloc(256, 1);
|
||||
context->log_ret[i] = (char*)box_calloc(128, 1);
|
||||
}
|
||||
context->log_call = (char*)box_calloc(BOX64ENV(rolling_log), 256*sizeof(char));
|
||||
context->log_ret = (char*)box_calloc(BOX64ENV(rolling_log), 128*sizeof(char));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -357,7 +349,7 @@ void FreeBox64Context(box64context_t** context)
|
||||
FreeMapSymbols(&ctx->uniques);
|
||||
|
||||
#ifdef DYNAREC
|
||||
//dynarec_log(LOG_INFO, "BOX64 Dynarec at exit: Max DB=%d, righter=%d\n", ctx->max_db_size, rb_get_righter(ctx->db_sizes));
|
||||
//dynarec_log(LOG_INFO, "BOX64 Dynarec at exit: Max DB=%d, rightmost=%d\n", ctx->max_db_size, rb_get_rightmost(ctx->db_sizes));
|
||||
rbtree_delete(ctx->db_sizes);
|
||||
#endif
|
||||
|
||||
|
||||
+1
-1
@@ -3,6 +3,6 @@
|
||||
|
||||
#define BOX64_MAJOR 0
|
||||
#define BOX64_MINOR 3
|
||||
#define BOX64_REVISION 6
|
||||
#define BOX64_REVISION 8
|
||||
|
||||
#endif //__BOX64_VERSION_H_
|
||||
+122
-290
@@ -15,11 +15,10 @@
|
||||
#include <sys/stat.h>
|
||||
#include <stdarg.h>
|
||||
#include <ctype.h>
|
||||
#ifdef DYNAREC
|
||||
#ifdef ARM64
|
||||
#include <linux/auxvec.h>
|
||||
#include <asm/hwcap.h>
|
||||
#ifdef BOX32
|
||||
#include <sys/personality.h>
|
||||
#endif
|
||||
#ifdef DYNAREC
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
@@ -49,6 +48,7 @@
|
||||
#include "env.h"
|
||||
#include "cleanup.h"
|
||||
#include "freq.h"
|
||||
#include "hostext.h"
|
||||
|
||||
box64context_t *my_context = NULL;
|
||||
extern box64env_t box64env;
|
||||
@@ -59,6 +59,7 @@ int box64_stdout_no_w = 0;
|
||||
uintptr_t box64_pagesize;
|
||||
path_collection_t box64_addlibs = {0};
|
||||
int box64_is32bits = 0;
|
||||
int box64_isAddressSpace32 = 0;
|
||||
int box64_rdtsc = 0;
|
||||
uint8_t box64_rdtsc_shift = 0;
|
||||
int box64_mapclean = 0;
|
||||
@@ -75,43 +76,7 @@ uint32_t default_fs = 0;
|
||||
int box64_isglibc234 = 0;
|
||||
|
||||
#ifdef DYNAREC
|
||||
#ifdef ARM64
|
||||
int arm64_asimd = 0;
|
||||
int arm64_aes = 0;
|
||||
int arm64_pmull = 0;
|
||||
int arm64_crc32 = 0;
|
||||
int arm64_atomics = 0;
|
||||
int arm64_sha1 = 0;
|
||||
int arm64_sha2 = 0;
|
||||
int arm64_uscat = 0;
|
||||
int arm64_flagm = 0;
|
||||
int arm64_flagm2 = 0;
|
||||
int arm64_frintts = 0;
|
||||
int arm64_afp = 0;
|
||||
int arm64_rndr = 0;
|
||||
#elif defined(RV64)
|
||||
int rv64_zba = 0;
|
||||
int rv64_zbb = 0;
|
||||
int rv64_zbc = 0;
|
||||
int rv64_zbs = 0;
|
||||
int rv64_vector = 0; // rvv 1.0 or xtheadvector
|
||||
int rv64_xtheadvector = 0;
|
||||
int rv64_vlen = 0;
|
||||
int rv64_xtheadba = 0;
|
||||
int rv64_xtheadbb = 0;
|
||||
int rv64_xtheadbs = 0;
|
||||
int rv64_xtheadcondmov = 0;
|
||||
int rv64_xtheadmemidx = 0;
|
||||
int rv64_xtheadmempair = 0;
|
||||
int rv64_xtheadfmemidx = 0;
|
||||
int rv64_xtheadmac = 0;
|
||||
int rv64_xtheadfmv = 0;
|
||||
#elif defined(LA64)
|
||||
int la64_lbt = 0;
|
||||
int la64_lam_bh = 0;
|
||||
int la64_lamcas = 0;
|
||||
int la64_scq = 0;
|
||||
#endif
|
||||
cpu_ext_t cpuext = {0};
|
||||
#endif
|
||||
|
||||
int box64_wine = 0;
|
||||
@@ -125,9 +90,10 @@ char* trace_func = NULL;
|
||||
|
||||
FILE* ftrace = NULL;
|
||||
char* ftrace_name = NULL;
|
||||
int ftrace_has_pid = 0;
|
||||
int ftrace_opened = 0;
|
||||
|
||||
void openFTrace(int reopen)
|
||||
|
||||
static void openFTrace(void)
|
||||
{
|
||||
const char* p = BOX64ENV(trace_file);
|
||||
#ifndef MAX_PATH
|
||||
@@ -135,251 +101,63 @@ void openFTrace(int reopen)
|
||||
#endif
|
||||
char tmp[MAX_PATH];
|
||||
char tmp2[MAX_PATH];
|
||||
int append=0;
|
||||
if(p && strlen(p) && p[strlen(p)-1]=='+') {
|
||||
int append = 0;
|
||||
|
||||
if (ftrace_name) box_free(ftrace_name);
|
||||
ftrace_name = NULL;
|
||||
|
||||
if (p && strlen(p) && p[strlen(p) - 1] == '+') {
|
||||
strncpy(tmp2, p, sizeof(tmp2));
|
||||
tmp2[strlen(p)-1]='\0';
|
||||
p = tmp2;
|
||||
append = 1;
|
||||
}
|
||||
if (reopen) {
|
||||
p = ftrace_name;
|
||||
append = 1;
|
||||
} else {
|
||||
if (p && strstr(p, "\%pid")) {
|
||||
int next = 0;
|
||||
do {
|
||||
strcpy(tmp, p);
|
||||
char* c = strstr(tmp, "%pid");
|
||||
*c = 0; // cut
|
||||
char pid[16];
|
||||
if (next)
|
||||
sprintf(pid, "%d-%d", GetTID(), next);
|
||||
else
|
||||
sprintf(pid, "%d", GetTID());
|
||||
strcat(tmp, pid);
|
||||
c = strstr(p, "\%pid") + strlen("\%pid");
|
||||
strcat(tmp, c);
|
||||
++next;
|
||||
} while (FileExist(tmp, IS_FILE) && !append);
|
||||
p = tmp;
|
||||
ftrace_has_pid = 1;
|
||||
}
|
||||
if (ftrace_name)
|
||||
box_free(ftrace_name);
|
||||
ftrace_name = NULL;
|
||||
}
|
||||
if(p) {
|
||||
if(!strcmp(p, "stderr"))
|
||||
ftrace = stderr;
|
||||
else {
|
||||
if(append)
|
||||
ftrace = fopen(p, "a");
|
||||
|
||||
if (!p || ftrace_opened) return;
|
||||
ftrace_opened = 1;
|
||||
|
||||
if (strstr(p, "\%pid")) {
|
||||
int next = 0;
|
||||
do {
|
||||
strcpy(tmp, p);
|
||||
char* c = strstr(tmp, "%pid");
|
||||
*c = 0; // cut
|
||||
char pid[16];
|
||||
if (next)
|
||||
sprintf(pid, "%d-%d", GetTID(), next);
|
||||
else
|
||||
ftrace = fopen(p, "w");
|
||||
if(!ftrace) {
|
||||
ftrace = stdout;
|
||||
printf_log(LOG_INFO, "Cannot open trace file \"%s\" for writing (error=%s)\n", p, strerror(errno));
|
||||
} else {
|
||||
if (!reopen) ftrace_name = box_strdup(p);
|
||||
/*fclose(ftrace);
|
||||
ftrace = NULL;*/
|
||||
if (!BOX64ENV(nobanner)) {
|
||||
printf("BOX64 Trace %s to \"%s\"\n", append?"appended":"redirected", p);
|
||||
box64_stdout_no_w = 1;
|
||||
}
|
||||
PrintBox64Version(0);
|
||||
sprintf(pid, "%d", GetTID());
|
||||
strcat(tmp, pid);
|
||||
c = strstr(p, "\%pid") + strlen("\%pid");
|
||||
strcat(tmp, c);
|
||||
++next;
|
||||
} while (FileExist(tmp, IS_FILE) && !append);
|
||||
p = tmp;
|
||||
}
|
||||
|
||||
if (!strcmp(p, "stderr"))
|
||||
ftrace = stderr;
|
||||
else {
|
||||
if (append)
|
||||
ftrace = fopen(p, "a");
|
||||
else
|
||||
ftrace = fopen(p, "w");
|
||||
if (!ftrace) {
|
||||
ftrace = stdout;
|
||||
printf_log(LOG_INFO, "Cannot open trace file \"%s\" for writing (error=%s), fallback to stdout\n", p, strerror(errno));
|
||||
} else {
|
||||
ftrace_name = box_strdup(p);
|
||||
if (!BOX64ENV(nobanner)) {
|
||||
printf("[BOX64] Trace %s to \"%s\" (set BOX64_NOBANNER=1 to suppress this log)\n", append ? "appended" : "redirected", p);
|
||||
box64_stdout_no_w = 1;
|
||||
}
|
||||
PrintBox64Version(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void my_prepare_fork()
|
||||
{
|
||||
if (ftrace_has_pid && ftrace && (ftrace != stdout) && (ftrace != stderr)) {
|
||||
printf_log(LOG_INFO, "%04d|Closed trace file of %s at prepare\n", GetTID(), GetLastApplyEntryName());
|
||||
fclose(ftrace);
|
||||
}
|
||||
}
|
||||
|
||||
void my_parent_fork()
|
||||
{
|
||||
if (ftrace_has_pid) {
|
||||
openFTrace(1);
|
||||
printf_log(LOG_INFO, "%04d|Reopened trace file of %s at parent\n", GetTID(), GetLastApplyEntryName());
|
||||
}
|
||||
}
|
||||
|
||||
void my_child_fork()
|
||||
{
|
||||
if (ftrace_has_pid) {
|
||||
openFTrace(0);
|
||||
printf_log(LOG_INFO, "%04d|Created trace file of %s at child\n", GetTID(), GetLastApplyEntryName());
|
||||
}
|
||||
}
|
||||
|
||||
const char* getCpuName();
|
||||
int getNCpu();
|
||||
|
||||
#ifdef DYNAREC
|
||||
void GatherDynarecExtensions()
|
||||
{
|
||||
#ifdef ARM64
|
||||
unsigned long hwcap = real_getauxval(AT_HWCAP);
|
||||
if(!hwcap)
|
||||
hwcap = HWCAP_ASIMD;
|
||||
// first, check all needed extensions, lif half, edsp and fastmult
|
||||
if((hwcap&HWCAP_ASIMD) == 0) {
|
||||
printf_log(LOG_INFO, "Missing ASMID cpu support, disabling Dynarec\n");
|
||||
SET_BOX64ENV(dynarec, 0);
|
||||
return;
|
||||
}
|
||||
if(hwcap&HWCAP_CRC32)
|
||||
arm64_crc32 = 1;
|
||||
if(hwcap&HWCAP_PMULL)
|
||||
arm64_pmull = 1;
|
||||
if(hwcap&HWCAP_AES)
|
||||
arm64_aes = 1;
|
||||
if(hwcap&HWCAP_ATOMICS)
|
||||
arm64_atomics = 1;
|
||||
#ifdef HWCAP_SHA1
|
||||
if(hwcap&HWCAP_SHA1)
|
||||
arm64_sha1 = 1;
|
||||
#endif
|
||||
#ifdef HWCAP_SHA2
|
||||
if(hwcap&HWCAP_SHA2)
|
||||
arm64_sha2 = 1;
|
||||
#endif
|
||||
#ifdef HWCAP_USCAT
|
||||
if(hwcap&HWCAP_USCAT)
|
||||
arm64_uscat = 1;
|
||||
#endif
|
||||
#ifdef HWCAP_FLAGM
|
||||
if(hwcap&HWCAP_FLAGM)
|
||||
arm64_flagm = 1;
|
||||
#endif
|
||||
unsigned long hwcap2 = real_getauxval(AT_HWCAP2);
|
||||
#ifdef HWCAP2_FLAGM2
|
||||
if(hwcap2&HWCAP2_FLAGM2)
|
||||
arm64_flagm2 = 1;
|
||||
#endif
|
||||
#ifdef HWCAP2_FRINT
|
||||
if(hwcap2&HWCAP2_FRINT)
|
||||
arm64_frintts = 1;
|
||||
#endif
|
||||
#ifdef HWCAP2_AFP
|
||||
if(hwcap2&HWCAP2_AFP)
|
||||
arm64_afp = 1;
|
||||
#endif
|
||||
#ifdef HWCAP2_RNG
|
||||
if(hwcap2&HWCAP2_RNG)
|
||||
arm64_rndr = 1;
|
||||
#endif
|
||||
printf_log(LOG_INFO, "Dynarec for ARM64, with extension: ASIMD");
|
||||
if(arm64_aes)
|
||||
printf_log_prefix(0, LOG_INFO, " AES");
|
||||
if(arm64_crc32)
|
||||
printf_log_prefix(0, LOG_INFO, " CRC32");
|
||||
if(arm64_pmull)
|
||||
printf_log_prefix(0, LOG_INFO, " PMULL");
|
||||
if(arm64_atomics)
|
||||
printf_log_prefix(0, LOG_INFO, " ATOMICS");
|
||||
if(arm64_sha1)
|
||||
printf_log_prefix(0, LOG_INFO, " SHA1");
|
||||
if(arm64_sha2)
|
||||
printf_log_prefix(0, LOG_INFO, " SHA2");
|
||||
if(arm64_uscat)
|
||||
printf_log_prefix(0, LOG_INFO, " USCAT");
|
||||
if(arm64_flagm)
|
||||
printf_log_prefix(0, LOG_INFO, " FLAGM");
|
||||
if(arm64_flagm2)
|
||||
printf_log_prefix(0, LOG_INFO, " FLAGM2");
|
||||
if(arm64_frintts)
|
||||
printf_log_prefix(0, LOG_INFO, " FRINT");
|
||||
if(arm64_afp)
|
||||
printf_log_prefix(0, LOG_INFO, " AFP");
|
||||
if(arm64_rndr)
|
||||
printf_log_prefix(0, LOG_INFO, " RNDR");
|
||||
printf_log_prefix(0, LOG_INFO, "\n");
|
||||
#elif defined(LA64)
|
||||
printf_log(LOG_INFO, "Dynarec for LoongArch ");
|
||||
char* p = getenv("BOX64_DYNAREC_LA64NOEXT");
|
||||
if(p == NULL || p[0] == '0') {
|
||||
uint32_t cpucfg2 = 0, idx = 2;
|
||||
asm volatile("cpucfg %0, %1" : "=r"(cpucfg2) : "r"(idx));
|
||||
if (((cpucfg2 >> 6) & 0b11) == 3) {
|
||||
printf_log_prefix(0, LOG_INFO, "with extension LSX LASX");
|
||||
} else {
|
||||
printf_log(LOG_INFO, "\nMissing LSX and/or LASX extension support, disabling Dynarec\n");
|
||||
SET_BOX64ENV(dynarec, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (la64_lbt = ((cpucfg2 >> 18) & 0b1))
|
||||
printf_log_prefix(0, LOG_INFO, " LBT_X86");
|
||||
if ((la64_lam_bh = (cpucfg2 >> 27) & 0b1))
|
||||
printf_log_prefix(0, LOG_INFO, " LAM_BH");
|
||||
if ((la64_lamcas = (cpucfg2 >> 28) & 0b1))
|
||||
printf_log_prefix(0, LOG_INFO, " LAMCAS");
|
||||
if ((la64_scq = (cpucfg2 >> 30) & 0b1))
|
||||
printf_log_prefix(0, LOG_INFO, " SCQ");
|
||||
}
|
||||
printf_log_prefix(0, LOG_INFO, "\n");
|
||||
#elif defined(RV64)
|
||||
void RV64_Detect_Function();
|
||||
// private env. variable for the developer ;)
|
||||
char *p = getenv("BOX64_DYNAREC_RV64NOEXT");
|
||||
if(p == NULL || strcasecmp(p, "1")) {
|
||||
RV64_Detect_Function();
|
||||
if (p) {
|
||||
p = strtok(p, ",");
|
||||
while (p) {
|
||||
if (!strcasecmp(p, "zba")) rv64_zba = 0;
|
||||
if (!strcasecmp(p, "zbb")) rv64_zbb = 0;
|
||||
if (!strcasecmp(p, "zbc")) rv64_zbc = 0;
|
||||
if (!strcasecmp(p, "zbs")) rv64_zbs = 0;
|
||||
if (!strcasecmp(p, "vector")) {
|
||||
rv64_vector = 0;
|
||||
rv64_xtheadvector = 0;
|
||||
}
|
||||
if (!strcasecmp(p, "xtheadba")) rv64_xtheadba = 0;
|
||||
if (!strcasecmp(p, "xtheadbb")) rv64_xtheadbb = 0;
|
||||
if (!strcasecmp(p, "xtheadbs")) rv64_xtheadbs = 0;
|
||||
if (!strcasecmp(p, "xtheadmemidx")) rv64_xtheadmemidx = 0;
|
||||
// if (!strcasecmp(p, "xtheadfmemidx")) rv64_xtheadfmemidx = 0;
|
||||
// if (!strcasecmp(p, "xtheadmac")) rv64_xtheadmac = 0;
|
||||
// if (!strcasecmp(p, "xtheadfmv")) rv64_xtheadfmv = 0;
|
||||
if (!strcasecmp(p, "xtheadmempair")) rv64_xtheadmempair = 0;
|
||||
if (!strcasecmp(p, "xtheadcondmov")) rv64_xtheadcondmov = 0;
|
||||
p = strtok(NULL, ",");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf_log(LOG_INFO, "Dynarec for rv64g");
|
||||
if (rv64_vector && !rv64_xtheadvector) printf_log_prefix(0, LOG_INFO, "v");
|
||||
if (rv64_zba) printf_log_prefix(0, LOG_INFO, "_zba");
|
||||
if (rv64_zbb) printf_log_prefix(0, LOG_INFO, "_zbb");
|
||||
if (rv64_zbc) printf_log_prefix(0, LOG_INFO, "_zbc");
|
||||
if (rv64_zbs) printf_log_prefix(0, LOG_INFO, "_zbs");
|
||||
if (rv64_vector && !rv64_xtheadvector) printf_log_prefix(0, LOG_INFO, "_zvl%d", rv64_vlen);
|
||||
if (rv64_xtheadba) printf_log_prefix(0, LOG_INFO, "_xtheadba");
|
||||
if (rv64_xtheadbb) printf_log_prefix(0, LOG_INFO, "_xtheadbb");
|
||||
if (rv64_xtheadbs) printf_log_prefix(0, LOG_INFO, "_xtheadbs");
|
||||
if (rv64_xtheadmempair) printf_log_prefix(0, LOG_INFO, "_xtheadmempair");
|
||||
if (rv64_xtheadcondmov) printf_log_prefix(0, LOG_INFO, "_xtheadcondmov");
|
||||
if (rv64_xtheadmemidx) printf_log_prefix(0, LOG_INFO, "_xtheadmemidx");
|
||||
// Disable the display since these are only detected but never used.
|
||||
// if(rv64_xtheadfmemidx) printf_log_prefix(0, LOG_INFO, " xtheadfmemidx");
|
||||
// if(rv64_xtheadmac) printf_log_prefix(0, LOG_INFO, " xtheadmac");
|
||||
// if(rv64_xtheadfmv) printf_log_prefix(0, LOG_INFO, " xtheadfmv");
|
||||
if (rv64_xtheadvector) printf_log_prefix(0, LOG_INFO, "_xthvector");
|
||||
printf_log_prefix(0, LOG_INFO, "\n");
|
||||
#else
|
||||
#error Unsupported architecture
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
int getNCpuUnmasked();
|
||||
|
||||
void computeRDTSC()
|
||||
{
|
||||
@@ -423,7 +201,7 @@ void computeRDTSC()
|
||||
|
||||
static void displayMiscInfo()
|
||||
{
|
||||
openFTrace(0);
|
||||
openFTrace();
|
||||
|
||||
if ((BOX64ENV(nobanner) || BOX64ENV(log)) && ftrace==stdout)
|
||||
box64_stdout_no_w = 1;
|
||||
@@ -434,18 +212,17 @@ static void displayMiscInfo()
|
||||
|
||||
char* p;
|
||||
|
||||
// grab pagesize
|
||||
box64_pagesize = sysconf(_SC_PAGESIZE);
|
||||
if(!box64_pagesize)
|
||||
box64_pagesize = 4096;
|
||||
|
||||
#ifdef DYNAREC
|
||||
// grab cpu extensions for dynarec usage
|
||||
GatherDynarecExtensions();
|
||||
if (DetectHostCpuFeatures())
|
||||
PrintHostCpuFeatures();
|
||||
else {
|
||||
printf_log(LOG_INFO, "Minimum CPU requirements not met, disabling DynaRec\n");
|
||||
SET_BOX64ENV(dynarec, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
// grab ncpu and cpu name
|
||||
int ncpu = getNCpu();
|
||||
int ncpu = getNCpuUnmasked();
|
||||
const char* cpuname = getCpuName();
|
||||
|
||||
printf_log(LOG_INFO, "Running on %s with %d core%s, pagesize: %zd\n", cpuname, ncpu, ncpu > 1 ? "s" : "", box64_pagesize);
|
||||
@@ -551,6 +328,8 @@ void PrintHelp() {
|
||||
PrintfFtrace(0, " '-v'|'--version' to print box64 version and quit\n");
|
||||
PrintfFtrace(0, " '-h'|'--help' to print this and quit\n");
|
||||
PrintfFtrace(0, " '-k'|'--kill-all' to kill all box64 instances\n");
|
||||
PrintfFtrace(0, " '--dynacache-list' to list of DynaCache file and their validity\n");
|
||||
PrintfFtrace(0, " '--dynacache-clean' to remove invalide DynaCache files\n");
|
||||
}
|
||||
|
||||
void KillAllInstances()
|
||||
@@ -586,7 +365,7 @@ void KillAllInstances()
|
||||
snprintf(self_name_with_deleted, sizeof(self_name_with_deleted), "%s (deleted)", self_name);
|
||||
|
||||
const pid_t self = getpid();
|
||||
while (entry = readdir(proc_dir)) {
|
||||
while ((entry = readdir(proc_dir))) {
|
||||
const pid_t pid = atoi(entry->d_name);
|
||||
if (!pid || pid == self) continue;
|
||||
|
||||
@@ -734,6 +513,8 @@ void setupTraceInit()
|
||||
uintptr_t s_trace_start=0, s_trace_end=0;
|
||||
if (strcmp(p, "1")==0)
|
||||
SetTraceEmu(0, 0);
|
||||
else if (strcmp(p, "0")==0)
|
||||
;
|
||||
else if (strchr(p,'-')) {
|
||||
if(sscanf(p, "%ld-%ld", &s_trace_start, &s_trace_end)!=2) {
|
||||
if(sscanf(p, "0x%lX-0x%lX", &s_trace_start, &s_trace_end)!=2)
|
||||
@@ -803,6 +584,8 @@ void setupTrace()
|
||||
uintptr_t s_trace_start=0, s_trace_end=0;
|
||||
if (strcmp(p, "1")==0)
|
||||
SetTraceEmu(0, 0);
|
||||
else if (strcmp(p, "0")==0)
|
||||
;
|
||||
else if (strchr(p,'-')) {
|
||||
if(sscanf(p, "%ld-%ld", &s_trace_start, &s_trace_end)!=2) {
|
||||
if(sscanf(p, "0x%lX-0x%lX", &s_trace_start, &s_trace_end)!=2)
|
||||
@@ -851,6 +634,7 @@ void endBox64()
|
||||
if(!my_context || box64_quit)
|
||||
return;
|
||||
|
||||
SerializeAllMapping(); // just to be safe
|
||||
// then call all the fini
|
||||
dynarec_log(LOG_DEBUG, "endBox64() called\n");
|
||||
box64_quit = 1;
|
||||
@@ -874,6 +658,7 @@ void endBox64()
|
||||
#ifndef STATICBUILD
|
||||
endMallocHook();
|
||||
#endif
|
||||
SerializeAllMapping(); // to be safe
|
||||
FreeBox64Context(&my_context);
|
||||
#ifdef DYNAREC
|
||||
// disable dynarec now
|
||||
@@ -951,6 +736,11 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
|
||||
|
||||
ftrace = stdout;
|
||||
|
||||
// grab pagesize
|
||||
box64_pagesize = sysconf(_SC_PAGESIZE);
|
||||
if(!box64_pagesize)
|
||||
box64_pagesize = 4096;
|
||||
|
||||
LoadEnvVariables();
|
||||
InitializeEnvFiles();
|
||||
|
||||
@@ -970,6 +760,14 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
|
||||
KillAllInstances();
|
||||
exit(0);
|
||||
}
|
||||
if(!strcmp(prog, "--dynacache-list")) {
|
||||
DynaCacheList(argv[nextarg+1]);
|
||||
exit(0);
|
||||
}
|
||||
if(!strcmp(prog, "--dynacache-clean")) {
|
||||
DynaCacheClean();
|
||||
exit(0);
|
||||
}
|
||||
// other options?
|
||||
if(!strcmp(prog, "--")) {
|
||||
prog = argv[++nextarg];
|
||||
@@ -1204,6 +1002,7 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
|
||||
box64_zoom = 1;
|
||||
}
|
||||
// special case for bash
|
||||
int setup_bash_rcfile = 0;
|
||||
if (!strcmp(box64_guest_name, "bash") || !strcmp(box64_guest_name, "box64-bash")) {
|
||||
printf_log(LOG_INFO, "Bash detected, disabling banner\n");
|
||||
if (!BOX64ENV(nobanner)) {
|
||||
@@ -1212,8 +1011,10 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
|
||||
}
|
||||
if (!bashpath) {
|
||||
bashpath = (char*)prog;
|
||||
SET_BOX64ENV(bash, (char*)prog);
|
||||
setenv("BOX64_BASH", prog, 1);
|
||||
}
|
||||
setup_bash_rcfile = 1;
|
||||
}
|
||||
if(!bashpath)
|
||||
bashpath = ResolveFile("box64-bash", &my_context->box64_path);
|
||||
@@ -1225,7 +1026,8 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
|
||||
ApplyEnvFileEntry(box64_wine_guest_name);
|
||||
box64_wine_guest_name = NULL;
|
||||
}
|
||||
openFTrace(0);
|
||||
// Try to open ftrace again after applying rcfile.
|
||||
openFTrace();
|
||||
setupZydis(my_context);
|
||||
PrintEnvVariables(&box64env, LOG_INFO);
|
||||
|
||||
@@ -1233,6 +1035,13 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
|
||||
my_context->argv[i] = box_strdup(argv[i+nextarg]);
|
||||
printf_log(LOG_INFO, "argv[%i]=\"%s\"\n", i, my_context->argv[i]);
|
||||
}
|
||||
|
||||
// Setup custom bash rcfile iff no args are present
|
||||
if (setup_bash_rcfile && my_context->argc == 1) {
|
||||
add_argv("--rcfile");
|
||||
add_argv("box64-custom-bashrc-file"); // handled by my_open
|
||||
}
|
||||
|
||||
if(BOX64ENV(nosandbox))
|
||||
{
|
||||
add_argv("--no-sandbox");
|
||||
@@ -1328,6 +1137,32 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
|
||||
}
|
||||
#ifdef BOX32
|
||||
box64_is32bits = FileIsX86ELF(my_context->fullpath);
|
||||
// try to switch personality, but only if not already tried
|
||||
if(box64_is32bits) {
|
||||
int tried = getenv("BOX32_PERSONA32BITS")?1:0;
|
||||
if(tried) {
|
||||
unsetenv("BOX32_PERSONA32BITS");
|
||||
int p = personality(0xffffffff);
|
||||
if(p==ADDR_LIMIT_32BIT) {
|
||||
box64_isAddressSpace32 = 1;
|
||||
printf_log(LOG_INFO, "Personality set to 32bits\n");
|
||||
}
|
||||
} else {
|
||||
if(personality(ADDR_LIMIT_32BIT)!=-1) {
|
||||
int nenv = 0;
|
||||
while(env[nenv]) nenv++;
|
||||
// alloc + "LD_PRELOAD" if needd + last NULL ending
|
||||
char** newenv = (char**)box_calloc(nenv+1+1, sizeof(char*));
|
||||
// copy strings
|
||||
for (int i=0; i<nenv; ++i)
|
||||
newenv[i] = box_strdup(env[i]);
|
||||
newenv[nenv] = "BOX32_PERSONA32BITS=1";
|
||||
// re-launch...
|
||||
if(execve(my_context->box64path, (void*)argv, newenv)<0)
|
||||
printf_log(LOG_NONE, "Failed to relaunch. Error is %d/%s (argv[0]=\"%s\")\n", errno, strerror(errno), argv[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(box64_is32bits) {
|
||||
printf_log(LOG_INFO, "Using Box32 to load 32bits elf\n");
|
||||
loadProtectionFromMap();
|
||||
@@ -1507,9 +1342,6 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
|
||||
SetRBP(emu, 0); // Frame pointer so to "No more frame pointer"
|
||||
}
|
||||
|
||||
// child fork to handle traces
|
||||
//pthread_atfork(my_prepare_fork, my_parent_fork, my_child_fork);
|
||||
|
||||
thread_set_emu(emu);
|
||||
|
||||
// export symbols
|
||||
|
||||
+757
-204
File diff suppressed because it is too large.
Load diff
@@ -5,148 +5,7 @@
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
ARM64 Linux Call Convention
|
||||
|
||||
SP The Stack Pointer.
|
||||
r30 LR The Link Register.
|
||||
r29 FP The Frame Pointer
|
||||
r19…r28 Callee-saved registers
|
||||
r18 The Platform Register, if needed; otherwise a temporary register. See notes.
|
||||
r17 IP1 The second intra-procedure-call temporary register (can be used by call veneers and PLT code); at other times may be used as a temporary register.
|
||||
r16 IP0 The first intra-procedure-call scratch register (can be used by call veneers and PLT code); at other times may be used as a temporary register.
|
||||
r9…r15 Temporary registers
|
||||
r8 Indirect result location register
|
||||
r0…r7 Parameter/result registers
|
||||
|
||||
For SIMD:
|
||||
The first eight registers, v0-v7, are used to pass argument values into a subroutine and to return result values from a function.
|
||||
They may also be used to hold intermediate values within a routine (but, in general, only between subroutine calls).
|
||||
|
||||
Registers v8-v15 must be preserved by a callee across subroutine calls;
|
||||
the remaining registers (v0-v7, v16-v31) do not need to be preserved (or should be preserved by the caller).
|
||||
Additionally, only the bottom 64 bits of each value stored in v8-v15 need to be preserved [8];
|
||||
it is the responsibility of the caller to preserve larger values.
|
||||
|
||||
For SVE:
|
||||
z0-z7 are used to pass scalable vector arguments to a subroutine, and to return scalable vector results from a function.
|
||||
If a subroutine takes at least one argument in scalable vector registers or scalable predicate registers,
|
||||
or returns results in such regisers, the subroutine must ensure that the entire contents of z8-z23 are preserved across the call.
|
||||
In other cases it need only preserve the low 64 bits of z8-z15, as described in SIMD and Floating-Point registers.
|
||||
p0-p3 are used to pass scalable predicate arguments to a subroutine and to return scalable predicate results from a function.
|
||||
If a subroutine takes at least one argument in scalable vector registers or scalable predicate registers,
|
||||
or returns results in such registers, the subroutine must ensure that p4-p15 are preserved across the call.
|
||||
In other cases it need not preserve any scalable predicate register contents.
|
||||
|
||||
*/
|
||||
|
||||
// x86 Register mapping
|
||||
#define xRAX 10
|
||||
#define xRCX 11
|
||||
#define xRDX 12
|
||||
#define xRBX 13
|
||||
#define xRSP 14
|
||||
#define xRBP 15
|
||||
#define xRSI 16
|
||||
#define xRDI 17
|
||||
#define xR8 18
|
||||
#define xR9 19
|
||||
#define xR10 20
|
||||
#define xR11 21
|
||||
#define xR12 22
|
||||
#define xR13 23
|
||||
#define xR14 24
|
||||
#define xR15 25
|
||||
#define xFlags 26
|
||||
#define xRIP 27
|
||||
#define xSavedSP 28
|
||||
|
||||
// convert a x86 register to native according to the register mapping
|
||||
#define TO_NAT(A) (xRAX + (A))
|
||||
|
||||
// 32bits version
|
||||
#define wEAX xRAX
|
||||
#define wECX xRCX
|
||||
#define wEDX xRDX
|
||||
#define wEBX xRBX
|
||||
#define wESP xRSP
|
||||
#define wEBP xRBP
|
||||
#define wESI xRSI
|
||||
#define wEDI xRDI
|
||||
#define wR8 xR8
|
||||
#define wR9 xR9
|
||||
#define wR10 xR10
|
||||
#define wR11 xR11
|
||||
#define wR12 xR12
|
||||
#define wR13 xR13
|
||||
#define wR14 xR14
|
||||
#define wR15 xR15
|
||||
#define wFlags xFlags
|
||||
// scratch registers
|
||||
#define x1 1
|
||||
#define x2 2
|
||||
#define x3 3
|
||||
#define x4 4
|
||||
#define x5 5
|
||||
#define x6 6
|
||||
#define x87pc 7
|
||||
// x87 can be a scratch, but check if it's used as x87 PC and restore if needed in that case
|
||||
// 32bits version of scratch
|
||||
#define w1 x1
|
||||
#define w2 x2
|
||||
#define w3 x3
|
||||
#define w4 x4
|
||||
#define w5 x5
|
||||
#define w6 x6
|
||||
#define w87pc x87pc
|
||||
// emu is r0
|
||||
#define xEmu 0
|
||||
// ARM64 LR
|
||||
#define xLR 30
|
||||
// ARM64 SP is r31 but is a special register
|
||||
#define xSP 31
|
||||
// xZR regs is 31
|
||||
#define xZR 31
|
||||
#define wZR xZR
|
||||
|
||||
// conditions
|
||||
// Z == 1
|
||||
#define cEQ 0b0000
|
||||
// Z != 1
|
||||
#define cNE 0b0001
|
||||
// C == 1
|
||||
#define cCS 0b0010
|
||||
// C == 1
|
||||
#define cHS cCS
|
||||
// C != 1
|
||||
#define cCC 0b0011
|
||||
// C != 1
|
||||
#define cLO cCC
|
||||
// N == 1
|
||||
#define cMI 0b0100
|
||||
// N != 1
|
||||
#define cPL 0b0101
|
||||
// V == 1
|
||||
#define cVS 0b0110
|
||||
// V != 1
|
||||
#define cVC 0b0111
|
||||
// C == 1 && Z == 0
|
||||
#define cHI 0b1000
|
||||
// C !=1 || Z == 1
|
||||
#define cLS 0b1001
|
||||
// N == V
|
||||
#define cGE 0b1010
|
||||
// N != V
|
||||
#define cLT 0b1011
|
||||
// N == V && Z == 0
|
||||
#define cGT 0b1100
|
||||
// N != V || Z == 1
|
||||
#define cLE 0b1101
|
||||
// always
|
||||
#define c__ 0b1110
|
||||
|
||||
//FCMP type of opcode produce:
|
||||
// if any NAN: CV / v1 == v2: ZC / v1 < v2: N / v1 > v2: C
|
||||
#include "arm64_mapping.h"
|
||||
|
||||
int convert_bitmask(uint64_t bitmask);
|
||||
#define convert_bitmask_w(A) convert_bitmask(((uint64_t)(A) << 32) + (uint32_t)(A))
|
||||
@@ -188,10 +47,12 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#define ADDx_REG(Rd, Rn, Rm) EMIT(ADDSUB_REG_gen(1, 0, 0, 0b00, Rm, 0, Rn, Rd))
|
||||
#define ADDSx_REG(Rd, Rn, Rm) FEMIT(ADDSUB_REG_gen(1, 0, 1, 0b00, Rm, 0, Rn, Rd))
|
||||
#define ADDx_REG_LSL(Rd, Rn, Rm, lsl) EMIT(ADDSUB_REG_gen(1, 0, 0, 0b00, Rm, lsl, Rn, Rd))
|
||||
#define ADDx_REG_LSR(Rd, Rn, Rm, lsr) EMIT(ADDSUB_REG_gen(1, 0, 0, 0b01, Rm, lsr, Rn, Rd))
|
||||
#define ADDz_REG_LSL(Rd, Rn, Rm, lsl) EMIT(ADDSUB_REG_gen(rex.is32bits?0:1, 0, 0, 0b00, Rm, lsl, Rn, Rd))
|
||||
#define ADDw_REG(Rd, Rn, Rm) EMIT(ADDSUB_REG_gen(0, 0, 0, 0b00, Rm, 0, Rn, Rd))
|
||||
#define ADDSw_REG(Rd, Rn, Rm) FEMIT(ADDSUB_REG_gen(0, 0, 1, 0b00, Rm, 0, Rn, Rd))
|
||||
#define ADDw_REG_LSL(Rd, Rn, Rm, lsl) EMIT(ADDSUB_REG_gen(0, 0, 0, 0b00, Rm, lsl, Rn, Rd))
|
||||
#define ADDw_REG_LSR(Rd, Rn, Rm, lsr) EMIT(ADDSUB_REG_gen(0, 0, 0, 0b01, Rm, lsr, Rn, Rd))
|
||||
#define ADDSw_REG_LSL(Rd, Rn, Rm, lsl) FEMIT(ADDSUB_REG_gen(0, 0, 1, 0b00, Rm, lsl, Rn, Rd))
|
||||
#define ADDxw_REG(Rd, Rn, Rm) EMIT(ADDSUB_REG_gen(rex.w, 0, 0, 0b00, Rm, 0, Rn, Rd))
|
||||
#define ADDz_REG(Rd, Rn, Rm) EMIT(ADDSUB_REG_gen(rex.is32bits?0:1, 0, 0, 0b00, Rm, 0, Rn, Rd))
|
||||
@@ -261,9 +122,11 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#define SBCSw_REG(Rd, Rn, Rm) FEMIT(ADDSUBC_gen(0, 1, 1, Rm, Rn, Rd))
|
||||
#define SBCSxw_REG(Rd, Rn, Rm) FEMIT(ADDSUBC_gen(rex.w, 1, 1, Rm, Rn, Rd))
|
||||
|
||||
#define SUB_ext(sf, op, S, Rm, option, imm3, Rn, Rd) ((sf)<<31 | (op)<<30 | (S)<<29 | 0b01011<<24 | 1<<21 | (Rm)<<16 | (option)<<13 | (imm3)<<10 | (Rn)<<5 | (Rd))
|
||||
#define SUBxw_UXTB(Rd, Rn, Rm) EMIT(SUB_ext(rex.w, 1, 0, Rm, 0b000, 0, Rn, Rd))
|
||||
#define SUBw_UXTB(Rd, Rn, Rm) EMIT(SUB_ext(0, 1, 0, Rm, 0b000, 0, Rn, Rd))
|
||||
#define ADDSUB_ext(sf, op, S, Rm, option, imm3, Rn, Rd) ((sf)<<31 | (op)<<30 | (S)<<29 | 0b01011<<24 | 1<<21 | (Rm)<<16 | (option)<<13 | (imm3)<<10 | (Rn)<<5 | (Rd))
|
||||
#define SUBxw_UXTB(Rd, Rn, Rm) EMIT(ADDSUB_ext(rex.w, 1, 0, Rm, 0b000, 0, Rn, Rd))
|
||||
#define SUBw_UXTB(Rd, Rn, Rm) EMIT(ADDSUB_ext(0, 1, 0, Rm, 0b000, 0, Rn, Rd))
|
||||
#define ADDw_UXTH(Rd, Rn, Rm) EMIT(ADDSUB_ext(0, 0, 0, Rm, 0b001, 0, Rn, Rd))
|
||||
#define ADDx_UXTW(Rd, Rn, Rm) EMIT(ADDSUB_ext(1, 0, 0, Rm, 0b010, 0, Rn, Rd))
|
||||
|
||||
// CCMP compare if cond is true, set nzcv if false
|
||||
#define CCMP_reg(sf, Rm, cond, Rn, nzcv) ((sf)<<31 | 1<<30 | 1<<29 | 0b11010010<<21 | (Rm)<<16 | (cond)<<12 | (Rn)<<5 | (nzcv))
|
||||
@@ -301,6 +164,8 @@ int convert_bitmask(uint64_t bitmask);
|
||||
|
||||
#define LDS_gen(size, op1, imm12, Rn, Rt) ((size)<<30 | 0b111<<27 | (op1)<<24 | 0b10<<22 | (imm12)<<10 | (Rn)<<5 | (Rt))
|
||||
#define LDRSW_U12(Rt, Rn, imm12) EMIT(LDS_gen(0b10, 0b01, ((uint32_t)((imm12)>>2))&0xfff, Rn, Rt))
|
||||
#define LDRSH_U12(Rt, Rn, imm12) EMIT(LDS_gen(0b01, 0b01, ((uint32_t)((imm12)>>1))&0xfff, Rn, Rt))
|
||||
#define LDRSB_U12(Rt, Rn, imm12) EMIT(LDS_gen(0b00, 0b01, ((uint32_t)(imm12))&0xfff, Rn, Rt))
|
||||
|
||||
#define LDR_REG_gen(size, Rm, option, S, Rn, Rt) ((size)<<30 | 0b111<<27 | 0b01<<22 | 1<<21 | (Rm)<<16 | (option)<<13 | (S)<<12 | (0b10)<<10 | (Rn)<<5 | (Rt))
|
||||
#define LDRx_REG(Rt, Rn, Rm) EMIT(LDR_REG_gen(0b11, Rm, 0b011, 0, Rn, Rt))
|
||||
@@ -338,6 +203,7 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#define LDRSW_REG(Rt, Rn, Rm) EMIT(LDRS_REG_gen(0b10, Rm, 0b011, 0, Rn, Rt))
|
||||
#define LDRSW_REG_SXTW(Rt, Rn, Rm) EMIT(LDRS_REG_gen(0b10, Rm, 0b110, 0, Rn, Rt))
|
||||
#define LDRSW_REGz(Rt, Rn, Rm) EMIT(LDRS_REG_gen(0b10, Rm, rex.is32bits?0b110:0b011, 0, Rn, Rt))
|
||||
#define LDRSH_REGz(Rt, Rn, Rm) EMIT(LDRS_REG_gen(0b01, Rm, rex.is32bits?0b110:0b011, 0, Rn, Rt))
|
||||
|
||||
#define LDR_PC_gen(opc, imm19, Rt) ((opc)<<30 | 0b011<<27 | (imm19)<<5 | (Rt))
|
||||
#define LDRx_literal(Rt, imm21) EMIT(LDR_PC_gen(0b01, (((int64_t)(imm21))>>2)&0x7FFFF, Rt))
|
||||
@@ -2487,4 +2353,14 @@ int convert_bitmask(uint64_t bitmask);
|
||||
//SHA256 hash update (part 2)
|
||||
#define SHA256H2(Vd, Vn, Vm) EMIT(SHA256H2_gen(Vm, Vn, Vd))
|
||||
|
||||
// LRCPC extension
|
||||
|
||||
#define LDAPR_gen(sz, Rn, Rt) ((sz)<<30 | 0b111<<27 | 1<<23 | 1<<21 | 0b11111<<16 | 1<<15 | 0b100<<12 | (Rn)<<5 | (Rt))
|
||||
#define LDAPRx(Rt, Rn) EMIT(LDAPR_gen(0b11, Rn, Rt))
|
||||
#define LDAPRw(Rt, Rn) EMIT(LDAPR_gen(0b10, Rn, Rt))
|
||||
#define LDAPRxw(Rt, Rn) EMIT(LDAPR_gen(0b10+rex.w, Rn, Rt))
|
||||
#define LDAPRz(Rt, Rn) EMIT(LDAPR_gen(rex.is32bits?0b10:0b11, Rn, Rt))
|
||||
#define LDAPRH(Rt, Rn) EMIT(LDAPR_gen(0b01, Rn, Rt))
|
||||
#define LDAPRB(Rt, Rn) EMIT(LDAPR_gen(0b00, Rn, Rt))
|
||||
|
||||
#endif //__ARM64_EMITTER_H__
|
||||
@@ -5,7 +5,7 @@
|
||||
.text
|
||||
.align 4
|
||||
|
||||
.extern arm64_atomics
|
||||
.extern cpuext
|
||||
.global arm64_lock_read_b
|
||||
.global arm64_lock_write_b
|
||||
.global arm64_lock_read_h
|
||||
@@ -23,6 +23,7 @@
|
||||
.global arm64_lock_storeifnull
|
||||
.global arm64_lock_storeifnull_d
|
||||
.global arm64_lock_storeifref
|
||||
.global arm64_lock_storeifref2
|
||||
.global arm64_lock_storeifref_d
|
||||
.global arm64_lock_storeifref2_d
|
||||
.global arm64_lock_decifnot0b
|
||||
@@ -106,10 +107,10 @@ arm64_lock_write_dq:
|
||||
|
||||
|
||||
arm64_lock_xchg_dd:
|
||||
adrp x3, arm64_atomics
|
||||
add x3, x3, #:lo12:arm64_atomics
|
||||
adrp x3, cpuext
|
||||
add x3, x3, #:lo12:cpuext
|
||||
ldr w3, [x3]
|
||||
cbnz w3, arm64_atomic_xchg_dd
|
||||
tbnz w3, #0, arm64_atomic_xchg_dd
|
||||
dmb ish
|
||||
arm64_lock_xchg_dd_0:
|
||||
// address is x0, value is x1, return old value in x0
|
||||
@@ -126,10 +127,10 @@ arm64_atomic_xchg_dd:
|
||||
ret
|
||||
|
||||
arm64_lock_xchg_d:
|
||||
adrp x3, arm64_atomics
|
||||
add x3, x3, #:lo12:arm64_atomics
|
||||
adrp x3, cpuext
|
||||
add x3, x3, #:lo12:cpuext
|
||||
ldr w3, [x3]
|
||||
cbnz w3, arm64_atomic_xchg_d
|
||||
tbnz w3, #0, arm64_atomic_xchg_d
|
||||
dmb ish
|
||||
arm64_lock_xchg_d_0:
|
||||
// address is x0, value is x1, return old value in x0
|
||||
@@ -146,10 +147,10 @@ arm64_atomic_xchg_d:
|
||||
ret
|
||||
|
||||
arm64_lock_xchg_h:
|
||||
adrp x3, arm64_atomics
|
||||
add x3, x3, #:lo12:arm64_atomics
|
||||
adrp x3, cpuext
|
||||
add x3, x3, #:lo12:cpuext
|
||||
ldr w3, [x3]
|
||||
cbnz w3, arm64_atomic_xchg_h
|
||||
tbnz w3, #0, arm64_atomic_xchg_h
|
||||
dmb ish
|
||||
arm64_lock_xchg_h_0:
|
||||
// address is x0, value is x1, return old value in x0
|
||||
@@ -166,10 +167,10 @@ arm64_atomic_xchg_h:
|
||||
ret
|
||||
|
||||
arm64_lock_xchg_b:
|
||||
adrp x3, arm64_atomics
|
||||
add x3, x3, #:lo12:arm64_atomics
|
||||
adrp x3, cpuext
|
||||
add x3, x3, #:lo12:cpuext
|
||||
ldr w3, [x3]
|
||||
cbnz w3, arm64_atomic_xchg_b
|
||||
tbnz w3, #0, arm64_atomic_xchg_b
|
||||
dmb ish
|
||||
arm64_lock_xchg_b_0:
|
||||
// address is x0, value is x1, return old value in x0
|
||||
@@ -186,10 +187,10 @@ arm64_atomic_xchg_b:
|
||||
ret
|
||||
|
||||
arm64_lock_storeifnull:
|
||||
adrp x3, arm64_atomics
|
||||
add x3, x3, #:lo12:arm64_atomics
|
||||
adrp x3, cpuext
|
||||
add x3, x3, #:lo12:cpuext
|
||||
ldr w3, [x3]
|
||||
cbnz w3, arm64_atomic_storeifnull
|
||||
tbnz w3, #0, arm64_atomic_storeifnull
|
||||
dmb ish
|
||||
1:
|
||||
// address is x0, value is x1, x1 store to x0 only if [x0] is 0. return old [x0] value
|
||||
@@ -211,10 +212,10 @@ arm64_atomic_storeifnull:
|
||||
|
||||
|
||||
arm64_lock_storeifnull_d:
|
||||
adrp x3, arm64_atomics
|
||||
add x3, x3, #:lo12:arm64_atomics
|
||||
adrp x3, cpuext
|
||||
add x3, x3, #:lo12:cpuext
|
||||
ldr w3, [x3]
|
||||
cbnz w3, arm64_atomic_storeifnull_d
|
||||
tbnz w3, #0, arm64_atomic_storeifnull_d
|
||||
dmb ish
|
||||
1:
|
||||
// address is x0, value is w1, w1 store to x0 only if [x0] is 0. return old [x0] value
|
||||
@@ -236,10 +237,10 @@ arm64_atomic_storeifnull_d:
|
||||
ret
|
||||
|
||||
arm64_lock_storeifref:
|
||||
adrp x3, arm64_atomics
|
||||
add x3, x3, #:lo12:arm64_atomics
|
||||
adrp x3, cpuext
|
||||
add x3, x3, #:lo12:cpuext
|
||||
ldr w3, [x3]
|
||||
cbnz w3, arm64_atomic_storeifref
|
||||
tbnz w3, #0, arm64_atomic_storeifref
|
||||
dmb ish
|
||||
1:
|
||||
// address is x0, value is x1, x1 store to x0 only if [x0] is x2. return new [x0] value (so x1 or old value)
|
||||
@@ -267,10 +268,10 @@ arm64_atomic_storeifref:
|
||||
ret
|
||||
|
||||
arm64_lock_storeifref_d:
|
||||
adrp x3, arm64_atomics
|
||||
add x3, x3, #:lo12:arm64_atomics
|
||||
adrp x3, cpuext
|
||||
add x3, x3, #:lo12:cpuext
|
||||
ldr w3, [x3]
|
||||
cbnz w3, arm64_atomic_storeifref_d
|
||||
tbnz w3, #0, arm64_atomic_storeifref_d
|
||||
dmb ish
|
||||
1:
|
||||
// address is x0, value is w1, w1 store to x0 only if [x0] is w2. return new [x0] value (so x1 or old value)
|
||||
@@ -298,10 +299,10 @@ arm64_atomic_storeifref_d:
|
||||
ret
|
||||
|
||||
arm64_lock_storeifref2_d:
|
||||
adrp x3, arm64_atomics
|
||||
add x3, x3, #:lo12:arm64_atomics
|
||||
adrp x3, cpuext
|
||||
add x3, x3, #:lo12:cpuext
|
||||
ldr w3, [x3]
|
||||
cbnz w3, arm64_atomic_storeifref2_d
|
||||
tbnz w3, #0, arm64_atomic_storeifref2_d
|
||||
dmb ish
|
||||
1:
|
||||
// address is x0, value is w1, w1 store to x0 only if [x0] is w2. return old [x0] value
|
||||
@@ -321,6 +322,30 @@ arm64_atomic_storeifref2_d:
|
||||
mov w0, w2
|
||||
ret
|
||||
|
||||
arm64_lock_storeifref2:
|
||||
adrp x3, cpuext
|
||||
add x3, x3, #:lo12:cpuext
|
||||
ldr w3, [x3]
|
||||
tbnz w3, #0, arm64_atomic_storeifref2
|
||||
dmb ish
|
||||
1:
|
||||
// address is x0, value is x1, x1 store to x0 only if [x0] is x2. return old [x0] value
|
||||
ldaxr x3, [x0]
|
||||
cmp x2, x3
|
||||
bne 2f
|
||||
stlxr w4, x1, [x0]
|
||||
cbnz w4, 1b
|
||||
2:
|
||||
mov x0, x3
|
||||
ret
|
||||
|
||||
arm64_atomic_storeifref2:
|
||||
dmb ish
|
||||
// address is x0, value is x1, x1 store to x0 only if [x0] is x2. return old [x0] value
|
||||
casal x2, x1, [x0]
|
||||
mov x0, x2
|
||||
ret
|
||||
|
||||
arm64_lock_decifnot0b:
|
||||
dmb ish
|
||||
1:
|
||||
@@ -352,10 +377,10 @@ arm64_lock_decifnot0:
|
||||
ret
|
||||
|
||||
arm64_lock_incif0:
|
||||
adrp x3, arm64_atomics
|
||||
add x3, x3, #:lo12:arm64_atomics
|
||||
adrp x3, cpuext
|
||||
add x3, x3, #:lo12:cpuext
|
||||
ldr w3, [x3]
|
||||
cbnz w3, arm64_atomic_incif0
|
||||
tbnz w3, #0, arm64_atomic_incif0
|
||||
dmb ish
|
||||
1:
|
||||
ldaxr w1, [x0]
|
||||
|
||||
@@ -55,11 +55,15 @@ extern void* arm64_atomic_storeifnull(void*p, void* val);
|
||||
extern void* arm64_lock_storeifref(void*p, void* val, void* ref);
|
||||
extern void* arm64_atomic_storeifref(void*p, void* val, void* ref);
|
||||
|
||||
// Atomically store value to [p] only if [p] is ref. Return old [p] value (so val or old)
|
||||
extern void* arm64_lock_storeifref2(void*p, void* val, void* ref);
|
||||
extern void* arm64_atomic_storeifref2(void*p, void* val, void* ref);
|
||||
|
||||
// Atomically store value to [p] only if [p] is ref. Return new [p] value (so val or old)
|
||||
extern uint32_t arm64_lock_storeifref_d(void*p, uint32_t val, uint32_t ref);
|
||||
extern uint32_t arm64_atomic_storeifref_d(void*p, uint32_t val, uint32_t ref);
|
||||
|
||||
// Atomically store value to [p] only if [p] is ref. Return new [p] value (so val or old)
|
||||
// Atomically store value to [p] only if [p] is ref. Return old [p] value (so ref or old)
|
||||
extern uint32_t arm64_lock_storeifref2_d(void*p, uint32_t val, uint32_t ref);
|
||||
extern uint32_t arm64_atomic_storeifref2_d(void*p, uint32_t val, uint32_t ref);
|
||||
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
#ifndef __ARM64_MAPPING_H__
|
||||
#define __ARM64_MAPPING_H__
|
||||
|
||||
|
||||
/*
|
||||
ARM64 Linux Call Convention
|
||||
|
||||
SP The Stack Pointer.
|
||||
r30 LR The Link Register.
|
||||
r29 FP The Frame Pointer
|
||||
r19…r28 Callee-saved registers
|
||||
r18 The Platform Register, if needed; otherwise a temporary register. See notes.
|
||||
r17 IP1 The second intra-procedure-call temporary register (can be used by call veneers and PLT code); at other times may be used as a temporary register.
|
||||
r16 IP0 The first intra-procedure-call scratch register (can be used by call veneers and PLT code); at other times may be used as a temporary register.
|
||||
r9…r15 Temporary registers
|
||||
r8 Indirect result location register
|
||||
r0…r7 Parameter/result registers
|
||||
|
||||
For SIMD:
|
||||
The first eight registers, v0-v7, are used to pass argument values into a subroutine and to return result values from a function.
|
||||
They may also be used to hold intermediate values within a routine (but, in general, only between subroutine calls).
|
||||
|
||||
Registers v8-v15 must be preserved by a callee across subroutine calls;
|
||||
the remaining registers (v0-v7, v16-v31) do not need to be preserved (or should be preserved by the caller).
|
||||
Additionally, only the bottom 64 bits of each value stored in v8-v15 need to be preserved [8];
|
||||
it is the responsibility of the caller to preserve larger values.
|
||||
|
||||
For SVE:
|
||||
z0-z7 are used to pass scalable vector arguments to a subroutine, and to return scalable vector results from a function.
|
||||
If a subroutine takes at least one argument in scalable vector registers or scalable predicate registers,
|
||||
or returns results in such regisers, the subroutine must ensure that the entire contents of z8-z23 are preserved across the call.
|
||||
In other cases it need only preserve the low 64 bits of z8-z15, as described in SIMD and Floating-Point registers.
|
||||
p0-p3 are used to pass scalable predicate arguments to a subroutine and to return scalable predicate results from a function.
|
||||
If a subroutine takes at least one argument in scalable vector registers or scalable predicate registers,
|
||||
or returns results in such registers, the subroutine must ensure that p4-p15 are preserved across the call.
|
||||
In other cases it need not preserve any scalable predicate register contents.
|
||||
|
||||
*/
|
||||
|
||||
// x86 Register mapping
|
||||
#define xRAX 10
|
||||
#define xRCX 11
|
||||
#define xRDX 12
|
||||
#define xRBX 13
|
||||
#define xRSP 14
|
||||
#define xRBP 15
|
||||
#define xRSI 16
|
||||
#define xRDI 17
|
||||
#define xR8 18
|
||||
#define xR9 19
|
||||
#define xR10 20
|
||||
#define xR11 21
|
||||
#define xR12 22
|
||||
#define xR13 23
|
||||
#define xR14 24
|
||||
#define xR15 25
|
||||
#define xFlags 26
|
||||
#define xRIP 27
|
||||
#define xSavedSP 28
|
||||
|
||||
// convert a x86 register to native according to the register mapping
|
||||
#define TO_NAT(A) (xRAX + (A))
|
||||
|
||||
// 32bits version
|
||||
#define wEAX xRAX
|
||||
#define wECX xRCX
|
||||
#define wEDX xRDX
|
||||
#define wEBX xRBX
|
||||
#define wESP xRSP
|
||||
#define wEBP xRBP
|
||||
#define wESI xRSI
|
||||
#define wEDI xRDI
|
||||
#define wR8 xR8
|
||||
#define wR9 xR9
|
||||
#define wR10 xR10
|
||||
#define wR11 xR11
|
||||
#define wR12 xR12
|
||||
#define wR13 xR13
|
||||
#define wR14 xR14
|
||||
#define wR15 xR15
|
||||
#define wFlags xFlags
|
||||
// scratch registers
|
||||
#define x1 1
|
||||
#define x2 2
|
||||
#define x3 3
|
||||
#define x4 4
|
||||
#define x5 5
|
||||
#define x6 6
|
||||
#define x87pc 7
|
||||
// x87 can be a scratch, but check if it's used as x87 PC and restore if needed in that case
|
||||
// 32bits version of scratch
|
||||
#define w1 x1
|
||||
#define w2 x2
|
||||
#define w3 x3
|
||||
#define w4 x4
|
||||
#define w5 x5
|
||||
#define w6 x6
|
||||
#define w87pc x87pc
|
||||
// emu is r0
|
||||
#define xEmu 0
|
||||
// ARM64 LR
|
||||
#define xLR 30
|
||||
// ARM64 SP is r31 but is a special register
|
||||
#define xSP 31
|
||||
// xZR regs is 31
|
||||
#define xZR 31
|
||||
#define wZR xZR
|
||||
|
||||
// conditions
|
||||
// Z == 1
|
||||
#define cEQ 0b0000
|
||||
// Z != 1
|
||||
#define cNE 0b0001
|
||||
// C == 1
|
||||
#define cCS 0b0010
|
||||
// C == 1
|
||||
#define cHS cCS
|
||||
// C != 1
|
||||
#define cCC 0b0011
|
||||
// C != 1
|
||||
#define cLO cCC
|
||||
// N == 1
|
||||
#define cMI 0b0100
|
||||
// N != 1
|
||||
#define cPL 0b0101
|
||||
// V == 1
|
||||
#define cVS 0b0110
|
||||
// V != 1
|
||||
#define cVC 0b0111
|
||||
// C == 1 && Z == 0
|
||||
#define cHI 0b1000
|
||||
// C !=1 || Z == 1
|
||||
#define cLS 0b1001
|
||||
// N == V
|
||||
#define cGE 0b1010
|
||||
// N != V
|
||||
#define cLT 0b1011
|
||||
// N == V && Z == 0
|
||||
#define cGT 0b1100
|
||||
// N != V || Z == 1
|
||||
#define cLE 0b1101
|
||||
// always
|
||||
#define c__ 0b1110
|
||||
|
||||
//FCMP type of opcode produce:
|
||||
// if any NAN: CV / v1 == v2: ZC / v1 < v2: N / v1 > v2: C
|
||||
|
||||
#endif //__ARM64_MAPPING_H__
|
||||
@@ -25,6 +25,7 @@ arm64_next:
|
||||
#ifdef _WIN32
|
||||
ldr x18, [x0, 3120]
|
||||
#endif
|
||||
mov x1, x27 // xRIP, should not be needed most of the time
|
||||
mov x2, x30 // "from" is in lr, so put in x2
|
||||
add x3, sp, 8*11 // x3 is address to change rip
|
||||
// call the function
|
||||
|
||||
@@ -1849,9 +1849,9 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
snprintf(buff, sizeof(buff), "SWP%s%s %s, %s, [%s]", a.A?"A":"", a.R?"L":"", sf?Xt[Rs]:Wt[Rs], sf?Xt[Rt]:Wt[Rt], XtSp[Rn]);
|
||||
return buff;
|
||||
}
|
||||
// SWPxw
|
||||
// SWP B/H
|
||||
if(isMask(opcode, "0f111000AR1sssss100000nnnnnttttt", &a)) {
|
||||
snprintf(buff, sizeof(buff), "CAS%s%s%s %s, %s, [%s]", a.A?"A":"", a.R?"L":"", sf?"H":"B", Xt[Rs], Xt[Rt], XtSp[Rn]);
|
||||
snprintf(buff, sizeof(buff), "SWP%s%s%s %s, %s, [%s]", a.A?"A":"", a.R?"L":"", sf?"H":"B", Xt[Rs], Xt[Rt], XtSp[Rn]);
|
||||
return buff;
|
||||
}
|
||||
// LDXXXxw
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "x64_signals.h"
|
||||
#include "os.h"
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
@@ -109,7 +110,17 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
LDRH_U12(x1, xEmu, offsetof(x64emu_t, segs[_ES]));
|
||||
PUSH1_32(x1);
|
||||
} else {
|
||||
DEFAULT;
|
||||
INST_NAME("Illegal 06");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_PEND);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
}
|
||||
GETIP(ip);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
UDF(0);
|
||||
*need_epilog = 1;
|
||||
*ok = 0;
|
||||
}
|
||||
break;
|
||||
case 0x07:
|
||||
@@ -119,7 +130,17 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
STRH_U12(x1, xEmu, offsetof(x64emu_t, segs[_ES]));
|
||||
STRw_U12(xZR, xEmu, offsetof(x64emu_t, segs_serial[_ES]));
|
||||
} else {
|
||||
DEFAULT;
|
||||
INST_NAME("Illegal 07");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_PEND);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
}
|
||||
GETIP(ip);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
UDF(0);
|
||||
*need_epilog = 1;
|
||||
*ok = 0;
|
||||
}
|
||||
break;
|
||||
case 0x08:
|
||||
@@ -207,7 +228,17 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
PUSH1_32(x1);
|
||||
SMWRITE();
|
||||
} else {
|
||||
DEFAULT;
|
||||
INST_NAME("Illegal 0E");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_PEND);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
}
|
||||
GETIP(ip);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
UDF(0);
|
||||
*need_epilog = 1;
|
||||
*ok = 0;
|
||||
}
|
||||
break;
|
||||
case 0x0F:
|
||||
@@ -285,7 +316,17 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
PUSH1_32(x1);
|
||||
SMWRITE();
|
||||
} else {
|
||||
DEFAULT;
|
||||
INST_NAME("Illegal 16");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_PEND);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
}
|
||||
GETIP(ip);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
UDF(0);
|
||||
*need_epilog = 1;
|
||||
*ok = 0;
|
||||
}
|
||||
break;
|
||||
case 0x17:
|
||||
@@ -296,7 +337,17 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
STRH_U12(x1, xEmu, offsetof(x64emu_t, segs[_SS]));
|
||||
STRw_U12(xZR, xEmu, offsetof(x64emu_t, segs_serial[_SS]));
|
||||
} else {
|
||||
DEFAULT;
|
||||
INST_NAME("Illegal 17");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_PEND);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
}
|
||||
GETIP(ip);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
UDF(0);
|
||||
*need_epilog = 1;
|
||||
*ok = 0;
|
||||
}
|
||||
break;
|
||||
case 0x18:
|
||||
@@ -362,7 +413,17 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
PUSH1_32(x1);
|
||||
SMWRITE();
|
||||
} else {
|
||||
DEFAULT;
|
||||
INST_NAME("Illegal 1E");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_PEND);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
}
|
||||
GETIP(ip);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
UDF(0);
|
||||
*need_epilog = 1;
|
||||
*ok = 0;
|
||||
}
|
||||
break;
|
||||
case 0x1F:
|
||||
@@ -373,7 +434,17 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
STRH_U12(x1, xEmu, offsetof(x64emu_t, segs[_DS]));
|
||||
STRw_U12(xZR, xEmu, offsetof(x64emu_t, segs_serial[_DS]));
|
||||
} else {
|
||||
DEFAULT;
|
||||
INST_NAME("Illegal 1F");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_PEND);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
}
|
||||
GETIP(ip);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
UDF(0);
|
||||
*need_epilog = 1;
|
||||
*ok = 0;
|
||||
}
|
||||
break;
|
||||
case 0x20:
|
||||
@@ -443,10 +514,20 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
READFLAGS(X_AF|X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_DF);
|
||||
UXTBx(x1, xRAX);
|
||||
CALL_(daa8, x1, 0);
|
||||
CALL_(const_daa8, x1, 0);
|
||||
BFIz(xRAX, x1, 0, 8);
|
||||
} else {
|
||||
DEFAULT;
|
||||
INST_NAME("Illegal 27");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_PEND);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
}
|
||||
GETIP(ip);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
UDF(0);
|
||||
*need_epilog = 1;
|
||||
*ok = 0;
|
||||
}
|
||||
break;
|
||||
case 0x28:
|
||||
@@ -508,10 +589,20 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
READFLAGS(X_AF|X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_DF);
|
||||
UXTBx(x1, xRAX);
|
||||
CALL_(das8, x1, 0);
|
||||
CALL_(const_das8, x1, 0);
|
||||
BFIz(xRAX, x1, 0, 8);
|
||||
} else {
|
||||
DEFAULT;
|
||||
INST_NAME("Illegal 2F");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_PEND);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
}
|
||||
GETIP(ip);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
UDF(0);
|
||||
*need_epilog = 1;
|
||||
*ok = 0;
|
||||
}
|
||||
break;
|
||||
case 0x30:
|
||||
@@ -602,10 +693,20 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
READFLAGS(X_AF);
|
||||
SETFLAGS(X_ALL, SF_SET_DF);
|
||||
UXTHx(x1, xRAX);
|
||||
CALL_(aaa16, x1, 0);
|
||||
CALL_(const_aaa16, x1, 0);
|
||||
BFIz(xRAX, x1, 0, 16);
|
||||
} else {
|
||||
DEFAULT;
|
||||
INST_NAME("Illegal 37");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_PEND);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
}
|
||||
GETIP(ip);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
UDF(0);
|
||||
*need_epilog = 1;
|
||||
*ok = 0;
|
||||
}
|
||||
break;
|
||||
case 0x38:
|
||||
@@ -670,10 +771,20 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
READFLAGS(X_AF);
|
||||
SETFLAGS(X_ALL, SF_SET_DF);
|
||||
UXTHw(x1, xRAX);
|
||||
CALL_(aas16, x1, 0);
|
||||
CALL_(const_aas16, x1, 0);
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
} else {
|
||||
DEFAULT;
|
||||
INST_NAME("Illegal 3F");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_PEND);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
}
|
||||
GETIP(ip);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
UDF(0);
|
||||
*need_epilog = 1;
|
||||
*ok = 0;
|
||||
}
|
||||
break;
|
||||
case 0x40:
|
||||
@@ -805,7 +916,17 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
PUSH2_32(xRSI, xRDI);
|
||||
SMWRITE();
|
||||
} else {
|
||||
DEFAULT;
|
||||
INST_NAME("Illegal 60");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_PEND);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
}
|
||||
GETIP(ip);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
UDF(0);
|
||||
*need_epilog = 1;
|
||||
*ok = 0;
|
||||
}
|
||||
break;
|
||||
case 0x61:
|
||||
@@ -817,7 +938,17 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
POP2_32(xRBX, xRDX);
|
||||
POP2_32(xRCX, xRAX);
|
||||
} else {
|
||||
DEFAULT;
|
||||
INST_NAME("Illegal 61");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_PEND);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
}
|
||||
GETIP(ip);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
UDF(0);
|
||||
*need_epilog = 1;
|
||||
*ok = 0;
|
||||
}
|
||||
break;
|
||||
case 0x62:
|
||||
@@ -836,7 +967,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
B_NEXT_nocond;
|
||||
MARK;
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_br, -1);
|
||||
CALL_S(const_native_br, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
} else {
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
@@ -846,7 +977,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_ud, -1);
|
||||
CALL_S(const_native_ud, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
*need_epilog = 0;
|
||||
@@ -1046,7 +1177,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_priv, -1);
|
||||
CALL_S(const_native_priv, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
*need_epilog = 0;
|
||||
@@ -1062,7 +1193,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_priv, -1);
|
||||
CALL_S(const_native_priv, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
*need_epilog = 0;
|
||||
@@ -1072,7 +1203,6 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
#define GO(GETFLAGS, NO, YES, F) \
|
||||
READFLAGS(F); \
|
||||
i8 = F8S; \
|
||||
BARRIER(BARRIER_MAYBE); \
|
||||
JUMP(addr+i8, 1); \
|
||||
GETFLAGS; \
|
||||
if(dyn->insts[ninst].x64.jmp_insts==-1 || \
|
||||
@@ -1086,7 +1216,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
jump_to_next(dyn, addr+i8, 0, ninst, rex.is32bits); \
|
||||
} else { \
|
||||
/* inside the block, cache transform */ \
|
||||
CacheTransform(dyn, ninst, cacheupd, x1, x2, x3); \
|
||||
CacheTransform(dyn, ninst, cacheupd); \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size);\
|
||||
SKIP_SEVL(i32); \
|
||||
B(i32); \
|
||||
@@ -1336,7 +1466,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
BFIx(eb1, x4, eb2, 8);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
if(arm64_atomics) {
|
||||
if(cpuext.atomics) {
|
||||
SWPALB(x4, x1, ed);
|
||||
} else {
|
||||
MARKLOCK;
|
||||
@@ -1346,7 +1476,6 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
STLXRB(x3, x4, ed);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
SMDMB();
|
||||
}
|
||||
BFIx(gb1, x1, gb2, 8);
|
||||
break;
|
||||
@@ -1363,7 +1492,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETGD;
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
if(!ALIGNED_ATOMICxw) {
|
||||
if(arm64_uscat) {
|
||||
if(cpuext.uscat) {
|
||||
ANDx_mask(x1, ed, 1, 0, 3); // mask = F
|
||||
CMPSw_U12(x1, 16-(1<<(2+rex.w)));
|
||||
B_MARK(cGT);
|
||||
@@ -1372,7 +1501,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
B_MARK(cNE);
|
||||
}
|
||||
}
|
||||
if(arm64_atomics) {
|
||||
if(cpuext.atomics) {
|
||||
SWPALxw(gd, gd, ed);
|
||||
if(!ALIGNED_ATOMICxw) {
|
||||
B_NEXT_nocond;
|
||||
@@ -1395,8 +1524,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
STRxw_U12(gd, ed, 0);
|
||||
MARK2;
|
||||
}
|
||||
SMDMB();
|
||||
if(!ALIGNED_ATOMICxw || !arm64_atomics) {
|
||||
if(!ALIGNED_ATOMICxw || !cpuext.atomics) {
|
||||
MOVxw_REG(gd, x1);
|
||||
}
|
||||
}
|
||||
@@ -1610,7 +1738,23 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("CDQ");
|
||||
SBFXxw(xRDX, xRAX, rex.w?63:31, 1);
|
||||
break;
|
||||
|
||||
case 0x9A:
|
||||
if(rex.is32bits) {
|
||||
DEFAULT;
|
||||
} else {
|
||||
INST_NAME("Illegal 9A");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_PEND);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
}
|
||||
GETIP(ip);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
UDF(0);
|
||||
*need_epilog = 1;
|
||||
*ok = 0;
|
||||
}
|
||||
break;
|
||||
case 0x9B:
|
||||
INST_NAME("FWAIT");
|
||||
break;
|
||||
@@ -2385,7 +2529,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(BOX64DRENV(dynarec_safeflags)) {
|
||||
READFLAGS(X_PEND); // lets play safe here too
|
||||
}
|
||||
fpu_purgecache(dyn, ninst, 1, x1, x2, x3); // using next, even if there no next
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
i32 = F16;
|
||||
retn_to_epilog(dyn, ip, ninst, rex, i32);
|
||||
*need_epilog = 0;
|
||||
@@ -2397,7 +2541,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(BOX64DRENV(dynarec_safeflags)) {
|
||||
READFLAGS(X_PEND); // so instead, force the deferred flags, so it's not too slow, and flags are not lost
|
||||
}
|
||||
fpu_purgecache(dyn, ninst, 1, x1, x2, x3); // using next, even if there no next
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
ret_to_epilog(dyn, ip, ninst, rex);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
@@ -2602,14 +2746,15 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
x87_purgecache(dyn, ninst, 0, x3, x1, x4);
|
||||
if ((BOX64ENV(log)<2 && !BOX64ENV(rolling_log) && !BOX64ENV(dynarec_test)) && tmp) {
|
||||
//GETIP(ip+3+8+8); // read the 0xCC
|
||||
call_n(dyn, ninst, *(void**)(addr+8), tmp);
|
||||
call_n(dyn, ninst, (void*)(addr+8), tmp);
|
||||
SMWRITE2();
|
||||
addr+=8+8;
|
||||
} else {
|
||||
GETIP(ip+1); // read the 0xCC
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
ADDx_U12(x3, xRIP, 8+8+2); // expected return address
|
||||
ADDx_U12(x1, xEmu, (uint32_t)offsetof(x64emu_t, ip)); // setup addr as &emu->ip
|
||||
CALL_(EmuInt3, -1, x3);
|
||||
CALL_(const_int3, -1, x3);
|
||||
SMWRITE2();
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
addr+=8+8;
|
||||
@@ -2626,15 +2771,15 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("INT 3");
|
||||
if(!BOX64ENV(ignoreint3)) {
|
||||
// check if TRAP signal is handled
|
||||
TABLE64(x1, (uintptr_t)my_context);
|
||||
MOV32w(x2, offsetof(box64context_t, signals[SIGTRAP]));
|
||||
TABLE64C(x1, const_context);
|
||||
MOV32w(x2, offsetof(box64context_t, signals[X64_SIGTRAP]));
|
||||
LDRx_REG(x3, x1, x2);
|
||||
//LDRx_U12(x3, x1, offsetof(box64context_t, signals[SIGTRAP]));
|
||||
//LDRx_U12(x3, x1, offsetof(box64context_t, signals[X64_SIGTRAP]));
|
||||
CMPSx_U12(x3, 0);
|
||||
B_MARK(cEQ);
|
||||
GETIP(addr); // update RIP
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_int3, -1);
|
||||
CALL_S(const_native_int3, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
MARK;
|
||||
jump_to_epilog(dyn, addr, 0, ninst);
|
||||
@@ -2652,7 +2797,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
MOV32w(x1, u8);
|
||||
CALL_S(native_int, -1);
|
||||
CALL_S(const_native_int, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
TABLE64(x3, addr); // expected return address
|
||||
CMPSx_REG(xRIP, x3);
|
||||
@@ -2670,7 +2815,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETIP(ip); // priviledged instruction, IP not updated
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
MOV32w(x1, u8);
|
||||
CALL(native_int, -1);
|
||||
CALL_S(const_native_int, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
LOAD_XEMU_REM();
|
||||
TABLE64(x3, addr); // expected return address
|
||||
@@ -2686,7 +2831,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SMEND();
|
||||
GETIP(addr);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL_S(EmuX86Syscall, -1);
|
||||
CALL_S(const_x86syscall, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
TABLE64(x3, addr); // expected return address
|
||||
CMPSx_REG(xRIP, x3);
|
||||
@@ -2705,7 +2850,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
GETIP(addr);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_int3, -1);
|
||||
CALL_S(const_native_int3, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
*need_epilog = 0;
|
||||
@@ -2724,7 +2869,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
MOV32w(x1,u8);
|
||||
CALL(native_int, -1);
|
||||
CALL_S(const_native_int, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
*need_epilog = 0;
|
||||
@@ -2742,7 +2887,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
TBZ_NEXT(wFlags, F_OF);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
MOV32w(x1,4);
|
||||
CALL(native_int, -1);
|
||||
CALL_S(const_native_int, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
}
|
||||
break;
|
||||
@@ -3140,7 +3285,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ANDw_mask(x2, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
}
|
||||
GETEDW(x4, x1, 0);
|
||||
CALL_(rex.w?((void*)rcl64):((void*)rcl32), ed, x4);
|
||||
CALL_(rex.w?const_rcl64:const_rcl32, ed, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 3:
|
||||
@@ -3158,7 +3303,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ANDw_mask(x2, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
}
|
||||
GETEDW(x4, x1, 0);
|
||||
CALL_(rex.w?((void*)rcr64):((void*)rcr32), ed, x4);
|
||||
CALL_(rex.w?const_rcr64:const_rcr32, ed, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 4:
|
||||
@@ -3231,10 +3376,20 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
UBFXx(x1, xRAX, 0, 8); // load AL
|
||||
u8 = F8;
|
||||
MOV32w(x2, u8);
|
||||
CALL_(aam16, x1, 0);
|
||||
CALL_(const_aam16, x1, 0);
|
||||
BFIz(xRAX, x1, 0, 16);
|
||||
} else {
|
||||
DEFAULT;
|
||||
INST_NAME("Illegal D4");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_PEND);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
}
|
||||
GETIP(ip);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
UDF(0);
|
||||
*need_epilog = 1;
|
||||
*ok = 0;
|
||||
}
|
||||
break;
|
||||
case 0xD5:
|
||||
@@ -3244,10 +3399,20 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
UBFXx(x1, xRAX, 0, 16); // load AX
|
||||
u8 = F8;
|
||||
MOV32w(x2, u8);
|
||||
CALL_(aad16, x1, 0);
|
||||
CALL_(const_aad16, x1, 0);
|
||||
BFIz(xRAX, x1, 0, 16);
|
||||
} else {
|
||||
DEFAULT;
|
||||
INST_NAME("Illegal D5");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_PEND);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
}
|
||||
GETIP(ip);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
UDF(0);
|
||||
*need_epilog = 1;
|
||||
*ok = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -3282,7 +3447,6 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
addr = dynarec64_DF(dyn, addr, ip, ninst, rex, rep, ok, need_epilog);
|
||||
break;
|
||||
#define GO(Z) \
|
||||
BARRIER(BARRIER_MAYBE); \
|
||||
JUMP(addr+i8, 1); \
|
||||
if(dyn->insts[ninst].x64.jmp_insts==-1 || \
|
||||
CHECK_CACHE()) { \
|
||||
@@ -3294,7 +3458,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
fpu_purgecache(dyn, ninst, 1, x1, x2, x3); \
|
||||
jump_to_next(dyn, addr+i8, 0, ninst, rex.is32bits); \
|
||||
} else { \
|
||||
CacheTransform(dyn, ninst, cacheupd, x1, x2, x3); \
|
||||
CacheTransform(dyn, ninst, cacheupd); \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size); \
|
||||
SKIP_SEVL(i32); \
|
||||
Bcond(c__, i32); \
|
||||
@@ -3308,6 +3472,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0xE0:
|
||||
INST_NAME("LOOPNZ");
|
||||
READFLAGS(X_ZF);
|
||||
SMEND();
|
||||
i8 = F8S;
|
||||
SUBz_U12(xRCX, xRCX, 1);
|
||||
TBNZ_NEXT(xFlags, F_ZF);
|
||||
@@ -3316,6 +3481,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0xE1:
|
||||
INST_NAME("LOOPZ");
|
||||
READFLAGS(X_ZF);
|
||||
SMEND();
|
||||
i8 = F8S;
|
||||
SUBz_U12(xRCX, xRCX, 1);
|
||||
TBZ_NEXT(xFlags, F_ZF);
|
||||
@@ -3328,7 +3494,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GO(0);
|
||||
break;
|
||||
case 0xE3:
|
||||
INST_NAME("JECXZ");
|
||||
INST_NAME("JRCXZ");
|
||||
i8 = F8S;
|
||||
GO(1);
|
||||
break;
|
||||
@@ -3349,7 +3515,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
u8 = F8;
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_priv, -1);
|
||||
CALL_S(const_native_priv, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
*need_epilog = 0;
|
||||
@@ -3365,7 +3531,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
#endif
|
||||
}
|
||||
#if STEP < 2
|
||||
if (!rex.is32bits && IsNativeCall(addr + i32, rex.is32bits, &dyn->insts[ninst].natcall, &dyn->insts[ninst].retn))
|
||||
if (!rex.is32bits && !dyn->need_reloc && IsNativeCall(addr + i32, rex.is32bits, &dyn->insts[ninst].natcall, &dyn->insts[ninst].retn))
|
||||
tmp = dyn->insts[ninst].pass2choice = 3;
|
||||
else
|
||||
tmp = dyn->insts[ninst].pass2choice = i32?0:1;
|
||||
@@ -3377,8 +3543,14 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags to "dont'care" state
|
||||
if(dyn->last_ip && (addr-dyn->last_ip<0x1000)) {
|
||||
ADDx_U12(x2, xRIP, addr-dyn->last_ip);
|
||||
} else if(dyn->last_ip && (dyn->last_ip-addr<0x1000)) {
|
||||
SUBx_U12(x2, xRIP, dyn->last_ip-addr);
|
||||
} else {
|
||||
MOV64x(x2, addr);
|
||||
if(dyn->need_reloc) {
|
||||
TABLE64(x2, addr);
|
||||
} else {
|
||||
MOV64x(x2, addr);
|
||||
}
|
||||
}
|
||||
PUSH1(x2);
|
||||
MESSAGE(LOG_DUMP, "Native Call to %s (retn=%d)\n", GetBridgeName((void*)(dyn->insts[ninst].natcall - 1)) ?: GetNativeName(GetNativeFnc(dyn->insts[ninst].natcall - 1)), dyn->insts[ninst].retn);
|
||||
@@ -3395,7 +3567,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
x87_purgecache(dyn, ninst, 0, x3, x1, x4);
|
||||
if ((BOX64ENV(log)<2 && !BOX64ENV(rolling_log)) && dyn->insts[ninst].natcall && tmp) {
|
||||
//GETIP(ip+3+8+8); // read the 0xCC
|
||||
call_n(dyn, ninst, *(void**)(dyn->insts[ninst].natcall+2+8), tmp);
|
||||
call_n(dyn, ninst, (void*)(dyn->insts[ninst].natcall+2+8), tmp);
|
||||
SMWRITE2();
|
||||
POP1(xRIP); // pop the return address
|
||||
dyn->last_ip = addr;
|
||||
@@ -3403,9 +3575,10 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETIP_(dyn->insts[ninst].natcall); // read the 0xCC already
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
ADDx_U12(x1, xEmu, (uint32_t)offsetof(x64emu_t, ip)); // setup addr as &emu->ip
|
||||
CALL_S(EmuInt3, -1);
|
||||
CALL_S(const_int3, -1);
|
||||
SMWRITE2();
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
// in case of dyn->need_reloc, the previous GETIP_ will end up in a TABLE64 that will generate a RELOC_CANCELBLOCK as natcall will be out of the mmap space anyway
|
||||
MOV64x(x3, dyn->insts[ninst].natcall);
|
||||
ADDx_U12(x3, x3, 2+8+8);
|
||||
CMPSx_REG(xRIP, x3);
|
||||
@@ -3424,7 +3597,11 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 1:
|
||||
// this is call to next step, so just push the return address to the stack
|
||||
MOV64x(x2, addr);
|
||||
if(dyn->need_reloc) {
|
||||
TABLE64(x2, addr);
|
||||
} else {
|
||||
MOV64x(x2, addr);
|
||||
}
|
||||
PUSH1z(x2);
|
||||
break;
|
||||
default:
|
||||
@@ -3434,8 +3611,13 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags to "dont'care" state
|
||||
}
|
||||
// regular call
|
||||
MOV64x(x2, addr);
|
||||
fpu_purgecache(dyn, ninst, 1, x1, x3, x4);
|
||||
if(dyn->need_reloc) {
|
||||
TABLE64(x2, addr);
|
||||
} else {
|
||||
MOV64x(x2, addr);
|
||||
}
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
//fpu_purgecache(dyn, ninst, 0, x1, x3, x4);
|
||||
PUSH1z(x2);
|
||||
if (BOX64DRENV(dynarec_callret)) {
|
||||
SET_HASCALLRET();
|
||||
@@ -3471,16 +3653,22 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
// jumps out of current dynablock...
|
||||
MARK;
|
||||
j64 = getJumpTableAddress64(addr);
|
||||
MOV64x(x4, j64);
|
||||
if(dyn->need_reloc) {
|
||||
AddRelocTable64JmpTbl(dyn, ninst, addr, STEP);
|
||||
TABLE64_(x4, j64);
|
||||
} else {
|
||||
MOV64x(x4, j64);
|
||||
}
|
||||
LDRx_U12(x4, x4, 0);
|
||||
BR(x4);
|
||||
}
|
||||
CLEARIP();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0xE9:
|
||||
case 0xEB:
|
||||
BARRIER(BARRIER_MAYBE);
|
||||
BARRIER(BARRIER_MAYBE); // there will be a barrier if there is a jump out
|
||||
if(opcode==0xEB && PK(0)==0xFF) {
|
||||
INST_NAME("JMP ib");
|
||||
MESSAGE(LOG_DEBUG, "Hack for EB FF opcode");
|
||||
@@ -3502,11 +3690,11 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(dyn->insts[ninst].x64.jmp_insts==-1) {
|
||||
// out of the block
|
||||
SET_NODF();
|
||||
fpu_purgecache(dyn, ninst, 1, x1, x2, x3);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
jump_to_next(dyn, j64, 0, ninst, rex.is32bits);
|
||||
} else {
|
||||
// inside the block
|
||||
CacheTransform(dyn, ninst, CHECK_CACHE(), x1, x2, x3);
|
||||
CacheTransform(dyn, ninst, CHECK_CACHE());
|
||||
tmp = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size);
|
||||
SKIP_SEVL(tmp);
|
||||
if(tmp==4) {
|
||||
@@ -3519,7 +3707,23 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
*ok = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xEA:
|
||||
if(rex.is32bits) {
|
||||
DEFAULT;
|
||||
} else {
|
||||
INST_NAME("Illegal EA");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_PEND);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
}
|
||||
GETIP(ip);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
UDF(0);
|
||||
*need_epilog = 1;
|
||||
*ok = 0;
|
||||
}
|
||||
break;
|
||||
case 0xEC: /* IN AL, DX */
|
||||
case 0xED: /* IN EAX, DX */
|
||||
case 0xEE: /* OUT DX, AL */
|
||||
@@ -3534,14 +3738,13 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_priv, -1);
|
||||
CALL_S(const_native_priv, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xF0:
|
||||
addr = dynarec64_F0(dyn, addr, ip, ninst, rex, rep, ok, need_epilog);
|
||||
break;
|
||||
@@ -3554,7 +3757,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_priv, -1); // is that a privileged opcodes or an int 1??
|
||||
CALL_S(const_native_priv, -1); // is that a privileged opcodes or an int 1??
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
*need_epilog = 0;
|
||||
@@ -3570,7 +3773,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_priv, -1);
|
||||
CALL_S(const_native_priv, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
*need_epilog = 0;
|
||||
@@ -3656,8 +3859,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
SET_DFNONE();
|
||||
IFX(X_CF|X_OF) {
|
||||
ASRxw(x2, x1, 8);
|
||||
CMPSw_REG_ASR(x2, x1, 16);
|
||||
SXTHw(x1, xRAX);
|
||||
SXTBw(x2, x1);
|
||||
CMPSw_REG(x2, x1);
|
||||
CSETw(x3, cNE);
|
||||
IFX(X_CF) {
|
||||
BFIw(xFlags, x3, F_CF, 1);
|
||||
@@ -3683,7 +3887,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
CBNZw_MARK3(ed);
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_div0, -1);
|
||||
CALL_S(const_native_div0, -1);
|
||||
CLEARIP();
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
@@ -3717,7 +3921,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
CBNZw_MARK3(ed);
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_div0, -1);
|
||||
CALL_S(const_native_div0, -1);
|
||||
CLEARIP();
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
@@ -3849,14 +4053,14 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MESSAGE(LOG_INFO, "Divide by 0 hack\n");
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_div0, -1);
|
||||
CALL_S(const_native_div0, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
} else {
|
||||
if(BOX64ENV(dynarec_div0)) {
|
||||
CBNZx_MARK3(ed);
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_div0, -1);
|
||||
CALL_S(const_native_div0, -1);
|
||||
CLEARIP();
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
@@ -3883,7 +4087,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
CBNZx_MARK3(ed);
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_div0, -1);
|
||||
CALL_S(const_native_div0, -1);
|
||||
CLEARIP();
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
@@ -3898,7 +4102,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
CBNZx_MARK3(ed);
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_div0, -1);
|
||||
CALL_S(const_native_div0, -1);
|
||||
CLEARIP();
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
@@ -3906,7 +4110,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
CBZxw_MARK(xRDX);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
CALL(div64, -1);
|
||||
CALL(const_div64, -1);
|
||||
B_NEXT_nocond;
|
||||
MARK;
|
||||
UDIVx(x2, xRAX, ed);
|
||||
@@ -3939,7 +4143,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
CBNZx_MARK3(wb);
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_div0, -1);
|
||||
CALL_S(const_native_div0, -1);
|
||||
CLEARIP();
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
@@ -3961,7 +4165,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
CBNZx_MARK3(ed);
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_div0, -1);
|
||||
CALL_S(const_native_div0, -1);
|
||||
CLEARIP();
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
@@ -3976,7 +4180,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
CBNZx_MARK3(ed);
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_div0, -1);
|
||||
CALL_S(const_native_div0, -1);
|
||||
CLEARIP();
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
@@ -3992,7 +4196,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
TBNZ_MARK(xRAX, 63);
|
||||
MARK3;
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
CALL((void*)idiv64, -1);
|
||||
CALL(const_idiv64, -1);
|
||||
B_NEXT_nocond;
|
||||
MARK;
|
||||
SDIVx(x2, xRAX, ed);
|
||||
@@ -4034,7 +4238,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_priv, -1);
|
||||
CALL_S(const_native_priv, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
*need_epilog = 0;
|
||||
@@ -4129,10 +4333,12 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
// jumps out of current dynablock...
|
||||
MARK;
|
||||
j64 = getJumpTableAddress64(addr);
|
||||
TABLE64(x4, j64);
|
||||
if(dyn->need_reloc) AddRelocTable64RetEndBlock(dyn, ninst, addr, STEP);
|
||||
TABLE64_(x4, j64);
|
||||
LDRx_U12(x4, x4, 0);
|
||||
BR(x4);
|
||||
}
|
||||
CLEARIP();
|
||||
break;
|
||||
case 3: // CALL FAR Ed
|
||||
if(MODREG) {
|
||||
@@ -4148,24 +4354,6 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
LDH(x3, wback, rex.w?8:4);
|
||||
LDH(x4, xEmu, offsetof(x64emu_t, segs[_CS]));
|
||||
GETIP_(addr);
|
||||
/*
|
||||
if(BOX64DRENV(dynarec_callret)) {
|
||||
SET_HASCALLRET();
|
||||
// Push actual return address
|
||||
if(addr < (dyn->start+dyn->isize)) {
|
||||
// there is a next...
|
||||
j64 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->native_size)):0;
|
||||
ADR_S20(x4, j64);
|
||||
MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
|
||||
} else {
|
||||
MESSAGE(LOG_NONE, "\tCALLRET set return to Jmptable(%p)\n", (void*)addr);
|
||||
j64 = getJumpTableAddress64(addr);
|
||||
TABLE64(x4, j64);
|
||||
LDRx_U12(x4, x4, 0);
|
||||
}
|
||||
STPx_S7_preindex(x4, xRIP, xSP, -16);
|
||||
}
|
||||
*/
|
||||
// not doing callret because call far will exit the dynablock anyway, to be sure to recompute CS segment
|
||||
PUSH1z(x4);
|
||||
PUSH1z(xRIP);
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#include "my_cpuid.h"
|
||||
#include "freq.h"
|
||||
#include "emu/x87emu_private.h"
|
||||
#include "emu/x64shaext.h"
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
@@ -55,12 +54,29 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MAYUSE(s0);
|
||||
MAYUSE(j64);
|
||||
MAYUSE(cacheupd);
|
||||
#if STEP > 1
|
||||
static const int8_t mask_shift8[] = { -7, -6, -5, -4, -3, -2, -1, 0 };
|
||||
#endif
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0x00:
|
||||
if(rex.is32bits) {
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("SLDT EW");
|
||||
if(MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
MOV32w(ed, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
STRH_U12(xZR, wback, 0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
} else {
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0x01:
|
||||
// TODO:, /0 is SGDT. While 0F 01 D0 is XGETBV, etc...
|
||||
nextop = F8;
|
||||
@@ -90,7 +106,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("RDTSCP");
|
||||
NOTEST(x1);
|
||||
if(box64_rdtsc) {
|
||||
CALL_(ReadTSC, x1, x3);
|
||||
CALL_(const_readtsc, x1, x3);
|
||||
} else {
|
||||
MRS_cntvct_el0(x1);
|
||||
}
|
||||
@@ -99,7 +115,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
LSRx(xRDX, x1, 32);
|
||||
MOVw_REG(xRAX, x1); // wipe upper part
|
||||
CALL_(helper_getcpu, x1, x3);
|
||||
CALL_(const_helper_getcpu, x1, x3);
|
||||
MOVw_REG(xRCX, x1); // IA32_TSC, 0 for now
|
||||
break;
|
||||
default:
|
||||
@@ -149,7 +165,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SMEND();
|
||||
GETIP(addr);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL_S(EmuX64Syscall, -1);
|
||||
CALL_S(const_x64syscall, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
TABLE64(x3, addr); // expected return address
|
||||
SUBx_REG(x3, x3, xRIP);
|
||||
@@ -168,10 +184,9 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
}
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_ud, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
UDF(0);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
@@ -184,10 +199,9 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
}
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_ud, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
UDF(0);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
@@ -225,7 +239,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_ud, -1);
|
||||
CALL_S(const_native_ud, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
*need_epilog = 0;
|
||||
@@ -379,6 +393,11 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
|
||||
case 0x19:
|
||||
case 0x1A:
|
||||
case 0x1B:
|
||||
case 0x1C:
|
||||
case 0x1D:
|
||||
case 0x1E:
|
||||
case 0x1F:
|
||||
INST_NAME("NOP (multibyte)");
|
||||
nextop = F8;
|
||||
@@ -443,11 +462,11 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("CVTTPS2PI Gm,Ex");
|
||||
nextop = F8;
|
||||
GETGM(q0);
|
||||
GETEX(v1, 0, 0);
|
||||
GETEXSD(v1, 0, 0);
|
||||
if (BOX64ENV(dynarec_fastround)) {
|
||||
VFCVTZSS(q0, v1);
|
||||
} else {
|
||||
if(arm64_frintts) {
|
||||
if(cpuext.frintts) {
|
||||
VFRINT32ZS(q0, v1);
|
||||
VFCVTZSS(q0, q0);
|
||||
} else {
|
||||
@@ -477,7 +496,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("CVTPS2PI Gm, Ex");
|
||||
nextop = F8;
|
||||
GETGM(q0);
|
||||
GETEX(v1, 0, 0);
|
||||
GETEXSD(v1, 0, 0);
|
||||
if (BOX64ENV(dynarec_fastround)) {
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x3);
|
||||
VFRINTIS(q0, v1);
|
||||
@@ -485,7 +504,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VFCVTZSS(q0, q0);
|
||||
} else {
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x3);
|
||||
if(arm64_frintts) {
|
||||
if(cpuext.frintts) {
|
||||
VFRINT32XS(q0, v1);
|
||||
VFCVTZSS(q0, q0);
|
||||
} else {
|
||||
@@ -520,7 +539,9 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
GETEXSS(s0, 0, 0);
|
||||
FCMPS(v0, s0);
|
||||
IFX(X_CF|X_PF|X_ZF) {
|
||||
FCMPS(v0, s0);
|
||||
}
|
||||
FCOMI(x1, x2);
|
||||
break;
|
||||
case 0x30:
|
||||
@@ -532,7 +553,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_priv, -1);
|
||||
CALL_S(const_native_priv, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
// continue the block
|
||||
@@ -541,7 +562,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("RDTSC");
|
||||
NOTEST(x1);
|
||||
if(box64_rdtsc) {
|
||||
CALL_(ReadTSC, x1, x3);
|
||||
CALL_(const_readtsc, x1, x3);
|
||||
} else {
|
||||
MRS_cntvct_el0(x1);
|
||||
}
|
||||
@@ -711,7 +732,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETEX(q1, 0, 0);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
VEORQ(v0, v0, v0);
|
||||
if(arm64_sha1) {
|
||||
if(cpuext.sha1) {
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
VMOVeS(v1, 0, q0, 3);
|
||||
SHA1H(v1, v1);
|
||||
@@ -735,7 +756,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0xCA:
|
||||
INST_NAME("SHA1MSG2 Gx, Ex");
|
||||
nextop = F8;
|
||||
if(arm64_sha1) {
|
||||
if(cpuext.sha1) {
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
VEXTQ_8(q0, q0, q0, 8);
|
||||
@@ -771,13 +792,13 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETG;
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
ADDx_U12(x1, xEmu, offsetof(x64emu_t, xmm[gd]));
|
||||
CALL(sha1msg2, -1);
|
||||
CALL(const_sha1msg2, -1);
|
||||
}
|
||||
break;
|
||||
case 0xCB:
|
||||
INST_NAME("SHA256RNDS2 Gx, Ex (, XMM0)");
|
||||
nextop = F8;
|
||||
if(arm64_sha2) {
|
||||
if(cpuext.sha2) {
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
d0 = sse_get_reg(dyn, ninst, x1, 0, 0);
|
||||
@@ -817,13 +838,13 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
ADDx_U12(x1, xEmu, offsetof(x64emu_t, xmm[gd]));
|
||||
sse_reflect_reg(dyn, ninst, 0);
|
||||
CALL(sha256rnds2, -1);
|
||||
CALL(const_sha256rnds2, -1);
|
||||
}
|
||||
break;
|
||||
case 0xCC:
|
||||
INST_NAME("SHA256MSG1 Gx, Ex");
|
||||
nextop = F8;
|
||||
if(arm64_sha2) {
|
||||
if(cpuext.sha2) {
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
SHA256SU0(q0, q1);
|
||||
@@ -842,13 +863,13 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETG;
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
ADDx_U12(x1, xEmu, offsetof(x64emu_t, xmm[gd]));
|
||||
CALL(sha256msg1, -1);
|
||||
CALL(const_sha256msg1, -1);
|
||||
}
|
||||
break;
|
||||
case 0xCD:
|
||||
INST_NAME("SHA256MSG2 Gx, Ex");
|
||||
nextop = F8;
|
||||
if(arm64_sha2) {
|
||||
if(cpuext.sha2) {
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
@@ -876,7 +897,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETG;
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
ADDx_U12(x1, xEmu, offsetof(x64emu_t, xmm[gd]));
|
||||
CALL(sha256msg2, -1);
|
||||
CALL(const_sha256msg2, -1);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -935,7 +956,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0xCC:
|
||||
INST_NAME("SHA1RNDS4 Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
if(arm64_sha1) {
|
||||
if(cpuext.sha1) {
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 1);
|
||||
u8 = F8&3;
|
||||
@@ -999,7 +1020,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
ADDx_U12(x1, xEmu, offsetof(x64emu_t, xmm[gd]));
|
||||
MOV32w(x3, u8);
|
||||
CALL(sha1rnds4, -1);
|
||||
CALL(const_sha1rnds4, -1);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1199,7 +1220,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0x5A:
|
||||
INST_NAME("CVTPS2PD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0, 0);
|
||||
GETEXSD(q0, 0, 0);
|
||||
GETGX_empty(q1);
|
||||
FCVTL(q1, q0);
|
||||
break;
|
||||
@@ -1237,13 +1258,9 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETEX(v1, 0, 0);
|
||||
// FMIN/FMAX wll not copy the value if v0[x] is NaN
|
||||
// but x86 will copy if either v0[x] or v1[x] is NaN, so lets force a copy if source is NaN
|
||||
if(BOX64ENV(dynarec_fastnan)) {
|
||||
VFMINQS(v0, v0, v1);
|
||||
} else {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
VFCMGTQS(q0, v1, v0); // 0 is NaN or v1 GT v0, so invert mask for copy
|
||||
VBIFQ(v0, v1, q0);
|
||||
}
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
VFCMGTQS(q0, v1, v0); // 0 is NaN or v1 GT v0, so invert mask for copy
|
||||
VBIFQ(v0, v1, q0);
|
||||
break;
|
||||
case 0x5E:
|
||||
INST_NAME("DIVPS Gx, Ex");
|
||||
@@ -1272,13 +1289,9 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETEX(v1, 0, 0);
|
||||
// FMIN/FMAX wll not copy the value if v0[x] is NaN
|
||||
// but x86 will copy if either v0[x] or v1[x] is NaN, or if values are equals, so lets force a copy if source is NaN
|
||||
if(BOX64ENV(dynarec_fastnan)) {
|
||||
VFMAXQS(v0, v0, v1);
|
||||
} else {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
VFCMGTQS(q0, v0, v1); // 0 is NaN or v0 GT v1, so invert mask for copy
|
||||
VBIFQ(v0, v1, q0);
|
||||
}
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
VFCMGTQS(q0, v0, v1); // 0 is NaN or v0 GT v1, so invert mask for copy
|
||||
VBIFQ(v0, v1, q0);
|
||||
break;
|
||||
case 0x60:
|
||||
INST_NAME("PUNPCKLBW Gm,Em");
|
||||
@@ -1677,7 +1690,6 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
j64 = (uint32_t)(addr+i32_); \
|
||||
else \
|
||||
j64 = addr+i32_; \
|
||||
BARRIER(BARRIER_MAYBE); \
|
||||
JUMP(j64, 1); \
|
||||
GETFLAGS; \
|
||||
if(dyn->insts[ninst].x64.jmp_insts==-1 || \
|
||||
@@ -1690,7 +1702,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
fpu_purgecache(dyn, ninst, 1, x1, x2, x3); \
|
||||
jump_to_next(dyn, j64, 0, ninst, rex.is32bits); \
|
||||
} else { \
|
||||
CacheTransform(dyn, ninst, cacheupd, x1, x2, x3); \
|
||||
CacheTransform(dyn, ninst, cacheupd); \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size); \
|
||||
SKIP_SEVL(i32); \
|
||||
B(i32); \
|
||||
@@ -1743,7 +1755,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("CPUID");
|
||||
NOTEST(x1);
|
||||
MOVx_REG(x1, xRAX);
|
||||
CALL_(my_cpuid, -1, 0);
|
||||
CALL_(const_cpuid, -1, 0);
|
||||
break;
|
||||
case 0xA3:
|
||||
INST_NAME("BT Ed, Gd");
|
||||
@@ -1787,6 +1799,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
WBACK;
|
||||
} else {
|
||||
FAKEED;
|
||||
if (!rex.w && !rex.is32bits && MODREG) { MOVw_REG(ed, ed); }
|
||||
F8;
|
||||
}
|
||||
break;
|
||||
@@ -1874,6 +1887,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
WBACK;
|
||||
} else {
|
||||
FAKEED;
|
||||
if (!rex.w && !rex.is32bits && MODREG) { MOVw_REG(ed, ed); }
|
||||
F8;
|
||||
}
|
||||
break;
|
||||
@@ -1922,18 +1936,18 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0:
|
||||
INST_NAME("FXSAVE Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (FXSAVE)\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
CALL(rex.is32bits?((void*)fpu_fxsave32):((void*)fpu_fxsave64), -1);
|
||||
CALL(rex.is32bits?const_fpu_fxsave32:const_fpu_fxsave64, -1);
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FXRSTOR Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (FXRSTOR)\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
CALL(rex.is32bits?((void*)fpu_fxrstor32):((void*)fpu_fxrstor64), -1);
|
||||
CALL(rex.is32bits?const_fpu_fxrstor32:const_fpu_fxrstor64, -1);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("LDMXCSR Md");
|
||||
@@ -1950,21 +1964,21 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(BOX64ENV(sse_flushto0)) {
|
||||
// try to sync mxcsr with fpsr on the flag side
|
||||
/* mapping is
|
||||
ARM -> X86
|
||||
0 -> 0 // Invalid operation
|
||||
1 -> 2 // Divide by 0
|
||||
2 -> 3 // Overflow
|
||||
3 -> 4 // underflow
|
||||
4 -> 5 // Inexact
|
||||
5 -> 1 // denormal
|
||||
ARM <-> X86
|
||||
0 <-> 0 // Invalid operation
|
||||
1 <-> 2 // Divide by 0
|
||||
2 <-> 3 // Overflow
|
||||
3 <-> 4 // underflow
|
||||
4 <-> 5 // Inexact
|
||||
5 <-> 1 // denormal
|
||||
*/
|
||||
// doing X86 -> ARM here, 0 1 2 3 4 5 -> 0 2 3 4 5 1
|
||||
// doing X86 -> ARM here, 543210 => 432150
|
||||
if(ed!=x1)
|
||||
MOVw_REG(x1, ed); // x1 = 543210
|
||||
RORw(x3, x1, 2); // x3 = 10.....5432
|
||||
BFIw(x1, x3, 1, 4); // x1 = 54320
|
||||
RORw(x3, x3, 32-1); // x3 = 0.....54321
|
||||
BFIw(x1, x3, 5, 1); // x1 = 154320
|
||||
UBFXw(x2, x1, 1, 5); // x2 = 54321
|
||||
BFIw(x1, x2, 2, 4); // x1 = 432110
|
||||
LSRw(x2, x2, 4); // x2 = 5
|
||||
BFIw(x1, x2, 1, 1); // x1 = 432150
|
||||
MRS_fpsr(x2);
|
||||
BFIx(x2, x1, 0, 6);
|
||||
MSR_fpsr(x2);
|
||||
@@ -1974,36 +1988,36 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("STMXCSR Md");
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
LDRw_U12(x4, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
STW(x4, ed, fixedaddress);
|
||||
if(BOX64ENV(sse_flushto0)) {
|
||||
// sync with fpsr, with mask from mxcsr
|
||||
MRS_fpsr(x1);
|
||||
// doing ARM -> X86 here, 543210 => 432150
|
||||
UBFXw(x2, x1, 1, 5); // x2 = 54321
|
||||
BFIw(x1, x2, 2, 4); // x1 = 432110
|
||||
LSRw(x2, x2, 4); // x2 = 5
|
||||
BFIw(x1, x2, 1, 1); // x1 = 432150
|
||||
// doing ARM -> X86 here, 0 1 2 3 4 5 -> 0 2 3 4 5 1
|
||||
RORw(x3, x1, 2); // x3 = 10.....5432
|
||||
BFIw(x1, x3, 1, 4); // x1 = 54320
|
||||
RORw(x3, x3, 32-1); // x3 = 0.....54321
|
||||
BFIw(x1, x3, 5, 1); // x1 = 154320
|
||||
//BFXILw(x3, x4, 7, 6); // this would the mask, but let's ignore that for now
|
||||
BFIw(x4, x1, 0, 6); // inject back the flags
|
||||
}
|
||||
STW(x4, ed, fixedaddress);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("XSAVE Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (XSAVE)\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
MOV32w(x2, rex.w?0:1);
|
||||
CALL((void*)fpu_xsave, -1);
|
||||
CALL(const_fpu_xsave, -1);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("XRSTOR Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (XRSTOR)\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
MOV32w(x2, rex.w?0:1);
|
||||
CALL((void*)fpu_xrstor, -1);
|
||||
CALL(const_fpu_xrstor, -1);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("CLFLUSH Ed");
|
||||
@@ -2012,7 +2026,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(ed!=x1) {
|
||||
MOVx_REG(x1, ed);
|
||||
}
|
||||
CALL_(native_clflush, -1, 0);
|
||||
CALL_(const_native_clflush, -1, 0);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
@@ -2092,18 +2106,23 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
CMPSxw_REG(xRAX, ed);
|
||||
}
|
||||
MOVxw_REG(x1, ed); // save value
|
||||
CSELxw(ed, gd, ed, cEQ);
|
||||
Bcond(cNE, 4 + (rex.w ? 4 : 8));
|
||||
MOVxw_REG(ed, gd);
|
||||
if (!rex.w) { B_NEXT_nocond; }
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 0);
|
||||
LDxw(x1, wback, fixedaddress);
|
||||
UFLAG_IF {emit_cmp32(dyn, ninst, rex, xRAX, x1, x3, x4, x5);}
|
||||
UFLAG_IF {
|
||||
emit_cmp32(dyn, ninst, rex, xRAX, x1, x3, x4, x5);
|
||||
}
|
||||
SUBxw_REG(x4, xRAX, x1);
|
||||
CBNZxw_MARK(x4);
|
||||
// EAX == Ed
|
||||
STxw(gd, wback, fixedaddress);
|
||||
if (!rex.w) { B_NEXT_nocond; }
|
||||
MARK;
|
||||
}
|
||||
MOVxw_REG(xRAX, x1); // upper part of RAX will be erase on 32bits, no mater what
|
||||
MOVxw_REG(xRAX, x1);
|
||||
break;
|
||||
|
||||
case 0xB3:
|
||||
@@ -2343,8 +2362,6 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
GETGD;
|
||||
if(ed!=gd)
|
||||
MOVxw_REG(gd, ed); // to handle ed=0, setting UD gd to 0
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(ed, ed);
|
||||
B_MARK(cEQ);
|
||||
@@ -2379,8 +2396,6 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
GETGD;
|
||||
if(ed!=gd)
|
||||
MOVxw_REG(gd, ed); // to handle ed=0, setting UD gd to 0
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(ed, ed);
|
||||
B_MARK(cEQ);
|
||||
@@ -2591,11 +2606,11 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOV32w(x1, (1<<F_OF)|(1<<F_SF)|(1<<F_ZF)|(1<<F_PF)|(1<<F_AF));
|
||||
BICw(xFlags, xFlags, x1);
|
||||
}
|
||||
if(arm64_rndr) {
|
||||
if(cpuext.rndr) {
|
||||
MRS_rndr(x1);
|
||||
IFX(X_CF) { CSETw(x3, cNE); }
|
||||
} else {
|
||||
CALL(rex.w?((void*)get_random64):((void*)get_random32), x1);
|
||||
CALL(rex.w?const_random64:const_random32, x1);
|
||||
IFX(X_CF) { MOV32w(x3, 1); }
|
||||
}
|
||||
IFX(X_CF) { BFIw(xFlags, x3, F_CF, 1); }
|
||||
@@ -2604,7 +2619,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 7:
|
||||
INST_NAME("RDPID Ed");
|
||||
GETED(0);
|
||||
CALL_(helper_getcpu, ed, x2);
|
||||
CALL_(const_helper_getcpu, ed, x2);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
@@ -2640,6 +2655,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 4:
|
||||
INST_NAME("Unsupported XSAVEC Ed");
|
||||
FAKEED;
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
GETIP(ip);
|
||||
UDF(0);
|
||||
break;
|
||||
case 6:
|
||||
@@ -2650,11 +2667,11 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOV32w(x1, (1<<F_OF)|(1<<F_SF)|(1<<F_ZF)|(1<<F_PF)|(1<<F_AF));
|
||||
BICw(xFlags, xFlags, x1);
|
||||
}
|
||||
if(arm64_rndr) {
|
||||
if(cpuext.rndr) {
|
||||
MRS_rndr(x1);
|
||||
IFX(X_CF) { CSETw(x3, cNE); }
|
||||
} else {
|
||||
CALL(rex.w?((void*)get_random64):((void*)get_random32), x1);
|
||||
CALL(rex.w?const_random64:const_random32, x1);
|
||||
IFX(X_CF) { MOV32w(x3, 1); }
|
||||
}
|
||||
IFX(X_CF) { BFIw(xFlags, x3, F_CF, 1); }
|
||||
@@ -2711,8 +2728,10 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETGM(d0);
|
||||
GETEM(d1, 0);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
UQXTN_32(v1, d1);
|
||||
MOVI_32(v0, 64);
|
||||
UMIN_32(v0, v0, d1); // limit to 0 .. +64 values (will force 32bits upper part to 0)
|
||||
UMIN_32(v0, v0, v1); // limit to 0 .. +64 values
|
||||
NEG_32(v0, v0);
|
||||
UXTL_32(v0, v0);
|
||||
USHL_R_64(d0, d0, v0);
|
||||
@@ -2740,7 +2759,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEM(q0, 0);
|
||||
GETGD;
|
||||
TABLE64(x1, (uintptr_t)&mask_shift8);
|
||||
TABLE64C(x1, const_8b_m7_m6_m5_m4_m3_m2_m1_0);
|
||||
VLDR64_U12(v0, x1, 0); // load shift
|
||||
MOVI_8(v1, 0x80); // load mask
|
||||
VAND(q1, v1, q0);
|
||||
|
||||
@@ -272,6 +272,27 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x7F:
|
||||
switch(rep) {
|
||||
case 2:
|
||||
INST_NAME("MOVDQU Ex,Gx");
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, (nextop&7) + (rex.b<<3));
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
ADDz_REG(x4, x4, ed);
|
||||
VST128(v0, x4, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xAF:
|
||||
switch(rep) {
|
||||
@@ -370,6 +391,27 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xBF:
|
||||
switch(rep) {
|
||||
case 0:
|
||||
INST_NAME("MOVSX Gd, Ew");
|
||||
nextop = F8;
|
||||
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
SXTHxw(gd, ed);
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
LDRSH_REGz(gd, x4, ed);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
@@ -541,7 +583,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(rex.is32bits)
|
||||
addr = dynarec64_6764_32(dyn, addr, ip, ninst, rex, rep, seg, ok, need_epilog);
|
||||
else {
|
||||
DEFAULT;
|
||||
addr = dynarec64_6764(dyn, addr, ip, ninst, rex, rep, seg, ok, need_epilog);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -619,7 +661,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_priv, -1);
|
||||
CALL_S(const_native_priv, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
*need_epilog = 0;
|
||||
@@ -635,7 +677,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_priv, -1);
|
||||
CALL_S(const_native_priv, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
*need_epilog = 0;
|
||||
@@ -1221,7 +1263,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(wback) {ADDx_REG(x6, x6, wback); wback=x6;}
|
||||
if(!rex.w && MODREG) {MOVw_REG(ed, ed);}
|
||||
CBZw_NEXT(x2);
|
||||
CALL_(rex.w?((void*)rcl64):((void*)rcl32), ed, x6);
|
||||
CALL_(rex.w?const_rcl64:const_rcl32, ed, x6);
|
||||
WBACK;
|
||||
break;
|
||||
case 3:
|
||||
@@ -1242,7 +1284,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(wback) {ADDx_REG(x6, x6, wback); wback=x6;}
|
||||
if(!rex.w && MODREG) {MOVw_REG(ed, ed);}
|
||||
CBZw_NEXT(x2);
|
||||
CALL_(rex.w?((void*)rcr64):((void*)rcr32), ed, x6);
|
||||
CALL_(rex.w?const_rcr64:const_rcr32, ed, x6);
|
||||
WBACK;
|
||||
break;
|
||||
case 4:
|
||||
@@ -1416,7 +1458,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
CBNZx_MARK3(ed);
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_div0, -1);
|
||||
CALL_S(const_native_div0, -1);
|
||||
CLEARIP();
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
@@ -1442,7 +1484,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
CBNZx_MARK3(ed);
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_div0, -1);
|
||||
CALL_S(const_native_div0, -1);
|
||||
CLEARIP();
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
@@ -1455,14 +1497,14 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETEDO(x6, 0);
|
||||
CBZxw_MARK(xRDX);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
CALL(div64, -1);
|
||||
CALL(const_div64, -1);
|
||||
B_NEXT_nocond;
|
||||
MARK;
|
||||
if(BOX64ENV(dynarec_div0)) {
|
||||
CBNZx_MARK3(ed);
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_div0, -1);
|
||||
CALL_S(const_native_div0, -1);
|
||||
CLEARIP();
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
@@ -1500,7 +1542,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
CBNZx_MARK3(wb);
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_div0, -1);
|
||||
CALL_S(const_native_div0, -1);
|
||||
CLEARIP();
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
@@ -1520,7 +1562,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
CBNZx_MARK3(ed);
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_div0, -1);
|
||||
CALL_S(const_native_div0, -1);
|
||||
CLEARIP();
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
@@ -1535,7 +1577,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
CBNZx_MARK3(ed);
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_div0, -1);
|
||||
CALL_S(const_native_div0, -1);
|
||||
CLEARIP();
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
@@ -1545,7 +1587,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MVNx_REG(x2, xRDX);
|
||||
CBZxw_MARK(x2);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
CALL((void*)idiv64, -1);
|
||||
CALL(const_idiv64, -1);
|
||||
B_NEXT_nocond;
|
||||
MARK;
|
||||
SDIVx(x2, xRAX, ed);
|
||||
@@ -1626,10 +1668,12 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
// jumps out of current dynablock...
|
||||
MARK;
|
||||
j64 = getJumpTableAddress64(addr);
|
||||
TABLE64(x4, j64);
|
||||
if(dyn->need_reloc) AddRelocTable64RetEndBlock(dyn, ninst, addr, STEP);
|
||||
TABLE64_(x4, j64);
|
||||
LDRx_U12(x4, x4, 0);
|
||||
BR(x4);
|
||||
}
|
||||
CLEARIP();
|
||||
break;
|
||||
case 4: // JMP Ed
|
||||
INST_NAME("JMP Ed");
|
||||
|
||||
@@ -472,6 +472,38 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOV32w(x2, (uint16_t)i16);
|
||||
PUSH1_16(x2);
|
||||
break;
|
||||
case 0x6C:
|
||||
case 0x6D:
|
||||
INST_NAME(opcode == 0x6C ? "INSB" : "INSW");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_PEND);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
}
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL_S(const_native_priv, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
break;
|
||||
case 0x6E:
|
||||
case 0x6F:
|
||||
INST_NAME(opcode == 0x6C ? "OUTSB" : "OUTSW");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_PEND);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
}
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL_S(const_native_priv, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
break;
|
||||
|
||||
case 0x70:
|
||||
case 0x71:
|
||||
@@ -596,9 +628,8 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!ALIGNED_ATOMICH) {
|
||||
TBNZ_MARK(ed, 0);
|
||||
}
|
||||
if(arm64_atomics) {
|
||||
if(cpuext.atomics) {
|
||||
SWPALH(gd, x1, ed);
|
||||
SMDMB();
|
||||
if(!ALIGNED_ATOMICH) {
|
||||
B_MARK2_nocond;
|
||||
}
|
||||
@@ -607,7 +638,6 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
LDAXRH(x1, ed);
|
||||
STLXRH(x3, gd, ed);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
SMDMB();
|
||||
if(!ALIGNED_ATOMICH) {
|
||||
B_MARK2_nocond;
|
||||
}
|
||||
@@ -619,7 +649,6 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
STLXRB(x3, gd, ed);
|
||||
CBNZx_MARK(x3);
|
||||
STRH_U12(gd, ed, 0);
|
||||
SMDMB();
|
||||
MARK2;
|
||||
}
|
||||
BFIz(gd, x1, 0, 16);
|
||||
@@ -670,7 +699,20 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x8D:
|
||||
INST_NAME("LEA Gd, Ed");
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if(MODREG) { // reg <= reg? that's an invalid operation
|
||||
DEFAULT;
|
||||
} else { // mem <= reg
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if (rex.w)
|
||||
MOVx_REG(gd, ed);
|
||||
else
|
||||
BFIx(gd, ed, 0, 16);
|
||||
}
|
||||
break;
|
||||
case 0x8E:
|
||||
INST_NAME("MOV Seg,Ew");
|
||||
nextop = F8;
|
||||
@@ -1284,8 +1326,9 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
ANDw_mask(x2, xRCX, 0, 0b00100);
|
||||
CBZw_NEXT(x2);
|
||||
GETEW(x1, 0);
|
||||
CALL_(rcl16, x1, x3);
|
||||
CALL_(const_rcl16, x1, x3);
|
||||
EWBACK;
|
||||
break;
|
||||
case 3:
|
||||
@@ -1298,8 +1341,9 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
ANDw_mask(x2, xRCX, 0, 0b00100);
|
||||
CBZw_NEXT(x2);
|
||||
GETEW(x1, 0);
|
||||
CALL_(rcr16, x1, x3);
|
||||
CALL_(const_rcr16, x1, x3);
|
||||
EWBACK;
|
||||
break;
|
||||
case 4:
|
||||
@@ -1361,11 +1405,11 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 6:
|
||||
INST_NAME("FNSTENV Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (FNSTENV16)\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3); // maybe only x87, not SSE?
|
||||
BARRIER(BARRIER_FLOAT); // maybe only x87, not SSE?
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
MOV32w(x2, 1);
|
||||
CALL(fpu_savenv, -1);
|
||||
CALL(const_fpu_savenv, -1);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
@@ -1381,25 +1425,69 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 4:
|
||||
INST_NAME("FRSTOR Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (FRSTOR16)\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
CALL(native_frstor16, -1);
|
||||
CALL(const_native_frstor16, -1);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FNSAVE Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (FNSAVE16)\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
CALL(native_fsave16, -1);
|
||||
CALL(reset_fpu, -1);
|
||||
CALL(const_native_fsave16, -1);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xE4: /* IN AL, Ib */
|
||||
case 0xE5: /* IN AX, Ib */
|
||||
case 0xE6: /* OUT Ib, AL */
|
||||
case 0xE7: /* OUT Ib, AX */
|
||||
INST_NAME(opcode==0xE4?"IN AL, Ib":(opcode==0xE5?"IN AX, Ib":(opcode==0xE6?"OUT Ib, AL":"OUT Ib, AX")));
|
||||
if (rex.is32bits && BOX64ENV(ignoreint3)) {
|
||||
F8;
|
||||
} else {
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_PEND);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
}
|
||||
u8 = F8;
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL_S(const_native_priv, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xEC: /* IN AL, DX */
|
||||
case 0xED: /* IN AX, DX */
|
||||
case 0xEE: /* OUT DX, AL */
|
||||
case 0xEF: /* OUT DX, AX */
|
||||
INST_NAME(opcode==0xEC?"IN AL, DX":(opcode==0xED?"IN AX, DX":(opcode==0xEE?"OUT DX, AL":"OUT DX, AX")));
|
||||
if(rex.is32bits && BOX64ENV(ignoreint3))
|
||||
{} else {
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_PEND);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
}
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL_S(const_native_priv, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
}
|
||||
break;
|
||||
case 0xF0:
|
||||
return dynarec64_66F0(dyn, addr, ip, ninst, rex, rep, ok, need_epilog);
|
||||
|
||||
@@ -1506,7 +1594,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
CBNZw_MARK3(ed);
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_div0, -1);
|
||||
CALL_S(const_native_div0, -1);
|
||||
CLEARIP();
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
@@ -1540,7 +1628,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
CBNZw_MARK3(ed);
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_div0, -1);
|
||||
CALL_S(const_native_div0, -1);
|
||||
CLEARIP();
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "../dynarec_helper.h"
|
||||
#include "emu/x64compstrings.h"
|
||||
|
||||
uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog)
|
||||
{
|
||||
@@ -47,9 +46,6 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
MAYUSE(eb2);
|
||||
MAYUSE(j64);
|
||||
#if STEP > 1
|
||||
static const int8_t mask_shift8[] = { -7, -6, -5, -4, -3, -2, -1, 0 };
|
||||
static const int8_t mask_string8[] = { 7, 6, 5, 4, 3, 2, 1, 0 };
|
||||
static const int8_t mask_string16[] = { 15, 14, 13, 12, 11, 10, 9, 8 };
|
||||
static const int8_t round_round[] = { 0, 2, 1, 3};
|
||||
#endif
|
||||
|
||||
@@ -168,6 +164,11 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
|
||||
case 0x18:
|
||||
case 0x19:
|
||||
case 0x1A:
|
||||
case 0x1B:
|
||||
case 0x1C:
|
||||
case 0x1D:
|
||||
case 0x1E:
|
||||
case 0x1F:
|
||||
INST_NAME("NOP (multibyte)");
|
||||
nextop = F8;
|
||||
@@ -233,7 +234,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VFCVTZSQD(q0, v1);
|
||||
SQXTN_32(q0, q0);
|
||||
} else {
|
||||
if(arm64_frintts) {
|
||||
if(cpuext.frintts) {
|
||||
VFRINT32ZDQ(q0, v1);
|
||||
VFCVTZSQD(q0, q0);
|
||||
SQXTN_32(q0, q0);
|
||||
@@ -273,7 +274,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VFCVTZSS(q0, q0);
|
||||
} else {
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x3);
|
||||
if(arm64_frintts) {
|
||||
if(cpuext.frintts) {
|
||||
VFRINT32XDQ(q0, v1);
|
||||
VFCVTZSQD(q0, q0);
|
||||
SQXTN_32(q0, q0);
|
||||
@@ -309,7 +310,9 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
GETEXSD(q0, 0, 0);
|
||||
FCMPD(v0, q0);
|
||||
IFX(X_CF|X_PF|X_ZF) {
|
||||
FCMPD(v0, q0);
|
||||
}
|
||||
FCOMI(x1, x2);
|
||||
break;
|
||||
|
||||
@@ -631,7 +634,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
} else {
|
||||
GETGX_empty(v0);
|
||||
SMREAD();
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff << 4, 15, rex, NULL, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff << 4, 15, rex, NULL, 0, 0);
|
||||
VLD128(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
@@ -769,7 +772,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
case 0xDB:
|
||||
INST_NAME("AESIMC Gx, Ex"); // AES-NI
|
||||
nextop = F8;
|
||||
if(arm64_aes) {
|
||||
if(cpuext.aes) {
|
||||
GETEX(q1, 0, 0);
|
||||
GETGX_empty(q0);
|
||||
AESIMC(q0, q1);
|
||||
@@ -781,13 +784,13 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
MOV32w(x1, gd);
|
||||
CALL(native_aesimc, -1);
|
||||
CALL(const_native_aesimc, -1);
|
||||
}
|
||||
break;
|
||||
case 0xDC:
|
||||
INST_NAME("AESENC Gx, Ex"); // AES-NI
|
||||
nextop = F8;
|
||||
if(arm64_aes) {
|
||||
if(cpuext.aes) {
|
||||
GETEX(q1, 0, 0);
|
||||
GETGX(q0, 1);
|
||||
v0 = fpu_get_scratch(dyn, ninst); // ARM64 internal operation differs a bit from x86_64
|
||||
@@ -804,7 +807,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
} else d0 = -1;
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
MOV32w(x1, gd);
|
||||
CALL(native_aese, -1);
|
||||
CALL(const_native_aese, -1);
|
||||
GETGX(q0, 1);
|
||||
VEORQ(q0, q0, (d0!=-1)?d0:q1);
|
||||
}
|
||||
@@ -812,7 +815,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
case 0xDD:
|
||||
INST_NAME("AESENCLAST Gx, Ex"); // AES-NI
|
||||
nextop = F8;
|
||||
if(arm64_aes) {
|
||||
if(cpuext.aes) {
|
||||
GETEX(q1, 0, 0);
|
||||
GETGX(q0, 1);
|
||||
v0 = fpu_get_scratch(dyn, ninst); // ARM64 internal operation differs a bit from x86_64
|
||||
@@ -828,7 +831,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
} else d0 = -1;
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
MOV32w(x1, gd);
|
||||
CALL(native_aeselast, -1);
|
||||
CALL(const_native_aeselast, -1);
|
||||
GETGX(q0, 1);
|
||||
VEORQ(q0, q0, (d0!=-1)?d0:q1);
|
||||
}
|
||||
@@ -836,7 +839,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
case 0xDE:
|
||||
INST_NAME("AESDEC Gx, Ex"); // AES-NI
|
||||
nextop = F8;
|
||||
if(arm64_aes) {
|
||||
if(cpuext.aes) {
|
||||
GETEX(q1, 0, 0);
|
||||
GETGX(q0, 1);
|
||||
v0 = fpu_get_scratch(dyn, ninst); // ARM64 internal operation differs a bit from x86_64
|
||||
@@ -853,7 +856,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
} else d0 = -1;
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
MOV32w(x1, gd);
|
||||
CALL(native_aesd, -1);
|
||||
CALL(const_native_aesd, -1);
|
||||
GETGX(q0, 1);
|
||||
VEORQ(q0, q0, (d0!=-1)?d0:q1);
|
||||
}
|
||||
@@ -861,7 +864,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
case 0xDF:
|
||||
INST_NAME("AESDECLAST Gx, Ex"); // AES-NI
|
||||
nextop = F8;
|
||||
if(arm64_aes) {
|
||||
if(cpuext.aes) {
|
||||
GETEX(q1, 0, 0);
|
||||
GETGX(q0, 1);
|
||||
v0 = fpu_get_scratch(dyn, ninst); // ARM64 internal operation differs a bit from x86_64
|
||||
@@ -877,7 +880,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
} else d0 = -1;
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
MOV32w(x1, gd);
|
||||
CALL(native_aesdlast, -1);
|
||||
CALL(const_native_aesdlast, -1);
|
||||
GETGX(q0, 1);
|
||||
VEORQ(q0, q0, (d0!=-1)?d0:q1);
|
||||
}
|
||||
@@ -907,10 +910,10 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
REV16x(x1, gd);
|
||||
BFIx(ed, x1, 0, 16);
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<1, (1<<1)-1, rex, NULL, 0, 0);
|
||||
REV16x(x1, gd);
|
||||
STH(x1, ed, fixedaddress);
|
||||
SMWRITE();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -923,7 +926,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGD;
|
||||
IFNATIVE_BEFORE(NF_CF) {
|
||||
if(INVERTED_CARRY_BEFORE) {
|
||||
if(arm64_flagm)
|
||||
if(cpuext.flagm)
|
||||
CFINV();
|
||||
else {
|
||||
MRS_nzcv(x3);
|
||||
@@ -1151,7 +1154,15 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
INST_NAME("PINSRB Gx, ED, Ib");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETED(1);
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
wback = 0;
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff, 0, rex, NULL, 0, 1);
|
||||
LDB(x1, wback, fixedaddress);
|
||||
ed = x1;
|
||||
}
|
||||
u8 = F8;
|
||||
VMOVQBfrom(q0, (u8&15), ed);
|
||||
break;
|
||||
@@ -1238,7 +1249,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
case 0x44:
|
||||
INST_NAME("PCLMULQDQ Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
if(arm64_pmull) {
|
||||
if(cpuext.pmull) {
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 1);
|
||||
u8 = F8;
|
||||
@@ -1276,7 +1287,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
u8 = F8;
|
||||
MOV32w(x4, u8);
|
||||
CALL(native_pclmul, -1);
|
||||
CALL(const_native_pclmul, -1);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1302,7 +1313,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
MOVx_REG(x4, xRAX);
|
||||
u8 = F8;
|
||||
MOV32w(x5, u8);
|
||||
CALL(sse42_compare_string_explicit_len, x1);
|
||||
CALL(const_sse42_compare_string_explicit_len, x1);
|
||||
q0 = sse_get_reg_empty(dyn, ninst, x2, 0);
|
||||
if(u8&0b1000000) {
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
@@ -1312,7 +1323,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
LSRw_IMM(x1, x1, 8);
|
||||
VDUPQB(q1, x1); // load the high 8bits of the mask
|
||||
VEXTQ_8(q0, q0, q1, 8); // low and hig bits mask
|
||||
TABLE64(x2, (uintptr_t)&mask_string8);
|
||||
TABLE64C(x2, const_8b_7_6_5_4_3_2_1_0);
|
||||
VLDR64_U12(q1, x2, 0); // load shift
|
||||
VDUPQ_64(q1, q1, 0);
|
||||
USHLQ_8(q0, q0, q1); // extract 1 bit
|
||||
@@ -1322,7 +1333,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
break;
|
||||
case 0b01:
|
||||
VDUPQH(q0, x1); // load the 8bits of the mask
|
||||
TABLE64(x2, (uintptr_t)&mask_string16);
|
||||
TABLE64C(x2, const_8b_15_14_13_12_11_10_9_8);
|
||||
VLDR64_U12(q1, x2, 0); // load shift
|
||||
UXTL_8(q1, q1); // extend mask to 16bits
|
||||
USHLQ_16(q0, q0, q1); // extract 1 bit
|
||||
@@ -1354,7 +1365,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
// transform that a mask in x1
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
VSHL_8(q0, q0, 7); // keep only bit 0x80
|
||||
TABLE64(x1, (uintptr_t)&mask_shift8);
|
||||
TABLE64C(x1, const_8b_m7_m6_m5_m4_m3_m2_m1_0);
|
||||
VLDR64_U12(q1, x1, 0); // load shift
|
||||
USHL_8(q0, q0, q1); // shift
|
||||
UADDLV_8(q0, q0); // accumulate
|
||||
@@ -1366,7 +1377,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
VSHL_8(d0, q0, 7); // keep only bit 0x80
|
||||
TABLE64(x1, (uintptr_t)&mask_shift8);
|
||||
TABLE64C(x1, const_8b_m7_m6_m5_m4_m3_m2_m1_0);
|
||||
VLDR64_U12(q1, x1, 0); // load shift
|
||||
USHL_8(d0, d0, q1); // shift
|
||||
UADDLV_8(d0, d0); // accumulate
|
||||
@@ -1390,10 +1401,10 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
CMPSw_REG(x3, x4);
|
||||
CSELw(x3, x3, x4, cLT); // x3 is lmem
|
||||
CMPSw_REG(x2, x4);
|
||||
CSELw(x2, x2, x4, cLT); // x2 is lreg
|
||||
CMPSw_REG(x2, x3);
|
||||
CSELw(x5, x3, x2, cLT); // x5 is max(lmem, lreg)
|
||||
CSELw(x2, x2, x3, cLT); // x2 is min(lmem, lreg)
|
||||
CSELw(x6, x2, x4, cLT); // x6 is lreg
|
||||
CMPSw_REG(x6, x3);
|
||||
CSELw(x5, x3, x6, cLT); // x5 is max(lmem, lreg)
|
||||
CSELw(x2, x6, x3, cLT); // x2 is min(lmem, lreg)
|
||||
// x2 is min length 0-n_packed
|
||||
MVNw_REG(x4, xZR);
|
||||
LSLw_REG(x87pc, x4, x2);
|
||||
@@ -1429,7 +1440,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
BFIw(xFlags, x5, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
CMPSw_REG(x2, x4);
|
||||
CMPSw_REG(x6, x4);
|
||||
CSETw(x5, cLT);
|
||||
BFIw(xFlags, x5, F_SF, 1);
|
||||
}
|
||||
@@ -1471,7 +1482,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
MOVw_REG(x4, xRAX);
|
||||
u8 = F8;
|
||||
MOV32w(x5, u8);
|
||||
CALL(sse42_compare_string_explicit_len, x1);
|
||||
CALL(const_sse42_compare_string_explicit_len, x1);
|
||||
}
|
||||
if(u8&0b1000000) {
|
||||
CBNZw_MARK(x1);
|
||||
@@ -1507,7 +1518,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
u8 = F8;
|
||||
MOV32w(x3, u8);
|
||||
CALL(sse42_compare_string_implicit_len, x1);
|
||||
CALL(const_sse42_compare_string_implicit_len, x1);
|
||||
q0 = sse_get_reg_empty(dyn, ninst, x2, 0);
|
||||
if(u8&0b1000000) {
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
@@ -1517,7 +1528,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
LSRw_IMM(x1, x1, 8);
|
||||
VDUPQB(q1, x1); // load the high 8bits of the mask
|
||||
VEXTQ_8(q0, q0, q1, 8); // low and hig bits mask
|
||||
TABLE64(x2, (uintptr_t)&mask_string8);
|
||||
TABLE64C(x2, const_8b_7_6_5_4_3_2_1_0);
|
||||
VLDR64_U12(q1, x2, 0); // load shift
|
||||
VDUPQ_64(q1, q1, 0);
|
||||
USHLQ_8(q0, q0, q1); // extract 1 bit
|
||||
@@ -1527,7 +1538,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
break;
|
||||
case 0b01:
|
||||
VDUPQH(q0, x1); // load the 8bits of the mask
|
||||
TABLE64(x2, (uintptr_t)&mask_string16);
|
||||
TABLE64C(x2, const_8b_15_14_13_12_11_10_9_8);
|
||||
VLDR64_U12(q1, x2, 0); // load shift
|
||||
UXTL_8(q1, q1); // extend mask to 16bits
|
||||
USHLQ_16(q0, q0, q1); // extract 1 bit
|
||||
@@ -1561,7 +1572,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
u8 = F8;
|
||||
MOV32w(x3, u8);
|
||||
CALL(sse42_compare_string_implicit_len, x1);
|
||||
CALL(const_sse42_compare_string_implicit_len, x1);
|
||||
CBNZw_MARK(x1);
|
||||
MOV32w(xRCX, (u8&1)?8:16);
|
||||
B_NEXT_nocond;
|
||||
@@ -1596,7 +1607,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
u8 = F8;
|
||||
MOV32w(x4, u8);
|
||||
CALL(native_aeskeygenassist, -1);
|
||||
CALL(const_native_aeskeygenassist, -1);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -1752,7 +1763,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
VFCVTZSQS(v0, v0);
|
||||
} else {
|
||||
if(arm64_frintts) {
|
||||
if(cpuext.frintts) {
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x3);
|
||||
VFRINT32XSQ(v0, v1); // handle overflow
|
||||
VFCVTZSQS(v0, v0);
|
||||
@@ -1807,13 +1818,9 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETEX(v1, 0, 0);
|
||||
// FMIN/FMAX wll not copy the value if v0[x] is NaN
|
||||
// but x86 will copy if either v0[x] or v1[x] is NaN, so lets force a copy if source is NaN
|
||||
if(BOX64ENV(dynarec_fastnan)) {
|
||||
VFMINQD(v0, v0, v1);
|
||||
} else {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
VFCMGTQD(q0, v1, v0); // 0 is NaN or v1 GT v0, so invert mask for copy
|
||||
VBIFQ(v0, v1, q0);
|
||||
}
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
VFCMGTQD(q0, v1, v0); // 0 is NaN or v1 GT v0, so invert mask for copy
|
||||
VBIFQ(v0, v1, q0);
|
||||
break;
|
||||
case 0x5E:
|
||||
INST_NAME("DIVPD Gx, Ex");
|
||||
@@ -1842,13 +1849,9 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETEX(v1, 0, 0);
|
||||
// FMIN/FMAX wll not copy the value if v0[x] is NaN
|
||||
// but x86 will copy if either v0[x] or v1[x] is NaN, or if values are equals, so lets force a copy if source is NaN
|
||||
if(BOX64ENV(dynarec_fastnan)) {
|
||||
VFMAXQD(v0, v0, v1);
|
||||
} else {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
VFCMGTQD(q0, v0, v1); // 0 is NaN or v0 GT v1, so invert mask for copy
|
||||
VBIFQ(v0, v1, q0);
|
||||
}
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
VFCMGTQD(q0, v0, v1); // 0 is NaN or v0 GT v1, so invert mask for copy
|
||||
VBIFQ(v0, v1, q0);
|
||||
break;
|
||||
case 0x60:
|
||||
INST_NAME("PUNPCKLBW Gx, Ex");
|
||||
@@ -2514,7 +2517,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(ed!=x1) {
|
||||
MOVx_REG(x1, ed);
|
||||
}
|
||||
CALL_(native_clflush, -1, 0);
|
||||
CALL_(const_native_clflush, -1, 0);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("CLFLUSHOPT Ed");
|
||||
@@ -2523,7 +2526,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(ed!=x1) {
|
||||
MOVx_REG(x1, ed);
|
||||
}
|
||||
CALL_(native_clflush, -1, 0);
|
||||
CALL_(const_native_clflush, -1, 0);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
@@ -2757,8 +2760,9 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
RBITw(x1, x1); // reverse
|
||||
CLZw(x1, x1); // x2 gets leading 0 == BSF
|
||||
MARK;
|
||||
if(!MODREG) MARK; // value gets written on 0 input only if input is a memory it seems
|
||||
BFIx(gd, x1, 0, 16);
|
||||
if(MODREG) MARK;
|
||||
IFX(X_ZF) {
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(x2, cEQ); //ZF not set
|
||||
@@ -2794,8 +2798,9 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
CLZw(x2, x1); // x2 gets leading 0
|
||||
SUBw_U12(x2, x2, 15);
|
||||
NEGw_REG(x1, x2); // complement
|
||||
MARK;
|
||||
if(!MODREG) MARK;
|
||||
BFIx(gd, x1, 0, 16);
|
||||
if(MODREG) MARK;
|
||||
IFX(X_ZF) {
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(x2, cEQ); //ZF not set
|
||||
@@ -3042,7 +3047,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEX(q0, 0, 0);
|
||||
GETGD;
|
||||
TABLE64(x2, 0x0706050403020100LL);
|
||||
TABLE64_(x2, 0x0706050403020100LL);
|
||||
VDUPQD(v0, x2);
|
||||
VSHRQ_8(q1, q0, 7);
|
||||
USHLQ_8(q1, q1, v0); // shift
|
||||
@@ -3188,7 +3193,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VFCVTZSQD(v0, v1); // convert double -> int64
|
||||
SQXTN_32(v0, v0); // convert int64 -> int32 with saturation in lower part, RaZ high part
|
||||
} else {
|
||||
if(arm64_frintts) {
|
||||
if(cpuext.frintts) {
|
||||
VFRINT32ZDQ(v0, v1); // handle overflow
|
||||
VFCVTZSQD(v0, v0); // convert double -> int64
|
||||
SQXTN_32(v0, v0); // convert int64 -> int32 with saturation in lower part, RaZ high part
|
||||
|
||||
@@ -64,7 +64,9 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
VLD64(v1, ed, fixedaddress);
|
||||
}
|
||||
FCMPD(v0, v1);
|
||||
IFX(X_CF|X_PF|X_ZF) {
|
||||
FCMPD(v0, v1);
|
||||
}
|
||||
FCOMI(x1, x2);
|
||||
break;
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
BFIx(ed, x6, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
if(arm64_atomics) {
|
||||
if(cpuext.atomics) {
|
||||
UFLAG_IF {
|
||||
LDADDALH(x5, x1, wback);
|
||||
emit_add16(dyn, ninst, x1, x5, x3, x4);
|
||||
@@ -74,7 +74,6 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
STLXRH(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
SMDMB();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -90,7 +89,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
BFIx(ed, x6, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
if(arm64_atomics) {
|
||||
if(cpuext.atomics) {
|
||||
UFLAG_IF {
|
||||
LDSETALH(x5, x1, wback);
|
||||
emit_or16(dyn, ninst, x1, x5, x3, x4);
|
||||
@@ -104,7 +103,6 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
STLXRH(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
SMDMB();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -128,7 +126,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
if(!ALIGNED_ATOMICH) {
|
||||
if(arm64_uscat) {
|
||||
if(cpuext.uscat) {
|
||||
ANDx_mask(x1, wback, 1, 0, 3); // mask = F
|
||||
CMPSw_U12(x1, 0xF);
|
||||
B_MARK3(cGE);
|
||||
@@ -138,7 +136,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
}
|
||||
// Aligned version
|
||||
if(arm64_atomics) {
|
||||
if(cpuext.atomics) {
|
||||
MOVw_REG(x1, x6);
|
||||
CASALH(x1, gd, wback);
|
||||
} else {
|
||||
@@ -168,7 +166,6 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
}
|
||||
MARK;
|
||||
SMDMB();
|
||||
// Common part (and fallback for EAX != Ed)
|
||||
UFLAG_IF {emit_cmp16(dyn, ninst, x6, x1, x3, x4, x5);}
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
@@ -187,7 +184,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
BFIx(ed, x5, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
if(arm64_atomics) {
|
||||
if(cpuext.atomics) {
|
||||
LDADDALH(x5, x1, wback);
|
||||
} else {
|
||||
MARKLOCK;
|
||||
@@ -196,7 +193,6 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
STLXRH(x3, x4, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
SMDMB();
|
||||
IFX(X_ALL|X_PEND) {
|
||||
MOVxw_REG(x2, x1);
|
||||
emit_add16(dyn, ninst, x2, x5, x3, x4);
|
||||
@@ -228,7 +224,6 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
emit_adc16(dyn, ninst, x1, x5, x3, x4);
|
||||
STLXRH(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
SMDMB();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -244,7 +239,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
BFIx(ed, x6, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
if(arm64_atomics) {
|
||||
if(cpuext.atomics) {
|
||||
MVNw_REG(x3, gd);
|
||||
UFLAG_IF {
|
||||
LDCLRALH(x3, x1, wback);
|
||||
@@ -259,7 +254,6 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
STLXRH(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
SMDMB();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -286,7 +280,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOV32w(x5, i16);
|
||||
if(!ALIGNED_ATOMICH) {
|
||||
if(arm64_uscat) {
|
||||
if(cpuext.uscat) {
|
||||
ANDx_mask(x1, wback, 1, 0, 3); // mask = F
|
||||
CMPSw_U12(x1, 0xF);
|
||||
B_MARK(cGE);
|
||||
@@ -295,7 +289,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
B_MARK(cNE);
|
||||
}
|
||||
}
|
||||
if(arm64_atomics) {
|
||||
if(cpuext.atomics) {
|
||||
UFLAG_IF {
|
||||
LDADDALH(x5, x1, wback);
|
||||
} else {
|
||||
@@ -308,7 +302,6 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
STLXRH(x3, x4, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
SMDMB();
|
||||
if(!ALIGNED_ATOMICH) {
|
||||
B_MARK2_nocond;
|
||||
MARK; // unaligned! also, not enough
|
||||
@@ -320,7 +313,6 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
STLXRB(x3, x4, wback);
|
||||
CBNZx_MARK(x3);
|
||||
STRH_U12(x4, wback, 0); // put the whole value
|
||||
SMDMB();
|
||||
}
|
||||
MARK2;
|
||||
UFLAG_IF {
|
||||
@@ -341,7 +333,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
if(!i64) {MOV32w(x5, i16);}
|
||||
if(arm64_atomics) {
|
||||
if(cpuext.atomics) {
|
||||
UFLAG_IF {
|
||||
LDSETALH(x5, x1, wback);
|
||||
emit_or16c(dyn, ninst, x1, i16, x3, x4);
|
||||
@@ -361,7 +353,6 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
STLXRH(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
SMDMB();
|
||||
}
|
||||
break;
|
||||
case 2: //ADC
|
||||
@@ -384,7 +375,6 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
emit_adc16(dyn, ninst, x1, x5, x3, x4);
|
||||
STLXRH(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
SMDMB();
|
||||
}
|
||||
break;
|
||||
case 3: //SBB
|
||||
@@ -407,7 +397,6 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
emit_sbb16(dyn, ninst, x1, x5, x3, x4);
|
||||
STLXRH(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
SMDMB();
|
||||
}
|
||||
break;
|
||||
case 4: //AND
|
||||
@@ -423,7 +412,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
i64 = convert_bitmask_w(i16);
|
||||
if(arm64_atomics) {
|
||||
if(cpuext.atomics) {
|
||||
MOV32w(x5, ~i16);
|
||||
UFLAG_IF {
|
||||
LDCLRALH(x5, x1, wback);
|
||||
@@ -447,7 +436,6 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
STLXRH(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
SMDMB();
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -466,7 +454,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOV32w(x5, i16);
|
||||
if(!ALIGNED_ATOMICH) {
|
||||
if(arm64_uscat) {
|
||||
if(cpuext.uscat) {
|
||||
ANDx_mask(x1, wback, 1, 0, 3); // mask = F
|
||||
CMPSw_U12(x1, 0xF);
|
||||
B_MARK(cGE);
|
||||
@@ -475,7 +463,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
B_MARK(cNE);
|
||||
}
|
||||
}
|
||||
if(arm64_atomics) {
|
||||
if(cpuext.atomics) {
|
||||
NEGw_REG(x4, x5);
|
||||
UFLAG_IF {
|
||||
LDADDALH(x4, x1, wback);
|
||||
@@ -489,7 +477,6 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
STLXRH(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
SMDMB();
|
||||
if(!ALIGNED_ATOMICH) {
|
||||
B_MARK2_nocond;
|
||||
MARK; // unaligned! also, not enough
|
||||
@@ -501,7 +488,6 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
STLXRB(x3, x4, wback);
|
||||
CBNZx_MARK(x3);
|
||||
STRH_U12(x4, wback, 0); // put the whole value
|
||||
SMDMB();
|
||||
}
|
||||
MARK2;
|
||||
UFLAG_IF {
|
||||
@@ -522,7 +508,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
i64 = convert_bitmask_w(i16);
|
||||
if(arm64_atomics) {
|
||||
if(cpuext.atomics) {
|
||||
UFLAG_IF {
|
||||
LDEORALH(x5, x1, wback);
|
||||
emit_xor16c(dyn, ninst, x1, i16, x3, x4);
|
||||
@@ -539,7 +525,6 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
emit_xor16(dyn, ninst, x1, x5, x3, x4);
|
||||
STLXRH(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
SMDMB();
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -574,7 +559,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
BFIx(ed, x6, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
if(arm64_atomics) {
|
||||
if(cpuext.atomics) {
|
||||
MOV32w(x3, 1);
|
||||
UFLAG_IF {
|
||||
LDADDALH(x3, x1, wback);
|
||||
@@ -589,7 +574,6 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
STLXRH(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
SMDMB();
|
||||
}
|
||||
break;
|
||||
case 1: //DEC Ew
|
||||
@@ -602,7 +586,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
BFIx(ed, x6, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
if(arm64_atomics) {
|
||||
if(cpuext.atomics) {
|
||||
MOV32w(x3, -1);
|
||||
UFLAG_IF {
|
||||
LDADDALH(x3, x1, wback);
|
||||
@@ -617,7 +601,6 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
STLXRH(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
SMDMB();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -45,12 +45,6 @@ uintptr_t dynarec64_66F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
MAYUSE(j64);
|
||||
#if STEP > 1
|
||||
static const int8_t mask_shift8[] = { -7, -6, -5, -4, -3, -2, -1, 0 };
|
||||
static const int8_t mask_string8[] = { 7, 6, 5, 4, 3, 2, 1, 0 };
|
||||
static const int8_t mask_string16[] = { 15, 14, 13, 12, 11, 10, 9, 8 };
|
||||
static const int8_t round_round[] = { 0, 2, 1, 3};
|
||||
#endif
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
@@ -63,7 +57,7 @@ uintptr_t dynarec64_66F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
nextop = F8;
|
||||
GETEW(x1, 0);
|
||||
GETGD;
|
||||
if(arm64_crc32) {
|
||||
if(cpuext.crc32) {
|
||||
CRC32CH(gd, gd, ed);
|
||||
} else {
|
||||
MOV32w(x2, 0x82f63b78);
|
||||
|
||||
@@ -45,12 +45,6 @@ uintptr_t dynarec64_66F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
MAYUSE(j64);
|
||||
#if STEP > 1
|
||||
static const int8_t mask_shift8[] = { -7, -6, -5, -4, -3, -2, -1, 0 };
|
||||
static const int8_t mask_string8[] = { 7, 6, 5, 4, 3, 2, 1, 0 };
|
||||
static const int8_t mask_string16[] = { 15, 14, 13, 12, 11, 10, 9, 8 };
|
||||
static const int8_t round_round[] = { 0, 2, 1, 3};
|
||||
#endif
|
||||
|
||||
switch(opcode) {
|
||||
case 0xB8:
|
||||
|
||||
@@ -230,7 +230,9 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
}
|
||||
FCMPS(v0, s0);
|
||||
IFX(X_CF|X_PF|X_ZF) {
|
||||
FCMPS(v0, s0);
|
||||
}
|
||||
FCOMI(x1, x2);
|
||||
break;
|
||||
default:
|
||||
@@ -1246,6 +1248,12 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x9C:
|
||||
INST_NAME("PUSHF");
|
||||
READFLAGS(X_ALL);
|
||||
PUSH1z(xFlags);
|
||||
break;
|
||||
|
||||
case 0xA1:
|
||||
INST_NAME("MOV EAX,Od");
|
||||
u64 = F32;
|
||||
@@ -1424,66 +1432,57 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
|
||||
|
||||
#define GO(NO, YES) \
|
||||
BARRIER(BARRIER_MAYBE); \
|
||||
#define GO(Z) \
|
||||
JUMP(addr+i8, 1); \
|
||||
if(dyn->insts[ninst].x64.jmp_insts==-1 || \
|
||||
CHECK_CACHE()) { \
|
||||
/* out of the block */ \
|
||||
i32 = dyn->insts[ninst].epilog-(dyn->native_size); \
|
||||
Bcond(NO, i32); \
|
||||
if(Z) {CBNZw(xRCX, i32);} else {CBZw(xRCX, i32);}; \
|
||||
if(dyn->insts[ninst].x64.jmp_insts==-1) { \
|
||||
if(!(dyn->insts[ninst].x64.barrier&BARRIER_FLOAT)) \
|
||||
fpu_purgecache(dyn, ninst, 1, x1, x2, x3); \
|
||||
jump_to_next(dyn, addr+i8, 0, ninst, rex.is32bits); \
|
||||
} else { \
|
||||
CacheTransform(dyn, ninst, cacheupd, x1, x2, x3); \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size);\
|
||||
CacheTransform(dyn, ninst, cacheupd); \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size); \
|
||||
SKIP_SEVL(i32); \
|
||||
B(i32); \
|
||||
Bcond(c__, i32); \
|
||||
} \
|
||||
} else { \
|
||||
/* inside the block */ \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size); \
|
||||
SKIP_SEVL(i32); \
|
||||
Bcond(YES, i32); \
|
||||
if(Z) {CBZw(xRCX, i32);} else {CBNZw(xRCX, i32);}; \
|
||||
}
|
||||
case 0xE0:
|
||||
INST_NAME("LOOPNZ (32bits)");
|
||||
READFLAGS(X_ZF);
|
||||
SMEND();
|
||||
i8 = F8S;
|
||||
MOVw_REG(x1, xRCX);
|
||||
SUBw_U12(x1, x1, 1);
|
||||
BFIx(xRCX, x1, 0, 32);
|
||||
CBZw_NEXT(x1); // ECX is 0, no LOOP
|
||||
TSTw_mask(xFlags, 0b011010, 0); //mask=0x40
|
||||
GO(cNE, cEQ);
|
||||
SUBw_U12(xRCX, xRCX, 1);
|
||||
TBNZ_NEXT(xFlags, F_ZF);
|
||||
GO(0);
|
||||
break;
|
||||
case 0xE1:
|
||||
INST_NAME("LOOPZ (32bits)");
|
||||
READFLAGS(X_ZF);
|
||||
SMEND();
|
||||
i8 = F8S;
|
||||
MOVw_REG(x1, xRCX);
|
||||
SUBw_U12(x1, x1, 1);
|
||||
BFIx(xRCX, x1, 0, 32);
|
||||
CBZw_NEXT(x1); // ECX is 0, no LOOP
|
||||
TSTw_mask(xFlags, 0b011010, 0); //mask=0x40
|
||||
GO(cEQ, cNE);
|
||||
SUBw_U12(xRCX, xRCX, 1);
|
||||
TBZ_NEXT(xFlags, F_ZF);
|
||||
GO(0);
|
||||
break;
|
||||
case 0xE2:
|
||||
INST_NAME("LOOP (32bits)");
|
||||
i8 = F8S;
|
||||
MOVw_REG(x1, xRCX);
|
||||
SUBSw_U12(x1, x1, 1);
|
||||
BFIx(xRCX, x1, 0, 32);
|
||||
GO(cEQ, cNE);
|
||||
SUBw_U12(xRCX, xRCX, 1);
|
||||
GO(0);
|
||||
break;
|
||||
case 0xE3:
|
||||
INST_NAME("JECXZ");
|
||||
i8 = F8S;
|
||||
MOVw_REG(x1, xRCX);
|
||||
TSTw_REG(x1, x1);
|
||||
GO(cNE, cEQ);
|
||||
GO(1);
|
||||
break;
|
||||
#undef GO
|
||||
|
||||
@@ -1616,7 +1615,7 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETED32H(x1, 0); // get edd changed addr, so cannot be called 2 times for same op...
|
||||
CBZxw_MARK(xRDX);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
CALL(div64, -1);
|
||||
CALL(const_div64, -1);
|
||||
B_NEXT_nocond;
|
||||
MARK;
|
||||
UDIVx(x2, xRAX, ed);
|
||||
@@ -1666,7 +1665,7 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MVNx_REG(x2, xRDX);
|
||||
CBZxw_MARK(x2);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
CALL((void*)idiv64, -1);
|
||||
CALL(const_idiv64, -1);
|
||||
B_NEXT_nocond;
|
||||
MARK;
|
||||
SDIVx(x2, xRAX, ed);
|
||||
@@ -1748,10 +1747,12 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
// jumps out of current dynablock...
|
||||
MARK;
|
||||
j64 = getJumpTableAddress64(addr);
|
||||
TABLE64(x4, j64);
|
||||
if(dyn->need_reloc) AddRelocTable64RetEndBlock(dyn, ninst, addr, STEP);
|
||||
TABLE64_(x4, j64);
|
||||
LDRx_U12(x4, x4, 0);
|
||||
BR(x4);
|
||||
}
|
||||
CLEARIP();
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "../dynarec_helper.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
|
||||
#define GETGm gd = ((nextop & 0x38) >> 3)
|
||||
|
||||
uintptr_t dynarec64_6764(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int seg, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip;
|
||||
(void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop;
|
||||
uint8_t gd, ed, wback, wb, wb1, wb2, gb1, gb2, eb1, eb2;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
int8_t i8;
|
||||
uint8_t u8;
|
||||
int32_t i32;
|
||||
int64_t j64, i64;
|
||||
int cacheupd = 0;
|
||||
int lock;
|
||||
int v0, v1, s0;
|
||||
MAYUSE(i32);
|
||||
MAYUSE(j64);
|
||||
MAYUSE(v0);
|
||||
MAYUSE(v1);
|
||||
MAYUSE(s0);
|
||||
MAYUSE(lock);
|
||||
MAYUSE(cacheupd);
|
||||
|
||||
rep = 0;
|
||||
while ((opcode == 0xF2) || (opcode == 0xF3)) {
|
||||
rep = opcode - 0xF1;
|
||||
opcode = F8;
|
||||
}
|
||||
|
||||
rex.rex = 0;
|
||||
while (opcode >= 0x40 && opcode <= 0x4f) {
|
||||
rex.rex = opcode;
|
||||
opcode = F8;
|
||||
}
|
||||
|
||||
|
||||
switch (opcode) {
|
||||
|
||||
case 0x89:
|
||||
INST_NAME("MOV Seg:Ed, Gd");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if (MODREG) { // reg <= reg
|
||||
MOVxw_REG(TO_NAT((nextop & 7) + (rex.b << 3)), gd);
|
||||
} else { // mem <= reg
|
||||
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
STRxw_REG(gd, x4, ed);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x8B:
|
||||
INST_NAME("MOV Gd, Seg:Ed");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if (MODREG) { // reg => reg
|
||||
MOVxw_REG(gd, TO_NAT((nextop & 7) + (rex.b << 3)));
|
||||
} else { // mem => reg
|
||||
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
LDRxw_REG(gd, x4, ed);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -89,7 +89,6 @@ uintptr_t dynarec64_67_32(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
break;
|
||||
|
||||
#define GO(NO, YES) \
|
||||
BARRIER(BARRIER_MAYBE); \
|
||||
JUMP(addr+i8, 1); \
|
||||
if(dyn->insts[ninst].x64.jmp_insts==-1 || \
|
||||
CHECK_CACHE()) { \
|
||||
@@ -101,7 +100,7 @@ uintptr_t dynarec64_67_32(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
fpu_purgecache(dyn, ninst, 1, x1, x2, x3); \
|
||||
jump_to_next(dyn, addr+i8, 0, ninst, rex.is32bits); \
|
||||
} else { \
|
||||
CacheTransform(dyn, ninst, cacheupd, x1, x2, x3); \
|
||||
CacheTransform(dyn, ninst, cacheupd); \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size);\
|
||||
SKIP_SEVL(i32); \
|
||||
B(i32); \
|
||||
@@ -116,6 +115,7 @@ uintptr_t dynarec64_67_32(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
INST_NAME("LOOPNZ (16bits)");
|
||||
READFLAGS(X_ZF);
|
||||
i8 = F8S;
|
||||
SMEND();
|
||||
UXTHw(x1, xRCX);
|
||||
SUBw_U12(x1, x1, 1);
|
||||
BFIx(xRCX, x1, 0, 16);
|
||||
@@ -126,6 +126,7 @@ uintptr_t dynarec64_67_32(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
case 0xE1:
|
||||
INST_NAME("LOOPZ (16bits)");
|
||||
READFLAGS(X_ZF);
|
||||
SMEND();
|
||||
i8 = F8S;
|
||||
UXTHw(x1, xRCX);
|
||||
SUBw_U12(x1, x1, 1);
|
||||
@@ -137,6 +138,7 @@ uintptr_t dynarec64_67_32(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
case 0xE2:
|
||||
INST_NAME("LOOP (16bits)");
|
||||
i8 = F8S;
|
||||
SMEND();
|
||||
UXTHw(x1, xRCX);
|
||||
SUBSw_U12(x1, x1, 1);
|
||||
BFIx(xRCX, x1, 0, 16);
|
||||
@@ -145,6 +147,7 @@ uintptr_t dynarec64_67_32(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
case 0xE3:
|
||||
INST_NAME("JCXZ");
|
||||
i8 = F8S;
|
||||
SMEND();
|
||||
TSTw_mask(xRCX, 0, 15); //mask=0xffff
|
||||
GO(cNE, cEQ);
|
||||
break;
|
||||
|
||||
@@ -100,7 +100,7 @@ static int arch_build(dynarec_arm_t* dyn, int ninst, arch_build_t* arch)
|
||||
// got through all naoncache to gather regs assignments
|
||||
int idx;
|
||||
for(int i=0; i<32; ++i)
|
||||
if(dyn->insts[ninst].n.neoncache[i].v!=-1)
|
||||
if(dyn->insts[ninst].n.neoncache[i].v)
|
||||
switch(dyn->insts[ninst].n.neoncache[i].t) {
|
||||
case NEON_CACHE_XMMW:
|
||||
arch->sse = 1;
|
||||
|
||||
@@ -54,9 +54,6 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
MAYUSE(s0);
|
||||
MAYUSE(j64);
|
||||
MAYUSE(cacheupd);
|
||||
#if STEP > 1
|
||||
static const int8_t mask_shift8[] = { -7, -6, -5, -4, -3, -2, -1, 0 };
|
||||
#endif
|
||||
|
||||
rex_t rex = vex.rex;
|
||||
|
||||
@@ -297,7 +294,9 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
GETEXSS(s0, 0, 0);
|
||||
FCMPS(v0, s0);
|
||||
IFX(X_CF|X_PF|X_ZF) {
|
||||
FCMPS(v0, s0);
|
||||
}
|
||||
FCOMI(x1, x2);
|
||||
break;
|
||||
|
||||
@@ -509,7 +508,12 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
case 0x5A:
|
||||
INST_NAME("VCVTPS2PD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX_empty_EX(v0, v1, 0);
|
||||
if (vex.l) {
|
||||
GETGX_empty_EX(v0, v1, 0);
|
||||
} else {
|
||||
GETEXSD(v1, 0, 0);
|
||||
GETGX_empty(v0);
|
||||
}
|
||||
if(vex.l) {
|
||||
GETGY_empty(q0, -1, -1, -1);
|
||||
FCVTL2(q0, v1);
|
||||
@@ -553,20 +557,14 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
case 0x5D:
|
||||
INST_NAME("VMINPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
}
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
|
||||
// FMIN/FMAX wll not copy a NaN if either is NaN
|
||||
// but x86 will copy src2 if either value is NaN, so lets force a copy of Src2 (Ex) if result is NaN
|
||||
if(BOX64ENV(dynarec_fastnan)) {
|
||||
VFMINQS(v0, v2, v1);
|
||||
} else {
|
||||
VFCMGTQS(q0, v1, v2); // 0 if NaN or v1 GT v2, so invert mask for copy
|
||||
if(v0!=v1) VBIFQ(v0, v1, q0);
|
||||
if(v0!=v2) VBITQ(v0, v2, q0);
|
||||
}
|
||||
VFCMGTQS(q0, v1, v2); // 0 if NaN or v1 GT v2, so invert mask for copy
|
||||
if(v0!=v1) VBIFQ(v0, v1, q0);
|
||||
if(v0!=v2) VBITQ(v0, v2, q0);
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
@@ -597,20 +595,14 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
case 0x5F:
|
||||
INST_NAME("VMAXPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
}
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
|
||||
// FMIN/FMAX wll not copy a NaN if either is NaN
|
||||
// but x86 will copy src2 if either value is NaN, so lets force a copy of Src2 (Ex) if result is NaN
|
||||
if(BOX64ENV(dynarec_fastnan)) {
|
||||
VFMAXQS(v0, v2, v1);
|
||||
} else {
|
||||
VFCMGTQS(q0, v2, v1); // 0 if NaN or v2 GT v1, so invert mask for copy
|
||||
if(v0!=v1) VBIFQ(v0, v1, q0);
|
||||
if(v0!=v2) VBITQ(v0, v2, q0);
|
||||
}
|
||||
VFCMGTQS(q0, v2, v1); // 0 if NaN or v2 GT v1, so invert mask for copy
|
||||
if(v0!=v1) VBIFQ(v0, v1, q0);
|
||||
if(v0!=v2) VBITQ(v0, v2, q0);
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
@@ -660,21 +652,21 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
if(BOX64ENV(sse_flushto0)) {
|
||||
// try to sync mxcsr with fpsr on the flag side
|
||||
/* mapping is
|
||||
ARM -> X86
|
||||
0 -> 0 // Invalid operation
|
||||
1 -> 2 // Divide by 0
|
||||
2 -> 3 // Overflow
|
||||
3 -> 4 // underflow
|
||||
4 -> 5 // Inexact
|
||||
5 -> 1 // denormal
|
||||
ARM <-> X86
|
||||
0 <-> 0 // Invalid operation
|
||||
1 <-> 2 // Divide by 0
|
||||
2 <-> 3 // Overflow
|
||||
3 <-> 4 // underflow
|
||||
4 <-> 5 // Inexact
|
||||
5 <-> 1 // denormal
|
||||
*/
|
||||
// doing X86 -> ARM here, 0 1 2 3 4 5 -> 0 2 3 4 5 1
|
||||
// doing X86 -> ARM here, 543210 => 432150
|
||||
if(ed!=x1)
|
||||
MOVw_REG(x1, ed); // x1 = 543210
|
||||
RORw(x3, x1, 2); // x3 = 10.....5432
|
||||
BFIw(x1, x3, 1, 4); // x1 = 54320
|
||||
RORw(x3, x3, 32-1); // x3 = 0.....54321
|
||||
BFIw(x1, x3, 5, 1); // x1 = 154320
|
||||
UBFXw(x2, x1, 1, 5); // x2 = 54321
|
||||
BFIw(x1, x2, 2, 4); // x1 = 432110
|
||||
LSRw(x2, x2, 4); // x2 = 5
|
||||
BFIw(x1, x2, 1, 1); // x1 = 432150
|
||||
MRS_fpsr(x2);
|
||||
BFIx(x2, x1, 0, 6);
|
||||
MSR_fpsr(x2);
|
||||
@@ -684,18 +676,18 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
INST_NAME("VSTMXCSR Md");
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
LDRw_U12(x4, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
STW(x4, ed, fixedaddress);
|
||||
if(BOX64ENV(sse_flushto0)) {
|
||||
// sync with fpsr, with mask from mxcsr
|
||||
MRS_fpsr(x1);
|
||||
// doing ARM -> X86 here, 543210 => 432150
|
||||
UBFXw(x2, x1, 1, 5); // x2 = 54321
|
||||
BFIw(x1, x2, 2, 4); // x1 = 432110
|
||||
LSRw(x2, x2, 4); // x2 = 5
|
||||
BFIw(x1, x2, 1, 1); // x1 = 432150
|
||||
// doing ARM -> X86 here, 0 1 2 3 4 5 -> 0 2 3 4 5 1
|
||||
RORw(x3, x1, 2); // x3 = 10.....5432
|
||||
BFIw(x1, x3, 1, 4); // x1 = 54320
|
||||
RORw(x3, x3, 32-1); // x3 = 0.....54321
|
||||
BFIw(x1, x3, 5, 1); // x1 = 154320
|
||||
//BFXILw(x3, x4, 7, 6); // this would the mask, but let's ignore that for now
|
||||
BFIw(x4, x1, 0, 6); // inject back the flags
|
||||
}
|
||||
STW(x4, ed, fixedaddress);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
|
||||
@@ -132,9 +132,14 @@ uintptr_t dynarec64_AVX_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, i
|
||||
IFX(X_OF) {
|
||||
IFNATIVE(NF_VF) {} else { BFCw(xFlags, F_OF, 1); }
|
||||
}
|
||||
if (BOX64ENV(dynarec_test)) {
|
||||
if (BOX64ENV(dynarec_safeflags)) {
|
||||
// those are UD flags
|
||||
IFX(X_AF) BFCw(xFlags, F_AF, 1);
|
||||
IFX(X_PF) BFCw(xFlags, F_PF, 1);
|
||||
if(BOX64ENV(cputype)) {
|
||||
IFX(X_PF) BFCw(xFlags, F_PF, 1);
|
||||
} else {
|
||||
IFX(X_PF) emit_pf(dyn, ninst, vd, x3);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -171,9 +176,14 @@ uintptr_t dynarec64_AVX_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, i
|
||||
IFX(X_OF) {
|
||||
IFNATIVE(NF_VF) {} else { BFCw(xFlags, F_OF, 1); }
|
||||
}
|
||||
if (BOX64ENV(dynarec_test)) {
|
||||
if (BOX64ENV(dynarec_safeflags)) {
|
||||
// those are UD flags
|
||||
IFX(X_AF) BFCw(xFlags, F_AF, 1);
|
||||
IFX(X_PF) BFCw(xFlags, F_PF, 1);
|
||||
if(BOX64ENV(cputype)) {
|
||||
IFX(X_PF) BFCw(xFlags, F_PF, 1);
|
||||
} else {
|
||||
IFX(X_PF) emit_pf(dyn, ninst, vd, x3);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -184,7 +194,7 @@ uintptr_t dynarec64_AVX_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, i
|
||||
GETVD;
|
||||
IFX(X_CF) {
|
||||
TSTxw_REG(ed, ed);
|
||||
CSETMw(x3, cEQ);
|
||||
CSETMw(x3, cNE);
|
||||
BFIw(xFlags, x3, F_CF, 1);
|
||||
}
|
||||
NEGxw_REG(x3, ed);
|
||||
@@ -211,9 +221,14 @@ uintptr_t dynarec64_AVX_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, i
|
||||
IFX(X_OF) {
|
||||
IFNATIVE(NF_VF) {} else { BFCw(xFlags, F_OF, 1); }
|
||||
}
|
||||
if (BOX64ENV(dynarec_test)) {
|
||||
if (BOX64ENV(dynarec_safeflags)) {
|
||||
// those are UD flags
|
||||
IFX(X_AF) BFCw(xFlags, F_AF, 1);
|
||||
IFX(X_PF) BFCw(xFlags, F_PF, 1);
|
||||
if(BOX64ENV(cputype)) {
|
||||
IFX(X_PF) BFCw(xFlags, F_PF, 1);
|
||||
} else {
|
||||
IFX(X_PF) emit_pf(dyn, ninst, vd, x3);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -259,11 +274,18 @@ uintptr_t dynarec64_AVX_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, i
|
||||
BFIw(xFlags, x3, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_AF) BFCw(xFlags, F_AF, 1);
|
||||
IFX(X_PF) BFCw(xFlags, F_PF, 1);
|
||||
IFX(X_OF) {
|
||||
IFNATIVE(NF_VF) {} else { BFCw(xFlags, F_OF, 1); }
|
||||
}
|
||||
if (BOX64ENV(dynarec_safeflags)) {
|
||||
// those are UD flags
|
||||
IFX(X_AF) BFCw(xFlags, F_AF, 1);
|
||||
if(BOX64ENV(cputype)) {
|
||||
IFX(X_PF) BFCw(xFlags, F_PF, 1);
|
||||
} else {
|
||||
IFX(X_PF) emit_pf(dyn, ninst, vd, x3);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xF7:
|
||||
@@ -273,22 +295,24 @@ uintptr_t dynarec64_AVX_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, i
|
||||
GETGD;
|
||||
GETED(0);
|
||||
GETVD;
|
||||
MOV64xw(x1, 0);
|
||||
UXTBw(x2, vd); // start
|
||||
BFXILw(x3, vd, 8, 8); // length
|
||||
MOV64xw(x5, 0);
|
||||
UXTBw(x4, vd); // start
|
||||
UBFXw(x3, vd, 8, 8); // length
|
||||
TSTw_REG(x3, x3);
|
||||
B_MARK(cEQ);
|
||||
LSRxw_REG(x1, ed, x2);
|
||||
CMPSw_U12(x3, rex.w?64:32);
|
||||
CMPSw_U12(x4, rex.w?64:32);
|
||||
B_MARK(cGE);
|
||||
MOV32w(x2, rex.w?64:32);
|
||||
SUBw_REG(x2, x2, x3);
|
||||
LSLxw_REG(x1, x1, x2);
|
||||
LSRxw_REG(x1, x1, x2);
|
||||
TSTxw_REG(x1, x1);
|
||||
LSRxw_REG(x5, ed, x4);
|
||||
CMPSw_U12(x3, rex.w?64:32);
|
||||
B_MARK(cGT);
|
||||
MOV32w(x4, rex.w?64:32);
|
||||
SUBw_REG(x4, x4, x3);
|
||||
LSLxw_REG(x5, x5, x4);
|
||||
LSRxw_REG(x5, x5, x4);
|
||||
MARK;
|
||||
MOVxw_REG(gd, x1);
|
||||
MOVxw_REG(gd, x5);
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(x5, x5);
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_ZF, 1);
|
||||
|
||||
@@ -268,7 +268,9 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
GETEXSD(q0, 0, 0);
|
||||
FCMPD(v0, q0);
|
||||
IFX(X_CF|X_PF|X_ZF) {
|
||||
FCMPD(v0, q0);
|
||||
}
|
||||
FCOMI(x1, x2);
|
||||
break;
|
||||
|
||||
@@ -285,8 +287,8 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
GETEY(q0);
|
||||
VMOVQDto(x1, q0, 0);
|
||||
VMOVQDto(x2, q0, 1);
|
||||
BFIx(x1, x2, 63, 1);
|
||||
RORx(x2, x1, 63);
|
||||
LSRx(x2, x2, 62);
|
||||
BFXILx(x2, x1, 63, 1);
|
||||
BFIx(gd, x2, 2, 2);
|
||||
}
|
||||
break;
|
||||
@@ -429,7 +431,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
INST_NAME("VCVTPS2DQ Gx, Ex");
|
||||
nextop = F8;
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x6);
|
||||
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
|
||||
if(!BOX64ENV(dynarec_fastround) && !cpuext.frintts) {
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
MOVI_32_lsl(d1, 0x80, 3);
|
||||
@@ -440,7 +442,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
VFRINTISQ(v0, v1);
|
||||
VFCVTZSQS(v0, v0);
|
||||
} else {
|
||||
if(arm64_frintts) {
|
||||
if(cpuext.frintts) {
|
||||
VFRINT32XSQ(v0, v1);
|
||||
VFCVTZSQS(v0, v0);
|
||||
} else {
|
||||
@@ -493,24 +495,19 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
case 0x5D:
|
||||
INST_NAME("VMINPD Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
if(!BOX64ENV(dynarec_fastnan))
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
|
||||
// FMIN/FMAX wll not copy a NaN if either is NaN
|
||||
// but x86 will copy src2 if either value is NaN, so lets force a copy of Src2 (Ex) if result is NaN
|
||||
if(BOX64ENV(dynarec_fastnan)) {
|
||||
VFMINQD(v0, v2, v1);
|
||||
} else {
|
||||
VFCMGTQD(q0, v1, v2); // 0 if NaN or v1 GT v2, so invert mask for copy
|
||||
if(v0!=v1) VBIFQ(v0, v1, q0);
|
||||
if(v0!=v2) VBITQ(v0, v2, q0);
|
||||
}
|
||||
VFCMGTQD(q0, v1, v2); // 0 if NaN or v1 GT v2, so invert mask for copy
|
||||
if(v0!=v1) VBIFQ(v0, v1, q0);
|
||||
if(v0!=v2) VBITQ(v0, v2, q0);
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x5E:
|
||||
INST_NAME("DIVPD Gx, Ex");
|
||||
INST_NAME("VDIVPD Gx, Ex");
|
||||
nextop = F8;
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
@@ -536,19 +533,14 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
case 0x5F:
|
||||
INST_NAME("VMAXPD Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
if(!BOX64ENV(dynarec_fastnan))
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
|
||||
// FMIN/FMAX wll not copy a NaN if either is NaN
|
||||
// but x86 will copy src2 if either value is NaN, so lets force a copy of Src2 (Ex) if result is NaN
|
||||
if(BOX64ENV(dynarec_fastnan)) {
|
||||
VFMAXQD(v0, v2, v1);
|
||||
} else {
|
||||
VFCMGTQD(q0, v2, v1); // 0 if NaN or v2 GT v1, so invert mask for copy
|
||||
if(v0!=v1) VBIFQ(v0, v1, q0);
|
||||
if(v0!=v2) VBITQ(v0, v2, q0);
|
||||
}
|
||||
VFCMGTQD(q0, v2, v1); // 0 if NaN or v2 GT v1, so invert mask for copy
|
||||
if(v0!=v1) VBIFQ(v0, v1, q0);
|
||||
if(v0!=v2) VBITQ(v0, v2, q0);
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
@@ -1459,7 +1451,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEX_Y(q0, 0, 0);
|
||||
GETGD;
|
||||
TABLE64(x2, 0x0706050403020100LL);
|
||||
TABLE64_(x2, 0x0706050403020100LL);
|
||||
VDUPQD(v0, x2);
|
||||
VSHRQ_8(q1, q0, 7);
|
||||
USHLQ_8(q1, q1, v0); // shift
|
||||
@@ -1694,7 +1686,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
else
|
||||
SQXTN2_32(v0, d0); // convert int64 -> int32 with saturation in higher part
|
||||
} else {
|
||||
if(arm64_frintts) {
|
||||
if(cpuext.frintts) {
|
||||
VFRINT32ZDQ(l?d0:v0, v1); // handle overflow
|
||||
VFCVTZSQD(l?d0:v0, l?d0:v0); // convert double -> int64
|
||||
if(!l)
|
||||
|
||||
@@ -22,11 +22,6 @@
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "../dynarec_helper.h"
|
||||
|
||||
static const float addsubps[4] = {-1.f, 1.f, -1.f, 1.f};
|
||||
static const double addsubpd[2] = {-1., 1.};
|
||||
static const float subaddps[4] = {1.f, -1.f, 1.f, -1.f};
|
||||
static const double subaddpd[2] = {1., -1.};
|
||||
|
||||
uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)need_epilog;
|
||||
@@ -779,7 +774,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
} else YMM0(gd);
|
||||
break;
|
||||
case 0x2E:
|
||||
INST_NAME("VMASKMOVPS Ex, Gx, Vx");
|
||||
INST_NAME("VMASKMOVPS Ex, Vx, Gx");
|
||||
nextop = F8;
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
GETVX(v2, 0);
|
||||
@@ -835,7 +830,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
SMWRITE2();
|
||||
break;
|
||||
case 0x2F:
|
||||
INST_NAME("VMASKMOVPD Ex, Gx, Vx");
|
||||
INST_NAME("VMASKMOVPD Ex, Vx, Gx");
|
||||
nextop = F8;
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
GETVX(v2, 0);
|
||||
@@ -1587,7 +1582,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
INST_NAME("VFMADDSUB213PS/D Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
TABLE64(x2, (rex.w)?((uintptr_t)&addsubpd):((uintptr_t)&addsubps));
|
||||
TABLE64C(x2, rex.w?const_2d_m1_1:const_4f_m1_1_m1_1);
|
||||
VLDR128_U12(q0, x2, 0);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
@@ -1738,7 +1733,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
INST_NAME("VFMADDSUB231PS/D Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
TABLE64(x2, (rex.w)?((uintptr_t)&addsubpd):((uintptr_t)&addsubps));
|
||||
TABLE64C(x2, rex.w?const_2d_m1_1:const_4f_m1_1_m1_1);
|
||||
VLDR128_U12(q0, x2, 0);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_VXEX(v0, v2, v1, 0); if(v0==v2 || v0==v1) q1 = fpu_get_scratch(dyn, ninst); } else { GETGY_VYEY(v0, v2, v1); }
|
||||
@@ -1761,7 +1756,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
INST_NAME("VFMSUBADD231PS/D Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
TABLE64(x2, (rex.w)?((uintptr_t)&subaddpd):((uintptr_t)&subaddps));
|
||||
TABLE64C(x2, rex.w?const_2d_1_m1:const_4f_1_m1_1_m1);
|
||||
VLDR128_U12(q0, x2, 0);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_VXEX(v0, v2, v1, 0); if(v0==v2 || v0==v1) q1 = fpu_get_scratch(dyn, ninst); } else { GETGY_VYEY(v0, v2, v1); }
|
||||
@@ -1879,7 +1874,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
INST_NAME("VAESIMC Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX_empty_EX(v0, v1, 0);
|
||||
if(arm64_aes) {
|
||||
if(cpuext.aes) {
|
||||
AESIMC(v0, v1);
|
||||
} else {
|
||||
if(v0!=v1) {
|
||||
@@ -1887,7 +1882,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
}
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
MOV32w(x1, gd);
|
||||
CALL(native_aesimc, -1);
|
||||
CALL(const_native_aesimc, -1);
|
||||
}
|
||||
YMM0(gd);
|
||||
break;
|
||||
@@ -1895,7 +1890,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
case 0xDC:
|
||||
INST_NAME("VAESENC Gx, Vx, Ex"); // AES-NI
|
||||
nextop = F8;
|
||||
if(arm64_aes) {
|
||||
if(cpuext.aes) {
|
||||
d0 = fpu_get_scratch(dyn, ninst); // ARM64 internal operation differs a bit from x86_64
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) {GETGX_empty_VXEX(v0, v2, v1, 0);} else {GETGY_empty_VYEY(v0, v2, v1);}
|
||||
@@ -1922,8 +1917,8 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
}
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
MOV32w(x1, gd);
|
||||
CALL(native_aese, -1);
|
||||
if(vex.l) {MOV32w(x1, gd); CALL(native_aese_y, -1);}
|
||||
CALL(const_native_aese, -1);
|
||||
if(vex.l) {MOV32w(x1, gd); CALL(const_native_aese_y, -1);}
|
||||
GETGX(q0, 1);
|
||||
VEORQ(q0, q0, (d0==-1)?q1:d0);
|
||||
if(vex.l) {
|
||||
@@ -1936,7 +1931,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
case 0xDD:
|
||||
INST_NAME("VAESENCLAST Gx, Vx, Ex"); // AES-NI
|
||||
nextop = F8;
|
||||
if(arm64_aes) {
|
||||
if(cpuext.aes) {
|
||||
d0 = fpu_get_scratch(dyn, ninst); // ARM64 internal operation differs a bit from x86_64
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
|
||||
@@ -1962,8 +1957,8 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
}
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
MOV32w(x1, gd);
|
||||
CALL(native_aeselast, -1);
|
||||
if(vex.l) {MOV32w(x1, gd); CALL(native_aeselast_y, -1);}
|
||||
CALL(const_native_aeselast, -1);
|
||||
if(vex.l) {MOV32w(x1, gd); CALL(const_native_aeselast_y, -1);}
|
||||
GETGX(q0, 1);
|
||||
VEORQ(q0, q0, (d0==-1)?q1:d0);
|
||||
if(vex.l) {
|
||||
@@ -1976,7 +1971,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
case 0xDE:
|
||||
INST_NAME("VAESDEC Gx, Vx, Ex"); // AES-NI
|
||||
nextop = F8;
|
||||
if(arm64_aes) {
|
||||
if(cpuext.aes) {
|
||||
d0 = fpu_get_scratch(dyn, ninst); // ARM64 internal operation differs a bit from x86_64
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) {GETGX_empty_VXEX(v0, v2, v1, 0);} else {GETGY_empty_VYEY(v0, v2, v1);}
|
||||
@@ -2003,8 +1998,8 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
}
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
MOV32w(x1, gd);
|
||||
CALL(native_aesd, -1);
|
||||
if(vex.l) {MOV32w(x1, gd); CALL(native_aesd_y, -1);}
|
||||
CALL(const_native_aesd, -1);
|
||||
if(vex.l) {MOV32w(x1, gd); CALL(const_native_aesd_y, -1);}
|
||||
GETGX(q0, 1);
|
||||
VEORQ(q0, q0, (d0==-1)?q1:d0);
|
||||
if(vex.l) {
|
||||
@@ -2017,7 +2012,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
case 0xDF:
|
||||
INST_NAME("VAESDECLAST Gx, Vx, Ex"); // AES-NI
|
||||
nextop = F8;
|
||||
if(arm64_aes) {
|
||||
if(cpuext.aes) {
|
||||
d0 = fpu_get_scratch(dyn, ninst); // ARM64 internal operation differs a bit from x86_64
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) {GETGX_empty_VXEX(v0, v2, v1, 0);} else {GETGY_empty_VYEY(v0, v2, v1);}
|
||||
@@ -2043,8 +2038,8 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
}
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
MOV32w(x1, gd);
|
||||
CALL(native_aesdlast, -1);
|
||||
if(vex.l) {MOV32w(x1, gd); CALL(native_aesdlast_y, -1);}
|
||||
CALL(const_native_aesdlast, -1);
|
||||
if(vex.l) {MOV32w(x1, gd); CALL(const_native_aesdlast_y, -1);}
|
||||
GETGX(q0, 1);
|
||||
VEORQ(q0, q0, (d0==-1)?q1:d0);
|
||||
if(vex.l) {
|
||||
|
||||
@@ -167,12 +167,12 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
u8 = F8;
|
||||
GETVX(v2, 0);
|
||||
GETGX_empty(v0);
|
||||
if((v0==v2) && ((u8&0xf0)==0)) {
|
||||
if((v0==v2) && ((u8&0b10110000)==0)) {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
VMOVQ(q0, v2);
|
||||
v2 = q0;
|
||||
}
|
||||
if((v0==v1) && ((u8&0xf0)==0x20)) {
|
||||
if((v0==v1) && ((u8&0b10110000)==0x20)) {
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
VMOVQ(q1, v1);
|
||||
v1 = q1;
|
||||
@@ -184,8 +184,8 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
case 3: if(MODREG) { d1 = ymm_get_reg(dyn, ninst, x1, s0, 0, gd, vex.v, -1); VMOVQ(v0, d1); } else { VLDR128_U12(v0, ed, fixedaddress+16); } break;
|
||||
default: VEORQ(v0, v0, v0);
|
||||
}
|
||||
if((u8&0xf0)==0x10) { if((u8&0x0f)!=1) d2 = ymm_get_reg(dyn, ninst, x1, vex.v, 0, gd, s0, -1); }
|
||||
if(MODREG && ((u8&0xf0)==0x30)) { if((u8&0x0f)!=3) d1 = ymm_get_reg(dyn, ninst, x1, s0, 0, gd, vex.v, -1); }
|
||||
if((u8&0b10110000)==0x10) { if((u8&0b1011)!=1) d2 = ymm_get_reg(dyn, ninst, x1, vex.v, 0, gd, s0, -1); }
|
||||
if(MODREG && ((u8&0b10110000)==0x30)) { if((u8&0b1011)!=3) d1 = ymm_get_reg(dyn, ninst, x1, s0, 0, gd, vex.v, -1); }
|
||||
v0 = ymm_get_reg_empty(dyn, ninst, x1, gd, vex.v, s0, -1);
|
||||
switch((u8>>4)&0b1011) {
|
||||
case 0: VMOVQ(v0, v2); break;
|
||||
@@ -378,7 +378,6 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
if(MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff, 0, rex, NULL, 0, 1);
|
||||
ed = x1;
|
||||
}
|
||||
@@ -396,7 +395,6 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
if(MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 1);
|
||||
ed = x1;
|
||||
}
|
||||
@@ -414,7 +412,6 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
if(MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 1);
|
||||
ed = x1;
|
||||
}
|
||||
@@ -436,7 +433,6 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
if(MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 1);
|
||||
ed = x1;
|
||||
}
|
||||
@@ -497,7 +493,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
break;
|
||||
|
||||
case 0x1D:
|
||||
INST_NAME("VCVTPS2PH Ex, Gx");
|
||||
INST_NAME("VCVTPS2PH Ex, Gx, Ib");
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
if(MODREG) {
|
||||
@@ -586,7 +582,11 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x22:
|
||||
INST_NAME("VINSERTD Gx, Vx, Ex, Ib");
|
||||
if (rex.w) {
|
||||
INST_NAME("VPINSRQ Gx, Vx, ED, Ib");
|
||||
} else {
|
||||
INST_NAME("VPINSRD Gx, Vx, ED, Ib");
|
||||
}
|
||||
nextop = F8;
|
||||
GETGX_empty_VX(v0, v2);
|
||||
GETED(1);
|
||||
@@ -662,7 +662,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
case 0x44:
|
||||
INST_NAME("VPCLMULQDQ Gx, Vx, Ex, Ib");
|
||||
nextop = F8;
|
||||
if(arm64_pmull) {
|
||||
if(cpuext.pmull) {
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) {
|
||||
@@ -706,7 +706,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
}
|
||||
u8 = F8;
|
||||
MOV32w(x4, u8);
|
||||
CALL_(vex.l?native_pclmul_y:native_pclmul_x, -1, x3);
|
||||
CALL_(vex.l?const_native_pclmul_y:const_native_pclmul_x, -1, x3);
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
@@ -810,7 +810,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
}
|
||||
u8 = F8;
|
||||
MOV32w(x4, u8);
|
||||
CALL(native_aeskeygenassist, -1);
|
||||
CALL(const_native_aeskeygenassist, -1);
|
||||
YMM0(gd);
|
||||
break;
|
||||
|
||||
|
||||
@@ -144,12 +144,12 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEXSD(q0, 0, 0);
|
||||
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
|
||||
if(!BOX64ENV(dynarec_fastround) && !cpuext.frintts) {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
}
|
||||
if(!BOX64ENV(dynarec_fastround) && arm64_frintts) {
|
||||
if(!BOX64ENV(dynarec_fastround) && cpuext.frintts) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
if(rex.w) {
|
||||
FRINT64ZD(v0, q0);
|
||||
@@ -160,7 +160,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
} else {
|
||||
FCVTZSxwD(gd, q0);
|
||||
}
|
||||
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
|
||||
if(!BOX64ENV(dynarec_fastround) && !cpuext.frintts) {
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_NEXT(x5, FPSR_IOC);
|
||||
if(rex.w) {
|
||||
@@ -175,14 +175,14 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEXSD(q0, 0, 0);
|
||||
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
|
||||
if(!BOX64ENV(dynarec_fastround) && !cpuext.frintts) {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
}
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x3);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
if(!BOX64ENV(dynarec_fastround) && arm64_frintts) {
|
||||
if(!BOX64ENV(dynarec_fastround) && cpuext.frintts) {
|
||||
if(rex.w) {
|
||||
FRINT64XD(d1, q0);
|
||||
} else {
|
||||
@@ -193,7 +193,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
FCVTZSxwD(gd, d1);
|
||||
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
|
||||
if(!BOX64ENV(dynarec_fastround) && !cpuext.frintts) {
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_NEXT(x5, FPSR_IOC);
|
||||
if(rex.w) {
|
||||
@@ -496,9 +496,9 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
case 0x09: CSETMx(x2, cHI); break; // Less than or unordered
|
||||
case 0x0a: CSETMx(x2, cCS); break; // Less or equal or unordered
|
||||
case 0x0b: MOV32w(x2, 0); break; // false
|
||||
case 0x0c: CSETMw(x2, cNE); CSETMx(x3, cVS); BICx(x2, x2, x3); break; // Not Equal not unordered
|
||||
case 0x0d: CSETMw(x2, cLS); break; // Greater or equal not unordered
|
||||
case 0x0e: CSETMw(x2, cCC); break; // Greater not unordered
|
||||
case 0x0c: CSETMx(x2, cNE); CSETMx(x3, cVS); BICx(x2, x2, x3); break; // Not Equal not unordered
|
||||
case 0x0d: CSETMx(x2, cLS); break; // Greater or equal not unordered
|
||||
case 0x0e: CSETMx(x2, cCC); break; // Greater not unordered
|
||||
case 0x0f: MOV64x(x2, 0xffffffffffffffffLL); break; // true
|
||||
}
|
||||
VMOVQDfrom(v0, 0, x2);
|
||||
@@ -509,9 +509,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
INST_NAME("VADDSUBPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
static float addsubps[4] = {-1.f, 1.f, -1.f, 1.f};
|
||||
MAYUSE(addsubps);
|
||||
MOV64x(x2, (uintptr_t)&addsubps);
|
||||
TABLE64C(x2, const_4f_m1_1_m1_1);
|
||||
VLDR128_U12(q0, x2, 0);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
|
||||
@@ -550,7 +548,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
else
|
||||
SQXTN2_32(v0, d0); // convert int64 -> int32 with saturation in higher part
|
||||
} else {
|
||||
if(arm64_frintts) {
|
||||
if(cpuext.frintts) {
|
||||
VFRINT32XDQ(l?d0:v0, v1); // round, handling of overflow and Nan to 0x80000000
|
||||
VFCVTNSQD(l?d0:v0, l?d0:v0); // convert double -> int64
|
||||
if(!l)
|
||||
@@ -598,11 +596,16 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
VMOVQ(v0, v1);
|
||||
}
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
v1 = ymm_get_reg_empty(dyn, ninst, x1, gd, -1, -1, -1);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0x3f<<4, 15, rex, NULL, 1, 0);
|
||||
VLDP128_I7(v0, v1, ed, fixedaddress);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
if (vex.l) {
|
||||
v1 = ymm_get_reg_empty(dyn, ninst, x1, gd, -1, -1, -1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0x3f << 4, 15, rex, NULL, 1, 0);
|
||||
VLDP128_I7(v0, v1, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff << 4, 15, rex, NULL, 0, 0);
|
||||
VLD128(v0, ed, fixedaddress);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
|
||||
@@ -81,7 +81,7 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
GETGXVXEX_empty(v0, v2, v1, 0);
|
||||
GETGXVXEX_empty(v0, v1, v2, 0);
|
||||
if((v2!=v1) && (v2!=v0)) VMOVQ(v2, v1);
|
||||
if(v2!=v0) VMOVeS(v2, 0, v0, 0);
|
||||
if((v2!=v1) && (v2==v0)) { VMOVeS(v2, 1, v0, 1); VMOVeD(v2, 1, v0, 1);}
|
||||
@@ -144,12 +144,12 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEXSS(d0, 0, 0);
|
||||
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
|
||||
if(!BOX64ENV(dynarec_fastround) && !cpuext.frintts) {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
}
|
||||
if(!BOX64ENV(dynarec_fastround) && arm64_frintts) {
|
||||
if(!BOX64ENV(dynarec_fastround) && cpuext.frintts) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
if(rex.w) {
|
||||
FRINT64ZS(v0, d0);
|
||||
@@ -160,7 +160,7 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
} else {
|
||||
FCVTZSxwS(gd, d0);
|
||||
}
|
||||
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
|
||||
if(!BOX64ENV(dynarec_fastround) && !cpuext.frintts) {
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_NEXT(x5, FPSR_IOC);
|
||||
if(rex.w) {
|
||||
@@ -175,14 +175,14 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEXSS(q0, 0, 0);
|
||||
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
|
||||
if(!BOX64ENV(dynarec_fastround) && !cpuext.frintts) {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
}
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x3);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
if(!BOX64ENV(dynarec_fastround) && arm64_frintts) {
|
||||
if(!BOX64ENV(dynarec_fastround) && cpuext.frintts) {
|
||||
if(rex.w) {
|
||||
FRINT64XS(d1, q0);
|
||||
} else {
|
||||
@@ -193,7 +193,7 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
FCVTZSxwS(gd, d1);
|
||||
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
|
||||
if(!BOX64ENV(dynarec_fastround) && !cpuext.frintts) {
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_NEXT(x5, FPSR_IOC);
|
||||
if(rex.w) {
|
||||
@@ -342,7 +342,7 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
if(BOX64ENV(dynarec_fastround)) {
|
||||
VFCVTZSQS(v0, v1);
|
||||
} else {
|
||||
if(arm64_frintts) {
|
||||
if(cpuext.frintts) {
|
||||
VFRINT32ZSQ(v0, v1);
|
||||
VFCVTZSQS(v0, v0);
|
||||
} else {
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "dynarec_arm64_consts.h"
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "emu/x87emu_private.h"
|
||||
#include "emu/x64primop.h"
|
||||
#include "my_cpuid.h"
|
||||
#include "freq.h"
|
||||
#include "debug.h"
|
||||
#include "custommem.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "emu/x64shaext.h"
|
||||
#include "emu/x87emu_private.h"
|
||||
#include "emu/x64compstrings.h"
|
||||
#include "x64test.h"
|
||||
#include "dynarec/dynarec_next.h"
|
||||
|
||||
static const int8_t mask_shift8[] = { -7, -6, -5, -4, -3, -2, -1, 0 };
|
||||
static const int8_t mask_string8[] = { 7, 6, 5, 4, 3, 2, 1, 0 };
|
||||
static const int8_t mask_string16[] = { 15, 14, 13, 12, 11, 10, 9, 8 };
|
||||
static const float addsubps[4] = {-1.f, 1.f, -1.f, 1.f};
|
||||
static const double addsubpd[2] = {-1., 1.};
|
||||
static const float subaddps[4] = {1.f, -1.f, 1.f, -1.f};
|
||||
static const double subaddpd[2] = {1., -1.};
|
||||
|
||||
#ifndef HAVE_TRACE
|
||||
void PrintTrace() {}
|
||||
#endif
|
||||
|
||||
uintptr_t getConst(arm64_consts_t which)
|
||||
{
|
||||
switch(which) {
|
||||
case const_none: dynarec_log(LOG_NONE, "Warning, const none used\n");
|
||||
return 0;
|
||||
case const_daa8: return (uintptr_t)daa8;
|
||||
case const_das8: return (uintptr_t)das8;
|
||||
case const_aaa16: return (uintptr_t)aaa16;
|
||||
case const_aas16: return (uintptr_t)aas16;
|
||||
case const_aam16: return (uintptr_t)aam16;
|
||||
case const_aad16: return (uintptr_t)aad16;
|
||||
case const_native_br: return (uintptr_t)native_br;
|
||||
case const_native_ud: return (uintptr_t)native_ud;
|
||||
case const_native_priv: return (uintptr_t)native_priv;
|
||||
case const_native_gpf: return (uintptr_t)native_gpf;
|
||||
case const_native_int3: return (uintptr_t)native_int3;
|
||||
case const_native_int: return (uintptr_t)native_int;
|
||||
case const_native_div0: return (uintptr_t)native_div0;
|
||||
case const_native_clflush: return (uintptr_t)native_clflush;
|
||||
case const_native_frstor16: return (uintptr_t)native_frstor16;
|
||||
case const_native_fsave16: return (uintptr_t)native_fsave16;
|
||||
case const_native_fsave: return (uintptr_t)native_fsave;
|
||||
case const_native_aesimc: return (uintptr_t)native_aesimc;
|
||||
case const_native_aesd: return (uintptr_t)native_aesd;
|
||||
case const_native_aesd_y: return (uintptr_t)native_aesd_y;
|
||||
case const_native_aesdlast: return (uintptr_t)native_aesdlast;
|
||||
case const_native_aesdlast_y: return (uintptr_t)native_aesdlast_y;
|
||||
case const_native_aese: return (uintptr_t)native_aese;
|
||||
case const_native_aese_y: return (uintptr_t)native_aese_y;
|
||||
case const_native_aeselast: return (uintptr_t)native_aeselast;
|
||||
case const_native_aeselast_y: return (uintptr_t)native_aeselast_y;
|
||||
case const_native_aeskeygenassist: return (uintptr_t)native_aeskeygenassist;
|
||||
case const_native_pclmul: return (uintptr_t)native_pclmul;
|
||||
case const_native_pclmul_x: return (uintptr_t)native_pclmul_x;
|
||||
case const_native_pclmul_y: return (uintptr_t)native_pclmul_y;
|
||||
case const_native_f2xm1: return (uintptr_t)native_f2xm1;
|
||||
case const_native_fyl2x: return (uintptr_t)native_fyl2x;
|
||||
case const_native_fyl2xp1: return (uintptr_t)native_fyl2xp1;
|
||||
case const_native_fxtract: return (uintptr_t)native_fxtract;
|
||||
case const_native_ftan: return (uintptr_t)native_ftan;
|
||||
case const_native_fpatan: return (uintptr_t)native_fpatan;
|
||||
case const_native_fcos: return (uintptr_t)native_fcos;
|
||||
case const_native_fsin: return (uintptr_t)native_fsin;
|
||||
case const_native_fsincos: return (uintptr_t)native_fsincos;
|
||||
case const_native_fscale: return (uintptr_t)native_fscale;
|
||||
case const_native_fld: return (uintptr_t)native_fld;
|
||||
case const_native_fstp: return (uintptr_t)native_fstp;
|
||||
case const_native_frstor: return (uintptr_t)native_frstor;
|
||||
case const_native_next: return (uintptr_t)native_next;
|
||||
case const_int3: return (uintptr_t)EmuInt3;
|
||||
case const_x86syscall: return (uintptr_t)EmuX86Syscall;
|
||||
case const_x64syscall: return (uintptr_t)EmuX64Syscall;
|
||||
case const_rcl16: return (uintptr_t)rcl16;
|
||||
case const_rcl32: return (uintptr_t)rcl32;
|
||||
case const_rcl64: return (uintptr_t)rcl64;
|
||||
case const_rcr16: return (uintptr_t)rcr16;
|
||||
case const_rcr32: return (uintptr_t)rcr32;
|
||||
case const_rcr64: return (uintptr_t)rcr64;
|
||||
case const_div64: return (uintptr_t)div64;
|
||||
case const_idiv64: return (uintptr_t)idiv64;
|
||||
case const_random32: return (uintptr_t)get_random32;
|
||||
case const_random64: return (uintptr_t)get_random64;
|
||||
case const_readtsc: return (uintptr_t)ReadTSC;
|
||||
case const_helper_getcpu: return (uintptr_t)helper_getcpu;
|
||||
case const_cpuid: return (uintptr_t)my_cpuid;
|
||||
case const_getsegmentbase: return (uintptr_t)GetSegmentBaseEmu;
|
||||
case const_updateflags_arm64: return (uintptr_t)create_updateflags();
|
||||
case const_reset_fpu: return (uintptr_t)reset_fpu;
|
||||
case const_sha1msg2: return (uintptr_t)sha1msg2;
|
||||
case const_sha1rnds4: return (uintptr_t)sha1rnds4;
|
||||
case const_sha256msg1: return (uintptr_t)sha256msg1;
|
||||
case const_sha256msg2: return (uintptr_t)sha256msg2;
|
||||
case const_sha256rnds2: return (uintptr_t)sha256rnds2;
|
||||
case const_fpu_loadenv: return (uintptr_t)fpu_loadenv;
|
||||
case const_fpu_savenv: return (uintptr_t)fpu_savenv;
|
||||
case const_fpu_fxsave32: return (uintptr_t)fpu_fxsave32;
|
||||
case const_fpu_fxsave64: return (uintptr_t)fpu_fxsave64;
|
||||
case const_fpu_fxrstor32: return (uintptr_t)fpu_fxrstor32;
|
||||
case const_fpu_fxrstor64: return (uintptr_t)fpu_fxrstor64;
|
||||
case const_fpu_xsave: return (uintptr_t)fpu_xsave;
|
||||
case const_fpu_xrstor: return (uintptr_t)fpu_xrstor;
|
||||
case const_fpu_fbld: return (uintptr_t)fpu_fbld;
|
||||
case const_fpu_fbst: return (uintptr_t)fpu_fbst;
|
||||
case const_sse42_compare_string_explicit_len: return (uintptr_t)sse42_compare_string_explicit_len;
|
||||
case const_sse42_compare_string_implicit_len: return (uintptr_t)sse42_compare_string_implicit_len;
|
||||
case const_x64test_step: return (uintptr_t)x64test_step;
|
||||
case const_printtrace: return (uintptr_t)PrintTrace;
|
||||
case const_epilog: return (uintptr_t)native_epilog;
|
||||
case const_jmptbl32: return getJumpTable32();
|
||||
case const_jmptbl48: return getJumpTable48();
|
||||
case const_jmptbl64: return getJumpTable64();
|
||||
case const_context: return (uintptr_t)my_context;
|
||||
case const_8b_m7_m6_m5_m4_m3_m2_m1_0: return (uintptr_t)&mask_shift8;
|
||||
case const_8b_7_6_5_4_3_2_1_0: return (uintptr_t)&mask_string8;
|
||||
case const_8b_15_14_13_12_11_10_9_8: return (uintptr_t)&mask_string16;
|
||||
case const_4f_m1_1_m1_1: return (uintptr_t)&addsubps;
|
||||
case const_4f_1_m1_1_m1: return (uintptr_t)&subaddps;
|
||||
case const_2d_m1_1: return (uintptr_t)&addsubpd;
|
||||
case const_2d_1_m1: return (uintptr_t)&subaddpd;
|
||||
|
||||
case const_last: dynarec_log(LOG_NONE, "Warning, const last used\n");
|
||||
return 0;
|
||||
}
|
||||
dynarec_log(LOG_NONE, "Warning, Unknown const %d used\n", which);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
#ifndef __DYNAREC_ARM64_CONSTS__
|
||||
#define __DYNAREC_ARM64_CONSTS__
|
||||
#include <stdint.h>
|
||||
|
||||
typedef enum arm64_consts_s {
|
||||
const_none,
|
||||
const_daa8,
|
||||
const_das8,
|
||||
const_aaa16,
|
||||
const_aas16,
|
||||
const_aam16,
|
||||
const_aad16,
|
||||
const_native_br,
|
||||
const_native_ud,
|
||||
const_native_priv,
|
||||
const_native_gpf,
|
||||
const_native_int3,
|
||||
const_native_int,
|
||||
const_native_div0,
|
||||
const_native_clflush,
|
||||
const_native_frstor16,
|
||||
const_native_fsave16,
|
||||
const_native_fsave,
|
||||
const_native_aesimc,
|
||||
const_native_aesd,
|
||||
const_native_aesd_y,
|
||||
const_native_aesdlast,
|
||||
const_native_aesdlast_y,
|
||||
const_native_aese,
|
||||
const_native_aese_y,
|
||||
const_native_aeselast,
|
||||
const_native_aeselast_y,
|
||||
const_native_aeskeygenassist,
|
||||
const_native_pclmul,
|
||||
const_native_pclmul_x,
|
||||
const_native_pclmul_y,
|
||||
const_native_f2xm1,
|
||||
const_native_fyl2x,
|
||||
const_native_fyl2xp1,
|
||||
const_native_fxtract,
|
||||
const_native_ftan,
|
||||
const_native_fpatan,
|
||||
const_native_fcos,
|
||||
const_native_fsin,
|
||||
const_native_fsincos,
|
||||
const_native_fscale,
|
||||
const_native_fld,
|
||||
const_native_fstp,
|
||||
const_native_frstor,
|
||||
const_native_next,
|
||||
const_int3,
|
||||
const_x86syscall,
|
||||
const_x64syscall,
|
||||
const_rcl16,
|
||||
const_rcl32,
|
||||
const_rcl64,
|
||||
const_rcr16,
|
||||
const_rcr32,
|
||||
const_rcr64,
|
||||
const_div64,
|
||||
const_idiv64,
|
||||
const_random32,
|
||||
const_random64,
|
||||
const_readtsc,
|
||||
const_helper_getcpu,
|
||||
const_cpuid,
|
||||
const_getsegmentbase,
|
||||
const_updateflags_arm64,
|
||||
const_reset_fpu,
|
||||
const_sha1msg2,
|
||||
const_sha1rnds4,
|
||||
const_sha256msg1,
|
||||
const_sha256msg2,
|
||||
const_sha256rnds2,
|
||||
const_fpu_loadenv,
|
||||
const_fpu_savenv,
|
||||
const_fpu_fxsave32,
|
||||
const_fpu_fxsave64,
|
||||
const_fpu_fxrstor32,
|
||||
const_fpu_fxrstor64,
|
||||
const_fpu_xsave,
|
||||
const_fpu_xrstor,
|
||||
const_fpu_fbld,
|
||||
const_fpu_fbst,
|
||||
const_sse42_compare_string_explicit_len,
|
||||
const_sse42_compare_string_implicit_len,
|
||||
const_x64test_step,
|
||||
const_printtrace,
|
||||
const_epilog,
|
||||
const_jmptbl32,
|
||||
const_jmptbl48,
|
||||
const_jmptbl64,
|
||||
const_context,
|
||||
const_8b_m7_m6_m5_m4_m3_m2_m1_0,
|
||||
const_8b_7_6_5_4_3_2_1_0,
|
||||
const_8b_15_14_13_12_11_10_9_8,
|
||||
const_4f_m1_1_m1_1,
|
||||
const_2d_m1_1,
|
||||
const_4f_1_m1_1_m1,
|
||||
const_2d_1_m1,
|
||||
|
||||
const_last
|
||||
} arm64_consts_t;
|
||||
|
||||
uintptr_t getConst(arm64_consts_t which);
|
||||
|
||||
// temporary define...
|
||||
#define const_PrintTrace const_printtrace
|
||||
|
||||
#endif //__DYNAREC_ARM64_CONSTS__
|
||||
@@ -271,7 +271,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (F2XM1)\n");
|
||||
i1 = x87_stackcount(dyn, ninst, x1);
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
CALL(native_f2xm1, -1);
|
||||
CALL(const_native_f2xm1, -1);
|
||||
x87_unstackcount(dyn, ninst, x1, i1);
|
||||
break;
|
||||
case 0xF1:
|
||||
@@ -280,7 +280,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
i1 = x87_stackcount(dyn, ninst, x1);
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(native_fyl2x, -1);
|
||||
CALL(const_native_fyl2x, -1);
|
||||
x87_unstackcount(dyn, ninst, x1, i1);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
@@ -291,7 +291,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
CALL_(native_ftan, -1, BOX64ENV(dynarec_fastround) ? 0 : u8);
|
||||
CALL_(const_native_ftan, -1, BOX64ENV(dynarec_fastround) ? 0 : u8);
|
||||
x87_unstackcount(dyn, ninst, x1, i1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
@@ -316,7 +316,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
CALL_(native_fpatan, -1, BOX64ENV(dynarec_fastround) ? 0 : u8);
|
||||
CALL_(const_native_fpatan, -1, BOX64ENV(dynarec_fastround) ? 0 : u8);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
x87_unstackcount(dyn, ninst, x1, i1);
|
||||
@@ -328,19 +328,11 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
X87_PUSH_EMPTY_OR_FAIL(dyn, ninst, 0);
|
||||
i1 = x87_stackcount(dyn, ninst, x1);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(native_fxtract, -1);
|
||||
CALL(const_native_fxtract, -1);
|
||||
x87_unstackcount(dyn, ninst, x1, i1);
|
||||
break;
|
||||
case 0xF5:
|
||||
INST_NAME("FPREM1");
|
||||
#if 0
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
i1 = x87_stackcount(dyn, ninst, x1);
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(native_fprem1, -1);
|
||||
x87_unstackcount(dyn, ninst, x1, i1);
|
||||
#else
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 1, NEON_CACHE_ST_D);
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
@@ -361,11 +353,10 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
LSRx(x4, x4, 1);
|
||||
BFIw(x1, x4, 8, 1);
|
||||
STRw_U12(x1, xEmu, offsetof(x64emu_t, sw));
|
||||
#endif
|
||||
break;
|
||||
case 0xF6:
|
||||
INST_NAME("FDECSTP");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
LDRw_U12(x2, xEmu, offsetof(x64emu_t, top));
|
||||
SUBw_U12(x2, x2, 1);
|
||||
ANDw_mask(x2, x2, 0, 2); //mask=7
|
||||
@@ -373,7 +364,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0xF7:
|
||||
INST_NAME("FINCSTP");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
LDRw_U12(x2, xEmu, offsetof(x64emu_t, top));
|
||||
ADDw_U12(x2, x2, 1);
|
||||
ANDw_mask(x2, x2, 0, 2); //mask=7
|
||||
@@ -381,14 +372,6 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0xF8:
|
||||
INST_NAME("FPREM");
|
||||
#if 0
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
i1 = x87_stackcount(dyn, ninst, x1);
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(native_fprem, -1);
|
||||
x87_unstackcount(dyn, ninst, x1, i1);
|
||||
#else
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 1, NEON_CACHE_ST_D);
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
@@ -409,7 +392,6 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
LSRx(x4, x4, 1);
|
||||
BFIw(x1, x4, 8, 1);
|
||||
STRw_U12(x1, xEmu, offsetof(x64emu_t, sw));
|
||||
#endif
|
||||
break;
|
||||
case 0xF9:
|
||||
INST_NAME("FYL2XP1");
|
||||
@@ -417,7 +399,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
i1 = x87_stackcount(dyn, ninst, x1);
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(native_fyl2xp1, -1);
|
||||
CALL(const_native_fyl2xp1, -1);
|
||||
x87_unstackcount(dyn, ninst, x1, i1);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
@@ -443,19 +425,13 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
CALL_(native_fsincos, -1, BOX64ENV(dynarec_fastround) ? 0 : u8);
|
||||
CALL_(const_native_fsincos, -1, BOX64ENV(dynarec_fastround) ? 0 : u8);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
x87_unstackcount(dyn, ninst, x1, i1);
|
||||
break;
|
||||
case 0xFC:
|
||||
INST_NAME("FRNDINT");
|
||||
#if 0
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
// use C helper for now, nothing staightforward is available
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
CALL(native_frndint, -1);
|
||||
#else
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x3);
|
||||
if(ST_IS_F(0)) {
|
||||
@@ -464,7 +440,6 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
FRINTID(v1, v1);
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
#endif
|
||||
break;
|
||||
case 0xFD:
|
||||
INST_NAME("FSCALE");
|
||||
@@ -474,7 +449,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
CALL_(native_fscale, -1, BOX64ENV(dynarec_fastround) ? 0 : u8);
|
||||
CALL_(const_native_fscale, -1, BOX64ENV(dynarec_fastround) ? 0 : u8);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
x87_unstackcount(dyn, ninst, x1, i1);
|
||||
@@ -486,7 +461,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
CALL_(native_fsin, -1, BOX64ENV(dynarec_fastround) ? 0 : u8);
|
||||
CALL_(const_native_fsin, -1, BOX64ENV(dynarec_fastround) ? 0 : u8);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
x87_unstackcount(dyn, ninst, x1, i1);
|
||||
@@ -498,7 +473,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
CALL_(native_fcos, -1, BOX64ENV(dynarec_fastround) ? 0 : u8);
|
||||
CALL_(const_native_fcos, -1, BOX64ENV(dynarec_fastround) ? 0 : u8);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
x87_unstackcount(dyn, ninst, x1, i1);
|
||||
@@ -550,13 +525,13 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 4:
|
||||
INST_NAME("FLDENV Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (FLDENV)\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3); // maybe only x87, not SSE?
|
||||
BARRIER(BARRIER_FLOAT); // maybe only x87, not SSE?
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {
|
||||
MOVx_REG(x1, ed);
|
||||
}
|
||||
MOV32w(x2, 0);
|
||||
CALL(fpu_loadenv, -1);
|
||||
CALL(const_fpu_loadenv, -1);
|
||||
NATIVE_RESTORE_X87PC();
|
||||
break;
|
||||
case 5:
|
||||
@@ -569,13 +544,13 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 6:
|
||||
INST_NAME("FNSTENV Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (FNSTENV)\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3); // maybe only x87, not SSE?
|
||||
BARRIER(BARRIER_FLOAT); // maybe only x87, not SSE?
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {
|
||||
MOVx_REG(x1, ed);
|
||||
}
|
||||
MOV32w(x2, 0);
|
||||
CALL(fpu_savenv, -1);
|
||||
CALL(const_fpu_savenv, -1);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FNSTCW Ew");
|
||||
|
||||
@@ -133,7 +133,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FNINIT");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (FNINIT)\n");
|
||||
x87_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
CALL(reset_fpu, -1);
|
||||
CALL(const_reset_fpu, -1);
|
||||
NATIVE_RESTORE_X87PC();
|
||||
break;
|
||||
case 0xE8:
|
||||
@@ -148,10 +148,12 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
FCMPS(v1, v2);
|
||||
} else {
|
||||
FCMPD(v1, v2);
|
||||
IFX(X_CF|X_PF|X_ZF) {
|
||||
if(ST_IS_F(0)) {
|
||||
FCMPS(v1, v2);
|
||||
} else {
|
||||
FCMPD(v1, v2);
|
||||
}
|
||||
}
|
||||
FCOMI(x1, x2);
|
||||
break;
|
||||
@@ -167,10 +169,12 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
FCMPS(v1, v2);
|
||||
} else {
|
||||
FCMPD(v1, v2);
|
||||
IFX(X_CF|X_PF|X_ZF) {
|
||||
if(ST_IS_F(0)) {
|
||||
FCMPS(v1, v2);
|
||||
} else {
|
||||
FCMPD(v1, v2);
|
||||
}
|
||||
}
|
||||
FCOMI(x1, x2);
|
||||
break;
|
||||
@@ -193,7 +197,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
if(arm64_frintts) {
|
||||
if(cpuext.frintts) {
|
||||
FRINT32ZD(s0, v1);
|
||||
FCVTZSwD(x5, s0);
|
||||
STW(x5, wback, fixedaddress);
|
||||
@@ -223,7 +227,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4); // x1 have the modified RPSCR reg
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
if(arm64_frintts) {
|
||||
if(cpuext.frintts) {
|
||||
FRINT32XD(s0, v1);
|
||||
FCVTZSwD(x5, s0);
|
||||
STW(x5, wback, fixedaddress);
|
||||
@@ -253,7 +257,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4); // x1 have the modified RPSCR reg
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
if(arm64_frintts) {
|
||||
if(cpuext.frintts) {
|
||||
FRINT32XD(s0, v1);
|
||||
FCVTZSwD(x5, s0);
|
||||
STW(x5, wback, fixedaddress);
|
||||
@@ -309,7 +313,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
X87_PUSH_EMPTY_OR_FAIL(dyn, ninst, 0);
|
||||
// sync top
|
||||
x87_reflectcount(dyn, ninst, x3, x4);
|
||||
CALL(native_fld, -1);
|
||||
CALL(const_native_fld, -1);
|
||||
// go back with the top & stack counter
|
||||
x87_unreflectcount(dyn, ninst, x3, x4);
|
||||
}
|
||||
@@ -327,7 +331,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
x87_reflectcount(dyn, ninst, x3, x4);
|
||||
CALL(native_fstp, -1);
|
||||
CALL(const_native_fstp, -1);
|
||||
x87_unreflectcount(dyn, ninst, x3, x4);
|
||||
} else {
|
||||
// Painfully long, straight conversion from the C code, shoud be optimized
|
||||
|
||||
@@ -49,7 +49,6 @@ uintptr_t dynarec64_DD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
INST_NAME("FFREE STx");
|
||||
#if 1
|
||||
if((nextop&7)==0 && PK(0)==0xD9 && PK(1)==0xF7) {
|
||||
MESSAGE(LOG_DUMP, "Hack for FFREE ST0 / FINCSTP\n");
|
||||
x87_do_pop(dyn, ninst, x1);
|
||||
@@ -57,12 +56,6 @@ uintptr_t dynarec64_DD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SKIPTEST(x1);
|
||||
} else
|
||||
x87_free(dyn, ninst, x1, x2, x3, nextop&7);
|
||||
#else
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
MOV32w(x1, nextop&7);
|
||||
CALL(fpu_do_free, -1);
|
||||
#endif
|
||||
break;
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
@@ -157,7 +150,7 @@ uintptr_t dynarec64_DD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VST64(v1, ed, fixedaddress);
|
||||
} else {
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
if(arm64_frintts) {
|
||||
if(cpuext.frintts) {
|
||||
FRINT64ZD(s0, v1);
|
||||
VFCVTZSd(s0, s0);
|
||||
VST64(s0, ed, fixedaddress);
|
||||
@@ -193,24 +186,22 @@ uintptr_t dynarec64_DD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 4:
|
||||
INST_NAME("FRSTOR m108byte");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (FRSTOR)\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
CALL(native_frstor, -1);
|
||||
CALL(const_native_frstor, -1);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FNSAVE m108byte");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (FNSAVE)\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
CALL(native_fsave, -1);
|
||||
CALL(reset_fpu, -1);
|
||||
CALL(const_native_fsave, -1);
|
||||
NATIVE_RESTORE_X87PC();
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FNSTSW m2byte");
|
||||
//fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x4, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
LDRw_U12(x2, xEmu, offsetof(x64emu_t, top));
|
||||
LDRH_U12(x3, xEmu, offsetof(x64emu_t, sw));
|
||||
|
||||
@@ -101,11 +101,13 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0))
|
||||
{
|
||||
FCMPS(v1, v2);
|
||||
} else {
|
||||
FCMPD(v1, v2);
|
||||
IFX(X_CF|X_PF|X_ZF) {
|
||||
if(ST_IS_F(0))
|
||||
{
|
||||
FCMPS(v1, v2);
|
||||
} else {
|
||||
FCMPD(v1, v2);
|
||||
}
|
||||
}
|
||||
FCOMI(x1, x2);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
@@ -122,11 +124,13 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0))
|
||||
{
|
||||
FCMPS(v1, v2);
|
||||
} else {
|
||||
FCMPD(v1, v2);
|
||||
IFX(X_CF|X_PF|X_ZF) {
|
||||
if(ST_IS_F(0))
|
||||
{
|
||||
FCMPS(v1, v2);
|
||||
} else {
|
||||
FCMPD(v1, v2);
|
||||
}
|
||||
}
|
||||
FCOMI(x1, x2);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
@@ -273,7 +277,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
s0 = x87_stackcount(dyn, ninst, x3);
|
||||
CALL(fpu_fbld, -1);
|
||||
CALL(const_fpu_fbld, -1);
|
||||
x87_unstackcount(dyn, ninst, x3, s0);
|
||||
break;
|
||||
case 5:
|
||||
@@ -310,7 +314,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
CALL(fpu_fbst, -1);
|
||||
CALL(const_fpu_fbst, -1);
|
||||
x87_unstackcount(dyn, ninst, x1, i1);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
@@ -354,7 +358,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
B_MARK3(c__);
|
||||
MARK2;
|
||||
}
|
||||
if(arm64_frintts) {
|
||||
if(cpuext.frintts) {
|
||||
FRINT64XD(s0, v1);
|
||||
VFCVTZSd(s0, s0);
|
||||
VST64(s0, wback, fixedaddress);
|
||||
|
||||
@@ -451,7 +451,7 @@ void emit_and8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw_REG(xFlags, xFlags, s3);
|
||||
}
|
||||
if(arm64_flagm) {
|
||||
if(cpuext.flagm) {
|
||||
COMP_ZFSF(s1, 8)
|
||||
} else {
|
||||
IFX(X_ZF) {
|
||||
@@ -496,7 +496,7 @@ void emit_and8c(dynarec_arm_t* dyn, int ninst, int s1, uint8_t c, int s3, int s4
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
if(arm64_flagm) {
|
||||
if(cpuext.flagm) {
|
||||
COMP_ZFSF(s1, 8)
|
||||
} else {
|
||||
IFX(X_ZF) {
|
||||
@@ -639,7 +639,7 @@ void emit_and16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw_REG(xFlags, xFlags, s3);
|
||||
}
|
||||
if(arm64_flagm) {
|
||||
if(cpuext.flagm) {
|
||||
COMP_ZFSF(s1, 16)
|
||||
} else {
|
||||
IFX(X_ZF) {
|
||||
@@ -684,7 +684,7 @@ void emit_and16c(dynarec_arm_t* dyn, int ninst, int s1, int16_t c, int s3, int s
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
if(arm64_flagm) {
|
||||
if(cpuext.flagm) {
|
||||
COMP_ZFSF(s1, 16)
|
||||
} else {
|
||||
IFX(X_ZF) {
|
||||
|
||||
@@ -991,7 +991,7 @@ void emit_adc32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
}
|
||||
IFNATIVE_BEFORE(NF_CF) {
|
||||
if(INVERTED_CARRY_BEFORE) {
|
||||
if(arm64_flagm)
|
||||
if(cpuext.flagm)
|
||||
CFINV();
|
||||
else {
|
||||
MRS_nzcv(s3);
|
||||
@@ -1134,7 +1134,7 @@ void emit_adc8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
IFNATIVE_BEFORE(NF_CF) {
|
||||
if(INVERTED_CARRY_BEFORE) {
|
||||
if(arm64_flagm)
|
||||
if(cpuext.flagm)
|
||||
CFINV();
|
||||
else {
|
||||
MRS_nzcv(s3);
|
||||
@@ -1198,7 +1198,7 @@ void emit_adc16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
IFNATIVE_BEFORE(NF_CF) {
|
||||
if(INVERTED_CARRY_BEFORE) {
|
||||
if(arm64_flagm)
|
||||
if(cpuext.flagm)
|
||||
CFINV();
|
||||
else {
|
||||
MRS_nzcv(s3);
|
||||
@@ -1321,7 +1321,7 @@ void emit_sbb32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
}
|
||||
IFNATIVE_BEFORE(NF_CF) {
|
||||
if(!INVERTED_CARRY_BEFORE) {
|
||||
if(arm64_flagm)
|
||||
if(cpuext.flagm)
|
||||
CFINV();
|
||||
else {
|
||||
MRS_nzcv(s3);
|
||||
@@ -1470,7 +1470,7 @@ void emit_sbb8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
IFNATIVE_BEFORE(NF_CF) {
|
||||
if(!INVERTED_CARRY_BEFORE) {
|
||||
if(arm64_flagm)
|
||||
if(cpuext.flagm)
|
||||
CFINV();
|
||||
else {
|
||||
MRS_nzcv(s3);
|
||||
@@ -1535,7 +1535,7 @@ void emit_sbb16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
IFNATIVE_BEFORE(NF_CF) {
|
||||
if(!INVERTED_CARRY_BEFORE) {
|
||||
if(arm64_flagm)
|
||||
if(cpuext.flagm)
|
||||
CFINV();
|
||||
else {
|
||||
MRS_nzcv(s3);
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -118,12 +118,12 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEXSD(q0, 0, 0);
|
||||
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
|
||||
if(!BOX64ENV(dynarec_fastround) && !cpuext.frintts) {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
}
|
||||
if(!BOX64ENV(dynarec_fastround) && arm64_frintts) {
|
||||
if(!BOX64ENV(dynarec_fastround) && cpuext.frintts) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
if(rex.w) {
|
||||
FRINT64ZD(v0, q0);
|
||||
@@ -134,7 +134,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
} else {
|
||||
FCVTZSxwD(gd, q0);
|
||||
}
|
||||
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
|
||||
if(!BOX64ENV(dynarec_fastround) && !cpuext.frintts) {
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_NEXT(x5, FPSR_IOC);
|
||||
if(rex.w) {
|
||||
@@ -149,14 +149,14 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEXSD(q0, 0, 0);
|
||||
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
|
||||
if(!BOX64ENV(dynarec_fastround) && !cpuext.frintts) {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
}
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x3);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
if(!BOX64ENV(dynarec_fastround) && arm64_frintts) {
|
||||
if(!BOX64ENV(dynarec_fastround) && cpuext.frintts) {
|
||||
if(rex.w) {
|
||||
FRINT64XD(d1, q0);
|
||||
} else {
|
||||
@@ -167,7 +167,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
FCVTZSxwD(gd, d1);
|
||||
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
|
||||
if(!BOX64ENV(dynarec_fastround) && !cpuext.frintts) {
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_NEXT(x5, FPSR_IOC);
|
||||
if(rex.w) {
|
||||
@@ -187,7 +187,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETEB(x1, 0);
|
||||
GETGD;
|
||||
if(arm64_crc32) {
|
||||
if(cpuext.crc32) {
|
||||
CRC32CB(gd, gd, ed);
|
||||
} else {
|
||||
EORw_REG(gd, gd, ed);
|
||||
@@ -204,7 +204,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
GETGD;
|
||||
if(arm64_crc32) {
|
||||
if(cpuext.crc32) {
|
||||
CRC32Cxw(gd, gd, ed);
|
||||
} else {
|
||||
MOV32w(x2, 0x82f63b78);
|
||||
@@ -430,7 +430,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
INST_NAME("HSUBPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
VUZP1Q_32(d0, v0, v1);
|
||||
VUZP2Q_32(v0, v0, v1);
|
||||
@@ -456,7 +456,6 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
j64 = (uint32_t)(addr+i32_); \
|
||||
else \
|
||||
j64 = addr+i32_; \
|
||||
BARRIER(BARRIER_MAYBE); \
|
||||
JUMP(j64, 1); \
|
||||
GETFLAGS; \
|
||||
if(dyn->insts[ninst].x64.jmp_insts==-1 || \
|
||||
@@ -469,7 +468,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
fpu_purgecache(dyn, ninst, 1, x1, x2, x3); \
|
||||
jump_to_next(dyn, j64, 0, ninst, rex.is32bits); \
|
||||
} else { \
|
||||
CacheTransform(dyn, ninst, cacheupd, x1, x2, x3); \
|
||||
CacheTransform(dyn, ninst, cacheupd); \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size); \
|
||||
SKIP_SEVL(i32); \
|
||||
B(i32); \
|
||||
@@ -523,9 +522,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
static float addsubps[4] = {-1.f, 1.f, -1.f, 1.f};
|
||||
MAYUSE(addsubps);
|
||||
MOV64x(x2, (uintptr_t)&addsubps); // no need to use table64, as box64 is loaded in low memory
|
||||
TABLE64C(x2, const_4f_m1_1_m1_1);
|
||||
VLDR128_U12(q0, x2, 0);
|
||||
VFMLAQS(v0, v1, q0);
|
||||
break;
|
||||
@@ -551,7 +548,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
SQXTN_32(v0, v0); // convert int64 -> int32 with saturation in lower part, RaZ high part
|
||||
} else {
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x3);
|
||||
if(arm64_frintts) {
|
||||
if(cpuext.frintts) {
|
||||
VFRINT32XDQ(v0, v1); // round, handling of overflow and Nan to 0x80000000
|
||||
VFCVTNSQD(v0, v0); // convert double -> int64
|
||||
SQXTN_32(v0, v0); // convert int64 -> int32 with saturation in lower part, RaZ high part
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
|
||||
@@ -119,12 +119,12 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEXSS(d0, 0, 0);
|
||||
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
|
||||
if(!BOX64ENV(dynarec_fastround) && !cpuext.frintts) {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
}
|
||||
if(!BOX64ENV(dynarec_fastround) && arm64_frintts) {
|
||||
if(!BOX64ENV(dynarec_fastround) && cpuext.frintts) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
if(rex.w) {
|
||||
FRINT64ZS(v0, d0);
|
||||
@@ -135,7 +135,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
} else {
|
||||
FCVTZSxwS(gd, d0);
|
||||
}
|
||||
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
|
||||
if(!BOX64ENV(dynarec_fastround) && !cpuext.frintts) {
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_NEXT(x5, FPSR_IOC);
|
||||
if(rex.w) {
|
||||
@@ -150,14 +150,14 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEXSS(q0, 0, 0);
|
||||
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
|
||||
if(!BOX64ENV(dynarec_fastround) && !cpuext.frintts) {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
}
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x3);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
if(!BOX64ENV(dynarec_fastround) && arm64_frintts) {
|
||||
if(!BOX64ENV(dynarec_fastround) && cpuext.frintts) {
|
||||
if(rex.w) {
|
||||
FRINT64XS(d1, q0);
|
||||
} else {
|
||||
@@ -168,7 +168,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
FCVTZSxwS(gd, d1);
|
||||
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
|
||||
if(!BOX64ENV(dynarec_fastround) && !cpuext.frintts) {
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_NEXT(x5, FPSR_IOC);
|
||||
if(rex.w) {
|
||||
@@ -322,7 +322,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(BOX64ENV(dynarec_fastround)) {
|
||||
VFCVTZSQS(v0, v1);
|
||||
} else {
|
||||
if(arm64_frintts) {
|
||||
if(cpuext.frintts) {
|
||||
VFRINT32ZSQ(v0, v1);
|
||||
VFCVTZSQS(v0, v0);
|
||||
} else {
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
@@ -182,7 +181,6 @@ int is_ymm_to_keep(dynarec_arm_t* dyn, int reg, int k1, int k2, int k3)
|
||||
// Reset fpu regs counter
|
||||
static void fpu_reset_reg_neoncache(neoncache_t* n)
|
||||
{
|
||||
n->fpu_reg = 0;
|
||||
for (int i=0; i<32; ++i) {
|
||||
n->fpuused[i]=0;
|
||||
n->neoncache[i].v = 0;
|
||||
@@ -563,7 +561,6 @@ void neoncacheUnwind(neoncache_t* cache)
|
||||
// And now, rebuild the x87cache info with neoncache
|
||||
cache->mmxcount = 0;
|
||||
cache->fpu_scratch = 0;
|
||||
cache->fpu_reg = 0;
|
||||
for(int i=0; i<8; ++i) {
|
||||
cache->x87cache[i] = -1;
|
||||
cache->mmxcache[i] = -1;
|
||||
@@ -579,13 +576,11 @@ void neoncacheUnwind(neoncache_t* cache)
|
||||
case NEON_CACHE_MM:
|
||||
cache->mmxcache[cache->neoncache[i].n] = i;
|
||||
++cache->mmxcount;
|
||||
++cache->fpu_reg;
|
||||
break;
|
||||
case NEON_CACHE_XMMR:
|
||||
case NEON_CACHE_XMMW:
|
||||
cache->ssecache[cache->neoncache[i].n].reg = i;
|
||||
cache->ssecache[cache->neoncache[i].n].write = (cache->neoncache[i].t==NEON_CACHE_XMMW)?1:0;
|
||||
++cache->fpu_reg;
|
||||
break;
|
||||
case NEON_CACHE_YMMR:
|
||||
case NEON_CACHE_YMMW:
|
||||
@@ -597,7 +592,6 @@ void neoncacheUnwind(neoncache_t* cache)
|
||||
cache->x87cache[x87reg] = cache->neoncache[i].n;
|
||||
cache->x87reg[x87reg] = i;
|
||||
++x87reg;
|
||||
++cache->fpu_reg;
|
||||
break;
|
||||
case NEON_CACHE_SCR:
|
||||
cache->fpuused[i] = 0;
|
||||
@@ -617,7 +611,6 @@ void neoncacheUnwind(neoncache_t* cache)
|
||||
cache->neoncache[reg].n = i;
|
||||
cache->ssecache[i].reg = reg;
|
||||
cache->ssecache[i].write = (cache->xmm_write&(1<<i))?1:0;
|
||||
++cache->fpu_reg;
|
||||
}
|
||||
cache->xmm_write = cache->xmm_removed = 0;
|
||||
}
|
||||
@@ -777,10 +770,17 @@ static register_mapping_t register_mappings[] = {
|
||||
void printf_x64_instruction(dynarec_native_t* dyn, zydis_dec_t* dec, instruction_x64_t* inst, const char* name);
|
||||
void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t rex)
|
||||
{
|
||||
if (!dyn->need_dump && !BOX64ENV(dynarec_gdbjit) && !BOX64ENV(dynarec_perf_map)) return;
|
||||
if (!dyn->need_dump && !BOX64ENV(dynarec_gdbjit) && !BOX64ENV(dynarec_perf_map)) {
|
||||
/*zydis_dec_t* dec = rex.is32bits ? my_context->dec32 : my_context->dec;
|
||||
if(dec && !OpcodeOK(dec, dyn->insts[ninst].x64.addr) && !strstr(name, "Illegal")) {
|
||||
uint8_t* p = (uint8_t*)dyn->insts[ninst].x64.addr;
|
||||
printf_log(LOG_INFO, "Warning: %p invalid opcode %02x %02x %02x %02x %02x %02x treated as valid\n", p, p[0], p[1], p[2], p[3], p[4], p[5]);
|
||||
}*/
|
||||
return;
|
||||
}
|
||||
|
||||
static char buf[4096];
|
||||
int length = sprintf(buf, "barrier=%d state=%d/%d/%d(%d:%d->%d:%d), %s=%X/%X, use=%X, need=%X/%X, sm=%d(%d/%d)",
|
||||
int length = sprintf(buf, "barrier=%d state=%d/%d/%d(%d:%d->%d:%d), %s=%X/%X, use=%X, need=%X/%X, sm=%d(%d/%d/%d)",
|
||||
dyn->insts[ninst].x64.barrier,
|
||||
dyn->insts[ninst].x64.state_flags,
|
||||
dyn->f.pending,
|
||||
@@ -795,7 +795,7 @@ void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t r
|
||||
dyn->insts[ninst].x64.use_flags,
|
||||
dyn->insts[ninst].x64.need_before,
|
||||
dyn->insts[ninst].x64.need_after,
|
||||
dyn->smwrite, dyn->insts[ninst].will_write, dyn->insts[ninst].last_write);
|
||||
dyn->smwrite, dyn->insts[ninst].will_write, dyn->insts[ninst].last_write, dyn->insts[ninst].lock);
|
||||
if (dyn->insts[ninst].nat_flags_op) {
|
||||
if (dyn->insts[ninst].nat_flags_op == NAT_FLAG_OP_TOUCH && dyn->insts[ninst].before_nat_flags)
|
||||
length += sprintf(buf + length, " NF:%d/read:%x", dyn->insts[ninst].nat_flags_op, dyn->insts[ninst].before_nat_flags);
|
||||
@@ -1155,6 +1155,7 @@ void updateNativeFlags(dynarec_native_t* dyn)
|
||||
void rasNativeState(dynarec_arm_t* dyn, int ninst)
|
||||
{
|
||||
dyn->insts[ninst].nat_flags_op = dyn->insts[ninst].set_nat_flags = dyn->insts[ninst].use_nat_flags = dyn->insts[ninst].need_nat_flags = 0;
|
||||
dyn->insts[ninst].ymm0_in = dyn->insts[ninst].ymm0_sub = dyn->insts[ninst].ymm0_add = dyn->insts[ninst].ymm0_out = dyn->insts[ninst].purge_ymm = 0;
|
||||
}
|
||||
|
||||
int nativeFlagsNeedsTransform(dynarec_arm_t* dyn, int ninst)
|
||||
@@ -1196,30 +1197,21 @@ void fpu_unwind_restore(dynarec_arm_t* dyn, int ninst, neoncache_t* cache)
|
||||
memcpy(&dyn->insts[ninst].n, cache, sizeof(neoncache_t));
|
||||
}
|
||||
|
||||
static void propagateXMMUneeded(dynarec_arm_t* dyn, int ninst, int a)
|
||||
static void propagateXYMMUneeded(dynarec_arm_t* dyn, int ninst, uint16_t mask_x, uint16_t mask_y)
|
||||
{
|
||||
if(!ninst) return;
|
||||
ninst = getNominalPred(dyn, ninst);
|
||||
while(ninst>=0) {
|
||||
if(dyn->insts[ninst].n.xmm_used&(1<<a)) return; // used, value is needed
|
||||
mask_x &= ~dyn->insts[ninst].n.xmm_used;
|
||||
mask_y &= ~dyn->insts[ninst].n.ymm_used;
|
||||
if(!mask_x && !mask_y) return; // used, value is needed
|
||||
if(dyn->insts[ninst].x64.barrier&BARRIER_FLOAT) return; // barrier, value is needed
|
||||
if(dyn->insts[ninst].n.xmm_unneeded&(1<<a)) return; // already handled
|
||||
mask_x &= ~dyn->insts[ninst].n.xmm_unneeded;
|
||||
mask_y &= ~dyn->insts[ninst].n.ymm_unneeded;
|
||||
if(!mask_x && !mask_y) return; // already handled
|
||||
if(dyn->insts[ninst].x64.jmp) return; // stop when a jump is detected, that gets too complicated
|
||||
dyn->insts[ninst].n.xmm_unneeded |= (1<<a); // flags
|
||||
ninst = getNominalPred(dyn, ninst); // continue
|
||||
}
|
||||
}
|
||||
|
||||
static void propagateYMMUneeded(dynarec_arm_t* dyn, int ninst, int a)
|
||||
{
|
||||
if(!ninst) return;
|
||||
ninst = getNominalPred(dyn, ninst);
|
||||
while(ninst>=0) {
|
||||
if(dyn->insts[ninst].n.ymm_used&(1<<a)) return; // used, value is needed
|
||||
if(dyn->insts[ninst].x64.barrier&BARRIER_FLOAT) return; // barrier, value is needed
|
||||
if(dyn->insts[ninst].n.ymm_unneeded&(1<<a)) return; // already handled
|
||||
if(dyn->insts[ninst].x64.jmp) return; // stop when a jump is detected, that gets too complicated
|
||||
dyn->insts[ninst].n.ymm_unneeded |= (1<<a); // flags
|
||||
dyn->insts[ninst].n.xmm_unneeded |= mask_x; // flags
|
||||
dyn->insts[ninst].n.ymm_unneeded |= mask_y; // flags
|
||||
ninst = getNominalPred(dyn, ninst); // continue
|
||||
}
|
||||
}
|
||||
@@ -1227,13 +1219,178 @@ static void propagateYMMUneeded(dynarec_arm_t* dyn, int ninst, int a)
|
||||
void updateUneeded(dynarec_arm_t* dyn)
|
||||
{
|
||||
for(int ninst=0; ninst<dyn->size; ++ninst) {
|
||||
if(dyn->insts[ninst].n.xmm_unneeded)
|
||||
for(int i=0; i<16; ++i)
|
||||
if(dyn->insts[ninst].n.xmm_unneeded&(1<<i))
|
||||
propagateXMMUneeded(dyn, ninst, i);
|
||||
if(dyn->insts[ninst].n.ymm_unneeded)
|
||||
for(int i=0; i<16; ++i)
|
||||
if(dyn->insts[ninst].n.ymm_unneeded&(1<<i))
|
||||
propagateYMMUneeded(dyn, ninst, i);
|
||||
if(dyn->insts[ninst].n.xmm_unneeded || dyn->insts[ninst].n.ymm_unneeded)
|
||||
propagateXYMMUneeded(dyn, ninst, dyn->insts[ninst].n.xmm_unneeded, dyn->insts[ninst].n.ymm_unneeded);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tryEarlyFpuBarrier(dynarec_arm_t* dyn, int last_fpu_used, int ninst)
|
||||
{
|
||||
// there is a barrier at ninst
|
||||
// check if, up to last fpu_used, if there is some suspicious jump that would prevent the barrier to be put earlier
|
||||
int usefull = 0;
|
||||
for(int i=ninst-1; i>last_fpu_used; --i)
|
||||
{
|
||||
if(!dyn->insts[i].x64.has_next)
|
||||
return; // break of chain, don't try to be smart for now
|
||||
if(dyn->insts[i].x64.barrier&BARRIER_FLOAT)
|
||||
return; // already done?
|
||||
if(dyn->insts[i].x64.jmp && dyn->insts[i].x64.jmp_insts==-1)
|
||||
usefull = 1;
|
||||
if(dyn->insts[i].x64.jmp && dyn->insts[i].x64.jmp_insts!=-1) {
|
||||
int i2 = dyn->insts[i].x64.jmp_insts;
|
||||
if(i2<last_fpu_used || i2>ninst) {
|
||||
// check if some xmm/ymm/x87 stack are used in landing point
|
||||
if(i2>ninst) {
|
||||
if(dyn->insts[i2].n.xmm_used || dyn->insts[i2].n.ymm_used || dyn->insts[i2].n.stack)
|
||||
return;
|
||||
}
|
||||
// we will stop there, not trying to guess too much thing
|
||||
if((usefull && (i+1)!=ninst)) {
|
||||
if(BOX64ENV(dynarec_dump) || BOX64ENV(dynarec_log)>1) dynarec_log(LOG_NONE, "Putting early Float Barrier in %d for %d\n", i+1, ninst);
|
||||
dyn->insts[i+1].x64.barrier|=BARRIER_FLOAT;
|
||||
}
|
||||
return;
|
||||
}
|
||||
usefull = 1;
|
||||
}
|
||||
for(int pred=0; pred<dyn->insts[i].pred_sz; ++pred) {
|
||||
if(dyn->insts[i].pred[pred]<=last_fpu_used) {
|
||||
if(usefull && ((i+1)!=ninst)) {
|
||||
if(BOX64ENV(dynarec_dump) || BOX64ENV(dynarec_log)>1) dynarec_log(LOG_NONE, "Putting early Float Barrier in %d for %d\n", i+1, ninst);
|
||||
dyn->insts[i+1].x64.barrier|=BARRIER_FLOAT;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(dyn->insts[i].pred_sz>1)
|
||||
usefull = 1;
|
||||
}
|
||||
if(usefull) {
|
||||
if(BOX64ENV(dynarec_dump) || BOX64ENV(dynarec_log)>1) dynarec_log(LOG_NONE, "Putting early Float Barrier in %d for %d\n", last_fpu_used, ninst);
|
||||
dyn->insts[last_fpu_used+1].x64.barrier|=BARRIER_FLOAT;
|
||||
}
|
||||
}
|
||||
|
||||
void propagateFpuBarrier(dynarec_arm_t* dyn)
|
||||
{
|
||||
int last_fpu_used = -1;
|
||||
for(int ninst=0; ninst<dyn->size; ++ninst) {
|
||||
int fpu_used = dyn->insts[ninst].n.xmm_used || dyn->insts[ninst].n.ymm_used || dyn->insts[ninst].mmx_used || dyn->insts[ninst].x87_used;
|
||||
if(fpu_used) last_fpu_used = ninst;
|
||||
dyn->insts[ninst].fpu_used = fpu_used;
|
||||
if(dyn->insts[ninst].fpupurge && (last_fpu_used!=-1) && (last_fpu_used!=(ninst-1))) {
|
||||
tryEarlyFpuBarrier(dyn, last_fpu_used, ninst);
|
||||
last_fpu_used = -1; // reset the last_fpu_used...
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void updateYmm0s(dynarec_arm_t* dyn, int ninst, int max_ninst_reached)
|
||||
{
|
||||
int can_incr = ninst == max_ninst_reached; // Are we the top-level call?
|
||||
int ok = 1;
|
||||
while ((can_incr || ok) && ninst < dyn->size) {
|
||||
// if(dyn->need_dump) dynarec_log(LOG_NONE, "update ninst=%d (%d): can_incr=%d\n", ninst, max_ninst_reached, can_incr);
|
||||
uint16_t new_purge_ymm, new_ymm0_in, new_ymm0_out;
|
||||
|
||||
if (dyn->insts[ninst].pred_sz && dyn->insts[ninst].x64.alive) {
|
||||
// The union of the empty set is empty (0), the intersection is the universe (-1)
|
||||
// The first instruction is the entry point, which has a virtual pred with ymm0_out = 0
|
||||
// Similarly, float barriers reset ymm0s
|
||||
uint16_t ymm0_union = 0;
|
||||
uint16_t ymm0_inter = (ninst && !(dyn->insts[ninst].x64.barrier & BARRIER_FLOAT)) ? ((uint16_t)-1) : (uint16_t)0;
|
||||
for (int i = 0; i < dyn->insts[ninst].pred_sz; ++i) {
|
||||
int pred = dyn->insts[ninst].pred[i];
|
||||
// if(dyn->need_dump) dynarec_log(LOG_NONE, "\twith pred[%d] = %d", i, pred);
|
||||
if (pred >= max_ninst_reached) {
|
||||
// if(dyn->need_dump) dynarec_log(LOG_NONE, " (skipped)\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
int pred_out = dyn->insts[pred].x64.has_callret ? 0 : dyn->insts[pred].ymm0_out;
|
||||
// if(dyn->need_dump) dynarec_log(LOG_NONE, " ~> %04X\n", pred_out);
|
||||
ymm0_union |= pred_out;
|
||||
ymm0_inter &= pred_out;
|
||||
}
|
||||
// if(dyn->need_dump) dynarec_log(LOG_NONE, "\t=> %04X,%04X\n", ymm0_union, ymm0_inter);
|
||||
// Notice the default values yield something coherent here (if all pred are after ninst)
|
||||
new_purge_ymm = ymm0_union & ~ymm0_inter;
|
||||
new_ymm0_in = ymm0_inter;
|
||||
new_ymm0_out = (ymm0_inter | dyn->insts[ninst].ymm0_add) & ~dyn->insts[ninst].ymm0_sub;
|
||||
|
||||
if ((dyn->insts[ninst].purge_ymm != new_purge_ymm) || (dyn->insts[ninst].ymm0_in != new_ymm0_in) || (dyn->insts[ninst].ymm0_out != new_ymm0_out)) {
|
||||
// Need to update self and next(s)
|
||||
dyn->insts[ninst].purge_ymm = new_purge_ymm;
|
||||
dyn->insts[ninst].ymm0_in = new_ymm0_in;
|
||||
dyn->insts[ninst].ymm0_out = new_ymm0_out;
|
||||
|
||||
if (can_incr) {
|
||||
// We always have ninst == max_ninst_reached when can_incr == 1
|
||||
++max_ninst_reached;
|
||||
} else {
|
||||
// We need to stop here if the opcode has no "real" next or if we reached the ninst of the toplevel
|
||||
ok = (max_ninst_reached - 1 != ninst) && dyn->insts[ninst].x64.has_next && !dyn->insts[ninst].x64.has_callret;
|
||||
}
|
||||
|
||||
int jmp = (dyn->insts[ninst].x64.jmp) ? dyn->insts[ninst].x64.jmp_insts : -1;
|
||||
if ((jmp != -1) && (jmp < max_ninst_reached)) {
|
||||
// if(dyn->need_dump) dynarec_log(LOG_NONE, "\t! jump to %d\n", jmp);
|
||||
// The jump goes before the last instruction reached, update the destination
|
||||
// If this is the top level call, this means the jump goes backward (jmp != ninst)
|
||||
// Otherwise, since we don't update all instructions, we may miss the update (don't use jmp < ninst)
|
||||
updateYmm0s(dyn, jmp, max_ninst_reached);
|
||||
}
|
||||
} else {
|
||||
if (can_incr) {
|
||||
// We always have ninst == max_ninst_reached when can_incr == 1
|
||||
++max_ninst_reached;
|
||||
|
||||
// Also update jumps to before (they are skipped otherwise)
|
||||
int jmp = (dyn->insts[ninst].x64.jmp) ? dyn->insts[ninst].x64.jmp_insts : -1;
|
||||
if ((jmp != -1) && (jmp < max_ninst_reached)) {
|
||||
// if(dyn->need_dump) dynarec_log(LOG_NONE, "\t! jump to %d\n", jmp);
|
||||
updateYmm0s(dyn, jmp, max_ninst_reached);
|
||||
}
|
||||
} else {
|
||||
// We didn't update anything, we can leave
|
||||
ok = 0;
|
||||
}
|
||||
}
|
||||
} else if (can_incr) {
|
||||
// We always have ninst == max_ninst_reached when can_incr == 1
|
||||
++max_ninst_reached;
|
||||
} else {
|
||||
// We didn't update anything, we can leave
|
||||
ok = 0;
|
||||
}
|
||||
++ninst;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// AVX helpers
|
||||
void avx_mark_zero(dynarec_arm_t* dyn, int ninst, int reg)
|
||||
{
|
||||
dyn->ymm_zero |= (1<<reg);
|
||||
}
|
||||
|
||||
int is_avx_zero(dynarec_arm_t* dyn, int ninst, int reg)
|
||||
{
|
||||
return (dyn->ymm_zero>>reg)&1;
|
||||
}
|
||||
|
||||
int is_avx_zero_unset(dynarec_arm_t* dyn, int ninst, int reg)
|
||||
{
|
||||
if((dyn->ymm_zero>>reg)&1) {
|
||||
dyn->ymm_zero &= ~(1<<reg);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void avx_mark_zero_reset(dynarec_arm_t* dyn, int ninst)
|
||||
{
|
||||
dyn->ymm_zero = 0;
|
||||
}
|
||||
@@ -86,7 +86,17 @@ void fpu_reset_ninst(dynarec_native_t* dyn, int ninst);
|
||||
// is st freed
|
||||
int fpu_is_st_freed(dynarec_native_t* dyn, int ninst, int st);
|
||||
|
||||
// propage FPU_BARRIER to trigger it as soon as possible (avoiding fetching an FPU reg if it's unused)
|
||||
void propagateFpuBarrier(dynarec_arm_t* dyn);
|
||||
// propage the uneeded flags on XMM/YMM regs (done between step 0 and step 1)
|
||||
void updateUneeded(dynarec_arm_t* dyn);
|
||||
|
||||
void updateYmm0s(dynarec_arm_t* dyn, int ninst, int max_ninst_reached);
|
||||
|
||||
// AVX helpers
|
||||
void avx_mark_zero(dynarec_arm_t* dyn, int ninst, int reg);
|
||||
int is_avx_zero(dynarec_arm_t* dyn, int ninst, int reg);
|
||||
int is_avx_zero_unset(dynarec_arm_t* dyn, int ninst, int reg);
|
||||
void avx_mark_zero_reset(dynarec_arm_t* dyn, int ninst);
|
||||
|
||||
#endif //__DYNAREC_ARM_FUNCTIONS_H__
|
||||
@@ -31,8 +31,7 @@ uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, u
|
||||
MAYUSE(dyn); MAYUSE(ninst); MAYUSE(delta);
|
||||
|
||||
if (l == LOCK_LOCK) {
|
||||
dyn->insts[ninst].lock_prefixed = 1;
|
||||
DMB_ISH();
|
||||
dyn->insts[ninst].lock = 1;
|
||||
}
|
||||
|
||||
if(rex.is32bits)
|
||||
@@ -101,7 +100,7 @@ uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, u
|
||||
} else if(tmp<0 && tmp>-0x1000) {
|
||||
GETIP(addr+delta);
|
||||
SUBx_U12(ret, xRIP, -tmp);
|
||||
} else if(tmp+addr+delta<0x1000000000000LL) { // 3 opcodes to load immediate is cheap enough
|
||||
} else if((tmp+addr+delta<0x1000000000000LL) && !dyn->need_reloc) { // 3 opcodes to load immediate is cheap enough
|
||||
MOV64x(ret, tmp+addr+delta);
|
||||
} else {
|
||||
MOV64x(ret, tmp);
|
||||
@@ -560,62 +559,91 @@ void jump_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst)
|
||||
GETIP_(ip);
|
||||
}
|
||||
NOTEST(x2);
|
||||
TABLE64(x2, (uintptr_t)arm64_epilog);
|
||||
TABLE64C(x2, const_epilog);
|
||||
SMEND();
|
||||
BR(x2);
|
||||
}
|
||||
|
||||
|
||||
static int indirect_lookup(dynarec_arm_t* dyn, int ninst, int is32bits, int s1, int s2)
|
||||
{
|
||||
MAYUSE(dyn);
|
||||
|
||||
if (!is32bits) {
|
||||
// check higher 48bits
|
||||
LSRx_IMM(s1, xRIP, 48);
|
||||
intptr_t j64 = (intptr_t)dyn->jmp_next - (intptr_t)dyn->block;
|
||||
CBNZw(s1, j64);
|
||||
// load table
|
||||
if(dyn->need_reloc) {
|
||||
TABLE64C(s2, const_jmptbl48);
|
||||
} else {
|
||||
MOV64x(s2, getConst(const_jmptbl48)); // this is a static value, so will be a low address
|
||||
}
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
UBFXx(s1, xRIP, JMPTABL_START3, JMPTABL_SHIFT3);
|
||||
LDRx_REG_LSL3(s2, s2, s1);
|
||||
#endif
|
||||
UBFXx(s1, xRIP, JMPTABL_START2, JMPTABL_SHIFT2);
|
||||
LDRx_REG_LSL3(s2, s2, s1);
|
||||
} else {
|
||||
// check higher 32bits disabled
|
||||
// LSRx_IMM(s1, xRIP, 32);
|
||||
// intptr_t j64 = (intptr_t)dyn->jmp_next - (intptr_t)dyn->block;
|
||||
// CBNZw(s1, j64);
|
||||
// load table
|
||||
TABLE64C(s2, const_jmptbl32);
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
UBFXx(s1, xRIP, JMPTABL_START2, JMPTABL_SHIFT2);
|
||||
LDRx_REG_LSL3(s2, s2, s1);
|
||||
#endif
|
||||
}
|
||||
UBFXx(s1, xRIP, JMPTABL_START1, JMPTABL_SHIFT1);
|
||||
LDRx_REG_LSL3(s2, s2, s1);
|
||||
UBFXx(s1, xRIP, JMPTABL_START0, JMPTABL_SHIFT0);
|
||||
LDRx_REG_LSL3(s1, s2, s1);
|
||||
return s1;
|
||||
}
|
||||
|
||||
void jump_to_next(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst, int is32bits)
|
||||
{
|
||||
MAYUSE(dyn); MAYUSE(ninst);
|
||||
MAYUSE(dyn);
|
||||
MAYUSE(ninst);
|
||||
MESSAGE(LOG_DUMP, "Jump to next\n");
|
||||
|
||||
if(is32bits)
|
||||
if (is32bits)
|
||||
ip &= 0xffffffffLL;
|
||||
|
||||
SMEND();
|
||||
if(reg) {
|
||||
if(reg!=xRIP) {
|
||||
|
||||
int dest;
|
||||
if (reg) {
|
||||
if (reg != xRIP) {
|
||||
MOVx_REG(xRIP, reg);
|
||||
}
|
||||
NOTEST(x2);
|
||||
uintptr_t tbl = is32bits?getJumpTable32():getJumpTable64();
|
||||
MAYUSE(tbl);
|
||||
MOV64x(x3, tbl);
|
||||
if(!is32bits) {
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
UBFXx(x2, xRIP, JMPTABL_START4, JMPTABL_SHIFT4);
|
||||
LDRx_REG_LSL3(x3, x3, x2);
|
||||
#endif
|
||||
UBFXx(x2, xRIP, JMPTABL_START3, JMPTABL_SHIFT3);
|
||||
LDRx_REG_LSL3(x3, x3, x2);
|
||||
}
|
||||
UBFXx(x2, xRIP, JMPTABL_START2, JMPTABL_SHIFT2);
|
||||
LDRx_REG_LSL3(x3, x3, x2);
|
||||
UBFXx(x2, xRIP, JMPTABL_START1, JMPTABL_SHIFT1);
|
||||
LDRx_REG_LSL3(x3, x3, x2);
|
||||
UBFXx(x2, xRIP, JMPTABL_START0, JMPTABL_SHIFT0);
|
||||
LDRx_REG_LSL3(x2, x3, x2);
|
||||
dest = indirect_lookup(dyn, ninst, is32bits, x2, x3);
|
||||
} else {
|
||||
NOTEST(x2);
|
||||
uintptr_t p = getJumpTableAddress64(ip);
|
||||
MAYUSE(p);
|
||||
MOV64x(x3, p);
|
||||
if(dyn->need_reloc) AddRelocTable64JmpTbl(dyn, ninst, ip, STEP);
|
||||
TABLE64_(x3, p);
|
||||
GETIP_(ip);
|
||||
LDRx_U12(x2, x3, 0);
|
||||
dest = x2;
|
||||
}
|
||||
if(reg!=x1) {
|
||||
MOVx_REG(x1, xRIP);
|
||||
}
|
||||
CLEARIP();
|
||||
#ifdef HAVE_TRACE
|
||||
//MOVx(x3, 15); no access to PC reg
|
||||
BLR(x2); // save LR...
|
||||
BLR(dest); // save LR...
|
||||
#else
|
||||
if (dyn->insts[ninst].x64.has_callret) {
|
||||
BLR(x2); // save LR...
|
||||
BLR(dest); // save LR...
|
||||
} else {
|
||||
BR(x2);
|
||||
BR(dest);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -636,27 +664,12 @@ void ret_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int ninst, rex_t rex)
|
||||
// not the correct return address, regular jump, but purge the stack first, it's unsync now...
|
||||
SUBx_U12(xSP, xSavedSP, 16);
|
||||
}
|
||||
uintptr_t tbl = rex.is32bits?getJumpTable32():getJumpTable64();
|
||||
NOTEST(x2);
|
||||
MOV64x(x2, tbl);
|
||||
if(!rex.is32bits) {
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
UBFXx(x3, xRIP, JMPTABL_START4, JMPTABL_SHIFT4);
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
#endif
|
||||
UBFXx(x3, xRIP, JMPTABL_START3, JMPTABL_SHIFT3);
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
}
|
||||
UBFXx(x3, xRIP, JMPTABL_START2, JMPTABL_SHIFT2);
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
UBFXx(x3, xRIP, JMPTABL_START1, JMPTABL_SHIFT1);
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
UBFXx(x3, xRIP, JMPTABL_START0, JMPTABL_SHIFT0);
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
int dest = indirect_lookup(dyn, ninst, rex.is32bits, x2, x3);
|
||||
#ifdef HAVE_TRACE
|
||||
BLR(x2);
|
||||
BLR(dest);
|
||||
#else
|
||||
BR(x2);
|
||||
BR(dest);
|
||||
#endif
|
||||
CLEARIP();
|
||||
}
|
||||
@@ -683,27 +696,12 @@ void retn_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int ninst, rex_t rex, int
|
||||
// not the correct return address, regular jump
|
||||
SUBx_U12(xSP, xSavedSP, 16);
|
||||
}
|
||||
uintptr_t tbl = rex.is32bits?getJumpTable32():getJumpTable64();
|
||||
NOTEST(x2);
|
||||
MOV64x(x2, tbl);
|
||||
if(!rex.is32bits) {
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
UBFXx(x3, xRIP, JMPTABL_START4, JMPTABL_SHIFT4);
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
#endif
|
||||
UBFXx(x3, xRIP, JMPTABL_START3, JMPTABL_SHIFT3);
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
}
|
||||
UBFXx(x3, xRIP, JMPTABL_START2, JMPTABL_SHIFT2);
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
UBFXx(x3, xRIP, JMPTABL_START1, JMPTABL_SHIFT1);
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
UBFXx(x3, xRIP, JMPTABL_START0, JMPTABL_SHIFT0);
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
int dest = indirect_lookup(dyn, ninst, rex.is32bits, x2, x3);
|
||||
#ifdef HAVE_TRACE
|
||||
BLR(x2);
|
||||
BLR(dest);
|
||||
#else
|
||||
BR(x2);
|
||||
BR(dest);
|
||||
#endif
|
||||
CLEARIP();
|
||||
}
|
||||
@@ -720,49 +718,70 @@ void iret_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int ninst, int is32bits, i
|
||||
// POP IP
|
||||
NOTEST(x2);
|
||||
if(is64bits) {
|
||||
POP1(xRIP);
|
||||
POP1(x1);
|
||||
POP1(x2);
|
||||
POP1(xFlags);
|
||||
POP1(x3);
|
||||
} else {
|
||||
POP1_32(xRIP);
|
||||
POP1_32(x1);
|
||||
POP1_32(x2);
|
||||
POP1_32(xFlags);
|
||||
POP1_32(x3);
|
||||
}
|
||||
// x2 is CS
|
||||
STRH_U12(x2, xEmu, offsetof(x64emu_t, segs[_CS]));
|
||||
STRw_U12(xZR, xEmu, offsetof(x64emu_t, segs_serial[_CS]));
|
||||
// check CS is NULL, sgfault if it is
|
||||
CBZw_MARK3(x1);
|
||||
// clean EFLAGS
|
||||
MOV32w(x1, 0x3F7FD7);
|
||||
ANDx_REG(xFlags, xFlags, x1);
|
||||
ORRx_mask(xFlags, xFlags, 1, 0b111111, 0); // xFlags | 0b10
|
||||
MOV32w(x4, 0x3F7FD7);
|
||||
ANDx_REG(x3, x3, x4);
|
||||
ORRx_mask(x3, x3, 1, 0b111111, 0); // xFlags | 0b10
|
||||
SET_DFNONE();
|
||||
if(is32bits) {
|
||||
ANDw_mask(x2, x2, 0, 7); // mask 0xff
|
||||
ANDw_mask(x4, x2, 0, 7); // mask 0xff
|
||||
// check if return segment is 64bits, then restore rsp too
|
||||
CMPSw_U12(x2, 0x23);
|
||||
CMPSw_U12(x4, 0x23);
|
||||
B_MARKSEG(cEQ);
|
||||
}
|
||||
// POP RSP
|
||||
if(is64bits) {
|
||||
POP1(x3); //rsp
|
||||
POP1(x2); //ss
|
||||
POP1(x4); //rsp
|
||||
POP1(x5); //ss
|
||||
} else {
|
||||
POP1_32(x3); //rsp
|
||||
POP1_32(x2); //ss
|
||||
POP1_32(x4); //rsp
|
||||
POP1_32(x5); //ss
|
||||
}
|
||||
// check if SS is NULL
|
||||
CBZw_MARK(x5);
|
||||
// POP SS
|
||||
STRH_U12(x2, xEmu, offsetof(x64emu_t, segs[_SS]));
|
||||
STRH_U12(x5, xEmu, offsetof(x64emu_t, segs[_SS]));
|
||||
STRw_U12(xZR, xEmu, offsetof(x64emu_t, segs_serial[_SS]));
|
||||
// set new RSP
|
||||
MOVx_REG(xRSP, x3);
|
||||
MOVx_REG(xRSP, x4);
|
||||
MARKSEG;
|
||||
// x2 is CS, x1 is IP, x3 is eFlags
|
||||
STRH_U12(x2, xEmu, offsetof(x64emu_t, segs[_CS]));
|
||||
STRw_U12(xZR, xEmu, offsetof(x64emu_t, segs_serial[_CS]));
|
||||
MOVx_REG(xRIP, x1);
|
||||
MOVw_REG(xFlags, x3);
|
||||
// Ret....
|
||||
MOV64x(x2, (uintptr_t)arm64_epilog); // epilog on purpose, CS might have changed!
|
||||
// epilog on purpose, CS might have changed!
|
||||
if(dyn->need_reloc)
|
||||
TABLE64C(x2, const_epilog);
|
||||
else
|
||||
MOV64x(x2, getConst(const_epilog));
|
||||
BR(x2);
|
||||
CLEARIP();
|
||||
MARK;
|
||||
if(is64bits)
|
||||
ADDx_U12(xRSP, xRSP, 8*2);
|
||||
else
|
||||
ADDx_U12(xRSP, xRSP, 4*2);
|
||||
MARK3;
|
||||
if(is64bits)
|
||||
ADDx_U12(xRSP, xRSP, 8*3);
|
||||
else
|
||||
ADDx_U12(xRSP, xRSP, 4*3);
|
||||
CALL_S(const_native_priv, -1);
|
||||
}
|
||||
|
||||
void call_c(dynarec_arm_t* dyn, int ninst, void* fnc, int reg, int ret, int saveflags, int savereg)
|
||||
void call_c(dynarec_arm_t* dyn, int ninst, arm64_consts_t fnc, int reg, int ret, int saveflags, int savereg)
|
||||
{
|
||||
MAYUSE(fnc);
|
||||
#if STEP == 0
|
||||
@@ -785,7 +804,7 @@ void call_c(dynarec_arm_t* dyn, int ninst, void* fnc, int reg, int ret, int save
|
||||
#ifdef _WIN32
|
||||
LDRx_U12(xR8, xEmu, offsetof(x64emu_t, win64_teb));
|
||||
#endif
|
||||
TABLE64(reg, (uintptr_t)fnc);
|
||||
TABLE64C(reg, fnc);
|
||||
BLR(reg);
|
||||
if(ret>=0) {
|
||||
MOVx_REG(ret, xEmu);
|
||||
@@ -816,7 +835,7 @@ void call_c(dynarec_arm_t* dyn, int ninst, void* fnc, int reg, int ret, int save
|
||||
//SET_NODF();
|
||||
}
|
||||
|
||||
void call_i(dynarec_arm_t* dyn, int ninst, void* fnc)
|
||||
void call_i(dynarec_arm_t* dyn, int ninst, arm64_consts_t fnc)
|
||||
{
|
||||
MAYUSE(fnc);
|
||||
#if STEP == 0
|
||||
@@ -837,7 +856,7 @@ void call_i(dynarec_arm_t* dyn, int ninst, void* fnc)
|
||||
#ifdef _WIN32
|
||||
LDRx_U12(xR8, xEmu, offsetof(x64emu_t, win64_teb));
|
||||
#endif
|
||||
TABLE64(x87pc, (uintptr_t)fnc);
|
||||
TABLE64C(x87pc, fnc);
|
||||
BLR(x87pc);
|
||||
LDPx_S7_postindex(xEmu, x1, xSP, 16);
|
||||
LDPx_S7_postindex(x2, x3, xSP, 16);
|
||||
@@ -886,7 +905,13 @@ void call_n(dynarec_arm_t* dyn, int ninst, void* fnc, int w)
|
||||
MOVx_REG(x4, xR8);
|
||||
MOVx_REG(x5, xR9);
|
||||
// native call
|
||||
TABLE64(16, (uintptr_t)fnc); // using x16 as scratch regs for call address
|
||||
if(dyn->need_reloc) {
|
||||
// fnc is indirect, to help with relocation (but PltResolver might be an issue here)
|
||||
TABLE64(16, (uintptr_t)fnc);
|
||||
LDRx_U12(16, 16, 0);
|
||||
} else {
|
||||
TABLE64_(16, *(uintptr_t*)fnc); // using x16 as scratch regs for call address
|
||||
}
|
||||
BLR(16);
|
||||
// put return value in x64 regs
|
||||
if(w>0) {
|
||||
@@ -914,6 +939,9 @@ void grab_segdata(dynarec_arm_t* dyn, uintptr_t addr, int ninst, int reg, int se
|
||||
MESSAGE(LOG_DUMP, "Get %s Offset\n", (segment==_FS)?"FS":"GS");
|
||||
int t2 = x4;
|
||||
if(reg==t2) ++t2;
|
||||
#ifdef _WIN32
|
||||
LDRx_U12(reg, xEmu, offsetof(x64emu_t, segs_offs[segment]));
|
||||
#else
|
||||
LDRw_U12(t2, xEmu, offsetof(x64emu_t, segs_serial[segment]));
|
||||
/*if(segment==_GS) {
|
||||
LDRx_U12(reg, xEmu, offsetof(x64emu_t, segs_offs[segment]));
|
||||
@@ -926,8 +954,9 @@ void grab_segdata(dynarec_arm_t* dyn, uintptr_t addr, int ninst, int reg, int se
|
||||
CBZw_MARKSEG(t2);
|
||||
}
|
||||
MOVZw(x1, segment);
|
||||
call_c(dyn, ninst, GetSegmentBaseEmu, t2, reg, 1, 0);
|
||||
call_c(dyn, ninst, const_getsegmentbase, t2, reg, 1, 0);
|
||||
MARKSEG;
|
||||
#endif
|
||||
MESSAGE(LOG_DUMP, "----%s Offset\n", (segment==_FS)?"FS":"GS");
|
||||
}
|
||||
|
||||
@@ -1016,6 +1045,7 @@ int neoncache_st_coherency(dynarec_arm_t* dyn, int ninst, int a, int b)
|
||||
// the reg returned is *2 for FLOAT
|
||||
int x87_do_push(dynarec_arm_t* dyn, int ninst, int s1, int t)
|
||||
{
|
||||
dyn->insts[ninst].x87_used = 1;
|
||||
if(dyn->n.mmxcount)
|
||||
mmx_purgecache(dyn, ninst, 0, s1);
|
||||
dyn->n.x87stack+=1;
|
||||
@@ -1050,6 +1080,7 @@ int x87_do_push(dynarec_arm_t* dyn, int ninst, int s1, int t)
|
||||
}
|
||||
void x87_do_push_empty(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
{
|
||||
dyn->insts[ninst].x87_used = 1;
|
||||
if(dyn->n.mmxcount)
|
||||
mmx_purgecache(dyn, ninst, 0, s1);
|
||||
dyn->n.x87stack+=1;
|
||||
@@ -1099,6 +1130,7 @@ static int internal_x87_dofree(dynarec_arm_t* dyn)
|
||||
}
|
||||
void x87_do_pop(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
{
|
||||
dyn->insts[ninst].x87_used = 1;
|
||||
if(dyn->n.mmxcount)
|
||||
mmx_purgecache(dyn, ninst, 0, s1);
|
||||
do {
|
||||
@@ -1181,17 +1213,7 @@ void x87_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1, int s2, int
|
||||
for (int i=0; i<8; ++i)
|
||||
if(dyn->n.x87cache[i]!=-1) {
|
||||
int st = dyn->n.x87cache[i]+dyn->n.stack_pop;
|
||||
#if STEP == 1
|
||||
if(!next) { // don't force promotion here
|
||||
// pre-apply pop, because purge happens in-between
|
||||
neoncache_promote_double(dyn, ninst, st);
|
||||
}
|
||||
#endif
|
||||
#if STEP == 3
|
||||
if(!next && neoncache_get_current_st(dyn, ninst, st)!=NEON_CACHE_ST_D) {
|
||||
MESSAGE(LOG_DUMP, "Warning, incoherency with purged ST%d cache\n", st);
|
||||
}
|
||||
#endif
|
||||
// don't force promotion here
|
||||
ADDw_U12(s3, s2, dyn->n.x87cache[i]); // unadjusted count, as it's relative to real top
|
||||
ANDw_mask(s3, s3, 0, 2); //mask=7 // (emu->top + st)&7
|
||||
switch(neoncache_get_current_st(dyn, ninst, st)) {
|
||||
@@ -1366,6 +1388,7 @@ void x87_unreflectcount(dynarec_arm_t* dyn, int ninst, int s1, int s2)
|
||||
|
||||
int x87_get_current_cache(dynarec_arm_t* dyn, int ninst, int st, int t)
|
||||
{
|
||||
dyn->insts[ninst].x87_used = 1;
|
||||
// search in cache first
|
||||
for (int i=0; i<8; ++i) {
|
||||
if(dyn->n.x87cache[i]==st) {
|
||||
@@ -1386,6 +1409,7 @@ int x87_get_current_cache(dynarec_arm_t* dyn, int ninst, int st, int t)
|
||||
|
||||
int x87_get_cache(dynarec_arm_t* dyn, int ninst, int populate, int s1, int s2, int st, int t)
|
||||
{
|
||||
dyn->insts[ninst].x87_used = 1;
|
||||
if(dyn->n.mmxcount)
|
||||
mmx_purgecache(dyn, ninst, 0, s1);
|
||||
int ret = x87_get_current_cache(dyn, ninst, st, t);
|
||||
@@ -1419,6 +1443,7 @@ int x87_get_cache(dynarec_arm_t* dyn, int ninst, int populate, int s1, int s2, i
|
||||
}
|
||||
int x87_get_neoncache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st)
|
||||
{
|
||||
dyn->insts[ninst].x87_used = 1;
|
||||
for(int ii=0; ii<24; ++ii)
|
||||
if((dyn->n.neoncache[ii].t == NEON_CACHE_ST_F
|
||||
|| dyn->n.neoncache[ii].t == NEON_CACHE_ST_D
|
||||
@@ -1430,10 +1455,12 @@ int x87_get_neoncache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st)
|
||||
}
|
||||
int x87_get_st(dynarec_arm_t* dyn, int ninst, int s1, int s2, int a, int t)
|
||||
{
|
||||
dyn->insts[ninst].x87_used = 1;
|
||||
return dyn->n.x87reg[x87_get_cache(dyn, ninst, 1, s1, s2, a, t)];
|
||||
}
|
||||
int x87_get_st_empty(dynarec_arm_t* dyn, int ninst, int s1, int s2, int a, int t)
|
||||
{
|
||||
dyn->insts[ninst].x87_used = 1;
|
||||
return dyn->n.x87reg[x87_get_cache(dyn, ninst, 0, s1, s2, a, t)];
|
||||
}
|
||||
|
||||
@@ -1488,6 +1515,7 @@ void x87_forget(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st)
|
||||
|
||||
void x87_reget_st(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st)
|
||||
{
|
||||
dyn->insts[ninst].x87_used = 1;
|
||||
if(dyn->n.mmxcount)
|
||||
mmx_purgecache(dyn, ninst, 0, s1);
|
||||
// search in cache first
|
||||
@@ -1538,6 +1566,7 @@ void x87_reget_st(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st)
|
||||
|
||||
void x87_free(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int st)
|
||||
{
|
||||
dyn->insts[ninst].x87_used = 1;
|
||||
int ret = -1;
|
||||
for (int i=0; (i<8) && (ret==-1); ++i)
|
||||
if(dyn->n.x87cache[i] == st)
|
||||
@@ -1671,6 +1700,7 @@ static int isx87Empty(dynarec_arm_t* dyn)
|
||||
// get neon register for a MMX reg, create the entry if needed
|
||||
int mmx_get_reg(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int a)
|
||||
{
|
||||
dyn->insts[ninst].mmx_used = 1;
|
||||
if(!dyn->n.x87stack && isx87Empty(dyn))
|
||||
x87_purgecache(dyn, ninst, 0, s1, s2, s3);
|
||||
if(dyn->n.mmxcache[a]!=-1)
|
||||
@@ -1683,6 +1713,7 @@ int mmx_get_reg(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int a)
|
||||
// get neon register for a MMX reg, but don't try to synch it if it needed to be created
|
||||
int mmx_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int a)
|
||||
{
|
||||
dyn->insts[ninst].mmx_used = 1;
|
||||
if(!dyn->n.x87stack && isx87Empty(dyn))
|
||||
x87_purgecache(dyn, ninst, 0, s1, s2, s3);
|
||||
if(dyn->n.mmxcache[a]!=-1)
|
||||
@@ -2055,8 +2086,10 @@ void fpu_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1, int s2, int
|
||||
x87_purgecache(dyn, ninst, next, s1, s2, s3);
|
||||
mmx_purgecache(dyn, ninst, next, s1);
|
||||
sse_purgecache(dyn, ninst, next, s1);
|
||||
if(!next)
|
||||
if(!next) {
|
||||
fpu_reset_reg(dyn);
|
||||
dyn->insts[ninst].fpupurge = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int findCacheSlot(dynarec_arm_t* dyn, int ninst, int t, int n, neoncache_t* cache)
|
||||
@@ -2179,7 +2212,7 @@ static void loadCache(dynarec_arm_t* dyn, int ninst, int stack_cnt, int s1, int
|
||||
break;
|
||||
case NEON_CACHE_YMMR:
|
||||
case NEON_CACHE_YMMW:
|
||||
if(dyn->insts[i2].n.xmm_unneeded&(1<<n)) {
|
||||
if(dyn->insts[i2].n.ymm_unneeded&(1<<n)) {
|
||||
MESSAGE(LOG_DUMP, "\t - ignoring unneeded %s\n", getCacheName(t, n));
|
||||
} else {
|
||||
MESSAGE(LOG_DUMP, "\t - Loading %s\n", getCacheName(t, n));
|
||||
@@ -2238,7 +2271,7 @@ static void unloadCache(dynarec_arm_t* dyn, int ninst, int stack_cnt, int s1, in
|
||||
MESSAGE(LOG_DUMP, "\t - ignoring %s\n", getCacheName(t, n));
|
||||
break;
|
||||
case NEON_CACHE_XMMW:
|
||||
if(dyn->insts[i2].n.xmm_unneeded&(1<<i)) {
|
||||
if(dyn->insts[i2].n.xmm_unneeded&(1<<n)) {
|
||||
MESSAGE(LOG_DUMP, "\t - ignoring unneeded %s\n", getCacheName(t, n));
|
||||
} else {
|
||||
MESSAGE(LOG_DUMP, "\t - Unloading %s\n", getCacheName(t, n));
|
||||
@@ -2246,7 +2279,7 @@ static void unloadCache(dynarec_arm_t* dyn, int ninst, int stack_cnt, int s1, in
|
||||
}
|
||||
break;
|
||||
case NEON_CACHE_YMMW:
|
||||
if(dyn->insts[i2].n.ymm_unneeded&(1<<i)) {
|
||||
if(dyn->insts[i2].n.ymm_unneeded&(1<<n)) {
|
||||
MESSAGE(LOG_DUMP, "\t - ignoring unneeded %s\n", getCacheName(t, n));
|
||||
} else {
|
||||
MESSAGE(LOG_DUMP, "\t - Unloading %s\n", getCacheName(t, n));
|
||||
@@ -2475,57 +2508,40 @@ static void fpuCacheTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2, int
|
||||
}
|
||||
MESSAGE(LOG_DUMP, "\t---- Cache Transform\n");
|
||||
}
|
||||
static void flagsCacheTransform(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
static void flagsCacheTransform(dynarec_arm_t* dyn, int ninst)
|
||||
{
|
||||
int j64;
|
||||
int jmp = dyn->insts[ninst].x64.jmp_insts;
|
||||
if(jmp<0)
|
||||
return;
|
||||
if(dyn->f.dfnone || (dyn->insts[jmp].f_exit.dfnone_here && !dyn->insts[jmp].x64.use_flags)) // flags are fully known, nothing we can do more
|
||||
if(dyn->f.dfnone || ((dyn->insts[jmp].f_exit.dfnone && !dyn->insts[jmp].f_entry.dfnone) && !dyn->insts[jmp].x64.use_flags)) // flags are fully known, nothing we can do more
|
||||
return;
|
||||
MESSAGE(LOG_DUMP, "\tFlags fetch ---- ninst=%d -> %d\n", ninst, jmp);
|
||||
int go = (dyn->insts[jmp].f_entry.dfnone && !dyn->f.dfnone && !dyn->insts[jmp].df_notneeded)?1:0;
|
||||
switch (dyn->insts[jmp].f_entry.pending) {
|
||||
case SF_UNKNOWN: break;
|
||||
case SF_SET:
|
||||
if(dyn->f.pending!=SF_SET && dyn->f.pending!=SF_SET_PENDING)
|
||||
go = 1;
|
||||
case SF_UNKNOWN:
|
||||
go = 0;
|
||||
break;
|
||||
case SF_SET_PENDING:
|
||||
if(dyn->f.pending!=SF_SET
|
||||
&& dyn->f.pending!=SF_SET_PENDING
|
||||
&& dyn->f.pending!=SF_PENDING
|
||||
) {
|
||||
// only sync if some previous flags are used or if all flags are not regenerated at the instuction
|
||||
if(dyn->insts[jmp].x64.use_flags || (dyn->insts[jmp].x64.set_flags!=X_ALL))
|
||||
go = 1;
|
||||
else if(go) {
|
||||
// just clear df flags
|
||||
go = 0;
|
||||
STRw_U12(xZR, xEmu, offsetof(x64emu_t, df));
|
||||
}
|
||||
default:
|
||||
if(go && !(dyn->insts[jmp].x64.need_before&X_PEND) && (dyn->f.pending!=SF_UNKNOWN)) {
|
||||
// just clear df flags
|
||||
go = 0;
|
||||
STRw_U12(xZR, xEmu, offsetof(x64emu_t, df));
|
||||
}
|
||||
break;
|
||||
case SF_PENDING:
|
||||
if(dyn->f.pending!=SF_SET
|
||||
&& dyn->f.pending!=SF_SET_PENDING
|
||||
&& dyn->f.pending!=SF_PENDING)
|
||||
go = 1;
|
||||
else if (dyn->insts[jmp].f_entry.dfnone !=dyn->f.dfnone)
|
||||
go = 1;
|
||||
break;
|
||||
}
|
||||
if(go) {
|
||||
if(dyn->f.pending!=SF_PENDING) {
|
||||
LDRw_U12(s1, xEmu, offsetof(x64emu_t, df));
|
||||
LDRw_U12(x1, xEmu, offsetof(x64emu_t, df));
|
||||
j64 = (GETMARKF2)-(dyn->native_size);
|
||||
CBZw(s1, j64);
|
||||
CBZw(x1, j64);
|
||||
}
|
||||
if(dyn->insts[ninst].need_nat_flags)
|
||||
MRS_nzcv(s1);
|
||||
CALL_(UpdateFlags, -1, s1);
|
||||
MRS_nzcv(x6);
|
||||
TABLE64C(x1, const_updateflags_arm64);
|
||||
BLR(x1);
|
||||
if(dyn->insts[ninst].need_nat_flags)
|
||||
MSR_nzcv(s1);
|
||||
MSR_nzcv(x6);
|
||||
MARKF2;
|
||||
}
|
||||
}
|
||||
@@ -2595,7 +2611,7 @@ static void nativeFlagsTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2)
|
||||
}
|
||||
// special case for NF_CF changing state
|
||||
if((flags_before&NF_CF) && (flags_after&NF_CF) && (nc_before!=nc_after)) {
|
||||
if(arm64_flagm && !mrs) {
|
||||
if(cpuext.flagm && !mrs) {
|
||||
CFINV();
|
||||
} else {
|
||||
GO_MRS(s2);
|
||||
@@ -2608,13 +2624,14 @@ static void nativeFlagsTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2)
|
||||
MESSAGE(LOG_DUMP, "\t---- Native Flags transform\n");
|
||||
}
|
||||
|
||||
void CacheTransform(dynarec_arm_t* dyn, int ninst, int cacheupd, int s1, int s2, int s3) {
|
||||
// Might use all Scratch registers!
|
||||
void CacheTransform(dynarec_arm_t* dyn, int ninst, int cacheupd) {
|
||||
if(cacheupd&1)
|
||||
flagsCacheTransform(dyn, ninst, s1);
|
||||
flagsCacheTransform(dyn, ninst);
|
||||
if(cacheupd&2)
|
||||
fpuCacheTransform(dyn, ninst, s1, s2, s3);
|
||||
fpuCacheTransform(dyn, ninst, x1, x2, x3);
|
||||
if(cacheupd&4)
|
||||
nativeFlagsTransform(dyn, ninst, s1, s2);
|
||||
nativeFlagsTransform(dyn, ninst, x1, x2);
|
||||
}
|
||||
|
||||
void fpu_reflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
// undef to get Close to SSE Float->int conversions
|
||||
//#define PRECISE_CVT
|
||||
|
||||
#ifndef STEP_PASS
|
||||
#if STEP == 0
|
||||
#include "dynarec_arm64_pass0.h"
|
||||
#elif STEP == 1
|
||||
@@ -13,10 +14,13 @@
|
||||
#elif STEP == 3
|
||||
#include "dynarec_arm64_pass3.h"
|
||||
#endif
|
||||
#define STEP_PASS
|
||||
#endif
|
||||
|
||||
#include "debug.h"
|
||||
#include "arm64_emitter.h"
|
||||
#include "../emu/x64primop.h"
|
||||
#include "dynarec_arm64_consts.h"
|
||||
|
||||
#define F8 *(uint8_t*)(addr++)
|
||||
#define F8S *(int8_t*)(addr++)
|
||||
@@ -215,9 +219,12 @@
|
||||
wb = ed = x1; \
|
||||
}
|
||||
//FAKEELike GETED, but doesn't get anything
|
||||
#define FAKEED \
|
||||
if (!MODREG) { \
|
||||
addr = fakeed(dyn, addr, ninst, nextop); \
|
||||
#define FAKEED \
|
||||
if (MODREG) { \
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3)); \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
addr = fakeed(dyn, addr, ninst, nextop); \
|
||||
}
|
||||
|
||||
// GETGW extract x64 register in gd, that is i
|
||||
@@ -942,7 +949,7 @@
|
||||
#define GEN_INVERTED_CARRY()
|
||||
#endif
|
||||
#ifndef INVERT_CARRY
|
||||
#define INVERT_CARRY(A) if(dyn->insts[ninst].normal_carry) {if(arm64_flagm) CFINV(); else {MRS_nzcv(A); EORx_mask(A, A, 1, 35, 0); MSR_nzcv(A);}}
|
||||
#define INVERT_CARRY(A) if(dyn->insts[ninst].normal_carry) {if(cpuext.flagm) CFINV(); else {MRS_nzcv(A); EORx_mask(A, A, 1, 35, 0); MSR_nzcv(A);}}
|
||||
#endif
|
||||
|
||||
// Generate FCOM with s1 and s2 scratch regs (the VCMP is already done)
|
||||
@@ -961,19 +968,19 @@
|
||||
|
||||
// Generate FCOMI with s1 and s2 scratch regs (the VCMP is already done)
|
||||
#define FCOMI(s1, s2) \
|
||||
IFX(X_OF|X_AF|X_SF|X_PEND) { \
|
||||
IFX(X_OF|X_AF|X_SF) { \
|
||||
MOV32w(s2, 0b100011010101); \
|
||||
BICw_REG(xFlags, xFlags, s2); \
|
||||
IFX(X_CF|X_PF|X_ZF|X_PEND) { \
|
||||
IFX(X_CF|X_PF|X_ZF) { \
|
||||
MOV32w(s2, 0b01000101); \
|
||||
} \
|
||||
} else { \
|
||||
IFX(X_CF|X_PF|X_ZF|X_PEND) { \
|
||||
IFX(X_CF|X_PF|X_ZF) { \
|
||||
MOV32w(s2, 0b01000101); \
|
||||
BICw_REG(xFlags, xFlags, s2); \
|
||||
} \
|
||||
} \
|
||||
IFX(X_CF|X_PF|X_ZF|X_PEND) { \
|
||||
IFX(X_CF|X_PF|X_ZF) { \
|
||||
CSETw(s1, cMI); /* 1 if less than, 0 else */ \
|
||||
/*s2 already set */ /* unordered */ \
|
||||
CSELw(s1, s2, s1, cVS); \
|
||||
@@ -1118,13 +1125,14 @@
|
||||
x87_do_pop(dyn, ninst, scratch)
|
||||
#endif
|
||||
|
||||
#define FORCE_DFNONE() STRw_U12(wZR, xEmu, offsetof(x64emu_t, df))
|
||||
|
||||
#define SET_DFNONE() \
|
||||
do { \
|
||||
if (!dyn->f.dfnone) { \
|
||||
STRw_U12(wZR, xEmu, offsetof(x64emu_t, df)); \
|
||||
FORCE_DFNONE(); \
|
||||
} \
|
||||
if(!dyn->insts[ninst].x64.may_set) { \
|
||||
dyn->f.dfnone_here = 1; \
|
||||
dyn->f.dfnone = 1; \
|
||||
} \
|
||||
} while(0)
|
||||
@@ -1134,7 +1142,8 @@
|
||||
MOVZw(S, (N)); \
|
||||
STRw_U12(S, xEmu, offsetof(x64emu_t, df)); \
|
||||
if (dyn->f.pending == SF_PENDING && dyn->insts[ninst].x64.need_after && !(dyn->insts[ninst].x64.need_after & X_PEND)) { \
|
||||
CALL_I(UpdateFlags); \
|
||||
TABLE64C(x6, const_updateflags_arm64); \
|
||||
BLR(x6); \
|
||||
dyn->f.pending = SF_SET; \
|
||||
SET_NODF(); \
|
||||
} \
|
||||
@@ -1145,7 +1154,7 @@
|
||||
#ifndef SET_NODF
|
||||
#define SET_NODF() dyn->f.dfnone = 0
|
||||
#endif
|
||||
#define SET_DFOK() dyn->f.dfnone = 1; dyn->f.dfnone_here=1
|
||||
#define SET_DFOK() dyn->f.dfnone = 1
|
||||
|
||||
#ifndef READFLAGS
|
||||
#define READFLAGS(A) \
|
||||
@@ -1156,7 +1165,8 @@
|
||||
j64 = (GETMARKF)-(dyn->native_size); \
|
||||
CBZw(x3, j64); \
|
||||
} \
|
||||
CALL_I(UpdateFlags); \
|
||||
TABLE64C(x6, const_updateflags_arm64); \
|
||||
BLR(x6); \
|
||||
MARKF; \
|
||||
dyn->f.pending = SF_SET; \
|
||||
SET_DFOK(); \
|
||||
@@ -1195,9 +1205,12 @@
|
||||
#define UFLAG_OP12(A1, A2) if(dyn->insts[ninst].x64.gen_flags) {STRxw_U12(A1, xEmu, offsetof(x64emu_t, op1));STRxw_U12(A2, xEmu, offsetof(x64emu_t, op2));}
|
||||
#define UFLAG_RES(A) if(dyn->insts[ninst].x64.gen_flags) {STRxw_U12(A, xEmu, offsetof(x64emu_t, res));}
|
||||
#define UFLAG_DF(r, A) if(dyn->insts[ninst].x64.gen_flags) {SET_DF(r, A);}
|
||||
#ifndef UFLAG_IF
|
||||
#define UFLAG_IF if(dyn->insts[ninst].x64.gen_flags)
|
||||
#define UFLAG_IF_DF if(dyn->insts[ninst].x64.gen_flags || (dyn->insts[ninst].f_entry.dfnone && dyn->insts[ninst].f_entry.dfnone_here))
|
||||
#endif
|
||||
#ifndef UFLAG_IF2
|
||||
#define UFLAG_IF2(A) if(dyn->insts[ninst].x64.gen_flags A)
|
||||
#endif
|
||||
#ifndef DEFAULT
|
||||
#define DEFAULT *ok = -1; BARRIER(2)
|
||||
#endif
|
||||
@@ -1207,9 +1220,15 @@
|
||||
#ifndef TABLE64
|
||||
#define TABLE64(A, V)
|
||||
#endif
|
||||
#ifndef TABLE64_
|
||||
#define TABLE64_(A, V)
|
||||
#endif
|
||||
#ifndef FTABLE64
|
||||
#define FTABLE64(A, V)
|
||||
#endif
|
||||
#ifndef TABLE64C
|
||||
#define TABLE64C(A, V)
|
||||
#endif
|
||||
|
||||
#define ARCH_INIT() \
|
||||
SMSTART(); \
|
||||
@@ -1222,23 +1241,40 @@
|
||||
#define GETIP_(A) MOV64x(xRIP, A)
|
||||
#else
|
||||
// put value in the Table64 even if not using it for now to avoid difference between Step2 and Step3. Needs to be optimized later...
|
||||
#define GETIP(A) \
|
||||
if(dyn->last_ip && ((A)-dyn->last_ip)<0x1000) { \
|
||||
uint64_t _delta_ip = (A)-dyn->last_ip; \
|
||||
dyn->last_ip += _delta_ip; \
|
||||
if(_delta_ip) { \
|
||||
ADDx_U12(xRIP, xRIP, _delta_ip); \
|
||||
} \
|
||||
} else { \
|
||||
dyn->last_ip = (A); \
|
||||
MOV64x(xRIP, dyn->last_ip); \
|
||||
#define GETIP(A) \
|
||||
if(dyn->last_ip && ((A)-dyn->last_ip)<0x1000) { \
|
||||
uint64_t _delta_ip = (A)-dyn->last_ip; \
|
||||
dyn->last_ip += _delta_ip; \
|
||||
if(_delta_ip) { \
|
||||
ADDx_U12(xRIP, xRIP, _delta_ip); \
|
||||
} \
|
||||
} else if(dyn->last_ip && (dyn->last_ip-(A))<0x1000) { \
|
||||
uint64_t _delta_ip = dyn->last_ip-(A); \
|
||||
dyn->last_ip -= _delta_ip; \
|
||||
if(_delta_ip) { \
|
||||
SUBx_U12(xRIP, xRIP, _delta_ip); \
|
||||
} \
|
||||
} else { \
|
||||
dyn->last_ip = (A); \
|
||||
if(dyn->need_reloc) { \
|
||||
TABLE64(xRIP, dyn->last_ip); \
|
||||
} else { \
|
||||
MOV64x(xRIP, dyn->last_ip); \
|
||||
} \
|
||||
}
|
||||
#define GETIP_(A) \
|
||||
if(dyn->last_ip && ((A)-dyn->last_ip)<0x1000) { \
|
||||
uint64_t _delta_ip = (A)-dyn->last_ip; \
|
||||
if(_delta_ip) {ADDx_U12(xRIP, xRIP, _delta_ip);}\
|
||||
} else { \
|
||||
MOV64x(xRIP, (A)); \
|
||||
#define GETIP_(A) \
|
||||
if(dyn->last_ip && ((A)-dyn->last_ip)<0x1000) { \
|
||||
uint64_t _delta_ip = (A)-dyn->last_ip; \
|
||||
if(_delta_ip) {ADDx_U12(xRIP, xRIP, _delta_ip);} \
|
||||
} else if(dyn->last_ip && (dyn->last_ip-(A))<0x1000) { \
|
||||
uint64_t _delta_ip = dyn->last_ip-(A); \
|
||||
if(_delta_ip) {SUBx_U12(xRIP, xRIP, _delta_ip);} \
|
||||
} else { \
|
||||
if(dyn->need_reloc) { \
|
||||
TABLE64(xRIP, (A)); \
|
||||
} else { \
|
||||
MOV64x(xRIP, (A)); \
|
||||
} \
|
||||
}
|
||||
#endif
|
||||
#define CLEARIP() dyn->last_ip=0
|
||||
@@ -1255,9 +1291,6 @@
|
||||
|
||||
#define MODREG ((nextop&0xC0)==0xC0)
|
||||
|
||||
void arm64_epilog(void);
|
||||
void* arm64_next(x64emu_t* emu, uintptr_t addr);
|
||||
|
||||
#ifndef STEPNAME
|
||||
#define STEPNAME3(N,M) N##M
|
||||
#define STEPNAME2(N,M) STEPNAME3(N,M)
|
||||
@@ -1266,6 +1299,8 @@ void* arm64_next(x64emu_t* emu, uintptr_t addr);
|
||||
|
||||
#define native_pass STEPNAME(native_pass)
|
||||
|
||||
#define updateflags_pass STEPNAME(updateflags_pass)
|
||||
|
||||
#define dynarec64_00 STEPNAME(dynarec64_00)
|
||||
#define dynarec64_0F STEPNAME(dynarec64_0F)
|
||||
#define dynarec64_64 STEPNAME(dynarec64_64)
|
||||
@@ -1274,6 +1309,7 @@ void* arm64_next(x64emu_t* emu, uintptr_t addr);
|
||||
#define dynarec64_67 STEPNAME(dynarec64_67)
|
||||
#define dynarec64_67_32 STEPNAME(dynarec64_67_32)
|
||||
#define dynarec64_67_AVX STEPNAME(dynarec64_67_AVX)
|
||||
#define dynarec64_6764 STEPNAME(dynarec64_6764)
|
||||
#define dynarec64_6764_32 STEPNAME(dynarec64_6764_32)
|
||||
#define dynarec64_D8 STEPNAME(dynarec64_D8)
|
||||
#define dynarec64_D9 STEPNAME(dynarec64_D9)
|
||||
@@ -1482,8 +1518,8 @@ void jump_to_next(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst, int is32
|
||||
void ret_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int ninst, rex_t rex);
|
||||
void retn_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int ninst, rex_t rex, int n);
|
||||
void iret_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int ninst, int is32bits, int is64bits);
|
||||
void call_c(dynarec_arm_t* dyn, int ninst, void* fnc, int reg, int ret, int saveflags, int save_reg);
|
||||
void call_i(dynarec_arm_t* dyn, int ninst, void* fnc);
|
||||
void call_c(dynarec_arm_t* dyn, int ninst, arm64_consts_t fnc, int reg, int ret, int saveflags, int save_reg);
|
||||
void call_i(dynarec_arm_t* dyn, int ninst, arm64_consts_t fnc);
|
||||
void call_n(dynarec_arm_t* dyn, int ninst, void* fnc, int w);
|
||||
void grab_segdata(dynarec_arm_t* dyn, uintptr_t addr, int ninst, int reg, int segment, int modreg);
|
||||
void emit_cmp8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5);
|
||||
@@ -1628,7 +1664,7 @@ int sse_setround(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
// purge ymm_zero mask according to purge_ymm
|
||||
void avx_purge_ymm(dynarec_arm_t* dyn, int ninst, uint16_t mask, int s1);
|
||||
|
||||
void CacheTransform(dynarec_arm_t* dyn, int ninst, int cacheupd, int s1, int s2, int s3);
|
||||
void CacheTransform(dynarec_arm_t* dyn, int ninst, int cacheupd);
|
||||
|
||||
void arm64_move32(dynarec_arm_t* dyn, int ninst, int reg, uint32_t val);
|
||||
void arm64_move64(dynarec_arm_t* dyn, int ninst, int reg, uint64_t val);
|
||||
@@ -1722,6 +1758,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec64_67_32(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec64_67_AVX(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec64_6764(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int seg, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec64_6764_32(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int seg, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog);
|
||||
@@ -1950,7 +1987,7 @@ uintptr_t dynarec64_AVX_F3_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
|
||||
#define COMP_ZFSF(s1, A) \
|
||||
IFX(X_ZF|X_SF) { \
|
||||
if(arm64_flagm) { \
|
||||
if(cpuext.flagm) { \
|
||||
SETF##A(s1); \
|
||||
IFX(X_ZF) { \
|
||||
IFNATIVE(NF_EQ) {} else { \
|
||||
@@ -1979,6 +2016,10 @@ uintptr_t dynarec64_AVX_F3_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
} \
|
||||
}
|
||||
|
||||
#define PURGE_YMM() avx_purge_ymm(dyn, ninst, dyn->insts[ninst+1].purge_ymm, x1)
|
||||
#define PURGE_YMM() \
|
||||
do { \
|
||||
if ((ok > 0) && reset_n == -1 && dyn->insts[ninst + 1].purge_ymm) \
|
||||
avx_purge_ymm(dyn, ninst, dyn->insts[ninst + 1].purge_ymm, x1); \
|
||||
} while (0)
|
||||
|
||||
#endif //__DYNAREC_ARM64_HELPER_H__
|
||||
@@ -58,6 +58,8 @@
|
||||
#define FEMIT(A) dyn->insts[ninst].nat_flags_op = dyn->insts[ninst].x64.set_flags?NAT_FLAG_OP_TOUCH:NAT_FLAG_OP_UNUSABLE
|
||||
#define IFNATIVE(A) if(mark_natflag(dyn, ninst, A, 0))
|
||||
#define IFNATIVEN(A) if(mark_natflag(dyn, ninst, A, 0))
|
||||
#define UFLAG_IF if(dyn->insts[ninst].x64.set_flags)
|
||||
#define UFLAG_IF2(A) if(dyn->insts[ninst].x64.set_flags A)
|
||||
#define IFX(A) if((dyn->insts[ninst].x64.set_flags&(A)))
|
||||
#define IFX2(A, B) if((dyn->insts[ninst].x64.set_flags&(A)) B)
|
||||
#define IFX_PENDOR0 if((dyn->insts[ninst].x64.set_flags&(X_PEND) || !dyn->insts[ninst].x64.set_flags))
|
||||
|
||||
@@ -15,7 +15,19 @@
|
||||
}
|
||||
#define INST_EPILOG dyn->insts[ninst].epilog = dyn->native_size;
|
||||
#define INST_NAME(name)
|
||||
#define TABLE64(A, V) {Table64(dyn, (V), 2); EMIT(0);}
|
||||
#define FTABLE64(A, V) {mmx87_regs_t v = {.d = V}; Table64(dyn, v.q, 2); EMIT(0);}
|
||||
#define TABLE64(A, V) do { \
|
||||
if(dyn->need_reloc) \
|
||||
AddRelocTable64Addr(dyn, ninst, (V), 2); \
|
||||
Table64(dyn, (V), 2); EMIT(0); \
|
||||
} while(0)
|
||||
#define TABLE64_(A, V) do { \
|
||||
Table64(dyn, (V), 2); EMIT(0); \
|
||||
} while(0)
|
||||
#define TABLE64C(A, V) do { \
|
||||
if(dyn->need_reloc) \
|
||||
AddRelocTable64Const(dyn, ninst, (V), 2); \
|
||||
Table64(dyn, getConst(V), 2); EMIT(0); \
|
||||
} while(0)
|
||||
#define FTABLE64(A, V) do {mmx87_regs_t v = {.d = V}; Table64(dyn, v.q, 2); EMIT(0);} while(0)
|
||||
#define CALLRET_RET() do {dyn->callrets[dyn->callret_size].type = 0; dyn->callrets[dyn->callret_size++].offs = dyn->native_size; EMIT(ARCH_NOP); } while(0)
|
||||
#define CALLRET_LOOP() do {dyn->callrets[dyn->callret_size].type = 1; dyn->callrets[dyn->callret_size++].offs = dyn->native_size; EMIT(ARCH_NOP); } while(0)
|
||||
@@ -24,7 +24,22 @@
|
||||
}
|
||||
#define INST_EPILOG
|
||||
#define INST_NAME(name) inst_name_pass3(dyn, ninst, name, rex)
|
||||
#define TABLE64(A, V) {int val64offset = Table64(dyn, (V), 3); MESSAGE(LOG_DUMP, " Table64: 0x%lx\n", (V)); LDRx_literal(A, val64offset);}
|
||||
#define FTABLE64(A, V) {mmx87_regs_t v = {.d = V}; int val64offset = Table64(dyn, v.q, 3); MESSAGE(LOG_DUMP, " FTable64: %g\n", v.d); VLDR64_literal(A, val64offset);}
|
||||
#define TABLE64(A, V) do { \
|
||||
if(dyn->need_reloc) \
|
||||
AddRelocTable64Addr(dyn, ninst, (V), 3); \
|
||||
int val64offset = Table64(dyn, (V), 3); \
|
||||
MESSAGE(LOG_DUMP, " Table64: 0x%lx\n", (V)); LDRx_literal(A, val64offset); \
|
||||
} while(0)
|
||||
#define TABLE64_(A, V) { \
|
||||
int val64offset = Table64(dyn, (V), 3); \
|
||||
MESSAGE(LOG_DUMP, " Table64: 0x%lx\n", (V)); LDRx_literal(A, val64offset); \
|
||||
}
|
||||
#define TABLE64C(A, V) do { \
|
||||
if(dyn->need_reloc) \
|
||||
AddRelocTable64Const(dyn, ninst, (V), 3); \
|
||||
int val64offset = Table64(dyn, getConst(V), 3); \
|
||||
MESSAGE(LOG_DUMP, " Table64C: 0x%lx\n", (V)); LDRx_literal(A, val64offset);\
|
||||
} while(0)
|
||||
#define FTABLE64(A, V) do {mmx87_regs_t v = {.d = V}; int val64offset = Table64(dyn, v.q, 3); MESSAGE(LOG_DUMP, " FTable64: %g\n", v.d); VLDR64_literal(A, val64offset);} while(0)
|
||||
#define CALLRET_RET() do {dyn->callrets[dyn->callret_size].type = 0; dyn->callrets[dyn->callret_size++].offs = dyn->native_size; EMIT(ARCH_NOP); } while(0)
|
||||
#define CALLRET_LOOP() do {dyn->callrets[dyn->callret_size].type = 1; dyn->callrets[dyn->callret_size++].offs = dyn->native_size; EMIT(ARCH_NOP); } while(0)
|
||||
@@ -6,6 +6,7 @@
|
||||
typedef struct x64emu_s x64emu_t;
|
||||
typedef struct dynablock_s dynablock_t;
|
||||
typedef struct instsize_s instsize_t;
|
||||
typedef struct box64env_s box64env_t;
|
||||
|
||||
#define BARRIER_MAYBE 8
|
||||
|
||||
@@ -72,7 +73,6 @@ typedef struct neoncache_s {
|
||||
int8_t x87stack; // cache stack counter
|
||||
int8_t mmxcount; // number of mmx register used (not both mmx and x87 at the same time)
|
||||
int8_t fpu_scratch; // scratch counter
|
||||
int8_t fpu_reg; // x87/sse/mmx reg counter
|
||||
uint16_t xmm_write; // 1bit of xmmXX removed write
|
||||
uint16_t xmm_removed; // 1bit if xmmXX was removed
|
||||
uint16_t xmm_used; // mask of the xmm regs used in this opcode
|
||||
@@ -87,7 +87,6 @@ typedef struct neoncache_s {
|
||||
typedef struct flagcache_s {
|
||||
int pending; // is there a pending flags here, or to check?
|
||||
uint8_t dfnone; // if deferred flags is already set to df_none
|
||||
uint8_t dfnone_here;// defered flags is cleared in this opcode
|
||||
} flagcache_t;
|
||||
|
||||
typedef struct instruction_arm64_s {
|
||||
@@ -116,7 +115,6 @@ typedef struct instruction_arm64_s {
|
||||
uint8_t will_read:1; // [strongmem] will read from memory
|
||||
uint8_t last_write:1; // [strongmem] the last write in a SEQ
|
||||
uint8_t lock:1; // [strongmem] lock semantic
|
||||
uint8_t lock_prefixed:1; // [strongmem] the opcode is lock prefixed
|
||||
uint8_t wfe:1; // opcode uses sevl + wfe
|
||||
uint8_t set_nat_flags; // 0 or combinaison of native flags define
|
||||
uint8_t use_nat_flags; // 0 or combinaison of native flags define
|
||||
@@ -132,6 +130,10 @@ typedef struct instruction_arm64_s {
|
||||
unsigned df_notneeded:1;
|
||||
unsigned unaligned:1; // this opcode can be re-generated for unaligned special case
|
||||
unsigned x87precision:1; // this opcode can handle x87pc
|
||||
unsigned mmx_used:1; // no fine tracking, just a global "any reg used"
|
||||
unsigned x87_used:1; // no fine tracking, just a global "any reg used"
|
||||
unsigned fpu_used:1; // any xmm/ymm/x87/mmx reg used
|
||||
unsigned fpupurge:1; // this opcode will purge all fpu regs
|
||||
flagcache_t f_exit; // flags status at end of instruction
|
||||
neoncache_t n; // neoncache at end of instruction (but before poping)
|
||||
flagcache_t f_entry; // flags status before the instruction begin
|
||||
@@ -142,6 +144,7 @@ typedef struct dynarec_arm_s {
|
||||
int32_t size;
|
||||
int32_t cap;
|
||||
uintptr_t start; // start of the block
|
||||
uintptr_t end; // maximum end of the block (only used in pass0)
|
||||
uint32_t isize; // size in bytes of x64 instructions included
|
||||
void* block; // memory pointer where next instruction is emitted
|
||||
uintptr_t native_start; // start of the arm code
|
||||
@@ -179,6 +182,10 @@ typedef struct dynarec_arm_s {
|
||||
void* gdbjit_block;
|
||||
uint32_t need_x87check; // needs x87 precision control check if non-null, or 0 if not
|
||||
uint32_t need_dump; // need to dump the block
|
||||
int need_reloc; // does the dynablock need relocations
|
||||
int reloc_size;
|
||||
uint32_t* relocs;
|
||||
box64env_t* env;
|
||||
} dynarec_arm_t;
|
||||
|
||||
void add_next(dynarec_arm_t *dyn, uintptr_t addr);
|
||||
@@ -189,18 +196,19 @@ int get_first_jump_addr(dynarec_arm_t *dyn, uintptr_t next);
|
||||
int is_nops(dynarec_arm_t *dyn, uintptr_t addr, int n);
|
||||
int is_instructions(dynarec_arm_t *dyn, uintptr_t addr, int n);
|
||||
|
||||
int isTable64(dynarec_arm_t *dyn, uint64_t val); // return 1 if val already in Table64
|
||||
int Table64(dynarec_arm_t *dyn, uint64_t val, int pass); // add a value to table64 (if needed) and gives back the imm19 to use in LDR_literal
|
||||
|
||||
void CreateJmpNext(void* addr, void* next);
|
||||
|
||||
#define GO_TRACE(A, B, s0) \
|
||||
GETIP(addr); \
|
||||
MOVx_REG(x1, xRIP); \
|
||||
MRS_nzcv(s0); \
|
||||
STORE_XEMU_CALL(xRIP); \
|
||||
MOV32w(x2, B); \
|
||||
CALL_(A, -1, s0); \
|
||||
MSR_nzcv(s0); \
|
||||
#define GO_TRACE(A, B, s0) \
|
||||
GETIP(addr); \
|
||||
MOVx_REG(x1, xRIP); \
|
||||
MRS_nzcv(s0); \
|
||||
STORE_XEMU_CALL(xRIP); \
|
||||
MOV32w(x2, B); \
|
||||
CALL_(const_##A, -1, s0); \
|
||||
MSR_nzcv(s0); \
|
||||
LOAD_XEMU_CALL(xRIP)
|
||||
|
||||
#endif //__DYNAREC_ARM_PRIVATE_H_
|
||||
@@ -0,0 +1,135 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "os.h"
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "custommem.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynablock.h"
|
||||
#include "../dynablock_private.h"
|
||||
|
||||
#include "dynarec_native.h"
|
||||
#include "../dynarec_arch.h"
|
||||
|
||||
void updateflags_pass0(dynarec_arm_t* dyn, uint64_t jmp_df[]);
|
||||
void updateflags_pass1(dynarec_arm_t* dyn, uint64_t jmp_df[]);
|
||||
void updateflags_pass2(dynarec_arm_t* dyn, uint64_t jmp_df[]);
|
||||
void updateflags_pass3(dynarec_arm_t* dyn, uint64_t jmp_df[]);
|
||||
|
||||
static dynablock_t* updaflags_arm64 = NULL;
|
||||
|
||||
static uint8_t dummy_code[] = {0x90, 0xc3}; // some dummy code so update_flags dynablock point to something
|
||||
|
||||
void* create_updateflags()
|
||||
{
|
||||
if(updaflags_arm64)
|
||||
return updaflags_arm64->block;
|
||||
uint64_t jmp_df[d_unknown+1] = {0};
|
||||
dynarec_arm_t helper = {0};
|
||||
instruction_arm64_t insts[1] = {0};
|
||||
helper.insts = insts;
|
||||
helper.need_dump = BOX64ENV(dynarec_dump);
|
||||
helper.cap = 1;
|
||||
helper.f.dfnone = 1;
|
||||
helper.f.pending = SF_NODF;
|
||||
helper.insts[0].x64.gen_flags = X_ALL;
|
||||
// pass 0
|
||||
updateflags_pass0(&helper, jmp_df);
|
||||
// check if all flags are handled
|
||||
int ok = 1;
|
||||
for(int i=d_none; i<d_unknown; ++i)
|
||||
if(!jmp_df[i]) {
|
||||
printf_log(LOG_NONE, "Error, UpdateFlags case %d is not handled, will crash later\n", i);
|
||||
ok = 0;
|
||||
}
|
||||
// pass 1
|
||||
updateflags_pass1(&helper, jmp_df);
|
||||
// pass 2
|
||||
helper.native_size = 0;
|
||||
updateflags_pass2(&helper, jmp_df);
|
||||
// alloc memory for pass3
|
||||
size_t native_size = (helper.native_size+7)&~7; // round the size...
|
||||
size_t sz = sizeof(void*) + native_size + helper.table64size*sizeof(uint64_t) + 4*sizeof(void*) + 0 + 0 + 0 + sizeof(dynablock_t) + 0;
|
||||
// dynablock_t* block (arm insts) table64 jmpnext code instsize arch callrets dynablock relocs
|
||||
void* actual_p = (void*)AllocDynarecMap((uintptr_t)&dummy_code, sz, 1); // arbitrary address
|
||||
void* p = (void*)(((uintptr_t)actual_p) + sizeof(void*));
|
||||
void* tablestart = p + native_size;
|
||||
void* next = tablestart + helper.table64size*sizeof(uint64_t);
|
||||
void* instsize = next + 4*sizeof(void*);
|
||||
void* arch = instsize + 0;
|
||||
void* callrets = arch + 0;
|
||||
if(actual_p==NULL) {
|
||||
dynarec_log(LOG_INFO, "AllocDynarecMap(%zu) failed, canceling UpdateBlock\n", sz);
|
||||
return NULL;
|
||||
}
|
||||
helper.block = p;
|
||||
dynablock_t* block = (dynablock_t*)(callrets+0);
|
||||
memset(block, 0, sizeof(dynablock_t));
|
||||
void* relocs = helper.need_reloc?(block+1):NULL;
|
||||
// fill the block
|
||||
block->x64_addr = &dummy_code;
|
||||
block->isize = 0;
|
||||
block->actual_block = actual_p;
|
||||
helper.relocs = relocs;
|
||||
block->relocs = relocs;
|
||||
block->table64size = helper.table64size;
|
||||
helper.native_start = (uintptr_t)p;
|
||||
helper.tablestart = (uintptr_t)tablestart;
|
||||
helper.jmp_next = (uintptr_t)next+sizeof(void*);
|
||||
helper.instsize = (instsize_t*)instsize;
|
||||
*(dynablock_t**)actual_p = block;
|
||||
helper.table64cap = helper.table64size;
|
||||
helper.table64 = (uint64_t*)helper.tablestart;
|
||||
helper.callrets = (callret_t*)callrets;
|
||||
block->table64 = helper.table64;
|
||||
helper.callret_size = 0;
|
||||
// pass 3, emit (log emit native opcode)
|
||||
if(helper.need_dump) {
|
||||
dynarec_log(LOG_NONE, "%s%04d|Emitting %zu bytes for UpdateFlags", (helper.need_dump>1)?"\e[01;36m":"", GetTID(), helper.native_size);
|
||||
PrintFunctionAddr(helper.start, " => ");
|
||||
dynarec_log_prefix(0, LOG_NONE, "%s\n", (helper.need_dump>1)?"\e[m":"");
|
||||
}
|
||||
helper.native_size = 0;
|
||||
updateflags_pass3(&helper, jmp_df);
|
||||
helper.jmp_sz = helper.jmp_cap = 0;
|
||||
helper.jmps = NULL;
|
||||
// keep size of instructions for signal handling
|
||||
block->instsize = instsize;
|
||||
helper.table64 = NULL;
|
||||
helper.instsize = NULL;
|
||||
helper.predecessor = NULL;
|
||||
block->size = sz;
|
||||
block->isize = helper.size;
|
||||
block->block = p;
|
||||
block->jmpnext = next+sizeof(void*);
|
||||
block->always_test = helper.always_test;
|
||||
block->dirty = block->always_test;
|
||||
block->is32bits = 0;
|
||||
block->relocsize = helper.reloc_size*sizeof(uint32_t);
|
||||
block->arch = NULL;
|
||||
block->arch_size = 0;
|
||||
block->callret_size = helper.callret_size;
|
||||
block->callrets = helper.callrets;
|
||||
block->native_size = native_size;
|
||||
*(dynablock_t**)next = block;
|
||||
*(void**)(next+3*sizeof(void*)) = NULL;
|
||||
CreateJmpNext(block->jmpnext, next+3*sizeof(void*));
|
||||
ClearCache(block->jmpnext, 4*sizeof(void*));
|
||||
block->x64_size = 0;
|
||||
// all done...
|
||||
ClearCache(actual_p+sizeof(void*), native_size); // need to clear the cache before execution...
|
||||
|
||||
updaflags_arm64 = block;
|
||||
return block->block;
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
+117
-56
@@ -1,6 +1,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "os.h"
|
||||
#include "debug.h"
|
||||
@@ -54,14 +55,14 @@ dynablock_t* InvalidDynablock(dynablock_t* db, int need_lock)
|
||||
if(db->callret_size) {
|
||||
// mark all callrets to UDF
|
||||
for(int i=0; i<db->callret_size; ++i)
|
||||
*(uint32_t*)(db->block+db->callrets[i].offs) = ARCH_NOP;
|
||||
*(uint32_t*)(db->block+db->callrets[i].offs) = ARCH_UDF;
|
||||
ClearCache(db->block, db->size);
|
||||
}
|
||||
#endif
|
||||
if(db_size && my_context) {
|
||||
if(db_size && my_context && !BOX64ENV(dynarec_dirty)) {
|
||||
uint32_t n = rb_dec(my_context->db_sizes, db_size, db_size+1);
|
||||
if(!n && (db_size >= my_context->max_db_size)) {
|
||||
my_context->max_db_size = rb_get_righter(my_context->db_sizes);
|
||||
my_context->max_db_size = rb_get_rightmost(my_context->db_sizes);
|
||||
dynarec_log(LOG_INFO, "BOX64 Dynarec: lower max_db=%d\n", my_context->max_db_size);
|
||||
}
|
||||
}
|
||||
@@ -71,29 +72,67 @@ dynablock_t* InvalidDynablock(dynablock_t* db, int need_lock)
|
||||
return db;
|
||||
}
|
||||
|
||||
dynablock_t* SwitchDynablock(dynablock_t* db, int need_lock)
|
||||
{
|
||||
if(db) {
|
||||
if(!db->done || !db->previous || !db->previous->gone)
|
||||
return NULL; // not a correct block!
|
||||
dynarec_log(LOG_DEBUG, "SwitchDynablock(%p/%p), db->block=%p->%p x64=%p:%p->%p hash->%x->%x\n", db, db->previous, db->block, db->previous->block, db->x64_addr, db->x64_addr+db->x64_size-1, db->previous->x64_addr+db->previous->x64_size-1, db->hash, db->previous->hash);
|
||||
// remove jumptable without waiting
|
||||
dynablock_t* db_new = db->previous;
|
||||
db->previous = NULL;
|
||||
if(need_lock)
|
||||
mutex_lock(&my_context->mutex_dyndump);
|
||||
InvalidDynablock(db, 0);
|
||||
db_new->done = 1;
|
||||
db_new->gone = 0;
|
||||
db_new->previous = db;
|
||||
#ifdef ARCH_NOP
|
||||
if(db_new->callret_size) {
|
||||
// mark all callrets to UDF
|
||||
for(int i=0; i<db_new->callret_size; ++i)
|
||||
*(uint32_t*)(db_new->block+db_new->callrets[i].offs) = ARCH_NOP;
|
||||
ClearCache(db_new->block, db_new->size);
|
||||
}
|
||||
#endif
|
||||
if(need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
return db_new;
|
||||
}
|
||||
return db;
|
||||
}
|
||||
|
||||
void FreeInvalidDynablock(dynablock_t* db, int need_lock)
|
||||
{
|
||||
if(db) {
|
||||
if(!db->gone)
|
||||
return; // already in the process of deletion!
|
||||
dynarec_log(LOG_DEBUG, "FreeInvalidDynablock(%p), db->block=%p x64=%p:%p already gone=%d\n", db, db->block, db->x64_addr, db->x64_addr+db->x64_size-1, db->gone);
|
||||
uintptr_t db_size = db->x64_size;
|
||||
if(need_lock)
|
||||
mutex_lock(&my_context->mutex_dyndump);
|
||||
FreeDynarecMap((uintptr_t)db->actual_block);
|
||||
customFree(db);
|
||||
if(db_size && my_context && BOX64ENV(dynarec_dirty)) {
|
||||
uint32_t n = rb_dec(my_context->db_sizes, db_size, db_size+1);
|
||||
if(!n && (db_size >= my_context->max_db_size)) {
|
||||
my_context->max_db_size = rb_get_rightmost(my_context->db_sizes);
|
||||
dynarec_log(LOG_INFO, "BOX64 Dynarec: lower max_db=%d\n", my_context->max_db_size);
|
||||
}
|
||||
}
|
||||
FreeDynarecMap((uintptr_t)db->actual_block); // will also free db
|
||||
if(need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
}
|
||||
}
|
||||
|
||||
void FreeDynablock(dynablock_t* db, int need_lock)
|
||||
void FreeDynablock(dynablock_t* db, int need_lock, int need_remove)
|
||||
{
|
||||
if(db) {
|
||||
if(db->gone)
|
||||
return; // already in the process of deletion!
|
||||
dynarec_log(LOG_DEBUG, "FreeDynablock(%p), db->block=%p x64=%p:%p already gone=%d\n", db, db->block, db->x64_addr, db->x64_addr+db->x64_size-1, db->gone);
|
||||
// remove jumptable without waiting
|
||||
setJumpTableDefault64(db->x64_addr);
|
||||
if(need_remove)
|
||||
setJumpTableDefault64(db->x64_addr);
|
||||
if(need_lock)
|
||||
mutex_lock(&my_context->mutex_dyndump);
|
||||
dynarec_log(LOG_DEBUG, " -- FreeDyrecMap(%p, %d)\n", db->actual_block, db->size);
|
||||
@@ -103,14 +142,13 @@ void FreeDynablock(dynablock_t* db, int need_lock)
|
||||
if(db_size && my_context) {
|
||||
uint32_t n = rb_dec(my_context->db_sizes, db_size, db_size+1);
|
||||
if(!n && (db_size >= my_context->max_db_size)) {
|
||||
my_context->max_db_size = rb_get_righter(my_context->db_sizes);
|
||||
my_context->max_db_size = rb_get_rightmost(my_context->db_sizes);
|
||||
dynarec_log(LOG_INFO, "BOX64 Dynarec: lower max_db=%d\n", my_context->max_db_size);
|
||||
}
|
||||
}
|
||||
if(db->previous)
|
||||
FreeInvalidDynablock(db->previous, 0);
|
||||
FreeDynarecMap((uintptr_t)db->actual_block);
|
||||
customFree(db);
|
||||
FreeDynarecMap((uintptr_t)db->actual_block); // will also free db
|
||||
if(need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
}
|
||||
@@ -170,21 +208,12 @@ int FreeRangeDynablock(dynablock_t* db, uintptr_t addr, uintptr_t size)
|
||||
|
||||
int need_lock = my_context?1:0;
|
||||
if(IntervalIntersects((uintptr_t)db->x64_addr, (uintptr_t)db->x64_addr+db->x64_size-1, addr, addr+size+1)) {
|
||||
FreeDynablock(db, need_lock);
|
||||
FreeDynablock(db, need_lock, 1);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
dynablock_t *AddNewDynablock(uintptr_t addr)
|
||||
{
|
||||
dynablock_t* block;
|
||||
// create and add new block
|
||||
dynarec_log(LOG_VERBOSE, "Ask for DynaRec Block creation @%p\n", (void*)addr);
|
||||
block = (dynablock_t*)customCalloc(1, sizeof(dynablock_t));
|
||||
return block;
|
||||
}
|
||||
|
||||
NEW_JUMPBUFF(dynarec_jmpbuf);
|
||||
|
||||
void cancelFillBlock()
|
||||
@@ -196,7 +225,7 @@ void cancelFillBlock()
|
||||
return NULL if block is not found / cannot be created.
|
||||
Don't create if create==0
|
||||
*/
|
||||
static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t filladdr, int create, int need_lock, int is32bits)
|
||||
static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t filladdr, int create, int need_lock, int is32bits, int is_new)
|
||||
{
|
||||
if (hasAlternate((void*)filladdr))
|
||||
return NULL;
|
||||
@@ -208,18 +237,38 @@ static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t
|
||||
return block;
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
static int critical_filled = 0;
|
||||
static sigset_t critical_prot = {0};
|
||||
sigset_t old_sig = {0};
|
||||
if(!critical_filled) {
|
||||
critical_filled = 1;
|
||||
sigfillset(&critical_prot);
|
||||
sigdelset(&critical_prot, SIGSEGV);
|
||||
sigdelset(&critical_prot, SIGILL);
|
||||
sigdelset(&critical_prot, SIGBUS);
|
||||
sigdelset(&critical_prot, SIGINT);
|
||||
sigdelset(&critical_prot, SIGABRT);
|
||||
sigdelset(&critical_prot, SIGFPE);
|
||||
}
|
||||
#endif
|
||||
|
||||
pthread_sigmask(SIG_BLOCK, &critical_prot, &old_sig);
|
||||
if(need_lock) {
|
||||
if(BOX64ENV(dynarec_wait)) {
|
||||
mutex_lock(&my_context->mutex_dyndump);
|
||||
} else {
|
||||
if(mutex_trylock(&my_context->mutex_dyndump)) // FillBlock not available for now
|
||||
if(mutex_trylock(&my_context->mutex_dyndump)) { // FillBlock not available for now
|
||||
pthread_sigmask(SIG_SETMASK, &old_sig, NULL);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
block = getDB(addr); // just in case
|
||||
if(block) {
|
||||
if(block && getNeedTest(addr) && (getProtection_fast(addr)&req_prot)!=req_prot)
|
||||
block = NULL;
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
pthread_sigmask(SIG_SETMASK, &old_sig, NULL);
|
||||
return block;
|
||||
}
|
||||
}
|
||||
@@ -227,34 +276,31 @@ static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t
|
||||
if((getProtection_fast(addr)&req_prot)!=req_prot) {// cannot be run, get out of the Dynarec
|
||||
if(need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
pthread_sigmask(SIG_SETMASK, &old_sig, NULL);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
block = AddNewDynablock(addr);
|
||||
|
||||
// fill the block
|
||||
block->x64_addr = (void*)addr;
|
||||
if (SigSetJmp(GET_JUMPBUFF(dynarec_jmpbuf), 1)) {
|
||||
printf_log(LOG_INFO, "FillBlock at %p triggered a segfault, canceling\n", (void*)addr);
|
||||
FreeDynablock(block, 0);
|
||||
if(need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
pthread_sigmask(SIG_SETMASK, &old_sig, NULL);
|
||||
return NULL;
|
||||
}
|
||||
void* ret = FillBlock64(block, filladdr, (addr==filladdr)?0:1, is32bits, MAX_INSTS);
|
||||
if(!ret) {
|
||||
block = FillBlock64(filladdr, (addr==filladdr)?0:1, is32bits, MAX_INSTS, is_new);
|
||||
if(!block) {
|
||||
dynarec_log(LOG_DEBUG, "Fillblock of block %p for %p returned an error\n", block, (void*)addr);
|
||||
customFree(block);
|
||||
block = NULL;
|
||||
}
|
||||
// check size
|
||||
if(block) {
|
||||
// fill-in jumptable
|
||||
if(!addJumpTableIfDefault64(block->x64_addr, block->dirty?block->jmpnext:block->block)) {
|
||||
FreeDynablock(block, 0);
|
||||
if(!addJumpTableIfDefault64(block->x64_addr, (block->dirty || block->always_test)?block->jmpnext:block->block)) {
|
||||
FreeDynablock(block, 0, 0);
|
||||
block = getDB(addr);
|
||||
MarkDynablock(block); // just in case...
|
||||
} else {
|
||||
if(block->dirty)
|
||||
block->dirty = 0;
|
||||
if(block->x64_size) {
|
||||
if(block->x64_size>my_context->max_db_size) {
|
||||
my_context->max_db_size = block->x64_size;
|
||||
@@ -267,6 +313,7 @@ static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t
|
||||
}
|
||||
if(need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
pthread_sigmask(SIG_SETMASK, &old_sig, NULL);
|
||||
|
||||
dynarec_log(LOG_DEBUG, "%04d| --- DynaRec Block %p created @%p:%p (%p, 0x%x bytes)\n", GetTID(), block, (void*)addr, (void*)(addr+((block)?block->x64_size:1)-1), (block)?block->block:0, (block)?block->size:0);
|
||||
|
||||
@@ -278,34 +325,50 @@ dynablock_t* DBGetBlock(x64emu_t* emu, uintptr_t addr, int create, int is32bits)
|
||||
int is_inhotpage = isInHotPage(addr);
|
||||
if(is_inhotpage && !BOX64ENV(dynarec_dirty))
|
||||
return NULL;
|
||||
dynablock_t *db = internalDBGetBlock(emu, addr, addr, create, 1, is32bits);
|
||||
dynablock_t *db = internalDBGetBlock(emu, addr, addr, create, 1, is32bits, 1);
|
||||
if(db && db->done && db->block && getNeedTest(addr)) {
|
||||
if (db->always_test) SchedYield(); // just calm down...
|
||||
//if (db->always_test) SchedYield(); // just calm down...
|
||||
uint32_t hash = X31_hash_code(db->x64_addr, db->x64_size);
|
||||
if(is_inhotpage && hash!=db->hash)
|
||||
return NULL; // will be handle when hotpage is over
|
||||
int need_lock = mutex_trylock(&my_context->mutex_dyndump);
|
||||
mutex_lock(&my_context->mutex_dyndump)?1:0;
|
||||
if(hash!=db->hash) {
|
||||
if(is_inhotpage && db->previous) {
|
||||
// check alternate
|
||||
if(db->previous && !db->dirty && X31_hash_code(db->previous->x64_addr, db->previous->x64_size)==db->previous->hash) {
|
||||
db = SwitchDynablock(db, 0);
|
||||
if(!addJumpTableIfDefault64(db->x64_addr, (db->always_test)?db->jmpnext:db->block)) {
|
||||
FreeDynablock(db, 0, 0);
|
||||
db = getDB(addr);
|
||||
MarkDynablock(db); // just in case...
|
||||
}
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
return db;
|
||||
}
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
return NULL; // will be handle when hotpage is over
|
||||
}
|
||||
db->done = 0; // invalidating the block
|
||||
dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X/%X, always_test:%d) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size-1, hash, db->hash, db->always_test,(void*)addr);
|
||||
dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X/%X, always_test:%d, previous=%p/hash=%X) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size-1, hash, db->hash, db->always_test,db->previous, db->previous?db->previous->hash:0,(void*)addr);
|
||||
// Free db, it's now invalid!
|
||||
dynablock_t* old = InvalidDynablock(db, need_lock);
|
||||
dynablock_t* old = InvalidDynablock(db, 0);
|
||||
// start again... (will create a new block)
|
||||
db = internalDBGetBlock(emu, addr, addr, create, need_lock, is32bits);
|
||||
db = internalDBGetBlock(emu, addr, addr, create, 0, is32bits, 0);
|
||||
if(db) {
|
||||
if(db->previous)
|
||||
FreeInvalidDynablock(db->previous, need_lock);
|
||||
FreeInvalidDynablock(db->previous, 0);
|
||||
db->previous = old;
|
||||
} else
|
||||
FreeInvalidDynablock(old, need_lock);
|
||||
FreeInvalidDynablock(old, 0);
|
||||
} else {
|
||||
if(is_inhotpage) {
|
||||
db->always_test = 2;
|
||||
// log?
|
||||
} else {
|
||||
dynarec_log(LOG_DEBUG, "Validating block %p from %p:%p (hash:%X, always_test:%d) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size-1, db->hash, db->always_test, (void*)addr);
|
||||
if(db->always_test)
|
||||
if(db->always_test) {
|
||||
if(db->always_test==2)
|
||||
db->always_test = 0;
|
||||
protectDB((uintptr_t)db->x64_addr, db->x64_size);
|
||||
else {
|
||||
} else {
|
||||
#ifdef ARCH_NOP
|
||||
if(db->callret_size) {
|
||||
// mark all callrets to UDF
|
||||
@@ -318,8 +381,7 @@ dynablock_t* DBGetBlock(x64emu_t* emu, uintptr_t addr, int create, int is32bits)
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
}
|
||||
if(!db || !db->block || !db->done)
|
||||
emu->test.test = 0;
|
||||
@@ -330,24 +392,24 @@ dynablock_t* DBAlternateBlock(x64emu_t* emu, uintptr_t addr, uintptr_t filladdr,
|
||||
{
|
||||
dynarec_log(LOG_DEBUG, "Creating AlternateBlock at %p for %p%s\n", (void*)addr, (void*)filladdr, is32bits?" 32bits":"");
|
||||
int create = 1;
|
||||
dynablock_t *db = internalDBGetBlock(emu, addr, filladdr, create, 1, is32bits);
|
||||
if(db && db->done && db->block && getNeedTest(filladdr)) {
|
||||
dynablock_t *db = internalDBGetBlock(emu, addr, filladdr, create, 1, is32bits, 1);
|
||||
if(db && db->done && db->block && (db->dirty || getNeedTest(filladdr))) {
|
||||
if (db->always_test) SchedYield(); // just calm down...
|
||||
int need_lock = mutex_trylock(&my_context->mutex_dyndump);
|
||||
mutex_lock(&my_context->mutex_dyndump);
|
||||
uint32_t hash = X31_hash_code(db->x64_addr, db->x64_size);
|
||||
if(hash!=db->hash) {
|
||||
db->done = 0; // invalidating the block
|
||||
dynarec_log(LOG_DEBUG, "Invalidating alt block %p from %p:%p (hash:%X/%X) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size, hash, db->hash, (void*)addr);
|
||||
// Free db, it's now invalid!
|
||||
dynablock_t* old = InvalidDynablock(db, need_lock);
|
||||
dynablock_t* old = InvalidDynablock(db, 0);
|
||||
// start again... (will create a new block)
|
||||
db = internalDBGetBlock(emu, addr, filladdr, create, need_lock, is32bits);
|
||||
db = internalDBGetBlock(emu, addr, filladdr, create, 0, is32bits, 0);
|
||||
if(db) {
|
||||
if(db->previous)
|
||||
FreeInvalidDynablock(db->previous, need_lock);
|
||||
FreeInvalidDynablock(db->previous, 0);
|
||||
db->previous = old;
|
||||
} else
|
||||
FreeInvalidDynablock(old, need_lock);
|
||||
FreeInvalidDynablock(old, 0);
|
||||
} else {
|
||||
if(db->always_test)
|
||||
protectDB((uintptr_t)db->x64_addr, db->x64_size);
|
||||
@@ -363,8 +425,7 @@ dynablock_t* DBAlternateBlock(x64emu_t* emu, uintptr_t addr, uintptr_t filladdr,
|
||||
protectDBJumpTable((uintptr_t)db->x64_addr, db->x64_size, db->block, db->jmpnext);
|
||||
}
|
||||
}
|
||||
if(!need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
}
|
||||
if(!db || !db->block || !db->done)
|
||||
emu->test.test = 0;
|
||||
|
||||
@@ -17,12 +17,13 @@ typedef struct dynablock_s {
|
||||
struct dynablock_s* previous; // a previous block that might need to be freed
|
||||
void* x64_addr;
|
||||
uintptr_t x64_size;
|
||||
size_t native_size;
|
||||
int size;
|
||||
uint32_t hash;
|
||||
uint8_t done;
|
||||
uint8_t gone;
|
||||
uint8_t dirty; // if need to be tested as soon as it's created
|
||||
uint8_t always_test:1;
|
||||
uint8_t always_test:2;
|
||||
uint8_t is32bits:1;
|
||||
int callret_size; // size of the array
|
||||
int isize;
|
||||
@@ -31,6 +32,10 @@ typedef struct dynablock_s {
|
||||
void* arch; // arch dependant per inst info (can be NULL)
|
||||
callret_t* callrets; // array of callret return, with NOP / UDF depending if the block is clean or dirty
|
||||
void* jmpnext; // a branch jmpnext code when block is marked
|
||||
size_t table64size;// to check table64
|
||||
void* table64; // to relocate the table64
|
||||
size_t relocsize; // number of relocations (should be an int only)
|
||||
void* relocs; // relocations, when block is loaded
|
||||
#ifdef GDBJIT
|
||||
void* gdbjit_block;
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,243 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "os.h"
|
||||
#include "dynarec_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "dynablock_private.h"
|
||||
#include "dynarec_arch.h"
|
||||
#include "custommem.h"
|
||||
#include "debug.h"
|
||||
|
||||
#define RELOC_TBL64C 1
|
||||
#define RELOC_TBL64ADDR 2
|
||||
#define RELOC_TBL64RETENDBL 3
|
||||
#define RELOC_CANCELBLOCK 4
|
||||
#define RELOC_TBL64TBLJMPH 5
|
||||
#define RELOC_TBL64TBLJMPL 6
|
||||
|
||||
typedef union reloc_s {
|
||||
uint8_t type;
|
||||
struct {
|
||||
uint8_t type;
|
||||
uint8_t C;
|
||||
uint16_t idx;
|
||||
} table64c;
|
||||
struct {
|
||||
uint8_t type;
|
||||
uint8_t nothing;
|
||||
uint16_t idx;
|
||||
} table64addr;
|
||||
struct {
|
||||
uint8_t type;
|
||||
uint8_t delta;
|
||||
uint16_t idx;
|
||||
} table64retendbl;
|
||||
struct {
|
||||
uint8_t type;
|
||||
uint8_t deltah;
|
||||
uint16_t idx;
|
||||
} table64jmptblh;
|
||||
struct {
|
||||
uint32_t type:8;
|
||||
uint32_t deltal:24;
|
||||
} table64jmptbll;
|
||||
uint32_t x;
|
||||
} reloc_t;
|
||||
|
||||
void AddRelocTable64Const(dynarec_native_t* dyn, int ninst, native_consts_t C, int pass)
|
||||
{
|
||||
if(!dyn->need_reloc)
|
||||
return;
|
||||
if(isTable64(dyn, getConst(C)))
|
||||
return;
|
||||
if(pass<3) {
|
||||
dyn->reloc_size++;
|
||||
return;
|
||||
}
|
||||
// generating the reloc
|
||||
reloc_t reloc = {0};
|
||||
reloc.table64c.type = RELOC_TBL64C;
|
||||
reloc.table64c.C = C;
|
||||
reloc.table64c.idx = dyn->table64size;
|
||||
dyn->relocs[dyn->reloc_size++] = reloc.x;
|
||||
}
|
||||
|
||||
void AddRelocTable64RetEndBlock(dynarec_native_t* dyn, int ninst, uintptr_t addr, int pass)
|
||||
{
|
||||
if(!dyn->need_reloc)
|
||||
return;
|
||||
if(isTable64(dyn, getJumpTableAddress64(addr)))
|
||||
return; // no need, already handled
|
||||
// TODO: check iif addr is in current map
|
||||
if(pass<3) {
|
||||
dyn->reloc_size++;
|
||||
return;
|
||||
}
|
||||
reloc_t reloc = {0};
|
||||
intptr_t delta = addr-(dyn->start + dyn->isize);
|
||||
if(delta>255 || delta<0) {
|
||||
dynarec_log(LOG_INFO, "Warning Relocation Ret End Block not possible: delta=%lld, aborting block\n", delta);
|
||||
dyn->abort = 1;
|
||||
}
|
||||
reloc.table64retendbl.type = RELOC_TBL64RETENDBL;
|
||||
reloc.table64retendbl.delta = delta;
|
||||
reloc.table64retendbl.idx = dyn->table64size;
|
||||
dyn->relocs[dyn->reloc_size++] = reloc.x;
|
||||
}
|
||||
|
||||
void AddRelocCancelBlock(dynarec_native_t* dyn, int ninst, int pass)
|
||||
{
|
||||
if(!dyn->need_reloc)
|
||||
return;
|
||||
if(pass<3) {
|
||||
dyn->reloc_size++;
|
||||
return;
|
||||
}
|
||||
reloc_t reloc = {0};
|
||||
reloc.type = RELOC_CANCELBLOCK;
|
||||
dyn->relocs[dyn->reloc_size++] = reloc.x;
|
||||
}
|
||||
|
||||
void AddRelocTable64Addr(dynarec_native_t* dyn, int ninst, uintptr_t addr, int pass)
|
||||
{
|
||||
if(!dyn->need_reloc)
|
||||
return;
|
||||
if(isTable64(dyn, addr))
|
||||
return; // no need, already handled
|
||||
// check if addr is in the same mmap area
|
||||
// else, use a cancel block instead
|
||||
uintptr_t start;
|
||||
int ok = 1;
|
||||
if(!IsAddrFileMapped(dyn->start, NULL, &start))
|
||||
ok = 0;
|
||||
else {
|
||||
uintptr_t end = start + SizeFileMapped(dyn->start);
|
||||
if(addr<start || addr>=end)
|
||||
ok = 0;
|
||||
if(ok && ((addr-start)>=0x100000000LL))
|
||||
ok = 0;
|
||||
}
|
||||
if(!ok) return AddRelocCancelBlock(dyn, ninst, pass);
|
||||
if(pass<3) {
|
||||
dyn->reloc_size++;
|
||||
return;
|
||||
}
|
||||
reloc_t reloc = {0};
|
||||
reloc.type = RELOC_TBL64ADDR;
|
||||
reloc.table64addr.idx = dyn->table64size;
|
||||
dyn->relocs[dyn->reloc_size++] = reloc.x;
|
||||
}
|
||||
|
||||
|
||||
void AddRelocTable64JmpTbl(dynarec_native_t* dyn, int ninst, uintptr_t addr, int pass)
|
||||
{
|
||||
if(!dyn->need_reloc)
|
||||
return;
|
||||
if(isTable64(dyn, getJumpTableAddress64(addr)))
|
||||
return; // no need, already handled
|
||||
// check if addr is in the same mmap area
|
||||
// else, use a cancel block instead
|
||||
uintptr_t start;
|
||||
int ok = 1;
|
||||
if(!IsAddrFileMapped(dyn->start, NULL, &start))
|
||||
ok = 0;
|
||||
else {
|
||||
uintptr_t end = start + SizeFileMapped(dyn->start);
|
||||
if(addr<start || addr>=end)
|
||||
ok = 0;
|
||||
if(ok && ((addr-start)>=0x100000000LL))
|
||||
ok = 0;
|
||||
}
|
||||
if(!ok) return AddRelocCancelBlock(dyn, ninst, pass);
|
||||
if(pass<3) {
|
||||
dyn->reloc_size+=2;
|
||||
return;
|
||||
}
|
||||
uintptr_t delta = addr - start;
|
||||
reloc_t reloc = {0};
|
||||
reloc.type = RELOC_TBL64TBLJMPH;
|
||||
reloc.table64jmptblh.idx = dyn->table64size;
|
||||
reloc.table64jmptblh.deltah = delta>>24;
|
||||
dyn->relocs[dyn->reloc_size++] = reloc.x;
|
||||
reloc.type = RELOC_TBL64TBLJMPL;
|
||||
reloc.table64jmptbll.deltal = delta&0xffffff;
|
||||
dyn->relocs[dyn->reloc_size++] = reloc.x;
|
||||
}
|
||||
|
||||
int ApplyRelocs(dynablock_t* block, intptr_t delta_block, intptr_t delta_map, uintptr_t mapping_start)
|
||||
{
|
||||
if(!block || !block->relocs || !block->relocsize)
|
||||
return 0;
|
||||
size_t reloc_size = block->relocsize / sizeof(uint32_t);
|
||||
reloc_t *relocs = block->relocs;
|
||||
uint64_t *table64 = block->table64;
|
||||
int idx;
|
||||
|
||||
int i = 0;
|
||||
uintptr_t addr;
|
||||
dynarec_log(LOG_DEBUG, "Will apply %zd reloc to dynablock starting at %p - %p\n", reloc_size, block->x64_addr, block->x64_addr + block->x64_size);
|
||||
while(i<reloc_size) {
|
||||
idx = -1;
|
||||
switch(relocs[i].type) {
|
||||
case RELOC_TBL64C:
|
||||
idx = relocs[i].table64c.idx;
|
||||
table64[idx] = getConst(relocs[i].table64c.C);
|
||||
dynarec_log(LOG_DEBUG, "\tApply Relocs[%d]: TABLE64[%d]=Const:%d\n", i, idx, relocs[i].table64c.C);
|
||||
break;
|
||||
case RELOC_TBL64ADDR:
|
||||
idx = relocs[i].table64addr.idx;
|
||||
table64[idx] += delta_map;
|
||||
dynarec_log(LOG_DEBUG, "\tApply Relocs[%d]: TABLE64[%d]=Addr in Map, delta=%zd\n", i, idx, delta_map);
|
||||
break;
|
||||
case RELOC_TBL64RETENDBL:
|
||||
idx = relocs[i].table64retendbl.idx;
|
||||
addr = (uintptr_t)block->x64_addr + block->x64_size + relocs[i].table64retendbl.delta;
|
||||
table64[idx] = getJumpTableAddress64(addr);
|
||||
dynarec_log(LOG_DEBUG, "\tApply Relocs[%d]: TABLE64[%d]=JmpTable64(%p)\n", i, idx, (void*)addr);
|
||||
break;
|
||||
case RELOC_CANCELBLOCK:
|
||||
dynarec_log(LOG_DEBUG, "\tApply Relocs[%d]: Cancel Block\n", i);
|
||||
block->dirty = 1;
|
||||
block->hash = 0;
|
||||
return 0;
|
||||
case RELOC_TBL64TBLJMPH:
|
||||
if(relocs[i+1].type!=RELOC_TBL64TBLJMPL)
|
||||
return -2; // bad sequence
|
||||
idx = relocs[i].table64jmptblh.idx;
|
||||
addr = relocs[i].table64jmptblh.deltah;
|
||||
addr = mapping_start + relocs[i+1].table64jmptbll.deltal + (addr<<24);
|
||||
table64[idx] = getJumpTableAddress64(addr);
|
||||
dynarec_log(LOG_DEBUG, "\tApply Relocs[%d,%d]: TABLE64[%d]=JmpTable64(%p)=%p\n", i, i+1, idx, (void*)addr, getJumpTableAddress64(addr));
|
||||
break;
|
||||
case RELOC_TBL64TBLJMPL:
|
||||
break;
|
||||
default:
|
||||
dynarec_log(LOG_DEBUG, "\tUnknown Relocs[%d]: %d\n", i, relocs[i].type);
|
||||
return -1;
|
||||
}
|
||||
if(idx!=-1) {
|
||||
if(idx>=block->table64size) {
|
||||
dynarec_log(LOG_NONE, "Warning: Reloc Table64 idx out of range (%d vs %d)\n", idx, block->table64size);
|
||||
}
|
||||
}
|
||||
++i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int RelocsHaveCancel(dynablock_t* block)
|
||||
{
|
||||
if(!block->relocs || !block->relocsize)
|
||||
return 0;
|
||||
size_t reloc_size = block->relocsize/sizeof(uint32_t);
|
||||
for(size_t i=0; i<reloc_size; ++i)
|
||||
if(((reloc_t*)block->relocs)[i].type == RELOC_CANCELBLOCK)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uintptr_t RelocGetNext()
|
||||
{
|
||||
return getConst(const_native_next);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
#ifndef __DYNACACHE_RELOC_H__
|
||||
#define __DYNACACHE_RELOC_H__
|
||||
|
||||
#ifdef ARM64
|
||||
#include "dynarec/arm64/dynarec_arm64_consts.h"
|
||||
#define native_consts_t arm64_consts_t
|
||||
#elif defined(RV64)
|
||||
#include "dynarec/rv64/dynarec_rv64_consts.h"
|
||||
#define native_consts_t rv64_consts_t
|
||||
#elif defined(LA64)
|
||||
#include "dynarec/la64/dynarec_la64_consts.h"
|
||||
#define native_consts_t la64_consts_t
|
||||
#else
|
||||
#error Unsupported architecture
|
||||
#endif
|
||||
|
||||
void AddRelocTable64Const(dynarec_native_t* dyn, int ninst, native_consts_t C, int pass);
|
||||
void AddRelocTable64Addr(dynarec_native_t* dyn, int ninst, uintptr_t addr, int pass);
|
||||
void AddRelocTable64RetEndBlock(dynarec_native_t* dyn, int ninst, uintptr_t addr, int pass);
|
||||
void AddRelocTable64JmpTbl(dynarec_native_t* dyn, int ninst, uintptr_t addr, int pass);
|
||||
void AddRelocCancelBlock(dynarec_native_t* dyn, int ninst, int pass);
|
||||
|
||||
int ApplyRelocs(dynablock_t* block, intptr_t delta_block, intptr_t delta_map, uintptr_t mapping_start);
|
||||
int RelocsHaveCancel(dynablock_t* block);
|
||||
uintptr_t RelocGetNext();
|
||||
|
||||
#endif
|
||||
@@ -43,10 +43,10 @@ void* LinkNext(x64emu_t* emu, uintptr_t addr, void* x2, uintptr_t* x3)
|
||||
} else if(emu->segs[_CS]==0x23 && addr>0x100000000LL) {
|
||||
dynablock_t* db = FindDynablockFromNativeAddress(x2-4);
|
||||
printf_log(LOG_INFO, "Warning, jumping to high address %p from %p (db=%p, x64addr=%p/%s)\n", (void*)addr, x2-4, db, db?(void*)getX64Address(db, (uintptr_t)x2-4):NULL, db?getAddrFunctionName(getX64Address(db, (uintptr_t)x2-4)):"(nil)");
|
||||
#endif
|
||||
} else if(!memExist(new_addr)) {
|
||||
dynablock_t* db = FindDynablockFromNativeAddress(x2-4);
|
||||
printf_log(LOG_INFO, "Warning, jumping to an unmapped address %p->%p from %p (db=%p, x64addr=%p/%s)\n", (void*)new_addr, (void*)addr, x2-4, db, db?(void*)getX64Address(db, (uintptr_t)x2-4):NULL, db?getAddrFunctionName(getX64Address(db, (uintptr_t)x2-4)):"(nil)");
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
void * jblock;
|
||||
@@ -166,7 +166,7 @@ void DynaRun(x64emu_t* emu)
|
||||
if ((skip = SigSetJmp(emu->jmpbuf, 1)))
|
||||
#endif
|
||||
{
|
||||
printf_log(LOG_DEBUG, "Setjmp DynaRun, fs=0x%x\n", emu->segs[_FS]);
|
||||
dynarec_log(LOG_DEBUG, "Setjmp DynaRun, fs=0x%x will %sskip dynarec next\n", emu->segs[_FS], (skip==3)?"not ":"");
|
||||
#ifdef DYNAREC
|
||||
if(BOX64ENV(dynarec_test)) {
|
||||
if(emu->test.clean)
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#define MAXBLOCK_SIZE ((1<<20)-200)
|
||||
|
||||
#define RAZ_SPECIFIC(A, N) rasNativeState(A, N)
|
||||
#define UPDATE_SPECIFICS(A) updateNativeFlags(A)
|
||||
#define UPDATE_SPECIFICS(A) updateYmm0s(dyn, 0, 0); updateNativeFlags(A); propagateFpuBarrier(A)
|
||||
#define PREUPDATE_SPECIFICS(A)
|
||||
#define POSTUPDATE_SPECIFICS(A) updateUneeded(A)
|
||||
#define ARCH_SIZE(A) get_size_arch(A)
|
||||
@@ -33,7 +33,9 @@
|
||||
#define STOP_NATIVE_FLAGS(A, B) A->insts[B].nat_flags_op = NAT_FLAG_OP_UNUSABLE
|
||||
#define ARCH_UNALIGNED(A, B) arch_unaligned(A, B)
|
||||
extern uint32_t arm64_crc(void* p, uint32_t len);
|
||||
#define ARCH_CRC(A, B) if(arm64_crc32) return arm64_crc(A, B)
|
||||
#define ARCH_CRC(A, B) if(cpuext.crc32) return arm64_crc(A, B)
|
||||
extern void* create_updateflags();
|
||||
#define ARCH_UPDATEFLAGS() create_updateflags()
|
||||
|
||||
#define ARCH_NOP 0b11010101000000110010000000011111
|
||||
#define ARCH_UDF 0xcafe
|
||||
@@ -103,4 +105,6 @@ extern uint32_t arm64_crc(void* p, uint32_t len);
|
||||
#error Unsupported platform
|
||||
#endif
|
||||
|
||||
#include "dynacache_reloc.h"
|
||||
|
||||
#endif //__DYNAREC_ARCH__H_
|
||||
@@ -36,7 +36,7 @@
|
||||
#define STRONGMEM_LAST_WRITE 1 // The level of a barrier before the last guest memory store will be put
|
||||
#define STRONGMEM_SEQ_WRITE 3 // The level of a barrier at every third memory store will be put
|
||||
|
||||
#define STRONGMEM_LEVEL() (box64_wine && VolatileRangesContains(ip) ? 0 : BOX64DRENV(dynarec_strongmem))
|
||||
#define STRONGMEM_LEVEL() ((box64_wine && VolatileRangesContains(ip)) ? 0 : BOX64DRENV(dynarec_strongmem))
|
||||
|
||||
#if STEP == 1
|
||||
|
||||
@@ -49,10 +49,10 @@
|
||||
dyn->insts[ninst].will_write = 1; \
|
||||
} while (0)
|
||||
|
||||
#define SMWRITELOCK(lock) \
|
||||
do { \
|
||||
dyn->insts[ninst].lock = lock; \
|
||||
SMWRITE(); \
|
||||
#define SMWRITELOCK(lock) \
|
||||
do { \
|
||||
if(lock) dyn->insts[ninst].lock = 1;\
|
||||
SMWRITE(); \
|
||||
} while (0)
|
||||
|
||||
#define SMWRITE2() \
|
||||
|
||||
+111
-131
@@ -23,6 +23,9 @@
|
||||
#include "dynarec_arch.h"
|
||||
#include "dynarec_next.h"
|
||||
#include "gdbjit.h"
|
||||
#include "khash.h"
|
||||
|
||||
KHASH_MAP_INIT_INT64(table64, uint32_t)
|
||||
|
||||
void printf_x64_instruction(dynarec_native_t* dyn, zydis_dec_t* dec, instruction_x64_t* inst, const char* name) {
|
||||
uint8_t *ip = (uint8_t*)inst->addr;
|
||||
@@ -293,27 +296,51 @@ void addInst(instsize_t* insts, size_t* size, int x64_size, int native_size)
|
||||
}
|
||||
}
|
||||
|
||||
static kh_table64_t* khtable64 = NULL;
|
||||
|
||||
int isTable64(dynarec_native_t *dyn, uint64_t val)
|
||||
{
|
||||
if(!khtable64)
|
||||
return 0;
|
||||
if(kh_get(table64, khtable64, val)==kh_end(khtable64))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
// add a value to table64 (if needed) and gives back the imm19 to use in LDR_literal
|
||||
int Table64(dynarec_native_t *dyn, uint64_t val, int pass)
|
||||
{
|
||||
if(!khtable64)
|
||||
khtable64 = kh_init(table64);
|
||||
// find the value if already present
|
||||
int idx = -1;
|
||||
for(int i=0; i<dyn->table64size && (idx==-1); ++i)
|
||||
if(dyn->table64[i] == val)
|
||||
idx = i;
|
||||
// not found, add it
|
||||
if(idx==-1) {
|
||||
khint_t k = kh_get(table64, khtable64, val);
|
||||
uint32_t idx = 0;
|
||||
if(k!=kh_end(khtable64)) {
|
||||
idx = kh_value(khtable64, k);
|
||||
} else {
|
||||
idx = dyn->table64size++;
|
||||
if(idx < dyn->table64cap)
|
||||
dyn->table64[idx] = val;
|
||||
else if(pass==3)
|
||||
printf_log(LOG_NONE, "Warning, table64 bigger than expected %d vs %d\n", idx, dyn->table64cap);
|
||||
if(pass==3) {
|
||||
if(idx < dyn->table64cap)
|
||||
dyn->table64[idx] = val;
|
||||
else
|
||||
printf_log(LOG_NONE, "Warning, table64 bigger than expected %d vs %d\n", idx, dyn->table64cap);
|
||||
}
|
||||
int ret;
|
||||
k = kh_put(table64, khtable64, val, &ret);
|
||||
kh_value(khtable64, k) = idx;
|
||||
}
|
||||
// calculate offset
|
||||
int delta = dyn->tablestart + idx*sizeof(uint64_t) - (uintptr_t)dyn->block;
|
||||
return delta;
|
||||
}
|
||||
|
||||
void ResetTable64(dynarec_native_t* dyn)
|
||||
{
|
||||
dyn->table64size = 0;
|
||||
if(khtable64) {
|
||||
kh_clear(table64, khtable64);
|
||||
}
|
||||
}
|
||||
|
||||
static void recurse_mark_alive(dynarec_native_t* dyn, int i)
|
||||
{
|
||||
if(dyn->insts[i].x64.alive)
|
||||
@@ -325,9 +352,8 @@ static void recurse_mark_alive(dynarec_native_t* dyn, int i)
|
||||
recurse_mark_alive(dyn, i+1);
|
||||
}
|
||||
|
||||
static int sizePredecessors(dynarec_native_t* dyn)
|
||||
static void sizePredecessors(dynarec_native_t* dyn)
|
||||
{
|
||||
int pred_sz = 1; // to be safe
|
||||
// compute total size of predecessor to allocate the array
|
||||
// mark alive...
|
||||
recurse_mark_alive(dyn, 0);
|
||||
@@ -335,7 +361,6 @@ static int sizePredecessors(dynarec_native_t* dyn)
|
||||
int jmpto;
|
||||
for(int i=0; i<dyn->size; ++i) {
|
||||
if(dyn->insts[i].x64.alive && dyn->insts[i].x64.jmp && ((jmpto=dyn->insts[i].x64.jmp_insts)!=-1)) {
|
||||
pred_sz++;
|
||||
dyn->insts[jmpto].pred_sz++;
|
||||
}
|
||||
}
|
||||
@@ -347,11 +372,9 @@ static int sizePredecessors(dynarec_native_t* dyn)
|
||||
// second the "has_next"
|
||||
for(int i=0; i<dyn->size-1; ++i) {
|
||||
if(dyn->insts[i].x64.has_next) {
|
||||
pred_sz++;
|
||||
dyn->insts[i+1].pred_sz++;
|
||||
}
|
||||
}
|
||||
return pred_sz;
|
||||
}
|
||||
static void fillPredecessors(dynarec_native_t* dyn)
|
||||
{
|
||||
@@ -417,93 +440,13 @@ static int updateNeed(dynarec_native_t* dyn, int ninst, uint8_t need) {
|
||||
return ninst;
|
||||
}
|
||||
|
||||
static void updateYmm0s(dynarec_native_t* dyn, int ninst, int max_ninst_reached) {
|
||||
int can_incr = ninst == max_ninst_reached; // Are we the top-level call?
|
||||
int ok = 1;
|
||||
while ((can_incr || ok) && ninst<dyn->size) {
|
||||
//if(dyn->need_dump) dynarec_log(LOG_NONE, "update ninst=%d (%d): can_incr=%d\n", ninst, max_ninst_reached, can_incr);
|
||||
uint16_t new_purge_ymm, new_ymm0_in, new_ymm0_out;
|
||||
|
||||
if (dyn->insts[ninst].pred_sz && dyn->insts[ninst].x64.alive) {
|
||||
// The union of the empty set is empty (0), the intersection is the universe (-1)
|
||||
// The first instruction is the entry point, which has a virtual pred with ymm0_out = 0
|
||||
// Similarly, float barriers reset ymm0s
|
||||
uint16_t ymm0_union = 0;
|
||||
uint16_t ymm0_inter = (ninst && !(dyn->insts[ninst].x64.barrier & BARRIER_FLOAT)) ? ((uint16_t)-1) : (uint16_t)0;
|
||||
for (int i = 0; i < dyn->insts[ninst].pred_sz; ++i) {
|
||||
int pred = dyn->insts[ninst].pred[i];
|
||||
//if(dyn->need_dump) dynarec_log(LOG_NONE, "\twith pred[%d] = %d", i, pred);
|
||||
if (pred >= max_ninst_reached) {
|
||||
//if(dyn->need_dump) dynarec_log(LOG_NONE, " (skipped)\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
int pred_out = dyn->insts[pred].x64.has_callret ? 0 : dyn->insts[pred].ymm0_out;
|
||||
//if(dyn->need_dump) dynarec_log(LOG_NONE, " ~> %04X\n", pred_out);
|
||||
ymm0_union |= pred_out;
|
||||
ymm0_inter &= pred_out;
|
||||
}
|
||||
//if(dyn->need_dump) dynarec_log(LOG_NONE, "\t=> %04X,%04X\n", ymm0_union, ymm0_inter);
|
||||
// Notice the default values yield something coherent here (if all pred are after ninst)
|
||||
new_purge_ymm = ymm0_union & ~ymm0_inter;
|
||||
new_ymm0_in = ymm0_inter;
|
||||
new_ymm0_out = (ymm0_inter | dyn->insts[ninst].ymm0_add) & ~dyn->insts[ninst].ymm0_sub;
|
||||
|
||||
if ((dyn->insts[ninst].purge_ymm != new_purge_ymm) || (dyn->insts[ninst].ymm0_in != new_ymm0_in) || (dyn->insts[ninst].ymm0_out != new_ymm0_out)) {
|
||||
// Need to update self and next(s)
|
||||
dyn->insts[ninst].purge_ymm = new_purge_ymm;
|
||||
dyn->insts[ninst].ymm0_in = new_ymm0_in;
|
||||
dyn->insts[ninst].ymm0_out = new_ymm0_out;
|
||||
|
||||
if (can_incr) {
|
||||
// We always have ninst == max_ninst_reached when can_incr == 1
|
||||
++max_ninst_reached;
|
||||
} else {
|
||||
// We need to stop here if the opcode has no "real" next or if we reached the ninst of the toplevel
|
||||
ok = (max_ninst_reached - 1 != ninst) && dyn->insts[ninst].x64.has_next && !dyn->insts[ninst].x64.has_callret;
|
||||
}
|
||||
|
||||
int jmp = (dyn->insts[ninst].x64.jmp)?dyn->insts[ninst].x64.jmp_insts:-1;
|
||||
if((jmp!=-1) && (jmp < max_ninst_reached)) {
|
||||
//if(dyn->need_dump) dynarec_log(LOG_NONE, "\t! jump to %d\n", jmp);
|
||||
// The jump goes before the last instruction reached, update the destination
|
||||
// If this is the top level call, this means the jump goes backward (jmp != ninst)
|
||||
// Otherwise, since we don't update all instructions, we may miss the update (don't use jmp < ninst)
|
||||
updateYmm0s(dyn, jmp, max_ninst_reached);
|
||||
}
|
||||
} else {
|
||||
if (can_incr) {
|
||||
// We always have ninst == max_ninst_reached when can_incr == 1
|
||||
++max_ninst_reached;
|
||||
|
||||
// Also update jumps to before (they are skipped otherwise)
|
||||
int jmp = (dyn->insts[ninst].x64.jmp)?dyn->insts[ninst].x64.jmp_insts:-1;
|
||||
if((jmp!=-1) && (jmp < max_ninst_reached)) {
|
||||
//if(dyn->need_dump) dynarec_log(LOG_NONE, "\t! jump to %d\n", jmp);
|
||||
updateYmm0s(dyn, jmp, max_ninst_reached);
|
||||
}
|
||||
} else {
|
||||
// We didn't update anything, we can leave
|
||||
ok = 0;
|
||||
}
|
||||
}
|
||||
} else if (can_incr) {
|
||||
// We always have ninst == max_ninst_reached when can_incr == 1
|
||||
++max_ninst_reached;
|
||||
} else {
|
||||
// We didn't update anything, we can leave
|
||||
ok = 0;
|
||||
}
|
||||
++ninst;
|
||||
}
|
||||
}
|
||||
|
||||
void* current_helper = NULL;
|
||||
static int static_jmps[MAX_INSTS+2];
|
||||
static uintptr_t static_next[MAX_INSTS+2];
|
||||
static uint64_t static_table64[(MAX_INSTS+3)/4];
|
||||
static instruction_native_t static_insts[MAX_INSTS+2] = {0};
|
||||
static callret_t static_callrets[MAX_INSTS+2] = {0};
|
||||
static int static_preds[MAX_INSTS*2+2]; // for the worst case scenario were all instructions are conditional jumps
|
||||
void* redundant_helper = NULL;
|
||||
// TODO: ninst could be a uint16_t instead of an int, that could same some temp. memory
|
||||
|
||||
void ClearCache(void* start, size_t len)
|
||||
@@ -549,6 +492,7 @@ void CancelBlock64(int need_lock)
|
||||
}
|
||||
}
|
||||
current_helper = NULL;
|
||||
redundant_helper = NULL;
|
||||
if(need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
}
|
||||
@@ -558,17 +502,21 @@ uintptr_t native_pass1(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
uintptr_t native_pass2(dynarec_native_t* dyn, uintptr_t addr, int alternate, int is32bits, int inst_max);
|
||||
uintptr_t native_pass3(dynarec_native_t* dyn, uintptr_t addr, int alternate, int is32bits, int inst_max);
|
||||
|
||||
void* CreateEmptyBlock(dynablock_t* block, uintptr_t addr, int is32bits) {
|
||||
block->isize = 0;
|
||||
block->done = 0;
|
||||
size_t sz = 4*sizeof(void*);
|
||||
void* actual_p = (void*)AllocDynarecMap(sz);
|
||||
dynablock_t* CreateEmptyBlock(uintptr_t addr, int is32bits, int is_new) {
|
||||
size_t sz = 4*sizeof(void*) + sizeof(dynablock_t);
|
||||
void* actual_p = (void*)AllocDynarecMap(addr, sz, is_new);
|
||||
void* p = actual_p + sizeof(void*);
|
||||
if(actual_p==NULL) {
|
||||
dynarec_log(LOG_INFO, "AllocDynarecMap(%p, %zu) failed, canceling block\n", block, sz);
|
||||
dynarec_log(LOG_INFO, "AllocDynarecMap(%p, %zu) failed, canceling block\n", (void*)addr, sz);
|
||||
CancelBlock64(0);
|
||||
return NULL;
|
||||
}
|
||||
dynablock_t* block = (dynablock_t*)(actual_p+4*sizeof(void*));
|
||||
memset(block, 0, sizeof(dynablock_t));
|
||||
// fill the block
|
||||
block->x64_addr = (void*)addr;
|
||||
block->isize = 0;
|
||||
block->done = 0;
|
||||
block->size = sz;
|
||||
block->actual_block = actual_p;
|
||||
block->block = p;
|
||||
@@ -582,7 +530,7 @@ void* CreateEmptyBlock(dynablock_t* block, uintptr_t addr, int is32bits) {
|
||||
return block;
|
||||
}
|
||||
|
||||
void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bits, int inst_max) {
|
||||
dynablock_t* FillBlock64(uintptr_t addr, int alternate, int is32bits, int inst_max, int is_new) {
|
||||
/*
|
||||
A Block must have this layout:
|
||||
|
||||
@@ -599,16 +547,19 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
*/
|
||||
if(addr>=BOX64ENV(nodynarec_start) && addr<BOX64ENV(nodynarec_end)) {
|
||||
dynarec_log(LOG_INFO, "Create empty block in no-dynarec zone\n");
|
||||
return CreateEmptyBlock(block, addr, is32bits);
|
||||
}
|
||||
if(current_helper) {
|
||||
dynarec_log(LOG_DEBUG, "Canceling dynarec FillBlock at %p as another one is going on\n", (void*)addr);
|
||||
return NULL;
|
||||
return CreateEmptyBlock(addr, is32bits, is_new);
|
||||
}
|
||||
if(checkInHotPage(addr)) {
|
||||
dynarec_log(LOG_DEBUG, "Not creating dynablock at %p as in a HotPage\n", (void*)addr);
|
||||
return NULL;
|
||||
}
|
||||
if(current_helper) {
|
||||
if(current_helper==redundant_helper) {
|
||||
dynarec_log(LOG_INFO, "%04d|Warning: previous FillBlock did not cleaned up correctly (helper=%p, x64addr=%p, db=%p)\n", GetTID(), current_helper, (void*)((dynarec_native_t*)current_helper)->start, ((dynarec_native_t*)current_helper)->dynablock);
|
||||
return NULL;
|
||||
}
|
||||
dynarec_log(LOG_INFO, "Warning: some static area curruption appeared (current=%p, redundant=%p)\n", current_helper, redundant_helper);
|
||||
}
|
||||
// protect the 1st page
|
||||
protectDB(addr, 1);
|
||||
// init the helper
|
||||
@@ -617,8 +568,8 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
#ifdef GDBJIT
|
||||
helper.gdbjit_block = box_calloc(1, sizeof(gdbjit_block_t));
|
||||
#endif
|
||||
current_helper = &helper;
|
||||
helper.dynablock = block;
|
||||
redundant_helper = current_helper = &helper;
|
||||
helper.dynablock = NULL;
|
||||
helper.start = addr;
|
||||
uintptr_t start = addr;
|
||||
helper.cap = MAX_INSTS;
|
||||
@@ -627,8 +578,14 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
helper.jmp_cap = MAX_INSTS;
|
||||
helper.next = static_next;
|
||||
helper.next_cap = MAX_INSTS;
|
||||
helper.table64 = static_table64;
|
||||
helper.table64cap = sizeof(static_table64)/sizeof(uint64_t);
|
||||
helper.table64 = NULL;
|
||||
helper.env = GetCurEnvByAddr(addr);
|
||||
ResetTable64(&helper);
|
||||
helper.table64cap = 0;
|
||||
helper.end = addr + SizeFileMapped(addr);
|
||||
if(helper.end == helper.start) // that means there is no mmap with a file associated to the memory
|
||||
helper.end = (uintptr_t)~0LL;
|
||||
helper.need_reloc = IsAddrNeedReloc(addr);
|
||||
// pass 0, addresses, x64 jump addresses, overall size of the block
|
||||
uintptr_t end = native_pass0(&helper, addr, alternate, is32bits, inst_max);
|
||||
if(helper.abort) {
|
||||
@@ -643,7 +600,7 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
if(!helper.size) {
|
||||
dynarec_log(LOG_INFO, "Warning, null-sized dynarec block (%p)\n", (void*)addr);
|
||||
CancelBlock64(0);
|
||||
return CreateEmptyBlock(block, addr, is32bits);
|
||||
return CreateEmptyBlock(addr, is32bits, is_new);
|
||||
}
|
||||
if(!isprotectedDB(addr, 1)) {
|
||||
dynarec_log(LOG_INFO, "Warning, write on current page on pass0, aborting dynablock creation (%p)\n", (void*)addr);
|
||||
@@ -667,6 +624,10 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
#endif
|
||||
{
|
||||
helper.insts[i].x64.need_after |= X_PEND;
|
||||
if(helper.insts[i].barrier_maybe) {
|
||||
helper.insts[i].x64.barrier|=BARRIER_FLOAT;
|
||||
helper.insts[i].barrier_maybe = 0;
|
||||
}
|
||||
} else {
|
||||
// find jump address instruction
|
||||
int k=-1;
|
||||
@@ -699,8 +660,6 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
k=i2;
|
||||
}*/
|
||||
if(k!=-1) {
|
||||
if(!helper.insts[i].barrier_maybe)
|
||||
helper.insts[k].x64.barrier |= BARRIER_FULL;
|
||||
// special case, loop on itself with some nop in between
|
||||
if(k<i && !helper.insts[i].x64.has_next && is_nops(&helper, helper.insts[k].x64.addr, helper.insts[i].x64.addr-helper.insts[k].x64.addr)) {
|
||||
#ifndef ARCH_NOP
|
||||
@@ -711,12 +670,18 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
#endif
|
||||
}
|
||||
helper.insts[i].x64.jmp_insts = k;
|
||||
helper.insts[i].barrier_maybe = 0;
|
||||
} else {
|
||||
if(helper.insts[i].barrier_maybe) {
|
||||
helper.insts[i].x64.barrier|=BARRIER_FLOAT;
|
||||
helper.insts[i].barrier_maybe = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// fill predecessors with the jump address
|
||||
int alloc_size = sizePredecessors(&helper);
|
||||
helper.predecessor = (int*)alloca(alloc_size*sizeof(int));
|
||||
sizePredecessors(&helper);
|
||||
helper.predecessor = static_preds;
|
||||
fillPredecessors(&helper);
|
||||
|
||||
PREUPDATE_SPECIFICS(&helper);
|
||||
@@ -730,7 +695,6 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
int ii = i;
|
||||
while(ii<helper.size && !helper.insts[ii].pred_sz) {
|
||||
fpu_reset_ninst(&helper, ii);
|
||||
helper.insts[ii].ymm0_in = helper.insts[ii].ymm0_sub = helper.insts[ii].ymm0_add = helper.insts[ii].ymm0_out = helper.insts[ii].purge_ymm = 0;
|
||||
RAZ_SPECIFIC(&helper, ii);
|
||||
++ii;
|
||||
}
|
||||
@@ -745,9 +709,8 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
// NULL block after removing dead code, how is that possible?
|
||||
dynarec_log(LOG_INFO, "Warning, null-sized dynarec block after trimming dead code (%p)\n", (void*)addr);
|
||||
CancelBlock64(0);
|
||||
return CreateEmptyBlock(block, addr, is32bits);
|
||||
return CreateEmptyBlock(addr, is32bits, is_new);
|
||||
}
|
||||
updateYmm0s(&helper, 0, 0);
|
||||
UPDATE_SPECIFICS(&helper);
|
||||
// check for still valid close loop
|
||||
for(int ii=0; ii<helper.jmp_sz && !helper.always_test; ++ii) {
|
||||
@@ -763,7 +726,8 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
// no need for next anymore
|
||||
helper.next_sz = helper.next_cap = 0;
|
||||
helper.next = NULL;
|
||||
|
||||
ResetTable64(&helper);
|
||||
helper.reloc_size = 0;
|
||||
// pass 1, float optimizations, first pass for flags
|
||||
native_pass1(&helper, addr, alternate, is32bits, inst_max);
|
||||
if(helper.abort) {
|
||||
@@ -776,6 +740,8 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
helper.need_x87check = 0;
|
||||
}
|
||||
POSTUPDATE_SPECIFICS(&helper);
|
||||
ResetTable64(&helper);
|
||||
helper.reloc_size = 0;
|
||||
// pass 2, instruction size
|
||||
helper.callrets = static_callrets;
|
||||
native_pass2(&helper, addr, alternate, is32bits, inst_max);
|
||||
@@ -798,16 +764,17 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
--imax;
|
||||
if(dyn->need_dump || BOX64ENV(dynarec_log))dynarec_log(LOG_NONE, "Dynablock oversized, with %zu (max=%zd), recomputing cutting at %d from %d\n", native_size, MAXBLOCK_SIZE, imax, helper.size);
|
||||
CancelBlock64(0);
|
||||
return FillBlock64(block, addr, alternate, is32bits, imax);
|
||||
return FillBlock64(addr, alternate, is32bits, imax, is_new);
|
||||
}
|
||||
size_t insts_rsize = (helper.insts_size+2)*sizeof(instsize_t);
|
||||
insts_rsize = (insts_rsize+7)&~7; // round the size...
|
||||
size_t arch_size = ARCH_SIZE(&helper);
|
||||
size_t callret_size = helper.callret_size*sizeof(callret_t);
|
||||
size_t reloc_size = helper.reloc_size*sizeof(uint32_t);
|
||||
// ok, now allocate mapped memory, with executable flag on
|
||||
size_t sz = sizeof(void*) + native_size + helper.table64size*sizeof(uint64_t) + 4*sizeof(void*) + insts_rsize + arch_size + callret_size;
|
||||
// dynablock_t* block (arm insts) table64 jmpnext code instsize arch callrets
|
||||
void* actual_p = (void*)AllocDynarecMap(sz);
|
||||
size_t sz = sizeof(void*) + native_size + helper.table64size*sizeof(uint64_t) + 4*sizeof(void*) + insts_rsize + arch_size + callret_size + sizeof(dynablock_t) + reloc_size;
|
||||
// dynablock_t* block (arm insts) table64 jmpnext code instsize arch callrets dynablock relocs
|
||||
void* actual_p = (void*)AllocDynarecMap(addr, sz, is_new);
|
||||
void* p = (void*)(((uintptr_t)actual_p) + sizeof(void*));
|
||||
void* tablestart = p + native_size;
|
||||
void* next = tablestart + helper.table64size*sizeof(uint64_t);
|
||||
@@ -815,12 +782,21 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
void* arch = instsize + insts_rsize;
|
||||
void* callrets = arch + arch_size;
|
||||
if(actual_p==NULL) {
|
||||
dynarec_log(LOG_INFO, "AllocDynarecMap(%p, %zu) failed, canceling block\n", block, sz);
|
||||
dynarec_log(LOG_INFO, "AllocDynarecMap(%p, %zu) failed, canceling block\n", (void*)addr, sz);
|
||||
CancelBlock64(0);
|
||||
return NULL;
|
||||
}
|
||||
helper.block = p;
|
||||
dynablock_t* block = (dynablock_t*)(callrets+callret_size);
|
||||
memset(block, 0, sizeof(dynablock_t));
|
||||
void* relocs = helper.need_reloc?(block+1):NULL;
|
||||
// fill the block
|
||||
block->x64_addr = (void*)addr;
|
||||
block->isize = 0;
|
||||
block->actual_block = actual_p;
|
||||
helper.relocs = relocs;
|
||||
block->relocs = relocs;
|
||||
block->table64size = helper.table64size;
|
||||
helper.native_start = (uintptr_t)p;
|
||||
helper.tablestart = (uintptr_t)tablestart;
|
||||
helper.jmp_next = (uintptr_t)next+sizeof(void*);
|
||||
@@ -829,6 +805,7 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
helper.table64cap = helper.table64size;
|
||||
helper.table64 = (uint64_t*)helper.tablestart;
|
||||
helper.callrets = (callret_t*)callrets;
|
||||
block->table64 = helper.table64;
|
||||
if(callret_size)
|
||||
memcpy(helper.callrets, static_callrets, helper.callret_size*sizeof(callret_t));
|
||||
helper.callret_size = 0;
|
||||
@@ -846,8 +823,9 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
size_t oldinstsize = helper.insts_size;
|
||||
int oldsize= helper.size;
|
||||
helper.native_size = 0;
|
||||
helper.table64size = 0; // reset table64 (but not the cap)
|
||||
ResetTable64(&helper); // reset table64 (but not the cap)
|
||||
helper.insts_size = 0; // reset
|
||||
helper.reloc_size = 0;
|
||||
native_pass3(&helper, addr, alternate, is32bits, inst_max);
|
||||
if(helper.abort) {
|
||||
if(dyn->need_dump || BOX64ENV(dynarec_log))dynarec_log(LOG_NONE, "Abort dynablock on pass3\n");
|
||||
@@ -869,6 +847,7 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
block->always_test = helper.always_test;
|
||||
block->dirty = block->always_test;
|
||||
block->is32bits = is32bits;
|
||||
block->relocsize = helper.reloc_size*sizeof(uint32_t);
|
||||
if(arch_size) {
|
||||
block->arch_size = arch_size;
|
||||
block->arch = ARCH_FILL(&helper, arch, arch_size);
|
||||
@@ -879,6 +858,7 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
}
|
||||
block->callret_size = helper.callret_size;
|
||||
block->callrets = helper.callrets;
|
||||
block->native_size = native_size;
|
||||
*(dynablock_t**)next = block;
|
||||
*(void**)(next+3*sizeof(void*)) = native_next;
|
||||
CreateJmpNext(block->jmpnext, next+3*sizeof(void*));
|
||||
@@ -920,6 +900,7 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
return NULL;
|
||||
}
|
||||
// ok, free the helper now
|
||||
ResetTable64(&helper);
|
||||
//dynaFree(helper.insts);
|
||||
helper.insts = NULL;
|
||||
if(insts_rsize/sizeof(instsize_t)<helper.insts_size) {
|
||||
@@ -931,7 +912,6 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
//protectDB(addr, end-addr);
|
||||
}
|
||||
if(getProtection(addr)&PROT_NEVERCLEAN) {
|
||||
block->dirty = 1;
|
||||
block->always_test = 1;
|
||||
}
|
||||
if(block->always_test) {
|
||||
@@ -943,7 +923,7 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
*(uint32_t*)(block->block+block->callrets[i].offs) = ARCH_UDF;
|
||||
#endif
|
||||
}
|
||||
current_helper = NULL;
|
||||
redundant_helper = current_helper = NULL;
|
||||
//block->done = 1;
|
||||
return (void*)block;
|
||||
return block;
|
||||
}
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "x64_signals.h"
|
||||
#include "os.h"
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
@@ -37,7 +38,7 @@ void native_fstp(x64emu_t* emu, void* p)
|
||||
void native_print_armreg(x64emu_t* emu, uintptr_t reg, uintptr_t n)
|
||||
{
|
||||
(void)emu;
|
||||
dynarec_log(LOG_DEBUG, "R%lu=0x%lx (%lu)\n", n, reg, reg);
|
||||
dynarec_log(LOG_INFO, "Debug Register R%lu=0x%lx (%lu)\n", n, reg, reg);
|
||||
}
|
||||
|
||||
void native_f2xm1(x64emu_t* emu)
|
||||
@@ -186,20 +187,26 @@ void native_ud(x64emu_t* emu)
|
||||
{
|
||||
if(BOX64ENV(dynarec_test))
|
||||
emu->test.test = 0;
|
||||
EmitSignal(emu, SIGILL, (void*)R_RIP, 0);
|
||||
EmitSignal(emu, X64_SIGILL, (void*)R_RIP, 0);
|
||||
}
|
||||
|
||||
void native_br(x64emu_t* emu)
|
||||
{
|
||||
if(BOX64ENV(dynarec_test))
|
||||
emu->test.test = 0;
|
||||
EmitSignal(emu, SIGSEGV, (void*)R_RIP, 0xb09d);
|
||||
EmitSignal(emu, X64_SIGSEGV, (void*)R_RIP, 0xb09d);
|
||||
}
|
||||
|
||||
void native_priv(x64emu_t* emu)
|
||||
{
|
||||
emu->test.test = 0;
|
||||
EmitSignal(emu, SIGSEGV, (void*)R_RIP, 0xbad0);
|
||||
EmitSignal(emu, X64_SIGSEGV, (void*)R_RIP, 0xbad0);
|
||||
}
|
||||
|
||||
void native_gpf(x64emu_t* emu)
|
||||
{
|
||||
emu->test.test = 0;
|
||||
EmitSignal(emu, X64_SIGSEGV, (void*)R_RIP, 0xbad0); // same effect has private opcode?
|
||||
}
|
||||
|
||||
void native_int(x64emu_t* emu, int num)
|
||||
@@ -216,7 +223,7 @@ void native_wineint(x64emu_t* emu, int num)
|
||||
#endif
|
||||
void native_int3(x64emu_t* emu)
|
||||
{
|
||||
EmitSignal(emu, SIGTRAP, NULL, 3);
|
||||
EmitSignal(emu, X64_SIGTRAP, NULL, 3);
|
||||
}
|
||||
|
||||
void native_div0(x64emu_t* emu)
|
||||
@@ -235,6 +242,7 @@ void native_fsave(x64emu_t* emu, uint8_t* ed)
|
||||
LD2D(p, &emu->x87[7-i].d);
|
||||
p+=10;
|
||||
}
|
||||
reset_fpu(emu);
|
||||
}
|
||||
void native_fsave16(x64emu_t* emu, uint8_t* ed)
|
||||
{
|
||||
@@ -246,6 +254,7 @@ void native_fsave16(x64emu_t* emu, uint8_t* ed)
|
||||
LD2D(p, &emu->x87[7-i].d);
|
||||
p+=10;
|
||||
}
|
||||
reset_fpu(emu);
|
||||
}
|
||||
void native_frstor(x64emu_t* emu, uint8_t* ed)
|
||||
{
|
||||
@@ -294,6 +303,147 @@ void native_fprem1(x64emu_t* emu)
|
||||
}
|
||||
}
|
||||
|
||||
const uint8_t ff_mult2[4][256] = {
|
||||
// a = 0x0e
|
||||
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,
|
||||
0xdb, 0xd5, 0xc7, 0xc9, 0xe3, 0xed, 0xff, 0xf1, 0xab, 0xa5, 0xb7, 0xb9, 0x93, 0x9d, 0x8f, 0x81,
|
||||
0x3b, 0x35, 0x27, 0x29, 0x03, 0x0d, 0x1f, 0x11, 0x4b, 0x45, 0x57, 0x59, 0x73, 0x7d, 0x6f, 0x61,
|
||||
0xad, 0xa3, 0xb1, 0xbf, 0x95, 0x9b, 0x89, 0x87, 0xdd, 0xd3, 0xc1, 0xcf, 0xe5, 0xeb, 0xf9, 0xf7,
|
||||
0x4d, 0x43, 0x51, 0x5f, 0x75, 0x7b, 0x69, 0x67, 0x3d, 0x33, 0x21, 0x2f, 0x05, 0x0b, 0x19, 0x17,
|
||||
0x76, 0x78, 0x6a, 0x64, 0x4e, 0x40, 0x52, 0x5c, 0x06, 0x08, 0x1a, 0x14, 0x3e, 0x30, 0x22, 0x2c,
|
||||
0x96, 0x98, 0x8a, 0x84, 0xae, 0xa0, 0xb2, 0xbc, 0xe6, 0xe8, 0xfa, 0xf4, 0xde, 0xd0, 0xc2, 0xcc,
|
||||
0x41, 0x4f, 0x5d, 0x53, 0x79, 0x77, 0x65, 0x6b, 0x31, 0x3f, 0x2d, 0x23, 0x09, 0x07, 0x15, 0x1b,
|
||||
0xa1, 0xaf, 0xbd, 0xb3, 0x99, 0x97, 0x85, 0x8b, 0xd1, 0xdf, 0xcd, 0xc3, 0xe9, 0xe7, 0xf5, 0xfb,
|
||||
0x9a, 0x94, 0x86, 0x88, 0xa2, 0xac, 0xbe, 0xb0, 0xea, 0xe4, 0xf6, 0xf8, 0xd2, 0xdc, 0xce, 0xc0,
|
||||
0x7a, 0x74, 0x66, 0x68, 0x42, 0x4c, 0x5e, 0x50, 0x0a, 0x04, 0x16, 0x18, 0x32, 0x3c, 0x2e, 0x20,
|
||||
0xec, 0xe2, 0xf0, 0xfe, 0xd4, 0xda, 0xc8, 0xc6, 0x9c, 0x92, 0x80, 0x8e, 0xa4, 0xaa, 0xb8, 0xb6,
|
||||
0x0c, 0x02, 0x10, 0x1e, 0x34, 0x3a, 0x28, 0x26, 0x7c, 0x72, 0x60, 0x6e, 0x44, 0x4a, 0x58, 0x56,
|
||||
0x37, 0x39, 0x2b, 0x25, 0x0f, 0x01, 0x13, 0x1d, 0x47, 0x49, 0x5b, 0x55, 0x7f, 0x71, 0x63, 0x6d,
|
||||
0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd, 0xa7, 0xa9, 0xbb, 0xb5, 0x9f, 0x91, 0x83, 0x8d,
|
||||
// a = 0x09
|
||||
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,
|
||||
0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04, 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c,
|
||||
0xab, 0xa2, 0xb9, 0xb0, 0x8f, 0x86, 0x9d, 0x94, 0xe3, 0xea, 0xf1, 0xf8, 0xc7, 0xce, 0xd5, 0xdc,
|
||||
0x76, 0x7f, 0x64, 0x6d, 0x52, 0x5b, 0x40, 0x49, 0x3e, 0x37, 0x2c, 0x25, 0x1a, 0x13, 0x08, 0x01,
|
||||
0xe6, 0xef, 0xf4, 0xfd, 0xc2, 0xcb, 0xd0, 0xd9, 0xae, 0xa7, 0xbc, 0xb5, 0x8a, 0x83, 0x98, 0x91,
|
||||
0x4d, 0x44, 0x5f, 0x56, 0x69, 0x60, 0x7b, 0x72, 0x05, 0x0c, 0x17, 0x1e, 0x21, 0x28, 0x33, 0x3a,
|
||||
0xdd, 0xd4, 0xcf, 0xc6, 0xf9, 0xf0, 0xeb, 0xe2, 0x95, 0x9c, 0x87, 0x8e, 0xb1, 0xb8, 0xa3, 0xaa,
|
||||
0xec, 0xe5, 0xfe, 0xf7, 0xc8, 0xc1, 0xda, 0xd3, 0xa4, 0xad, 0xb6, 0xbf, 0x80, 0x89, 0x92, 0x9b,
|
||||
0x7c, 0x75, 0x6e, 0x67, 0x58, 0x51, 0x4a, 0x43, 0x34, 0x3d, 0x26, 0x2f, 0x10, 0x19, 0x02, 0x0b,
|
||||
0xd7, 0xde, 0xc5, 0xcc, 0xf3, 0xfa, 0xe1, 0xe8, 0x9f, 0x96, 0x8d, 0x84, 0xbb, 0xb2, 0xa9, 0xa0,
|
||||
0x47, 0x4e, 0x55, 0x5c, 0x63, 0x6a, 0x71, 0x78, 0x0f, 0x06, 0x1d, 0x14, 0x2b, 0x22, 0x39, 0x30,
|
||||
0x9a, 0x93, 0x88, 0x81, 0xbe, 0xb7, 0xac, 0xa5, 0xd2, 0xdb, 0xc0, 0xc9, 0xf6, 0xff, 0xe4, 0xed,
|
||||
0x0a, 0x03, 0x18, 0x11, 0x2e, 0x27, 0x3c, 0x35, 0x42, 0x4b, 0x50, 0x59, 0x66, 0x6f, 0x74, 0x7d,
|
||||
0xa1, 0xa8, 0xb3, 0xba, 0x85, 0x8c, 0x97, 0x9e, 0xe9, 0xe0, 0xfb, 0xf2, 0xcd, 0xc4, 0xdf, 0xd6,
|
||||
0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e, 0x79, 0x70, 0x6b, 0x62, 0x5d, 0x54, 0x4f, 0x46,
|
||||
// a = 0x0d
|
||||
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,
|
||||
0xbb, 0xb6, 0xa1, 0xac, 0x8f, 0x82, 0x95, 0x98, 0xd3, 0xde, 0xc9, 0xc4, 0xe7, 0xea, 0xfd, 0xf0,
|
||||
0x6b, 0x66, 0x71, 0x7c, 0x5f, 0x52, 0x45, 0x48, 0x03, 0x0e, 0x19, 0x14, 0x37, 0x3a, 0x2d, 0x20,
|
||||
0x6d, 0x60, 0x77, 0x7a, 0x59, 0x54, 0x43, 0x4e, 0x05, 0x08, 0x1f, 0x12, 0x31, 0x3c, 0x2b, 0x26,
|
||||
0xbd, 0xb0, 0xa7, 0xaa, 0x89, 0x84, 0x93, 0x9e, 0xd5, 0xd8, 0xcf, 0xc2, 0xe1, 0xec, 0xfb, 0xf6,
|
||||
0xd6, 0xdb, 0xcc, 0xc1, 0xe2, 0xef, 0xf8, 0xf5, 0xbe, 0xb3, 0xa4, 0xa9, 0x8a, 0x87, 0x90, 0x9d,
|
||||
0x06, 0x0b, 0x1c, 0x11, 0x32, 0x3f, 0x28, 0x25, 0x6e, 0x63, 0x74, 0x79, 0x5a, 0x57, 0x40, 0x4d,
|
||||
0xda, 0xd7, 0xc0, 0xcd, 0xee, 0xe3, 0xf4, 0xf9, 0xb2, 0xbf, 0xa8, 0xa5, 0x86, 0x8b, 0x9c, 0x91,
|
||||
0x0a, 0x07, 0x10, 0x1d, 0x3e, 0x33, 0x24, 0x29, 0x62, 0x6f, 0x78, 0x75, 0x56, 0x5b, 0x4c, 0x41,
|
||||
0x61, 0x6c, 0x7b, 0x76, 0x55, 0x58, 0x4f, 0x42, 0x09, 0x04, 0x13, 0x1e, 0x3d, 0x30, 0x27, 0x2a,
|
||||
0xb1, 0xbc, 0xab, 0xa6, 0x85, 0x88, 0x9f, 0x92, 0xd9, 0xd4, 0xc3, 0xce, 0xed, 0xe0, 0xf7, 0xfa,
|
||||
0xb7, 0xba, 0xad, 0xa0, 0x83, 0x8e, 0x99, 0x94, 0xdf, 0xd2, 0xc5, 0xc8, 0xeb, 0xe6, 0xf1, 0xfc,
|
||||
0x67, 0x6a, 0x7d, 0x70, 0x53, 0x5e, 0x49, 0x44, 0x0f, 0x02, 0x15, 0x18, 0x3b, 0x36, 0x21, 0x2c,
|
||||
0x0c, 0x01, 0x16, 0x1b, 0x38, 0x35, 0x22, 0x2f, 0x64, 0x69, 0x7e, 0x73, 0x50, 0x5d, 0x4a, 0x47,
|
||||
0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff, 0xb4, 0xb9, 0xae, 0xa3, 0x80, 0x8d, 0x9a, 0x97,
|
||||
// a = 0x0b
|
||||
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,
|
||||
0x7b, 0x70, 0x6d, 0x66, 0x57, 0x5c, 0x41, 0x4a, 0x23, 0x28, 0x35, 0x3e, 0x0f, 0x04, 0x19, 0x12,
|
||||
0xcb, 0xc0, 0xdd, 0xd6, 0xe7, 0xec, 0xf1, 0xfa, 0x93, 0x98, 0x85, 0x8e, 0xbf, 0xb4, 0xa9, 0xa2,
|
||||
0xf6, 0xfd, 0xe0, 0xeb, 0xda, 0xd1, 0xcc, 0xc7, 0xae, 0xa5, 0xb8, 0xb3, 0x82, 0x89, 0x94, 0x9f,
|
||||
0x46, 0x4d, 0x50, 0x5b, 0x6a, 0x61, 0x7c, 0x77, 0x1e, 0x15, 0x08, 0x03, 0x32, 0x39, 0x24, 0x2f,
|
||||
0x8d, 0x86, 0x9b, 0x90, 0xa1, 0xaa, 0xb7, 0xbc, 0xd5, 0xde, 0xc3, 0xc8, 0xf9, 0xf2, 0xef, 0xe4,
|
||||
0x3d, 0x36, 0x2b, 0x20, 0x11, 0x1a, 0x07, 0x0c, 0x65, 0x6e, 0x73, 0x78, 0x49, 0x42, 0x5f, 0x54,
|
||||
0xf7, 0xfc, 0xe1, 0xea, 0xdb, 0xd0, 0xcd, 0xc6, 0xaf, 0xa4, 0xb9, 0xb2, 0x83, 0x88, 0x95, 0x9e,
|
||||
0x47, 0x4c, 0x51, 0x5a, 0x6b, 0x60, 0x7d, 0x76, 0x1f, 0x14, 0x09, 0x02, 0x33, 0x38, 0x25, 0x2e,
|
||||
0x8c, 0x87, 0x9a, 0x91, 0xa0, 0xab, 0xb6, 0xbd, 0xd4, 0xdf, 0xc2, 0xc9, 0xf8, 0xf3, 0xee, 0xe5,
|
||||
0x3c, 0x37, 0x2a, 0x21, 0x10, 0x1b, 0x06, 0x0d, 0x64, 0x6f, 0x72, 0x79, 0x48, 0x43, 0x5e, 0x55,
|
||||
0x01, 0x0a, 0x17, 0x1c, 0x2d, 0x26, 0x3b, 0x30, 0x59, 0x52, 0x4f, 0x44, 0x75, 0x7e, 0x63, 0x68,
|
||||
0xb1, 0xba, 0xa7, 0xac, 0x9d, 0x96, 0x8b, 0x80, 0xe9, 0xe2, 0xff, 0xf4, 0xc5, 0xce, 0xd3, 0xd8,
|
||||
0x7a, 0x71, 0x6c, 0x67, 0x56, 0x5d, 0x40, 0x4b, 0x22, 0x29, 0x34, 0x3f, 0x0e, 0x05, 0x18, 0x13,
|
||||
0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb, 0x92, 0x99, 0x84, 0x8f, 0xbe, 0xb5, 0xa8, 0xa3,
|
||||
};
|
||||
const uint8_t ff_mult3[4][256] = {
|
||||
// a = 0x02
|
||||
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,
|
||||
0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e,
|
||||
0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e,
|
||||
0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e,
|
||||
0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe,
|
||||
0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde,
|
||||
0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe,
|
||||
0x1b, 0x19, 0x1f, 0x1d, 0x13, 0x11, 0x17, 0x15, 0x0b, 0x09, 0x0f, 0x0d, 0x03, 0x01, 0x07, 0x05,
|
||||
0x3b, 0x39, 0x3f, 0x3d, 0x33, 0x31, 0x37, 0x35, 0x2b, 0x29, 0x2f, 0x2d, 0x23, 0x21, 0x27, 0x25,
|
||||
0x5b, 0x59, 0x5f, 0x5d, 0x53, 0x51, 0x57, 0x55, 0x4b, 0x49, 0x4f, 0x4d, 0x43, 0x41, 0x47, 0x45,
|
||||
0x7b, 0x79, 0x7f, 0x7d, 0x73, 0x71, 0x77, 0x75, 0x6b, 0x69, 0x6f, 0x6d, 0x63, 0x61, 0x67, 0x65,
|
||||
0x9b, 0x99, 0x9f, 0x9d, 0x93, 0x91, 0x97, 0x95, 0x8b, 0x89, 0x8f, 0x8d, 0x83, 0x81, 0x87, 0x85,
|
||||
0xbb, 0xb9, 0xbf, 0xbd, 0xb3, 0xb1, 0xb7, 0xb5, 0xab, 0xa9, 0xaf, 0xad, 0xa3, 0xa1, 0xa7, 0xa5,
|
||||
0xdb, 0xd9, 0xdf, 0xdd, 0xd3, 0xd1, 0xd7, 0xd5, 0xcb, 0xc9, 0xcf, 0xcd, 0xc3, 0xc1, 0xc7, 0xc5,
|
||||
0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5,
|
||||
// a = 0x01
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
|
||||
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
|
||||
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
|
||||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
|
||||
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
|
||||
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
|
||||
0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
|
||||
0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
|
||||
0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
|
||||
0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
|
||||
0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
|
||||
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
|
||||
// a = 0x01
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
|
||||
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
|
||||
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
|
||||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
|
||||
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
|
||||
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
|
||||
0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
|
||||
0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
|
||||
0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
|
||||
0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
|
||||
0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
|
||||
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
|
||||
// a = 0x03
|
||||
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,
|
||||
0x60, 0x63, 0x66, 0x65, 0x6c, 0x6f, 0x6a, 0x69, 0x78, 0x7b, 0x7e, 0x7d, 0x74, 0x77, 0x72, 0x71,
|
||||
0x50, 0x53, 0x56, 0x55, 0x5c, 0x5f, 0x5a, 0x59, 0x48, 0x4b, 0x4e, 0x4d, 0x44, 0x47, 0x42, 0x41,
|
||||
0xc0, 0xc3, 0xc6, 0xc5, 0xcc, 0xcf, 0xca, 0xc9, 0xd8, 0xdb, 0xde, 0xdd, 0xd4, 0xd7, 0xd2, 0xd1,
|
||||
0xf0, 0xf3, 0xf6, 0xf5, 0xfc, 0xff, 0xfa, 0xf9, 0xe8, 0xeb, 0xee, 0xed, 0xe4, 0xe7, 0xe2, 0xe1,
|
||||
0xa0, 0xa3, 0xa6, 0xa5, 0xac, 0xaf, 0xaa, 0xa9, 0xb8, 0xbb, 0xbe, 0xbd, 0xb4, 0xb7, 0xb2, 0xb1,
|
||||
0x90, 0x93, 0x96, 0x95, 0x9c, 0x9f, 0x9a, 0x99, 0x88, 0x8b, 0x8e, 0x8d, 0x84, 0x87, 0x82, 0x81,
|
||||
0x9b, 0x98, 0x9d, 0x9e, 0x97, 0x94, 0x91, 0x92, 0x83, 0x80, 0x85, 0x86, 0x8f, 0x8c, 0x89, 0x8a,
|
||||
0xab, 0xa8, 0xad, 0xae, 0xa7, 0xa4, 0xa1, 0xa2, 0xb3, 0xb0, 0xb5, 0xb6, 0xbf, 0xbc, 0xb9, 0xba,
|
||||
0xfb, 0xf8, 0xfd, 0xfe, 0xf7, 0xf4, 0xf1, 0xf2, 0xe3, 0xe0, 0xe5, 0xe6, 0xef, 0xec, 0xe9, 0xea,
|
||||
0xcb, 0xc8, 0xcd, 0xce, 0xc7, 0xc4, 0xc1, 0xc2, 0xd3, 0xd0, 0xd5, 0xd6, 0xdf, 0xdc, 0xd9, 0xda,
|
||||
0x5b, 0x58, 0x5d, 0x5e, 0x57, 0x54, 0x51, 0x52, 0x43, 0x40, 0x45, 0x46, 0x4f, 0x4c, 0x49, 0x4a,
|
||||
0x6b, 0x68, 0x6d, 0x6e, 0x67, 0x64, 0x61, 0x62, 0x73, 0x70, 0x75, 0x76, 0x7f, 0x7c, 0x79, 0x7a,
|
||||
0x3b, 0x38, 0x3d, 0x3e, 0x37, 0x34, 0x31, 0x32, 0x23, 0x20, 0x25, 0x26, 0x2f, 0x2c, 0x29, 0x2a,
|
||||
0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, 0x1f, 0x1c, 0x19, 0x1a,
|
||||
};
|
||||
|
||||
static uint8_t ff_mult(uint8_t a, uint8_t b)
|
||||
{
|
||||
int retval = 0;
|
||||
@@ -320,10 +470,15 @@ void native_aesimc(x64emu_t* emu, int xmm)
|
||||
sse_regs_t eax1 = emu->xmm[xmm];
|
||||
|
||||
for(int j=0; j<4; ++j) {
|
||||
emu->xmm[xmm].ub[0+j*4] = ff_mult(0x0E, eax1.ub[0+j*4]) ^ ff_mult(0x0B, eax1.ub[1+j*4]) ^ ff_mult(0x0D, eax1.ub[2+j*4]) ^ ff_mult(0x09, eax1.ub[3+j*4]);
|
||||
emu->xmm[xmm].ub[1+j*4] = ff_mult(0x09, eax1.ub[0+j*4]) ^ ff_mult(0x0E, eax1.ub[1+j*4]) ^ ff_mult(0x0B, eax1.ub[2+j*4]) ^ ff_mult(0x0D, eax1.ub[3+j*4]);
|
||||
emu->xmm[xmm].ub[2+j*4] = ff_mult(0x0D, eax1.ub[0+j*4]) ^ ff_mult(0x09, eax1.ub[1+j*4]) ^ ff_mult(0x0E, eax1.ub[2+j*4]) ^ ff_mult(0x0B, eax1.ub[3+j*4]);
|
||||
emu->xmm[xmm].ub[3+j*4] = ff_mult(0x0B, eax1.ub[0+j*4]) ^ ff_mult(0x0D, eax1.ub[1+j*4]) ^ ff_mult(0x09, eax1.ub[2+j*4]) ^ ff_mult(0x0E, eax1.ub[3+j*4]);
|
||||
// 0x0E -> 0, 0x09 -> 1, 0x0D -> 2, 0x0B -> 3
|
||||
// emu->xmm[xmm].ub[0+j*4] = ff_mult(0x0E, eax1.ub[0+j*4]) ^ ff_mult(0x0B, eax1.ub[1+j*4]) ^ ff_mult(0x0D, eax1.ub[2+j*4]) ^ ff_mult(0x09, eax1.ub[3+j*4]);
|
||||
// emu->xmm[xmm].ub[1+j*4] = ff_mult(0x09, eax1.ub[0+j*4]) ^ ff_mult(0x0E, eax1.ub[1+j*4]) ^ ff_mult(0x0B, eax1.ub[2+j*4]) ^ ff_mult(0x0D, eax1.ub[3+j*4]);
|
||||
// emu->xmm[xmm].ub[2+j*4] = ff_mult(0x0D, eax1.ub[0+j*4]) ^ ff_mult(0x09, eax1.ub[1+j*4]) ^ ff_mult(0x0E, eax1.ub[2+j*4]) ^ ff_mult(0x0B, eax1.ub[3+j*4]);
|
||||
// emu->xmm[xmm].ub[3+j*4] = ff_mult(0x0B, eax1.ub[0+j*4]) ^ ff_mult(0x0D, eax1.ub[1+j*4]) ^ ff_mult(0x09, eax1.ub[2+j*4]) ^ ff_mult(0x0E, eax1.ub[3+j*4]);
|
||||
emu->xmm[xmm].ub[0+j*4] = ff_mult2[0][eax1.ub[0+j*4]] ^ ff_mult2[3][eax1.ub[1+j*4]] ^ ff_mult2[2][eax1.ub[2+j*4]] ^ ff_mult2[1][eax1.ub[3+j*4]];
|
||||
emu->xmm[xmm].ub[1+j*4] = ff_mult2[1][eax1.ub[0+j*4]] ^ ff_mult2[0][eax1.ub[1+j*4]] ^ ff_mult2[3][eax1.ub[2+j*4]] ^ ff_mult2[2][eax1.ub[3+j*4]];
|
||||
emu->xmm[xmm].ub[2+j*4] = ff_mult2[2][eax1.ub[0+j*4]] ^ ff_mult2[1][eax1.ub[1+j*4]] ^ ff_mult2[0][eax1.ub[2+j*4]] ^ ff_mult2[3][eax1.ub[3+j*4]];
|
||||
emu->xmm[xmm].ub[3+j*4] = ff_mult2[3][eax1.ub[0+j*4]] ^ ff_mult2[2][eax1.ub[1+j*4]] ^ ff_mult2[1][eax1.ub[2+j*4]] ^ ff_mult2[0][eax1.ub[3+j*4]];
|
||||
}
|
||||
}
|
||||
void native_aesimc_y(x64emu_t* emu, int ymm)
|
||||
@@ -331,10 +486,14 @@ void native_aesimc_y(x64emu_t* emu, int ymm)
|
||||
sse_regs_t eay1 = emu->ymm[ymm];
|
||||
|
||||
for(int j=0; j<4; ++j) {
|
||||
emu->ymm[ymm].ub[0+j*4] = ff_mult(0x0E, eay1.ub[0+j*4]) ^ ff_mult(0x0B, eay1.ub[1+j*4]) ^ ff_mult(0x0D, eay1.ub[2+j*4]) ^ ff_mult(0x09, eay1.ub[3+j*4]);
|
||||
emu->ymm[ymm].ub[1+j*4] = ff_mult(0x09, eay1.ub[0+j*4]) ^ ff_mult(0x0E, eay1.ub[1+j*4]) ^ ff_mult(0x0B, eay1.ub[2+j*4]) ^ ff_mult(0x0D, eay1.ub[3+j*4]);
|
||||
emu->ymm[ymm].ub[2+j*4] = ff_mult(0x0D, eay1.ub[0+j*4]) ^ ff_mult(0x09, eay1.ub[1+j*4]) ^ ff_mult(0x0E, eay1.ub[2+j*4]) ^ ff_mult(0x0B, eay1.ub[3+j*4]);
|
||||
emu->ymm[ymm].ub[3+j*4] = ff_mult(0x0B, eay1.ub[0+j*4]) ^ ff_mult(0x0D, eay1.ub[1+j*4]) ^ ff_mult(0x09, eay1.ub[2+j*4]) ^ ff_mult(0x0E, eay1.ub[3+j*4]);
|
||||
// emu->ymm[ymm].ub[0+j*4] = ff_mult(0x0E, eay1.ub[0+j*4]) ^ ff_mult(0x0B, eay1.ub[1+j*4]) ^ ff_mult(0x0D, eay1.ub[2+j*4]) ^ ff_mult(0x09, eay1.ub[3+j*4]);
|
||||
// emu->ymm[ymm].ub[1+j*4] = ff_mult(0x09, eay1.ub[0+j*4]) ^ ff_mult(0x0E, eay1.ub[1+j*4]) ^ ff_mult(0x0B, eay1.ub[2+j*4]) ^ ff_mult(0x0D, eay1.ub[3+j*4]);
|
||||
// emu->ymm[ymm].ub[2+j*4] = ff_mult(0x0D, eay1.ub[0+j*4]) ^ ff_mult(0x09, eay1.ub[1+j*4]) ^ ff_mult(0x0E, eay1.ub[2+j*4]) ^ ff_mult(0x0B, eay1.ub[3+j*4]);
|
||||
// emu->ymm[ymm].ub[3+j*4] = ff_mult(0x0B, eay1.ub[0+j*4]) ^ ff_mult(0x0D, eay1.ub[1+j*4]) ^ ff_mult(0x09, eay1.ub[2+j*4]) ^ ff_mult(0x0E, eay1.ub[3+j*4]);
|
||||
emu->ymm[ymm].ub[0+j*4] = ff_mult2[0][eay1.ub[0+j*4]] ^ ff_mult2[3][eay1.ub[1+j*4]] ^ ff_mult2[2][eay1.ub[2+j*4]] ^ ff_mult2[1][eay1.ub[3+j*4]];
|
||||
emu->ymm[ymm].ub[1+j*4] = ff_mult2[1][eay1.ub[0+j*4]] ^ ff_mult2[0][eay1.ub[1+j*4]] ^ ff_mult2[3][eay1.ub[2+j*4]] ^ ff_mult2[2][eay1.ub[3+j*4]];
|
||||
emu->ymm[ymm].ub[2+j*4] = ff_mult2[2][eay1.ub[0+j*4]] ^ ff_mult2[1][eay1.ub[1+j*4]] ^ ff_mult2[0][eay1.ub[2+j*4]] ^ ff_mult2[3][eay1.ub[3+j*4]];
|
||||
emu->ymm[ymm].ub[3+j*4] = ff_mult2[3][eay1.ub[0+j*4]] ^ ff_mult2[2][eay1.ub[1+j*4]] ^ ff_mult2[1][eay1.ub[2+j*4]] ^ ff_mult2[0][eay1.ub[3+j*4]];
|
||||
}
|
||||
}
|
||||
void native_aesmc(x64emu_t* emu, int xmm)
|
||||
@@ -342,10 +501,15 @@ void native_aesmc(x64emu_t* emu, int xmm)
|
||||
sse_regs_t eax1 = emu->xmm[xmm];
|
||||
|
||||
for(int j=0; j<4; ++j) {
|
||||
emu->xmm[xmm].ub[0+j*4] = ff_mult(0x02, eax1.ub[0+j*4]) ^ ff_mult(0x03, eax1.ub[1+j*4]) ^ eax1.ub[2+j*4] ^ eax1.ub[3+j*4] ;
|
||||
emu->xmm[xmm].ub[1+j*4] = eax1.ub[0+j*4] ^ ff_mult(0x02, eax1.ub[1+j*4]) ^ ff_mult(0x03, eax1.ub[2+j*4]) ^ eax1.ub[3+j*4] ;
|
||||
emu->xmm[xmm].ub[2+j*4] = eax1.ub[0+j*4] ^ eax1.ub[1+j*4] ^ ff_mult(0x02, eax1.ub[2+j*4]) ^ ff_mult(0x03, eax1.ub[3+j*4]);
|
||||
emu->xmm[xmm].ub[3+j*4] = ff_mult(0x03, eax1.ub[0+j*4]) ^ eax1.ub[1+j*4] ^ eax1.ub[2+j*4] ^ ff_mult(0x02, eax1.ub[3+j*4]);
|
||||
// 0x02 -> 0, 0x01 -> 1, 0x01 -> 2, 0x03 -> 3
|
||||
// emu->xmm[xmm].ub[0+j*4] = ff_mult(0x02, eax1.ub[0+j*4]) ^ ff_mult(0x03, eax1.ub[1+j*4]) ^ eax1.ub[2+j*4] ^ eax1.ub[3+j*4] ;
|
||||
// emu->xmm[xmm].ub[1+j*4] = eax1.ub[0+j*4] ^ ff_mult(0x02, eax1.ub[1+j*4]) ^ ff_mult(0x03, eax1.ub[2+j*4]) ^ eax1.ub[3+j*4] ;
|
||||
// emu->xmm[xmm].ub[2+j*4] = eax1.ub[0+j*4] ^ eax1.ub[1+j*4] ^ ff_mult(0x02, eax1.ub[2+j*4]) ^ ff_mult(0x03, eax1.ub[3+j*4]);
|
||||
// emu->xmm[xmm].ub[3+j*4] = ff_mult(0x03, eax1.ub[0+j*4]) ^ eax1.ub[1+j*4] ^ eax1.ub[2+j*4] ^ ff_mult(0x02, eax1.ub[3+j*4]);
|
||||
emu->xmm[xmm].ub[0+j*4] = ff_mult3[0][eax1.ub[0+j*4]] ^ ff_mult3[3][eax1.ub[1+j*4]] ^ ff_mult3[2][eax1.ub[2+j*4]] ^ ff_mult3[1][eax1.ub[3+j*4]];
|
||||
emu->xmm[xmm].ub[1+j*4] = ff_mult3[1][eax1.ub[0+j*4]] ^ ff_mult3[0][eax1.ub[1+j*4]] ^ ff_mult3[3][eax1.ub[2+j*4]] ^ ff_mult3[2][eax1.ub[3+j*4]];
|
||||
emu->xmm[xmm].ub[2+j*4] = ff_mult3[2][eax1.ub[0+j*4]] ^ ff_mult3[1][eax1.ub[1+j*4]] ^ ff_mult3[0][eax1.ub[2+j*4]] ^ ff_mult3[3][eax1.ub[3+j*4]];
|
||||
emu->xmm[xmm].ub[3+j*4] = ff_mult3[3][eax1.ub[0+j*4]] ^ ff_mult3[2][eax1.ub[1+j*4]] ^ ff_mult3[1][eax1.ub[2+j*4]] ^ ff_mult3[0][eax1.ub[3+j*4]];
|
||||
}
|
||||
}
|
||||
void native_aesmc_y(x64emu_t* emu, int ymm)
|
||||
@@ -353,16 +517,20 @@ void native_aesmc_y(x64emu_t* emu, int ymm)
|
||||
sse_regs_t eay1 = emu->ymm[ymm];
|
||||
|
||||
for(int j=0; j<4; ++j) {
|
||||
emu->ymm[ymm].ub[0+j*4] = ff_mult(0x02, eay1.ub[0+j*4]) ^ ff_mult(0x03, eay1.ub[1+j*4]) ^ eay1.ub[2+j*4] ^ eay1.ub[3+j*4] ;
|
||||
emu->ymm[ymm].ub[1+j*4] = eay1.ub[0+j*4] ^ ff_mult(0x02, eay1.ub[1+j*4]) ^ ff_mult(0x03, eay1.ub[2+j*4]) ^ eay1.ub[3+j*4] ;
|
||||
emu->ymm[ymm].ub[2+j*4] = eay1.ub[0+j*4] ^ eay1.ub[1+j*4] ^ ff_mult(0x02, eay1.ub[2+j*4]) ^ ff_mult(0x03, eay1.ub[3+j*4]);
|
||||
emu->ymm[ymm].ub[3+j*4] = ff_mult(0x03, eay1.ub[0+j*4]) ^ eay1.ub[1+j*4] ^ eay1.ub[2+j*4] ^ ff_mult(0x02, eay1.ub[3+j*4]);
|
||||
// emu->ymm[ymm].ub[0+j*4] = ff_mult(0x02, eay1.ub[0+j*4]) ^ ff_mult(0x03, eay1.ub[1+j*4]) ^ eay1.ub[2+j*4] ^ eay1.ub[3+j*4] ;
|
||||
// emu->ymm[ymm].ub[1+j*4] = eay1.ub[0+j*4] ^ ff_mult(0x02, eay1.ub[1+j*4]) ^ ff_mult(0x03, eay1.ub[2+j*4]) ^ eay1.ub[3+j*4] ;
|
||||
// emu->ymm[ymm].ub[2+j*4] = eay1.ub[0+j*4] ^ eay1.ub[1+j*4] ^ ff_mult(0x02, eay1.ub[2+j*4]) ^ ff_mult(0x03, eay1.ub[3+j*4]);
|
||||
// emu->ymm[ymm].ub[3+j*4] = ff_mult(0x03, eay1.ub[0+j*4]) ^ eay1.ub[1+j*4] ^ eay1.ub[2+j*4] ^ ff_mult(0x02, eay1.ub[3+j*4]);
|
||||
emu->ymm[ymm].ub[0+j*4] = ff_mult3[0][eay1.ub[0+j*4]] ^ ff_mult3[3][eay1.ub[1+j*4]] ^ ff_mult3[2][eay1.ub[2+j*4]] ^ ff_mult3[1][eay1.ub[3+j*4]];
|
||||
emu->ymm[ymm].ub[1+j*4] = ff_mult3[1][eay1.ub[0+j*4]] ^ ff_mult3[0][eay1.ub[1+j*4]] ^ ff_mult3[3][eay1.ub[2+j*4]] ^ ff_mult3[2][eay1.ub[3+j*4]];
|
||||
emu->ymm[ymm].ub[2+j*4] = ff_mult3[2][eay1.ub[0+j*4]] ^ ff_mult3[1][eay1.ub[1+j*4]] ^ ff_mult3[0][eay1.ub[2+j*4]] ^ ff_mult3[3][eay1.ub[3+j*4]];
|
||||
emu->ymm[ymm].ub[3+j*4] = ff_mult3[3][eay1.ub[0+j*4]] ^ ff_mult3[2][eay1.ub[1+j*4]] ^ ff_mult3[1][eay1.ub[2+j*4]] ^ ff_mult3[0][eay1.ub[3+j*4]];
|
||||
}
|
||||
}
|
||||
// A0 B1 C2 D3 E4 F5 G6 H7 I8 J9 Ka Lb Mc Nd Oe Pf
|
||||
// A N K H E B O L I F C P M J G D
|
||||
static const uint8_t invshiftrows[] = {0,13,10, 7, 4, 1,14,11, 8, 5, 2,15,12, 9, 6, 3};
|
||||
static const uint8_t invsubbytes[256] = {
|
||||
const uint8_t invshiftrows[] = {0,13,10, 7, 4, 1,14,11, 8, 5, 2,15,12, 9, 6, 3};
|
||||
const uint8_t invsubbytes[256] = {
|
||||
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,
|
||||
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
|
||||
@@ -402,8 +570,8 @@ void native_aesdlast_y(x64emu_t* emu, int ymm)
|
||||
emu->ymm[ymm].ub[i] = invsubbytes[eay1.ub[i]];
|
||||
|
||||
}
|
||||
static const uint8_t shiftrows[] = {0, 5,10,15, 4, 9,14, 3, 8,13, 2, 7,12, 1, 6,11};
|
||||
static const uint8_t subbytes[256] = {
|
||||
const uint8_t shiftrows[] = {0, 5,10,15, 4, 9,14, 3, 8,13, 2, 7,12, 1, 6,11};
|
||||
const uint8_t subbytes[256] = {
|
||||
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,
|
||||
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
|
||||
@@ -617,34 +785,6 @@ uint8_t geted_ib(dynarec_native_t* dyn, uintptr_t addr, int ninst, uint8_t nexto
|
||||
}
|
||||
#undef F8
|
||||
|
||||
// AVX
|
||||
void avx_mark_zero(dynarec_native_t* dyn, int ninst, int reg)
|
||||
{
|
||||
dyn->ymm_zero |= (1<<reg);
|
||||
}
|
||||
|
||||
int is_avx_zero(dynarec_native_t* dyn, int ninst, int reg)
|
||||
{
|
||||
return (dyn->ymm_zero>>reg)&1;
|
||||
}
|
||||
int is_avx_zero_unset(dynarec_native_t* dyn, int ninst, int reg)
|
||||
{
|
||||
if((dyn->ymm_zero>>reg)&1) {
|
||||
dyn->ymm_zero &= ~(1<<reg);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
void avx_mark_zero_reset(dynarec_native_t* dyn, int ninst)
|
||||
{
|
||||
dyn->ymm_zero = 0;
|
||||
}
|
||||
|
||||
void avx_unmark_zero(dynarec_native_t* dyn, int ninst, int reg)
|
||||
{
|
||||
dyn->ymm_zero &= ~(1<<reg);
|
||||
}
|
||||
|
||||
void propagate_nodf(dynarec_native_t* dyn, int ninst)
|
||||
{
|
||||
while(ninst>=0) {
|
||||
|
||||
@@ -55,6 +55,7 @@ void native_clflush(x64emu_t* emu, void* p);
|
||||
void native_ud(x64emu_t* emu);
|
||||
void native_br(x64emu_t* emu);
|
||||
void native_priv(x64emu_t* emu);
|
||||
void native_gpf(x64emu_t* emu);
|
||||
void native_int3(x64emu_t* emu);
|
||||
void native_int(x64emu_t* emu, int num);
|
||||
void native_wineint(x64emu_t* emu, int num);
|
||||
@@ -74,13 +75,6 @@ uintptr_t fakeed(dynarec_native_t* dyn, uintptr_t addr, int ninst, uint8_t nexto
|
||||
// return Ib on a mod/rm opcode without emitting anything
|
||||
uint8_t geted_ib(dynarec_native_t* dyn, uintptr_t addr, int ninst, uint8_t nextop);
|
||||
|
||||
// AVX utilities
|
||||
void avx_mark_zero(dynarec_native_t* dyn, int ninst, int reg);
|
||||
int is_avx_zero(dynarec_native_t* dyn, int ninst, int reg);
|
||||
int is_avx_zero_unset(dynarec_native_t* dyn, int ninst, int reg);
|
||||
void avx_mark_zero_reset(dynarec_native_t* dyn, int ninst);
|
||||
void avx_unmark_zero(dynarec_native_t* dyn, int ninst, int reg);
|
||||
|
||||
typedef struct register_mapping_s {
|
||||
const char* name;
|
||||
const char* native;
|
||||
|
||||
@@ -69,7 +69,8 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
if(cur_page != ((addr)&~(box64_pagesize-1))) {
|
||||
cur_page = (addr)&~(box64_pagesize-1);
|
||||
uint32_t prot = getProtection(addr);
|
||||
if(!(prot&PROT_READ) || checkInHotPage(addr)) {
|
||||
if(!(prot&PROT_READ) || checkInHotPage(addr) || (addr>dyn->end)) {
|
||||
dynarec_log(LOG_INFO, "Stopping dynablock because of protection, hotpage or mmap crossing at %p -> %p inst=%d\n", (void*)dyn->start, (void*)addr, ninst);
|
||||
need_epilog = 1;
|
||||
break;
|
||||
}
|
||||
@@ -116,7 +117,6 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
else if(ninst && (dyn->insts[ninst].pred_sz>1 || (dyn->insts[ninst].pred_sz==1 && dyn->insts[ninst].pred[0]!=ninst-1)))
|
||||
dyn->last_ip = 0; // reset IP if some jump are coming here
|
||||
#endif
|
||||
dyn->f.dfnone_here = 0;
|
||||
NEW_INST;
|
||||
MESSAGE(LOG_DUMP, "New Instruction %s:%p, native:%p\n", is32bits?"x86":"x64",(void*)addr, (void*)dyn->block);
|
||||
#ifdef ARCH_NOP
|
||||
@@ -134,8 +134,8 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
WILLWRITE();
|
||||
}
|
||||
|
||||
int is_opcode_volatile = box64_wine && VolatileRangesContains(ip);
|
||||
if (is_opcode_volatile && !dyn->insts[ninst].lock_prefixed && dyn->insts[ninst].will_write)
|
||||
int is_opcode_volatile = /*box64_wine &&*/ VolatileRangesContains(ip) && VolatileOpcodesHas(ip);
|
||||
if (is_opcode_volatile && !dyn->insts[ninst].lock)
|
||||
DMB_ISHST();
|
||||
#endif
|
||||
if((dyn->insts[ninst].x64.need_before&~X_PEND) && !ninst) {
|
||||
@@ -168,11 +168,16 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
#endif
|
||||
|
||||
rep = 0;
|
||||
rex.is32bits = is32bits;
|
||||
uint8_t pk = PK(0);
|
||||
while((pk==0xF2) || (pk==0xF3) || (pk==0x3E) || (pk==0x26)) {
|
||||
while((pk==0xF2) || (pk==0xF3) || (pk==0x3E) || (pk==0x26)
|
||||
|| (is32bits && ((pk==0x2E) || (pk==0x36)))
|
||||
) {
|
||||
switch(pk) {
|
||||
case 0xF2: rep = 1; break;
|
||||
case 0xF3: rep = 2; break;
|
||||
case 0x2E:
|
||||
case 0x36:
|
||||
case 0x3E:
|
||||
case 0x26: /* ignored */ break;
|
||||
}
|
||||
@@ -180,7 +185,6 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
pk = PK(0);
|
||||
}
|
||||
rex.rex = 0;
|
||||
rex.is32bits = is32bits;
|
||||
if(!rex.is32bits)
|
||||
while(pk>=0x40 && pk<=0x4f) {
|
||||
rex.rex = pk;
|
||||
@@ -194,8 +198,8 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
INST_EPILOG;
|
||||
|
||||
#if STEP > 1
|
||||
if (is_opcode_volatile && !dyn->insts[ninst].lock_prefixed && dyn->insts[ninst].will_read)
|
||||
DMB_ISHLD();
|
||||
if (is_opcode_volatile || dyn->insts[ninst].lock)
|
||||
DMB_ISH();
|
||||
#endif
|
||||
|
||||
fpu_reset_scratch(dyn);
|
||||
@@ -255,7 +259,7 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
}
|
||||
#else
|
||||
// check if block need to be stopped, because it's a 00 00 opcode (unreadeable is already checked earlier)
|
||||
if((ok>0) && !dyn->forward && !(*(uint32_t*)addr)) {
|
||||
if((ok>0) && !dyn->forward && (!(getProtection(addr)&PROT_READ) || !(*(uint32_t*)addr))) {
|
||||
if (dyn->need_dump) dynarec_log(LOG_NONE, "Stopping block at %p reason: %s\n", (void*)addr, "Next opcode is 00 00 00 00");
|
||||
ok = 0;
|
||||
need_epilog = 1;
|
||||
@@ -299,7 +303,7 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
} else {
|
||||
// need to find back that instruction to copy the caches, as previous version cannot be used anymore
|
||||
// and pred table is not ready yet
|
||||
reset_n = get_first_jump(dyn, next);
|
||||
reset_n = get_first_jump_addr(dyn, next);
|
||||
}
|
||||
if (dyn->need_dump) dynarec_log(LOG_NONE, "Extend block %p, %s%p -> %p (ninst=%d, jump from %d)\n", dyn, dyn->insts[ninst].x64.has_callret ? "(opt. call) " : "", (void*)addr, (void*)next, ninst + 1, dyn->insts[ninst].x64.has_callret ? ninst : reset_n);
|
||||
} else if (next && (int)(next - addr) < BOX64ENV(dynarec_forward) && (getProtection(next) & PROT_READ) /*BOX64DRENV(dynarec_bigblock)>=stopblock*/) {
|
||||
@@ -346,8 +350,7 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
}
|
||||
if((ok>0) && dyn->insts[ninst].x64.has_callret)
|
||||
reset_n = -2;
|
||||
if((ok>0) && reset_n==-1 && dyn->insts[ninst+1].purge_ymm)
|
||||
PURGE_YMM();
|
||||
PURGE_YMM();
|
||||
++ninst;
|
||||
#if STEP == 0
|
||||
memset(&dyn->insts[ninst], 0, sizeof(instruction_native_t));
|
||||
|
||||
@@ -12,16 +12,20 @@ void arm64_epilog(void) EXPORTDYN;
|
||||
void la64_next(void) EXPORTDYN;
|
||||
void la64_prolog(x64emu_t* emu, void* addr) EXPORTDYN;
|
||||
void la64_epilog(void) EXPORTDYN;
|
||||
void la64_epilog_fast(void) EXPORTDYN;
|
||||
#define native_next la64_next
|
||||
#define native_prolog la64_prolog
|
||||
#define native_epilog la64_epilog
|
||||
#define native_epilog_fast la64_epilog_fast
|
||||
#elif defined(RV64)
|
||||
void rv64_next(void) EXPORTDYN;
|
||||
void rv64_prolog(x64emu_t* emu, void* addr) EXPORTDYN;
|
||||
void rv64_epilog(void) EXPORTDYN;
|
||||
void rv64_epilog_fast(void) EXPORTDYN;
|
||||
#define native_next rv64_next
|
||||
#define native_prolog rv64_prolog
|
||||
#define native_epilog rv64_epilog
|
||||
#define native_epilog_fast rv64_epilog_fast
|
||||
#else
|
||||
#error Unsupported architecture
|
||||
#endif
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "x64_signals.h"
|
||||
#include "os.h"
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
@@ -377,6 +377,9 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
i64 = F32S;
|
||||
emit_sub32c(dyn, ninst, rex, xRAX, i64, x2, x3, x4, x5);
|
||||
break;
|
||||
case 0x2E:
|
||||
INST_NAME("CS:");
|
||||
break;
|
||||
case 0x30:
|
||||
INST_NAME("XOR Eb, Gb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
@@ -669,9 +672,9 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION); // Hack to set flags in "don't care" state
|
||||
}
|
||||
GETIP(ip);
|
||||
GETIP(ip, x7);
|
||||
STORE_XEMU_CALL();
|
||||
CALL(native_priv, -1);
|
||||
CALL(const_native_priv, -1, 0, 0);
|
||||
LOAD_XEMU_CALL();
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
*need_epilog = 0;
|
||||
@@ -685,9 +688,9 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION); // Hack to set flags in "don't care" state
|
||||
}
|
||||
GETIP(ip);
|
||||
GETIP(ip, x7);
|
||||
STORE_XEMU_CALL();
|
||||
CALL(native_priv, -1);
|
||||
CALL(const_native_priv, -1, 0, 0);
|
||||
LOAD_XEMU_CALL();
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
*need_epilog = 0;
|
||||
@@ -700,7 +703,7 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
BARRIER(BARRIER_MAYBE); \
|
||||
JUMP(addr + i8, 1); \
|
||||
if (!dyn->insts[ninst].nat_flags_fusion) { \
|
||||
if (la64_lbt) { \
|
||||
if (cpuext.lbt) { \
|
||||
X64_SETJ(tmp1, I); \
|
||||
} else { \
|
||||
GETFLAGS; \
|
||||
@@ -712,7 +715,7 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
if (dyn->insts[ninst].nat_flags_fusion) { \
|
||||
NATIVEJUMP_safe(NATNO, i32); \
|
||||
} else { \
|
||||
if (la64_lbt) \
|
||||
if (cpuext.lbt) \
|
||||
BEQZ_safe(tmp1, i32); \
|
||||
else \
|
||||
B##NO##_safe(tmp1, i32); \
|
||||
@@ -732,7 +735,7 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
if (dyn->insts[ninst].nat_flags_fusion) { \
|
||||
NATIVEJUMP_safe(NATYES, i32); \
|
||||
} else { \
|
||||
if (la64_lbt) \
|
||||
if (cpuext.lbt) \
|
||||
BNEZ_safe(tmp1, i32); \
|
||||
else \
|
||||
B##YES##_safe(tmp1, i32); \
|
||||
@@ -980,11 +983,10 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
GETGB(x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
|
||||
if (la64_lam_bh) {
|
||||
if (cpuext.lam_bh) {
|
||||
AMSWAP_DB_B(x1, gd, ed);
|
||||
BSTRINS_D(gb1, x1, gb2 + 7, gb2);
|
||||
} else {
|
||||
SMDMB();
|
||||
|
||||
// calculate shift amount
|
||||
ANDI(x1, ed, 0x3);
|
||||
@@ -1027,7 +1029,6 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
GETGD;
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
|
||||
SMDMB();
|
||||
ANDI(x3, ed, (1 << (2 + rex.w)) - 1);
|
||||
BNEZ_MARK(x3);
|
||||
MARKLOCK;
|
||||
@@ -1040,7 +1041,6 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
LDxw(x1, ed, 0);
|
||||
SDxw(gd, ed, 0);
|
||||
MARK2;
|
||||
SMDMB();
|
||||
MVxw(gd, x1);
|
||||
}
|
||||
break;
|
||||
@@ -1671,7 +1671,7 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
GETEB(x1, 1);
|
||||
u8 = F8;
|
||||
MOV32w(x2, u8);
|
||||
CALL_(rol8, ed, x3);
|
||||
CALL_(const_rol8, ed, x3, x1, x2);
|
||||
EBBACK();
|
||||
break;
|
||||
case 4:
|
||||
@@ -1868,6 +1868,45 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
break;
|
||||
case 0xC4:
|
||||
nextop = F8;
|
||||
if (rex.is32bits && !(MODREG)) {
|
||||
DEFAULT;
|
||||
} else {
|
||||
vex_t vex = { 0 };
|
||||
vex.rex = rex;
|
||||
u8 = nextop;
|
||||
vex.m = u8 & 0b00011111;
|
||||
vex.rex.b = (u8 & 0b00100000) ? 0 : 1;
|
||||
vex.rex.x = (u8 & 0b01000000) ? 0 : 1;
|
||||
vex.rex.r = (u8 & 0b10000000) ? 0 : 1;
|
||||
u8 = F8;
|
||||
vex.p = u8 & 0b00000011;
|
||||
vex.l = (u8 >> 2) & 1;
|
||||
vex.v = ((~u8) >> 3) & 0b1111;
|
||||
vex.rex.w = (u8 >> 7) & 1;
|
||||
addr = dynarec64_AVX(dyn, addr, ip, ninst, vex, ok, need_epilog);
|
||||
}
|
||||
break;
|
||||
case 0xC5:
|
||||
nextop = F8;
|
||||
if (rex.is32bits && !(MODREG)) {
|
||||
DEFAULT;
|
||||
} else {
|
||||
vex_t vex = { 0 };
|
||||
vex.rex = rex;
|
||||
u8 = nextop;
|
||||
vex.p = u8 & 0b00000011;
|
||||
vex.l = (u8 >> 2) & 1;
|
||||
vex.v = ((~u8) >> 3) & 0b1111;
|
||||
vex.rex.r = (u8 & 0b10000000) ? 0 : 1;
|
||||
vex.rex.b = 0;
|
||||
vex.rex.x = 0;
|
||||
vex.rex.w = 0;
|
||||
vex.m = VEX_M_0F;
|
||||
addr = dynarec64_AVX(dyn, addr, ip, ninst, vex, ok, need_epilog);
|
||||
}
|
||||
break;
|
||||
case 0xC6:
|
||||
INST_NAME("MOV Eb, Ib");
|
||||
nextop = F8;
|
||||
@@ -1940,13 +1979,13 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
|
||||
// FIXME: Even the basic support of isSimpleWrapper is disabled for now.
|
||||
|
||||
GETIP(ip + 1); // read the 0xCC
|
||||
GETIP(ip + 1, x7); // read the 0xCC
|
||||
STORE_XEMU_CALL();
|
||||
ADDI_D(x3, xRIP, 8 + 8 + 2); // expected return address
|
||||
ADDI_D(x1, xEmu, (uint32_t)offsetof(x64emu_t, ip)); // setup addr as &emu->ip
|
||||
CALL_S(EmuInt3, -1);
|
||||
CALL_(const_int3, -1, x3, x1, 0);
|
||||
LOAD_XEMU_CALL();
|
||||
addr += 8 + 8;
|
||||
TABLE64(x3, addr); // expected return address
|
||||
BNE_MARK(xRIP, x3);
|
||||
LD_W(x1, xEmu, offsetof(x64emu_t, quit));
|
||||
CBZ_NEXT(x1);
|
||||
@@ -1957,13 +1996,13 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("INT 3");
|
||||
if (!BOX64ENV(ignoreint3)) {
|
||||
// check if TRAP signal is handled
|
||||
TABLE64(x1, (uintptr_t)my_context);
|
||||
MOV32w(x2, offsetof(box64context_t, signals[SIGTRAP]));
|
||||
TABLE64C(x1, const_context);
|
||||
MOV32w(x2, offsetof(box64context_t, signals[X64_SIGTRAP]));
|
||||
LDX_D(x3, x1, x2);
|
||||
BEQZ_MARK(x3);
|
||||
GETIP(addr);
|
||||
GETIP(addr, x7);
|
||||
STORE_XEMU_CALL();
|
||||
CALL(native_int3, -1);
|
||||
CALL(const_native_int3, -1, 0, 0);
|
||||
LOAD_XEMU_CALL();
|
||||
MARK;
|
||||
jump_to_epilog(dyn, addr, 0, ninst);
|
||||
@@ -1978,18 +2017,18 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("INT 29/2c/2d");
|
||||
// lets do nothing
|
||||
MESSAGE(LOG_INFO, "INT 29/2c/2d Windows interruption\n");
|
||||
GETIP(ip); // priviledged instruction, IP not updated
|
||||
GETIP(ip, x7); // priviledged instruction, IP not updated
|
||||
STORE_XEMU_CALL();
|
||||
MOV32w(x1, u8);
|
||||
CALL(native_int, -1);
|
||||
CALL(const_native_int, -1, x1, 0);
|
||||
LOAD_XEMU_CALL();
|
||||
} else if (u8 == 0x80) {
|
||||
INST_NAME("32bits SYSCALL");
|
||||
NOTEST(x1);
|
||||
SMEND();
|
||||
GETIP(addr);
|
||||
GETIP(addr, x7);
|
||||
STORE_XEMU_CALL();
|
||||
CALL_S(EmuX86Syscall, -1);
|
||||
CALL_S(const_x86syscall, -1, 0);
|
||||
LOAD_XEMU_CALL();
|
||||
TABLE64(x3, addr); // expected return address
|
||||
BNE_MARK(xRIP, x3);
|
||||
@@ -2005,9 +2044,9 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION); // Hack to set flags in "don't care" state
|
||||
}
|
||||
GETIP(addr);
|
||||
GETIP(addr, x7);
|
||||
STORE_XEMU_CALL();
|
||||
CALL(native_int3, -1);
|
||||
CALL(const_native_int3, -1, 0, 0);
|
||||
LOAD_XEMU_CALL();
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
*need_epilog = 0;
|
||||
@@ -2019,9 +2058,9 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION); // Hack to set flags in "don't care" state
|
||||
}
|
||||
GETIP(ip); // priviledged instruction, IP not updated
|
||||
GETIP(ip, x7); // priviledged instruction, IP not updated
|
||||
STORE_XEMU_CALL();
|
||||
CALL(native_priv, -1);
|
||||
CALL(const_native_priv, -1, 0, 0);
|
||||
LOAD_XEMU_CALL();
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
*need_epilog = 0;
|
||||
@@ -2052,7 +2091,7 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
}
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
SETFLAGS(X_OF | X_CF, SF_SET_DF, NAT_FLAGS_NOFUSION);
|
||||
CALL_(rol8, ed, x3);
|
||||
CALL_(const_rol8, ed, x3, x1, x2);
|
||||
EBBACK();
|
||||
break;
|
||||
case 4:
|
||||
@@ -2134,7 +2173,7 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
SETFLAGS(X_OF | X_CF, SF_SET_DF, NAT_FLAGS_NOFUSION);
|
||||
MOV32w(x2, 1);
|
||||
GETEDW(x4, x1, 0);
|
||||
CALL_(rex.w ? ((void*)rcr64) : ((void*)rcr32), ed, x4);
|
||||
CALL_(rex.w ? const_rcr64 : const_rcr32, ed, x4, x1, x2);
|
||||
WBACK;
|
||||
if (!wback && !rex.w) ZEROUP(ed);
|
||||
break;
|
||||
@@ -2289,7 +2328,7 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
READFLAGS(X_ZF);
|
||||
i8 = F8S;
|
||||
ADDI_D(xRCX, xRCX, -1);
|
||||
if (la64_lbt)
|
||||
if (cpuext.lbt)
|
||||
X64_GET_EFLAGS(x1, X_ZF);
|
||||
else
|
||||
ANDI(x1, xFlags, 1 << F_ZF);
|
||||
@@ -2301,7 +2340,7 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
READFLAGS(X_ZF);
|
||||
i8 = F8S;
|
||||
ADDI_D(xRCX, xRCX, -1);
|
||||
if (la64_lbt)
|
||||
if (cpuext.lbt)
|
||||
X64_GET_EFLAGS(x1, X_ZF);
|
||||
else
|
||||
ANDI(x1, xFlags, 1 << F_ZF);
|
||||
@@ -2330,10 +2369,10 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
#endif
|
||||
}
|
||||
#if STEP < 2
|
||||
if (!rex.is32bits && IsNativeCall(addr + i32, rex.is32bits, &dyn->insts[ninst].natcall, &dyn->insts[ninst].retn))
|
||||
if (!rex.is32bits && !dyn->need_reloc && IsNativeCall(addr + i32, rex.is32bits, &dyn->insts[ninst].natcall, &dyn->insts[ninst].retn))
|
||||
tmp = dyn->insts[ninst].pass2choice = 3;
|
||||
else
|
||||
tmp = dyn->insts[ninst].pass2choice = 0;
|
||||
tmp = dyn->insts[ninst].pass2choice = i32 ? 0 : 1;
|
||||
#else
|
||||
tmp = dyn->insts[ninst].pass2choice;
|
||||
#endif
|
||||
@@ -2342,10 +2381,14 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION); // Hack to set flags to "dont'care" state
|
||||
SKIPTEST(x1);
|
||||
BARRIER(BARRIER_FULL);
|
||||
if (dyn->last_ip && (addr - dyn->last_ip < 0x800)) {
|
||||
if (dyn->last_ip && ((addr - dyn->last_ip < 0x800) || (dyn->last_ip - addr < 0x800))) {
|
||||
ADDI_D(x2, xRIP, addr - dyn->last_ip);
|
||||
} else {
|
||||
TABLE64(x2, addr);
|
||||
if (dyn->need_reloc) {
|
||||
TABLE64(x2, addr);
|
||||
} else {
|
||||
MOV64x(x2, addr);
|
||||
}
|
||||
}
|
||||
PUSH1(x2);
|
||||
MESSAGE(LOG_DUMP, "Native Call to %s (retn=%d)\n", GetNativeName(GetNativeFnc(dyn->insts[ninst].natcall - 1)), dyn->insts[ninst].retn);
|
||||
@@ -2362,17 +2405,17 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
// // return value will be on the stack, so the stack depth needs to be updated
|
||||
// x87_purgecache(dyn, ninst, 0, x3, x1, x4);
|
||||
if ((BOX64ENV(log) < 2 && !BOX64ENV(rolling_log)) && dyn->insts[ninst].natcall && tmp) {
|
||||
// GETIP(ip+3+8+8); // read the 0xCC
|
||||
// FIXME: call_n(dyn, ninst, *(void**)(dyn->insts[ninst].natcall + 2 + 8), tmp);
|
||||
// GETIP(ip+3+8+8, x7); // read the 0xCC
|
||||
// FIXME: call_n(dyn, ninst, (void*)(dyn->insts[ninst].natcall + 2 + 8), tmp);
|
||||
POP1(xRIP); // pop the return address
|
||||
dyn->last_ip = addr;
|
||||
} else {
|
||||
GETIP_(dyn->insts[ninst].natcall); // read the 0xCC already
|
||||
GETIP_(dyn->insts[ninst].natcall, x7); // read the 0xCC already
|
||||
STORE_XEMU_CALL();
|
||||
ADDI_D(x1, xEmu, (uint32_t)offsetof(x64emu_t, ip)); // setup addr as &emu->ip
|
||||
CALL_S(EmuInt3, -1);
|
||||
CALL_S(const_int3, -1, x1);
|
||||
LOAD_XEMU_CALL();
|
||||
TABLE64(x3, dyn->insts[ninst].natcall);
|
||||
MOV64x(x3, dyn->insts[ninst].natcall);
|
||||
ADDI_D(x3, x3, 2 + 8 + 8);
|
||||
BNE_MARK(xRIP, x3); // Not the expected address, exit dynarec block
|
||||
POP1(xRIP); // pop the return address
|
||||
@@ -2384,8 +2427,6 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
ADD_D(xRSP, xRSP, x3);
|
||||
}
|
||||
}
|
||||
TABLE64(x3, addr);
|
||||
BNE_MARK(xRIP, x3); // Not the expected address again
|
||||
LD_W(x1, xEmu, offsetof(x64emu_t, quit));
|
||||
CBZ_NEXT(x1);
|
||||
MARK;
|
||||
@@ -2393,6 +2434,15 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
dyn->last_ip = addr;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
// this is call to next step, so just push the return address to the stack
|
||||
if (dyn->need_reloc) {
|
||||
TABLE64(x2, addr);
|
||||
} else {
|
||||
MOV64x(x2, addr);
|
||||
}
|
||||
PUSH1z(x2);
|
||||
break;
|
||||
default:
|
||||
if ((BOX64DRENV(dynarec_safeflags) > 1) || (ninst && dyn->insts[ninst - 1].x64.set_flags)) {
|
||||
READFLAGS(X_PEND); // that's suspicious
|
||||
@@ -2400,18 +2450,10 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION); // Hack to set flags to "dont'care" state
|
||||
}
|
||||
// regular call
|
||||
/*if (BOX64DRENV(dynarec_callret) && BOX64DRENV(dynarec_bigblock) > 1) {
|
||||
BARRIER(BARRIER_FULL);
|
||||
} else {
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
}*/
|
||||
|
||||
if (rex.is32bits) {
|
||||
MOV32w(x2, addr);
|
||||
} else {
|
||||
if (dyn->need_reloc) {
|
||||
TABLE64(x2, addr);
|
||||
} else {
|
||||
MOV64x(x2, addr);
|
||||
}
|
||||
fpu_purgecache(dyn, ninst, 1, x1, x3, x4);
|
||||
PUSH1z(x2);
|
||||
@@ -2446,7 +2488,12 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
// jumps out of current dynablock...
|
||||
MARK;
|
||||
j64 = getJumpTableAddress64(addr);
|
||||
TABLE64(x4, j64);
|
||||
if (dyn->need_reloc) {
|
||||
AddRelocTable64JmpTbl(dyn, ninst, addr, STEP);
|
||||
TABLE64_(x4, j64);
|
||||
} else {
|
||||
MOV64x(x4, j64);
|
||||
}
|
||||
LD_D(x4, x4, 0);
|
||||
BR(x4);
|
||||
}
|
||||
@@ -2496,9 +2543,9 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION); // Hack to set flags in "don't care" state
|
||||
}
|
||||
GETIP(ip);
|
||||
GETIP(ip, x7);
|
||||
STORE_XEMU_CALL();
|
||||
CALL(native_priv, -1);
|
||||
CALL(const_native_priv, -1, 0, 0);
|
||||
LOAD_XEMU_CALL();
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
*need_epilog = 0;
|
||||
@@ -2508,7 +2555,7 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("CMC");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
if (la64_lbt) {
|
||||
if (cpuext.lbt) {
|
||||
X64_GET_EFLAGS(x3, X_CF);
|
||||
XORI(x3, x3, 1 << F_CF);
|
||||
X64_SET_EFLAGS(x3, X_CF);
|
||||
@@ -2564,7 +2611,7 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
SETFLAGS(X_ALL, SF_SET_DF, NAT_FLAGS_NOFUSION);
|
||||
GETEB(x1, 0);
|
||||
CALL(div8, -1);
|
||||
CALL(const_div8, -1, x1, 0);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
@@ -2674,8 +2721,7 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
GETEDH(x4, x1, 0); // get edd changed addr, so cannot be called 2 times for same op...
|
||||
BEQ_MARK(xRDX, xZR);
|
||||
if (ed != x1) { MV(x1, ed); }
|
||||
CALL(div64, -1);
|
||||
CALL(const_div64, -1, ed, 0);
|
||||
B_NEXT_nocond;
|
||||
MARK;
|
||||
DIV_DU(x2, xRAX, ed);
|
||||
@@ -2720,8 +2766,7 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
BNE_MARK3(x2, xZR);
|
||||
BLT_MARK(xRAX, xZR);
|
||||
MARK3;
|
||||
if (ed != x1) MV(x1, ed);
|
||||
CALL((void*)idiv64, -1);
|
||||
CALL(const_idiv64, -1, ed, 0);
|
||||
B_NEXT_nocond;
|
||||
MARK;
|
||||
DIV_D(x2, xRAX, ed);
|
||||
@@ -2739,7 +2784,7 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("CLC");
|
||||
SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
SET_DFNONE();
|
||||
if (la64_lbt)
|
||||
if (cpuext.lbt)
|
||||
X64_SET_EFLAGS(xZR, X_CF);
|
||||
else
|
||||
BSTRINS_D(xFlags, xZR, F_CF, F_CF);
|
||||
@@ -2748,7 +2793,7 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("STC");
|
||||
SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
SET_DFNONE();
|
||||
if (la64_lbt) {
|
||||
if (cpuext.lbt) {
|
||||
ORI(x3, xZR, 1 << F_CF);
|
||||
X64_SET_EFLAGS(x3, X_CF);
|
||||
} else {
|
||||
@@ -2816,7 +2861,7 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
}
|
||||
GETIP_(addr);
|
||||
GETIP_(addr, x7);
|
||||
if (BOX64DRENV(dynarec_callret)) {
|
||||
SET_HASCALLRET();
|
||||
// Push actual return address
|
||||
@@ -2842,7 +2887,8 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
// jumps out of current dynablock...
|
||||
MARK;
|
||||
j64 = getJumpTableAddress64(addr);
|
||||
TABLE64(x4, j64);
|
||||
if (dyn->need_reloc) AddRelocTable64RetEndBlock(dyn, ninst, addr, STEP);
|
||||
TABLE64_(x4, j64);
|
||||
LD_D(x4, x4, 0);
|
||||
BR(x4);
|
||||
}
|
||||
|
||||
@@ -86,9 +86,9 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("SYSCALL");
|
||||
NOTEST(x1);
|
||||
SMEND();
|
||||
GETIP(addr);
|
||||
GETIP(addr, x7);
|
||||
STORE_XEMU_CALL();
|
||||
CALL_S(EmuX64Syscall, -1);
|
||||
CALL_S(const_x64syscall, -1, 0);
|
||||
LOAD_XEMU_CALL();
|
||||
TABLE64(x3, addr); // expected return address
|
||||
BNE_MARK(xRIP, x3);
|
||||
@@ -105,9 +105,9 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION); // Hack to set flags in "don't care" state
|
||||
}
|
||||
GETIP(ip);
|
||||
GETIP(ip, x7);
|
||||
STORE_XEMU_CALL();
|
||||
CALL(native_ud, -1);
|
||||
CALL(const_native_ud, -1, 0, 0);
|
||||
LOAD_XEMU_CALL();
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
*need_epilog = 0;
|
||||
@@ -125,7 +125,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
}
|
||||
break;
|
||||
case 0x10:
|
||||
INST_NAME("MOVUPS Gx,Ex");
|
||||
INST_NAME("MOVUPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if (MODREG) {
|
||||
@@ -158,16 +158,18 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 0x12:
|
||||
nextop = F8;
|
||||
if (MODREG) {
|
||||
INST_NAME("MOVHLPS Gx,Ex");
|
||||
INST_NAME("MOVHLPS Gx, Ex");
|
||||
GETGX(v0, 1);
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop & 7) + (rex.b << 3), 0);
|
||||
VEXTRINS_D(v0, v1, 1);
|
||||
} else {
|
||||
INST_NAME("MOVLPS Gx,Ex");
|
||||
INST_NAME("MOVLPS Gx, Ex");
|
||||
GETGX(v0, 1);
|
||||
SMREAD();
|
||||
GETEX(q1, 0, 0);
|
||||
VEXTRINS_D(v0, q1, 0);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x3, &fixedaddress, rex, NULL, 1, 0);
|
||||
FLD_D(v1, ed, fixedaddress);
|
||||
VEXTRINS_D(v0, v1, 0);
|
||||
}
|
||||
break;
|
||||
case 0x13:
|
||||
@@ -202,11 +204,11 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 0x16:
|
||||
nextop = F8;
|
||||
if (MODREG) {
|
||||
INST_NAME("MOVLHPS Gx,Ex");
|
||||
INST_NAME("MOVLHPS Gx, Ex");
|
||||
GETGX(v0, 1);
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop & 7) + (rex.b << 3), 0);
|
||||
} else {
|
||||
INST_NAME("MOVHPS Gx,Ex");
|
||||
INST_NAME("MOVHPS Gx, Ex");
|
||||
SMREAD();
|
||||
GETGX(v0, 1);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
@@ -247,13 +249,18 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
}
|
||||
break;
|
||||
case 0x19:
|
||||
case 0x1A:
|
||||
case 0x1B:
|
||||
case 0x1C:
|
||||
case 0x1D:
|
||||
case 0x1E:
|
||||
case 0x1F:
|
||||
INST_NAME("NOP (multibyte)");
|
||||
nextop = F8;
|
||||
FAKEED;
|
||||
break;
|
||||
case 0x28:
|
||||
INST_NAME("MOVAPS Gx,Ex");
|
||||
INST_NAME("MOVAPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if (MODREG) {
|
||||
@@ -295,7 +302,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
VEXTRINS_D(v0, q0, VEXTRINS_IMM_4_0(0, 0));
|
||||
break;
|
||||
case 0x2B:
|
||||
INST_NAME("MOVNTPS Ex,Gx");
|
||||
INST_NAME("MOVNTPS Ex, Gx");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
@@ -309,10 +316,10 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
}
|
||||
break;
|
||||
case 0x2C:
|
||||
INST_NAME("CVTTPS2PI Gm,Ex");
|
||||
INST_NAME("CVTTPS2PI Gm, Ex");
|
||||
nextop = F8;
|
||||
GETGM(v0);
|
||||
GETEX(v1, 0, 0);
|
||||
GETEXSD(v1, 0, 0);
|
||||
if (BOX64ENV(dynarec_fastround)) {
|
||||
VFTINTRZ_W_S(v0, v1);
|
||||
} else {
|
||||
@@ -339,7 +346,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("CVTPS2PI Gm, Ex");
|
||||
nextop = F8;
|
||||
GETGM(v0);
|
||||
GETEX(v1, 0, 0);
|
||||
GETEXSD(v1, 0, 0);
|
||||
u8 = sse_setround(dyn, ninst, x4, x6);
|
||||
if (BOX64ENV(dynarec_fastround)) {
|
||||
VFTINTRZ_W_S(v0, v1);
|
||||
@@ -420,7 +427,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("RDTSC");
|
||||
NOTEST(x1);
|
||||
if (box64_rdtsc) {
|
||||
CALL(ReadTSC, x3); // will return the u64 in x3
|
||||
CALL(const_readtsc, x3, 0, 0); // will return the u64 in x3
|
||||
} else {
|
||||
RDTIME_D(x3, xZR);
|
||||
}
|
||||
@@ -485,21 +492,18 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
VSHUF4I_W(q0, q0, 0b11011000);
|
||||
break;
|
||||
case 0x04:
|
||||
INST_NAME("PMADDUBSW Gm,Em");
|
||||
INST_NAME("PMADDUBSW Gm, Em");
|
||||
nextop = F8;
|
||||
GETGM(q0);
|
||||
GETEM(q1, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
VEXT2XV_HU_BU(v0, q0);
|
||||
VEXT2XV_H_B(v1, q1);
|
||||
XVMUL_H(v0, v0, v1);
|
||||
VPICKEV_H(q0, v1, v0);
|
||||
VPICKOD_H(v0, v1, v0);
|
||||
VSADD_H(q0, v0, q0);
|
||||
VMULWEV_H_BU_B(v0, q0, q1);
|
||||
VMULWOD_H_BU_B(v1, q0, q1);
|
||||
VSADD_H(q0, v0, v1);
|
||||
break;
|
||||
case 0x05:
|
||||
INST_NAME("PHSUBW Gm,Em");
|
||||
INST_NAME("PHSUBW Gm, Em");
|
||||
nextop = F8;
|
||||
GETGM(q0);
|
||||
GETEM(q1, 0);
|
||||
@@ -511,7 +515,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
VSHUF4I_W(q0, q0, 0b11011000);
|
||||
break;
|
||||
case 0x06:
|
||||
INST_NAME("PHSUBD Gm,Em");
|
||||
INST_NAME("PHSUBD Gm, Em");
|
||||
nextop = F8;
|
||||
GETGM(q0);
|
||||
GETEM(q1, 0);
|
||||
@@ -523,7 +527,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
VSHUF4I_W(q0, q0, 0b11011000);
|
||||
break;
|
||||
case 0x07:
|
||||
INST_NAME("PHSUBSW Gm,Em");
|
||||
INST_NAME("PHSUBSW Gm, Em");
|
||||
nextop = F8;
|
||||
GETGM(q0);
|
||||
GETEM(q1, 0);
|
||||
@@ -535,28 +539,28 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
VSHUF4I_W(q0, q0, 0b11011000);
|
||||
break;
|
||||
case 0x08:
|
||||
INST_NAME("PSIGNB Gm,Em");
|
||||
INST_NAME("PSIGNB Gm, Em");
|
||||
nextop = F8;
|
||||
GETGM(q0);
|
||||
GETEM(q1, 0);
|
||||
VSIGNCOV_B(q0, q1, q0);
|
||||
break;
|
||||
case 0x09:
|
||||
INST_NAME("PSIGNW Gm,Em");
|
||||
INST_NAME("PSIGNW Gm, Em");
|
||||
nextop = F8;
|
||||
GETGM(q0);
|
||||
GETEM(q1, 0);
|
||||
VSIGNCOV_H(q0, q1, q0);
|
||||
break;
|
||||
case 0x0A:
|
||||
INST_NAME("PSIGND Gm,Em");
|
||||
INST_NAME("PSIGND Gm, Em");
|
||||
nextop = F8;
|
||||
GETGM(q0);
|
||||
GETEM(q1, 0);
|
||||
VSIGNCOV_W(q0, q1, q0);
|
||||
break;
|
||||
case 0x0B:
|
||||
INST_NAME("PMULHRSW Gm,Em");
|
||||
INST_NAME("PMULHRSW Gm, Em");
|
||||
nextop = F8;
|
||||
GETGM(q0);
|
||||
GETEM(q1, 0);
|
||||
@@ -570,7 +574,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
VSRLNI_H_W(q0, v0, 1);
|
||||
break;
|
||||
case 0x1C:
|
||||
INST_NAME("PABSB Gm,Em");
|
||||
INST_NAME("PABSB Gm, Em");
|
||||
nextop = F8;
|
||||
GETGM(q0);
|
||||
GETEM(q1, 0);
|
||||
@@ -579,7 +583,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
VABSD_B(q0, q1, v0);
|
||||
break;
|
||||
case 0x1D:
|
||||
INST_NAME("PABSW Gm,Em");
|
||||
INST_NAME("PABSW Gm, Em");
|
||||
nextop = F8;
|
||||
GETGM(q0);
|
||||
GETEM(q1, 0);
|
||||
@@ -588,7 +592,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
VABSD_H(q0, q1, v0);
|
||||
break;
|
||||
case 0x1E:
|
||||
INST_NAME("PABSD Gm,Em");
|
||||
INST_NAME("PABSD Gm, Em");
|
||||
nextop = F8;
|
||||
GETGM(q0);
|
||||
GETEM(q1, 0);
|
||||
@@ -623,12 +627,10 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
ed = (nextop & 7) + (rex.b << 3);
|
||||
sse_reflect_reg(dyn, ninst, ed);
|
||||
ADDI_D(x2, xEmu, offsetof(x64emu_t, xmm[ed]));
|
||||
ed = x2;
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 0, 0);
|
||||
if (ed != x2) {
|
||||
MV(x2, ed);
|
||||
}
|
||||
}
|
||||
GETG;
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
@@ -636,22 +638,22 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
sse_reflect_reg(dyn, ninst, 0);
|
||||
switch (u8) {
|
||||
case 0xC8:
|
||||
CALL(sha1nexte, -1);
|
||||
CALL(const_sha1nexte, -1, x1, ed);
|
||||
break;
|
||||
case 0xC9:
|
||||
CALL(sha1msg1, -1);
|
||||
CALL(const_sha1msg1, -1, x1, ed);
|
||||
break;
|
||||
case 0xCA:
|
||||
CALL(sha1msg2, -1);
|
||||
CALL(const_sha1msg2, -1, x1, ed);
|
||||
break;
|
||||
case 0xCB:
|
||||
CALL(sha256rnds2, -1);
|
||||
CALL(const_sha256rnds2, -1, x1, ed);
|
||||
break;
|
||||
case 0xCC:
|
||||
CALL(sha256msg1, -1);
|
||||
CALL(const_sha256msg1, -1, x1, ed);
|
||||
break;
|
||||
case 0xCD:
|
||||
CALL(sha256msg2, -1);
|
||||
CALL(const_sha256msg2, -1, x1, ed);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -713,17 +715,17 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
ed = (nextop & 7) + (rex.b << 3);
|
||||
sse_reflect_reg(dyn, ninst, ed);
|
||||
ADDI_D(x2, xEmu, offsetof(x64emu_t, xmm[ed]));
|
||||
wback = x2;
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, NULL, 0, 1);
|
||||
if (wback != x2) MV(x2, wback);
|
||||
}
|
||||
u8 = F8;
|
||||
GETG;
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
ADDI_D(x1, xEmu, offsetof(x64emu_t, xmm[gd]));
|
||||
MOV32w(x3, u8);
|
||||
CALL(sha1rnds4, -1);
|
||||
CALL4(const_sha1rnds4, -1, x1, wback, x3, 0);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
@@ -733,7 +735,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
#define GO(GETFLAGS, NO, YES, NATNO, NATYES, F, I) \
|
||||
READFLAGS_FUSION(F, x1, x2, x3, x4, x5); \
|
||||
if (!dyn->insts[ninst].nat_flags_fusion) { \
|
||||
if (la64_lbt) { \
|
||||
if (cpuext.lbt) { \
|
||||
X64_SETJ(tmp1, I); \
|
||||
} else { \
|
||||
GETFLAGS; \
|
||||
@@ -746,7 +748,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
if (dyn->insts[ninst].nat_flags_fusion) { \
|
||||
NATIVEJUMP(NATNO, 8); \
|
||||
} else { \
|
||||
if (la64_lbt) \
|
||||
if (cpuext.lbt) \
|
||||
BEQZ(tmp1, 8); \
|
||||
else \
|
||||
B##NO(tmp1, 8); \
|
||||
@@ -758,7 +760,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
if (dyn->insts[ninst].nat_flags_fusion) { \
|
||||
NATIVEJUMP(NATNO, 8); \
|
||||
} else { \
|
||||
if (la64_lbt) \
|
||||
if (cpuext.lbt) \
|
||||
BEQZ(tmp1, 8); \
|
||||
else \
|
||||
B##NO(tmp1, 8); \
|
||||
@@ -785,7 +787,17 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
nextop = F8;
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX_empty(v0);
|
||||
VFSQRT_S(v0, q0);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
VFCMP_S(d0, q0, q0, cEQ);
|
||||
VFSQRT_S(v0, q0);
|
||||
VFCMP_S(d1, v0, v0, cEQ);
|
||||
VANDN_V(d1, d1, d0);
|
||||
VSLLI_W(d1, d1, 31);
|
||||
VOR_V(v0, v0, d1);
|
||||
} else
|
||||
VFSQRT_S(v0, q0);
|
||||
break;
|
||||
case 0x52:
|
||||
INST_NAME("RSQRTPS Gx, Ex");
|
||||
@@ -793,7 +805,11 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
SKIPTEST(x1);
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX_empty(q1);
|
||||
VFRSQRT_S(q1, q0);
|
||||
if (cpuext.frecipe) {
|
||||
VFRSQRTE_S(q1, q0);
|
||||
} else {
|
||||
VFRSQRT_S(q1, q0);
|
||||
}
|
||||
break;
|
||||
case 0x53:
|
||||
INST_NAME("RCPPS Gx, Ex");
|
||||
@@ -801,8 +817,11 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
SKIPTEST(x1);
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX_empty(q1);
|
||||
// TODO: use v1.1 vfrecipe when possible
|
||||
VFRECIP_S(q1, q0);
|
||||
if (cpuext.frecipe) {
|
||||
VFRECIPE_S(q1, q0);
|
||||
} else {
|
||||
VFRECIP_S(q1, q0);
|
||||
}
|
||||
break;
|
||||
case 0x54:
|
||||
INST_NAME("ANDPS Gx, Ex");
|
||||
@@ -870,7 +889,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 0x5A:
|
||||
INST_NAME("CVTPS2PD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0, 0);
|
||||
GETEXSD(q0, 0, 0);
|
||||
GETGX(q1, 1);
|
||||
VFCVTL_D_S(q1, q0);
|
||||
break;
|
||||
@@ -1277,7 +1296,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
BARRIER(BARRIER_MAYBE); \
|
||||
JUMP(j64, 1); \
|
||||
if (!dyn->insts[ninst].nat_flags_fusion) { \
|
||||
if (la64_lbt) { \
|
||||
if (cpuext.lbt) { \
|
||||
X64_SETJ(x1, I); \
|
||||
} else { \
|
||||
GETFLAGS; \
|
||||
@@ -1289,7 +1308,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
if (dyn->insts[ninst].nat_flags_fusion) { \
|
||||
NATIVEJUMP_safe(NATNO, i32); \
|
||||
} else { \
|
||||
if (la64_lbt) \
|
||||
if (cpuext.lbt) \
|
||||
BEQZ_safe(x1, i32); \
|
||||
else \
|
||||
B##NO##_safe(x1, i32); \
|
||||
@@ -1309,7 +1328,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
if (dyn->insts[ninst].nat_flags_fusion) { \
|
||||
NATIVEJUMP_safe(NATYES, i32); \
|
||||
} else { \
|
||||
if (la64_lbt) \
|
||||
if (cpuext.lbt) \
|
||||
BNEZ_safe(tmp1, i32); \
|
||||
else \
|
||||
B##YES##_safe(tmp1, i32); \
|
||||
@@ -1325,7 +1344,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
READFLAGS(F); \
|
||||
tmp1 = x1; \
|
||||
tmp3 = x3; \
|
||||
if (la64_lbt) { \
|
||||
if (cpuext.lbt) { \
|
||||
X64_SETJ(x3, I); \
|
||||
} else { \
|
||||
GETFLAGS; \
|
||||
@@ -1354,8 +1373,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 0xA2:
|
||||
INST_NAME("CPUID");
|
||||
NOTEST(x1);
|
||||
MV(A1, xRAX);
|
||||
CALL_(my_cpuid, -1, 0);
|
||||
CALL_(const_cpuid, -1, 0, xRAX, 0);
|
||||
// BX and DX are not synchronized durring the call, so need to force the update
|
||||
LD_D(xRDX, xEmu, offsetof(x64emu_t, regs[_DX]));
|
||||
LD_D(xRBX, xEmu, offsetof(x64emu_t, regs[_BX]));
|
||||
@@ -1371,15 +1389,18 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
SRAIxw(x1, gd, 5 + rex.w); // r1 = (gd>>5)
|
||||
ALSL_D(x3, wback, x1, 2 + rex.w); // (&ed) += r1*4;
|
||||
if (rex.w)
|
||||
SRAI_D(x1, gd, 6);
|
||||
else
|
||||
SRAI_W(x1, gd, 5);
|
||||
ALSL_D(x3, x1, wback, 2 + rex.w); // (&ed) += r1*4;
|
||||
LDxw(x1, x3, fixedaddress);
|
||||
ed = x1;
|
||||
}
|
||||
if (X_CF) {
|
||||
ANDI(x2, gd, rex.w ? 0x3f : 0x1f);
|
||||
SRLxw(x4, ed, x2);
|
||||
if (la64_lbt)
|
||||
if (cpuext.lbt)
|
||||
X64_SET_EFLAGS(x4, X_CF);
|
||||
else
|
||||
BSTRINS_D(xFlags, x4, F_CF, F_CF);
|
||||
@@ -1397,6 +1418,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
WBACK;
|
||||
} else {
|
||||
FAKEED;
|
||||
if (!rex.w && !rex.is32bits && MODREG) { ZEROUP(ed); }
|
||||
F8;
|
||||
}
|
||||
break;
|
||||
@@ -1412,7 +1434,10 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
SRAI_D(x1, gd, 5 + rex.w);
|
||||
if (rex.w)
|
||||
SRAI_D(x1, gd, 6);
|
||||
else
|
||||
SRAI_W(x1, gd, 5);
|
||||
ALSL_D(x3, x1, wback, 2 + rex.w);
|
||||
LDxw(x1, x3, fixedaddress);
|
||||
ed = x1;
|
||||
@@ -1421,7 +1446,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
ANDI(x2, gd, rex.w ? 0x3f : 0x1f);
|
||||
IFX (X_CF) {
|
||||
SRL_D(x4, ed, x2);
|
||||
if (la64_lbt) {
|
||||
if (cpuext.lbt) {
|
||||
X64_SET_EFLAGS(x4, X_CF);
|
||||
} else {
|
||||
BSTRINS_D(xFlags, x4, F_CF, F_CF);
|
||||
@@ -1450,6 +1475,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
WBACK;
|
||||
} else {
|
||||
FAKEED;
|
||||
if (!rex.w && !rex.is32bits && MODREG) { ZEROUP(ed); }
|
||||
F8;
|
||||
}
|
||||
break;
|
||||
@@ -1483,8 +1509,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
DEFAULT;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x3, &fixedaddress, rex, NULL, 0, 0);
|
||||
if (ed != x1) { MV(x1, ed); }
|
||||
CALL(rex.is32bits ? ((void*)fpu_fxsave32) : ((void*)fpu_fxsave64), -1);
|
||||
CALL(rex.is32bits ? const_fpu_fxsave32 : const_fpu_fxsave64, -1, ed, 0);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
@@ -1493,21 +1518,54 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
SKIPTEST(x1);
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x3, &fixedaddress, rex, NULL, 0, 0);
|
||||
if (ed != x1) { MV(x1, ed); }
|
||||
CALL(rex.is32bits ? ((void*)fpu_fxrstor32) : ((void*)fpu_fxrstor64), -1);
|
||||
CALL(rex.is32bits ? const_fpu_fxrstor32 : const_fpu_fxrstor64, -1, ed, 0);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("LDMXCSR Md");
|
||||
GETED(0);
|
||||
ST_W(ed, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
if (BOX64ENV(sse_flushto0)) {
|
||||
// TODO
|
||||
/* LA <-> x86
|
||||
16/24 <-> 5 inexact
|
||||
17/25 <-> 4 underflow
|
||||
18/26 <-> 3 overflow
|
||||
19/27 <-> 2 divide by zero
|
||||
x <-> 1 denormal
|
||||
20/28 <-> 0 invalid operation
|
||||
*/
|
||||
// Doing x86 -> LA here, ignore denormal
|
||||
XOR(x4, x4, x4);
|
||||
BSTRPICK_W(x3, ed, 5, 5);
|
||||
BSTRINS_W(x4, x3, 16, 16);
|
||||
BSTRPICK_W(x3, ed, 4, 4);
|
||||
BSTRINS_W(x4, x3, 17, 17);
|
||||
BSTRPICK_W(x3, ed, 3, 3);
|
||||
BSTRINS_W(x4, x3, 18, 18);
|
||||
BSTRPICK_W(x3, ed, 2, 2);
|
||||
BSTRINS_W(x4, x3, 19, 19);
|
||||
BSTRPICK_W(x3, ed, 0, 0);
|
||||
BSTRINS_W(x4, x3, 20, 20);
|
||||
MOVGR2FCSR(FCSR2, x4);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("STMXCSR Md");
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, x2, &fixedaddress, rex, NULL, 0, 0);
|
||||
LD_WU(x4, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
if (BOX64ENV(sse_flushto0)) {
|
||||
MOVFCSR2GR(x5, FCSR2);
|
||||
// Doing LA -> x86 here, ignore denormal
|
||||
BSTRPICK_W(x3, x5, 16, 16);
|
||||
BSTRINS_W(x4, x3, 5, 5);
|
||||
BSTRPICK_W(x3, x5, 17, 17);
|
||||
BSTRINS_W(x4, x3, 4, 4);
|
||||
BSTRPICK_W(x3, x5, 18, 18);
|
||||
BSTRINS_W(x4, x3, 3, 3);
|
||||
BSTRPICK_W(x3, x5, 19, 19);
|
||||
BSTRINS_W(x4, x3, 2, 2);
|
||||
BSTRPICK_W(x3, x5, 20, 20);
|
||||
BSTRINS_W(x4, x3, 0, 0);
|
||||
}
|
||||
ST_W(x4, wback, fixedaddress);
|
||||
break;
|
||||
case 4:
|
||||
@@ -1515,25 +1573,22 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x2, &fixedaddress, rex, NULL, 0, 0);
|
||||
if (ed != x1) { MV(x1, ed); }
|
||||
MOV32w(x2, rex.w ? 0 : 1);
|
||||
CALL((void*)fpu_xsave, -1);
|
||||
CALL(const_fpu_xsave, -1, ed, x2);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("XRSTOR Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x2, &fixedaddress, rex, NULL, 0, 0);
|
||||
if (ed != x1) { MV(x1, ed); }
|
||||
MOV32w(x2, rex.w ? 0 : 1);
|
||||
CALL((void*)fpu_xrstor, -1);
|
||||
CALL(const_fpu_xrstor, -1, ed, x2);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("CLFLUSH Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization?\n");
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x2, &fixedaddress, rex, NULL, 0, 0);
|
||||
if (ed != x1) { MV(x1, ed); }
|
||||
CALL_(native_clflush, -1, 0);
|
||||
CALL_(const_native_clflush, -1, 0, ed, 0);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
@@ -1552,7 +1607,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
if (rex.w) {
|
||||
// 64bits imul
|
||||
UFLAG_IF {
|
||||
if (la64_lbt) {
|
||||
if (cpuext.lbt) {
|
||||
X64_MUL_D(gd, ed);
|
||||
}
|
||||
MULH_D(x3, gd, ed);
|
||||
@@ -1564,7 +1619,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFXA (X_CF | X_OF, !la64_lbt) {
|
||||
IFXA (X_CF | X_OF, !cpuext.lbt) {
|
||||
SRAI_D(x4, gd, 63);
|
||||
XOR(x3, x3, x4);
|
||||
SNEZ(x3, x3);
|
||||
@@ -1581,7 +1636,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
// 32bits imul
|
||||
UFLAG_IF {
|
||||
if (la64_lbt) {
|
||||
if (cpuext.lbt) {
|
||||
X64_MUL_W(gd, ed);
|
||||
}
|
||||
SLLI_W(gd, gd, 0);
|
||||
@@ -1596,7 +1651,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else IFX (X_CF | X_OF) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFXA (X_CF | X_OF, !la64_lbt) {
|
||||
IFXA (X_CF | X_OF, !cpuext.lbt) {
|
||||
SRAI_W(x4, gd, 31);
|
||||
SUB_D(x3, x3, x4);
|
||||
SNEZ(x3, x3);
|
||||
@@ -1625,7 +1680,10 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
SRAIxw(x1, gd, 5 + rex.w);
|
||||
if (rex.w)
|
||||
SRAI_D(x1, gd, 6);
|
||||
else
|
||||
SRAI_W(x1, gd, 5);
|
||||
ADDSL(x3, wback, x1, 2 + rex.w, x1);
|
||||
LDxw(x1, x3, fixedaddress);
|
||||
ed = x1;
|
||||
@@ -1633,7 +1691,11 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
}
|
||||
ANDI(x2, gd, rex.w ? 0x3f : 0x1f);
|
||||
SRL_D(x4, ed, x2);
|
||||
BSTRINS_D(xFlags, x4, 0, 0);
|
||||
if(cpuext.lbt) {
|
||||
X64_SET_EFLAGS(x4, X_CF);
|
||||
} else {
|
||||
BSTRINS_D(xFlags, x4, 0, 0);
|
||||
}
|
||||
ADDI_D(x4, xZR, 1);
|
||||
ANDI(x2, gd, rex.w ? 0x3f : 0x1f);
|
||||
SLL_D(x4, x4, x2);
|
||||
@@ -1689,7 +1751,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
u8 = F8;
|
||||
u8 &= rex.w ? 0x3f : 0x1f;
|
||||
BSTRPICK_D(x4, ed, u8, u8);
|
||||
if (la64_lbt)
|
||||
if (cpuext.lbt)
|
||||
X64_SET_EFLAGS(x4, X_CF);
|
||||
else
|
||||
BSTRINS_D(xFlags, x4, 0, 0);
|
||||
@@ -1702,7 +1764,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
u8 = F8;
|
||||
u8 &= (rex.w ? 0x3f : 0x1f);
|
||||
BSTRPICK_D(x4, ed, u8, u8);
|
||||
if (la64_lbt)
|
||||
if (cpuext.lbt)
|
||||
X64_SET_EFLAGS(x4, X_CF);
|
||||
else
|
||||
BSTRINS_D(xFlags, x4, 0, 0);
|
||||
@@ -1723,7 +1785,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
u8 = F8;
|
||||
u8 &= (rex.w ? 0x3f : 0x1f);
|
||||
BSTRPICK_D(x4, ed, u8, u8);
|
||||
if (la64_lbt)
|
||||
if (cpuext.lbt)
|
||||
X64_SET_EFLAGS(x4, X_CF);
|
||||
else
|
||||
BSTRINS_D(xFlags, x4, 0, 0);
|
||||
@@ -1743,7 +1805,10 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
u8 = F8;
|
||||
u8 &= rex.w ? 0x3f : 0x1f;
|
||||
BSTRPICK_D(x3, ed, u8, u8);
|
||||
BSTRINS_D(xFlags, x3, 0, 0);
|
||||
if (cpuext.lbt)
|
||||
X64_SET_EFLAGS(x3, X_CF);
|
||||
else
|
||||
BSTRINS_D(xFlags, x3, 0, 0);
|
||||
if (u8 <= 10) {
|
||||
XORI(ed, ed, (1LL << u8));
|
||||
} else {
|
||||
@@ -1773,7 +1838,10 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
SRAIxw(x1, gd, 5 + rex.w);
|
||||
if (rex.w)
|
||||
SRAI_D(x1, gd, 6);
|
||||
else
|
||||
SRAI_W(x1, gd, 5);
|
||||
ADDSL(x3, wback, x1, 2 + rex.w, x1);
|
||||
LDxw(x1, x3, fixedaddress);
|
||||
ed = x1;
|
||||
@@ -1781,7 +1849,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
}
|
||||
ANDI(x2, gd, rex.w ? 0x3f : 0x1f);
|
||||
SRL_D(x4, ed, x2);
|
||||
if (la64_lbt)
|
||||
if (cpuext.lbt)
|
||||
X64_SET_EFLAGS(x4, X_CF);
|
||||
else
|
||||
BSTRINS_D(xFlags, x4, F_CF, F_CF);
|
||||
@@ -1807,7 +1875,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
ed = x4;
|
||||
}
|
||||
BNE_MARK(ed, xZR);
|
||||
if (la64_lbt) {
|
||||
if (cpuext.lbt) {
|
||||
ADDI_D(x3, xZR, 1 << F_ZF);
|
||||
X64_SET_EFLAGS(x3, X_ZF);
|
||||
} else {
|
||||
@@ -1820,7 +1888,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
CTZ_D(gd, ed);
|
||||
else
|
||||
CTZ_W(gd, ed);
|
||||
if (la64_lbt) {
|
||||
if (cpuext.lbt) {
|
||||
X64_SET_EFLAGS(xZR, X_ZF);
|
||||
} else {
|
||||
BSTRINS_D(xFlags, xZR, F_ZF, F_ZF);
|
||||
@@ -1838,7 +1906,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
ed = x4;
|
||||
}
|
||||
BNE_MARK(ed, xZR);
|
||||
if (la64_lbt) {
|
||||
if (cpuext.lbt) {
|
||||
ADDI_D(x3, xZR, 1 << F_ZF);
|
||||
X64_SET_EFLAGS(x3, X_ZF);
|
||||
} else {
|
||||
@@ -1846,7 +1914,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
}
|
||||
B_NEXT_nocond;
|
||||
MARK;
|
||||
if (la64_lbt) {
|
||||
if (cpuext.lbt) {
|
||||
X64_SET_EFLAGS(xZR, X_ZF);
|
||||
} else {
|
||||
BSTRINS_D(xFlags, xZR, F_ZF, F_ZF);
|
||||
@@ -2123,7 +2191,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
VAVGR_BU(v0, v0, v1);
|
||||
break;
|
||||
case 0xE1:
|
||||
INST_NAME("PSRAW Gm,Em");
|
||||
INST_NAME("PSRAW Gm, Em");
|
||||
nextop = F8;
|
||||
GETGM(v0);
|
||||
GETEM(v1, 0);
|
||||
@@ -2133,12 +2201,12 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
VSRA_H(v0, v0, q0);
|
||||
break;
|
||||
case 0xE2:
|
||||
INST_NAME("PSRAD Gm,Em");
|
||||
INST_NAME("PSRAD Gm, Em");
|
||||
nextop = F8;
|
||||
GETGM(v0);
|
||||
GETEM(v1, 0);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
VMINI_WU(q0, v1, 31);
|
||||
VMINI_DU(q0, v1, 31);
|
||||
VREPLVEI_W(q0, q0, 0);
|
||||
VSRA_W(v0, v0, q0);
|
||||
break;
|
||||
@@ -2147,7 +2215,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
nextop = F8;
|
||||
GETGM(v0);
|
||||
GETEM(v1, 0);
|
||||
VAVG_HU(v0, v0, v1);
|
||||
VAVGR_HU(v0, v0, v1);
|
||||
break;
|
||||
case 0xE4:
|
||||
INST_NAME("PMULHUW Gm,Em");
|
||||
@@ -2191,7 +2259,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
VSSUB_H(v0, v0, q0);
|
||||
break;
|
||||
case 0xEA:
|
||||
INST_NAME("PMINSW Gx,Ex");
|
||||
INST_NAME("PMINSW Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGM(v0);
|
||||
GETEM(v1, 0);
|
||||
|
||||
@@ -252,10 +252,10 @@ uintptr_t dynarec64_64(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
else
|
||||
i64 = F8S;
|
||||
MOV64xw(x5, i64);
|
||||
IFXA (X_ALL, !la64_lbt)
|
||||
IFXA (X_ALL, !cpuext.lbt)
|
||||
ST_D(x6, xEmu, offsetof(x64emu_t, scratch));
|
||||
emit_adc32(dyn, ninst, rex, ed, x5, x3, x4, x6, x7);
|
||||
IFXA (X_ALL, !la64_lbt) {
|
||||
IFXA (X_ALL, !cpuext.lbt) {
|
||||
LD_D(x6, xEmu, offsetof(x64emu_t, scratch));
|
||||
}
|
||||
WBACKO(x6);
|
||||
@@ -444,6 +444,22 @@ uintptr_t dynarec64_64(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else
|
||||
LDXxw(xRAX, x4, x1);
|
||||
break;
|
||||
case 0xA3:
|
||||
INST_NAME("MOV FS:Od, EAX");
|
||||
grab_segdata(dyn, addr, ninst, x4, seg, 0);
|
||||
if (rex.is32bits)
|
||||
u64 = F32;
|
||||
else
|
||||
u64 = F64;
|
||||
if (u64 < 0x800) {
|
||||
ADDIz(x1, x4, u64);
|
||||
} else {
|
||||
MOV64z(x1, u64);
|
||||
ADDz(x1, x1, x4);
|
||||
}
|
||||
SDxw(xRAX, x1, 0);
|
||||
SMWRITE2();
|
||||
break;
|
||||
case 0xC6:
|
||||
INST_NAME("MOV Seg:Eb, Ib");
|
||||
nextop = F8;
|
||||
@@ -502,6 +518,19 @@ uintptr_t dynarec64_64(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0xFF:
|
||||
nextop = F8;
|
||||
switch ((nextop >> 3) & 7) {
|
||||
case 6: // Push Ed
|
||||
INST_NAME("PUSH Ed");
|
||||
grab_segdata(dyn, addr, ninst, x6, seg, (MODREG));
|
||||
GETEDOz(x6, 0, x3);
|
||||
PUSH1z(ed);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
|
||||
@@ -782,7 +782,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
MOV32w(x2, u8);
|
||||
CALL_(rol16, x1, x3);
|
||||
CALL_(const_rol16, x1, x3, x1, x2);
|
||||
EWBACK;
|
||||
break;
|
||||
case 1:
|
||||
@@ -792,7 +792,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
MOV32w(x2, u8);
|
||||
CALL_(ror16, x1, x3);
|
||||
CALL_(const_ror16, x1, x3, x1, x2);
|
||||
EWBACK;
|
||||
break;
|
||||
case 4:
|
||||
@@ -872,7 +872,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
SETFLAGS(X_OF | X_CF, SF_SET_DF, NAT_FLAGS_NOFUSION);
|
||||
if (BOX64DRENV(dynarec_safeflags) > 1) MAYSETFLAGS();
|
||||
GETEW(x1, 1);
|
||||
CALL_(rol16, x1, x3);
|
||||
CALL_(const_rol16, x1, x3, x1, x2);
|
||||
EWBACK;
|
||||
break;
|
||||
case 5:
|
||||
@@ -968,9 +968,9 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
OR(x2, x2, x7);
|
||||
if(BOX64ENV(dynarec_div0)) {
|
||||
BNE_MARK3(ed, xZR);
|
||||
GETIP_(ip);
|
||||
GETIP_(ip, x6);
|
||||
STORE_XEMU_CALL();
|
||||
CALL(native_div0, -1);
|
||||
CALL(const_native_div0, -1, 0, 0);
|
||||
CLEARIP();
|
||||
LOAD_XEMU_CALL();
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
@@ -989,9 +989,9 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
GETSEW(x1, 0);
|
||||
if (BOX64ENV(dynarec_div0)) {
|
||||
BNE_MARK3(ed, xZR);
|
||||
GETIP_(ip);
|
||||
GETIP_(ip, x7);
|
||||
STORE_XEMU_CALL();
|
||||
CALL(native_div0, -1);
|
||||
CALL(const_native_div0, -1, 0, 0);
|
||||
CLEARIP();
|
||||
LOAD_XEMU_CALL();
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
@@ -1026,6 +1026,11 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
emit_dec16(dyn, ninst, x1, x2, x4, x5, x6);
|
||||
EWBACK;
|
||||
break;
|
||||
case 6: // Push Ew
|
||||
INST_NAME("PUSH Ew");
|
||||
GETEW(x1, 0);
|
||||
PUSH1_16(ed);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
|
||||
switch (opcode) {
|
||||
case 0x10:
|
||||
INST_NAME("MOVUPD Gx,Ex");
|
||||
INST_NAME("MOVUPD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
@@ -172,6 +172,11 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
break;
|
||||
case 0x18:
|
||||
case 0x19:
|
||||
case 0x1A:
|
||||
case 0x1B:
|
||||
case 0x1C:
|
||||
case 0x1D:
|
||||
case 0x1E:
|
||||
case 0x1F:
|
||||
INST_NAME("NOP (multibyte)");
|
||||
nextop = F8;
|
||||
@@ -231,7 +236,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
}
|
||||
break;
|
||||
case 0x2C:
|
||||
INST_NAME("CVTTPD2PI Gm,Ex");
|
||||
INST_NAME("CVTTPD2PI Gm, Ex");
|
||||
nextop = F8;
|
||||
GETGM(v0);
|
||||
GETEX(v1, 0, 0);
|
||||
@@ -270,7 +275,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
}
|
||||
break;
|
||||
case 0x2D:
|
||||
INST_NAME("CVTPD2PI Gm,Ex");
|
||||
INST_NAME("CVTPD2PI Gm, Ex");
|
||||
nextop = F8;
|
||||
GETGM(v0);
|
||||
GETEX(v1, 0, 0);
|
||||
@@ -400,19 +405,15 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
VSADD_H(q0, v0, v1);
|
||||
break;
|
||||
case 0x04:
|
||||
INST_NAME("PMADDUBSW Gx,Ex");
|
||||
INST_NAME("PMADDUBSW Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
VEXT2XV_HU_BU(v0, q0);
|
||||
VEXT2XV_H_B(v1, q1);
|
||||
XVMUL_H(v0, v0, v1);
|
||||
XVPERMI_Q(v1, v0, 1); // v1[127:0] = v0[255:128];
|
||||
VPICKEV_H(q0, v1, v0);
|
||||
VPICKOD_H(v0, v1, v0);
|
||||
VSADD_H(q0, v0, q0);
|
||||
VMULWEV_H_BU_B(v0, q0, q1);
|
||||
VMULWOD_H_BU_B(v1, q0, q1);
|
||||
VSADD_H(q0, v0, v1);
|
||||
break;
|
||||
case 0x05:
|
||||
INST_NAME("PHSUBW Gx, Ex");
|
||||
@@ -434,7 +435,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
VPICKEV_W(v0, q1, q0);
|
||||
VPICKOD_W(v1, q1, q0);
|
||||
VSUB_D(q0, v0, v1);
|
||||
VSUB_W(q0, v0, v1);
|
||||
break;
|
||||
case 0x07:
|
||||
INST_NAME("PHSUBSW Gx, Ex");
|
||||
@@ -469,7 +470,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
VSIGNCOV_W(q0, q1, q0);
|
||||
break;
|
||||
case 0x0B:
|
||||
INST_NAME("PMULHRSW Gx,Ex");
|
||||
INST_NAME("PMULHRSW Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
@@ -484,7 +485,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
XVPERMI_D(q0, v0, 0b1000);
|
||||
break;
|
||||
case 0x10:
|
||||
INST_NAME("PBLENDVB Gx,Ex");
|
||||
INST_NAME("PBLENDVB Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
@@ -496,19 +497,19 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
}
|
||||
break;
|
||||
case 0x14:
|
||||
INST_NAME("BLENDVPS Gx,Ex");
|
||||
INST_NAME("BLENDVPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
v0 = sse_get_reg(dyn, ninst, x1, 0, 0); // XMM0
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
if (q0 != q1) {
|
||||
VSRA_W(v1, v0, 31);
|
||||
VSLTI_W(v1, v0, 0);
|
||||
VBITSEL_V(q0, q0, q1, v1);
|
||||
}
|
||||
break;
|
||||
case 0x15:
|
||||
INST_NAME("BLENDVPD Gx,Ex");
|
||||
INST_NAME("BLENDVPD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
@@ -525,7 +526,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
|
||||
GETGX(q0, 0);
|
||||
GETEX(q1, 0, 0);
|
||||
if (!la64_lbt) {
|
||||
if (!cpuext.lbt) {
|
||||
CLEAR_FLAGS(x3);
|
||||
} else IFX (X_ALL) {
|
||||
X64_SET_EFLAGS(xZR, X_ALL);
|
||||
@@ -536,7 +537,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
VAND_V(v0, q1, q0);
|
||||
VSETEQZ_V(fcc0, v0);
|
||||
BCEQZ_MARK(fcc0);
|
||||
if (la64_lbt) {
|
||||
if (cpuext.lbt) {
|
||||
ADDI_D(x3, xZR, 1 << F_ZF);
|
||||
X64_SET_EFLAGS(x3, X_ZF);
|
||||
} else {
|
||||
@@ -548,9 +549,9 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
VANDN_V(v0, q0, q1);
|
||||
VSETEQZ_V(fcc0, v0);
|
||||
BCEQZ_MARK2(fcc0);
|
||||
if (la64_lbt) {
|
||||
if (cpuext.lbt) {
|
||||
ADDI_D(x3, xZR, 1 << F_CF);
|
||||
X64_SET_EFLAGS(x3, X_ZF);
|
||||
X64_SET_EFLAGS(x3, X_CF);
|
||||
} else {
|
||||
ORI(xFlags, xFlags, 1 << F_CF);
|
||||
}
|
||||
@@ -558,7 +559,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
MARK2;
|
||||
break;
|
||||
case 0x1C:
|
||||
INST_NAME("PABSB Gx,Ex");
|
||||
INST_NAME("PABSB Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q1, 0, 0);
|
||||
GETGX_empty(q0);
|
||||
@@ -567,7 +568,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
VABSD_B(q0, q1, v0);
|
||||
break;
|
||||
case 0x1D:
|
||||
INST_NAME("PABSW Gx,Ex");
|
||||
INST_NAME("PABSW Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q1, 0, 0);
|
||||
GETGX_empty(q0);
|
||||
@@ -576,7 +577,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
VABSD_H(q0, q1, v0);
|
||||
break;
|
||||
case 0x1E:
|
||||
INST_NAME("PABSD Gx,Ex");
|
||||
INST_NAME("PABSD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q1, 0, 0);
|
||||
GETGX_empty(q0);
|
||||
@@ -801,7 +802,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
}
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
MOV32w(x1, gd);
|
||||
CALL(native_aesimc, -1);
|
||||
CALL(const_native_aesimc, -1, x1, 0);
|
||||
break;
|
||||
case 0xDC:
|
||||
INST_NAME("AESENC Gx, Ex"); // AES-NI
|
||||
@@ -815,7 +816,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
d0 = -1;
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
MOV32w(x1, gd);
|
||||
CALL(native_aese, -1);
|
||||
CALL(const_native_aese, -1, x1, 0);
|
||||
GETGX(q0, 1);
|
||||
VXOR_V(q0, q0, (d0 != -1) ? d0 : q1);
|
||||
break;
|
||||
@@ -831,7 +832,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
d0 = -1;
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
MOV32w(x1, gd);
|
||||
CALL(native_aeselast, -1);
|
||||
CALL(const_native_aeselast, -1, x1, 0);
|
||||
GETGX(q0, 1);
|
||||
VXOR_V(q0, q0, (d0 != -1) ? d0 : q1);
|
||||
break;
|
||||
@@ -847,7 +848,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
d0 = -1;
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
MOV32w(x1, gd);
|
||||
CALL(native_aesd, -1);
|
||||
CALL(const_native_aesd, -1, x1, 0);
|
||||
GETGX(q0, 1);
|
||||
VXOR_V(q0, q0, (d0 != -1) ? d0 : q1);
|
||||
break;
|
||||
@@ -863,7 +864,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
d0 = -1;
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
MOV32w(x1, gd);
|
||||
CALL(native_aesdlast, -1);
|
||||
CALL(const_native_aesdlast, -1, x1, 0);
|
||||
GETGX(q0, 1);
|
||||
VXOR_V(q0, q0, (d0 != -1) ? d0 : q1);
|
||||
break;
|
||||
@@ -959,7 +960,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
INST_NAME("BLENDPS Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEXSS(q1, 0, 1);
|
||||
GETEX(q1, 0, 1);
|
||||
u8 = F8 & 0b1111;
|
||||
if ((u8 & 0b11) == 0b11) {
|
||||
VEXTRINS_D(q0, q1, 0);
|
||||
@@ -978,7 +979,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
INST_NAME("BLENDPD Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEXSD(q1, 0, 1);
|
||||
GETEX(q1, 0, 1);
|
||||
u8 = F8 & 0b11;
|
||||
if (u8 == 0b01) {
|
||||
VEXTRINS_D(q0, q1, 0b00000000);
|
||||
@@ -1002,8 +1003,8 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
VOR_V(q0, q1, q1);
|
||||
} else {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
VBSLL_V(q0, q0, 16 - u8);
|
||||
VBSRL_V(d0, q1, u8);
|
||||
VBSLL_V(q0, q0, 16 - u8);
|
||||
VOR_V(q0, q0, d0);
|
||||
}
|
||||
break;
|
||||
@@ -1111,7 +1112,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
if (rex.w) {
|
||||
VPICKVE2GR_D(ed, q0, (u8 & 1));
|
||||
} else {
|
||||
VPICKVE2GR_W(ed, q0, (u8 & 3));
|
||||
VPICKVE2GR_WU(ed, q0, (u8 & 3));
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, x5, &fixedaddress, rex, NULL, 1, 1);
|
||||
@@ -1147,7 +1148,15 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
INST_NAME("PINSRB Gx, ED, Ib");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETED(1);
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
wback = 0;
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, NULL, 1, 1);
|
||||
LD_B(x1, wback, fixedaddress);
|
||||
ed = x1;
|
||||
}
|
||||
u8 = F8;
|
||||
VINSGR2VR_B(q0, ed, (u8 & 0xf));
|
||||
break;
|
||||
@@ -1155,21 +1164,19 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
INST_NAME("INSERTPS Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
u8 = F8;
|
||||
uint8_t src_index = (u8 >> 6) & 3;
|
||||
uint8_t dst_index = (u8 >> 4) & 3;
|
||||
uint8_t zmask = u8 & 0xf;
|
||||
q2 = fpu_get_scratch(dyn);
|
||||
if (MODREG) {
|
||||
u8 = F8;
|
||||
q1 = sse_get_reg(dyn, ninst, x1, (nextop & 7) + (rex.b << 3), 0);
|
||||
VEXTRINS_W(q0, q1, VEXTRINS_IMM_4_0(dst_index, src_index));
|
||||
VEXTRINS_W(q0, q1, VEXTRINS_IMM_4_0(((u8 >> 4) & 3), ((u8 >> 6) & 3)));
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, x5, &fixedaddress, rex, NULL, 0, 1);
|
||||
u8 = F8;
|
||||
FLD_S(q2, wback, fixedaddress);
|
||||
VEXTRINS_W(q0, q2, VEXTRINS_IMM_4_0(dst_index, 0)); // src index is zero when Ex is mem operand
|
||||
VEXTRINS_W(q0, q2, VEXTRINS_IMM_4_0(((u8 >> 4) & 3), 0)); // src index is zero when Ex is mem operand
|
||||
}
|
||||
uint8_t zmask = u8 & 0xf;
|
||||
VXOR_V(q2, q2, q2);
|
||||
if (zmask) {
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
@@ -1262,7 +1269,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
}
|
||||
u8 = F8;
|
||||
MOV32w(x4, u8);
|
||||
CALL(native_pclmul, -1);
|
||||
CALL4(const_native_pclmul, -1, x1, x2, x3, x4);
|
||||
break;
|
||||
case 0x61:
|
||||
INST_NAME("PCMPESTRI Gx, Ex, Ib");
|
||||
@@ -1278,15 +1285,15 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
if (ed > 7)
|
||||
sse_reflect_reg(dyn, ninst, ed);
|
||||
ADDI_D(x1, xEmu, offsetof(x64emu_t, xmm[ed]));
|
||||
ed = x1;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x5, &fixedaddress, rex, NULL, 0, 1);
|
||||
if (ed != x1) MV(x1, ed);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x2, &fixedaddress, rex, NULL, 0, 1);
|
||||
}
|
||||
MV(x2, xRDX);
|
||||
MV(x4, xRAX);
|
||||
u8 = F8;
|
||||
MOV32w(x5, u8);
|
||||
CALL(sse42_compare_string_explicit_len, x1);
|
||||
CALL6(const_sse42_compare_string_explicit_len, x1, ed, x2, x3, x4, x5, 0);
|
||||
ZEROUP(x1);
|
||||
BNEZ_MARK(x1);
|
||||
MOV32w(xRCX, (u8 & 1) ? 8 : 16);
|
||||
@@ -1311,13 +1318,13 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
ed = (nextop & 7) + (rex.b << 3);
|
||||
if (ed > 7) sse_reflect_reg(dyn, ninst, ed);
|
||||
ADDI_D(x1, xEmu, offsetof(x64emu_t, xmm[ed]));
|
||||
ed = x1;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x2, &fixedaddress, rex, NULL, 0, 1);
|
||||
if (ed != x1) MV(x1, ed);
|
||||
}
|
||||
u8 = F8;
|
||||
MOV32w(x3, u8);
|
||||
CALL(sse42_compare_string_implicit_len, x1);
|
||||
CALL4(const_sse42_compare_string_implicit_len, x1, ed, x2, x3, 0);
|
||||
BNEZ_MARK(x1);
|
||||
MOV32w(xRCX, (u8 & 1) ? 8 : 16);
|
||||
B_NEXT_nocond;
|
||||
@@ -1350,7 +1357,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
}
|
||||
u8 = F8;
|
||||
MOV32w(x4, u8);
|
||||
CALL(native_aeskeygenassist, -1);
|
||||
CALL4(const_native_aeskeygenassist, -1, x1, x2, x3, x4);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
@@ -1361,7 +1368,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
READFLAGS(F); \
|
||||
tmp1 = x1; \
|
||||
tmp3 = x3; \
|
||||
if (la64_lbt) { \
|
||||
if (cpuext.lbt) { \
|
||||
X64_SETJ(x1, I); \
|
||||
} else { \
|
||||
GETFLAGS; \
|
||||
@@ -1375,7 +1382,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
LD_HU(x4, ed, fixedaddress); \
|
||||
ed = x4; \
|
||||
} \
|
||||
if (la64_lbt) \
|
||||
if (cpuext.lbt) \
|
||||
BEQZ(x1, 4 + 4); \
|
||||
else \
|
||||
B##NO(x1, 4 + 4); \
|
||||
@@ -1605,28 +1612,28 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
break;
|
||||
|
||||
case 0x60:
|
||||
INST_NAME("PUNPCKLBW Gx,Ex");
|
||||
INST_NAME("PUNPCKLBW Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(q0, 0, 0);
|
||||
VILVL_B(v0, q0, v0);
|
||||
break;
|
||||
case 0x61:
|
||||
INST_NAME("PUNPCKLWD Gx,Ex");
|
||||
INST_NAME("PUNPCKLWD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(q0, 0, 0);
|
||||
VILVL_H(v0, q0, v0);
|
||||
break;
|
||||
case 0x62:
|
||||
INST_NAME("PUNPCKLDQ Gx,Ex");
|
||||
INST_NAME("PUNPCKLDQ Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(q0, 0, 0);
|
||||
VILVL_W(v0, q0, v0);
|
||||
break;
|
||||
case 0x63:
|
||||
INST_NAME("PACKSSWB Gx,Ex");
|
||||
INST_NAME("PACKSSWB Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
@@ -1641,21 +1648,21 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
}
|
||||
break;
|
||||
case 0x64:
|
||||
INST_NAME("PCMPGTB Gx,Ex");
|
||||
INST_NAME("PCMPGTB Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
VSLT_B(v0, v1, v0);
|
||||
break;
|
||||
case 0x65:
|
||||
INST_NAME("PCMPGTW Gx,Ex");
|
||||
INST_NAME("PCMPGTW Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
VSLT_H(v0, v1, v0);
|
||||
break;
|
||||
case 0x66:
|
||||
INST_NAME("PCMPGTD Gx,Ex");
|
||||
INST_NAME("PCMPGTD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
@@ -1682,28 +1689,28 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
}
|
||||
break;
|
||||
case 0x68:
|
||||
INST_NAME("PUNPCKHBW Gx,Ex");
|
||||
INST_NAME("PUNPCKHBW Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
VILVH_B(q0, q1, q0);
|
||||
break;
|
||||
case 0x69:
|
||||
INST_NAME("PUNPCKHWD Gx,Ex");
|
||||
INST_NAME("PUNPCKHWD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
VILVH_H(q0, q1, q0);
|
||||
break;
|
||||
case 0x6A:
|
||||
INST_NAME("PUNPCKHDQ Gx,Ex");
|
||||
INST_NAME("PUNPCKHDQ Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
VILVH_W(q0, q1, q0);
|
||||
break;
|
||||
case 0x6B:
|
||||
INST_NAME("PACKSSDW Gx,Ex");
|
||||
INST_NAME("PACKSSDW Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
@@ -1713,7 +1720,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
VOR_V(v0, d0, d0);
|
||||
break;
|
||||
case 0x6C:
|
||||
INST_NAME("PUNPCKLQDQ Gx,Ex");
|
||||
INST_NAME("PUNPCKLQDQ Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
if (MODREG) {
|
||||
@@ -1726,7 +1733,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
VILVL_D(v0, v1, v0); // v0[127:64] = v1[63:0]
|
||||
break;
|
||||
case 0x6D:
|
||||
INST_NAME("PUNPCKHQDQ Gx,Ex");
|
||||
INST_NAME("PUNPCKHQDQ Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
if (MODREG) {
|
||||
@@ -1778,7 +1785,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
}
|
||||
break;
|
||||
case 0x70:
|
||||
INST_NAME("PSHUFD Gx,Ex,Ib");
|
||||
INST_NAME("PSHUFD Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 1);
|
||||
@@ -1932,21 +1939,21 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
}
|
||||
break;
|
||||
case 0x74:
|
||||
INST_NAME("PCMPEQB Gx,Ex");
|
||||
INST_NAME("PCMPEQB Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(q0, 0, 0);
|
||||
VSEQ_B(v0, v0, q0);
|
||||
break;
|
||||
case 0x75:
|
||||
INST_NAME("PCMPEQW Gx,Ex");
|
||||
INST_NAME("PCMPEQW Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(q0, 0, 0);
|
||||
VSEQ_H(v0, v0, q0);
|
||||
break;
|
||||
case 0x76:
|
||||
INST_NAME("PCMPEQD Gx,Ex");
|
||||
INST_NAME("PCMPEQD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(q0, 0, 0);
|
||||
@@ -2047,7 +2054,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETGW(x2);
|
||||
ANDI(gd, gd, 15);
|
||||
SRL_D(x4, ed, gd);
|
||||
if (la64_lbt)
|
||||
if (cpuext.lbt)
|
||||
X64_SET_EFLAGS(x4, X_CF);
|
||||
else
|
||||
BSTRINS_D(xFlags, x4, F_CF, F_CF);
|
||||
@@ -2097,7 +2104,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
u8 &= rex.w ? 0x3f : 15;
|
||||
IFX (X_CF) {
|
||||
BSTRPICK_D(x3, ed, u8, u8);
|
||||
if (la64_lbt) {
|
||||
if (cpuext.lbt) {
|
||||
X64_SET_EFLAGS(x3, X_CF);
|
||||
} else {
|
||||
BSTRINS_D(xFlags, x3, F_CF, F_CF);
|
||||
@@ -2202,10 +2209,15 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
case 0xCF:
|
||||
INST_NAME("BSWAP Reg");
|
||||
gd = TO_NAT((opcode & 7) + (rex.b << 3));
|
||||
REVBxw(gd, gd);
|
||||
if(rex.w){
|
||||
REVB_D(gd, gd);
|
||||
} else {
|
||||
REVB_2H(x2, gd);
|
||||
BSTRINS_D(gd, x2, 15, 0);
|
||||
}
|
||||
break;
|
||||
case 0xD0:
|
||||
INST_NAME("ADDSUBPD Gx,Ex");
|
||||
INST_NAME("ADDSUBPD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
@@ -2215,7 +2227,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
VEXTRINS_D(q0, v0, 0);
|
||||
break;
|
||||
case 0xD1:
|
||||
INST_NAME("PSRLW Gx,Ex");
|
||||
INST_NAME("PSRLW Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
@@ -2234,16 +2246,14 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETEX(q1, 0, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
VSAT_DU(v0, q1, 31);
|
||||
VREPLVEI_W(v0, v0, 0);
|
||||
VLDI(v1, 0b1000000011111); // broadcast 31 as uint32
|
||||
VSLT_WU(v1, v1, v0);
|
||||
VMINI_WU(v0, v0, 31);
|
||||
VSRL_W(q0, q0, v0);
|
||||
VREPLVEI_D(v0, q1, 0);
|
||||
VSLEI_DU(v0, v0, 31);
|
||||
VREPLVEI_W(v1, q1, 0);
|
||||
VSRL_W(q0, q0, v1);
|
||||
VAND_V(q0, q0, v0);
|
||||
break;
|
||||
case 0xD3:
|
||||
INST_NAME("PSRLQ Gx,Ex");
|
||||
INST_NAME("PSRLQ Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
@@ -2252,10 +2262,9 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
VREPLVEI_D(v0, q1, 0);
|
||||
VLDI(v1, 0b0110000111111); // broadcast 63 as uint64
|
||||
VMIN_DU(d0, v0, v1);
|
||||
VSLT_DU(v1, v1, v0);
|
||||
VSRL_D(q0, q0, d0);
|
||||
VSRL_D(q0, q0, v1);
|
||||
VSLE_DU(v1, v0, v1);
|
||||
VSRL_D(q0, q0, v0);
|
||||
VAND_V(q0, q0, v1);
|
||||
break;
|
||||
case 0xD4:
|
||||
INST_NAME("PADDQ Gx, Ex");
|
||||
@@ -2265,7 +2274,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
VADD_D(v0, v0, q0);
|
||||
break;
|
||||
case 0xD5:
|
||||
INST_NAME("PMULLW Gx,Ex");
|
||||
INST_NAME("PMULLW Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
@@ -2325,21 +2334,21 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
VMIN_BU(q0, q0, q1);
|
||||
break;
|
||||
case 0xDB:
|
||||
INST_NAME("PAND Gx,Ex");
|
||||
INST_NAME("PAND Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(q0, 0, 0);
|
||||
VAND_V(v0, v0, q0);
|
||||
break;
|
||||
case 0xDC:
|
||||
INST_NAME("PADDUSB Gx,Ex");
|
||||
INST_NAME("PADDUSB Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
VSADD_BU(q0, q0, q1);
|
||||
break;
|
||||
case 0xDD:
|
||||
INST_NAME("PADDUSW Gx,Ex");
|
||||
INST_NAME("PADDUSW Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
@@ -2353,7 +2362,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
VMAX_BU(q0, q0, q1);
|
||||
break;
|
||||
case 0xDF:
|
||||
INST_NAME("PANDN Gx,Ex");
|
||||
INST_NAME("PANDN Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(q0, 0, 0);
|
||||
@@ -2377,36 +2386,31 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
VSRA_H(q0, q0, v0);
|
||||
break;
|
||||
case 0xE2:
|
||||
INST_NAME("PSRAD Gx,Ex");
|
||||
INST_NAME("PSRAD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
VREPLVEI_D(v0, q1, 0);
|
||||
VSLEI_DU(v1, v0, 31);
|
||||
VREPLVEI_W(v0, q1, 0);
|
||||
VSRAI_W(v2, q0, 31);
|
||||
VMINI_DU(v0, q1, 31);
|
||||
VREPLVEI_W(v0, v0, 0);
|
||||
VSRA_W(q0, q0, v0);
|
||||
VBITSEL_V(q0, v2, q0, v1);
|
||||
break;
|
||||
case 0xE3:
|
||||
INST_NAME("PAVGW Gx,Ex");
|
||||
INST_NAME("PAVGW Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
VAVGR_HU(v0, v0, v1);
|
||||
break;
|
||||
case 0xE4:
|
||||
INST_NAME("PMULHUW Gx,Ex");
|
||||
INST_NAME("PMULHUW Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
VMUH_HU(v0, v0, v1);
|
||||
break;
|
||||
case 0xE5:
|
||||
INST_NAME("PMULHW Gx,Ex");
|
||||
INST_NAME("PMULHW Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
@@ -2417,8 +2421,20 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
nextop = F8;
|
||||
GETEX(v1, 0, 0);
|
||||
GETGX_empty(v0);
|
||||
// TODO: fastround
|
||||
VFTINTRZ_W_D(v0, v1, v1);
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
VFTINTRZ_W_D(d0, v1, v1);
|
||||
VLDI(q0, 0b1001110000000); // broadcast 32bit 0x80000000 to all
|
||||
LU52I_D(x5, xZR, 0x41e);
|
||||
VREPLGR2VR_D(q1, x5);
|
||||
VFCMP_D(q1, q1, v1, cULE);
|
||||
VSHUF4I_W(q1, q1, 0b00001000);
|
||||
VBITSEL_V(v0, d0, q0, q1);
|
||||
} else {
|
||||
VFTINTRZ_W_D(v0, v1, v1);
|
||||
}
|
||||
VINSGR2VR_D(v0, xZR, 1);
|
||||
break;
|
||||
case 0xE7:
|
||||
@@ -2434,56 +2450,56 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
}
|
||||
break;
|
||||
case 0xE8:
|
||||
INST_NAME("PSUBSB Gx,Ex");
|
||||
INST_NAME("PSUBSB Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(q0, 0, 0);
|
||||
VSSUB_B(v0, v0, q0);
|
||||
break;
|
||||
case 0xE9:
|
||||
INST_NAME("PSUBSW Gx,Ex");
|
||||
INST_NAME("PSUBSW Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(q0, 0, 0);
|
||||
VSSUB_H(v0, v0, q0);
|
||||
break;
|
||||
case 0xEA:
|
||||
INST_NAME("PMINSW Gx,Ex");
|
||||
INST_NAME("PMINSW Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(q0, 0, 0);
|
||||
VMIN_H(v0, v0, q0);
|
||||
break;
|
||||
case 0xEB:
|
||||
INST_NAME("POR Gx,Ex");
|
||||
INST_NAME("POR Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(q0, 0, 0);
|
||||
VOR_V(v0, v0, q0);
|
||||
break;
|
||||
case 0xEC:
|
||||
INST_NAME("PADDSB Gx,Ex");
|
||||
INST_NAME("PADDSB Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(q0, 0, 0);
|
||||
VSADD_B(v0, v0, q0);
|
||||
break;
|
||||
case 0xED:
|
||||
INST_NAME("PADDSW Gx,Ex");
|
||||
INST_NAME("PADDSW Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(q0, 0, 0);
|
||||
VSADD_H(v0, v0, q0);
|
||||
break;
|
||||
case 0xEE:
|
||||
INST_NAME("PMAXSW Gx,Ex");
|
||||
INST_NAME("PMAXSW Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(q0, 0, 0);
|
||||
VMAX_H(v0, v0, q0);
|
||||
break;
|
||||
case 0xEF:
|
||||
INST_NAME("PXOR Gx,Ex");
|
||||
INST_NAME("PXOR Gx, Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if (MODREG && ((nextop & 7) + (rex.b << 3) == gd)) {
|
||||
@@ -2503,15 +2519,11 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETEX(q1, 0, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
VREPLVE_H(v1, q1, xZR);
|
||||
VPICKVE2GR_DU(x4, q1, 0);
|
||||
SLTUI(x3, x4, 16);
|
||||
SUB_D(x3, xZR, x3);
|
||||
NOR(x3, x3, xZR);
|
||||
VREPLGR2VR_D(v0, x3);
|
||||
VREPLVEI_D(v0, q1, 0);
|
||||
VSLEI_DU(v0, v0, 15);
|
||||
VREPLVEI_H(v1, q1, 0);
|
||||
VSLL_H(q0, q0, v1);
|
||||
VAND_V(v0, q0, v0);
|
||||
VXOR_V(q0, q0, v0);
|
||||
VAND_V(q0, q0, v0);
|
||||
break;
|
||||
case 0xF2:
|
||||
INST_NAME("PSLLD Gx, Ex");
|
||||
@@ -2520,15 +2532,11 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETEX(q1, 0, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
VREPLVE_W(v1, q1, xZR);
|
||||
VPICKVE2GR_DU(x4, q1, 0);
|
||||
SLTUI(x3, x4, 32);
|
||||
SUB_D(x3, xZR, x3);
|
||||
NOR(x3, x3, xZR);
|
||||
VREPLGR2VR_D(v0, x3);
|
||||
VREPLVEI_D(v0, q1, 0);
|
||||
VSLEI_DU(v0, v0, 31);
|
||||
VREPLVEI_W(v1, q1, 0);
|
||||
VSLL_W(q0, q0, v1);
|
||||
VAND_V(v0, q0, v0);
|
||||
VXOR_V(q0, q0, v0);
|
||||
VAND_V(q0, q0, v0);
|
||||
break;
|
||||
case 0xF3:
|
||||
INST_NAME("PSLLQ Gx, Ex");
|
||||
@@ -2537,15 +2545,11 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETEX(q1, 0, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
VREPLVE_D(v1, q1, xZR);
|
||||
VPICKVE2GR_DU(x4, q1, 0);
|
||||
SLTUI(x3, x4, 64);
|
||||
SUB_D(x3, xZR, x3);
|
||||
NOR(x3, x3, xZR);
|
||||
VREPLGR2VR_D(v0, x3);
|
||||
VSLL_D(q0, q0, v1);
|
||||
VAND_V(v0, q0, v0);
|
||||
VXOR_V(q0, q0, v0);
|
||||
VREPLVEI_D(v0, q1, 0);
|
||||
VLDI(v1, (0b011 << 10) | 0x3f);
|
||||
VSLE_DU(v1, v0, v1);
|
||||
VSLL_D(q0, q0, v0);
|
||||
VAND_V(q0, q0, v1);
|
||||
break;
|
||||
case 0xF4:
|
||||
INST_NAME("PMULUDQ Gx,Ex");
|
||||
@@ -2597,14 +2601,14 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
VSUB_B(v0, v0, q0);
|
||||
break;
|
||||
case 0xF9:
|
||||
INST_NAME("PSUBW Gx,Ex");
|
||||
INST_NAME("PSUBW Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(q0, 0, 0);
|
||||
VSUB_H(v0, v0, q0);
|
||||
break;
|
||||
case 0xFA:
|
||||
INST_NAME("PSUBD Gx,Ex");
|
||||
INST_NAME("PSUBD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(q0, 0, 0);
|
||||
|
||||
@@ -53,7 +53,6 @@ uintptr_t dynarec64_66F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
case 0x81:
|
||||
case 0x83:
|
||||
nextop = F8;
|
||||
SMDMB();
|
||||
switch ((nextop >> 3) & 7) {
|
||||
case 0: // ADD
|
||||
if (opcode == 0x81) {
|
||||
@@ -80,7 +79,7 @@ uintptr_t dynarec64_66F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
u64 = (uint16_t)(int16_t)F8S;
|
||||
MOV64x(x5, u64);
|
||||
|
||||
if (la64_lam_bh) {
|
||||
if (cpuext.lam_bh) {
|
||||
AMADD_DB_H(x1, x5, wback);
|
||||
} else {
|
||||
ANDI(x3, wback, 0b10);
|
||||
@@ -119,7 +118,6 @@ uintptr_t dynarec64_66F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
SMDMB();
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -57,16 +57,17 @@ uintptr_t dynarec64_66F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, in
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
VINSGR2VR_H(v0, ed, 0);
|
||||
VPCNT_H(v0, v0);
|
||||
VPICKVE2GR_HU(gd, v0, 0);
|
||||
VPICKVE2GR_HU(x2, v0, 0);
|
||||
BSTRINS_D(gd, x2, 15, 0);
|
||||
IFX (X_ALL) {
|
||||
if (la64_lbt) {
|
||||
if (cpuext.lbt) {
|
||||
X64_SET_EFLAGS(xZR, X_ALL);
|
||||
BNEZ_MARK(gd);
|
||||
BNEZ_MARK(x2);
|
||||
ADDI_D(x5, xZR, 1 << F_ZF);
|
||||
X64_SET_EFLAGS(x5, X_ZF);
|
||||
} else {
|
||||
CLEAR_FLAGS(x2);
|
||||
BNEZ_MARK(gd);
|
||||
CLEAR_FLAGS(x5);
|
||||
BNEZ_MARK(x2);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
MARK;
|
||||
|
||||
@@ -60,6 +60,47 @@ uintptr_t dynarec64_67(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
}
|
||||
|
||||
switch(opcode) {
|
||||
case 0x0F:
|
||||
opcode = F8;
|
||||
switch (opcode) {
|
||||
case 0xB6:
|
||||
INST_NAME("MOVZX Gd, Eb");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if (MODREG) {
|
||||
ed = (nextop & 7) + (rex.b << 3);
|
||||
if (rex.rex) {
|
||||
eb1 = TO_NAT(ed);
|
||||
eb2 = 0;
|
||||
} else {
|
||||
eb1 = TO_NAT(ed & 3); // Ax, Cx, Dx or Bx
|
||||
eb2 = ((ed & 4) << 1); // L or H
|
||||
}
|
||||
BSTRPICK_D(gd, eb1, eb2 + 7, eb2);
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
LD_BU(gd, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0xB7:
|
||||
INST_NAME("MOVZX Gd, Ew");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
BSTRPICK_D(gd, ed, 15, 0);
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
LD_HU(gd, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x19:
|
||||
INST_NAME("SBB Ed, Gd");
|
||||
READFLAGS(X_CF);
|
||||
@@ -97,6 +138,140 @@ uintptr_t dynarec64_67(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
MOV64xw(x2, i64);
|
||||
emit_sbb32(dyn, ninst, rex, xRAX, x2, x3, x4, x5);
|
||||
break;
|
||||
|
||||
case 0x81:
|
||||
case 0x83:
|
||||
nextop = F8;
|
||||
switch ((nextop >> 3) & 7) {
|
||||
case 0: // ADD
|
||||
if (opcode == 0x81) {
|
||||
INST_NAME("ADD Ed, Id");
|
||||
} else {
|
||||
INST_NAME("ADD Ed, Ib");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETED32((opcode == 0x81) ? 4 : 1);
|
||||
if (opcode == 0x81)
|
||||
i64 = F32S;
|
||||
else
|
||||
i64 = F8S;
|
||||
emit_add32c(dyn, ninst, rex, ed, i64, x3, x4, x5, x6);
|
||||
WBACK;
|
||||
break;
|
||||
case 1: // OR
|
||||
if (opcode == 0x81) {
|
||||
INST_NAME("OR Ed, Id");
|
||||
} else {
|
||||
INST_NAME("OR Ed, Ib");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETED32((opcode == 0x81) ? 4 : 1);
|
||||
if (opcode == 0x81)
|
||||
i64 = F32S;
|
||||
else
|
||||
i64 = F8S;
|
||||
emit_or32c(dyn, ninst, rex, ed, i64, x3, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 2: // ADC
|
||||
if (opcode == 0x81) {
|
||||
INST_NAME("ADC Ed, Id");
|
||||
} else {
|
||||
INST_NAME("ADC Ed, Ib");
|
||||
}
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETED32((opcode == 0x81) ? 4 : 1);
|
||||
if (opcode == 0x81)
|
||||
i64 = F32S;
|
||||
else
|
||||
i64 = F8S;
|
||||
MOV64xw(x5, i64);
|
||||
emit_adc32(dyn, ninst, rex, ed, x5, x3, x4, x5, x6);
|
||||
WBACK;
|
||||
break;
|
||||
case 3: // SBB
|
||||
if (opcode == 0x81) {
|
||||
INST_NAME("SBB Ed, Id");
|
||||
} else {
|
||||
INST_NAME("SBB Ed, Ib");
|
||||
}
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETED32((opcode == 0x81) ? 4 : 1);
|
||||
if (opcode == 0x81)
|
||||
i64 = F32S;
|
||||
else
|
||||
i64 = F8S;
|
||||
MOV64xw(x5, i64);
|
||||
emit_sbb32(dyn, ninst, rex, ed, x5, x3, x4, x5);
|
||||
WBACK;
|
||||
break;
|
||||
case 4: // AND
|
||||
if (opcode == 0x81) {
|
||||
INST_NAME("AND Ed, Id");
|
||||
} else {
|
||||
INST_NAME("AND Ed, Ib");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETED32((opcode == 0x81) ? 4 : 1);
|
||||
if (opcode == 0x81)
|
||||
i64 = F32S;
|
||||
else
|
||||
i64 = F8S;
|
||||
emit_and32c(dyn, ninst, rex, ed, i64, x3, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 5: // SUB
|
||||
if (opcode == 0x81) {
|
||||
INST_NAME("SUB Ed, Id");
|
||||
} else {
|
||||
INST_NAME("SUB Ed, Ib");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETED32((opcode == 0x81) ? 4 : 1);
|
||||
if (opcode == 0x81)
|
||||
i64 = F32S;
|
||||
else
|
||||
i64 = F8S;
|
||||
emit_sub32c(dyn, ninst, rex, ed, i64, x3, x4, x5, x6);
|
||||
WBACK;
|
||||
break;
|
||||
case 6: // XOR
|
||||
if (opcode == 0x81) {
|
||||
INST_NAME("XOR Ed, Id");
|
||||
} else {
|
||||
INST_NAME("XOR Ed, Ib");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETED32((opcode == 0x81) ? 4 : 1);
|
||||
if (opcode == 0x81)
|
||||
i64 = F32S;
|
||||
else
|
||||
i64 = F8S;
|
||||
emit_xor32c(dyn, ninst, rex, ed, i64, x3, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 7: // CMP
|
||||
if (opcode == 0x81) {
|
||||
INST_NAME("CMP Ed, Id");
|
||||
} else {
|
||||
INST_NAME("CMP Ed, Ib");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETED32((opcode == 0x81) ? 4 : 1);
|
||||
if (opcode == 0x81)
|
||||
i64 = F32S;
|
||||
else
|
||||
i64 = F8S;
|
||||
if (i64) {
|
||||
MOV64x(x2, i64);
|
||||
emit_cmp32(dyn, ninst, rex, ed, x2, x3, x4, x5, x6);
|
||||
} else
|
||||
emit_cmp32_0(dyn, ninst, rex, nextop, ed, x3, x4, x5);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x88:
|
||||
INST_NAME("MOV Eb, Gb");
|
||||
nextop = F8;
|
||||
@@ -142,6 +317,18 @@ uintptr_t dynarec64_67(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
SMWRITELOCK(lock);
|
||||
}
|
||||
break;
|
||||
case 0x8B:
|
||||
INST_NAME("MOV Gd, Ed");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if (MODREG) {
|
||||
MVxw(gd, TO_NAT((nextop & 7) + (rex.b << 3)));
|
||||
} else {
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, &lock, 1, 0);
|
||||
SMREADLOCK(lock);
|
||||
LDxw(gd, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0x8D:
|
||||
INST_NAME("LEA Gd, Ed");
|
||||
nextop = F8;
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
|
||||
#include "la64_printer.h"
|
||||
#include "dynarec_la64_private.h"
|
||||
#include "dynarec_la64_functions.h"
|
||||
#include "dynarec_la64_helper.h"
|
||||
|
||||
static const char* avx_prefix_string(uint16_t p)
|
||||
{
|
||||
switch (p) {
|
||||
case VEX_P_NONE: return "0";
|
||||
case VEX_P_66: return "66";
|
||||
case VEX_P_F2: return "F2";
|
||||
case VEX_P_F3: return "F3";
|
||||
default: return "??";
|
||||
}
|
||||
}
|
||||
static const char* avx_map_string(uint16_t m)
|
||||
{
|
||||
switch (m) {
|
||||
case VEX_M_NONE: return "0";
|
||||
case VEX_M_0F: return "0F";
|
||||
case VEX_M_0F38: return "0F38";
|
||||
case VEX_M_0F3A: return "0F3A";
|
||||
default: return "??";
|
||||
}
|
||||
}
|
||||
|
||||
uintptr_t dynarec64_AVX(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip;
|
||||
(void)need_epilog;
|
||||
|
||||
uint8_t opcode = PK(0);
|
||||
rex_t rex = vex.rex;
|
||||
|
||||
|
||||
if ((vex.m == VEX_M_0F) && (vex.p == VEX_P_NONE))
|
||||
addr = dynarec64_AVX_0F(dyn, addr, ip, ninst, vex, ok, need_epilog);
|
||||
else if ((vex.m == VEX_M_0F38) && (vex.p == VEX_P_NONE))
|
||||
addr = dynarec64_AVX_0F38(dyn, addr, ip, ninst, vex, ok, need_epilog);
|
||||
else if ((vex.m == VEX_M_0F) && (vex.p == VEX_P_66))
|
||||
addr = dynarec64_AVX_66_0F(dyn, addr, ip, ninst, vex, ok, need_epilog);
|
||||
else if ((vex.m == VEX_M_0F) && (vex.p == VEX_P_F2))
|
||||
addr = dynarec64_AVX_F2_0F(dyn, addr, ip, ninst, vex, ok, need_epilog);
|
||||
else if ((vex.m == VEX_M_0F) && (vex.p == VEX_P_F3))
|
||||
addr = dynarec64_AVX_F3_0F(dyn, addr, ip, ninst, vex, ok, need_epilog);
|
||||
else if ((vex.m == VEX_M_0F38) && (vex.p == VEX_P_66))
|
||||
addr = dynarec64_AVX_66_0F38(dyn, addr, ip, ninst, vex, ok, need_epilog);
|
||||
else if ((vex.m == VEX_M_0F3A) && (vex.p == VEX_P_66))
|
||||
addr = dynarec64_AVX_66_0F3A(dyn, addr, ip, ninst, vex, ok, need_epilog);
|
||||
else if( (vex.m == VEX_M_0F38) && (vex.p == VEX_P_F2))
|
||||
addr = dynarec64_AVX_F2_0F38(dyn, addr, ip, ninst, vex, ok, need_epilog);
|
||||
else if ((vex.m == VEX_M_0F3A) && (vex.p == VEX_P_F2))
|
||||
addr = dynarec64_AVX_F2_0F3A(dyn, addr, ip, ninst, vex, ok, need_epilog);
|
||||
else if( (vex.m==VEX_M_0F38) && (vex.p==VEX_P_F3))
|
||||
addr = dynarec64_AVX_F3_0F38(dyn, addr, ip, ninst, vex, ok, need_epilog);
|
||||
else {
|
||||
DEFAULT;
|
||||
}
|
||||
|
||||
if ((*ok == -1) && (BOX64ENV(dynarec_log) >= LOG_INFO || dyn->need_dump || BOX64ENV(dynarec_missing)))
|
||||
if (!dyn->size || BOX64ENV(dynarec_log) > LOG_INFO || dyn->need_dump) {
|
||||
dynarec_log(LOG_NONE, " Dynarec unimplemented VEX opcode size %d prefix %s map %s opcode %02X\n", 128 << vex.l, avx_prefix_string(vex.p), avx_map_string(vex.m), opcode);
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,624 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "env.h"
|
||||
#include "box64context.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
|
||||
#include "la64_printer.h"
|
||||
#include "dynarec_la64_private.h"
|
||||
#include "dynarec_la64_functions.h"
|
||||
#include "../dynarec_helper.h"
|
||||
|
||||
uintptr_t dynarec64_AVX_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip;
|
||||
(void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop, u8;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback, wb1, wb2;
|
||||
uint8_t eb1, eb2, gb1, gb2;
|
||||
int32_t i32, i32_;
|
||||
int cacheupd = 0;
|
||||
int v0, v1, v2;
|
||||
int q0, q1, q2;
|
||||
int d0, d1, d2;
|
||||
int s0;
|
||||
uint64_t tmp64u;
|
||||
int64_t j64;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
MAYUSE(wb1);
|
||||
MAYUSE(wb2);
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
MAYUSE(gb1);
|
||||
MAYUSE(gb2);
|
||||
MAYUSE(q0);
|
||||
MAYUSE(q1);
|
||||
MAYUSE(d0);
|
||||
MAYUSE(d1);
|
||||
MAYUSE(s0);
|
||||
MAYUSE(j64);
|
||||
MAYUSE(cacheupd);
|
||||
|
||||
rex_t rex = vex.rex;
|
||||
|
||||
switch (opcode) {
|
||||
case 0x10:
|
||||
INST_NAME("VMOVUPS Gx, Ex");
|
||||
nextop = F8;
|
||||
if (MODREG) {
|
||||
GETGY_empty_EY_xy(q0, q1, 0);
|
||||
if (vex.l) {
|
||||
XVOR_V(q0, q1, q1);
|
||||
} else {
|
||||
VOR_V(q0, q1, q1);
|
||||
}
|
||||
} else {
|
||||
GETGYxy_empty(q0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
if (vex.l) {
|
||||
XVLD(q0, ed, fixedaddress);
|
||||
} else {
|
||||
VLD(q0, ed, fixedaddress);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x11:
|
||||
INST_NAME("VMOVUPS Ex, Gx");
|
||||
nextop = F8;
|
||||
GETGYxy(q0, 0);
|
||||
if (MODREG) {
|
||||
GETEYxy_empty(q1, 0);
|
||||
if (vex.l) {
|
||||
XVOR_V(q1, q0, q0);
|
||||
} else {
|
||||
VOR_V(q1, q0, q0);
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x4, x5, &fixedaddress, rex, NULL, 1, 0);
|
||||
if (vex.l) {
|
||||
XVST(q0, ed, fixedaddress);
|
||||
} else {
|
||||
VST(q0, ed, fixedaddress);
|
||||
}
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x12:
|
||||
nextop = F8;
|
||||
GETVYx(v1, 0);
|
||||
if (MODREG) {
|
||||
INST_NAME("VMOVHLPS Gx, Vx, Ex");
|
||||
GETEYx(v2, 0, 0);
|
||||
GETGYx_empty(v0);
|
||||
VEXTRINS_D(v0, v2, VEXTRINS_IMM_4_0(0, 1));
|
||||
VEXTRINS_D(v0, v1, VEXTRINS_IMM_4_0(1, 1));
|
||||
} else {
|
||||
INST_NAME("VMOVLPS Gx, Vx, Ex");
|
||||
GETEYSD(v2, 0, 0);
|
||||
GETGYx_empty(v0);
|
||||
VEXTRINS_D(v0, v2, VEXTRINS_IMM_4_0(0, 0));
|
||||
VEXTRINS_D(v0, v1, VEXTRINS_IMM_4_0(1, 1));
|
||||
}
|
||||
break;
|
||||
case 0x13:
|
||||
nextop = F8;
|
||||
INST_NAME("VMOVLPS Ex, Gx");
|
||||
GETGYx(v0, 0);
|
||||
if (MODREG) {
|
||||
DEFAULT;
|
||||
return addr;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x4, x5, &fixedaddress, rex, NULL, 1, 0);
|
||||
FST_D(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x14:
|
||||
INST_NAME("VUNPCKLPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
|
||||
VILVLxy(W, v0, v2, v1);
|
||||
break;
|
||||
case 0x15:
|
||||
INST_NAME("VUNPCKHPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
|
||||
VILVHxy(W, v0, v2, v1);
|
||||
break;
|
||||
case 0x16:
|
||||
nextop = F8;
|
||||
GETVYx(v1, 0);
|
||||
if (MODREG) {
|
||||
INST_NAME("VMOVLHPS Gx, Vx, Ex");
|
||||
GETEYx(v2, 0, 0);
|
||||
GETGYx_empty(v0);
|
||||
VEXTRINS_D(v0, v2, VEXTRINS_IMM_4_0(1, 0));
|
||||
VEXTRINS_D(v0, v1, VEXTRINS_IMM_4_0(0, 0));
|
||||
} else {
|
||||
INST_NAME("VMOVHPS Gx, Vx, Ex");
|
||||
GETEYSD(v2, 0, 0);
|
||||
GETGYx_empty(v0);
|
||||
VEXTRINS_D(v0, v2, VEXTRINS_IMM_4_0(1, 0));
|
||||
VEXTRINS_D(v0, v1, VEXTRINS_IMM_4_0(0, 0));
|
||||
}
|
||||
break;
|
||||
case 0x17:
|
||||
nextop = F8;
|
||||
INST_NAME("VMOVHPS Ex, Gx");
|
||||
GETGYx(v0, 0);
|
||||
if (MODREG) {
|
||||
DEFAULT;
|
||||
return addr;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x4, x5, &fixedaddress, rex, NULL, 0, 0);
|
||||
VSTELM_D(v0, ed, fixedaddress, 1);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x28:
|
||||
INST_NAME("VMOVAPS Gx, Ex");
|
||||
nextop = F8;
|
||||
if (MODREG) {
|
||||
GETGY_empty_EY_xy(q0, q1, 0);
|
||||
if (vex.l) {
|
||||
XVOR_V(q0, q1, q1);
|
||||
} else {
|
||||
VOR_V(q0, q1, q1);
|
||||
}
|
||||
} else {
|
||||
GETGYxy_empty(q0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x4, x5, &fixedaddress, rex, NULL, 1, 0);
|
||||
if (vex.l) {
|
||||
XVLD(q0, ed, fixedaddress);
|
||||
} else {
|
||||
VLD(q0, ed, fixedaddress);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x29:
|
||||
INST_NAME("VMOVAPS Ex, Gx");
|
||||
nextop = F8;
|
||||
GETGYxy(q0, 0);
|
||||
if (MODREG) {
|
||||
GETEYxy_empty(q1, 0);
|
||||
if (vex.l) {
|
||||
XVOR_V(q1, q0, q0);
|
||||
} else {
|
||||
VOR_V(q1, q0, q0);
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x4, x5, &fixedaddress, rex, NULL, 1, 0);
|
||||
if (vex.l) {
|
||||
XVST(q0, ed, fixedaddress);
|
||||
} else {
|
||||
VST(q0, ed, fixedaddress);
|
||||
}
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x2B:
|
||||
INST_NAME("VMOVNTPS Ex, Gx");
|
||||
nextop = F8;
|
||||
GETGYxy(q0, 0);
|
||||
if (MODREG) {
|
||||
DEFAULT;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x4, x5, &fixedaddress, rex, NULL, 1, 0);
|
||||
if (vex.l) {
|
||||
XVST(q0, ed, fixedaddress);
|
||||
} else {
|
||||
VST(q0, ed, fixedaddress);
|
||||
}
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x2E:
|
||||
// no special check...
|
||||
case 0x2F:
|
||||
if (opcode == 0x2F) {
|
||||
INST_NAME("VCOMISS Gx, Ex");
|
||||
} else {
|
||||
INST_NAME("VUCOMISS Gx, Ex");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETGYx(d0, 0);
|
||||
GETEYSS(v0, 0, 0);
|
||||
CLEAR_FLAGS(x2);
|
||||
// if isnan(d0) || isnan(v0)
|
||||
IFX (X_ZF | X_PF | X_CF) {
|
||||
FCMP_S(fcc0, d0, v0, cUN);
|
||||
BCEQZ_MARK(fcc0);
|
||||
ORI(xFlags, xFlags, (1 << F_ZF) | (1 << F_PF) | (1 << F_CF));
|
||||
B_MARK3_nocond;
|
||||
}
|
||||
MARK;
|
||||
// else if isless(d0, v0)
|
||||
IFX (X_CF) {
|
||||
FCMP_S(fcc1, d0, v0, cLT);
|
||||
BCEQZ_MARK2(fcc1);
|
||||
ORI(xFlags, xFlags, 1 << F_CF);
|
||||
B_MARK3_nocond;
|
||||
}
|
||||
MARK2;
|
||||
// else if d0 == v0
|
||||
IFX (X_ZF) {
|
||||
FCMP_S(fcc2, d0, v0, cEQ);
|
||||
BCEQZ_MARK3(fcc2);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
MARK3;
|
||||
IFX (X_ALL) {
|
||||
SPILL_EFLAGS();
|
||||
}
|
||||
break;
|
||||
case 0x50:
|
||||
nextop = F8;
|
||||
INST_NAME("VMOVMSKPS Gd, Ex");
|
||||
GETEYxy(v0, 0, 0);
|
||||
GETGD;
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
if (vex.l) {
|
||||
XVMSKLTZ_W(d1, v0);
|
||||
XVPICKVE2GR_DU(gd, d1, 0);
|
||||
XVPICKVE2GR_DU(x4, d1, 2);
|
||||
BSTRINS_D(gd, x4, 7, 4);
|
||||
} else {
|
||||
VMSKLTZ_W(d1, v0);
|
||||
VPICKVE2GR_DU(gd, d1, 0);
|
||||
}
|
||||
break;
|
||||
case 0x51:
|
||||
INST_NAME("VSQRTPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGY_empty_EY_xy(v0, v1, 0);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
VFCMPxy(S, d0, v1, v1, cEQ);
|
||||
VFSQRTxy(S, v0, v1);
|
||||
VFCMPxy(S, d1, v0, v0, cEQ);
|
||||
VANDN_Vxy(d1, d1, d0);
|
||||
VSLLIxy(W, d1, d1, 31);
|
||||
VOR_Vxy(v0, v0, d1);
|
||||
} else {
|
||||
VFSQRTxy(S, v0, v1);
|
||||
}
|
||||
break;
|
||||
case 0x52:
|
||||
INST_NAME("VRSQRTPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGY_empty_EY_xy(v0, v1, 0);
|
||||
if (cpuext.frecipe) {
|
||||
VFRSQRTExy(S, v0, v1);
|
||||
} else {
|
||||
VFRSQRTxy(S, v0, v1);
|
||||
}
|
||||
break;
|
||||
case 0x53:
|
||||
INST_NAME("VRCPPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGY_empty_EY_xy(v0, v1, 0);
|
||||
if (cpuext.frecipe) {
|
||||
VFRECIPExy(S, v0, v1);
|
||||
} else {
|
||||
VFRECIPxy(S, v0, v1);
|
||||
}
|
||||
break;
|
||||
case 0x54:
|
||||
INST_NAME("VANDPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
|
||||
VAND_Vxy(v0, v1, v2);
|
||||
break;
|
||||
case 0x55:
|
||||
INST_NAME("VANDNPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
|
||||
VANDN_Vxy(v0, v1, v2);
|
||||
break;
|
||||
case 0x56:
|
||||
INST_NAME("VORPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
|
||||
VOR_Vxy(v0, v1, v2);
|
||||
break;
|
||||
case 0x57:
|
||||
INST_NAME("VXORPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
|
||||
VXOR_Vxy(v0, v1, v2);
|
||||
break;
|
||||
case 0x58:
|
||||
INST_NAME("VADDPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
VFCMPxy(S, d0, v1, v2, cUN);
|
||||
}
|
||||
VFADDxy(S, v0, v1, v2);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
VFCMPxy(S, d1, v0, v0, cUN);
|
||||
VANDN_Vxy(d0, d0, d1);
|
||||
VLDIxy(d1, (0b010 << 9) | 0b1111111100);
|
||||
VSLLIxy(W, d1, d1, 20); // broadcast 0xFFC00000
|
||||
VBITSEL_Vxy(v0, v0, d1, d0);
|
||||
}
|
||||
break;
|
||||
case 0x59:
|
||||
INST_NAME("VMULPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
VFCMPxy(S, d0, v1, v2, cUN);
|
||||
}
|
||||
VFMULxy(S, v0, v1, v2);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
VFCMPxy(S, d1, v0, v0, cUN);
|
||||
VANDN_Vxy(d0, d0, d1);
|
||||
VLDIxy(d1, (0b010 << 9) | 0b1111111100);
|
||||
VSLLIxy(W, d1, d1, 20); // broadcast 0xFFC00000
|
||||
VBITSEL_Vxy(v0, v0, d1, d0);
|
||||
}
|
||||
break;
|
||||
case 0x5A:
|
||||
INST_NAME("VCVTPS2PD Gx, Ex");
|
||||
nextop = F8;
|
||||
if(vex.l){
|
||||
GETEYx(v1, 0 ,0);
|
||||
} else {
|
||||
GETEYSD(v1, 0, 0);
|
||||
}
|
||||
GETGYxy_empty(v0);
|
||||
if(!BOX64ENV(dynarec_fastround)) {
|
||||
u8 = sse_setround(dyn, ninst, x6, x4);
|
||||
}
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
if(vex.l) {
|
||||
XVFCVTH_D_S(d0, v1);
|
||||
XVFCVTL_D_S(v0, v1);
|
||||
XVPERMI_Q(v0, d0, XVPERMI_IMM_4_0(0, 2));
|
||||
} else {
|
||||
VFCVTL_D_S(v0, v1);
|
||||
}
|
||||
if(!BOX64ENV(dynarec_fastround)) {
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
}
|
||||
break;
|
||||
case 0x5B:
|
||||
INST_NAME("VCVTDQ2PS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEYxy(v1, 0, 0);
|
||||
GETGYxy_empty(v0);
|
||||
if(vex.l){
|
||||
XVFFINT_S_W(v0, v1);
|
||||
}else{
|
||||
VFFINT_S_W(v0, v1);
|
||||
}
|
||||
break;
|
||||
case 0x5C:
|
||||
INST_NAME("VSUBPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
VFCMPxy(S, d0, v1, v2, cUN);
|
||||
}
|
||||
VFSUBxy(S, v0, v1, v2);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
VFCMPxy(S, d1, v0, v0, cUN);
|
||||
VANDN_Vxy(d0, d0, d1);
|
||||
VLDIxy(d1, (0b010 << 9) | 0b1111111100);
|
||||
VSLLIxy(W, d1, d1, 20); // broadcast 0xFFC00000
|
||||
VBITSEL_Vxy(v0, v0, d1, d0);
|
||||
}
|
||||
break;
|
||||
case 0x5D:
|
||||
INST_NAME("VMINPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
|
||||
if (BOX64ENV(dynarec_fastnan)) {
|
||||
VFMINxy(S, v0, v2, v1);
|
||||
} else {
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
VFCMPxy(S, q0, v2, v1, cULE);
|
||||
VBITSEL_Vxy(v0, v1, v2, q0);
|
||||
}
|
||||
break;
|
||||
case 0x5E:
|
||||
INST_NAME("VDIVPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
VFCMPxy(S, d0, v1, v2, cUN);
|
||||
}
|
||||
VFDIVxy(S, v0, v1, v2);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
VFCMPxy(S, d1, v0, v0, cUN);
|
||||
VANDN_Vxy(d0, d0, d1);
|
||||
VLDIxy(d1, (0b010 << 9) | 0b1111111100);
|
||||
VSLLIxy(W, d1, d1, 20); // broadcast 0xFFC00000
|
||||
VBITSEL_Vxy(v0, v0, d1, d0);
|
||||
}
|
||||
break;
|
||||
case 0x5F:
|
||||
INST_NAME("VMAXPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
|
||||
if (BOX64ENV(dynarec_fastnan)) {
|
||||
VFMAXxy(S, v0, v2, v1);
|
||||
} else {
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
VFCMPxy(S, q0, v2, v1, cLT);
|
||||
VBITSEL_Vxy(v0, v2, v1, q0);
|
||||
}
|
||||
break;
|
||||
case 0x77:
|
||||
if (!vex.l) {
|
||||
INST_NAME("VZEROUPPER");
|
||||
if (vex.v != 0) {
|
||||
UDF();
|
||||
} else {
|
||||
q2 = fpu_get_scratch(dyn);
|
||||
XVXOR_V(q2, q2, q2);
|
||||
for (int i = 0; i < (rex.is32bits ? 8 : 16); ++i) {
|
||||
if (dyn->lsx.avxcache[i].v != -1) {
|
||||
// avx used register
|
||||
if (dyn->lsx.avxcache[i].width == LSX_AVX_WIDTH_256) {
|
||||
// 256 width, fill upper 128bits with zero.
|
||||
q1 = avx_get_reg(dyn, ninst, x1, i, 1, LSX_AVX_WIDTH_256); // mark reg write (dirty)
|
||||
XVPERMI_Q(q1, q2, XVPERMI_IMM_4_0(0, 2));
|
||||
} else {
|
||||
// 128 width, lazy save.
|
||||
q1 = avx_get_reg(dyn, ninst, x1, i, 1, LSX_AVX_WIDTH_128); // mark reg write (dirty)
|
||||
dyn->lsx.avxcache[i].zero_upper = 1;
|
||||
}
|
||||
} else {
|
||||
// SSE register or unused register, store 128bit zero to x64emu_t.ymm[]
|
||||
VST(q2, xEmu, offsetof(x64emu_t, ymm[i]));
|
||||
}
|
||||
}
|
||||
SMWRITE2();
|
||||
}
|
||||
} else {
|
||||
INST_NAME("VZEROALL");
|
||||
if (vex.v != 0) {
|
||||
UDF();
|
||||
} else {
|
||||
for (int i = 0; i < (rex.is32bits ? 8 : 16); ++i) {
|
||||
q0 = avx_get_reg_empty(dyn, ninst, x1, i, LSX_AVX_WIDTH_256);
|
||||
XVXOR_V(q0, q0, q0);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xAE:
|
||||
nextop = F8;
|
||||
if (MODREG) {
|
||||
DEFAULT;
|
||||
} else
|
||||
switch ((nextop >> 3) & 7) {
|
||||
case 2:
|
||||
INST_NAME("VLDMXCSR Md");
|
||||
GETED(0);
|
||||
ST_W(ed, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
if (BOX64ENV(sse_flushto0)) {
|
||||
/* LA <-> x86
|
||||
16/24 <-> 5 inexact
|
||||
17/25 <-> 4 underflow
|
||||
18/26 <-> 3 overflow
|
||||
19/27 <-> 2 divide by zero
|
||||
x <-> 1 denormal
|
||||
20/28 <-> 0 invalid operation
|
||||
*/
|
||||
// Doing x86 -> LA here, ignore denormal
|
||||
XOR(x4, x4, x4);
|
||||
BSTRPICK_W(x3, ed, 5, 5);
|
||||
BSTRINS_W(x4, x3, 16, 16);
|
||||
BSTRPICK_W(x3, ed, 4, 4);
|
||||
BSTRINS_W(x4, x3, 17, 17);
|
||||
BSTRPICK_W(x3, ed, 3, 3);
|
||||
BSTRINS_W(x4, x3, 18, 18);
|
||||
BSTRPICK_W(x3, ed, 2, 2);
|
||||
BSTRINS_W(x4, x3, 19, 19);
|
||||
BSTRPICK_W(x3, ed, 0, 0);
|
||||
BSTRINS_W(x4, x3, 20, 20);
|
||||
MOVGR2FCSR(FCSR2, x4);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("VSTMXCSR Md");
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, x2, &fixedaddress, rex, NULL, 0, 0);
|
||||
LD_WU(x4, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
if (BOX64ENV(sse_flushto0)) {
|
||||
MOVFCSR2GR(x5, FCSR2);
|
||||
// Doing LA -> x86 here, ignore denormal
|
||||
BSTRPICK_W(x3, x5, 16, 16);
|
||||
BSTRINS_W(x4, x3, 5, 5);
|
||||
BSTRPICK_W(x3, x5, 17, 17);
|
||||
BSTRINS_W(x4, x3, 4, 4);
|
||||
BSTRPICK_W(x3, x5, 18, 18);
|
||||
BSTRINS_W(x4, x3, 3, 3);
|
||||
BSTRPICK_W(x3, x5, 19, 19);
|
||||
BSTRINS_W(x4, x3, 2, 2);
|
||||
BSTRPICK_W(x3, x5, 20, 20);
|
||||
BSTRINS_W(x4, x3, 0, 0);
|
||||
}
|
||||
ST_W(x4, wback, fixedaddress);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0xC2:
|
||||
INST_NAME("VCMPPS Gx, Vx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGY_empty_VYEY_xy(v0, v1, v2, 1);
|
||||
u8 = F8;
|
||||
switch (u8 & 0xf) {
|
||||
case 0x00: VFCMPxy(S, v0, v1, v2, cEQ); break; // Equal, not unordered
|
||||
case 0x01: VFCMPxy(S, v0, v1, v2, cLT); break; // Less than
|
||||
case 0x02: VFCMPxy(S, v0, v1, v2, cLE); break; // Less or equal
|
||||
case 0x03: VFCMPxy(S, v0, v1, v2, cUN); break; // unordered
|
||||
case 0x04: VFCMPxy(S, v0, v1, v2, cUNE); break; // Not Equal (or unordered on ARM, not on X86...)
|
||||
case 0x05: VFCMPxy(S, v0, v2, v1, cULE); break; // Greater or equal or unordered
|
||||
case 0x06: VFCMPxy(S, v0, v2, v1, cULT); break; // Greater or unordered
|
||||
case 0x07: VFCMPxy(S, v0, v1, v2, cOR); break; // Greater or unordered
|
||||
case 0x08: VFCMPxy(S, v0, v1, v2, cUEQ); break; // Equal, or unordered
|
||||
case 0x09: VFCMPxy(S, v0, v1, v2, cULT); break; // Less than or unordered
|
||||
case 0x0a: VFCMPxy(S, v0, v1, v2, cULE); break; // Less or equal or unordered
|
||||
case 0x0b: XVXOR_V(v0, v0, v0); break; // false
|
||||
case 0x0c: VFCMPxy(S, v0, v1, v2, cNE); break; // Not Eual, ordered
|
||||
case 0x0d: VFCMPxy(S, v0, v2, v1, cLE); break; // Greater or Equal ordered
|
||||
case 0x0e: VFCMPxy(S, v0, v2, v1, cLT); break; // Greater ordered
|
||||
case 0x0f: VSEQxy(B, v0, v1, v1); break; // true
|
||||
}
|
||||
break;
|
||||
case 0xC6:
|
||||
INST_NAME("VSHUFPS Gx, Vx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGY_empty_VYEY_xy(v0, v1, v2, 1);
|
||||
u8 = F8;
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
if (v1 == v2) {
|
||||
VSHUF4Ixy(W, v0, v1, u8);
|
||||
} else {
|
||||
VSHUF4Ixy(W, d0, v1, u8);
|
||||
VSHUF4Ixy(W, d1, v2, u8 >> 4);
|
||||
VPICKEVxy(D, v0, d1, d0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,235 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "env.h"
|
||||
#include "box64context.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
|
||||
#include "la64_printer.h"
|
||||
#include "dynarec_la64_private.h"
|
||||
#include "dynarec_la64_functions.h"
|
||||
#include "../dynarec_helper.h"
|
||||
|
||||
uintptr_t dynarec64_AVX_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip;
|
||||
(void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop, u8;
|
||||
uint8_t gd, ed, vd;
|
||||
uint8_t wback, wb1, wb2;
|
||||
uint8_t eb1, eb2, gb1, gb2;
|
||||
int32_t i32, i32_;
|
||||
int cacheupd = 0;
|
||||
int v0, v1, v2;
|
||||
int q0, q1, q2;
|
||||
int d0, d1, d2;
|
||||
int s0;
|
||||
uint64_t tmp64u;
|
||||
int64_t j64;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
MAYUSE(wb1);
|
||||
MAYUSE(wb2);
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
MAYUSE(gb1);
|
||||
MAYUSE(gb2);
|
||||
MAYUSE(q0);
|
||||
MAYUSE(q1);
|
||||
MAYUSE(d0);
|
||||
MAYUSE(d1);
|
||||
MAYUSE(s0);
|
||||
MAYUSE(j64);
|
||||
MAYUSE(cacheupd);
|
||||
|
||||
rex_t rex = vex.rex;
|
||||
|
||||
switch (opcode) {
|
||||
case 0xF2:
|
||||
INST_NAME("ANDN Gd, Vd, Ed");
|
||||
nextop = F8;
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
|
||||
GETGD;
|
||||
GETED(0);
|
||||
GETVD;
|
||||
ANDN(gd, ed, vd);
|
||||
if (!rex.w) {
|
||||
BSTRPICK_D(gd, gd, 31, 0);
|
||||
}
|
||||
CLEAR_FLAGS(x6);
|
||||
IFX (X_SF) {
|
||||
SRLI_D(x6, gd, rex.w ? 63 : 31);
|
||||
SLLI_D(x6, x6, F_SF);
|
||||
OR(xFlags, xFlags, x6);
|
||||
}
|
||||
IFX (X_ZF) {
|
||||
BNEZ(gd, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
SPILL_EFLAGS();
|
||||
break;
|
||||
case 0xF3:
|
||||
nextop = F8;
|
||||
switch ((nextop >> 3) & 7) {
|
||||
case 1:
|
||||
INST_NAME("BLSR Vd, Ed");
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
|
||||
GETED(0);
|
||||
GETVD;
|
||||
CLEAR_FLAGS(x6);
|
||||
IFX (X_CF) {
|
||||
BNEZ(ed, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_CF);
|
||||
}
|
||||
ADDIxw(x3, ed, -1);
|
||||
AND(vd, ed, x3);
|
||||
if (!rex.w) {
|
||||
BSTRPICK_D(vd, vd, 31, 0);
|
||||
}
|
||||
IFX (X_ZF) {
|
||||
BNEZ(vd, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX (X_SF) {
|
||||
BSTRPICK_D(x5, vd, rex.w ? 63 : 31, rex.w ? 63 : 31);
|
||||
SLLI_D(x5, x5, F_SF);
|
||||
OR(xFlags, xFlags, x5);
|
||||
}
|
||||
SPILL_EFLAGS();
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("BLSMSK Vd, Ed");
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
|
||||
GETED(0);
|
||||
GETVD;
|
||||
CLEAR_FLAGS(x6);
|
||||
IFX (X_CF) {
|
||||
BNEZ(ed, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_CF);
|
||||
}
|
||||
ADDIxw(x3, ed, -1);
|
||||
XOR(vd, ed, x3);
|
||||
if (!rex.w) {
|
||||
BSTRPICK_D(vd, vd, 31, 0);
|
||||
}
|
||||
IFX (X_SF) {
|
||||
BSTRPICK_D(x5, vd, rex.w ? 63 : 31, rex.w ? 63 : 31);
|
||||
SLLI_D(x5, x5, F_SF);
|
||||
OR(xFlags, xFlags, x5);
|
||||
}
|
||||
SPILL_EFLAGS();
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("BLSI Vd, Ed");
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
|
||||
GETED(0);
|
||||
GETVD;
|
||||
CLEAR_FLAGS(x6);
|
||||
IFX (X_CF) {
|
||||
BEQZ(ed, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_CF);
|
||||
}
|
||||
SUBxw(x3, xZR, ed);
|
||||
AND(vd, ed, x3);
|
||||
if (!rex.w) {
|
||||
BSTRPICK_D(vd, vd, 31, 0);
|
||||
}
|
||||
IFX (X_ZF) {
|
||||
BNEZ(vd, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX (X_SF) {
|
||||
BSTRPICK_D(x5, vd, rex.w ? 63 : 31, rex.w ? 63 : 31);
|
||||
SLLI_D(x5, x5, F_SF);
|
||||
OR(xFlags, xFlags, x5);
|
||||
}
|
||||
SPILL_EFLAGS();
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xF5:
|
||||
INST_NAME("BZHI Gd, Ed, Vd");
|
||||
nextop = F8;
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
|
||||
GETGD;
|
||||
GETED(0);
|
||||
GETVD;
|
||||
CLEAR_FLAGS(x6);
|
||||
BSTRPICK_D(x4, vd, 7, 0);
|
||||
MOV64x(x5, rex.w ? 64 : 32);
|
||||
BGE_MARK(x4, x5);
|
||||
ADDI_D(x6, xZR, -1);
|
||||
SLL_D(x6, x6, x4);
|
||||
ANDN(gd, ed, x6);
|
||||
B_MARK2_nocond;
|
||||
MARK;
|
||||
OR(gd, ed, ed);
|
||||
IFX (X_CF) {
|
||||
ORI(xFlags, xFlags, 1 << F_CF);
|
||||
}
|
||||
MARK2;
|
||||
if (!rex.w) {
|
||||
BSTRPICK_D(gd, gd, 31, 0);
|
||||
}
|
||||
IFX (X_ZF) {
|
||||
BNEZ(gd, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX (X_SF) {
|
||||
BSTRPICK_D(x5, gd, rex.w ? 63 : 31, rex.w ? 63 : 31);
|
||||
SLLI_D(x5, x5, F_SF);
|
||||
OR(xFlags, xFlags, x5);
|
||||
}
|
||||
SPILL_EFLAGS();
|
||||
break;
|
||||
|
||||
case 0xF7:
|
||||
INST_NAME("BEXTR Gd, Vd, Ed");
|
||||
nextop = F8;
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
|
||||
GETGD;
|
||||
GETED(0);
|
||||
GETVD;
|
||||
BSTRPICK_D(x4, vd, 7, 0); // start
|
||||
BSTRPICK_D(x3, vd, 15, 8); // length
|
||||
XOR(x5, x5, x5);
|
||||
BEQZ_MARK(x3);
|
||||
MOV64xw(x6, rex.w ? 64 : 32);
|
||||
BGE_MARK(x4, x6);
|
||||
SRLxw(x5, ed, x4);
|
||||
BLT_MARK(x6, x3);
|
||||
SUBxw(x6, x6, x3);
|
||||
SLLxw(x5, x5, x6);
|
||||
SRLxw(x5, x5, x6);
|
||||
MARK;
|
||||
OR(gd, x5, x5);
|
||||
if (!rex.w) {
|
||||
BSTRPICK_D(gd, gd, 31, 0);
|
||||
}
|
||||
CLEAR_FLAGS(x6);
|
||||
IFX (X_ZF) {
|
||||
BNEZ(gd, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
SPILL_EFLAGS();
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,810 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "env.h"
|
||||
#include "box64context.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
|
||||
#include "la64_printer.h"
|
||||
#include "dynarec_la64_private.h"
|
||||
#include "dynarec_la64_functions.h"
|
||||
#include "../dynarec_helper.h"
|
||||
|
||||
uintptr_t dynarec64_AVX_66_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip;
|
||||
(void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop, u8;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback, wb1, wb2;
|
||||
uint8_t eb1, eb2, gb1, gb2;
|
||||
int32_t i32, i32_;
|
||||
int cacheupd = 0;
|
||||
int v0, v1, v2;
|
||||
int q0, q1, q2;
|
||||
int d0, d1, d2;
|
||||
int s0;
|
||||
uint64_t tmp64u;
|
||||
int64_t j64;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
MAYUSE(wb1);
|
||||
MAYUSE(wb2);
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
MAYUSE(gb1);
|
||||
MAYUSE(gb2);
|
||||
MAYUSE(q0);
|
||||
MAYUSE(q1);
|
||||
MAYUSE(d0);
|
||||
MAYUSE(d1);
|
||||
MAYUSE(s0);
|
||||
MAYUSE(j64);
|
||||
MAYUSE(cacheupd);
|
||||
#if STEP > 1
|
||||
static const int8_t round_round[] = {
|
||||
0x3, // round to nearest with ties to even
|
||||
0x0, // round toward minus infinity
|
||||
0x1, // round toward plus infinity
|
||||
0x2 // round toward zero
|
||||
};
|
||||
#endif
|
||||
rex_t rex = vex.rex;
|
||||
|
||||
switch (opcode) {
|
||||
case 0x00:
|
||||
case 0x01:
|
||||
if (opcode) {
|
||||
INST_NAME("VPERMPD Gx, Ex, Imm8");
|
||||
} else {
|
||||
INST_NAME("VPERMQ Gx, Ex, Imm8");
|
||||
}
|
||||
nextop = F8;
|
||||
if (!vex.l) EMIT(0);
|
||||
GETGY_empty_EY_xy(v0, v1, 1);
|
||||
u8 = F8;
|
||||
XVPERMI_D(v0, v1, u8);
|
||||
break;
|
||||
case 0x02:
|
||||
case 0x0C:
|
||||
if (opcode == 0x2) {
|
||||
INST_NAME("VPBLENDD Gx, Vx, Ex, Ib");
|
||||
} else {
|
||||
INST_NAME("VBLENDPS Gx, Vx, Ex, Ib");
|
||||
}
|
||||
nextop = F8;
|
||||
GETGY_empty_VYEY_xy(v0, v1, v2, 1);
|
||||
u8 = F8;
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
if (vex.l) {
|
||||
// 256bits fast path
|
||||
if (u8 == 0) {
|
||||
if (v0 != v1) XVOR_V(v0, v1, v1);
|
||||
break;
|
||||
} else if (u8 == 0xFF) {
|
||||
if (v0 != v2) XVOR_V(v0, v2, v2);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// VEX.128 128bits fast path
|
||||
if ((u8 & 0xf) == 0) {
|
||||
if (v0 != v1) VOR_V(v0, v1, v1);
|
||||
break;
|
||||
} else if ((u8 & 0xf) == 0xF) {
|
||||
if (v0 != v2) VOR_V(v0, v2, v2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
tmp64u = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (u8 & (1 << i)) tmp64u |= (0xffULL << (i * 8));
|
||||
}
|
||||
MOV64x(x5, tmp64u);
|
||||
MOVGR2FR_D(d0, x5);
|
||||
VEXT2XV_W_B(d0, d0);
|
||||
XVBITSEL_V(v0, v1, v2, d0);
|
||||
break;
|
||||
case 0x04:
|
||||
INST_NAME("VPERMILPS Gx, Ex, Imm8");
|
||||
nextop = F8;
|
||||
GETGY_empty_EY_xy(v0, v1, 1);
|
||||
u8 = F8;
|
||||
VSHUF4Ixy(W, v0, v1, u8);
|
||||
break;
|
||||
case 0x05:
|
||||
INST_NAME("VPERMILPD Gx, Ex, Imm8");
|
||||
nextop = F8;
|
||||
GETGY_empty_EY_xy(v0, v1, 1);
|
||||
u8 = F8;
|
||||
u8 = 0b10100000 + ((u8 & 0b00001000) << 3) + ((u8 & 0b00000100) << 2) + ((u8 & 0b00000010) << 1) + (u8 & 0b00000001);
|
||||
XVPERMI_D(v0, v1, u8);
|
||||
break;
|
||||
case 0x06:
|
||||
case 0x46:
|
||||
if (opcode == 0x06) {
|
||||
INST_NAME("VPERM2F128 Gx, Vx, Ex, Imm8");
|
||||
} else {
|
||||
INST_NAME("VPERM2I128 Gx, Vx, Ex, Imm8");
|
||||
}
|
||||
nextop = F8;
|
||||
if (!vex.l) EMIT(0);
|
||||
GETGY_empty_VYEY_xy(v0, v1, v2, 1);
|
||||
u8 = F8;
|
||||
if ((u8 & 0x88) == 0x88) {
|
||||
XVXOR_V(v0, v0, v0);
|
||||
break;
|
||||
}
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
uint8_t zero_low = (u8 & 0x8) >> 3;
|
||||
uint8_t zero_up = (u8 & 0x80) >> 7;
|
||||
uint8_t vec_lo = (u8 & 0x2) >> 1;
|
||||
uint8_t index_lo = u8 & 0x1;
|
||||
uint8_t vec_hi = (u8 & 0x20) >> 5;
|
||||
uint8_t index_hi = (u8 & 0x10) >> 4;
|
||||
if (!zero_low && !zero_up) {
|
||||
if (v0 == v1) {
|
||||
XVPERMI_Q(v0, v2, XVPERMI_IMM_4_0((vec_hi ? 0 : 2) | index_hi, (vec_lo ? 0 : 2) | index_lo));
|
||||
} else if (v0 == v2) {
|
||||
XVPERMI_Q(v0, v1, XVPERMI_IMM_4_0((vec_hi << 1) | index_hi, ((vec_lo) << 1) | index_lo));
|
||||
} else {
|
||||
XVOR_V(v0, v2, v2);
|
||||
XVPERMI_Q(v0, v1, XVPERMI_IMM_4_0((vec_hi << 1) | index_hi, ((vec_lo) << 1) | index_lo));
|
||||
}
|
||||
break;
|
||||
}
|
||||
XVXOR_V(d0, d0, d0);
|
||||
if (zero_low) {
|
||||
XVORI_B(v0, vec_hi ? v2 : v1, 0);
|
||||
XVPERMI_Q(v0, d0, XVPERMI_IMM_4_0(2 + index_hi, 0));
|
||||
} else {
|
||||
XVORI_B(v0, vec_lo ? v2 : v1, 0);
|
||||
XVPERMI_Q(v0, d0, XVPERMI_IMM_4_0(0, 2 + index_lo));
|
||||
}
|
||||
break;
|
||||
case 0x08:
|
||||
INST_NAME("VROUNDPS Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGY_empty_EY_xy(v0, v1, 1);
|
||||
u8 = F8;
|
||||
if (u8 & 4) {
|
||||
u8 = sse_setround(dyn, ninst, x1, x2);
|
||||
if (vex.l) {
|
||||
XVFRINT_S(v0, v1);
|
||||
} else {
|
||||
VFRINT_S(v0, v1);
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
} else {
|
||||
if (vex.l) {
|
||||
XVFRINTRRD_S(v0, v1, round_round[u8 & 3]);
|
||||
} else {
|
||||
VFRINTRRD_S(v0, v1, round_round[u8 & 3]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x09:
|
||||
INST_NAME("VROUNDPD Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGY_empty_EY_xy(v0, v1, 1);
|
||||
u8 = F8;
|
||||
if (u8 & 4) {
|
||||
u8 = sse_setround(dyn, ninst, x1, x2);
|
||||
if (vex.l) {
|
||||
XVFRINT_D(v0, v1);
|
||||
} else {
|
||||
VFRINT_D(v0, v1);
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
} else {
|
||||
if (vex.l) {
|
||||
XVFRINTRRD_D(v0, v1, round_round[u8 & 3]);
|
||||
} else {
|
||||
VFRINTRRD_D(v0, v1, round_round[u8 & 3]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x0A:
|
||||
INST_NAME("VROUNDSS Gx, Vx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETEYSS(v2, 0, 1);
|
||||
GETVYx(v1, 0);
|
||||
GETGYx_empty(v0);
|
||||
u8 = F8;
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
if (u8 & 4) {
|
||||
u8 = sse_setround(dyn, ninst, x1, x2);
|
||||
VFRINT_S(d0, v2);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
} else {
|
||||
VFRINTRRD_S(d0, v2, round_round[u8 & 3]);
|
||||
}
|
||||
if (v0 != v1) VOR_V(v0, v1, v1);
|
||||
VEXTRINS_W(v0, d0, 0);
|
||||
break;
|
||||
case 0x0B:
|
||||
INST_NAME("VROUNDSD Gx, Vx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETEYSD(v2, 0, 1);
|
||||
GETVYx(v1, 0);
|
||||
GETGYx_empty(v0);
|
||||
u8 = F8;
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
if (u8 & 4) {
|
||||
u8 = sse_setround(dyn, ninst, x1, x2);
|
||||
VFRINT_D(d0, v2);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
} else {
|
||||
VFRINTRRD_D(d0, v2, round_round[u8 & 3]);
|
||||
}
|
||||
if (v0 != v1) VOR_V(v0, v1, v1);
|
||||
VEXTRINS_D(v0, d0, 0);
|
||||
break;
|
||||
case 0x0D:
|
||||
INST_NAME("VBLENDPD Gx, Vx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGY_empty_VYEY_xy(v0, v1, v2, 1);
|
||||
u8 = F8;
|
||||
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
if (vex.l) {
|
||||
u8 = u8 & 0b1111;
|
||||
if (u8 == 0b0000) {
|
||||
XVOR_V(v0, v1, v1);
|
||||
break;
|
||||
}
|
||||
if (u8 == 0b1111) {
|
||||
XVOR_V(v0, v2, v2);
|
||||
break;
|
||||
}
|
||||
if (u8 == 0b0011) {
|
||||
if (v0 == v1) {
|
||||
XVPERMI_Q(v0, v2, XVPERMI_IMM_4_0(3, 0));
|
||||
} else {
|
||||
XVOR_V(v0, v2, v2);
|
||||
XVPERMI_Q(v0, v1, XVPERMI_IMM_4_0(1, 2));
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (u8 == 0b1100) {
|
||||
if (v0 == v1) {
|
||||
XVPERMI_Q(v0, v2, XVPERMI_IMM_4_0(1, 2));
|
||||
} else {
|
||||
XVOR_V(v0, v2, v2);
|
||||
XVPERMI_Q(v0, v1, XVPERMI_IMM_4_0(3, 0));
|
||||
}
|
||||
break;
|
||||
}
|
||||
XVOR_V(d0, v1, v1);
|
||||
XVOR_V(d1, v1, v1);
|
||||
if (u8 & 1) XVEXTRINS_D(d0, v2, VEXTRINS_IMM_4_0(0, 0));
|
||||
if (u8 & 2) XVEXTRINS_D(d0, v2, VEXTRINS_IMM_4_0(1, 1));
|
||||
if (u8 & 4) XVEXTRINS_D(d1, v2, VEXTRINS_IMM_4_0(0, 0));
|
||||
if (u8 & 8) XVEXTRINS_D(d1, v2, VEXTRINS_IMM_4_0(1, 1));
|
||||
XVPERMI_Q(d0, d1, XVPERMI_IMM_4_0(1, 2));
|
||||
XVOR_V(v0, d0, d0);
|
||||
} else {
|
||||
u8 = u8 & 0b11;
|
||||
switch (u8) {
|
||||
case 0b00:
|
||||
VOR_V(v0, v1, v1);
|
||||
break;
|
||||
case 0b11:
|
||||
VOR_V(v0, v2, v2);
|
||||
break;
|
||||
case 0b01:
|
||||
VEXTRINS_D(v0, v1, VEXTRINS_IMM_4_0(1, 1));
|
||||
VEXTRINS_D(v0, v2, VEXTRINS_IMM_4_0(0, 0));
|
||||
break;
|
||||
case 0b10:
|
||||
VEXTRINS_D(v0, v1, VEXTRINS_IMM_4_0(0, 0));
|
||||
VEXTRINS_D(v0, v2, VEXTRINS_IMM_4_0(1, 1));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x0E:
|
||||
INST_NAME("VPBLENDW Gx, Vx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGY_empty_VYEY_xy(v0, v1, v2, 1);
|
||||
u8 = F8;
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
if (u8 == 0) {
|
||||
if (v0 != v1) VOR_Vxy(v0, v1, v1);
|
||||
break;
|
||||
} else if (u8 == 0xFF) {
|
||||
if (v0 != v2) VOR_Vxy(v0, v2, v2);
|
||||
break;
|
||||
}
|
||||
tmp64u = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (u8 & (1 << i)) tmp64u |= (0xffULL << (i * 8));
|
||||
}
|
||||
MOV64x(x5, tmp64u);
|
||||
MOVGR2FR_D(d0, x5);
|
||||
VEXT2XV_H_B(d0, d0);
|
||||
XVPERMI_Q(d0, d0, 0);
|
||||
XVBITSEL_V(v0, v1, v2, d0);
|
||||
break;
|
||||
case 0x0F:
|
||||
INST_NAME("VPALIGNR Gx, Vx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGY_empty_VYEY_xy(v0, v1, v2, 1);
|
||||
u8 = F8;
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
if (vex.l) {
|
||||
if (u8 > 31) {
|
||||
XVXOR_V(v0, v0, v0);
|
||||
break;
|
||||
} else {
|
||||
if (u8 > 15) {
|
||||
XVBSRL_V(v0, v1, u8 - 16);
|
||||
} else if (!u8) {
|
||||
XVOR_V(v0, v2, v2);
|
||||
} else {
|
||||
XVBSLL_V(d0, v1, 16 - u8);
|
||||
XVBSRL_V(d1, v2, u8);
|
||||
XVOR_V(v0, d0, d1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (u8 > 31) {
|
||||
XVXOR_V(v0, v0, v0);
|
||||
YMM_UNMARK_UPPER_ZERO(v0);
|
||||
} else if (u8 > 15) {
|
||||
VBSRL_V(v0, v1, u8 - 16);
|
||||
} else if (!u8) {
|
||||
VOR_V(v0, v2, v2);
|
||||
} else {
|
||||
VBSLL_V(d0, v1, 16 - u8);
|
||||
VBSRL_V(d1, v2, u8);
|
||||
VOR_V(v0, d0, d1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x14:
|
||||
INST_NAME("VPEXTRB Ed, Gx, imm8");
|
||||
nextop = F8;
|
||||
GETGYx(q0, 0);
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
u8 = (F8) & 15;
|
||||
VPICKVE2GR_BU(ed, q0, u8);
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x4, &fixedaddress, rex, NULL, 0, 1);
|
||||
u8 = (F8) & 15;
|
||||
VSTELM_B(q0, wback, 0, u8);
|
||||
}
|
||||
break;
|
||||
case 0x15:
|
||||
INST_NAME("VPEXTRW Ed, Gx, imm8");
|
||||
nextop = F8;
|
||||
GETGYx(q0, 0);
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
u8 = (F8) & 7;
|
||||
VPICKVE2GR_HU(ed, q0, u8);
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x4, &fixedaddress, rex, NULL, 0, 1);
|
||||
u8 = (F8) & 7;
|
||||
VSTELM_H(q0, wback, 0, u8);
|
||||
}
|
||||
break;
|
||||
case 0x16:
|
||||
if (rex.w) {
|
||||
INST_NAME("VPEXTRQ Ed, Gx, Ib");
|
||||
} else {
|
||||
INST_NAME("VPEXTRD Ed, Gx, Ib");
|
||||
}
|
||||
nextop = F8;
|
||||
GETGYx(q0, 0);
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
u8 = F8;
|
||||
if (rex.w) {
|
||||
VPICKVE2GR_D(ed, q0, (u8 & 1));
|
||||
} else {
|
||||
VPICKVE2GR_WU(ed, q0, (u8 & 3));
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, x5, &fixedaddress, rex, NULL, 0, 1);
|
||||
u8 = F8;
|
||||
if (rex.w) {
|
||||
VSTELM_D(q0, ed, 0, (u8 & 1));
|
||||
} else {
|
||||
VSTELM_W(q0, ed, 0, (u8 & 3));
|
||||
}
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x17:
|
||||
INST_NAME("VEXTRACTPS Ed, Gx, imm8");
|
||||
nextop = F8;
|
||||
GETGYx(v0, 0);
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
u8 = F8 & 0b11;
|
||||
VPICKVE2GR_WU(ed, v0, u8);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, x5, &fixedaddress, rex, NULL, 0, 1);
|
||||
u8 = F8 & 0b11;
|
||||
VSTELM_W(v0, ed, 0, u8);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x18:
|
||||
case 0x38:
|
||||
if (opcode == 0x18) {
|
||||
INST_NAME("VINSERTF128 Gx, Vx, Ex, imm8");
|
||||
} else {
|
||||
INST_NAME("VINSERTI128 Gx, Vx, Ex, imm8");
|
||||
}
|
||||
nextop = F8;
|
||||
GETEYx(q2, 0, 1);
|
||||
GETVYy(q1, 0);
|
||||
GETGYy_empty(q0);
|
||||
u8 = F8;
|
||||
if (q0 != q2) {
|
||||
if (q0 != q1) XVOR_V(q0, q1, q1);
|
||||
XVPERMI_Q(q0, q2, ((u8 & 1) == 0) ? 0x30 : 0x02);
|
||||
} else {
|
||||
XVPERMI_Q(q0, q1, ((u8 & 1) == 0) ? 0x12 : 0x20);
|
||||
}
|
||||
break;
|
||||
case 0x19:
|
||||
case 0x39:
|
||||
if (opcode == 0x19) {
|
||||
INST_NAME("VEXTRACTF128 Ex, Gx, imm8");
|
||||
} else {
|
||||
INST_NAME("VEXTRACTI128 Ex, Gx, imm8");
|
||||
}
|
||||
nextop = F8;
|
||||
GETGYy(q0, 0);
|
||||
if (MODREG) {
|
||||
GETEYx_empty(q1, 1);
|
||||
u8 = F8;
|
||||
if ((u8 & 1) == 0) {
|
||||
VOR_V(q1, q0, q0);
|
||||
} else {
|
||||
XVPERMI_Q(q1, q0, XVPERMI_IMM_4_0(3, 1));
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x4, x5, &fixedaddress, rex, NULL, 0, 1);
|
||||
u8 = F8;
|
||||
if ((u8 & 1) == 1) {
|
||||
XVSTELM_D(q0, ed, 0, 2);
|
||||
XVSTELM_D(q0, ed, 1, 3);
|
||||
} else {
|
||||
VST(q0, ed, fixedaddress);
|
||||
}
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x1D:
|
||||
INST_NAME("VCVTPS2PH Ex, Gx, Ib");
|
||||
nextop = F8;
|
||||
GETGYxy(v0, 0);
|
||||
if (vex.l) {
|
||||
GETEYx(v1, 1, 1);
|
||||
} else {
|
||||
GETEYSD(v1, 1, 1);
|
||||
}
|
||||
u8 = F8;
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
if (u8 & 4) {
|
||||
u8 = sse_setround(dyn, ninst, x1, x2);
|
||||
} else {
|
||||
MOVFCSR2GR(x4, FCSR3);
|
||||
ORI(x5, x5, round_round[u8 & 3]);
|
||||
SLLI_D(x5, x5, 8);
|
||||
MOVGR2FCSR(FCSR3, x5);
|
||||
u8 = x4;
|
||||
}
|
||||
if (vex.l) {
|
||||
XVXOR_V(d0, d0, d0);
|
||||
XVFCVT_H_S(v1, d0, v0);
|
||||
XVPERMI_D(v1, v1, 0b11011000);
|
||||
PUTEYx(v1);
|
||||
} else {
|
||||
XVXOR_V(d0, d0, d0);
|
||||
VFCVT_H_S(v1, d0, v0);
|
||||
PUTEYSD(v1);
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 0x20:
|
||||
INST_NAME("VPINSRB Gx, Vx, ED, Ib");
|
||||
nextop = F8;
|
||||
GETEB(x5, 1);
|
||||
GETVYx(v1, 0);
|
||||
GETGYx_empty(v0);
|
||||
u8 = F8;
|
||||
if (v0 != v1) VOR_V(v0, v1, v1);
|
||||
VINSGR2VR_B(v0, ed, (u8 & 0xf));
|
||||
break;
|
||||
case 0x21:
|
||||
INST_NAME("VINSERTPS Gx, Vx, Ex, Ib");
|
||||
nextop = F8;
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
if (MODREG) {
|
||||
GETGY_empty_VYEY_xy(v0, v1, v2, 1);
|
||||
u8 = F8;
|
||||
if (v0 == v2) {
|
||||
VOR_V(q1, v2, v2);
|
||||
if (v0 != v1) VOR_V(v0, v1, v1);
|
||||
VEXTRINS_W(v0, q1, VEXTRINS_IMM_4_0((u8 >> 4) & 3, (u8 >> 6) & 3));
|
||||
} else {
|
||||
if (v0 != v1) VOR_V(v0, v1, v1);
|
||||
VEXTRINS_W(v0, v2, VEXTRINS_IMM_4_0((u8 >> 4) & 3, (u8 >> 6) & 3));
|
||||
}
|
||||
} else {
|
||||
GETVYx(v1, 0);
|
||||
GETGYx_empty(v0);
|
||||
if (v0 != v1) VOR_V(v0, v1, v1);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, x5, &fixedaddress, rex, NULL, 1, 1);
|
||||
u8 = F8;
|
||||
FLD_S(q1, wback, fixedaddress);
|
||||
VEXTRINS_W(v0, q1, VEXTRINS_IMM_4_0((u8 >> 4) & 3, 0)); // src index is zero when Ex is mem operand
|
||||
}
|
||||
uint8_t zmask = u8 & 0xf;
|
||||
if (zmask) {
|
||||
VXOR_V(q1, q1, q1);
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
if (zmask & (1 << i)) {
|
||||
VEXTRINS_W(v0, q1, VEXTRINS_IMM_4_0(i, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x22:
|
||||
if (rex.w) {
|
||||
INST_NAME("VPINSRQ Gx, Vx, ED, Ib");
|
||||
} else {
|
||||
INST_NAME("VPINSRD Gx, Vx, ED, Ib");
|
||||
}
|
||||
nextop = F8;
|
||||
GETED(1);
|
||||
GETVYx(v1, 0);
|
||||
GETGYx_empty(v0);
|
||||
u8 = F8;
|
||||
if (v0 != v1) VOR_V(v0, v1, v1);
|
||||
if (rex.w) {
|
||||
VINSGR2VR_D(v0, ed, (u8 & 0x1));
|
||||
} else {
|
||||
VINSGR2VR_W(v0, ed, (u8 & 0x3));
|
||||
}
|
||||
break;
|
||||
case 0x40:
|
||||
INST_NAME("VDPPS Gx, Vx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGY_empty_VYEY_xy(v0, v1, v2, 1);
|
||||
u8 = F8;
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
d2 = fpu_get_scratch(dyn);
|
||||
VFMULxy(S, d0, v1, v2);
|
||||
VXOR_Vxy(d2, d2, d2);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (!(u8 & (1 << (4 + i)))) {
|
||||
VEXTRINSxy(W, d0, d2, (i << 4));
|
||||
}
|
||||
}
|
||||
VSHUF4Ixy(W, d1, d0, 0b10110001); // v0[a,b,c,d] v1[b,a,d,c]
|
||||
VFADDxy(S, d0, d0, d1); // v0[ab,ba,cd,dc]
|
||||
VSHUF4Ixy(W, d1, d0, 0b01001110); // v1[cd,dc,ab,ba]
|
||||
VFADDxy(S, d0, d0, d1); // v0[abcd,badc,cdab,dcba]
|
||||
VREPLVEIxy(W, v0, d0, 0);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (!(u8 & (1 << i))) {
|
||||
VEXTRINSxy(W, v0, d2, (i << 4));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x41:
|
||||
INST_NAME("VDPPD Gx, Vx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGY_empty_VYEY_xy(v0, v1, v2, 1);
|
||||
u8 = F8;
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
d2 = fpu_get_scratch(dyn);
|
||||
VFMULxy(D, d0, v1, v2);
|
||||
VXOR_Vxy(d2, d2, d2);
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
if (!(u8 & (1 << (4 + i)))) {
|
||||
VEXTRINSxy(D, d0, d2, (i << 4));
|
||||
}
|
||||
}
|
||||
VSHUF4Ixy(W, d1, d0, 0b01001110); // v0[a,b] v1[b,a]
|
||||
VFADDxy(D, d0, d0, d1); // v0[ab,ba]
|
||||
VREPLVEIxy(D, v0, d0, 0);
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
if (!(u8 & (1 << i))) {
|
||||
VEXTRINSxy(D, v0, d2, (i << 4));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x42:
|
||||
INST_NAME("VMPSADBW Gx, Vx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGY_empty_VYEY_xy(v0, v1, v2, 1);
|
||||
u8 = F8;
|
||||
if (vex.l) {
|
||||
uint8_t low_blk2_offset = 4 * (u8 & 3);
|
||||
uint8_t low_blk1_offset = 4 * ((u8 >> 2) & 1);
|
||||
uint8_t high_blk2_offset = 4 * ((u8 >> 3) & 3);
|
||||
uint8_t high_blk1_offset = 4 * ((u8 >> 5) & 1);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
q2 = fpu_get_scratch(dyn);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
if (low_blk1_offset == high_blk1_offset) {
|
||||
// generate hi128/low128 mask in one shot
|
||||
XVMEPATMSK_V(d0, 1, low_blk1_offset);
|
||||
XVMEPATMSK_V(d1, 1, low_blk1_offset + 4);
|
||||
XVSHUF_B(q0, v1, v1, d0);
|
||||
XVSHUF_B(q2, v1, v1, d1);
|
||||
} else {
|
||||
XVMEPATMSK_V(d0, 1, low_blk1_offset);
|
||||
XVMEPATMSK_V(d1, 1, high_blk1_offset);
|
||||
XVSHUF_B(q0, v1, v1, d0);
|
||||
XVSHUF_B(q1, v1, v1, d1);
|
||||
XVPERMI_Q(q0, q1, XVPERMI_IMM_4_0(1, 2));
|
||||
XVMEPATMSK_V(d0, 1, low_blk1_offset + 4);
|
||||
XVMEPATMSK_V(d1, 1, high_blk1_offset + 4);
|
||||
XVSHUF_B(q2, v1, v1, d0);
|
||||
XVSHUF_B(q1, v1, v1, d1);
|
||||
XVPERMI_Q(q2, q1, XVPERMI_IMM_4_0(1, 2));
|
||||
}
|
||||
if (low_blk2_offset == high_blk2_offset) {
|
||||
// generate hi128/low128 mask in one shot
|
||||
XVBSRL_V(q1, v2, low_blk2_offset);
|
||||
XVSHUF4I_W(q1, q1, 0b00000000);
|
||||
} else {
|
||||
XVBSRL_V(q1, v2, low_blk2_offset);
|
||||
XVBSRL_V(d1, v2, high_blk2_offset);
|
||||
XVPERMI_Q(q1, d1, XVPERMI_IMM_4_0(1, 2));
|
||||
XVSHUF4I_W(q1, q1, 0b00000000);
|
||||
}
|
||||
XVABSD_BU(d0, q0, q1);
|
||||
XVABSD_BU(d1, q2, q1);
|
||||
XVHADDW_HU_BU(d0, d0, d0);
|
||||
XVHADDW_HU_BU(d1, d1, d1);
|
||||
XVHADDW_WU_HU(d0, d0, d0);
|
||||
XVHADDW_WU_HU(d1, d1, d1);
|
||||
XVSSRANI_HU_W(d0, d0, 0);
|
||||
XVSSRANI_HU_W(d1, d1, 0);
|
||||
XVEXTRINS_D(v0, d0, VEXTRINS_IMM_4_0(0, 0));
|
||||
XVEXTRINS_D(v0, d1, VEXTRINS_IMM_4_0(1, 0));
|
||||
} else {
|
||||
uint8_t blk2_offset = 4 * (u8 & 3);
|
||||
uint8_t blk1_offset = 4 * ((u8 >> 2) & 1);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
q2 = fpu_get_scratch(dyn);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
VMEPATMSK_V(d0, 1, blk1_offset);
|
||||
VMEPATMSK_V(d1, 1, blk1_offset + 4);
|
||||
VSHUF_B(q0, v1, v1, d0);
|
||||
VSHUF_B(q2, v1, v1, d1);
|
||||
VBSRL_V(q1, v2, blk2_offset);
|
||||
VSHUF4I_W(q1, q1, 0b00000000);
|
||||
|
||||
VABSD_BU(d0, q0, q1);
|
||||
VABSD_BU(d1, q2, q1);
|
||||
VHADDW_HU_BU(d0, d0, d0);
|
||||
VHADDW_HU_BU(d1, d1, d1);
|
||||
VHADDW_WU_HU(d0, d0, d0);
|
||||
VHADDW_WU_HU(d1, d1, d1);
|
||||
VSSRANI_HU_W(d0, d0, 0);
|
||||
VSSRANI_HU_W(d1, d1, 0);
|
||||
VEXTRINS_D(v0, d0, VEXTRINS_IMM_4_0(0, 0));
|
||||
VEXTRINS_D(v0, d1, VEXTRINS_IMM_4_0(1, 0));
|
||||
}
|
||||
break;
|
||||
case 0x44:
|
||||
INST_NAME("VPCLMULQDQ Gx, Vx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
avx_forget_reg(dyn, ninst, gd);
|
||||
avx_reflect_reg(dyn, ninst, vex.v);
|
||||
MOV32w(x1, gd); // gx
|
||||
MOV32w(x2, vex.v); // vx
|
||||
if (MODREG) {
|
||||
ed = (nextop & 7) + (rex.b << 3);
|
||||
avx_forget_reg(dyn, ninst, ed);
|
||||
MOV32w(x3, ed); // ex
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, x5, &fixedaddress, rex, NULL, 0, 1);
|
||||
if (ed != x3) MV(x3, ed);
|
||||
}
|
||||
u8 = F8;
|
||||
MOV32w(x4, u8);
|
||||
CALL4_(vex.l ? const_native_pclmul_y : const_native_pclmul_x, -1, x3, x1, x2, x3, x4);
|
||||
if (!vex.l) {
|
||||
ST_D(xZR, xEmu, offsetof(x64emu_t, ymm[gd]));
|
||||
ST_D(xZR, xEmu, offsetof(x64emu_t, ymm[gd]) + 8);
|
||||
}
|
||||
break;
|
||||
case 0x4A:
|
||||
INST_NAME("VBLENDVPS Gx, Vx, Ex, XMMImm8");
|
||||
nextop = F8;
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop) >> 4;
|
||||
d0 = avx_get_reg(dyn, ninst, x5, u8, 0, LSX_AVX_WIDTH_128);
|
||||
GETGY_empty_VYEY_xy(v0, v1, v2, 1);
|
||||
F8;
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
VSLTIxy(W, q0, d0, 0);
|
||||
VBITSEL_Vxy(v0, v1, v2, q0);
|
||||
break;
|
||||
case 0x4B:
|
||||
INST_NAME("VBLENDVPD Gx, Vx, Ex, XMMImm8");
|
||||
nextop = F8;
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop) >> 4;
|
||||
d0 = avx_get_reg(dyn, ninst, x5, u8, 0, LSX_AVX_WIDTH_128);
|
||||
GETGY_empty_VYEY_xy(v0, v1, v2, 1);
|
||||
F8;
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
VSLTIxy(D, q0, d0, 0);
|
||||
VBITSEL_Vxy(v0, v1, v2, q0);
|
||||
break;
|
||||
case 0x4C:
|
||||
INST_NAME("VPBLENDVB Gx, Vx, Ex, XMMImm8");
|
||||
nextop = F8;
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop) >> 4;
|
||||
d0 = avx_get_reg(dyn, ninst, x5, u8, 0, LSX_AVX_WIDTH_128);
|
||||
GETGY_empty_VYEY_xy(v0, v1, v2, 1);
|
||||
F8;
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
VSLTIxy(B, q0, d0, 0);
|
||||
VBITSEL_Vxy(v0, v1, v2, q0);
|
||||
break;
|
||||
case 0xDF:
|
||||
INST_NAME("VAESKEYGENASSIST Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
avx_forget_reg(dyn, ninst, gd);
|
||||
MOV32w(x1, gd); // gx
|
||||
if (MODREG) {
|
||||
ed = (nextop & 7) + (rex.b << 3);
|
||||
avx_forget_reg(dyn, ninst, ed);
|
||||
MOV32w(x2, ed);
|
||||
MOV32w(x3, 0); // p = NULL
|
||||
} else {
|
||||
MOV32w(x2, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, x2, &fixedaddress, rex, NULL, 0, 1);
|
||||
if (ed != x3) {
|
||||
MV(x3, ed);
|
||||
}
|
||||
}
|
||||
u8 = F8;
|
||||
MOV32w(x4, u8);
|
||||
CALL4(const_native_aeskeygenassist, -1, x1, x2, x3, x4);
|
||||
if (!vex.l) {
|
||||
ST_D(xZR, xEmu, offsetof(x64emu_t, ymm[gd]));
|
||||
ST_D(xZR, xEmu, offsetof(x64emu_t, ymm[gd]) + 8);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,524 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "env.h"
|
||||
#include "box64context.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
|
||||
#include "la64_printer.h"
|
||||
#include "dynarec_la64_private.h"
|
||||
#include "dynarec_la64_functions.h"
|
||||
#include "../dynarec_helper.h"
|
||||
|
||||
uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip;
|
||||
(void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop, u8;
|
||||
uint8_t gd, ed, vd;
|
||||
uint8_t wback, wb1, wb2;
|
||||
uint8_t eb1, eb2, gb1, gb2;
|
||||
int32_t i32, i32_;
|
||||
int cacheupd = 0;
|
||||
int v0, v1, v2;
|
||||
int q0, q1, q2;
|
||||
int d0, d1, d2;
|
||||
int s0;
|
||||
uint64_t tmp64u, u64;
|
||||
int64_t j64;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
MAYUSE(wb1);
|
||||
MAYUSE(wb2);
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
MAYUSE(gb1);
|
||||
MAYUSE(gb2);
|
||||
MAYUSE(q0);
|
||||
MAYUSE(q1);
|
||||
MAYUSE(d0);
|
||||
MAYUSE(d1);
|
||||
MAYUSE(s0);
|
||||
MAYUSE(j64);
|
||||
MAYUSE(cacheupd);
|
||||
|
||||
rex_t rex = vex.rex;
|
||||
|
||||
switch (opcode) {
|
||||
|
||||
case 0x10:
|
||||
INST_NAME("VMOVSD Gx, [Vx,] Ex");
|
||||
nextop = F8;
|
||||
if (MODREG) {
|
||||
GETVYx(q1, 0);
|
||||
GETEYSD(q2, 0, 0);
|
||||
GETGYx_empty(q0);
|
||||
if (gd != vex.v) VOR_V(q0, q1, q1);
|
||||
VEXTRINS_D(q0, q2, 0);
|
||||
} else {
|
||||
GETEYSD(q2, 0, 0);
|
||||
GETGYx_empty(q0);
|
||||
XVPICKVE_D(q0, q2, 0);
|
||||
YMM_UNMARK_UPPER_ZERO(q0);
|
||||
}
|
||||
break;
|
||||
case 0x11:
|
||||
INST_NAME("VMOVSD Ex, [Vx,] Gx");
|
||||
nextop = F8;
|
||||
GETGYx(q2, 0);
|
||||
if (MODREG) {
|
||||
if (ed == vex.v) {
|
||||
GETEYSD(q0, 1, 0);
|
||||
VEXTRINS_D(q0, q2, 0);
|
||||
} else {
|
||||
GETVYx(q1, 0);
|
||||
GETEYSD(q0, 1, 0);
|
||||
VOR_V(q0, q1, q1);
|
||||
VEXTRINS_D(q0, q2, 0);
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
FST_D(q2, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x12:
|
||||
INST_NAME("VMOVDDUP Gx, Ex");
|
||||
nextop = F8;
|
||||
if (MODREG) {
|
||||
GETGY_empty_EY_xy(q0, q1, 0);
|
||||
} else {
|
||||
GETGYxy_empty(q0);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x4, x5, &fixedaddress, rex, NULL, 0, 0);
|
||||
if (vex.l) {
|
||||
XVLD(q1, ed, 0);
|
||||
} else {
|
||||
VLDREPL_D(q0, ed, 0);
|
||||
}
|
||||
}
|
||||
if (vex.l) {
|
||||
XVSHUF4I_D(q0, q1, 0b1010);
|
||||
} else if (MODREG) {
|
||||
VREPLVE_D(q0, q1, 0);
|
||||
}
|
||||
break;
|
||||
case 0x2A:
|
||||
INST_NAME("VCVTSI2SD Gx, Vx, Ed");
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
GETVYx(v1, 0);
|
||||
GETGYx_empty(v0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
u8 = sse_setround(dyn, ninst, x2, x3);
|
||||
}
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
if (rex.w) {
|
||||
MOVGR2FR_D(d1, ed);
|
||||
FFINT_D_L(d1, d1);
|
||||
} else {
|
||||
MOVGR2FR_W(d1, ed);
|
||||
FFINT_D_W(d1, d1);
|
||||
}
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
}
|
||||
if(v0 != v1) VOR_V(v0, v1, v1);
|
||||
VEXTRINS_D(v0, d1, 0);
|
||||
break;
|
||||
case 0x2C:
|
||||
INST_NAME("VCVTTSD2SI Gd, Ex");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEYSD(q0, 0, 0);
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
MOVGR2FCSR(FCSR2, xZR); // reset all bits
|
||||
}
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
if (rex.w) {
|
||||
FTINTRZ_L_D(d1, q0);
|
||||
MOVFR2GR_D(gd, d1);
|
||||
} else {
|
||||
FTINTRZ_W_D(d1, q0);
|
||||
MOVFR2GR_S(gd, d1);
|
||||
ZEROUP(gd);
|
||||
}
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
MOVFCSR2GR(x5, FCSR2); // get back FPSR to check
|
||||
MOV32w(x3, (1 << FR_V) | (1 << FR_O));
|
||||
AND(x5, x5, x3);
|
||||
CBZ_NEXT(x5);
|
||||
if (rex.w) {
|
||||
MOV64x(gd, 0x8000000000000000LL);
|
||||
} else {
|
||||
MOV32w(gd, 0x80000000);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x2D:
|
||||
INST_NAME("VCVTSD2SI Gd, Ex");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEYSD(q0, 0, 0);
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
MOVGR2FCSR(FCSR2, xZR); // reset all bits
|
||||
}
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
u8 = sse_setround(dyn, ninst, x2, x3);
|
||||
if (rex.w) {
|
||||
FTINT_L_D(d1, q0);
|
||||
MOVFR2GR_D(gd, d1);
|
||||
} else {
|
||||
FTINT_W_D(d1, q0);
|
||||
MOVFR2GR_S(gd, d1);
|
||||
ZEROUP(gd);
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
MOVFCSR2GR(x5, FCSR2); // get back FPSR to check
|
||||
MOV32w(x3, (1 << FR_V) | (1 << FR_O));
|
||||
AND(x5, x5, x3);
|
||||
CBZ_NEXT(x5);
|
||||
if (rex.w) {
|
||||
MOV64x(gd, 0x8000000000000000LL);
|
||||
} else {
|
||||
MOV32w(gd, 0x80000000);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x51:
|
||||
INST_NAME("VSQRTSD Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETVYx(v1, 0);
|
||||
GETEYSD(v2, 0, 0);
|
||||
GETGYx_empty(v0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
FSQRT_D(d1, v2);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
VXOR_V(d0, d0, d0);
|
||||
FCMP_D(fcc0, v2, d0, cLT);
|
||||
BCEQZ(fcc0, 4 + 4);
|
||||
FNEG_D(d1, d1);
|
||||
}
|
||||
if (v0 != v1) VOR_V(v0, v1, v1);
|
||||
VEXTRINS_D(v0, d1, 0);
|
||||
break;
|
||||
case 0x58:
|
||||
INST_NAME("VADDSD Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETVYx(v1, 0);
|
||||
GETEYSD(v2, 0, 0);
|
||||
GETGYx_empty(v0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
FADD_D(d0, v1, v2);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
FCMP_D(fcc0, v1, v2, cUN);
|
||||
BCNEZ_MARK(fcc0);
|
||||
FCMP_D(fcc1, d0, d0, cOR);
|
||||
BCNEZ_MARK(fcc1);
|
||||
FNEG_D(d0, d0);
|
||||
}
|
||||
MARK;
|
||||
if (v0 != v1) VOR_V(v0, v1, v1);
|
||||
VEXTRINS_D(v0, d0, 0);
|
||||
break;
|
||||
case 0x59:
|
||||
INST_NAME("VMULSD Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETVYx(v1, 0);
|
||||
GETEYSD(v2, 0, 0);
|
||||
GETGYx_empty(v0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
FMUL_D(d0, v1, v2);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
FCMP_D(fcc0, v1, v2, cUN);
|
||||
BCNEZ_MARK(fcc0);
|
||||
FCMP_D(fcc1, d0, d0, cOR);
|
||||
BCNEZ_MARK(fcc1);
|
||||
FNEG_D(d0, d0);
|
||||
}
|
||||
MARK;
|
||||
if (v0 != v1) VOR_V(v0, v1, v1);
|
||||
VEXTRINS_D(v0, d0, 0);
|
||||
break;
|
||||
case 0x5A:
|
||||
INST_NAME("VCVTSD2SS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETEYSD(v2, 0, 0);
|
||||
GETVYx(v1, 0);
|
||||
GETGYx_empty(v0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
FCVT_S_D(d0, v2);
|
||||
if(v0 != v1) VOR_V(v0, v1, v1);
|
||||
XVINSVE0_W(v0, d0, 0);
|
||||
break;
|
||||
case 0x5C:
|
||||
INST_NAME("VSUBSD Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETVYx(v1, 0);
|
||||
GETEYSD(v2, 0, 0);
|
||||
GETGYx_empty(v0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
FSUB_D(d0, v1, v2);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
FCMP_D(fcc0, v1, v2, cUN);
|
||||
BCNEZ_MARK(fcc0);
|
||||
FCMP_D(fcc1, d0, d0, cOR);
|
||||
BCNEZ_MARK(fcc1);
|
||||
FNEG_D(d0, d0);
|
||||
}
|
||||
MARK;
|
||||
if (v0 != v1) VOR_V(v0, v1, v1);
|
||||
VEXTRINS_D(v0, d0, 0);
|
||||
break;
|
||||
case 0x5D:
|
||||
INST_NAME("VMINSD Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETVYx(v1, 0);
|
||||
GETEYSD(v2, 0, 0);
|
||||
GETGYx_empty(v0);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
if (BOX64ENV(dynarec_fastnan)) {
|
||||
FMIN_D(q0, v1, v2);
|
||||
} else {
|
||||
FCMP_D(fcc0, v2, v1, cULE);
|
||||
FSEL(q0, v1, v2, fcc0);
|
||||
}
|
||||
if (v0 != v1) VOR_V(v0, v1, v1);
|
||||
VEXTRINS_D(v0, q0, 0);
|
||||
break;
|
||||
case 0x5E:
|
||||
INST_NAME("VDIVSD Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETVYx(v1, 0);
|
||||
GETEYSD(v2, 0, 0);
|
||||
GETGYx_empty(v0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
FDIV_D(d0, v1, v2);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
FCMP_D(fcc0, v1, v2, cUN);
|
||||
BCNEZ_MARK(fcc0);
|
||||
FCMP_D(fcc1, d0, d0, cOR);
|
||||
BCNEZ_MARK(fcc1);
|
||||
FNEG_D(d0, d0);
|
||||
}
|
||||
MARK;
|
||||
if (v0 != v1) VOR_V(v0, v1, v1);
|
||||
VEXTRINS_D(v0, d0, 0);
|
||||
break;
|
||||
case 0x5F:
|
||||
INST_NAME("VMAXSD Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETVYx(v1, 0);
|
||||
GETEYSD(v2, 0, 0);
|
||||
GETGYx_empty(v0);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
if (BOX64ENV(dynarec_fastnan)) {
|
||||
FMAX_D(q0, v1, v2);
|
||||
} else {
|
||||
FCMP_D(fcc0, v2, v1, cLT);
|
||||
FSEL(q0, v2, v1, fcc0);
|
||||
}
|
||||
if (v0 != v1) VOR_V(v0, v1, v1);
|
||||
VEXTRINS_D(v0, q0, 0);
|
||||
break;
|
||||
case 0x70:
|
||||
INST_NAME("VPSHUFLW Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGY_empty_EY_xy(v0, v1, 1);
|
||||
u8 = F8;
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
if (v0 != v1) {
|
||||
VSHUF4Ixy(H, v0, v1, u8);
|
||||
VEXTRINSxy(D, v0, v1, VEXTRINS_IMM_4_0(1, 1));
|
||||
} else {
|
||||
VSHUF4Ixy(H, d0, v1, u8);
|
||||
VEXTRINSxy(D, v0, d0, VEXTRINS_IMM_4_0(0, 0));
|
||||
}
|
||||
break;
|
||||
case 0x7C:
|
||||
INST_NAME("VHADDPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
VPICKEVxy(W, q0, v2, v1);
|
||||
VPICKODxy(W, v0, v2, v1);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
VFCMPxy(S, d0, q0, v0, cUN);
|
||||
}
|
||||
VFADDxy(S, v0, q0, v0);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
VFCMPxy(S, d1, v0, v0, cUN);
|
||||
VANDN_Vxy(d0, d0, d1);
|
||||
VLDIxy(d1, (0b010 << 9) | 0b1111111100);
|
||||
VSLLIxy(W, d1, d1, 20); // broadcast 0xFFC00000
|
||||
VBITSEL_Vxy(v0, v0, d1, d0);
|
||||
}
|
||||
break;
|
||||
case 0x7D:
|
||||
INST_NAME("VHSUBPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
VPICKEVxy(W, q0, v2, v1);
|
||||
VPICKODxy(W, v0, v2, v1);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
VFCMPxy(S, d0, q0, v0, cUN);
|
||||
}
|
||||
VFSUBxy(S, v0, q0, v0);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
VFCMPxy(S, d1, v0, v0, cUN);
|
||||
VANDN_Vxy(d0, d0, d1);
|
||||
VLDIxy(d1, (0b010 << 9) | 0b1111111100);
|
||||
VSLLIxy(W, d1, d1, 20); // broadcast 0xFFC00000
|
||||
VBITSEL_Vxy(v0, v0, d1, d0);
|
||||
}
|
||||
break;
|
||||
case 0xC2:
|
||||
INST_NAME("VCMPSD Gx, Vx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETVYx(v1, 0);
|
||||
GETEYSD(v2, 0, 1);
|
||||
GETGYx(v0, 1);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
u8 = F8;
|
||||
switch (u8 & 0xf) {
|
||||
case 0x00: VFCMP_D(q0, v1, v2, cEQ); break; // Equal, not unordered
|
||||
case 0x01: VFCMP_D(q0, v1, v2, cLT); break; // Less than
|
||||
case 0x02: VFCMP_D(q0, v1, v2, cLE); break; // Less or equal
|
||||
case 0x03: VFCMP_D(q0, v1, v2, cUN); break; // unordered
|
||||
case 0x04: VFCMP_D(q0, v1, v2, cUNE); break; // Not Equal (or unordered on ARM, not on X86...)
|
||||
case 0x05: VFCMP_D(q0, v2, v1, cULE); break; // Greater or equal or unordered
|
||||
case 0x06: VFCMP_D(q0, v2, v1, cULT); break; // Greater or unordered
|
||||
case 0x07: VFCMP_D(q0, v1, v2, cOR); break; // Greater or unordered
|
||||
case 0x08: VFCMP_D(q0, v1, v2, cUEQ); break; // Equal, or unordered
|
||||
case 0x09: VFCMP_D(q0, v1, v2, cULT); break; // Less than or unordered
|
||||
case 0x0a: VFCMP_D(q0, v1, v2, cULE); break; // Less or equal or unordered
|
||||
case 0x0b: VXOR_V(q0, q0, q0); break; // false
|
||||
case 0x0c: VFCMP_D(q0, v1, v2, cNE); break; // Not Eual, ordered
|
||||
case 0x0d: VFCMP_D(q0, v2, v1, cLE); break; // Greater or Equal ordered
|
||||
case 0x0e: VFCMP_D(q0, v2, v1, cLT); break; // Greater ordered
|
||||
case 0x0f: VSEQ_B(q0, v1, v1); break; // true
|
||||
}
|
||||
XVXOR_V(v0, v0, v0);
|
||||
XVPERMI_Q(v0, v1, XVPERMI_IMM_4_0(3, 0));
|
||||
XVINSVE0_D(v0, q0, 0);
|
||||
YMM_UNMARK_UPPER_ZERO(v0);
|
||||
break;
|
||||
case 0xD0:
|
||||
INST_NAME("VADDSUBPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
VFCMPxy(S, d0, v1, v2, cUN);
|
||||
}
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
VFSUBxy(S, q0, v1, v2);
|
||||
VFADDxy(S, v0, v1, v2);
|
||||
VEXTRINSxy(W, v0, q0, VEXTRINS_IMM_4_0(0, 0));
|
||||
VEXTRINSxy(W, v0, q0, VEXTRINS_IMM_4_0(2, 2));
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
VFCMPxy(S, d1, v0, v0, cUN);
|
||||
VANDN_Vxy(d0, d0, d1);
|
||||
VLDIxy(d1, (0b010 << 9) | 0b1111111100);
|
||||
VSLLIxy(W, d1, d1, 20); // broadcast 0xFFC00000
|
||||
VBITSEL_Vxy(v0, v0, d1, d0);
|
||||
}
|
||||
break;
|
||||
case 0xE6:
|
||||
INST_NAME("VCVTPD2DQ Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEYxy(v1, 0, 0);
|
||||
GETGYx_empty(v0);
|
||||
u8 = sse_setround(dyn, ninst, x1, x2);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
if (vex.l) {
|
||||
XVXOR_V(d0, d0, d0);
|
||||
XVFTINT_W_D(v0, d0, v1); // v0 [lo0, lo1, --, --, hi0, hi1, --, -- ]
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
q2 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
XVFTINT_L_D(q2, v1);
|
||||
XVLDI(q0, 0b1001110000000); // broadcast 0x80000000 to all
|
||||
MOV32w(x5, 0x7FFFFFFF);
|
||||
BSTRPICK_D(x5, x5, 31, 0);
|
||||
XVREPLGR2VR_D(q1, x5);
|
||||
XVFCMP_D(d0, v1, v1, cUN); // get Nan mask
|
||||
XVSLT_D(d1, q1, q2); // get +inf mask
|
||||
XVOR_V(d0, d1, d0);
|
||||
XVSRLNI_W_D(d0, d0, 0); // [A,B,C,D] => [a,b,--,--,c,d,--,--]
|
||||
XVBITSEL_V(v0, v0, q0, d0);
|
||||
}
|
||||
XVPERMI_D(v0, v0, 0b11011000);
|
||||
} else {
|
||||
VFTINT_W_D(d0, v1, v1);
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
q2 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
VFTINT_L_D(d1, v1);
|
||||
VLDI(q0, 0b1001110000000); // broadcast 0x80000000 to all
|
||||
MOV32w(x5, 0x7FFFFFFF);
|
||||
BSTRPICK_D(x5, x5, 31, 0);
|
||||
VREPLGR2VR_D(q1, x5);
|
||||
VSLT_D(q1, q1, d1); // get +inf mask
|
||||
VFCMP_D(q2, v1, v1, cUN); // get Nan mask
|
||||
VOR_V(q1, q1, q2);
|
||||
VSHUF4I_W(q1, q1, 0b11011000);
|
||||
VBITSEL_V(d0, d0, q0, q1);
|
||||
}
|
||||
XVPICKVE_D(v0, d0, 0);
|
||||
YMM_UNMARK_UPPER_ZERO(v0);
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 0xF0:
|
||||
INST_NAME("VLDDQU Gx, Ex");
|
||||
nextop = F8;
|
||||
if (MODREG) {
|
||||
GETGY_empty_EY_xy(q0, q1, 0);
|
||||
if (vex.l) {
|
||||
XVOR_V(q0, q1, q1);
|
||||
} else {
|
||||
VOR_V(q0, q1, q1);
|
||||
}
|
||||
} else {
|
||||
GETGYxy_empty(q0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
if (vex.l) {
|
||||
XVLD(q0, ed, fixedaddress);
|
||||
} else {
|
||||
VLD(q0, ed, fixedaddress);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "env.h"
|
||||
#include "box64context.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
|
||||
#include "la64_printer.h"
|
||||
#include "dynarec_la64_private.h"
|
||||
#include "dynarec_la64_functions.h"
|
||||
#include "../dynarec_helper.h"
|
||||
|
||||
uintptr_t dynarec64_AVX_F2_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip;
|
||||
(void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop, u8;
|
||||
uint8_t gd, ed, vd;
|
||||
uint8_t wback, wb1, wb2;
|
||||
uint8_t eb1, eb2, gb1, gb2;
|
||||
int32_t i32, i32_;
|
||||
int cacheupd = 0;
|
||||
int v0, v1, v2;
|
||||
int q0, q1, q2;
|
||||
int d0, d1, d2;
|
||||
int s0;
|
||||
uint64_t tmp64u;
|
||||
int64_t j64;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
MAYUSE(wb1);
|
||||
MAYUSE(wb2);
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
MAYUSE(gb1);
|
||||
MAYUSE(gb2);
|
||||
MAYUSE(q0);
|
||||
MAYUSE(q1);
|
||||
MAYUSE(d0);
|
||||
MAYUSE(d1);
|
||||
MAYUSE(s0);
|
||||
MAYUSE(j64);
|
||||
MAYUSE(cacheupd);
|
||||
|
||||
rex_t rex = vex.rex;
|
||||
|
||||
switch (opcode) {
|
||||
case 0xF5:
|
||||
INST_NAME("PDEP Gd, Vd, Ed");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETVD;
|
||||
GETED(0);
|
||||
if (gd == ed || gd == vd) {
|
||||
gb1 = gd;
|
||||
gd = x6;
|
||||
} else {
|
||||
gb1 = 0;
|
||||
}
|
||||
MOV64x(gd, 0);
|
||||
MOV64x(x3, 1);
|
||||
MOV64x(x4, 1);
|
||||
MARK;
|
||||
AND(x5, ed, x4);
|
||||
BEQZ_MARK2(x5);
|
||||
AND(x5, vd, x3);
|
||||
BEQZ_MARK3(x5);
|
||||
OR(gd, gd, x4);
|
||||
MARK3;
|
||||
SLLIxw(x3, x3, 1);
|
||||
MARK2;
|
||||
SLLIxw(x4, x4, 1);
|
||||
BNEZ_MARK(x4);
|
||||
if (gb1)
|
||||
OR(gb1, gd, gd);
|
||||
break;
|
||||
case 0xF6:
|
||||
INST_NAME("MULX Gd, Vd, Ed (,RDX)");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED(0);
|
||||
GETVD;
|
||||
if ((gd == xRDX) || (gd == ed) || (gd == vd))
|
||||
gb1 = x3;
|
||||
else
|
||||
gb1 = gd;
|
||||
if (rex.w) {
|
||||
MULH_DU(gb1, xRDX, ed);
|
||||
if (gd != vd) { MUL_D(vd, xRDX, ed); }
|
||||
if (gb1 == x3) {
|
||||
OR(gd, gb1, gb1);
|
||||
}
|
||||
} else {
|
||||
MULH_WU(gb1, xRDX, ed);
|
||||
if (gd != vd) { MUL_W(vd, xRDX, ed); }
|
||||
}
|
||||
if (gb1 == x3) {
|
||||
BSTRINS_D(gd, gb1, 31, 0);
|
||||
}
|
||||
break;
|
||||
case 0xF7:
|
||||
INST_NAME("SHRX Gd, Ed, Vd");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED(0);
|
||||
GETVD;
|
||||
ANDI(x5, vd, rex.w ? 0x3f : 0x1f);
|
||||
SRLxw(gd, ed, x5);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "env.h"
|
||||
#include "box64context.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
|
||||
#include "la64_printer.h"
|
||||
#include "dynarec_la64_private.h"
|
||||
#include "dynarec_la64_functions.h"
|
||||
#include "../dynarec_helper.h"
|
||||
|
||||
uintptr_t dynarec64_AVX_F2_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip;
|
||||
(void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop, u8;
|
||||
uint8_t gd, ed, vd;
|
||||
uint8_t wback, wb1, wb2;
|
||||
uint8_t eb1, eb2, gb1, gb2;
|
||||
int32_t i32, i32_;
|
||||
int cacheupd = 0;
|
||||
int v0, v1, v2;
|
||||
int q0, q1, q2;
|
||||
int d0, d1, d2;
|
||||
int s0;
|
||||
uint64_t tmp64u;
|
||||
int64_t j64;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
MAYUSE(wb1);
|
||||
MAYUSE(wb2);
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
MAYUSE(gb1);
|
||||
MAYUSE(gb2);
|
||||
MAYUSE(q0);
|
||||
MAYUSE(q1);
|
||||
MAYUSE(d0);
|
||||
MAYUSE(d1);
|
||||
MAYUSE(s0);
|
||||
MAYUSE(j64);
|
||||
MAYUSE(cacheupd);
|
||||
|
||||
rex_t rex = vex.rex;
|
||||
|
||||
switch (opcode) {
|
||||
case 0xF0:
|
||||
INST_NAME("RORX Gd, Ed, Ib");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED(1);
|
||||
u8 = F8;
|
||||
ROTRIxw(gd, ed, u8 & (rex.w ? 0x3f : 0x1f));
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,504 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "env.h"
|
||||
#include "box64context.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
|
||||
#include "la64_printer.h"
|
||||
#include "dynarec_la64_private.h"
|
||||
#include "dynarec_la64_functions.h"
|
||||
#include "../dynarec_helper.h"
|
||||
|
||||
uintptr_t dynarec64_AVX_F3_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip;
|
||||
(void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop, u8;
|
||||
uint8_t gd, ed, vd;
|
||||
uint8_t wback, wb1, wb2, gback, vback;
|
||||
uint8_t eb1, eb2, gb1, gb2;
|
||||
int32_t i32, i32_;
|
||||
int cacheupd = 0;
|
||||
int v0, v1, v2;
|
||||
int q0, q1, q2;
|
||||
int d0, d1, d2;
|
||||
int s0;
|
||||
uint64_t tmp64u, u64;
|
||||
int64_t j64;
|
||||
int64_t fixedaddress, gdoffset, vxoffset;
|
||||
int unscaled;
|
||||
|
||||
rex_t rex = vex.rex;
|
||||
|
||||
switch (opcode) {
|
||||
case 0x10:
|
||||
INST_NAME("VMOVSS Gx, [Vx,] Ex");
|
||||
nextop = F8;
|
||||
if (MODREG) {
|
||||
GETVYx(q1, 0);
|
||||
GETEYSS(q2, 0, 0);
|
||||
GETGYx_empty(q0);
|
||||
if (gd != vex.v) VOR_V(q0, q1, q1);
|
||||
VEXTRINS_W(q0, q2, 0);
|
||||
} else {
|
||||
GETEYSS(q2, 0, 0);
|
||||
GETGYx_empty(q0);
|
||||
XVPICKVE_W(q0, q2, 0);
|
||||
YMM_UNMARK_UPPER_ZERO(q0);
|
||||
}
|
||||
break;
|
||||
case 0x11:
|
||||
INST_NAME("VMOVSS Ex, [Vx,] Gx");
|
||||
nextop = F8;
|
||||
GETGYx(q2, 0);
|
||||
if (MODREG) {
|
||||
if (ed == vex.v) {
|
||||
GETEYSS(q0, 1, 0);
|
||||
VEXTRINS_W(q0, q2, 0);
|
||||
} else {
|
||||
GETVYx(q1, 0);
|
||||
GETEYSS(q0, 1, 0);
|
||||
VOR_V(q0, q1, q1);
|
||||
VEXTRINS_W(q0, q2, 0);
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
FST_S(q2, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x12:
|
||||
INST_NAME("VMOVSLDUP Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGY_empty_EY_xy(q0, q1, 0);
|
||||
if (vex.l) {
|
||||
XVPACKEV_W(q0, q1, q1);
|
||||
} else {
|
||||
VPACKEV_W(q0, q1, q1);
|
||||
}
|
||||
break;
|
||||
case 0x16:
|
||||
INST_NAME("VMOVSHDUP Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGY_empty_EY_xy(q0, q1, 0);
|
||||
if (vex.l) {
|
||||
XVPACKOD_W(q0, q1, q1);
|
||||
} else {
|
||||
VPACKOD_W(q0, q1, q1);
|
||||
}
|
||||
break;
|
||||
case 0x2A:
|
||||
INST_NAME("VCVTSI2SS Gx, Vx, Ed");
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
GETVYx(v1, 0);
|
||||
GETGYx_empty(v0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
u8 = sse_setround(dyn, ninst, x2, x3);
|
||||
}
|
||||
if (rex.w) {
|
||||
MOVGR2FR_D(d1, ed);
|
||||
FFINT_S_L(d1, d1);
|
||||
} else {
|
||||
MOVGR2FR_W(d1, ed);
|
||||
FFINT_S_W(d1, d1);
|
||||
}
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
}
|
||||
if(v0 != v1) VOR_V(v0, v1, v1);
|
||||
VEXTRINS_W(v0, d1, 0);
|
||||
break;
|
||||
case 0x2C:
|
||||
INST_NAME("VCVTTSS2SI Gd, Ex");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEYSS(d0, 0, 0);
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
MOVGR2FCSR(FCSR2, xZR); // reset all bits
|
||||
}
|
||||
u8 = sse_setround(dyn, ninst, x5, x6);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
if (rex.w) {
|
||||
FTINTRZ_L_S(d1, d0);
|
||||
MOVFR2GR_D(gd, d1);
|
||||
} else {
|
||||
FTINTRZ_W_S(d1, d0);
|
||||
MOVFR2GR_S(gd, d1);
|
||||
ZEROUP(gd);
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
MOVFCSR2GR(x5, FCSR2); // get back FPSR to check
|
||||
MOV32w(x3, (1 << FR_V) | (1 << FR_O));
|
||||
AND(x5, x5, x3);
|
||||
CBZ_NEXT(x5);
|
||||
if (rex.w) {
|
||||
MOV64x(gd, 0x8000000000000000LL);
|
||||
} else {
|
||||
MOV32w(gd, 0x80000000);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x2D:
|
||||
INST_NAME("VCVTSS2SI Gd, Ex");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEYSS(d0, 0, 0);
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
MOVGR2FCSR(FCSR2, xZR); // reset all bits
|
||||
}
|
||||
u8 = sse_setround(dyn, ninst, x5, x6);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
if (rex.w) {
|
||||
FTINT_L_S(d1, d0);
|
||||
MOVFR2GR_D(gd, d1);
|
||||
} else {
|
||||
FTINT_W_S(d1, d0);
|
||||
MOVFR2GR_S(gd, d1);
|
||||
ZEROUP(gd);
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
MOVFCSR2GR(x5, FCSR2); // get back FPSR to check
|
||||
MOV32w(x3, (1 << FR_V) | (1 << FR_O));
|
||||
AND(x5, x5, x3);
|
||||
CBZ_NEXT(x5);
|
||||
if (rex.w) {
|
||||
MOV64x(gd, 0x8000000000000000LL);
|
||||
} else {
|
||||
MOV32w(gd, 0x80000000);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x51:
|
||||
INST_NAME("VSQRTSS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETVYx(v1, 0);
|
||||
GETEYSS(v2, 0, 0);
|
||||
GETGYx_empty(v0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
FSQRT_S(d1, v2);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
VXOR_V(d0, d0, d0);
|
||||
FCMP_S(fcc0, v2, d0, cLT);
|
||||
BCEQZ(fcc0, 4 + 4);
|
||||
FNEG_S(d1, d1);
|
||||
}
|
||||
if (v0 != v1) VOR_V(v0, v1, v1);
|
||||
VEXTRINS_W(v0, d1, 0);
|
||||
break;
|
||||
case 0x52:
|
||||
INST_NAME("VRSQRTSS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETVYx(v1, 0);
|
||||
GETEYSS(v2, 0, 0);
|
||||
GETGYx_empty(v0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
if (cpuext.frecipe) {
|
||||
FRSQRTE_S(d0, v1);
|
||||
} else {
|
||||
FRSQRT_S(d0, v1);
|
||||
}
|
||||
if (v0 != v1) VOR_V(v0, v1, v1);
|
||||
VEXTRINS_W(v0, d0, 0);
|
||||
break;
|
||||
case 0x53:
|
||||
INST_NAME("VRCPSS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETVYx(v1, 0);
|
||||
GETEYSS(v2, 0, 0);
|
||||
GETGYx_empty(v0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
if (cpuext.frecipe) {
|
||||
FRECIPE_S(d0, v1);
|
||||
} else {
|
||||
FRECIP_S(d0, v1);
|
||||
}
|
||||
if (v0 != v1) VOR_V(v0, v1, v1);
|
||||
VEXTRINS_W(v0, d0, 0);
|
||||
break;
|
||||
case 0x58:
|
||||
INST_NAME("VADDSS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETVYx(v1, 0);
|
||||
GETEYSS(v2, 0, 0);
|
||||
GETGYx_empty(v0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
FADD_S(d0, v1, v2);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
FCMP_S(fcc0, v1, v2, cUN);
|
||||
BCNEZ_MARK(fcc0);
|
||||
FCMP_S(fcc1, d0, d0, cOR);
|
||||
BCNEZ_MARK(fcc1);
|
||||
FNEG_S(d0, d0);
|
||||
}
|
||||
MARK;
|
||||
if (v0 != v1) VOR_V(v0, v1, v1);
|
||||
VEXTRINS_W(v0, d0, 0);
|
||||
break;
|
||||
case 0x59:
|
||||
INST_NAME("VMULSS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETVYx(v1, 0);
|
||||
GETEYSS(v2, 0, 0);
|
||||
GETGYx_empty(v0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
FMUL_S(d0, v1, v2);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
FCMP_S(fcc0, v1, v2, cUN);
|
||||
BCNEZ_MARK(fcc0);
|
||||
FCMP_S(fcc1, d0, d0, cOR);
|
||||
BCNEZ_MARK(fcc1);
|
||||
FNEG_S(d0, d0);
|
||||
}
|
||||
MARK;
|
||||
if (v0 != v1) VOR_V(v0, v1, v1);
|
||||
VEXTRINS_W(v0, d0, 0);
|
||||
break;
|
||||
case 0x5A:
|
||||
INST_NAME("VCVTSS2SD Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETVYx(v1, 0);
|
||||
GETEYSS(v2, 0, 0);
|
||||
GETGYx_empty(v0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
FCVT_D_S(d1, v2);
|
||||
if(v0 != v1) VOR_V(v0, v1, v1);
|
||||
VEXTRINS_D(v0, d1, 0);
|
||||
break;
|
||||
case 0x5B:
|
||||
INST_NAME("VCVTTPS2DQ Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGY_empty_EY_xy(v0, v1, 0);
|
||||
if (vex.l) {
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn); // mask
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
XVFTINTRZ_W_S(d1, v1);
|
||||
XVLDI(q0, 0b1001110000000); // broadcast 0x80000000 to all
|
||||
XVLDI(d0, (0b10011 << 8) | 0x4f);
|
||||
XVFCMP_S(q1, d0, v1, cULE); // get Nan,+overflow mark
|
||||
XVBITSEL_V(v0, d1, q0, q1);
|
||||
} else {
|
||||
XVFTINTRZ_W_S(v0, v1);
|
||||
}
|
||||
} else {
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn); // mask
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
VFTINTRZ_W_S(d1, v1);
|
||||
VLDI(q0, 0b1001110000000); // broadcast 0x80000000 to all
|
||||
VLDI(d0, (0b10011 << 8) | 0x4f);
|
||||
VFCMP_S(q1, d0, v1, cULE); // get Nan,+overflow mark
|
||||
VBITSEL_V(v0, d1, q0, q1);
|
||||
} else {
|
||||
VFTINTRZ_W_S(v0, v1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x5C:
|
||||
INST_NAME("VSUBSS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETVYx(v1, 0);
|
||||
GETEYSS(v2, 0, 0);
|
||||
GETGYx_empty(v0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
FSUB_S(d0, v1, v2);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
FCMP_S(fcc0, v1, v2, cUN);
|
||||
BCNEZ_MARK(fcc0);
|
||||
FCMP_S(fcc1, d0, d0, cOR);
|
||||
BCNEZ_MARK(fcc1);
|
||||
FNEG_S(d0, d0);
|
||||
}
|
||||
MARK;
|
||||
if (v0 != v1) VOR_V(v0, v1, v1);
|
||||
VEXTRINS_W(v0, d0, 0);
|
||||
break;
|
||||
case 0x5D:
|
||||
INST_NAME("VMINSS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETVYx(v1, 0);
|
||||
GETEYSS(v2, 0, 0);
|
||||
GETGYx_empty(v0);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
if (BOX64ENV(dynarec_fastnan)) {
|
||||
FMIN_S(q0, v1, v2);
|
||||
} else {
|
||||
FCMP_S(fcc0, v2, v1, cULE);
|
||||
FSEL(q0, v1, v2, fcc0);
|
||||
}
|
||||
if (v0 != v1) VOR_V(v0, v1, v1);
|
||||
VEXTRINS_W(v0, q0, 0);
|
||||
break;
|
||||
case 0x5E:
|
||||
INST_NAME("VDIVSS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETVYx(v1, 0);
|
||||
GETEYSS(v2, 0, 0);
|
||||
GETGYx_empty(v0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
FDIV_S(d0, v1, v2);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
FCMP_S(fcc0, v1, v2, cUN);
|
||||
BCNEZ_MARK(fcc0);
|
||||
FCMP_S(fcc1, d0, d0, cOR);
|
||||
BCNEZ_MARK(fcc1);
|
||||
FNEG_S(d0, d0);
|
||||
}
|
||||
MARK;
|
||||
if (v0 != v1) VOR_V(v0, v1, v1);
|
||||
VEXTRINS_W(v0, d0, 0);
|
||||
break;
|
||||
case 0x5F:
|
||||
INST_NAME("VMAXSS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETVYx(v1, 0);
|
||||
GETEYSS(v2, 0, 0);
|
||||
GETGYx_empty(v0);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
if (BOX64ENV(dynarec_fastnan)) {
|
||||
FMAX_S(q0, v1, v2);
|
||||
} else {
|
||||
FCMP_S(fcc0, v2, v1, cLT);
|
||||
FSEL(q0, v2, v1, fcc0);
|
||||
}
|
||||
if (v0 != v1) VOR_V(v0, v1, v1);
|
||||
VEXTRINS_W(v0, q0, 0);
|
||||
break;
|
||||
case 0x6F:
|
||||
INST_NAME("VMOVDQU Gx, Ex");
|
||||
nextop = F8;
|
||||
if (MODREG) {
|
||||
GETGY_empty_EY_xy(q0, q1, 0);
|
||||
if (vex.l) {
|
||||
XVOR_V(q0, q1, q1);
|
||||
} else {
|
||||
VOR_V(q0, q1, q1);
|
||||
}
|
||||
} else {
|
||||
GETGYxy_empty(q0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
if (vex.l) {
|
||||
XVLD(q0, ed, fixedaddress);
|
||||
} else {
|
||||
VLD(q0, ed, fixedaddress);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x70:
|
||||
INST_NAME("VPSHUFHW Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGY_empty_EY_xy(v0, v1, 1);
|
||||
u8 = F8;
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
if (v0 != v1) {
|
||||
VSHUF4Ixy(H, v0, v1, u8);
|
||||
VEXTRINSxy(D, v0, v1, VEXTRINS_IMM_4_0(0, 0));
|
||||
} else {
|
||||
VSHUF4Ixy(H, d0, v1, u8);
|
||||
VEXTRINSxy(D, v0, d0, VEXTRINS_IMM_4_0(1, 1));
|
||||
}
|
||||
break;
|
||||
case 0x7E:
|
||||
INST_NAME("VMOVQ Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEYSD(q1, 0, 0);
|
||||
GETGYx_empty(q0);
|
||||
XVPICKVE_D(q0, q1, 0);
|
||||
YMM_UNMARK_UPPER_ZERO(q0);
|
||||
break;
|
||||
case 0x7F:
|
||||
INST_NAME("VMOVDQU Ex, Gx");
|
||||
nextop = F8;
|
||||
GETGYxy(q0, 0);
|
||||
if (MODREG) {
|
||||
GETEYxy_empty(q1, 0);
|
||||
if (vex.l) {
|
||||
XVOR_V(q1, q0, q0);
|
||||
} else {
|
||||
VOR_V(q1, q0, q0);
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x4, x5, &fixedaddress, rex, NULL, 1, 0);
|
||||
if (vex.l) {
|
||||
XVST(q0, ed, fixedaddress);
|
||||
} else {
|
||||
VST(q0, ed, fixedaddress);
|
||||
}
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0xC2:
|
||||
INST_NAME("VCMPSS Gx, Vx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETVYx(v1, 0);
|
||||
GETEYSS(v2, 0, 1);
|
||||
GETGYx(v0, 1);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
u8 = F8;
|
||||
switch (u8 & 0xf) {
|
||||
case 0x00: VFCMP_S(q0, v1, v2, cEQ); break; // Equal, not unordered
|
||||
case 0x01: VFCMP_S(q0, v1, v2, cLT); break; // Less than
|
||||
case 0x02: VFCMP_S(q0, v1, v2, cLE); break; // Less or equal
|
||||
case 0x03: VFCMP_S(q0, v1, v2, cUN); break; // unordered
|
||||
case 0x04: VFCMP_S(q0, v1, v2, cUNE); break; // Not Equal (or unordered on ARM, not on X86...)
|
||||
case 0x05: VFCMP_S(q0, v2, v1, cULE); break; // Greater or equal or unordered
|
||||
case 0x06: VFCMP_S(q0, v2, v1, cULT); break; // Greater or unordered
|
||||
case 0x07: VFCMP_S(q0, v1, v2, cOR); break; // Greater or unordered
|
||||
case 0x08: VFCMP_S(q0, v1, v2, cUEQ); break; // Equal, or unordered
|
||||
case 0x09: VFCMP_S(q0, v1, v2, cULT); break; // Less than or unordered
|
||||
case 0x0a: VFCMP_S(q0, v1, v2, cULE); break; // Less or equal or unordered
|
||||
case 0x0b: VXOR_V(q0, q0, q0); break; // false
|
||||
case 0x0c: VFCMP_S(q0, v1, v2, cNE); break; // Not Eual, ordered
|
||||
case 0x0d: VFCMP_S(q0, v2, v1, cLE); break; // Greater or Equal ordered
|
||||
case 0x0e: VFCMP_S(q0, v2, v1, cLT); break; // Greater ordered
|
||||
case 0x0f: VSEQ_B(q0, v1, v1); break; // true
|
||||
}
|
||||
XVXOR_V(v0, v0, v0);
|
||||
XVPERMI_Q(v0, v1, XVPERMI_IMM_4_0(3, 0));
|
||||
XVINSVE0_W(v0, q0, 0);
|
||||
YMM_UNMARK_UPPER_ZERO(v0);
|
||||
break;
|
||||
case 0xE6:
|
||||
INST_NAME("CVTDQ2PD Gx, Ex");
|
||||
nextop = F8;
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
if(vex.l){
|
||||
GETEYx(v1, 0, 0);
|
||||
GETGYy_empty(v0);
|
||||
XVFFINTL_D_W(v0, v1);
|
||||
XVFFINTH_D_W(d0, v1);
|
||||
XVPERMI_Q(v0, d0, XVPERMI_IMM_4_0(0, 2));
|
||||
}else{
|
||||
GETEYSD(v1, 0, 0);
|
||||
GETGYx_empty(v0);
|
||||
VFFINTL_D_W(v0, v1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
Loaded 100 of 395 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user