mirror of
https://github.com/ptitSeb/box64.git
synced 2026-11-08 17:39:19 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2b300bd199 | ||
|
|
9c69ebd717 | ||
|
|
ea01b56422 | ||
|
|
216cf51d4a | ||
|
|
1476b502a2 | ||
|
|
bc53ae8925 | ||
|
|
9cef52a1fc | ||
|
|
5ed60d99a8 | ||
|
|
d7c7a716fe | ||
|
|
41bee35634 | ||
|
|
e764029cae | ||
|
|
b110623103 | ||
|
|
35c1f97115 | ||
|
|
e8a7bef5a0 | ||
|
|
c2f73e6de0 | ||
|
|
0724f52d5f | ||
|
|
61a605a2dc | ||
|
|
7a058c9194 | ||
|
|
99971e94c0 | ||
|
|
445d885090 | ||
|
|
fc02f0d140 | ||
|
|
c2d02977f8 | ||
|
|
946c999e25 | ||
|
|
c8b6f80f99 | ||
|
|
9444ce0b89 | ||
|
|
401d2ae0b9 | ||
|
|
8dde796103 | ||
|
|
7ba0e7a055 | ||
|
|
eb039c0449 | ||
|
|
0c0f5263e1 | ||
|
|
ad70febaac | ||
|
|
39583c6da4 | ||
|
|
1bf4851cf6 | ||
|
|
2129e98b0e | ||
|
|
b015f33376 | ||
|
|
2636e7e8b5 | ||
|
|
b0e726d953 | ||
|
|
eb40c49132 | ||
|
|
5dadc513db | ||
|
|
4120dc10bd | ||
|
|
48f51bd5fe | ||
|
|
940317949a | ||
|
|
f9b6ea48e9 | ||
|
|
3567c6da2b | ||
|
|
f3fe72b541 | ||
|
|
14966e48a6 | ||
|
|
91b282235b | ||
|
|
63c3e4fcf5 | ||
|
|
c740590bcd | ||
|
|
e868c89233 | ||
|
|
c517d7196d | ||
|
|
cb42b3b00f | ||
|
|
61362b06ec | ||
|
|
bb8559933f | ||
|
|
c2cb333261 | ||
|
|
b7e4cc4f50 | ||
|
|
a4908f1407 | ||
|
|
a252e87fa9 | ||
|
|
ee3ee539e0 | ||
|
|
c4b79374fe | ||
|
|
5dfa27ea58 | ||
|
|
49cba432c2 | ||
|
|
39a9cf903f | ||
|
|
611ac3933c | ||
|
|
fdd1509ee5 | ||
|
|
52a9443f53 | ||
|
|
0d1488b016 | ||
|
|
fb4662cb28 | ||
|
|
32a747979a | ||
|
|
362a92c158 | ||
|
|
c27b659bce | ||
|
|
049cbd3783 | ||
|
|
8b5b5aa3a7 | ||
|
|
f85b9ac664 | ||
|
|
ee5a41e21e | ||
|
|
d49fc43791 | ||
|
|
9ec7930eb1 | ||
|
|
26dd597a1b | ||
|
|
040f8d9a9f | ||
|
|
f107321d06 | ||
|
|
64313d5aa6 | ||
|
|
71845a11bb | ||
|
|
e3adda8ff9 | ||
|
|
85e79a8224 | ||
|
|
9ef3e080fa | ||
|
|
4b5f63dc6d | ||
|
|
730e9d215c | ||
|
|
efa1cbd49a | ||
|
|
91798194d5 | ||
|
|
d550f9384c | ||
|
|
d59d531f14 | ||
|
|
c9369c5ea1 | ||
|
|
05fd25d3bb | ||
|
|
2b75a0de55 | ||
|
|
59e1da5f74 | ||
|
|
639466d45a | ||
|
|
95bdaf6eca | ||
|
|
9dc10bdc47 | ||
|
|
bf212a7b52 | ||
|
|
40d83ad882 | ||
|
|
baa9efeaa6 | ||
|
|
0c17b55e28 | ||
|
|
e2f4ab7700 | ||
|
|
84982ff86f | ||
|
|
cfd17e59ac | ||
|
|
af0b0c6c9d | ||
|
|
0e588e444f | ||
|
|
f575a7846e | ||
|
|
c7ff0f658b | ||
|
|
b8cc8594f6 | ||
|
|
6197b70a9a | ||
|
|
60396f58c0 | ||
|
|
ee83ef4c01 | ||
|
|
4b7e116aa7 | ||
|
|
785d3ed5ab | ||
|
|
33d1727925 | ||
|
|
a50d34e4ba | ||
|
|
7e0c4dcee5 | ||
|
|
f5174d12aa | ||
|
|
2cb25c095a | ||
|
|
d0039c65b4 | ||
|
|
099bd148cb | ||
|
|
20885702b9 | ||
|
|
751582df05 | ||
|
|
5212de0d66 | ||
|
|
056bb38607 | ||
|
|
1a01adb2ef | ||
|
|
797731e9e2 | ||
|
|
3e2c698710 | ||
|
|
58b24c85a2 | ||
|
|
28ebc1a0b7 | ||
|
|
65487dac51 | ||
|
|
592af6db3b | ||
|
|
997140f500 | ||
|
|
16f0adec6f | ||
|
|
ba6ff73c69 | ||
|
|
2bf78ea18c | ||
|
|
fc6efb220b | ||
|
|
523bfbdf3b | ||
|
|
46ad2261e7 | ||
|
|
6c60ad4695 | ||
|
|
37697e2ec7 | ||
|
|
f5eb3c1e9b | ||
|
|
5cfd379e97 | ||
|
|
fecaf3111b | ||
|
|
ff6f34aadf | ||
|
|
4c3d55fb5c | ||
|
|
d2a5005dcc | ||
|
|
05e1b422d3 | ||
|
|
69f49f79e4 | ||
|
|
2453eb9b2d | ||
|
|
93b4813ee2 | ||
|
|
7cbe71c218 | ||
|
|
8bb53e1001 | ||
|
|
f79af5afd4 | ||
|
|
7c27085bd3 | ||
|
|
53834f2b29 | ||
|
|
7c09957263 | ||
|
|
242832fa3c | ||
|
|
9beb6b4f63 | ||
|
|
0861a88d6e | ||
|
|
1c0dc8ec7c | ||
|
|
b21776f9b0 | ||
|
|
998f164aa3 | ||
|
|
58d8627cea | ||
|
|
877ca41451 | ||
|
|
94dedd47c6 | ||
|
|
1173c1d23f | ||
|
|
d9c9575e6a | ||
|
|
2239f92816 | ||
|
|
637e177408 | ||
|
|
bb653e6888 | ||
|
|
09e07973dd | ||
|
|
6b7afd7f8e | ||
|
|
eb7858d23a | ||
|
|
1db09fe897 | ||
|
|
22a5b573d5 | ||
|
|
f12f366a3d | ||
|
|
b51ab081ae | ||
|
|
50fcaf04b4 | ||
|
|
96bca6eac3 | ||
|
|
ed7147e598 | ||
|
|
4892c68f17 | ||
|
|
3ab56994da | ||
|
|
a54afc8e04 | ||
|
|
01b5ee9c78 | ||
|
|
a513cd847b | ||
|
|
06b6871c80 | ||
|
|
f5dc038621 | ||
|
|
38dce9138d | ||
|
|
2aa5c5f337 | ||
|
|
e6d2c12792 | ||
|
|
c3dbdf419d | ||
|
|
c566ba970d | ||
|
|
81925643e8 | ||
|
|
285c874e53 | ||
|
|
ba078c63a8 | ||
|
|
a54959a6e3 | ||
|
|
c573742845 | ||
|
|
dab01b8b9f | ||
|
|
9e58047980 | ||
|
|
6f8f37e8ff | ||
|
|
3ec950726b | ||
|
|
cec62dad44 | ||
|
|
89eca28d3a | ||
|
|
313e4854a0 | ||
|
|
8c1ffca530 | ||
|
|
7099774a3c | ||
|
|
925f6a9922 | ||
|
|
356200159a | ||
|
|
f0d8712275 | ||
|
|
fe3b66b018 | ||
|
|
83af8c6cdf | ||
|
|
ad5b5ea617 | ||
|
|
b439817467 | ||
|
|
276191cdcf | ||
|
|
8438b61747 | ||
|
|
f4a9f8dd79 | ||
|
|
f235c7f702 | ||
|
|
8e1e2c7840 | ||
|
|
0b632afbfe | ||
|
|
89dcd2566b | ||
|
|
314edea645 | ||
|
|
fe28bd93bd | ||
|
|
d882a5c8fe | ||
|
|
044dec0bfa | ||
|
|
ed8b6fe9db | ||
|
|
c98b4c8f45 | ||
|
|
b78d81d319 | ||
|
|
9f3be89e12 | ||
|
|
9e0b300354 | ||
|
|
dde6d26236 | ||
|
|
e6eac39759 | ||
|
|
5654e77625 | ||
|
|
c9f01d975d | ||
|
|
1fe213f900 | ||
|
|
802002b7a3 | ||
|
|
69a7c00841 | ||
|
|
c24f040888 | ||
|
|
0f225fc1a0 | ||
|
|
666506e834 | ||
|
|
21c0a2e7d7 | ||
|
|
03204f709e | ||
|
|
6827fc6cc9 | ||
|
|
cff4798249 | ||
|
|
93bf308179 | ||
|
|
166c4858a1 | ||
|
|
4b8fb02198 | ||
|
|
8432f7d8e2 | ||
|
|
ec675564c6 | ||
|
|
8c71178238 | ||
|
|
72df0bd1a0 | ||
|
|
6035cbd5c1 | ||
|
|
d7007dd3cc | ||
|
|
9c5daf5954 | ||
|
|
a57bc9e780 | ||
|
|
2e2bed4374 | ||
|
|
4eeaddf490 | ||
|
|
0cd53ca748 | ||
|
|
fa2bd920bd | ||
|
|
613f2cccf1 | ||
|
|
d91461f468 | ||
|
|
bcc497c865 | ||
|
|
2414f82c38 | ||
|
|
fd7d811b29 | ||
|
|
e533cd0ea1 | ||
|
|
9b7e5d69b2 | ||
|
|
0c5e6d867f | ||
|
|
32c646d0d2 | ||
|
|
35a6828209 | ||
|
|
2b66675a08 | ||
|
|
93638ac95a | ||
|
|
f489761e68 | ||
|
|
56ccde005e | ||
|
|
47e4aa0b84 | ||
|
|
b977d84f11 | ||
|
|
b7f14ff338 | ||
|
|
86211e5970 | ||
|
|
d8669d7c7d | ||
|
|
0d8e02a3fe | ||
|
|
1e681cead0 | ||
|
|
53f2423578 | ||
|
|
6cdfa05604 | ||
|
|
d55e879879 | ||
|
|
d377433997 | ||
|
|
207073bf36 | ||
|
|
316f31a4bb | ||
|
|
ada8efcdef | ||
|
|
99d0889cfd | ||
|
|
653a67c8ad | ||
|
|
b99893d1c3 | ||
|
|
a5c4d01649 | ||
|
|
82105a1543 | ||
|
|
c65910fd25 | ||
|
|
b5de464e85 | ||
|
|
81eb0b45b3 | ||
|
|
c772d1ab49 | ||
|
|
1af7c15801 | ||
|
|
e11901a7a6 | ||
|
|
0b2f84df54 | ||
|
|
a1ff40733b | ||
|
|
a61888e06c | ||
|
|
691259ec0d | ||
|
|
91e678da5b | ||
|
|
8a7c2b5228 | ||
|
|
e7710f59fa | ||
|
|
4039f3c249 | ||
|
|
6f46ccdd5a | ||
|
|
b79ba11d95 | ||
|
|
5a35184ba7 | ||
|
|
db801da658 | ||
|
|
f160fe3300 | ||
|
|
5d5dd3a3bc | ||
|
|
5fa65a4b38 | ||
|
|
cc34c75fc3 | ||
|
|
7fb1a34947 | ||
|
|
d087020139 | ||
|
|
4065e61ec5 | ||
|
|
da6b799a10 | ||
|
|
967c73efd1 | ||
|
|
6a35cd2a56 | ||
|
|
ebf03f8878 | ||
|
|
d7dbee5126 | ||
|
|
08930381e9 | ||
|
|
495c98a488 | ||
|
|
80a4b61e5c | ||
|
|
1d20968f82 | ||
|
|
ca8d569e63 | ||
|
|
670770e24a | ||
|
|
b55b138303 | ||
|
|
d0c7cb46e7 | ||
|
|
6e1e7de52b | ||
|
|
bb0a445a6b | ||
|
|
7157803c03 | ||
|
|
b7c5adae3d | ||
|
|
809b663350 | ||
|
|
1c4f1cb8c2 | ||
|
|
cace5f0ccb | ||
|
|
4aaa0b5d24 | ||
|
|
c0829b807c | ||
|
|
7d3cdb06e3 | ||
|
|
42f3884478 | ||
|
|
fcd46e2cdc | ||
|
|
f36f9d290d | ||
|
|
ae512cc4ed | ||
|
|
4fd59da003 | ||
|
|
e2d7cc5011 | ||
|
|
79413a4147 | ||
|
|
80b357da41 | ||
|
|
a54f516447 | ||
|
|
26ba1148e8 | ||
|
|
8b2b96d5c5 | ||
|
|
e21a506936 | ||
|
|
e86c6359d6 | ||
|
|
acce64b268 | ||
|
|
89713993cb | ||
|
|
cf24eaf9d2 | ||
|
|
cd1ac51b79 | ||
|
|
a7ded59393 | ||
|
|
205ef4ddeb | ||
|
|
145689783f | ||
|
|
21a21b04e6 | ||
|
|
87e19076ad | ||
|
|
9492b6ca66 | ||
|
|
4a45db781f | ||
|
|
0329d5fcc2 | ||
|
|
f39b5514c5 | ||
|
|
4700a6322e | ||
|
|
91a8fef1bb | ||
|
|
a56a66a227 | ||
|
|
1b262dac29 | ||
|
|
3b15ef1cb5 | ||
|
|
9ac695b9be | ||
|
|
05060803b2 | ||
|
|
e84f2e4a8b | ||
|
|
6fac9ee35b | ||
|
|
93cc31bc48 | ||
|
|
13ee4acd59 | ||
|
|
1360e7112c | ||
|
|
12987af561 | ||
|
|
e071a70ec2 | ||
|
|
48db75961e | ||
|
|
da0820ce0a | ||
|
|
ac81132435 | ||
|
|
946da43038 | ||
|
|
cad9450e16 | ||
|
|
0c7cc657cc | ||
|
|
ce4590f5ba | ||
|
|
cd3f5ca97d | ||
|
|
fc2a6d4dd1 | ||
|
|
85fe4c628e | ||
|
|
1bb7d9efd8 | ||
|
|
25b4dd1457 | ||
|
|
ea13414083 | ||
|
|
3e745474d3 | ||
|
|
5ad2f155c1 | ||
|
|
945b4192b1 | ||
|
|
3b71ba6090 | ||
|
|
9fc4697233 | ||
|
|
8a37b12f81 | ||
|
|
6ac7d7a1db | ||
|
|
291db1530c | ||
|
|
e77ea1b45c | ||
|
|
80db0175e0 | ||
|
|
15f90899eb | ||
|
|
e2ce483e0d | ||
|
|
41b31dc58d | ||
|
|
f8b9c7b2b7 | ||
|
|
a8000cb629 | ||
|
|
17f2371804 | ||
|
|
4d377de5ab | ||
|
|
956f6ffc15 | ||
|
|
600ae18d4b | ||
|
|
39aa02c19c | ||
|
|
7dcb86f500 | ||
|
|
f873255a19 | ||
|
|
4662ab1c80 | ||
|
|
b0b34e3a2a | ||
|
|
631da8a532 | ||
|
|
f80886fd68 | ||
|
|
cbe7ced335 | ||
|
|
955f6e74ab | ||
|
|
8a982e8b5e | ||
|
|
47f5fe7caf | ||
|
|
6e0f32f4ca | ||
|
|
62eca11bee | ||
|
|
13f5ec1524 | ||
|
|
e751d41ba7 | ||
|
|
7fd884b9c1 | ||
|
|
a98887589d | ||
|
|
0882f910df | ||
|
|
f65c22d329 | ||
|
|
485959195e | ||
|
|
28fb1bb0c0 | ||
|
|
cc12620868 | ||
|
|
9c89e64691 | ||
|
|
d432b18d23 | ||
|
|
98c0811525 | ||
|
|
77b16ae30d | ||
|
|
f4a4bdd006 | ||
|
|
ed7dddc3d8 | ||
|
|
4c6401c66b | ||
|
|
42441c99cc | ||
|
|
f775474062 | ||
|
|
c30e012e8d | ||
|
|
d90522bc4e | ||
|
|
0f7bec0d38 | ||
|
|
201b971ad7 | ||
|
|
1c72527dc8 | ||
|
|
5ce3e29913 | ||
|
|
1a7cff559a | ||
|
|
c28b0629fa | ||
|
|
6a3c56c131 | ||
|
|
d03c85da90 | ||
|
|
6a5d831331 | ||
|
|
2164c564f2 | ||
|
|
2a33cf4e60 | ||
|
|
6698a844f6 | ||
|
|
1c5ccefdef | ||
|
|
64bfd06be4 | ||
|
|
5bf154195d | ||
|
|
0239305f69 | ||
|
|
3ee5558c70 | ||
|
|
059dc12adc | ||
|
|
610c63cd15 | ||
|
|
fa3db3df11 | ||
|
|
4b4c0143d9 | ||
|
|
fa76ce1f05 | ||
|
|
59bb9c2083 | ||
|
|
689d64b62a | ||
|
|
f6c3386960 | ||
|
|
5055866a5a | ||
|
|
9f7d0c4404 | ||
|
|
7e5aa3e7c6 | ||
|
|
c7afc0b3df | ||
|
|
566ff08109 | ||
|
|
2247b61ed3 | ||
|
|
55d6971a23 | ||
|
|
7168167400 | ||
|
|
7e17c862cf | ||
|
|
bb60cc8568 | ||
|
|
857c4600dc | ||
|
|
88bd65998f | ||
|
|
ecbd382ae4 | ||
|
|
16f63a94c3 | ||
|
|
bd7ff2efd6 | ||
|
|
ed21342995 | ||
|
|
4c238f0e17 | ||
|
|
7c000adb87 | ||
|
|
2d4f073925 | ||
|
|
a25aab1426 | ||
|
|
54f593fa75 | ||
|
|
054de8e83f | ||
|
|
e6d1bf78a6 | ||
|
|
b4b8617a92 | ||
|
|
20bad4e126 | ||
|
|
3650609975 | ||
|
|
fe3b30ccbb | ||
|
|
ccae82e1f5 | ||
|
|
f1addb8b28 | ||
|
|
96f5108a37 | ||
|
|
3eeb10c0a6 | ||
|
|
ce3d2afad2 | ||
|
|
bdee719767 | ||
|
|
42263e0be9 | ||
|
|
ca08012bbf | ||
|
|
ca47ee273e | ||
|
|
eb299f500b | ||
|
|
a25b50d3aa | ||
|
|
b735a8663e |
No files matched your search
+1
-1
@@ -12,7 +12,7 @@ MaxEmptyLinesToKeep: 2
|
||||
IndentCaseLabels: true
|
||||
AlignConsecutiveMacros: true
|
||||
WhitespaceSensitiveMacros: ['QUOTE']
|
||||
IfMacros: ['IFX', 'IFXORNAT', 'IFX2', 'IFXA', 'IFX_PENDOR0', 'IFXX', 'IFX2X', 'IFXN', 'UFLAG_IF', 'PASS2IF']
|
||||
IfMacros: ['IFX', 'IFXORNAT', 'IFX2', 'IFXA', 'IFX_PENDOR0', 'IFXX', 'IFX2X', 'IFXN', 'UFLAG_IF', 'PASS2IF', 'IF_UNALIGNED', 'IF_ALIGNED']
|
||||
UseTab: Never
|
||||
IndentPPDirectives: None
|
||||
---
|
||||
@@ -29,7 +29,7 @@ jobs:
|
||||
matrix:
|
||||
platform: [X64, RISCV, RK3588, ARM64, ANDROID, TERMUX, LARCH64, ANDROID_GLIBC]
|
||||
type: [Release, Trace, StaticBuild, Box32]
|
||||
os: [ubuntu-latest]
|
||||
os: [ubuntu-latest, ubuntu-22.04-arm]
|
||||
exclude:
|
||||
- platform: ANDROID
|
||||
type: StaticBuild
|
||||
@@ -41,6 +41,22 @@ jobs:
|
||||
type: Box32
|
||||
- platform: TERMUX
|
||||
type: Box32
|
||||
- platform: X64
|
||||
os: ubuntu-22.04-arm
|
||||
- platform: RISCV
|
||||
os: ubuntu-22.04-arm
|
||||
- platform: RK3588
|
||||
os: ubuntu-latest
|
||||
- platform: ARM64
|
||||
os: ubuntu-latest
|
||||
- platform: ANDROID
|
||||
os: ubuntu-22.04-arm
|
||||
- platform: TERMUX
|
||||
os: ubuntu-22.04-arm
|
||||
- platform: LARCH64
|
||||
os: ubuntu-22.04-arm
|
||||
- platform: ANDROID_GLIBC
|
||||
os: ubuntu-latest
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
@@ -53,6 +69,7 @@ jobs:
|
||||
if [[ ${{ matrix.platform }} != 'X64' && ${{ matrix.platform }} != 'RISCV' && ${{ matrix.platform }} != 'LARCH64' ]]; then
|
||||
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
|
||||
echo "BOX64_COMPILER=$PWD/android-ndk-r26b/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android31-clang" >> $GITHUB_ENV
|
||||
@@ -63,7 +80,7 @@ jobs:
|
||||
sudo chmod 755 -R /system
|
||||
elif [[ ${{ matrix.platform }} == 'ANDROID_GLIBC' ]]; then
|
||||
sudo apt-get -y install git gcc-aarch64-linux-gnu
|
||||
echo "BOX64_PLATFORM_MARCRO=-DARM64=1 -DARM_DYNAREC=1 -DBAD_SIGNAL=1" >> $GITHUB_ENV
|
||||
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
|
||||
else
|
||||
sudo apt-get -y install git gcc-aarch64-linux-gnu
|
||||
@@ -71,7 +88,6 @@ jobs:
|
||||
echo "BOX64_COMPILER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
|
||||
fi
|
||||
if [[ ${{ matrix.platform }} == 'TERMUX' ]]; then
|
||||
sudo apt-get -y install p7zip
|
||||
wget https://mirrors.utermux.dev/termux/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
|
||||
@@ -92,7 +108,7 @@ jobs:
|
||||
elif [[ ${{ matrix.platform }} == 'RISCV' ]]; then
|
||||
echo BOX64_PLATFORM_MARCRO="-DRV64=ON" >> $GITHUB_ENV
|
||||
echo "BOX64_COMPILER=riscv64-linux-gnu-gcc" >> $GITHUB_ENV
|
||||
sudo apt-get -y install git gcc-riscv64-linux-gnu cmake make python3 ninja-build
|
||||
sudo apt-get -y install git gcc-riscv64-linux-gnu cmake make python3 ninja-build libglib2.0-dev
|
||||
elif [[ ${{ matrix.platform }} == 'LARCH64' ]]; then
|
||||
sudo mkdir /usr/local/larch
|
||||
wget -O- -q https://github.com/loongson/build-tools/releases/download/2023.08.08/CLFS-loongarch64-8.1-x86_64-cross-tools-gcc-glibc.tar.xz | sudo tar -C /usr/local/larch --strip-components=1 --xz -xf -
|
||||
@@ -241,13 +257,6 @@ jobs:
|
||||
|
||||
BOX64_DYNAREC=0 ctest $CTEST_OPTIONS
|
||||
ctest $CTEST_OPTIONS
|
||||
elif [[ ${{ matrix.platform }} != 'X64' ]]; then # AArch64
|
||||
export INTERPRETER=qemu-aarch64-static
|
||||
export QEMU_LD_PREFIX=/usr/aarch64-linux-gnu/
|
||||
|
||||
BOX64_DYNAREC=0 ctest $CTEST_OPTIONS
|
||||
ctest $CTEST_OPTIONS
|
||||
BOX64_DYNAREC_TEST=1 ctest $CTEST_OPTIONS -E nocosim
|
||||
else
|
||||
ctest -j$(nproc)
|
||||
fi
|
||||
@@ -256,6 +265,9 @@ jobs:
|
||||
id: git-info
|
||||
run: echo "SHORT_COMMIT=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
|
||||
|
||||
- name: "Get Box64 Version"
|
||||
run: echo "BOX64_VERSION=$(cat src/box64version.h | grep BOX64_MAJOR | cut -d " " -f 3).$(cat src/box64version.h | grep BOX64_MINOR | cut -d " " -f 3).$(cat src/box64version.h | grep BOX64_REVISION | cut -d " " -f 3)" >> $GITHUB_ENV
|
||||
|
||||
- name: "Packaging WCP file for Winlator"
|
||||
if: matrix.platform == 'ANDROID_GLIBC' && matrix.type != 'StaticBuild'
|
||||
run: |
|
||||
@@ -277,6 +289,23 @@ jobs:
|
||||
patchelf --set-interpreter /data/data/com.winlator/files/imagefs/usr/lib/ld-linux-aarch64.so.1 ./box64
|
||||
tar --zstd -cf box64-latest.wcp box64 profile.json
|
||||
|
||||
- name: "Package Rat File for MiceWine"
|
||||
if: matrix.platform == 'ANDROID' && matrix.type != 'StaticBuild'
|
||||
run: |
|
||||
cd build
|
||||
|
||||
mkdir -p files/usr/bin
|
||||
|
||||
cp box64 files/usr/bin
|
||||
|
||||
echo "name=Box64 (CI Build)" > pkg-header
|
||||
echo "category=Box64" >> pkg-header
|
||||
echo "version=${BOX64_VERSION}-${SHORT_COMMIT}" >> pkg-header
|
||||
echo "architecture=aarch64" >> pkg-header
|
||||
echo "vkDriverLib=" >> pkg-header
|
||||
|
||||
7z -tzip -mx=5 a box64-latest.rat files pkg-header
|
||||
|
||||
- name: "Upload Artifact"
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
@@ -289,3 +318,10 @@ jobs:
|
||||
with:
|
||||
name: box64-latest-${{ matrix.type }}-wcp
|
||||
path: build/box64-latest.wcp
|
||||
|
||||
- name: "Upload Rat File"
|
||||
if: matrix.platform == 'ANDROID' && matrix.type != 'StaticBuild'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: box64-MiceWine-${{ matrix.type }}
|
||||
path: build/box64-latest.rat
|
||||
+14
@@ -73,3 +73,17 @@ backup/
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
|
||||
# Archives
|
||||
*.7z
|
||||
*.deb
|
||||
*.eopkg
|
||||
*.gz
|
||||
*.rar
|
||||
*.rpm
|
||||
*.tar*
|
||||
*.xbps
|
||||
*.xz
|
||||
*.zip
|
||||
*.zst
|
||||
*.zstd
|
||||
+70
-13
@@ -30,9 +30,10 @@ option(LX2160A "Set to ON if targeting an LX2160A based device" ${LX2160A})
|
||||
option(ARM64 "Set to ON if targeting a generic ARM64 based device" ${ARM64})
|
||||
option(ANDROID "Set to ON if targeting an Android device" ${ANDROID})
|
||||
option(TERMUX "Set to ON if targeting an Android device with Termux" ${TERMUX})
|
||||
option(WINLATOR_GLIBC "Set to ON if targeting an Android device with Winlator Glibc" ${WINLATOR_GLIBC})
|
||||
option(USE_CCACHE "Set to ON to use ccache if present in the system" ${USE_CCACHE})
|
||||
option(HAVE_TRACE "Set to ON to have Trace ability (needs ZydisInfo library)" ${HAVE_TRACE})
|
||||
option(SAVE_MEM "Set to ON to build dynarec with some slower memory saving optimisations" ${SAVE_MEM})
|
||||
option(SAVE_MEM "Set to ON to build dynarec with some slower memory saving optimizations" ${SAVE_MEM})
|
||||
option(NOLOADADDR "Set to ON to avoid fixing the load address of Box64" OFF)
|
||||
option(NOGIT "Set to ON if not building from a git clone repo (like when building from a zip download from github)" ${NOGIT})
|
||||
option(BAD_SIGNAL "Set to ON to activate the workaround for incoherent si_info on SIGSEGV" ${BAD_SIGNAL})
|
||||
@@ -41,6 +42,8 @@ option(CI "Set to ON if running in CI" ${CI})
|
||||
option(WITH_MOLD "Set to ON to use with mold" ${WITH_MOLD})
|
||||
option(BOX32 "Set to ON to add Linux 32bits support (experimental, do not use)" ${BOX32})
|
||||
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})
|
||||
|
||||
if(TERMUX)
|
||||
set(TERMUX_PATH "/data/data/com.termux/files")
|
||||
@@ -52,6 +55,10 @@ if(LARCH64)
|
||||
set(ARM_DYNAREC OFF CACHE BOOL "")
|
||||
set(RV64_DYNAREC OFF CACHE BOOL "")
|
||||
set(LARCH64_DYNAREC ON CACHE BOOL "")
|
||||
if(LARCH64_ABI_1)
|
||||
message(STATUS "Build for Loongarch64 ABI 1.0 system")
|
||||
add_definitions(-DLA64_ABI_1)
|
||||
endif()
|
||||
endif()
|
||||
if(RV64)
|
||||
set(LD80BITS OFF CACHE BOOL "")
|
||||
@@ -86,10 +93,15 @@ if(SW64)
|
||||
endif()
|
||||
if(ANDROID)
|
||||
set(TERMUX_PATH "/data/data/com.termux/files")
|
||||
set(NOLOADADDR ON CACHE BOOL "")
|
||||
#set(NOLOADADDR ON CACHE BOOL "") #no need to force this setting it seems now
|
||||
set(BAD_SIGNAL ON CACHE BOOL "")
|
||||
endif()
|
||||
|
||||
if(GDBJIT)
|
||||
message(STATUS "Build with GDBJIT support")
|
||||
add_definitions(-DGDBJIT)
|
||||
endif()
|
||||
|
||||
option(LD80BITS "Set to ON if host device have 80bits long double (i.e. i386)" ${LD80BITS})
|
||||
option(NOALIGN "Set to ON if host device doesn't need re-align (i.e. i386)" ${NOALIGN})
|
||||
option(ARM_DYNAREC "Set to ON to use ARM Dynamic Recompilation" ${ARM_DYNAREC})
|
||||
@@ -245,6 +257,9 @@ endif()
|
||||
if(TERMUX)
|
||||
add_definitions(-DTERMUX)
|
||||
endif()
|
||||
if(WINLATOR_GLIBC)
|
||||
add_definitions(-DWINLATOR_GLIBC)
|
||||
endif()
|
||||
if(BAD_SIGNAL)
|
||||
add_definitions(-DBAD_SIGNAL)
|
||||
endif()
|
||||
@@ -360,6 +375,7 @@ set(ELFLOADER_SRC
|
||||
"${BOX64_ROOT}/src/elfs/elfdwarf_private.c"
|
||||
"${BOX64_ROOT}/src/emu/x64compstrings.c"
|
||||
"${BOX64_ROOT}/src/emu/x64emu.c"
|
||||
"${BOX64_ROOT}/src/emu/x64printer.c"
|
||||
"${BOX64_ROOT}/src/emu/x64int3.c"
|
||||
"${BOX64_ROOT}/src/emu/x87emu_private.c"
|
||||
"${BOX64_ROOT}/src/emu/x64primop.c"
|
||||
@@ -381,11 +397,12 @@ set(ELFLOADER_SRC
|
||||
"${BOX64_ROOT}/src/tools/box64stack.c"
|
||||
"${BOX64_ROOT}/src/tools/bridge.c"
|
||||
"${BOX64_ROOT}/src/tools/callback.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/rcfile.c"
|
||||
"${BOX64_ROOT}/src/tools/env.c"
|
||||
"${BOX64_ROOT}/src/tools/wine_tools.c"
|
||||
"${BOX64_ROOT}/src/wrapped/generated/wrapper.c"
|
||||
)
|
||||
@@ -411,6 +428,7 @@ if(BOX32)
|
||||
"${BOX64_ROOT}/src/librarian/globalsymbols32.c"
|
||||
"${BOX64_ROOT}/src/libtools/myalign32.c"
|
||||
"${BOX64_ROOT}/src/libtools/myalign64_32.c"
|
||||
"${BOX64_ROOT}/src/libtools/myalignxcb32.c"
|
||||
"${BOX64_ROOT}/src/libtools/signal32.c"
|
||||
"${BOX64_ROOT}/src/libtools/threads32.c"
|
||||
"${BOX64_ROOT}/src/libtools/libc_net32.c"
|
||||
@@ -620,6 +638,7 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxcbrandr.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxcbrender.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxcbrenderutil.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxcbres.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxcbshape.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxcbshm.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxcbsync.c"
|
||||
@@ -660,6 +679,7 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedpangocairo.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedpangoft2.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedpam.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedpcap.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedplc4.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedplds4.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedpng16.c"
|
||||
@@ -767,7 +787,7 @@ if(NOT CI)
|
||||
OUTPUT "${BOX64_ROOT}/src/wrapped/generated/functions_list.txt"
|
||||
COMMAND "${PYTHON_EXECUTABLE}" "${BOX64_ROOT}/rebuild_wrappers.py"
|
||||
"${BOX64_ROOT}"
|
||||
"PANDORA" "HAVE_LD80BITS" "NOALIGN" "HAVE_TRACE" "ANDROID" "TERMUX" "STATICBUILD" "--"
|
||||
"PANDORA" "HAVE_LD80BITS" "NOALIGN" "HAVE_TRACE" "ANDROID" "TERMUX" "STATICBUILD" "LA64" "--"
|
||||
${WRAPPEDS_HEAD}
|
||||
MAIN_DEPENDENCY "${BOX64_ROOT}/rebuild_wrappers.py"
|
||||
DEPENDS ${WRAPPEDS} ${WRAPPEDS_HEAD}
|
||||
@@ -816,6 +836,7 @@ if(BOX32)
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedfreetype.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedfontconfig.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibx11.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibxdamage.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibxext.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibxfixes.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibxrender.c"
|
||||
@@ -827,10 +848,19 @@ if(BOX32)
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibxxf86vm.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedxinerama.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedexpat.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibx11xcb.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibxcb.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibxcbres.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedudev0.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedudev1.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibuuid.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedgnutls.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedtcmallocminimal.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedcairo.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibdrm.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibvdpau.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappednsl.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibcups.c"
|
||||
)
|
||||
endif()
|
||||
string(REPLACE ".c" "_private.h" MODROOT ${BOX64_ROOT})
|
||||
@@ -849,7 +879,7 @@ if(BOX32)
|
||||
OUTPUT "${BOX64_ROOT}/src/wrapped32/generated/functions_list.txt"
|
||||
COMMAND "${PYTHON_EXECUTABLE}" "${BOX64_ROOT}/rebuild_wrappers_32.py"
|
||||
"${BOX64_ROOT}"
|
||||
"PANDORA" "HAVE_LD80BITS" "NOALIGN" "HAVE_TRACE" "ANDROID" "TERMUX" "STATICBUILD" "--"
|
||||
"PANDORA" "HAVE_LD80BITS" "NOALIGN" "HAVE_TRACE" "ANDROID" "TERMUX" "WINLATOR_GLIBC" "STATICBUILD" "--"
|
||||
${WRAPPEDS32_HEAD}
|
||||
MAIN_DEPENDENCY "${BOX64_ROOT}/rebuild_wrappers_32.py"
|
||||
DEPENDS ${WRAPPEDS32} ${WRAPPEDS32_HEAD}
|
||||
@@ -877,6 +907,7 @@ if(ARM_DYNAREC)
|
||||
${DYNAREC_SRC}
|
||||
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_functions.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_arch.c"
|
||||
"${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"
|
||||
@@ -937,6 +968,7 @@ if(RV64_DYNAREC)
|
||||
${DYNAREC_SRC}
|
||||
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_functions.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_arch.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/rv64_printer.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_jmpnext.c"
|
||||
"${BOX64_ROOT}/src/rv64detect.c"
|
||||
@@ -1016,14 +1048,21 @@ if(LARCH64_DYNAREC)
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_64.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_66.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_6664.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_67.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_f30f.c"
|
||||
"${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_67.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_f0.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_f20f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/la64/dynarec_la64_f30f.c"
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
if(GDBJIT)
|
||||
set(GDBJITREADER "${BOX64_ROOT}/gdbjit/reader.c")
|
||||
endif()
|
||||
|
||||
if(DYNAREC)
|
||||
set(DYNAREC_PASS
|
||||
"${BOX64_ROOT}/src/wrapped/generated/wrapper.h"
|
||||
@@ -1067,6 +1106,10 @@ if(DYNAREC)
|
||||
$<TARGET_OBJECTS:native_pass3>
|
||||
$<TARGET_OBJECTS:test_interpreter>
|
||||
)
|
||||
|
||||
if(GDBJIT)
|
||||
add_library(box64gdbjitreader SHARED ${GDBJITREADER})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# creates git_head.h
|
||||
@@ -1105,7 +1148,7 @@ else()
|
||||
target_link_libraries(${BOX64} c m dl)
|
||||
endif()
|
||||
else()
|
||||
set_target_properties(${BOX64} PROPERTIES LINK_FLAGS "-Wl,--no-as-needed -lc -lm -ldl -lrt -lpthread -lresolv -lutil -Wl,--as-needed -pthread")
|
||||
set_property(TARGET ${BOX64} APPEND_STRING PROPERTY LINK_FLAGS "-Wl,--no-as-needed -lc -lm -ldl -lrt -lpthread -lresolv -lutil -Wl,--as-needed -pthread ")
|
||||
endif()
|
||||
endif()
|
||||
if(DYNAREC)
|
||||
@@ -1116,9 +1159,9 @@ target_link_libraries(${BOX64} interpreter)
|
||||
if(${CMAKE_VERSION} VERSION_LESS "3.13")
|
||||
if(NOT NOLOADADDR)
|
||||
if(CMAKE_C_COMPILER_ID STREQUAL "Clang" OR WITH_MOLD)
|
||||
set_target_properties(${BOX64} PROPERTIES LINK_FLAGS "-no-pie -Wl,--image-base=${BOX64_ELF_ADDRESS}")
|
||||
set_property(TARGET ${BOX64} APPEND_STRING PROPERTY LINK_FLAGS "-no-pie -Wl,--image-base=${BOX64_ELF_ADDRESS} ")
|
||||
else()
|
||||
set_target_properties(${BOX64} PROPERTIES LINK_FLAGS "-Wl,-Ttext-segment,${BOX64_ELF_ADDRESS}")
|
||||
set_property(TARGET ${BOX64} APPEND_STRING PROPERTY LINK_FLAGS "-Wl,-Ttext-segment,${BOX64_ELF_ADDRESS} ")
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
@@ -1126,7 +1169,7 @@ else()
|
||||
if(NOT NOLOADADDR)
|
||||
if(CMAKE_C_COMPILER_ID STREQUAL "Clang" OR WITH_MOLD)
|
||||
if(WITH_MOLD) # --image-base requires -no-pie in mold!
|
||||
set_target_properties(${BOX64} PROPERTIES LINK_FLAGS "-no-pie -lm")
|
||||
set_property(TARGET ${BOX64} APPEND_STRING PROPERTY LINK_FLAGS "-no-pie -lm ")
|
||||
endif()
|
||||
target_link_options(${BOX64} PUBLIC LINKER:--image-base=${BOX64_ELF_ADDRESS})
|
||||
else()
|
||||
@@ -1156,6 +1199,9 @@ if(NOT _x86 AND NOT _x86_64)
|
||||
install(PROGRAMS ${CMAKE_SOURCE_DIR}/tests/box64-bash DESTINATION ${TERMUX_PATH}/usr/bin)
|
||||
endif()
|
||||
endif()
|
||||
if (GDBJIT)
|
||||
install(TARGETS box64gdbjitreader RUNTIME DESTINATION lib)
|
||||
endif()
|
||||
if(NOT NO_CONF_INSTALL)
|
||||
configure_file(system/box64.conf.cmake system/box64.conf)
|
||||
if(NOT TERMUX)
|
||||
@@ -1462,6 +1508,17 @@ add_test(avx_intrinsics ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${B
|
||||
|
||||
set_tests_properties(avx_intrinsics PROPERTIES ENVIRONMENT "BOX64_DYNAREC_FASTNAN=0;BOX64_DYNAREC_FASTROUND=0;BOX64_AVX=2")
|
||||
|
||||
add_test(fpu_rounding ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test31 -D TEST_OUTPUT=tmpfile31.txt
|
||||
-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()
|
||||
|
||||
else()
|
||||
|
||||
add_test(bootSyscall ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
@@ -1741,8 +1798,8 @@ if(BOX32)
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref20.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME multiple_dlopen_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test21 -D TEST_OUTPUT=tmpfile32_21.txt
|
||||
add_test(NAME multiple_dlopen_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test21 -D TEST_OUTPUT=tmpfile32_21.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref21.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ Box64 offers environment variables to control its behavior. For details, see [Us
|
||||
## 🚀 Compiling and Installation
|
||||
|
||||
- [Compilation Instructions](https://github.com/ptitSeb/box64/blob/main/docs/COMPILE.md)
|
||||
- [Bundle x86 Libraries](https://github.com/ptitSeb/box64/blob/main/docs/BUNDLE-X86-LIBS.md)
|
||||
- [Wine Installation for Box64](https://github.com/ptitSeb/box64/blob/main/docs/X64WINE.md)
|
||||
|
||||
---
|
||||
@@ -50,7 +51,7 @@ Box64 requires 64-bit libraries on the host system, as it directly translates x8
|
||||
|
||||
**Notes**
|
||||
|
||||
1. Box32 mode is in the making, which aims to support 32-bit binaries on Box64, you can enable it at build time, but do not expect everything to work. There is actually a few things that works, amny that don't. It's a known issue, no need to create tickets about it for now.
|
||||
1. Box32 mode is in the making, which aims to support 32-bit binaries on Box64, you can enable it at build time, but do not expect everything to work. There is actually a few things that work, many that don't. It's a known issue, no need to create tickets about it for now.
|
||||
2. Some installers may default to x86 on 64-bit host OSes, causing compatibility issues. Workaround: Use a fake `uname` that returns "x86_64" for `-m`.
|
||||
|
||||
---
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/bluez-libs-5.72-2.el9.i686.rpm,af1aba8e6fa5ccf33032d58a3acc59368c07d532293396db205fb9a4bc1241ae
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/bluez-libs-5.72-2.el9.x86_64.rpm,49c273813b4616240acdae8dae893192658c7541482f9bbb2c46dfe19b61877d
|
||||
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/fribidi-1.0.10-6.el9.2.i686.rpm,75f808f0f5f93aceb4e477aa5f302edbed07a605a0644f0ea929d4ea609e36a0
|
||||
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/fribidi-1.0.10-6.el9.2.x86_64.rpm,b4763ca410f8479b2775efb55ba09e6722948af7526180a56309e3e090c27010
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/gmp-6.2.0-13.el9.i686.rpm,fe352f7d197ebdf2c92bbd6e548f9f6b7ac9e69e7a9d6c9861a6274482e79d73
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/gmp-6.2.0-13.el9.x86_64.rpm,babe0b1385e723476a216d5f4b72453e031c3d683b19344786c2bddf7203cb04
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/gnutls-3.8.3-4.el9_4.i686.rpm,64cf0b0136d3f9b80b07ce2d4b8ce6a4ab86617e8ef9baf560bdfa5edef825ea
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/gnutls-3.8.3-4.el9_4.x86_64.rpm,16c48c504fe62f8e19cac7c6442d3e08bba487f610c2f533116dac32357cda86
|
||||
https://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/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/AppStream/x86_64/os/Packages/libICE-1.0.10-8.el9.i686.rpm,d9c44bb34c990fdcc6987feefacfc9e1e7997ca25f1e0a59c9adc9c16f2266d1
|
||||
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libICE-1.0.10-8.el9.x86_64.rpm,d0b867203384942985c3c4ad6fc9ec0000fcc9965408451a6cdef8df06a3833c
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libidn2-2.3.0-7.el9.i686.rpm,4458e2d416b5e6714ec664c4f88791eee7d1e707026a5854d948a6159911465b
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libidn2-2.3.0-7.el9.x86_64.rpm,c3ff43237c05258ee0dd77c28540fc8d0d824f1567b115ddfd555b78d2ee0e7a
|
||||
https://cdn.getsol.us/repo/shannon/libj/libjpeg-turbo/libjpeg-turbo-32bit-3.0.3-21-1-x86_64.eopkg,5624990281f6520026aa2252c711f02d4916099aeac63accc83bd2135b9d3220
|
||||
https://cdn.getsol.us/repo/shannon/libj/libjpeg-turbo/libjpeg-turbo-3.0.3-21-1-x86_64.eopkg,c92f19d446b4c2450306f13b1a908f2552400da09301996fe349fee243d964d2
|
||||
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libogg-1.3.4-6.el9.i686.rpm,9e4ff6fa0251c5357ae8f648b3e396d0043d5b3f2fb28d23325f5bd592c67aee
|
||||
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libogg-1.3.4-6.el9.x86_64.rpm,83b4b333e335654674032d1cda4d7deb328b5a409f95e3952c3dc482b684fd8f
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libpng-1.6.37-12.el9.i686.rpm,66bf967e84f0d8e7a0059f2b7dda33482ff5e4fe088d0e3bc86dc54e6c7c97be
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libpng-1.6.37-12.el9.x86_64.rpm,ebb3e927dfafa0b199e00e2bef4c10c85fc82a70c359faf9aeb599eda70bfa5e
|
||||
https://repo.almalinux.org/almalinux/9.5/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/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://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/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
|
||||
|
@@ -0,0 +1,93 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -x
|
||||
|
||||
extract_pkg_auto() {
|
||||
# Example x86_64 package name: libcurl3-gnutls_7.74.0-1.3+deb11u7~bpo11+1_amd64.deb
|
||||
# Example x86 package name: libcurl3-gnutls_7.74.0-1.3+deb11u7~bpo11+1_i386.deb
|
||||
if echo "${1}" | grep -q -P ".deb$"; then
|
||||
echo "DEB (Debian) package detected."
|
||||
ar x "$(basename "${1}")"
|
||||
tar --extract --file data.tar*
|
||||
# Example x86_64 package name: curl-gnutls-8.1.2-44-1-x86_64.eopkg
|
||||
# Example x86 package name: curl-gnutls-32bit-8.1.2-44-1-x86_64.eopkg
|
||||
elif echo "${1}" | grep -q -P ".eopkg$"; then
|
||||
echo "EOPKG (Solus Linux) package detected."
|
||||
unzip -o "$(basename "${1}")"
|
||||
tar --extract --file install.tar.xz
|
||||
# Example x86_64 package name: bluez-libs-5.63-1.el8.x86_64.rpm
|
||||
# Example x86 package name: bluez-libs-5.63-1.el8.i686.rpm
|
||||
elif echo "${1}" | grep -q -P ".rpm$"; then
|
||||
echo "RPM (Fedora) detected."
|
||||
rpm2cpio "$(basename "${1}")" | cpio -idmv
|
||||
# Example x86_64 package name: libjpeg-turbo-3.0.1_1.x86_64.xbps
|
||||
# Example x86 package name: libjpeg-turbo-32bit-3.0.1_1.x86_64.xbps
|
||||
elif echo "${1}" | grep -q -P ".xbps$"; then
|
||||
echo "XBPS (Void Linux) package detected."
|
||||
tar --extract --file "$(basename "${1}")"
|
||||
else
|
||||
echo "Unknown package."
|
||||
echo "Unsupported package type."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
box64_dir=$(pwd)
|
||||
dir_tmp_local="$(mktemp --directory)"
|
||||
cd "${dir_tmp_local}"
|
||||
|
||||
for line in $(cat "${box64_dir}/box64-bundle-x86-libs.csv");
|
||||
do pkg_url="$(echo "${line}" | cut -d, -f1)"
|
||||
pkg_checksum_expected="$(echo "${line}" | cut -d, -f2)"
|
||||
pkg_name="$(basename "${pkg_url}")"
|
||||
curl --silent --location --remote-name "${pkg_url}"
|
||||
pkg_checksum_actual="$(sha256sum ${pkg_name} | awk '{print $1}')"
|
||||
if [[ "${pkg_checksum_expected}" -ne "${pkg_checksum_actual}" ]];
|
||||
then echo "Invalid checksum for ${pkg_name}"
|
||||
echo "Expected: ${pkg_checksum_expected}"
|
||||
echo "Actual: ${pkg_checksum_actual}"
|
||||
exit 1
|
||||
fi
|
||||
extract_pkg_auto "${pkg_name}"
|
||||
done
|
||||
|
||||
# Start preperation of bundles.
|
||||
mkdir -p \
|
||||
"${dir_tmp_local}/bundle-libs/usr/lib/box64-i386-linux-gnu" \
|
||||
"${dir_tmp_local}/bundle-libs/usr/lib/box64-x86_64-linux-gnu" \
|
||||
"${dir_tmp_local}/bundle-pkgs" \
|
||||
|
||||
# Copy Debian family libraries.
|
||||
cp --archive "${dir_tmp_local}"/usr/lib/i386-linux-gnu/*.so* "${dir_tmp_local}/bundle-libs/usr/lib/box64-i386-linux-gnu"
|
||||
cp --archive "${dir_tmp_local}"/usr/lib/x86_64-linux-gnu/*.so* "${dir_tmp_local}/bundle-libs/usr/lib/box64-x86_64-linux-gnu"
|
||||
# Copy Fedora family libraries.
|
||||
cp --archive "${dir_tmp_local}"/usr/lib/*.so* "${dir_tmp_local}/bundle-libs/usr/lib/box64-i386-linux-gnu"
|
||||
cp --archive "${dir_tmp_local}"/usr/lib64/*.so* "${dir_tmp_local}/bundle-libs/usr/lib/box64-x86_64-linux-gnu"
|
||||
# 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"
|
||||
|
||||
# Create "<LIBRARY_FILE>.so" symlinks.
|
||||
for dir_lib in \
|
||||
"${dir_tmp_local}/bundle-libs/usr/lib/box64-i386-linux-gnu" \
|
||||
"${dir_tmp_local}/bundle-libs/usr/lib/box64-x86_64-linux-gnu"
|
||||
# If two or more libraries of the same name exist, this will symlink the oldest version.
|
||||
# Pipe this into a reverse sort `| sort -r` to symlink the newest version.
|
||||
do for lib in $(ls -1 "${dir_lib}")
|
||||
# Example output: libbluetooth.so
|
||||
do lib_base="$(echo "${lib}" | cut -d. -f1,2)"
|
||||
if ! ls "${dir_lib}/${lib_base}" 2> /dev/null
|
||||
then ln -s "${lib}" "${dir_lib}/${lib_base}"
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
mv "${dir_tmp_local}"/*.deb "${dir_tmp_local}/bundle-pkgs/"
|
||||
mv "${dir_tmp_local}"/*.eopkg "${dir_tmp_local}/bundle-pkgs/"
|
||||
mv "${dir_tmp_local}"/*.rpm "${dir_tmp_local}/bundle-pkgs/"
|
||||
|
||||
tar --directory "${dir_tmp_local}/bundle-libs" --create --file "${box64_dir}/box64-bundle-x86-libs.tar.gz" .
|
||||
tar --directory "${dir_tmp_local}/bundle-pkgs" --create --file "${box64_dir}/box64-bundle-x86-pkgs.tar.gz" .
|
||||
|
||||
# Clean up.
|
||||
cd -
|
||||
rm -r -f "${dir_tmp_local}"
|
||||
Vendored
+10
@@ -1,3 +1,13 @@
|
||||
box64 (0.3.4) unstable; urgency=low
|
||||
|
||||
* This version is Faster and more compatible
|
||||
* => The RV64 backend got faster and more stable, with lots of RVV 1.0 / xThreadVector support to emulate SSE/SSE2+ opcode (no AVX yet)
|
||||
* => On ARM64, Box64 now support more DRM types than before.
|
||||
* => BOX32 can run steam now. At least on ARM64 backend, it's still not working on RV64 and LA64 for now.
|
||||
* Please check CHAGELOG.md for more details
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 10 Mar 2025 10:30:33 -0100
|
||||
|
||||
box64 (0.3.2) unstable; urgency=low
|
||||
|
||||
* Introduced Box32 to run 32bits apps on 64bits OS
|
||||
|
||||
Vendored
+2
-1
@@ -21,4 +21,5 @@ override_dh_shlibdeps:
|
||||
--exclude=libcrypto.so.1.1 \
|
||||
--exclude=libmbedx509.so.1 \
|
||||
--exclude=libcrypto.so.1.0.0 \
|
||||
--exclude=libssl.1.0.0
|
||||
--exclude=libssl.so.1.0.0 \
|
||||
--exclude=box64-bash
|
||||
@@ -0,0 +1,66 @@
|
||||
# Bundling x86 Libraries
|
||||
|
||||
The script `box64-bundle-x86-libs.sh` is provided to download, extract, and re-bundle x86_64 and x86 libraries for use with Box64/Box32 and Box86. These libraries improve Box emulation. This bundle provides a much smaller size compared to using a full root file system of an operating system.
|
||||
|
||||
## Usage
|
||||
|
||||
### Administrator
|
||||
|
||||
Install required dependencies for the bundle script.
|
||||
|
||||
- Debian
|
||||
```
|
||||
sudo apt-get update
|
||||
sudo apt-get install coreutils curl binutils rpm2cpio 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`.
|
||||
- `box64-bundle-x86-pkgs.tar.gz` = All of the Linux distribution packages used to extract the library files. This is only created for preservation purposes and is otherwise unused.
|
||||
|
||||
Extract the library archive. Box will automatically search these paths for library files to emulate.
|
||||
|
||||
```
|
||||
sudo tar --extract --file box64-bundle-x86-libs.tar.gz --directory /
|
||||
```
|
||||
|
||||
### Developer
|
||||
|
||||
Add new packages to the `box64-bundle-x86-libs.csv` file in the format of `<PACKAGE_URL>,<SHA256_CHECKSUM>`.
|
||||
|
||||
Supported packages:
|
||||
- DEB (Debian)
|
||||
- EOPKG (Solus)
|
||||
- RPM (Fedora)
|
||||
- XBPS (Void Linux)
|
||||
|
||||
Preference of operating system packages that provide a library:
|
||||
1. RPMs from AlmaLinux 9 provide 10 years of updates.
|
||||
2. DEBs from Debian 11 provide 5 years of updates.
|
||||
3. EOPKG from Solus provide old variants of obscure 32-bit libraries.
|
||||
4. XBPS from Void Linux provide updated variants of obscure 32-bit libraries.
|
||||
5. Other (whereever a library is packaged)
|
||||
|
||||
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>`
|
||||
- XBPS
|
||||
- `xbps-query --repository --ownedby <LIBRARY_FILE>`
|
||||
|
||||
Once the package name is found, find the exact URL for downloading it.
|
||||
- DEB = Explore "main" and "contrib". Search for packages with the name "deb11" in it. Use the "amd64.deb" and "i386.deb" packages.
|
||||
- https://archive.debian.org/debian/pool/
|
||||
- EOPKG = Use the "`<VERSION>-<RELEASE>-x86_64.eopkg`" and "`32bit-<VERSION>-<RELEASE>-x86_64.eopkg`" packages.
|
||||
- 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/
|
||||
- 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.
|
||||
@@ -1,3 +1,39 @@
|
||||
v0.3.4
|
||||
======
|
||||
* This version is Faster and more compatible:
|
||||
=> The RV64 backend got faster and more stable, with lots of RVV 1.0 / xThreadVector support to emulate SSE/SSE2+ opcode (no AVX yet)
|
||||
=> On ARM64, Box64 now support more DRM types than before.
|
||||
=> BOX32 can run steam now. At least on ARM64 backend, it's still not working on RV64 and LA64 for now.
|
||||
* Added support to emulate Windows Syscall (needs Proton and a 48bits address space for now)
|
||||
* Added BOX64_DYNAREC_DIRTY to have a faster (but less safe) way to handle code that write in it's current page
|
||||
* Added a few rarely used opcodes
|
||||
* Added experimental support for GDBJIT, that allow an x86/x86_64 program to be debugged on ARM/RV64/LA64 platform with x86 regs and opcode view (might generate a lot of file tho)
|
||||
* Added support for Perf tools in a similar way if GDBJIT, to have an x86 fine view of the performances
|
||||
* Reworked undefined flags for common operations, to be similar to real CPU
|
||||
* Reworked cpuid handling, adding BOX64_CPUTYPE support to select Intel/AMD emulation (no 3DNow! support on AMD for now)
|
||||
* Reworked ucontext link to be closer to the real thing (and make it more simple)
|
||||
* Improved memory traking, file descriptor backed memory map, and detect wine loaded dll
|
||||
* Introduced settings per library and dll (mostly for Dynarec)
|
||||
* Wrapper: More functions addes, and some fixes too
|
||||
* BOX32: Many fixes around pthreads wrapping
|
||||
* BOX32: More functions wrapped.
|
||||
* BOX32: More libraies wrapped.
|
||||
* BOX32: Some reworks on how high memory (higher than 32bits) is masked, and can be used for Dynarec blocks.
|
||||
* Dynarec: The usual batch of fixes, improvments and opcodes additions on all 3 supported backend
|
||||
* Dynarec: Some fixes to NativeFlags handling, both on ARM64 and RV64
|
||||
* Dynarec: Added optimized REP MOVSB (expected for default CPUTYPE=0, according to new cpuid return)
|
||||
* Dynarec: LA64: more opcoded addes, using hardware extensions like AES
|
||||
* Dynarec: RV64: More work on using RVV 1.0 and xTheadVector extension to emulate SSE/SSE2+ opcodes
|
||||
* Dynarec: RV64: Added informations on flags when building blocks, to be used when a signal happens to rebuild a x86 context more accurate
|
||||
* Dynarec: ARM64: Reworked undefined flags for common operations, to be similar to real CPU
|
||||
* Dynarec: ARM64: Added informations on flags and xmm/ymm/x87 register when building blocks, to be used when a signal happens to rebuild a x86 context 100% accurate
|
||||
* TRACE: Reworked how trace for wrapped function call is printed.
|
||||
* TRACE: Reworked logs to prefix each line with a (optionaly colored) BOX32 or BOX64
|
||||
* COSIM: Some rework on cosim to limit false negative, especialy when handling x87 operations
|
||||
* LA64: Added limited support for ABI 1.0
|
||||
* CI: github CI now also generate MiceWine .rat archive, along with Winlator .wcp archive and regular linux builds.
|
||||
* RCFile: Added many new games profiles (both for speed improvment or for compatibilty)
|
||||
|
||||
v0.3.2
|
||||
======
|
||||
* Introduced Box32 to run 32bits apps on 64bits OS
|
||||
|
||||
+81
-46
@@ -5,10 +5,12 @@ If you don't want to compile box64 yourself and prefer to use third-party pre-bu
|
||||
|
||||
You can also generate your own package using the [instructions below](https://github.com/ptitSeb/box64/blob/main/docs/COMPILE.md#debian-packaging).
|
||||
|
||||
Additional installation steps may be necessary when copying only the box64 executable file without running make install in cross-build environments. See [Cross-compiling](https://github.com/ptitSeb/box64/blob/main/docs/COMPILE.md#Cross-compiling)
|
||||
|
||||
## Per-platform compiling instructions
|
||||
----
|
||||
|
||||
### The general approach
|
||||
|
||||
### The general approach is:
|
||||
```
|
||||
git clone https://github.com/ptitSeb/box64
|
||||
cd box64
|
||||
@@ -20,10 +22,11 @@ If it's the first install, you also need:
|
||||
```
|
||||
sudo systemctl restart systemd-binfmt
|
||||
```
|
||||
- You can use `make -j1`, `make -j2` to prevent running out of memory
|
||||
- You can also add `-DBAD_SIGNAL=ON` to the cmake command if you are on Linux Kernel mixed with Android, like on RK3588.
|
||||
- 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.
|
||||
|
||||
#### Example of generic ARM64 build for linux platforms
|
||||
|
||||
#### For Instance, if you want to build box64 for Generic ARM64 Linux platforms, it would look like this:
|
||||
```
|
||||
git clone https://github.com/ptitSeb/box64
|
||||
cd box64
|
||||
@@ -36,21 +39,21 @@ sudo systemctl restart systemd-binfmt
|
||||
|
||||
#### for RK3399
|
||||
|
||||
Using a 64bit OS:
|
||||
On a 64bit OS:
|
||||
```
|
||||
-D RK3399=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
|
||||
#### for RK3588 / RK3588S
|
||||
|
||||
Using a 64bit OS:
|
||||
On a 64bit OS:
|
||||
```
|
||||
-D RK3588=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
|
||||
#### for Raspberry Pi 3
|
||||
|
||||
Warning, you need a 64bit OS:
|
||||
On a 64bit OS:
|
||||
|
||||
If building on the Pi, you will also need a large swap (3 GB+)
|
||||
[optionally reduce GPU memory to a minimum (e.g. 16 MB) using `raspi-config`
|
||||
@@ -66,7 +69,7 @@ Still, this can be faster if your build is attended.
|
||||
|
||||
#### for Raspberry Pi 4
|
||||
|
||||
Warning, you need a 64bit OS:
|
||||
On a 64bit OS:
|
||||
|
||||
```
|
||||
-D RPI4ARM64=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
@@ -80,7 +83,7 @@ Warning, you need a 64bit OS:
|
||||
|
||||
#### for TEGRA X1
|
||||
|
||||
Using a 64bit OS:
|
||||
On a 64bit OS:
|
||||
|
||||
```
|
||||
-D TEGRAX1=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
@@ -88,7 +91,7 @@ Using a 64bit OS:
|
||||
|
||||
#### for Jetson Xavier/T194
|
||||
|
||||
Using a 64bit OS:
|
||||
On a 64bit OS:
|
||||
|
||||
```
|
||||
-D TEGRA_T194=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
@@ -96,16 +99,16 @@ Using a 64bit OS:
|
||||
|
||||
#### for Jetson Orin/T234
|
||||
|
||||
Using a 64bit OS:
|
||||
On a 64bit OS:
|
||||
|
||||
Caution: please use gcc-11 or higher, older gcc doesn't know cortex-a78ae
|
||||
Note: use gcc-11 or higher, older gcc doesn't know cortex-a78ae
|
||||
```
|
||||
-D TEGRA_T234=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
|
||||
#### for ODROID N2/N2+
|
||||
|
||||
Using a 64bit OS:
|
||||
On a 64bit OS:
|
||||
|
||||
```
|
||||
-D ODROIDN2=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
@@ -113,7 +116,7 @@ Using a 64bit OS:
|
||||
|
||||
#### for Snapdragon
|
||||
|
||||
Using a 64bit OS:
|
||||
On a 64bit OS:
|
||||
|
||||
```
|
||||
-D SD845=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
@@ -125,18 +128,18 @@ or
|
||||
-D SD888=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
|
||||
Depending how recent your Snapdragon is
|
||||
Depending on how recent your Snapdragon is
|
||||
|
||||
#### for Phytium
|
||||
|
||||
Using a 64bit OS:
|
||||
On a 64bit OS:
|
||||
```
|
||||
-D PHYTIUM=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
|
||||
#### for ADLink machines
|
||||
|
||||
Using a 64bit OS:
|
||||
On a 64bit OS:
|
||||
```
|
||||
-D ADLINK=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
@@ -151,7 +154,7 @@ Only test on Asahi with Fedora, using the default "16K page" kernel
|
||||
|
||||
#### for LoongArch
|
||||
|
||||
Using a 64bit OS:
|
||||
On a 64bit OS:
|
||||
|
||||
```
|
||||
-D LARCH64=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
@@ -159,7 +162,7 @@ Using a 64bit OS:
|
||||
|
||||
#### for RISC-V
|
||||
|
||||
Using a 64bit OS:
|
||||
On a 64bit OS:
|
||||
|
||||
```
|
||||
-D RV64=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
@@ -167,7 +170,7 @@ Using a 64bit OS:
|
||||
|
||||
#### for PowerPC 64 LE
|
||||
|
||||
Using a 64bit OS:
|
||||
On a 64bit OS:
|
||||
|
||||
```
|
||||
-D PPC64LE=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
@@ -175,7 +178,7 @@ Using a 64bit OS:
|
||||
|
||||
#### for LX2160A
|
||||
|
||||
Using a 64bit OS:
|
||||
On a 64bit OS:
|
||||
|
||||
```
|
||||
-D LX2160A=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
@@ -183,7 +186,7 @@ Using a 64bit OS:
|
||||
|
||||
#### for Termux
|
||||
|
||||
You must have ARM64 Device for build box64.
|
||||
You must have ARM64 machine to build box64.
|
||||
|
||||
##### in CHRoot/PRoot
|
||||
|
||||
@@ -193,15 +196,16 @@ You must have ARM64 Device for build box64.
|
||||
|
||||
##### in Termux (Native)
|
||||
|
||||
NOTE: BUILDING BOX64 IN TERMUX NATIVE IS EXPERIMENTAL AND DOESN'T GONNA RUN LINUX BINARIES IN NATIVE TERMUX BOX64!!!
|
||||
Note: Box64 in native termux is experimental and won't run linux binaries!
|
||||
|
||||
You also needed have `libandroid-sysv-semaphore` and `libandroid-spawn` libraries:
|
||||
You also need `libandroid-sysv-semaphore` and `libandroid-spawn` libraries.
|
||||
|
||||
```
|
||||
-D TERMUX=1 -DCMAKE_C_COMPILER=clang -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
|
||||
#### for x86_64 Linux
|
||||
|
||||
```
|
||||
-D LD80BITS=1 -D NOALIGN=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
@@ -215,58 +219,58 @@ Alternatively, you can **use the curses-based ccmake (or any other gui frontend
|
||||
|
||||
### Customize your build
|
||||
|
||||
#### Use ccache if you have it
|
||||
#### Use ccache when present
|
||||
|
||||
Add `-DUSE_CCACHE=1` if you have ccache (it's better if you plan to touch the sources)
|
||||
Add `-DUSE_CCACHE=1` option if you have ccache and plan to touch the sources.
|
||||
|
||||
#### To have some debug info
|
||||
#### Include debug information
|
||||
|
||||
The `-DCMAKE_BUILD_TYPE=RelWithDebInfo` argument makes a build that is both optimized for speed, and has debug information embedded. That way, if you have a crash or try to analyse performance, you'll have some symbols.
|
||||
Add `-DCMAKE_BUILD_TYPE=RelWithDebInfo` option for an optimized build with debug information embedded. That way, if you want to debug a crash or analyze performance, you have symbols.
|
||||
|
||||
#### To have a Trace Enabled build
|
||||
#### Build with trace
|
||||
|
||||
To have a trace enabled build (***the interpreter will be slightly slower***), add `-DHAVE_TRACE=1`. But you will need to have the [Zydis library](https://github.com/zyantific/zydis) in your `LD_LIBRARY_PATH` or in the system library folders at runtime. Use version v3.2.1, as later version changed the API and will no longer work with box64
|
||||
To have a trace enabled build (***the interpreter will be slightly slower***), add `-DHAVE_TRACE=1`. You will need the [Zydis library](https://github.com/zyantific/zydis) in your `LD_LIBRARY_PATH` or in the system library folders at runtime to get x86 trace. Use version v3.2.1, as later versions have changed the API and no longer work with box64.
|
||||
|
||||
#### To have ARM Dynarec
|
||||
#### Build ARM DynaRec
|
||||
|
||||
Dynarec is only available on ARM (for the meantime), Activate it by using `-DARM_DYNAREC=1`.
|
||||
Add `-DARM_DYNAREC=1` option to enable DynaRec on ARM machines.
|
||||
|
||||
#### To have a build using less memory
|
||||
#### Save memory at run time
|
||||
|
||||
You can use `-DSAVE_MEM` to have a build that will try to save some memory. It's, for now, only increasing the jumptable from 4 level to 5 levels. The added granularity avoid wasting space, but the 1 level more to the jumptable means there is on read from memory more when jumping between blocks.
|
||||
You can use `-DSAVE_MEM` to have a build that will try to save some memory. For now, it only increases the jumptable from 4 levels to 5. The added granularity avoids wasting space, but adds one more read from memory when jumping between blocks.
|
||||
|
||||
#### Not building from a git clone
|
||||
#### Build outside of a git repo
|
||||
|
||||
If you are not building from a git clone (for example, downloading a release source code zip from github), you need to use `-DNOGIT=1` from cmake to be able to build (box64 uses git SHA1 to show last commit in version number).
|
||||
Box64 uses git SHA1 to show last commit in version number, use `-DNOGIT=1` option when building outside of a git repo (for example, downloading a release source code zip from github).
|
||||
|
||||
#### Use faster linker
|
||||
|
||||
You need to add `-DWITH_MOLD=1` if GNU ld is extremely slow. Then run `mold -run make -j4` to build (make sure [Mold](https://github.com/rui314/mold) is installed).
|
||||
Add `-DWITH_MOLD=1` option when GNU ld is extremely slow. Then run `mold -run make -j4` to build (make sure [Mold](https://github.com/rui314/mold) is installed).
|
||||
|
||||
#### Build a statically linked box64
|
||||
|
||||
You can now build box64 statically linked, with `-DSTATICBUILD`. This is to use inside an x86_64 chroot. Note that this version of box64 will have just the minimum of wrapped libs. So only libc, libm and libpthread basically are wrapped. Other libs (like libGL or libvulkan, SDL2, etc...) will not be wrapped and x86_64 version will be used. It's designed to be used in docker image, or in headless server.
|
||||
Also, the Static Build is highly experimental, but feedback are always welcomed.
|
||||
You can now build box64 statically linked, with `-DSTATICBUILD` to use inside of a x86_64 chroot. Note that this version of box64 will only have the minimal wrapped libs, such as libc, libm and libpthread. Other libs (like libGL or libvulkan, SDL2, etc...) will use x86_64 versions. A static build is intended to be used in a docker image, or in a headless server. It is highly experimental, but feedback is always welcome.
|
||||
|
||||
----
|
||||
|
||||
## Testing
|
||||
----
|
||||
|
||||
A few tests are included with box64.
|
||||
|
||||
They can be launched using the `ctest` command.
|
||||
|
||||
The tests are very basic and only tests some functionality for now.
|
||||
The tests are very basic and only test some functionality for now.
|
||||
|
||||
----
|
||||
|
||||
## Debian Packaging
|
||||
----
|
||||
Box64 can also be packaged into a .deb file ***using the source code zip from the releases page*** with `DEB_BUILD_OPTIONS=nostrip dpkg-buildpackage -us -uc -nc`. Configure any additional cmake options you might want in `debian/rules`.
|
||||
|
||||
## Pre-build packages
|
||||
----
|
||||
Box64 can also be packaged into a .deb file ***using the source code zip from the releases page*** with `DEB_BUILD_OPTIONS=nostrip dpkg-buildpackage -us -uc -nc`. Configure any additional cmake options you want in `debian/rules`.
|
||||
|
||||
## Pre-built packages
|
||||
|
||||
### Debian-based Linux
|
||||
|
||||
You can use the [Pi-Apps-Coders apt repository](https://github.com/Pi-Apps-Coders/box64-debs) to install precompiled box64 debs, updated every 24 hours.
|
||||
|
||||
```
|
||||
@@ -296,3 +300,34 @@ Signed-By: /usr/share/keyrings/box64-archive-keyring.gpg" | sudo tee /etc/apt/so
|
||||
sudo apt update
|
||||
sudo apt install box64-generic-arm -y
|
||||
```
|
||||
|
||||
## Cross-compiling
|
||||
----
|
||||
### Set Up the Cross-Compiler
|
||||
For example, to compile Box64 for RISC-V on an x86 machine, you can get prebuilt GNU toolchain from the [riscv-gnu-toolchain](https://github.com/riscv-collab/riscv-gnu-toolchain/releases)
|
||||
|
||||
### Run CMake with Cross-Compilation Options
|
||||
Follow the per-platform compilation instructions to configure the CMake options for your target architecture.
|
||||
In particular, you must specify the cross-compiler. For example:
|
||||
```
|
||||
-DCMAKE_C_COMPILER=riscv64-unknown-linux-gnu-gcc # Or whichever cross-compiler you use
|
||||
```
|
||||
|
||||
### Running tests with QEMU (optional)
|
||||
To do a quick check, run:
|
||||
```
|
||||
qemu-riscv64 -L path/to/your/riscv64/sysroot box64 --help
|
||||
```
|
||||
You can run `dirname $(find -name libc.so.6)` to determine whether sysroot is provided by the prebuilt GNU toolchain or not.
|
||||
|
||||
To run CTest-based tests under QEMU:
|
||||
```
|
||||
ctest -j$(nproc)
|
||||
```
|
||||
|
||||
### Installing on the Target Machine
|
||||
After successfully cross-compiling, copy the box64 executable to your RISC-V device. Note that simply copying the binary does not automatically install Box64’s shared libraries. Because `make install` does not run on the target during cross-compilation, libraries required for emulation may be missing.
|
||||
|
||||
To fix this, copy the shared libraries folder from the Box64 repository (`x64lib` or `x86lib`) to your target. Place them into the proper library search paths, for example:
|
||||
- `/usr/lib/box64-x86_64-linux-gnu/` (for x86_64)
|
||||
- `/usr/lib/box64-i386-linux-gnu/` (for i386)
|
||||
+695
-426
File diff suppressed because it is too large.
Load diff
+558
-278
File diff suppressed because it is too large.
Load diff
+134
@@ -0,0 +1,134 @@
|
||||
# Usage: python gen.py
|
||||
|
||||
import json
|
||||
import os
|
||||
from collections import defaultdict
|
||||
|
||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
usage_file = os.path.join(script_dir, 'usage.json')
|
||||
|
||||
with open(usage_file, 'r') as file:
|
||||
data = json.load(file)
|
||||
|
||||
with open(os.path.join(script_dir, '../USAGE.md'), 'w') as md_file:
|
||||
md_file.write("""<!--- This file is generated by gen.py, do not edit it directly. -->
|
||||
Usage
|
||||
----
|
||||
|
||||
There are many environment variables to control Box64's behaviour, which will be listed below by category.
|
||||
|
||||
### 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`.
|
||||
Settings priority follows this order (from highest to lowest): `~/.box64rc` > `/etc/box64.box64rc` > environment variables.
|
||||
|
||||
Example configuration:
|
||||
|
||||
```
|
||||
[factorio]
|
||||
BOX64_DYNAREC_SAFEFLAGS=0
|
||||
BOX64_DYNAREC_BIGBLOCK=2
|
||||
BOX64_DYNAREC_FORWARD=1024
|
||||
BOX64_DYNAREC_CALLRET=1
|
||||
```
|
||||
|
||||
This configuration will apply the specified settings application-wide to any executable named `factorio`.
|
||||
|
||||
### Advanced usage
|
||||
|
||||
1. **Wildcard Matching**
|
||||
|
||||
Asterisks (`*`) can be used for basic pattern matching in application names. For instance, `[*setup*]` will match any program containing "setup" in its name. Note this implements simple wildcard matching rather than full regex support.
|
||||
2. **Custom Configuration File**
|
||||
|
||||
The `BOX64_RCFILE` environment variable can specify an alternative configuration file instead of the default `/etc/box64.box64rc`.
|
||||
3. **Per-File Settings**
|
||||
|
||||
Sections starting with `/` apply to specific files. For example:
|
||||
```
|
||||
[/d3d9.dll]
|
||||
BOX64_DYNAREC_SAFEFLAGS=0
|
||||
```
|
||||
These settings will only affect the `d3d9.dll` file. This syntax also works for **emulated** Linux libraries, e.g., `[/libstdc++.so.6]`.
|
||||
|
||||
----
|
||||
|
||||
""")
|
||||
|
||||
categories = defaultdict(list)
|
||||
for entry in data:
|
||||
categories[entry["category"]].append(entry)
|
||||
|
||||
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")
|
||||
for option in entry['options']:
|
||||
md_file.write(f" * {option['key']}: {option['description']} {"[Default]" if option['default'] else ""}\n")
|
||||
md_file.write("\n")
|
||||
|
||||
|
||||
with open(os.path.join(script_dir, '../box64.pod'), 'w') as pod_file:
|
||||
pod_file.write("""=head1 NAME
|
||||
|
||||
box64 - Linux Userspace x86_64 Emulator with a twist
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
B<box64> [B<--help>] [B<--version>] I<executable>
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
B<Box64> lets you run x86_64 Linux programs (such as games) on non-x86_64 Linux
|
||||
systems, like ARM (host system needs to be 64-bit little-endian). Since B<Box64>
|
||||
uses the native versions of some "system" libraries, like libc, libm, SDL, and
|
||||
OpenGL, it's easy to integrate and use with most applications, and performance
|
||||
can be surprisingly high in many cases. B<Box64> integrates with DynaRec (dynamic
|
||||
recompiler) for the ARM64 platform, providing a speed boost between 5 to 10
|
||||
times faster than using only the interpreter.
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
=over 8
|
||||
|
||||
=item B<-h,--help>
|
||||
|
||||
Print box64 help and quit.
|
||||
|
||||
=item B<-v,--version>
|
||||
|
||||
Print box64 version and quit.
|
||||
|
||||
=back
|
||||
|
||||
=head1 BRIEF USAGE
|
||||
|
||||
There are many environment variables to control B<Box64>'s behaviour. In
|
||||
addition to environment variables, B<Box64> also looks for 2 places for rcfile:
|
||||
F</etc/box64.box64rc> and F<~/.box64rc>, in the format of .ini files.
|
||||
Settings priority: F<~/.box64rc> > F</etc/box64.box64rc> > environment variables.
|
||||
Example:
|
||||
|
||||
[factorio]
|
||||
BOX64_DYNAREC_SAFEFLAGS=0
|
||||
BOX64_DYNAREC_BIGBLOCK=2
|
||||
BOX64_DYNAREC_FORWARD=1024
|
||||
BOX64_DYNAREC_CALLRET=1
|
||||
|
||||
=head1 ENVIRONMENT VARIABLES
|
||||
|
||||
=over 8
|
||||
|
||||
""")
|
||||
|
||||
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")
|
||||
for option in entry['options']:
|
||||
pod_file.write(f" * {option['key']} : {option['description']} {"[Default]" if option['default'] else ""}\n")
|
||||
pod_file.write("\n")
|
||||
|
||||
pod_file.write("""
|
||||
=back
|
||||
|
||||
=cut
|
||||
""")
|
||||
+1605
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,45 @@
|
||||
#include "gdbjit.h"
|
||||
#include <stdio.h>
|
||||
|
||||
static char block_name_buffer[16];
|
||||
|
||||
static enum gdb_status read_debug_info(struct gdb_reader_funcs* self, struct gdb_symbol_callbacks* cbs, void* memory, long memory_sz)
|
||||
{
|
||||
gdbjit_block_t* block = (gdbjit_block_t*)memory;
|
||||
|
||||
struct gdb_object* object = cbs->object_open(cbs);
|
||||
struct gdb_symtab* symtab = cbs->symtab_open(cbs, object, block->filename);
|
||||
sprintf(block_name_buffer, "%x", block->x64start);
|
||||
cbs->block_open(cbs, symtab, NULL, block->start, block->end, block_name_buffer);
|
||||
|
||||
cbs->line_mapping_add(cbs, symtab, block->nlines, block->lines);
|
||||
|
||||
cbs->symtab_close(cbs, symtab);
|
||||
cbs->object_close(cbs, object);
|
||||
|
||||
return GDB_SUCCESS;
|
||||
}
|
||||
|
||||
enum gdb_status unwind_frame(struct gdb_reader_funcs* self, struct gdb_unwind_callbacks* cbs)
|
||||
{
|
||||
return GDB_SUCCESS;
|
||||
}
|
||||
|
||||
struct gdb_frame_id get_frame_id(struct gdb_reader_funcs* self, struct gdb_unwind_callbacks* cbs)
|
||||
{
|
||||
struct gdb_frame_id frame = {0xdeadbeef, 0};
|
||||
return frame;
|
||||
}
|
||||
|
||||
void destroy_reader(struct gdb_reader_funcs* self) {}
|
||||
|
||||
__attribute__((visibility("default"))) struct gdb_reader_funcs* gdb_init_reader(void)
|
||||
{
|
||||
static struct gdb_reader_funcs funcs = {GDB_READER_INTERFACE_VERSION, NULL, read_debug_info, unwind_frame, get_frame_id, destroy_reader};
|
||||
return &funcs;
|
||||
}
|
||||
|
||||
__attribute__((visibility("default"))) int plugin_is_GPL_compatible (void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
Executable
+31
@@ -0,0 +1,31 @@
|
||||
#!/bin/bash
|
||||
|
||||
# create necessary directories
|
||||
mkdir -p ~/steam
|
||||
mkdir -p ~/steam/tmp
|
||||
cd ~/steam/tmp
|
||||
|
||||
# download latest deb and unpack
|
||||
wget https://cdn.cloudflare.steamstatic.com/client/installer/steam.deb
|
||||
ar x steam.deb
|
||||
tar xf data.tar.xz
|
||||
|
||||
# remove deb archives, not needed anymore
|
||||
rm ./*.tar.xz ./steam.deb
|
||||
|
||||
# move deb contents to steam folder
|
||||
mv ./usr/* ../
|
||||
cd ../ && rm -rf ./tmp/
|
||||
|
||||
# create run script
|
||||
echo '#!/bin/bash
|
||||
export STEAMOS=1
|
||||
export STEAM_RUNTIME=1
|
||||
export DBUS_FATAL_WARNINGS=0
|
||||
~/steam/bin/steam $@' > steam
|
||||
|
||||
# make script executable and move
|
||||
chmod +x steam
|
||||
sudo mv steam /usr/local/bin/
|
||||
|
||||
echo "Script complete."
|
||||
+63
-6
@@ -363,7 +363,7 @@ def readFiles(files: Iterable[Filename]) -> Tuple[JumbledGlobals, JumbledRedirec
|
||||
gbl : JumbledGlobals = {}
|
||||
redirects: JumbledRedirects = {}
|
||||
filespec : JumbledFilesSpecific = {}
|
||||
|
||||
|
||||
functions: Dict[str, Filename] = {}
|
||||
halt_required = False # Is there a GO(*, .FE*) or similar in-batch error(s)?
|
||||
# First read the files inside the headers
|
||||
@@ -842,24 +842,25 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
|
||||
# H could be allowed maybe?
|
||||
allowed_simply: Dict[str, str] = {"ARM64": "v", "RV64": "v"}
|
||||
allowed_regs : Dict[str, str] = {"ARM64": "cCwWiuIUlLp", "RV64": "CWuIUlLp"}
|
||||
allowed_regs : Dict[str, str] = {"ARM64": "cCwWiuIUlLp", "RV64": "CWIUlLp"}
|
||||
allowed_fpr : Dict[str, str] = {"ARM64": "fd", "RV64": "fd"}
|
||||
allowed_sextw : Dict[str, str] = {"ARM64": "", "RV64": "cwiu"}
|
||||
|
||||
# Detect functions which return in an x87 register
|
||||
retx87_wraps: Dict[ClausesStr, List[FunctionType]] = {}
|
||||
return_x87: str = "D"
|
||||
|
||||
# Sanity checks
|
||||
forbidden_simple: Dict[str, str] = {"ARM64": "EDVOSNHPAxXYb", "RV64": "EcwiDVOSNHPAxXYb"}
|
||||
forbidden_simple: Dict[str, str] = {"ARM64": "EDVOSNHPAxXYb", "RV64": "EDVOSNHPAxXYb"}
|
||||
assert(all(k in allowed_simply for k in forbidden_simple))
|
||||
assert(all(k in allowed_regs for k in forbidden_simple))
|
||||
assert(all(k in allowed_fpr for k in forbidden_simple))
|
||||
for k1 in forbidden_simple:
|
||||
assert(len(allowed_simply[k1]) + len(allowed_regs[k1]) + len(allowed_fpr[k1]) + len(forbidden_simple[k1]) == len(allowed_conv.values))
|
||||
assert(len(allowed_simply[k1]) + len(allowed_regs[k1]) + len(allowed_fpr[k1]) + len(allowed_sextw[k1]) + len(forbidden_simple[k1]) == len(allowed_conv.values))
|
||||
assert(all(c not in allowed_regs[k1] for c in allowed_simply[k1]))
|
||||
assert(all(c not in allowed_simply[k1] + allowed_regs[k1] for c in allowed_fpr[k1]))
|
||||
assert(all(c not in allowed_simply[k1] + allowed_regs[k1] + allowed_fpr[k1] for c in forbidden_simple[k1]))
|
||||
assert(all(c in allowed_simply[k1] + allowed_regs[k1] + allowed_fpr[k1] + forbidden_simple[k1] for c in allowed_conv.values))
|
||||
assert(all(c in allowed_simply[k1] + allowed_regs[k1] + allowed_fpr[k1] + allowed_sextw[k1] + forbidden_simple[k1] for c in allowed_conv.values))
|
||||
assert(all(c in allowed_conv.values for c in return_x87))
|
||||
assert(all(c in forbidden_simple[k] for c in depends_on_ld for k in forbidden_simple))
|
||||
|
||||
@@ -872,6 +873,7 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
for k in forbidden_simple:
|
||||
regs_count: int = 0
|
||||
fpr_count : int = 0
|
||||
sextw_mask: int = 0
|
||||
|
||||
if v.get_convention() is not allowed_conv:
|
||||
continue
|
||||
@@ -884,6 +886,9 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
fpr_count = fpr_count + 1
|
||||
elif c in allowed_simply[k]:
|
||||
continue
|
||||
elif c in allowed_sextw[k]:
|
||||
sextw_mask |= 1 << regs_count
|
||||
regs_count += 1
|
||||
else:
|
||||
break
|
||||
else:
|
||||
@@ -891,6 +896,7 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
if (regs_count <= 6) and (fpr_count <= 8):
|
||||
# All checks passed!
|
||||
ret_val = 1 + fpr_count
|
||||
ret_val |= sextw_mask << 4
|
||||
if v[0] in allowed_fpr[k]:
|
||||
ret_val = -ret_val
|
||||
ret[k] = ret_val
|
||||
@@ -1027,6 +1033,26 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
#ifndef __{filename}UNDEFS_H_
|
||||
#define __{filename}UNDEFS_H_
|
||||
|
||||
""",
|
||||
"x64printer.c": """
|
||||
#include <inttypes.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "x64emu.h"
|
||||
#include "x64emu_private.h"
|
||||
#include "wrapper.h"
|
||||
|
||||
#define PRIp "p"
|
||||
#define PRIf "f"
|
||||
#define PRILf "Lf"
|
||||
#define PRIs "s"
|
||||
|
||||
void x64Print(x64emu_t* emu, char* buff, size_t buffsz, const char* func, int tid, wrapper_t w)
|
||||
{lbr}
|
||||
#ifdef HAVE_TRACE
|
||||
if (0) {lbr}
|
||||
"""
|
||||
}
|
||||
files_guard = {
|
||||
@@ -1049,6 +1075,14 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
"fnundefs.h": """
|
||||
|
||||
#endif // __{filename}UNDEFS_H_
|
||||
""",
|
||||
"x64printer.c": """
|
||||
else
|
||||
#endif // HAVE_TRACE
|
||||
{lbr}
|
||||
snprintf(buff, buffsz, "%04d|%p: Calling %s(0x%lX, 0x%lX, 0x%lX, ...)", tid, *(void**)(R_RSP), func, R_RDI, R_RSI, R_RDX);
|
||||
{rbr}
|
||||
{rbr}
|
||||
"""
|
||||
}
|
||||
|
||||
@@ -1724,7 +1758,30 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
if k != str(Clauses()):
|
||||
file.write("#endif\n")
|
||||
file.write(files_guard["wrapper.h"].format(lbr="{", rbr="}", version=ver))
|
||||
|
||||
# E v c w i I C W u U f d D l L p V O S N H P A x X Y b
|
||||
formats_map = ["(error)", "(error)", "i8", "i16", "i32", "i64", "u8", "u16", "u32", "u64", "f", "f", "Lf", "i64", "u64", "p", "p", "(error)", "(error)", "(error)", "u64", "p", "p", "(error)", "(error)", "(error)", "(error)"]
|
||||
|
||||
# Rewrite the x64printer.c file:
|
||||
with open(os.path.join(root, "src", "emu", "x64printer.c"), 'w') as file:
|
||||
file.write(files_header["x64printer.c"].format(lbr="{", rbr="}", version=ver))
|
||||
|
||||
for k in gbls:
|
||||
if k != str(Clauses()):
|
||||
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'):
|
||||
continue
|
||||
formats = sig[2:].replace("G", "UU")
|
||||
params = '' if formats == "v" else ", " + function_args_systemV(FunctionType(formats))[:-2]
|
||||
formats = '' if formats == "v" else ', '.join("%\" PRI{x} \"".format(x=formats_map[FunctionType(sig).get_convention().values.index(t)]) for t in formats)
|
||||
file.write(" {rbr} else if (w == {signature}) {lbr}\n".format(signature=signature, lbr="{", rbr="}"))
|
||||
file.write(" snprintf(buff, buffsz, \"%04d|%p: Calling %s({formats})\", tid, *(void**)(R_RSP), func{params});\n".format(formats=formats, params=params))
|
||||
if k != str(Clauses()):
|
||||
file.write("#endif\n")
|
||||
file.write(" }\n")
|
||||
file.write(files_guard["x64printer.c"].format(lbr="{", rbr="}", version=ver))
|
||||
|
||||
# Rewrite the *types.h files:
|
||||
for k in conventions:
|
||||
td_types[k][conventions[k].values.index('A')] = "va_list"
|
||||
|
||||
+15
-7
@@ -583,8 +583,8 @@ class FileSpec:
|
||||
# CONSTANT- rvalues: valid replacement values (outside of structures)
|
||||
# CONSTANT- validrepl: valid replacement values (for structures)
|
||||
# structs: structure ids and additional data
|
||||
values: Sequence[str] = ['E', 'v', 'c', 'w', 'i', 'I', 'C', 'W', 'u', 'U', 'f', 'd', 'D', 'K', 'l', 'L', 'p', 'h', 'H', 'a', 'A', 'V', 'O', 'S', '2', 'P', 'N', 'M', 's', 'r', 'b', 'B', '_', 't', 'X']
|
||||
rvalues: Sequence[str] = ['E', 'v', 'c', 'w', 'i', 'I', 'C', 'W', 'u', 'U', 'f', 'd', 'D', 'K', 'l', 'L', 'p', 'h', 'H', 'a', 'A', 'V', 'O', 'S', '2', 'P', 'N', 'M', 's', 'r', 'b', 'B', '_', 't', 'X']
|
||||
values: Sequence[str] = ['E', 'v', 'c', 'w', 'i', 'I', 'C', 'W', 'u', 'U', 'f', 'd', 'D', 'K', 'l', 'L', 'p', 'h', 'H', 'a', 'A', 'V', 'O', 'S', '2', 'P', 'N', 'M', 's', 'r', 'b', 'B', '_', 't', 'X', 'n']
|
||||
rvalues: Sequence[str] = ['E', 'v', 'c', 'w', 'i', 'I', 'C', 'W', 'u', 'U', 'f', 'd', 'D', 'K', 'l', 'L', 'p', 'h', 'H', 'a', 'A', 'V', 'O', 'S', '2', 'P', 'N', 'M', 's', 'r', 'b', 'B', '_', 't', 'X', 'n']
|
||||
validrepl: Sequence[str] = ['c', 'w', 'i', 'I', 'C', 'W', 'u', 'U', 'f', 'd', 'D', 'K', 'l', 'L', 'p', 'h', 'H', 'a', 'A', 'V', 'O', 'S', '2', 'P', 'N', 'M', 's', 'r', 'b', 'B', '_']
|
||||
|
||||
def __init__(self) -> None:
|
||||
@@ -1150,7 +1150,8 @@ def generate_files(root: str, files: Iterable[str], ver: str, gbls: SortedGlobal
|
||||
"\n#error Invalid return type: wo structure declaration\n", # B
|
||||
"\n#error Invalid return type: end of structure declaration\n", # _
|
||||
"R_EAX = to_cstring(fn({0}));", # t
|
||||
"R_EAX = to_ptrv(addDisplay(fn({0})));", # X
|
||||
"R_EAX = to_ptrv(addDisplay(fn({0})));", # X
|
||||
"\n#error Invalid return type: xcb_connection_t*\n", # n
|
||||
]
|
||||
asargs = [
|
||||
"emu, ", # E
|
||||
@@ -1188,6 +1189,7 @@ def generate_files(root: str, files: Iterable[str], ver: str, gbls: SortedGlobal
|
||||
"\n#error Invalid argument type: end of structure declaration\n", # _
|
||||
"\n#error Invalid argument type: maybe-high string\n",# t
|
||||
"getDisplay(from_ptriv(R_ESP + {p})), ", # X
|
||||
"aligned_xcb, ", # n
|
||||
]
|
||||
if len(FileSpec.values) != len(asreturns):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(asreturns) = {lenvals}".format(lenval=len(FileSpec.values), lenvals=len(asreturns)))
|
||||
@@ -1201,6 +1203,9 @@ def generate_files(root: str, files: Iterable[str], ver: str, gbls: SortedGlobal
|
||||
CType[(value, CType.ReadWrite.none)].aspre = ""
|
||||
CType[(value, CType.ReadWrite.none)].asarg = asarg
|
||||
CType[(value, CType.ReadWrite.none)].aspost = ""
|
||||
if value == 'n':
|
||||
CType[(value, CType.ReadWrite.none)].aspre = f"void *aligned_xcb = align_xcb_connection32(from_ptriv(R_ESP + {{p}})); "
|
||||
CType[(value, CType.ReadWrite.none)].aspost = f" unalign_xcb_connection32(aligned_xcb, from_ptriv(R_ESP + {{p}}));"
|
||||
for ctn in CType.getSingletons():
|
||||
CType[ctn].generate_converters()
|
||||
|
||||
@@ -1300,6 +1305,9 @@ def generate_files(root: str, files: Iterable[str], ver: str, gbls: SortedGlobal
|
||||
void* getDisplay(void*);
|
||||
void* addDisplay(void*);
|
||||
|
||||
void* align_xcb_connection32(void* src);
|
||||
void unalign_xcb_connection32(void* src, void* dst);
|
||||
|
||||
""",
|
||||
"wrapper32.h": """
|
||||
#ifndef __WRAPPER32_H_
|
||||
@@ -1405,8 +1413,8 @@ def generate_files(root: str, files: Iterable[str], ver: str, gbls: SortedGlobal
|
||||
files_guard[fhdr] = trim(files_guard[fhdr])
|
||||
|
||||
# Typedefs
|
||||
# E v c w i I C W u U f d D K l L p h H a A V O S 2 P N M s r b B _ t X
|
||||
tdtypes = ["x64emu_t*", "void", "int8_t", "int16_t", "int32_t", "int64_t", "uint8_t", "uint16_t", "uint32_t", "uint64_t", "float", "double", "long double", "double", "intptr_t", "uintptr_t", "void*", "uintptr_t", "uintptr_t", "void*", "void*", "void*", "int32_t", "void*", "_2uint_struct_t", "void*", "...", "...", "void*", "\n#error _\n", "\n#error _\n", "\n#error _\n", "\n#error _\n", "char*", "void*"]
|
||||
# E v c w i I C W u U f d D K l L p h H a A V O S 2 P N M s r b B _ t X n
|
||||
tdtypes = ["x64emu_t*", "void", "int8_t", "int16_t", "int32_t", "int64_t", "uint8_t", "uint16_t", "uint32_t", "uint64_t", "float", "double", "long double", "double", "intptr_t", "uintptr_t", "void*", "uintptr_t", "uintptr_t", "void*", "void*", "void*", "int32_t", "void*", "_2uint_struct_t", "void*", "...", "...", "void*", "\n#error _\n", "\n#error _\n", "\n#error _\n", "\n#error _\n", "char*", "void*", "void*"]
|
||||
if len(FileSpec.values) != len(tdtypes):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(tdtypes) = {lentypes}".format(lenval=len(FileSpec.values), lentypes=len(tdtypes)))
|
||||
def generate_typedefs(funs: Iterable[FunctionType], file):
|
||||
@@ -1431,8 +1439,8 @@ def generate_files(root: str, files: Iterable[str], ver: str, gbls: SortedGlobal
|
||||
for i in range(2, len(funtype.orig.replaced))) + ");\n")
|
||||
|
||||
# Wrappers
|
||||
# E v c w i I C W u U f d D K l L p h H a A V O S 2 P N M s r b B _ t X
|
||||
deltas = [0, 4, 4, 4, 4, 8, 4, 4, 4, 8, 4, 8, 12, 12, 4, 4, 4, 4, 4, 4, 4, 1, 4, 4, 8, 4, 0, 0, 0, 1, 1, 4, 1, 4, 4]
|
||||
# E v c w i I C W u U f d D K l L p h H a A V O S 2 P N M s r b B _ t X n
|
||||
deltas = [0, 4, 4, 4, 4, 8, 4, 4, 4, 8, 4, 8, 12, 12, 4, 4, 4, 4, 4, 4, 4, 1, 4, 4, 8, 4, 0, 0, 0, 1, 1, 4, 1, 4, 4, 4]
|
||||
# Asserts
|
||||
if len(FileSpec.values) != len(deltas):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(deltas) = {lendeltas}".format(lenval=len(FileSpec.values), lendeltas=len(deltas)))
|
||||
|
||||
+7
-7
@@ -147,11 +147,11 @@ ulong_t to_hash_d(uintptr_t p) {
|
||||
}
|
||||
|
||||
typedef struct struct_locale_s {
|
||||
void* p0[13];
|
||||
void* p0[13]; // struct __locale_data *
|
||||
void* p1; //const unsigned short int *__ctype_b;
|
||||
void* p2; //const int *__ctype_tolower;
|
||||
void* p3; //const int *__ctype_toupper;
|
||||
void* p4[13];
|
||||
void* p4[13]; //const char*
|
||||
} struct_locale_t;
|
||||
// not a real structure
|
||||
#define LOCALE_SIGN 0x54abcd845412LL
|
||||
@@ -180,7 +180,7 @@ void to_struct_locale(ptr_t d, const struct_locale_t *src) {
|
||||
dest->p0[i] = to_hashv(src->p0[i]);
|
||||
}
|
||||
for(int i=0; i<13; ++i) {
|
||||
dest->p4[i] = to_hashv(src->p4[i]);
|
||||
dest->p4[i] = to_cstring(src->p4[i]);
|
||||
}
|
||||
// copy the 3 ctype int (1st is short int, but int will do)
|
||||
memcpy(dest->type_b, src->p1-128*sizeof(short), 384*sizeof(short));
|
||||
@@ -194,9 +194,9 @@ void free_struct_locale(const struct_locale_t *src) {
|
||||
for(int i=0; i<13; ++i) {
|
||||
to_hash_d((uintptr_t)src->p0[i]);
|
||||
}
|
||||
for(int i=0; i<13; ++i) {
|
||||
/*for(int i=0; i<13; ++i) {
|
||||
to_hash_d((uintptr_t)src->p4[i]);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
// Convert from locale key to original 64bits value
|
||||
@@ -314,7 +314,7 @@ ptr_t to_cstring(char* p) {
|
||||
// create a new key, but need write lock!
|
||||
pthread_rwlock_unlock(&hash_lock);
|
||||
pthread_rwlock_wrlock(&hash_lock);
|
||||
ret = to_ptrv(box_strdup(p));
|
||||
ret = to_ptrv(box32_strdup(p));
|
||||
int r;
|
||||
k = kh_put(strings, const_strings, (char*)from_ptrv(ret), &r);
|
||||
kh_value(const_strings, k) = ret;
|
||||
@@ -335,7 +335,7 @@ ptr_t to_cstring_d(char* p) {
|
||||
} else {
|
||||
ret = kh_value(const_strings, k);
|
||||
kh_del(strings, const_strings, k);
|
||||
free(from_ptrv(ret));
|
||||
box32_free(from_ptrv(ret));
|
||||
}
|
||||
pthread_rwlock_unlock(&hash_lock);
|
||||
return ret;
|
||||
|
||||
+9
-11
@@ -19,7 +19,6 @@
|
||||
#include "wrapper.h"
|
||||
#include "x64emu.h"
|
||||
#include "signals.h"
|
||||
#include "rcfile.h"
|
||||
#include "gltools.h"
|
||||
#include "rbtree.h"
|
||||
#include "dynarec.h"
|
||||
@@ -49,7 +48,6 @@ void finiAllHelpers(box64context_t* context)
|
||||
static int finied = 0;
|
||||
if(finied)
|
||||
return;
|
||||
DeleteParams();
|
||||
fini_pthread_helper(context);
|
||||
fini_signal_helper();
|
||||
fini_bridge_helper();
|
||||
@@ -77,8 +75,8 @@ void free_tlsdatasize(void* p)
|
||||
if(!p)
|
||||
return;
|
||||
tlsdatasize_t *data = (tlsdatasize_t*)p;
|
||||
box_free(data->ptr);
|
||||
box_free(p);
|
||||
actual_free(data->ptr);
|
||||
actual_free(p);
|
||||
if(my_context)
|
||||
pthread_setspecific(my_context->tlskey, NULL);
|
||||
}
|
||||
@@ -181,8 +179,8 @@ static void atfork_child_box64context(void)
|
||||
|
||||
void freeCycleLog(box64context_t* ctx)
|
||||
{
|
||||
if(cycle_log) {
|
||||
for(int i=0; i<cycle_log; ++i) {
|
||||
if(BOX64ENV(rolling_log)) {
|
||||
for(int i=0; i<BOX64ENV(rolling_log); ++i) {
|
||||
box_free(ctx->log_call[i]);
|
||||
box_free(ctx->log_ret[i]);
|
||||
}
|
||||
@@ -194,10 +192,10 @@ void freeCycleLog(box64context_t* ctx)
|
||||
}
|
||||
void initCycleLog(box64context_t* context)
|
||||
{
|
||||
if(cycle_log) {
|
||||
context->log_call = (char**)box_calloc(cycle_log, sizeof(char*));
|
||||
context->log_ret = (char**)box_calloc(cycle_log, sizeof(char*));
|
||||
for(int i=0; i<cycle_log; ++i) {
|
||||
if(BOX64ENV(rolling_log)) {
|
||||
context->log_call = (char**)box_calloc(BOX64ENV(rolling_log), sizeof(char*));
|
||||
context->log_ret = (char**)box_calloc(BOX64ENV(rolling_log), sizeof(char*));
|
||||
for(int i=0; i<BOX64ENV(rolling_log); ++i) {
|
||||
context->log_call[i] = (char*)box_calloc(256, 1);
|
||||
context->log_ret[i] = (char*)box_calloc(128, 1);
|
||||
}
|
||||
@@ -303,7 +301,7 @@ void FreeBox64Context(box64context_t** context)
|
||||
if(--(*context)->forked >= 0)
|
||||
return;
|
||||
|
||||
box64context_t* ctx = *context; // local copy to do the cleanning
|
||||
box64context_t* ctx = *context; // local copy to do the cleaning
|
||||
|
||||
//clean_current_emuthread(); // cleaning main thread seems a bad idea
|
||||
if(ctx->local_maplib)
|
||||
|
||||
+1
-1
@@ -3,6 +3,6 @@
|
||||
|
||||
#define BOX64_MAJOR 0
|
||||
#define BOX64_MINOR 3
|
||||
#define BOX64_REVISION 2
|
||||
#define BOX64_REVISION 4
|
||||
|
||||
#endif //__BOX64_VERSION_H_
|
||||
+1
-1
@@ -9,7 +9,7 @@
|
||||
|
||||
void PrintBox64Version()
|
||||
{
|
||||
printf_log(LOG_NONE, "Box64%s%s v%d.%d.%d %s built on %s %s\n",
|
||||
printf_ftrace(1, "Box64%s%s v%d.%d.%d %s built on %s %s\n",
|
||||
#ifdef HAVE_TRACE
|
||||
" with trace",
|
||||
#else
|
||||
|
||||
@@ -1,6 +1,21 @@
|
||||
#include "box64version.h"
|
||||
#ifdef NOGIT
|
||||
#define GITREV "nogit"
|
||||
#else
|
||||
#include "git_head.h"
|
||||
#endif
|
||||
|
||||
#ifndef __BUILD_INFO_H__
|
||||
#define __BUILD_INFO_H__
|
||||
|
||||
void PrintBox64Version(void);
|
||||
|
||||
#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
|
||||
|
||||
#endif //__BUILD_INFO_H__
|
||||
+313
-1315
File diff suppressed because it is too large.
Load diff
+218
-114
@@ -7,6 +7,7 @@
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <syscall.h>
|
||||
#include <sys/personality.h>
|
||||
|
||||
#include "box64context.h"
|
||||
#include "elfloader.h"
|
||||
@@ -34,6 +35,7 @@
|
||||
|
||||
// init inside dynablocks.c
|
||||
static mmaplist_t *mmaplist = NULL;
|
||||
static rbtree_t *rbt_dynmem = NULL;
|
||||
static uint64_t jmptbl_allocated = 0, jmptbl_allocated1 = 0, jmptbl_allocated2 = 0, jmptbl_allocated3 = 0;
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
static uint64_t jmptbl_allocated4 = 0;
|
||||
@@ -85,6 +87,7 @@ typedef struct blocklist_s {
|
||||
static int n_blocks = 0; // number of blocks for custom malloc
|
||||
static int c_blocks = 0; // capacity of blocks for custom malloc
|
||||
static blocklist_t* p_blocks = NULL; // actual blocks for custom malloc
|
||||
static int setting_prot = 0;
|
||||
|
||||
typedef union mark_s {
|
||||
struct {
|
||||
@@ -317,6 +320,16 @@ static size_t sizeBlock(void* sub)
|
||||
return SIZE_BLOCK(s->next);
|
||||
}
|
||||
|
||||
static int isBlockChainCoherent(blockmark_t* m, blockmark_t* end)
|
||||
{
|
||||
while(m) {
|
||||
if(m>end) return 0;
|
||||
if(m==end) return 1;
|
||||
m = NEXT_BLOCK(m);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// return 1 if block is coherent, 0 if not (and printf the issues)
|
||||
int printBlockCoherent(int i)
|
||||
{
|
||||
@@ -327,6 +340,8 @@ int printBlockCoherent(int i)
|
||||
int ret = 1;
|
||||
blockmark_t* m = (blockmark_t*)p_blocks[i].block;
|
||||
if(!m) {printf_log(LOG_NONE, "Warning, block #%d is NULL\n", i); return 0;}
|
||||
// check coherency of the chained list first
|
||||
if(!isBlockChainCoherent(m, (blockmark_t*)(p_blocks[i].block+p_blocks[i].size-sizeof(blockmark_t)))) {printf_log(LOG_NONE, "Warning, block #%d chained list is not coherent\n", i); return 0;}
|
||||
// check if first is correct
|
||||
blockmark_t* first = getNextFreeBlock(m);
|
||||
if(p_blocks[i].first && p_blocks[i].first!=first) {printf_log(LOG_NONE, "First %p and stored first %p differs for block %d\n", first, p_blocks[i].first, i); ret = 0;}
|
||||
@@ -486,17 +501,18 @@ void* internal_customMalloc(size_t size, int is32bits)
|
||||
// add a new block
|
||||
int i = n_blocks++;
|
||||
if(n_blocks>c_blocks) {
|
||||
c_blocks += 4;
|
||||
c_blocks += box64_is32bits?8:256;
|
||||
p_blocks = (blocklist_t*)box_realloc(p_blocks, c_blocks*sizeof(blocklist_t));
|
||||
}
|
||||
size_t allocsize = (fullsize>MMAPSIZE)?fullsize:MMAPSIZE;
|
||||
allocsize = (allocsize+box64_pagesize-1)&~(box64_pagesize-1);
|
||||
p_blocks[i].block = NULL; // incase there is a re-entrance
|
||||
p_blocks[i].first = NULL;
|
||||
p_blocks[i].size = 0;
|
||||
if(is32bits) // unlocking, because mmap might use it
|
||||
mutex_unlock(&mutex_blocks);
|
||||
void* p = is32bits
|
||||
?mmap(NULL, allocsize, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE|MAP_32BIT, -1, 0)
|
||||
?box_mmap(NULL, allocsize, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE|MAP_32BIT, -1, 0)
|
||||
:internal_mmap(NULL, allocsize, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
|
||||
if(is32bits)
|
||||
mutex_lock(&mutex_blocks);
|
||||
@@ -521,11 +537,13 @@ void* internal_customMalloc(size_t size, int is32bits)
|
||||
if(blockstree)
|
||||
rb_set(blockstree, (uintptr_t)p, (uintptr_t)p+allocsize, i);
|
||||
if(mapallmem) {
|
||||
// defer the setProtection...
|
||||
//setProtection((uintptr_t)p, allocsize, PROT_READ | PROT_WRITE);
|
||||
defered_prot_p = (uintptr_t)p;
|
||||
defered_prot_sz = allocsize;
|
||||
defered_prot_prot = PROT_READ|PROT_WRITE;
|
||||
if(setting_prot) {
|
||||
// defer the setProtection...
|
||||
defered_prot_p = (uintptr_t)p;
|
||||
defered_prot_sz = allocsize;
|
||||
defered_prot_prot = PROT_READ|PROT_WRITE;
|
||||
} else
|
||||
setProtection((uintptr_t)p, allocsize, PROT_READ | PROT_WRITE);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -601,7 +619,7 @@ void* customRealloc32(void* p, size_t size)
|
||||
|
||||
void internal_customFree(void* p, int is32bits)
|
||||
{
|
||||
if(!p) {
|
||||
if(!p || !inited) {
|
||||
return;
|
||||
}
|
||||
uintptr_t addr = (uintptr_t)p;
|
||||
@@ -777,8 +795,12 @@ size_t customGetUsableSize(void* p)
|
||||
|
||||
#ifdef DYNAREC
|
||||
#define NCHUNK 64
|
||||
typedef struct mapchunk_s {
|
||||
blocklist_t chunk;
|
||||
rbtree_t* tree;
|
||||
} mapchunk_t;
|
||||
typedef struct mmaplist_s {
|
||||
blocklist_t chunks[NCHUNK];
|
||||
mapchunk_t chunks[NCHUNK];
|
||||
mmaplist_t* next;
|
||||
} mmaplist_t;
|
||||
|
||||
@@ -789,30 +811,10 @@ dynablock_t* FindDynablockFromNativeAddress(void* p)
|
||||
|
||||
uintptr_t addr = (uintptr_t)p;
|
||||
|
||||
int i= 0;
|
||||
mmaplist_t* list = mmaplist;
|
||||
if(!list)
|
||||
return NULL;
|
||||
while(list) {
|
||||
if ((addr>(uintptr_t)list->chunks[i].block)
|
||||
&& (addr<((uintptr_t)list->chunks[i].block+list->chunks[i].size))) {
|
||||
blockmark_t* sub = (blockmark_t*)list->chunks[i].block;
|
||||
while((uintptr_t)sub<addr) {
|
||||
blockmark_t* n = NEXT_BLOCK(sub);
|
||||
if((uintptr_t)n>addr) {
|
||||
// found it!
|
||||
// self is the field of a block
|
||||
return *(dynablock_t**)((uintptr_t)sub+sizeof(blockmark_t));
|
||||
}
|
||||
sub = n;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
++i;
|
||||
if(i==NCHUNK) {
|
||||
i = 0;
|
||||
list = list->next;
|
||||
}
|
||||
mapchunk_t* bl = (mapchunk_t*)rb_get_64(rbt_dynmem, (uintptr_t)p);
|
||||
if(bl) {
|
||||
dynablock_t** ret = (dynablock_t**)rb_get_64(bl->tree, (uintptr_t)p);
|
||||
if(ret) return *ret;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@@ -821,6 +823,7 @@ dynablock_t* FindDynablockFromNativeAddress(void* p)
|
||||
void* box32_dynarec_mmap(size_t size)
|
||||
{
|
||||
// find a block that was prereserve before and big enough
|
||||
size = (size+box64_pagesize-1)&~(box64_pagesize-1);
|
||||
uint32_t flag;
|
||||
static uintptr_t cur = 0x100000000LL;
|
||||
uintptr_t bend = 0;
|
||||
@@ -859,19 +862,20 @@ uintptr_t AllocDynarecMap(size_t size)
|
||||
int i = 0;
|
||||
uintptr_t sz = size + 2*sizeof(blockmark_t);
|
||||
while(1) {
|
||||
if(list->chunks[i].maxfree>=size) {
|
||||
if(list->chunks[i].chunk.maxfree>=size) {
|
||||
// looks free, try to alloc!
|
||||
size_t rsize = 0;
|
||||
void* sub = getFirstBlock(list->chunks[i].block, size, &rsize, list->chunks[i].first);
|
||||
void* sub = getFirstBlock(list->chunks[i].chunk.block, size, &rsize, list->chunks[i].chunk.first);
|
||||
if(sub) {
|
||||
void* ret = allocBlock(list->chunks[i].block, sub, size, &list->chunks[i].first);
|
||||
if(rsize==list->chunks[i].maxfree)
|
||||
list->chunks[i].maxfree = getMaxFreeBlock(list->chunks[i].block, list->chunks[i].size, list->chunks[i].first);
|
||||
void* ret = allocBlock(list->chunks[i].chunk.block, sub, size, &list->chunks[i].chunk.first);
|
||||
if(rsize==list->chunks[i].chunk.maxfree)
|
||||
list->chunks[i].chunk.maxfree = getMaxFreeBlock(list->chunks[i].chunk.block, list->chunks[i].chunk.size, list->chunks[i].chunk.first);
|
||||
rb_set_64(list->chunks[i].tree, (uintptr_t)ret, (uintptr_t)ret+size, (uintptr_t)ret);
|
||||
return (uintptr_t)ret;
|
||||
}
|
||||
}
|
||||
// check if new
|
||||
if(!list->chunks[i].size) {
|
||||
if(!list->chunks[i].chunk.size) {
|
||||
// alloc a new block, aversized or not, we are at the end of the list
|
||||
size_t allocsize = (sz>DYNMMAPSZ)?sz:DYNMMAPSZ;
|
||||
// allign sz with pagesize
|
||||
@@ -905,9 +909,11 @@ uintptr_t AllocDynarecMap(size_t size)
|
||||
#endif
|
||||
setProtection((uintptr_t)p, allocsize, PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||
|
||||
list->chunks[i].block = p;
|
||||
list->chunks[i].first = p;
|
||||
list->chunks[i].size = allocsize;
|
||||
list->chunks[i].chunk.block = p;
|
||||
list->chunks[i].chunk.first = p;
|
||||
list->chunks[i].chunk.size = allocsize;
|
||||
list->chunks[i].tree = rbtree_init("dynamap");
|
||||
rb_set_64(rbt_dynmem, (uintptr_t)p, (uintptr_t)p+allocsize, (uintptr_t)&list->chunks[i]);
|
||||
// setup marks
|
||||
blockmark_t* m = (blockmark_t*)p;
|
||||
m->prev.x32 = 0;
|
||||
@@ -917,10 +923,11 @@ uintptr_t AllocDynarecMap(size_t size)
|
||||
n->next.x32 = 0;
|
||||
n->prev.x32 = m->next.x32;
|
||||
// alloc 1st block
|
||||
void* ret = allocBlock(list->chunks[i].block, p, size, &list->chunks[i].first);
|
||||
list->chunks[i].maxfree = getMaxFreeBlock(list->chunks[i].block, list->chunks[i].size, list->chunks[i].first);
|
||||
if(list->chunks[i].maxfree)
|
||||
list->chunks[i].first = getNextFreeBlock(m);
|
||||
void* ret = allocBlock(list->chunks[i].chunk.block, p, size, &list->chunks[i].chunk.first);
|
||||
list->chunks[i].chunk.maxfree = getMaxFreeBlock(list->chunks[i].chunk.block, list->chunks[i].chunk.size, list->chunks[i].chunk.first);
|
||||
if(list->chunks[i].chunk.maxfree)
|
||||
list->chunks[i].chunk.first = getNextFreeBlock(m);
|
||||
rb_set_64(list->chunks[i].tree, (uintptr_t)ret, (uintptr_t)ret+size, (uintptr_t)ret);
|
||||
return (uintptr_t)ret;
|
||||
}
|
||||
// next chunk...
|
||||
@@ -939,23 +946,16 @@ void FreeDynarecMap(uintptr_t addr)
|
||||
if(!addr)
|
||||
return;
|
||||
|
||||
int i= 0;
|
||||
mmaplist_t* list = mmaplist;
|
||||
|
||||
while(list) {
|
||||
if ((addr>(uintptr_t)list->chunks[i].block)
|
||||
&& (addr<((uintptr_t)list->chunks[i].block+list->chunks[i].size))) {
|
||||
void* sub = (void*)(addr-sizeof(blockmark_t));
|
||||
size_t newfree = freeBlock(list->chunks[i].block, list->chunks[i].size, sub, &list->chunks[i].first);
|
||||
if(list->chunks[i].maxfree < newfree)
|
||||
list->chunks[i].maxfree = newfree;
|
||||
return;
|
||||
}
|
||||
++i;
|
||||
if(i==NCHUNK) {
|
||||
i = 0;
|
||||
list = list->next;
|
||||
}
|
||||
mapchunk_t* bl = (mapchunk_t*)rb_get_64(rbt_dynmem, addr);
|
||||
|
||||
if(bl) {
|
||||
void* sub = (void*)(addr-sizeof(blockmark_t));
|
||||
size_t newfree = freeBlock(bl->chunk.block, bl->chunk.size, sub, &bl->chunk.first);
|
||||
if(bl->chunk.maxfree < newfree)
|
||||
bl->chunk.maxfree = newfree;
|
||||
rb_unset(bl->tree, addr, addr+newfree);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1020,42 +1020,27 @@ void addDBFromAddressRange(uintptr_t addr, size_t size)
|
||||
}
|
||||
}
|
||||
|
||||
void cleanDBFromAddressRange(uintptr_t addr, size_t size, int destroy)
|
||||
// Will return 1 if at least 1 db in the address range
|
||||
int cleanDBFromAddressRange(uintptr_t addr, size_t size, int destroy)
|
||||
{
|
||||
uintptr_t start_addr = my_context?((addr<my_context->max_db_size)?0:(addr-my_context->max_db_size)):addr;
|
||||
dynarec_log(LOG_DEBUG, "cleanDBFromAddressRange %p/%p -> %p %s\n", (void*)addr, (void*)start_addr, (void*)(addr+size-1), destroy?"destroy":"mark");
|
||||
dynablock_t* db = NULL;
|
||||
uintptr_t end = addr+size;
|
||||
int ret = 0;
|
||||
while (start_addr<end) {
|
||||
start_addr = getDBSize(start_addr, end-start_addr, &db);
|
||||
if(db) {
|
||||
ret = 1;
|
||||
if(destroy)
|
||||
FreeRangeDynablock(db, addr, size);
|
||||
else
|
||||
MarkRangeDynablock(db, addr, size);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Will return 1 if at least 1 db in the address range
|
||||
int isDBFromAddressRange(uintptr_t addr, size_t size)
|
||||
{
|
||||
uintptr_t start_addr = my_context?((addr<my_context->max_db_size)?0:(addr-my_context->max_db_size)):addr;
|
||||
dynarec_log(LOG_DEBUG, "isDBFromAddressRange %p/%p -> %p => ", (void*)addr, (void*)start_addr, (void*)(addr+size-1));
|
||||
dynablock_t* db = NULL;
|
||||
uintptr_t end = addr+size;
|
||||
while (start_addr<end) {
|
||||
start_addr = getDBSize(start_addr, end-start_addr, &db);
|
||||
if(db) {
|
||||
dynarec_log(LOG_DEBUG, "1\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
dynarec_log(LOG_DEBUG, "0\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
static uintptr_t *create_jmptbl(uintptr_t idx0, uintptr_t idx1, uintptr_t idx2, uintptr_t idx3, uintptr_t idx4)
|
||||
{
|
||||
@@ -1472,7 +1457,7 @@ int isprotectedDB(uintptr_t addr, size_t size)
|
||||
uint32_t prot;
|
||||
uintptr_t bend;
|
||||
if (!rb_get_end(memprot, addr, &prot, &bend) || !(prot&PROT_DYN)) {
|
||||
dynarec_log(LOG_DEBUG, "0\n");
|
||||
dynarec_log_prefix(0, LOG_DEBUG, "0\n");
|
||||
UNLOCK_PROT_READ();
|
||||
return 0;
|
||||
} else {
|
||||
@@ -1480,24 +1465,42 @@ int isprotectedDB(uintptr_t addr, size_t size)
|
||||
}
|
||||
}
|
||||
UNLOCK_PROT_READ();
|
||||
dynarec_log(LOG_DEBUG, "1\n");
|
||||
dynarec_log_prefix(0, LOG_DEBUG, "1\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
uintptr_t hotpage = 0;
|
||||
int hotpage_cnt = 0;
|
||||
static uintptr_t hotpage = 0;
|
||||
static int hotpage_cnt = 0;
|
||||
static int repeated_count = 0;
|
||||
static uintptr_t repeated_page = 0;
|
||||
#define HOTPAGE_MARK 64
|
||||
#define HOTPAGE_DIRTY 2
|
||||
void SetHotPage(uintptr_t addr)
|
||||
{
|
||||
hotpage = addr&~(box64_pagesize-1);
|
||||
hotpage_cnt = HOTPAGE_MARK;
|
||||
hotpage_cnt = BOX64ENV(dynarec_dirty)?HOTPAGE_DIRTY:HOTPAGE_MARK;
|
||||
}
|
||||
void CheckHotPage(uintptr_t addr)
|
||||
{
|
||||
uintptr_t page = (uintptr_t)addr&~(box64_pagesize-1);
|
||||
if(repeated_count==1 && repeated_page==page) {
|
||||
dynarec_log(LOG_DEBUG, "Detecting a Hotpage at %p (%d)\n", (void*)repeated_page, repeated_count);
|
||||
SetHotPage(repeated_page);
|
||||
repeated_count = 0;
|
||||
repeated_page = 0;
|
||||
} else {
|
||||
repeated_count = 1;
|
||||
repeated_page = page;
|
||||
}
|
||||
}
|
||||
int isInHotPage(uintptr_t addr)
|
||||
{
|
||||
if(!hotpage_cnt)
|
||||
return 0;
|
||||
--hotpage_cnt;
|
||||
return (addr>=hotpage) && (addr<hotpage+box64_pagesize);
|
||||
int ret = (addr>=hotpage) && (addr<hotpage+box64_pagesize);
|
||||
if(ret)
|
||||
--hotpage_cnt;
|
||||
return ret;
|
||||
}
|
||||
int checkInHotPage(uintptr_t addr)
|
||||
{
|
||||
@@ -1520,7 +1523,8 @@ void updateProtection(uintptr_t addr, size_t size, uint32_t prot)
|
||||
rb_get_end(memprot, cur, &oprot, &bend);
|
||||
if(bend>end) bend = end;
|
||||
uint32_t dyn=(oprot&PROT_DYN);
|
||||
if(!(dyn&PROT_NEVERPROT)) {
|
||||
uint32_t never = dyn&PROT_NEVERPROT;
|
||||
if(!(never)) {
|
||||
if(dyn && (prot&PROT_WRITE)) { // need to remove the write protection from this block
|
||||
dyn = PROT_DYNAREC;
|
||||
int ret = mprotect((void*)cur, bend-cur, prot&~PROT_WRITE);
|
||||
@@ -1529,7 +1533,7 @@ void updateProtection(uintptr_t addr, size_t size, uint32_t prot)
|
||||
dyn = PROT_DYNAREC_R;
|
||||
}
|
||||
}
|
||||
uint32_t new_prot = prot?(prot|dyn):prot;
|
||||
uint32_t new_prot = prot?(prot|dyn):(prot|never);
|
||||
if (new_prot != oprot)
|
||||
rb_set(memprot, cur, bend, new_prot);
|
||||
cur = bend;
|
||||
@@ -1541,10 +1545,12 @@ void setProtection(uintptr_t addr, size_t size, uint32_t prot)
|
||||
{
|
||||
size = ALIGN(size);
|
||||
LOCK_PROT();
|
||||
++setting_prot;
|
||||
uintptr_t cur = addr & ~(box64_pagesize-1);
|
||||
uintptr_t end = ALIGN(cur+size);
|
||||
rb_set(mapallmem, cur, end, 1);
|
||||
rb_set(memprot, cur, end, prot);
|
||||
--setting_prot;
|
||||
UNLOCK_PROT();
|
||||
}
|
||||
|
||||
@@ -1597,11 +1603,19 @@ void allocProtection(uintptr_t addr, size_t size, uint32_t prot)
|
||||
size = ALIGN(size);
|
||||
addr &= ~(box64_pagesize-1);
|
||||
LOCK_PROT();
|
||||
rb_set(mapallmem, addr, addr+size, 1);
|
||||
uint32_t val;
|
||||
uintptr_t endb;
|
||||
int there = rb_get_end(mapallmem, addr, &val, &endb);
|
||||
// block is here or absent, no half-block handled..
|
||||
if(!there)
|
||||
rb_set(mapallmem, addr, addr+size, 1);
|
||||
UNLOCK_PROT();
|
||||
// don't need to add precise tracking probably
|
||||
}
|
||||
|
||||
uintptr_t pbrk = 0;
|
||||
uintptr_t old_brk = 0;
|
||||
uintptr_t* cur_brk = NULL;
|
||||
void loadProtectionFromMap()
|
||||
{
|
||||
if(box64_mapclean)
|
||||
@@ -1618,6 +1632,8 @@ void loadProtectionFromMap()
|
||||
if(sscanf(buf, "%lx-%lx %c%c%c", &s, &e, &r, &w, &x)==5) {
|
||||
int prot = ((r=='r')?PROT_READ:0)|((w=='w')?PROT_WRITE:0)|((x=='x')?PROT_EXEC:0);
|
||||
allocProtection(s, e-s, prot);
|
||||
if(!pbrk && strstr(buf, "[heap]"))
|
||||
pbrk = s;
|
||||
if(s>0x7fff00000000LL)
|
||||
have48bits = 1;
|
||||
}
|
||||
@@ -1626,9 +1642,13 @@ void loadProtectionFromMap()
|
||||
if(!shown48bits) {
|
||||
shown48bits = 1;
|
||||
if(have48bits)
|
||||
printf_log(LOG_INFO, "BOX64: Detected 48bits at least of address space\n");
|
||||
printf_log(LOG_INFO, "Detected 48bits at least of address space\n");
|
||||
else
|
||||
printf_log(LOG_INFO, "BOX64: Didn't detect 48bits of address space, considering it's 39bits\n");
|
||||
printf_log(LOG_INFO, "Didn't detect 48bits of address space, considering it's 39bits\n");
|
||||
}
|
||||
if(!pbrk) {
|
||||
printf_log(LOG_INFO, "Warning, program break not found\n");
|
||||
if(cur_brk) pbrk = *cur_brk; // approximate is better than nothing
|
||||
}
|
||||
fclose(f);
|
||||
box64_mapclean = 1;
|
||||
@@ -1679,6 +1699,11 @@ int memExist(uintptr_t addr)
|
||||
|
||||
void* find31bitBlockNearHint(void* hint_, size_t size, uintptr_t mask)
|
||||
{
|
||||
// first, check if program break as changed
|
||||
if(pbrk && cur_brk && *cur_brk!=old_brk) {
|
||||
old_brk = *cur_brk;
|
||||
setProtection(pbrk, old_brk-pbrk, PROT_READ|PROT_WRITE);
|
||||
}
|
||||
uint32_t prot;
|
||||
uintptr_t hint = (uintptr_t)hint_;
|
||||
if(hint_<LOWEST) hint = (uintptr_t)WINE_LOWEST;
|
||||
@@ -1728,6 +1753,11 @@ void* find47bitBlock(size_t size)
|
||||
}
|
||||
void* find47bitBlockNearHint(void* hint, size_t size, uintptr_t mask)
|
||||
{
|
||||
// first, check if program break as changed
|
||||
if(pbrk && cur_brk && *cur_brk!=old_brk) {
|
||||
old_brk = *cur_brk;
|
||||
setProtection(pbrk, old_brk-pbrk, PROT_READ|PROT_WRITE);
|
||||
}
|
||||
uint32_t prot;
|
||||
if(hint<LOWEST) hint = LOWEST;
|
||||
uintptr_t bend = 0;
|
||||
@@ -1859,7 +1889,7 @@ void reverveHigMem32(void)
|
||||
// printf_log(LOG_DEBUG, " Failed to reserve %zx sized block\n", cur_size);
|
||||
cur_size>>=1;
|
||||
} else {
|
||||
rb_set(mapallmem, (uintptr_t)cur, (uintptr_t)cur+cur_size, 1);
|
||||
rb_set(mapallmem, (uintptr_t)cur, (uintptr_t)cur+cur_size, 2);
|
||||
//printf_log(LOG_DEBUG, "Reserved high %p (%zx)\n", cur, cur_size);
|
||||
}
|
||||
}
|
||||
@@ -1893,7 +1923,7 @@ void reverveHigMem32(void)
|
||||
}
|
||||
}
|
||||
printf_log(LOG_INFO, "Memory higher than 32bits reserved\n");
|
||||
if(box64_log>=LOG_DEBUG) {
|
||||
if (BOX64ENV(log)>=LOG_DEBUG) {
|
||||
uintptr_t start=0x100000000LL;
|
||||
int prot;
|
||||
uintptr_t bend;
|
||||
@@ -1904,6 +1934,7 @@ void reverveHigMem32(void)
|
||||
start = bend;
|
||||
}
|
||||
}
|
||||
personality(ADDR_LIMIT_32BIT);
|
||||
}
|
||||
#endif
|
||||
void my_reserveHighMem()
|
||||
@@ -1915,6 +1946,20 @@ void my_reserveHighMem()
|
||||
#ifdef BOX32
|
||||
if(box64_is32bits) {
|
||||
reverveHigMem32();
|
||||
// now reserve some memory in low address (because wine tend to allocate everything for itself)
|
||||
void* p[20];
|
||||
#define SZ 2*1024*1024
|
||||
size_t n = sizeof(p)/sizeof(p[0]);
|
||||
for(size_t i=0; i<n; ++i)
|
||||
p[i] = box32_malloc(SZ-128);
|
||||
if (BOX64ENV(log)>=LOG_DEBUG) {
|
||||
printf_log(LOG_DEBUG, "Reserved %u MB of low memory [", (SZ)*n);
|
||||
for(size_t i=0; i<n; ++i)
|
||||
printf_log(LOG_DEBUG, "%p%s", p[i], (i==(n-1))?"]\n":", ");
|
||||
}
|
||||
for(size_t i=0; i<n; ++i)
|
||||
box32_free(p[i]);
|
||||
#undef SZ
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
@@ -1945,14 +1990,8 @@ void my_reserveHighMem()
|
||||
|
||||
void reserveHighMem()
|
||||
{
|
||||
char* p = getenv("BOX64_RESERVE_HIGH");
|
||||
if(!box64_is32bits)
|
||||
#if 0//def ADLINK
|
||||
if(p && p[0]=='0')
|
||||
#else
|
||||
if(!p || p[0]=='0')
|
||||
#endif
|
||||
return; // don't reserve by default
|
||||
if(!box64_is32bits && !BOX64ENV(reserve_high))
|
||||
return; // don't reserve by default on 64bits
|
||||
my_reserveHighMem();
|
||||
}
|
||||
|
||||
@@ -1962,6 +2001,7 @@ void init_custommem_helper(box64context_t* ctx)
|
||||
if(inited) // already initialized
|
||||
return;
|
||||
inited = 1;
|
||||
cur_brk = dlsym(RTLD_NEXT, "__curbrk");
|
||||
blockstree = rbtree_init("blockstree");
|
||||
// if there is some blocks already
|
||||
if(n_blocks)
|
||||
@@ -1971,7 +2011,7 @@ void init_custommem_helper(box64context_t* ctx)
|
||||
sigfillset(&critical_prot);
|
||||
init_mutexes();
|
||||
#ifdef DYNAREC
|
||||
if(box64_dynarec) {
|
||||
if(BOX64ENV(dynarec)) {
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
for(int i=0; i<(1<<JMPTABL_SHIFT4); ++i)
|
||||
box64_jmptbl4[i] = box64_jmptbldefault3;
|
||||
@@ -1989,6 +2029,7 @@ void init_custommem_helper(box64context_t* ctx)
|
||||
box64_jmptbldefault0[i] = (uintptr_t)native_next;
|
||||
}
|
||||
lockaddress = kh_init(lockaddress);
|
||||
rbt_dynmem = rbtree_init("rbt_dynmem");
|
||||
#endif
|
||||
pthread_atfork(NULL, NULL, atfork_child_custommem);
|
||||
// init mapallmem list
|
||||
@@ -2029,25 +2070,26 @@ void fini_custommem_helper(box64context_t *ctx)
|
||||
}
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
}
|
||||
if(box64_log) printf("Allocation:\n- dynarec: %lld kio\n- customMalloc: %lld kio\n- jump table: %lld kio (%lld level 4, %lld level 3, %lld level 2, %lld level 1 table allocated, for %lld jumps, with at most %lld per level 1)\n", dynarec_allocated / 1024, customMalloc_allocated / 1024, jmptbl_allocated / 1024, jmptbl_allocated4, jmptbl_allocated3, jmptbl_allocated2, jmptbl_allocated1, njmps, njmps_in_lv1_max);
|
||||
#else
|
||||
if(box64_log) printf("Allocation:\n- dynarec: %lld kio\n- customMalloc: %lld kio\n- jump table: %lld kio (%lld level 3, %lld level 2, %lld level 1 table allocated, for %lld jumps, with at most %lld per level 1)\n", dynarec_allocated / 1024, customMalloc_allocated / 1024, jmptbl_allocated / 1024, jmptbl_allocated3, jmptbl_allocated2, jmptbl_allocated1, njmps, njmps_in_lv1_max);
|
||||
#endif
|
||||
if(box64_log)
|
||||
testAllBlocks();
|
||||
if(BOX64ENV(log)) printf("Allocation:\n- dynarec: %lld kio\n- customMalloc: %lld kio\n- jump table: %lld kio (%lld level 4, %lld level 3, %lld level 2, %lld level 1 table allocated, for %lld jumps, with at most %lld per level 1)\n", dynarec_allocated / 1024, customMalloc_allocated / 1024, jmptbl_allocated / 1024, jmptbl_allocated4, jmptbl_allocated3, jmptbl_allocated2, jmptbl_allocated1, njmps, njmps_in_lv1_max);
|
||||
#else
|
||||
if(BOX64ENV(log)) printf("Allocation:\n- dynarec: %lld kio\n- customMalloc: %lld kio\n- jump table: %lld kio (%lld level 3, %lld level 2, %lld level 1 table allocated, for %lld jumps, with at most %lld per level 1)\n", dynarec_allocated / 1024, customMalloc_allocated / 1024, jmptbl_allocated / 1024, jmptbl_allocated3, jmptbl_allocated2, jmptbl_allocated1, njmps, njmps_in_lv1_max);
|
||||
#endif
|
||||
if(BOX64ENV(log)) testAllBlocks();
|
||||
#endif
|
||||
if(!inited)
|
||||
return;
|
||||
inited = 0;
|
||||
#ifdef DYNAREC
|
||||
if(box64_dynarec) {
|
||||
if(BOX64ENV(dynarec)) {
|
||||
dynarec_log(LOG_DEBUG, "Free global Dynarecblocks\n");
|
||||
mmaplist_t* head = mmaplist;
|
||||
mmaplist = NULL;
|
||||
while(head) {
|
||||
for (int i=0; i<NCHUNK; ++i) {
|
||||
if(head->chunks[i].block)
|
||||
internal_munmap(head->chunks[i].block, head->chunks[i].size);
|
||||
if(head->chunks[i].chunk.block)
|
||||
internal_munmap(head->chunks[i].chunk.block, head->chunks[i].chunk.size);
|
||||
if(head->chunks[i].tree)
|
||||
rbtree_delete(head->chunks[i].tree);
|
||||
}
|
||||
mmaplist_t *old = head;
|
||||
head = head->next;
|
||||
@@ -2080,6 +2122,8 @@ void fini_custommem_helper(box64context_t *ctx)
|
||||
}
|
||||
kh_destroy(lockaddress, lockaddress);
|
||||
lockaddress = NULL;
|
||||
rbtree_delete(rbt_dynmem);
|
||||
rbt_dynmem = NULL;
|
||||
#endif
|
||||
rbtree_delete(memprot);
|
||||
memprot = NULL;
|
||||
@@ -2146,3 +2190,63 @@ int internal_munmap(void* addr, unsigned long length)
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifndef MAP_FIXED_NOREPLACE
|
||||
#define MAP_FIXED_NOREPLACE 0x200000
|
||||
#endif
|
||||
#ifndef MAP_32BIT
|
||||
#define MAP_32BIT 0x40
|
||||
#endif
|
||||
EXPORT void* box_mmap(void *addr, size_t length, int prot, int flags, int fd, ssize_t offset)
|
||||
{
|
||||
if(prot&PROT_WRITE)
|
||||
prot|=PROT_READ; // PROT_READ is implicit with PROT_WRITE on i386
|
||||
int new_flags = flags;
|
||||
void* old_addr = addr;
|
||||
#ifndef NOALIGN
|
||||
new_flags&=~MAP_32BIT; // remove MAP_32BIT
|
||||
if((flags&MAP_32BIT) && !(flags&MAP_FIXED)) {
|
||||
// MAP_32BIT only exist on x86_64!
|
||||
addr = find31bitBlockNearHint(old_addr, length, 0);
|
||||
} else if (box64_wine || 1) { // other mmap should be restricted to 47bits
|
||||
if (!(flags&MAP_FIXED) && !addr)
|
||||
addr = find47bitBlock(length);
|
||||
}
|
||||
#endif
|
||||
void* ret = internal_mmap(addr, length, prot, new_flags, fd, offset);
|
||||
#if !defined(NOALIGN)
|
||||
if((ret!=MAP_FAILED) && (flags&MAP_32BIT) &&
|
||||
(((uintptr_t)ret>0xffffffffLL) || ((box64_wine) && ((uintptr_t)ret&0xffff) && (ret!=addr)))) {
|
||||
int olderr = errno;
|
||||
internal_munmap(ret, length);
|
||||
loadProtectionFromMap(); // reload map, because something went wrong previously
|
||||
addr = find31bitBlockNearHint(old_addr, length, 0); // is this the best way?
|
||||
new_flags = (addr && isBlockFree(addr, length) )? (new_flags|MAP_FIXED) : new_flags;
|
||||
if((new_flags&(MAP_FIXED|MAP_FIXED_NOREPLACE))==(MAP_FIXED|MAP_FIXED_NOREPLACE)) new_flags&=~MAP_FIXED_NOREPLACE;
|
||||
ret = internal_mmap(addr, length, prot, new_flags, fd, offset);
|
||||
if(old_addr && ret!=old_addr && ret!=MAP_FAILED)
|
||||
errno = olderr;
|
||||
} else if((ret!=MAP_FAILED) && !(flags&MAP_FIXED) && ((box64_wine)) && (addr && (addr!=ret)) &&
|
||||
(((uintptr_t)ret>0x7fffffffffffLL) || ((uintptr_t)ret&~0xffff))) {
|
||||
int olderr = errno;
|
||||
internal_munmap(ret, length);
|
||||
loadProtectionFromMap(); // reload map, because something went wrong previously
|
||||
addr = find47bitBlockNearHint(old_addr, length, 0); // is this the best way?
|
||||
new_flags = (addr && isBlockFree(addr, length)) ? (new_flags|MAP_FIXED) : new_flags;
|
||||
if((new_flags&(MAP_FIXED|MAP_FIXED_NOREPLACE))==(MAP_FIXED|MAP_FIXED_NOREPLACE)) new_flags&=~MAP_FIXED_NOREPLACE;
|
||||
ret = internal_mmap(addr, length, prot, new_flags, fd, offset);
|
||||
if(old_addr && ret!=old_addr && ret!=MAP_FAILED) {
|
||||
errno = olderr;
|
||||
if(old_addr>(void*)0x7fffffffff && !have48bits)
|
||||
errno = EEXIST;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
EXPORT int box_munmap(void* addr, size_t length)
|
||||
{
|
||||
int ret = internal_munmap(addr, length);
|
||||
return ret;
|
||||
}
|
||||
+6
-3
@@ -2,6 +2,8 @@
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "env.h"
|
||||
|
||||
#ifndef MAP_FAILED
|
||||
#define MAP_FAILED ((void *) -1)
|
||||
#endif
|
||||
@@ -24,17 +26,18 @@ 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* 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);
|
||||
|
||||
extern int running32bits;
|
||||
extern int box64_mmap32;
|
||||
extern box64env_t box64env;
|
||||
|
||||
EXPORT void* mmap64(void *addr, unsigned long length, int prot, int flags, int fd, ssize_t offset)
|
||||
{
|
||||
void* ret;
|
||||
if(!addr && ((running32bits && box64_mmap32) || (flags&MAP_32BIT) || box64_is32bits))
|
||||
ret = my_mmap64(NULL, addr, length, prot, flags | MAP_32BIT, fd, offset);
|
||||
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);
|
||||
if(ret!=MAP_FAILED && mapallmem)
|
||||
|
||||
@@ -144,6 +144,9 @@ p0-p3 are used to pass scalable predicate arguments to a subroutine and to retur
|
||||
// always
|
||||
#define c__ 0b1110
|
||||
|
||||
//FCMP type of opcode produce:
|
||||
// if any NAN: CV / v1 == v2: ZC / v1 < v2: N / v1 > v2: C
|
||||
|
||||
int convert_bitmask(uint64_t bitmask);
|
||||
#define convert_bitmask_w(A) convert_bitmask(((uint64_t)(A) << 32) + (uint32_t)(A))
|
||||
#define convert_bitmask_x(A) convert_bitmask((uint64_t)A)
|
||||
@@ -205,17 +208,26 @@ int convert_bitmask(uint64_t bitmask);
|
||||
|
||||
#define SUBx_REG(Rd, Rn, Rm) EMIT(ADDSUB_REG_gen(1, 1, 0, 0b00, Rm, 0, Rn, Rd))
|
||||
#define SUBSx_REG(Rd, Rn, Rm) FEMIT(ADDSUB_REG_gen(1, 1, 1, 0b00, Rm, 0, Rn, Rd))
|
||||
#define SUBSx_REG_ASR(Rd, Rn, Rm, asr) FEMIT(ADDSUB_REG_gen(1, 1, 1, 0b10, Rm, asr, Rn, Rd))
|
||||
#define SUBx_REG_LSL(Rd, Rn, Rm, lsl) EMIT(ADDSUB_REG_gen(1, 1, 0, 0b00, Rm, lsl, Rn, Rd))
|
||||
#define SUBw_REG(Rd, Rn, Rm) EMIT(ADDSUB_REG_gen(0, 1, 0, 0b00, Rm, 0, Rn, Rd))
|
||||
#define SUBw_REG_LSL(Rd, Rn, Rm, lsl) EMIT(ADDSUB_REG_gen(0, 1, 0, 0b00, Rm, lsl, Rn, Rd))
|
||||
#define SUBw_REG_ASR(Rd, Rn, Rm, asr) EMIT(ADDSUB_REG_gen(0, 1, 0, 0b10, Rm, asr, Rn, Rd))
|
||||
#define SUBSw_REG(Rd, Rn, Rm) FEMIT(ADDSUB_REG_gen(0, 1, 1, 0b00, Rm, 0, Rn, Rd))
|
||||
#define SUBSw_REG_LSL(Rd, Rn, Rm, lsl) FEMIT(ADDSUB_REG_gen(0, 1, 1, 0b00, Rm, lsl, Rn, Rd))
|
||||
#define SUBSw_REG_LSR(Rd, Rn, Rm, lsr) FEMIT(ADDSUB_REG_gen(0, 1, 1, 0b01, Rm, lsr, Rn, Rd))
|
||||
#define SUBSw_REG_ASR(Rd, Rn, Rm, asr) FEMIT(ADDSUB_REG_gen(0, 1, 1, 0b10, Rm, asr, Rn, Rd))
|
||||
#define SUBxw_REG(Rd, Rn, Rm) EMIT(ADDSUB_REG_gen(rex.w, 1, 0, 0b00, Rm, 0, Rn, Rd))
|
||||
#define SUBz_REG(Rd, Rn, Rm) EMIT(ADDSUB_REG_gen(rex.is32bits?0:1, 1, 0, 0b00, Rm, 0, Rn, Rd))
|
||||
#define SUBSxw_REG(Rd, Rn, Rm) FEMIT(ADDSUB_REG_gen(rex.w, 1, 1, 0b00, Rm, 0, Rn, Rd))
|
||||
#define SUBSxw_REG_ASR(Rd, Rn, Rm, asr) FEMIT(ADDSUB_REG_gen(rex.w, 1, 1, 0b10, Rm, asr, Rn, Rd))
|
||||
#define CMPSx_REG(Rn, Rm) SUBSx_REG(xZR, Rn, Rm)
|
||||
#define CMPSx_REG_ASR(Rn, Rm, asr) SUBSx_REG_ASR(xZR, Rn, Rm, asr)
|
||||
#define CMPSw_REG(Rn, Rm) SUBSw_REG(wZR, Rn, Rm)
|
||||
#define CMPSw_REG_LSR(Rn, Rm, lsr) SUBSw_REG_LSR(wZR, Rn, Rm, lsr)
|
||||
#define CMPSw_REG_ASR(Rn, Rm, asr) SUBSw_REG_ASR(wZR, Rn, Rm, asr)
|
||||
#define CMPSxw_REG(Rn, Rm) SUBSxw_REG(xZR, Rn, Rm)
|
||||
#define CMPSxw_REG_ASR(Rn, Rm, asr) SUBSxw_REG_ASR(xZR, Rn, Rm, asr)
|
||||
#define NEGx_REG(Rd, Rm) SUBx_REG(Rd, xZR, Rm);
|
||||
#define NEGw_REG(Rd, Rm) SUBw_REG(Rd, wZR, Rm);
|
||||
#define NEGxw_REG(Rd, Rm) SUBxw_REG(Rd, xZR, Rm);
|
||||
@@ -248,6 +260,10 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#define SBCSw_REG(Rd, Rn, Rm) FEMIT(ADDSUBC_gen(0, 1, 1, Rm, Rn, Rd))
|
||||
#define SBCSxw_REG(Rd, Rn, Rm) FEMIT(ADDSUBC_gen(rex.w, 1, 1, Rm, Rn, Rd))
|
||||
|
||||
#define SUB_ext(sf, op, S, Rm, option, imm3, Rn, Rd) ((sf)<<31 | (op)<<30 | (S)<<29 | 0b01011<<24 | 1<<21 | (Rm)<<16 | (option)<<13 | (imm3)<<10 | (Rn)<<5 | (Rd))
|
||||
#define SUBxw_UXTB(Rd, Rn, Rm) EMIT(SUB_ext(rex.w, 1, 0, Rm, 0b000, 0, Rn, Rd))
|
||||
#define SUBw_UXTB(Rd, Rn, Rm) EMIT(SUB_ext(0, 1, 0, Rm, 0b000, 0, Rn, Rd))
|
||||
|
||||
// CCMP compare if cond is true, set nzcv if false
|
||||
#define CCMP_reg(sf, Rm, cond, Rn, nzcv) ((sf)<<31 | 1<<30 | 1<<29 | 0b11010010<<21 | (Rm)<<16 | (cond)<<12 | (Rn)<<5 | (nzcv))
|
||||
#define CCMPw(Wn, Wm, nzcv, cond) FEMIT(CCMP_reg(0, Wm, cond, Wn, nzcv))
|
||||
@@ -290,18 +306,24 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#define LDRx_REG_LSL3(Rt, Rn, Rm) EMIT(LDR_REG_gen(0b11, Rm, 0b011, 1, Rn, Rt))
|
||||
#define LDRx_REG_UXTW3(Rt, Rn, Rm) EMIT(LDR_REG_gen(0b11, Rm, 0b010, 1, Rn, Rt))
|
||||
#define LDRx_REG_SXTW(Rt, Rn, Rm) EMIT(LDR_REG_gen(0b11, Rm, 0b110, 0, Rn, Rt))
|
||||
#define LDRx_REGz(Rt, Rn, Rm) EMIT(LDR_REG_gen(0b11, Rm, rex.is32bits?0b110:0b011, 0, Rn, Rt))
|
||||
#define LDRw_REG(Rt, Rn, Rm) EMIT(LDR_REG_gen(0b10, Rm, 0b011, 0, Rn, Rt))
|
||||
#define LDRw_REG_LSL2(Rt, Rn, Rm) EMIT(LDR_REG_gen(0b10, Rm, 0b011, 1, Rn, Rt))
|
||||
#define LDRw_REG_SXTW(Rt, Rn, Rm) EMIT(LDR_REG_gen(0b10, Rm, 0b110, 0, Rn, Rt))
|
||||
#define LDRw_REGz(Rt, Rn, Rm) EMIT(LDR_REG_gen(0b10, Rm, rex.is32bits?0b110:0b011, 0, Rn, Rt))
|
||||
#define LDRxw_REG(Rt, Rn, Rm) EMIT(LDR_REG_gen(0b10+rex.w, Rm, 0b011, 0, Rn, Rt))
|
||||
#define LDRz_REG(Rt, Rn, Rm) EMIT(LDR_REG_gen(rex.is32bits?0b10:0b11, Rm, 0b011, 0, Rn, Rt))
|
||||
#define LDRxw_REG_SXTW(Rt, Rn, Rm) EMIT(LDR_REG_gen(0b10+rex.w, Rm, 0b110, 0, Rn, Rt))
|
||||
#define LDRxw_REGz(Rt, Rn, Rm) EMIT(LDR_REG_gen(0b10+rex.w, Rm, rex.is32bits?0b110:0b011, 0, Rn, Rt))
|
||||
#define LDRz_REG_SXTW(Rt, Rn, Rm) EMIT(LDR_REG_gen(rex.is32bits?0b10:0b11, Rm, 0b110, 0, Rn, Rt))
|
||||
#define LDRz_REGz(Rt, Rn, Rm) EMIT(LDR_REG_gen(rex.is32bits?0b10:0b11, Rm, rex.is32bits?0b110:0b011, 0, Rn, Rt))
|
||||
#define LDRB_REG(Rt, Rn, Rm) EMIT(LDR_REG_gen(0b00, Rm, 0b011, 0, Rn, Rt))
|
||||
#define LDRB_REG_UXTW(Rt, Rn, Rm) EMIT(LDR_REG_gen(0b00, Rm, 0b010, 0, Rn, Rt))
|
||||
#define LDRB_REG_SXTW(Rt, Rn, Rm) EMIT(LDR_REG_gen(0b00, Rm, 0b110, 0, Rn, Rt))
|
||||
#define LDRB_REGz(Rt, Rn, Rm) EMIT(LDR_REG_gen(0b00, Rm, rex.is32bits?0b110:0b011, 0, Rn, Rt))
|
||||
#define LDRH_REG(Rt, Rn, Rm) EMIT(LDR_REG_gen(0b01, Rm, 0b011, 0, Rn, Rt))
|
||||
#define LDRH_REG_SXTW(Rt, Rn, Rm) EMIT(LDR_REG_gen(0b01, Rm, 0b110, 0, Rn, Rt))
|
||||
#define LDRH_REGz(Rt, Rn, Rm) EMIT(LDR_REG_gen(0b01, Rm, rex.is32bits?0b110:0b011, 0, Rn, Rt))
|
||||
|
||||
#define LDRS_U12_gen(size, op1, opc, imm12, Rn, Rt) ((size)<<30 | 0b111<<27 | (op1)<<24 | (opc)<<22 | (imm12)<<10 | (Rn)<<5 | (Rt))
|
||||
#define LDRSHx_U12(Rt, Rn, imm12) EMIT(LDRS_U12_gen(0b01, 0b01, 0b10, ((uint32_t)(imm12>>1))&0xfff, Rn, Rt))
|
||||
@@ -314,6 +336,7 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#define LDRS_REG_gen(size, Rm, option, S, Rn, Rt) ((size)<<30 | 0b111<<27 | 0b10<<22 | 1<<21 | (Rm)<<16 | (option)<<13 | (S)<<12 | (0b10)<<10 | (Rn)<<5 | (Rt))
|
||||
#define LDRSW_REG(Rt, Rn, Rm) EMIT(LDRS_REG_gen(0b10, Rm, 0b011, 0, Rn, Rt))
|
||||
#define LDRSW_REG_SXTW(Rt, Rn, Rm) EMIT(LDRS_REG_gen(0b10, Rm, 0b110, 0, Rn, Rt))
|
||||
#define LDRSW_REGz(Rt, Rn, Rm) EMIT(LDRS_REG_gen(0b10, Rm, rex.is32bits?0b110:0b011, 0, Rn, Rt))
|
||||
|
||||
#define 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))
|
||||
@@ -390,12 +413,15 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#define STRw_REG_SXTW(Rt, Rn, Rm) EMIT(STR_REG_gen(0b10, Rm, 0b110, 0, Rn, Rt))
|
||||
#define STRB_REG(Rt, Rn, Rm) EMIT(STR_REG_gen(0b00, Rm, 0b011, 0, Rn, Rt))
|
||||
#define STRB_REG_SXTW(Rt, Rn, Rm) EMIT(STR_REG_gen(0b00, Rm, 0b110, 0, Rn, Rt))
|
||||
#define STRB_REGz(Rt, Rn, Rm) EMIT(STR_REG_gen(0b00, Rm, rex.is32bits?0b110:0b011, 0, Rn, Rt))
|
||||
#define STRH_REG(Rt, Rn, Rm) EMIT(STR_REG_gen(0b01, Rm, 0b011, 0, Rn, Rt))
|
||||
#define STRH_REG_SXTW(Rt, Rn, Rm) EMIT(STR_REG_gen(0b01, Rm, 0b110, 0, Rn, Rt))
|
||||
#define STRxw_REG(Rt, Rn, Rm) EMIT(STR_REG_gen(rex.w?0b11:0b10, Rm, 0b011, 0, Rn, Rt))
|
||||
#define STRxw_REG_SXTW(Rt, Rn, Rm) EMIT(STR_REG_gen(rex.w?0b11:0b10, Rm, 0b110, 0, Rn, Rt))
|
||||
#define STRxw_REGz(Rt, Rn, Rm) EMIT(STR_REG_gen(rex.w?0b11:0b10, Rm, rex.is32bits?0b110:0b011, 0, Rn, Rt))
|
||||
#define STRz_REG(Rt, Rn, Rm) EMIT(STR_REG_gen(rex.is32bits?0b10:0b11, Rm, 0b011, 0, Rn, Rt))
|
||||
#define STRz_REG_SXTW(Rt, Rn, Rm) EMIT(STR_REG_gen(rex.is32bits?0b10:0b11, Rm, 0b110, 0, Rn, Rt))
|
||||
#define STRz_REGz(Rt, Rn, Rm) EMIT(STR_REG_gen(rex.is32bits?0b10:0b11, Rm, rex.is32bits?0b110:0b011, 0, Rn, Rt))
|
||||
|
||||
// LOAD/STORE PAIR
|
||||
#define MEMPAIR_gen(size, L, op2, imm7, Rt2, Rn, Rt) ((size)<<31 | 0b101<<27 | (op2)<<23 | (L)<<22 | (imm7)<<15 | (Rt2)<<10 | (Rn)<<5 | (Rt))
|
||||
@@ -560,7 +586,7 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#define CSINV_gen(sf, Rm, cond, Rn, Rd) ((sf)<<31 | 1<<30 | 0b11010100<<21 | (Rm)<<16 | (cond)<<12 | (Rn)<<5 | (Rd))
|
||||
#define CSINVx(Rd, Rn, Rm, cond) EMIT(CSINV_gen(1, Rm, cond, Rn, Rd))
|
||||
#define CSINVw(Rd, Rn, Rm, cond) EMIT(CSINV_gen(0, Rm, cond, Rn, Rd))
|
||||
#define CSINVxw(Rd, Rn, Rm, cond) EMIT(CSINV_gen(rex.w?, Rm, cond, Rn, Rd))
|
||||
#define CSINVxw(Rd, Rn, Rm, cond) EMIT(CSINV_gen(rex.w, Rm, cond, Rn, Rd))
|
||||
#define CINVx(Rd, Rn, cond) CSINVx(Rd, Rn, Rn, invertCond(cond))
|
||||
#define CINVw(Rd, Rn, cond) CSINVw(Rd, Rn, Rn, invertCond(cond))
|
||||
#define CINVxw(Rd, Rn, cond) CSINVxw(Rd, Rn, Rn, invertCond(cond))
|
||||
@@ -694,6 +720,7 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#define BFCx(Rd, lsb, width) BFMx(Rd, xZR, ((-(lsb))%64)&0x3f, (width)-1)
|
||||
#define BFCw(Rd, lsb, width) BFMw(Rd, xZR, ((-(lsb))%32)&0x1f, (width)-1)
|
||||
#define BFCxw(Rd, lsb, width) BFMxw(Rd, xZR, rex.w?(((-(lsb))%64)&0x3f):(((-(lsb))%32)&0x1f), (width)-1)
|
||||
#define BFCz(Rd, lsb, width) if(rex.is32bits) {BFCw(Rd, lsb, width);} else {BFCx(Rd, lsb, width);}
|
||||
// Insert lsb:width part of Rn into low part of Rd (leaving rest of Rd untouched)
|
||||
#define BFXILx(Rd, Rn, lsb, width) EMIT(BFM_gen(1, 0b01, 1, (lsb), (lsb)+(width)-1, Rn, Rd))
|
||||
// Insert lsb:width part of Rn into low part of Rd (leaving rest of Rd untouched)
|
||||
@@ -918,10 +945,12 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#define VLD64(A, B, C) if(unscaled) {VLDR64_I9(A, B, C);} else {VLDR64_U12(A, B, C);}
|
||||
#define VLD32(A, B, C) if(unscaled) {VLDR32_I9(A, B, C);} else {VLDR32_U12(A, B, C);}
|
||||
#define VLD16(A, B, C) if(unscaled) {VLDR16_I9(A, B, C);} else {VLDR16_U12(A, B, C);}
|
||||
#define VLD8(A, B, C) if(unscaled) {VLDR8_I9(A, B, C);} else {VLDR8_U12(A, B, C);}
|
||||
#define VST128(A, B, C) if(unscaled) {VSTR128_I9(A, B, C);} else {VSTR128_U12(A, B, C);}
|
||||
#define VST64(A, B, C) if(unscaled) {VSTR64_I9(A, B, C);} else {VSTR64_U12(A, B, C);}
|
||||
#define VST32(A, B, C) if(unscaled) {VSTR32_I9(A, B, C);} else {VSTR32_U12(A, B, C);}
|
||||
#define VST16(A, B, C) if(unscaled) {VSTR16_I9(A, B, C);} else {VSTR16_U12(A, B, C);}
|
||||
#define VST8(A, B, C) if(unscaled) {VSTR8_I9(A, B, C);} else {VSTR8_U12(A, B, C);}
|
||||
|
||||
#define VMEMW_gen(size, opc, imm9, op2, Rn, Rt) ((size)<<30 | 0b111<<27 | 1<<26 | (opc)<<22 | (imm9)<<12 | (op2)<<10 | 0b01<<10 | (Rn)<<5 | (Rt))
|
||||
#define VLDR64_S9_postindex(Rt, Rn, imm9) EMIT(VMEMW_gen(0b11, 0b01, (imm9)&0x1ff, 0b01, Rn, Rt))
|
||||
@@ -1141,7 +1170,9 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#define VFMOVDQ_8(Vd, u8) EMIT(FMOV_vector_imm(1, 1, ((u8)>>5)&0b111, (u8)&0b11111, Vd))
|
||||
|
||||
#define FMOV_scalar_imm(type, imm8, Rd) (0b11110<<24 | (type)<<22 | 1<<21 | (imm8)<<13 | 0b100<<10 | (Rd))
|
||||
// FMOV to Sd, imm=7 :~6:6:6:6:6:6:5:4 :3:2:1:0....
|
||||
#define FMOVS_8(Sd, u8) EMIT(FMOV_scalar_imm(0b00, u8, Sd))
|
||||
// FMOV to Dd, imm=7 :~6:6:6:6:6:6:6:6:6:5:4 :3:2:1:0....
|
||||
#define FMOVD_8(Dd, u8) EMIT(FMOV_scalar_imm(0b01, u8, Dd))
|
||||
|
||||
// VMOV
|
||||
@@ -1297,7 +1328,7 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#define VFRSQRTSQS(Vd, Vn, Vm) EMIT(FRSQRTS_vector(1, 0, Vm, Vn, Vd))
|
||||
#define VFRSQRTSQD(Vd, Vn, Vm) EMIT(FRSQRTS_vector(1, 0, Vm, Vn, Vd))
|
||||
|
||||
// CMP
|
||||
// CMP . NZCV: unordere=0011, eq=0110, inf=1000, sup=0010
|
||||
#define FCMP_scalar(type, Rn, Rm, opc) (0b11110<<24 | (type)<<22 | 1<<21 | (Rm)<<16 | 0b1000<<10 | (Rn)<<5 | (opc)<<3)
|
||||
#define FCMPS(Sn, Sm) FEMIT(FCMP_scalar(0b00, Sn, Sm, 0b00))
|
||||
#define FCMPD(Dn, Dm) FEMIT(FCMP_scalar(0b01, Dn, Dm, 0b00))
|
||||
@@ -1826,7 +1857,7 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#define FCMLTS_0(Rd, Rn) EMIT(FCMP_0_scalar(0, 0, 0b10, (Rn), (Rd)))
|
||||
#define FCMLTD_0(Rd, Rn) EMIT(FCMP_0_scalar(0, 1, 0b10, (Rn), (Rd)))
|
||||
|
||||
// Scalar Float CMP
|
||||
// Scalar Float CMEQ
|
||||
#define FCMP_op_scalar(U, E, sz, Rm, ac, Rn, Rd) (0b01<<30 | (U)<<29 | 0b11110<<24 | (E)<<23 | (sz)<<22 | 1<<21 | (Rm)<<16 | 0b1110<<12 | (ac)<<11 | 1<<10 | (Rn)<<5 | (Rd))
|
||||
#define FCMEQS(Rd, Rn, Rm) EMIT(FCMP_op_scalar(0, 0, 0, (Rm), 0, (Rn), (Rd)))
|
||||
#define FCMEQD(Rd, Rn, Rm) EMIT(FCMP_op_scalar(0, 0, 1, (Rm), 0, (Rn), (Rd)))
|
||||
|
||||
@@ -554,6 +554,16 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
snprintf(buff, sizeof(buff), "SUBS %s, %s, %s %s %d", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm], shifts[shift], imm);
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "f1001011001mmmmmoooiiinnnnnddddd", &a)) {
|
||||
const char* shifts[2][8] = {{ "UXTB", "UXTH", "LSL", "UXTX", "SXTB", "SXTH", "SXTW", "SXTX"}, {"UXTB", "UXTH", "UXTW", "LSL", "SXTB", "SXTH", "SXTW", "SXTX" }};
|
||||
if(((sf==0 && shift==2) || (sf==1 && shift==3)) && imm==0)
|
||||
snprintf(buff, sizeof(buff), "SUB %s, %s, %s", sf?XtSp[Rd]:WtSp[Rd], sf?XtSp[Rn]:WtSp[Rn], sf?XtSp[Rm]:WtSp[Rm]);
|
||||
else if(shift==0)
|
||||
snprintf(buff, sizeof(buff), "SUB %s, %s, %s %s", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm], shifts[sf][shift]);
|
||||
else
|
||||
snprintf(buff, sizeof(buff), "SUB %s, %s, %s %s %d", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm], shifts[sf][shift], imm);
|
||||
return buff;
|
||||
}
|
||||
// ---- LOGIC
|
||||
if(isMask(opcode, "f11100100Nrrrrrrssssssnnnnnddddd", &a)) {
|
||||
uint64_t i = DecodeBitMasks(a.N, imms, immr);
|
||||
@@ -743,8 +753,12 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
snprintf(buff, sizeof(buff), "BFC %s, %d, %d", sf?Xt[Rd]:Wt[Rd], lsb, width);
|
||||
else
|
||||
snprintf(buff, sizeof(buff), "BFI %s, %s, %d, %d", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], lsb, width);
|
||||
} else
|
||||
snprintf(buff, sizeof(buff), "BFXIL %s, %s, %d, %d", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], immr, imms-immr+1);
|
||||
} else {
|
||||
if(Rn==31 && immr==0)
|
||||
snprintf(buff, sizeof(buff), "BFC %s, %d, %d", sf?Xt[Rd]:Wt[Rd], immr, imms-immr+1);
|
||||
else
|
||||
snprintf(buff, sizeof(buff), "BFXIL %s, %s, %d, %d", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], immr, imms-immr+1);
|
||||
}
|
||||
return buff;
|
||||
}
|
||||
// ---- BRANCH / TEST
|
||||
@@ -768,17 +782,12 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
}
|
||||
if(isMask(opcode, "f0110100iiiiiiiiiiiiiiiiiiittttt", &a)) {
|
||||
int offset = signExtend(imm, 19)<<2;
|
||||
snprintf(buff, sizeof(buff), "CBZ %s, #%+di\t; %p", Xt[Rt], offset>>2, (void*)(addr + offset));
|
||||
snprintf(buff, sizeof(buff), "CBZ %s, #%+di\t; %p", sf?Xt[Rt]:Wt[Rt], offset>>2, (void*)(addr + offset));
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "f0110101iiiiiiiiiiiiiiiiiiittttt", &a)) {
|
||||
int offset = signExtend(imm, 19)<<2;
|
||||
snprintf(buff, sizeof(buff), "CBNZ %s, #%+di\t; %p", Xt[Rt], offset>>2, (void*)(addr + offset));
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "f0110100iiiiiiiiiiiiiiiiiiittttt", &a)) {
|
||||
int offset = signExtend(imm, 19)<<2;
|
||||
snprintf(buff, sizeof(buff), "CBZ %s, #%+di\t; %p", Xt[Rt], offset>>2, (void*)(addr + offset));
|
||||
snprintf(buff, sizeof(buff), "CBNZ %s, #%+di\t; %p", sf?Xt[Rt]:Wt[Rt], offset>>2, (void*)(addr + offset));
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "s0110110sssssiiiiiiiiiiiiiittttt", &a)) {
|
||||
@@ -1324,6 +1333,12 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
snprintf(buff, sizeof(buff), "FCMP %c%d, %c%d", s, Rn, s, Rm);
|
||||
return buff;
|
||||
}
|
||||
//FCMEQ
|
||||
if(isMask(opcode, "000111100f1mmmmm111001nnnnnddddd", &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;
|
||||
}
|
||||
//FCMP vector
|
||||
if(isMask(opcode, "0QU01110cf1mmmmm111001nnnnnddddd", &a)) {
|
||||
char s = (sf==0)?'S':((sf==1)?'D':'?');
|
||||
@@ -1574,12 +1589,12 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
}
|
||||
|
||||
// LD1/ST1 single structure
|
||||
if(isMask(opcode, "0Q0011010L000000cc0Sffnnnnnttttt", &a)) {
|
||||
if(isMask(opcode, "0Q0011010Lo00000cc0Sffnnnnnttttt", &a)) {
|
||||
int scale = a.c;
|
||||
int idx = 0;
|
||||
const char* Y[] = {"B", "H", "S", "D"};
|
||||
switch(scale) {
|
||||
case 3: scale = sf; /* rep = 1; */ break;
|
||||
case 3: scale = sf; /* rep = 1; */ idx=(8*(a.Q+1))>>scale; break;
|
||||
case 0: idx = (a.Q<<3) | (a.S<<2) | sf; break;
|
||||
case 1: idx = (a.Q<<2) | (a.S<<1) | (sf>>1); break;
|
||||
case 2: if(!(sf&1))
|
||||
@@ -1590,7 +1605,10 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
}
|
||||
break;
|
||||
}
|
||||
snprintf(buff, sizeof(buff), "%s1 {V%d.%s}[%d], [%s]", a.L?"LD":"ST", Rt, Y[scale], idx, XtSp[Rn]);
|
||||
if(!option && a.L && scale==3)
|
||||
snprintf(buff, sizeof(buff), "LD1R {V%d.%d%s}, [%s]", Rt, idx, Y[scale], XtSp[Rn]);
|
||||
else
|
||||
snprintf(buff, sizeof(buff), "%s1 {V%d.%s}[%d], [%s]", a.L?"LD":"ST", Rt, Y[scale], idx, XtSp[Rn]);
|
||||
return buff;
|
||||
}
|
||||
// LDUR/STUR
|
||||
@@ -1637,6 +1655,11 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
snprintf(buff, sizeof(buff), "%cQXTN%s V%d.%s, V%d.%s", a.U?'U':'S', a.Q?"2":"", Rd, Vd, Rn, Va);
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "01U11110ff100001010010nnnnnddddd", &a)) {
|
||||
const char Z[] = {'B', 'H', 'S', 'D', '?'};
|
||||
snprintf(buff, sizeof(buff), "SQXT%sN %c%d, %c%d", a.U?"U":"", Z[sf], Rd, Z[sf+1], Rn);
|
||||
return buff;
|
||||
}
|
||||
|
||||
// (S/U)SSHL(2) / (U/S)XTL(2)
|
||||
if(isMask(opcode, "0QU011110hhhhiii101001nnnnnddddd", &a)) {
|
||||
@@ -1667,6 +1690,15 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
return buff;
|
||||
}
|
||||
|
||||
// CNT
|
||||
if(isMask(opcode, "0Q00111000100000010110nnnnnddddd", &a)) {
|
||||
const char* Y[] = {"8B", "16B"};
|
||||
const char* Vd = Y[a.Q];
|
||||
const char* Va = Y[a.Q];
|
||||
snprintf(buff, sizeof(buff), "CNT V%d.%s, V%d.%s", Rd, Vd, Rn, Va);
|
||||
return buff;
|
||||
}
|
||||
|
||||
// DUP
|
||||
if(isMask(opcode, "0Q001110000iiiii000001nnnnnddddd", &a)) {
|
||||
const char* Y[] = {"8B", "16B", "4H", "8H", "2S", "4S", "??", "2D"};
|
||||
@@ -1713,14 +1745,26 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
return buff;
|
||||
}
|
||||
|
||||
// DMB ISH
|
||||
// DMB
|
||||
if(isMask(opcode, "11010101000000110011nnnn10111111", &a)) {
|
||||
snprintf(buff, sizeof(buff), "DMB %s", (Rn==0b1011)?"ISH":"???");
|
||||
const char* barrier[] = {
|
||||
"???", "???", "???", "???", // 0-3
|
||||
"???", "???", "???", "???", // 4-7
|
||||
"???", "ISHLD", "ISHST", "ISH", // 8-11
|
||||
"???", "LD", "ST", "SY" // 12-15
|
||||
};
|
||||
snprintf(buff, sizeof(buff), "DMB %s", barrier[Rn]);
|
||||
return buff;
|
||||
}
|
||||
// DSB ISH/ISHST
|
||||
// DSB
|
||||
if(isMask(opcode, "11010101000000110011nnnn10011111", &a)) {
|
||||
snprintf(buff, sizeof(buff), "DSB %s", (Rn==0b1011)?"ISH":((Rn==0b1010)?"ISHST":"???"));
|
||||
const char* barrier[] = {
|
||||
"???", "???", "???", "???", // 0-3
|
||||
"???", "???", "???", "???", // 4-7
|
||||
"???", "ISHLD", "ISHST", "ISH", // 8-11
|
||||
"???", "LD", "ST", "SY" // 12-15
|
||||
};
|
||||
snprintf(buff, sizeof(buff), "DSB %s", barrier[Rn]);
|
||||
return buff;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -165,7 +165,11 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
|
||||
case 0x09:
|
||||
INST_NAME("WBINVD");
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_PEND);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
}
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_ud, -1);
|
||||
@@ -177,7 +181,11 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
|
||||
case 0x0B:
|
||||
INST_NAME("UD2");
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_PEND);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
}
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_ud, -1);
|
||||
@@ -212,7 +220,11 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0x0E:
|
||||
INST_NAME("femms");
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_PEND);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
}
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_ud, -1);
|
||||
@@ -248,8 +260,20 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, ed);
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VST128(v0, ed, fixedaddress);
|
||||
IF_UNALIGNED(ip) {
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VST128(v0, ed, fixedaddress);
|
||||
}
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
@@ -325,7 +349,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0x18:
|
||||
nextop = F8;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if (MODREG) {
|
||||
INST_NAME("NOP (multibyte)");
|
||||
} else
|
||||
switch((nextop>>3)&7) {
|
||||
@@ -355,6 +379,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x19:
|
||||
case 0x1F:
|
||||
INST_NAME("NOP (multibyte)");
|
||||
nextop = F8;
|
||||
@@ -422,7 +447,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGM(q0);
|
||||
GETEX(v1, 0, 0);
|
||||
if (box64_dynarec_fastround) {
|
||||
if (BOX64ENV(dynarec_fastround)) {
|
||||
VFCVTZSS(q0, v1);
|
||||
} else {
|
||||
if(arm64_frintts) {
|
||||
@@ -456,7 +481,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGM(q0);
|
||||
GETEX(v1, 0, 0);
|
||||
if (box64_dynarec_fastround) {
|
||||
if (BOX64ENV(dynarec_fastround)) {
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x3);
|
||||
VFRINTIS(q0, v1);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
@@ -499,11 +524,15 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETGX(v0, 0);
|
||||
GETEXSS(s0, 0, 0);
|
||||
FCMPS(v0, s0);
|
||||
FCOMI(x1, x2, 0, v0, s0, 1); // disabled precise cmp
|
||||
FCOMI(x1, x2);
|
||||
break;
|
||||
case 0x30:
|
||||
INST_NAME("WRMSR");
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_PEND);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
}
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_priv, -1);
|
||||
@@ -1003,16 +1032,17 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOV32w(gd, 0);
|
||||
if(MODREG) {
|
||||
// EX is an xmm reg
|
||||
GETEX(q0, 0, 0);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
GETEX(v0, 0, 0);
|
||||
SQXTN_16(q0, v0); // reduces the 4 32bits to 4 16bits
|
||||
VMOVQDto(x1, q0, 0);
|
||||
LSRx(x1, x1, 31);
|
||||
LSRx(x1, x1, 15);
|
||||
BFIx(gd, x1, 0, 1);
|
||||
LSRx(x1, x1, 32);
|
||||
LSRx(x1, x1, 16);
|
||||
BFIx(gd, x1, 1, 1);
|
||||
VMOVQDto(x1, q0, 1);
|
||||
LSRx(x1, x1, 31);
|
||||
LSRx(x1, x1, 16);
|
||||
BFIx(gd, x1, 2, 1);
|
||||
LSRx(x1, x1, 32);
|
||||
LSRx(x1, x1, 16);
|
||||
BFIx(gd, x1, 3, 1);
|
||||
} else {
|
||||
// EX is memory
|
||||
@@ -1108,15 +1138,41 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("ADDPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX(v0, 1);
|
||||
VFADDQS(v0, v0, q0);
|
||||
GETGX(q1, 1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
VFMAXQS(v0, q0, q1); // propagate NAN
|
||||
VFCMEQQS(v0, v0, v0); // 0 if NAN, 1 if not NAN
|
||||
}
|
||||
VFADDQS(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 0x59:
|
||||
INST_NAME("MULPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX(v0, 1);
|
||||
VFMULQS(v0, v0, q0);
|
||||
GETGX(q1, 1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
VFMAXQS(v0, q0, q1); // propagate NAN
|
||||
VFCMEQQS(v0, v0, v0); // 0 if NAN, 1 if not NAN
|
||||
}
|
||||
VFMULQS(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 0x5A:
|
||||
INST_NAME("CVTPS2PD Gx, Ex");
|
||||
@@ -1136,8 +1192,21 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("SUBPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX(v0, 1);
|
||||
VFSUBQS(v0, v0, q0);
|
||||
GETGX(q1, 1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
VFMAXQS(v0, q0, q1); // propagate NAN
|
||||
VFCMEQQS(v0, v0, v0); // 0 if NAN, 1 if not NAN
|
||||
}
|
||||
VFSUBQS(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 0x5D:
|
||||
INST_NAME("MINPS Gx, Ex");
|
||||
@@ -1147,7 +1216,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
// 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(!box64_dynarec_fastnan && (v0!=v1)) {
|
||||
if(!BOX64ENV(dynarec_fastnan) && (v0!=v1)) {
|
||||
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
|
||||
@@ -1157,8 +1226,21 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("DIVPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX(v0, 1);
|
||||
VFDIVQS(v0, v0, q0);
|
||||
GETGX(q1, 1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
VFMAXQS(v0, q0, q1); // propagate NAN
|
||||
VFCMEQQS(v0, v0, v0); // 0 if NAN, 1 if not NAN
|
||||
}
|
||||
VFDIVQS(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 0x5F:
|
||||
INST_NAME("MAXPS Gx, Ex");
|
||||
@@ -1168,7 +1250,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
// 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(!box64_dynarec_fastnan && (v0!=v1)) {
|
||||
if(!BOX64ENV(dynarec_fastnan) && (v0!=v1)) {
|
||||
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
|
||||
@@ -1532,7 +1614,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("MOVD Ed, Gm");
|
||||
nextop = F8;
|
||||
GETGM(v0);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 0x07) + (rex.b << 3));
|
||||
if(rex.w) {
|
||||
FMOVxD(ed, v0);
|
||||
@@ -1641,8 +1723,11 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0xA3:
|
||||
INST_NAME("BT Ed, Gd");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
if(!BOX64ENV(dynarec_safeflags)) {
|
||||
SETFLAGS(X_ALL&~X_ZF, SF_SUBSET);
|
||||
} else {
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
}
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
@@ -1669,11 +1754,11 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0xA4:
|
||||
nextop = F8;
|
||||
INST_NAME("SHLD Ed, Gd, Ib");
|
||||
if(geted_ib(dyn, addr, ninst, nextop)) {
|
||||
if(geted_ib(dyn, addr, ninst, nextop)&(rex.w?63:31)) {
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETED(1);
|
||||
GETGD;
|
||||
u8 = F8;
|
||||
u8 = F8&(rex.w?63:31);
|
||||
emit_shld32c(dyn, ninst, rex, ed, gd, u8, x3, x4);
|
||||
WBACK;
|
||||
} else {
|
||||
@@ -1684,9 +1769,11 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0xA5:
|
||||
nextop = F8;
|
||||
INST_NAME("SHLD Ed, Gd, CL");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
if(box64_dynarec_safeflags>1)
|
||||
MAYSETFLAGS();
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETGD;
|
||||
GETED(0);
|
||||
if(!rex.w && !rex.is32bits && MODREG) {MOVw_REG(ed, ed);}
|
||||
@@ -1714,8 +1801,11 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
|
||||
case 0xAB:
|
||||
INST_NAME("BTS Ed, Gd");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
if(!BOX64ENV(dynarec_safeflags)) {
|
||||
SETFLAGS(X_ALL&~X_ZF, SF_SUBSET);
|
||||
} else {
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
}
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
@@ -1751,11 +1841,11 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0xAC:
|
||||
nextop = F8;
|
||||
INST_NAME("SHRD Ed, Gd, Ib");
|
||||
if(geted_ib(dyn, addr, ninst, nextop)) {
|
||||
if(geted_ib(dyn, addr, ninst, nextop)&(rex.w?63:31)) {
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETED(1);
|
||||
GETGD;
|
||||
u8 = F8;
|
||||
u8 = F8&(rex.w?63:31);
|
||||
emit_shrd32c(dyn, ninst, rex, ed, gd, u8, x3, x4);
|
||||
WBACK;
|
||||
} else {
|
||||
@@ -1766,9 +1856,11 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0xAD:
|
||||
nextop = F8;
|
||||
INST_NAME("SHRD Ed, Gd, CL");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
if(box64_dynarec_safeflags>1)
|
||||
MAYSETFLAGS();
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETGD;
|
||||
GETED(0);
|
||||
if(!rex.w && !rex.is32bits && MODREG) {MOVw_REG(ed, ed);}
|
||||
@@ -1805,7 +1897,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FXSAVE Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (FXSAVE)\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
@@ -1813,7 +1905,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FXRSTOR Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (FXRSTOR)\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
@@ -1823,24 +1915,57 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("LDMXCSR Md");
|
||||
GETED(0);
|
||||
STRw_U12(ed, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
if(box64_sse_flushto0) {
|
||||
MRS_fpcr(x1); // get fpscr
|
||||
if(BOX64ENV(sse_flushto0)) {
|
||||
MRS_fpcr(x2); // get fpscr
|
||||
LSRw_IMM(x3, ed, 15); // get FZ bit
|
||||
BFIw(x1, x3, 24, 1); // inject FZ bit
|
||||
BFIw(x2, x3, 24, 1); // inject FZ bit
|
||||
EORw_REG_LSR(x3, x3, ed, 1); // FZ xor DAZ
|
||||
BFIw(x1, x3, 1, 1); // inject AH bit
|
||||
MSR_fpcr(x1); // put new fpscr
|
||||
BFIw(x2, x3, 1, 1); // inject AH bit
|
||||
MSR_fpcr(x2); // put new fpscr
|
||||
}
|
||||
if(BOX64ENV(sse_flushto0)) {
|
||||
// try to sync mxcsr with fpsr on the flag side
|
||||
/* mapping is
|
||||
ARM -> X86
|
||||
0 -> 0 // Invalid operation
|
||||
1 -> 2 // Divide by 0
|
||||
2 -> 3 // Overflow
|
||||
3 -> 4 // underflow
|
||||
4 -> 5 // Inexact
|
||||
5 -> 1 // denormal
|
||||
*/
|
||||
// doing X86 -> ARM here, 0 1 2 3 4 5 -> 0 2 3 4 5 1
|
||||
if(ed!=x1)
|
||||
MOVw_REG(x1, ed); // x1 = 543210
|
||||
RORw(x3, x1, 2); // x3 = 10.....5432
|
||||
BFIw(x1, x3, 1, 4); // x1 = 54320
|
||||
RORw(x3, x3, 32-1); // x3 = 0.....54321
|
||||
BFIw(x1, x3, 5, 1); // x1 = 154320
|
||||
MRS_fpsr(x2);
|
||||
BFIx(x2, x1, 0, 6);
|
||||
MSR_fpsr(x2);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
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));
|
||||
if(BOX64ENV(sse_flushto0)) {
|
||||
// sync with fpsr, with mask from mxcsr
|
||||
MRS_fpsr(x1);
|
||||
// doing ARM -> X86 here, 543210 => 432150
|
||||
UBFXw(x2, x1, 1, 5); // x2 = 54321
|
||||
BFIw(x1, x2, 2, 4); // x1 = 432110
|
||||
LSRw(x2, x2, 4); // x2 = 5
|
||||
BFIw(x1, x2, 1, 1); // x1 = 432150
|
||||
//BFXILw(x3, x4, 7, 6); // this would the mask, but let's ignore that for now
|
||||
BFIw(x4, x1, 0, 6); // inject back the flags
|
||||
}
|
||||
STW(x4, ed, fixedaddress);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("XSAVE Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (XSAVE)\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
@@ -1849,7 +1974,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("XRSTOR Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (XRSTOR)\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
@@ -1858,7 +1983,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("CLFLUSH Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization?\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (CLFLUSH)?\n");
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {
|
||||
MOVx_REG(x1, ed);
|
||||
@@ -1871,7 +1996,11 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0xAF:
|
||||
INST_NAME("IMUL Gd, Ed");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
if(BOX64ENV(dynarec_safeflags) && BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
}
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED(0);
|
||||
@@ -1880,10 +2009,9 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
UFLAG_IF {
|
||||
SMULH(x3, gd, ed);
|
||||
MULx(gd, gd, ed);
|
||||
SET_DFNONE(x4);
|
||||
SET_DFNONE();
|
||||
IFX(X_CF|X_OF) {
|
||||
ASRx(x4, gd, 63);
|
||||
CMPSx_REG(x3, x4);
|
||||
CMPSx_REG_ASR(x3, gd, 63);
|
||||
CSETw(x3, cNE);
|
||||
IFX(X_CF) {
|
||||
BFIw(xFlags, x3, F_CF, 1);
|
||||
@@ -1901,10 +2029,9 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SMULL(gd, gd, ed);
|
||||
LSRx(x3, gd, 32);
|
||||
MOVw_REG(gd, gd);
|
||||
SET_DFNONE(x4);
|
||||
SET_DFNONE();
|
||||
IFX(X_CF|X_OF) {
|
||||
ASRw(x4, gd, 31);
|
||||
CMPSw_REG(x3, x4);
|
||||
CMPSw_REG_ASR(x3, gd, 31);
|
||||
CSETw(x3, cNE);
|
||||
IFX(X_CF) {
|
||||
BFIw(xFlags, x3, F_CF, 1);
|
||||
@@ -1917,12 +2044,13 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MULxw(gd, gd, ed);
|
||||
}
|
||||
}
|
||||
IFX(X_AF | X_PF | X_ZF | X_SF)
|
||||
if(box64_dynarec_test) {
|
||||
// to avoid noise during test
|
||||
MOV32w(x1, (1<<F_ZF)|(1<<F_AF)|(1<<F_PF)|(1<<F_SF));
|
||||
BICw(xFlags, xFlags, x1);
|
||||
}
|
||||
IFX2(X_AF, && !BOX64ENV(cputype)) {BFCw(xFlags, F_AF, 1);}
|
||||
IFX2(X_ZF, && !BOX64ENV(cputype)) {BFCw(xFlags, F_ZF, 1);}
|
||||
IFX2(X_SF, && !BOX64ENV(cputype)) {
|
||||
LSRxw(x3, gd, rex.w?63:31);
|
||||
BFIw(xFlags, x3, F_SF, 1);
|
||||
}
|
||||
IFX2(X_PF, && !BOX64ENV(cputype)) emit_pf(dyn, ninst, gd, x3);
|
||||
break;
|
||||
|
||||
case 0xB1:
|
||||
@@ -1954,8 +2082,12 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
|
||||
case 0xB3:
|
||||
INST_NAME("BTR Ed, Gd");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
if(!BOX64ENV(dynarec_safeflags)) {
|
||||
SETFLAGS(X_ALL&~X_ZF, SF_SUBSET);
|
||||
} else {
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
}
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
@@ -2028,8 +2160,11 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
switch((nextop>>3)&7) {
|
||||
case 4:
|
||||
INST_NAME("BT Ed, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
if(!BOX64ENV(dynarec_safeflags)) {
|
||||
SETFLAGS(X_ALL&~X_ZF, SF_SUBSET);
|
||||
} else {
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
}
|
||||
gd = x2;
|
||||
if(MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
@@ -2041,12 +2176,17 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
u8 = F8;
|
||||
u8&=rex.w?0x3f:0x1f;
|
||||
BFXILxw(xFlags, ed, u8, 1); // inject 1 bit from u8 to F_CF (i.e. pos 0)
|
||||
IFX(X_CF) {
|
||||
BFXILxw(xFlags, ed, u8, 1); // inject 1 bit from u8 to F_CF (i.e. pos 0)
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("BTS Ed, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
if(!BOX64ENV(dynarec_safeflags)) {
|
||||
SETFLAGS(X_ALL&~X_ZF, SF_SUBSET);
|
||||
} else {
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
}
|
||||
if(MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
wback = 0;
|
||||
@@ -2070,8 +2210,11 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("BTR Ed, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
if(!BOX64ENV(dynarec_safeflags)) {
|
||||
SETFLAGS(X_ALL&~X_ZF, SF_SUBSET);
|
||||
} else {
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
}
|
||||
if(MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
wback = 0;
|
||||
@@ -2094,8 +2237,11 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("BTC Ed, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
if(!BOX64ENV(dynarec_safeflags)) {
|
||||
SETFLAGS(X_ALL&~X_ZF, SF_SUBSET);
|
||||
} else {
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
}
|
||||
if(MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
wback = 0;
|
||||
@@ -2123,8 +2269,11 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0xBB:
|
||||
INST_NAME("BTC Ed, Gd");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
if(!BOX64ENV(dynarec_safeflags)) {
|
||||
SETFLAGS(X_ALL&~X_ZF, SF_SUBSET);
|
||||
} else {
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
}
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
@@ -2159,8 +2308,8 @@ 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_DF);
|
||||
SET_DFNONE(x1);
|
||||
SETFLAGS(X_ZF, SF_SET);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
GETGD;
|
||||
@@ -2182,8 +2331,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0xBD:
|
||||
INST_NAME("BSR Gd, Ed");
|
||||
SETFLAGS(X_ZF, SF_SET_DF);
|
||||
SET_DFNONE(x1);
|
||||
SETFLAGS(X_ZF, SF_SET);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
GETGD;
|
||||
@@ -2384,11 +2533,11 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0xC7:
|
||||
// rep has no impact here
|
||||
nextop = F8;
|
||||
if(MODREG) switch((nextop>>3)&7) {
|
||||
if(MODREG) switch((nextop>>3)&7) {
|
||||
case 6:
|
||||
INST_NAME("RDRAND Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_DF);
|
||||
SET_DFNONE(x1);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SET_DFNONE();
|
||||
GETED(0);
|
||||
IFX(X_OF|X_SF|X_ZF|X_PF|X_AF) {
|
||||
MOV32w(x1, (1<<F_OF)|(1<<F_SF)|(1<<F_ZF)|(1<<F_PF)|(1<<F_AF));
|
||||
@@ -2404,6 +2553,11 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
IFX(X_CF) { BFIw(xFlags, x3, F_CF, 1); }
|
||||
MOVxw_REG(ed, x1);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("RDPID Ed");
|
||||
GETED(0);
|
||||
CALL_(helper_getcpu, ed, x2);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
} else switch((nextop>>3)&7) {
|
||||
@@ -2442,8 +2596,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("RDRAND Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_DF);
|
||||
SET_DFNONE(x1);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SET_DFNONE();
|
||||
IFX(X_OF|X_SF|X_ZF|X_PF|X_AF) {
|
||||
MOV32w(x1, (1<<F_OF)|(1<<F_SF)|(1<<F_ZF)|(1<<F_PF)|(1<<F_AF));
|
||||
BICw(xFlags, xFlags, x1);
|
||||
@@ -2480,50 +2634,28 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGM(d0);
|
||||
GETEM(d1, 0);
|
||||
if(MODREG) {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
}
|
||||
else {
|
||||
q0 = d1;
|
||||
}
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
VMOVBto(x1, d1, 0);
|
||||
MOVZw(x2, 16);
|
||||
SUBSw_REG(x2, x2, x1);
|
||||
B_MARK(cGT);
|
||||
VMOVQDfrom(d0, 0, xZR);
|
||||
B_NEXT_nocond;
|
||||
MARK;
|
||||
VDUPQS(q1, x2);
|
||||
UXTL_16(q0, d0);
|
||||
USHLQ_32(q0, q0, q1);
|
||||
VUZP2Q_16(q0, q0, q0);
|
||||
VMOVeD(d0, 0, q0, 0);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
UQXTN_32(v0, d1);
|
||||
MOVI_32(v1, 16);
|
||||
UMIN_32(v0, v0, v1); // limit to 0 .. +15 values
|
||||
VDUP_16(v0, v0, 0); // only the low 8bits will be used anyway
|
||||
NEG_16(v0, v0);
|
||||
USHL_16(d0, d0, v0);
|
||||
break;
|
||||
case 0xD2:
|
||||
INST_NAME("PSRLD Gm, Em");
|
||||
nextop = F8;
|
||||
GETGM(d0);
|
||||
GETEM(d1, 0);
|
||||
if(MODREG) {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
}
|
||||
else {
|
||||
q0 = d1;
|
||||
}
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
VMOVBto(x1, d1, 0);
|
||||
MOVZw(x2, 32);
|
||||
SUBSw_REG(x2, x2, x1);
|
||||
B_MARK(cGT);
|
||||
VMOVQDfrom(d0, 0, xZR);
|
||||
B_NEXT_nocond;
|
||||
MARK;
|
||||
VDUPQD(q1, x2);
|
||||
UXTL_32(q0, d0);
|
||||
USHLQ_64(q0, q0, q1);
|
||||
VUZP2Q_32(q0, q0, q0);
|
||||
VMOVeD(d0, 0, q0, 0);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
UQXTN_32(v0, d1);
|
||||
MOVI_32(v1, 32);
|
||||
UMIN_32(v0, v0, v1); // limit to 0 .. +31 values
|
||||
VDUP_32(v0, v0, 0); // only the low 8bits will be used anyway
|
||||
NEG_32(v0, v0);
|
||||
USHL_32(d0, d0, v0);
|
||||
break;
|
||||
case 0xD3:
|
||||
INST_NAME("PSRLQ Gm,Em");
|
||||
@@ -2531,11 +2663,10 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETGM(d0);
|
||||
GETEM(d1, 0);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
//MOVI_64(v0, 64); not 64!
|
||||
MOV32w(x1, 64);
|
||||
VMOVQDfrom(v0, 0, x1);
|
||||
MOVI_32(v0, 64);
|
||||
UMIN_32(v0, v0, d1); // limit to 0 .. +64 values (will force 32bits upper part to 0)
|
||||
NEG_64(v0, v0);
|
||||
NEG_32(v0, v0);
|
||||
UXTL_32(v0, v0);
|
||||
USHL_R_64(d0, d0, v0);
|
||||
break;
|
||||
case 0xD4:
|
||||
@@ -2667,7 +2798,18 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETEM(d1, 0);
|
||||
URHADD_16(d0, d0, d1);
|
||||
break;
|
||||
|
||||
case 0xE4:
|
||||
INST_NAME("PMULHUW Gm,Em");
|
||||
nextop = F8;
|
||||
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);
|
||||
break;
|
||||
case 0xE5:
|
||||
INST_NAME("PMULHW Gm,Em");
|
||||
nextop = F8;
|
||||
@@ -2759,8 +2901,11 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETGM(d0);
|
||||
GETEM(d1, 0);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
VMOVHto(x1, d1, 0);
|
||||
VDUPH(v0, x1);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
UQXTN_32(v0, d1);
|
||||
MOVI_32(v1, 16);
|
||||
UMIN_32(v0, v0, v1); // limit to 0 .. +16 values
|
||||
VDUP_16(v0, v0, 0);
|
||||
USHL_16(d0, d0, v0);
|
||||
break;
|
||||
case 0xF2:
|
||||
@@ -2803,7 +2948,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
VSMULL_16(q0, v0, v1);
|
||||
VADDPQ_32(q0, q0, q0); //ADDP from Q to non-Q?
|
||||
VMOVQ(v0, q0);
|
||||
VMOV(v0, q0);
|
||||
break;
|
||||
case 0xF6:
|
||||
INST_NAME("PSADBW Gm, Em");
|
||||
@@ -2812,10 +2957,10 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETEM(q1, 0);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
VEOR(d1, d1, d1); // is it necessary?
|
||||
UABDL_8(d0, q0, q1);
|
||||
UADDLVQ_16(d1, d0);
|
||||
VMOVeD(q0, 0, d1, 0);
|
||||
UABDL_8(d0, q0, q1); // 8bits absolute difference in 16bits
|
||||
UADDLVQ_16(d1, d0); // sum accros vector on the 16bits value inside a 32bits scalar
|
||||
UXTL_32(d1, d1); // 32bits -> 64bits
|
||||
VMOV(q0, d1);
|
||||
break;
|
||||
case 0xF7:
|
||||
INST_NAME("MASKMOVQ Gm, Em");
|
||||
@@ -2826,9 +2971,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
VSSHR_8(d1, q1, 7); // d1 = byte slection mask
|
||||
VLDR64_U12(d0, xRDI, 0);
|
||||
VBIC(d0, d0, d1); // d0 = clear masked byte
|
||||
VAND(d1, q0, d1); // d1 = masked Gm
|
||||
VORR(d0, d0, d1);
|
||||
VBIT(d0, q0, d1);
|
||||
VSTR64_U12(d0, xRDI, 0);
|
||||
break;
|
||||
case 0xF8:
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -436,21 +436,42 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
INST_NAME("IMUL Gw,Ew,Ib");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
if(BOX64ENV(dynarec_safeflags)>1 && BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
}
|
||||
nextop = F8;
|
||||
GETSEW(x1, (opcode==0x69)?2:1);
|
||||
if(opcode==0x69) i32 = F16S; else i32 = F8S;
|
||||
MOV32w(x2, i32);
|
||||
MULw(x2, x2, x1);
|
||||
UFLAG_RES(x2);
|
||||
gd=x2;
|
||||
GWBACK;
|
||||
UFLAG_DF(x1, d_imul16);
|
||||
SET_DFNONE();
|
||||
IFX(X_CF|X_OF) {
|
||||
ASRw(x1, x2, 15);
|
||||
CMPSw_REG_ASR(x1, x2, 31);
|
||||
CSETw(x3, cNE);
|
||||
IFX(X_CF) {
|
||||
BFIw(xFlags, x3, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BFIw(xFlags, x3, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX2(X_AF, && !BOX64ENV(cputype)) {BFCw(xFlags, F_AF, 1);}
|
||||
IFX2(X_ZF, && !BOX64ENV(cputype)) {BFCw(xFlags, F_ZF, 1);}
|
||||
IFX2(X_SF, && !BOX64ENV(cputype)) {
|
||||
LSRw(x3, x2, 15);
|
||||
BFIw(xFlags, x3, F_SF, 1);
|
||||
}
|
||||
IFX2(X_PF, && !BOX64ENV(cputype)) emit_pf(dyn, ninst, x2, x3);
|
||||
break;
|
||||
case 0x6A:
|
||||
INST_NAME("PUSH Ib");
|
||||
u16 = (uint16_t)F8S;
|
||||
MOV32w(x2, u16);
|
||||
i16 = F8S;
|
||||
MOV32w(x2, (uint16_t)i16);
|
||||
PUSH1_16(x2);
|
||||
break;
|
||||
|
||||
@@ -643,9 +664,9 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop=F8;
|
||||
u8 = (nextop&0x38)>>3;
|
||||
LDRH_U12(x3, xEmu, offsetof(x64emu_t, segs[u8]));
|
||||
if((nextop&0xC0)==0xC0) { // reg <= seg
|
||||
if (MODREG) {
|
||||
BFIz(TO_NAT((nextop & 7) + (rex.b << 3)), x3, 0, 16);
|
||||
} else { // mem <= seg
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
STH(x3, wback, fixedaddress);
|
||||
SMWRITE2();
|
||||
@@ -656,7 +677,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("MOV Seg,Ew");
|
||||
nextop = F8;
|
||||
u8 = (nextop&0x38)>>3;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
} else {
|
||||
SMREAD();
|
||||
@@ -671,7 +692,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("POP Ew");
|
||||
nextop = F8;
|
||||
POP1_16(x1);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if (MODREG) {
|
||||
wback = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
BFIz(wback, x1, 0, 16);
|
||||
} else {
|
||||
@@ -718,12 +739,12 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("POPF");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SMREAD();
|
||||
POP1_16(x1); // probably not usefull...
|
||||
POP1_16(x1);
|
||||
MOV32w(x2, 0x7FD7);
|
||||
ANDw_REG(x1, x1, x2);
|
||||
ORRw_mask(x1, x1, 0b011111, 0); //mask=0x00000002
|
||||
BFIw(xFlags, x1, 0, 16);
|
||||
MOV32w(x1, 0x3F7FD7);
|
||||
ANDw_REG(xFlags, xFlags, x1);
|
||||
ORRw_mask(xFlags, xFlags, 0b011111, 0); //mask=0x00000002
|
||||
SET_DFNONE(x1);
|
||||
SET_DFNONE();
|
||||
if(box64_wine) { // should this be done all the time?
|
||||
TBZ_NEXT(xFlags, F_TF);
|
||||
// go to epilog, TF should trigger at end of next opcode, so using Interpreter only
|
||||
@@ -732,7 +753,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
|
||||
case 0xA1:
|
||||
INST_NAME("MOV EAX,Od");
|
||||
INST_NAME("MOV AX,Od");
|
||||
if(rex.is32bits)
|
||||
u64 = F32;
|
||||
else
|
||||
@@ -745,7 +766,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
|
||||
case 0xA3:
|
||||
INST_NAME("MOV Od,EAX");
|
||||
INST_NAME("MOV Od,AX");
|
||||
if(rex.is32bits)
|
||||
u64 = F32;
|
||||
else
|
||||
@@ -761,17 +782,53 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("REP MOVSB");
|
||||
CBZx_NEXT(xRCX);
|
||||
TBNZ_MARK2(xFlags, F_DF);
|
||||
IF_UNALIGNED(ip) {
|
||||
// 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)) {
|
||||
SUBx_REG(x2, xRDI, xRSI);
|
||||
CMPSx_U12(x2, 4);
|
||||
B_MARK(cCC);
|
||||
}
|
||||
ORRw_REG(x1, xRSI, xRDI);
|
||||
ANDw_mask(x1, x1, 0, 1); //mask = 3
|
||||
CBNZw_MARK(x1);
|
||||
MARK3;
|
||||
CMPSx_U12(xRCX, 4);
|
||||
B_MARK(cCC);
|
||||
LDRw_S9_postindex(x1, xRSI, 4);
|
||||
STRw_S9_postindex(x1, xRDI, 4);
|
||||
SUBx_U12(xRCX, xRCX, 4);
|
||||
CBNZx_MARK3(xRCX);
|
||||
CBZx_MARKLOCK(xRCX);
|
||||
} else {
|
||||
if(BOX64DRENV(dynarec_safeflags)) {
|
||||
SUBx_REG(x2, xRDI, xRSI);
|
||||
CMPSx_U12(x2, 8);
|
||||
B_MARK(cCC);
|
||||
}
|
||||
// special optim for large RCX value on forward case only
|
||||
MARK3;
|
||||
CMPSx_U12(xRCX, 8);
|
||||
B_MARK(cCC);
|
||||
LDRx_S9_postindex(x1, xRSI, 8);
|
||||
STRx_S9_postindex(x1, xRDI, 8);
|
||||
SUBx_U12(xRCX, xRCX, 8);
|
||||
CBNZx_MARK3(xRCX);
|
||||
CBZx_MARKLOCK(xRCX);
|
||||
}
|
||||
MARK; // Part with DF==0
|
||||
LDRB_S9_postindex(x1, xRSI, 1);
|
||||
STRB_S9_postindex(x1, xRDI, 1);
|
||||
SUBx_U12(xRCX, xRCX, 1);
|
||||
CBNZx_MARK(xRCX);
|
||||
B_NEXT_nocond;
|
||||
B_MARKLOCK_nocond;
|
||||
MARK2; // Part with DF==1
|
||||
LDRB_S9_postindex(x1, xRSI, -1);
|
||||
STRB_S9_postindex(x1, xRDI, -1);
|
||||
SUBx_U12(xRCX, xRCX, 1);
|
||||
CBNZx_MARK2(xRCX);
|
||||
MARKLOCK;
|
||||
// done
|
||||
} else {
|
||||
INST_NAME("MOVSB");
|
||||
@@ -818,9 +875,11 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 1:
|
||||
case 2:
|
||||
if(rep==1) {INST_NAME("REPNZ CMPSW");} else {INST_NAME("REPZ CMPSW");}
|
||||
if(box64_dynarec_safeflags>1)
|
||||
MAYSETFLAGS();
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
CBZx_NEXT(xRCX);
|
||||
TBNZ_MARK2(xFlags, F_DF);
|
||||
MARK; // Part with DF==0
|
||||
@@ -918,9 +977,11 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 1:
|
||||
case 2:
|
||||
if(rep==1) {INST_NAME("REPNZ SCASW");} else {INST_NAME("REPZ SCASW");}
|
||||
if(box64_dynarec_safeflags>1)
|
||||
MAYSETFLAGS();
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
CBZx_NEXT(xRCX);
|
||||
UXTHw(x1, xRAX);
|
||||
TBNZ_MARK2(xFlags, F_DF);
|
||||
@@ -962,9 +1023,12 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0xBF:
|
||||
INST_NAME("MOV Reg16, Iw");
|
||||
u16 = F16;
|
||||
MOV32w(x1, u16);
|
||||
gd = TO_NAT((opcode & 7) + (rex.b << 3));
|
||||
BFIz(gd, x1, 0, 16);
|
||||
if(u16) {
|
||||
MOV32w(x1, u16);
|
||||
BFIz(gd, x1, 0, 16);
|
||||
} else
|
||||
BFCz(gd, 0, 16);
|
||||
break;
|
||||
|
||||
case 0xC1:
|
||||
@@ -972,7 +1036,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("ROL Ew, Ib");
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop) & 15;
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop) & 0x1f;
|
||||
if (u8) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
|
||||
GETEW(x1, 1);
|
||||
@@ -986,7 +1050,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("ROR Ew, Ib");
|
||||
if (geted_ib(dyn, addr, ninst, nextop) & 15) {
|
||||
if (geted_ib(dyn, addr, ninst, nextop) & 0x1f) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
|
||||
GETEW(x1, 1);
|
||||
u8 = (F8)&0x1f;
|
||||
@@ -999,7 +1063,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("RCL Ew, Ib");
|
||||
if (geted_ib(dyn, addr, ninst, nextop) & 31) {
|
||||
if (geted_ib(dyn, addr, ninst, nextop) & 0x1f) {
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
|
||||
GETEW(x1, 1);
|
||||
@@ -1013,7 +1077,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("RCR Ew, Ib");
|
||||
if (geted_ib(dyn, addr, ninst, nextop) & 31) {
|
||||
if (geted_ib(dyn, addr, ninst, nextop) & 0x1f) {
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
|
||||
GETEW(x1, 1);
|
||||
@@ -1074,13 +1138,20 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
u16 = F16;
|
||||
MOV32w(x1, u16);
|
||||
BFIz(ed, x1, 0, 16);
|
||||
if(u16) {
|
||||
MOV32w(x1, u16);
|
||||
BFIz(ed, x1, 0, 16);
|
||||
} else
|
||||
BFCz(ed, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, &lock, 0, 2);
|
||||
u16 = F16;
|
||||
MOV32w(x1, u16);
|
||||
STH(x1, ed, fixedaddress);
|
||||
if(u16) {
|
||||
MOV32w(x1, u16);
|
||||
STH(x1, ed, fixedaddress);
|
||||
} else {
|
||||
STH(xZR, ed, fixedaddress);
|
||||
}
|
||||
SMWRITELOCK(lock);
|
||||
}
|
||||
break;
|
||||
@@ -1148,9 +1219,10 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("ROL Ew, CL");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_OF|X_CF);
|
||||
}
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET);
|
||||
if(box64_dynarec_safeflags>1)
|
||||
MAYSETFLAGS();
|
||||
UFLAG_IF {
|
||||
ANDw_mask(x2, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
CBZw_NEXT(x2);
|
||||
@@ -1159,50 +1231,58 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOV32w(x4, 16);
|
||||
SUBx_REG(x2, x4, x2);
|
||||
GETEW(x1, 0);
|
||||
IFX2(X_OF, && !BOX64ENV(cputype)) {
|
||||
LSRw(x4, ed, 14);
|
||||
EORw_REG_LSR(x4, x4, x4, 1);
|
||||
BFIw(xFlags, x4, F_OF, 1);
|
||||
}
|
||||
ORRw_REG_LSL(ed, ed, ed, 16);
|
||||
LSRw_REG(ed, ed, x2);
|
||||
EWBACK;
|
||||
UFLAG_IF { // calculate flags directly
|
||||
SUBw_U12(x2, x2, 15);
|
||||
CBNZw_MARK(x2);
|
||||
EORw_REG_LSR(x3, ed, ed, 15);
|
||||
BFIw(xFlags, x3, F_OF, 1);
|
||||
MARK;
|
||||
IFX2(X_OF, && BOX64ENV(cputype)) {
|
||||
EORxw_REG_LSR(x3, ed, ed, 15);
|
||||
BFIw(xFlags, x3, F_OF, 1);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
BFIw(xFlags, ed, F_CF, 1);
|
||||
UFLAG_DF(x2, d_none);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("ROR Ew, CL");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_OF|X_CF);
|
||||
}
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET);
|
||||
if(box64_dynarec_safeflags>1)
|
||||
MAYSETFLAGS();
|
||||
UFLAG_IF {
|
||||
ANDw_mask(x2, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
CBZw_NEXT(x2);
|
||||
}
|
||||
ANDw_mask(x2, xRCX, 0, 0b00011); //mask=0x00000000f
|
||||
GETEW(x1, 0);
|
||||
IFX2(X_OF, && !BOX64ENV(cputype)) {
|
||||
EORw_REG_LSR(x4, ed, ed, 15);
|
||||
BFIw(xFlags, x4, F_OF, 1);
|
||||
}
|
||||
ORRw_REG_LSL(ed, ed, ed, 16);
|
||||
LSRw_REG(ed, ed, x2);
|
||||
EWBACK;
|
||||
UFLAG_IF { // calculate flags directly
|
||||
SUBw_U12(x2, x2, 1);
|
||||
CBNZw_MARK(x2);
|
||||
LSRxw(x2, ed, 14); // x2 = d>>14
|
||||
EORw_REG_LSR(x2, x2, x2, 1); // x2 = ((d>>14) ^ ((d>>14)>>1))
|
||||
BFIw(xFlags, x2, F_OF, 1);
|
||||
MARK;
|
||||
IFX2(X_OF, && BOX64ENV(cputype)) {
|
||||
LSRxw(x2, ed, 14); // x2 = d>>6
|
||||
EORw_REG_LSR(x2, x2, x2, 1); // x2 = ((d>>14) ^ ((d>>14)>>1))
|
||||
BFIw(xFlags, x2, F_OF, 1);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
BFXILw(xFlags, ed, 15, 1);
|
||||
UFLAG_DF(x2, d_none);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("RCL Ew, CL");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
if(box64_dynarec_safeflags>1)
|
||||
MAYSETFLAGS();
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (RCL Ex, CL)\n");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_OF|X_CF);
|
||||
} else {
|
||||
READFLAGS(X_CF);
|
||||
}
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
ANDw_mask(x2, xRCX, 0, 0b00100);
|
||||
GETEW(x1, 0);
|
||||
@@ -1211,10 +1291,12 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("RCR Ew, CL");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
if(box64_dynarec_safeflags>1)
|
||||
MAYSETFLAGS();
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (RCR Ew, CL)\n");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_OF|X_CF);
|
||||
} else {
|
||||
READFLAGS(X_CF);
|
||||
}
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
ANDw_mask(x2, xRCX, 0, 0b00100);
|
||||
GETEW(x1, 0);
|
||||
@@ -1224,9 +1306,11 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 4:
|
||||
case 6:
|
||||
INST_NAME("SHL Ew, CL");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
if(box64_dynarec_safeflags>1)
|
||||
MAYSETFLAGS();
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
ANDw_mask(x2, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
UFLAG_IF {
|
||||
CBZw_NEXT(x2);
|
||||
@@ -1237,9 +1321,11 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("SHR Ew, CL");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
if(box64_dynarec_safeflags>1)
|
||||
MAYSETFLAGS();
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
ANDw_mask(x2, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
UFLAG_IF {
|
||||
CBZw_NEXT(x2);
|
||||
@@ -1250,9 +1336,11 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("SAR Ew, CL");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
if(box64_dynarec_safeflags>1)
|
||||
MAYSETFLAGS();
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
ANDw_mask(x2, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
UFLAG_IF {
|
||||
CBZw_NEXT(x2);
|
||||
@@ -1264,7 +1352,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 0xD9:
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
@@ -1273,7 +1361,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
switch((nextop>>3)&7) {
|
||||
case 6:
|
||||
INST_NAME("FNSTENV Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (FNSTENV16)\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3); // maybe only x87, not SSE?
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
@@ -1293,7 +1381,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
switch((nextop>>3)&7) {
|
||||
case 4:
|
||||
INST_NAME("FRSTOR Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (FRSTOR16)\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
@@ -1301,7 +1389,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FNSAVE Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (FNSAVE16)\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
@@ -1329,9 +1417,15 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("NOT Ew");
|
||||
GETEW(x1, 0);
|
||||
MVNw_REG(ed, ed);
|
||||
EWBACK;
|
||||
if(MODREG) {
|
||||
CALCEW();
|
||||
int mask = convert_bitmask_x(0xffff);
|
||||
EORx_mask(wback, wback, (mask>>12)&1, mask&0x3F, (mask>>6)&0x3F);
|
||||
} else {
|
||||
GETEW(x1, 0);
|
||||
MVNw_REG(ed, ed);
|
||||
EWBACK;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("NEG Ew");
|
||||
@@ -1342,25 +1436,66 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("MUL AX, Ew");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
if(BOX64ENV(dynarec_safeflags) && BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
}
|
||||
GETEW(x1, 0);
|
||||
UXTHw(x2, xRAX);
|
||||
MULw(x1, x2, x1);
|
||||
UFLAG_RES(x1);
|
||||
BFIz(xRAX, x1, 0, 16);
|
||||
BFXILx(xRDX, x1, 16, 16);
|
||||
UFLAG_DF(x1, d_mul16);
|
||||
SET_DFNONE();
|
||||
IFX(X_CF|X_OF) {
|
||||
CMPSw_REG_LSR(xZR, x1, 16);
|
||||
CSETw(x3, cNE);
|
||||
IFX(X_CF) {
|
||||
BFIw(xFlags, x3, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BFIw(xFlags, x3, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX2(X_AF, && !BOX64ENV(cputype)) {BFCw(xFlags, F_AF, 1);}
|
||||
IFX2(X_ZF, && !BOX64ENV(cputype)) {BFCw(xFlags, F_ZF, 1);}
|
||||
IFX2(X_SF, && !BOX64ENV(cputype)) {
|
||||
LSRxw(x3, xRAX, 15);
|
||||
BFIw(xFlags, x3, F_SF, 1);
|
||||
}
|
||||
IFX2(X_PF, && !BOX64ENV(cputype)) emit_pf(dyn, ninst, xRAX, x3);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("IMUL AX, Ew");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
if(BOX64ENV(dynarec_safeflags) && BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
}
|
||||
GETSEW(x1, 0);
|
||||
SXTHw(x2, xRAX);
|
||||
MULw(x1, x2, x1);
|
||||
UFLAG_RES(x1);
|
||||
BFIz(xRAX, x1, 0, 16);
|
||||
BFXILx(xRDX, x1, 16, 16);
|
||||
UFLAG_DF(x1, d_imul16);
|
||||
SET_DFNONE();
|
||||
IFX(X_CF|X_OF) {
|
||||
ASRw(x2, x1, 15);
|
||||
CMPSw_REG_ASR(x2, x1, 31);
|
||||
CSETw(x3, cNE);
|
||||
IFX(X_CF) {
|
||||
BFIw(xFlags, x3, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BFIw(xFlags, x3, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX2(X_AF, && !BOX64ENV(cputype)) {BFCw(xFlags, F_AF, 1);}
|
||||
IFX2(X_ZF, && !BOX64ENV(cputype)) {BFCw(xFlags, F_ZF, 1);}
|
||||
IFX2(X_SF, && !BOX64ENV(cputype)) {
|
||||
LSRxw(x3, xRAX, 15);
|
||||
BFIw(xFlags, x3, F_SF, 1);
|
||||
}
|
||||
IFX2(X_PF, && !BOX64ENV(cputype)) emit_pf(dyn, ninst, xRAX, x3);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("DIV Ew");
|
||||
@@ -1368,7 +1503,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETEW(x1, 0);
|
||||
UXTHw(x2, xRAX);
|
||||
BFIw(x2, xRDX, 16, 16);
|
||||
if(box64_dynarec_div0) {
|
||||
if(BOX64ENV(dynarec_div0)) {
|
||||
CBNZw_MARK3(ed);
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
@@ -1382,19 +1517,27 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MSUBw(x4, x3, ed, x2); // x4 = x2 mod ed (i.e. x2 - x3*ed)
|
||||
BFIz(xRAX, x3, 0, 16);
|
||||
BFIz(xRDX, x4, 0, 16);
|
||||
SET_DFNONE(x2);
|
||||
IFX(X_AF | X_SF | X_CF | X_PF | X_ZF | X_OF)
|
||||
if(box64_dynarec_test) {
|
||||
MOV32w(x1, (1<<F_AF) | (1<<F_SF) | (1<<F_CF) | (1<<F_PF) | (1<<F_ZF) | (1<<F_OF));
|
||||
BICw(xFlags, xFlags, x1);
|
||||
}
|
||||
SET_DFNONE();
|
||||
IFX(X_OF) {BFCw(xFlags, F_OF, 1);}
|
||||
IFX(X_CF) {BFCw(xFlags, F_CF, 1);}
|
||||
IFX2(X_AF, && !BOX64ENV(cputype)) {BFCw(xFlags, F_AF, 1);}
|
||||
IFX2(X_AF, && BOX64ENV(cputype)) {ORRw_mask(xFlags, xFlags, 28, 0);} //mask=0x10
|
||||
IFX2(X_ZF, && !BOX64ENV(cputype)) {ORRw_mask(xFlags, xFlags, 26, 0);} //mask=0x40
|
||||
IFX2(X_ZF, && BOX64ENV(cputype)) {BFCw(xFlags, F_ZF, 1);}
|
||||
IFX(X_SF) {BFCw(xFlags, F_SF, 1);}
|
||||
IFX2(X_PF, && !BOX64ENV(cputype)) {ORRw_mask(xFlags, xFlags, 30, 0);} //mask=0x04
|
||||
IFX2(X_PF, && BOX64ENV(cputype)) {BFCw(xFlags, F_PF, 1);}
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("IDIV Ew");
|
||||
SKIPTEST(x1);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
if(!BOX64ENV(dynarec_safeflags)) {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
} else if(BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_SF|X_PF|X_ZF|X_AF, SF_SET);
|
||||
}
|
||||
GETSEW(x1, 0);
|
||||
if(box64_dynarec_div0) {
|
||||
if(BOX64ENV(dynarec_div0)) {
|
||||
CBNZw_MARK3(ed);
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
@@ -1410,25 +1553,26 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MSUBw(x4, x3, ed, x2); // x4 = x2 mod ed (i.e. x2 - x3*ed)
|
||||
BFIz(xRAX, x3, 0, 16);
|
||||
BFIz(xRDX, x4, 0, 16);
|
||||
SET_DFNONE(x2);
|
||||
IFX(X_AF | X_SF | X_CF | X_PF | X_ZF | X_OF)
|
||||
if(box64_dynarec_test) {
|
||||
MOV32w(x1, (1<<F_AF) | (1<<F_SF) | (1<<F_CF) | (1<<F_PF) | (1<<F_ZF) | (1<<F_OF));
|
||||
BICw(xFlags, xFlags, x1);
|
||||
}
|
||||
if(!BOX64ENV(dynarec_safeflags)) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFX2(X_AF, && BOX64ENV(cputype)) {ORRw_mask(xFlags, xFlags, 28, 0);} //mask=0x10
|
||||
IFX2(X_ZF, && BOX64ENV(cputype)) {BFCw(xFlags, F_ZF, 1);}
|
||||
IFX2(X_SF, && BOX64ENV(cputype)) {BFCw(xFlags, F_SF, 1);}
|
||||
IFX2(X_PF, && BOX64ENV(cputype)) {BFCw(xFlags, F_PF, 1);}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0xF8:
|
||||
INST_NAME("CLC");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
SET_DFNONE();
|
||||
BFCx(xFlags, F_CF, 1);
|
||||
break;
|
||||
case 0xF9:
|
||||
INST_NAME("STC");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
SET_DFNONE();
|
||||
ORRx_mask(xFlags, xFlags, 1, 0, 0); // xFlags | 1
|
||||
break;
|
||||
|
||||
|
||||
@@ -168,6 +168,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
SMWRITE2();
|
||||
break;
|
||||
|
||||
case 0x18:
|
||||
case 0x19:
|
||||
case 0x1F:
|
||||
INST_NAME("NOP (multibyte)");
|
||||
nextop = F8;
|
||||
@@ -231,7 +233,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGM(q0);
|
||||
GETEX(v1, 0, 0);
|
||||
if(box64_dynarec_fastround) {
|
||||
if(BOX64ENV(dynarec_fastround)) {
|
||||
VFCVTZSQD(q0, v1);
|
||||
SQXTN_32(q0, q0);
|
||||
} else {
|
||||
@@ -267,7 +269,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGM(q0);
|
||||
GETEX(v1, 0, 0);
|
||||
if(box64_dynarec_fastround) {
|
||||
if(BOX64ENV(dynarec_fastround)) {
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x3);
|
||||
VFRINTIDQ(q0, v1);
|
||||
FCVTXN(q0, q0);
|
||||
@@ -312,7 +314,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(v0, 0);
|
||||
GETEXSD(q0, 0, 0);
|
||||
FCMPD(v0, q0);
|
||||
FCOMI(x1, x2, 0, v0, q0, 0); //disable precise cmp
|
||||
FCOMI(x1, x2);
|
||||
break;
|
||||
|
||||
case 0x38: // SSSE3 opcodes
|
||||
@@ -475,7 +477,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
break;
|
||||
|
||||
case 0x14:
|
||||
INST_NAME("PBLENDVPS Gx,Ex");
|
||||
INST_NAME("BLENDVPS Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
@@ -483,13 +485,11 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
if(q0!=q1) {
|
||||
VSSHRQ_32(v1, v0, 31); // bit[31]-> bit[31..0]
|
||||
VBICQ(q0, q0, v1);
|
||||
VANDQ(v1, q1, v1);
|
||||
VORRQ(q0, q0, v1);
|
||||
VBITQ(q0, q1, v1);
|
||||
}
|
||||
break;
|
||||
case 0x15:
|
||||
INST_NAME("PBLENDVPD Gx,Ex");
|
||||
INST_NAME("BLENDVPD Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
@@ -497,9 +497,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
if(q0!=q1) {
|
||||
VSSHRQ_64(v1, v0, 63); // bit[63]-> bit[63..0]
|
||||
VBICQ(q0, q0, v1);
|
||||
VANDQ(v1, q1, v1);
|
||||
VORRQ(q0, q0, v1);
|
||||
VBITQ(q0, q1, v1);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -530,7 +528,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
MOV32w(x1, (1<<F_PF)|(1<<F_AF)|(1<<F_OF)|(1<<F_SF));
|
||||
BICw_REG(xFlags, xFlags, x1);
|
||||
}
|
||||
SET_DFNONE(x1);
|
||||
SET_DFNONE();
|
||||
break;
|
||||
|
||||
case 0x1C:
|
||||
@@ -924,13 +922,27 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
GETED(0);
|
||||
GETGD;
|
||||
MRS_nzcv(x3);
|
||||
BFIx(x3, xFlags, 29, 1); // set C
|
||||
MSR_nzcv(x3); // load CC into ARM CF
|
||||
IFNATIVE_BEFORE(NF_CF) {
|
||||
if(INVERTED_CARRY_BEFORE) {
|
||||
if(arm64_flagm)
|
||||
CFINV();
|
||||
else {
|
||||
MRS_nzcv(x3);
|
||||
EORx_mask(x3, x3, 1, 35, 0); //mask=1<<NZCV_C
|
||||
MSR_nzcv(x3);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
MRS_nzcv(x3);
|
||||
BFIx(x3, xFlags, 29, 1); // set C
|
||||
MSR_nzcv(x3); // load CC into ARM CF
|
||||
}
|
||||
IFX(X_CF) {
|
||||
ADCSxw_REG(gd, gd, ed);
|
||||
CSETw(x3, cCS);
|
||||
BFIw(xFlags, x3, F_CF, 1);
|
||||
IFNATIVE(NF_CF) {} else {
|
||||
CSETw(x3, cCS);
|
||||
BFIw(xFlags, x3, F_CF, 1);
|
||||
}
|
||||
} else {
|
||||
ADCxw_REG(gd, gd, ed);
|
||||
}
|
||||
@@ -1014,9 +1026,13 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
u8 = F8&0b1111;
|
||||
if(u8==0b0011) {
|
||||
VMOVeD(q0, 0, q1, 0);
|
||||
} else if(u8==0b1100) {
|
||||
u8&=~0b0011;
|
||||
}
|
||||
if(u8==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);
|
||||
}
|
||||
@@ -1224,6 +1240,27 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x41:
|
||||
INST_NAME("DPPD Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 1);
|
||||
u8 = F8;
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
VFMULQD(v0, q0, q1);
|
||||
// mask some, duplicate all, mask some
|
||||
for(int i=0; i<2; ++i)
|
||||
if(!(u8&(1<<(4+i)))) {
|
||||
VMOVQDfrom(v0, i, xZR);
|
||||
}
|
||||
FADDPD(v0, v0);
|
||||
VDUPQ_64(q0, v0, 0);
|
||||
for(int i=0; i<2; ++i)
|
||||
if(!(u8&(1<<i))) {
|
||||
VMOVQDfrom(q0, i, xZR);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x44:
|
||||
INST_NAME("PCLMULQDQ Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
@@ -1404,7 +1441,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
// flags
|
||||
IFX(X_ALL) {
|
||||
SET_DFNONE(x4);
|
||||
SET_DFNONE();
|
||||
IFX(X_CF) {
|
||||
CMPSw_REG(x1, xZR);
|
||||
CSETw(x4, cNE);
|
||||
@@ -1417,7 +1454,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
CSETw(x5, cLT);
|
||||
BFIw(xFlags, x5, F_ZF, 1);
|
||||
}
|
||||
IFX(F_SF) {
|
||||
IFX(X_SF) {
|
||||
CMPSw_REG(x2, x4);
|
||||
CSETw(x5, cLT);
|
||||
BFIw(xFlags, x5, F_SF, 1);
|
||||
@@ -1626,7 +1663,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX_empty(q1);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
@@ -1681,7 +1718,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX(q1, 1);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
@@ -1689,7 +1726,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VFCMEQQD(v0, v0, v0); // 0 if NAN, 1 if not NAN
|
||||
}
|
||||
VFADDQD(q1, q1, q0);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
VFCMEQQD(v1, q1, q1); // 0 => out is NAN
|
||||
VBICQ(v1, v0, v1); // forget it in any input was a NAN already
|
||||
VSHLQ_64(v1, v1, 63); // only keep the sign bit
|
||||
@@ -1701,7 +1738,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX(q1, 1);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
@@ -1709,7 +1746,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VFCMEQQD(v0, v0, v0); // 0 if NAN, 1 if not NAN
|
||||
}
|
||||
VFMULQD(q1, q1, q0);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
VFCMEQQD(v1, q1, q1); // 0 => out is NAN
|
||||
VBICQ(v1, v0, v1); // forget it in any input was a NAN already
|
||||
VSHLQ_64(v1, v1, 63); // only keep the sign bit
|
||||
@@ -1721,7 +1758,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETEX(v1, 0, 0);
|
||||
GETGX_empty(v0);
|
||||
if(box64_dynarec_fastround==2) {
|
||||
if(BOX64ENV(dynarec_fastround)==2) {
|
||||
FCVTXN(v0, v1);
|
||||
} else {
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x3);
|
||||
@@ -1734,7 +1771,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETEX(v1, 0, 0);
|
||||
GETGX_empty(v0);
|
||||
if(box64_dynarec_fastround) {
|
||||
if(BOX64ENV(dynarec_fastround)) {
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x3);
|
||||
VFRINTISQ(v0, v1);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
@@ -1769,7 +1806,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX(q1, 1);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
@@ -1777,7 +1814,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VFCMEQQD(v0, v0, v0); // 0 if NAN, 1 if not NAN
|
||||
}
|
||||
VFSUBQD(q1, q1, q0);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
VFCMEQQD(v1, q1, q1); // 0 => out is NAN
|
||||
VBICQ(v1, v0, v1); // forget it in any input was a NAN already
|
||||
VSHLQ_64(v1, v1, 63); // only keep the sign bit
|
||||
@@ -1791,7 +1828,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETEX(v1, 0, 0);
|
||||
// FMIN/FMAX wll not copy the value if v0[x] is NaN
|
||||
// but x86 will copy if either v0[x] or v1[x] is NaN, so lets force a copy if source is NaN
|
||||
if(!box64_dynarec_fastnan && v0!=v1) {
|
||||
if(!BOX64ENV(dynarec_fastnan) && v0!=v1) {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
VFCMEQQD(q0, v0, v0); // 0 is NaN, 1 is not NaN, so MASK for NaN
|
||||
VANDQ(v0, v0, q0);
|
||||
@@ -1805,7 +1842,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX(q1, 1);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
@@ -1813,7 +1850,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VFCMEQQD(v0, v0, v0); // 0 if NAN, 1 if not NAN
|
||||
}
|
||||
VFDIVQD(q1, q1, q0);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
VFCMEQQD(v1, q1, q1); // 0 => out is NAN
|
||||
VBICQ(v1, v0, v1); // forget it in any input was a NAN already
|
||||
VSHLQ_64(v1, v1, 63); // only keep the sign bit
|
||||
@@ -1827,7 +1864,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETEX(v1, 0, 0);
|
||||
// FMIN/FMAX wll not copy the value if v0[x] is NaN
|
||||
// but x86 will copy if either v0[x] or v1[x] is NaN, so lets force a copy if source is NaN
|
||||
if(!box64_dynarec_fastnan && v0!=v1) {
|
||||
if(!BOX64ENV(dynarec_fastnan) && v0!=v1) {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
VFCMEQQD(q0, v0, v0); // 0 is NaN, 1 is not NaN, so MASK for NaN
|
||||
VANDQ(v0, v0, q0);
|
||||
@@ -2247,7 +2284,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(q1, 1);
|
||||
GETEX(q0, 0, 0);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
@@ -2258,7 +2295,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VFCMEQQD(v0, v0, v0); // 0 if NAN, 1 if not NAN
|
||||
}
|
||||
VFADDPQD(q1, q1, q0);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
VFCMEQQD(v1, q1, q1); // 0 => out is NAN
|
||||
VBICQ(v1, v0, v1); // forget it in any input was a NAN already
|
||||
VSHLQ_64(v1, v1, 63); // only keep the sign bit
|
||||
@@ -2315,8 +2352,11 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
|
||||
case 0xA3:
|
||||
INST_NAME("BT Ew, Gw");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
if(!BOX64ENV(dynarec_safeflags)) {
|
||||
SETFLAGS(X_ALL&~X_ZF, SF_SUBSET);
|
||||
} else {
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
}
|
||||
nextop = F8;
|
||||
gd = TO_NAT(((nextop & 0x38) >> 3) + (rex.r << 3)); // GETGD
|
||||
if(MODREG) {
|
||||
@@ -2354,9 +2394,11 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
case 0xA5:
|
||||
nextop = F8;
|
||||
INST_NAME("SHLD Ew, Gw, CL");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
if(box64_dynarec_safeflags>1)
|
||||
MAYSETFLAGS();
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
ANDw_mask(x4, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
@@ -2369,8 +2411,11 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
|
||||
case 0xAB:
|
||||
INST_NAME("BTS Ew, Gw");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
if(!BOX64ENV(dynarec_safeflags)) {
|
||||
SETFLAGS(X_ALL&~X_ZF, SF_SUBSET);
|
||||
} else {
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
}
|
||||
nextop = F8;
|
||||
gd = TO_NAT(((nextop & 0x38) >> 3) + (rex.r << 3)); // GETGD
|
||||
if(MODREG) {
|
||||
@@ -2394,6 +2439,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
ORRx_REG(ed, ed, x1);
|
||||
if(wback) {
|
||||
STH(ed, wback, fixedaddress);
|
||||
SMWRITE();
|
||||
}
|
||||
break;
|
||||
case 0xAC:
|
||||
@@ -2415,9 +2461,11 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
case 0xAD:
|
||||
nextop = F8;
|
||||
INST_NAME("SHRD Ew, Gw, CL");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
if(box64_dynarec_safeflags>1)
|
||||
MAYSETFLAGS();
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
ANDw_mask(x4, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
@@ -2428,23 +2476,77 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
emit_shrd16(dyn, ninst, ed, gd, x4, x5, x6);
|
||||
EWBACK;
|
||||
break;
|
||||
|
||||
case 0xAE:
|
||||
nextop = F8;
|
||||
if(MODREG)
|
||||
switch (nextop) {
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
else
|
||||
switch((nextop>>3)&7) {
|
||||
case 6:
|
||||
INST_NAME("CLWB Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (CLWB)?\n");
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {
|
||||
MOVx_REG(x1, ed);
|
||||
}
|
||||
CALL_(native_clflush, -1, 0);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("CLFLUSHOPT Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (CLFLUSHOPT)?\n");
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {
|
||||
MOVx_REG(x1, ed);
|
||||
}
|
||||
CALL_(native_clflush, -1, 0);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0xAF:
|
||||
INST_NAME("IMUL Gw,Ew");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
if(BOX64ENV(dynarec_safeflags) && BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
}
|
||||
nextop = F8;
|
||||
GETSEW(x1, 0);
|
||||
GETSGW(x2);
|
||||
MULw(x2, x2, x1);
|
||||
UFLAG_RES(x2);
|
||||
GWBACK;
|
||||
UFLAG_DF(x1, d_imul16);
|
||||
SET_DFNONE();
|
||||
IFX(X_CF|X_OF) {
|
||||
ASRw(x1, x2, 15);
|
||||
CMPSw_REG_ASR(x1, x2, 31);
|
||||
CSETw(x3, cNE);
|
||||
IFX(X_CF) {
|
||||
BFIw(xFlags, x3, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BFIw(xFlags, x3, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX2(X_AF, && !BOX64ENV(cputype)) {BFCw(xFlags, F_AF, 1);}
|
||||
IFX2(X_ZF, && !BOX64ENV(cputype)) {BFCw(xFlags, F_ZF, 1);}
|
||||
IFX2(X_SF, && !BOX64ENV(cputype)) {
|
||||
LSRxw(x3, gd, 15);
|
||||
BFIw(xFlags, x3, F_SF, 1);
|
||||
}
|
||||
IFX2(X_PF, && !BOX64ENV(cputype)) emit_pf(dyn, ninst, gd, x3);
|
||||
break;
|
||||
|
||||
case 0xB3:
|
||||
INST_NAME("BTR Ew, Gw");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
if(!BOX64ENV(dynarec_safeflags)) {
|
||||
SETFLAGS(X_ALL&~X_ZF, SF_SUBSET);
|
||||
} else {
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
}
|
||||
nextop = F8;
|
||||
gd = TO_NAT(((nextop & 0x38) >> 3) + (rex.r << 3)); // GETGD
|
||||
if(MODREG) {
|
||||
@@ -2513,18 +2615,26 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
switch((nextop>>3)&7) {
|
||||
case 4:
|
||||
INST_NAME("BT Ew, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
if(!BOX64ENV(dynarec_safeflags)) {
|
||||
SETFLAGS(X_ALL&~X_ZF, SF_SUBSET);
|
||||
} else {
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
}
|
||||
gd = x2;
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
u8&=rex.w?0x3f:0x0f;
|
||||
BFXILxw(xFlags, ed, u8, 1); // inject 1 bit from u8 to F_CF (i.e. pos 0)
|
||||
IFX(X_CF) {
|
||||
BFXILxw(xFlags, ed, u8, 1); // inject 1 bit from u8 to F_CF (i.e. pos 0)
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("BTS Ew, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
if(!BOX64ENV(dynarec_safeflags)) {
|
||||
SETFLAGS(X_ALL&~X_ZF, SF_SUBSET);
|
||||
} else {
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
}
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
u8&=(rex.w?0x3f:0x0f);
|
||||
@@ -2537,8 +2647,11 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("BTR Ew, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
if(!BOX64ENV(dynarec_safeflags)) {
|
||||
SETFLAGS(X_ALL&~X_ZF, SF_SUBSET);
|
||||
} else {
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
}
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
u8&=(rex.w?0x3f:0x0f);
|
||||
@@ -2550,8 +2663,11 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("BTC Ew, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
if(!BOX64ENV(dynarec_safeflags)) {
|
||||
SETFLAGS(X_ALL&~X_ZF, SF_SUBSET);
|
||||
} else {
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
}
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
u8&=(rex.w?0x3f:0x0f);
|
||||
@@ -2568,8 +2684,11 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
break;
|
||||
case 0xBB:
|
||||
INST_NAME("BTC Ew, Gw");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
if(!BOX64ENV(dynarec_safeflags)) {
|
||||
SETFLAGS(X_ALL&~X_ZF, SF_SUBSET);
|
||||
} else {
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
}
|
||||
nextop = F8;
|
||||
gd = TO_NAT(((nextop & 0x38) >> 3) + (rex.r << 3)); // GETGD
|
||||
if(MODREG) {
|
||||
@@ -2600,7 +2719,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
case 0xBC:
|
||||
INST_NAME("BSF Gw,Ew");
|
||||
SETFLAGS(X_ZF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEW(x1, 0); // Get EW
|
||||
@@ -2624,7 +2743,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
case 0xBD:
|
||||
INST_NAME("BSR Gw,Ew");
|
||||
SETFLAGS(X_ZF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEW(x1, 0); // Get EW
|
||||
@@ -2882,20 +3001,17 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEX(q0, 0, 0);
|
||||
GETGD;
|
||||
TABLE64(x1, (uintptr_t)&mask_shift8);
|
||||
VLDR64_U12(v0, x1, 0); // load shift
|
||||
MOVI_8(v1, 0x80); // load mask
|
||||
VAND(q1, v1, q0);
|
||||
USHL_8(q1, q1, v0); // shift
|
||||
UADDLV_8(q1, q1); // accumalte
|
||||
VMOVBto(gd, q1, 0);
|
||||
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, q0, 1);
|
||||
VAND(q1, v1, q1); // keep highest bit
|
||||
USHL_8(q1, q1, v0); // shift
|
||||
VMOVeD(q1, 0, q1, 1);
|
||||
UADDLV_8(q1, q1); // accumalte
|
||||
VMOVBto(x1, q1, 0);
|
||||
BFIx(gd, x1, 8, 8);
|
||||
VMOVBto(x2, q1, 0);
|
||||
BFIw(gd, x2, 8, 8);
|
||||
break;
|
||||
case 0xD8:
|
||||
INST_NAME("PSUBUSB Gx, Ex");
|
||||
@@ -3024,7 +3140,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETEX(v1, 0, 0);
|
||||
GETGX_empty(v0);
|
||||
if(box64_dynarec_fastround) {
|
||||
if(BOX64ENV(dynarec_fastround)) {
|
||||
VFCVTZSQD(v0, v1); // convert double -> int64
|
||||
SQXTN_32(v0, v0); // convert int64 -> int32 with saturation in lower part, RaZ high part
|
||||
} else {
|
||||
|
||||
@@ -58,17 +58,16 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3), 0);
|
||||
} else {
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
ADDz_REG(x4, x4, ed);
|
||||
ed = x4;
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
if(rex.is32bits)
|
||||
VLDR64_REG_SXTW(v1, x4, ed);
|
||||
else
|
||||
VLDR64_REG(v1, ed, x4);
|
||||
VLD64(v1, ed, fixedaddress);
|
||||
}
|
||||
FCMPD(v0, v1);
|
||||
FCOMI(x1, x2, 0, v0, v1, 0); //disable precise cmp
|
||||
FCOMI(x1, x2);
|
||||
break;
|
||||
|
||||
case 0x6F:
|
||||
@@ -80,13 +79,12 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VMOVQ(v0, v1);
|
||||
} else {
|
||||
GETGX_empty(v0);
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
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);
|
||||
SMREAD();
|
||||
if(rex.is32bits)
|
||||
VLDR128_REG_SXTW(v0, x4, ed);
|
||||
else
|
||||
VLDR128_REG(v0, ed, x4);
|
||||
ADDz_REG(x4, x4, ed);
|
||||
ed = x4;
|
||||
VLD128(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -98,12 +96,11 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 1);
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(rex.is32bits)
|
||||
VSTR128_REG_SXTW(v0, x4, ed);
|
||||
else
|
||||
VSTR128_REG(v0, ed, x4);
|
||||
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);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
@@ -117,12 +114,11 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, (nextop&7) + (rex.b<<3));
|
||||
FMOVD(v1, v0);
|
||||
} else {
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(rex.is32bits)
|
||||
VSTR64_REG_SXTW(v0, x4, ed);
|
||||
else
|
||||
VSTR64_REG(v0, ed, x4);
|
||||
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);
|
||||
SMWRITE();
|
||||
}
|
||||
break;
|
||||
@@ -138,7 +134,7 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
case 0: //ADD
|
||||
if(opcode==0x81) {INST_NAME("ADD Ew, Iw");} else {INST_NAME("ADD Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_segdata(dyn, addr, ninst, x1, seg);
|
||||
grab_segdata(dyn, addr, ninst, x1, seg, (MODREG));
|
||||
GETEWO(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOVZw(x5, i16);
|
||||
@@ -148,7 +144,7 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
case 1: //OR
|
||||
if(opcode==0x81) {INST_NAME("OR Ew, Iw");} else {INST_NAME("OR Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_segdata(dyn, addr, ninst, x1, seg);
|
||||
grab_segdata(dyn, addr, ninst, x1, seg, (MODREG));
|
||||
GETEWO(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
emit_or16c(dyn, ninst, x1, i16, x2, x4);
|
||||
@@ -158,7 +154,7 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(opcode==0x81) {INST_NAME("ADC Ew, Iw");} else {INST_NAME("ADC Ew, Ib");}
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_segdata(dyn, addr, ninst, x1, seg);
|
||||
grab_segdata(dyn, addr, ninst, x1, seg, (MODREG));
|
||||
GETEWO(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOVZw(x5, i16);
|
||||
@@ -169,7 +165,7 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(opcode==0x81) {INST_NAME("SBB Ew, Iw");} else {INST_NAME("SBB Ew, Ib");}
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_segdata(dyn, addr, ninst, x1, seg);
|
||||
grab_segdata(dyn, addr, ninst, x1, seg, (MODREG));
|
||||
GETEWO(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOVZw(x5, i16);
|
||||
@@ -179,7 +175,7 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
case 4: //AND
|
||||
if(opcode==0x81) {INST_NAME("AND Ew, Iw");} else {INST_NAME("AND Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_segdata(dyn, addr, ninst, x1, seg);
|
||||
grab_segdata(dyn, addr, ninst, x1, seg, (MODREG));
|
||||
GETEWO(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
emit_and16c(dyn, ninst, x1, i16, x2, x4);
|
||||
@@ -188,7 +184,7 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
case 5: //SUB
|
||||
if(opcode==0x81) {INST_NAME("SUB Ew, Iw");} else {INST_NAME("SUB Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_segdata(dyn, addr, ninst, x1, seg);
|
||||
grab_segdata(dyn, addr, ninst, x1, seg, (MODREG));
|
||||
GETEWO(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOVZw(x5, i16);
|
||||
@@ -198,7 +194,7 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
case 6: //XOR
|
||||
if(opcode==0x81) {INST_NAME("XOR Ew, Iw");} else {INST_NAME("XOR Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_segdata(dyn, addr, ninst, x1, seg);
|
||||
grab_segdata(dyn, addr, ninst, x1, seg, (MODREG));
|
||||
GETEWO(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
emit_xor16c(dyn, ninst, x1, i16, x2, x4);
|
||||
@@ -207,7 +203,7 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
case 7: //CMP
|
||||
if(opcode==0x81) {INST_NAME("CMP Ew, Iw");} else {INST_NAME("CMP Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_segdata(dyn, addr, ninst, x1, seg);
|
||||
grab_segdata(dyn, addr, ninst, x1, seg, (MODREG));
|
||||
GETEWO(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
if(i16) {
|
||||
@@ -233,15 +229,14 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
}
|
||||
} else {
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<(rex.w?3:1), rex.w?7:1, rex, NULL, 0, 0);
|
||||
ADDz_REG(x4, x4, ed);
|
||||
ed = x4;
|
||||
if(rex.w) {
|
||||
STRx_REG(gd, ed, x4);
|
||||
STx(gd, ed, fixedaddress);
|
||||
} else {
|
||||
if(rex.is32bits)
|
||||
STRH_REG_SXTW(gd, x4, ed);
|
||||
else
|
||||
STRH_REG(gd, ed, x4);
|
||||
STH(gd, ed, fixedaddress);
|
||||
}
|
||||
SMWRITE();
|
||||
}
|
||||
@@ -261,16 +256,15 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
}
|
||||
} else { // mem <= reg
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<(rex.w?3:1), rex.w?7:1, rex, NULL, 0, 0);
|
||||
ADDz_REG(x4, x4, ed);
|
||||
ed = x4;
|
||||
if(rex.w) {
|
||||
LDRx_REG(gd, ed, x4);
|
||||
LDx(gd, ed, fixedaddress);
|
||||
} else {
|
||||
if(rex.is32bits)
|
||||
LDRH_REG_SXTW(x1, x4, ed);
|
||||
else
|
||||
LDRH_REG(x1, ed, x4);
|
||||
LDH(x1, ed, fixedaddress);
|
||||
BFIx(gd, x1, 0, 16);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,6 +158,8 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
MARK3;
|
||||
LDRH_U12(x1, wback, 0);
|
||||
LDAXRB(x3, wback); // dummy read, to arm the write...
|
||||
SUBw_UXTB(x3, x3, x1);
|
||||
CBNZw_MARK3(x3);
|
||||
CMPSw_REG(x6, x1);
|
||||
B_MARK(cNE);
|
||||
// EAX == Ed
|
||||
@@ -166,8 +168,8 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
STRH_U12(gd, wback, 0);
|
||||
}
|
||||
}
|
||||
SMDMB();
|
||||
MARK;
|
||||
SMDMB();
|
||||
// Common part (and fallback for EAX != Ed)
|
||||
UFLAG_IF {emit_cmp16(dyn, ninst, x6, x1, x3, x4, x5);}
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
@@ -295,30 +297,36 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
}
|
||||
if(arm64_atomics) {
|
||||
LDADDALH(x5, x1, wback);
|
||||
UFLAG_IF {
|
||||
emit_add16(dyn, ninst, x1, x5, x3, x4);
|
||||
LDADDALH(x5, x1, wback);
|
||||
} else {
|
||||
STADDLH(x5, wback);
|
||||
}
|
||||
} else {
|
||||
MARKLOCK;
|
||||
LDAXRH(x1, wback);
|
||||
emit_add16(dyn, ninst, x1, x5, x3, x4);
|
||||
STLXRH(x3, x1, wback);
|
||||
ADDw_REG(x4, x1, x5);
|
||||
STLXRH(x3, x4, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
SMDMB();
|
||||
if(!ALIGNED_ATOMICH) {
|
||||
B_NEXT_nocond;
|
||||
B_MARK2_nocond;
|
||||
MARK; // unaligned! also, not enough
|
||||
LDRH_U12(x1, wback, 0);
|
||||
LDAXRB(x4, wback);
|
||||
BFIw(x1, x4, 0, 8); // re-inject
|
||||
emit_add16(dyn, ninst, x1, x5, x3, x4);
|
||||
STLXRB(x3, x1, wback);
|
||||
SUBw_UXTB(x4, x4, x1);
|
||||
CBNZw_MARK(x4);
|
||||
ADDw_REG(x4, x1, x5);
|
||||
STLXRB(x3, x4, wback);
|
||||
CBNZx_MARK(x3);
|
||||
STRH_U12(x1, wback, 0); // put the whole value
|
||||
STRH_U12(x4, wback, 0); // put the whole value
|
||||
SMDMB();
|
||||
}
|
||||
MARK2;
|
||||
UFLAG_IF {
|
||||
emit_add16(dyn, ninst, x1, x5, x3, x4);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1: //OR
|
||||
@@ -472,30 +480,34 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
NEGw_REG(x4, x5);
|
||||
UFLAG_IF {
|
||||
LDADDALH(x4, x1, wback);
|
||||
emit_sub16(dyn, ninst, x1, x5, x3, x4);
|
||||
} else {
|
||||
STADDLH(x4, wback);
|
||||
}
|
||||
} else {
|
||||
MARKLOCK;
|
||||
LDAXRH(x1, wback);
|
||||
emit_sub16(dyn, ninst, x1, x5, x3, x4);
|
||||
SUBw_REG(x4, x1, x5);
|
||||
STLXRH(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
SMDMB();
|
||||
if(!ALIGNED_ATOMICH) {
|
||||
B_NEXT_nocond;
|
||||
B_MARK2_nocond;
|
||||
MARK; // unaligned! also, not enough
|
||||
LDRH_U12(x1, wback, 0);
|
||||
LDAXRB(x4, wback);
|
||||
BFIw(x1, x4, 0, 8); // re-inject
|
||||
emit_sub16(dyn, ninst, x1, x5, x3, x4);
|
||||
STLXRB(x3, x1, wback);
|
||||
SUBw_UXTB(x4, x4, x1);
|
||||
CBNZw_MARK(x4);
|
||||
SUBw_REG(x4, x1, x5);
|
||||
STLXRB(x3, x4, wback);
|
||||
CBNZx_MARK(x3);
|
||||
STRH_U12(x1, wback, 0); // put the whole value
|
||||
STRH_U12(x4, wback, 0); // put the whole value
|
||||
SMDMB();
|
||||
}
|
||||
MARK2;
|
||||
UFLAG_IF {
|
||||
emit_sub16(dyn, ninst, x1, x5, x3, x4);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 6: //XOR
|
||||
|
||||
@@ -55,11 +55,64 @@ uintptr_t dynarec64_66F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
#endif
|
||||
|
||||
switch(opcode) {
|
||||
case 0xB8:
|
||||
INST_NAME("POPCNT Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
VEORQ(v1, v1, v1);
|
||||
VMOVQDfrom(v1, 0, ed);
|
||||
CNT_8(v1, v1);
|
||||
UADDLV_8(v1, v1);
|
||||
VMOVHto(gd, v1, 0);
|
||||
IFX(X_ALL) {
|
||||
IFX(X_AF|X_PF|X_SF|X_OF|X_CF) {
|
||||
MOV32w(x1, (1<<F_OF) | (1<<F_SF) | (1<<F_ZF) | (1<<F_AF) | (1<<F_CF) | (1<<F_PF));
|
||||
BICw(xFlags, xFlags, x1);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CMPSw_U12(gd, 0);
|
||||
IFNATIVE(NF_EQ) {}
|
||||
else {
|
||||
CSETw(x1, cEQ);
|
||||
BFIw(xFlags, x1, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
GWBACK;
|
||||
break;
|
||||
|
||||
case 0xBC:
|
||||
INST_NAME("TZCNT Gw, Ew");
|
||||
SETFLAGS(X_CF|X_ZF, SF_SUBSET);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETEW(x1, 0);
|
||||
GETGW(x2);
|
||||
TSTxw_REG(ed, ed);
|
||||
IFX(X_CF) {
|
||||
CSETw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_CF, 1); // CF = is source 0?
|
||||
}
|
||||
RBITw(x3, ed); // reverse
|
||||
CLZw(gd, x3); // x2 gets leading 0 == TZCNT
|
||||
MOV32w(x3, 16);
|
||||
CSELw(gd, x3, gd, cEQ); // if src is zero, use bit width as res
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(gd, gd);
|
||||
CSETw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_ZF, 1); // ZF = is dest 0?
|
||||
}
|
||||
GWBACK;
|
||||
break;
|
||||
|
||||
case 0xBD:
|
||||
INST_NAME("LZCNT Gw, Ew");
|
||||
SETFLAGS(X_CF|X_ZF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETEW(x1, 0);
|
||||
GETGW(x2);
|
||||
@@ -68,14 +121,14 @@ uintptr_t dynarec64_66F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
CSETw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_CF, 1); // CF = is source 0?
|
||||
}
|
||||
LSLw_IMM(ed, ed, 16);
|
||||
CLZw(gd, ed);
|
||||
SUBw_U12(gd, gd, 16); // sub zero cnt of high word
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(gd, gd);
|
||||
CSETw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_ZF, 1); // ZF = is dest 0?
|
||||
}
|
||||
EWBACK;
|
||||
GWBACK;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -38,6 +38,7 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
int32_t i32;
|
||||
int64_t j64, i64;
|
||||
int16_t i16;
|
||||
uint64_t u64;
|
||||
int cacheupd = 0;
|
||||
int lock;
|
||||
int v0, v1, s0;
|
||||
@@ -57,7 +58,7 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
|
||||
|
||||
while(opcode==0x67) opcode = F8;
|
||||
|
||||
|
||||
// reset rex after 67
|
||||
GETREX();
|
||||
|
||||
@@ -215,7 +216,7 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
}
|
||||
FCMPS(v0, s0);
|
||||
FCOMI(x1, x2, 0, v0, s0, 1); //disabled precise cmp
|
||||
FCOMI(x1, x2);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
@@ -916,7 +917,11 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
|
||||
case 0x6B:
|
||||
INST_NAME("IMUL Gd, Ed, Ib");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
if(BOX64ENV(dynarec_safeflags)>1 && BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
}
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED32(1);
|
||||
@@ -927,14 +932,9 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
UFLAG_IF {
|
||||
SMULH(x3, ed, x4);
|
||||
MULx(gd, ed, x4);
|
||||
SET_DFNONE(x1);
|
||||
IFX(X_ZF | X_PF | X_AF | X_SF) {
|
||||
MOV32w(x1, (1<<F_ZF)|(1<<F_AF)|(1<<F_PF)|(1<<F_SF));
|
||||
BICw(xFlags, xFlags, x1);
|
||||
}
|
||||
SET_DFNONE();
|
||||
IFX(X_CF | X_OF) {
|
||||
ASRx(x4, gd, 63);
|
||||
CMPSx_REG(x3, x4);
|
||||
CMPSx_REG_ASR(x3, gd, 63);
|
||||
CSETw(x1, cNE);
|
||||
IFX(X_CF) {
|
||||
BFIw(xFlags, x1, F_CF, 1);
|
||||
@@ -952,14 +952,9 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SMULL(gd, ed, x4);
|
||||
LSRx(x3, gd, 32);
|
||||
MOVw_REG(gd, gd);
|
||||
SET_DFNONE(x1);
|
||||
IFX(X_ZF | X_PF | X_AF | X_SF) {
|
||||
MOV32w(x1, (1<<F_ZF)|(1<<F_AF)|(1<<F_PF)|(1<<F_SF));
|
||||
BICw(xFlags, xFlags, x1);
|
||||
}
|
||||
SET_DFNONE();
|
||||
IFX(X_CF | X_OF) {
|
||||
ASRw(x4, gd, 31);
|
||||
CMPSw_REG(x3, x4);
|
||||
CMPSw_REG_ASR(x3, gd, 31);
|
||||
CSETw(x1, cNE);
|
||||
IFX(X_CF) {
|
||||
BFIw(xFlags, x1, F_CF, 1);
|
||||
@@ -972,6 +967,13 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MULxw(gd, ed, x4);
|
||||
}
|
||||
}
|
||||
IFX2(X_AF, && !BOX64ENV(cputype)) {BFCw(xFlags, F_AF, 1);}
|
||||
IFX2(X_ZF, && !BOX64ENV(cputype)) {BFCw(xFlags, F_ZF, 1);}
|
||||
IFX2(X_SF, && !BOX64ENV(cputype)) {
|
||||
LSRxw(x3, gd, rex.w?63:31);
|
||||
BFIw(xFlags, x3, F_SF, 1);
|
||||
}
|
||||
IFX2(X_PF, && !BOX64ENV(cputype)) emit_pf(dyn, ninst, gd, x3);
|
||||
break;
|
||||
|
||||
case 0x70:
|
||||
@@ -1171,9 +1173,7 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
DEFAULT;
|
||||
} else { // mem <= reg
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, gd, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=gd) {
|
||||
MOVw_REG(gd, ed);
|
||||
}
|
||||
MOVw_REG(gd, ed); // need to trucate to 32bits as it's 67 prefixed
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1196,6 +1196,15 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xA1:
|
||||
INST_NAME("MOV EAX,Od");
|
||||
u64 = F32;
|
||||
MOV64z(x1, u64);
|
||||
lock=isLockAddress(u64);
|
||||
SMREADLOCK(lock);
|
||||
LDRxw_U12(xRAX, x1, 0);
|
||||
break;
|
||||
|
||||
case 0xA9:
|
||||
INST_NAME("TEST EAX, Id");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
@@ -1457,7 +1466,11 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("MUL EAX, Ed");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
if(BOX64ENV(dynarec_safeflags) && BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
}
|
||||
GETED32(0);
|
||||
if(rex.w) {
|
||||
if(ed==xRDX) gd=x3; else gd=xRDX;
|
||||
@@ -1469,29 +1482,32 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOVw_REG(xRAX, xRDX);
|
||||
LSRx(xRDX, xRDX, 32);
|
||||
}
|
||||
UFLAG_IF {
|
||||
SET_DFNONE(x4);
|
||||
IFX(X_CF|X_OF) {
|
||||
CMPSxw_U12(xRDX, 0);
|
||||
CSETw(x3, cNE);
|
||||
IFX(X_CF) {
|
||||
BFIw(xFlags, x3, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BFIw(xFlags, x3, F_OF, 1);
|
||||
}
|
||||
SET_DFNONE();
|
||||
IFX(X_CF|X_OF) {
|
||||
CMPSxw_U12(xRDX, 0);
|
||||
CSETw(x3, cNE);
|
||||
IFX(X_CF) {
|
||||
BFIw(xFlags, x3, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BFIw(xFlags, x3, F_OF, 1);
|
||||
}
|
||||
IFX(X_AF | X_PF | X_ZF | X_SF)
|
||||
if(box64_dynarec_test) {
|
||||
// to avoid noise during test
|
||||
MOV32w(x3, (1<<F_ZF)|(1<<F_AF)|(1<<F_PF)|(1<<F_SF));
|
||||
BICw(xFlags, xFlags, x3);
|
||||
}
|
||||
}
|
||||
IFX2(X_AF, && !BOX64ENV(cputype)) {BFCw(xFlags, F_AF, 1);}
|
||||
IFX2(X_ZF, && !BOX64ENV(cputype)) {BFCw(xFlags, F_ZF, 1);}
|
||||
IFX2(X_SF, && !BOX64ENV(cputype)) {
|
||||
LSRxw(x3, xRAX, rex.w?63:31);
|
||||
BFIw(xFlags, x3, F_SF, 1);
|
||||
}
|
||||
IFX2(X_PF, && !BOX64ENV(cputype)) emit_pf(dyn, ninst, xRAX, x3);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("IMUL EAX, Ed");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
if(BOX64ENV(dynarec_safeflags) && BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
}
|
||||
GETED32(0);
|
||||
if(rex.w) {
|
||||
if(ed==xRDX) gd=x3; else gd=xRDX;
|
||||
@@ -1503,9 +1519,24 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOVw_REG(xRAX, xRDX);
|
||||
LSRx(xRDX, xRDX, 32);
|
||||
}
|
||||
UFLAG_RES(xRAX);
|
||||
UFLAG_OP1(xRDX);
|
||||
UFLAG_DF(x2, rex.w?d_imul64:d_imul32);
|
||||
SET_DFNONE();
|
||||
IFX(X_CF|X_OF) {
|
||||
CMPSxw_REG_ASR(xRDX, xRAX, rex.w?63:31);
|
||||
CSETw(x3, cNE);
|
||||
IFX(X_CF) {
|
||||
BFIw(xFlags, x3, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BFIw(xFlags, x3, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX2(X_AF, && !BOX64ENV(cputype)) {BFCw(xFlags, F_AF, 1);}
|
||||
IFX2(X_ZF, && !BOX64ENV(cputype)) {BFCw(xFlags, F_ZF, 1);}
|
||||
IFX2(X_SF, && !BOX64ENV(cputype)) {
|
||||
LSRxw(x3, xRAX, rex.w?63:31);
|
||||
BFIw(xFlags, x3, F_SF, 1);
|
||||
}
|
||||
IFX2(X_PF, && !BOX64ENV(cputype)) emit_pf(dyn, ninst, xRAX, x3);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("DIV Ed");
|
||||
@@ -1543,17 +1574,25 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOVx_REG(xRAX, x2);
|
||||
}
|
||||
}
|
||||
SET_DFNONE(x2);
|
||||
IFX(X_AF | X_SF | X_CF | X_PF | X_ZF | X_OF)
|
||||
if(box64_dynarec_test) {
|
||||
MOV32w(x1, (1<<F_AF) | (1<<F_SF) | (1<<F_CF) | (1<<F_PF) | (1<<F_ZF) | (1<<F_OF));
|
||||
BICw(xFlags, xFlags, x1);
|
||||
}
|
||||
SET_DFNONE();
|
||||
IFX(X_OF) {BFCw(xFlags, F_OF, 1);}
|
||||
IFX(X_CF) {BFCw(xFlags, F_CF, 1);}
|
||||
IFX2(X_AF, && !BOX64ENV(cputype)) {BFCw(xFlags, F_AF, 1);}
|
||||
IFX2(X_AF, && BOX64ENV(cputype)) {ORRw_mask(xFlags, xFlags, 28, 0);} //mask=0x10
|
||||
IFX2(X_ZF, && !BOX64ENV(cputype)) {ORRw_mask(xFlags, xFlags, 26, 0);} //mask=0x40
|
||||
IFX2(X_ZF, && BOX64ENV(cputype)) {BFCw(xFlags, F_ZF, 1);}
|
||||
IFX(X_SF) {BFCw(xFlags, F_SF, 1);}
|
||||
IFX2(X_PF, && !BOX64ENV(cputype)) {ORRw_mask(xFlags, xFlags, 30, 0);} //mask=0x04
|
||||
IFX2(X_PF, && BOX64ENV(cputype)) {BFCw(xFlags, F_PF, 1);}
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("IDIV Ed");
|
||||
NOTEST(x1);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
if(!BOX64ENV(dynarec_safeflags)) {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
} else if(BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_SF|X_PF|X_ZF|X_AF, SF_SET);
|
||||
}
|
||||
if(!rex.w) {
|
||||
GETSED32w(0);
|
||||
MOVw_REG(x3, xRAX);
|
||||
@@ -1585,12 +1624,13 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOVx_REG(xRAX, x2);
|
||||
}
|
||||
}
|
||||
SET_DFNONE(x2);
|
||||
IFX(X_AF | X_SF | X_CF | X_PF | X_ZF | X_OF)
|
||||
if(box64_dynarec_test) {
|
||||
MOV32w(x1, (1<<F_AF) | (1<<F_SF) | (1<<F_CF) | (1<<F_PF) | (1<<F_ZF) | (1<<F_OF));
|
||||
BICw(xFlags, xFlags, x1);
|
||||
}
|
||||
if(!BOX64ENV(dynarec_safeflags)) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFX2(X_AF, && BOX64ENV(cputype)) {ORRw_mask(xFlags, xFlags, 28, 0);} //mask=0x10
|
||||
IFX2(X_ZF, && BOX64ENV(cputype)) {BFCw(xFlags, F_ZF, 1);}
|
||||
IFX2(X_SF, && BOX64ENV(cputype)) {BFCw(xFlags, F_SF, 1);}
|
||||
IFX2(X_PF, && BOX64ENV(cputype)) {BFCw(xFlags, F_PF, 1);}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -1613,7 +1653,7 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 2: // CALL Ed
|
||||
INST_NAME("CALL Ed");
|
||||
PASS2IF((box64_dynarec_safeflags>1) ||
|
||||
PASS2IF((BOX64DRENV(dynarec_safeflags)>1) ||
|
||||
((ninst && dyn->insts[ninst-1].x64.set_flags)
|
||||
|| ((ninst>1) && dyn->insts[ninst-2].x64.set_flags)), 1)
|
||||
{
|
||||
@@ -1622,7 +1662,7 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); //Hack to put flag in "don't care" state
|
||||
}
|
||||
GETED32(0);
|
||||
if(box64_dynarec_callret && box64_dynarec_bigblock>1) {
|
||||
if(BOX64DRENV(dynarec_callret) && BOX64DRENV(dynarec_bigblock)>1) {
|
||||
BARRIER(BARRIER_FULL);
|
||||
} else {
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
@@ -1630,7 +1670,7 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
*ok = 0;
|
||||
}
|
||||
GETIP_(addr);
|
||||
if(box64_dynarec_callret) {
|
||||
if(BOX64DRENV(dynarec_callret)) {
|
||||
SET_HASCALLRET();
|
||||
// Push actual return address
|
||||
if(addr < (dyn->start+dyn->isize)) {
|
||||
@@ -1647,7 +1687,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(box64_dynarec_callret && addr >= (dyn->start + dyn->isize)) {
|
||||
if(BOX64DRENV(dynarec_callret) && addr >= (dyn->start + dyn->isize)) {
|
||||
// jumps out of current dynablock...
|
||||
MARK;
|
||||
j64 = getJumpTableAddress64(addr);
|
||||
|
||||
@@ -68,9 +68,10 @@ uintptr_t dynarec64_6764_32(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, in
|
||||
if(MODREG) { // reg <= reg
|
||||
MOVxw_REG(TO_NAT((nextop & 7) + (rex.b << 3)), gd);
|
||||
} else { // mem <= reg
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0, 0, 0);
|
||||
STRw_REG(gd, ed, x4);
|
||||
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
|
||||
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, 0);
|
||||
ADDz_REG(x4, x4, ed);
|
||||
STz(gd, x4, fixedaddress);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -81,9 +82,10 @@ uintptr_t dynarec64_6764_32(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, in
|
||||
if(MODREG) { // reg => reg
|
||||
MOVxw_REG(gd, TO_NAT((nextop & 7) + (rex.b << 3)));
|
||||
} else { // mem => reg
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0, 0, 0);
|
||||
LDRw_REG(gd, ed, x4);
|
||||
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
|
||||
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, 0);
|
||||
ADDz_REG(x4, x4, ed);
|
||||
LDz(gd, x4, fixedaddress);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -94,17 +96,18 @@ uintptr_t dynarec64_6764_32(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, in
|
||||
POP1_32(x1);
|
||||
MOVxw_REG(TO_NAT((nextop & 7) + (rex.b << 3)), x1);
|
||||
} else { // mem <= reg
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
|
||||
POP1_32(x1);
|
||||
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0, 0, 0);
|
||||
STRw_REG(x1, ed, x4);
|
||||
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, 0);
|
||||
ADDz_REG(x4, x4, ed);
|
||||
STz(x1, x4, fixedaddress);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xA1:
|
||||
INST_NAME("MOV EAX, Seg:[Od]");
|
||||
i32 = F16;
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
grab_segdata(dyn, addr, ninst, x4, seg, 0);
|
||||
if(i32<4096 && !(i32&3)) {
|
||||
LDRw_U12(xRAX, x4, i32);
|
||||
} else if(i32<256) {
|
||||
@@ -118,7 +121,7 @@ uintptr_t dynarec64_6764_32(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, in
|
||||
case 0xA3:
|
||||
INST_NAME("MOV Seg:[Od], EAX");
|
||||
i32 = F16;
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
grab_segdata(dyn, addr, ninst, x4, seg, 0);
|
||||
if(i32<4096 && !(i32&3)) {
|
||||
STRw_U12(xRAX, x4, i32);
|
||||
} else if(i32<256) {
|
||||
@@ -131,16 +134,17 @@ uintptr_t dynarec64_6764_32(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, in
|
||||
|
||||
case 0xFF:
|
||||
nextop = F8;
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
|
||||
switch((nextop>>3)&7) {
|
||||
case 6: // Push Ed
|
||||
INST_NAME("PUSH FS:Ew");
|
||||
if((nextop&0xC0)==0xC0) { // reg
|
||||
if (MODREG) {
|
||||
DEFAULT;
|
||||
} else { // mem <= i32
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0, 0, 0);
|
||||
LDRw_REG(x3, ed, x4);
|
||||
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, 0);
|
||||
ADDz_REG(x4, x4, ed);
|
||||
LDW(x3, x4, fixedaddress);
|
||||
PUSH1_32(x3);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -85,15 +85,21 @@ uintptr_t dynarec64_67_AVX(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETGD;
|
||||
GETED32(0);
|
||||
GETVD;
|
||||
if(rex.w) {
|
||||
// 64bits mul
|
||||
UMULH(x3, xRDX, ed);
|
||||
MULx(vd, xRDX, ed);
|
||||
MOVx_REG(gd, x3);
|
||||
if(rex.w) {
|
||||
// 64bits mul
|
||||
if((gd==xRDX) || (gd==ed) || (gd==vd))
|
||||
gb1 = x3;
|
||||
else
|
||||
gb1 = gd;
|
||||
UMULH(gb1, xRDX, ed);
|
||||
if(gd!=vd) {MULx(vd, xRDX, ed);}
|
||||
if(gb1==x3) {
|
||||
MOVx_REG(gd, gb1);
|
||||
}
|
||||
} else {
|
||||
// 32bits mul
|
||||
UMULL(x3, xRDX, ed);
|
||||
MOVw_REG(vd, x3);
|
||||
if(gd!=vd) {MOVw_REG(vd, x3);}
|
||||
LSRx(gd, x3, 32);
|
||||
}
|
||||
break;
|
||||
@@ -120,14 +126,29 @@ uintptr_t dynarec64_67_AVX(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x6E:
|
||||
INST_NAME("VMOVD Gx, Ed");
|
||||
nextop = F8;
|
||||
GETGX_empty(v0);
|
||||
GETED(0);
|
||||
VEORQ(v0, v0, v0); // RAZ vector
|
||||
if(rex.w) {
|
||||
FMOVDx(v0, ed);
|
||||
} else {
|
||||
FMOVSw(v0, ed);
|
||||
}
|
||||
YMM0(gd);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
}
|
||||
else {DEFAULT;}
|
||||
|
||||
if((*ok==-1) && (box64_dynarec_log>=LOG_INFO || box64_dynarec_dump || box64_dynarec_missing==1)) {
|
||||
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 || 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);
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,418 @@
|
||||
#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"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_native.h"
|
||||
|
||||
//order might be important, so define SUPER for the right one
|
||||
#define SUPER() \
|
||||
GO(flags) \
|
||||
GO(x87) \
|
||||
GO(mmx) \
|
||||
GO(sse) \
|
||||
GO(ymm) \
|
||||
|
||||
|
||||
typedef struct arch_flags_s
|
||||
{
|
||||
uint8_t defered:1;
|
||||
uint8_t nf:1;
|
||||
uint8_t eq:1;
|
||||
uint8_t vf:1;
|
||||
uint8_t cf:1;
|
||||
uint8_t inv_cf:1;
|
||||
} arch_flags_t;
|
||||
|
||||
#define X87_ST_D 0
|
||||
#define X87_ST_F 1
|
||||
#define X87_ST_I64 2
|
||||
typedef struct arch_x87_s
|
||||
{
|
||||
int8_t delta; //up to +/-7
|
||||
uint8_t x87; // 1bit is STx present
|
||||
uint16_t x87_type; // 2bits per STx type
|
||||
uint32_t x87_pos; //4bits per STx position (well, 3 would be enough)
|
||||
} arch_x87_t;
|
||||
|
||||
typedef struct arch_mmx_s
|
||||
{
|
||||
uint8_t mmx; //1bit for each mmx reg present
|
||||
} arch_mmx_t;
|
||||
|
||||
typedef struct arch_sse_s
|
||||
{
|
||||
uint16_t sse; //1bit for each sse reg present
|
||||
} arch_sse_t;
|
||||
|
||||
typedef struct arch_ymm_s
|
||||
{
|
||||
uint16_t ymm0; // 1bit for ymm0
|
||||
uint16_t ymm; // 1bit for each ymm present
|
||||
uint64_t ymm_pos; // 4bits for position of each ymm present
|
||||
} arch_ymm_t;
|
||||
|
||||
typedef struct arch_arch_s
|
||||
{
|
||||
#define GO(A) uint16_t A:1;
|
||||
SUPER()
|
||||
#undef GO
|
||||
uint16_t unaligned:1;
|
||||
uint16_t seq:10; // how many instruction on the same values
|
||||
} arch_arch_t;
|
||||
|
||||
typedef struct arch_build_s
|
||||
{
|
||||
#define GO(A) uint8_t A:1;
|
||||
SUPER()
|
||||
#undef GO
|
||||
uint8_t unaligned;
|
||||
#define GO(A) arch_##A##_t A##_;
|
||||
SUPER()
|
||||
#undef GO
|
||||
} arch_build_t;
|
||||
|
||||
static arch_build_t static_build[MAX_INSTS+2] = {0};
|
||||
|
||||
static int arch_build(dynarec_arm_t* dyn, int ninst, arch_build_t* arch)
|
||||
{
|
||||
memset(arch, 0, sizeof(arch_build_t));
|
||||
// flags
|
||||
if((dyn->insts[ninst].f_entry.dfnone==0) || dyn->insts[ninst].need_nat_flags || dyn->insts[ninst].before_nat_flags) {
|
||||
arch->flags = 1;
|
||||
arch->flags_.defered = dyn->insts[ninst].f_entry.dfnone==0;
|
||||
uint8_t flags = dyn->insts[ninst].need_nat_flags | dyn->insts[ninst].before_nat_flags;
|
||||
arch->flags_.vf = flags&NF_VF;
|
||||
arch->flags_.nf = flags&NF_SF;
|
||||
arch->flags_.eq = flags&NF_EQ;
|
||||
arch->flags_.cf = flags&NF_CF;
|
||||
if(arch->flags_.cf)
|
||||
arch->flags_.inv_cf = !dyn->insts[ninst].normal_carry;
|
||||
}
|
||||
// got through all naoncache to gather regs assignments
|
||||
int idx;
|
||||
for(int i=0; i<32; ++i)
|
||||
if(dyn->insts[ninst].n.neoncache[i].v!=-1)
|
||||
switch(dyn->insts[ninst].n.neoncache[i].t) {
|
||||
case NEON_CACHE_XMMW:
|
||||
arch->sse = 1;
|
||||
arch->sse_.sse |= 1<<dyn->insts[ninst].n.neoncache[i].n;
|
||||
break;
|
||||
case NEON_CACHE_MM:
|
||||
arch->mmx = 1;
|
||||
arch->mmx_.mmx |= 1<<dyn->insts[ninst].n.neoncache[i].n;
|
||||
break;
|
||||
case NEON_CACHE_YMMW:
|
||||
arch->ymm = 1;
|
||||
arch->ymm_.ymm |= 1<<dyn->insts[ninst].n.neoncache[i].n;
|
||||
idx = i;
|
||||
if(idx>=EMM0 && idx<=EMM0+8)
|
||||
idx-=EMM0;
|
||||
else
|
||||
idx-=SCRATCH0-8;
|
||||
arch->ymm_.ymm_pos |= idx<<(dyn->insts[ninst].n.neoncache[i].n*4);
|
||||
break;
|
||||
case NEON_CACHE_ST_D:
|
||||
arch->x87 = 1;
|
||||
arch->x87_.x87 |= 1<<dyn->insts[ninst].n.neoncache[i].n;
|
||||
arch->x87_.x87_pos = (i-EMM0)<<(dyn->insts[ninst].n.neoncache[i].n*4);
|
||||
arch->x87_.x87_type = (X87_ST_D)<<(dyn->insts[ninst].n.neoncache[i].n*2);
|
||||
break;
|
||||
case NEON_CACHE_ST_F:
|
||||
arch->x87 = 1;
|
||||
arch->x87_.x87 |= 1<<dyn->insts[ninst].n.neoncache[i].n;
|
||||
arch->x87_.x87_pos = (i-EMM0)<<(dyn->insts[ninst].n.neoncache[i].n*4);
|
||||
arch->x87_.x87_type = (X87_ST_F)<<(dyn->insts[ninst].n.neoncache[i].n*2);
|
||||
break;
|
||||
case NEON_CACHE_ST_I64:
|
||||
arch->x87 = 1;
|
||||
arch->x87_.x87 |= 1<<dyn->insts[ninst].n.neoncache[i].n;
|
||||
arch->x87_.x87_pos = (i-EMM0)<<(dyn->insts[ninst].n.neoncache[i].n*4);
|
||||
arch->x87_.x87_type = (X87_ST_I64)<<(dyn->insts[ninst].n.neoncache[i].n*2);
|
||||
break;
|
||||
case NEON_CACHE_XMMR:
|
||||
case NEON_CACHE_YMMR:
|
||||
default:
|
||||
// doing nothing, it's just a value read in memory
|
||||
break;
|
||||
}
|
||||
// ymm0
|
||||
if(dyn->insts[ninst].ymm0_out) {
|
||||
arch->ymm = 1;
|
||||
arch->ymm_.ymm0 = dyn->insts[ninst].ymm0_out;
|
||||
}
|
||||
// x87 top
|
||||
if(dyn->insts[ninst].n.x87stack) {
|
||||
arch->x87 = 1;
|
||||
arch->x87_.delta = dyn->insts[ninst].n.x87stack;
|
||||
}
|
||||
// opcode can handle unaligned
|
||||
arch->unaligned = dyn->insts[ninst].unaligned;
|
||||
return arch->flags + arch->x87 + arch->mmx + arch->sse + arch->ymm + arch->unaligned;
|
||||
}
|
||||
|
||||
static int sizeof_arch(arch_arch_t* arch)
|
||||
{
|
||||
int sz = sizeof(arch_arch_t);
|
||||
#define GO(A) if(arch->A) sz+=sizeof(arch_##A##_t);
|
||||
SUPER()
|
||||
#undef GO
|
||||
return sz;
|
||||
}
|
||||
|
||||
static int sizeof_arch_build(arch_build_t* build)
|
||||
{
|
||||
int sz = sizeof(arch_arch_t);
|
||||
#define GO(A) if(build->A) sz+=sizeof(arch_##A##_t);
|
||||
SUPER()
|
||||
#undef GO
|
||||
return sz;
|
||||
}
|
||||
|
||||
size_t get_size_arch(dynarec_arm_t* dyn)
|
||||
{
|
||||
arch_build_t* previous = NULL;
|
||||
size_t sz = 0;
|
||||
int seq = 0;
|
||||
int nseq = 0;
|
||||
int last = 0;
|
||||
if(!dyn->size) return 0;
|
||||
for(int i=0; i<dyn->size; ++i) {
|
||||
arch_build_t* build = static_build+i;
|
||||
last = arch_build(dyn, i, build);
|
||||
if(i && (!memcmp(build, previous, sizeof(arch_build_t))) && (seq<((1<<10)-1))) {
|
||||
// same sequence, increment
|
||||
++seq;
|
||||
} else {
|
||||
seq = 0;
|
||||
++nseq;
|
||||
previous = build;
|
||||
sz += sizeof_arch_build(build);
|
||||
}
|
||||
}
|
||||
if(nseq==1 && !last)
|
||||
return 0; //empty, no flags, no nothing
|
||||
return sz;
|
||||
}
|
||||
|
||||
static void build_next(arch_arch_t* arch, arch_build_t* build)
|
||||
{
|
||||
#define GO(A) arch->A = build->A;
|
||||
SUPER()
|
||||
#undef GO
|
||||
arch->unaligned = build->unaligned;
|
||||
arch->seq = 0;
|
||||
void* p = ((void*)arch)+sizeof(arch_arch_t);
|
||||
#define GO(A) \
|
||||
if(build->A) { \
|
||||
memcpy(p, &(build->A##_), sizeof(arch_ ##A##_t)); \
|
||||
p+=sizeof(arch_##A##_t); \
|
||||
}
|
||||
SUPER()
|
||||
#undef GO
|
||||
}
|
||||
|
||||
void* populate_arch(dynarec_arm_t* dyn, void* p, size_t tot_sz)
|
||||
{
|
||||
arch_build_t* previous = NULL;
|
||||
arch_arch_t* arch = p;
|
||||
arch_arch_t* next = p;
|
||||
int seq = 0;
|
||||
size_t total = 0;
|
||||
if(!tot_sz) return NULL;
|
||||
for(int i=0; i<dyn->size; ++i) {
|
||||
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;
|
||||
} else {
|
||||
int sz = sizeof_arch_build(build);
|
||||
if(total+sz>tot_sz) {
|
||||
printf_log(LOG_INFO, "Warning: populate_arch oversized\n");
|
||||
return NULL;
|
||||
}
|
||||
arch = next;
|
||||
build_next(arch, build);
|
||||
seq = 0;
|
||||
previous = build;
|
||||
total += sz;
|
||||
next = (arch_arch_t*)((uintptr_t)arch+sz);
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
int getX64AddressInst(dynablock_t* db, uintptr_t x64pc); // define is signal.c
|
||||
|
||||
// NZCV N
|
||||
#define NZCV_N 31
|
||||
// NZCV Z
|
||||
#define NZCV_Z 30
|
||||
// NZCV C
|
||||
#define NZCV_C 29
|
||||
// NZCV V
|
||||
#define NZCV_V 28
|
||||
|
||||
void adjust_arch(dynablock_t* db, x64emu_t* emu, ucontext_t* p, uintptr_t x64pc)
|
||||
{
|
||||
if(!db->arch_size || !db->arch)
|
||||
return;
|
||||
int ninst = getX64AddressInst(db, x64pc);
|
||||
dynarec_log(LOG_INFO, "adjust_arch(...), db=%p, x64pc=%p, nints=%d", db, (void*)x64pc, ninst);
|
||||
if(ninst<0) {
|
||||
dynarec_log_prefix(0, LOG_INFO, "\n");
|
||||
return;
|
||||
}
|
||||
if(ninst==0) {
|
||||
dynarec_log_prefix(0, LOG_INFO, "\n");
|
||||
CHECK_FLAGS(emu);
|
||||
return;
|
||||
}
|
||||
// look for state at ninst-1
|
||||
arch_arch_t* arch = db->arch;
|
||||
arch_arch_t* next = arch;
|
||||
#define GO(A) arch_##A##_t* A = NULL;
|
||||
SUPER()
|
||||
#undef GO
|
||||
int i = 0;
|
||||
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":"");
|
||||
next = (arch_arch_t*)((uintptr_t)next + sizeof_arch(arch));
|
||||
}
|
||||
int sz = sizeof(arch_arch_t);
|
||||
#define GO(A) \
|
||||
if(arch->A) { \
|
||||
A = (arch_##A##_t*)((uintptr_t)arch + sz); \
|
||||
sz+=sizeof(arch_##A##_t); \
|
||||
}
|
||||
SUPER()
|
||||
#undef GO
|
||||
if(flags) {
|
||||
dynarec_log_prefix(0, LOG_INFO, " flags[%s-%s%s%s%s] ", flags->defered?"defered":"", flags->nf?"S":"", flags->vf?"O":"", flags->eq?"Z":"", flags->cf?(flags->inv_cf?"C(inv)":"C"):"");
|
||||
if(flags->defered) {
|
||||
CHECK_FLAGS(emu);
|
||||
//return;
|
||||
}
|
||||
if(flags->nf) {
|
||||
CONDITIONAL_SET_FLAG(p->uc_mcontext.pstate&(1<<NZCV_N), F_SF);
|
||||
}
|
||||
if(flags->vf) {
|
||||
CONDITIONAL_SET_FLAG(p->uc_mcontext.pstate&(1<<NZCV_V), F_OF);
|
||||
}
|
||||
if(flags->eq) {
|
||||
CONDITIONAL_SET_FLAG(p->uc_mcontext.pstate&(1<<NZCV_Z), F_ZF);
|
||||
}
|
||||
if(flags->cf) {
|
||||
if(flags->inv_cf) {
|
||||
CONDITIONAL_SET_FLAG((p->uc_mcontext.pstate&(1<<NZCV_C))==0, F_CF);
|
||||
} else {
|
||||
CONDITIONAL_SET_FLAG(p->uc_mcontext.pstate&(1<<NZCV_C), F_CF);
|
||||
}
|
||||
}
|
||||
}
|
||||
struct fpsimd_context *fpsimd = NULL;
|
||||
// find fpsimd struct
|
||||
{
|
||||
struct _aarch64_ctx * ff = (struct _aarch64_ctx*)p->uc_mcontext.__reserved;
|
||||
while (ff->magic && !fpsimd) {
|
||||
if(ff->magic==FPSIMD_MAGIC)
|
||||
fpsimd = (struct fpsimd_context*)ff;
|
||||
else
|
||||
ff = (struct _aarch64_ctx*)((uintptr_t)ff + ff->size);
|
||||
}
|
||||
}
|
||||
if(sse) {
|
||||
dynarec_log_prefix(0, LOG_INFO, " sse[%x (fpsimd=%p)] ", sse->sse, fpsimd);
|
||||
for(int i=0; i<16; ++i)
|
||||
if(fpsimd && (sse->sse>>i)&1) {
|
||||
int idx = 0;
|
||||
if(i>7) {
|
||||
idx = XMM8 + i - 8;
|
||||
} else {
|
||||
idx = XMM0 + i;
|
||||
}
|
||||
emu->xmm[i].u128 = fpsimd->vregs[idx];
|
||||
}
|
||||
}
|
||||
if(ymm) {
|
||||
dynarec_log_prefix(0, LOG_INFO, " ymm[%x, pos=%x, 0=%x (fpsimd=%p)] ", ymm->ymm, ymm->ymm_pos, ymm->ymm0, fpsimd);
|
||||
for(int i=0; i<16; ++i) {
|
||||
if(fpsimd && (ymm->ymm>>i)&1) {
|
||||
int idx = (ymm->ymm_pos>>(i*4))&0xf;
|
||||
if(i>7) {
|
||||
idx = SCRATCH0 + i - 8;
|
||||
} else {
|
||||
idx = EMM0 + i;
|
||||
}
|
||||
emu->ymm[i].u128 = fpsimd->vregs[idx];
|
||||
}
|
||||
if(ymm->ymm0&(1<<i))
|
||||
emu->ymm[i].u128 = 0;
|
||||
}
|
||||
}
|
||||
if(mmx) {
|
||||
dynarec_log_prefix(0, LOG_INFO, " mmx[%x (fpsimd=%p)] ", mmx->mmx, fpsimd);
|
||||
for(int i=0; i<8; ++i)
|
||||
if(fpsimd && (mmx->mmx>>i)&1) {
|
||||
int idx = EMM0 + i;
|
||||
emu->mmx[i].q = fpsimd->vregs[idx]&0xffffffffffffffffLL;
|
||||
}
|
||||
}
|
||||
if(x87) {
|
||||
dynarec_log_prefix(0, LOG_INFO, " x87[%x, pos=%x, type=%x (fpsimd=%p)] ", x87->x87, x87->x87_pos, x87->x87_type, fpsimd);
|
||||
emu->top -= x87->delta;
|
||||
for(int i=0; i<8; ++i) {
|
||||
if(x87->x87&(1<<i)) {
|
||||
int idx = EMM0 + (x87->x87_pos>>(i*4))&0x0f;
|
||||
int t = (x87->x87_type>>(i*2))&0x3;
|
||||
switch (t) {
|
||||
case X87_ST_F:
|
||||
emu->x87[(emu->top+i)&7].d = *(float*)&fpsimd->vregs[idx];
|
||||
break;
|
||||
case X87_ST_I64:
|
||||
emu->x87[(emu->top+i)&7].d = *(int64_t*)&fpsimd->vregs[idx];
|
||||
break;
|
||||
case X87_ST_D:
|
||||
emu->x87[(emu->top+i)&7].d = *(double*)&fpsimd->vregs[idx];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
dynarec_log_prefix(0, LOG_INFO, "\n");
|
||||
}
|
||||
|
||||
int arch_unaligned(dynablock_t* db, uintptr_t x64pc)
|
||||
{
|
||||
if(!db)
|
||||
return 0;
|
||||
if(!db->arch_size || !db->arch)
|
||||
return 0;
|
||||
int ninst = getX64AddressInst(db, x64pc);
|
||||
if(ninst<0) {
|
||||
return 0;
|
||||
}
|
||||
// look for state at ninst
|
||||
arch_arch_t* arch = db->arch;
|
||||
arch_arch_t* next = arch;
|
||||
int i = -1;
|
||||
while(i<ninst) {
|
||||
arch = next;
|
||||
i += 1+arch->seq;
|
||||
next = (arch_arch_t*)((uintptr_t)next + sizeof_arch(arch));
|
||||
}
|
||||
return arch->unaligned;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#ifndef __DYNAREC_ARM_ARCH_H__
|
||||
#define __DYNAREC_ARM_ARCH_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <ucontext.h>
|
||||
|
||||
#include "x64emu.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.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);
|
||||
//adjust flags and more
|
||||
void adjust_arch(dynablock_t* db, x64emu_t* emu, ucontext_t* p, uintptr_t x64pc);
|
||||
// get if instruction can be regenerated for unaligned access
|
||||
int arch_unaligned(dynablock_t* db, uintptr_t x64pc);
|
||||
#endif // __DYNAREC_ARM_ARCH_H__
|
||||
@@ -71,8 +71,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) && (box64_dynarec_log>=LOG_INFO || box64_dynarec_dump || box64_dynarec_missing==1)) {
|
||||
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 || 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);
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -290,7 +290,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETGX(v0, 0);
|
||||
GETEXSS(s0, 0, 0);
|
||||
FCMPS(v0, s0);
|
||||
FCOMI(x1, x2, 0, v0, s0, 1); //disable precise cmp
|
||||
FCOMI(x1, x2);
|
||||
break;
|
||||
|
||||
case 0x50:
|
||||
@@ -302,7 +302,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
// EX is an xmm reg
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETEX(v0, 0, 0); } else { GETEY(v0); }
|
||||
if(!l) { GETEX_Y(v0, 0, 0); } else { GETEY(v0); }
|
||||
SQXTN_16(q0, v0); // reduces the 4 32bits to 4 16bits
|
||||
VMOVQDto(x1, q0, 0);
|
||||
LSRx(x1, x1, 15);
|
||||
@@ -440,22 +440,50 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
case 0x58:
|
||||
INST_NAME("VADDPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETGX_empty_VXEX(v0, v2, v1, 0);
|
||||
VFADDQS(v0, v2, v1);
|
||||
if(vex.l) {
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
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
|
||||
VFMAXQS(q0, v2, v1); // propagate NAN
|
||||
VFCMEQQS(q0, q0, q0); // 0 if NAN, 1 if not NAN
|
||||
}
|
||||
VFADDQS(v0, v2, v1);
|
||||
} else YMM0(gd)
|
||||
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;
|
||||
case 0x59:
|
||||
INST_NAME("VMULPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETGX_empty_VXEX(v0, v2, v1, 0);
|
||||
VFMULQS(v0, v2, v1);
|
||||
if(vex.l) {
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
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
|
||||
VFMAXQS(q0, v2, v1); // propagate NAN
|
||||
VFCMEQQS(q0, q0, q0); // 0 if NAN, 1 if not NAN
|
||||
}
|
||||
VFMULQS(v0, v2, v1);
|
||||
} else YMM0(gd)
|
||||
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;
|
||||
case 0x5A:
|
||||
INST_NAME("VCVTPS2PD Gx, Ex");
|
||||
@@ -480,17 +508,31 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
case 0x5C:
|
||||
INST_NAME("VSUBPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETGX_empty_VXEX(v0, v2, v1, 0);
|
||||
VFSUBQS(v0, v2, v1);
|
||||
if(vex.l) {
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
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
|
||||
VFMAXQS(q0, v2, v1); // propagate NAN
|
||||
VFCMEQQS(q0, q0, q0); // 0 if NAN, 1 if not NAN
|
||||
}
|
||||
VFSUBQS(v0, v2, v1);
|
||||
} else YMM0(gd)
|
||||
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;
|
||||
case 0x5D:
|
||||
INST_NAME("VMINPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
if(!box64_dynarec_fastnan) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
}
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
@@ -498,7 +540,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
// 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(!box64_dynarec_fastnan && (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
|
||||
}
|
||||
@@ -508,17 +550,31 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
case 0x5E:
|
||||
INST_NAME("VDIVPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETGX_empty_VXEX(v0, v2, v1, 0);
|
||||
VFDIVQS(v0, v2, v1);
|
||||
if(vex.l) {
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
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
|
||||
VFMAXQS(q0, v2, v1); // propagate NAN
|
||||
VFCMEQQS(q0, q0, q0); // 0 if NAN, 1 if not NAN
|
||||
}
|
||||
VFDIVQS(v0, v2, v1);
|
||||
} else YMM0(gd)
|
||||
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;
|
||||
case 0x5F:
|
||||
INST_NAME("VMAXPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
if(!box64_dynarec_fastnan) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
}
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
@@ -526,7 +582,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
// 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(!box64_dynarec_fastnan && (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
|
||||
}
|
||||
@@ -568,19 +624,52 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
INST_NAME("VLDMXCSR Md");
|
||||
GETED(0);
|
||||
STRw_U12(ed, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
if(box64_sse_flushto0) {
|
||||
MRS_fpcr(x1); // get fpscr
|
||||
if(BOX64ENV(sse_flushto0)) {
|
||||
MRS_fpcr(x2); // get fpscr
|
||||
LSRw_IMM(x3, ed, 15); // get FZ bit
|
||||
BFIw(x1, x3, 24, 1); // inject FZ bit
|
||||
BFIw(x2, x3, 24, 1); // inject FZ bit
|
||||
EORw_REG_LSR(x3, x3, ed, 1); // FZ xor DAZ
|
||||
BFIw(x1, x3, 1, 1); // inject AH bit
|
||||
MSR_fpcr(x1); // put new fpscr
|
||||
BFIw(x2, x3, 1, 1); // inject AH bit
|
||||
MSR_fpcr(x2); // put new fpscr
|
||||
}
|
||||
if(BOX64ENV(sse_flushto0)) {
|
||||
// try to sync mxcsr with fpsr on the flag side
|
||||
/* mapping is
|
||||
ARM -> X86
|
||||
0 -> 0 // Invalid operation
|
||||
1 -> 2 // Divide by 0
|
||||
2 -> 3 // Overflow
|
||||
3 -> 4 // underflow
|
||||
4 -> 5 // Inexact
|
||||
5 -> 1 // denormal
|
||||
*/
|
||||
// doing X86 -> ARM here, 0 1 2 3 4 5 -> 0 2 3 4 5 1
|
||||
if(ed!=x1)
|
||||
MOVw_REG(x1, ed); // x1 = 543210
|
||||
RORw(x3, x1, 2); // x3 = 10.....5432
|
||||
BFIw(x1, x3, 1, 4); // x1 = 54320
|
||||
RORw(x3, x3, 32-1); // x3 = 0.....54321
|
||||
BFIw(x1, x3, 5, 1); // x1 = 154320
|
||||
MRS_fpsr(x2);
|
||||
BFIx(x2, x1, 0, 6);
|
||||
MSR_fpsr(x2);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
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));
|
||||
if(BOX64ENV(sse_flushto0)) {
|
||||
// sync with fpsr, with mask from mxcsr
|
||||
MRS_fpsr(x1);
|
||||
// doing ARM -> X86 here, 543210 => 432150
|
||||
UBFXw(x2, x1, 1, 5); // x2 = 54321
|
||||
BFIw(x1, x2, 2, 4); // x1 = 432110
|
||||
LSRw(x2, x2, 4); // x2 = 5
|
||||
BFIw(x1, x2, 1, 1); // x1 = 432150
|
||||
//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:
|
||||
@@ -634,15 +723,21 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
u8 = F8;
|
||||
if(v2==v1 && (u8&0x3)==((u8>>2)&3) && (u8&0xf)==((u8>>4)&0xf)) {
|
||||
VDUPQ_32(v0, v2, u8&3);
|
||||
} else if(v2==v1 && (u8==0xe0)) { // easy special case
|
||||
} else if(v2==v1 && (u8==0xe0)) { // elements 3 2 0 0
|
||||
VMOVQ(v0, v2);
|
||||
VMOVeS(v0, 1, v0, 0);
|
||||
} else if(v2==v1 && (u8==0xe5)) { // easy special case
|
||||
} else if(v2==v1 && (u8==0xe5)) { // elements 3 2 1 1
|
||||
VMOVQ(v0, v2);
|
||||
VMOVeS(v0, 0, v0, 1);
|
||||
} else if(MODREG && u8==0x88) {
|
||||
} else if(v2==v1 && (u8==0xa0)) { // elements 2 2 0 0
|
||||
VTRNQ1_32(v0, v1, v2);
|
||||
} else if(v2==v1 && (u8==0xf5)) { // elements 3 3 1 1
|
||||
VTRNQ2_32(v0, v1, v2);
|
||||
} else if(v2==v1 && (u8==0xb1)) { // elements 2 3 0 1
|
||||
VREV64Q_32(v0, v1);
|
||||
} else if(MODREG && u8==0x88) { // elements 2 0 2 0
|
||||
VUZP1Q_32(v0, v2, v1);
|
||||
} else if(MODREG && u8==0xdd) {
|
||||
} else if(MODREG && u8==0xdd) { // elements 3 1 3 1
|
||||
VUZP2Q_32(v0, v2, v1);
|
||||
} else {
|
||||
if((v0==v1) || (v0==v2)) {
|
||||
@@ -674,15 +769,21 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETGY_empty_VY(v0, v2, 0, (MODREG)?((nextop&7)+(rex.b<<3)):-1, -1);
|
||||
if(v2==v1 && (u8&0x3)==((u8>>2)&3) && (u8&0xf)==((u8>>4)&0xf)) {
|
||||
VDUPQ_32(v0, v2, u8&3);
|
||||
} else if(v2==v1 && (u8==0xe0)) {
|
||||
} else if(v2==v1 && (u8==0xe0)) { // elements 3 2 0 0
|
||||
VMOVQ(v0, v2);
|
||||
VMOVeS(v0, 1, v0, 0);
|
||||
} else if(v2==v1 && (u8==0xe5)) {
|
||||
} else if(v2==v1 && (u8==0xe5)) { // elements 3 2 1 1
|
||||
VMOVQ(v0, v2);
|
||||
VMOVeS(v0, 0, v0, 1);
|
||||
} else if(MODREG && u8==0x88) {
|
||||
} else if(v2==v1 && (u8==0xa0)) { // elements 2 2 0 0
|
||||
VTRNQ1_32(v0, v1, v2);
|
||||
} else if(v2==v1 && (u8==0xf5)) { // elements 3 3 1 1
|
||||
VTRNQ2_32(v0, v1, v2);
|
||||
} else if(v2==v1 && (u8==0xb1)) { // elements 2 3 0 1
|
||||
VREV64Q_32(v0, v1);
|
||||
} else if(MODREG && u8==0x88) { // elements 2 0 2 0
|
||||
VUZP1Q_32(v0, v2, v1);
|
||||
} else if(MODREG && u8==0xdd) {
|
||||
} else if(MODREG && u8==0xdd) { // elements 3 1 3 1
|
||||
VUZP2Q_32(v0, v2, v1);
|
||||
} else {
|
||||
if(s0) d0 = v0;
|
||||
|
||||
@@ -39,6 +39,7 @@ uintptr_t dynarec64_AVX_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, i
|
||||
int q0, q1, q2;
|
||||
int d0, d1, d2;
|
||||
int s0;
|
||||
int need_tst;
|
||||
uint64_t tmp64u;
|
||||
int64_t j64;
|
||||
int64_t fixedaddress;
|
||||
@@ -68,21 +69,32 @@ uintptr_t dynarec64_AVX_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, i
|
||||
GETGD;
|
||||
GETED(0);
|
||||
GETVD;
|
||||
IFX(X_ZF)
|
||||
need_tst = 0;
|
||||
IFX(X_ZF) need_tst = 1;
|
||||
IFXNATIVE(X_SF, NF_SF) need_tst = 1;
|
||||
IFXNATIVE(X_OF, NF_VF) need_tst = 1;
|
||||
IFXNATIVE(X_CF, NF_CF) need_tst = 1;
|
||||
if(need_tst)
|
||||
BICSxw(gd, ed, vd);
|
||||
else
|
||||
BICxw(gd, ed, vd);
|
||||
IFX(X_ZF) {
|
||||
CSETw(x1, cEQ);
|
||||
BFIw(xFlags, x1, F_ZF, 1);
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(x1, cEQ);
|
||||
BFIw(xFlags, x1, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_OF) {
|
||||
IFNATIVE(NF_VF) {} else {BFCw(xFlags, F_OF, 1);}
|
||||
}
|
||||
IFX(X_CF) {
|
||||
IFNATIVE(NF_CF) {} else {BFCw(xFlags, F_CF, 1);}
|
||||
}
|
||||
IFX(X_OF)
|
||||
BFCw(xFlags, F_OF, 1);
|
||||
IFX(X_CF)
|
||||
BFCw(xFlags, F_CF, 1);
|
||||
IFX(X_SF) {
|
||||
LSRxw_IMM(x1, gd, rex.w?63:31);
|
||||
BFIw(xFlags, x1, F_SF, 1);
|
||||
IFNATIVE(NF_SF) {} else {
|
||||
LSRxw_IMM(x1, gd, rex.w?63:31);
|
||||
BFIw(xFlags, x1, F_SF, 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xF3:
|
||||
@@ -99,24 +111,108 @@ uintptr_t dynarec64_AVX_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, i
|
||||
BFIw(xFlags, x3, F_CF, 1);
|
||||
}
|
||||
SUBxw_U12(x3, ed, 1);
|
||||
IFX(X_ZF)
|
||||
need_tst = 0;
|
||||
IFX(X_ZF) need_tst = 1;
|
||||
IFXNATIVE(X_SF, NF_SF) need_tst = 1;
|
||||
IFXNATIVE(X_OF, NF_VF) need_tst = 1;
|
||||
if(need_tst)
|
||||
ANDSxw_REG(vd, ed, x3);
|
||||
else
|
||||
ANDxw_REG(vd, ed, x3);
|
||||
IFX(X_ZF) {
|
||||
CSETMw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_ZF, 1);
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETMw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(x3, vd, rex.w?63:31);
|
||||
BFIw(xFlags, x3, F_SF, 1);
|
||||
IFNATIVE(NF_SF) {} else {
|
||||
LSRxw(x3, vd, rex.w?63:31);
|
||||
BFIw(xFlags, x3, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_OF) BFCw(xFlags, F_OF, 1);
|
||||
if(box64_dynarec_test) {
|
||||
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);
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
INST_NAME("BLSMSK Vd, Ed");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETED(0);
|
||||
GETVD;
|
||||
IFX(X_CF) {
|
||||
TSTxw_REG(ed, ed);
|
||||
CSETMw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_CF, 1);
|
||||
}
|
||||
SUBxw_U12(x3, ed, 1);
|
||||
need_tst = 0;
|
||||
IFX(X_ZF) need_tst = 1;
|
||||
IFXNATIVE(X_SF, NF_SF) need_tst = 1;
|
||||
IFXNATIVE(X_OF, NF_VF) need_tst = 1;
|
||||
EORxw_REG(vd, ed, x3);
|
||||
if(need_tst)
|
||||
TSTxw_REG(vd, vd);
|
||||
IFX(X_ZF) {
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETMw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
IFNATIVE(NF_SF) {} else {
|
||||
LSRxw(x3, vd, rex.w?63:31);
|
||||
BFIw(xFlags, x3, F_SF, 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);
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
INST_NAME("BLSI Vd, Ed");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETED(0);
|
||||
GETVD;
|
||||
IFX(X_CF) {
|
||||
TSTxw_REG(ed, ed);
|
||||
CSETMw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_CF, 1);
|
||||
}
|
||||
NEGxw_REG(x3, ed);
|
||||
need_tst = 0;
|
||||
IFX(X_ZF) need_tst = 1;
|
||||
IFXNATIVE(X_SF, NF_SF) need_tst = 1;
|
||||
IFXNATIVE(X_OF, NF_VF) need_tst = 1;
|
||||
if(need_tst)
|
||||
ANDSxw_REG(vd, ed, x3);
|
||||
else
|
||||
ANDxw_REG(vd, ed, x3);
|
||||
IFX(X_ZF) {
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETMw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
IFNATIVE(NF_SF) {} else {
|
||||
LSRxw(x3, vd, rex.w?63:31);
|
||||
BFIw(xFlags, x3, F_SF, 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);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
@@ -131,27 +227,72 @@ uintptr_t dynarec64_AVX_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, i
|
||||
GETVD;
|
||||
UXTBw(x1, vd);
|
||||
CMPSw_U12(x1, rex.w?64:32);
|
||||
CSETxw(x2, cPL);
|
||||
IFX(F_CF) {
|
||||
CSETMxw(x2, cPL);
|
||||
IFX(X_CF) {
|
||||
BFIw(xFlags, x2, F_CF, 1);
|
||||
}
|
||||
MVNxw_REG(x2, x2); //prepare mask
|
||||
B_MARK(cPL);
|
||||
LSLxw_REG(x2, x2, x1);
|
||||
MARK;
|
||||
IFX(X_ZF) {
|
||||
need_tst = 0;
|
||||
IFX(X_ZF) need_tst = 1;
|
||||
IFXNATIVE(X_SF, NF_SF) need_tst = 1;
|
||||
IFXNATIVE(X_OF, NF_VF) need_tst = 1;
|
||||
if(need_tst) {
|
||||
BICSxw(gd, ed, x2);
|
||||
CSETw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_ZF, 1);
|
||||
} else
|
||||
BICxw(gd, ed, x2);
|
||||
IFX(X_ZF) {
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(x3, gd, rex.w?63:31);
|
||||
BFIw(xFlags, x3, F_SF, 1);
|
||||
IFNATIVE(NF_SF) {} else {
|
||||
LSRxw(x3, gd, rex.w?63:31);
|
||||
BFIw(xFlags, x3, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_AF) BFCw(xFlags, F_AF, 1);
|
||||
IFX(X_PF) BFCw(xFlags, F_PF, 1);
|
||||
IFX(X_OF) BFCw(xFlags, F_OF, 1);
|
||||
IFX(X_OF) IFNATIVE(NF_VF) {} else {BFCw(xFlags, F_OF, 1);}
|
||||
break;
|
||||
|
||||
case 0xF7:
|
||||
INST_NAME("BEXTR Gd, Ed, Vd");
|
||||
nextop = F8;
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETGD;
|
||||
GETED(0);
|
||||
GETVD;
|
||||
MOV64xw(x1, 0);
|
||||
UXTBw(x2, vd); // start
|
||||
BFXILw(x3, vd, 8, 8); // length
|
||||
TSTw_REG(x3, x3);
|
||||
B_MARK(cEQ);
|
||||
LSRxw_REG(x1, ed, x2);
|
||||
CMPSw_U12(x3, rex.w?64:32);
|
||||
B_MARK(cGE);
|
||||
MOV32w(x2, rex.w?64:32);
|
||||
SUBw_REG(x2, x2, x3);
|
||||
LSLxw_REG(x1, x1, x2);
|
||||
LSRxw_REG(x1, x1, x2);
|
||||
TSTxw_REG(x1, x1);
|
||||
MARK;
|
||||
MOVxw_REG(gd, x1);
|
||||
IFX(X_ZF) {
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
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);}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -56,9 +56,6 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
MAYUSE(s0);
|
||||
MAYUSE(j64);
|
||||
MAYUSE(cacheupd);
|
||||
#if STEP > 1
|
||||
static const int8_t mask_shift8[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
|
||||
#endif
|
||||
|
||||
/* Remember to not create a new fpu_scratch after some GY/VY/EY is created, because Y can be in the scratch area and might overlap (and scratch will win) */
|
||||
|
||||
@@ -273,7 +270,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
GETGX(v0, 0);
|
||||
GETEXSD(q0, 0, 0);
|
||||
FCMPD(v0, q0);
|
||||
FCOMI(x1, x2, 0, v0, q0, 0); //disable precise cmp
|
||||
FCOMI(x1, x2);
|
||||
break;
|
||||
|
||||
case 0x50:
|
||||
@@ -298,13 +295,13 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
case 0x51:
|
||||
INST_NAME("VSQRTPD Gx, Ex");
|
||||
nextop = F8;
|
||||
if(!box64_dynarec_fastnan) {
|
||||
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(v0, v1, 0); } else { GETGY_empty_EY(v0, v1); }
|
||||
if(!box64_dynarec_fastnan) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
// check if any input value was NAN
|
||||
VFCMEQQD(d0, v1, v1); // 0 if NAN, 1 if not NAN
|
||||
VFSQRTQD(v0, v1);
|
||||
@@ -362,19 +359,19 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
case 0x58:
|
||||
INST_NAME("VADDPD Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
if(!box64_dynarec_fastnan) {
|
||||
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(!box64_dynarec_fastnan) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
// check if any input value was NAN
|
||||
VFMAXQD(q0, v2, v1); // propagate NAN
|
||||
VFCMEQQD(q0, q0, q0); // 0 if NAN, 1 if not NAN
|
||||
}
|
||||
VFADDQD(v0, v2, v1);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
VFCMEQQD(q1, v0, v0); // 0 => out is NAN
|
||||
VBICQ(q1, q0, q1); // forget it in any input was a NAN already
|
||||
VSHLQ_64(q1, q1, 63); // only keep the sign bit
|
||||
@@ -386,19 +383,19 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
case 0x59:
|
||||
INST_NAME("VMULPD Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
if(!box64_dynarec_fastnan) {
|
||||
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(!box64_dynarec_fastnan) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
// check if any input value was NAN
|
||||
VFMAXQD(q0, v2, v1); // propagate NAN
|
||||
VFCMEQQD(q0, q0, q0); // 0 if NAN, 1 if not NAN
|
||||
}
|
||||
VFMULQD(v0, v2, v1);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
VFCMEQQD(q1, v0, v0); // 0 => out is NAN
|
||||
VBICQ(q1, q0, q1); // forget it in any input was a NAN already
|
||||
VSHLQ_64(q1, q1, 63); // only keep the sign bit
|
||||
@@ -410,9 +407,9 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
case 0x5A:
|
||||
INST_NAME("VCVTPD2PS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(v1, 0, 0);
|
||||
GETEX_Y(v1, 0, 0);
|
||||
GETGX_empty(v0);
|
||||
if(box64_dynarec_fastround==2) {
|
||||
if(BOX64ENV(dynarec_fastround)==2) {
|
||||
FCVTXN(v0, v1);
|
||||
} else {
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x4);
|
||||
@@ -421,7 +418,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
}
|
||||
if(vex.l) {
|
||||
GETEY(v1);
|
||||
if(box64_dynarec_fastround==2) {
|
||||
if(BOX64ENV(dynarec_fastround)==2) {
|
||||
FCVTXN2(v0, v1);
|
||||
} else {
|
||||
FCVTN2(v0, v1);
|
||||
@@ -434,14 +431,14 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
INST_NAME("VCVTPS2DQ Gx, Ex");
|
||||
nextop = F8;
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x6);
|
||||
if(!box64_dynarec_fastround && !arm64_frintts) {
|
||||
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
MOVI_32_lsl(d1, 0x80, 3);
|
||||
}
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETEX(v1, 0, 0); GETGX_empty(v0); } else { GETGY_empty_EY(v0, v1); }
|
||||
if(box64_dynarec_fastround) {
|
||||
if(!l) { GETEX_Y(v1, 0, 0); GETGX_empty(v0); } else { GETGY_empty_EY(v0, v1); }
|
||||
if(BOX64ENV(dynarec_fastround)) {
|
||||
VFRINTISQ(v0, v1);
|
||||
VFCVTZSQS(v0, v0);
|
||||
} else {
|
||||
@@ -457,7 +454,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
FRINTIS(d0, d0);
|
||||
VFCVTZSs(d0, d0);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TSTw_mask(x5, 0, 0); // mask=1
|
||||
TSTw_mask(x5, 0, 0); // mask=(1<<IOC)
|
||||
FCSELS(d0, d0, d1, cEQ);
|
||||
VMOVeS(v0, i, d0, 0);
|
||||
}
|
||||
@@ -470,19 +467,19 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
case 0x5C:
|
||||
INST_NAME("VSUBPD Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
if(!box64_dynarec_fastnan) {
|
||||
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(!box64_dynarec_fastnan) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
// check if any input value was NAN
|
||||
VFMAXQD(q0, v1, v2); // propagate NAN
|
||||
VFCMEQQD(q0, q0, q0); // 0 if NAN, 1 if not NAN
|
||||
}
|
||||
VFSUBQD(v0, v2, v1);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
VFCMEQQD(q1, v0, v0); // 0 => out is NAN
|
||||
VBICQ(q1, q0, q1); // forget it in any input was a NAN already
|
||||
VSHLQ_64(q1, q1, 63); // only keep the sign bit
|
||||
@@ -494,14 +491,14 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
case 0x5D:
|
||||
INST_NAME("VMINPD Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
if(!box64_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
|
||||
VFMINQD(v0, v2, v1);
|
||||
if(!box64_dynarec_fastnan && (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
|
||||
}
|
||||
@@ -511,19 +508,19 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
case 0x5E:
|
||||
INST_NAME("DIVPD Gx, Ex");
|
||||
nextop = F8;
|
||||
if(!box64_dynarec_fastnan) {
|
||||
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(!box64_dynarec_fastnan) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
// check if any input value was NAN
|
||||
VFMAXQD(q0, v2, v1); // propagate NAN
|
||||
VFCMEQQD(q0, q0, q0); // 0 if NAN, 1 if not NAN
|
||||
}
|
||||
VFDIVQD(v0, v2, v1);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
VFCMEQQD(q1, v0, v0); // 0 => out is NAN
|
||||
VBICQ(q1, q0, q1); // forget it in any input was a NAN already
|
||||
VSHLQ_64(q1, q1, 63); // only keep the sign bit
|
||||
@@ -535,7 +532,7 @@ 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(!box64_dynarec_fastnan) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
}
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
@@ -543,7 +540,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
// 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(!box64_dynarec_fastnan && (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
|
||||
}
|
||||
@@ -1128,13 +1125,13 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
case 0x7C:
|
||||
INST_NAME("VHADDPD Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
if(!box64_dynarec_fastnan) {
|
||||
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(!box64_dynarec_fastnan) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
// check if any input value was NAN
|
||||
// but need to mix low/high part
|
||||
VTRNQ1_64(q0, v2, v1);
|
||||
@@ -1143,7 +1140,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
VFCMEQQD(q0, q0, q0); // 0 if NAN, 1 if not NAN
|
||||
}
|
||||
VFADDPQD(v0, v2, v1);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
VFCMEQQD(q1, v0, v0); // 0 => out is NAN
|
||||
VBICQ(q1, q0, q1); // forget it in any input was a NAN already
|
||||
VSHLQ_64(q1, q1, 63); // only keep the sign bit
|
||||
@@ -1189,11 +1186,11 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
VMOVQ(v1, v0);
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0xffe<<4, 15, rex, NULL, 0, 0);
|
||||
VSTR128_U12(v0, ed, fixedaddress);
|
||||
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);
|
||||
VSTR128_U12(v0, ed, fixedaddress+16);
|
||||
VST128(v0, ed, fixedaddress+16);
|
||||
}
|
||||
SMWRITE2();
|
||||
}
|
||||
@@ -1254,7 +1251,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
GETEX(v0, 0, 1);
|
||||
GETEX(v0, 0, 1); // no vex.l case
|
||||
u8 = (F8)&7;
|
||||
VMOVHto(gd, v0, u8);
|
||||
} else {
|
||||
@@ -1396,9 +1393,8 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEX_Y(q0, 0, 0);
|
||||
GETGD;
|
||||
TABLE64(x2, (uintptr_t)&mask_shift8);
|
||||
VLDR64_U12(v0, x2, 0); // load shift
|
||||
VDUPQ_64(v0, v0, 0);
|
||||
TABLE64(x2, 0x0706050403020100LL);
|
||||
VDUPQD(v0, x2);
|
||||
VSHRQ_8(q1, q0, 7);
|
||||
USHLQ_8(q1, q1, v0); // shift
|
||||
UADDLV_8(v1, q1); // accumalte
|
||||
@@ -1620,11 +1616,11 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
GETEX_Y(v1, 0, 0);
|
||||
GETGX_empty(v0);
|
||||
} else {
|
||||
if(box64_dynarec_fastround)
|
||||
if(BOX64ENV(dynarec_fastround))
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
GETEY(v1);
|
||||
}
|
||||
if(box64_dynarec_fastround) {
|
||||
if(BOX64ENV(dynarec_fastround)) {
|
||||
VFCVTZSQD(l?d0:v0, v1); // convert double -> int64
|
||||
if(!l)
|
||||
SQXTN_32(v0, v0); // convert int64 -> int32 with saturation in lower part, RaZ high part
|
||||
@@ -1796,12 +1792,13 @@ 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);
|
||||
UQXTN_32(q0, v1);
|
||||
MOVI_32(q1, 16);
|
||||
UMIN_32(q0, q0, q1); // limit to 0 .. +16 values
|
||||
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_VYEY(v0, v2, v1); }
|
||||
UQXTN_32(q0, v1);
|
||||
UMIN_32(q0, q0, q1); // limit to 0 .. +16 values
|
||||
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);
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
@@ -1811,12 +1808,13 @@ 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);
|
||||
UQXTN_32(q0, v1);
|
||||
MOVI_32(q1, 32);
|
||||
UMIN_32(q0, q0, q1); // limit to 0 .. +32 values
|
||||
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_VYEY(v0, v2, v1); }
|
||||
UQXTN_32(q0, v1);
|
||||
UMIN_32(q0, q0, q1); // limit to 0 .. +32 values
|
||||
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); }
|
||||
USHLQ_32(v0, v2, q0);
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
@@ -1826,12 +1824,13 @@ 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);
|
||||
UQXTN_32(q0, v1);
|
||||
MOVI_32(q1, 64);
|
||||
UMIN_32(q0, q0, q1); // limit to 0 .. +64 values
|
||||
VDUPQ_64(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_VYEY(v0, v2, v1); }
|
||||
UQXTN_32(q0, v1);
|
||||
UMIN_32(q0, q0, q1); // limit to 0 .. +64 values
|
||||
VDUPQ_64(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);
|
||||
@@ -1881,7 +1880,21 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0xF7:
|
||||
INST_NAME("VMASKMOVDQU Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0); //no vex.l case
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
VLDR128_U12(v0, xRDI, 0);
|
||||
if(MODREG)
|
||||
v1 = fpu_get_scratch(dyn, ninst); // need to preserve the register
|
||||
else
|
||||
v1 = q1;
|
||||
VSSHRQ_8(v1, q1, 7); // get the mask
|
||||
VBITQ(v0, q0, v1);
|
||||
VSTR128_U12(v0, xRDI, 0); // put back
|
||||
break;
|
||||
case 0xF8:
|
||||
INST_NAME("VPSUBB Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
|
||||
static const float addsubps[4] = {-1.f, 1.f, -1.f, 1.f};
|
||||
static const double addsubpd[2] = {-1., 1.};
|
||||
static const float subaddps[4] = {1.f, -1.f, 1.f, -1.f};
|
||||
static const double subaddpd[2] = {1., -1.};
|
||||
|
||||
uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
|
||||
{
|
||||
@@ -97,7 +99,18 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0x03:
|
||||
INST_NAME("VPHADDSW Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_VXEX(q0, q2, q1, 0); } else { GETGY_empty_VYEY(q0, q2, q1); }
|
||||
VUZP2Q_16(v0, q2, q1);
|
||||
VUZP1Q_16(q0, q2, q1);
|
||||
SQADDQ_16(q0, q0, v0);
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x04:
|
||||
INST_NAME("PMADDUBSW Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
@@ -124,7 +137,42 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0x05:
|
||||
INST_NAME("VPHSUBW Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_VXEX(q0, q2, q1, 0); } else { GETGY_empty_VYEY(q0, q2, q1); }
|
||||
VUZP2Q_16(v0, q2, q1);
|
||||
VUZP1Q_16(q0, q2, q1);
|
||||
VSUBQ_16(q0, q0, v0);
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x06:
|
||||
INST_NAME("VPHSUBD Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_VXEX(q0, q2, q1, 0); } else { GETGY_empty_VYEY(q0, q2, q1); }
|
||||
VUZP2Q_32(v0, q2, q1);
|
||||
VUZP1Q_32(q0, q2, q1);
|
||||
VSUBQ_32(q0, q0, v0);
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x7:
|
||||
INST_NAME("VPHSUBSW Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_VXEX(q0, q2, q1, 0); } else { GETGY_empty_VYEY(q0, q2, q1); }
|
||||
VUZP2Q_16(v0, q2, q1);
|
||||
VUZP1Q_16(q0, q2, q1);
|
||||
SQSUBQ_16(q0, q0, v0);
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x08:
|
||||
INST_NAME("VPSIGNB Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
@@ -204,6 +252,109 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0x0E:
|
||||
INST_NAME("VTESTPS GX, EX");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
GETEX_Y(v1, 0, 0);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
if(vex.l) {
|
||||
if(!MODREG)
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
q2 = fpu_get_scratch(dyn, ninst);
|
||||
GETGY(q0, 0, MODREG?((nextop&7)+(rex.b<<3)):-1, -1, -1);
|
||||
GETEY(q1);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
VBICQ(v2, v1, v0);
|
||||
VSHRQ_32(v2, v2, 31);
|
||||
if(vex.l) {
|
||||
VBICQ(q2, q1, q0);
|
||||
VSHRQ_32(q2, q2, 31);
|
||||
VORRQ(v2, v2, q2);
|
||||
}
|
||||
CMEQQ_0_64(v2, v2);
|
||||
UQXTN_32(v2, v2);
|
||||
VMOVQDto(x2, v2, 0);
|
||||
ADDSx_U12(xZR, x2, 1);
|
||||
CSETw(x2, cEQ);
|
||||
BFIw(xFlags, x2, F_CF, 1);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
VANDQ(v2, v0, v1);
|
||||
VSHRQ_32(v2, v2, 31);
|
||||
if(vex.l) {
|
||||
VANDQ(q2, q0, q1);
|
||||
VSHRQ_32(q2, q2, 31);
|
||||
VORRQ(v2, v2, q2);
|
||||
}
|
||||
CMEQQ_0_64(v2, v2);
|
||||
UQXTN_32(v2, v2);
|
||||
VMOVQDto(x2, v2, 0);
|
||||
ADDSx_U12(xZR, x2, 1);
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(x2, cEQ);
|
||||
BFIw(xFlags, x2, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_AF|X_SF|X_OF|X_PF) {
|
||||
MOV32w(x2, (1<<F_AF) | (1<<F_OF) | (1<<F_SF) | (1<<F_PF));
|
||||
BICw(xFlags, xFlags, x2);
|
||||
}
|
||||
break;
|
||||
case 0x0F:
|
||||
INST_NAME("VTESTPD GX, EX");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
GETEX_Y(v1, 0, 0);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
if(vex.l) {
|
||||
if(!MODREG)
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
q2 = fpu_get_scratch(dyn, ninst);
|
||||
GETGY(q0, 0, MODREG?((nextop&7)+(rex.b<<3)):-1, -1, -1);
|
||||
GETEY(q1);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
VBICQ(v2, v1, v0);
|
||||
VSHRQ_64(v2, v2, 63);
|
||||
if(vex.l) {
|
||||
VBICQ(q2, q1, q0);
|
||||
VSHRQ_64(q2, q2, 63);
|
||||
VORRQ(v2, v2, q2);
|
||||
}
|
||||
CMEQQ_0_64(v2, v2);
|
||||
UQXTN_32(v2, v2);
|
||||
VMOVQDto(x2, v2, 0);
|
||||
ADDSx_U12(xZR, x2, 1);
|
||||
CSETw(x2, cEQ);
|
||||
BFIw(xFlags, x2, F_CF, 1);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
VANDQ(v2, v0, v1);
|
||||
VSHRQ_64(v2, v2, 63);
|
||||
if(vex.l) {
|
||||
VANDQ(q2, q0, q1);
|
||||
VSHRQ_64(q2, q2, 63);
|
||||
VORRQ(v2, v2, q2);
|
||||
}
|
||||
CMEQQ_0_64(v2, v2);
|
||||
UQXTN_32(v2, v2);
|
||||
VMOVQDto(x2, v2, 0);
|
||||
ADDSx_U12(xZR, x2, 1);
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(x2, cEQ);
|
||||
BFIw(xFlags, x2, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_AF|X_SF|X_OF|X_PF) {
|
||||
MOV32w(x2, (1<<F_AF) | (1<<F_OF) | (1<<F_SF) | (1<<F_PF));
|
||||
BICw(xFlags, xFlags, x2);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x13:
|
||||
INST_NAME("VCVTPH2PS Gx, Ex");
|
||||
nextop = F8;
|
||||
@@ -241,6 +392,8 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
VLDR128_U12(d0, ed, fixedaddress);
|
||||
VLDR128_U12(d1, ed, fixedaddress+16);
|
||||
}
|
||||
MOV32w(x3, 0x03020100);
|
||||
VDUPQS(q1, x3);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) {
|
||||
GETVX(v2, 0);
|
||||
@@ -253,14 +406,10 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
MOVIQ_32(q0, 7); // index and 7
|
||||
VANDQ(q0, v2, q0);
|
||||
SQXTN_16(q0, q0); // index in 16bits
|
||||
VSHL_16(q0, q0, 1); // double the index
|
||||
VZIP1Q_16(q0, q0, q0); // repeat the index by pair
|
||||
MOVIQ_32_lsl(q1, 1, 2); // q1 as 16bits is 0 / 1
|
||||
VADDQ_16(q0, q0, q1);
|
||||
SQXTN_8(q0, q0); // index in 8bits
|
||||
VSHL_8(q0, q0, 1); // double the index
|
||||
VSHL_8(q0, q0, 2); // quadruple the indexes
|
||||
VZIP1Q_8(q0, q0, q0); // repeat the index by pair
|
||||
MOVIQ_16(q1, 1, 1);
|
||||
VADDQ_8(q0, q0, q1);
|
||||
// fetch the datas
|
||||
VTBLQ2_8(v0, d0, q0);
|
||||
@@ -272,35 +421,21 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
if(MODREG) {
|
||||
GETEX(v1, 0, 0);
|
||||
} else {
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0xffe<<4, 15, rex, NULL, 0, 0);
|
||||
}
|
||||
GETEX_Y(v1, 0, 0);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
if(vex.l) {
|
||||
GETGY(v0, 0, MODREG?((nextop&7)+(rex.b<<3)):-1, -1, -1);
|
||||
if(MODREG) {
|
||||
GETEY(v1);
|
||||
} else {
|
||||
VLDR128_U12(v1, ed, fixedaddress+16);
|
||||
}
|
||||
} else {
|
||||
if(!MODREG)
|
||||
VLDR128_U12(v1, ed, fixedaddress);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
VANDQ(v2, v0, v1);
|
||||
CMEQQ_0_64(v2, v2);
|
||||
UQXTN_32(v2, v2);
|
||||
VMOVQDto(x2, v2, 0);
|
||||
ADDSx_U12(xZR, x2, 1);
|
||||
CSETw(x2, cEQ);
|
||||
BFIw(xFlags, x2, F_ZF, 1);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
q2 = fpu_get_scratch(dyn, ninst);
|
||||
GETGY(q0, 0, MODREG?((nextop&7)+(rex.b<<3)):-1, -1, -1);
|
||||
GETEY(q1);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
VBICQ(v2, v1, v0);
|
||||
if(vex.l) {
|
||||
VBICQ(q2, q1, q0);
|
||||
VORRQ(v2, v2, q2);
|
||||
}
|
||||
CMEQQ_0_64(v2, v2);
|
||||
UQXTN_32(v2, v2);
|
||||
VMOVQDto(x2, v2, 0);
|
||||
@@ -308,6 +443,21 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
CSETw(x2, cEQ);
|
||||
BFIw(xFlags, x2, F_CF, 1);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
VANDQ(v2, v0, v1);
|
||||
if(vex.l) {
|
||||
VANDQ(q2, q0, q1);
|
||||
VORRQ(v2, v2, q2);
|
||||
}
|
||||
CMEQQ_0_64(v2, v2);
|
||||
UQXTN_32(v2, v2);
|
||||
VMOVQDto(x2, v2, 0);
|
||||
ADDSx_U12(xZR, x2, 1);
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(x2, cEQ);
|
||||
BFIw(xFlags, x2, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_AF|X_SF|X_OF|X_PF) {
|
||||
MOV32w(x2, (1<<F_AF) | (1<<F_OF) | (1<<F_SF) | (1<<F_PF));
|
||||
BICw(xFlags, xFlags, x2);
|
||||
@@ -318,16 +468,16 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
VLD32(v1, ed, fixedaddress);
|
||||
}
|
||||
GETGX_empty(v0);
|
||||
VDUPQ_32(v0, v1, 0);
|
||||
if(vex.l) {
|
||||
GETGY_empty(v0, -1, -1, -1);
|
||||
GETGX_empty(v0);
|
||||
VDUPQ_32(v0, v1, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
GETGX_empty(v0);
|
||||
VLDQ1R_32(v0, ed);
|
||||
}
|
||||
if(vex.l) {
|
||||
GETGY_empty(v1, -1, -1, -1);
|
||||
VMOVQ(v1, v0);
|
||||
} else YMM0(gd);
|
||||
break;
|
||||
case 0x19:
|
||||
@@ -335,16 +485,16 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
VLD64(v1, ed, fixedaddress);
|
||||
}
|
||||
GETGX_empty(v0);
|
||||
VDUPQ_64(v0, v1, 0);
|
||||
if(vex.l) {
|
||||
GETGY_empty(v0, -1, -1, -1);
|
||||
GETGX_empty(v0);
|
||||
VDUPQ_64(v0, v1, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
GETGX_empty(v0);
|
||||
VLDQ1R_64(v0, ed);
|
||||
}
|
||||
if(vex.l) {
|
||||
GETGY_empty(v1, -1, -1, -1);
|
||||
VMOVQ(v1, v0);
|
||||
} else YMM0(gd);
|
||||
break;
|
||||
case 0x1A:
|
||||
@@ -394,7 +544,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
case 0x20:
|
||||
INST_NAME("VPMOVSXBW Gx, Ex");
|
||||
nextop = F8;
|
||||
if(vex.l) {GETEX(q1, 0, 0);} else {GETEX64(q1, 0, 0);}
|
||||
if(vex.l) {GETEX(q1, 0, 0);} else {GETEX64(q1, 0, 0);} //no GETEY
|
||||
GETGX_empty(q0);
|
||||
if(vex.l) {
|
||||
GETGY_empty(v0, -1, -1, -1);
|
||||
@@ -433,7 +583,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
case 0x23:
|
||||
INST_NAME("VPMOVSXWD Gx, Ex");
|
||||
nextop = F8;
|
||||
if(vex.l) {GETEX(q1, 0, 0);} else {GETEX64(q1, 0, 0);}
|
||||
if(vex.l) {GETEX(q1, 0, 0);} else {GETEX64(q1, 0, 0);} //no GETEY
|
||||
GETGX_empty(q0);
|
||||
if(vex.l) {
|
||||
GETGY_empty(v0, -1, -1, -1);
|
||||
@@ -457,7 +607,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
case 0x25:
|
||||
INST_NAME("VPMOVSXDQ Gx, Ex");
|
||||
nextop = F8;
|
||||
if(vex.l) {GETEX(q1, 0, 0);} else {GETEX64(q1, 0, 0);}
|
||||
if(vex.l) {GETEX(q1, 0, 0);} else {GETEX64(q1, 0, 0);} //no GETEY
|
||||
GETGX_empty(q0);
|
||||
if(vex.l) {
|
||||
GETGY_empty(v0, -1, -1, -1);
|
||||
@@ -495,7 +645,15 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
|
||||
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);
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x2B:
|
||||
INST_NAME("VPACKUSDW Gx, Ex, Vx");
|
||||
nextop = F8;
|
||||
@@ -523,29 +681,115 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
case 0x2C:
|
||||
INST_NAME("VMASKMOVPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETGX_empty_VXEX(v0, v2, v1, 0);
|
||||
GETVX(v2, 0);
|
||||
GETGX_empty(v0);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
// create mask
|
||||
VSSHRQ_32(q0, v2, 31);
|
||||
VANDQ(v0, v1, q0);
|
||||
if(vex.l) {
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
VSSHRQ_32(q0, v2, 31);
|
||||
if (MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x3, (nextop & 7) + (rex.b << 3), 0);
|
||||
VANDQ(v0, v1, q0);
|
||||
} 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);
|
||||
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);
|
||||
if(vex.l)
|
||||
ADDx_U12(ed, ed, 4);
|
||||
}
|
||||
if(vex.l) {
|
||||
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);
|
||||
}
|
||||
} else YMM0(gd);
|
||||
break;
|
||||
case 0x2D:
|
||||
INST_NAME("VMASKMOVPD Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETGX_empty_VXEX(v0, v2, v1, 0);
|
||||
GETVX(v2, 0);
|
||||
GETGX_empty(v0);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
// create mask
|
||||
VSSHRQ_64(q0, v2, 63);
|
||||
VANDQ(v0, v1, q0);
|
||||
if(vex.l) {
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
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);
|
||||
} 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);
|
||||
VMOVQDto(x4, q0, 1);
|
||||
CBZx(x4, 4+1*4);
|
||||
VLD1_64(v0, 1, ed);
|
||||
if(vex.l)
|
||||
ADDx_U12(ed, ed, 8);
|
||||
}
|
||||
if(vex.l) {
|
||||
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_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);
|
||||
}
|
||||
} else YMM0(gd);
|
||||
break;
|
||||
case 0x2E:
|
||||
@@ -557,37 +801,58 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
VSSHRQ_32(q0, v2, 31);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x3, (nextop&7)+(rex.b<<3), 1);
|
||||
VBITQ(v1, v0, q0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0xffe<<4, 15, rex, NULL, 0, 0);
|
||||
unscaled = 0;
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
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!
|
||||
SQXTN_32(v1, q0);
|
||||
VMOVQDto(x4, v1, 0);
|
||||
CBZx(x4, 4+3*4);
|
||||
VLDR128_U12(v1, ed, fixedaddress);
|
||||
}
|
||||
// create mask
|
||||
VBITQ(v1, v0, q0);
|
||||
if(!MODREG) {
|
||||
VSTR128_U12(v1, ed, fixedaddress);
|
||||
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);
|
||||
if(vex.l)
|
||||
ADDx_U12(ed, ed, 4);
|
||||
}
|
||||
|
||||
if(vex.l && !is_avx_zero(dyn, ninst, vex.v)) {
|
||||
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)
|
||||
if(MODREG) {
|
||||
v1 = ymm_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 1, gd, vex.v, -1);
|
||||
else {
|
||||
SQXTN_32(v1, q0);
|
||||
VMOVQDto(x4, v1, 0);
|
||||
CBZx(x4, 4+3*4);
|
||||
VLDR128_U12(v1, ed, fixedaddress+16);
|
||||
VBITQ(v1, v0, q0);
|
||||
}
|
||||
VBITQ(v1, v0, q0);
|
||||
if(!MODREG) {
|
||||
VSTR128_U12(v1, ed, fixedaddress+16);
|
||||
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);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -595,43 +860,49 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
INST_NAME("VMASKMOVPD Ex, Gx, Vx");
|
||||
nextop = F8;
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
GETVX(v2, 0);
|
||||
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);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0xffe<<4, 15, rex, NULL, 0, 0);
|
||||
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.
|
||||
// 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!
|
||||
SQXTN_32(q1, q0);
|
||||
VMOVQDto(x4, q1, 0);
|
||||
CBZx(x4, 4+3*4);
|
||||
VLDR128_U12(v1, ed, fixedaddress);
|
||||
}
|
||||
// create mask
|
||||
VBITQ(v1, v0, q0);
|
||||
if(!MODREG) {
|
||||
VSTR128_U12(v1, ed, fixedaddress);
|
||||
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);
|
||||
if(vex.l)
|
||||
ADDx_U12(ed, ed, 8);
|
||||
}
|
||||
|
||||
if(vex.l && !is_avx_zero(dyn, ninst, vex.v)) {
|
||||
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)
|
||||
if(MODREG) {
|
||||
v1 = ymm_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 1, gd, vex.v, -1);
|
||||
else {
|
||||
SQXTN_32(q1, q0);
|
||||
VMOVQDto(x4, q1, 0);
|
||||
CBZx(x4, 4+3*4);
|
||||
VLDR128_U12(v1, ed, fixedaddress+16);
|
||||
VBITQ(v1, v0, q0);
|
||||
}
|
||||
VBITQ(v1, v0, q0);
|
||||
if(!MODREG) {
|
||||
VSTR128_U12(v1, ed, fixedaddress+16);
|
||||
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);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -639,7 +910,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
INST_NAME("VPMOVZXBW Gx, Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(vex.l) { GETEX(q1, 0, 0); } else { GETEX64(q1, 0, 0); YMM0(gd); }
|
||||
if(vex.l) { GETEX(q1, 0, 0); } else { GETEX64(q1, 0, 0); YMM0(gd); } //no GETEY
|
||||
GETGX_empty(q0);
|
||||
if(vex.l) {
|
||||
GETGY_empty(v0, -1, -1, -1);
|
||||
@@ -681,7 +952,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
INST_NAME("VPMOVZXWD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(vex.l) { GETEX(q1, 0, 0); } else { GETEX64(q1, 0, 0); YMM0(gd); }
|
||||
if(vex.l) { GETEX(q1, 0, 0); } else { GETEX64(q1, 0, 0); YMM0(gd); } //no GETEY
|
||||
GETGX_empty(q0);
|
||||
if(vex.l) {
|
||||
GETGY_empty(v0, -1, -1, -1);
|
||||
@@ -707,7 +978,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
INST_NAME("VPMOVZXDQ Gx, Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(vex.l) { GETEX(q1, 0, 0); } else { GETEX64(q1, 0, 0); YMM0(gd); }
|
||||
if(vex.l) { GETEX(q1, 0, 0); } else { GETEX64(q1, 0, 0); YMM0(gd); } //no GETEY
|
||||
GETGX_empty(q0);
|
||||
if(vex.l) {
|
||||
GETGY_empty(v0, -1, -1, -1);
|
||||
@@ -807,9 +1078,9 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x41:
|
||||
INST_NAME("PHMINPOSUW Gx, Ex");
|
||||
INST_NAME("VPHMINPOSUW Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(v1, 0, 0);
|
||||
GETEX(v1, 0, 0); //no vex.l case
|
||||
GETGX_empty(v0);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
@@ -1014,6 +1285,10 @@ 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);
|
||||
@@ -1027,12 +1302,12 @@ 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, 4);
|
||||
ADDx_U12(ed, ed, 8);
|
||||
VMOVQDto(x4, q0, 1);
|
||||
CBZx(x4, 4+1*4);
|
||||
VLD1_64(v1, 1, ed);
|
||||
if(!l && vex.l)
|
||||
ADDx_U12(ed, ed, 4);
|
||||
ADDx_U12(ed, ed, 8);
|
||||
} else {
|
||||
VSSHRQ_32(q0, v2, 31);
|
||||
VMOVSto(x4, q0, 0);
|
||||
@@ -1064,31 +1339,65 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
nextop = F8;
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) {
|
||||
GETGX(v0, 0); GETVX(v2, 0);
|
||||
if(MODREG) {
|
||||
if(MODREG) {
|
||||
if(!l) {
|
||||
GETGX(v0, 0); GETVX(v2, 0);
|
||||
s0 = (nextop&7)+(rex.b<<3);
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, s0);
|
||||
} else {
|
||||
GETGY(v0, 0, vex.v, s0, -1); v2 = ymm_get_reg(dyn, ninst, x1, vex.v, 0, gd, s0, -1);
|
||||
v1 = ymm_get_reg_empty(dyn, ninst, x1, s0, gd, vex.v, -1);
|
||||
}
|
||||
if(rex.w)
|
||||
VSSHRQ_64(q0, v2, 63);
|
||||
else
|
||||
VSSHRQ_32(q0, v2, 31);
|
||||
VBITQ(v1, v0, q0);
|
||||
} else {
|
||||
if(!l) {
|
||||
GETGX(v0, 0); GETVX(v2, 0);
|
||||
s0 = -1;
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0xffe<<4, 15, rex, NULL, 0, 0);
|
||||
VLDR128_U12(v1, ed, fixedaddress);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
EORx_REG(x4, x4, x4);
|
||||
} else {
|
||||
GETGY(v0, 0, vex.v, s0, -1); v2 = ymm_get_reg(dyn, ninst, x1, vex.v, 0, gd, s0, -1);
|
||||
}
|
||||
if(rex.w)
|
||||
{
|
||||
VSSHRQ_64(q0, v2, 63);
|
||||
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);
|
||||
if(!l && vex.l)
|
||||
ADDx_U12(ed, ed, 8);
|
||||
}
|
||||
} else {
|
||||
GETGY(v0, 0, vex.v, s0, -1); v2 = ymm_get_reg(dyn, ninst, x1, vex.v, 0, gd, s0, -1);
|
||||
if(MODREG)
|
||||
v1 = ymm_get_reg_empty(dyn, ninst, x1, s0, gd, vex.v, -1);
|
||||
else
|
||||
VLDR128_U12(v1, ed, fixedaddress+16);
|
||||
{
|
||||
VSSHRQ_32(q0, v2, 31);
|
||||
VMOVSto(x4, q0, 0);
|
||||
CBZx(x4, 4+1*4);
|
||||
VST1_32(v0, 0, ed);
|
||||
ADDx_U12(ed, ed, 4);
|
||||
VMOVSto(x4, q0, 1);
|
||||
CBZx(x4, 4+1*4);
|
||||
VST1_32(v0, 1, ed);
|
||||
ADDx_U12(ed, ed, 4);
|
||||
VMOVSto(x4, q0, 2);
|
||||
CBZx(x4, 4+1*4);
|
||||
VST1_32(v0, 2, ed);
|
||||
ADDx_U12(ed, ed, 4);
|
||||
VMOVSto(x4, q0, 3);
|
||||
CBZx(x4, 4+1*4);
|
||||
VST1_32(v0, 3, ed);
|
||||
if(!l && vex.l)
|
||||
ADDx_U12(ed, ed, 4);
|
||||
}
|
||||
}
|
||||
if(rex.w)
|
||||
VSSHRQ_64(q0, v2, 63);
|
||||
else
|
||||
VSSHRQ_32(q0, v2, 31);
|
||||
VBITQ(v1, v0, q0);
|
||||
if(!MODREG)
|
||||
VSTR128_U12(v1, ed, fixedaddress+16*l);
|
||||
}
|
||||
// no raz of upper ymm
|
||||
break;
|
||||
@@ -1502,7 +1811,29 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0xB7:
|
||||
INST_NAME("VFMSUBADD231PS/D Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
TABLE64(x2, (rex.w)?((uintptr_t)&subaddpd):((uintptr_t)&subaddps));
|
||||
VLDR128_U12(q0, x2, 0);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_VXEX(v0, v2, v1, 0); if(v0==v2 || v0==v1) q1 = fpu_get_scratch(dyn, ninst); } else { GETGY_VYEY(v0, v2, v1); }
|
||||
if(v0!=v1 && v0!=v2) {
|
||||
q1 = v0;
|
||||
}
|
||||
if(rex.w) {
|
||||
VFMULQD(q1, v0, q0);
|
||||
VFMLAQD(q1, v1, v2);
|
||||
} else {
|
||||
VFMULQS(q1, v0, q0);
|
||||
VFMLAQS(q1, v1, v2);
|
||||
}
|
||||
if(q1!=v0)
|
||||
VMOVQ(v0, q1);
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0xB8:
|
||||
INST_NAME("VFMADD231PS/D Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
@@ -1589,6 +1920,23 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0xDB:
|
||||
INST_NAME("VAESIMC Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX_empty_EX(v0, v1, 0);
|
||||
if(arm64_aes) {
|
||||
AESIMC(v0, v1);
|
||||
} else {
|
||||
if(v0!=v1) {
|
||||
VMOVQ(v0, v1);
|
||||
}
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
MOV32w(x1, gd);
|
||||
CALL(native_aesimc, -1);
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0xDC:
|
||||
INST_NAME("VAESENC Gx, Vx, Ex"); // AES-NI
|
||||
nextop = F8;
|
||||
|
||||
@@ -135,15 +135,21 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
if(!l) {
|
||||
GETGX_empty_EX(v0, v1, 1);
|
||||
u8 = F8;
|
||||
if(v0==v1) {q1 = fpu_get_scratch(dyn, ninst); VMOVQ(q1, v1);}
|
||||
} else {
|
||||
GETGY_empty_EY(v0, v1);
|
||||
if(v0==v1) {VMOVQ(q1, v1);}
|
||||
}
|
||||
if(((u8>>(l*2))&1)==((u8>>(1+l*2))&1))
|
||||
VDUPQ_64(v0, (v0==v1)?q1:v1, ((u8>>(l*2))&1));
|
||||
else for(int i=0; i<2; ++i)
|
||||
VMOVeD(v0, i, (v0==v1)?q1:v1, (u8>>(i+l*2))&1);
|
||||
switch(((u8>>(l*2))&3)) {
|
||||
case 0b00:
|
||||
case 0b11:
|
||||
VDUPQ_64(v0, v1, ((u8>>(l*2))&1));
|
||||
break;
|
||||
case 0b10:
|
||||
if(v0!=v1) VMOVQ(v0, v1);
|
||||
break;
|
||||
case 0b01:
|
||||
VEXTQ_8(v0, v1, v1, 8); // invert 64bits values
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
@@ -308,7 +314,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
} else YMM0(gd);
|
||||
break;
|
||||
case 0x0D:
|
||||
INST_NAME("VPBLENDPD Gx, Vx, Ex, Ib");
|
||||
INST_NAME("VBLENDPD Gx, Vx, Ex, Ib");
|
||||
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); }
|
||||
@@ -592,32 +598,60 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
// first mask
|
||||
wb1 = 0; // mask
|
||||
for(int i=0; i<4; ++i)
|
||||
if(u8&(1<<i))
|
||||
wb1 |= (3<<(i*2));
|
||||
MOVI_64(q0, wb1); // load 8bits value as a 8bytes mask
|
||||
SXTL_16(q0, q0); // expand 16bits to 32bits...
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
// second mask
|
||||
wb1 = 0; // mask
|
||||
for(int i=0; i<4; ++i)
|
||||
if((u8>>4)&(1<<i))
|
||||
wb1 |= (3<<(i*2));
|
||||
MOVI_64(q1, wb1); // load 8bits value as a 8bytes mask
|
||||
SXTL_16(q1, q1); // expand 16bits to 32bits...
|
||||
if((u8&0x0f)!=0x0f) {
|
||||
wb1 = 0; // mask
|
||||
for(int i=0; i<4; ++i)
|
||||
if(u8&(1<<i))
|
||||
wb1 |= (3<<(i*2));
|
||||
MOVI_64(q0, wb1); // load 8bits value as a 8bytes mask
|
||||
SXTL_16(q0, q0); // expand 16bits to 32bits...
|
||||
}
|
||||
if((u8&0xf0)!=0xf0) {
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
// second mask
|
||||
wb1 = 0; // mask
|
||||
for(int i=0; i<4; ++i)
|
||||
if((u8>>4)&(1<<i))
|
||||
wb1 |= (3<<(i*2));
|
||||
MOVI_64(q1, wb1); // load 8bits value as a 8bytes mask
|
||||
SXTL_16(q1, q1); // expand 16bits to 32bits...
|
||||
}
|
||||
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); }
|
||||
VFMULQS(v0, v2, v1);
|
||||
VANDQ(v0, v0, q1); // second mask
|
||||
if((u8&0xf0)!=0xf0) {
|
||||
VANDQ(v0, v0, q1); // second mask
|
||||
}
|
||||
VFADDPQS(v0, v0, v0);
|
||||
FADDPS(v0, v0);
|
||||
VDUPQ_32(v0, v0, 0);
|
||||
VANDQ(v0, v0, q0); // first mask
|
||||
if((u8&0x0f)!=0x0f) {
|
||||
VANDQ(v0, v0, q0); // first mask
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0x41:
|
||||
INST_NAME("VDPPD Gx, Vx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGX_empty_VXEX(v0, v1, v2, 0);
|
||||
u8 = F8;
|
||||
VFMULQD(v0, v1, v2);
|
||||
// mask some, duplicate all, mask some
|
||||
for(int i=0; i<2; ++i)
|
||||
if(!(u8&(1<<(4+i)))) {
|
||||
VMOVQDfrom(v0, i, xZR);
|
||||
}
|
||||
FADDPD(v0, v0);
|
||||
VDUPQ_64(v0, v0, 0);
|
||||
for(int i=0; i<2; ++i)
|
||||
if(!(u8&(1<<i))) {
|
||||
VMOVQDfrom(v0, i, xZR);
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0x44:
|
||||
INST_NAME("PCLMULQDQ Gx, Vx, Ex, Ib");
|
||||
nextop = F8;
|
||||
@@ -770,6 +804,30 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0xDF:
|
||||
INST_NAME("VAESKEYGENASSIST Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
MOV32w(x1, gd); // gx
|
||||
if(MODREG) {
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
sse_forget_reg(dyn, ninst, ed);
|
||||
MOV32w(x2, ed);
|
||||
MOV32w(x3, 0); //p = NULL
|
||||
} else {
|
||||
MOV32w(x2, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 1);
|
||||
if(ed!=x3) {
|
||||
MOVx_REG(x3, ed);
|
||||
}
|
||||
}
|
||||
u8 = F8;
|
||||
MOV32w(x4, u8);
|
||||
CALL(native_aeskeygenassist, -1);
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
if(vex.l) {
|
||||
GETGY_empty(v0, -1, -1, -1);
|
||||
ADDx_U12(x3, ed, 16);
|
||||
VLDQ1R_64(v0, ed);
|
||||
VLDQ1R_64(v0, x3);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
@@ -140,13 +140,13 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEXSD(q0, 0, 0);
|
||||
if(!box64_dynarec_fastround) {
|
||||
if(!BOX64ENV(dynarec_fastround)) {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
}
|
||||
FCVTZSxwD(gd, q0);
|
||||
if(!box64_dynarec_fastround) {
|
||||
if(!BOX64ENV(dynarec_fastround)) {
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_NEXT(x5, FPSR_IOC);
|
||||
if(rex.w) {
|
||||
@@ -161,7 +161,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEXSD(q0, 0, 0);
|
||||
if(!box64_dynarec_fastround) {
|
||||
if(!BOX64ENV(dynarec_fastround)) {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
@@ -171,7 +171,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
FRINTID(d1, q0);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
FCVTZSxwD(gd, d1);
|
||||
if(!box64_dynarec_fastround) {
|
||||
if(!BOX64ENV(dynarec_fastround)) {
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_NEXT(x5, FPSR_IOC);
|
||||
if(rex.w) {
|
||||
@@ -188,14 +188,14 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSD(v1, 0, 0);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
FCMEQD(q0, v1, v1); // 0 if NAN, 1 if not NAN
|
||||
}
|
||||
FSQRTD(d1, v1);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
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
|
||||
@@ -211,28 +211,54 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
case 0x58:
|
||||
INST_NAME("VADDSD Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
q2 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSD(v1, 0, 0);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
FADDD(d1, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
FMAXD(q1, v0, v1); // propagate NAN
|
||||
FCMEQD(q1, q1, q1); // 0 if NAN, 1 if not NAN
|
||||
FADDD(q2, v1, v2); // the high part of the vector is erased...
|
||||
FCMEQD(q0, q2, q2); // 0 => out is NAN
|
||||
VBIC(q0, q1, q0); // forget it in any input was a NAN already
|
||||
SHL_64(q0, q0, 63); // only keep the sign bit
|
||||
VORR(q2, q2, q0); // NAN -> -NAN
|
||||
} else {
|
||||
FADDD(q2, v1, v2); // the high part of the vector is erased...
|
||||
}
|
||||
if(v0!=v2) {
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeD(v0, 0, d1, 0);
|
||||
VMOVeD(v0, 0, q2, 0);
|
||||
YMM0(gd)
|
||||
break;
|
||||
case 0x59:
|
||||
INST_NAME("VMULSD Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
q2 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSD(v1, 0, 0);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
FMULD(d1, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
FMAXD(q1, v0, v1); // propagate NAN
|
||||
FCMEQD(q1, q1, q1); // 0 if NAN, 1 if not NAN
|
||||
FMULD(q2, v1, v2); // the high part of the vector is erased...
|
||||
FCMEQD(q0, q2, q2); // 0 => out is NAN
|
||||
VBIC(q0, q1, q0); // forget it in any input was a NAN already
|
||||
SHL_64(q0, q0, 63); // only keep the sign bit
|
||||
VORR(q2, q2, q0); // NAN -> -NAN
|
||||
} else {
|
||||
FMULD(q2, v1, v2); // the high part of the vector is erased...
|
||||
}
|
||||
if(v0!=v2) {
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeD(v0, 0, d1, 0);
|
||||
YMM0(gd)
|
||||
VMOVeD(v0, 0, q2, 0);
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x5A:
|
||||
INST_NAME("VCVTSD2SS Gx, Vx, Ex");
|
||||
@@ -240,7 +266,13 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSD(v1, 0, 0);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
FCVT_S_D(d1, v1);
|
||||
if(BOX64ENV(dynarec_fastround)==2) {
|
||||
FCVT_S_D(d1, v1);
|
||||
} else {
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x3);
|
||||
FCVT_S_D(d1, v1);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
}
|
||||
if(v0!=v2) {
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
@@ -251,14 +283,27 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
case 0x5C:
|
||||
INST_NAME("VSUBSD Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
q2 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSD(v1, 0, 0);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
FSUBD(d1, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
FMAXD(q1, v0, v1); // propagate NAN
|
||||
FCMEQD(q1, q1, q1); // 0 if NAN, 1 if not NAN
|
||||
FSUBD(q2, v2, v1); // the high part of the vector is erased...
|
||||
FCMEQD(q0, q2, q2); // 0 => out is NAN
|
||||
VBIC(q0, q1, q0); // forget it in any input was a NAN already
|
||||
SHL_64(q0, q0, 63); // only keep the sign bit
|
||||
VORR(q2, q2, q0); // NAN -> -NAN
|
||||
} else {
|
||||
FSUBD(q2, v2, v1); // the high part of the vector is erased...
|
||||
}
|
||||
if(v0!=v2) {
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeD(v0, 0, d1, 0);
|
||||
VMOVeD(v0, 0, q2, 0);
|
||||
YMM0(gd)
|
||||
break;
|
||||
case 0x5D:
|
||||
@@ -279,27 +324,27 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
case 0x5E:
|
||||
INST_NAME("VDIVSD Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
q2 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSD(v1, 0, 0);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
FMAXD(q0, v2, v1); // propagate NAN
|
||||
FCMEQD(q0, q0, q0); // 0 if NAN, 1 if not NAN
|
||||
}
|
||||
FDIVD(d1, v2, v1);
|
||||
if(!box64_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
|
||||
VORR(d1, d1, q1); // NAN -> -NAN
|
||||
FMAXD(q1, v0, v1); // propagate NAN
|
||||
FCMEQD(q1, q1, q1); // 0 if NAN, 1 if not NAN
|
||||
FDIVD(q2, v2, v1); // the high part of the vector is erased...
|
||||
FCMEQD(q0, q2, q2); // 0 => out is NAN
|
||||
VBIC(q0, q1, q0); // forget it in any input was a NAN already
|
||||
SHL_64(q0, q0, 63); // only keep the sign bit
|
||||
VORR(q2, q2, q0); // NAN -> -NAN
|
||||
} else {
|
||||
FDIVD(q2, v2, v1); // the high part of the vector is erased...
|
||||
}
|
||||
if(v0!=v2) {
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeD(v0, 0, d1, 0);
|
||||
VMOVeD(v0, 0, q2, 0);
|
||||
YMM0(gd)
|
||||
break;
|
||||
case 0x5F:
|
||||
@@ -322,7 +367,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
nextop = F8;
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETEX(v1, 0, 1); GETGX(v0, 1); u8 = F8; } else { GETGY(v0, 1, MODREG?((nextop&7)+(rex.b<<3)):-1, -1, -1); GETEY(v1); }
|
||||
if(!l) { GETEX_Y(v1, 0, 1); GETGX(v0, 1); u8 = F8; } else { GETGY(v0, 1, MODREG?((nextop&7)+(rex.b<<3)):-1, -1, -1); GETEY(v1); }
|
||||
if(u8==0b00000000 || u8==0b01010101 || u8==0b10101010 || u8==0b11111111) {
|
||||
if(v0==v1) {
|
||||
VMOVQ(d0, v1);
|
||||
@@ -360,6 +405,29 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x7D:
|
||||
INST_NAME("VHSUBPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
if(MODREG || (v1==v2)) {
|
||||
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);
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0xC2:
|
||||
INST_NAME("CMPSD Gx, Ex, Ib");
|
||||
@@ -389,13 +457,16 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
static float addsubps[4] = {-1.f, 1.f, -1.f, 1.f};
|
||||
MAYUSE(addsubps);
|
||||
TABLE64(x2, (uintptr_t)&addsubps);
|
||||
MOV64x(x2, (uintptr_t)&addsubps);
|
||||
VLDR128_U12(q0, x2, 0);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); if(v0==v1) q1 = fpu_get_scratch(dyn, ninst); } else { GETGY_empty_VYEY(v0, v2, v1); }
|
||||
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
|
||||
if(v0==v1) {
|
||||
VFMULQS(q1, v1, q0);
|
||||
VFADDQS(v0, v2, q1);
|
||||
//TODO: find a better way
|
||||
if(!l) q1 = fpu_get_scratch(dyn, ninst);
|
||||
VMOVQ(q1, v2);
|
||||
VFMLAQS(q1, v1, q0);
|
||||
VMOVQ(v0, q1);
|
||||
} else {
|
||||
if(v0!=v2) VMOVQ(v0, v2);
|
||||
VFMLAQS(v0, v1, q0);
|
||||
@@ -412,12 +483,12 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
if(!l) {
|
||||
GETEX_Y(v1, 0, 0);
|
||||
GETGX_empty(v0);
|
||||
if(!box64_dynarec_fastround || vex.l)
|
||||
if(!BOX64ENV(dynarec_fastround) || vex.l)
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
} else {
|
||||
GETEY(v1);
|
||||
}
|
||||
if(box64_dynarec_fastround) {
|
||||
if(BOX64ENV(dynarec_fastround)) {
|
||||
VFRINTIDQ(l?d0:v0, v1);
|
||||
VFCVTNSQD(l?d0:v0, l?d0:v0); // convert double -> int64
|
||||
if(!l)
|
||||
|
||||
@@ -60,7 +60,36 @@ uintptr_t dynarec64_AVX_F2_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
rex_t rex = vex.rex;
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0xF5:
|
||||
INST_NAME("PDEP Gd, Ed, Vd");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED(0);
|
||||
GETVD;
|
||||
if(gd==ed || gd==vd) {
|
||||
gb1 = gd;
|
||||
gd = x4;
|
||||
} else {
|
||||
gb1 = 0;
|
||||
}
|
||||
// x3 = mask of mask, loop while not 0
|
||||
MOV32w(gd, 0);
|
||||
MOV64x(x2, 1);
|
||||
MOV64x(x3, 1);
|
||||
MARK;
|
||||
TSTxw_REG(ed, x3);
|
||||
B_MARK2(cEQ);
|
||||
TSTxw_REG(vd, x2);
|
||||
B_MARK3(cEQ);
|
||||
ORRxw_REG(gd, gd, x3);
|
||||
MARK3;
|
||||
LSLxw_IMM(x2, x2, 1);
|
||||
MARK2;
|
||||
LSLxw_IMM(x3, x3, 1);
|
||||
CBNZxw_MARK(x3);
|
||||
if(gb1)
|
||||
MOVxw_REG(gb1, gd);
|
||||
break;
|
||||
case 0xF6:
|
||||
INST_NAME("MULX Gd, Vd, Ed (,RDX)");
|
||||
nextop = F8;
|
||||
@@ -69,13 +98,19 @@ uintptr_t dynarec64_AVX_F2_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
GETVD;
|
||||
if(rex.w) {
|
||||
// 64bits mul
|
||||
UMULH(x3, xRDX, ed);
|
||||
MULx(vd, xRDX, ed);
|
||||
MOVx_REG(gd, x3);
|
||||
if((gd==xRDX) || (gd==ed) || (gd==vd))
|
||||
gb1 = x3;
|
||||
else
|
||||
gb1 = gd;
|
||||
UMULH(gb1, xRDX, ed);
|
||||
if(gd!=vd) {MULx(vd, xRDX, ed);}
|
||||
if(gb1==x3) {
|
||||
MOVx_REG(gd, gb1);
|
||||
}
|
||||
} else {
|
||||
// 32bits mul
|
||||
UMULL(x3, xRDX, ed);
|
||||
MOVw_REG(vd, x3);
|
||||
if(gd!=vd) {MOVw_REG(vd, x3);}
|
||||
LSRx(gd, x3, 32);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -140,13 +140,13 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEXSS(d0, 0, 0);
|
||||
if(!box64_dynarec_fastround) {
|
||||
if(!BOX64ENV(dynarec_fastround)) {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
}
|
||||
FCVTZSxwS(gd, d0);
|
||||
if(!box64_dynarec_fastround) {
|
||||
if(!BOX64ENV(dynarec_fastround)) {
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_NEXT(x5, FPSR_IOC);
|
||||
if(rex.w) {
|
||||
@@ -161,7 +161,7 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEXSS(q0, 0, 0);
|
||||
if(!box64_dynarec_fastround) {
|
||||
if(!BOX64ENV(dynarec_fastround)) {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
@@ -171,7 +171,7 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
FRINTIS(d1, q0);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
FCVTZSxwS(gd, d1);
|
||||
if(!box64_dynarec_fastround) {
|
||||
if(!BOX64ENV(dynarec_fastround)) {
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_NEXT(x5, FPSR_IOC);
|
||||
if(rex.w) {
|
||||
@@ -234,35 +234,53 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
case 0x58:
|
||||
INST_NAME("VADDSS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
q2 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSS(v1, 0, 0);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
FMAXS(q1, v0, v1); // propagate NAN
|
||||
FCMEQS(q1, q1, q1); // 0 if NAN, 1 if not NAN
|
||||
FADDS(q2, v1, v2); // the high part of the vector is erased...
|
||||
FCMEQS(q0, q2, q2); // 0 => out is NAN
|
||||
VBIC(q0, q1, q0); // forget it in any input was a NAN already
|
||||
VSHL_32(q0, q0, 31); // only keep the sign bit
|
||||
VORR(q2, q2, q0); // NAN -> -NAN
|
||||
} else {
|
||||
FADDS(q2, v1, v2); // the high part of the vector is erased...
|
||||
}
|
||||
if(v0!=v2) {
|
||||
if(v0==v1) {
|
||||
VMOV(d1, v1);
|
||||
v1 = d1;
|
||||
}
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
FADDS(d1, v0, v1);
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
VMOVeS(v0, 0, q2, 0);
|
||||
YMM0(gd)
|
||||
break;
|
||||
case 0x59:
|
||||
INST_NAME("VMULSS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
q2 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSS(v1, 0, 0);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
FMAXS(q1, v0, v1); // propagate NAN
|
||||
FCMEQS(q1, q1, q1); // 0 if NAN, 1 if not NAN
|
||||
FMULS(q2, v1, v2); // the high part of the vector is erased...
|
||||
FCMEQS(q0, q2, q2); // 0 => out is NAN
|
||||
VBIC(q0, q1, q0); // forget it in any input was a NAN already
|
||||
VSHL_32(q0, q0, 31); // only keep the sign bit
|
||||
VORR(q2, q2, q0); // NAN -> -NAN
|
||||
} else {
|
||||
FMULS(q2, v1, v2); // the high part of the vector is erased...
|
||||
}
|
||||
if(v0!=v2) {
|
||||
if(v0==v1) {
|
||||
VMOV(d1, v1);
|
||||
v1 = d1;
|
||||
}
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
FMULS(d1, v0, v1);
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
VMOVeS(v0, 0, q2, 0);
|
||||
YMM0(gd)
|
||||
break;
|
||||
case 0x5A:
|
||||
@@ -286,13 +304,13 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
INST_NAME("VCVTTPS2DQ Gx, Ex");
|
||||
nextop = F8;
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
if(!box64_dynarec_fastround) {
|
||||
if(!BOX64ENV(dynarec_fastround)) {
|
||||
MRS_fpsr(x5);
|
||||
ORRw_mask(x4, xZR, 1, 0); //0x80000000
|
||||
}
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_EX(v0, v1, 0); } else { GETGY_empty_EY(v0, v1); }
|
||||
if(box64_dynarec_fastround) {
|
||||
if(BOX64ENV(dynarec_fastround)) {
|
||||
VFCVTZSQS(v0, v1);
|
||||
} else {
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
@@ -314,14 +332,27 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
case 0x5C:
|
||||
INST_NAME("VSUBSS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
q2 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSS(v1, 0, 0);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
FSUBS(d1, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
FMAXS(q1, v0, v1); // propagate NAN
|
||||
FCMEQS(q1, q1, q1); // 0 if NAN, 1 if not NAN
|
||||
FSUBS(q2, v2, v1); // the high part of the vector is erased...
|
||||
FCMEQS(q0, q2, q2); // 0 => out is NAN
|
||||
VBIC(q0, q1, q0); // forget it in any input was a NAN already
|
||||
VSHL_32(q0, q0, 31); // only keep the sign bit
|
||||
VORR(q2, q2, q0); // NAN -> -NAN
|
||||
} else {
|
||||
FSUBS(q2, v2, v1); // the high part of the vector is erased...
|
||||
}
|
||||
if(v0!=v2) {
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
VMOVeS(v0, 0, q2, 0);
|
||||
YMM0(gd)
|
||||
break;
|
||||
case 0x5D:
|
||||
@@ -341,14 +372,27 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
case 0x5E:
|
||||
INST_NAME("VDIVSS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
q2 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSS(v1, 0, 0);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
FDIVS(d1, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
FMAXS(q1, v0, v1); // propagate NAN
|
||||
FCMEQS(q1, q1, q1); // 0 if NAN, 1 if not NAN
|
||||
FDIVS(q2, v2, v1); // the high part of the vector is erased...
|
||||
FCMEQS(q0, q2, q2); // 0 => out is NAN
|
||||
VBIC(q0, q1, q0); // forget it in any input was a NAN already
|
||||
VSHL_32(q0, q0, 31); // only keep the sign bit
|
||||
VORR(q2, q2, q0); // NAN -> -NAN
|
||||
} else {
|
||||
FDIVS(q2, v2, v1); // the high part of the vector is erased...
|
||||
}
|
||||
if(v0!=v2) {
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
VMOVeS(v0, 0, q2, 0);
|
||||
YMM0(gd)
|
||||
break;
|
||||
case 0x5F:
|
||||
@@ -395,7 +439,7 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
nextop = F8;
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETEX(v1, 0, 1); GETGX(v0, 1); u8 = F8; } else { GETGY(v0, 1, MODREG?((nextop&7)+(rex.b<<3)):-1, -1, -1); GETEY(v1); }
|
||||
if(!l) { GETEX_Y(v1, 0, 1); GETGX(v0, 1); u8 = F8; } else { GETGY(v0, 1, MODREG?((nextop&7)+(rex.b<<3)):-1, -1, -1); GETEY(v1); }
|
||||
if(u8==0b00000000 || u8==0b01010101 || u8==0b10101010 || u8==0b11111111) {
|
||||
VDUP_16(d0, v1, 4+(u8&3));
|
||||
} else {
|
||||
@@ -447,11 +491,30 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
VMOVQ(v1, v0);
|
||||
} // no ymm raz here it seems
|
||||
} 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);
|
||||
IF_UNALIGNED(ip) {
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
SMWRITE2();
|
||||
}
|
||||
|
||||
@@ -61,6 +61,35 @@ uintptr_t dynarec64_AVX_F3_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0xF5:
|
||||
INST_NAME("PEXT Gd, Ed, Vd");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED(0);
|
||||
GETVD;
|
||||
if(gd==ed || gd==vd) {
|
||||
gb1 = gd;
|
||||
gd = x4;
|
||||
} else {
|
||||
gb1 = 0;
|
||||
}
|
||||
// x3 = mask of mask, loop while not 0
|
||||
MOV32w(gd, 0);
|
||||
MOV64x(x3, 1LL<<(rex.w?63:31));
|
||||
MARK;
|
||||
TSTxw_REG(ed, x3);
|
||||
B_MARK2(cEQ); // mask not set
|
||||
TSTxw_REG(vd, x3);
|
||||
CSINCxw(gd, gd, gd, cEQ); // return gd if TRUE, else gd+1
|
||||
RORxw(gd, gd, 1);
|
||||
MARK2;
|
||||
LSRxw_IMM(x3, x3, 1);
|
||||
CBNZxw_MARK(x3);
|
||||
RBITxw(gd, gd);
|
||||
if(gb1)
|
||||
MOVxw_REG(gb1, gd);
|
||||
break;
|
||||
|
||||
case 0xF7:
|
||||
INST_NAME("SARX Gd, Ed, Vd");
|
||||
nextop = F8;
|
||||
|
||||
@@ -29,6 +29,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
|
||||
uint8_t nextop = F8;
|
||||
uint8_t ed;
|
||||
uint8_t u8;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
int v1, v2;
|
||||
@@ -51,11 +52,15 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FADD ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
FADDS(v1, v1, v2);
|
||||
} else {
|
||||
FADDD(v1, v1, v2);
|
||||
}
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
@@ -68,11 +73,15 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FMUL ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
FMULS(v1, v1, v2);
|
||||
} else {
|
||||
FMULD(v1, v1, v2);
|
||||
}
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
@@ -90,7 +99,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
FCMPD(v1, v2);
|
||||
}
|
||||
FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0));
|
||||
FCOM(x1, x2, x3);
|
||||
break;
|
||||
case 0xD8:
|
||||
case 0xD9:
|
||||
@@ -108,7 +117,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
FCMPD(v1, v2);
|
||||
}
|
||||
FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0));
|
||||
FCOM(x1, x2, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xE0:
|
||||
@@ -122,11 +131,15 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FSUB ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
FSUBS(v1, v1, v2);
|
||||
} else {
|
||||
FSUBD(v1, v1, v2);
|
||||
}
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 0xE8:
|
||||
case 0xE9:
|
||||
@@ -139,11 +152,15 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FSUBR ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
FSUBS(v1, v2, v1);
|
||||
} else {
|
||||
FSUBD(v1, v2, v1);
|
||||
}
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
@@ -156,11 +173,15 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FDIV ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
FDIVS(v1, v1, v2);
|
||||
} else {
|
||||
FDIVD(v1, v1, v2);
|
||||
}
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 0xF8:
|
||||
case 0xF9:
|
||||
@@ -173,11 +194,15 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FDIVR ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
FDIVS(v1, v2, v1);
|
||||
} else {
|
||||
FDIVD(v1, v2, v1);
|
||||
}
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
@@ -190,12 +215,16 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
FADDS(v1, v1, s0);
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
FADDD(v1, v1, s0);
|
||||
}
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FMUL ST0, float[ED]");
|
||||
@@ -203,12 +232,16 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
FMULS(v1, v1, s0);
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
FMULD(v1, v1, s0);
|
||||
}
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FCOM ST0, float[ED]");
|
||||
@@ -222,7 +255,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
FCVT_D_S(s0, s0);
|
||||
FCMPD(v1, s0);
|
||||
}
|
||||
FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0));
|
||||
FCOM(x1, x2, x3);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FCOMP ST0, float[ED]");
|
||||
@@ -236,7 +269,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
FCVT_D_S(s0, s0);
|
||||
FCMPD(v1, s0);
|
||||
}
|
||||
FCOM(x1, x2, x3, x4, v1, s0, ST_IS_F(0));
|
||||
FCOM(x1, x2, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
@@ -245,12 +278,16 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
FSUBS(v1, v1, s0);
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
FSUBD(v1, v1, s0);
|
||||
}
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FSUBR ST0, float[ED]");
|
||||
@@ -258,12 +295,16 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
FSUBS(v1, s0, v1);
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
FSUBD(v1, s0, v1);
|
||||
}
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FDIV ST0, float[ED]");
|
||||
@@ -271,12 +312,16 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
FDIVS(v1, v1, s0);
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
FDIVD(v1, v1, s0);
|
||||
}
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FDIVR ST0, float[ED]");
|
||||
@@ -284,12 +329,16 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
FDIVS(v1, s0, v1);
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
FDIVD(v1, s0, v1);
|
||||
}
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
|
||||
@@ -128,7 +128,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
FCMPD_0(v1);
|
||||
}
|
||||
FCOM(x1, x2, x3, x4, 0, 0, ST_IS_F(0)); // same flags...
|
||||
FCOM(x1, x2, x3); // same flags...
|
||||
break;
|
||||
case 0xE5:
|
||||
INST_NAME("FXAM");
|
||||
@@ -270,7 +270,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
|
||||
case 0xF0:
|
||||
INST_NAME("F2XM1");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (F2XM1)\n");
|
||||
i1 = x87_stackcount(dyn, ninst, x1);
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
CALL(native_f2xm1, -1);
|
||||
@@ -278,7 +278,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0xF1:
|
||||
INST_NAME("FYL2X");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (FYL2X)\n");
|
||||
i1 = x87_stackcount(dyn, ninst, x1);
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
@@ -288,11 +288,15 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0xF2:
|
||||
INST_NAME("FPTAN");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (FPTAN)\n");
|
||||
i1 = x87_stackcount(dyn, ninst, x1);
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
CALL(native_ftan, -1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
CALL_(native_ftan, -1, BOX64ENV(dynarec_fastround) ? 0 : u8);
|
||||
x87_unstackcount(dyn, ninst, x1, i1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
if(PK(0)==0xdd && PK(1)==0xd8) {
|
||||
MESSAGE(LOG_DUMP, "Optimized next DD D8 fstp st0, st0, not emitting 1\n");
|
||||
u8 = F8;
|
||||
@@ -308,17 +312,21 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0xF3:
|
||||
INST_NAME("FPATAN");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (FPATAN)\n");
|
||||
i1 = x87_stackcount(dyn, ninst, x1);
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(native_fpatan, -1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
CALL_(native_fpatan, -1, BOX64ENV(dynarec_fastround) ? 0 : u8);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
x87_unstackcount(dyn, ninst, x1, i1);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xF4:
|
||||
INST_NAME("FXTRACT");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (FXTRACT)\n");
|
||||
X87_PUSH_EMPTY_OR_FAIL(dyn, ninst, 0);
|
||||
i1 = x87_stackcount(dyn, ninst, x1);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
@@ -327,8 +335,8 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0xF5:
|
||||
INST_NAME("FPREM1");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
#if 0
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
i1 = x87_stackcount(dyn, ninst, x1);
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
@@ -407,7 +415,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0xF9:
|
||||
INST_NAME("FYL2XP1");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (FYL2XP1)\n");
|
||||
i1 = x87_stackcount(dyn, ninst, x1);
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
@@ -418,19 +426,27 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0xFA:
|
||||
INST_NAME("FSQRT");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
FSQRTS(v1, v1);
|
||||
} else {
|
||||
FSQRTD(v1, v1);
|
||||
}
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 0xFB:
|
||||
INST_NAME("FSINCOS");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (FSINCOS)\n");
|
||||
X87_PUSH_EMPTY_OR_FAIL(dyn, ninst, 0);
|
||||
i1 = x87_stackcount(dyn, ninst, x1);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(native_fsincos, -1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
CALL_(native_fsincos, -1, BOX64ENV(dynarec_fastround) ? 0 : u8);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
x87_unstackcount(dyn, ninst, x1, i1);
|
||||
break;
|
||||
case 0xFC:
|
||||
@@ -453,27 +469,39 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0xFD:
|
||||
INST_NAME("FSCALE");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (FSCALE)\n");
|
||||
i1 = x87_stackcount(dyn, ninst, x1);
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(native_fscale, -1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
CALL_(native_fscale, -1, BOX64ENV(dynarec_fastround) ? 0 : u8);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
x87_unstackcount(dyn, ninst, x1, i1);
|
||||
break;
|
||||
case 0xFE:
|
||||
INST_NAME("FSIN");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (FSIN)\n");
|
||||
i1 = x87_stackcount(dyn, ninst, x1);
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
CALL(native_fsin, -1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
CALL_(native_fsin, -1, BOX64ENV(dynarec_fastround) ? 0 : u8);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
x87_unstackcount(dyn, ninst, x1, i1);
|
||||
break;
|
||||
case 0xFF:
|
||||
INST_NAME("FCOS");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (FCOS)\n");
|
||||
i1 = x87_stackcount(dyn, ninst, x1);
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
CALL(native_fcos, -1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
CALL_(native_fcos, -1, BOX64ENV(dynarec_fastround) ? 0 : u8);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
x87_unstackcount(dyn, ninst, x1, i1);
|
||||
break;
|
||||
default:
|
||||
@@ -483,7 +511,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, box64_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, BOX64ENV(dynarec_x87double)?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)) {
|
||||
@@ -497,7 +525,11 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
s0 = v1;
|
||||
else {
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
FCVT_S_D(s0, v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
}
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VST32(s0, ed, fixedaddress);
|
||||
@@ -507,14 +539,18 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_F);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
if(!ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
FCVT_S_D(v1, v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
}
|
||||
VST32(v1, ed, fixedaddress);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FLDENV Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (FLDENV)\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3); // maybe only x87, not SSE?
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {
|
||||
@@ -530,7 +566,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FNSTENV Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (FNSTENV)\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3); // maybe only x87, not SSE?
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {
|
||||
|
||||
@@ -29,6 +29,7 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
int64_t j64;
|
||||
uint8_t ed;
|
||||
uint8_t wback;
|
||||
uint8_t u8;
|
||||
int v1, v2;
|
||||
int d0;
|
||||
int s0;
|
||||
@@ -130,7 +131,7 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
FCMPD(v1, v2);
|
||||
}
|
||||
FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0));
|
||||
FCOM(x1, x2, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
@@ -148,7 +149,11 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
FADDD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FIMUL ST0, Ed");
|
||||
@@ -158,7 +163,11 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
FMULD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FICOM ST0, Ed");
|
||||
@@ -169,7 +178,7 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
FCMPD(v1, v2);
|
||||
FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0));
|
||||
FCOM(x1, x2, x3);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FICOMP ST0, Ed");
|
||||
@@ -180,7 +189,7 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
FCMPD(v1, v2);
|
||||
FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0));
|
||||
FCOM(x1, x2, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
@@ -191,7 +200,11 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
FSUBD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FISUBR ST0, Ed");
|
||||
@@ -201,7 +214,11 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
FSUBD(v1, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FIDIV ST0, Ed");
|
||||
@@ -211,7 +228,11 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
FDIVD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FIDIVR ST0, Ed");
|
||||
@@ -221,7 +242,11 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
FDIVD(v1, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
}
|
||||
return addr;
|
||||
|
||||
@@ -127,14 +127,13 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0xE2:
|
||||
INST_NAME("FNCLEX");
|
||||
LDRH_U12(x2, xEmu, offsetof(x64emu_t, sw));
|
||||
MOV32w(x1, 0);
|
||||
BFIw(x2, x1, 0, 8); // IE .. PE, SF, ES
|
||||
BFIw(x2, x1, 15, 1); // B
|
||||
BFCw(x2, 0, 8); // IE .. PE, SF, ES
|
||||
BFCw(x2, 15, 1); // B
|
||||
STRH_U12(x2, xEmu, offsetof(x64emu_t, sw));
|
||||
break;
|
||||
case 0xE3:
|
||||
INST_NAME("FNINIT");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (FNINIT)\n");
|
||||
x87_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
CALL(reset_fpu, -1);
|
||||
break;
|
||||
@@ -155,7 +154,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
FCMPD(v1, v2);
|
||||
}
|
||||
FCOMI(x1, x2, x4, v1, v2, ST_IS_F(0));
|
||||
FCOMI(x1, x2);
|
||||
break;
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
@@ -174,7 +173,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
FCMPD(v1, v2);
|
||||
}
|
||||
FCOMI(x1, x2, x4, v1, v2, ST_IS_F(0));
|
||||
FCOMI(x1, x2);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -202,13 +201,17 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
BFCw(x5, FPSR_QC, 1); // reset QC bit
|
||||
MSR_fpsr(x5);
|
||||
FRINTZD(s0, v1);
|
||||
VFCVTZSd(s0, s0);
|
||||
SQXTN_S_D(s0, s0);
|
||||
VST32(s0, wback, fixedaddress);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_MARK3(x5, FPSR_IOC);
|
||||
TBNZ_MARK2(x5, FPSR_IOC);
|
||||
TBNZ_MARK2(x5, FPSR_QC);
|
||||
B_MARK3_nocond;
|
||||
MARK2;
|
||||
MOV32w(x5, 0x80000000);
|
||||
STW(x5, wback, fixedaddress);
|
||||
MARK3;
|
||||
@@ -228,13 +231,17 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
BFCw(x5, FPSR_QC, 1); // reset QC bit
|
||||
MSR_fpsr(x5);
|
||||
FRINTXD(s0, v1);
|
||||
VFCVTZSd(s0, s0);
|
||||
SQXTN_S_D(s0, s0);
|
||||
VST32(s0, wback, fixedaddress);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_MARK3(x5, FPSR_IOC);
|
||||
TBNZ_MARK2(x5, FPSR_IOC);
|
||||
TBNZ_MARK2(x5, FPSR_QC);
|
||||
B_MARK3_nocond;
|
||||
MARK2;
|
||||
MOV32w(x5, 0x80000000);
|
||||
STW(x5, wback, fixedaddress);
|
||||
MARK3;
|
||||
@@ -254,13 +261,17 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
BFCw(x5, FPSR_QC, 1); // reset QC bit
|
||||
MSR_fpsr(x5);
|
||||
FRINTXD(s0, v1);
|
||||
VFCVTZSd(s0, s0);
|
||||
SQXTN_S_D(s0, s0);
|
||||
VST32(s0, wback, fixedaddress);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_MARK3(x5, FPSR_IOC);
|
||||
TBNZ_MARK2(x5, FPSR_IOC);
|
||||
TBNZ_MARK2(x5, FPSR_QC);
|
||||
B_MARK3_nocond;
|
||||
MARK2;
|
||||
MOV32w(x5, 0x80000000);
|
||||
STW(x5, wback, fixedaddress);
|
||||
MARK3;
|
||||
@@ -289,7 +300,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
STRx_U12(x5, ed, 0);
|
||||
STRH_U12(x6, ed, 8);
|
||||
} else {
|
||||
if(box64_x87_no80bits) {
|
||||
if(BOX64ENV(x87_no80bits)) {
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
VLDR64_U12(v1, ed, fixedaddress);
|
||||
} else {
|
||||
@@ -298,77 +309,73 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
X87_PUSH_EMPTY_OR_FAIL(dyn, ninst, 0);
|
||||
// sync top
|
||||
s0 = x87_stackcount(dyn, ninst, x3);
|
||||
x87_reflectcount(dyn, ninst, x3, x4);
|
||||
CALL(native_fld, -1);
|
||||
// go back with the top & stack counter
|
||||
x87_unstackcount(dyn, ninst, x3, s0);
|
||||
x87_unreflectcount(dyn, ninst, x3, x4);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FSTP tbyte");
|
||||
if(box64_x87_no80bits) {
|
||||
if(BOX64ENV(x87_no80bits)) {
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VST64(v1, wback, fixedaddress);
|
||||
} else {
|
||||
#if 0
|
||||
x87_forget(dyn, ninst, x1, x3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {
|
||||
MOVx_REG(x1, ed);
|
||||
if(!BOX64ENV(dynarec_fastround)) {
|
||||
x87_forget(dyn, ninst, x1, x3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
x87_reflectcount(dyn, ninst, x3, x4);
|
||||
CALL(native_fstp, -1);
|
||||
x87_unreflectcount(dyn, ninst, x3, x4);
|
||||
} else {
|
||||
// Painfully long, straight conversion from the C code, shoud be optimized
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
FMOVxD(x1, v1);
|
||||
// do special value first
|
||||
TSTx_mask(x1, 1, 0b00000, 0b111110); //0x7fffffffffffffffL
|
||||
B_MARK(cNE);
|
||||
// Zero
|
||||
LSRx(x3, x1, 63-15); //x3 = sign+exp
|
||||
MOVZw(x5, 0); // x5 = mantisse
|
||||
B_MARK3_nocond;
|
||||
MARK;
|
||||
// get sign, in main ouput x5 for sign+exp
|
||||
ANDx_mask(x5, x1, 1, 1, 0); //0x8000000000000000
|
||||
LSRx(x5, x5, 63-15); // x5 = sign
|
||||
// get exp
|
||||
LSRx(x3, x1, 52); // x3 = exp11
|
||||
ANDw_mask(x3, x3, 0, 0b1010); //0x7ff
|
||||
ANDSx_mask(x1, x1, 1, 0, 0b110011); //0x000fffffffffffffL
|
||||
LSLx_IMM(x1, x1, 11); // mantice
|
||||
CMPSw_U12(x3, 0x7ff);
|
||||
B_MARK2(cNE);
|
||||
// NaN and Infinite
|
||||
ORRw_mask(x3, x5, 0, 0b1110); //x3 = sign | 0x7fff
|
||||
ORRx_mask(x5, x1, 1, 1, 0); //0x8000000000000000
|
||||
B_MARK3_nocond;
|
||||
MARK2;
|
||||
// regular / denormals
|
||||
MOVZw(x4, 16383-1023); //BIAS80 - BIAS64
|
||||
CBZw(x3, 4+4*4); // exp11 == 0?
|
||||
// normals
|
||||
ADDw_REG(x3, x3, x4); // x3 = exp16
|
||||
ORRw_REG(x3, x3, x5); // x3 = sign | exp
|
||||
ORRx_mask(x5, x1, 1, 1, 0); //0x8000000000000000 x5 = mantisse
|
||||
B_MARK3_nocond;
|
||||
// denormals
|
||||
CLZx(x6, x1);
|
||||
ADDw_U12(x6, x6, 1); // "one"
|
||||
SUBw_REG(x3, x4, x6); // x3 = exp16
|
||||
ORRw_REG(x3, x3, x5); // x3 = sign | exp16
|
||||
LSLx_REG(x5, x1, x6); // x5 = mantisse
|
||||
MARK3;
|
||||
STRx_U12(x5, wback, 0);
|
||||
STRH_U12(x3, wback, 8);
|
||||
}
|
||||
CALL(native_fstp, -1);
|
||||
#else
|
||||
// Painfully long, straight conversion from the C code, shoud be optimized
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
FMOVxD(x1, v1);
|
||||
// do special value first
|
||||
TSTx_mask(x1, 1, 0b00000, 0b111110); //0x7fffffffffffffffL
|
||||
B_MARK(cNE);
|
||||
// Zero
|
||||
LSRx(x3, x1, 63-15); //x3 = sign+exp
|
||||
MOVZw(x5, 0); // x5 = mantisse
|
||||
B_MARK3_nocond;
|
||||
MARK;
|
||||
// get sign, in main ouput x5 for sign+exp
|
||||
ANDx_mask(x5, x1, 1, 1, 0); //0x8000000000000000
|
||||
LSRx(x5, x5, 63-15); // x5 = sign
|
||||
// get exp
|
||||
LSRx(x3, x1, 52); // x3 = exp11
|
||||
ANDw_mask(x3, x3, 0, 0b1010); //0x7ff
|
||||
MOV32w(x4, 0x7ff);
|
||||
CMPSw_REG(x3, x4);
|
||||
B_MARK2(cNE);
|
||||
// NaN and Infinite
|
||||
ORRw_mask(x3, x5, 0, 0b1110); //x3 = sign | 0x7fff
|
||||
TSTx_mask(x1, 1, 0, 0b110011); //0x000fffffffffffffL
|
||||
ORRx_mask(x5, xZR, 1, 1, 0); //0x8000000000000000
|
||||
ORRx_mask(x4, xZR, 1, 0b10, 0b01); //0xc000000000000000
|
||||
CSELx(x5, x5, x4, cEQ); // x5 = mantisse
|
||||
B_MARK3_nocond;
|
||||
MARK2;
|
||||
// regular / denormals
|
||||
ANDx_mask(x1, x1, 1, 0, 0b110011); //0x000fffffffffffffL
|
||||
LSLx_IMM(x1, x1, 11); //x1 = mantisse missing "1"
|
||||
MOVZw(x4, 16383-1023); //BIAS80 - BIAS64
|
||||
CBZw(x3, 4+3*4); // exp11 == 0?
|
||||
// normals
|
||||
ADDw_REG(x3, x3, x4); // x3 = exp16
|
||||
ORRw_REG(x3, x3, x5); // x3 = sign | exp
|
||||
ORRx_mask(x5, x1, 1, 1, 0); //0x8000000000000000 x5 = mantisse
|
||||
B_MARK3_nocond;
|
||||
// denormals
|
||||
CLZx(x6, x1);
|
||||
ADDw_U12(x6, x6, 1); // "one"
|
||||
SUBw_REG(x3, x4, x6); // x3 = exp16
|
||||
ORRw_REG(x3, x3, x5); // x3 = sign | exp16
|
||||
LSLx_REG(x5, x1, x6); // x5 = mantisse
|
||||
MARK3;
|
||||
STRx_U12(x5, wback, 0);
|
||||
STRH_U12(x3, wback, 8);
|
||||
#endif
|
||||
}
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
@@ -29,6 +29,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
|
||||
uint8_t nextop = F8;
|
||||
uint8_t wback;
|
||||
uint8_t u8;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
int v1, v2;
|
||||
@@ -49,11 +50,15 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FADD STx, ST0");
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
FADDS(v1, v1, v2);
|
||||
} else {
|
||||
FADDD(v1, v1, v2);
|
||||
}
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
@@ -66,11 +71,15 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FMUL STx, ST0");
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
FMULS(v1, v1, v2);
|
||||
} else {
|
||||
FMULD(v1, v1, v2);
|
||||
}
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
@@ -88,7 +97,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
FCMPD(v1, v2);
|
||||
}
|
||||
FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0));
|
||||
FCOM(x1, x2, x3);
|
||||
break;
|
||||
case 0xD8:
|
||||
case 0xD9:
|
||||
@@ -106,7 +115,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
FCMPD(v1, v2);
|
||||
}
|
||||
FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0));
|
||||
FCOM(x1, x2, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xE0:
|
||||
@@ -120,11 +129,15 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FSUBR STx, ST0");
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
FSUBS(v1, v2, v1);
|
||||
} else {
|
||||
FSUBD(v1, v2, v1);
|
||||
}
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 0xE8:
|
||||
case 0xE9:
|
||||
@@ -137,11 +150,15 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FSUB STx, ST0");
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
FSUBS(v1, v1, v2);
|
||||
} else {
|
||||
FSUBD(v1, v1, v2);
|
||||
}
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
@@ -154,11 +171,15 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FDIVR STx, ST0");
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
FDIVS(v1, v2, v1);
|
||||
} else {
|
||||
FDIVD(v1, v2, v1);
|
||||
}
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 0xF8:
|
||||
case 0xF9:
|
||||
@@ -171,11 +192,15 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FDIV STx, ST0");
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
FDIVS(v1, v1, v2);
|
||||
} else {
|
||||
FDIVD(v1, v1, v2);
|
||||
}
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
@@ -188,7 +213,11 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v2, wback, fixedaddress);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
FADDD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FMUL ST0, double[ED]");
|
||||
@@ -196,7 +225,11 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v2, wback, fixedaddress);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
FMULD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FCOM ST0, double[ED]");
|
||||
@@ -205,7 +238,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v2, wback, fixedaddress);
|
||||
FCMPD(v1, v2);
|
||||
FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0));
|
||||
FCOM(x1, x2, x3);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FCOMP ST0, double[ED]");
|
||||
@@ -214,7 +247,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v2, wback, fixedaddress);
|
||||
FCMPD(v1, v2);
|
||||
FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0));
|
||||
FCOM(x1, x2, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
@@ -223,7 +256,11 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v2, wback, fixedaddress);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
FSUBD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FSUBR ST0, double[ED]");
|
||||
@@ -231,7 +268,11 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v2, wback, fixedaddress);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
FSUBD(v1, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FDIV ST0, double[ED]");
|
||||
@@ -239,7 +280,11 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v2, wback, fixedaddress);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
FDIVD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FDIVR ST0, double[ED]");
|
||||
@@ -247,7 +292,11 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v2, wback, fixedaddress);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
FDIVD(v1, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
}
|
||||
return addr;
|
||||
|
||||
@@ -118,7 +118,7 @@ uintptr_t dynarec64_DD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
FCMPD(v1, v2);
|
||||
}
|
||||
FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0));
|
||||
FCOM(x1, x2, x3);
|
||||
break;
|
||||
case 0xE8:
|
||||
case 0xE9:
|
||||
@@ -136,7 +136,7 @@ uintptr_t dynarec64_DD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
FCMPD(v1, v2);
|
||||
}
|
||||
FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0));
|
||||
FCOM(x1, x2, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
@@ -161,19 +161,20 @@ uintptr_t dynarec64_DD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
if(arm64_frintts) {
|
||||
FRINT64ZD(s0, v1);
|
||||
FCVTZSxD(x2, s0);
|
||||
STx(x2, ed, fixedaddress);
|
||||
VFCVTZSd(s0, s0);
|
||||
VST64(s0, ed, fixedaddress);
|
||||
} else {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
FRINTRRD(s0, v1, 3);
|
||||
FCVTZSxD(x2, s0);
|
||||
VFCVTZSd(s0, s0);
|
||||
VST64(s0, ed, fixedaddress);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_MARK3(x5, FPSR_IOC);
|
||||
ORRx_mask(x2, xZR, 1, 1, 0); //0x8000000000000000
|
||||
MARK3;
|
||||
STx(x2, ed, fixedaddress);
|
||||
MARK3;
|
||||
}
|
||||
}
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
@@ -193,7 +194,7 @@ uintptr_t dynarec64_DD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FRSTOR m108byte");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (FRSTOR)\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
@@ -201,7 +202,7 @@ uintptr_t dynarec64_DD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FNSAVE m108byte");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (FNSAVE)\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
|
||||
@@ -29,6 +29,7 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
|
||||
uint8_t nextop = F8;
|
||||
uint8_t wback;
|
||||
uint8_t u8;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
int v1, v2;
|
||||
@@ -49,11 +50,15 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FADDP STx, ST0");
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
FADDS(v1, v1, v2);
|
||||
} else {
|
||||
FADDD(v1, v1, v2);
|
||||
}
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xC8:
|
||||
@@ -67,11 +72,15 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FMULP STx, ST0");
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
FMULS(v1, v1, v2);
|
||||
} else {
|
||||
FMULD(v1, v1, v2);
|
||||
}
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xD0:
|
||||
@@ -90,7 +99,7 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
FCMPD(v1, v2);
|
||||
}
|
||||
FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0));
|
||||
FCOM(x1, x2, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xD9:
|
||||
@@ -102,7 +111,7 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
FCMPD(v1, v2);
|
||||
}
|
||||
FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0));
|
||||
FCOM(x1, x2, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
@@ -117,11 +126,15 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FSUBRP STx, ST0");
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
FSUBS(v1, v2, v1);
|
||||
} else {
|
||||
FSUBD(v1, v2, v1);
|
||||
}
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xE8:
|
||||
@@ -135,11 +148,15 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FSUBP STx, ST0");
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
FSUBS(v1, v1, v2);
|
||||
} else {
|
||||
FSUBD(v1, v1, v2);
|
||||
}
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xF0:
|
||||
@@ -153,11 +170,15 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FDIVRP STx, ST0");
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
FDIVS(v1, v2, v1);
|
||||
} else {
|
||||
FDIVD(v1, v2, v1);
|
||||
}
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xF8:
|
||||
@@ -171,11 +192,15 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FDIVP STx, ST0");
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
FDIVS(v1, v1, v2);
|
||||
} else {
|
||||
FDIVD(v1, v1, v2);
|
||||
}
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
default:
|
||||
@@ -215,7 +240,7 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
FCMPD(v1, v2);
|
||||
FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0));
|
||||
FCOM(x1, x2, x3);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FICOMP ST0, word[ED]");
|
||||
@@ -227,7 +252,7 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
FCMPD(v1, v2);
|
||||
FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0));
|
||||
FCOM(x1, x2, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
|
||||
@@ -109,7 +109,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
FCMPD(v1, v2);
|
||||
}
|
||||
FCOMI(x1, x2, x4, v1, v2, ST_IS_F(0));
|
||||
FCOMI(x1, x2);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xF0:
|
||||
@@ -130,7 +130,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
FCMPD(v1, v2);
|
||||
}
|
||||
FCOMI(x1, x2, x4, v1, v2, ST_IS_F(0));
|
||||
FCOMI(x1, x2);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
@@ -175,12 +175,12 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VFCVTZSd(s0, v1);
|
||||
SQXTN_S_D(s0, s0);
|
||||
}
|
||||
VMOVSto(x3, s0, 0);
|
||||
SQXTN_H_S(s0, s0);
|
||||
VMOVHto(x3, s0, 0);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBNZ_MARK2(x5, FPSR_IOC);
|
||||
SXTHw(x5, x3); // check if 16bits value is fine
|
||||
SUBw_REG(x5, x5, x3);
|
||||
CBZw_MARK3(x5);
|
||||
TBNZ_MARK2(x5, FPSR_QC);
|
||||
B_MARK3_nocond;
|
||||
MARK2;
|
||||
MOV32w(x3, 0x8000);
|
||||
MARK3;
|
||||
@@ -215,12 +215,12 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VFCVTZSd(s0, s0);
|
||||
SQXTN_S_D(s0, s0);
|
||||
}
|
||||
VMOVSto(x3, s0, 0);
|
||||
SQXTN_H_S(s0, s0);
|
||||
VMOVHto(x3, s0, 0);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBNZ_MARK2(x5, FPSR_IOC);
|
||||
SXTHw(x5, x3); // check if 16bits value is fine
|
||||
SUBw_REG(x5, x5, x3);
|
||||
CBZw_MARK3(x5);
|
||||
TBNZ_MARK2(x5, FPSR_QC);
|
||||
B_MARK3_nocond;
|
||||
MARK2;
|
||||
MOV32w(x3, 0x8000);
|
||||
MARK3;
|
||||
@@ -245,6 +245,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
#else
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
BFCw(x5, FPSR_QC, 1); // reset QC bit
|
||||
MSR_fpsr(x5);
|
||||
if(ST_IS_F(0)) {
|
||||
FRINTXS(s0, v1);
|
||||
@@ -254,12 +255,12 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VFCVTZSd(s0, s0);
|
||||
SQXTN_S_D(s0, s0);
|
||||
}
|
||||
VMOVSto(x3, s0, 0);
|
||||
SQXTN_H_S(s0, s0);
|
||||
VMOVHto(x3, s0, 0);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBNZ_MARK2(x5, FPSR_IOC);
|
||||
SXTHw(x5, x3); // check if 16bits value is fine
|
||||
SUBw_REG(x5, x5, x3);
|
||||
CBZw_MARK3(x5);
|
||||
TBNZ_MARK2(x5, FPSR_QC);
|
||||
B_MARK3_nocond;
|
||||
MARK2;
|
||||
MOV32w(x3, 0x8000);
|
||||
MARK3;
|
||||
@@ -355,16 +356,22 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
B_MARK3(c__);
|
||||
MARK2;
|
||||
}
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
FRINTXD(s0, v1);
|
||||
VFCVTZSd(s0, s0);
|
||||
VST64(s0, wback, fixedaddress);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_MARK3(x5, FPSR_IOC);
|
||||
ORRx_mask(x5, xZR, 1, 1, 0); //0x8000000000000000
|
||||
STx(x5, wback, fixedaddress);
|
||||
if(arm64_frintts) {
|
||||
FRINT64XD(s0, v1);
|
||||
VFCVTZSd(s0, s0);
|
||||
VST64(s0, wback, fixedaddress);
|
||||
} else {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
FRINTXD(s0, v1);
|
||||
VFCVTZSd(s0, s0);
|
||||
VST64(s0, wback, fixedaddress);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_MARK3(x5, FPSR_IOC);
|
||||
ORRx_mask(x5, xZR, 1, 1, 0); //0x8000000000000000
|
||||
STx(x5, wback, fixedaddress);
|
||||
}
|
||||
MARK3;
|
||||
#endif
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
|
||||
@@ -27,8 +27,8 @@ void emit_or32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3,
|
||||
MAYUSE(s2);
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, rex.w?d_or64:d_or32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
ORRxw_REG(s1, s1, s2);
|
||||
IFX(X_PEND) {
|
||||
@@ -81,8 +81,8 @@ void emit_or32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, rex.w?d_or64:d_or32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
ORRxw_mask(s1, s1, (mask>>12)&1, mask&0x3F, (mask>>6)&0x3F);
|
||||
IFX(X_PEND) {
|
||||
@@ -130,8 +130,8 @@ void emit_xor32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
MAYUSE(s2);
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, rex.w?d_xor64:d_xor32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
EORxw_REG(s1, s1, s2);
|
||||
IFX(X_PEND) {
|
||||
@@ -177,17 +177,21 @@ void emit_xor32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
void emit_xor32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4)
|
||||
{
|
||||
int mask = convert_bitmask_xw(c);
|
||||
if(!mask) {
|
||||
if(!mask && !((!rex.w && c==0xffffffffLL) || (rex.w && c==0xffffffffffffffffLL))) {
|
||||
MOV64xw(s3, c);
|
||||
emit_xor32(dyn, ninst, rex, s1, s3, s3, s4);
|
||||
return;
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, rex.w?d_xor64:d_xor32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
if(!mask) {
|
||||
MVNxw_REG(s1, s1);
|
||||
} else {
|
||||
EORxw_mask(s1, s1, (mask>>12)&1, mask&0x3F, (mask>>6)&0x3F);
|
||||
}
|
||||
EORxw_mask(s1, s1, (mask>>12)&1, mask&0x3F, (mask>>6)&0x3F);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
@@ -233,8 +237,8 @@ void emit_and32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
MAYUSE(s2);
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, rex.w?d_and64:d_and32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFX(X_ZF|X_SF|X_CF|X_OF) {
|
||||
ANDSxw_REG(s1, s1, s2);
|
||||
@@ -285,8 +289,8 @@ void emit_and32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, in
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, rex.w?d_and64:d_and32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFX(X_ZF|X_SF|X_CF|X_OF) {
|
||||
ANDSxw_mask(s1, s1, (mask>>12)&1, mask&0x3F, (mask>>6)&0x3F);
|
||||
@@ -332,8 +336,8 @@ void emit_or8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
MAYUSE(s2);
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, d_or8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
ORRw_REG(s1, s1, s2);
|
||||
IFX(X_PEND) {
|
||||
@@ -360,8 +364,8 @@ void emit_or8c(dynarec_arm_t* dyn, int ninst, int s1, uint8_t c, int s3, int s4)
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, d_or8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
ORRw_mask(s1, s1, mask&0x3F, (mask>>6)&0x3F);
|
||||
IFX(X_PEND) {
|
||||
@@ -383,8 +387,8 @@ void emit_xor8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
MAYUSE(s2);
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, d_xor8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
EORx_REG(s1, s1, s2);
|
||||
IFX(X_PEND) {
|
||||
@@ -411,8 +415,8 @@ void emit_xor8c(dynarec_arm_t* dyn, int ninst, int s1, uint8_t c, int s3, int s4
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, d_xor8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
EORw_mask(s1, s1, mask&0x3F, (mask>>6)&0x3F);
|
||||
IFX(X_PEND) {
|
||||
@@ -434,8 +438,8 @@ void emit_and8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
MAYUSE(s2);
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, d_and8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ANDSw_REG(s1, s1, s2);
|
||||
@@ -479,8 +483,8 @@ void emit_and8c(dynarec_arm_t* dyn, int ninst, int s1, uint8_t c, int s3, int s4
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, d_and8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ANDSw_mask(s1, s1, mask&0x3F, (mask>>6)&0x3F);
|
||||
@@ -519,8 +523,8 @@ void emit_or16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
MAYUSE(s2);
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, d_or16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
ORRw_REG(s1, s1, s2);
|
||||
IFX(X_PEND) {
|
||||
@@ -547,8 +551,8 @@ void emit_or16c(dynarec_arm_t* dyn, int ninst, int s1, int16_t c, int s3, int s4
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, d_or16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
ORRw_mask(s1, s1, mask&0x3F, (mask>>6)&0x3F);
|
||||
IFX(X_PEND) {
|
||||
@@ -570,8 +574,8 @@ void emit_xor16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
MAYUSE(s2);
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, d_xor16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
EORw_REG(s1, s1, s2);
|
||||
IFX(X_PEND) {
|
||||
@@ -598,8 +602,8 @@ void emit_xor16c(dynarec_arm_t* dyn, int ninst, int s1, int16_t c, int s3, int s
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, d_xor16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
EORw_mask(s1, s1, mask&0x3F, (mask>>6)&0x3F);
|
||||
IFX(X_PEND) {
|
||||
@@ -622,8 +626,8 @@ void emit_and16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
MAYUSE(s2);
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, d_and16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ANDSw_REG(s1, s1, s2);
|
||||
@@ -667,8 +671,8 @@ void emit_and16c(dynarec_arm_t* dyn, int ninst, int s1, int16_t c, int s3, int s
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, d_and16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ANDSw_mask(s1, s1, mask&0x3F, (mask>>6)&0x3F);
|
||||
|
||||
@@ -29,8 +29,8 @@ void emit_add32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, rex.w?d_add64:d_add32b);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFX(X_AF) {
|
||||
ORRxw_REG(s3, s1, s2); // s3 = op1 | op2
|
||||
@@ -83,8 +83,7 @@ void emit_add32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
void emit_add32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4, int s5)
|
||||
{
|
||||
MAYUSE(s5);
|
||||
if(s1==xRSP && (!dyn->insts || dyn->insts[ninst].x64.gen_flags==X_PEND))
|
||||
{
|
||||
if((s1==xRSP) && (BOX64DRENV(dynarec_safeflags)<2) && (!dyn->insts || (dyn->insts[ninst].x64.gen_flags==X_PEND) || (!BOX64ENV(dynarec_df) && (dyn->insts[ninst].x64.gen_flags==X_ALL)))) {
|
||||
// special case when doing math on ESP and only PEND is needed: ignoring it!
|
||||
if(c>=0 && c<0x1000) {
|
||||
ADDx_U12(s1, s1, c);
|
||||
@@ -99,8 +98,8 @@ void emit_add32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, in
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s5, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w?d_add64:d_add32b);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFX(X_AF) {
|
||||
IFX(X_PEND) {} else {MOV64xw(s5, c);}
|
||||
@@ -167,8 +166,8 @@ void emit_sub32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, rex.w?d_sub64:d_sub32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFX(X_AF) {
|
||||
ORNxw_REG(s3, s2, s1); // s3 = ~op1 | op2
|
||||
@@ -224,8 +223,7 @@ void emit_sub32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
void emit_sub32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4, int s5)
|
||||
{
|
||||
MAYUSE(s5);
|
||||
if(s1==xRSP && (!dyn->insts || dyn->insts[ninst].x64.gen_flags==X_PEND))
|
||||
{
|
||||
if(s1==xRSP && (BOX64DRENV(dynarec_safeflags)<2) && (!dyn->insts || (dyn->insts[ninst].x64.gen_flags==X_PEND) || (!BOX64ENV(dynarec_df) && (dyn->insts[ninst].x64.gen_flags==X_ALL)))) {
|
||||
// special case when doing math on RSP and only PEND is needed: ignoring it!
|
||||
if(c>=0 && c<0x1000) {
|
||||
SUBxw_U12(s1, s1, c);
|
||||
@@ -240,8 +238,8 @@ void emit_sub32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, in
|
||||
MOV64xw(s5, c);
|
||||
STRxw_U12(s5, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w?d_sub64:d_sub32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFX(X_AF) {
|
||||
IFX(X_PEND) {} else {MOV64xw(s5, c);}
|
||||
@@ -311,8 +309,8 @@ void emit_add8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRB_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_add8b);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFX(X_AF | X_OF) {
|
||||
ORRw_REG(s3, s1, s2); // s3 = op1 | op2
|
||||
@@ -377,8 +375,8 @@ void emit_add8c(dynarec_arm_t* dyn, int ninst, int s1, uint8_t c, int s3, int s4
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRB_U12(s4, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_add8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFX(X_AF | X_OF) {
|
||||
IFX(X_PEND) {} else {MOV32w(s4, c);}
|
||||
@@ -420,8 +418,8 @@ void emit_sub8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRB_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_sub8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFX(X_AF|X_OF|X_CF) {
|
||||
MVNw_REG(s3, s1);
|
||||
@@ -467,8 +465,8 @@ void emit_sub8c(dynarec_arm_t* dyn, int ninst, int s1, uint8_t c, int s3, int s4
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRB_U12(s5, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_sub8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFX(X_AF|X_OF|X_CF) {
|
||||
MVNw_REG(s3, s1);
|
||||
@@ -514,8 +512,8 @@ void emit_add16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRH_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_add16b);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFX(X_AF) {
|
||||
ORRw_REG(s3, s1, s2); // s3 = op1 | op2
|
||||
@@ -573,7 +571,7 @@ void emit_add16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
|
||||
// emit ADD16 instruction, from s1, const c, store result in s1 using s3 and s4 as scratch
|
||||
//void emit_add16c(dynarec_arm_t* dyn, int ninst, int s1, int c, int s3, int s4)
|
||||
// void emit_add16c(dynarec_arm_t* dyn, int ninst, int s1, int c, int s3, int s4)
|
||||
//{
|
||||
// IFX(X_PEND) {
|
||||
// MOVW(s3, c);
|
||||
@@ -581,7 +579,7 @@ void emit_add16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
// STR_IMM9(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
// SET_DF(s4, d_add16);
|
||||
// } else IFX(X_ALL) {
|
||||
// SET_DFNONE(s4);
|
||||
// SET_DFNONE();
|
||||
// }
|
||||
// IFX(X_AF | X_OF) {
|
||||
// MOV_REG(s4, s1);
|
||||
@@ -647,8 +645,8 @@ void emit_sub16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRH_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_sub16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFX(X_AF|X_OF|X_CF) {
|
||||
ORNw_REG(s3, s2, s1); // s3 = ~op1 | op2
|
||||
@@ -683,7 +681,7 @@ void emit_sub16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
|
||||
// emit SUB16 instruction, from s1, constant c, store result in s1 using s3 and s4 as scratch
|
||||
//void emit_sub16c(dynarec_arm_t* dyn, int ninst, int s1, int c, int s3, int s4)
|
||||
// void emit_sub16c(dynarec_arm_t* dyn, int ninst, int s1, int c, int s3, int s4)
|
||||
//{
|
||||
// IFX(X_PEND) {
|
||||
// MOVW(s3, c);
|
||||
@@ -691,7 +689,7 @@ void emit_sub16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
// STR_IMM9(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
// SET_DF(s4, d_sub16);
|
||||
// } else IFX(X_ALL) {
|
||||
// SET_DFNONE(s4);
|
||||
// SET_DFNONE();
|
||||
// }
|
||||
// IFX(X_AF|X_OF|X_CF) {
|
||||
// MVN_REG_LSL_IMM5(s4, s1, 0);
|
||||
@@ -750,7 +748,7 @@ void emit_sub16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
// emit INC32 instruction, from s1, store result in s1 using s3 and s4 as scratch
|
||||
void emit_inc32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s3, int s4)
|
||||
{
|
||||
SET_DFNONE(s4);
|
||||
SET_DFNONE();
|
||||
IFX(X_AF) {
|
||||
if(rex.w) {
|
||||
ORRx_mask(s3, s1, 1, 0, 0); // s3 = op1 | op2
|
||||
@@ -797,7 +795,7 @@ void emit_inc32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s3, int s4
|
||||
// emit INC8 instruction, from s1, store result in s1 using s3 and s4 as scratch
|
||||
void emit_inc8(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
{
|
||||
SET_DFNONE(s3);
|
||||
SET_DFNONE();
|
||||
IFX(X_AF | X_OF) {
|
||||
ORRw_mask(s3, s1, 0, 0); // s3 = op1 | op2
|
||||
ANDw_mask(s4, s1, 0, 0); // s4 = op1 & op2
|
||||
@@ -825,7 +823,7 @@ void emit_inc8(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
// emit INC16 instruction, from s1, store result in s1 using s3 and s4 as scratch
|
||||
void emit_inc16(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
{
|
||||
SET_DFNONE(s3);
|
||||
SET_DFNONE();
|
||||
IFX(X_AF | X_OF) {
|
||||
ORRw_mask(s3, s1, 0, 0); // s3 = op1 | op2
|
||||
ANDw_mask(s4, s1, 0, 0); // s4 = op1 & op2
|
||||
@@ -853,7 +851,7 @@ void emit_inc16(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
// emit DEC32 instruction, from s1, store result in s1 using s3 and s4 as scratch
|
||||
void emit_dec32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s3, int s4)
|
||||
{
|
||||
SET_DFNONE(s4);
|
||||
SET_DFNONE();
|
||||
IFX(X_AF) {
|
||||
MVNxw_REG(s3, s1);
|
||||
if(rex.w) {
|
||||
@@ -901,7 +899,7 @@ void emit_dec32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s3, int s4
|
||||
// emit DEC8 instruction, from s1, store result in s1 using s3 and s4 as scratch
|
||||
void emit_dec8(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
{
|
||||
SET_DFNONE(s3);
|
||||
SET_DFNONE();
|
||||
IFX(X_AF|X_OF) {
|
||||
MVNw_REG(s3, s1);
|
||||
ANDw_mask(s4, s3, 0, 0); // s4 = ~op1 & op2
|
||||
@@ -943,7 +941,7 @@ void emit_dec8(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
// emit DEC16 instruction, from s1, store result in s1 using s3 and s4 as scratch
|
||||
void emit_dec16(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
{
|
||||
SET_DFNONE(s3);
|
||||
SET_DFNONE();
|
||||
IFX(X_AF|X_OF) {
|
||||
MVNw_REG(s4, s1);
|
||||
}
|
||||
@@ -990,8 +988,8 @@ void emit_adc32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, rex.w?d_adc64:d_adc32b);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFNATIVE_BEFORE(NF_CF) {
|
||||
if(INVERTED_CARRY_BEFORE) {
|
||||
@@ -1056,7 +1054,7 @@ void emit_adc32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
}
|
||||
|
||||
// emit ADC32 instruction, from s1, constant c, store result in s1 using s3 and s4 as scratch
|
||||
//void emit_adc32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
// void emit_adc32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
//{
|
||||
// IFX(X_PEND) {
|
||||
// MOV32(s3, c);
|
||||
@@ -1064,7 +1062,7 @@ void emit_adc32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
// STR_IMM9(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
// SET_DF(s4, d_adc32);
|
||||
// } else IFX(X_ALL) {
|
||||
// SET_DFNONE(s4);
|
||||
// SET_DFNONE();
|
||||
// }
|
||||
// IFX(X_AF) {
|
||||
// MOV_REG(s4, s1);
|
||||
@@ -1133,8 +1131,8 @@ void emit_adc8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRB_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_adc8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFNATIVE_BEFORE(NF_CF) {
|
||||
if(INVERTED_CARRY_BEFORE) {
|
||||
@@ -1197,8 +1195,8 @@ void emit_adc16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRH_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_adc16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFNATIVE_BEFORE(NF_CF) {
|
||||
if(INVERTED_CARRY_BEFORE) {
|
||||
@@ -1246,7 +1244,7 @@ void emit_adc16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
|
||||
// emit ADC16 instruction, from s1, const c, store result in s1 using s3 and s4 as scratch
|
||||
//void emit_adc16c(dynarec_arm_t* dyn, int ninst, int s1, int c, int s3, int s4)
|
||||
// void emit_adc16c(dynarec_arm_t* dyn, int ninst, int s1, int c, int s3, int s4)
|
||||
//{
|
||||
// IFX(X_PEND) {
|
||||
// MOVW(s3, c);
|
||||
@@ -1254,7 +1252,7 @@ void emit_adc16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
// STR_IMM9(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
// SET_DF(s3, d_adc16);
|
||||
// } else IFX(X_ALL) {
|
||||
// SET_DFNONE(s3);
|
||||
// SET_DFNONE();
|
||||
// }
|
||||
// IFX(X_AF | X_OF) {
|
||||
// MOV_REG(s4, s1);
|
||||
@@ -1320,8 +1318,8 @@ void emit_sbb32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, rex.w?d_sbb64:d_sbb32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFNATIVE_BEFORE(NF_CF) {
|
||||
if(!INVERTED_CARRY_BEFORE) {
|
||||
@@ -1390,7 +1388,7 @@ void emit_sbb32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
}
|
||||
|
||||
// emit SBB32 instruction, from s1, constant c, store result in s1 using s3 and s4 as scratch
|
||||
//void emit_sbb32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
// void emit_sbb32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
//{
|
||||
// IFX(X_PEND) {
|
||||
// MOV32(s3, c);
|
||||
@@ -1398,7 +1396,7 @@ void emit_sbb32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
// STR_IMM9(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
// SET_DF(s4, d_sbb32);
|
||||
// } else IFX(X_ALL) {
|
||||
// SET_DFNONE(s4);
|
||||
// SET_DFNONE();
|
||||
// }
|
||||
// IFX(X_AF) {
|
||||
// MVN_REG_LSL_IMM5(s4, s1, 0);
|
||||
@@ -1469,8 +1467,8 @@ void emit_sbb8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRB_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_sbb8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFNATIVE_BEFORE(NF_CF) {
|
||||
if(!INVERTED_CARRY_BEFORE) {
|
||||
@@ -1534,8 +1532,8 @@ void emit_sbb16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRH_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_sbb16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFNATIVE_BEFORE(NF_CF) {
|
||||
if(!INVERTED_CARRY_BEFORE) {
|
||||
@@ -1584,7 +1582,7 @@ void emit_sbb16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
|
||||
// emit SBB16 instruction, from s1, constant c, store result in s1 using s3 and s4 as scratch
|
||||
//void emit_sbb16c(dynarec_arm_t* dyn, int ninst, int s1, int c, int s3, int s4)
|
||||
// void emit_sbb16c(dynarec_arm_t* dyn, int ninst, int s1, int c, int s3, int s4)
|
||||
//{
|
||||
// IFX(X_PEND) {
|
||||
// MOVW(s3, c);
|
||||
@@ -1592,7 +1590,7 @@ void emit_sbb16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
// STR_IMM9(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
// SET_DF(s3, d_sbb16);
|
||||
// } else IFX(X_ALL) {
|
||||
// SET_DFNONE(s3);
|
||||
// SET_DFNONE();
|
||||
// }
|
||||
// IFX(X_AF|X_OF|X_CF) {
|
||||
// MVN_REG_LSL_IMM5(s4, s1, 0);
|
||||
@@ -1656,8 +1654,8 @@ void emit_neg32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s3, int s4
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s3, rex.w?d_neg64:d_neg32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFX(X_CF) {
|
||||
TSTxw_REG(s1, s1);
|
||||
@@ -1709,8 +1707,8 @@ void emit_neg16(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s3, d_neg16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFX(X_CF) {
|
||||
TSTw_REG(s1, s1);
|
||||
@@ -1758,8 +1756,8 @@ void emit_neg8(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s3, d_neg8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFX(X_CF) {
|
||||
TSTw_REG(s1, s1);
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -30,7 +30,7 @@ void emit_cmp32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
STRxw_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w?d_cmp64:d_cmp32);
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFX(X_AF) {
|
||||
ORNxw_REG(s3, s2, s1); // s3 = ~op1 | op2
|
||||
@@ -88,7 +88,7 @@ void emit_cmp32_0(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s3, int
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
SET_DF(s4, rex.w?d_cmp64:d_cmp32);
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
SET_DFNONE();
|
||||
}
|
||||
SUBSxw_U12(s3, s1, 0); // res = s1 - 0
|
||||
// and now the tricky ones (and mostly unused), PF and AF
|
||||
@@ -134,7 +134,7 @@ void emit_cmp16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, i
|
||||
STRH_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_cmp16);
|
||||
} else {
|
||||
SET_DFNONE(s3);
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFX(X_AF) {
|
||||
ORNw_REG(s3, s2, s1); // s3 = ~op1 | op2
|
||||
@@ -206,7 +206,7 @@ void emit_cmp16_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
SET_DF(s3, d_cmp16);
|
||||
} else {
|
||||
SET_DFNONE(s3);
|
||||
SET_DFNONE();
|
||||
}
|
||||
// bc = (res & (~d | s)) | (~d & s) = 0
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
@@ -227,7 +227,7 @@ void emit_cmp8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, in
|
||||
STRB_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_cmp8);
|
||||
} else {
|
||||
SET_DFNONE(s3);
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFX(X_AF) {
|
||||
ORNw_REG(s3, s2, s1); // s3 = ~op1 | op2
|
||||
@@ -298,7 +298,7 @@ void emit_cmp8_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
SET_DF(s3, d_cmp8);
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
SET_DFNONE();
|
||||
}
|
||||
// bc = (res & (~d | s)) | (~d & s) = 0
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
@@ -318,7 +318,7 @@ void emit_test32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
IFX_PENDOR0 {
|
||||
SET_DF(s3, rex.w?d_tst64:d_tst32);
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFX(X_CF) {
|
||||
IFNATIVE(NF_CF) {} else {
|
||||
@@ -362,7 +362,7 @@ void emit_test32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i
|
||||
IFX_PENDOR0 {
|
||||
SET_DF(s3, rex.w?d_tst64:d_tst32);
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFX(X_CF) {
|
||||
IFNATIVE(NF_CF) {} else {
|
||||
@@ -410,7 +410,7 @@ void emit_test16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4,
|
||||
IFX_PENDOR0 {
|
||||
SET_DF(s3, d_tst16);
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFX(X_CF|X_ZF|X_SF|X_OF) {
|
||||
LSLw(s5, s1, 16);
|
||||
@@ -458,7 +458,7 @@ void emit_test16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int
|
||||
IFX_PENDOR0 {
|
||||
SET_DF(s3, d_tst16);
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFX(X_CF|X_ZF|X_SF|X_OF) {
|
||||
LSLw(s5, s1, 16);
|
||||
@@ -517,7 +517,7 @@ void emit_test8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, i
|
||||
IFX_PENDOR0 {
|
||||
SET_DF(s3, d_tst8);
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFX(X_CF|X_ZF|X_SF|X_OF) {
|
||||
LSLw(s5, s1, 24);
|
||||
@@ -565,7 +565,7 @@ void emit_test8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int
|
||||
IFX_PENDOR0 {
|
||||
SET_DF(s3, d_tst8);
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFX(X_CF|X_ZF|X_SF|X_OF) {
|
||||
LSLw(s5, s1, 24);
|
||||
|
||||
@@ -33,7 +33,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
int32_t i32;
|
||||
int64_t i64, j64;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
int unscaled, mask;
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
MAYUSE(gb1);
|
||||
@@ -60,7 +60,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGB(x2);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if (MODREG) {
|
||||
if(rex.rex) {
|
||||
wback = TO_NAT((nextop & 0x07) + (rex.b << 3));
|
||||
wb2 = 0;
|
||||
@@ -77,7 +77,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(arm64_atomics) {
|
||||
UFLAG_IF {
|
||||
LDADDALB(x2, x1, wback);
|
||||
emit_add8(dyn, ninst, x1, x2, x4, x5);
|
||||
emit_add8(dyn, ninst, x1, x2, x4, x5);
|
||||
} else {
|
||||
STADDLB(x2, wback);
|
||||
}
|
||||
@@ -114,7 +114,6 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(arm64_atomics) {
|
||||
UFLAG_IF {
|
||||
LDADDALxw(gd, x1, wback);
|
||||
emit_add32(dyn, ninst, rex, x1, gd, x3, x4);
|
||||
} else {
|
||||
STADDLxw(gd, wback);
|
||||
}
|
||||
@@ -122,23 +121,28 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
MARKLOCK;
|
||||
LDAXRxw(x1, wback);
|
||||
emit_add32(dyn, ninst, rex, x1, gd, x3, x4);
|
||||
STLXRxw(x3, x1, wback);
|
||||
ADDxw_REG(x4, x1, gd);
|
||||
STLXRxw(x3, x4, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
SMDMB();
|
||||
}
|
||||
if(!ALIGNED_ATOMICxw) {
|
||||
B_NEXT_nocond;
|
||||
B_MARK2_nocond;
|
||||
MARK; // unaligned! also, not enough
|
||||
LDRxw_U12(x1, wback, 0);
|
||||
LDAXRB(x4, wback);
|
||||
BFIxw(x1, x4, 0, 8); // re-inject
|
||||
emit_add32(dyn, ninst, rex, x1, gd, x3, x4);
|
||||
STLXRB(x3, x1, wback);
|
||||
SUBxw_UXTB(x4, x4, x1); // substract with the byte only
|
||||
CBNZw_MARK(x4); // jump if different
|
||||
ADDxw_REG(x4, x1, gd);
|
||||
STLXRB(x3, x4, wback);
|
||||
CBNZx_MARK(x3);
|
||||
STRxw_U12(x1, wback, 0); // put the whole value
|
||||
STRxw_U12(x4, wback, 0); // put the whole value
|
||||
SMDMB();
|
||||
}
|
||||
MARK2;
|
||||
UFLAG_IF {
|
||||
emit_add32(dyn, ninst, rex, x1, gd, x3, x4);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -147,7 +151,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGB(x2);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if (MODREG) {
|
||||
if(rex.rex) {
|
||||
wback = TO_NAT((nextop & 0x07) + (rex.b << 3));
|
||||
wb2 = 0;
|
||||
@@ -164,7 +168,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(arm64_atomics) {
|
||||
LDSETALB(x2, x1, wback);
|
||||
UFLAG_IF {
|
||||
emit_or8(dyn, ninst, x1, x2, x4, x5);
|
||||
emit_or8(dyn, ninst, x1, x2, x4, x5);
|
||||
}
|
||||
} else {
|
||||
MARKLOCK;
|
||||
@@ -189,7 +193,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(arm64_atomics) {
|
||||
LDSETALxw(gd, x1, wback);
|
||||
UFLAG_IF {
|
||||
emit_or32(dyn, ninst, rex, x1, gd, x3, x4);
|
||||
emit_or32(dyn, ninst, rex, x1, gd, x3, x4);
|
||||
}
|
||||
} else {
|
||||
MARKLOCK;
|
||||
@@ -208,8 +212,11 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
|
||||
case 0xAB:
|
||||
INST_NAME("LOCK BTS Ed, Gd");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
if(!BOX64ENV(dynarec_safeflags)) {
|
||||
SETFLAGS(X_ALL&~X_ZF, SF_SUBSET);
|
||||
} else {
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
}
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
@@ -226,7 +233,9 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
ANDSw_mask(x4, x4, 0, 0); //mask=1
|
||||
}
|
||||
BFIw(xFlags, x4, F_CF, 1);
|
||||
IFX(X_CF) {
|
||||
BFIw(xFlags, x4, F_CF, 1);
|
||||
}
|
||||
MOV32w(x4, 1);
|
||||
LSLxw_REG(x4, x4, x2);
|
||||
ORRxw_REG(ed, ed, x4);
|
||||
@@ -235,14 +244,17 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ANDw_mask(x2, gd, 0, 0b00010); //mask=0x000000007
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
ASRxw(x1, gd, 3); // r1 = (gd>>3)
|
||||
ADDx_REG_LSL(x3, wback, x1, 0); //(&ed)+=r1;
|
||||
if(!rex.w && !rex.is32bits) {SXTWx(x1, x1);}
|
||||
ADDz_REG_LSL(x3, wback, x1, 0); //(&ed)+=r1;
|
||||
ed = x1;
|
||||
wback = x3;
|
||||
MOV32w(x5, 1);
|
||||
MARKLOCK;
|
||||
LDAXRB(ed, wback);
|
||||
LSRw_REG(x4, ed, x2);
|
||||
BFIw(xFlags, x4, F_CF, 1);
|
||||
IFX(X_CF) {
|
||||
BFIw(xFlags, x4, F_CF, 1);
|
||||
}
|
||||
LSLw_REG(x4, x5, x2);
|
||||
ORRw_REG(ed, ed, x4);
|
||||
STLXRB(x4, ed, wback);
|
||||
@@ -343,15 +355,17 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(arm64_atomics) {
|
||||
UFLAG_IF {
|
||||
MOVxw_REG(x1, xRAX);
|
||||
CASALxw(xRAX, gd, wback);
|
||||
CASALxw(x1, gd, wback);
|
||||
SMDMB();
|
||||
emit_cmp32(dyn, ninst, rex, x1, xRAX, x3, x4, x5);
|
||||
if(!ALIGNED_ATOMICxw) {
|
||||
B_MARK_nocond;
|
||||
}
|
||||
} else {
|
||||
CASALxw(xRAX, gd, wback);
|
||||
SMDMB();
|
||||
}
|
||||
if(!ALIGNED_ATOMICxw) {
|
||||
B_NEXT_nocond;
|
||||
if(!ALIGNED_ATOMICxw) {
|
||||
B_NEXT_nocond;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
MARKLOCK;
|
||||
@@ -372,6 +386,8 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MARK3;
|
||||
LDRxw_U12(x1, wback, 0);
|
||||
LDAXRB(x3, wback); // dummy read, to arm the write...
|
||||
SUBxw_UXTB(x3, x3, x1);
|
||||
CBNZw_MARK3(x3);
|
||||
CMPSxw_REG(xRAX, x1);
|
||||
B_MARK(cNE);
|
||||
// EAX == Ed
|
||||
@@ -380,11 +396,12 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
STRxw_U12(gd, wback, 0);
|
||||
SMDMB();
|
||||
}
|
||||
if(!ALIGNED_ATOMICxw || !arm64_atomics) {
|
||||
MARK;
|
||||
// Common part (and fallback for EAX != Ed)
|
||||
UFLAG_IF {emit_cmp32(dyn, ninst, rex, xRAX, x1, x3, x4, x5);}
|
||||
MOVxw_REG(xRAX, x1); // upper par of RAX will be erase on 32bits, no mater what
|
||||
MARK;
|
||||
// Common part (and fallback for EAX != Ed)
|
||||
UFLAG_IF {emit_cmp32(dyn, ninst, rex, xRAX, x1, x3, x4, x5); MOVxw_REG(xRAX, x1);}
|
||||
else {
|
||||
if(!ALIGNED_ATOMICxw || !arm64_atomics)
|
||||
MOVxw_REG(xRAX, x1); // upper par of RAX will be erase on 32bits, no mater what
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -395,8 +412,11 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
|
||||
case 0xB3:
|
||||
INST_NAME("LOCK BTR Ed, Gd");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
if(!BOX64ENV(dynarec_safeflags)) {
|
||||
SETFLAGS(X_ALL&~X_ZF, SF_SUBSET);
|
||||
} else {
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
}
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
@@ -408,12 +428,9 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ANDw_mask(x2, gd, 0, 0b00100); //mask=0x00000001f
|
||||
}
|
||||
LSRxw_REG(x4, ed, x2);
|
||||
if(rex.w) {
|
||||
ANDx_mask(x4, x4, 1, 0, 0); //mask=1
|
||||
} else {
|
||||
ANDw_mask(x4, x4, 0, 0); //mask=1
|
||||
IFX(X_CF) {
|
||||
BFIw(xFlags, x4, F_CF, 1);
|
||||
}
|
||||
BFIw(xFlags, x4, F_CF, 1);
|
||||
MOV32w(x4, 1);
|
||||
LSLxw_REG(x4, x4, x2);
|
||||
BICxw_REG(ed, ed, x4);
|
||||
@@ -422,14 +439,17 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ANDw_mask(x2, gd, 0, 0b00010); //mask=0x000000007
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
ASRx(x1, gd, 3); // r1 = (gd>>3), there might be an issue for negative 32bits values here
|
||||
ADDx_REG_LSL(x3, wback, x1, 0); //(&ed)+=r1;
|
||||
if(!rex.w && !rex.is32bits) {SXTWx(x1, x1);}
|
||||
ADDz_REG_LSL(x3, wback, x1, 0); //(&ed)+=r1;
|
||||
ed = x1;
|
||||
wback = x3;
|
||||
MOV32w(x5, 1);
|
||||
MARKLOCK;
|
||||
LDAXRB(ed, wback);
|
||||
LSRw_REG(x4, ed, x2);
|
||||
BFIw(xFlags, x4, F_CF, 1);
|
||||
IFX(X_CF) {
|
||||
BFIw(xFlags, x4, F_CF, 1);
|
||||
}
|
||||
LSLw_REG(x4, x5, x2);
|
||||
BICw_REG(ed, ed, x4);
|
||||
STLXRB(x4, ed, wback);
|
||||
@@ -443,17 +463,22 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
switch((nextop>>3)&7) {
|
||||
case 4:
|
||||
INST_NAME("LOCK BT Ed, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
if(!BOX64ENV(dynarec_safeflags)) {
|
||||
SETFLAGS(X_ALL&~X_ZF, SF_SUBSET);
|
||||
} else {
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
}
|
||||
gd = x2;
|
||||
if(MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
u8 = F8;
|
||||
u8&=rex.w?0x3f:0x1f;
|
||||
BFXILxw(xFlags, ed, u8, 1); // inject 1 bit from u8 to F_CF (i.e. pos 0)
|
||||
IFX(X_CF) {
|
||||
BFXILxw(xFlags, ed, u8, 1); // inject 1 bit from u8 to F_CF (i.e. pos 0)
|
||||
}
|
||||
} else {
|
||||
// Will fetch only 1 byte, to avoid alignment issue
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 1);
|
||||
u8 = F8;
|
||||
if(u8>>3) {
|
||||
ADDx_U12(x3, wback, u8>>3);
|
||||
@@ -463,36 +488,44 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
LDAXRB(x1, wback);
|
||||
ed = x1;
|
||||
wback = x3;
|
||||
BFXILxw(xFlags, x1, u8&7, 1); // inject 1 bit from u8 to F_CF (i.e. pos 0)
|
||||
IFX(X_CF) {
|
||||
BFXILxw(xFlags, x1, u8&7, 1); // inject 1 bit from u8 to F_CF (i.e. pos 0)
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("LOCK BTS Ed, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
if(!BOX64ENV(dynarec_safeflags)) {
|
||||
SETFLAGS(X_ALL&~X_ZF, SF_SUBSET);
|
||||
} else {
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
}
|
||||
if(MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
wback = 0;
|
||||
u8 = F8;
|
||||
u8&=(rex.w?0x3f:0x1f);
|
||||
BFXILxw(xFlags, ed, u8, 1); // inject 1 bit from u8 to F_CF (i.e. pos 0)
|
||||
TBNZ_NEXT(xFlags, 0); // bit already set, jump to next instruction
|
||||
MOV32w(x4, 1);
|
||||
ORRxw_REG_LSL(ed, ed, x4, u8);
|
||||
IFX(X_CF) {
|
||||
BFXILxw(xFlags, ed, u8, 1); // inject 1 bit from u8 to F_CF (i.e. pos 0)
|
||||
}
|
||||
mask = convert_bitmask_xw(1LL<<u8);
|
||||
ORRxw_mask(ed, ed, (mask>>12)&1, mask&0x3F, (mask>>6)&0x3F);
|
||||
} else {
|
||||
// Will fetch only 1 byte, to avoid alignment issue
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 1);
|
||||
u8 = F8;
|
||||
if(u8>>3) {
|
||||
ADDx_U12(x3, wback, u8>>3);
|
||||
wback = x3;
|
||||
}
|
||||
ed = x1;
|
||||
MOV32w(x5, 1);
|
||||
MARKLOCK;
|
||||
LDAXRB(ed, wback);
|
||||
BFXILw(xFlags, ed, u8&7, 1); // inject 1 bit from u8 to F_CF (i.e. pos 0)
|
||||
BFIw(ed, x5, u8&7, 1);
|
||||
IFX(X_CF) {
|
||||
BFXILw(xFlags, ed, u8&7, 1); // inject 1 bit from u8 to F_CF (i.e. pos 0)
|
||||
}
|
||||
mask = convert_bitmask_xw(1LL<<(u8&7));
|
||||
ORRxw_mask(ed, ed, (mask>>12)&1, mask&0x3F, (mask>>6)&0x3F);
|
||||
STLXRB(x4, ed, wback);
|
||||
CBNZw_MARKLOCK(x4);
|
||||
SMDMB();
|
||||
@@ -500,18 +533,22 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("LOCK BTR Ed, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
if(!BOX64ENV(dynarec_safeflags)) {
|
||||
SETFLAGS(X_ALL&~X_ZF, SF_SUBSET);
|
||||
} else {
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
}
|
||||
if(MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
wback = 0;
|
||||
u8 = F8;
|
||||
u8&=(rex.w?0x3f:0x1f);
|
||||
BFXILxw(xFlags, ed, u8, 1); // inject 1 bit from u8 to F_CF (i.e. pos 0)
|
||||
TBZ_NEXT(xFlags, 0); // bit already clear, jump to next instruction
|
||||
IFX(X_CF) {
|
||||
BFXILxw(xFlags, ed, u8, 1); // inject 1 bit from u8 to F_CF (i.e. pos 0)
|
||||
}
|
||||
BFCxw(ed, u8, 1);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 1);
|
||||
u8 = F8;
|
||||
if(u8>>3) {
|
||||
ADDx_U12(x3, wback, u8>>3);
|
||||
@@ -529,29 +566,36 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("LOCK BTC Ed, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
if(!BOX64ENV(dynarec_safeflags)) {
|
||||
SETFLAGS(X_ALL&~X_ZF, SF_SUBSET);
|
||||
} else {
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
}
|
||||
if(MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
wback = 0;
|
||||
u8 = F8;
|
||||
u8&=(rex.w?0x3f:0x1f);
|
||||
BFXILxw(xFlags, ed, u8, 1); // inject 1 bit from u8 to F_CF (i.e. pos 0)
|
||||
IFX(X_CF) {
|
||||
BFXILxw(xFlags, ed, u8, 1); // inject 1 bit from u8 to F_CF (i.e. pos 0)
|
||||
}
|
||||
MOV32w(x4, 1);
|
||||
EORxw_REG_LSL(ed, ed, x4, u8);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 1);
|
||||
u8 = F8;
|
||||
if(u8>>3) {
|
||||
ADDx_U12(x3, wback, u8>>3);
|
||||
wback = x3;
|
||||
}
|
||||
ed = x1;
|
||||
MOV32w(x5, 1);
|
||||
MARKLOCK;
|
||||
LDAXRB(ed, wback);
|
||||
BFXILw(xFlags, ed, u8&7, 1); // inject 1 bit from u8 to F_CF (i.e. pos 0)
|
||||
EORw_REG_LSL(ed, ed, x5, u8&7);
|
||||
IFX(X_CF) {
|
||||
BFXILw(xFlags, ed, u8&7, 1); // inject 1 bit from u8 to F_CF (i.e. pos 0)
|
||||
}
|
||||
mask = convert_bitmask_xw(1LL<<(u8&7));
|
||||
ORRxw_mask(ed, ed, (mask>>12)&1, mask&0x3F, (mask>>6)&0x3F);
|
||||
STLXRB(x4, ed, wback);
|
||||
CBNZw_MARKLOCK(x4);
|
||||
SMDMB();
|
||||
@@ -635,16 +679,9 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
if(arm64_atomics) {
|
||||
UFLAG_IF {
|
||||
MOVxw_REG(x3, gd);
|
||||
LDADDALxw(x3, gd, wback);
|
||||
SMDMB();
|
||||
emit_add32(dyn, ninst, rex, x3, gd, x4, x5);
|
||||
LDADDALxw(gd, x1, wback);
|
||||
} else {
|
||||
LDADDALxw(gd, gd, wback);
|
||||
SMDMB();
|
||||
}
|
||||
if(!ALIGNED_ATOMICxw) {
|
||||
B_NEXT_nocond;
|
||||
}
|
||||
} else {
|
||||
MARKLOCK;
|
||||
@@ -652,28 +689,32 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ADDxw_REG(x4, x1, gd);
|
||||
STLXRxw(x3, x4, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
SMDMB();
|
||||
if(!ALIGNED_ATOMICxw) {
|
||||
B_MARK2_nocond;
|
||||
}
|
||||
}
|
||||
SMDMB();
|
||||
if(!ALIGNED_ATOMICxw) {
|
||||
UFLAG_IF {
|
||||
B_MARK2_nocond;
|
||||
} else {
|
||||
if(!arm64_atomics) MOVxw_REG(gd, x1);
|
||||
B_NEXT_nocond;
|
||||
}
|
||||
MARK;
|
||||
LDRxw_U12(x1, wback, 0);
|
||||
LDAXRB(x4, wback);
|
||||
BFIxw(x1, x4, 0, 8);
|
||||
SUBxw_UXTB(x4, x4, x1);
|
||||
CBNZw_MARK(x4);
|
||||
ADDxw_REG(x4, x1, gd);
|
||||
STLXRB(x3, x4, wback);
|
||||
CBNZx_MARK(x3);
|
||||
STRxw_U12(x4, wback, 0);
|
||||
SMDMB();
|
||||
}
|
||||
if(!ALIGNED_ATOMICxw || !arm64_atomics) {
|
||||
MARK2;
|
||||
IFX(X_ALL|X_PEND) {
|
||||
MOVxw_REG(x2, x1);
|
||||
emit_add32(dyn, ninst, rex, x2, gd, x3, x4);
|
||||
}
|
||||
MARK2;
|
||||
UFLAG_IF {
|
||||
MOVxw_REG(x3, x1);
|
||||
emit_add32(dyn, ninst, rex, x3, gd, x4, x5);
|
||||
MOVxw_REG(gd, x1);
|
||||
} else if(!arm64_atomics || !ALIGNED_ATOMICxw) {
|
||||
MOVxw_REG(gd, x1);
|
||||
}
|
||||
}
|
||||
@@ -699,7 +740,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(arm64_uscat) {
|
||||
if(rex.w) {
|
||||
TSTx_mask(wback, 1, 0, 3);
|
||||
B_MARK2(cNE);
|
||||
B_MARK2(cNE);
|
||||
} else {
|
||||
ANDx_mask(x2, wback, 1, 0, 3); // mask = F
|
||||
CMPSw_U12(x2, 8);
|
||||
@@ -754,6 +795,8 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MARK2;
|
||||
LDPxw_S7_offset(x2, x3, wback, 0);
|
||||
LDAXRB(x5, wback);
|
||||
SUBxw_UXTB(x5, x5, x2);
|
||||
CBNZw_MARK2(x5);
|
||||
CMPSxw_REG(xRAX, x2);
|
||||
CCMPxw(xRDX, x3, 0, cEQ);
|
||||
B_MARKSEG(cNE); // EAX!=ED[0] || EDX!=Ed[1]
|
||||
@@ -794,7 +837,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGB(x2);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if (MODREG) {
|
||||
if(rex.rex) {
|
||||
wback = TO_NAT((nextop & 0x07) + (rex.b << 3));
|
||||
wb2 = 0;
|
||||
@@ -915,34 +958,42 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
B_MARK(cNE);
|
||||
}
|
||||
}
|
||||
if(arm64_atomics) {
|
||||
if(arm64_atomics && 0) { // disabled because 0x80000000 has no negative
|
||||
NEGxw_REG(x1, gd);
|
||||
UFLAG_IF {
|
||||
LDADDALxw(x1, x1, wback);
|
||||
emit_sub32(dyn, ninst, rex, x1, gd, x3, x4);
|
||||
} else {
|
||||
STADDLxw(x1, wback);
|
||||
}
|
||||
} else {
|
||||
MARKLOCK;
|
||||
LDAXRxw(x1, wback);
|
||||
emit_sub32(dyn, ninst, rex, x1, gd, x3, x4);
|
||||
STLXRxw(x3, x1, wback);
|
||||
SUBxw_REG(x4, x1, gd);
|
||||
STLXRxw(x3, x4, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
SMDMB();
|
||||
}
|
||||
SMDMB();
|
||||
if(!ALIGNED_ATOMICxw) {
|
||||
B_NEXT_nocond;
|
||||
UFLAG_IF {
|
||||
B_MARK2_nocond;
|
||||
} else {
|
||||
B_NEXT_nocond;
|
||||
}
|
||||
MARK; // unaligned! also, not enough
|
||||
LDRxw_U12(x1, wback, 0);
|
||||
LDAXRB(x4, wback);
|
||||
BFIxw(x1, x4, 0, 8); // re-inject
|
||||
emit_sub32(dyn, ninst, rex, x1, gd, x3, x4);
|
||||
STLXRB(x3, x1, wback);
|
||||
SUBxw_UXTB(x4, x4, x1);
|
||||
CBNZw_MARK(x4);
|
||||
SUBxw_REG(x4, x1, gd);
|
||||
STLXRB(x3, x4, wback);
|
||||
CBNZx_MARK(x3);
|
||||
STRxw_U12(x1, wback, 0); // put the whole value
|
||||
STRxw_U12(x4, wback, 0); // put the whole value
|
||||
SMDMB();
|
||||
}
|
||||
UFLAG_IF {
|
||||
MARK2;
|
||||
emit_sub32(dyn, ninst, rex, x1, gd, x3, x4);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -951,7 +1002,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
emit_xor32(dyn, ninst, rex, ed, gd, x3, x4);
|
||||
} else {
|
||||
@@ -969,31 +1020,34 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(arm64_atomics) {
|
||||
UFLAG_IF {
|
||||
LDEORALxw(gd, x1, wback);
|
||||
emit_xor32(dyn, ninst, rex, x1, gd, x3, x4);
|
||||
} else {
|
||||
STEORLxw(gd, wback);
|
||||
}
|
||||
SMDMB();
|
||||
} else {
|
||||
MARKLOCK;
|
||||
LDAXRxw(x1, wback);
|
||||
emit_xor32(dyn, ninst, rex, x1, gd, x3, x4);
|
||||
STLXRxw(x3, x1, wback);
|
||||
EORxw_REG(x4, x1, gd);
|
||||
STLXRxw(x3, x4, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
SMDMB();
|
||||
}
|
||||
SMDMB();
|
||||
if(!ALIGNED_ATOMICxw) {
|
||||
B_NEXT_nocond;
|
||||
B_MARK2_nocond;
|
||||
MARK; // unaligned! also, not enough
|
||||
LDRxw_U12(x1, wback, 0);
|
||||
LDAXRB(x4, wback);
|
||||
BFIxw(x1, x4, 0, 8); // re-inject
|
||||
emit_xor32(dyn, ninst, rex, x1, gd, x3, x4);
|
||||
STLXRB(x3, x1, wback);
|
||||
SUBxw_UXTB(x4, x4, x1);
|
||||
CBNZw_MARK(x4);
|
||||
EORxw_REG(x4, x1, gd);
|
||||
STLXRB(x3, x4, wback);
|
||||
CBNZx_MARK(x3);
|
||||
STRxw_U12(x1, wback, 0); // put the whole value
|
||||
STRxw_U12(x4, wback, 0); // put the whole value
|
||||
SMDMB();
|
||||
}
|
||||
MARK2;
|
||||
UFLAG_IF {
|
||||
emit_xor32(dyn, ninst, rex, x1, gd, x3, x4);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1189,7 +1243,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOV32w(x2, u8);
|
||||
UFLAG_IF {
|
||||
LDEORALB(x2, x1, wback);
|
||||
emit_xor8(dyn, ninst, x1, x2, x3, x4);
|
||||
emit_xor8(dyn, ninst, x1, x2, x3, x4);
|
||||
} else {
|
||||
STEORLB(x2, wback);
|
||||
}
|
||||
@@ -1238,6 +1292,9 @@ 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((i64<=-0x1000) || (i64>=0x1000)) {
|
||||
MOV64xw(x5, i64);
|
||||
}
|
||||
if(!ALIGNED_ATOMICxw) {
|
||||
if(arm64_uscat) {
|
||||
ANDx_mask(x1, wback, 1, 0, 3); // mask = F
|
||||
@@ -1249,35 +1306,56 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
}
|
||||
if(arm64_atomics) {
|
||||
MOV64xw(x3, i64);
|
||||
UFLAG_IF {
|
||||
LDADDALxw(x3, x1, wback);
|
||||
SMDMB();
|
||||
emit_add32(dyn, ninst, rex, x1, x3, x4, x5);
|
||||
} else {
|
||||
STADDLxw(x3, wback);
|
||||
SMDMB();
|
||||
if((i64>-0x1000) && (i64<0x1000)) {
|
||||
MOV64xw(x5, i64);
|
||||
}
|
||||
UFLAG_IF {
|
||||
LDADDALxw(x5, x1, wback);
|
||||
} else {
|
||||
STADDLxw(x5, wback);
|
||||
}
|
||||
SMDMB();
|
||||
} else {
|
||||
MARKLOCK;
|
||||
LDAXRxw(x1, wback);
|
||||
emit_add32c(dyn, ninst, rex, x1, i64, x3, x4, x5);
|
||||
STLXRxw(x3, x1, wback);
|
||||
if(i64>=0 && i64<0x1000) {
|
||||
ADDxw_U12(x4, x1, i64);
|
||||
} else if(i64<0 && i64>-0x1000) {
|
||||
SUBxw_U12(x4, x1, -i64);
|
||||
} else {
|
||||
ADDxw_REG(x4, x1, x5);
|
||||
}
|
||||
STLXRxw(x3, x4, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
SMDMB();
|
||||
}
|
||||
if(!ALIGNED_ATOMICxw) {
|
||||
B_NEXT_nocond;
|
||||
B_MARK2_nocond;
|
||||
MARK; // unaligned! also, not enough
|
||||
LDRxw_U12(x1, wback, 0);
|
||||
LDAXRB(x4, wback);
|
||||
BFIxw(x1, x4, 0, 8); // re-inject
|
||||
emit_add32c(dyn, ninst, rex, x1, i64, x3, x4, x5);
|
||||
STLXRB(x3, x1, wback);
|
||||
SUBxw_UXTB(x4, x4, x1);
|
||||
CBNZw_MARK(x4);
|
||||
if(i64>=0 && i64<0x1000) {
|
||||
ADDxw_U12(x4, x1, i64);
|
||||
} else if(i64<0 && i64>-0x1000) {
|
||||
SUBxw_U12(x4, x1, -i64);
|
||||
} else {
|
||||
ADDxw_REG(x4, x1, x5);
|
||||
}
|
||||
STLXRB(x3, x4, wback);
|
||||
CBNZx_MARK(x3);
|
||||
STRxw_U12(x1, wback, 0); // put the whole value
|
||||
STRxw_U12(x4, wback, 0); // put the whole value
|
||||
SMDMB();
|
||||
}
|
||||
MARK2;
|
||||
UFLAG_IF {
|
||||
if((i64<=-0x1000) || (i64>=0x1000)) {
|
||||
emit_add32(dyn, ninst, rex, x1, x5, x3, x4);
|
||||
} else {
|
||||
emit_add32c(dyn, ninst, rex, x1, i64, x3, x4, x5);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1: //OR
|
||||
@@ -1286,23 +1364,22 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
MOV64xw(x5, i64);
|
||||
emit_or32(dyn, ninst, rex, ed, x5, x3, x4);
|
||||
emit_or32c(dyn, ninst, rex, ed, i64, x3, x4);
|
||||
} 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;
|
||||
MOV64xw(x5, i64);
|
||||
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_or32(dyn, ninst, rex, x1, x5, x3, x4);
|
||||
emit_or32c(dyn, ninst, rex, x1, i64, x3, x4);
|
||||
STLXRxw(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
@@ -1372,10 +1449,9 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
STCLRLxw(x5, wback);
|
||||
}
|
||||
} else {
|
||||
MOV64xw(x5, i64);
|
||||
MARKLOCK;
|
||||
LDAXRxw(x1, wback);
|
||||
emit_and32(dyn, ninst, rex, x1, x5, x3, x4);
|
||||
emit_and32c(dyn, ninst, rex, x1, i64, x3, x4);
|
||||
STLXRxw(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
@@ -1388,11 +1464,13 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
MOV64xw(x5, i64);
|
||||
emit_sub32(dyn, ninst, rex, ed, x5, x3, x4);
|
||||
emit_sub32c(dyn, ninst, rex, ed, i64, x3, x4, x5);
|
||||
} 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((i64<=-0x1000) || (i64>=0x1000)) {
|
||||
MOV64xw(x5, i64);
|
||||
}
|
||||
if(!ALIGNED_ATOMICxw) {
|
||||
if(arm64_uscat) {
|
||||
ANDx_mask(x1, wback, 1, 0, 3); // mask = F
|
||||
@@ -1404,36 +1482,64 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
}
|
||||
if(arm64_atomics) {
|
||||
MOV64xw(x5, -i64);
|
||||
if((i64>-0x1000) && (i64<0x1000)) {
|
||||
MOV64xw(x5, -i64);
|
||||
} else {
|
||||
NEGxw_REG(x5, x5);
|
||||
}
|
||||
UFLAG_IF {
|
||||
LDADDALxw(x5, x1, wback);
|
||||
SMDMB();
|
||||
NEGxw_REG(x5, x5);
|
||||
emit_sub32(dyn, ninst, rex, x1, x5, x3, x4);
|
||||
if((i64<=-0x1000) || (i64>=0x1000))
|
||||
NEGxw_REG(x5, x5);
|
||||
} else {
|
||||
STADDLxw(x5, wback);
|
||||
SMDMB();
|
||||
}
|
||||
SMDMB();
|
||||
} else {
|
||||
MARKLOCK;
|
||||
LDAXRxw(x1, wback);
|
||||
emit_sub32c(dyn, ninst, rex, x1, i64, x3, x4, x5);
|
||||
STLXRxw(x3, x1, wback);
|
||||
if(i64>=0 && i64<0x1000) {
|
||||
SUBxw_U12(x4, x1, i64);
|
||||
} else if(i64<0 && i64>-0x1000) {
|
||||
ADDxw_U12(x4, x1, -i64);
|
||||
} else {
|
||||
SUBxw_REG(x4, x1, x5);
|
||||
}
|
||||
STLXRxw(x3, x4, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
SMDMB();
|
||||
}
|
||||
if(!ALIGNED_ATOMICxw) {
|
||||
B_NEXT_nocond;
|
||||
UFLAG_IF {
|
||||
B_MARK2_nocond;
|
||||
} else {
|
||||
B_NEXT_nocond;
|
||||
}
|
||||
MARK; // unaligned! also, not enough
|
||||
LDRxw_U12(x1, wback, 0);
|
||||
LDAXRB(x4, wback);
|
||||
BFIxw(x1, x4, 0, 8); // re-inject
|
||||
emit_sub32c(dyn, ninst, rex, x1, i64, x3, x4, x5);
|
||||
STLXRB(x3, x1, wback);
|
||||
SUBxw_UXTB(x4, x4, x1);
|
||||
CBNZw_MARK(x4);
|
||||
if(i64>=0 && i64<0x1000) {
|
||||
SUBxw_U12(x4, x1, i64);
|
||||
} else if(i64<0 && i64>-0x1000) {
|
||||
ADDxw_U12(x4, x1, -i64);
|
||||
} else {
|
||||
SUBxw_REG(x4, x1, x5);
|
||||
}
|
||||
STLXRB(x3, x4, wback);
|
||||
CBNZx_MARK(x3);
|
||||
STRxw_U12(x1, wback, 0); // put the whole value
|
||||
STRxw_U12(x4, wback, 0); // put the whole value
|
||||
SMDMB();
|
||||
}
|
||||
UFLAG_IF {
|
||||
MARK2;
|
||||
if((i64<=-0x1000) || (i64>=0x1000)) {
|
||||
emit_sub32(dyn, ninst, rex, x1, x5, x3, x4);
|
||||
} else {
|
||||
emit_sub32c(dyn, ninst, rex, x1, i64, x3, x4, x5);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 6: //XOR
|
||||
@@ -1447,8 +1553,8 @@ 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;
|
||||
MOV64xw(x5, i64);
|
||||
if(arm64_atomics) {
|
||||
MOV64xw(x5, i64);
|
||||
UFLAG_IF {
|
||||
LDEORALxw(x5, x1, wback);
|
||||
emit_xor32(dyn, ninst, rex, x1, x5, x3, x4);
|
||||
@@ -1458,7 +1564,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
MARKLOCK;
|
||||
LDAXRxw(x1, wback);
|
||||
emit_xor32(dyn, ninst, rex, x1, x5, x3, x4);
|
||||
emit_xor32c(dyn, ninst, rex, x1, i64, x3, x4);
|
||||
STLXRxw(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
@@ -1556,7 +1662,9 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!ALIGNED_ATOMICxw) {
|
||||
MARK;
|
||||
LDRxw_U12(x1, ed, 0);
|
||||
LDAXRB(x3, ed);
|
||||
LDAXRB(x4, ed);
|
||||
SUBxw_UXTB(x4, x4, x1);
|
||||
CBNZw_MARK(x4);
|
||||
STLXRB(x3, gd, ed);
|
||||
CBNZx_MARK(x3);
|
||||
STRxw_U12(gd, ed, 0);
|
||||
@@ -1589,11 +1697,44 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
EBBACK;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
MARKLOCK;
|
||||
LDAXRB(x1, wback);
|
||||
if(arm64_atomics) {
|
||||
MOV32w(x1, 0xff);
|
||||
STEORLB(x1, wback);
|
||||
} else {
|
||||
MARKLOCK;
|
||||
LDAXRB(x1, wback);
|
||||
MVNw_REG(x1, x1);
|
||||
STLXRB(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
SMDMB();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0xF7:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 2:
|
||||
INST_NAME("LOCK NOT Ed");
|
||||
if(MODREG) {
|
||||
GETED(x1);
|
||||
MVNw_REG(x1, x1);
|
||||
STLXRB(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
EBBACK;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
if(arm64_atomics) {
|
||||
MOV64x(x1, ~0LL);
|
||||
STEORLxw(x1, wback);
|
||||
} else {
|
||||
MARKLOCK;
|
||||
LDAXRxw(x1, wback);
|
||||
MVNw_REG(x1, x1);
|
||||
STLXRxw(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
SMDMB();
|
||||
}
|
||||
break;
|
||||
@@ -1690,30 +1831,38 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOV32w(x3, 1);
|
||||
UFLAG_IF {
|
||||
LDADDALxw(x3, x1, wback);
|
||||
emit_inc32(dyn, ninst, rex, x1, x3, x4);
|
||||
} else {
|
||||
STADDLxw(x3, wback);
|
||||
}
|
||||
} else {
|
||||
MARKLOCK;
|
||||
LDAXRxw(x1, wback);
|
||||
emit_inc32(dyn, ninst, rex, x1, x3, x4);
|
||||
STLXRxw(x3, x1, wback);
|
||||
ADDxw_U12(x4, x1, 1);
|
||||
STLXRxw(x3, x4, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
SMDMB();
|
||||
if(!ALIGNED_ATOMICxw) {
|
||||
B_NEXT_nocond;
|
||||
UFLAG_IF {
|
||||
B_MARK2_nocond;
|
||||
} else {
|
||||
B_NEXT_nocond;
|
||||
}
|
||||
MARK;
|
||||
LDRxw_U12(x1, wback, 0);
|
||||
LDAXRB(x4, wback);
|
||||
BFIxw(x1, x4, 0, 8); // re-inject
|
||||
emit_inc32(dyn, ninst, rex, x1, x3, x4);
|
||||
STLXRB(x3, x1, wback);
|
||||
SUBxw_UXTB(x4, x4, x1);
|
||||
CBNZw_MARK(x4);
|
||||
ADDxw_U12(x4, x1, 1);
|
||||
STLXRB(x3, x4, wback);
|
||||
CBNZw_MARK(x3);
|
||||
STRxw_U12(x1, wback, 0);
|
||||
STRxw_U12(x4, wback, 0);
|
||||
SMDMB();
|
||||
}
|
||||
UFLAG_IF {
|
||||
MARK2;
|
||||
emit_inc32(dyn, ninst, rex, x1, x3, x4);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1: //DEC Ed
|
||||
@@ -1738,30 +1887,38 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOV64xw(x3, -1);
|
||||
UFLAG_IF {
|
||||
LDADDALxw(x3, x1, wback);
|
||||
emit_dec32(dyn, ninst, rex, x1, x3, x4);
|
||||
} else {
|
||||
STADDLxw(x3, wback);
|
||||
}
|
||||
} else {
|
||||
MARKLOCK;
|
||||
LDAXRxw(x1, wback);
|
||||
emit_dec32(dyn, ninst, rex, x1, x3, x4);
|
||||
STLXRxw(x3, x1, wback);
|
||||
SUBxw_U12(x4, x1, 1);
|
||||
STLXRxw(x3, x4, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
SMDMB();
|
||||
if(!ALIGNED_ATOMICxw) {
|
||||
B_NEXT_nocond;
|
||||
UFLAG_IF {
|
||||
B_MARK2_nocond;
|
||||
} else {
|
||||
B_NEXT_nocond;
|
||||
}
|
||||
MARK;
|
||||
LDRxw_U12(x1, wback, 0);
|
||||
LDAXRB(x4, wback);
|
||||
BFIxw(x1, x4, 0, 8); // re-inject
|
||||
emit_dec32(dyn, ninst, rex, x1, x3, x4);
|
||||
STLXRB(x3, x1, wback);
|
||||
SUBxw_UXTB(x4, x4, x1);
|
||||
CBNZw_MARK(x4);
|
||||
SUBxw_U12(x4, x1, 1);
|
||||
STLXRB(x3, x4, wback);
|
||||
CBNZw_MARK(x3);
|
||||
STRxw_U12(x1, wback, 0);
|
||||
STRxw_U12(x4, wback, 0);
|
||||
SMDMB();
|
||||
}
|
||||
UFLAG_IF {
|
||||
MARK2;
|
||||
emit_dec32(dyn, ninst, rex, x1, x3, x4);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -100,11 +100,17 @@ uintptr_t dynarec64_F20F(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) {
|
||||
SCVTFDx(d1, ed);
|
||||
} else {
|
||||
SCVTFDw(d1, ed);
|
||||
}
|
||||
if(BOX64ENV(dynarec_fastround)<2) {
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
}
|
||||
VMOVeD(v0, 0, d1, 0);
|
||||
break;
|
||||
|
||||
@@ -113,13 +119,13 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEXSD(q0, 0, 0);
|
||||
if(!box64_dynarec_fastround) {
|
||||
if(!BOX64ENV(dynarec_fastround)) {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
}
|
||||
FCVTZSxwD(gd, q0);
|
||||
if(!box64_dynarec_fastround) {
|
||||
if(!BOX64ENV(dynarec_fastround)) {
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_NEXT(x5, FPSR_IOC);
|
||||
if(rex.w) {
|
||||
@@ -134,7 +140,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEXSD(q0, 0, 0);
|
||||
if(!box64_dynarec_fastround) {
|
||||
if(!BOX64ENV(dynarec_fastround)) {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
@@ -144,7 +150,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
FRINTID(d1, q0);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
FCVTZSxwD(gd, d1);
|
||||
if(!box64_dynarec_fastround) {
|
||||
if(!BOX64ENV(dynarec_fastround)) {
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_NEXT(x5, FPSR_IOC);
|
||||
if(rex.w) {
|
||||
@@ -206,19 +212,23 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
case 0x51:
|
||||
INST_NAME("SQRTSD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETGX(q0, 1);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSD(d0, 0, 0);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
FCMLTD_0(v1, d0);
|
||||
SHL_64(v1, v1, 63);
|
||||
// check if any input value was NAN
|
||||
FCMEQD(v0, d0, d0); // 0 if NAN, 1 if not NAN
|
||||
FSQRTD(d1, d0);
|
||||
VORR(d1, d1, v1);
|
||||
FCMEQD(v1, d1, d1); // 0 => out is NAN
|
||||
VBIC(v1, v0, v1); // forget it in any input was a NAN already
|
||||
SHL_64(v1, v1, 63); // only keep the sign bit
|
||||
VORR(d1, d1, v1); // NAN -> -NAN
|
||||
} else {
|
||||
FSQRTD(d1, d0);
|
||||
}
|
||||
VMOVeD(v0, 0, d1, 0);
|
||||
VMOVeD(q0, 0, d1, 0);
|
||||
break;
|
||||
|
||||
case 0x58:
|
||||
@@ -227,7 +237,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(d1, 1);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSD(d0, 0, 0);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
@@ -249,7 +259,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(d1, 1);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSD(d0, 0, 0);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
@@ -271,7 +281,13 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(v0, 1);
|
||||
GETEXSD(d0, 0, 0);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
FCVT_S_D(d1, d0);
|
||||
if(BOX64ENV(dynarec_fastround)>1) {
|
||||
FCVT_S_D(d1, d0);
|
||||
} else {
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x3);
|
||||
FCVT_S_D(d1, d0);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
}
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
break;
|
||||
|
||||
@@ -281,7 +297,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(d1, 1);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSD(d0, 0, 0);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
@@ -319,7 +335,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(v0, 1);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSD(v1, 0, 0);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
@@ -389,26 +405,14 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
INST_NAME("HADDPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
VLD128(v1, ed, fixedaddress);
|
||||
}
|
||||
GETEX(v1, 0, 1);
|
||||
VFADDPQS(v0, v0, v1);
|
||||
break;
|
||||
case 0x7D:
|
||||
INST_NAME("HSUBPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
VLD128(v1, ed, fixedaddress);
|
||||
}
|
||||
GETEX(v1, 0, 1);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
VUZP1Q_32(d0, v0, v1);
|
||||
VUZP2Q_32(v0, v0, v1);
|
||||
@@ -491,7 +495,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
static float addsubps[4] = {-1.f, 1.f, -1.f, 1.f};
|
||||
MAYUSE(addsubps);
|
||||
TABLE64(x2, (uintptr_t)&addsubps);
|
||||
MOV64x(x2, (uintptr_t)&addsubps); // no need to use table64, as box64 is loaded in low memory
|
||||
VLDR128_U12(q0, x2, 0);
|
||||
VFMLAQS(v0, v1, q0);
|
||||
break;
|
||||
@@ -509,7 +513,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETEX(v1, 0, 0);
|
||||
GETGX_empty(v0);
|
||||
if(box64_dynarec_fastround) {
|
||||
if(BOX64ENV(dynarec_fastround)) {
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x3);
|
||||
VFRINTIDQ(v0, v1);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
|
||||
@@ -131,13 +131,13 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEXSS(d0, 0, 0);
|
||||
if(!box64_dynarec_fastround) {
|
||||
if(!BOX64ENV(dynarec_fastround)) {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
}
|
||||
FCVTZSxwS(gd, d0);
|
||||
if(!box64_dynarec_fastround) {
|
||||
if(!BOX64ENV(dynarec_fastround)) {
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_NEXT(x5, FPSR_IOC);
|
||||
if(rex.w) {
|
||||
@@ -152,7 +152,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEXSS(q0, 0, 0);
|
||||
if(!box64_dynarec_fastround) {
|
||||
if(!BOX64ENV(dynarec_fastround)) {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
@@ -162,7 +162,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
FRINTIS(d1, q0);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
FCVTZSxwS(gd, d1);
|
||||
if(!box64_dynarec_fastround) {
|
||||
if(!BOX64ENV(dynarec_fastround)) {
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_NEXT(x5, FPSR_IOC);
|
||||
if(rex.w) {
|
||||
@@ -185,8 +185,12 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETED(0);
|
||||
GETGD;
|
||||
MRS_nzcv(x3);
|
||||
LSRw(x4, xFlags, F_OF);
|
||||
BFIx(x3, x4, 29, 1); // set C
|
||||
IFNATIVE_BEFORE(NF_VF) {
|
||||
LSRw(x4, x3, NZCV_V);
|
||||
} else {
|
||||
LSRw(x4, xFlags, F_OF);
|
||||
}
|
||||
BFIx(x3, x4, NZCV_C, 1); // set C
|
||||
MSR_nzcv(x3); // load CC into ARM CF
|
||||
IFX(X_OF) {
|
||||
ADCSxw_REG(gd, gd, ed);
|
||||
@@ -242,11 +246,24 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
case 0x58:
|
||||
INST_NAME("ADDSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
GETGX(d1, 1);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSS(d0, 0, 0);
|
||||
FADDS(d1, v0, d0); // the high part of the vector is erased...
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
FMAXS(v0, d0, d1); // propagate NAN
|
||||
FCMEQS(v0, v0, v0); // 0 if NAN, 1 if not NAN
|
||||
FADDS(v1, d1, d0); // the high part of the vector is erased...
|
||||
FCMEQS(q0, v1, v1); // 0 => out is NAN
|
||||
VBIC(q0, v0, q0); // forget it in any input was a NAN already
|
||||
VSHL_32(q0, q0, 31); // only keep the sign bit
|
||||
VORR(v1, v1, q0); // NAN -> -NAN
|
||||
} else {
|
||||
FADDS(v1, d1, d0); // the high part of the vector is erased...
|
||||
}
|
||||
VMOVeS(d1, 0, v1, 0);
|
||||
break;
|
||||
case 0x59:
|
||||
INST_NAME("MULSS Gx, Ex");
|
||||
@@ -254,19 +271,19 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(d1, 1);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSS(d0, 0, 0);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
FMAXS(v0, d0, d1); // propagate NAN
|
||||
FCMEQS(v0, v0, v0); // 0 if NAN, 1 if not NAN
|
||||
FMULS(v1, d1, d0);
|
||||
FMULS(v1, d1, d0); // the high part of the vector is erased...
|
||||
FCMEQS(q0, v1, v1); // 0 => out is NAN
|
||||
VBIC(q0, v0, q0); // forget it in any input was a NAN already
|
||||
VSHL_32(q0, q0, 31); // only keep the sign bit
|
||||
VSHL_32(q0, q0, 31); // only keep the sign bit
|
||||
VORR(v1, v1, q0); // NAN -> -NAN
|
||||
} else {
|
||||
FMULS(v1, d1, d0);
|
||||
FMULS(v1, d1, d0); // the high part of the vector is erased...
|
||||
}
|
||||
VMOVeS(d1, 0, v1, 0);
|
||||
break;
|
||||
@@ -284,7 +301,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETEX(v1, 0, 0) ;
|
||||
GETGX_empty(v0);
|
||||
if(box64_dynarec_fastround) {
|
||||
if(BOX64ENV(dynarec_fastround)) {
|
||||
VFCVTZSQS(v0, v1);
|
||||
} else {
|
||||
MRS_fpsr(x5);
|
||||
@@ -307,11 +324,24 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
case 0x5C:
|
||||
INST_NAME("SUBSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
GETGX(d1, 1);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSS(d0, 0, 0);
|
||||
FSUBS(d1, v0, d0);
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
FMAXS(v0, d0, d1); // propagate NAN
|
||||
FCMEQS(v0, v0, v0); // 0 if NAN, 1 if not NAN
|
||||
FSUBS(v1, d1, d0); // the high part of the vector is erased...
|
||||
FCMEQS(q0, v1, v1); // 0 => out is NAN
|
||||
VBIC(q0, v0, q0); // forget it in any input was a NAN already
|
||||
VSHL_32(q0, q0, 31); // only keep the sign bit
|
||||
VORR(v1, v1, q0); // NAN -> -NAN
|
||||
} else {
|
||||
FSUBS(v1, d1, d0); // the high part of the vector is erased...
|
||||
}
|
||||
VMOVeS(d1, 0, v1, 0);
|
||||
break;
|
||||
case 0x5D:
|
||||
INST_NAME("MINSS Gx, Ex");
|
||||
@@ -332,11 +362,24 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
case 0x5E:
|
||||
INST_NAME("DIVSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
GETGX(d1, 1);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSS(d0, 0, 0);
|
||||
FDIVS(d1, v0, d0);
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
FMAXS(v0, d0, d1); // propagate NAN
|
||||
FCMEQS(v0, v0, v0); // 0 if NAN, 1 if not NAN
|
||||
FDIVS(v1, d1, d0); // the high part of the vector is erased...
|
||||
FCMEQS(q0, v1, v1); // 0 => out is NAN
|
||||
VBIC(q0, v0, q0); // forget it in any input was a NAN already
|
||||
VSHL_32(q0, q0, 31); // only keep the sign bit
|
||||
VORR(v1, v1, q0); // NAN -> -NAN
|
||||
} else {
|
||||
FDIVS(v1, d1, d0); // the high part of the vector is erased...
|
||||
}
|
||||
VMOVeS(d1, 0, v1, 0);
|
||||
break;
|
||||
case 0x5F:
|
||||
INST_NAME("MAXSS Gx, Ex");
|
||||
@@ -417,8 +460,20 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, (nextop&7) + (rex.b<<3));
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VST128(v0, ed, fixedaddress);
|
||||
IF_UNALIGNED(ip) {
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VST128(v0, ed, fixedaddress);
|
||||
}
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
@@ -454,7 +509,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
case 0xB8:
|
||||
INST_NAME("POPCNT Gd, Ed");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SET_DFNONE(x1);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
GETGD;
|
||||
@@ -478,19 +533,27 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
CNT_8(v1, v1);
|
||||
UADDLV_8(v1, v1);
|
||||
VMOVQDto(gd, v1, 0);
|
||||
VMOVHto(gd, v1, 0);
|
||||
IFX(X_ALL) {
|
||||
MOV32w(x1, (1<<F_OF) | (1<<F_SF) | (1<<F_ZF) | (1<<F_AF) | (1<<F_CF) | (1<<F_PF));
|
||||
BICw(xFlags, xFlags, x1);
|
||||
CBNZx(gd, 4+4);
|
||||
BFIw(xFlags, xFlags, F_ZF, 1);
|
||||
IFX(X_AF|X_PF|X_SF|X_OF|X_CF) {
|
||||
MOV32w(x1, (1<<F_OF) | (1<<F_SF) | (1<<F_ZF) | (1<<F_AF) | (1<<F_CF) | (1<<F_PF));
|
||||
BICw(xFlags, xFlags, x1);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CMPSw_U12(gd, 0);
|
||||
IFNATIVE(NF_EQ) {}
|
||||
else {
|
||||
CSETw(x1, cEQ);
|
||||
BFIw(xFlags, x1, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xBC:
|
||||
INST_NAME("TZCNT Gd, Ed");
|
||||
SETFLAGS(X_CF|X_ZF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
GETGD;
|
||||
@@ -510,7 +573,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
case 0xBD:
|
||||
INST_NAME("LZCNT Gd, Ed");
|
||||
SETFLAGS(X_CF|X_ZF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
GETGD;
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "custommem.h"
|
||||
#include "bridge.h"
|
||||
#include "gdbjit.h"
|
||||
|
||||
// Get a FPU scratch reg
|
||||
int fpu_get_scratch(dynarec_arm_t* dyn, int ninst)
|
||||
@@ -286,7 +287,7 @@ 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(box64_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(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(i>=0) {
|
||||
dyn->insts[ninst].n.neoncache[i].t = NEON_CACHE_ST_D;
|
||||
if(!dyn->insts[ninst].n.barrier)
|
||||
@@ -303,19 +304,19 @@ 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(box64_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(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(i<0) return;
|
||||
dyn->insts[ninst].n.neoncache[i].t = NEON_CACHE_ST_D;
|
||||
// check combined propagation too
|
||||
if(dyn->insts[ninst].n.combined1 || dyn->insts[ninst].n.combined2) {
|
||||
if(dyn->insts[ninst].n.swapped) {
|
||||
//if(box64_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(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 (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(box64_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(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);
|
||||
neoncache_promote_double_combined(dyn, ninst, maxinst, a);
|
||||
}
|
||||
}
|
||||
@@ -331,19 +332,19 @@ 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(box64_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(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 (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(box64_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(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(i<0) return;
|
||||
dyn->insts[ninst].n.neoncache[i].t = NEON_CACHE_ST_D;
|
||||
// check combined propagation too
|
||||
if((dyn->insts[ninst].n.combined1 || dyn->insts[ninst].n.combined2) && !dyn->insts[ninst].n.swapped) {
|
||||
//if(box64_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(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);
|
||||
neoncache_promote_double_combined(dyn, ninst, maxinst, a);
|
||||
}
|
||||
a-=dyn->insts[ninst].n.stack_pop; // adjust Stack depth: remove pop'd ST (going forward)
|
||||
@@ -359,20 +360,20 @@ 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(box64_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(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(i<0) return;
|
||||
dyn->n.neoncache[i].t = NEON_CACHE_ST_D;
|
||||
dyn->insts[ninst].n.neoncache[i].t = NEON_CACHE_ST_D;
|
||||
// check combined propagation too
|
||||
if(dyn->n.combined1 || dyn->n.combined2) {
|
||||
if(dyn->n.swapped) {
|
||||
//if(box64_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(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->n.combined1 == a)
|
||||
a = dyn->n.combined2;
|
||||
else if(dyn->n.combined2 == a)
|
||||
a = dyn->n.combined1;
|
||||
} else {
|
||||
//if(box64_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(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->n.combined1 == a)
|
||||
neoncache_promote_double(dyn, ninst, dyn->n.combined2);
|
||||
else if(dyn->n.combined2 == a)
|
||||
@@ -658,101 +659,204 @@ const char* getCacheName(int t, int n)
|
||||
return buff;
|
||||
}
|
||||
|
||||
static register_mapping_t register_mappings[] = {
|
||||
{ "rax", "x10" },
|
||||
{ "eax", "w10" },
|
||||
{ "ax", "x10" },
|
||||
{ "ah", "x10" },
|
||||
{ "al", "x10" },
|
||||
{ "rcx", "x11" },
|
||||
{ "ecx", "w11" },
|
||||
{ "cx", "x11" },
|
||||
{ "ch", "x11" },
|
||||
{ "cl", "x11" },
|
||||
{ "rdx", "x12" },
|
||||
{ "edx", "w12" },
|
||||
{ "dx", "x12" },
|
||||
{ "dh", "x12" },
|
||||
{ "dl", "x12" },
|
||||
{ "rbx", "x13" },
|
||||
{ "ebx", "w13" },
|
||||
{ "bx", "x13" },
|
||||
{ "bh", "x13" },
|
||||
{ "bl", "x13" },
|
||||
{ "rsi", "x14" },
|
||||
{ "esi", "w14" },
|
||||
{ "si", "x14" },
|
||||
{ "sil", "x14" },
|
||||
{ "rdi", "x15" },
|
||||
{ "edi", "w15" },
|
||||
{ "di", "x15" },
|
||||
{ "dil", "x15" },
|
||||
{ "rsp", "x16" },
|
||||
{ "esp", "w16" },
|
||||
{ "sp", "x16" },
|
||||
{ "spl", "x16" },
|
||||
{ "rbp", "x17" },
|
||||
{ "ebp", "w17" },
|
||||
{ "bp", "x17" },
|
||||
{ "bpl", "x17" },
|
||||
{ "r8", "x18" },
|
||||
{ "r8d", "w18" },
|
||||
{ "r8w", "x18" },
|
||||
{ "r8b", "x18" },
|
||||
{ "r9", "x19" },
|
||||
{ "r9d", "w19" },
|
||||
{ "r9w", "x19" },
|
||||
{ "r9b", "x19" },
|
||||
{ "r10", "x20" },
|
||||
{ "r10d", "w20" },
|
||||
{ "r10w", "x20" },
|
||||
{ "r10b", "x20" },
|
||||
{ "r11", "x21" },
|
||||
{ "r11d", "w21" },
|
||||
{ "r11w", "x21" },
|
||||
{ "r11b", "x21" },
|
||||
{ "r12", "x22" },
|
||||
{ "r12d", "w22" },
|
||||
{ "r12w", "x22" },
|
||||
{ "r12b", "x22" },
|
||||
{ "r13", "x23" },
|
||||
{ "r13d", "w23" },
|
||||
{ "r13w", "x23" },
|
||||
{ "r13b", "x23" },
|
||||
{ "r14", "x24" },
|
||||
{ "r14d", "w24" },
|
||||
{ "r14w", "x24" },
|
||||
{ "r14b", "x24" },
|
||||
{ "r15", "x25" },
|
||||
{ "r15d", "w25" },
|
||||
{ "r15w", "x25" },
|
||||
{ "r15b", "x25" },
|
||||
{ "rip", "x27" },
|
||||
};
|
||||
|
||||
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(box64_dynarec_dump) {
|
||||
printf_x64_instruction(rex.is32bits?my_context->dec32:my_context->dec, &dyn->insts[ninst].x64, name);
|
||||
dynarec_log(LOG_NONE, "%s%p: %d emitted opcodes, inst=%d, barrier=%d state=%d/%d/%d(%d:%d->%d:%d), %s=%X/%X, use=%X, need=%X/%X, sm=%d(%d/%d)",
|
||||
(box64_dynarec_dump>1)?"\e[32m":"",
|
||||
(void*)(dyn->native_start+dyn->insts[ninst].address),
|
||||
dyn->insts[ninst].size/4,
|
||||
ninst,
|
||||
dyn->insts[ninst].x64.barrier,
|
||||
dyn->insts[ninst].x64.state_flags,
|
||||
dyn->f.pending,
|
||||
dyn->f.dfnone,
|
||||
dyn->insts[ninst].f_entry.pending,
|
||||
dyn->insts[ninst].f_entry.dfnone,
|
||||
dyn->insts[ninst].f_exit.pending,
|
||||
dyn->insts[ninst].f_exit.dfnone,
|
||||
dyn->insts[ninst].x64.may_set?"may":"set",
|
||||
dyn->insts[ninst].x64.set_flags,
|
||||
dyn->insts[ninst].x64.gen_flags,
|
||||
dyn->insts[ninst].x64.use_flags,
|
||||
dyn->insts[ninst].x64.need_before,
|
||||
dyn->insts[ninst].x64.need_after,
|
||||
dyn->smwrite, dyn->insts[ninst].will_write, dyn->insts[ninst].last_write);
|
||||
if(dyn->insts[ninst].nat_flags_op) {
|
||||
if(dyn->insts[ninst].nat_flags_op==NAT_FLAG_OP_TOUCH && dyn->insts[ninst].before_nat_flags)
|
||||
printf_log(LOG_NONE, " NF:%d/read:%x", dyn->insts[ninst].nat_flags_op, dyn->insts[ninst].before_nat_flags);
|
||||
else
|
||||
printf_log(LOG_NONE, " NF:%d", dyn->insts[ninst].nat_flags_op);
|
||||
if (!BOX64DRENV(dynarec_dump) && !BOX64ENV(dynarec_gdbjit) && !BOX64ENV(dynarec_perf_map)) return;
|
||||
|
||||
static char buf[256];
|
||||
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,
|
||||
dyn->f.pending,
|
||||
dyn->f.dfnone,
|
||||
dyn->insts[ninst].f_entry.pending,
|
||||
dyn->insts[ninst].f_entry.dfnone,
|
||||
dyn->insts[ninst].f_exit.pending,
|
||||
dyn->insts[ninst].f_exit.dfnone,
|
||||
dyn->insts[ninst].x64.may_set ? "may" : "set",
|
||||
dyn->insts[ninst].x64.set_flags,
|
||||
dyn->insts[ninst].x64.gen_flags,
|
||||
dyn->insts[ninst].x64.use_flags,
|
||||
dyn->insts[ninst].x64.need_before,
|
||||
dyn->insts[ninst].x64.need_after,
|
||||
dyn->smwrite, dyn->insts[ninst].will_write, dyn->insts[ninst].last_write);
|
||||
if (dyn->insts[ninst].nat_flags_op) {
|
||||
if (dyn->insts[ninst].nat_flags_op == NAT_FLAG_OP_TOUCH && dyn->insts[ninst].before_nat_flags)
|
||||
length += sprintf(buf + length, " NF:%d/read:%x", dyn->insts[ninst].nat_flags_op, dyn->insts[ninst].before_nat_flags);
|
||||
else
|
||||
length += sprintf(buf + length, " NF:%d", dyn->insts[ninst].nat_flags_op);
|
||||
}
|
||||
if (dyn->insts[ninst].use_nat_flags || dyn->insts[ninst].set_nat_flags || dyn->insts[ninst].need_nat_flags) {
|
||||
length += sprintf(buf + length, " nf:%hhx/%hhx/%hhx", dyn->insts[ninst].set_nat_flags, dyn->insts[ninst].use_nat_flags, dyn->insts[ninst].need_nat_flags);
|
||||
}
|
||||
if (dyn->insts[ninst].invert_carry)
|
||||
length += sprintf(buf + length, " CI");
|
||||
if (dyn->insts[ninst].gen_inverted_carry)
|
||||
length += sprintf(buf + length, " gic");
|
||||
if (dyn->insts[ninst].before_nat_flags & NF_CF) {
|
||||
length += sprintf(buf + length, " %ccb", dyn->insts[ninst].normal_carry_before ? 'n' : 'i');
|
||||
}
|
||||
if (dyn->insts[ninst].need_nat_flags & NF_CF) {
|
||||
length += sprintf(buf + length, " %cc", dyn->insts[ninst].normal_carry ? 'n' : 'i');
|
||||
}
|
||||
if (dyn->insts[ninst].pred_sz) {
|
||||
length += sprintf(buf + length, ", pred=");
|
||||
for (int ii = 0; ii < dyn->insts[ninst].pred_sz; ++ii)
|
||||
length += sprintf(buf + length, "%s%d", ii ? "/" : "", dyn->insts[ninst].pred[ii]);
|
||||
}
|
||||
if (!dyn->insts[ninst].x64.alive)
|
||||
length += sprintf(buf + length, "not executed");
|
||||
if (dyn->insts[ninst].x64.jmp && dyn->insts[ninst].x64.jmp_insts >= 0) {
|
||||
length += sprintf(buf + length, ", jmp=%d", dyn->insts[ninst].x64.jmp_insts);
|
||||
}
|
||||
if (dyn->insts[ninst].x64.jmp && dyn->insts[ninst].x64.jmp_insts == -1)
|
||||
length += sprintf(buf + length, ", jmp=out");
|
||||
if (dyn->insts[ninst].x64.has_callret)
|
||||
length += sprintf(buf + length, ", callret");
|
||||
if (dyn->last_ip) {
|
||||
length += sprintf(buf + length, ", last_ip=%p", (void*)dyn->last_ip);
|
||||
}
|
||||
for (int ii = 0; ii < 32; ++ii) {
|
||||
switch (dyn->insts[ninst].n.neoncache[ii].t) {
|
||||
case NEON_CACHE_ST_D: length += sprintf(buf + length, " D%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
|
||||
case NEON_CACHE_ST_F: length += sprintf(buf + length, " S%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
|
||||
case NEON_CACHE_ST_I64: length += sprintf(buf + length, " D%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
|
||||
case NEON_CACHE_MM: length += sprintf(buf + length, " D%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
|
||||
case NEON_CACHE_XMMW: length += sprintf(buf + length, " Q%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
|
||||
case NEON_CACHE_XMMR: length += sprintf(buf + length, " Q%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
|
||||
case NEON_CACHE_YMMW: length += sprintf(buf + length, " Q%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
|
||||
case NEON_CACHE_YMMR: length += sprintf(buf + length, " Q%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
|
||||
// case NEON_CACHE_SCR: length += sprintf(buf + length, " D%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
|
||||
case NEON_CACHE_NONE:
|
||||
default: break;
|
||||
}
|
||||
if(dyn->insts[ninst].use_nat_flags || dyn->insts[ninst].set_nat_flags || dyn->insts[ninst].need_nat_flags)
|
||||
printf_log(LOG_NONE, " nf:%hhx/%hhx/%hhx", dyn->insts[ninst].set_nat_flags, dyn->insts[ninst].use_nat_flags, dyn->insts[ninst].need_nat_flags);
|
||||
if(dyn->insts[ninst].invert_carry)
|
||||
printf_log(LOG_NONE, " CI");
|
||||
if(dyn->insts[ninst].gen_inverted_carry)
|
||||
printf_log(LOG_NONE, " gic");
|
||||
if(dyn->insts[ninst].before_nat_flags&NF_CF)
|
||||
printf_log(LOG_NONE, " %ccb", dyn->insts[ninst].normal_carry_before?'n':'i');
|
||||
if(dyn->insts[ninst].need_nat_flags&NF_CF)
|
||||
printf_log(LOG_NONE, " %cc", dyn->insts[ninst].normal_carry?'n':'i');
|
||||
if(dyn->insts[ninst].pred_sz) {
|
||||
dynarec_log(LOG_NONE, ", pred=");
|
||||
for(int ii=0; ii<dyn->insts[ninst].pred_sz; ++ii)
|
||||
dynarec_log(LOG_NONE, "%s%d", ii?"/":"", dyn->insts[ninst].pred[ii]);
|
||||
}
|
||||
if(!dyn->insts[ninst].x64.alive)
|
||||
dynarec_log(LOG_NONE, " not executed");
|
||||
if(dyn->insts[ninst].x64.jmp && dyn->insts[ninst].x64.jmp_insts>=0)
|
||||
dynarec_log(LOG_NONE, ", jmp=%d", dyn->insts[ninst].x64.jmp_insts);
|
||||
if(dyn->insts[ninst].x64.jmp && dyn->insts[ninst].x64.jmp_insts==-1)
|
||||
dynarec_log(LOG_NONE, ", jmp=out");
|
||||
if(dyn->insts[ninst].x64.has_callret)
|
||||
dynarec_log(LOG_NONE, ", callret");
|
||||
if(dyn->last_ip)
|
||||
dynarec_log(LOG_NONE, ", last_ip=%p", (void*)dyn->last_ip);
|
||||
for(int ii=0; ii<32; ++ii) {
|
||||
switch(dyn->insts[ninst].n.neoncache[ii].t) {
|
||||
case NEON_CACHE_ST_D: dynarec_log(LOG_NONE, " D%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
|
||||
case NEON_CACHE_ST_F: dynarec_log(LOG_NONE, " S%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
|
||||
case NEON_CACHE_ST_I64: dynarec_log(LOG_NONE, " D%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
|
||||
case NEON_CACHE_MM: dynarec_log(LOG_NONE, " D%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
|
||||
case NEON_CACHE_XMMW: dynarec_log(LOG_NONE, " Q%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
|
||||
case NEON_CACHE_XMMR: dynarec_log(LOG_NONE, " Q%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
|
||||
case NEON_CACHE_YMMW: dynarec_log(LOG_NONE, " Q%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
|
||||
case NEON_CACHE_YMMR: dynarec_log(LOG_NONE, " Q%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
|
||||
//case NEON_CACHE_SCR: dynarec_log(LOG_NONE, " D%d:%s", ii, getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n)); break;
|
||||
case NEON_CACHE_NONE:
|
||||
default: break;
|
||||
}
|
||||
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" : "");
|
||||
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" : "");
|
||||
}
|
||||
if (dyn->insts[ninst].n.ymm_used) {
|
||||
length += sprintf(buf + length, " ymmUsed=%04x", dyn->insts[ninst].n.ymm_used);
|
||||
}
|
||||
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);
|
||||
}
|
||||
if (dyn->insts[ninst].purge_ymm) {
|
||||
length += sprintf(buf + length, " purgeYmm=%04x", dyn->insts[ninst].purge_ymm);
|
||||
}
|
||||
if (dyn->n.stack || dyn->insts[ninst].n.stack_next || dyn->insts[ninst].n.x87stack) {
|
||||
length += sprintf(buf + length, " X87:%d/%d(+%d/-%d)%d", dyn->n.stack, dyn->insts[ninst].n.stack_next, dyn->insts[ninst].n.stack_push, dyn->insts[ninst].n.stack_pop, dyn->insts[ninst].n.x87stack);
|
||||
}
|
||||
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)) {
|
||||
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" : "");
|
||||
}
|
||||
if (BOX64ENV(dynarec_gdbjit)) {
|
||||
static char buf2[512];
|
||||
if (BOX64ENV(dynarec_gdbjit) > 1) {
|
||||
sprintf(buf2, "; %d: %d opcodes, %s", ninst, dyn->insts[ninst].size / 4, buf);
|
||||
dyn->gdbjit_block = GdbJITBlockAddLine(dyn->gdbjit_block, (dyn->native_start + dyn->insts[ninst].address), buf2);
|
||||
}
|
||||
if(memcmp(dyn->insts[ninst].n.neoncache, dyn->n.neoncache, sizeof(dyn->n.neoncache))) {
|
||||
dynarec_log(LOG_NONE, " %s(Change:", (box64_dynarec_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) {
|
||||
dynarec_log(LOG_NONE, " V%d:%s", ii, getCacheName(dyn->n.neoncache[ii].t, dyn->n.neoncache[ii].n));
|
||||
dynarec_log(LOG_NONE, "->%s", getCacheName(dyn->insts[ninst].n.neoncache[ii].t, dyn->insts[ninst].n.neoncache[ii].n));
|
||||
}
|
||||
dynarec_log(LOG_NONE, ")%s", (box64_dynarec_dump>1)?"\e[0;32m":"");
|
||||
zydis_dec_t* dec = rex.is32bits ? my_context->dec32 : my_context->dec;
|
||||
const char* inst_name = name;
|
||||
if (dec) {
|
||||
inst_name = DecodeX64Trace(dec, dyn->insts[ninst].x64.addr, 0);
|
||||
x64disas_add_register_mapping_annotations(buf2, inst_name, register_mappings, sizeof(register_mappings) / sizeof(register_mappings[0]));
|
||||
inst_name = buf2;
|
||||
}
|
||||
if(dyn->insts[ninst].n.ymm_used)
|
||||
dynarec_log(LOG_NONE, " ymmUsed=%04x", dyn->insts[ninst].n.ymm_used);
|
||||
if(dyn->ymm_zero || dyn->insts[ninst].ymm0_add || dyn->insts[ninst].ymm0_sub || dyn->insts[ninst].ymm0_out)
|
||||
dynarec_log(LOG_NONE, " 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);
|
||||
if(dyn->insts[ninst].purge_ymm)
|
||||
dynarec_log(LOG_NONE, " purgeYmm=%04x", dyn->insts[ninst].purge_ymm);
|
||||
if(dyn->n.stack || dyn->insts[ninst].n.stack_next || dyn->insts[ninst].n.x87stack)
|
||||
dynarec_log(LOG_NONE, " X87:%d/%d(+%d/-%d)%d", dyn->n.stack, dyn->insts[ninst].n.stack_next, dyn->insts[ninst].n.stack_push, dyn->insts[ninst].n.stack_pop, dyn->insts[ninst].n.x87stack);
|
||||
if(dyn->insts[ninst].n.combined1 || dyn->insts[ninst].n.combined2)
|
||||
dynarec_log(LOG_NONE, " %s:%d/%d", dyn->insts[ninst].n.swapped?"SWP":"CMB", dyn->insts[ninst].n.combined1, dyn->insts[ninst].n.combined2);
|
||||
dynarec_log(LOG_NONE, "%s\n", (box64_dynarec_dump>1)?"\e[m":"");
|
||||
dyn->gdbjit_block = GdbJITBlockAddLine(dyn->gdbjit_block, (dyn->native_start + dyn->insts[ninst].address), inst_name);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void print_opcode(dynarec_native_t* dyn, int ninst, uint32_t opcode)
|
||||
{
|
||||
dynarec_log(LOG_NONE, "\t%08x\t%s\n", opcode, arm64_print(opcode, (uintptr_t)dyn->block));
|
||||
dynarec_log_prefix(0, LOG_NONE, "\t%08x\t%s\n", opcode, arm64_print(opcode, (uintptr_t)dyn->block));
|
||||
}
|
||||
|
||||
static void x87_reset(neoncache_t* n)
|
||||
@@ -822,9 +926,9 @@ uint8_t mark_natflag(dynarec_arm_t* dyn, int ninst, uint8_t flag, int before)
|
||||
{
|
||||
if(dyn->insts[ninst].x64.set_flags && !before) {
|
||||
dyn->insts[ninst].set_nat_flags |= flag;
|
||||
if(dyn->insts[ninst].x64.use_flags) {
|
||||
dyn->insts[ninst].use_nat_flags |= flag;
|
||||
}
|
||||
//if(dyn->insts[ninst].x64.use_flags) {
|
||||
// dyn->insts[ninst].use_nat_flags |= flag;
|
||||
//}
|
||||
} else {
|
||||
if(before)
|
||||
dyn->insts[ninst].use_nat_flags_before |= flag;
|
||||
@@ -861,39 +965,52 @@ static uint8_t getNativeFlagsUsed(dynarec_arm_t* dyn, int start, uint8_t flags)
|
||||
int nat_flags_used = 0;
|
||||
int ninst = start;
|
||||
while(ninst<dyn->size) {
|
||||
//printf_log(LOG_INFO, "getNativeFlagsUsed ninst:%d/%d, flags=%x, used_flags=%x(%d), nat_flags_op_before:%x, nat_flags_op:%x, need_after:%x\n", ninst, start, flags, used_flags, nat_flags_used, dyn->insts[ninst].nat_flags_op_before, dyn->insts[ninst].nat_flags_op, flag2native(dyn->insts[ninst].x64.need_after));
|
||||
//printf_log(LOG_INFO, "getNativeFlagsUsed ninst:%d/%d, flags=%x, used_flags=%x(%d), nat_flags_op_before:%x, nat_flags_op:%x, need_after:%x set_nat_flags:%x nat_flags_used:%x(%x)\n", ninst, start, flags, used_flags, nat_flags_used, dyn->insts[ninst].nat_flags_op_before, dyn->insts[ninst].nat_flags_op, flag2native(dyn->insts[ninst].x64.need_after),dyn->insts[ninst].set_nat_flags, dyn->insts[ninst].use_nat_flags, dyn->insts[ninst].use_nat_flags_before);
|
||||
// check if this is an opcode that generate flags but consume flags before
|
||||
if(dyn->insts[ninst].nat_flags_op_before)
|
||||
return 0;
|
||||
// check if nat flags are used "before"
|
||||
if(dyn->insts[ninst].use_nat_flags_before)
|
||||
if(dyn->insts[ninst].use_nat_flags_before) {
|
||||
// check if the gen flags are compatible
|
||||
if(dyn->insts[ninst].use_nat_flags_before&~flags)
|
||||
return 0;
|
||||
nat_flags_used = 1;
|
||||
if(dyn->insts[ninst].nat_flags_op==NAT_FLAG_OP_TOUCH && dyn->insts[ninst].use_nat_flags_before)
|
||||
used_flags|=dyn->insts[ninst].use_nat_flags_before&flags;
|
||||
}
|
||||
// if the opcode generate flags, return
|
||||
if(dyn->insts[ninst].nat_flags_op==NAT_FLAG_OP_TOUCH && (start!=ninst)) {
|
||||
if(!nat_flags_used)
|
||||
return 0;
|
||||
if(used_flags&~dyn->insts[ninst].set_nat_flags) {
|
||||
// check partial changes that would destroy flag state
|
||||
if(dyn->insts[ninst].use_nat_flags_before&flags)
|
||||
return nat_flags_used?used_flags:0;
|
||||
// but also check if there is before needed
|
||||
return used_flags;
|
||||
// check if flags are all refreshed, then it's ok
|
||||
if((used_flags&dyn->insts[ninst].set_nat_flags)==used_flags)
|
||||
return used_flags;
|
||||
// incompatible
|
||||
return 0;
|
||||
}
|
||||
return nat_flags_used?used_flags:0;
|
||||
return used_flags;
|
||||
}
|
||||
// check if there is a callret barrier
|
||||
if(dyn->insts[ninst].x64.has_callret)
|
||||
return 0;
|
||||
// check if nat flags are used
|
||||
if(dyn->insts[ninst].use_nat_flags)
|
||||
if(dyn->insts[ninst].use_nat_flags) {
|
||||
// check if the gen flags are compatible
|
||||
if(dyn->insts[ninst].use_nat_flags&~flags)
|
||||
return 0;
|
||||
nat_flags_used = 1;
|
||||
// check if flags are used, but not the natives ones
|
||||
used_flags |= dyn->insts[ninst].use_nat_flags&flags;
|
||||
}
|
||||
if(ninst!=start && dyn->insts[ninst].x64.use_flags) {
|
||||
if((flag2native(dyn->insts[ninst].x64.use_flags)&~(dyn->insts[ninst].use_nat_flags))&used_flags)
|
||||
return 0;
|
||||
// also check if the gen flags are compatible
|
||||
if((dyn->insts[ninst].use_nat_flags)&~flags)
|
||||
// some flags not compatible with native, partial use not allowed
|
||||
if(flag2native(dyn->insts[ninst].x64.use_flags)!=dyn->insts[ninst].use_nat_flags)
|
||||
return 0;
|
||||
// check if flags are used, but not the natives ones
|
||||
//if(dyn->insts[ninst].use_nat_flags&~used_flags)
|
||||
// return 0;
|
||||
}
|
||||
// check if flags are generated without native option
|
||||
if((start!=ninst) && dyn->insts[ninst].x64.gen_flags && (flag2native(dyn->insts[ninst].x64.gen_flags&dyn->insts[ninst].x64.need_after)&used_flags)) {
|
||||
@@ -909,7 +1026,8 @@ static uint8_t getNativeFlagsUsed(dynarec_arm_t* dyn, int start, uint8_t flags)
|
||||
if(dyn->insts[ninst].nat_flags_op && (start!=ninst))
|
||||
return 0;
|
||||
// update used flags
|
||||
used_flags |= (flag2native(dyn->insts[ninst].x64.need_after)&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
|
||||
@@ -933,7 +1051,7 @@ static void propagateNativeFlags(dynarec_arm_t* dyn, int start)
|
||||
//printf_log(LOG_INFO, "propagateNativeFlags called for start=%d, flags=%x, will need:%x\n", start, flags, flag2native(dyn->insts[ninst].x64.need_after));
|
||||
if(!flags) return;
|
||||
// also check if some native flags are used but not genereated here
|
||||
if(flag2native(dyn->insts[ninst].x64.need_after)&~flags) return;
|
||||
if(flag2native(dyn->insts[ninst].x64.use_flags)&~flags) return;
|
||||
uint8_t used_flags = getNativeFlagsUsed(dyn, start, flags);
|
||||
//printf_log(LOG_INFO, " will use:%x, carry:%d, generate inverted carry:%d\n", used_flags, used_flags&NF_CF, dyn->insts[ninst].gen_inverted_carry);
|
||||
if(!used_flags) return; // the flags wont be used, so just cancel
|
||||
@@ -978,9 +1096,9 @@ static void propagateNativeFlags(dynarec_arm_t* dyn, int start)
|
||||
|
||||
void updateNativeFlags(dynarec_native_t* dyn)
|
||||
{
|
||||
if(!box64_dynarec_nativeflags)
|
||||
if(!BOX64ENV(dynarec_nativeflags))
|
||||
return;
|
||||
// backward check if native flags are used
|
||||
// forward check if native flags are used
|
||||
for(int ninst=0; ninst<dyn->size; ++ninst)
|
||||
if(flag2native(dyn->insts[ninst].x64.gen_flags) && (dyn->insts[ninst].nat_flags_op==NAT_FLAG_OP_TOUCH)) {
|
||||
propagateNativeFlags(dyn, ninst);
|
||||
@@ -1020,3 +1138,13 @@ int nativeFlagsNeedsTransform(dynarec_arm_t* dyn, int ninst)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void fpu_save_and_unwind(dynarec_arm_t* dyn, int ninst, neoncache_t* cache)
|
||||
{
|
||||
memcpy(cache, &dyn->insts[ninst].n, sizeof(neoncache_t));
|
||||
neoncacheUnwind(&dyn->insts[ninst].n);
|
||||
}
|
||||
void fpu_unwind_restore(dynarec_arm_t* dyn, int ninst, neoncache_t* cache)
|
||||
{
|
||||
memcpy(&dyn->insts[ninst].n, cache, sizeof(neoncache_t));
|
||||
}
|
||||
@@ -67,6 +67,9 @@ int fpuCacheNeedsTransform(dynarec_arm_t* dyn, int ninst);
|
||||
|
||||
// Undo the changes of a neoncache to get the status before the instruction
|
||||
void neoncacheUnwind(neoncache_t* cache);
|
||||
void fpu_save_and_unwind(dynarec_arm_t* dyn, int ninst, neoncache_t* cache);
|
||||
void fpu_unwind_restore(dynarec_arm_t* dyn, int ninst, neoncache_t* cache);
|
||||
|
||||
|
||||
// Get if ED will have the correct parity. Not emitting anything. Parity is 2 for DWORD or 3 for QWORD
|
||||
int getedparity(dynarec_native_t* dyn, int ninst, uintptr_t addr, uint8_t nextop, int parity, int delta);
|
||||
|
||||
@@ -580,7 +580,7 @@ void jump_to_next(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst, int is32
|
||||
NOTEST(x2);
|
||||
uintptr_t tbl = is32bits?getJumpTable32():getJumpTable64();
|
||||
MAYUSE(tbl);
|
||||
TABLE64(x3, tbl);
|
||||
MOV64x(x3, tbl);
|
||||
if(!is32bits) {
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
UBFXx(x2, xRIP, JMPTABL_START4, JMPTABL_SHIFT4);
|
||||
@@ -599,7 +599,7 @@ void jump_to_next(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst, int is32
|
||||
NOTEST(x2);
|
||||
uintptr_t p = getJumpTableAddress64(ip);
|
||||
MAYUSE(p);
|
||||
TABLE64(x3, p);
|
||||
MOV64x(x3, p);
|
||||
GETIP_(ip);
|
||||
LDRx_U12(x2, x3, 0);
|
||||
}
|
||||
@@ -626,7 +626,7 @@ void ret_to_epilog(dynarec_arm_t* dyn, int ninst, rex_t rex)
|
||||
POP1z(xRIP);
|
||||
MOVz_REG(x1, xRIP);
|
||||
SMEND();
|
||||
if(box64_dynarec_callret) {
|
||||
if(BOX64DRENV(dynarec_callret)) {
|
||||
// pop the actual return address for ARM stack
|
||||
LDPx_S7_postindex(xLR, x6, xSP, 16);
|
||||
SUBx_REG(x6, x6, xRIP); // is it the right address?
|
||||
@@ -673,7 +673,7 @@ void retn_to_epilog(dynarec_arm_t* dyn, int ninst, rex_t rex, int n)
|
||||
}
|
||||
MOVz_REG(x1, xRIP);
|
||||
SMEND();
|
||||
if(box64_dynarec_callret) {
|
||||
if(BOX64DRENV(dynarec_callret)) {
|
||||
// pop the actual return address for ARM stack
|
||||
LDPx_S7_postindex(xLR, x6, xSP, 16);
|
||||
SUBx_REG(x6, x6, xRIP); // is it the right address?
|
||||
@@ -715,7 +715,7 @@ void iret_to_epilog(dynarec_arm_t* dyn, int ninst, int is32bits, int is64bits)
|
||||
MAYUSE(j64);
|
||||
MESSAGE(LOG_DUMP, "IRet to epilog\n");
|
||||
SMEND();
|
||||
SET_DFNONE(x2);
|
||||
SET_DFNONE();
|
||||
// POP IP
|
||||
NOTEST(x2);
|
||||
if(is64bits) {
|
||||
@@ -734,7 +734,7 @@ void iret_to_epilog(dynarec_arm_t* dyn, int ninst, int is32bits, int is64bits)
|
||||
MOV32w(x1, 0x3F7FD7);
|
||||
ANDx_REG(xFlags, xFlags, x1);
|
||||
ORRx_mask(xFlags, xFlags, 1, 0b111111, 0); // xFlags | 0b10
|
||||
SET_DFNONE(x1);
|
||||
SET_DFNONE();
|
||||
if(is32bits) {
|
||||
ANDw_mask(x2, x2, 0, 7); // mask 0xff
|
||||
// check if return segment is 64bits, then restore rsp too
|
||||
@@ -809,6 +809,42 @@ void call_c(dynarec_arm_t* dyn, int ninst, void* fnc, int reg, int ret, int save
|
||||
//SET_NODF();
|
||||
}
|
||||
|
||||
void call_i(dynarec_arm_t* dyn, int ninst, void* fnc)
|
||||
{
|
||||
MAYUSE(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(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
|
||||
STPx_S7_offset(xRAX, xRCX, xEmu, offsetof(x64emu_t, regs[_AX])); // x9..x15, x16,x17,x18 those needs to be saved by caller
|
||||
STPx_S7_offset(xRDX, xRBX, xEmu, offsetof(x64emu_t, regs[_DX]));
|
||||
STPx_S7_offset(xRSP, xRBP, xEmu, offsetof(x64emu_t, regs[_SP]));
|
||||
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);
|
||||
|
||||
TABLE64(x7, (uintptr_t)fnc);
|
||||
BLR(x7);
|
||||
LDPx_S7_postindex(xEmu, x1, xSP, 16);
|
||||
LDPx_S7_postindex(x2, x3, xSP, 16);
|
||||
LDPx_S7_postindex(x4, x5, xSP, 16);
|
||||
#define GO(A, B) LDPx_S7_offset(x##A, x##B, xEmu, offsetof(x64emu_t, regs[_##A]))
|
||||
GO(RAX, RCX);
|
||||
GO(RDX, RBX);
|
||||
GO(RSP, RBP);
|
||||
GO(RSI, RDI);
|
||||
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);
|
||||
//SET_NODF();
|
||||
}
|
||||
|
||||
void call_n(dynarec_arm_t* dyn, int ninst, void* fnc, int w)
|
||||
{
|
||||
MAYUSE(fnc);
|
||||
@@ -858,19 +894,20 @@ void call_n(dynarec_arm_t* dyn, int ninst, void* fnc, int w)
|
||||
//SET_NODF();
|
||||
}
|
||||
|
||||
void grab_segdata(dynarec_arm_t* dyn, uintptr_t addr, int ninst, int reg, int segment)
|
||||
void grab_segdata(dynarec_arm_t* dyn, uintptr_t addr, int ninst, int reg, int segment, int modreg)
|
||||
{
|
||||
(void)addr;
|
||||
int64_t j64;
|
||||
MAYUSE(j64);
|
||||
if (modreg) return;
|
||||
MESSAGE(LOG_DUMP, "Get %s Offset\n", (segment==_FS)?"FS":"GS");
|
||||
int t2 = x4;
|
||||
if(reg==t2) ++t2;
|
||||
LDRw_U12(t2, xEmu, offsetof(x64emu_t, segs_serial[segment]));
|
||||
if(segment==_GS) {
|
||||
/*if(segment==_GS) {
|
||||
LDRx_U12(reg, xEmu, offsetof(x64emu_t, segs_offs[segment]));
|
||||
CBNZw_MARKSEG(t2); // fast check
|
||||
} else {
|
||||
} else*/ {
|
||||
LDRx_U12(reg, xEmu, offsetof(x64emu_t, context));
|
||||
LDRw_U12(reg, reg, offsetof(box64context_t, sel_serial));
|
||||
SUBw_REG(t2, reg, t2);
|
||||
@@ -1188,7 +1225,41 @@ void x87_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1, int s2, int
|
||||
}
|
||||
MESSAGE(LOG_DUMP, "\t---Purge x87 Cache and Synch Stackcount\n");
|
||||
}
|
||||
|
||||
void x87_reflectcount(dynarec_arm_t* dyn, int ninst, int s1, int s2)
|
||||
{
|
||||
// Synch top & stack counter
|
||||
int a = dyn->n.x87stack;
|
||||
if(a) {
|
||||
MESSAGE(LOG_DUMP, "\tSync x87 Count of %d-----\n", a);
|
||||
// Add x87stack to emu fpu_stack
|
||||
LDRw_U12(s2, xEmu, offsetof(x64emu_t, fpu_stack));
|
||||
if(a>0) {
|
||||
ADDw_U12(s2, s2, a);
|
||||
} else {
|
||||
SUBw_U12(s2, s2, -a);
|
||||
}
|
||||
STRw_U12(s2, xEmu, offsetof(x64emu_t, fpu_stack));
|
||||
// Sub x87stack to top, with and 7
|
||||
LDRw_U12(s2, xEmu, offsetof(x64emu_t, top));
|
||||
if(a>0) {
|
||||
SUBw_U12(s2, s2, a);
|
||||
} else {
|
||||
ADDw_U12(s2, s2, -a);
|
||||
}
|
||||
ANDw_mask(s2, s2, 0, 2); //mask=7
|
||||
STRw_U12(s2, xEmu, offsetof(x64emu_t, top));
|
||||
// update tags
|
||||
LDRH_U12(s1, xEmu, offsetof(x64emu_t, fpu_tags));
|
||||
if(a>0) {
|
||||
LSLw_IMM(s1, s1, a*2);
|
||||
} else {
|
||||
ORRw_mask(s1, s1, 0b010000, 0b001111); // 0xffff0000
|
||||
LSRw_IMM(s1, s1, -a*2);
|
||||
}
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, fpu_tags));
|
||||
MESSAGE(LOG_DUMP, "\t-----Sync x87 Count\n");
|
||||
}
|
||||
}
|
||||
static void x87_reflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
{
|
||||
// Synch top & stack counter
|
||||
@@ -1248,7 +1319,7 @@ static void x87_reflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int
|
||||
}
|
||||
}
|
||||
|
||||
static void x87_unreflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
void x87_unreflectcount(dynarec_arm_t* dyn, int ninst, int s1, int s2)
|
||||
{
|
||||
// go back with the top & stack counter
|
||||
int a = dyn->n.x87stack;
|
||||
@@ -2217,7 +2288,7 @@ static void fpuCacheTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2, int
|
||||
neoncache_t cache = dyn->n;
|
||||
int s1_val = 0;
|
||||
int s2_val = 0;
|
||||
// unload every uneeded cache
|
||||
// unload every unneeded cache
|
||||
// ymm0 first
|
||||
int s3_top = 1;
|
||||
uint16_t to_purge = dyn->ymm_zero&~dyn->insts[i2].ymm0_in;
|
||||
@@ -2233,7 +2304,7 @@ static void fpuCacheTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2, int
|
||||
}
|
||||
}
|
||||
s3_top = 0xffff;
|
||||
// check SSE first, than MMX, in order, to optimise successive memory write
|
||||
// check SSE first, than MMX, in order, to optimize successive memory write
|
||||
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)
|
||||
@@ -2504,7 +2575,7 @@ void fpu_reflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
void fpu_unreflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
{
|
||||
// need to undo some things on the x87 tracking
|
||||
x87_unreflectcache(dyn, ninst, s1, s2, s3);
|
||||
x87_unreflectcount(dyn, ninst, s1, s2);
|
||||
}
|
||||
|
||||
void emit_pf(dynarec_arm_t* dyn, int ninst, int s1, int s4)
|
||||
@@ -2609,10 +2680,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(box64_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(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);
|
||||
#endif
|
||||
#if defined(HAVE_TRACE) && (STEP>2)
|
||||
if(box64_dynarec_dump && 0) //disable for now, need more work
|
||||
if(BOX64DRENV(dynarec_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)
|
||||
|
||||
@@ -74,17 +74,18 @@
|
||||
LDz(x1, wback, fixedaddress); \
|
||||
ed = x1; \
|
||||
}
|
||||
#define GETEDw(D) if((nextop&0xC0)==0xC0) { \
|
||||
ed = xEAX+(nextop&7)+(rex.b<<3); \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL,0, D); \
|
||||
LDW(x1, wback, fixedaddress); \
|
||||
ed = x1; \
|
||||
}
|
||||
#define GETEDw(D) \
|
||||
if (MODREG) { \
|
||||
ed = xEAX + (nextop & 7) + (rex.b << 3); \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff << 2, 3, rex, NULL, 0, D); \
|
||||
LDW(x1, wback, fixedaddress); \
|
||||
ed = x1; \
|
||||
}
|
||||
#define GETSEDw(D) \
|
||||
if ((nextop & 0xC0) == 0xC0) { \
|
||||
if (MODREG) { \
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3)); \
|
||||
SXTWx(x1, ed); \
|
||||
wb = x1; \
|
||||
@@ -106,7 +107,7 @@
|
||||
ed = x1; \
|
||||
}
|
||||
#define GETSED32w(D) \
|
||||
if ((nextop & 0xC0) == 0xC0) { \
|
||||
if (MODREG) { \
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3)); \
|
||||
SXTWx(x1, ed); \
|
||||
wb = x1; \
|
||||
@@ -175,13 +176,10 @@
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, NULL, 0, D); \
|
||||
if (rex.is32bits) \
|
||||
LDRxw_REG_SXTW(x1, O, wback); \
|
||||
else \
|
||||
LDRxw_REG(x1, wback, O); \
|
||||
LDRxw_REGz(x1, O, wback); \
|
||||
ed = x1; \
|
||||
}
|
||||
#define WBACKO(O) if(wback) {if(rex.is32bits) STRxw_REG_SXTW(ed, O, wback); else STRxw_REG(ed, wback, O); SMWRITE2();}
|
||||
#define WBACKO(O) if(wback) {STRxw_REGz(ed, O, wback); SMWRITE2();}
|
||||
//GETEDOx can use r1 for ed, and r2 for wback. wback is 0 if ed is xEAX..xEDI
|
||||
#define GETEDOx(O, D) \
|
||||
if (MODREG) { \
|
||||
@@ -190,10 +188,7 @@
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, NULL, 0, D); \
|
||||
if (rex.is32bits) \
|
||||
LDRx_REG_SXTW(x1, O, wback); \
|
||||
else \
|
||||
LDRx_REG(x1, wback, O); \
|
||||
LDRx_REGz(x1, O, wback); \
|
||||
ed = x1; \
|
||||
}
|
||||
//GETEDOz can use r1 for ed, and r2 for wback. wback is 0 if ed is xEAX..xEDI
|
||||
@@ -204,14 +199,11 @@
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, NULL, 0, D); \
|
||||
if (rex.is32bits) \
|
||||
LDRz_REG_SXTW(x1, O, wback); \
|
||||
else \
|
||||
LDRz_REG(x1, wback, O); \
|
||||
LDRz_REGz(x1, O, wback); \
|
||||
ed = x1; \
|
||||
}
|
||||
#define GETSEDOw(O, D) \
|
||||
if ((nextop & 0xC0) == 0xC0) { \
|
||||
if (MODREG) { \
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3)); \
|
||||
SXTWx(x1, ed); \
|
||||
wb = x1; \
|
||||
@@ -219,10 +211,7 @@
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, NULL, 0, D); \
|
||||
if (rex.is32bits) \
|
||||
LDRSW_REG_SXTW(x1, O, wback); \
|
||||
else \
|
||||
LDRSW_REG(x1, wback, O); \
|
||||
LDRSW_REGz(x1, O, wback); \
|
||||
wb = ed = x1; \
|
||||
}
|
||||
//FAKEELike GETED, but doesn't get anything
|
||||
@@ -257,6 +246,9 @@
|
||||
ed = i; \
|
||||
wb1 = 1; \
|
||||
}
|
||||
//Compute wback for MDREG only, no fetching
|
||||
#define CALCEW() \
|
||||
wback = TO_NAT((nextop & 7) + (rex.b << 3)); \
|
||||
//GETEW will use i for ed, and can use r3 for wback.
|
||||
#define GETEW(i, D) \
|
||||
if (MODREG) { \
|
||||
@@ -321,6 +313,16 @@
|
||||
#define EWBACKW(w) if(wb1) {STH(w, wback, fixedaddress); SMWRITE();} else {BFIx(wback, w, 0, 16);}
|
||||
// Write back gd in correct register
|
||||
#define GWBACK BFIx(TO_NAT(((nextop & 0x38) >> 3) + (rex.r << 3)), gd, 0, 16);
|
||||
// no fetch version of GETEB for MODREG path only
|
||||
#define CALCEB() \
|
||||
if (rex.rex) { \
|
||||
wback = TO_NAT((nextop & 7) + (rex.b << 3)); \
|
||||
wb2 = 0; \
|
||||
} else { \
|
||||
wback = (nextop & 7); \
|
||||
wb2 = (wback >> 2) * 8; \
|
||||
wback = TO_NAT(wback & 3); \
|
||||
} \
|
||||
//GETEB will use i for ed, and can use r3 for wback.
|
||||
#define GETEB(i, D) \
|
||||
if (MODREG) { \
|
||||
@@ -409,6 +411,16 @@
|
||||
}
|
||||
// Write eb (ed) back to original register / memory
|
||||
#define EBBACK if(wb1) {STB(ed, wback, fixedaddress); SMWRITE();} else {BFIx(wback, ed, wb2, 8);}
|
||||
// no fetch version of GETGB
|
||||
#define CALCGB() \
|
||||
if (rex.rex) { \
|
||||
gb1 = TO_NAT(((nextop & 0x38) >> 3) + (rex.r << 3)); \
|
||||
gb2 = 0; \
|
||||
} else { \
|
||||
gd = (nextop & 0x38) >> 3; \
|
||||
gb2 = ((gd & 4) << 1); \
|
||||
gb1 = TO_NAT(gd & 3); \
|
||||
} \
|
||||
//GETGB will use i for gd
|
||||
#define GETGB(i) \
|
||||
if (rex.rex) { \
|
||||
@@ -704,8 +716,8 @@
|
||||
TSTw_mask(xFlags, 0b010110, 0); \
|
||||
CNEGx(r, r, cNE)
|
||||
|
||||
#define ALIGNED_ATOMICxw ((fixedaddress && !(fixedaddress&(((1<<(2+rex.w))-1)))) || box64_dynarec_aligned_atomics)
|
||||
#define ALIGNED_ATOMICH ((fixedaddress && !(fixedaddress&1)) || box64_dynarec_aligned_atomics)
|
||||
#define ALIGNED_ATOMICxw ((fixedaddress && !(fixedaddress&(((1<<(2+rex.w))-1)))) || BOX64ENV(dynarec_aligned_atomics))
|
||||
#define ALIGNED_ATOMICH ((fixedaddress && !(fixedaddress&1)) || BOX64ENV(dynarec_aligned_atomics))
|
||||
|
||||
// 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
|
||||
@@ -716,6 +728,9 @@
|
||||
// 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)
|
||||
// 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)
|
||||
|
||||
#define MARK dyn->insts[ninst].mark = dyn->native_size
|
||||
#define GETMARK dyn->insts[ninst].mark
|
||||
@@ -784,6 +799,10 @@
|
||||
#define CBNZx_MARK2(reg) \
|
||||
j64 = GETMARK2-(dyn->native_size); \
|
||||
CBNZx(reg, j64)
|
||||
// Branch to MARK2 if reg is not 0 (use j64)
|
||||
#define CBNZw_MARK2(reg) \
|
||||
j64 = GETMARK2-(dyn->native_size); \
|
||||
CBNZw(reg, j64)
|
||||
#define CBNZxw_MARK2(reg) \
|
||||
j64 = GETMARK2-(dyn->native_size); \
|
||||
CBNZxw(reg, j64)
|
||||
@@ -879,6 +898,10 @@
|
||||
#define B_MARKLOCK(cond) \
|
||||
j64 = GETMARKLOCK-(dyn->native_size); \
|
||||
Bcond(cond, j64)
|
||||
// Branch to MARKLOCK unconditional (use j64)
|
||||
#define B_MARKLOCK_nocond \
|
||||
j64 = GETMARKLOCK-(dyn->native_size); \
|
||||
B(j64)
|
||||
// Branch to MARKLOCK if reg is not 0 (use j64)
|
||||
#define CBNZw_MARKLOCK(reg) \
|
||||
j64 = GETMARKLOCK-(dyn->native_size); \
|
||||
@@ -887,6 +910,10 @@
|
||||
#define CBNZx_MARKLOCK(reg) \
|
||||
j64 = GETMARKLOCK-(dyn->native_size); \
|
||||
CBNZx(reg, j64)
|
||||
// Branch to MARKLOCK if reg is 0 (use j64)
|
||||
#define CBZx_MARKLOCK(reg) \
|
||||
j64 = GETMARKLOCK-(dyn->native_size); \
|
||||
CBZx(reg, j64)
|
||||
|
||||
#ifndef IFNATIVE
|
||||
#define IFNATIVE(A) if(dyn->insts[ninst].need_nat_flags&(A))
|
||||
@@ -915,7 +942,7 @@
|
||||
#endif
|
||||
|
||||
// Generate FCOM with s1 and s2 scratch regs (the VCMP is already done)
|
||||
#define FCOM(s1, s2, s3, s4, v1, v2, is_f) \
|
||||
#define FCOM(s1, s2, s3) \
|
||||
LDRH_U12(s3, xEmu, offsetof(x64emu_t, sw)); /*offset is 8bits right?*/\
|
||||
MOV32w(s1, 0b0100011100000000); \
|
||||
BICw_REG(s3, s3, s1); \
|
||||
@@ -925,33 +952,11 @@
|
||||
CSELw(s1, s2, s1, cEQ); \
|
||||
MOV32w(s2, 0b01000101); /* unordered */ \
|
||||
CSELw(s1, s2, s1, cVS); \
|
||||
if(v1||v2) { \
|
||||
Bcond(cVS, 10*4); \
|
||||
if(is_f) { \
|
||||
ORRw_mask(s4, xZR, 12, 10); /*+inf*/ \
|
||||
FMOVwS(s2, v1); \
|
||||
CMPSw_REG(s2, s4); \
|
||||
Bcond(cEQ, 5*4); /* same */ \
|
||||
FMOVwS(s2, v2); \
|
||||
ORRw_mask(s4, s4, 1, 0); /*-inf*/ \
|
||||
CMPSw_REG(s2, s4); \
|
||||
} else { \
|
||||
ORRx_mask(s4, xZR, 1, 12, 10); /*+inf*/ \
|
||||
FMOVxD(s2, v1); \
|
||||
CMPSx_REG(s2, s4); \
|
||||
Bcond(cEQ, 5*4); /* same */ \
|
||||
FMOVxD(s2, v2); \
|
||||
ORRx_mask(s4, s4, 1, 1, 0); /*-inf*/ \
|
||||
CMPSx_REG(s2, s4); \
|
||||
} \
|
||||
Bcond(cNE, 4+4); /* same */ \
|
||||
MOVZw(s2, 0); \
|
||||
} \
|
||||
ORRw_REG_LSL(s3, s3, s1, 8); \
|
||||
STRH_U12(s3, xEmu, offsetof(x64emu_t, sw))
|
||||
|
||||
// Generate FCOMI with s1 and s2 scratch regs (the VCMP is already done)
|
||||
#define FCOMI(s1, s2, s4, v1, v2, is_f) \
|
||||
#define FCOMI(s1, s2) \
|
||||
IFX(X_OF|X_AF|X_SF|X_PEND) { \
|
||||
MOV32w(s2, 0b100011010101); \
|
||||
BICw_REG(xFlags, xFlags, s2); \
|
||||
@@ -971,32 +976,17 @@
|
||||
MOV32w(s2, 0b01000000); /* zero */ \
|
||||
CSELw(s1, s2, s1, cEQ); \
|
||||
/* greater than leave 0 */ \
|
||||
if(s4) { \
|
||||
Bcond(cVS, 10*4); \
|
||||
if(is_f) { \
|
||||
ORRw_mask(s4, xZR, 12, 10); /*+inf*/ \
|
||||
FMOVwS(s2, v1); \
|
||||
CMPSw_REG(s2, s4); \
|
||||
Bcond(cEQ, 5*4); /* same */ \
|
||||
FMOVwS(s2, v2); \
|
||||
ORRw_mask(s4, s4, 1, 0); /*-inf*/ \
|
||||
CMPSw_REG(s2, s4); \
|
||||
} else { \
|
||||
ORRx_mask(s4, xZR, 1, 12, 10); /*+inf*/ \
|
||||
FMOVxD(s2, v1); \
|
||||
CMPSx_REG(s2, s4); \
|
||||
Bcond(cEQ, 5*4); /* same */ \
|
||||
FMOVxD(s2, v2); \
|
||||
ORRx_mask(s4, s4, 1, 1, 0); /*-inf*/ \
|
||||
CMPSx_REG(s2, s4); \
|
||||
} \
|
||||
Bcond(cNE, 4+4); /* same */ \
|
||||
MOVZw(s1, 0); \
|
||||
} \
|
||||
ORRw_REG(xFlags, xFlags, s1); \
|
||||
} \
|
||||
SET_DFNONE(s1); \
|
||||
SET_DFNONE(); \
|
||||
|
||||
#ifndef IF_UNALIGNED
|
||||
#define IF_UNALIGNED(A) if(is_addr_unaligned(A))
|
||||
#endif
|
||||
|
||||
#ifndef IF_ALIGNED
|
||||
#define IF_ALIGNED(A) if (!is_addr_unaligned(A))
|
||||
#endif
|
||||
|
||||
#define STORE_REG(A) STRx_U12(x##A, xEmu, offsetof(x64emu_t, regs[_##A]))
|
||||
#define STP_REGS(A, B) STPx_S7_offset(x##A, x##B, xEmu, offsetof(x64emu_t, regs[_##A]))
|
||||
@@ -1075,7 +1065,7 @@
|
||||
#else
|
||||
#define X87_PUSH_OR_FAIL(var, dyn, ninst, scratch, t) \
|
||||
if ((dyn->n.x87stack==8) || (dyn->n.pushed==8)) { \
|
||||
if(box64_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(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); \
|
||||
dyn->abort = 1; \
|
||||
return addr; \
|
||||
} \
|
||||
@@ -1083,7 +1073,7 @@
|
||||
|
||||
#define X87_PUSH_EMPTY_OR_FAIL(dyn, ninst, scratch) \
|
||||
if ((dyn->n.x87stack==8) || (dyn->n.pushed==8)) { \
|
||||
if(box64_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(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); \
|
||||
dyn->abort = 1; \
|
||||
return addr; \
|
||||
} \
|
||||
@@ -1091,34 +1081,42 @@
|
||||
|
||||
#define X87_POP_OR_FAIL(dyn, ninst, scratch) \
|
||||
if ((dyn->n.x87stack==-8) || (dyn->n.poped==8)) { \
|
||||
if(box64_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(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); \
|
||||
dyn->abort = 1; \
|
||||
return addr; \
|
||||
} \
|
||||
x87_do_pop(dyn, ninst, scratch)
|
||||
#endif
|
||||
|
||||
#define SET_DFNONE(S) do {dyn->f.dfnone_here=1; if(!dyn->f.dfnone) {STRw_U12(wZR, xEmu, offsetof(x64emu_t, df)); dyn->f.dfnone=1;}} while(0);
|
||||
#define SET_DF(S, N) \
|
||||
if((N)!=d_none) { \
|
||||
MOVZw(S, (N)); \
|
||||
STRw_U12(S, xEmu, offsetof(x64emu_t, df)); \
|
||||
if(dyn->f.pending==SF_PENDING && dyn->insts[ninst].x64.need_after && !(dyn->insts[ninst].x64.need_after&X_PEND)) { \
|
||||
CALL_(UpdateFlags, -1, 0); \
|
||||
dyn->f.pending = SF_SET; \
|
||||
SET_NODF(); \
|
||||
} \
|
||||
dyn->f.dfnone=0; \
|
||||
} else SET_DFNONE(S)
|
||||
#define SET_DFNONE() \
|
||||
do { \
|
||||
if (!dyn->f.dfnone) { \
|
||||
STRw_U12(wZR, xEmu, offsetof(x64emu_t, df)); \
|
||||
} \
|
||||
if(!dyn->insts[ninst].x64.may_set) { \
|
||||
dyn->f.dfnone_here = 1; \
|
||||
dyn->f.dfnone = 1; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define SET_DF(S, N) \
|
||||
if ((N) != d_none) { \
|
||||
MOVZw(S, (N)); \
|
||||
STRw_U12(S, xEmu, offsetof(x64emu_t, df)); \
|
||||
if (dyn->f.pending == SF_PENDING && dyn->insts[ninst].x64.need_after && !(dyn->insts[ninst].x64.need_after & X_PEND)) { \
|
||||
CALL_I(UpdateFlags); \
|
||||
dyn->f.pending = SF_SET; \
|
||||
SET_NODF(); \
|
||||
} \
|
||||
dyn->f.dfnone = 0; \
|
||||
} else \
|
||||
SET_DFNONE()
|
||||
|
||||
#ifndef SET_NODF
|
||||
#define SET_NODF() dyn->f.dfnone = 0
|
||||
#endif
|
||||
#define SET_DFOK() dyn->f.dfnone = 1; dyn->f.dfnone_here=1
|
||||
|
||||
#ifndef MAYSETFLAGS
|
||||
#define MAYSETFLAGS() do {} while (0)
|
||||
#endif
|
||||
|
||||
#ifndef READFLAGS
|
||||
#define READFLAGS(A) \
|
||||
if(((A)!=X_PEND && dyn->f.pending!=SF_SET) \
|
||||
@@ -1128,7 +1126,7 @@
|
||||
j64 = (GETMARKF)-(dyn->native_size); \
|
||||
CBZw(x3, j64); \
|
||||
} \
|
||||
CALL_(UpdateFlags, -1, 0); \
|
||||
CALL_I(UpdateFlags); \
|
||||
MARKF; \
|
||||
dyn->f.pending = SF_SET; \
|
||||
SET_DFOK(); \
|
||||
@@ -1142,7 +1140,7 @@
|
||||
&& (dyn->insts[ninst].x64.gen_flags&(~(A)))) \
|
||||
READFLAGS(((dyn->insts[ninst].x64.gen_flags&X_PEND)?X_ALL:dyn->insts[ninst].x64.gen_flags)&(~(A)));\
|
||||
if(dyn->insts[ninst].x64.gen_flags) switch(B) { \
|
||||
case SF_SUBSET: \
|
||||
case SF_SUBSET: SET_DFNONE(); dyn->f.pending = SF_SET; break; \
|
||||
case SF_SET: dyn->f.pending = SF_SET; break; \
|
||||
case SF_SET_DF: dyn->f.pending = SF_SET; dyn->f.dfnone = 1; break; \
|
||||
case SF_SET_NODF: dyn->f.pending = SF_SET; dyn->f.dfnone = 0; break; \
|
||||
@@ -1166,8 +1164,10 @@
|
||||
#define UFLAG_OP2(A) if(dyn->insts[ninst].x64.gen_flags) {STRxw_U12(A, xEmu, offsetof(x64emu_t, op2));}
|
||||
#define UFLAG_OP12(A1, A2) if(dyn->insts[ninst].x64.gen_flags) {STRxw_U12(A1, xEmu, offsetof(x64emu_t, op1));STRxw_U12(A2, xEmu, offsetof(x64emu_t, op2));}
|
||||
#define UFLAG_RES(A) if(dyn->insts[ninst].x64.gen_flags) {STRxw_U12(A, xEmu, offsetof(x64emu_t, res));}
|
||||
#define UFLAG_DF(r, A) if(dyn->insts[ninst].x64.gen_flags) {SET_DF(r, A)}
|
||||
#define UFLAG_DF(r, A) if(dyn->insts[ninst].x64.gen_flags) {SET_DF(r, A);}
|
||||
#define UFLAG_IF if(dyn->insts[ninst].x64.gen_flags)
|
||||
#define UFLAG_IF_DF if(dyn->insts[ninst].x64.gen_flags || (dyn->insts[ninst].f_entry.dfnone && dyn->insts[ninst].f_entry.dfnone_here))
|
||||
#define UFLAG_IF2(A) if(dyn->insts[ninst].x64.gen_flags A)
|
||||
#ifndef DEFAULT
|
||||
#define DEFAULT *ok = -1; BARRIER(2)
|
||||
#endif
|
||||
@@ -1188,8 +1188,8 @@
|
||||
#define ARCH_RESET()
|
||||
|
||||
#if STEP < 2
|
||||
#define GETIP(A) TABLE64(0, 0)
|
||||
#define GETIP_(A) TABLE64(0, 0)
|
||||
#define GETIP(A) MOV64x(xRIP, A)
|
||||
#define GETIP_(A) MOV64x(xRIP, A)
|
||||
#else
|
||||
// put value in the Table64 even if not using it for now to avoid difference between Step2 and Step3. Needs to be optimized later...
|
||||
#define GETIP(A) \
|
||||
@@ -1201,20 +1201,14 @@
|
||||
} \
|
||||
} else { \
|
||||
dyn->last_ip = (A); \
|
||||
if(dyn->last_ip<0xffffffff) { \
|
||||
MOV64x(xRIP, dyn->last_ip); \
|
||||
} else \
|
||||
TABLE64(xRIP, dyn->last_ip); \
|
||||
MOV64x(xRIP, dyn->last_ip); \
|
||||
}
|
||||
#define GETIP_(A) \
|
||||
if(dyn->last_ip && ((A)-dyn->last_ip)<0x1000) { \
|
||||
uint64_t _delta_ip = (A)-dyn->last_ip; \
|
||||
if(_delta_ip) {ADDx_U12(xRIP, xRIP, _delta_ip);}\
|
||||
} else { \
|
||||
if((A)<0xffffffff) { \
|
||||
MOV64x(xRIP, (A)); \
|
||||
} else \
|
||||
TABLE64(xRIP, (A)); \
|
||||
MOV64x(xRIP, (A)); \
|
||||
}
|
||||
#endif
|
||||
#define CLEARIP() dyn->last_ip=0
|
||||
@@ -1288,6 +1282,7 @@ void* arm64_next(x64emu_t* emu, uintptr_t addr);
|
||||
#define retn_to_epilog STEPNAME(retn_to_epilog)
|
||||
#define iret_to_epilog STEPNAME(iret_to_epilog)
|
||||
#define call_c STEPNAME(call_c)
|
||||
#define call_i STEPNAME(call_i)
|
||||
#define call_n STEPNAME(call_n)
|
||||
#define grab_segdata STEPNAME(grab_segdata)
|
||||
#define emit_cmp8 STEPNAME(emit_cmp8)
|
||||
@@ -1430,6 +1425,8 @@ void* arm64_next(x64emu_t* emu, uintptr_t addr);
|
||||
#define fpu_purgecache STEPNAME(fpu_purgecache)
|
||||
#define mmx_purgecache STEPNAME(mmx_purgecache)
|
||||
#define x87_purgecache STEPNAME(x87_purgecache)
|
||||
#define x87_reflectcount STEPNAME(x87_reflectcount)
|
||||
#define x87_unreflectcount STEPNAME(x87_unreflectcount)
|
||||
#define fpu_reflectcache STEPNAME(fpu_reflectcache)
|
||||
#define fpu_unreflectcache STEPNAME(fpu_unreflectcache)
|
||||
#define avx_purge_ymm STEPNAME(avx_purge_ymm)
|
||||
@@ -1456,8 +1453,9 @@ 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 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);
|
||||
void grab_segdata(dynarec_arm_t* dyn, uintptr_t addr, int ninst, int reg, int segment);
|
||||
void grab_segdata(dynarec_arm_t* dyn, uintptr_t addr, int ninst, int reg, int segment, int modreg);
|
||||
void emit_cmp8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5);
|
||||
void emit_cmp16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5);
|
||||
void emit_cmp32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5);
|
||||
@@ -1667,6 +1665,11 @@ void fpu_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1, int s2, int
|
||||
void mmx_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1);
|
||||
// purge x87 cache
|
||||
void x87_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1, int s2, int s3);
|
||||
// temporarily set x87 stack count for C functions
|
||||
void x87_reflectcount(dynarec_arm_t* dyn, int ninst, int s1, int s2);
|
||||
// restore count after
|
||||
void x87_unreflectcount(dynarec_arm_t* dyn, int ninst, int s1, int s2);
|
||||
// global fpu helper
|
||||
void fpu_reflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
void fpu_unreflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
void fpu_pushcache(dynarec_arm_t* dyn, int ninst, int s1, int not07);
|
||||
@@ -1892,19 +1895,19 @@ uintptr_t dynarec64_AVX_F3_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
} \
|
||||
break
|
||||
|
||||
#define NOTEST(s1) \
|
||||
if(box64_dynarec_test) { \
|
||||
STRw_U12(xZR, xEmu, offsetof(x64emu_t, test.test)); \
|
||||
STRw_U12(xZR, xEmu, offsetof(x64emu_t, test.clean));\
|
||||
#define NOTEST(s1) \
|
||||
if (BOX64ENV(dynarec_test)) { \
|
||||
STRw_U12(xZR, xEmu, offsetof(x64emu_t, test.test)); \
|
||||
STRw_U12(xZR, xEmu, offsetof(x64emu_t, test.clean)); \
|
||||
}
|
||||
#define SKIPTEST(s1) \
|
||||
if(box64_dynarec_test) { \
|
||||
STRw_U12(xZR, xEmu, offsetof(x64emu_t, test.clean));\
|
||||
#define SKIPTEST(s1) \
|
||||
if (BOX64ENV(dynarec_test)) { \
|
||||
STRw_U12(xZR, xEmu, offsetof(x64emu_t, test.clean)); \
|
||||
}
|
||||
#define GOTEST(s1, s2) \
|
||||
if(box64_dynarec_test) { \
|
||||
MOV32w(s2, 1); \
|
||||
STRw_U12(s2, xEmu, offsetof(x64emu_t, test.test)); \
|
||||
#define GOTEST(s1, s2) \
|
||||
if (BOX64ENV(dynarec_test)) { \
|
||||
MOV32w(s2, 1); \
|
||||
STRw_U12(s2, xEmu, offsetof(x64emu_t, test.test)); \
|
||||
}
|
||||
|
||||
#define GETREX() \
|
||||
|
||||
@@ -6,15 +6,16 @@
|
||||
if(ninst) dyn->insts[ninst-1].x64.size = dyn->insts[ninst].x64.addr - dyn->insts[ninst-1].x64.addr
|
||||
|
||||
#define MESSAGE(A, ...) do {} while (0)
|
||||
#define MAYSETFLAGS() dyn->insts[ninst].x64.may_set = 1
|
||||
#define READFLAGS(A) \
|
||||
dyn->insts[ninst].x64.use_flags = A; dyn->f.dfnone = 1;\
|
||||
if(!BOX64ENV(dynarec_df) && (A)&X_PEND) dyn->insts[ninst].x64.use_flags = X_ALL; \
|
||||
dyn->f.pending=SF_SET
|
||||
#define SETFLAGS(A,B) \
|
||||
dyn->insts[ninst].x64.set_flags = A; \
|
||||
dyn->insts[ninst].x64.state_flags = (B)&~SF_DF; \
|
||||
dyn->f.pending=(B)&SF_SET_PENDING; \
|
||||
dyn->f.dfnone=((B)&SF_SET)?(((B)==SF_SET_NODF)?0:1):0;
|
||||
dyn->f.dfnone=((B)&SF_SET)?(((B)==SF_SET_NODF)?0:1):0; \
|
||||
if(!BOX64ENV(dynarec_df)) {dyn->f.dfnone=1; dyn->f.pending=0; if((A)==SF_PENDING){printf_log(LOG_INFO, "Warning, some opcode use SF_PENDING, forcing deferedflags ON\n"); SET_BOX64ENV(dynarec_df, 1); }}
|
||||
#define EMIT(A) dyn->native_size+=4
|
||||
#define JUMP(A, C) add_jump(dyn, ninst); add_next(dyn, (uintptr_t)A); SMEND(); dyn->insts[ninst].x64.jmp = A; dyn->insts[ninst].x64.jmp_cond = C; dyn->insts[ninst].x64.jmp_insts = 0
|
||||
#define BARRIER(A) if(A!=BARRIER_MAYBE) {fpu_purgecache(dyn, ninst, 0, x1, x2, x3); dyn->insts[ninst].x64.barrier = A;} else dyn->insts[ninst].barrier_maybe = 1
|
||||
@@ -33,23 +34,27 @@
|
||||
if(dyn->insts[ninst].nat_flags_op==NAT_FLAG_OP_TOUCH && !dyn->insts[ninst].set_nat_flags) \
|
||||
dyn->insts[ninst].nat_flags_op=NAT_FLAG_OP_UNUSABLE; \
|
||||
dyn->insts[ninst].x64.has_next = (ok>0)?1:0;
|
||||
#define INST_NAME(name)
|
||||
#define DEFAULT \
|
||||
--dyn->size; \
|
||||
*ok = -1; \
|
||||
if(box64_dynarec_log>=LOG_INFO || box64_dynarec_dump || box64_dynarec_missing==1) {\
|
||||
dynarec_log(LOG_NONE, "%p: Dynarec stopped because of %sOpcode %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", \
|
||||
(void*)ip, rex.is32bits?"x86 ":"x64 ",\
|
||||
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, " => "); \
|
||||
dynarec_log(LOG_NONE, "\n"); \
|
||||
#define INST_NAME(name)
|
||||
#define DEFAULT \
|
||||
--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)) { \
|
||||
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) { \
|
||||
dynarec_log_prefix(0, LOG_NONE, "%s", DecodeX64Trace(dec, dyn->insts[ninst].x64.addr, 1)); \
|
||||
} else { \
|
||||
dynarec_log_prefix(0, LOG_NONE, "%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", \
|
||||
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, " => "); \
|
||||
dynarec_log_prefix(0, LOG_NONE, "\n"); \
|
||||
}
|
||||
|
||||
|
||||
#define FEMIT(A) dyn->insts[ninst].nat_flags_op = dyn->insts[ninst].x64.set_flags?NAT_FLAG_OP_TOUCH:NAT_FLAG_OP_UNUSABLE
|
||||
#define IFNATIVE(A) if(mark_natflag(dyn, ninst, A, 0))
|
||||
#define IFNATIVEN(A) if(mark_natflag(dyn, ninst, A, 0))
|
||||
@@ -64,3 +69,6 @@
|
||||
#define IFNATIVE_BEFORE(A) if(mark_natflag(dyn, ninst, A, 1))
|
||||
#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)))
|
||||
@@ -2,16 +2,16 @@
|
||||
#define FINI
|
||||
#define MESSAGE(A, ...) do {} while (0)
|
||||
#define EMIT(A) do {} while (0)
|
||||
#define MAYSETFLAGS() dyn->insts[ninst].x64.may_set = 1
|
||||
#define SET_NODF() \
|
||||
if(!dyn->insts[ninst].x64.gen_flags && !dyn->insts[ninst].x64.use_flags) \
|
||||
propagate_nodf(dyn, ninst); \
|
||||
dyn->f.dfnone = 0
|
||||
#define SETFLAGS(A,B) \
|
||||
dyn->insts[ninst].x64.set_flags = A; \
|
||||
dyn->insts[ninst].x64.state_flags = (B)&~SF_DF; \
|
||||
dyn->f.pending=(B)&SF_SET_PENDING; \
|
||||
dyn->f.dfnone=((B)&SF_SET)?(((B)==SF_SET_NODF)?0:1):0;
|
||||
#define SETFLAGS(A,B) \
|
||||
dyn->insts[ninst].x64.set_flags = A; \
|
||||
dyn->insts[ninst].x64.state_flags = (B)&~SF_DF; \
|
||||
dyn->f.pending=(B)&SF_SET_PENDING; \
|
||||
dyn->f.dfnone=((B)&SF_SET)?(((B)==SF_SET_NODF)?0:1):0; \
|
||||
if(!BOX64ENV(dynarec_df)) {dyn->f.dfnone=1; dyn->f.pending=0; }
|
||||
#define NEW_INST \
|
||||
dyn->insts[ninst].f_entry = dyn->f; \
|
||||
dyn->n.combined1 = dyn->n.combined2 = 0;\
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#define FINI \
|
||||
if(ninst) { \
|
||||
dyn->insts[ninst].address = (dyn->insts[ninst-1].address+dyn->insts[ninst-1].size); \
|
||||
dyn->insts_size += 1+((dyn->insts[ninst].x64.size>(dyn->insts[ninst].size/4))?dyn->insts[ninst].x64.size:(dyn->insts[ninst].size/4))/15; \
|
||||
dyn->insts_size += 1+((dyn->insts[ninst-1].x64.size>(dyn->insts[ninst-1].size/4))?dyn->insts[ninst-1].x64.size:(dyn->insts[ninst-1].size/4))/15; \
|
||||
}
|
||||
|
||||
#define MESSAGE(A, ...) do {} while (0)
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
#define INIT
|
||||
#define FINI \
|
||||
if(ninst) \
|
||||
addInst(dyn->instsize, &dyn->insts_size, dyn->insts[ninst].x64.size, dyn->insts[ninst].size/4); \
|
||||
addInst(dyn->instsize, &dyn->insts_size, dyn->insts[ninst-1].x64.size, dyn->insts[ninst-1].size/4); \
|
||||
addInst(dyn->instsize, &dyn->insts_size, 0, 0);
|
||||
#define EMIT(A) \
|
||||
do{ \
|
||||
if(box64_dynarec_dump) print_opcode(dyn, ninst, (uint32_t)(A)); \
|
||||
if(BOX64DRENV(dynarec_dump)) print_opcode(dyn, ninst, (uint32_t)(A)); \
|
||||
if((uintptr_t)dyn->block<dyn->tablestart) \
|
||||
*(uint32_t*)(dyn->block) = (uint32_t)(A); \
|
||||
dyn->block += 4; dyn->native_size += 4; \
|
||||
dyn->insts[ninst].size2 += 4; \
|
||||
}while(0)
|
||||
|
||||
#define MESSAGE(A, ...) if(box64_dynarec_dump) dynarec_log(LOG_NONE, __VA_ARGS__)
|
||||
#define MESSAGE(A, ...) if(BOX64DRENV(dynarec_dump)) dynarec_log(LOG_NONE, __VA_ARGS__)
|
||||
#define NEW_INST \
|
||||
if(ninst) { \
|
||||
if(dyn->insts[ninst].address!=(uintptr_t)dyn->block-(uintptr_t)dyn->native_start) dyn->abort = 1; \
|
||||
|
||||
@@ -122,6 +122,7 @@ typedef struct instruction_arm64_s {
|
||||
unsigned normal_carry_before:1;
|
||||
unsigned invert_carry:1; // this opcode force an inverted carry
|
||||
unsigned df_notneeded:1;
|
||||
unsigned unaligned:1; // this opcode can be re-generated for unaligned special case
|
||||
flagcache_t f_exit; // flags status at end of instruction
|
||||
neoncache_t n; // neoncache at end of instruction (but before poping)
|
||||
flagcache_t f_entry; // flags status before the instruction begin
|
||||
@@ -164,6 +165,7 @@ typedef struct dynarec_arm_s {
|
||||
uint8_t doublepop;
|
||||
uint8_t always_test;
|
||||
uint8_t abort; // abort the creation of the block
|
||||
void* gdbjit_block;
|
||||
} dynarec_arm_t;
|
||||
|
||||
void add_next(dynarec_arm_t *dyn, uintptr_t addr);
|
||||
|
||||
@@ -208,7 +208,7 @@ static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t
|
||||
}
|
||||
|
||||
if(need_lock) {
|
||||
if(box64_dynarec_wait) {
|
||||
if(BOX64ENV(dynarec_wait)) {
|
||||
mutex_lock(&my_context->mutex_dyndump);
|
||||
} else {
|
||||
if(mutex_trylock(&my_context->mutex_dyndump)) // FillBlock not available for now
|
||||
|
||||
@@ -21,7 +21,9 @@ typedef struct dynablock_s {
|
||||
uint8_t is32bits:1;
|
||||
int isize;
|
||||
instsize_t* instsize;
|
||||
void* arch; // arch dependant per inst info (can be NULL)
|
||||
size_t arch_size; // size of of arch dependant infos
|
||||
void* jmpnext; // a branch jmpnext code when block is marked
|
||||
} dynablock_t;
|
||||
|
||||
#endif //__DYNABLOCK_PRIVATE_H_
|
||||
#endif //__DYNABLOCK_PRIVATE_H_
|
||||
+15
-20
@@ -52,7 +52,7 @@ void* LinkNext(x64emu_t* emu, uintptr_t addr, void* x2, uintptr_t* x3)
|
||||
dynablock_t* block = NULL;
|
||||
if(hasAlternate((void*)addr)) {
|
||||
printf_log(LOG_DEBUG, "Jmp address has alternate: %p", (void*)addr);
|
||||
if(box64_log<LOG_DEBUG) dynarec_log(LOG_INFO, "Jmp address has alternate: %p", (void*)addr);
|
||||
if (BOX64ENV(log)<LOG_DEBUG) dynarec_log(LOG_INFO, "Jmp address has alternate: %p", (void*)addr);
|
||||
uintptr_t old_addr = addr;
|
||||
addr = (uintptr_t)getAlternate((void*)addr); // set new address
|
||||
R_RIP = addr; // but also new RIP!
|
||||
@@ -63,7 +63,7 @@ void* LinkNext(x64emu_t* emu, uintptr_t addr, void* x2, uintptr_t* x3)
|
||||
block = DBGetBlock(emu, addr, 1, is32bits);
|
||||
if(!block) {
|
||||
#ifdef HAVE_TRACE
|
||||
if(LOG_INFO<=box64_dynarec_log) {
|
||||
if(LOG_INFO<=BOX64ENV(dynarec_log)) {
|
||||
if(checkInHotPage(addr)) {
|
||||
dynarec_log(LOG_INFO, "Not trying to run a block from a Hotpage at %p\n", (void*)addr);
|
||||
} else {
|
||||
@@ -79,7 +79,7 @@ void* LinkNext(x64emu_t* emu, uintptr_t addr, void* x2, uintptr_t* x3)
|
||||
if(!block->done) {
|
||||
// not finished yet... leave linker
|
||||
#ifdef HAVE_TRACE
|
||||
if(box64_dynarec_log && !block->isize) {
|
||||
if(BOX64ENV(dynarec_log) && !block->isize) {
|
||||
dynablock_t* db = FindDynablockFromNativeAddress(x2-4);
|
||||
printf_log(LOG_NONE, "Warning, NULL block at %p from %p (db=%p, x64addr=%p/%s)\n", (void*)addr, x2-4, db, db?(void*)getX64Address(db, (uintptr_t)x2-4):NULL, db?getAddrFunctionName(getX64Address(db, (uintptr_t)x2-4)):"(nil)");
|
||||
}
|
||||
@@ -109,9 +109,6 @@ void DynaCall(x64emu_t* emu, uintptr_t addr)
|
||||
multiuint_t old_op1 = emu->op1;
|
||||
multiuint_t old_op2 = emu->op2;
|
||||
multiuint_t old_res = emu->res;
|
||||
// uc_link
|
||||
void* old_uc_link = emu->uc_link;
|
||||
emu->uc_link = NULL;
|
||||
|
||||
#ifdef BOX32
|
||||
if(box64_is32bits)
|
||||
@@ -124,7 +121,6 @@ void DynaCall(x64emu_t* emu, uintptr_t addr)
|
||||
DynaRun(emu);
|
||||
emu->quit = 0; // reset Quit flags...
|
||||
emu->df = d_none;
|
||||
emu->uc_link = old_uc_link;
|
||||
if(emu->flags.quitonlongjmp && emu->flags.longjmp) {
|
||||
if(emu->flags.quitonlongjmp==1)
|
||||
emu->flags.longjmp = 0; // don't change anything because of the longjmp
|
||||
@@ -176,7 +172,7 @@ void DynaRun(x64emu_t* emu)
|
||||
{
|
||||
printf_log(LOG_DEBUG, "Setjmp DynaRun, fs=0x%x\n", emu->segs[_FS]);
|
||||
#ifdef DYNAREC
|
||||
if(box64_dynarec_test) {
|
||||
if(BOX64ENV(dynarec_test)) {
|
||||
if(emu->test.clean)
|
||||
x64test_check(emu, R_RIP);
|
||||
emu->test.clean = 0;
|
||||
@@ -188,7 +184,7 @@ void DynaRun(x64emu_t* emu)
|
||||
emu->flags.need_jmpbuf = 0;
|
||||
|
||||
#ifdef DYNAREC
|
||||
if(!box64_dynarec)
|
||||
if(!BOX64ENV(dynarec))
|
||||
#endif
|
||||
Run(emu, 0);
|
||||
#ifdef DYNAREC
|
||||
@@ -214,12 +210,20 @@ void DynaRun(x64emu_t* emu)
|
||||
skip = 0;
|
||||
// no block, of block doesn't have DynaRec content (yet, temp is not null)
|
||||
// Use interpreter (should use single instruction step...)
|
||||
dynarec_log(LOG_DEBUG, "%04d|Running Interpreter @%p, emu=%p\n", GetTID(), (void*)R_RIP, emu);
|
||||
if(box64_dynarec_test)
|
||||
if(BOX64ENV(dynarec_log)) {
|
||||
if(ACCESS_FLAG(F_TF))
|
||||
dynarec_log(LOG_INFO, "%04d|Running Interpreter @%p, emu=%p because TF is on\n", GetTID(), (void*)R_RIP, emu);
|
||||
else
|
||||
dynarec_log(LOG_DEBUG, "%04d|Running Interpreter @%p, emu=%p\n", GetTID(), (void*)R_RIP, emu);
|
||||
}
|
||||
if (BOX64ENV(dynarec_test))
|
||||
emu->test.clean = 0;
|
||||
Run(emu, 1);
|
||||
} else {
|
||||
dynarec_log(LOG_DEBUG, "%04d|Running DynaRec Block @%p (%p) of %d x64 insts (hash=0x%x) emu=%p\n", GetTID(), (void*)R_RIP, block->block, block->isize, block->hash, emu);
|
||||
if(!BOX64ENV(dynarec_df)) {
|
||||
CHECK_FLAGS(emu);
|
||||
}
|
||||
// block is here, let's run it!
|
||||
native_prolog(emu, block->block);
|
||||
}
|
||||
@@ -229,15 +233,6 @@ void DynaRun(x64emu_t* emu)
|
||||
emu->fork = 0;
|
||||
emu = x64emu_fork(emu, forktype);
|
||||
}
|
||||
if(emu->quit && emu->uc_link) {
|
||||
emu->quit = 0;
|
||||
#ifdef BOX32
|
||||
if(box64_is32bits)
|
||||
my32_setcontext(emu, emu->uc_link);
|
||||
else
|
||||
#endif
|
||||
my_setcontext(emu, emu->uc_link);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if(emu->flags.need_jmpbuf)
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#define instruction_native_t instruction_arm64_t
|
||||
#define dynarec_native_t dynarec_arm_t
|
||||
#define extcache_native_t neoncache_t
|
||||
|
||||
#define ADDITIONNAL_DEFINITION() \
|
||||
int fpuCacheNeedsTransform(dynarec_native_t* dyn, int ninst);
|
||||
@@ -16,6 +17,7 @@
|
||||
#include "arm64/arm64_printer.h"
|
||||
#include "arm64/dynarec_arm64_private.h"
|
||||
#include "arm64/dynarec_arm64_functions.h"
|
||||
#include "arm64/dynarec_arm64_arch.h"
|
||||
// Limit here is defined by LD litteral, that is 19bits
|
||||
#define MAXBLOCK_SIZE ((1<<19)-200)
|
||||
|
||||
@@ -23,10 +25,16 @@
|
||||
#define UPDATE_SPECIFICS(A) updateNativeFlags(A)
|
||||
#define PREUPDATE_SPECIFICS(A)
|
||||
|
||||
#define ARCH_SIZE(A) get_size_arch(A)
|
||||
#define ARCH_FILL(A, B, C) populate_arch(A, B, C)
|
||||
#define ARCH_ADJUST(A, B, C, D) adjust_arch(A, B, C, D)
|
||||
#define STOP_NATIVE_FLAGS(A, B) A->insts[B].nat_flags_op = NAT_FLAG_OP_UNUSABLE
|
||||
#define ARCH_UNALIGNED(A, B) arch_unaligned(A, B)
|
||||
#elif defined(LA64)
|
||||
|
||||
#define instruction_native_t instruction_la64_t
|
||||
#define dynarec_native_t dynarec_la64_t
|
||||
#define extcache_native_t lsxcache_t
|
||||
|
||||
#define ADDITIONNAL_DEFINITION() \
|
||||
int fpuCacheNeedsTransform(dynarec_native_t* dyn, int ninst);
|
||||
@@ -42,11 +50,18 @@
|
||||
|
||||
#define RAZ_SPECIFIC(A, N)
|
||||
#define UPDATE_SPECIFICS(A)
|
||||
#define PREUPDATE_SPECIFICS(A)
|
||||
#define PREUPDATE_SPECIFICS(A) updateNativeFlags(A)
|
||||
|
||||
#define ARCH_SIZE(A) 0
|
||||
#define ARCH_FILL(A, B, C) NULL
|
||||
#define ARCH_ADJUST(A, B, C, D) {}
|
||||
#define STOP_NATIVE_FLAGS(A, B) {}
|
||||
#define ARCH_UNALIGNED(A, B) 0
|
||||
#elif defined(RV64)
|
||||
|
||||
#define instruction_native_t instruction_rv64_t
|
||||
#define dynarec_native_t dynarec_rv64_t
|
||||
#define extcache_native_t extcache_t
|
||||
|
||||
#define ADDITIONNAL_DEFINITION() \
|
||||
int fpuCacheNeedsTransform(dynarec_native_t* dyn, int ninst); \
|
||||
@@ -59,12 +74,19 @@
|
||||
#include "rv64/rv64_printer.h"
|
||||
#include "rv64/dynarec_rv64_private.h"
|
||||
#include "rv64/dynarec_rv64_functions.h"
|
||||
#include "rv64/dynarec_rv64_arch.h"
|
||||
// Limit here is unconditionnal jump, that is signed 21bits
|
||||
#define MAXBLOCK_SIZE ((1<<20)-200)
|
||||
|
||||
#define RAZ_SPECIFIC(A, N)
|
||||
#define UPDATE_SPECIFICS(A)
|
||||
#define PREUPDATE_SPECIFICS(A) updateNativeFlags(A)
|
||||
|
||||
#define ARCH_SIZE(A) get_size_arch(A)
|
||||
#define ARCH_FILL(A, B, C) populate_arch(A, B, C)
|
||||
#define ARCH_ADJUST(A, B, C, D) {}
|
||||
#define STOP_NATIVE_FLAGS(A, B) {}
|
||||
#define ARCH_UNALIGNED(A, B) arch_unaligned(A, B)
|
||||
#else
|
||||
#error Unsupported platform
|
||||
#endif
|
||||
|
||||
@@ -49,12 +49,12 @@
|
||||
SMWRITE(); \
|
||||
} while (0)
|
||||
|
||||
#define SMWRITE2() \
|
||||
do { \
|
||||
if (box64_dynarec_strongmem >= STRONGMEM_SIMD_WRITE) { \
|
||||
dyn->smwrite = 1; \
|
||||
dyn->insts[ninst].will_write = 2; \
|
||||
} \
|
||||
#define SMWRITE2() \
|
||||
do { \
|
||||
if (BOX64DRENV(dynarec_strongmem) >= STRONGMEM_SIMD_WRITE) { \
|
||||
dyn->smwrite = 1; \
|
||||
dyn->insts[ninst].will_write = 2; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define SMREAD()
|
||||
@@ -71,7 +71,7 @@
|
||||
#define SMEND() \
|
||||
do { \
|
||||
/* If there is any guest memory write, which is a SEQ, then compute the last_write. */ \
|
||||
if (dyn->smwrite && (box64_dynarec_strongmem >= STRONGMEM_LAST_WRITE)) { \
|
||||
if (dyn->smwrite && (BOX64DRENV(dynarec_strongmem) >= STRONGMEM_LAST_WRITE)) { \
|
||||
int i = ninst; \
|
||||
while (i >= 0 && !dyn->insts[i].will_write) \
|
||||
--i; \
|
||||
@@ -88,7 +88,7 @@
|
||||
#define SMWRITE() \
|
||||
do { \
|
||||
/* Put a barrier at every third memory write. */ \
|
||||
if (box64_dynarec_strongmem >= STRONGMEM_SEQ_WRITE) { \
|
||||
if (BOX64DRENV(dynarec_strongmem) >= STRONGMEM_SEQ_WRITE) { \
|
||||
if (++dyn->smwrite >= 3 /* Every third memory write */) { \
|
||||
DMB_ISH(); \
|
||||
dyn->smwrite = 1; \
|
||||
@@ -110,10 +110,10 @@
|
||||
} while (0)
|
||||
|
||||
// Similar to SMWRITE, but for SIMD instructions.
|
||||
#define SMWRITE2() \
|
||||
do { \
|
||||
if (box64_dynarec_strongmem >= STRONGMEM_SIMD_WRITE) \
|
||||
SMWRITE(); \
|
||||
#define SMWRITE2() \
|
||||
do { \
|
||||
if (BOX64DRENV(dynarec_strongmem) >= STRONGMEM_SIMD_WRITE) \
|
||||
SMWRITE(); \
|
||||
} while (0)
|
||||
|
||||
// An opcode reads guest memory, this need to be put before the LOAD instruction manually.
|
||||
@@ -130,22 +130,22 @@
|
||||
} while (0)
|
||||
|
||||
// An opcode will write memory, this will be put before the STORE instruction automatically.
|
||||
#define WILLWRITE() \
|
||||
do { \
|
||||
if (box64_dynarec_strongmem >= dyn->insts[ninst].will_write && dyn->smwrite == 0) { \
|
||||
/* Will write but never written, this is the start of a SEQ, put a barrier. */ \
|
||||
if (box64_dynarec_weakbarrier) \
|
||||
DMB_ISHLD(); \
|
||||
else \
|
||||
DMB_ISH(); \
|
||||
} else if (box64_dynarec_strongmem >= STRONGMEM_LAST_WRITE && box64_dynarec_weakbarrier != 2 \
|
||||
&& dyn->insts[ninst].last_write) { \
|
||||
/* Last write, put a barrier */ \
|
||||
if (box64_dynarec_weakbarrier) \
|
||||
DMB_ISHST(); \
|
||||
else \
|
||||
DMB_ISH(); \
|
||||
} \
|
||||
#define WILLWRITE() \
|
||||
do { \
|
||||
if (BOX64DRENV(dynarec_strongmem) >= dyn->insts[ninst].will_write && dyn->smwrite == 0) { \
|
||||
/* Will write but never written, this is the start of a SEQ, put a barrier. */ \
|
||||
if (BOX64ENV(dynarec_weakbarrier)) \
|
||||
DMB_ISHLD(); \
|
||||
else \
|
||||
DMB_ISH(); \
|
||||
} else if (BOX64DRENV(dynarec_strongmem) >= STRONGMEM_LAST_WRITE && BOX64ENV(dynarec_weakbarrier) != 2 \
|
||||
&& dyn->insts[ninst].last_write) { \
|
||||
/* Last write, put a barrier */ \
|
||||
if (BOX64ENV(dynarec_weakbarrier)) \
|
||||
DMB_ISHST(); \
|
||||
else \
|
||||
DMB_ISH(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// Similar to WILLWRITE, but checks lock.
|
||||
@@ -167,11 +167,11 @@
|
||||
// Will be put at the end of the SEQ
|
||||
#define SMEND() \
|
||||
do { \
|
||||
if (box64_dynarec_strongmem) { \
|
||||
if (BOX64DRENV(dynarec_strongmem)) { \
|
||||
/* It's a SEQ, put a barrier here. */ \
|
||||
if (dyn->smwrite) { \
|
||||
/* Check if the next instruction has a end loop mark */ \
|
||||
if (box64_dynarec_weakbarrier) \
|
||||
if (BOX64ENV(dynarec_weakbarrier)) \
|
||||
DMB_ISHST(); \
|
||||
else \
|
||||
DMB_ISH(); \
|
||||
@@ -184,6 +184,8 @@
|
||||
#define SMDMB() DMB_ISH()
|
||||
#endif
|
||||
|
||||
int is_addr_unaligned(uintptr_t addr);
|
||||
|
||||
#ifdef ARM64
|
||||
#include "arm64/dynarec_arm64_helper.h"
|
||||
#elif defined(LA64)
|
||||
|
||||
+102
-36
@@ -1,3 +1,4 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
@@ -22,25 +23,26 @@
|
||||
#include "dynarec_native.h"
|
||||
#include "dynarec_arch.h"
|
||||
#include "dynarec_next.h"
|
||||
#include "gdbjit.h"
|
||||
|
||||
void printf_x64_instruction(zydis_dec_t* dec, instruction_x64_t* inst, const char* name) {
|
||||
void printf_x64_instruction(dynarec_native_t* dyn, zydis_dec_t* dec, instruction_x64_t* inst, const char* name) {
|
||||
uint8_t *ip = (uint8_t*)inst->addr;
|
||||
if(ip[0]==0xcc && ip[1]=='S' && ip[2]=='C') {
|
||||
uintptr_t a = *(uintptr_t*)(ip+3);
|
||||
if(a==0) {
|
||||
dynarec_log(LOG_NONE, "%s%p: Exit x64emu%s\n", (box64_dynarec_dump>1)?"\e[01;33m":"", (void*)ip, (box64_dynarec_dump>1)?"\e[m":"");
|
||||
dynarec_log(LOG_NONE, "%s%p: Exit x64emu%s\n", (BOX64DRENV(dynarec_dump)>1)?"\e[01;33m":"", (void*)ip, (BOX64DRENV(dynarec_dump)>1)?"\e[m":"");
|
||||
} else {
|
||||
dynarec_log(LOG_NONE, "%s%p: Native call to %p%s\n", (box64_dynarec_dump>1)?"\e[01;33m":"", (void*)ip, (void*)a, (box64_dynarec_dump>1)?"\e[m":"");
|
||||
dynarec_log(LOG_NONE, "%s%p: Native call to %p%s\n", (BOX64DRENV(dynarec_dump)>1)?"\e[01;33m":"", (void*)ip, (void*)a, (BOX64DRENV(dynarec_dump)>1)?"\e[m":"");
|
||||
}
|
||||
} else {
|
||||
if(dec) {
|
||||
dynarec_log(LOG_NONE, "%s%p: %s", (box64_dynarec_dump>1)?"\e[01;33m":"", ip, DecodeX64Trace(dec, inst->addr));
|
||||
dynarec_log(LOG_NONE, "%s%p: %s", (BOX64DRENV(dynarec_dump) > 1) ? "\e[01;33m" : "", ip, DecodeX64Trace(dec, inst->addr, 1));
|
||||
} else {
|
||||
dynarec_log(LOG_NONE, "%s%p: ", (box64_dynarec_dump>1)?"\e[01;33m":"", ip);
|
||||
dynarec_log(LOG_NONE, "%s%p: ", (BOX64DRENV(dynarec_dump)>1)?"\e[01;33m":"", ip);
|
||||
for(int i=0; i<inst->size; ++i) {
|
||||
dynarec_log(LOG_NONE, "%02X ", ip[i]);
|
||||
dynarec_log_prefix(0, LOG_NONE, "%02X ", ip[i]);
|
||||
}
|
||||
dynarec_log(LOG_NONE, " %s", name);
|
||||
dynarec_log_prefix(0, LOG_NONE, " %s", name);
|
||||
}
|
||||
// print Call function name if possible
|
||||
if(ip[0]==0xE8 || ip[0]==0xE9) { // Call / Jmp
|
||||
@@ -53,12 +55,12 @@ void printf_x64_instruction(zydis_dec_t* dec, instruction_x64_t* inst, const cha
|
||||
}
|
||||
}
|
||||
// end of line and colors
|
||||
dynarec_log(LOG_NONE, "%s\n", (box64_dynarec_dump>1)?"\e[m":"");
|
||||
dynarec_log_prefix(0, LOG_NONE, "%s\n", (BOX64DRENV(dynarec_dump)>1)?"\e[m":"");
|
||||
}
|
||||
}
|
||||
|
||||
void add_next(dynarec_native_t *dyn, uintptr_t addr) {
|
||||
if(!box64_dynarec_bigblock)
|
||||
if (!BOX64DRENV(dynarec_bigblock))
|
||||
return;
|
||||
// exist?
|
||||
for(int i=0; i<dyn->next_sz; ++i)
|
||||
@@ -377,9 +379,10 @@ static int updateNeed(dynarec_native_t* dyn, int ninst, uint8_t need) {
|
||||
while (ninst>=0) {
|
||||
// need pending but instruction is only a subset: remove pend and use an X_ALL instead
|
||||
need |= dyn->insts[ninst].x64.need_after;
|
||||
if((need&X_PEND) && (dyn->insts[ninst].x64.state_flags==SF_SUBSET || dyn->insts[ninst].x64.state_flags==SF_SET || dyn->insts[ninst].x64.state_flags==SF_SET_NODF)) {
|
||||
if((need&X_PEND) && ((dyn->insts[ninst].x64.state_flags==SF_SUBSET) || (dyn->insts[ninst].x64.state_flags==SF_SET) || (dyn->insts[ninst].x64.state_flags==SF_SET_NODF))) {
|
||||
need &=~X_PEND;
|
||||
need |= X_ALL;
|
||||
STOP_NATIVE_FLAGS(dyn, ninst);
|
||||
}
|
||||
if((need&X_PEND) && dyn->insts[ninst].x64.state_flags==SF_SUBSET_PENDING) {
|
||||
need |= X_ALL&~(dyn->insts[ninst].x64.set_flags);
|
||||
@@ -419,7 +422,7 @@ static void updateYmm0s(dynarec_native_t* dyn, int ninst, int max_ninst_reached)
|
||||
int can_incr = ninst == max_ninst_reached; // Are we the top-level call?
|
||||
int ok = 1;
|
||||
while ((can_incr || ok) && ninst<dyn->size) {
|
||||
//if(box64_dynarec_dump) dynarec_log(LOG_NONE, "update ninst=%d (%d): can_incr=%d\n", ninst, max_ninst_reached, can_incr);
|
||||
//if(BOX64DRENV(dynarec_dump)) dynarec_log(LOG_NONE, "update ninst=%d (%d): can_incr=%d\n", ninst, max_ninst_reached, can_incr);
|
||||
uint16_t new_purge_ymm, new_ymm0_in, new_ymm0_out;
|
||||
|
||||
if (dyn->insts[ninst].pred_sz && dyn->insts[ninst].x64.alive) {
|
||||
@@ -430,18 +433,18 @@ static void updateYmm0s(dynarec_native_t* dyn, int ninst, int max_ninst_reached)
|
||||
uint16_t ymm0_inter = (ninst && !(dyn->insts[ninst].x64.barrier & BARRIER_FLOAT)) ? ((uint16_t)-1) : (uint16_t)0;
|
||||
for (int i = 0; i < dyn->insts[ninst].pred_sz; ++i) {
|
||||
int pred = dyn->insts[ninst].pred[i];
|
||||
//if(box64_dynarec_dump) dynarec_log(LOG_NONE, "\twith pred[%d] = %d", i, pred);
|
||||
//if(BOX64DRENV(dynarec_dump)) dynarec_log(LOG_NONE, "\twith pred[%d] = %d", i, pred);
|
||||
if (pred >= max_ninst_reached) {
|
||||
//if(box64_dynarec_dump) dynarec_log(LOG_NONE, " (skipped)\n");
|
||||
//if(BOX64DRENV(dynarec_dump)) dynarec_log(LOG_NONE, " (skipped)\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
int pred_out = dyn->insts[pred].x64.has_callret ? 0 : dyn->insts[pred].ymm0_out;
|
||||
//if(box64_dynarec_dump) dynarec_log(LOG_NONE, " ~> %04X\n", pred_out);
|
||||
//if(BOX64DRENV(dynarec_dump)) dynarec_log(LOG_NONE, " ~> %04X\n", pred_out);
|
||||
ymm0_union |= pred_out;
|
||||
ymm0_inter &= pred_out;
|
||||
}
|
||||
//if(box64_dynarec_dump) dynarec_log(LOG_NONE, "\t=> %04X,%04X\n", ymm0_union, ymm0_inter);
|
||||
//if(BOX64DRENV(dynarec_dump)) dynarec_log(LOG_NONE, "\t=> %04X,%04X\n", ymm0_union, ymm0_inter);
|
||||
// Notice the default values yield something coherent here (if all pred are after ninst)
|
||||
new_purge_ymm = ymm0_union & ~ymm0_inter;
|
||||
new_ymm0_in = ymm0_inter;
|
||||
@@ -463,7 +466,7 @@ static void updateYmm0s(dynarec_native_t* dyn, int ninst, int max_ninst_reached)
|
||||
|
||||
int jmp = (dyn->insts[ninst].x64.jmp)?dyn->insts[ninst].x64.jmp_insts:-1;
|
||||
if((jmp!=-1) && (jmp < max_ninst_reached)) {
|
||||
//if(box64_dynarec_dump) dynarec_log(LOG_NONE, "\t! jump to %d\n", jmp);
|
||||
//if(BOX64DRENV(dynarec_dump)) dynarec_log(LOG_NONE, "\t! jump to %d\n", jmp);
|
||||
// The jump goes before the last instruction reached, update the destination
|
||||
// If this is the top level call, this means the jump goes backward (jmp != ninst)
|
||||
// Otherwise, since we don't update all instructions, we may miss the update (don't use jmp < ninst)
|
||||
@@ -477,7 +480,7 @@ static void updateYmm0s(dynarec_native_t* dyn, int ninst, int max_ninst_reached)
|
||||
// Also update jumps to before (they are skipped otherwise)
|
||||
int jmp = (dyn->insts[ninst].x64.jmp)?dyn->insts[ninst].x64.jmp_insts:-1;
|
||||
if((jmp!=-1) && (jmp < max_ninst_reached)) {
|
||||
//if(box64_dynarec_dump) dynarec_log(LOG_NONE, "\t! jump to %d\n", jmp);
|
||||
//if(BOX64DRENV(dynarec_dump)) dynarec_log(LOG_NONE, "\t! jump to %d\n", jmp);
|
||||
updateYmm0s(dyn, jmp, max_ninst_reached);
|
||||
}
|
||||
} else {
|
||||
@@ -503,6 +506,37 @@ static uint64_t static_table64[(MAX_INSTS+3)/4];
|
||||
static instruction_native_t static_insts[MAX_INSTS+2] = {0};
|
||||
// TODO: ninst could be a uint16_t instead of an int, that could same some temp. memory
|
||||
|
||||
void ClearCache(void* start, size_t len)
|
||||
{
|
||||
#if defined(ARM64)
|
||||
// manually clear cache, I have issue with regular function on Ampere with kernel 6.12.4
|
||||
uintptr_t xstart = (uintptr_t)start;
|
||||
uintptr_t xend = (uintptr_t)start + len + 1;
|
||||
// Cache Type Info. Only grab the info once
|
||||
static uint64_t ctr_el0 = 0;
|
||||
if (ctr_el0 == 0)
|
||||
__asm __volatile("mrs %0, ctr_el0" : "=r"(ctr_el0));
|
||||
const int ctr_el0_idc = (ctr_el0>>28)&1; // 0: datacache needs to be cleaned too, 1: no need
|
||||
const int ctr_el0_dic = (ctr_el0>>29)&1; // 0: instruction cache needs to be cleaned, 1: no need
|
||||
const uintptr_t dcache_line_size = 4 << ((ctr_el0 >> 16) & 15);
|
||||
const uintptr_t icache_line_size = 4 << ((ctr_el0 >> 0) & 15);
|
||||
if (!ctr_el0_idc) {
|
||||
//purge each dcache line if no icache is defined...
|
||||
for (uint64_t addr=xstart&~(dcache_line_size-1); addr<xend; addr+=dcache_line_size)
|
||||
__asm __volatile("dc cvau, %0" ::"r"(addr));
|
||||
}
|
||||
// ignoring idc...
|
||||
if (1/*ctr_el0_idx*/) {
|
||||
// purge each icache line
|
||||
for (uint64_t addr=xstart&~(icache_line_size-1); addr<xend; addr+=icache_line_size)
|
||||
__asm __volatile("ic ivau, %0" ::"r"(addr));
|
||||
}
|
||||
__asm __volatile("isb sy");
|
||||
#else
|
||||
__builtin___clear_cache(start, start+len+1);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CancelBlock64(int need_lock)
|
||||
{
|
||||
if(need_lock)
|
||||
@@ -544,7 +578,7 @@ void* CreateEmptyBlock(dynablock_t* block, uintptr_t addr, int is32bits) {
|
||||
*(void**)(p+2*sizeof(void*)) = native_epilog;
|
||||
CreateJmpNext(block->jmpnext, p+2*sizeof(void*));
|
||||
// all done...
|
||||
__clear_cache(actual_p, actual_p+sz); // need to clear the cache before execution...
|
||||
ClearCache(actual_p+sizeof(void*), 3*sizeof(void*)); // need to clear the cache before execution...
|
||||
return block;
|
||||
}
|
||||
|
||||
@@ -560,9 +594,10 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
B+16 .. B+23 : jmpnext (or jmp_epilog) address. jumpnext is used when the block needs testing
|
||||
B+24 .. B+31 : empty (in case an architecture needs more than 2 opcodes)
|
||||
B+32 .. B+32+sz : instsize (compressed array with each instruction length on x64 and native side)
|
||||
C .. C+sz : arch: arch specific info (likes flags info) per inst (can be absent)
|
||||
|
||||
*/
|
||||
if(addr>=box64_nodynarec_start && addr<box64_nodynarec_end) {
|
||||
if(addr>=BOX64ENV(nodynarec_start) && addr<BOX64ENV(nodynarec_end)) {
|
||||
dynarec_log(LOG_INFO, "Create empty block in no-dynarec zone\n");
|
||||
return CreateEmptyBlock(block, addr, is32bits);
|
||||
}
|
||||
@@ -574,6 +609,10 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
protectDB(addr, 1);
|
||||
// init the helper
|
||||
dynarec_native_t helper = {0};
|
||||
dynarec_native_t* dyn = &helper;
|
||||
#ifdef GDBJIT
|
||||
helper.gdbjit_block = box_calloc(1, sizeof(gdbjit_block_t));
|
||||
#endif
|
||||
current_helper = &helper;
|
||||
helper.dynablock = block;
|
||||
helper.start = addr;
|
||||
@@ -589,7 +628,7 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
// pass 0, addresses, x64 jump addresses, overall size of the block
|
||||
uintptr_t end = native_pass0(&helper, addr, alternate, is32bits);
|
||||
if(helper.abort) {
|
||||
if(box64_dynarec_dump || box64_dynarec_log)dynarec_log(LOG_NONE, "Abort dynablock on pass0\n");
|
||||
if(BOX64DRENV(dynarec_dump) || BOX64ENV(dynarec_log))dynarec_log(LOG_NONE, "Abort dynablock on pass0\n");
|
||||
CancelBlock64(0);
|
||||
return NULL;
|
||||
}
|
||||
@@ -671,7 +710,7 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
|
||||
PREUPDATE_SPECIFICS(&helper);
|
||||
|
||||
int pos = helper.size;
|
||||
int pos = helper.size-1;
|
||||
while (pos>=0)
|
||||
pos = updateNeed(&helper, pos, 0);
|
||||
// remove fpu stuff on non-executed code
|
||||
@@ -704,7 +743,7 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
// pass 1, float optimizations, first pass for flags
|
||||
native_pass1(&helper, addr, alternate, is32bits);
|
||||
if(helper.abort) {
|
||||
if(box64_dynarec_dump || box64_dynarec_log)dynarec_log(LOG_NONE, "Abort dynablock on pass1\n");
|
||||
if(BOX64DRENV(dynarec_dump) || BOX64ENV(dynarec_log))dynarec_log(LOG_NONE, "Abort dynablock on pass1\n");
|
||||
CancelBlock64(0);
|
||||
return NULL;
|
||||
}
|
||||
@@ -712,7 +751,7 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
// pass 2, instruction size
|
||||
native_pass2(&helper, addr, alternate, is32bits);
|
||||
if(helper.abort) {
|
||||
if(box64_dynarec_dump || box64_dynarec_log)dynarec_log(LOG_NONE, "Abort dynablock on pass2\n");
|
||||
if(BOX64DRENV(dynarec_dump) || BOX64ENV(dynarec_log))dynarec_log(LOG_NONE, "Abort dynablock on pass2\n");
|
||||
CancelBlock64(0);
|
||||
return NULL;
|
||||
}
|
||||
@@ -720,14 +759,16 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
size_t insts_rsize = (helper.insts_size+2)*sizeof(instsize_t);
|
||||
insts_rsize = (insts_rsize+7)&~7; // round the size...
|
||||
size_t native_size = (helper.native_size+7)&~7; // round the size...
|
||||
size_t arch_size = ARCH_SIZE(&helper);
|
||||
// ok, now allocate mapped memory, with executable flag on
|
||||
size_t sz = sizeof(void*) + native_size + helper.table64size*sizeof(uint64_t) + 4*sizeof(void*) + insts_rsize;
|
||||
// dynablock_t* block (arm insts) table64 jmpnext code instsize
|
||||
size_t sz = sizeof(void*) + native_size + helper.table64size*sizeof(uint64_t) + 4*sizeof(void*) + insts_rsize + arch_size;
|
||||
// dynablock_t* block (arm insts) table64 jmpnext code instsize arch
|
||||
void* actual_p = (void*)AllocDynarecMap(sz);
|
||||
void* p = (void*)(((uintptr_t)actual_p) + sizeof(void*));
|
||||
void* tablestart = p + native_size;
|
||||
void* next = tablestart + helper.table64size*sizeof(uint64_t);
|
||||
void* instsize = next + 4*sizeof(void*);
|
||||
void* arch = instsize + insts_rsize;
|
||||
if(actual_p==NULL) {
|
||||
dynarec_log(LOG_INFO, "AllocDynarecMap(%p, %zu) failed, canceling block\n", block, sz);
|
||||
CancelBlock64(0);
|
||||
@@ -743,10 +784,13 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
helper.table64cap = helper.table64size;
|
||||
helper.table64 = (uint64_t*)helper.tablestart;
|
||||
// pass 3, emit (log emit native opcode)
|
||||
if(box64_dynarec_dump) {
|
||||
dynarec_log(LOG_NONE, "%s%04d|Emitting %zu bytes for %u %s bytes", (box64_dynarec_dump>1)?"\e[01;36m":"", GetTID(), helper.native_size, helper.isize, is32bits?"x86":"x64");
|
||||
if(BOX64DRENV(dynarec_dump)) {
|
||||
dynarec_log(LOG_NONE, "%s%04d|Emitting %zu bytes for %u %s bytes (native=%zu, table64=%zu, instsize=%zu, arch=%zu)", (BOX64DRENV(dynarec_dump)>1)?"\e[01;36m":"", GetTID(), helper.native_size, helper.isize, is32bits?"x86":"x64", native_size, helper.table64size*sizeof(uint64_t), insts_rsize, arch_size);
|
||||
printFunctionAddr(helper.start, " => ");
|
||||
dynarec_log(LOG_NONE, "%s\n", (box64_dynarec_dump>1)?"\e[m":"");
|
||||
dynarec_log(LOG_NONE, "%s\n", (BOX64DRENV(dynarec_dump)>1)?"\e[m":"");
|
||||
}
|
||||
if (BOX64ENV(dynarec_gdbjit) && (!BOX64ENV(dynarec_gdbjit_end) || (addr >= BOX64ENV(dynarec_gdbjit_start) && addr < BOX64ENV(dynarec_gdbjit_end)))) {
|
||||
GdbJITNewBlock(helper.gdbjit_block, (GDB_CORE_ADDR)block->actual_block, (GDB_CORE_ADDR)block->actual_block + native_size, helper.start);
|
||||
}
|
||||
int oldtable64size = helper.table64size;
|
||||
size_t oldnativesize = helper.native_size;
|
||||
@@ -757,7 +801,7 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
helper.insts_size = 0; // reset
|
||||
native_pass3(&helper, addr, alternate, is32bits);
|
||||
if(helper.abort) {
|
||||
if(box64_dynarec_dump || box64_dynarec_log)dynarec_log(LOG_NONE, "Abort dynablock on pass3\n");
|
||||
if(BOX64DRENV(dynarec_dump) || BOX64ENV(dynarec_log))dynarec_log(LOG_NONE, "Abort dynablock on pass3\n");
|
||||
CancelBlock64(0);
|
||||
return NULL;
|
||||
}
|
||||
@@ -776,13 +820,25 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
block->always_test = helper.always_test;
|
||||
block->dirty = block->always_test;
|
||||
block->is32bits = is32bits;
|
||||
if(arch_size) {
|
||||
block->arch_size = arch_size;
|
||||
block->arch = ARCH_FILL(&helper, arch, arch_size);
|
||||
if(!block->arch) block->arch_size = 0;
|
||||
} else {
|
||||
block->arch = NULL;
|
||||
block->arch_size = arch_size;
|
||||
}
|
||||
*(dynablock_t**)next = block;
|
||||
*(void**)(next+3*sizeof(void*)) = native_next;
|
||||
CreateJmpNext(block->jmpnext, next+3*sizeof(void*));
|
||||
ClearCache(block->jmpnext, 4*sizeof(void*));
|
||||
//block->x64_addr = (void*)start;
|
||||
block->x64_size = end-start;
|
||||
// all done...
|
||||
__clear_cache(actual_p, actual_p+sz); // need to clear the cache before execution...
|
||||
if (BOX64ENV(dynarec_gdbjit) && (!BOX64ENV(dynarec_gdbjit_end) || (addr >= BOX64ENV(dynarec_gdbjit_start) && addr < BOX64ENV(dynarec_gdbjit_end)))) {
|
||||
GdbJITBlockReady(helper.gdbjit_block);
|
||||
}
|
||||
ClearCache(actual_p+sizeof(void*), native_size); // need to clear the cache before execution...
|
||||
block->hash = X31_hash_code(block->x64_addr, block->x64_size);
|
||||
// Check if something changed, to abort if it is
|
||||
if((helper.abort || (block->hash != hash))) {
|
||||
@@ -791,17 +847,17 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
return NULL;
|
||||
}
|
||||
if((oldnativesize!=helper.native_size) || (oldtable64size<helper.table64size)) {
|
||||
printf_log(LOG_NONE, "BOX64: Warning, size difference in block between pass2 (%zu, %d) & pass3 (%zu, %d)!\n", oldnativesize+oldtable64size*8, oldsize, helper.native_size+helper.table64size*8, helper.size);
|
||||
printf_log(LOG_NONE, "Warning, size difference in block between pass2 (%zu, %d) & pass3 (%zu, %d)!\n", oldnativesize+oldtable64size*8, oldsize, helper.native_size+helper.table64size*8, helper.size);
|
||||
uint8_t *dump = (uint8_t*)helper.start;
|
||||
printf_log(LOG_NONE, "Dump of %d x64 opcodes:\n", helper.size);
|
||||
for(int i=0; i<helper.size; ++i) {
|
||||
printf_log(LOG_NONE, "%s%p:", (helper.insts[i].size2!=helper.insts[i].size)?"=====> ":"", dump);
|
||||
for(; dump<(uint8_t*)helper.insts[i+1].x64.addr; ++dump)
|
||||
printf_log(LOG_NONE, " %02X", *dump);
|
||||
printf_log(LOG_NONE, "\t%d -> %d", helper.insts[i].size2, helper.insts[i].size);
|
||||
printf_log_prefix(0, LOG_NONE, " %02X", *dump);
|
||||
printf_log_prefix(0, LOG_NONE, "\t%d -> %d", helper.insts[i].size2, helper.insts[i].size);
|
||||
if(helper.insts[i].ymm0_pass2 || helper.insts[i].ymm0_pass3)
|
||||
printf_log(LOG_NONE, "\t %04x -> %04x", helper.insts[i].ymm0_pass2, helper.insts[i].ymm0_pass3);
|
||||
printf_log(LOG_NONE, "\n");
|
||||
printf_log_prefix(0, LOG_NONE, "\t %04x -> %04x", helper.insts[i].ymm0_pass2, helper.insts[i].ymm0_pass3);
|
||||
printf_log_prefix(0, LOG_NONE, "\n");
|
||||
}
|
||||
printf_log(LOG_NONE, "Table64 \t%d -> %d\n", oldtable64size*8, helper.table64size*8);
|
||||
printf_log(LOG_NONE, " ------------\n");
|
||||
@@ -812,7 +868,7 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
//dynaFree(helper.insts);
|
||||
helper.insts = NULL;
|
||||
if(insts_rsize/sizeof(instsize_t)<helper.insts_size) {
|
||||
printf_log(LOG_NONE, "BOX64: Warning, insts_size difference in block between pass2 (%zu) and pass3 (%zu), allocated: %zu\n", oldinstsize, helper.insts_size, insts_rsize/sizeof(instsize_t));
|
||||
printf_log(LOG_NONE, "Warning, insts_size difference in block between pass2 (%zu) and pass3 (%zu), allocated: %zu\n", oldinstsize, helper.insts_size, insts_rsize/sizeof(instsize_t));
|
||||
}
|
||||
if(!isprotectedDB(addr, end-addr)) {
|
||||
dynarec_log(LOG_DEBUG, "Warning, block unprotected while being processed %p:%ld, marking as need_test\n", block->x64_addr, block->x64_size);
|
||||
@@ -830,3 +886,13 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
//block->done = 1;
|
||||
return (void*)block;
|
||||
}
|
||||
|
||||
void writePerfMap(uintptr_t func_addr, uintptr_t code_addr, size_t code_size, const char* inst_name)
|
||||
{
|
||||
char pbuf[128];
|
||||
uint64_t sz = 0;
|
||||
uintptr_t start = 0;
|
||||
const char* symbname = FindNearestSymbolName(FindElfAddress(my_context, func_addr), (void*)func_addr, &start, &sz);
|
||||
snprintf(pbuf, sizeof(pbuf), "0x%lx %ld %s:%s\n", code_addr, code_size, symbname, inst_name);
|
||||
write(BOX64ENV(dynarec_perf_map_fd), pbuf, strlen(pbuf));
|
||||
}
|
||||
@@ -42,7 +42,7 @@ void native_print_armreg(x64emu_t* emu, uintptr_t reg, uintptr_t n)
|
||||
|
||||
void native_f2xm1(x64emu_t* emu)
|
||||
{
|
||||
ST0.d = exp2(ST0.d) - 1.0;
|
||||
ST0.d = expm1(LN2 * ST0.d);
|
||||
}
|
||||
void native_fyl2x(x64emu_t* emu)
|
||||
{
|
||||
@@ -50,11 +50,14 @@ void native_fyl2x(x64emu_t* emu)
|
||||
}
|
||||
void native_ftan(x64emu_t* emu)
|
||||
{
|
||||
#pragma STDC FENV_ACCESS ON
|
||||
// seems that tan of glib doesn't follow the rounding direction mode
|
||||
ST0.d = tan(ST0.d);
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
}
|
||||
void native_fpatan(x64emu_t* emu)
|
||||
{
|
||||
#pragma STDC FENV_ACCESS ON
|
||||
ST1.d = atan2(ST1.d, ST0.d);
|
||||
}
|
||||
void native_fxtract(x64emu_t* emu)
|
||||
@@ -97,10 +100,12 @@ void native_fprem(x64emu_t* emu)
|
||||
}
|
||||
void native_fyl2xp1(x64emu_t* emu)
|
||||
{
|
||||
ST(1).d = log2(ST0.d + 1.0)*ST(1).d;
|
||||
ST(1).d = log1p(ST0.d)*ST(1).d/LN2;
|
||||
}
|
||||
void native_fsincos(x64emu_t* emu)
|
||||
{
|
||||
#pragma STDC FENV_ACCESS ON
|
||||
// seems that sincos of glib doesn't follow the rounding direction mode
|
||||
sincos(ST1.d, &ST1.d, &ST0.d);
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
}
|
||||
@@ -110,16 +115,21 @@ void native_frndint(x64emu_t* emu)
|
||||
}
|
||||
void native_fscale(x64emu_t* emu)
|
||||
{
|
||||
#pragma STDC FENV_ACCESS ON
|
||||
if(ST0.d!=0.0)
|
||||
ST0.d *= exp2(trunc(ST1.d));
|
||||
ST0.d = ldexp(ST0.d, trunc(ST1.d));
|
||||
}
|
||||
void native_fsin(x64emu_t* emu)
|
||||
{
|
||||
#pragma STDC FENV_ACCESS ON
|
||||
// seems that sin of glib doesn't follow the rounding direction mode
|
||||
ST0.d = sin(ST0.d);
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
}
|
||||
void native_fcos(x64emu_t* emu)
|
||||
{
|
||||
#pragma STDC FENV_ACCESS ON
|
||||
// seems that cos of glib doesn't follow the rounding direction mode
|
||||
ST0.d = cos(ST0.d);
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
}
|
||||
@@ -174,11 +184,18 @@ void native_fld(x64emu_t* emu, uint8_t* ed)
|
||||
|
||||
void native_ud(x64emu_t* emu)
|
||||
{
|
||||
if(box64_dynarec_test)
|
||||
if(BOX64ENV(dynarec_test))
|
||||
emu->test.test = 0;
|
||||
emit_signal(emu, SIGILL, (void*)R_RIP, 0);
|
||||
}
|
||||
|
||||
void native_br(x64emu_t* emu)
|
||||
{
|
||||
if(BOX64ENV(dynarec_test))
|
||||
emu->test.test = 0;
|
||||
emit_signal(emu, SIGSEGV, (void*)R_RIP, 0xb09d);
|
||||
}
|
||||
|
||||
void native_priv(x64emu_t* emu)
|
||||
{
|
||||
emu->test.test = 0;
|
||||
@@ -669,4 +686,33 @@ void propagate_nodf(dynarec_native_t* dyn, int ninst)
|
||||
dyn->insts[ninst].df_notneeded = 1;
|
||||
--ninst;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void x64disas_add_register_mapping_annotations(char* buf, const char* disas, const register_mapping_t* mappings, size_t mappings_sz)
|
||||
{
|
||||
static char tmp[32];
|
||||
tmp[0] = '\0';
|
||||
int len = 0;
|
||||
// skip the mnemonic
|
||||
char* p = strchr(disas, ' ');
|
||||
if (!p) {
|
||||
sprintf(buf, "%s", disas);
|
||||
return;
|
||||
}
|
||||
p++; // skip the space
|
||||
while (*p) {
|
||||
while (*p && !(*p >= 'a' && *p <= 'e') && *p != 's' && *p != 'r') // skip non-register characters
|
||||
p++;
|
||||
if (!*p) break;
|
||||
for (int i = 0; i < mappings_sz; ++i) {
|
||||
if (!strncmp(p, mappings[i].name, strlen(mappings[i].name))) {
|
||||
len += sprintf(tmp + len, " %s,", mappings[i].native);
|
||||
p += strlen(mappings[i].name) - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
p++;
|
||||
}
|
||||
if (tmp[0]) tmp[strlen(tmp) - 1] = '\0';
|
||||
sprintf(buf, "%-35s ;%s", disas, tmp);
|
||||
}
|
||||
@@ -53,6 +53,7 @@ void native_pclmul_y(x64emu_t* emu, int gy, int vy, void* p, uint32_t u8);
|
||||
void native_clflush(x64emu_t* emu, void* p);
|
||||
|
||||
void native_ud(x64emu_t* emu);
|
||||
void native_br(x64emu_t* emu);
|
||||
void native_priv(x64emu_t* emu);
|
||||
void native_singlestep(x64emu_t* emu);
|
||||
void native_int3(x64emu_t* emu);
|
||||
@@ -83,6 +84,13 @@ int is_avx_zero_unset(dynarec_native_t* dyn, int ninst, int reg);
|
||||
void avx_mark_zero_reset(dynarec_native_t* dyn, int ninst);
|
||||
void avx_unmark_zero(dynarec_native_t* dyn, int ninst, int reg);
|
||||
|
||||
typedef struct register_mapping_s {
|
||||
const char* name;
|
||||
const char* native;
|
||||
} register_mapping_t;
|
||||
|
||||
void x64disas_add_register_mapping_annotations(char* buf, const char* disas, const register_mapping_t* mappings, size_t mappings_sz);
|
||||
|
||||
ADDITIONNAL_DEFINITION()
|
||||
|
||||
#endif //__DYNAREC_NATIVE_FUNCTIONS_H__
|
||||
@@ -57,7 +57,7 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
ARCH_INIT();
|
||||
int reset_n = -1; // -1 no reset; -2 reset to 0; else reset to the state of reset_n
|
||||
dyn->last_ip = (alternate || (dyn->insts && dyn->insts[0].pred_sz))?0:ip; // RIP is always set at start of block unless there is a predecessor!
|
||||
int stopblock = 2+(FindElfAddress(my_context, addr)?0:1); // if block is in elf_memory, it can be extended with box64_dynarec_bigblock==2, else it needs 3
|
||||
int stopblock = 2 + ((FindElfAddress(my_context, addr) || IsAddrFileMapped(addr, NULL, NULL)) ? 0 : 1); // if block is in elf memory or file mapped memory, it can be extended with BOX64DRENV(dynarec_bigblock)==2, else it needs 3
|
||||
// ok, go now
|
||||
INIT;
|
||||
#if STEP == 0
|
||||
@@ -67,7 +67,7 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
#if STEP == 0
|
||||
if(cur_page != ((addr)&~(box64_pagesize-1))) {
|
||||
cur_page = (addr)&~(box64_pagesize-1);
|
||||
if(!(getProtection(addr)&PROT_READ)) {
|
||||
if(!(getProtection(addr)&PROT_READ) || checkInHotPage(addr)) {
|
||||
need_epilog = 1;
|
||||
break;
|
||||
}
|
||||
@@ -123,18 +123,21 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
WILLWRITE();
|
||||
}
|
||||
#endif
|
||||
if((dyn->insts[ninst].x64.need_before&~X_PEND) && !dyn->insts[ninst].pred_sz) {
|
||||
if((dyn->insts[ninst].x64.need_before&~X_PEND) && !ninst) {
|
||||
READFLAGS(dyn->insts[ninst].x64.need_before&~X_PEND);
|
||||
}
|
||||
if(box64_dynarec_test && (!box64_dynarec_test_end || (ip>=box64_dynarec_test_start && ip<box64_dynarec_test_end) )) {
|
||||
if(BOX64ENV(dynarec_test) && (!BOX64ENV(dynarec_test_end) || (ip>=BOX64ENV(dynarec_test_start) && ip<BOX64ENV(dynarec_test_end)))) {
|
||||
MESSAGE(LOG_DUMP, "TEST STEP ----\n");
|
||||
extcache_native_t save;
|
||||
fpu_save_and_unwind(dyn, ninst, &save);
|
||||
fpu_reflectcache(dyn, ninst, x1, x2, x3);
|
||||
GO_TRACE(x64test_step, 1, x5);
|
||||
fpu_unreflectcache(dyn, ninst, x1, x2, x3);
|
||||
fpu_unwind_restore(dyn, ninst, &save);
|
||||
MESSAGE(LOG_DUMP, "----------\n");
|
||||
}
|
||||
#ifdef HAVE_TRACE
|
||||
else if(my_context->dec && box64_dynarec_trace) {
|
||||
else if(my_context->dec && BOX64ENV(dynarec_trace)) {
|
||||
if((trace_end == 0)
|
||||
|| ((ip >= trace_start) && (ip < trace_end))) {
|
||||
MESSAGE(LOG_DUMP, "TRACE ----\n");
|
||||
@@ -176,7 +179,7 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
#if STEP > 0
|
||||
if(dyn->insts[ninst].x64.has_next && dyn->insts[next].x64.barrier) {
|
||||
if(dyn->insts[next].x64.barrier&BARRIER_FLOAT) {
|
||||
#ifdef RV64
|
||||
#if defined (RV64) || defined(LA64)
|
||||
uint8_t tmp1, tmp2, tmp3;
|
||||
if(dyn->insts[next].nat_flags_fusion) get_free_scratch(dyn, next, &tmp1, &tmp2, &tmp3, x1, x2, x3, x4, x5);
|
||||
else { tmp1=x1; tmp2=x2; tmp3=x3; }
|
||||
@@ -228,16 +231,17 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
}
|
||||
#else
|
||||
// check if block need to be stopped, because it's a 00 00 opcode (unreadeable is already checked earlier)
|
||||
if((ok>0) && !dyn->forward && !(*(uint8_t*)addr) && !(*(uint8_t*)(addr+1))) {
|
||||
if(box64_dynarec_dump) dynarec_log(LOG_NONE, "Stopping block at %p reason: %s\n", (void*)addr, "Next opcode is 00 00");
|
||||
if((ok>0) && !dyn->forward && !(*(uint32_t*)addr)) {
|
||||
if(BOX64DRENV(dynarec_dump)) dynarec_log(LOG_NONE, "Stopping block at %p reason: %s\n", (void*)addr, "Next opcode is 00 00 00 00");
|
||||
ok = 0;
|
||||
need_epilog = 1;
|
||||
dyn->insts[ninst].x64.need_after |= X_PEND;
|
||||
}
|
||||
if(dyn->forward) {
|
||||
if(dyn->forward_to == addr && !need_epilog && ok>=0) {
|
||||
// we made it!
|
||||
reset_n = get_first_jump_addr(dyn, addr);
|
||||
if(box64_dynarec_dump) dynarec_log(LOG_NONE, "Forward extend block for %d bytes %s%p -> %p (ninst %d - %d)\n", dyn->forward_to-dyn->forward, dyn->insts[dyn->forward_ninst].x64.has_callret?"(opt. call) ":"", (void*)dyn->forward, (void*)dyn->forward_to, reset_n, ninst);
|
||||
if(BOX64DRENV(dynarec_dump)) dynarec_log(LOG_NONE, "Forward extend block for %d bytes %s%p -> %p (ninst %d - %d)\n", dyn->forward_to-dyn->forward, dyn->insts[dyn->forward_ninst].x64.has_callret?"(opt. call) ":"", (void*)dyn->forward, (void*)dyn->forward_to, reset_n, ninst);
|
||||
if(dyn->insts[dyn->forward_ninst].x64.has_callret && !dyn->insts[dyn->forward_ninst].x64.has_next)
|
||||
dyn->insts[dyn->forward_ninst].x64.has_next = 1; // this block actually continue
|
||||
dyn->forward = 0;
|
||||
@@ -247,7 +251,7 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
ok = 1; // in case it was 0
|
||||
} else if ((dyn->forward_to < addr) || ok<=0) {
|
||||
// something when wrong! rollback
|
||||
if(box64_dynarec_dump) dynarec_log(LOG_NONE, "Could not forward extend block for %d bytes %p -> %p\n", dyn->forward_to-dyn->forward, (void*)dyn->forward, (void*)dyn->forward_to);
|
||||
if(BOX64DRENV(dynarec_dump)) dynarec_log(LOG_NONE, "Could not forward extend block for %d bytes %p -> %p\n", dyn->forward_to-dyn->forward, (void*)dyn->forward, (void*)dyn->forward_to);
|
||||
ok = 0;
|
||||
dyn->size = dyn->forward_size;
|
||||
ninst = dyn->forward_ninst;
|
||||
@@ -258,7 +262,7 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
dyn->forward_ninst = 0;
|
||||
}
|
||||
// else just continue
|
||||
} else if(!ok && !need_epilog && box64_dynarec_bigblock && (getProtection(addr+3)&~PROT_READ))
|
||||
} else if (!ok && !need_epilog && BOX64DRENV(dynarec_bigblock) && (getProtection(addr + 3) & ~PROT_READ))
|
||||
if(*(uint32_t*)addr!=0) { // check if need to continue (but is next 4 bytes are 0, stop)
|
||||
uintptr_t next = get_closest_next(dyn, addr);
|
||||
if(next && (
|
||||
@@ -273,9 +277,9 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
// and pred table is not ready yet
|
||||
reset_n = get_first_jump(dyn, next);
|
||||
}
|
||||
if(box64_dynarec_dump) dynarec_log(LOG_NONE, "Extend block %p, %s%p -> %p (ninst=%d, jump from %d)\n", dyn, dyn->insts[ninst].x64.has_callret?"(opt. call) ":"", (void*)addr, (void*)next, ninst+1, dyn->insts[ninst].x64.has_callret?ninst:reset_n);
|
||||
} else if(next && (int)(next-addr)<box64_dynarec_forward && (getProtection(next)&PROT_READ)/*box64_dynarec_bigblock>=stopblock*/) {
|
||||
if(!((box64_dynarec_bigblock<stopblock) && !isJumpTableDefault64((void*)next))) {
|
||||
if(BOX64DRENV(dynarec_dump)) dynarec_log(LOG_NONE, "Extend block %p, %s%p -> %p (ninst=%d, jump from %d)\n", dyn, dyn->insts[ninst].x64.has_callret?"(opt. call) ":"", (void*)addr, (void*)next, ninst+1, dyn->insts[ninst].x64.has_callret?ninst:reset_n);
|
||||
} else if (next && (int)(next - addr) < BOX64ENV(dynarec_forward) && (getProtection(next) & PROT_READ) /*BOX64DRENV(dynarec_bigblock)>=stopblock*/) {
|
||||
if (!((BOX64DRENV(dynarec_bigblock) < stopblock) && !isJumpTableDefault64((void*)next))) {
|
||||
if(dyn->forward) {
|
||||
if(next<dyn->forward_to)
|
||||
dyn->forward_to = next;
|
||||
@@ -323,9 +327,8 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
++ninst;
|
||||
#if STEP == 0
|
||||
memset(&dyn->insts[ninst], 0, sizeof(instruction_native_t));
|
||||
if((ok>0) && (((box64_dynarec_bigblock<stopblock) && !isJumpTableDefault64((void*)addr))
|
||||
|| (addr>=box64_nodynarec_start && addr<box64_nodynarec_end)))
|
||||
#else
|
||||
if ((ok > 0) && (((BOX64DRENV(dynarec_bigblock) < stopblock) && !isJumpTableDefault64((void*)addr)) || (addr >= BOX64ENV(nodynarec_start) && addr < BOX64ENV(nodynarec_end))))
|
||||
#else
|
||||
if((ok>0) && (ninst==dyn->size))
|
||||
#endif
|
||||
{
|
||||
@@ -341,10 +344,8 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
dyn->forward_ninst = 0;
|
||||
}
|
||||
#endif
|
||||
int j32;
|
||||
MAYUSE(j32);
|
||||
MESSAGE(LOG_DEBUG, "Stopping block %p (%d / %d)\n",(void*)init_addr, ninst, dyn->size);
|
||||
if(!box64_dynarec_dump && addr>=box64_nodynarec_start && addr<box64_nodynarec_end)
|
||||
if(!BOX64DRENV(dynarec_dump) && addr>=BOX64ENV(nodynarec_start) && addr<BOX64ENV(nodynarec_end))
|
||||
dynarec_log(LOG_INFO, "Stopping block in no-dynarec zone\n");
|
||||
--ninst;
|
||||
if(!dyn->insts[ninst].x64.barrier) {
|
||||
|
||||
@@ -39,7 +39,7 @@ typedef struct instruction_x64_s {
|
||||
int jmp_insts; // instuction to jump to (-1 if out of the block)
|
||||
uint8_t jmp_cond:1; // 1 of conditionnal jump
|
||||
uint8_t has_next:1; // does this opcode can continue to the next?
|
||||
uint8_t has_callret:1; // this instruction have an optimised call setup
|
||||
uint8_t has_callret:1; // this instruction have an optimized call setup
|
||||
uint8_t alive:1; // this opcode gets executed (0 if dead code in that block)
|
||||
uint8_t barrier; // next instruction is a jump point, so no optim allowed
|
||||
uint8_t state_flags;// One of SF_XXX state
|
||||
@@ -51,6 +51,4 @@ typedef struct instruction_x64_s {
|
||||
uint8_t need_after; // calculated
|
||||
} instruction_x64_t;
|
||||
|
||||
void printf_x64_instruction(zydis_dec_t* dec, instruction_x64_t* inst, const char* name);
|
||||
|
||||
#endif //__DYNAREC_PRIVATE_H_
|
||||
+517
-239
File diff suppressed because it is too large.
Load diff
+340
-124
@@ -37,6 +37,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
uint8_t wb1, wback, wb2, gback;
|
||||
uint8_t eb1, eb2;
|
||||
uint8_t gb1, gb2;
|
||||
uint8_t tmp1, tmp2, tmp3;
|
||||
int32_t i32, i32_;
|
||||
int cacheupd = 0;
|
||||
int v0, v1;
|
||||
@@ -63,8 +64,8 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 0x01:
|
||||
// TODO:, /0 is SGDT. While 0F 01 D0 is XGETBV, etc...
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
switch(nextop) {
|
||||
if (MODREG) {
|
||||
switch (nextop) {
|
||||
case 0xD0:
|
||||
INST_NAME("XGETBV");
|
||||
BEQZ_MARK(xRCX);
|
||||
@@ -77,7 +78,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
DEFAULT;
|
||||
}
|
||||
} else {
|
||||
switch((nextop>>3)&7) {
|
||||
switch ((nextop >> 3) & 7) {
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
@@ -101,7 +102,11 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
break;
|
||||
case 0x0B:
|
||||
INST_NAME("UD2");
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
if (BOX64DRENV(dynarec_safeflags) > 1) {
|
||||
READFLAGS(X_PEND);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION); // Hack to set flags in "don't care" state
|
||||
}
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL();
|
||||
CALL(native_ud, -1);
|
||||
@@ -171,7 +176,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
nextop = F8;
|
||||
INST_NAME("MOVLPS Ex,Gx");
|
||||
GETGX(v0, 0);
|
||||
if(MODREG) {
|
||||
if (MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop & 7) + (rex.b << 3), 1);
|
||||
VEXTRINS_D(v1, v0, 0);
|
||||
} else {
|
||||
@@ -216,20 +221,18 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
nextop = F8;
|
||||
INST_NAME("MOVHPS Ex,Gx");
|
||||
GETGX(v0, 0);
|
||||
if(MODREG) {
|
||||
if (MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop & 7) + (rex.b << 3), 1);
|
||||
VEXTRINS_D(v1, v0, 0x01);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x3, &fixedaddress, rex, NULL, 1, 0);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
VEXTRINS_D(v1, v0, 0x01);
|
||||
FST_D(v1, ed, fixedaddress);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x3, &fixedaddress, rex, NULL, 0, 0);
|
||||
VSTELM_D(v0, ed, 0, 1);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x18:
|
||||
nextop = F8;
|
||||
if ((nextop & 0xC0) == 0xC0) {
|
||||
if (MODREG) {
|
||||
INST_NAME("NOP (multibyte)");
|
||||
} else
|
||||
switch ((nextop >> 3) & 7) {
|
||||
@@ -245,6 +248,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
FAKEED;
|
||||
}
|
||||
break;
|
||||
case 0x19:
|
||||
case 0x1F:
|
||||
INST_NAME("NOP (multibyte)");
|
||||
nextop = F8;
|
||||
@@ -303,7 +307,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
INST_NAME("UCOMISS Gx, Ex");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETGX(d0, 0);
|
||||
@@ -339,8 +343,11 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 0x31:
|
||||
INST_NAME("RDTSC");
|
||||
NOTEST(x1);
|
||||
// TODO: how to read the wall-clock real time on LoongArch?
|
||||
CALL(ReadTSC, x3); // will return the u64 in x3
|
||||
if (box64_rdtsc) {
|
||||
CALL(ReadTSC, x3); // will return the u64 in x3
|
||||
} else {
|
||||
RDTIME_D(x3, xZR);
|
||||
}
|
||||
if (box64_rdtsc_shift) {
|
||||
SRLI_D(x3, x3, box64_rdtsc_shift);
|
||||
}
|
||||
@@ -410,40 +417,102 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0xF0:
|
||||
INST_NAME("MOVBE Gd, Ed");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
LDxw(gd, ed, fixedaddress);
|
||||
if (rex.w) {
|
||||
REVB_D(gd, gd);
|
||||
} else {
|
||||
REVB_2W(gd, gd);
|
||||
ZEROUP(gd);
|
||||
}
|
||||
break;
|
||||
case 0xF1:
|
||||
INST_NAME("MOVBE Ed, Gd");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
if (rex.w)
|
||||
REVB_D(x1, gd);
|
||||
else
|
||||
REVB_2W(x1, gd);
|
||||
SDxw(x1, wback, fixedaddress);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0x3A: // more SSE3 opcodes
|
||||
opcode = F8;
|
||||
switch (opcode) {
|
||||
case 0xCC:
|
||||
INST_NAME("SHA1RNDS4 Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
if (MODREG) {
|
||||
ed = (nextop & 7) + (rex.b << 3);
|
||||
sse_reflect_reg(dyn, ninst, ed);
|
||||
ADDI_D(x2, xEmu, offsetof(x64emu_t, xmm[ed]));
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, NULL, 0, 1);
|
||||
if (wback != x2) MV(x2, wback);
|
||||
}
|
||||
u8 = F8;
|
||||
GETG;
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
ADDI_D(x1, xEmu, offsetof(x64emu_t, xmm[gd]));
|
||||
MOV32w(x3, u8);
|
||||
CALL(sha1rnds4, -1);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
#define GO(GETFLAGS, NO, YES, F, I) \
|
||||
READFLAGS(F); \
|
||||
if (la64_lbt) { \
|
||||
X64_SETJ(x1, I); \
|
||||
} else { \
|
||||
GETFLAGS; \
|
||||
} \
|
||||
nextop = F8; \
|
||||
GETGD; \
|
||||
if (MODREG) { \
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3)); \
|
||||
if (la64_lbt) \
|
||||
BEQZ(x1, 8); \
|
||||
else \
|
||||
B##NO(x1, 8); \
|
||||
MV(gd, ed); \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x4, &fixedaddress, rex, NULL, 1, 0); \
|
||||
if (la64_lbt) \
|
||||
BEQZ(x1, 8); \
|
||||
else \
|
||||
B##NO(x1, 8); \
|
||||
LDxw(gd, ed, fixedaddress); \
|
||||
} \
|
||||
if (!rex.w) ZEROUP(gd);
|
||||
#define GO(GETFLAGS, NO, YES, NATNO, NATYES, F, I) \
|
||||
READFLAGS_FUSION(F, x1, x2, x3, x4, x5); \
|
||||
if (!dyn->insts[ninst].nat_flags_fusion) { \
|
||||
if (la64_lbt) { \
|
||||
X64_SETJ(tmp1, I); \
|
||||
} else { \
|
||||
GETFLAGS; \
|
||||
} \
|
||||
} \
|
||||
nextop = F8; \
|
||||
GETGD; \
|
||||
if (MODREG) { \
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3)); \
|
||||
if (dyn->insts[ninst].nat_flags_fusion) { \
|
||||
NATIVEJUMP(NATNO, 8); \
|
||||
} else { \
|
||||
if (la64_lbt) \
|
||||
BEQZ(tmp1, 8); \
|
||||
else \
|
||||
B##NO(tmp1, 8); \
|
||||
} \
|
||||
MV(gd, ed); \
|
||||
if (!rex.w) ZEROUP(gd); \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, tmp2, tmp3, &fixedaddress, rex, NULL, 1, 0); \
|
||||
if (dyn->insts[ninst].nat_flags_fusion) { \
|
||||
NATIVEJUMP(NATNO, 8); \
|
||||
} else { \
|
||||
if (la64_lbt) \
|
||||
BEQZ(tmp1, 8); \
|
||||
else \
|
||||
B##NO(tmp1, 8); \
|
||||
} \
|
||||
LDxw(gd, ed, fixedaddress); \
|
||||
}
|
||||
|
||||
GOCOND(0x40, "CMOV", "Gd, Ed");
|
||||
|
||||
#undef GO
|
||||
#undef GO
|
||||
|
||||
case 0x50:
|
||||
INST_NAME("MOVMSPKPS Gd, Ex");
|
||||
@@ -525,8 +594,22 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("MULPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX(v0, 1);
|
||||
VFMUL_S(v0, v0, q0);
|
||||
GETGX(q1, 1);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
VFCMP_S(v0, q0, q1, cUN);
|
||||
}
|
||||
VFMUL_S(q1, q1, q0);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
VFCMP_S(v1, q1, q1, cUN);
|
||||
VANDN_V(v0, v0, v1);
|
||||
VLDI(v1, 0b011111111100); // broadcast 0xFFFFFFFFFFFFFFFC
|
||||
VSLLI_W(v1, v1, 20);
|
||||
VAND_V(v1, v0, v1);
|
||||
VANDN_V(v0, v0, q1);
|
||||
VOR_V(q1, v0, v1);
|
||||
}
|
||||
break;
|
||||
case 0x5A:
|
||||
INST_NAME("CVTPS2PD Gx, Ex");
|
||||
@@ -546,15 +629,29 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("SUBPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX(v0, 1);
|
||||
VFSUB_S(v0, v0, q0);
|
||||
GETGX(q1, 1);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
VFCMP_S(v0, q0, q1, cUN);
|
||||
}
|
||||
VFSUB_S(q1, q1, q0);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
VFCMP_S(v1, q1, q1, cUN);
|
||||
VANDN_V(v0, v0, v1);
|
||||
VLDI(v1, 0b011111111100); // broadcast 0xFFFFFFFFFFFFFFFC
|
||||
VSLLI_W(v1, v1, 20);
|
||||
VAND_V(v1, v0, v1);
|
||||
VANDN_V(v0, v0, q1);
|
||||
VOR_V(q1, v0, v1);
|
||||
}
|
||||
break;
|
||||
case 0x5D:
|
||||
INST_NAME("MINPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
if (!box64_dynarec_fastnan && v0 != v1) {
|
||||
if (!BOX64ENV(dynarec_fastnan) && v0 != v1) {
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
// always copy from v1 if any oprand is NaN
|
||||
VFCMP_S(q0, v0, v1, cUN);
|
||||
@@ -568,15 +665,29 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("DIVPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX(v0, 1);
|
||||
VFDIV_S(v0, v0, q0);
|
||||
GETGX(q1, 1);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
VFCMP_S(v0, q0, q1, cUN);
|
||||
}
|
||||
VFDIV_S(q1, q1, q0);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
VFCMP_S(v1, q1, q1, cUN);
|
||||
VANDN_V(v0, v0, v1);
|
||||
VLDI(v1, 0b011111111100); // broadcast 0xFFFFFFFFFFFFFFFC
|
||||
VSLLI_W(v1, v1, 20);
|
||||
VAND_V(v1, v0, v1);
|
||||
VANDN_V(v0, v0, q1);
|
||||
VOR_V(q1, v0, v1);
|
||||
}
|
||||
break;
|
||||
case 0x5F:
|
||||
INST_NAME("MAXPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
if (!box64_dynarec_fastnan && v0 != v1) {
|
||||
if (!BOX64ENV(dynarec_fastnan) && v0 != v1) {
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
// always copy from v1 if any oprand is NaN
|
||||
VFCMP_S(q0, v0, v1, cUN);
|
||||
@@ -587,52 +698,64 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
VFMAX_S(v0, v0, v1);
|
||||
break;
|
||||
|
||||
#define GO(GETFLAGS, NO, YES, F, I) \
|
||||
READFLAGS(F); \
|
||||
i32_ = F32S; \
|
||||
if(rex.is32bits) \
|
||||
j64 = (uint32_t)(addr+i32_); \
|
||||
else \
|
||||
j64 = addr+i32_; \
|
||||
BARRIER(BARRIER_MAYBE); \
|
||||
JUMP(j64, 1); \
|
||||
if (la64_lbt) { \
|
||||
X64_SETJ(x1, I); \
|
||||
} else { \
|
||||
GETFLAGS; \
|
||||
} \
|
||||
if (dyn->insts[ninst].x64.jmp_insts == -1 || CHECK_CACHE()) { \
|
||||
/* out of the block */ \
|
||||
i32 = dyn->insts[ninst].epilog - (dyn->native_size); \
|
||||
if (la64_lbt) \
|
||||
BEQZ_safe(x1, i32); \
|
||||
else \
|
||||
B##NO##_safe(x1, i32); \
|
||||
if (dyn->insts[ninst].x64.jmp_insts == -1) { \
|
||||
if (!(dyn->insts[ninst].x64.barrier & BARRIER_FLOAT)) \
|
||||
fpu_purgecache(dyn, ninst, 1, x1, x2, x3); \
|
||||
jump_to_next(dyn, j64, 0, ninst, rex.is32bits); \
|
||||
} else { \
|
||||
CacheTransform(dyn, ninst, cacheupd, x1, x2, x3); \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address - (dyn->native_size); \
|
||||
B(i32); \
|
||||
} \
|
||||
} else { \
|
||||
/* inside the block */ \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address - (dyn->native_size); \
|
||||
if (la64_lbt) \
|
||||
BNEZ_safe(x1, i32); \
|
||||
else \
|
||||
B##YES##_safe(x1, i32); \
|
||||
}
|
||||
#define GO(GETFLAGS, NO, YES, NATNO, NATYES, F, I) \
|
||||
READFLAGS_FUSION(F, x1, x2, x3, x4, x5); \
|
||||
i32_ = F32S; \
|
||||
if (rex.is32bits) \
|
||||
j64 = (uint32_t)(addr + i32_); \
|
||||
else \
|
||||
j64 = addr + i32_; \
|
||||
BARRIER(BARRIER_MAYBE); \
|
||||
JUMP(j64, 1); \
|
||||
if (!dyn->insts[ninst].nat_flags_fusion) { \
|
||||
if (la64_lbt) { \
|
||||
X64_SETJ(x1, I); \
|
||||
} else { \
|
||||
GETFLAGS; \
|
||||
} \
|
||||
} \
|
||||
if (dyn->insts[ninst].x64.jmp_insts == -1 || CHECK_CACHE()) { \
|
||||
/* out of the block */ \
|
||||
i32 = dyn->insts[ninst].epilog - (dyn->native_size); \
|
||||
if (dyn->insts[ninst].nat_flags_fusion) { \
|
||||
NATIVEJUMP_safe(NATNO, i32); \
|
||||
} else { \
|
||||
if (la64_lbt) \
|
||||
BEQZ_safe(x1, i32); \
|
||||
else \
|
||||
B##NO##_safe(x1, i32); \
|
||||
} \
|
||||
if (dyn->insts[ninst].x64.jmp_insts == -1) { \
|
||||
if (!(dyn->insts[ninst].x64.barrier & BARRIER_FLOAT)) \
|
||||
fpu_purgecache(dyn, ninst, 1, tmp1, tmp2, tmp3); \
|
||||
jump_to_next(dyn, j64, 0, ninst, rex.is32bits); \
|
||||
} else { \
|
||||
CacheTransform(dyn, ninst, cacheupd, tmp1, tmp2, tmp3); \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address - (dyn->native_size); \
|
||||
B(i32); \
|
||||
} \
|
||||
} else { \
|
||||
/* inside the block */ \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address - (dyn->native_size); \
|
||||
if (dyn->insts[ninst].nat_flags_fusion) { \
|
||||
NATIVEJUMP_safe(NATYES, i32); \
|
||||
} else { \
|
||||
if (la64_lbt) \
|
||||
BNEZ_safe(tmp1, i32); \
|
||||
else \
|
||||
B##YES##_safe(tmp1, i32); \
|
||||
} \
|
||||
}
|
||||
|
||||
GOCOND(0x80, "J", "Id");
|
||||
|
||||
#undef GO
|
||||
#undef GO
|
||||
|
||||
|
||||
#define GO(GETFLAGS, NO, YES, F, I) \
|
||||
#define GO(GETFLAGS, NO, YES, NATNO, NATYES, F, I) \
|
||||
READFLAGS(F); \
|
||||
tmp1 = x1; \
|
||||
tmp3 = x3; \
|
||||
if (la64_lbt) { \
|
||||
X64_SETJ(x3, I); \
|
||||
} else { \
|
||||
@@ -657,7 +780,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
}
|
||||
|
||||
GOCOND(0x90, "SET", "Eb");
|
||||
#undef GO
|
||||
#undef GO
|
||||
|
||||
case 0xA2:
|
||||
INST_NAME("CPUID");
|
||||
@@ -670,7 +793,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
break;
|
||||
case 0xA3:
|
||||
INST_NAME("BT Ed, Gd");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
@@ -684,18 +807,20 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
LDxw(x1, x3, fixedaddress);
|
||||
ed = x1;
|
||||
}
|
||||
ANDI(x2, gd, rex.w ? 0x3f : 0x1f);
|
||||
SRLxw(x4, ed, x2);
|
||||
if (la64_lbt)
|
||||
X64_SET_EFLAGS(x4, X_CF);
|
||||
else
|
||||
BSTRINS_D(xFlags, x4, F_CF, F_CF);
|
||||
if (X_CF) {
|
||||
ANDI(x2, gd, rex.w ? 0x3f : 0x1f);
|
||||
SRLxw(x4, ed, x2);
|
||||
if (la64_lbt)
|
||||
X64_SET_EFLAGS(x4, X_CF);
|
||||
else
|
||||
BSTRINS_D(xFlags, x4, F_CF, F_CF);
|
||||
}
|
||||
break;
|
||||
case 0xA4:
|
||||
nextop = F8;
|
||||
INST_NAME("SHLD Ed, Gd, Ib");
|
||||
if (geted_ib(dyn, addr, ninst, nextop)) {
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETED(1);
|
||||
GETGD;
|
||||
u8 = F8;
|
||||
@@ -708,7 +833,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
break;
|
||||
case 0xAB:
|
||||
INST_NAME("BTS Ed, Gd");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
@@ -747,7 +872,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
nextop = F8;
|
||||
INST_NAME("SHRD Ed, Gd, Ib");
|
||||
if (geted_ib(dyn, addr, ninst, nextop)) {
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETED(1);
|
||||
GETGD;
|
||||
u8 = F8;
|
||||
@@ -806,7 +931,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("LDMXCSR Md");
|
||||
GETED(0);
|
||||
ST_W(ed, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
if (box64_sse_flushto0) {
|
||||
if (BOX64ENV(sse_flushto0)) {
|
||||
// TODO
|
||||
}
|
||||
break;
|
||||
@@ -820,27 +945,25 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("XSAVE Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, x2, &fixedaddress, rex, NULL, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x2, &fixedaddress, rex, NULL, 0, 0);
|
||||
if (ed != x1) { MV(x1, ed); }
|
||||
MOV32w(x2, rex.w?0:1);
|
||||
MOV32w(x2, rex.w ? 0 : 1);
|
||||
CALL((void*)fpu_xsave, -1);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("XRSTOR Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, x2, &fixedaddress, rex, NULL, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x2, &fixedaddress, rex, NULL, 0, 0);
|
||||
if (ed != x1) { MV(x1, ed); }
|
||||
MOV32w(x2, rex.w?0:1);
|
||||
MOV32w(x2, rex.w ? 0 : 1);
|
||||
CALL((void*)fpu_xrstor, -1);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("CLFLUSH Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization?\n");
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, x2, &fixedaddress, rex, NULL, 0, 0);
|
||||
if (wback != A1) {
|
||||
MV(A1, wback);
|
||||
}
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x2, &fixedaddress, rex, NULL, 0, 0);
|
||||
if (ed != x1) { MV(x1, ed); }
|
||||
CALL_(native_clflush, -1, 0);
|
||||
break;
|
||||
default:
|
||||
@@ -849,11 +972,11 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
break;
|
||||
case 0xAF:
|
||||
INST_NAME("IMUL Gd, Ed");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
SETFLAGS(X_ALL, SF_PENDING, NAT_FLAGS_NOFUSION);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED(0);
|
||||
if (box64_dynarec_test) {
|
||||
if (BOX64ENV(dynarec_test)) {
|
||||
// avoid noise during test
|
||||
CLEAR_FLAGS(x3);
|
||||
}
|
||||
@@ -921,6 +1044,38 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
ZEROUP(gd);
|
||||
}
|
||||
break;
|
||||
case 0xB3:
|
||||
INST_NAME("BTR Ed, Gd");
|
||||
SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
wback = 0;
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
SRAIxw(x1, gd, 5 + rex.w);
|
||||
ADDSL(x3, wback, x1, 2 + rex.w, x1);
|
||||
LDxw(x1, x3, fixedaddress);
|
||||
ed = x1;
|
||||
wback = x3;
|
||||
}
|
||||
ANDI(x2, gd, rex.w ? 0x3f : 0x1f);
|
||||
SRL_D(x4, ed, x2);
|
||||
BSTRINS_D(xFlags, x4, 0, 0);
|
||||
ADDI_D(x4, xZR, 1);
|
||||
ANDI(x2, gd, rex.w ? 0x3f : 0x1f);
|
||||
SLL_D(x4, x4, x2);
|
||||
ANDN(ed, ed, x4);
|
||||
if (wback) {
|
||||
SDxw(ed, wback, fixedaddress);
|
||||
SMWRITE();
|
||||
} else if (!rex.w) {
|
||||
ZEROUP(ed);
|
||||
}
|
||||
break;
|
||||
case 0xB6:
|
||||
INST_NAME("MOVZX Gd, Eb");
|
||||
nextop = F8;
|
||||
@@ -931,8 +1086,8 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
eb2 = 0;
|
||||
} else {
|
||||
ed = (nextop & 7);
|
||||
eb1 = TO_NAT(ed & 3); // Ax, Cx, Dx or Bx
|
||||
eb2 = (ed & 4) >> 2; // L or H
|
||||
eb1 = TO_NAT(ed & 3); // Ax, Cx, Dx or Bx
|
||||
eb2 = (ed & 4) >> 2; // L or H
|
||||
}
|
||||
BSTRPICK_D(gd, eb1, eb2 * 8 + 7, eb2 * 8);
|
||||
} else {
|
||||
@@ -959,7 +1114,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
switch ((nextop >> 3) & 7) {
|
||||
case 4:
|
||||
INST_NAME("BT Ed, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
SET_DFNONE();
|
||||
GETED(1);
|
||||
u8 = F8;
|
||||
@@ -972,7 +1127,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("BTS Ed, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
SET_DFNONE();
|
||||
GETED(1);
|
||||
u8 = F8;
|
||||
@@ -990,11 +1145,10 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else if (!rex.w) {
|
||||
ZEROUP(ed);
|
||||
}
|
||||
MARK;
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("BTR Ed, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
SET_DFNONE();
|
||||
GETED(1);
|
||||
u8 = F8;
|
||||
@@ -1011,11 +1165,10 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else if (!rex.w) {
|
||||
ZEROUP(ed);
|
||||
}
|
||||
MARK;
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("BTC Ed, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
SET_DFNONE();
|
||||
GETED(1);
|
||||
u8 = F8;
|
||||
@@ -1039,9 +1192,43 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0xBB:
|
||||
INST_NAME("BTC Ed, Gd");
|
||||
SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
wback = 0;
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
SRAIxw(x1, gd, 5 + rex.w);
|
||||
ADDSL(x3, wback, x1, 2 + rex.w, x1);
|
||||
LDxw(x1, x3, fixedaddress);
|
||||
ed = x1;
|
||||
wback = x3;
|
||||
}
|
||||
ANDI(x2, gd, rex.w ? 0x3f : 0x1f);
|
||||
SRL_D(x4, ed, x2);
|
||||
if (la64_lbt)
|
||||
X64_SET_EFLAGS(x4, X_CF);
|
||||
else
|
||||
BSTRINS_D(xFlags, x4, F_CF, F_CF);
|
||||
ADDI_D(x4, xZR, 1);
|
||||
SLL_D(x4, x4, x2);
|
||||
XOR(ed, ed, x4);
|
||||
if (wback) {
|
||||
SDxw(ed, wback, fixedaddress);
|
||||
SMWRITE();
|
||||
} else if (!rex.w) {
|
||||
ZEROUP(ed);
|
||||
}
|
||||
break;
|
||||
case 0xBC:
|
||||
INST_NAME("BSF Gd, Ed");
|
||||
SETFLAGS(X_ZF, SF_SUBSET);
|
||||
SETFLAGS(X_ZF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
@@ -1067,13 +1254,12 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
if (la64_lbt) {
|
||||
X64_SET_EFLAGS(xZR, X_ZF);
|
||||
} else {
|
||||
ADDI_D(x3, xZR, ~(1 << F_ZF));
|
||||
AND(xFlags, xFlags, x3);
|
||||
BSTRINS_D(xFlags, xZR, F_ZF, F_ZF);
|
||||
}
|
||||
break;
|
||||
case 0xBD:
|
||||
INST_NAME("BSR Gd, Ed");
|
||||
SETFLAGS(X_ZF, SF_SUBSET);
|
||||
SETFLAGS(X_ZF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
@@ -1094,8 +1280,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
if (la64_lbt) {
|
||||
X64_SET_EFLAGS(xZR, X_ZF);
|
||||
} else {
|
||||
ADDI_D(x3, xZR, ~(1 << F_ZF));
|
||||
AND(xFlags, xFlags, x3);
|
||||
BSTRINS_D(xFlags, xZR, F_ZF, F_ZF);
|
||||
}
|
||||
if (rex.w)
|
||||
CLZ_D(gd, ed);
|
||||
@@ -1157,6 +1342,17 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 7: VFCMP_S(v0, v0, v1, cOR); break; // not NaN
|
||||
}
|
||||
break;
|
||||
case 0xC3:
|
||||
INST_NAME("MOVNTI Ed, Gd");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if (MODREG) {
|
||||
MVxw(TO_NAT((nextop & 7) + (rex.b << 3)), gd);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
SDxw(gd, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0xC6:
|
||||
INST_NAME("SHUFPS Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
@@ -1172,6 +1368,26 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
VEXTRINS_D(v0, q1, 0x11); // v0[127:64] = q1[127:64]
|
||||
}
|
||||
break;
|
||||
case 0xC7:
|
||||
// rep has no impact here
|
||||
nextop = F8;
|
||||
if (MODREG) {
|
||||
switch ((nextop >> 3) & 7) {
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
} else {
|
||||
switch ((nextop >> 3) & 7) {
|
||||
case 4:
|
||||
INST_NAME("Unsupported XSAVEC Ed");
|
||||
FAKEED;
|
||||
UDF();
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
case 0xCA:
|
||||
|
||||
@@ -63,27 +63,50 @@ uintptr_t dynarec64_64(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
switch (opcode) {
|
||||
case 0x03:
|
||||
INST_NAME("ADD Gd, Seg:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
nextop = F8;
|
||||
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
|
||||
GETGD;
|
||||
GETEDO(x4, 0);
|
||||
emit_add32(dyn, ninst, rex, gd, ed, x3, x4, x5);
|
||||
break;
|
||||
case 0x0B:
|
||||
INST_NAME("OR Gd, Seg:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
nextop = F8;
|
||||
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
|
||||
GETGD;
|
||||
GETEDO(x4, 0);
|
||||
emit_or32(dyn, ninst, rex, gd, ed, x3, x4);
|
||||
break;
|
||||
case 0x0F:
|
||||
opcode = F8;
|
||||
switch (opcode) {
|
||||
case 0x18:
|
||||
case 0x19:
|
||||
case 0x1F:
|
||||
INST_NAME("NOP (multibyte)");
|
||||
nextop = F8;
|
||||
FAKEED;
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0x2B:
|
||||
INST_NAME("SUB Gd, Seg:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
nextop = F8;
|
||||
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
|
||||
GETGD;
|
||||
GETEDO(x4, 0);
|
||||
emit_sub32(dyn, ninst, rex, gd, ed, x3, x4, x5);
|
||||
break;
|
||||
case 0x33:
|
||||
INST_NAME("XOR Gd, Seg:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
nextop = F8;
|
||||
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
|
||||
GETGD;
|
||||
GETEDO(x4, 0);
|
||||
emit_xor32(dyn, ninst, rex, gd, ed, x3, x4);
|
||||
@@ -102,8 +125,8 @@ uintptr_t dynarec64_64(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
switch ((nextop >> 3) & 7) {
|
||||
case 0: // ADD
|
||||
INST_NAME("ADD Eb, Ib");
|
||||
grab_segdata(dyn, addr, ninst, x1, seg);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_segdata(dyn, addr, ninst, x1, seg, (MODREG));
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETEBO(x1, 1);
|
||||
u8 = F8;
|
||||
emit_add8c(dyn, ninst, x1, u8, x2, x4, x5);
|
||||
@@ -111,8 +134,8 @@ uintptr_t dynarec64_64(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
break;
|
||||
case 1: // OR
|
||||
INST_NAME("OR Eb, Ib");
|
||||
grab_segdata(dyn, addr, ninst, x1, seg);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_segdata(dyn, addr, ninst, x1, seg, (MODREG));
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETEBO(x1, 1);
|
||||
u8 = F8;
|
||||
emit_or8c(dyn, ninst, x1, u8, x2, x4, x5);
|
||||
@@ -120,9 +143,9 @@ uintptr_t dynarec64_64(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
break;
|
||||
case 2: // ADC
|
||||
INST_NAME("ADC Eb, Ib");
|
||||
grab_segdata(dyn, addr, ninst, x1, seg);
|
||||
grab_segdata(dyn, addr, ninst, x1, seg, (MODREG));
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETEBO(x1, 1);
|
||||
u8 = F8;
|
||||
emit_adc8c(dyn, ninst, x1, u8, x2, x4, x5, x6);
|
||||
@@ -130,9 +153,9 @@ uintptr_t dynarec64_64(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
break;
|
||||
case 3: // SBB
|
||||
INST_NAME("SBB Eb, Ib");
|
||||
grab_segdata(dyn, addr, ninst, x1, seg);
|
||||
grab_segdata(dyn, addr, ninst, x1, seg, (MODREG));
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETEBO(x1, 1);
|
||||
u8 = F8;
|
||||
emit_sbb8c(dyn, ninst, x1, u8, x2, x4, x5, x6);
|
||||
@@ -140,8 +163,8 @@ uintptr_t dynarec64_64(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
break;
|
||||
case 4: // AND
|
||||
INST_NAME("AND Eb, Ib");
|
||||
grab_segdata(dyn, addr, ninst, x1, seg);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_segdata(dyn, addr, ninst, x1, seg, (MODREG));
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETEBO(x1, 1);
|
||||
u8 = F8;
|
||||
emit_and8c(dyn, ninst, x1, u8, x2, x4);
|
||||
@@ -149,8 +172,8 @@ uintptr_t dynarec64_64(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
break;
|
||||
case 5: // SUB
|
||||
INST_NAME("SUB Eb, Ib");
|
||||
grab_segdata(dyn, addr, ninst, x1, seg);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_segdata(dyn, addr, ninst, x1, seg, (MODREG));
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETEBO(x1, 1);
|
||||
u8 = F8;
|
||||
emit_sub8c(dyn, ninst, x1, u8, x2, x4, x5, x6);
|
||||
@@ -158,8 +181,8 @@ uintptr_t dynarec64_64(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
break;
|
||||
case 6: // XOR
|
||||
INST_NAME("XOR Eb, Ib");
|
||||
grab_segdata(dyn, addr, ninst, x1, seg);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_segdata(dyn, addr, ninst, x1, seg, (MODREG));
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETEBO(x1, 1);
|
||||
u8 = F8;
|
||||
emit_xor8c(dyn, ninst, x1, u8, x2, x4);
|
||||
@@ -167,8 +190,8 @@ uintptr_t dynarec64_64(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
break;
|
||||
case 7: // CMP
|
||||
INST_NAME("CMP Eb, Ib");
|
||||
grab_segdata(dyn, addr, ninst, x1, seg);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_segdata(dyn, addr, ninst, x1, seg, (MODREG));
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETEBO(x1, 1);
|
||||
u8 = F8;
|
||||
if (u8) {
|
||||
@@ -185,7 +208,7 @@ uintptr_t dynarec64_64(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 0x81:
|
||||
case 0x83:
|
||||
nextop = F8;
|
||||
grab_segdata(dyn, addr, ninst, x6, seg);
|
||||
grab_segdata(dyn, addr, ninst, x6, seg, (MODREG));
|
||||
switch ((nextop >> 3) & 7) {
|
||||
case 0:
|
||||
if (opcode == 0x81) {
|
||||
@@ -193,7 +216,7 @@ uintptr_t dynarec64_64(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
INST_NAME("ADD Ed, Ib");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETEDO(x6, (opcode == 0x81) ? 4 : 1);
|
||||
if (opcode == 0x81)
|
||||
i64 = F32S;
|
||||
@@ -208,7 +231,7 @@ uintptr_t dynarec64_64(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
INST_NAME("OR Ed, Ib");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETEDO(x6, (opcode == 0x81) ? 4 : 1);
|
||||
if (opcode == 0x81)
|
||||
i64 = F32S;
|
||||
@@ -224,7 +247,7 @@ uintptr_t dynarec64_64(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("ADC Ed, Ib");
|
||||
}
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETEDO(x6, (opcode == 0x81) ? 4 : 1);
|
||||
if (opcode == 0x81)
|
||||
i64 = F32S;
|
||||
@@ -246,7 +269,7 @@ uintptr_t dynarec64_64(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("SBB Ed, Ib");
|
||||
}
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETEDO(x6, (opcode == 0x81) ? 4 : 1);
|
||||
if (opcode == 0x81)
|
||||
i64 = F32S;
|
||||
@@ -262,7 +285,7 @@ uintptr_t dynarec64_64(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
INST_NAME("AND Ed, Ib");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETEDO(x6, (opcode == 0x81) ? 4 : 1);
|
||||
if (opcode == 0x81)
|
||||
i64 = F32S;
|
||||
@@ -277,7 +300,7 @@ uintptr_t dynarec64_64(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
INST_NAME("SUB Ed, Ib");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETEDO(x6, (opcode == 0x81) ? 4 : 1);
|
||||
if (opcode == 0x81)
|
||||
i64 = F32S;
|
||||
@@ -292,7 +315,7 @@ uintptr_t dynarec64_64(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
INST_NAME("XOR Ed, Ib");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETEDO(x6, (opcode == 0x81) ? 4 : 1);
|
||||
if (opcode == 0x81)
|
||||
i64 = F32S;
|
||||
@@ -307,24 +330,57 @@ uintptr_t dynarec64_64(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
INST_NAME("CMP Ed, Ib");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETEDO(x6, (opcode == 0x81) ? 4 : 1);
|
||||
if (opcode == 0x81)
|
||||
i64 = F32S;
|
||||
else
|
||||
i64 = F8S;
|
||||
if (i64) {
|
||||
MOV64xw(x2, i64);
|
||||
MOV64x(x2, i64);
|
||||
emit_cmp32(dyn, ninst, rex, ed, x2, x3, x4, x5, x6);
|
||||
} else
|
||||
emit_cmp32_0(dyn, ninst, rex, ed, x3, x4);
|
||||
emit_cmp32_0(dyn, ninst, rex, nextop, ed, x3, x4, x5);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x88:
|
||||
INST_NAME("MOV Seg:Eb, Gb");
|
||||
nextop = F8;
|
||||
gd = ((nextop & 0x38) >> 3) + (rex.r << 3);
|
||||
if (rex.rex) {
|
||||
gb2 = 0;
|
||||
gb1 = TO_NAT(gd);
|
||||
} else {
|
||||
gb2 = ((gd & 4) << 1);
|
||||
gb1 = TO_NAT(gd & 3);
|
||||
}
|
||||
if (gb2) {
|
||||
gd = x4;
|
||||
BSTRPICK_D(gd, gb1, gb2 + 7, gb2);
|
||||
} else {
|
||||
gd = gb1;
|
||||
}
|
||||
if (MODREG) {
|
||||
ed = (nextop & 7) + (rex.b << 3);
|
||||
if (rex.rex) {
|
||||
eb1 = TO_NAT(ed);
|
||||
eb2 = 0;
|
||||
} else {
|
||||
eb1 = TO_NAT(ed & 3); // Ax, Cx, Dx or Bx
|
||||
eb2 = ((ed & 4) << 1); // L or H
|
||||
}
|
||||
BSTRINS_D(eb1, gd, eb2 + 7, eb2);
|
||||
} else {
|
||||
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
STX_B(gd, x4, wback);
|
||||
}
|
||||
break;
|
||||
case 0x89:
|
||||
INST_NAME("MOV Seg:Ed, Gd");
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
nextop = F8;
|
||||
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
|
||||
GETGD;
|
||||
if (MODREG) { // reg <= reg
|
||||
MVxw(TO_NAT((nextop & 7) + (rex.b << 3)), gd);
|
||||
@@ -342,8 +398,8 @@ uintptr_t dynarec64_64(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
break;
|
||||
case 0x8B:
|
||||
INST_NAME("MOV Gd, Seg:Ed");
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
nextop = F8;
|
||||
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
|
||||
GETGD;
|
||||
if (MODREG) { // reg <= reg
|
||||
MVxw(gd, TO_NAT((nextop & 7) + (rex.b << 3)));
|
||||
@@ -359,9 +415,26 @@ uintptr_t dynarec64_64(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x8E:
|
||||
INST_NAME("MOV Seg, Ew");
|
||||
nextop = F8;
|
||||
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
|
||||
u8 = (nextop & 0x38) >> 3;
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, NULL, 0, 0);
|
||||
ADDz(x4, wback, x4);
|
||||
LD_HU(x1, x4, 0);
|
||||
ed = x1;
|
||||
}
|
||||
ST_H(ed, xEmu, offsetof(x64emu_t, segs[u8]));
|
||||
ST_W(xZR, xEmu, offsetof(x64emu_t, segs_serial[u8]));
|
||||
break;
|
||||
case 0xA1:
|
||||
INST_NAME("MOV EAX, FS:Od");
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
grab_segdata(dyn, addr, ninst, x4, seg, 0);
|
||||
if (rex.is32bits)
|
||||
u64 = F32;
|
||||
else
|
||||
@@ -375,8 +448,8 @@ uintptr_t dynarec64_64(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
break;
|
||||
case 0xC6:
|
||||
INST_NAME("MOV Seg:Eb, Ib");
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
nextop = F8;
|
||||
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
|
||||
if (MODREG) { // reg <= u8
|
||||
u8 = F8;
|
||||
if (!rex.rex) {
|
||||
@@ -408,8 +481,8 @@ uintptr_t dynarec64_64(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
break;
|
||||
case 0xC7:
|
||||
INST_NAME("MOV Seg:Ed, Id");
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
nextop = F8;
|
||||
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
|
||||
if (MODREG) { // reg <= i32
|
||||
i64 = F32S;
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
|
||||
@@ -60,7 +60,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
switch (opcode) {
|
||||
case 0x01:
|
||||
INST_NAME("ADD Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
@@ -69,7 +69,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
break;
|
||||
case 0x03:
|
||||
INST_NAME("ADD Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
@@ -78,7 +78,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
break;
|
||||
case 0x05:
|
||||
INST_NAME("ADD AX, Iw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
i32 = F16;
|
||||
BSTRPICK_D(x1, xRAX, 15, 0);
|
||||
MOV32w(x2, i32);
|
||||
@@ -87,7 +87,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
break;
|
||||
case 0x09:
|
||||
INST_NAME("OR Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
@@ -96,7 +96,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
break;
|
||||
case 0x0B:
|
||||
INST_NAME("OR Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
@@ -105,7 +105,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
break;
|
||||
case 0x0D:
|
||||
INST_NAME("OR AX, Iw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
i32 = F16;
|
||||
BSTRPICK_D(x1, xRAX, 15, 0);
|
||||
MOV32w(x2, i32);
|
||||
@@ -115,6 +115,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 0x0F:
|
||||
switch (rep) {
|
||||
case 0: addr = dynarec64_660F(dyn, addr, ip, ninst, rex, ok, need_epilog); break;
|
||||
case 1: addr = dynarec64_66F20F(dyn, addr, ip, ninst, rex, ok, need_epilog); break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
@@ -122,7 +123,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 0x11:
|
||||
INST_NAME("ADC Ew, Gw");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
@@ -132,7 +133,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 0x13:
|
||||
INST_NAME("ADC Gw, Ew");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
@@ -142,7 +143,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 0x15:
|
||||
INST_NAME("ADC AX, Iw");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
u64 = F16;
|
||||
BSTRPICK_D(x1, xRAX, 15, 0);
|
||||
MOV64x(x2, u64);
|
||||
@@ -152,7 +153,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 0x19:
|
||||
INST_NAME("SBB Ew, Gw");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
@@ -162,7 +163,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 0x1B:
|
||||
INST_NAME("SBB Gw, Ew");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
@@ -172,7 +173,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 0x1D:
|
||||
INST_NAME("SBB AX, Iw");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
BSTRPICK_D(x1, xRAX, 15, 0);
|
||||
u64 = F16;
|
||||
MOV64x(x2, u64);
|
||||
@@ -181,7 +182,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
break;
|
||||
case 0x21:
|
||||
INST_NAME("AND Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
@@ -190,7 +191,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
break;
|
||||
case 0x23:
|
||||
INST_NAME("AND Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
@@ -199,7 +200,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
break;
|
||||
case 0x25:
|
||||
INST_NAME("AND AX, Iw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
i32 = F16;
|
||||
BSTRPICK_D(x1, xRAX, 15, 0);
|
||||
MOV32w(x2, i32);
|
||||
@@ -208,7 +209,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
break;
|
||||
case 0x29:
|
||||
INST_NAME("SUB Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
@@ -217,7 +218,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
break;
|
||||
case 0x2B:
|
||||
INST_NAME("SUB Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
@@ -226,7 +227,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
break;
|
||||
case 0x2D:
|
||||
INST_NAME("SUB AX, Iw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
i32 = F16;
|
||||
BSTRPICK_D(x1, xRAX, 15, 0);
|
||||
MOV32w(x2, i32);
|
||||
@@ -235,7 +236,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
break;
|
||||
case 0x31:
|
||||
INST_NAME("XOR Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
@@ -244,7 +245,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
break;
|
||||
case 0x33:
|
||||
INST_NAME("XOR Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
@@ -253,7 +254,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
break;
|
||||
case 0x35:
|
||||
INST_NAME("XOR AX, Iw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
i32 = F16;
|
||||
BSTRPICK_D(x1, xRAX, 15, 0);
|
||||
MOV32w(x2, i32);
|
||||
@@ -262,7 +263,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
break;
|
||||
case 0x39:
|
||||
INST_NAME("CMP Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
@@ -270,7 +271,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
break;
|
||||
case 0x3B:
|
||||
INST_NAME("CMP Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
@@ -278,7 +279,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
break;
|
||||
case 0x3D:
|
||||
INST_NAME("CMP AX, Iw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
i32 = F16;
|
||||
BSTRPICK_D(x1, xRAX, 15, 0);
|
||||
if (i32) {
|
||||
@@ -304,7 +305,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
INST_NAME("IMUL Gw,Ew,Ib");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
SETFLAGS(X_ALL, SF_PENDING, NAT_FLAGS_NOFUSION);
|
||||
nextop = F8;
|
||||
GETSEW(x1, (opcode == 0x69) ? 2 : 1);
|
||||
if (opcode == 0x69)
|
||||
@@ -328,7 +329,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
INST_NAME("ADD Ew, Ib");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETEW(x1, (opcode == 0x81) ? 2 : 1);
|
||||
if (opcode == 0x81)
|
||||
u64 = F16;
|
||||
@@ -344,7 +345,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
INST_NAME("OR Ew, Ib");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETEW(x1, (opcode == 0x81) ? 2 : 1);
|
||||
if (opcode == 0x81)
|
||||
u64 = F16;
|
||||
@@ -361,7 +362,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("ADC Ew, Ib");
|
||||
}
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETEW(x1, (opcode == 0x81) ? 2 : 1);
|
||||
if (opcode == 0x81)
|
||||
u64 = F16;
|
||||
@@ -378,7 +379,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("SBB Ew, Ib");
|
||||
}
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETEW(x1, (opcode == 0x81) ? 2 : 1);
|
||||
if (opcode == 0x81)
|
||||
u64 = F16;
|
||||
@@ -394,7 +395,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
INST_NAME("AND Ew, Ib");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETEW(x1, (opcode == 0x81) ? 2 : 1);
|
||||
if (opcode == 0x81)
|
||||
u64 = F16;
|
||||
@@ -410,7 +411,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
INST_NAME("SUB Ew, Ib");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETEW(x1, (opcode == 0x81) ? 2 : 1);
|
||||
if (opcode == 0x81)
|
||||
u64 = F16;
|
||||
@@ -426,7 +427,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
INST_NAME("XOR Ew, Ib");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETEW(x1, (opcode == 0x81) ? 2 : 1);
|
||||
if (opcode == 0x81)
|
||||
u64 = F16;
|
||||
@@ -442,7 +443,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
INST_NAME("CMP Ew, Ib");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETEW(x1, (opcode == 0x81) ? 2 : 1);
|
||||
if (opcode == 0x81)
|
||||
u64 = F16;
|
||||
@@ -460,7 +461,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
break;
|
||||
case 0x85:
|
||||
INST_NAME("TEST Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
nextop = F8;
|
||||
GETEW(x1, 0);
|
||||
GETGW(x2);
|
||||
@@ -497,6 +498,21 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
BSTRINSz(gd, x1, 15, 0);
|
||||
}
|
||||
break;
|
||||
case 0x8E:
|
||||
INST_NAME("MOV Seg, Ew");
|
||||
nextop = F8;
|
||||
u8 = (nextop & 0x38) >> 3;
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
LD_HU(x1, wback, fixedaddress);
|
||||
ed = x1;
|
||||
}
|
||||
ST_H(ed, xEmu, offsetof(x64emu_t, segs[u8]));
|
||||
ST_H(xZR, xEmu, offsetof(x64emu_t, segs_serial[u8]));
|
||||
break;
|
||||
case 0x90:
|
||||
case 0x91:
|
||||
case 0x92:
|
||||
@@ -515,12 +531,32 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
BSTRINSz(gd, x2, 15, 0);
|
||||
}
|
||||
break;
|
||||
case 0x98:
|
||||
INST_NAME("CBW");
|
||||
SLLI_D(x1, xRAX, 56);
|
||||
SRAI_D(x1, x1, 56);
|
||||
BSTRINSz(xRAX, x1, 15, 0);
|
||||
break;
|
||||
case 0xA4:
|
||||
if (rep) {
|
||||
INST_NAME("REP MOVSB");
|
||||
CBZ_NEXT(xRCX);
|
||||
ANDI(x1, xFlags, 1 << F_DF);
|
||||
BNEZ_MARK2(x1);
|
||||
// special optim for large RCX value on forward case only
|
||||
OR(x1, xRSI, xRDI);
|
||||
ANDI(x1, x1, 7);
|
||||
BNEZ_MARK(x1);
|
||||
ADDI_D(x6, xZR, 8);
|
||||
MARK3;
|
||||
BLT_MARK(xRCX, x6);
|
||||
LD_D(x1, xRSI, 0);
|
||||
ST_D(x1, xRDI, 0);
|
||||
ADDI_D(xRSI, xRSI, 8);
|
||||
ADDI_D(xRDI, xRDI, 8);
|
||||
ADDI_D(xRCX, xRCX, -8);
|
||||
BNEZ_MARK3(xRCX);
|
||||
B_NEXT_nocond;
|
||||
MARK; // Part with DF==0
|
||||
LD_BU(x1, xRSI, 0);
|
||||
ST_B(x1, xRDI, 0);
|
||||
@@ -577,9 +613,63 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
ADD_D(xRDI, xRDI, x3);
|
||||
}
|
||||
break;
|
||||
case 0xA7:
|
||||
switch (rep) {
|
||||
case 1:
|
||||
case 2:
|
||||
if (rep == 1) {
|
||||
INST_NAME("REPNZ CMPSW");
|
||||
} else {
|
||||
INST_NAME("REPZ CMPSW");
|
||||
}
|
||||
MAYSETFLAGS();
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_NOFUSION);
|
||||
CBZ_NEXT(xRCX);
|
||||
ANDI(x1, xFlags, 1 << F_DF);
|
||||
BNEZ_MARK2(x1);
|
||||
MARK; // DF==0
|
||||
LD_HU(x1, xRSI, 0);
|
||||
LD_HU(x2, xRDI, 0);
|
||||
ADDI_D(xRSI, xRSI, 2);
|
||||
ADDI_D(xRDI, xRDI, 2);
|
||||
ADDI_D(xRCX, xRCX, -1);
|
||||
if (rep == 1) {
|
||||
BEQ_MARK3(x1, x2); // REPNZ
|
||||
} else {
|
||||
BNE_MARK3(x1, x2); // REPZ
|
||||
}
|
||||
BNEZ_MARK(xRCX);
|
||||
B_MARK3_nocond;
|
||||
MARK2; // DF=1
|
||||
LD_HU(x1, xRSI, 0);
|
||||
LD_HU(x2, xRDI, 0);
|
||||
ADDI_D(xRSI, xRSI, -2);
|
||||
ADDI_D(xRDI, xRDI, -2);
|
||||
ADDI_D(xRCX, xRCX, -1);
|
||||
if (rep == 1) {
|
||||
BEQ_MARK3(x1, x2); // REPNZ
|
||||
} else {
|
||||
BNE_MARK3(x1, x2); // REPZ
|
||||
}
|
||||
BNEZ_MARK2(xRCX);
|
||||
MARK3; // end
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5, x6);
|
||||
break;
|
||||
default:
|
||||
INST_NAME("CMPSW");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_NOFUSION);
|
||||
GETDIR(x3, x1, 2);
|
||||
LD_HU(x1, xRSI, 0);
|
||||
LD_HU(x2, xRDI, 0);
|
||||
ADD_D(xRSI, xRSI, x3);
|
||||
ADD_D(xRDI, xRDI, x3);
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5, x6);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0xA9:
|
||||
INST_NAME("TEST AX,Iw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
u16 = F16;
|
||||
MOV32w(x2, u16);
|
||||
BSTRPICK_D(x1, xRAX, 15, 0);
|
||||
@@ -610,6 +700,65 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
ADD_D(xRDI, xRDI, x3);
|
||||
}
|
||||
break;
|
||||
case 0xAF:
|
||||
switch (rep) {
|
||||
case 1:
|
||||
case 2:
|
||||
if (rep == 1) {
|
||||
INST_NAME("REPNZ SCASW");
|
||||
} else {
|
||||
INST_NAME("REPZ SCASW");
|
||||
}
|
||||
MAYSETFLAGS();
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
CBZ_NEXT(xRCX);
|
||||
GETDIR(x3, x1, rex.w ? 8 : 2);
|
||||
if (rex.w) {
|
||||
MARK;
|
||||
LD_D(x2, xRDI, 0);
|
||||
ADD_D(xRDI, xRDI, x3);
|
||||
ADDI_D(xRCX, xRCX, -1);
|
||||
if (rep == 1) {
|
||||
BEQ_MARK3(xRAX, x2);
|
||||
} else {
|
||||
BNE_MARK3(xRAX, x2);
|
||||
}
|
||||
BNE_MARK(xRCX, xZR);
|
||||
MARK3;
|
||||
emit_cmp32(dyn, ninst, rex, xRAX, x2, x3, x4, x5, x6);
|
||||
} else {
|
||||
BSTRPICK_D(x1, xRAX, 15, 0);
|
||||
MARK;
|
||||
LD_HU(x2, xRDI, 0);
|
||||
ADD_D(xRDI, xRDI, x3);
|
||||
ADDI_D(xRCX, xRCX, -1);
|
||||
if (rep == 1) {
|
||||
BEQ_MARK3(x1, x2);
|
||||
} else {
|
||||
BNE_MARK3(x1, x2);
|
||||
}
|
||||
BNE_MARK(xRCX, xZR);
|
||||
MARK3;
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5, x6);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
INST_NAME("SCASW");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETDIR(x3, x1, rex.w ? 8 : 2);
|
||||
if (rex.w) {
|
||||
LD_D(x2, xRDI, 0);
|
||||
ADD_D(xRDI, xRDI, x3);
|
||||
emit_cmp32(dyn, ninst, rex, xRAX, x2, x3, x4, x5, x6);
|
||||
} else {
|
||||
BSTRPICK_D(x1, xRAX, 15, 0);
|
||||
LD_HU(x2, xRDI, 0);
|
||||
ADD_D(xRDI, xRDI, x3);
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5, x6);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0xB8:
|
||||
case 0xB9:
|
||||
case 0xBA:
|
||||
@@ -630,7 +779,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 0:
|
||||
INST_NAME("ROL Ew, Ib");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
SETFLAGS(X_OF | X_CF, SF_SET_DF);
|
||||
SETFLAGS(X_OF | X_CF, SF_SET_DF, NAT_FLAGS_NOFUSION);
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
MOV32w(x2, u8);
|
||||
@@ -640,7 +789,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 1:
|
||||
INST_NAME("ROR Ew, Ib");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
SETFLAGS(X_OF | X_CF, SF_SET_DF);
|
||||
SETFLAGS(X_OF | X_CF, SF_SET_DF, NAT_FLAGS_NOFUSION);
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
MOV32w(x2, u8);
|
||||
@@ -650,48 +799,42 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 4:
|
||||
case 6:
|
||||
INST_NAME("SHL Ew, Ib");
|
||||
UFLAG_IF { MESSAGE(LOG_DUMP, "Need Optimization for flags\n"); }
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
UFLAG_IF { MOV32w(x2, (u8 & 15)); }
|
||||
UFLAG_OP12(ed, x2)
|
||||
if (MODREG) {
|
||||
SLLI_D(ed, ed, 48 + (u8 & 15));
|
||||
SRLI_D(ed, ed, 48);
|
||||
if (geted_ib(dyn, addr, ninst, nextop) & 0x1f) {
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION); // some flags are left undefined
|
||||
GETEW(x1, 0);
|
||||
u8 = (F8) & 0x1f;
|
||||
emit_shl16c(dyn, ninst, x1, u8, x5, x4, x6);
|
||||
EWBACK;
|
||||
} else {
|
||||
SLLI_D(ed, ed, u8 & 15);
|
||||
FAKEED;
|
||||
F8;
|
||||
}
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_shl16);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("SHR Ew, Ib");
|
||||
UFLAG_IF { MESSAGE(LOG_DUMP, "Need Optimization for flags\n"); }
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
UFLAG_IF { MOV32w(x2, (u8 & 15)); }
|
||||
UFLAG_OP12(ed, x2)
|
||||
SRLI_D(ed, ed, u8 & 15);
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_shr16);
|
||||
if (geted_ib(dyn, addr, ninst, nextop) & 0x1f) {
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION); // some flags are left undefined
|
||||
GETEW(x1, 0);
|
||||
u8 = (F8) & 0x1f;
|
||||
emit_shr16c(dyn, ninst, x1, u8, x5, x4, x6);
|
||||
EWBACK;
|
||||
} else {
|
||||
FAKEED;
|
||||
F8;
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("SAR Ew, Ib");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
UFLAG_IF { MESSAGE(LOG_DUMP, "Need Optimization for flags\n"); }
|
||||
GETSEW(x1, 1);
|
||||
u8 = F8;
|
||||
UFLAG_IF { MOV32w(x2, (u8 & 15)); }
|
||||
UFLAG_OP12(ed, x2)
|
||||
SRAI_D(ed, ed, u8 & 15);
|
||||
if (MODREG) BSTRPICK_D(ed, ed, 15, 0);
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_sar16);
|
||||
if (geted_ib(dyn, addr, ninst, nextop) & 0x1f) {
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION); // some flags are left undefined
|
||||
GETSEW(x1, 0);
|
||||
u8 = (F8) & 0x1f;
|
||||
emit_sar16c(dyn, ninst, x1, u8, x5, x4, x6);
|
||||
EWBACK;
|
||||
} else {
|
||||
FAKEED;
|
||||
F8;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
@@ -717,6 +860,22 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 0xD3:
|
||||
nextop = F8;
|
||||
switch ((nextop >> 3) & 7) {
|
||||
case 0:
|
||||
if (opcode == 0xD1) {
|
||||
INST_NAME("ROL Ew, 1");
|
||||
MOV32w(x2, 1);
|
||||
} else {
|
||||
INST_NAME("ROL Ew, CL");
|
||||
ANDI(x2, xRCX, 0x1f);
|
||||
BEQ_NEXT(x2, xZR);
|
||||
}
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
SETFLAGS(X_OF | X_CF, SF_SET_DF, NAT_FLAGS_NOFUSION);
|
||||
if (BOX64DRENV(dynarec_safeflags) > 1) MAYSETFLAGS();
|
||||
GETEW(x1, 1);
|
||||
CALL_(rol16, x1, x3);
|
||||
EWBACK;
|
||||
break;
|
||||
case 5:
|
||||
if (opcode == 0xD1) {
|
||||
INST_NAME("SHR Ew, 1");
|
||||
@@ -726,8 +885,8 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
ANDI(x2, xRCX, 0x1f);
|
||||
BEQ_NEXT(x2, xZR);
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
if (box64_dynarec_safeflags > 1) MAYSETFLAGS();
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION); // some flags are left undefined
|
||||
if (BOX64DRENV(dynarec_safeflags) > 1) MAYSETFLAGS();
|
||||
GETEW(x1, 0);
|
||||
emit_shr16(dyn, ninst, x1, x2, x5, x4, x6);
|
||||
EWBACK;
|
||||
@@ -742,8 +901,8 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
ANDI(x2, xRCX, 0x1f);
|
||||
BEQ_NEXT(x2, xZR);
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
if (box64_dynarec_safeflags > 1)
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION); // some flags are left undefined
|
||||
if (BOX64DRENV(dynarec_safeflags) > 1)
|
||||
MAYSETFLAGS();
|
||||
GETEW(x1, 0);
|
||||
emit_shl16(dyn, ninst, x1, x2, x5, x4, x6);
|
||||
@@ -758,8 +917,8 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
ANDI(x2, xRCX, 0x1f);
|
||||
BEQ_NEXT(x2, xZR);
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
if (box64_dynarec_safeflags > 1)
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION); // some flags are left undefined
|
||||
if (BOX64DRENV(dynarec_safeflags) > 1)
|
||||
MAYSETFLAGS();
|
||||
GETSEW(x1, 0);
|
||||
emit_sar16(dyn, ninst, x1, x2, x5, x4, x6);
|
||||
@@ -769,35 +928,46 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xF0:
|
||||
return dynarec64_66F0(dyn, addr, ip, ninst, rex, rep, ok, need_epilog);
|
||||
|
||||
case 0xF7:
|
||||
nextop = F8;
|
||||
switch ((nextop >> 3) & 7) {
|
||||
case 0:
|
||||
case 1:
|
||||
INST_NAME("TEST Ew, Iw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETEW(x1, 2);
|
||||
u16 = F16;
|
||||
MOV32w(x2, u16);
|
||||
emit_test16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("NOT Ew");
|
||||
GETEW(x1, 0);
|
||||
MOV32w(x5, 0xffff);
|
||||
XOR(ed, ed, x5); // No flags affected
|
||||
EWBACK;
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("NEG Ew");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETEW(x1, 0);
|
||||
emit_neg16(dyn, ninst, ed, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("DIV Ew");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
|
||||
SET_DFNONE();
|
||||
GETEW(x1, 0);
|
||||
BSTRPICK_D(x2, xRAX, 15, 0);
|
||||
SLLI_D(x7, xRDX, 48);
|
||||
SRLI_D(x7, x7, 32);
|
||||
OR(x2, x2, x7);
|
||||
if(box64_dynarec_div0) {
|
||||
if(BOX64ENV(dynarec_div0)) {
|
||||
BNE_MARK3(ed, xZR);
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL();
|
||||
@@ -815,10 +985,10 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 7:
|
||||
INST_NAME("IDIV Ew");
|
||||
NOTEST(x1);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
|
||||
SET_DFNONE();
|
||||
GETSEW(x1, 0);
|
||||
if (box64_dynarec_div0) {
|
||||
if (BOX64ENV(dynarec_div0)) {
|
||||
BNE_MARK3(ed, xZR);
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL();
|
||||
@@ -845,14 +1015,14 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
switch ((nextop >> 3) & 7) {
|
||||
case 0:
|
||||
INST_NAME("INC Ew");
|
||||
SETFLAGS(X_ALL & ~X_CF, SF_SUBSET_PENDING);
|
||||
SETFLAGS(X_ALL & ~X_CF, SF_SUBSET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETEW(x1, 0);
|
||||
emit_inc16(dyn, ninst, x1, x2, x4, x5);
|
||||
EWBACK;
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("DEC Ew");
|
||||
SETFLAGS(X_ALL & ~X_CF, SF_SUBSET_PENDING);
|
||||
SETFLAGS(X_ALL & ~X_CF, SF_SUBSET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETEW(x1, 0);
|
||||
emit_dec16(dyn, ninst, x1, x2, x4, x5, x6);
|
||||
EWBACK;
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -51,7 +51,7 @@ uintptr_t dynarec64_6664(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
if (ed != gd) BSTRINS_D(gd, ed, 15, 0);
|
||||
}
|
||||
} else { // mem <= reg
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
ADDz(x4, ed, x4);
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "la64_emitter.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 "la64_printer.h"
|
||||
#include "dynarec_la64_private.h"
|
||||
#include "../dynarec_helper.h"
|
||||
#include "dynarec_la64_functions.h"
|
||||
|
||||
|
||||
uintptr_t dynarec64_66F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip;
|
||||
(void)rep;
|
||||
(void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop;
|
||||
uint8_t gd, ed, u8;
|
||||
uint8_t wback, wb1, wb2, gb1, gb2;
|
||||
int32_t i32;
|
||||
int64_t i64, j64;
|
||||
uint64_t u64;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
MAYUSE(gb1);
|
||||
MAYUSE(gb2);
|
||||
MAYUSE(wb1);
|
||||
MAYUSE(wb2);
|
||||
MAYUSE(j64);
|
||||
|
||||
while ((opcode == 0xF2) || (opcode == 0xF3)) {
|
||||
rep = opcode - 0xF1;
|
||||
opcode = F8;
|
||||
}
|
||||
|
||||
GETREX();
|
||||
|
||||
switch (opcode) {
|
||||
case 0x81:
|
||||
case 0x83:
|
||||
nextop = F8;
|
||||
SMDMB();
|
||||
switch ((nextop >> 3) & 7) {
|
||||
case 0: // ADD
|
||||
if (opcode == 0x81) {
|
||||
INST_NAME("LOCK ADD Ew, Iw");
|
||||
} else {
|
||||
INST_NAME("LOCK ADD Ew, Ib");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
if (MODREG) {
|
||||
if (opcode == 0x81)
|
||||
u64 = F16;
|
||||
else
|
||||
u64 = (uint16_t)(int16_t)F8S;
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
MOV64x(x5, u64);
|
||||
BSTRPICK_D(x6, ed, 15, 0);
|
||||
emit_add16(dyn, ninst, x6, x5, x3, x4, x2);
|
||||
BSTRINS_D(ed, x6, 15, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, (opcode == 0x81) ? 2 : 1);
|
||||
if (opcode == 0x81)
|
||||
u64 = F16;
|
||||
else
|
||||
u64 = (uint16_t)(int16_t)F8S;
|
||||
MOV64x(x5, u64);
|
||||
|
||||
if (la64_lam_bh) {
|
||||
AMADD_DB_H(x1, x5, wback);
|
||||
} else {
|
||||
ANDI(x3, wback, 0b10);
|
||||
BNEZ_MARK(x3);
|
||||
// lower 16 bits
|
||||
MARKLOCK;
|
||||
LL_W(x1, wback, 0);
|
||||
ADD_D(x4, x1, x5);
|
||||
MV(x3, x1);
|
||||
BSTRINS_D(x3, x4, 15, 0);
|
||||
SC_W(x3, wback, 0);
|
||||
BEQZ_MARKLOCK(x3);
|
||||
IFXORNAT (X_ALL | X_PEND) {
|
||||
BSTRPICK_D(x1, x1, 15, 0);
|
||||
}
|
||||
B_MARK3_nocond;
|
||||
MARK;
|
||||
// upper 16 bits
|
||||
XORI(wback, wback, 0b10);
|
||||
MARK2;
|
||||
LL_W(x1, wback, 0);
|
||||
BSTRPICK_D(x3, x1, 15, 0);
|
||||
SRLI_W(x1, x1, 16);
|
||||
ADD_D(x4, x1, x5);
|
||||
BSTRINS_D(x3, x4, 31, 15);
|
||||
SC_W(x3, wback, 0);
|
||||
BEQZ_MARK2(x3);
|
||||
MARK3;
|
||||
}
|
||||
// final
|
||||
IFXORNAT (X_ALL | X_PEND) {
|
||||
emit_add16(dyn, ninst, x1, x5, x3, x4, x6);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
SMDMB();
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "la64_emitter.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 "la64_printer.h"
|
||||
#include "dynarec_la64_private.h"
|
||||
#include "dynarec_la64_functions.h"
|
||||
#include "../dynarec_helper.h"
|
||||
|
||||
uintptr_t dynarec64_66F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip;
|
||||
(void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop, u8, s8;
|
||||
int32_t i32;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback, wb1, wb2, gback;
|
||||
uint8_t eb1, eb2;
|
||||
int64_t j64;
|
||||
uint64_t tmp64u, tmp64u2;
|
||||
int v0, v1;
|
||||
int q0, q1;
|
||||
int d0, d1;
|
||||
int64_t fixedaddress, gdoffset;
|
||||
int unscaled;
|
||||
|
||||
MAYUSE(d0);
|
||||
MAYUSE(d1);
|
||||
MAYUSE(q0);
|
||||
MAYUSE(q1);
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
MAYUSE(j64);
|
||||
|
||||
switch (opcode) {
|
||||
case 0x38: // these are some more SSSE4.2+ opcodes
|
||||
opcode = F8;
|
||||
switch (opcode) {
|
||||
case 0xF1:
|
||||
INST_NAME("CRC32 Gd, Ew");
|
||||
nextop = F8;
|
||||
GETEW(x1, 0);
|
||||
GETGD;
|
||||
CRCC_W_H_W(gd, gd, ed);
|
||||
ZEROUP(gd);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -65,7 +65,7 @@ uintptr_t dynarec64_67(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 0x19:
|
||||
INST_NAME("SBB Ed, Gd");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED32(0);
|
||||
@@ -75,7 +75,7 @@ uintptr_t dynarec64_67(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 0x1A:
|
||||
INST_NAME("SBB Gb, Eb");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
nextop = F8;
|
||||
GETEB32(x2, 0);
|
||||
GETGB(x1);
|
||||
@@ -85,7 +85,7 @@ uintptr_t dynarec64_67(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 0x1B:
|
||||
INST_NAME("SBB Gd, Ed");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED32(0);
|
||||
@@ -94,7 +94,7 @@ uintptr_t dynarec64_67(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 0x1D:
|
||||
INST_NAME("SBB EAX, Id");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
i64 = F32S;
|
||||
MOV64xw(x2, i64);
|
||||
emit_sbb32(dyn, ninst, rex, xRAX, x2, x3, x4, x5);
|
||||
@@ -155,12 +155,14 @@ uintptr_t dynarec64_67(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
ZEROUP2(gd, ed);
|
||||
}
|
||||
break;
|
||||
case 0xE8:
|
||||
return dynarec64_00(dyn, addr - 1, ip, ninst, rex, rep, ok, need_epilog); // addr-1, to "put back" opcode)
|
||||
case 0xF7:
|
||||
nextop = F8;
|
||||
switch ((nextop >> 3) & 7) {
|
||||
case 4:
|
||||
INST_NAME("MUL EAX, Ed");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
SETFLAGS(X_ALL, SF_PENDING, NAT_FLAGS_NOFUSION);
|
||||
GETED32(0);
|
||||
if (rex.w) {
|
||||
if (ed == xRDX)
|
||||
|
||||
@@ -25,9 +25,10 @@
|
||||
// emit XOR8 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed)
|
||||
void emit_xor8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX (X_PEND) {
|
||||
SET_DF(s4, d_xor8);
|
||||
} else IFX (X_ALL) {
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
@@ -62,9 +63,10 @@ void emit_xor8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
// emit XOR8 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_xor8c(dynarec_la64_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX (X_PEND) {
|
||||
SET_DF(s4, d_xor8);
|
||||
} else IFX (X_ALL) {
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
@@ -74,6 +76,7 @@ void emit_xor8c(dynarec_la64_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
X64_XOR_B(s1, s3);
|
||||
}
|
||||
XORI(s1, s1, c & 0xff);
|
||||
ANDI(s1, s1, 0xff);
|
||||
IFX (X_PEND)
|
||||
ST_B(s1, xEmu, offsetof(x64emu_t, res));
|
||||
return;
|
||||
@@ -102,9 +105,10 @@ void emit_xor8c(dynarec_la64_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
// emit XOR16 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed)
|
||||
void emit_xor16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX (X_PEND) {
|
||||
SET_DF(s4, d_xor16);
|
||||
} else IFX (X_ALL) {
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
@@ -142,9 +146,10 @@ void emit_xor16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4,
|
||||
// emit XOR32 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
|
||||
void emit_xor32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, rex.w ? d_xor64 : d_xor32);
|
||||
} else IFX(X_ALL) {
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
@@ -193,9 +198,10 @@ void emit_xor32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
// emit XOR32 instruction, from s1, c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_xor32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4)
|
||||
{
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX (X_PEND) {
|
||||
SET_DF(s4, rex.w ? d_xor64 : d_xor32);
|
||||
} else IFX (X_ALL) {
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
@@ -259,9 +265,10 @@ void emit_xor32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i
|
||||
// emit AND8 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed)
|
||||
void emit_and8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s3, d_and8);
|
||||
} else IFX(X_ALL) {
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
@@ -296,9 +303,10 @@ void emit_and8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
// emit AND8 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_and8c(dynarec_la64_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX (X_PEND) {
|
||||
SET_DF(s3, d_and8);
|
||||
} else IFX(X_ALL) {
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
@@ -333,9 +341,10 @@ void emit_and8c(dynarec_la64_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
|
||||
void emit_and16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX (X_PEND) {
|
||||
SET_DF(s3, d_tst16);
|
||||
} else IFX (X_ALL) {
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
@@ -370,9 +379,10 @@ void emit_and16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
// emit AND32 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
|
||||
void emit_and32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX (X_PEND) {
|
||||
SET_DF(s3, rex.w ? d_tst64 : d_tst32);
|
||||
} else IFX(X_ALL) {
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
@@ -412,9 +422,10 @@ void emit_and32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
// emit AND32 instruction, from s1, c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_and32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX (X_PEND) {
|
||||
SET_DF(s3, rex.w ? d_tst64 : d_tst32);
|
||||
} else IFX(X_ALL) {
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
@@ -458,9 +469,10 @@ void emit_and32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i
|
||||
// emit OR16 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed)
|
||||
void emit_or16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX (X_PEND) {
|
||||
SET_DF(s3, d_or16);
|
||||
} else IFX (X_ALL) {
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
@@ -495,9 +507,10 @@ void emit_or16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
// emit OR32 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
|
||||
void emit_or32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX (X_PEND) {
|
||||
SET_DF(s4, rex.w?d_or64:d_or32);
|
||||
} else IFX(X_ALL) {
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
@@ -540,9 +553,10 @@ void emit_or32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
// emit OR32 instruction, from s1, c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_or32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX (X_PEND) {
|
||||
SET_DF(s4, rex.w ? d_or64 : d_or32);
|
||||
} else IFX(X_ALL) {
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
@@ -594,9 +608,10 @@ void emit_or32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, in
|
||||
// emit OR8 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed)
|
||||
void emit_or8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX (X_PEND) {
|
||||
SET_DF(s3, d_or8);
|
||||
} else IFX (X_ALL) {
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,8 @@
|
||||
// emit ADD32 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
|
||||
void emit_add32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX (X_PEND) {
|
||||
if (rex.w) {
|
||||
ST_D(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
ST_D(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
@@ -34,12 +35,12 @@ void emit_add32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
ST_W(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
}
|
||||
SET_DF(s3, rex.w ? d_add64 : d_add32b);
|
||||
} else IFX(X_ALL) {
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
IFX(X_ALL) {
|
||||
IFX (X_ALL) {
|
||||
if (rex.w)
|
||||
X64_ADD_DU(s1, s2);
|
||||
else
|
||||
@@ -48,14 +49,13 @@ void emit_add32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
ADDxw(s1, s1, s2);
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
|
||||
IFX(X_PEND)
|
||||
IFX (X_PEND)
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
return;
|
||||
}
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX(X_CF)
|
||||
{
|
||||
IFX (X_CF) {
|
||||
if (rex.w) {
|
||||
ZEROUP2(s5, s1);
|
||||
ZEROUP2(s4, s2);
|
||||
@@ -77,30 +77,25 @@ void emit_add32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
ORI(xFlags, xFlags, 1 << F_CF);
|
||||
}
|
||||
}
|
||||
IFX(X_AF | X_OF)
|
||||
{
|
||||
IFX (X_AF | X_OF) {
|
||||
OR(s3, s1, s2); // s3 = op1 | op2
|
||||
AND(s4, s1, s2); // s4 = op1 & op2
|
||||
}
|
||||
|
||||
ADDxw(s1, s1, s2);
|
||||
|
||||
IFX(X_PEND)
|
||||
{
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_AF | X_OF)
|
||||
{
|
||||
IFX (X_AF | X_OF) {
|
||||
ANDN(s3, s3, s1); // s3 = ~res & (op1 | op2)
|
||||
OR(s3, s3, s4); // cc = (~res & (op1 | op2)) | (op1 & op2)
|
||||
IFX(X_AF)
|
||||
{
|
||||
IFX (X_AF) {
|
||||
ANDI(s4, s3, 0x08); // AF: cc & 0x08
|
||||
BEQZ(s4, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_AF);
|
||||
}
|
||||
IFX(X_OF)
|
||||
{
|
||||
IFX (X_OF) {
|
||||
SRLI_D(s3, s3, rex.w ? 62 : 30);
|
||||
SRLI_D(s4, s3, 1);
|
||||
XOR(s3, s3, s4);
|
||||
@@ -109,20 +104,17 @@ void emit_add32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
ORI(xFlags, xFlags, 1 << F_OF);
|
||||
}
|
||||
}
|
||||
IFX(X_SF)
|
||||
{
|
||||
IFX (X_SF) {
|
||||
BGE(s1, xZR, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
if (!rex.w) {
|
||||
ZEROUP(s1);
|
||||
}
|
||||
IFX(X_PF)
|
||||
{
|
||||
IFX (X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
IFX(X_ZF)
|
||||
{
|
||||
IFX (X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
@@ -131,7 +123,8 @@ void emit_add32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
// emit ADD32 instruction, from s1, constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_add32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
if (s1 == xRSP && (!dyn->insts || dyn->insts[ninst].x64.gen_flags == X_PEND)) {
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
if ((s1 == xRSP) && (BOX64DRENV(dynarec_safeflags) < 2) && (!dyn->insts || (dyn->insts[ninst].x64.gen_flags == X_PEND) || (!BOX64ENV(dynarec_df) && (dyn->insts[ninst].x64.gen_flags == X_ALL)))) {
|
||||
// special case when doing math on ESP and only PEND is needed: ignoring it!
|
||||
if (c >= -2048 && c < 2048) {
|
||||
ADDI_D(s1, s1, c);
|
||||
@@ -142,25 +135,21 @@ void emit_add32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i
|
||||
if (!rex.w) { ZEROUP(s1); }
|
||||
return;
|
||||
}
|
||||
IFX(X_PEND | X_AF | X_CF | X_OF)
|
||||
{
|
||||
IFX (X_PEND | X_AF | X_CF | X_OF) {
|
||||
MOV64xw(s2, c);
|
||||
} else if (la64_lbt) {
|
||||
MOV64xw(s2, c);
|
||||
}
|
||||
IFX(X_PEND)
|
||||
{
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SDxw(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, rex.w ? d_add64 : d_add32b);
|
||||
}
|
||||
else IFX(X_ALL)
|
||||
{
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
IFX(X_ALL) {
|
||||
IFX (X_ALL) {
|
||||
if (rex.w)
|
||||
X64_ADD_DU(s1, s2);
|
||||
else
|
||||
@@ -169,14 +158,12 @@ void emit_add32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i
|
||||
ADDxw(s1, s1, s2);
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
|
||||
IFX(X_PEND)
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
IFX (X_PEND) SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
return;
|
||||
}
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX(X_CF)
|
||||
{
|
||||
IFX (X_CF) {
|
||||
if (rex.w) {
|
||||
ZEROUP2(s5, s1);
|
||||
ZEROUP2(s4, s2);
|
||||
@@ -198,8 +185,7 @@ void emit_add32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i
|
||||
ORI(xFlags, xFlags, 1 << F_CF);
|
||||
}
|
||||
}
|
||||
IFX(X_AF | X_OF)
|
||||
{
|
||||
IFX (X_AF | X_OF) {
|
||||
OR(s3, s1, s2); // s3 = op1 | op2
|
||||
AND(s4, s1, s2); // s4 = op1 & op2
|
||||
}
|
||||
@@ -207,30 +193,25 @@ void emit_add32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i
|
||||
if (c >= -2048 && c < 2048) {
|
||||
ADDIxw(s1, s1, c);
|
||||
} else {
|
||||
IFX(X_PEND | X_AF | X_CF | X_OF) { }
|
||||
else
|
||||
{
|
||||
IFX (X_PEND | X_AF | X_CF | X_OF) {
|
||||
} else {
|
||||
MOV64xw(s2, c);
|
||||
}
|
||||
ADDxw(s1, s1, s2);
|
||||
}
|
||||
|
||||
IFX(X_PEND)
|
||||
{
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_AF | X_OF)
|
||||
{
|
||||
IFX (X_AF | X_OF) {
|
||||
ANDN(s3, s3, s1); // s3 = ~res & (op1 | op2)
|
||||
OR(s3, s3, s4); // cc = (~res & (op1 | op2)) | (op1 & op2)
|
||||
IFX(X_AF)
|
||||
{
|
||||
IFX (X_AF) {
|
||||
ANDI(s4, s3, 0x08); // AF: cc & 0x08
|
||||
BEQZ(s4, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_AF);
|
||||
}
|
||||
IFX(X_OF)
|
||||
{
|
||||
IFX (X_OF) {
|
||||
SRLI_D(s3, s3, rex.w ? 62 : 30);
|
||||
SRLI_D(s4, s3, 1);
|
||||
XOR(s3, s3, s4);
|
||||
@@ -239,20 +220,17 @@ void emit_add32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i
|
||||
ORI(xFlags, xFlags, 1 << F_OF);
|
||||
}
|
||||
}
|
||||
IFX(X_SF)
|
||||
{
|
||||
IFX (X_SF) {
|
||||
BGE(s1, xZR, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
if (!rex.w) {
|
||||
ZEROUP(s1);
|
||||
}
|
||||
IFX(X_PF)
|
||||
{
|
||||
IFX (X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
IFX(X_ZF)
|
||||
{
|
||||
IFX (X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
@@ -261,40 +239,42 @@ void emit_add32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i
|
||||
// emit ADD8 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
|
||||
void emit_add8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX (X_PEND) {
|
||||
ST_B(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
ST_B(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_add8);
|
||||
} else IFX(X_ALL) {
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
IFX(X_ALL) {
|
||||
IFX (X_ALL) {
|
||||
X64_ADD_B(s1, s2);
|
||||
}
|
||||
ADD_D(s1, s1, s2);
|
||||
IFX(X_PEND)
|
||||
ANDI(s1, s1, 0xff);
|
||||
IFX (X_PEND)
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, res));
|
||||
return;
|
||||
}
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX(X_AF | X_OF) {
|
||||
IFX (X_AF | X_OF) {
|
||||
OR(s3, s1, s2); // s3 = op1 | op2
|
||||
AND(s4, s1, s2); // s4 = op1 & op2
|
||||
}
|
||||
ADD_D(s1, s1, s2);
|
||||
|
||||
IFX(X_AF | X_OF) {
|
||||
IFX (X_AF | X_OF) {
|
||||
ANDN(s3, s3, s1); // s3 = ~res & (op1 | op2)
|
||||
OR(s3, s3, s4); // cc = (~res & (op1 | op2)) | (op1 & op2)
|
||||
IFX(X_AF) {
|
||||
IFX (X_AF) {
|
||||
ANDI(s4, s3, 0x08); // AF: cc & 0x08
|
||||
BEQZ(s4, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_AF);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
IFX (X_OF) {
|
||||
SRLI_D(s3, s3, 6);
|
||||
SRLI_D(s4, s3, 1);
|
||||
XOR(s3, s3, s4);
|
||||
@@ -303,25 +283,25 @@ void emit_add8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
ORI(xFlags, xFlags, 1 << F_OF);
|
||||
}
|
||||
}
|
||||
IFX(X_CF) {
|
||||
IFX (X_CF) {
|
||||
SRLI_D(s3, s1, 8);
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_CF);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
IFX (X_PEND) {
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
ANDI(s1, s1, 0xff);
|
||||
IFX(X_ZF) {
|
||||
IFX (X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
IFX (X_SF) {
|
||||
SRLI_D(s3, s1, 7);
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
IFX (X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
@@ -329,48 +309,51 @@ void emit_add8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
// emit ADD8 instruction, from s1, const c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_add8c(dynarec_la64_t* dyn, int ninst, int s1, int c, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX (X_PEND) {
|
||||
MOV32w(s4, c & 0xff);
|
||||
ST_B(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
ST_B(s4, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_add8);
|
||||
} else IFX(X_ALL) {
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
IFX(X_ALL) {
|
||||
IFX(X_PEND) {} else { MOV32w(s4, c & 0xff); }
|
||||
IFX (X_ALL) {
|
||||
IFX (X_PEND) {
|
||||
} else {
|
||||
MOV32w(s4, c & 0xff);
|
||||
}
|
||||
X64_ADD_B(s1, s4);
|
||||
}
|
||||
ADDI_D(s1, s1, c & 0xff);
|
||||
|
||||
IFX(X_PEND)
|
||||
ANDI(s1, s1, 0xff);
|
||||
IFX (X_PEND)
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, res));
|
||||
return;
|
||||
}
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX(X_AF | X_OF)
|
||||
{
|
||||
IFX(X_PEND) {} else { MOV32w(s4, c & 0xff); }
|
||||
IFX (X_AF | X_OF) {
|
||||
IFX (X_PEND) {
|
||||
} else {
|
||||
MOV32w(s4, c & 0xff);
|
||||
}
|
||||
OR(s3, s1, s4); // s3 = op1 | op2
|
||||
AND(s4, s1, s4); // s4 = op1 & op2
|
||||
}
|
||||
ADDI_D(s1, s1, c & 0xff);
|
||||
|
||||
IFX(X_AF | X_OF)
|
||||
{
|
||||
IFX (X_AF | X_OF) {
|
||||
ANDN(s3, s3, s1); // s3 = ~res & (op1 | op2)
|
||||
OR(s3, s3, s4); // cc = (~res & (op1 | op2)) | (op1 & op2)
|
||||
IFX(X_AF)
|
||||
{
|
||||
IFX (X_AF) {
|
||||
ANDI(s4, s3, 0x08); // AF: cc & 0x08
|
||||
BEQZ(s4, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_AF);
|
||||
}
|
||||
IFX(X_OF)
|
||||
{
|
||||
IFX (X_OF) {
|
||||
SRLI_D(s3, s3, 6);
|
||||
SRLI_D(s4, s3, 1);
|
||||
XOR(s3, s3, s4);
|
||||
@@ -379,30 +362,25 @@ void emit_add8c(dynarec_la64_t* dyn, int ninst, int s1, int c, int s2, int s3, i
|
||||
ORI(xFlags, xFlags, 1 << F_OF);
|
||||
}
|
||||
}
|
||||
IFX(X_CF)
|
||||
{
|
||||
IFX (X_CF) {
|
||||
SRLI_D(s3, s1, 8);
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_CF);
|
||||
}
|
||||
IFX(X_PEND)
|
||||
{
|
||||
IFX (X_PEND) {
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
ANDI(s1, s1, 0xff);
|
||||
IFX(X_ZF)
|
||||
{
|
||||
IFX (X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX(X_SF)
|
||||
{
|
||||
IFX (X_SF) {
|
||||
SRLI_D(s3, s1, 7);
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
IFX(X_PF)
|
||||
{
|
||||
IFX (X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
@@ -410,11 +388,12 @@ void emit_add8c(dynarec_la64_t* dyn, int ninst, int s1, int c, int s2, int s3, i
|
||||
// emit ADD16 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
|
||||
void emit_add16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX (X_PEND) {
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
ST_H(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_add16);
|
||||
} else IFX (X_ALL) {
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFXA (X_AF | X_OF, !la64_lbt) {
|
||||
@@ -481,47 +460,48 @@ void emit_add16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4,
|
||||
// emit SUB8 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
|
||||
void emit_sub8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX (X_PEND) {
|
||||
ST_B(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
ST_B(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_sub8);
|
||||
} else IFX(X_ALL) {
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
IFX(X_ALL) {
|
||||
IFX (X_ALL) {
|
||||
X64_SUB_B(s1, s2);
|
||||
}
|
||||
SUB_D(s1, s1, s2);
|
||||
|
||||
IFX(X_PEND)
|
||||
ANDI(s1, s1, 0xff);
|
||||
IFX (X_PEND)
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, res));
|
||||
return;
|
||||
}
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX(X_AF | X_CF | X_OF) {
|
||||
IFX (X_AF | X_CF | X_OF) {
|
||||
// for later flag calculation
|
||||
NOR(s5, xZR, s1);
|
||||
}
|
||||
|
||||
SUB_D(s1, s1, s2);
|
||||
ANDI(s1, s1, 0xff);
|
||||
IFX(X_SF) {
|
||||
IFX (X_SF) {
|
||||
SRLI_D(s3, s1, 7);
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
IFX (X_PEND) {
|
||||
ST_B(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
CALC_SUB_FLAGS(s5, s2, s1, s3, s4, 8);
|
||||
IFX(X_ZF) {
|
||||
IFX (X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
IFX (X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
@@ -529,18 +509,19 @@ void emit_sub8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, i
|
||||
// emit SUB8 instruction, from s1, constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_sub8c(dynarec_la64_t* dyn, int ninst, int s1, int c, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
MOV32w(s2, c&0xff);
|
||||
MOV32w(s2, c & 0xff);
|
||||
emit_sub8(dyn, ninst, s1, s2, s3, s4, s5);
|
||||
}
|
||||
|
||||
// emit SUB16 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
|
||||
void emit_sub16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX (X_PEND) {
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
ST_H(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_sub16);
|
||||
} else IFX (X_ALL) {
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
@@ -558,7 +539,10 @@ void emit_sub16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4,
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
|
||||
if (la64_lbt) return;
|
||||
if (la64_lbt) {
|
||||
BSTRPICK_D(s1, s1, 15, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
SLLI_D(s1, s1, 48);
|
||||
@@ -581,16 +565,17 @@ void emit_sub16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4,
|
||||
// emit SUB32 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
|
||||
void emit_sub32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SDxw(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, rex.w?d_sub64:d_sub32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DF(s3, rex.w ? d_sub64 : d_sub32);
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
IFX(X_ALL) {
|
||||
IFX (X_ALL) {
|
||||
if (rex.w)
|
||||
X64_SUB_DU(s1, s2);
|
||||
else
|
||||
@@ -599,34 +584,34 @@ void emit_sub32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
SUBxw(s1, s1, s2);
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
|
||||
IFX(X_PEND)
|
||||
IFX (X_PEND)
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
return;
|
||||
}
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX(X_AF | X_CF | X_OF) {
|
||||
IFX (X_AF | X_CF | X_OF) {
|
||||
// for later flag calculation
|
||||
NOR(s5, xZR, s1);
|
||||
}
|
||||
|
||||
SUBxw(s1, s1, s2);
|
||||
IFX(X_PEND) {
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_SF) {
|
||||
IFX (X_SF) {
|
||||
BGE(s1, xZR, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
if (!rex.w) {
|
||||
ZEROUP(s1);
|
||||
}
|
||||
CALC_SUB_FLAGS(s5, s2, s1, s3, s4, rex.w?64:32);
|
||||
IFX(X_ZF) {
|
||||
CALC_SUB_FLAGS(s5, s2, s1, s3, s4, rex.w ? 64 : 32);
|
||||
IFX (X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
IFX (X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
@@ -634,8 +619,8 @@ void emit_sub32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
// emit SUB32 instruction, from s1, constant c, store result in s1 using s2, s3, s4 and s5 as scratch
|
||||
void emit_sub32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
if(s1==xRSP && (!dyn->insts || dyn->insts[ninst].x64.gen_flags==X_PEND))
|
||||
{
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
if ((s1 == xRSP) && (BOX64DRENV(dynarec_safeflags) < 2) && (!dyn->insts || (dyn->insts[ninst].x64.gen_flags == X_PEND) || (!BOX64ENV(dynarec_df) && (dyn->insts[ninst].x64.gen_flags == X_ALL)))) {
|
||||
// special case when doing math on RSP and only PEND is needed: ignoring it!
|
||||
if (c > -2048 && c <= 2048) {
|
||||
ADDI_D(s1, s1, -c);
|
||||
@@ -647,18 +632,21 @@ void emit_sub32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i
|
||||
return;
|
||||
}
|
||||
|
||||
IFX(X_PEND) {
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
MOV64xw(s2, c);
|
||||
SDxw(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, rex.w?d_sub64:d_sub32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DF(s3, rex.w ? d_sub64 : d_sub32);
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
IFX(X_PEND) {} else {MOV64xw(s2, c);}
|
||||
IFX(X_ALL) {
|
||||
IFX (X_PEND) {
|
||||
} else {
|
||||
MOV64xw(s2, c);
|
||||
}
|
||||
IFX (X_ALL) {
|
||||
if (rex.w) {
|
||||
X64_SUB_DU(s1, s2);
|
||||
} else {
|
||||
@@ -668,13 +656,13 @@ void emit_sub32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i
|
||||
SUBxw(s1, s1, s2);
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
|
||||
IFX(X_PEND)
|
||||
IFX (X_PEND)
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
return;
|
||||
}
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX(X_AF | X_CF | X_OF) {
|
||||
IFX (X_AF | X_CF | X_OF) {
|
||||
// for later flag calculation
|
||||
NOR(s5, xZR, s1);
|
||||
}
|
||||
@@ -682,32 +670,35 @@ void emit_sub32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i
|
||||
if (c > -2048 && c <= 2048) {
|
||||
ADDIxw(s1, s1, -c);
|
||||
} else {
|
||||
IFX(X_PEND) {} else {MOV64xw(s2, c);}
|
||||
IFX (X_PEND) {
|
||||
} else {
|
||||
MOV64xw(s2, c);
|
||||
}
|
||||
SUBxw(s1, s1, s2);
|
||||
}
|
||||
|
||||
IFX(X_AF | X_CF | X_OF) {
|
||||
IFX(X_PEND) {}
|
||||
else if (c > -2048 && c <= 2048) {
|
||||
IFX (X_AF | X_CF | X_OF) {
|
||||
IFX (X_PEND) {
|
||||
} else if (c > -2048 && c <= 2048) {
|
||||
MOV64xw(s2, c);
|
||||
}
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_SF) {
|
||||
IFX (X_SF) {
|
||||
BGE(s1, xZR, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
if (!rex.w) {
|
||||
ZEROUP(s1);
|
||||
}
|
||||
CALC_SUB_FLAGS(s5, s2, s1, s3, s4, rex.w?64:32);
|
||||
IFX(X_ZF) {
|
||||
CALC_SUB_FLAGS(s5, s2, s1, s3, s4, rex.w ? 64 : 32);
|
||||
IFX (X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
IFX (X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
@@ -716,11 +707,12 @@ void emit_sub32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i
|
||||
// emit SBB8 instruction, from s1, s2, store result in s1 using s3, s4 and s5 as scratch
|
||||
void emit_sbb8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX (X_PEND) {
|
||||
ST_B(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
ST_B(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_sbb8);
|
||||
} else IFX (X_ALL) {
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
@@ -730,7 +722,6 @@ void emit_sbb8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, i
|
||||
IFX (X_ALL) {
|
||||
X64_SBC_B(s1, s2);
|
||||
}
|
||||
|
||||
ANDI(s1, s3, 0xff);
|
||||
IFX (X_PEND)
|
||||
ST_B(s1, xEmu, offsetof(x64emu_t, res));
|
||||
@@ -778,15 +769,16 @@ void emit_sbb8c(dynarec_la64_t* dyn, int ninst, int s1, int c, int s3, int s4, i
|
||||
// emit SBB16 instruction, from s1, s2, store result in s1 using s3, s4 and s5 as scratch
|
||||
void emit_sbb16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX (X_PEND) {
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
ST_H(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_sbb16);
|
||||
} else IFX (X_ALL) {
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
IFXA (X_ALL, la64_lbt) {
|
||||
if (la64_lbt) {
|
||||
SBC_H(s3, s1, s2);
|
||||
|
||||
IFX (X_ALL) {
|
||||
@@ -832,11 +824,12 @@ void emit_sbb16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4,
|
||||
// emit SBB32 instruction, from s1, s2, store result in s1 using s3, s4 and s5 as scratch
|
||||
void emit_sbb32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SDxw(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, rex.w ? d_sbb64 : d_sbb32);
|
||||
} else IFX (X_ALL) {
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
@@ -852,8 +845,10 @@ void emit_sbb32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
else
|
||||
X64_SBC_W(s1, s2);
|
||||
}
|
||||
MVxw(s1, s3);
|
||||
|
||||
if (rex.w)
|
||||
MV(s1, s3);
|
||||
else
|
||||
ZEROUP2(s1, s3);
|
||||
IFX (X_PEND)
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
return;
|
||||
@@ -895,10 +890,11 @@ void emit_sbb32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
// emit NEG8 instruction, from s1, store result in s1 using s2 and s3 as scratch
|
||||
void emit_neg8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
{
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX (X_PEND) {
|
||||
ST_B(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s3, d_neg8);
|
||||
} else IFX (X_ALL) {
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFX (X_AF | X_OF) {
|
||||
@@ -957,10 +953,11 @@ void emit_neg8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
// emit NEG32 instruction, from s1, store result in s1 using s2 and s3 as scratch
|
||||
void emit_neg32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3)
|
||||
{
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s3, rex.w ? d_neg64 : d_neg32);
|
||||
} else IFX (X_ALL) {
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
@@ -983,9 +980,7 @@ void emit_neg32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
if (!rex.w) {
|
||||
ZEROUP(s1);
|
||||
}
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1032,11 +1027,12 @@ void emit_neg32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
// emit ADC8 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
|
||||
void emit_adc8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX (X_PEND) {
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
ST_H(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_adc8);
|
||||
} else IFX (X_ALL) {
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
@@ -1046,7 +1042,7 @@ void emit_adc8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, i
|
||||
IFX (X_ALL) {
|
||||
X64_ADC_B(s1, s2);
|
||||
}
|
||||
MV(s1, s3);
|
||||
ANDI(s1, s3, 0xff);
|
||||
IFX (X_PEND) {
|
||||
ST_W(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
@@ -1115,11 +1111,12 @@ void emit_adc8c(dynarec_la64_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
// emit ADC16 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
|
||||
void emit_adc16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX (X_PEND) {
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
ST_H(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_adc16);
|
||||
} else IFX (X_ALL) {
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
@@ -1129,7 +1126,7 @@ void emit_adc16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4,
|
||||
IFX (X_ALL) {
|
||||
X64_ADC_H(s1, s2);
|
||||
}
|
||||
MV(s1, s3);
|
||||
BSTRPICK_D(s1, s3, 15, 0);
|
||||
IFX (X_PEND) {
|
||||
ST_W(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
@@ -1191,11 +1188,12 @@ void emit_adc16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4,
|
||||
// emit ADC32 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
|
||||
void emit_adc32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5, int s6)
|
||||
{
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SDxw(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, rex.w ? d_adc64 : d_adc32b);
|
||||
} else IFX (X_ALL) {
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
@@ -1211,7 +1209,10 @@ void emit_adc32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
else
|
||||
X64_ADC_W(s1, s2);
|
||||
}
|
||||
MV(s1, s3);
|
||||
if (rex.w)
|
||||
MV(s1, s3);
|
||||
else
|
||||
ZEROUP2(s1, s3);
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
@@ -1294,10 +1295,11 @@ void emit_adc32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
// emit INC8 instruction, from s1, store result in s1 using s2, s3 and s4 as scratch
|
||||
void emit_inc8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX (X_PEND) {
|
||||
ST_B(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s3, d_inc8);
|
||||
} else IFX (X_ALL) {
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFXA (X_AF | X_OF, !la64_lbt) {
|
||||
@@ -1360,10 +1362,11 @@ void emit_inc8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
// emit INC16 instruction, from s1, store result in s1 using s3 and s4 as scratch
|
||||
void emit_inc16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX (X_PEND) {
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s3, d_inc16);
|
||||
} else IFX (X_ZF | X_OF | X_AF | X_SF | X_PF) {
|
||||
} else IFXORNAT (X_ZF | X_OF | X_AF | X_SF | X_PF) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFXA (X_AF | X_OF, !la64_lbt) {
|
||||
@@ -1429,10 +1432,11 @@ void emit_inc16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
// emit INC32 instruction, from s1, store result in s1 using s3 and s4 as scratch
|
||||
void emit_inc32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s3, rex.w ? d_inc64 : d_inc32);
|
||||
} else IFX (X_ALL) {
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
@@ -1501,10 +1505,11 @@ void emit_inc32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
// emit DEC8 instruction, from s1, store result in s1 using s2, s3 and s4 as scratch
|
||||
void emit_dec8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX (X_PEND) {
|
||||
ST_B(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s3, d_dec8);
|
||||
} else IFX (X_ALL) {
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFXA (X_AF | X_OF, !la64_lbt) {
|
||||
@@ -1568,10 +1573,11 @@ void emit_dec8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
// emit DEC16 instruction, from s1, store result in s1 using s3 and s4 as scratch
|
||||
void emit_dec16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX (X_PEND) {
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s3, d_dec16);
|
||||
} else IFX (X_ALL) {
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFX (X_AF | X_OF) {
|
||||
@@ -1636,10 +1642,11 @@ void emit_dec16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4,
|
||||
// emit DEC32 instruction, from s1, store result in s1 using s3 and s4 as scratch
|
||||
void emit_dec32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s3, rex.w ? d_dec64 : d_dec32);
|
||||
} else IFX (X_ALL) {
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFXA (X_AF | X_OF, !la64_lbt) {
|
||||
@@ -1709,10 +1716,11 @@ void emit_dec32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
// emit NEG16 instruction, from s1, store result in s1 using s2 and s3 as scratch
|
||||
void emit_neg16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
{
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX (X_PEND) {
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s3, d_neg16);
|
||||
} else IFX (X_ALL) {
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFX (X_AF | X_OF) {
|
||||
|
||||
@@ -25,12 +25,13 @@
|
||||
// emit SHL16 instruction, from s1 , shift s2, store result in s1 using s3, s4 and s5 as scratch
|
||||
void emit_shl16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
// s2 is not 0 here and is 1..1f/3f
|
||||
IFX (X_PEND) {
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
ST_H(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, d_shl16);
|
||||
} else IFX (X_ALL) {
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
@@ -86,20 +87,117 @@ void emit_shl16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4,
|
||||
}
|
||||
}
|
||||
|
||||
// emit SHL32 instruction, from s1 , shift s2, store result in s1 using s3, s4 and s5 as scratch
|
||||
void emit_shl32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5)
|
||||
// emit SHL16 instruction, from s1 , constant c, store result in s1 using s3, s4 and s5 as scratch
|
||||
void emit_shl16c(dynarec_la64_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4, int s5)
|
||||
{
|
||||
// s2 is not 0 here and is 1..1f/3f
|
||||
IFX(X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SDxw(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w?d_shl64:d_shl32);
|
||||
} else IFX(X_ALL) {
|
||||
if (!c) return;
|
||||
// c != 0
|
||||
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX (X_PEND) {
|
||||
MOV64x(s3, c);
|
||||
ST_H(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s4, d_shl16);
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
IFX(X_ALL) {
|
||||
IFX (X_PEND) {
|
||||
} else {
|
||||
MOV64x(s3, c);
|
||||
}
|
||||
IFX (X_ALL) {
|
||||
X64_SLL_H(s1, s3);
|
||||
}
|
||||
|
||||
SLLI_D(s1, s1, c);
|
||||
BSTRPICK_D(s1, s1, 15, 0);
|
||||
|
||||
IFX (X_PEND) {
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
if (c < 16) {
|
||||
IFX (X_CF | X_OF) {
|
||||
SRLI_D(s3, s1, 16 - c);
|
||||
ANDI(s5, s3, 1); // LSB == F_CF
|
||||
IFX (X_CF) {
|
||||
OR(xFlags, xFlags, s5);
|
||||
}
|
||||
}
|
||||
|
||||
SLLI_D(s1, s1, c + 48);
|
||||
IFX (X_SF) {
|
||||
BGE(s1, xZR, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
SRLI_D(s1, s1, 48);
|
||||
|
||||
IFX (X_PEND) {
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX (X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX (X_OF) {
|
||||
// OF flag is affected only on 1-bit shifts
|
||||
if (c == 1) {
|
||||
SRLI_D(s3, s1, 15);
|
||||
XOR(s3, s3, s5);
|
||||
SLLI_D(s3, s3, F_OF);
|
||||
OR(xFlags, xFlags, s3);
|
||||
}
|
||||
}
|
||||
IFX (X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
} else {
|
||||
IFX (X_CF) {
|
||||
if (c == 16) {
|
||||
ANDI(s3, s1, 1);
|
||||
OR(xFlags, xFlags, s3); // F_CF == 0
|
||||
}
|
||||
}
|
||||
MV(s1, xZR);
|
||||
|
||||
IFX (X_PEND) {
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
// OF nop
|
||||
// SF nop
|
||||
// AF nop
|
||||
IFX (X_PF | X_ZF) {
|
||||
IFX (X_ZF) {
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX (X_PF) {
|
||||
ORI(xFlags, xFlags, 1 << F_PF);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// emit SHL32 instruction, from s1 , shift s2, store result in s1 using s3, s4 and s5 as scratch
|
||||
void emit_shl32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
// s2 is not 0 here and is 1..1f/3f
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SDxw(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w ? d_shl64 : d_shl32);
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
IFX (X_ALL) {
|
||||
if (rex.w)
|
||||
X64_SLL_D(s1, s2);
|
||||
else
|
||||
@@ -107,49 +205,49 @@ void emit_shl32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
}
|
||||
SLL_D(s1, s1, s2);
|
||||
if (!rex.w) { ZEROUP(s1); }
|
||||
IFX(X_PEND) {
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX(X_CF | X_OF) {
|
||||
ADDI_D(s5, s2, rex.w?-64:-32);
|
||||
IFX (X_CF | X_OF) {
|
||||
ADDI_D(s5, s2, rex.w ? -64 : -32);
|
||||
SUB_D(s5, xZR, s5);
|
||||
SRL_W(s3, s1, s5);
|
||||
ANDI(s5, s3, 1); // LSB == F_CF
|
||||
IFX(X_CF) {
|
||||
IFX (X_CF) {
|
||||
OR(xFlags, xFlags, s5);
|
||||
}
|
||||
}
|
||||
|
||||
SLL_D(s1, s1, s2);
|
||||
|
||||
IFX(X_SF) {
|
||||
IFX (X_SF) {
|
||||
BGE(s1, xZR, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
if (!rex.w) {
|
||||
ZEROUP(s1);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
IFX (X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
IFX (X_OF) {
|
||||
// OF flag is affected only on 1-bit shifts
|
||||
ADDI_D(s3, s2, -1);
|
||||
BNEZ(s3, 4 + 4 * 4);
|
||||
SRLIxw(s3, s1, rex.w?63:31);
|
||||
SRLIxw(s3, s1, rex.w ? 63 : 31);
|
||||
XOR(s3, s3, s5);
|
||||
SLLI_D(s3, s3, F_OF);
|
||||
OR(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
IFX (X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
@@ -159,7 +257,8 @@ void emit_shl32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
|
||||
{
|
||||
if (!c) return;
|
||||
|
||||
IFX(X_PEND) {
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX (X_PEND) {
|
||||
if (c) {
|
||||
MOV64x(s3, c);
|
||||
SDxw(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
@@ -167,14 +266,17 @@ void emit_shl32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
|
||||
SDxw(xZR, xEmu, offsetof(x64emu_t, op2));
|
||||
}
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s4, rex.w?d_shl64:d_shl32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DF(s4, rex.w ? d_shl64 : d_shl32);
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
if(la64_lbt) {
|
||||
IFX(X_PEND) {} else { MOV64x(s3, c); }
|
||||
IFX(X_ALL) {
|
||||
if (la64_lbt) {
|
||||
IFX (X_PEND) {
|
||||
} else {
|
||||
MOV64x(s3, c);
|
||||
}
|
||||
IFX (X_ALL) {
|
||||
if (rex.w)
|
||||
X64_SLL_D(s1, s3);
|
||||
else
|
||||
@@ -182,19 +284,19 @@ void emit_shl32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
|
||||
}
|
||||
|
||||
SLLIxw(s1, s1, c);
|
||||
|
||||
IFX(X_PEND) {
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX(X_CF | X_OF) {
|
||||
IFX (X_CF | X_OF) {
|
||||
if (c > 0) {
|
||||
SRLI_D(s3, s1, (rex.w ? 64 : 32) - c);
|
||||
ANDI(s5, s3, 1); // LSB == F_CF
|
||||
IFX(X_CF) {
|
||||
IFX (X_CF) {
|
||||
OR(xFlags, xFlags, s5);
|
||||
}
|
||||
}
|
||||
@@ -206,21 +308,21 @@ void emit_shl32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
|
||||
SLLI_W(s1, s1, c);
|
||||
}
|
||||
|
||||
IFX(X_SF) {
|
||||
IFX (X_SF) {
|
||||
BGE(s1, xZR, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
if (!rex.w) {
|
||||
ZEROUP(s1);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
IFX (X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
IFX (X_OF) {
|
||||
// OF flag is affected only on 1-bit shifts
|
||||
if (c == 1) {
|
||||
SRLIxw(s3, s1, rex.w ? 63 : 31);
|
||||
@@ -229,7 +331,73 @@ void emit_shl32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
|
||||
OR(xFlags, xFlags, s3);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
IFX (X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit SHL8 instruction, from s1 , shift s2, store result in s1 using s3, s4 and s5 as scratch
|
||||
void emit_shl8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
|
||||
IFX (X_PEND) {
|
||||
ST_B(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
ST_B(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, d_shl8);
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
IFX (X_ALL) {
|
||||
X64_SLL_B(s1, s2);
|
||||
}
|
||||
SLL_D(s1, s1, s2);
|
||||
ANDI(s1, s1, 0xff);
|
||||
|
||||
IFX (X_PEND) {
|
||||
ST_B(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
SLL_D(s1, s1, s2);
|
||||
|
||||
// s2 is not 0 here and is 1..1f/3f
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX (X_CF | X_OF) {
|
||||
SRLI_D(s5, s1, 8);
|
||||
ANDI(s5, s5, 1); // LSB == F_CF
|
||||
IFX (X_CF) {
|
||||
OR(xFlags, xFlags, s5);
|
||||
}
|
||||
}
|
||||
|
||||
SLLI_D(s1, s1, 56);
|
||||
IFX (X_SF) {
|
||||
BGE(s1, xZR, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
SRLI_D(s1, s1, 56);
|
||||
|
||||
IFX (X_PEND) {
|
||||
ST_B(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX (X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX (X_OF) {
|
||||
// OF flag is affected only on 1-bit shifts
|
||||
ADDI_D(s3, s2, -1);
|
||||
BNEZ(s3, 4 + 4 * 4);
|
||||
SRLI_D(s3, s1, 7);
|
||||
XOR(s3, s3, s5);
|
||||
SLLI_D(s3, s3, F_OF);
|
||||
OR(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX (X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
@@ -237,14 +405,13 @@ void emit_shl32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
|
||||
// emit SHR8 instruction, from s1 , shift s2 (!0 and and'd already), store result in s1 using s3 and s4 as scratch
|
||||
void emit_shr8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
int64_t j64;
|
||||
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
|
||||
IFX (X_PEND) {
|
||||
ST_B(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
ST_B(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s4, d_shr8);
|
||||
} else IFX (X_ALL) {
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
@@ -294,16 +461,75 @@ void emit_shr8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, i
|
||||
}
|
||||
}
|
||||
|
||||
// emit SAR8 instruction, from s1 , shift s2 (!0 and and'd already), store result in s1 using s3, s4 and s5 as scratch
|
||||
void emit_sar8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
int64_t j64;
|
||||
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
|
||||
IFX (X_PEND) {
|
||||
ST_B(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
ST_B(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s4, d_sar8);
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
IFX (X_ALL) {
|
||||
X64_SRA_B(s1, s2);
|
||||
}
|
||||
SRA_D(s1, s1, s2);
|
||||
ANDI(s1, s1, 0xff);
|
||||
|
||||
IFX (X_PEND) {
|
||||
ST_B(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX (X_CF) {
|
||||
ADDI_D(s3, s2, -1);
|
||||
SRA_D(s3, s1, s3);
|
||||
ANDI(s3, s3, 1); // LSB == F_CF
|
||||
OR(xFlags, xFlags, s3);
|
||||
}
|
||||
// For the SAR instruction, the OF flag is cleared for all 1-bit shifts.
|
||||
// OF nop
|
||||
IFX (X_SF) {
|
||||
// SF is the same as the original operand
|
||||
BGE(s1, xZR, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
|
||||
SRA_D(s1, s1, s2);
|
||||
ANDI(s1, s1, 0xff);
|
||||
|
||||
IFX (X_PEND) {
|
||||
ST_B(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX (X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX (X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit SHR16 instruction, from s1 , shift s2 (!0 and and'd already), store result in s1 using s3 and s4 as scratch
|
||||
void emit_shr16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
int64_t j64;
|
||||
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX (X_PEND) {
|
||||
ST_H(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s4, d_shr16);
|
||||
} else IFX (X_ALL) {
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
@@ -354,17 +580,85 @@ void emit_shr16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4,
|
||||
}
|
||||
}
|
||||
|
||||
// emit SHR16 instruction, from s1 , constant c, store result in s1 using s3, s4 and s5 as scratch
|
||||
void emit_shr16c(dynarec_la64_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4, int s5)
|
||||
{
|
||||
if (!c) return;
|
||||
// c != 0
|
||||
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX (X_PEND) {
|
||||
MOV64x(s3, c);
|
||||
ST_H(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s4, d_shr16);
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
IFX (X_PEND) {
|
||||
} else {
|
||||
MOV64x(s3, c);
|
||||
}
|
||||
IFX (X_ALL) {
|
||||
X64_SRL_H(s1, s3);
|
||||
}
|
||||
SRLI_D(s1, s1, c);
|
||||
IFX (X_PEND) {
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX (X_CF) {
|
||||
if (c > 1) {
|
||||
SRAI_D(s3, s1, c - 1);
|
||||
ANDI(s3, s3, 1); // LSB == F_CF
|
||||
} else {
|
||||
// no need to shift
|
||||
ANDI(s3, s1, 1); // LSB == F_CF
|
||||
}
|
||||
OR(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX (X_OF) {
|
||||
// OF flag is affected only on 1-bit shifts
|
||||
// OF flag is set to the most-significant bit of the original operand
|
||||
if (c == 1) {
|
||||
SRLI_D(s3, s1, 15);
|
||||
SLLI_D(s3, s3, F_OF);
|
||||
OR(xFlags, xFlags, s3);
|
||||
}
|
||||
}
|
||||
|
||||
SRLI_D(s1, s1, c);
|
||||
|
||||
// SF should be unset
|
||||
IFX (X_PEND) {
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX (X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX (X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit SHR32 instruction, from s1 , shift s2 (!0 and and'd already), store result in s1 using s3 and s4 as scratch
|
||||
void emit_shr32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
int64_t j64;
|
||||
|
||||
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX (X_PEND) {
|
||||
SDxw(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s4, rex.w ? d_shr64 : d_shr32);
|
||||
} else IFX (X_ALL) {
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
@@ -424,7 +718,8 @@ void emit_shr32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
// emit SHR32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_shr32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX (X_PEND) {
|
||||
if (c) {
|
||||
MOV64x(s3, c);
|
||||
SDxw(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
@@ -432,19 +727,22 @@ void emit_shr32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
|
||||
SDxw(xZR, xEmu, offsetof(x64emu_t, op2));
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s4, rex.w ? d_shr64 : d_shr32);
|
||||
} else IFX(X_ALL) {
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
if (!c) {
|
||||
IFX(X_PEND) {
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
IFX(X_PEND) {} else { MOV64x(s3, c); }
|
||||
IFX(X_ALL) {
|
||||
IFX (X_PEND) {
|
||||
} else {
|
||||
MOV64x(s3, c);
|
||||
}
|
||||
IFX (X_ALL) {
|
||||
if (rex.w)
|
||||
X64_SRL_D(s1, s3);
|
||||
else
|
||||
@@ -452,15 +750,15 @@ void emit_shr32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
|
||||
}
|
||||
|
||||
SRLIxw(s1, s1, c);
|
||||
|
||||
IFX(X_PEND) {
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX(X_CF) {
|
||||
IFX (X_CF) {
|
||||
if (c > 1) {
|
||||
SRAI_D(s3, s1, c - 1);
|
||||
ANDI(s3, s3, 1); // LSB == F_CF
|
||||
@@ -470,7 +768,7 @@ void emit_shr32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
|
||||
}
|
||||
OR(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
IFX (X_OF) {
|
||||
// OF flag is affected only on 1-bit shifts
|
||||
// OF flag is set to the most-significant bit of the original operand
|
||||
if (c == 1) {
|
||||
@@ -486,21 +784,21 @@ void emit_shr32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
|
||||
SRLI_W(s1, s1, c);
|
||||
}
|
||||
|
||||
IFX(X_SF) {
|
||||
IFX (X_SF) {
|
||||
BGE(s1, xZR, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
if (!rex.w) {
|
||||
ZEROUP(s1);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
IFX (X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
IFX (X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
@@ -511,11 +809,12 @@ void emit_sar16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4,
|
||||
{
|
||||
int64_t j64;
|
||||
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX (X_PEND) {
|
||||
ST_H(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s4, d_sar16);
|
||||
} else IFX (X_ALL) {
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
@@ -563,10 +862,78 @@ void emit_sar16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// emit SAR16 instruction, from s1 , constant c, store result in s1 using s3, s4 and s5 as scratch
|
||||
void emit_sar16c(dynarec_la64_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4, int s5)
|
||||
{
|
||||
if (!c) return;
|
||||
// c != 0
|
||||
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX (X_PEND) {
|
||||
MOV64x(s3, c);
|
||||
ST_H(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s4, d_sar16);
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
IFX (X_PEND) {
|
||||
} else {
|
||||
MOV64x(s3, c);
|
||||
}
|
||||
IFX (X_ALL) {
|
||||
X64_SRA_H(s1, s3);
|
||||
}
|
||||
SRLI_D(s1, s1, c);
|
||||
BSTRPICK_D(s1, s1, 15, 0);
|
||||
IFX (X_PEND) {
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX (X_CF) {
|
||||
if (c > 1) {
|
||||
SRAI_D(s3, s1, c - 1);
|
||||
ANDI(s3, s3, 1); // LSB == F_CF
|
||||
} else {
|
||||
// no need to shift
|
||||
ANDI(s3, s1, 1); // LSB == F_CF
|
||||
}
|
||||
OR(xFlags, xFlags, s3);
|
||||
}
|
||||
// For the SAR instruction, the OF flag is cleared for all 1-bit shifts.
|
||||
// OF nop
|
||||
IFX (X_SF) {
|
||||
// SF is the same as the original operand
|
||||
BGE(s1, xZR, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
|
||||
SRLI_D(s1, s1, c);
|
||||
BSTRPICK_D(s1, s1, 15, 0);
|
||||
|
||||
IFX (X_PEND) {
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX (X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX (X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit SAR32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_sar32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX (X_PEND) {
|
||||
if (c) {
|
||||
MOV64x(s3, c);
|
||||
SDxw(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
@@ -574,19 +941,22 @@ void emit_sar32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
|
||||
SDxw(xZR, xEmu, offsetof(x64emu_t, op2));
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s4, rex.w ? d_sar64 : d_sar32);
|
||||
} else IFX(X_ALL) {
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
if (!c) {
|
||||
IFX(X_PEND) {
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
IFX(X_PEND) {} else { MOV64x(s3, c); }
|
||||
IFX(X_ALL) {
|
||||
IFX (X_PEND) {
|
||||
} else {
|
||||
MOV64x(s3, c);
|
||||
}
|
||||
IFX (X_ALL) {
|
||||
if (rex.w)
|
||||
X64_SRA_D(s1, s3);
|
||||
else
|
||||
@@ -594,15 +964,15 @@ void emit_sar32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
|
||||
}
|
||||
|
||||
SRAIxw(s1, s1, c);
|
||||
|
||||
IFX(X_PEND) {
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX(X_CF) {
|
||||
IFX (X_CF) {
|
||||
if (c > 1) {
|
||||
SRAI_D(s3, s1, c - 1);
|
||||
ANDI(s3, s3, 1); // LSB == F_CF
|
||||
@@ -622,21 +992,21 @@ void emit_sar32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
|
||||
}
|
||||
|
||||
// SRAI_W sign-extends, so test sign bit before clearing upper bits
|
||||
IFX(X_SF) {
|
||||
IFX (X_SF) {
|
||||
BGE(s1, xZR, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
if (!rex.w) {
|
||||
ZEROUP(s1);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
IFX (X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
IFX (X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
@@ -647,11 +1017,12 @@ void emit_ror32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
|
||||
{
|
||||
if (!c) return;
|
||||
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX (X_PEND) {
|
||||
MOV32w(s3, c);
|
||||
SDxw(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w ? d_ror64 : d_ror32);
|
||||
} else IFX (X_ALL) {
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
if (!c) {
|
||||
@@ -669,6 +1040,7 @@ void emit_ror32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
|
||||
}
|
||||
|
||||
ROTRIxw(s1, s1, c);
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
@@ -701,11 +1073,13 @@ void emit_ror32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
|
||||
void emit_rol32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
int64_t j64;
|
||||
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
BEQ_NEXT(s2, xZR);
|
||||
IFX (X_PEND) {
|
||||
SDxw(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w ? d_rol64 : d_rol32);
|
||||
} else IFX (X_ALL) {
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
@@ -716,9 +1090,6 @@ void emit_rol32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
X64_ROTL_W(s1, s2);
|
||||
}
|
||||
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
BEQ_NEXT(s2, xZR);
|
||||
|
||||
SLLxw(s3, s1, s2);
|
||||
NEG_D(s4, s2);
|
||||
ADDI_D(s4, s4, rex.w ? 64 : 32);
|
||||
@@ -756,6 +1127,7 @@ void emit_ror32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
{
|
||||
int64_t j64;
|
||||
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
if (!rex.w) {
|
||||
ZEROUP(s1);
|
||||
}
|
||||
@@ -763,7 +1135,7 @@ void emit_ror32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
IFX (X_PEND) {
|
||||
SDxw(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w ? d_ror64 : d_ror32);
|
||||
} else IFX (X_ALL) {
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
@@ -814,11 +1186,12 @@ void emit_rol32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
|
||||
{
|
||||
if (!c) return;
|
||||
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX (X_PEND) {
|
||||
MOV32w(s3, c);
|
||||
SDxw(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w ? d_rol64 : d_rol32);
|
||||
} else IFX (X_ALL) {
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
if (!c) {
|
||||
@@ -869,6 +1242,7 @@ void emit_shld32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, uin
|
||||
{
|
||||
c &= (rex.w ? 0x3f : 0x1f);
|
||||
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX (X_PEND) {
|
||||
if (c) {
|
||||
MOV64x(s3, c);
|
||||
@@ -877,7 +1251,7 @@ void emit_shld32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, uin
|
||||
SDxw(xZR, xEmu, offsetof(x64emu_t, op2));
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s4, rex.w ? d_shld64 : d_shld32);
|
||||
} else IFX (X_ALL) {
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
@@ -944,6 +1318,7 @@ void emit_shrd32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, uin
|
||||
{
|
||||
c &= (rex.w ? 0x3f : 0x1f);
|
||||
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR);
|
||||
IFX (X_PEND) {
|
||||
if (c) {
|
||||
MOV64x(s3, c);
|
||||
@@ -952,7 +1327,7 @@ void emit_shrd32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, uin
|
||||
SDxw(xZR, xEmu, offsetof(x64emu_t, op2));
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s4, rex.w ? d_shrd64 : d_shrd32);
|
||||
} else IFX (X_ALL) {
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
if (!c) {
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "la64_emitter.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
@@ -33,6 +34,8 @@ void emit_cmp8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, i
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
NAT_FLAGS_ENABLE_CARRY();
|
||||
NAT_FLAGS_ENABLE_SIGN();
|
||||
if (la64_lbt) {
|
||||
IFX(X_ALL) {
|
||||
X64_SUB_B(s1, s2);
|
||||
@@ -42,6 +45,15 @@ void emit_cmp8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, i
|
||||
SUB_D(s6, s1, s2);
|
||||
ST_B(s6, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
if (dyn->insts[ninst].nat_flags_fusion) {
|
||||
if (dyn->insts[ninst].nat_flags_needsign) {
|
||||
EXT_W_B(s3, s1);
|
||||
EXT_W_B(s4, s2);
|
||||
NAT_FLAGS_OPS(s3, s4);
|
||||
} else {
|
||||
NAT_FLAGS_OPS(s1, s2);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -70,6 +82,15 @@ void emit_cmp8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, i
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s6, s3, s4);
|
||||
}
|
||||
if (dyn->insts[ninst].nat_flags_fusion) {
|
||||
if (dyn->insts[ninst].nat_flags_needsign) {
|
||||
EXT_W_B(s3, s1);
|
||||
EXT_W_B(s4, s2);
|
||||
NAT_FLAGS_OPS(s3, s4);
|
||||
} else {
|
||||
NAT_FLAGS_OPS(s1, s2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// emit CMP8 instruction, from cmp s1 , 0, using s3 and s4 as scratch
|
||||
@@ -84,10 +105,20 @@ void emit_cmp8_0(dynarec_la64_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
NAT_FLAGS_ENABLE_CARRY();
|
||||
NAT_FLAGS_ENABLE_SIGN();
|
||||
if (la64_lbt) {
|
||||
IFX(X_ALL) {
|
||||
X64_SUB_B(s1, xZR);
|
||||
}
|
||||
if (dyn->insts[ninst].nat_flags_fusion) {
|
||||
if (dyn->insts[ninst].nat_flags_needsign) {
|
||||
EXT_W_B(s3, s1);
|
||||
NAT_FLAGS_OPS(s3, xZR);
|
||||
} else {
|
||||
NAT_FLAGS_OPS(s1, xZR);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -104,6 +135,14 @@ void emit_cmp8_0(dynarec_la64_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
if (dyn->insts[ninst].nat_flags_fusion) {
|
||||
if (dyn->insts[ninst].nat_flags_needsign) {
|
||||
EXT_W_B(s3, s1);
|
||||
NAT_FLAGS_OPS(s3, xZR);
|
||||
} else {
|
||||
NAT_FLAGS_OPS(s1, xZR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// emit CMP16 instruction, from cmp s1, s2, using s3 and s4 as scratch
|
||||
@@ -117,6 +156,8 @@ void emit_cmp16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4,
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
NAT_FLAGS_ENABLE_CARRY();
|
||||
NAT_FLAGS_ENABLE_SIGN();
|
||||
if (la64_lbt) {
|
||||
IFX(X_ALL) {
|
||||
X64_SUB_H(s1, s2);
|
||||
@@ -126,6 +167,15 @@ void emit_cmp16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4,
|
||||
SUB_D(s6, s1, s2);
|
||||
ST_H(s6, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
if (dyn->insts[ninst].nat_flags_fusion) {
|
||||
if (dyn->insts[ninst].nat_flags_needsign) {
|
||||
EXT_W_H(s3, s1);
|
||||
EXT_W_H(s4, s2);
|
||||
NAT_FLAGS_OPS(s3, s4);
|
||||
} else {
|
||||
NAT_FLAGS_OPS(s1, s2);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -156,6 +206,15 @@ void emit_cmp16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4,
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s6, s3, s4);
|
||||
}
|
||||
if (dyn->insts[ninst].nat_flags_fusion) {
|
||||
if (dyn->insts[ninst].nat_flags_needsign) {
|
||||
EXT_W_H(s3, s1);
|
||||
EXT_W_H(s4, s2);
|
||||
NAT_FLAGS_OPS(s3, s4);
|
||||
} else {
|
||||
NAT_FLAGS_OPS(s1, s2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// emit CMP16 instruction, from cmp s1 , #0, using s3 and s4 as scratch
|
||||
@@ -170,10 +229,20 @@ void emit_cmp16_0(dynarec_la64_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
NAT_FLAGS_ENABLE_CARRY();
|
||||
NAT_FLAGS_ENABLE_SIGN();
|
||||
if (la64_lbt) {
|
||||
IFX(X_ALL) {
|
||||
X64_SUB_H(s1, xZR);
|
||||
}
|
||||
if (dyn->insts[ninst].nat_flags_fusion) {
|
||||
if (dyn->insts[ninst].nat_flags_needsign) {
|
||||
EXT_W_H(s3, s1);
|
||||
NAT_FLAGS_OPS(s3, xZR);
|
||||
} else {
|
||||
NAT_FLAGS_OPS(s1, xZR);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -190,6 +259,14 @@ void emit_cmp16_0(dynarec_la64_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
if (dyn->insts[ninst].nat_flags_fusion) {
|
||||
if (dyn->insts[ninst].nat_flags_needsign) {
|
||||
EXT_W_H(s3, s1);
|
||||
NAT_FLAGS_OPS(s3, xZR);
|
||||
} else {
|
||||
NAT_FLAGS_OPS(s1, xZR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// emit CMP32 instruction, from cmp s1, s2, using s3 and s4 as scratch
|
||||
@@ -203,6 +280,8 @@ void emit_cmp32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
NAT_FLAGS_ENABLE_CARRY();
|
||||
NAT_FLAGS_ENABLE_SIGN();
|
||||
if (la64_lbt) {
|
||||
IFX(X_ALL) {
|
||||
if (rex.w)
|
||||
@@ -215,6 +294,20 @@ void emit_cmp32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
SUBxw(s6, s1, s2);
|
||||
SDxw(s6, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
if (dyn->insts[ninst].nat_flags_fusion) {
|
||||
if (rex.w)
|
||||
NAT_FLAGS_OPS(s1, s2);
|
||||
else {
|
||||
if (dyn->insts[ninst].nat_flags_needsign) {
|
||||
SEXT_W(s3, s1);
|
||||
SEXT_W(s4, s2);
|
||||
} else {
|
||||
ZEROUP2(s3, s1);
|
||||
ZEROUP2(s4, s2);
|
||||
}
|
||||
NAT_FLAGS_OPS(s3, s4);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -244,10 +337,24 @@ void emit_cmp32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s6, s3, s4);
|
||||
}
|
||||
if (dyn->insts[ninst].nat_flags_fusion) {
|
||||
if (rex.w)
|
||||
NAT_FLAGS_OPS(s1, s2);
|
||||
else {
|
||||
if (dyn->insts[ninst].nat_flags_needsign) {
|
||||
SEXT_W(s3, s1);
|
||||
SEXT_W(s4, s2);
|
||||
} else {
|
||||
ZEROUP2(s3, s1);
|
||||
ZEROUP2(s4, s2);
|
||||
}
|
||||
NAT_FLAGS_OPS(s3, s4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// emit CMP32 instruction, from cmp s1, 0, using s3 and s4 as scratch
|
||||
void emit_cmp32_0(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s3, int s4)
|
||||
void emit_cmp32_0(dynarec_la64_t* dyn, int ninst, rex_t rex, uint8_t nextop, int s1, int s3, int s4, int s5)
|
||||
{
|
||||
IFX_PENDOR0 {
|
||||
ST_D(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
@@ -258,6 +365,8 @@ void emit_cmp32_0(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s3, int
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
NAT_FLAGS_ENABLE_CARRY();
|
||||
NAT_FLAGS_ENABLE_SIGN();
|
||||
if (la64_lbt) {
|
||||
IFX(X_ALL) {
|
||||
if (rex.w)
|
||||
@@ -265,6 +374,21 @@ void emit_cmp32_0(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s3, int
|
||||
else
|
||||
X64_SUB_W(s1, xZR);
|
||||
}
|
||||
if (dyn->insts[ninst].nat_flags_fusion) {
|
||||
if (rex.w)
|
||||
NAT_FLAGS_OPS(s1, xZR);
|
||||
else {
|
||||
if (dyn->insts[ninst].nat_flags_needsign) {
|
||||
SEXT_W(s3, s1);
|
||||
NAT_FLAGS_OPS(s3, xZR);
|
||||
} else if (MODREG) {
|
||||
ZEROUP2(s3, s1);
|
||||
NAT_FLAGS_OPS(s3, xZR);
|
||||
} else {
|
||||
NAT_FLAGS_OPS(s1, xZR);
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -278,12 +402,34 @@ void emit_cmp32_0(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s3, int
|
||||
}
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
int res = s1;
|
||||
IFX (X_ZF | X_PF) {
|
||||
if (!rex.w && MODREG) {
|
||||
ZEROUP2(s5, s1);
|
||||
res = s5;
|
||||
}
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
BNEZ(res, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, res, s3, s4);
|
||||
}
|
||||
if (dyn->insts[ninst].nat_flags_fusion) {
|
||||
if (rex.w)
|
||||
NAT_FLAGS_OPS(s1, xZR);
|
||||
else {
|
||||
if (dyn->insts[ninst].nat_flags_needsign) {
|
||||
SEXT_W(s3, s1);
|
||||
NAT_FLAGS_OPS(s3, xZR);
|
||||
} else if (res == s5) { // zero-up'd case
|
||||
NAT_FLAGS_OPS(res, xZR);
|
||||
} else {
|
||||
ZEROUP2(s3, s1);
|
||||
NAT_FLAGS_OPS(s3, xZR);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,14 +443,23 @@ void emit_test8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4,
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
NAT_FLAGS_ENABLE_SIGN();
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s3, xZR);
|
||||
if (la64_lbt) {
|
||||
IFX(X_ALL) {
|
||||
X64_AND_B(s1, s2);
|
||||
}
|
||||
|
||||
IFX_PENDOR0 {
|
||||
if (dyn->insts[ninst].nat_flags_fusion) {
|
||||
AND(s3, s1, s2);
|
||||
ST_D(s3, xEmu, offsetof(x64emu_t, res));
|
||||
if (dyn->insts[ninst].nat_flags_needsign) {
|
||||
EXT_W_B(s3, s3);
|
||||
}
|
||||
}
|
||||
|
||||
IFX_PENDOR0 {
|
||||
if (!dyn->insts[ninst].nat_flags_fusion) AND(s3, s1, s2);
|
||||
ST_B(s3, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -327,6 +482,64 @@ void emit_test8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4,
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s3, s4, s5);
|
||||
}
|
||||
if (dyn->insts[ninst].nat_flags_fusion && dyn->insts[ninst].nat_flags_needsign) {
|
||||
EXT_W_B(s3, s3);
|
||||
}
|
||||
}
|
||||
|
||||
// emit TEST8 instruction, from test s1, c, using s3, s4 and s5 as scratch
|
||||
void emit_test8c(dynarec_la64_t* dyn, int ninst, int s1, uint8_t c, int s3, int s4, int s5)
|
||||
{
|
||||
IFX_PENDOR0 {
|
||||
SET_DF(s3, d_tst8);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
NAT_FLAGS_ENABLE_SIGN();
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s3, xZR);
|
||||
|
||||
if (la64_lbt) {
|
||||
IFX (X_ALL) {
|
||||
ADDI_D(s3, xZR, c);
|
||||
X64_AND_B(s1, s3);
|
||||
}
|
||||
|
||||
if (dyn->insts[ninst].nat_flags_fusion) {
|
||||
ANDI(s3, s1, c);
|
||||
if (dyn->insts[ninst].nat_flags_needsign) {
|
||||
EXT_W_B(s3, s3);
|
||||
}
|
||||
}
|
||||
|
||||
IFX_PENDOR0 {
|
||||
if (!dyn->insts[ninst].nat_flags_fusion) ANDI(s3, s1, c);
|
||||
ST_B(s3, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
ANDI(s3, s1, c); // res = s1 & c
|
||||
|
||||
IFX_PENDOR0 {
|
||||
ST_D(s3, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX (X_SF) {
|
||||
SRLI_D(s4, s3, 7);
|
||||
BEQZ(s4, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
IFX (X_ZF) {
|
||||
BNEZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX (X_PF) {
|
||||
emit_pf(dyn, ninst, s3, s4, s5);
|
||||
}
|
||||
if (dyn->insts[ninst].nat_flags_fusion && dyn->insts[ninst].nat_flags_needsign) {
|
||||
EXT_W_B(s3, s3);
|
||||
}
|
||||
}
|
||||
|
||||
// emit TEST16 instruction, from test s1, s2, using s3, s4 and s5 as scratch
|
||||
@@ -338,13 +551,22 @@ void emit_test16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4,
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
NAT_FLAGS_ENABLE_SIGN();
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s3, xZR);
|
||||
if (la64_lbt) {
|
||||
IFX (X_ALL) {
|
||||
X64_AND_H(s1, s2);
|
||||
}
|
||||
|
||||
IFX_PENDOR0 {
|
||||
if (dyn->insts[ninst].nat_flags_fusion) {
|
||||
AND(s3, s1, s2);
|
||||
if (dyn->insts[ninst].nat_flags_needsign) {
|
||||
EXT_W_H(s3, s3);
|
||||
}
|
||||
}
|
||||
|
||||
IFX_PENDOR0 {
|
||||
if (!dyn->insts[ninst].nat_flags_fusion) AND(s3, s1, s2);
|
||||
ST_H(s3, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
@@ -368,6 +590,9 @@ void emit_test16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4,
|
||||
IFX (X_PF) {
|
||||
emit_pf(dyn, ninst, s3, s4, s5);
|
||||
}
|
||||
if (dyn->insts[ninst].nat_flags_fusion && dyn->insts[ninst].nat_flags_needsign) {
|
||||
EXT_W_H(s3, s3);
|
||||
}
|
||||
}
|
||||
|
||||
// emit TEST32 instruction, from test s1, s2, using s3 and s4 as scratch
|
||||
@@ -379,6 +604,8 @@ void emit_test32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
NAT_FLAGS_ENABLE_SIGN();
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s3, xZR);
|
||||
if (la64_lbt) {
|
||||
IFX(X_ALL) {
|
||||
if (rex.w)
|
||||
@@ -387,8 +614,17 @@ void emit_test32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int
|
||||
X64_AND_W(s1, s2);
|
||||
}
|
||||
|
||||
IFX_PENDOR0 {
|
||||
if (dyn->insts[ninst].nat_flags_fusion) {
|
||||
AND(s3, s1, s2);
|
||||
if (dyn->insts[ninst].nat_flags_needsign) {
|
||||
if (!rex.w) SEXT_W(s3, s3);
|
||||
} else if (!rex.w) {
|
||||
ZEROUP(s3);
|
||||
}
|
||||
}
|
||||
|
||||
IFX_PENDOR0 {
|
||||
if (!dyn->insts[ninst].nat_flags_fusion) AND(s3, s1, s2);
|
||||
SDxw(s3, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
@@ -415,18 +651,27 @@ void emit_test32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s3, s4, s5);
|
||||
}
|
||||
if (dyn->insts[ninst].nat_flags_fusion && !rex.w) {
|
||||
if (dyn->insts[ninst].nat_flags_needsign) {
|
||||
SEXT_W(s3, s3);
|
||||
} else {
|
||||
ZEROUP(s3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// emit TEST32 instruction, from test s1, s2, using s3 and s4 as scratch
|
||||
void emit_test32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4, int s5)
|
||||
{
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s3, xZR);
|
||||
IFX_PENDOR0 {
|
||||
SET_DF(s3, rex.w ? d_tst64 : d_tst32);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
|
||||
NAT_FLAGS_ENABLE_SIGN();
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s3, xZR);
|
||||
if (la64_lbt) {
|
||||
IFX(X_ALL) {
|
||||
MOV64xw(s3, c);
|
||||
@@ -436,13 +681,23 @@ void emit_test32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c,
|
||||
X64_AND_W(s1, s3);
|
||||
}
|
||||
|
||||
IFX_PENDOR0 {
|
||||
if (c >= 0 && c <= 4095) {
|
||||
ANDI(s3, s1, c);
|
||||
} else {
|
||||
IFX(X_ALL) { } else MOV64xw(s3, c);
|
||||
AND(s3, s1, s3);
|
||||
if (c >= 0 && c <= 4095) {
|
||||
ANDI(s3, s1, c);
|
||||
} else {
|
||||
IFX (X_ALL) {
|
||||
} else
|
||||
MOV64xw(s3, c);
|
||||
AND(s3, s1, s3);
|
||||
}
|
||||
if (dyn->insts[ninst].nat_flags_fusion) {
|
||||
if (dyn->insts[ninst].nat_flags_needsign) {
|
||||
if (!rex.w) SEXT_W(s3, s3);
|
||||
} else if (!rex.w) {
|
||||
ZEROUP(s3);
|
||||
}
|
||||
}
|
||||
|
||||
IFX_PENDOR0 {
|
||||
SDxw(s3, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
@@ -471,4 +726,11 @@ void emit_test32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c,
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s3, s4, s5);
|
||||
}
|
||||
if (dyn->insts[ninst].nat_flags_fusion && !rex.w) {
|
||||
if (dyn->insts[ninst].nat_flags_needsign) {
|
||||
SEXT_W(s3, s3);
|
||||
} else {
|
||||
ZEROUP(s3);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loaded 100 of 468 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user