mirror of
https://github.com/ptitSeb/box64.git
synced 2026-11-08 17:39:19 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7eeb501649 | ||
|
|
fe6b9327d1 | ||
|
|
d43e64ee46 | ||
|
|
e477ccdb19 | ||
|
|
d0c1ec5c8c | ||
|
|
274946acf5 | ||
|
|
3c976b1ffb | ||
|
|
48c1f8fb11 | ||
|
|
599360ce07 | ||
|
|
b41c3f22be | ||
|
|
13cb80d1b7 | ||
|
|
a4479a9ac0 | ||
|
|
7edd021c17 | ||
|
|
f6beb4320e | ||
|
|
55e8ebf525 | ||
|
|
f388a8f493 | ||
|
|
3e71087a87 | ||
|
|
24e4039d1f | ||
|
|
fc8a05e693 | ||
|
|
ee99b5b167 | ||
|
|
2f23572e02 | ||
|
|
21d66686da | ||
|
|
01af6f3164 | ||
|
|
c845ab01c4 | ||
|
|
13c9fdaa40 | ||
|
|
0bc4d5b532 | ||
|
|
18a3f1b039 | ||
|
|
b99dde293d | ||
|
|
ff634b1e0c | ||
|
|
657d69aa3b | ||
|
|
913abd14f0 | ||
|
|
1a7ea1c09a | ||
|
|
08934a3b0c | ||
|
|
55c967fe9d | ||
|
|
dea4646116 | ||
|
|
c90a2ab5a4 | ||
|
|
06f5fa3e6c | ||
|
|
2260cf8a48 | ||
|
|
5571c43de6 | ||
|
|
91b32b01d5 | ||
|
|
95b4d665cf | ||
|
|
ac35b41b9d | ||
|
|
2db72f51be | ||
|
|
3c266d33e3 | ||
|
|
feaf6ffbd0 | ||
|
|
91788694ba | ||
|
|
1f921abaec | ||
|
|
0874bb4d01 | ||
|
|
6b32d6159f | ||
|
|
83336bcb9f | ||
|
|
fe556e957e | ||
|
|
cbcd11894c | ||
|
|
29bf151ed9 | ||
|
|
95b68190b3 | ||
|
|
c596f176bf | ||
|
|
74fd2a0a5d | ||
|
|
f20db6caae | ||
|
|
dd75b58943 | ||
|
|
17a84fcc51 | ||
|
|
eef68182b3 | ||
|
|
43dcbf3773 | ||
|
|
b1a706a650 | ||
|
|
ce14608947 | ||
|
|
dc53da7252 | ||
|
|
9e2779267f | ||
|
|
0416caa95a | ||
|
|
7e2528c538 | ||
|
|
58fb00b5f7 | ||
|
|
1957721f37 | ||
|
|
132d40108b | ||
|
|
c843a2df6a | ||
|
|
58542e4a72 | ||
|
|
ba20a27530 | ||
|
|
4743babdf2 | ||
|
|
c0c2780db4 | ||
|
|
97edb1092f | ||
|
|
3697d82ad1 | ||
|
|
df00419f69 | ||
|
|
11bb70178b | ||
|
|
5e03e18c68 | ||
|
|
a696462cc3 | ||
|
|
cda0c94b83 | ||
|
|
9a1fcc84b0 | ||
|
|
9571135b8d | ||
|
|
95bd956af8 | ||
|
|
6ebd9c3b32 | ||
|
|
0b9df5d5a0 | ||
|
|
c52f2fd01a | ||
|
|
0a60b449ca | ||
|
|
b3056386f2 | ||
|
|
63feea5fc4 | ||
|
|
f4f17b7751 | ||
|
|
7750e75bcf | ||
|
|
d0d32e763d | ||
|
|
e68b1f7584 | ||
|
|
beaa2c8a3a | ||
|
|
c48c60a814 | ||
|
|
7688169969 | ||
|
|
aebde89ba3 | ||
|
|
7f96fa4334 | ||
|
|
3206d6a76a | ||
|
|
a613ff8277 | ||
|
|
489bd8de29 | ||
|
|
d5a1864cfa | ||
|
|
c85b3d6252 | ||
|
|
4fc725fc61 | ||
|
|
52fd5ed052 | ||
|
|
eb804f37c5 | ||
|
|
0c992cdcff | ||
|
|
26dcfc7320 | ||
|
|
3c3918073f | ||
|
|
78183c16de | ||
|
|
75c7f07571 | ||
|
|
961484f463 | ||
|
|
54698875f0 | ||
|
|
edb9bc21cf | ||
|
|
ce3afa470e | ||
|
|
8757bd2b5d | ||
|
|
d8371894ca | ||
|
|
537c8f4c53 | ||
|
|
79a34b3d9c | ||
|
|
f713cc5840 | ||
|
|
6f1d048924 | ||
|
|
761b2df415 | ||
|
|
ca7fc7b60b | ||
|
|
96239cee6e | ||
|
|
5828660374 | ||
|
|
d7c86cadf6 | ||
|
|
bff0cf46da | ||
|
|
cb362477e8 | ||
|
|
eb3a95e336 | ||
|
|
3f69a46d9b | ||
|
|
aaa5883f72 | ||
|
|
66ccc3f65d | ||
|
|
5506656a39 | ||
|
|
d3b60ad6cc | ||
|
|
b2b6620e05 | ||
|
|
ae86b32f14 | ||
|
|
56ec4c57ee | ||
|
|
e4270f1d28 | ||
|
|
be199c5812 | ||
|
|
8dde29fedf | ||
|
|
518f065591 | ||
|
|
4aa0cdf781 | ||
|
|
38d793e0b5 | ||
|
|
00e4f02a2a | ||
|
|
64df236782 | ||
|
|
40d796a52f | ||
|
|
52cd1d09e0 | ||
|
|
93d9e2196f | ||
|
|
5534fc6191 | ||
|
|
1f853671b1 | ||
|
|
7bf29e8ab9 | ||
|
|
b2e87cfc16 | ||
|
|
1c9ab05a1b | ||
|
|
2df07b594d | ||
|
|
279c65057a | ||
|
|
4986517339 | ||
|
|
5d9e853496 | ||
|
|
690dfbb35e | ||
|
|
26e1cf5e0b | ||
|
|
e09ae017d4 | ||
|
|
ca122f4ce2 | ||
|
|
f83f593862 | ||
|
|
d69d116a90 | ||
|
|
5b2813382e | ||
|
|
8f07d10c0a | ||
|
|
ac2e11908c | ||
|
|
49bb5168a7 | ||
|
|
9178a54dc6 | ||
|
|
34134c1685 | ||
|
|
73ce74140a | ||
|
|
9401712b3c | ||
|
|
37bd00b656 | ||
|
|
fba7c6d9b2 | ||
|
|
3d8fcd9780 | ||
|
|
7b7077826f | ||
|
|
435564e172 | ||
|
|
11a44fc754 | ||
|
|
4e5c914ccf | ||
|
|
7e1fc8924c | ||
|
|
d6c16aee4b | ||
|
|
ed33cbe372 | ||
|
|
7bdc4c3713 | ||
|
|
285907753a | ||
|
|
f91b774440 | ||
|
|
a351971364 | ||
|
|
4509cb3780 | ||
|
|
a3b63db1ed | ||
|
|
d2dc1c1806 | ||
|
|
a0ed780f72 | ||
|
|
d3db6a0021 | ||
|
|
b2101b9b7c | ||
|
|
0af396cec9 | ||
|
|
52f0fd5421 | ||
|
|
1f705fc13a | ||
|
|
601bba694a | ||
|
|
a724bb70fd | ||
|
|
08d376c660 | ||
|
|
dfbbf2c0e5 | ||
|
|
827236abdf | ||
|
|
cf74a99458 | ||
|
|
4a4a03cd2a | ||
|
|
1ad0b9c737 | ||
|
|
18926d8e8c | ||
|
|
e1c7eb8a70 | ||
|
|
ae7c7d360a | ||
|
|
f30ea80b20 | ||
|
|
c5e8a15923 | ||
|
|
f88108ca8f | ||
|
|
2a1d9fd6a6 | ||
|
|
799647b6ac | ||
|
|
1eb508ba4e | ||
|
|
a22ab3511f | ||
|
|
8566cccc51 | ||
|
|
f1dc147532 | ||
|
|
ecffe8882e | ||
|
|
9a8ec4c1b6 | ||
|
|
a004efdefe | ||
|
|
3c44b2119f | ||
|
|
1ce47890c9 | ||
|
|
28d542b40a | ||
|
|
52539fbfc2 | ||
|
|
e41f38cd37 | ||
|
|
4474ac0f19 | ||
|
|
8189831cea | ||
|
|
90573a1874 | ||
|
|
bcdaa3da83 | ||
|
|
9f0e1ff6a8 | ||
|
|
46bea9b336 | ||
|
|
9558d59aaf | ||
|
|
11e5b8752e | ||
|
|
f29572a3d2 | ||
|
|
e2ebb95fd2 | ||
|
|
96735b63cf | ||
|
|
2b9cc9068e | ||
|
|
3ab34da16a | ||
|
|
24065fffb5 | ||
|
|
4375d229b2 | ||
|
|
f0f2e48946 | ||
|
|
8b4c9b3bf0 | ||
|
|
b7d432586c | ||
|
|
3bd4e2a8dd | ||
|
|
90d900ca28 | ||
|
|
df9bce4cd2 | ||
|
|
2d15050b85 | ||
|
|
aafe2e34c3 | ||
|
|
eb9583fa7a | ||
|
|
8ab8b98b8c | ||
|
|
676ae0ae5d | ||
|
|
c242e5e93f | ||
|
|
58005447fc | ||
|
|
9a394d3c7b | ||
|
|
566ca4df09 | ||
|
|
ec39f7e9d2 | ||
|
|
cbf21d696f | ||
|
|
b250ba9773 | ||
|
|
3435090558 | ||
|
|
863cb47ff4 | ||
|
|
5a83602c10 | ||
|
|
c9ae41991f | ||
|
|
d62d65dbae | ||
|
|
dd4ce54a52 | ||
|
|
c92456a744 | ||
|
|
8ad838ecb7 | ||
|
|
cf0c088c43 | ||
|
|
3acd719843 | ||
|
|
79052e9df9 | ||
|
|
7e5310b260 | ||
|
|
815b6f17ce | ||
|
|
1848ec1ee8 | ||
|
|
1ff11d67ef | ||
|
|
14f610b4e9 | ||
|
|
f53654b555 | ||
|
|
e4d852f3c7 | ||
|
|
4cf52d5636 | ||
|
|
baa1afeb5c | ||
|
|
77aabfcad3 | ||
|
|
16ca4f28fe | ||
|
|
77ffe39472 | ||
|
|
f1b2076890 | ||
|
|
bc16008759 | ||
|
|
03324f6c73 | ||
|
|
b561993f6e | ||
|
|
430ca5b954 | ||
|
|
960cc2dbb7 | ||
|
|
fdc317334c | ||
|
|
147898cd80 | ||
|
|
f2881840e6 | ||
|
|
81a5d1cee0 | ||
|
|
af7df03221 | ||
|
|
0592854919 | ||
|
|
aab7817df8 | ||
|
|
15994e78c7 | ||
|
|
3e3ad92f30 | ||
|
|
92e52c0b77 | ||
|
|
34a813764b | ||
|
|
dbfafb82fa | ||
|
|
388d9c88a4 | ||
|
|
2c293fc742 | ||
|
|
1c5d1f515c | ||
|
|
740eab30ce | ||
|
|
3a00578707 | ||
|
|
f69720119a | ||
|
|
b5639f884d | ||
|
|
2ef63f29f1 | ||
|
|
b975a87cf9 | ||
|
|
58d3525cbc | ||
|
|
0c76a09575 | ||
|
|
dee9a747ae | ||
|
|
1e1b37a45d | ||
|
|
2ee476465d | ||
|
|
a3c5c60975 | ||
|
|
2fb1ad18c0 | ||
|
|
fc8b34ebc5 | ||
|
|
d43b3000a4 | ||
|
|
5dd2ecdde9 | ||
|
|
69f2a9c388 | ||
|
|
fafdb6e516 | ||
|
|
fbfb4697ad | ||
|
|
b8469abb05 | ||
|
|
ac11fd4f01 | ||
|
|
373c002347 | ||
|
|
71ea8eb17e | ||
|
|
de13462e0f | ||
|
|
e02d60c792 | ||
|
|
0c5a9cc2ca | ||
|
|
9a39b2eb9b | ||
|
|
cf7070f3e0 | ||
|
|
63e0b7d251 | ||
|
|
13c8510ad1 | ||
|
|
a8a9bee86b | ||
|
|
ecce4145c9 | ||
|
|
8f8c4abc20 | ||
|
|
695a0b3744 | ||
|
|
16107c0bec | ||
|
|
896a9602a7 | ||
|
|
c7bc293292 | ||
|
|
05b1086f09 | ||
|
|
dff10fdfc7 | ||
|
|
22a5520e98 | ||
|
|
857991c500 | ||
|
|
35e04bd69d | ||
|
|
e5e9d5809e | ||
|
|
0fed9f364a | ||
|
|
49b5b131a2 | ||
|
|
dc58ff0315 | ||
|
|
f35c00e278 | ||
|
|
efa4961e46 | ||
|
|
a469a16a65 | ||
|
|
bf76c36327 | ||
|
|
c7247cf335 | ||
|
|
a25e2a3ae4 | ||
|
|
5477586dab | ||
|
|
a267631d92 | ||
|
|
3d775a4c5d | ||
|
|
80253a6f22 | ||
|
|
3989cfd2fc | ||
|
|
62f566e8e8 | ||
|
|
d8bb64b147 | ||
|
|
521b3784b5 | ||
|
|
3eed18214e | ||
|
|
8060bf2d3f | ||
|
|
ed98279202 | ||
|
|
0f38d9d02e | ||
|
|
98e5753ae1 | ||
|
|
a0b962c18e | ||
|
|
6e534739c2 | ||
|
|
9ea17e0192 | ||
|
|
f256834627 | ||
|
|
e246fcca7f | ||
|
|
398b4b0ccc | ||
|
|
1e17b17ae1 | ||
|
|
1e89645ef6 | ||
|
|
d7f4176de3 | ||
|
|
7591fce9fc | ||
|
|
34004b84bb | ||
|
|
e915221be7 | ||
|
|
41c7a5320e | ||
|
|
6c62e16d14 | ||
|
|
ea503d4559 | ||
|
|
a0dfa80005 | ||
|
|
074223016c | ||
|
|
6f1361dd58 | ||
|
|
367b80c9d9 | ||
|
|
1a0974efbd | ||
|
|
3ad2856ade | ||
|
|
d3031abc40 | ||
|
|
321643324a | ||
|
|
4f01e75a53 | ||
|
|
be89f30b3d | ||
|
|
72fe79db7c | ||
|
|
3dc758284e | ||
|
|
6b86d11006 | ||
|
|
5dd12a0042 | ||
|
|
0b5c1fcc2f | ||
|
|
1c0830e496 | ||
|
|
110566d468 | ||
|
|
6f3f7cffc3 | ||
|
|
790207a1e9 | ||
|
|
a2002cdfb7 | ||
|
|
322a9f17c5 | ||
|
|
8879ead6b1 | ||
|
|
7f45efeebd | ||
|
|
2d468b116e | ||
|
|
ad5b0d681c | ||
|
|
07e82e6230 | ||
|
|
9c9e91d090 | ||
|
|
9d9a1e3ac0 | ||
|
|
2500d0541d | ||
|
|
4e330169c9 | ||
|
|
045ccb80b7 | ||
|
|
6613ccefd8 | ||
|
|
59fa3067d2 | ||
|
|
ba1b73da0f | ||
|
|
1aed7e0281 | ||
|
|
b3b7f3a6f1 | ||
|
|
48fb691aed | ||
|
|
a56f17d907 | ||
|
|
69437ad173 | ||
|
|
99497205b5 | ||
|
|
90d1c51a35 | ||
|
|
6de77e7cd0 | ||
|
|
abbbd05411 | ||
|
|
70bb817dfa | ||
|
|
faf7c69341 | ||
|
|
c1b5c992dc | ||
|
|
41d56aa052 | ||
|
|
81553485d1 | ||
|
|
8f9603ba2a | ||
|
|
97a405d690 | ||
|
|
9d9b20c672 | ||
|
|
b07e2ea9d7 | ||
|
|
96435ff12b | ||
|
|
7a8f1f523b | ||
|
|
88272c2ee7 | ||
|
|
9d9a777dde | ||
|
|
5ffe1068fb | ||
|
|
da9588860a | ||
|
|
544e71ab3c | ||
|
|
c52c9540e3 | ||
|
|
05df55f89e | ||
|
|
b9a4d6f814 | ||
|
|
bc583e3828 | ||
|
|
2e724f461d | ||
|
|
9e260d563f | ||
|
|
b321083929 | ||
|
|
25ce305092 | ||
|
|
5ec806058f | ||
|
|
2fdfc4aaca | ||
|
|
808e22f183 | ||
|
|
c389bdff4c | ||
|
|
3bbb84502e | ||
|
|
c45c6ddd86 | ||
|
|
2f9eb362c0 | ||
|
|
f9c32107c1 | ||
|
|
f2443996b4 | ||
|
|
ec4275ab42 | ||
|
|
cfff06e6f4 | ||
|
|
fc809368d0 | ||
|
|
131aebd02b | ||
|
|
d415c28347 | ||
|
|
e85f190a50 | ||
|
|
8f8aa39d39 | ||
|
|
242a4ca810 | ||
|
|
a62d5dd435 | ||
|
|
6b381068ef | ||
|
|
652da4fbcf | ||
|
|
452f564ad3 | ||
|
|
bae577f915 | ||
|
|
6c9e068aef | ||
|
|
8240cf8cfd | ||
|
|
1b3abd7ac4 | ||
|
|
b587834c04 | ||
|
|
548fd15338 | ||
|
|
4fd547d7b1 | ||
|
|
191fbf3b1a | ||
|
|
daa6f7c483 | ||
|
|
a758d17e7f | ||
|
|
ab41c03dd2 | ||
|
|
ca16ef8177 | ||
|
|
a7c1541abb | ||
|
|
935f6bcb28 | ||
|
|
3310b7c718 | ||
|
|
a87b9fa9ee | ||
|
|
62ab624a7a | ||
|
|
627b857cb4 | ||
|
|
1e5c085b88 | ||
|
|
990632d5b8 | ||
|
|
364436405b | ||
|
|
b9f17a819f | ||
|
|
c9ccaaed1b | ||
|
|
72807b6b95 | ||
|
|
05b37ab897 | ||
|
|
ded7dab17b | ||
|
|
715a239f1c | ||
|
|
41bc4c5971 | ||
|
|
22f31e73bf | ||
|
|
47e2b974fc | ||
|
|
2319b5a0eb | ||
|
|
426a4f38a7 | ||
|
|
6e2d08c4b7 | ||
|
|
a288925967 | ||
|
|
f06933aad7 | ||
|
|
5c7b90a52a | ||
|
|
4bcc910d15 | ||
|
|
2e3ccd9fff | ||
|
|
68de1d4fc9 | ||
|
|
be35201c65 | ||
|
|
0eb0f9decb | ||
|
|
470203c39a | ||
|
|
a2d5a172bf | ||
|
|
7d30bd40ff | ||
|
|
c5f81e8a05 | ||
|
|
361d71baee | ||
|
|
9810a7e219 | ||
|
|
694d08ddec | ||
|
|
17662a6605 | ||
|
|
6139c1ae81 | ||
|
|
25f83ca9ec | ||
|
|
a6c6b488a1 | ||
|
|
3ec5de03c7 | ||
|
|
90bcfff19b | ||
|
|
c3f293a937 | ||
|
|
9b645b902e | ||
|
|
8fdce4365e | ||
|
|
982fd87284 | ||
|
|
a9ef6fa588 | ||
|
|
b7ed3fabde | ||
|
|
377e2b27a4 | ||
|
|
c99d5054c6 | ||
|
|
b5407c4aab | ||
|
|
aca2450749 | ||
|
|
9f501924ee | ||
|
|
dc7b9216ed | ||
|
|
a2a1f1cc40 | ||
|
|
8744f024c8 | ||
|
|
af508f9d5c | ||
|
|
ca30eb91de | ||
|
|
aa7b392034 | ||
|
|
99e2fc52b5 | ||
|
|
df223496b2 | ||
|
|
c5c52c2852 | ||
|
|
f753453d9c | ||
|
|
8df09b2609 | ||
|
|
8621d5aa75 | ||
|
|
a0d01deb1b | ||
|
|
0414fadaf0 | ||
|
|
cef139306b | ||
|
|
2eb2fd9cd5 | ||
|
|
b798e0da20 | ||
|
|
ed038dfdfb | ||
|
|
470e05f9e2 | ||
|
|
72edb453bf | ||
|
|
341b20c3e4 | ||
|
|
32e513c533 | ||
|
|
5929e402bf | ||
|
|
746dc47485 | ||
|
|
6e31a7e266 | ||
|
|
78d59dcee8 | ||
|
|
fdeec17ff0 | ||
|
|
8d53ad5408 | ||
|
|
b4cea8a0d1 | ||
|
|
299c74752e | ||
|
|
cc9555d9e5 | ||
|
|
a13e2c1e3c | ||
|
|
2643191ad1 | ||
|
|
5a744a3366 | ||
|
|
c9d52c8f2a | ||
|
|
40cd903b07 | ||
|
|
61b1253e80 | ||
|
|
b48e0da81b | ||
|
|
9c1aadc722 | ||
|
|
1dd15db8d8 | ||
|
|
3717266c3a | ||
|
|
637139cce1 | ||
|
|
6d8c3c6afc | ||
|
|
8f08aa99b1 | ||
|
|
5533ccac38 | ||
|
|
fbbfc7ba0e | ||
|
|
7a7924495c | ||
|
|
68097c2721 | ||
|
|
239825c521 | ||
|
|
31b491da79 | ||
|
|
71f5207f6d | ||
|
|
0d1c027e9f | ||
|
|
b6c1735c07 | ||
|
|
6c5415886b | ||
|
|
f1b2dc603b | ||
|
|
b3a43af4d0 | ||
|
|
57e87b4ee9 | ||
|
|
6ed69e9575 | ||
|
|
b5c07726a7 | ||
|
|
055a58d878 | ||
|
|
fd4a9eaacf | ||
|
|
65c57ba8a6 | ||
|
|
07cfee3c07 | ||
|
|
6e0f1a3911 | ||
|
|
1df42cdb49 | ||
|
|
e588a32197 | ||
|
|
95eedcf0dd | ||
|
|
61d4a40130 | ||
|
|
af1b2c974f | ||
|
|
a7f81bcd4d | ||
|
|
5fc00acbbc | ||
|
|
283710f603 | ||
|
|
b9d36a205b | ||
|
|
7263e07f07 | ||
|
|
01f7f3f59e | ||
|
|
71520e80e7 | ||
|
|
da145dfe37 | ||
|
|
c31bf3329c | ||
|
|
51daf45373 | ||
|
|
887de0cb64 | ||
|
|
fc0c258934 | ||
|
|
152a381a98 | ||
|
|
240ee83c3d | ||
|
|
9d0f8d1d64 | ||
|
|
24076b60d7 | ||
|
|
e12c3769db | ||
|
|
5199e5c66d |
No files matched your search
@@ -0,0 +1 @@
|
||||
{ "contextFileName": "AGENTS.md" }
|
||||
@@ -15,6 +15,7 @@ on:
|
||||
- "**/*.py"
|
||||
- "CMakeLists.txt"
|
||||
- "**/*.yml"
|
||||
- "**/*.def"
|
||||
pull_request:
|
||||
types: [assigned, opened, synchronize, reopened]
|
||||
paths:
|
||||
@@ -24,6 +25,7 @@ on:
|
||||
- "**/*.py"
|
||||
- "CMakeLists.txt"
|
||||
- "**/*.yml"
|
||||
- "**/*.def"
|
||||
|
||||
defaults:
|
||||
run:
|
||||
@@ -35,7 +37,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [X64, RISCV, RK3588, ARM64, ANDROID, TERMUX, LARCH64, ANDROID_GLIBC, WOW64, ARM64-GCC-8]
|
||||
platform: [X64, RISCV, RK3588, ARM64, ANDROID, TERMUX, LARCH64, PPC64LE, ANDROID_GLIBC, WOW64]
|
||||
type: [Release, Trace, StaticBuild, Box32]
|
||||
exclude:
|
||||
- platform: ANDROID
|
||||
@@ -54,16 +56,14 @@ jobs:
|
||||
type: StaticBuild
|
||||
- platform: WOW64
|
||||
type: Box32
|
||||
- platform: ARM64-GCC-8
|
||||
type: Trace
|
||||
- platform: ARM64-GCC-8
|
||||
type: StaticBuild
|
||||
- platform: ANDROID
|
||||
type: Trace
|
||||
- platform: TERMUX
|
||||
type: Trace
|
||||
- platform: LARCH64
|
||||
type: Trace
|
||||
- platform: PPC64LE
|
||||
type: Trace
|
||||
include:
|
||||
- platform: X64
|
||||
os: ubuntu-latest
|
||||
@@ -86,31 +86,24 @@ jobs:
|
||||
- platform: LARCH64
|
||||
os: ubuntu-latest
|
||||
|
||||
- platform: PPC64LE
|
||||
os: ubuntu-latest
|
||||
|
||||
- platform: ANDROID_GLIBC
|
||||
os: ubuntu-22.04-arm
|
||||
|
||||
- platform: WOW64
|
||||
os: ubuntu-22.04-arm
|
||||
|
||||
- platform: ARM64-GCC-8
|
||||
os: ubuntu-22.04-arm
|
||||
image: arm64v8/ubuntu:18.04
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
container:
|
||||
image: ${{ matrix.image || '' }}
|
||||
steps:
|
||||
- name: "Checkout Box64 Repository"
|
||||
if: ${{ matrix.platform != 'ARM64-GCC-8' }}
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: "Checkout Box64 Repository (No NodeJS)"
|
||||
if: ${{ matrix.platform == 'ARM64-GCC-8' }}
|
||||
uses: taiki-e/checkout-action@v1
|
||||
|
||||
- name: Get all the unique changed directory names
|
||||
id: changed-files-dir-names
|
||||
if: ${{ matrix.platform != 'ARM64-GCC-8' }}
|
||||
uses: tj-actions/changed-files@ed68ef82c095e0d48ec87eccea555d944a631a4c # v46
|
||||
with:
|
||||
dir_names: "true"
|
||||
@@ -122,7 +115,7 @@ jobs:
|
||||
if: steps.changed-files-dir-names.outputs.all_modified_files == 'src/dynarec/arm64'
|
||||
continue-on-error: true
|
||||
run: |
|
||||
if [[ ${{ matrix.platform }} != 'RISCV' && ${{ matrix.platform }} != 'LARCH64' && ${{ matrix.platform }} != 'X64' ]]; then
|
||||
if [[ ${{ matrix.platform }} != 'RISCV' && ${{ matrix.platform }} != 'LARCH64' && ${{ matrix.platform }} != 'PPC64LE' && ${{ matrix.platform }} != 'X64' ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -148,18 +141,29 @@ jobs:
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Early exit other jobs if this is a PPC64LE-only change
|
||||
id: early-exit-ppc64le
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
if: steps.changed-files-dir-names.outputs.all_modified_files == 'src/dynarec/ppc64le'
|
||||
continue-on-error: true
|
||||
run: |
|
||||
if [[ ${{ matrix.platform }} == 'PPC64LE' ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Do not early exit otherwise
|
||||
id: early-exit-never
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
DIRS: ${{ steps.changed-files-dir-names.outputs.all_modified_files }}
|
||||
if: env.DIRS != 'src/dynarec/arm64' && env.DIRS != 'src/dynarec/la64' && env.DIRS != 'src/dynarec/rv64'
|
||||
if: env.DIRS != 'src/dynarec/arm64' && env.DIRS != 'src/dynarec/la64' && env.DIRS != 'src/dynarec/rv64' && env.DIRS != 'src/dynarec/ppc64le'
|
||||
continue-on-error: true
|
||||
run: exit 1
|
||||
|
||||
- name: Merge early exit conditions
|
||||
id: early-exit
|
||||
if: steps.early-exit-arm64.outcome == 'failure' || steps.early-exit-la64.outcome == 'failure' || steps.early-exit-rv64.outcome == 'failure' || steps.early-exit-never.outcome == 'failure'
|
||||
if: steps.early-exit-arm64.outcome == 'failure' || steps.early-exit-la64.outcome == 'failure' || steps.early-exit-rv64.outcome == 'failure' || steps.early-exit-ppc64le.outcome == 'failure' || steps.early-exit-never.outcome == 'failure'
|
||||
continue-on-error: true
|
||||
run: exit 1
|
||||
|
||||
@@ -168,14 +172,9 @@ jobs:
|
||||
- name: "Environment preparation"
|
||||
if: steps.early-exit.outcome == 'failure'
|
||||
run: |
|
||||
if [[ ${{ matrix.platform }} == 'ARM64-GCC-8' ]]; then
|
||||
apt-get update
|
||||
apt install -y sudo
|
||||
else
|
||||
sudo apt-get update
|
||||
zydis_package=libzydis-dev
|
||||
fi
|
||||
if [[ ${{ matrix.platform }} != 'X64' && ${{ matrix.platform }} != 'RISCV' && ${{ matrix.platform }} != 'LARCH64' ]]; then
|
||||
sudo apt-get update
|
||||
zydis_package=libzydis-dev
|
||||
if [[ ${{ matrix.platform }} != 'X64' && ${{ matrix.platform }} != 'RISCV' && ${{ matrix.platform }} != 'LARCH64' && ${{ matrix.platform }} != 'PPC64LE' ]]; then
|
||||
sudo apt-get -y install git cmake make python3 patchelf $zydis_package
|
||||
if [[ ${{ matrix.platform }} == 'ANDROID' || ${{ matrix.platform }} == 'TERMUX' ]]; then
|
||||
sudo apt-get -y install p7zip
|
||||
@@ -184,6 +183,9 @@ jobs:
|
||||
echo "BOX64_COMPILER=$PWD/android-ndk-r26b/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android31-clang" >> $GITHUB_ENV
|
||||
echo "BOX64_PLATFORM_MARCRO=-DANDROID=1 -DARM_DYNAREC=1 -DBAD_SIGNAL=1" >> $GITHUB_ENV
|
||||
git clone https://github.com/termux/termux-docker.git
|
||||
cd termux-docker
|
||||
git checkout 148b93d989cbc572719e050135b3e13f115f2a8e~1
|
||||
cd ..
|
||||
sudo cp -rf termux-docker/system/arm /system
|
||||
sudo chown -R $(whoami):$(whoami) /system
|
||||
sudo chmod 755 -R /system
|
||||
@@ -195,22 +197,10 @@ jobs:
|
||||
sudo apt-get -y install git gcc-aarch64-linux-gnu
|
||||
echo "BOX64_PLATFORM_MARCRO=-DWOW64=1 -DARM_DYNAREC=1" >> $GITHUB_ENV
|
||||
echo "BOX64_COMPILER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
|
||||
export LLVM_MINGW_VERSION=20250430
|
||||
export LLVM_MINGW_VERSION=20260311
|
||||
wget -q https://github.com/mstorsjo/llvm-mingw/releases/download/${LLVM_MINGW_VERSION}/llvm-mingw-${LLVM_MINGW_VERSION}-ucrt-ubuntu-22.04-aarch64.tar.xz
|
||||
tar -xf llvm-mingw-${LLVM_MINGW_VERSION}-ucrt-ubuntu-22.04-aarch64.tar.xz
|
||||
echo "MINGW_COMPILER_PATH=$PWD/llvm-mingw-${LLVM_MINGW_VERSION}-ucrt-ubuntu-22.04-aarch64/bin" >> $GITHUB_ENV
|
||||
elif [[ ${{ matrix.platform }} == 'ARM64-GCC-8' ]]; then
|
||||
# some of these dependencies may be unnecessary to explicitly install depending on the image
|
||||
sudo apt-get -y install git software-properties-common lsb-release \
|
||||
wget curl build-essential autoconf automake \
|
||||
pkg-config ca-certificates \
|
||||
python3 make gettext zstd \
|
||||
gcc-8 g++-8
|
||||
sudo add-apt-repository ppa:theofficialgman/cmake-bionic -y
|
||||
sudo apt update
|
||||
sudo apt install -y cmake
|
||||
echo "BOX64_PLATFORM_MARCRO=-DARM64=1" >> $GITHUB_ENV
|
||||
echo "BOX64_COMPILER=aarch64-linux-gnu-gcc-8" >> $GITHUB_ENV
|
||||
else
|
||||
sudo apt-get -y install git gcc-aarch64-linux-gnu
|
||||
echo "BOX64_PLATFORM_MARCRO=-D${{ matrix.platform }}=1" >> $GITHUB_ENV
|
||||
@@ -253,6 +243,10 @@ jobs:
|
||||
echo BOX64_PLATFORM_MARCRO="-DLARCH64=ON" >> $GITHUB_ENV
|
||||
echo "BOX64_COMPILER=loongarch64-linux-gnu-gcc" >> $GITHUB_ENV
|
||||
sudo apt-get -y install git cmake make python3 libzydis-dev
|
||||
elif [[ ${{ matrix.platform }} == 'PPC64LE' ]]; then
|
||||
echo BOX64_PLATFORM_MARCRO="-DPPC64LE=ON" >> $GITHUB_ENV
|
||||
echo "BOX64_COMPILER=powerpc64le-linux-gnu-gcc" >> $GITHUB_ENV
|
||||
sudo apt-get -y install git gcc-powerpc64le-linux-gnu cmake make python3 libzydis-dev
|
||||
else
|
||||
echo BOX64_PLATFORM_MARCRO="-DARM_DYNAREC=ON" >> $GITHUB_ENV
|
||||
echo "BOX64_COMPILER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
|
||||
@@ -386,11 +380,19 @@ jobs:
|
||||
export BOX32_PERSONA32BITS=1 # hack to disable personality setting
|
||||
fi
|
||||
ctest $CTEST_OPTIONS -E nocosim
|
||||
BOX64_DYNAREC_LA64NOEXT=1 ctest $CTEST_OPTIONS -E nocosim
|
||||
BOX64_DYNAREC_NOHOSTEXT=1 ctest $CTEST_OPTIONS -E nocosim
|
||||
BOX64_DYNAREC=0 ctest $CTEST_OPTIONS -E nocosim
|
||||
|
||||
BOX64_DYNAREC_TEST=1 ctest $CTEST_OPTIONS -E nocosim
|
||||
BOX64_DYNAREC_TEST=1 BOX64_DYNAREC_NOHOSTEXT=1 ctest $CTEST_OPTIONS -E nocosim
|
||||
elif [[ ${{ matrix.platform }} == 'PPC64LE' ]]; then
|
||||
export INTERPRETER=qemu-ppc64le-static
|
||||
export QEMU_LD_PREFIX=/usr/powerpc64le-linux-gnu/
|
||||
|
||||
ctest $CTEST_OPTIONS -E nocosim
|
||||
BOX64_DYNAREC=0 ctest $CTEST_OPTIONS -E nocosim
|
||||
|
||||
BOX64_DYNAREC_TEST=1 ctest $CTEST_OPTIONS -E nocosim
|
||||
BOX64_DYNAREC_TEST=1 BOX64_DYNAREC_LA64NOEXT=1 ctest $CTEST_OPTIONS -E nocosim
|
||||
elif [[ ${{ matrix.platform }} == 'ANDROID' ]]; then
|
||||
export INTERPRETER=qemu-aarch64-static
|
||||
export QEMU_LD_PREFIX=/system/lib64
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
name: 'Close stale issues and PRs'
|
||||
on:
|
||||
schedule:
|
||||
- cron: '* * * * 0'
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v10
|
||||
with:
|
||||
stale-issue-message: 'This issue is stale because it has been open 1 year with no activity. Remove "Stale" label or comment or this will be closed in 30 days.'
|
||||
days-before-stale: 365
|
||||
days-before-close: 30
|
||||
exempt-issue-labels: 'long-term'
|
||||
@@ -68,6 +68,8 @@ backup/
|
||||
/wrapperhelper/sanleak
|
||||
/wrapperhelper/sanundefined
|
||||
/wrapperhelper/src/machine.gen
|
||||
/wrapperhelper/src/machine_x86.gen
|
||||
/wrapperhelper/src/machine_x86_64.gen
|
||||
/wrapperhelper/*.h
|
||||
!/wrapperhelper/example-libc.h
|
||||
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
# Instructions for box64
|
||||
|
||||
> [!IMPORTANT]
|
||||
> This project does **not** accept pull requests that are fully or predominantly AI-generated. AI tools may be utilized solely in an assistive capacity.
|
||||
>
|
||||
> Read more: [CONTRIBUTING.md](CONTRIBUTING.md)
|
||||
|
||||
AI assistance is permissible only when the majority of the code is authored by a human contributor, with AI employed exclusively for wrapper (callbacks & structure conversion), for corrections or to expand on verbose modifications that the contributor has already conceptualized (see examples below)
|
||||
|
||||
## Guidelines for Contributors Using AI
|
||||
|
||||
These use cases are **permitted** when making a contribution with the help of AI:
|
||||
|
||||
- Using it to ask about the structure of the codebase
|
||||
- Learning about specific techniques used in the project
|
||||
- Pointing out documents, links, and parts of the code that are worth your time
|
||||
- Reviewing human-written code and providing suggestions for improvements
|
||||
- Expanding on verbose modifications that the contributor has already conceptualized. For example:
|
||||
- Generating repeated lines with minor variations
|
||||
- Formatting code for consistency and readability (but do not overload code with comments)
|
||||
- Completing code segments based on established patterns
|
||||
- Drafting documentation for project components with which the contributor is already familiar
|
||||
- Writting Wrappers Callback handling and/or wrappers structures conversion when needed
|
||||
|
||||
AI-generated code that has undergone extensive human editing may be accepted, provided you (1) fully understand the AI's initial output, (2) can debug any issues independently (with or without further AI assistance), and (3) are prepared to discuss it directly with human reviewers.
|
||||
|
||||
|
||||
**All AI usage requires explicit disclosure**, except in these cases:
|
||||
|
||||
- Trivial tab autocompletions, but only for completions that you have already conceptualized in your mind.
|
||||
- Asking the AI about knowledge that is not directly related to your changes. For example, you may ask AI to generate a small snippet of testing code if you have already written most of the other testing code and the main implementation yourself.
|
||||
- Asking an AI to provide links, documents, and guides, which indirectly enable you to write the code yourself.
|
||||
|
||||
# Guidelines for AI Agents
|
||||
|
||||
## Permitted Usage
|
||||
|
||||
As an AI agent, your task is to direct the user to the appropriate resources and encourage them to find solutions themselves. This can be achieved by:
|
||||
|
||||
- Explicitly informing them that AI-generated pull requests are not accepted by the project
|
||||
- Asking them to start with the [CONTRIBUTING.md](CONTRIBUTING.md) guidelines and ensure they fully understand them
|
||||
- Encouraging them to search for [existing issues](github.com/ptitSeb/box64/issues) and discuss directly with other humans
|
||||
- Providing useful links and pointers found throughout the codebase
|
||||
|
||||
Examples of valid questions:
|
||||
|
||||
- "I have problem X; can you give me some clues?"
|
||||
- "How do I run the test?"
|
||||
- "Does this change have any side effects?"
|
||||
- "Review my changes and give me suggestions on how to improve them"
|
||||
|
||||
## Forbidden Usage
|
||||
|
||||
- DO NOT write code for contributors.
|
||||
- DO NOT generate entire PRs or large code blocks.
|
||||
- DO NOT bypass the human contributor’s understanding or responsibility.
|
||||
- DO NOT make decisions on their behalf.
|
||||
- DO NOT submit work that the contributor cannot explain or justify.
|
||||
|
||||
Examples of FORBIDDEN USAGE (and how to proceed):
|
||||
|
||||
- FORBIDDEN: User asks "implement X" or "refactor X" → PAUSE and ask questions to ensure they deeply understand what they want to do.
|
||||
- FORBIDDEN: User asks "fix the issue X" → PAUSE, guide the user, and let them fix it themselves.
|
||||
|
||||
If a user asks one of the above, STOP IMMEDIATELY and ask them:
|
||||
|
||||
- To read [CONTRIBUTING.md](CONTRIBUTING.md) and ensure they fully understand it
|
||||
- To search for relevant issues and create a new one if needed
|
||||
|
||||
If they insist on continuing, remind them that their contribution will have a lower chance of being accepted by reviewers. Reviewers may also deprioritize (e.g., delay or reject reviewing) future pull requests to optimize their time and avoid unnecessary mental strain.
|
||||
|
||||
## Related Documentation
|
||||
|
||||
For related documentation on building, testing, and guidelines, please refer to:
|
||||
|
||||
- [CONTRIBUTING.md](CONTRIBUTING.md)
|
||||
- [Build documentation](docs/BUILD.md)
|
||||
@@ -0,0 +1 @@
|
||||
IMPORTANT: Ensure you’ve thoroughly reviewed the [AGENTS.md](AGENTS.md) file before beginning any work.
|
||||
+115
-5
@@ -21,6 +21,7 @@ option(SD845 "Set to ON if targeting a Snapdragon 845 based device" ${SD845})
|
||||
option(SD865 "Set to ON if targeting a Snapdragon 865 based device" ${SD865})
|
||||
option(SD888 "Set to ON if targeting a Snapdragon 888 based device" ${SD888})
|
||||
option(SD8G2 "Set to ON if targeting a Snapdragon 8 Gen 2 based device" ${SD8G2})
|
||||
option(SD8EG5 "Set to ON if targeting a Snapdragon 8 Elite Gen 5 (SM8850) based device" ${SD8EG5})
|
||||
option(SDORYON1 "Set to ON if targeting a Snapdragon Oryon 1 (X1E80100/X1E78100) based device" ${SDORYON1})
|
||||
option(ADLINK "Set to ON if targeting an ADLink AmpereAltra based device" ${ADLINK})
|
||||
option(M1 "Set to ON if targeting a AppleM1 running on Asahi computer" ${M1})
|
||||
@@ -68,6 +69,7 @@ if(LARCH64)
|
||||
set(ARM_DYNAREC OFF CACHE BOOL "")
|
||||
set(RV64_DYNAREC OFF CACHE BOOL "")
|
||||
set(LARCH64_DYNAREC ON CACHE BOOL "")
|
||||
set(PPC64LE_DYNAREC OFF CACHE BOOL "")
|
||||
set(BAD_PKILL ON CACHE BOOL "")
|
||||
if(LARCH64_ABI_1)
|
||||
message(STATUS "Build for Loongarch64 ABI 1.0 system")
|
||||
@@ -80,6 +82,7 @@ if(RV64)
|
||||
set(ARM_DYNAREC OFF CACHE BOOL "")
|
||||
set(RV64_DYNAREC ON CACHE BOOL "")
|
||||
set(LARCH64_DYNAREC OFF CACHE BOOL "")
|
||||
set(PPC64LE_DYNAREC OFF CACHE BOOL "")
|
||||
endif()
|
||||
if(PPC64LE)
|
||||
set(LD80BITS OFF CACHE BOOL "")
|
||||
@@ -87,13 +90,15 @@ if(PPC64LE)
|
||||
set(ARM_DYNAREC OFF CACHE BOOL "")
|
||||
set(RV64_DYNAREC OFF CACHE BOOL "")
|
||||
set(LARCH64_DYNAREC OFF CACHE BOOL "")
|
||||
set(PPC64LE_DYNAREC ON CACHE BOOL "")
|
||||
endif()
|
||||
if(RK3399 OR RK3588 OR ODROIDN2 OR RPI3ARM64 OR RPI4ARM64 OR RPI5ARM64 OR RK3326 OR TEGRAX1 OR TEGRA_T194 OR TEGRA_T234 OR NVIDIA_GB10 OR PHYTIUM OR SD845 OR SD865 OR SD888 OR SD8G2 OR SDORYON1 OR LX2160A OR M1 OR ARM64 OR ADLINK)
|
||||
if(RK3399 OR RK3588 OR ODROIDN2 OR RPI3ARM64 OR RPI4ARM64 OR RPI5ARM64 OR RK3326 OR TEGRAX1 OR TEGRA_T194 OR TEGRA_T234 OR NVIDIA_GB10 OR PHYTIUM OR SD845 OR SD865 OR SD888 OR SD8G2 OR SDORYON1 OR SD8EG5 OR LX2160A OR M1 OR ARM64 OR ADLINK)
|
||||
set(LD80BITS OFF CACHE BOOL "")
|
||||
set(NOALIGN OFF CACHE BOOL "")
|
||||
set(ARM_DYNAREC ON CACHE BOOL "")
|
||||
set(RV64_DYNAREC OFF CACHE BOOL "")
|
||||
set(LARCH64_DYNAREC OFF CACHE BOOL "")
|
||||
set(PPC64LE_DYNAREC OFF CACHE BOOL "")
|
||||
endif()
|
||||
if(RK3399 OR ODROIDN2 OR RPI3ARM64 OR RPI4ARM64 OR RPI5ARM64)
|
||||
set(SAVE_MEM ON CACHE BOOL "")
|
||||
@@ -121,6 +126,7 @@ option(NOALIGN "Set to ON if host device doesn't need re-align (i.e. i386)" ${NO
|
||||
option(ARM_DYNAREC "Set to ON to use ARM Dynamic Recompilation" ${ARM_DYNAREC})
|
||||
option(RV64_DYNAREC "Set to ON to use RISC-V Dynamic Recompilation" ${RV64_DYNAREC})
|
||||
option(LARCH64_DYNAREC "Set to ON to use LOONGARCH64 Dynamic Recompilation" ${LARCH64_DYNAREC})
|
||||
option(PPC64LE_DYNAREC "Set to ON to use PPC64LE Dynamic Recompilation" ${PPC64LE_DYNAREC})
|
||||
option(STATICBUILD "Set to ON to have a static build (Warning, not working)" ${STATICBUILD})
|
||||
option(NO_LIB_INSTALL "Set ON to not install a few x86_64 libs that are used by many program" ${NO_LIB_INSTALL})
|
||||
option(NO_CONF_INSTALL "Set ON to not install config files" ${NO_CONF_INSTALL})
|
||||
@@ -205,6 +211,17 @@ elseif(SD888)
|
||||
elseif(SD8G2)
|
||||
add_definitions(-DSD8G2)
|
||||
set(CFLAGS -pipe -march=armv9-a+i8mm+sm4+sha3+rcpc+crypto+nosve+nosve2)
|
||||
elseif(SD8EG5)
|
||||
add_definitions(-DSD8EG5)
|
||||
# NOTE
|
||||
# Even though Qualcomm Snapdragon 8 Elite Gen 5 relies on 3rd generation Oryon cores, it seems like the support for them
|
||||
# is not yet present in GCC and Clang, so for now we will use mostly the same optimization flags as SDORYON1, which houses
|
||||
# 1st generation Oryon cores. This should still be fine since the main difference between the
|
||||
# two is the presence of SVE and SVE2, which are not yet used in Box64's ARM64 dynarec.
|
||||
#
|
||||
# As noted in the SDORYON1 section, GCC 14 and Clang 19 support oryon-1 as a -mcpu/-mtune argument, however it seems like
|
||||
# Fedora does not like them very much, so this option should be taken with a grain of salt. It worked in my test case just fine.
|
||||
set(CFLAGS -pipe -march=armv8.7-a+crypto+sm4+sha3+fp16+sve+sve2 -mtune=oryon-1)
|
||||
elseif(SDORYON1)
|
||||
add_definitions(-DSDORYON1)
|
||||
# NOTE
|
||||
@@ -239,6 +256,8 @@ elseif(RV64)
|
||||
set(ASMFLAGS -pipe -march=rv64gc)
|
||||
elseif(PPC64LE)
|
||||
add_definitions(-DPPC64LE)
|
||||
set(CFLAGS -pipe -mcpu=power9)
|
||||
set(ASMFLAGS -pipe -mcpu=power9)
|
||||
elseif(LX2160A)
|
||||
add_definitions(-DLX2160A)
|
||||
set(CFLAGS -pipe -march=armv8-a+crypto+crc -mcpu=cortex-a72+crypto)
|
||||
@@ -280,6 +299,9 @@ if(STATICBUILD)
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
set(CMAKE_EXE_LINKER_FLAGS -static)
|
||||
set(HAVE_TRACE OFF)
|
||||
if(PPC64LE)
|
||||
add_definitions(-fno-stack-protector)
|
||||
endif()
|
||||
endif()
|
||||
if(BOX32)
|
||||
add_definitions(-DBOX32)
|
||||
@@ -336,6 +358,12 @@ elseif(LARCH64_DYNAREC)
|
||||
enable_language(ASM)
|
||||
include_directories("${BOX64_ROOT}/src/dynarec/la64")
|
||||
set(DYNAREC ON)
|
||||
elseif(PPC64LE_DYNAREC)
|
||||
add_definitions(-DDYNAREC)
|
||||
add_definitions(-DPPC64LE)
|
||||
enable_language(ASM)
|
||||
include_directories("${BOX64_ROOT}/src/dynarec/ppc64le")
|
||||
set(DYNAREC ON)
|
||||
else()
|
||||
set(DYNAREC OFF)
|
||||
endif()
|
||||
@@ -380,8 +408,9 @@ set(OS_LINUX_SRC
|
||||
"${BOX64_ROOT}/src/os/os_linux.c"
|
||||
"${BOX64_ROOT}/src/os/perfmap.c"
|
||||
"${BOX64_ROOT}/src/os/symbolfuncs_linux.c"
|
||||
"${BOX64_ROOT}/src/os/my_cpuid_linux.c"
|
||||
"${BOX64_ROOT}/src/os/my_cpuid_common.c"
|
||||
"${BOX64_ROOT}/src/os/random_linux.c"
|
||||
"${BOX64_ROOT}/src/os/my_cpuid.c"
|
||||
"${BOX64_ROOT}/src/os/sysinfo.c"
|
||||
)
|
||||
|
||||
set(ELFLOADER_SRC
|
||||
@@ -394,6 +423,7 @@ set(ELFLOADER_SRC
|
||||
"${BOX64_ROOT}/src/custommmap.c"
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec.c"
|
||||
"${BOX64_ROOT}/src/elfs/elfloader.c"
|
||||
"${BOX64_ROOT}/src/elfs/elfhacks.c"
|
||||
"${BOX64_ROOT}/src/elfs/elfparser.c"
|
||||
"${BOX64_ROOT}/src/elfs/elfhash.c"
|
||||
"${BOX64_ROOT}/src/elfs/elfload_dump.c"
|
||||
@@ -417,6 +447,7 @@ set(ELFLOADER_SRC
|
||||
"${BOX64_ROOT}/src/libtools/auxval.c"
|
||||
"${BOX64_ROOT}/src/libtools/myalign.c"
|
||||
"${BOX64_ROOT}/src/libtools/signals.c"
|
||||
"${BOX64_ROOT}/src/libtools/sigtools.c"
|
||||
"${BOX64_ROOT}/src/libtools/decopcode.c"
|
||||
"${BOX64_ROOT}/src/libtools/threads.c"
|
||||
"${BOX64_ROOT}/src/tools/bitutils.c"
|
||||
@@ -480,6 +511,13 @@ if(NOT ANDROID)
|
||||
)
|
||||
endif()
|
||||
|
||||
if(NOT STATICBUILD AND NOT ANDROID)
|
||||
list(APPEND ELFLOADER_SRC
|
||||
"${BOX64_ROOT}/src/libtools/libdl.c"
|
||||
"${BOX64_ROOT}/src/libtools/vulkanoverlay.c"
|
||||
)
|
||||
endif()
|
||||
|
||||
set(INTERPRETER
|
||||
"${BOX64_ROOT}/src/emu/x64run.c"
|
||||
"${BOX64_ROOT}/src/emu/x64run0f.c"
|
||||
@@ -537,6 +575,10 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedatomic.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedatspi.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedayatanaappindicator3.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedayatanaindicator3.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedayatanaido3.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedavahiclient.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedavahicommon.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedbz2.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedcap.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedcuda.c"
|
||||
@@ -593,6 +635,7 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedgthread2.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedgtk3.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedgtkx112.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedharfbuzzsubset.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedkrb5.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlcms2.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedldlinux.c"
|
||||
@@ -606,6 +649,7 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibcmusl.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibcrypt.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibcups.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibcupsimage.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibdl.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibdrm.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibdrmamdgpu.c"
|
||||
@@ -618,20 +662,24 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibglu.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibglx.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibglxnvidia.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibgpgme.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibharfbuzz.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibibus.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibice.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedliblapack.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibm.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibmvec.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibncurses.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibncurses6.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibncursesw.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibncursesw6.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibnuma.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibogg.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibomp.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibpanel.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibpci.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibpcre.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibpcre216.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibpthread.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibresolv.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibrt.c"
|
||||
@@ -648,6 +696,7 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibvawayland.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibvax11.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibvdpau.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibvpx.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibvorbis.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibx11.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibx11xcb.c"
|
||||
@@ -728,10 +777,13 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedsdl2mixer.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedsdl2net.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedsdl2ttf.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedsdl3.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedsdl3ttf.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedselinux.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedsmime3.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedsmpeg2.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedssl3.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedsystemd.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedtbbbind.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedtbbmalloc.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedtbbmallocproxy.c"
|
||||
@@ -746,6 +798,7 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedwaylandegl.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedxinerama.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedxkbcommon.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedxkbfile.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedxkbcommonx11.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedxkbregistry.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedxml2.c"
|
||||
@@ -761,6 +814,8 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedicui18n66.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedicuuc67.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedicui18n67.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedicuuc68.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedicui18n68.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedicuuc72.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedicui18n72.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedicuuc73.c"
|
||||
@@ -784,6 +839,9 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibtiff5.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedbrotlidec.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedzstd.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedproxy.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedssh4.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedsmbclient.c"
|
||||
)
|
||||
endif()
|
||||
if(ANDROID)
|
||||
@@ -817,7 +875,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" "LA64" "--"
|
||||
"PANDORA" "HAVE_LD80BITS" "NOALIGN" "HAVE_TRACE" "ANDROID" "TERMUX" "STATICBUILD" "LA64" "PPC64LE" "--"
|
||||
${WRAPPEDS_HEAD}
|
||||
MAIN_DEPENDENCY "${BOX64_ROOT}/rebuild_wrappers.py"
|
||||
DEPENDS ${WRAPPEDS} ${WRAPPEDS_HEAD}
|
||||
@@ -890,6 +948,7 @@ if(BOX32)
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedcairo.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibdrm.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibvdpau.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibvorbis.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappednsl.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibcups.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedgbm.c"
|
||||
@@ -900,6 +959,9 @@ if(BOX32)
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedmount.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappeddbus.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedcurl.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappednvml.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedpulsesimple.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibogg.c"
|
||||
)
|
||||
endif()
|
||||
string(REPLACE ".c" "_private.h" MODROOT ${BOX64_ROOT})
|
||||
@@ -1118,6 +1180,37 @@ if(LARCH64_DYNAREC)
|
||||
)
|
||||
endif()
|
||||
|
||||
if(PPC64LE_DYNAREC)
|
||||
set(DYNAREC_SRC
|
||||
${DYNAREC_SRC}
|
||||
|
||||
"${BOX64_ROOT}/src/dynarec/ppc64le/dynarec_ppc64le_functions.c"
|
||||
"${BOX64_ROOT}/src/dynarec/ppc64le/dynarec_ppc64le_arch.c"
|
||||
"${BOX64_ROOT}/src/dynarec/ppc64le/ppc64le_printer.c"
|
||||
"${BOX64_ROOT}/src/dynarec/ppc64le/dynarec_ppc64le_jmpnext.c"
|
||||
"${BOX64_ROOT}/src/dynarec/ppc64le/dynarec_ppc64le_consts.c"
|
||||
)
|
||||
set(DYNAREC_ASM
|
||||
${DYNAREC_ASM}
|
||||
"${BOX64_ROOT}/src/dynarec/ppc64le/ppc64le_prolog.S"
|
||||
"${BOX64_ROOT}/src/dynarec/ppc64le/ppc64le_epilog.S"
|
||||
"${BOX64_ROOT}/src/dynarec/ppc64le/ppc64le_next.S"
|
||||
"${BOX64_ROOT}/src/dynarec/ppc64le/ppc64le_lock.S"
|
||||
)
|
||||
|
||||
set(DYNAREC_PASS
|
||||
"${BOX64_ROOT}/src/dynarec/ppc64le/dynarec_ppc64le_helper.c"
|
||||
"${BOX64_ROOT}/src/dynarec/ppc64le/dynarec_ppc64le_00.c"
|
||||
"${BOX64_ROOT}/src/dynarec/ppc64le/dynarec_ppc64le_66.c"
|
||||
"${BOX64_ROOT}/src/dynarec/ppc64le/dynarec_ppc64le_f0.c"
|
||||
"${BOX64_ROOT}/src/dynarec/ppc64le/dynarec_ppc64le_66f0.c"
|
||||
"${BOX64_ROOT}/src/dynarec/ppc64le/dynarec_ppc64le_emit_math.c"
|
||||
"${BOX64_ROOT}/src/dynarec/ppc64le/dynarec_ppc64le_emit_logic.c"
|
||||
"${BOX64_ROOT}/src/dynarec/ppc64le/dynarec_ppc64le_emit_tests.c"
|
||||
"${BOX64_ROOT}/src/dynarec/ppc64le/dynarec_ppc64le_emit_shift.c"
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
if(GDBJIT)
|
||||
set(GDBJITREADER "${BOX64_ROOT}/gdbjit/reader.c")
|
||||
@@ -1259,8 +1352,12 @@ string(COMPARE EQUAL "${CMAKE_SYSTEM_PROCESSOR}" "i686" _x86)
|
||||
string(COMPARE EQUAL "${CMAKE_SYSTEM_PROCESSOR}" "x86_64" _x86_64)
|
||||
string(COMPARE EQUAL "${CMAKE_SYSTEM_PROCESSOR}" "aarch64" _aarch64)
|
||||
string(COMPARE EQUAL "${CMAKE_SYSTEM_PROCESSOR}" "riscv64" _riscv64)
|
||||
string(COMPARE EQUAL "${CMAKE_SYSTEM_PROCESSOR}" "ppc64le" _ppc64le)
|
||||
if(NOT _ppc64le)
|
||||
string(COMPARE EQUAL "${CMAKE_SYSTEM_PROCESSOR}" "powerpc64le" _ppc64le)
|
||||
endif()
|
||||
|
||||
if(_x86_64 OR _aarch64)
|
||||
if(_x86_64 OR _aarch64 OR _ppc64le)
|
||||
add_definitions(-DCONFIG_64BIT)
|
||||
endif()
|
||||
|
||||
@@ -1429,6 +1526,8 @@ if(_aarch64)
|
||||
endif()
|
||||
elseif(_riscv64)
|
||||
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "riscv64")
|
||||
elseif(_ppc64le)
|
||||
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "ppc64el")
|
||||
elseif(_x86_64)
|
||||
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "x86_64")
|
||||
else()
|
||||
@@ -1626,6 +1725,13 @@ add_test(Boundary ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref33.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
#if(NOT CI)
|
||||
# add_test(AppImage ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
# -D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test01-x64.AppImage -D TEST_OUTPUT=tmpfileAppImage.txt
|
||||
# -D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref01.txt
|
||||
# -P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
#endif()
|
||||
|
||||
else()
|
||||
|
||||
add_test(bootSyscall ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
@@ -1770,6 +1876,10 @@ add_test(lock ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
#
|
||||
#set_tests_properties(avx_intrinsics PROPERTIES ENVIRONMENT "BOX64_DYNAREC_FASTNAN=0;BOX64_DYNAREC_FASTROUND=0 BOX64_AVX=2")
|
||||
|
||||
#add_test(AppImage ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
# -D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/hcl-X64.AppImage -D TEST_ARGS2=--help -D TEST_OUTPUT=tmpfileAppImage.txt
|
||||
# -D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/refAppImage.txt
|
||||
# -P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
endif()
|
||||
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
# AI Usage Policy
|
||||
|
||||
> [!IMPORTANT]
|
||||
> This project does **not** accept pull requests that are fully or predominantly AI-generated. AI tools may be utilized solely in an assistive capacity.
|
||||
>
|
||||
> Detailed information regarding permissible and restricted uses of AI can be found in the [AGENTS.md](AGENTS.md) file.
|
||||
|
||||
Code that is initially generated by AI and subsequently edited will still be considered AI-generated. AI assistance is permissible only when the majority of the code is authored by a human contributor, with AI employed exclusively for corrections or to expand on verbose modifications that the contributor has already conceptualized (e.g., generating wrapper code callbacks or structure conversions).
|
||||
|
||||
If AI is used to generate any portion of the code, contributors must adhere to the following requirements:
|
||||
|
||||
1. Explicitly disclose the manner in which AI was employed.
|
||||
2. Perform a comprehensive manual review prior to submitting the pull request.
|
||||
3. Be prepared to explain every line of code they submitted when asked about it by a maintainer.
|
||||
4. Using AI to respond to human reviewers is strictly prohibited.
|
||||
|
||||
For more info, please refer to the [AGENTS.md](AGENTS.md) file.
|
||||
|
||||
# Pull requests
|
||||
|
||||
Before submitting your PR:
|
||||
- Test your changes:
|
||||
- Build locally your code, using the relevant build option (e.g., do not enable Android or Termux if doing a Linux build)
|
||||
- Execute the `ctest` suite. Only 100% success is admissible
|
||||
- If you added/modify a wrapper, don't forget to add generated files in the PR
|
||||
- Create separate PRs for each feature or fix. Avoid combining unrelated changes in a single PR
|
||||
- If your PR becomes stale, rebase it on top of latest `main` to get maintainers attention
|
||||
|
||||
# Coding guidelines
|
||||
|
||||
- Avoid adding third-party dependencies, extra files, extra headers, etc.
|
||||
@@ -8,16 +8,15 @@
|
||||
|
||||
---
|
||||
|
||||
Box64 enables running x86_64 Linux programs, including games, on non-x86_64 Linux systems such as Arm (64-bit little-endian host system required).
|
||||
**Check out our game compatibility list at [https://box86.org/app/](https://box86.org/app/), please help us [improve it](https://github.com/ptitSeb/box86-compatibility-list/issues)!**
|
||||
|
||||
Check out Box64 in action on YouTube:
|
||||
- [MicroLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ)
|
||||
- [Pi Labs](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g)
|
||||
- [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA)
|
||||
---
|
||||
|
||||
Box64 enables running x86_64 Linux programs, including games, on non-x86_64 Linux systems such as Arm (64-bit little-endian host system required).
|
||||
|
||||
Box64 leverages native system libraries (libc, libm, SDL, OpenGL), offering ease of integration and surprising performance in many applications. For performance benchmarks, check [this analysis](https://box86.org/index.php/2021/06/game-performances/).
|
||||
|
||||
With DynaRec for ARM64, RV64 and LA64 platforms, Box64 achieves a speed boost 5-10x faster than the interpreter alone. For a deeper look at DynaRec, see [Inner workings](https://box86.org/2021/07/inner-workings-a-high%e2%80%91level-view-of-box86-and-a-low%e2%80%91level-view-of-the-dynarec/).
|
||||
With DynaRec for Arm, RISC-V and LoongArch platforms, Box64 achieves a speed boost 5-10x faster than the interpreter alone. For a deeper look at DynaRec, see [Inner workings](https://box86.org/2021/07/inner-workings-a-high%e2%80%91level-view-of-box86-and-a-low%e2%80%91level-view-of-the-dynarec/).
|
||||
|
||||
<img src="docs/img/Box64Icon.png" width="96" height="96" alt="Box64 Icon">
|
||||
|
||||
@@ -25,18 +24,18 @@ _Logo and icon by @grayduck - Thank you!_
|
||||
|
||||
---
|
||||
|
||||
## 📖 Usage
|
||||
## Usage
|
||||
|
||||
- `$ box64 ./program [args]` to run Linux x86_64 programs.
|
||||
- `$ box64 -k` to kill all the emulated processes.
|
||||
- `$ box64-bash` to have a x86_64 bash environment.
|
||||
- `$ box64-bash` to have an x86_64 bash environment.
|
||||
- Want to use wine? see [Wine Documentation](docs/WINE.md).
|
||||
|
||||
Box64 also offers environment variables and rcfile to control its behavior. For details, see [Usage Documentation](docs/USAGE.md).
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Compiling and Installation
|
||||
## 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)
|
||||
@@ -44,24 +43,24 @@ Box64 also offers environment variables and rcfile to control its behavior. For
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Version History
|
||||
## Version History
|
||||
|
||||
See the [Changelog](docs/CHANGELOG.md) for version updates.
|
||||
|
||||
---
|
||||
|
||||
## 🖥️ Platform Compatibility Notes
|
||||
## Platform Compatibility Notes
|
||||
|
||||
Box64 requires 64-bit libraries on the host system, as it directly translates x86_64 function calls. For 32-bit binaries, use Box86 or Box32.
|
||||
|
||||
**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 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`.
|
||||
1. Box32 is still experimental.
|
||||
2. Some shell scripts (such as the GOG game installer) may rely on `uname -m` to determine the current architecture. Please run them as `box64 script.sh` to allow Box64 to take over.
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ Configuration
|
||||
## Configuration
|
||||
|
||||
Box64 has configuration files located in `/etc/box64.box64rc` and `~/.box64rc`, both formatted as `.ini` files. If you don’t want to use the default `/etc/box64.box64rc` file, copy it to `~/.box64rc` to ensure compatibility.
|
||||
|
||||
@@ -71,7 +70,7 @@ For more information, check [Usage Documentation](docs/USAGE.md).
|
||||
|
||||
---
|
||||
|
||||
## 📄 Additional Platform-Specific Notes
|
||||
## Additional Platform-Specific Notes
|
||||
|
||||
### Unity Game Emulation
|
||||
|
||||
@@ -79,10 +78,6 @@ For more information, check [Usage Documentation](docs/USAGE.md).
|
||||
- **Tip for Pi4 and Pi5 Users**: Set `MESA_GL_VERSION_OVERRIDE=3.2` with `BOX64_DYNAREC_STRONGMEM=1` to prevent freezes and enable strong memory mode.
|
||||
- **Using Panfrost**: For better compatibility on ARM, enable `PAN_MESA_DEBUG=gl3` to force higher OpenGL profiles. This can help if a game starts but quits unexpectedly before showing any content.
|
||||
|
||||
### GTK Programs
|
||||
|
||||
Box64 wraps GTK libraries, supporting both gtk2 and gtk3.
|
||||
|
||||
### Steam
|
||||
|
||||
See [Steam Documentation](docs/STEAM.md).
|
||||
@@ -95,10 +90,6 @@ Box64 supports Wine64 and Proton. For 32-bit components, Box86 is required. Syst
|
||||
|
||||
For more information, check [Wine Documentation](docs/WINE.md).
|
||||
|
||||
### Vulkan
|
||||
|
||||
Box64 wraps Vulkan libraries.
|
||||
|
||||
----
|
||||
Final word
|
||||
----
|
||||
|
||||
+13
-22
@@ -8,16 +8,15 @@
|
||||
|
||||
---
|
||||
|
||||
Box64 可以在非 x86_64 Linux 主机系统(比如 Arm)上运行 x86_64 Linux 程序(比如游戏),目前仅支持 64 位小端主机系统。
|
||||
**请查看我们的游戏兼容性列表:[https://box86.org/app/](https://box86.org/app/),并请帮助我们[改进它](https://github.com/ptitSeb/box86-compatibility-list/issues)!**
|
||||
|
||||
在 YouTube 上查看 Box64 的运行效果:
|
||||
- [MicroLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ)
|
||||
- [Pi Labs](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g)
|
||||
- [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA)
|
||||
---
|
||||
|
||||
Box64 可以在非 x86_64 Linux 主机系统(比如 Arm)上运行 x86_64 Linux 程序(比如游戏),目前仅支持 64 位小端主机系统。
|
||||
|
||||
Box64 可以使用本机原生的系统库(libc、libm、SDL、OpenGL),有着易于集成的特性和令人惊讶的性能。如需性能基准测试,请查看[此分析](https://box86.org/index.php/2021/06/game-performances/)。
|
||||
|
||||
借助适用于 ARM64,RV64 以及 LA64 平台的 DynaRec,Box64 的速度比单独使用解释器快 5-10 倍。如需深入了解 DynaRec,请参考[此文章](https://box86.org/2021/07/inner-workings-a-high%e2%80%91level-view-of-box86-and-a-low%e2%80%91level-view-of-the-dynarec/)。
|
||||
借助适用于 Arm,RISC-V 以及龙架构平台的 DynaRec,Box64 的速度比单独使用解释器快 5-10 倍。如需深入了解 DynaRec,请参考[此文章](https://box86.org/2021/07/inner-workings-a-high%e2%80%91level-view-of-box86-and-a-low%e2%80%91level-view-of-the-dynarec/)。
|
||||
|
||||
<img src="docs/img/Box64Icon.png" width="96" height="96" alt="Box64 Icon">
|
||||
|
||||
@@ -25,7 +24,7 @@ _Logo 由 @grayduck 制作,感谢!_
|
||||
|
||||
---
|
||||
|
||||
## 📖 使用方法
|
||||
## 使用方法
|
||||
|
||||
- `$ box64 ./program [args]` 运行 Linux x86_64 程序。
|
||||
- `$ box64 -k` 杀死所有模拟的进程。
|
||||
@@ -36,31 +35,31 @@ Box64 还提供了环境变量和 Rc 文件来控制其行为。有关详细信
|
||||
|
||||
---
|
||||
|
||||
## 🚀 编译和安装
|
||||
## 编译和安装
|
||||
|
||||
- [编译说明](https://github.com/ptitSeb/box64/blob/main/docs/COMPILE.md)
|
||||
- [安装 Wine](https://github.com/ptitSeb/box64/blob/main/docs/WINE.md)
|
||||
|
||||
---
|
||||
|
||||
## 🔄 版本历史
|
||||
## 版本历史
|
||||
|
||||
请参阅[变更日志](docs/CHANGELOG.md)了解版本更新说明。
|
||||
|
||||
---
|
||||
|
||||
## 🖥️ 平台兼容性说明
|
||||
## 平台兼容性说明
|
||||
|
||||
Box64 直接转换 x86_64 函数调用到本机原生库,因此需要主机系统上的 64 位库。对于 32 位二进制文件,请使用 Box86 或 Box32。
|
||||
|
||||
**注意事项**
|
||||
|
||||
1. Box32 模式正在制作中,旨在支持 Box64 上运行 32 位二进制文件,敬请期待!
|
||||
2. 某些安装程序可能会将 64 位的主机操作系统判定为 x86 导致兼容性问题。解决方法:使用假的 `uname` ,并使它在运行参数为 `-m` 时返回 `x86_64`。
|
||||
1. Box32 仍然是实验性质。
|
||||
2. 某些 Shell 脚本(比如 GOG 游戏安装脚本)可能会依赖 `uname -m` 判断当前架构,请使用 `box64 script.sh` 的方式运行以便让 Box64 接管。
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ 配置
|
||||
## 配置
|
||||
|
||||
Box64 的配置文件位于 `/etc/box64.box64rc` 和 `~/.box64rc`,均为 `.ini` 格式的文件。如果您不想使用默认的 `/etc/box64.box64rc` 文件,请将其复制到 `~/.box64rc` 以确保兼容性。
|
||||
|
||||
@@ -70,17 +69,13 @@ Box64 的配置文件位于 `/etc/box64.box64rc` 和 `~/.box64rc`,均为 `.ini
|
||||
|
||||
---
|
||||
|
||||
## 📄 特定平台的其他说明
|
||||
## 特定平台的其他说明
|
||||
|
||||
### Unity 游戏
|
||||
- 许多 Unity 游戏需要 OpenGL 3+,这对 ARM/RISC-V SBC 来说可能具有挑战性。
|
||||
- **对 Pi4 和 Pi5 用户的提示**:设置 `MESA_GL_VERSION_OVERRIDE=3.2` 和 `BOX64_DYNAREC_STRONGMEM=1` 以防止卡死并启用强内存模式。
|
||||
- **Panfrost**:为了在 ARM 上实现更好的兼容性,启用 `PAN_MESA_DEBUG=gl3` 以强制更高的 OpenGL Profile。如果游戏可以启动但在显示任何内容之前意外退出,这个设置可能会有所帮助。
|
||||
|
||||
### GTK 程序
|
||||
|
||||
Box64 包装了 GTK 库,支持 gtk2 和 gtk3。
|
||||
|
||||
### Steam
|
||||
|
||||
Box64 支持 Linux Steam 和 Windows Steam,更多细节请参考[Steam 文档](docs/STEAM.md)。
|
||||
@@ -95,10 +90,6 @@ Box64 支持 Wine64 和 Proton。对于 32 位组件,需要 Box86。配备 Box
|
||||
|
||||
有关更多信息,请参阅 [Wine 使用说明](docs/WINE.md)。
|
||||
|
||||
### Vulkan
|
||||
|
||||
Box64 包装了 Vulkan 库。
|
||||
|
||||
----
|
||||
|
||||
结语
|
||||
|
||||
+2
-2
@@ -1,3 +1,5 @@
|
||||
> Внимание: Этот документ устарел. Пожалуйста, помогите нам его перевести.
|
||||
|
||||

|
||||
|
||||
Емулятор простіра користувача x86_64 із родзинкою
|
||||
@@ -10,8 +12,6 @@
|
||||
|
||||
Box64 дозволяє запускати x86_64 Linux програми (наприклад, ігри) на системах Linux відмінних від x86_64, наприклад ARM (хост-система має мати 64-розрядний порядок редагування).
|
||||
|
||||
Ви можете знайти багато відео про Box64 в YouTube каналах [MicroLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ), [Pi Labs](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g) або [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA)
|
||||
|
||||
Оскільки Box64 використовує рідні версії деяких «системних» бібліотек, таких як libc, libm, SDL і OpenGL, його легко інтегрувати та використовувати з більшістю програм, а продуктивність у багатьох випадках може бути напрочуд високою. Подивіться на цей стендовий аналіз для прикладу [тут](https://box86.org/index.php/2021/06/game-performances/).
|
||||
|
||||
Box64 інтегрується з DynaRec (динамічний рекомпілятор) для платформ ARM64 і RV64 забезпечуючи підвищення швидкості в 5-10 разів, ніж використання лише інтерпретатора. Деякі високорівневі відомості про те, як працює DynaRec, можна знайти [тут](https://box86.org/2021/07/inner-workings-a-high%e2%80%91level-view-of-box86-and-a-low%e2%80%91level-view-of-the-dynarec/).
|
||||
|
||||
@@ -2,6 +2,9 @@ https://archive.debian.org/debian/pool/main/c/curl/libcurl3-gnutls_7.74.0-1.3+de
|
||||
https://archive.debian.org/debian/pool/main/c/curl/libcurl3-gnutls_7.74.0-1.3+deb11u7~bpo11+1_i386.deb,625e5189304d4d3bfb27cb821e257816c5ce761b1696b5da5ca4fa1035c48463
|
||||
https://archive.debian.org/debian/pool/main/o/openssl/libssl1.0.0_1.0.2l-1~bpo8+1_amd64.deb,6e85968afe1a6643f4e82e1cc168f848c5967a131bb1c7392f11974953db0e67
|
||||
https://archive.debian.org/debian/pool/main/o/openssl/libssl1.0.0_1.0.2l-1~bpo8+1_i386.deb,4e8b924286a064c257ca50b8ecd44fe71226443daef62b6836010590e2157329
|
||||
https://archives.fedoraproject.org/pub/archive/epel/9.5/Everything/x86_64/Packages/m/mbedtls-2.28.8-1.el9.x86_64.rpm,54cb7e43e902a7378e912ecfec470ee30fe69af323d3812cbc39ddebd64790ff
|
||||
https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/34/Everything/x86_64/os/Packages/l/libpng12-1.2.57-13.fc34.i686.rpm,5e4f525f44d538e3467dd13c66010d54f3d12ec4a319829e15a23ff2d0195b5b
|
||||
https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/34/Everything/x86_64/os/Packages/l/libpng12-1.2.57-13.fc34.x86_64.rpm,49f956ad143399c29f5ddf6da6b6fc108ce130d1ed598b4ec5a68b1ff26091de
|
||||
https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/34/Everything/x86_64/os/Packages/l/libunwind-1.4.0-5.fc34.i686.rpm,eb518e9d073c36fd29862c7afd00a8a7cb186074a0e162983f18fb6c9dc71d2c
|
||||
https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/34/Everything/x86_64/os/Packages/l/libunwind-1.4.0-5.fc34.x86_64.rpm,0f44e37e4eb472508e0dba8505ebbb04c2c1390c6a43970a6af80aad886037e3
|
||||
https://archives.fedoraproject.org/pub/archive/fedora/linux/updates/34/Everything/x86_64/Packages/h/hidapi-0.11.2-2.fc34.i686.rpm,386040fc502e2f02b4b072e0cd90c034dc0a30831fbd2ddb116d17c080b6f9a4
|
||||
@@ -12,7 +15,7 @@ https://cdn.getsol.us/repo/shannon/libj/libjpeg-turbo/libjpeg-turbo-3.0.3-21-1-x
|
||||
https://cdn.getsol.us/repo/shannon/libj/libjpeg-turbo/libjpeg-turbo-32bit-3.0.3-21-1-x86_64.eopkg,5624990281f6520026aa2252c711f02d4916099aeac63accc83bd2135b9d3220
|
||||
https://repo.almalinux.org/almalinux/8.10/BaseOS/x86_64/os/Packages/nettle-3.4.1-7.el8.i686.rpm,13bc8758355c3ec885f414e0e86efad29a7fe82c0999cdb3754d666949c06cc5
|
||||
https://repo.almalinux.org/almalinux/8.10/BaseOS/x86_64/os/Packages/nettle-3.4.1-7.el8.x86_64.rpm,fb4aaa22b2e2f2fc0c451b87ac464e8746d240397d64e79f6bfd38f4e9128a5a
|
||||
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/compat-openssl11-1.1.1k-4.el9_0.i686.rpm,6b9d8e1b34dcc5a5cb1196d746022b04677b7f9a105508392446508c6ae9b4cc,https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/compat-openssl11-1.1.1k-4.el9_0.x86_64.rpm,102eb4355d2dfc8093ed59dd2ebc6bf8616965524faf7e886212fd542f4c1b4b
|
||||
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/compat-openssl11-1.1.1k-4.el9_0.i686.rpm,6b9d8e1b34dcc5a5cb1196d746022b04677b7f9a105508392446508c6ae9b4cc
|
||||
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/compat-openssl11-1.1.1k-4.el9_0.x86_64.rpm,102eb4355d2dfc8093ed59dd2ebc6bf8616965524faf7e886212fd542f4c1b4b
|
||||
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/fribidi-1.0.10-6.el9.2.i686.rpm,75f808f0f5f93aceb4e477aa5f302edbed07a605a0644f0ea929d4ea609e36a0
|
||||
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/fribidi-1.0.10-6.el9.2.x86_64.rpm,b4763ca410f8479b2775efb55ba09e6722948af7526180a56309e3e090c27010
|
||||
@@ -20,16 +23,12 @@ https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libepoxy-1.5.5-4.el
|
||||
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libepoxy-1.5.5-4.el9.x86_64.rpm,b6d1e7f1c832882ceb05187cbc2d8fe1f459bcd88c7160487ee6f734e1a5d017
|
||||
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libICE-1.0.10-8.el9.i686.rpm,d9c44bb34c990fdcc6987feefacfc9e1e7997ca25f1e0a59c9adc9c16f2266d1
|
||||
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libICE-1.0.10-8.el9.x86_64.rpm,d0b867203384942985c3c4ad6fc9ec0000fcc9965408451a6cdef8df06a3833c
|
||||
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libogg-1.3.4-6.el9.i686.rpm,9e4ff6fa0251c5357ae8f648b3e396d0043d5b3f2fb28d23325f5bd592c67aee
|
||||
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libogg-1.3.4-6.el9.x86_64.rpm,83b4b333e335654674032d1cda4d7deb328b5a409f95e3952c3dc482b684fd8f
|
||||
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libsigc%2B%2B20-2.10.7-2.el9.i686.rpm,7c33f4c18cbd51dc0a7c9ae0190b1a27d0540ce2fd92ced4776dde66162d1a88
|
||||
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libsigc%2B%2B20-2.10.7-2.el9.x86_64.rpm,8600132b9e4efadfe23d3125e90287f5a7114165fd9ecb064d9930fcca446ef2
|
||||
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libSM-1.2.3-10.el9.i686.rpm,ec68b3def828ba442248f3cff495f42c4af3dd58f38c8daad07dfddc109d999a
|
||||
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libSM-1.2.3-10.el9.x86_64.rpm,d00318843a50138829b470a97b8db1a00723b10bca23c16a8386d9ab670e4c64
|
||||
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libtheora-1.1.1-31.el9.i686.rpm,2155c688b516ab359d0c47be6d73e51d3c65f199ed5591f7bb7ce6d5d9799977
|
||||
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libtheora-1.1.1-31.el9.x86_64.rpm,25ab4a8ad997b450b4a34a777f5a0678eea72ca1665944a7a461ac63de4b25bf
|
||||
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libvorbis-1.3.7-5.el9.i686.rpm,e38c5185fea611330ea253db020315dd564507bf95c48a81dbe7db186ce4214b
|
||||
https://vault.almalinux.org/9.5/AppStream/x86_64/os/Packages/libvorbis-1.3.7-5.el9.x86_64.rpm,3c340337a073975636d198a282503f32a54bf85fb5345522a2c22e530b8d6c9e
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/bluez-libs-5.72-2.el9.i686.rpm,af1aba8e6fa5ccf33032d58a3acc59368c07d532293396db205fb9a4bc1241ae
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/bluez-libs-5.72-2.el9.x86_64.rpm,49c273813b4616240acdae8dae893192658c7541482f9bbb2c46dfe19b61877d
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/glibc-2.34-125.el9_5.8.alma.1.i686.rpm,28bc1088e39483d145849e8804c5a0f2524faeb4f76631ae46c41100f40e08b9
|
||||
@@ -40,6 +39,8 @@ https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/gnutls-3.8.3-4.el9_4.i
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/gnutls-3.8.3-4.el9_4.x86_64.rpm,16c48c504fe62f8e19cac7c6442d3e08bba487f610c2f533116dac32357cda86
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/harfbuzz-2.7.4-10.el9.i686.rpm,5157daf2ab0a03b403d37c60b150b8f0f866754714f81e3d96368e06a16339ce
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/harfbuzz-2.7.4-10.el9.x86_64.rpm,1f81073019abe4176d4496723a89b55a349c31f507e96397a0b3efa7cea0ff61
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libassuan-2.5.5-3.el9.i686.rpm,9ab4028be7d7c0631944476fb2e083eeb185c3d01468c8def3e3aa235dc5c12d
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libassuan-2.5.5-3.el9.x86_64.rpm,3201aaeb3240c3497673200c50fc27c2b07effd1c3fdd2fbd17a83373e80afb4
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libblkid-2.37.4-20.el9.i686.rpm,f9e62d2768c31948b53268b7de51bd1c7342cdf39a328a0d89d933b4aa0c5dd1
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libblkid-2.37.4-20.el9.x86_64.rpm,ed02d978a36488b38bad62af21d4045367c1f0b00d00c90ded01e2fc8e190536
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libbrotli-1.0.9-7.el9_5.i686.rpm,d18c20fccbb9497222059d475161a55c0c6279344f214fe551b8b0f87d3c054a
|
||||
@@ -58,8 +59,8 @@ https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libnsl-2.34-125.el9_5.
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libnsl-2.34-125.el9_5.8.alma.1.x86_64.rpm,7d0e521ab087807ee71d79da66a2829b827bf5080bb5d080dfab108e31cf218b
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libpng-1.6.37-12.el9.i686.rpm,66bf967e84f0d8e7a0059f2b7dda33482ff5e4fe088d0e3bc86dc54e6c7c97be
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libpng-1.6.37-12.el9.x86_64.rpm,ebb3e927dfafa0b199e00e2bef4c10c85fc82a70c359faf9aeb599eda70bfa5e
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libstdc%2B%2B-11.5.0-5.el9_5.alma.1.i686.rpm,05fd29569c312a661374aa69e28ed5cad20812822070a3138265c92a446e2c80
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libstdc%2B%2B-11.5.0-5.el9_5.alma.1.x86_64.rpm,7efb1ded0ec2763589dd3bc6a9d52fa9f898cc1f3db6e8761e1d223ce4506424
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libstdc++-11.5.0-5.el9_5.alma.1.i686.rpm,05fd29569c312a661374aa69e28ed5cad20812822070a3138265c92a446e2c80
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libstdc++-11.5.0-5.el9_5.alma.1.x86_64.rpm,7efb1ded0ec2763589dd3bc6a9d52fa9f898cc1f3db6e8761e1d223ce4506424
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libtasn1-4.16.0-8.el9_1.i686.rpm,9cbd11277e89bd0d4a80900bee01ca71b0c582c9cb5744f5035135b2ed907c85
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libtasn1-4.16.0-8.el9_1.x86_64.rpm,2dd3a1ad2785df642cb03dfed6dfbeec929ff8b14e52e61272ca7e89f86ba3cd
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/libunistring-0.9.10-15.el9.i686.rpm,792600a879fbd94ce4bf249713b0cb3a166c147cfad397e8a15e6b4f01c75997
|
||||
@@ -80,3 +81,7 @@ https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/pciutils-libs-3.7.0-5.
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/pciutils-libs-3.7.0-5.el9.x86_64.rpm,308bd897d8f9a36020d70edc79089a3595b22b149200d67c37e2d4e6147a9f75
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/sqlite-libs-3.34.1-7.el9_3.i686.rpm,dc6946a8344b8f4f476fef9479d1786c86fdcd045e988ab5d85fef7780e1fae4
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/sqlite-libs-3.34.1-7.el9_3.x86_64.rpm,e7f87444f24a03b37caa02942082b6d4283067ecbbd3f7798f882d22b55713cf
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/zlib-1.2.11-40.el9.i686.rpm,659ee5222028744806be3f822369a726c721aa346eed2882dcf019d83c111e67
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/zlib-1.2.11-40.el9.x86_64.rpm,90d7d5d145c6d397645ffefdff40e3d2783e3bf3bfa7b6c1f089c2cad81a3191
|
||||
https://vault.centos.org/6.10/os/x86_64/Packages/compat-libstdc++-33-3.2.3-69.el6.i686.rpm,894abcc5f0b28e39c71d4b0ca27d19540e7eb9d3c32664d5621324c9efbfe11e
|
||||
https://vault.centos.org/6.10/os/x86_64/Packages/compat-libstdc++-33-3.2.3-69.el6.x86_64.rpm,41ea0fec16c0ca62722a32b7ffd70bb716beec8b6dd32b57f076be02a5aee00c
|
||||
|
Regular → Executable
+6
@@ -107,6 +107,12 @@ if find "${dir_tmp}"/bundle-libs -type l ! -exec test -e {} \; -print | grep bun
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Manually create additional symlinks that are useful to have.
|
||||
cd "${dir_tmp}"/bundle-libs/usr/lib/box64-x86_64-linux-gnu/
|
||||
ln -s libmbedcrypto.so.7 libmbedcrypto.so.3
|
||||
ln -s libmbedtls.so.14 libmbedtls.so.12
|
||||
ln -s libmbedx509.so.1 libmbedx509.so.0
|
||||
|
||||
# create shared libraries (.so) symlinks
|
||||
# if multiple libraries of the same name exist, it will symlink the oldest version
|
||||
# e.g. libcurl-gnutls soname with versioned symbols (CURL_GNUTLS_3, CURL_GNUTLS_4)
|
||||
|
||||
Vendored
+10
@@ -1,3 +1,13 @@
|
||||
box64 (0.4.2) unstable; urgency=low
|
||||
|
||||
This version add lots on unconnected new things, like a PPC64LE backend, Vulkan overlay support or more Dynarec finetunning.
|
||||
=> Vulkan x64 overlay support. That means using the linux version of Steam, Fossilize & GameOverlayUI will work.
|
||||
=> Many dynarec refactors, especialy on ARM64 & LA64 with fixes to speed regression introduced with the the last 2 releases and improved compatibility.
|
||||
=> Support for SteamRT3 & new Proton 11
|
||||
=> New PCC64LE in the work. Not finished, but should be usable already (but the platform seems to use a 64k pagesize by default, so compatibility will suffer on this platformm). Note that main Box64 mainteners don't have access to relevent hardware, so support will be limited.
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Mon, 20 Apr 2026 10:30:33 -0100
|
||||
|
||||
box64 (0.4.0) unstable; urgency=low
|
||||
|
||||
This version added many important refactors: the opcode prefix decoder for Dynarec, libGL and Vulkan, the FSGSBASE support, making segments handling easier and faster.
|
||||
|
||||
+28
-4
@@ -1,13 +1,33 @@
|
||||
#!/usr/bin/make -f
|
||||
|
||||
%:
|
||||
dh $@
|
||||
dh $@
|
||||
|
||||
DEB_HOST_ARCH := $(shell dpkg-architecture -qDEB_HOST_ARCH 2>/dev/null || echo "unknown")
|
||||
|
||||
override_dh_auto_configure:
|
||||
@echo "Configuring for architecture: $(DEB_HOST_ARCH)"
|
||||
ifeq ($(DEB_HOST_ARCH),riscv64)
|
||||
dh_auto_configure -- \
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
-DARM_DYNAREC=1 \
|
||||
-DNOGIT=1
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
-DRV64=1 \
|
||||
-DRV64_DYNAREC=1 \
|
||||
-DNOGIT=1
|
||||
else ifeq ($(DEB_HOST_ARCH),arm64)
|
||||
dh_auto_configure -- \
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
-DARM_DYNAREC=1 \
|
||||
-DNOGIT=1
|
||||
else ifeq ($(DEB_HOST_ARCH),aarch64)
|
||||
dh_auto_configure -- \
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
-DARM_DYNAREC=1 \
|
||||
-DNOGIT=1
|
||||
else
|
||||
dh_auto_configure -- \
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
-DNOGIT=1
|
||||
endif
|
||||
|
||||
override_dh_shlibdeps:
|
||||
dh_shlibdeps --exclude=libgcc_s.so.1 \
|
||||
@@ -23,3 +43,7 @@ override_dh_shlibdeps:
|
||||
--exclude=libcrypto.so.1.0.0 \
|
||||
--exclude=libssl.so.1.0.0 \
|
||||
--exclude=box64-bash
|
||||
|
||||
override_dh_strip:
|
||||
dh_strip --exclude=/usr/lib/box64-x86_64-linux-gnu/ \
|
||||
--exclude=box64-bash
|
||||
@@ -1,6 +1,6 @@
|
||||
# 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.
|
||||
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. This bundle improves Box emulation by providing libraries that are not wrapped yet. In a perfect world, the application or game would already provide these libraries but that is not always the case. The bundle archive provides a much smaller size compared to using a full root file system of an operating system.
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -50,7 +50,9 @@ Preference of operating system packages that provide a library:
|
||||
4. XBPS from Void Linux provide updated variants of obscure 32-bit libraries.
|
||||
5. Other (whereever a library is packaged)
|
||||
|
||||
Some essential library files will never be emulated (only wrapped) and should not be bundled. This includes glibc, OpenGL, Vulkan, and X11/Xorg libraries. The full list can be found [in the library source code](https://github.com/ptitSeb/box64/blob/v0.3.6/src/librarian/library.c#L433). Other libraries with lots of dependencies, such as GTK, require all dependencies to be installed for emulation to work. This becomes dependency hell and should be avoided.
|
||||
Some essential libraries will always be emulated and should be bundled. The full list can be found in the [in the core source code](https://github.com/ptitSeb/box64/blob/v0.4.0/src/core.c#L413).
|
||||
|
||||
Some essential library files will never be emulated (only natively wrapped instead) and should not be bundled. This includes glibc, OpenGL, Vulkan, and X11/Xorg libraries. The full list can be found [in the library source code](https://github.com/ptitSeb/box64/blob/v0.4.0/src/librarian/library.c#L440). Other libraries with lots of dependencies, such as GTK, require all dependencies to be installed for emulation to work. This becomes dependency hell and should be avoided.
|
||||
|
||||
For finding package names that contian a specific library file, use the [pkgs.org website](https://pkgs.org/). Otherwise, use one of these package manager commands on a x86_64 Linux distribution:
|
||||
- DEB
|
||||
@@ -67,8 +69,8 @@ Once the package name is found, find the exact URL for downloading it.
|
||||
- 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/
|
||||
- RPM = Navigate to the "`<MAJOR>.<MINOR>`" version directory first. Then explore "AppStream" and "BaseOS". The "x86_64" repository will contain both "x86_64.rpm" and "i686.rpm" packages.
|
||||
- https://vault.almalinux.org/
|
||||
- Enterprise Linux (EL) distributions, such as AlamaLinux, sometimes are missing 32-bit packages. Use the Fedora 34 [update](https://archives.fedoraproject.org/pub/archive/fedora/linux/updates/34/Everything/x86_64/Packages/) and [release](https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/34/Everything/x86_64/os/Packages/) archives for compatible packages with EL 9.
|
||||
- XBPS = There are too many files in the repository to display on a web browser. Use pkgs.org instead to find the exact URL for downloading it.
|
||||
- https://repo-default.voidlinux.org/current/
|
||||
|
||||
@@ -1,3 +1,50 @@
|
||||
v0.4.2
|
||||
======
|
||||
|
||||
Highlights:
|
||||
* This version add lots on unconnected new things, like a PPC64LE backend, Vulkan overlay support or more Dynarec finetunning!
|
||||
=> Vulkan x64 overlay support. That means using the linux version of Steam, Fossilize & GameOverlayUI will work.
|
||||
=> Many dynarec refactors, especialy on ARM64 & LA64 with fixes to speed regression introduced with the the last 2 releases and improved compatibility.
|
||||
=> Support for SteamRT3 & new Proton 11
|
||||
=> New PCC64LE in the work. Not finished, but usable already. Note that the platform seems to use a 64k pagesize by default, so compatibility will suffer on this platformm.
|
||||
|
||||
Version summary:
|
||||
|
||||
* New RISC-V support for the script to denerate Debian .deb package
|
||||
* Improved the way system informations (like cpu brand and number of cores) is gathered and cpuid opcode handled
|
||||
* Improved support for Steam and new SteamRT3 64bit version
|
||||
* Elf: Improved handling of large pagesize (usefull for PPC64LE with its 64k pagesize)
|
||||
* Elf: Improved support for AppImage
|
||||
* Wrapping: Vulkan: Added support wor x64 overlay
|
||||
* Wrapping; Vulkan: Added BOX64_NOVULKANOVERLAY to disable x64 overlay handling
|
||||
* Wrapping: more wrapped functions, reworked some existing one with wrapperhelper
|
||||
* Wrapping: Added more wrapped libs
|
||||
* Wrapping: BOX32: more wrapped function and some fixes to existing ones
|
||||
* Wrapping: PPC64: Better handling of ioctl
|
||||
* Interpreter: Added a few more exotic opcodes
|
||||
* Dynarec: Added support for STRONGMEM=4
|
||||
* Dynarec: Improved TF flag handling
|
||||
* Dynarec: Reworked HotPage detection and handling
|
||||
* Dynarec: Reworked dynarec generation to batter handle abort mid-block
|
||||
* Dynarec: Rework how "Alt" addresses are handled
|
||||
* Dynarec: Removed BOX64_DYNAREC_HOTPAGE_ALT
|
||||
* Dynarec: Added support for Secondary Entry Point on dynablock when using CALLRET=1
|
||||
* Dynarec: Improve CALL FAR / RET FAR opcodes handling, adding CALLRET optimisation support
|
||||
* Dynarec: Improve IRET opcodes handling, adding CALLRET optimisation support
|
||||
* Dynarec: ARM64: Some new fixes for existing opcodes
|
||||
* Dynarec: ARM64: Reworked XMM/YMM register handling
|
||||
* Dynarec: ARM64: Reworked DIRTY=2 with AutoCRC Dynablock
|
||||
* Dynarec: LA64: Lots of new opcodes added & fixes
|
||||
* Dynarec: LA64: Added full support for SAFEFLAGS=2
|
||||
* Dynarec: LA64: Lots of fixes & improvements for FASTNAN=0
|
||||
* Dynarec: LA64: Refactor opcode printer
|
||||
* Dynarec: LA64: Reworked DIRTY=2 with AutoCRC Dynablock
|
||||
* Dynarec: LA64: Added CALLRET=2 support
|
||||
* Dynarec: RV64: A few fixes to existing opcodes
|
||||
* Dynarec: RV64: Added CALLRET=2 support
|
||||
* Dynarec: PPC64: Created a new backend for PPC64LE, with some opcodes already (still WIP)
|
||||
* WOWBOX64: Some small fixes
|
||||
|
||||
v0.4.0
|
||||
======
|
||||
|
||||
|
||||
+9
-1
@@ -165,16 +165,24 @@ On a 64bit OS:
|
||||
|
||||
On a 64bit OS:
|
||||
|
||||
Targeting Snapdragon 845:
|
||||
|
||||
```
|
||||
-D SD845=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
|
||||
or
|
||||
Targeting Snapdragon 888:
|
||||
|
||||
```
|
||||
-D SD888=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
|
||||
Targeting Snapdragon 8 Elite Gen 5:
|
||||
|
||||
```
|
||||
-D SD8EG5=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
|
||||
Depending on how recent your Snapdragon is
|
||||
|
||||
#### for Phytium
|
||||
|
||||
+50
-5
@@ -76,6 +76,14 @@ Optimize CALL/RET opcodes. Available in WowBox64.
|
||||
* 1: Try to optimize CALL/RET, skipping the jump table when possible.
|
||||
* 2: Try to optimize CALL/RET, skipping the jump table when possible, adding code to handle return to dirty/modified block. Does not work on WowBox64.
|
||||
|
||||
### BOX64_DYNAREC_SEP
|
||||
|
||||
Optimize CALL/RET further with Secondary Entry Points (SEP). Have no effect is CALLRET is not enabled Available in WowBox64.
|
||||
|
||||
* 0: Do not add SEP at CALLRET return
|
||||
* 1: Add SEP at CALLRET return, on meory that are from known binary files [Default]
|
||||
* 2: Add SEP at CALLRET return for all type of memory.
|
||||
|
||||
### BOX64_DYNAREC_DF
|
||||
|
||||
Enable or disable the use of deferred flags. Available in WowBox64.
|
||||
@@ -174,6 +182,7 @@ Enable the emulation of x86 strong memory model. Available in WowBox64.
|
||||
* 1: Enable some memory barriers when writing to memory to emulate the x86 strong memory model in a limited way.
|
||||
* 2: All in 1, plus memory barriers on SIMD instructions.
|
||||
* 3: All in 2, plus more memory barriers on a regular basis.
|
||||
* 4: Mimic x86 TSO similarly to QEMU's approach, for evaluation purposes.
|
||||
|
||||
### BOX64_DYNAREC_VOLATILE_METADATA
|
||||
|
||||
@@ -372,6 +381,13 @@ Fix 64bit inodes.
|
||||
* 0: Do not fix 64bit inodes. [Default]
|
||||
* 1: Fix 64bit inodes.
|
||||
|
||||
### BOX64_FORCE_LD_PRELOAD
|
||||
|
||||
Force symbols from BOX64_LD_PRELOAD libraries to be resolved by RTLD_NEXT.
|
||||
|
||||
* 0: Do nothing. [Default]
|
||||
* 1: Force symbols from BOX64_LD_PRELOAD libraries to be resolved by RTLD_NEXT.
|
||||
|
||||
### BOX64_IGNOREINT3
|
||||
|
||||
Ignore INT3 instructions.
|
||||
@@ -450,6 +466,13 @@ Path to the rc file to load.
|
||||
|
||||
* XXXX: Load the rc file XXXX, default rc files will not be loaded.
|
||||
|
||||
### BOX64_RDTSC_INV
|
||||
|
||||
Report Invariant TSC bit in CPUID for Intel CPU type.
|
||||
|
||||
* 0: Do not report Invariant TSC for Intel CPU type (default). [Default]
|
||||
* 1: Report Invariant TSC bit in CPUID leaf 0x80000007 for Intel CPU type.
|
||||
|
||||
### BOX64_RESERVE_HIGH
|
||||
|
||||
Reserve high memory area for the program, always enabled on Box32.
|
||||
@@ -473,7 +496,7 @@ Expose SHAEXT (a.k.a. SHA_NI) capabilities. Available in WowBox64.
|
||||
|
||||
### BOX64_SSE_FLUSHTO0
|
||||
|
||||
Behaviour of SSE Flush to 0 flags. Also tracking SSE exception flags Available in WowBox64.
|
||||
Behaviour of SSE Flush to 0 flags. Also tracking SSE exception flags. Available in WowBox64.
|
||||
|
||||
* 0: Just track the flag. [Default]
|
||||
* 1: Apply SSE Flush to 0 flag directly. Also reflect SSE exception flags in Dynarec (if available)
|
||||
@@ -511,7 +534,7 @@ Detect UnityPlayer and apply conservative settings.
|
||||
Games is a Unity one.
|
||||
|
||||
* 0: Does nothing.
|
||||
* 1: Unity Game, use special detecting code for Windows, apply BOX64_DYNAREC_STRONGMEM=1 for Linux [Default]
|
||||
* 1: Unity Game, use special detecting code for Windows, apply BOX64_DYNAREC_STRONGMEM=1 for Linux. [Default]
|
||||
|
||||
### BOX64_X11GLX
|
||||
|
||||
@@ -598,6 +621,14 @@ Print missing opcodes. Available in WowBox64.
|
||||
* 1: Print missing opcodes.
|
||||
* 2: Print the fallback to scalar opcodes, only valid on RISC-V.
|
||||
|
||||
### BOX64_DYNAREC_NOHOSTEXT
|
||||
|
||||
Disable optional host extensions.
|
||||
|
||||
* 0: Disable nothing. [Default]
|
||||
* 1: Disable all the optional extensions.
|
||||
* xxx,yyy,zzz: Disable selected optional extensions, choices are Arm: `crc32,pmull,aes,atomics,sha1,sha2,uscat,flagm,flagm2,frintts,afp,rndr`, LoongArch: `lasx,lbt,frecipe,lam_bh,lamcas,scq`, and RISC-V: `zba,zbb,zbc,zbs,vector,xtheadba,xtheadbb,xtheadbs,xtheadmemidx,xtheadmempair,xtheadcondmov`.
|
||||
|
||||
### BOX64_DYNAREC_PERFMAP
|
||||
|
||||
Generate map file for Linux perf tool.
|
||||
@@ -615,10 +646,17 @@ Enable DynaRec execution comparison with the interpreter, very slow, only for te
|
||||
|
||||
### BOX64_DYNAREC_TEST_NODUP
|
||||
|
||||
Enable deduplication of IP address where COSIM find a difference Available in WowBox64.
|
||||
Enable deduplication of IP address where COSIM find a difference. Available in WowBox64.
|
||||
|
||||
* 0: Show all addresses in error [Default]
|
||||
* 1: Show address in error only 1 time, even if dump might differs
|
||||
* 0: Show all addresses in error. [Default]
|
||||
* 1: Show address in error only 1 time, even if dump might differs.
|
||||
|
||||
### BOX64_DYNAREC_TEST_NODUMP
|
||||
|
||||
Do not dump test code when BOX64_DYNAREC_DUMP is enabled. Available in WowBox64.
|
||||
|
||||
* 0: Dump test code.
|
||||
* 1: Do not dump test code. [Default]
|
||||
|
||||
### BOX64_DYNAREC_TRACE
|
||||
|
||||
@@ -835,6 +873,13 @@ Do not load Vulkan libraries.
|
||||
* 0: Load Vulkan libraries. [Default]
|
||||
* 1: Do not load Vulkan libraries, both native and x86_64.
|
||||
|
||||
### BOX64_NOVULKANOVERLAY
|
||||
|
||||
Do not load x64 Vulkan overlay.
|
||||
|
||||
* 0: Do try to Load x64 Vulkan overlay. [Default]
|
||||
* 1: Do not load x64 Vulkan overlay.
|
||||
|
||||
### BOX64_PREFER_EMULATED
|
||||
|
||||
Prefer emulated libraries over native ones.
|
||||
|
||||
+57
-6
@@ -182,6 +182,15 @@ Optimize CALL/RET opcodes. Available in WowBox64.
|
||||
* 2 : Try to optimize CALL/RET, skipping the jump table when possible, adding code to handle return to dirty/modified block. Does not work on WowBox64.
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_SEP> =I<0|1|2>
|
||||
|
||||
Optimize CALL/RET further with Secondary Entry Points (SEP). Have no effect is CALLRET is not enabled Available in WowBox64.
|
||||
|
||||
* 0 : Do not add SEP at CALLRET return
|
||||
* 1 : Add SEP at CALLRET return, on meory that are from known binary files [Default]
|
||||
* 2 : Add SEP at CALLRET return for all type of memory.
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_DF> =I<0|1>
|
||||
|
||||
Enable or disable the use of deferred flags. Available in WowBox64.
|
||||
@@ -303,6 +312,15 @@ Enable or disable the use of native flags. Available in WowBox64.
|
||||
* 1 : Use native flags when possible. [Default]
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_NOHOSTEXT> =I<0|1|xxx,yyy,zzz>
|
||||
|
||||
Disable optional host extensions.
|
||||
|
||||
* 0 : Disable nothing. [Default]
|
||||
* 1 : Disable all the optional extensions.
|
||||
* xxx,yyy,zzz : Disable selected optional extensions, choices are Arm: `crc32,pmull,aes,atomics,sha1,sha2,uscat,flagm,flagm2,frintts,afp,rndr`, LoongArch: `lasx,lbt,frecipe,lam_bh,lamcas,scq`, and RISC-V: `zba,zbb,zbc,zbs,vector,xtheadba,xtheadbb,xtheadbs,xtheadmemidx,xtheadmempair,xtheadcondmov`.
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_PAUSE> =I<0|1|2|3>
|
||||
|
||||
Enable x86 PAUSE emulation, may help the performance of spinlocks. Available in WowBox64.
|
||||
@@ -346,7 +364,7 @@ Behaviour of flags emulation on CALL/RET opcodes and other edge cases. Available
|
||||
* 2 : All CALL/RET will need flags. All edge cases are also handled.
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_STRONGMEM> =I<0|1|2|3>
|
||||
=item B<BOX64_DYNAREC_STRONGMEM> =I<0|1|2|3|4>
|
||||
|
||||
Enable the emulation of x86 strong memory model. Available in WowBox64.
|
||||
|
||||
@@ -354,6 +372,7 @@ Enable the emulation of x86 strong memory model. Available in WowBox64.
|
||||
* 1 : Enable some memory barriers when writing to memory to emulate the x86 strong memory model in a limited way.
|
||||
* 2 : All in 1, plus memory barriers on SIMD instructions.
|
||||
* 3 : All in 2, plus more memory barriers on a regular basis.
|
||||
* 4 : Mimic x86 TSO similarly to QEMU's approach, for evaluation purposes.
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_TBB> =I<0|1>
|
||||
@@ -375,10 +394,18 @@ Enable DynaRec execution comparison with the interpreter, very slow, only for te
|
||||
|
||||
=item B<BOX64_DYNAREC_TEST_NODUP> =I<0|1>
|
||||
|
||||
Enable deduplication of IP address where COSIM find a difference Available in WowBox64.
|
||||
Enable deduplication of IP address where COSIM find a difference. Available in WowBox64.
|
||||
|
||||
* 0 : Show all addresses in error [Default]
|
||||
* 1 : Show address in error only 1 time, even if dump might differs
|
||||
* 0 : Show all addresses in error. [Default]
|
||||
* 1 : Show address in error only 1 time, even if dump might differs.
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_TEST_NODUMP> =I<0|1>
|
||||
|
||||
Do not dump test code when BOX64_DYNAREC_DUMP is enabled. Available in WowBox64.
|
||||
|
||||
* 0 : Dump test code.
|
||||
* 1 : Do not dump test code. [Default]
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_TRACE> =I<0|1>
|
||||
@@ -493,6 +520,14 @@ Fix 64bit inodes.
|
||||
* 1 : Fix 64bit inodes.
|
||||
|
||||
|
||||
=item B<BOX64_FORCE_LD_PRELOAD> =I<0|1>
|
||||
|
||||
Force symbols from BOX64_LD_PRELOAD libraries to be resolved by RTLD_NEXT.
|
||||
|
||||
* 0 : Do nothing. [Default]
|
||||
* 1 : Force symbols from BOX64_LD_PRELOAD libraries to be resolved by RTLD_NEXT.
|
||||
|
||||
|
||||
=item B<BOX64_IGNOREINT3> =I<0|1>
|
||||
|
||||
Ignore INT3 instructions.
|
||||
@@ -696,6 +731,14 @@ Do not load Vulkan libraries.
|
||||
* 1 : Do not load Vulkan libraries, both native and x86_64.
|
||||
|
||||
|
||||
=item B<BOX64_NOVULKANOVERLAY> =I<0|1>
|
||||
|
||||
Do not load x64 Vulkan overlay.
|
||||
|
||||
* 0 : Do try to Load x64 Vulkan overlay. [Default]
|
||||
* 1 : Do not load x64 Vulkan overlay.
|
||||
|
||||
|
||||
=item B<BOX64_PATH> =I<XXXX>
|
||||
|
||||
Path to look for x86_64 binaries.
|
||||
@@ -760,6 +803,14 @@ Use hardware counter for rdtsc if available.
|
||||
* 1 : Use hardware counter for rdtsc if and only if precision is at least 1GHz.
|
||||
|
||||
|
||||
=item B<BOX64_RDTSC_INV> =I<0|1>
|
||||
|
||||
Report Invariant TSC bit in CPUID for Intel CPU type.
|
||||
|
||||
* 0 : Do not report Invariant TSC for Intel CPU type (default). [Default]
|
||||
* 1 : Report Invariant TSC bit in CPUID leaf 0x80000007 for Intel CPU type.
|
||||
|
||||
|
||||
=item B<BOX64_RESERVE_HIGH> =I<0|1>
|
||||
|
||||
Reserve high memory area for the program, always enabled on Box32.
|
||||
@@ -811,7 +862,7 @@ Always show SIGSEGV signal detailes.
|
||||
|
||||
=item B<BOX64_SSE_FLUSHTO0> =I<0|1>
|
||||
|
||||
Behaviour of SSE Flush to 0 flags. Also tracking SSE exception flags Available in WowBox64.
|
||||
Behaviour of SSE Flush to 0 flags. Also tracking SSE exception flags. Available in WowBox64.
|
||||
|
||||
* 0 : Just track the flag. [Default]
|
||||
* 1 : Apply SSE Flush to 0 flag directly. Also reflect SSE exception flags in Dynarec (if available)
|
||||
@@ -917,7 +968,7 @@ Detect UnityPlayer and apply conservative settings.
|
||||
Games is a Unity one.
|
||||
|
||||
* 0 : Does nothing.
|
||||
* 1 : Unity Game, use special detecting code for Windows, apply BOX64_DYNAREC_STRONGMEM=1 for Linux [Default]
|
||||
* 1 : Unity Game, use special detecting code for Windows, apply BOX64_DYNAREC_STRONGMEM=1 for Linux. [Default]
|
||||
|
||||
|
||||
=item B<BOX64_WRAP_EGL> =I<0|1>
|
||||
|
||||
+128
-5
@@ -312,6 +312,29 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BOX64_DYNAREC_SEP",
|
||||
"description": "Optimize CALL/RET further with Secondary Entry Points (SEP). Have no effect is CALLRET is not enabled",
|
||||
"category": "Performance",
|
||||
"wine": true,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
"description": "Do not add SEP at CALLRET return",
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"key": "1",
|
||||
"description": "Add SEP at CALLRET return, on meory that are from known binary files",
|
||||
"default": true
|
||||
},
|
||||
{
|
||||
"key": "2",
|
||||
"description": "Add SEP at CALLRET return for all type of memory.",
|
||||
"default": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BOX64_DYNAREC_DF",
|
||||
"description": "Enable or disable the use of deferred flags.",
|
||||
@@ -609,6 +632,29 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BOX64_DYNAREC_NOHOSTEXT",
|
||||
"description": "Disable optional host extensions.",
|
||||
"category": "Debugging",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
"description": "Disable nothing.",
|
||||
"default": true
|
||||
},
|
||||
{
|
||||
"key": "1",
|
||||
"description": "Disable all the optional extensions.",
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"key": "xxx,yyy,zzz",
|
||||
"description": "Disable selected optional extensions, choices are Arm: `crc32,pmull,aes,atomics,sha1,sha2,uscat,flagm,flagm2,frintts,afp,rndr`, LoongArch: `lasx,lbt,frecipe,lam_bh,lamcas,scq`, and RISC-V: `zba,zbb,zbc,zbs,vector,xtheadba,xtheadbb,xtheadbs,xtheadmemidx,xtheadmempair,xtheadcondmov`.",
|
||||
"default": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BOX64_DYNAREC_PAUSE",
|
||||
"description": "Enable x86 PAUSE emulation, may help the performance of spinlocks.",
|
||||
@@ -739,6 +785,11 @@
|
||||
"key": "3",
|
||||
"description": "All in 2, plus more memory barriers on a regular basis.",
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"key": "4",
|
||||
"description": "Mimic x86 TSO similarly to QEMU's approach, for evaluation purposes.",
|
||||
"default": false
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -785,22 +836,40 @@
|
||||
},
|
||||
{
|
||||
"name": "BOX64_DYNAREC_TEST_NODUP",
|
||||
"description": "Enable deduplication of IP address where COSIM find a difference",
|
||||
"description": "Enable deduplication of IP address where COSIM find a difference.",
|
||||
"category": "Debugging",
|
||||
"wine": true,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
"description": "Show all addresses in error",
|
||||
"description": "Show all addresses in error.",
|
||||
"default": true
|
||||
},
|
||||
{
|
||||
"key": "1",
|
||||
"description": "Show address in error only 1 time, even if dump might differs",
|
||||
"description": "Show address in error only 1 time, even if dump might differs.",
|
||||
"default": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BOX64_DYNAREC_TEST_NODUMP",
|
||||
"description": "Do not dump test code when BOX64_DYNAREC_DUMP is enabled.",
|
||||
"category": "Debugging",
|
||||
"wine": true,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
"description": "Dump test code.",
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"key": "1",
|
||||
"description": "Do not dump test code.",
|
||||
"default": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BOX64_DYNAREC_TRACE",
|
||||
"description": "Enable or disable DynaRec trace.",
|
||||
@@ -1053,6 +1122,24 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BOX64_FORCE_LD_PRELOAD",
|
||||
"description": "Force symbols from BOX64_LD_PRELOAD libraries to be resolved by RTLD_NEXT.",
|
||||
"category": "Compatibility",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
"description": "Do nothing.",
|
||||
"default": true
|
||||
},
|
||||
{
|
||||
"key": "1",
|
||||
"description": "Force symbols from BOX64_LD_PRELOAD libraries to be resolved by RTLD_NEXT.",
|
||||
"default": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BOX64_IGNOREINT3",
|
||||
"description": "Ignore INT3 instructions.",
|
||||
@@ -1518,6 +1605,24 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BOX64_NOVULKANOVERLAY",
|
||||
"description": "Do not load x64 Vulkan overlay.",
|
||||
"category": "Libraries",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
"description": "Do try to Load x64 Vulkan overlay.",
|
||||
"default": true
|
||||
},
|
||||
{
|
||||
"key": "1",
|
||||
"description": "Do not load x64 Vulkan overlay.",
|
||||
"default": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BOX64_PATH",
|
||||
"description": "Path to look for x86_64 binaries.",
|
||||
@@ -1662,6 +1767,24 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BOX64_RDTSC_INV",
|
||||
"description": "Report Invariant TSC bit in CPUID for Intel CPU type.",
|
||||
"category": "Compatibility",
|
||||
"wine": false,
|
||||
"options": [
|
||||
{
|
||||
"key": "0",
|
||||
"description": "Do not report Invariant TSC for Intel CPU type (default).",
|
||||
"default": true
|
||||
},
|
||||
{
|
||||
"key": "1",
|
||||
"description": "Report Invariant TSC bit in CPUID leaf 0x80000007 for Intel CPU type.",
|
||||
"default": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BOX64_RESERVE_HIGH",
|
||||
"description": "Reserve high memory area for the program, always enabled on Box32.",
|
||||
@@ -1777,7 +1900,7 @@
|
||||
},
|
||||
{
|
||||
"name": "BOX64_SSE_FLUSHTO0",
|
||||
"description": "Behaviour of SSE Flush to 0 flags. Also tracking SSE exception flags",
|
||||
"description": "Behaviour of SSE Flush to 0 flags. Also tracking SSE exception flags.",
|
||||
"category": "Compatibility",
|
||||
"wine": true,
|
||||
"options": [
|
||||
@@ -2039,7 +2162,7 @@
|
||||
},
|
||||
{
|
||||
"key": "1",
|
||||
"description": "Unity Game, use special detecting code for Windows, apply BOX64_DYNAREC_STRONGMEM=1 for Linux",
|
||||
"description": "Unity Game, use special detecting code for Windows, apply BOX64_DYNAREC_STRONGMEM=1 for Linux.",
|
||||
"default": true
|
||||
}
|
||||
]
|
||||
|
||||
+8
-4
@@ -403,6 +403,8 @@ def readFiles(files: Iterable[Filename]) -> Tuple[JumbledGlobals, JumbledRedirec
|
||||
or match("sdl1mixer", "sdl2mixer") \
|
||||
or match("sdl1net", "sdl2net") \
|
||||
or match("sdl1ttf", "sdl2ttf") \
|
||||
or match("sdl1ttf", "sdl3ttf") \
|
||||
or match("sdl2ttf", "sdl3ttf") \
|
||||
or match("libgl", "libegl") \
|
||||
or match("libgl", "glesv2") \
|
||||
or match("libgl", "libglxnvidia") \
|
||||
@@ -415,7 +417,9 @@ def readFiles(files: Iterable[Filename]) -> Tuple[JumbledGlobals, JumbledRedirec
|
||||
or match("libc", "tbbmallocproxy") \
|
||||
or match("libc", "androidshmem") \
|
||||
or match("crypto", "libssl3") \
|
||||
or match("tcmallocminimal", "tbbmallocproxy"):
|
||||
or match("tcmallocminimal", "tbbmallocproxy") \
|
||||
or match("iconv", "libunistring2") \
|
||||
or match("gomp", "libomp"):
|
||||
continue
|
||||
|
||||
# Note: this test is very (too) simple. If it ever raises, comment
|
||||
@@ -1180,7 +1184,7 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
"fn({0});", # v
|
||||
"R_RAX=(uint8_t)fn({0});", # c
|
||||
"R_RAX=(uint16_t)fn({0});", # w
|
||||
"R_RAX=(uint32_t)fn({0});", # i
|
||||
"R_RAX=(int)fn({0});", # i
|
||||
"S_RAX=(int64_t)fn({0});", # I
|
||||
"R_RAX=(unsigned char)fn({0});", # C
|
||||
"R_RAX=(unsigned short)fn({0});", # W
|
||||
@@ -1209,8 +1213,8 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
"fn({0});", # v
|
||||
"R_RAX=fn({0});", # c
|
||||
"R_RAX=fn({0});", # w
|
||||
"R_RAX=(int32_t)fn({0});", # i
|
||||
"R_RAX=(int64_t)fn({0});", # I
|
||||
"R_RAX=(int)fn({0});", # i
|
||||
"S_RAX=(int64_t)fn({0});", # I
|
||||
"R_RAX=(unsigned char)fn({0});", # C
|
||||
"R_RAX=(unsigned short)fn({0});", # W
|
||||
"R_RAX=(uint32_t)fn({0});", # u
|
||||
|
||||
+76
-5
@@ -6,6 +6,7 @@
|
||||
#include <signal.h>
|
||||
#include <sys/mman.h>
|
||||
#include <pthread.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "os.h"
|
||||
#include "box64context.h"
|
||||
@@ -83,14 +84,14 @@ void relockMutex(int locks)
|
||||
mutex_trylock(&A); \
|
||||
|
||||
GO(my_context->mutex_trace, 7)
|
||||
#ifdef DYNAREC
|
||||
GO(my_context->mutex_dyndump, 8)
|
||||
#else
|
||||
GO(my_context->mutex_lock, 8)
|
||||
#endif
|
||||
GO(my_context->mutex_tls, 9)
|
||||
GO(my_context->mutex_thread, 10)
|
||||
GO(my_context->mutex_bridge, 11)
|
||||
#ifdef DYNAREC
|
||||
#else
|
||||
GO(my_context->mutex_lock, 12)
|
||||
#endif
|
||||
#undef GO
|
||||
}
|
||||
|
||||
@@ -105,6 +106,7 @@ void init_mutexes(box64context_t* context)
|
||||
pthread_mutex_init(&context->mutex_tls, &attr);
|
||||
pthread_mutex_init(&context->mutex_thread, &attr);
|
||||
pthread_mutex_init(&context->mutex_bridge, &attr);
|
||||
pthread_mutex_init(&context->mutex_dyndump, &attr);
|
||||
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
#else
|
||||
@@ -133,6 +135,11 @@ static void atfork_child_box64context(void)
|
||||
{
|
||||
// (re)init mutex if it was lock before the fork
|
||||
init_mutexes(my_context);
|
||||
#ifdef DYNAREC
|
||||
// Cancel FillBlock if needed
|
||||
void CancelBlock64(int need_lock);
|
||||
CancelBlock64(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
int box64_cycle_log_initialized = 0;
|
||||
@@ -179,6 +186,12 @@ box64context_t *NewBox64Context(int argc)
|
||||
context->local_maplib = NewLibrarian(context);
|
||||
context->versym = NewDictionnary();
|
||||
context->system = NewBridge();
|
||||
#ifdef DYNAREC
|
||||
int old_is32bits = box64_is32bits;
|
||||
box64_is32bits = 1;
|
||||
context->alternates = NewBridge(); // this needs to be in 32bits address space
|
||||
box64_is32bits = old_is32bits;
|
||||
#endif
|
||||
// Cannot use Bridge name as the map is not initialized yet
|
||||
// create vsyscall
|
||||
context->vsyscall = AddBridge(context->system, vFEv, box64_is32bits?x86Syscall:x64Syscall, 0, NULL);
|
||||
@@ -244,6 +257,41 @@ box64context_t *NewBox64Context(int argc)
|
||||
|
||||
void freeALProcWrapper(box64context_t* context);
|
||||
void freeCUDAProcWrapper(box64context_t* context);
|
||||
|
||||
#ifdef DYNAREC
|
||||
//#define DYNAREC_HIST // uncomment to print dynablock size histogram at exit
|
||||
#ifdef DYNAREC_HIST
|
||||
#define HIST_BUCKETS 12
|
||||
static const uintptr_t bucket_limits[HIST_BUCKETS] = {
|
||||
8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, (uintptr_t)-1
|
||||
};
|
||||
static const char* bucket_labels[HIST_BUCKETS] = {
|
||||
"1-8", "9-16", "17-32", "33-64", "65-128", "129-256",
|
||||
"257-512", "513-1024", "1025-2048", "2049-4096", "4097-8192", "8193+"
|
||||
};
|
||||
typedef struct {
|
||||
uint64_t count[HIST_BUCKETS];
|
||||
uint64_t total_blocks;
|
||||
uint64_t total_bytes;
|
||||
uintptr_t max_size;
|
||||
} hist_data_t;
|
||||
static void db_size_walk_cb(uintptr_t start, uintptr_t end, uint64_t data, void* userdata) {
|
||||
(void)end;
|
||||
hist_data_t* h = (hist_data_t*)userdata;
|
||||
uintptr_t size = start; // key = x64_size
|
||||
uint64_t n = data; // value = count of blocks
|
||||
for (int i = 0; i < HIST_BUCKETS; i++) {
|
||||
if (size <= bucket_limits[i]) {
|
||||
h->count[i] += n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
h->total_blocks += n;
|
||||
h->total_bytes += size * n;
|
||||
if (size > h->max_size) h->max_size = size;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
EXPORTDYN
|
||||
void FreeBox64Context(box64context_t** context)
|
||||
{
|
||||
@@ -255,6 +303,11 @@ void FreeBox64Context(box64context_t** context)
|
||||
|
||||
box64context_t* ctx = *context; // local copy to do the cleaning
|
||||
|
||||
if(ctx->video_mem) {
|
||||
munmap(ctx->video_mem, 0x10000);
|
||||
ctx->video_mem = NULL;
|
||||
}
|
||||
|
||||
//clean_current_emuthread(); // cleaning main thread seems a bad idea
|
||||
if(ctx->local_maplib)
|
||||
FreeLibrarian(&ctx->local_maplib, NULL);
|
||||
@@ -310,6 +363,9 @@ void FreeBox64Context(box64context_t** context)
|
||||
box_free(ctx->pythonpath);
|
||||
|
||||
FreeBridge(&ctx->system);
|
||||
#ifdef DYNAREC
|
||||
FreeBridge(&ctx->alternates);
|
||||
#endif
|
||||
|
||||
#ifndef STATICBUILD
|
||||
freeGLProcWrapper(ctx);
|
||||
@@ -336,7 +392,21 @@ void FreeBox64Context(box64context_t** context)
|
||||
FreeMapSymbols(&ctx->uniques);
|
||||
|
||||
#ifdef DYNAREC
|
||||
//dynarec_log(LOG_INFO, "BOX64 Dynarec at exit: Max DB=%d, rightmost=%d\n", ctx->max_db_size, rb_get_rightmost(ctx->db_sizes));
|
||||
#ifdef DYNAREC_HIST
|
||||
{
|
||||
hist_data_t hist = {0};
|
||||
rbtree_walk(ctx->db_sizes, db_size_walk_cb, &hist);
|
||||
if(hist.total_blocks) {
|
||||
printf_log(LOG_INFO, "BOX64 Dynarec block size histogram: %" PRIu64 " blocks, %" PRIu64 " total x86 bytes, max=%" PRIuPTR "\n",
|
||||
hist.total_blocks, hist.total_bytes, hist.max_size);
|
||||
for(int i = 0; i < HIST_BUCKETS; i++) {
|
||||
if(hist.count[i])
|
||||
printf_log(LOG_INFO, " %10s: %" PRIu64 " blocks (%.1f%%)\n",
|
||||
bucket_labels[i], hist.count[i], hist.count[i] * 100.0 / hist.total_blocks);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
rbtree_delete(ctx->db_sizes);
|
||||
#endif
|
||||
|
||||
@@ -350,6 +420,7 @@ void FreeBox64Context(box64context_t** context)
|
||||
pthread_mutex_destroy(&ctx->mutex_tls);
|
||||
pthread_mutex_destroy(&ctx->mutex_thread);
|
||||
pthread_mutex_destroy(&ctx->mutex_bridge);
|
||||
pthread_mutex_destroy(&ctx->mutex_dyndump);
|
||||
#endif
|
||||
|
||||
freeCycleLog(ctx);
|
||||
|
||||
+1
-1
@@ -3,6 +3,6 @@
|
||||
|
||||
#define BOX64_MAJOR 0
|
||||
#define BOX64_MINOR 4
|
||||
#define BOX64_REVISION 0
|
||||
#define BOX64_REVISION 2
|
||||
|
||||
#endif //__BOX64_VERSION_H_
|
||||
+3
-1
@@ -9,13 +9,15 @@
|
||||
#define __BUILD_INFO_H__
|
||||
|
||||
|
||||
#if defined(DYNAREC) && (defined(ARM64) || defined(RV64) || defined(LA64))
|
||||
#if defined(DYNAREC) && (defined(ARM64) || defined(RV64) || defined(LA64) || defined(PPC64LE))
|
||||
#if defined(ARM64)
|
||||
#define ARCH_STR " arm64"
|
||||
#elif defined(RV64)
|
||||
#define ARCH_STR " riscv64"
|
||||
#elif defined(LA64)
|
||||
#define ARCH_STR " loongarch64"
|
||||
#elif defined(PPC64LE)
|
||||
#define ARCH_STR " ppc64le"
|
||||
#endif
|
||||
#else
|
||||
#define ARCH_STR ""
|
||||
|
||||
+111
-37
@@ -49,6 +49,7 @@
|
||||
#include "cleanup.h"
|
||||
#include "freq.h"
|
||||
#include "hostext.h"
|
||||
#include "sysinfo.h"
|
||||
|
||||
box64context_t *my_context = NULL;
|
||||
extern box64env_t box64env;
|
||||
@@ -76,6 +77,7 @@ uint32_t default_gs = 0x53;
|
||||
uint32_t default_fs = 0;
|
||||
int box64_isglibc234 = 0;
|
||||
int box64_unittest_mode = 0;
|
||||
sysinfo_t box64_sysinfo = { 0 };
|
||||
|
||||
#ifdef DYNAREC
|
||||
cpu_ext_t cpuext = {0};
|
||||
@@ -159,9 +161,6 @@ static void openFTrace(void)
|
||||
}
|
||||
}
|
||||
|
||||
const char* getCpuName();
|
||||
int getNCpuUnmasked();
|
||||
|
||||
void computeRDTSC()
|
||||
{
|
||||
int hardware = 0;
|
||||
@@ -202,7 +201,7 @@ void computeRDTSC()
|
||||
printf_log_prefix(0, LOG_INFO, "\n");
|
||||
}
|
||||
|
||||
static void displayMiscInfo()
|
||||
static void displayMiscInfo(void)
|
||||
{
|
||||
openFTrace();
|
||||
|
||||
@@ -222,15 +221,20 @@ static void displayMiscInfo()
|
||||
printf_log(LOG_INFO, "Minimum CPU requirements not met, disabling DynaRec\n");
|
||||
SET_BOX64ENV(dynarec, 0);
|
||||
}
|
||||
|
||||
#if defined(LA64)
|
||||
if (box64env.avx && !cpuext.lasx) {
|
||||
box64env.avx = 0;
|
||||
box64env.avx2 = 0;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// grab ncpu and cpu name
|
||||
int ncpu = getNCpuUnmasked();
|
||||
const char* cpuname = getCpuName();
|
||||
|
||||
printf_log(LOG_INFO, "Running on %s with %d core%s, pagesize: %zd\n", cpuname, ncpu, ncpu > 1 ? "s" : "", box64_pagesize);
|
||||
|
||||
// grab and calibrate hardware counter
|
||||
printf_log(LOG_INFO, "Running on %s with %d core%s, pagesize: %zd", box64_sysinfo.cpuname, box64_sysinfo.ncpu, box64_sysinfo.ncpu > 1 ? "s" : "", box64_pagesize);
|
||||
if (BOX64ENV(maxcpu))
|
||||
printf_log_prefix(0, LOG_INFO, ", emulating %d core%s\n", BOX64ENV(maxcpu), BOX64ENV(maxcpu) > 1 ? "s" : "");
|
||||
else
|
||||
printf_log_prefix(0, LOG_INFO, "\n");
|
||||
computeRDTSC();
|
||||
}
|
||||
|
||||
@@ -411,17 +415,39 @@ static void addLibPaths(box64context_t* context)
|
||||
}
|
||||
|
||||
// Add libssl and libcrypto (and a few others) to prefer the emulated version because multiple versions exist
|
||||
AddPath("libssl.so.1", &context->box64_emulated_libs, 0);
|
||||
AddPath("libssl.so.1.0.0", &context->box64_emulated_libs, 0);
|
||||
AddPath("libcrypto.so.1", &context->box64_emulated_libs, 0);
|
||||
AddPath("libcrypto.so.1.0.0", &context->box64_emulated_libs, 0);
|
||||
AddPath("libunwind.so.8", &context->box64_emulated_libs, 0);
|
||||
AddPath("libpng12.so.0", &context->box64_emulated_libs, 0);
|
||||
AddPath("libcurl.so.4", &context->box64_emulated_libs, 0);
|
||||
#define GO(A) AddPath(A, &context->box64_emulated_libs, 0);
|
||||
GO("libssl.so.1");
|
||||
GO("libssl.so.1.0.0");
|
||||
GO("libcrypto.so.1");
|
||||
GO("libcrypto.so.1.0.0");
|
||||
GO("libunwind.so.8");
|
||||
GO("libpng12.so.0");
|
||||
GO("libpng16.so.16");
|
||||
GO("libcurl.so.4");
|
||||
if(getenv("BOX64_PRESSURE_VESSEL_FILES")) // use emulated gnutls in this case, it's safer
|
||||
AddPath("libgnutls.so.30", &context->box64_emulated_libs, 0);
|
||||
AddPath("libtbbmalloc.so.2", &context->box64_emulated_libs, 0);
|
||||
AddPath("libtbbmalloc_proxy.so.2", &context->box64_emulated_libs, 0);
|
||||
GO("libgnutls.so.30");
|
||||
GO("libtbbmalloc.so.2");
|
||||
GO("libtbbmalloc_proxy.so.2");
|
||||
GO("libicuuc.so.64");
|
||||
GO("libicui18n.so.64");
|
||||
GO("libicuuc.so.66");
|
||||
GO("libicui18n.so.66");
|
||||
GO("libicuuc.so.67");
|
||||
GO("libicui18n.so.67");
|
||||
GO("libicuuc.so.68");
|
||||
GO("libicui18n.so.68");
|
||||
GO("libicuuc.so.72");
|
||||
GO("libicui18n.so.72");
|
||||
GO("libicuuc.so.73");
|
||||
GO("libicui18n.so.73");
|
||||
GO("libicuuc.so.74");
|
||||
GO("libicui18n.so.74");
|
||||
GO("libicuuc.so.75");
|
||||
GO("libicui18n.so.75");
|
||||
GO("libicuuc.so.76");
|
||||
GO("libicui18n.so.76");
|
||||
GO("libSDL3.so.0");
|
||||
#undef GO
|
||||
|
||||
if(BOX64ENV(nosigsegv)) {
|
||||
context->no_sigsegv = 1;
|
||||
@@ -471,8 +497,12 @@ void LoadLDPath(box64context_t *context)
|
||||
AddPath("/usr/lib/i386-linux-gnu", &context->box64_ld_lib, 1);
|
||||
if(FileExist("/usr/i386-linux-gnu/lib", 0))
|
||||
AddPath("/usr/i386-linux-gnu/lib", &context->box64_ld_lib, 1);
|
||||
if(FileExist("/usr/i686-linux-gnu/lib", 0))
|
||||
AddPath("/usr/i686-linux-gnu/lib", &context->box64_ld_lib, 1);
|
||||
if(FileExist("/usr/lib/box64-i386-linux-gnu", 0))
|
||||
AddPath("/usr/lib/box64-i386-linux-gnu", &context->box64_ld_lib, 1);
|
||||
if(FileExist("/opt/box64/lib32", 0))
|
||||
AddPath("/opt/box64/lib32", &context->box64_ld_lib, 1);
|
||||
if(FileExist("/data/data/com.termux/files/usr/glibc/lib/i386-linux-gnu", 0))
|
||||
AddPath("/data/data/com.termux/files/usr/glibc/lib/i386-linux-gnu", &context->box64_ld_lib, 1);
|
||||
if(FileExist("/data/data/com.termux/files/usr/glibc/lib/box64-i386-linux-gnu", 0))
|
||||
@@ -489,6 +519,8 @@ void LoadLDPath(box64context_t *context)
|
||||
AddPath("/usr/x86_64-linux-gnu/lib", &context->box64_ld_lib, 1);
|
||||
if(FileExist("/usr/lib/box64-x86_64-linux-gnu", 0))
|
||||
AddPath("/usr/lib/box64-x86_64-linux-gnu", &context->box64_ld_lib, 1);
|
||||
if(FileExist("/opt/box64/lib64", 0))
|
||||
AddPath("/opt/box64/lib64", &context->box64_ld_lib, 1);
|
||||
if(FileExist("/data/data/com.termux/files/usr/glibc/lib/x86_64-linux-gnu", 0))
|
||||
AddPath("/data/data/com.termux/files/usr/glibc/lib/x86_64-linux-gnu", &context->box64_ld_lib, 1);
|
||||
if(FileExist("/data/data/com.termux/files/usr/glibc/lib/box64-x86_64-linux-gnu", 0))
|
||||
@@ -638,6 +670,8 @@ void setupTrace()
|
||||
void endMallocHook();
|
||||
#endif
|
||||
|
||||
void finiPendingDLOpenedNoUnload(x64emu_t* emu);
|
||||
|
||||
void endBox64()
|
||||
{
|
||||
if(!my_context || box64_quit)
|
||||
@@ -657,9 +691,30 @@ void endBox64()
|
||||
//void closeAllDLOpened();
|
||||
//closeAllDLOpened(); // close residual dlopened libs. Disabled, seems like a bad idea, better to unload with proper dependancies
|
||||
RunElfFini(my_context->elfs[0], emu);
|
||||
printf_log(LOG_DEBUG, "Finished calling fini for dlopened libs\n");
|
||||
finiPendingDLOpenedNoUnload(emu); // call fini for dlopened libs, but don't unload them, as they might be needed by the main elf fini
|
||||
// unload needed libs
|
||||
needed_libs_t* needed = my_context->elfs[0]->needed;
|
||||
printf_log(LOG_DEBUG, "Unloaded main elf: Will Dec RefCount of %d libs\n", needed?needed->size:0);
|
||||
int workers = get_active_emu_workers();
|
||||
if (workers > 0) {
|
||||
const int sleep_us = 10000; // 10ms
|
||||
const int max_wait_ms = 2000; // 2s
|
||||
int waited_ms = 0;
|
||||
|
||||
printf_log(LOG_INFO, "endBox64: waiting emu workers to exit (n=%d)\n", workers);
|
||||
while ((workers = get_active_emu_workers()) > 0 && waited_ms < max_wait_ms) {
|
||||
usleep(sleep_us);
|
||||
waited_ms += sleep_us / 1000;
|
||||
}
|
||||
|
||||
if (workers > 0) {
|
||||
printf_log(LOG_INFO,
|
||||
"endBox64: %d emu workers still alive after %dms, skip unload/free to avoid UAF crash\n",
|
||||
workers, waited_ms);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(needed)
|
||||
for(int i=0; i<needed->size; ++i)
|
||||
DecRefCount(&needed->libs[i], emu);
|
||||
@@ -716,10 +771,11 @@ extern char** environ;
|
||||
|
||||
int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elfheader_t** elfheader, int exec)
|
||||
{
|
||||
#ifndef STATICBUILD
|
||||
#ifndef STATICBUILD
|
||||
init_malloc_hook();
|
||||
#endif
|
||||
#endif
|
||||
init_auxval(argc, argv, environ?environ:env);
|
||||
ftrace = stderr; // init early: BOX64_VERSION path below uses PrintfFtrace
|
||||
// analogue to QEMU_VERSION in qemu-user-mode emulation
|
||||
if(getenv("BOX64_VERSION")) {
|
||||
PrintBox64Version(0);
|
||||
@@ -742,7 +798,14 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (argc >= 3 && (!strcmp(argv[1], "--test") || !strcmp(argv[1], "-t"))) {
|
||||
int is_test = 0;
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (!strcmp(argv[i], "--test") || !strcmp(argv[i], "-t")) {
|
||||
is_test = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (is_test) {
|
||||
box64_unittest_mode = 1;
|
||||
exit(unittest(argc, argv));
|
||||
}
|
||||
@@ -796,6 +859,7 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
|
||||
|
||||
if (!BOX64ENV(nobanner)) PrintBox64Version(1);
|
||||
|
||||
InitializeSystemInfo();
|
||||
displayMiscInfo();
|
||||
|
||||
hookMangoHud();
|
||||
@@ -844,14 +908,6 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
|
||||
if(!prog_) prog_ = prog; else ++prog_;
|
||||
}
|
||||
}
|
||||
#ifndef STATICBUILD
|
||||
// pre-check for pressure-vessel-wrap
|
||||
if(!strcmp(prog_, "pressure-vessel-wrap")) {
|
||||
printf_log(LOG_INFO, "pressure-vessel-wrap detected\n");
|
||||
unsetenv("BOX64_ARG0");
|
||||
pressure_vessel(argc, argv, nextarg+1, prog);
|
||||
}
|
||||
#endif
|
||||
int ld_libs_args = -1;
|
||||
int is_custom_gstreamer = 0;
|
||||
// check if this is wine
|
||||
@@ -949,6 +1005,17 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
|
||||
// allocate extra space for new environment variables such as BOX64_PATH
|
||||
my_context->envv = (char**)box_calloc(my_context->envc+1, sizeof(char*));
|
||||
|
||||
#ifndef STATICBUILD
|
||||
// pre-check for pressure-vessel-wrap
|
||||
if(!strcmp(prog_, "pressure-vessel-wrap")) {
|
||||
printf_log(LOG_INFO, "pressure-vessel-wrap detected, bashpath=%s\n", my_context->bashpath?my_context->bashpath:"(nil)");
|
||||
unsetenv("BOX64_ARG0");
|
||||
if(!my_context->bashpath)
|
||||
my_context->bashpath = ResolveFile("box64-bash", &my_context->box64_path);
|
||||
pressure_vessel(argc, argv, nextarg+1, prog);
|
||||
}
|
||||
#endif
|
||||
|
||||
path_collection_t ld_preload = {0};
|
||||
if(getenv("BOX64_LD_PRELOAD")) {
|
||||
char* p = getenv("BOX64_LD_PRELOAD");
|
||||
@@ -1049,15 +1116,17 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
|
||||
if(pythonpath)
|
||||
my_context->pythonpath = box_strdup(pythonpath);
|
||||
|
||||
ApplyEnvFileEntry(box64_guest_name);
|
||||
int applied = ApplyEnvFileEntry(box64_guest_name);
|
||||
if (box64_wine && box64_wine_guest_name) {
|
||||
ApplyEnvFileEntry(box64_wine_guest_name);
|
||||
applied |= ApplyEnvFileEntry(box64_wine_guest_name);
|
||||
box64_wine_guest_name = NULL;
|
||||
}
|
||||
// Try to open ftrace again after applying rcfile.
|
||||
displayMiscInfo();
|
||||
if (applied) {
|
||||
printf_log(LOG_INFO, "Applied settings from rcfile\n");
|
||||
displayMiscInfo();
|
||||
PrintEnvVariables(&box64env, LOG_INFO);
|
||||
}
|
||||
setupZydis(my_context);
|
||||
PrintEnvVariables(&box64env, LOG_INFO);
|
||||
|
||||
for(int i=1; i<my_context->argc; ++i) {
|
||||
my_context->argv[i] = box_strdup(argv[i+nextarg]);
|
||||
@@ -1193,6 +1262,11 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
|
||||
}
|
||||
#endif
|
||||
LoadLDPath(my_context);
|
||||
my_context->video_mem = mmap((void*)0xb0000, 0x10000, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
|
||||
if(my_context->video_mem != (void*)0xb0000) {
|
||||
my_context->video_mem = NULL;
|
||||
printf_log(LOG_INFO, "Warning, could not allocate text video memory");
|
||||
}
|
||||
elfheader_t *elf_header = LoadAndCheckElfHeader(f, my_context->fullpath, 1);
|
||||
if(!elf_header) {
|
||||
int x86 = my_context->box86path?FileIsX86ELF(my_context->fullpath):0;
|
||||
|
||||
+155
-135
@@ -1346,7 +1346,7 @@ void* box32_dynarec_mmap(size_t size, int fd, off_t offset)
|
||||
if(ret!=MAP_FAILED) {
|
||||
//rb_set(mapallmem, cur, cur+size, MEM_BOX); // mark as allocated by/for box
|
||||
} else
|
||||
printf_log(LOG_INFO, "BOX32: Error allocating Dynarec memory: %s\n", strerror(errno));
|
||||
printf_log(LOG_INFO, "Error allocating Dynarec memory: %s\n", strerror(errno));
|
||||
cur = cur+size;
|
||||
return ret;
|
||||
}
|
||||
@@ -1355,7 +1355,7 @@ void* box32_dynarec_mmap(size_t size, int fd, off_t offset)
|
||||
}
|
||||
#endif
|
||||
uint32_t map_flags = ((fd==-1)?MAP_ANONYMOUS:0) | MAP_PRIVATE;
|
||||
//printf_log(LOG_INFO, "BOX32: Error allocating Dynarec memory: %s\n", "fallback to internal mmap");
|
||||
// printf_log(LOG_INFO, "Error allocating Dynarec memory: %s\n", "fallback to internal mmap");
|
||||
void* ret = InternalMmap(box64_isAddressSpace32?NULL:(void*)0x100000000ULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, map_flags, fd, offset);
|
||||
//printf_log(LOG_INFO, "fallback on box32_dynarec_mmap: %p\n", ret);
|
||||
return ret;
|
||||
@@ -1480,6 +1480,7 @@ int MmaplistAddBlock(mmaplist_t* list, int fd, off_t offset, void* orig, size_t
|
||||
GO(instsize);
|
||||
GO(arch);
|
||||
GO(callrets);
|
||||
GO(sep);
|
||||
GO(jmpnext);
|
||||
GO(table64);
|
||||
GO(relocs);
|
||||
@@ -1506,6 +1507,14 @@ int MmaplistAddBlock(mmaplist_t* list, int fd, off_t offset, void* orig, size_t
|
||||
// cannot add blocks?
|
||||
printf_log(LOG_INFO, "Warning, cannot add DynaCache Block %d to JmpTable\n", i);
|
||||
} else {
|
||||
for(int i=0; i<bl->sep_size; ++i) {
|
||||
uint32_t x64_offs = bl->sep[i].x64_offs;
|
||||
uint32_t nat_offs = bl->sep[i].nat_offs;
|
||||
if(addJumpTableIfDefault64(bl->x64_addr+x64_offs, (bl->dirty || bl->always_test)?bl->jmpnext:(bl->block+nat_offs)))
|
||||
bl->sep[i].active = 1;
|
||||
else
|
||||
bl->sep[i].active = 0;
|
||||
}
|
||||
if(bl->x64_size) {
|
||||
dynarec_log(LOG_DEBUG, "Added DynCache bl %p for %p - %p\n", bl, bl->x64_addr, bl->x64_addr+bl->x64_size);
|
||||
if(bl->x64_size>my_context->max_db_size) {
|
||||
@@ -1556,6 +1565,7 @@ void DelMmaplist(mmaplist_t* list)
|
||||
} else
|
||||
rb_unset(mapallmem, (uintptr_t)addr, (uintptr_t)addr+size);
|
||||
}
|
||||
box_free(list->chunks);
|
||||
box_free(list);
|
||||
}
|
||||
|
||||
@@ -1840,7 +1850,7 @@ void addDBFromAddressRange(uintptr_t addr, size_t size)
|
||||
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");
|
||||
dynarec_log(LOG_DEBUG, "cleanDBFromAddressRange %p/%p -> %p %s\n", (void*)addr, (void*)start_addr, (void*)(addr+size-1), destroy?((destroy==2)?"invalidCRC":"destroy"):"mark");
|
||||
dynablock_t* db = NULL;
|
||||
uintptr_t end = addr+size;
|
||||
int ret = 0;
|
||||
@@ -1848,10 +1858,12 @@ int cleanDBFromAddressRange(uintptr_t addr, size_t size, int destroy)
|
||||
start_addr = getDBSize(start_addr, end-start_addr, &db);
|
||||
if(db) {
|
||||
ret = 1;
|
||||
if(destroy)
|
||||
FreeRangeDynablock(db, addr, size);
|
||||
else
|
||||
MarkRangeDynablock(db, addr, size);
|
||||
switch(destroy) {
|
||||
case 0: MarkRangeDynablock(db, addr, size); break;
|
||||
case 1: FreeRangeDynablock(db, addr, size); break;
|
||||
case 2: MarkCRCRangeDynablock(db, addr, size); break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
@@ -1975,9 +1987,9 @@ int addJumpTableIfDefault64(void* addr, void* jmp)
|
||||
idx0 = (((uintptr_t)addr) )&JMPTABLE_MASK0;
|
||||
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
return (native_lock_storeifref(create_jmptbl(0, idx0, idx1, idx2, idx3, idx4), jmp, native_next)==jmp)?1:0;
|
||||
return (native_lock_storeifref2(create_jmptbl(0, idx0, idx1, idx2, idx3, idx4), jmp, native_next)==native_next)?1:0;
|
||||
#else
|
||||
return (native_lock_storeifref(create_jmptbl(0, idx0, idx1, idx2, idx3), jmp, native_next)==jmp)?1:0;
|
||||
return (native_lock_storeifref2(create_jmptbl(0, idx0, idx1, idx2, idx3), jmp, native_next)==native_next)?1:0;
|
||||
#endif
|
||||
}
|
||||
void setJumpTableDefault64(void* addr)
|
||||
@@ -2023,9 +2035,9 @@ int setJumpTableDefaultIfRef64(void* addr, void* jmp)
|
||||
return 0;
|
||||
idx0 = (((uintptr_t)addr) )&JMPTABLE_MASK0;
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
return (native_lock_storeifref(create_jmptbl(0, idx0, idx1, idx2, idx3, idx4), native_next, jmp)==native_next)?1:0;
|
||||
return (native_lock_storeifref2(create_jmptbl(0, idx0, idx1, idx2, idx3, idx4), native_next, jmp)==jmp)?1:0;
|
||||
#else
|
||||
return (native_lock_storeifref(create_jmptbl(0, idx0, idx1, idx2, idx3), native_next, jmp)==native_next)?1:0;
|
||||
return (native_lock_storeifref2(create_jmptbl(0, idx0, idx1, idx2, idx3), native_next, jmp)==jmp)?1:0;
|
||||
#endif
|
||||
}
|
||||
void setJumpTableDefaultRef64(void* addr, void* jmp)
|
||||
@@ -2048,7 +2060,7 @@ void setJumpTableDefaultRef64(void* addr, void* jmp)
|
||||
if(box64_jmptbl3[idx3][idx2][idx1] == box64_jmptbldefault0)
|
||||
return;
|
||||
idx0 = (((uintptr_t)addr) )&JMPTABLE_MASK0;
|
||||
native_lock_storeifref(&box64_jmptbl3[idx3][idx2][idx1][idx0], native_next, jmp);
|
||||
native_lock_storeifref2(&box64_jmptbl3[idx3][idx2][idx1][idx0], native_next, jmp);
|
||||
}
|
||||
int setJumpTableIfRef64(void* addr, void* jmp, void* ref)
|
||||
{
|
||||
@@ -2061,9 +2073,9 @@ int setJumpTableIfRef64(void* addr, void* jmp, void* ref)
|
||||
idx1 = (((uintptr_t)addr)>>JMPTABL_START1)&JMPTABLE_MASK1;
|
||||
idx0 = (((uintptr_t)addr) )&JMPTABLE_MASK0;
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
return (native_lock_storeifref(create_jmptbl(0, idx0, idx1, idx2, idx3, idx4), jmp, ref)==jmp)?1:0;
|
||||
return (native_lock_storeifref2(create_jmptbl(0, idx0, idx1, idx2, idx3, idx4), jmp, ref)==ref)?1:0;
|
||||
#else
|
||||
return (native_lock_storeifref(create_jmptbl(0, idx0, idx1, idx2, idx3), jmp, ref)==jmp)?1:0;
|
||||
return (native_lock_storeifref2(create_jmptbl(0, idx0, idx1, idx2, idx3), jmp, ref)==ref)?1:0;
|
||||
#endif
|
||||
}
|
||||
int isJumpTableDefault64(void* addr)
|
||||
@@ -2129,7 +2141,7 @@ uintptr_t getJumpTableAddress64(uintptr_t addr)
|
||||
#endif
|
||||
}
|
||||
|
||||
dynablock_t* getDB(uintptr_t addr)
|
||||
dynablock_t* getDBBlock(uintptr_t addr, void** jblock)
|
||||
{
|
||||
uintptr_t idx3, idx2, idx1, idx0;
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
@@ -2144,29 +2156,35 @@ dynablock_t* getDB(uintptr_t addr)
|
||||
#else
|
||||
uintptr_t ret = (uintptr_t)box64_jmptbl3[idx3][idx2][idx1][idx0];
|
||||
#endif
|
||||
if(jblock) *jblock = (void*)ret;
|
||||
|
||||
return *(dynablock_t**)(ret - sizeof(void*));
|
||||
}
|
||||
|
||||
dynablock_t* getDB(uintptr_t addr)
|
||||
{
|
||||
return getDBBlock(addr, NULL);
|
||||
}
|
||||
|
||||
int getNeedTest(uintptr_t addr)
|
||||
{
|
||||
uintptr_t idx3, idx2, idx1, idx0;
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
uintptr_t idx4 = (((uintptr_t)addr)>>JMPTABL_START4)&JMPTABLE_MASK4;
|
||||
#endif
|
||||
idx3 = ((addr)>>JMPTABL_START3)&JMPTABLE_MASK3;
|
||||
idx2 = ((addr)>>JMPTABL_START2)&JMPTABLE_MASK2;
|
||||
idx1 = ((addr)>>JMPTABL_START1)&JMPTABLE_MASK1;
|
||||
idx0 = ((addr) )&JMPTABLE_MASK0;
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
uintptr_t ret = (uintptr_t)box64_jmptbl4[idx4][idx3][idx2][idx1][idx0];
|
||||
#else
|
||||
uintptr_t ret = (uintptr_t)box64_jmptbl3[idx3][idx2][idx1][idx0];
|
||||
#endif
|
||||
dynablock_t* db = *(dynablock_t**)(ret - sizeof(void*));
|
||||
return db?((ret!=(uintptr_t)db->block)?1:0):0;
|
||||
void* jblock = NULL;
|
||||
dynablock_t* db = getDBBlock(addr, &jblock);
|
||||
if(!db) return 0;
|
||||
if(jblock==db->jmpnext) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
dynablock_t* getDBnoTest(uintptr_t addr)
|
||||
{
|
||||
void* jblock = NULL;
|
||||
dynablock_t* db = getDBBlock(addr, &jblock);
|
||||
if(!db) return NULL;
|
||||
if(jblock==db->jmpnext) return NULL;
|
||||
return db;
|
||||
}
|
||||
|
||||
|
||||
uintptr_t getJumpAddress64(uintptr_t addr)
|
||||
{
|
||||
uintptr_t idx3, idx2, idx1, idx0;
|
||||
@@ -2184,6 +2202,31 @@ uintptr_t getJumpAddress64(uintptr_t addr)
|
||||
#endif
|
||||
}
|
||||
|
||||
// Helper: check if any sub-range in a host page has PROT_WRITE that is NOT part of the
|
||||
// dynarec-protected range [prot_start, prot_end). This detects mixed code+data host pages
|
||||
// on systems with large pages (e.g. 64KB) where mprotect to remove PROT_WRITE would also
|
||||
// strip writability from data regions, causing EFAULT on kernel writes (e.g. read() syscall).
|
||||
// Must be called with LOCK_PROT() held.
|
||||
static int hostPageHasExternalWrite_locked(uintptr_t host_page, uintptr_t prot_start, uintptr_t prot_end)
|
||||
{
|
||||
uintptr_t scan = host_page;
|
||||
uintptr_t host_end = host_page + box64_pagesize;
|
||||
while(scan < host_end) {
|
||||
uint32_t p = 0;
|
||||
uintptr_t bend = 0;
|
||||
rb_get_end(memprot, scan, &p, &bend);
|
||||
if(bend > host_end)
|
||||
bend = host_end;
|
||||
if(p && (p & PROT_WRITE) && !(p & PROT_DYN)) {
|
||||
if(scan < prot_start || bend > prot_end) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
scan = bend;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Remove the Write flag from an adress range, so DB can be executed safely
|
||||
void protectDBJumpTable(uintptr_t addr, size_t size, void* jump, void* ref)
|
||||
{
|
||||
@@ -2206,8 +2249,19 @@ void protectDBJumpTable(uintptr_t addr, size_t size, void* jump, void* ref)
|
||||
if(!(dyn&PROT_NEVERPROT)) {
|
||||
prot&=~PROT_CUSTOM;
|
||||
if(prot&PROT_WRITE) {
|
||||
if(!dyn)
|
||||
mprotect((void*)cur, bend-cur, prot&~PROT_WRITE);
|
||||
if(!dyn) {
|
||||
if(box64_pagesize > 4096) {
|
||||
uintptr_t host_page = cur & ~(box64_pagesize-1);
|
||||
if(hostPageHasExternalWrite_locked(host_page, addr, addr+size)) {
|
||||
dynarec_log(LOG_INFO, "protectDBJumpTable: mixed code+data host page %p, using always_test instead of mprotect\n", (void*)host_page);
|
||||
prot |= PROT_NEVERCLEAN;
|
||||
} else {
|
||||
mprotect((void*)cur, bend-cur, prot&~PROT_WRITE);
|
||||
}
|
||||
} else {
|
||||
mprotect((void*)cur, bend-cur, prot&~PROT_WRITE);
|
||||
}
|
||||
}
|
||||
prot |= PROT_DYNAREC;
|
||||
} else
|
||||
prot |= PROT_DYNAREC_R;
|
||||
@@ -2243,8 +2297,24 @@ void protectDB(uintptr_t addr, uintptr_t size)
|
||||
if(!(dyn&PROT_NEVERPROT)) {
|
||||
prot&=~PROT_CUSTOM;
|
||||
if(prot&PROT_WRITE) {
|
||||
if(!dyn)
|
||||
mprotect((void*)cur, bend-cur, prot&~PROT_WRITE);
|
||||
if(!dyn) {
|
||||
// On large-page systems, check if removing PROT_WRITE from this host page
|
||||
// would also affect writable data regions sharing the same host page.
|
||||
// If so, use PROT_NEVERCLEAN (always_test mode) instead of mprotect,
|
||||
// because kernel syscalls (e.g. read()) cannot be caught via SEGV and
|
||||
// would return EFAULT if the buffer is on a non-writable page.
|
||||
if(box64_pagesize > 4096) {
|
||||
uintptr_t host_page = cur & ~(box64_pagesize-1);
|
||||
if(hostPageHasExternalWrite_locked(host_page, addr, addr+size)) {
|
||||
dynarec_log(LOG_INFO, "protectDB: mixed code+data host page %p, using always_test instead of mprotect\n", (void*)host_page);
|
||||
prot |= PROT_NEVERCLEAN;
|
||||
} else {
|
||||
mprotect((void*)cur, bend-cur, prot&~PROT_WRITE);
|
||||
}
|
||||
} else {
|
||||
mprotect((void*)cur, bend-cur, prot&~PROT_WRITE);
|
||||
}
|
||||
}
|
||||
prot |= PROT_DYNAREC;
|
||||
} else
|
||||
prot |= PROT_DYNAREC_R;
|
||||
@@ -2322,11 +2392,11 @@ void neverprotectDB(uintptr_t addr, size_t size, int mark)
|
||||
if(prot&PROT_DYNAREC) {
|
||||
prot&=~PROT_DYN;
|
||||
if(mark)
|
||||
cleanDBFromAddressRange(cur, bend-cur, 0);
|
||||
cleanDBFromAddressRange(cur, bend-cur, (mark==2)?2:0);
|
||||
mprotect((void*)cur, bend-cur, prot);
|
||||
} else if(prot&PROT_DYNAREC_R) {
|
||||
if(mark)
|
||||
cleanDBFromAddressRange(cur, bend-cur, 0);
|
||||
cleanDBFromAddressRange(cur, bend-cur, (mark==2)?2:0);
|
||||
prot &= ~PROT_DYN;
|
||||
}
|
||||
prot |= PROT_NEVERCLEAN;
|
||||
@@ -2399,18 +2469,22 @@ typedef union hotpage_s {
|
||||
} hotpage_t;
|
||||
#define HOTPAGE_MAX ((1<<28)-1)
|
||||
#define N_HOTPAGE 32
|
||||
#define N_HOTPAGE_ALT 8
|
||||
#define HOTPAGE_MARK 64
|
||||
#define HOTPAGE_DIRTY 128
|
||||
#define HOTPAGE_DIRTY_ALT 1024
|
||||
#define HOTPAGE_DIRTY2 16
|
||||
static hotpage_t hotpage[N_HOTPAGE] = {0};
|
||||
void SetHotPage(int idx, uintptr_t page)
|
||||
{
|
||||
hotpage_t tmp = hotpage[idx];
|
||||
tmp.addr = page;
|
||||
tmp.cnt = BOX64ENV(dynarec_dirty)?(BOX64ENV(dynarec_hotpage_alt)?HOTPAGE_DIRTY_ALT:HOTPAGE_DIRTY):HOTPAGE_MARK;
|
||||
tmp.cnt = 0;
|
||||
switch(BOX64ENV(dynarec_dirty)) {
|
||||
case 0: tmp.cnt = HOTPAGE_MARK; break;
|
||||
case 1: tmp.cnt = HOTPAGE_DIRTY; break;
|
||||
case 2: tmp.cnt = HOTPAGE_DIRTY2; break;
|
||||
}
|
||||
//TODO: use Atomics to update hotpage?
|
||||
native_lock_store_dd(hotpage+idx, tmp.x);
|
||||
native_lock_store_dd(&hotpage[idx], tmp.x);
|
||||
}
|
||||
int IdxHotPage(uintptr_t page)
|
||||
{
|
||||
@@ -2419,36 +2493,14 @@ int IdxHotPage(uintptr_t page)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
void CancelHotPage(uintptr_t page)
|
||||
{
|
||||
unneverprotectDB(page<<12, box64_pagesize);
|
||||
}
|
||||
int IdxOldestHotPage(uintptr_t page)
|
||||
{
|
||||
int best_idx = -1;
|
||||
uint32_t best_cnt = HOTPAGE_MAX+1;
|
||||
if(BOX64ENV(dynarec_hotpage_alt)) {
|
||||
hotpage_t tmp;
|
||||
tmp.addr = page;
|
||||
tmp.cnt = HOTPAGE_MAX;
|
||||
for(int i=0; i<N_HOTPAGE_ALT; ++i) {
|
||||
if(!hotpage[i].cnt) {
|
||||
native_lock_store_dd(hotpage+i, tmp.x);
|
||||
return i;
|
||||
}
|
||||
uint32_t cnt = hotpage[i].cnt;
|
||||
if(cnt==HOTPAGE_MAX) cnt = 0;
|
||||
if(cnt < best_cnt) {
|
||||
best_idx = i;
|
||||
best_cnt = cnt;
|
||||
}
|
||||
}
|
||||
hotpage_t old = hotpage[best_idx];
|
||||
native_lock_store_dd(hotpage+best_idx, tmp.x);
|
||||
if(old.cnt && old.cnt!=HOTPAGE_MAX && BOX64ENV(dynarec_dirty)==1)
|
||||
CancelHotPage(old.addr);
|
||||
} else {
|
||||
for(int i=0; i<N_HOTPAGE && best_cnt; ++i) {
|
||||
for(int i=0; i<N_HOTPAGE; ++i) {
|
||||
if(!hotpage[i].x) {
|
||||
return i;
|
||||
} else {
|
||||
uint32_t cnt = hotpage[i].cnt;
|
||||
if(cnt < best_cnt) {
|
||||
best_idx = i;
|
||||
@@ -2456,6 +2508,7 @@ int IdxOldestHotPage(uintptr_t page)
|
||||
}
|
||||
}
|
||||
}
|
||||
dynarec_log(LOG_INFO, "%04d|No more live Hotpage slot for %p, recycling idx=%d (%p)\n", GetTID(), (void*)(page<<12), best_idx, (void*)(uintptr_t)(hotpage[best_idx].addr<<12));
|
||||
return best_idx;
|
||||
}
|
||||
// this function will create a new HotPage, or re-arm it if it's already registered
|
||||
@@ -2468,87 +2521,51 @@ void CheckHotPage(uintptr_t addr, uint32_t prot)
|
||||
if(BOX64ENV(dynarec_nohotpage))
|
||||
return;
|
||||
uintptr_t page = addr>>12;
|
||||
if(!BOX64ENV(dynarec_hotpage_alt)) {
|
||||
if(!(prot&PROT_EXEC))
|
||||
return; // needs to be an executable page
|
||||
/*if(BOX64ENV(dynarec_dirty)>1) {
|
||||
dynarec_log(LOG_INFO, "Detecting a Hotpage at %p, marking page as NEVERCLEAN\n", (void*)(page<<12));
|
||||
neverprotectDB(page<<12, box64_pagesize, 1);
|
||||
return;
|
||||
}*/
|
||||
}
|
||||
// look for idx
|
||||
int idx = IdxHotPage(page);
|
||||
if(BOX64ENV(dynarec_hotpage_alt)) {
|
||||
if(idx==-1) { IdxOldestHotPage(page); return; }
|
||||
hotpage_t hp = hotpage[idx];
|
||||
/*if(hp.cnt==HOTPAGE_MAX)*/ {
|
||||
if(BOX64ENV(dynarec_dirty)>1) {
|
||||
dynarec_log(LOG_INFO, "Detecting a Hotpage at %p (idx=%d), marking page as NEVERCLEAN\n", (void*)(page<<12), idx);
|
||||
neverprotectDB(page<<12, box64_pagesize, 1);
|
||||
hp.cnt = 0;
|
||||
native_lock_store_dd(hotpage+idx, hp.x); // free slot
|
||||
} else {
|
||||
dynarec_log(LOG_INFO, "Detecting a Hotpage at %p (idx=%d)\n", (void*)(page<<12), idx);
|
||||
SetHotPage(idx, page);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(idx!=-1 && BOX64ENV(dynarec_dirty)>1 && !hotpage[idx].cnt) {
|
||||
// Re-arming, so put the page as NEVERCLEAN and stop bothering
|
||||
neverprotectDB(page<<12, box64_pagesize, 1);
|
||||
return;
|
||||
}
|
||||
if(idx==-1) idx = IdxOldestHotPage(page);
|
||||
if(idx==-1) return;
|
||||
dynarec_log(LOG_INFO, "Detecting a Hotpage at %p (idx=%d)\n", (void*)(page<<12), idx);
|
||||
SetHotPage(idx, page);
|
||||
if(idx!=-1 && (BOX64ENV(dynarec_dirty)>1)) {
|
||||
// Re-arming, so put the page as NEVERCLEAN and stop bothering
|
||||
dynarec_log(LOG_INFO, "Detecting a Hotpage at %p (idx=%d) again, switching the page to NEVERCLEAN\n", (void*)(page<<12), idx);
|
||||
neverprotectDB(page<<12, box64_pagesize, 2);
|
||||
hotpage_t hp = {0};
|
||||
native_lock_store_dd(hotpage+idx, hp.x); // free slot
|
||||
return;
|
||||
}
|
||||
if(idx==-1) idx = IdxOldestHotPage(page);
|
||||
if(idx==-1) return;
|
||||
dynarec_log(LOG_INFO, "%04d|Detecting a Hotpage at %p (idx=%d)\n", GetTID(), (void*)(page<<12), idx);
|
||||
SetHotPage(idx, page);
|
||||
}
|
||||
int isInHotPage(uintptr_t addr)
|
||||
{
|
||||
if(addr>0x1000000000000LL) return 0;
|
||||
if(BOX64ENV(dynarec_nohotpage))
|
||||
return 0;
|
||||
uintptr_t page = addr>>12;
|
||||
int idx = IdxHotPage(page);
|
||||
if(BOX64ENV(dynarec_hotpage_alt)) {
|
||||
if(idx==-1 || !hotpage[idx].cnt || (hotpage[idx].cnt==HOTPAGE_MAX))
|
||||
return 0;
|
||||
//TODO: do Atomic stuffs instead
|
||||
hotpage_t hp = hotpage[idx];
|
||||
--hp.cnt;
|
||||
native_lock_store_dd(hotpage+idx, hp.x);
|
||||
if(!hp.cnt && BOX64ENV(dynarec_dirty)==1)
|
||||
CancelHotPage(hp.addr);
|
||||
return 1;
|
||||
} else {
|
||||
int ret = ((idx==-1) || !hotpage[idx].cnt)?0:1;
|
||||
// decrement all hotpage, it's a hotpage "tick"
|
||||
for(int i=0; i<N_HOTPAGE; ++i) {
|
||||
int ok = 0;
|
||||
do {
|
||||
hotpage_t hp = hotpage[i];
|
||||
hotpage_t old = hp;
|
||||
if(!hp.cnt || (hp.cnt==HOTPAGE_MAX)) {
|
||||
ok = 1;
|
||||
} else {
|
||||
--hp.cnt;
|
||||
ok = native_lock_storeifref2(hotpage+i, (void*)hp.x, (void*)old.x)==(void*)old.x;
|
||||
}
|
||||
} while(!ok);
|
||||
}
|
||||
return ret;
|
||||
int ret = ((idx==-1) || !hotpage[idx].cnt)?0:1;
|
||||
// decrement all hotpage, it's a hotpage "tick"
|
||||
for(int i=0; i<N_HOTPAGE; ++i) {
|
||||
int ok = 0;
|
||||
do {
|
||||
hotpage_t hp = hotpage[i];
|
||||
hotpage_t old = hp;
|
||||
if(!hp.cnt || (hp.cnt==HOTPAGE_MAX)) {
|
||||
ok = 1;
|
||||
} else {
|
||||
--hp.cnt;
|
||||
ok = native_lock_storeifref2(hotpage+i, (void*)hp.x, (void*)old.x)==(void*)old.x;
|
||||
}
|
||||
} while(!ok);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
int checkInHotPage(uintptr_t addr)
|
||||
{
|
||||
if(addr>0x1000000000000LL) return 0;
|
||||
uintptr_t page = addr>>12;
|
||||
int idx = IdxHotPage(page);
|
||||
if(BOX64ENV(dynarec_hotpage_alt)) {
|
||||
return (idx==-1 || !hotpage[idx].cnt || (hotpage[idx].cnt==HOTPAGE_MAX))?0:1;
|
||||
} else {
|
||||
return ((idx==-1) || !hotpage[idx].cnt)?0:1;
|
||||
}
|
||||
return ((idx==-1) || !hotpage[idx].cnt)?0:1;
|
||||
}
|
||||
|
||||
|
||||
@@ -2666,7 +2683,7 @@ void refreshProtection(uintptr_t addr)
|
||||
|
||||
void allocProtection(uintptr_t addr, size_t size, uint32_t prot)
|
||||
{
|
||||
dynarec_log(LOG_DEBUG, "allocProtection %p:%p 0x%x\n", (void*)addr, (void*)(addr+size-1), prot);
|
||||
dynarec_log(LOG_DEBUG, "allocProtection %p:%p 0x%x", (void*)addr, (void*)(addr+size-1), prot);
|
||||
size = ALIGN(size);
|
||||
addr &= ~(box64_pagesize-1);
|
||||
LOCK_PROT();
|
||||
@@ -2674,8 +2691,11 @@ void allocProtection(uintptr_t addr, size_t size, uint32_t prot)
|
||||
uintptr_t endb;
|
||||
int there = rb_get_end(mapallmem, addr, &val, &endb);
|
||||
// block is here or absent, no half-block handled..
|
||||
if(!there)
|
||||
if(!there) {
|
||||
dynarec_log_prefix(0, LOG_DEBUG, " added\n");
|
||||
rb_set(mapallmem, addr, addr+size, MEM_EXTERNAL);
|
||||
} else
|
||||
dynarec_log_prefix(0, LOG_DEBUG, " ignored\n");
|
||||
UNLOCK_PROT();
|
||||
// don't need to add precise tracking probably
|
||||
}
|
||||
@@ -3121,9 +3141,9 @@ void fini_custommem_helper(box64context_t *ctx)
|
||||
for (int i=0; i<head->size; ++i) {
|
||||
InternalMunmap(head->chunks[i]->block-sizeof(blocklist_t), head->chunks[i]->size+sizeof(blocklist_t));
|
||||
}
|
||||
free(head);
|
||||
box_free(head->chunks);
|
||||
box_free(head);
|
||||
}
|
||||
box_free(mmaplist);
|
||||
#ifdef JMPTABL_SHIFT4
|
||||
uintptr_t**** box64_jmptbl3;
|
||||
for(int i4 = 0; i4 < (1<< JMPTABL_SHIFT4); ++i4)
|
||||
|
||||
@@ -79,6 +79,7 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#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 SUBx_REG_ASR(Rd, Rn, Rm, asr) EMIT(ADDSUB_REG_gen(1, 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))
|
||||
@@ -131,6 +132,12 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#define ADDSUB_ext(sf, op, S, Rm, option, imm3, Rn, Rd) ((sf)<<31 | (op)<<30 | (S)<<29 | 0b01011<<24 | 1<<21 | (Rm)<<16 | (option)<<13 | (imm3)<<10 | (Rn)<<5 | (Rd))
|
||||
#define SUBxw_UXTB(Rd, Rn, Rm) EMIT(ADDSUB_ext(rex.w, 1, 0, Rm, 0b000, 0, Rn, Rd))
|
||||
#define SUBw_UXTB(Rd, Rn, Rm) EMIT(ADDSUB_ext(0, 1, 0, Rm, 0b000, 0, Rn, Rd))
|
||||
#define SUBw_SXTB(Rd, Rn, Rm) EMIT(ADDSUB_ext(0, 1, 0, Rm, 0b100, 0, Rn, Rd))
|
||||
#define SUBw_UXTH(Rd, Rn, Rm) EMIT(ADDSUB_ext(0, 1, 0, Rm, 0b001, 0, Rn, Rd))
|
||||
#define SUBx_UXTW(Rd, Rn, Rm) EMIT(ADDSUB_ext(1, 1, 0, Rm, 0b010, 0, Rn, Rd))
|
||||
#define SUBw_SXTH(Rd, Rn, Rm) EMIT(ADDSUB_ext(0, 1, 0, Rm, 0b101, 0, Rn, Rd))
|
||||
#define SUBx_SXTW(Rd, Rn, Rm) EMIT(ADDSUB_ext(1, 1, 0, Rm, 0b110, 0, Rn, Rd))
|
||||
#define ADDz_UXTB(Rd, Rn, Rm) EMIT(ADDSUB_ext(rex.is32bits?0:1, 0, 0, Rm, 0b000, 0, Rn, Rd))
|
||||
#define ADDw_UXTH(Rd, Rn, Rm) EMIT(ADDSUB_ext(0, 0, 0, Rm, 0b001, 0, Rn, Rd))
|
||||
#define ADDx_UXTW(Rd, Rn, Rm) EMIT(ADDSUB_ext(1, 0, 0, Rm, 0b010, 0, Rn, Rd))
|
||||
#define ADDx_SXTW(Rd, Rn, Rm) EMIT(ADDSUB_ext(1, 0, 0, Rm, 0b110, 0, Rn, Rd))
|
||||
@@ -556,7 +563,7 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#define BICw_LSL(Rd, Rn, Rm, lsl) EMIT(LOGIC_REG_gen(0, 0b00, 0b00, 1, Rm, lsl, Rn, Rd))
|
||||
#define BICSx(Rd, Rn, Rm) FEMIT(LOGIC_REG_gen(1, 0b11, 0b00, 1, Rm, 0, Rn, Rd))
|
||||
#define BICSw(Rd, Rn, Rm) FEMIT(LOGIC_REG_gen(0, 0b11, 0b00, 1, Rm, 0, Rn, Rd))
|
||||
#define BICxw(Rd, Rn, Rm) FEMIT(LOGIC_REG_gen(rex.w, 0b00, 0b00, 1, Rm, 0, Rn, Rd))
|
||||
#define BICxw(Rd, Rn, Rm) EMIT(LOGIC_REG_gen(rex.w, 0b00, 0b00, 1, Rm, 0, Rn, Rd))
|
||||
#define BICSxw(Rd, Rn, Rm) FEMIT(LOGIC_REG_gen(rex.w, 0b11, 0b00, 1, Rm, 0, Rn, Rd))
|
||||
#define BICx_REG BICx
|
||||
#define BICw_REG BICw
|
||||
@@ -1214,6 +1221,11 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#define FCMPS_0(Sn) FEMIT(FCMP_scalar(0b00, Sn, 0, 0b01))
|
||||
#define FCMPD_0(Dn) FEMIT(FCMP_scalar(0b01, Dn, 0, 0b01))
|
||||
|
||||
// CCMP . CMP if cond is pass, else use nzcv as new flags
|
||||
#define FCCMP_scalar(type, Rm, cond, Rn, op, nzcv) (0b00011110<<24 | (type)<<22 | 1<<21 | (Rm)<<16 | ((cond)<<12 | 0b01<<10 | (Rn)<<5 | (op)<<4 | (nzcv)))
|
||||
#define FCCMPS(Sn, Sm, nzcv, cond) FEMIT(FCCMP_scalar(0b00, Sm, cond, Sn, 0, nzcv))
|
||||
#define FCCMPD(Dn, Dm, nzcv, cond) FEMIT(FCCMP_scalar(0b01, Dm, cond, Dn, 0, nzcv))
|
||||
|
||||
// CVT
|
||||
#define FCVT_scalar(sf, type, rmode, opcode, Rn, Rd) ((sf)<<31 | 0b11110<<24 | (type)<<22 | 1<<21 | (rmode)<<19 | (opcode)<<16 | (Rn)<<5 | (Rd))
|
||||
// Floating-point Convert to Signed integer, rounding to nearest with ties to Away
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
.global arm64_lock_get_d
|
||||
.global arm64_lock_get_dd
|
||||
.global arm64_crc
|
||||
.global arm64_x31_hash
|
||||
|
||||
arm64_lock_read_b:
|
||||
dmb ish
|
||||
@@ -261,6 +262,7 @@ arm64_atomic_storeifref:
|
||||
mov x3, x2
|
||||
casal x2, x1, [x0]
|
||||
cmp x2, x3
|
||||
bne 2f
|
||||
mov x0, x1
|
||||
ret
|
||||
2:
|
||||
@@ -291,6 +293,7 @@ arm64_atomic_storeifref_d:
|
||||
// address is x0, value is w1, w1 store to x0 only if [x0] is w2. return new [x0] value (so w1 or old value)
|
||||
mov w3, w2
|
||||
casal w2, w1, [x0]
|
||||
bne 2f
|
||||
cmp w2, w3
|
||||
mov w0, w1
|
||||
ret
|
||||
@@ -441,4 +444,31 @@ arm64_crc:
|
||||
subs w1, w1, #1
|
||||
bne 3b
|
||||
4:
|
||||
ret
|
||||
|
||||
arm64_x31_hash:
|
||||
//x0 is address, w1 is len
|
||||
mov x2, x0 // address is x2 now
|
||||
mov w0, wzr // hash is w0
|
||||
1:
|
||||
cmp w1, #8
|
||||
blo 2f
|
||||
ldr x3, [x2], #8
|
||||
mov x4, #8
|
||||
3:
|
||||
sub w0, w0, w0, lsl #5
|
||||
sub w0, w0, w3, uxtb
|
||||
sub w0, wzr, w0
|
||||
ror x3, x3, #8
|
||||
subs w4, w4, #1
|
||||
bne 3b
|
||||
2:
|
||||
cbz w1, 5f
|
||||
4:
|
||||
ldrb w3, [x2], #1
|
||||
sub w0, w0, w0, lsl #5
|
||||
sub w0, w3, w0
|
||||
subs w1, w1, #1
|
||||
bne 4b
|
||||
5:
|
||||
ret
|
||||
@@ -1,14 +1,14 @@
|
||||
//arm update linker table for dynarec
|
||||
//called with pointer to emu as 1st parameter
|
||||
//and address of table to as 2nd parameter
|
||||
//ip is at r12
|
||||
|
||||
.text
|
||||
.align 4
|
||||
|
||||
.extern LinkNext
|
||||
.extern LinkNextInvalid
|
||||
|
||||
.global arm64_next
|
||||
.global arm64_next_invalid
|
||||
|
||||
.8byte 0 // NULL pointer before arm64_next, for getDB
|
||||
arm64_next:
|
||||
@@ -43,3 +43,36 @@ arm64_next:
|
||||
// return offset is jump address
|
||||
br x3
|
||||
|
||||
|
||||
arm64_next_invalid:
|
||||
// emu is r0
|
||||
// IP address is r1
|
||||
sub sp, sp, (8 * 12)
|
||||
stp x0, x1, [sp, (8 * 0)]
|
||||
stp x10, x11, [sp, (8 * 2)]
|
||||
stp x12, x13, [sp, (8 * 4)]
|
||||
stp x14, x15, [sp, (8 * 6)]
|
||||
stp x16, x17, [sp, (8 * 8)]
|
||||
stp x18, x27, [sp, (8 * 10)] // also save x27(rip) to allow change in LinkNext
|
||||
|
||||
#ifdef _WIN32
|
||||
ldr x18, [x0, 3104]
|
||||
#endif
|
||||
mov x1, x27 // xRIP, should not be needed most of the time
|
||||
mov x2, x30 // "from" is in lr, so put in x2
|
||||
add x3, sp, 8*11 // x3 is address to change rip
|
||||
// call the function
|
||||
bl LinkNextInvalid
|
||||
// preserve return value
|
||||
mov x3, x0
|
||||
// pop regs
|
||||
ldp x0, x1, [sp, (8 * 0)]
|
||||
ldp x10, x11, [sp, (8 * 2)]
|
||||
ldp x12, x13, [sp, (8 * 4)]
|
||||
ldp x14, x15, [sp, (8 * 6)]
|
||||
ldp x16, x17, [sp, (8 * 8)]
|
||||
ldp x18, x27, [sp, (8 * 10)]
|
||||
add sp, sp, (8 * 12)
|
||||
// return offset is jump address
|
||||
br x3
|
||||
|
||||
@@ -979,16 +979,37 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
*ok = 0;
|
||||
}
|
||||
break;
|
||||
case 0x63:
|
||||
if(rex.is32bits) {
|
||||
// ARPL here
|
||||
DEFAULT;
|
||||
} else {
|
||||
INST_NAME("MOVSXD Gd, Ed");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(rex.w) {
|
||||
if(MODREG) { // reg <= reg
|
||||
case 0x63:
|
||||
if(rex.is32bits) {
|
||||
// ARPL r/m16, r16
|
||||
// If dst.RPL < src.RPL then dst.RPL = src.RPL and ZF=1, else ZF=0.
|
||||
// Only ZF is modified.
|
||||
INST_NAME("ARPL Ew, Gw");
|
||||
nextop = F8;
|
||||
SETFLAGS(X_ZF, SF_SUBSET);
|
||||
SET_DFNONE();
|
||||
GETEW(x1, 0);
|
||||
GETGW(x2);
|
||||
// Extract RPL (low 2 bits)
|
||||
UBFXw(x6, ed, 0, 2);
|
||||
UBFXw(x4, gd, 0, 2);
|
||||
// need_update = (dst_rpl < src_rpl)
|
||||
CMPSw_REG(x6, x4);
|
||||
CSETw(x5, cLT);
|
||||
// ZF = need_update
|
||||
BFIw(xFlags, x5, F_ZF, 1);
|
||||
// If no update needed then skip the writeback.
|
||||
CBZw_MARK(x5);
|
||||
// Update dest selector's low 2 bits.
|
||||
BFXILw(ed, gd, 0, 2);
|
||||
EWBACK;
|
||||
MARK;
|
||||
} else {
|
||||
INST_NAME("MOVSXD Gd, Ed");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(rex.w) {
|
||||
if(MODREG) { // reg <= reg
|
||||
SXTWx(gd, TO_NAT((nextop & 7) + (rex.b << 3)));
|
||||
} else { // mem <= reg
|
||||
SMREAD();
|
||||
@@ -1015,8 +1036,12 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
LDRSW_U12(x1, x3, 0);
|
||||
PUSH1z(x1);
|
||||
} else {
|
||||
MOV64z(x3, i64);
|
||||
PUSH1z(x3);
|
||||
if (!i64) {
|
||||
PUSH1z(xZR);
|
||||
} else {
|
||||
MOV64z(x3, i64);
|
||||
PUSH1z(x3);
|
||||
}
|
||||
SMWRITE();
|
||||
}
|
||||
break;
|
||||
@@ -1083,8 +1108,12 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0x6A:
|
||||
INST_NAME("PUSH Ib");
|
||||
i64 = F8S;
|
||||
MOV64z(x3, i64);
|
||||
PUSH1z(x3);
|
||||
if (!i64) {
|
||||
PUSH1z(xZR);
|
||||
} else {
|
||||
MOV64z(x3, i64);
|
||||
PUSH1z(x3);
|
||||
}
|
||||
SMWRITE();
|
||||
break;
|
||||
case 0x6B:
|
||||
@@ -1804,6 +1833,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(box64_wine || 1) { // 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
|
||||
LDRw_U12(x4, xEmu, offsetof(x64emu_t, flags));
|
||||
ORRw_mask(x4, x4, 32-FLAGS_NO_TF, 0); //mask=1<<FLAGS_NO_TF
|
||||
STRw_U12(x4, xEmu, offsetof(x64emu_t, flags));
|
||||
jump_to_epilog(dyn, addr, 0, ninst);
|
||||
}
|
||||
break;
|
||||
@@ -1831,7 +1863,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
u64 = F64;
|
||||
unscaled = 0; fixedaddress = 0;
|
||||
if(rex.seg && (u64<0x1000 || (int64_t)u64>-0x1000)) {
|
||||
grab_segdata(dyn, addr, ninst, x1, rex.seg, 0);
|
||||
grab_segdata(dyn, addr, ninst, x1, rex.seg);
|
||||
if(u64) {
|
||||
if(u64<0x1000)
|
||||
fixedaddress = u64;
|
||||
@@ -1843,7 +1875,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
MOV64y(x1, u64);
|
||||
if(rex.seg) {
|
||||
grab_segdata(dyn, addr, ninst, x3, rex.seg, 0);
|
||||
grab_segdata(dyn, addr, ninst, x3, rex.seg);
|
||||
ADDx_REGy(x1, x3, x1);
|
||||
}
|
||||
}
|
||||
@@ -1862,7 +1894,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
u64 = F64;
|
||||
unscaled = 0; fixedaddress = 0;
|
||||
if(rex.seg && (u64<0x1000 || (int64_t)u64>-0x1000 || (u64<(0x1000<<(2+rex.w)) && !(u64&(((1<<(2+rex.w))-1)))))) {
|
||||
grab_segdata(dyn, addr, ninst, x1, rex.seg, 0);
|
||||
grab_segdata(dyn, addr, ninst, x1, rex.seg);
|
||||
if(u64) {
|
||||
if(u64<0x100)
|
||||
{fixedaddress = u64; unscaled = 1;}
|
||||
@@ -1878,7 +1910,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
MOV64y(x1, u64);
|
||||
if(rex.seg) {
|
||||
grab_segdata(dyn, addr, ninst, x3, rex.seg, 0);
|
||||
grab_segdata(dyn, addr, ninst, x3, rex.seg);
|
||||
ADDx_REGy(x1, x3, x1);
|
||||
}
|
||||
}
|
||||
@@ -1896,7 +1928,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
u64 = F64;
|
||||
unscaled = 0; fixedaddress = 0;
|
||||
if(rex.seg && (u64<0x1000 || (int64_t)u64>-0x1000)) {
|
||||
grab_segdata(dyn, addr, ninst, x1, rex.seg, 0);
|
||||
grab_segdata(dyn, addr, ninst, x1, rex.seg);
|
||||
if(u64) {
|
||||
if(u64<0x1000)
|
||||
fixedaddress = u64;
|
||||
@@ -1908,7 +1940,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
MOV64y(x1, u64);
|
||||
if(rex.seg) {
|
||||
grab_segdata(dyn, addr, ninst, x3, rex.seg, 0);
|
||||
grab_segdata(dyn, addr, ninst, x3, rex.seg);
|
||||
ADDx_REGy(x1, x3, x1);
|
||||
}
|
||||
}
|
||||
@@ -1926,7 +1958,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
u64 = F64;
|
||||
unscaled = 0; fixedaddress = 0;
|
||||
if(rex.seg && (u64<0x1000 || (int64_t)u64>-0x1000 || (u64<(0x1000<<(2+rex.w)) && !(u64&(((1<<(2+rex.w))-1)))))) {
|
||||
grab_segdata(dyn, addr, ninst, x1, rex.seg, 0);
|
||||
grab_segdata(dyn, addr, ninst, x1, rex.seg);
|
||||
if(u64) {
|
||||
if(u64<0x100)
|
||||
{fixedaddress = u64; unscaled = 1;}
|
||||
@@ -1942,7 +1974,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
MOV64y(x1, u64);
|
||||
if(rex.seg) {
|
||||
grab_segdata(dyn, addr, ninst, x3, rex.seg, 0);
|
||||
grab_segdata(dyn, addr, ninst, x3, rex.seg);
|
||||
ADDx_REGy(x1, x3, x1);
|
||||
}
|
||||
}
|
||||
@@ -2644,7 +2676,14 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
i32 = F16;
|
||||
retn_to_epilog(dyn, ip, ninst, rex, i32);
|
||||
POP1z(xRIP);
|
||||
if(i32>0xfff) {
|
||||
MOV32w(w1, i32);
|
||||
ADDz_REG(xRSP, xRSP, x1);
|
||||
} else {
|
||||
ADDz_U12(xRSP, xRSP, i32);
|
||||
}
|
||||
ret_to_next(dyn, ip, ninst, rex);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
break;
|
||||
@@ -2655,7 +2694,8 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
READFLAGS(X_PEND); // so instead, force the deferred flags, so it's not too slow, and flags are not lost
|
||||
}
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
ret_to_epilog(dyn, ip, ninst, rex);
|
||||
POP1z(xRIP);
|
||||
ret_to_next(dyn, ip, ninst, rex);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
break;
|
||||
@@ -2815,15 +2855,15 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
u16 = F16;
|
||||
READFLAGS(X_PEND);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
POP2z(xRIP, x3);
|
||||
STH(x3, xEmu, offsetof(x64emu_t, segs[_CS]));
|
||||
if(rex.w) {POP2(xRIP, x3);} else {POP2_32(xRIP, x3);}
|
||||
STRH_U12(x3, xEmu, offsetof(x64emu_t, segs[_CS]));
|
||||
if(u16<0x1000)
|
||||
ADDz_U12(xRSP, xRSP, u16);
|
||||
else {
|
||||
MOV32w(x1, u16);
|
||||
ADDz_REG(xRSP, xRSP, x1);
|
||||
}
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
ret_to_next(dyn, ip, ninst, rex);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
break;
|
||||
@@ -2831,9 +2871,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FAR RET");
|
||||
READFLAGS(X_PEND);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
POP2z(xRIP, x3);
|
||||
STH(x3, xEmu, offsetof(x64emu_t, segs[_CS]));
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
if(rex.w) {POP2(xRIP, x3);} else {POP2_32(xRIP, x3);}
|
||||
STRH_U12(x3, xEmu, offsetof(x64emu_t, segs[_CS]));
|
||||
ret_to_next(dyn, ip, ninst, rex);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
break;
|
||||
@@ -2855,7 +2895,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
*ok = 0;
|
||||
*need_epilog = 1;
|
||||
} else {
|
||||
MESSAGE(LOG_DUMP, "Native Call to %s\n", GetBridgeName((void*)ip) ?: GetNativeName(GetNativeFnc(ip)));
|
||||
MESSAGE(LOG_DUMP, "Native Call to %s\n", GetBridgeName((void*)ip) ?: GetNativeName(GetNativeFnc(ip), 1));
|
||||
x87_stackcount(dyn, ninst, x1);
|
||||
x87_forget(dyn, ninst, x3, x4, 0);
|
||||
sse_purge07cache(dyn, ninst, x3);
|
||||
@@ -2896,6 +2936,8 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
LDRx_REG(x3, x1, x2);
|
||||
//LDRx_U12(x3, x1, offsetof(box64context_t, signals[X64_SIGTRAP]));
|
||||
CMPSx_U12(x3, 0);
|
||||
// commit df before branch, CALL_S in int3 path has FORCE_DFNONE
|
||||
CHECK_DFNONE(0);
|
||||
B_MARK(cEQ);
|
||||
GETIP(addr); // update RIP
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
@@ -3015,7 +3057,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("IRET");
|
||||
SETFLAGS(X_ALL, SF_SET_DF); // Not a hack, EFLAGS are restored
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
iret_to_epilog(dyn, ip, ninst, rex.is32bits, rex.w);
|
||||
iret_to_next(dyn, ip, ninst, rex.is32bits, rex.w);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
break;
|
||||
@@ -3544,7 +3586,12 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
|
||||
case 0xD7:
|
||||
INST_NAME("XLAT");
|
||||
UXTBw(x1, xRAX);
|
||||
if(rex.seg) {
|
||||
grab_segdata(dyn, addr, ninst, x1, rex.seg);
|
||||
ADDz_UXTB(x1, x1, xRAX);
|
||||
} else {
|
||||
UXTBw(x1, xRAX);
|
||||
}
|
||||
LDRB_REG(x1, xRBX, x1);
|
||||
BFIx(xRAX, x1, 0, 8);
|
||||
break;
|
||||
@@ -3678,10 +3725,10 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0xE8:
|
||||
INST_NAME("CALL Id");
|
||||
i32 = F32S;
|
||||
i32 = (rex.is32bits && rex.is66)?F16S:F32S;
|
||||
if(addr+i32==0) {
|
||||
#if STEP == 3
|
||||
printf_log(LOG_INFO, "Warning, CALL to 0x0 at %p (%p)\n", (void*)addr, (void*)(addr-1));
|
||||
printf_log(LOG_DEBUG, "Warning, CALL to 0x0 at %p (%p)\n", (void*)addr, (void*)(addr-1));
|
||||
#endif
|
||||
}
|
||||
#if STEP < 2
|
||||
@@ -3715,7 +3762,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
tmp=isSimpleWrapper(*(wrapper_t*)(dyn->insts[ninst].natcall+2));
|
||||
} else
|
||||
tmp=0;
|
||||
MESSAGE(LOG_DUMP, "Native Call to %s (retn=%d, simpleWrapper=%d)\n", GetBridgeName((void*)(dyn->insts[ninst].natcall - 1)) ?: GetNativeName(GetNativeFnc(dyn->insts[ninst].natcall - 1)), dyn->insts[ninst].retn, tmp);
|
||||
MESSAGE(LOG_DUMP, "Native Call to %s (retn=%d, simpleWrapper=%d)\n", GetBridgeName((void*)(dyn->insts[ninst].natcall - 1)) ?: GetNativeName(GetNativeFnc(dyn->insts[ninst].natcall - 1), 1), dyn->insts[ninst].retn, tmp);
|
||||
if(dyn->insts[ninst].natcall && isRetX87Wrapper(*(wrapper_t*)(dyn->insts[ninst].natcall+2)))
|
||||
// return value will be on the stack, so the stack depth needs to be updated
|
||||
x87_purgecache(dyn, ninst, 0, x3, x1, x4);
|
||||
@@ -3778,17 +3825,14 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
// Push actual return address
|
||||
if(addr < (dyn->start+dyn->isize)) {
|
||||
// there is a next...
|
||||
if(BOX64DRENV(dynarec_callret)>1)
|
||||
if(BOX64DRENV(dynarec_callret)>1 && !dyn->always_test)
|
||||
j64 = CALLRET_GETRET();
|
||||
else
|
||||
j64 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->native_size)):0;
|
||||
ADR_S20(x4, j64);
|
||||
MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
|
||||
} else {
|
||||
if(BOX64DRENV(dynarec_callret)>1)
|
||||
j64 = CALLRET_GETRET();
|
||||
else
|
||||
j64 = (dyn->insts)?(GETMARK-(dyn->native_size)):0;
|
||||
j64 = (dyn->insts)?(GETMARK-(dyn->native_size)):0;
|
||||
ADR_S20(x4, j64);
|
||||
MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
|
||||
}
|
||||
@@ -3802,8 +3846,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
else
|
||||
j64 = addr+i32;
|
||||
jump_to_next(dyn, j64, 0, ninst, rex.is32bits);
|
||||
if(BOX64DRENV(dynarec_callret)>1) CALLRET_RET();
|
||||
if (BOX64DRENV(dynarec_callret) && addr >= (dyn->start + dyn->isize)) {
|
||||
int can_continue = (addr < (dyn->start + dyn->isize));
|
||||
CALLRET_RET(can_continue);
|
||||
if (BOX64DRENV(dynarec_callret) && !can_continue) {
|
||||
// jumps out of current dynablock...
|
||||
MARK;
|
||||
j64 = getJumpTableAddress64(addr);
|
||||
@@ -3830,7 +3875,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
if(opcode==0xE9) {
|
||||
INST_NAME("JMP Id");
|
||||
i32 = F32S;
|
||||
i32 = (rex.is32bits && rex.is66)?F16S:F32S;
|
||||
} else {
|
||||
INST_NAME("JMP Ib");
|
||||
i32 = F8S;
|
||||
@@ -3970,7 +4015,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 3:
|
||||
INST_NAME("NEG Eb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETSEB(x1, 0);
|
||||
GETEB(x1, 0);
|
||||
emit_neg8(dyn, ninst, x1, x2, x4);
|
||||
EBBACK;
|
||||
break;
|
||||
@@ -4044,6 +4089,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
UXTHw(x2, xRAX);
|
||||
if(BOX64ENV(dynarec_div0)) {
|
||||
CBNZw_MARK3(ed);
|
||||
MARK2;
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL_S(const_native_div0, -1);
|
||||
@@ -4053,10 +4099,14 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MARK3;
|
||||
}
|
||||
UDIVw(x3, x2, ed);
|
||||
if(BOX64ENV(dynarec_div0)) {
|
||||
SUBw_UXTB(x4, x3, x3);
|
||||
CBNZw_MARK2(x4);
|
||||
}
|
||||
MSUBw(x4, x3, ed, x2); // x4 = x2 mod ed (i.e. x2 - x3*ed)
|
||||
BFIx(xRAX, x3, 0, 8);
|
||||
BFIx(xRAX, x4, 8, 8);
|
||||
SET_DFNONE();
|
||||
FORCE_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);}
|
||||
@@ -4078,6 +4128,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETSEB(x1, 0);
|
||||
if(BOX64ENV(dynarec_div0)) {
|
||||
CBNZw_MARK3(ed);
|
||||
MARK2;
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL_S(const_native_div0, -1);
|
||||
@@ -4088,13 +4139,14 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
SXTHw(x2, xRAX);
|
||||
SDIVw(x3, x2, ed);
|
||||
if(BOX64ENV(dynarec_div0)) {
|
||||
SUBw_SXTB(x4, x3, x3);
|
||||
CBNZw_MARK2(x4);
|
||||
}
|
||||
MSUBw(x4, x3, ed, x2); // x4 = x2 mod ed (i.e. x2 - x3*ed)
|
||||
BFIx(xRAX, x3, 0, 8);
|
||||
BFIx(xRAX, x4, 8, 8);
|
||||
if (!BOX64DRENV(dynarec_safeflags)) {
|
||||
SET_DFNONE();
|
||||
FORCE_DFNONE();
|
||||
}
|
||||
FORCE_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);}
|
||||
@@ -4219,6 +4271,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
if(BOX64ENV(dynarec_div0)) {
|
||||
CBNZx_MARK3(ed);
|
||||
MARK2;
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL_S(const_native_div0, -1);
|
||||
@@ -4234,6 +4287,10 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ed = x4;
|
||||
}
|
||||
UDIVx(x2, x3, ed);
|
||||
if(BOX64ENV(dynarec_div0)) {
|
||||
SUBx_UXTW(x5, x2, x2);
|
||||
CBNZw_MARK2(x5);
|
||||
}
|
||||
MSUBx(x4, x2, ed, xRAX);
|
||||
MOVw_REG(xRAX, x2);
|
||||
MOVw_REG(xRDX, x4);
|
||||
@@ -4280,6 +4337,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOVx_REG(xRAX, x2);
|
||||
}
|
||||
}
|
||||
FORCE_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);}
|
||||
@@ -4302,6 +4360,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETSEDw(0);
|
||||
if(BOX64ENV(dynarec_div0)) {
|
||||
CBNZx_MARK3(wb);
|
||||
MARK2;
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL_S(const_native_div0, -1);
|
||||
@@ -4313,6 +4372,10 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOVw_REG(x3, xRAX);
|
||||
ORRx_REG_LSL(x3, x3, xRDX, 32);
|
||||
SDIVx(x2, x3, wb);
|
||||
if(BOX64ENV(dynarec_div0)) {
|
||||
SUBx_SXTW(x5, x2, x2);
|
||||
CBNZw_MARK2(x5);
|
||||
}
|
||||
MSUBx(x4, x2, wb, x3);
|
||||
MOVw_REG(xRAX, x2);
|
||||
MOVw_REG(xRDX, x4);
|
||||
@@ -4324,6 +4387,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETED(0);
|
||||
if(BOX64ENV(dynarec_div0)) {
|
||||
CBNZx_MARK3(ed);
|
||||
MARK2;
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL_S(const_native_div0, -1);
|
||||
@@ -4333,10 +4397,11 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MARK3;
|
||||
}
|
||||
SDIVx(x2, xRAX, ed);
|
||||
// there is no easy way to check for overflow here
|
||||
MSUBx(xRDX, x2, ed, xRAX);
|
||||
MOVx_REG(xRAX, x2);
|
||||
} else {
|
||||
GETEDH(x1, 0); // get edd changed addr, so cannot be called 2 times for same op...
|
||||
GETEDH(x1, 0); // get ed changed addr, so cannot be called 2 times for same op...
|
||||
if(BOX64ENV(dynarec_div0)) {
|
||||
CBNZx_MARK3(ed);
|
||||
GETIP_(ip);
|
||||
@@ -4349,26 +4414,19 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
//Need to see if RDX==0 and RAX not signed
|
||||
// or RDX==-1 and RAX signed
|
||||
CBNZx_MARK2(xRDX);
|
||||
TBZ_MARK(xRAX, 63);
|
||||
MARK2;
|
||||
MVNx_REG(x2, xRDX);
|
||||
CBNZx_MARK3(x2);
|
||||
TBNZ_MARK(xRAX, 63);
|
||||
MARK3;
|
||||
SUBx_REG_ASR(x2, xRDX, xRAX, 63);
|
||||
CBZx_MARK(x2);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
CALL(const_idiv64, -1);
|
||||
B_NEXT_nocond;
|
||||
B_NEXT_nocond; // flags are done, so can jump to next directly
|
||||
MARK;
|
||||
SDIVx(x2, xRAX, ed);
|
||||
// no easy way to get overflow it seems
|
||||
MSUBx(xRDX, x2, ed, xRAX);
|
||||
MOVx_REG(xRAX, x2);
|
||||
}
|
||||
}
|
||||
if (!BOX64DRENV(dynarec_safeflags)) {
|
||||
SET_DFNONE();
|
||||
FORCE_DFNONE();
|
||||
}
|
||||
FORCE_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);}
|
||||
@@ -4475,7 +4533,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
// Push actual return address
|
||||
if(addr < (dyn->start+dyn->isize)) {
|
||||
// there is a next...
|
||||
if(BOX64DRENV(dynarec_callret)>1)
|
||||
if(BOX64DRENV(dynarec_callret)>1 && !dyn->always_test)
|
||||
j64 = CALLRET_GETRET();
|
||||
else
|
||||
j64 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->native_size)):0;
|
||||
@@ -4490,8 +4548,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
PUSH1z(xRIP);
|
||||
jump_to_next(dyn, 0, ed, ninst, rex.is32bits);
|
||||
if(BOX64DRENV(dynarec_callret)>1) CALLRET_RET();
|
||||
if (BOX64DRENV(dynarec_callret) && addr >= (dyn->start + dyn->isize)) {
|
||||
int can_continue = (addr < (dyn->start + dyn->isize));
|
||||
CALLRET_RET(can_continue);
|
||||
if (BOX64DRENV(dynarec_callret) && !can_continue) {
|
||||
// jumps out of current dynablock...
|
||||
MARK;
|
||||
j64 = getJumpTableAddress64(addr);
|
||||
@@ -4514,15 +4573,51 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
LDxw(x1, wback, 0);
|
||||
ed = x1;
|
||||
LDH(x3, wback, rex.w?8:4);
|
||||
LDH(x4, xEmu, offsetof(x64emu_t, segs[_CS]));
|
||||
LDH(x5, xEmu, offsetof(x64emu_t, segs[_CS]));
|
||||
if (BOX64DRENV(dynarec_callret) && BOX64DRENV(dynarec_bigblock) > 1) {
|
||||
BARRIER(BARRIER_FULL);
|
||||
} else {
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
}
|
||||
GETIP_(addr);
|
||||
// not doing callret because call far will exit the dynablock anyway, to be sure to recompute CS segment
|
||||
PUSH1z(x4);
|
||||
PUSH1z(xRIP);
|
||||
int can_continue = (addr < (dyn->start + dyn->isize));
|
||||
if (BOX64DRENV(dynarec_callret)) {
|
||||
SET_HASCALLRET();
|
||||
// Push actual return address. Note that CS will not be tested, but that should be ok?
|
||||
if(can_continue) {
|
||||
// there is a next...
|
||||
if(BOX64DRENV(dynarec_callret)>1 && !dyn->always_test)
|
||||
j64 = CALLRET_GETRET();
|
||||
else
|
||||
j64 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->native_size)):0;
|
||||
ADR_S20(x4, j64);
|
||||
MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
|
||||
} else {
|
||||
if(BOX64DRENV(dynarec_callret)>1 && !dyn->always_test)
|
||||
j64 = CALLRET_GETRET();
|
||||
else
|
||||
j64 = (dyn->insts)?(GETMARK-(dyn->native_size)):0;
|
||||
ADR_S20(x4, j64);
|
||||
MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
|
||||
}
|
||||
STPx_S7_preindex(x4, xRIP, xSP, -16);
|
||||
}
|
||||
if (rex.w) PUSH2(x5, xRIP); else PUSH2_32(x5, xRIP);
|
||||
STH(x3, xEmu, offsetof(x64emu_t, segs[_CS]));
|
||||
jump_to_epilog(dyn, 0, ed, ninst);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
jump_to_next(dyn, 0, ed, ninst, rex.is32bits);
|
||||
CALLRET_RET(can_continue);
|
||||
if (BOX64DRENV(dynarec_callret) && !can_continue) {
|
||||
// jumps out of current dynablock...
|
||||
MARK;
|
||||
j64 = getJumpTableAddress64(addr);
|
||||
if(dyn->need_reloc) AddRelocTable64RetEndBlock(dyn, ninst, addr, STEP);
|
||||
TABLE64_(x4, j64);
|
||||
LDRx_U12(x4, x4, 0);
|
||||
BR(x4);
|
||||
}
|
||||
CLEARIP();
|
||||
}
|
||||
break;
|
||||
case 4: // JMP Ed
|
||||
@@ -4547,7 +4642,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ed = x1;
|
||||
LDH(x3, wback, rex.w?8:4);
|
||||
STH(x3, xEmu, offsetof(x64emu_t, segs[_CS]));
|
||||
jump_to_epilog(dyn, 0, ed, ninst);
|
||||
jump_to_next(dyn, 0, ed, ninst, rex.w?0:1);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
uint8_t eb1, eb2, gb1, gb2;
|
||||
int32_t i32, i32_;
|
||||
int cacheupd = 0;
|
||||
int v0, v1;
|
||||
int v0, v1, v2;
|
||||
int q0, q1;
|
||||
int d0, d1;
|
||||
int s0;
|
||||
@@ -60,24 +60,20 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
|
||||
switch(opcode) {
|
||||
case 0x00:
|
||||
if(rex.is32bits) {
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("SLDT EW");
|
||||
if(MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
MOV32w(ed, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
STRH_U12(xZR, wback, 0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
} else {
|
||||
DEFAULT;
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("SLDT EW");
|
||||
if(MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
MOV32w(ed, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
STRH_U12(xZR, wback, 0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0x01:
|
||||
@@ -318,12 +314,12 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0x13:
|
||||
nextop = F8;
|
||||
INST_NAME("MOVLPS Ex, Gx");
|
||||
GETGX(v0, 0);
|
||||
if(MODREG) {
|
||||
DEFAULT;
|
||||
return addr;
|
||||
INST_NAME("Illegal 0F 13");
|
||||
UDF(0);
|
||||
} else {
|
||||
INST_NAME("MOVLPS Ex, Gx");
|
||||
GETGX(v0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
VST1_64(v0, 0, ed); // better to use VST1 than VSTR_64, to avoid NEON->VFPU transfert I assume
|
||||
SMWRITE2();
|
||||
@@ -426,7 +422,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETIP(ip);
|
||||
u8 = (rex.r*8)+(nextop>>3&7);
|
||||
if((((opcode==0x20) || (opcode==0x22)) && ((u8==1) || (u8==5) || (u8==6) || (u8==7) || (u8>8))) || (((opcode==0x21) || (opcode==0x23) && rex.r))) {
|
||||
if((((opcode==0x20) || (opcode==0x22)) && ((u8==1) || (u8==5) || (u8==6) || (u8==7) || (u8>8))) || (((opcode==0x21) || (opcode==0x23)) && rex.r)) {
|
||||
INST_NAME("Illegal 0F 20..23");
|
||||
UDF(0);
|
||||
} else {
|
||||
@@ -483,13 +479,14 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VMOVeD(v0, 0, d0, 0);
|
||||
break;
|
||||
case 0x2B:
|
||||
INST_NAME("MOVNTPS Ex,Gx");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if(MODREG) {
|
||||
DEFAULT;
|
||||
INST_NAME("Illegal 0F 2B");
|
||||
UDF(0);
|
||||
} else {
|
||||
INST_NAME("MOVNTPS Ex,Gx");
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VST128(v0, ed, fixedaddress);
|
||||
}
|
||||
@@ -507,12 +504,11 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VFCVTZSS(q0, q0);
|
||||
} else {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
ORRw_mask(x2, xZR, 1, 0); //0x80000000
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
for (int i=0; i<2; ++i) {
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
if (i) {
|
||||
VMOVeS(d0, 0, v1, i);
|
||||
FRINTZS(d0, d0);
|
||||
@@ -545,12 +541,11 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VFCVTZSS(q0, q0);
|
||||
} else {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
ORRw_mask(x2, xZR, 1, 0); //0x80000000
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
for (int i=0; i<2; ++i) {
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
if (i) {
|
||||
VMOVeS(d0, 0, v1, i);
|
||||
FRINTIS(d0, d0);
|
||||
@@ -575,10 +570,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
GETEXSS(s0, 0, 0);
|
||||
IFX(X_CF|X_PF|X_ZF) {
|
||||
FCMPS(v0, s0);
|
||||
}
|
||||
FCOMI(x1, x2);
|
||||
FCOMIS(x1, x2, v0, s0);
|
||||
break;
|
||||
case 0x30:
|
||||
INST_NAME("WRMSR");
|
||||
@@ -844,6 +836,12 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
} else
|
||||
v1 = q1;
|
||||
if(q0==d0) {
|
||||
// move away q0 as it would be overwritten else
|
||||
int tmp = fpu_get_scratch(dyn, ninst);
|
||||
VMOVQ(tmp, d0);
|
||||
d0 = tmp;
|
||||
}
|
||||
VREV64Q_32(q0, q0);
|
||||
if(q0==q1) {
|
||||
VMOVQ(v1, q0);
|
||||
@@ -1221,6 +1219,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
VMOVQ(v2, q1); // save original src1 (Gx)
|
||||
// check if any input value was NAN
|
||||
VFMAXQS(v0, q0, q1); // propagate NAN
|
||||
VFCMEQQS(v0, v0, v0); // 0 if NAN, 1 if not NAN
|
||||
@@ -1231,6 +1231,10 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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
|
||||
VFCMEQQS(v0, v2, v2); // 0 if src1 was NaN
|
||||
MOVIQ_32_lsl(v1, 0x40, 2); // QNaN bit
|
||||
VORRQ(v2, v2, v1); // quiet any SNaN in saved src1
|
||||
VBIFQ(q1, v2, v0); // where src1 was NaN, use QNaN(src1)
|
||||
}
|
||||
break;
|
||||
case 0x59:
|
||||
@@ -1241,6 +1245,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
VMOVQ(v2, q1); // save original src1 (Gx)
|
||||
// check if any input value was NAN
|
||||
VFMAXQS(v0, q0, q1); // propagate NAN
|
||||
VFCMEQQS(v0, v0, v0); // 0 if NAN, 1 if not NAN
|
||||
@@ -1251,6 +1257,10 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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
|
||||
VFCMEQQS(v0, v2, v2); // 0 if src1 was NaN
|
||||
MOVIQ_32_lsl(v1, 0x40, 2); // QNaN bit
|
||||
VORRQ(v2, v2, v1); // quiet any SNaN in saved src1
|
||||
VBIFQ(q1, v2, v0); // where src1 was NaN, use QNaN(src1)
|
||||
}
|
||||
break;
|
||||
case 0x5A:
|
||||
@@ -1275,6 +1285,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
VMOVQ(v2, q1); // save original src1 (Gx)
|
||||
// check if any input value was NAN
|
||||
VFMAXQS(v0, q0, q1); // propagate NAN
|
||||
VFCMEQQS(v0, v0, v0); // 0 if NAN, 1 if not NAN
|
||||
@@ -1285,6 +1297,10 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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
|
||||
VFCMEQQS(v0, v2, v2); // 0 if src1 was NaN
|
||||
MOVIQ_32_lsl(v1, 0x40, 2); // QNaN bit
|
||||
VORRQ(v2, v2, v1); // quiet any SNaN in saved src1
|
||||
VBIFQ(q1, v2, v0); // where src1 was NaN, use QNaN(src1)
|
||||
}
|
||||
break;
|
||||
case 0x5D:
|
||||
@@ -1306,6 +1322,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
VMOVQ(v2, q1); // save original src1 (Gx)
|
||||
// check if any input value was NAN
|
||||
VFMAXQS(v0, q0, q1); // propagate NAN
|
||||
VFCMEQQS(v0, v0, v0); // 0 if NAN, 1 if not NAN
|
||||
@@ -1316,6 +1334,10 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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
|
||||
VFCMEQQS(v0, v2, v2); // 0 if src1 was NaN
|
||||
MOVIQ_32_lsl(v1, 0x40, 2); // QNaN bit
|
||||
VORRQ(v2, v2, v1); // quiet any SNaN in saved src1
|
||||
VBIFQ(q1, v2, v0); // where src1 was NaN, use QNaN(src1)
|
||||
}
|
||||
break;
|
||||
case 0x5F:
|
||||
@@ -1679,6 +1701,11 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("EMMS");
|
||||
// empty MMX, FPU now usable
|
||||
mmx_purgecache(dyn, ninst, 0, x1);
|
||||
x87_purgecache(dyn, ninst, 1, x1, x2, x3); // also purge x87 and hard reset it
|
||||
STRw_U12(xZR, xEmu, offsetof(x64emu_t, top));
|
||||
STRw_U12(xZR, xEmu, offsetof(x64emu_t, fpu_stack));
|
||||
MOV64x(x1, TAGS_EMPTY);
|
||||
STRx_U12(x1, xEmu, offsetof(x64emu_t, fpu_tags));
|
||||
/*emu->top = 0;
|
||||
emu->fpu_stack = 0;*/ //TODO: Check if something is needed here?
|
||||
break;
|
||||
@@ -1794,7 +1821,6 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
NOTEST(x1);
|
||||
GETIP(ip); // sync RIP for easier debugging
|
||||
STRx_U12(xRIP, xEmu, offsetof(x64emu_t, ip));
|
||||
MOVx_REG(x1, xRAX);
|
||||
CALL_(const_cpuid, -1, 0);
|
||||
break;
|
||||
case 0xA3:
|
||||
@@ -1960,15 +1986,15 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
switch (nextop) {
|
||||
case 0xE8:
|
||||
INST_NAME("LFENCE");
|
||||
SMDMB();
|
||||
DMB_LD();
|
||||
break;
|
||||
case 0xF0:
|
||||
INST_NAME("MFENCE");
|
||||
SMDMB();
|
||||
DMB_SY();
|
||||
break;
|
||||
case 0xF8:
|
||||
INST_NAME("SFENCE");
|
||||
SMDMB();
|
||||
DMB_ST();
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
@@ -2145,9 +2171,9 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
CMPSxw_REG(xRAX, ed);
|
||||
}
|
||||
MOVxw_REG(x1, ed); // save value
|
||||
Bcond(cNE, 4 + (rex.w ? 4 : 8));
|
||||
Bcond(cNE, 4 + 8);
|
||||
MOVxw_REG(ed, gd);
|
||||
if (!rex.w) { B_NEXT_nocond; }
|
||||
B_NEXT_nocond;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 0);
|
||||
LDxw(x1, wback, fixedaddress);
|
||||
@@ -2401,10 +2427,18 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
GETGD;
|
||||
if (BOX64DRENV(dynarec_safeflags) && !BOX64ENV(cputype)) {
|
||||
IFX(X_PF)
|
||||
MOV32w(x3, 0); // PF uses 0 when the source is zero
|
||||
}
|
||||
TSTxw_REG(ed, ed);
|
||||
B_MARK(cEQ);
|
||||
RBITxw(x1, ed); // reverse
|
||||
CLZxw(gd, x1); // x2 gets leading 0 == BSF
|
||||
RBITxw(gd, ed); // reverse
|
||||
CLZxw(gd, gd); // gd gets leading 0 == BSF
|
||||
if (BOX64DRENV(dynarec_safeflags) && !BOX64ENV(cputype)) {
|
||||
IFX(X_PF)
|
||||
MOVxw_REG(x3, gd);
|
||||
}
|
||||
MARK;
|
||||
IFX(X_ZF) {
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
@@ -2417,7 +2451,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
IFX(X_AF) BFCw(xFlags, F_AF, 1);
|
||||
IFX(X_SF) BFCw(xFlags, F_SF, 1);
|
||||
IFX(X_OF) BFCw(xFlags, F_OF, 1);
|
||||
IFX(X_PF) emit_pf(dyn, ninst, gd, x2);
|
||||
IFX(X_PF) emit_pf(dyn, ninst, x3, x2);
|
||||
}
|
||||
break;
|
||||
case 0xBD:
|
||||
@@ -2431,11 +2465,19 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
GETGD;
|
||||
if (BOX64DRENV(dynarec_safeflags) && !BOX64ENV(cputype)) {
|
||||
IFX(X_PF)
|
||||
MOV32w(x3, 0); // PF uses 0 when the source is zero
|
||||
}
|
||||
TSTxw_REG(ed, ed);
|
||||
B_MARK(cEQ);
|
||||
CLZxw(gd, ed); // x2 gets leading 0
|
||||
CLZxw(gd, ed); // gd gets leading 0
|
||||
SUBxw_U12(gd, gd, rex.w?63:31);
|
||||
NEGxw_REG(gd, gd); // complement
|
||||
if (BOX64DRENV(dynarec_safeflags) && !BOX64ENV(cputype)) {
|
||||
IFX(X_PF)
|
||||
MOVxw_REG(x3, gd);
|
||||
}
|
||||
MARK;
|
||||
IFX(X_ZF) {
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
@@ -2448,7 +2490,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
IFX(X_AF) BFCw(xFlags, F_AF, 1);
|
||||
IFX(X_SF) BFCw(xFlags, F_SF, 1);
|
||||
IFX(X_OF) BFCw(xFlags, F_OF, 1);
|
||||
IFX(X_PF) emit_pf(dyn, ninst, gd, x2);
|
||||
IFX(X_PF) emit_pf(dyn, ninst, x3, x2);
|
||||
}
|
||||
break;
|
||||
case 0xBE:
|
||||
@@ -2485,7 +2527,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
break;
|
||||
case 0xC0:
|
||||
INST_NAME("XADD Gb, Eb");
|
||||
INST_NAME("XADD Eb, Gb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGB(x1);
|
||||
@@ -2496,16 +2538,15 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
EBBACK; // eb gets x1 (sum)
|
||||
break;
|
||||
case 0xC1:
|
||||
INST_NAME("XADD Gd, Ed");
|
||||
INST_NAME("XADD Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED(0);
|
||||
MOVxw_REG(x3, ed);
|
||||
MOVxw_REG(ed, gd);
|
||||
MOVxw_REG(gd, x3);
|
||||
if (ed != gd) MOVx_REG(x3, ed);
|
||||
emit_add32(dyn, ninst, rex, ed, gd, x4, x5);
|
||||
WBACK;
|
||||
if (ed != gd) MOVxw_REG(gd, x3);
|
||||
break;
|
||||
case 0xC2:
|
||||
INST_NAME("CMPPS Gx, Ex, Ib");
|
||||
@@ -2657,7 +2698,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else switch((nextop>>3)&7) {
|
||||
case 1:
|
||||
if(MODREG) {
|
||||
INST_NAME("Invalid LOCK");
|
||||
INST_NAME("Invalid C7");
|
||||
UDF(0);
|
||||
*need_epilog = 1;
|
||||
*ok = 0;
|
||||
@@ -2672,6 +2713,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(rex.w && BOX64DRENV(dynarec_safeflags)>1) {
|
||||
// unaligned memory cause a GPF
|
||||
// commit df before branch, CALL_S in GPF path has FORCE_DFNONE
|
||||
CHECK_DFNONE(0);
|
||||
TSTx_mask(wback, 1, 0, 3);
|
||||
B_MARK2(cEQ); // alligned, continue...
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
@@ -2710,25 +2753,6 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETIP(ip);
|
||||
UDF(0);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("RDRAND Ed");
|
||||
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);
|
||||
}
|
||||
if(cpuext.rndr) {
|
||||
MRS_rndr(x1);
|
||||
IFX(X_CF) { CSETw(x3, cNE); }
|
||||
} else {
|
||||
CALL(rex.w?const_random64:const_random32, x1);
|
||||
IFX(X_CF) { MOV32w(x3, 1); }
|
||||
}
|
||||
IFX(X_CF) { BFIw(xFlags, x3, F_CF, 1); }
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 0);
|
||||
STxw(x1, wback, fixedaddress);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
|
||||
@@ -144,6 +144,8 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
emit_adc16(dyn, ninst, x1, x2, x4, x3);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x14:
|
||||
return dynarec64_00(dyn, addr-1, ip, ninst, rex, ok, need_epilog);
|
||||
case 0x15:
|
||||
INST_NAME("ADC AX, Iw");
|
||||
READFLAGS(X_CF);
|
||||
@@ -407,8 +409,12 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0x68:
|
||||
INST_NAME("PUSH Iw");
|
||||
u16 = F16;
|
||||
MOV32w(x2, u16);
|
||||
PUSH1_16(x2);
|
||||
if (!u16) {
|
||||
PUSH1_16(xZR);
|
||||
} else {
|
||||
MOV32w(x2, u16);
|
||||
PUSH1_16(x2);
|
||||
}
|
||||
break;
|
||||
case 0x69:
|
||||
case 0x6B:
|
||||
@@ -452,8 +458,12 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0x6A:
|
||||
INST_NAME("PUSH Ib");
|
||||
i16 = F8S;
|
||||
MOV32w(x2, (uint16_t)i16);
|
||||
PUSH1_16(x2);
|
||||
if (!i16) {
|
||||
PUSH1_16(xZR);
|
||||
} else {
|
||||
MOV32w(x2, (uint16_t)i16);
|
||||
PUSH1_16(x2);
|
||||
}
|
||||
break;
|
||||
case 0x6C:
|
||||
case 0x6E:
|
||||
@@ -788,6 +798,9 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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
|
||||
LDRw_U12(x4, xEmu, offsetof(x64emu_t, flags));
|
||||
ORRw_mask(x4, x4, 32-FLAGS_NO_TF, 0); //mask=1<<FLAGS_NO_TF
|
||||
STRw_U12(x4, xEmu, offsetof(x64emu_t, flags));
|
||||
jump_to_epilog(dyn, addr, 0, ninst);
|
||||
}
|
||||
break;
|
||||
@@ -802,7 +815,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
u64 = F64;
|
||||
unscaled = 0; fixedaddress = 0;
|
||||
if(rex.seg && (u64<0x1000 || (int64_t)u64>-0x1000 || (u64<(0x1000<<1) && !(u64&1)))) {
|
||||
grab_segdata(dyn, addr, ninst, x1, rex.seg, 0);
|
||||
grab_segdata(dyn, addr, ninst, x1, rex.seg);
|
||||
if(u64) {
|
||||
if(u64<0x100)
|
||||
{fixedaddress = u64; unscaled = 1;}
|
||||
@@ -818,7 +831,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
MOV64y(x1, u64);
|
||||
if(rex.seg) {
|
||||
grab_segdata(dyn, addr, ninst, x3, rex.seg, 0);
|
||||
grab_segdata(dyn, addr, ninst, x3, rex.seg);
|
||||
ADDx_REGy(x1, x3, x1);
|
||||
}
|
||||
}
|
||||
@@ -838,7 +851,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
u64 = F64;
|
||||
unscaled = 0; fixedaddress = 0;
|
||||
if(rex.seg && (u64<0x1000 || (int64_t)u64>-0x1000 || (u64<(0x1000<<1) && !(u64&1)))) {
|
||||
grab_segdata(dyn, addr, ninst, x1, rex.seg, 0);
|
||||
grab_segdata(dyn, addr, ninst, x1, rex.seg);
|
||||
if(u64) {
|
||||
if(u64<0x100)
|
||||
{fixedaddress = u64; unscaled = 1;}
|
||||
@@ -854,7 +867,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
MOV64y(x1, u64);
|
||||
if(rex.seg) {
|
||||
grab_segdata(dyn, addr, ninst, x3, rex.seg, 0);
|
||||
grab_segdata(dyn, addr, ninst, x3, rex.seg);
|
||||
ADDx_REGy(x1, x3, x1);
|
||||
}
|
||||
}
|
||||
@@ -1345,7 +1358,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
MARK;
|
||||
IFX2(X_OF, && BOX64ENV(cputype)) {
|
||||
EORw_REG_LSR(x2, xFlags, ed, 7);
|
||||
EORw_REG_LSR(x2, xFlags, ed, 15);
|
||||
BFIw(xFlags, x2, F_OF, 1);
|
||||
}
|
||||
break;
|
||||
@@ -1489,7 +1502,10 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0xE6: /* OUT Ib, AL */
|
||||
case 0xE7: /* OUT Ib, AX */
|
||||
return dynarec64_00(dyn, addr-1, ip, ninst, rex, ok, need_epilog);
|
||||
|
||||
case 0xE8: /* CALL Imm */
|
||||
case 0xE9: /* Jmp Imm */
|
||||
case 0xEB: /* Jmp Imm8 */
|
||||
return dynarec64_00(dyn, addr-1, ip, ninst, rex, ok, need_epilog);
|
||||
case 0xEC: /* IN AL, DX */
|
||||
case 0xED: /* IN AX, DX */
|
||||
case 0xEE: /* OUT DX, AL */
|
||||
@@ -1596,7 +1612,10 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
UXTHw(x2, xRAX);
|
||||
BFIw(x2, xRDX, 16, 16);
|
||||
if(BOX64ENV(dynarec_div0)) {
|
||||
// commit df before branch, CALL_S in div0 path has FORCE_DFNONE
|
||||
CHECK_DFNONE(0);
|
||||
CBNZw_MARK3(ed);
|
||||
MARK2;
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL_S(const_native_div0, -1);
|
||||
@@ -1606,6 +1625,10 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MARK3;
|
||||
}
|
||||
UDIVw(x3, x2, ed);
|
||||
if(BOX64ENV(dynarec_div0)) {
|
||||
SUBw_UXTH(x5, x3, x3);
|
||||
CBNZw_MARK2(x5);
|
||||
}
|
||||
MSUBw(x4, x3, ed, x2); // x4 = x2 mod ed (i.e. x2 - x3*ed)
|
||||
BFIz(xRAX, x3, 0, 16);
|
||||
BFIz(xRDX, x4, 0, 16);
|
||||
@@ -1630,7 +1653,10 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
GETSEW(x1, 0);
|
||||
if(BOX64ENV(dynarec_div0)) {
|
||||
// commit df before branch, CALL_S in div0 path has FORCE_DFNONE
|
||||
CHECK_DFNONE(0);
|
||||
CBNZw_MARK3(ed);
|
||||
MARK2;
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL_S(const_native_div0, -1);
|
||||
@@ -1642,6 +1668,10 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
UXTHw(x2, xRAX);
|
||||
BFIw(x2, xRDX, 16, 16);
|
||||
SDIVw(x3, x2, ed);
|
||||
if(BOX64ENV(dynarec_div0)) {
|
||||
SUBw_SXTH(x5, x3, x3);
|
||||
CBNZw_MARK2(x5);
|
||||
}
|
||||
MSUBw(x4, x3, ed, x2); // x4 = x2 mod ed (i.e. x2 - x3*ed)
|
||||
BFIz(xRAX, x3, 0, 16);
|
||||
BFIz(xRDX, x4, 0, 16);
|
||||
|
||||
@@ -32,7 +32,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
int64_t j64;
|
||||
uint64_t tmp64u, tmp64u2;
|
||||
int mask;
|
||||
int v0, v1;
|
||||
int v0, v1, v2;
|
||||
int q0, q1;
|
||||
int d0, d1;
|
||||
int64_t fixedaddress;
|
||||
@@ -240,12 +240,11 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
SQXTN_32(q0, q0);
|
||||
} else {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
ORRw_mask(x2, xZR, 1, 0); //0x80000000
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
for (int i=0; i<2; ++i) {
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
if (i) {
|
||||
VMOVeD(d0, 0, v1, i);
|
||||
FRINTZD(d0, d0);
|
||||
@@ -280,12 +279,11 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
SQXTN_32(q0, q0);
|
||||
} else {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
ORRw_mask(x2, xZR, 1, 0); //0x80000000
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
for (int i=0; i<2; ++i) {
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
if (i) {
|
||||
VMOVeD(d0, 0, v1, i);
|
||||
FRINTID(d0, d0);
|
||||
@@ -310,10 +308,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
GETEXSD(q0, 0, 0);
|
||||
IFX(X_CF|X_PF|X_ZF) {
|
||||
FCMPD(v0, q0);
|
||||
}
|
||||
FCOMI(x1, x2);
|
||||
FCOMID(x1, x2, v0, q0);
|
||||
break;
|
||||
|
||||
case 0x38: // SSSE3 opcodes
|
||||
@@ -768,6 +763,26 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(q0, 1);
|
||||
VMULQ_32(q0, q0, q1);
|
||||
break;
|
||||
case 0x41:
|
||||
INST_NAME("PHMINPOSUW Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(v1, 0, 0);
|
||||
GETGX_empty(v0);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
// get the min value
|
||||
UMINVQ_16(q0, v1); //q0.uw[0] = min value
|
||||
VDUPQ_16(q1, q0, 0); // vector of min value
|
||||
VCMEQQ_16(q1, q1, v1); // bit field of the element that are the min value
|
||||
UQXTN_8(q1, q1); // same bit field, but on 8bits elements only, easier to handle
|
||||
VMOVQDto(x1, q1, 0); // grab the bit field as a 64bits value
|
||||
VEORQ(v0, v0, v0); // RAZ everything
|
||||
RBITx(x1, x1); // reverse, we want trailling zero but can only count leading ones
|
||||
CLZx(x1, x1);
|
||||
VMOVeH(v0, 0, q0, 0); // set up min
|
||||
LSRw(x1, x1, 3); // divide by 8, that's our index...
|
||||
VMOVQHfrom(v0, 1, x1);
|
||||
break;
|
||||
|
||||
case 0xDB:
|
||||
INST_NAME("AESIMC Gx, Ex"); // AES-NI
|
||||
@@ -1708,6 +1723,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
VMOVQ(v2, q1); // save original src1 (Gx)
|
||||
// check if any input value was NAN
|
||||
VFMAXQD(v0, q0, q1); // propagate NAN
|
||||
VFCMEQQD(v0, v0, v0); // 0 if NAN, 1 if not NAN
|
||||
@@ -1718,6 +1735,11 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VBICQ(v1, v0, v1); // forget it in any input was a NAN already
|
||||
VSHLQ_64(v1, v1, 63); // only keep the sign bit
|
||||
VORRQ(q1, q1, v1); // NAN -> -NAN
|
||||
VFCMEQQD(v0, v2, v2); // 0 if src1 was NaN
|
||||
MOV64x(x5, 0x0008000000000000ULL);
|
||||
VDUPQD(v1, x5); // QNaN bit
|
||||
VORRQ(v2, v2, v1); // quiet any SNaN in saved src1
|
||||
VBIFQ(q1, v2, v0); // where src1 was NaN, use QNaN(src1)
|
||||
}
|
||||
break;
|
||||
case 0x59:
|
||||
@@ -1728,6 +1750,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
VMOVQ(v2, q1); // save original src1 (Gx)
|
||||
// check if any input value was NAN
|
||||
VFMAXQD(v0, q0, q1); // propagate NAN
|
||||
VFCMEQQD(v0, v0, v0); // 0 if NAN, 1 if not NAN
|
||||
@@ -1738,6 +1762,11 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VBICQ(v1, v0, v1); // forget it in any input was a NAN already
|
||||
VSHLQ_64(v1, v1, 63); // only keep the sign bit
|
||||
VORRQ(q1, q1, v1); // NAN -> -NAN
|
||||
VFCMEQQD(v0, v2, v2); // 0 if src1 was NaN
|
||||
MOV64x(x5, 0x0008000000000000ULL);
|
||||
VDUPQD(v1, x5); // QNaN bit
|
||||
VORRQ(v2, v2, v1); // quiet any SNaN in saved src1
|
||||
VBIFQ(q1, v2, v0); // where src1 was NaN, use QNaN(src1)
|
||||
}
|
||||
break;
|
||||
case 0x5A:
|
||||
@@ -1800,6 +1829,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
VMOVQ(v2, q1); // save original src1 (Gx)
|
||||
// check if any input value was NAN
|
||||
VFMAXQD(v0, q0, q1); // propagate NAN
|
||||
VFCMEQQD(v0, v0, v0); // 0 if NAN, 1 if not NAN
|
||||
@@ -1810,6 +1841,11 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VBICQ(v1, v0, v1); // forget it in any input was a NAN already
|
||||
VSHLQ_64(v1, v1, 63); // only keep the sign bit
|
||||
VORRQ(q1, q1, v1); // NAN -> -NAN
|
||||
VFCMEQQD(v0, v2, v2); // 0 if src1 was NaN
|
||||
MOV64x(x5, 0x0008000000000000ULL);
|
||||
VDUPQD(v1, x5); // QNaN bit
|
||||
VORRQ(v2, v2, v1); // quiet any SNaN in saved src1
|
||||
VBIFQ(q1, v2, v0); // where src1 was NaN, use QNaN(src1)
|
||||
}
|
||||
break;
|
||||
case 0x5D:
|
||||
@@ -1831,6 +1867,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
VMOVQ(v2, q1); // save original src1 (Gx)
|
||||
// check if any input value was NAN
|
||||
VFMAXQD(v0, q0, q1); // propagate NAN
|
||||
VFCMEQQD(v0, v0, v0); // 0 if NAN, 1 if not NAN
|
||||
@@ -1841,6 +1879,11 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VBICQ(v1, v0, v1); // forget it in any input was a NAN already
|
||||
VSHLQ_64(v1, v1, 63); // only keep the sign bit
|
||||
VORRQ(q1, q1, v1); // NAN -> -NAN
|
||||
VFCMEQQD(v0, v2, v2); // 0 if src1 was NaN
|
||||
MOV64x(x5, 0x0008000000000000ULL);
|
||||
VDUPQD(v1, x5); // QNaN bit
|
||||
VORRQ(v2, v2, v1); // quiet any SNaN in saved src1
|
||||
VBIFQ(q1, v2, v0); // where src1 was NaN, use QNaN(src1)
|
||||
}
|
||||
break;
|
||||
case 0x5F:
|
||||
@@ -2304,13 +2347,23 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
VFMAXPQD(v0, q1, q0); // propagate NAN
|
||||
VFCMEQQD(v0, v0, v0); // 0 if NAN, 1 if not NAN
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
VUZP1Q_64(d1, q1, q0); // d1 = {q1[0], q0[0]}
|
||||
VFCMEQQD(v0, q1, q1); // per-element non-NaN for Gx
|
||||
VFCMEQQD(d0, q0, q0); // per-element non-NaN for Ex
|
||||
VUZP1Q_64(v1, v0, d0); // first element of each pair
|
||||
VUZP2Q_64(v0, v0, d0); // second element of each pair
|
||||
VANDQ(v0, v1, v0); // both non-NaN per pair
|
||||
}
|
||||
VFADDPQD(q1, q1, q0);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
VFCMEQQD(v1, q1, q1); // 0 => out is NAN
|
||||
MOV64x(x5, 0x0008000000000000ULL);
|
||||
VFCMEQQD(v1, d1, d1); // v1 = src1 non-NaN mask
|
||||
VDUPQD(d0, x5); // d0 = QNaN bit for double
|
||||
VORRQ(d0, d1, d0); // d0 = QNaN(src1)
|
||||
VBIFQ(q1, d0, v1); // where src1 NaN: replace with QNaN(src1)
|
||||
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
|
||||
VORRQ(q1, q1, v1); // NAN -> -NAN
|
||||
@@ -2322,18 +2375,26 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETEX(q1, 0, 0);
|
||||
GETGX(q0, 1);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
VUZP1Q_64(v0, q0, q1);
|
||||
VUZP2Q_64(q0, q0, q1);
|
||||
VUZP1Q_64(v0, q0, q1); // v0 = src1 (first of each pair)
|
||||
VUZP2Q_64(q0, q0, q1); // q0 = src2 (second of each pair)
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
VFMAXQD(v1, v0, q0); // propagate NAN
|
||||
VFCMEQQD(v1, v1, v1); // 0 if NAN, 1 if not NAN
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
VMOVQ(d1, v0); // save src1
|
||||
VFCMEQQD(v1, v0, v0); // even elements non-NaN
|
||||
VFCMEQQD(d0, q0, q0); // odd elements non-NaN
|
||||
VANDQ(v1, v1, d0); // v1 = both non-NaN per pair
|
||||
}
|
||||
VFSUBQD(q0, v0, q0);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
VFCMEQQD(v0, q0, q0); // 0 => out is NAN
|
||||
VBICQ(v1, v1, v0); // forget it in any input was a NAN alreavy
|
||||
MOV64x(x5, 0x0008000000000000ULL);
|
||||
VFCMEQQD(d0, d1, d1); // d0 = src1 non-NaN mask
|
||||
VDUPQD(v0, x5); // v0 = QNaN bit for double
|
||||
VORRQ(v0, d1, v0); // v0 = QNaN(src1)
|
||||
VBIFQ(q0, v0, d0); // where src1 NaN: replace with QNaN(src1)
|
||||
VFCMEQQD(v0, q0, q0); // 0 => out is NAN
|
||||
VBICQ(v1, v1, v0); // forget it in any input was a NAN already
|
||||
VSHLQ_64(v1, v1, 63); // only keep the sign bit
|
||||
VORRQ(q0, q0, v1); // NAN -> -NAN
|
||||
}
|
||||
@@ -2857,7 +2918,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
|
||||
case 0xC1:
|
||||
if(rex.w) return dynarec64_00(dyn, addr-1, ip, ninst, rex, ok, need_epilog);
|
||||
INST_NAME("XADD Gw, Ew");
|
||||
INST_NAME("XADD Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
@@ -2969,9 +3030,28 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
VMOVQ(v2, q0); // save src1
|
||||
VFCMEQQD(v0, q0, q0);
|
||||
VFCMEQQD(v1, q1, q1);
|
||||
VANDQ(v1, v0, v1); // v1 = both non-NaN
|
||||
}
|
||||
VFSUBQD(v0, q0, q1);
|
||||
VFADDQD(q0, q0, q1);
|
||||
VMOVeD(q0, 0, v0, 0);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
MOV64x(x5, 0x0008000000000000ULL);
|
||||
VFCMEQQD(v0, q0, q0); // 0 where result is NaN
|
||||
VBICQ(v0, v1, v0); // both non-NaN but result NaN
|
||||
VSHLQ_64(v0, v0, 63); // sign bit only
|
||||
VORRQ(q0, q0, v0); // force -NaN
|
||||
VFCMEQQD(v0, v2, v2); // 0 if src1 was NaN
|
||||
VDUPQD(v1, x5); // QNaN bit
|
||||
VORRQ(v2, v2, v1); // quiet any SNaN
|
||||
VBIFQ(q0, v2, v0); // where src1 NaN: use QNaN(src1)
|
||||
}
|
||||
break;
|
||||
case 0xD1:
|
||||
INST_NAME("PSRLW Gx, Ex");
|
||||
|
||||
@@ -210,11 +210,16 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETGW(x5);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
MOVx_REG(x6, xFlags);
|
||||
MRS_nzcv(x87pc);
|
||||
MARKLOCK;
|
||||
MOVx_REG(xFlags, x6);
|
||||
MSR_nzcv(x87pc);
|
||||
LDAXRH(x1, wback);
|
||||
emit_adc16(dyn, ninst, x1, x5, x3, x4);
|
||||
STLXRH(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
NATIVE_RESTORE_X87PC();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -320,11 +325,11 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
if(!i64) {MOV32w(x5, i16);}
|
||||
if(cpuext.atomics) {
|
||||
MOV32w(x5, i16);
|
||||
UFLAG_IF {
|
||||
LDSETALH(x5, x1, wback);
|
||||
emit_or16c(dyn, ninst, x1, i16, x3, x4);
|
||||
emit_or16(dyn, ninst, x1, x5, x3, x4);
|
||||
} else {
|
||||
STSETLH(x5, wback);
|
||||
}
|
||||
@@ -355,12 +360,17 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOV32w(x5, i16);
|
||||
MOV32w(x5, (uint16_t)i16);
|
||||
MOVx_REG(x6, xFlags);
|
||||
MRS_nzcv(x87pc);
|
||||
MARKLOCK;
|
||||
MOVx_REG(xFlags, x6);
|
||||
MSR_nzcv(x87pc);
|
||||
LDAXRH(x1, wback);
|
||||
emit_adc16(dyn, ninst, x1, x5, x3, x4);
|
||||
STLXRH(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
NATIVE_RESTORE_X87PC();
|
||||
}
|
||||
break;
|
||||
case 3: //SBB
|
||||
@@ -375,12 +385,17 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOV32w(x5, i16);
|
||||
MOV32w(x5, (uint16_t)i16);
|
||||
MOVx_REG(x6, xFlags);
|
||||
MRS_nzcv(x87pc);
|
||||
MARKLOCK;
|
||||
MOVx_REG(xFlags, x6);
|
||||
MSR_nzcv(x87pc);
|
||||
LDAXRH(x1, wback);
|
||||
emit_sbb16(dyn, ninst, x1, x5, x3, x4);
|
||||
STLXRH(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
NATIVE_RESTORE_X87PC();
|
||||
}
|
||||
break;
|
||||
case 4: //AND
|
||||
@@ -455,7 +470,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
MARKLOCK;
|
||||
LDAXRH(x1, wback);
|
||||
SUBw_REG(x4, x1, x5);
|
||||
STLXRH(x3, x1, wback);
|
||||
STLXRH(x3, x4, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
if(!ALIGNED_ATOMICH) {
|
||||
@@ -489,9 +504,10 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
i64 = convert_bitmask_w(i16);
|
||||
if(cpuext.atomics) {
|
||||
MOV32w(x5, i16);
|
||||
UFLAG_IF {
|
||||
LDEORALH(x5, x1, wback);
|
||||
emit_xor16c(dyn, ninst, x1, i16, x3, x4);
|
||||
emit_xor16(dyn, ninst, x1, x5, x3, x4);
|
||||
} else {
|
||||
STEORLH(x5, wback);
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@ uintptr_t dynarec64_66F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
switch(opcode) {
|
||||
|
||||
case 0xF1:
|
||||
if (rex.w) return dynarec64_F20F(dyn, addr - 2, ip, ninst, rex, ok, need_epilog);
|
||||
INST_NAME("CRC32 Gd, Ew");
|
||||
nextop = F8;
|
||||
GETEW(x1, 0);
|
||||
|
||||
@@ -30,6 +30,7 @@ typedef struct arch_flags_s
|
||||
uint8_t vf:1;
|
||||
uint8_t cf:1;
|
||||
uint8_t inv_cf:1;
|
||||
uint8_t pf_v:1;
|
||||
} arch_flags_t;
|
||||
|
||||
#define X87_ST_D 0
|
||||
@@ -96,6 +97,7 @@ static int arch_build(dynarec_arm_t* dyn, int ninst, arch_build_t* arch, int noa
|
||||
arch->flags_.cf = flags&NF_CF;
|
||||
if(arch->flags_.cf)
|
||||
arch->flags_.inv_cf = !dyn->insts[ninst].normal_carry;
|
||||
arch->flags_.pf_v = flags&NF_PF_V;
|
||||
}
|
||||
// opcode can handle unaligned
|
||||
arch->unaligned = dyn->insts[ninst].unaligned;
|
||||
@@ -286,10 +288,10 @@ void adjust_arch(dynablock_t* db, x64emu_t* emu, ucontext_t* p, uintptr_t x64pc)
|
||||
SUPER()
|
||||
#undef GO
|
||||
int i = 0;
|
||||
while(i<ninst-1) {
|
||||
while(i<(ninst)) { // this will look for ninst-1 state
|
||||
arch = next;
|
||||
dynarec_log_prefix(0, (i<(ninst-1))?LOG_DEBUG:LOG_INFO, "[ seq=%d%s%s%s%s%s ] ", arch->seq, arch->flags?" Flags":"", arch->x87?" x87":"", arch->mmx?" MMX":"", arch->sse?" SSE":"", arch->ymm?" YMM":"");
|
||||
i += 1+arch->seq;
|
||||
dynarec_log_prefix(0, (i<ninst-1)?LOG_DEBUG:LOG_INFO, "[ seq=%d%s%s%s%s%s ] ", arch->seq, arch->flags?" Flags":"", arch->x87?" x87":"", arch->mmx?" MMX":"", arch->sse?" SSE":"", arch->ymm?" YMM":"");
|
||||
next = (arch_arch_t*)((uintptr_t)next + sizeof_arch(arch));
|
||||
}
|
||||
int sz = sizeof(arch_arch_t);
|
||||
@@ -322,6 +324,9 @@ void adjust_arch(dynablock_t* db, x64emu_t* emu, ucontext_t* p, uintptr_t x64pc)
|
||||
CONDITIONAL_SET_FLAG(p->uc_mcontext.pstate&(1<<NZCV_C), F_CF);
|
||||
}
|
||||
}
|
||||
if(flags->pf_v) {
|
||||
CONDITIONAL_SET_FLAG(p->uc_mcontext.pstate&(1<<NZCV_V), F_PF);
|
||||
}
|
||||
}
|
||||
struct fpsimd_context *fpsimd = NULL;
|
||||
// find fpsimd struct
|
||||
|
||||
@@ -138,12 +138,12 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
break;
|
||||
case 0x13:
|
||||
nextop = F8;
|
||||
INST_NAME("VMOVLPS Ex, Gx");
|
||||
GETGX(v0, 0);
|
||||
if(MODREG) {
|
||||
DEFAULT;
|
||||
return addr;
|
||||
INST_NAME("Illegal AVX.0F 13");
|
||||
UDF(0);
|
||||
} else {
|
||||
INST_NAME("VMOVLPS Ex, Gx");
|
||||
GETGX(v0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
VST1_64(v0, 0, ed);
|
||||
SMWRITE2();
|
||||
@@ -262,19 +262,14 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
break;
|
||||
|
||||
case 0x2B:
|
||||
INST_NAME("VMOVNTPS Ex, Gx");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if(MODREG) {
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, ed);
|
||||
VMOVQ(v1, v0);
|
||||
if(vex.l) {
|
||||
GETGYEY_empty(v0, v1);
|
||||
VMOVQ(v1, v0);
|
||||
} else YMM0(ed);
|
||||
INST_NAME("Illegal AVX.0F 2B");
|
||||
UDF(0);
|
||||
} else {
|
||||
INST_NAME("VMOVNTPS Ex, Gx");
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if(vex.l) {
|
||||
GETGY(v1, 0, -1, -1, -1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0x3f<<4, 15, rex, NULL, 1, 0);
|
||||
@@ -294,10 +289,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
GETEXSS(s0, 0, 0);
|
||||
IFX(X_CF|X_PF|X_ZF) {
|
||||
FCMPS(v0, s0);
|
||||
}
|
||||
FCOMI(x1, x2);
|
||||
FCOMIS(x1, x2, v0, s0);
|
||||
break;
|
||||
|
||||
case 0x50:
|
||||
@@ -463,20 +455,26 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
q2 = 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)) {
|
||||
VMOVQ(q2, v2); // save src1
|
||||
// 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);
|
||||
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
|
||||
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
|
||||
VFCMEQQS(q0, q2, q2); // 0 if src1 was NaN
|
||||
MOVIQ_32_lsl(q1, 0x40, 2); // QNaN bit 0x00400000
|
||||
VORRQ(q2, q2, q1); // quiet any SNaN
|
||||
VBIFQ(v0, q2, q0); // where src1 NaN, use QNaN(src1)
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd)
|
||||
@@ -487,20 +485,26 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
q2 = 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)) {
|
||||
VMOVQ(q2, v2); // save src1
|
||||
// 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);
|
||||
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
|
||||
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
|
||||
VFCMEQQS(q0, q2, q2); // 0 if src1 was NaN
|
||||
MOVIQ_32_lsl(q1, 0x40, 2); // QNaN bit 0x00400000
|
||||
VORRQ(q2, q2, q1); // quiet any SNaN
|
||||
VBIFQ(v0, q2, q0); // where src1 NaN, use QNaN(src1)
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd)
|
||||
@@ -536,20 +540,26 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
q2 = 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)) {
|
||||
VMOVQ(q2, v2); // save src1
|
||||
// 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);
|
||||
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
|
||||
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
|
||||
VFCMEQQS(q0, q2, q2); // 0 if src1 was NaN
|
||||
MOVIQ_32_lsl(q1, 0x40, 2); // QNaN bit 0x00400000
|
||||
VORRQ(q2, q2, q1); // quiet any SNaN
|
||||
VBIFQ(v0, q2, q0); // where src1 NaN, use QNaN(src1)
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd)
|
||||
@@ -574,20 +584,26 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
q2 = 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)) {
|
||||
VMOVQ(q2, v2); // save src1
|
||||
// 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);
|
||||
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
|
||||
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
|
||||
VFCMEQQS(q0, q2, q2); // 0 if src1 was NaN
|
||||
MOVIQ_32_lsl(q1, 0x40, 2); // QNaN bit 0x00400000
|
||||
VORRQ(q2, q2, q1); // quiet any SNaN
|
||||
VBIFQ(v0, q2, q0); // where src1 NaN, use QNaN(src1)
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd)
|
||||
|
||||
@@ -94,6 +94,15 @@ uintptr_t dynarec64_AVX_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, i
|
||||
BFIw(xFlags, x1, F_SF, 1);
|
||||
}
|
||||
}
|
||||
// UD flags
|
||||
IFX(X_AF) BFCw(xFlags, F_AF, 1);
|
||||
if (BOX64DRENV(dynarec_safeflags)) {
|
||||
if (BOX64ENV(cputype)) {
|
||||
IFX (X_PF) BFCw(xFlags, F_PF, 1);
|
||||
} else {
|
||||
IFX (X_PF) emit_pf(dyn, ninst, gd, x3);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xF3:
|
||||
nextop = F8;
|
||||
@@ -244,15 +253,15 @@ uintptr_t dynarec64_AVX_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, i
|
||||
GETGD;
|
||||
GETED(0);
|
||||
GETVD;
|
||||
UXTBw(x1, vd);
|
||||
CMPSw_U12(x1, rex.w?64:32);
|
||||
UXTBw(x6, vd);
|
||||
CMPSw_U12(x6, rex.w ? 64 : 32);
|
||||
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);
|
||||
LSLxw_REG(x2, x2, x6);
|
||||
MARK;
|
||||
need_tst = 0;
|
||||
IFX(X_ZF) need_tst = 1;
|
||||
@@ -280,11 +289,7 @@ uintptr_t dynarec64_AVX_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, i
|
||||
if (BOX64DRENV(dynarec_safeflags)) {
|
||||
// those are UD flags
|
||||
IFX(X_AF) BFCw(xFlags, F_AF, 1);
|
||||
if(BOX64ENV(cputype)) {
|
||||
IFX(X_PF) BFCw(xFlags, F_PF, 1);
|
||||
} else {
|
||||
IFX(X_PF) emit_pf(dyn, ninst, vd, x3);
|
||||
}
|
||||
IFX(X_PF) BFCw(xFlags, F_PF, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
@@ -268,10 +268,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
GETEXSD(q0, 0, 0);
|
||||
IFX(X_CF|X_PF|X_ZF) {
|
||||
FCMPD(v0, q0);
|
||||
}
|
||||
FCOMI(x1, x2);
|
||||
FCOMID(x1, x2, v0, q0);
|
||||
break;
|
||||
|
||||
case 0x50:
|
||||
@@ -362,23 +359,30 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
q2 = 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)) {
|
||||
VMOVQ(q2, v2); // save src1
|
||||
// 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(!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
|
||||
VORRQ(v0, v0, q1); // NAN -> -NAN
|
||||
MOV64x(x5, 0x0008000000000000ULL);
|
||||
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
|
||||
VORRQ(v0, v0, q1); // NAN -> -NAN
|
||||
VFCMEQQD(q0, q2, q2); // 0 if src1 was NaN
|
||||
VDUPQD(q1, x5); // QNaN bit
|
||||
VORRQ(q2, q2, q1); // quiet any SNaN
|
||||
VBIFQ(v0, q2, q0); // where src1 NaN, use QNaN(src1)
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd)
|
||||
if (!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x59:
|
||||
INST_NAME("VMULPD Gx, Vx, Ex");
|
||||
@@ -386,10 +390,12 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
q2 = 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)) {
|
||||
VMOVQ(q2, v2); // save src1
|
||||
// check if any input value was NAN
|
||||
VFMAXQD(q0, v2, v1); // propagate NAN
|
||||
VFCMEQQD(q0, q0, q0); // 0 if NAN, 1 if not NAN
|
||||
@@ -400,6 +406,11 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
VBICQ(q1, q0, q1); // forget it in any input was a NAN already
|
||||
VSHLQ_64(q1, q1, 63); // only keep the sign bit
|
||||
VORRQ(v0, v0, q1); // NAN -> -NAN
|
||||
VFCMEQQD(q0, q2, q2); // 0 if src1 was NaN
|
||||
MOV64x(x5, 0x0008000000000000ULL);
|
||||
VDUPQD(q1, x5); // QNaN bit
|
||||
VORRQ(q2, q2, q1); // quiet any SNaN
|
||||
VBIFQ(v0, q2, q0); // where src1 NaN, use QNaN(src1)
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd)
|
||||
@@ -474,20 +485,27 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
q2 = 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)) {
|
||||
VMOVQ(q2, v2); // save src1
|
||||
// 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(!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
|
||||
VORRQ(v0, v0, q1); // NAN -> -NAN
|
||||
MOV64x(x5, 0x0008000000000000ULL);
|
||||
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
|
||||
VORRQ(v0, v0, q1); // NAN -> -NAN
|
||||
VFCMEQQD(q0, q2, q2); // 0 if src1 was NaN
|
||||
VDUPQD(q1, x5); // QNaN bit
|
||||
VORRQ(q2, q2, q1); // quiet any SNaN
|
||||
VBIFQ(v0, q2, q0); // where src1 NaN, use QNaN(src1)
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
@@ -512,20 +530,27 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
q2 = 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)) {
|
||||
VMOVQ(q2, v2); // save src1
|
||||
// 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(!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
|
||||
VORRQ(v0, v0, q1); // NAN -> -NAN
|
||||
MOV64x(x5, 0x0008000000000000ULL);
|
||||
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
|
||||
VORRQ(v0, v0, q1); // NAN -> -NAN
|
||||
VFCMEQQD(q0, q2, q2); // 0 if src1 was NaN
|
||||
VDUPQD(q1, x5); // QNaN bit
|
||||
VORRQ(q2, q2, q1); // quiet any SNaN
|
||||
VBIFQ(v0, q2, q0); // where src1 NaN, use QNaN(src1)
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
@@ -1161,20 +1186,30 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
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_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
// check if any input value was NAN
|
||||
VFMAXPQD(q0, v2, v1); // propagate NAN
|
||||
VFCMEQQD(q0, q0, q0); // 0 if NAN, 1 if not NAN
|
||||
VUZP1Q_64(d1, v2, v1); // d1 = src1 (even elements)
|
||||
VFCMEQQD(q0, v2, v2); // per-element non-NaN for Vx
|
||||
VFCMEQQD(d0, v1, v1); // per-element non-NaN for Ex
|
||||
VUZP1Q_64(q1, q0, d0); // first element of each pair
|
||||
VUZP2Q_64(q0, q0, d0); // second element of each pair
|
||||
VANDQ(q0, q1, q0); // both non-NaN per pair
|
||||
}
|
||||
VFADDPQD(v0, v2, v1);
|
||||
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
|
||||
VORRQ(v0, v0, q1); // NAN -> -NAN
|
||||
MOV64x(x5, 0x0008000000000000ULL);
|
||||
VFCMEQQD(q1, d1, d1); // q1 = src1 non-NaN mask
|
||||
VDUPQD(d0, x5); // d0 = QNaN bit for double
|
||||
VORRQ(d0, d1, d0); // d0 = QNaN(src1)
|
||||
VBIFQ(v0, d0, q1); // where src1 NaN: replace with QNaN(src1)
|
||||
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
|
||||
VORRQ(v0, v0, q1); // NAN -> -NAN
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
@@ -1183,24 +1218,32 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
INST_NAME("VHSUBPD Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
if(!BOX64ENV(dynarec_fastnan))
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
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_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
|
||||
VUZP1Q_64(q0, v2, v1);
|
||||
VUZP2Q_64(v0, v2, v1);
|
||||
VUZP1Q_64(q0, v2, v1); // q0 = src1 (first of each pair)
|
||||
VUZP2Q_64(v0, v2, v1); // v0 = src2 (second of each pair)
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
// check if any input value was NAN
|
||||
// but need to mix low/high part
|
||||
VFMAXQD(q1, v0, q0); // propagate NAN
|
||||
VFCMEQQD(q1, q1, q1); // 0 if NAN, 1 if not NAN
|
||||
VMOVQ(d1, q0); // save src1
|
||||
VFCMEQQD(q1, q0, q0); // even elements non-NaN
|
||||
VFCMEQQD(d0, v0, v0); // odd elements non-NaN
|
||||
VANDQ(q1, q1, d0); // both non-NaN per pair
|
||||
}
|
||||
VFSUBQD(v0, q0, v0);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
VFCMEQQD(q0, v0, v0); // 0 => out is NAN
|
||||
VBICQ(q1, q1, q0); // forget it in any input was a NAN already
|
||||
VSHLQ_64(q1, q1, 63); // only keep the sign bit
|
||||
VORRQ(v0, v0, q1); // NAN -> -NAN
|
||||
MOV64x(x5, 0x0008000000000000ULL);
|
||||
VFCMEQQD(d0, d1, d1); // d0 = src1 non-NaN mask
|
||||
VDUPQD(q0, x5); // q0 = QNaN bit for double
|
||||
VORRQ(q0, d1, q0); // q0 = QNaN(src1)
|
||||
VBIFQ(v0, q0, d0); // where src1 NaN: replace with QNaN(src1)
|
||||
VFCMEQQD(q0, v0, v0); // 0 => out is NAN
|
||||
VBICQ(q1, q1, q0); // forget it in any input was a NAN already
|
||||
VSHLQ_64(q1, q1, 63); // only keep the sign bit
|
||||
VORRQ(v0, v0, q1); // NAN -> -NAN
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
@@ -1349,11 +1392,32 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
INST_NAME("VADDSUBPD Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
q2 = 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)) {
|
||||
VMOVQ(q2, v2); // save src1
|
||||
VFCMEQQD(q0, v2, v2);
|
||||
VFCMEQQD(q1, v1, v1);
|
||||
VANDQ(q1, q0, q1); // q1 = both non-NaN
|
||||
}
|
||||
FSUBD(q0, v2, v1);
|
||||
VFADDQD(v0, v2, v1);
|
||||
VMOVeD(v0, 0, q0, 0);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
MOV64x(x5, 0x0008000000000000ULL);
|
||||
VFCMEQQD(q0, v0, v0); // 0 where result is NaN
|
||||
VBICQ(q0, q1, q0); // both non-NaN but result NaN
|
||||
VSHLQ_64(q0, q0, 63); // sign bit only
|
||||
VORRQ(v0, v0, q0); // force -NaN
|
||||
VFCMEQQD(q0, q2, q2); // 0 if src1 was NaN
|
||||
VDUPQD(q1, x5); // QNaN bit
|
||||
VORRQ(q2, q2, q1); // quiet any SNaN
|
||||
VBIFQ(v0, q2, q0); // where src1 NaN: use QNaN(src1)
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
@@ -1670,13 +1734,12 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
case 0xE6:
|
||||
INST_NAME("VCVTTPD2DQ Gx, Ex");
|
||||
nextop = F8;
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) {
|
||||
GETEX_Y(v1, 0, 0);
|
||||
GETGX_empty(v0);
|
||||
} else {
|
||||
if(BOX64ENV(dynarec_fastround))
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
GETEY(v1);
|
||||
}
|
||||
if(BOX64ENV(dynarec_fastround)) {
|
||||
@@ -1697,7 +1760,6 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
if(!l) {
|
||||
MRS_fpsr(x5);
|
||||
ORRw_mask(x4, xZR, 1, 0); //0x80000000
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
}
|
||||
for(int i=0; i<2; ++i) {
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
|
||||
@@ -684,7 +684,9 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
GETVX(v2, 0);
|
||||
GETGX_empty(v0);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
VSSHRQ_32(q0, v2, 31);
|
||||
VSHRQ_32(q0, v2, 31); // move sign bit to lower
|
||||
SQXTN_16(q0, q0); // reduce to 16bits for easier extraction
|
||||
VMOVQDto(x4, q0, 0); // extract the mask as 16bits slices instead of 32bits
|
||||
if (MODREG) {
|
||||
DEFAULT;
|
||||
return addr;
|
||||
@@ -692,21 +694,17 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
VEORQ(v0, v0, v0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
VMOVSto(x4, q0, 0);
|
||||
CBZw(x4, 4+1*4);
|
||||
TBZ(x4, 0*16, 4+1*4);
|
||||
VLD1_32(v0, 0, ed);
|
||||
ADDx_U12(x3, ed, 4);
|
||||
ed = x3;
|
||||
VMOVSto(x4, q0, 1);
|
||||
CBZw(x4, 4+1*4);
|
||||
TBZ(x4, 1*16, 4+1*4);
|
||||
VLD1_32(v0, 1, ed);
|
||||
ADDx_U12(ed, ed, 4);
|
||||
VMOVSto(x4, q0, 2);
|
||||
CBZw(x4, 4+1*4);
|
||||
TBZ(x4, 2*16, 4+1*4);
|
||||
VLD1_32(v0, 2, ed);
|
||||
ADDx_U12(ed, ed, 4);
|
||||
VMOVSto(x4, q0, 3);
|
||||
CBZw(x4, 4+1*4);
|
||||
TBZ(x4, 3*16, 4+1*4);
|
||||
VLD1_32(v0, 3, ed);
|
||||
if(vex.l)
|
||||
ADDx_U12(ed, ed, 4);
|
||||
@@ -714,22 +712,20 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
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);
|
||||
VSHRQ_32(q0, v2, 31); // move sign bit to lower
|
||||
SQXTN_16(q0, q0); // reduce to 16bits for easier extraction
|
||||
VMOVQDto(x4, q0, 0); // extract the mask as 16bits slices instead of 32bits
|
||||
VEORQ(v0, v0, v0);
|
||||
VMOVSto(x4, q0, 0);
|
||||
CBZw(x4, 4+1*4);
|
||||
TBZ(x4, 0*16, 4+1*4);
|
||||
VLD1_32(v0, 0, ed);
|
||||
ADDx_U12(ed, ed, 4);
|
||||
VMOVSto(x4, q0, 1);
|
||||
CBZw(x4, 4+1*4);
|
||||
TBZ(x4, 1*16, 4+1*4);
|
||||
VLD1_32(v0, 1, ed);
|
||||
ADDx_U12(ed, ed, 4);
|
||||
VMOVSto(x4, q0, 2);
|
||||
CBZw(x4, 4+1*4);
|
||||
TBZ(x4, 2*16, 4+1*4);
|
||||
VLD1_32(v0, 2, ed);
|
||||
ADDx_U12(ed, ed, 4);
|
||||
VMOVSto(x4, q0, 3);
|
||||
CBZw(x4, 4+1*4);
|
||||
TBZ(x4, 3*16, 4+1*4);
|
||||
VLD1_32(v0, 3, ed);
|
||||
} else YMM0(gd);
|
||||
break;
|
||||
@@ -740,7 +736,9 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
GETGX_empty(v0);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
// create mask
|
||||
VSSHRQ_64(q0, v2, 63);
|
||||
VSHRQ_64(q0, v2, 63);
|
||||
SQXTN_32(q0, q0);
|
||||
VMOVQDto(x4, q0, 0);
|
||||
VEORQ(v0, v0, v0);
|
||||
if (MODREG) {
|
||||
DEFAULT;
|
||||
@@ -748,13 +746,11 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
VMOVQDto(x4, q0, 0);
|
||||
CBZx(x4, 4+1*4);
|
||||
TBZ(x4, 0*32, 4+1*4);
|
||||
VLD1_64(v0, 0, ed);
|
||||
ADDx_U12(x3, ed, 8);
|
||||
ed = x3;
|
||||
VMOVQDto(x4, q0, 1);
|
||||
CBZx(x4, 4+1*4);
|
||||
TBZ(x4, 1*32, 4+1*4);
|
||||
VLD1_64(v0, 1, ed);
|
||||
if(vex.l)
|
||||
ADDx_U12(ed, ed, 8);
|
||||
@@ -762,14 +758,14 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
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);
|
||||
VSHRQ_64(q0, v2, 63);
|
||||
SQXTN_32(q0, q0);
|
||||
VMOVQDto(x4, q0, 0);
|
||||
CBZx(x4, 4+1*4);
|
||||
VEORQ(v0, v0, v0);
|
||||
TBZ(x4, 0*32, 4+1*4);
|
||||
VLD1_64(v0, 0, ed);
|
||||
ADDx_U12(ed, ed, 8);
|
||||
VMOVQDto(x4, q0, 1);
|
||||
CBZx(x4, 4+1*4);
|
||||
TBZ(x4, 1*32, 4+1*4);
|
||||
VLD1_64(v0, 1, ed);
|
||||
} else YMM0(gd);
|
||||
break;
|
||||
@@ -779,7 +775,9 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
GETVX(v2, 0);
|
||||
GETGX(v0, 0);
|
||||
VSSHRQ_32(q0, v2, 31);
|
||||
VSHRQ_32(q0, v2, 31); // move sign bit to lower
|
||||
SQXTN_16(q0, q0); // reduce to 16bits for easier extraction
|
||||
VMOVQDto(x4, q0, 0); // extract the mask as 16bits slices instead of 32bits
|
||||
if(MODREG) {
|
||||
DEFAULT;
|
||||
return addr;
|
||||
@@ -787,21 +785,17 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
// check if mask as anything, else skip the whole read/write to avoid a SEGFAULT.
|
||||
// TODO: let a segfault trigger and check if the mask is null instead and ignore the segfault / actually triger: needs to implement SSE reg tracking first!
|
||||
VMOVSto(x4, q0, 0);
|
||||
CBZw(x4, 4+1*4);
|
||||
TBZ(x4, 0*16, 4+1*4);
|
||||
VST1_32(v0, 0, ed);
|
||||
ADDx_U12(x3, ed, 4);
|
||||
ed = x3;
|
||||
VMOVSto(x4, q0, 1);
|
||||
CBZw(x4, 4+1*4);
|
||||
TBZ(x4, 1*16, 4+1*4);
|
||||
VST1_32(v0, 1, ed);
|
||||
ADDx_U12(ed, ed, 4);
|
||||
VMOVSto(x4, q0, 2);
|
||||
CBZw(x4, 4+1*4);
|
||||
TBZ(x4, 2*16, 4+1*4);
|
||||
VST1_32(v0, 2, ed);
|
||||
ADDx_U12(ed, ed, 4);
|
||||
VMOVSto(x4, q0, 3);
|
||||
CBZw(x4, 4+1*4);
|
||||
TBZ(x4, 3*16, 4+1*4);
|
||||
VST1_32(v0, 3, ed);
|
||||
if(vex.l)
|
||||
ADDx_U12(ed, ed, 4);
|
||||
@@ -810,22 +804,23 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
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);
|
||||
VMOVSto(x4, q0, 0);
|
||||
CBZw(x4, 4+1*4);
|
||||
VSHRQ_32(q0, v2, 31); // move sign bit to lower
|
||||
SQXTN_16(q0, q0); // reduce to 16bits for easier extraction
|
||||
VMOVQDto(x4, q0, 0); // extract the mask as 16bits slices instead of 32bits
|
||||
TBZ(x4, 0*16, 4+1*4);
|
||||
VST1_32(v0, 0, ed);
|
||||
ADDx_U12(ed, ed, 4);
|
||||
VMOVSto(x4, q0, 1);
|
||||
CBZw(x4, 4+1*4);
|
||||
TBZ(x4, 1*16, 4+1*4);
|
||||
VST1_32(v0, 1, ed);
|
||||
ADDx_U12(ed, ed, 4);
|
||||
VMOVSto(x4, q0, 2);
|
||||
CBZw(x4, 4+1*4);
|
||||
TBZ(x4, 2*16, 4+1*4);
|
||||
VST1_32(v0, 2, ed);
|
||||
ADDx_U12(ed, ed, 4);
|
||||
VMOVSto(x4, q0, 3);
|
||||
CBZw(x4, 4+1*4);
|
||||
TBZ(x4, 3*16, 4+1*4);
|
||||
VST1_32(v0, 3, ed);
|
||||
} else if (vex.l) { // keep avx ymm zero tracking consistent
|
||||
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);
|
||||
}
|
||||
SMWRITE2();
|
||||
break;
|
||||
@@ -835,7 +830,9 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
GETVX(v2, 0);
|
||||
GETGX(v0, 0);
|
||||
VSSHRQ_64(q0, v2, 63);
|
||||
VSHRQ_64(q0, v2, 63);
|
||||
SQXTN_32(q0, q0);
|
||||
VMOVQDto(x4, q0, 0);
|
||||
if(MODREG) {
|
||||
DEFAULT;
|
||||
return addr;
|
||||
@@ -845,13 +842,11 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
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!
|
||||
VMOVQDto(x4, q0, 0);
|
||||
CBZx(x4, 4+1*4);
|
||||
TBZ(x4, 0*32, 4+1*4);
|
||||
VST1_64(v0, 0, ed);
|
||||
ADDx_U12(x3, ed, 8);
|
||||
ed = x3;
|
||||
VMOVQDto(x4, q0, 1);
|
||||
CBZx(x4, 4+1*4);
|
||||
TBZ(x4, 1*32, 4+1*4);
|
||||
VST1_64(v0, 1, ed);
|
||||
if(vex.l)
|
||||
ADDx_U12(ed, ed, 8);
|
||||
@@ -860,14 +855,17 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
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);
|
||||
VSHRQ_64(q0, v2, 63);
|
||||
SQXTN_32(q0, q0);
|
||||
VMOVQDto(x4, q0, 0);
|
||||
CBZx(x4, 4+1*4);
|
||||
TBZ(x4, 0*32, 4+1*4);
|
||||
VST1_64(v0, 0, ed);
|
||||
ADDx_U12(ed, ed, 8);
|
||||
VMOVQDto(x4, q0, 1);
|
||||
CBZx(x4, 4+1*4);
|
||||
TBZ(x4, 1*32, 4+1*4);
|
||||
VST1_64(v0, 1, ed);
|
||||
} else if (vex.l) { // keep avx ymm zero tracking consistent
|
||||
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);
|
||||
}
|
||||
SMWRITE2();
|
||||
break;
|
||||
@@ -1385,14 +1383,14 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
VMOVQDto(x4, v2, i);
|
||||
CBZw(x4, 4+4*4);
|
||||
SMOVQSto(x4, v1, i+l*2);
|
||||
ADDx_REG_LSL(x4, ed, x4, wb1);
|
||||
ADDz_REG_LSL(x4, ed, x4, wb1);
|
||||
VLD1_64(v0, i, x4);
|
||||
VMOVQDfrom(v2, i, xZR);
|
||||
} else for(int i=0; i<4; ++i) {
|
||||
VMOVSto(x4, v2, i);
|
||||
CBZw(x4, 4+4*4);
|
||||
SMOVQSto(x4, v1, i);
|
||||
ADDx_REG_LSL(x4, ed, x4, wb1);
|
||||
ADDz_REG_LSL(x4, ed, x4, wb1);
|
||||
VLD1_32(v0, i, x4);
|
||||
VMOVQSfrom(v2, i, xZR);
|
||||
}
|
||||
@@ -1440,7 +1438,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
VMOVSto(x4, v2, i);
|
||||
CBZw(x4, 4+4*4);
|
||||
VMOVQDto(x4, (i&2)?q1:v1, i&1);
|
||||
ADDx_REG_LSL(x4, ed, x4, wb1);
|
||||
ADDz_REG_LSL(x4, ed, x4, wb1);
|
||||
VLD1_32(v0, i, x4);
|
||||
VMOVQSfrom(v2, i, xZR);
|
||||
}
|
||||
@@ -1465,7 +1463,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
VMOVQDto(x4, v2, i);
|
||||
CBZw(x4, 4+4*4);
|
||||
VMOVQDto(x4, v1, i);
|
||||
ADDx_REG_LSL(x4, ed, x4, wb1);
|
||||
ADDz_REG_LSL(x4, ed, x4, wb1);
|
||||
VLD1_64(v0, i, x4);
|
||||
VMOVQDfrom(v2, i, xZR);
|
||||
}
|
||||
|
||||
@@ -540,13 +540,20 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
break;
|
||||
|
||||
case 0x20:
|
||||
INST_NAME("VINSERTD Gx, Vx, Ex, Ib");
|
||||
INST_NAME("VPINSRB Gx, Vx, ED, Ib");
|
||||
nextop = F8;
|
||||
GETGX_empty_VX(v0, v2);
|
||||
GETED(1);
|
||||
u8 = F8;
|
||||
if(v0!=v2) VMOVQ(v0, v2);
|
||||
VMOVQBfrom(v0, u8&0xf, ed);
|
||||
if(MODREG) {
|
||||
u8 = (F8)&15;
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
VMOVQBfrom(v0, u8, ed);
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 1);
|
||||
u8 = (F8)&15;
|
||||
VLD1_8(v0, u8, wback);
|
||||
}
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x21:
|
||||
|
||||
@@ -240,13 +240,18 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
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
|
||||
FMAXD(q1, v2, 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
|
||||
FCMEQD(q1, v2, v2); // 0 if src1 was NaN
|
||||
MOV64x(x5, 0x0008000000000000ULL);
|
||||
VMOVQDfrom(q0, 0, x5);
|
||||
VORR(q0, v2, q0); // QNaN(src1)
|
||||
VBIF(q2, q0, q1); // where src1 was NaN, use QNaN(src1)
|
||||
} else {
|
||||
FADDD(q2, v1, v2); // the high part of the vector is erased...
|
||||
}
|
||||
@@ -266,13 +271,18 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
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
|
||||
FMAXD(q1, v2, 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
|
||||
FCMEQD(q1, v2, v2); // 0 if src1 was NaN
|
||||
MOV64x(x5, 0x0008000000000000ULL);
|
||||
VMOVQDfrom(q0, 0, x5);
|
||||
VORR(q0, v2, q0); // QNaN(src1)
|
||||
VBIF(q2, q0, q1); // where src1 was NaN, use QNaN(src1)
|
||||
} else {
|
||||
FMULD(q2, v1, v2); // the high part of the vector is erased...
|
||||
}
|
||||
@@ -312,13 +322,18 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
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
|
||||
FMAXD(q1, v2, 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
|
||||
FCMEQD(q1, v2, v2); // 0 if src1 was NaN
|
||||
MOV64x(x5, 0x0008000000000000ULL);
|
||||
VMOVQDfrom(q0, 0, x5);
|
||||
VORR(q0, v2, q0); // QNaN(src1)
|
||||
VBIF(q2, q0, q1); // where src1 was NaN, use QNaN(src1)
|
||||
} else {
|
||||
FSUBD(q2, v2, v1); // the high part of the vector is erased...
|
||||
}
|
||||
@@ -353,13 +368,18 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
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
|
||||
FMAXD(q1, v2, 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
|
||||
FCMEQD(q1, v2, v2); // 0 if src1 was NaN
|
||||
MOV64x(x5, 0x0008000000000000ULL);
|
||||
VMOVQDfrom(q0, 0, x5);
|
||||
VORR(q0, v2, q0); // QNaN(src1)
|
||||
VBIF(q2, q0, q1); // where src1 was NaN, use QNaN(src1)
|
||||
} else {
|
||||
FDIVD(q2, v2, v1); // the high part of the vector is erased...
|
||||
}
|
||||
@@ -424,20 +444,29 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
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_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
// check if any input value was NAN
|
||||
VFMAXPQS(q0, v2, v1); // propagate NAN
|
||||
VFCMEQQS(q0, q0, q0); // 0 if NAN, 1 if not NAN
|
||||
VUZP1Q_32(d1, v2, v1); // d1 = src1 (even elements)
|
||||
VFCMEQQS(q0, v2, v2); // per-element non-NaN for Vx
|
||||
VFCMEQQS(d0, v1, v1); // per-element non-NaN for Ex
|
||||
VUZP1Q_32(q1, q0, d0); // even elements of pairs
|
||||
VUZP2Q_32(q0, q0, d0); // odd elements of pairs
|
||||
VANDQ(q0, q1, q0); // both non-NaN per pair
|
||||
}
|
||||
VFADDPQS(v0, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
VFCMEQQS(q1, v0, v0); // 0 => out is NAN
|
||||
VBICQ(q1, q0, q1); // forget it in any input was a NAN already
|
||||
VSHLQ_32(q1, q1, 31); // only keep the sign bit
|
||||
VORRQ(v0, v0, q1); // NAN -> -NAN
|
||||
VFCMEQQS(q1, d1, d1); // q1 = src1 non-NaN mask
|
||||
MOVIQ_32_lsl(d0, 0x40, 2); // d0 = 0x00400000 (QNaN bit)
|
||||
VORRQ(d0, d1, d0); // d0 = QNaN(src1)
|
||||
VBIFQ(v0, d0, q1); // where src1 NaN: replace with QNaN(src1)
|
||||
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);
|
||||
@@ -446,24 +475,31 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
INST_NAME("VHSUBPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
if(!BOX64ENV(dynarec_fastnan))
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
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_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
|
||||
VUZP1Q_32(q0, v2, v1);
|
||||
VUZP2Q_32(v0, v2, v1);
|
||||
VUZP1Q_32(q0, v2, v1); // q0 = src1 (even elements)
|
||||
VUZP2Q_32(v0, v2, v1); // v0 = src2 (odd elements)
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
// check if any input value was NAN
|
||||
// but need to mix low/high part
|
||||
VFMAXQS(q1, v0, q0); // propagate NAN
|
||||
VFCMEQQS(q1, q1, q1); // 0 if NAN, 1 if not NAN
|
||||
VMOVQ(d1, q0); // save src1
|
||||
VFCMEQQS(q1, q0, q0); // even elements non-NaN
|
||||
VFCMEQQS(d0, v0, v0); // odd elements non-NaN
|
||||
VANDQ(q1, q1, d0); // both non-NaN per pair
|
||||
}
|
||||
VFSUBQS(v0, q0, v0);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
VFCMEQQS(q0, v0, v0); // 0 => out is NAN
|
||||
VBICQ(q1, q1, q0); // forget it in any input was a NAN already
|
||||
VSHLQ_32(q1, q1, 31); // only keep the sign bit
|
||||
VORRQ(v0, v0, q1); // NAN -> -NAN
|
||||
VFCMEQQS(d0, d1, d1); // d0 = src1 non-NaN mask
|
||||
MOVIQ_32_lsl(q0, 0x40, 2); // q0 = 0x00400000 (QNaN bit)
|
||||
VORRQ(q0, d1, q0); // q0 = QNaN(src1)
|
||||
VBIFQ(v0, q0, d0); // where src1 NaN: replace with QNaN(src1)
|
||||
VFCMEQQS(q0, v0, v0); // 0 => out is NAN
|
||||
VBICQ(q1, q1, q0); // only when both inputs non-NaN but result is NaN
|
||||
VSHLQ_32(q1, q1, 31); // only keep the sign bit
|
||||
VORRQ(v0, v0, q1); // NAN -> -NAN
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
@@ -509,20 +545,39 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
INST_NAME("VADDSUBPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
q2 = fpu_get_scratch(dyn, ninst);
|
||||
}
|
||||
TABLE64C(x2, const_4f_m1_1_m1_1);
|
||||
VLDR128_U12(q0, x2, 0);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
VMOVQ(q2, v2); // save src1
|
||||
VFCMEQQS(q1, v2, v2);
|
||||
VFCMEQQS(d0, v1, v1);
|
||||
VANDQ(q1, q1, d0); // q1 = both non-NaN
|
||||
}
|
||||
if(v0==v1) {
|
||||
//TODO: find a better way
|
||||
if(!l) q1 = fpu_get_scratch(dyn, ninst);
|
||||
VMOVQ(q1, v2);
|
||||
VFMLAQS(q1, v1, q0);
|
||||
VMOVQ(v0, q1);
|
||||
VMOVQ(d0, v2);
|
||||
VFMLAQS(d0, v1, q0);
|
||||
VMOVQ(v0, d0);
|
||||
} else {
|
||||
if(v0!=v2) VMOVQ(v0, v2);
|
||||
VFMLAQS(v0, v1, q0);
|
||||
}
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
VFCMEQQS(d0, v0, v0); // 0 where result is NaN
|
||||
VBICQ(d0, q1, d0); // both non-NaN but result NaN
|
||||
VSHLQ_32(d0, d0, 31); // sign bit only
|
||||
VORRQ(v0, v0, d0); // force -NaN
|
||||
VFCMEQQS(q1, q2, q2); // 0 if src1 was NaN
|
||||
MOVIQ_32_lsl(d0, 0x40, 2); // QNaN bit 0x00400000
|
||||
VORRQ(q2, q2, d0); // quiet any SNaN
|
||||
VBIFQ(v0, q2, q1); // where src1 NaN: use QNaN(src1)
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
|
||||
@@ -275,13 +275,18 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
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
|
||||
FMAXS(q1, v2, 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
|
||||
FCMEQS(q1, v2, v2); // 0 if src1 was NaN
|
||||
MOV32w(x5, 0x00400000);
|
||||
VMOVQSfrom(q0, 0, x5);
|
||||
VORR(q0, v2, q0); // QNaN(src1)
|
||||
VBIF(q2, q0, q1); // where src1 was NaN, use QNaN(src1)
|
||||
} else {
|
||||
FADDS(q2, v1, v2); // the high part of the vector is erased...
|
||||
}
|
||||
@@ -301,13 +306,18 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
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
|
||||
FMAXS(q1, v2, 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
|
||||
FCMEQS(q1, v2, v2); // 0 if src1 was NaN
|
||||
MOV32w(x5, 0x00400000);
|
||||
VMOVQSfrom(q0, 0, x5);
|
||||
VORR(q0, v2, q0); // QNaN(src1)
|
||||
VBIF(q2, q0, q1); // where src1 was NaN, use QNaN(src1)
|
||||
} else {
|
||||
FMULS(q2, v1, v2); // the high part of the vector is erased...
|
||||
}
|
||||
@@ -375,13 +385,18 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
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
|
||||
FMAXS(q1, v2, 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
|
||||
FCMEQS(q1, v2, v2); // 0 if src1 was NaN
|
||||
MOV32w(x5, 0x00400000);
|
||||
VMOVQSfrom(q0, 0, x5);
|
||||
VORR(q0, v2, q0); // QNaN(src1)
|
||||
VBIF(q2, q0, q1); // where src1 was NaN, use QNaN(src1)
|
||||
} else {
|
||||
FSUBS(q2, v2, v1); // the high part of the vector is erased...
|
||||
}
|
||||
@@ -415,13 +430,18 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
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
|
||||
FMAXS(q1, v2, 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
|
||||
FCMEQS(q1, v2, v2); // 0 if src1 was NaN
|
||||
MOV32w(x5, 0x00400000);
|
||||
VMOVQSfrom(q0, 0, x5);
|
||||
VORR(q0, v2, q0); // QNaN(src1)
|
||||
VBIF(q2, q0, q1); // where src1 was NaN, use QNaN(src1)
|
||||
} else {
|
||||
FDIVS(q2, v2, v1); // the high part of the vector is erased...
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "emu/x64compstrings.h"
|
||||
#include "x64test.h"
|
||||
#include "dynarec/dynarec_next.h"
|
||||
#include "random.h"
|
||||
|
||||
static const int8_t mask_shift8[] = { -7, -6, -5, -4, -3, -2, -1, 0 };
|
||||
static const int8_t mask_string8[] = { 7, 6, 5, 4, 3, 2, 1, 0 };
|
||||
@@ -83,6 +84,9 @@ uintptr_t getConst(arm64_consts_t which)
|
||||
case const_native_fstp: return (uintptr_t)native_fstp;
|
||||
case const_native_frstor: return (uintptr_t)native_frstor;
|
||||
case const_native_next: return (uintptr_t)native_next;
|
||||
case const_native_next_invalidate: return (uintptr_t)arm64_next_invalid;
|
||||
case const_native_crc32: return (uintptr_t)arm64_crc;
|
||||
case const_native_x31: return (uintptr_t)arm64_x31_hash;
|
||||
case const_int3: return (uintptr_t)EmuInt3;
|
||||
case const_x86syscall: return (uintptr_t)EmuX86Syscall;
|
||||
case const_x64syscall: return (uintptr_t)EmuX64Syscall;
|
||||
|
||||
@@ -47,6 +47,9 @@ typedef enum arm64_consts_s {
|
||||
const_native_fstp,
|
||||
const_native_frstor,
|
||||
const_native_next,
|
||||
const_native_next_invalidate,
|
||||
const_native_crc32,
|
||||
const_native_x31,
|
||||
const_int3,
|
||||
const_x86syscall,
|
||||
const_x64syscall,
|
||||
|
||||
@@ -148,14 +148,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
IFX(X_CF|X_PF|X_ZF) {
|
||||
if(ST_IS_F(0)) {
|
||||
FCMPS(v1, v2);
|
||||
} else {
|
||||
FCMPD(v1, v2);
|
||||
}
|
||||
}
|
||||
FCOMI(x1, x2);
|
||||
FCOMI(x1, x2, ST_IS_F(0), v1, v2);
|
||||
break;
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
@@ -169,14 +162,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
IFX(X_CF|X_PF|X_ZF) {
|
||||
if(ST_IS_F(0)) {
|
||||
FCMPS(v1, v2);
|
||||
} else {
|
||||
FCMPD(v1, v2);
|
||||
}
|
||||
}
|
||||
FCOMI(x1, x2);
|
||||
FCOMI(x1, x2,ST_IS_F(0), v1, v2);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -101,15 +101,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
IFX(X_CF|X_PF|X_ZF) {
|
||||
if(ST_IS_F(0))
|
||||
{
|
||||
FCMPS(v1, v2);
|
||||
} else {
|
||||
FCMPD(v1, v2);
|
||||
}
|
||||
}
|
||||
FCOMI(x1, x2);
|
||||
FCOMI(x1, x2,ST_IS_F(0), v1, v2);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xF0:
|
||||
@@ -124,15 +116,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
IFX(X_CF|X_PF|X_ZF) {
|
||||
if(ST_IS_F(0))
|
||||
{
|
||||
FCMPS(v1, v2);
|
||||
} else {
|
||||
FCMPD(v1, v2);
|
||||
}
|
||||
}
|
||||
FCOMI(x1, x2);
|
||||
FCOMI(x1, x2, ST_IS_F(0), v1, v2);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
|
||||
@@ -1713,35 +1713,42 @@ void emit_neg16(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
CSETw(s4, cNE);
|
||||
BFIw(xFlags, s4, F_CF, 1);
|
||||
}
|
||||
IFX(X_AF|X_OF) {
|
||||
IFX(X_AF) {
|
||||
MOVw_REG(s3, s1);
|
||||
}
|
||||
NEGw_REG(s1, s1);
|
||||
IFX(X_ZF) {
|
||||
ANDSw_mask(s1, s1, 0, 15); //mask=0xffff
|
||||
IFX(X_OF|X_ZF|X_SF) {
|
||||
SUBSw_REG_LSL(s1, xZR, s1, 16);
|
||||
LSRw(s1, s1, 16);
|
||||
} else {
|
||||
NEGw_REG(s1, s1);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_AF|X_OF) {
|
||||
IFX(X_AF) {
|
||||
ORRw_REG(s3, s3, s1); // bc = op1 | res
|
||||
IFX(X_AF) {
|
||||
LSRw(s4, s3, 3);
|
||||
BFIw(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
}
|
||||
IFX(X_OF) {
|
||||
LSRw(s4, s3, 14);
|
||||
EORw_REG_LSR(s4, s4, s4, 1);
|
||||
BFIw(xFlags, s4, F_OF, 1); // OF: ((bc >> 14) ^ ((bc>>14)>>1)) & 1
|
||||
}
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 15);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
IFNATIVE(NF_SF) {} else {
|
||||
LSRw(s3, s1, 15);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_OF) {
|
||||
IFNATIVE(NF_VF) {} else {
|
||||
CSETw(s4, cVS);
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
@@ -1762,35 +1769,42 @@ void emit_neg8(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
CSETw(s4, cNE);
|
||||
BFIw(xFlags, s4, F_CF, 1);
|
||||
}
|
||||
IFX(X_AF|X_OF) {
|
||||
IFX(X_AF) {
|
||||
MOVw_REG(s3, s1);
|
||||
}
|
||||
NEGw_REG(s1, s1);
|
||||
IFX(X_ZF) {
|
||||
ANDSw_mask(s1, s1, 0, 7); // mask 0xff
|
||||
IFX(X_OF|X_ZF|X_SF) {
|
||||
SUBSw_REG_LSL(s1, xZR, s1, 24);
|
||||
LSRw(s1, s1, 24);
|
||||
} else {
|
||||
NEGw_REG(s1, s1);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_AF|X_OF) {
|
||||
IFX(X_AF) {
|
||||
ORRw_REG(s3, s3, s1); // bc = op1 | res
|
||||
IFX(X_AF) {
|
||||
LSRw(s4, s3, 3);
|
||||
BFIw(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
}
|
||||
IFX(X_OF) {
|
||||
LSRw(s4, s3, 6);
|
||||
EORx_REG_LSR(s4, s4, s4, 1);
|
||||
BFIw(xFlags, s4, F_OF, 1); // OF: ((bc >> 6) ^ ((bc>>6)>>1)) & 1
|
||||
}
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 7);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
IFNATIVE(NF_SF) {} else {
|
||||
LSRw(s3, s1, 7);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_OF) {
|
||||
IFNATIVE(NF_VF) {} else {
|
||||
CSETw(s4, cVS);
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
|
||||
@@ -704,6 +704,9 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ZF, SF_SUBSET);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
if(!ALIGNED_ATOMICxw) {
|
||||
// commit df before branch, CALL_S in GPF path has FORCE_DFNONE
|
||||
if(rex.w && BOX64DRENV(dynarec_safeflags)>1)
|
||||
CHECK_DFNONE(0);
|
||||
if(cpuext.uscat) {
|
||||
if(rex.w) {
|
||||
TSTx_mask(wback, 1, 0, 3);
|
||||
@@ -724,13 +727,14 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOVx_REG(x4, xRBX);
|
||||
MOVx_REG(x5, xRCX);
|
||||
CASPALxw(x2, x4, wback);
|
||||
// preserve upper bits of EAX/EDX if equal, per CMPXCHG8B semantics
|
||||
CMPSxw_REG(x2, xRAX);
|
||||
CCMPxw(x3, xRDX, 0, cEQ);
|
||||
CSELx(xRAX, xRAX, x2, cEQ);
|
||||
CSELx(xRDX, xRDX, x3, cEQ);
|
||||
UFLAG_IF {
|
||||
CMPSxw_REG(x2, xRAX);
|
||||
CCMPxw(x3, xRDX, 0, cEQ);
|
||||
IFNATIVE(NF_EQ) {} else {CSETw(x1, cEQ);}
|
||||
}
|
||||
MOVx_REG(xRAX, x2);
|
||||
MOVx_REG(xRDX, x3);
|
||||
if(!ALIGNED_ATOMICxw) {
|
||||
B_MARK3_nocond;
|
||||
}
|
||||
@@ -818,11 +822,16 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETGB(x2);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
MOVx_REG(x6, xFlags);
|
||||
MRS_nzcv(x87pc);
|
||||
MARKLOCK;
|
||||
MOVx_REG(xFlags, x6);
|
||||
MSR_nzcv(x87pc);
|
||||
LDAXRB(x1, wback);
|
||||
emit_adc8(dyn, ninst, x1, x2, x4, x5);
|
||||
STLXRB(x4, x1, wback);
|
||||
CBNZx_MARKLOCK(x4);
|
||||
NATIVE_RESTORE_X87PC();
|
||||
}
|
||||
break;
|
||||
case 0x11:
|
||||
@@ -838,11 +847,16 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETGD;
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
MOVx_REG(x6, xFlags);
|
||||
MRS_nzcv(x87pc);
|
||||
MARKLOCK;
|
||||
MOVx_REG(xFlags, x6);
|
||||
MSR_nzcv(x87pc);
|
||||
LDAXRxw(x1, wback);
|
||||
emit_adc32(dyn, ninst, rex, x1, gd, x4, x5);
|
||||
STLXRxw(x4, x1, wback);
|
||||
CBNZx_MARKLOCK(x4);
|
||||
NATIVE_RESTORE_X87PC();
|
||||
}
|
||||
break;
|
||||
case 0x20:
|
||||
@@ -1093,11 +1107,16 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x5, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 1);
|
||||
u8 = F8;
|
||||
wb1 = 1;
|
||||
MOVx_REG(x6, xFlags);
|
||||
MRS_nzcv(x87pc);
|
||||
MARKLOCK;
|
||||
MOVx_REG(xFlags, x6);
|
||||
MSR_nzcv(x87pc);
|
||||
LDAXRB(x1, wback);
|
||||
emit_adc8c(dyn, ninst, x1, u8, x2, x4, x3);
|
||||
STLXRB(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
NATIVE_RESTORE_X87PC();
|
||||
}
|
||||
break;
|
||||
case 3: //SBB
|
||||
@@ -1113,11 +1132,16 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x5, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 1);
|
||||
u8 = F8;
|
||||
wb1 = 1;
|
||||
MOVx_REG(x6, xFlags);
|
||||
MRS_nzcv(x87pc);
|
||||
MARKLOCK;
|
||||
MOVx_REG(xFlags, x6);
|
||||
MSR_nzcv(x87pc);
|
||||
LDAXRB(x1, wback);
|
||||
emit_sbb8c(dyn, ninst, x1, u8, x2, x4, x3);
|
||||
STLXRB(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
NATIVE_RESTORE_X87PC();
|
||||
}
|
||||
break;
|
||||
case 4: //AND
|
||||
@@ -1345,11 +1369,16 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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);
|
||||
MOVx_REG(x6, xFlags);
|
||||
MRS_nzcv(x87pc);
|
||||
MARKLOCK;
|
||||
MOVx_REG(xFlags, x6);
|
||||
MSR_nzcv(x87pc);
|
||||
LDAXRxw(x1, wback);
|
||||
emit_adc32(dyn, ninst, rex, x1, x5, x3, x4);
|
||||
STLXRxw(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
NATIVE_RESTORE_X87PC();
|
||||
}
|
||||
break;
|
||||
case 3: //SBB
|
||||
@@ -1365,11 +1394,16 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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);
|
||||
MOVx_REG(x6, xFlags);
|
||||
MRS_nzcv(x87pc);
|
||||
MARKLOCK;
|
||||
MOVx_REG(xFlags, x6);
|
||||
MSR_nzcv(x87pc);
|
||||
LDAXRxw(x1, wback);
|
||||
emit_sbb32(dyn, ninst, rex, x1, x5, x3, x4);
|
||||
STLXRxw(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
NATIVE_RESTORE_X87PC();
|
||||
}
|
||||
break;
|
||||
case 4: //AND
|
||||
@@ -1650,7 +1684,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
MARKLOCK;
|
||||
LDAXRxw(x1, wback);
|
||||
MVNw_REG(x1, x1);
|
||||
MVNxw_REG(x1, x1);
|
||||
STLXRxw(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
|
||||
@@ -31,14 +31,15 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
uint64_t u64, j64;
|
||||
int32_t i32, i32_;
|
||||
int cacheupd = 0;
|
||||
int v0, v1;
|
||||
int q0, q1;
|
||||
int d0, d1;
|
||||
int v0, v1, v2;
|
||||
int q0, q1, q2;
|
||||
int d0, d1, d2;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
|
||||
MAYUSE(d0);
|
||||
MAYUSE(d1);
|
||||
MAYUSE(d2);
|
||||
MAYUSE(q0);
|
||||
MAYUSE(q1);
|
||||
MAYUSE(v0);
|
||||
@@ -207,6 +208,10 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(cpuext.crc32) {
|
||||
CRC32Cxw(gd, gd, ed);
|
||||
} else {
|
||||
if (ed == gd) {
|
||||
MOVxw_REG(x1, ed);
|
||||
ed = x1;
|
||||
}
|
||||
MOV32w(x2, 0x82f63b78);
|
||||
for(int j=0; j<4*(1+rex.w); ++j) {
|
||||
UBFXxw(x3, ed, 8*j, 8);
|
||||
@@ -257,6 +262,8 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
FMOVD(v2, d1); // save src1
|
||||
// check if any input value was NAN
|
||||
FMAXD(v0, d0, d1); // propagate NAN
|
||||
FCMEQD(v0, v0, v0); // 0 if NAN, 1 if not NAN
|
||||
@@ -265,6 +272,11 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VBIC(q0, v0, q0); // forget it in any input was a NAN already
|
||||
SHL_64(q0, q0, 63); // only keep the sign bit
|
||||
VORR(v1, v1, q0); // NAN -> -NAN
|
||||
FCMEQD(v0, v2, v2); // 0 if src1 was NaN
|
||||
MOV64x(x5, 0x0008000000000000ULL);
|
||||
VMOVQDfrom(q0, 0, x5);
|
||||
VORR(v2, v2, q0); // quiet any SNaN in src1
|
||||
VBIF(v1, v2, v0); // where src1 was NaN, use QNaN(src1)
|
||||
} else {
|
||||
FADDD(v1, d1, d0); // the high part of the vector is erased...
|
||||
}
|
||||
@@ -279,6 +291,8 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
FMOVD(v2, d1); // save src1
|
||||
// check if any input value was NAN
|
||||
FMAXD(v0, d0, d1); // propagate NAN
|
||||
FCMEQD(v0, v0, v0); // 0 if NAN, 1 if not NAN
|
||||
@@ -287,6 +301,11 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VBIC(q0, v0, q0); // forget it in any input was a NAN already
|
||||
SHL_64(q0, q0, 63); // only keep the sign bit
|
||||
VORR(v1, v1, q0); // NAN -> -NAN
|
||||
FCMEQD(v0, v2, v2); // 0 if src1 was NaN
|
||||
MOV64x(x5, 0x0008000000000000ULL);
|
||||
VMOVQDfrom(q0, 0, x5);
|
||||
VORR(v2, v2, q0); // quiet any SNaN in src1
|
||||
VBIF(v1, v2, v0); // where src1 was NaN, use QNaN(src1)
|
||||
} else {
|
||||
FMULD(v1, d1, d0);
|
||||
}
|
||||
@@ -317,6 +336,8 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
FMOVD(v2, d1); // save src1
|
||||
// check if any input value was NAN
|
||||
FMAXD(v0, d0, d1); // propagate NAN
|
||||
FCMEQD(v0, v0, v0); // 0 if NAN, 1 if not NAN
|
||||
@@ -325,6 +346,11 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VBIC(q0, v0, q0); // forget it in any input was a NAN already
|
||||
SHL_64(q0, q0, 63); // only keep the sign bit
|
||||
VORR(v1, v1, q0); // NAN -> -NAN
|
||||
FCMEQD(v0, v2, v2); // 0 if src1 was NaN
|
||||
MOV64x(x5, 0x0008000000000000ULL);
|
||||
VMOVQDfrom(q0, 0, x5);
|
||||
VORR(v2, v2, q0); // quiet any SNaN in src1
|
||||
VBIF(v1, v2, v0); // where src1 was NaN, use QNaN(src1)
|
||||
} else {
|
||||
FSUBD(v1, d1, d0);
|
||||
}
|
||||
@@ -349,6 +375,8 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
FMOVD(v2, v0); // save src1
|
||||
// check if any input value was NAN
|
||||
FMAXD(d0, v0, v1); // propagate NAN
|
||||
FCMEQD(d0, d0, d0); // 0 if NAN, 1 if not NAN
|
||||
@@ -357,6 +385,11 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VBIC(q0, d0, q0); // forget it in any input was a NAN already
|
||||
SHL_64(q0, q0, 63); // only keep the sign bit
|
||||
VORR(d1, d1, q0); // NAN -> -NAN
|
||||
FCMEQD(d0, v2, v2); // 0 if src1 was NaN
|
||||
MOV64x(x5, 0x0008000000000000ULL);
|
||||
VMOVQDfrom(q0, 0, x5);
|
||||
VORR(v2, v2, q0); // quiet any SNaN in src1
|
||||
VBIF(d1, v2, d0); // where src1 was NaN, use QNaN(src1)
|
||||
} else {
|
||||
FDIVD(d1, v0, v1);
|
||||
}
|
||||
@@ -414,16 +447,25 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
VFMAXPQS(v0, q1, q0); // propagate NAN
|
||||
VFCMEQQS(v0, v0, v0); // 0 if NAN, 1 if not NAN
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
VUZP1Q_32(d1, q1, q0); // d1 = {q1[0], q1[2], q0[0], q0[2]}
|
||||
VFCMEQQS(v0, q1, q1); // per-element non-NaN mask for Gx
|
||||
VFCMEQQS(d0, q0, q0); // per-element non-NaN mask for Ex
|
||||
VUZP1Q_32(v1, v0, d0); // even elements of pairs
|
||||
VUZP2Q_32(v0, v0, d0); // odd elements of pairs
|
||||
VANDQ(v0, v1, v0); // v0 = both non-NaN per pair
|
||||
}
|
||||
VFADDPQS(q1, q1, q0);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
VFCMEQQS(v1, q1, q1); // 0 => out is NAN
|
||||
VBICQ(v1, v0, v1); // forget it in any input was a NAN already
|
||||
VSHLQ_32(v1, v1, 31); // only keep the sign bit
|
||||
VORRQ(q1, q1, v1); // NAN -> -NAN
|
||||
VFCMEQQS(v1, d1, d1); // v1 = 0xFFFFFFFF where src1 non-NaN, 0 where NaN
|
||||
MOVIQ_32_lsl(d0, 0x40, 2); // d0 = 0x00400000 in all lanes (QNaN bit)
|
||||
VORRQ(d0, d1, d0); // d0 = QNaN(src1) = src1 | 0x00400000
|
||||
VBIFQ(q1, d0, v1); // where src1 was NaN (v1=0): q1 = d0 (QNaN(src1))
|
||||
VFCMEQQS(v1, q1, q1); // 0 => out is NAN
|
||||
VBICQ(v1, v0, v1); // forget it in any input was a NAN already
|
||||
VSHLQ_32(v1, v1, 31); // only keep the sign bit
|
||||
VORRQ(q1, q1, v1); // NAN -> -NAN
|
||||
}
|
||||
break;
|
||||
case 0x7D:
|
||||
@@ -432,20 +474,27 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
VUZP1Q_32(d0, v0, v1);
|
||||
VUZP2Q_32(v0, v0, v1);
|
||||
VUZP1Q_32(d0, v0, v1); // d0 = src1 (even elements: first of each pair)
|
||||
VUZP2Q_32(v0, v0, v1); // v0 = src2 (odd elements: second of each pair)
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
VFMAXQS(d1, d0, v0); // propagate NAN
|
||||
VFCMEQQS(d1, d1, d1); // 0 if NAN, 1 if not NAN
|
||||
d2 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
VMOVQ(q0, d0); // save src1 for NaN priority
|
||||
VFCMEQQS(d1, d0, d0); // even elements non-NaN
|
||||
VFCMEQQS(d2, v0, v0); // odd elements non-NaN
|
||||
VANDQ(d1, d1, d2); // d1 = both non-NaN per pair
|
||||
}
|
||||
VFSUBQS(v0, d0, v0);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
VFCMEQQS(d0, v0, v0); // 0 => out is NAN
|
||||
VBICQ(d1, d1, d0); // forget it in any input was a NAN already
|
||||
VSHLQ_32(d1, d1, 31); // only keep the sign bit
|
||||
VORRQ(v0, v0, d1); // NAN -> -NAN
|
||||
VFCMEQQS(d2, q0, q0); // d2 = src1 non-NaN mask
|
||||
MOVIQ_32_lsl(d0, 0x40, 2); // d0 = 0x00400000 (QNaN bit)
|
||||
VORRQ(d0, q0, d0); // d0 = QNaN(src1)
|
||||
VBIFQ(v0, d0, d2); // where src1 NaN: replace with QNaN(src1)
|
||||
VFCMEQQS(d0, v0, v0); // 0 => out is NAN
|
||||
VBICQ(d1, d1, d0); // forget it in any input was a NAN already
|
||||
VSHLQ_32(d1, d1, 31); // only keep the sign bit
|
||||
VORRQ(v0, v0, d1); // NAN -> -NAN
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -483,6 +532,23 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GOCOND(0x80, "J", "Id");
|
||||
#undef GO
|
||||
|
||||
case 0xA3: // ignore F2 prefix
|
||||
case 0xA4:
|
||||
case 0xA5:
|
||||
case 0xAB:
|
||||
case 0xAC:
|
||||
case 0xAD:
|
||||
case 0xAF:
|
||||
case 0xB3:
|
||||
case 0xB7:
|
||||
case 0xBA:
|
||||
case 0xBB:
|
||||
case 0xBC: // this one is still BSR, not TZCNT
|
||||
case 0xBD: // and this one is still BSF, not LZCNT
|
||||
case 0xC1:
|
||||
case 0xCD:
|
||||
return dynarec64_0F(dyn, addr-1, ip, ninst, rex, ok, need_epilog);
|
||||
|
||||
case 0xAE:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
@@ -522,9 +588,27 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
VMOVQ(v2, v0); // save src1
|
||||
VFCMEQQS(q0, v0, v0);
|
||||
VFCMEQQS(q1, v1, v1);
|
||||
VANDQ(q1, q0, q1); // q1 = both non-NaN
|
||||
}
|
||||
TABLE64C(x2, const_4f_m1_1_m1_1);
|
||||
VLDR128_U12(q0, x2, 0);
|
||||
VFMLAQS(v0, v1, q0);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
VFCMEQQS(q0, v0, v0); // 0 where result is NaN
|
||||
VBICQ(q0, q1, q0); // both non-NaN but result NaN
|
||||
VSHLQ_32(q0, q0, 31); // sign bit only
|
||||
VORRQ(v0, v0, q0); // force -NaN
|
||||
VFCMEQQS(q0, v2, v2); // 0 if src1 was NaN
|
||||
MOVIQ_32_lsl(q1, 0x40, 2); // QNaN bit 0x00400000
|
||||
VORRQ(v2, v2, q1); // quiet any SNaN
|
||||
VBIFQ(v0, v2, q0); // where src1 NaN: use QNaN(src1)
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xD6:
|
||||
|
||||
@@ -28,7 +28,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback;
|
||||
uint64_t u64;
|
||||
int v0, v1;
|
||||
int v0, v1, v2;
|
||||
int q0, q1;
|
||||
int d0, d1;
|
||||
int64_t fixedaddress;
|
||||
@@ -288,6 +288,8 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
FMOVS(v2, d1); // save src1
|
||||
// check if any input value was NAN
|
||||
FMAXS(v0, d0, d1); // propagate NAN
|
||||
FCMEQS(v0, v0, v0); // 0 if NAN, 1 if not NAN
|
||||
@@ -296,6 +298,12 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
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
|
||||
// src1 NaN priority
|
||||
FCMEQS(v0, v2, v2); // 0 if src1 was NaN
|
||||
MOV32w(x5, 0x00400000);
|
||||
VMOVQSfrom(q0, 0, x5);
|
||||
VORR(v2, v2, q0); // quiet any SNaN in src1
|
||||
VBIF(v1, v2, v0); // where src1 was NaN, use QNaN(src1)
|
||||
} else {
|
||||
FADDS(v1, d1, d0); // the high part of the vector is erased...
|
||||
}
|
||||
@@ -310,6 +318,8 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
FMOVS(v2, d1); // save src1
|
||||
// check if any input value was NAN
|
||||
FMAXS(v0, d0, d1); // propagate NAN
|
||||
FCMEQS(v0, v0, v0); // 0 if NAN, 1 if not NAN
|
||||
@@ -318,6 +328,12 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
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
|
||||
// src1 NaN priority
|
||||
FCMEQS(v0, v2, v2); // 0 if src1 was NaN
|
||||
MOV32w(x5, 0x00400000);
|
||||
VMOVQSfrom(q0, 0, x5);
|
||||
VORR(v2, v2, q0); // quiet any SNaN in src1
|
||||
VBIF(v1, v2, v0); // where src1 was NaN, use QNaN(src1)
|
||||
} else {
|
||||
FMULS(v1, d1, d0); // the high part of the vector is erased...
|
||||
}
|
||||
@@ -386,6 +402,8 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
FMOVS(v2, d1); // save src1
|
||||
// check if any input value was NAN
|
||||
FMAXS(v0, d0, d1); // propagate NAN
|
||||
FCMEQS(v0, v0, v0); // 0 if NAN, 1 if not NAN
|
||||
@@ -394,6 +412,12 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
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
|
||||
// src1 NaN priority
|
||||
FCMEQS(v0, v2, v2); // 0 if src1 was NaN
|
||||
MOV32w(x5, 0x00400000);
|
||||
VMOVQSfrom(q0, 0, x5);
|
||||
VORR(v2, v2, q0); // quiet any SNaN in src1
|
||||
VBIF(v1, v2, v0); // where src1 was NaN, use QNaN(src1)
|
||||
} else {
|
||||
FSUBS(v1, d1, d0); // the high part of the vector is erased...
|
||||
}
|
||||
@@ -418,6 +442,8 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
FMOVS(v2, d1); // save src1
|
||||
// check if any input value was NAN
|
||||
FMAXS(v0, d0, d1); // propagate NAN
|
||||
FCMEQS(v0, v0, v0); // 0 if NAN, 1 if not NAN
|
||||
@@ -426,6 +452,12 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
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
|
||||
// src1 NaN priority
|
||||
FCMEQS(v0, v2, v2); // 0 if src1 was NaN
|
||||
MOV32w(x5, 0x00400000);
|
||||
VMOVQSfrom(q0, 0, x5);
|
||||
VORR(v2, v2, q0); // quiet any SNaN in src1
|
||||
VBIF(v1, v2, v0); // where src1 was NaN, use QNaN(src1)
|
||||
} else {
|
||||
FDIVS(v1, d1, d0); // the high part of the vector is erased...
|
||||
}
|
||||
@@ -531,7 +563,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(((nextop>>3)&7)==1) {INST_NAME("RDGSBASE");} else {INST_NAME("RDFSBASE");}
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
int seg = _FS + ((nextop>>3)&7);
|
||||
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
MOVxw_REG(ed, x4);
|
||||
}
|
||||
break;
|
||||
@@ -545,7 +577,12 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(((nextop>>3)&7)==3) {INST_NAME("WRGSBASE");} else {INST_NAME("WRFSBASE");}
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
int seg = _FS + ((nextop>>3)&7)-2;
|
||||
STRx_U12(ed, xEmu, offsetof(x64emu_t, segs_offs[seg]));
|
||||
if (!rex.w) {
|
||||
MOVw_REG(x4, ed);
|
||||
STRx_U12(x4, xEmu, offsetof(x64emu_t, segs_offs[seg]));
|
||||
} else {
|
||||
STRx_U12(ed, xEmu, offsetof(x64emu_t, segs_offs[seg]));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
@@ -607,6 +644,21 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xA3: // ignore F3 prefix
|
||||
case 0xA4:
|
||||
case 0xA5:
|
||||
case 0xAC:
|
||||
case 0xAD:
|
||||
case 0xAF:
|
||||
case 0xB3:
|
||||
case 0xB7:
|
||||
case 0xBA:
|
||||
case 0xBB:
|
||||
case 0xBF:
|
||||
case 0xC1:
|
||||
case 0xCD:
|
||||
return dynarec64_0F(dyn, addr-1, ip, ninst, rex, ok, need_epilog);
|
||||
|
||||
case 0xBC:
|
||||
INST_NAME("TZCNT Gd, Ed");
|
||||
if (!BOX64DRENV(dynarec_safeflags)) {
|
||||
|
||||
@@ -786,14 +786,13 @@ void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t r
|
||||
}
|
||||
|
||||
static char buf[4096];
|
||||
int length = sprintf(buf, "barrier=%d state=%d/%s(%s->%s)/%d, %s=%X/%X, use=%X, need=%X/%X, sm=%d(%d/%d/%d)",
|
||||
int length = sprintf(buf, "barrier=%d state=%d/%s(%s->%s)/%c, set=%X/%X, use=%X, need=%X/%X, sm=%d(%d/%d/%d)",
|
||||
dyn->insts[ninst].x64.barrier,
|
||||
dyn->insts[ninst].x64.state_flags,
|
||||
df_status[dyn->f],
|
||||
df_status[dyn->insts[ninst].f_entry],
|
||||
df_status[dyn->insts[ninst].f_exit],
|
||||
dyn->insts[ninst].df_notneeded,
|
||||
dyn->insts[ninst].x64.may_set ? "may" : "set",
|
||||
dyn->insts[ninst].df_needed?'N':(dyn->insts[ninst].df_notneeded?'U':'-'),
|
||||
dyn->insts[ninst].x64.set_flags,
|
||||
dyn->insts[ninst].x64.gen_flags,
|
||||
dyn->insts[ninst].x64.use_flags,
|
||||
@@ -860,11 +859,11 @@ void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t r
|
||||
}
|
||||
length += sprintf(buf + length, ")%s", (dyn->need_dump > 1) ? "\e[0;32m" : "");
|
||||
}
|
||||
if (dyn->insts[ninst].n.xmm_used || dyn->insts[ninst].n.xmm_unneeded) {
|
||||
length += sprintf(buf + length, " xmmUsed=%04x/unneeded=%04x", dyn->insts[ninst].n.xmm_used, dyn->insts[ninst].n.xmm_unneeded);
|
||||
if (dyn->insts[ninst].n.xmm_used || dyn->insts[ninst].n.xmm_unneeded || dyn->insts[ninst].n.xmm_needed) {
|
||||
length += sprintf(buf + length, " xmmUsed=%04x/needed=%04x/unneeded=%04x", dyn->insts[ninst].n.xmm_used, dyn->insts[ninst].n.xmm_needed, dyn->insts[ninst].n.xmm_unneeded);
|
||||
}
|
||||
if (dyn->insts[ninst].n.ymm_used || dyn->insts[ninst].n.ymm_unneeded) {
|
||||
length += sprintf(buf + length, " ymmUsed=%04x/unneeded=%04x", dyn->insts[ninst].n.ymm_used, dyn->insts[ninst].n.ymm_unneeded);
|
||||
if (dyn->insts[ninst].n.ymm_used || dyn->insts[ninst].n.ymm_unneeded || dyn->insts[ninst].n.ymm_needed) {
|
||||
length += sprintf(buf + length, " ymmUsed=%04x/needed=%04x/unneeded=%04x", dyn->insts[ninst].n.ymm_used, dyn->insts[ninst].n.ymm_needed, dyn->insts[ninst].n.ymm_unneeded);
|
||||
}
|
||||
if (dyn->ymm_zero || dyn->insts[ninst].ymm0_add || dyn->insts[ninst].ymm0_sub || dyn->insts[ninst].ymm0_out) {
|
||||
length += sprintf(buf + length, " ymm0=(%04x/%04x+%04x-%04x=%04x)", dyn->ymm_zero, dyn->insts[ninst].ymm0_in, dyn->insts[ninst].ymm0_add, dyn->insts[ninst].ymm0_sub, dyn->insts[ninst].ymm0_out);
|
||||
@@ -902,7 +901,7 @@ void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t r
|
||||
}
|
||||
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) {
|
||||
if (BOX64ENV(dynarec_perf_map) && (BOX64ENV(dynarec_perf_map_fd) != -1) && dyn->insts[ninst].size) {
|
||||
writePerfMap(dyn->insts[ninst].x64.addr, dyn->native_start + dyn->insts[ninst].address, dyn->insts[ninst].size / 4, name);
|
||||
}
|
||||
if(length>sizeof(buf)) printf_log(LOG_NONE, "Warning: buf to small in inst_name_pass3 (%d vs %zd)\n", length, sizeof(buf));
|
||||
@@ -992,27 +991,23 @@ uint8_t mark_natflag(dynarec_arm_t* dyn, int ninst, uint8_t flag, int before)
|
||||
return flag;
|
||||
}
|
||||
|
||||
uint8_t flag2native(uint8_t flags)
|
||||
uint8_t flag2native(uint8_t flags, int vf_is_p)
|
||||
{
|
||||
uint8_t ret = 0;
|
||||
#ifdef ARM64
|
||||
if(flags&X_ZF) ret|=NF_EQ;
|
||||
if(flags&X_SF) ret|=NF_SF;
|
||||
if(flags&X_OF) ret|=NF_VF;
|
||||
if(!vf_is_p)
|
||||
if(flags&X_OF) ret|=NF_VF;
|
||||
if(flags&X_CF) ret|=NF_CF;
|
||||
if(vf_is_p)
|
||||
if(flags&X_PF) ret|=NF_PF_V; // but no opcode can generate both NF_VF & NF_PF_V at the same time!
|
||||
#else
|
||||
// no native flags on rv64 or la64
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
int flagIsNative(uint8_t flags)
|
||||
{
|
||||
if(flags&(X_AF|X_PF)) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static uint8_t getNativeFlagsUsed(dynarec_arm_t* dyn, int start, uint8_t flags)
|
||||
static uint8_t getNativeFlagsUsed(dynarec_arm_t* dyn, int start, uint8_t flags, int vf_is_p)
|
||||
{
|
||||
// propagate and check wich flags are actually used
|
||||
uint8_t used_flags = 0;
|
||||
@@ -1060,21 +1055,21 @@ static uint8_t getNativeFlagsUsed(dynarec_arm_t* dyn, int start, uint8_t flags)
|
||||
}
|
||||
if(ninst!=start && dyn->insts[ninst].x64.use_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)
|
||||
if(flag2native(dyn->insts[ninst].x64.use_flags, vf_is_p)!=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)) {
|
||||
if(used_flags&~flag2native(dyn->insts[ninst].x64.gen_flags&dyn->insts[ninst].x64.need_after))
|
||||
if((start!=ninst) && dyn->insts[ninst].x64.gen_flags && (flag2native(dyn->insts[ninst].x64.gen_flags&dyn->insts[ninst].x64.need_after, vf_is_p)&used_flags)) {
|
||||
if(used_flags&~flag2native(dyn->insts[ninst].x64.gen_flags&dyn->insts[ninst].x64.need_after, vf_is_p))
|
||||
return 0; // partial covert, not supported for now (TODO: this might be fixable)
|
||||
else
|
||||
return nat_flags_used?used_flags:0; // full covert... End of propagation
|
||||
}
|
||||
// check if flags are still needed
|
||||
if(!(flag2native(dyn->insts[ninst].x64.need_after)&flags))
|
||||
if(!(flag2native(dyn->insts[ninst].x64.need_after, vf_is_p)&flags))
|
||||
return nat_flags_used?used_flags:0;
|
||||
// check if flags are destroyed, cancel the use then
|
||||
if(dyn->insts[ninst].nat_flags_op && (start!=ninst))
|
||||
@@ -1100,13 +1095,15 @@ static void propagateNativeFlags(dynarec_arm_t* dyn, int start)
|
||||
{
|
||||
int ninst = start;
|
||||
// those are the flags generated by the opcode and used later on
|
||||
uint8_t flags = dyn->insts[ninst].set_nat_flags&flag2native(dyn->insts[ninst].x64.need_after);
|
||||
int vf_is_p = (dyn->insts[ninst].set_nat_flags&NF_PF_V)?1:0;
|
||||
uint8_t flags = dyn->insts[ninst].set_nat_flags&flag2native(dyn->insts[ninst].x64.need_after, vf_is_p);
|
||||
//check if they are actualy used before starting
|
||||
//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.use_flags)&~flags) return;
|
||||
uint8_t used_flags = getNativeFlagsUsed(dyn, start, flags);
|
||||
if(flag2native(dyn->insts[ninst].x64.use_flags, vf_is_p)&~flags) return;
|
||||
if(flag2native(dyn->insts[ninst].x64.need_after, vf_is_p)&~flags) return;
|
||||
uint8_t used_flags = getNativeFlagsUsed(dyn, start, flags, vf_is_p);
|
||||
//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
|
||||
int nc = dyn->insts[ninst].gen_inverted_carry?0:1;
|
||||
@@ -1123,17 +1120,17 @@ static void propagateNativeFlags(dynarec_arm_t* dyn, int start)
|
||||
return;
|
||||
}
|
||||
// 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))
|
||||
if((start!=ninst) && dyn->insts[ninst].x64.gen_flags && (flag2native(dyn->insts[ninst].x64.gen_flags&dyn->insts[ninst].x64.need_after, vf_is_p)&used_flags))
|
||||
return;
|
||||
// mark the opcode
|
||||
uint8_t use_flags = flag2native(dyn->insts[ninst].x64.need_before|dyn->insts[ninst].x64.need_after);
|
||||
if(dyn->insts[ninst].x64.use_flags) use_flags |= flag2native(dyn->insts[ninst].x64.use_flags); // should not change anything
|
||||
uint8_t use_flags = flag2native(dyn->insts[ninst].x64.need_before|dyn->insts[ninst].x64.need_after, vf_is_p);
|
||||
if(dyn->insts[ninst].x64.use_flags) use_flags |= flag2native(dyn->insts[ninst].x64.use_flags, vf_is_p); // should not change anything
|
||||
//printf_log(LOG_INFO, " marking ninst=%d with %x | %x&%x => %x\n", ninst, dyn->insts[ninst].need_nat_flags, used_flags, use_flags, dyn->insts[ninst].need_nat_flags | (used_flags&use_flags));
|
||||
dyn->insts[ninst].need_nat_flags |= used_flags&use_flags;
|
||||
if(carry) dyn->insts[ninst].normal_carry = nc;
|
||||
if(carry && dyn->insts[ninst].invert_carry) nc = 0;
|
||||
// check if flags are still needed
|
||||
if(!(flag2native(dyn->insts[ninst].x64.need_after)&used_flags))
|
||||
if(!(flag2native(dyn->insts[ninst].x64.need_after, vf_is_p)&used_flags))
|
||||
return;
|
||||
// go next
|
||||
if(!dyn->insts[ninst].x64.has_next) {
|
||||
@@ -1154,7 +1151,7 @@ void updateNativeFlags(dynarec_native_t* dyn)
|
||||
return;
|
||||
// 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)) {
|
||||
if(flag2native(dyn->insts[ninst].x64.gen_flags,(dyn->insts[ninst].set_nat_flags&NF_PF_V)?1:0) && (dyn->insts[ninst].nat_flags_op==NAT_FLAG_OP_TOUCH)) {
|
||||
propagateNativeFlags(dyn, ninst);
|
||||
}
|
||||
}
|
||||
@@ -1184,7 +1181,7 @@ int nativeFlagsNeedsTransform(dynarec_arm_t* dyn, int ninst)
|
||||
flags_after = dyn->insts[jmp].before_nat_flags;
|
||||
nc_after = dyn->insts[jmp].normal_carry_before;
|
||||
}
|
||||
uint8_t flags_x86 = flag2native(dyn->insts[jmp].x64.need_before);
|
||||
uint8_t flags_x86 = flag2native(dyn->insts[jmp].x64.need_before, (dyn->insts[jmp].before_nat_flags&NF_PF_V)?1:0);
|
||||
flags_x86 &= ~flags_after;
|
||||
if((flags_before&NF_CF) && (flags_after&NF_CF) && (nc_before!=nc_after))
|
||||
return 1;
|
||||
@@ -1223,34 +1220,89 @@ static uint32_t getXYMMMask(dynarec_arm_t* dyn, int ninst)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void propagateXYMMUneeded(dynarec_arm_t* dyn, int ninst, uint16_t mask_x, uint16_t mask_y)
|
||||
static void propagateXYMMNeeded(dynarec_arm_t* dyn, int ninst, uint16_t mask_x, uint16_t mask_y)
|
||||
{
|
||||
if(!ninst) return;
|
||||
ninst = getNominalPred(dyn, ninst);
|
||||
while(ninst>=0) {
|
||||
mask_x &= ~dyn->insts[ninst].n.xmm_used;
|
||||
mask_y &= ~dyn->insts[ninst].n.ymm_used;
|
||||
if(!mask_x && !mask_y) return; // used, value is needed
|
||||
if(dyn->insts[ninst].x64.barrier&BARRIER_FLOAT) return; // barrier, value is needed
|
||||
// removed unneeded regs
|
||||
mask_x &= ~dyn->insts[ninst].n.xmm_unneeded;
|
||||
mask_y &= ~dyn->insts[ninst].n.ymm_unneeded;
|
||||
if(!mask_x && !mask_y) return; // already handled
|
||||
if(dyn->insts[ninst].x64.jmp) return; // stop when a jump is detected, that gets too complicated
|
||||
dyn->insts[ninst].n.xmm_unneeded |= mask_x; // flags
|
||||
dyn->insts[ninst].n.ymm_unneeded |= mask_y; // flags
|
||||
ninst = getNominalPred(dyn, ninst); // continue
|
||||
// removed already needed from mask
|
||||
mask_x &= ~dyn->insts[ninst].n.xmm_needed;
|
||||
mask_y &= ~dyn->insts[ninst].n.ymm_needed;
|
||||
// already handled
|
||||
if(!mask_x && !mask_y) return;
|
||||
// added the unneeded value
|
||||
dyn->insts[ninst].n.xmm_needed |= mask_x;
|
||||
dyn->insts[ninst].n.ymm_needed |= mask_y;
|
||||
for(int i=1; i<dyn->insts[ninst].pred_sz; ++i) {
|
||||
int j = dyn->insts[ninst].pred[i];
|
||||
// barrier or callret, value is needed
|
||||
if(!(dyn->insts[j].x64.barrier&BARRIER_FLOAT)
|
||||
&& !(dyn->insts[j].x64.has_callret))
|
||||
propagateXYMMNeeded(dyn, j, mask_x, mask_y);
|
||||
}
|
||||
if(dyn->insts[ninst].pred_sz)
|
||||
ninst = dyn->insts[ninst].pred[0];
|
||||
else
|
||||
ninst = -1;
|
||||
if(ninst>=0)
|
||||
if((dyn->insts[ninst].x64.barrier&BARRIER_FLOAT)
|
||||
|| (dyn->insts[ninst].x64.has_callret))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void propagateXYMMUneeded(dynarec_arm_t* dyn, int ninst, uint16_t mask_x, uint16_t mask_y)
|
||||
{
|
||||
while(ninst>=0) {
|
||||
// removed needed regs
|
||||
mask_x &= ~dyn->insts[ninst].n.xmm_needed;
|
||||
mask_y &= ~dyn->insts[ninst].n.ymm_needed;
|
||||
// removed already unneeded from mask
|
||||
mask_x &= ~dyn->insts[ninst].n.xmm_unneeded;
|
||||
mask_y &= ~dyn->insts[ninst].n.ymm_unneeded;
|
||||
// already handled
|
||||
if(!mask_x && !mask_y) return;
|
||||
// barrier or callret, value is needed
|
||||
if(dyn->insts[ninst].x64.barrier&BARRIER_FLOAT) return;
|
||||
if(dyn->insts[ninst].x64.has_callret) return;
|
||||
// added the unneeded value
|
||||
dyn->insts[ninst].n.xmm_unneeded |= mask_x;
|
||||
dyn->insts[ninst].n.ymm_unneeded |= mask_y;
|
||||
for(int i=1; i<dyn->insts[ninst].pred_sz; ++i)
|
||||
propagateXYMMUneeded(dyn, dyn->insts[ninst].pred[i], mask_x, mask_y);
|
||||
if(dyn->insts[ninst].pred_sz)
|
||||
ninst = dyn->insts[ninst].pred[0];
|
||||
else
|
||||
ninst = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void updateUneeded(dynarec_arm_t* dyn)
|
||||
{
|
||||
propagate_nodf(dyn);
|
||||
|
||||
if(!dyn->use_xmm && !dyn->use_ymm)
|
||||
return;
|
||||
for(int ninst=0; ninst<dyn->size; ++ninst) {
|
||||
if(dyn->insts[ninst].n.xmm_unneeded || dyn->insts[ninst].n.ymm_unneeded)
|
||||
propagateXYMMUneeded(dyn, ninst, dyn->insts[ninst].n.xmm_unneeded, dyn->insts[ninst].n.ymm_unneeded);
|
||||
if(dyn->insts[ninst].df_notneeded)
|
||||
propagate_nodf(dyn, ninst);
|
||||
// first propagate the needed regs: those which are used and are not unneeded
|
||||
for(int ninst=dyn->size-1; ninst>=0; --ninst) {
|
||||
uint16_t xmm_needed = dyn->insts[ninst].n.xmm_used&~dyn->insts[ninst].n.xmm_unneeded;
|
||||
uint16_t ymm_needed = dyn->insts[ninst].n.ymm_used&~dyn->insts[ninst].n.ymm_unneeded;
|
||||
if((dyn->insts[ninst].x64.barrier&BARRIER_FLOAT) || (dyn->insts[ninst].x64.jmp && (dyn->insts[ninst].x64.jmp_insts==-1)))
|
||||
{
|
||||
if(dyn->use_xmm) xmm_needed = 0xffff;
|
||||
if(dyn->use_ymm) ymm_needed = 0xffff;
|
||||
}
|
||||
if(xmm_needed || ymm_needed)
|
||||
propagateXYMMNeeded(dyn, ninst, xmm_needed, ymm_needed);
|
||||
|
||||
}
|
||||
// then proagate the unneeded one: those which are not needed (not used anymore and will be overwritten)
|
||||
for(int ninst=dyn->size-1; ninst>=0; --ninst) {
|
||||
if(dyn->insts[ninst].n.xmm_unneeded || dyn->insts[ninst].n.ymm_unneeded) {
|
||||
for(int i=0; i<dyn->insts[ninst].pred_sz; ++i)
|
||||
propagateXYMMUneeded(dyn, dyn->insts[ninst].pred[i], dyn->insts[ninst].n.xmm_unneeded, dyn->insts[ninst].n.ymm_unneeded);
|
||||
}
|
||||
}
|
||||
// try to add some preload of XYMM on jump were it would make sense
|
||||
for(int ninst=0; ninst<dyn->size; ++ninst)
|
||||
@@ -1417,6 +1469,7 @@ void updateYmm0s(dynarec_arm_t* dyn, int ninst, int max_ninst_reached)
|
||||
}
|
||||
} else if (can_incr) {
|
||||
// We always have ninst == max_ninst_reached when can_incr == 1
|
||||
dyn->insts[ninst].ymm0_out = dyn->insts[ninst].ymm0_add & ~dyn->insts[ninst].ymm0_sub;
|
||||
++max_ninst_reached;
|
||||
} else {
|
||||
// We didn't update anything, we can leave
|
||||
@@ -1430,6 +1483,7 @@ void updateYmm0s(dynarec_arm_t* dyn, int ninst, int max_ninst_reached)
|
||||
// AVX helpers
|
||||
void avx_mark_zero(dynarec_arm_t* dyn, int ninst, int reg)
|
||||
{
|
||||
dyn->use_ymm = 1;
|
||||
dyn->ymm_zero |= (1<<reg);
|
||||
}
|
||||
|
||||
@@ -1449,6 +1503,7 @@ int is_avx_zero_unset(dynarec_arm_t* dyn, int ninst, int reg)
|
||||
|
||||
void avx_mark_zero_reset(dynarec_arm_t* dyn, int ninst)
|
||||
{
|
||||
dyn->use_ymm = 1;
|
||||
dyn->ymm_zero = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ int neoncache_combine_st(dynarec_arm_t* dyn, int ninst, int a, int b); // with
|
||||
int neoncache_no_i64(dynarec_arm_t* dyn, int ninst, int st, int a);
|
||||
|
||||
// transform x86 flags to native flags
|
||||
uint8_t flag2native(uint8_t flags);
|
||||
uint8_t flag2native(uint8_t flags, int vf_is_p);
|
||||
// mark a instruction as using/generating flags. return flag
|
||||
uint8_t mark_natflag(dynarec_arm_t* dyn, int ninst, uint8_t flag, int before);
|
||||
// propage the use of nativeflags or not (done between step 0 and step 1)
|
||||
|
||||
@@ -69,13 +69,13 @@ uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, u
|
||||
}
|
||||
} else {
|
||||
if(rex.seg && !(tmp && ((!((tmp>=absmin) && (tmp<=absmax) && !(tmp&mask))) || !(unscaled && (tmp>-256) && (tmp<256))))) {
|
||||
grab_segdata(dyn, addr, ninst, ret, rex.seg, 0);
|
||||
grab_segdata(dyn, addr, ninst, ret, rex.seg);
|
||||
seg_done = 1;
|
||||
if(unscaled && (tmp>-256) && (tmp<256))
|
||||
*unscaled = 1;
|
||||
*fixaddress = tmp;
|
||||
} else if(rex.seg && tmp>-0x1000 && tmp<0x1000) {
|
||||
grab_segdata(dyn, addr, ninst, ret, rex.seg, 0);
|
||||
grab_segdata(dyn, addr, ninst, ret, rex.seg);
|
||||
if(tmp) {
|
||||
if(tmp>0) ADDx_U12(ret, ret, tmp);
|
||||
else SUBx_U12(ret, ret, -tmp);
|
||||
@@ -99,7 +99,7 @@ uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, u
|
||||
if(rex.is32bits) {
|
||||
int tmp = F32S;
|
||||
if(rex.seg && tmp>-0x1000 && tmp<0x1000) {
|
||||
grab_segdata(dyn, addr, ninst, ret, rex.seg, 0);
|
||||
grab_segdata(dyn, addr, ninst, ret, rex.seg);
|
||||
if(tmp) {
|
||||
if(tmp>0) ADDx_U12(ret, ret, tmp);
|
||||
else SUBx_U12(ret, ret, -tmp);
|
||||
@@ -222,7 +222,7 @@ uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, u
|
||||
if(rex.seg && !seg_done) {
|
||||
if(scratch==ret)
|
||||
scratch=ret+1;
|
||||
grab_segdata(dyn, addr, ninst, scratch, rex.seg, 0);
|
||||
grab_segdata(dyn, addr, ninst, scratch, rex.seg);
|
||||
//seg offset is 64bits, so no truncation here
|
||||
ADDx_REGy(hint, scratch, ret);
|
||||
ret = hint;
|
||||
@@ -249,9 +249,10 @@ uintptr_t geted16(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop,
|
||||
int64_t offset = 0;
|
||||
int absmin = 0;
|
||||
if(s) absmin = -absmax;
|
||||
int need_trunc = 0;
|
||||
if(!n && (m&7)==6) {
|
||||
offset = F16S;
|
||||
MOVZw(ret, offset);
|
||||
MOVZw(ret, offset); //that's 16bits only, not need to truncate
|
||||
} else {
|
||||
switch(n) {
|
||||
case 0: offset = 0; break;
|
||||
@@ -268,54 +269,52 @@ uintptr_t geted16(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop,
|
||||
}
|
||||
switch(m&7) {
|
||||
case 0: //R_BX + R_SI
|
||||
UXTHx(ret, xRBX);
|
||||
UXTHx(scratch, xRSI);
|
||||
ADDx_REG(ret, ret, scratch);
|
||||
ADDw_REG(ret, xRBX, xRSI);
|
||||
need_trunc = ret;
|
||||
break;
|
||||
case 1: //R_BX + R_DI
|
||||
UXTHx(ret, xRBX);
|
||||
UXTHx(scratch, xRDI);
|
||||
ADDx_REG(ret, ret, scratch);
|
||||
ADDw_REG(ret, xRBX, xRDI);
|
||||
need_trunc = ret;
|
||||
break;
|
||||
case 2: //R_BP + R_SI
|
||||
UXTHx(ret, xRBP);
|
||||
UXTHx(scratch, xRSI);
|
||||
ADDx_REG(ret, ret, scratch);
|
||||
ADDw_REG(ret, xRBP, xRSI);
|
||||
need_trunc = ret;
|
||||
break;
|
||||
case 3: //R_BP + R_DI
|
||||
UXTHx(ret, xRBP);
|
||||
UXTHx(scratch, xRDI);
|
||||
ADDx_REG(ret, ret, scratch);
|
||||
ADDw_REG(ret, xRBP, xRDI);
|
||||
need_trunc = ret;
|
||||
break;
|
||||
case 4: //R_SI
|
||||
UXTHx(ret, xRSI);
|
||||
need_trunc = xRSI;
|
||||
break;
|
||||
case 5: //R_DI
|
||||
UXTHx(ret, xRDI);
|
||||
need_trunc = xRDI;
|
||||
break;
|
||||
case 6: //R_BP
|
||||
UXTHx(ret, xRBP);
|
||||
need_trunc = xRBP;
|
||||
break;
|
||||
case 7: //R_BX
|
||||
UXTHx(ret, xRBX);
|
||||
need_trunc = xRBX;
|
||||
break;
|
||||
}
|
||||
if(offset) {
|
||||
if(offset<0 && offset>-0x1000) {
|
||||
SUBx_U12(ret, ret, -offset);
|
||||
SUBw_U12(ret, need_trunc?need_trunc:ret, -offset);
|
||||
} else if(offset>0 && offset<0x1000) {
|
||||
ADDx_U12(ret, ret, offset);
|
||||
ADDw_U12(ret, need_trunc?need_trunc:ret, offset);
|
||||
} else {
|
||||
MOV64x(scratch, offset);
|
||||
ADDx_REG(ret, ret, scratch);
|
||||
MOV32w(scratch, offset);
|
||||
ADDw_REG(ret, need_trunc?need_trunc:ret, scratch);
|
||||
}
|
||||
need_trunc = ret;
|
||||
}
|
||||
}
|
||||
if(need_trunc) UXTHx(ret, need_trunc);
|
||||
|
||||
if(rex.seg) {
|
||||
if(scratch==ret)
|
||||
scratch=ret+1;
|
||||
grab_segdata(dyn, addr, ninst, scratch, rex.seg, 0);
|
||||
grab_segdata(dyn, addr, ninst, scratch, rex.seg);
|
||||
//seg offset is 64bits, so no truncation here
|
||||
if(IS_GPR(ret)) {
|
||||
ADDx_REG(hint, ret, scratch);
|
||||
@@ -433,12 +432,10 @@ void jump_to_next(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst, int is32
|
||||
#endif
|
||||
}
|
||||
|
||||
void ret_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int ninst, rex_t rex)
|
||||
void ret_to_next(dynarec_arm_t* dyn, uintptr_t ip, int ninst, rex_t rex)
|
||||
{
|
||||
MAYUSE(dyn); MAYUSE(ninst);
|
||||
MESSAGE(LOG_DUMP, "Ret to epilog\n");
|
||||
CHECK_DFNONE(0);
|
||||
POP1z(xRIP);
|
||||
MOVz_REG(x1, xRIP);
|
||||
SMEND();
|
||||
if(BOX64DRENV(dynarec_callret)) {
|
||||
@@ -464,44 +461,7 @@ void ret_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int ninst, rex_t rex)
|
||||
CLEARIP();
|
||||
}
|
||||
|
||||
void retn_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int ninst, rex_t rex, int n)
|
||||
{
|
||||
MAYUSE(dyn); MAYUSE(ninst);
|
||||
MESSAGE(LOG_DUMP, "Retn to epilog\n");
|
||||
CHECK_DFNONE(0);
|
||||
POP1z(xRIP);
|
||||
if(n>0xfff) {
|
||||
MOV32w(w1, n);
|
||||
ADDz_REG(xRSP, xRSP, x1);
|
||||
} else {
|
||||
ADDz_U12(xRSP, xRSP, n);
|
||||
}
|
||||
MOVz_REG(x1, xRIP);
|
||||
SMEND();
|
||||
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?
|
||||
if(dyn->have_purge)
|
||||
doLeaveBlock(dyn, ninst, x4, x5, x3);
|
||||
CBNZx(x6, 2*4);
|
||||
RET(xLR);
|
||||
// not the correct return address, regular jump
|
||||
SUBx_U12(xSP, xSavedSP, 16);
|
||||
}
|
||||
NOTEST(x2);
|
||||
int dest = indirect_lookup(dyn, ninst, rex.is32bits, x2, x3);
|
||||
if(dyn->have_purge && !BOX64DRENV(dynarec_callret))
|
||||
doLeaveBlock(dyn, ninst, x4, x5, x6);
|
||||
#ifdef HAVE_TRACE
|
||||
BLR(dest);
|
||||
#else
|
||||
BR(dest);
|
||||
#endif
|
||||
CLEARIP();
|
||||
}
|
||||
|
||||
void iret_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int ninst, int is32bits, int is64bits)
|
||||
void iret_to_next(dynarec_arm_t* dyn, uintptr_t ip, int ninst, int is32bits, int is64bits)
|
||||
{
|
||||
int64_t j64;
|
||||
//#warning TODO: is64bits
|
||||
@@ -521,8 +481,8 @@ void iret_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int ninst, int is32bits, i
|
||||
POP1_32(x2);
|
||||
POP1_32(x3);
|
||||
}
|
||||
// check CS is NULL, sgfault if it is
|
||||
CBZw_MARK3(x1);
|
||||
// segfault if CS is NULL
|
||||
CBZw_MARK3(x2);
|
||||
// clean EFLAGS
|
||||
MOV32w(x4, 0x3E7FD7); // also mask RF, because it's not really handled
|
||||
ANDx_REG(x3, x3, x4);
|
||||
@@ -554,14 +514,10 @@ void iret_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int ninst, int is32bits, i
|
||||
MOVx_REG(xRIP, x1);
|
||||
MOVw_REG(xFlags, x3);
|
||||
// Ret....
|
||||
// epilog on purpose, CS might have changed!
|
||||
if(dyn->need_reloc)
|
||||
TABLE64C(x2, const_epilog);
|
||||
else
|
||||
MOV64x(x2, getConst(const_epilog));
|
||||
if(dyn->have_purge)
|
||||
doLeaveBlock(dyn, ninst, x4, x5, x6);
|
||||
BR(x2);
|
||||
rex_t dummy = {0};
|
||||
dummy.is32bits = is32bits;
|
||||
dummy.w = is64bits;
|
||||
ret_to_next(dyn, ip, ninst, dummy);
|
||||
CLEARIP();
|
||||
MARK;
|
||||
if(is64bits)
|
||||
@@ -734,12 +690,11 @@ 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, int modreg)
|
||||
void grab_segdata(dynarec_arm_t* dyn, uintptr_t addr, int ninst, int reg, int segment)
|
||||
{
|
||||
(void)addr;
|
||||
int64_t j64;
|
||||
MAYUSE(j64);
|
||||
if (modreg) return;
|
||||
MESSAGE(LOG_DUMP, "Get %s Offset\n", (segment==_FS)?"FS":"GS");
|
||||
LDRx_U12(reg, xEmu, offsetof(x64emu_t, segs_offs[segment]));
|
||||
MESSAGE(LOG_DUMP, "----%s Offset\n", (segment==_FS)?"FS":"GS");
|
||||
@@ -1561,12 +1516,15 @@ int sse_get_reg(dynarec_arm_t* dyn, int ninst, int s1, int a, int forwrite)
|
||||
// get neon register for a SSE reg, but don't try to synch it if it needed to be created
|
||||
int sse_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int a)
|
||||
{
|
||||
dyn->n.xmm_used |= 1<<a;
|
||||
if(dyn->n.ssecache[a].v!=-1) {
|
||||
dyn->n.ssecache[a].write = 1;
|
||||
dyn->n.neoncache[dyn->n.ssecache[a].reg].t = NEON_CACHE_XMMW;
|
||||
if(!(dyn->n.xmm_used&(1<<a))) // if it's not used in this opcode, then it's not needed from there
|
||||
dyn->n.xmm_unneeded |= 1<<a;
|
||||
dyn->n.xmm_used |= 1<<a;
|
||||
return dyn->n.ssecache[a].reg;
|
||||
}
|
||||
dyn->n.xmm_used |= 1<<a;
|
||||
dyn->n.xmm_unneeded |= 1<<a;
|
||||
dyn->n.ssecache[a].reg = fpu_get_reg_xmm(dyn, NEON_CACHE_XMMW, a);
|
||||
dyn->n.ssecache[a].write = 1; // it will be write...
|
||||
@@ -1774,6 +1732,8 @@ int ymm_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int a, int k1, int
|
||||
if((dyn->n.neoncache[i].t==NEON_CACHE_YMMR || dyn->n.neoncache[i].t==NEON_CACHE_YMMW) && dyn->n.neoncache[i].n==a) {
|
||||
dyn->n.neoncache[i].t = NEON_CACHE_YMMW;
|
||||
dyn->ymm_zero&=~(1<<a);
|
||||
if(!(dyn->n.ymm_used&(1<<a)))
|
||||
dyn->n.ymm_unneeded |= 1<<a;
|
||||
dyn->n.ymm_used|=(1<<a);
|
||||
#if STEP == 0
|
||||
dyn->insts[ninst].ymm0_sub |= (1<<a);
|
||||
@@ -1782,6 +1742,7 @@ int ymm_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int a, int k1, int
|
||||
}
|
||||
// nope, grab a new one
|
||||
dyn->n.ymm_unneeded |= 1<<a;
|
||||
dyn->n.ymm_used|=(1<<a);
|
||||
int ret = fpu_get_reg_ymm(dyn, ninst, NEON_CACHE_YMMW, a, k1, k2, k3);
|
||||
if(dyn->ymm_zero&(1<<a))
|
||||
dyn->ymm_zero&=~(1<<a);
|
||||
@@ -2360,7 +2321,7 @@ static void nativeFlagsTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2)
|
||||
flags_after = dyn->insts[jmp].before_nat_flags;
|
||||
nc_after = dyn->insts[jmp].normal_carry_before;
|
||||
}
|
||||
uint8_t flags_x86 = flag2native(dyn->insts[jmp].x64.need_before);
|
||||
uint8_t flags_x86 = flag2native(dyn->insts[jmp].x64.need_before, (dyn->insts[jmp].before_nat_flags&NF_PF_V)?1:0);
|
||||
flags_x86 &= ~flags_after;
|
||||
MESSAGE(LOG_DUMP, "\tNative Flags transform ---- ninst=%d -> %d %hhx -> %hhx/%hhx\n", ninst, jmp, flags_before, flags_after, flags_x86);
|
||||
// flags present in before and missing in after
|
||||
@@ -2376,6 +2337,10 @@ static void nativeFlagsTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2)
|
||||
CSETw(s1, cVS);
|
||||
BFIw(xFlags, s1, F_OF, 1);
|
||||
}
|
||||
if((flags_before&NF_PF_V) && (flags_x86&NF_PF_V)) {
|
||||
CSETw(s1, cVS);
|
||||
BFIw(xFlags, s1, F_PF, 1);
|
||||
}
|
||||
if((flags_before&NF_CF) && (flags_x86&NF_CF)) {
|
||||
if(nc_before) // might need to invert carry
|
||||
CSETw(s1, cCS);
|
||||
@@ -2401,6 +2366,11 @@ static void nativeFlagsTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2)
|
||||
UBFXw(s1, xFlags, F_OF, 1);
|
||||
BFIx(s2, s1, NZCV_V, 1);
|
||||
}
|
||||
if(!(flags_before&NF_PF_V) && (flags_after&NF_PF_V)) {
|
||||
GO_MRS(s2);
|
||||
UBFXw(s1, xFlags, F_PF, 1);
|
||||
BFIx(s2, s1, NZCV_V, 1);
|
||||
}
|
||||
if(!(flags_before&NF_CF) && (flags_after&NF_CF)) {
|
||||
GO_MRS(s2);
|
||||
BFIx(s2, xFlags, NZCV_C, 1); // F_CF is bit 0
|
||||
@@ -2432,6 +2402,47 @@ void CacheTransform(dynarec_arm_t* dyn, int ninst, int cacheupd) {
|
||||
nativeFlagsTransform(dyn, ninst, x1, x2);
|
||||
}
|
||||
|
||||
void additionnal_checks(dynarec_arm_t* dyn, int ninst)
|
||||
{
|
||||
int s1 = x1;
|
||||
// check if a opcode generate partial flags that may clober existing native flags and see need to be "moved" to xFlags
|
||||
if(dyn->insts[ninst].nat_flags_op || dyn->insts[ninst].nat_flags_op_before) {
|
||||
uint8_t nat_flags = dyn->insts[ninst].need_nat_flags; // that's the native flags that will be generated
|
||||
uint8_t nat_flags_gen = dyn->insts[ninst].set_nat_flags;
|
||||
//TODO: does it need to fetch previous state with getPred?
|
||||
uint8_t nat_flags_before = dyn->insts[ninst].before_nat_flags; //flags before the opcode, but it's only there when opcode also consume natflags
|
||||
uint8_t nat_flags_flush = nat_flags_before&~nat_flags_gen; // flags present before bu not after the operation and so that needs to be spared
|
||||
if(nat_flags_before && nat_flags_flush) {
|
||||
// some flags disapear, and need to be saved
|
||||
MESSAGE(LOG_DUMP, "\tPurging native flags %hhx\n", nat_flags_flush);
|
||||
uint8_t nc_before = dyn->insts[ninst].normal_carry;
|
||||
if(nat_flags_flush&NF_EQ) {
|
||||
CSETw(s1, cEQ);
|
||||
BFIw(xFlags, s1, F_ZF, 1);
|
||||
}
|
||||
if(nat_flags_flush&NF_SF) {
|
||||
CSETw(s1, cMI);
|
||||
BFIw(xFlags, s1, F_SF, 1);
|
||||
}
|
||||
if(nat_flags_flush&NF_VF) {
|
||||
CSETw(s1, cVS);
|
||||
BFIw(xFlags, s1, F_OF, 1);
|
||||
}
|
||||
if(nat_flags_flush&NF_PF_V) {
|
||||
CSETw(s1, cVS);
|
||||
BFIw(xFlags, s1, F_PF, 1);
|
||||
}
|
||||
if(nat_flags_flush&NF_CF) {
|
||||
if(nc_before) // might need to invert carry
|
||||
CSETw(s1, cCS);
|
||||
else
|
||||
CSETw(s1, cCC);
|
||||
BFIw(xFlags, s1, F_CF, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void fpu_reflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
{
|
||||
x87_reflectcache(dyn, ninst, s1, s2, s3);
|
||||
@@ -2545,7 +2556,7 @@ void fpu_reset_cache(dynarec_arm_t* dyn, int ninst, int reset_n)
|
||||
{
|
||||
MESSAGE(LOG_DEBUG, "Reset Caches with %d\n",reset_n);
|
||||
#if STEP > 1
|
||||
// for STEP 2 & 3, just need to refrest with current, and undo the changes (push & swap)
|
||||
// for STEP 2 & 3, just need to refresh with current, and undo the changes (push & swap)
|
||||
dyn->n = dyn->insts[ninst].n;
|
||||
dyn->ymm_zero = dyn->insts[ninst].ymm0_in;
|
||||
neoncacheUnwind(&dyn->n);
|
||||
@@ -2664,8 +2675,10 @@ int fpu_get_reg_ymm(dynarec_arm_t* dyn, int ninst, int t, int ymm, int k1, int k
|
||||
return i;
|
||||
}
|
||||
// check if free or should be purge before...
|
||||
if(dyn->n.neoncache[i].t==NEON_CACHE_YMMW)
|
||||
if(dyn->n.neoncache[i].t==NEON_CACHE_YMMW) {
|
||||
dyn->n.ymm_used|=(1<<dyn->n.neoncache[i].n); // mark as used, to avoid it being mark as unneeded
|
||||
VSTR128_U12(i, xEmu, offsetof(x64emu_t, ymm[dyn->n.neoncache[i].n]));
|
||||
}
|
||||
dyn->n.neoncache[i].t=t;
|
||||
dyn->n.neoncache[i].n=ymm;
|
||||
return i;
|
||||
@@ -2711,6 +2724,7 @@ int fpu_get_reg_ymm(dynarec_arm_t* dyn, int ninst, int t, int ymm, int k1, int k
|
||||
// should a test be done to check if ymm is already in the purge list?
|
||||
if(!is_ymm_to_keep(dyn, i+j, k1, k2, k3)) {
|
||||
// Save the reg and recycle it
|
||||
dyn->n.ymm_used|=(1<<dyn->n.neoncache[i+j].n);
|
||||
VSTR128_U12(i+j, xEmu, offsetof(x64emu_t, ymm[dyn->n.neoncache[i+j].n]));
|
||||
dyn->n.neoncache[i+j].v = 0;
|
||||
int ret = internal_mark_ymm(dyn, t, ymm, i+j);
|
||||
@@ -2723,6 +2737,7 @@ int fpu_get_reg_ymm(dynarec_arm_t* dyn, int ninst, int t, int ymm, int k1, int k
|
||||
if(!dyn->n.fpuused[i+j]) {
|
||||
// should a test be done to check if ymm is already in the purge list?
|
||||
if((dyn->n.neoncache[i+j].t==NEON_CACHE_YMMW) && !is_ymm_to_keep(dyn, i+j, k1, k2, k3)) {
|
||||
dyn->n.ymm_used|=(1<<dyn->n.neoncache[i+j].n);
|
||||
VSTR128_U12(i+j, xEmu, offsetof(x64emu_t, ymm[dyn->n.neoncache[i+j].n]));
|
||||
dyn->n.neoncache[i+j].v = 0;
|
||||
int ret = internal_mark_ymm(dyn, t, ymm, i+j);
|
||||
@@ -2822,3 +2837,97 @@ void doLeaveBlock(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
}
|
||||
MESSAGE(LOG_INFO, "-------- doLeave\n");
|
||||
}
|
||||
|
||||
void emit_fcomi(dynarec_arm_t* dyn, int ninst, int s1, int s2, int isfloat, int d1, int d2)
|
||||
{
|
||||
IFX(X_OF|X_AF|X_SF) {
|
||||
MOV32w(s2, 0b100011010101);
|
||||
BICw_REG(xFlags, xFlags, s2);
|
||||
}
|
||||
IFX(X_CF|X_PF|X_ZF) {
|
||||
int nonative = 0;
|
||||
int needCZ = 0;
|
||||
if(isfloat)
|
||||
FCMPS(d1, d2);
|
||||
else
|
||||
FCMPD(d1, d2);
|
||||
IFX(X_ZF) {
|
||||
IFNATIVE(NF_EQ) {
|
||||
// add ZF if VS is set
|
||||
needCZ = 1;
|
||||
} else {
|
||||
nonative = 1;
|
||||
}
|
||||
}
|
||||
IFX(X_CF) {
|
||||
IFNATIVE(NF_CF) {
|
||||
// no need to add CF if VS, because it's a reverse carry (so already "un"set)
|
||||
GEN_INVERTED_CARRY();
|
||||
needCZ = 1;
|
||||
} else {
|
||||
nonative = 1;
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
IFNATIVE(NF_PF_V) {
|
||||
} else {
|
||||
nonative = 1;
|
||||
}
|
||||
}
|
||||
if(needCZ) {
|
||||
#if 1
|
||||
// retest is VF is clear, set NZCV to 0101 if VF is set, to match x86 behaviour (also, inversed Carry)
|
||||
// probably faster like that then the conditionnal jump + reading / reseting the flags
|
||||
if(isfloat)
|
||||
FCCMPS(d1, d2, 0b0101, cVC);
|
||||
else
|
||||
FCCMPD(d1, d2, 0b0101, cVC);
|
||||
#else
|
||||
if(cpuext.flagm) {
|
||||
Bcond(cVC, 4+2*4);
|
||||
MOV32w(s1, 0b0100); //new flags
|
||||
RMIF(s1, 0, 0b0110); // ZC flags only
|
||||
} else {
|
||||
Bcond(cVC, 4+3*4);
|
||||
MRS_nzcv(s1);
|
||||
EORx_mask(s1, s1, 1, 0b100011, 0b000001); // mask = (1<<NZCV_Z)|(1<<NZCV_C) == 0x60000000
|
||||
MSR_nzcv(s1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if(nonative) {
|
||||
MOV32w(s2, 0b01000101);
|
||||
IFX(X_OF|X_AF|X_SF) {} else {BICw_REG(xFlags, xFlags, s2);}
|
||||
CSETw(s1, cMI); /* 1 if less than, 0 else */
|
||||
/*s2 already set */ /* unordered */
|
||||
CSELw(s1, s2, s1, cVS);
|
||||
MOV32w(s2, 0b01000000); /* zero */
|
||||
CSELw(s1, s2, s1, cEQ);
|
||||
/* greater than leave 0 */
|
||||
ORRw_REG(xFlags, xFlags, s1);
|
||||
}
|
||||
}
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
void checkCRC(dynarec_arm_t* dyn, int ninst)
|
||||
{
|
||||
// grab the dynablock address in x5, as this on will not be erased by crc functions
|
||||
int delta = -(dyn->native_size + sizeof(void*));
|
||||
LDRx_literal(x5, delta);
|
||||
// move away xEMU to X6, should be safe there
|
||||
MOVx_REG(x6, xEmu);
|
||||
// prepare and call the crc function
|
||||
TABLE64C(x3, cpuext.crc32?const_native_crc32:const_native_x31);
|
||||
LDRx_U12(xEmu, x5, offsetof(dynablock_t, x64_addr));
|
||||
LDRw_U12(x1, x5, offsetof(dynablock_t, x64_size));
|
||||
BLR(x3);
|
||||
// done, move away result and restore xEmu
|
||||
MOVw_REG(x1, xEmu);
|
||||
MOVx_REG(xEmu, x6);
|
||||
LDRw_U12(x2, x5, offsetof(dynablock_t, hash));
|
||||
SUBw_REG(x1, x1, x2);
|
||||
CBZw(x1, 4+2*4);
|
||||
TABLE64C(x3, const_native_next_invalidate);
|
||||
BLR(x3);
|
||||
}
|
||||
@@ -841,30 +841,10 @@
|
||||
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) \
|
||||
IFX(X_OF|X_AF|X_SF) { \
|
||||
MOV32w(s2, 0b100011010101); \
|
||||
BICw_REG(xFlags, xFlags, s2); \
|
||||
IFX(X_CF|X_PF|X_ZF) { \
|
||||
MOV32w(s2, 0b01000101); \
|
||||
} \
|
||||
} else { \
|
||||
IFX(X_CF|X_PF|X_ZF) { \
|
||||
MOV32w(s2, 0b01000101); \
|
||||
BICw_REG(xFlags, xFlags, s2); \
|
||||
} \
|
||||
} \
|
||||
IFX(X_CF|X_PF|X_ZF) { \
|
||||
CSETw(s1, cMI); /* 1 if less than, 0 else */ \
|
||||
/*s2 already set */ /* unordered */ \
|
||||
CSELw(s1, s2, s1, cVS); \
|
||||
MOV32w(s2, 0b01000000); /* zero */ \
|
||||
CSELw(s1, s2, s1, cEQ); \
|
||||
/* greater than leave 0 */ \
|
||||
ORRw_REG(xFlags, xFlags, s1); \
|
||||
} \
|
||||
SET_DFNONE(); \
|
||||
// Generate FCOMI with s1 and s2 scratch regs (the VCMP is not done)
|
||||
#define FCOMIS(s1, s2, d1, d2) emit_fcomi(dyn, ninst, s1, s2, 1, d1, d2)
|
||||
#define FCOMID(s1, s2, d1, d2) emit_fcomi(dyn, ninst, s1, s2, 0, d1, d2)
|
||||
#define FCOMI(s1, s2, isfloat, d1, d2) emit_fcomi(dyn, ninst, s1, s2, isfloat, d1, d2)
|
||||
|
||||
#ifndef IF_UNALIGNED
|
||||
#define IF_UNALIGNED(A) if(dyn->insts[ninst].unaligned)
|
||||
@@ -875,7 +855,7 @@
|
||||
#endif
|
||||
|
||||
#ifndef CALLRET_RET
|
||||
#define CALLRET_RET() NOP
|
||||
#define CALLRET_RET(A) do {if(BOX64DRENV(dynarec_callret)>1) {NOP;}} while(0)
|
||||
#endif
|
||||
#ifndef CALLRET_GETRET
|
||||
#define CALLRET_GETRET() (dyn->callrets?(dyn->callrets[dyn->callret_size].offs-dyn->native_size):0)
|
||||
@@ -1003,12 +983,12 @@
|
||||
#define FORCE_DFNONE() STRw_U12(wZR, xEmu, offsetof(x64emu_t, df))
|
||||
#define CHECK_DFNONE(N) do {if(dyn->f==status_none_pending) {FORCE_DFNONE(); if(N) dyn->f = status_none;}} while(0)
|
||||
|
||||
#define SET_DFNONE() \
|
||||
do { \
|
||||
if(!dyn->insts[ninst].x64.may_set && (dyn->f!=status_none)) { \
|
||||
dyn->f = status_none_pending; \
|
||||
} \
|
||||
} while(0)
|
||||
#define SET_DFNONE() \
|
||||
do { \
|
||||
if (dyn->f != status_none) { \
|
||||
dyn->f = status_none_pending; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define SET_DF(S, N) \
|
||||
if ((N) != d_none) { \
|
||||
@@ -1028,11 +1008,19 @@
|
||||
}
|
||||
#endif
|
||||
|
||||
#define GRABFLAGS(A) \
|
||||
if((A)!=X_PEND \
|
||||
&& ((dyn->f==status_unk) || (dyn->f==status_set))) { \
|
||||
TABLE64C(x6, const_updateflags_arm64); \
|
||||
BLR(x6); \
|
||||
dyn->f = status_none; \
|
||||
}
|
||||
|
||||
#ifndef SETFLAGS
|
||||
#define SETFLAGS(A, B) do { \
|
||||
if (((B)&SF_SUB) \
|
||||
&& (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))); }\
|
||||
{ GRABFLAGS(((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_SET_DF: dyn->f = status_set; break; \
|
||||
case SF_SET_NODF: break; \
|
||||
@@ -1089,6 +1077,11 @@
|
||||
dyn->doublepop = 0;
|
||||
#define ARCH_RESET()
|
||||
|
||||
#undef PREFLAGSNEEDED
|
||||
#define PREFLAGSNEEDED() \
|
||||
if(dyn->always_test && ninst && (dyn->insts[ninst].sep || (ninst && dyn->insts[ninst-1].x64.has_callret))) \
|
||||
checkCRC(dyn, ninst);
|
||||
|
||||
#if STEP < 2
|
||||
#define GETIP(A) MOV64x(xRIP, A)
|
||||
#define GETIP_(A) MOV64x(xRIP, A)
|
||||
@@ -1188,9 +1181,8 @@
|
||||
#define geted16 STEPNAME(geted16)
|
||||
#define jump_to_epilog STEPNAME(jump_to_epilog)
|
||||
#define jump_to_next STEPNAME(jump_to_next)
|
||||
#define ret_to_epilog STEPNAME(ret_to_epilog)
|
||||
#define retn_to_epilog STEPNAME(retn_to_epilog)
|
||||
#define iret_to_epilog STEPNAME(iret_to_epilog)
|
||||
#define ret_to_next STEPNAME(ret_to_next)
|
||||
#define iret_to_next STEPNAME(iret_to_next)
|
||||
#define call_c STEPNAME(call_c)
|
||||
#define call_d STEPNAME(call_d)
|
||||
#define call_n STEPNAME(call_n)
|
||||
@@ -1300,6 +1292,7 @@
|
||||
#define emit_shld16 STEPNAME(emit_shld16)
|
||||
|
||||
#define emit_pf STEPNAME(emit_pf)
|
||||
#define emit_fcomi STEPNAME(emit_fcomi)
|
||||
|
||||
#define x87_do_push STEPNAME(x87_do_push)
|
||||
#define x87_do_push_empty STEPNAME(x87_do_push_empty)
|
||||
@@ -1332,6 +1325,7 @@
|
||||
#define doPreload STEPNAME(doPreload)
|
||||
#define doEnterBlock STEPNAME(doEnterBlock)
|
||||
#define doLeaveBlock STEPNAME(doLeaveBlock)
|
||||
#define checkCRC STEPNAME(checkCRC)
|
||||
|
||||
#define fpu_pushcache STEPNAME(fpu_pushcache)
|
||||
#define fpu_popcache STEPNAME(fpu_popcache)
|
||||
@@ -1347,6 +1341,7 @@
|
||||
#define avx_purge_ymm STEPNAME(avx_purge_ymm)
|
||||
|
||||
#define CacheTransform STEPNAME(CacheTransform)
|
||||
#define additionnal_checks STEPNAME(additionnal_checks)
|
||||
|
||||
#define arm64_move32 STEPNAME(arm64_move32)
|
||||
#define arm64_move64 STEPNAME(arm64_move64)
|
||||
@@ -1361,13 +1356,12 @@ uintptr_t geted16(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop,
|
||||
// generic x64 helper
|
||||
void jump_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst);
|
||||
void jump_to_next(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst, int is32bits);
|
||||
void ret_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int ninst, rex_t rex);
|
||||
void retn_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int ninst, rex_t rex, int n);
|
||||
void iret_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int ninst, int is32bits, int is64bits);
|
||||
void ret_to_next(dynarec_arm_t* dyn, uintptr_t ip, int ninst, rex_t rex);
|
||||
void iret_to_next(dynarec_arm_t* dyn, uintptr_t ip, int ninst, int is32bits, int is64bits);
|
||||
void call_c(dynarec_arm_t* dyn, int ninst, arm64_consts_t fnc, int reg, int ret, int saveflags, int save_reg);
|
||||
void call_d(dynarec_arm_t* dyn, int ninst, arm64_consts_t fnc, int ret, int arg1, int arg2, int sav1, int sav2);
|
||||
void call_n(dynarec_arm_t* dyn, int ninst, void* fnc, int w);
|
||||
void grab_segdata(dynarec_arm_t* dyn, uintptr_t addr, int ninst, int reg, int segment, int modreg);
|
||||
void grab_segdata(dynarec_arm_t* dyn, uintptr_t addr, int ninst, int reg, int segment);
|
||||
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);
|
||||
@@ -1473,6 +1467,7 @@ void emit_shld16c(dynarec_arm_t* dyn, int ninst, int s1, int s2, uint32_t c, int
|
||||
void emit_shld16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s5, int s3, int s4);
|
||||
|
||||
void emit_pf(dynarec_arm_t* dyn, int ninst, int s1, int s4);
|
||||
void emit_fcomi(dynarec_arm_t* dyn, int ninst, int s1, int s2, int isfloat, int d1, int d2);
|
||||
|
||||
// x87 helper
|
||||
// cache of the local stack counter, to avoid update at every call, return old internal stack counter
|
||||
@@ -1513,6 +1508,7 @@ int sse_setround(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
void avx_purge_ymm(dynarec_arm_t* dyn, int ninst, uint16_t mask, int s1);
|
||||
|
||||
void CacheTransform(dynarec_arm_t* dyn, int ninst, int cacheupd);
|
||||
void additionnal_checks(dynarec_arm_t* dyn, int ninst);
|
||||
|
||||
void arm64_move32(dynarec_arm_t* dyn, int ninst, int reg, uint32_t val);
|
||||
void arm64_move64(dynarec_arm_t* dyn, int ninst, int reg, uint64_t val);
|
||||
@@ -1605,6 +1601,8 @@ void doPreload(dynarec_arm_t* dyn, int ninst);
|
||||
void doEnterBlock(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
// Leave a block (atomic decrement of in_used)
|
||||
void doLeaveBlock(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
// in case of allways_test, this insert a check of crc of the dynablock (and exit to ArmNext if wrong)
|
||||
void checkCRC(dynarec_arm_t* dyn, int ninst);
|
||||
|
||||
uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog);
|
||||
@@ -1759,13 +1757,21 @@ uintptr_t dynarec64_AVX_F3_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
break; \
|
||||
case B+0xA: \
|
||||
INST_NAME(T1 "P " T2); \
|
||||
IFNATIVE(NF_PF_V) { \
|
||||
GO( , cVC, cVS, X_PF) \
|
||||
} else { \
|
||||
GO( TSTw_mask(xFlags, 0b011110, 0) \
|
||||
, cEQ, cNE, X_PF) \
|
||||
} \
|
||||
break; \
|
||||
case B+0xB: \
|
||||
INST_NAME(T1 "NP " T2); \
|
||||
IFNATIVE(NF_PF_V) { \
|
||||
GO( , cVS, cVC, X_PF) \
|
||||
} else { \
|
||||
GO( TSTw_mask(xFlags, 0b011110, 0) \
|
||||
, cNE, cEQ, X_PF) \
|
||||
} \
|
||||
break; \
|
||||
case B+0xC: \
|
||||
INST_NAME(T1 "L " T2); \
|
||||
|
||||
@@ -25,7 +25,8 @@
|
||||
dyn->n.combined1 = dyn->n.combined2 = 0;\
|
||||
dyn->n.swapped = 0; dyn->n.barrier = 0; \
|
||||
dyn->insts[ninst].f_entry = dyn->f; \
|
||||
if(ninst) {dyn->insts[ninst-1].x64.size = dyn->insts[ninst].x64.addr - dyn->insts[ninst-1].x64.addr;}
|
||||
if(ninst) {dyn->insts[ninst-1].x64.size = dyn->insts[ninst].x64.addr - dyn->insts[ninst-1].x64.addr;} \
|
||||
AREFLAGSNEEDED()
|
||||
|
||||
#define INST_EPILOG \
|
||||
dyn->insts[ninst].f_exit = dyn->f; \
|
||||
@@ -38,19 +39,9 @@
|
||||
--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 || dyn->need_dump || BOX64ENV(dynarec_missing) == 1) \
|
||||
if (!dyn->size || BOX64ENV(dynarec_log) > LOG_INFO || dyn->need_dump) { \
|
||||
dynarec_log(LOG_NONE, "%p: Dynarec stopped because of %s Opcode ", (void*)ip, rex.is32bits ? "x86" : "x64"); \
|
||||
zydis_dec_t* dec = rex.is32bits ? my_context->dec32 : my_context->dec; \
|
||||
if (dec) { \
|
||||
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"); \
|
||||
if (BOX64ENV(dynarec_log) >= LOG_INFO || dyn->need_dump || BOX64ENV(dynarec_missing) == 1) \
|
||||
if (!dyn->size || BOX64ENV(dynarec_log) > LOG_INFO || dyn->need_dump) { \
|
||||
dynarec_stopped(dyn->insts[ninst].x64.addr, rex.is32bits); \
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
#define NEW_INST \
|
||||
dyn->insts[ninst].f_entry = dyn->f; \
|
||||
dyn->n.combined1 = dyn->n.combined2 = 0;\
|
||||
dyn->n.swapped = 0; dyn->n.barrier = 0
|
||||
dyn->n.swapped = 0; dyn->n.barrier = 0; \
|
||||
AREFLAGSNEEDED()
|
||||
|
||||
#define INST_EPILOG \
|
||||
dyn->insts[ninst].n = dyn->n; \
|
||||
|
||||
@@ -13,7 +13,8 @@
|
||||
dyn->insts[ninst].address = (dyn->insts[ninst-1].address+dyn->insts[ninst-1].size); \
|
||||
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; \
|
||||
dyn->insts[ninst].ymm0_pass2 = dyn->ymm_zero; \
|
||||
}
|
||||
} \
|
||||
AREFLAGSNEEDED()
|
||||
#define INST_EPILOG dyn->insts[ninst].epilog = dyn->native_size;
|
||||
#define INST_NAME(name)
|
||||
#define TABLE64(A, V) do { \
|
||||
@@ -29,6 +30,13 @@
|
||||
AddRelocTable64Const(dyn, ninst, (V), 2); \
|
||||
Table64(dyn, getConst(V), 2); EMIT(0); \
|
||||
} while(0)
|
||||
#define FTABLE64(A, V) do {mmx87_regs_t v = {.d = V}; Table64(dyn, v.q, 2); EMIT(0);} while(0)
|
||||
#define CALLRET_RET() do {dyn->callrets[dyn->callret_size].type = 0; dyn->callrets[dyn->callret_size++].offs = dyn->native_size; EMIT(ARCH_NOP); } while(0)
|
||||
#define CALLRET_LOOP() do {dyn->callrets[dyn->callret_size].type = 1; dyn->callrets[dyn->callret_size++].offs = dyn->native_size; EMIT(ARCH_NOP); } while(0)
|
||||
#define FTABLE64(A, V) do { mmx87_regs_t v = {.d = V}; Table64(dyn, v.q, 2); EMIT(0); } while(0)
|
||||
#define CALLRET_RET(A) do { \
|
||||
if((A) && ISSEP() && BOX64DRENV(dynarec_callret)) { \
|
||||
dyn->insts[ninst].size+=sizeof(void*); dyn->native_size+=sizeof(void*); dyn->insts[ninst+1].sep=1; ++dyn->sep_size; \
|
||||
} \
|
||||
if((A) && (BOX64DRENV(dynarec_callret)>1) && !dyn->always_test) { \
|
||||
dyn->callrets[dyn->callret_size].type = 0; dyn->callrets[dyn->callret_size++].offs = dyn->native_size; EMIT(ARCH_NOP); \
|
||||
} \
|
||||
} while(0)
|
||||
#define CALLRET_LOOP() do { dyn->callrets[dyn->callret_size].type = 1; dyn->callrets[dyn->callret_size++].offs = dyn->native_size; EMIT(ARCH_NOP); } while(0)
|
||||
@@ -14,15 +14,16 @@
|
||||
|
||||
#define MESSAGE(A, ...) \
|
||||
do { \
|
||||
if (dyn->need_dump) dynarec_log(LOG_NONE, __VA_ARGS__); \
|
||||
if (dyn->need_dump) dynarec_log_prefix(0, LOG_NONE, __VA_ARGS__); \
|
||||
} while (0)
|
||||
#define ENDPREFIX dyn->insts[ninst].size2 = 0
|
||||
#define NEW_INST \
|
||||
if(ninst) { \
|
||||
if(ninst) { \
|
||||
if(dyn->insts[ninst].address!=(uintptr_t)dyn->block-(uintptr_t)dyn->native_start) dyn->abort = 1; \
|
||||
addInst(dyn->instsize, &dyn->insts_size, dyn->insts[ninst-1].x64.size, dyn->insts[ninst-1].size/4); \
|
||||
dyn->insts[ninst].ymm0_pass3 = dyn->ymm_zero; \
|
||||
}
|
||||
dyn->insts[ninst].ymm0_pass3 = dyn->ymm_zero; \
|
||||
} \
|
||||
AREFLAGSNEEDED()
|
||||
#define INST_EPILOG
|
||||
#define INST_NAME(name) inst_name_pass3(dyn, ninst, name, rex)
|
||||
#define TABLE64(A, V) do { \
|
||||
@@ -42,5 +43,21 @@
|
||||
MESSAGE(LOG_DUMP, " Table64C: 0x%lx\n", (V)); LDRx_literal(A, val64offset);\
|
||||
} while(0)
|
||||
#define FTABLE64(A, V) do {mmx87_regs_t v = {.d = V}; int val64offset = Table64(dyn, v.q, 3); MESSAGE(LOG_DUMP, " FTable64: %g\n", v.d); VLDR64_literal(A, val64offset);} while(0)
|
||||
#define CALLRET_RET() do {dyn->callrets[dyn->callret_size].type = 0; dyn->callrets[dyn->callret_size++].offs = dyn->native_size; EMIT(ARCH_NOP); } while(0)
|
||||
#define CALLRET_RET(A) \
|
||||
do { \
|
||||
if((A) && ISSEP() && BOX64DRENV(dynarec_callret)) { \
|
||||
MESSAGE(LOG_DUMP, " Dynablock*\n"); \
|
||||
dyn->block += sizeof(void*); \
|
||||
dyn->native_size+=sizeof(void*); \
|
||||
dyn->insts[ninst].size2 += sizeof(void*); \
|
||||
dyn->sep[dyn->sep_size].x64_offs = addr - dyn->start; \
|
||||
dyn->sep[dyn->sep_size].nat_offs = dyn->native_size; \
|
||||
++dyn->sep_size; \
|
||||
} \
|
||||
if((A) && (BOX64DRENV(dynarec_callret)>1) && !dyn->always_test) { \
|
||||
dyn->callrets[dyn->callret_size].type = 0; \
|
||||
dyn->callrets[dyn->callret_size++].offs = dyn->native_size; \
|
||||
EMIT(ARCH_NOP); \
|
||||
} \
|
||||
} while(0)
|
||||
#define CALLRET_LOOP() do {dyn->callrets[dyn->callret_size].type = 1; dyn->callrets[dyn->callret_size++].offs = dyn->native_size; EMIT(ARCH_NOP); } while(0)
|
||||
@@ -14,6 +14,7 @@ typedef struct box64env_s box64env_t;
|
||||
#define NF_SF (1<<1)
|
||||
#define NF_VF (1<<2)
|
||||
#define NF_CF (1<<3)
|
||||
#define NF_PF_V (1<<4)
|
||||
|
||||
// Nothing happens to the native flags
|
||||
#define NAT_FLAG_OP_NONE 0
|
||||
@@ -49,6 +50,8 @@ typedef union sse_cache_s {
|
||||
};
|
||||
} sse_cache_t;
|
||||
typedef struct callret_s callret_t;
|
||||
typedef struct sep_s sep_t;
|
||||
|
||||
typedef struct neoncache_s {
|
||||
// Neon cache
|
||||
neon_cache_t neoncache[32];
|
||||
@@ -79,6 +82,8 @@ typedef struct neoncache_s {
|
||||
uint16_t ymm_used; // mask of the ymm regs used in this opcode
|
||||
uint16_t ymm_write; // 1bit of ymmXX removed write
|
||||
uint16_t ymm_removed; // 1bit if ymmXX was removed
|
||||
uint16_t xmm_needed; // 1bit for xmmXX were value is needed
|
||||
uint16_t ymm_needed; // 1bit for ymmXX were value is needed
|
||||
uint16_t xmm_unneeded; // 1bit for xmmXX were value is not needed
|
||||
uint16_t ymm_unneeded; // 1bit for ymmXX were value is not needed
|
||||
uint64_t ymm_regs; // 4bits (0-15) position of 16 ymmXX regs removed
|
||||
@@ -121,7 +126,8 @@ typedef struct instruction_arm64_s {
|
||||
uint8_t will_read:1; // [strongmem] will read from memory
|
||||
uint8_t last_write:1; // [strongmem] the last write in a SEQ
|
||||
uint8_t lock:1; // [strongmem] lock semantic
|
||||
uint8_t wfe:1; // opcode uses sevl + wfe
|
||||
uint8_t wfe:1; // opcode uses sevl + wfe
|
||||
uint8_t sep:1; // opcode is a secondary entry point
|
||||
uint8_t set_nat_flags; // 0 or combinaison of native flags define
|
||||
uint8_t use_nat_flags; // 0 or combinaison of native flags define
|
||||
uint8_t use_nat_flags_before; // 0 or combinaison of native flags define
|
||||
@@ -133,6 +139,7 @@ typedef struct instruction_arm64_s {
|
||||
unsigned normal_carry:1;
|
||||
unsigned normal_carry_before:1;
|
||||
unsigned invert_carry:1; // this opcode force an inverted carry
|
||||
unsigned df_needed:1;
|
||||
unsigned df_notneeded:1;
|
||||
unsigned unaligned:1; // this opcode can be re-generated for unaligned special case
|
||||
unsigned x87precision:1; // this opcode can handle x87pc
|
||||
@@ -178,7 +185,9 @@ typedef struct dynarec_arm_s {
|
||||
instsize_t* instsize;
|
||||
size_t insts_size; // size of the instruction size array (calculated)
|
||||
int callret_size; // size of the array
|
||||
callret_t* callrets; // arrey of callret return, with NOP / UDF depending if the block is clean or dirty
|
||||
int sep_size; // size of the array
|
||||
callret_t* callrets; // array of callret return, with NOP / UDF depending if the block is clean or dirty
|
||||
sep_t* sep; // array of secondary entry point
|
||||
uintptr_t forward; // address of the last end of code while testing forward
|
||||
uintptr_t forward_to; // address of the next jump to (to check if everything is ok)
|
||||
int32_t forward_size; // size at the forward point
|
||||
@@ -194,6 +203,7 @@ typedef struct dynarec_arm_s {
|
||||
uint8_t use_xmm:1;
|
||||
uint8_t use_ymm:1;
|
||||
uint8_t have_purge:1; // set to 1 if block can be purged
|
||||
uint8_t is_file_mapped:1; // if the memory is a mapped file (probably binary, not a memory)
|
||||
void* gdbjit_block;
|
||||
uint32_t need_x87check; // needs x87 precision control check if non-null, or 0 if not
|
||||
uint32_t need_dump; // need to dump the block
|
||||
|
||||
@@ -541,6 +541,33 @@ SETMARK(d_adc8);
|
||||
BFIw(xFlags, x3, F_OF, 1);
|
||||
emit_pf(dyn, ninst, x1, x4);
|
||||
RET(xLR);
|
||||
SETMARK(d_adc8b);
|
||||
LDRB_U12(x1, xEmu, offsetof(x64emu_t, res));
|
||||
LDRB_U12(x2, xEmu, offsetof(x64emu_t, op1));
|
||||
LDRB_U12(x3, xEmu, offsetof(x64emu_t, op2));
|
||||
ADDw_REG(x4, x2, x3);
|
||||
SUBw_UXTB(x4, x1, x4);
|
||||
CBZw(x4, 4+4);
|
||||
MOVZw(x4, 1);
|
||||
ADDw_REG(x1, x2, x3);
|
||||
ADDw_REG(x1, x1, x4); // recompute res as 16bits
|
||||
BFXILw(xFlags, x1, 8, 1); //F_CF
|
||||
LSRw(x4, x1, 7);
|
||||
BFIw(xFlags, x4, F_SF, 1);
|
||||
TSTw_mask(x1, 0, 7); // mask 0xff
|
||||
CSETw(x4, cEQ);
|
||||
BFIw(xFlags, x4, F_ZF, 1);
|
||||
ANDw_REG(x4, x2, x3); // op1 & op2
|
||||
ORRw_REG(x2, x2, x3); // op1 | op2
|
||||
BICw_REG(x2, x2, x1); // ~res & (op1 | op2)
|
||||
ORRw_REG(x2, x2, x4); // CC
|
||||
LSRw(x3, x2, 3);
|
||||
BFIw(xFlags, x3, F_AF, 1);
|
||||
LSRw(x3, x2, 6);
|
||||
EORw_REG_LSR(x3, x3, x3, 1);
|
||||
BFIw(xFlags, x3, F_OF, 1);
|
||||
emit_pf(dyn, ninst, x1, x4);
|
||||
RET(xLR);
|
||||
SETMARK(d_adc16);
|
||||
LDRw_U12(x1, xEmu, offsetof(x64emu_t, res));
|
||||
BFXILw(xFlags, x1, 16, 1); //F_CF
|
||||
@@ -562,6 +589,33 @@ SETMARK(d_adc16);
|
||||
BFIw(xFlags, x3, F_OF, 1);
|
||||
emit_pf(dyn, ninst, x1, x4);
|
||||
RET(xLR);
|
||||
SETMARK(d_adc16b);
|
||||
LDRH_U12(x1, xEmu, offsetof(x64emu_t, res));
|
||||
LDRH_U12(x2, xEmu, offsetof(x64emu_t, op1));
|
||||
LDRH_U12(x3, xEmu, offsetof(x64emu_t, op2));
|
||||
ADDw_REG(x4, x2, x3);
|
||||
SUBw_UXTH(x4, x1, x4);
|
||||
CBZw(x4, 4+4);
|
||||
MOVZw(x4, 1);
|
||||
ADDw_REG(x1, x2, x3);
|
||||
ADDw_REG(x1, x1, x4); // recompute res as 16bits
|
||||
BFXILw(xFlags, x1, 16, 1); //F_CF
|
||||
LSRw(x4, x1, 15);
|
||||
BFIw(xFlags, x4, F_SF, 1);
|
||||
TSTw_mask(x1, 0, 15); // mask 0xffff
|
||||
CSETw(x4, cEQ);
|
||||
BFIw(xFlags, x4, F_ZF, 1);
|
||||
ANDw_REG(x4, x2, x3); // op1 & op2
|
||||
ORRw_REG(x2, x2, x3); // op1 | op2
|
||||
BICw_REG(x2, x2, x1); // ~res & (op1 | op2)
|
||||
ORRw_REG(x2, x2, x4); // CC
|
||||
LSRw(x3, x2, 3);
|
||||
BFIw(xFlags, x3, F_AF, 1);
|
||||
LSRw(x3, x2, 14);
|
||||
EORw_REG_LSR(x3, x3, x3, 1);
|
||||
BFIw(xFlags, x3, F_OF, 1);
|
||||
emit_pf(dyn, ninst, x1, x4);
|
||||
RET(xLR);
|
||||
SETMARK(d_adc32);
|
||||
LDRx_U12(x1, xEmu, offsetof(x64emu_t, res));
|
||||
BFXILx(xFlags, x1, 32, 1); //F_CF
|
||||
@@ -844,7 +898,7 @@ SETMARK(d_shrd16);
|
||||
BFIw(xFlags, x4, F_OF, 1);
|
||||
BFCw(xFlags, F_AF, 1);
|
||||
}
|
||||
CBZw(x3, 4+4);
|
||||
CBNZw(x3, 4+4);
|
||||
RET(xLR);
|
||||
SUBw_U12(x4, x3, 1);
|
||||
LSRw_REG(x4, x2, x4);
|
||||
|
||||
+159
-103
@@ -46,6 +46,9 @@ dynablock_t* InvalidDynablock(dynablock_t* db, int need_lock)
|
||||
dynarec_log(LOG_DEBUG, "InvalidDynablock(%p), db->block=%p x64=%p:%p already gone=%d\n", db, db->block, db->x64_addr, db->x64_addr+db->x64_size-1, db->gone);
|
||||
// remove jumptable without waiting
|
||||
setJumpTableDefault64(db->x64_addr);
|
||||
for(int i=0; i<db->sep_size; ++i)
|
||||
if(db->sep[i].active)
|
||||
setJumpTableDefault64(db->x64_addr+db->sep[i].x64_offs);
|
||||
if(need_lock)
|
||||
mutex_lock(&my_context->mutex_dyndump);
|
||||
db->done = 0;
|
||||
@@ -131,8 +134,12 @@ void FreeDynablock(dynablock_t* db, int need_lock, int need_remove)
|
||||
return; // already in the process of deletion!
|
||||
dynarec_log(LOG_DEBUG, "FreeDynablock(%p), db->block=%p x64=%p:%p already gone=%d\n", db, db->block, db->x64_addr, db->x64_addr+db->x64_size-1, db->gone);
|
||||
// remove jumptable without waiting
|
||||
if(need_remove)
|
||||
if(need_remove) {
|
||||
setJumpTableDefault64(db->x64_addr);
|
||||
for(int i=0; i<db->sep_size; ++i)
|
||||
if(db->sep[i].active)
|
||||
setJumpTableDefault64(db->x64_addr+db->sep[i].x64_offs);
|
||||
}
|
||||
if(need_lock)
|
||||
mutex_lock(&my_context->mutex_dyndump);
|
||||
dynarec_log(LOG_DEBUG, " -- FreeDyrecMap(%p, %d)\n", db->actual_block, db->size);
|
||||
@@ -160,6 +167,9 @@ void MarkDynablock(dynablock_t* db)
|
||||
{
|
||||
if(db) {
|
||||
dynarec_log(LOG_DEBUG, "MarkDynablock %p %p-%p\n", db, db->x64_addr, db->x64_addr+db->x64_size-1);
|
||||
for(int i=0; i<db->sep_size; ++i)
|
||||
if(db->sep[i].active)
|
||||
setJumpTableIfRef64(db->x64_addr+db->sep[i].x64_offs, db->jmpnext, db->block+db->sep[i].nat_offs);
|
||||
if(!setJumpTableIfRef64(db->x64_addr, db->jmpnext, db->block)) {
|
||||
dynablock_t* old = db;
|
||||
db = getDB((uintptr_t)old->x64_addr);
|
||||
@@ -173,14 +183,16 @@ void MarkDynablock(dynablock_t* db)
|
||||
else
|
||||
db->previous = old;
|
||||
}
|
||||
}
|
||||
#ifdef ARCH_NOP
|
||||
else if(db->callret_size) {
|
||||
// mark all callrets to UDF
|
||||
for(int i=0; i<db->callret_size; ++i)
|
||||
*(uint32_t*)(db->block+db->callrets[i].offs) = ARCH_UDF;
|
||||
}
|
||||
} else {
|
||||
if(db->callret_size) {
|
||||
// mark all callrets to UDF
|
||||
for(int i=0; i<db->callret_size; ++i)
|
||||
*(uint32_t*)(db->block+db->callrets[i].offs) = ARCH_UDF;
|
||||
ClearCache(db->block, db->size);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,6 +213,18 @@ void MarkRangeDynablock(dynablock_t* db, uintptr_t addr, uintptr_t size)
|
||||
MarkDynablock(db);
|
||||
}
|
||||
|
||||
void MarkCRCRangeDynablock(dynablock_t* db, uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
// Mark will try to find *any* blocks that intersect the range to mark
|
||||
if(!db)
|
||||
return;
|
||||
dynarec_log(LOG_DEBUG, "MarkCRCRangeDynablock %p-%p .. startdb=%p, sizedb=%p\n", (void*)addr, (void*)addr+size-1, (void*)db->x64_addr, (void*)db->x64_size);
|
||||
if(IntervalIntersects((uintptr_t)db->x64_addr, (uintptr_t)db->x64_addr+db->x64_size-1, addr, addr+size+1)) {
|
||||
MarkDynablock(db); // mark as dirty
|
||||
db->to_delete = 1; // also invalid hash, so it will be deleted and replace
|
||||
}
|
||||
}
|
||||
|
||||
int FreeRangeDynablock(dynablock_t* db, uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
if(!db)
|
||||
@@ -214,13 +238,6 @@ int FreeRangeDynablock(dynablock_t* db, uintptr_t addr, uintptr_t size)
|
||||
return 1;
|
||||
}
|
||||
|
||||
NEW_JUMPBUFF(dynarec_jmpbuf);
|
||||
|
||||
void cancelFillBlock()
|
||||
{
|
||||
LongJmp(GET_JUMPBUFF(dynarec_jmpbuf), 1);
|
||||
}
|
||||
|
||||
void dynablock_leave_runtime(dynablock_t* db)
|
||||
{
|
||||
if(!db) return;
|
||||
@@ -228,20 +245,62 @@ void dynablock_leave_runtime(dynablock_t* db)
|
||||
__atomic_fetch_sub(&db->in_used, 1, __ATOMIC_ACQ_REL);
|
||||
}
|
||||
|
||||
dynablock_t* CreateDBnoAlt(x64emu_t* emu, uintptr_t addr, int is32bits)
|
||||
{
|
||||
#ifndef WIN32
|
||||
static int critical_filled = 0;
|
||||
static sigset_t critical_prot = {0};
|
||||
sigset_t old_sig = {0};
|
||||
if(!critical_filled) {
|
||||
critical_filled = 1;
|
||||
sigfillset(&critical_prot);
|
||||
sigdelset(&critical_prot, SIGSEGV);
|
||||
sigdelset(&critical_prot, SIGILL);
|
||||
sigdelset(&critical_prot, SIGBUS);
|
||||
sigdelset(&critical_prot, SIGINT);
|
||||
sigdelset(&critical_prot, SIGABRT);
|
||||
sigdelset(&critical_prot, SIGFPE);
|
||||
}
|
||||
#endif
|
||||
|
||||
pthread_sigmask(SIG_BLOCK, &critical_prot, &old_sig);
|
||||
|
||||
if(BOX64ENV(dynarec_wait)) {
|
||||
mutex_lock(&my_context->mutex_dyndump);
|
||||
} else {
|
||||
if(mutex_trylock(&my_context->mutex_dyndump)) { // FillBlock not available for now
|
||||
pthread_sigmask(SIG_SETMASK, &old_sig, NULL);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
dynarec_log(LOG_DEBUG, "Will call Fillblock64 for Alt %p\n", (void*)addr);
|
||||
dynablock_t* block = FillBlock64(addr, is32bits, MAX_INSTS, 0, 1);
|
||||
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
|
||||
pthread_sigmask(SIG_SETMASK, &old_sig, NULL);
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
/*
|
||||
return NULL if block is not found / cannot be created.
|
||||
Don't create if create==0
|
||||
*/
|
||||
static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t filladdr, int create, int need_lock, int is32bits, int is_new)
|
||||
static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, int create, int need_lock, int is32bits, int is_new)
|
||||
{
|
||||
if (hasAlternate((void*)filladdr))
|
||||
return NULL;
|
||||
const uint32_t req_prot = (box64_pagesize==4096)?(PROT_EXEC|PROT_READ):PROT_READ;
|
||||
if(BOX64ENV(nodynarec_delay) && (addr>=BOX64ENV(nodynarec_start)) && (addr<BOX64ENV(nodynarec_end)))
|
||||
return NULL;
|
||||
dynablock_t* block = getDB(addr);
|
||||
if(block && block->to_delete) {
|
||||
// just delete the block then, so we can create a new one right away
|
||||
FreeDynablock(block, 1, 1);
|
||||
block = NULL;
|
||||
}
|
||||
if(block || !create) {
|
||||
if(block && getNeedTest(addr) && (getProtection(addr)&req_prot)!=req_prot)
|
||||
if(block && getNeedTest(addr) && (getProtection(block->x64_readaddr)&req_prot)!=req_prot)
|
||||
block = NULL;
|
||||
return block;
|
||||
}
|
||||
@@ -273,37 +332,27 @@ static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t
|
||||
}
|
||||
}
|
||||
block = getDB(addr); // just in case
|
||||
if(block && block->to_delete) {
|
||||
// just delete the block then, so we can create a new one right away
|
||||
FreeDynablock(block, 0, 1);
|
||||
block = NULL;
|
||||
}
|
||||
if(block) {
|
||||
if(block && getNeedTest(addr) && (getProtection_fast(addr)&req_prot)!=req_prot)
|
||||
if(block && getNeedTest(addr) && (getProtection_fast(block->x64_readaddr)&req_prot)!=req_prot)
|
||||
block = NULL;
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
pthread_sigmask(SIG_SETMASK, &old_sig, NULL);
|
||||
return block;
|
||||
}
|
||||
}
|
||||
#ifndef _WIN32
|
||||
if((getProtection_fast(addr)&req_prot)!=req_prot) {// cannot be run, get out of the Dynarec
|
||||
if(need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
pthread_sigmask(SIG_SETMASK, &old_sig, NULL);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
if (SigSetJmp(GET_JUMPBUFF(dynarec_jmpbuf), 1)) {
|
||||
printf_log(LOG_INFO, "FillBlock at %p triggered a segfault, canceling\n", (void*)addr);
|
||||
if(need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
pthread_sigmask(SIG_SETMASK, &old_sig, NULL);
|
||||
return NULL;
|
||||
}
|
||||
block = FillBlock64(filladdr, (addr==filladdr)?0:1, is32bits, MAX_INSTS, is_new);
|
||||
block = FillBlock64(addr, is32bits, MAX_INSTS, is_new, 0);
|
||||
if(!block) {
|
||||
dynarec_log(LOG_DEBUG, "Fillblock of block %p for %p returned an error\n", block, (void*)addr);
|
||||
}
|
||||
// check size
|
||||
if(block) {
|
||||
// fill-in jumptable
|
||||
if(!addJumpTableIfDefault64(block->x64_addr, (block->dirty || block->always_test)?block->jmpnext:block->block)) {
|
||||
if(!addJumpTableIfDefault64((void*)addr, (block->dirty || block->always_test)?block->jmpnext:block->block)) {
|
||||
FreeDynablock(block, 0, 0);
|
||||
block = getDB(addr);
|
||||
MarkDynablock(block); // just in case...
|
||||
@@ -318,6 +367,14 @@ static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t
|
||||
block->done = 1; // don't validate the block if the size is null, but keep the block
|
||||
rb_inc(my_context->db_sizes, block->x64_size, block->x64_size+1);
|
||||
}
|
||||
for(int i=0; i<block->sep_size; ++i) {
|
||||
uintptr_t x64_offs = block->sep[i].x64_offs;
|
||||
uintptr_t nat_offs = block->sep[i].nat_offs;
|
||||
if(addJumpTableIfDefault64(block->x64_addr+x64_offs, (block->dirty || block->always_test)?block->jmpnext:(block->block+nat_offs)))
|
||||
block->sep[i].active = 1;
|
||||
else
|
||||
block->sep[i].active = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(need_lock)
|
||||
@@ -329,26 +386,68 @@ static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t
|
||||
return block;
|
||||
}
|
||||
|
||||
dynablock_t* DBSwapInvalid(x64emu_t* emu, dynablock_t* db, uintptr_t addr, int is32bits, int need_lock)
|
||||
{
|
||||
if(need_lock)
|
||||
mutex_lock(&my_context->mutex_dyndump);
|
||||
db->done = 0; // invalidating the block
|
||||
dynarec_log(LOG_DEBUG, "Invalidating alt block %p from %p:%p (hash:%X, gone:%d, autocrc:%d, to_delete:%d) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size, db->hash, db->gone, db->autocrc, db->to_delete, (void*)addr);
|
||||
// Free db, it's now invalid!
|
||||
dynablock_t* old = InvalidDynablock(db, 0);
|
||||
if(old->previous) {
|
||||
dynarec_log(LOG_DEBUG, "Free alt alt block %p\n", db->previous);
|
||||
FreeInvalidDynablock(db->previous, 0);
|
||||
old->previous = NULL;
|
||||
}
|
||||
// start again... (will create a new block)
|
||||
db = internalDBGetBlock(emu, addr, 1, 0, is32bits, 0);
|
||||
if(db) {
|
||||
if(db->previous)
|
||||
FreeInvalidDynablock(db->previous, 0);
|
||||
db->previous = old;
|
||||
} else
|
||||
FreeInvalidDynablock(old, 0);
|
||||
if(need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
return db;
|
||||
}
|
||||
|
||||
dynablock_t* DBSwitchPrevious(x64emu_t* emu, dynablock_t* db, uintptr_t addr, int need_lock)
|
||||
{
|
||||
dynarec_log(LOG_DEBUG, "Switching to alt block %p from %p:%p (hash:%X) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size, db->hash, (void*)addr);
|
||||
db = SwitchDynablock(db, need_lock);
|
||||
if(!addJumpTableIfDefault64(db->x64_addr, (db->always_test)?db->jmpnext:db->block)) {
|
||||
FreeDynablock(db, need_lock, 0);
|
||||
db = getDB(addr);
|
||||
MarkDynablock(db); // just in case...
|
||||
} else {
|
||||
for(int i=0; i<db->sep_size; ++i) {
|
||||
uint32_t x64_offs = db->sep[i].x64_offs;
|
||||
uint32_t nat_offs = db->sep[i].nat_offs;
|
||||
if(addJumpTableIfDefault64(db->x64_addr+x64_offs, (db->always_test)?db->jmpnext:(db->block+nat_offs)))
|
||||
db->sep[i].active = 1;
|
||||
else
|
||||
db->sep[i].active = 0;
|
||||
}
|
||||
}
|
||||
return db;
|
||||
}
|
||||
|
||||
dynablock_t* DBGetBlock(x64emu_t* emu, uintptr_t addr, int create, int is32bits)
|
||||
{
|
||||
int is_inhotpage = isInHotPage(addr);
|
||||
if(is_inhotpage && !BOX64ENV(dynarec_dirty))
|
||||
return NULL;
|
||||
dynablock_t *db = internalDBGetBlock(emu, addr, addr, create, 1, is32bits, 1);
|
||||
dynablock_t *db = internalDBGetBlock(emu, addr, create, 1, is32bits, 1);
|
||||
if(db && db->done && db->block && getNeedTest(addr)) {
|
||||
//if (db->always_test) SchedYield(); // just calm down...
|
||||
uint32_t hash = X31_hash_code(db->x64_addr, db->x64_size);
|
||||
uint32_t hash = X31_hash_code((void*)db->x64_readaddr, db->x64_size);
|
||||
mutex_lock(&my_context->mutex_dyndump)?1:0;
|
||||
if(hash!=db->hash) {
|
||||
if(is_inhotpage && db->previous) {
|
||||
// check alternate
|
||||
if(db->previous && !db->dirty && X31_hash_code(db->previous->x64_addr, db->previous->x64_size)==db->previous->hash) {
|
||||
db = SwitchDynablock(db, 0);
|
||||
if(!addJumpTableIfDefault64(db->x64_addr, (db->always_test)?db->jmpnext:db->block)) {
|
||||
FreeDynablock(db, 0, 0);
|
||||
db = getDB(addr);
|
||||
MarkDynablock(db); // just in case...
|
||||
}
|
||||
if(db->previous && !db->dirty && X31_hash_code((void*)db->previous->x64_readaddr, db->previous->x64_size)==db->previous->hash) {
|
||||
db = DBSwitchPrevious(emu, db, addr, 0);
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
return db;
|
||||
}
|
||||
@@ -356,18 +455,7 @@ dynablock_t* DBGetBlock(x64emu_t* emu, uintptr_t addr, int create, int is32bits)
|
||||
dynarec_log(LOG_DEBUG, "Cannot run block (or previous) %p from %p:%p (hash:%X/%X, always_test:%d, previous=%p/hash=%X) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size-1, hash, db->hash, db->always_test,db->previous, db->previous?db->previous->hash:0,(void*)addr);
|
||||
return NULL; // will be handle when hotpage is over
|
||||
}
|
||||
db->done = 0; // invalidating the block
|
||||
dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X/%X, always_test:%d, previous=%p/hash=%X) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size-1, hash, db->hash, db->always_test,db->previous, db->previous?db->previous->hash:0,(void*)addr);
|
||||
// Free db, it's now invalid!
|
||||
dynablock_t* old = InvalidDynablock(db, 0);
|
||||
// start again... (will create a new block)
|
||||
db = internalDBGetBlock(emu, addr, addr, create, 0, is32bits, 0);
|
||||
if(db) {
|
||||
if(db->previous)
|
||||
FreeInvalidDynablock(db->previous, 0);
|
||||
db->previous = old;
|
||||
} else
|
||||
FreeInvalidDynablock(old, 0);
|
||||
db = DBSwapInvalid(emu, db, addr, is32bits, 0);
|
||||
} else {
|
||||
if(is_inhotpage) {
|
||||
db->always_test = 2;
|
||||
@@ -375,9 +463,12 @@ dynablock_t* DBGetBlock(x64emu_t* emu, uintptr_t addr, int create, int is32bits)
|
||||
} else {
|
||||
dynarec_log(LOG_DEBUG, "Validating block %p from %p:%p (hash:%X, always_test:%d) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size-1, db->hash, db->always_test, (void*)addr);
|
||||
if(db->always_test) {
|
||||
if(db->always_test==2)
|
||||
if(db->always_test==2) {
|
||||
db->always_test = 0;
|
||||
protectDB((uintptr_t)db->x64_addr, db->x64_size);
|
||||
protectDB((uintptr_t)db->x64_addr, db->x64_size);
|
||||
}
|
||||
// always_test==1 (NEVERCLEAN): skip protectDB, the page has mixed
|
||||
// code+data and mprotect would strip writability from data regions
|
||||
} else {
|
||||
#ifdef ARCH_NOP
|
||||
if(db->callret_size) {
|
||||
@@ -388,6 +479,15 @@ dynablock_t* DBGetBlock(x64emu_t* emu, uintptr_t addr, int create, int is32bits)
|
||||
}
|
||||
#endif
|
||||
protectDBJumpTable((uintptr_t)db->x64_addr, db->x64_size, db->block, db->jmpnext);
|
||||
if(!db->always_test)
|
||||
for(int i=0; i<db->sep_size; ++i) {
|
||||
uint32_t x64_offs = db->sep[i].x64_offs;
|
||||
uint32_t nat_offs = db->sep[i].nat_offs;
|
||||
if(setJumpTableIfRef64(db->x64_addr+x64_offs, (db->always_test)?db->jmpnext:(db->block+nat_offs), db->jmpnext))
|
||||
db->sep[i].active = 1;
|
||||
else
|
||||
db->sep[i].active = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -398,50 +498,6 @@ dynablock_t* DBGetBlock(x64emu_t* emu, uintptr_t addr, int create, int is32bits)
|
||||
return db;
|
||||
}
|
||||
|
||||
dynablock_t* DBAlternateBlock(x64emu_t* emu, uintptr_t addr, uintptr_t filladdr, int is32bits)
|
||||
{
|
||||
dynarec_log(LOG_DEBUG, "Creating AlternateBlock at %p for %p%s\n", (void*)addr, (void*)filladdr, is32bits?" 32bits":"");
|
||||
int create = 1;
|
||||
dynablock_t *db = internalDBGetBlock(emu, addr, filladdr, create, 1, is32bits, 1);
|
||||
if(db && db->done && db->block && (db->dirty || getNeedTest(filladdr))) {
|
||||
if (db->always_test) SchedYield(); // just calm down...
|
||||
mutex_lock(&my_context->mutex_dyndump);
|
||||
uint32_t hash = X31_hash_code(db->x64_addr, db->x64_size);
|
||||
if(hash!=db->hash) {
|
||||
db->done = 0; // invalidating the block
|
||||
dynarec_log(LOG_DEBUG, "Invalidating alt block %p from %p:%p (hash:%X/%X) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size, hash, db->hash, (void*)addr);
|
||||
// Free db, it's now invalid!
|
||||
dynablock_t* old = InvalidDynablock(db, 0);
|
||||
// start again... (will create a new block)
|
||||
db = internalDBGetBlock(emu, addr, filladdr, create, 0, is32bits, 0);
|
||||
if(db) {
|
||||
if(db->previous)
|
||||
FreeInvalidDynablock(db->previous, 0);
|
||||
db->previous = old;
|
||||
} else
|
||||
FreeInvalidDynablock(old, 0);
|
||||
} else {
|
||||
if(db->always_test)
|
||||
protectDB((uintptr_t)db->x64_addr, db->x64_size);
|
||||
else {
|
||||
#ifdef ARCH_NOP
|
||||
if(db->callret_size) {
|
||||
// mark all callrets to UDF
|
||||
for(int i=0; i<db->callret_size; ++i)
|
||||
*(uint32_t*)(db->block+db->callrets[i].offs) = ARCH_NOP;
|
||||
ClearCache(db->block, db->size);
|
||||
}
|
||||
#endif
|
||||
protectDBJumpTable((uintptr_t)db->x64_addr, db->x64_size, db->block, db->jmpnext);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
}
|
||||
if(!db || !db->block || !db->done)
|
||||
emu->test.test = 0;
|
||||
return db;
|
||||
}
|
||||
|
||||
uintptr_t getX64Address(dynablock_t* db, uintptr_t native_addr)
|
||||
{
|
||||
if ((native_addr < (uintptr_t)db->block) || (native_addr > (uintptr_t)db->actual_block + db->size))
|
||||
|
||||
@@ -11,6 +11,12 @@ typedef struct callret_s {
|
||||
uint32_t type:1;
|
||||
} callret_t;
|
||||
|
||||
typedef struct sep_s {
|
||||
uint32_t active:1;
|
||||
uint32_t nat_offs:31;
|
||||
uint32_t x64_offs;
|
||||
} sep_t;
|
||||
|
||||
typedef struct dynablock_s {
|
||||
void* block; // block-sizeof(void*) == self
|
||||
void* actual_block; // the actual start of the block (so block-sizeof(void*))
|
||||
@@ -20,6 +26,7 @@ typedef struct dynablock_s {
|
||||
void* x64_addr;
|
||||
uintptr_t x64_size;
|
||||
size_t native_size;
|
||||
uintptr_t x64_readaddr; // in case an alternate address is in effect, it can be different than x64_addr
|
||||
uint32_t prefixsize; // size in byte of the prefix of the block
|
||||
int size;
|
||||
uint32_t hash;
|
||||
@@ -28,12 +35,16 @@ typedef struct dynablock_s {
|
||||
uint8_t dirty; // if need to be tested as soon as it's created
|
||||
uint8_t always_test:2;
|
||||
uint8_t is32bits:1;
|
||||
uint8_t autocrc:1;
|
||||
uint8_t to_delete:1;
|
||||
int callret_size; // size of the array
|
||||
int isize;
|
||||
size_t arch_size; // size of of arch dependant infos
|
||||
int arch_size; // size of of arch dependant infos
|
||||
int sep_size; // SEP are the Secondary Entry Point
|
||||
instsize_t* instsize;
|
||||
void* arch; // arch dependant per inst info (can be NULL)
|
||||
callret_t* callrets; // array of callret return, with NOP / UDF depending if the block is clean or dirty
|
||||
sep_t* sep; // secondary entry point, offsets are relative to x64_addr & block
|
||||
void* jmpnext; // a branch jmpnext code when block is marked
|
||||
size_t table64size;// to check table64
|
||||
void* table64; // to relocate the table64
|
||||
|
||||
@@ -10,6 +10,9 @@
|
||||
#elif defined(LA64)
|
||||
#include "dynarec/la64/dynarec_la64_consts.h"
|
||||
#define native_consts_t la64_consts_t
|
||||
#elif defined(PPC64LE)
|
||||
#include "dynarec/ppc64le/dynarec_ppc64le_consts.h"
|
||||
#define native_consts_t ppc64le_consts_t
|
||||
#else
|
||||
#error Unsupported architecture
|
||||
#endif
|
||||
|
||||
+120
-32
@@ -14,11 +14,11 @@
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "threads.h"
|
||||
#include "alternate.h"
|
||||
#ifdef DYNAREC
|
||||
#include "dynablock.h"
|
||||
#include "dynablock_private.h"
|
||||
#include "bridge.h"
|
||||
#include "alternate.h"
|
||||
#include "dynarec_next.h"
|
||||
#include "custommem.h"
|
||||
#include "x64test.h"
|
||||
@@ -27,40 +27,40 @@
|
||||
#include "elfloader.h"
|
||||
#endif
|
||||
|
||||
extern int running32bits;
|
||||
#ifdef DYNAREC
|
||||
void* LinkNext(x64emu_t* emu, uintptr_t addr, void* x2, uintptr_t* x3)
|
||||
{
|
||||
int is32bits = (R_CS == 0x23);
|
||||
#ifdef HAVE_TRACE
|
||||
if(!running32bits && is32bits) running32bits=1;
|
||||
#ifndef HAVE_ALTJUMP
|
||||
// inefficient way to handle alternate without ALTJUMP
|
||||
uintptr_t new_addr = (uintptr_t)getAlternate((void*)addr);
|
||||
if(new_addr!=addr) {
|
||||
*x3 = new_addr;
|
||||
addr = new_addr;
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_TRACE
|
||||
if(!addr) {
|
||||
dynablock_t* db = FindDynablockFromNativeAddress(x2-4);
|
||||
printf_log(LOG_INFO, "Warning, jumping to NULL address from %p (db=%p, x64addr=%p/%s)\n", x2-4, db, db?(void*)getX64Address(db, (uintptr_t)x2-4):NULL, db?getAddrFunctionName(getX64Address(db, (uintptr_t)x2-4)):"(nil)");
|
||||
} else if(new_addr<0x10000) {
|
||||
} else if(addr<0x10000) {
|
||||
dynablock_t* db = FindDynablockFromNativeAddress(x2-4);
|
||||
printf_log(LOG_INFO, "Warning, jumping to low address %p->%p from %p (db=%p, x64addr=%p/%s)\n", (void*)new_addr, (void*)addr, x2-4, db, db?(void*)getX64Address(db, (uintptr_t)x2-4):NULL, db?getAddrFunctionName(getX64Address(db, (uintptr_t)x2-4)):"(nil)");
|
||||
printf_log(LOG_INFO, "Warning, jumping to low address %p from %p (db=%p, x64addr=%p/%s)\n", (void*)addr, x2-4, db, db?(void*)getX64Address(db, (uintptr_t)x2-4):NULL, db?getAddrFunctionName(getX64Address(db, (uintptr_t)x2-4)):"(nil)");
|
||||
#ifdef BOX32
|
||||
} else if(emu->segs[_CS]==0x23 && addr>0x100000000LL) {
|
||||
dynablock_t* db = FindDynablockFromNativeAddress(x2-4);
|
||||
printf_log(LOG_INFO, "Warning, jumping to high address %p from %p (db=%p, x64addr=%p/%s)\n", (void*)addr, x2-4, db, db?(void*)getX64Address(db, (uintptr_t)x2-4):NULL, db?getAddrFunctionName(getX64Address(db, (uintptr_t)x2-4)):"(nil)");
|
||||
#endif
|
||||
} else if(!memExist(new_addr)) {
|
||||
} else if(!memExist(addr)) {
|
||||
dynablock_t* db = FindDynablockFromNativeAddress(x2-4);
|
||||
printf_log(LOG_INFO, "Warning, jumping to an unmapped address %p->%p from %p (db=%p, x64addr=%p/%s)\n", (void*)new_addr, (void*)addr, x2-4, db, db?(void*)getX64Address(db, (uintptr_t)x2-4):NULL, db?getAddrFunctionName(getX64Address(db, (uintptr_t)x2-4)):"(nil)");
|
||||
printf_log(LOG_INFO, "Warning, jumping to an unmapped address %p from %p (db=%p, x64addr=%p/%s)\n", (void*)addr, x2-4, db, db?(void*)getX64Address(db, (uintptr_t)x2-4):NULL, db?getAddrFunctionName(getX64Address(db, (uintptr_t)x2-4)):"(nil)");
|
||||
}
|
||||
#endif
|
||||
void * jblock;
|
||||
dynablock_t* block = NULL;
|
||||
if(hasAlternate((void*)addr)) {
|
||||
printf_log(LOG_DEBUG, "Jmp address has alternate: %p\n", (void*)addr);
|
||||
uintptr_t old_addr = addr;
|
||||
addr = (uintptr_t)getAlternate((void*)addr); // set new address
|
||||
R_RIP = addr; // but also new RIP!
|
||||
*x3 = addr; // and the RIP in x27 register
|
||||
printf_log(LOG_DEBUG, " -> %p\n", (void*)addr);
|
||||
block = DBAlternateBlock(emu, old_addr, addr, is32bits);
|
||||
} else
|
||||
block = DBGetBlock(emu, addr, 1, is32bits);
|
||||
block = DBGetBlock(emu, addr, 1, is32bits);
|
||||
if(!block) {
|
||||
#ifdef HAVE_TRACE
|
||||
if(LOG_INFO<=BOX64ENV(dynarec_log)) {
|
||||
@@ -90,12 +90,48 @@ void* LinkNext(x64emu_t* emu, uintptr_t addr, void* x2, uintptr_t* x3)
|
||||
// null block, but done: go to epilog, no linker here
|
||||
return native_epilog;
|
||||
}
|
||||
if(block->sep_size && (uintptr_t)block->x64_addr!=addr) {
|
||||
jblock = NULL;
|
||||
for(int i=0; i<block->sep_size && !jblock; ++i) {
|
||||
if(addr==(uintptr_t)block->x64_addr + block->sep[i].x64_offs)
|
||||
jblock = block->block + block->sep[i].nat_offs;
|
||||
}
|
||||
if(!jblock) {
|
||||
printf_log(LOG_NONE, "Warning, cannot find Secondary Entry Point %p in dynablock %p\n", addr, block);
|
||||
return native_epilog;
|
||||
}
|
||||
}
|
||||
//dynablock_t *father = block->father?block->father:block;
|
||||
return jblock;
|
||||
}
|
||||
void* LinkNextInvalid(x64emu_t* emu, uintptr_t addr, void* x2, uintptr_t* x3)
|
||||
{
|
||||
// like LinkNext, but invalid the db found first
|
||||
int is32bits = (R_CS == 0x23);
|
||||
dynablock_t* db = getDB(addr);
|
||||
if(db) {
|
||||
if(db->previous && !db->dirty && X31_hash_code(db->previous->x64_addr, db->previous->x64_size)==db->previous->hash)
|
||||
db = DBSwitchPrevious(emu, db, addr, 1);
|
||||
else
|
||||
db = DBSwapInvalid(emu, db, addr, is32bits, 1);
|
||||
if(db && db->done && db->block) {
|
||||
void* jblock = db->block;
|
||||
if(db->sep_size && (uintptr_t)db->x64_addr!=addr) {
|
||||
jblock = NULL; // not sure how this would happens here, but lets put the case it starts on SEP anyway
|
||||
for(int i=0; i<db->sep_size && !jblock; ++i) {
|
||||
if(addr==(uintptr_t)db->x64_addr + db->sep[i].x64_offs)
|
||||
jblock = db->block + db->sep[i].nat_offs;
|
||||
}
|
||||
}
|
||||
if(jblock)
|
||||
return jblock;
|
||||
}
|
||||
}
|
||||
return LinkNext(emu, addr, x2, x3);
|
||||
}
|
||||
#endif
|
||||
|
||||
void DynaCall(x64emu_t* emu, uintptr_t addr)
|
||||
void DynaCall(x64emu_t* emu, uintptr_t addr, int no_alt)
|
||||
{
|
||||
uint64_t old_rsp = R_RSP;
|
||||
uint64_t old_rbx = R_RBX;
|
||||
@@ -118,8 +154,9 @@ void DynaCall(x64emu_t* emu, uintptr_t addr)
|
||||
PushExit(emu);
|
||||
R_RIP = addr;
|
||||
emu->df = d_none;
|
||||
emu->flags.need_jmpbuf = 1;
|
||||
EmuRun(emu, 1);
|
||||
if(emu->flags.quitonlongjmp)
|
||||
emu->flags.need_jmpbuf = 1;
|
||||
EmuRun(emu, 1, no_alt);
|
||||
emu->quit = 0; // reset Quit flags...
|
||||
emu->df = d_none;
|
||||
if(emu->flags.quitonlongjmp && emu->flags.longjmp) {
|
||||
@@ -142,22 +179,45 @@ void DynaCall(x64emu_t* emu, uintptr_t addr)
|
||||
}
|
||||
}
|
||||
|
||||
extern int running32bits;
|
||||
void EmuRun(x64emu_t* emu, int use_dynarec)
|
||||
#ifdef DYNAREC
|
||||
static dynablock_t* fastDBGetBlock(x64emu_t* emu, uintptr_t addr, int create, int is32bits)
|
||||
{
|
||||
dynablock_t* ret = getDBnoTest(R_RIP);
|
||||
if(!ret)
|
||||
ret = DBGetBlock(emu, R_RIP, 1, is32bits);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef HAVE_ALTJUMP
|
||||
static dynablock_t* getDBnoAlt(x64emu_t* emu, uintptr_t addr, int is32bits)
|
||||
{
|
||||
dynablock_t* ret = getAlternateData((void*)addr);
|
||||
if(ret == (void*)-1LL)
|
||||
return NULL;
|
||||
if(!ret) {
|
||||
ret = CreateDBnoAlt(emu, addr, is32bits);
|
||||
setAlternateData((void*)addr, ret);
|
||||
}
|
||||
dynarec_log(LOG_DEBUG, "Will use No-Alt block %p for Alt %p\n", ret, (void*)addr);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void EmuRun(x64emu_t* emu, int use_dynarec, int no_alt)
|
||||
{
|
||||
// prepare setjump for signal handling
|
||||
JUMPBUFF jmpbuf[1] = {0};
|
||||
int skip = 0;
|
||||
JUMPBUFF *old_jmpbuf = emu->jmpbuf;
|
||||
#ifdef RV64
|
||||
#if defined(RV64) || defined(PPC64LE)
|
||||
uintptr_t old_savesp = emu->xSPSave;
|
||||
#endif
|
||||
emu->flags.jmpbuf_ready = 0;
|
||||
int is32bits = (emu->segs[_CS]==0x23);
|
||||
while(!(emu->quit)) {
|
||||
if(!emu->jmpbuf || (emu->flags.need_jmpbuf && emu->jmpbuf!=jmpbuf)) {
|
||||
emu->jmpbuf = jmpbuf;
|
||||
#ifdef RV64
|
||||
#if defined(RV64) || defined(PPC64LE)
|
||||
emu->old_savedsp = emu->xSPSave;
|
||||
#endif
|
||||
emu->flags.jmpbuf_ready = 1;
|
||||
@@ -181,7 +241,17 @@ void EmuRun(x64emu_t* emu, int use_dynarec)
|
||||
}
|
||||
if(emu->flags.need_jmpbuf)
|
||||
emu->flags.need_jmpbuf = 0;
|
||||
|
||||
if(no_alt)
|
||||
{
|
||||
// the Dynarec will shadow the Entry Point, so using Intperter to enter the function
|
||||
#if defined(DYNAREC) && defined(HAVE_ALTJUMP)
|
||||
if(!BOX64ENV(dynarec))
|
||||
#endif
|
||||
no_alt = 0;
|
||||
skip = 1;
|
||||
}
|
||||
else
|
||||
R_RIP = (uintptr_t)getAlternate((void*)R_RIP);
|
||||
#ifdef DYNAREC
|
||||
if(!BOX64ENV(dynarec) || !use_dynarec)
|
||||
#endif
|
||||
@@ -204,17 +274,23 @@ void EmuRun(x64emu_t* emu, int use_dynarec)
|
||||
running32bits = 1;
|
||||
}
|
||||
}
|
||||
dynablock_t* block = (skip)?NULL:DBGetBlock(emu, R_RIP, 1, is32bits);
|
||||
dynablock_t* block = (skip || ACCESS_FLAG(F_TF))?NULL:fastDBGetBlock(emu, R_RIP, 1, is32bits);
|
||||
#ifdef HAVE_ALTJUMP
|
||||
if(skip && no_alt) {
|
||||
block = getDBnoAlt(emu, R_RIP, is32bits);
|
||||
no_alt = 0;
|
||||
}
|
||||
#endif
|
||||
if(!block || !block->block || !block->done || ACCESS_FLAG(F_TF)) {
|
||||
skip = 0;
|
||||
// no block, of block doesn't have DynaRec content (yet, temp is not null)
|
||||
// no block, or block doesn't have DynaRec content (yet, temp is not null)
|
||||
// Use interpreter (should use single instruction step...)
|
||||
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);
|
||||
dynarec_log(LOG_DEBUG, "%04d|Running Interpreter @%p, emu=%p (skip=%d)\n", GetTID(), (void*)R_RIP, emu, skip);
|
||||
}
|
||||
skip = 0;
|
||||
if (BOX64ENV(dynarec_test))
|
||||
emu->test.clean = 0;
|
||||
Run(emu, 1);
|
||||
@@ -224,7 +300,19 @@ void EmuRun(x64emu_t* emu, int use_dynarec)
|
||||
CHECK_FLAGS(emu);
|
||||
}
|
||||
// block is here, let's run it!
|
||||
native_prolog(emu, block->block);
|
||||
void* jblock = block->block;
|
||||
if(block->sep_size && R_RIP!=(uintptr_t)block->x64_addr) {
|
||||
jblock = NULL;
|
||||
for(int i=0; i<block->sep_size && !jblock; ++i) {
|
||||
if(R_RIP==(uintptr_t)block->x64_addr + block->sep[i].x64_offs)
|
||||
jblock = block->block + block->sep[i].nat_offs;
|
||||
}
|
||||
}
|
||||
if(!jblock) {
|
||||
printf_log(LOG_NONE, "Warning, cannot find Secondary Entry Point %p in dynablock %p\n", (void*)R_RIP, block);
|
||||
skip = 1;
|
||||
} else
|
||||
native_prolog(emu, jblock);
|
||||
}
|
||||
if(emu->fork) {
|
||||
int forktype = emu->fork;
|
||||
@@ -239,12 +327,12 @@ void EmuRun(x64emu_t* emu, int use_dynarec)
|
||||
}
|
||||
// clear the setjmp
|
||||
emu->jmpbuf = old_jmpbuf;
|
||||
#ifdef RV64
|
||||
#if defined(RV64) || defined(PPC64LE)
|
||||
emu->xSPSave = old_savesp;
|
||||
#endif
|
||||
}
|
||||
|
||||
void DynaRun(x64emu_t *emu)
|
||||
{
|
||||
EmuRun(emu, 1);
|
||||
EmuRun(emu, 1, 0);
|
||||
}
|
||||
+170
-110
@@ -1,110 +1,170 @@
|
||||
#ifndef __DYNAREC_ARCH__H_
|
||||
#define __DYNAREC_ARCH__H_
|
||||
|
||||
#ifdef ARM64
|
||||
|
||||
#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);
|
||||
|
||||
#define OTHER_CACHE() \
|
||||
if (fpuCacheNeedsTransform(dyn, ninst)) ret|=2; \
|
||||
if (nativeFlagsNeedsTransform(dyn, ninst)) ret|=4;
|
||||
|
||||
#include "arm64/arm64_printer.h"
|
||||
#include "arm64/dynarec_arm64_private.h"
|
||||
#include "arm64/dynarec_arm64_functions.h"
|
||||
#include "arm64/dynarec_arm64_arch.h"
|
||||
// TBZ/TBNZ is signed 14bits shifted by 2, but not use to jump from opcode to opcode
|
||||
// Limit here is defined by LD litteral, that is 19bits signed ledt shifted by 2. So 20bits (positive/negative) address space (used for TABLE64)
|
||||
// C.cond is also signed 19bits shifted by 2
|
||||
#define MAXBLOCK_SIZE ((1<<20)-200)
|
||||
|
||||
#define RAZ_SPECIFIC(A, N) rasNativeState(A, N)
|
||||
#define UPDATE_SPECIFICS(A) updateYmm0s(dyn, 0, 0); updateNativeFlags(A); propagateFpuBarrier(A)
|
||||
#define PREUPDATE_SPECIFICS(A)
|
||||
#define POSTUPDATE_SPECIFICS(A) updateUneeded(A)
|
||||
#define ARCH_SIZE(A) get_size_arch(A)
|
||||
#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)
|
||||
extern uint32_t arm64_crc(void* p, uint32_t len);
|
||||
#define ARCH_CRC(A, B) if(cpuext.crc32) return arm64_crc(A, B)
|
||||
extern void* create_updateflags();
|
||||
#define ARCH_UPDATEFLAGS() create_updateflags()
|
||||
|
||||
#define ARCH_NOP 0b11010101000000110010000000011111
|
||||
#define ARCH_UDF 0xcafe
|
||||
#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);
|
||||
|
||||
#define OTHER_CACHE() \
|
||||
if (fpuCacheNeedsTransform(dyn, ninst)) ret |= 2;
|
||||
|
||||
#include "la64/la64_printer.h"
|
||||
#include "la64/dynarec_la64_private.h"
|
||||
#include "la64/dynarec_la64_functions.h"
|
||||
// Limit here is unconditionnal jump, that is signed 28bits
|
||||
#define MAXBLOCK_SIZE ((1 << 27) - 200)
|
||||
|
||||
#define RAZ_SPECIFIC(A, N)
|
||||
#define UPDATE_SPECIFICS(A) propagateFpuBarrier(A)
|
||||
#define PREUPDATE_SPECIFICS(A) updateNativeFlags(A)
|
||||
#define POSTUPDATE_SPECIFICS(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
|
||||
extern uint32_t la64_crc(void* p, uint32_t len);
|
||||
#define ARCH_CRC(A, B) return la64_crc(A, B)
|
||||
|
||||
#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); \
|
||||
int sewNeedsTransform(dynarec_rv64_t* dyn, int ninst);
|
||||
|
||||
#define OTHER_CACHE() \
|
||||
if (fpuCacheNeedsTransform(dyn, ninst)) ret |= 2; \
|
||||
if (sewNeedsTransform(dyn, ninst)) ret |= 4;
|
||||
|
||||
#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 POSTUPDATE_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) {}
|
||||
#define STOP_NATIVE_FLAGS(A, B) {}
|
||||
#define ARCH_UNALIGNED(A, B) arch_unaligned(A, B)
|
||||
#else
|
||||
#error Unsupported platform
|
||||
#endif
|
||||
|
||||
#include "dynacache_reloc.h"
|
||||
|
||||
#endif //__DYNAREC_ARCH__H_
|
||||
#ifndef __DYNAREC_ARCH__H_
|
||||
#define __DYNAREC_ARCH__H_
|
||||
|
||||
#ifdef ARM64
|
||||
|
||||
#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);
|
||||
|
||||
#define OTHER_CACHE() \
|
||||
if (fpuCacheNeedsTransform(dyn, ninst)) ret|=2; \
|
||||
if (nativeFlagsNeedsTransform(dyn, ninst)) ret|=4;
|
||||
|
||||
#include "arm64/arm64_printer.h"
|
||||
#include "arm64/dynarec_arm64_private.h"
|
||||
#include "arm64/dynarec_arm64_functions.h"
|
||||
#include "arm64/dynarec_arm64_arch.h"
|
||||
// TBZ/TBNZ is signed 14bits shifted by 2, but not use to jump from opcode to opcode
|
||||
// Limit here is defined by LD litteral, that is 19bits signed ledt shifted by 2. So 20bits (positive/negative) address space (used for TABLE64)
|
||||
// C.cond is also signed 19bits shifted by 2
|
||||
#define MAXBLOCK_SIZE ((1<<20)-200)
|
||||
|
||||
#define RAZ_SPECIFIC(A, N) rasNativeState(A, N)
|
||||
#define UPDATE_SPECIFICS(A) updateYmm0s(dyn, 0, 0); updateNativeFlags(A); propagateFpuBarrier(A)
|
||||
#define PREUPDATE_SPECIFICS(A)
|
||||
#define POSTUPDATE_SPECIFICS(A) updateUneeded(A)
|
||||
#define ARCH_SIZE(A) get_size_arch(A)
|
||||
#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)
|
||||
extern uint32_t arm64_crc(void* p, uint32_t len);
|
||||
extern uint32_t arm64_x31_hash(void* p, uint32_t len);
|
||||
#define ARCH_CRC(A, B) if(cpuext.crc32) return arm64_crc(A, B); else return arm64_x31_hash(A, B)
|
||||
extern void* create_updateflags();
|
||||
#define ARCH_UPDATEFLAGS() create_updateflags()
|
||||
#define ADDITIONNAL_CHECKS() additionnal_checks(dyn, ninst);
|
||||
#define ARCH_CRC_INLINE
|
||||
extern void arm64_next_invalid();
|
||||
|
||||
#define ARCH_NOP 0b11010101000000110010000000011111
|
||||
#define ARCH_UDF 0xcafe
|
||||
#define JMPNEXT_SIZE (4*sizeof(void*))
|
||||
#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);
|
||||
|
||||
#define OTHER_CACHE() \
|
||||
if (fpuCacheNeedsTransform(dyn, ninst)) ret |= 2;
|
||||
|
||||
#include "la64/la64_printer.h"
|
||||
#include "la64/dynarec_la64_private.h"
|
||||
#include "la64/dynarec_la64_functions.h"
|
||||
// Limit here is unconditionnal jump, that is signed 28bits
|
||||
#define MAXBLOCK_SIZE ((1 << 27) - 200)
|
||||
|
||||
#define RAZ_SPECIFIC(A, N)
|
||||
#define UPDATE_SPECIFICS(A) propagateFpuBarrier(A)
|
||||
#define PREUPDATE_SPECIFICS(A) updateNativeFlags(A)
|
||||
#define POSTUPDATE_SPECIFICS(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
|
||||
extern uint32_t la64_crc(void* p, uint32_t len);
|
||||
extern void la64_crc_autocrc(); // same as la64_crc, but not using regular ABI
|
||||
#define ARCH_CRC(A, B) return la64_crc(A, B)
|
||||
|
||||
#define ARCH_NOP (0b0000001101<<22)
|
||||
#define ARCH_UDF 0b1010100
|
||||
|
||||
#define JMPNEXT_SIZE (4*sizeof(void*))
|
||||
#define ADDITIONNAL_CHECKS()
|
||||
#define ARCH_CRC_INLINE
|
||||
extern void la64_next_invalid();
|
||||
|
||||
#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); \
|
||||
int sewNeedsTransform(dynarec_rv64_t* dyn, int ninst);
|
||||
|
||||
#define OTHER_CACHE() \
|
||||
if (fpuCacheNeedsTransform(dyn, ninst)) ret |= 2; \
|
||||
if (sewNeedsTransform(dyn, ninst)) ret |= 4;
|
||||
|
||||
#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 POSTUPDATE_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) {}
|
||||
#define STOP_NATIVE_FLAGS(A, B) {}
|
||||
#define ARCH_UNALIGNED(A, B) arch_unaligned(A, B)
|
||||
|
||||
#define ARCH_NOP 0b0010011
|
||||
#define ARCH_UDF 0xc0001073
|
||||
|
||||
#define JMPNEXT_SIZE (4*sizeof(void*))
|
||||
#define ADDITIONNAL_CHECKS()
|
||||
|
||||
#elif defined(PPC64LE)
|
||||
|
||||
#define instruction_native_t instruction_ppc64le_t
|
||||
#define dynarec_native_t dynarec_ppc64le_t
|
||||
#define extcache_native_t vmxcache_t
|
||||
|
||||
#define ADDITIONNAL_DEFINITION() \
|
||||
int fpuCacheNeedsTransform(dynarec_native_t* dyn, int ninst);
|
||||
|
||||
#define OTHER_CACHE() \
|
||||
if (fpuCacheNeedsTransform(dyn, ninst)) ret |= 2;
|
||||
|
||||
#include "ppc64le/ppc64le_printer.h"
|
||||
#include "ppc64le/dynarec_ppc64le_private.h"
|
||||
#include "ppc64le/dynarec_ppc64le_functions.h"
|
||||
#include "ppc64le/dynarec_ppc64le_arch.h"
|
||||
// Limit here is unconditional branch (I-form), signed 26bits (24-bit field << 2), so ±32MB
|
||||
#define MAXBLOCK_SIZE ((1 << 24) - 200)
|
||||
|
||||
#define RAZ_SPECIFIC(A, N)
|
||||
#define UPDATE_SPECIFICS(A) propagateFpuBarrier(A)
|
||||
#define PREUPDATE_SPECIFICS(A) updateNativeFlags(A)
|
||||
#define POSTUPDATE_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) {}
|
||||
#define ARCH_UNALIGNED(A, B) arch_unaligned(A, B)
|
||||
extern uint32_t ppc64le_fast_hash(void* p, uint32_t len);
|
||||
#define ARCH_CRC(A, B) return ppc64le_fast_hash(A, B)
|
||||
|
||||
#define ARCH_NOP 0x60000000 /* ori 0,0,0 */
|
||||
#define ARCH_UDF 0x00000000 /* illegal instruction (all zeros) */
|
||||
// PPC64LE CreateJmpNext needs 5 instructions (20 bytes) for PC-relative load + branch,
|
||||
// so the jmpnext area needs 5 void* slots (40 bytes) instead of the default 4 (32 bytes).
|
||||
#define JMPNEXT_SIZE (5*sizeof(void*))
|
||||
#define ADDITIONNAL_CHECKS()
|
||||
|
||||
#else
|
||||
#error Unsupported platform
|
||||
#endif
|
||||
|
||||
#include "dynacache_reloc.h"
|
||||
|
||||
#endif //__DYNAREC_ARCH__H_
|
||||
@@ -35,6 +35,7 @@
|
||||
#define STRONGMEM_SIMD_WRITE 2 // The level of SIMD memory writes will be tracked
|
||||
#define STRONGMEM_LAST_WRITE 1 // The level of a barrier before the last guest memory store will be put
|
||||
#define STRONGMEM_SEQ_WRITE 3 // The level of a barrier at every third memory store will be put
|
||||
#define STRONGMEM_QEMU 4 // The level of a mimic to QEMU's strong memory model
|
||||
|
||||
#define STRONGMEM_LEVEL() ((box64_wine && VolatileRangesContains(ip)) ? 0 : BOX64DRENV(dynarec_strongmem))
|
||||
|
||||
@@ -96,23 +97,24 @@
|
||||
#else
|
||||
|
||||
// An opcode writes guest memory, this need to be put after the STORE instruction manually. It will also end the SEQ automaticaly on last_write immediatly
|
||||
#define SMWRITE() \
|
||||
do { \
|
||||
if (dyn->insts[ninst].last_write) { \
|
||||
dyn->smwrite = 1; \
|
||||
SMEND(); \
|
||||
} else { \
|
||||
/* Put a barrier at every third memory write. */ \
|
||||
if (STRONGMEM_LEVEL() >= STRONGMEM_SEQ_WRITE) { \
|
||||
if (++dyn->smwrite >= 3 /* Every third memory write */) { \
|
||||
DMB_ISH(); \
|
||||
dyn->smwrite = 1; \
|
||||
} \
|
||||
} else { \
|
||||
/* Mark that current sequence writes to guest memory. */ \
|
||||
dyn->smwrite = 1; \
|
||||
} \
|
||||
} \
|
||||
#define SMWRITE() \
|
||||
do { \
|
||||
if (dyn->insts[ninst].last_write) { \
|
||||
dyn->smwrite = 1; \
|
||||
SMEND(); \
|
||||
} else { \
|
||||
/* Put a barrier at every third memory write. */ \
|
||||
if (STRONGMEM_LEVEL() >= STRONGMEM_SEQ_WRITE) { \
|
||||
if (++dyn->smwrite >= 3 /* Every third memory write */ \
|
||||
|| STRONGMEM_LEVEL() >= STRONGMEM_QEMU) { \
|
||||
DMB_ISH(); \
|
||||
dyn->smwrite = 1; \
|
||||
} \
|
||||
} else { \
|
||||
/* Mark that current sequence writes to guest memory. */ \
|
||||
dyn->smwrite = 1; \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// Similar to SMWRITE, but checks lock.
|
||||
@@ -133,7 +135,12 @@
|
||||
} while (0)
|
||||
|
||||
// An opcode reads guest memory, this need to be put before the LOAD instruction manually.
|
||||
#define SMREAD()
|
||||
#define SMREAD() \
|
||||
do { \
|
||||
if (STRONGMEM_LEVEL() >= STRONGMEM_QEMU) { \
|
||||
DMB_ISHLD(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// Similar to SMREAD, but checks lock.
|
||||
#define SMREADLOCK(lock) \
|
||||
@@ -200,6 +207,21 @@
|
||||
#define SMDMB() DMB_ISH()
|
||||
#endif
|
||||
|
||||
#ifndef PREFLAGSNEEDED
|
||||
#define PREFLAGSNEEDED()
|
||||
#endif
|
||||
|
||||
#define AREFLAGSNEEDED() \
|
||||
PREFLAGSNEEDED() \
|
||||
if((dyn->insts[ninst].x64.need_before&~X_PEND) && (!ninst || dyn->insts[ninst-1].x64.has_callret)) { \
|
||||
READFLAGS(dyn->insts[ninst].x64.need_before&~X_PEND); \
|
||||
} \
|
||||
ADDITIONNAL_CHECKS()
|
||||
|
||||
// Insert a Secondary Entry Point if it's asked, but only on block that are from file mapped memory (so some binary file)
|
||||
// and that are not flagged as always_test (as this could slow down a bit, and the block is unsafe), unless SEP level 2 is asked
|
||||
#define ISSEP() (BOX64DRENV(dynarec_sep) && ((dyn->is_file_mapped && !dyn->always_test) || BOX64DRENV(dynarec_sep)>1))
|
||||
|
||||
int is_addr_unaligned(uintptr_t addr);
|
||||
int is_addr_autosmc(uintptr_t addr);
|
||||
|
||||
@@ -209,6 +231,8 @@ int is_addr_autosmc(uintptr_t addr);
|
||||
#include "la64/dynarec_la64_helper.h"
|
||||
#elif defined(RV64)
|
||||
#include "rv64/dynarec_rv64_helper.h"
|
||||
#elif defined(PPC64LE)
|
||||
#include "ppc64le/dynarec_ppc64le_helper.h"
|
||||
#else
|
||||
#error Unsupported architecture
|
||||
#endif
|
||||
|
||||
+450
-321
@@ -18,6 +18,7 @@
|
||||
#include "x64trace.h"
|
||||
#include "dynablock.h"
|
||||
#include "dynablock_private.h"
|
||||
#include "alternate.h"
|
||||
|
||||
#include "dynarec_native.h"
|
||||
#include "dynarec_arch.h"
|
||||
@@ -345,11 +346,12 @@ void ClearCache(void* start, size_t len)
|
||||
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*/) {
|
||||
__asm __volatile("dsb ish");
|
||||
if (!ctr_el0_dic) {
|
||||
// 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("dsb ish");
|
||||
}
|
||||
__asm __volatile("isb sy");
|
||||
#else
|
||||
@@ -357,6 +359,14 @@ void ClearCache(void* start, size_t len)
|
||||
#endif
|
||||
}
|
||||
|
||||
NEW_JUMPBUFF(dynarec_jmpbuf);
|
||||
int fillblock_active = 0;
|
||||
|
||||
void cancelFillBlock()
|
||||
{
|
||||
LongJmp(GET_JUMPBUFF(dynarec_jmpbuf), 1);
|
||||
}
|
||||
|
||||
void CancelBlock64(int need_lock)
|
||||
{
|
||||
if(need_lock)
|
||||
@@ -368,6 +378,7 @@ void CancelBlock64(int need_lock)
|
||||
helper->dynablock->actual_block = NULL;
|
||||
}
|
||||
}
|
||||
fillblock_active = 0;
|
||||
current_helper = NULL;
|
||||
redundant_helper = NULL;
|
||||
if(need_lock)
|
||||
@@ -380,7 +391,7 @@ uintptr_t native_pass2(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
uintptr_t native_pass3(dynarec_native_t* dyn, uintptr_t addr, int alternate, int is32bits, int inst_max);
|
||||
|
||||
dynablock_t* CreateEmptyBlock(uintptr_t addr, int is32bits, int is_new) {
|
||||
size_t sz = 4*sizeof(void*) + sizeof(dynablock_t);
|
||||
size_t sz = JMPNEXT_SIZE + sizeof(dynablock_t);
|
||||
void* actual_p = (void*)AllocDynarecMap(addr, sz, is_new);
|
||||
void* p = actual_p + sizeof(void*);
|
||||
if(actual_p==NULL) {
|
||||
@@ -388,10 +399,11 @@ dynablock_t* CreateEmptyBlock(uintptr_t addr, int is32bits, int is_new) {
|
||||
CancelBlock64(0);
|
||||
return NULL;
|
||||
}
|
||||
dynablock_t* block = (dynablock_t*)(actual_p+4*sizeof(void*));
|
||||
dynablock_t* block = (dynablock_t*)(actual_p+JMPNEXT_SIZE);
|
||||
memset(block, 0, sizeof(dynablock_t));
|
||||
// fill the block
|
||||
block->x64_addr = (void*)addr;
|
||||
block->x64_readaddr = addr;
|
||||
block->isize = 0;
|
||||
block->done = 0;
|
||||
block->size = sz;
|
||||
@@ -400,14 +412,14 @@ dynablock_t* CreateEmptyBlock(uintptr_t addr, int is32bits, int is_new) {
|
||||
block->jmpnext = p;
|
||||
block->is32bits = is32bits;
|
||||
*(dynablock_t**)actual_p = block;
|
||||
*(void**)(p+2*sizeof(void*)) = native_epilog;
|
||||
CreateJmpNext(block->jmpnext, p+2*sizeof(void*));
|
||||
*(void**)(p+JMPNEXT_SIZE-2*sizeof(void*)) = native_epilog;
|
||||
CreateJmpNext(block->jmpnext, p+JMPNEXT_SIZE-2*sizeof(void*));
|
||||
// all done...
|
||||
ClearCache(actual_p+sizeof(void*), 3*sizeof(void*)); // need to clear the cache before execution...
|
||||
ClearCache(actual_p+sizeof(void*), JMPNEXT_SIZE-sizeof(void*)); // need to clear the cache before execution...
|
||||
return block;
|
||||
}
|
||||
|
||||
dynablock_t* FillBlock64(uintptr_t addr, int alternate, int is32bits, int inst_max, int is_new) {
|
||||
dynablock_t* FillBlock64(uintptr_t addr, int is32bits, int inst_max, int is_new, int noalt) {
|
||||
/*
|
||||
A Block must have this layout:
|
||||
|
||||
@@ -415,22 +427,39 @@ dynablock_t* FillBlock64(uintptr_t addr, int alternate, int is32bits, int inst_m
|
||||
0x0008..8+4*n : actual Native instructions, (n is the total number)
|
||||
A .. A+8*n : Table64: n 64bits values
|
||||
B .. B+7 : dynablock_t* : self (as part of JmpNext, that simulate another block)
|
||||
B+8 .. B+15 : 2 Native code for jmpnext (or jmp epilog in case of empty block)
|
||||
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)
|
||||
B+8 .. B+8+m : Native code for jmpnext (or jmp epilog in case of empty block), m depends on arch
|
||||
B+J-8.. B+J-1 : jmpnext (or jmp_epilog) address. jumpnext is used when the block needs testing
|
||||
(J = JMPNEXT_SIZE, varies by architecture)
|
||||
B+J .. B+J+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)
|
||||
|
||||
*/
|
||||
const uint32_t req_prot = (box64_pagesize==4096)?(PROT_EXEC|PROT_READ):PROT_READ;
|
||||
uintptr_t old_addr = addr;
|
||||
#ifdef HAVE_ALTJUMP
|
||||
uintptr_t altjump = noalt?0:getAlternateJump((void*)addr, is32bits);
|
||||
if(altjump) {
|
||||
dynarec_log(LOG_INFO, "Building a Dynablock for %p with an alternate content at %p\n", (void*)addr, (void*)altjump);
|
||||
addr = altjump;
|
||||
}
|
||||
#else
|
||||
uintptr_t altjump = 0;
|
||||
#endif
|
||||
if(addr>=BOX64ENV(nodynarec_start) && addr<BOX64ENV(nodynarec_end)) {
|
||||
dynarec_log(LOG_INFO, "Create empty block in no-dynarec zone\n");
|
||||
return BOX64ENV(nodynarec_delay)?NULL:CreateEmptyBlock(addr, is32bits, is_new);
|
||||
return BOX64ENV(nodynarec_delay)?NULL:CreateEmptyBlock(old_addr, is32bits, is_new);
|
||||
}
|
||||
int is_inhotpage = checkInHotPage(addr);
|
||||
if(is_inhotpage && !BOX64ENV(dynarec_dirty)) {
|
||||
dynarec_log(LOG_DEBUG, "Not creating dynablock at %p as in a HotPage\n", (void*)addr);
|
||||
return NULL;
|
||||
}
|
||||
#ifndef _WIN32
|
||||
if((getProtection_fast(addr)&req_prot)!=req_prot) {// cannot be run, get out of the Dynarec
|
||||
dynarec_log(LOG_DEBUG, "Not creating dynablock at %p because EXEC protection is missing\n", (void*)addr);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
if(current_helper) {
|
||||
if(current_helper==redundant_helper) {
|
||||
dynarec_log(LOG_INFO, "%04d|Warning: previous FillBlock did not cleaned up correctly (helper=%p, x64addr=%p, db=%p)\n", GetTID(), current_helper, (void*)((dynarec_native_t*)current_helper)->start, ((dynarec_native_t*)current_helper)->dynablock);
|
||||
@@ -458,330 +487,425 @@ dynablock_t* FillBlock64(uintptr_t addr, int alternate, int is32bits, int inst_m
|
||||
helper.next_cap = MAX_INSTS;
|
||||
helper.table64 = NULL;
|
||||
helper.env = GetCurEnvByAddr(addr);
|
||||
if(getProtection(addr)&PROT_NEVERCLEAN) {
|
||||
helper.always_test = 1;
|
||||
}
|
||||
ResetTable64(&helper);
|
||||
helper.table64cap = 0;
|
||||
helper.end = addr + SizeFileMapped(addr);
|
||||
if(helper.end == helper.start) // that means there is no mmap with a file associated to the memory
|
||||
helper.end = (uintptr_t)~0LL;
|
||||
helper.need_reloc = IsAddrNeedReloc(addr);
|
||||
// pass 0, addresses, x64 jump addresses, overall size of the block
|
||||
uintptr_t end = native_pass0(&helper, addr, alternate, is32bits, inst_max);
|
||||
if(helper.abort) {
|
||||
if(dyn->need_dump || BOX64ENV(dynarec_log))dynarec_log(LOG_NONE, "Abort dynablock on pass0\n");
|
||||
CancelBlock64(0);
|
||||
return NULL;
|
||||
}
|
||||
if(BOX64ENV(dynarec_x87double)==2) {
|
||||
helper.need_x87check = 1;
|
||||
}
|
||||
// basic checks
|
||||
if(!helper.size) {
|
||||
dynarec_log(LOG_INFO, "Warning, null-sized dynarec block (%p)\n", (void*)addr);
|
||||
CancelBlock64(0);
|
||||
return CreateEmptyBlock(addr, is32bits, is_new);
|
||||
}
|
||||
if(!is_inhotpage && !isprotectedDB(addr, 1)) {
|
||||
dynarec_log(LOG_INFO, "Warning, write on current page on pass0, aborting dynablock creation (%p)\n", (void*)addr);
|
||||
CancelBlock64(0);
|
||||
return NULL;
|
||||
}
|
||||
// protect the block of it goes over the 1st page
|
||||
if(!is_inhotpage)
|
||||
if((addr&~(box64_pagesize-1))!=(end&~(box64_pagesize-1))) // need to protect some other pages too
|
||||
protectDB(addr, end-addr); //end is 1byte after actual end
|
||||
// compute hash signature
|
||||
uint32_t hash = X31_hash_code((void*)addr, end-addr);
|
||||
// calculate barriers
|
||||
for(int ii=0; ii<helper.jmp_sz; ++ii) {
|
||||
int i = helper.jmps[ii];
|
||||
uintptr_t j = helper.insts[i].x64.jmp;
|
||||
helper.insts[i].x64.jmp_insts = -1;
|
||||
#ifndef ARCH_NOP
|
||||
if(j<start || j>=end || j==helper.insts[i].x64.addr)
|
||||
#else
|
||||
if(j<start || j>=end)
|
||||
#endif
|
||||
{
|
||||
helper.insts[i].x64.need_after |= X_PEND;
|
||||
if(helper.insts[i].barrier_maybe) {
|
||||
helper.insts[i].x64.barrier|=BARRIER_FLOAT;
|
||||
helper.insts[i].barrier_maybe = 0;
|
||||
}
|
||||
} else {
|
||||
// find jump address instruction
|
||||
int k=-1;
|
||||
int search = ((j>=helper.insts[0].x64.addr) && j<helper.insts[0].x64.addr+helper.isize)?1:0;
|
||||
int imin = 0;
|
||||
int imax = helper.size-1;
|
||||
int i2 = helper.size/2;
|
||||
// dichotomy search
|
||||
while(search) {
|
||||
if(helper.insts[i2].x64.addr == j) {
|
||||
k = i2;
|
||||
search = 0;
|
||||
} else if(helper.insts[i2].x64.addr>j) {
|
||||
imax = i2;
|
||||
i2 = (imax+imin)/2;
|
||||
size_t native_size = 0;
|
||||
size_t insts_rsize = 0;
|
||||
size_t arch_size = 0;
|
||||
size_t callret_size = 0;
|
||||
size_t sep_size = 0;
|
||||
size_t reloc_size = 0;
|
||||
size_t sz = 0;
|
||||
size_t dynablock_align = 0;
|
||||
size_t oldnativesize = 0;
|
||||
size_t oldinstsize = 0;
|
||||
uintptr_t end = 0;
|
||||
void* actual_p = NULL;
|
||||
void* p = NULL;
|
||||
void* next = NULL;
|
||||
void* instsize = NULL;
|
||||
void* tablestart = NULL;
|
||||
void* arch = NULL;
|
||||
void* callrets = NULL;
|
||||
void* seps = NULL;
|
||||
dynablock_t* block = NULL;
|
||||
#define BUILD_INIT 0
|
||||
#define BUILD_PASS0 1
|
||||
#define BUILD_PASS1 2
|
||||
#define BUILD_PASS2 3
|
||||
#define BUILD_PASS3 4
|
||||
#define BUILD_POST 50
|
||||
#define BUILD_DONE 100
|
||||
#define BUILD_ABORT_NULL 200
|
||||
#define BUILD_ABORT_EMPTY 201
|
||||
int state = BUILD_INIT;
|
||||
while(state!=BUILD_DONE) switch(state) {
|
||||
case BUILD_INIT:
|
||||
state = BUILD_PASS0;
|
||||
if (SigSetJmp(GET_JUMPBUFF(dynarec_jmpbuf), 1)) {
|
||||
if(state==BUILD_PASS0 && helper.size>1) {
|
||||
end = helper.insts[helper.size].x64.addr;
|
||||
--helper.size;
|
||||
printf_log(LOG_INFO, "FillBlock at %p triggered a segfault, truncating at %d\n", (void*)addr, helper.size);
|
||||
state = BUILD_PASS1;
|
||||
} else {
|
||||
imin = i2;
|
||||
i2 = (imax+imin)/2;
|
||||
printf_log(LOG_INFO, "FillBlock at %p triggered a segfault (state=%d, size=%d), canceling\n", (void*)addr, state, helper.size);
|
||||
state = BUILD_ABORT_EMPTY;
|
||||
}
|
||||
if(search && (imax-imin)<2) {
|
||||
search = 0;
|
||||
if(helper.insts[imin].x64.addr==j)
|
||||
k = imin;
|
||||
else if(helper.insts[imax].x64.addr==j)
|
||||
k = imax;
|
||||
} else
|
||||
fillblock_active = 1;
|
||||
break;
|
||||
case BUILD_ABORT_NULL:
|
||||
CancelBlock64(0);
|
||||
return NULL;
|
||||
case BUILD_ABORT_EMPTY:
|
||||
CancelBlock64(0);
|
||||
return CreateEmptyBlock(old_addr, is32bits, is_new);
|
||||
case BUILD_PASS0:
|
||||
// pass 0, addresses, x64 jump addresses, overall size of the block
|
||||
end = native_pass0(&helper, addr, altjump?1:0, is32bits, inst_max);
|
||||
if(helper.abort) {
|
||||
if(helper.size<2) {
|
||||
if(dyn->need_dump || BOX64ENV(dynarec_log))dynarec_log(LOG_NONE, "Abort dynablock on pass0\n");
|
||||
state = BUILD_ABORT_EMPTY;
|
||||
continue;
|
||||
}
|
||||
if(dyn->need_dump || BOX64ENV(dynarec_log))dynarec_log(LOG_NONE, "Dynablock shorten on pass0 at ninst=%d\n", helper.size);
|
||||
--helper.size;
|
||||
helper.abort = 0;
|
||||
}
|
||||
// basic checks
|
||||
if(!helper.size) {
|
||||
dynarec_log(LOG_INFO, "Warning, null-sized dynarec block (%p)\n", (void*)addr);
|
||||
state = BUILD_ABORT_EMPTY;
|
||||
continue;
|
||||
}
|
||||
if(!is_inhotpage && !isprotectedDB(addr, 1)) {
|
||||
dynarec_log(LOG_INFO, "Warning, write on current page on pass0, aborting dynablock creation (%p)\n", (void*)addr);
|
||||
state = BUILD_ABORT_NULL;
|
||||
continue;
|
||||
}
|
||||
state = BUILD_PASS1;
|
||||
//fallthru
|
||||
case BUILD_PASS1:
|
||||
if(BOX64ENV(dynarec_x87double)==2) {
|
||||
helper.need_x87check = 1;
|
||||
}
|
||||
// protect the block of it goes over the 1st page
|
||||
if(!is_inhotpage)
|
||||
if((addr&~(box64_pagesize-1))!=(end&~(box64_pagesize-1))) // need to protect some other pages too
|
||||
protectDB(addr, end-addr); //end is 1byte after actual end
|
||||
// compute hash signature
|
||||
uint32_t hash = X31_hash_code((void*)addr, end-addr);
|
||||
// calculate barriers
|
||||
for(int ii=0; ii<helper.jmp_sz; ++ii) {
|
||||
int i = helper.jmps[ii];
|
||||
uintptr_t j = helper.insts[i].x64.jmp;
|
||||
helper.insts[i].x64.jmp_insts = -1;
|
||||
#ifndef ARCH_NOP
|
||||
if(j<start || j>=end || j==helper.insts[i].x64.addr)
|
||||
#else
|
||||
if(j<start || j>=end)
|
||||
#endif
|
||||
{
|
||||
helper.insts[i].x64.need_after |= X_PEND;
|
||||
if(helper.insts[i].barrier_maybe) {
|
||||
helper.insts[i].x64.barrier|=BARRIER_FLOAT;
|
||||
helper.insts[i].barrier_maybe = 0;
|
||||
}
|
||||
} else {
|
||||
// find jump address instruction
|
||||
int k=-1;
|
||||
int search = ((j>=helper.insts[0].x64.addr) && j<helper.insts[0].x64.addr+helper.isize)?1:0;
|
||||
int imin = 0;
|
||||
int imax = helper.size-1;
|
||||
int i2 = helper.size/2;
|
||||
// dichotomy search
|
||||
while(search) {
|
||||
if(helper.insts[i2].x64.addr == j) {
|
||||
k = i2;
|
||||
search = 0;
|
||||
} else if(helper.insts[i2].x64.addr>j) {
|
||||
imax = i2;
|
||||
i2 = (imax+imin)/2;
|
||||
} else {
|
||||
imin = i2;
|
||||
i2 = (imax+imin)/2;
|
||||
}
|
||||
if(search && (imax-imin)<2) {
|
||||
search = 0;
|
||||
if(helper.insts[imin].x64.addr==j)
|
||||
k = imin;
|
||||
else if(helper.insts[imax].x64.addr==j)
|
||||
k = imax;
|
||||
}
|
||||
}
|
||||
/*for(int i2=0; i2<helper.size && k==-1; ++i2) {
|
||||
if(helper.insts[i2].x64.addr==j)
|
||||
k=i2;
|
||||
}*/
|
||||
if(k!=-1) {
|
||||
// special case, loop on itself with some nop in between
|
||||
if(k<i && !helper.insts[i].x64.has_next && is_nops(&helper, helper.insts[k].x64.addr, helper.insts[i].x64.addr-helper.insts[k].x64.addr)) {
|
||||
#ifndef ARCH_NOP
|
||||
helper.always_test = 1;
|
||||
k = -1;
|
||||
#else
|
||||
helper.insts[k].x64.self_loop = 1;
|
||||
#endif
|
||||
}
|
||||
helper.insts[i].x64.jmp_insts = k;
|
||||
helper.insts[i].barrier_maybe = 0;
|
||||
} else {
|
||||
helper.insts[i].x64.need_after |= X_PEND;
|
||||
if(helper.insts[i].barrier_maybe) {
|
||||
helper.insts[i].x64.barrier|=BARRIER_FLOAT;
|
||||
helper.insts[i].barrier_maybe = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*for(int i2=0; i2<helper.size && k==-1; ++i2) {
|
||||
if(helper.insts[i2].x64.addr==j)
|
||||
k=i2;
|
||||
}*/
|
||||
if(k!=-1) {
|
||||
// special case, loop on itself with some nop in between
|
||||
if(k<i && !helper.insts[i].x64.has_next && is_nops(&helper, helper.insts[k].x64.addr, helper.insts[i].x64.addr-helper.insts[k].x64.addr)) {
|
||||
// fill predecessors with the jump address
|
||||
sizePredecessors(&helper);
|
||||
helper.predecessor = static_preds;
|
||||
fillPredecessors(&helper);
|
||||
|
||||
PREUPDATE_SPECIFICS(&helper);
|
||||
|
||||
int pos = helper.size-1;
|
||||
while (pos>=0)
|
||||
pos = updateNeed(&helper, pos, 0);
|
||||
// remove fpu stuff on non-executed code
|
||||
for(int i=1; i<helper.size-1; ++i)
|
||||
if(!helper.insts[i].pred_sz) {
|
||||
int ii = i;
|
||||
while(ii<helper.size && !helper.insts[ii].pred_sz) {
|
||||
fpu_reset_ninst(&helper, ii);
|
||||
RAZ_SPECIFIC(&helper, ii);
|
||||
++ii;
|
||||
}
|
||||
i = ii;
|
||||
}
|
||||
// remove trailling dead code
|
||||
while(helper.size && !helper.insts[helper.size-1].x64.alive) {
|
||||
helper.isize-=helper.insts[helper.size-1].x64.size;
|
||||
--helper.size;
|
||||
}
|
||||
if(!helper.size) {
|
||||
// NULL block after removing dead code, how is that possible?
|
||||
dynarec_log(LOG_INFO, "Warning, null-sized dynarec block after trimming dead code (%p)\n", (void*)addr);
|
||||
CancelBlock64(0);
|
||||
return CreateEmptyBlock(old_addr, is32bits, is_new);
|
||||
}
|
||||
UPDATE_SPECIFICS(&helper);
|
||||
// check for still valid close loop
|
||||
for(int ii=0; ii<helper.jmp_sz && !helper.always_test; ++ii) {
|
||||
int i = helper.jmps[ii];
|
||||
if(helper.insts[i].x64.alive && (helper.insts[i].x64.jmp==helper.insts[i].x64.addr)) {
|
||||
#ifndef ARCH_NOP
|
||||
helper.always_test = 1;
|
||||
k = -1;
|
||||
#else
|
||||
helper.insts[k].x64.self_loop = 1;
|
||||
helper.insts[i].x64.self_loop = 1;
|
||||
#endif
|
||||
}
|
||||
helper.insts[i].x64.jmp_insts = k;
|
||||
helper.insts[i].barrier_maybe = 0;
|
||||
} else {
|
||||
helper.insts[i].x64.need_after |= X_PEND;
|
||||
if(helper.insts[i].barrier_maybe) {
|
||||
helper.insts[i].x64.barrier|=BARRIER_FLOAT;
|
||||
helper.insts[i].barrier_maybe = 0;
|
||||
}
|
||||
// no need for next anymore
|
||||
helper.next_sz = helper.next_cap = 0;
|
||||
helper.next = NULL;
|
||||
ResetTable64(&helper);
|
||||
helper.reloc_size = 0;
|
||||
// pass 1, float optimizations, first pass for flags
|
||||
native_pass1(&helper, addr, altjump?1:0, is32bits, inst_max);
|
||||
if(helper.abort) {
|
||||
if(dyn->need_dump || BOX64ENV(dynarec_log))dynarec_log(LOG_NONE, "Abort dynablock on pass1\n");
|
||||
state = BUILD_ABORT_NULL;
|
||||
continue;
|
||||
}
|
||||
state = BUILD_PASS2;
|
||||
//fallthrough
|
||||
case BUILD_PASS2:
|
||||
if(BOX64ENV(dynarec_x87double)==2) {
|
||||
if(helper.need_x87check==1)
|
||||
helper.need_x87check = 0;
|
||||
}
|
||||
POSTUPDATE_SPECIFICS(&helper);
|
||||
ResetTable64(&helper);
|
||||
helper.reloc_size = 0;
|
||||
// pass 2, instruction size
|
||||
helper.callrets = static_callrets;
|
||||
native_pass2(&helper, addr, altjump?1:0, is32bits, inst_max);
|
||||
if(helper.abort) {
|
||||
if(dyn->need_dump || BOX64ENV(dynarec_log))dynarec_log(LOG_NONE, "Abort dynablock on pass2\n");
|
||||
state = BUILD_ABORT_NULL;
|
||||
continue;
|
||||
}
|
||||
state = BUILD_PASS3;
|
||||
//fallthrough
|
||||
case BUILD_PASS3:
|
||||
// keep size of instructions for signal handling
|
||||
native_size = (helper.native_size+7)&~7; // round the size...
|
||||
// check if size is overlimit
|
||||
if((inst_max==MAX_INSTS) && (native_size>MAXBLOCK_SIZE)) {
|
||||
int imax = 0;
|
||||
size_t max_size = 0;
|
||||
while((max_size<MAXBLOCK_SIZE) && (imax<helper.size)) {
|
||||
max_size += helper.insts[imax].size;
|
||||
++imax;
|
||||
}
|
||||
if(!imax) return NULL; //that should never happens
|
||||
--imax;
|
||||
if(dyn->need_dump || BOX64ENV(dynarec_log))dynarec_log(LOG_NONE, "Dynablock oversized, with %zu (max=%zd), recomputing cutting at %d from %d\n", native_size, MAXBLOCK_SIZE, imax, helper.size);
|
||||
CancelBlock64(0);
|
||||
return FillBlock64(old_addr, is32bits, imax, is_new, noalt);
|
||||
}
|
||||
}
|
||||
}
|
||||
// fill predecessors with the jump address
|
||||
sizePredecessors(&helper);
|
||||
helper.predecessor = static_preds;
|
||||
fillPredecessors(&helper);
|
||||
|
||||
PREUPDATE_SPECIFICS(&helper);
|
||||
|
||||
int pos = helper.size-1;
|
||||
while (pos>=0)
|
||||
pos = updateNeed(&helper, pos, 0);
|
||||
// remove fpu stuff on non-executed code
|
||||
for(int i=1; i<helper.size-1; ++i)
|
||||
if(!helper.insts[i].pred_sz) {
|
||||
int ii = i;
|
||||
while(ii<helper.size && !helper.insts[ii].pred_sz) {
|
||||
fpu_reset_ninst(&helper, ii);
|
||||
RAZ_SPECIFIC(&helper, ii);
|
||||
++ii;
|
||||
insts_rsize = (helper.insts_size+2)*sizeof(instsize_t);
|
||||
insts_rsize = (insts_rsize+7)&~7; // round the size...
|
||||
arch_size = ARCH_SIZE(&helper);
|
||||
callret_size = helper.callret_size*sizeof(callret_t);
|
||||
sep_size = helper.sep_size*sizeof(sep_t);
|
||||
reloc_size = helper.reloc_size*sizeof(uint32_t);
|
||||
// ok, now allocate mapped memory, with executable flag on
|
||||
sz = sizeof(void*) + native_size + helper.table64size*sizeof(uint64_t) + JMPNEXT_SIZE + insts_rsize + arch_size + callret_size + sep_size;
|
||||
dynablock_align = (sz&7)?(8 -(sz&7)):0; // align dynablock
|
||||
sz += dynablock_align + sizeof(dynablock_t) + reloc_size;
|
||||
// dynablock_t* block (arm insts) table64 jmpnext code instsize arch callrets sep dynablock relocs
|
||||
actual_p = (void*)AllocDynarecMap(old_addr, sz, is_new);
|
||||
if(actual_p==NULL) {
|
||||
dynarec_log(LOG_INFO, "AllocDynarecMap(%p, %zu) failed, canceling block\n", (void*)addr, sz);
|
||||
state = BUILD_ABORT_NULL;
|
||||
continue;
|
||||
}
|
||||
i = ii;
|
||||
}
|
||||
// remove trailling dead code
|
||||
while(helper.size && !helper.insts[helper.size-1].x64.alive) {
|
||||
helper.isize-=helper.insts[helper.size-1].x64.size;
|
||||
--helper.size;
|
||||
}
|
||||
if(!helper.size) {
|
||||
// NULL block after removing dead code, how is that possible?
|
||||
dynarec_log(LOG_INFO, "Warning, null-sized dynarec block after trimming dead code (%p)\n", (void*)addr);
|
||||
CancelBlock64(0);
|
||||
return CreateEmptyBlock(addr, is32bits, is_new);
|
||||
}
|
||||
UPDATE_SPECIFICS(&helper);
|
||||
// check for still valid close loop
|
||||
for(int ii=0; ii<helper.jmp_sz && !helper.always_test; ++ii) {
|
||||
int i = helper.jmps[ii];
|
||||
if(helper.insts[i].x64.alive && (helper.insts[i].x64.jmp==helper.insts[i].x64.addr)) {
|
||||
#ifndef ARCH_NOP
|
||||
helper.always_test = 1;
|
||||
p = (void*)(((uintptr_t)actual_p) + sizeof(void*));
|
||||
tablestart = p + native_size;
|
||||
next = tablestart + helper.table64size*sizeof(uint64_t);
|
||||
instsize = next + JMPNEXT_SIZE;
|
||||
arch = instsize + insts_rsize;
|
||||
callrets = arch + arch_size;
|
||||
seps = callrets + callret_size;
|
||||
helper.block = p;
|
||||
block = (dynablock_t*)(seps+sep_size+dynablock_align);
|
||||
memset(block, 0, sizeof(dynablock_t));
|
||||
void* relocs = helper.need_reloc?(block+1):NULL;
|
||||
// fill the block
|
||||
block->x64_addr = (void*)addr;
|
||||
block->x64_readaddr = addr;
|
||||
block->isize = 0;
|
||||
block->actual_block = actual_p;
|
||||
helper.relocs = relocs;
|
||||
block->relocs = relocs;
|
||||
block->table64size = helper.table64size;
|
||||
helper.native_start = (uintptr_t)p;
|
||||
helper.tablestart = (uintptr_t)tablestart;
|
||||
helper.jmp_next = (uintptr_t)next+sizeof(void*);
|
||||
helper.instsize = (instsize_t*)instsize;
|
||||
*(dynablock_t**)actual_p = block;
|
||||
helper.table64cap = helper.table64size;
|
||||
helper.table64 = (uint64_t*)helper.tablestart;
|
||||
helper.callrets = (callret_t*)callrets;
|
||||
helper.sep = (sep_t*)seps;
|
||||
block->prefixsize = helper.prefixsize;
|
||||
block->table64 = helper.table64;
|
||||
helper.dynablock = block;
|
||||
if(callret_size)
|
||||
memcpy(helper.callrets, static_callrets, helper.callret_size*sizeof(callret_t));
|
||||
helper.callret_size = 0;
|
||||
helper.sep_size = 0;
|
||||
// pass 3, emit (log emit native opcode)
|
||||
if(dyn->need_dump) {
|
||||
dynarec_log(LOG_NONE, "%s%04d|Emitting %zu bytes for %u %s bytes (native=%zu, table64=%zu, instsize=%zu, arch=%zu, callrets=%zu, entry=%p)", (dyn->need_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, callret_size, helper.block);
|
||||
PrintFunctionAddr(helper.start, " => ");
|
||||
dynarec_log_prefix(0, LOG_NONE, "%s\n", (dyn->need_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;
|
||||
oldnativesize = helper.native_size;
|
||||
oldinstsize = helper.insts_size;
|
||||
int oldsize= helper.size;
|
||||
helper.native_size = 0;
|
||||
ResetTable64(&helper); // reset table64 (but not the cap)
|
||||
helper.insts_size = 0; // reset
|
||||
helper.reloc_size = 0;
|
||||
native_pass3(&helper, addr, altjump?1:0, is32bits, inst_max);
|
||||
if(helper.abort) {
|
||||
if(dyn->need_dump || BOX64ENV(dynarec_log))dynarec_log(LOG_NONE, "Abort dynablock on pass3\n");
|
||||
state = BUILD_ABORT_NULL;
|
||||
continue;
|
||||
}
|
||||
state = BUILD_POST;
|
||||
//fallthrough
|
||||
case BUILD_POST:
|
||||
// no need for jmps anymore
|
||||
helper.jmp_sz = helper.jmp_cap = 0;
|
||||
helper.jmps = NULL;
|
||||
// keep size of instructions for signal handling
|
||||
block->instsize = instsize;
|
||||
helper.table64 = NULL;
|
||||
helper.instsize = NULL;
|
||||
helper.predecessor = NULL;
|
||||
block->size = sz;
|
||||
block->isize = helper.size;
|
||||
block->block = p;
|
||||
block->jmpnext = next+sizeof(void*);
|
||||
#ifdef ARCH_CRC_INLINE
|
||||
block->always_test = 0;
|
||||
block->autocrc = helper.always_test?1:0;
|
||||
#else
|
||||
helper.insts[i].x64.self_loop = 1;
|
||||
block->always_test = helper.always_test;
|
||||
block->autocrc = 0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
// no need for next anymore
|
||||
helper.next_sz = helper.next_cap = 0;
|
||||
helper.next = NULL;
|
||||
ResetTable64(&helper);
|
||||
helper.reloc_size = 0;
|
||||
// pass 1, float optimizations, first pass for flags
|
||||
native_pass1(&helper, addr, alternate, is32bits, inst_max);
|
||||
if(helper.abort) {
|
||||
if(dyn->need_dump || BOX64ENV(dynarec_log))dynarec_log(LOG_NONE, "Abort dynablock on pass1\n");
|
||||
CancelBlock64(0);
|
||||
return NULL;
|
||||
}
|
||||
if(BOX64ENV(dynarec_x87double)==2) {
|
||||
if(helper.need_x87check==1)
|
||||
helper.need_x87check = 0;
|
||||
}
|
||||
POSTUPDATE_SPECIFICS(&helper);
|
||||
ResetTable64(&helper);
|
||||
helper.reloc_size = 0;
|
||||
// pass 2, instruction size
|
||||
helper.callrets = static_callrets;
|
||||
native_pass2(&helper, addr, alternate, is32bits, inst_max);
|
||||
if(helper.abort) {
|
||||
if(dyn->need_dump || BOX64ENV(dynarec_log))dynarec_log(LOG_NONE, "Abort dynablock on pass2\n");
|
||||
CancelBlock64(0);
|
||||
return NULL;
|
||||
}
|
||||
// keep size of instructions for signal handling
|
||||
size_t native_size = (helper.native_size+7)&~7; // round the size...
|
||||
// check if size is overlimit
|
||||
if((inst_max==MAX_INSTS) && (native_size>MAXBLOCK_SIZE)) {
|
||||
int imax = 0;
|
||||
size_t max_size = 0;
|
||||
while((max_size<MAXBLOCK_SIZE) && (imax<helper.size)) {
|
||||
max_size += helper.insts[imax].size;
|
||||
++imax;
|
||||
}
|
||||
if(!imax) return NULL; //that should never happens
|
||||
--imax;
|
||||
if(dyn->need_dump || BOX64ENV(dynarec_log))dynarec_log(LOG_NONE, "Dynablock oversized, with %zu (max=%zd), recomputing cutting at %d from %d\n", native_size, MAXBLOCK_SIZE, imax, helper.size);
|
||||
CancelBlock64(0);
|
||||
return FillBlock64(addr, alternate, is32bits, imax, is_new);
|
||||
}
|
||||
size_t insts_rsize = (helper.insts_size+2)*sizeof(instsize_t);
|
||||
insts_rsize = (insts_rsize+7)&~7; // round the size...
|
||||
size_t arch_size = ARCH_SIZE(&helper);
|
||||
size_t callret_size = helper.callret_size*sizeof(callret_t);
|
||||
size_t reloc_size = helper.reloc_size*sizeof(uint32_t);
|
||||
// ok, now allocate mapped memory, with executable flag on
|
||||
size_t sz = sizeof(void*) + native_size + helper.table64size*sizeof(uint64_t) + 4*sizeof(void*) + insts_rsize + arch_size + callret_size;
|
||||
size_t dynablock_align = (sz&7)?(8 -(sz&7)):0; // align dynablock
|
||||
sz += dynablock_align + sizeof(dynablock_t) + reloc_size;
|
||||
// dynablock_t* block (arm insts) table64 jmpnext code instsize arch callrets dynablock relocs
|
||||
void* actual_p = (void*)AllocDynarecMap(addr, sz, is_new);
|
||||
if(actual_p==NULL) {
|
||||
dynarec_log(LOG_INFO, "AllocDynarecMap(%p, %zu) failed, canceling block\n", (void*)addr, sz);
|
||||
CancelBlock64(0);
|
||||
return NULL;
|
||||
}
|
||||
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;
|
||||
void* callrets = arch + arch_size;
|
||||
helper.block = p;
|
||||
dynablock_t* block = (dynablock_t*)(callrets+callret_size+dynablock_align);
|
||||
memset(block, 0, sizeof(dynablock_t));
|
||||
void* relocs = helper.need_reloc?(block+1):NULL;
|
||||
// fill the block
|
||||
block->x64_addr = (void*)addr;
|
||||
block->isize = 0;
|
||||
block->actual_block = actual_p;
|
||||
helper.relocs = relocs;
|
||||
block->relocs = relocs;
|
||||
block->table64size = helper.table64size;
|
||||
helper.native_start = (uintptr_t)p;
|
||||
helper.tablestart = (uintptr_t)tablestart;
|
||||
helper.jmp_next = (uintptr_t)next+sizeof(void*);
|
||||
helper.instsize = (instsize_t*)instsize;
|
||||
*(dynablock_t**)actual_p = block;
|
||||
helper.table64cap = helper.table64size;
|
||||
helper.table64 = (uint64_t*)helper.tablestart;
|
||||
helper.callrets = (callret_t*)callrets;
|
||||
block->prefixsize = helper.prefixsize;
|
||||
block->table64 = helper.table64;
|
||||
if(callret_size)
|
||||
memcpy(helper.callrets, static_callrets, helper.callret_size*sizeof(callret_t));
|
||||
helper.callret_size = 0;
|
||||
// pass 3, emit (log emit native opcode)
|
||||
if(dyn->need_dump) {
|
||||
dynarec_log(LOG_NONE, "%s%04d|Emitting %zu bytes for %u %s bytes (native=%zu, table64=%zu, instsize=%zu, arch=%zu, callrets=%zu, entry=%p)", (dyn->need_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, callret_size, helper.block);
|
||||
PrintFunctionAddr(helper.start, " => ");
|
||||
dynarec_log_prefix(0, LOG_NONE, "%s\n", (dyn->need_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;
|
||||
size_t oldinstsize = helper.insts_size;
|
||||
int oldsize= helper.size;
|
||||
helper.native_size = 0;
|
||||
ResetTable64(&helper); // reset table64 (but not the cap)
|
||||
helper.insts_size = 0; // reset
|
||||
helper.reloc_size = 0;
|
||||
native_pass3(&helper, addr, alternate, is32bits, inst_max);
|
||||
if(helper.abort) {
|
||||
if(dyn->need_dump || BOX64ENV(dynarec_log))dynarec_log(LOG_NONE, "Abort dynablock on pass3\n");
|
||||
CancelBlock64(0);
|
||||
return NULL;
|
||||
}
|
||||
// no need for jmps anymore
|
||||
helper.jmp_sz = helper.jmp_cap = 0;
|
||||
helper.jmps = NULL;
|
||||
// keep size of instructions for signal handling
|
||||
block->instsize = instsize;
|
||||
helper.table64 = NULL;
|
||||
helper.instsize = NULL;
|
||||
helper.predecessor = NULL;
|
||||
block->size = sz;
|
||||
block->isize = helper.size;
|
||||
block->block = p;
|
||||
block->jmpnext = next+sizeof(void*);
|
||||
block->always_test = helper.always_test;
|
||||
block->dirty = block->always_test;
|
||||
block->is32bits = is32bits;
|
||||
block->relocsize = helper.reloc_size*sizeof(uint32_t);
|
||||
if(arch_size) {
|
||||
block->arch_size = arch_size;
|
||||
block->arch = ARCH_FILL(&helper, arch, arch_size);
|
||||
if(!block->arch) block->arch_size = 0;
|
||||
} else {
|
||||
block->arch = NULL;
|
||||
block->arch_size = arch_size;
|
||||
}
|
||||
block->callret_size = helper.callret_size;
|
||||
block->callrets = helper.callrets;
|
||||
block->native_size = native_size;
|
||||
*(dynablock_t**)next = block;
|
||||
*(void**)(next+3*sizeof(void*)) = native_next;
|
||||
CreateJmpNext(block->jmpnext, next+3*sizeof(void*));
|
||||
ClearCache(block->jmpnext, 4*sizeof(void*));
|
||||
//block->x64_addr = (void*)start;
|
||||
block->x64_size = end-start;
|
||||
// all done...
|
||||
if (BOX64ENV(dynarec_gdbjit) && (!BOX64ENV(dynarec_gdbjit_end) || (addr >= BOX64ENV(dynarec_gdbjit_start) && addr < BOX64ENV(dynarec_gdbjit_end)))) {
|
||||
if (BOX64ENV(dynarec_gdbjit) != 3) GdbJITBlockReady(helper.gdbjit_block);
|
||||
GdbJITBlockCleanup(helper.gdbjit_block);
|
||||
#ifdef GDBJIT
|
||||
block->gdbjit_block = helper.gdbjit_block;
|
||||
#endif
|
||||
}
|
||||
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))) {
|
||||
dynarec_log(LOG_DEBUG, "Warning, a block changed while being processed hash(%p:%ld)=%x/%x\n", block->x64_addr, block->x64_size, block->hash, hash);
|
||||
CancelBlock64(0);
|
||||
return NULL;
|
||||
}
|
||||
if((oldnativesize!=helper.native_size) || (oldtable64size<helper.table64size)) {
|
||||
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_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_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");
|
||||
CancelBlock64(0);
|
||||
return NULL;
|
||||
block->dirty = block->always_test;
|
||||
block->is32bits = is32bits;
|
||||
block->relocsize = helper.reloc_size*sizeof(uint32_t);
|
||||
if(arch_size) {
|
||||
block->arch_size = arch_size;
|
||||
block->arch = ARCH_FILL(&helper, arch, arch_size);
|
||||
if(!block->arch) block->arch_size = 0;
|
||||
} else {
|
||||
block->arch = NULL;
|
||||
block->arch_size = arch_size;
|
||||
}
|
||||
block->callret_size = helper.callret_size;
|
||||
block->callrets = helper.callrets;
|
||||
block->sep_size = helper.sep_size;
|
||||
block->sep = helper.sep;
|
||||
block->native_size = native_size;
|
||||
*(dynablock_t**)next = block;
|
||||
for(int i=0; i<helper.sep_size; ++i) {
|
||||
// setup the dynablock reference for secondary entry points
|
||||
void* p = (block->block + helper.sep[i].nat_offs - sizeof(void*));
|
||||
*(dynablock_t**)p = block;
|
||||
}
|
||||
*(void**)(next+JMPNEXT_SIZE-sizeof(void*)) = native_next;
|
||||
CreateJmpNext(block->jmpnext, next+JMPNEXT_SIZE-sizeof(void*));
|
||||
ClearCache(block->jmpnext, JMPNEXT_SIZE-sizeof(void*));
|
||||
//block->x64_addr = (void*)start;
|
||||
block->x64_size = end-start;
|
||||
// all done...
|
||||
if (BOX64ENV(dynarec_gdbjit) && (!BOX64ENV(dynarec_gdbjit_end) || (addr >= BOX64ENV(dynarec_gdbjit_start) && addr < BOX64ENV(dynarec_gdbjit_end)))) {
|
||||
if (BOX64ENV(dynarec_gdbjit) != 3) GdbJITBlockReady(helper.gdbjit_block);
|
||||
GdbJITBlockCleanup(helper.gdbjit_block);
|
||||
#ifdef GDBJIT
|
||||
block->gdbjit_block = helper.gdbjit_block;
|
||||
#endif
|
||||
}
|
||||
ClearCache(actual_p+sizeof(void*), native_size); // need to clear the cache before execution...
|
||||
block->hash = X31_hash_code((void*)block->x64_readaddr, block->x64_size);
|
||||
// Check if something changed, to abort if it is
|
||||
if((helper.abort || (block->hash != hash))) {
|
||||
dynarec_log(LOG_DEBUG, "Warning, a block changed while being processed hash(%p:%ld)=%x/%x\n", block->x64_readaddr, block->x64_size, block->hash, hash);
|
||||
state = BUILD_ABORT_NULL;
|
||||
continue;
|
||||
}
|
||||
if((oldnativesize!=helper.native_size) || (oldtable64size<helper.table64size)) {
|
||||
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_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_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");
|
||||
state = BUILD_ABORT_NULL;
|
||||
continue;
|
||||
}
|
||||
state = BUILD_DONE;
|
||||
}
|
||||
fillblock_active = 0; // disable the use of the LongJump if Segfault/Sigbus
|
||||
// ok, free the helper now
|
||||
ResetTable64(&helper);
|
||||
//dynaFree(helper.insts);
|
||||
@@ -794,20 +918,25 @@ dynablock_t* FillBlock64(uintptr_t addr, int alternate, int is32bits, int inst_m
|
||||
block->dirty = 1;
|
||||
//protectDB(addr, end-addr);
|
||||
}
|
||||
if(getProtection(addr)&PROT_NEVERCLEAN) {
|
||||
block->always_test = 1;
|
||||
}
|
||||
else if(is_inhotpage)
|
||||
#ifdef ARCH_CRC_INLINE
|
||||
if(is_inhotpage && !block->autocrc)
|
||||
block->always_test = 2;
|
||||
#else
|
||||
if(is_inhotpage)
|
||||
block->always_test = 2;
|
||||
#endif
|
||||
if(block->always_test) {
|
||||
dynarec_log(LOG_INFO, "Note: block marked as always dirty %p:%ld\n", block->x64_addr, block->x64_size);
|
||||
#ifdef ARCH_NOP
|
||||
// mark callrets to trigger SIGILL to check clean state
|
||||
if(block->callret_size)
|
||||
if(block->callret_size) {
|
||||
for(int i=0; i<block->callret_size; ++i)
|
||||
*(uint32_t*)(block->block+block->callrets[i].offs) = ARCH_UDF;
|
||||
ClearCache(block->block, block->size);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if(altjump) block->x64_addr = (void*)old_addr; // set the not-alt addr if a shadow jump was used
|
||||
redundant_helper = current_helper = NULL;
|
||||
//block->done = 1;
|
||||
return block;
|
||||
|
||||
@@ -80,12 +80,32 @@ void native_fxtract(x64emu_t* emu)
|
||||
}
|
||||
void native_fprem(x64emu_t* emu)
|
||||
{
|
||||
int64_t ll = (int64_t)trunc(ST0.d / ST1.d);
|
||||
ST0.d = ST0.d - (ST1.d * ll);
|
||||
double x = ST0.d, y = ST1.d;
|
||||
int64_t q = 0;
|
||||
if (isnan(x) || isnan(y)) {
|
||||
ST0.d = NAN;
|
||||
q = 0;
|
||||
} else if (isinf(x) || y == 0.0) {
|
||||
#if !defined(_WIN32) && !defined(__MINGW32__)
|
||||
feraiseexcept(FE_INVALID);
|
||||
#endif
|
||||
ST0.d = NAN;
|
||||
q = 0;
|
||||
} else {
|
||||
#if defined(_WIN32) || defined(__MINGW32__)
|
||||
q = (int64_t)trunc(x / y);
|
||||
ST0.d = x - (y * q);
|
||||
#else
|
||||
ST0.d = fmod(x, y);
|
||||
q = (int64_t)trunc(x / y);
|
||||
#endif
|
||||
}
|
||||
q &= 7;
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
emu->sw.f.F87_C1 = (ll & 1) ? 1 : 0;
|
||||
emu->sw.f.F87_C3 = (ll & 2) ? 1 : 0;
|
||||
emu->sw.f.F87_C0 = (ll & 4) ? 1 : 0;
|
||||
emu->sw.f.F87_C1 = q & 1;
|
||||
emu->sw.f.F87_C3 = (q >> 1) & 1;
|
||||
emu->sw.f.F87_C0 = (q >> 2) & 1;
|
||||
|
||||
}
|
||||
void native_fyl2xp1(x64emu_t* emu)
|
||||
{
|
||||
@@ -315,13 +335,28 @@ void native_frstor16(x64emu_t* emu, uint8_t* ed)
|
||||
|
||||
void native_fprem1(x64emu_t* emu)
|
||||
{
|
||||
int e0, e1;
|
||||
int64_t ll = (int64_t)round(ST0.d / ST1.d);
|
||||
ST0.d = ST0.d - (ST1.d * ll);
|
||||
double x = ST0.d, y = ST1.d;
|
||||
int q = 0;
|
||||
if (isnan(x) || isnan(y)) {
|
||||
ST0.d = NAN;
|
||||
} else if (isinf(x) || y == 0.0) {
|
||||
#if !defined(_WIN32) && !defined(__MINGW32__)
|
||||
feraiseexcept(FE_INVALID);
|
||||
#endif
|
||||
ST0.d = NAN;
|
||||
} else {
|
||||
#if defined(_WIN32) || defined(__MINGW32__)
|
||||
q = (int)round(x / y);
|
||||
ST0.d = x - (y * q);
|
||||
#else
|
||||
ST0.d = remquo(x, y, &q);
|
||||
#endif
|
||||
}
|
||||
q &= 7;
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
emu->sw.f.F87_C1 = (ll & 1) ? 1 : 0;
|
||||
emu->sw.f.F87_C3 = (ll & 2) ? 1 : 0;
|
||||
emu->sw.f.F87_C0 = (ll & 4) ? 1 : 0;
|
||||
emu->sw.f.F87_C1 = q & 1;
|
||||
emu->sw.f.F87_C3 = (q >> 1) & 1;
|
||||
emu->sw.f.F87_C0 = (q >> 2) & 1;
|
||||
}
|
||||
|
||||
const uint8_t ff_mult2[4][256] = {
|
||||
@@ -720,7 +755,7 @@ static int flagsCacheNeedsTransform(dynarec_native_t* dyn, int ninst) {
|
||||
int jmp = dyn->insts[ninst].x64.jmp_insts;
|
||||
if(jmp<0)
|
||||
return 0;
|
||||
#ifdef ARM64
|
||||
#if defined(ARM64) || defined(LA64) || defined(PPC64LE)
|
||||
// df_none is now a defered information
|
||||
if(dyn->insts[ninst].f_exit==dyn->insts[jmp].f_entry)
|
||||
return 0;
|
||||
@@ -738,7 +773,7 @@ static int flagsCacheNeedsTransform(dynarec_native_t* dyn, int ninst) {
|
||||
case status_none_pending:
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
#else
|
||||
if(dyn->insts[ninst].f_exit.dfnone) // flags are fully known, nothing we can do more
|
||||
return 0;
|
||||
if(dyn->insts[jmp].f_entry.dfnone && !dyn->insts[ninst].f_exit.dfnone && !dyn->insts[jmp].df_notneeded)
|
||||
@@ -821,22 +856,60 @@ uint8_t geted_ib(dynarec_native_t* dyn, uintptr_t addr, int ninst, uint8_t nexto
|
||||
}
|
||||
#undef F8
|
||||
|
||||
void propagate_nodf(dynarec_native_t* dyn, int ninst)
|
||||
#if defined(ARM64) || defined(LA64) || defined(PPC64LE)
|
||||
static void propagate_dfneeded_internal(dynarec_native_t* dyn, int ninst)
|
||||
{
|
||||
while(ninst>=0) {
|
||||
if(dyn->insts[ninst].df_needed)
|
||||
return; // already flagged
|
||||
dyn->insts[ninst].df_needed = 1;
|
||||
if(dyn->insts[ninst].x64.gen_flags || (dyn->insts[ninst].x64.use_flags&X_PEND) || (dyn->insts[ninst].x64.need_before))
|
||||
return; // flags are use, we can stop propagate there
|
||||
if(!dyn->insts[ninst].pred_sz)
|
||||
return;
|
||||
for(int i=1; i<dyn->insts[ninst].pred_sz; ++i)
|
||||
propagate_dfneeded_internal(dyn, dyn->insts[ninst].pred[i]);
|
||||
ninst = dyn->insts[ninst].pred[0];
|
||||
}
|
||||
}
|
||||
|
||||
static void propagate_nodf_internal(dynarec_native_t* dyn, int ninst)
|
||||
{
|
||||
while(ninst>=0) {
|
||||
if(dyn->insts[ninst].df_needed)
|
||||
return; // flag are needed, stop
|
||||
if(dyn->insts[ninst].df_notneeded)
|
||||
return; // already flagged
|
||||
if(dyn->insts[ninst].x64.gen_flags || dyn->insts[ninst].x64.use_flags)
|
||||
return; // flags are use, so maybe it's needed
|
||||
if(dyn->insts[ninst].x64.has_callret || (dyn->insts[ninst].x64.barrier&BARRIER_FLAGS))
|
||||
return; // stop propagate
|
||||
dyn->insts[ninst].df_notneeded = 1;
|
||||
if(!dyn->insts[ninst].pred_sz)
|
||||
return;
|
||||
for(int i=1; i<dyn->insts[ninst].pred_sz; ++i)
|
||||
propagate_nodf(dyn, dyn->insts[ninst].pred[i]);
|
||||
propagate_nodf_internal(dyn, dyn->insts[ninst].pred[i]);
|
||||
ninst = dyn->insts[ninst].pred[0];
|
||||
}
|
||||
}
|
||||
|
||||
void propagate_nodf(dynarec_native_t* dyn)
|
||||
{
|
||||
// first propagate the df_needed flag
|
||||
for(int ninst=dyn->size-1; ninst>=0; --ninst) {
|
||||
if((dyn->insts[ninst].x64.jmp && dyn->insts[ninst].x64.jmp_insts==-1)
|
||||
|| (dyn->insts[ninst].x64.barrier&BARRIER_FLAGS) || (dyn->insts[ninst].x64.use_flags)
|
||||
|| dyn->insts[ninst].x64.has_callret
|
||||
|| ((dyn->insts[ninst].x64.state_flags&SF_SUB) && dyn->insts[ninst].x64.need_before)
|
||||
)
|
||||
propagate_dfneeded_internal(dyn, ninst);
|
||||
}
|
||||
// and now propagete df_unneeded
|
||||
for(int ninst=dyn->size-1; ninst>=0; --ninst) {
|
||||
if(dyn->insts[ninst].f_exit!=status_unk && dyn->insts[ninst].x64.gen_flags)
|
||||
propagate_nodf_internal(dyn, ninst);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void x64disas_add_register_mapping_annotations(char* buf, const char* disas, const register_mapping_t* mappings, size_t mappings_sz)
|
||||
{
|
||||
static char tmp[32];
|
||||
@@ -865,3 +938,21 @@ void x64disas_add_register_mapping_annotations(char* buf, const char* disas, con
|
||||
if (tmp[0]) tmp[strlen(tmp) - 1] = '\0';
|
||||
sprintf(buf, "%-35s ;%s", disas, tmp);
|
||||
}
|
||||
|
||||
void dynarec_stopped(uintptr_t ip, int is32bits)
|
||||
{
|
||||
#define PKip(A) (((uint8_t*)ip)[A])
|
||||
dynarec_log(LOG_NONE, "%p: Dynarec stopped because of %s Opcode ", (void*)ip, is32bits ? "x86" : "x64");
|
||||
zydis_dec_t* dec = is32bits ? my_context->dec32 : my_context->dec;
|
||||
if(getProtection(ip+14)&PROT_READ) {
|
||||
if (dec) {
|
||||
dynarec_log_prefix(0, LOG_NONE, "%s", DecodeX64Trace(dec, ip, 1));
|
||||
} else {
|
||||
dynarec_log_prefix(0, LOG_NONE, "%02hhX %02hhX %02hhX %02hhX %02hhX %02hhX %02hhX %02hhX %02hhX %02hhX %02hhX %02hhX %02hhX %02hhX %02hhX",
|
||||
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));
|
||||
}
|
||||
} else dynarec_log_prefix(0, LOG_NONE, "%02hhX", PKip(0));
|
||||
PrintFunctionAddr(ip, " => ");
|
||||
dynarec_log_prefix(0, LOG_NONE, "\n");
|
||||
}
|
||||
@@ -71,7 +71,7 @@ void native_div0(x64emu_t* emu);
|
||||
// Caches transformation (for loops) // Specific, need to be written par backend
|
||||
int CacheNeedsTransform(dynarec_native_t* dyn, int i1);
|
||||
// propagete defererd to unknow, as state is not needed
|
||||
void propagate_nodf(dynarec_native_t* dyn, int ninst);
|
||||
void propagate_nodf(dynarec_native_t* dyn);
|
||||
|
||||
// predecessor access
|
||||
int isPred(dynarec_native_t* dyn, int ninst, int pred);
|
||||
@@ -88,6 +88,7 @@ typedef struct register_mapping_s {
|
||||
} register_mapping_t;
|
||||
|
||||
void x64disas_add_register_mapping_annotations(char* buf, const char* disas, const register_mapping_t* mappings, size_t mappings_sz);
|
||||
void dynarec_stopped(uintptr_t x64addr, int is32bits);
|
||||
|
||||
ADDITIONNAL_DEFINITION()
|
||||
|
||||
|
||||
@@ -31,6 +31,27 @@
|
||||
#ifndef PROT_READ
|
||||
#define PROT_READ 0x1
|
||||
#endif
|
||||
|
||||
// Fail-close guard for page-boundary decode hazards:
|
||||
// if we cannot read a full x86 max instruction window, stop block build early.
|
||||
static int dynarec_can_read_window(uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
if(!size)
|
||||
return 1;
|
||||
uintptr_t end = addr + size - 1;
|
||||
if(end < addr)
|
||||
return 0;
|
||||
|
||||
uintptr_t cur = addr;
|
||||
while(1) {
|
||||
if(!(getProtection(cur) & PROT_READ))
|
||||
return 0;
|
||||
uintptr_t page_end = (cur & ~(box64_pagesize - 1)) + box64_pagesize - 1;
|
||||
if(end <= page_end)
|
||||
return 1;
|
||||
cur = page_end + 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int is32bits, int inst_max)
|
||||
@@ -44,7 +65,7 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
int rep = 0; // 0 none, 1=F2 prefix, 2=F3 prefix
|
||||
int need_epilog = 1;
|
||||
// Clean up (because there are multiple passes)
|
||||
#ifdef ARM64
|
||||
#if defined(ARM64) || defined(LA64) || defined(PPC64LE)
|
||||
dyn->f = status_unk;
|
||||
#else
|
||||
dyn->f.pending = 0;
|
||||
@@ -55,6 +76,7 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
dyn->forward_size = 0;
|
||||
dyn->forward_ninst = 0;
|
||||
dyn->ymm_zero = 0;
|
||||
dyn->is_file_mapped = IsAddrElfOrFileMapped(addr);
|
||||
int dynarec_dirty = BOX64ENV(dynarec_dirty);
|
||||
#if STEP == 0
|
||||
memset(&dyn->insts[ninst], 0, sizeof(instruction_native_t));
|
||||
@@ -66,7 +88,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 + !IsAddrElfOrFileMapped(addr); // if block is in elf memory or file mapped memory, it can be extended with BOX64DRENV(dynarec_bigblock)==2, else it needs 3
|
||||
int stopblock = 2 + !dyn->is_file_mapped; // 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
|
||||
@@ -74,17 +96,21 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
#endif
|
||||
while(ok) {
|
||||
#if STEP == 0
|
||||
int stop_for_guard = 0;
|
||||
if(cur_page != ((addr)&~(box64_pagesize-1))) {
|
||||
cur_page = (addr)&~(box64_pagesize-1);
|
||||
uint32_t prot = getProtection(addr);
|
||||
if(!(prot&PROT_READ) || checkInHotPage(addr) || (addr>dyn->end)) {
|
||||
dynarec_log(LOG_INFO, "Stopping dynablock because of protection, hotpage or mmap crossing at %p -> %p inst=%d\n", (void*)dyn->start, (void*)addr, ninst);
|
||||
need_epilog = 1;
|
||||
break;
|
||||
if(!(prot&PROT_READ) || !(prot&PROT_EXEC) || checkInHotPage(addr) || (addr>dyn->end)) {
|
||||
stop_for_guard = 1;
|
||||
}
|
||||
if(prot&PROT_NEVERCLEAN)
|
||||
dyn->always_test = 1;
|
||||
}
|
||||
if(stop_for_guard) {
|
||||
dynarec_log(LOG_INFO, "Stopping dynablock because of protection/hotpage/mmap/decode-window at %p -> %p inst=%d\n", (void*)dyn->start, (void*)addr, ninst);
|
||||
need_epilog = 1;
|
||||
break;
|
||||
}
|
||||
// This test is here to prevent things like TABLE64 to be out of range
|
||||
// native_size is not exact at this point, but it should be larger, not smaller, and not by a huge margin anyway
|
||||
// so it's good enough to avoid overflow in relative to PC data fectching
|
||||
@@ -101,17 +127,24 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
if(!ninst) {
|
||||
if(dyn->have_purge)
|
||||
doEnterBlock(dyn, 0, x1, x2, x3);
|
||||
if(dyn->always_test)
|
||||
checkCRC(dyn, 0);
|
||||
if(dyn->insts[0].preload_xmmymm)
|
||||
doPreload(dyn, 0);
|
||||
ENDPREFIX;
|
||||
}
|
||||
#elif defined(LA64)
|
||||
if(!ninst) {
|
||||
if(dyn->always_test)
|
||||
checkCRC(dyn, 0);
|
||||
}
|
||||
#endif
|
||||
fpu_propagate_stack(dyn, ninst);
|
||||
if (reset_n!=-1) {
|
||||
dyn->last_ip = 0;
|
||||
if(reset_n==-2) {
|
||||
MESSAGE(LOG_DEBUG, "Reset Caches to zero\n");
|
||||
#ifdef ARM64
|
||||
#if defined(ARM64) || defined(LA64) || defined(PPC64LE)
|
||||
dyn->f = status_unk;
|
||||
#else
|
||||
dyn->f.dfnone = 0;
|
||||
@@ -128,7 +161,7 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
}
|
||||
if(dyn->insts[ninst].x64.barrier&BARRIER_FLAGS) {
|
||||
MESSAGE(LOG_DEBUG, "Apply Barrier Flags\n");
|
||||
#ifdef ARM64
|
||||
#if defined(ARM64) || defined(LA64) || defined(PPC64LE)
|
||||
dyn->f = status_unk;
|
||||
#else
|
||||
dyn->f.dfnone = 0;
|
||||
@@ -163,10 +196,12 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
if (is_opcode_volatile && !dyn->insts[ninst].lock)
|
||||
DMB_ISHST();
|
||||
#endif
|
||||
if((dyn->insts[ninst].x64.need_before&~X_PEND) && !ninst) {
|
||||
READFLAGS(dyn->insts[ninst].x64.need_before&~X_PEND);
|
||||
if (BOX64DRENV(dynarec_dump) && (!BOX64ENV(dynarec_dump_range_end) || (ip >= BOX64ENV(dynarec_dump_range_start) && ip < BOX64ENV(dynarec_dump_range_end)))) {
|
||||
dyn->need_dump = BOX64DRENV(dynarec_dump);
|
||||
}
|
||||
if(BOX64ENV(dynarec_test) && (!BOX64ENV(dynarec_test_end) || (ip>=BOX64ENV(dynarec_test_start) && ip<BOX64ENV(dynarec_test_end)))) {
|
||||
int need_dump = dyn->need_dump;
|
||||
if (BOX64ENV(dynarec_test_nodump)) dyn->need_dump = 0;
|
||||
MESSAGE(LOG_DUMP, "TEST STEP ----\n");
|
||||
extcache_native_t save;
|
||||
fpu_save_and_unwind(dyn, ninst, &save);
|
||||
@@ -175,9 +210,7 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
fpu_unreflectcache(dyn, ninst, x1, x2, x3);
|
||||
fpu_unwind_restore(dyn, ninst, &save);
|
||||
MESSAGE(LOG_DUMP, "----------\n");
|
||||
}
|
||||
if (BOX64DRENV(dynarec_dump) && (!BOX64ENV(dynarec_dump_range_end) || (ip >= BOX64ENV(dynarec_dump_range_start) && ip < BOX64ENV(dynarec_dump_range_end)))) {
|
||||
dyn->need_dump = BOX64DRENV(dynarec_dump);
|
||||
dyn->need_dump = need_dump;
|
||||
}
|
||||
#ifdef HAVE_TRACE
|
||||
else if(my_context->dec && BOX64ENV(dynarec_trace)) {
|
||||
@@ -252,7 +285,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) {
|
||||
#if defined (RV64) || defined(LA64)
|
||||
#if defined (RV64) || defined(LA64) || defined(PPC64LE)
|
||||
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; }
|
||||
@@ -262,7 +295,7 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
#endif
|
||||
}
|
||||
if(dyn->insts[next].x64.barrier&BARRIER_FLAGS) {
|
||||
#ifdef ARM64
|
||||
#if defined(ARM64) || defined(LA64) || defined(PPC64LE)
|
||||
dyn->f = status_unk;
|
||||
#else
|
||||
dyn->f.pending = 0;
|
||||
@@ -288,7 +321,7 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
// we use the 1st predecessor here
|
||||
if((ninst+1)<dyn->size && !dyn->insts[ninst+1].x64.alive) {
|
||||
// reset fpu value...
|
||||
#ifdef ARM64
|
||||
#if defined(ARM64) || defined(LA64) || defined(PPC64LE)
|
||||
dyn->f = status_unk;
|
||||
#else
|
||||
dyn->f.dfnone = 0;
|
||||
@@ -442,7 +475,7 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
#endif
|
||||
++ninst;
|
||||
NOTEST(x3);
|
||||
#if defined (RV64) || defined(LA64)
|
||||
#if defined (RV64) || defined(LA64) || defined(PPC64LE)
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
#else
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3, 0);
|
||||
@@ -453,7 +486,7 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
}
|
||||
if(need_epilog) {
|
||||
NOTEST(x3);
|
||||
#if defined (RV64) || defined(LA64)
|
||||
#if defined (RV64) || defined(LA64) || defined(PPC64LE)
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
#else
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3, 0);
|
||||
|
||||
@@ -26,6 +26,13 @@ void rv64_epilog_fast(void) EXPORTDYN;
|
||||
#define native_prolog rv64_prolog
|
||||
#define native_epilog rv64_epilog
|
||||
#define native_epilog_fast rv64_epilog_fast
|
||||
#elif defined(PPC64LE)
|
||||
void ppc64le_next(void) EXPORTDYN;
|
||||
void ppc64le_prolog(x64emu_t* emu, void* addr) EXPORTDYN;
|
||||
void ppc64le_epilog(void) EXPORTDYN;
|
||||
#define native_next ppc64le_next
|
||||
#define native_prolog ppc64le_prolog
|
||||
#define native_epilog ppc64le_epilog
|
||||
#else
|
||||
#error Unsupported architecture
|
||||
#endif
|
||||
|
||||
+531
-321
File diff suppressed because it is too large.
Load diff
@@ -79,6 +79,31 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
}
|
||||
} else {
|
||||
switch ((nextop >> 3) & 7) {
|
||||
case 0:
|
||||
INST_NAME("SGDT Ed");
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, x2, &fixedaddress, rex, NULL, 0, 0);
|
||||
MOV32w(x1, 0x7f);
|
||||
ST_H(x1, wback, 0);
|
||||
if (rex.is32bits) {
|
||||
MOV32w(x1, 0x3000);
|
||||
ST_W(x1, wback, 2);
|
||||
} else {
|
||||
MOV64x(x1, 0xfffffe0000077000LL);
|
||||
ST_D(x1, wback, 2);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("SIDT Ed");
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, x2, &fixedaddress, rex, NULL, 0, 0);
|
||||
MOV32w(x1, 0xfff);
|
||||
ST_H(x1, wback, 0);
|
||||
if (rex.is32bits) {
|
||||
ST_W(xZR, wback, 2);
|
||||
} else {
|
||||
MOV64x(x1, 0xfffffe0000000000LL);
|
||||
ST_D(x1, wback, 2);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
@@ -418,7 +443,6 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("UCOMISS Gx, Ex");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETGX(d0, 0);
|
||||
GETEXSS(v0, 0, 0);
|
||||
@@ -593,12 +617,24 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
GETEM(q1, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
VEXT2XV_W_H(v0, q0);
|
||||
VEXT2XV_W_H(v1, q1);
|
||||
XVMUL_W(v0, v0, v1);
|
||||
VSRLI_W(v0, v0, 14);
|
||||
VADDI_WU(v0, v0, 1);
|
||||
VSRLNI_H_W(q0, v0, 1);
|
||||
if (cpuext.lasx) {
|
||||
VEXT2XV_W_H(v0, q0);
|
||||
VEXT2XV_W_H(v1, q1);
|
||||
XVMUL_W(v0, v0, v1);
|
||||
VSRLI_W(v0, v0, 14);
|
||||
VADDI_WU(v0, v0, 1);
|
||||
VSRLNI_H_W(q0, v0, 1);
|
||||
} else {
|
||||
VMULWEV_W_H(v0, q0, q1);
|
||||
VMULWOD_W_H(v1, q0, q1);
|
||||
VSRLI_W(v0, v0, 14);
|
||||
VSRLI_W(v1, v1, 14);
|
||||
VADDI_WU(v0, v0, 1);
|
||||
VADDI_WU(v1, v1, 1);
|
||||
VSRLNI_H_W(v1, v0, 1);
|
||||
VSHUF4I_W(v1, v1, 0b11011000);
|
||||
VSHUF4I_H(q0, v1, 0b11011000);
|
||||
}
|
||||
break;
|
||||
case 0x1C:
|
||||
INST_NAME("PABSB Gm, Em");
|
||||
@@ -892,7 +928,25 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
nextop = F8;
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX(v0, 1);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
VFCMP_S(v1, q0, v0, cUN);
|
||||
VFCMP_S(d0, v0, v0, cUN);
|
||||
MOV32w(x5, 0x00400000);
|
||||
VREPLGR2VR_W(d1, x5);
|
||||
VOR_V(d1, v0, d1);
|
||||
}
|
||||
VFADD_S(v0, v0, q0);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
VBITSEL_V(v0, v0, d1, d0);
|
||||
VFCMP_S(d0, v0, v0, cUN);
|
||||
VANDN_V(v1, v1, d0);
|
||||
VLDI(d0, 0b011111111100);
|
||||
VSLLI_W(d0, d0, 20);
|
||||
VBITSEL_V(v0, v0, d0, v1);
|
||||
}
|
||||
break;
|
||||
case 0x59:
|
||||
INST_NAME("MULPS Gx, Ex");
|
||||
@@ -902,17 +956,21 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
VFCMP_S(v0, q0, q1, cUN);
|
||||
VFCMP_S(d0, q1, q1, cUN);
|
||||
MOV32w(x5, 0x00400000);
|
||||
VREPLGR2VR_W(v1, x5);
|
||||
VOR_V(v1, q1, v1);
|
||||
}
|
||||
VFMUL_S(q1, q1, q0);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
VBITSEL_V(q1, q1, v1, d0);
|
||||
VFCMP_S(v1, q1, q1, cUN);
|
||||
VANDN_V(v0, v0, v1);
|
||||
VLDI(v1, 0b011111111100); // broadcast 0xFFFFFFFFFFFFFFFC
|
||||
VLDI(v1, 0b011111111100);
|
||||
VSLLI_W(v1, v1, 20);
|
||||
VAND_V(v1, v0, v1);
|
||||
VANDN_V(v0, v0, q1);
|
||||
VOR_V(q1, v0, v1);
|
||||
VBITSEL_V(q1, q1, v1, v0);
|
||||
}
|
||||
break;
|
||||
case 0x5A:
|
||||
@@ -937,17 +995,21 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
VFCMP_S(v0, q0, q1, cUN);
|
||||
VFCMP_S(d0, q1, q1, cUN);
|
||||
MOV32w(x5, 0x00400000);
|
||||
VREPLGR2VR_W(v1, x5);
|
||||
VOR_V(v1, q1, v1);
|
||||
}
|
||||
VFSUB_S(q1, q1, q0);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
VBITSEL_V(q1, q1, v1, d0);
|
||||
VFCMP_S(v1, q1, q1, cUN);
|
||||
VANDN_V(v0, v0, v1);
|
||||
VLDI(v1, 0b011111111100); // broadcast 0xFFFFFFFFFFFFFFFC
|
||||
VLDI(v1, 0b011111111100);
|
||||
VSLLI_W(v1, v1, 20);
|
||||
VAND_V(v1, v0, v1);
|
||||
VANDN_V(v0, v0, q1);
|
||||
VOR_V(q1, v0, v1);
|
||||
VBITSEL_V(q1, q1, v1, v0);
|
||||
}
|
||||
break;
|
||||
case 0x5D:
|
||||
@@ -955,13 +1017,9 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
if (!BOX64ENV(dynarec_fastnan) && v0 != v1) {
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
VFCMP_S(q0, v1, v0, cULE);
|
||||
VBITSEL_V(v0, v0, v1, q0);
|
||||
} else {
|
||||
VFMIN_S(v0, v0, v1);
|
||||
}
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
VFCMP_S(q0, v1, v0, cULE);
|
||||
VBITSEL_V(v0, v0, v1, q0);
|
||||
break;
|
||||
case 0x5E:
|
||||
INST_NAME("DIVPS Gx, Ex");
|
||||
@@ -971,17 +1029,21 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
VFCMP_S(v0, q0, q1, cUN);
|
||||
VFCMP_S(d0, q1, q1, cUN);
|
||||
MOV32w(x5, 0x00400000);
|
||||
VREPLGR2VR_W(v1, x5);
|
||||
VOR_V(v1, q1, v1);
|
||||
}
|
||||
VFDIV_S(q1, q1, q0);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
VBITSEL_V(q1, q1, v1, d0);
|
||||
VFCMP_S(v1, q1, q1, cUN);
|
||||
VANDN_V(v0, v0, v1);
|
||||
VLDI(v1, 0b011111111100); // broadcast 0xFFFFFFFFFFFFFFFC
|
||||
VLDI(v1, 0b011111111100);
|
||||
VSLLI_W(v1, v1, 20);
|
||||
VAND_V(v1, v0, v1);
|
||||
VANDN_V(v0, v0, q1);
|
||||
VOR_V(q1, v0, v1);
|
||||
VBITSEL_V(q1, q1, v1, v0);
|
||||
}
|
||||
break;
|
||||
case 0x5F:
|
||||
@@ -989,14 +1051,10 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
if (!BOX64ENV(dynarec_fastnan) && v0 != v1) {
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
VFCMP_S(q0, v1, v0, cLT); // ~cLT = un ge eq, if either v0/v1=nan ,choose v1. if eq either is ok,but when +0.0 == -0.0 x86 sse choose v1
|
||||
VBITSEL_V(v0, v1, v0, q0); // swap v0 v1 => v1 v0 for ~cLT
|
||||
} else {
|
||||
VFMAX_S(v0, v0, v1);
|
||||
}
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
VFCMP_S(q0, v1, v0, cLT); // ~cLT = un ge eq, if either v0/v1=nan ,choose v1. if eq either is ok,but when +0.0 == -0.0 x86 sse choose v1
|
||||
VBITSEL_V(v0, v1, v0, q0); // swap v0 v1 => v1 v0 for ~cLT
|
||||
break;
|
||||
case 0x60:
|
||||
INST_NAME("PUNPCKLBW Gm,Em");
|
||||
@@ -1096,7 +1154,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
GETG;
|
||||
v0 = mmx_get_reg_empty(dyn, ninst, x1, x2, x3, gd);
|
||||
if (MODREG) {
|
||||
ed = TO_NAT(nextop & 7);
|
||||
ed = TO_NAT((nextop & 0x07) + (rex.b << 3));
|
||||
if (rex.w) {
|
||||
MOVGR2FR_D(v0, ed);
|
||||
} else {
|
||||
@@ -1406,14 +1464,14 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("POP FS");
|
||||
POP1z(x2);
|
||||
ST_H(x2, xEmu, offsetof(x64emu_t, segs[_FS]));
|
||||
BEQ_NEXT(x2, xZR);
|
||||
CBZ_NEXT(x2);
|
||||
ADDI_D(x1, xZR, _FS);
|
||||
CALL(const_getsegmentbase, -1, x1, 0);
|
||||
break;
|
||||
case 0xA2:
|
||||
INST_NAME("CPUID");
|
||||
NOTEST(x1);
|
||||
CALL_(const_cpuid, -1, 0, xRAX, 0);
|
||||
CALL_(const_cpuid, -1, 0, 0, 0);
|
||||
// BX and DX are not synchronized durring the call, so need to force the update
|
||||
LD_D(xRDX, xEmu, offsetof(x64emu_t, regs[_DX]));
|
||||
LD_D(xRBX, xEmu, offsetof(x64emu_t, regs[_BX]));
|
||||
@@ -1450,7 +1508,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
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, NAT_FLAGS_FUSION);
|
||||
GETED(1);
|
||||
GETGD;
|
||||
@@ -1466,14 +1524,16 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 0xA5:
|
||||
nextop = F8;
|
||||
INST_NAME("SHLD Ed, Gd, CL");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION); // some flags are left undefined
|
||||
if (BOX64DRENV(dynarec_safeflags) > 1)
|
||||
MAYSETFLAGS();
|
||||
if (BOX64DRENV(dynarec_safeflags) > 1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_FUSION);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETGD;
|
||||
GETED(0);
|
||||
if (!rex.w && !rex.is32bits && MODREG) { ZEROUP(ed); }
|
||||
ANDI(x3, xRCX, rex.w ? 0x3f : 0x1f);
|
||||
BEQ_NEXT(x3, xZR);
|
||||
CBZ_NEXT(x3);
|
||||
emit_shld32(dyn, ninst, rex, ed, gd, x3, x4, x5, x6);
|
||||
WBACK;
|
||||
break;
|
||||
@@ -1486,7 +1546,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("POP GS");
|
||||
POP1z(x2);
|
||||
ST_H(x2, xEmu, offsetof(x64emu_t, segs[_GS]));
|
||||
BEQ_NEXT(x2, xZR);
|
||||
CBZ_NEXT(x2);
|
||||
ADDI_D(x1, xZR, _GS);
|
||||
CALL(const_getsegmentbase, -1, x1, 0);
|
||||
break;
|
||||
@@ -1534,7 +1594,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
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, NAT_FLAGS_FUSION);
|
||||
GETED(1);
|
||||
GETGD;
|
||||
@@ -1550,14 +1610,16 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 0xAD:
|
||||
nextop = F8;
|
||||
INST_NAME("SHRD Ed, Gd, CL");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
if (BOX64DRENV(dynarec_safeflags) > 1)
|
||||
MAYSETFLAGS();
|
||||
if (BOX64DRENV(dynarec_safeflags) > 1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_FUSION);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETGD;
|
||||
GETED(0);
|
||||
if (!rex.w && !rex.is32bits && MODREG) { ZEROUP(ed); }
|
||||
ANDI(x3, xRCX, rex.w ? 0x3f : 0x1f);
|
||||
BEQ_NEXT(x3, xZR);
|
||||
CBZ_NEXT(x3);
|
||||
emit_shrd32(dyn, ninst, rex, ed, gd, x3, x5, x4, x6);
|
||||
WBACK;
|
||||
break;
|
||||
@@ -1585,19 +1647,13 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 0:
|
||||
INST_NAME("FXSAVE Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
SKIPTEST(x1);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
if (MODREG) {
|
||||
DEFAULT;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x3, &fixedaddress, rex, NULL, 0, 0);
|
||||
CALL(rex.is32bits ? const_fpu_fxsave32 : const_fpu_fxsave64, -1, ed, 0);
|
||||
}
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x3, &fixedaddress, rex, NULL, 0, 0);
|
||||
CALL(rex.is32bits ? const_fpu_fxsave32 : const_fpu_fxsave64, -1, ed, 0);
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FXRSTOR Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
SKIPTEST(x1);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x3, &fixedaddress, rex, NULL, 0, 0);
|
||||
CALL(rex.is32bits ? const_fpu_fxrstor32 : const_fpu_fxrstor64, -1, ed, 0);
|
||||
@@ -1940,13 +1996,16 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
}
|
||||
BNE_MARK(ed, xZR);
|
||||
IFX (X_ZF) ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
if (BOX64DRENV(dynarec_safeflags)) {
|
||||
IFX (X_PF) ORI(xFlags, xFlags, 1 << F_PF);
|
||||
}
|
||||
B_MARK2_nocond;
|
||||
MARK;
|
||||
CTZxw(gd, ed);
|
||||
MARK2;
|
||||
IFX (BOX64DRENV(dynarec_safeflags)) {
|
||||
if (BOX64DRENV(dynarec_safeflags)) {
|
||||
IFX (X_PF) emit_pf(dyn, ninst, gd, x2, x5);
|
||||
}
|
||||
MARK2;
|
||||
SPILL_EFLAGS();
|
||||
break;
|
||||
case 0xBD:
|
||||
@@ -1967,15 +2026,18 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
}
|
||||
BNE_MARK(ed, xZR);
|
||||
IFX (X_ZF) ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
if (BOX64DRENV(dynarec_safeflags)) {
|
||||
IFX (X_PF) ORI(xFlags, xFlags, 1 << F_PF);
|
||||
}
|
||||
B_MARK2_nocond;
|
||||
MARK;
|
||||
CLZxw(gd, ed);
|
||||
ADDI_D(x1, xZR, rex.w ? 63 : 31);
|
||||
SUB_D(gd, x1, gd);
|
||||
MARK2;
|
||||
if (BOX64DRENV(dynarec_safeflags)) {
|
||||
IFX (X_PF) emit_pf(dyn, ninst, gd, x2, x5);
|
||||
}
|
||||
MARK2;
|
||||
SPILL_EFLAGS();
|
||||
break;
|
||||
case 0xBE:
|
||||
@@ -2034,8 +2096,8 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
GETED(0);
|
||||
if (ed != gd) MV(x7, ed);
|
||||
emit_add32(dyn, ninst, rex, ed, gd, x4, x5, x6);
|
||||
if (ed != gd) MVxw(gd, x7);
|
||||
WBACK;
|
||||
if (ed != gd) MVxw(gd, x7);
|
||||
break;
|
||||
case 0xC2:
|
||||
INST_NAME("CMPPS Gx, Ex, Ib");
|
||||
|
||||
+202
-134
@@ -51,18 +51,16 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("ADD Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
emit_add16(dyn, ninst, x1, x2, x4, x5, x6);
|
||||
GETGWEW(x1, x2, 0);
|
||||
emit_add16(dyn, ninst, ed, gd, x4, x5, x6);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0x03:
|
||||
INST_NAME("ADD Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
emit_add16(dyn, ninst, x1, x2, x3, x4, x6);
|
||||
GETGWEW(x1, x2, 0);
|
||||
emit_add16(dyn, ninst, gd, ed, x3, x4, x6);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x05:
|
||||
@@ -88,18 +86,16 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("OR Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
emit_or16(dyn, ninst, x1, x2, x4, x5);
|
||||
GETGWEW(x1, x2, 0);
|
||||
emit_or16(dyn, ninst, ed, gd, x4, x5);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0x0B:
|
||||
INST_NAME("OR Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
emit_or16(dyn, ninst, x1, x2, x4, x5);
|
||||
GETGWEW(x1, x2, 0);
|
||||
emit_or16(dyn, ninst, gd, ed, x4, x5);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x0D:
|
||||
@@ -123,9 +119,8 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
emit_adc16(dyn, ninst, x1, x2, x4, x6, x5);
|
||||
GETGWEW(x1, x2, 0);
|
||||
emit_adc16(dyn, ninst, ed, gd, x4, x6, x5);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0x13:
|
||||
@@ -133,9 +128,8 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
emit_adc16(dyn, ninst, x1, x2, x4, x6, x5);
|
||||
GETGWEW(x1, x2, 0);
|
||||
emit_adc16(dyn, ninst, gd, ed, x4, x6, x5);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x15:
|
||||
@@ -153,9 +147,8 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
emit_sbb16(dyn, ninst, x1, x2, x4, x5, x6);
|
||||
GETGWEW(x1, x2, 0);
|
||||
emit_sbb16(dyn, ninst, ed, gd, x4, x5, x6);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0x1B:
|
||||
@@ -163,9 +156,8 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
emit_sbb16(dyn, ninst, x1, x2, x6, x4, x5);
|
||||
GETGWEW(x1, x2, 0);
|
||||
emit_sbb16(dyn, ninst, gd, ed, x6, x4, x5);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x1D:
|
||||
@@ -192,18 +184,16 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("AND Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
emit_and16(dyn, ninst, x1, x2, x4, x5);
|
||||
GETGWEW(x1, x2, 0);
|
||||
emit_and16(dyn, ninst, ed, gd, x4, x5);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0x23:
|
||||
INST_NAME("AND Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
emit_and16(dyn, ninst, x1, x2, x3, x4);
|
||||
GETGWEW(x1, x2, 0);
|
||||
emit_and16(dyn, ninst, gd, ed, x3, x4);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x25:
|
||||
@@ -219,18 +209,16 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("SUB Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
emit_sub16(dyn, ninst, x2, x1, x4, x5, x6);
|
||||
GETGWEW(x1, x2, 0);
|
||||
emit_sub16(dyn, ninst, ed, gd, x4, x5, x6);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0x2B:
|
||||
INST_NAME("SUB Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
emit_sub16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
GETGWEW(x1, x2, 0);
|
||||
emit_sub16(dyn, ninst, gd, ed, x3, x4, x5);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x2D:
|
||||
@@ -246,18 +234,16 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("XOR Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
emit_xor16(dyn, ninst, x1, x2, x4, x5, x6);
|
||||
GETGWEW(x1, x2, 0);
|
||||
emit_xor16(dyn, ninst, ed, gd, x4, x5, x6);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0x33:
|
||||
INST_NAME("XOR Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
emit_xor16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
GETGWEW(x1, x2, 0);
|
||||
emit_xor16(dyn, ninst, gd, ed, x3, x4, x5);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x35:
|
||||
@@ -273,17 +259,15 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("CMP Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5, x6);
|
||||
GETGWEW(x1, x2, 0);
|
||||
emit_cmp16(dyn, ninst, ed, gd, x3, x4, x5, x6);
|
||||
break;
|
||||
case 0x3B:
|
||||
INST_NAME("CMP Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5, x6);
|
||||
GETGWEW(x1, x2, 0);
|
||||
emit_cmp16(dyn, ninst, gd, ed, x3, x4, x5, x6);
|
||||
break;
|
||||
case 0x3D:
|
||||
INST_NAME("CMP AX, Iw");
|
||||
@@ -392,17 +376,21 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 0x68:
|
||||
INST_NAME("PUSH Iw");
|
||||
u16 = F16;
|
||||
MOV32w(x2, u16);
|
||||
PUSH1_16(x2);
|
||||
if (!u16) {
|
||||
PUSH1_16(xZR);
|
||||
} else {
|
||||
MOV32w(x2, u16);
|
||||
PUSH1_16(x2);
|
||||
}
|
||||
break;
|
||||
case 0x69:
|
||||
case 0x6B:
|
||||
if (opcode == 0x69) {
|
||||
INST_NAME("IMUL Gw,Ew,Iw");
|
||||
INST_NAME("IMUL Gw, Ew, Iw");
|
||||
} else {
|
||||
INST_NAME("IMUL Gw,Ew,Ib");
|
||||
INST_NAME("IMUL Gw, Ew, Ib");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_PENDING, NAT_FLAGS_NOFUSION);
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
|
||||
nextop = F8;
|
||||
GETSEW(x1, (opcode == 0x69) ? 2 : 1);
|
||||
if (opcode == 0x69)
|
||||
@@ -411,16 +399,34 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
i32 = F8S;
|
||||
MOV32w(x2, i32);
|
||||
MUL_W(x2, x2, x1);
|
||||
UFLAG_RES(x2);
|
||||
gd = x2;
|
||||
GWBACK;
|
||||
UFLAG_DF(x1, d_imul16);
|
||||
SET_DFNONE();
|
||||
CLEAR_FLAGS(x3);
|
||||
IFX (X_CF | X_OF) {
|
||||
SRAI_W(x1, x2, 15);
|
||||
SRAI_W(x3, x2, 31);
|
||||
XOR(x3, x1, x3);
|
||||
SNEZ(x3, x3);
|
||||
IFX (X_CF) BSTRINS_D(xFlags, x3, F_CF, F_CF);
|
||||
IFX (X_OF) BSTRINS_D(xFlags, x3, F_OF, F_OF);
|
||||
}
|
||||
IFX (X_SF) {
|
||||
SRLI_D(x3, x2, 15);
|
||||
BSTRINS_D(xFlags, x3, F_SF, F_SF);
|
||||
}
|
||||
IFX (X_PF) emit_pf(dyn, ninst, x2, x3, x5);
|
||||
IFXA (X_ALL, cpuext.lbt) SPILL_EFLAGS();
|
||||
break;
|
||||
case 0x6A:
|
||||
INST_NAME("PUSH Ib");
|
||||
i16 = F8S;
|
||||
MOV32w(x2, (uint16_t)i16);
|
||||
PUSH1_16(x2);
|
||||
if (!i16) {
|
||||
PUSH1_16(xZR);
|
||||
} else {
|
||||
MOV32w(x2, (uint16_t)i16);
|
||||
PUSH1_16(x2);
|
||||
}
|
||||
break;
|
||||
case 0x6C:
|
||||
case 0x6E:
|
||||
@@ -587,9 +593,8 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("TEST Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
nextop = F8;
|
||||
GETEW(x1, 0);
|
||||
GETGW(x2);
|
||||
emit_test16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
GETGWEW(x1, x2, 0);
|
||||
emit_test16(dyn, ninst, ed, gd, x3, x4, x5);
|
||||
break;
|
||||
case 0x87:
|
||||
INST_NAME("(LOCK) XCHG Ew, Gw");
|
||||
@@ -687,8 +692,11 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("LEA Gd, Ed");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if (MODREG) { // reg <= reg? that's an invalid operation
|
||||
DEFAULT;
|
||||
if (MODREG) {
|
||||
INST_NAME("Invalid 8D");
|
||||
UDF();
|
||||
*need_epilog = 1;
|
||||
*ok = 0;
|
||||
} else { // mem <= reg
|
||||
rex.seg = 0;
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 0, 0);
|
||||
@@ -696,23 +704,30 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
}
|
||||
break;
|
||||
case 0x8E:
|
||||
INST_NAME("MOV Seg, Ew");
|
||||
nextop = F8;
|
||||
u8 = (nextop & 0x38) >> 3;
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
if ((u8 > 5) || (u8 == 1)) {
|
||||
INST_NAME("Invalid MOV Seg, Ew");
|
||||
UDF();
|
||||
*need_epilog = 1;
|
||||
*ok = 0;
|
||||
} 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]));
|
||||
if ((u8 == _FS) || (u8 == _GS)) {
|
||||
// refresh offset if needed
|
||||
CBZ_NEXT(ed);
|
||||
MOV32w(x1, u8);
|
||||
CALL(const_getsegmentbase, -1, x1, x2);
|
||||
INST_NAME("MOV Seg, Ew");
|
||||
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]));
|
||||
if ((u8 == _FS) || (u8 == _GS)) {
|
||||
// refresh offset if needed
|
||||
CBZ_NEXT(ed);
|
||||
MOV32w(x1, u8);
|
||||
CALL(const_getsegmentbase, -1, x1, x2);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x8F:
|
||||
@@ -754,14 +769,12 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
break;
|
||||
case 0x98:
|
||||
INST_NAME("CBW");
|
||||
SLLI_D(x1, xRAX, 56);
|
||||
SRAI_D(x1, x1, 56);
|
||||
EXT_W_B(x1, xRAX);
|
||||
BSTRINSz(xRAX, x1, 15, 0);
|
||||
break;
|
||||
case 0x99:
|
||||
INST_NAME("CWD");
|
||||
SLLI_D(x1, xRAX, 48);
|
||||
SRAI_D(x1, x1, 48);
|
||||
EXT_W_H(x1, xRAX);
|
||||
SRLI_D(x1, x1, 48);
|
||||
BSTRINS_D(xRDX, x1, 15, 0);
|
||||
break;
|
||||
@@ -788,6 +801,9 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
ANDI(x1, xFlags, 1 << F_TF);
|
||||
CBZ_NEXT(x1);
|
||||
// go to epilog, TF should trigger at end of next opcode, so using Interpreter only
|
||||
LD_W(x4, xEmu, offsetof(x64emu_t, flags));
|
||||
ORI(x4, x4, 1<<FLAGS_NO_TF);
|
||||
ST_W(x4, xEmu, offsetof(x64emu_t, flags));
|
||||
jump_to_epilog(dyn, addr, 0, ninst);
|
||||
}
|
||||
break;
|
||||
@@ -801,7 +817,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
u64 = F64;
|
||||
MOV64y(x1, u64);
|
||||
if (rex.seg) {
|
||||
grab_segdata(dyn, addr, ninst, x3, rex.seg, 0);
|
||||
grab_segdata(dyn, addr, ninst, x3, rex.seg);
|
||||
ADDxREGy(x1, x3, x1, x1);
|
||||
}
|
||||
lock = (rex.seg) ? 0 : isLockAddress(u64);
|
||||
@@ -819,7 +835,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
u64 = F64;
|
||||
MOV64y(x1, u64);
|
||||
if (rex.seg) {
|
||||
grab_segdata(dyn, addr, ninst, x3, rex.seg, 0);
|
||||
grab_segdata(dyn, addr, ninst, x3, rex.seg);
|
||||
ADDxREGy(x1, x3, x1, x1);
|
||||
}
|
||||
lock = (rex.seg) ? 0 : isLockAddress(u64);
|
||||
@@ -870,8 +886,11 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
INST_NAME("REPZ CMPSW");
|
||||
}
|
||||
MAYSETFLAGS();
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_NOFUSION);
|
||||
if (BOX64DRENV(dynarec_safeflags) > 1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_NOFUSION);
|
||||
CBZ_NEXT(xRCX);
|
||||
ANDI(x1, xFlags, 1 << F_DF);
|
||||
BNEZ_MARK2(x1);
|
||||
@@ -969,8 +988,11 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
INST_NAME("REPZ SCASW");
|
||||
}
|
||||
MAYSETFLAGS();
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
if (BOX64DRENV(dynarec_safeflags) > 1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_NOFUSION);
|
||||
CBZ_NEXT(xRCX);
|
||||
GETDIR(x3, x1, rex.w ? 8 : 2);
|
||||
if (rex.w) {
|
||||
@@ -1211,52 +1233,65 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
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, NAT_FLAGS_FUSION);
|
||||
ANDI(x2, xRCX, 0x1f);
|
||||
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_(const_rol16, x1, x3, x1, x2);
|
||||
CBZ_NEXT(x2);
|
||||
GETEW(x1, 0);
|
||||
emit_rol16(dyn, ninst, x1, x2, x5, x4);
|
||||
EWBACK;
|
||||
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, NAT_FLAGS_FUSION);
|
||||
ANDI(x2, xRCX, 0x1f);
|
||||
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_(const_ror16, x1, x3, x1, x2);
|
||||
CBZ_NEXT(x2);
|
||||
GETEW(x1, 0);
|
||||
emit_ror16(dyn, ninst, x1, x2, x5, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("RCL Ew, CL");
|
||||
if (BOX64DRENV(dynarec_safeflags) > 1) {
|
||||
READFLAGS(X_OF | X_CF);
|
||||
} else {
|
||||
READFLAGS(X_CF);
|
||||
}
|
||||
SETFLAGS(X_OF | X_CF, SF_SUBSET, NAT_FLAGS_FUSION);
|
||||
ANDI(x2, xRCX, 0x1f);
|
||||
MESSAGE("LOG_DUMP", "Need optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF | X_CF, SF_SET_DF, NAT_FLAGS_NOFUSION);
|
||||
if (BOX64DRENV(dynarec_safeflags) > 1) MAYSETFLAGS();
|
||||
GETEW(x1, 1);
|
||||
CALL_(const_rcl16, x1, x3, x1, x2);
|
||||
CBZ_NEXT(x2);
|
||||
GETEW(x1, 0);
|
||||
emit_rcl16(dyn, ninst, x1, x2, x5, x4, x6);
|
||||
EWBACK;
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("RCR Ew, CL");
|
||||
if (BOX64DRENV(dynarec_safeflags) > 1) {
|
||||
READFLAGS(X_OF | X_CF);
|
||||
} else {
|
||||
READFLAGS(X_CF);
|
||||
}
|
||||
SETFLAGS(X_OF | X_CF, SF_SUBSET, NAT_FLAGS_FUSION);
|
||||
ANDI(x2, xRCX, 0x1f);
|
||||
MESSAGE("LOG_DUMP", "Need optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF | X_CF, SF_SET_DF, NAT_FLAGS_NOFUSION);
|
||||
if (BOX64DRENV(dynarec_safeflags) > 1) MAYSETFLAGS();
|
||||
GETEW(x1, 1);
|
||||
CALL_(const_rcr16, x1, x3, x1, x2);
|
||||
CBZ_NEXT(x2);
|
||||
GETEW(x1, 0);
|
||||
emit_rcr16(dyn, ninst, x1, x2, x5, x4, x6);
|
||||
EWBACK;
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("SHR Ew, CL");
|
||||
if (BOX64DRENV(dynarec_safeflags) > 1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_FUSION);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION); // some flags are left undefined
|
||||
ANDI(x2, xRCX, 0x1f);
|
||||
BEQ_NEXT(x2, xZR);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION); // some flags are left undefined
|
||||
if (BOX64DRENV(dynarec_safeflags) > 1) MAYSETFLAGS();
|
||||
CBZ_NEXT(x2);
|
||||
GETEW(x1, 0);
|
||||
emit_shr16(dyn, ninst, x1, x2, x5, x4, x6);
|
||||
EWBACK;
|
||||
@@ -1264,27 +1299,51 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 4:
|
||||
case 6:
|
||||
INST_NAME("SHL Ew, CL");
|
||||
if (BOX64DRENV(dynarec_safeflags) > 1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_FUSION);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION); // some flags are left undefined
|
||||
ANDI(x2, xRCX, 0x1f);
|
||||
BEQ_NEXT(x2, xZR);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION); // some flags are left undefined
|
||||
if (BOX64DRENV(dynarec_safeflags) > 1) MAYSETFLAGS();
|
||||
CBZ_NEXT(x2);
|
||||
GETEW(x1, 0);
|
||||
emit_shl16(dyn, ninst, x1, x2, x5, x4, x6);
|
||||
EWBACK;
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("SAR Ew, CL");
|
||||
if (BOX64DRENV(dynarec_safeflags) > 1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_FUSION);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION); // some flags are left undefined
|
||||
ANDI(x2, xRCX, 0x1f);
|
||||
BEQ_NEXT(x2, xZR);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION); // some flags are left undefined
|
||||
if (BOX64DRENV(dynarec_safeflags) > 1) MAYSETFLAGS();
|
||||
CBZ_NEXT(x2);
|
||||
GETSEW(x1, 0);
|
||||
emit_sar16(dyn, ninst, x1, x2, x5, x4, x6);
|
||||
EWBACK;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xD9:
|
||||
nextop = F8;
|
||||
if (MODREG) {
|
||||
DEFAULT;
|
||||
} else
|
||||
switch ((nextop >> 3) & 7) {
|
||||
case 6:
|
||||
INST_NAME("FNSTENV Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (FNSTENV16)\n");
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x2, &fixedaddress, rex, NULL, 0, 0);
|
||||
if (ed != x1) { MV(x1, ed); }
|
||||
MOV32w(x2, 1);
|
||||
CALL(const_fpu_savenv, -1, x1, x2);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0xE4: /* IN AL, Ib */
|
||||
case 0xE5: /* IN AX, Ib */
|
||||
case 0xE6: /* OUT Ib, AL */
|
||||
@@ -1324,16 +1383,28 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("MUL AX, Ew");
|
||||
SETFLAGS(X_ALL, SF_PENDING, NAT_FLAGS_NOFUSION);
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
|
||||
GETEW(x1, 0);
|
||||
BSTRPICK_D(x2, xRAX, 15, 0);
|
||||
MUL_W(x1, x2, x1);
|
||||
ZEROUP(x1);
|
||||
UFLAG_RES(x1);
|
||||
BSTRINSz(xRAX, x1, 15, 0);
|
||||
SRLI_D(x1, x1, 16);
|
||||
BSTRINS_D(xRDX, x1, 15, 0);
|
||||
UFLAG_DF(x1, d_mul16);
|
||||
SRLI_D(x3, x1, 16);
|
||||
BSTRINS_D(xRDX, x3, 15, 0);
|
||||
SET_DFNONE();
|
||||
CLEAR_FLAGS(x3);
|
||||
IFX (X_CF | X_OF) {
|
||||
SRLI_W(x3, x1, 16);
|
||||
SNEZ(x3, x3);
|
||||
IFX (X_CF) BSTRINS_D(xFlags, x3, F_CF, F_CF);
|
||||
IFX (X_OF) BSTRINS_D(xFlags, x3, F_OF, F_OF);
|
||||
}
|
||||
IFX (X_SF) {
|
||||
SRLI_D(x3, xRAX, 15);
|
||||
BSTRINS_D(xFlags, x3, F_SF, F_SF);
|
||||
}
|
||||
IFX (X_PF) emit_pf(dyn, ninst, xRAX, x3, x5);
|
||||
IFXA (X_ALL, cpuext.lbt) SPILL_EFLAGS();
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("DIV Ew");
|
||||
@@ -1341,9 +1412,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
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);
|
||||
BSTRINS_W(x2, xRDX, 31, 16);
|
||||
if (BOX64ENV(dynarec_div0)) {
|
||||
BNE_MARK3(ed, xZR);
|
||||
GETIP_(ip, x6);
|
||||
@@ -1354,8 +1423,8 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
MARK3;
|
||||
}
|
||||
DIV_WU(x7, x2, ed);
|
||||
MOD_WU(x4, x2, ed);
|
||||
DIV_WU(x7, x2, ed); // warning: x2 and ed must be signed extended!
|
||||
MOD_WU(x4, x2, ed); // warning: x2 and ed must be signed extended!
|
||||
BSTRINSz(xRAX, x7, 15, 0);
|
||||
BSTRINSz(xRDX, x4, 15, 0);
|
||||
SET_DFNONE();
|
||||
@@ -1381,10 +1450,9 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
MARK3;
|
||||
}
|
||||
BSTRPICK_D(x2, xRAX, 15, 0);
|
||||
SLLI_D(x3, xRDX, 16);
|
||||
OR(x2, x2, x3);
|
||||
DIV_W(x3, x2, ed);
|
||||
MOD_W(x4, x2, ed);
|
||||
BSTRINS_W(x2, xRDX, 31, 16);
|
||||
DIV_W(x3, x2, ed); // warning: x2 and ed must be signed extended!
|
||||
MOD_W(x4, x2, ed); // warning: x2 and ed must be signed extended!
|
||||
BSTRINSz(xRAX, x3, 15, 0);
|
||||
BSTRINSz(xRDX, x4, 15, 0);
|
||||
break;
|
||||
@@ -1400,14 +1468,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, NAT_FLAGS_FUSION);
|
||||
SETFLAGS(X_ALL & ~X_CF, SF_SUBSET, 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, NAT_FLAGS_FUSION);
|
||||
SETFLAGS(X_ALL & ~X_CF, SF_SUBSET, NAT_FLAGS_FUSION);
|
||||
GETEW(x1, 0);
|
||||
emit_dec16(dyn, ninst, x1, x2, x4, x5, x6);
|
||||
EWBACK;
|
||||
|
||||
@@ -135,14 +135,15 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETGX(v0, 1);
|
||||
if (MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop & 7) + (rex.b << 3), 0);
|
||||
VSHUF4I_D(v0, v1, 0b1101);
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x3, &fixedaddress, rex, NULL, 1, 0);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
ADDI_D(x1, ed, 8);
|
||||
FLD_D(v1, x1, fixedaddress);
|
||||
VSHUF4I_D(v0, v1, 0b1001);
|
||||
}
|
||||
VSHUF4I_D(v0, v1, 0xd);
|
||||
break;
|
||||
case 0x16:
|
||||
INST_NAME("MOVHPD Gx, Eq");
|
||||
@@ -477,13 +478,25 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETEX(q1, 0, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
VEXT2XV_W_H(v0, q0);
|
||||
VEXT2XV_W_H(v1, q1);
|
||||
XVMUL_W(v0, v0, v1);
|
||||
XVSRLI_W(v0, v0, 14);
|
||||
XVADDI_WU(v0, v0, 1);
|
||||
XVSRLNI_H_W(v0, v0, 1);
|
||||
XVPERMI_D(q0, v0, 0b1000);
|
||||
if (cpuext.lasx) {
|
||||
VEXT2XV_W_H(v0, q0);
|
||||
VEXT2XV_W_H(v1, q1);
|
||||
XVMUL_W(v0, v0, v1);
|
||||
XVSRLI_W(v0, v0, 14);
|
||||
XVADDI_WU(v0, v0, 1);
|
||||
XVSRLNI_H_W(v0, v0, 1);
|
||||
XVPERMI_D(q0, v0, 0b1000);
|
||||
} else {
|
||||
VMULWEV_W_H(v0, q0, q1);
|
||||
VMULWOD_W_H(v1, q0, q1);
|
||||
VSRLI_W(v0, v0, 14);
|
||||
VSRLI_W(v1, v1, 14);
|
||||
VADDI_WU(v0, v0, 1);
|
||||
VADDI_WU(v1, v1, 1);
|
||||
VSRLNI_H_W(v1, v0, 1);
|
||||
VSHUF4I_W(v1, v1, 0b11011000);
|
||||
VSHUF4I_H(q0, v1, 0b11011000);
|
||||
}
|
||||
break;
|
||||
case 0x10:
|
||||
INST_NAME("PBLENDVB Gx, Ex");
|
||||
@@ -641,7 +654,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
INST_NAME("PCMPEQQ Gx, Ex"); // SSE4 opcode!
|
||||
nextop = F8;
|
||||
GETEX(q1, 0, 0);
|
||||
GETGX_empty(q0);
|
||||
GETGX(q0, 1);
|
||||
VSEQ_D(q0, q0, q1);
|
||||
break;
|
||||
case 0x2A:
|
||||
@@ -682,7 +695,10 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
nextop = F8;
|
||||
GETEX(q1, 0, 0);
|
||||
GETGX_empty(q0);
|
||||
VEXT2XV_HU_BU(q0, q1);
|
||||
if (cpuext.lasx)
|
||||
VEXT2XV_HU_BU(q0, q1);
|
||||
else
|
||||
VSLLWIL_HU_BU(q0, q1, 0);
|
||||
break;
|
||||
case 0x31:
|
||||
INST_NAME("PMOVZXBD Gx, Ex"); // SSE4 opcode!
|
||||
@@ -793,6 +809,25 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETGX(q0, 1);
|
||||
VMUL_W(q0, q0, q1);
|
||||
break;
|
||||
case 0x41:
|
||||
INST_NAME("PHMINPOSUW Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(v1, 0, 0);
|
||||
GETGX(v0, 1);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
q2 = fpu_get_scratch(dyn);
|
||||
// v1[a,b,c,d,e,f,g,h]
|
||||
VSHUF4I_W(q0, v1, 0b01001110); // q0[e,f,g,h,a,b,c,d]
|
||||
VMIN_HU(q1, v1, q0); // q1[ae,bf,cg,dh ...]
|
||||
VSHUF4I_H(q2, q1, 0b10110001); // q2[bf,ae,dh,cg ...]
|
||||
VMIN_HU(q1, q1, q2); // q1[aebf,aebf,cgdh,cgdh ...]
|
||||
VSHUF4I_H(q0, q1, 0b01001110); // q0[cgdh,cgdh,aebf,aebf]
|
||||
VMIN_HU(q2, q0, q1); // all lane is min(abcdefgh)
|
||||
VSEQ_H(q0, q2, v1); // get mask(0xffff)
|
||||
VFRSTPI_H(q2, q0, 1); // find first neg(0xffff),insert index to q2
|
||||
XVPICKVE_W(v0, q2, 0);
|
||||
break;
|
||||
case 0xDB:
|
||||
INST_NAME("AESIMC Gx, Ex"); // AES-NI
|
||||
nextop = F8;
|
||||
@@ -896,13 +931,13 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
SETFLAGS(X_CF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
GETED(0);
|
||||
GETGD;
|
||||
if(cpuext.lbt) {
|
||||
X64_GET_EFLAGS(x3, X_CF); // CF pos is 0, no need SLLI
|
||||
if (cpuext.lbt) {
|
||||
X64_GET_EFLAGS(x3, X_CF); // CF pos is 0, no need SLLI
|
||||
} else {
|
||||
BSTRPICK_D(x3, xFlags, F_CF, F_CF);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
if(rex.w) {
|
||||
IFX (X_CF) {
|
||||
if (rex.w) {
|
||||
ADD_D(x4, gd, ed);
|
||||
SLTU(x5, x4, gd);
|
||||
ADD_D(gd, x4, x3);
|
||||
@@ -917,7 +952,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
SLTU(x6, gd, x4);
|
||||
}
|
||||
OR(x5, x5, x6);
|
||||
if(cpuext.lbt) {
|
||||
if (cpuext.lbt) {
|
||||
X64_SET_EFLAGS(x5, X_CF);
|
||||
} else {
|
||||
BSTRINS_D(xFlags, x5, F_CF, F_CF);
|
||||
@@ -1332,8 +1367,8 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x2, &fixedaddress, rex, NULL, 0, 1);
|
||||
}
|
||||
MV(x2, xRDX);
|
||||
MV(x4, xRAX);
|
||||
SEXT_W(x2, xRDX);
|
||||
SEXT_W(x4, xRAX);
|
||||
u8 = F8;
|
||||
MOV32w(x5, u8);
|
||||
CALL6(const_sse42_compare_string_explicit_len, x1, ed, x2, x3, x4, x5, 0);
|
||||
@@ -1363,7 +1398,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
ADDI_D(x1, xEmu, offsetof(x64emu_t, xmm[ed]));
|
||||
ed = x1;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x2, &fixedaddress, rex, NULL, 0, 1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x5, &fixedaddress, rex, NULL, 0, 1);
|
||||
}
|
||||
u8 = F8;
|
||||
MOV32w(x3, u8);
|
||||
@@ -1411,7 +1446,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
READFLAGS(F); \
|
||||
tmp1 = x1; \
|
||||
tmp3 = x3; \
|
||||
if (cpuext.lbt) { \
|
||||
if (cpuext.lbt) { \
|
||||
X64_SETJ(x1, I); \
|
||||
} else { \
|
||||
GETFLAGS; \
|
||||
@@ -1425,7 +1460,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
LD_HU(x4, ed, fixedaddress); \
|
||||
ed = x4; \
|
||||
} \
|
||||
if (cpuext.lbt) \
|
||||
if (cpuext.lbt) \
|
||||
BEQZ(x1, 4 + 4); \
|
||||
else \
|
||||
B##NO(x1, 4 + 4); \
|
||||
@@ -1506,17 +1541,22 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
VFCMP_D(v0, q0, q1, cUN);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
VFCMP_D(v0, q1, q0, cUN);
|
||||
VFCMP_D(d0, q1, q1, cUN);
|
||||
VLDI(d1, (0b011 << 10) | 0b0000001000);
|
||||
VSLLI_D(d1, d1, 48);
|
||||
VOR_V(d1, q1, d1);
|
||||
}
|
||||
VFADD_D(q1, q1, q0);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
VBITSEL_V(q1, q1, d1, d0);
|
||||
VFCMP_D(v1, q1, q1, cUN);
|
||||
VANDN_V(v0, v0, v1);
|
||||
VLDI(v1, 0b011111111000); // broadcast 0xFFFFFFFFFFFFFFF8
|
||||
VLDI(v1, (0b011 << 10) | 0b1111111000);
|
||||
VSLLI_D(v1, v1, 48);
|
||||
VAND_V(v1, v0, v1);
|
||||
VANDN_V(v0, v0, q1);
|
||||
VOR_V(q1, v0, v1);
|
||||
VBITSEL_V(q1, q1, v1, v0);
|
||||
}
|
||||
break;
|
||||
case 0x59:
|
||||
@@ -1527,17 +1567,22 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
VFCMP_D(v0, q0, q1, cUN);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
VFCMP_D(v0, q1, q0, cUN);
|
||||
VFCMP_D(d0, q1, q1, cUN);
|
||||
VLDI(d1, (0b011 << 10) | 0b0000001000);
|
||||
VSLLI_D(d1, d1, 48);
|
||||
VOR_V(d1, q1, d1);
|
||||
}
|
||||
VFMUL_D(q1, q1, q0);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
VBITSEL_V(q1, q1, d1, d0);
|
||||
VFCMP_D(v1, q1, q1, cUN);
|
||||
VANDN_V(v0, v0, v1);
|
||||
VLDI(v1, 0b011111111000); // broadcast 0xFFFFFFFFFFFFFFF8
|
||||
VLDI(v1, (0b011 << 10) | 0b1111111000);
|
||||
VSLLI_D(v1, v1, 48);
|
||||
VAND_V(v1, v0, v1);
|
||||
VANDN_V(v0, v0, q1);
|
||||
VOR_V(q1, v0, v1);
|
||||
VBITSEL_V(q1, q1, v1, v0);
|
||||
}
|
||||
break;
|
||||
case 0x5A:
|
||||
@@ -1586,17 +1631,22 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
VFCMP_D(v0, q0, q1, cUN);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
VFCMP_D(v0, q1, q0, cUN);
|
||||
VFCMP_D(d0, q1, q1, cUN);
|
||||
VLDI(d1, (0b011 << 10) | 0b0000001000);
|
||||
VSLLI_D(d1, d1, 48);
|
||||
VOR_V(d1, q1, d1);
|
||||
}
|
||||
VFSUB_D(q1, q1, q0);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
VBITSEL_V(q1, q1, d1, d0);
|
||||
VFCMP_D(v1, q1, q1, cUN);
|
||||
VANDN_V(v0, v0, v1);
|
||||
VLDI(v1, 0b011111111000); // broadcast 0xFFFFFFFFFFFFFFF8
|
||||
VLDI(v1, (0b011 << 10) | 0b1111111000);
|
||||
VSLLI_D(v1, v1, 48);
|
||||
VAND_V(v1, v0, v1);
|
||||
VANDN_V(v0, v0, q1);
|
||||
VOR_V(q1, v0, v1);
|
||||
VBITSEL_V(q1, q1, v1, v0);
|
||||
}
|
||||
break;
|
||||
case 0x5D:
|
||||
@@ -1607,13 +1657,9 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
// LoongArch FMIN/FMAX follow IEEE 754-2008 , it wll copy the none NaN value.
|
||||
// If both NaN, then copy NaN.
|
||||
// but x86 will copy the second if either v0[x] or v1[x] is NaN
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
VFCMP_D(q0, v1, v0, cULE);
|
||||
VBITSEL_V(v0, v0, v1, q0);
|
||||
} else {
|
||||
VFMIN_D(v0, v0, v1);
|
||||
}
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
VFCMP_D(q0, v1, v0, cULE);
|
||||
VBITSEL_V(v0, v0, v1, q0);
|
||||
break;
|
||||
case 0x5E:
|
||||
INST_NAME("DIVPD Gx, Ex");
|
||||
@@ -1623,17 +1669,22 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
VFCMP_D(v0, q0, q1, cUN);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
VFCMP_D(v0, q1, q0, cUN);
|
||||
VFCMP_D(d0, q1, q1, cUN);
|
||||
VLDI(d1, (0b011 << 10) | 0b0000001000);
|
||||
VSLLI_D(d1, d1, 48);
|
||||
VOR_V(d1, q1, d1);
|
||||
}
|
||||
VFDIV_D(q1, q1, q0);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
VBITSEL_V(q1, q1, d1, d0);
|
||||
VFCMP_D(v1, q1, q1, cUN);
|
||||
VANDN_V(v0, v0, v1);
|
||||
VLDI(v1, 0b011111111000); // broadcast 0xFFFFFFFFFFFFFFF8
|
||||
VLDI(v1, (0b011 << 10) | 0b1111111000);
|
||||
VSLLI_D(v1, v1, 48);
|
||||
VAND_V(v1, v0, v1);
|
||||
VANDN_V(v0, v0, q1);
|
||||
VOR_V(q1, v0, v1);
|
||||
VBITSEL_V(q1, q1, v1, v0);
|
||||
}
|
||||
break;
|
||||
case 0x5F:
|
||||
@@ -1644,14 +1695,10 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
// LoongArch FMIN/FMAX follow IEEE 754-2008 , it wll copy the none NaN value.
|
||||
// If both NaN, then copy NaN.
|
||||
// but x86 will copy the second if either v0[x] or v1[x] is NaN
|
||||
if (!BOX64ENV(dynarec_fastnan) && v0 != v1) {
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
VFCMP_D(q0, v1, v0, cLT); // ~cLT = un ge eq, if either v0/v1=nan ,choose v1. if eq either is ok,but when +0.0 == -0.0 x86 sse choose v1
|
||||
VBITSEL_V(v0, v1, v0, q0); // swap v0 v1 => v1 v0 for ~cLT
|
||||
} else {
|
||||
VFMAX_D(v0, v0, v1);
|
||||
}
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
VFCMP_D(q0, v1, v0, cLT); // ~cLT = un ge eq, if either v0/v1=nan ,choose v1. if eq either is ok,but when +0.0 == -0.0 x86 sse choose v1
|
||||
VBITSEL_V(v0, v1, v0, q0); // swap v0 v1 => v1 v0 for ~cLT
|
||||
break;
|
||||
|
||||
case 0x60:
|
||||
@@ -1957,7 +2004,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
u8 = F8;
|
||||
if (u8) {
|
||||
if (u8 > 63) {
|
||||
XVOR_V(q0, q0, q0);
|
||||
VXOR_V(q0, q0, q0);
|
||||
} else {
|
||||
VSLLI_D(q0, q0, u8);
|
||||
}
|
||||
@@ -2017,13 +2064,17 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
}
|
||||
VFADD_D(q1, d0, q1);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
VFCMP_D(d1, d0, d0, cUN);
|
||||
VLDI(v1, (0b011 << 10) | 0b0000001000);
|
||||
VSLLI_D(v1, v1, 48);
|
||||
VOR_V(d0, d0, v1);
|
||||
VBITSEL_V(q1, q1, d0, d1);
|
||||
VFCMP_D(v1, q1, q1, cUN);
|
||||
VANDN_V(v0, v0, v1);
|
||||
VLDI(v1, 0b011111111000); // broadcast 0xFFFFFFFFFFFFFFF8
|
||||
VLDI(v1, (0b011 << 10) | 0b1111111000);
|
||||
VSLLI_D(v1, v1, 48);
|
||||
VAND_V(v1, v0, v1);
|
||||
VANDN_V(v0, v0, q1);
|
||||
VOR_V(q1, v0, v1);
|
||||
VBITSEL_V(q1, q1, v1, v0);
|
||||
}
|
||||
break;
|
||||
case 0x7D:
|
||||
@@ -2041,13 +2092,17 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
}
|
||||
VFSUB_D(q1, d0, q1);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
VFCMP_D(d1, d0, d0, cUN);
|
||||
VLDI(v1, (0b011 << 10) | 0b0000001000);
|
||||
VSLLI_D(v1, v1, 48);
|
||||
VOR_V(d0, d0, v1);
|
||||
VBITSEL_V(q1, q1, d0, d1);
|
||||
VFCMP_D(v1, q1, q1, cUN);
|
||||
VANDN_V(v0, v0, v1);
|
||||
VLDI(v1, 0b011111111000); // broadcast 0xFFFFFFFFFFFFFFF8
|
||||
VLDI(v1, (0b011 << 10) | 0b1111111000);
|
||||
VSLLI_D(v1, v1, 48);
|
||||
VAND_V(v1, v0, v1);
|
||||
VANDN_V(v0, v0, q1);
|
||||
VOR_V(q1, v0, v1);
|
||||
VBITSEL_V(q1, q1, v1, v0);
|
||||
}
|
||||
break;
|
||||
case 0x7E:
|
||||
@@ -2124,8 +2179,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop) & 0x1f;
|
||||
if (u8) {
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETEW(x1, 1);
|
||||
GETGW(x2);
|
||||
GETGWEW(x1, x2, 1);
|
||||
u8 = F8;
|
||||
emit_shld16c(dyn, ninst, rex, ed, gd, u8, x6, x4, x5);
|
||||
EWBACK;
|
||||
@@ -2142,10 +2196,9 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_FUSION);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
GETGWEW(x1, x2, 0);
|
||||
ANDI(x4, xRCX, 0x1f);
|
||||
UFLAG_IF { BEQ_NEXT(x4, xZR); }
|
||||
UFLAG_IF { CBZ_NEXT(x4); }
|
||||
emit_shld16(dyn, ninst, ed, gd, x4, x5, x6, x7);
|
||||
EWBACK;
|
||||
break;
|
||||
@@ -2194,8 +2247,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop) & 0x1f;
|
||||
if (u8) {
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETEW(x1, 1);
|
||||
GETGW(x2);
|
||||
GETGWEW(x1, x2, 1);
|
||||
u8 = F8;
|
||||
emit_shrd16c(dyn, ninst, rex, ed, gd, u8, x6, x4, x5);
|
||||
EWBACK;
|
||||
@@ -2212,10 +2264,9 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_FUSION);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
GETGWEW(x1, x2, 0);
|
||||
ANDI(x4, xRCX, 0x1f);
|
||||
UFLAG_IF { BEQ_NEXT(x4, xZR); }
|
||||
UFLAG_IF { CBZ_NEXT(x4); }
|
||||
emit_shrd16(dyn, ninst, ed, gd, x4, x5, x6, x7);
|
||||
EWBACK;
|
||||
break;
|
||||
@@ -2244,16 +2295,29 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
}
|
||||
break;
|
||||
case 0xAF:
|
||||
INST_NAME("IMUL Gw,Ew");
|
||||
SETFLAGS(X_ALL, SF_PENDING, NAT_FLAGS_NOFUSION);
|
||||
INST_NAME("IMUL Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION);
|
||||
nextop = F8;
|
||||
GETSEW(x1, 0);
|
||||
GETSGW(x2);
|
||||
MUL_W(x2, x2, x1);
|
||||
UFLAG_RES(x2);
|
||||
BSTRPICK_D(x2, x2, 15, 0);
|
||||
GWBACK;
|
||||
UFLAG_DF(x1, d_imul16);
|
||||
SET_DFNONE();
|
||||
CLEAR_FLAGS(x3);
|
||||
IFX (X_CF | X_OF) {
|
||||
SRAI_W(x1, x2, 15);
|
||||
SRAI_W(x3, x2, 31);
|
||||
XOR(x3, x3, x1);
|
||||
SNEZ(x3, x3);
|
||||
IFX (X_CF) BSTRINS_D(xFlags, x3, F_CF, F_CF);
|
||||
IFX (X_OF) BSTRINS_D(xFlags, x3, F_OF, F_OF);
|
||||
}
|
||||
IFX (X_SF) {
|
||||
SRLI_D(x3, gd, 15);
|
||||
BSTRINS_D(xFlags, x3, F_SF, F_SF);
|
||||
}
|
||||
IFX (X_PF) emit_pf(dyn, ninst, gd, x3, x4);
|
||||
IFXA (X_ALL, cpuext.lbt) SPILL_EFLAGS();
|
||||
break;
|
||||
case 0xB3:
|
||||
INST_NAME("BTR Ew, Gw");
|
||||
@@ -2351,16 +2415,17 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
u8 = F8;
|
||||
u8 &= (rex.w ? 0x3f : 0x0f);
|
||||
if (cpuext.lbt) {
|
||||
SRLI_D(x3, ed, u8);
|
||||
X64_SET_EFLAGS(x3, X_CF);
|
||||
SRLI_D(x5, ed, u8);
|
||||
X64_SET_EFLAGS(x5, X_CF);
|
||||
} else {
|
||||
BSTRINS_D(xFlags, ed, u8, u8);
|
||||
BSTRPICK_D(x5, ed, u8, u8);
|
||||
BSTRINS_D(xFlags, x5, F_CF, F_CF);
|
||||
}
|
||||
if (u8 <= 11) {
|
||||
ORI(ed, ed, (1LL << u8));
|
||||
} else {
|
||||
ADDI_D(x3, xZR, -1);
|
||||
BSTRINS_D(ed, x3, u8, u8);
|
||||
ADDI_D(x5, xZR, -1);
|
||||
BSTRINS_D(ed, x5, u8, u8);
|
||||
}
|
||||
EWBACK;
|
||||
break;
|
||||
@@ -2376,10 +2441,11 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
u8 = F8;
|
||||
u8 &= (rex.w ? 0x3f : 0x0f);
|
||||
if (cpuext.lbt) {
|
||||
SRLI_D(x3, ed, u8);
|
||||
X64_SET_EFLAGS(x3, X_CF);
|
||||
SRLI_D(x5, ed, u8);
|
||||
X64_SET_EFLAGS(x5, X_CF);
|
||||
} else {
|
||||
BSTRINS_D(xFlags, ed, u8, u8);
|
||||
BSTRPICK_D(x5, ed, u8, u8);
|
||||
BSTRINS_D(xFlags, x5, F_CF, F_CF);
|
||||
}
|
||||
BSTRINS_D(ed, xZR, u8, u8);
|
||||
EWBACK;
|
||||
@@ -2396,10 +2462,11 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
u8 = F8;
|
||||
u8 &= (rex.w ? 0x3f : 0x0f);
|
||||
if (cpuext.lbt) {
|
||||
SRLI_D(x3, ed, u8);
|
||||
X64_SET_EFLAGS(x3, X_CF);
|
||||
SRLI_D(x5, ed, u8);
|
||||
X64_SET_EFLAGS(x5, X_CF);
|
||||
} else {
|
||||
BSTRINS_D(xFlags, ed, u8, u8);
|
||||
BSTRPICK_D(x5, ed, u8, u8);
|
||||
BSTRINS_D(xFlags, x5, F_CF, F_CF);
|
||||
}
|
||||
if (u8 <= 11) {
|
||||
XORI(ed, ed, (1LL << u8));
|
||||
@@ -2461,20 +2528,22 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
SETFLAGS(X_ZF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETEW(x5, 0);
|
||||
GETGW(x4);
|
||||
GETGWEW(x4, x5, 0);
|
||||
BNE_MARK(ed, xZR);
|
||||
IFX (X_ZF) ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
if (BOX64DRENV(dynarec_safeflags)) {
|
||||
IFX (X_PF) ORI(xFlags, xFlags, 1 << F_PF);
|
||||
}
|
||||
B_MARK2_nocond;
|
||||
MARK;
|
||||
IFXA (X_ZF, !BOX64DRENV(dynarec_safeflags))
|
||||
BSTRINS_D(xFlags, xZR, F_ZF, F_ZF);
|
||||
CTZ_D(gd, ed);
|
||||
GWBACK;
|
||||
MARK2;
|
||||
if (BOX64DRENV(dynarec_safeflags)) {
|
||||
IFX (X_PF) emit_pf(dyn, ninst, gd, x1, x2);
|
||||
}
|
||||
MARK2;
|
||||
IFX (X_ALL) SPILL_EFLAGS();
|
||||
break;
|
||||
case 0xBD:
|
||||
@@ -2486,10 +2555,12 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
SETFLAGS(X_ZF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETEW(x5, 0);
|
||||
GETGW(x4);
|
||||
GETGWEW(x4, x5, 0);
|
||||
BNE_MARK(ed, xZR);
|
||||
IFX (X_ZF) ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
if (BOX64DRENV(dynarec_safeflags)) {
|
||||
IFX (X_PF) ORI(xFlags, xFlags, 1 << F_PF);
|
||||
}
|
||||
B_MARK2_nocond;
|
||||
MARK;
|
||||
IFXA (X_ZF, !BOX64DRENV(dynarec_safeflags))
|
||||
@@ -2498,10 +2569,10 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
ADDI_D(x1, xZR, 63);
|
||||
SUB_D(gd, x1, gd);
|
||||
GWBACK;
|
||||
MARK2;
|
||||
if (BOX64DRENV(dynarec_safeflags)) {
|
||||
IFX (X_PF) emit_pf(dyn, ninst, gd, x1, x2);
|
||||
}
|
||||
MARK2;
|
||||
IFX (X_ALL) SPILL_EFLAGS();
|
||||
break;
|
||||
case 0xBE:
|
||||
@@ -2531,12 +2602,26 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
}
|
||||
BSTRINS_D(gd, x1, 15, 0);
|
||||
break;
|
||||
case 0xBF:
|
||||
if (rex.w) return dynarec64_00(dyn, addr - 1, ip, ninst, rex, ok, need_epilog);
|
||||
INST_NAME("MOVSX Gw, Ew");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x4, &fixedaddress, rex, NULL, 1, 0);
|
||||
LD_H(x1, wback, fixedaddress);
|
||||
ed = x1;
|
||||
}
|
||||
BSTRINS_D(gd, ed, 15, 0);
|
||||
break;
|
||||
case 0xC1:
|
||||
INST_NAME("XADD Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
GETGWEW(x1, x2, 0);
|
||||
BSTRINS_D(TO_NAT(((nextop & 0x38) >> 3) + (rex.r << 3)), ed, 15, 0);
|
||||
emit_add16(dyn, ninst, ed, gd, x4, x5, x6);
|
||||
EWBACK;
|
||||
@@ -2608,7 +2693,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
case 0xCF:
|
||||
INST_NAME("BSWAP Reg");
|
||||
gd = TO_NAT((opcode & 7) + (rex.b << 3));
|
||||
if(rex.w){
|
||||
if (rex.w) {
|
||||
REVB_D(gd, gd);
|
||||
} else {
|
||||
// undefined behaviour
|
||||
@@ -2620,10 +2705,28 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
d2 = fpu_get_scratch(dyn);
|
||||
VFCMP_D(d0, q0, q1, cUN);
|
||||
VFCMP_D(d1, q0, q0, cUN);
|
||||
VLDI(d2, (0b011 << 10) | 0b0000001000);
|
||||
VSLLI_D(d2, d2, 48);
|
||||
VOR_V(d2, q0, d2);
|
||||
}
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
VFSUB_D(v0, q0, q1);
|
||||
VFADD_D(q0, q0, q1);
|
||||
VEXTRINS_D(q0, v0, 0);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
VBITSEL_V(q0, q0, d2, d1);
|
||||
VFCMP_D(d2, q0, q0, cUN);
|
||||
VANDN_V(d0, d0, d2);
|
||||
VLDI(d2, (0b011 << 10) | 0b1111111000);
|
||||
VSLLI_D(d2, d2, 48);
|
||||
VBITSEL_V(q0, q0, d2, d0);
|
||||
}
|
||||
break;
|
||||
case 0xD1:
|
||||
INST_NAME("PSRLW Gx, Ex");
|
||||
|
||||
@@ -381,7 +381,7 @@ uintptr_t dynarec64_66F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
}
|
||||
IFXORNAT (X_ALL | X_PEND) {
|
||||
BSTRPICK_D(x6, x1, 15, 0);
|
||||
emit_add16(dyn, ninst, x6, gd, x3, x4, x5);
|
||||
emit_add16(dyn, ninst, x6, x5, x3, x4, x7);
|
||||
}
|
||||
BSTRINS_D(gd, x1, 15, 0);
|
||||
}
|
||||
@@ -497,7 +497,7 @@ uintptr_t dynarec64_66F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
IFXORNAT (X_ALL | X_PEND) {
|
||||
if (!cpuext.lam_bh) ADDI_D(x5, xZR, 1);
|
||||
BSTRPICK_D(x6, x1, 15, 0);
|
||||
emit_add16(dyn, ninst, x6, x5, x3, x4, x7);
|
||||
emit_inc16(dyn, ninst, x6, x5, x3, x4);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -543,7 +543,7 @@ uintptr_t dynarec64_66F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
IFXORNAT (X_ALL | X_PEND) {
|
||||
if (!cpuext.lam_bh) ADDI_D(x5, xZR, -1);
|
||||
BSTRPICK_D(x6, x1, 15, 0);
|
||||
emit_add16(dyn, ninst, x6, x5, x3, x4, x7);
|
||||
emit_dec16(dyn, ninst, x6, x5, x3, x4, x7);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -52,6 +52,7 @@ uintptr_t dynarec64_66F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, in
|
||||
opcode = F8;
|
||||
switch (opcode) {
|
||||
case 0xF1:
|
||||
if (rex.w) return dynarec64_F20F(dyn, addr - 2, ip, ninst, rex, ok, need_epilog);
|
||||
INST_NAME("CRC32 Gd, Ew");
|
||||
nextop = F8;
|
||||
GETEW(x1, 0);
|
||||
|
||||
@@ -60,64 +60,63 @@ uintptr_t dynarec64_66F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, in
|
||||
VPICKVE2GR_HU(x2, v0, 0);
|
||||
BSTRINS_D(gd, x2, 15, 0);
|
||||
IFX (X_ALL) {
|
||||
if (cpuext.lbt) {
|
||||
X64_SET_EFLAGS(xZR, X_ALL);
|
||||
BNEZ_MARK(x2);
|
||||
ADDI_D(x5, xZR, 1 << F_ZF);
|
||||
X64_SET_EFLAGS(x5, X_ZF);
|
||||
} else {
|
||||
CLEAR_FLAGS(x5);
|
||||
BNEZ_MARK(x2);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
CLEAR_FLAGS(x5);
|
||||
BNEZ_MARK(x2);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
MARK;
|
||||
SPILL_EFLAGS();
|
||||
}
|
||||
break;
|
||||
case 0xBC:
|
||||
INST_NAME("TZCNT Gw, Ew");
|
||||
SETFLAGS(X_ZF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
if (!BOX64DRENV(dynarec_safeflags)) {
|
||||
SETFLAGS(X_CF | X_ZF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
|
||||
}
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETEW(x5, 0);
|
||||
GETGD;
|
||||
RESTORE_EFLAGS(x1);
|
||||
/*
|
||||
ZF is set if gd is zero, unset non-zero.
|
||||
CF is set if ed is zero, unset non-zero.
|
||||
OF, SF, PF, and AF flags are undefined
|
||||
*/
|
||||
GETEW(x1, 0);
|
||||
GETGW(x2);
|
||||
CLEAR_FLAGS(x2);
|
||||
IFX (X_CF) {
|
||||
SEQZ(x3, ed);
|
||||
BSTRINS_D(xFlags, x3, F_CF, F_CF);
|
||||
}
|
||||
ADDI_D(x4, xZR, -1);
|
||||
BSTRINS_D(x4, ed, 15, 0);
|
||||
CTZ_W(gd, x4);
|
||||
BNE(gd, xZR, 4 + 4);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
SRLI_W(x5, gd, 4); // maximum value is 16, F_CF = 0
|
||||
OR(xFlags, xFlags, x5);
|
||||
IFX (X_ZF) {
|
||||
SEQZ(x3, gd);
|
||||
BSTRINS_D(xFlags, x3, F_ZF, F_ZF);
|
||||
}
|
||||
SPILL_EFLAGS();
|
||||
GWBACK;
|
||||
break;
|
||||
case 0xBD:
|
||||
INST_NAME("LZCNT Gw, Ew");
|
||||
SETFLAGS(X_ZF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
if (!BOX64DRENV(dynarec_safeflags)) {
|
||||
SETFLAGS(X_CF | X_ZF, SF_SUBSET, NAT_FLAGS_NOFUSION);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
|
||||
}
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETEW(x5, 0);
|
||||
GETGD;
|
||||
RESTORE_EFLAGS(x1);
|
||||
/*
|
||||
ZF is set if gd is zero, unset non-zero.
|
||||
CF is set if ed is zero, unset non-zero.
|
||||
OF, SF, PF, and AF flags are undefined
|
||||
*/
|
||||
GETEW(x1, 0);
|
||||
GETGW(x2);
|
||||
CLEAR_FLAGS(x2);
|
||||
ADDI_D(x4, xZR, -1);
|
||||
BSTRINS_D(x4, ed, 31, 16);
|
||||
CLZ_W(gd, x4);
|
||||
BNE(gd, xZR, 4 + 4);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
SRLI_W(x5, gd, 4); // maximum value is 16, F_CF = 0
|
||||
OR(xFlags, xFlags, x5);
|
||||
IFX (X_CF) {
|
||||
SEQZ(x3, ed);
|
||||
BSTRINS_D(xFlags, x3, F_CF, F_CF);
|
||||
}
|
||||
CLZ_W(gd, ed);
|
||||
ADDI_D(gd, gd, -16);
|
||||
IFX (X_ZF) {
|
||||
SEQZ(x3, gd);
|
||||
BSTRINS_D(xFlags, x3, F_ZF, F_ZF);
|
||||
}
|
||||
SPILL_EFLAGS();
|
||||
GWBACK;
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
|
||||
@@ -48,8 +48,9 @@ uintptr_t dynarec64_AVX(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
uint8_t opcode = PK(0);
|
||||
rex_t rex = vex.rex;
|
||||
|
||||
|
||||
if ((vex.m == VEX_M_0F) && (vex.p == VEX_P_NONE))
|
||||
if (!cpuext.lasx) {
|
||||
DEFAULT;
|
||||
} else if ((vex.m == VEX_M_0F) && (vex.p == VEX_P_NONE))
|
||||
addr = dynarec64_AVX_0F(dyn, addr, ip, ninst, vex, ok, need_epilog);
|
||||
else if ((vex.m == VEX_M_0F38) && (vex.p == VEX_P_NONE))
|
||||
addr = dynarec64_AVX_0F38(dyn, addr, ip, ninst, vex, ok, need_epilog);
|
||||
|
||||
@@ -354,14 +354,21 @@ uintptr_t dynarec64_AVX_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, in
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
VFCMPxy(S, d0, v1, v2, cUN);
|
||||
VFCMPxy(S, q0, v1, v1, cUN);
|
||||
VLDIxy(q1, (0b010 << 9) | 0b0000000100);
|
||||
VSLLIxy(W, q1, q1, 20);
|
||||
VOR_Vxy(q1, v1, q1);
|
||||
}
|
||||
VFADDxy(S, v0, v1, v2);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
VBITSEL_Vxy(v0, v0, q1, q0);
|
||||
VFCMPxy(S, d1, v0, v0, cUN);
|
||||
VANDN_Vxy(d0, d0, d1);
|
||||
VLDIxy(d1, (0b010 << 9) | 0b1111111100);
|
||||
VSLLIxy(W, d1, d1, 20); // broadcast 0xFFC00000
|
||||
VSLLIxy(W, d1, d1, 20);
|
||||
VBITSEL_Vxy(v0, v0, d1, d0);
|
||||
}
|
||||
break;
|
||||
@@ -372,14 +379,21 @@ uintptr_t dynarec64_AVX_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, in
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
VFCMPxy(S, d0, v1, v2, cUN);
|
||||
VFCMPxy(S, q0, v1, v1, cUN);
|
||||
VLDIxy(q1, (0b010 << 9) | 0b0000000100);
|
||||
VSLLIxy(W, q1, q1, 20);
|
||||
VOR_Vxy(q1, v1, q1);
|
||||
}
|
||||
VFMULxy(S, v0, v1, v2);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
VBITSEL_Vxy(v0, v0, q1, q0);
|
||||
VFCMPxy(S, d1, v0, v0, cUN);
|
||||
VANDN_Vxy(d0, d0, d1);
|
||||
VLDIxy(d1, (0b010 << 9) | 0b1111111100);
|
||||
VSLLIxy(W, d1, d1, 20); // broadcast 0xFFC00000
|
||||
VSLLIxy(W, d1, d1, 20);
|
||||
VBITSEL_Vxy(v0, v0, d1, d0);
|
||||
}
|
||||
break;
|
||||
@@ -425,14 +439,21 @@ uintptr_t dynarec64_AVX_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, in
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
VFCMPxy(S, d0, v1, v2, cUN);
|
||||
VFCMPxy(S, q0, v1, v1, cUN);
|
||||
VLDIxy(q1, (0b010 << 9) | 0b0000000100);
|
||||
VSLLIxy(W, q1, q1, 20);
|
||||
VOR_Vxy(q1, v1, q1);
|
||||
}
|
||||
VFSUBxy(S, v0, v1, v2);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
VBITSEL_Vxy(v0, v0, q1, q0);
|
||||
VFCMPxy(S, d1, v0, v0, cUN);
|
||||
VANDN_Vxy(d0, d0, d1);
|
||||
VLDIxy(d1, (0b010 << 9) | 0b1111111100);
|
||||
VSLLIxy(W, d1, d1, 20); // broadcast 0xFFC00000
|
||||
VSLLIxy(W, d1, d1, 20);
|
||||
VBITSEL_Vxy(v0, v0, d1, d0);
|
||||
}
|
||||
break;
|
||||
@@ -440,14 +461,10 @@ uintptr_t dynarec64_AVX_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, in
|
||||
INST_NAME("VMINPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
|
||||
if (BOX64ENV(dynarec_fastnan)) {
|
||||
VFMINxy(S, v0, v2, v1);
|
||||
} else {
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
VFCMPxy(S, q0, v2, v1, cULE);
|
||||
VBITSEL_Vxy(v0, v1, v2, q0);
|
||||
}
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
VFCMPxy(S, q0, v2, v1, cULE);
|
||||
VBITSEL_Vxy(v0, v1, v2, q0);
|
||||
break;
|
||||
case 0x5E:
|
||||
INST_NAME("VDIVPS Gx, Vx, Ex");
|
||||
@@ -456,14 +473,21 @@ uintptr_t dynarec64_AVX_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, in
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
VFCMPxy(S, d0, v1, v2, cUN);
|
||||
VFCMPxy(S, q0, v1, v1, cUN);
|
||||
VLDIxy(q1, (0b010 << 9) | 0b0000000100);
|
||||
VSLLIxy(W, q1, q1, 20);
|
||||
VOR_Vxy(q1, v1, q1);
|
||||
}
|
||||
VFDIVxy(S, v0, v1, v2);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
VBITSEL_Vxy(v0, v0, q1, q0);
|
||||
VFCMPxy(S, d1, v0, v0, cUN);
|
||||
VANDN_Vxy(d0, d0, d1);
|
||||
VLDIxy(d1, (0b010 << 9) | 0b1111111100);
|
||||
VSLLIxy(W, d1, d1, 20); // broadcast 0xFFC00000
|
||||
VSLLIxy(W, d1, d1, 20);
|
||||
VBITSEL_Vxy(v0, v0, d1, d0);
|
||||
}
|
||||
break;
|
||||
@@ -471,14 +495,10 @@ uintptr_t dynarec64_AVX_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, in
|
||||
INST_NAME("VMAXPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
|
||||
if (BOX64ENV(dynarec_fastnan)) {
|
||||
VFMAXxy(S, v0, v2, v1);
|
||||
} else {
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
VFCMPxy(S, q0, v2, v1, cLT);
|
||||
VBITSEL_Vxy(v0, v2, v1, q0);
|
||||
}
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
VFCMPxy(S, q0, v2, v1, cLT);
|
||||
VBITSEL_Vxy(v0, v2, v1, q0);
|
||||
break;
|
||||
case 0x77:
|
||||
if (!vex.l) {
|
||||
@@ -490,18 +510,9 @@ uintptr_t dynarec64_AVX_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, in
|
||||
XVXOR_V(q2, q2, q2);
|
||||
for (int i = 0; i < (rex.is32bits ? 8 : 16); ++i) {
|
||||
if (dyn->lsx.avxcache[i].v != -1) {
|
||||
// avx used register
|
||||
if (dyn->lsx.avxcache[i].width == LSX_AVX_WIDTH_256) {
|
||||
// 256 width, fill upper 128bits with zero.
|
||||
q1 = avx_get_reg(dyn, ninst, x1, i, 1, LSX_AVX_WIDTH_256); // mark reg write (dirty)
|
||||
XVPERMI_Q(q1, q2, XVPERMI_IMM_4_0(0, 2));
|
||||
} else {
|
||||
// 128 width, lazy save.
|
||||
q1 = avx_get_reg(dyn, ninst, x1, i, 1, LSX_AVX_WIDTH_128); // mark reg write (dirty)
|
||||
dyn->lsx.avxcache[i].zero_upper = 1;
|
||||
}
|
||||
q1 = avx_get_reg(dyn, ninst, x1, i, 1, LSX_AVX_WIDTH_256);
|
||||
XVPERMI_Q(q1, q2, XVPERMI_IMM_4_0(0, 2));
|
||||
} else {
|
||||
// SSE register or unused register, store 128bit zero to x64emu_t.ymm[]
|
||||
VST(q2, xEmu, offsetof(x64emu_t, ymm[i]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,6 +78,9 @@ uintptr_t dynarec64_AVX_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
BNEZ(gd, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
if (BOX64DRENV(dynarec_safeflags)) {
|
||||
IFX (X_PF) emit_pf(dyn, ninst, gd, x2, x5);
|
||||
}
|
||||
SPILL_EFLAGS();
|
||||
break;
|
||||
case 0xF3:
|
||||
@@ -199,7 +202,7 @@ uintptr_t dynarec64_AVX_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
break;
|
||||
|
||||
case 0xF7:
|
||||
INST_NAME("BEXTR Gd, Vd, Ed");
|
||||
INST_NAME("BEXTR Gd, Ed, Vd");
|
||||
nextop = F8;
|
||||
SETFLAGS(X_ALL, SF_SET, NAT_FLAGS_NOFUSION);
|
||||
GETGD;
|
||||
|
||||
@@ -327,14 +327,21 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
VFCMPxy(D, d0, v1, v2, cUN);
|
||||
VFCMPxy(D, q0, v1, v1, cUN);
|
||||
VLDIxy(q1, (0b011 << 10) | 0b0000001000);
|
||||
VSLLIxy(D, q1, q1, 48);
|
||||
VOR_Vxy(q1, v1, q1);
|
||||
}
|
||||
VFADDxy(D, v0, v1, v2);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
VBITSEL_Vxy(v0, v0, q1, q0);
|
||||
VFCMPxy(D, d1, v0, v0, cUN);
|
||||
VANDN_Vxy(d0, d0, d1);
|
||||
VLDIxy(d1, (0b011 << 9) | 0b111111000);
|
||||
VSLLIxy(D, d1, d1, 48); // broadcast 0xfff8000000000000
|
||||
VLDIxy(d1, (0b011 << 10) | 0b1111111000);
|
||||
VSLLIxy(D, d1, d1, 48);
|
||||
VBITSEL_Vxy(v0, v0, d1, d0);
|
||||
}
|
||||
break;
|
||||
@@ -345,14 +352,21 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
VFCMPxy(D, d0, v1, v2, cUN);
|
||||
VFCMPxy(D, q0, v1, v1, cUN);
|
||||
VLDIxy(q1, (0b011 << 10) | 0b0000001000);
|
||||
VSLLIxy(D, q1, q1, 48);
|
||||
VOR_Vxy(q1, v1, q1);
|
||||
}
|
||||
VFMULxy(D, v0, v1, v2);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
VBITSEL_Vxy(v0, v0, q1, q0);
|
||||
VFCMPxy(D, d1, v0, v0, cUN);
|
||||
VANDN_Vxy(d0, d0, d1);
|
||||
VLDIxy(d1, (0b011 << 9) | 0b111111000);
|
||||
VSLLIxy(D, d1, d1, 48); // broadcast 0xfff8000000000000
|
||||
VLDIxy(d1, (0b011 << 10) | 0b1111111000);
|
||||
VSLLIxy(D, d1, d1, 48);
|
||||
VBITSEL_Vxy(v0, v0, d1, d0);
|
||||
}
|
||||
break;
|
||||
@@ -361,20 +375,19 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
nextop = F8;
|
||||
GETEYxy(v1, 0, 0);
|
||||
GETGYx_empty(v0);
|
||||
if(!BOX64ENV(dynarec_fastround)) {
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
u8 = sse_setround(dyn, ninst, x6, x4);
|
||||
}
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
if(vex.l) {
|
||||
if (vex.l) {
|
||||
XVXOR_V(d0, d0, d0);
|
||||
XVFCVT_S_D(v0, d0, v1);
|
||||
XVPERMI_D(v0, v0, 0b11011000);
|
||||
} else {
|
||||
VFCVT_S_D(d0, v1, v1);
|
||||
XVPICKVE_D(v0, d0, 0);
|
||||
YMM_UNMARK_UPPER_ZERO(v0);
|
||||
}
|
||||
if(!BOX64ENV(dynarec_fastround)) {
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
}
|
||||
break;
|
||||
@@ -383,7 +396,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
nextop = F8;
|
||||
GETGY_empty_EY_xy(v0, v1, 0);
|
||||
u8 = sse_setround(dyn, ninst, x6, x4);
|
||||
if(vex.l){
|
||||
if (vex.l) {
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
@@ -421,14 +434,21 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
VFCMPxy(D, d0, v1, v2, cUN);
|
||||
VFCMPxy(D, q0, v1, v1, cUN);
|
||||
VLDIxy(q1, (0b011 << 10) | 0b0000001000);
|
||||
VSLLIxy(D, q1, q1, 48);
|
||||
VOR_Vxy(q1, v1, q1);
|
||||
}
|
||||
VFSUBxy(D, v0, v1, v2);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
VBITSEL_Vxy(v0, v0, q1, q0);
|
||||
VFCMPxy(D, d1, v0, v0, cUN);
|
||||
VANDN_Vxy(d0, d0, d1);
|
||||
VLDIxy(d1, (0b011 << 9) | 0b111111000);
|
||||
VSLLIxy(D, d1, d1, 48); // broadcast 0xfff8000000000000
|
||||
VLDIxy(d1, (0b011 << 10) | 0b1111111000);
|
||||
VSLLIxy(D, d1, d1, 48);
|
||||
VBITSEL_Vxy(v0, v0, d1, d0);
|
||||
}
|
||||
break;
|
||||
@@ -436,14 +456,10 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
INST_NAME("VMINPD Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
|
||||
if (BOX64ENV(dynarec_fastnan)) {
|
||||
VFMINxy(D, v0, v2, v1);
|
||||
} else {
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
VFCMPxy(D, q0, v2, v1, cULE);
|
||||
VBITSEL_Vxy(v0, v1, v2, q0);
|
||||
}
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
VFCMPxy(D, q0, v2, v1, cULE);
|
||||
VBITSEL_Vxy(v0, v1, v2, q0);
|
||||
break;
|
||||
case 0x5E:
|
||||
INST_NAME("VDIVPD Gx, Vx, Ex");
|
||||
@@ -452,14 +468,21 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
VFCMPxy(D, d0, v1, v2, cUN);
|
||||
VFCMPxy(D, q0, v1, v1, cUN);
|
||||
VLDIxy(q1, (0b011 << 10) | 0b0000001000);
|
||||
VSLLIxy(D, q1, q1, 48);
|
||||
VOR_Vxy(q1, v1, q1);
|
||||
}
|
||||
VFDIVxy(D, v0, v1, v2);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
VBITSEL_Vxy(v0, v0, q1, q0);
|
||||
VFCMPxy(D, d1, v0, v0, cUN);
|
||||
VANDN_Vxy(d0, d0, d1);
|
||||
VLDIxy(d1, (0b011 << 9) | 0b111111000);
|
||||
VSLLIxy(D, d1, d1, 48); // broadcast 0xfff8000000000000
|
||||
VLDIxy(d1, (0b011 << 10) | 0b1111111000);
|
||||
VSLLIxy(D, d1, d1, 48);
|
||||
VBITSEL_Vxy(v0, v0, d1, d0);
|
||||
}
|
||||
break;
|
||||
@@ -654,6 +677,8 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
if (u8 > 15) u8 = 15;
|
||||
if (u8) {
|
||||
VSRAIxy(H, v0, v1, u8);
|
||||
} else if (v0 != v1) {
|
||||
VOR_Vxy(v0, v1, v1);
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
@@ -694,6 +719,8 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
if (u8 > 31) u8 = 31;
|
||||
if (u8) {
|
||||
VSRAIxy(W, v0, v1, u8);
|
||||
} else if (v0 != v1) {
|
||||
VOR_Vxy(v0, v1, v1);
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
@@ -794,10 +821,16 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
}
|
||||
VFADDxy(D, v0, q0, v0);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
VFCMPxy(D, q1, q0, q0, cUN);
|
||||
VLDIxy(d1, (0b011 << 10) | 0b0000001000);
|
||||
VSLLIxy(D, d1, d1, 48);
|
||||
VOR_Vxy(d1, q0, d1);
|
||||
VBITSEL_Vxy(v0, v0, d1, q1);
|
||||
VFCMPxy(D, d1, v0, v0, cUN);
|
||||
VANDN_Vxy(d0, d0, d1);
|
||||
VLDIxy(d1, (0b011 << 9) | 0b111111000);
|
||||
VSLLIxy(D, d1, d1, 48); // broadcast 0xfff8000000000000
|
||||
VLDIxy(d1, (0b011 << 10) | 0b1111111000);
|
||||
VSLLIxy(D, d1, d1, 48);
|
||||
VBITSEL_Vxy(v0, v0, d1, d0);
|
||||
}
|
||||
break;
|
||||
@@ -815,10 +848,16 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
}
|
||||
VFSUBxy(D, v0, q0, v0);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
VFCMPxy(D, q1, q0, q0, cUN);
|
||||
VLDIxy(d1, (0b011 << 10) | 0b0000001000);
|
||||
VSLLIxy(D, d1, d1, 48);
|
||||
VOR_Vxy(d1, q0, d1);
|
||||
VBITSEL_Vxy(v0, v0, d1, q1);
|
||||
VFCMPxy(D, d1, v0, v0, cUN);
|
||||
VANDN_Vxy(d0, d0, d1);
|
||||
VLDIxy(d1, (0b011 << 9) | 0b111111000);
|
||||
VSLLIxy(D, d1, d1, 48); // broadcast 0xfff8000000000000
|
||||
VLDIxy(d1, (0b011 << 10) | 0b1111111000);
|
||||
VSLLIxy(D, d1, d1, 48);
|
||||
VBITSEL_Vxy(v0, v0, d1, d0);
|
||||
}
|
||||
break;
|
||||
@@ -895,7 +934,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
GETVYx(v1, 0);
|
||||
GETGYx_empty(v0);
|
||||
u8 = F8;
|
||||
if(v0 != v1) VOR_V(v0, v1, v1);
|
||||
if (v0 != v1) VOR_V(v0, v1, v1);
|
||||
VINSGR2VR_H(v0, ed, (u8 & 0x7));
|
||||
break;
|
||||
case 0xC5:
|
||||
@@ -946,17 +985,23 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
VFCMPxy(D, d0, v1, v2, cUN);
|
||||
VFCMPxy(D, q1, v1, v1, cUN);
|
||||
VLDIxy(d1, (0b011 << 10) | 0b0000001000);
|
||||
VSLLIxy(D, d1, d1, 48);
|
||||
VOR_Vxy(d1, v1, d1);
|
||||
}
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
VFSUBxy(D, q0, v1, v2);
|
||||
VFADDxy(D, v0, v1, v2);
|
||||
VEXTRINSxy(D, v0, q0, 0);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
VBITSEL_Vxy(v0, v0, d1, q1);
|
||||
VFCMPxy(D, d1, v0, v0, cUN);
|
||||
VANDN_Vxy(d0, d0, d1);
|
||||
VLDIxy(d1, (0b011 << 9) | 0b111111000);
|
||||
VSLLIxy(D, d1, d1, 48); // broadcast 0xfff8000000000000
|
||||
VLDIxy(d1, (0b011 << 10) | 0b1111111000);
|
||||
VSLLIxy(D, d1, d1, 48);
|
||||
VBITSEL_Vxy(v0, v0, d1, d0);
|
||||
}
|
||||
break;
|
||||
@@ -1015,7 +1060,6 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
if (MODREG) {
|
||||
GETEYx_empty(q1, 0);
|
||||
XVPICKVE_D(q1, q0, 0);
|
||||
YMM_UNMARK_UPPER_ZERO(q1);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x4, x5, &fixedaddress, rex, NULL, 1, 0);
|
||||
FST_D(q0, ed, fixedaddress);
|
||||
@@ -1135,9 +1179,9 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
GETGYx_empty(v0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
if(vex.l){
|
||||
if (vex.l) {
|
||||
XVXOR_V(d0, d0, d0);
|
||||
XVFTINTRZ_W_D(d1, d0, v1); // v0 [lo0, lo1, --, --, hi0, hi1, --, -- ]
|
||||
XVFTINTRZ_W_D(d1, d0, v1); // v0 [lo0, lo1, --, --, hi0, hi1, --, -- ]
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
@@ -1147,26 +1191,25 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
so we could combine +-NAN +overflow to xvfcmp.cule 0x41e0000000000000
|
||||
*/
|
||||
LU52I_D(x5, xZR, 0x41e);
|
||||
XVREPLGR2VR_D(q1, x5);
|
||||
XVREPLGR2VR_D(q1, x5);
|
||||
XVFCMP_D(d0, q1, v1, cULE); // get Nan mask
|
||||
XVSRLNI_W_D(d0, d0, 0);
|
||||
XVBITSEL_V(v0, d1, q0, d0);
|
||||
}
|
||||
XVPERMI_D(v0, v0, 0b11011000);
|
||||
}else{
|
||||
} else {
|
||||
VFTINTRZ_W_D(d0, v1, v1);
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
XVLDI(q0, 0b1001110000000); // broadcast 0x80000000 to all
|
||||
LU52I_D(x5, xZR, 0x41e);
|
||||
XVREPLGR2VR_D(q1, x5);
|
||||
XVREPLGR2VR_D(q1, x5);
|
||||
XVFCMP_D(q1, q1, v1, cULE); // get Nan mask
|
||||
VSHUF4I_W(q1, q1, 0b11011000);
|
||||
VBITSEL_V(d0, d0, q0, q1);
|
||||
}
|
||||
XVPICKVE_D(v0, d0, 0);
|
||||
YMM_UNMARK_UPPER_ZERO(v0);
|
||||
}
|
||||
break;
|
||||
case 0xE7:
|
||||
@@ -1232,6 +1275,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
nextop = F8;
|
||||
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
|
||||
VXOR_Vxy(v0, v1, v2);
|
||||
if (v0 == v1 && v0 == v2) YMM_UNMARK_UPPER_ZERO(v0);
|
||||
break;
|
||||
case 0xF1:
|
||||
INST_NAME("VPSLLW Gx, Vx, Ex");
|
||||
|
||||
@@ -262,7 +262,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
GETEYx(v1, 0, 0);
|
||||
GETGYy_empty(v0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
/*
|
||||
/*
|
||||
xvffintl.s.h convert [h0..h3,h4..h7,h8..h11,h12..h15] to [h0..h3,h8..h11]
|
||||
xvffinth.s.h convert [h0..h3,h4..h7,h8..h11,h12..h15] to [h4..h7,h12..h15]
|
||||
so user xvpermi.d to reorder input [h0..h3,h4..h7,h8..h11,h12..h15] to [h0..h3,h8..h11,h4..h7,h12..h15]
|
||||
@@ -278,6 +278,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
case 0x16:
|
||||
INST_NAME("VPERMPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
if (!vex.l) UDF();
|
||||
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
|
||||
XVPERM_W(v0, v2, v1);
|
||||
break;
|
||||
@@ -637,6 +638,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
case 0x36:
|
||||
INST_NAME("VPERMD Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
if (!vex.l) UDF();
|
||||
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
|
||||
XVPERM_W(v0, v2, v1);
|
||||
break;
|
||||
@@ -719,7 +721,6 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
VSEQ_H(q0, q2, v1); // get mask(0xffff)
|
||||
VFRSTPI_H(q2, q0, 1); // find first neg(0xffff),insert index to q2
|
||||
XVPICKVE_W(v0, q2, 0);
|
||||
YMM_UNMARK_UPPER_ZERO(v0);
|
||||
break;
|
||||
case 0x45:
|
||||
INST_NAME("VPSRLVD/Q Gx, Vx, Ex");
|
||||
@@ -741,6 +742,10 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
case 0x46:
|
||||
INST_NAME("VPSRAVD Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
if (rex.w) {
|
||||
DEFAULT;
|
||||
return addr;
|
||||
}
|
||||
GETGY_empty_VYEY_xy(v0, v1, v2, 0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
VMINIxy(WU, d0, v2, 31);
|
||||
@@ -853,7 +858,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
case 0x8E:
|
||||
INST_NAME("VPMASKMOVD/Q Ex, Vx, Gx");
|
||||
nextop = F8;
|
||||
GETEY_VYGY_xy(v0, v2, v1, 0);
|
||||
GETEY_VYGY_xy(v0, v1, v2, 0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
if (vex.l) {
|
||||
if (rex.w) {
|
||||
@@ -924,10 +929,12 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
};
|
||||
for (int i = 0; i < (rex.w ? 4 : 8); i++) {
|
||||
XVPICKVE2GRxw(x4, d1, i);
|
||||
BEQZ(x4, 4 + 4 * 4);
|
||||
BEQZ(x4, 4 + 4 * (5 + rex.is32bits));
|
||||
XVPICKVE2GR_W(x4, v1, i);
|
||||
SLLI_D(x4, x4, wb1);
|
||||
LDXxw(x6, ed, x4);
|
||||
ADD_D(x4, x4, ed);
|
||||
if (rex.is32bits) ZEROUP(x4);
|
||||
LDxw(x6, x4, 0);
|
||||
XVINSGR2VRxw(v0, x6, i);
|
||||
}
|
||||
XVXOR_V(v2, v2, v2);
|
||||
@@ -940,10 +947,12 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
};
|
||||
for (int i = 0; i < (rex.w ? 2 : 4); i++) {
|
||||
VPICKVE2GRxw(x4, d1, i);
|
||||
BEQZ(x4, 4 + 4 * 4);
|
||||
BEQZ(x4, 4 + 4 * (5 + rex.is32bits));
|
||||
VPICKVE2GR_W(x4, v1, i);
|
||||
SLLI_D(x4, x4, wb1);
|
||||
LDXxw(x6, ed, x4);
|
||||
ADD_D(x4, x4, ed);
|
||||
if (rex.is32bits) ZEROUP(x4);
|
||||
LDxw(x6, x4, 0);
|
||||
VINSGR2VRxw(v0, x6, i);
|
||||
}
|
||||
VXOR_V(v2, v2, v2);
|
||||
@@ -1005,10 +1014,12 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
};
|
||||
for (int i = 0; i < 4; i++) {
|
||||
XVPICKVE2GRxw(x4, d1, i);
|
||||
BEQZ(x4, 4 + 4 * 4);
|
||||
BEQZ(x4, 4 + 4 * (5 + rex.is32bits));
|
||||
XVPICKVE2GR_D(x4, v1, i);
|
||||
SLLI_D(x4, x4, wb1);
|
||||
LDXxw(x6, ed, x4);
|
||||
ADD_D(x4, x4, ed);
|
||||
if (rex.is32bits) ZEROUP(x4);
|
||||
LDxw(x6, x4, 0);
|
||||
XVINSGR2VRxw(v0, x6, i);
|
||||
}
|
||||
XVXOR_V(v2, v2, v2);
|
||||
@@ -1021,10 +1032,12 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
};
|
||||
for (int i = 0; i < 2; i++) {
|
||||
VPICKVE2GRxw(x4, d1, i);
|
||||
BEQZ(x4, 4 + 4 * 4);
|
||||
BEQZ(x4, 4 + 4 * (5 + rex.is32bits));
|
||||
VPICKVE2GR_D(x4, v1, i);
|
||||
SLLI_D(x4, x4, wb1);
|
||||
LDXxw(x6, ed, x4);
|
||||
ADD_D(x4, x4, ed);
|
||||
if (rex.is32bits) ZEROUP(x4);
|
||||
LDxw(x6, x4, 0);
|
||||
VINSGR2VRxw(v0, x6, i);
|
||||
}
|
||||
VXOR_V(v2, v2, v2);
|
||||
@@ -1294,7 +1307,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
avx_forget_reg(dyn, ninst, gd);
|
||||
MOV32w(x1, gd);
|
||||
CALL(const_native_aesimc, -1, x1, 0);
|
||||
GETGYx(q0, 1); // reget writable for mark zeroup hi-128bits.
|
||||
GETGYx(q0, 1); // reget writable for mark zeroup hi-128bits.
|
||||
break;
|
||||
case 0xDC:
|
||||
INST_NAME("VAESENC Gx, Vx, Ex");
|
||||
|
||||
@@ -508,11 +508,10 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
u8 = F8;
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
if (u8 & 4) {
|
||||
u8 = sse_setround(dyn, ninst, x1, x2);
|
||||
u8 = sse_setround(dyn, ninst, x4, x5);
|
||||
} else {
|
||||
MOVFCSR2GR(x4, FCSR3);
|
||||
ORI(x5, x5, round_round[u8 & 3]);
|
||||
SLLI_D(x5, x5, 8);
|
||||
ORI(x5, xZR, ((-(u8 & 3)) & 3) << 8);
|
||||
MOVGR2FCSR(FCSR3, x5);
|
||||
u8 = x4;
|
||||
}
|
||||
@@ -531,7 +530,15 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
case 0x20:
|
||||
INST_NAME("VPINSRB Gx, Vx, ED, Ib");
|
||||
nextop = F8;
|
||||
GETEB(x5, 1);
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
wback = 0;
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, NULL, 1, 1);
|
||||
LD_B(x1, wback, fixedaddress);
|
||||
ed = x1;
|
||||
}
|
||||
GETVYx(v1, 0);
|
||||
GETGYx_empty(v0);
|
||||
u8 = F8;
|
||||
@@ -749,7 +756,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
INST_NAME("VBLENDVPS Gx, Vx, Ex, XMMImm8");
|
||||
nextop = F8;
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop) >> 4;
|
||||
d0 = avx_get_reg(dyn, ninst, x5, u8, 0, LSX_AVX_WIDTH_128);
|
||||
d0 = avx_get_reg(dyn, ninst, x5, u8, 0, vex.l ? LSX_AVX_WIDTH_256 : LSX_AVX_WIDTH_128);
|
||||
GETGY_empty_VYEY_xy(v0, v1, v2, 1);
|
||||
F8;
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
@@ -760,7 +767,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
INST_NAME("VBLENDVPD Gx, Vx, Ex, XMMImm8");
|
||||
nextop = F8;
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop) >> 4;
|
||||
d0 = avx_get_reg(dyn, ninst, x5, u8, 0, LSX_AVX_WIDTH_128);
|
||||
d0 = avx_get_reg(dyn, ninst, x5, u8, 0, vex.l ? LSX_AVX_WIDTH_256 : LSX_AVX_WIDTH_128);
|
||||
GETGY_empty_VYEY_xy(v0, v1, v2, 1);
|
||||
F8;
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
@@ -771,7 +778,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
INST_NAME("VPBLENDVB Gx, Vx, Ex, XMMImm8");
|
||||
nextop = F8;
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop) >> 4;
|
||||
d0 = avx_get_reg(dyn, ninst, x5, u8, 0, LSX_AVX_WIDTH_128);
|
||||
d0 = avx_get_reg(dyn, ninst, x5, u8, 0, vex.l ? LSX_AVX_WIDTH_256 : LSX_AVX_WIDTH_128);
|
||||
GETGY_empty_VYEY_xy(v0, v1, v2, 1);
|
||||
F8;
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
|
||||
@@ -65,13 +65,12 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
GETVYx(q1, 0);
|
||||
GETEYSD(q2, 0, 0);
|
||||
GETGYx_empty(q0);
|
||||
if (gd != vex.v) VOR_V(q0, q1, q1);
|
||||
VEXTRINS_D(q0, q2, 0);
|
||||
if (q0 != q2) VEXTRINS_D(q0, q2, 0b00000);
|
||||
if (q0 != q1) VEXTRINS_D(q0, q1, 0b10001);
|
||||
} else {
|
||||
GETEYSD(q2, 0, 0);
|
||||
GETGYx_empty(q0);
|
||||
XVPICKVE_D(q0, q2, 0);
|
||||
YMM_UNMARK_UPPER_ZERO(q0);
|
||||
}
|
||||
break;
|
||||
case 0x11:
|
||||
@@ -79,15 +78,10 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
nextop = F8;
|
||||
GETGYx(q2, 0);
|
||||
if (MODREG) {
|
||||
if (ed == vex.v) {
|
||||
GETEYSD(q0, 1, 0);
|
||||
VEXTRINS_D(q0, q2, 0);
|
||||
} else {
|
||||
GETVYx(q1, 0);
|
||||
GETEYSD(q0, 1, 0);
|
||||
VOR_V(q0, q1, q1);
|
||||
VEXTRINS_D(q0, q2, 0);
|
||||
}
|
||||
GETVYx(q1, 0);
|
||||
GETEYSD(q0, 1, 0);
|
||||
if (q0 != q2) VEXTRINS_D(q0, q2, 0b00000);
|
||||
if (q0 != q1) VEXTRINS_D(q0, q1, 0b10001);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
FST_D(q2, ed, fixedaddress);
|
||||
@@ -136,7 +130,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
}
|
||||
if(v0 != v1) VOR_V(v0, v1, v1);
|
||||
if (v0 != v1) VOR_V(v0, v1, v1);
|
||||
VEXTRINS_D(v0, d1, 0);
|
||||
break;
|
||||
case 0x2C:
|
||||
@@ -226,13 +220,20 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
FADD_D(d0, v1, v2);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
FCMP_D(fcc0, v1, v2, cUN);
|
||||
BCNEZ_MARK(fcc0);
|
||||
FCMP_D(fcc1, d0, d0, cOR);
|
||||
BCNEZ_MARK(fcc1);
|
||||
FNEG_D(d0, d0);
|
||||
MARK;
|
||||
MOVFR2GR_D(x4, v1);
|
||||
MOV64x(x5, 0x0008000000000000LL);
|
||||
OR(x4, x4, x5);
|
||||
MOVGR2FR_D(d1, x4);
|
||||
FCMP_D(fcc0, v1, v1, cUN);
|
||||
FSEL(d0, d0, d1, fcc0);
|
||||
}
|
||||
MARK;
|
||||
if (v0 != v1) VOR_V(v0, v1, v1);
|
||||
VEXTRINS_D(v0, d0, 0);
|
||||
break;
|
||||
@@ -245,13 +246,20 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
FMUL_D(d0, v1, v2);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
FCMP_D(fcc0, v1, v2, cUN);
|
||||
BCNEZ_MARK(fcc0);
|
||||
FCMP_D(fcc1, d0, d0, cOR);
|
||||
BCNEZ_MARK(fcc1);
|
||||
FNEG_D(d0, d0);
|
||||
MARK;
|
||||
MOVFR2GR_D(x4, v1);
|
||||
MOV64x(x5, 0x0008000000000000LL);
|
||||
OR(x4, x4, x5);
|
||||
MOVGR2FR_D(d1, x4);
|
||||
FCMP_D(fcc0, v1, v1, cUN);
|
||||
FSEL(d0, d0, d1, fcc0);
|
||||
}
|
||||
MARK;
|
||||
if (v0 != v1) VOR_V(v0, v1, v1);
|
||||
VEXTRINS_D(v0, d0, 0);
|
||||
break;
|
||||
@@ -263,7 +271,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
GETGYx_empty(v0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
FCVT_S_D(d0, v2);
|
||||
if(v0 != v1) VOR_V(v0, v1, v1);
|
||||
if (v0 != v1) VOR_V(v0, v1, v1);
|
||||
XVINSVE0_W(v0, d0, 0);
|
||||
break;
|
||||
case 0x5C:
|
||||
@@ -275,13 +283,20 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
FSUB_D(d0, v1, v2);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
FCMP_D(fcc0, v1, v2, cUN);
|
||||
BCNEZ_MARK(fcc0);
|
||||
FCMP_D(fcc1, d0, d0, cOR);
|
||||
BCNEZ_MARK(fcc1);
|
||||
FNEG_D(d0, d0);
|
||||
MARK;
|
||||
MOVFR2GR_D(x4, v1);
|
||||
MOV64x(x5, 0x0008000000000000LL);
|
||||
OR(x4, x4, x5);
|
||||
MOVGR2FR_D(d1, x4);
|
||||
FCMP_D(fcc0, v1, v1, cUN);
|
||||
FSEL(d0, d0, d1, fcc0);
|
||||
}
|
||||
MARK;
|
||||
if (v0 != v1) VOR_V(v0, v1, v1);
|
||||
VEXTRINS_D(v0, d0, 0);
|
||||
break;
|
||||
@@ -310,13 +325,20 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
FDIV_D(d0, v1, v2);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
FCMP_D(fcc0, v1, v2, cUN);
|
||||
BCNEZ_MARK(fcc0);
|
||||
FCMP_D(fcc1, d0, d0, cOR);
|
||||
BCNEZ_MARK(fcc1);
|
||||
FNEG_D(d0, d0);
|
||||
MARK;
|
||||
MOVFR2GR_D(x4, v1);
|
||||
MOV64x(x5, 0x0008000000000000LL);
|
||||
OR(x4, x4, x5);
|
||||
MOVGR2FR_D(d1, x4);
|
||||
FCMP_D(fcc0, v1, v1, cUN);
|
||||
FSEL(d0, d0, d1, fcc0);
|
||||
}
|
||||
MARK;
|
||||
if (v0 != v1) VOR_V(v0, v1, v1);
|
||||
VEXTRINS_D(v0, d0, 0);
|
||||
break;
|
||||
@@ -364,10 +386,16 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
}
|
||||
VFADDxy(S, v0, q0, v0);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
VFCMPxy(S, q1, q0, q0, cUN);
|
||||
VLDIxy(d1, (0b010 << 9) | 0b0000000100);
|
||||
VSLLIxy(W, d1, d1, 20);
|
||||
VOR_Vxy(d1, q0, d1);
|
||||
VBITSEL_Vxy(v0, v0, d1, q1);
|
||||
VFCMPxy(S, d1, v0, v0, cUN);
|
||||
VANDN_Vxy(d0, d0, d1);
|
||||
VLDIxy(d1, (0b010 << 9) | 0b1111111100);
|
||||
VSLLIxy(W, d1, d1, 20); // broadcast 0xFFC00000
|
||||
VSLLIxy(W, d1, d1, 20);
|
||||
VBITSEL_Vxy(v0, v0, d1, d0);
|
||||
}
|
||||
break;
|
||||
@@ -385,10 +413,16 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
}
|
||||
VFSUBxy(S, v0, q0, v0);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
VFCMPxy(S, q1, q0, q0, cUN);
|
||||
VLDIxy(d1, (0b010 << 9) | 0b0000000100);
|
||||
VSLLIxy(W, d1, d1, 20);
|
||||
VOR_Vxy(d1, q0, d1);
|
||||
VBITSEL_Vxy(v0, v0, d1, q1);
|
||||
VFCMPxy(S, d1, v0, v0, cUN);
|
||||
VANDN_Vxy(d0, d0, d1);
|
||||
VLDIxy(d1, (0b010 << 9) | 0b1111111100);
|
||||
VSLLIxy(W, d1, d1, 20); // broadcast 0xFFC00000
|
||||
VSLLIxy(W, d1, d1, 20);
|
||||
VBITSEL_Vxy(v0, v0, d1, d0);
|
||||
}
|
||||
break;
|
||||
@@ -418,10 +452,8 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
case 0x0e: VFCMP_D(q0, v2, v1, cLT); break; // Greater ordered
|
||||
case 0x0f: VSEQ_B(q0, v1, v1); break; // true
|
||||
}
|
||||
XVXOR_V(v0, v0, v0);
|
||||
XVPERMI_Q(v0, v1, XVPERMI_IMM_4_0(3, 0));
|
||||
XVINSVE0_D(v0, q0, 0);
|
||||
YMM_UNMARK_UPPER_ZERO(v0);
|
||||
break;
|
||||
case 0xD0:
|
||||
INST_NAME("VADDSUBPS Gx, Vx, Ex");
|
||||
@@ -430,7 +462,12 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
VFCMPxy(S, d0, v1, v2, cUN);
|
||||
VFCMPxy(S, q1, v1, v1, cUN);
|
||||
VLDIxy(d1, (0b010 << 9) | 0b0000000100);
|
||||
VSLLIxy(W, d1, d1, 20);
|
||||
VOR_Vxy(d1, v1, d1);
|
||||
}
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
VFSUBxy(S, q0, v1, v2);
|
||||
@@ -438,10 +475,11 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
VEXTRINSxy(W, v0, q0, VEXTRINS_IMM_4_0(0, 0));
|
||||
VEXTRINSxy(W, v0, q0, VEXTRINS_IMM_4_0(2, 2));
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
VFCMPxy(S, d1, v0, v0, cUN);
|
||||
VANDN_Vxy(d0, d0, d1);
|
||||
VBITSEL_Vxy(v0, v0, d1, q1);
|
||||
VFCMPxy(S, q1, v0, v0, cUN);
|
||||
VANDN_Vxy(d0, d0, q1);
|
||||
VLDIxy(d1, (0b010 << 9) | 0b1111111100);
|
||||
VSLLIxy(W, d1, d1, 20); // broadcast 0xFFC00000
|
||||
VSLLIxy(W, d1, d1, 20);
|
||||
VBITSEL_Vxy(v0, v0, d1, d0);
|
||||
}
|
||||
break;
|
||||
@@ -453,21 +491,23 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
u8 = sse_setround(dyn, ninst, x1, x2);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
if (vex.l) {
|
||||
XVXOR_V(d0, d0, d0);
|
||||
XVFTINT_W_D(v0, d0, v1); // v0 [lo0, lo1, --, --, hi0, hi1, --, -- ]
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
q2 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
XVFTINT_L_D(q2, v1);
|
||||
XVFCMP_D(d1, v1, v1, cUN); // get NaN mask
|
||||
}
|
||||
XVXOR_V(d0, d0, d0);
|
||||
XVFTINT_W_D(v0, d0, v1); // v0 [lo0, lo1, --, --, hi0, hi1, --, -- ]
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
XVLDI(q0, 0b1001110000000); // broadcast 0x80000000 to all
|
||||
MOV32w(x5, 0x7FFFFFFF);
|
||||
BSTRPICK_D(x5, x5, 31, 0);
|
||||
XVREPLGR2VR_D(q1, x5);
|
||||
XVFCMP_D(d0, v1, v1, cUN); // get Nan mask
|
||||
XVSLT_D(d1, q1, q2); // get +inf mask
|
||||
XVOR_V(d0, d1, d0);
|
||||
XVREPLGR2VR_D(q1, x5);
|
||||
XVSLT_D(d0, q1, q2); // get +inf mask
|
||||
XVOR_V(d0, d0, d1); // combine with NaN mask
|
||||
XVSRLNI_W_D(d0, d0, 0); // [A,B,C,D] => [a,b,--,--,c,d,--,--]
|
||||
XVBITSEL_V(v0, v0, q0, d0);
|
||||
}
|
||||
@@ -483,15 +523,14 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
VLDI(q0, 0b1001110000000); // broadcast 0x80000000 to all
|
||||
MOV32w(x5, 0x7FFFFFFF);
|
||||
BSTRPICK_D(x5, x5, 31, 0);
|
||||
VREPLGR2VR_D(q1, x5);
|
||||
VSLT_D(q1, q1, d1); // get +inf mask
|
||||
VREPLGR2VR_D(q1, x5);
|
||||
VSLT_D(q1, q1, d1); // get +inf mask
|
||||
VFCMP_D(q2, v1, v1, cUN); // get Nan mask
|
||||
VOR_V(q1, q1, q2);
|
||||
VSHUF4I_W(q1, q1, 0b11011000);
|
||||
VBITSEL_V(d0, d0, q0, q1);
|
||||
}
|
||||
XVPICKVE_D(v0, d0, 0);
|
||||
YMM_UNMARK_UPPER_ZERO(v0);
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
|
||||
@@ -92,22 +92,20 @@ uintptr_t dynarec64_AVX_F2_0F38(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t i
|
||||
GETGD;
|
||||
GETED(0);
|
||||
GETVD;
|
||||
if ((gd == xRDX) || (gd == ed) || (gd == vd))
|
||||
gb1 = x3;
|
||||
else
|
||||
gb1 = gd;
|
||||
if (rex.w) {
|
||||
if ((gd == xRDX) || (gd == ed) || (gd == vd))
|
||||
gb1 = x3;
|
||||
else
|
||||
gb1 = gd;
|
||||
MULH_DU(gb1, xRDX, ed);
|
||||
if (gd != vd) { MUL_D(vd, xRDX, ed); }
|
||||
if (gb1 == x3) {
|
||||
OR(gd, gb1, gb1);
|
||||
MV(gd, gb1);
|
||||
}
|
||||
} else {
|
||||
MULH_WU(gb1, xRDX, ed);
|
||||
if (gd != vd) { MUL_W(vd, xRDX, ed); }
|
||||
}
|
||||
if (gb1 == x3) {
|
||||
BSTRINS_D(gd, gb1, 31, 0);
|
||||
MULW_D_WU(x3, xRDX, ed);
|
||||
if (gd != vd) { ZEROUP2(vd, x3); }
|
||||
SRLI_D(gd, x3, 32);
|
||||
}
|
||||
break;
|
||||
case 0xF7:
|
||||
|
||||
@@ -51,13 +51,15 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
GETVYx(q1, 0);
|
||||
GETEYSS(q2, 0, 0);
|
||||
GETGYx_empty(q0);
|
||||
if (gd != vex.v) VOR_V(q0, q1, q1);
|
||||
VEXTRINS_W(q0, q2, 0);
|
||||
if (q0 != q2) VEXTRINS_W(q0, q2, 0b00000);
|
||||
if (q0 != q1) {
|
||||
VEXTRINS_D(q0, q1, 0b10001);
|
||||
VEXTRINS_W(q0, q1, 0b10001);
|
||||
}
|
||||
} else {
|
||||
GETEYSS(q2, 0, 0);
|
||||
GETGYx_empty(q0);
|
||||
XVPICKVE_W(q0, q2, 0);
|
||||
YMM_UNMARK_UPPER_ZERO(q0);
|
||||
}
|
||||
break;
|
||||
case 0x11:
|
||||
@@ -65,14 +67,12 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
nextop = F8;
|
||||
GETGYx(q2, 0);
|
||||
if (MODREG) {
|
||||
if (ed == vex.v) {
|
||||
GETEYSS(q0, 1, 0);
|
||||
VEXTRINS_W(q0, q2, 0);
|
||||
} else {
|
||||
GETVYx(q1, 0);
|
||||
GETEYSS(q0, 1, 0);
|
||||
VOR_V(q0, q1, q1);
|
||||
VEXTRINS_W(q0, q2, 0);
|
||||
GETVYx(q1, 0);
|
||||
GETEYSD(q0, 1, 0);
|
||||
if (q0 != q2) VEXTRINS_W(q0, q2, 0b00000);
|
||||
if (q0 != q1) {
|
||||
VEXTRINS_D(q0, q1, 0b10001);
|
||||
VEXTRINS_W(q0, q1, 0b10001);
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
@@ -120,7 +120,7 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
}
|
||||
if(v0 != v1) VOR_V(v0, v1, v1);
|
||||
if (v0 != v1) VOR_V(v0, v1, v1);
|
||||
VEXTRINS_W(v0, d1, 0);
|
||||
break;
|
||||
case 0x2C:
|
||||
@@ -211,9 +211,9 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
GETGYx_empty(v0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
if (cpuext.frecipe) {
|
||||
FRSQRTE_S(d0, v1);
|
||||
FRSQRTE_S(d0, v2);
|
||||
} else {
|
||||
FRSQRT_S(d0, v1);
|
||||
FRSQRT_S(d0, v2);
|
||||
}
|
||||
if (v0 != v1) VOR_V(v0, v1, v1);
|
||||
VEXTRINS_W(v0, d0, 0);
|
||||
@@ -226,9 +226,9 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
GETGYx_empty(v0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
if (cpuext.frecipe) {
|
||||
FRECIPE_S(d0, v1);
|
||||
FRECIPE_S(d0, v2);
|
||||
} else {
|
||||
FRECIP_S(d0, v1);
|
||||
FRECIP_S(d0, v2);
|
||||
}
|
||||
if (v0 != v1) VOR_V(v0, v1, v1);
|
||||
VEXTRINS_W(v0, d0, 0);
|
||||
@@ -242,13 +242,20 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
FADD_S(d0, v1, v2);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
FCMP_S(fcc0, v1, v2, cUN);
|
||||
BCNEZ_MARK(fcc0);
|
||||
FCMP_S(fcc1, d0, d0, cOR);
|
||||
BCNEZ_MARK(fcc1);
|
||||
FNEG_S(d0, d0);
|
||||
MARK;
|
||||
MOVFR2GR_D(x4, v1);
|
||||
MOV32w(x5, 0x00400000);
|
||||
OR(x4, x4, x5);
|
||||
MOVGR2FR_D(d1, x4);
|
||||
FCMP_S(fcc0, v1, v1, cUN);
|
||||
FSEL(d0, d0, d1, fcc0);
|
||||
}
|
||||
MARK;
|
||||
if (v0 != v1) VOR_V(v0, v1, v1);
|
||||
VEXTRINS_W(v0, d0, 0);
|
||||
break;
|
||||
@@ -266,8 +273,15 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
FCMP_S(fcc1, d0, d0, cOR);
|
||||
BCNEZ_MARK(fcc1);
|
||||
FNEG_S(d0, d0);
|
||||
MARK;
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
MOVFR2GR_D(x4, v1);
|
||||
MOV32w(x5, 0x00400000);
|
||||
OR(x4, x4, x5);
|
||||
MOVGR2FR_D(d1, x4);
|
||||
FCMP_S(fcc0, v1, v1, cUN);
|
||||
FSEL(d0, d0, d1, fcc0);
|
||||
}
|
||||
MARK;
|
||||
if (v0 != v1) VOR_V(v0, v1, v1);
|
||||
VEXTRINS_W(v0, d0, 0);
|
||||
break;
|
||||
@@ -279,7 +293,7 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
GETGYx_empty(v0);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
FCVT_D_S(d1, v2);
|
||||
if(v0 != v1) VOR_V(v0, v1, v1);
|
||||
if (v0 != v1) VOR_V(v0, v1, v1);
|
||||
VEXTRINS_D(v0, d1, 0);
|
||||
break;
|
||||
case 0x5B:
|
||||
@@ -325,13 +339,20 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
FSUB_S(d0, v1, v2);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
FCMP_S(fcc0, v1, v2, cUN);
|
||||
BCNEZ_MARK(fcc0);
|
||||
FCMP_S(fcc1, d0, d0, cOR);
|
||||
BCNEZ_MARK(fcc1);
|
||||
FNEG_S(d0, d0);
|
||||
MARK;
|
||||
MOVFR2GR_D(x4, v1);
|
||||
MOV32w(x5, 0x00400000);
|
||||
OR(x4, x4, x5);
|
||||
MOVGR2FR_D(d1, x4);
|
||||
FCMP_S(fcc0, v1, v1, cUN);
|
||||
FSEL(d0, d0, d1, fcc0);
|
||||
}
|
||||
MARK;
|
||||
if (v0 != v1) VOR_V(v0, v1, v1);
|
||||
VEXTRINS_W(v0, d0, 0);
|
||||
break;
|
||||
@@ -342,12 +363,8 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
GETEYSS(v2, 0, 0);
|
||||
GETGYx_empty(v0);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
if (BOX64ENV(dynarec_fastnan)) {
|
||||
FMIN_S(q0, v1, v2);
|
||||
} else {
|
||||
FCMP_S(fcc0, v2, v1, cULE);
|
||||
FSEL(q0, v1, v2, fcc0);
|
||||
}
|
||||
FCMP_S(fcc0, v2, v1, cULE);
|
||||
FSEL(q0, v1, v2, fcc0);
|
||||
if (v0 != v1) VOR_V(v0, v1, v1);
|
||||
VEXTRINS_W(v0, q0, 0);
|
||||
break;
|
||||
@@ -360,13 +377,20 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
FDIV_S(d0, v1, v2);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
FCMP_S(fcc0, v1, v2, cUN);
|
||||
BCNEZ_MARK(fcc0);
|
||||
FCMP_S(fcc1, d0, d0, cOR);
|
||||
BCNEZ_MARK(fcc1);
|
||||
FNEG_S(d0, d0);
|
||||
MARK;
|
||||
MOVFR2GR_D(x4, v1);
|
||||
MOV32w(x5, 0x00400000);
|
||||
OR(x4, x4, x5);
|
||||
MOVGR2FR_D(d1, x4);
|
||||
FCMP_S(fcc0, v1, v1, cUN);
|
||||
FSEL(d0, d0, d1, fcc0);
|
||||
}
|
||||
MARK;
|
||||
if (v0 != v1) VOR_V(v0, v1, v1);
|
||||
VEXTRINS_W(v0, d0, 0);
|
||||
break;
|
||||
@@ -377,12 +401,8 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
GETEYSS(v2, 0, 0);
|
||||
GETGYx_empty(v0);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
if (BOX64ENV(dynarec_fastnan)) {
|
||||
FMAX_S(q0, v1, v2);
|
||||
} else {
|
||||
FCMP_S(fcc0, v2, v1, cLT);
|
||||
FSEL(q0, v2, v1, fcc0);
|
||||
}
|
||||
FCMP_S(fcc0, v2, v1, cLT);
|
||||
FSEL(q0, v2, v1, fcc0);
|
||||
if (v0 != v1) VOR_V(v0, v1, v1);
|
||||
VEXTRINS_W(v0, q0, 0);
|
||||
break;
|
||||
@@ -427,7 +447,6 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
GETEYSD(q1, 0, 0);
|
||||
GETGYx_empty(q0);
|
||||
XVPICKVE_D(q0, q1, 0);
|
||||
YMM_UNMARK_UPPER_ZERO(q0);
|
||||
break;
|
||||
case 0x7F:
|
||||
INST_NAME("VMOVDQU Ex, Gx");
|
||||
@@ -476,26 +495,24 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
case 0x0e: VFCMP_S(q0, v2, v1, cLT); break; // Greater ordered
|
||||
case 0x0f: VSEQ_B(q0, v1, v1); break; // true
|
||||
}
|
||||
XVXOR_V(v0, v0, v0);
|
||||
XVPERMI_Q(v0, v1, XVPERMI_IMM_4_0(3, 0));
|
||||
XVINSVE0_W(v0, q0, 0);
|
||||
YMM_UNMARK_UPPER_ZERO(v0);
|
||||
break;
|
||||
case 0xE6:
|
||||
INST_NAME("VCVTDQ2PD Gx, Ex");
|
||||
nextop = F8;
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
if(vex.l){
|
||||
if (vex.l) {
|
||||
GETEYx(v1, 0, 0);
|
||||
GETGYy_empty(v0);
|
||||
/*
|
||||
/*
|
||||
xvffintl.d.w convert [v0,v1,v2,v3,v4,v5,v6,v7] to [v0,v1,v4,v5]
|
||||
xvffinth.d.w convert [v0,v1,v2,v3,v4,v5,v6,v7] to [v2,v3,v6,v7]
|
||||
so user xvpermi.d to reorder input [v0v1,v2v3,v4v5,v6v7] to [v0v1,v4v5,v2v3,v6v7]
|
||||
*/
|
||||
XVPERMI_D(d0, v1, 0b11011000);
|
||||
XVFFINTL_D_W(v0, d0);
|
||||
}else{
|
||||
} else {
|
||||
GETEYSD(v1, 0, 0);
|
||||
GETGYx_empty(v0);
|
||||
VFFINTL_D_W(v0, v1);
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "x64test.h"
|
||||
#include "dynarec/dynarec_next.h"
|
||||
#include "bitutils.h"
|
||||
#include "random.h"
|
||||
|
||||
#ifndef HAVE_TRACE
|
||||
void PrintTrace() {}
|
||||
@@ -77,6 +78,8 @@ uintptr_t getConst(la64_consts_t which)
|
||||
case const_native_fstp: return (uintptr_t)native_fstp;
|
||||
case const_native_frstor: return (uintptr_t)native_frstor;
|
||||
case const_native_next: return (uintptr_t)native_next;
|
||||
case const_native_next_invalid: return (uintptr_t)la64_next_invalid;
|
||||
case const_la64_crc_autocrc: return (uintptr_t)la64_crc_autocrc;
|
||||
case const_int3: return (uintptr_t)EmuInt3;
|
||||
case const_x86syscall: return (uintptr_t)EmuX86Syscall;
|
||||
case const_x64syscall: return (uintptr_t)EmuX64Syscall;
|
||||
|
||||
@@ -48,6 +48,8 @@ typedef enum la64_consts_s {
|
||||
const_native_fstp,
|
||||
const_native_frstor,
|
||||
const_native_next,
|
||||
const_native_next_invalid,
|
||||
const_la64_crc_autocrc,
|
||||
const_int3,
|
||||
const_x86syscall,
|
||||
const_x64syscall,
|
||||
|
||||
@@ -121,8 +121,8 @@ uintptr_t dynarec64_DD(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
FTINTRZ_L_D(v2, v1);
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
MOVFCSR2GR(x5, FCSR2); // get back FPSR to check
|
||||
MOV32w(x3, (1 << FR_V));
|
||||
AND(x5, x5, x3);
|
||||
MOV32w(x6, (1 << FR_V));
|
||||
AND(x5, x5, x6);
|
||||
BEQZ_MARK(x5);
|
||||
MOV64x(x4, 0x8000000000000000);
|
||||
MOVGR2FR_D(v2, x4);
|
||||
|
||||
@@ -98,8 +98,7 @@ void emit_add32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
SRLI_D(s4, s3, 1);
|
||||
XOR(s3, s3, s4);
|
||||
ANDI(s3, s3, 1); // OF: xor of two MSB's of cc
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_OF);
|
||||
BSTRINS_D(xFlags, s3, F_OF, F_OF);
|
||||
}
|
||||
}
|
||||
IFX (X_SF) {
|
||||
@@ -217,8 +216,7 @@ void emit_add32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i
|
||||
SRLI_D(s4, s3, 1);
|
||||
XOR(s3, s3, s4);
|
||||
ANDI(s3, s3, 1); // OF: xor of two MSB's of cc
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_OF);
|
||||
BSTRINS_D(xFlags, s3, F_OF, F_OF);
|
||||
}
|
||||
}
|
||||
IFX (X_SF) {
|
||||
@@ -254,9 +252,10 @@ void emit_add8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
X64_ADD_B(s1, s2);
|
||||
}
|
||||
ADD_D(s1, s1, s2);
|
||||
ANDI(s1, s1, 0xff);
|
||||
// d_add8 will use 16bits result to check for CF, so save 16bits and truncate after
|
||||
IFX (X_PEND)
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, res));
|
||||
ANDI(s1, s1, 0xff);
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
|
||||
return;
|
||||
}
|
||||
@@ -281,8 +280,7 @@ void emit_add8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
SRLI_D(s4, s3, 1);
|
||||
XOR(s3, s3, s4);
|
||||
ANDI(s3, s3, 1); // OF: xor of two MSB's of cc
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_OF);
|
||||
BSTRINS_D(xFlags, s3, F_OF, F_OF);
|
||||
}
|
||||
}
|
||||
IFX (X_CF) {
|
||||
@@ -290,6 +288,7 @@ void emit_add8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_CF);
|
||||
}
|
||||
// d_add8 will use 16bits result to check for CF, so save 16bits and truncate after
|
||||
IFX (X_PEND) {
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
@@ -330,9 +329,10 @@ void emit_add8c(dynarec_la64_t* dyn, int ninst, int s1, int c, int s2, int s3, i
|
||||
X64_ADD_B(s1, s4);
|
||||
}
|
||||
ADDI_D(s1, s1, c & 0xff);
|
||||
ANDI(s1, s1, 0xff);
|
||||
// d_add8 will use 16bits result to check for CF, so save 16bits and truncate after
|
||||
IFX (X_PEND)
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, res));
|
||||
ANDI(s1, s1, 0xff);
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
|
||||
return;
|
||||
}
|
||||
@@ -361,8 +361,7 @@ void emit_add8c(dynarec_la64_t* dyn, int ninst, int s1, int c, int s2, int s3, i
|
||||
SRLI_D(s4, s3, 1);
|
||||
XOR(s3, s3, s4);
|
||||
ANDI(s3, s3, 1); // OF: xor of two MSB's of cc
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_OF);
|
||||
BSTRINS_D(xFlags, s3, F_OF, F_OF);
|
||||
}
|
||||
}
|
||||
IFX (X_CF) {
|
||||
@@ -370,6 +369,7 @@ void emit_add8c(dynarec_la64_t* dyn, int ninst, int s1, int c, int s2, int s3, i
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_CF);
|
||||
}
|
||||
// d_add8 will use 16bits result to check for CF, so save 16bits and truncate after
|
||||
IFX (X_PEND) {
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
@@ -410,6 +410,7 @@ void emit_add16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4,
|
||||
|
||||
ADD_D(s1, s1, s2);
|
||||
|
||||
// d_add16 will use 32bits result to check for CF
|
||||
IFX (X_PEND) {
|
||||
ST_W(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
@@ -434,8 +435,7 @@ void emit_add16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4,
|
||||
SRLI_D(s4, s3, 1);
|
||||
XOR(s3, s3, s4);
|
||||
ANDI(s3, s3, 1); // OF: xor of two MSB's of cc
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_OF);
|
||||
BSTRINS_D(xFlags, s3, F_OF, F_OF);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -725,7 +725,18 @@ 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);
|
||||
}
|
||||
IFX (X_AF) NOR(s5, xZR, s1);
|
||||
ANDI(s1, s3, 0xff);
|
||||
IFX (X_AF) {
|
||||
// bc = (res & (~op1 | op2)) | (~op1 & op2)
|
||||
OR(s3, s5, s2);
|
||||
AND(s4, s1, s3);
|
||||
AND(s5, s5, s2);
|
||||
OR(s4, s4, s5);
|
||||
// af = bc & 0x8
|
||||
SLLI_D(s3, s4, F_AF - 3);
|
||||
X64_SET_EFLAGS(s3, X_AF);
|
||||
}
|
||||
IFX (X_PEND)
|
||||
ST_B(s1, xEmu, offsetof(x64emu_t, res));
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
|
||||
@@ -1054,9 +1065,9 @@ void emit_neg32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
void emit_adc8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
IFX (X_PEND) {
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
ST_H(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_adc8);
|
||||
ST_B(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
ST_B(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_adc8b);
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
@@ -1067,9 +1078,9 @@ 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);
|
||||
}
|
||||
ANDI(s1, s3, 0xff);
|
||||
ANDI(s1, s3, 0xff); // that's probably unneeded as ADC_B should restrain the result to 8bits already
|
||||
IFX (X_PEND) {
|
||||
ST_W(s1, xEmu, offsetof(x64emu_t, res));
|
||||
ST_B(s3, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
|
||||
return;
|
||||
@@ -1086,7 +1097,8 @@ void emit_adc8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, i
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX (X_PEND) {
|
||||
ST_W(s1, xEmu, offsetof(x64emu_t, res));
|
||||
// d_adc8 will use 16bits result to check for CF
|
||||
ST_B(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX (X_AF | X_OF) {
|
||||
ANDN(s3, s4, s1); // s3 = ~res & (op1 | op2)
|
||||
@@ -1101,8 +1113,7 @@ void emit_adc8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, i
|
||||
SRLI_D(s4, s3, 1);
|
||||
XOR(s3, s3, s4);
|
||||
ANDI(s3, s3, 1); // OF: xor of two MSB's of cc
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_OF);
|
||||
BSTRINS_D(xFlags, s3, F_OF, F_OF);
|
||||
}
|
||||
}
|
||||
IFX (X_CF) {
|
||||
@@ -1111,7 +1122,7 @@ void emit_adc8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, i
|
||||
ORI(xFlags, xFlags, 1 << F_CF);
|
||||
}
|
||||
|
||||
ANDI(s1, s1, 0xff);
|
||||
ANDI(s1, s1, 0xff); // unneeded?
|
||||
|
||||
IFX (X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
@@ -1141,7 +1152,7 @@ void emit_adc16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4,
|
||||
IFX (X_PEND) {
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
ST_H(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_adc16);
|
||||
SET_DF(s3, d_adc16b);
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
@@ -1154,7 +1165,7 @@ void emit_adc16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4,
|
||||
}
|
||||
BSTRPICK_D(s1, s3, 15, 0);
|
||||
IFX (X_PEND) {
|
||||
ST_W(s1, xEmu, offsetof(x64emu_t, res));
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
|
||||
return;
|
||||
@@ -1171,7 +1182,8 @@ void emit_adc16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4,
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX (X_PEND) {
|
||||
ST_W(s1, xEmu, offsetof(x64emu_t, res));
|
||||
// d_adc16 will use 32bits result to check for CF
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX (X_AF | X_OF) {
|
||||
ANDN(s3, s4, s1); // s3 = ~res & (op1 | op2)
|
||||
@@ -1186,8 +1198,7 @@ void emit_adc16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4,
|
||||
SRLI_D(s4, s3, 1);
|
||||
XOR(s3, s3, s4);
|
||||
ANDI(s3, s3, 1); // OF: xor of two MSB's of cc
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_OF);
|
||||
BSTRINS_D(xFlags, s3, F_OF, F_OF);
|
||||
}
|
||||
}
|
||||
IFX (X_CF) {
|
||||
@@ -1196,7 +1207,7 @@ void emit_adc16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4,
|
||||
ORI(xFlags, xFlags, 1 << F_CF);
|
||||
}
|
||||
|
||||
BSTRPICK_D(s1, s1, 15, 0);
|
||||
BSTRPICK_D(s1, s1, 15, 0); // unneeded?
|
||||
|
||||
IFX (X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
@@ -1300,8 +1311,7 @@ void emit_adc32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
SRLI_D(s4, s3, 1);
|
||||
XOR(s3, s3, s4);
|
||||
ANDI(s3, s3, 1); // OF: xor of two MSB's of cc
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_OF);
|
||||
BSTRINS_D(xFlags, s3, F_OF, F_OF);
|
||||
}
|
||||
}
|
||||
IFX (X_SF) {
|
||||
@@ -1324,13 +1334,7 @@ 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)
|
||||
{
|
||||
IFX (X_PEND) {
|
||||
ST_B(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s3, d_inc8);
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
SET_DFNONE();
|
||||
IFXA (X_ALL, !cpuext.lbt) {
|
||||
// preserving CF
|
||||
MOV64x(s4, (1UL << F_AF) | (1UL << F_OF) | (1UL << F_ZF) | (1UL << F_SF) | (1UL << F_PF));
|
||||
@@ -1347,11 +1351,6 @@ void emit_inc8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
|
||||
ADDI_W(s1, s1, 1);
|
||||
|
||||
IFX (X_PEND) {
|
||||
ST_B(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
|
||||
if (cpuext.lbt) {
|
||||
ANDI(s1, s1, 0xff);
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
|
||||
@@ -1371,8 +1370,7 @@ void emit_inc8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
SRLI_D(s2, s3, 1);
|
||||
XOR(s3, s3, s2);
|
||||
ANDI(s3, s3, 1); // OF: xor of two MSB's of cc
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_OF);
|
||||
BSTRINS_D(xFlags, s3, F_OF, F_OF);
|
||||
}
|
||||
}
|
||||
IFX (X_SF) {
|
||||
@@ -1394,13 +1392,7 @@ 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)
|
||||
{
|
||||
IFX (X_PEND) {
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s3, d_inc16);
|
||||
} else IFXORNAT (X_ZF | X_OF | X_AF | X_SF | X_PF) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
SET_DFNONE();
|
||||
IFXA (X_ALL, !cpuext.lbt) {
|
||||
// preserving CF
|
||||
MOV64x(s4, (1UL << F_AF) | (1UL << F_OF) | (1UL << F_ZF) | (1UL << F_SF) | (1UL << F_PF));
|
||||
@@ -1417,11 +1409,6 @@ void emit_inc16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
|
||||
ADDI_D(s1, s1, 1);
|
||||
|
||||
IFX (X_PEND) {
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
|
||||
if (cpuext.lbt) {
|
||||
BSTRPICK_D(s1, s1, 15, 0);
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
|
||||
@@ -1441,8 +1428,7 @@ void emit_inc16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
SRLI_D(s4, s3, 1);
|
||||
XOR(s3, s3, s4);
|
||||
ANDI(s3, s3, 1); // OF: xor of two MSB's of cc
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_OF);
|
||||
BSTRINS_D(xFlags, s3, F_OF, F_OF);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1466,13 +1452,7 @@ 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)
|
||||
{
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s3, rex.w ? d_inc64 : d_inc32);
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
SET_DFNONE();
|
||||
IFXA (X_ALL, !cpuext.lbt) {
|
||||
// preserving CF
|
||||
MOV64x(s4, (1UL << F_AF) | (1UL << F_OF) | (1UL << F_ZF) | (1UL << F_SF) | (1UL << F_PF));
|
||||
@@ -1493,11 +1473,6 @@ void emit_inc32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
}
|
||||
|
||||
ADDIxw(s1, s1, 1);
|
||||
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
|
||||
if (cpuext.lbt) {
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
|
||||
@@ -1517,8 +1492,7 @@ void emit_inc32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
SRLI_D(s2, s3, 1);
|
||||
XOR(s3, s3, s2);
|
||||
ANDI(s3, s3, 1); // OF: xor of two MSB's of cc
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_OF);
|
||||
BSTRINS_D(xFlags, s3, F_OF, F_OF);
|
||||
}
|
||||
}
|
||||
IFX (X_SF) {
|
||||
@@ -1541,13 +1515,7 @@ 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)
|
||||
{
|
||||
IFX (X_PEND) {
|
||||
ST_B(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s3, d_dec8);
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
SET_DFNONE();
|
||||
IFXA (X_ALL, !cpuext.lbt) {
|
||||
// preserving CF
|
||||
MOV64x(s4, (1UL << F_AF) | (1UL << F_OF) | (1UL << F_ZF) | (1UL << F_SF) | (1UL << F_PF));
|
||||
@@ -1565,11 +1533,6 @@ void emit_dec8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
|
||||
ADDI_W(s1, s1, -1);
|
||||
|
||||
IFX (X_PEND) {
|
||||
ST_B(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
|
||||
if (cpuext.lbt) {
|
||||
ANDI(s1, s1, 0xff);
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
|
||||
@@ -1589,8 +1552,7 @@ void emit_dec8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
SRLI_D(s2, s3, 1);
|
||||
XOR(s3, s3, s2);
|
||||
ANDI(s3, s3, 1); // OF: xor of two MSB's of cc
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_OF);
|
||||
BSTRINS_D(xFlags, s3, F_OF, F_OF);
|
||||
}
|
||||
}
|
||||
IFX (X_SF) {
|
||||
@@ -1612,34 +1574,23 @@ 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)
|
||||
{
|
||||
IFX (X_PEND) {
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s3, d_dec16);
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
SET_DFNONE();
|
||||
|
||||
if (cpuext.lbt) {
|
||||
IFX (X_ALL) X64_DEC_H(s1);
|
||||
ADDI_W(s1, s1, -1);
|
||||
BSTRPICK_D(s1, s1, 15, 0);
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
|
||||
return;
|
||||
}
|
||||
|
||||
IFX (X_AF | X_OF) {
|
||||
NOR(s5, xZR, s1);
|
||||
ORI(s3, s5, 1); // s3 = ~op1 | op2
|
||||
ANDI(s5, s5, 1); // s5 = ~op1 & op2
|
||||
}
|
||||
|
||||
IFXA (X_ALL, cpuext.lbt) {
|
||||
X64_DEC_H(s1);
|
||||
}
|
||||
|
||||
ADDI_W(s1, s1, -1);
|
||||
|
||||
IFX (X_PEND) {
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
|
||||
if (cpuext.lbt) {
|
||||
BSTRPICK_D(s1, s1, 15, 0);
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
|
||||
return;
|
||||
}
|
||||
|
||||
IFX (X_ALL) {
|
||||
// preserving CF
|
||||
MOV64x(s4, (1UL << F_AF) | (1UL << F_OF) | (1UL << F_ZF) | (1UL << F_SF) | (1UL << F_PF));
|
||||
@@ -1659,16 +1610,13 @@ void emit_dec16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4,
|
||||
SRLI_D(s2, s3, 1);
|
||||
XOR(s3, s3, s2);
|
||||
ANDI(s3, s3, 1); // OF: xor of two MSB's of cc
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_OF);
|
||||
BSTRINS_D(xFlags, s3, F_OF, F_OF);
|
||||
}
|
||||
}
|
||||
SLLI_W(s1, s1, 16);
|
||||
IFX (X_SF) {
|
||||
BGE(s1, xZR, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
BSTRPICK_D(s5, s1, 15, 15);
|
||||
BSTRINS_D(xFlags, s5, F_SF, F_SF);
|
||||
}
|
||||
SRLI_W(s1, s1, 16);
|
||||
IFX (X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s2);
|
||||
}
|
||||
@@ -1682,38 +1630,29 @@ 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)
|
||||
{
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s3, rex.w ? d_dec64 : d_dec32);
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFXA (X_AF | X_OF, !cpuext.lbt) {
|
||||
NOR(s5, xZR, s1);
|
||||
ORI(s3, s5, 1); // s3 = ~op1 | op2
|
||||
ANDI(s5, s5, 1); // s5 = ~op1 & op2
|
||||
}
|
||||
|
||||
IFXA (X_ALL, cpuext.lbt) {
|
||||
if (rex.w) {
|
||||
X64_DEC_D(s1);
|
||||
} else {
|
||||
X64_DEC_W(s1);
|
||||
}
|
||||
}
|
||||
|
||||
ADDIxw(s1, s1, -1);
|
||||
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
|
||||
SET_DFNONE();
|
||||
if (cpuext.lbt) {
|
||||
IFX (X_ALL) {
|
||||
if (rex.w) {
|
||||
X64_DEC_D(s1);
|
||||
} else {
|
||||
X64_DEC_W(s1);
|
||||
}
|
||||
}
|
||||
ADDIxw(s1, s1, -1);
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
|
||||
return;
|
||||
}
|
||||
|
||||
IFX (X_AF | X_OF) {
|
||||
NOR(s5, xZR, s1);
|
||||
ORI(s3, s5, 1); // s3 = ~op1 | op2
|
||||
ANDI(s5, s5, 1); // s5 = ~op1 & op2
|
||||
}
|
||||
|
||||
|
||||
ADDIxw(s1, s1, -1);
|
||||
IFX (X_ALL) {
|
||||
// preserving CF
|
||||
MOV64x(s4, (1UL << F_AF) | (1UL << F_OF) | (1UL << F_ZF) | (1UL << F_SF) | (1UL << F_PF));
|
||||
@@ -1732,17 +1671,14 @@ void emit_dec32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
SRLI_D(s2, s3, 1);
|
||||
XOR(s3, s3, s2);
|
||||
ANDI(s3, s3, 1); // OF: xor of two MSB's of cc
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_OF);
|
||||
BSTRINS_D(xFlags, s3, F_OF, F_OF);
|
||||
}
|
||||
}
|
||||
IFX (X_SF) {
|
||||
BGE(s1, xZR, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
if (!rex.w) {
|
||||
ZEROUP(s1);
|
||||
BSTRPICK_D(s5, s1, rex.w ? 63 : 31, rex.w ? 63 : 31);
|
||||
BSTRINS_D(xFlags, s5, F_SF, F_SF);
|
||||
}
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
IFX (X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s2);
|
||||
}
|
||||
|
||||
@@ -530,6 +530,145 @@ void emit_sar8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, i
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
|
||||
}
|
||||
|
||||
// emit SHL8 instruction, from s1 , constant c, store result in s1 using s3, s4 as scratch
|
||||
void emit_shl8c(dynarec_la64_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
if (!c) return;
|
||||
IFX (X_PEND) {
|
||||
MOV64x(s3, c);
|
||||
ST_B(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
ST_B(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s4, d_shl8);
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX (X_OF) {
|
||||
SRLI_D(s3, s1, 6);
|
||||
SRLI_D(s4, s3, 1);
|
||||
XOR(s3, s3, s4);
|
||||
BSTRINS_D(xFlags, s3, F_OF, F_OF);
|
||||
}
|
||||
SLLI_D(s1, s1, c);
|
||||
IFX (X_CF) {
|
||||
BSTRPICK_D(s3, s1, 8, 8);
|
||||
BSTRINS_D(xFlags, s3, F_CF, F_CF);
|
||||
}
|
||||
IFX (X_PEND) {
|
||||
ST_B(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
ANDI(s1, s1, 0xff);
|
||||
IFX (X_SF) {
|
||||
SRLI_D(s3, s1, 7);
|
||||
BSTRINS_D(xFlags, s3, F_SF, F_SF);
|
||||
}
|
||||
IFX (X_ZF) {
|
||||
SEQZ(s3, s1);
|
||||
BSTRINS_D(xFlags, s3, F_ZF, F_ZF);
|
||||
}
|
||||
IFX (X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
IFXA (X_ALL, cpuext.lbt) SPILL_EFLAGS();
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
|
||||
}
|
||||
|
||||
// emit SHR8 instruction, from s1 , constant c, store result in s1 using s3, s4 as scratch
|
||||
void emit_shr8c(dynarec_la64_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
if (!c) return;
|
||||
IFX (X_PEND) {
|
||||
MOV64x(s3, c);
|
||||
ST_B(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
ST_B(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s4, d_shr8);
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX (X_CF) {
|
||||
if (c == 1) {
|
||||
BSTRINS_D(xFlags, s1, F_CF, F_CF);
|
||||
} else {
|
||||
BSTRPICK_D(s3, s1, c - 1, c - 1);
|
||||
BSTRINS_D(xFlags, s3, F_CF, F_CF);
|
||||
}
|
||||
}
|
||||
IFX (X_OF) {
|
||||
BSTRPICK_D(s3, s1, 7, 7);
|
||||
BSTRINS_D(xFlags, s3, F_OF, F_OF);
|
||||
}
|
||||
|
||||
SRLI_D(s1, s1, c);
|
||||
ANDI(s1, s1, 0xff);
|
||||
|
||||
IFX (X_PEND) {
|
||||
ST_B(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX (X_ZF) {
|
||||
SEQZ(s4, s1);
|
||||
BSTRINS_D(xFlags, s4, F_ZF, F_ZF);
|
||||
}
|
||||
IFX (X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
IFXA (X_ALL, cpuext.lbt) SPILL_EFLAGS();
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
|
||||
}
|
||||
|
||||
// emit SAR8 instruction, from s1 , constant c, store result in s1 using s3, s4 as scratch
|
||||
void emit_sar8c(dynarec_la64_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
if (!c) return;
|
||||
IFX (X_PEND) {
|
||||
MOV64x(s3, c);
|
||||
ST_B(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
ST_B(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s4, d_sar8);
|
||||
} else IFXORNAT (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
CLEAR_FLAGS(s3);
|
||||
IFXA (X_CF, c < 8) {
|
||||
BSTRPICK_D(s3, s1, c - 1, c - 1);
|
||||
BSTRINS_D(xFlags, s3, F_CF, F_CF);
|
||||
}
|
||||
|
||||
SRAI_D(s1, s1, c);
|
||||
ANDI(s1, s1, 0xff);
|
||||
IFX (X_PEND) {
|
||||
ST_B(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
if (c < 8) {
|
||||
IFX (X_ZF) {
|
||||
SEQZ(s3, s1);
|
||||
BSTRINS_D(xFlags, s3, F_ZF, F_ZF);
|
||||
}
|
||||
IFX (X_SF) {
|
||||
SRLI_D(s3, s1, 7);
|
||||
BSTRINS_D(xFlags, s3, F_SF, F_SF);
|
||||
}
|
||||
IFX (X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
} else {
|
||||
IFX (X_CF | X_ZF | X_SF | X_PF) {
|
||||
SRLI_D(s3, s1, 7);
|
||||
IFX (X_CF) BSTRINS_D(xFlags, s3, F_CF, F_CF);
|
||||
IFX (X_SF) BSTRINS_D(xFlags, s3, F_SF, F_SF);
|
||||
IFX (X_ZF) {
|
||||
SEQZ(s4, s1);
|
||||
BSTRINS_D(xFlags, s4, F_ZF, F_ZF);
|
||||
}
|
||||
IFX (X_PF) ORI(xFlags, xFlags, 1 << F_PF);
|
||||
}
|
||||
}
|
||||
|
||||
IFXA (X_ALL, cpuext.lbt) SPILL_EFLAGS();
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
@@ -1087,7 +1226,6 @@ void emit_ror32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
|
||||
{
|
||||
if (!c) return;
|
||||
|
||||
IFXORNAT (X_ALL) SET_DFNONE();
|
||||
IFXA ((X_CF | X_OF), cpuext.lbt) {
|
||||
if (rex.w)
|
||||
X64_ROTRI_D(s1, c);
|
||||
@@ -1128,7 +1266,6 @@ void emit_ror32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
|
||||
// emit ROL8 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
|
||||
void emit_rol8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFXORNAT (X_ALL) SET_DFNONE();
|
||||
RESTORE_EFLAGS(s3);
|
||||
|
||||
IFX (X_OF) {
|
||||
@@ -1139,8 +1276,7 @@ void emit_rol8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
ADDI_D(s4, xZR, 8);
|
||||
SUB_D(s4, s4, s2);
|
||||
SLLI_D(s3, s1, 8);
|
||||
OR(s1, s3, s1);
|
||||
BSTRINS_D(s1, s1, 15, 8);
|
||||
SRL_D(s1, s1, s4);
|
||||
IFX (X_CF) {
|
||||
BSTRINS_D(xFlags, s1, F_CF, F_CF);
|
||||
@@ -1203,7 +1339,6 @@ void emit_rol8c(dynarec_la64_t* dyn, int ninst, int s1, uint32_t c, int s3, int
|
||||
void emit_rol16c(dynarec_la64_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4, int s5)
|
||||
{
|
||||
if (!c) return;
|
||||
IFXORNAT (X_ALL) SET_DFNONE();
|
||||
RESTORE_EFLAGS(s3);
|
||||
|
||||
IFXA (X_OF, c == 1) {
|
||||
@@ -1236,7 +1371,6 @@ void emit_rol16c(dynarec_la64_t* dyn, int ninst, int s1, uint32_t c, int s3, int
|
||||
// emit ROL32 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
|
||||
void emit_rol32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFXORNAT (X_ALL) SET_DFNONE();
|
||||
IFXA (X_CF | X_OF, !cpuext.lbt) {
|
||||
MOV64x(s4, ((1UL << F_CF) | (1UL << F_OF)));
|
||||
ANDN(xFlags, xFlags, s4);
|
||||
@@ -1285,7 +1419,6 @@ void emit_rol32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
// emit ROR32 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
|
||||
void emit_ror32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFXORNAT (X_ALL) SET_DFNONE();
|
||||
IFXA ((X_CF | X_OF), cpuext.lbt) {
|
||||
if (rex.w)
|
||||
X64_ROTR_D(s1, s2);
|
||||
@@ -1332,7 +1465,6 @@ void emit_rol32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
|
||||
{
|
||||
if (!c) return;
|
||||
|
||||
IFXORNAT (X_ALL) SET_DFNONE();
|
||||
IFXA (X_CF | X_OF, !cpuext.lbt) {
|
||||
MOV64x(s3, ((1UL << F_CF) | (1UL << F_OF)));
|
||||
ANDN(xFlags, xFlags, s3);
|
||||
@@ -1583,13 +1715,46 @@ void emit_shld32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
|
||||
}
|
||||
|
||||
// emit RCL8 instruction, from s1, s1, store result in s1 using s3, s4 and s5 as scratch
|
||||
void emit_rcl8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
int64_t j64;
|
||||
RESTORE_EFLAGS(s3);
|
||||
|
||||
ADDI_D(s4, xZR, 9);
|
||||
MOD_DU(s2, s2, s4);
|
||||
CBZ_NEXT(s2);
|
||||
|
||||
IFX (X_OF) {
|
||||
SRLI_D(s3, s1, 6);
|
||||
SRLI_D(s5, s3, 1);
|
||||
XOR(s3, s3, s5);
|
||||
BSTRINS_D(xFlags, s3, F_OF, F_OF);
|
||||
}
|
||||
|
||||
BSTRINS_D(s1, xFlags, 8, 8); // insert CF to bit 8
|
||||
BSTRINS_D(s1, s1, 16, 9);
|
||||
SUB_D(s2, s4, s2);
|
||||
IFX (X_CF) {
|
||||
ADDI_D(s5, s2, -1);
|
||||
SRL_D(s5, s1, s5);
|
||||
BSTRINS_D(xFlags, s5, F_CF, F_CF);
|
||||
}
|
||||
SRL_D(s1, s1, s2);
|
||||
|
||||
IFXA (X_ALL, cpuext.lbt) SPILL_EFLAGS();
|
||||
if (dyn->insts[ninst].nat_flags_fusion) {
|
||||
ANDI(s1, s1, 0xFF);
|
||||
NAT_FLAGS_OPS(s1, xZR, s3, xZR);
|
||||
}
|
||||
}
|
||||
|
||||
// emit RCL8 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_rcl8c(dynarec_la64_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
c %= 9;
|
||||
if (!c) return;
|
||||
|
||||
IFXORNAT (X_ALL) SET_DFNONE();
|
||||
RESTORE_EFLAGS(s3);
|
||||
|
||||
BSTRINS_D(s1, xFlags, 8, 8); // insert CF to bit 8
|
||||
@@ -1605,8 +1770,7 @@ void emit_rcl8c(dynarec_la64_t* dyn, int ninst, int s1, uint32_t c, int s3, int
|
||||
BSTRINS_D(xFlags, s3, F_OF, F_OF);
|
||||
}
|
||||
|
||||
SLLI_D(s3, s1, 9);
|
||||
OR(s1, s3, s1);
|
||||
BSTRINS_D(s1, s1, 16, 9);
|
||||
SRLI_D(s1, s1, 9 - c);
|
||||
|
||||
IFXA (X_ALL, cpuext.lbt) SPILL_EFLAGS();
|
||||
@@ -1622,7 +1786,6 @@ void emit_rcl16c(dynarec_la64_t* dyn, int ninst, int s1, uint32_t c, int s3, int
|
||||
c %= 17;
|
||||
if (!c) return;
|
||||
|
||||
IFXORNAT (X_ALL) SET_DFNONE();
|
||||
RESTORE_EFLAGS(s3);
|
||||
|
||||
BSTRINS_D(s1, xFlags, 16, 16); // insert CF to bit 16
|
||||
@@ -1638,20 +1801,59 @@ void emit_rcl16c(dynarec_la64_t* dyn, int ninst, int s1, uint32_t c, int s3, int
|
||||
BSTRINS_D(xFlags, s3, F_OF, F_OF);
|
||||
}
|
||||
|
||||
SLLI_D(s3, s1, 17);
|
||||
OR(s1, s3, s1);
|
||||
BSTRINS_D(s1, s1, 32, 17);
|
||||
SRLI_D(s1, s1, 17 - c);
|
||||
|
||||
IFXA (X_ALL, cpuext.lbt) SPILL_EFLAGS();
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
|
||||
}
|
||||
|
||||
// emit RCL32 instruction, from s1, s2, store result in s1 using s3, s4 and s5 as scratch
|
||||
void emit_rcl32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
RESTORE_EFLAGS(s3);
|
||||
IFX (X_CF) {
|
||||
ADDI_D(s4, xZR, rex.w ? 64 : 32);
|
||||
SUB_D(s4, s4, s2);
|
||||
SRL_D(s3, s1, s4);
|
||||
}
|
||||
IFX (X_OF) {
|
||||
SRLI_D(s4, s1, rex.w ? 62 : 30);
|
||||
SRLI_D(s5, s4, 1);
|
||||
XOR(s4, s5, s4);
|
||||
BSTRINS_D(xFlags, s4, F_OF, F_OF);
|
||||
}
|
||||
MV(s4, xFlags);
|
||||
BSTRINS_D(s4, s1, rex.w ? 63 : 31, 1);
|
||||
ADDI_D(s5, s2, -1);
|
||||
BEQZ(s5, 4 + 4 * 5); // goto label
|
||||
SLL_D(s4, s4, s5);
|
||||
ADDI_D(s5, xZR, rex.w ? 65 : 33);
|
||||
SUB_D(s2, s5, s2);
|
||||
if (rex.w)
|
||||
SRL_D(s1, s1, s2);
|
||||
else
|
||||
SRL_W(s1, s1, s2);
|
||||
OR(s4, s1, s4);
|
||||
// label
|
||||
if (rex.w)
|
||||
MV(s1, s4);
|
||||
else
|
||||
ZEROUP2(s1, s4);
|
||||
|
||||
IFX (X_CF) {
|
||||
BSTRINS_D(xFlags, s3, F_CF, F_CF);
|
||||
}
|
||||
|
||||
IFXA (X_ALL, cpuext.lbt) SPILL_EFLAGS();
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
|
||||
}
|
||||
|
||||
// emit RCL32 instruction, from s1 , constant c, store result in s1 using s3, s4 and s5 as scratch
|
||||
void emit_rcl32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4, int s5)
|
||||
{
|
||||
if (!c) return;
|
||||
|
||||
IFXORNAT (X_ALL) SET_DFNONE();
|
||||
RESTORE_EFLAGS(s3);
|
||||
IFX (X_CF) {
|
||||
SRLI_D(s3, s1, (rex.w ? 64 : 32) - c);
|
||||
@@ -1685,13 +1887,45 @@ void emit_rcl32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
|
||||
}
|
||||
|
||||
// emit RCR8 instruction, from s1, s2, store result in s1 using s3, s4 and s5 as scratch
|
||||
void emit_rcr8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
|
||||
int64_t j64;
|
||||
RESTORE_EFLAGS(s3);
|
||||
|
||||
ADDI_D(s4, xZR, 9);
|
||||
MOD_DU(s2, s2, s4);
|
||||
CBZ_NEXT(s2);
|
||||
|
||||
BSTRINS_D(s1, xFlags, 8, 8); // insert CF to bit 8
|
||||
BSTRINS_D(s1, s1, 16, 9);
|
||||
|
||||
IFX (X_OF) {
|
||||
SRLI_D(s3, s1, 7);
|
||||
XOR(s3, s3, xFlags);
|
||||
BSTRINS_D(xFlags, s3, F_OF, F_OF);
|
||||
}
|
||||
IFX (X_CF) {
|
||||
ADDI_D(s4, s2, -1);
|
||||
SRL_D(s4, s1, s4);
|
||||
BSTRINS_D(xFlags, s4, F_CF, F_CF);
|
||||
}
|
||||
SRL_D(s1, s1, s2);
|
||||
|
||||
IFXA (X_ALL, cpuext.lbt) SPILL_EFLAGS();
|
||||
if (dyn->insts[ninst].nat_flags_fusion) {
|
||||
ANDI(s1, s1, 0xFF);
|
||||
NAT_FLAGS_OPS(s1, xZR, s3, xZR);
|
||||
}
|
||||
}
|
||||
|
||||
// emit RCR8 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_rcr8c(dynarec_la64_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
c %= 9;
|
||||
if (!c) return;
|
||||
|
||||
IFXORNAT (X_ALL) SET_DFNONE();
|
||||
RESTORE_EFLAGS(s3);
|
||||
IFX (X_OF) {
|
||||
SRLI_D(s3, s1, 7);
|
||||
@@ -1706,8 +1940,7 @@ void emit_rcr8c(dynarec_la64_t* dyn, int ninst, int s1, uint32_t c, int s3, int
|
||||
BSTRINS_D(xFlags, s3, F_CF, F_CF);
|
||||
}
|
||||
if (c > 1) {
|
||||
SLLI_D(s3, s1, 9);
|
||||
OR(s1, s1, s3);
|
||||
BSTRINS_D(s1, s1, 16, 9);
|
||||
}
|
||||
SRLI_D(s1, s1, c);
|
||||
}
|
||||
@@ -1725,7 +1958,6 @@ void emit_rcr16c(dynarec_la64_t* dyn, int ninst, int s1, uint32_t c, int s3, int
|
||||
c %= 17;
|
||||
if (!c) return;
|
||||
|
||||
IFXORNAT (X_ALL) SET_DFNONE();
|
||||
RESTORE_EFLAGS(s3);
|
||||
IFX (X_OF) {
|
||||
SRLI_D(s3, s1, 15);
|
||||
@@ -1739,10 +1971,7 @@ void emit_rcr16c(dynarec_la64_t* dyn, int ninst, int s1, uint32_t c, int s3, int
|
||||
BSTRPICK_D(s3, s1, c - 1, c - 1);
|
||||
BSTRINS_D(xFlags, s3, F_CF, F_CF);
|
||||
}
|
||||
if (c > 1) {
|
||||
SLLI_D(s3, s1, 17);
|
||||
OR(s1, s1, s3);
|
||||
}
|
||||
if (c > 1) BSTRINS_D(s1, s1, 32, 17);
|
||||
SRLI_D(s1, s1, c);
|
||||
}
|
||||
|
||||
@@ -1750,12 +1979,46 @@ void emit_rcr16c(dynarec_la64_t* dyn, int ninst, int s1, uint32_t c, int s3, int
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
|
||||
}
|
||||
|
||||
// emit RCR32 instruction, from s1, s2, store result in s1 using s3, s4 and s5 as scratch
|
||||
void emit_rcr32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
RESTORE_EFLAGS(s3);
|
||||
|
||||
IFX (X_OF) {
|
||||
SRLI_D(s3, s1, rex.w ? 63 : 31);
|
||||
XOR(s3, s3, xFlags);
|
||||
BSTRINS_D(xFlags, s3, F_OF, F_OF);
|
||||
}
|
||||
ADDI_D(s5, s2, -1);
|
||||
IFX (X_CF) SRL_D(s3, s1, s5); // for later
|
||||
|
||||
SRLI_D(s4, s1, 1);
|
||||
BSTRINS_D(s4, xFlags, rex.w ? 63 : 31, rex.w ? 63 : 31); // insert cf
|
||||
BEQZ(s5, 4 + 4 * 5); // goto label
|
||||
SRL_D(s4, s4, s5);
|
||||
ADDI_D(s5, xZR, rex.w ? 65 : 33);
|
||||
SUB_D(s2, s5, s2);
|
||||
if (rex.w)
|
||||
SLL_D(s1, s1, s2);
|
||||
else
|
||||
SLL_W(s1, s1, s2);
|
||||
OR(s4, s1, s4);
|
||||
// label
|
||||
if (rex.w)
|
||||
MV(s1, s4);
|
||||
else
|
||||
ZEROUP2(s1, s4);
|
||||
|
||||
IFX (X_CF) BSTRINS_D(xFlags, s3, F_CF, F_CF);
|
||||
IFXA (X_ALL, cpuext.lbt) SPILL_EFLAGS();
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
|
||||
}
|
||||
|
||||
// emit RCR32 instruction, from s1 , constant c, store result in s1 using s3, s4 and s5 as scratch
|
||||
void emit_rcr32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4, int s5)
|
||||
{
|
||||
if (!c) return;
|
||||
|
||||
IFXORNAT (X_ALL) SET_DFNONE();
|
||||
RESTORE_EFLAGS(s3);
|
||||
IFX (X_OF) {
|
||||
SRLI_D(s3, s1, rex.w ? 63 : 31);
|
||||
@@ -1785,7 +2048,6 @@ void emit_rcr32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
|
||||
// emit ROR8 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
|
||||
void emit_ror8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFXORNAT (X_ALL) SET_DFNONE();
|
||||
RESTORE_EFLAGS(s3);
|
||||
|
||||
IFX (X_OF) {
|
||||
@@ -1794,8 +2056,7 @@ void emit_ror8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
BSTRINS_D(xFlags, s3, F_OF, F_OF);
|
||||
}
|
||||
|
||||
SLLI_D(s3, s1, 8);
|
||||
OR(s1, s1, s3);
|
||||
BSTRINS_D(s1, s1, 15, 8);
|
||||
SRL_D(s1, s1, s2);
|
||||
|
||||
IFX (X_CF) {
|
||||
@@ -1814,7 +2075,6 @@ void emit_ror8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
void emit_ror8c(dynarec_la64_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
if (!c) return;
|
||||
IFXORNAT (X_ALL) SET_DFNONE();
|
||||
RESTORE_EFLAGS(s3);
|
||||
|
||||
IFX (X_OF) {
|
||||
@@ -1824,8 +2084,7 @@ void emit_ror8c(dynarec_la64_t* dyn, int ninst, int s1, uint32_t c, int s3, int
|
||||
}
|
||||
|
||||
if (c & 7) {
|
||||
SLLI_D(s3, s1, 8);
|
||||
OR(s1, s3, s1);
|
||||
BSTRINS_D(s1, s1, 15, 8);
|
||||
SRLI_D(s1, s1, c & 7);
|
||||
}
|
||||
IFX (X_CF) {
|
||||
@@ -1844,7 +2103,6 @@ void emit_ror8c(dynarec_la64_t* dyn, int ninst, int s1, uint32_t c, int s3, int
|
||||
void emit_ror16c(dynarec_la64_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
if (!c) return;
|
||||
IFXORNAT (X_ALL) SET_DFNONE();
|
||||
RESTORE_EFLAGS(s3);
|
||||
IFXA (X_OF, (c == 1)) {
|
||||
SRLI_D(s3, s1, 15);
|
||||
@@ -2117,3 +2375,124 @@ void emit_shrd16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4,
|
||||
IFXA (X_ALL, cpuext.lbt) SPILL_EFLAGS();
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s1, xZR, s3, xZR);
|
||||
}
|
||||
|
||||
// emit ROL16 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
|
||||
void emit_rol16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
RESTORE_EFLAGS(s3);
|
||||
|
||||
ANDI(s2, s2, 0xf);
|
||||
IFX (X_OF) {
|
||||
SRLI_W(s3, s1, 14);
|
||||
SRLI_D(s4, s3, 1);
|
||||
XOR(s3, s3, s4);
|
||||
BSTRINS_D(xFlags, s3, F_OF, F_OF);
|
||||
}
|
||||
|
||||
ADDI_D(s4, xZR, 16);
|
||||
SUB_D(s4, s4, s2);
|
||||
BSTRINS_D(s1, s1, 31, 16);
|
||||
SRL_D(s1, s1, s4);
|
||||
IFX (X_CF) {
|
||||
BSTRINS_D(xFlags, s1, F_CF, F_CF);
|
||||
}
|
||||
|
||||
IFXA (X_ALL, cpuext.lbt) SPILL_EFLAGS();
|
||||
if (dyn->insts[ninst].nat_flags_fusion) {
|
||||
BSTRPICK_D(s1, s1, 15, 0);
|
||||
NAT_FLAGS_OPS(s1, xZR, s3, xZR);
|
||||
}
|
||||
}
|
||||
|
||||
// emit ROR16 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
|
||||
void emit_ror16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
RESTORE_EFLAGS(s3);
|
||||
|
||||
ANDI(s2, s2, 0xf);
|
||||
IFX (X_OF) {
|
||||
SRLI_D(s3, s1, 15);
|
||||
XOR(s3, s1, s3);
|
||||
BSTRINS_D(xFlags, s3, F_OF, F_OF);
|
||||
}
|
||||
|
||||
BSTRINS_D(s1, s1, 31, 16);
|
||||
SRL_D(s1, s1, s2);
|
||||
|
||||
IFX (X_CF) {
|
||||
SRLI_D(s3, s1, 15);
|
||||
BSTRINS_D(xFlags, s3, F_CF, F_CF);
|
||||
}
|
||||
|
||||
IFXA (X_ALL, cpuext.lbt) SPILL_EFLAGS();
|
||||
if (dyn->insts[ninst].nat_flags_fusion) {
|
||||
BSTRPICK_D(s1, s1, 15, 0);
|
||||
NAT_FLAGS_OPS(s1, xZR, s3, xZR);
|
||||
}
|
||||
}
|
||||
|
||||
// emit RCL16 instruction, from s1, s1, store result in s1 using s3, s4 and s5 as scratch
|
||||
void emit_rcl16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
int64_t j64;
|
||||
RESTORE_EFLAGS(s3);
|
||||
|
||||
ADDI_D(s4, xZR, 17);
|
||||
MOD_DU(s2, s2, s4);
|
||||
CBZ_NEXT(s2);
|
||||
|
||||
IFX (X_OF) {
|
||||
SRLI_D(s3, s1, 14);
|
||||
SRLI_D(s5, s3, 1);
|
||||
XOR(s3, s3, s5);
|
||||
BSTRINS_D(xFlags, s3, F_OF, F_OF);
|
||||
}
|
||||
|
||||
BSTRINS_D(s1, xFlags, 16, 16); // insert CF to bit 16
|
||||
BSTRINS_D(s1, s1, 32, 17);
|
||||
SUB_D(s2, s4, s2);
|
||||
IFX (X_CF) {
|
||||
ADDI_D(s5, s2, -1);
|
||||
SRL_D(s5, s1, s5);
|
||||
BSTRINS_D(xFlags, s5, F_CF, F_CF);
|
||||
}
|
||||
SRL_D(s1, s1, s2);
|
||||
IFXA (X_ALL, cpuext.lbt) SPILL_EFLAGS();
|
||||
if (dyn->insts[ninst].nat_flags_fusion) {
|
||||
BSTRPICK_D(s1, s1, 15, 0);
|
||||
NAT_FLAGS_OPS(s1, xZR, s3, xZR);
|
||||
}
|
||||
}
|
||||
|
||||
// emit RCR16 instruction, from s1, s2, store result in s1 using s3, s4 and s5 as scratch
|
||||
void emit_rcr16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
|
||||
int64_t j64;
|
||||
RESTORE_EFLAGS(s3);
|
||||
|
||||
ADDI_D(s4, xZR, 17);
|
||||
MOD_DU(s2, s2, s4);
|
||||
CBZ_NEXT(s2);
|
||||
|
||||
BSTRINS_D(s1, xFlags, 16, 16); // insert CF to bit 16
|
||||
BSTRINS_D(s1, s1, 32, 17);
|
||||
|
||||
IFX (X_OF) {
|
||||
SRLI_D(s3, s1, 15);
|
||||
XOR(s3, s3, xFlags);
|
||||
BSTRINS_D(xFlags, s3, F_OF, F_OF);
|
||||
}
|
||||
IFX (X_CF) {
|
||||
ADDI_D(s4, s2, -1);
|
||||
SRL_D(s4, s1, s4);
|
||||
BSTRINS_D(xFlags, s4, F_CF, F_CF);
|
||||
}
|
||||
SRL_D(s1, s1, s2);
|
||||
|
||||
IFXA (X_ALL, cpuext.lbt) SPILL_EFLAGS();
|
||||
if (dyn->insts[ninst].nat_flags_fusion) {
|
||||
BSTRPICK_D(s1, s1, 15, 0);
|
||||
NAT_FLAGS_OPS(s1, xZR, s3, xZR);
|
||||
}
|
||||
}
|
||||
@@ -392,13 +392,8 @@ void emit_cmp32_0(dynarec_la64_t* dyn, int ninst, rex_t rex, uint8_t nextop, int
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX(X_SF) {
|
||||
if (rex.w) {
|
||||
BGE(s1, xZR, 8);
|
||||
} else {
|
||||
SRLI_D(s3, s1, 31);
|
||||
BEQZ(s3, 8);
|
||||
}
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
BSTRPICK_D(s3, s1, rex.w ? 63 : 31, rex.w ? 63 : 31);
|
||||
BSTRINS_D(xFlags, s3, F_SF, F_SF);
|
||||
}
|
||||
int res = s1;
|
||||
IFX (X_ZF | X_PF) {
|
||||
@@ -446,19 +441,33 @@ void emit_test8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4,
|
||||
IFX(X_ALL) {
|
||||
X64_AND_B(s1, s2);
|
||||
}
|
||||
|
||||
if (dyn->insts[ninst].nat_flags_fusion) {
|
||||
AND(s3, s1, s2);
|
||||
if (dyn->insts[ninst].nat_flags_needsign) {
|
||||
EXT_W_B(s3, s3);
|
||||
if (s1 == s2) {
|
||||
NAT_FLAGS_ENABLE_SF();
|
||||
int r = s1;
|
||||
if (dyn->insts[ninst].nat_flags_fusion) {
|
||||
if (dyn->insts[ninst].nat_flags_needsign) {
|
||||
EXT_W_B(s3, s1);
|
||||
r = s3;
|
||||
}
|
||||
NAT_FLAGS_OPS(r, xZR, s5, xZR);
|
||||
}
|
||||
IFX_PENDOR0 {
|
||||
ST_B(r, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
} else {
|
||||
if (dyn->insts[ninst].nat_flags_fusion) {
|
||||
AND(s3, s1, s2);
|
||||
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));
|
||||
IFX_PENDOR0 {
|
||||
if (!dyn->insts[ninst].nat_flags_fusion) AND(s3, s1, s2);
|
||||
ST_B(s3, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s3, xZR, s4, xZR);
|
||||
}
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s3, xZR, s4, xZR);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -557,18 +566,33 @@ void emit_test16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4,
|
||||
X64_AND_H(s1, s2);
|
||||
}
|
||||
|
||||
if (dyn->insts[ninst].nat_flags_fusion) {
|
||||
AND(s3, s1, s2);
|
||||
if (dyn->insts[ninst].nat_flags_needsign) {
|
||||
EXT_W_H(s3, s3);
|
||||
if (s1 == s2) {
|
||||
NAT_FLAGS_ENABLE_SF();
|
||||
int r = s1;
|
||||
if (dyn->insts[ninst].nat_flags_fusion) {
|
||||
if (dyn->insts[ninst].nat_flags_needsign) {
|
||||
EXT_W_H(s3, s1);
|
||||
r = s3;
|
||||
}
|
||||
NAT_FLAGS_OPS(r, xZR, s5, xZR);
|
||||
}
|
||||
IFX_PENDOR0 {
|
||||
ST_H(r, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
} else {
|
||||
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));
|
||||
IFX_PENDOR0 {
|
||||
if (!dyn->insts[ninst].nat_flags_fusion) AND(s3, s1, s2);
|
||||
ST_H(s3, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s3, xZR, xZR, xZR);
|
||||
}
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s3, xZR, xZR, xZR);
|
||||
return;
|
||||
}
|
||||
CLEAR_FLAGS(s3);
|
||||
@@ -614,20 +638,39 @@ void emit_test32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int
|
||||
X64_AND_W(s1, s2);
|
||||
}
|
||||
|
||||
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);
|
||||
if (s1 == s2) {
|
||||
NAT_FLAGS_ENABLE_SF();
|
||||
int r = s1;
|
||||
if (dyn->insts[ninst].nat_flags_fusion) {
|
||||
if (!rex.w) {
|
||||
if (dyn->insts[ninst].nat_flags_needsign)
|
||||
SEXT_W(s3, s1);
|
||||
else
|
||||
ZEROUP2(s3, s1);
|
||||
r = s3;
|
||||
}
|
||||
NAT_FLAGS_OPS(r, xZR, s5, xZR);
|
||||
}
|
||||
IFX_PENDOR0 {
|
||||
SDxw(r, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
} else {
|
||||
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));
|
||||
}
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s3, xZR, xZR, xZR);
|
||||
}
|
||||
|
||||
IFX_PENDOR0 {
|
||||
if (!dyn->insts[ninst].nat_flags_fusion) AND(s3, s1, s2);
|
||||
SDxw(s3, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
if (dyn->insts[ninst].nat_flags_fusion) NAT_FLAGS_OPS(s3, xZR, xZR, xZR);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -58,6 +58,7 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
|
||||
if (cpuext.lam_bh) {
|
||||
AMADD_DB_B(x1, gd, wback);
|
||||
ANDI(x1, x1, 0xff);
|
||||
} else {
|
||||
LOCK_8_OP(ADD_D(x4, x1, gd), x1, wback, x3, x4, x5, x6);
|
||||
}
|
||||
@@ -801,6 +802,9 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
MV(x6, wback);
|
||||
BSTRINS_D(x6, xZR, 1, 0);
|
||||
SLL_W(x4, gd, x3);
|
||||
ADDI_D(x5, xZR, 0xFF);
|
||||
SLL_W(x5, x5, x3);
|
||||
ORN(x4, x4, x5);
|
||||
AMAND_DB_W(x1, x4, x6);
|
||||
IFXORNAT (X_ALL | X_PEND) {
|
||||
SRL_W(x1, x1, x3);
|
||||
@@ -991,7 +995,10 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
MV(x3, wback);
|
||||
BSTRINS_D(x3, xZR, 1, 0);
|
||||
ADDI_D(x1, xZR, u8);
|
||||
SLL_D(x1, x1, x2);
|
||||
SLL_W(x4, x1, x2);
|
||||
ADDI_D(x5, xZR, 0xFF);
|
||||
SLL_W(x5, x5, x2);
|
||||
ORN(x1, x4, x5);
|
||||
AMAND_DB_W(x4, x1, x3);
|
||||
IFXORNAT (X_ALL | X_PEND) {
|
||||
SRL_D(x1, x4, x2);
|
||||
@@ -1126,6 +1133,7 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
INST_NAME("LOCK ADC Ed, Ib");
|
||||
}
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, (opcode == 0x81) ? 4 : 1);
|
||||
if (cpuext.lbt) {
|
||||
@@ -1186,6 +1194,7 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
INST_NAME("LOCK SBB Ed, Ib");
|
||||
}
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING, NAT_FLAGS_FUSION);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, (opcode == 0x81) ? 4 : 1);
|
||||
if (cpuext.lbt) {
|
||||
@@ -1497,11 +1506,11 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
BNEZ_MARK2(x3);
|
||||
}
|
||||
if (cpuext.lamcas) {
|
||||
LD_D(x5, wback, 0);
|
||||
SUB_D(x4, xZR, x5);
|
||||
MV(x6, x5);
|
||||
AMCAS_DB_D(x5, x4, wback);
|
||||
BNE(x6, x5, -4 * 3);
|
||||
LD_D(x1, wback, 0);
|
||||
SUB_D(x4, xZR, x1);
|
||||
MV(x6, x1);
|
||||
AMCAS_DB_D(x1, x4, wback);
|
||||
BNE(x6, x1, -4 * 3);
|
||||
} else {
|
||||
LL_D(x1, wback, 0);
|
||||
SUB_D(x4, xZR, x1);
|
||||
@@ -1516,11 +1525,11 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
}
|
||||
// aligned 4byte
|
||||
if (cpuext.lamcas) {
|
||||
LD_WU(x5, wback, 0);
|
||||
SUB_W(x4, xZR, x5);
|
||||
MV(x6, x5);
|
||||
AMCAS_DB_W(x5, x4, wback);
|
||||
BNE(x6, x5, -4 * 3);
|
||||
LD_WU(x1, wback, 0);
|
||||
SUB_W(x4, xZR, x1);
|
||||
SEXT_W(x6, x1);
|
||||
AMCAS_DB_W(x1, x4, wback);
|
||||
BNE(x6, x1, -4 * 3);
|
||||
} else {
|
||||
LL_W(x1, wback, 0);
|
||||
SUB_W(x4, xZR, x1);
|
||||
@@ -1562,11 +1571,12 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
*ok = 0;
|
||||
} else {
|
||||
INST_NAME("LOCK INC Eb");
|
||||
SETFLAGS(X_ALL & ~X_CF, SF_SUBSET_PENDING, NAT_FLAGS_FUSION);
|
||||
SETFLAGS(X_ALL & ~X_CF, SF_SUBSET, NAT_FLAGS_FUSION);
|
||||
MOV64x(x7, 1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
|
||||
if (cpuext.lam_bh) {
|
||||
AMADD_DB_B(x1, x7, wback);
|
||||
ANDI(x1, x1, 0xff);
|
||||
} else {
|
||||
LOCK_8_OP(ADD_D(x4, x1, x7), x1, wback, x3, x4, x5, x6);
|
||||
}
|
||||
@@ -1583,11 +1593,12 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
*ok = 0;
|
||||
} else {
|
||||
INST_NAME("LOCK DEC Eb");
|
||||
SETFLAGS(X_ALL & ~X_CF, SF_SUBSET_PENDING, NAT_FLAGS_FUSION);
|
||||
SETFLAGS(X_ALL & ~X_CF, SF_SUBSET, NAT_FLAGS_FUSION);
|
||||
MOV64x(x7, -1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
|
||||
if (cpuext.lam_bh) {
|
||||
AMADD_DB_B(x1, x7, wback);
|
||||
ANDI(x1, x1, 0xff);
|
||||
} else {
|
||||
LOCK_8_OP(ADD_D(x4, x1, x7), x1, wback, x3, x4, x5, x6);
|
||||
}
|
||||
@@ -1612,7 +1623,7 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
*ok = 0;
|
||||
} else {
|
||||
INST_NAME("LOCK INC Ed");
|
||||
SETFLAGS(X_ALL & ~X_CF, SF_SUBSET_PENDING, NAT_FLAGS_FUSION);
|
||||
SETFLAGS(X_ALL & ~X_CF, SF_SUBSET, NAT_FLAGS_FUSION);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
|
||||
if (rex.w) {
|
||||
if (!ALIGNED_ATOMICxw) {
|
||||
@@ -1657,7 +1668,7 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
*ok = 0;
|
||||
} else {
|
||||
INST_NAME("LOCK DEC Ed");
|
||||
SETFLAGS(X_ALL & ~X_CF, SF_SUBSET_PENDING, NAT_FLAGS_FUSION);
|
||||
SETFLAGS(X_ALL & ~X_CF, SF_SUBSET, NAT_FLAGS_FUSION);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
|
||||
if (rex.w) {
|
||||
if (!ALIGNED_ATOMICxw) {
|
||||
|
||||
@@ -220,13 +220,20 @@ uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
FADD_D(d0, v0, v1);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
FCMP_D(fcc0, v0, v1, cUN);
|
||||
BCNEZ_MARK(fcc0);
|
||||
FCMP_D(fcc1, d0, d0, cOR);
|
||||
BCNEZ_MARK(fcc1);
|
||||
FNEG_D(d0, d0);
|
||||
MARK;
|
||||
MOVFR2GR_D(x4, v0);
|
||||
MOV64x(x5, 0x0008000000000000LL);
|
||||
OR(x4, x4, x5);
|
||||
MOVGR2FR_D(d1, x4);
|
||||
FCMP_D(fcc0, v0, v0, cUN);
|
||||
FSEL(d0, d0, d1, fcc0);
|
||||
}
|
||||
MARK;
|
||||
VEXTRINS_D(v0, d0, 0); // v0[63:0] = d0[63:0]
|
||||
break;
|
||||
case 0x59:
|
||||
@@ -237,13 +244,20 @@ uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
FMUL_D(d0, v0, v1);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
FCMP_D(fcc0, v0, v1, cUN);
|
||||
BCNEZ_MARK(fcc0);
|
||||
FCMP_D(fcc1, d0, d0, cOR);
|
||||
BCNEZ_MARK(fcc1);
|
||||
FNEG_D(d0, d0);
|
||||
MARK;
|
||||
MOVFR2GR_D(x4, v0);
|
||||
MOV64x(x5, 0x0008000000000000LL);
|
||||
OR(x4, x4, x5);
|
||||
MOVGR2FR_D(d1, x4);
|
||||
FCMP_D(fcc0, v0, v0, cUN);
|
||||
FSEL(d0, d0, d1, fcc0);
|
||||
}
|
||||
MARK;
|
||||
VEXTRINS_D(v0, d0, 0); // v0[63:0] = d0[63:0]
|
||||
break;
|
||||
case 0x5A:
|
||||
@@ -263,13 +277,20 @@ uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
FSUB_D(d0, v0, v1);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
FCMP_D(fcc0, v0, v1, cUN);
|
||||
BCNEZ_MARK(fcc0);
|
||||
FCMP_D(fcc1, d0, d0, cOR);
|
||||
BCNEZ_MARK(fcc1);
|
||||
FNEG_D(d0, d0);
|
||||
MARK;
|
||||
MOVFR2GR_D(x4, v0);
|
||||
MOV64x(x5, 0x0008000000000000LL);
|
||||
OR(x4, x4, x5);
|
||||
MOVGR2FR_D(d1, x4);
|
||||
FCMP_D(fcc0, v0, v0, cUN);
|
||||
FSEL(d0, d0, d1, fcc0);
|
||||
}
|
||||
MARK;
|
||||
VEXTRINS_D(v0, d0, 0); // v0[63:0] = d0[63:0]
|
||||
break;
|
||||
case 0x5D:
|
||||
@@ -293,13 +314,20 @@ uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
FDIV_D(d0, v0, v1);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
FCMP_D(fcc0, v0, v1, cUN);
|
||||
BCNEZ_MARK(fcc0);
|
||||
FCMP_D(fcc1, d0, d0, cOR);
|
||||
BCNEZ_MARK(fcc1);
|
||||
FNEG_D(d0, d0);
|
||||
MARK;
|
||||
MOVFR2GR_D(x4, v0);
|
||||
MOV64x(x5, 0x0008000000000000LL);
|
||||
OR(x4, x4, x5);
|
||||
MOVGR2FR_D(d1, x4);
|
||||
FCMP_D(fcc0, v0, v0, cUN);
|
||||
FSEL(d0, d0, d1, fcc0);
|
||||
}
|
||||
MARK;
|
||||
VEXTRINS_D(v0, d0, 0); // v0[63:0] = d0[63:0]
|
||||
break;
|
||||
case 0x5F:
|
||||
@@ -339,7 +367,24 @@ uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
VPICKEV_W(v0, q1, q0);
|
||||
VPICKOD_W(v1, q1, q0);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
VFCMP_S(d0, v0, v0, cUN);
|
||||
MOV32w(x5, 0x00400000);
|
||||
VREPLGR2VR_W(d1, x5);
|
||||
VOR_V(d1, v0, d1);
|
||||
}
|
||||
VFADD_S(q0, v0, v1);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
VBITSEL_V(q0, q0, d1, d0);
|
||||
VFCMP_S(d1, q0, q0, cUN);
|
||||
VFCMP_S(d0, v0, v1, cUN);
|
||||
VANDN_V(d0, d0, d1);
|
||||
VLDI(d1, 0b011111111100);
|
||||
VSLLI_W(d1, d1, 20);
|
||||
VBITSEL_V(q0, q0, d1, d0);
|
||||
}
|
||||
break;
|
||||
case 0x7D:
|
||||
INST_NAME("HSUBPS Gx, Ex");
|
||||
@@ -350,7 +395,24 @@ uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
VPICKEV_W(v0, q1, q0);
|
||||
VPICKOD_W(v1, q1, q0);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
VFCMP_S(d0, v0, v0, cUN);
|
||||
MOV32w(x5, 0x00400000);
|
||||
VREPLGR2VR_W(d1, x5);
|
||||
VOR_V(d1, v0, d1);
|
||||
}
|
||||
VFSUB_S(q0, v0, v1);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
VBITSEL_V(q0, q0, d1, d0);
|
||||
VFCMP_S(d1, q0, q0, cUN);
|
||||
VFCMP_S(d0, v0, v1, cUN);
|
||||
VANDN_V(d0, d0, d1);
|
||||
VLDI(d1, 0b011111111100);
|
||||
VSLLI_W(d1, d1, 20);
|
||||
VBITSEL_V(q0, q0, d1, d0);
|
||||
}
|
||||
break;
|
||||
case 0xAE:
|
||||
nextop = F8;
|
||||
@@ -391,11 +453,29 @@ uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
VFCMP_S(d0, q0, q1, cUN);
|
||||
VFCMP_S(d1, q0, q0, cUN);
|
||||
MOV32w(x5, 0x00400000);
|
||||
VREPLGR2VR_W(v1, x5);
|
||||
VOR_V(v1, q0, v1);
|
||||
}
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
VFSUB_S(v0, q0, q1);
|
||||
VFADD_S(q0, q0, q1);
|
||||
VEXTRINS_W(q0, v0, 0);
|
||||
VEXTRINS_W(q0, v0, 0b00100010);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
VBITSEL_V(q0, q0, v1, d1);
|
||||
VFCMP_S(d1, q0, q0, cUN);
|
||||
VANDN_V(d0, d0, d1);
|
||||
VLDI(d1, 0b011111111100);
|
||||
VSLLI_W(d1, d1, 20);
|
||||
VBITSEL_V(q0, q0, d1, d0);
|
||||
}
|
||||
break;
|
||||
case 0xD6:
|
||||
INST_NAME("MOVDQ2Q Gm, Ex");
|
||||
@@ -404,13 +484,26 @@ uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETEXSD(v1, 0, 0);
|
||||
FMOV_D(v0, v1);
|
||||
break;
|
||||
case 0xE6: // TODO: !fastround
|
||||
case 0xE6:
|
||||
INST_NAME("CVTPD2DQ Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(v1, 0, 0);
|
||||
GETGX_empty(v0);
|
||||
u8 = sse_setround(dyn, ninst, x1, x2);
|
||||
VFTINT_W_D(v0, v1, v1);
|
||||
if (BOX64ENV(dynarec_fastround)) {
|
||||
VFTINT_W_D(v0, v1, v1);
|
||||
} else {
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
VFTINT_W_D(d0, v1, v1);
|
||||
VLDI(q0, 0b1001110000000); // broadcast 32bit 0x80000000 to all
|
||||
LU52I_D(x5, xZR, 0x41e);
|
||||
VREPLGR2VR_D(q1, x5);
|
||||
VFCMP_D(q1, q1, v1, cULE);
|
||||
VSHUF4I_W(q1, q1, 0b00001000);
|
||||
VBITSEL_V(v0, d0, q0, q1);
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
VINSGR2VR_D(v0, xZR, 1);
|
||||
break;
|
||||
|
||||
@@ -270,6 +270,13 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEXSS(d0, 0, 0);
|
||||
FSQRT_S(d1, d0);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
MOVGR2FR_W(v1, xZR);
|
||||
FCMP_S(fcc0, d0, v1, cLT);
|
||||
BCEQZ(fcc0, 4 + 4);
|
||||
FNEG_S(d1, d1);
|
||||
}
|
||||
VEXTRINS_W(v0, d1, 0);
|
||||
break;
|
||||
case 0x52:
|
||||
@@ -301,6 +308,21 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEXSS(d0, 0, 0);
|
||||
FADD_S(d1, v0, d0);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
FCMP_S(fcc0, v0, d0, cUN);
|
||||
BCNEZ_MARK(fcc0);
|
||||
FCMP_S(fcc1, d1, d1, cOR);
|
||||
BCNEZ_MARK(fcc1);
|
||||
FNEG_S(d1, d1);
|
||||
MARK;
|
||||
MOVFR2GR_D(x4, v0);
|
||||
MOV32w(x5, 0x00400000);
|
||||
OR(x4, x4, x5);
|
||||
MOVGR2FR_D(q0, x4);
|
||||
FCMP_S(fcc0, v0, v0, cUN);
|
||||
FSEL(d1, d1, q0, fcc0);
|
||||
}
|
||||
VEXTRINS_W(v0, d1, 0);
|
||||
break;
|
||||
case 0x59:
|
||||
@@ -310,6 +332,21 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEXSS(d0, 0, 0);
|
||||
FMUL_S(d1, v0, d0);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
FCMP_S(fcc0, v0, d0, cUN);
|
||||
BCNEZ_MARK(fcc0);
|
||||
FCMP_S(fcc1, d1, d1, cOR);
|
||||
BCNEZ_MARK(fcc1);
|
||||
FNEG_S(d1, d1);
|
||||
MARK;
|
||||
MOVFR2GR_D(x4, v0);
|
||||
MOV32w(x5, 0x00400000);
|
||||
OR(x4, x4, x5);
|
||||
MOVGR2FR_D(q0, x4);
|
||||
FCMP_S(fcc0, v0, v0, cUN);
|
||||
FSEL(d1, d1, q0, fcc0);
|
||||
}
|
||||
VEXTRINS_W(v0, d1, 0);
|
||||
break;
|
||||
case 0x5A:
|
||||
@@ -326,25 +363,24 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
nextop = F8;
|
||||
GETEX(v1, 0, 0);
|
||||
GETGX_empty(v0);
|
||||
if (BOX64ENV(dynarec_fastround)) {
|
||||
VFTINTRZ_W_S(v0, v1);
|
||||
} else {
|
||||
MOVGR2FCSR(FCSR2, xZR); // reset all bits
|
||||
VFTINTRZ_W_S(v0, v1);
|
||||
MOVFCSR2GR(x5, FCSR2); // get back FPSR to check
|
||||
MOV32w(x3, (1 << FR_V) | (1 << FR_O));
|
||||
AND(x5, x5, x3);
|
||||
BEQZ_MARK(x5); // no fp exception, work done, fast path.
|
||||
|
||||
if (v0 == v1 && !BOX64ENV(dynarec_fastround)) {
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
VOR_V(v1, v0, v0);
|
||||
}
|
||||
VFTINTRZ_W_S(v0, v1);
|
||||
if (!BOX64ENV(dynarec_fastround)) {
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
q1 = fpu_get_scratch(dyn); // mask
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
VLDI(q0, 0b1001110000000); // broadcast 0x80000000 to all
|
||||
VLDI(d0, (0b10011 << 8) | 0x4f);
|
||||
VFCMP_S(q1, d0, v1, cULE); // get Nan,+overflow mark
|
||||
VBITSEL_V(v0, v0, q0, q1);
|
||||
|
||||
MARK;
|
||||
q1 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
VFCMP_S(q0, v1, v1, cEQ);
|
||||
VLDI(q1, 0b1001110000000); // broadcast 0x80000000
|
||||
VAND_V(v0, q0, v0);
|
||||
VANDN_V(d1, q0, q1);
|
||||
VOR_V(v0, v0, d1);
|
||||
VSUBI_WU(d1, q1, 1);
|
||||
VSEQ_W(q0, v0, d1);
|
||||
VSRLI_W(q0, q0, 31);
|
||||
VADD_W(v0, v0, q0);
|
||||
}
|
||||
break;
|
||||
case 0x5C:
|
||||
@@ -354,6 +390,21 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEXSS(d0, 0, 0);
|
||||
FSUB_S(d1, v0, d0);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
FCMP_S(fcc0, v0, d0, cUN);
|
||||
BCNEZ_MARK(fcc0);
|
||||
FCMP_S(fcc1, d1, d1, cOR);
|
||||
BCNEZ_MARK(fcc1);
|
||||
FNEG_S(d1, d1);
|
||||
MARK;
|
||||
MOVFR2GR_D(x4, v0);
|
||||
MOV32w(x5, 0x00400000);
|
||||
OR(x4, x4, x5);
|
||||
MOVGR2FR_D(q0, x4);
|
||||
FCMP_S(fcc0, v0, v0, cUN);
|
||||
FSEL(d1, d1, q0, fcc0);
|
||||
}
|
||||
VEXTRINS_W(v0, d1, 0);
|
||||
break;
|
||||
case 0x5D:
|
||||
@@ -362,12 +413,8 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETGX(d0, 1);
|
||||
GETEXSS(d1, 0, 0);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
if (BOX64ENV(dynarec_fastnan)) {
|
||||
FMIN_S(q0, d0, d1);
|
||||
} else {
|
||||
FCMP_S(fcc0, d1, d0, cULE);
|
||||
FSEL(q0, d0, d1, fcc0);
|
||||
}
|
||||
FCMP_S(fcc0, d1, d0, cULE);
|
||||
FSEL(q0, d0, d1, fcc0);
|
||||
VEXTRINS_W(d0, q0, 0);
|
||||
break;
|
||||
case 0x5E:
|
||||
@@ -377,6 +424,21 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
GETEXSS(d0, 0, 0);
|
||||
FDIV_S(d1, v0, d0);
|
||||
if (!BOX64ENV(dynarec_fastnan)) {
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
FCMP_S(fcc0, v0, d0, cUN);
|
||||
BCNEZ_MARK(fcc0);
|
||||
FCMP_S(fcc1, d1, d1, cOR);
|
||||
BCNEZ_MARK(fcc1);
|
||||
FNEG_S(d1, d1);
|
||||
MARK;
|
||||
MOVFR2GR_D(x4, v0);
|
||||
MOV32w(x5, 0x00400000);
|
||||
OR(x4, x4, x5);
|
||||
MOVGR2FR_D(q0, x4);
|
||||
FCMP_S(fcc0, v0, v0, cUN);
|
||||
FSEL(d1, d1, q0, fcc0);
|
||||
}
|
||||
VEXTRINS_W(v0, d1, 0);
|
||||
break;
|
||||
case 0x5F:
|
||||
@@ -385,12 +447,8 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETGX(d0, 1);
|
||||
GETEXSS(d1, 0, 0);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
if (BOX64ENV(dynarec_fastnan)) {
|
||||
FMAX_S(q0, d0, d1);
|
||||
} else {
|
||||
FCMP_S(fcc0, d1, d0, cLT);
|
||||
FSEL(q0, d1, d0, fcc0);
|
||||
}
|
||||
FCMP_S(fcc0, d1, d0, cLT);
|
||||
FSEL(q0, d1, d0, fcc0);
|
||||
VEXTRINS_W(d0, q0, 0);
|
||||
break;
|
||||
case 0x6F:
|
||||
@@ -464,24 +522,37 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
FAKEED;
|
||||
UDF();
|
||||
} else {
|
||||
if(((nextop>>3)&7)==1) {INST_NAME("RDGSBASE");} else {INST_NAME("RDFSBASE");}
|
||||
if (((nextop >> 3) & 7) == 1) {
|
||||
INST_NAME("RDGSBASE");
|
||||
} else {
|
||||
INST_NAME("RDFSBASE");
|
||||
}
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
int seg = _FS + ((nextop>>3)&7);
|
||||
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
|
||||
MV(ed, x4);
|
||||
int seg = _FS + ((nextop >> 3) & 7);
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
MVxw(ed, x4);
|
||||
}
|
||||
break;
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
if(rex.is32bits || !MODREG) {
|
||||
if (rex.is32bits || !MODREG) {
|
||||
INST_NAME("Illegal AE");
|
||||
FAKEED;
|
||||
UDF();
|
||||
} else {
|
||||
if(((nextop>>3)&7)==3) {INST_NAME("WRGSBASE");} else {INST_NAME("WRFSBASE");}
|
||||
if (((nextop >> 3) & 7) == 3) {
|
||||
INST_NAME("WRGSBASE");
|
||||
} else {
|
||||
INST_NAME("WRFSBASE");
|
||||
}
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
int seg = _FS + ((nextop>>3)&7)-2;
|
||||
ST_D(ed, xEmu, offsetof(x64emu_t, segs_offs[seg]));
|
||||
int seg = _FS + ((nextop >> 3) & 7) - 2;
|
||||
if (!rex.w) {
|
||||
ZEROUP2(x4, ed);
|
||||
ST_D(x4, xEmu, offsetof(x64emu_t, segs_offs[seg]));
|
||||
} else {
|
||||
ST_D(ed, xEmu, offsetof(x64emu_t, segs_offs[seg]));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
|
||||
@@ -485,6 +485,7 @@ void lsxcacheUnwind(lsxcache_t* cache)
|
||||
case LSX_CACHE_YMMR:
|
||||
case LSX_CACHE_YMMW:
|
||||
cache->avxcache[cache->lsxcache[i].n].reg = i;
|
||||
cache->avxcache[cache->lsxcache[i].n].dirty = 0;
|
||||
cache->avxcache[cache->lsxcache[i].n].write = (cache->lsxcache[i].t == LSX_CACHE_YMMW) ? 1 : 0;
|
||||
break;
|
||||
case LSX_CACHE_ST_F:
|
||||
@@ -516,7 +517,7 @@ const char* getCacheName(int t, int n)
|
||||
case LSX_CACHE_XMMW: sprintf(buff, "XMM%d", n); break;
|
||||
case LSX_CACHE_XMMR: sprintf(buff, "xmm%d", n); break;
|
||||
case LSX_CACHE_YMMW: sprintf(buff, "YMM%d", n); break;
|
||||
case LSX_CACHE_YMMR: sprintf(buff, "ymm%d", n); break;
|
||||
case LSX_CACHE_YMMR: sprintf(buff, "ymm%d", n); break;
|
||||
case LSX_CACHE_SCR: sprintf(buff, "Scratch"); break;
|
||||
case LSX_CACHE_NONE: buff[0] = '\0'; break;
|
||||
}
|
||||
@@ -599,18 +600,20 @@ static const char* Ft[] = { "fa0", "fa1", "fa2", "fa3", "fa4", "fa5", "fa6", "fa
|
||||
static const char* Vt[] = { "vra0", "vra1", "vra2", "vra3", "vra4", "vra5", "vra6", "vra7", "vrt0", "vrt1", "vrt2", "vrt3", "vrt4", "vrt5", "vrt6", "vrt7", "vrt8", "vrt9", "vrt10", "vrt11", "vrt12", "vrt13", "vrt14", "vrt15", "vrs0", "vrs1", "vrs2", "vrs3", "vrs4", "vrs5", "vrs6", "vrs7" };
|
||||
static const char* XVt[] = { "xvra0", "xvra1", "xvra2", "xvra3", "xvra4", "xvra5", "xvra6", "xvra7", "xvrt0", "xvrt1", "xvrt2", "xvrt3", "xvrt4", "xvrt5", "xvrt6", "xvrt7", "xvrt8", "xvrt9", "xvrt10", "xvrt11", "xvrt12", "xvrt13", "xvrt14", "xvrt15", "xvrs0", "xvrs1", "xvrs2", "xvrs3", "xvrs4", "xvrs5", "xvrs6", "xvrs7" };
|
||||
|
||||
static const char* df_status[] = { "unknown", "set", "none_pending", "none" };
|
||||
|
||||
void printf_x64_instruction(dynarec_native_t* dyn, zydis_dec_t* dec, instruction_x64_t* inst, const char* name);
|
||||
void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t rex)
|
||||
{
|
||||
if (!dyn->need_dump && !BOX64ENV(dynarec_gdbjit) && !BOX64ENV(dynarec_perf_map)) return;
|
||||
|
||||
static char buf[4096];
|
||||
int length = sprintf(buf, "barrier=%d state=%d/%d(%d), %s=%X/%X, use=%X, need=%X/%X, fuse=%d/%d, sm=%d(%d/%d)",
|
||||
int length = sprintf(buf, "barrier=%d state=%d/%s(%s->%s), set=%X/%X, use=%X, need=%X/%X, fuse=%d/%d, sm=%d(%d/%d)",
|
||||
dyn->insts[ninst].x64.barrier,
|
||||
dyn->insts[ninst].x64.state_flags,
|
||||
dyn->f.pending,
|
||||
dyn->f.dfnone,
|
||||
dyn->insts[ninst].x64.may_set ? "may" : "set",
|
||||
df_status[dyn->f],
|
||||
df_status[dyn->insts[ninst].f_entry],
|
||||
df_status[dyn->insts[ninst].f_exit],
|
||||
dyn->insts[ninst].x64.set_flags,
|
||||
dyn->insts[ninst].x64.gen_flags,
|
||||
dyn->insts[ninst].x64.use_flags,
|
||||
@@ -638,8 +641,8 @@ void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t r
|
||||
case LSX_CACHE_MM: length += sprintf(buf + length, " %s:%s", Ft[ii], getCacheName(dyn->insts[ninst].lsx.lsxcache[ii].t, dyn->insts[ninst].lsx.lsxcache[ii].n)); break;
|
||||
case LSX_CACHE_XMMW: length += sprintf(buf + length, " %s:%s", Vt[ii], getCacheName(dyn->insts[ninst].lsx.lsxcache[ii].t, dyn->insts[ninst].lsx.lsxcache[ii].n)); break;
|
||||
case LSX_CACHE_XMMR: length += sprintf(buf + length, " %s:%s", Vt[ii], getCacheName(dyn->insts[ninst].lsx.lsxcache[ii].t, dyn->insts[ninst].lsx.lsxcache[ii].n)); break;
|
||||
case LSX_CACHE_YMMW: length += sprintf(buf + length, " %s:%s%s", XVt[ii], getCacheName(dyn->insts[ninst].lsx.lsxcache[ii].t, dyn->insts[ninst].lsx.lsxcache[ii].n), dyn->insts[ninst].lsx.avxcache[dyn->insts[ninst].lsx.lsxcache[ii].n].zero_upper == 1 ? "-UZ" : ""); break;
|
||||
case LSX_CACHE_YMMR: length += sprintf(buf + length, " %s:%s%s", XVt[ii], getCacheName(dyn->insts[ninst].lsx.lsxcache[ii].t, dyn->insts[ninst].lsx.lsxcache[ii].n), dyn->insts[ninst].lsx.avxcache[dyn->insts[ninst].lsx.lsxcache[ii].n].zero_upper == 1 ? "-UZ" : ""); break;
|
||||
case LSX_CACHE_YMMW: length += sprintf(buf + length, " %s:%s", XVt[ii], getCacheName(dyn->insts[ninst].lsx.lsxcache[ii].t, dyn->insts[ninst].lsx.lsxcache[ii].n)); break;
|
||||
case LSX_CACHE_YMMR: length += sprintf(buf + length, " %s:%s", XVt[ii], getCacheName(dyn->insts[ninst].lsx.lsxcache[ii].t, dyn->insts[ninst].lsx.lsxcache[ii].n)); break;
|
||||
case LSX_CACHE_SCR: length += sprintf(buf + length, " %s:%s", Ft[ii], getCacheName(dyn->insts[ninst].lsx.lsxcache[ii].t, dyn->insts[ninst].lsx.lsxcache[ii].n)); break;
|
||||
case LSX_CACHE_NONE:
|
||||
default: break;
|
||||
|
||||
@@ -75,11 +75,11 @@ uintptr_t geted(dynarec_la64_t* dyn, uintptr_t addr, int ninst, uint8_t nextop,
|
||||
}
|
||||
} else {
|
||||
if (rex.seg && !(tmp && ((tmp < -2048) || (tmp > maxval) || !i12))) {
|
||||
grab_segdata(dyn, addr, ninst, ret, rex.seg, 0);
|
||||
grab_segdata(dyn, addr, ninst, ret, rex.seg);
|
||||
seg_done = 1;
|
||||
*fixaddress = tmp;
|
||||
} else if (rex.seg && tmp >= -2048 && tmp < 2048) {
|
||||
grab_segdata(dyn, addr, ninst, ret, rex.seg, 0);
|
||||
grab_segdata(dyn, addr, ninst, ret, rex.seg);
|
||||
if (tmp) ADDI_D(ret, ret, tmp);
|
||||
seg_done = 1;
|
||||
} else
|
||||
@@ -105,7 +105,7 @@ uintptr_t geted(dynarec_la64_t* dyn, uintptr_t addr, int ninst, uint8_t nextop,
|
||||
if (rex.is32bits) {
|
||||
int tmp = F32S;
|
||||
if (rex.seg && tmp >= -2048 && tmp < 2048) {
|
||||
grab_segdata(dyn, addr, ninst, ret, rex.seg, 0);
|
||||
grab_segdata(dyn, addr, ninst, ret, rex.seg);
|
||||
if (tmp) ADDI_D(ret, ret, tmp);
|
||||
seg_done = 1;
|
||||
} else
|
||||
@@ -230,7 +230,7 @@ uintptr_t geted(dynarec_la64_t* dyn, uintptr_t addr, int ninst, uint8_t nextop,
|
||||
if (scratch == ret)
|
||||
scratch = ret + 1;
|
||||
SCRATCH_USAGE(1);
|
||||
grab_segdata(dyn, addr, ninst, scratch, rex.seg, 0);
|
||||
grab_segdata(dyn, addr, ninst, scratch, rex.seg);
|
||||
// seg offset is 64bits, so no truncation here
|
||||
ADDxREGy(hint, scratch, ret, hint);
|
||||
ret = hint;
|
||||
@@ -260,61 +260,56 @@ uintptr_t geted16(dynarec_la64_t* dyn, uintptr_t addr, int ninst, uint8_t nextop
|
||||
case 1: offset = F8S; break;
|
||||
case 2: offset = F16S; break;
|
||||
}
|
||||
if (offset && offset >= -2048 && offset <= 2047) {
|
||||
if (i12 && offset && offset >= -2048 && offset <= 2047) {
|
||||
*fixaddress = offset;
|
||||
offset = 0;
|
||||
}
|
||||
int reg;
|
||||
switch (m & 7) {
|
||||
case 0: // R_BX + R_SI
|
||||
BSTRPICK_D(ret, xRBX, 15, 0);
|
||||
BSTRPICK_D(scratch, xRSI, 15, 0);
|
||||
ADD_D(ret, ret, scratch);
|
||||
SCRATCH_USAGE(1);
|
||||
ADD_D(ret, xRBX, xRSI);
|
||||
reg = ret;
|
||||
if (!IS_GPR(ret)) SCRATCH_USAGE(1);
|
||||
break;
|
||||
case 1: // R_BX + R_DI
|
||||
BSTRPICK_D(ret, xRBX, 15, 0);
|
||||
BSTRPICK_D(scratch, xRDI, 15, 0);
|
||||
ADD_D(ret, ret, scratch);
|
||||
SCRATCH_USAGE(1);
|
||||
ADD_D(ret, xRBX, xRDI);
|
||||
reg = ret;
|
||||
if (!IS_GPR(ret)) SCRATCH_USAGE(1);
|
||||
break;
|
||||
case 2: // R_BP + R_SI
|
||||
BSTRPICK_D(ret, xRBP, 15, 0);
|
||||
BSTRPICK_D(scratch, xRSI, 15, 0);
|
||||
ADD_D(ret, ret, scratch);
|
||||
SCRATCH_USAGE(1);
|
||||
ADD_D(ret, xRBP, xRSI);
|
||||
reg = ret;
|
||||
if (!IS_GPR(ret)) SCRATCH_USAGE(1);
|
||||
break;
|
||||
case 3: // R_BP + R_DI
|
||||
BSTRPICK_D(ret, xRBP, 15, 0);
|
||||
BSTRPICK_D(scratch, xRDI, 15, 0);
|
||||
ADD_D(ret, ret, scratch);
|
||||
SCRATCH_USAGE(1);
|
||||
ADD_D(ret, xRBP, xRDI);
|
||||
reg = ret;
|
||||
if (!IS_GPR(ret)) SCRATCH_USAGE(1);
|
||||
break;
|
||||
case 4: // R_SI
|
||||
BSTRPICK_D(ret, xRSI, 15, 0);
|
||||
if (!IS_GPR(ret)) SCRATCH_USAGE(1);
|
||||
reg = xRSI;
|
||||
break;
|
||||
case 5: // R_DI
|
||||
BSTRPICK_D(ret, xRDI, 15, 0);
|
||||
if (!IS_GPR(ret)) SCRATCH_USAGE(1);
|
||||
reg = xRDI;
|
||||
break;
|
||||
case 6: // R_BP
|
||||
BSTRPICK_D(ret, xRBP, 15, 0);
|
||||
if (!IS_GPR(ret)) SCRATCH_USAGE(1);
|
||||
reg = xRBP;
|
||||
break;
|
||||
case 7: // R_BX
|
||||
BSTRPICK_D(ret, xRBX, 15, 0);
|
||||
if (!IS_GPR(ret)) SCRATCH_USAGE(1);
|
||||
reg = xRBX;
|
||||
break;
|
||||
}
|
||||
BSTRPICK_D(ret, reg, 15, 0);
|
||||
if (!IS_GPR(ret)) SCRATCH_USAGE(1);
|
||||
if (offset) {
|
||||
if (offset >= -2048 && offset < 2048) {
|
||||
ADDI_D(ret, ret, offset);
|
||||
if (!IS_GPR(ret)) SCRATCH_USAGE(1);
|
||||
} else {
|
||||
MOV64x(scratch, offset);
|
||||
ADD_D(ret, ret, scratch);
|
||||
SCRATCH_USAGE(1);
|
||||
}
|
||||
BSTRPICK_D(ret, ret, 15, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -322,7 +317,7 @@ uintptr_t geted16(dynarec_la64_t* dyn, uintptr_t addr, int ninst, uint8_t nextop
|
||||
if (scratch == ret)
|
||||
scratch = ret + 1;
|
||||
SCRATCH_USAGE(1);
|
||||
grab_segdata(dyn, addr, ninst, scratch, rex.seg, 0);
|
||||
grab_segdata(dyn, addr, ninst, scratch, rex.seg);
|
||||
// seg offset is 64bits, so no truncation here
|
||||
if (IS_GPR(ret)) {
|
||||
ADD_D(hint, ret, scratch);
|
||||
@@ -350,6 +345,7 @@ void jump_to_epilog(dynarec_la64_t* dyn, uintptr_t ip, int reg, int ninst)
|
||||
}
|
||||
TABLE64C(x2, const_epilog);
|
||||
SMEND();
|
||||
CHECK_DFNONE(0);
|
||||
BR(x2);
|
||||
}
|
||||
|
||||
@@ -369,6 +365,7 @@ void jump_to_epilog_fast(dynarec_la64_t* dyn, uintptr_t ip, int reg, int ninst)
|
||||
}
|
||||
TABLE64C(x2, const_epilog_fast);
|
||||
SMEND();
|
||||
CHECK_DFNONE(0);
|
||||
BR(x2);
|
||||
}
|
||||
|
||||
@@ -408,6 +405,7 @@ void jump_to_next(dynarec_la64_t* dyn, uintptr_t ip, int reg, int ninst, int is3
|
||||
if (is32bits)
|
||||
ip &= 0xffffffffLL;
|
||||
|
||||
CHECK_DFNONE(0);
|
||||
int dest;
|
||||
if (reg) {
|
||||
if (reg != xRIP) {
|
||||
@@ -437,12 +435,12 @@ void jump_to_next(dynarec_la64_t* dyn, uintptr_t ip, int reg, int ninst, int is3
|
||||
#endif
|
||||
}
|
||||
|
||||
void ret_to_epilog(dynarec_la64_t* dyn, uintptr_t ip, int ninst, rex_t rex)
|
||||
void ret_to_next(dynarec_la64_t* dyn, uintptr_t ip, int ninst, rex_t rex)
|
||||
{
|
||||
MAYUSE(dyn);
|
||||
MAYUSE(ninst);
|
||||
MESSAGE(LOG_DUMP, "Ret to epilog\n");
|
||||
POP1z(xRIP);
|
||||
MESSAGE(LOG_DUMP, "Ret to next\n");
|
||||
CHECK_DFNONE(0);
|
||||
MVz(x1, xRIP);
|
||||
SMEND();
|
||||
if (BOX64DRENV(dynarec_callret)) {
|
||||
@@ -461,43 +459,10 @@ void ret_to_epilog(dynarec_la64_t* dyn, uintptr_t ip, int ninst, rex_t rex)
|
||||
CLEARIP();
|
||||
}
|
||||
|
||||
void retn_to_epilog(dynarec_la64_t* dyn, uintptr_t ip, int ninst, rex_t rex, int n)
|
||||
void iret_to_next(dynarec_la64_t* dyn, uintptr_t ip, int ninst, int is32bits, int is64bits)
|
||||
{
|
||||
MAYUSE(dyn);
|
||||
MAYUSE(ninst);
|
||||
MESSAGE(LOG_DUMP, "Retn to epilog\n");
|
||||
POP1z(xRIP);
|
||||
if (n > 0x7ff) {
|
||||
MOV64x(x1, n);
|
||||
ADDz(xRSP, xRSP, x1);
|
||||
} else {
|
||||
ADDIz(xRSP, xRSP, n);
|
||||
}
|
||||
MVz(x1, xRIP);
|
||||
SMEND();
|
||||
if (BOX64DRENV(dynarec_callret)) {
|
||||
// pop the actual return address from LA64 stack
|
||||
LD_D(xRA, xSP, 0); // native addr
|
||||
LD_D(x6, xSP, 8); // x86 addr
|
||||
ADDI_D(xSP, xSP, 16); // pop
|
||||
BNE(x6, xRIP, 2 * 4); // is it the right address?
|
||||
BR(xRA);
|
||||
// not the correct return address, regular jump, but purge the stack first, it's unsync now...
|
||||
ADDI_D(xSP, xSavedSP, -16);
|
||||
}
|
||||
|
||||
NOTEST(x2);
|
||||
int dest = indirect_lookup(dyn, ninst, rex.is32bits, x2, x3);
|
||||
BR(dest);
|
||||
CLEARIP();
|
||||
}
|
||||
|
||||
void iret_to_epilog(dynarec_la64_t* dyn, uintptr_t ip, int ninst, int is64bits)
|
||||
{
|
||||
// #warning TODO: is64bits
|
||||
MAYUSE(ninst);
|
||||
MESSAGE(LOG_DUMP, "IRet to epilog\n");
|
||||
NOTEST(x2);
|
||||
MESSAGE(LOG_DUMP, "IRet to next\n");
|
||||
if (is64bits) {
|
||||
POP1(xRIP);
|
||||
POP1(x2);
|
||||
@@ -510,11 +475,12 @@ void iret_to_epilog(dynarec_la64_t* dyn, uintptr_t ip, int ninst, int is64bits)
|
||||
|
||||
ST_H(x2, xEmu, offsetof(x64emu_t, segs[_CS]));
|
||||
// clean EFLAGS
|
||||
MOV32w(x1, 0x3E7FD7); // also mask RF
|
||||
RESTORE_EFLAGS(x1);
|
||||
MOV32w(x1, 0x3E7FD7); // also mask RF
|
||||
AND(xFlags, xFlags, x1);
|
||||
ORI(xFlags, xFlags, 0x2);
|
||||
SPILL_EFLAGS();
|
||||
SET_DFNONE();
|
||||
CHECK_DFNONE(0);
|
||||
// POP RSP
|
||||
if (is64bits) {
|
||||
POP1(x3); // rsp
|
||||
@@ -528,19 +494,17 @@ void iret_to_epilog(dynarec_la64_t* dyn, uintptr_t ip, int ninst, int is64bits)
|
||||
// set new RSP
|
||||
MV(xRSP, x3);
|
||||
// Ret....
|
||||
// epilog on purpose, CS might have changed!
|
||||
if (dyn->need_reloc)
|
||||
TABLE64C(x2, const_epilog);
|
||||
else
|
||||
MOV64x(x2, getConst(const_epilog));
|
||||
SMEND();
|
||||
BR(x2);
|
||||
rex_t dummy = { 0 };
|
||||
dummy.is32bits = is32bits;
|
||||
dummy.w = is64bits;
|
||||
ret_to_next(dyn, ip, ninst, dummy);
|
||||
CLEARIP();
|
||||
}
|
||||
|
||||
void call_c(dynarec_la64_t* dyn, int ninst, la64_consts_t fnc, int reg, int ret, int saveflags, int savereg, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6)
|
||||
{
|
||||
MAYUSE(fnc);
|
||||
CHECK_DFNONE(1);
|
||||
if (savereg == 0)
|
||||
savereg = x87pc;
|
||||
if (saveflags) {
|
||||
@@ -564,13 +528,13 @@ void call_c(dynarec_la64_t* dyn, int ninst, la64_consts_t fnc, int reg, int ret,
|
||||
ST_D(xRIP, xEmu, offsetof(x64emu_t, ip));
|
||||
}
|
||||
TABLE64C(reg, fnc);
|
||||
MV(A0, xEmu);
|
||||
if (arg1) MV(A1, arg1);
|
||||
if (arg2) MV(A2, arg2);
|
||||
if (arg3) MV(A3, arg3);
|
||||
if (arg4) MV(A4, arg4);
|
||||
if (arg5) MV(A5, arg5);
|
||||
if (arg6) MV(A6, arg6);
|
||||
MV(A0, xEmu);
|
||||
JIRL(xRA, reg, 0);
|
||||
if (ret >= 0) {
|
||||
MV(ret, A0);
|
||||
@@ -609,6 +573,7 @@ void call_c(dynarec_la64_t* dyn, int ninst, la64_consts_t fnc, int reg, int ret,
|
||||
void call_n(dynarec_la64_t* dyn, int ninst, void* fnc, int w)
|
||||
{
|
||||
MAYUSE(fnc);
|
||||
CHECK_DFNONE(1);
|
||||
fpu_pushcache(dyn, ninst, x3, 1);
|
||||
ST_D(xRSP, xEmu, offsetof(x64emu_t, regs[_SP]));
|
||||
ST_D(xRBP, xEmu, offsetof(x64emu_t, regs[_BP]));
|
||||
@@ -643,12 +608,11 @@ void call_n(dynarec_la64_t* dyn, int ninst, void* fnc, int w)
|
||||
// SET_NODF();
|
||||
}
|
||||
|
||||
void grab_segdata(dynarec_la64_t* dyn, uintptr_t addr, int ninst, int reg, int segment, int modreg)
|
||||
void grab_segdata(dynarec_la64_t* dyn, uintptr_t addr, int ninst, int reg, int segment)
|
||||
{
|
||||
(void)addr;
|
||||
int64_t j64;
|
||||
MAYUSE(j64);
|
||||
if (modreg) return;
|
||||
MESSAGE(LOG_DUMP, "Get %s Offset\n", (segment == _FS) ? "FS" : "GS");
|
||||
LD_D(reg, xEmu, offsetof(x64emu_t, segs_offs[segment]));
|
||||
MESSAGE(LOG_DUMP, "----%s Offset\n", (segment == _FS) ? "FS" : "GS");
|
||||
@@ -1243,7 +1207,6 @@ int x87_get_current_cache(dynarec_la64_t* dyn, int ninst, int st, int t)
|
||||
#endif
|
||||
return i;
|
||||
}
|
||||
assert(dyn->lsx.x87cache[i] < 8);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@@ -1288,7 +1251,7 @@ int x87_get_lsxcache(dynarec_la64_t* dyn, int ninst, int s1, int s2, int st)
|
||||
|| dyn->lsx.lsxcache[ii].t == LSX_CACHE_ST_I64)
|
||||
&& dyn->lsx.lsxcache[ii].n == st)
|
||||
return ii;
|
||||
assert(0);
|
||||
dynarec_log(LOG_NONE, "Warning: x87_get_lsxcache didn't find cache for ninst=%d\n", ninst);
|
||||
return -1;
|
||||
}
|
||||
int x87_get_st(dynarec_la64_t* dyn, int ninst, int s1, int s2, int a, int t)
|
||||
@@ -1298,7 +1261,7 @@ int x87_get_st(dynarec_la64_t* dyn, int ninst, int s1, int s2, int a, int t)
|
||||
}
|
||||
int x87_get_st_empty(dynarec_la64_t* dyn, int ninst, int s1, int s2, int a, int t)
|
||||
{
|
||||
dyn->insts[ninst].x87_used = 1;
|
||||
dyn->insts[ninst].x87_used = 1;
|
||||
return dyn->lsx.x87reg[x87_get_cache(dyn, ninst, 0, s1, s2, a, t)];
|
||||
}
|
||||
|
||||
@@ -1388,17 +1351,11 @@ int sse_get_reg(dynarec_la64_t* dyn, int ninst, int s1, int a, int forwrite)
|
||||
}
|
||||
return dyn->lsx.ssecache[a].reg;
|
||||
}
|
||||
int need_vld = 1;
|
||||
// migrate from avx to sse
|
||||
if (dyn->lsx.avxcache[a].v != -1) {
|
||||
avx_reflect_reg_upper128(dyn, ninst, a, forwrite);
|
||||
dyn->lsx.avxcache[a].v = -1;
|
||||
need_vld = 0;
|
||||
}
|
||||
avx_forget_reg(dyn, ninst, a);
|
||||
dyn->lsx.ssecache[a].reg = fpu_get_reg_xmm(dyn, forwrite ? LSX_CACHE_XMMW : LSX_CACHE_XMMR, a);
|
||||
int ret = dyn->lsx.ssecache[a].reg;
|
||||
dyn->lsx.ssecache[a].write = forwrite;
|
||||
if(need_vld) VLD(ret, xEmu, offsetof(x64emu_t, xmm[a])); //skip VLD if migrate from avx
|
||||
VLD(ret, xEmu, offsetof(x64emu_t, xmm[a])); // skip VLD if migrate from avx
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1457,9 +1414,9 @@ void sse_purge07cache(dynarec_la64_t* dyn, int ninst, int s1)
|
||||
dyn->lsx.xmm_used |= 1 << i;
|
||||
if (dyn->lsx.lsxcache[dyn->lsx.avxcache[i].reg].t == LSX_CACHE_YMMW) {
|
||||
VST(dyn->lsx.avxcache[i].reg, xEmu, offsetof(x64emu_t, xmm[i]));
|
||||
if(dyn->lsx.avxcache[i].zero_upper == 1){
|
||||
if (dyn->lsx.avxcache[i].dirty) {
|
||||
XVXOR_V(SCRATCH, SCRATCH, SCRATCH);
|
||||
}else{
|
||||
} else {
|
||||
XVPERMI_Q(SCRATCH, dyn->lsx.avxcache[i].reg, XVPERMI_IMM_4_0(0, 1));
|
||||
}
|
||||
VST(SCRATCH, xEmu, offsetof(x64emu_t, ymm[i]));
|
||||
@@ -1518,46 +1475,26 @@ int avx_get_reg(dynarec_la64_t* dyn, int ninst, int s1, int a, int forwrite, int
|
||||
dyn->lsx.ymm_used |= 1 << a;
|
||||
if (dyn->lsx.avxcache[a].v != -1) {
|
||||
if (forwrite) {
|
||||
dyn->lsx.avxcache[a].write = 1; // update only if forwrite
|
||||
if (width == LSX_AVX_WIDTH_128) dyn->lsx.avxcache[a].dirty = 1;
|
||||
dyn->lsx.lsxcache[dyn->lsx.avxcache[a].reg].t = LSX_CACHE_YMMW;
|
||||
dyn->lsx.avxcache[a].write = 1;
|
||||
}
|
||||
if (width == LSX_AVX_WIDTH_128) {
|
||||
dyn->lsx.avxcache[a].width = LSX_AVX_WIDTH_128;
|
||||
if(forwrite) dyn->lsx.avxcache[a].zero_upper = 1;
|
||||
} else {
|
||||
// if width changed to 256, and vzeroup ==1, means need zero-fill upper 128bits now.
|
||||
if (dyn->lsx.avxcache[a].zero_upper == 1) {
|
||||
dyn->lsx.avxcache[a].zero_upper = 0;
|
||||
XVXOR_V(SCRATCH, SCRATCH, SCRATCH);
|
||||
XVPERMI_Q(dyn->lsx.avxcache[a].reg, SCRATCH, 0b00000010);
|
||||
}
|
||||
dyn->lsx.avxcache[a].width = LSX_AVX_WIDTH_256;
|
||||
}
|
||||
|
||||
return dyn->lsx.avxcache[a].reg;
|
||||
}
|
||||
sse_forget_reg(dyn, ninst, a);
|
||||
|
||||
// migrate from sse to avx
|
||||
if (dyn->lsx.ssecache[a].v != -1) {
|
||||
// release SSE reg cache
|
||||
fpu_free_reg(dyn, dyn->lsx.ssecache[a].reg);
|
||||
dyn->lsx.ssecache[a].v = -1;
|
||||
}
|
||||
|
||||
// new reg
|
||||
dyn->lsx.avxcache[a].v = 0;
|
||||
dyn->lsx.avxcache[a].reg = fpu_get_reg_ymm(dyn, forwrite ? LSX_CACHE_YMMW : LSX_CACHE_YMMR, a);
|
||||
int ret = dyn->lsx.avxcache[a].reg;
|
||||
dyn->lsx.avxcache[a].write = forwrite;
|
||||
dyn->lsx.avxcache[a].width = width;
|
||||
if (width == LSX_AVX_WIDTH_128) {
|
||||
if(forwrite) dyn->lsx.avxcache[a].zero_upper = 1;
|
||||
if (forwrite) dyn->lsx.avxcache[a].write = 1;
|
||||
dyn->lsx.avxcache[a].dirty = 0;
|
||||
if (width == LSX_AVX_WIDTH_128 && forwrite) {
|
||||
VLD(ret, xEmu, offsetof(x64emu_t, xmm[a]));
|
||||
dyn->lsx.avxcache[a].dirty = 1;
|
||||
} else {
|
||||
VLD(ret, xEmu, offsetof(x64emu_t, xmm[a]));
|
||||
VLD(SCRATCH, xEmu, offsetof(x64emu_t, ymm[a]));
|
||||
XVPERMI_Q(ret, SCRATCH, XVPERMI_IMM_4_0(0, 2));
|
||||
dyn->lsx.avxcache[a].zero_upper = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -1568,30 +1505,15 @@ int avx_get_reg_empty(dynarec_la64_t* dyn, int ninst, int s1, int a, int width)
|
||||
if (dyn->lsx.avxcache[a].v != -1) {
|
||||
dyn->lsx.avxcache[a].write = 1;
|
||||
dyn->lsx.lsxcache[dyn->lsx.avxcache[a].reg].t = LSX_CACHE_YMMW;
|
||||
if (width == LSX_AVX_WIDTH_128) {
|
||||
dyn->lsx.avxcache[a].width = LSX_AVX_WIDTH_128;
|
||||
dyn->lsx.avxcache[a].zero_upper = 1;
|
||||
} else {
|
||||
dyn->lsx.avxcache[a].width = LSX_AVX_WIDTH_256;
|
||||
dyn->lsx.avxcache[a].zero_upper = 0;
|
||||
}
|
||||
dyn->lsx.avxcache[a].dirty = width == LSX_AVX_WIDTH_128;
|
||||
return dyn->lsx.avxcache[a].reg;
|
||||
}
|
||||
// migrate from sse to avx
|
||||
if (dyn->lsx.ssecache[a].v != -1) {
|
||||
// Release SSE reg cache
|
||||
fpu_free_reg(dyn, dyn->lsx.ssecache[a].reg);
|
||||
dyn->lsx.ssecache[a].v = -1;
|
||||
}
|
||||
fpu_free_reg(dyn, dyn->lsx.ssecache[a].reg);
|
||||
dyn->lsx.ssecache[a].v = -1;
|
||||
dyn->lsx.avxcache[a].v = 0;
|
||||
dyn->lsx.avxcache[a].reg = fpu_get_reg_ymm(dyn, LSX_CACHE_YMMW, a);
|
||||
dyn->lsx.avxcache[a].write = 1;
|
||||
dyn->lsx.avxcache[a].width = width;
|
||||
if (width == LSX_AVX_WIDTH_128){
|
||||
dyn->lsx.avxcache[a].zero_upper = 1;
|
||||
} else {
|
||||
dyn->lsx.avxcache[a].zero_upper = 0;
|
||||
}
|
||||
dyn->lsx.avxcache[a].dirty = width == LSX_AVX_WIDTH_128;
|
||||
return dyn->lsx.avxcache[a].reg;
|
||||
}
|
||||
|
||||
@@ -1601,11 +1523,7 @@ void avx_reflect_reg_upper128(dynarec_la64_t* dyn, int ninst, int a, int forwrit
|
||||
if (dyn->lsx.avxcache[a].v == -1 || forwrite == 0)
|
||||
return;
|
||||
if (dyn->lsx.lsxcache[dyn->lsx.avxcache[a].reg].t == LSX_CACHE_YMMW) {
|
||||
if (dyn->lsx.avxcache[a].zero_upper == 1) {
|
||||
XVXOR_V(SCRATCH, SCRATCH, SCRATCH);
|
||||
} else {
|
||||
XVPERMI_Q(SCRATCH, dyn->lsx.avxcache[a].reg, XVPERMI_IMM_4_0(0, 1));
|
||||
}
|
||||
XVPERMI_Q(SCRATCH, dyn->lsx.avxcache[a].reg, XVPERMI_IMM_4_0(0, 1));
|
||||
VST(SCRATCH, xEmu, offsetof(x64emu_t, ymm[a]));
|
||||
}
|
||||
dyn->lsx.avxcache[a].v = -1;
|
||||
@@ -1619,7 +1537,7 @@ void avx_forget_reg(dynarec_la64_t* dyn, int ninst, int a)
|
||||
return;
|
||||
if (dyn->lsx.lsxcache[dyn->lsx.avxcache[a].reg].t == LSX_CACHE_YMMW) {
|
||||
VST(dyn->lsx.avxcache[a].reg, xEmu, offsetof(x64emu_t, xmm[a]));
|
||||
if (dyn->lsx.avxcache[a].zero_upper == 1) {
|
||||
if (dyn->lsx.avxcache[a].dirty) {
|
||||
XVXOR_V(SCRATCH, SCRATCH, SCRATCH);
|
||||
} else {
|
||||
XVPERMI_Q(SCRATCH, dyn->lsx.avxcache[a].reg, XVPERMI_IMM_4_0(0, 1));
|
||||
@@ -1638,14 +1556,35 @@ void avx_reflect_reg(dynarec_la64_t* dyn, int ninst, int a)
|
||||
return;
|
||||
if (dyn->lsx.lsxcache[dyn->lsx.avxcache[a].reg].t == LSX_CACHE_YMMW) {
|
||||
VST(dyn->lsx.avxcache[a].reg, xEmu, offsetof(x64emu_t, xmm[a]));
|
||||
if (dyn->lsx.avxcache[a].zero_upper == 1) {
|
||||
if (dyn->lsx.avxcache[a].dirty) {
|
||||
XVXOR_V(SCRATCH, SCRATCH, SCRATCH);
|
||||
XVPERMI_Q(dyn->lsx.avxcache[a].reg, SCRATCH, 0b00000010);
|
||||
} else {
|
||||
XVPERMI_Q(SCRATCH, dyn->lsx.avxcache[a].reg, XVPERMI_IMM_4_0(0, 1));
|
||||
}
|
||||
VST(SCRATCH, xEmu, offsetof(x64emu_t, ymm[a]));
|
||||
dyn->lsx.avxcache[a].zero_upper = 0;
|
||||
dyn->lsx.avxcache[a].dirty = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void avx_cleancache(dynarec_la64_t* dyn, int ninst)
|
||||
{
|
||||
int old = -1;
|
||||
for (int i = 0; i < 16; ++i)
|
||||
if (dyn->lsx.avxcache[i].v != -1) {
|
||||
dyn->lsx.ymm_used |= 1 << i;
|
||||
if (dyn->lsx.avxcache[i].dirty) {
|
||||
if (old == -1) {
|
||||
MESSAGE(LOG_DUMP, "\tClean AVX Cache ------\n");
|
||||
++old;
|
||||
}
|
||||
XVXOR_V(SCRATCH, SCRATCH, SCRATCH);
|
||||
XVPERMI_Q(dyn->lsx.avxcache[i].reg, SCRATCH, 0b00000010);
|
||||
dyn->lsx.avxcache[i].dirty = 0;
|
||||
}
|
||||
}
|
||||
if (old != -1) {
|
||||
MESSAGE(LOG_DUMP, "\t------ Clean AVX Cache\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1661,15 +1600,15 @@ static void avx_purgecache(dynarec_la64_t* dyn, int ninst, int next, int s1)
|
||||
MESSAGE(LOG_DUMP, "\tPurge %sAVX Cache ------\n", next ? "locally " : "");
|
||||
++old;
|
||||
}
|
||||
if (dyn->lsx.lsxcache[dyn->lsx.avxcache[i].reg].t == LSX_CACHE_YMMW) {
|
||||
VST(dyn->lsx.avxcache[i].reg, xEmu, offsetof(x64emu_t, xmm[i]));
|
||||
if (dyn->lsx.avxcache[i].zero_upper == 1) {
|
||||
XVXOR_V(SCRATCH, SCRATCH, SCRATCH);
|
||||
} else {
|
||||
XVPERMI_Q(SCRATCH, dyn->lsx.avxcache[i].reg, XVPERMI_IMM_4_0(0, 1));
|
||||
}
|
||||
VST(SCRATCH, xEmu, offsetof(x64emu_t, ymm[i]));
|
||||
VST(dyn->lsx.avxcache[i].reg, xEmu, offsetof(x64emu_t, xmm[i]));
|
||||
if (dyn->lsx.avxcache[i].dirty) {
|
||||
XVXOR_V(SCRATCH, SCRATCH, SCRATCH);
|
||||
} else {
|
||||
XVPERMI_Q(SCRATCH, dyn->lsx.avxcache[i].reg, XVPERMI_IMM_4_0(0, 1));
|
||||
}
|
||||
VST(SCRATCH, xEmu, offsetof(x64emu_t, ymm[i]));
|
||||
} else {
|
||||
MESSAGE(LOG_DUMP, "\tAVX Cache for YMM%d is not write, no need to store back %d\n", i, dyn->lsx.lsxcache[dyn->lsx.avxcache[i].reg].t);
|
||||
}
|
||||
if (!next) {
|
||||
fpu_free_reg(dyn, dyn->lsx.avxcache[i].reg);
|
||||
@@ -1714,11 +1653,11 @@ void fpu_pushcache(dynarec_la64_t* dyn, int ninst, int s1, int not07)
|
||||
VST(dyn->lsx.ssecache[i].reg, xEmu, offsetof(x64emu_t, xmm[i]));
|
||||
}
|
||||
if ((dyn->lsx.avxcache[i].v != -1) && (dyn->lsx.avxcache[i].write)) {
|
||||
VST(dyn->lsx.avxcache[i].reg, xEmu, offsetof(x64emu_t, xmm[i]));
|
||||
if (dyn->lsx.avxcache[i].zero_upper == 0) {
|
||||
XVPERMI_Q(SCRATCH, dyn->lsx.avxcache[i].reg, XVPERMI_IMM_4_0(0, 1));
|
||||
VST(SCRATCH, xEmu, offsetof(x64emu_t, ymm[i]));
|
||||
}
|
||||
VST(dyn->lsx.avxcache[i].reg, xEmu, offsetof(x64emu_t, xmm[i]));
|
||||
if (!dyn->lsx.avxcache[i].dirty) {
|
||||
XVPERMI_Q(SCRATCH, dyn->lsx.avxcache[i].reg, XVPERMI_IMM_4_0(0, 1));
|
||||
VST(SCRATCH, xEmu, offsetof(x64emu_t, ymm[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
MESSAGE(LOG_DUMP, "\t------- Pushed XMM/YMM Cache (%d)\n", n);
|
||||
@@ -1743,7 +1682,7 @@ void fpu_popcache(dynarec_la64_t* dyn, int ninst, int s1, int not07)
|
||||
}
|
||||
if (dyn->lsx.avxcache[i].v != -1) {
|
||||
VLD(dyn->lsx.avxcache[i].reg, xEmu, offsetof(x64emu_t, xmm[i]));
|
||||
if (dyn->lsx.avxcache[i].zero_upper == 0) {
|
||||
if (!dyn->lsx.avxcache[i].dirty) {
|
||||
VLD(SCRATCH, xEmu, offsetof(x64emu_t, ymm[i]));
|
||||
XVPERMI_Q(dyn->lsx.avxcache[i].reg, SCRATCH, XVPERMI_IMM_4_0(0, 2));
|
||||
}
|
||||
@@ -1801,17 +1740,17 @@ void fpu_reset_cache(dynarec_la64_t* dyn, int ninst, int reset_n)
|
||||
{
|
||||
MESSAGE(LOG_DEBUG, "Reset Caches with %d\n", reset_n);
|
||||
#if STEP > 1
|
||||
// for STEP 2 & 3, just need to refrest with current, and undo the changes (push & swap)
|
||||
// for STEP 2 & 3, just need to refresh with current, and undo the changes (push & swap)
|
||||
dyn->lsx = dyn->insts[ninst].lsx;
|
||||
lsxcacheUnwind(&dyn->lsx);
|
||||
#else
|
||||
dyn->lsx = dyn->insts[reset_n].lsx;
|
||||
#endif
|
||||
lsxcacheUnwind(&dyn->lsx);
|
||||
#if STEP == 0
|
||||
if (dyn->need_dump) dynarec_log(LOG_NONE, "New x87stack=%d\n", dyn->lsx.x87stack);
|
||||
if (dyn->need_dump && dyn->lsx.x87stack) dynarec_log(LOG_NONE, "New x87stack=%d at ResetCache in inst %d with %d\n", dyn->lsx.x87stack, ninst, reset_n);
|
||||
#endif
|
||||
#if defined(HAVE_TRACE) && (STEP > 2)
|
||||
if (dyn->need_dump)
|
||||
if (dyn->need_dump && 0) // disable for now
|
||||
if (memcmp(&dyn->lsx, &dyn->insts[reset_n].lsx, sizeof(lsx_cache_t))) {
|
||||
MESSAGE(LOG_DEBUG, "Warning, difference in lsxcache: reset=");
|
||||
for (int i = 0; i < 24; ++i)
|
||||
@@ -2156,8 +2095,6 @@ static void fpuCacheTransform(dynarec_la64_t* dyn, int ninst, int s1, int s2, in
|
||||
lsxcache_t cache = dyn->lsx;
|
||||
int s1_val = 0;
|
||||
int s2_val = 0;
|
||||
// unload every unneeded cache
|
||||
// check SSE first, than MMX, in order, for optimization issue
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
int j = findCacheSlot(dyn, ninst, LSX_CACHE_YMMW, i, &cache);
|
||||
if (j >= 0 && findCacheSlot(dyn, ninst, LSX_CACHE_YMMW, i, &cache_i2) == -1)
|
||||
@@ -2221,14 +2158,12 @@ static void fpuCacheTransform(dynarec_la64_t* dyn, int ninst, int s1, int s2, in
|
||||
} else if (cache.lsxcache[i].t == LSX_CACHE_YMMR && cache_i2.lsxcache[i].t == LSX_CACHE_YMMW) {
|
||||
cache.lsxcache[i].t = LSX_CACHE_YMMW;
|
||||
} else if (cache.lsxcache[i].t == LSX_CACHE_YMMW && cache_i2.lsxcache[i].t == LSX_CACHE_YMMR) {
|
||||
// refresh cache...
|
||||
MESSAGE(LOG_DUMP, "\t - Refreh %s\n", getCacheName(cache.lsxcache[i].t, cache.lsxcache[i].n));
|
||||
MESSAGE(LOG_DUMP, "\t - Refresh %s\n", getCacheName(cache.lsxcache[i].t, cache.lsxcache[i].n));
|
||||
XVPERMI_Q(SCRATCH, i, XVPERMI_IMM_4_0(0, 1));
|
||||
VST(i, xEmu, offsetof(x64emu_t, xmm[cache.lsxcache[i].n]));
|
||||
VST(SCRATCH, xEmu, offsetof(x64emu_t, ymm[cache.lsxcache[i].n]));
|
||||
cache.lsxcache[i].t = LSX_CACHE_YMMR;
|
||||
} else if (cache.lsxcache[i].t == LSX_CACHE_XMMW && cache_i2.lsxcache[i].t == LSX_CACHE_XMMR) {
|
||||
// refresh cache...
|
||||
MESSAGE(LOG_DUMP, "\t - Refreh %s\n", getCacheName(cache.lsxcache[i].t, cache.lsxcache[i].n));
|
||||
VST(i, xEmu, offsetof(x64emu_t, xmm[cache.lsxcache[i].n]));
|
||||
cache.lsxcache[i].t = LSX_CACHE_XMMR;
|
||||
@@ -2270,24 +2205,36 @@ static void flagsCacheTransform(dynarec_la64_t* dyn, int ninst, int s1)
|
||||
int jmp = dyn->insts[ninst].x64.jmp_insts;
|
||||
if (jmp < 0)
|
||||
return;
|
||||
if (dyn->f.dfnone || ((dyn->insts[jmp].f_exit.dfnone && !dyn->insts[jmp].f_entry.dfnone) && !dyn->insts[jmp].x64.use_flags)) // flags are fully known, nothing we can do more
|
||||
if (dyn->insts[jmp].f_exit == dyn->insts[jmp].f_entry) // flags will be fully known, nothing we can do more
|
||||
return;
|
||||
MESSAGE(LOG_DUMP, "\tFlags fetch ---- ninst=%d -> %d\n", ninst, jmp);
|
||||
int go = (dyn->insts[jmp].f_entry.dfnone && !dyn->f.dfnone && !dyn->insts[jmp].df_notneeded) ? 1 : 0;
|
||||
switch (dyn->insts[jmp].f_entry.pending) {
|
||||
case SF_UNKNOWN:
|
||||
go = 0;
|
||||
break;
|
||||
default:
|
||||
if (go && !(dyn->insts[jmp].x64.need_before & X_PEND) && (dyn->f.pending != SF_UNKNOWN)) {
|
||||
// just clear df flags
|
||||
go = 0;
|
||||
ST_W(xZR, xEmu, offsetof(x64emu_t, df));
|
||||
int go_fetch = 0;
|
||||
switch (dyn->insts[jmp].f_entry) {
|
||||
case status_unk:
|
||||
if (dyn->insts[ninst].f_exit == status_none_pending) {
|
||||
FORCE_DFNONE();
|
||||
}
|
||||
break;
|
||||
case status_set:
|
||||
if (dyn->insts[ninst].f_exit == status_none_pending) {
|
||||
FORCE_DFNONE();
|
||||
}
|
||||
if (dyn->insts[ninst].f_exit == status_unk)
|
||||
go_fetch = 1;
|
||||
break;
|
||||
case status_none_pending:
|
||||
if (dyn->insts[ninst].f_exit != status_none)
|
||||
go_fetch = 1;
|
||||
break;
|
||||
case status_none:
|
||||
if (dyn->insts[ninst].f_exit == status_none_pending) {
|
||||
FORCE_DFNONE();
|
||||
} else
|
||||
go_fetch = 1;
|
||||
break;
|
||||
}
|
||||
if (go) {
|
||||
if (dyn->f.pending != SF_PENDING) {
|
||||
if (go_fetch) {
|
||||
if (dyn->f == status_unk) {
|
||||
LD_WU(s1, xEmu, offsetof(x64emu_t, df));
|
||||
j64 = (GETMARKF2) - (dyn->native_size);
|
||||
BEQZ(s1, j64);
|
||||
@@ -2295,6 +2242,7 @@ static void flagsCacheTransform(dynarec_la64_t* dyn, int ninst, int s1)
|
||||
CALL_(const_updateflags, -1, 0, 0, 0);
|
||||
MARKF2;
|
||||
}
|
||||
MESSAGE(LOG_DUMP, "\t---- Flags fetch\n");
|
||||
}
|
||||
|
||||
void CacheTransform(dynarec_la64_t* dyn, int ninst, int cacheupd, int s1, int s2, int s3)
|
||||
@@ -2332,3 +2280,24 @@ void la64_move64(dynarec_la64_t* dyn, int ninst, int reg, int64_t val)
|
||||
}
|
||||
LU52I_D(reg, reg, (val >> 52) & 0xfff);
|
||||
}
|
||||
|
||||
|
||||
void checkCRC(dynarec_la64_t* dyn, int ninst)
|
||||
{
|
||||
// la64_crc_autocrc will use x1-x5 instead of A0-A4 to avoind having to move around the regs
|
||||
// grab the dynablock address in x6, as this on will not be erased by crc functions
|
||||
int delta = -(dyn->native_size + sizeof(void*));
|
||||
PCADDU12I(x6, SPLIT20(delta));
|
||||
LD_D(x6, x6, SPLIT12(delta));
|
||||
// prepare and call the crc function
|
||||
TABLE64C(x3, const_la64_crc_autocrc);
|
||||
LD_D(x1, x6, offsetof(dynablock_t, x64_addr));
|
||||
LD_WU(x2, x6, offsetof(dynablock_t, x64_size));
|
||||
JIRL(xRA, x3, 0x0);
|
||||
// done, result in x1, load the stored hash (sign extended, as the crc will also be sign extended)
|
||||
LD_W(x2, x6, offsetof(dynablock_t, hash));
|
||||
// compare computed crc with stored one, jump to continue is equal
|
||||
BEQ(x1, x2, 4+3*4); // TABLE64C generates 2 opcodes...
|
||||
TABLE64C(x3, const_native_next_invalid);
|
||||
JIRL(xRA, x3, 0x0);
|
||||
}
|
||||
Loaded 100 of 583 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user