mirror of
https://github.com/ptitSeb/box64.git
synced 2026-11-09 04:09:46 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
03d220b1d2 | ||
|
|
053c4fd6bb | ||
|
|
7b0fada974 | ||
|
|
d09b46c1bf | ||
|
|
294178b598 | ||
|
|
e9242b8849 | ||
|
|
c5755c8241 | ||
|
|
75dcfb225a | ||
|
|
067e84eb05 | ||
|
|
faffa2a4d0 | ||
|
|
c3659df777 | ||
|
|
5aac024868 | ||
|
|
a4523caf81 | ||
|
|
db1c2cedbf | ||
|
|
4b96a74fc3 | ||
|
|
1b131d28df | ||
|
|
ec2e94249b | ||
|
|
0ffb15fce3 | ||
|
|
61a62645e8 | ||
|
|
e4edb65c2b | ||
|
|
b49bcbf68b | ||
|
|
eb69484bd6 | ||
|
|
195ac02ea1 | ||
|
|
8ebe32257e | ||
|
|
89e470d59c | ||
|
|
7a76430e87 | ||
|
|
60890a550b | ||
|
|
2038df85c0 | ||
|
|
ab5d2eba64 | ||
|
|
b142c5a181 | ||
|
|
37ed49cbb8 | ||
|
|
94ed2596c0 | ||
|
|
84498707dd | ||
|
|
d29be5fd14 | ||
|
|
53bb00a769 | ||
|
|
038e9511d1 | ||
|
|
94789d6705 | ||
|
|
67b15f09cf | ||
|
|
a0693590bd | ||
|
|
f1df65d88f | ||
|
|
6697c7d229 | ||
|
|
6a41f33bf3 | ||
|
|
67f7c988d5 | ||
|
|
01da6215de | ||
|
|
1fc558fcab | ||
|
|
c835881a77 | ||
|
|
a9f4e72c4b | ||
|
|
1f46ca81af | ||
|
|
8dbeee5dcb | ||
|
|
7a4cf9fc9e | ||
|
|
2fdd7f6188 | ||
|
|
803d8ac28a | ||
|
|
77c2683762 | ||
|
|
ae9ee3d9d8 | ||
|
|
6947a5bb94 | ||
|
|
103875b487 | ||
|
|
4c234b0418 | ||
|
|
abd1ebb425 | ||
|
|
e994c65116 | ||
|
|
c52b36abd4 | ||
|
|
a42936d998 | ||
|
|
e09adad1b9 | ||
|
|
b6429edf09 | ||
|
|
1e2bae9237 | ||
|
|
b7ddb92c80 | ||
|
|
d40f51bdc5 | ||
|
|
b78ffcfad8 | ||
|
|
3f9c5c496c | ||
|
|
37068c4f36 | ||
|
|
18a02fafb1 | ||
|
|
06d4fc79ec | ||
|
|
fa874ffcbc | ||
|
|
b729e3e37b | ||
|
|
73e7c6b480 | ||
|
|
5916869329 | ||
|
|
c9f3b990b4 | ||
|
|
6592b63800 | ||
|
|
1898d35c53 | ||
|
|
77f7c1278b | ||
|
|
1c7a7c9895 | ||
|
|
bd23f259cc | ||
|
|
efe1eb73dc | ||
|
|
8c51be6985 | ||
|
|
f25af13f79 | ||
|
|
019f85e4a3 | ||
|
|
7af5f625d7 | ||
|
|
a1ac9cccc4 | ||
|
|
b13811259a | ||
|
|
a7f4041604 | ||
|
|
72e05a52b2 | ||
|
|
e1e3122a1f | ||
|
|
4f88b2bdd7 | ||
|
|
5b8a71d720 | ||
|
|
58021bbf42 | ||
|
|
45d3cbd1b4 | ||
|
|
e07ec82344 | ||
|
|
37eb5492ba | ||
|
|
0e7b986116 | ||
|
|
be16c14dcb | ||
|
|
a1c29448a3 | ||
|
|
16bdcc0c93 | ||
|
|
2798c3c8cd | ||
|
|
d7538334e0 | ||
|
|
5dbcc4ad0d | ||
|
|
2cd4d60325 | ||
|
|
3dc00e9262 | ||
|
|
649af04fa5 | ||
|
|
3b97efb9ca | ||
|
|
8005af1387 | ||
|
|
5b45329968 | ||
|
|
b1379c88d4 | ||
|
|
274949f9d0 | ||
|
|
4a70577e6f | ||
|
|
b818a29499 | ||
|
|
69c88442b4 | ||
|
|
3d0b4ac9e1 | ||
|
|
4be5149b8d | ||
|
|
76ba181d98 | ||
|
|
4542244c4f | ||
|
|
a58e9d1dc9 | ||
|
|
938a2379c6 | ||
|
|
881814b21c | ||
|
|
915c4bf3b7 | ||
|
|
7a8a1a7791 | ||
|
|
e38d20e610 | ||
|
|
3d18e9c9e2 | ||
|
|
27685a4680 | ||
|
|
81b26569e5 | ||
|
|
76bbca2808 | ||
|
|
b435966bd0 | ||
|
|
be0839a478 | ||
|
|
f81f29b19a | ||
|
|
816c4bdb61 | ||
|
|
a9ddd396c4 | ||
|
|
f0b060dadd | ||
|
|
b1eabd7583 | ||
|
|
7a2d9967f5 | ||
|
|
2aeddc8829 | ||
|
|
df4dcf88da | ||
|
|
8160a90fd5 | ||
|
|
a8adde9234 | ||
|
|
daa3fca1f1 | ||
|
|
d744026819 | ||
|
|
689d6b9330 | ||
|
|
22fdc90fe2 | ||
|
|
78193c5f1a | ||
|
|
51d2b73cd7 | ||
|
|
7b5200094c | ||
|
|
5d14413b89 | ||
|
|
ec54969094 | ||
|
|
11513d662d | ||
|
|
6487ee0eda | ||
|
|
8d7db7f1fb | ||
|
|
11563f3b62 | ||
|
|
ff566e8116 | ||
|
|
1ddf9a0a00 | ||
|
|
35fa13899a | ||
|
|
5ee4385477 | ||
|
|
25000d0903 | ||
|
|
b96e410f53 | ||
|
|
6203880a5f | ||
|
|
889dd64c5f | ||
|
|
198eea49a8 | ||
|
|
b500a6ebc2 | ||
|
|
cb26a742ff | ||
|
|
4b44501d17 | ||
|
|
830cc8a498 | ||
|
|
16b0922ec5 | ||
|
|
9791016c74 | ||
|
|
ced1157132 | ||
|
|
56982e4c05 | ||
|
|
f5e93a14a2 | ||
|
|
eae608f35c | ||
|
|
89dbd81f27 | ||
|
|
c835227b8b | ||
|
|
57f07446ea | ||
|
|
7b2e084170 | ||
|
|
ab70523b39 | ||
|
|
f0859e6462 | ||
|
|
737a93a77c | ||
|
|
17cbeab0be | ||
|
|
313e16d2bc | ||
|
|
ae8b5b4239 | ||
|
|
1aa29ec1d3 | ||
|
|
f72d43b77e | ||
|
|
25de8bd35c | ||
|
|
5c9dc159d2 | ||
|
|
5a4021d72b | ||
|
|
ebaea69204 | ||
|
|
a221d50c17 | ||
|
|
4441be7a02 | ||
|
|
bb7dfd395f | ||
|
|
b552de33f9 | ||
|
|
35c8beb15f | ||
|
|
e1fd56123c | ||
|
|
b7ae6ebc27 | ||
|
|
9b904c622a | ||
|
|
950371427d | ||
|
|
be63129179 | ||
|
|
02423c2d7d | ||
|
|
4add55aa45 | ||
|
|
7334bb46c6 | ||
|
|
9c962f8b2c | ||
|
|
1f73944603 | ||
|
|
e844c5baa3 | ||
|
|
c849178bf8 | ||
|
|
ff4ae1f4d8 | ||
|
|
f7acb78743 | ||
|
|
6796b9ca02 | ||
|
|
e4da025dc0 | ||
|
|
b6b069cf8d | ||
|
|
f9475aa540 | ||
|
|
c6f0872e50 | ||
|
|
71dc02e06f | ||
|
|
e9715e4f0f | ||
|
|
8f197a7c08 | ||
|
|
3542c88dc1 | ||
|
|
4585b74310 | ||
|
|
768dfd37bb | ||
|
|
d8212fab48 | ||
|
|
740f4a19dc | ||
|
|
c469ed867a | ||
|
|
37dcb1a77b | ||
|
|
2e90a5dbaf | ||
|
|
d988a39456 | ||
|
|
fc381e744e | ||
|
|
e52b24b615 | ||
|
|
7158405b73 | ||
|
|
e059506d5e | ||
|
|
6da3a1265d | ||
|
|
d51997bc77 | ||
|
|
af555abb6f | ||
|
|
926e4b2da8 | ||
|
|
4903177bab | ||
|
|
d8a6fa0395 | ||
|
|
69127efae9 | ||
|
|
6f0db360a4 | ||
|
|
223de50ec9 | ||
|
|
5cfad22165 | ||
|
|
815836d285 | ||
|
|
468a3c2165 | ||
|
|
3afe87bcce | ||
|
|
d79d6bd6c2 | ||
|
|
cc6500b7dd | ||
|
|
ad494480ce | ||
|
|
854f6675db | ||
|
|
fc15743ff9 | ||
|
|
91ead3b12a | ||
|
|
75aaf7aa64 | ||
|
|
39a66e25ee | ||
|
|
574d6f9dab | ||
|
|
c39869b770 | ||
|
|
302b6493e2 | ||
|
|
20ea2987a8 | ||
|
|
eee547d50a | ||
|
|
a19f4b9eca | ||
|
|
6f3f3e0e85 | ||
|
|
2384462f61 | ||
|
|
e6e6c3ac65 | ||
|
|
102e6a1f61 | ||
|
|
460e6c517d | ||
|
|
965105c08a | ||
|
|
3fef880a7d | ||
|
|
e7b4c79d12 | ||
|
|
7cdfa187c5 | ||
|
|
d0da57547e | ||
|
|
e60fd72672 | ||
|
|
c6ae7d36dd | ||
|
|
3836625017 | ||
|
|
319f67d577 | ||
|
|
28d12f6785 | ||
|
|
e7113b228f | ||
|
|
bc3cfe82cf | ||
|
|
6ccac8ab5a | ||
|
|
c9d756eeea | ||
|
|
549b57ee30 | ||
|
|
660dbfc3ad | ||
|
|
d89ad5f1b9 | ||
|
|
00a7d321a7 | ||
|
|
4c9765cd5e | ||
|
|
fe307dbc96 | ||
|
|
518c860e5d | ||
|
|
053c389cfb | ||
|
|
81be6b1f30 | ||
|
|
3d975b090e | ||
|
|
882d933d84 | ||
|
|
9579dd9ff1 | ||
|
|
46a91e0ad9 | ||
|
|
b26a20e709 | ||
|
|
d7eb87129e | ||
|
|
7f569247d5 | ||
|
|
1ba0ea157f | ||
|
|
1e64476f31 | ||
|
|
96080e48cf | ||
|
|
4695a4ff3c | ||
|
|
8f3018e10c | ||
|
|
24b0ba9885 | ||
|
|
4f04deadfe | ||
|
|
064c2b037e | ||
|
|
12a90ebe98 | ||
|
|
5cd201241b | ||
|
|
6b2373af93 | ||
|
|
cf32412f98 | ||
|
|
f559bc48a4 | ||
|
|
0021fbbea3 | ||
|
|
ee530a7331 | ||
|
|
b7cb36d362 | ||
|
|
1bd471bf13 | ||
|
|
21911620c8 | ||
|
|
56f58501ec | ||
|
|
a89748e9e5 | ||
|
|
91f9a58b30 | ||
|
|
fea05a30e8 | ||
|
|
e678e8428b | ||
|
|
20377b9927 | ||
|
|
163689d2bb | ||
|
|
e49551bda5 | ||
|
|
514427cf8a | ||
|
|
68f5512ee7 | ||
|
|
b3165e62ab | ||
|
|
0fbf5f1896 | ||
|
|
592a2a75bb | ||
|
|
6c46e3d9b1 | ||
|
|
fa85d4d900 | ||
|
|
51d9eb966d | ||
|
|
310d4016fa | ||
|
|
0bb41a73c2 | ||
|
|
f9f082ee53 | ||
|
|
66bb1aeb89 | ||
|
|
91848efa34 | ||
|
|
5ea247b84c | ||
|
|
8c991cb676 | ||
|
|
70770db8be | ||
|
|
d0a5352c1a | ||
|
|
7391befb7e | ||
|
|
c9b6b5fbe0 | ||
|
|
62765f151a | ||
|
|
d592c1996d | ||
|
|
8b3d4404d7 | ||
|
|
b060fca66c | ||
|
|
4aab7a02f4 | ||
|
|
6d7af8674a | ||
|
|
5fc3188bc8 | ||
|
|
f4f868831a | ||
|
|
1e89ccb17e | ||
|
|
e80b595e8e | ||
|
|
ecc5375615 | ||
|
|
8da0fab674 | ||
|
|
fb955a3975 | ||
|
|
8cd3ba8c9e | ||
|
|
8cba915bca | ||
|
|
cd3163a785 | ||
|
|
b472459a22 | ||
|
|
42c241ee4e | ||
|
|
fb6ee29539 | ||
|
|
be6104c2ed | ||
|
|
3f90221b18 | ||
|
|
b5c792f5f0 | ||
|
|
b45d75f0c4 | ||
|
|
b68d46311d | ||
|
|
2c7a2082e6 | ||
|
|
3230265646 | ||
|
|
c2a77fca27 | ||
|
|
670876112e | ||
|
|
495d3cc4c0 | ||
|
|
b7ab26073e | ||
|
|
1c3df4b92c | ||
|
|
b1ba548d62 | ||
|
|
da4f574bdd | ||
|
|
8561a4a833 | ||
|
|
c40f9651bc | ||
|
|
104e582253 | ||
|
|
03c69338f5 | ||
|
|
0fa28b87f1 | ||
|
|
4ae94c5168 | ||
|
|
a429ca70e7 | ||
|
|
ee760fced1 | ||
|
|
a80659075d | ||
|
|
da0d0c1fc2 | ||
|
|
5ea2c245d6 | ||
|
|
e7b71cba5f | ||
|
|
d2817e7246 | ||
|
|
7ae8e9a86f | ||
|
|
0a59695fb3 | ||
|
|
cfdeb3685c | ||
|
|
fdf01ace3f | ||
|
|
30689882f0 | ||
|
|
d2e8ff5118 | ||
|
|
ec385c8e75 | ||
|
|
3aed032738 | ||
|
|
409b5a37fb | ||
|
|
9587e490cc | ||
|
|
ad40638345 | ||
|
|
443fe043e4 | ||
|
|
6d9560870d | ||
|
|
95d6106e3a | ||
|
|
5fb1ee033e | ||
|
|
fed73858c6 | ||
|
|
cb5a52bf40 | ||
|
|
eaa5f8feec | ||
|
|
8c6d9f04ec | ||
|
|
45f7b4991f | ||
|
|
98151eaebf | ||
|
|
933381f5fa | ||
|
|
a021fc2005 | ||
|
|
75e9aae281 | ||
|
|
b0de73852c | ||
|
|
d7744ea22d | ||
|
|
d3d3fa25f5 | ||
|
|
98162e395f | ||
|
|
9511d83955 | ||
|
|
10cbb3c8a9 | ||
|
|
0a3fa1c918 | ||
|
|
75e8b9961b | ||
|
|
5ab56ee172 | ||
|
|
7873b70306 | ||
|
|
86d9d851c6 | ||
|
|
aed08d428e | ||
|
|
affeef2380 | ||
|
|
a6c1e4126e | ||
|
|
ba630300b6 | ||
|
|
0e32c17076 | ||
|
|
14569db74d | ||
|
|
c519556962 | ||
|
|
c7280d9312 | ||
|
|
daca99017b | ||
|
|
546238681e | ||
|
|
87327b182f | ||
|
|
5b9951e1bd | ||
|
|
6ce22546fe | ||
|
|
2da064d04d | ||
|
|
77141304f6 | ||
|
|
3336cb6248 | ||
|
|
7fa3a1e627 | ||
|
|
d28c8aa41a | ||
|
|
7b065eb17a | ||
|
|
7f23664566 | ||
|
|
d555d9661f | ||
|
|
18888e404e | ||
|
|
394513971c | ||
|
|
8b75020036 | ||
|
|
e1d121aa6b | ||
|
|
30285d9ec6 | ||
|
|
9795027988 | ||
|
|
d49fb1568e | ||
|
|
ea067beac2 | ||
|
|
8905a31469 | ||
|
|
e6fd9c05f1 | ||
|
|
a79128e951 | ||
|
|
1793c2a182 | ||
|
|
b72002703e | ||
|
|
a17a97a545 | ||
|
|
0d73fc7228 | ||
|
|
8aab7296b8 | ||
|
|
4aa7eb1187 | ||
|
|
1af85c69a1 | ||
|
|
3087ea0e61 | ||
|
|
b0ad333ea4 | ||
|
|
835ecf8a19 | ||
|
|
470ff6e652 | ||
|
|
3ef6d28108 | ||
|
|
fb701d8e39 | ||
|
|
d4a539b957 | ||
|
|
7c4c6823fe | ||
|
|
3fc677cb85 |
No files matched your search
@@ -27,7 +27,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [X64, RISCV, RK3588, ARM64, ANDROID, TERMUX, LARCH64, ANDROID_GLIBC]
|
||||
platform: [X64, RISCV, RK3588, ARM64, ANDROID, TERMUX, LARCH64, ANDROID_GLIBC, WOW64]
|
||||
type: [Release, Trace, StaticBuild, Box32]
|
||||
os: [ubuntu-latest, ubuntu-22.04-arm]
|
||||
exclude:
|
||||
@@ -57,6 +57,14 @@ jobs:
|
||||
os: ubuntu-22.04-arm
|
||||
- platform: ANDROID_GLIBC
|
||||
os: ubuntu-latest
|
||||
- platform: WOW64
|
||||
os: ubuntu-latest
|
||||
- platform: WOW64
|
||||
type: Trace
|
||||
- platform: WOW64
|
||||
type: StaticBuild
|
||||
- platform: WOW64
|
||||
type: Box32
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
@@ -70,8 +78,8 @@ jobs:
|
||||
sudo apt-get -y install git cmake make python3 patchelf
|
||||
if [[ ${{ matrix.platform }} == 'ANDROID' || ${{ matrix.platform }} == 'TERMUX' ]]; then
|
||||
sudo apt-get -y install p7zip
|
||||
wget https://dl.google.com/android/repository/android-ndk-r26b-linux.zip
|
||||
unzip android-ndk-r26b-linux.zip
|
||||
wget -q https://dl.google.com/android/repository/android-ndk-r26b-linux.zip
|
||||
unzip -qq android-ndk-r26b-linux.zip
|
||||
echo "BOX64_COMPILER=$PWD/android-ndk-r26b/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android31-clang" >> $GITHUB_ENV
|
||||
echo "BOX64_PLATFORM_MARCRO=-DANDROID=1 -DARM_DYNAREC=1 -DBAD_SIGNAL=1" >> $GITHUB_ENV
|
||||
git clone https://github.com/termux/termux-docker.git
|
||||
@@ -82,13 +90,21 @@ jobs:
|
||||
sudo apt-get -y install git gcc-aarch64-linux-gnu
|
||||
echo "BOX64_PLATFORM_MARCRO=-DARM64=1 -DWINLATOR_GLIBC=1 -DARM_DYNAREC=1 -DBAD_SIGNAL=1" >> $GITHUB_ENV
|
||||
echo "BOX64_COMPILER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
|
||||
elif [[ ${{ matrix.platform }} == 'WOW64' ]]; then
|
||||
sudo apt-get -y install git gcc-aarch64-linux-gnu
|
||||
echo "BOX64_PLATFORM_MARCRO=-DWOW64=1 -DARM_DYNAREC=1" >> $GITHUB_ENV
|
||||
echo "BOX64_COMPILER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
|
||||
export LLVM_MINGW_VERSION=20250430
|
||||
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
|
||||
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://mirrors.utermux.dev/termux/termux-main/pool/main/liba/libandroid-sysv-semaphore/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_aarch64.deb
|
||||
7z x libandroid-sysv-semaphore_0.1_aarch64.deb
|
||||
tar -xf data.tar.xz
|
||||
sudo cp -rf data /
|
||||
@@ -193,6 +209,7 @@ jobs:
|
||||
|
||||
- name: "Build Box64"
|
||||
run: |
|
||||
export PATH=$PATH:${{ env.MINGW_COMPILER_PATH }}
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_C_COMPILER=${{ env.BOX64_COMPILER }}\
|
||||
@@ -257,6 +274,8 @@ jobs:
|
||||
|
||||
BOX64_DYNAREC=0 ctest $CTEST_OPTIONS
|
||||
ctest $CTEST_OPTIONS
|
||||
elif [[ ${{matrix.type}} == 'Box32' ]]; then
|
||||
ctest $CTEST_OPTIONS
|
||||
else
|
||||
ctest -j$(nproc)
|
||||
fi
|
||||
@@ -306,12 +325,6 @@ jobs:
|
||||
|
||||
7z -tzip -mx=5 a box64-latest.rat files pkg-header
|
||||
|
||||
- name: "Upload Artifact"
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: box64-${{ matrix.platform }}-${{ matrix.type }}
|
||||
path: build/box64
|
||||
|
||||
- name: "Upload WCP file"
|
||||
if: matrix.platform == 'ANDROID_GLIBC' && matrix.type != 'StaticBuild'
|
||||
uses: actions/upload-artifact@v4
|
||||
@@ -325,3 +338,10 @@ jobs:
|
||||
with:
|
||||
name: box64-MiceWine-${{ matrix.type }}
|
||||
path: build/box64-latest.rat
|
||||
|
||||
- name: "Upload WowBox64 file"
|
||||
if: matrix.platform == 'WOW64' && matrix.type == 'Release'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: wowbox64-${{ matrix.type }}
|
||||
path: build/wowbox64-prefix/src/wowbox64-build/wowbox64.dll
|
||||
+130
-73
@@ -44,6 +44,7 @@ option(BOX32 "Set to ON to add Linux 32bits support (experimental, do not use)"
|
||||
option(BOX32_BINFMT "Also setup binfmt integration for box32" ${BOX32_BINFMT})
|
||||
option(LARCH64_ABI_1 "Set to ON if building for Loongarch64 ABI 1.0 system" ${LARCH64_ABI_1})
|
||||
option(GDBJIT "Set to ON to enable GDB JIT support" ${GDBJIT})
|
||||
option(WOW64 "Set to ON if you want a WOW64 PE build in addition")
|
||||
|
||||
if(TERMUX)
|
||||
set(TERMUX_PATH "/data/data/com.termux/files")
|
||||
@@ -141,68 +142,53 @@ endif()
|
||||
if(RPI3ARM64)
|
||||
add_definitions(-DRPI)
|
||||
add_definitions(-DRPI3ARM64)
|
||||
add_definitions(-pipe -march=armv8-a+crc -mtune=cortex-a53)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8-a+crc -mtune=cortex-a53")
|
||||
set(CFLAGS -pipe -march=armv8-a+crc -mtune=cortex-a53)
|
||||
elseif(RPI4ARM64)
|
||||
add_definitions(-DRPI)
|
||||
add_definitions(-DRPI4ARM64)
|
||||
add_definitions(-pipe -march=armv8-a+crc -mtune=cortex-a72)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8-a+crc -mtune=cortex-a72")
|
||||
set(CFLAGS -pipe -march=armv8-a+crc -mtune=cortex-a72)
|
||||
elseif(RPI5ARM64)
|
||||
add_definitions(-DRPI)
|
||||
add_definitions(-DRPI5ARM64)
|
||||
add_definitions(-pipe -march=armv8.2-a+crc+crypto+fp16+rcpc+dotprod -mtune=cortex-a76)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8.2-a+crc+crypto+fp16+rcpc+dotprod -mtune=cortex-a76")
|
||||
set(CFLAGS -pipe -march=armv8.2-a+crc+crypto+fp16+rcpc+dotprod -mtune=cortex-a76)
|
||||
elseif(RK3326)
|
||||
add_definitions(-DRK3326)
|
||||
add_definitions(-pipe -march=armv8-a+crc+simd+crypto -mcpu=cortex-a35+crypto)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8-a+crc+simd+crypto -mcpu=cortex-a35+crypto")
|
||||
set(CFLAGS -pipe -march=armv8-a+crc+simd+crypto -mcpu=cortex-a35+crypto)
|
||||
elseif(RK3399)
|
||||
add_definitions(-DRK3399)
|
||||
add_definitions(-pipe -march=armv8-a+crc+simd+crypto -mcpu=cortex-a72.cortex-a53+crypto)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8-a+crc+simd+crypto -mcpu=cortex-a72.cortex-a53+crypto")
|
||||
set(CFLAGS -pipe -march=armv8-a+crc+simd+crypto -mcpu=cortex-a72.cortex-a53+crypto)
|
||||
elseif(RK3588)
|
||||
add_definitions(-DRK3588)
|
||||
add_definitions(-pipe -mcpu=cortex-a76.cortex-a55+crypto)
|
||||
add_definitions(-DBAD_SIGNAL)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -mcpu=cortex-a76.cortex-a55+crypto")
|
||||
set(CFLAGS -pipe -mcpu=cortex-a76.cortex-a55+crypto)
|
||||
elseif(ODROIDN2)
|
||||
add_definitions(-DODROIDN2)
|
||||
add_definitions(-march=armv8-a+crc+simd+crypto -mcpu=cortex-a73.cortex-a53+crypto)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8-a+crc+simd+crypto -mcpu=cortex-a73.cortex-a53+crypto")
|
||||
set(CFLAGS -march=armv8-a+crc+simd+crypto -mcpu=cortex-a73.cortex-a53+crypto)
|
||||
elseif(TEGRAX1)
|
||||
add_definitions(-DTEGRAX1)
|
||||
add_definitions(-pipe -march=armv8-a+crc+simd+crypto -mcpu=cortex-a57+crypto)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8-a+crc+simd+crypto -mcpu=cortex-a57+crypto")
|
||||
set(CFLAGS -pipe -march=armv8-a+crc+simd+crypto -mcpu=cortex-a57+crypto)
|
||||
elseif(TEGRA_T194)
|
||||
add_definitions(-DTEGRA_T194)
|
||||
add_definitions(-pipe -march=armv8.2-a+fp16+simd+crypto+predres -mcpu=cortex-a76+crypto -mtune=cortex-a76)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8.2-a+fp16+simd+crypto+predres -mcpu=cortex-a76+crypto -mtune=cortex-a76")
|
||||
set(CFLAGS -pipe -march=armv8.2-a+fp16+simd+crypto+predres -mcpu=cortex-a76+crypto -mtune=cortex-a76)
|
||||
elseif(TEGRA_T234)
|
||||
add_definitions(-DTEGRA_T234)
|
||||
add_definitions(-pipe -march=armv8.2-a+fp16+simd+crypto+predres -mcpu=cortex-a78ae+crypto -mtune=cortex-a78ae)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8.2-a+fp16+simd+crypto+predres -mcpu=cortex-a78ae+crypto -mtune=cortex-a78ae")
|
||||
set(CFLAGS -pipe -march=armv8.2-a+fp16+simd+crypto+predres -mcpu=cortex-a78ae+crypto -mtune=cortex-a78ae)
|
||||
elseif(PHYTIUM)
|
||||
add_definitions(-DPHYTIUM)
|
||||
add_definitions(-pipe -march=armv8.1-a+crc+simd+crypto)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8.1-a+crc+simd+crypto+aes")
|
||||
set(CFLAGS -pipe -march=armv8.1-a+crc+simd+crypto)
|
||||
elseif(SD845)
|
||||
add_definitions(-DSD845)
|
||||
add_definitions(-pipe -march=armv8.2-a+simd+crypto -mtune=cortex-a75.cortex-a55)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8.2-a+simd+crypto -mtune=cortex-a75.cortex-a55")
|
||||
set(CFLAGS -pipe -march=armv8.2-a+simd+crypto -mtune=cortex-a75.cortex-a55)
|
||||
elseif(SD865)
|
||||
add_definitions(-DSD865)
|
||||
#note that cortex-a77.cortex-a55 is not supported, so fall back to a76 instead
|
||||
add_definitions(-pipe -march=armv8.2-a+simd+crypto -mtune=cortex-a76.cortex-a55)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8.2-a+simd+crypto -mtune=cortex-a76.cortex-a55")
|
||||
set(CFLAGS -pipe -march=armv8.2-a+simd+crypto -mtune=cortex-a76.cortex-a55)
|
||||
elseif(SD888)
|
||||
add_definitions(-DSD888)
|
||||
add_definitions(-pipe -march=armv8.4-a+simd+crypto)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8.4-a+simd+crypto")
|
||||
set(CFLAGS -pipe -march=armv8.4-a+simd+crypto)
|
||||
elseif(SD8G2)
|
||||
add_definitions(-DSD8G2)
|
||||
add_definitions(-pipe -march=armv9-a+i8mm+sm4+sha3+rcpc+crypto+nosve+nosve2)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv9-a+i8mm+sm4+sha3+rcpc+crypto+nosve+nosve2")
|
||||
set(CFLAGS -pipe -march=armv9-a+i8mm+sm4+sha3+rcpc+crypto+nosve+nosve2)
|
||||
elseif(SDORYON1)
|
||||
add_definitions(-DSDORYON1)
|
||||
# NOTE
|
||||
@@ -219,37 +205,38 @@ elseif(SDORYON1)
|
||||
# * the 3rd positional argument is represented as the "scheduler"
|
||||
# * the 6th positional argument is represented as the "cost"
|
||||
# I've chosen the a57 because I don't know if I should choose the a72
|
||||
add_definitions(-pipe -march=armv8.6-a+crypto+sm4+sha3+fp16 -mtune=cortex-a57)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8.6-a+crypto+sm4+sha3+fp16 -mtune=cortex-a57")
|
||||
set(CFLAGS -pipe -march=armv8.6-a+crypto+sm4+sha3+fp16 -mtune=cortex-a57)
|
||||
elseif(ADLINK)
|
||||
add_definitions(-DADLINK)
|
||||
add_definitions(-pipe -mcpu=neoverse-n1 -fuse-ld=gold -fuse-linker-plugin)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -mcpu=neoverse-n1")
|
||||
set(CFLAGS -pipe -mcpu=neoverse-n1 -fuse-ld=gold -fuse-linker-plugin)
|
||||
elseif(M1)
|
||||
add_definitions(-DM1)
|
||||
add_definitions(-pipe -march=armv8.5-a+simd+crypto)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8.5-a+simd+crypto")
|
||||
set(CFLAGS -pipe -march=armv8.5-a+simd+crypto)
|
||||
elseif(LARCH64)
|
||||
add_definitions(-DLA64)
|
||||
add_definitions(-pipe -march=loongarch64)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=loongarch64")
|
||||
set(CFLAGS -pipe -march=loongarch64)
|
||||
set(ASMFLAGS -pipe -march=loongarch64)
|
||||
elseif(RV64)
|
||||
add_definitions(-DRV64)
|
||||
add_definitions(-pipe -march=rv64gc)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=rv64gc")
|
||||
set(CFLAGS -pipe -march=rv64gc)
|
||||
set(ASMFLAGS -pipe -march=rv64gc)
|
||||
elseif(PPC64LE)
|
||||
add_definitions(-DPPC64LE)
|
||||
elseif(LX2160A)
|
||||
add_definitions(-DLX2160A)
|
||||
add_definitions(-pipe -march=armv8-a+crypto+crc -mcpu=cortex-a72+crypto)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8-a+crypto+crc -mcpu=cortex-a72+crypto")
|
||||
set(CFLAGS -pipe -march=armv8-a+crypto+crc -mcpu=cortex-a72+crypto)
|
||||
elseif(SW64)
|
||||
add_definitions(-DSW64)
|
||||
elseif(ARM64)
|
||||
#add_definitions(-pipe -march=native)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8-a+simd")
|
||||
elseif(ARM_DYNAREC)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8-a+crc+simd+crypto")
|
||||
endif()
|
||||
if(ARM_DYNAREC)
|
||||
if (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_C_COMPILER_VERSION VERSION_LESS "9.0")
|
||||
set(ASMFLAGS -pipe -march=armv8.2-a+crc+simd+crypto)
|
||||
else()
|
||||
#putting a random cpu that have 8.2 architecture so assembly can be build. the use of the feature are conditionnal anyway
|
||||
set(ASMFLAGS -pipe -mcpu=cortex-a76)
|
||||
endif()
|
||||
endif()
|
||||
if(ANDROID)
|
||||
add_definitions(-DANDROID)
|
||||
@@ -271,7 +258,7 @@ if(STATICBUILD)
|
||||
add_definitions(-DSTATICBUILD)
|
||||
add_definitions(-Wno-deprecated-declarations) #by-design, deprecated function can be used
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "-static")
|
||||
set(CMAKE_EXE_LINKER_FLAGS -static)
|
||||
set(HAVE_TRACE OFF)
|
||||
endif()
|
||||
if(BOX32)
|
||||
@@ -360,6 +347,17 @@ set_source_files_properties(
|
||||
PROPERTIES GENERATED TRUE
|
||||
HEADER_FILE_ONLY TRUE)
|
||||
|
||||
set(OS_LINUX_SRC
|
||||
"${BOX64_ROOT}/src/os/backtrace.c"
|
||||
"${BOX64_ROOT}/src/os/emit_signals_linux.c"
|
||||
"${BOX64_ROOT}/src/os/freq_linux.c"
|
||||
"${BOX64_ROOT}/src/os/os_linux.c"
|
||||
"${BOX64_ROOT}/src/os/perfmap.c"
|
||||
"${BOX64_ROOT}/src/os/symbolfuncs_linux.c"
|
||||
"${BOX64_ROOT}/src/os/my_cpuid_linux.c"
|
||||
"${BOX64_ROOT}/src/os/my_cpuid_common.c"
|
||||
)
|
||||
|
||||
set(ELFLOADER_SRC
|
||||
"${BOX64_ROOT}/src/main.c"
|
||||
"${BOX64_ROOT}/src/core.c"
|
||||
@@ -373,6 +371,7 @@ set(ELFLOADER_SRC
|
||||
"${BOX64_ROOT}/src/elfs/elfhash.c"
|
||||
"${BOX64_ROOT}/src/elfs/elfload_dump.c"
|
||||
"${BOX64_ROOT}/src/elfs/elfdwarf_private.c"
|
||||
"${BOX64_ROOT}/src/emu/entrypoint.c"
|
||||
"${BOX64_ROOT}/src/emu/x64compstrings.c"
|
||||
"${BOX64_ROOT}/src/emu/x64emu.c"
|
||||
"${BOX64_ROOT}/src/emu/x64printer.c"
|
||||
@@ -396,14 +395,16 @@ set(ELFLOADER_SRC
|
||||
"${BOX64_ROOT}/src/tools/bitutils.c"
|
||||
"${BOX64_ROOT}/src/tools/box64stack.c"
|
||||
"${BOX64_ROOT}/src/tools/bridge.c"
|
||||
"${BOX64_ROOT}/src/tools/alternate.c"
|
||||
"${BOX64_ROOT}/src/tools/callback.c"
|
||||
"${BOX64_ROOT}/src/tools/cleanup.c"
|
||||
"${BOX64_ROOT}/src/tools/gdbjit.c"
|
||||
"${BOX64_ROOT}/src/tools/my_cpuid.c"
|
||||
"${BOX64_ROOT}/src/tools/fileutils.c"
|
||||
"${BOX64_ROOT}/src/tools/pathcoll.c"
|
||||
"${BOX64_ROOT}/src/tools/rbtree.c"
|
||||
"${BOX64_ROOT}/src/tools/env.c"
|
||||
"${BOX64_ROOT}/src/tools/wine_tools.c"
|
||||
"${BOX64_ROOT}/src/tools/pe_tools.c"
|
||||
"${BOX64_ROOT}/src/wrapped/generated/wrapper.c"
|
||||
)
|
||||
if(NOT STATICBUILD)
|
||||
@@ -464,6 +465,7 @@ set(INTERPRETER
|
||||
"${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"
|
||||
@@ -576,6 +578,9 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlcms2.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedldlinux.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibasound.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibavcodec58.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibavformat58.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibavutil56.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibbsd.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibc.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibcmusl.c"
|
||||
@@ -861,6 +866,14 @@ if(BOX32)
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibvdpau.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappednsl.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibcups.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedgbm.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibegl.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibglx.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedselinux.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedblkid.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedmount.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappeddbus.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedcurl.c"
|
||||
)
|
||||
endif()
|
||||
string(REPLACE ".c" "_private.h" MODROOT ${BOX64_ROOT})
|
||||
@@ -871,7 +884,7 @@ if(BOX32)
|
||||
set(WRAPPEDS32_HEAD ${WRAPPEDS32_HEAD} ${B})
|
||||
set_source_files_properties(${A} PROPERTIES OBJECT_DEPENDS ${B})
|
||||
endforeach()
|
||||
|
||||
|
||||
set(WRAPPER32 "${BOX64_ROOT}/src/wrapped32/generated/wrapper32.c" "${BOX64_ROOT}/src/wrapped32/generated/wrapper32.h")
|
||||
|
||||
if(NOT CI)
|
||||
@@ -911,7 +924,9 @@ 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"
|
||||
|
||||
)
|
||||
set(DYNAREC_ASM
|
||||
${DYNAREC_ASM}
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/arm64_prolog.S"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/arm64_epilog.S"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/arm64_next.S"
|
||||
@@ -972,7 +987,9 @@ if(RV64_DYNAREC)
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/rv64_printer.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_jmpnext.c"
|
||||
"${BOX64_ROOT}/src/rv64detect.c"
|
||||
|
||||
)
|
||||
set(DYNAREC_ASM
|
||||
${DYNAREC_ASM}
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/rv64_prolog.S"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/rv64_epilog.S"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/rv64_next.S"
|
||||
@@ -1030,7 +1047,9 @@ 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"
|
||||
|
||||
)
|
||||
set(DYNAREC_ASM
|
||||
${DYNAREC_ASM}
|
||||
"${BOX64_ROOT}/src/dynarec/la64/la64_prolog.S"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/la64_epilog.S"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/la64_next.S"
|
||||
@@ -1051,6 +1070,7 @@ if(LARCH64_DYNAREC)
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_660f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_66f0.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_66f20f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_66f30f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_67.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_f0.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_f20f.c"
|
||||
@@ -1075,18 +1095,22 @@ if(DYNAREC)
|
||||
)
|
||||
endif()
|
||||
|
||||
add_library(dynarec_native OBJECT ${DYNAREC_SRC})
|
||||
set_source_files_properties(${DYNAREC_PASS} PROPERTIES COMPILE_OPTIONS "${CFLAGS}")
|
||||
set_source_files_properties(${DYNAREC_ASM} PROPERTIES COMPILE_OPTIONS "${ASMFLAGS}")
|
||||
set_source_files_properties(${INTERPRETER} PROPERTIES COMPILE_OPTIONS "${CFLAGS}")
|
||||
|
||||
add_library(dynarec_native OBJECT ${DYNAREC_SRC} ${DYNAREC_ASM})
|
||||
|
||||
add_library(native_pass0 OBJECT ${DYNAREC_PASS})
|
||||
set_target_properties(native_pass0 PROPERTIES COMPILE_FLAGS "-DSTEP=0")
|
||||
set_target_properties(native_pass0 PROPERTIES COMPILE_DEFINITIONS "STEP=0")
|
||||
add_library(native_pass1 OBJECT ${DYNAREC_PASS})
|
||||
set_target_properties(native_pass1 PROPERTIES COMPILE_FLAGS "-DSTEP=1")
|
||||
set_target_properties(native_pass1 PROPERTIES COMPILE_DEFINITIONS "STEP=1")
|
||||
add_library(native_pass2 OBJECT ${DYNAREC_PASS})
|
||||
set_target_properties(native_pass2 PROPERTIES COMPILE_FLAGS "-DSTEP=2")
|
||||
set_target_properties(native_pass2 PROPERTIES COMPILE_DEFINITIONS "STEP=2")
|
||||
add_library(native_pass3 OBJECT ${DYNAREC_PASS})
|
||||
set_target_properties(native_pass3 PROPERTIES COMPILE_FLAGS "-DSTEP=3")
|
||||
set_target_properties(native_pass3 PROPERTIES COMPILE_DEFINITIONS "STEP=3")
|
||||
add_library(test_interpreter OBJECT ${INTERPRETER})
|
||||
set_target_properties(test_interpreter PROPERTIES COMPILE_FLAGS "-DTEST_INTERPRETER")
|
||||
set_target_properties(test_interpreter PROPERTIES COMPILE_DEFINITIONS "TEST_INTERPRETER")
|
||||
add_dependencies(native_pass0 WRAPPERS)
|
||||
add_dependencies(native_pass1 WRAPPERS)
|
||||
add_dependencies(native_pass2 WRAPPERS)
|
||||
@@ -1112,12 +1136,14 @@ if(DYNAREC)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set_source_files_properties(${OS_LINUX_SRC} ${ELFLOADER_SRC} ${INTERPRETER} ${WRAPPEDS} ${WRAPPEDS32} PROPERTIES COMPILE_OPTIONS "${CFLAGS}")
|
||||
|
||||
# creates git_head.h
|
||||
if(DYNAREC)
|
||||
add_custom_command(
|
||||
OUTPUT "${BOX64_ROOT}/src/git_head.h"
|
||||
COMMAND sh -c "echo \\\#define GITREV \\\"$(git rev-parse --short HEAD)\\\">\"${BOX64_ROOT}/src/git_head.h\""
|
||||
DEPENDS dynarec ${ELFLOADER_SRC} ${INTERPRETER} ${WRAPPEDS} ${WRAPPEDS32}
|
||||
DEPENDS ${DYNAREC_SRC} ${DYNAREC_ASM} ${DYNAREC_PASS} ${ELFLOADER_SRC} ${INTERPRETER} ${WRAPPEDS} ${WRAPPEDS32}
|
||||
VERBATIM)
|
||||
else()
|
||||
add_custom_command(
|
||||
@@ -1127,9 +1153,19 @@ else()
|
||||
VERBATIM)
|
||||
endif()
|
||||
|
||||
add_custom_target(generate_git_head_target
|
||||
DEPENDS "${BOX64_ROOT}/src/git_head.h"
|
||||
)
|
||||
add_custom_target(functions_list DEPENDS "${BOX64_ROOT}/src/wrapped/generated/functions_list.txt" "${BOX64_ROOT}/src/wrapped32/generated/functions_list.txt")
|
||||
add_dependencies(generate_git_head_target functions_list)
|
||||
|
||||
add_library(interpreter OBJECT ${INTERPRETER})
|
||||
|
||||
add_executable(${BOX64} ${ELFLOADER_SRC} ${WRAPPEDS} ${WRAPPEDS32} "${BOX64_ROOT}/src/git_head.h")
|
||||
add_library(mainobj OBJECT ${OS_LINUX_SRC} ${ELFLOADER_SRC} ${WRAPPEDS} ${WRAPPEDS32})
|
||||
add_dependencies(mainobj generate_git_head_target)
|
||||
|
||||
add_executable(${BOX64})
|
||||
target_link_libraries(${BOX64} mainobj)
|
||||
set_target_properties(${BOX64} PROPERTIES ENABLE_EXPORTS ON)
|
||||
add_dependencies(${BOX64} WRAPPERS)
|
||||
if(BOX32)
|
||||
@@ -1297,6 +1333,27 @@ if(NOT TARGET uninstall)
|
||||
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
|
||||
endif()
|
||||
|
||||
string(REPLACE ";" "," DYNAREC_ASM_STR "${DYNAREC_ASM}")
|
||||
string(REPLACE ";" "," DYNAREC_PASS_STR "${DYNAREC_PASS}")
|
||||
string(REPLACE ";" "," INTERPRETER_STR "${INTERPRETER}")
|
||||
|
||||
if(WOW64 AND ARM_DYNAREC)
|
||||
include(ExternalProject)
|
||||
ExternalProject_Add(
|
||||
wowbox64
|
||||
SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/wow64"
|
||||
CMAKE_ARGS
|
||||
-DCMAKE_TOOLCHAIN_FILE=${CMAKE_CURRENT_SOURCE_DIR}/wow64/toolchain_mingw.cmake
|
||||
-DDYNAREC_PASS_STR=${DYNAREC_PASS_STR}
|
||||
-DDYNAREC_ASM_STR=${DYNAREC_ASM_STR}
|
||||
-DINTERPRETER_STR=${INTERPRETER_STR}
|
||||
INSTALL_COMMAND ""
|
||||
TEST_COMMAND ""
|
||||
BUILD_ALWAYS ON
|
||||
)
|
||||
add_dependencies(wowbox64 generate_git_head_target)
|
||||
endif()
|
||||
|
||||
set(CPACK_GENERATOR "DEB")
|
||||
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "ptitSeb")
|
||||
set(CPACK_PACKAGE_CONTACT "[email protected]")
|
||||
@@ -1513,11 +1570,14 @@ add_test(fpu_rounding ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref31.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
if(ARM_DYNAREC)
|
||||
set_tests_properties(fpu_rounding PROPERTIES ENVIRONMENT "BOX64_DYNAREC_FASTROUND=0;BOX64_DYNAREC_TEST=1")
|
||||
else()
|
||||
set_tests_properties(fpu_rounding PROPERTIES ENVIRONMENT "BOX64_DYNAREC=0")
|
||||
endif()
|
||||
set_tests_properties(fpu_rounding PROPERTIES ENVIRONMENT "BOX64_DYNAREC_FASTROUND=0")
|
||||
|
||||
add_test(x87pc ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test32 -D TEST_OUTPUT=tmpfile32.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref32.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
set_tests_properties(x87pc PROPERTIES ENVIRONMENT "BOX64_DYNAREC_X87DOUBLE=2")
|
||||
|
||||
else()
|
||||
|
||||
@@ -1733,14 +1793,11 @@ if(BOX32)
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref09.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
if(NOT CI)
|
||||
add_test(NAME cppThreads_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
add_test(NAME cppThreads_32bits_nocosim COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test10 -D TEST_OUTPUT=tmpfile32_10.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref10.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
set_tests_properties(cppThreads_32bits PROPERTIES ENVIRONMENT "BOX64_LD_LIBRARY_PATH=${CMAKE_SOURCE_DIR}/x86lib")
|
||||
endif()
|
||||
set_tests_properties(cppThreads_32bits_nocosim PROPERTIES ENVIRONMENT "BOX64_LD_LIBRARY_PATH=${CMAKE_SOURCE_DIR}/x86lib")
|
||||
|
||||
add_test(NAME tlsData_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test11 -D TEST_OUTPUT=tmpfile32_11.txt
|
||||
@@ -1812,13 +1869,13 @@ if(BOX32)
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake)
|
||||
endforeach()
|
||||
|
||||
#add_test(NAME sse_optimized_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
# -D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test17_o2 -D TEST_OUTPUT=tmpfile32_17_o2.txt
|
||||
#add_test(NAME sse_optimized_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
# -D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test17_o2 -D TEST_OUTPUT=tmpfile32_17_o2.txt
|
||||
# -D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref17_o2.txt
|
||||
# -P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
#set_tests_properties(sse_optimized_32bits PROPERTIES ENVIRONMENT "BOX64_DYNAREC_FASTNAN=0;BOX64_DYNAREC_FASTROUND=0")
|
||||
|
||||
#set_tests_properties(sse_optimized_32bits PROPERTIES ENVIRONMENT "BOX64_DYNAREC_FASTNAN=0;BOX64_DYNAREC_FASTROUND=0")
|
||||
|
||||
add_test(bswap_32bits ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test23 -D TEST_OUTPUT=tmpfile32_23.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref23.txt
|
||||
|
||||
@@ -6,10 +6,20 @@ https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/gmp-6.2.0-13.
|
||||
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
|
||||
@@ -20,19 +30,37 @@ https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libogg-1.3
|
||||
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://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
|
||||
|
@@ -26,8 +26,7 @@ extract_pkg_auto() {
|
||||
echo "XBPS (Void Linux) package detected."
|
||||
tar --extract --file "$(basename "${1}")"
|
||||
else
|
||||
echo "Unknown package."
|
||||
echo "Unsupported package type."
|
||||
echo "Unsupported package type detected."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
@@ -63,6 +62,9 @@ cp --archive "${dir_tmp_local}"/usr/lib/x86_64-linux-gnu/*.so* "${dir_tmp_local}
|
||||
# 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"
|
||||
|
||||
@@ -84,6 +86,7 @@ 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" .
|
||||
|
||||
Vendored
+12
@@ -1,3 +1,15 @@
|
||||
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
|
||||
|
||||
=> WowBox64 can be built directly from Box64 repo, and can be found in the CI artifacts also
|
||||
=> it also supports a subset of BOX64_XXXX settings, which can be set from command line or via a setting file ".box64rc" in the Wine prefix home
|
||||
=> Volatile Metadata, when present, allows only applying strong memory ordering when needed, as marked by the compiler, giving overall better performances
|
||||
=> The precision control bit of x87 is now handled, allowing some older games to run correctly
|
||||
=> More work has been done in the handling of precise NaN and Round handling in SSE & AVX opcodes
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 6 Jun 2025 10:30:33 -0100
|
||||
|
||||
box64 (0.3.4) unstable; urgency=low
|
||||
|
||||
* This version is Faster and more compatible
|
||||
|
||||
@@ -13,6 +13,10 @@ Install required dependencies for the bundle script.
|
||||
sudo apt-get update
|
||||
sudo apt-get install coreutils curl binutils rpm2cpio tar zstd
|
||||
```
|
||||
- Fedora
|
||||
```
|
||||
sudo dnf install coreutils curl binutils tar zstd
|
||||
```
|
||||
|
||||
Run `box64-bundle-x86-libs.sh`. This will create two archives:
|
||||
- `box64-bundle-x86-libs.tar.gz` = All of the extracted library files in the directory structure of `usr/lib/box64-i386-linux-gnu` and `usr/lib/box64-x86_64-linux-gnu`.
|
||||
@@ -41,13 +45,15 @@ 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.
|
||||
|
||||
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:
|
||||
- DEB
|
||||
- `apt-file <LIBRARY_FILE>`
|
||||
- EOPKG
|
||||
- Does not support file search. Use pkgs.org instead.
|
||||
- RPM
|
||||
- `dnf provides <LIBRARY_FILE>`
|
||||
- `dnf provides "*/<LIBRARY_FILE>*"`
|
||||
- XBPS
|
||||
- `xbps-query --repository --ownedby <LIBRARY_FILE>`
|
||||
|
||||
@@ -58,9 +64,10 @@ Once the package name is found, find the exact URL for downloading it.
|
||||
- https://cdn.getsol.us/repo/shannon/
|
||||
- RPM = Navigate to the "`<MAJOR>.<MINOR>`" version directory first. Then explore "AppStream" and "BaseOS". Use the "x86_64.rpm" and "i686.rpm" packages.
|
||||
- https://repo.almalinux.org/almalinux/
|
||||
- Enterprise Linux (EL) distributions, such as AlamaLinux, sometimes are missing 32-bit packages. Use the Fedora 34 [update](https://archives.fedoraproject.org/pub/archive/fedora/linux/updates/34/Everything/x86_64/Packages/) and [release](https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/34/Everything/x86_64/os/Packages/) archives for compatible packages with EL 9.
|
||||
- XBPS = There are too many files in the repository to display on a web browser. Use pkgs.org instead to find the exact URL for downloading it.
|
||||
- https://repo-default.voidlinux.org/current/
|
||||
|
||||
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 Arch Linux, 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. 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.
|
||||
@@ -1,3 +1,49 @@
|
||||
v0.3.6
|
||||
======
|
||||
|
||||
Highlights:
|
||||
|
||||
* 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
|
||||
|
||||
=> WowBox64 can be built directly from Box64 repo, and can be found in the CI artifacts also
|
||||
=> it also supports a subset of BOX64_XXXX settings, which can be set from command line or via a setting file ".box64rc" in the Wine prefix home
|
||||
=> Volatile Metadata, when present, allows only applying strong memory ordering when needed, as marked by the compiler, giving overall better performances
|
||||
=> The precision control bit of x87 is now handled, allowing some older games to run correctly
|
||||
=> More work has been done in the handling of precise NaN and Round handling in SSE & AVX opcodes
|
||||
|
||||
Version summary:
|
||||
|
||||
* Added/fixed some Syscalls, helping Go programs
|
||||
* Wrapper: more functions added, and some fixes too. Vulkan is 1.4 now, among other things
|
||||
* Wrapper: Added a few more wrapped libs (like some avcodec and friends)
|
||||
* Improve internal memory allocator (with a dedicated allocator for small memory allocations), and fixed some issues around it
|
||||
* Improve internal mmaped file tracking
|
||||
* Box32: Some small refactoring around memory management and internal memory allocations
|
||||
* Box32: More functions wrapped
|
||||
* Box32: More libraries wrapped
|
||||
* ARM64: Added support for Atomic extension in many internal functions (not related to Dynarec).
|
||||
* ARM64: Added support for CRC2 extension for internal CRC functions
|
||||
* Interp: A few fixes to some opcodes, and better NAN handling on some selected SSE/AVX opcodes
|
||||
* Interp: Added a few opcodes with exotic prefixes
|
||||
* Dynarec: Introcude BOX64_DYNAREC_ROUND=2 to handle x87 precision control bit (ARM64 and RV64, LA64 still doesn't handle x87 yet)
|
||||
* Dynarec: Some small optimizations on Strongmem emulation, making it more efficient
|
||||
* Dynarec: Some speed optimizations on code that do SMC and waiting slot
|
||||
* Dynarec: Added CALLRET=2 to improve call/ret optimization compatibility with SMC code
|
||||
* Dynarec: ARM64: Various optimizations and fixes on some opcodes, especially AVX ones
|
||||
* Dynarec: ARM64: Added missing FASTNAN=0 handling on some SSE/AVX opcodes
|
||||
* Dynarec: ARM64: Added some exotic prefixed opcodes
|
||||
* Dynarec: ARM64: Avoid purging XMM/YMM register on intra-block loop if possible
|
||||
* Dynarec: RV64: Many fixes and improvments around x87 emulation
|
||||
* Dynarec: RV64: Added some more missing opcodes, especially some LOCK prefixed ones and many MMX ones
|
||||
* Dynarec: RV64: Various fixes on some existing opcodes
|
||||
* Dynarec: RV64: Improved nativeflags handling, allowing for more cases to use it
|
||||
* Dynarec: LA64: Added some more opcodes and MMX handling
|
||||
* Dynarec: LA64: Various fixes to some existing opcodes
|
||||
* Android: Improved signal handling, structure alignment, and transformation
|
||||
* WowBox64: Created the dll, with RcFile, Env. Var. handling and log printout (both ARM64 Dynarec and Interpreter available)
|
||||
* Cosim: Various fixes and improvements to limit false negatives and improve readability of logs
|
||||
* RcFile: A few fixes for some values that would be ignored
|
||||
|
||||
v0.3.4
|
||||
======
|
||||
* This version is Faster and more compatible:
|
||||
|
||||
+36
-3
@@ -25,6 +25,25 @@ sudo systemctl restart systemd-binfmt
|
||||
- You can use `make -j1`, `make -j2` with less jobs to prevent running out of memory
|
||||
- You can also add `-DBAD_SIGNAL=ON` to the cmake command if you are on a Linux Kernel mixed with Android, like on RK3588.
|
||||
|
||||
### Note about Box32
|
||||
|
||||
If you want to build Box64 with the Box32 option, you will need to add `-DBOX32=ON` to the cmake command. That will enable 32bits process to be run with Box64.
|
||||
If you also want binfmt integration on 32bits binaries, you also need to add `-DBOX32_BINFMT=ON` to the cmake command.
|
||||
|
||||
### Note about WowBox64
|
||||
|
||||
A highly experimantal subproject named WowBox64 has been added as a build option, add `-DWOW64=ON` to the cmake command to enable it.
|
||||
It will build alongside the regular Box64, and produce a `wowbox64.dll` file in `build/wowbox64-prefix/src/wowbox64-build/` directory.
|
||||
|
||||
### Note about binfmt_misc on Android
|
||||
|
||||
[binfmt_misc](https://en.wikipedia.org/wiki/Binfmt_misc) is a capability of the Linux kernel which allows arbitrary executable file formats to be recognized and passed to certain user space applications such as Box64 usually used with systemd but systems like Android can't run/use systemd so you will need to register Box64 manually, this will also work inside a CHRoot.
|
||||
```
|
||||
sudo mount -t binfmt_misc none /proc/sys/fs/binfmt_misc
|
||||
sudo echo ':box64:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x3e\x00:\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/box64:' | sudo tee /proc/sys/fs/binfmt_misc/register
|
||||
```
|
||||
|
||||
|
||||
#### Example of generic ARM64 build for linux platforms
|
||||
|
||||
```
|
||||
@@ -35,6 +54,18 @@ make -j4
|
||||
sudo make install
|
||||
sudo systemctl restart systemd-binfmt
|
||||
```
|
||||
|
||||
#### Example of generic ARM64 build for linux platforms with full box32 integration
|
||||
|
||||
```
|
||||
git clone https://github.com/ptitSeb/box64
|
||||
cd box64
|
||||
mkdir build; cd build; cmake .. -D ARM_DYNAREC=ON -D CMAKE_BUILD_TYPE=RelWithDebInfo -D BOX32=ON -D BOX32_BINFMT=ON
|
||||
make -j4
|
||||
sudo make install
|
||||
sudo systemctl restart systemd-binfmt
|
||||
```
|
||||
|
||||
----
|
||||
|
||||
#### for RK3399
|
||||
@@ -231,9 +262,11 @@ Add `-DCMAKE_BUILD_TYPE=RelWithDebInfo` option for an optimized build with debug
|
||||
|
||||
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.
|
||||
|
||||
#### Build ARM DynaRec
|
||||
#### Build DynaRec
|
||||
|
||||
Add `-DARM_DYNAREC=1` option to enable DynaRec on ARM machines.
|
||||
Add `-D ARM_DYNAREC=ON` option to enable DynaRec on ARM machines.
|
||||
Add `-D RV64_DYNAREC=ON` option to enable DynaRec on RV64 machines.
|
||||
Add `-D LARCH64_DYNAREC=ON` option to enable DynaRec on LARCH64 machines.
|
||||
|
||||
#### Save memory at run time
|
||||
|
||||
@@ -330,4 +363,4 @@ After successfully cross-compiling, copy the box64 executable to your RISC-V dev
|
||||
|
||||
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)
|
||||
- `/usr/lib/box64-i386-linux-gnu/` (for i386)
|
||||
+76
-33
@@ -4,9 +4,12 @@ Usage
|
||||
|
||||
There are many environment variables to control Box64's behaviour, which will be listed below by category.
|
||||
|
||||
There are 2 types of Box64 builds: the Wine WOW64 build (WowBox64) and the regular Linux build. Beware only some of the environment variables are available in WowBox64.
|
||||
|
||||
### Configuration files
|
||||
|
||||
In addition to environment variables, by default, Box64 also looks for 2 places for rcfile: the system-wide `/etc/box64.box64rc` and user-specific `~/.box64rc`.
|
||||
In addition to environment variables, if you're using the regular Linux build, Box64 also looks for 2 places for rcfile by default: the system-wide `/etc/box64.box64rc` and user-specific `~/.box64rc`.
|
||||
While in WowBox64, the configuration file is checked at `%USERPROFILE%/.box64rc` only.
|
||||
Settings priority follows this order (from highest to lowest): `~/.box64rc` > `/etc/box64.box64rc` > environment variables.
|
||||
|
||||
Example configuration:
|
||||
@@ -21,7 +24,7 @@ BOX64_DYNAREC_CALLRET=1
|
||||
|
||||
This configuration will apply the specified settings application-wide to any executable named `factorio`.
|
||||
|
||||
### Advanced usage
|
||||
### Advanced usage for Linux build
|
||||
|
||||
1. **Wildcard Matching**
|
||||
|
||||
@@ -171,6 +174,14 @@ Add --no-sandbox argument to the guest program.
|
||||
|
||||
## Compatibility
|
||||
|
||||
### BOX64_AVX
|
||||
|
||||
Expose AVX extension to CPUID and cpuinfo file. Default value is 2 on Arm64 because it's fully implemented in DynaRec, 0 otherwise. Availble in WowBox64.
|
||||
|
||||
* 0: Do not expose AVX capabilities.
|
||||
* 1: Expose AVX, BMI1, F16C and VAES extensions to CPUID and cpuinfo file.
|
||||
* 2: All in 1, plus AVX2, BMI2, FMA, ADX,VPCLMULQDQ and RDRAND extensions.
|
||||
|
||||
### BOX64_BASH
|
||||
|
||||
Path to the bash executable.
|
||||
@@ -179,7 +190,7 @@ Path to the bash executable.
|
||||
|
||||
### BOX64_CPUTYPE
|
||||
|
||||
Specify the CPU type to emulate.
|
||||
Specify the CPU type to emulate. Availble in WowBox64.
|
||||
|
||||
* 0: Emulate a Intel CPU Model. [Default]
|
||||
* 1: Emulate a AMD CPU Model.
|
||||
@@ -200,7 +211,7 @@ Detect MonoBleedingEdge and apply conservative settings.
|
||||
|
||||
### BOX64_DYNAREC_DIV0
|
||||
|
||||
Enable or disable the generation of division-by-zero exception.
|
||||
Enable or disable the generation of division-by-zero exception. Availble in WowBox64.
|
||||
|
||||
* 0: Do not generate thr division-by-zero exception. [Default]
|
||||
* 1: Generate the division-by-zero exception.
|
||||
@@ -214,10 +225,11 @@ Enable or disable libtbb detection.
|
||||
|
||||
### BOX64_DYNAREC_X87DOUBLE
|
||||
|
||||
Force the use of float/double for x87 emulation.
|
||||
Force the use of float/double for x87 emulation. Availble in WowBox64.
|
||||
|
||||
* 0: Try to use float when possible for x87 emulation. [Default]
|
||||
* 1: Only use Double for x87 emulation.
|
||||
* 2: Check Precision Control low precision on x87 emulation.
|
||||
|
||||
### BOX64_EXIT
|
||||
|
||||
@@ -264,7 +276,7 @@ Behaviour when hooking malloc operators.
|
||||
|
||||
### BOX64_MAXCPU
|
||||
|
||||
Maximum CPU cores exposed.
|
||||
Maximum CPU cores exposed. Availble in WowBox64.
|
||||
|
||||
* 0: Use the actual number of CPU cores. [Default]
|
||||
* XXXX: Use XXXX CPU cores.
|
||||
@@ -311,14 +323,14 @@ Expose SHAEXT (a.k.a. SHA_NI) capabilities.
|
||||
|
||||
### BOX64_SSE_FLUSHTO0
|
||||
|
||||
Behaviour of SSE Flush to 0 flags.
|
||||
Behaviour of SSE Flush to 0 flags. Availble in WowBox64.
|
||||
|
||||
* 0: Just track the flag. [Default]
|
||||
* 1: Apply SSE Flush to 0 flag directly.
|
||||
|
||||
### BOX64_SSE42
|
||||
|
||||
Expose SSE4.2 capabilities.
|
||||
Expose SSE4.2 capabilities. Availble in WowBox64.
|
||||
|
||||
* 0: Do not expose SSE4.2 capabilities.
|
||||
* 1: Expose SSE4.2 capabilities. [Default]
|
||||
@@ -360,7 +372,7 @@ Call XInitThreads when loading X11. This is mostly for old Loki games with the L
|
||||
|
||||
### BOX64_X87_NO80BITS
|
||||
|
||||
Behavoiur of x87 80bits long double.
|
||||
Behavoiur of x87 80bits long double. Availble in WowBox64.
|
||||
|
||||
* 0: Try to handle 80bits long double as precise as possible. [Default]
|
||||
* 1: Use 64bits double for x87.
|
||||
@@ -376,19 +388,25 @@ Enable or disable the logging of dlsym errors.
|
||||
|
||||
### BOX64_DUMP
|
||||
|
||||
Dump elfloader debug information.
|
||||
Dump elfloader debug information. Availble in WowBox64.
|
||||
|
||||
* 0: Do not dump elfloader debug information. [Default]
|
||||
* 1: Dump elfloader debug information.
|
||||
|
||||
### BOX64_DYNAREC_DUMP
|
||||
|
||||
Enable DynaRec dump.
|
||||
Enable DynaRec dump. Availble in WowBox64.
|
||||
|
||||
* 0: Do not dump DynaRec blocks. [Default]
|
||||
* 1: Dump DynaRec blocks.
|
||||
* 2: Dump DynaRec blocks with some colors.
|
||||
|
||||
### BOX64_DYNAREC_DUMP_RANGE
|
||||
|
||||
Dump DynaRec blocks in the specified range. Availble in WowBox64.
|
||||
|
||||
* 0xXXXXXXXX-0xYYYYYYYY: Define the range where dynablock gets dumped (inclusive-exclusive).
|
||||
|
||||
### BOX64_DYNAREC_GDBJIT
|
||||
|
||||
The GDBJIT debugging support, only available on build with `-DGDBJIT=ON`, enable it with gdb command: jit-reader-load /usr/local/lib/libbox64gdbjitreader.so.
|
||||
@@ -396,10 +414,12 @@ The GDBJIT debugging support, only available on build with `-DGDBJIT=ON`, enable
|
||||
* 0: Dynarec will not generate GDBJIT debuginfo. [Default]
|
||||
* 1: Dynarec will generate GDBJIT debuginfo.
|
||||
* 2: Dynarec will generate detailed GDBJIT debuginfo with internal state.
|
||||
* 3: Dynarec will register detailed GDBJIT debuginfo only for dynablocks that the guest program trap into, greatly improving performance.
|
||||
* 0xXXXXXXX-0xYYYYYYY: Define the range where Dynarec will generate detailed GDBJIT debuginfo with internal state.
|
||||
|
||||
### BOX64_DYNAREC_LOG
|
||||
|
||||
Disable or enable DynaRec logs.
|
||||
Disable or enable DynaRec logs. Availble in WowBox64.
|
||||
|
||||
* 0: Disable DynaRec logs. [Default]
|
||||
* 1: Enable minimal DynaRec logs.
|
||||
@@ -408,7 +428,7 @@ Disable or enable DynaRec logs.
|
||||
|
||||
### BOX64_DYNAREC_MISSING
|
||||
|
||||
Print missing opcodes.
|
||||
Print missing opcodes. Availble in WowBox64.
|
||||
|
||||
* 0: Do not print the missing opcode. [Default]
|
||||
* 1: Print missing opcodes.
|
||||
@@ -423,7 +443,7 @@ Generate map file for Linux perf tool.
|
||||
|
||||
### BOX64_DYNAREC_TEST
|
||||
|
||||
Enable DynaRec execution comparison with the interpreter, very slow, only for testing.
|
||||
Enable DynaRec execution comparison with the interpreter, very slow, only for testing. Availble in WowBox64.
|
||||
|
||||
* 0: No comparison. [Default]
|
||||
* 1: Each opcode runs on interpreter and on Dynarec, regs and memory are compared and printed when they differ.
|
||||
@@ -453,18 +473,18 @@ Set the address where the program is loaded, only active for PIE guest programs.
|
||||
|
||||
### BOX64_LOG
|
||||
|
||||
Enable or disable Box64 logs.
|
||||
Enable or disable Box64 logs, default value is 0 if stdout is not terminal, 1 otherwise. Availble in WowBox64.
|
||||
|
||||
* 0: Disable Box64 logs. [Default]
|
||||
* 0: Disable Box64 logs.
|
||||
* 1: Enable minimal Box64 logs.
|
||||
* 2: Enable debug level Box64 logs.
|
||||
* 3: Enable verbose level Box64 logs.
|
||||
|
||||
### BOX64_NOBANNER
|
||||
|
||||
Disable the Box64 banner.
|
||||
Disable the Box64 banner. Availble in WowBox64.
|
||||
|
||||
* 0: Show the Box64 banner. [Default]
|
||||
* 0: Show the Box64 banner.
|
||||
* 1: Do not show the Box64 banner.
|
||||
|
||||
### BOX64_NOSIGSEGV
|
||||
@@ -487,7 +507,7 @@ Show last few wrapped function call when a signal is caught.
|
||||
|
||||
* 0: Does nothing. [Default]
|
||||
* 1: Show last 16 wrapped function call when a signal is caught.
|
||||
* XXX: Show last XXX wrapped function call when a signal is caught.
|
||||
* XXXX: Show last XXXX wrapped function call when a signal is caught.
|
||||
|
||||
### BOX64_SHOWBT
|
||||
|
||||
@@ -558,16 +578,23 @@ Only available on box64 build with trace. Adds trace of all instructions execute
|
||||
|
||||
## 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).
|
||||
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.
|
||||
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.
|
||||
@@ -576,14 +603,15 @@ Enable building bigger DynaRec code blocks for better performance.
|
||||
|
||||
### BOX64_DYNAREC_CALLRET
|
||||
|
||||
Optimize CALL/RET opcodes.
|
||||
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.
|
||||
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]
|
||||
@@ -594,17 +622,18 @@ 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.
|
||||
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.
|
||||
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]
|
||||
@@ -612,7 +641,7 @@ Enable or disable fast rounding.
|
||||
|
||||
### BOX64_DYNAREC_FORWARD
|
||||
|
||||
Define max allowed forward value when building block.
|
||||
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]
|
||||
@@ -620,14 +649,14 @@ Define max allowed forward value when building block.
|
||||
|
||||
### BOX64_DYNAREC_NATIVEFLAGS
|
||||
|
||||
Enable or disable the use of native flags.
|
||||
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.
|
||||
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.
|
||||
@@ -636,7 +665,7 @@ Enable x86 PAUSE emulation, may help the performance of spinlocks.
|
||||
|
||||
### BOX64_DYNAREC_SAFEFLAGS
|
||||
|
||||
Behaviour of flags emulation on CALL/RET opcodes.
|
||||
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]
|
||||
@@ -644,31 +673,45 @@ Behaviour of flags emulation on CALL/RET opcodes.
|
||||
|
||||
### BOX64_DYNAREC_STRONGMEM
|
||||
|
||||
Enable the emulation of x86 strong memory model.
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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).
|
||||
|
||||
|
||||
+81
-36
@@ -73,6 +73,15 @@ Arguments to pass to the guest program, only valid if there is no existing argum
|
||||
* XXXX YYYY ZZZZ : Pass arguments XXXX, YYYY and ZZZZ to the guest program.
|
||||
|
||||
|
||||
=item B<BOX64_AVX> =I<0|1|2>
|
||||
|
||||
Expose AVX extension to CPUID and cpuinfo file. Default value is 2 on Arm64 because it's fully implemented in DynaRec, 0 otherwise. Availble in WowBox64.
|
||||
|
||||
* 0 : Do not expose AVX capabilities.
|
||||
* 1 : Expose AVX, BMI1, F16C and VAES extensions to CPUID and cpuinfo file.
|
||||
* 2 : All in 1, plus AVX2, BMI2, FMA, ADX,VPCLMULQDQ and RDRAND extensions.
|
||||
|
||||
|
||||
=item B<BOX64_BASH> =I<XXXX>
|
||||
|
||||
Path to the bash executable.
|
||||
@@ -98,7 +107,7 @@ Add -cef-disable-gpu-compositor argument to the guest program.
|
||||
|
||||
=item B<BOX64_CPUTYPE> =I<0|1>
|
||||
|
||||
Specify the CPU type to emulate.
|
||||
Specify the CPU type to emulate. Availble in WowBox64.
|
||||
|
||||
* 0 : Emulate a Intel CPU Model. [Default]
|
||||
* 1 : Emulate a AMD CPU Model.
|
||||
@@ -122,15 +131,23 @@ Enable or disable the logging of dlsym errors.
|
||||
|
||||
=item B<BOX64_DUMP> =I<0|1>
|
||||
|
||||
Dump elfloader debug information.
|
||||
Dump elfloader debug information. Availble in WowBox64.
|
||||
|
||||
* 0 : Do not dump elfloader debug information. [Default]
|
||||
* 1 : Dump elfloader debug information.
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC> =I<0|1>
|
||||
|
||||
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.
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_ALIGNED_ATOMICS> =I<0|1>
|
||||
|
||||
Generate aligned atomics only (only available on Arm64 for now).
|
||||
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.
|
||||
@@ -138,7 +155,7 @@ Generate aligned atomics only (only available on Arm64 for now).
|
||||
|
||||
=item B<BOX64_DYNAREC_BIGBLOCK> =I<0|1|2|3>
|
||||
|
||||
Enable building bigger DynaRec code blocks for better performance.
|
||||
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.
|
||||
@@ -154,33 +171,35 @@ Detect MonoBleedingEdge and apply conservative settings.
|
||||
* 1 : Detect MonoBleedingEdge and apply BOX64_DYNAREC_BIGBLOCK=0 BOX64_DYNAREC_STRONGMEM=1 when detected. [Default]
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_CALLRET> =I<0|1>
|
||||
=item B<BOX64_DYNAREC_CALLRET> =I<0|1|2>
|
||||
|
||||
Optimize CALL/RET opcodes.
|
||||
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.
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_DF> =I<0|1>
|
||||
|
||||
Enable or disable the use of deferred flags.
|
||||
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]
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_DIRTY> =I<0|1>
|
||||
=item B<BOX64_DYNAREC_DIRTY> =I<0|1|2>
|
||||
|
||||
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).
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_DIV0> =I<0|1>
|
||||
|
||||
Enable or disable the generation of division-by-zero exception.
|
||||
Enable or disable the generation of division-by-zero exception. Availble in WowBox64.
|
||||
|
||||
* 0 : Do not generate thr division-by-zero exception. [Default]
|
||||
* 1 : Generate the division-by-zero exception.
|
||||
@@ -188,16 +207,23 @@ Enable or disable the generation of division-by-zero exception.
|
||||
|
||||
=item B<BOX64_DYNAREC_DUMP> =I<0|1|2>
|
||||
|
||||
Enable DynaRec dump.
|
||||
Enable DynaRec dump. Availble in WowBox64.
|
||||
|
||||
* 0 : Do not dump DynaRec blocks. [Default]
|
||||
* 1 : Dump DynaRec blocks.
|
||||
* 2 : Dump DynaRec blocks with some colors.
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_DUMP_RANGE> =I<0xXXXXXXXX-0xYYYYYYYY>
|
||||
|
||||
Dump DynaRec blocks in the specified range. Availble in WowBox64.
|
||||
|
||||
* 0xXXXXXXXX-0xYYYYYYYY : Define the range where dynablock gets dumped (inclusive-exclusive).
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_FASTNAN> =I<0|1>
|
||||
|
||||
Enable or disable fast NaN handling.
|
||||
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]
|
||||
@@ -205,7 +231,7 @@ Enable or disable fast NaN handling.
|
||||
|
||||
=item B<BOX64_DYNAREC_FASTROUND> =I<0|1|2>
|
||||
|
||||
Enable or disable fast rounding.
|
||||
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]
|
||||
@@ -214,25 +240,27 @@ Enable or disable fast rounding.
|
||||
|
||||
=item B<BOX64_DYNAREC_FORWARD> =I<0|128|XXXX>
|
||||
|
||||
Define max allowed forward value when building block.
|
||||
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.
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_GDBJIT> =I<0|1|2>
|
||||
=item B<BOX64_DYNAREC_GDBJIT> =I<0|1|2|3|0xXXXXXXX-0xYYYYYYY>
|
||||
|
||||
The GDBJIT debugging support, only available on build with `-DGDBJIT=ON`, enable it with gdb command: jit-reader-load /usr/local/lib/libbox64gdbjitreader.so.
|
||||
|
||||
* 0 : Dynarec will not generate GDBJIT debuginfo. [Default]
|
||||
* 1 : Dynarec will generate GDBJIT debuginfo.
|
||||
* 2 : Dynarec will generate detailed GDBJIT debuginfo with internal state.
|
||||
* 3 : Dynarec will register detailed GDBJIT debuginfo only for dynablocks that the guest program trap into, greatly improving performance.
|
||||
* 0xXXXXXXX-0xYYYYYYY : Define the range where Dynarec will generate detailed GDBJIT debuginfo with internal state.
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_LOG> =I<0|1|2|3>
|
||||
|
||||
Disable or enable DynaRec logs.
|
||||
Disable or enable DynaRec logs. Availble in WowBox64.
|
||||
|
||||
* 0 : Disable DynaRec logs. [Default]
|
||||
* 1 : Enable minimal DynaRec logs.
|
||||
@@ -242,7 +270,7 @@ Disable or enable DynaRec logs.
|
||||
|
||||
=item B<BOX64_DYNAREC_MISSING> =I<0|1|2>
|
||||
|
||||
Print missing opcodes.
|
||||
Print missing opcodes. Availble in WowBox64.
|
||||
|
||||
* 0 : Do not print the missing opcode. [Default]
|
||||
* 1 : Print missing opcodes.
|
||||
@@ -251,7 +279,7 @@ Print missing opcodes.
|
||||
|
||||
=item B<BOX64_DYNAREC_NATIVEFLAGS> =I<0|1>
|
||||
|
||||
Enable or disable the use of native flags.
|
||||
Enable or disable the use of native flags. Availble in WowBox64.
|
||||
|
||||
* 0 : Do not use native flags.
|
||||
* 1 : Use native flags when possible. [Default]
|
||||
@@ -259,7 +287,7 @@ Enable or disable the use of native flags.
|
||||
|
||||
=item B<BOX64_DYNAREC_PAUSE> =I<0|1|2|3>
|
||||
|
||||
Enable x86 PAUSE emulation, may help the performance of spinlocks.
|
||||
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.
|
||||
@@ -277,7 +305,7 @@ Generate map file for Linux perf tool.
|
||||
|
||||
=item B<BOX64_DYNAREC_SAFEFLAGS> =I<0|1|2>
|
||||
|
||||
Behaviour of flags emulation on CALL/RET opcodes.
|
||||
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]
|
||||
@@ -286,7 +314,7 @@ Behaviour of flags emulation on CALL/RET opcodes.
|
||||
|
||||
=item B<BOX64_DYNAREC_STRONGMEM> =I<0|1|2|3>
|
||||
|
||||
Enable the emulation of x86 strong memory model.
|
||||
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.
|
||||
@@ -304,7 +332,7 @@ Enable or disable libtbb detection.
|
||||
|
||||
=item B<BOX64_DYNAREC_TEST> =I<0|1|0xXXXXXXXX-0xYYYYYYYY>
|
||||
|
||||
Enable DynaRec execution comparison with the interpreter, very slow, only for testing.
|
||||
Enable DynaRec execution comparison with the interpreter, very slow, only for testing. Availble in WowBox64.
|
||||
|
||||
* 0 : No comparison. [Default]
|
||||
* 1 : Each opcode runs on interpreter and on Dynarec, regs and memory are compared and printed when they differ.
|
||||
@@ -319,9 +347,17 @@ Enable or disable DynaRec trace.
|
||||
* 1 : Trace DynaRec blocks, will slow down the program a lot and generates huge logs.
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_VOLATILE_METADATA> =I<0|1>
|
||||
|
||||
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]
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_WAIT> =I<0|1>
|
||||
|
||||
Wait or not for the building of a DynaRec code block to be ready.
|
||||
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]
|
||||
@@ -329,19 +365,20 @@ Wait or not for the building of a DynaRec code block to be ready.
|
||||
|
||||
=item B<BOX64_DYNAREC_WEAKBARRIER> =I<0|1|2>
|
||||
|
||||
Tweak the memory barriers to reduce the performance impact by strong memory emualtion.
|
||||
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.
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_X87DOUBLE> =I<0|1>
|
||||
=item B<BOX64_DYNAREC_X87DOUBLE> =I<0|1|2>
|
||||
|
||||
Force the use of float/double for x87 emulation.
|
||||
Force the use of float/double for x87 emulation. Availble in WowBox64.
|
||||
|
||||
* 0 : Try to use float when possible for x87 emulation. [Default]
|
||||
* 1 : Only use Double for x87 emulation.
|
||||
* 2 : Check Precision Control low precision on x87 emulation.
|
||||
|
||||
|
||||
=item B<BOX64_EMULATED_LIBS> =I<XXXX|XXXX:YYYY:ZZZZ>
|
||||
@@ -464,9 +501,9 @@ Set the address where the program is loaded, only active for PIE guest programs.
|
||||
|
||||
=item B<BOX64_LOG> =I<0|1|2|3>
|
||||
|
||||
Enable or disable Box64 logs.
|
||||
Enable or disable Box64 logs, default value is 0 if stdout is not terminal, 1 otherwise. Availble in WowBox64.
|
||||
|
||||
* 0 : Disable Box64 logs. [Default]
|
||||
* 0 : Disable Box64 logs.
|
||||
* 1 : Enable minimal Box64 logs.
|
||||
* 2 : Enable debug level Box64 logs.
|
||||
* 3 : Enable verbose level Box64 logs.
|
||||
@@ -483,23 +520,31 @@ Behaviour when hooking malloc operators.
|
||||
|
||||
=item B<BOX64_MAXCPU> =I<0|XXXX>
|
||||
|
||||
Maximum CPU cores exposed.
|
||||
Maximum CPU cores exposed. Availble in WowBox64.
|
||||
|
||||
* 0 : Use the actual number of CPU cores. [Default]
|
||||
* XXXX : Use XXXX CPU cores.
|
||||
|
||||
|
||||
=item B<BOX64_MMAP32> =I<0|1>
|
||||
|
||||
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]
|
||||
|
||||
|
||||
=item B<BOX64_NOBANNER> =I<0|1>
|
||||
|
||||
Disable the Box64 banner.
|
||||
Disable the Box64 banner. Availble in WowBox64.
|
||||
|
||||
* 0 : Show the Box64 banner. [Default]
|
||||
* 0 : Show the Box64 banner.
|
||||
* 1 : Do not show the Box64 banner.
|
||||
|
||||
|
||||
=item B<BOX64_NODYNAREC> =I<0xXXXXXXXX-0xYYYYYYYY>
|
||||
|
||||
Forbid dynablock creation in the address range specified, helpful for debugging behaviour difference between Dynarec and Interpreter.
|
||||
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).
|
||||
|
||||
@@ -606,13 +651,13 @@ Reserve high memory area for the program, always enabled on Box32.
|
||||
* 1 : Reserve high memory area for the program.
|
||||
|
||||
|
||||
=item B<BOX64_ROLLING_LOG> =I<0|1|XXX>
|
||||
=item B<BOX64_ROLLING_LOG> =I<0|1|XXXX>
|
||||
|
||||
Show last few wrapped function call when a signal is caught.
|
||||
|
||||
* 0 : Does nothing. [Default]
|
||||
* 1 : Show last 16 wrapped function call when a signal is caught.
|
||||
* XXX : Show last XXX wrapped function call when a signal is caught.
|
||||
* XXXX : Show last XXXX wrapped function call when a signal is caught.
|
||||
|
||||
|
||||
=item B<BOX64_SDL2_JGUID> =I<0|1>
|
||||
@@ -649,7 +694,7 @@ Always show SIGSEGV signal detailes.
|
||||
|
||||
=item B<BOX64_SSE_FLUSHTO0> =I<0|1>
|
||||
|
||||
Behaviour of SSE Flush to 0 flags.
|
||||
Behaviour of SSE Flush to 0 flags. Availble in WowBox64.
|
||||
|
||||
* 0 : Just track the flag. [Default]
|
||||
* 1 : Apply SSE Flush to 0 flag directly.
|
||||
@@ -657,7 +702,7 @@ Behaviour of SSE Flush to 0 flags.
|
||||
|
||||
=item B<BOX64_SSE42> =I<0|1>
|
||||
|
||||
Expose SSE4.2 capabilities.
|
||||
Expose SSE4.2 capabilities. Availble in WowBox64.
|
||||
|
||||
* 0 : Do not expose SSE4.2 capabilities.
|
||||
* 1 : Expose SSE4.2 capabilities. [Default]
|
||||
@@ -773,7 +818,7 @@ Call XInitThreads when loading X11. This is mostly for old Loki games with the L
|
||||
|
||||
=item B<BOX64_X87_NO80BITS> =I<0|1>
|
||||
|
||||
Behavoiur of x87 80bits long double.
|
||||
Behavoiur of x87 80bits long double. Availble in WowBox64.
|
||||
|
||||
* 0 : Try to handle 80bits long double as precise as possible. [Default]
|
||||
* 1 : Use 64bits double for x87.
|
||||
|
||||
+200
-6
@@ -2,6 +2,7 @@
|
||||
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
from collections import defaultdict
|
||||
|
||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
@@ -17,9 +18,12 @@ Usage
|
||||
|
||||
There are many environment variables to control Box64's behaviour, which will be listed below by category.
|
||||
|
||||
There are 2 types of Box64 builds: the Wine WOW64 build (WowBox64) and the regular Linux build. Beware only some of the environment variables are available in WowBox64.
|
||||
|
||||
### Configuration files
|
||||
|
||||
In addition to environment variables, by default, Box64 also looks for 2 places for rcfile: the system-wide `/etc/box64.box64rc` and user-specific `~/.box64rc`.
|
||||
In addition to environment variables, if you're using the regular Linux build, Box64 also looks for 2 places for rcfile by default: the system-wide `/etc/box64.box64rc` and user-specific `~/.box64rc`.
|
||||
While in WowBox64, the configuration file is checked at `%USERPROFILE%/.box64rc` only.
|
||||
Settings priority follows this order (from highest to lowest): `~/.box64rc` > `/etc/box64.box64rc` > environment variables.
|
||||
|
||||
Example configuration:
|
||||
@@ -34,7 +38,7 @@ BOX64_DYNAREC_CALLRET=1
|
||||
|
||||
This configuration will apply the specified settings application-wide to any executable named `factorio`.
|
||||
|
||||
### Advanced usage
|
||||
### Advanced usage for Linux build
|
||||
|
||||
1. **Wildcard Matching**
|
||||
|
||||
@@ -62,9 +66,9 @@ This configuration will apply the specified settings application-wide to any exe
|
||||
for category, entries in categories.items():
|
||||
md_file.write(f"## {category}\n\n")
|
||||
for entry in entries:
|
||||
md_file.write(f"### {entry['name']}\n\n{entry['description']}\n\n")
|
||||
md_file.write(f"### {entry['name']}\n\n{entry['description']}{' Availble in WowBox64.' if entry['wine'] else ''}\n\n")
|
||||
for option in entry['options']:
|
||||
md_file.write(f" * {option['key']}: {option['description']} {"[Default]" if option['default'] else ""}\n")
|
||||
md_file.write(f" * {option['key']}: {option['description']} {'[Default]' if option['default'] else ''}\n")
|
||||
md_file.write("\n")
|
||||
|
||||
|
||||
@@ -122,9 +126,9 @@ Example:
|
||||
""")
|
||||
|
||||
for entry in data:
|
||||
pod_file.write(f"\n=item B<{entry['name']}> =I<{ '|'.join(option['key'] for option in entry['options']) }>\n\n{entry['description']}\n\n")
|
||||
pod_file.write(f"\n=item B<{entry['name']}> =I<{ '|'.join(option['key'] for option in entry['options']) }>\n\n{entry['description']}{' Availble in WowBox64.' if entry['wine'] else ''}\n\n")
|
||||
for option in entry['options']:
|
||||
pod_file.write(f" * {option['key']} : {option['description']} {"[Default]" if option['default'] else ""}\n")
|
||||
pod_file.write(f" * {option['key']} : {option['description']} {'[Default]' if option['default'] else ''}\n")
|
||||
pod_file.write("\n")
|
||||
|
||||
pod_file.write("""
|
||||
@@ -132,3 +136,193 @@ Example:
|
||||
|
||||
=cut
|
||||
""")
|
||||
|
||||
####################
|
||||
# Validation
|
||||
####################
|
||||
|
||||
PADDING = 30
|
||||
INCLUDE_BLANK = False
|
||||
|
||||
def get_usage_entry(usage, define):
|
||||
entry = list(e for e in usage if e["name"] == define)
|
||||
if len(entry) == 0:
|
||||
print(f"{define:<{PADDING}}: missing usage.json entry")
|
||||
elif len(entry) > 1:
|
||||
print(f"{define:<{PADDING}}: multiple usage entries found", len(entry))
|
||||
else:
|
||||
return entry[0]
|
||||
return None
|
||||
|
||||
# check `default` uniqueness
|
||||
for entry in data:
|
||||
i = list(d["default"] for d in entry["options"]).count(True)
|
||||
if i > 1:
|
||||
print(f"{entry['name']:<{PADDING}}: multiple default values usage.json")
|
||||
|
||||
|
||||
# regex to match env.h C code
|
||||
regex = {
|
||||
"INTEGER": re.compile(
|
||||
r"^\s*INTEGER\((?P<define>\w+), (?P<name>\w+), (?P<default>\w+), (?P<min>\w+), (?P<max>\w+), (?P<wine>\w+)\)"
|
||||
),
|
||||
"INTEGER64": re.compile(
|
||||
r"^\s*INTEGER64\((?P<define>\w+), (?P<name>\w+), (?P<default>\w+), (?P<wine>\w+)\)"
|
||||
),
|
||||
"BOOLEAN": re.compile(
|
||||
r"^\s*BOOLEAN\((?P<define>\w+), (?P<name>\w+), (?P<default>\w+), (?P<wine>\w+)\)"
|
||||
),
|
||||
"ADDRESS": re.compile(r"^\s*ADDRESS\((?P<define>\w+), (?P<name>\w+), (?P<wine>\w+)\)"),
|
||||
"STRING": re.compile(r"^\s*STRING\((?P<define>\w+), (?P<name>\w+), (?P<wine>\w+)\)"),
|
||||
}
|
||||
|
||||
env_file = os.path.join(script_dir, "../../src/include/env.h")
|
||||
with open(env_file, "r") as file:
|
||||
matches = {}
|
||||
for line in file.readlines():
|
||||
for t, r in regex.items():
|
||||
m = r.search(line)
|
||||
if m:
|
||||
# filter out comments and other non useful code
|
||||
if m.group("define") == "NAME":
|
||||
continue
|
||||
|
||||
if t not in matches:
|
||||
matches[t] = {}
|
||||
if (m.group("define") in matches[t]):
|
||||
# multiple definitions, no default
|
||||
matches[t][m.group("define")]['no_default'] = True
|
||||
break
|
||||
matches[t][m.group("define")] = m.groupdict()
|
||||
matches[t][m.group("define")]['no_default'] = False
|
||||
|
||||
for define, m in matches["INTEGER"].items():
|
||||
name = m["name"]
|
||||
default = None if m["no_default"] or not m["default"].isdigit() else int(m["default"])
|
||||
min = int(m["min"])
|
||||
max = int(m["max"])
|
||||
|
||||
# Check default in valid range
|
||||
if default and (default < min or default > max):
|
||||
print(f"{define:<{PADDING}}: default lays outside of min/max range")
|
||||
|
||||
# Check consistency with usage.json
|
||||
if e := get_usage_entry(data, define):
|
||||
# guess min/max values if possible
|
||||
min2 = max2 = None
|
||||
# blank means that the entry has an 'XXXX' entry which usually indicated that arbitrary values are valid
|
||||
blank = False
|
||||
default2 = None
|
||||
|
||||
if int(m["wine"]) != int(e["wine"]):
|
||||
print(f"{define:<{PADDING}}: wine mismatch: env.h={int(m['wine'])}, usage.json={int(e['wine'])}")
|
||||
|
||||
for o in e["options"]:
|
||||
if o["key"] == "XXXX":
|
||||
blank = True
|
||||
continue
|
||||
|
||||
val = int(o["key"]) # not supposed to fail
|
||||
|
||||
min2 = min2 if min2 is not None and min2 < val else val
|
||||
max2 = max2 if max2 is not None and max2 > val else val
|
||||
|
||||
if o["default"]:
|
||||
default2 = val
|
||||
|
||||
if min2 and min2 != min:
|
||||
if not blank or (blank and INCLUDE_BLANK):
|
||||
print(
|
||||
f"{define:<{PADDING}}: min value mismatch: env.h={min}, usage.json={min2}{(' (possible false positive)' if blank else '')}"
|
||||
)
|
||||
if max2 and max2 != max:
|
||||
if not blank or (blank and INCLUDE_BLANK):
|
||||
print(
|
||||
f"{define:<{PADDING}}: max value mismatch: env.h={max}, usage.json={max2}{(' (possible false positive)' if blank else '')}"
|
||||
)
|
||||
if default2 != default:
|
||||
print(
|
||||
f"{define:<{PADDING}}: default value mismatch: env.h={default}, usage.json={default2}"
|
||||
)
|
||||
|
||||
for define, m in matches['INTEGER64'].items():
|
||||
# similar to INTEGER but without min/max
|
||||
name = m["name"]
|
||||
default = None if m["no_default"] or not m["default"].isdigit() else int(m["default"])
|
||||
|
||||
# Check consistency with usage.json
|
||||
if e := get_usage_entry(data, define):
|
||||
default2 = None
|
||||
|
||||
if int(m["wine"]) != int(e["wine"]):
|
||||
print(f"{define:<{PADDING}}: wine mismatch: env.h={int(m['wine'])}, usage.json={int(e['wine'])}")
|
||||
|
||||
for o in e["options"]:
|
||||
if o["key"] == "XXXX":
|
||||
continue
|
||||
|
||||
val = int(o["key"])
|
||||
|
||||
if o["default"]:
|
||||
default2 = val
|
||||
|
||||
if default2 != default:
|
||||
print(
|
||||
f"{define:<{PADDING}}: default value mismatch: env.h={default}, usage.json={default2}"
|
||||
)
|
||||
|
||||
for define, m in matches["BOOLEAN"].items():
|
||||
name = m["name"]
|
||||
default = None if m["no_default"] or m["default"] not in ["0", "1"] else bool(m["default"])
|
||||
|
||||
# Check consistency with usage.json
|
||||
if e := get_usage_entry(data, define):
|
||||
default2 = None
|
||||
|
||||
if int(m["wine"]) != int(e["wine"]):
|
||||
print(f"{define:<{PADDING}}: wine mismatch: env.h={int(m['wine'])}, usage.json={int(e['wine'])}")
|
||||
|
||||
for o in e["options"]:
|
||||
try:
|
||||
val = bool(o["key"])
|
||||
except ValueError:
|
||||
print(f"{define:<{PADDING}}: failed to parse boolean {o['key']}")
|
||||
|
||||
if o["default"]:
|
||||
default2 = val
|
||||
|
||||
if default2 != default:
|
||||
print(
|
||||
f"{define:<{PADDING}}: default value mismatch: env.h={default}, usage.json={default2}"
|
||||
)
|
||||
|
||||
# ADDRESS and STRING are not that interesting
|
||||
for define, m in matches["ADDRESS"].items():
|
||||
if e := get_usage_entry(data, define):
|
||||
if int(m["wine"]) != int(e["wine"]):
|
||||
print(f"{define:<{PADDING}}: wine mismatch: env.h={int(m['wine'])}, usage.json={int(e['wine'])}")
|
||||
|
||||
for define, m in matches["STRING"].items():
|
||||
# skip BOX64_ENV[1-5] entries, they mismatch but this is fine
|
||||
if define.startswith("BOX64_ENV"):
|
||||
continue
|
||||
if e := get_usage_entry(data, define):
|
||||
if int(m["wine"]) != int(e["wine"]):
|
||||
print(f"{define:<{PADDING}}: wine mismatch: env.h={int(m['wine'])}, usage.json={int(e['wine'])}")
|
||||
|
||||
# check that everything from usage.json is in env.h
|
||||
for e in data:
|
||||
define = e["name"]
|
||||
|
||||
# skip BOX64_ENV[1-5] entries, they mismatch but this is fine
|
||||
if define.startswith("BOX64_ENV"):
|
||||
continue
|
||||
|
||||
found = False
|
||||
for t in matches:
|
||||
for d in matches[t]:
|
||||
if d == define:
|
||||
found = True
|
||||
|
||||
if not found:
|
||||
print(f"{define:<{PADDING}}: missing env.h entry")
|
||||
+209
-5
@@ -3,6 +3,7 @@
|
||||
"name": "BOX64_ADDLIBS",
|
||||
"description": "Add extras to the needed libraries list, rarely needed.",
|
||||
"category": "Libraries",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "XXXX",
|
||||
@@ -20,6 +21,7 @@
|
||||
"name": "BOX64_ALLOWMISSINGLIBS",
|
||||
"description": "Allow missing libraries to be ignored.",
|
||||
"category": "Libraries",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -37,6 +39,7 @@
|
||||
"name": "BOX64_ARGS",
|
||||
"description": "Arguments to pass to the guest program, only valid if there is no existing arguments.",
|
||||
"category": "Arguments",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "XXXX",
|
||||
@@ -50,10 +53,34 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BOX64_AVX",
|
||||
"description": "Expose AVX extension to CPUID and cpuinfo file. Default value is 2 on Arm64 because it's fully implemented in DynaRec, 0 otherwise.",
|
||||
"category": "Compatibility",
|
||||
"wine": true,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
"description": "Do not expose AVX capabilities.",
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"key": "1",
|
||||
"description": "Expose AVX, BMI1, F16C and VAES extensions to CPUID and cpuinfo file.",
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"key": "2",
|
||||
"description": "All in 1, plus AVX2, BMI2, FMA, ADX,VPCLMULQDQ and RDRAND extensions.",
|
||||
"default": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BOX64_BASH",
|
||||
"description": "Path to the bash executable.",
|
||||
"category": "Compatibility",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "XXXX",
|
||||
@@ -66,6 +93,7 @@
|
||||
"name": "BOX64_CEFDISABLEGPU",
|
||||
"description": "Add -cef-disable-gpu argument to the guest program.",
|
||||
"category": "Arguments",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -83,6 +111,7 @@
|
||||
"name": "BOX64_CEFDISABLEGPUCOMPOSITOR",
|
||||
"description": "Add -cef-disable-gpu-compositor argument to the guest program.",
|
||||
"category": "Arguments",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -100,6 +129,7 @@
|
||||
"name": "BOX64_CPUTYPE",
|
||||
"description": "Specify the CPU type to emulate.",
|
||||
"category": "Compatibility",
|
||||
"wine": true,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -117,6 +147,7 @@
|
||||
"name": "BOX64_CRASHHANDLER",
|
||||
"description": "Use a dummy crash handler or not.",
|
||||
"category": "Compatibility",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -134,6 +165,7 @@
|
||||
"name": "BOX64_DLSYM_ERROR",
|
||||
"description": "Enable or disable the logging of dlsym errors.",
|
||||
"category": "Debugging",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -151,6 +183,7 @@
|
||||
"name": "BOX64_DUMP",
|
||||
"description": "Dump elfloader debug information.",
|
||||
"category": "Debugging",
|
||||
"wine": true,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -164,10 +197,29 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BOX64_DYNAREC",
|
||||
"description": "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.",
|
||||
"category": "Performance",
|
||||
"wine": true,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
"description": "Disable DynaRec.",
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"key": "1",
|
||||
"description": "Enable DynaRec.",
|
||||
"default": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BOX64_DYNAREC_ALIGNED_ATOMICS",
|
||||
"description": "Generate aligned atomics only (only available on Arm64 for now).",
|
||||
"category": "Performance",
|
||||
"wine": true,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -185,6 +237,7 @@
|
||||
"name": "BOX64_DYNAREC_BIGBLOCK",
|
||||
"description": "Enable building bigger DynaRec code blocks for better performance.",
|
||||
"category": "Performance",
|
||||
"wine": true,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -212,6 +265,7 @@
|
||||
"name": "BOX64_DYNAREC_BLEEDING_EDGE",
|
||||
"description": "Detect MonoBleedingEdge and apply conservative settings.",
|
||||
"category": "Compatibility",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -229,6 +283,7 @@
|
||||
"name": "BOX64_DYNAREC_CALLRET",
|
||||
"description": "Optimize CALL/RET opcodes.",
|
||||
"category": "Performance",
|
||||
"wine": true,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -239,6 +294,11 @@
|
||||
"key": "1",
|
||||
"description": "Try to optimize CALL/RET, skipping the jump table when possible.",
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"key": "2",
|
||||
"description": "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.",
|
||||
"default": false
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -246,6 +306,7 @@
|
||||
"name": "BOX64_DYNAREC_DF",
|
||||
"description": "Enable or disable the use of deferred flags.",
|
||||
"category": "Performance",
|
||||
"wine": true,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -263,6 +324,7 @@
|
||||
"name": "BOX64_DYNAREC_DIRTY",
|
||||
"description": "Allow continue running a block that is unprotected and potentially dirty.",
|
||||
"category": "Performance",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -273,6 +335,11 @@
|
||||
"key": "1",
|
||||
"description": "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.",
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"key": "2",
|
||||
"description": "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).",
|
||||
"default": false
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -280,6 +347,7 @@
|
||||
"name": "BOX64_DYNAREC_DIV0",
|
||||
"description": "Enable or disable the generation of division-by-zero exception.",
|
||||
"category": "Compatibility",
|
||||
"wine": true,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -297,6 +365,7 @@
|
||||
"name": "BOX64_DYNAREC_DUMP",
|
||||
"description": "Enable DynaRec dump.",
|
||||
"category": "Debugging",
|
||||
"wine": true,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -315,10 +384,24 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BOX64_DYNAREC_DUMP_RANGE",
|
||||
"description": "Dump DynaRec blocks in the specified range.",
|
||||
"category": "Debugging",
|
||||
"wine": true,
|
||||
"options": [
|
||||
{
|
||||
"key": "0xXXXXXXXX-0xYYYYYYYY",
|
||||
"description": "Define the range where dynablock gets dumped (inclusive-exclusive).",
|
||||
"default": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BOX64_DYNAREC_FASTNAN",
|
||||
"description": "Enable or disable fast NaN handling.",
|
||||
"category": "Performance",
|
||||
"wine": true,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -336,6 +419,7 @@
|
||||
"name": "BOX64_DYNAREC_FASTROUND",
|
||||
"description": "Enable or disable fast rounding.",
|
||||
"category": "Performance",
|
||||
"wine": true,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -358,6 +442,7 @@
|
||||
"name": "BOX64_DYNAREC_FORWARD",
|
||||
"description": "Define max allowed forward value when building block.",
|
||||
"category": "Performance",
|
||||
"wine": true,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -380,6 +465,7 @@
|
||||
"name": "BOX64_DYNAREC_GDBJIT",
|
||||
"description": "The GDBJIT debugging support, only available on build with `-DGDBJIT=ON`, enable it with gdb command: jit-reader-load /usr/local/lib/libbox64gdbjitreader.so.",
|
||||
"category": "Debugging",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -395,6 +481,16 @@
|
||||
"key": "2",
|
||||
"description": "Dynarec will generate detailed GDBJIT debuginfo with internal state.",
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"key": "3",
|
||||
"description": "Dynarec will register detailed GDBJIT debuginfo only for dynablocks that the guest program trap into, greatly improving performance.",
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"key": "0xXXXXXXX-0xYYYYYYY",
|
||||
"description": "Define the range where Dynarec will generate detailed GDBJIT debuginfo with internal state.",
|
||||
"default": false
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -402,6 +498,7 @@
|
||||
"name": "BOX64_DYNAREC_LOG",
|
||||
"description": "Disable or enable DynaRec logs.",
|
||||
"category": "Debugging",
|
||||
"wine": true,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -429,6 +526,7 @@
|
||||
"name": "BOX64_DYNAREC_MISSING",
|
||||
"description": "Print missing opcodes.",
|
||||
"category": "Debugging",
|
||||
"wine": true,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -451,6 +549,7 @@
|
||||
"name": "BOX64_DYNAREC_NATIVEFLAGS",
|
||||
"description": "Enable or disable the use of native flags.",
|
||||
"category": "Performance",
|
||||
"wine": true,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -468,6 +567,7 @@
|
||||
"name": "BOX64_DYNAREC_PAUSE",
|
||||
"description": "Enable x86 PAUSE emulation, may help the performance of spinlocks.",
|
||||
"category": "Performance",
|
||||
"wine": true,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -495,6 +595,7 @@
|
||||
"name": "BOX64_DYNAREC_PERFMAP",
|
||||
"description": "Generate map file for Linux perf tool.",
|
||||
"category": "Debugging",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -512,6 +613,7 @@
|
||||
"name": "BOX64_DYNAREC_SAFEFLAGS",
|
||||
"description": "Behaviour of flags emulation on CALL/RET opcodes.",
|
||||
"category": "Performance",
|
||||
"wine": true,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -534,6 +636,7 @@
|
||||
"name": "BOX64_DYNAREC_STRONGMEM",
|
||||
"description": "Enable the emulation of x86 strong memory model.",
|
||||
"category": "Performance",
|
||||
"wine": true,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -561,6 +664,7 @@
|
||||
"name": "BOX64_DYNAREC_TBB",
|
||||
"description": "Enable or disable libtbb detection.",
|
||||
"category": "Compatibility",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -578,6 +682,7 @@
|
||||
"name": "BOX64_DYNAREC_TEST",
|
||||
"description": "Enable DynaRec execution comparison with the interpreter, very slow, only for testing.",
|
||||
"category": "Debugging",
|
||||
"wine": true,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -600,6 +705,7 @@
|
||||
"name": "BOX64_DYNAREC_TRACE",
|
||||
"description": "Enable or disable DynaRec trace.",
|
||||
"category": "Debugging",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -613,10 +719,29 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BOX64_DYNAREC_VOLATILE_METADATA",
|
||||
"description": "Use volatile metadata parsed from PE files, only valid for 64bit Windows games.",
|
||||
"category": "Performance",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
"description": "Do not use volatile metadata.",
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"key": "1",
|
||||
"description": "Use volatile metadata, which will guide Box64 for better strong memory emulation.",
|
||||
"default": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BOX64_DYNAREC_WAIT",
|
||||
"description": "Wait or not for the building of a DynaRec code block to be ready.",
|
||||
"category": "Performance",
|
||||
"wine": true,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -634,6 +759,7 @@
|
||||
"name": "BOX64_DYNAREC_WEAKBARRIER",
|
||||
"description": "Tweak the memory barriers to reduce the performance impact by strong memory emualtion.",
|
||||
"category": "Performance",
|
||||
"wine": true,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -656,6 +782,7 @@
|
||||
"name": "BOX64_DYNAREC_X87DOUBLE",
|
||||
"description": "Force the use of float/double for x87 emulation.",
|
||||
"category": "Compatibility",
|
||||
"wine": true,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -666,6 +793,11 @@
|
||||
"key": "1",
|
||||
"description": "Only use Double for x87 emulation.",
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"key": "2",
|
||||
"description": "Check Precision Control low precision on x87 emulation.",
|
||||
"default": false
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -673,6 +805,7 @@
|
||||
"name": "BOX64_EMULATED_LIBS",
|
||||
"description": "Force the use of emulated libraries.",
|
||||
"category": "Libraries",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "XXXX",
|
||||
@@ -690,6 +823,7 @@
|
||||
"name": "BOX64_ENV",
|
||||
"description": "Add an environment variable.",
|
||||
"category": "Environment",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "XXXX=yyyy",
|
||||
@@ -702,6 +836,7 @@
|
||||
"name": "BOX64_ENV[1-5]",
|
||||
"description": "Add an environment variable.",
|
||||
"category": "Environment",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "XXXX=yyyy",
|
||||
@@ -714,6 +849,7 @@
|
||||
"name": "BOX64_EXIT",
|
||||
"description": "Just exit, do not try to run the program.",
|
||||
"category": "Compatibility",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -731,6 +867,7 @@
|
||||
"name": "BOX64_FIX_64BIT_INODES",
|
||||
"description": "Fix 64bit inodes.",
|
||||
"category": "Compatibility",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -748,6 +885,7 @@
|
||||
"name": "BOX64_IGNOREINT3",
|
||||
"description": "Ignore INT3 instructions.",
|
||||
"category": "Compatibility",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -765,6 +903,7 @@
|
||||
"name": "BOX64_INSERT_ARGS",
|
||||
"description": "Prepend arguments to the command line.",
|
||||
"category": "Arguments",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "XXXX",
|
||||
@@ -782,6 +921,7 @@
|
||||
"name": "BOX64_INPROCESSGPU",
|
||||
"description": "Add --in-process-gpu argument to the guest program.",
|
||||
"category": "Arguments",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -799,6 +939,7 @@
|
||||
"name": "BOX64_JITGDB",
|
||||
"description": "Launch gdb or not for SIGSEGV, SIGILL, and SIGBUS.",
|
||||
"category": "Debugging",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -826,6 +967,7 @@
|
||||
"name": "BOX64_JVM",
|
||||
"description": "Detect libjvm and apply conservative settings.",
|
||||
"category": "Compatibility",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -843,6 +985,7 @@
|
||||
"name": "BOX64_LD_LIBRARY_PATH",
|
||||
"description": "Path to look for x86_64 libraries.",
|
||||
"category": "Libraries",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "XXXX",
|
||||
@@ -855,6 +998,7 @@
|
||||
"name": "BOX64_LD_PRELOAD",
|
||||
"description": "Force loading libraries with the binary.",
|
||||
"category": "Libraries",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "XXXX",
|
||||
@@ -872,6 +1016,7 @@
|
||||
"name": "BOX64_LIBCEF",
|
||||
"description": "Detect libcef and apply BOX64_MALLOC_HACK settings.",
|
||||
"category": "Compatibility",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -889,6 +1034,7 @@
|
||||
"name": "BOX64_LIBGL",
|
||||
"description": "Set the name for libGL.",
|
||||
"category": "Libraries",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "libXXXX",
|
||||
@@ -906,6 +1052,7 @@
|
||||
"name": "BOX64_LOAD_ADDR",
|
||||
"description": "Set the address where the program is loaded, only active for PIE guest programs.",
|
||||
"category": "Debugging",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0xXXXXXXXX",
|
||||
@@ -916,13 +1063,14 @@
|
||||
},
|
||||
{
|
||||
"name": "BOX64_LOG",
|
||||
"description": "Enable or disable Box64 logs.",
|
||||
"description": "Enable or disable Box64 logs, default value is 0 if stdout is not terminal, 1 otherwise.",
|
||||
"category": "Debugging",
|
||||
"wine": true,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
"description": "Disable Box64 logs.",
|
||||
"default": true
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"key": "1",
|
||||
@@ -945,6 +1093,7 @@
|
||||
"name": "BOX64_MALLOC_HACK",
|
||||
"description": "Behaviour when hooking malloc operators.",
|
||||
"category": "Compatibility",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -967,6 +1116,7 @@
|
||||
"name": "BOX64_MAXCPU",
|
||||
"description": "Maximum CPU cores exposed.",
|
||||
"category": "Compatibility",
|
||||
"wine": true,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -980,15 +1130,34 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BOX64_MMAP32",
|
||||
"description": "Force 32-bit compatible memory mappings on 64-bit programs that run 32-bit code (like Wine WOW64), can improve performance.",
|
||||
"category": "Performance",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
"description": "Do not force 32-bit memory mappings.",
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"key": "1",
|
||||
"description": "Force 32-bit memory mappings.",
|
||||
"default": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BOX64_NOBANNER",
|
||||
"description": "Disable the Box64 banner.",
|
||||
"category": "Debugging",
|
||||
"wine": true,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
"description": "Show the Box64 banner.",
|
||||
"default": true
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"key": "1",
|
||||
@@ -1001,6 +1170,7 @@
|
||||
"name": "BOX64_NODYNAREC",
|
||||
"description": "Forbid dynablock creation in the address range specified, helpful for debugging behaviour difference between Dynarec and Interpreter.",
|
||||
"category": "Performance",
|
||||
"wine": true,
|
||||
"options": [
|
||||
{
|
||||
"key": "0xXXXXXXXX-0xYYYYYYYY",
|
||||
@@ -1013,6 +1183,7 @@
|
||||
"name": "BOX64_NOGTK",
|
||||
"description": "Do not load wrapped GTK libraries.",
|
||||
"category": "Libraries",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -1030,6 +1201,7 @@
|
||||
"name": "BOX64_NOPULSE",
|
||||
"description": "Do not load PulseAudio libraries (both native and x86_64).",
|
||||
"category": "Libraries",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -1047,6 +1219,7 @@
|
||||
"name": "BOX64_NORCFILES",
|
||||
"description": "Do not load any rc files.",
|
||||
"category": "Compatibility",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -1064,6 +1237,7 @@
|
||||
"name": "BOX64_NOSANDBOX",
|
||||
"description": "Add --no-sandbox argument to the guest program.",
|
||||
"category": "Arguments",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -1081,6 +1255,7 @@
|
||||
"name": "BOX64_NOSIGSEGV",
|
||||
"description": "Disable the handling of SIGSEGV.",
|
||||
"category": "Debugging",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -1098,6 +1273,7 @@
|
||||
"name": "BOX64_NOSIGILL",
|
||||
"description": "Disable the handling of SIGILL.",
|
||||
"category": "Debugging",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -1115,6 +1291,7 @@
|
||||
"name": "BOX64_NOVULKAN",
|
||||
"description": "Do not load Vulkan libraries.",
|
||||
"category": "Libraries",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -1132,6 +1309,7 @@
|
||||
"name": "BOX64_PATH",
|
||||
"description": "Path to look for x86_64 binaries.",
|
||||
"category": "Compatibility",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "XXXX",
|
||||
@@ -1144,6 +1322,7 @@
|
||||
"name": "BOX64_PREFER_EMULATED",
|
||||
"description": "Prefer emulated libraries over native ones.",
|
||||
"category": "Libraries",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -1161,6 +1340,7 @@
|
||||
"name": "BOX64_PREFER_WRAPPED",
|
||||
"description": "Prefer wrapped libs first even if the lib is specified with absolute path.",
|
||||
"category": "Libraries",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -1178,6 +1358,7 @@
|
||||
"name": "BOX64_RCFILE",
|
||||
"description": "Path to the rc file to load.",
|
||||
"category": "Compatibility",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "XXXX",
|
||||
@@ -1190,6 +1371,7 @@
|
||||
"name": "BOX64_RDTSC_1GHZ",
|
||||
"description": "Use hardware counter for rdtsc if available.",
|
||||
"category": "Performance",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -1207,6 +1389,7 @@
|
||||
"name": "BOX64_RESERVE_HIGH",
|
||||
"description": "Reserve high memory area for the program, always enabled on Box32.",
|
||||
"category": "Compatibility",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -1224,6 +1407,7 @@
|
||||
"name": "BOX64_ROLLING_LOG",
|
||||
"description": "Show last few wrapped function call when a signal is caught.",
|
||||
"category": "Debugging",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -1236,8 +1420,8 @@
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"key": "XXX",
|
||||
"description": "Show last XXX wrapped function call when a signal is caught.",
|
||||
"key": "XXXX",
|
||||
"description": "Show last XXXX wrapped function call when a signal is caught.",
|
||||
"default": false
|
||||
}
|
||||
]
|
||||
@@ -1246,6 +1430,7 @@
|
||||
"name": "BOX64_SDL2_JGUID",
|
||||
"description": "Use a workaround for SDL_GetJoystickGUIDInfo function for wrapped SDL2.",
|
||||
"category": "Compatibility",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -1263,6 +1448,7 @@
|
||||
"name": "BOX64_SHAEXT",
|
||||
"description": "Expose SHAEXT (a.k.a. SHA_NI) capabilities.",
|
||||
"category": "Compatibility",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -1280,6 +1466,7 @@
|
||||
"name": "BOX64_SHOWBT",
|
||||
"description": "Show native and emulated backtrace when a signal is caught.",
|
||||
"category": "Debugging",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -1297,6 +1484,7 @@
|
||||
"name": "BOX64_SHOWSEGV",
|
||||
"description": "Always show SIGSEGV signal detailes.",
|
||||
"category": "Debugging",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -1314,6 +1502,7 @@
|
||||
"name": "BOX64_SSE_FLUSHTO0",
|
||||
"description": "Behaviour of SSE Flush to 0 flags.",
|
||||
"category": "Compatibility",
|
||||
"wine": true,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -1331,6 +1520,7 @@
|
||||
"name": "BOX64_SSE42",
|
||||
"description": "Expose SSE4.2 capabilities.",
|
||||
"category": "Compatibility",
|
||||
"wine": true,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -1348,6 +1538,7 @@
|
||||
"name": "BOX64_SYNC_ROUNDING",
|
||||
"description": "Synchronize rounding mode between x86 and native.",
|
||||
"category": "Compatibility",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -1365,6 +1556,7 @@
|
||||
"name": "BOX64_TRACE_COLOR",
|
||||
"description": "Enable or disable colored trace output.",
|
||||
"category": "Debugging",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -1382,6 +1574,7 @@
|
||||
"name": "BOX64_TRACE_EMM",
|
||||
"description": "Enable or disable EMM (i.e. MMX) trace output.",
|
||||
"category": "Debugging",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -1399,6 +1592,7 @@
|
||||
"name": "BOX64_TRACE_FILE",
|
||||
"description": "Send all log and trace to a file instead of `stdout`.",
|
||||
"category": "Debugging",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "XXXX",
|
||||
@@ -1421,6 +1615,7 @@
|
||||
"name": "BOX64_TRACE_INIT",
|
||||
"description": "Same as BOX64_TRACE but starts the trace immediately.",
|
||||
"category": "Debugging",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -1438,6 +1633,7 @@
|
||||
"name": "BOX64_TRACE_START",
|
||||
"description": "Start trace after N opcodes executed.",
|
||||
"category": "Debugging",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -1460,6 +1656,7 @@
|
||||
"name": "BOX64_TRACE_XMM",
|
||||
"description": "Enable or disable XMM (i.e. SSE) trace output.",
|
||||
"category": "Debugging",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -1477,6 +1674,7 @@
|
||||
"name": "BOX64_TRACE",
|
||||
"description": "Only available on box64 build with trace. Adds trace of all instructions executed, along with a register dump.",
|
||||
"category": "Debugging",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -1504,6 +1702,7 @@
|
||||
"name": "BOX64_UNITYPLAYER",
|
||||
"description": "Detect UnityPlayer and apply conservative settings.",
|
||||
"category": "Compatibility",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -1521,6 +1720,7 @@
|
||||
"name": "BOX64_WRAP_EGL",
|
||||
"description": "Prefer wrapped libs for EGL and GLESv2.",
|
||||
"category": "Libraries",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -1538,6 +1738,7 @@
|
||||
"name": "BOX64_X11GLX",
|
||||
"description": "Force Xorg GLX extension to be present.",
|
||||
"category": "Compatibility",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -1555,6 +1756,7 @@
|
||||
"name": "BOX64_X11SYNC",
|
||||
"description": "Force synchronized operation on X11 display.",
|
||||
"category": "Compatibility",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -1572,6 +1774,7 @@
|
||||
"name": "BOX64_X11THREADS",
|
||||
"description": "Call XInitThreads when loading X11. This is mostly for old Loki games with the Loki_Compat library.",
|
||||
"category": "Compatibility",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
@@ -1589,6 +1792,7 @@
|
||||
"name": "BOX64_X87_NO80BITS",
|
||||
"description": "Behavoiur of x87 80bits long double.",
|
||||
"category": "Compatibility",
|
||||
"wine": true,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
|
||||
Vendored
+71
@@ -0,0 +1,71 @@
|
||||
/* origin: FreeBSD /usr/src/lib/msun/src/k_cos.c */
|
||||
/*
|
||||
* ====================================================
|
||||
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
||||
*
|
||||
* Developed at SunSoft, a Sun Microsystems, Inc. business.
|
||||
* Permission to use, copy, modify, and distribute this
|
||||
* software is freely granted, provided that this notice
|
||||
* is preserved.
|
||||
* ====================================================
|
||||
*/
|
||||
/*
|
||||
* __cos( x, y )
|
||||
* kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164
|
||||
* Input x is assumed to be bounded by ~pi/4 in magnitude.
|
||||
* Input y is the tail of x.
|
||||
*
|
||||
* Algorithm
|
||||
* 1. Since cos(-x) = cos(x), we need only to consider positive x.
|
||||
* 2. if x < 2^-27 (hx<0x3e400000 0), return 1 with inexact if x!=0.
|
||||
* 3. cos(x) is approximated by a polynomial of degree 14 on
|
||||
* [0,pi/4]
|
||||
* 4 14
|
||||
* cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x
|
||||
* where the remez error is
|
||||
*
|
||||
* | 2 4 6 8 10 12 14 | -58
|
||||
* |cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x +C6*x )| <= 2
|
||||
* | |
|
||||
*
|
||||
* 4 6 8 10 12 14
|
||||
* 4. let r = C1*x +C2*x +C3*x +C4*x +C5*x +C6*x , then
|
||||
* cos(x) ~ 1 - x*x/2 + r
|
||||
* since cos(x+y) ~ cos(x) - sin(x)*y
|
||||
* ~ cos(x) - x*y,
|
||||
* a correction term is necessary in cos(x) and hence
|
||||
* cos(x+y) = 1 - (x*x/2 - (r - x*y))
|
||||
* For better accuracy, rearrange to
|
||||
* cos(x+y) ~ w + (tmp + (r-x*y))
|
||||
* where w = 1 - x*x/2 and tmp is a tiny correction term
|
||||
* (1 - x*x/2 == w + tmp exactly in infinite precision).
|
||||
* The exactness of w + tmp in infinite precision depends on w
|
||||
* and tmp having the same precision as x. If they have extra
|
||||
* precision due to compiler bugs, then the extra precision is
|
||||
* only good provided it is retained in all terms of the final
|
||||
* expression for cos(). Retention happens in all cases tested
|
||||
* under FreeBSD, so don't pessimize things by forcibly clipping
|
||||
* any extra precision in w.
|
||||
*/
|
||||
|
||||
#include "libm.h"
|
||||
|
||||
static const double
|
||||
C1 = 4.16666666666666019037e-02, /* 0x3FA55555, 0x5555554C */
|
||||
C2 = -1.38888888888741095749e-03, /* 0xBF56C16C, 0x16C15177 */
|
||||
C3 = 2.48015872894767294178e-05, /* 0x3EFA01A0, 0x19CB1590 */
|
||||
C4 = -2.75573143513906633035e-07, /* 0xBE927E4F, 0x809C52AD */
|
||||
C5 = 2.08757232129817482790e-09, /* 0x3E21EE9E, 0xBDB4B1C4 */
|
||||
C6 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */
|
||||
|
||||
double __cos(double x, double y)
|
||||
{
|
||||
double_t hz,z,r,w;
|
||||
|
||||
z = x*x;
|
||||
w = z*z;
|
||||
r = z*(C1+z*(C2+z*C3)) + w*w*(C4+z*(C5+z*C6));
|
||||
hz = 0.5*z;
|
||||
w = 1.0-hz;
|
||||
return w + (((1.0-w)-hz) + (z*r-x*y));
|
||||
}
|
||||
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
#include "libm.h"
|
||||
|
||||
double __math_divzero(uint32_t sign)
|
||||
{
|
||||
return fp_barrier(sign ? -1.0 : 1.0) / 0.0;
|
||||
}
|
||||
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
#include "libm.h"
|
||||
|
||||
double __math_invalid(double x)
|
||||
{
|
||||
return (x - x) / (x - x);
|
||||
}
|
||||
Vendored
+190
@@ -0,0 +1,190 @@
|
||||
/* origin: FreeBSD /usr/src/lib/msun/src/e_rem_pio2.c */
|
||||
/*
|
||||
* ====================================================
|
||||
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
||||
*
|
||||
* Developed at SunSoft, a Sun Microsystems, Inc. business.
|
||||
* Permission to use, copy, modify, and distribute this
|
||||
* software is freely granted, provided that this notice
|
||||
* is preserved.
|
||||
* ====================================================
|
||||
*
|
||||
* Optimized by Bruce D. Evans.
|
||||
*/
|
||||
/* __rem_pio2(x,y)
|
||||
*
|
||||
* return the remainder of x rem pi/2 in y[0]+y[1]
|
||||
* use __rem_pio2_large() for large x
|
||||
*/
|
||||
|
||||
#include "libm.h"
|
||||
|
||||
#if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1
|
||||
#define EPS DBL_EPSILON
|
||||
#elif FLT_EVAL_METHOD==2
|
||||
#define EPS LDBL_EPSILON
|
||||
#endif
|
||||
|
||||
/*
|
||||
* invpio2: 53 bits of 2/pi
|
||||
* pio2_1: first 33 bit of pi/2
|
||||
* pio2_1t: pi/2 - pio2_1
|
||||
* pio2_2: second 33 bit of pi/2
|
||||
* pio2_2t: pi/2 - (pio2_1+pio2_2)
|
||||
* pio2_3: third 33 bit of pi/2
|
||||
* pio2_3t: pi/2 - (pio2_1+pio2_2+pio2_3)
|
||||
*/
|
||||
static const double
|
||||
toint = 1.5/EPS,
|
||||
pio4 = 0x1.921fb54442d18p-1,
|
||||
invpio2 = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */
|
||||
pio2_1 = 1.57079632673412561417e+00, /* 0x3FF921FB, 0x54400000 */
|
||||
pio2_1t = 6.07710050650619224932e-11, /* 0x3DD0B461, 0x1A626331 */
|
||||
pio2_2 = 6.07710050630396597660e-11, /* 0x3DD0B461, 0x1A600000 */
|
||||
pio2_2t = 2.02226624879595063154e-21, /* 0x3BA3198A, 0x2E037073 */
|
||||
pio2_3 = 2.02226624871116645580e-21, /* 0x3BA3198A, 0x2E000000 */
|
||||
pio2_3t = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */
|
||||
|
||||
/* caller must handle the case when reduction is not needed: |x| ~<= pi/4 */
|
||||
int __rem_pio2(double x, double *y)
|
||||
{
|
||||
union {double f; uint64_t i;} u = {x};
|
||||
double_t z,w,t,r,fn;
|
||||
double tx[3],ty[2];
|
||||
uint32_t ix;
|
||||
int sign, n, ex, ey, i;
|
||||
|
||||
sign = u.i>>63;
|
||||
ix = u.i>>32 & 0x7fffffff;
|
||||
if (ix <= 0x400f6a7a) { /* |x| ~<= 5pi/4 */
|
||||
if ((ix & 0xfffff) == 0x921fb) /* |x| ~= pi/2 or 2pi/2 */
|
||||
goto medium; /* cancellation -- use medium case */
|
||||
if (ix <= 0x4002d97c) { /* |x| ~<= 3pi/4 */
|
||||
if (!sign) {
|
||||
z = x - pio2_1; /* one round good to 85 bits */
|
||||
y[0] = z - pio2_1t;
|
||||
y[1] = (z-y[0]) - pio2_1t;
|
||||
return 1;
|
||||
} else {
|
||||
z = x + pio2_1;
|
||||
y[0] = z + pio2_1t;
|
||||
y[1] = (z-y[0]) + pio2_1t;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if (!sign) {
|
||||
z = x - 2*pio2_1;
|
||||
y[0] = z - 2*pio2_1t;
|
||||
y[1] = (z-y[0]) - 2*pio2_1t;
|
||||
return 2;
|
||||
} else {
|
||||
z = x + 2*pio2_1;
|
||||
y[0] = z + 2*pio2_1t;
|
||||
y[1] = (z-y[0]) + 2*pio2_1t;
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ix <= 0x401c463b) { /* |x| ~<= 9pi/4 */
|
||||
if (ix <= 0x4015fdbc) { /* |x| ~<= 7pi/4 */
|
||||
if (ix == 0x4012d97c) /* |x| ~= 3pi/2 */
|
||||
goto medium;
|
||||
if (!sign) {
|
||||
z = x - 3*pio2_1;
|
||||
y[0] = z - 3*pio2_1t;
|
||||
y[1] = (z-y[0]) - 3*pio2_1t;
|
||||
return 3;
|
||||
} else {
|
||||
z = x + 3*pio2_1;
|
||||
y[0] = z + 3*pio2_1t;
|
||||
y[1] = (z-y[0]) + 3*pio2_1t;
|
||||
return -3;
|
||||
}
|
||||
} else {
|
||||
if (ix == 0x401921fb) /* |x| ~= 4pi/2 */
|
||||
goto medium;
|
||||
if (!sign) {
|
||||
z = x - 4*pio2_1;
|
||||
y[0] = z - 4*pio2_1t;
|
||||
y[1] = (z-y[0]) - 4*pio2_1t;
|
||||
return 4;
|
||||
} else {
|
||||
z = x + 4*pio2_1;
|
||||
y[0] = z + 4*pio2_1t;
|
||||
y[1] = (z-y[0]) + 4*pio2_1t;
|
||||
return -4;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ix < 0x413921fb) { /* |x| ~< 2^20*(pi/2), medium size */
|
||||
medium:
|
||||
/* rint(x/(pi/2)) */
|
||||
fn = rint(x * invpio2);
|
||||
n = (int32_t)fn;
|
||||
r = x - fn*pio2_1;
|
||||
w = fn*pio2_1t; /* 1st round, good to 85 bits */
|
||||
/* Matters with directed rounding. */
|
||||
if (predict_false(r - w < -pio4)) {
|
||||
n--;
|
||||
fn--;
|
||||
r = x - fn*pio2_1;
|
||||
w = fn*pio2_1t;
|
||||
} else if (predict_false(r - w > pio4)) {
|
||||
n++;
|
||||
fn++;
|
||||
r = x - fn*pio2_1;
|
||||
w = fn*pio2_1t;
|
||||
}
|
||||
y[0] = r - w;
|
||||
u.f = y[0];
|
||||
ey = u.i>>52 & 0x7ff;
|
||||
ex = ix>>20;
|
||||
if (ex - ey > 16) { /* 2nd round, good to 118 bits */
|
||||
t = r;
|
||||
w = fn*pio2_2;
|
||||
r = t - w;
|
||||
w = fn*pio2_2t - ((t-r)-w);
|
||||
y[0] = r - w;
|
||||
u.f = y[0];
|
||||
ey = u.i>>52 & 0x7ff;
|
||||
if (ex - ey > 49) { /* 3rd round, good to 151 bits, covers all cases */
|
||||
t = r;
|
||||
w = fn*pio2_3;
|
||||
r = t - w;
|
||||
w = fn*pio2_3t - ((t-r)-w);
|
||||
y[0] = r - w;
|
||||
}
|
||||
}
|
||||
y[1] = (r - y[0]) - w;
|
||||
return n;
|
||||
}
|
||||
/*
|
||||
* all other (large) arguments
|
||||
*/
|
||||
if (ix >= 0x7ff00000) { /* x is inf or NaN */
|
||||
y[0] = y[1] = x - x;
|
||||
return 0;
|
||||
}
|
||||
/* set z = scalbn(|x|,-ilogb(x)+23) */
|
||||
u.f = x;
|
||||
u.i &= (uint64_t)-1>>12;
|
||||
u.i |= (uint64_t)(0x3ff + 23)<<52;
|
||||
z = u.f;
|
||||
for (i=0; i < 2; i++) {
|
||||
tx[i] = (double)(int32_t)z;
|
||||
z = (z-tx[i])*0x1p24;
|
||||
}
|
||||
tx[i] = z;
|
||||
/* skip zero terms, first term is non-zero */
|
||||
while (tx[i] == 0.0)
|
||||
i--;
|
||||
n = __rem_pio2_large(tx,ty,(int)(ix>>20)-(0x3ff+23),i+1,1);
|
||||
if (sign) {
|
||||
y[0] = -ty[0];
|
||||
y[1] = -ty[1];
|
||||
return -n;
|
||||
}
|
||||
y[0] = ty[0];
|
||||
y[1] = ty[1];
|
||||
return n;
|
||||
}
|
||||
Vendored
+442
@@ -0,0 +1,442 @@
|
||||
/* origin: FreeBSD /usr/src/lib/msun/src/k_rem_pio2.c */
|
||||
/*
|
||||
* ====================================================
|
||||
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
||||
*
|
||||
* Developed at SunSoft, a Sun Microsystems, Inc. business.
|
||||
* Permission to use, copy, modify, and distribute this
|
||||
* software is freely granted, provided that this notice
|
||||
* is preserved.
|
||||
* ====================================================
|
||||
*/
|
||||
/*
|
||||
* __rem_pio2_large(x,y,e0,nx,prec)
|
||||
* double x[],y[]; int e0,nx,prec;
|
||||
*
|
||||
* __rem_pio2_large return the last three digits of N with
|
||||
* y = x - N*pi/2
|
||||
* so that |y| < pi/2.
|
||||
*
|
||||
* The method is to compute the integer (mod 8) and fraction parts of
|
||||
* (2/pi)*x without doing the full multiplication. In general we
|
||||
* skip the part of the product that are known to be a huge integer (
|
||||
* more accurately, = 0 mod 8 ). Thus the number of operations are
|
||||
* independent of the exponent of the input.
|
||||
*
|
||||
* (2/pi) is represented by an array of 24-bit integers in ipio2[].
|
||||
*
|
||||
* Input parameters:
|
||||
* x[] The input value (must be positive) is broken into nx
|
||||
* pieces of 24-bit integers in double precision format.
|
||||
* x[i] will be the i-th 24 bit of x. The scaled exponent
|
||||
* of x[0] is given in input parameter e0 (i.e., x[0]*2^e0
|
||||
* match x's up to 24 bits.
|
||||
*
|
||||
* Example of breaking a double positive z into x[0]+x[1]+x[2]:
|
||||
* e0 = ilogb(z)-23
|
||||
* z = scalbn(z,-e0)
|
||||
* for i = 0,1,2
|
||||
* x[i] = floor(z)
|
||||
* z = (z-x[i])*2**24
|
||||
*
|
||||
*
|
||||
* y[] ouput result in an array of double precision numbers.
|
||||
* The dimension of y[] is:
|
||||
* 24-bit precision 1
|
||||
* 53-bit precision 2
|
||||
* 64-bit precision 2
|
||||
* 113-bit precision 3
|
||||
* The actual value is the sum of them. Thus for 113-bit
|
||||
* precison, one may have to do something like:
|
||||
*
|
||||
* long double t,w,r_head, r_tail;
|
||||
* t = (long double)y[2] + (long double)y[1];
|
||||
* w = (long double)y[0];
|
||||
* r_head = t+w;
|
||||
* r_tail = w - (r_head - t);
|
||||
*
|
||||
* e0 The exponent of x[0]. Must be <= 16360 or you need to
|
||||
* expand the ipio2 table.
|
||||
*
|
||||
* nx dimension of x[]
|
||||
*
|
||||
* prec an integer indicating the precision:
|
||||
* 0 24 bits (single)
|
||||
* 1 53 bits (double)
|
||||
* 2 64 bits (extended)
|
||||
* 3 113 bits (quad)
|
||||
*
|
||||
* External function:
|
||||
* double scalbn(), floor();
|
||||
*
|
||||
*
|
||||
* Here is the description of some local variables:
|
||||
*
|
||||
* jk jk+1 is the initial number of terms of ipio2[] needed
|
||||
* in the computation. The minimum and recommended value
|
||||
* for jk is 3,4,4,6 for single, double, extended, and quad.
|
||||
* jk+1 must be 2 larger than you might expect so that our
|
||||
* recomputation test works. (Up to 24 bits in the integer
|
||||
* part (the 24 bits of it that we compute) and 23 bits in
|
||||
* the fraction part may be lost to cancelation before we
|
||||
* recompute.)
|
||||
*
|
||||
* jz local integer variable indicating the number of
|
||||
* terms of ipio2[] used.
|
||||
*
|
||||
* jx nx - 1
|
||||
*
|
||||
* jv index for pointing to the suitable ipio2[] for the
|
||||
* computation. In general, we want
|
||||
* ( 2^e0*x[0] * ipio2[jv-1]*2^(-24jv) )/8
|
||||
* is an integer. Thus
|
||||
* e0-3-24*jv >= 0 or (e0-3)/24 >= jv
|
||||
* Hence jv = max(0,(e0-3)/24).
|
||||
*
|
||||
* jp jp+1 is the number of terms in PIo2[] needed, jp = jk.
|
||||
*
|
||||
* q[] double array with integral value, representing the
|
||||
* 24-bits chunk of the product of x and 2/pi.
|
||||
*
|
||||
* q0 the corresponding exponent of q[0]. Note that the
|
||||
* exponent for q[i] would be q0-24*i.
|
||||
*
|
||||
* PIo2[] double precision array, obtained by cutting pi/2
|
||||
* into 24 bits chunks.
|
||||
*
|
||||
* f[] ipio2[] in floating point
|
||||
*
|
||||
* iq[] integer array by breaking up q[] in 24-bits chunk.
|
||||
*
|
||||
* fq[] final product of x*(2/pi) in fq[0],..,fq[jk]
|
||||
*
|
||||
* ih integer. If >0 it indicates q[] is >= 0.5, hence
|
||||
* it also indicates the *sign* of the result.
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Constants:
|
||||
* The hexadecimal values are the intended ones for the following
|
||||
* constants. The decimal values may be used, provided that the
|
||||
* compiler will convert from decimal to binary accurately enough
|
||||
* to produce the hexadecimal values shown.
|
||||
*/
|
||||
|
||||
#include "libm.h"
|
||||
|
||||
static const int init_jk[] = {3,4,4,6}; /* initial value for jk */
|
||||
|
||||
/*
|
||||
* Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi
|
||||
*
|
||||
* integer array, contains the (24*i)-th to (24*i+23)-th
|
||||
* bit of 2/pi after binary point. The corresponding
|
||||
* floating value is
|
||||
*
|
||||
* ipio2[i] * 2^(-24(i+1)).
|
||||
*
|
||||
* NB: This table must have at least (e0-3)/24 + jk terms.
|
||||
* For quad precision (e0 <= 16360, jk = 6), this is 686.
|
||||
*/
|
||||
static const int32_t ipio2[] = {
|
||||
0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62,
|
||||
0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A,
|
||||
0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129,
|
||||
0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41,
|
||||
0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8,
|
||||
0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF,
|
||||
0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5,
|
||||
0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08,
|
||||
0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3,
|
||||
0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880,
|
||||
0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B,
|
||||
|
||||
#if LDBL_MAX_EXP > 1024
|
||||
0x47C419, 0xC367CD, 0xDCE809, 0x2A8359, 0xC4768B, 0x961CA6,
|
||||
0xDDAF44, 0xD15719, 0x053EA5, 0xFF0705, 0x3F7E33, 0xE832C2,
|
||||
0xDE4F98, 0x327DBB, 0xC33D26, 0xEF6B1E, 0x5EF89F, 0x3A1F35,
|
||||
0xCAF27F, 0x1D87F1, 0x21907C, 0x7C246A, 0xFA6ED5, 0x772D30,
|
||||
0x433B15, 0xC614B5, 0x9D19C3, 0xC2C4AD, 0x414D2C, 0x5D000C,
|
||||
0x467D86, 0x2D71E3, 0x9AC69B, 0x006233, 0x7CD2B4, 0x97A7B4,
|
||||
0xD55537, 0xF63ED7, 0x1810A3, 0xFC764D, 0x2A9D64, 0xABD770,
|
||||
0xF87C63, 0x57B07A, 0xE71517, 0x5649C0, 0xD9D63B, 0x3884A7,
|
||||
0xCB2324, 0x778AD6, 0x23545A, 0xB91F00, 0x1B0AF1, 0xDFCE19,
|
||||
0xFF319F, 0x6A1E66, 0x615799, 0x47FBAC, 0xD87F7E, 0xB76522,
|
||||
0x89E832, 0x60BFE6, 0xCDC4EF, 0x09366C, 0xD43F5D, 0xD7DE16,
|
||||
0xDE3B58, 0x929BDE, 0x2822D2, 0xE88628, 0x4D58E2, 0x32CAC6,
|
||||
0x16E308, 0xCB7DE0, 0x50C017, 0xA71DF3, 0x5BE018, 0x34132E,
|
||||
0x621283, 0x014883, 0x5B8EF5, 0x7FB0AD, 0xF2E91E, 0x434A48,
|
||||
0xD36710, 0xD8DDAA, 0x425FAE, 0xCE616A, 0xA4280A, 0xB499D3,
|
||||
0xF2A606, 0x7F775C, 0x83C2A3, 0x883C61, 0x78738A, 0x5A8CAF,
|
||||
0xBDD76F, 0x63A62D, 0xCBBFF4, 0xEF818D, 0x67C126, 0x45CA55,
|
||||
0x36D9CA, 0xD2A828, 0x8D61C2, 0x77C912, 0x142604, 0x9B4612,
|
||||
0xC459C4, 0x44C5C8, 0x91B24D, 0xF31700, 0xAD43D4, 0xE54929,
|
||||
0x10D5FD, 0xFCBE00, 0xCC941E, 0xEECE70, 0xF53E13, 0x80F1EC,
|
||||
0xC3E7B3, 0x28F8C7, 0x940593, 0x3E71C1, 0xB3092E, 0xF3450B,
|
||||
0x9C1288, 0x7B20AB, 0x9FB52E, 0xC29247, 0x2F327B, 0x6D550C,
|
||||
0x90A772, 0x1FE76B, 0x96CB31, 0x4A1679, 0xE27941, 0x89DFF4,
|
||||
0x9794E8, 0x84E6E2, 0x973199, 0x6BED88, 0x365F5F, 0x0EFDBB,
|
||||
0xB49A48, 0x6CA467, 0x427271, 0x325D8D, 0xB8159F, 0x09E5BC,
|
||||
0x25318D, 0x3974F7, 0x1C0530, 0x010C0D, 0x68084B, 0x58EE2C,
|
||||
0x90AA47, 0x02E774, 0x24D6BD, 0xA67DF7, 0x72486E, 0xEF169F,
|
||||
0xA6948E, 0xF691B4, 0x5153D1, 0xF20ACF, 0x339820, 0x7E4BF5,
|
||||
0x6863B2, 0x5F3EDD, 0x035D40, 0x7F8985, 0x295255, 0xC06437,
|
||||
0x10D86D, 0x324832, 0x754C5B, 0xD4714E, 0x6E5445, 0xC1090B,
|
||||
0x69F52A, 0xD56614, 0x9D0727, 0x50045D, 0xDB3BB4, 0xC576EA,
|
||||
0x17F987, 0x7D6B49, 0xBA271D, 0x296996, 0xACCCC6, 0x5414AD,
|
||||
0x6AE290, 0x89D988, 0x50722C, 0xBEA404, 0x940777, 0x7030F3,
|
||||
0x27FC00, 0xA871EA, 0x49C266, 0x3DE064, 0x83DD97, 0x973FA3,
|
||||
0xFD9443, 0x8C860D, 0xDE4131, 0x9D3992, 0x8C70DD, 0xE7B717,
|
||||
0x3BDF08, 0x2B3715, 0xA0805C, 0x93805A, 0x921110, 0xD8E80F,
|
||||
0xAF806C, 0x4BFFDB, 0x0F9038, 0x761859, 0x15A562, 0xBBCB61,
|
||||
0xB989C7, 0xBD4010, 0x04F2D2, 0x277549, 0xF6B6EB, 0xBB22DB,
|
||||
0xAA140A, 0x2F2689, 0x768364, 0x333B09, 0x1A940E, 0xAA3A51,
|
||||
0xC2A31D, 0xAEEDAF, 0x12265C, 0x4DC26D, 0x9C7A2D, 0x9756C0,
|
||||
0x833F03, 0xF6F009, 0x8C402B, 0x99316D, 0x07B439, 0x15200C,
|
||||
0x5BC3D8, 0xC492F5, 0x4BADC6, 0xA5CA4E, 0xCD37A7, 0x36A9E6,
|
||||
0x9492AB, 0x6842DD, 0xDE6319, 0xEF8C76, 0x528B68, 0x37DBFC,
|
||||
0xABA1AE, 0x3115DF, 0xA1AE00, 0xDAFB0C, 0x664D64, 0xB705ED,
|
||||
0x306529, 0xBF5657, 0x3AFF47, 0xB9F96A, 0xF3BE75, 0xDF9328,
|
||||
0x3080AB, 0xF68C66, 0x15CB04, 0x0622FA, 0x1DE4D9, 0xA4B33D,
|
||||
0x8F1B57, 0x09CD36, 0xE9424E, 0xA4BE13, 0xB52333, 0x1AAAF0,
|
||||
0xA8654F, 0xA5C1D2, 0x0F3F0B, 0xCD785B, 0x76F923, 0x048B7B,
|
||||
0x721789, 0x53A6C6, 0xE26E6F, 0x00EBEF, 0x584A9B, 0xB7DAC4,
|
||||
0xBA66AA, 0xCFCF76, 0x1D02D1, 0x2DF1B1, 0xC1998C, 0x77ADC3,
|
||||
0xDA4886, 0xA05DF7, 0xF480C6, 0x2FF0AC, 0x9AECDD, 0xBC5C3F,
|
||||
0x6DDED0, 0x1FC790, 0xB6DB2A, 0x3A25A3, 0x9AAF00, 0x9353AD,
|
||||
0x0457B6, 0xB42D29, 0x7E804B, 0xA707DA, 0x0EAA76, 0xA1597B,
|
||||
0x2A1216, 0x2DB7DC, 0xFDE5FA, 0xFEDB89, 0xFDBE89, 0x6C76E4,
|
||||
0xFCA906, 0x70803E, 0x156E85, 0xFF87FD, 0x073E28, 0x336761,
|
||||
0x86182A, 0xEABD4D, 0xAFE7B3, 0x6E6D8F, 0x396795, 0x5BBF31,
|
||||
0x48D784, 0x16DF30, 0x432DC7, 0x356125, 0xCE70C9, 0xB8CB30,
|
||||
0xFD6CBF, 0xA200A4, 0xE46C05, 0xA0DD5A, 0x476F21, 0xD21262,
|
||||
0x845CB9, 0x496170, 0xE0566B, 0x015299, 0x375550, 0xB7D51E,
|
||||
0xC4F133, 0x5F6E13, 0xE4305D, 0xA92E85, 0xC3B21D, 0x3632A1,
|
||||
0xA4B708, 0xD4B1EA, 0x21F716, 0xE4698F, 0x77FF27, 0x80030C,
|
||||
0x2D408D, 0xA0CD4F, 0x99A520, 0xD3A2B3, 0x0A5D2F, 0x42F9B4,
|
||||
0xCBDA11, 0xD0BE7D, 0xC1DB9B, 0xBD17AB, 0x81A2CA, 0x5C6A08,
|
||||
0x17552E, 0x550027, 0xF0147F, 0x8607E1, 0x640B14, 0x8D4196,
|
||||
0xDEBE87, 0x2AFDDA, 0xB6256B, 0x34897B, 0xFEF305, 0x9EBFB9,
|
||||
0x4F6A68, 0xA82A4A, 0x5AC44F, 0xBCF82D, 0x985AD7, 0x95C7F4,
|
||||
0x8D4D0D, 0xA63A20, 0x5F57A4, 0xB13F14, 0x953880, 0x0120CC,
|
||||
0x86DD71, 0xB6DEC9, 0xF560BF, 0x11654D, 0x6B0701, 0xACB08C,
|
||||
0xD0C0B2, 0x485551, 0x0EFB1E, 0xC37295, 0x3B06A3, 0x3540C0,
|
||||
0x7BDC06, 0xCC45E0, 0xFA294E, 0xC8CAD6, 0x41F3E8, 0xDE647C,
|
||||
0xD8649B, 0x31BED9, 0xC397A4, 0xD45877, 0xC5E369, 0x13DAF0,
|
||||
0x3C3ABA, 0x461846, 0x5F7555, 0xF5BDD2, 0xC6926E, 0x5D2EAC,
|
||||
0xED440E, 0x423E1C, 0x87C461, 0xE9FD29, 0xF3D6E7, 0xCA7C22,
|
||||
0x35916F, 0xC5E008, 0x8DD7FF, 0xE26A6E, 0xC6FDB0, 0xC10893,
|
||||
0x745D7C, 0xB2AD6B, 0x9D6ECD, 0x7B723E, 0x6A11C6, 0xA9CFF7,
|
||||
0xDF7329, 0xBAC9B5, 0x5100B7, 0x0DB2E2, 0x24BA74, 0x607DE5,
|
||||
0x8AD874, 0x2C150D, 0x0C1881, 0x94667E, 0x162901, 0x767A9F,
|
||||
0xBEFDFD, 0xEF4556, 0x367ED9, 0x13D9EC, 0xB9BA8B, 0xFC97C4,
|
||||
0x27A831, 0xC36EF1, 0x36C594, 0x56A8D8, 0xB5A8B4, 0x0ECCCF,
|
||||
0x2D8912, 0x34576F, 0x89562C, 0xE3CE99, 0xB920D6, 0xAA5E6B,
|
||||
0x9C2A3E, 0xCC5F11, 0x4A0BFD, 0xFBF4E1, 0x6D3B8E, 0x2C86E2,
|
||||
0x84D4E9, 0xA9B4FC, 0xD1EEEF, 0xC9352E, 0x61392F, 0x442138,
|
||||
0xC8D91B, 0x0AFC81, 0x6A4AFB, 0xD81C2F, 0x84B453, 0x8C994E,
|
||||
0xCC2254, 0xDC552A, 0xD6C6C0, 0x96190B, 0xB8701A, 0x649569,
|
||||
0x605A26, 0xEE523F, 0x0F117F, 0x11B5F4, 0xF5CBFC, 0x2DBC34,
|
||||
0xEEBC34, 0xCC5DE8, 0x605EDD, 0x9B8E67, 0xEF3392, 0xB817C9,
|
||||
0x9B5861, 0xBC57E1, 0xC68351, 0x103ED8, 0x4871DD, 0xDD1C2D,
|
||||
0xA118AF, 0x462C21, 0xD7F359, 0x987AD9, 0xC0549E, 0xFA864F,
|
||||
0xFC0656, 0xAE79E5, 0x362289, 0x22AD38, 0xDC9367, 0xAAE855,
|
||||
0x382682, 0x9BE7CA, 0xA40D51, 0xB13399, 0x0ED7A9, 0x480569,
|
||||
0xF0B265, 0xA7887F, 0x974C88, 0x36D1F9, 0xB39221, 0x4A827B,
|
||||
0x21CF98, 0xDC9F40, 0x5547DC, 0x3A74E1, 0x42EB67, 0xDF9DFE,
|
||||
0x5FD45E, 0xA4677B, 0x7AACBA, 0xA2F655, 0x23882B, 0x55BA41,
|
||||
0x086E59, 0x862A21, 0x834739, 0xE6E389, 0xD49EE5, 0x40FB49,
|
||||
0xE956FF, 0xCA0F1C, 0x8A59C5, 0x2BFA94, 0xC5C1D3, 0xCFC50F,
|
||||
0xAE5ADB, 0x86C547, 0x624385, 0x3B8621, 0x94792C, 0x876110,
|
||||
0x7B4C2A, 0x1A2C80, 0x12BF43, 0x902688, 0x893C78, 0xE4C4A8,
|
||||
0x7BDBE5, 0xC23AC4, 0xEAF426, 0x8A67F7, 0xBF920D, 0x2BA365,
|
||||
0xB1933D, 0x0B7CBD, 0xDC51A4, 0x63DD27, 0xDDE169, 0x19949A,
|
||||
0x9529A8, 0x28CE68, 0xB4ED09, 0x209F44, 0xCA984E, 0x638270,
|
||||
0x237C7E, 0x32B90F, 0x8EF5A7, 0xE75614, 0x08F121, 0x2A9DB5,
|
||||
0x4D7E6F, 0x5119A5, 0xABF9B5, 0xD6DF82, 0x61DD96, 0x023616,
|
||||
0x9F3AC4, 0xA1A283, 0x6DED72, 0x7A8D39, 0xA9B882, 0x5C326B,
|
||||
0x5B2746, 0xED3400, 0x7700D2, 0x55F4FC, 0x4D5901, 0x8071E0,
|
||||
#endif
|
||||
};
|
||||
|
||||
static const double PIo2[] = {
|
||||
1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */
|
||||
7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */
|
||||
5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */
|
||||
3.28200341580791294123e-22, /* 0x3B78CC51, 0x60000000 */
|
||||
1.27065575308067607349e-29, /* 0x39F01B83, 0x80000000 */
|
||||
1.22933308981111328932e-36, /* 0x387A2520, 0x40000000 */
|
||||
2.73370053816464559624e-44, /* 0x36E38222, 0x80000000 */
|
||||
2.16741683877804819444e-51, /* 0x3569F31D, 0x00000000 */
|
||||
};
|
||||
|
||||
int __rem_pio2_large(double *x, double *y, int e0, int nx, int prec)
|
||||
{
|
||||
int32_t jz,jx,jv,jp,jk,carry,n,iq[20],i,j,k,m,q0,ih;
|
||||
double z,fw,f[20],fq[20],q[20];
|
||||
|
||||
/* initialize jk*/
|
||||
jk = init_jk[prec];
|
||||
jp = jk;
|
||||
|
||||
/* determine jx,jv,q0, note that 3>q0 */
|
||||
jx = nx-1;
|
||||
jv = (e0-3)/24; if(jv<0) jv=0;
|
||||
q0 = e0-24*(jv+1);
|
||||
|
||||
/* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */
|
||||
j = jv-jx; m = jx+jk;
|
||||
for (i=0; i<=m; i++,j++)
|
||||
f[i] = j<0 ? 0.0 : (double)ipio2[j];
|
||||
|
||||
/* compute q[0],q[1],...q[jk] */
|
||||
for (i=0; i<=jk; i++) {
|
||||
for (j=0,fw=0.0; j<=jx; j++)
|
||||
fw += x[j]*f[jx+i-j];
|
||||
q[i] = fw;
|
||||
}
|
||||
|
||||
jz = jk;
|
||||
recompute:
|
||||
/* distill q[] into iq[] reversingly */
|
||||
for (i=0,j=jz,z=q[jz]; j>0; i++,j--) {
|
||||
fw = (double)(int32_t)(0x1p-24*z);
|
||||
iq[i] = (int32_t)(z - 0x1p24*fw);
|
||||
z = q[j-1]+fw;
|
||||
}
|
||||
|
||||
/* compute n */
|
||||
z = scalbn(z,q0); /* actual value of z */
|
||||
z -= 8.0*floor(z*0.125); /* trim off integer >= 8 */
|
||||
n = (int32_t)z;
|
||||
z -= (double)n;
|
||||
ih = 0;
|
||||
if (q0 > 0) { /* need iq[jz-1] to determine n */
|
||||
i = iq[jz-1]>>(24-q0); n += i;
|
||||
iq[jz-1] -= i<<(24-q0);
|
||||
ih = iq[jz-1]>>(23-q0);
|
||||
}
|
||||
else if (q0 == 0) ih = iq[jz-1]>>23;
|
||||
else if (z >= 0.5) ih = 2;
|
||||
|
||||
if (ih > 0) { /* q > 0.5 */
|
||||
n += 1; carry = 0;
|
||||
for (i=0; i<jz; i++) { /* compute 1-q */
|
||||
j = iq[i];
|
||||
if (carry == 0) {
|
||||
if (j != 0) {
|
||||
carry = 1;
|
||||
iq[i] = 0x1000000 - j;
|
||||
}
|
||||
} else
|
||||
iq[i] = 0xffffff - j;
|
||||
}
|
||||
if (q0 > 0) { /* rare case: chance is 1 in 12 */
|
||||
switch(q0) {
|
||||
case 1:
|
||||
iq[jz-1] &= 0x7fffff; break;
|
||||
case 2:
|
||||
iq[jz-1] &= 0x3fffff; break;
|
||||
}
|
||||
}
|
||||
if (ih == 2) {
|
||||
z = 1.0 - z;
|
||||
if (carry != 0)
|
||||
z -= scalbn(1.0,q0);
|
||||
}
|
||||
}
|
||||
|
||||
/* check if recomputation is needed */
|
||||
if (z == 0.0) {
|
||||
j = 0;
|
||||
for (i=jz-1; i>=jk; i--) j |= iq[i];
|
||||
if (j == 0) { /* need recomputation */
|
||||
for (k=1; iq[jk-k]==0; k++); /* k = no. of terms needed */
|
||||
|
||||
for (i=jz+1; i<=jz+k; i++) { /* add q[jz+1] to q[jz+k] */
|
||||
f[jx+i] = (double)ipio2[jv+i];
|
||||
for (j=0,fw=0.0; j<=jx; j++)
|
||||
fw += x[j]*f[jx+i-j];
|
||||
q[i] = fw;
|
||||
}
|
||||
jz += k;
|
||||
goto recompute;
|
||||
}
|
||||
}
|
||||
|
||||
/* chop off zero terms */
|
||||
if (z == 0.0) {
|
||||
jz -= 1;
|
||||
q0 -= 24;
|
||||
while (iq[jz] == 0) {
|
||||
jz--;
|
||||
q0 -= 24;
|
||||
}
|
||||
} else { /* break z into 24-bit if necessary */
|
||||
z = scalbn(z,-q0);
|
||||
if (z >= 0x1p24) {
|
||||
fw = (double)(int32_t)(0x1p-24*z);
|
||||
iq[jz] = (int32_t)(z - 0x1p24*fw);
|
||||
jz += 1;
|
||||
q0 += 24;
|
||||
iq[jz] = (int32_t)fw;
|
||||
} else
|
||||
iq[jz] = (int32_t)z;
|
||||
}
|
||||
|
||||
/* convert integer "bit" chunk to floating-point value */
|
||||
fw = scalbn(1.0,q0);
|
||||
for (i=jz; i>=0; i--) {
|
||||
q[i] = fw*(double)iq[i];
|
||||
fw *= 0x1p-24;
|
||||
}
|
||||
|
||||
/* compute PIo2[0,...,jp]*q[jz,...,0] */
|
||||
for(i=jz; i>=0; i--) {
|
||||
for (fw=0.0,k=0; k<=jp && k<=jz-i; k++)
|
||||
fw += PIo2[k]*q[i+k];
|
||||
fq[jz-i] = fw;
|
||||
}
|
||||
|
||||
/* compress fq[] into y[] */
|
||||
switch(prec) {
|
||||
case 0:
|
||||
fw = 0.0;
|
||||
for (i=jz; i>=0; i--)
|
||||
fw += fq[i];
|
||||
y[0] = ih==0 ? fw : -fw;
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
fw = 0.0;
|
||||
for (i=jz; i>=0; i--)
|
||||
fw += fq[i];
|
||||
// TODO: drop excess precision here once double_t is used
|
||||
fw = (double)fw;
|
||||
y[0] = ih==0 ? fw : -fw;
|
||||
fw = fq[0]-fw;
|
||||
for (i=1; i<=jz; i++)
|
||||
fw += fq[i];
|
||||
y[1] = ih==0 ? fw : -fw;
|
||||
break;
|
||||
case 3: /* painful */
|
||||
for (i=jz; i>0; i--) {
|
||||
fw = fq[i-1]+fq[i];
|
||||
fq[i] += fq[i-1]-fw;
|
||||
fq[i-1] = fw;
|
||||
}
|
||||
for (i=jz; i>1; i--) {
|
||||
fw = fq[i-1]+fq[i];
|
||||
fq[i] += fq[i-1]-fw;
|
||||
fq[i-1] = fw;
|
||||
}
|
||||
for (fw=0.0,i=jz; i>=2; i--)
|
||||
fw += fq[i];
|
||||
if (ih==0) {
|
||||
y[0] = fq[0]; y[1] = fq[1]; y[2] = fw;
|
||||
} else {
|
||||
y[0] = -fq[0]; y[1] = -fq[1]; y[2] = -fw;
|
||||
}
|
||||
}
|
||||
return n&7;
|
||||
}
|
||||
Vendored
+64
@@ -0,0 +1,64 @@
|
||||
/* origin: FreeBSD /usr/src/lib/msun/src/k_sin.c */
|
||||
/*
|
||||
* ====================================================
|
||||
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
||||
*
|
||||
* Developed at SunSoft, a Sun Microsystems, Inc. business.
|
||||
* Permission to use, copy, modify, and distribute this
|
||||
* software is freely granted, provided that this notice
|
||||
* is preserved.
|
||||
* ====================================================
|
||||
*/
|
||||
/* __sin( x, y, iy)
|
||||
* kernel sin function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854
|
||||
* Input x is assumed to be bounded by ~pi/4 in magnitude.
|
||||
* Input y is the tail of x.
|
||||
* Input iy indicates whether y is 0. (if iy=0, y assume to be 0).
|
||||
*
|
||||
* Algorithm
|
||||
* 1. Since sin(-x) = -sin(x), we need only to consider positive x.
|
||||
* 2. Callers must return sin(-0) = -0 without calling here since our
|
||||
* odd polynomial is not evaluated in a way that preserves -0.
|
||||
* Callers may do the optimization sin(x) ~ x for tiny x.
|
||||
* 3. sin(x) is approximated by a polynomial of degree 13 on
|
||||
* [0,pi/4]
|
||||
* 3 13
|
||||
* sin(x) ~ x + S1*x + ... + S6*x
|
||||
* where
|
||||
*
|
||||
* |sin(x) 2 4 6 8 10 12 | -58
|
||||
* |----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x +S6*x )| <= 2
|
||||
* | x |
|
||||
*
|
||||
* 4. sin(x+y) = sin(x) + sin'(x')*y
|
||||
* ~ sin(x) + (1-x*x/2)*y
|
||||
* For better accuracy, let
|
||||
* 3 2 2 2 2
|
||||
* r = x *(S2+x *(S3+x *(S4+x *(S5+x *S6))))
|
||||
* then 3 2
|
||||
* sin(x) = x + (S1*x + (x *(r-y/2)+y))
|
||||
*/
|
||||
|
||||
#include "libm.h"
|
||||
|
||||
static const double
|
||||
S1 = -1.66666666666666324348e-01, /* 0xBFC55555, 0x55555549 */
|
||||
S2 = 8.33333333332248946124e-03, /* 0x3F811111, 0x1110F8A6 */
|
||||
S3 = -1.98412698298579493134e-04, /* 0xBF2A01A0, 0x19C161D5 */
|
||||
S4 = 2.75573137070700676789e-06, /* 0x3EC71DE3, 0x57B1FE7D */
|
||||
S5 = -2.50507602534068634195e-08, /* 0xBE5AE5E6, 0x8A2B9CEB */
|
||||
S6 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */
|
||||
|
||||
double __sin(double x, double y, int iy)
|
||||
{
|
||||
double_t z,r,v,w;
|
||||
|
||||
z = x*x;
|
||||
w = z*z;
|
||||
r = S2 + z*(S3 + z*S4) + z*w*(S5 + z*S6);
|
||||
v = z*x;
|
||||
if (iy == 0)
|
||||
return x + v*(S1 + z*r);
|
||||
else
|
||||
return x - ((z*(0.5*y - v*r) - y) - v*S1);
|
||||
}
|
||||
Vendored
+79
@@ -0,0 +1,79 @@
|
||||
/* origin: FreeBSD /usr/src/lib/msun/src/s_cos.c */
|
||||
/*
|
||||
* ====================================================
|
||||
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
||||
*
|
||||
* Developed at SunPro, a Sun Microsystems, Inc. business.
|
||||
* Permission to use, copy, modify, and distribute this
|
||||
* software is freely granted, provided that this notice
|
||||
* is preserved.
|
||||
* ====================================================
|
||||
*/
|
||||
/* cos(x)
|
||||
* Return cosine function of x.
|
||||
*
|
||||
* kernel function:
|
||||
* __sin ... sine function on [-pi/4,pi/4]
|
||||
* __cos ... cosine function on [-pi/4,pi/4]
|
||||
* __rem_pio2 ... argument reduction routine
|
||||
*
|
||||
* Method.
|
||||
* Let S,C and T denote the sin, cos and tan respectively on
|
||||
* [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2
|
||||
* in [-pi/4 , +pi/4], and let n = k mod 4.
|
||||
* We have
|
||||
*
|
||||
* n sin(x) cos(x) tan(x)
|
||||
* ----------------------------------------------------------
|
||||
* 0 S C T
|
||||
* 1 C -S -1/T
|
||||
* 2 -S -C T
|
||||
* 3 -C S -1/T
|
||||
* ----------------------------------------------------------
|
||||
*
|
||||
* Special cases:
|
||||
* Let trig be any of sin, cos, or tan.
|
||||
* trig(+-INF) is NaN, with signals;
|
||||
* trig(NaN) is that NaN;
|
||||
*
|
||||
* Accuracy:
|
||||
* TRIG(x) returns trig(x) nearly rounded
|
||||
*/
|
||||
|
||||
#include "libm.h"
|
||||
|
||||
double __cdecl cos(double x)
|
||||
{
|
||||
double y[2];
|
||||
uint32_t ix;
|
||||
unsigned n;
|
||||
|
||||
GET_HIGH_WORD(ix, x);
|
||||
ix &= 0x7fffffff;
|
||||
|
||||
/* |x| ~< pi/4 */
|
||||
if (ix <= 0x3fe921fb) {
|
||||
if (ix < 0x3e46a09e) { /* |x| < 2**-27 * sqrt(2) */
|
||||
/* raise inexact if x!=0 */
|
||||
FORCE_EVAL(x + 0x1p120f);
|
||||
return 1.0;
|
||||
}
|
||||
return __cos(x, 0);
|
||||
}
|
||||
|
||||
/* cos(Inf or NaN) is NaN */
|
||||
if (isinf(x))
|
||||
return math_error(_DOMAIN, "cos", x, 0, x - x);
|
||||
if (ix >= 0x7ff00000)
|
||||
return x-x;
|
||||
|
||||
/* argument reduction */
|
||||
n = __rem_pio2(x, y);
|
||||
switch (n&3) {
|
||||
case 0: return __cos(y[0], y[1]);
|
||||
case 1: return -__sin(y[0], y[1], 1);
|
||||
case 2: return -__cos(y[0], y[1]);
|
||||
default:
|
||||
return __sin(y[0], y[1], 1);
|
||||
}
|
||||
}
|
||||
Vendored
+130
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Double-precision 2^x function.
|
||||
*
|
||||
* Copyright (c) 2018, Arm Limited.
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include "libm.h"
|
||||
#include "exp_data.h"
|
||||
|
||||
#define N (1 << EXP_TABLE_BITS)
|
||||
#define Shift __exp_data.exp2_shift
|
||||
#define T __exp_data.tab
|
||||
#define C1 __exp_data.exp2_poly[0]
|
||||
#define C2 __exp_data.exp2_poly[1]
|
||||
#define C3 __exp_data.exp2_poly[2]
|
||||
#define C4 __exp_data.exp2_poly[3]
|
||||
#define C5 __exp_data.exp2_poly[4]
|
||||
|
||||
/* Handle cases that may overflow or underflow when computing the result that
|
||||
is scale*(1+TMP) without intermediate rounding. The bit representation of
|
||||
scale is in SBITS, however it has a computed exponent that may have
|
||||
overflown into the sign bit so that needs to be adjusted before using it as
|
||||
a double. (int32_t)KI is the k used in the argument reduction and exponent
|
||||
adjustment of scale, positive k here means the result may overflow and
|
||||
negative k means the result may underflow. */
|
||||
static inline double specialcase(double_t tmp, uint64_t sbits, uint64_t ki)
|
||||
{
|
||||
double_t scale, y;
|
||||
|
||||
if ((ki & 0x80000000) == 0) {
|
||||
/* k > 0, the exponent of scale might have overflowed by 1. */
|
||||
sbits -= 1ull << 52;
|
||||
scale = asdouble(sbits);
|
||||
y = 2 * (scale + scale * tmp);
|
||||
return eval_as_double(y);
|
||||
}
|
||||
/* k < 0, need special care in the subnormal range. */
|
||||
sbits += 1022ull << 52;
|
||||
scale = asdouble(sbits);
|
||||
y = scale + scale * tmp;
|
||||
if (y < 1.0) {
|
||||
/* Round y to the right precision before scaling it into the subnormal
|
||||
range to avoid double rounding that can cause 0.5+E/2 ulp error where
|
||||
E is the worst-case ulp error outside the subnormal range. So this
|
||||
is only useful if the goal is better than 1 ulp worst-case error. */
|
||||
double_t hi, lo;
|
||||
lo = scale - y + scale * tmp;
|
||||
hi = 1.0 + y;
|
||||
lo = 1.0 - hi + y + lo;
|
||||
y = eval_as_double(hi + lo) - 1.0;
|
||||
/* Avoid -0.0 with downward rounding. */
|
||||
if (WANT_ROUNDING && y == 0.0)
|
||||
y = 0.0;
|
||||
/* The underflow exception needs to be signaled explicitly. */
|
||||
fp_force_eval(fp_barrier(0x1p-1022) * 0x1p-1022);
|
||||
}
|
||||
y = 0x1p-1022 * y;
|
||||
return eval_as_double(y);
|
||||
}
|
||||
|
||||
/* Top 12 bits of a double (sign and exponent bits). */
|
||||
static inline uint32_t top12(double x)
|
||||
{
|
||||
return asuint64(x) >> 52;
|
||||
}
|
||||
|
||||
double __cdecl exp2(double x)
|
||||
{
|
||||
uint32_t abstop;
|
||||
uint64_t ki, idx, top, sbits;
|
||||
double_t kd, r, r2, scale, tail, tmp;
|
||||
|
||||
abstop = top12(x) & 0x7ff;
|
||||
if (predict_false(abstop - top12(0x1p-54) >= top12(512.0) - top12(0x1p-54))) {
|
||||
if (abstop - top12(0x1p-54) >= 0x80000000)
|
||||
/* Avoid spurious underflow for tiny x. */
|
||||
/* Note: 0 is common input. */
|
||||
return WANT_ROUNDING ? 1.0 + x : 1.0;
|
||||
if (abstop >= top12(1024.0)) {
|
||||
if (asuint64(x) == asuint64(-INFINITY))
|
||||
return 0.0;
|
||||
if (abstop >= top12(INFINITY))
|
||||
return 1.0 + x;
|
||||
if (!(asuint64(x) >> 63)) {
|
||||
errno = ERANGE;
|
||||
return fp_barrier(DBL_MAX) * DBL_MAX;
|
||||
}
|
||||
else if (x <= -2147483648.0) {
|
||||
fp_barrier(x + 0x1p120f);
|
||||
return 0;
|
||||
}
|
||||
else if (asuint64(x) >= asuint64(-1075.0)) {
|
||||
errno = ERANGE;
|
||||
fp_barrier(x + 0x1p120f);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (2 * asuint64(x) > 2 * asuint64(928.0))
|
||||
/* Large x is special cased below. */
|
||||
abstop = 0;
|
||||
}
|
||||
|
||||
/* exp2(x) = 2^(k/N) * 2^r, with 2^r in [2^(-1/2N),2^(1/2N)]. */
|
||||
/* x = k/N + r, with int k and r in [-1/2N, 1/2N]. */
|
||||
kd = eval_as_double(x + Shift);
|
||||
ki = asuint64(kd); /* k. */
|
||||
kd -= Shift; /* k/N for int k. */
|
||||
r = x - kd;
|
||||
/* 2^(k/N) ~= scale * (1 + tail). */
|
||||
idx = 2 * (ki % N);
|
||||
top = ki << (52 - EXP_TABLE_BITS);
|
||||
tail = asdouble(T[idx]);
|
||||
/* This is only a valid scale when -1023*N < k < 1024*N. */
|
||||
sbits = T[idx + 1] + top;
|
||||
/* exp2(x) = 2^(k/N) * 2^r ~= scale + scale * (tail + 2^r - 1). */
|
||||
/* Evaluation is optimized assuming superscalar pipelined execution. */
|
||||
r2 = r * r;
|
||||
/* Without fma the worst case error is 0.5/N ulp larger. */
|
||||
/* Worst case error is less than 0.5+0.86/N+(abs poly error * 2^53) ulp. */
|
||||
tmp = tail + r * C1 + r2 * (C2 + r * C3) + r2 * r2 * (C4 + r * C5);
|
||||
if (predict_false(abstop == 0))
|
||||
return specialcase(tmp, sbits, ki);
|
||||
scale = asdouble(sbits);
|
||||
/* Note: tmp == 0 or |tmp| > 2^-65 and scale > 2^-928, so there
|
||||
is no spurious underflow here even without fma. */
|
||||
return eval_as_double(scale + scale * tmp);
|
||||
}
|
||||
Vendored
+182
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Shared data between exp, exp2 and pow.
|
||||
*
|
||||
* Copyright (c) 2018, Arm Limited.
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "exp_data.h"
|
||||
|
||||
#define N (1 << EXP_TABLE_BITS)
|
||||
|
||||
const struct exp_data __exp_data = {
|
||||
// N/ln2
|
||||
.invln2N = 0x1.71547652b82fep0 * N,
|
||||
// -ln2/N
|
||||
.negln2hiN = -0x1.62e42fefa0000p-8,
|
||||
.negln2loN = -0x1.cf79abc9e3b3ap-47,
|
||||
// Used for rounding when !TOINT_INTRINSICS
|
||||
#if EXP_USE_TOINT_NARROW
|
||||
.shift = 0x1800000000.8p0,
|
||||
#else
|
||||
.shift = 0x1.8p52,
|
||||
#endif
|
||||
// exp polynomial coefficients.
|
||||
.poly = {
|
||||
// abs error: 1.555*2^-66
|
||||
// ulp error: 0.509 (0.511 without fma)
|
||||
// if |x| < ln2/256+eps
|
||||
// abs error if |x| < ln2/256+0x1p-15: 1.09*2^-65
|
||||
// abs error if |x| < ln2/128: 1.7145*2^-56
|
||||
0x1.ffffffffffdbdp-2,
|
||||
0x1.555555555543cp-3,
|
||||
0x1.55555cf172b91p-5,
|
||||
0x1.1111167a4d017p-7,
|
||||
},
|
||||
.exp2_shift = 0x1.8p52 / N,
|
||||
// exp2 polynomial coefficients.
|
||||
.exp2_poly = {
|
||||
// abs error: 1.2195*2^-65
|
||||
// ulp error: 0.507 (0.511 without fma)
|
||||
// if |x| < 1/256
|
||||
// abs error if |x| < 1/128: 1.9941*2^-56
|
||||
0x1.62e42fefa39efp-1,
|
||||
0x1.ebfbdff82c424p-3,
|
||||
0x1.c6b08d70cf4b5p-5,
|
||||
0x1.3b2abd24650ccp-7,
|
||||
0x1.5d7e09b4e3a84p-10,
|
||||
},
|
||||
// 2^(k/N) ~= H[k]*(1 + T[k]) for int k in [0,N)
|
||||
// tab[2*k] = asuint64(T[k])
|
||||
// tab[2*k+1] = asuint64(H[k]) - (k << 52)/N
|
||||
.tab = {
|
||||
0x0, 0x3ff0000000000000,
|
||||
0x3c9b3b4f1a88bf6e, 0x3feff63da9fb3335,
|
||||
0xbc7160139cd8dc5d, 0x3fefec9a3e778061,
|
||||
0xbc905e7a108766d1, 0x3fefe315e86e7f85,
|
||||
0x3c8cd2523567f613, 0x3fefd9b0d3158574,
|
||||
0xbc8bce8023f98efa, 0x3fefd06b29ddf6de,
|
||||
0x3c60f74e61e6c861, 0x3fefc74518759bc8,
|
||||
0x3c90a3e45b33d399, 0x3fefbe3ecac6f383,
|
||||
0x3c979aa65d837b6d, 0x3fefb5586cf9890f,
|
||||
0x3c8eb51a92fdeffc, 0x3fefac922b7247f7,
|
||||
0x3c3ebe3d702f9cd1, 0x3fefa3ec32d3d1a2,
|
||||
0xbc6a033489906e0b, 0x3fef9b66affed31b,
|
||||
0xbc9556522a2fbd0e, 0x3fef9301d0125b51,
|
||||
0xbc5080ef8c4eea55, 0x3fef8abdc06c31cc,
|
||||
0xbc91c923b9d5f416, 0x3fef829aaea92de0,
|
||||
0x3c80d3e3e95c55af, 0x3fef7a98c8a58e51,
|
||||
0xbc801b15eaa59348, 0x3fef72b83c7d517b,
|
||||
0xbc8f1ff055de323d, 0x3fef6af9388c8dea,
|
||||
0x3c8b898c3f1353bf, 0x3fef635beb6fcb75,
|
||||
0xbc96d99c7611eb26, 0x3fef5be084045cd4,
|
||||
0x3c9aecf73e3a2f60, 0x3fef54873168b9aa,
|
||||
0xbc8fe782cb86389d, 0x3fef4d5022fcd91d,
|
||||
0x3c8a6f4144a6c38d, 0x3fef463b88628cd6,
|
||||
0x3c807a05b0e4047d, 0x3fef3f49917ddc96,
|
||||
0x3c968efde3a8a894, 0x3fef387a6e756238,
|
||||
0x3c875e18f274487d, 0x3fef31ce4fb2a63f,
|
||||
0x3c80472b981fe7f2, 0x3fef2b4565e27cdd,
|
||||
0xbc96b87b3f71085e, 0x3fef24dfe1f56381,
|
||||
0x3c82f7e16d09ab31, 0x3fef1e9df51fdee1,
|
||||
0xbc3d219b1a6fbffa, 0x3fef187fd0dad990,
|
||||
0x3c8b3782720c0ab4, 0x3fef1285a6e4030b,
|
||||
0x3c6e149289cecb8f, 0x3fef0cafa93e2f56,
|
||||
0x3c834d754db0abb6, 0x3fef06fe0a31b715,
|
||||
0x3c864201e2ac744c, 0x3fef0170fc4cd831,
|
||||
0x3c8fdd395dd3f84a, 0x3feefc08b26416ff,
|
||||
0xbc86a3803b8e5b04, 0x3feef6c55f929ff1,
|
||||
0xbc924aedcc4b5068, 0x3feef1a7373aa9cb,
|
||||
0xbc9907f81b512d8e, 0x3feeecae6d05d866,
|
||||
0xbc71d1e83e9436d2, 0x3feee7db34e59ff7,
|
||||
0xbc991919b3ce1b15, 0x3feee32dc313a8e5,
|
||||
0x3c859f48a72a4c6d, 0x3feedea64c123422,
|
||||
0xbc9312607a28698a, 0x3feeda4504ac801c,
|
||||
0xbc58a78f4817895b, 0x3feed60a21f72e2a,
|
||||
0xbc7c2c9b67499a1b, 0x3feed1f5d950a897,
|
||||
0x3c4363ed60c2ac11, 0x3feece086061892d,
|
||||
0x3c9666093b0664ef, 0x3feeca41ed1d0057,
|
||||
0x3c6ecce1daa10379, 0x3feec6a2b5c13cd0,
|
||||
0x3c93ff8e3f0f1230, 0x3feec32af0d7d3de,
|
||||
0x3c7690cebb7aafb0, 0x3feebfdad5362a27,
|
||||
0x3c931dbdeb54e077, 0x3feebcb299fddd0d,
|
||||
0xbc8f94340071a38e, 0x3feeb9b2769d2ca7,
|
||||
0xbc87deccdc93a349, 0x3feeb6daa2cf6642,
|
||||
0xbc78dec6bd0f385f, 0x3feeb42b569d4f82,
|
||||
0xbc861246ec7b5cf6, 0x3feeb1a4ca5d920f,
|
||||
0x3c93350518fdd78e, 0x3feeaf4736b527da,
|
||||
0x3c7b98b72f8a9b05, 0x3feead12d497c7fd,
|
||||
0x3c9063e1e21c5409, 0x3feeab07dd485429,
|
||||
0x3c34c7855019c6ea, 0x3feea9268a5946b7,
|
||||
0x3c9432e62b64c035, 0x3feea76f15ad2148,
|
||||
0xbc8ce44a6199769f, 0x3feea5e1b976dc09,
|
||||
0xbc8c33c53bef4da8, 0x3feea47eb03a5585,
|
||||
0xbc845378892be9ae, 0x3feea34634ccc320,
|
||||
0xbc93cedd78565858, 0x3feea23882552225,
|
||||
0x3c5710aa807e1964, 0x3feea155d44ca973,
|
||||
0xbc93b3efbf5e2228, 0x3feea09e667f3bcd,
|
||||
0xbc6a12ad8734b982, 0x3feea012750bdabf,
|
||||
0xbc6367efb86da9ee, 0x3fee9fb23c651a2f,
|
||||
0xbc80dc3d54e08851, 0x3fee9f7df9519484,
|
||||
0xbc781f647e5a3ecf, 0x3fee9f75e8ec5f74,
|
||||
0xbc86ee4ac08b7db0, 0x3fee9f9a48a58174,
|
||||
0xbc8619321e55e68a, 0x3fee9feb564267c9,
|
||||
0x3c909ccb5e09d4d3, 0x3feea0694fde5d3f,
|
||||
0xbc7b32dcb94da51d, 0x3feea11473eb0187,
|
||||
0x3c94ecfd5467c06b, 0x3feea1ed0130c132,
|
||||
0x3c65ebe1abd66c55, 0x3feea2f336cf4e62,
|
||||
0xbc88a1c52fb3cf42, 0x3feea427543e1a12,
|
||||
0xbc9369b6f13b3734, 0x3feea589994cce13,
|
||||
0xbc805e843a19ff1e, 0x3feea71a4623c7ad,
|
||||
0xbc94d450d872576e, 0x3feea8d99b4492ed,
|
||||
0x3c90ad675b0e8a00, 0x3feeaac7d98a6699,
|
||||
0x3c8db72fc1f0eab4, 0x3feeace5422aa0db,
|
||||
0xbc65b6609cc5e7ff, 0x3feeaf3216b5448c,
|
||||
0x3c7bf68359f35f44, 0x3feeb1ae99157736,
|
||||
0xbc93091fa71e3d83, 0x3feeb45b0b91ffc6,
|
||||
0xbc5da9b88b6c1e29, 0x3feeb737b0cdc5e5,
|
||||
0xbc6c23f97c90b959, 0x3feeba44cbc8520f,
|
||||
0xbc92434322f4f9aa, 0x3feebd829fde4e50,
|
||||
0xbc85ca6cd7668e4b, 0x3feec0f170ca07ba,
|
||||
0x3c71affc2b91ce27, 0x3feec49182a3f090,
|
||||
0x3c6dd235e10a73bb, 0x3feec86319e32323,
|
||||
0xbc87c50422622263, 0x3feecc667b5de565,
|
||||
0x3c8b1c86e3e231d5, 0x3feed09bec4a2d33,
|
||||
0xbc91bbd1d3bcbb15, 0x3feed503b23e255d,
|
||||
0x3c90cc319cee31d2, 0x3feed99e1330b358,
|
||||
0x3c8469846e735ab3, 0x3feede6b5579fdbf,
|
||||
0xbc82dfcd978e9db4, 0x3feee36bbfd3f37a,
|
||||
0x3c8c1a7792cb3387, 0x3feee89f995ad3ad,
|
||||
0xbc907b8f4ad1d9fa, 0x3feeee07298db666,
|
||||
0xbc55c3d956dcaeba, 0x3feef3a2b84f15fb,
|
||||
0xbc90a40e3da6f640, 0x3feef9728de5593a,
|
||||
0xbc68d6f438ad9334, 0x3feeff76f2fb5e47,
|
||||
0xbc91eee26b588a35, 0x3fef05b030a1064a,
|
||||
0x3c74ffd70a5fddcd, 0x3fef0c1e904bc1d2,
|
||||
0xbc91bdfbfa9298ac, 0x3fef12c25bd71e09,
|
||||
0x3c736eae30af0cb3, 0x3fef199bdd85529c,
|
||||
0x3c8ee3325c9ffd94, 0x3fef20ab5fffd07a,
|
||||
0x3c84e08fd10959ac, 0x3fef27f12e57d14b,
|
||||
0x3c63cdaf384e1a67, 0x3fef2f6d9406e7b5,
|
||||
0x3c676b2c6c921968, 0x3fef3720dcef9069,
|
||||
0xbc808a1883ccb5d2, 0x3fef3f0b555dc3fa,
|
||||
0xbc8fad5d3ffffa6f, 0x3fef472d4a07897c,
|
||||
0xbc900dae3875a949, 0x3fef4f87080d89f2,
|
||||
0x3c74a385a63d07a7, 0x3fef5818dcfba487,
|
||||
0xbc82919e2040220f, 0x3fef60e316c98398,
|
||||
0x3c8e5a50d5c192ac, 0x3fef69e603db3285,
|
||||
0x3c843a59ac016b4b, 0x3fef7321f301b460,
|
||||
0xbc82d52107b43e1f, 0x3fef7c97337b9b5f,
|
||||
0xbc892ab93b470dc9, 0x3fef864614f5a129,
|
||||
0x3c74b604603a88d3, 0x3fef902ee78b3ff6,
|
||||
0x3c83c5ec519d7271, 0x3fef9a51fbc74c83,
|
||||
0xbc8ff7128fd391f0, 0x3fefa4afa2a490da,
|
||||
0xbc8dae98e223747d, 0x3fefaf482d8e67f1,
|
||||
0x3c8ec3bc41aa2008, 0x3fefba1bee615a27,
|
||||
0x3c842b94c3a9eb32, 0x3fefc52b376bba97,
|
||||
0x3c8a64a931d185ee, 0x3fefd0765b6e4540,
|
||||
0xbc8e37bae43be3ed, 0x3fefdbfdad9cbe14,
|
||||
0x3c77893b4d91cd9d, 0x3fefe7c1819e90d8,
|
||||
0x3c5305c14160cc89, 0x3feff3c22b8f71f1,
|
||||
},
|
||||
};
|
||||
Vendored
+26
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Arm Limited.
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
#ifndef _EXP_DATA_H
|
||||
#define _EXP_DATA_H
|
||||
|
||||
#include <features.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define EXP_TABLE_BITS 7
|
||||
#define EXP_POLY_ORDER 5
|
||||
#define EXP_USE_TOINT_NARROW 0
|
||||
#define EXP2_POLY_ORDER 5
|
||||
extern hidden const struct exp_data {
|
||||
double invln2N;
|
||||
double shift;
|
||||
double negln2hiN;
|
||||
double negln2loN;
|
||||
double poly[4]; /* Last four coefficients. */
|
||||
double exp2_shift;
|
||||
double exp2_poly[EXP2_POLY_ORDER];
|
||||
uint64_t tab[2*(1 << EXP_TABLE_BITS)];
|
||||
} __exp_data;
|
||||
|
||||
#endif
|
||||
Vendored
+202
@@ -0,0 +1,202 @@
|
||||
/* origin: FreeBSD /usr/src/lib/msun/src/s_expm1.c */
|
||||
/*
|
||||
* ====================================================
|
||||
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
||||
*
|
||||
* Developed at SunPro, a Sun Microsystems, Inc. business.
|
||||
* Permission to use, copy, modify, and distribute this
|
||||
* software is freely granted, provided that this notice
|
||||
* is preserved.
|
||||
* ====================================================
|
||||
*/
|
||||
/* expm1(x)
|
||||
* Returns exp(x)-1, the exponential of x minus 1.
|
||||
*
|
||||
* Method
|
||||
* 1. Argument reduction:
|
||||
* Given x, find r and integer k such that
|
||||
*
|
||||
* x = k*ln2 + r, |r| <= 0.5*ln2 ~ 0.34658
|
||||
*
|
||||
* Here a correction term c will be computed to compensate
|
||||
* the error in r when rounded to a floating-point number.
|
||||
*
|
||||
* 2. Approximating expm1(r) by a special rational function on
|
||||
* the interval [0,0.34658]:
|
||||
* Since
|
||||
* r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 - r^4/360 + ...
|
||||
* we define R1(r*r) by
|
||||
* r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 * R1(r*r)
|
||||
* That is,
|
||||
* R1(r**2) = 6/r *((exp(r)+1)/(exp(r)-1) - 2/r)
|
||||
* = 6/r * ( 1 + 2.0*(1/(exp(r)-1) - 1/r))
|
||||
* = 1 - r^2/60 + r^4/2520 - r^6/100800 + ...
|
||||
* We use a special Remez algorithm on [0,0.347] to generate
|
||||
* a polynomial of degree 5 in r*r to approximate R1. The
|
||||
* maximum error of this polynomial approximation is bounded
|
||||
* by 2**-61. In other words,
|
||||
* R1(z) ~ 1.0 + Q1*z + Q2*z**2 + Q3*z**3 + Q4*z**4 + Q5*z**5
|
||||
* where Q1 = -1.6666666666666567384E-2,
|
||||
* Q2 = 3.9682539681370365873E-4,
|
||||
* Q3 = -9.9206344733435987357E-6,
|
||||
* Q4 = 2.5051361420808517002E-7,
|
||||
* Q5 = -6.2843505682382617102E-9;
|
||||
* z = r*r,
|
||||
* with error bounded by
|
||||
* | 5 | -61
|
||||
* | 1.0+Q1*z+...+Q5*z - R1(z) | <= 2
|
||||
* | |
|
||||
*
|
||||
* expm1(r) = exp(r)-1 is then computed by the following
|
||||
* specific way which minimize the accumulation rounding error:
|
||||
* 2 3
|
||||
* r r [ 3 - (R1 + R1*r/2) ]
|
||||
* expm1(r) = r + --- + --- * [--------------------]
|
||||
* 2 2 [ 6 - r*(3 - R1*r/2) ]
|
||||
*
|
||||
* To compensate the error in the argument reduction, we use
|
||||
* expm1(r+c) = expm1(r) + c + expm1(r)*c
|
||||
* ~ expm1(r) + c + r*c
|
||||
* Thus c+r*c will be added in as the correction terms for
|
||||
* expm1(r+c). Now rearrange the term to avoid optimization
|
||||
* screw up:
|
||||
* ( 2 2 )
|
||||
* ({ ( r [ R1 - (3 - R1*r/2) ] ) } r )
|
||||
* expm1(r+c)~r - ({r*(--- * [--------------------]-c)-c} - --- )
|
||||
* ({ ( 2 [ 6 - r*(3 - R1*r/2) ] ) } 2 )
|
||||
* ( )
|
||||
*
|
||||
* = r - E
|
||||
* 3. Scale back to obtain expm1(x):
|
||||
* From step 1, we have
|
||||
* expm1(x) = either 2^k*[expm1(r)+1] - 1
|
||||
* = or 2^k*[expm1(r) + (1-2^-k)]
|
||||
* 4. Implementation notes:
|
||||
* (A). To save one multiplication, we scale the coefficient Qi
|
||||
* to Qi*2^i, and replace z by (x^2)/2.
|
||||
* (B). To achieve maximum accuracy, we compute expm1(x) by
|
||||
* (i) if x < -56*ln2, return -1.0, (raise inexact if x!=inf)
|
||||
* (ii) if k=0, return r-E
|
||||
* (iii) if k=-1, return 0.5*(r-E)-0.5
|
||||
* (iv) if k=1 if r < -0.25, return 2*((r+0.5)- E)
|
||||
* else return 1.0+2.0*(r-E);
|
||||
* (v) if (k<-2||k>56) return 2^k(1-(E-r)) - 1 (or exp(x)-1)
|
||||
* (vi) if k <= 20, return 2^k((1-2^-k)-(E-r)), else
|
||||
* (vii) return 2^k(1-((E+2^-k)-r))
|
||||
*
|
||||
* Special cases:
|
||||
* expm1(INF) is INF, expm1(NaN) is NaN;
|
||||
* expm1(-INF) is -1, and
|
||||
* for finite argument, only expm1(0)=0 is exact.
|
||||
*
|
||||
* Accuracy:
|
||||
* according to an error analysis, the error is always less than
|
||||
* 1 ulp (unit in the last place).
|
||||
*
|
||||
* Misc. info.
|
||||
* For IEEE double
|
||||
* if x > 7.09782712893383973096e+02 then expm1(x) overflow
|
||||
*
|
||||
* Constants:
|
||||
* The hexadecimal values are the intended ones for the following
|
||||
* constants. The decimal values may be used, provided that the
|
||||
* compiler will convert from decimal to binary accurately enough
|
||||
* to produce the hexadecimal values shown.
|
||||
*/
|
||||
|
||||
#include "libm.h"
|
||||
|
||||
static const double
|
||||
o_threshold = 7.09782712893383973096e+02, /* 0x40862E42, 0xFEFA39EF */
|
||||
ln2_hi = 6.93147180369123816490e-01, /* 0x3fe62e42, 0xfee00000 */
|
||||
ln2_lo = 1.90821492927058770002e-10, /* 0x3dea39ef, 0x35793c76 */
|
||||
invln2 = 1.44269504088896338700e+00, /* 0x3ff71547, 0x652b82fe */
|
||||
/* Scaled Q's: Qn_here = 2**n * Qn_above, for R(2*z) where z = hxs = x*x/2: */
|
||||
Q1 = -3.33333333333331316428e-02, /* BFA11111 111110F4 */
|
||||
Q2 = 1.58730158725481460165e-03, /* 3F5A01A0 19FE5585 */
|
||||
Q3 = -7.93650757867487942473e-05, /* BF14CE19 9EAADBB7 */
|
||||
Q4 = 4.00821782732936239552e-06, /* 3ED0CFCA 86E65239 */
|
||||
Q5 = -2.01099218183624371326e-07; /* BE8AFDB7 6E09C32D */
|
||||
|
||||
double __cdecl expm1(double x)
|
||||
{
|
||||
double_t y,hi,lo,c,t,e,hxs,hfx,r1,twopk;
|
||||
union {double f; uint64_t i;} u = {x};
|
||||
uint32_t hx = u.i>>32 & 0x7fffffff;
|
||||
int k, sign = u.i>>63;
|
||||
|
||||
/* filter out huge and non-finite argument */
|
||||
if (hx >= 0x4043687A) { /* if |x|>=56*ln2 */
|
||||
if (isnan(x))
|
||||
return x;
|
||||
if (isinf(x))
|
||||
return sign ? -1 : x;
|
||||
if (sign)
|
||||
return math_error(_UNDERFLOW, "exp", x, 0, -1);
|
||||
if (x > o_threshold) {
|
||||
return math_error(_OVERFLOW, "exp", x, 0, x * 0x1p1023);
|
||||
}
|
||||
}
|
||||
|
||||
/* argument reduction */
|
||||
if (hx > 0x3fd62e42) { /* if |x| > 0.5 ln2 */
|
||||
if (hx < 0x3FF0A2B2) { /* and |x| < 1.5 ln2 */
|
||||
if (!sign) {
|
||||
hi = x - ln2_hi;
|
||||
lo = ln2_lo;
|
||||
k = 1;
|
||||
} else {
|
||||
hi = x + ln2_hi;
|
||||
lo = -ln2_lo;
|
||||
k = -1;
|
||||
}
|
||||
} else {
|
||||
k = invln2*x + (sign ? -0.5 : 0.5);
|
||||
t = k;
|
||||
hi = x - t*ln2_hi; /* t*ln2_hi is exact here */
|
||||
lo = t*ln2_lo;
|
||||
}
|
||||
x = hi-lo;
|
||||
c = (hi-x)-lo;
|
||||
} else if (hx < 0x3c900000) { /* |x| < 2**-54, return x */
|
||||
if (hx < 0x00100000)
|
||||
FORCE_EVAL((float)x);
|
||||
return x;
|
||||
} else
|
||||
k = 0;
|
||||
|
||||
/* x is now in primary range */
|
||||
hfx = 0.5*x;
|
||||
hxs = x*hfx;
|
||||
r1 = 1.0+hxs*(Q1+hxs*(Q2+hxs*(Q3+hxs*(Q4+hxs*Q5))));
|
||||
t = 3.0-r1*hfx;
|
||||
e = hxs*((r1-t)/(6.0 - x*t));
|
||||
if (k == 0) /* c is 0 */
|
||||
return x - (x*e-hxs);
|
||||
e = x*(e-c) - c;
|
||||
e -= hxs;
|
||||
/* exp(x) ~ 2^k (x_reduced - e + 1) */
|
||||
if (k == -1)
|
||||
return 0.5*(x-e) - 0.5;
|
||||
if (k == 1) {
|
||||
if (x < -0.25)
|
||||
return -2.0*(e-(x+0.5));
|
||||
return 1.0+2.0*(x-e);
|
||||
}
|
||||
u.i = (uint64_t)(0x3ff + k)<<52; /* 2^k */
|
||||
twopk = u.f;
|
||||
if (k < 0 || k > 56) { /* suffice to return exp(x)-1 */
|
||||
y = x - e + 1.0;
|
||||
if (k == 1024)
|
||||
y = y*2.0*0x1p1023;
|
||||
else
|
||||
y = y*twopk;
|
||||
return y - 1.0;
|
||||
}
|
||||
u.i = (uint64_t)(0x3ff - k)<<52; /* 2^-k */
|
||||
if (k < 20)
|
||||
y = (x-e+(1-u.f))*twopk;
|
||||
else
|
||||
y = (x-(e+u.f)+1)*twopk;
|
||||
return y;
|
||||
}
|
||||
Vendored
+23
@@ -0,0 +1,23 @@
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
|
||||
double __cdecl frexp(double x, int *e)
|
||||
{
|
||||
union { double d; uint64_t i; } y = { x };
|
||||
int ee = y.i>>52 & 0x7ff;
|
||||
|
||||
if (!ee) {
|
||||
if (x) {
|
||||
x = frexp(x*0x1p64, e);
|
||||
*e -= 64;
|
||||
} else *e = 0;
|
||||
return x;
|
||||
} else if (ee == 0x7ff) {
|
||||
return x;
|
||||
}
|
||||
|
||||
*e = ee - 0x3fe;
|
||||
y.i &= 0x800fffffffffffffull;
|
||||
y.i |= 0x3fe0000000000000ull;
|
||||
return y.d;
|
||||
}
|
||||
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
#ifndef FEATURES_H
|
||||
#define FEATURES_H
|
||||
|
||||
#define weak
|
||||
#define hidden
|
||||
#define weak_alias(old, new)
|
||||
|
||||
#endif
|
||||
Vendored
+282
@@ -0,0 +1,282 @@
|
||||
#ifndef _LIBM_H
|
||||
#define _LIBM_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
#include <errno.h>
|
||||
#include <features.h>
|
||||
|
||||
typedef float float_t;
|
||||
typedef double double_t;
|
||||
|
||||
hidden double math_error(int type, const char *name, double arg1, double arg2, double retval);
|
||||
|
||||
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
|
||||
#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
union ldshape {
|
||||
long double f;
|
||||
struct {
|
||||
uint64_t m;
|
||||
uint16_t se;
|
||||
} i;
|
||||
};
|
||||
#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER == __BIG_ENDIAN
|
||||
/* This is the m68k variant of 80-bit long double, and this definition only works
|
||||
* on archs where the alignment requirement of uint64_t is <= 4. */
|
||||
union ldshape {
|
||||
long double f;
|
||||
struct {
|
||||
uint16_t se;
|
||||
uint16_t pad;
|
||||
uint64_t m;
|
||||
} i;
|
||||
};
|
||||
#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
union ldshape {
|
||||
long double f;
|
||||
struct {
|
||||
uint64_t lo;
|
||||
uint32_t mid;
|
||||
uint16_t top;
|
||||
uint16_t se;
|
||||
} i;
|
||||
struct {
|
||||
uint64_t lo;
|
||||
uint64_t hi;
|
||||
} i2;
|
||||
};
|
||||
#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER == __BIG_ENDIAN
|
||||
union ldshape {
|
||||
long double f;
|
||||
struct {
|
||||
uint16_t se;
|
||||
uint16_t top;
|
||||
uint32_t mid;
|
||||
uint64_t lo;
|
||||
} i;
|
||||
struct {
|
||||
uint64_t hi;
|
||||
uint64_t lo;
|
||||
} i2;
|
||||
};
|
||||
#else
|
||||
#error Unsupported long double representation
|
||||
#endif
|
||||
|
||||
/* Support non-nearest rounding mode. */
|
||||
#define WANT_ROUNDING 1
|
||||
/* Support signaling NaNs. */
|
||||
#define WANT_SNAN 0
|
||||
|
||||
#if WANT_SNAN
|
||||
#error SNaN is unsupported
|
||||
#else
|
||||
#define issignalingf_inline(x) 0
|
||||
#define issignaling_inline(x) 0
|
||||
#endif
|
||||
|
||||
#ifndef TOINT_INTRINSICS
|
||||
#define TOINT_INTRINSICS 0
|
||||
#endif
|
||||
|
||||
#if TOINT_INTRINSICS
|
||||
/* Round x to nearest int in all rounding modes, ties have to be rounded
|
||||
consistently with converttoint so the results match. If the result
|
||||
would be outside of [-2^31, 2^31-1] then the semantics is unspecified. */
|
||||
static double_t roundtoint(double_t);
|
||||
|
||||
/* Convert x to nearest int in all rounding modes, ties have to be rounded
|
||||
consistently with roundtoint. If the result is not representible in an
|
||||
int32_t then the semantics is unspecified. */
|
||||
static int32_t converttoint(double_t);
|
||||
#endif
|
||||
|
||||
/* Helps static branch prediction so hot path can be better optimized. */
|
||||
#ifdef __GNUC__
|
||||
#define predict_true(x) __builtin_expect(!!(x), 1)
|
||||
#define predict_false(x) __builtin_expect(x, 0)
|
||||
#else
|
||||
#define predict_true(x) (x)
|
||||
#define predict_false(x) (x)
|
||||
#endif
|
||||
|
||||
/* Evaluate an expression as the specified type. With standard excess
|
||||
precision handling a type cast or assignment is enough (with
|
||||
-ffloat-store an assignment is required, in old compilers argument
|
||||
passing and return statement may not drop excess precision).
|
||||
|
||||
If compiled without -ffloat-store or -fexcess-precision=standard,
|
||||
an extra volatile qualifier here will force limiting the precision. */
|
||||
|
||||
static inline float eval_as_float(float x)
|
||||
{
|
||||
volatile float y = x;
|
||||
return y;
|
||||
}
|
||||
|
||||
static inline double eval_as_double(double x)
|
||||
{
|
||||
volatile double y = x;
|
||||
return y;
|
||||
}
|
||||
|
||||
/* fp_barrier returns its input, but limits code transformations
|
||||
as if it had a side-effect (e.g. observable io) and returned
|
||||
an arbitrary value. */
|
||||
|
||||
#ifndef fp_barrierf
|
||||
#define fp_barrierf fp_barrierf
|
||||
static inline float fp_barrierf(float x)
|
||||
{
|
||||
volatile float y = x;
|
||||
return y;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef fp_barrier
|
||||
#define fp_barrier fp_barrier
|
||||
static inline double fp_barrier(double x)
|
||||
{
|
||||
volatile double y = x;
|
||||
return y;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef fp_barrierl
|
||||
#define fp_barrierl fp_barrierl
|
||||
static inline long double fp_barrierl(long double x)
|
||||
{
|
||||
volatile long double y = x;
|
||||
return y;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* fp_force_eval ensures that the input value is computed when that's
|
||||
otherwise unused. To prevent the constant folding of the input
|
||||
expression, an additional fp_barrier may be needed or a compilation
|
||||
mode that does so (e.g. -frounding-math in gcc). Then it can be
|
||||
used to evaluate an expression for its fenv side-effects only. */
|
||||
|
||||
#ifndef fp_force_evalf
|
||||
#define fp_force_evalf fp_force_evalf
|
||||
static inline void fp_force_evalf(float x)
|
||||
{
|
||||
volatile float y;
|
||||
y = x;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef fp_force_eval
|
||||
#define fp_force_eval fp_force_eval
|
||||
static inline void fp_force_eval(double x)
|
||||
{
|
||||
volatile double y;
|
||||
y = x;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef fp_force_evall
|
||||
#define fp_force_evall fp_force_evall
|
||||
static inline void fp_force_evall(long double x)
|
||||
{
|
||||
volatile long double y;
|
||||
y = x;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define FORCE_EVAL(x) do { \
|
||||
if (sizeof(x) == sizeof(float)) { \
|
||||
fp_force_evalf(x); \
|
||||
} else if (sizeof(x) == sizeof(double)) { \
|
||||
fp_force_eval(x); \
|
||||
} else { \
|
||||
fp_force_evall(x); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define asuint(f) ((union{float _f; uint32_t _i;}){f})._i
|
||||
#define asfloat(i) ((union{uint32_t _i; float _f;}){i})._f
|
||||
#define asuint64(f) ((union{double _f; uint64_t _i;}){f})._i
|
||||
#define asdouble(i) ((union{uint64_t _i; double _f;}){i})._f
|
||||
|
||||
#define EXTRACT_WORDS(hi,lo,d) \
|
||||
do { \
|
||||
uint64_t __u = asuint64(d); \
|
||||
(hi) = __u >> 32; \
|
||||
(lo) = (uint32_t)__u; \
|
||||
} while (0)
|
||||
|
||||
#define GET_HIGH_WORD(hi,d) \
|
||||
do { \
|
||||
(hi) = asuint64(d) >> 32; \
|
||||
} while (0)
|
||||
|
||||
#define GET_LOW_WORD(lo,d) \
|
||||
do { \
|
||||
(lo) = (uint32_t)asuint64(d); \
|
||||
} while (0)
|
||||
|
||||
#define INSERT_WORDS(d,hi,lo) \
|
||||
do { \
|
||||
(d) = asdouble(((uint64_t)(hi)<<32) | (uint32_t)(lo)); \
|
||||
} while (0)
|
||||
|
||||
#define SET_HIGH_WORD(d,hi) \
|
||||
INSERT_WORDS(d, hi, (uint32_t)asuint64(d))
|
||||
|
||||
#define SET_LOW_WORD(d,lo) \
|
||||
INSERT_WORDS(d, asuint64(d)>>32, lo)
|
||||
|
||||
#define GET_FLOAT_WORD(w,d) \
|
||||
do { \
|
||||
(w) = asuint(d); \
|
||||
} while (0)
|
||||
|
||||
#define SET_FLOAT_WORD(d,w) \
|
||||
do { \
|
||||
(d) = asfloat(w); \
|
||||
} while (0)
|
||||
|
||||
hidden int __rem_pio2_large(double*,double*,int,int,int);
|
||||
|
||||
hidden int __rem_pio2(double,double*);
|
||||
hidden double __sin(double,double,int);
|
||||
hidden double __cos(double,double);
|
||||
hidden double __tan(double,double,int);
|
||||
hidden double __expo2(double,double);
|
||||
|
||||
hidden int __rem_pio2f(float,double*);
|
||||
hidden float __sindf(double);
|
||||
hidden float __cosdf(double);
|
||||
hidden float __tandf(double,int);
|
||||
hidden float __expo2f(float,float);
|
||||
|
||||
hidden int __rem_pio2l(long double, long double *);
|
||||
hidden long double __sinl(long double, long double, int);
|
||||
hidden long double __cosl(long double, long double);
|
||||
hidden long double __tanl(long double, long double, int);
|
||||
|
||||
hidden long double __polevll(long double, const long double *, int);
|
||||
hidden long double __p1evll(long double, const long double *, int);
|
||||
|
||||
extern int __signgam;
|
||||
hidden double __lgamma_r(double, int *);
|
||||
hidden float __lgammaf_r(float, int *);
|
||||
|
||||
/* error handling functions */
|
||||
hidden float __math_xflowf(uint32_t, float);
|
||||
hidden float __math_uflowf(uint32_t);
|
||||
hidden float __math_oflowf(uint32_t);
|
||||
hidden float __math_divzerof(uint32_t);
|
||||
hidden float __math_invalidf(float);
|
||||
hidden double __math_xflow(uint32_t, double);
|
||||
hidden double __math_uflow(uint32_t);
|
||||
hidden double __math_oflow(uint32_t);
|
||||
hidden double __math_divzero(uint32_t);
|
||||
hidden double __math_invalid(double);
|
||||
#if LDBL_MANT_DIG != DBL_MANT_DIG
|
||||
hidden long double __math_invalidl(long double);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
#include <math.h>
|
||||
|
||||
double __cdecl ldexp(double x, int n)
|
||||
{
|
||||
return scalbn(x, n);
|
||||
}
|
||||
Vendored
+126
@@ -0,0 +1,126 @@
|
||||
/* origin: FreeBSD /usr/src/lib/msun/src/s_log1p.c */
|
||||
/*
|
||||
* ====================================================
|
||||
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
||||
*
|
||||
* Developed at SunPro, a Sun Microsystems, Inc. business.
|
||||
* Permission to use, copy, modify, and distribute this
|
||||
* software is freely granted, provided that this notice
|
||||
* is preserved.
|
||||
* ====================================================
|
||||
*/
|
||||
/* double log1p(double x)
|
||||
* Return the natural logarithm of 1+x.
|
||||
*
|
||||
* Method :
|
||||
* 1. Argument Reduction: find k and f such that
|
||||
* 1+x = 2^k * (1+f),
|
||||
* where sqrt(2)/2 < 1+f < sqrt(2) .
|
||||
*
|
||||
* Note. If k=0, then f=x is exact. However, if k!=0, then f
|
||||
* may not be representable exactly. In that case, a correction
|
||||
* term is need. Let u=1+x rounded. Let c = (1+x)-u, then
|
||||
* log(1+x) - log(u) ~ c/u. Thus, we proceed to compute log(u),
|
||||
* and add back the correction term c/u.
|
||||
* (Note: when x > 2**53, one can simply return log(x))
|
||||
*
|
||||
* 2. Approximation of log(1+f): See log.c
|
||||
*
|
||||
* 3. Finally, log1p(x) = k*ln2 + log(1+f) + c/u. See log.c
|
||||
*
|
||||
* Special cases:
|
||||
* log1p(x) is NaN with signal if x < -1 (including -INF) ;
|
||||
* log1p(+INF) is +INF; log1p(-1) is -INF with signal;
|
||||
* log1p(NaN) is that NaN with no signal.
|
||||
*
|
||||
* Accuracy:
|
||||
* according to an error analysis, the error is always less than
|
||||
* 1 ulp (unit in the last place).
|
||||
*
|
||||
* Constants:
|
||||
* The hexadecimal values are the intended ones for the following
|
||||
* constants. The decimal values may be used, provided that the
|
||||
* compiler will convert from decimal to binary accurately enough
|
||||
* to produce the hexadecimal values shown.
|
||||
*
|
||||
* Note: Assuming log() return accurate answer, the following
|
||||
* algorithm can be used to compute log1p(x) to within a few ULP:
|
||||
*
|
||||
* u = 1+x;
|
||||
* if(u==1.0) return x ; else
|
||||
* return log(u)*(x/(u-1.0));
|
||||
*
|
||||
* See HP-15C Advanced Functions Handbook, p.193.
|
||||
*/
|
||||
|
||||
#include "libm.h"
|
||||
|
||||
static const double
|
||||
ln2_hi = 6.93147180369123816490e-01, /* 3fe62e42 fee00000 */
|
||||
ln2_lo = 1.90821492927058770002e-10, /* 3dea39ef 35793c76 */
|
||||
Lg1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */
|
||||
Lg2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */
|
||||
Lg3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */
|
||||
Lg4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */
|
||||
Lg5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */
|
||||
Lg6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */
|
||||
Lg7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */
|
||||
|
||||
double __cdecl log1p(double x)
|
||||
{
|
||||
union {double f; uint64_t i;} u = {x};
|
||||
double_t hfsq,f,c,s,z,R,w,t1,t2,dk;
|
||||
uint32_t hx,hu;
|
||||
int k;
|
||||
|
||||
hx = u.i>>32;
|
||||
k = 1;
|
||||
if (hx < 0x3fda827a || hx>>31) { /* 1+x < sqrt(2)+ */
|
||||
if (hx >= 0xbff00000) { /* x <= -1.0 */
|
||||
if (x == -1) {
|
||||
errno = ERANGE;
|
||||
return x/0.0; /* log1p(-1) = -inf */
|
||||
}
|
||||
errno = EDOM;
|
||||
return (x-x)/0.0; /* log1p(x<-1) = NaN */
|
||||
}
|
||||
if (hx<<1 < 0x3ca00000<<1) { /* |x| < 2**-53 */
|
||||
fp_barrier(x + 0x1p120f);
|
||||
/* underflow if subnormal */
|
||||
if ((hx&0x7ff00000) == 0)
|
||||
FORCE_EVAL((float)x);
|
||||
return x;
|
||||
}
|
||||
if (hx <= 0xbfd2bec4) { /* sqrt(2)/2- <= 1+x < sqrt(2)+ */
|
||||
k = 0;
|
||||
c = 0;
|
||||
f = x;
|
||||
}
|
||||
} else if (hx >= 0x7ff00000)
|
||||
return x;
|
||||
if (k) {
|
||||
u.f = 1 + x;
|
||||
hu = u.i>>32;
|
||||
hu += 0x3ff00000 - 0x3fe6a09e;
|
||||
k = (int)(hu>>20) - 0x3ff;
|
||||
/* correction term ~ log(1+x)-log(u), avoid underflow in c/u */
|
||||
if (k < 54) {
|
||||
c = k >= 2 ? 1-(u.f-x) : x-(u.f-1);
|
||||
c /= u.f;
|
||||
} else
|
||||
c = 0;
|
||||
/* reduce u into [sqrt(2)/2, sqrt(2)] */
|
||||
hu = (hu&0x000fffff) + 0x3fe6a09e;
|
||||
u.i = (uint64_t)hu<<32 | (u.i&0xffffffff);
|
||||
f = u.f - 1;
|
||||
}
|
||||
hfsq = 0.5*f*f;
|
||||
s = f/(2.0+f);
|
||||
z = s*s;
|
||||
w = z*z;
|
||||
t1 = w*(Lg2+w*(Lg4+w*Lg6));
|
||||
t2 = z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7)));
|
||||
R = t2 + t1;
|
||||
dk = k;
|
||||
return s*(hfsq+R) + (dk*ln2_lo+c) - hfsq + f + dk*ln2_hi;
|
||||
}
|
||||
Vendored
+128
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Double-precision log2(x) function.
|
||||
*
|
||||
* Copyright (c) 2018, Arm Limited.
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include "libm.h"
|
||||
#include "log2_data.h"
|
||||
|
||||
#define T __log2_data.tab
|
||||
#define T2 __log2_data.tab2
|
||||
#define B __log2_data.poly1
|
||||
#define A __log2_data.poly
|
||||
#define InvLn2hi __log2_data.invln2hi
|
||||
#define InvLn2lo __log2_data.invln2lo
|
||||
#define N (1 << LOG2_TABLE_BITS)
|
||||
#define OFF 0x3fe6000000000000
|
||||
|
||||
/* Top 16 bits of a double. */
|
||||
static inline uint32_t top16(double x)
|
||||
{
|
||||
return asuint64(x) >> 48;
|
||||
}
|
||||
|
||||
double __cdecl log2(double x)
|
||||
{
|
||||
double_t z, r, r2, r4, y, invc, logc, kd, hi, lo, t1, t2, t3, p;
|
||||
uint64_t ix, iz, tmp;
|
||||
uint32_t top;
|
||||
int k, i;
|
||||
|
||||
ix = asuint64(x);
|
||||
top = top16(x);
|
||||
#define LO asuint64(1.0 - 0x1.5b51p-5)
|
||||
#define HI asuint64(1.0 + 0x1.6ab2p-5)
|
||||
if (predict_false(ix - LO < HI - LO)) {
|
||||
/* Handle close to 1.0 inputs separately. */
|
||||
/* Fix sign of zero with downward rounding when x==1. */
|
||||
if (WANT_ROUNDING && predict_false(ix == asuint64(1.0)))
|
||||
return 0;
|
||||
r = x - 1.0;
|
||||
#if __FP_FAST_FMA
|
||||
hi = r * InvLn2hi;
|
||||
lo = r * InvLn2lo + __builtin_fma(r, InvLn2hi, -hi);
|
||||
#else
|
||||
double_t rhi, rlo;
|
||||
rhi = asdouble(asuint64(r) & -1ULL << 32);
|
||||
rlo = r - rhi;
|
||||
hi = rhi * InvLn2hi;
|
||||
lo = rlo * InvLn2hi + r * InvLn2lo;
|
||||
#endif
|
||||
r2 = r * r; /* rounding error: 0x1p-62. */
|
||||
r4 = r2 * r2;
|
||||
/* Worst-case error is less than 0.54 ULP (0.55 ULP without fma). */
|
||||
p = r2 * (B[0] + r * B[1]);
|
||||
y = hi + p;
|
||||
lo += hi - y + p;
|
||||
lo += r4 * (B[2] + r * B[3] + r2 * (B[4] + r * B[5]) +
|
||||
r4 * (B[6] + r * B[7] + r2 * (B[8] + r * B[9])));
|
||||
y += lo;
|
||||
return eval_as_double(y);
|
||||
}
|
||||
if (predict_false(top - 0x0010 >= 0x7ff0 - 0x0010)) {
|
||||
/* x < 0x1p-1022 or inf or nan. */
|
||||
if (ix * 2 == 0) {
|
||||
errno = ERANGE;
|
||||
return __math_divzero(1);
|
||||
}
|
||||
if (ix == asuint64(INFINITY)) /* log(inf) == inf. */
|
||||
return x;
|
||||
if ((top & 0x7ff0) == 0x7ff0 && (ix & 0xfffffffffffffULL))
|
||||
return x;
|
||||
if (top & 0x8000) {
|
||||
errno = EDOM;
|
||||
return __math_invalid(x);
|
||||
}
|
||||
/* x is subnormal, normalize it. */
|
||||
ix = asuint64(x * 0x1p52);
|
||||
ix -= 52ULL << 52;
|
||||
}
|
||||
|
||||
/* x = 2^k z; where z is in range [OFF,2*OFF) and exact.
|
||||
The range is split into N subintervals.
|
||||
The ith subinterval contains z and c is near its center. */
|
||||
tmp = ix - OFF;
|
||||
i = (tmp >> (52 - LOG2_TABLE_BITS)) % N;
|
||||
k = (int64_t)tmp >> 52; /* arithmetic shift */
|
||||
iz = ix - (tmp & 0xfffULL << 52);
|
||||
invc = T[i].invc;
|
||||
logc = T[i].logc;
|
||||
z = asdouble(iz);
|
||||
kd = (double_t)k;
|
||||
|
||||
/* log2(x) = log2(z/c) + log2(c) + k. */
|
||||
/* r ~= z/c - 1, |r| < 1/(2*N). */
|
||||
#if __FP_FAST_FMA
|
||||
/* rounding error: 0x1p-55/N. */
|
||||
r = __builtin_fma(z, invc, -1.0);
|
||||
t1 = r * InvLn2hi;
|
||||
t2 = r * InvLn2lo + __builtin_fma(r, InvLn2hi, -t1);
|
||||
#else
|
||||
double_t rhi, rlo;
|
||||
/* rounding error: 0x1p-55/N + 0x1p-65. */
|
||||
r = (z - T2[i].chi - T2[i].clo) * invc;
|
||||
rhi = asdouble(asuint64(r) & -1ULL << 32);
|
||||
rlo = r - rhi;
|
||||
t1 = rhi * InvLn2hi;
|
||||
t2 = rlo * InvLn2hi + r * InvLn2lo;
|
||||
#endif
|
||||
|
||||
/* hi + lo = r/ln2 + log2(c) + k. */
|
||||
t3 = kd + logc;
|
||||
hi = t3 + t1;
|
||||
lo = t3 - hi + t1 + t2;
|
||||
|
||||
/* log2(r+1) = r/ln2 + r^2*poly(r). */
|
||||
/* Evaluation is optimized assuming superscalar pipelined execution. */
|
||||
r2 = r * r; /* rounding error: 0x1p-54/N^2. */
|
||||
r4 = r2 * r2;
|
||||
/* Worst-case error if |y| > 0x1p-4: 0.547 ULP (0.550 ULP without fma).
|
||||
~ 0.5 + 2/N/ln2 + abs-poly-error*0x1p56 ULP (+ 0.003 ULP without fma). */
|
||||
p = A[0] + r * A[1] + r2 * (A[2] + r * A[3]) + r4 * (A[4] + r * A[5]);
|
||||
y = lo + r2 * p + hi;
|
||||
return eval_as_double(y);
|
||||
}
|
||||
Vendored
+201
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* Data for log2.
|
||||
*
|
||||
* Copyright (c) 2018, Arm Limited.
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "log2_data.h"
|
||||
|
||||
#define N (1 << LOG2_TABLE_BITS)
|
||||
|
||||
const struct log2_data __log2_data = {
|
||||
// First coefficient: 0x1.71547652b82fe1777d0ffda0d24p0
|
||||
.invln2hi = 0x1.7154765200000p+0,
|
||||
.invln2lo = 0x1.705fc2eefa200p-33,
|
||||
.poly1 = {
|
||||
// relative error: 0x1.2fad8188p-63
|
||||
// in -0x1.5b51p-5 0x1.6ab2p-5
|
||||
-0x1.71547652b82fep-1,
|
||||
0x1.ec709dc3a03f7p-2,
|
||||
-0x1.71547652b7c3fp-2,
|
||||
0x1.2776c50f05be4p-2,
|
||||
-0x1.ec709dd768fe5p-3,
|
||||
0x1.a61761ec4e736p-3,
|
||||
-0x1.7153fbc64a79bp-3,
|
||||
0x1.484d154f01b4ap-3,
|
||||
-0x1.289e4a72c383cp-3,
|
||||
0x1.0b32f285aee66p-3,
|
||||
},
|
||||
.poly = {
|
||||
// relative error: 0x1.a72c2bf8p-58
|
||||
// abs error: 0x1.67a552c8p-66
|
||||
// in -0x1.f45p-8 0x1.f45p-8
|
||||
-0x1.71547652b8339p-1,
|
||||
0x1.ec709dc3a04bep-2,
|
||||
-0x1.7154764702ffbp-2,
|
||||
0x1.2776c50034c48p-2,
|
||||
-0x1.ec7b328ea92bcp-3,
|
||||
0x1.a6225e117f92ep-3,
|
||||
},
|
||||
/* Algorithm:
|
||||
|
||||
x = 2^k z
|
||||
log2(x) = k + log2(c) + log2(z/c)
|
||||
log2(z/c) = poly(z/c - 1)
|
||||
|
||||
where z is in [1.6p-1; 1.6p0] which is split into N subintervals and z falls
|
||||
into the ith one, then table entries are computed as
|
||||
|
||||
tab[i].invc = 1/c
|
||||
tab[i].logc = (double)log2(c)
|
||||
tab2[i].chi = (double)c
|
||||
tab2[i].clo = (double)(c - (double)c)
|
||||
|
||||
where c is near the center of the subinterval and is chosen by trying +-2^29
|
||||
floating point invc candidates around 1/center and selecting one for which
|
||||
|
||||
1) the rounding error in 0x1.8p10 + logc is 0,
|
||||
2) the rounding error in z - chi - clo is < 0x1p-64 and
|
||||
3) the rounding error in (double)log2(c) is minimized (< 0x1p-68).
|
||||
|
||||
Note: 1) ensures that k + logc can be computed without rounding error, 2)
|
||||
ensures that z/c - 1 can be computed as (z - chi - clo)*invc with close to a
|
||||
single rounding error when there is no fast fma for z*invc - 1, 3) ensures
|
||||
that logc + poly(z/c - 1) has small error, however near x == 1 when
|
||||
|log2(x)| < 0x1p-4, this is not enough so that is special cased. */
|
||||
.tab = {
|
||||
{0x1.724286bb1acf8p+0, -0x1.1095feecdb000p-1},
|
||||
{0x1.6e1f766d2cca1p+0, -0x1.08494bd76d000p-1},
|
||||
{0x1.6a13d0e30d48ap+0, -0x1.00143aee8f800p-1},
|
||||
{0x1.661ec32d06c85p+0, -0x1.efec5360b4000p-2},
|
||||
{0x1.623fa951198f8p+0, -0x1.dfdd91ab7e000p-2},
|
||||
{0x1.5e75ba4cf026cp+0, -0x1.cffae0cc79000p-2},
|
||||
{0x1.5ac055a214fb8p+0, -0x1.c043811fda000p-2},
|
||||
{0x1.571ed0f166e1ep+0, -0x1.b0b67323ae000p-2},
|
||||
{0x1.53909590bf835p+0, -0x1.a152f5a2db000p-2},
|
||||
{0x1.5014fed61adddp+0, -0x1.9217f5af86000p-2},
|
||||
{0x1.4cab88e487bd0p+0, -0x1.8304db0719000p-2},
|
||||
{0x1.49539b4334feep+0, -0x1.74189f9a9e000p-2},
|
||||
{0x1.460cbdfafd569p+0, -0x1.6552bb5199000p-2},
|
||||
{0x1.42d664ee4b953p+0, -0x1.56b23a29b1000p-2},
|
||||
{0x1.3fb01111dd8a6p+0, -0x1.483650f5fa000p-2},
|
||||
{0x1.3c995b70c5836p+0, -0x1.39de937f6a000p-2},
|
||||
{0x1.3991c4ab6fd4ap+0, -0x1.2baa1538d6000p-2},
|
||||
{0x1.3698e0ce099b5p+0, -0x1.1d98340ca4000p-2},
|
||||
{0x1.33ae48213e7b2p+0, -0x1.0fa853a40e000p-2},
|
||||
{0x1.30d191985bdb1p+0, -0x1.01d9c32e73000p-2},
|
||||
{0x1.2e025cab271d7p+0, -0x1.e857da2fa6000p-3},
|
||||
{0x1.2b404cf13cd82p+0, -0x1.cd3c8633d8000p-3},
|
||||
{0x1.288b02c7ccb50p+0, -0x1.b26034c14a000p-3},
|
||||
{0x1.25e2263944de5p+0, -0x1.97c1c2f4fe000p-3},
|
||||
{0x1.234563d8615b1p+0, -0x1.7d6023f800000p-3},
|
||||
{0x1.20b46e33eaf38p+0, -0x1.633a71a05e000p-3},
|
||||
{0x1.1e2eefdcda3ddp+0, -0x1.494f5e9570000p-3},
|
||||
{0x1.1bb4a580b3930p+0, -0x1.2f9e424e0a000p-3},
|
||||
{0x1.19453847f2200p+0, -0x1.162595afdc000p-3},
|
||||
{0x1.16e06c0d5d73cp+0, -0x1.f9c9a75bd8000p-4},
|
||||
{0x1.1485f47b7e4c2p+0, -0x1.c7b575bf9c000p-4},
|
||||
{0x1.12358ad0085d1p+0, -0x1.960c60ff48000p-4},
|
||||
{0x1.0fef00f532227p+0, -0x1.64ce247b60000p-4},
|
||||
{0x1.0db2077d03a8fp+0, -0x1.33f78b2014000p-4},
|
||||
{0x1.0b7e6d65980d9p+0, -0x1.0387d1a42c000p-4},
|
||||
{0x1.0953efe7b408dp+0, -0x1.a6f9208b50000p-5},
|
||||
{0x1.07325cac53b83p+0, -0x1.47a954f770000p-5},
|
||||
{0x1.05197e40d1b5cp+0, -0x1.d23a8c50c0000p-6},
|
||||
{0x1.03091c1208ea2p+0, -0x1.16a2629780000p-6},
|
||||
{0x1.0101025b37e21p+0, -0x1.720f8d8e80000p-8},
|
||||
{0x1.fc07ef9caa76bp-1, 0x1.6fe53b1500000p-7},
|
||||
{0x1.f4465d3f6f184p-1, 0x1.11ccce10f8000p-5},
|
||||
{0x1.ecc079f84107fp-1, 0x1.c4dfc8c8b8000p-5},
|
||||
{0x1.e573a99975ae8p-1, 0x1.3aa321e574000p-4},
|
||||
{0x1.de5d6f0bd3de6p-1, 0x1.918a0d08b8000p-4},
|
||||
{0x1.d77b681ff38b3p-1, 0x1.e72e9da044000p-4},
|
||||
{0x1.d0cb5724de943p-1, 0x1.1dcd2507f6000p-3},
|
||||
{0x1.ca4b2dc0e7563p-1, 0x1.476ab03dea000p-3},
|
||||
{0x1.c3f8ee8d6cb51p-1, 0x1.7074377e22000p-3},
|
||||
{0x1.bdd2b4f020c4cp-1, 0x1.98ede8ba94000p-3},
|
||||
{0x1.b7d6c006015cap-1, 0x1.c0db86ad2e000p-3},
|
||||
{0x1.b20366e2e338fp-1, 0x1.e840aafcee000p-3},
|
||||
{0x1.ac57026295039p-1, 0x1.0790ab4678000p-2},
|
||||
{0x1.a6d01bc2731ddp-1, 0x1.1ac056801c000p-2},
|
||||
{0x1.a16d3bc3ff18bp-1, 0x1.2db11d4fee000p-2},
|
||||
{0x1.9c2d14967feadp-1, 0x1.406464ec58000p-2},
|
||||
{0x1.970e4f47c9902p-1, 0x1.52dbe093af000p-2},
|
||||
{0x1.920fb3982bcf2p-1, 0x1.651902050d000p-2},
|
||||
{0x1.8d30187f759f1p-1, 0x1.771d2cdeaf000p-2},
|
||||
{0x1.886e5ebb9f66dp-1, 0x1.88e9c857d9000p-2},
|
||||
{0x1.83c97b658b994p-1, 0x1.9a80155e16000p-2},
|
||||
{0x1.7f405ffc61022p-1, 0x1.abe186ed3d000p-2},
|
||||
{0x1.7ad22181415cap-1, 0x1.bd0f2aea0e000p-2},
|
||||
{0x1.767dcf99eff8cp-1, 0x1.ce0a43dbf4000p-2},
|
||||
},
|
||||
#if !__FP_FAST_FMA
|
||||
.tab2 = {
|
||||
{0x1.6200012b90a8ep-1, 0x1.904ab0644b605p-55},
|
||||
{0x1.66000045734a6p-1, 0x1.1ff9bea62f7a9p-57},
|
||||
{0x1.69fffc325f2c5p-1, 0x1.27ecfcb3c90bap-55},
|
||||
{0x1.6e00038b95a04p-1, 0x1.8ff8856739326p-55},
|
||||
{0x1.71fffe09994e3p-1, 0x1.afd40275f82b1p-55},
|
||||
{0x1.7600015590e1p-1, -0x1.2fd75b4238341p-56},
|
||||
{0x1.7a00012655bd5p-1, 0x1.808e67c242b76p-56},
|
||||
{0x1.7e0003259e9a6p-1, -0x1.208e426f622b7p-57},
|
||||
{0x1.81fffedb4b2d2p-1, -0x1.402461ea5c92fp-55},
|
||||
{0x1.860002dfafcc3p-1, 0x1.df7f4a2f29a1fp-57},
|
||||
{0x1.89ffff78c6b5p-1, -0x1.e0453094995fdp-55},
|
||||
{0x1.8e00039671566p-1, -0x1.a04f3bec77b45p-55},
|
||||
{0x1.91fffe2bf1745p-1, -0x1.7fa34400e203cp-56},
|
||||
{0x1.95fffcc5c9fd1p-1, -0x1.6ff8005a0695dp-56},
|
||||
{0x1.9a0003bba4767p-1, 0x1.0f8c4c4ec7e03p-56},
|
||||
{0x1.9dfffe7b92da5p-1, 0x1.e7fd9478c4602p-55},
|
||||
{0x1.a1fffd72efdafp-1, -0x1.a0c554dcdae7ep-57},
|
||||
{0x1.a5fffde04ff95p-1, 0x1.67da98ce9b26bp-55},
|
||||
{0x1.a9fffca5e8d2bp-1, -0x1.284c9b54c13dep-55},
|
||||
{0x1.adfffddad03eap-1, 0x1.812c8ea602e3cp-58},
|
||||
{0x1.b1ffff10d3d4dp-1, -0x1.efaddad27789cp-55},
|
||||
{0x1.b5fffce21165ap-1, 0x1.3cb1719c61237p-58},
|
||||
{0x1.b9fffd950e674p-1, 0x1.3f7d94194cep-56},
|
||||
{0x1.be000139ca8afp-1, 0x1.50ac4215d9bcp-56},
|
||||
{0x1.c20005b46df99p-1, 0x1.beea653e9c1c9p-57},
|
||||
{0x1.c600040b9f7aep-1, -0x1.c079f274a70d6p-56},
|
||||
{0x1.ca0006255fd8ap-1, -0x1.a0b4076e84c1fp-56},
|
||||
{0x1.cdfffd94c095dp-1, 0x1.8f933f99ab5d7p-55},
|
||||
{0x1.d1ffff975d6cfp-1, -0x1.82c08665fe1bep-58},
|
||||
{0x1.d5fffa2561c93p-1, -0x1.b04289bd295f3p-56},
|
||||
{0x1.d9fff9d228b0cp-1, 0x1.70251340fa236p-55},
|
||||
{0x1.de00065bc7e16p-1, -0x1.5011e16a4d80cp-56},
|
||||
{0x1.e200002f64791p-1, 0x1.9802f09ef62ep-55},
|
||||
{0x1.e600057d7a6d8p-1, -0x1.e0b75580cf7fap-56},
|
||||
{0x1.ea00027edc00cp-1, -0x1.c848309459811p-55},
|
||||
{0x1.ee0006cf5cb7cp-1, -0x1.f8027951576f4p-55},
|
||||
{0x1.f2000782b7dccp-1, -0x1.f81d97274538fp-55},
|
||||
{0x1.f6000260c450ap-1, -0x1.071002727ffdcp-59},
|
||||
{0x1.f9fffe88cd533p-1, -0x1.81bdce1fda8bp-58},
|
||||
{0x1.fdfffd50f8689p-1, 0x1.7f91acb918e6ep-55},
|
||||
{0x1.0200004292367p+0, 0x1.b7ff365324681p-54},
|
||||
{0x1.05fffe3e3d668p+0, 0x1.6fa08ddae957bp-55},
|
||||
{0x1.0a0000a85a757p+0, -0x1.7e2de80d3fb91p-58},
|
||||
{0x1.0e0001a5f3fccp+0, -0x1.1823305c5f014p-54},
|
||||
{0x1.11ffff8afbaf5p+0, -0x1.bfabb6680bac2p-55},
|
||||
{0x1.15fffe54d91adp+0, -0x1.d7f121737e7efp-54},
|
||||
{0x1.1a00011ac36e1p+0, 0x1.c000a0516f5ffp-54},
|
||||
{0x1.1e00019c84248p+0, -0x1.082fbe4da5dap-54},
|
||||
{0x1.220000ffe5e6ep+0, -0x1.8fdd04c9cfb43p-55},
|
||||
{0x1.26000269fd891p+0, 0x1.cfe2a7994d182p-55},
|
||||
{0x1.2a00029a6e6dap+0, -0x1.00273715e8bc5p-56},
|
||||
{0x1.2dfffe0293e39p+0, 0x1.b7c39dab2a6f9p-54},
|
||||
{0x1.31ffff7dcf082p+0, 0x1.df1336edc5254p-56},
|
||||
{0x1.35ffff05a8b6p+0, -0x1.e03564ccd31ebp-54},
|
||||
{0x1.3a0002e0eaeccp+0, 0x1.5f0e74bd3a477p-56},
|
||||
{0x1.3e000043bb236p+0, 0x1.c7dcb149d8833p-54},
|
||||
{0x1.4200002d187ffp+0, 0x1.e08afcf2d3d28p-56},
|
||||
{0x1.460000d387cb1p+0, 0x1.20837856599a6p-55},
|
||||
{0x1.4a00004569f89p+0, -0x1.9fa5c904fbcd2p-55},
|
||||
{0x1.4e000043543f3p+0, -0x1.81125ed175329p-56},
|
||||
{0x1.51fffcc027f0fp+0, 0x1.883d8847754dcp-54},
|
||||
{0x1.55ffffd87b36fp+0, -0x1.709e731d02807p-55},
|
||||
{0x1.59ffff21df7bap+0, 0x1.7f79f68727b02p-55},
|
||||
{0x1.5dfffebfc3481p+0, -0x1.180902e30e93ep-54},
|
||||
},
|
||||
#endif
|
||||
};
|
||||
Vendored
+28
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Arm Limited.
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
#ifndef _LOG2_DATA_H
|
||||
#define _LOG2_DATA_H
|
||||
|
||||
#include <features.h>
|
||||
|
||||
#define LOG2_TABLE_BITS 6
|
||||
#define LOG2_POLY_ORDER 7
|
||||
#define LOG2_POLY1_ORDER 11
|
||||
extern hidden const struct log2_data {
|
||||
double invln2hi;
|
||||
double invln2lo;
|
||||
double poly[LOG2_POLY_ORDER - 1];
|
||||
double poly1[LOG2_POLY1_ORDER - 1];
|
||||
struct {
|
||||
double invc, logc;
|
||||
} tab[1 << LOG2_TABLE_BITS];
|
||||
#if !__FP_FAST_FMA
|
||||
struct {
|
||||
double chi, clo;
|
||||
} tab2[1 << LOG2_TABLE_BITS];
|
||||
#endif
|
||||
} __log2_data;
|
||||
|
||||
#endif
|
||||
Vendored
+34
@@ -0,0 +1,34 @@
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include "libm.h"
|
||||
|
||||
double __cdecl scalbn(double x, int n)
|
||||
{
|
||||
union {double f; uint64_t i;} u;
|
||||
double_t y = x;
|
||||
|
||||
if (n > 1023) {
|
||||
y *= 0x1p1023;
|
||||
n -= 1023;
|
||||
if (n > 1023) {
|
||||
y *= 0x1p1023;
|
||||
n -= 1023;
|
||||
if (n > 1023)
|
||||
n = 1023;
|
||||
}
|
||||
} else if (n < -1022) {
|
||||
/* make sure final n < -53 to avoid double
|
||||
rounding in the subnormal range */
|
||||
y *= 0x1p-1022 * 0x1p53;
|
||||
n += 1022 - 53;
|
||||
if (n < -1022) {
|
||||
y *= 0x1p-1022 * 0x1p53;
|
||||
n += 1022 - 53;
|
||||
if (n < -1022)
|
||||
n = -1022;
|
||||
}
|
||||
}
|
||||
u.i = (uint64_t)(0x3ff+n)<<52;
|
||||
x = y * u.f;
|
||||
return x;
|
||||
}
|
||||
Vendored
+80
@@ -0,0 +1,80 @@
|
||||
/* origin: FreeBSD /usr/src/lib/msun/src/s_sin.c */
|
||||
/*
|
||||
* ====================================================
|
||||
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
||||
*
|
||||
* Developed at SunPro, a Sun Microsystems, Inc. business.
|
||||
* Permission to use, copy, modify, and distribute this
|
||||
* software is freely granted, provided that this notice
|
||||
* is preserved.
|
||||
* ====================================================
|
||||
*/
|
||||
/* sin(x)
|
||||
* Return sine function of x.
|
||||
*
|
||||
* kernel function:
|
||||
* __sin ... sine function on [-pi/4,pi/4]
|
||||
* __cos ... cose function on [-pi/4,pi/4]
|
||||
* __rem_pio2 ... argument reduction routine
|
||||
*
|
||||
* Method.
|
||||
* Let S,C and T denote the sin, cos and tan respectively on
|
||||
* [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2
|
||||
* in [-pi/4 , +pi/4], and let n = k mod 4.
|
||||
* We have
|
||||
*
|
||||
* n sin(x) cos(x) tan(x)
|
||||
* ----------------------------------------------------------
|
||||
* 0 S C T
|
||||
* 1 C -S -1/T
|
||||
* 2 -S -C T
|
||||
* 3 -C S -1/T
|
||||
* ----------------------------------------------------------
|
||||
*
|
||||
* Special cases:
|
||||
* Let trig be any of sin, cos, or tan.
|
||||
* trig(+-INF) is NaN, with signals;
|
||||
* trig(NaN) is that NaN;
|
||||
*
|
||||
* Accuracy:
|
||||
* TRIG(x) returns trig(x) nearly rounded
|
||||
*/
|
||||
|
||||
#include "libm.h"
|
||||
|
||||
double __cdecl sin(double x)
|
||||
{
|
||||
double y[2];
|
||||
uint32_t ix;
|
||||
unsigned n;
|
||||
|
||||
/* High word of x. */
|
||||
GET_HIGH_WORD(ix, x);
|
||||
ix &= 0x7fffffff;
|
||||
|
||||
/* |x| ~< pi/4 */
|
||||
if (ix <= 0x3fe921fb) {
|
||||
if (ix < 0x3e500000) { /* |x| < 2**-26 */
|
||||
/* raise inexact if x != 0 and underflow if subnormal*/
|
||||
FORCE_EVAL(ix < 0x00100000 ? x/0x1p120f : x+0x1p120f);
|
||||
return x;
|
||||
}
|
||||
return __sin(x, 0.0, 0);
|
||||
}
|
||||
|
||||
/* sin(Inf or NaN) is NaN */
|
||||
if (isinf(x))
|
||||
return math_error(_DOMAIN, "sin", x, 0, x - x);
|
||||
if (ix >= 0x7ff00000)
|
||||
return x - x;
|
||||
|
||||
/* argument reduction needed */
|
||||
n = __rem_pio2(x, y);
|
||||
switch (n&3) {
|
||||
case 0: return __sin(y[0], y[1], 1);
|
||||
case 1: return __cos(y[0], y[1]);
|
||||
case 2: return -__sin(y[0], y[1], 1);
|
||||
default:
|
||||
return -__cos(y[0], y[1]);
|
||||
}
|
||||
}
|
||||
Vendored
+69
@@ -0,0 +1,69 @@
|
||||
/* origin: FreeBSD /usr/src/lib/msun/src/s_sin.c */
|
||||
/*
|
||||
* ====================================================
|
||||
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
||||
*
|
||||
* Developed at SunPro, a Sun Microsystems, Inc. business.
|
||||
* Permission to use, copy, modify, and distribute this
|
||||
* software is freely granted, provided that this notice
|
||||
* is preserved.
|
||||
* ====================================================
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include "libm.h"
|
||||
|
||||
void __cdecl sincos(double x, double *sin, double *cos)
|
||||
{
|
||||
double y[2], s, c;
|
||||
uint32_t ix;
|
||||
unsigned n;
|
||||
|
||||
GET_HIGH_WORD(ix, x);
|
||||
ix &= 0x7fffffff;
|
||||
|
||||
/* |x| ~< pi/4 */
|
||||
if (ix <= 0x3fe921fb) {
|
||||
/* if |x| < 2**-27 * sqrt(2) */
|
||||
if (ix < 0x3e46a09e) {
|
||||
/* raise inexact if x!=0 and underflow if subnormal */
|
||||
FORCE_EVAL(ix < 0x00100000 ? x/0x1p120f : x+0x1p120f);
|
||||
*sin = x;
|
||||
*cos = 1.0;
|
||||
return;
|
||||
}
|
||||
*sin = __sin(x, 0.0, 0);
|
||||
*cos = __cos(x, 0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* sincos(Inf or NaN) is NaN */
|
||||
if (ix >= 0x7ff00000) {
|
||||
*sin = *cos = x - x;
|
||||
return;
|
||||
}
|
||||
|
||||
/* argument reduction needed */
|
||||
n = __rem_pio2(x, y);
|
||||
s = __sin(y[0], y[1], 1);
|
||||
c = __cos(y[0], y[1]);
|
||||
switch (n&3) {
|
||||
case 0:
|
||||
*sin = s;
|
||||
*cos = c;
|
||||
break;
|
||||
case 1:
|
||||
*sin = c;
|
||||
*cos = -s;
|
||||
break;
|
||||
case 2:
|
||||
*sin = -s;
|
||||
*cos = -c;
|
||||
break;
|
||||
case 3:
|
||||
default:
|
||||
*sin = -c;
|
||||
*cos = s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Vendored
+158
@@ -0,0 +1,158 @@
|
||||
#include <stdint.h>
|
||||
#include <math.h>
|
||||
#include "libm.h"
|
||||
#include "sqrt_data.h"
|
||||
|
||||
#define FENV_SUPPORT 1
|
||||
|
||||
/* returns a*b*2^-32 - e, with error 0 <= e < 1. */
|
||||
static inline uint32_t mul32(uint32_t a, uint32_t b)
|
||||
{
|
||||
return (uint64_t)a*b >> 32;
|
||||
}
|
||||
|
||||
/* returns a*b*2^-64 - e, with error 0 <= e < 3. */
|
||||
static inline uint64_t mul64(uint64_t a, uint64_t b)
|
||||
{
|
||||
uint64_t ahi = a>>32;
|
||||
uint64_t alo = a&0xffffffff;
|
||||
uint64_t bhi = b>>32;
|
||||
uint64_t blo = b&0xffffffff;
|
||||
return ahi*bhi + (ahi*blo >> 32) + (alo*bhi >> 32);
|
||||
}
|
||||
|
||||
double __cdecl sqrt(double x)
|
||||
{
|
||||
uint64_t ix, top, m;
|
||||
|
||||
/* special case handling. */
|
||||
ix = asuint64(x);
|
||||
top = ix >> 52;
|
||||
if (predict_false(top - 0x001 >= 0x7ff - 0x001)) {
|
||||
/* x < 0x1p-1022 or inf or nan. */
|
||||
if (ix * 2 == 0)
|
||||
return x;
|
||||
if (ix == 0x7ff0000000000000)
|
||||
return x;
|
||||
if (ix > 0x7ff0000000000000)
|
||||
return math_error(_DOMAIN, "sqrt", x, 0, (x - x) / (x - x));
|
||||
/* x is subnormal, normalize it. */
|
||||
ix = asuint64(x * 0x1p52);
|
||||
top = ix >> 52;
|
||||
top -= 52;
|
||||
}
|
||||
|
||||
/* argument reduction:
|
||||
x = 4^e m; with integer e, and m in [1, 4)
|
||||
m: fixed point representation [2.62]
|
||||
2^e is the exponent part of the result. */
|
||||
int even = top & 1;
|
||||
m = (ix << 11) | 0x8000000000000000;
|
||||
if (even) m >>= 1;
|
||||
top = (top + 0x3ff) >> 1;
|
||||
|
||||
/* approximate r ~ 1/sqrt(m) and s ~ sqrt(m) when m in [1,4)
|
||||
|
||||
initial estimate:
|
||||
7bit table lookup (1bit exponent and 6bit significand).
|
||||
|
||||
iterative approximation:
|
||||
using 2 goldschmidt iterations with 32bit int arithmetics
|
||||
and a final iteration with 64bit int arithmetics.
|
||||
|
||||
details:
|
||||
|
||||
the relative error (e = r0 sqrt(m)-1) of a linear estimate
|
||||
(r0 = a m + b) is |e| < 0.085955 ~ 0x1.6p-4 at best,
|
||||
a table lookup is faster and needs one less iteration
|
||||
6 bit lookup table (128b) gives |e| < 0x1.f9p-8
|
||||
7 bit lookup table (256b) gives |e| < 0x1.fdp-9
|
||||
for single and double prec 6bit is enough but for quad
|
||||
prec 7bit is needed (or modified iterations). to avoid
|
||||
one more iteration >=13bit table would be needed (16k).
|
||||
|
||||
a newton-raphson iteration for r is
|
||||
w = r*r
|
||||
u = 3 - m*w
|
||||
r = r*u/2
|
||||
can use a goldschmidt iteration for s at the end or
|
||||
s = m*r
|
||||
|
||||
first goldschmidt iteration is
|
||||
s = m*r
|
||||
u = 3 - s*r
|
||||
r = r*u/2
|
||||
s = s*u/2
|
||||
next goldschmidt iteration is
|
||||
u = 3 - s*r
|
||||
r = r*u/2
|
||||
s = s*u/2
|
||||
and at the end r is not computed only s.
|
||||
|
||||
they use the same amount of operations and converge at the
|
||||
same quadratic rate, i.e. if
|
||||
r1 sqrt(m) - 1 = e, then
|
||||
r2 sqrt(m) - 1 = -3/2 e^2 - 1/2 e^3
|
||||
the advantage of goldschmidt is that the mul for s and r
|
||||
are independent (computed in parallel), however it is not
|
||||
"self synchronizing": it only uses the input m in the
|
||||
first iteration so rounding errors accumulate. at the end
|
||||
or when switching to larger precision arithmetics rounding
|
||||
errors dominate so the first iteration should be used.
|
||||
|
||||
the fixed point representations are
|
||||
m: 2.30 r: 0.32, s: 2.30, d: 2.30, u: 2.30, three: 2.30
|
||||
and after switching to 64 bit
|
||||
m: 2.62 r: 0.64, s: 2.62, d: 2.62, u: 2.62, three: 2.62 */
|
||||
|
||||
static const uint64_t three = 0xc0000000;
|
||||
uint64_t r, s, d, u, i;
|
||||
|
||||
i = (ix >> 46) % 128;
|
||||
r = (uint32_t)__rsqrt_tab[i] << 16;
|
||||
/* |r sqrt(m) - 1| < 0x1.fdp-9 */
|
||||
s = mul32(m>>32, r);
|
||||
/* |s/sqrt(m) - 1| < 0x1.fdp-9 */
|
||||
d = mul32(s, r);
|
||||
u = three - d;
|
||||
r = mul32(r, u) << 1;
|
||||
/* |r sqrt(m) - 1| < 0x1.7bp-16 */
|
||||
s = mul32(s, u) << 1;
|
||||
/* |s/sqrt(m) - 1| < 0x1.7bp-16 */
|
||||
d = mul32(s, r);
|
||||
u = three - d;
|
||||
r = mul32(r, u) << 1;
|
||||
/* |r sqrt(m) - 1| < 0x1.3704p-29 (measured worst-case) */
|
||||
r = r << 32;
|
||||
s = mul64(m, r);
|
||||
d = mul64(s, r);
|
||||
u = (three<<32) - d;
|
||||
s = mul64(s, u); /* repr: 3.61 */
|
||||
/* -0x1p-57 < s - sqrt(m) < 0x1.8001p-61 */
|
||||
s = (s - 2) >> 9; /* repr: 12.52 */
|
||||
/* -0x1.09p-52 < s - sqrt(m) < -0x1.fffcp-63 */
|
||||
|
||||
/* s < sqrt(m) < s + 0x1.09p-52,
|
||||
compute nearest rounded result:
|
||||
the nearest result to 52 bits is either s or s+0x1p-52,
|
||||
we can decide by comparing (2^52 s + 0.5)^2 to 2^104 m. */
|
||||
uint64_t d0, d1, d2;
|
||||
double y, t;
|
||||
d0 = (m << 42) - s*s;
|
||||
d1 = s - d0;
|
||||
d2 = d1 + s + 1;
|
||||
s += d1 >> 63;
|
||||
s &= 0x000fffffffffffff;
|
||||
s |= top << 52;
|
||||
y = asdouble(s);
|
||||
if (FENV_SUPPORT) {
|
||||
/* handle rounding modes and inexact exception:
|
||||
only (s+1)^2 == 2^42 m case is exact otherwise
|
||||
add a tiny value to cause the fenv effects. */
|
||||
uint64_t tiny = predict_false(d2==0) ? 0 : 0x0010000000000000;
|
||||
tiny |= (d1^d2) & 0x8000000000000000;
|
||||
t = asdouble(tiny);
|
||||
y = eval_as_double(y + t);
|
||||
}
|
||||
return y;
|
||||
}
|
||||
Vendored
+19
@@ -0,0 +1,19 @@
|
||||
#include "sqrt_data.h"
|
||||
const uint16_t __rsqrt_tab[128] = {
|
||||
0xb451,0xb2f0,0xb196,0xb044,0xaef9,0xadb6,0xac79,0xab43,
|
||||
0xaa14,0xa8eb,0xa7c8,0xa6aa,0xa592,0xa480,0xa373,0xa26b,
|
||||
0xa168,0xa06a,0x9f70,0x9e7b,0x9d8a,0x9c9d,0x9bb5,0x9ad1,
|
||||
0x99f0,0x9913,0x983a,0x9765,0x9693,0x95c4,0x94f8,0x9430,
|
||||
0x936b,0x92a9,0x91ea,0x912e,0x9075,0x8fbe,0x8f0a,0x8e59,
|
||||
0x8daa,0x8cfe,0x8c54,0x8bac,0x8b07,0x8a64,0x89c4,0x8925,
|
||||
0x8889,0x87ee,0x8756,0x86c0,0x862b,0x8599,0x8508,0x8479,
|
||||
0x83ec,0x8361,0x82d8,0x8250,0x81c9,0x8145,0x80c2,0x8040,
|
||||
0xff02,0xfd0e,0xfb25,0xf947,0xf773,0xf5aa,0xf3ea,0xf234,
|
||||
0xf087,0xeee3,0xed47,0xebb3,0xea27,0xe8a3,0xe727,0xe5b2,
|
||||
0xe443,0xe2dc,0xe17a,0xe020,0xdecb,0xdd7d,0xdc34,0xdaf1,
|
||||
0xd9b3,0xd87b,0xd748,0xd61a,0xd4f1,0xd3cd,0xd2ad,0xd192,
|
||||
0xd07b,0xcf69,0xce5b,0xcd51,0xcc4a,0xcb48,0xca4a,0xc94f,
|
||||
0xc858,0xc764,0xc674,0xc587,0xc49d,0xc3b7,0xc2d4,0xc1f4,
|
||||
0xc116,0xc03c,0xbf65,0xbe90,0xbdbe,0xbcef,0xbc23,0xbb59,
|
||||
0xba91,0xb9cc,0xb90a,0xb84a,0xb78c,0xb6d0,0xb617,0xb560,
|
||||
};
|
||||
Vendored
+13
@@ -0,0 +1,13 @@
|
||||
#ifndef _SQRT_DATA_H
|
||||
#define _SQRT_DATA_H
|
||||
|
||||
#include <features.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* if x in [1,2): i = (int)(64*x);
|
||||
if x in [2,4): i = (int)(32*x-64);
|
||||
__rsqrt_tab[i]*2^-16 is estimating 1/sqrt(x) with small relative error:
|
||||
|__rsqrt_tab[i]*0x1p-16*sqrt(x) - 1| < -0x1.fdp-9 < 2^-8 */
|
||||
extern hidden const uint16_t __rsqrt_tab[128];
|
||||
|
||||
#endif
|
||||
Vendored
+83
@@ -0,0 +1,83 @@
|
||||
#include <stdint.h>
|
||||
#include <math.h>
|
||||
#include "libm.h"
|
||||
#include "sqrt_data.h"
|
||||
|
||||
#define FENV_SUPPORT 1
|
||||
|
||||
static inline uint32_t mul32(uint32_t a, uint32_t b)
|
||||
{
|
||||
return (uint64_t)a*b >> 32;
|
||||
}
|
||||
|
||||
/* see sqrt.c for more detailed comments. */
|
||||
|
||||
float __cdecl sqrtf(float x)
|
||||
{
|
||||
uint32_t ix, m, m1, m0, even, ey;
|
||||
|
||||
ix = asuint(x);
|
||||
if (predict_false(ix - 0x00800000 >= 0x7f800000 - 0x00800000)) {
|
||||
/* x < 0x1p-126 or inf or nan. */
|
||||
if (ix * 2 == 0)
|
||||
return x;
|
||||
if (ix == 0x7f800000)
|
||||
return x;
|
||||
if (ix > 0x7f800000)
|
||||
return math_error(_DOMAIN, "sqrtf", x, 0, (x - x) / (x - x));
|
||||
/* x is subnormal, normalize it. */
|
||||
ix = asuint(x * 0x1p23f);
|
||||
ix -= 23 << 23;
|
||||
}
|
||||
|
||||
/* x = 4^e m; with int e and m in [1, 4). */
|
||||
even = ix & 0x00800000;
|
||||
m1 = (ix << 8) | 0x80000000;
|
||||
m0 = (ix << 7) & 0x7fffffff;
|
||||
m = even ? m0 : m1;
|
||||
|
||||
/* 2^e is the exponent part of the return value. */
|
||||
ey = ix >> 1;
|
||||
ey += 0x3f800000 >> 1;
|
||||
ey &= 0x7f800000;
|
||||
|
||||
/* compute r ~ 1/sqrt(m), s ~ sqrt(m) with 2 goldschmidt iterations. */
|
||||
static const uint32_t three = 0xc0000000;
|
||||
uint32_t r, s, d, u, i;
|
||||
i = (ix >> 17) % 128;
|
||||
r = (uint32_t)__rsqrt_tab[i] << 16;
|
||||
/* |r*sqrt(m) - 1| < 0x1p-8 */
|
||||
s = mul32(m, r);
|
||||
/* |s/sqrt(m) - 1| < 0x1p-8 */
|
||||
d = mul32(s, r);
|
||||
u = three - d;
|
||||
r = mul32(r, u) << 1;
|
||||
/* |r*sqrt(m) - 1| < 0x1.7bp-16 */
|
||||
s = mul32(s, u) << 1;
|
||||
/* |s/sqrt(m) - 1| < 0x1.7bp-16 */
|
||||
d = mul32(s, r);
|
||||
u = three - d;
|
||||
s = mul32(s, u);
|
||||
/* -0x1.03p-28 < s/sqrt(m) - 1 < 0x1.fp-31 */
|
||||
s = (s - 1)>>6;
|
||||
/* s < sqrt(m) < s + 0x1.08p-23 */
|
||||
|
||||
/* compute nearest rounded result. */
|
||||
uint32_t d0, d1, d2;
|
||||
float y, t;
|
||||
d0 = (m << 16) - s*s;
|
||||
d1 = s - d0;
|
||||
d2 = d1 + s + 1;
|
||||
s += d1 >> 31;
|
||||
s &= 0x007fffff;
|
||||
s |= ey;
|
||||
y = asfloat(s);
|
||||
if (FENV_SUPPORT) {
|
||||
/* handle rounding and inexact exception. */
|
||||
uint32_t tiny = predict_false(d2==0) ? 0 : 0x01000000;
|
||||
tiny |= (d1^d2) & 0x80000000;
|
||||
t = asfloat(tiny);
|
||||
y = eval_as_float(y + t);
|
||||
}
|
||||
return y;
|
||||
}
|
||||
+1
-1
@@ -1770,7 +1770,7 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
file.write("#if {k}\n".format(k=k))
|
||||
for signature in gbls[k]:
|
||||
sig = signature if signature[2] != "E" else (signature[:2]+signature[3:])
|
||||
if any(letter in sig[2:] for letter in "OSNxXYb") or signature.endswith('FE'):
|
||||
if any(letter in sig[2:] for letter in "OSNHxXYb") or signature.endswith('FE') or signature[1] == 'W':
|
||||
continue
|
||||
formats = sig[2:].replace("G", "UU")
|
||||
params = '' if formats == "v" else ", " + function_args_systemV(FunctionType(formats))[:-2]
|
||||
|
||||
@@ -874,6 +874,8 @@ def readFiles(files: Iterable[str]) -> Tuple[JumbledFunctions, JumbledFunctions,
|
||||
or match("gstinterfaces010","gstaudio")\
|
||||
or match("gstreamer010","gstreamer") \
|
||||
or match("appindicator","appindicator3")\
|
||||
or match("libgl", "libegl") \
|
||||
or match("libgl", "libglx") \
|
||||
\
|
||||
or match("libc", "tcmallocminimal") \
|
||||
or match("libc", "ldlinux") \
|
||||
|
||||
@@ -17,13 +17,6 @@ endif()
|
||||
|
||||
set(ENV{BOX64_LOG} 0)
|
||||
set(ENV{BOX64_NOBANNER} 1)
|
||||
if( EXISTS ${CMAKE_SOURCE_DIR}/x64lib )
|
||||
# we are inside box64 folder
|
||||
set(ENV{BOX64_LD_LIBRARY_PATH} ${CMAKE_SOURCE_DIR}/x64lib)
|
||||
else()
|
||||
# we are inside build folder
|
||||
set(ENV{BOX64_LD_LIBRARY_PATH} ${CMAKE_SOURCE_DIR}/../x64lib)
|
||||
endif( EXISTS ${CMAKE_SOURCE_DIR}/x64lib )
|
||||
|
||||
# run the test program, capture the stdout/stderr and the result var
|
||||
execute_process(
|
||||
|
||||
+4
-35
@@ -7,6 +7,7 @@
|
||||
#include <sys/mman.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "os.h"
|
||||
#include "box64context.h"
|
||||
#include "debug.h"
|
||||
#include "elfloader.h"
|
||||
@@ -14,6 +15,7 @@
|
||||
#include "threads.h"
|
||||
#include "x64trace.h"
|
||||
#include "bridge.h"
|
||||
#include "alternate.h"
|
||||
#include "librarian.h"
|
||||
#include "library.h"
|
||||
#include "wrapper.h"
|
||||
@@ -21,7 +23,7 @@
|
||||
#include "signals.h"
|
||||
#include "gltools.h"
|
||||
#include "rbtree.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#ifdef BOX32
|
||||
#include "box32.h"
|
||||
#endif
|
||||
@@ -84,39 +86,6 @@ void free_tlsdatasize(void* p)
|
||||
void x64Syscall(x64emu_t *emu);
|
||||
void x86Syscall(x64emu_t *emu);
|
||||
|
||||
int unlockMutex()
|
||||
{
|
||||
int ret = unlockCustommemMutex();
|
||||
int i;
|
||||
#ifdef USE_CUSTOM_MUTEX
|
||||
uint32_t tid = (uint32_t)GetTID();
|
||||
#define GO(A, B) \
|
||||
i = (native_lock_storeifref2_d(&A, 0, tid)==tid); \
|
||||
if(i) { \
|
||||
ret|=(1<<B); \
|
||||
}
|
||||
#else
|
||||
#define GO(A, B) \
|
||||
i = checkUnlockMutex(&A); \
|
||||
if(i) { \
|
||||
ret|=(1<<B); \
|
||||
}
|
||||
#endif
|
||||
|
||||
GO(my_context->mutex_trace, 7)
|
||||
#ifdef DYNAREC
|
||||
GO(my_context->mutex_dyndump, 8)
|
||||
#else
|
||||
GO(my_context->mutex_lock, 8)
|
||||
#endif
|
||||
GO(my_context->mutex_tls, 9)
|
||||
GO(my_context->mutex_thread, 10)
|
||||
GO(my_context->mutex_bridge, 11)
|
||||
#undef GO
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void relockMutex(int locks)
|
||||
{
|
||||
relockCustommemMutex(locks);
|
||||
@@ -192,7 +161,7 @@ void freeCycleLog(box64context_t* ctx)
|
||||
}
|
||||
void initCycleLog(box64context_t* context)
|
||||
{
|
||||
if(BOX64ENV(rolling_log)) {
|
||||
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) {
|
||||
|
||||
+1
-1
@@ -3,6 +3,6 @@
|
||||
|
||||
#define BOX64_MAJOR 0
|
||||
#define BOX64_MINOR 3
|
||||
#define BOX64_REVISION 4
|
||||
#define BOX64_REVISION 6
|
||||
|
||||
#endif //__BOX64_VERSION_H_
|
||||
+15
-17
@@ -1,27 +1,25 @@
|
||||
#include <stdio.h>
|
||||
#include "debug.h"
|
||||
#include "box64version.h"
|
||||
#ifdef NOGIT
|
||||
#define GITREV "nogit"
|
||||
#include "build_info.h"
|
||||
|
||||
#if defined(DYNAREC)
|
||||
#define WITH_DYNAREC_STR " with Dynarec"
|
||||
#else
|
||||
#include "git_head.h"
|
||||
#define WITH_DYNAREC_STR ""
|
||||
#endif
|
||||
|
||||
void PrintBox64Version()
|
||||
#ifdef HAVE_TRACE
|
||||
#define WITH_TRACE_STR " with trace"
|
||||
#else
|
||||
#define WITH_TRACE_STR ""
|
||||
#endif
|
||||
|
||||
void PrintBox64Version(int prefix)
|
||||
{
|
||||
printf_ftrace(1, "Box64%s%s v%d.%d.%d %s built on %s %s\n",
|
||||
#ifdef HAVE_TRACE
|
||||
" with trace",
|
||||
#else
|
||||
"",
|
||||
#endif
|
||||
#ifdef DYNAREC
|
||||
" with Dynarec",
|
||||
#else
|
||||
"",
|
||||
#endif
|
||||
BOX64_MAJOR, BOX64_MINOR, BOX64_REVISION,
|
||||
GITREV,
|
||||
PrintfFtrace(prefix, BOX64_BUILD_INFO_STRING WITH_DYNAREC_STR WITH_TRACE_STR " built on %s %s\n",
|
||||
__DATE__, __TIME__);
|
||||
}
|
||||
|
||||
#undef WITH_TRACE
|
||||
#undef WITH_DYNAREC
|
||||
+24
-6
@@ -8,14 +8,32 @@
|
||||
#ifndef __BUILD_INFO_H__
|
||||
#define __BUILD_INFO_H__
|
||||
|
||||
void PrintBox64Version(void);
|
||||
|
||||
#if defined(DYNAREC) && (defined(ARM64) || defined(RV64) || defined(LA64))
|
||||
#if defined(ARM64)
|
||||
#define ARCH_STR " arm64"
|
||||
#elif defined(RV64)
|
||||
#define ARCH_STR " riscv64"
|
||||
#elif defined(LA64)
|
||||
#define ARCH_STR " loongarch64"
|
||||
#endif
|
||||
#else
|
||||
#define ARCH_STR ""
|
||||
#endif
|
||||
|
||||
void PrintBox64Version(int prefix);
|
||||
|
||||
#define BOX64_BUILD_INFO_STR_HELPER(x) #x
|
||||
#define BOX64_BUILD_INFO_STR(x) BOX64_BUILD_INFO_STR_HELPER(x)
|
||||
|
||||
#define BOX64_BUILD_INFO_STRING \
|
||||
"Box64" \
|
||||
" v" BOX64_BUILD_INFO_STR(BOX64_MAJOR) "." BOX64_BUILD_INFO_STR(BOX64_MINOR) "." BOX64_BUILD_INFO_STR(BOX64_REVISION) \
|
||||
" " GITREV
|
||||
#ifdef _WIN32
|
||||
#define BOX64_STR "WowBox64"
|
||||
#else
|
||||
#define BOX64_STR "Box64"
|
||||
#endif
|
||||
|
||||
#endif //__BUILD_INFO_H__
|
||||
#define BOX64_BUILD_INFO_STRING \
|
||||
BOX64_STR ARCH_STR \
|
||||
" v" BOX64_BUILD_INFO_STR(BOX64_MAJOR) "." BOX64_BUILD_INFO_STR(BOX64_MINOR) "." BOX64_BUILD_INFO_STR(BOX64_REVISION) " " GITREV
|
||||
|
||||
#endif //__BUILD_INFO_H__
|
||||
+89
-43
@@ -12,7 +12,9 @@
|
||||
#include <sys/mman.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdarg.h>
|
||||
#include <ctype.h>
|
||||
#ifdef DYNAREC
|
||||
#ifdef ARM64
|
||||
#include <linux/auxvec.h>
|
||||
@@ -23,26 +25,30 @@
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#include "os.h"
|
||||
#include "build_info.h"
|
||||
#include "debug.h"
|
||||
#include "fileutils.h"
|
||||
#include "box64context.h"
|
||||
#include "box64cpu.h"
|
||||
#include "box64cpu_util.h"
|
||||
#include "wine_tools.h"
|
||||
#include "elfloader.h"
|
||||
#include "custommem.h"
|
||||
#include "box64stack.h"
|
||||
#include "auxval.h"
|
||||
#include "x64emu.h"
|
||||
#include "threads.h"
|
||||
#include "x64trace.h"
|
||||
#include "librarian.h"
|
||||
#include "x64run.h"
|
||||
#include "symbols.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "elfs/elfloader_private.h"
|
||||
#include "x64emu.h"
|
||||
#include "library.h"
|
||||
#include "core.h"
|
||||
#include "env.h"
|
||||
#include "cleanup.h"
|
||||
#include "freq.h"
|
||||
|
||||
box64context_t *my_context = NULL;
|
||||
extern box64env_t box64env;
|
||||
@@ -182,39 +188,12 @@ void openFTrace(int reopen)
|
||||
printf("BOX64 Trace %s to \"%s\"\n", append?"appended":"redirected", p);
|
||||
box64_stdout_no_w = 1;
|
||||
}
|
||||
PrintBox64Version();
|
||||
PrintBox64Version(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void printf_ftrace(int prefix, const char* fmt, ...)
|
||||
{
|
||||
if(ftrace_name) {
|
||||
int fd = fileno(ftrace);
|
||||
if(fd<0 || lseek(fd, 0, SEEK_CUR)==(off_t)-1) {
|
||||
ftrace=fopen(ftrace_name, "a");
|
||||
printf_log(LOG_INFO, "%04d|Recreated trace because fd was invalid\n", GetTID());
|
||||
}
|
||||
}
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
if (prefix && ftrace == stdout) {
|
||||
if (prefix > 1) {
|
||||
fprintf(ftrace, "[\033[31m%s\033[0m] ",
|
||||
box64_is32bits ? "BOX32" : "BOX64");
|
||||
} else {
|
||||
fprintf(ftrace, box64_is32bits ? "[BOX32] " : "[BOX64] ");
|
||||
}
|
||||
}
|
||||
vfprintf(ftrace, fmt, args);
|
||||
|
||||
fflush(ftrace);
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void my_prepare_fork()
|
||||
{
|
||||
if (ftrace_has_pid && ftrace && (ftrace != stdout) && (ftrace != stderr)) {
|
||||
@@ -566,11 +545,69 @@ void AddNewLibs(const char* list)
|
||||
}
|
||||
|
||||
void PrintHelp() {
|
||||
printf_ftrace(1, "This is Box64, the Linux x86_64 emulator with a twist.\n");
|
||||
printf_ftrace(1, "Usage is 'box64 [options] path/to/software [args]' to launch x86_64 software.\n");
|
||||
printf_ftrace(1, " options are:\n");
|
||||
printf_ftrace(1, " '-v'|'--version' to print box64 version and quit\n");
|
||||
printf_ftrace(1, " '-h'|'--help' to print this and quit\n");
|
||||
PrintfFtrace(0, "This is Box64, the Linux x86_64 emulator with a twist.\n");
|
||||
PrintfFtrace(0, "Usage is 'box64 [options] path/to/software [args]' to launch x86_64 software.\n");
|
||||
PrintfFtrace(0, " options are:\n");
|
||||
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");
|
||||
}
|
||||
|
||||
void KillAllInstances()
|
||||
{
|
||||
|
||||
struct dirent* entry;
|
||||
ssize_t len;
|
||||
char proc_path[PATH_MAX];
|
||||
char exe_path[PATH_MAX];
|
||||
char exe_target[PATH_MAX];
|
||||
char self_name[PATH_MAX];
|
||||
char self_name_with_deleted[PATH_MAX];
|
||||
|
||||
DIR* proc_dir = opendir("/proc");
|
||||
if (proc_dir == NULL) {
|
||||
perror("opendir(/proc)");
|
||||
return;
|
||||
}
|
||||
|
||||
ssize_t self_len = readlink("/proc/self/exe", exe_path, sizeof(exe_path) - 1);
|
||||
if (self_len == -1) {
|
||||
perror("readlink(/proc/self/exe)");
|
||||
closedir(proc_dir);
|
||||
return;
|
||||
}
|
||||
exe_path[self_len] = '\0';
|
||||
|
||||
char* base_name_self = strrchr(exe_path, '/');
|
||||
base_name_self = base_name_self ? base_name_self + 1 : exe_path;
|
||||
strncpy(self_name, base_name_self, sizeof(self_name));
|
||||
self_name[sizeof(self_name) - 1] = '\0';
|
||||
|
||||
snprintf(self_name_with_deleted, sizeof(self_name_with_deleted), "%s (deleted)", self_name);
|
||||
|
||||
const pid_t self = getpid();
|
||||
while (entry = readdir(proc_dir)) {
|
||||
const pid_t pid = atoi(entry->d_name);
|
||||
if (!pid || pid == self) continue;
|
||||
|
||||
snprintf(proc_path, sizeof(proc_path), "/proc/%s", entry->d_name);
|
||||
struct stat statbuf;
|
||||
if (stat(proc_path, &statbuf) == -1 || !S_ISDIR(statbuf.st_mode)) continue;
|
||||
snprintf(exe_path, sizeof(exe_path), "%s/exe", proc_path);
|
||||
ssize_t len = readlink(exe_path, exe_target, sizeof(exe_target) - 1);
|
||||
if (len == -1) continue;
|
||||
exe_target[len] = '\0';
|
||||
char* base_name = strrchr(exe_target, '/');
|
||||
base_name = base_name ? base_name + 1 : exe_target;
|
||||
if (strcmp(base_name, self_name) != 0 && strcmp(base_name, self_name_with_deleted) != 0) continue;
|
||||
|
||||
if (!kill(pid, SIGKILL)) {
|
||||
printf_log(LOG_INFO, "Killed box64 process %d\n", pid);
|
||||
} else {
|
||||
printf_log(LOG_INFO, "Failed to kill box64 process %d: %s\n", pid, strerror(errno));
|
||||
}
|
||||
}
|
||||
closedir(proc_dir);
|
||||
}
|
||||
|
||||
static void addLibPaths(box64context_t* context)
|
||||
@@ -891,12 +928,12 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
|
||||
init_auxval(argc, argv, environ?environ:env);
|
||||
// analogue to QEMU_VERSION in qemu-user-mode emulation
|
||||
if(getenv("BOX64_VERSION")) {
|
||||
PrintBox64Version();
|
||||
PrintBox64Version(0);
|
||||
exit(0);
|
||||
}
|
||||
// trying to open and load 1st arg
|
||||
if(argc==1) {
|
||||
/*PrintBox64Version();
|
||||
/*PrintBox64Version(1);
|
||||
PrintHelp();
|
||||
return 1;*/
|
||||
printf("[BOX64] Missing operand after 'box64'\n");
|
||||
@@ -917,27 +954,28 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
|
||||
LoadEnvVariables();
|
||||
InitializeEnvFiles();
|
||||
|
||||
if (!BOX64ENV(nobanner)) PrintBox64Version();
|
||||
|
||||
|
||||
const char* prog = argv[1];
|
||||
int nextarg = 1;
|
||||
// check if some options are passed
|
||||
while(prog && prog[0]=='-') {
|
||||
if(!strcmp(prog, "-v") || !strcmp(prog, "--version")) {
|
||||
if (BOX64ENV(nobanner)) PrintBox64Version();
|
||||
PrintBox64Version(0);
|
||||
exit(0);
|
||||
}
|
||||
if(!strcmp(prog, "-h") || !strcmp(prog, "--help")) {
|
||||
PrintHelp();
|
||||
exit(0);
|
||||
}
|
||||
if (!strcmp(prog, "-k") || !strcmp(prog, "--kill-all")) {
|
||||
KillAllInstances();
|
||||
exit(0);
|
||||
}
|
||||
// other options?
|
||||
if(!strcmp(prog, "--")) {
|
||||
prog = argv[++nextarg];
|
||||
break;
|
||||
}
|
||||
printf("Warning, Unrecognized option '%s'\n", prog);
|
||||
printf("Warning, unrecognized option '%s'\n", prog);
|
||||
prog = argv[++nextarg];
|
||||
}
|
||||
if(!prog || nextarg==argc) {
|
||||
@@ -945,6 +983,8 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (!BOX64ENV(nobanner)) PrintBox64Version(1);
|
||||
|
||||
displayMiscInfo();
|
||||
|
||||
hookMangoHud();
|
||||
@@ -1020,6 +1060,12 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
|
||||
// check if it exist
|
||||
if(FileExist(tmp, 0)) {
|
||||
box64_custom_gstreamer = box_strdup(tmp);
|
||||
} else {
|
||||
*pp = '\0';
|
||||
strcat(tmp, "/../lib/x86_64-linux-gnu/gstreamer-1.0");
|
||||
if(FileExist(tmp, 0)) {
|
||||
box64_custom_gstreamer = box_strdup(tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Try to get the name of the exe being run, to ApplyEnvFileEntry laters
|
||||
@@ -1475,7 +1521,7 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
|
||||
if(!ElfGetGlobalSymbolStartEnd(elf_header, &wineinfo, NULL, "wine_main_preload_info", &ver, &vername, 1, &veropt))
|
||||
if(!ElfGetWeakSymbolStartEnd(elf_header, &wineinfo, NULL, "wine_main_preload_info", &ver, &vername, 1, &veropt))
|
||||
ElfGetLocalSymbolStartEnd(elf_header, &wineinfo, NULL, "wine_main_preload_info", &ver, &vername, 1, &veropt);
|
||||
if(!wineinfo) {printf_log(LOG_NONE, "Warning, Symbol wine_main_preload_info not found\n");}
|
||||
if(!wineinfo) {printf_log(LOG_DEBUG, "Warning, Symbol wine_main_preload_info not found\n");}
|
||||
else {
|
||||
*(void**)wineinfo = get_wine_prereserve();
|
||||
printf_log(LOG_DEBUG, "WINE wine_main_preload_info found and updated %p -> %p\n", get_wine_prereserve(), *(void**)wineinfo);
|
||||
|
||||
+445
-255
File diff suppressed because it is too large.
Load diff
+4
-4
@@ -24,8 +24,8 @@ extern void* mapallmem;
|
||||
extern int box64_is32bits;
|
||||
void setProtection(uintptr_t addr, size_t size, uint32_t prot);
|
||||
void freeProtection(uintptr_t addr, size_t size);
|
||||
void* internal_mmap(void *addr, unsigned long length, int prot, int flags, int fd, ssize_t offset);
|
||||
int internal_munmap(void* addr, unsigned long length);
|
||||
void* InternalMmap(void* addr, unsigned long length, int prot, int flags, int fd, ssize_t offset);
|
||||
int InternalMunmap(void* addr, unsigned long length);
|
||||
void* box_mmap(void *addr, unsigned long length, int prot, int flags, int fd, ssize_t offset);
|
||||
|
||||
void* my_mmap64(x64emu_t* emu, void *addr, unsigned long length, int prot, int flags, int fd, ssize_t offset);
|
||||
@@ -39,7 +39,7 @@ EXPORT void* mmap64(void *addr, unsigned long length, int prot, int flags, int f
|
||||
if(!addr && ((running32bits && BOX64ENV(mmap32)) || (flags&MAP_32BIT) || box64_is32bits))
|
||||
ret = box_mmap(addr, length, prot, flags | MAP_32BIT, fd, offset);
|
||||
else
|
||||
ret = internal_mmap(addr, length, prot, flags, fd, offset);
|
||||
ret = InternalMmap(addr, length, prot, flags, fd, offset);
|
||||
if(ret!=MAP_FAILED && mapallmem)
|
||||
setProtection((uintptr_t)ret, length, prot);
|
||||
return ret;
|
||||
@@ -48,7 +48,7 @@ EXPORT void* mmap(void *addr, unsigned long length, int prot, int flags, int fd,
|
||||
|
||||
EXPORT int munmap(void* addr, unsigned long length)
|
||||
{
|
||||
int ret = internal_munmap(addr, length);
|
||||
int ret = InternalMunmap(addr, length);
|
||||
if(!ret && mapallmem) {
|
||||
freeProtection((uintptr_t)addr, length);
|
||||
}
|
||||
|
||||
@@ -89,7 +89,8 @@ p0-p3 are used to pass scalable predicate arguments to a subroutine and to retur
|
||||
#define x4 4
|
||||
#define x5 5
|
||||
#define x6 6
|
||||
#define x7 7
|
||||
#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
|
||||
@@ -97,7 +98,7 @@ p0-p3 are used to pass scalable predicate arguments to a subroutine and to retur
|
||||
#define w4 x4
|
||||
#define w5 x5
|
||||
#define w6 x6
|
||||
#define w7 x7
|
||||
#define w87pc x87pc
|
||||
// emu is r0
|
||||
#define xEmu 0
|
||||
// ARM64 LR
|
||||
@@ -339,7 +340,7 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#define LDRSW_REGz(Rt, Rn, Rm) EMIT(LDRS_REG_gen(0b10, 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, imm19) EMIT(LDR_PC_gen(0b01, ((imm19)>>2)&0x7FFFF, Rt))
|
||||
#define LDRx_literal(Rt, imm21) EMIT(LDR_PC_gen(0b01, (((int64_t)(imm21))>>2)&0x7FFFF, Rt))
|
||||
|
||||
#define LDU_gen(size, opc, imm9, Rn, Rt) ((size)<<30 | 0b111<<27 | (opc)<<22 | ((imm9)&0x1ff)<<12 | (Rn)<<5 | (Rt))
|
||||
#define LDURx_I9(Rt, Rn, imm9) EMIT(LDU_gen(0b11, 0b01, imm9, Rn, Rt))
|
||||
@@ -908,7 +909,7 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#define FCSELS(Sd, Sn, Sm, cond) EMIT(FCSEL_scalar(0b00, Sm, cond, Sn, Sd))
|
||||
#define FCSELD(Dd, Dn, Dm, cond) EMIT(FCSEL_scalar(0b01, Dm, cond, Dn, Dd))
|
||||
|
||||
// VLDR
|
||||
// VLDR/VSTR
|
||||
#define VMEM_gen(size, opc, imm12, Rn, Rt) ((size)<<30 | 0b111<<27 | 1<<26 | 0b01<<24 | (opc)<<22 | (imm12)<<10 | (Rn)<<5 | (Rt))
|
||||
// imm13 must be 1-aligned
|
||||
#define VLDR16_U12(Ht, Rn, imm13) EMIT(VMEM_gen(0b01, 0b01, ((uint32_t)((imm13)>>1))&0xfff, Rn, Ht))
|
||||
@@ -927,6 +928,15 @@ int convert_bitmask(uint64_t bitmask);
|
||||
// (imm13) must be 1-aligned
|
||||
#define VSTR16_U12(Ht, Rn, imm13) EMIT(VMEM_gen(0b01, 0b00, ((uint32_t)((imm13)>>1))&0xfff, Rn, Ht))
|
||||
|
||||
//VLDP/VSTP
|
||||
#define VMEMP_vector(opc, L, imm7, Rt2, Rn, Rt) ((opc)<<30 | 0b101<<27 | 1<<26 | 0b010<<23 | (L)<<22 | (imm7)<<15 | (Rt2)<<10 | (Rn)<<5 | (Rt))
|
||||
#define VLDP32_I7(Rt1, Rt2, Rn, imm9) EMIT(VMEMP_vector(0b00, 1, (((int64_t)(imm9))>>2)&0x7f, Rt2, Rn, Rt1))
|
||||
#define VLDP64_I7(Rt1, Rt2, Rn, imm10) EMIT(VMEMP_vector(0b01, 1, (((int64_t)(imm10))>>3)&0x7f, Rt2, Rn, Rt1))
|
||||
#define VLDP128_I7(Rt1, Rt2, Rn, imm11) EMIT(VMEMP_vector(0b10, 1, (((int64_t)(imm11))>>4)&0x7f, Rt2, Rn, Rt1))
|
||||
#define VSTP32_I7(Rt1, Rt2, Rn, imm9) EMIT(VMEMP_vector(0b00, 0, (((int64_t)(imm9))>>2)&0x7f, Rt2, Rn, Rt1))
|
||||
#define VSTP64_I7(Rt1, Rt2, Rn, imm10) EMIT(VMEMP_vector(0b01, 0, (((int64_t)(imm10))>>3)&0x7f, Rt2, Rn, Rt1))
|
||||
#define VSTP128_I7(Rt1, Rt2, Rn, imm11) EMIT(VMEMP_vector(0b10, 0, (((int64_t)(imm11))>>4)&0x7f, Rt2, Rn, Rt1))
|
||||
|
||||
#define VMEMUR_vector(size, opc, imm9, Rn, Rt) ((size)<<30 | 0b111<<27 | 1<<26 | (opc)<<22 | (imm9)<<12 | (Rn)<<5 | (Rt))
|
||||
// signed offset, no alignement!
|
||||
#define VLDR8_I9(Vt, Rn, imm9) EMIT(VMEMUR_vector(0b00, 0b01, (imm9)&0b111111111, Rn, Vt))
|
||||
@@ -1569,6 +1579,12 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#define VFMAXQS(Vd, Vn, Vm) EMIT(FMINMAX_vector(1, 0, 0, 0, Vm, Vn, Vd))
|
||||
#define VFMINQD(Vd, Vn, Vm) EMIT(FMINMAX_vector(1, 0, 1, 1, Vm, Vn, Vd))
|
||||
#define VFMAXQD(Vd, Vn, Vm) EMIT(FMINMAX_vector(1, 0, 0, 1, Vm, Vn, Vd))
|
||||
#define VFMINPS(Vd, Vn, Vm) EMIT(FMINMAX_vector(0, 1, 1, 0, Vm, Vn, Vd))
|
||||
#define VFMAXPS(Vd, Vn, Vm) EMIT(FMINMAX_vector(0, 1, 0, 0, Vm, Vn, Vd))
|
||||
#define VFMINPQS(Vd, Vn, Vm) EMIT(FMINMAX_vector(1, 1, 1, 0, Vm, Vn, Vd))
|
||||
#define VFMAXPQS(Vd, Vn, Vm) EMIT(FMINMAX_vector(1, 1, 0, 0, Vm, Vn, Vd))
|
||||
#define VFMINPQD(Vd, Vn, Vm) EMIT(FMINMAX_vector(1, 1, 1, 1, Vm, Vn, Vd))
|
||||
#define VFMAXPQD(Vd, Vn, Vm) EMIT(FMINMAX_vector(1, 1, 0, 1, Vm, Vn, Vd))
|
||||
|
||||
#define FMINMAX_scalar(type, Rm, op, Rn, Rd) (0b11110<<24 | (type)<<22 | 1<<21 | (Rm)<<16 | 0b01<<14 | (op)<<12 | 0b10<<10 | (Rn)<<5 | (Rd))
|
||||
#define FMINS(Sd, Sn, Sm) EMIT(FMINMAX_scalar(0b00, Sm, 0b01, Sn, Sd))
|
||||
@@ -2150,6 +2166,10 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#define URHADDQ_16(Vd, Vn, Vm) EMIT(RHADD_vector(1, 1, 0b01, Vm, Vn, Vd))
|
||||
#define URHADDQ_32(Vd, Vn, Vm) EMIT(RHADD_vector(1, 1, 0b10, Vm, Vn, Vd))
|
||||
|
||||
//SRSHR/URSHR
|
||||
#define RSHR(Q, U, immh, immb, Rn, Rd) ((Q)<<30 | (U)<<29 | 0b011110<<23 | (immh)<<19 | (immb)<<16 | 1<<13 | 0<<12 | 1<<10 | (Rn)<<5 | (Rd))
|
||||
#define SRSHRQ_32(Vd, Vn, shift) EMIT(RSHR(1, 0, 0b0100 | (((32-(shift))>>3)&0b11), (32-(shift))&0b111, Vn, Vd))
|
||||
|
||||
// QRDMULH Signed saturating (Rounding) Doubling Multiply returning High half
|
||||
#define QDMULH_vector(Q, U, size, Rm, Rn, Rd) ((Q)<<30 | (U)<<29 | 0b01110<<24 | (size)<<22 | 1<<21 | (Rm)<<16 | 0b10110<<11 | 1<<10 | (Rn)<<5 | (Rd))
|
||||
#define SQRDMULH_8(Vd, Vn, Vm) EMIT(QDMULH_vector(0, 1, 0b00, Vm, Vn, Vd))
|
||||
|
||||
@@ -19,6 +19,9 @@ arm64_epilog:
|
||||
stp x24, x25, [x0, (8 * 14)]
|
||||
stp x26, x27, [x0, (8 * 16)] // put back reg value in emu, including EIP (so x27 must be EIP now)
|
||||
//restore all used register
|
||||
#ifdef _WIN32
|
||||
ldr x18, [x0, 3120]
|
||||
#endif
|
||||
add sp, x28, 0
|
||||
//vpop {d8-d15}
|
||||
ldp x19, x20, [sp, (8 * 0)]
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
.text
|
||||
.align 4
|
||||
|
||||
.extern arm64_atomics
|
||||
.global arm64_lock_read_b
|
||||
.global arm64_lock_write_b
|
||||
.global arm64_lock_read_h
|
||||
@@ -33,6 +34,7 @@
|
||||
.global arm64_lock_get_b
|
||||
.global arm64_lock_get_d
|
||||
.global arm64_lock_get_dd
|
||||
.global arm64_crc
|
||||
|
||||
arm64_lock_read_b:
|
||||
dmb ish
|
||||
@@ -104,6 +106,10 @@ arm64_lock_write_dq:
|
||||
|
||||
|
||||
arm64_lock_xchg_dd:
|
||||
adrp x3, arm64_atomics
|
||||
add x3, x3, #:lo12:arm64_atomics
|
||||
ldr w3, [x3]
|
||||
cbnz w3, arm64_atomic_xchg_dd
|
||||
dmb ish
|
||||
arm64_lock_xchg_dd_0:
|
||||
// address is x0, value is x1, return old value in x0
|
||||
@@ -113,7 +119,17 @@ arm64_lock_xchg_dd_0:
|
||||
mov x0, x2
|
||||
ret
|
||||
|
||||
arm64_atomic_xchg_dd:
|
||||
dmb ish
|
||||
// address is x0, value is x1, return old value in x0
|
||||
swpal x1, x0, [x0]
|
||||
ret
|
||||
|
||||
arm64_lock_xchg_d:
|
||||
adrp x3, arm64_atomics
|
||||
add x3, x3, #:lo12:arm64_atomics
|
||||
ldr w3, [x3]
|
||||
cbnz w3, arm64_atomic_xchg_d
|
||||
dmb ish
|
||||
arm64_lock_xchg_d_0:
|
||||
// address is x0, value is x1, return old value in x0
|
||||
@@ -123,7 +139,17 @@ arm64_lock_xchg_d_0:
|
||||
mov w0, w2
|
||||
ret
|
||||
|
||||
arm64_atomic_xchg_d:
|
||||
dmb ish
|
||||
// address is x0, value is x1, return old value in x0
|
||||
swpal w1, w0, [x0]
|
||||
ret
|
||||
|
||||
arm64_lock_xchg_h:
|
||||
adrp x3, arm64_atomics
|
||||
add x3, x3, #:lo12:arm64_atomics
|
||||
ldr w3, [x3]
|
||||
cbnz w3, arm64_atomic_xchg_h
|
||||
dmb ish
|
||||
arm64_lock_xchg_h_0:
|
||||
// address is x0, value is x1, return old value in x0
|
||||
@@ -133,7 +159,17 @@ arm64_lock_xchg_h_0:
|
||||
mov w0, w2
|
||||
ret
|
||||
|
||||
arm64_atomic_xchg_h:
|
||||
dmb ish
|
||||
// address is x0, value is x1, return old value in x0
|
||||
swpalh w1, w0, [x0]
|
||||
ret
|
||||
|
||||
arm64_lock_xchg_b:
|
||||
adrp x3, arm64_atomics
|
||||
add x3, x3, #:lo12:arm64_atomics
|
||||
ldr w3, [x3]
|
||||
cbnz w3, arm64_atomic_xchg_b
|
||||
dmb ish
|
||||
arm64_lock_xchg_b_0:
|
||||
// address is x0, value is x1, return old value in x0
|
||||
@@ -143,7 +179,17 @@ arm64_lock_xchg_b_0:
|
||||
mov w0, w2
|
||||
ret
|
||||
|
||||
arm64_atomic_xchg_b:
|
||||
dmb ish
|
||||
// address is x0, value is x1, return old value in x0
|
||||
swpalb w1, w0, [x0]
|
||||
ret
|
||||
|
||||
arm64_lock_storeifnull:
|
||||
adrp x3, arm64_atomics
|
||||
add x3, x3, #:lo12:arm64_atomics
|
||||
ldr w3, [x3]
|
||||
cbnz w3, 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
|
||||
@@ -155,7 +201,20 @@ arm64_lock_storeifnull:
|
||||
mov x0, x2
|
||||
ret
|
||||
|
||||
arm64_atomic_storeifnull:
|
||||
dmb ish
|
||||
// address is x0, value is x1, x1 store to x0 only if [x0] is 0. return old [x0] value
|
||||
mov x2, xzr
|
||||
casal x2, x1, [x0]
|
||||
mov x0, x2
|
||||
ret
|
||||
|
||||
|
||||
arm64_lock_storeifnull_d:
|
||||
adrp x3, arm64_atomics
|
||||
add x3, x3, #:lo12:arm64_atomics
|
||||
ldr w3, [x3]
|
||||
cbnz w3, 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
|
||||
@@ -168,7 +227,19 @@ arm64_lock_storeifnull_d:
|
||||
mov w0, w2
|
||||
ret
|
||||
|
||||
arm64_atomic_storeifnull_d:
|
||||
dmb ish
|
||||
// address is x0, value is w1, w1 store to x0 only if [x0] is 0. return old [x0] value
|
||||
mov x2, xzr
|
||||
casal w2, w1, [x0]
|
||||
mov w0, w2
|
||||
ret
|
||||
|
||||
arm64_lock_storeifref:
|
||||
adrp x3, arm64_atomics
|
||||
add x3, x3, #:lo12:arm64_atomics
|
||||
ldr w3, [x3]
|
||||
cbnz w3, 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)
|
||||
@@ -183,7 +254,23 @@ arm64_lock_storeifref:
|
||||
mov x0, x3
|
||||
ret
|
||||
|
||||
arm64_atomic_storeifref:
|
||||
dmb ish
|
||||
// address is x0, value is x1, x1 store to x0 only if [x0] is x2. return new [x0] value (so x1 or old value)
|
||||
mov x3, x2
|
||||
casal x2, x1, [x0]
|
||||
cmp x2, x3
|
||||
mov x0, x1
|
||||
ret
|
||||
2:
|
||||
mov x0, x3
|
||||
ret
|
||||
|
||||
arm64_lock_storeifref_d:
|
||||
adrp x3, arm64_atomics
|
||||
add x3, x3, #:lo12:arm64_atomics
|
||||
ldr w3, [x3]
|
||||
cbnz w3, 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)
|
||||
@@ -198,7 +285,23 @@ arm64_lock_storeifref_d:
|
||||
mov w0, w3
|
||||
ret
|
||||
|
||||
arm64_atomic_storeifref_d:
|
||||
dmb ish
|
||||
// address is x0, value is w1, w1 store to x0 only if [x0] is w2. return new [x0] value (so w1 or old value)
|
||||
mov w3, w2
|
||||
casal w2, w1, [x0]
|
||||
cmp w2, w3
|
||||
mov w0, w1
|
||||
ret
|
||||
2:
|
||||
mov w0, w3
|
||||
ret
|
||||
|
||||
arm64_lock_storeifref2_d:
|
||||
adrp x3, arm64_atomics
|
||||
add x3, x3, #:lo12:arm64_atomics
|
||||
ldr w3, [x3]
|
||||
cbnz w3, 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
|
||||
@@ -211,6 +314,13 @@ arm64_lock_storeifref2_d:
|
||||
mov w0, w3
|
||||
ret
|
||||
|
||||
arm64_atomic_storeifref2_d:
|
||||
dmb ish
|
||||
// address is x0, value is w1, w1 store to x0 only if [x0] is w2. return old [x0] value
|
||||
casal w2, w1, [x0]
|
||||
mov w0, w2
|
||||
ret
|
||||
|
||||
arm64_lock_decifnot0b:
|
||||
dmb ish
|
||||
1:
|
||||
@@ -242,6 +352,10 @@ arm64_lock_decifnot0:
|
||||
ret
|
||||
|
||||
arm64_lock_incif0:
|
||||
adrp x3, arm64_atomics
|
||||
add x3, x3, #:lo12:arm64_atomics
|
||||
ldr w3, [x3]
|
||||
cbnz w3, arm64_atomic_incif0
|
||||
dmb ish
|
||||
1:
|
||||
ldaxr w1, [x0]
|
||||
@@ -254,6 +368,13 @@ arm64_lock_incif0:
|
||||
mov w0, w1
|
||||
ret
|
||||
|
||||
arm64_atomic_incif0:
|
||||
mov w1, #1
|
||||
dmb ish
|
||||
swpal w1, wzr, [x0]
|
||||
mov w0, w1
|
||||
ret
|
||||
|
||||
arm64_lock_store:
|
||||
str w1, [x0]
|
||||
dmb ish
|
||||
@@ -275,3 +396,24 @@ arm64_lock_get_d:
|
||||
arm64_lock_get_dd:
|
||||
ldaxr x0, [x0]
|
||||
ret
|
||||
|
||||
arm64_crc:
|
||||
//x0 is address, w1 is len
|
||||
mov x2, x0 // address is x2 now
|
||||
mov w0, wzr // crc is w0
|
||||
1:
|
||||
cmp w1, #8
|
||||
blo 2f
|
||||
ldr x3, [x2], #8
|
||||
crc32x w0, w0, x3
|
||||
subs w1, w1, #8
|
||||
bne 1b
|
||||
2:
|
||||
cbz w1, 4f
|
||||
3:
|
||||
ldrb w3, [x2], #1
|
||||
crc32b w0, w0, w3
|
||||
subs w1, w1, #1
|
||||
bne 3b
|
||||
4:
|
||||
ret
|
||||
@@ -29,30 +29,39 @@ extern int arm64_lock_write_dq(uint64_t a, uint64_t b, void* addr);
|
||||
|
||||
// Atomically exchange value at [p] with val, return old p
|
||||
extern uintptr_t arm64_lock_xchg_dd(void* p, uintptr_t val);
|
||||
extern uintptr_t arm64_atomic_xchg_dd(void* p, uintptr_t val);
|
||||
|
||||
// Atomically exchange value at [p] with val, return old p
|
||||
extern uint32_t arm64_lock_xchg_d(void* p, uint32_t val);
|
||||
extern uint32_t arm64_atomic_xchg_d(void* p, uint32_t val);
|
||||
|
||||
// Atomically exchange value at [p] with val, return old p
|
||||
extern uint32_t arm64_lock_xchg_h(void* p, uint32_t val);
|
||||
extern uint32_t arm64_atomic_xchg_h(void* p, uint32_t val);
|
||||
|
||||
// Atomically exchange value at [p] with val, return old p
|
||||
extern uint32_t arm64_lock_xchg_b(void* p, uint32_t val);
|
||||
extern uint32_t arm64_atomic_xchg_b(void* p, uint32_t val);
|
||||
|
||||
// Atomically store value to [p] only if [p] is NULL. Return old [p] value
|
||||
extern uint32_t arm64_lock_storeifnull_d(void*p, uint32_t val);
|
||||
extern uint32_t arm64_atomic_storeifnull_d(void*p, uint32_t val);
|
||||
|
||||
// Atomically store value to [p] only if [p] is NULL. Return old [p] value
|
||||
extern void* arm64_lock_storeifnull(void*p, void* val);
|
||||
extern void* arm64_atomic_storeifnull(void*p, void* val);
|
||||
|
||||
// Atomically store value to [p] only if [p] is ref. Return new [p] value (so val or old)
|
||||
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 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)
|
||||
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);
|
||||
|
||||
// decrement atomically the byte at [p] (but only if p not 0)
|
||||
extern void arm64_lock_decifnot0b(void*p);
|
||||
|
||||
@@ -22,6 +22,9 @@ arm64_next:
|
||||
stp x16, x17, [sp, (8 * 8)]
|
||||
stp x18, x27, [sp, (8 * 10)] // also save x27(rip) to allow change in LinkNext
|
||||
|
||||
#ifdef _WIN32
|
||||
ldr x18, [x0, 3120]
|
||||
#endif
|
||||
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
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "debug.h"
|
||||
@@ -407,9 +408,9 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
if(sf) {
|
||||
uint64_t noti=~(((uint64_t)imm)<<(hw*16));
|
||||
if(!hw)
|
||||
snprintf(buff, sizeof(buff), "MOVN %s, 0x%x\t; 0x%lx", Xt[Rd], imm, noti);
|
||||
snprintf(buff, sizeof(buff), "MOVN %s, 0x%x\t; 0x%"PRIx64, Xt[Rd], imm, noti);
|
||||
else
|
||||
snprintf(buff, sizeof(buff), "MOVN %s, 0x%x LSL %d\t; 0x%lx", Xt[Rd], imm, 16*hw, noti);
|
||||
snprintf(buff, sizeof(buff), "MOVN %s, 0x%x LSL %d\t; 0x%"PRIx64, Xt[Rd], imm, 16*hw, noti);
|
||||
} else {
|
||||
uint32_t noti=~(((uint32_t)imm)<<(hw*16));
|
||||
if(!hw)
|
||||
@@ -569,11 +570,11 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
uint64_t i = DecodeBitMasks(a.N, imms, immr);
|
||||
if(!sf) i&=0xffffffff;
|
||||
if(sf==0 && a.N==1)
|
||||
snprintf(buff, sizeof(buff), "invalid ANDS %s, %s, 0x%lx", Wt[Rd], Wt[Rn], i);
|
||||
snprintf(buff, sizeof(buff), "invalid ANDS %s, %s, 0x%"PRIx64, Wt[Rd], Wt[Rn], i);
|
||||
else if(Rd==31)
|
||||
snprintf(buff, sizeof(buff), "TST %s, 0x%lx", sf?Xt[Rn]:Wt[Rn], i);
|
||||
snprintf(buff, sizeof(buff), "TST %s, 0x%"PRIx64, sf?Xt[Rn]:Wt[Rn], i);
|
||||
else
|
||||
snprintf(buff, sizeof(buff), "ANDS %s, %s, 0x%lx", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], i);
|
||||
snprintf(buff, sizeof(buff), "ANDS %s, %s, 0x%"PRIx64, sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], i);
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "f1101010hh0mmmmmiiiiiinnnnnddddd", &a)) {
|
||||
@@ -611,9 +612,9 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
uint64_t i = DecodeBitMasks(a.N, imms, immr);
|
||||
if(!sf) i&=0xffffffff;
|
||||
if(sf==0 && a.N==1)
|
||||
snprintf(buff, sizeof(buff), "invalid ORR %s, %s, 0x%lx", Wt[Rd], Wt[Rn], i);
|
||||
snprintf(buff, sizeof(buff), "invalid ORR %s, %s, 0x%"PRIx64, Wt[Rd], Wt[Rn], i);
|
||||
else
|
||||
snprintf(buff, sizeof(buff), "ORR %s, %s, 0x%lx", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], i);
|
||||
snprintf(buff, sizeof(buff), "ORR %s, %s, 0x%"PRIx64, sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], i);
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "f0101010hh1mmmmmiiiiiinnnnnddddd", &a)) {
|
||||
@@ -646,9 +647,9 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
uint64_t i = DecodeBitMasks(a.N, imms, immr);
|
||||
if(!sf) i&=0xffffffff;
|
||||
if(sf==0 && a.N==1)
|
||||
snprintf(buff, sizeof(buff), "invalid EOR %s, %s, 0x%lx", Wt[Rd], Wt[Rn], i);
|
||||
snprintf(buff, sizeof(buff), "invalid EOR %s, %s, 0x%"PRIx64, Wt[Rd], Wt[Rn], i);
|
||||
else
|
||||
snprintf(buff, sizeof(buff), "EOR %s, %s, 0x%lx", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], i);
|
||||
snprintf(buff, sizeof(buff), "EOR %s, %s, 0x%"PRIx64, sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], i);
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "f1001010hh0mmmmmiiiiiinnnnnddddd", &a)) {
|
||||
@@ -663,9 +664,9 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
uint64_t i = DecodeBitMasks(a.N, imms, immr);
|
||||
if(!sf) i&=0xffffffff;
|
||||
if(sf==0 && a.N==1)
|
||||
snprintf(buff, sizeof(buff), "invalid AND %s, %s, 0x%lx", Wt[Rd], Wt[Rn], i);
|
||||
snprintf(buff, sizeof(buff), "invalid AND %s, %s, 0x%"PRIx64, Wt[Rd], Wt[Rn], i);
|
||||
else
|
||||
snprintf(buff, sizeof(buff), "AND %s, %s, 0x%lx", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], i);
|
||||
snprintf(buff, sizeof(buff), "AND %s, %s, 0x%"PRIx64, sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], i);
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "f0001010hh0mmmmmiiiiiinnnnnddddd", &a)) {
|
||||
@@ -770,6 +771,13 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
snprintf(buff, sizeof(buff), "BLR %s", Xt[Rn]);
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "1101011001011111000000nnnnn00000", &a)) {
|
||||
if(Rn==30)
|
||||
snprintf(buff, sizeof(buff), "RET");
|
||||
else
|
||||
snprintf(buff, sizeof(buff), "RET %s", Xt[Rn]);
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "01010100iiiiiiiiiiiiiiiiiii0cccc", &a)) {
|
||||
int offset = signExtend(imm, 19)<<2;
|
||||
snprintf(buff, sizeof(buff), "B.%s #+%di\t; %p", conds[cond], offset>>2, (void*)(addr + offset));
|
||||
@@ -792,12 +800,12 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
}
|
||||
if(isMask(opcode, "s0110110sssssiiiiiiiiiiiiiittttt", &a)) {
|
||||
int offset = signExtend(imm, 14)<<2;
|
||||
snprintf(buff, sizeof(buff), "TBZ %s, 0x%x, #%+di\t; %p", (imms<31)?Xt[Rt]:Wt[Rt], imms, offset>>2, (void*)(addr + offset));
|
||||
snprintf(buff, sizeof(buff), "TBZ %s, %d, #%+di\t; %p", (imms<31)?Xt[Rt]:Wt[Rt], imms, offset>>2, (void*)(addr + offset));
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "s0110111sssssiiiiiiiiiiiiiittttt", &a)) {
|
||||
int offset = signExtend(imm, 14)<<2;
|
||||
snprintf(buff, sizeof(buff), "TBNZ %s, 0x%x, #%+di\t; %p", (imms<31)?Xt[Rt]:Wt[Rt], imms, offset>>2, (void*)(addr + offset));
|
||||
snprintf(buff, sizeof(buff), "TBNZ %s, %d, #%+di\t; %p", (imms<31)?Xt[Rt]:Wt[Rt], imms, offset>>2, (void*)(addr + offset));
|
||||
return buff;
|
||||
}
|
||||
|
||||
@@ -1068,9 +1076,9 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
tmp64u |= 0xffLL<<(i*8);
|
||||
|
||||
if(a.Q)
|
||||
snprintf(buff, sizeof(buff), "MOVI V%d.2D, #0x%016lx", Rd, tmp64u);
|
||||
snprintf(buff, sizeof(buff), "MOVI V%d.2D, #0x%016"PRIx64, Rd, tmp64u);
|
||||
else
|
||||
snprintf(buff, sizeof(buff), "MOVI D%d, #0x%016lx", Rd, tmp64u);
|
||||
snprintf(buff, sizeof(buff), "MOVI D%d, #0x%016"PRIx64, Rd, tmp64u);
|
||||
return buff;
|
||||
}
|
||||
|
||||
@@ -1111,7 +1119,7 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
|
||||
// ADR
|
||||
if(isMask(opcode, "0ss10000iiiiiiiiiiiiiiiiiiiddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "ADR, %s, %ld", Xt[Rd], signExtend((imm)<<2|(imms), 20));
|
||||
snprintf(buff, sizeof(buff), "ADR, %s, %"PRId64, Xt[Rd], signExtend((imm)<<2|(imms), 20));
|
||||
return buff;
|
||||
}
|
||||
|
||||
@@ -1334,7 +1342,7 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
return buff;
|
||||
}
|
||||
//FCMEQ
|
||||
if(isMask(opcode, "000111100f1mmmmm111001nnnnnddddd", &a)) {
|
||||
if(isMask(opcode, "010111100f1mmmmm111001nnnnnddddd", &a)) {
|
||||
char s = (sf==0)?'S':'D';
|
||||
snprintf(buff, sizeof(buff), "FCMEQ %c%d, %c%d, %c%d", s, Rd, s, Rn, s, Rm);
|
||||
return buff;
|
||||
@@ -1355,18 +1363,18 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
snprintf(buff, sizeof(buff), "F%s %c%d, %c%d, %c%d", (option==3)?"MINNM":((option==2)?"MAXNM":((!option)?"MAX":"MIN")), s, Rd, s, Rn, s, Rm);
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "0Q001110of1mmmmm110001nnnnnddddd", &a)) {
|
||||
if(isMask(opcode, "0QU01110of1mmmmm110001nnnnnddddd", &a)) {
|
||||
char s = (sf==0)?'S':((sf==1)?'D':'?');
|
||||
int n = (sf==0)?2:1;
|
||||
n *= a.Q?2:1;
|
||||
snprintf(buff, sizeof(buff), "F%sNM%s V%d.%d%c, V%d.%d%c, V%d.%d%c", option?"MIN":"MAX", a.Q?"Q":"", Rd, n, s, Rn, n, s, Rm, n, s);
|
||||
snprintf(buff, sizeof(buff), "F%sNM%s%s V%d.%d%c, V%d.%d%c, V%d.%d%c", option?"MIN":"MAX", a.U?"P":"", a.Q?"Q":"", Rd, n, s, Rn, n, s, Rm, n, s);
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "0Q001110of1mmmmm111101nnnnnddddd", &a)) {
|
||||
if(isMask(opcode, "0QU01110of1mmmmm111101nnnnnddddd", &a)) {
|
||||
char s = (sf==0)?'S':((sf==1)?'D':'?');
|
||||
int n = (sf==0)?2:1;
|
||||
n *= a.Q?2:1;
|
||||
snprintf(buff, sizeof(buff), "F%s%s V%d.%d%c, V%d.%d%c, V%d.%d%c", option?"MIN":"MAX", a.Q?"Q":"", Rd, n, s, Rn, n, s, Rm, n, s);
|
||||
snprintf(buff, sizeof(buff), "F%s%s%s V%d.%d%c, V%d.%d%c, V%d.%d%c", option?"MIN":"MAX", a.U?"P":"", a.Q?"Q":"", Rd, n, s, Rn, n, s, Rm, n, s);
|
||||
return buff;
|
||||
}
|
||||
// FMADD
|
||||
@@ -1580,6 +1588,28 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
snprintf(buff, sizeof(buff), "%cRHADD V%d.%s, V%d.%s, V%d.%s", a.U?'U':'S', Rd, Vd, Rn, Vd, Rm, Vd);
|
||||
return buff;
|
||||
}
|
||||
//S/URSHR
|
||||
if(isMask(opcode, "0QU011110iiiiiii001001nnnnnddddd", &a)) {
|
||||
int shft = 0;
|
||||
int sz = 0;
|
||||
const char* Y[] = {"8B", "16B", "4H", "8H", "2S", "4S", "??", "2D"};
|
||||
if(imm&0b1000000) {
|
||||
sz = 3;
|
||||
shft = imm&0b111111;
|
||||
} else if(imm&0b100000) {
|
||||
sz = 2;
|
||||
shft = imm&0b1111;
|
||||
} else if(imm&0b10000) {
|
||||
sz = 1;
|
||||
shft = imm&0b111;
|
||||
} else if(imm&0b1000) {
|
||||
sz = 0;
|
||||
shft = imm&0b111;
|
||||
}
|
||||
const char* Vd = Y[(sz<<1) | a.Q];
|
||||
snprintf(buff, sizeof(buff), "%cRSHR V%d.%s, V%d.%s, #%d", a.U?'U':'S', Rd, Vd, Rn, Vd, shft);
|
||||
return buff;
|
||||
}
|
||||
//SQ(R)DMULH
|
||||
if(isMask(opcode, "0QU01110ff1mmmmm101101nnnnnddddd", &a)) {
|
||||
const char* Y[] = {"8B", "16B", "4H", "8H", "2S", "4S", "??", "???"};
|
||||
@@ -1637,6 +1667,17 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
snprintf(buff, sizeof(buff), "%sR %s%d, [%s, %+d]", a.L?"LD":"ST", Y[sz], Rt, XtSp[Rn], imm);
|
||||
return buff;
|
||||
}
|
||||
// LDP/STP vector
|
||||
if(isMask(opcode, "ff1011010Liiiiiii22222nnnnnttttt", &a)) {
|
||||
const char* Y[] = {"S", "D", "Q", "?"};
|
||||
int sz = sf;
|
||||
int offset = signExtend(imm, 7)<<(2+sz);
|
||||
if(!offset)
|
||||
snprintf(buff, sizeof(buff), "%sP %s%d, %s%d, [%s]", a.L?"LD":"ST", Y[sz], Rt, Y[sz], Rt2, XtSp[Rn]);
|
||||
else
|
||||
snprintf(buff, sizeof(buff), "%sP %s%d, %s%d, [%s, %s0x%x]", a.L?"LD":"ST", Y[sz], Rt, Y[sz], Rt2, XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
return buff;
|
||||
}
|
||||
|
||||
// (S/U)QXT(U)N
|
||||
if(isMask(opcode, "0Q101110ff100001001010nnnnnddddd", &a)) {
|
||||
@@ -1744,6 +1785,26 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
snprintf(buff, sizeof(buff), "PMULL%s V%d.%s, V%d.%s, V%d.%s", a.Q?"2":"", Rd, Vd, Rn, Vn, Rm, Vn);
|
||||
return buff;
|
||||
}
|
||||
// [S/U]MULL
|
||||
if(isMask(opcode, "0QU01110ff1mmmmm110000nnnnnddddd", &a)) {
|
||||
const char* Y[] = {"8B", "16B", "4H", "8H", "2S", "4S", "??", "??"};
|
||||
const char* Z[] = {"8H", "4S", "2D", "??"};
|
||||
int sz = sf;
|
||||
const char* Vn = Y[(sz<<1)|a.Q];
|
||||
const char* Vd = Z[sz];
|
||||
snprintf(buff, sizeof(buff), "%cMULL%s V%d.%s, V%d.%s, V%d.%s", a.U?'U':'S', a.Q?"2":"", Rd, Vd, Rn, Vn, Rm, Vn);
|
||||
return buff;
|
||||
}
|
||||
//XTN(2)
|
||||
if(isMask(opcode, "0Q001110ff100001001010nnnnnddddd", &a)) {
|
||||
const char* Y[] = {"8B", "16B", "4H", "8H", "2S", "4S", "??", "??"};
|
||||
const char* Z[] = {"8H", "4S", "2D", "??"};
|
||||
int sz = sf;
|
||||
const char* Vd = Y[(sz<<1)|a.Q];
|
||||
const char* Vn = Z[sz];
|
||||
snprintf(buff, sizeof(buff), "XTN%s V%d.%s, V%d.%s", a.Q?"2":"", Rd, Vd, Rn, Vn);
|
||||
return buff;
|
||||
}
|
||||
|
||||
// DMB
|
||||
if(isMask(opcode, "11010101000000110011nnnn10111111", &a)) {
|
||||
|
||||
@@ -2,23 +2,23 @@
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "os.h"
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "bridge.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
#include "../dynablock_private.h"
|
||||
#include "custommem.h"
|
||||
|
||||
#include "alternate.h"
|
||||
#include "mysignal.h"
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
@@ -1442,6 +1442,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOVxw_REG(TO_NAT((nextop & 7) + (rex.b << 3)), gd);
|
||||
} else { // mem <= reg
|
||||
IF_UNALIGNED(ip) {
|
||||
MESSAGE(LOG_DEBUG, "\tUnaligned path");
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, &lock, 0, 0);
|
||||
if(gd==wback) {
|
||||
MOVx_REG(x2, wback);
|
||||
@@ -1559,15 +1560,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
POP1z(TO_NAT((nextop & 7) + (rex.b << 3)));
|
||||
} else {
|
||||
POP1z(x2); // so this can handle POP [ESP] and maybe some variant too
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
if(ed==xRSP) {
|
||||
STz(x2, ed, fixedaddress);
|
||||
} else {
|
||||
// complicated to just allow a segfault that can be recovered correctly
|
||||
SUBz_U12(xRSP, xRSP, rex.is32bits?4:8);
|
||||
STz(x2, ed, fixedaddress);
|
||||
ADDz_U12(xRSP, xRSP, rex.is32bits?4:8);
|
||||
}
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<(2+rex.is32bits), (1<<(2+rex.is32bits))-1, rex, NULL, 0, 0);
|
||||
STz(x2, ed, fixedaddress);
|
||||
SMWRITE();
|
||||
}
|
||||
break;
|
||||
case 0x90:
|
||||
@@ -1705,6 +1700,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
CBZx_NEXT(xRCX);
|
||||
TBNZ_MARK2(xFlags, F_DF);
|
||||
IF_UNALIGNED(ip) {
|
||||
MESSAGE(LOG_DEBUG, "\tUnaligned path");
|
||||
// special optim for large RCX value on forward case only
|
||||
// but because it's unaligned path, check if a byte per byt is needed, and do 4-bytes per 4-bytes only instead
|
||||
if(BOX64DRENV(dynarec_safeflags)) {
|
||||
@@ -1716,8 +1712,8 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ANDw_mask(x1, x1, 0, 1); //mask = 3
|
||||
CBNZw_MARK(x1);
|
||||
MARK3;
|
||||
CMPSx_U12(xRCX, 4);
|
||||
B_MARK(cCC);
|
||||
ANDx_mask(x1, xRCX, 1, 0b111110, 0b111101); // mask=0xfffffffffffffffc, so ~3LL
|
||||
CBZx_MARK(x1); // xRCX<4
|
||||
LDRw_S9_postindex(x1, xRSI, 4);
|
||||
STRw_S9_postindex(x1, xRDI, 4);
|
||||
SUBx_U12(xRCX, xRCX, 4);
|
||||
@@ -1731,8 +1727,8 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
// special optim for large RCX value on forward case only
|
||||
MARK3;
|
||||
CMPSx_U12(xRCX, 8);
|
||||
B_MARK(cCC);
|
||||
ANDx_mask(x1, xRCX, 1, 0b111101, 0b111100); // mask=0xfffffffffffffff8, so ~7LL
|
||||
CBZx_MARK(x1); // xRCX<8
|
||||
LDRx_S9_postindex(x1, xRSI, 8);
|
||||
STRx_S9_postindex(x1, xRDI, 8);
|
||||
SUBx_U12(xRCX, xRCX, 8);
|
||||
@@ -1897,16 +1893,46 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("REP STOSB");
|
||||
CBZx_NEXT(xRCX);
|
||||
TBNZ_MARK2(xFlags, F_DF);
|
||||
IF_UNALIGNED(ip) {
|
||||
MESSAGE(LOG_DEBUG, "\tUnaligned path");
|
||||
// special optim for large RCX value on forward case only
|
||||
// but because it's unaligned path, check if a byte per byt is needed, and do 4-bytes per 4-bytes only instead
|
||||
ANDw_mask(x1, xRDI, 0, 1); //mask = 3
|
||||
CBNZw_MARK(x1);
|
||||
UXTBw(x3, xRAX); // prepare x3
|
||||
ORRw_REG_LSL(x3, x3, x3, 8);
|
||||
ORRw_REG_LSL(x3, x3, x3, 16); // 4bytes ready
|
||||
MARK3;
|
||||
ANDx_mask(x1, xRCX, 1, 0b111110, 0b111101); // mask=0xfffffffffffffffc, so ~3LL
|
||||
CBZx_MARK(x1); // xRCX<4
|
||||
STRw_S9_postindex(x3, xRDI, 4);
|
||||
SUBx_U12(xRCX, xRCX, 4);
|
||||
CBNZx_MARK3(xRCX);
|
||||
CBZx_MARKLOCK(xRCX);
|
||||
} else {
|
||||
// special optim for large RCX value on forward case only
|
||||
UXTBw(x3, xRAX); // prepare x3
|
||||
ORRw_REG_LSL(x3, x3, x3, 8);
|
||||
ORRw_REG_LSL(x3, x3, x3, 16);
|
||||
ORRx_REG_LSL(x3, x3, x3, 32); // 8 bytes...
|
||||
MARK3;
|
||||
ANDx_mask(x1, xRCX, 1, 0b111101, 0b111100); // mask=0xfffffffffffffff8, so ~7LL
|
||||
CBZx_MARK(x1); // xRCX<8
|
||||
STRx_S9_postindex(x3, xRDI, 8);
|
||||
SUBx_U12(xRCX, xRCX, 8);
|
||||
CBNZx_MARK3(xRCX);
|
||||
CBZx_MARKLOCK(xRCX);
|
||||
}
|
||||
MARK; // Part with DF==0
|
||||
STRB_S9_postindex(xRAX, xRDI, 1);
|
||||
SUBx_U12(xRCX, xRCX, 1);
|
||||
CBNZx_MARK(xRCX);
|
||||
B_MARK3_nocond;
|
||||
B_MARKLOCK_nocond;
|
||||
MARK2; // Part with DF==1
|
||||
STRB_S9_postindex(xRAX, xRDI, -1);
|
||||
SUBx_U12(xRCX, xRCX, 1);
|
||||
CBNZx_MARK2(xRCX);
|
||||
MARK3;
|
||||
MARKLOCK;
|
||||
// done
|
||||
} else {
|
||||
INST_NAME("STOSB");
|
||||
@@ -2361,7 +2387,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); // using next, even if there no next
|
||||
i32 = F16;
|
||||
retn_to_epilog(dyn, ninst, rex, i32);
|
||||
retn_to_epilog(dyn, ip, ninst, rex, i32);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
break;
|
||||
@@ -2372,7 +2398,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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
|
||||
ret_to_epilog(dyn, ninst, rex);
|
||||
ret_to_epilog(dyn, ip, ninst, rex);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
break;
|
||||
@@ -2463,6 +2489,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOV64xw(ed, i64);
|
||||
} else { // mem <= i32
|
||||
IF_UNALIGNED(ip) {
|
||||
MESSAGE(LOG_DEBUG, "\tUnaligned path");
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, &lock, 0, 4);
|
||||
i64 = F32S;
|
||||
if(i64) {
|
||||
@@ -2549,7 +2576,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0xCC:
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack, set all flags (to an unknown state...)
|
||||
NOTEST(x1);
|
||||
if(PK(0)=='S' && PK(1)=='C') {
|
||||
if (IsBridgeSignature(PK(0), PK(1))) {
|
||||
addr+=2;
|
||||
//BARRIER(BARRIER_FLOAT);
|
||||
INST_NAME("Special Box64 instruction");
|
||||
@@ -2564,7 +2591,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
*ok = 0;
|
||||
*need_epilog = 1;
|
||||
} else {
|
||||
MESSAGE(LOG_DUMP, "Native Call to %s\n", getBridgeName((void*)ip)?:GetNativeName(GetNativeFnc(ip)));
|
||||
MESSAGE(LOG_DUMP, "Native Call to %s\n", GetBridgeName((void*)ip) ?: GetNativeName(GetNativeFnc(ip)));
|
||||
x87_stackcount(dyn, ninst, x1);
|
||||
x87_forget(dyn, ninst, x3, x4, 0);
|
||||
sse_purge07cache(dyn, ninst, x3);
|
||||
@@ -2580,9 +2607,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
GETIP(ip+1); // read the 0xCC
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
ADDx_U12(x3, xRIP, 8+8); // expected return address
|
||||
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_(x64Int3, -1, x3);
|
||||
CALL_(EmuInt3, -1, x3);
|
||||
SMWRITE2();
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
addr+=8+8;
|
||||
@@ -2619,22 +2646,47 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0xCD:
|
||||
u8 = F8;
|
||||
if(box64_wine && (u8==0x2D || u8==0x2C || u8==0x29)) {
|
||||
INST_NAME("INT 29/2c/2d");
|
||||
#ifdef _WIN32
|
||||
NOTEST(x1);
|
||||
SMEND();
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
MOV32w(x1, u8);
|
||||
CALL_S(native_int, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
TABLE64(x3, addr); // expected return address
|
||||
CMPSx_REG(xRIP, x3);
|
||||
B_MARK(cNE);
|
||||
LDRw_U12(w1, xEmu, offsetof(x64emu_t, quit));
|
||||
CBZw_NEXT(w1);
|
||||
MARK;
|
||||
LOAD_XEMU_REM();
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
#else
|
||||
if(box64_wine && (u8==0x2E || u8==0x2D || u8==0x2C || u8==0x29)) {
|
||||
INST_NAME("INT 29/2c/2d/2e");
|
||||
// lets do nothing
|
||||
MESSAGE(LOG_INFO, "INT 29/2c/2d Windows interruption\n");
|
||||
MESSAGE(LOG_INFO, "INT 29/2c/2d/2e Windows interruption\n");
|
||||
GETIP(ip); // priviledged instruction, IP not updated
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
MOV32w(x1, u8);
|
||||
CALL(native_int, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
LOAD_XEMU_REM();
|
||||
TABLE64(x3, addr); // expected return address
|
||||
CMPSx_REG(xRIP, x3);
|
||||
B_MARK(cNE);
|
||||
LDRw_U12(w1, xEmu, offsetof(x64emu_t, quit));
|
||||
CBZw_NEXT(w1);
|
||||
MARK;
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
} else if (u8==0x80) {
|
||||
INST_NAME("32bits SYSCALL");
|
||||
NOTEST(x1);
|
||||
SMEND();
|
||||
GETIP(addr);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL_S(x86Syscall, -1);
|
||||
CALL_S(EmuX86Syscall, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
TABLE64(x3, addr); // expected return address
|
||||
CMPSx_REG(xRIP, x3);
|
||||
@@ -2678,6 +2730,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case 0xCE:
|
||||
if(!rex.is32bits) {
|
||||
@@ -2697,7 +2750,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("IRET");
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Not a hack, EFLAGS are restored
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
iret_to_epilog(dyn, ninst, rex.is32bits, rex.w);
|
||||
iret_to_epilog(dyn, ip, ninst, rex.is32bits, rex.w);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
break;
|
||||
@@ -3312,7 +3365,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(dyn, addr+i32, rex.is32bits, &dyn->insts[ninst].natcall, &dyn->insts[ninst].retn))
|
||||
if (!rex.is32bits && 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;
|
||||
@@ -3328,7 +3381,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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);
|
||||
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);
|
||||
SKIPTEST(x1); // disable test as this hack dos 2 instructions for 1
|
||||
// calling a native function
|
||||
SMEND();
|
||||
@@ -3350,7 +3403,7 @@ 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(x64Int3, -1);
|
||||
CALL_S(EmuInt3, -1);
|
||||
SMWRITE2();
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
MOV64x(x3, dyn->insts[ninst].natcall);
|
||||
@@ -3389,11 +3442,17 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
// 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;
|
||||
if(BOX64DRENV(dynarec_callret)>1)
|
||||
j64 = CALLRET_GETRET();
|
||||
else
|
||||
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 {
|
||||
j64 = (dyn->insts)?(GETMARK-(dyn->native_size)):0;
|
||||
if(BOX64DRENV(dynarec_callret)>1)
|
||||
j64 = CALLRET_GETRET();
|
||||
else
|
||||
j64 = (dyn->insts)?(GETMARK-(dyn->native_size)):0;
|
||||
ADR_S20(x4, j64);
|
||||
MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
|
||||
}
|
||||
@@ -3407,6 +3466,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
else
|
||||
j64 = addr+i32;
|
||||
jump_to_next(dyn, j64, 0, ninst, rex.is32bits);
|
||||
if(BOX64DRENV(dynarec_callret)>1) CALLRET_RET();
|
||||
if (BOX64DRENV(dynarec_callret) && addr >= (dyn->start + dyn->isize)) {
|
||||
// jumps out of current dynablock...
|
||||
MARK;
|
||||
@@ -3650,7 +3710,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_safeflags)) {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
} else if(BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_SF|X_PF|X_ZF|X_AF, SF_SET);
|
||||
SETFLAGS(X_SF|X_PF|X_ZF|X_AF, SF_SUBSET);
|
||||
}
|
||||
GETSEB(x1, 0);
|
||||
if(BOX64ENV(dynarec_div0)) {
|
||||
@@ -4049,7 +4109,10 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
// 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;
|
||||
if(BOX64DRENV(dynarec_callret)>1)
|
||||
j64 = CALLRET_GETRET();
|
||||
else
|
||||
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 {
|
||||
@@ -4061,6 +4124,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
PUSH1z(xRIP);
|
||||
jump_to_next(dyn, 0, ed, ninst, rex.is32bits);
|
||||
if(BOX64DRENV(dynarec_callret)>1) CALLRET_RET();
|
||||
if (BOX64DRENV(dynarec_callret) && addr >= (dyn->start + dyn->isize)) {
|
||||
// jumps out of current dynablock...
|
||||
MARK;
|
||||
|
||||
@@ -5,10 +5,8 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
@@ -16,9 +14,9 @@
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
#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"
|
||||
@@ -151,7 +149,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(x64Syscall, -1);
|
||||
CALL_S(EmuX64Syscall, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
TABLE64(x3, addr); // expected return address
|
||||
SUBx_REG(x3, x3, xRIP);
|
||||
@@ -261,6 +259,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
IF_UNALIGNED(ip) {
|
||||
MESSAGE(LOG_DEBUG, "\tUnaligned path");
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(wback!=x1) {
|
||||
MOVx_REG(x1, wback);
|
||||
@@ -280,12 +279,12 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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);
|
||||
VMOVeD(v0, 0, v1, 1);
|
||||
} else {
|
||||
INST_NAME("MOVLPS Gx,Ex");
|
||||
INST_NAME("MOVLPS Gx, Ex");
|
||||
GETGX(v0, 1);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
@@ -294,11 +293,11 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0x13:
|
||||
nextop = F8;
|
||||
INST_NAME("MOVLPS Ex,Gx");
|
||||
INST_NAME("MOVLPS Ex, Gx");
|
||||
GETGX(v0, 0);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 1);
|
||||
VMOVeD(v1, 0, v0, 0);
|
||||
DEFAULT;
|
||||
return addr;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
VST1_64(v0, 0, ed); // better to use VST1 than VSTR_64, to avoid NEON->VFPU transfert I assume
|
||||
@@ -322,12 +321,12 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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);
|
||||
VMOVeD(v0, 1, v1, 0);
|
||||
} else {
|
||||
INST_NAME("MOVHPS Gx,Ex");
|
||||
INST_NAME("MOVHPS Gx, Ex");
|
||||
SMREAD();
|
||||
GETGX(v0, 1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
@@ -336,7 +335,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0x17:
|
||||
nextop = F8;
|
||||
INST_NAME("MOVHPS Ex,Gx");
|
||||
INST_NAME("MOVHPS Ex, Gx");
|
||||
GETGX(v0, 0);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 1);
|
||||
@@ -434,9 +433,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if(MODREG) {
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, ed);
|
||||
VMOVQ(v1, v0);
|
||||
DEFAULT;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VST128(v0, ed, fixedaddress);
|
||||
@@ -643,11 +640,11 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETEM(q1, 0);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
CMGT_0_8(v0, q1);
|
||||
VAND(v0, v0, q0);
|
||||
CMLT_0_8(v1, q1);
|
||||
VMUL_8(q0, q0, v1);
|
||||
VORR(q0, q0, v0);
|
||||
NEG_8(v0, q0); // get NEG
|
||||
CMLT_0_8(v1, q1); // calculate mask
|
||||
VBIF(v0, q0, v1); // put back positive values
|
||||
CMEQ_0_8(v1, q1); // handle case where Ex is 0
|
||||
VBIC(q0, v0, v1);
|
||||
break;
|
||||
case 0x09:
|
||||
INST_NAME("PSIGNW Gm,Em");
|
||||
@@ -656,11 +653,11 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETEM(q1, 0);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
CMGT_0_16(v0, q1);
|
||||
VAND(v0, v0, q0);
|
||||
CMLT_0_16(v1, q1);
|
||||
VMUL_16(q0, q0, v1);
|
||||
VORR(q0, q0, v0);
|
||||
NEG_16(v0, q0); // get NEG
|
||||
CMLT_0_16(v1, q1); // calculate mask
|
||||
VBIF(v0, q0, v1); // put back positive values
|
||||
CMEQ_0_16(v1, q1); // handle case where Ex is 0
|
||||
VBIC(q0, v0, v1);
|
||||
break;
|
||||
case 0x0A:
|
||||
INST_NAME("PSIGND Gm,Em");
|
||||
@@ -669,18 +666,21 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETEM(q1, 0);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
CMGT_0_32(v0, q1);
|
||||
VAND(v0, v0, q0);
|
||||
CMLT_0_32(v1, q1);
|
||||
VMUL_32(q0, q0, v1);
|
||||
VORR(q0, q0, v0);
|
||||
NEG_32(v0, q0); // get NEG
|
||||
CMLT_0_32(v1, q1); // calculate mask
|
||||
VBIF(v0, q0, v1); // put back positive values
|
||||
CMEQ_0_32(v1, q1); // handle case where Ex is 0
|
||||
VBIC(q0, v0, v1);
|
||||
break;
|
||||
case 0x0B:
|
||||
INST_NAME("PMULHRSW Gm,Em");
|
||||
nextop = F8;
|
||||
GETGM(q0);
|
||||
GETEM(q1, 0);
|
||||
SQRDMULH_16(q0, q0, q1);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
VSMULL_16(v0, q0, q1);
|
||||
SRSHRQ_32(v0, v0, 15);
|
||||
XTN_16(q0, v0);
|
||||
break;
|
||||
case 0x1C:
|
||||
INST_NAME("PABSB Gm,Em");
|
||||
@@ -1026,7 +1026,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GOCOND(0x40, "CMOV", "Gd, Ed");
|
||||
#undef GO
|
||||
case 0x50:
|
||||
INST_NAME("MOVMSPKPS Gd, Ex");
|
||||
INST_NAME("MOVMSKPS Gd, Ex");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
MOV32w(gd, 0);
|
||||
@@ -1047,14 +1047,13 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
// EX is memory
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, (0xfff<<3)-8, 7, rex, NULL, 0, 0);
|
||||
LDRx_U12(x1, ed, fixedaddress+0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0x3f<<3, 7, rex, NULL, 1, 0);
|
||||
LDPx_S7_offset(x1, x2, ed, fixedaddress);
|
||||
LSRx(x1, x1, 31);
|
||||
BFIx(gd, x1, 0, 1);
|
||||
LSRx(x1, x1, 32);
|
||||
BFIx(gd, x1, 1, 1);
|
||||
LDRx_U12(x1, ed, fixedaddress+8);
|
||||
LSRx(x1, x1, 31);
|
||||
LSRx(x1, x2, 31);
|
||||
BFIx(gd, x1, 2, 1);
|
||||
LSRx(x1, x1, 32);
|
||||
BFIx(gd, x1, 3, 1);
|
||||
@@ -1064,32 +1063,50 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("SQRTPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX_empty(v0);
|
||||
VFSQRTQS(v0, q0);
|
||||
GETGX_empty(q1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
VFCMEQQS(v0, q0, q0); // 0 if NAN, 1 if not NAN
|
||||
VFSQRTQS(q1, q0);
|
||||
VFCMEQQS(v1, q1, q1); // 0 => out is NAN
|
||||
VBICQ(v1, v0, v1); // forget it in any input was a NAN already
|
||||
VSHLQ_32(v1, v1, 31); // only keep the sign bit
|
||||
VORRQ(q1, q1, v1); // NAN -> -NAN
|
||||
} else {
|
||||
VFSQRTQS(q1, q0);
|
||||
}
|
||||
break;
|
||||
case 0x52:
|
||||
INST_NAME("RSQRTPS Gx, Ex");
|
||||
nextop = F8;
|
||||
SKIPTEST(x1);
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX_empty(q1);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
// more precise
|
||||
if(q1==q0)
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
else
|
||||
v1 = q1;
|
||||
VFRSQRTEQS(v0, q0);
|
||||
VFMULQS(v1, v0, q0);
|
||||
VFRSQRTSQS(v1, v1, v0);
|
||||
VFMULQS(q1, v1, v0);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
VFCMEQQS(d0, q0, q0); // 0 if NAN, 1 if not NAN
|
||||
}
|
||||
VFMOVSQ_8(v0, 0b01110000); //1.0f
|
||||
VFSQRTQS(q1, q0);
|
||||
VFDIVQS(q1, v0, q1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
VFCMEQQS(d1, q1, q1); // 0 => out is NAN
|
||||
VBICQ(d1, d0, d1); // forget it in any input was a NAN already
|
||||
VSHLQ_32(d1, d1, 31); // only keep the sign bit
|
||||
VORRQ(q1, q1, d1); // NAN -> -NAN
|
||||
}
|
||||
break;
|
||||
case 0x53:
|
||||
INST_NAME("RCPPS Gx, Ex");
|
||||
nextop = F8;
|
||||
SKIPTEST(x1);
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX_empty(q1);
|
||||
#if 0
|
||||
SKIPTEST(x1);
|
||||
if(q0 == q1)
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
else
|
||||
@@ -1098,6 +1115,11 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VFRECPEQS(v0, q0);
|
||||
VFRECPSQS(v1, v0, q0);
|
||||
VFMULQS(q1, v0, v1);
|
||||
#else
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
VFMOVSQ_8(v0, 0b01110000); //1.0f
|
||||
VFDIVQS(q1, v0, q0);
|
||||
#endif
|
||||
break;
|
||||
case 0x54:
|
||||
INST_NAME("ANDPS Gx, Ex");
|
||||
@@ -1178,7 +1200,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("CVTPS2PD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX(q1, 1);
|
||||
GETGX_empty(q1);
|
||||
FCVTL(q1, q0);
|
||||
break;
|
||||
case 0x5B:
|
||||
@@ -1215,11 +1237,12 @@ 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
|
||||
VFMINQS(v0, v0, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan) && (v0!=v1)) {
|
||||
if(BOX64ENV(dynarec_fastnan)) {
|
||||
VFMINQS(v0, v0, v1);
|
||||
} else {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
VFCMEQQS(q0, v0, v0); // 0 is NaN, 1 is not NaN, so MASK for NaN
|
||||
VBIFQ(v0, v1, q0); // copy dest where source is NaN
|
||||
VFCMGTQS(q0, v1, v0); // 0 is NaN or v1 GT v0, so invert mask for copy
|
||||
VBIFQ(v0, v1, q0);
|
||||
}
|
||||
break;
|
||||
case 0x5E:
|
||||
@@ -1248,12 +1271,13 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETGX(v0, 1);
|
||||
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
|
||||
VFMAXQS(v0, v0, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan) && (v0!=v1)) {
|
||||
// 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);
|
||||
VFCMEQQS(q0, v0, v0); // 0 is NaN, 1 is not NaN, so MASK for NaN
|
||||
VBIFQ(v0, v1, q0); // copy dest where source is NaN
|
||||
VFCMGTQS(q0, v0, v1); // 0 is NaN or v0 GT v1, so invert mask for copy
|
||||
VBIFQ(v0, v1, q0);
|
||||
}
|
||||
break;
|
||||
case 0x60:
|
||||
@@ -1925,7 +1949,7 @@ 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
|
||||
/* mapping is
|
||||
ARM -> X86
|
||||
0 -> 0 // Invalid operation
|
||||
1 -> 2 // Divide by 0
|
||||
@@ -1950,6 +1974,7 @@ 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);
|
||||
@@ -1961,7 +1986,6 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
//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");
|
||||
@@ -2062,11 +2086,13 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
wback = 0;
|
||||
UFLAG_IF {emit_cmp32(dyn, ninst, rex, xRAX, ed, x3, x4, x5);}
|
||||
MOVxw_REG(x1, ed); // save value
|
||||
SUBxw_REG(x4, xRAX, x1);
|
||||
CBNZxw_MARK(x4);
|
||||
MOVxw_REG(ed, gd);
|
||||
UFLAG_IF {
|
||||
emit_cmp32(dyn, ninst, rex, xRAX, ed, x3, x4, x5);
|
||||
} else {
|
||||
CMPSxw_REG(xRAX, ed);
|
||||
}
|
||||
MOVxw_REG(x1, ed); // save value
|
||||
CSELxw(ed, gd, ed, cEQ);
|
||||
} 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);
|
||||
@@ -2075,8 +2101,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
CBNZxw_MARK(x4);
|
||||
// EAX == Ed
|
||||
STxw(gd, wback, fixedaddress);
|
||||
MARK;
|
||||
}
|
||||
MARK;
|
||||
MOVxw_REG(xRAX, x1); // upper part of RAX will be erase on 32bits, no mater what
|
||||
break;
|
||||
|
||||
@@ -2308,11 +2334,17 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0xBC:
|
||||
INST_NAME("BSF Gd, Ed");
|
||||
SETFLAGS(X_ZF, SF_SET);
|
||||
if(!BOX64ENV(dynarec_safeflags) || BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_ZF, SF_SUBSET);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
}
|
||||
SET_DFNONE();
|
||||
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);
|
||||
@@ -2324,18 +2356,31 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MARK;
|
||||
IFX(X_ZF) {
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(x1, cEQ); //other flags are undefined
|
||||
BFIw(xFlags, x1, F_ZF, 1);
|
||||
CSETw(x2, cEQ); //other flags are undefined
|
||||
BFIw(xFlags, x2, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
if(BOX64ENV(dynarec_safeflags) && !BOX64ENV(cputype)) {
|
||||
IFX(X_CF) BFCw(xFlags, F_CF, 1);
|
||||
IFX(X_AF) BFCw(xFlags, F_AF, 1);
|
||||
IFX(X_SF) BFCw(xFlags, F_SF, 1);
|
||||
IFX(X_OF) BFCw(xFlags, F_OF, 1);
|
||||
IFX(X_PF) emit_pf(dyn, ninst, gd, x2);
|
||||
}
|
||||
break;
|
||||
case 0xBD:
|
||||
INST_NAME("BSR Gd, Ed");
|
||||
SETFLAGS(X_ZF, SF_SET);
|
||||
if(!BOX64ENV(dynarec_safeflags) || BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_ZF, SF_SUBSET);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
}
|
||||
SET_DFNONE();
|
||||
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);
|
||||
@@ -2348,10 +2393,17 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MARK;
|
||||
IFX(X_ZF) {
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(x1, cEQ); //other flags are undefined
|
||||
BFIw(xFlags, x1, F_ZF, 1);
|
||||
CSETw(x2, cEQ); //other flags are undefined
|
||||
BFIw(xFlags, x2, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
if(BOX64ENV(dynarec_safeflags) && !BOX64ENV(cputype)) {
|
||||
IFX(X_CF) BFCw(xFlags, F_CF, 1);
|
||||
IFX(X_AF) BFCw(xFlags, F_AF, 1);
|
||||
IFX(X_SF) BFCw(xFlags, F_SF, 1);
|
||||
IFX(X_OF) BFCw(xFlags, F_OF, 1);
|
||||
IFX(X_PF) emit_pf(dyn, ninst, gd, x2);
|
||||
}
|
||||
break;
|
||||
case 0xBE:
|
||||
INST_NAME("MOVSX Gd, Eb");
|
||||
@@ -2420,23 +2472,19 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0: VFCMEQQS(v0, v0, v1); break; // Equal
|
||||
case 1: VFCMGTQS(v0, v1, v0); break; // Less than
|
||||
case 2: VFCMGEQS(v0, v1, v0); break; // Less or equal
|
||||
case 3: VFCMEQQS(v0, v0, v0);
|
||||
if(v0!=v1) {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
VFCMEQQS(q0, v1, v1);
|
||||
VANDQ(v0, v0, q0);
|
||||
case 3: if(v0!=v1) {
|
||||
VFMAXQS(v0, v0, v1); // propagate NAN
|
||||
}
|
||||
VFCMEQQS(v0, v0, v0);
|
||||
VMVNQ(v0, v0);
|
||||
break; // NaN (NaN is not equal to himself)
|
||||
case 4: VFCMEQQS(v0, v0, v1); VMVNQ(v0, v0); break; // Not Equal (or unordered on ARM, not on X86...)
|
||||
case 5: VFCMGTQS(v0, v1, v0); VMVNQ(v0, v0); break; // Greater or equal or unordered
|
||||
case 6: VFCMGEQS(v0, v1, v0); VMVNQ(v0, v0); break; // Greater or unordered
|
||||
case 7: VFCMEQQS(v0, v0, v0);
|
||||
if(v0!=v1) {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
VFCMEQQS(q0, v1, v1);
|
||||
VANDQ(v0, v0, q0);
|
||||
case 7: if(v0!=v1) {
|
||||
VFMAXQS(v0, v0, v1); // propagate NAN
|
||||
}
|
||||
VFCMEQQS(v0, v0, v0);
|
||||
break; // not NaN
|
||||
}
|
||||
break;
|
||||
@@ -2804,11 +2852,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETGM(v0);
|
||||
GETEM(v1, 0);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
VUMULL_16(q0, v0, v1);
|
||||
VUMULL2_16(q1, v0, v1);
|
||||
UQSHRN_16(v0, q0, 16);
|
||||
UQSHRN2_16(v0, q1, 16);
|
||||
UQSHRN_16(v0, q0, 16); // saturation will never happens as only 16bits remain and fits in 16bits
|
||||
break;
|
||||
case 0xE5:
|
||||
INST_NAME("PMULHW Gm,Em");
|
||||
|
||||
@@ -5,16 +5,16 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
#include "../dynablock_private.h"
|
||||
#include "custommem.h"
|
||||
|
||||
#include "arm64_printer.h"
|
||||
@@ -217,7 +217,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
ADDz_REG(x4, x4, ed);
|
||||
VLD128(v0, ed, fixedaddress);
|
||||
VLD128(v0, x4, fixedaddress);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -264,7 +264,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
ADDz_REG(x4, x4, ed);
|
||||
VLD128(v0, ed, fixedaddress);
|
||||
VLD128(v0, x4, fixedaddress);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -1603,11 +1603,17 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
// 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;
|
||||
if(BOX64DRENV(dynarec_callret)>1)
|
||||
j64 = CALLRET_GETRET();
|
||||
else
|
||||
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 {
|
||||
j64 = (dyn->insts)?(GETMARK-(dyn->native_size)):0;
|
||||
if(BOX64DRENV(dynarec_callret)>1)
|
||||
j64 = CALLRET_GETRET();
|
||||
else
|
||||
j64 = (dyn->insts)?(GETMARK-(dyn->native_size)):0;
|
||||
ADR_S20(x4, j64);
|
||||
MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
|
||||
}
|
||||
@@ -1615,6 +1621,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
PUSH1z(xRIP);
|
||||
jump_to_next(dyn, 0, ed, ninst, rex.is32bits);
|
||||
if(BOX64DRENV(dynarec_callret)>1) CALLRET_RET();
|
||||
if (BOX64DRENV(dynarec_callret) && addr >= (dyn->start + dyn->isize)) {
|
||||
// jumps out of current dynablock...
|
||||
MARK;
|
||||
|
||||
@@ -5,14 +5,12 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "emu/x87emu_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
@@ -783,6 +781,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
CBZx_NEXT(xRCX);
|
||||
TBNZ_MARK2(xFlags, F_DF);
|
||||
IF_UNALIGNED(ip) {
|
||||
MESSAGE(LOG_DEBUG, "\tUnaligned path");
|
||||
// special optim for large RCX value on forward case only
|
||||
// but because it's unaligned path, check if a byte per byt is needed, and do 4-bytes per 4-bytes only instead
|
||||
if(BOX64DRENV(dynarec_safeflags)) {
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -5,10 +5,8 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
@@ -83,8 +81,7 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
SMREAD();
|
||||
ADDz_REG(x4, x4, ed);
|
||||
ed = x4;
|
||||
VLD128(v0, ed, fixedaddress);
|
||||
VLD128(v0, x4, fixedaddress);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -99,8 +96,7 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
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);
|
||||
ed = x4;
|
||||
VST128(v0, ed, fixedaddress);
|
||||
VST128(v0, x4, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
@@ -117,8 +113,7 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
ADDz_REG(x4, x4, ed);
|
||||
ed = x4;
|
||||
VST64(v0, ed, fixedaddress);
|
||||
VST64(v0, x4, fixedaddress);
|
||||
SMWRITE();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -5,10 +5,9 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
|
||||
@@ -5,10 +5,8 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
|
||||
@@ -5,10 +5,8 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
@@ -87,7 +85,15 @@ uintptr_t dynarec64_66F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
|
||||
case 0xBC:
|
||||
INST_NAME("TZCNT Gw, Ew");
|
||||
SETFLAGS(X_CF|X_ZF, SF_SUBSET);
|
||||
if(!BOX64ENV(dynarec_safeflags)) {
|
||||
SETFLAGS(X_CF|X_ZF, SF_SUBSET);
|
||||
} else {
|
||||
if(BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_ALL&~X_OF, SF_SUBSET);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
}
|
||||
}
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETEW(x1, 0);
|
||||
@@ -106,12 +112,26 @@ uintptr_t dynarec64_66F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
CSETw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_ZF, 1); // ZF = is dest 0?
|
||||
}
|
||||
if(BOX64ENV(dynarec_safeflags)) {
|
||||
IFX(X_AF) BFCw(xFlags, F_AF, 1);
|
||||
IFX(X_PF) BFCw(xFlags, F_PF, 1);
|
||||
IFX(X_SF) BFCw(xFlags, F_SF, 1);
|
||||
IFX2(X_OF, && !BOX64ENV(cputype)) BFCw(xFlags, F_OF, 1);
|
||||
}
|
||||
GWBACK;
|
||||
break;
|
||||
|
||||
case 0xBD:
|
||||
INST_NAME("LZCNT Gw, Ew");
|
||||
SETFLAGS(X_CF|X_ZF, SF_SUBSET);
|
||||
if(!BOX64ENV(dynarec_safeflags)) {
|
||||
SETFLAGS(X_CF|X_ZF, SF_SUBSET);
|
||||
} else {
|
||||
if(BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_ALL&~X_OF, SF_SUBSET);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
}
|
||||
}
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETEW(x1, 0);
|
||||
@@ -128,6 +148,12 @@ uintptr_t dynarec64_66F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
CSETw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_ZF, 1); // ZF = is dest 0?
|
||||
}
|
||||
if(BOX64ENV(dynarec_safeflags)) {
|
||||
IFX(X_AF) BFCw(xFlags, F_AF, 1);
|
||||
IFX(X_PF) BFCw(xFlags, F_PF, 1);
|
||||
IFX(X_SF) BFCw(xFlags, F_SF, 1);
|
||||
IFX2(X_OF, && !BOX64ENV(cputype)) BFCw(xFlags, F_OF, 1);
|
||||
}
|
||||
GWBACK;
|
||||
break;
|
||||
|
||||
|
||||
@@ -5,16 +5,15 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
#include "../dynablock_private.h"
|
||||
#include "custommem.h"
|
||||
|
||||
#include "arm64_printer.h"
|
||||
@@ -30,7 +29,7 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop;
|
||||
uint8_t gd, ed, wback, wb, wb1, wb2, gb1, gb2, eb1, eb2;
|
||||
uint8_t gd, ed, wback, wb, wb1, wb2, gb1, gb2, eb1, eb2, q0, q1;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
int8_t i8;
|
||||
@@ -198,6 +197,22 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x29:
|
||||
INST_NAME("MOVAPS Ex,Gx");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if(MODREG) {
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, ed);
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VST128(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x2E:
|
||||
// no special check...
|
||||
case 0x2F:
|
||||
@@ -748,6 +763,20 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x76:
|
||||
INST_NAME("PCMPEQD Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
if(MODREG) {
|
||||
q0 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
} else {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VLD128(q0, ed, fixedaddress);
|
||||
}
|
||||
VCMEQQ_32(v0, v0, q0);
|
||||
break;
|
||||
|
||||
case 0x7E:
|
||||
INST_NAME("MOVD Ed,Gx");
|
||||
nextop = F8;
|
||||
@@ -787,6 +816,27 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xEF:
|
||||
INST_NAME("PXOR Gx,Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG && ((nextop&7)+(rex.b<<3)==gd)) {
|
||||
// special case for PXOR Gx, Gx
|
||||
q0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VEORQ(q0, q0, q0);
|
||||
} else {
|
||||
q0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
if(MODREG) {
|
||||
q1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
} else {
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VLD128(q1, ed, fixedaddress);
|
||||
}
|
||||
VEORQ(q0, q0, q1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xFE:
|
||||
INST_NAME("PADDD Gx,Ex");
|
||||
nextop = F8;
|
||||
@@ -1675,11 +1725,17 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
// 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;
|
||||
if(BOX64DRENV(dynarec_callret)>1)
|
||||
j64 = CALLRET_GETRET();
|
||||
else
|
||||
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 {
|
||||
j64 = (dyn->insts)?(GETMARK-(dyn->native_size)):0;
|
||||
if(BOX64DRENV(dynarec_callret)>1)
|
||||
j64 = CALLRET_GETRET();
|
||||
else
|
||||
j64 = (dyn->insts)?(GETMARK-(dyn->native_size)):0;
|
||||
ADR_S20(x4, j64);
|
||||
MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
|
||||
}
|
||||
@@ -1687,6 +1743,7 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
PUSH1z(xRIP);
|
||||
jump_to_next(dyn, 0, ed, ninst, rex.is32bits);
|
||||
if(BOX64DRENV(dynarec_callret)>1) CALLRET_RET();
|
||||
if(BOX64DRENV(dynarec_callret) && addr >= (dyn->start + dyn->isize)) {
|
||||
// jumps out of current dynablock...
|
||||
MARK;
|
||||
|
||||
@@ -5,10 +5,8 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
|
||||
@@ -5,10 +5,8 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
@@ -61,6 +59,31 @@ uintptr_t dynarec64_67_32(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0x0F:
|
||||
opcode=F8;
|
||||
switch(opcode) {
|
||||
|
||||
case 0x29:
|
||||
INST_NAME("MOVAPS Ex,Gx");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if(MODREG) {
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, ed);
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
addr = geted16(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, 0);
|
||||
VST128(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 64:
|
||||
addr = dynarec64_6764_32(dyn, addr, ip, ninst, rex, rep, _FS, ok, need_epilog);
|
||||
break;
|
||||
|
||||
@@ -5,10 +5,9 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
@@ -117,12 +116,13 @@ uintptr_t dynarec64_67_AVX(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, (nextop&7)+(rex.b<<3));
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, ed);
|
||||
VMOV(v1, v0);
|
||||
YMM0((nextop&7)+(rex.b<<3));
|
||||
YMM0(ed);
|
||||
} else {
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VSTR64_U12(v0, ed, fixedaddress);
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VST64(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -146,9 +146,9 @@ uintptr_t dynarec64_67_AVX(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
}
|
||||
else {DEFAULT;}
|
||||
|
||||
if((*ok==-1) && (BOX64ENV(dynarec_log)>=LOG_INFO || BOX64DRENV(dynarec_dump) || BOX64ENV(dynarec_missing)==1))
|
||||
if(!dyn->size || BOX64ENV(dynarec_log)>LOG_INFO || BOX64DRENV(dynarec_dump)) {
|
||||
dynarec_log(LOG_NONE, "Dynarec unimplemented AVX opcode size %d prefix %s map %s opcode %02X ", 128<<vex.l, avx_prefix_string(vex.p), avx_map_string(vex.m), opcode);
|
||||
if((*ok==-1) && (BOX64ENV(dynarec_log)>=LOG_INFO || dyn->need_dump || BOX64ENV(dynarec_missing)==1))
|
||||
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;
|
||||
}
|
||||
@@ -1,14 +1,12 @@
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <ucontext.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "dynablock.h"
|
||||
#include "x64emu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "x64run.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "dynarec/dynablock_private.h"
|
||||
#include "dynarec_arm64_arch.h"
|
||||
@@ -156,7 +154,7 @@ static int arch_build(dynarec_arm_t* dyn, int ninst, arch_build_t* arch)
|
||||
arch->x87 = 1;
|
||||
arch->x87_.delta = dyn->insts[ninst].n.x87stack;
|
||||
}
|
||||
// opcode can handle unaligned
|
||||
// opcode can handle unaligned
|
||||
arch->unaligned = dyn->insts[ninst].unaligned;
|
||||
return arch->flags + arch->x87 + arch->mmx + arch->sse + arch->ymm + arch->unaligned;
|
||||
}
|
||||
@@ -234,12 +232,11 @@ void* populate_arch(dynarec_arm_t* dyn, void* p, size_t tot_sz)
|
||||
arch_build_t* build = static_build+i;
|
||||
if(i && (!memcmp(build, previous, sizeof(arch_build_t))) && (seq<((1<<10)-1))) {
|
||||
// same sequence, increment
|
||||
seq++;
|
||||
arch->seq = seq;
|
||||
arch->seq = ++seq;
|
||||
} else {
|
||||
int sz = sizeof_arch_build(build);
|
||||
if(total+sz>tot_sz) {
|
||||
printf_log(LOG_INFO, "Warning: populate_arch oversized\n");
|
||||
printf_log(LOG_INFO, "Warning: populate_arch on undersized buffer (%d+%d/%d, inst %d/%d)\n", total, sz, tot_sz, i, dyn->size);
|
||||
return NULL;
|
||||
}
|
||||
arch = next;
|
||||
@@ -253,8 +250,6 @@ void* populate_arch(dynarec_arm_t* dyn, void* p, size_t tot_sz)
|
||||
return p;
|
||||
}
|
||||
|
||||
int getX64AddressInst(dynablock_t* db, uintptr_t x64pc); // define is signal.c
|
||||
|
||||
// NZCV N
|
||||
#define NZCV_N 31
|
||||
// NZCV Z
|
||||
@@ -264,6 +259,7 @@ int getX64AddressInst(dynablock_t* db, uintptr_t x64pc); // define is signal.c
|
||||
// NZCV V
|
||||
#define NZCV_V 28
|
||||
|
||||
#ifndef _WIN32 // TODO: Implemented this for Win32
|
||||
void adjust_arch(dynablock_t* db, x64emu_t* emu, ucontext_t* p, uintptr_t x64pc)
|
||||
{
|
||||
if(!db->arch_size || !db->arch)
|
||||
@@ -289,7 +285,7 @@ void adjust_arch(dynablock_t* db, x64emu_t* emu, ucontext_t* p, uintptr_t x64pc)
|
||||
while(i<ninst-1) {
|
||||
arch = next;
|
||||
i += 1+arch->seq;
|
||||
dynarec_log_prefix(0, LOG_INFO, "[ seq=%d%s%s%s%s%s ] ", arch->seq, arch->flags?" Flags":"", arch->x87?" x87":"", arch->mmx?" MMX":"", arch->sse?" SSE":"", arch->ymm?" YMM":"");
|
||||
dynarec_log_prefix(0, (i<ninst-1)?LOG_DEBUG:LOG_INFO, "[ seq=%d%s%s%s%s%s ] ", arch->seq, arch->flags?" Flags":"", arch->x87?" x87":"", arch->mmx?" MMX":"", arch->sse?" SSE":"", arch->ymm?" YMM":"");
|
||||
next = (arch_arch_t*)((uintptr_t)next + sizeof_arch(arch));
|
||||
}
|
||||
int sz = sizeof(arch_arch_t);
|
||||
@@ -394,6 +390,7 @@ void adjust_arch(dynablock_t* db, x64emu_t* emu, ucontext_t* p, uintptr_t x64pc)
|
||||
}
|
||||
dynarec_log_prefix(0, LOG_INFO, "\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
int arch_unaligned(dynablock_t* db, uintptr_t x64pc)
|
||||
{
|
||||
|
||||
@@ -2,19 +2,23 @@
|
||||
#define __DYNAREC_ARM_ARCH_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <ucontext.h>
|
||||
|
||||
#include "x64emu.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
|
||||
// get size of arch specific info (can be 0)
|
||||
size_t get_size_arch(dynarec_arm_t* dyn);
|
||||
//populate the array
|
||||
void* populate_arch(dynarec_arm_t* dyn, void* p, size_t sz);
|
||||
#ifndef _WIN32
|
||||
#include <ucontext.h>
|
||||
//adjust flags and more
|
||||
void adjust_arch(dynablock_t* db, x64emu_t* emu, ucontext_t* p, uintptr_t x64pc);
|
||||
#else
|
||||
#define adjust_arch(db, emu, p, x64pc)
|
||||
#endif
|
||||
// get if instruction can be regenerated for unaligned access
|
||||
int arch_unaligned(dynablock_t* db, uintptr_t x64pc);
|
||||
#endif // __DYNAREC_ARM_ARCH_H__
|
||||
@@ -5,10 +5,8 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
@@ -71,9 +69,9 @@ uintptr_t dynarec64_AVX(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
addr = dynarec64_AVX_F3_0F38(dyn, addr, ip, ninst, vex, ok, need_epilog);
|
||||
else {DEFAULT;}
|
||||
|
||||
if((*ok==-1) && (BOX64ENV(dynarec_log)>=LOG_INFO || BOX64DRENV(dynarec_dump) || BOX64ENV(dynarec_missing)==1))
|
||||
if(!dyn->size || BOX64ENV(dynarec_log)>LOG_INFO || BOX64DRENV(dynarec_dump)) {
|
||||
dynarec_log(LOG_NONE, "Dynarec unimplemented AVX opcode size %d prefix %s map %s opcode %02X ", 128<<vex.l, avx_prefix_string(vex.p), avx_map_string(vex.m), opcode);
|
||||
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;
|
||||
}
|
||||
@@ -5,10 +5,8 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
@@ -81,11 +79,13 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0xffe<<4, 15, rex, NULL, 0, 0);
|
||||
VLDR128_U12(v0, ed, fixedaddress); // no alignment issue with ARMv8 NEON :)
|
||||
if(vex.l) {
|
||||
v0 = ymm_get_reg_empty(dyn, ninst, x1, gd, -1, -1, -1);
|
||||
VLDR128_U12(v0, ed, fixedaddress+16);
|
||||
v1 = ymm_get_reg_empty(dyn, ninst, x1, gd, -1, -1, -1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &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); // no alignment issue with ARMv8 NEON :)
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
@@ -103,13 +103,15 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
v0 = ymm_get_reg(dyn, ninst, x1, gd, 0, ed, -1, -1);
|
||||
v1 = ymm_get_reg_empty(dyn, ninst, x1, ed, gd, -1, -1);
|
||||
VMOVQ(v1, v0);
|
||||
}
|
||||
} else YMM0(ed);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0xffe<<4, 15, rex, NULL, 0, 0);
|
||||
VSTR128_U12(v0, ed, fixedaddress);
|
||||
if(vex.l) {
|
||||
v0 = ymm_get_reg(dyn, ninst, x1, gd, 0, ed, -1, -1);
|
||||
VSTR128_U12(v0, ed, fixedaddress+16);
|
||||
v1 = ymm_get_reg(dyn, ninst, x1, gd, 0, ed, -1, -1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0x3f<<4, 15, rex, NULL, 1, 0);
|
||||
VSTP128_I7(v0, v1, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VST128(v0, ed, fixedaddress);
|
||||
}
|
||||
SMWRITE2();
|
||||
}
|
||||
@@ -139,17 +141,14 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
break;
|
||||
case 0x13:
|
||||
nextop = F8;
|
||||
INST_NAME("VMOVLPS Ex, Vx, Gx");
|
||||
INST_NAME("VMOVLPS Ex, Gx");
|
||||
GETGX(v0, 0);
|
||||
GETVX(v2, 0);
|
||||
if(v1!=v2)
|
||||
VMOVQ(v0, v2);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 1);
|
||||
if(v0!=v1) VMOVeD(v1, 0, v0, 0);
|
||||
DEFAULT;
|
||||
return addr;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
VST1_64(v0, 0, ed); // better to use VST1 than VSTR_64, to avoid NEON->VFPU transfert I assume
|
||||
VST1_64(v0, 0, ed);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
@@ -197,15 +196,18 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x17:
|
||||
INST_NAME("VMOVHPS Ex,Gx");
|
||||
INST_NAME("VMOVHPS Ex, Gx");
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 1);
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
v1 = sse_get_reg(dyn, ninst, x1, ed, 1);
|
||||
VMOVeD(v1, 0, v0, 1);
|
||||
YMM0(ed);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
VST1_64(v0, 1, ed);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -225,11 +227,13 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0xffe<<4, 15, rex, NULL, 0, 0);
|
||||
VLDR128_U12(v0, ed, fixedaddress);
|
||||
if(vex.l) {
|
||||
GETGY_empty(v0, -1, -1, -1);
|
||||
VLDR128_U12(v0, ed, fixedaddress+16);
|
||||
GETGY_empty(v1, -1, -1, -1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0x3f<<4, 15, rex, NULL, 1, 0);
|
||||
VLDP128_I7(v0, v1, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VLD128(v0, ed, fixedaddress);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
@@ -246,13 +250,15 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
if(vex.l) {
|
||||
GETGYEY_empty(v0, v1);
|
||||
VMOVQ(v1, v0);
|
||||
}
|
||||
} else YMM0(ed);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0xffe<<4, 15, rex, NULL, 0, 0);
|
||||
VSTR128_U12(v0, ed, fixedaddress);
|
||||
if(vex.l) {
|
||||
GETGY(v0, 0, -1, -1, -1);
|
||||
VSTR128_U12(v0, ed, fixedaddress+16);
|
||||
GETGY(v1, 0, -1, -1, -1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0x3f<<4, 15, rex, NULL, 1, 0);
|
||||
VSTP128_I7(v0, v1, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VST128(v0, ed, fixedaddress);
|
||||
}
|
||||
SMWRITE2();
|
||||
}
|
||||
@@ -270,13 +276,15 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
if(vex.l) {
|
||||
GETGYEY_empty(v0, v1);
|
||||
VMOVQ(v1, v0);
|
||||
}
|
||||
} else YMM0(ed);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0xffe<<4, 15, rex, NULL, 0, 0);
|
||||
VSTR128_U12(v0, ed, fixedaddress);
|
||||
if(vex.l) {
|
||||
GETGY(v0, 0, -1, -1, -1);
|
||||
VSTR128_U12(v0, ed, fixedaddress+16);
|
||||
GETGY(v1, 0, -1, -1, -1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0x3f<<4, 15, rex, NULL, 1, 0);
|
||||
VSTP128_I7(v0, v1, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VST128(v0, ed, fixedaddress);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -294,7 +302,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
break;
|
||||
|
||||
case 0x50:
|
||||
INST_NAME("VMOVMSPKPS Gd, Ex");
|
||||
INST_NAME("VMOVMSKPS Gd, Ex");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
MOV32w(gd, 0);
|
||||
@@ -317,15 +325,14 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
} else {
|
||||
// EX is memory
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, (0xfff<<3)-24, 7, rex, NULL, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, (0x3f<<3)-16, 7, rex, NULL, 1, 0);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
LDRx_U12(x1, ed, fixedaddress+16*l);
|
||||
LDPx_S7_offset(x1, x2, ed, fixedaddress+16*l);
|
||||
LSRx(x1, x1, 31);
|
||||
BFIx(gd, x1, 0+(l*4), 1);
|
||||
LSRx(x1, x1, 32);
|
||||
BFIx(gd, x1, 1+(l*4), 1);
|
||||
LDRx_U12(x1, ed, fixedaddress+8+16*l);
|
||||
LSRx(x1, x1, 31);
|
||||
LSRx(x1, x2, 31);
|
||||
BFIx(gd, x1, 2+(l*4), 1);
|
||||
LSRx(x1, x1, 32);
|
||||
BFIx(gd, x1, 3+(l*4), 1);
|
||||
@@ -336,9 +343,23 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
INST_NAME("VSQRTPS Gx, Ex");
|
||||
nextop = F8;
|
||||
SKIPTEST(x1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
}
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_EX(q0, q1, 0); } else { GETGY_empty_EY(q0, q1); }
|
||||
VFSQRTQS(q0, q1);
|
||||
if(!l) { GETGX_empty_EX(v0, v1, 0); } else { GETGY_empty_EY(v0, v1); }
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
// check if any input value was NAN
|
||||
VFCMEQQS(d0, v1, v1); // 0 if NAN, 1 if not NAN
|
||||
VFSQRTQS(v0, v1);
|
||||
VFCMEQQS(d1, v0, v0); // 0 => out is NAN
|
||||
VBICQ(d1, d0, d1); // forget it in any input was a NAN already
|
||||
VSHLQ_32(d1, d1, 31); // only keep the sign bit
|
||||
VORRQ(v0, v0, d1); // NAN -> -NAN
|
||||
} else {
|
||||
VFSQRTQS(v0, v1);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
@@ -539,10 +560,12 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
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
|
||||
VFMINQS(v0, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan) && (v2!=v1)) {
|
||||
VFCMEQQS(q0, v0, v0); // 0 is NaN, 1 is not NaN, so MASK for NaN
|
||||
VBIFQ(v0, v1, q0); // copy dest where source 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);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
@@ -581,10 +604,12 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
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
|
||||
VFMAXQS(v0, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan) && (v2!=v1)) {
|
||||
VFCMEQQS(q0, v0, v0); // 0 is NaN, 1 is not NaN, so MASK for NaN
|
||||
VBIFQ(v0, v1, q0); // copy dest where source 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);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
@@ -659,6 +684,7 @@ 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);
|
||||
@@ -670,7 +696,6 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
//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;
|
||||
@@ -683,7 +708,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 1); u8 = F8; } else { GETGY_empty_VYEY(v0, v2, v1); }
|
||||
if(((u8&15)==3) || ((u8&15)==7) || ((u8&15)==8) || ((u8&15)==9) || ((u8&15)==10) || ((u8&15)==12) || ((u8&15)==13) || ((u8&15)==14)) {
|
||||
if(((u8&15)==3) || ((u8&15)==7) || ((u8&15)==8) || ((u8&15)==9) || ((u8&15)==10) || ((u8&15)==12)) {
|
||||
VFMAXQS(q0, v2, v1); // propagate NAN
|
||||
VFCMEQQS(((u8&15)==7)?v0:q0, q0, q0); // 0 if NAN, 1 if not NAN
|
||||
}
|
||||
|
||||
@@ -5,10 +5,8 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
@@ -131,7 +129,9 @@ uintptr_t dynarec64_AVX_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, i
|
||||
BFIw(xFlags, x3, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_OF) IFNATIVE(NF_VF) {} else {BFCw(xFlags, F_OF, 1);}
|
||||
IFX(X_OF) {
|
||||
IFNATIVE(NF_VF) {} else { BFCw(xFlags, F_OF, 1); }
|
||||
}
|
||||
if (BOX64ENV(dynarec_test)) {
|
||||
IFX(X_AF) BFCw(xFlags, F_AF, 1);
|
||||
IFX(X_PF) BFCw(xFlags, F_PF, 1);
|
||||
@@ -168,7 +168,9 @@ uintptr_t dynarec64_AVX_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, i
|
||||
BFIw(xFlags, x3, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_OF) IFNATIVE(NF_VF) {} else {BFCw(xFlags, F_OF, 1);}
|
||||
IFX(X_OF) {
|
||||
IFNATIVE(NF_VF) {} else { BFCw(xFlags, F_OF, 1); }
|
||||
}
|
||||
if (BOX64ENV(dynarec_test)) {
|
||||
IFX(X_AF) BFCw(xFlags, F_AF, 1);
|
||||
IFX(X_PF) BFCw(xFlags, F_PF, 1);
|
||||
@@ -206,7 +208,9 @@ uintptr_t dynarec64_AVX_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, i
|
||||
BFIw(xFlags, x3, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_OF) IFNATIVE(NF_VF) {} else {BFCw(xFlags, F_OF, 1);}
|
||||
IFX(X_OF) {
|
||||
IFNATIVE(NF_VF) {} else { BFCw(xFlags, F_OF, 1); }
|
||||
}
|
||||
if (BOX64ENV(dynarec_test)) {
|
||||
IFX(X_AF) BFCw(xFlags, F_AF, 1);
|
||||
IFX(X_PF) BFCw(xFlags, F_PF, 1);
|
||||
@@ -257,7 +261,9 @@ uintptr_t dynarec64_AVX_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, i
|
||||
}
|
||||
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);}
|
||||
IFX(X_OF) {
|
||||
IFNATIVE(NF_VF) {} else { BFCw(xFlags, F_OF, 1); }
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xF7:
|
||||
@@ -291,8 +297,12 @@ uintptr_t dynarec64_AVX_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, i
|
||||
IFX(X_AF) BFCw(xFlags, F_AF, 1);
|
||||
IFX(X_PF) BFCw(xFlags, F_PF, 1);
|
||||
IFX(X_CF) BFCw(xFlags, F_CF, 1);
|
||||
IFX(X_OF) IFNATIVE(NF_VF) {} else {BFCw(xFlags, F_OF, 1);}
|
||||
IFX(X_SF) IFNATIVE(NF_SF) {} else {BFCw(xFlags, F_SF, 1);}
|
||||
IFX(X_OF) {
|
||||
IFNATIVE(NF_VF) {} else { BFCw(xFlags, F_OF, 1); }
|
||||
}
|
||||
IFX(X_SF) {
|
||||
IFNATIVE(NF_SF) {} else { BFCw(xFlags, F_SF, 1); }
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -5,10 +5,8 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
@@ -78,11 +76,13 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
} else {
|
||||
SMREAD();
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0xffe<<4, 15, rex, NULL, 0, 0);
|
||||
VLDR128_U12(v0, ed, fixedaddress);
|
||||
if(vex.l) {
|
||||
GETGY_empty(v0, -1, -1, -1);
|
||||
VLDR128_U12(v0, ed, fixedaddress+16);
|
||||
GETGY_empty(v1, -1, -1, -1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &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);
|
||||
@@ -93,18 +93,21 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, (nextop&7)+(rex.b<<3));
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, ed);
|
||||
VMOVQ(v1, v0);
|
||||
if(vex.l) {
|
||||
GETGYEY_empty(v0, v1);
|
||||
VMOVQ(v1, v0);
|
||||
}
|
||||
} else YMM0(ed);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0xffe<<4, 15, rex, NULL, 0, 0);
|
||||
VSTR128_U12(v0, ed, fixedaddress);
|
||||
if(vex.l) {
|
||||
GETGY(v0, 0, -1, -1, -1);
|
||||
VSTR128_U12(v0, ed, fixedaddress+16);
|
||||
GETGY(v1, 0, -1, -1, -1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0x3f<<4, 15, rex, NULL, 1, 0);
|
||||
VSTP128_I7(v0, v1, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VST128(v0, ed, fixedaddress);
|
||||
}
|
||||
SMWRITE2();
|
||||
}
|
||||
@@ -118,14 +121,11 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
return addr;
|
||||
}
|
||||
GETGX_empty_VX(v0, v2);
|
||||
if(v0==v2) {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
VMOVQ(q0, v2);
|
||||
}
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
VLD1_64(v0, 0, ed);
|
||||
VMOVeD(v0, 1, (v0==v2)?q0:v2, 1);
|
||||
if(v0!=v2)
|
||||
VMOVeD(v0, 1, v2, 1);
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x13:
|
||||
@@ -168,25 +168,22 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
return addr;
|
||||
}
|
||||
GETGX_empty_VX(v0, v2);
|
||||
if(v0==v2) {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
VMOVQ(q0, v2);
|
||||
}
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
VLD1_64(v0, 1, ed);
|
||||
VMOVeD(v0, 0, (v0==v2)?q0:v2, 0);
|
||||
if(v0!=v2)
|
||||
VMOVeD(v0, 0, v2, 0);
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x17:
|
||||
INST_NAME("VMOVHPD Eq, Gx");
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
if(MODREG) {
|
||||
// access register instead of memory is bad opcode!
|
||||
DEFAULT;
|
||||
return addr;
|
||||
}
|
||||
GETGX(v0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
VST1_64(v0, 1, ed);
|
||||
SMWRITE2();
|
||||
@@ -207,11 +204,13 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
} else {
|
||||
SMREAD();
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0xffe<<4, 15, rex, NULL, 0, 0);
|
||||
VLDR128_U12(v0, ed, fixedaddress);
|
||||
if(vex.l) {
|
||||
GETGY_empty(v0, -1, -1, -1);
|
||||
VLDR128_U12(v0, ed, fixedaddress+16);
|
||||
GETGY_empty(v1, -1, -1, -1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &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);
|
||||
@@ -222,18 +221,21 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, (nextop&7)+(rex.b<<3));
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, ed);
|
||||
VMOVQ(v1, v0);
|
||||
if(vex.l) {
|
||||
GETGYEY_empty(v0, v1);
|
||||
VMOVQ(v1, v0);
|
||||
}
|
||||
} else YMM0(ed);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0xffe<<4, 15, rex, NULL, 0, 0);
|
||||
VSTR128_U12(v0, ed, fixedaddress);
|
||||
if(vex.l) {
|
||||
GETGY(v0, 0, -1, -1, -1);
|
||||
VSTR128_U12(v0, ed, fixedaddress+16);
|
||||
GETGY(v1, 0, -1, -1, -1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0x3f<<4, 15, rex, NULL, 1, 0);
|
||||
VSTP128_I7(v0, v1, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VST128(v0, ed, fixedaddress);
|
||||
}
|
||||
SMWRITE2();
|
||||
}
|
||||
@@ -243,20 +245,17 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
INST_NAME("VMOVNTPD Ex,Gx");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, (nextop&7)+(rex.b<<3));
|
||||
VMOVQ(v1, v0);
|
||||
if(vex.l) {
|
||||
GETGYEY_empty(v0, v1);
|
||||
VMOVQ(v1, v0);
|
||||
}
|
||||
DEFAULT;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0xffe<<4, 15, rex, NULL, 0, 0);
|
||||
VSTR128_U12(v0, ed, fixedaddress);
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if(vex.l) {
|
||||
GETGY(v0, 0, -1, -1, -1);
|
||||
VSTR128_U12(v0, ed, fixedaddress+16);
|
||||
GETGY(v1, 0, -1, -1, -1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0x3f<<4, 15, rex, NULL, 1, 0);
|
||||
VSTP128_I7(v0, v1, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VST128(v0, ed, fixedaddress);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -286,10 +285,9 @@ 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);
|
||||
LSRx(x1, x1, 63);
|
||||
LSRx(x2, x2, 63);
|
||||
BFIx(gd, x1, 2, 1);
|
||||
BFIx(gd, x2, 3, 1);
|
||||
BFIx(x1, x2, 63, 1);
|
||||
RORx(x2, x1, 63);
|
||||
BFIx(gd, x2, 2, 2);
|
||||
}
|
||||
break;
|
||||
case 0x51:
|
||||
@@ -437,7 +435,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
MOVI_32_lsl(d1, 0x80, 3);
|
||||
}
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETEX_Y(v1, 0, 0); GETGX_empty(v0); } else { GETGY_empty_EY(v0, v1); }
|
||||
if(!l) { GETGX_empty_EX(v0, v1, 0); } else { GETGY_empty_EY(v0, v1); }
|
||||
if(BOX64ENV(dynarec_fastround)) {
|
||||
VFRINTISQ(v0, v1);
|
||||
VFCVTZSQS(v0, v0);
|
||||
@@ -450,8 +448,12 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
for(int i=0; i<4; ++i) {
|
||||
BFCx(x5, FPSR_IOC, 1); // reset IOC bits
|
||||
MSR_fpsr(x5);
|
||||
VMOVeS(d0, 0, v1, i);
|
||||
FRINTIS(d0, d0);
|
||||
if(i) {
|
||||
VMOVeS(d0, 0, v1, i);
|
||||
FRINTIS(d0, d0);
|
||||
} else {
|
||||
FRINTIS(d0, v1);
|
||||
}
|
||||
VFCVTZSs(d0, d0);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TSTw_mask(x5, 0, 0); // mask=(1<<IOC)
|
||||
@@ -497,10 +499,12 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
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
|
||||
VFMINQD(v0, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan) && (v2!=v1)) {
|
||||
VFCMEQQD(q0, v0, v0); // 0 is NaN, 1 is not NaN, so MASK for NaN
|
||||
VBIFQ(v0, v1, q0); // copy dest where source 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);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
@@ -532,17 +536,18 @@ 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)) {
|
||||
if(!BOX64ENV(dynarec_fastnan))
|
||||
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
|
||||
VFMAXQD(v0, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan) && (v2!=v1)) {
|
||||
VFCMEQQD(q0, v0, v0); // 0 is NaN, 1 is not NaN, so MASK for NaN
|
||||
VBIFQ(v0, v1, q0); // copy dest where source 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);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
@@ -770,8 +775,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
INST_NAME("VMOVDQA Gx, Ex");
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
GETGX_empty(v0);
|
||||
GETGX_empty_EX(v0, v1, 0);
|
||||
VMOVQ(v0, v1);
|
||||
if(vex.l) {
|
||||
GETGY_empty_EY(v0, v1);
|
||||
@@ -780,11 +784,13 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
} else {
|
||||
GETGX_empty(v0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0xffe<<4, 15, rex, NULL, 0, 0);
|
||||
VLDR128_U12(v0, ed, fixedaddress);
|
||||
if(vex.l) {
|
||||
GETGY_empty(v0, -1, -1, -1);
|
||||
VLDR128_U12(v0, ed, fixedaddress+16);
|
||||
GETGY_empty(v1, -1, -1, -1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0x3f<<4, 15, rex, NULL, 1, 0);
|
||||
VLDP128_I7(v0, v1, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VLD128(v0, ed, fixedaddress);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
@@ -792,58 +798,121 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
case 0x70:
|
||||
INST_NAME("VPSHUFD Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
u8 = F8;
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(MODREG) {
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
if(!l)
|
||||
v1 = sse_get_reg(dyn, ninst, x1, ed, 0);
|
||||
else
|
||||
v1 = ymm_get_reg(dyn, ninst, x1, ed, 0, gd, -1, -1);
|
||||
|
||||
} else {
|
||||
ed = -1;
|
||||
if(!l) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
GETGX_empty(v0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 1);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
} else {
|
||||
GETGY_empty_EY(v0, v1);
|
||||
ADDx_U12(x1, wback, 16);
|
||||
wback = x1;
|
||||
}
|
||||
if(u8==0x4E) {
|
||||
if(v0==v1) {
|
||||
VEXTQ_8(v0, v0, v0, 8);
|
||||
} else {
|
||||
VMOVeD(v0, 0, v1, 1);
|
||||
VMOVeD(v0, 1, v1, 0);
|
||||
}
|
||||
if(!l) {
|
||||
u8 = F8;
|
||||
GETGX_empty(v0);
|
||||
} else {
|
||||
GETGY_empty(v0, ed, -1, -1);
|
||||
}
|
||||
switch(u8) {
|
||||
case 0x4E: // Swap Up/Lower 64bits parts
|
||||
if(!MODREG)
|
||||
VLDR128_U12(v1, wback, 0);
|
||||
VEXTQ_8(v0, v1, v1, 8);
|
||||
break;
|
||||
case 0x00: // duplicate lower 32bits to all spot
|
||||
if(MODREG)
|
||||
VDUPQ_32(v0, v1, 0);
|
||||
else
|
||||
VLDQ1R_32(v0, wback);
|
||||
break;
|
||||
case 0x55: // duplicate slot 1 to all spot
|
||||
if(MODREG)
|
||||
VDUPQ_32(v0, v1, 1);
|
||||
else {
|
||||
ADDx_U12(x2, wback, 4);
|
||||
VLDQ1R_32(v0, x2);
|
||||
}
|
||||
} else if(u8==0x00) {
|
||||
VDUPQ_32(v0, v1, 0);
|
||||
} else if(u8==0x55) {
|
||||
VDUPQ_32(v0, v1, 1);
|
||||
} else if(u8==0xAA) {
|
||||
VDUPQ_32(v0, v1, 2);
|
||||
} else if(u8==0xFF) {
|
||||
VDUPQ_32(v0, v1, 3);
|
||||
} else if(u8==0x44) {
|
||||
VDUPQ_64(v0, v1, 0);
|
||||
} else if(u8==0xEE) {
|
||||
VDUPQ_64(v0, v1, 1);
|
||||
} else if(u8==0xB1) {
|
||||
break;
|
||||
case 0xAA: // duplicate slot 2 to all spot
|
||||
if(MODREG)
|
||||
VDUPQ_32(v0, v1, 2);
|
||||
else {
|
||||
ADDx_U12(x2, wback, 8);
|
||||
VLDQ1R_32(v0, x2);
|
||||
}
|
||||
break;
|
||||
case 0xFF: // duplicate slot 3 to all spot
|
||||
if(MODREG)
|
||||
VDUPQ_32(v0, v1, 3);
|
||||
else {
|
||||
ADDx_U12(x2, wback, 12);
|
||||
VLDQ1R_32(v0, x2);
|
||||
}
|
||||
break;
|
||||
case 0x44: // duplicate slot 0/1 to all spot
|
||||
if(MODREG)
|
||||
VDUPQ_64(v0, v1, 0);
|
||||
else
|
||||
VLDQ1R_64(v0, wback);
|
||||
break;
|
||||
case 0xEE: // duplicate slot 2/3 to all spot
|
||||
if(MODREG)
|
||||
VDUPQ_64(v0, v1, 1);
|
||||
else {
|
||||
ADDx_U12(x2, wback, 8);
|
||||
VLDQ1R_64(v0, x2);
|
||||
}
|
||||
break;
|
||||
case 0xB1: // invert 0/1 and 2/3
|
||||
if(!MODREG)
|
||||
VLDR128_U12(v1, wback, 0);
|
||||
VREV64Q_32(v0, v1);
|
||||
} else if(u8==0xFA) {
|
||||
VZIP2Q_32(v0, v1, v1);
|
||||
} else if(u8==0x50) {
|
||||
VZIP1Q_32(v0, v1, v1);
|
||||
} else if(u8==0xF5) {
|
||||
VTRNQ2_32(v0, v1, v1);
|
||||
} else if(u8==0xA0) {
|
||||
VTRNQ1_32(v0, v1, v1);
|
||||
} else if(v0!=v1) {
|
||||
VMOVeS(v0, 0, v1, (u8>>(0*2))&3);
|
||||
VMOVeS(v0, 1, v1, (u8>>(1*2))&3);
|
||||
VMOVeS(v0, 2, v1, (u8>>(2*2))&3);
|
||||
VMOVeS(v0, 3, v1, (u8>>(3*2))&3);
|
||||
} else {
|
||||
if(!l) {
|
||||
break;
|
||||
case 0x39: // 0 3 2 1: ror 32 bits
|
||||
if(!MODREG)
|
||||
VLDR128_U12(v1, wback, 0);
|
||||
VEXTQ_8(v0, v1, v1, 4);
|
||||
break;
|
||||
case 0x93: // 2 1 0 3: 0 3 2 1: ror 32 bits then invert low/high 64bits
|
||||
if(!MODREG)
|
||||
VLDR128_U12(v1, wback, 0);
|
||||
VEXTQ_8(v0, v1, v1, 4);
|
||||
VEXTQ_8(v0, v0, v0, 8);
|
||||
break;
|
||||
default:
|
||||
if(!MODREG) {
|
||||
i32 = -1;
|
||||
for (int i=0; i<4; ++i) {
|
||||
int32_t idx = (u8>>(i*2))&3;
|
||||
if(idx!=i32) {
|
||||
ADDx_U12(x2, wback, idx*4);
|
||||
i32 = idx;
|
||||
}
|
||||
VLD1_32(v0, i, x2);
|
||||
}
|
||||
} else if(v0!=v1) {
|
||||
VMOVeS(v0, 0, v1, (u8>>(0*2))&3);
|
||||
VMOVeS(v0, 1, v1, (u8>>(1*2))&3);
|
||||
VMOVeS(v0, 2, v1, (u8>>(2*2))&3);
|
||||
VMOVeS(v0, 3, v1, (u8>>(3*2))&3);
|
||||
} else {
|
||||
uint64_t swp[4] = {
|
||||
(0)|(1<<8)|(2<<16)|(3<<24),
|
||||
(4)|(5<<8)|(6<<16)|(7<<24),
|
||||
(8)|(9<<8)|(10<<16)|(11<<24),
|
||||
(12)|(13<<8)|(14<<16)|(15<<24)
|
||||
};
|
||||
if(!l) d0 = fpu_get_scratch(dyn, ninst);
|
||||
tmp64u = swp[(u8>>(0*2))&3] | (swp[(u8>>(1*2))&3]<<32);
|
||||
MOV64x(x2, tmp64u);
|
||||
VMOVQDfrom(d0, 0, x2);
|
||||
@@ -854,35 +923,8 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
MOV64x(x3, tmp64u2);
|
||||
VMOVQDfrom(d0, 1, x3);
|
||||
}
|
||||
VTBLQ1_8(v0, v1, d0);
|
||||
}
|
||||
VTBLQ1_8(v0, v1, d0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
SMREAD();
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
i32 = -1;
|
||||
if(!l) {
|
||||
GETGX_empty(v0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 1);
|
||||
u8 = F8;
|
||||
} else {
|
||||
GETGY_empty(v0, -1, -1, -1);
|
||||
ADDx_U12(x3, ed, 16);
|
||||
ed = x3;
|
||||
}
|
||||
if (u8) {
|
||||
for (int i=0; i<4; ++i) {
|
||||
int32_t idx = (u8>>(i*2))&3;
|
||||
if(idx!=i32) {
|
||||
ADDx_U12(x2, ed, idx*4);
|
||||
i32 = idx;
|
||||
}
|
||||
VLD1_32(v0, i, x2);
|
||||
}
|
||||
} else {
|
||||
VLDQ1R_32(v0, ed);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
@@ -907,8 +949,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
case 4:
|
||||
INST_NAME("VPSRAW Vx, Ex, Ib");
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETVX_empty_EX(v0, v1, 1); u8 = F8; } else { GETVY_empty_EY(v0, v1); }
|
||||
if(u8>15) u8=15;
|
||||
if(!l) { GETVX_empty_EX(v0, v1, 1); u8 = F8; if(u8>15) u8=15;} else { GETVY_empty_EY(v0, v1); }
|
||||
if(u8) {
|
||||
VSSHRQ_16(v0, v1, u8);
|
||||
} else if(v0!=v1) VMOVQ(v0, v1);
|
||||
@@ -963,10 +1004,10 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
if(!l) {
|
||||
GETVX_empty_EX(v0, v1, 1);
|
||||
u8 = F8;
|
||||
if(u8>31) u8=31;
|
||||
} else {
|
||||
GETVY_empty_EY(v0, v1);
|
||||
}
|
||||
if(u8>31) u8=31;
|
||||
if(u8) {
|
||||
VSSHRQ_32(v0, v1, u8);
|
||||
} else if(v0!=v1)
|
||||
@@ -1133,10 +1174,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
// check if any input value was NAN
|
||||
// but need to mix low/high part
|
||||
VTRNQ1_64(q0, v2, v1);
|
||||
VTRNQ2_64(q1, v2, v1);
|
||||
VFMAXQD(q0, q0, q1); // propagate NAN
|
||||
VFMAXPQD(q0, v2, v1); // propagate NAN
|
||||
VFCMEQQD(q0, q0, q0); // 0 if NAN, 1 if not NAN
|
||||
}
|
||||
VFADDPQD(v0, v2, v1);
|
||||
@@ -1149,7 +1187,32 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0x7D:
|
||||
INST_NAME("VHSUBPD Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
if(!BOX64ENV(dynarec_fastnan))
|
||||
q1 = 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); }
|
||||
VUZP1Q_64(q0, v2, v1);
|
||||
VUZP2Q_64(v0, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
// check if any input value was NAN
|
||||
// but need to mix low/high part
|
||||
VFMAXQD(q1, v0, q0); // propagate NAN
|
||||
VFCMEQQD(q1, q1, q1); // 0 if NAN, 1 if not NAN
|
||||
}
|
||||
VFSUBQD(v0, q0, v0);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
VFCMEQQD(q0, v0, v0); // 0 => out is NAN
|
||||
VBICQ(q1, q1, q0); // forget it in any input was a NAN already
|
||||
VSHLQ_64(q1, q1, 63); // only keep the sign bit
|
||||
VORRQ(v0, v0, q1); // NAN -> -NAN
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x7E:
|
||||
INST_NAME("VMOVD Ed,Gx");
|
||||
nextop = F8;
|
||||
@@ -1179,18 +1242,21 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 1);
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
v1 = sse_get_reg(dyn, ninst, x1, ed, 1);
|
||||
VMOVQ(v1, v0);
|
||||
if(vex.l) {
|
||||
GETGYEY(v0, v1);
|
||||
VMOVQ(v1, v0);
|
||||
}
|
||||
} else YMM0(ed);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xffe<<4, 15, rex, NULL, 0, 0);
|
||||
VST128(v0, ed, fixedaddress);
|
||||
if(vex.l) {
|
||||
GETGY(v0, 0, -1, -1, -1);
|
||||
VST128(v0, ed, fixedaddress+16);
|
||||
GETGY(v1, 0, -1, -1, -1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0x3f<<4, 15, rex, NULL, 1, 0);
|
||||
VSTP128_I7(v0, v1, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VST128(v0, ed, fixedaddress);
|
||||
}
|
||||
SMWRITE2();
|
||||
}
|
||||
@@ -1202,7 +1268,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 1); u8 = F8; } else { GETGY_empty_VYEY(v0, v2, v1); }
|
||||
if(((u8&15)==3) || ((u8&15)==7) || ((u8&15)==8) || ((u8&15)==9) || ((u8&15)==10) || ((u8&15)==12) || ((u8&15)==13) || ((u8&15)==14)) {
|
||||
if(((u8&15)==3) || ((u8&15)==7) || ((u8&15)==8) || ((u8&15)==9) || ((u8&15)==10) || ((u8&15)==12)) {
|
||||
VFMAXQD(q0, v2, v1); // propagate NAN
|
||||
VFCMEQQD(((u8&15)==7)?v0:q0, q0, q0); // 0 if NAN, 1 if not NAN
|
||||
}
|
||||
@@ -1304,15 +1370,14 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
nextop = F8;
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEX(v1, 0, 0);
|
||||
MOVI_32(q1, 16);
|
||||
UQXTN_32(q0, v1);
|
||||
UMIN_32(q0, q0, q1); // limit to 0 .. +16 values
|
||||
NEG_32(q0, q0); // neg to do shr
|
||||
VDUPQ_16(q0, q0, 0); // only the low 8bits will be used anyway
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VY(v0, v2, 0, -1, -1); }
|
||||
if(!l) {
|
||||
UQXTN_32(q0, v1);
|
||||
UMIN_32(q0, q0, q1); // limit to 0 .. +16 values
|
||||
NEG_32(q0, q0); // neg to do shr
|
||||
VDUPQ_16(q0, q0, 0); // only the low 8bits will be used anyway
|
||||
}
|
||||
if(!l) { GETGX_empty_VX(v0, v2); } else { GETGY_empty_VY(v0, v2, 0, -1, -1); }
|
||||
USHLQ_16(v0, v2, q0); // SHR x8
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
@@ -1322,15 +1387,14 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
nextop = F8;
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEX(v1, 0, 0);
|
||||
MOVI_32(q1, 32);
|
||||
UQXTN_32(q0, v1);
|
||||
UMIN_32(q0, q0, q1); // limit to 0 .. +32 values
|
||||
NEG_32(q0, q0); // neg to do shr
|
||||
VDUPQ_32(q0, q0, 0); // only the low 8bits will be used anyway
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VY(v0, v2, 0, -1, -1); }
|
||||
if(!l) {
|
||||
UQXTN_32(q0, v1);
|
||||
UMIN_32(q0, q0, q1); // limit to 0 .. +32 values
|
||||
NEG_32(q0, q0); // neg to do shr
|
||||
VDUPQ_16(q0, q0, 0); // only the low 8bits will be used anyway
|
||||
}
|
||||
if(!l) { GETGX_empty_VX(v0, v2); } else { GETGY_empty_VY(v0, v2, 0, -1, -1); }
|
||||
USHLQ_32(v0, v2, q0); // SHR x4
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
@@ -1340,15 +1404,14 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
nextop = F8;
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEX(v1, 0, 0);
|
||||
MOVI_32(q1, 64);
|
||||
UQXTN_32(q0, v1);
|
||||
UMIN_32(q0, q0, q1); // limit to 0 .. +64 values
|
||||
NEG_32(q0, q0); // neg to do shr
|
||||
VDUPQ_32(q0, q0, 0); // only the low 8bits will be used anyway
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VY(v0, v2, 0, -1, -1); }
|
||||
if(!l) {
|
||||
UQXTN_32(q0, v1);
|
||||
UMIN_32(q0, q0, q1); // limit to 0 .. +64 values
|
||||
NEG_32(q0, q0); // neg to do shr
|
||||
VDUPQ_16(q0, q0, 0); // only the low 8bits will be used anyway
|
||||
}
|
||||
if(!l) { GETGX_empty_VX(v0, v2); } else { GETGY_empty_VY(v0, v2, 0, -1, -1); }
|
||||
USHLQ_64(v0, v2, q0);
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
@@ -1377,45 +1440,51 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, (nextop&7)+(rex.b<<3));
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, ed);
|
||||
VMOV(v1, v0);
|
||||
YMM0((nextop&7)+(rex.b<<3));
|
||||
YMM0(ed);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VSTR64_U12(v0, ed, fixedaddress);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VST64(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0xD7:
|
||||
nextop = F8;
|
||||
INST_NAME("VPMOVMSKB Gd, Ex");
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEX_Y(q0, 0, 0);
|
||||
GETGD;
|
||||
TABLE64(x2, 0x0706050403020100LL);
|
||||
VDUPQD(v0, x2);
|
||||
VSHRQ_8(q1, q0, 7);
|
||||
USHLQ_8(q1, q1, v0); // shift
|
||||
UADDLV_8(v1, q1); // accumalte
|
||||
VMOVBto(gd, v1, 0);
|
||||
// and now the high part
|
||||
VMOVeD(q1, 0, q1, 1);
|
||||
UADDLV_8(q1, q1); // accumalte
|
||||
VMOVBto(x2, q1, 0);
|
||||
BFIw(gd, x2, 8, 8);
|
||||
if(vex.l) {
|
||||
GETEY(q0);
|
||||
if(MODREG) {
|
||||
INST_NAME("VPMOVMSKB Gd, Ex");
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEX_Y(q0, 0, 0);
|
||||
GETGD;
|
||||
TABLE64(x2, 0x0706050403020100LL);
|
||||
VDUPQD(v0, x2);
|
||||
VSHRQ_8(q1, q0, 7);
|
||||
USHLQ_8(q1, q1, v0); // shift
|
||||
UADDLV_8(v1, q1); // accumalte
|
||||
VMOVBto(x2, v1, 0);
|
||||
BFIw(gd, x2, 16, 8);
|
||||
VMOVBto(gd, v1, 0);
|
||||
// and now the high part
|
||||
VMOVeD(q1, 0, q1, 1);
|
||||
UADDLV_8(q1, q1); // accumalte
|
||||
VMOVBto(x2, q1, 0);
|
||||
BFIw(gd, x2, 24, 8);
|
||||
BFIw(gd, x2, 8, 8);
|
||||
if(vex.l) {
|
||||
GETEY(q0);
|
||||
VSHRQ_8(q1, q0, 7);
|
||||
USHLQ_8(q1, q1, v0); // shift
|
||||
UADDLV_8(v1, q1); // accumalte
|
||||
VMOVBto(x2, v1, 0);
|
||||
BFIw(gd, x2, 16, 8);
|
||||
// and now the high part
|
||||
VMOVeD(q1, 0, q1, 1);
|
||||
UADDLV_8(q1, q1); // accumalte
|
||||
VMOVBto(x2, q1, 0);
|
||||
BFIw(gd, x2, 24, 8);
|
||||
}
|
||||
} else {
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0xD8:
|
||||
@@ -1540,15 +1609,14 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
nextop = F8;
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEX(v1, 0, 0);
|
||||
MOVI_32(q1, 15);
|
||||
UQXTN_32(q0, v1);
|
||||
UMIN_32(q0, q0, q1); // limit to -15 .. +15 values
|
||||
NEG_16(q0, q0);
|
||||
VDUPQ_16(q0, q0, 0); // only the low 8bits will be used anyway
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VY(v0, v2, 0, -1, -1); }
|
||||
if(!l) {
|
||||
UQXTN_32(q0, v1);
|
||||
UMIN_32(q0, q0, q1); // limit to -15 .. +15 values
|
||||
NEG_16(q0, q0);
|
||||
VDUPQ_16(q0, q0, 0); // only the low 8bits will be used anyway
|
||||
}
|
||||
if(!l) { GETGX_empty_VX(v0, v2); } else { GETGY_empty_VY(v0, v2, 0, -1, -1); }
|
||||
SSHLQ_16(v0, v2, q0);
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
@@ -1558,15 +1626,14 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
nextop = F8;
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEX(v1, 0, 0);
|
||||
MOVI_32(q1, 31);
|
||||
UQXTN_32(q0, v1);
|
||||
UMIN_32(q0, q0, q1); // limit to 0 .. +31 values
|
||||
NEG_32(q0, q0);
|
||||
VDUPQ_32(q0, q0, 0); // only the low 8bits will be used anyway
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VY(v0, v2, 0, -1, -1); }
|
||||
if(!l) {
|
||||
UQXTN_32(q0, v1);
|
||||
UMIN_32(q0, q0, q1); // limit to 0 .. +31 values
|
||||
NEG_32(q0, q0);
|
||||
VDUPQ_32(q0, q0, 0); // only the low 8bits will be used anyway
|
||||
}
|
||||
if(!l) { GETGX_empty_VX(v0, v2); } else { GETGY_empty_VY(v0, v2, 0, -1, -1); }
|
||||
SSHLQ_32(v0, v2, q0);
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
@@ -1589,7 +1656,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
|
||||
VUMULL_16(q0, v2, v1);
|
||||
VUMULL2_16(q1, v2, v1);
|
||||
UQSHRN_16(v0, q0, 16);
|
||||
UQSHRN_16(v0, q0, 16); // 16bits->16bits: no saturation
|
||||
UQSHRN2_16(v0, q1, 16);
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
@@ -1627,28 +1694,35 @@ 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(!l) {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
ORRw_mask(x4, xZR, 1, 0); //0x80000000
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
}
|
||||
for(int i=0; i<2; ++i) {
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
if(i) {
|
||||
VMOVeD(d0, 0, v1, i);
|
||||
FCVTZSwD(x1, d0);
|
||||
} else {
|
||||
FCVTZSwD(x1, v1);
|
||||
if(arm64_frintts) {
|
||||
VFRINT32ZDQ(l?d0:v0, v1); // handle overflow
|
||||
VFCVTZSQD(l?d0:v0, l?d0:v0); // convert double -> int64
|
||||
if(!l)
|
||||
SQXTN_32(v0, v0); // convert int64 -> int32 with saturation in lower part, RaZ high part
|
||||
else
|
||||
SQXTN2_32(v0, d0); // convert int64 -> int32 with saturation in higher part
|
||||
} else {
|
||||
if(!l) {
|
||||
MRS_fpsr(x5);
|
||||
ORRw_mask(x4, xZR, 1, 0); //0x80000000
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
}
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TSTw_mask(x5, 0, 0); // mask = 1 = FPSR_IOC
|
||||
CSELx(x1, x1, x4, cEQ);
|
||||
VMOVQSfrom(v0, i+l*2, x1);
|
||||
for(int i=0; i<2; ++i) {
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
if(i) {
|
||||
VMOVeD(d0, 0, v1, i);
|
||||
FCVTZSwD(x1, d0);
|
||||
} else {
|
||||
FCVTZSwD(x1, v1);
|
||||
}
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TSTw_mask(x5, 0, 0); // mask = 1 = FPSR_IOC
|
||||
CSELx(x1, x1, x4, cEQ);
|
||||
VMOVQSfrom(v0, i+l*2, x1);
|
||||
}
|
||||
if(!vex.l && !l) VMOVQDfrom(v0, 1, xZR);
|
||||
}
|
||||
if(!vex.l && !l) VMOVQDfrom(v0, 1, xZR);
|
||||
}
|
||||
}
|
||||
YMM0(gd);
|
||||
@@ -1657,20 +1731,17 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
INST_NAME("VMOVNTDQ Ex,Gx");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, (nextop&7)+(rex.b<<3));
|
||||
VMOVQ(v1, v0);
|
||||
if(vex.l) {
|
||||
GETGYEY_empty(v0, v1);
|
||||
VMOVQ(v1, v0);
|
||||
}
|
||||
DEFAULT;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0xffe<<4, 15, rex, NULL, 0, 0);
|
||||
VSTR128_U12(v0, ed, fixedaddress);
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if(vex.l) {
|
||||
GETGY(v0, 0, -1, -1, -1);
|
||||
VSTR128_U12(v0, ed, fixedaddress+16);
|
||||
GETGY(v1, 0, -1, -1, -1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0x3f<<4, 15, rex, NULL, 1, 0);
|
||||
VSTP128_I7(v0, v1, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VST128(v0, ed, fixedaddress);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1792,7 +1863,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
nextop = F8;
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEX_Y(v1, 0, 0);
|
||||
GETEX(v1, 0, 0);
|
||||
UQXTN_32(q0, v1);
|
||||
MOVI_32(q1, 16);
|
||||
UMIN_32(q0, q0, q1); // limit to 0 .. +16 values
|
||||
@@ -1808,7 +1879,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
nextop = F8;
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEX_Y(v1, 0, 0);
|
||||
GETEX(v1, 0, 0);
|
||||
UQXTN_32(q0, v1);
|
||||
MOVI_32(q1, 32);
|
||||
UMIN_32(q0, q0, q1); // limit to 0 .. +32 values
|
||||
@@ -1824,7 +1895,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
nextop = F8;
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEX_Y(v1, 0, 0);
|
||||
GETEX(v1, 0, 0);
|
||||
UQXTN_32(q0, v1);
|
||||
MOVI_32(q1, 64);
|
||||
UMIN_32(q0, q0, q1); // limit to 0 .. +64 values
|
||||
@@ -1883,7 +1954,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
case 0xF7:
|
||||
INST_NAME("VMASKMOVDQU Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETGX(q0, 0);
|
||||
GETEX(q1, 0, 0); //no vex.l case
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
VLDR128_U12(v0, xRDI, 0);
|
||||
|
||||
@@ -5,10 +5,8 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
@@ -221,10 +219,17 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
case 0x0B:
|
||||
INST_NAME("VPMULHRSW Gx,Vx, Ex");
|
||||
nextop = F8;
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
q1 = 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); }
|
||||
SQRDMULHQ_16(v0, v2, v1);
|
||||
}
|
||||
VSMULL_16(q0, v1, v2);
|
||||
VSMULL2_16(q1, v1, v2);
|
||||
SRSHRQ_32(q0, q0, 15);
|
||||
SRSHRQ_32(q1, q1, 15);
|
||||
XTN_16(v0, q0);
|
||||
XTN2_16(v0, q1);
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x0C:
|
||||
@@ -388,9 +393,8 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
v1 = ymm_get_reg(dyn, ninst, x3, s0, 0, gd, vex.v, -1);
|
||||
VMOVQ(d1, v1);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0xffe<<4, 15, rex, NULL, 0, 0);
|
||||
VLDR128_U12(d0, ed, fixedaddress);
|
||||
VLDR128_U12(d1, ed, fixedaddress+16);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0x3f<<4, 15, rex, NULL, 1, 0);
|
||||
VLDP128_I7(d0, d1, ed, fixedaddress);
|
||||
}
|
||||
MOV32w(x3, 0x03020100);
|
||||
VDUPQS(q1, x3);
|
||||
@@ -557,12 +561,11 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
nextop = F8;
|
||||
if(vex.l) {GETEX64(q1, 0, 0);} else {GETEX32(q1, 0, 0);}
|
||||
GETGX_empty(q0);
|
||||
SXTL_8(q0, q1);
|
||||
if(vex.l) {
|
||||
GETGY_empty(v0, -1, -1, -1);
|
||||
SXTL_8(v0, q1);
|
||||
SXTL2_16(v0, v0);
|
||||
SXTL2_16(v0, q0);
|
||||
} else YMM0(gd);
|
||||
SXTL_8(q0, q1);
|
||||
SXTL_16(q0, q0);
|
||||
break;
|
||||
case 0x22:
|
||||
@@ -570,14 +573,12 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
nextop = F8;
|
||||
if(vex.l) {GETEX32(q1, 0, 0);} else {GETEX16(q1, 0, 0);}
|
||||
GETGX_empty(q0);
|
||||
if(vex.l) {
|
||||
GETGY_empty(v0, -1, -1, -1);
|
||||
SXTL_8(v0, q1);
|
||||
SXTL_16(v0, v0);
|
||||
SXTL2_32(v0, v0);
|
||||
} else YMM0(gd);
|
||||
SXTL_8(q0, q1);
|
||||
SXTL_16(q0, q0);
|
||||
if(vex.l) {
|
||||
GETGY_empty(v0, -1, -1, -1);
|
||||
SXTL2_32(v0, q0);
|
||||
} else YMM0(gd);
|
||||
SXTL_32(q0, q0);
|
||||
break;
|
||||
case 0x23:
|
||||
@@ -596,12 +597,11 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
nextop = F8;
|
||||
if(vex.l) {GETEX64(q1, 0, 0);} else {GETEX32(q1, 0, 0);}
|
||||
GETGX_empty(q0);
|
||||
SXTL_16(q0, q1);
|
||||
if(vex.l) {
|
||||
GETGY_empty(v0, -1, -1, -1);
|
||||
SXTL_16(v0, q1);
|
||||
SXTL2_32(v0, v0);
|
||||
SXTL2_32(v0, q0);
|
||||
} else YMM0(gd);
|
||||
SXTL_16(q0, q1);
|
||||
SXTL_32(q0, q0);
|
||||
break;
|
||||
case 0x25:
|
||||
@@ -648,18 +648,25 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
case 0x2A:
|
||||
INST_NAME("VMOVNTDQA Gx, Ex");
|
||||
nextop = F8;
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_EX(v0, v1, 0); } else { GETGY_empty_EY(v0, v1); }
|
||||
VMOVQ(v0, v1);
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
DEFAULT;
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
if(vex.l) {
|
||||
GETGY_empty(v1, -1, -1, -1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &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);
|
||||
YMM0(gd);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x2B:
|
||||
INST_NAME("VPACKUSDW Gx, Ex, Vx");
|
||||
nextop = F8;
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
VEORQ(q0, q0, q0);
|
||||
q1 = 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); }
|
||||
if(v0==v1 && v2!=v1) {
|
||||
@@ -667,13 +674,11 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
VMOVQ(q2, v1);
|
||||
v1 = q2;
|
||||
}
|
||||
SMAXQ_32(q1, v2, q0); // values < 0 => 0
|
||||
UQXTN_16(v0, q1);
|
||||
SQXTUN_16(v0, v2);
|
||||
if(v2==v1) {
|
||||
VMOVeD(v0, 1, v0, 0);
|
||||
} else {
|
||||
SMAXQ_32(q1, v1, q0);
|
||||
UQXTN2_16(v0, q1);
|
||||
SQXTUN2_16(v0, v1);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
@@ -686,20 +691,17 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
VSSHRQ_32(q0, v2, 31);
|
||||
if (MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x3, (nextop & 7) + (rex.b << 3), 0);
|
||||
VANDQ(v0, v1, q0);
|
||||
DEFAULT;
|
||||
return addr;
|
||||
} else {
|
||||
VEORQ(v0, v0, v0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x3) {
|
||||
MOVz_REG(x3, ed);
|
||||
ed = x3;
|
||||
}
|
||||
VMOVSto(x4, q0, 0);
|
||||
CBZw(x4, 4+1*4);
|
||||
VLD1_32(v0, 0, ed);
|
||||
ADDx_U12(ed, ed, 4);
|
||||
ADDx_U12(x3, ed, 4);
|
||||
ed = x3;
|
||||
VMOVSto(x4, q0, 1);
|
||||
CBZw(x4, 4+1*4);
|
||||
VLD1_32(v0, 1, ed);
|
||||
@@ -718,27 +720,22 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
v2 = ymm_get_reg(dyn, ninst, x1, vex.v, 0, gd, (MODREG)?((nextop&7)+(rex.b<<3)):-1, -1);
|
||||
v0 = ymm_get_reg_empty(dyn, ninst, x1, gd, vex.v, (MODREG)?((nextop&7)+(rex.b<<3)):-1, -1);
|
||||
VSSHRQ_32(q0, v2, 31);
|
||||
if(MODREG) {
|
||||
v1 = ymm_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0, gd, vex.v, -1);
|
||||
VANDQ(v0, v1, q0);
|
||||
} else {
|
||||
VEORQ(v0, v0, v0);
|
||||
VMOVSto(x4, q0, 0);
|
||||
CBZw(x4, 4+1*4);
|
||||
VLD1_32(v0, 0, ed);
|
||||
ADDx_U12(ed, ed, 4);
|
||||
VMOVSto(x4, q0, 1);
|
||||
CBZw(x4, 4+1*4);
|
||||
VLD1_32(v0, 1, ed);
|
||||
ADDx_U12(ed, ed, 4);
|
||||
VMOVSto(x4, q0, 2);
|
||||
CBZw(x4, 4+1*4);
|
||||
VLD1_32(v0, 2, ed);
|
||||
ADDx_U12(ed, ed, 4);
|
||||
VMOVSto(x4, q0, 3);
|
||||
CBZw(x4, 4+1*4);
|
||||
VLD1_32(v0, 3, ed);
|
||||
}
|
||||
VEORQ(v0, v0, v0);
|
||||
VMOVSto(x4, q0, 0);
|
||||
CBZw(x4, 4+1*4);
|
||||
VLD1_32(v0, 0, ed);
|
||||
ADDx_U12(ed, ed, 4);
|
||||
VMOVSto(x4, q0, 1);
|
||||
CBZw(x4, 4+1*4);
|
||||
VLD1_32(v0, 1, ed);
|
||||
ADDx_U12(ed, ed, 4);
|
||||
VMOVSto(x4, q0, 2);
|
||||
CBZw(x4, 4+1*4);
|
||||
VLD1_32(v0, 2, ed);
|
||||
ADDx_U12(ed, ed, 4);
|
||||
VMOVSto(x4, q0, 3);
|
||||
CBZw(x4, 4+1*4);
|
||||
VLD1_32(v0, 3, ed);
|
||||
} else YMM0(gd);
|
||||
break;
|
||||
case 0x2D:
|
||||
@@ -751,19 +748,16 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
VSSHRQ_64(q0, v2, 63);
|
||||
VEORQ(v0, v0, v0);
|
||||
if (MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x3, (nextop & 7) + (rex.b << 3), 0);
|
||||
VANDQ(v0, v1, q0);
|
||||
DEFAULT;
|
||||
return addr;
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x3) {
|
||||
MOVz_REG(x3, ed);
|
||||
ed = x3;
|
||||
}
|
||||
VMOVQDto(x4, q0, 0);
|
||||
CBZx(x4, 4+1*4);
|
||||
VLD1_64(v0, 0, ed);
|
||||
ADDx_U12(ed, ed, 8);
|
||||
ADDx_U12(x3, ed, 8);
|
||||
ed = x3;
|
||||
VMOVQDto(x4, q0, 1);
|
||||
CBZx(x4, 4+1*4);
|
||||
VLD1_64(v0, 1, ed);
|
||||
@@ -775,21 +769,13 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
v0 = ymm_get_reg_empty(dyn, ninst, x1, gd, vex.v, (MODREG)?((nextop&7)+(rex.b<<3)):-1, -1);
|
||||
VSSHRQ_64(q0, v2, 63);
|
||||
VEORQ(v0, v0, v0);
|
||||
if(MODREG)
|
||||
{
|
||||
v1 = ymm_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0, gd, vex.v, -1);
|
||||
VANDQ(v0, v1, q0);
|
||||
}
|
||||
else
|
||||
{
|
||||
VMOVQDto(x4, q0, 0);
|
||||
CBZx(x4, 4+1*4);
|
||||
VLD1_64(v0, 0, ed);
|
||||
ADDx_U12(ed, ed, 8);
|
||||
VMOVQDto(x4, q0, 1);
|
||||
CBZx(x4, 4+1*4);
|
||||
VLD1_64(v0, 1, ed);
|
||||
}
|
||||
VMOVQDto(x4, q0, 0);
|
||||
CBZx(x4, 4+1*4);
|
||||
VLD1_64(v0, 0, ed);
|
||||
ADDx_U12(ed, ed, 8);
|
||||
VMOVQDto(x4, q0, 1);
|
||||
CBZx(x4, 4+1*4);
|
||||
VLD1_64(v0, 1, ed);
|
||||
} else YMM0(gd);
|
||||
break;
|
||||
case 0x2E:
|
||||
@@ -800,20 +786,17 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
GETGX(v0, 0);
|
||||
VSSHRQ_32(q0, v2, 31);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x3, (nextop&7)+(rex.b<<3), 1);
|
||||
VBITQ(v1, v0, q0);
|
||||
DEFAULT;
|
||||
return addr;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x3) {
|
||||
MOVz_REG(x3, ed);
|
||||
ed = x3;
|
||||
}
|
||||
// check if mask as anything, else skip the whole read/write to avoid a SEGFAULT.
|
||||
// TODO: let a segfault trigger and check if the mask is null instead and ignore the segfault / actually triger: needs to implement SSE reg tracking first!
|
||||
VMOVSto(x4, q0, 0);
|
||||
CBZw(x4, 4+1*4);
|
||||
VST1_32(v0, 0, ed);
|
||||
ADDx_U12(ed, ed, 4);
|
||||
ADDx_U12(x3, ed, 4);
|
||||
ed = x3;
|
||||
VMOVSto(x4, q0, 1);
|
||||
CBZw(x4, 4+1*4);
|
||||
VST1_32(v0, 1, ed);
|
||||
@@ -833,28 +816,23 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
v2 = ymm_get_reg(dyn, ninst, x1, vex.v, 0, gd, (MODREG)?((nextop&7)+(rex.b<<3)):-1, -1);
|
||||
v0 = ymm_get_reg(dyn, ninst, x1, gd, 0, vex.v, (MODREG)?((nextop&7)+(rex.b<<3)):-1, -1);
|
||||
VSSHRQ_32(q0, v2, 31);
|
||||
if(MODREG) {
|
||||
v1 = ymm_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 1, gd, vex.v, -1);
|
||||
VBITQ(v1, v0, q0);
|
||||
}
|
||||
else {
|
||||
VMOVSto(x4, q0, 0);
|
||||
CBZw(x4, 4+1*4);
|
||||
VST1_32(v0, 0, ed);
|
||||
ADDx_U12(ed, ed, 4);
|
||||
VMOVSto(x4, q0, 1);
|
||||
CBZw(x4, 4+1*4);
|
||||
VST1_32(v0, 1, ed);
|
||||
ADDx_U12(ed, ed, 4);
|
||||
VMOVSto(x4, q0, 2);
|
||||
CBZw(x4, 4+1*4);
|
||||
VST1_32(v0, 2, ed);
|
||||
ADDx_U12(ed, ed, 4);
|
||||
VMOVSto(x4, q0, 3);
|
||||
CBZw(x4, 4+1*4);
|
||||
VST1_32(v0, 3, ed);
|
||||
}
|
||||
VMOVSto(x4, q0, 0);
|
||||
CBZw(x4, 4+1*4);
|
||||
VST1_32(v0, 0, ed);
|
||||
ADDx_U12(ed, ed, 4);
|
||||
VMOVSto(x4, q0, 1);
|
||||
CBZw(x4, 4+1*4);
|
||||
VST1_32(v0, 1, ed);
|
||||
ADDx_U12(ed, ed, 4);
|
||||
VMOVSto(x4, q0, 2);
|
||||
CBZw(x4, 4+1*4);
|
||||
VST1_32(v0, 2, ed);
|
||||
ADDx_U12(ed, ed, 4);
|
||||
VMOVSto(x4, q0, 3);
|
||||
CBZw(x4, 4+1*4);
|
||||
VST1_32(v0, 3, ed);
|
||||
}
|
||||
SMWRITE2();
|
||||
break;
|
||||
case 0x2F:
|
||||
INST_NAME("VMASKMOVPD Ex, Gx, Vx");
|
||||
@@ -864,14 +842,10 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
GETGX(v0, 0);
|
||||
VSSHRQ_64(q0, v2, 63);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x3, (nextop&7)+(rex.b<<3), 1);
|
||||
VBITQ(v1, v0, q0);
|
||||
DEFAULT;
|
||||
return addr;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x3) {
|
||||
MOVz_REG(x3, ed);
|
||||
ed = x3;
|
||||
}
|
||||
unscaled = 0;
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
// check if mask as anything, else skip the whole read/write to avoid a SEGFAULT.
|
||||
@@ -879,7 +853,8 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
VMOVQDto(x4, q0, 0);
|
||||
CBZx(x4, 4+1*4);
|
||||
VST1_64(v0, 0, ed);
|
||||
ADDx_U12(ed, ed, 8);
|
||||
ADDx_U12(x3, ed, 8);
|
||||
ed = x3;
|
||||
VMOVQDto(x4, q0, 1);
|
||||
CBZx(x4, 4+1*4);
|
||||
VST1_64(v0, 1, ed);
|
||||
@@ -891,20 +866,15 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
v2 = ymm_get_reg(dyn, ninst, x1, vex.v, 0, gd, (MODREG)?((nextop&7)+(rex.b<<3)):-1, -1);
|
||||
v0 = ymm_get_reg(dyn, ninst, x1, gd, 0, vex.v, (MODREG)?((nextop&7)+(rex.b<<3)):-1, -1);
|
||||
VSSHRQ_64(q0, v2, 63);
|
||||
if(MODREG) {
|
||||
v1 = ymm_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 1, gd, vex.v, -1);
|
||||
VBITQ(v1, v0, q0);
|
||||
}
|
||||
else {
|
||||
VMOVQDto(x4, q0, 0);
|
||||
CBZx(x4, 4+1*4);
|
||||
VST1_64(v0, 0, ed);
|
||||
ADDx_U12(ed, ed, 8);
|
||||
VMOVQDto(x4, q0, 1);
|
||||
CBZx(x4, 4+1*4);
|
||||
VST1_64(v0, 1, ed);
|
||||
}
|
||||
VMOVQDto(x4, q0, 0);
|
||||
CBZx(x4, 4+1*4);
|
||||
VST1_64(v0, 0, ed);
|
||||
ADDx_U12(ed, ed, 8);
|
||||
VMOVQDto(x4, q0, 1);
|
||||
CBZx(x4, 4+1*4);
|
||||
VST1_64(v0, 1, ed);
|
||||
}
|
||||
SMWRITE2();
|
||||
break;
|
||||
case 0x30:
|
||||
INST_NAME("VPMOVZXBW Gx, Ex");
|
||||
@@ -924,12 +894,11 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
GETG;
|
||||
if(vex.l) { GETEX64(q1, 0, 0); } else { GETEX32(q1, 0, 0); YMM0(gd); }
|
||||
GETGX_empty(q0);
|
||||
UXTL_8(q0, q1);
|
||||
if(vex.l) {
|
||||
GETGY_empty(v0, -1, -1, -1);
|
||||
UXTL_8(v0, q1);
|
||||
UXTL2_16(v0, v0);
|
||||
UXTL2_16(v0, q0);
|
||||
}
|
||||
UXTL_8(q0, q1);
|
||||
UXTL_16(q0, q0);
|
||||
break;
|
||||
case 0x32:
|
||||
@@ -938,14 +907,12 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
GETG;
|
||||
if(vex.l) { GETEX32(q1, 0, 0); } else { GETEX16(q1, 0, 0); YMM0(gd); }
|
||||
GETGX_empty(q0);
|
||||
if(vex.l) {
|
||||
GETGY_empty(v0, -1, -1, -1);
|
||||
UXTL_8(v0, q1);
|
||||
UXTL_16(v0, v0);
|
||||
UXTL2_32(v0, v0);
|
||||
}
|
||||
UXTL_8(q0, q1);
|
||||
UXTL_16(q0, q0);
|
||||
if(vex.l) {
|
||||
GETGY_empty(v0, -1, -1, -1);
|
||||
UXTL2_32(v0, q0);
|
||||
}
|
||||
UXTL_32(q0, q0);
|
||||
break;
|
||||
case 0x33:
|
||||
@@ -966,12 +933,11 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
GETG;
|
||||
if(vex.l) { GETEX64(q1, 0, 0); } else { GETEX32(q1, 0, 0); YMM0(gd); }
|
||||
GETGX_empty(q0);
|
||||
UXTL_16(q0, q1);
|
||||
if(vex.l) {
|
||||
GETGY_empty(v0, -1, -1, -1);
|
||||
UXTL_16(v0, q1);
|
||||
UXTL2_32(v0, v0);
|
||||
UXTL2_32(v0, q0);
|
||||
}
|
||||
UXTL_16(q0, q1);
|
||||
UXTL_32(q0, q0);
|
||||
break;
|
||||
case 0x35:
|
||||
@@ -1108,7 +1074,6 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
|
||||
if(!MODREG) q0 = v1;
|
||||
if(rex.w) {
|
||||
VEORQ(q1, q1, q1);
|
||||
MOVI_32(q1, 64);
|
||||
// no 64bits vmin/vmax
|
||||
UQXTN_32(q0, v1);
|
||||
@@ -1117,7 +1082,6 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
NEGQ_64(q0, q0);
|
||||
USHLQ_64(v0, v2, q0);
|
||||
} else {
|
||||
VEORQ(q1, q1, q1);
|
||||
MOVIQ_32(q1, 32);
|
||||
UMINQ_32(q0, v1, q1);
|
||||
NEGQ_32(q0, q0);
|
||||
@@ -1127,29 +1091,18 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x46:
|
||||
INST_NAME("VPSRAVD/Q Gx, Vx, Ex");
|
||||
INST_NAME("VPSRAVD Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
if(rex.w) {DEFAULT; return addr;}
|
||||
if(MODREG) q0 = fpu_get_scratch(dyn, ninst);
|
||||
q1 = 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); }
|
||||
if(!MODREG) q0 = v1;
|
||||
if(rex.w) {
|
||||
VEORQ(q1, q1, q1);
|
||||
MOVI_32(q1, 64);
|
||||
// no 64bits vmin/vmax
|
||||
UQXTN_32(q0, v1);
|
||||
UMIN_32(q0, q0, q1);
|
||||
UXTL_32(q0, q0);
|
||||
NEGQ_64(q0, q0);
|
||||
SSHLQ_64(v0, v2, q0);
|
||||
} else {
|
||||
VEORQ(q1, q1, q1);
|
||||
MOVIQ_32(q1, 32);
|
||||
UMINQ_32(q0, v1, q1);
|
||||
NEGQ_32(q0, q0);
|
||||
SSHLQ_32(v0, v2, q0);
|
||||
}
|
||||
MOVIQ_32(q1, 32);
|
||||
UMINQ_32(q0, v1, q1);
|
||||
NEGQ_32(q0, q0);
|
||||
SSHLQ_32(v0, v2, q0);
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
@@ -1162,7 +1115,6 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
|
||||
if(!MODREG) q0 = v1;
|
||||
if(rex.w) {
|
||||
VEORQ(q1, q1, q1);
|
||||
MOVI_32(q1, 64);
|
||||
// no 64bits vmin/vmax
|
||||
UQXTN_32(q0, v1);
|
||||
@@ -1170,7 +1122,6 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
UXTL_32(q0, q0);
|
||||
USHLQ_64(v0, v2, q0);
|
||||
} else {
|
||||
VEORQ(q1, q1, q1);
|
||||
MOVIQ_32(q1, 32);
|
||||
UMINQ_32(q0, v1, q1);
|
||||
USHLQ_32(v0, v2, q0);
|
||||
@@ -1221,48 +1172,38 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
break;
|
||||
|
||||
case 0x78:
|
||||
INST_NAME("VBROADCASTB Gx, Ex");
|
||||
INST_NAME("VPBROADCASTB Gx, Ex");
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
GETGX_empty(v0);
|
||||
VDUPQ_8(v0, v1, 0);
|
||||
if(vex.l) {
|
||||
GETGY_empty(v0, -1, -1, -1);
|
||||
VDUPQ_8(v0, v1, 0);
|
||||
}
|
||||
} else {
|
||||
GETGX_empty(v0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
VLDQ1R_8(v0, ed);
|
||||
if(vex.l) {
|
||||
GETGY_empty(v0, -1, -1, -1);
|
||||
VLDQ1R_8(v0, ed);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
if(vex.l) {
|
||||
GETGY_empty(v1, -1, -1, -1);
|
||||
VMOVQ(v1, v0);
|
||||
} else YMM0(gd);
|
||||
break;
|
||||
case 0x79:
|
||||
INST_NAME("VBROADCASTW Gx, Ex");
|
||||
INST_NAME("VPBROADCASTW Gx, Ex");
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
GETGX_empty(v0);
|
||||
VDUPQ_16(v0, v1, 0);
|
||||
if(vex.l) {
|
||||
GETGY_empty(v0, -1, -1, -1);
|
||||
VDUPQ_16(v0, v1, 0);
|
||||
}
|
||||
} else {
|
||||
GETGX_empty(v0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
VLDQ1R_16(v0, ed);
|
||||
if(vex.l) {
|
||||
GETGY_empty(v0, -1, -1, -1);
|
||||
VLDQ1R_16(v0, ed);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
if(vex.l) {
|
||||
GETGY_empty(v1, -1, -1, -1);
|
||||
VMOVQ(v1, v0);
|
||||
} else YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0x8C:
|
||||
@@ -1285,10 +1226,6 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
if(!l) {
|
||||
GETGX_empty_VX(v0, v2);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x3) {
|
||||
MOVx_REG(x3, ed);
|
||||
ed = x3;
|
||||
}
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
} else {
|
||||
GETGY_empty_VY(v0, v2, 0, -1, -1);
|
||||
@@ -1302,7 +1239,8 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
VMOVQDto(x4, q0, 0);
|
||||
CBZx(x4, 4+1*4);
|
||||
VLD1_64(v1, 0, ed);
|
||||
ADDx_U12(ed, ed, 8);
|
||||
ADDx_U12(x3, ed, 8);
|
||||
if(ed!=x3) ed=x3;
|
||||
VMOVQDto(x4, q0, 1);
|
||||
CBZx(x4, 4+1*4);
|
||||
VLD1_64(v1, 1, ed);
|
||||
@@ -1313,7 +1251,8 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
VMOVSto(x4, q0, 0);
|
||||
CBZx(x4, 4+1*4);
|
||||
VLD1_32(v1, 0, ed);
|
||||
ADDx_U12(ed, ed, 4);
|
||||
ADDx_U12(x3, ed, 4);
|
||||
if(ed!=x3) ed=x3;
|
||||
VMOVSto(x4, q0, 1);
|
||||
CBZx(x4, 4+1*4);
|
||||
VLD1_32(v1, 1, ed);
|
||||
@@ -1369,7 +1308,8 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
VMOVQDto(x4, q0, 0);
|
||||
CBZx(x4, 4+1*4);
|
||||
VST1_64(v0, 0, ed);
|
||||
ADDx_U12(ed, ed, 8);
|
||||
ADDx_U12(x3, ed, 8);
|
||||
if(ed!=x3) ed=x3;
|
||||
VMOVQDto(x4, q0, 1);
|
||||
CBZx(x4, 4+1*4);
|
||||
VST1_64(v0, 1, ed);
|
||||
@@ -1382,7 +1322,8 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
VMOVSto(x4, q0, 0);
|
||||
CBZx(x4, 4+1*4);
|
||||
VST1_32(v0, 0, ed);
|
||||
ADDx_U12(ed, ed, 4);
|
||||
ADDx_U12(x3, ed, 4);
|
||||
if(ed!=x3) ed=x3;
|
||||
VMOVSto(x4, q0, 1);
|
||||
CBZx(x4, 4+1*4);
|
||||
VST1_32(v0, 1, ed);
|
||||
@@ -1399,18 +1340,20 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!MODREG) {SMWRITE2();}
|
||||
// no raz of upper ymm
|
||||
break;
|
||||
|
||||
case 0x90:
|
||||
case 0x92:
|
||||
if(opcode==0x90) {INST_NAME("VPGATHERDD Gx, VSIB, Vx");} else {INST_NAME("VGATHERDPD/VGATHERDPS Gx, VSIB, Vx");}
|
||||
if(opcode==0x90) {INST_NAME("VPGATHERDD/VPGATHERDQ Gx, VSIB, Vx");} else {INST_NAME("VGATHERDPD/VGATHERDPS Gx, VSIB, Vx");}
|
||||
nextop = F8;
|
||||
if(((nextop&7)!=4) || MODREG) {UDF(0);}
|
||||
GETG;
|
||||
u8 = F8; //SIB
|
||||
if((u8&0x7)==0x5 && !(nextop&0xC0)) {
|
||||
MOV64x(x5, F32S64);
|
||||
int64_t i64 = F32S64;
|
||||
MOV64x(x5, i64);
|
||||
eb1 = x5;
|
||||
} else
|
||||
eb1 = TO_NAT((u8 & 0x7) + (rex.b << 3)); // base
|
||||
@@ -1463,13 +1406,14 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
break;
|
||||
case 0x91:
|
||||
case 0x93:
|
||||
if(opcode==0x91) {INST_NAME("VPGATHERQD Gx, VSIB, Vx");} else {INST_NAME("VGATHERQPD/VGATHERQPS Gx, VSIB, Vx");}
|
||||
if(opcode==0x91) {INST_NAME("VPGATHERQD/VPGATHERQQ Gx, VSIB, Vx");} else {INST_NAME("VGATHERQPD/VGATHERQPS Gx, VSIB, Vx");}
|
||||
nextop = F8;
|
||||
if(((nextop&7)!=4) || MODREG) {UDF(0);}
|
||||
GETG;
|
||||
u8 = F8; //SIB
|
||||
if((u8&0x7)==0x5 && !(nextop&0xC0)) {
|
||||
MOV64x(x5, F32S64);
|
||||
int64_t i64 = F32S64;
|
||||
MOV64x(x5, i64);
|
||||
eb1 = x5;
|
||||
} else
|
||||
eb1 = TO_NAT((u8 & 0x7) + (rex.b << 3)); // base
|
||||
@@ -1553,12 +1497,13 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETVX(v2, 0);
|
||||
if(rex.w) {GETEXSD(v1, 0, 0);} else {GETEXSS(v1, 0, 0);}
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
if(rex.w) {
|
||||
GETEXSD(v1, 0, 0);
|
||||
FMADD_64(q0, v2, v1, v0);
|
||||
VMOVeD(v0, 0, q0, 0);
|
||||
} else {
|
||||
GETEXSS(v1, 0, 0);
|
||||
FMADD_32(q0, v2, v1, v0);
|
||||
VMOVeS(v0, 0, q0, 0);
|
||||
}
|
||||
@@ -1676,12 +1621,13 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETVX(v2, 0);
|
||||
if(rex.w) {GETEXSD(v1, 0, 0);} else {GETEXSS(v1, 0, 0);}
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
if(rex.w) {
|
||||
GETEXSD(v1, 0, 0);
|
||||
FMADD_64(q0, v1, v0, v2);
|
||||
VMOVeD(v0, 0, q0, 0);
|
||||
} else {
|
||||
GETEXSS(v1, 0, 0);
|
||||
FMADD_32(q0, v1, v0, v2);
|
||||
VMOVeS(v0, 0, q0, 0);
|
||||
}
|
||||
@@ -1848,12 +1794,13 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETVX(v2, 0);
|
||||
if(rex.w) {GETEXSD(v1, 0, 0);} else {GETEXSS(v1, 0, 0);}
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
if(rex.w) {
|
||||
GETEXSD(v1, 0, 0);
|
||||
FMADD_64(q0, v0, v1, v2);
|
||||
VMOVeD(v0, 0, q0, 0);
|
||||
} else {
|
||||
GETEXSS(v1, 0, 0);
|
||||
FMADD_32(q0, v0, v1, v2);
|
||||
VMOVeS(v0, 0, q0, 0);
|
||||
}
|
||||
@@ -1863,9 +1810,17 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
INST_NAME("VFNMSUB231PS/D Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_VXEX(v0, v2, v1, 0); } else { GETGY_VYEY(v0, v2, v1); }
|
||||
if(rex.w) VFMLSQD(v0, v1, v2); else VFMLSQS(v0, v1, v2);
|
||||
if(rex.w) VFNEGQD(v0, v0); else VFNEGQS(v0, v0);
|
||||
if(!l) {
|
||||
GETGX_VXEX(v0, v2, v1, 0);
|
||||
if(v0==v1 || v0==v2) q0 = fpu_get_scratch(dyn, ninst); else q0 = v0;
|
||||
} else {
|
||||
GETGY_VYEY(v0, v2, v1);
|
||||
if(!(v0==v1 || v0==v2)) q0 = v0;
|
||||
}
|
||||
// chenge to get sign of zero correct
|
||||
if(rex.w) VFNEGQD(q0, v0); else VFNEGQS(q0, v0);
|
||||
if(rex.w) VFMLAQD(q0, v1, v2); else VFMLAQS(q0, v1, v2);
|
||||
if(q0!=v0) VMOVQ(v0, q0);
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
@@ -1934,7 +1889,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
MOV32w(x1, gd);
|
||||
CALL(native_aesimc, -1);
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0xDC:
|
||||
@@ -1974,7 +1929,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
if(vex.l) {
|
||||
GETGY_empty(v0, (d0==-1)?(nextop&7)+(rex.b<<3):-1, -1, -1);
|
||||
VEORQ(v0, v0, (d0==-1)?v1:d0);
|
||||
} else YMM0(gd);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
@@ -2014,7 +1969,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
if(vex.l) {
|
||||
GETGY_empty(v0, (d0==-1)?(nextop&7)+(rex.b<<3):-1, -1, -1);
|
||||
VEORQ(v0, v0, (d0==-1)?v1:d0);
|
||||
} else YMM0(gd);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
@@ -2055,7 +2010,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
if(vex.l) {
|
||||
GETGY_empty(v0, (d0==-1)?(nextop&7)+(rex.b<<3):-1, -1, -1);
|
||||
VEORQ(v0, v0, (d0==-1)?v1:d0);
|
||||
} else YMM0(gd);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
@@ -2095,7 +2050,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
if(vex.l) {
|
||||
GETGY_empty(v0, (d0==-1)?(nextop&7)+(rex.b<<3):-1, -1, -1);
|
||||
VEORQ(v0, v0, (d0==-1)?v1:d0);
|
||||
} else YMM0(gd);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
|
||||
@@ -5,10 +5,8 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
@@ -179,7 +177,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
VMOVQ(q1, v1);
|
||||
v1 = q1;
|
||||
}
|
||||
switch(u8&0x0f) {
|
||||
switch(u8&0b1011) {
|
||||
case 0: if(v0!=v2) VMOVQ(v0, v2); break;
|
||||
case 1: d2 = ymm_get_reg(dyn, ninst, x1, vex.v, 0, gd, s0, -1); VMOVQ(v0, d2); break;
|
||||
case 2: if(MODREG) { if(v0!=v1) VMOVQ(v0, v1); } else { VLDR128_U12(v0, ed, fixedaddress); } break;
|
||||
@@ -189,7 +187,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
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); }
|
||||
v0 = ymm_get_reg_empty(dyn, ninst, x1, gd, vex.v, s0, -1);
|
||||
switch((u8>>4)&0x0f) {
|
||||
switch((u8>>4)&0b1011) {
|
||||
case 0: VMOVQ(v0, v2); break;
|
||||
case 1: if(v0!=d2) VMOVQ(v0, d2); break;
|
||||
case 2: if(MODREG) { if(v0!=v1) VMOVQ(v0, v1); } else { VLDR128_U12(v0, ed, fixedaddress); } break;
|
||||
@@ -274,17 +272,21 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
} else if(q0==q1) {
|
||||
for(int i=0; i<4; ++i)
|
||||
if(u8&(1<<i)) {
|
||||
VMOVeS(q0, i, q1, i);
|
||||
//VMOVeS(q0, i, q1, i);
|
||||
} else if(q0!=q2)
|
||||
VMOVeS(q0, i, q2, i);
|
||||
} else {
|
||||
if(q0!=q2)
|
||||
VMOVQ(q0, q2);
|
||||
if((u8&15)==0b0011) {
|
||||
if((u8&0b0011)==0b0011) {
|
||||
VMOVeD(q0, 0, q1, 0);
|
||||
} else if((u8&15)==0b1100) {
|
||||
u8&=~0b0011;
|
||||
}
|
||||
if((u8&0b1100)==0b1100) {
|
||||
VMOVeD(q0, 1, q1, 1);
|
||||
} else for(int i=0; i<4; ++i)
|
||||
u8&=~0b1100;
|
||||
}
|
||||
for(int i=0; i<4; ++i)
|
||||
if(u8&(1<<i)) {
|
||||
VMOVeS(q0, i, q1, i);
|
||||
}
|
||||
@@ -296,17 +298,21 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
} else if(q0==q1) {
|
||||
for(int i=0; i<4; ++i)
|
||||
if(u8&(1<<(i+4))) {
|
||||
VMOVeS(q0, i, q1, i);
|
||||
//VMOVeS(q0, i, q1, i);
|
||||
} else if(q0!=q2)
|
||||
VMOVeS(q0, i, q2, i);
|
||||
} else {
|
||||
if(q0!=q2)
|
||||
VMOVQ(q0, q2);
|
||||
if((u8>>4)==0b0011) {
|
||||
if(((u8>>4)&0b0011)==0b0011) {
|
||||
VMOVeD(q0, 0, q1, 0);
|
||||
} else if((u8>>4)==0b1100) {
|
||||
u8&=~0b00110000;
|
||||
}
|
||||
if(((u8>>4)&0b1100)==0b1100) {
|
||||
VMOVeD(q0, 1, q1, 1);
|
||||
} else for(int i=0; i<4; ++i)
|
||||
u8&=~0b11000000;
|
||||
}
|
||||
for(int i=0; i<4; ++i)
|
||||
if(u8&(1<<(i+4))) {
|
||||
VMOVeS(q0, i, q1, i);
|
||||
}
|
||||
@@ -318,7 +324,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
nextop = F8;
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_VXEX(q0, q2, q1, 1); u8 = F8; } else { GETGY_empty_VYEY(q0, q2, q1); }
|
||||
switch(u8>>(l*2)&3) {
|
||||
switch((u8>>(l*2))&3) {
|
||||
case 0b00: if(q0!=q2) VMOVQ(q0, q2); break; // VxVx
|
||||
case 0b01: if(q0!=q1) VMOVeD(q0, 0, q1, 0); if(q0!=q2) VMOVeD(q0, 1, q2, 1); break; // Ex[0]Vx[1]
|
||||
case 0b10: if(q0!=q2) VMOVeD(q0, 0, q2, 0); if(q0!=q1) VMOVeD(q0, 1, q1, 1); break; // Vx[0]Ex[1]
|
||||
@@ -337,12 +343,8 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
MOVI_64(q0, u8);
|
||||
SXTL_8(q0, q0); // expand 8bits to 16bits...
|
||||
}
|
||||
if(v0==v1) {
|
||||
VBIFQ(v0, v2, q0);
|
||||
} else {
|
||||
if(v0!=v2) VMOVQ(v0, v2);
|
||||
VBITQ(v0, v1, q0);
|
||||
}
|
||||
if(v0!=v2) VBIFQ(v0, v2, q0);
|
||||
if(v0!=v1) VBITQ(v0, v1, q0);
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
@@ -384,6 +386,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
VMOVBto(ed, v0, u8&0x0f);
|
||||
if(!MODREG) {
|
||||
STB(ed, wback, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x15:
|
||||
@@ -401,6 +404,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
VMOVHto(ed, v0, u8&7);
|
||||
if(!MODREG) {
|
||||
STH(ed, wback, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x16:
|
||||
@@ -422,6 +426,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
}
|
||||
if(!MODREG) {
|
||||
STxw(ed, wback, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x17:
|
||||
@@ -439,6 +444,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
VMOVSto(ed, v0, u8&3);
|
||||
if(!MODREG) {
|
||||
STW(ed, wback, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x18:
|
||||
@@ -485,6 +491,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 1);
|
||||
VST128(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
F8; // read u8, but it's been already handled
|
||||
break;
|
||||
@@ -649,11 +656,11 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
if(!(u8&(1<<i))) {
|
||||
VMOVQDfrom(v0, i, xZR);
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0x44:
|
||||
INST_NAME("PCLMULQDQ Gx, Vx, Ex, Ib");
|
||||
INST_NAME("VPCLMULQDQ Gx, Vx, Ex, Ib");
|
||||
nextop = F8;
|
||||
if(arm64_pmull) {
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
@@ -682,34 +689,24 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) {
|
||||
GETG;
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
sse_reflect_reg(dyn, ninst, vex.v);
|
||||
GETG;
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
sse_reflect_reg(dyn, ninst, vex.v);
|
||||
MOV32w(x1, gd); // gx
|
||||
MOV32w(x2, vex.v); // vx
|
||||
if(MODREG) {
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
sse_forget_reg(dyn, ninst, ed);
|
||||
MOV32w(x3, ed);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 1);
|
||||
if(ed!=x3) {
|
||||
MOVx_REG(x3, ed);
|
||||
}
|
||||
MOV32w(x1, gd); // gx
|
||||
MOV32w(x2, vex.v); // vx
|
||||
if(MODREG) {
|
||||
if(!l) {
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
sse_forget_reg(dyn, ninst, ed);
|
||||
}
|
||||
MOV32w(x3, ed);
|
||||
} else {
|
||||
if(!l) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 1);
|
||||
if(ed!=x3) {
|
||||
MOVx_REG(x3, ed);
|
||||
}
|
||||
} else {
|
||||
ADDx_U12(x3, ed, 16);
|
||||
}
|
||||
}
|
||||
if(!l) u8 = F8;
|
||||
MOV32w(x4, u8);
|
||||
CALL_(l?native_pclmul_y:native_pclmul_x, -1, x3);
|
||||
}
|
||||
u8 = F8;
|
||||
MOV32w(x4, u8);
|
||||
CALL_(vex.l?native_pclmul_y:native_pclmul_x, -1, x3);
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
@@ -736,12 +733,8 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
v0 = ymm_get_reg_empty(dyn, ninst, x1, gd, vex.v, u8, (MODREG)?((nextop&7)+(rex.b<<3)):-1);
|
||||
}
|
||||
VSSHRQ_32(q0, q1, 31); // create mask
|
||||
if(v0==v1)
|
||||
VBIFQ(v0, v2, q0);
|
||||
else {
|
||||
if(v0!=v2) VMOVQ(v0, v2);
|
||||
VBITQ(v0, v1, q0);
|
||||
}
|
||||
if(v0!=v2) VBIFQ(v0, v2, q0);
|
||||
if(v0!=v1) VBITQ(v0, v1, q0);
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
@@ -765,41 +758,34 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
v0 = ymm_get_reg_empty(dyn, ninst, x1, gd, vex.v, u8, (MODREG)?((nextop&7)+(rex.b<<3)):-1);
|
||||
}
|
||||
VSSHRQ_64(q0, q1, 63); // create mask
|
||||
if(v0==v1)
|
||||
VBIFQ(v0, v2, q0);
|
||||
else {
|
||||
if(v0!=v2) VMOVQ(v0, v2);
|
||||
VBITQ(v0, v1, q0);
|
||||
}
|
||||
if(v0!=v2) VBIFQ(v0, v2, q0);
|
||||
if(v0!=v1) VBITQ(v0, v1, q0);
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x4C:
|
||||
INST_NAME("VBLENDPVB Gx, Vx, Ex, XMMImm8");
|
||||
INST_NAME("VPBLENDVB Gx, Vx, Ex, XMMImm8");
|
||||
nextop = F8;
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop)>>4;
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) {
|
||||
q1 = sse_get_reg(dyn, ninst, x1, u8, 0);
|
||||
GETGX_empty_VXEX(v0, v2, v1, 1);
|
||||
F8;
|
||||
} else {
|
||||
v2 = ymm_get_reg(dyn, ninst, x1, vex.v, 0, gd, u8, (MODREG)?((nextop&7)+(rex.b<<3)):-1);
|
||||
v2 = ymm_get_reg(dyn, ninst, x1, vex.v, 0, gd, u8, (MODREG)?ed:-1);
|
||||
if(MODREG)
|
||||
v1 = ymm_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0, gd, vex.v, u8);
|
||||
v1 = ymm_get_reg(dyn, ninst, x1, ed, 0, gd, vex.v, u8);
|
||||
else
|
||||
VLDR128_U12(v1, ed, fixedaddress+16);
|
||||
q1 = ymm_get_reg(dyn, ninst, x1, u8, 0, vex.v, gd, (MODREG)?((nextop&7)+(rex.b<<3)):-1);
|
||||
v0 = ymm_get_reg_empty(dyn, ninst, x1, gd, vex.v, u8, (MODREG)?((nextop&7)+(rex.b<<3)):-1);
|
||||
q1 = ymm_get_reg(dyn, ninst, x1, u8, 0, vex.v, gd, (MODREG)?ed:-1);
|
||||
v0 = ymm_get_reg_empty(dyn, ninst, x1, gd, vex.v, u8, (MODREG)?ed:-1);
|
||||
}
|
||||
VSSHRQ_8(q0, q1, 7); // create mask
|
||||
if(v0==v1)
|
||||
VBIFQ(v0, v2, q0);
|
||||
else {
|
||||
if(v0!=v2) VMOVQ(v0, v2);
|
||||
VBITQ(v0, v1, q0);
|
||||
}
|
||||
if(v0!=v2) VBIFQ(v0, v2, q0);
|
||||
if(v0!=v1) VBITQ(v0, v1, q0);
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
@@ -825,7 +811,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);
|
||||
if(!vex.l) YMM0(gd);
|
||||
YMM0(gd);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -5,10 +5,8 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
@@ -125,11 +123,17 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
GETGX_empty_VX(v0, v1);
|
||||
GETED(0);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
if(BOX64ENV(dynarec_fastround)<2) {
|
||||
u8 = sse_setround(dyn, ninst, x3, x4, x5);
|
||||
}
|
||||
if(rex.w) {
|
||||
SCVTFDx(d1, ed);
|
||||
} else {
|
||||
SCVTFDw(d1, ed);
|
||||
}
|
||||
if(BOX64ENV(dynarec_fastround)<2) {
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
}
|
||||
if(v0!=v1) VMOVQ(v0, v1);
|
||||
VMOVeD(v0, 0, d1, 0);
|
||||
YMM0(gd);
|
||||
@@ -140,13 +144,23 @@ 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)) {
|
||||
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
}
|
||||
FCVTZSxwD(gd, q0);
|
||||
if(!BOX64ENV(dynarec_fastround)) {
|
||||
if(!BOX64ENV(dynarec_fastround) && arm64_frintts) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
if(rex.w) {
|
||||
FRINT64ZD(v0, q0);
|
||||
} else {
|
||||
FRINT32ZD(v0, q0);
|
||||
}
|
||||
FCVTZSxwD(gd, v0);
|
||||
} else {
|
||||
FCVTZSxwD(gd, q0);
|
||||
}
|
||||
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_NEXT(x5, FPSR_IOC);
|
||||
if(rex.w) {
|
||||
@@ -161,17 +175,25 @@ 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)) {
|
||||
if(!BOX64ENV(dynarec_fastround) && !arm64_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);
|
||||
FRINTID(d1, q0);
|
||||
if(!BOX64ENV(dynarec_fastround) && arm64_frintts) {
|
||||
if(rex.w) {
|
||||
FRINT64XD(d1, q0);
|
||||
} else {
|
||||
FRINT32XD(d1, q0);
|
||||
}
|
||||
} else {
|
||||
FRINTID(d1, q0);
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
FCVTZSxwD(gd, d1);
|
||||
if(!BOX64ENV(dynarec_fastround)) {
|
||||
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_NEXT(x5, FPSR_IOC);
|
||||
if(rex.w) {
|
||||
@@ -198,7 +220,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
FCMEQD(q1, d1, d1); // 0 => out is NAN
|
||||
VBIC(q1, q0, q1); // forget it in any input was a NAN already
|
||||
VSHLQ_64(q1, q1, 63); // only keep the sign bit
|
||||
SHL_64(q1, q1, 63); // only keep the sign bit
|
||||
VORR(d1, d1, q1); // NAN -> -NAN
|
||||
}
|
||||
if(v0!=v2) {
|
||||
@@ -314,7 +336,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
GETGX_empty_VX(v0, v2);
|
||||
// VMINSD: if any input is NaN, or Ex[0]<Gx[0], copy Ex[0] -> Gx[0]
|
||||
FCMPD(v2, v1);
|
||||
FCSELD(d1, v1, v2, cCS);
|
||||
FCSELD(d1, v1, v2, cCS); //CS: NAN or == or Vx > Ex
|
||||
if(v0!=v2) {
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
@@ -354,7 +376,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
GETEXSD(v1, 0, 0);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
FCMPD(v1, v2);
|
||||
FCSELD(d1, v1, v2, cCS);
|
||||
FCSELD(d1, v1, v2, cCS); //CS: NAN or == or Ex > Vx
|
||||
if(v0!=v2) {
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
@@ -399,9 +421,24 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
case 0x7C:
|
||||
INST_NAME("VHADDPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
q1 = 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); }
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
// check if any input value was NAN
|
||||
VFMAXPQS(q0, v2, v1); // propagate NAN
|
||||
VFCMEQQS(q0, q0, q0); // 0 if NAN, 1 if not NAN
|
||||
}
|
||||
VFADDPQS(v0, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
VFCMEQQS(q1, v0, v0); // 0 => out is NAN
|
||||
VBICQ(q1, q0, q1); // forget it in any input was a NAN already
|
||||
VSHLQ_32(q1, q1, 31); // only keep the sign bit
|
||||
VORRQ(v0, v0, q1); // NAN -> -NAN
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
@@ -409,43 +446,60 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
INST_NAME("VHSUBPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
if(MODREG || (v1==v2)) {
|
||||
if(!BOX64ENV(dynarec_fastnan))
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
} else
|
||||
q1 = v1;
|
||||
if(vex.l)
|
||||
q2 = fpu_get_scratch(dyn, ninst);
|
||||
else
|
||||
q2 = q0;
|
||||
// q0 will contains -1 / 0 / -1 / 0
|
||||
MOVIQ_64(q0, 0xf0);
|
||||
VSHLQ_32(q0, q0, 31); // keep sign bit
|
||||
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); }
|
||||
VEORQ(q1, v1, q0);
|
||||
VEORQ(q2, v2, q0);
|
||||
VFADDPQS(v0, q2, q1);
|
||||
VUZP1Q_32(q0, v2, v1);
|
||||
VUZP2Q_32(v0, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
// check if any input value was NAN
|
||||
// but need to mix low/high part
|
||||
VFMAXQS(q1, v0, q0); // propagate NAN
|
||||
VFCMEQQS(q1, q1, q1); // 0 if NAN, 1 if not NAN
|
||||
}
|
||||
VFSUBQS(v0, q0, v0);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
VFCMEQQS(q0, v0, v0); // 0 => out is NAN
|
||||
VBICQ(q1, q1, q0); // forget it in any input was a NAN already
|
||||
VSHLQ_32(q1, q1, 31); // only keep the sign bit
|
||||
VORRQ(v0, v0, q1); // NAN -> -NAN
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0xC2:
|
||||
INST_NAME("CMPSD Gx, Ex, Ib");
|
||||
INST_NAME("VCMPSD Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETEXSD(v1, 0, 1);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
u8 = F8;
|
||||
FCMPD(v2, v1);
|
||||
if(((u8&15)!=0x0b) && ((u8&15)!=0x0f)) {
|
||||
if((u8&15)>7)
|
||||
FCMPD(v1, v2);
|
||||
else
|
||||
FCMPD(v2, v1);
|
||||
}
|
||||
// TODO: create a test for this one, there might be an issue with cases 9, 10 and 13
|
||||
if(v0!=v2) VMOVQ(v0, v2);
|
||||
switch(u8&7) {
|
||||
case 0: CSETMx(x2, cEQ); break; // Equal
|
||||
case 1: CSETMx(x2, cCC); break; // Less than
|
||||
case 2: CSETMx(x2, cLS); break; // Less or equal
|
||||
case 3: CSETMx(x2, cVS); break; // NaN
|
||||
case 4: CSETMx(x2, cNE); break; // Not Equal or unordered
|
||||
case 5: CSETMx(x2, cCS); break; // Greater or equal or unordered
|
||||
case 6: CSETMx(x2, cHI); break; // Greater or unordered, test inverted, N!=V so unordered or less than (inverted)
|
||||
case 7: CSETMx(x2, cVC); break; // not NaN
|
||||
switch(u8&15) {
|
||||
case 0x00: CSETMx(x2, cEQ); break; // Equal
|
||||
case 0x01: CSETMx(x2, cCC); break; // Less than
|
||||
case 0x02: CSETMx(x2, cLS); break; // Less or equal
|
||||
case 0x03: CSETMx(x2, cVS); break; // NaN
|
||||
case 0x04: CSETMx(x2, cNE); break; // Not Equal or unordered
|
||||
case 0x05: CSETMx(x2, cCS); break; // Greater or equal or unordered
|
||||
case 0x06: CSETMx(x2, cHI); break; // Greater or unordered
|
||||
case 0x07: CSETMx(x2, cVC); break; // not NaN
|
||||
case 0x08: CSETMx(x2, cEQ); CSETMx(x3, cVS); ORRx_REG(x2, x2, x3); break; // Equal or unordered
|
||||
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 0x0f: MOV64x(x2, 0xffffffffffffffffLL); break; // true
|
||||
}
|
||||
VMOVQDfrom(v0, 0, x2);
|
||||
YMM0(gd);
|
||||
@@ -496,28 +550,35 @@ 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(!l) {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
ORRw_mask(x4, xZR, 1, 0); //0x80000000
|
||||
}
|
||||
for(int i=0; i<2; ++i) {
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
if(i) {
|
||||
VMOVeD(d0, 0, v1, i);
|
||||
FRINTID(d0, d0);
|
||||
} else {
|
||||
FRINTID(d0, v1);
|
||||
if(arm64_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)
|
||||
SQXTN_32(v0, v0); // convert int64 -> int32 with saturation in lower part, RaZ high part
|
||||
else
|
||||
SQXTN2_32(v0, d0); // convert int64 -> int32 with saturation in higher part
|
||||
} else {
|
||||
if(!l) {
|
||||
MRS_fpsr(x5);
|
||||
ORRw_mask(x4, xZR, 1, 0); //0x80000000
|
||||
}
|
||||
FCVTZSwD(x1, d0);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TSTw_mask(x5, 0, 0); // mask = 1 = FPSR_IOC
|
||||
CSELx(x1, x1, x4, cEQ);
|
||||
VMOVQSfrom(v0, i+l*2, x1);
|
||||
for(int i=0; i<2; ++i) {
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
if(i) {
|
||||
VMOVeD(d0, 0, v1, i);
|
||||
FRINTID(d0, d0);
|
||||
} else {
|
||||
FRINTID(d0, v1);
|
||||
}
|
||||
FCVTZSwD(x1, d0);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TSTw_mask(x5, 0, 0); // mask = 1 = FPSR_IOC
|
||||
CSELx(x1, x1, x4, cEQ);
|
||||
VMOVQSfrom(v0, i+l*2, x1);
|
||||
}
|
||||
if(!vex.l && !l) VMOVQDfrom(v0, 1, xZR);
|
||||
}
|
||||
if(!vex.l && !l) VMOVQDfrom(v0, 1, xZR);
|
||||
}
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
@@ -525,7 +586,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
break;
|
||||
|
||||
case 0xF0:
|
||||
INST_NAME("LDDQU Gx,Ex");
|
||||
INST_NAME("VLDDQU Gx,Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
@@ -538,11 +599,10 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
}
|
||||
} 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, x1, &fixedaddress, NULL, 0xffe<<4, 7, rex, NULL, 0, 0);
|
||||
VLDR128_U12(v0, ed, fixedaddress);
|
||||
v0 = ymm_get_reg_empty(dyn, ninst, x1, gd, -1, -1, -1);
|
||||
VLDR128_U12(v0, ed, fixedaddress+16);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0x3f<<4, 15, rex, NULL, 1, 0);
|
||||
VLDP128_I7(v0, v1, ed, fixedaddress);
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
|
||||
@@ -5,10 +5,8 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
|
||||
@@ -5,10 +5,8 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
|
||||
@@ -5,10 +5,8 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
@@ -108,7 +106,7 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
break;
|
||||
|
||||
case 0x16:
|
||||
INST_NAME("MOVSHDUP Gx, Ex");
|
||||
INST_NAME("VMOVSHDUP Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX_Y(q1, 0, 0);
|
||||
GETGX_empty(q0);
|
||||
@@ -125,11 +123,17 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
GETGX_empty_VX(v0, v1);
|
||||
GETED(0);
|
||||
if(BOX64ENV(dynarec_fastround)<2) {
|
||||
u8 = sse_setround(dyn, ninst, x3, x4, x5);
|
||||
}
|
||||
if(rex.w) {
|
||||
SCVTFSx(d1, ed);
|
||||
} else {
|
||||
SCVTFSw(d1, ed);
|
||||
}
|
||||
if(BOX64ENV(dynarec_fastround)<2) {
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
}
|
||||
if(v0!=v1) VMOVQ(v0, v1);
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
YMM0(gd);
|
||||
@@ -140,13 +144,23 @@ 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)) {
|
||||
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
}
|
||||
FCVTZSxwS(gd, d0);
|
||||
if(!BOX64ENV(dynarec_fastround)) {
|
||||
if(!BOX64ENV(dynarec_fastround) && arm64_frintts) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
if(rex.w) {
|
||||
FRINT64ZS(v0, d0);
|
||||
} else {
|
||||
FRINT32ZS(v0, d0);
|
||||
}
|
||||
FCVTZSxwS(gd, v0);
|
||||
} else {
|
||||
FCVTZSxwS(gd, d0);
|
||||
}
|
||||
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_NEXT(x5, FPSR_IOC);
|
||||
if(rex.w) {
|
||||
@@ -161,17 +175,25 @@ 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)) {
|
||||
if(!BOX64ENV(dynarec_fastround) && !arm64_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);
|
||||
FRINTIS(d1, q0);
|
||||
if(!BOX64ENV(dynarec_fastround) && arm64_frintts) {
|
||||
if(rex.w) {
|
||||
FRINT64XS(d1, q0);
|
||||
} else {
|
||||
FRINT32XS(d1, q0);
|
||||
}
|
||||
} else {
|
||||
FRINTIS(d1, q0);
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
FCVTZSxwS(gd, d1);
|
||||
if(!BOX64ENV(dynarec_fastround)) {
|
||||
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_NEXT(x5, FPSR_IOC);
|
||||
if(rex.w) {
|
||||
@@ -183,12 +205,24 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
break;
|
||||
|
||||
case 0x51:
|
||||
INST_NAME("SQRTSS Gx, Ex");
|
||||
INST_NAME("VSQRTSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEXSS(d0, 0, 0);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
FCMEQS(q0, v1, v1); // 0 if NAN, 1 if not NAN
|
||||
}
|
||||
FSQRTS(d1, d0);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
FCMEQS(q1, d1, d1); // 0 => out is NAN
|
||||
VBIC(q1, q0, q1); // forget it in any input was a NAN already
|
||||
VSHL_32(q1, q1, 31); // only keep the sign bit
|
||||
VORR(d1, d1, q1); // NAN -> -NAN
|
||||
}
|
||||
if(v0!=v2) VMOVQ(v0, v2);
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
YMM0(gd);
|
||||
@@ -289,15 +323,10 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSS(v1, 0, 0);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
if(v0!=v2) {
|
||||
if(v0==v1) {
|
||||
VMOV(d1, v1);
|
||||
v1 = d1;
|
||||
}
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
FCVT_D_S(d1, v1);
|
||||
VMOVeD(v0, 0, d1, 0);
|
||||
if(v0!=v2)
|
||||
VMOVeD(v0, 1, v2, 1);
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x5B:
|
||||
@@ -313,17 +342,24 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
if(BOX64ENV(dynarec_fastround)) {
|
||||
VFCVTZSQS(v0, v1);
|
||||
} else {
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
for(int i=0; i<4; ++i) {
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
VMOVeS(d0, 0, v1, i);
|
||||
VFCVTZSs(d0, d0);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ(x5, FPSR_IOC, 4+4);
|
||||
VMOVQSfrom(d0, 0, x4);
|
||||
VMOVeS(v0, i, d0, 0);
|
||||
if(arm64_frintts) {
|
||||
VFRINT32ZSQ(v0, v1);
|
||||
VFCVTZSQS(v0, v0);
|
||||
} else {
|
||||
for(int i=0; i<4; ++i) {
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
if(i) {
|
||||
VMOVeS(d0, 0, v1, i);
|
||||
VFCVTZSs(d0, d0);
|
||||
} else {
|
||||
VFCVTZSs(d0, v1);
|
||||
}
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ(x5, FPSR_IOC, 4+4);
|
||||
VMOVQSfrom(d0, 0, x4);
|
||||
VMOVeS(v0, i, d0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -362,7 +398,7 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
GETEXSS(v1, 0, 0);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
FCMPS(v2, v1);
|
||||
FCSELS(d1, v1, v2, cCS);
|
||||
FCSELS(d1, v1, v2, cCS); //CS: NAN or == or Ex > Vx
|
||||
if(v0!=v2) {
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
@@ -402,7 +438,7 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
GETEXSS(v1, 0, 0);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
FCMPS(v1, v2);
|
||||
FCSELS(d1, v1, v2, cCS);
|
||||
FCSELS(d1, v1, v2, cCS); //CS: NAN or == or Ex > Vx
|
||||
if(v0!=v2) {
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
@@ -414,22 +450,22 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
INST_NAME("VMOVDQU Gx, Ex");// no alignment constraint on NEON here, so same as MOVDQA
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
GETGX_empty(v0);
|
||||
GETGX_empty_EX(v0, v1, 0);
|
||||
VMOVQ(v0, v1);
|
||||
if(vex.l) {
|
||||
v1 = ymm_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0, gd, -12, -1);
|
||||
GETGY_empty(v0, (nextop&7)+(rex.b<<3), -1, -1);
|
||||
GETGY_empty_EY(v0, v1);
|
||||
VMOVQ(v0, v1);
|
||||
}
|
||||
} else {
|
||||
GETGX_empty(v0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0xffe<<4, 15, rex, NULL, 0, 0);
|
||||
VLDR128_U12(v0, ed, fixedaddress);
|
||||
if(vex.l) {
|
||||
GETGY_empty(v0, -1, -1, -1);
|
||||
VLDR128_U12(v0, ed, fixedaddress+16);
|
||||
GETGY_empty(v1, -1, -1, -1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &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);
|
||||
@@ -464,7 +500,7 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
break;
|
||||
|
||||
case 0x7E:
|
||||
INST_NAME("MOVQ Gx, Ex");
|
||||
INST_NAME("VMOVQ Gx, Ex");
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3), 0);
|
||||
@@ -483,37 +519,37 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, (nextop&7) + (rex.b<<3));
|
||||
ed = (nextop&7) + (rex.b<<3);
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, ed);
|
||||
VMOVQ(v1, v0);
|
||||
if(vex.l) {
|
||||
GETGY(v0, 0, (nextop&7) + (rex.b<<3), -1, -1);
|
||||
v1 = ymm_get_reg_empty(dyn, ninst, x1, (nextop&7) + (rex.b<<3), gd, -1, -1);
|
||||
GETGY(v0, 0, ed, -1, -1);
|
||||
v1 = ymm_get_reg_empty(dyn, ninst, x1, ed, gd, -1, -1);
|
||||
VMOVQ(v1, v0);
|
||||
} // no ymm raz here it seems
|
||||
} else YMM0(ed);
|
||||
} else {
|
||||
IF_UNALIGNED(ip) {
|
||||
MESSAGE(LOG_DEBUG, "\tUnaligned path");
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(wback!=x1) {
|
||||
MOVx_REG(x1, wback);
|
||||
wback = x1;
|
||||
}
|
||||
for(int i=0; i<16; ++i) {
|
||||
VST1_8(v0, i, wback);
|
||||
ADDx_U12(wback, wback, 1);
|
||||
VST1_8(v0, i, i?x1:wback);
|
||||
ADDx_U12(x1, i?x1:wback, 1);
|
||||
}
|
||||
if(vex.l) {
|
||||
GETGY(v0, 0, -1, -1, -1);
|
||||
for(int i=0; i<16; ++i) {
|
||||
VST1_8(v0, i, wback);
|
||||
ADDx_U12(wback, wback, 1);
|
||||
VST1_8(v0, i, x1);
|
||||
ADDx_U12(x1, x1, 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0xffe<<4, 15, rex, NULL, 0, 0);
|
||||
VSTR128_U12(v0, ed, fixedaddress);
|
||||
if(vex.l) {
|
||||
GETGY(v0, 0, -1, -1, -1);
|
||||
VSTR128_U12(v0, ed, fixedaddress+16);
|
||||
GETGY(v1, 0, -1, -1, -1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0x3f<<4, 15, rex, NULL, 1, 0);
|
||||
VSTP128_I7(v0, v1, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VST128(v0, ed, fixedaddress);
|
||||
}
|
||||
}
|
||||
SMWRITE2();
|
||||
|
||||
@@ -5,10 +5,8 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
|
||||
@@ -5,10 +5,8 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
@@ -59,6 +57,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
FADDD(v1, v1, v2);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
@@ -80,6 +79,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
FMULD(v1, v1, v2);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
@@ -138,6 +138,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
FSUBD(v1, v1, v2);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
@@ -159,6 +160,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
FSUBD(v1, v2, v1);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
@@ -180,6 +182,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
FDIVD(v1, v1, v2);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
@@ -201,6 +204,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
FDIVD(v1, v2, v1);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
@@ -223,6 +227,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
FCVT_D_S(s0, s0);
|
||||
FADDD(v1, v1, s0);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
@@ -240,6 +245,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
FCVT_D_S(s0, s0);
|
||||
FMULD(v1, v1, s0);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
@@ -286,6 +292,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
FCVT_D_S(s0, s0);
|
||||
FSUBD(v1, v1, s0);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
@@ -303,6 +310,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
FCVT_D_S(s0, s0);
|
||||
FSUBD(v1, s0, v1);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
@@ -320,6 +328,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
FCVT_D_S(s0, s0);
|
||||
FDIVD(v1, v1, s0);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
@@ -337,6 +346,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
FCVT_D_S(s0, s0);
|
||||
FDIVD(v1, s0, v1);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
|
||||
@@ -5,10 +5,8 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
@@ -433,6 +431,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
FSQRTD(v1, v1);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
@@ -511,7 +510,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FLD ST0, float[ED]");
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, BOX64ENV(dynarec_x87double)?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, (BOX64ENV(dynarec_x87double)==1)?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v1, ed, fixedaddress);
|
||||
if(!ST_IS_F(0)) {
|
||||
@@ -558,11 +557,14 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
MOV32w(x2, 0);
|
||||
CALL(fpu_loadenv, -1);
|
||||
NATIVE_RESTORE_X87PC();
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FLDCW Ew");
|
||||
GETEW(x1, 0);
|
||||
STRH_U12(x1, xEmu, offsetof(x64emu_t, cw)); // hopefully cw is not too far for an imm8
|
||||
if(dyn->need_x87check)
|
||||
UBFXw(x87pc, x1, 8, 2);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FNSTENV Ed");
|
||||
|
||||
@@ -5,10 +5,8 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
@@ -152,6 +150,7 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
FADDD(v1, v1, v2);
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
@@ -166,6 +165,7 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
FMULD(v1, v1, v2);
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
@@ -203,6 +203,7 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
FSUBD(v1, v1, v2);
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
@@ -217,6 +218,7 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
FSUBD(v1, v2, v1);
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
@@ -231,6 +233,7 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
FDIVD(v1, v1, v2);
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
@@ -245,6 +248,7 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
FDIVD(v1, v2, v1);
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
|
||||
@@ -5,10 +5,8 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
@@ -136,6 +134,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (FNINIT)\n");
|
||||
x87_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
CALL(reset_fpu, -1);
|
||||
NATIVE_RESTORE_X87PC();
|
||||
break;
|
||||
case 0xE8:
|
||||
case 0xE9:
|
||||
|
||||
@@ -5,10 +5,8 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
@@ -57,6 +55,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
FADDD(v1, v1, v2);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
@@ -78,6 +77,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
FMULD(v1, v1, v2);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
@@ -136,6 +136,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
FSUBD(v1, v2, v1);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
@@ -157,6 +158,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
FSUBD(v1, v1, v2);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
@@ -178,6 +180,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
FDIVD(v1, v2, v1);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
@@ -199,6 +202,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
FDIVD(v1, v1, v2);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
@@ -216,6 +220,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
FADDD(v1, v1, v2);
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
@@ -228,6 +233,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
FMULD(v1, v1, v2);
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
@@ -259,6 +265,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
FSUBD(v1, v1, v2);
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
@@ -271,6 +278,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
FSUBD(v1, v2, v1);
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
@@ -283,6 +291,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
FDIVD(v1, v1, v2);
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
@@ -295,6 +304,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
FDIVD(v1, v2, v1);
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
|
||||
@@ -5,10 +5,8 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
@@ -208,6 +206,7 @@ uintptr_t dynarec64_DD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
CALL(native_fsave, -1);
|
||||
CALL(reset_fpu, -1);
|
||||
NATIVE_RESTORE_X87PC();
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FNSTSW m2byte");
|
||||
|
||||
@@ -5,10 +5,8 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
@@ -57,6 +55,7 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
FADDD(v1, v1, v2);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
@@ -79,6 +78,7 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
FMULD(v1, v1, v2);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
@@ -133,6 +133,7 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
FSUBD(v1, v2, v1);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
@@ -155,6 +156,7 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
FSUBD(v1, v1, v2);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
@@ -177,6 +179,7 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
FDIVD(v1, v2, v1);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
@@ -199,6 +202,7 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
FDIVD(v1, v1, v2);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
@@ -218,6 +222,7 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
FADDD(v1, v1, v2);
|
||||
X87_CHECK_PRECISION(v1);
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FIMUL ST0, word[ED]");
|
||||
@@ -229,6 +234,7 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
FMULD(v1, v1, v2);
|
||||
X87_CHECK_PRECISION(v1);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FICOM ST0, word[ED]");
|
||||
@@ -265,6 +271,7 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
FSUBD(v1, v1, v2);
|
||||
X87_CHECK_PRECISION(v1);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FISUBR ST0, word[ED]");
|
||||
@@ -276,6 +283,7 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
FSUBD(v1, v2, v1);
|
||||
X87_CHECK_PRECISION(v1);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FIDIV ST0, word[ED]");
|
||||
@@ -287,6 +295,7 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
FDIVD(v1, v1, v2);
|
||||
X87_CHECK_PRECISION(v1);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FIDIVR ST0, word[ED]");
|
||||
@@ -298,6 +307,7 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
FDIVD(v1, v2, v1);
|
||||
X87_CHECK_PRECISION(v1);
|
||||
break;
|
||||
}
|
||||
return addr;
|
||||
|
||||
@@ -5,10 +5,8 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
|
||||
@@ -5,10 +5,8 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
|
||||
@@ -5,10 +5,8 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
|
||||
@@ -5,10 +5,8 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
|
||||
@@ -5,10 +5,8 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
|
||||
@@ -5,10 +5,8 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
@@ -52,7 +50,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
|
||||
|
||||
GETREX();
|
||||
SKIPTEST(x1); // DYNAREC_TEST doesn't work, by nature, on atomic opration
|
||||
//SKIPTEST(x1); // DYNAREC_TEST doesn't work, by nature, on atomic opration
|
||||
|
||||
switch(opcode) {
|
||||
case 0x00:
|
||||
@@ -285,11 +283,9 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
UFLAG_IF {emit_cmp8(dyn, ninst, x6, ed, x3, x4, x5);}
|
||||
SUBxw_REG(x6, x6, x2);
|
||||
CBNZxw_MARK2(x6);
|
||||
BFIx(wback, x2, wb2, 8);
|
||||
MOVxw_REG(ed, gd);
|
||||
BFIx(wback, gd, wb2, 8);
|
||||
MARK2;
|
||||
BFIx(xRAX, x2, 0, 8);
|
||||
B_NEXT_nocond;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
if(arm64_atomics) {
|
||||
@@ -331,14 +327,14 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
wback = 0;
|
||||
UFLAG_IF {emit_cmp32(dyn, ninst, rex, xRAX, ed, x3, x4, x5);}
|
||||
MOVxw_REG(x1, ed); // save value
|
||||
SUBxw_REG(x3, xRAX, x1);
|
||||
CBNZxw_MARK2(x3);
|
||||
MOVxw_REG(ed, gd);
|
||||
MARK2;
|
||||
UFLAG_IF {
|
||||
emit_cmp32(dyn, ninst, rex, xRAX, ed, x3, x4, x5);
|
||||
} else {
|
||||
CMPSxw_REG(xRAX, ed);
|
||||
}
|
||||
MOVxw_REG(x1, ed); // save value
|
||||
CSELxw(ed, gd, ed, cEQ);
|
||||
MOVxw_REG(xRAX, x1);
|
||||
B_NEXT_nocond;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
if(!ALIGNED_ATOMICxw) {
|
||||
@@ -375,7 +371,6 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
// EAX == Ed
|
||||
STLXRxw(x4, gd, wback);
|
||||
CBNZx_MARKLOCK(x4);
|
||||
SMDMB();
|
||||
// done
|
||||
if(!ALIGNED_ATOMICxw) {
|
||||
B_MARK_nocond;
|
||||
@@ -394,9 +389,9 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
STLXRB(x4, gd, wback);
|
||||
CBNZx_MARK3(x4);
|
||||
STRxw_U12(gd, wback, 0);
|
||||
SMDMB();
|
||||
}
|
||||
MARK;
|
||||
SMDMB();
|
||||
// Common part (and fallback for EAX != Ed)
|
||||
UFLAG_IF {emit_cmp32(dyn, ninst, rex, xRAX, x1, x3, x4, x5); MOVxw_REG(xRAX, x1);}
|
||||
else {
|
||||
@@ -1368,22 +1363,27 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
if(arm64_atomics) {
|
||||
MOV64xw(x5, i64);
|
||||
UFLAG_IF {
|
||||
LDSETALxw(x5, x1, wback);
|
||||
emit_or32(dyn, ninst, rex, x1, x5, x3, x4);
|
||||
} else {
|
||||
STSETLxw(x5, wback);
|
||||
}
|
||||
if(wback==xRSP && !i64) {
|
||||
// this is __faststorefence
|
||||
DMB_ST();
|
||||
} else {
|
||||
MARKLOCK;
|
||||
LDAXRxw(x1, wback);
|
||||
emit_or32c(dyn, ninst, rex, x1, i64, x3, x4);
|
||||
STLXRxw(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
if(arm64_atomics) {
|
||||
MOV64xw(x5, i64);
|
||||
UFLAG_IF {
|
||||
LDSETALxw(x5, x1, wback);
|
||||
emit_or32(dyn, ninst, rex, x1, x5, x3, x4);
|
||||
} else {
|
||||
STSETLxw(x5, wback);
|
||||
}
|
||||
} else {
|
||||
MARKLOCK;
|
||||
LDAXRxw(x1, wback);
|
||||
emit_or32c(dyn, ninst, rex, x1, i64, x3, x4);
|
||||
STLXRxw(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
SMDMB();
|
||||
}
|
||||
SMDMB();
|
||||
}
|
||||
break;
|
||||
case 2: //ADC
|
||||
|
||||
@@ -5,10 +5,8 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
@@ -34,7 +32,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
int32_t i32, i32_;
|
||||
int cacheupd = 0;
|
||||
int v0, v1;
|
||||
int q0;
|
||||
int q0, q1;
|
||||
int d0, d1;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
@@ -42,6 +40,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
MAYUSE(d0);
|
||||
MAYUSE(d1);
|
||||
MAYUSE(q0);
|
||||
MAYUSE(q1);
|
||||
MAYUSE(v0);
|
||||
MAYUSE(v1);
|
||||
|
||||
@@ -119,13 +118,23 @@ 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)) {
|
||||
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
}
|
||||
FCVTZSxwD(gd, q0);
|
||||
if(!BOX64ENV(dynarec_fastround)) {
|
||||
if(!BOX64ENV(dynarec_fastround) && arm64_frintts) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
if(rex.w) {
|
||||
FRINT64ZD(v0, q0);
|
||||
} else {
|
||||
FRINT32ZD(v0, q0);
|
||||
}
|
||||
FCVTZSxwD(gd, v0);
|
||||
} else {
|
||||
FCVTZSxwD(gd, q0);
|
||||
}
|
||||
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_NEXT(x5, FPSR_IOC);
|
||||
if(rex.w) {
|
||||
@@ -140,17 +149,25 @@ 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)) {
|
||||
if(!BOX64ENV(dynarec_fastround) && !arm64_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);
|
||||
FRINTID(d1, q0);
|
||||
if(!BOX64ENV(dynarec_fastround) && arm64_frintts) {
|
||||
if(rex.w) {
|
||||
FRINT64XD(d1, q0);
|
||||
} else {
|
||||
FRINT32XD(d1, q0);
|
||||
}
|
||||
} else {
|
||||
FRINTID(d1, q0);
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
FCVTZSxwD(gd, d1);
|
||||
if(!BOX64ENV(dynarec_fastround)) {
|
||||
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_NEXT(x5, FPSR_IOC);
|
||||
if(rex.w) {
|
||||
@@ -319,15 +336,9 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(v0, 1);
|
||||
GETEXSD(v1, 0, 0);
|
||||
// MINSD: if any input is NaN, or Ex[0]<Gx[0], copy Ex[0] -> Gx[0]
|
||||
#if 0
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
FMINNMD(d0, v0, v1); // NaN handling may be slightly different, is that a problem?
|
||||
VMOVeD(v0, 0, d0, 0); // to not erase uper part
|
||||
#else
|
||||
FCMPD(v0, v1);
|
||||
B_NEXT(cCC); //Less than
|
||||
B_NEXT(cCC); //CC invert of CS: NAN or == or Gx > Ex
|
||||
VMOVeD(v0, 0, v1, 0); // to not erase uper part
|
||||
#endif
|
||||
break;
|
||||
case 0x5E:
|
||||
INST_NAME("DIVSD Gx, Ex");
|
||||
@@ -357,15 +368,9 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(v0, 1);
|
||||
GETEXSD(v1, 0, 0);
|
||||
// MAXSD: if any input is NaN, or Ex[0]>Gx[0], copy Ex[0] -> Gx[0]
|
||||
#if 0
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
FMAXNMD(d0, v0, v1); // NaN handling may be slightly different, is that a problem?
|
||||
VMOVeD(v0, 0, d0, 0); // to not erase uper part
|
||||
#else
|
||||
FCMPD(v0, v1);
|
||||
B_NEXT(cGT); //Greater than
|
||||
FCMPD(v1, v0);
|
||||
B_NEXT(cCC); //CC invert of CS: NAN or == or Ex > Gx
|
||||
VMOVeD(v0, 0, v1, 0); // to not erase uper part
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 0x70:
|
||||
@@ -404,9 +409,22 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
case 0x7C:
|
||||
INST_NAME("HADDPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 1);
|
||||
VFADDPQS(v0, v0, v1);
|
||||
GETGX(q1, 1);
|
||||
GETEX(q0, 0, 0);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
VFMAXPQS(v0, q1, q0); // propagate NAN
|
||||
VFCMEQQS(v0, v0, v0); // 0 if NAN, 1 if not NAN
|
||||
}
|
||||
VFADDPQS(q1, q1, q0);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
VFCMEQQS(v1, q1, q1); // 0 => out is NAN
|
||||
VBICQ(v1, v0, v1); // forget it in any input was a NAN already
|
||||
VSHLQ_32(v1, v1, 31); // only keep the sign bit
|
||||
VORRQ(q1, q1, v1); // NAN -> -NAN
|
||||
}
|
||||
break;
|
||||
case 0x7D:
|
||||
INST_NAME("HSUBPS Gx, Ex");
|
||||
@@ -416,7 +434,19 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
VUZP1Q_32(d0, v0, v1);
|
||||
VUZP2Q_32(v0, v0, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
VFMAXQS(d1, d0, v0); // propagate NAN
|
||||
VFCMEQQS(d1, d1, d1); // 0 if NAN, 1 if not NAN
|
||||
}
|
||||
VFSUBQS(v0, d0, v0);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
VFCMEQQS(d0, v0, v0); // 0 => out is NAN
|
||||
VBICQ(d1, d1, d0); // forget it in any input was a NAN already
|
||||
VSHLQ_32(d1, d1, 31); // only keep the sign bit
|
||||
VORRQ(v0, v0, d1); // NAN -> -NAN
|
||||
}
|
||||
break;
|
||||
|
||||
#define GO(GETFLAGS, NO, YES, F) \
|
||||
@@ -521,28 +551,32 @@ 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);
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
ORRw_mask(x4, xZR, 1, 0); //0x80000000
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
for(int i=0; i<2; ++i) {
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
if(i) {
|
||||
VMOVeD(d0, 0, v1, i);
|
||||
FRINTID(d0, d0);
|
||||
} else {
|
||||
FRINTID(d0, v1);
|
||||
if(arm64_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
|
||||
} else {
|
||||
MRS_fpsr(x5);
|
||||
ORRw_mask(x4, xZR, 1, 0); //0x80000000
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
for(int i=0; i<2; ++i) {
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
if(i) {
|
||||
VMOVeD(d0, 0, v1, i);
|
||||
FRINTID(d0, d0);
|
||||
} else {
|
||||
FRINTID(d0, v1);
|
||||
}
|
||||
FCVTZSwD(x1, d0);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ(x5, FPSR_IOC, 4+4);
|
||||
MOVw_REG(x1, x4);
|
||||
VMOVQSfrom(v0, i, x1);
|
||||
}
|
||||
FCVTZSwD(x1, d0);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ(x5, FPSR_IOC, 4+4);
|
||||
MOVw_REG(x1, x4);
|
||||
VMOVQSfrom(v0, i, x1);
|
||||
VMOVQDfrom(v0, 1, xZR);
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
VMOVQDfrom(v0, 1, xZR);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -557,7 +591,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 7, 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;
|
||||
|
||||
@@ -5,10 +5,8 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
@@ -79,30 +77,14 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
case 0x12:
|
||||
INST_NAME("MOVSLDUP Gx, Ex");
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
q1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
VLD128(q1, ed, fixedaddress);
|
||||
}
|
||||
GETGX_empty(q0);
|
||||
GETGX_empty_EX(q0, q1, 0);
|
||||
VTRNQ1_32(q0, q1, q1);
|
||||
break;
|
||||
|
||||
case 0x16:
|
||||
INST_NAME("MOVSHDUP Gx, Ex");
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
q1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
VLD128(q1, ed, fixedaddress);
|
||||
}
|
||||
GETGX_empty(q0);
|
||||
GETGX_empty_EX(q0, q1, 0);
|
||||
VTRNQ2_32(q0, q1, q1);
|
||||
break;
|
||||
|
||||
@@ -118,11 +100,17 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(v0, 1);
|
||||
GETED(0);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
if(BOX64ENV(dynarec_fastround)<2) {
|
||||
u8 = sse_setround(dyn, ninst, x3, x4, x5);
|
||||
}
|
||||
if(rex.w) {
|
||||
SCVTFSx(d1, ed);
|
||||
} else {
|
||||
SCVTFSw(d1, ed);
|
||||
}
|
||||
if(BOX64ENV(dynarec_fastround)<2) {
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
}
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
break;
|
||||
|
||||
@@ -131,13 +119,23 @@ 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)) {
|
||||
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
}
|
||||
FCVTZSxwS(gd, d0);
|
||||
if(!BOX64ENV(dynarec_fastround)) {
|
||||
if(!BOX64ENV(dynarec_fastround) && arm64_frintts) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
if(rex.w) {
|
||||
FRINT64ZS(v0, d0);
|
||||
} else {
|
||||
FRINT32ZS(v0, d0);
|
||||
}
|
||||
FCVTZSxwS(gd, v0);
|
||||
} else {
|
||||
FCVTZSxwS(gd, d0);
|
||||
}
|
||||
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_NEXT(x5, FPSR_IOC);
|
||||
if(rex.w) {
|
||||
@@ -152,17 +150,25 @@ 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)) {
|
||||
if(!BOX64ENV(dynarec_fastround) && !arm64_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);
|
||||
FRINTIS(d1, q0);
|
||||
if(!BOX64ENV(dynarec_fastround) && arm64_frintts) {
|
||||
if(rex.w) {
|
||||
FRINT64XS(d1, q0);
|
||||
} else {
|
||||
FRINT32XS(d1, q0);
|
||||
}
|
||||
} else {
|
||||
FRINTIS(d1, q0);
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
FCVTZSxwS(gd, d1);
|
||||
if(!BOX64ENV(dynarec_fastround)) {
|
||||
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_NEXT(x5, FPSR_IOC);
|
||||
if(rex.w) {
|
||||
@@ -209,11 +215,23 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
case 0x51:
|
||||
INST_NAME("SQRTSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETGX(q0, 1);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSS(d0, 0, 0);
|
||||
FSQRTS(d1, d0);
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
FCMEQS(v0, d0, d0); // 0 if NAN, 1 if not NAN
|
||||
FSQRTS(d1, d0);
|
||||
FCMEQS(v1, d1, d1); // 0 => out is NAN
|
||||
VBIC(v1, v0, v1); // forget it in any input was a NAN already
|
||||
VSHL_32(v1, v1, 31); // only keep the sign bit
|
||||
VORR(d1, d1, v1); // NAN -> -NAN
|
||||
} else {
|
||||
FSQRTS(d1, d0);
|
||||
}
|
||||
VMOVeS(q0, 0, d1, 0);
|
||||
break;
|
||||
case 0x52:
|
||||
INST_NAME("RSQRTSS Gx, Ex");
|
||||
@@ -304,20 +322,40 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(BOX64ENV(dynarec_fastround)) {
|
||||
VFCVTZSQS(v0, v1);
|
||||
} else {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
ORRw_mask(x4, xZR, 1, 0); //0x80000000
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
for(int i=0; i<4; ++i) {
|
||||
if(arm64_frintts) {
|
||||
VFRINT32ZSQ(v0, v1);
|
||||
VFCVTZSQS(v0, v0);
|
||||
} else {
|
||||
// try to transform the 4 values first, then fall back to 1 at time if needed
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
VMOVeS(d0, 0, v1, i);
|
||||
VFCVTZSs(d0, d0);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
if(v0!=v1) {
|
||||
VFCVTZSQS(v0, v1);
|
||||
} else {
|
||||
VFCVTZSQS(d0, v1);
|
||||
}
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ(x5, FPSR_IOC, 4+4);
|
||||
VMOVQSfrom(d0, 0, x4);
|
||||
VMOVeS(v0, i, d0, 0);
|
||||
if(v0!=v1) {
|
||||
TBZ_NEXT(x5, FPSR_IOC);
|
||||
} else {
|
||||
TBNZ_MARK(x5, FPSR_IOC);
|
||||
VMOVQ(v0, d0);
|
||||
B_NEXT_nocond;
|
||||
MARK;
|
||||
}
|
||||
ORRw_mask(x4, xZR, 1, 0); //0x80000000
|
||||
for(int i=0; i<4; ++i) {
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
VMOVeS(d0, 0, v1, i);
|
||||
VFCVTZSs(d0, d0);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ(x5, FPSR_IOC, 4+4);
|
||||
VMOVQSfrom(d0, 0, x4);
|
||||
VMOVeS(v0, i, d0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -349,15 +387,9 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(v0, 1);
|
||||
GETEXSS(v1, 0, 0);
|
||||
// MINSS: if any input is NaN, or Ex[0]<Gx[0], copy Ex[0] -> Gx[0]
|
||||
#if 0
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
FMINNMS(d0, v0, v1); // NaN handling may be slightly different, is that a problem?
|
||||
VMOVeS(v0, 0, d0, 0); // to not erase uper part
|
||||
#else
|
||||
FCMPS(v0, v1);
|
||||
B_NEXT(cCC); //Less than
|
||||
B_NEXT(cCC); //CC invert of CS: NAN or == or Gx > Ex
|
||||
VMOVeS(v0, 0, v1, 0); // to not erase uper part
|
||||
#endif
|
||||
break;
|
||||
case 0x5E:
|
||||
INST_NAME("DIVSS Gx, Ex");
|
||||
@@ -387,23 +419,16 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(v0, 1);
|
||||
GETEXSS(v1, 0, 0);
|
||||
// MAXSS: if any input is NaN, or Ex[0]>Gx[0], copy Ex[0] -> Gx[0]
|
||||
#if 0
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
FMAXNMS(d0, v0, v1); // NaN handling may be slightly different, is that a problem?
|
||||
VMOVeS(v0, 0, d0, 0); // to not erase uper part
|
||||
#else
|
||||
FCMPS(v0, v1);
|
||||
B_NEXT(cGT); //Greater than
|
||||
FCMPS(v1, v0);
|
||||
B_NEXT(cCC); //CC: invert of CS: NAN or == or Ex > Gx
|
||||
VMOVeS(v0, 0, v1, 0); // to not erase uper part
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 0x6F:
|
||||
INST_NAME("MOVDQU Gx,Ex");// no alignment constraint on NEON here, so same as MOVDQA
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
GETGX_empty(v0);
|
||||
GETGX_empty_EX(v0, v1, 0);
|
||||
VMOVQ(v0, v1);
|
||||
} else {
|
||||
GETGX_empty(v0);
|
||||
@@ -461,14 +486,11 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
IF_UNALIGNED(ip) {
|
||||
MESSAGE(LOG_DEBUG, "\tUnaligned path");
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(wback!=x1) {
|
||||
MOVx_REG(x1, wback);
|
||||
wback = x1;
|
||||
}
|
||||
for(int i=0; i<16; ++i) {
|
||||
VST1_8(v0, i, wback);
|
||||
ADDx_U12(wback, wback, 1);
|
||||
VST1_8(v0, i, i?x1:wback);
|
||||
ADDx_U12(x1, i?x1:wback, 1);
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
@@ -552,7 +574,15 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
|
||||
case 0xBC:
|
||||
INST_NAME("TZCNT Gd, Ed");
|
||||
SETFLAGS(X_CF|X_ZF, SF_SUBSET);
|
||||
if(!BOX64ENV(dynarec_safeflags)) {
|
||||
SETFLAGS(X_CF|X_ZF, SF_SUBSET);
|
||||
} else {
|
||||
if(BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_ALL&~X_OF, SF_SUBSET);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
}
|
||||
}
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
@@ -569,10 +599,24 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
CSETw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_ZF, 1); // ZF = is dest 0?
|
||||
}
|
||||
if(BOX64ENV(dynarec_safeflags)) {
|
||||
IFX(X_AF) BFCw(xFlags, F_AF, 1);
|
||||
IFX(X_PF) BFCw(xFlags, F_PF, 1);
|
||||
IFX(X_SF) BFCw(xFlags, F_SF, 1);
|
||||
IFX2(X_OF, && !BOX64ENV(cputype)) BFCw(xFlags, F_OF, 1);
|
||||
}
|
||||
break;
|
||||
case 0xBD:
|
||||
INST_NAME("LZCNT Gd, Ed");
|
||||
SETFLAGS(X_CF|X_ZF, SF_SUBSET);
|
||||
if(!BOX64ENV(dynarec_safeflags)) {
|
||||
SETFLAGS(X_CF|X_ZF, SF_SUBSET);
|
||||
} else {
|
||||
if(BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_ALL&~X_OF, SF_SUBSET);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
}
|
||||
}
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
@@ -588,6 +632,12 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
CSETw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_ZF, 1); // ZF = is dest 0?
|
||||
}
|
||||
if(BOX64ENV(dynarec_safeflags)) {
|
||||
IFX(X_AF) BFCw(xFlags, F_AF, 1);
|
||||
IFX(X_PF) BFCw(xFlags, F_PF, 1);
|
||||
IFX(X_SF) BFCw(xFlags, F_SF, 1);
|
||||
IFX2(X_OF, && !BOX64ENV(cputype)) BFCw(xFlags, F_OF, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC2:
|
||||
|
||||
@@ -10,28 +10,31 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "emu/x87emu_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "signals.h"
|
||||
#include "dynarec_native.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "custommem.h"
|
||||
#include "bridge.h"
|
||||
#include "gdbjit.h"
|
||||
#include "perfmap.h"
|
||||
|
||||
// Get a FPU scratch reg
|
||||
int fpu_get_scratch(dynarec_arm_t* dyn, int ninst)
|
||||
{
|
||||
int ret = SCRATCH0 + dyn->n.fpu_scratch++;
|
||||
if(dyn->n.ymm_used) printf_log(LOG_INFO, "Warning, getting a scratch register after getting some YMM at inst=%d\n", ninst);
|
||||
if(dyn->n.ymm_used) {
|
||||
printf_log(LOG_INFO, "Warning, getting a scratch register after getting some YMM at inst=%d", ninst);
|
||||
uint8_t* addr = (uint8_t*)dyn->insts[ninst].x64.addr;
|
||||
printf_log_prefix(0, LOG_INFO, "(%hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX)\n", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7]);
|
||||
}
|
||||
if(dyn->n.neoncache[ret].t==NEON_CACHE_YMMR || dyn->n.neoncache[ret].t==NEON_CACHE_YMMW) {
|
||||
// should only happens in step 0...
|
||||
dyn->insts[ninst].purge_ymm |= (1<<dyn->n.neoncache[ret].n); // mark as purged
|
||||
@@ -43,7 +46,11 @@ int fpu_get_scratch(dynarec_arm_t* dyn, int ninst)
|
||||
int fpu_get_double_scratch(dynarec_arm_t* dyn, int ninst)
|
||||
{
|
||||
int ret = SCRATCH0 + dyn->n.fpu_scratch;
|
||||
if(dyn->n.ymm_used) printf_log(LOG_INFO, "Warning, getting a double scratch register after getting some YMM at inst=%d\n", ninst);
|
||||
if(dyn->n.ymm_used) {
|
||||
printf_log(LOG_INFO, "Warning, getting a double scratch register after getting some YMM at inst=%d", ninst);
|
||||
uint8_t* addr = (uint8_t*)dyn->insts[ninst].x64.addr;
|
||||
printf_log_prefix(0, LOG_INFO, "(%hhX %hhX %hhX %hhX %hhX %hhX %hhX %hhX)\n", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7]);
|
||||
}
|
||||
if(dyn->n.neoncache[ret].t==NEON_CACHE_YMMR || dyn->n.neoncache[ret].t==NEON_CACHE_YMMW) {
|
||||
// should only happens in step 0...
|
||||
dyn->insts[ninst].purge_ymm |= (1<<dyn->n.neoncache[ret].n); // mark as purged
|
||||
@@ -65,6 +72,11 @@ void fpu_reset_scratch(dynarec_arm_t* dyn)
|
||||
dyn->n.ymm_regs = 0;
|
||||
dyn->n.ymm_write = 0;
|
||||
dyn->n.ymm_removed = 0;
|
||||
dyn->n.xmm_write = 0;
|
||||
dyn->n.xmm_used = 0;
|
||||
dyn->n.xmm_unneeded = 0;
|
||||
dyn->n.ymm_unneeded = 0;
|
||||
dyn->n.xmm_removed = 0;
|
||||
}
|
||||
// Get a x87 double reg
|
||||
int fpu_get_reg_x87(dynarec_arm_t* dyn, int ninst, int t, int n)
|
||||
@@ -96,6 +108,11 @@ void fpu_free_reg(dynarec_arm_t* dyn, int reg)
|
||||
else
|
||||
dyn->n.ymm_regs |= ((uint64_t)(reg-EMM0))<<(dyn->n.neoncache[reg].n*4);
|
||||
}
|
||||
if(dyn->n.neoncache[reg].t==NEON_CACHE_XMMR || dyn->n.neoncache[reg].t==NEON_CACHE_XMMW) {
|
||||
dyn->n.xmm_removed |= 1<<dyn->n.neoncache[reg].n;
|
||||
if(dyn->n.neoncache[reg].t==NEON_CACHE_XMMW)
|
||||
dyn->n.xmm_write |= 1<<dyn->n.neoncache[reg].n;
|
||||
}
|
||||
if(dyn->n.neoncache[reg].t!=NEON_CACHE_ST_F && dyn->n.neoncache[reg].t!=NEON_CACHE_ST_D && dyn->n.neoncache[reg].t!=NEON_CACHE_ST_I64)
|
||||
dyn->n.neoncache[reg].v = 0;
|
||||
if(dyn->n.fpu_scratch && reg==SCRATCH0+dyn->n.fpu_scratch-1)
|
||||
@@ -174,6 +191,8 @@ static void fpu_reset_reg_neoncache(neoncache_t* n)
|
||||
n->ymm_removed = 0;
|
||||
n->ymm_used = 0;
|
||||
n->ymm_write = 0;
|
||||
n->xmm_removed = 0;
|
||||
n->xmm_write = 0;
|
||||
|
||||
}
|
||||
void fpu_reset_reg(dynarec_arm_t* dyn)
|
||||
@@ -287,9 +306,10 @@ static void neoncache_promote_double_combined(dynarec_arm_t* dyn, int ninst, int
|
||||
} else
|
||||
a = dyn->insts[ninst].n.combined1;
|
||||
int i = neoncache_get_st_f_i64_noback(dyn, ninst, a);
|
||||
//if(BOX64DRENV(dynarec_dump)) dynarec_log(LOG_NONE, "neoncache_promote_double_combined, ninst=%d combined%c %d i=%d (stack:%d/%d)\n", ninst, (a == dyn->insts[ninst].n.combined2)?'2':'1', a ,i, dyn->insts[ninst].n.stack_push, -dyn->insts[ninst].n.stack_pop);
|
||||
//if(dyn->need_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_combined, ninst=%d combined%c %d i=%d (stack:%d/%d)\n", ninst, (a == dyn->insts[ninst].n.combined2)?'2':'1', a ,i, dyn->insts[ninst].n.stack_push, -dyn->insts[ninst].n.stack_pop);
|
||||
if(i>=0) {
|
||||
dyn->insts[ninst].n.neoncache[i].t = NEON_CACHE_ST_D;
|
||||
if(dyn->insts[ninst].x87precision) dyn->need_x87check = 2;
|
||||
if(!dyn->insts[ninst].n.barrier)
|
||||
neoncache_promote_double_internal(dyn, ninst-1, maxinst, a-dyn->insts[ninst].n.stack_push);
|
||||
// go forward is combined is not pop'd
|
||||
@@ -304,19 +324,20 @@ static void neoncache_promote_double_internal(dynarec_arm_t* dyn, int ninst, int
|
||||
while(ninst>=0) {
|
||||
a+=dyn->insts[ninst].n.stack_pop; // adjust Stack depth: add pop'd ST (going backward)
|
||||
int i = neoncache_get_st_f_i64(dyn, ninst, a);
|
||||
//if(BOX64DRENV(dynarec_dump)) dynarec_log(LOG_NONE, "neoncache_promote_double_internal, ninst=%d, a=%d st=%d:%d, i=%d\n", ninst, a, dyn->insts[ninst].n.stack, dyn->insts[ninst].n.stack_next, i);
|
||||
//if(dyn->need_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_internal, ninst=%d, a=%d st=%d:%d, i=%d\n", ninst, a, dyn->insts[ninst].n.stack, dyn->insts[ninst].n.stack_next, i);
|
||||
if(i<0) return;
|
||||
dyn->insts[ninst].n.neoncache[i].t = NEON_CACHE_ST_D;
|
||||
if(dyn->insts[ninst].x87precision) dyn->need_x87check = 2;
|
||||
// check combined propagation too
|
||||
if(dyn->insts[ninst].n.combined1 || dyn->insts[ninst].n.combined2) {
|
||||
if(dyn->insts[ninst].n.swapped) {
|
||||
//if(BOX64DRENV(dynarec_dump)) dynarec_log(LOG_NONE, "neoncache_promote_double_internal, ninst=%d swapped %d/%d vs %d with st %d\n", ninst, dyn->insts[ninst].n.combined1 ,dyn->insts[ninst].n.combined2, a, dyn->insts[ninst].n.stack);
|
||||
//if(dyn->need_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_internal, ninst=%d swapped %d/%d vs %d with st %d\n", ninst, dyn->insts[ninst].n.combined1 ,dyn->insts[ninst].n.combined2, a, dyn->insts[ninst].n.stack);
|
||||
if (a==dyn->insts[ninst].n.combined1)
|
||||
a = dyn->insts[ninst].n.combined2;
|
||||
else if (a==dyn->insts[ninst].n.combined2)
|
||||
a = dyn->insts[ninst].n.combined1;
|
||||
} else {
|
||||
//if(BOX64DRENV(dynarec_dump)) dynarec_log(LOG_NONE, "neoncache_promote_double_internal, ninst=%d combined %d/%d vs %d with st %d\n", ninst, dyn->insts[ninst].n.combined1 ,dyn->insts[ninst].n.combined2, a, dyn->insts[ninst].n.stack);
|
||||
//if(dyn->need_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_internal, ninst=%d combined %d/%d vs %d with st %d\n", ninst, dyn->insts[ninst].n.combined1 ,dyn->insts[ninst].n.combined2, a, dyn->insts[ninst].n.stack);
|
||||
neoncache_promote_double_combined(dyn, ninst, maxinst, a);
|
||||
}
|
||||
}
|
||||
@@ -332,19 +353,20 @@ static void neoncache_promote_double_forward(dynarec_arm_t* dyn, int ninst, int
|
||||
while((ninst!=-1) && (ninst<maxinst) && (a>=0)) {
|
||||
a+=dyn->insts[ninst].n.stack_push; // // adjust Stack depth: add push'd ST (going forward)
|
||||
if((dyn->insts[ninst].n.combined1 || dyn->insts[ninst].n.combined2) && dyn->insts[ninst].n.swapped) {
|
||||
//if(BOX64DRENV(dynarec_dump)) dynarec_log(LOG_NONE, "neoncache_promote_double_forward, ninst=%d swapped %d/%d vs %d with st %d\n", ninst, dyn->insts[ninst].n.combined1 ,dyn->insts[ninst].n.combined2, a, dyn->insts[ninst].n.stack);
|
||||
//if(dyn->need_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_forward, ninst=%d swapped %d/%d vs %d with st %d\n", ninst, dyn->insts[ninst].n.combined1 ,dyn->insts[ninst].n.combined2, a, dyn->insts[ninst].n.stack);
|
||||
if (a==dyn->insts[ninst].n.combined1)
|
||||
a = dyn->insts[ninst].n.combined2;
|
||||
else if (a==dyn->insts[ninst].n.combined2)
|
||||
a = dyn->insts[ninst].n.combined1;
|
||||
}
|
||||
int i = neoncache_get_st_f_i64_noback(dyn, ninst, a);
|
||||
//if(BOX64DRENV(dynarec_dump)) dynarec_log(LOG_NONE, "neoncache_promote_double_forward, ninst=%d, a=%d st=%d:%d(%d/%d), i=%d\n", ninst, a, dyn->insts[ninst].n.stack, dyn->insts[ninst].n.stack_next, dyn->insts[ninst].n.stack_push, -dyn->insts[ninst].n.stack_pop, i);
|
||||
//if(dyn->need_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_forward, ninst=%d, a=%d st=%d:%d(%d/%d), i=%d\n", ninst, a, dyn->insts[ninst].n.stack, dyn->insts[ninst].n.stack_next, dyn->insts[ninst].n.stack_push, -dyn->insts[ninst].n.stack_pop, i);
|
||||
if(i<0) return;
|
||||
dyn->insts[ninst].n.neoncache[i].t = NEON_CACHE_ST_D;
|
||||
if(dyn->insts[ninst].x87precision) dyn->need_x87check = 2;
|
||||
// check combined propagation too
|
||||
if((dyn->insts[ninst].n.combined1 || dyn->insts[ninst].n.combined2) && !dyn->insts[ninst].n.swapped) {
|
||||
//if(BOX64DRENV(dynarec_dump)) dynarec_log(LOG_NONE, "neoncache_promote_double_forward, ninst=%d combined %d/%d vs %d with st %d\n", ninst, dyn->insts[ninst].n.combined1 ,dyn->insts[ninst].n.combined2, a, dyn->insts[ninst].n.stack);
|
||||
//if(dyn->need_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_forward, ninst=%d combined %d/%d vs %d with st %d\n", ninst, dyn->insts[ninst].n.combined1 ,dyn->insts[ninst].n.combined2, a, dyn->insts[ninst].n.stack);
|
||||
neoncache_promote_double_combined(dyn, ninst, maxinst, a);
|
||||
}
|
||||
a-=dyn->insts[ninst].n.stack_pop; // adjust Stack depth: remove pop'd ST (going forward)
|
||||
@@ -360,20 +382,21 @@ static void neoncache_promote_double_forward(dynarec_arm_t* dyn, int ninst, int
|
||||
void neoncache_promote_double(dynarec_arm_t* dyn, int ninst, int a)
|
||||
{
|
||||
int i = neoncache_get_current_st_f_i64(dyn, a);
|
||||
//if(BOX64DRENV(dynarec_dump)) dynarec_log(LOG_NONE, "neoncache_promote_double, ninst=%d a=%d st=%d i=%d\n", ninst, a, dyn->n.stack, i);
|
||||
//if(dyn->need_dump) dynarec_log(LOG_NONE, "neoncache_promote_double, ninst=%d a=%d st=%d i=%d\n", ninst, a, dyn->n.stack, i);
|
||||
if(i<0) return;
|
||||
dyn->n.neoncache[i].t = NEON_CACHE_ST_D;
|
||||
dyn->insts[ninst].n.neoncache[i].t = NEON_CACHE_ST_D;
|
||||
if(dyn->insts[ninst].x87precision) dyn->need_x87check = 2;
|
||||
// check combined propagation too
|
||||
if(dyn->n.combined1 || dyn->n.combined2) {
|
||||
if(dyn->n.swapped) {
|
||||
//if(BOX64DRENV(dynarec_dump)) dynarec_log(LOG_NONE, "neoncache_promote_double, ninst=%d swapped! %d/%d vs %d\n", ninst, dyn->n.combined1 ,dyn->n.combined2, a);
|
||||
//if(dyn->need_dump) dynarec_log(LOG_NONE, "neoncache_promote_double, ninst=%d swapped! %d/%d vs %d\n", ninst, dyn->n.combined1 ,dyn->n.combined2, a);
|
||||
if(dyn->n.combined1 == a)
|
||||
a = dyn->n.combined2;
|
||||
else if(dyn->n.combined2 == a)
|
||||
a = dyn->n.combined1;
|
||||
} else {
|
||||
//if(BOX64DRENV(dynarec_dump)) dynarec_log(LOG_NONE, "neoncache_promote_double, ninst=%d combined! %d/%d vs %d\n", ninst, dyn->n.combined1 ,dyn->n.combined2, a);
|
||||
//if(dyn->need_dump) dynarec_log(LOG_NONE, "neoncache_promote_double, ninst=%d combined! %d/%d vs %d\n", ninst, dyn->n.combined1 ,dyn->n.combined2, a);
|
||||
if(dyn->n.combined1 == a)
|
||||
neoncache_promote_double(dyn, ninst, dyn->n.combined2);
|
||||
else if(dyn->n.combined2 == a)
|
||||
@@ -431,11 +454,13 @@ int fpuCacheNeedsTransform(dynarec_arm_t* dyn, int ninst) {
|
||||
return 1;
|
||||
for(int i=0; i<32 && !ret; ++i)
|
||||
if(dyn->insts[ninst].n.neoncache[i].v) { // there is something at ninst for i
|
||||
int t = dyn->insts[ninst].n.neoncache[i].t;
|
||||
int n = dyn->insts[ninst].n.neoncache[i].n;
|
||||
if(!(
|
||||
(dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_ST_F
|
||||
|| dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_ST_D
|
||||
|| dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_ST_I64)
|
||||
&& dyn->insts[ninst].n.neoncache[i].n<dyn->insts[ninst].n.stack_pop))
|
||||
(t==NEON_CACHE_ST_F
|
||||
|| t==NEON_CACHE_ST_D
|
||||
|| t==NEON_CACHE_ST_I64)
|
||||
&& n<dyn->insts[ninst].n.stack_pop))
|
||||
ret = 1;
|
||||
}
|
||||
return ret;
|
||||
@@ -451,15 +476,20 @@ int fpuCacheNeedsTransform(dynarec_arm_t* dyn, int ninst) {
|
||||
|
||||
for(int i=0; i<32; ++i) {
|
||||
if(dyn->insts[ninst].n.neoncache[i].v) { // there is something at ninst for i
|
||||
int t = dyn->insts[ninst].n.neoncache[i].t;
|
||||
int n = dyn->insts[ninst].n.neoncache[i].n;
|
||||
if(!cache_i2.neoncache[i].v) { // but there is nothing at i2 for i
|
||||
if(((t==NEON_CACHE_XMMR) || (t==NEON_CACHE_XMMW)) && (cache_i2.xmm_unneeded&(1<<n))) { /* nothing*/}
|
||||
else if(((t==NEON_CACHE_YMMR) || (t==NEON_CACHE_YMMW)) && (cache_i2.ymm_unneeded&(1<<n))) { /* nothing*/}
|
||||
else
|
||||
ret = 1;
|
||||
} else if(dyn->insts[ninst].n.neoncache[i].v!=cache_i2.neoncache[i].v) { // there is something different
|
||||
if(dyn->insts[ninst].n.neoncache[i].n!=cache_i2.neoncache[i].n) { // not the same x64 reg
|
||||
if(n!=cache_i2.neoncache[i].n) { // not the same x64 reg
|
||||
ret = 1;
|
||||
}
|
||||
else if(dyn->insts[ninst].n.neoncache[i].t == NEON_CACHE_XMMR && cache_i2.neoncache[i].t == NEON_CACHE_XMMW)
|
||||
else if((t == NEON_CACHE_XMMR) && cache_i2.neoncache[i].t == NEON_CACHE_XMMW)
|
||||
{/* nothing */ }
|
||||
else if(dyn->insts[ninst].n.neoncache[i].t == NEON_CACHE_YMMR && cache_i2.neoncache[i].t == NEON_CACHE_YMMW)
|
||||
else if((t == NEON_CACHE_YMMR) && cache_i2.neoncache[i].t == NEON_CACHE_YMMW)
|
||||
{/* nothing */ }
|
||||
else
|
||||
ret = 1;
|
||||
@@ -578,7 +608,20 @@ void neoncacheUnwind(neoncache_t* cache)
|
||||
cache->fpuused[i] = 0;
|
||||
}
|
||||
}
|
||||
// add back removed YMM
|
||||
// add back removed XMM
|
||||
if(cache->xmm_removed) {
|
||||
for(int i=0; i<16; ++i)
|
||||
if(cache->xmm_removed&(1<<i)) {
|
||||
int reg = (i<8)?(XMM0+i):(XMM8+i-8);
|
||||
cache->neoncache[reg].t = (cache->xmm_write&(1<<i))?NEON_CACHE_XMMW:NEON_CACHE_XMMR;
|
||||
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;
|
||||
}
|
||||
// add back removed YMM
|
||||
if(cache->ymm_removed) {
|
||||
for(int i=0; i<16; ++i)
|
||||
if(cache->ymm_removed&(1<<i)) {
|
||||
@@ -587,8 +630,8 @@ void neoncacheUnwind(neoncache_t* cache)
|
||||
reg = reg - 8 + SCRATCH0;
|
||||
else
|
||||
reg = reg + EMM0;
|
||||
if(cache->neoncache[reg].v)
|
||||
printf_log(LOG_INFO, "Warning, recreating YMM%d on non empty slot %s", i, getCacheName(cache->neoncache[reg].t, cache->neoncache[reg].n));
|
||||
//if(cache->neoncache[reg].v) // this is normal when a ymm is purged to make space for another one
|
||||
// printf_log(LOG_INFO, "Warning, recreating YMM%d on non empty slot %s", i, getCacheName(cache->neoncache[reg].t, cache->neoncache[reg].n));
|
||||
cache->neoncache[reg].t = (cache->ymm_write&(1<<i))?NEON_CACHE_YMMW:NEON_CACHE_YMMR;
|
||||
cache->neoncache[reg].n = i;
|
||||
}
|
||||
@@ -734,9 +777,9 @@ 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 (!BOX64DRENV(dynarec_dump) && !BOX64ENV(dynarec_gdbjit) && !BOX64ENV(dynarec_perf_map)) return;
|
||||
if (!dyn->need_dump && !BOX64ENV(dynarec_gdbjit) && !BOX64ENV(dynarec_perf_map)) return;
|
||||
|
||||
static char buf[256];
|
||||
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)",
|
||||
dyn->insts[ninst].x64.barrier,
|
||||
dyn->insts[ninst].x64.state_flags,
|
||||
@@ -805,16 +848,19 @@ void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t r
|
||||
}
|
||||
}
|
||||
if (memcmp(dyn->insts[ninst].n.neoncache, dyn->n.neoncache, sizeof(dyn->n.neoncache))) {
|
||||
length += sprintf(buf + length, " %s(Change:", (BOX64DRENV(dynarec_dump) > 1) ? "\e[1;91m" : "");
|
||||
length += sprintf(buf + length, " %s(Change:", (dyn->need_dump > 1) ? "\e[1;91m" : "");
|
||||
for (int ii = 0; ii < 32; ++ii)
|
||||
if (dyn->insts[ninst].n.neoncache[ii].v != dyn->n.neoncache[ii].v) {
|
||||
length += sprintf(buf + length, " V%d:%s", ii, getCacheName(dyn->n.neoncache[ii].t, dyn->n.neoncache[ii].n));
|
||||
length += sprintf(buf + length, "->%s", getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n));
|
||||
}
|
||||
length += sprintf(buf + length, ")%s", (BOX64DRENV(dynarec_dump) > 1) ? "\e[0;32m" : "");
|
||||
length += sprintf(buf + length, ")%s", (dyn->need_dump > 1) ? "\e[0;32m" : "");
|
||||
}
|
||||
if (dyn->insts[ninst].n.ymm_used) {
|
||||
length += sprintf(buf + length, " ymmUsed=%04x", dyn->insts[ninst].n.ymm_used);
|
||||
if (dyn->insts[ninst].n.xmm_used || dyn->insts[ninst].n.xmm_unneeded) {
|
||||
length += sprintf(buf + length, " xmmUsed=%04x/unneeded=%04x", dyn->insts[ninst].n.xmm_used, dyn->insts[ninst].n.xmm_unneeded);
|
||||
}
|
||||
if (dyn->insts[ninst].n.ymm_used || dyn->insts[ninst].n.ymm_unneeded) {
|
||||
length += sprintf(buf + length, " ymmUsed=%04x/unneeded=%04x", dyn->insts[ninst].n.ymm_used, dyn->insts[ninst].n.ymm_unneeded);
|
||||
}
|
||||
if (dyn->ymm_zero || dyn->insts[ninst].ymm0_add || dyn->insts[ninst].ymm0_sub || dyn->insts[ninst].ymm0_out) {
|
||||
length += sprintf(buf + length, " ymm0=(%04x/%04x+%04x-%04x=%04x)", dyn->ymm_zero, dyn->insts[ninst].ymm0_in, dyn->insts[ninst].ymm0_add, dyn->insts[ninst].ymm0_sub, dyn->insts[ninst].ymm0_out);
|
||||
@@ -828,11 +874,11 @@ void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t r
|
||||
if (dyn->insts[ninst].n.combined1 || dyn->insts[ninst].n.combined2) {
|
||||
length += sprintf(buf + length, " %s:%d/%d", dyn->insts[ninst].n.swapped ? "SWP" : "CMB", dyn->insts[ninst].n.combined1, dyn->insts[ninst].n.combined2);
|
||||
}
|
||||
if (BOX64DRENV(dynarec_dump)) {
|
||||
if (dyn->need_dump) {
|
||||
printf_x64_instruction(dyn, rex.is32bits ? my_context->dec32 : my_context->dec, &dyn->insts[ninst].x64, name);
|
||||
dynarec_log(LOG_NONE, "%s%p: %d emitted opcodes, inst=%d, %s%s\n",
|
||||
(BOX64DRENV(dynarec_dump) > 1) ? "\e[32m" : "",
|
||||
(void*)(dyn->native_start + dyn->insts[ninst].address), dyn->insts[ninst].size / 4, ninst, buf, (BOX64DRENV(dynarec_dump) > 1) ? "\e[m" : "");
|
||||
(dyn->need_dump > 1) ? "\e[32m" : "",
|
||||
(void*)(dyn->native_start + dyn->insts[ninst].address), dyn->insts[ninst].size / 4, ninst, buf, (dyn->need_dump > 1) ? "\e[m" : "");
|
||||
}
|
||||
if (BOX64ENV(dynarec_gdbjit)) {
|
||||
static char buf2[512];
|
||||
@@ -852,6 +898,7 @@ void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t r
|
||||
if (BOX64ENV(dynarec_perf_map) && BOX64ENV(dynarec_perf_map_fd) != -1) {
|
||||
writePerfMap(dyn->insts[ninst].x64.addr, dyn->native_start + dyn->insts[ninst].address, dyn->insts[ninst].size / 4, name);
|
||||
}
|
||||
if(length>sizeof(buf)) printf_log(LOG_NONE, "Warning: buf to small in inst_name_pass3 (%d vs %zd)\n", length, sizeof(buf));
|
||||
}
|
||||
|
||||
void print_opcode(dynarec_native_t* dyn, int ninst, uint32_t opcode)
|
||||
@@ -1027,7 +1074,7 @@ static uint8_t getNativeFlagsUsed(dynarec_arm_t* dyn, int start, uint8_t flags)
|
||||
return 0;
|
||||
// update used flags
|
||||
//used_flags |= (flag2native(dyn->insts[ninst].x64.need_after)&flags);
|
||||
|
||||
|
||||
// go next
|
||||
if(!dyn->insts[ninst].x64.has_next) {
|
||||
// check if it's a jump to an opcode with only 1 preds, then just follow the jump
|
||||
@@ -1133,7 +1180,7 @@ int nativeFlagsNeedsTransform(dynarec_arm_t* dyn, int ninst)
|
||||
flags_x86 &= ~flags_after;
|
||||
if((flags_before&NF_CF) && (flags_after&NF_CF) && (nc_before!=nc_after))
|
||||
return 1;
|
||||
// all flags_after should be present and none remaining flags_x86
|
||||
// all flags_after should be present and none remaining flags_x86
|
||||
if(((flags_before&flags_after)!=flags_after) || (flags_before&flags_x86))
|
||||
return 1;
|
||||
return 0;
|
||||
@@ -1148,3 +1195,45 @@ 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)
|
||||
{
|
||||
if(!ninst) return;
|
||||
ninst = getNominalPred(dyn, ninst);
|
||||
while(ninst>=0) {
|
||||
if(dyn->insts[ninst].n.xmm_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.xmm_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.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
|
||||
ninst = getNominalPred(dyn, ninst); // continue
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -85,4 +85,8 @@ 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 the uneeded flags on XMM/YMM regs (done between step 0 and step 1)
|
||||
void updateUneeded(dynarec_arm_t* dyn);
|
||||
|
||||
#endif //__DYNAREC_ARM_FUNCTIONS_H__
|
||||
@@ -7,10 +7,8 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
@@ -32,7 +30,10 @@ 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) { /*SMDMB();*/DMB_ISH(); }
|
||||
if (l == LOCK_LOCK) {
|
||||
dyn->insts[ninst].lock_prefixed = 1;
|
||||
DMB_ISH();
|
||||
}
|
||||
|
||||
if(rex.is32bits)
|
||||
return geted_32(dyn, addr, ninst, nextop, ed, hint, fixaddress, unscaled, absmax, mask, l, s);
|
||||
@@ -619,7 +620,7 @@ void jump_to_next(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst, int is32
|
||||
#endif
|
||||
}
|
||||
|
||||
void ret_to_epilog(dynarec_arm_t* dyn, int ninst, rex_t rex)
|
||||
void ret_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int ninst, rex_t rex)
|
||||
{
|
||||
MAYUSE(dyn); MAYUSE(ninst);
|
||||
MESSAGE(LOG_DUMP, "Ret to epilog\n");
|
||||
@@ -660,7 +661,7 @@ void ret_to_epilog(dynarec_arm_t* dyn, int ninst, rex_t rex)
|
||||
CLEARIP();
|
||||
}
|
||||
|
||||
void retn_to_epilog(dynarec_arm_t* dyn, int ninst, rex_t rex, int n)
|
||||
void retn_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int ninst, rex_t rex, int n)
|
||||
{
|
||||
MAYUSE(dyn); MAYUSE(ninst);
|
||||
MESSAGE(LOG_DUMP, "Retn to epilog\n");
|
||||
@@ -707,7 +708,7 @@ void retn_to_epilog(dynarec_arm_t* dyn, int ninst, rex_t rex, int n)
|
||||
CLEARIP();
|
||||
}
|
||||
|
||||
void iret_to_epilog(dynarec_arm_t* dyn, int ninst, int is32bits, int is64bits)
|
||||
void iret_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int ninst, int is32bits, int is64bits)
|
||||
{
|
||||
int64_t j64;
|
||||
//#warning TODO: is64bits
|
||||
@@ -768,7 +769,7 @@ void call_c(dynarec_arm_t* dyn, int ninst, void* fnc, int reg, int ret, int save
|
||||
dyn->insts[ninst].nat_flags_op = NAT_FLAG_OP_UNUSABLE;
|
||||
#endif
|
||||
if(savereg==0)
|
||||
savereg = 7;
|
||||
savereg = x87pc;
|
||||
if(saveflags) {
|
||||
STRx_U12(xFlags, xEmu, offsetof(x64emu_t, eflags));
|
||||
}
|
||||
@@ -781,6 +782,9 @@ void call_c(dynarec_arm_t* dyn, int ninst, void* fnc, int reg, int ret, int save
|
||||
STPx_S7_offset(xR8, xR9, xEmu, offsetof(x64emu_t, regs[_R8]));
|
||||
fpu_pushcache(dyn, ninst, savereg, 0);
|
||||
}
|
||||
#ifdef _WIN32
|
||||
LDRx_U12(xR8, xEmu, offsetof(x64emu_t, win64_teb));
|
||||
#endif
|
||||
TABLE64(reg, (uintptr_t)fnc);
|
||||
BLR(reg);
|
||||
if(ret>=0) {
|
||||
@@ -806,6 +810,9 @@ void call_c(dynarec_arm_t* dyn, int ninst, void* fnc, int reg, int ret, int save
|
||||
if(saveflags) {
|
||||
LDRx_U12(xFlags, xEmu, offsetof(x64emu_t, eflags));
|
||||
}
|
||||
if(savereg!=x87pc && dyn->need_x87check) {
|
||||
NATIVE_RESTORE_X87PC();
|
||||
}
|
||||
//SET_NODF();
|
||||
}
|
||||
|
||||
@@ -815,7 +822,7 @@ void call_i(dynarec_arm_t* dyn, int ninst, void* fnc)
|
||||
#if STEP == 0
|
||||
dyn->insts[ninst].nat_flags_op = NAT_FLAG_OP_UNUSABLE;
|
||||
#endif
|
||||
STPx_S7_preindex(x6, x7, xSP, -16);
|
||||
STPx_S7_preindex(x6, x87pc, xSP, -16);
|
||||
STPx_S7_preindex(x4, x5, xSP, -16);
|
||||
STPx_S7_preindex(x2, x3, xSP, -16);
|
||||
STPx_S7_preindex(xEmu, x1, xSP, -16); // ARM64 stack needs to be 16byte aligned
|
||||
@@ -825,10 +832,13 @@ void call_i(dynarec_arm_t* dyn, int ninst, void* fnc)
|
||||
STPx_S7_offset(xRSI, xRDI, xEmu, offsetof(x64emu_t, regs[_SI]));
|
||||
STPx_S7_offset(xR8, xR9, xEmu, offsetof(x64emu_t, regs[_R8]));
|
||||
STRx_U12(xFlags, xEmu, offsetof(x64emu_t, eflags));
|
||||
fpu_pushcache(dyn, ninst, x7, 0);
|
||||
fpu_pushcache(dyn, ninst, x87pc, 0);
|
||||
|
||||
TABLE64(x7, (uintptr_t)fnc);
|
||||
BLR(x7);
|
||||
#ifdef _WIN32
|
||||
LDRx_U12(xR8, xEmu, offsetof(x64emu_t, win64_teb));
|
||||
#endif
|
||||
TABLE64(x87pc, (uintptr_t)fnc);
|
||||
BLR(x87pc);
|
||||
LDPx_S7_postindex(xEmu, x1, xSP, 16);
|
||||
LDPx_S7_postindex(x2, x3, xSP, 16);
|
||||
LDPx_S7_postindex(x4, x5, xSP, 16);
|
||||
@@ -840,8 +850,8 @@ void call_i(dynarec_arm_t* dyn, int ninst, void* fnc)
|
||||
GO(R8, R9);
|
||||
#undef GO
|
||||
LDRx_U12(xFlags, xEmu, offsetof(x64emu_t, eflags));
|
||||
fpu_popcache(dyn, ninst, x7, 0); // savereg will not be used
|
||||
LDPx_S7_postindex(x6, x7, xSP, 16);
|
||||
fpu_popcache(dyn, ninst, x87pc, 0); // savereg will not be used
|
||||
LDPx_S7_postindex(x6, x87pc, xSP, 16);
|
||||
//SET_NODF();
|
||||
}
|
||||
|
||||
@@ -861,12 +871,12 @@ void call_n(dynarec_arm_t* dyn, int ninst, void* fnc, int w)
|
||||
if(abs(w)>1) {
|
||||
MESSAGE(LOG_DUMP, "Getting %d XMM args\n", abs(w)-1);
|
||||
for(int i=0; i<abs(w)-1; ++i) {
|
||||
sse_get_reg(dyn, ninst, x7, i, w);
|
||||
sse_get_reg(dyn, ninst, x3, i, w);
|
||||
}
|
||||
}
|
||||
if(w<0) {
|
||||
MESSAGE(LOG_DUMP, "Return in XMM0\n");
|
||||
sse_get_reg_empty(dyn, ninst, x7, 0);
|
||||
sse_get_reg_empty(dyn, ninst, x3, 0);
|
||||
}
|
||||
// prepare regs for native call
|
||||
MOVx_REG(0, xRDI);
|
||||
@@ -891,6 +901,7 @@ void call_n(dynarec_arm_t* dyn, int ninst, void* fnc, int w)
|
||||
|
||||
fpu_popcache(dyn, ninst, x3, 1);
|
||||
LDRx_U12(xFlags, xEmu, offsetof(x64emu_t, eflags));
|
||||
NATIVE_RESTORE_X87PC();
|
||||
//SET_NODF();
|
||||
}
|
||||
|
||||
@@ -1309,7 +1320,7 @@ static void x87_reflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int
|
||||
if(dyn->n.x87cache[i]!=-1) {
|
||||
ADDw_U12(s3, s2, dyn->n.x87cache[i]);
|
||||
ANDw_mask(s3, s3, 0, 2); // mask=7 // (emu->top + i)&7
|
||||
if(neoncache_get_st_f(dyn, ninst, dyn->n.x87cache[i])>=0) {
|
||||
if(neoncache_get_current_st_f(dyn, dyn->n.x87cache[i])>=0) {
|
||||
int scratch = fpu_get_scratch(dyn, ninst);
|
||||
FCVT_D_S(scratch, dyn->n.x87reg[i]);
|
||||
VSTR64_REG_LSL3(scratch, s1, s3);
|
||||
@@ -1718,6 +1729,7 @@ static void mmx_reflectcache(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
// get neon register for a SSE reg, create the entry if needed
|
||||
int sse_get_reg(dynarec_arm_t* dyn, int ninst, int s1, int a, int forwrite)
|
||||
{
|
||||
dyn->n.xmm_used |= 1<<a;
|
||||
if(dyn->n.ssecache[a].v!=-1) {
|
||||
if(forwrite) {
|
||||
dyn->n.ssecache[a].write = 1; // update only if forwrite
|
||||
@@ -1734,11 +1746,13 @@ int sse_get_reg(dynarec_arm_t* dyn, int ninst, int s1, int a, int forwrite)
|
||||
// get neon register for a SSE reg, but don't try to synch it if it needed to be created
|
||||
int sse_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int a)
|
||||
{
|
||||
dyn->n.xmm_used |= 1<<a;
|
||||
if(dyn->n.ssecache[a].v!=-1) {
|
||||
dyn->n.ssecache[a].write = 1;
|
||||
dyn->n.neoncache[dyn->n.ssecache[a].reg].t = NEON_CACHE_XMMW;
|
||||
return dyn->n.ssecache[a].reg;
|
||||
}
|
||||
dyn->n.xmm_unneeded |= 1<<a;
|
||||
dyn->n.ssecache[a].reg = fpu_get_reg_xmm(dyn, NEON_CACHE_XMMW, a);
|
||||
dyn->n.ssecache[a].write = 1; // it will be write...
|
||||
return dyn->n.ssecache[a].reg;
|
||||
@@ -1746,6 +1760,7 @@ int sse_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int a)
|
||||
// forget neon register for a SSE reg, create the entry if needed
|
||||
void sse_forget_reg(dynarec_arm_t* dyn, int ninst, int a)
|
||||
{
|
||||
dyn->n.xmm_used |= 1<<a;
|
||||
if(dyn->n.ssecache[a].v==-1)
|
||||
return;
|
||||
if(dyn->n.neoncache[dyn->n.ssecache[a].reg].t == NEON_CACHE_XMMW) {
|
||||
@@ -1781,6 +1796,7 @@ void sse_purge07cache(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
MESSAGE(LOG_DUMP, "\tPurge XMM0..7 Cache ------\n");
|
||||
++old;
|
||||
}
|
||||
dyn->n.xmm_used |= (1<<i);
|
||||
if(dyn->n.neoncache[dyn->n.ssecache[i].reg].t == NEON_CACHE_XMMW) {
|
||||
VSTR128_U12(dyn->n.ssecache[i].reg, xEmu, offsetof(x64emu_t, xmm[i]));
|
||||
}
|
||||
@@ -1798,9 +1814,10 @@ static void sse_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1)
|
||||
int old = -1;
|
||||
for (int i=0; i<16; ++i)
|
||||
if(dyn->n.ssecache[i].v!=-1) {
|
||||
if(next) dyn->n.xmm_used |= (1<<i);
|
||||
if(dyn->n.ssecache[i].write) {
|
||||
if (old==-1) {
|
||||
MESSAGE(LOG_DUMP, "\tPurge %sSSE Cache ------\n", next?"locally ":"");
|
||||
MESSAGE(LOG_DUMP, "\tPurge %sSSE Cache ------\n", next?"localy ":"");
|
||||
++old;
|
||||
}
|
||||
VSTR128_U12(dyn->n.ssecache[i].reg, xEmu, offsetof(x64emu_t, xmm[i]));
|
||||
@@ -1838,6 +1855,8 @@ static void sse_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1)
|
||||
}
|
||||
if(!next && (dyn->n.neoncache[i].t==NEON_CACHE_YMMW || dyn->n.neoncache[i].t==NEON_CACHE_YMMR))
|
||||
dyn->n.neoncache[i].v = 0;
|
||||
if(next && (dyn->n.neoncache[i].t==NEON_CACHE_YMMW || dyn->n.neoncache[i].t==NEON_CACHE_YMMR))
|
||||
dyn->n.xmm_used |= (1<<dyn->n.neoncache[i].n);
|
||||
}
|
||||
// All done
|
||||
if(old!=-1) {
|
||||
@@ -1847,10 +1866,14 @@ static void sse_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1)
|
||||
|
||||
static void sse_reflectcache(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
{
|
||||
for (int i=0; i<16; ++i)
|
||||
if(dyn->n.ssecache[i].v!=-1 && dyn->n.ssecache[i].write) {
|
||||
VSTR128_U12(dyn->n.ssecache[i].reg, xEmu, offsetof(x64emu_t, xmm[i]));
|
||||
for (int i=0; i<16; ++i) {
|
||||
if(dyn->n.ssecache[i].v!=-1) {
|
||||
dyn->n.xmm_used |= 1<<i;
|
||||
if(dyn->n.ssecache[i].write) {
|
||||
VSTR128_U12(dyn->n.ssecache[i].reg, xEmu, offsetof(x64emu_t, xmm[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
//AVX
|
||||
if(dyn->ymm_zero) {
|
||||
int s1_set = 0;
|
||||
@@ -1863,13 +1886,18 @@ static void sse_reflectcache(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
STPx_S7_offset(xZR, xZR, s1, i*16);
|
||||
}
|
||||
}
|
||||
for(int i=0; i<32; ++i)
|
||||
for(int i=0; i<32; ++i) {
|
||||
if(dyn->n.neoncache[i].t == NEON_CACHE_YMMW)
|
||||
VSTR128_U12(i, xEmu, offsetof(x64emu_t, ymm[dyn->n.neoncache[i].n]));
|
||||
if((dyn->n.neoncache[i].t == NEON_CACHE_YMMW) || (dyn->n.neoncache[i].t == NEON_CACHE_YMMR))
|
||||
dyn->n.xmm_used |= 1<<dyn->n.neoncache[i].n;
|
||||
}
|
||||
}
|
||||
|
||||
void sse_reflect_reg(dynarec_arm_t* dyn, int ninst, int a)
|
||||
{
|
||||
dyn->n.xmm_used |= 1<<a;
|
||||
dyn->n.ymm_used |= 1<<a;
|
||||
if(is_avx_zero(dyn, ninst, a)) {
|
||||
//only ymm[0] can be accessed with STP :(
|
||||
if(!a)
|
||||
@@ -1938,6 +1966,7 @@ int ymm_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int a, int k1, int
|
||||
return i;
|
||||
}
|
||||
// nope, grab a new one
|
||||
dyn->n.ymm_unneeded |= 1<<a;
|
||||
int ret = fpu_get_reg_ymm(dyn, ninst, NEON_CACHE_YMMW, a, k1, k2, k3);
|
||||
if(dyn->ymm_zero&(1<<a))
|
||||
dyn->ymm_zero&=~(1<<a);
|
||||
@@ -1963,6 +1992,7 @@ void ymm_mark_zero(dynarec_arm_t* dyn, int ninst, int a)
|
||||
#if STEP == 0
|
||||
dyn->insts[ninst].ymm0_add |= (1<<a);
|
||||
#endif
|
||||
dyn->n.ymm_unneeded |= 1<<a;
|
||||
avx_mark_zero(dyn, ninst, a);
|
||||
}
|
||||
|
||||
@@ -2118,7 +2148,7 @@ static void swapCache(dynarec_arm_t* dyn, int ninst, int i, int j, neoncache_t *
|
||||
cache->neoncache[j].v = tmp.v;
|
||||
}
|
||||
|
||||
static void loadCache(dynarec_arm_t* dyn, int ninst, int stack_cnt, int s1, int s2, int s3, int* s1_val, int* s2_val, int* s3_top, neoncache_t *cache, int i, int t, int n)
|
||||
static void loadCache(dynarec_arm_t* dyn, int ninst, int stack_cnt, int s1, int s2, int s3, int* s1_val, int* s2_val, int* s3_top, neoncache_t *cache, int i, int t, int n, int i2)
|
||||
{
|
||||
if(cache->neoncache[i].v) {
|
||||
int quad = 0;
|
||||
@@ -2140,13 +2170,21 @@ static void loadCache(dynarec_arm_t* dyn, int ninst, int stack_cnt, int s1, int
|
||||
switch(t) {
|
||||
case NEON_CACHE_XMMR:
|
||||
case NEON_CACHE_XMMW:
|
||||
MESSAGE(LOG_DUMP, "\t - Loading %s\n", getCacheName(t, n));
|
||||
VLDR128_U12(i, xEmu, offsetof(x64emu_t, xmm[n]));
|
||||
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 - Loading %s\n", getCacheName(t, n));
|
||||
VLDR128_U12(i, xEmu, offsetof(x64emu_t, xmm[n]));
|
||||
}
|
||||
break;
|
||||
case NEON_CACHE_YMMR:
|
||||
case NEON_CACHE_YMMW:
|
||||
MESSAGE(LOG_DUMP, "\t - Loading %s\n", getCacheName(t, n));
|
||||
VLDR128_U12(i, xEmu, offsetof(x64emu_t, ymm[n]));
|
||||
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 - Loading %s\n", getCacheName(t, n));
|
||||
VLDR128_U12(i, xEmu, offsetof(x64emu_t, ymm[n]));
|
||||
}
|
||||
break;
|
||||
case NEON_CACHE_MM:
|
||||
MESSAGE(LOG_DUMP, "\t - Loading %s\n", getCacheName(t, n));
|
||||
@@ -2192,7 +2230,7 @@ static void loadCache(dynarec_arm_t* dyn, int ninst, int stack_cnt, int s1, int
|
||||
cache->neoncache[i].t = t;
|
||||
}
|
||||
|
||||
static void unloadCache(dynarec_arm_t* dyn, int ninst, int stack_cnt, int s1, int s2, int s3, int* s1_val, int* s2_val, int* s3_top, neoncache_t *cache, int i, int t, int n)
|
||||
static void unloadCache(dynarec_arm_t* dyn, int ninst, int stack_cnt, int s1, int s2, int s3, int* s1_val, int* s2_val, int* s3_top, neoncache_t *cache, int i, int t, int n, int i2)
|
||||
{
|
||||
switch(t) {
|
||||
case NEON_CACHE_XMMR:
|
||||
@@ -2200,12 +2238,20 @@ 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:
|
||||
MESSAGE(LOG_DUMP, "\t - Unloading %s\n", getCacheName(t, n));
|
||||
VSTR128_U12(i, xEmu, offsetof(x64emu_t, xmm[n]));
|
||||
if(dyn->insts[i2].n.xmm_unneeded&(1<<i)) {
|
||||
MESSAGE(LOG_DUMP, "\t - ignoring unneeded %s\n", getCacheName(t, n));
|
||||
} else {
|
||||
MESSAGE(LOG_DUMP, "\t - Unloading %s\n", getCacheName(t, n));
|
||||
VSTR128_U12(i, xEmu, offsetof(x64emu_t, xmm[n]));
|
||||
}
|
||||
break;
|
||||
case NEON_CACHE_YMMW:
|
||||
MESSAGE(LOG_DUMP, "\t - Unloading %s\n", getCacheName(t, n));
|
||||
VSTR128_U12(i, xEmu, offsetof(x64emu_t, ymm[n]));
|
||||
if(dyn->insts[i2].n.ymm_unneeded&(1<<i)) {
|
||||
MESSAGE(LOG_DUMP, "\t - ignoring unneeded %s\n", getCacheName(t, n));
|
||||
} else {
|
||||
MESSAGE(LOG_DUMP, "\t - Unloading %s\n", getCacheName(t, n));
|
||||
VSTR128_U12(i, xEmu, offsetof(x64emu_t, ymm[n]));
|
||||
}
|
||||
break;
|
||||
case NEON_CACHE_MM:
|
||||
MESSAGE(LOG_DUMP, "\t - Unloading %s\n", getCacheName(t, n));
|
||||
@@ -2274,8 +2320,19 @@ static void fpuCacheTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2, int
|
||||
neoncacheUnwind(&cache_i2);
|
||||
|
||||
if(!cache_i2.stack) {
|
||||
int purge = 1;
|
||||
for (int i=0; i<24 && purge; ++i)
|
||||
int purge = 0; // default to purge if there is any regs that are not needed at jump
|
||||
// but first check if there is regs that can be discarded because unneeded at jump point
|
||||
for(int i=0; i<32 && !purge; ++i) {
|
||||
if(dyn->insts[ninst].n.neoncache[i].v) {
|
||||
int t = dyn->insts[ninst].n.neoncache[i].t;
|
||||
int n = dyn->insts[ninst].n.neoncache[i].n;
|
||||
if(((t==NEON_CACHE_XMMR) || (t==NEON_CACHE_XMMW)) && (cache_i2.xmm_unneeded&(1<<n))) {/* nothing */}
|
||||
else if(((t==NEON_CACHE_YMMR) || (t==NEON_CACHE_YMMW)) && (cache_i2.ymm_unneeded&(1<<n))) {/* nothing */}
|
||||
else ++purge;
|
||||
}
|
||||
}
|
||||
// Now check if there is any regs at jump point
|
||||
for (int i=0; i<32 && purge; ++i)
|
||||
if(cache_i2.neoncache[i].v)
|
||||
purge = 0;
|
||||
if(purge) {
|
||||
@@ -2296,11 +2353,13 @@ static void fpuCacheTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2, int
|
||||
MESSAGE(LOG_DUMP, "\t- YMM Zero %04x / %04x\n", dyn->ymm_zero, (dyn->insts[i2].purge_ymm|to_purge));
|
||||
for(int i=0; i<16; ++i)
|
||||
if(is_avx_zero(dyn, ninst, i) && (dyn->insts[i2].purge_ymm|to_purge)&(1<<i)) {
|
||||
if(s3_top) {
|
||||
ADDx_U12(s3, xEmu,offsetof(x64emu_t, ymm[0]));
|
||||
s3_top = 0;
|
||||
if(!(dyn->insts[i2].n.ymm_unneeded&(1<<i))) {
|
||||
if(s3_top) {
|
||||
ADDx_U12(s3, xEmu,offsetof(x64emu_t, ymm[0]));
|
||||
s3_top = 0;
|
||||
}
|
||||
STPx_S7_offset(xZR, xZR, s3, i*16);
|
||||
}
|
||||
STPx_S7_offset(xZR, xZR, s3, i*16);
|
||||
}
|
||||
}
|
||||
s3_top = 0xffff;
|
||||
@@ -2308,22 +2367,22 @@ static void fpuCacheTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2, int
|
||||
for(int i=0; i<16; ++i) {
|
||||
int j=findCacheSlot(dyn, ninst, NEON_CACHE_XMMW, i, &cache);
|
||||
if(j>=0 && findCacheSlot(dyn, ninst, NEON_CACHE_XMMW, i, &cache_i2)==-1)
|
||||
unloadCache(dyn, ninst, stack_cnt, s1, s2, s3, &s1_val, &s2_val, &s3_top, &cache, j, cache.neoncache[j].t, cache.neoncache[j].n);
|
||||
unloadCache(dyn, ninst, stack_cnt, s1, s2, s3, &s1_val, &s2_val, &s3_top, &cache, j, cache.neoncache[j].t, cache.neoncache[j].n, i2);
|
||||
}
|
||||
for(int i=0; i<16; ++i) {
|
||||
int j=findCacheSlot(dyn, ninst, NEON_CACHE_YMMW, i, &cache);
|
||||
if(j>=0 && findCacheSlot(dyn, ninst, NEON_CACHE_YMMW, i, &cache_i2)==-1)
|
||||
unloadCache(dyn, ninst, stack_cnt, s1, s2, s3, &s1_val, &s2_val, &s3_top, &cache, j, cache.neoncache[j].t, cache.neoncache[j].n);
|
||||
unloadCache(dyn, ninst, stack_cnt, s1, s2, s3, &s1_val, &s2_val, &s3_top, &cache, j, cache.neoncache[j].t, cache.neoncache[j].n, i2);
|
||||
}
|
||||
for(int i=0; i<8; ++i) {
|
||||
int j=findCacheSlot(dyn, ninst, NEON_CACHE_MM, i, &cache);
|
||||
if(j>=0 && findCacheSlot(dyn, ninst, NEON_CACHE_MM, i, &cache_i2)==-1)
|
||||
unloadCache(dyn, ninst, stack_cnt, s1, s2, s3, &s1_val, &s2_val, &s3_top, &cache, j, cache.neoncache[j].t, cache.neoncache[j].n);
|
||||
unloadCache(dyn, ninst, stack_cnt, s1, s2, s3, &s1_val, &s2_val, &s3_top, &cache, j, cache.neoncache[j].t, cache.neoncache[j].n, i2);
|
||||
}
|
||||
for(int i=0; i<32; ++i) {
|
||||
if(cache.neoncache[i].v)
|
||||
if(findCacheSlot(dyn, ninst, cache.neoncache[i].t, cache.neoncache[i].n, &cache_i2)==-1)
|
||||
unloadCache(dyn, ninst, stack_cnt, s1, s2, s3, &s1_val, &s2_val, &s3_top, &cache, i, cache.neoncache[i].t, cache.neoncache[i].n);
|
||||
unloadCache(dyn, ninst, stack_cnt, s1, s2, s3, &s1_val, &s2_val, &s3_top, &cache, i, cache.neoncache[i].t, cache.neoncache[i].n, i2);
|
||||
}
|
||||
// and now load/swap the missing one
|
||||
for(int i=0; i<32; ++i) {
|
||||
@@ -2331,7 +2390,7 @@ static void fpuCacheTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2, int
|
||||
if(cache_i2.neoncache[i].v != cache.neoncache[i].v) {
|
||||
int j;
|
||||
if((j=findCacheSlot(dyn, ninst, cache_i2.neoncache[i].t, cache_i2.neoncache[i].n, &cache))==-1)
|
||||
loadCache(dyn, ninst, stack_cnt, s1, s2, s3, &s1_val, &s2_val, &s3_top, &cache, i, cache_i2.neoncache[i].t, cache_i2.neoncache[i].n);
|
||||
loadCache(dyn, ninst, stack_cnt, s1, s2, s3, &s1_val, &s2_val, &s3_top, &cache, i, cache_i2.neoncache[i].t, cache_i2.neoncache[i].n, i2);
|
||||
else {
|
||||
// it's here, lets swap if needed
|
||||
if(j!=i)
|
||||
@@ -2680,10 +2739,10 @@ void fpu_reset_cache(dynarec_arm_t* dyn, int ninst, int reset_n)
|
||||
dyn->ymm_zero = dyn->insts[reset_n].ymm0_out;
|
||||
#endif
|
||||
#if STEP == 0
|
||||
if(BOX64DRENV(dynarec_dump) && dyn->n.x87stack) dynarec_log(LOG_NONE, "New x87stack=%d at ResetCache in inst %d with %d\n", dyn->n.x87stack, ninst, reset_n);
|
||||
if(dyn->need_dump && dyn->n.x87stack) dynarec_log(LOG_NONE, "New x87stack=%d at ResetCache in inst %d with %d\n", dyn->n.x87stack, ninst, reset_n);
|
||||
#endif
|
||||
#if defined(HAVE_TRACE) && (STEP>2)
|
||||
if(BOX64DRENV(dynarec_dump) && 0) //disable for now, need more work
|
||||
if(dyn->need_dump && 0) //disable for now, need more work
|
||||
if(memcmp(&dyn->n, &dyn->insts[reset_n].n, sizeof(neoncache_t))) {
|
||||
MESSAGE(LOG_DEBUG, "Warning, difference in neoncache: reset=");
|
||||
for(int i=0; i<32; ++i)
|
||||
|
||||
@@ -721,13 +721,13 @@
|
||||
|
||||
// CALL will use x7 for the call address. Return value can be put in ret (unless ret is -1)
|
||||
// R0 will not be pushed/popd if ret is -2
|
||||
#define CALL(F, ret) call_c(dyn, ninst, F, x7, ret, 1, 0)
|
||||
#define CALL(F, ret) call_c(dyn, ninst, F, x87pc, ret, 1, 0)
|
||||
// CALL_ will use x7 for the call address. Return value can be put in ret (unless ret is -1)
|
||||
// R0 will not be pushed/popd if ret is -2
|
||||
#define CALL_(F, ret, reg) call_c(dyn, ninst, F, x7, ret, 1, reg)
|
||||
#define CALL_(F, ret, reg) call_c(dyn, ninst, F, x87pc, ret, 1, reg)
|
||||
// CALL_S will use x7 for the call address. Return value can be put in ret (unless ret is -1)
|
||||
// R0 will not be pushed/popd if ret is -2. Flags are not save/restored
|
||||
#define CALL_S(F, ret) call_c(dyn, ninst, F, x7, ret, 0, 0)
|
||||
#define CALL_S(F, ret) call_c(dyn, ninst, F, x87pc, ret, 0, 0)
|
||||
// CALL_ will use x7 for the call address.
|
||||
// All regs are saved, including scratch. This is use to call internal function that should not change state
|
||||
#define CALL_I(F) call_i(dyn, ninst, F)
|
||||
@@ -760,6 +760,10 @@
|
||||
j64 = GETMARK-(dyn->native_size); \
|
||||
CBZw(reg, j64)
|
||||
// Branch to MARK if reg is 0 (use j64)
|
||||
#define CBZx_MARK(reg) \
|
||||
j64 = GETMARK-(dyn->native_size); \
|
||||
CBZx(reg, j64)
|
||||
// Branch to MARK if reg is 0 (use j64)
|
||||
#define CBZxw_MARK(reg) \
|
||||
j64 = GETMARK-(dyn->native_size); \
|
||||
CBZxw(reg, j64)
|
||||
@@ -981,11 +985,37 @@
|
||||
SET_DFNONE(); \
|
||||
|
||||
#ifndef IF_UNALIGNED
|
||||
#define IF_UNALIGNED(A) if(is_addr_unaligned(A))
|
||||
#define IF_UNALIGNED(A) if(dyn->insts[ninst].unaligned)
|
||||
#endif
|
||||
|
||||
#ifndef IF_ALIGNED
|
||||
#define IF_ALIGNED(A) if (!is_addr_unaligned(A))
|
||||
#define IF_ALIGNED(A) if (!dyn->insts[ninst].unaligned)
|
||||
#endif
|
||||
|
||||
#ifndef CALLRET_RET
|
||||
#define CALLRET_RET() NOP
|
||||
#endif
|
||||
#ifndef CALLRET_GETRET
|
||||
#define CALLRET_GETRET() (dyn->callrets?(dyn->callrets[dyn->callret_size].offs-dyn->native_size):0)
|
||||
#endif
|
||||
#ifndef CALLRET_LOOP
|
||||
#define CALLRET_LOOP() NOP
|
||||
#endif
|
||||
|
||||
#ifndef NATIVE_RESTORE_X87PC
|
||||
#define NATIVE_RESTORE_X87PC() \
|
||||
if(dyn->need_x87check) { \
|
||||
LDRH_U12(x87pc, xEmu, offsetof(x64emu_t, cw)); \
|
||||
UBFXw(x87pc, x87pc, 8, 2); \
|
||||
}
|
||||
#endif
|
||||
#ifndef X87_CHECK_PRECISION
|
||||
#define X87_CHECK_PRECISION(A) \
|
||||
if (!ST_IS_F(0) && dyn->need_x87check) { \
|
||||
CBNZw(x87pc, 4 + 8); \
|
||||
FCVT_S_D(A, A); \
|
||||
FCVT_D_S(A, A); \
|
||||
}
|
||||
#endif
|
||||
|
||||
#define STORE_REG(A) STRx_U12(x##A, xEmu, offsetof(x64emu_t, regs[_##A]))
|
||||
@@ -1065,7 +1095,7 @@
|
||||
#else
|
||||
#define X87_PUSH_OR_FAIL(var, dyn, ninst, scratch, t) \
|
||||
if ((dyn->n.x87stack==8) || (dyn->n.pushed==8)) { \
|
||||
if(BOX64DRENV(dynarec_dump)) dynarec_log(LOG_NONE, " Warning, suspicious x87 Push, stack=%d/%d on inst %d\n", dyn->n.x87stack, dyn->n.pushed, ninst); \
|
||||
if(dyn->need_dump) dynarec_log(LOG_NONE, " Warning, suspicious x87 Push, stack=%d/%d on inst %d\n", dyn->n.x87stack, dyn->n.pushed, ninst); \
|
||||
dyn->abort = 1; \
|
||||
return addr; \
|
||||
} \
|
||||
@@ -1073,7 +1103,7 @@
|
||||
|
||||
#define X87_PUSH_EMPTY_OR_FAIL(dyn, ninst, scratch) \
|
||||
if ((dyn->n.x87stack==8) || (dyn->n.pushed==8)) { \
|
||||
if(BOX64DRENV(dynarec_dump)) dynarec_log(LOG_NONE, " Warning, suspicious x87 Push, stack=%d/%d on inst %d\n", dyn->n.x87stack, dyn->n.pushed, ninst); \
|
||||
if(dyn->need_dump) dynarec_log(LOG_NONE, " Warning, suspicious x87 Push, stack=%d/%d on inst %d\n", dyn->n.x87stack, dyn->n.pushed, ninst); \
|
||||
dyn->abort = 1; \
|
||||
return addr; \
|
||||
} \
|
||||
@@ -1081,7 +1111,7 @@
|
||||
|
||||
#define X87_POP_OR_FAIL(dyn, ninst, scratch) \
|
||||
if ((dyn->n.x87stack==-8) || (dyn->n.poped==8)) { \
|
||||
if(BOX64DRENV(dynarec_dump)) dynarec_log(LOG_NONE, " Warning, suspicious x87 Pop, stack=%d/%d on inst %d\n", dyn->n.x87stack, dyn->n.poped, ninst); \
|
||||
if(dyn->need_dump) dynarec_log(LOG_NONE, " Warning, suspicious x87 Pop, stack=%d/%d on inst %d\n", dyn->n.x87stack, dyn->n.poped, ninst); \
|
||||
dyn->abort = 1; \
|
||||
return addr; \
|
||||
} \
|
||||
@@ -1449,9 +1479,9 @@ uintptr_t geted16(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop,
|
||||
// generic x64 helper
|
||||
void jump_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst);
|
||||
void jump_to_next(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst, int is32bits);
|
||||
void ret_to_epilog(dynarec_arm_t* dyn, int ninst, rex_t rex);
|
||||
void retn_to_epilog(dynarec_arm_t* dyn, int ninst, rex_t rex, int n);
|
||||
void iret_to_epilog(dynarec_arm_t* dyn, int ninst, int is32bits, int is64bits);
|
||||
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_n(dynarec_arm_t* dyn, int ninst, void* fnc, int w);
|
||||
|
||||
@@ -39,8 +39,8 @@
|
||||
--dyn->size; \
|
||||
*ok = -1; \
|
||||
if (ninst) { dyn->insts[ninst - 1].x64.size = ip - dyn->insts[ninst - 1].x64.addr; } \
|
||||
if (BOX64ENV(dynarec_log) >= LOG_INFO || BOX64DRENV(dynarec_dump) || BOX64ENV(dynarec_missing) == 1) \
|
||||
if (!dyn->size || BOX64ENV(dynarec_log) > LOG_INFO || BOX64DRENV(dynarec_dump)) { \
|
||||
if (BOX64ENV(dynarec_log) >= LOG_INFO || dyn->need_dump || BOX64ENV(dynarec_missing) == 1) \
|
||||
if (!dyn->size || BOX64ENV(dynarec_log) > LOG_INFO || dyn->need_dump) { \
|
||||
dynarec_log(LOG_NONE, "%p: Dynarec stopped because of %s Opcode ", (void*)ip, rex.is32bits ? "x86" : "x64"); \
|
||||
zydis_dec_t* dec = rex.is32bits ? my_context->dec32 : my_context->dec; \
|
||||
if (dec) { \
|
||||
@@ -50,7 +50,7 @@
|
||||
PKip(0), PKip(1), PKip(2), PKip(3), PKip(4), PKip(5), PKip(6), PKip(7), PKip(8), PKip(9), \
|
||||
PKip(10), PKip(11), PKip(12), PKip(13), PKip(14)); \
|
||||
} \
|
||||
printFunctionAddr(ip, " => "); \
|
||||
PrintFunctionAddr(ip, " => "); \
|
||||
dynarec_log_prefix(0, LOG_NONE, "\n"); \
|
||||
}
|
||||
|
||||
@@ -70,5 +70,11 @@
|
||||
#define INVERT_CARRY(A) dyn->insts[ninst].invert_carry = 1
|
||||
#define INVERT_CARRY_BEFORE(A) dyn->insts[ninst].invert_carry_before = 1
|
||||
// mark opcode as "unaligned" possible only if the current address is not marked as already unaligned
|
||||
#define IF_UNALIGNED(A) if((dyn->insts[ninst].unaligned=(is_addr_unaligned(A)?0:1)))
|
||||
#define IF_ALIGNED(A) if((dyn->insts[ninst].unaligned=(is_addr_unaligned(A)?1:0)))
|
||||
#define IF_UNALIGNED(A) if((dyn->insts[ninst].unaligned=is_addr_unaligned(A)))
|
||||
#define IF_ALIGNED(A) if(!(dyn->insts[ninst].unaligned=is_addr_unaligned(A)))
|
||||
|
||||
#define NATIVE_RESTORE_X87PC()
|
||||
#define X87_CHECK_PRECISION(A) \
|
||||
do { \
|
||||
if (dyn->need_x87check) dyn->insts[ninst].x87precision = 1; \
|
||||
} while (0)
|
||||
Loaded 100 of 474 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user