mirror of
https://github.com/ptitSeb/box64.git
synced 2026-11-08 10:10:25 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
03d220b1d2 | ||
|
|
053c4fd6bb | ||
|
|
7b0fada974 | ||
|
|
d09b46c1bf | ||
|
|
294178b598 | ||
|
|
e9242b8849 | ||
|
|
c5755c8241 | ||
|
|
75dcfb225a | ||
|
|
067e84eb05 | ||
|
|
faffa2a4d0 | ||
|
|
c3659df777 | ||
|
|
5aac024868 | ||
|
|
a4523caf81 | ||
|
|
db1c2cedbf | ||
|
|
4b96a74fc3 | ||
|
|
1b131d28df | ||
|
|
ec2e94249b | ||
|
|
0ffb15fce3 | ||
|
|
61a62645e8 | ||
|
|
e4edb65c2b | ||
|
|
b49bcbf68b | ||
|
|
eb69484bd6 | ||
|
|
195ac02ea1 | ||
|
|
8ebe32257e | ||
|
|
89e470d59c | ||
|
|
7a76430e87 | ||
|
|
60890a550b | ||
|
|
2038df85c0 | ||
|
|
ab5d2eba64 | ||
|
|
b142c5a181 | ||
|
|
37ed49cbb8 | ||
|
|
94ed2596c0 | ||
|
|
84498707dd | ||
|
|
d29be5fd14 | ||
|
|
53bb00a769 | ||
|
|
038e9511d1 | ||
|
|
94789d6705 | ||
|
|
67b15f09cf | ||
|
|
a0693590bd | ||
|
|
f1df65d88f | ||
|
|
6697c7d229 | ||
|
|
6a41f33bf3 | ||
|
|
67f7c988d5 | ||
|
|
01da6215de | ||
|
|
1fc558fcab | ||
|
|
c835881a77 | ||
|
|
a9f4e72c4b | ||
|
|
1f46ca81af | ||
|
|
8dbeee5dcb | ||
|
|
7a4cf9fc9e | ||
|
|
2fdd7f6188 | ||
|
|
803d8ac28a | ||
|
|
77c2683762 | ||
|
|
ae9ee3d9d8 | ||
|
|
6947a5bb94 | ||
|
|
103875b487 | ||
|
|
4c234b0418 | ||
|
|
abd1ebb425 | ||
|
|
e994c65116 | ||
|
|
c52b36abd4 | ||
|
|
a42936d998 | ||
|
|
e09adad1b9 | ||
|
|
b6429edf09 | ||
|
|
1e2bae9237 | ||
|
|
b7ddb92c80 | ||
|
|
d40f51bdc5 | ||
|
|
b78ffcfad8 | ||
|
|
3f9c5c496c | ||
|
|
37068c4f36 | ||
|
|
18a02fafb1 | ||
|
|
06d4fc79ec | ||
|
|
fa874ffcbc | ||
|
|
b729e3e37b | ||
|
|
73e7c6b480 | ||
|
|
5916869329 | ||
|
|
c9f3b990b4 | ||
|
|
6592b63800 | ||
|
|
1898d35c53 | ||
|
|
77f7c1278b | ||
|
|
1c7a7c9895 | ||
|
|
bd23f259cc | ||
|
|
efe1eb73dc | ||
|
|
8c51be6985 | ||
|
|
f25af13f79 | ||
|
|
019f85e4a3 | ||
|
|
7af5f625d7 | ||
|
|
a1ac9cccc4 | ||
|
|
b13811259a | ||
|
|
a7f4041604 | ||
|
|
72e05a52b2 | ||
|
|
e1e3122a1f | ||
|
|
4f88b2bdd7 | ||
|
|
5b8a71d720 | ||
|
|
58021bbf42 | ||
|
|
45d3cbd1b4 | ||
|
|
e07ec82344 | ||
|
|
37eb5492ba | ||
|
|
0e7b986116 | ||
|
|
be16c14dcb | ||
|
|
a1c29448a3 | ||
|
|
16bdcc0c93 | ||
|
|
2798c3c8cd | ||
|
|
d7538334e0 | ||
|
|
5dbcc4ad0d | ||
|
|
2cd4d60325 | ||
|
|
3dc00e9262 | ||
|
|
649af04fa5 | ||
|
|
3b97efb9ca | ||
|
|
8005af1387 | ||
|
|
5b45329968 | ||
|
|
b1379c88d4 | ||
|
|
274949f9d0 | ||
|
|
4a70577e6f | ||
|
|
b818a29499 | ||
|
|
69c88442b4 | ||
|
|
3d0b4ac9e1 | ||
|
|
4be5149b8d | ||
|
|
76ba181d98 | ||
|
|
4542244c4f | ||
|
|
a58e9d1dc9 | ||
|
|
938a2379c6 | ||
|
|
881814b21c | ||
|
|
915c4bf3b7 | ||
|
|
7a8a1a7791 | ||
|
|
e38d20e610 | ||
|
|
3d18e9c9e2 | ||
|
|
27685a4680 | ||
|
|
81b26569e5 | ||
|
|
76bbca2808 | ||
|
|
b435966bd0 | ||
|
|
be0839a478 | ||
|
|
f81f29b19a | ||
|
|
816c4bdb61 | ||
|
|
a9ddd396c4 | ||
|
|
f0b060dadd | ||
|
|
b1eabd7583 | ||
|
|
7a2d9967f5 | ||
|
|
2aeddc8829 | ||
|
|
df4dcf88da | ||
|
|
8160a90fd5 | ||
|
|
a8adde9234 | ||
|
|
daa3fca1f1 | ||
|
|
d744026819 | ||
|
|
689d6b9330 | ||
|
|
22fdc90fe2 | ||
|
|
78193c5f1a | ||
|
|
51d2b73cd7 | ||
|
|
7b5200094c | ||
|
|
5d14413b89 | ||
|
|
ec54969094 | ||
|
|
11513d662d | ||
|
|
6487ee0eda | ||
|
|
8d7db7f1fb | ||
|
|
11563f3b62 | ||
|
|
ff566e8116 | ||
|
|
1ddf9a0a00 | ||
|
|
35fa13899a | ||
|
|
5ee4385477 | ||
|
|
25000d0903 | ||
|
|
b96e410f53 | ||
|
|
6203880a5f | ||
|
|
889dd64c5f | ||
|
|
198eea49a8 | ||
|
|
b500a6ebc2 | ||
|
|
cb26a742ff | ||
|
|
4b44501d17 | ||
|
|
830cc8a498 | ||
|
|
16b0922ec5 | ||
|
|
9791016c74 | ||
|
|
ced1157132 | ||
|
|
56982e4c05 | ||
|
|
f5e93a14a2 | ||
|
|
eae608f35c | ||
|
|
89dbd81f27 | ||
|
|
c835227b8b | ||
|
|
57f07446ea | ||
|
|
7b2e084170 | ||
|
|
ab70523b39 | ||
|
|
f0859e6462 | ||
|
|
737a93a77c | ||
|
|
17cbeab0be | ||
|
|
313e16d2bc | ||
|
|
ae8b5b4239 | ||
|
|
1aa29ec1d3 | ||
|
|
f72d43b77e | ||
|
|
25de8bd35c | ||
|
|
5c9dc159d2 | ||
|
|
5a4021d72b | ||
|
|
ebaea69204 | ||
|
|
a221d50c17 | ||
|
|
4441be7a02 | ||
|
|
bb7dfd395f | ||
|
|
b552de33f9 | ||
|
|
35c8beb15f | ||
|
|
e1fd56123c | ||
|
|
b7ae6ebc27 | ||
|
|
9b904c622a | ||
|
|
950371427d | ||
|
|
be63129179 | ||
|
|
02423c2d7d | ||
|
|
4add55aa45 | ||
|
|
7334bb46c6 | ||
|
|
9c962f8b2c | ||
|
|
1f73944603 | ||
|
|
e844c5baa3 | ||
|
|
c849178bf8 | ||
|
|
ff4ae1f4d8 | ||
|
|
f7acb78743 | ||
|
|
6796b9ca02 | ||
|
|
e4da025dc0 | ||
|
|
b6b069cf8d | ||
|
|
f9475aa540 | ||
|
|
c6f0872e50 | ||
|
|
71dc02e06f | ||
|
|
e9715e4f0f | ||
|
|
8f197a7c08 | ||
|
|
3542c88dc1 | ||
|
|
4585b74310 | ||
|
|
768dfd37bb | ||
|
|
d8212fab48 | ||
|
|
740f4a19dc | ||
|
|
c469ed867a | ||
|
|
37dcb1a77b | ||
|
|
2e90a5dbaf | ||
|
|
d988a39456 | ||
|
|
fc381e744e | ||
|
|
e52b24b615 | ||
|
|
7158405b73 | ||
|
|
e059506d5e | ||
|
|
6da3a1265d | ||
|
|
d51997bc77 | ||
|
|
af555abb6f | ||
|
|
926e4b2da8 | ||
|
|
4903177bab | ||
|
|
d8a6fa0395 | ||
|
|
69127efae9 | ||
|
|
6f0db360a4 | ||
|
|
223de50ec9 | ||
|
|
5cfad22165 | ||
|
|
815836d285 | ||
|
|
468a3c2165 | ||
|
|
3afe87bcce | ||
|
|
d79d6bd6c2 | ||
|
|
cc6500b7dd | ||
|
|
ad494480ce | ||
|
|
854f6675db | ||
|
|
fc15743ff9 | ||
|
|
91ead3b12a | ||
|
|
75aaf7aa64 | ||
|
|
39a66e25ee | ||
|
|
574d6f9dab | ||
|
|
c39869b770 | ||
|
|
302b6493e2 | ||
|
|
20ea2987a8 | ||
|
|
eee547d50a | ||
|
|
a19f4b9eca | ||
|
|
6f3f3e0e85 | ||
|
|
2384462f61 | ||
|
|
e6e6c3ac65 | ||
|
|
102e6a1f61 | ||
|
|
460e6c517d | ||
|
|
965105c08a | ||
|
|
3fef880a7d | ||
|
|
e7b4c79d12 | ||
|
|
7cdfa187c5 | ||
|
|
d0da57547e | ||
|
|
e60fd72672 | ||
|
|
c6ae7d36dd | ||
|
|
3836625017 | ||
|
|
319f67d577 | ||
|
|
28d12f6785 | ||
|
|
e7113b228f | ||
|
|
bc3cfe82cf | ||
|
|
6ccac8ab5a | ||
|
|
c9d756eeea | ||
|
|
549b57ee30 | ||
|
|
660dbfc3ad | ||
|
|
d89ad5f1b9 | ||
|
|
00a7d321a7 | ||
|
|
4c9765cd5e | ||
|
|
fe307dbc96 | ||
|
|
518c860e5d | ||
|
|
053c389cfb | ||
|
|
81be6b1f30 | ||
|
|
3d975b090e | ||
|
|
882d933d84 | ||
|
|
9579dd9ff1 | ||
|
|
46a91e0ad9 | ||
|
|
b26a20e709 | ||
|
|
d7eb87129e | ||
|
|
7f569247d5 | ||
|
|
1ba0ea157f | ||
|
|
1e64476f31 | ||
|
|
96080e48cf | ||
|
|
4695a4ff3c | ||
|
|
8f3018e10c | ||
|
|
24b0ba9885 | ||
|
|
4f04deadfe | ||
|
|
064c2b037e | ||
|
|
12a90ebe98 | ||
|
|
5cd201241b | ||
|
|
6b2373af93 | ||
|
|
cf32412f98 | ||
|
|
f559bc48a4 | ||
|
|
0021fbbea3 | ||
|
|
ee530a7331 | ||
|
|
b7cb36d362 | ||
|
|
1bd471bf13 | ||
|
|
21911620c8 | ||
|
|
56f58501ec | ||
|
|
a89748e9e5 | ||
|
|
91f9a58b30 | ||
|
|
fea05a30e8 | ||
|
|
e678e8428b | ||
|
|
20377b9927 | ||
|
|
163689d2bb | ||
|
|
e49551bda5 | ||
|
|
514427cf8a | ||
|
|
68f5512ee7 | ||
|
|
b3165e62ab | ||
|
|
0fbf5f1896 | ||
|
|
592a2a75bb | ||
|
|
6c46e3d9b1 | ||
|
|
fa85d4d900 | ||
|
|
51d9eb966d | ||
|
|
310d4016fa | ||
|
|
0bb41a73c2 | ||
|
|
f9f082ee53 | ||
|
|
66bb1aeb89 | ||
|
|
91848efa34 | ||
|
|
5ea247b84c | ||
|
|
8c991cb676 | ||
|
|
70770db8be | ||
|
|
d0a5352c1a | ||
|
|
7391befb7e | ||
|
|
c9b6b5fbe0 | ||
|
|
62765f151a | ||
|
|
d592c1996d | ||
|
|
8b3d4404d7 | ||
|
|
b060fca66c | ||
|
|
4aab7a02f4 | ||
|
|
6d7af8674a | ||
|
|
5fc3188bc8 | ||
|
|
f4f868831a | ||
|
|
1e89ccb17e | ||
|
|
e80b595e8e | ||
|
|
ecc5375615 | ||
|
|
8da0fab674 | ||
|
|
fb955a3975 | ||
|
|
8cd3ba8c9e | ||
|
|
8cba915bca | ||
|
|
cd3163a785 | ||
|
|
b472459a22 | ||
|
|
42c241ee4e | ||
|
|
fb6ee29539 | ||
|
|
be6104c2ed | ||
|
|
3f90221b18 | ||
|
|
b5c792f5f0 | ||
|
|
b45d75f0c4 | ||
|
|
b68d46311d | ||
|
|
2c7a2082e6 | ||
|
|
3230265646 | ||
|
|
c2a77fca27 | ||
|
|
670876112e | ||
|
|
495d3cc4c0 | ||
|
|
b7ab26073e | ||
|
|
1c3df4b92c | ||
|
|
b1ba548d62 | ||
|
|
da4f574bdd | ||
|
|
8561a4a833 | ||
|
|
c40f9651bc | ||
|
|
104e582253 | ||
|
|
03c69338f5 | ||
|
|
0fa28b87f1 | ||
|
|
4ae94c5168 | ||
|
|
a429ca70e7 | ||
|
|
ee760fced1 | ||
|
|
a80659075d | ||
|
|
da0d0c1fc2 | ||
|
|
5ea2c245d6 | ||
|
|
e7b71cba5f | ||
|
|
d2817e7246 | ||
|
|
7ae8e9a86f | ||
|
|
0a59695fb3 | ||
|
|
cfdeb3685c | ||
|
|
fdf01ace3f | ||
|
|
30689882f0 | ||
|
|
d2e8ff5118 | ||
|
|
ec385c8e75 | ||
|
|
3aed032738 | ||
|
|
409b5a37fb | ||
|
|
9587e490cc | ||
|
|
ad40638345 | ||
|
|
443fe043e4 | ||
|
|
6d9560870d | ||
|
|
95d6106e3a | ||
|
|
5fb1ee033e | ||
|
|
fed73858c6 | ||
|
|
cb5a52bf40 | ||
|
|
eaa5f8feec | ||
|
|
8c6d9f04ec | ||
|
|
45f7b4991f | ||
|
|
98151eaebf | ||
|
|
933381f5fa | ||
|
|
a021fc2005 | ||
|
|
75e9aae281 | ||
|
|
b0de73852c | ||
|
|
d7744ea22d | ||
|
|
d3d3fa25f5 | ||
|
|
98162e395f | ||
|
|
9511d83955 | ||
|
|
10cbb3c8a9 | ||
|
|
0a3fa1c918 | ||
|
|
75e8b9961b | ||
|
|
5ab56ee172 | ||
|
|
7873b70306 | ||
|
|
86d9d851c6 | ||
|
|
aed08d428e | ||
|
|
affeef2380 | ||
|
|
a6c1e4126e | ||
|
|
ba630300b6 | ||
|
|
0e32c17076 | ||
|
|
14569db74d | ||
|
|
c519556962 | ||
|
|
c7280d9312 | ||
|
|
daca99017b | ||
|
|
546238681e | ||
|
|
87327b182f | ||
|
|
5b9951e1bd | ||
|
|
6ce22546fe | ||
|
|
2da064d04d | ||
|
|
77141304f6 | ||
|
|
3336cb6248 | ||
|
|
7fa3a1e627 | ||
|
|
d28c8aa41a | ||
|
|
7b065eb17a | ||
|
|
7f23664566 | ||
|
|
d555d9661f | ||
|
|
18888e404e | ||
|
|
394513971c | ||
|
|
8b75020036 | ||
|
|
e1d121aa6b | ||
|
|
30285d9ec6 | ||
|
|
9795027988 | ||
|
|
d49fb1568e | ||
|
|
ea067beac2 | ||
|
|
8905a31469 | ||
|
|
e6fd9c05f1 | ||
|
|
a79128e951 | ||
|
|
1793c2a182 | ||
|
|
b72002703e | ||
|
|
a17a97a545 | ||
|
|
0d73fc7228 | ||
|
|
8aab7296b8 | ||
|
|
4aa7eb1187 | ||
|
|
1af85c69a1 | ||
|
|
3087ea0e61 | ||
|
|
b0ad333ea4 | ||
|
|
835ecf8a19 | ||
|
|
470ff6e652 | ||
|
|
3ef6d28108 | ||
|
|
fb701d8e39 | ||
|
|
d4a539b957 | ||
|
|
7c4c6823fe | ||
|
|
3fc677cb85 | ||
|
|
2b300bd199 | ||
|
|
9c69ebd717 | ||
|
|
ea01b56422 | ||
|
|
216cf51d4a | ||
|
|
1476b502a2 | ||
|
|
bc53ae8925 | ||
|
|
9cef52a1fc | ||
|
|
5ed60d99a8 | ||
|
|
d7c7a716fe | ||
|
|
41bee35634 | ||
|
|
e764029cae | ||
|
|
b110623103 | ||
|
|
35c1f97115 | ||
|
|
e8a7bef5a0 | ||
|
|
c2f73e6de0 | ||
|
|
0724f52d5f | ||
|
|
61a605a2dc | ||
|
|
7a058c9194 | ||
|
|
99971e94c0 | ||
|
|
445d885090 | ||
|
|
fc02f0d140 | ||
|
|
c2d02977f8 | ||
|
|
946c999e25 | ||
|
|
c8b6f80f99 | ||
|
|
9444ce0b89 | ||
|
|
401d2ae0b9 | ||
|
|
8dde796103 | ||
|
|
7ba0e7a055 | ||
|
|
eb039c0449 | ||
|
|
0c0f5263e1 | ||
|
|
ad70febaac | ||
|
|
39583c6da4 | ||
|
|
1bf4851cf6 | ||
|
|
2129e98b0e | ||
|
|
b015f33376 | ||
|
|
2636e7e8b5 | ||
|
|
b0e726d953 | ||
|
|
eb40c49132 | ||
|
|
5dadc513db | ||
|
|
4120dc10bd | ||
|
|
48f51bd5fe | ||
|
|
940317949a | ||
|
|
f9b6ea48e9 | ||
|
|
3567c6da2b | ||
|
|
f3fe72b541 | ||
|
|
14966e48a6 | ||
|
|
91b282235b | ||
|
|
63c3e4fcf5 | ||
|
|
c740590bcd | ||
|
|
e868c89233 | ||
|
|
c517d7196d | ||
|
|
cb42b3b00f | ||
|
|
61362b06ec | ||
|
|
bb8559933f | ||
|
|
c2cb333261 | ||
|
|
b7e4cc4f50 | ||
|
|
a4908f1407 | ||
|
|
a252e87fa9 | ||
|
|
ee3ee539e0 | ||
|
|
c4b79374fe | ||
|
|
5dfa27ea58 | ||
|
|
49cba432c2 | ||
|
|
39a9cf903f | ||
|
|
611ac3933c | ||
|
|
fdd1509ee5 | ||
|
|
52a9443f53 | ||
|
|
0d1488b016 | ||
|
|
fb4662cb28 | ||
|
|
32a747979a | ||
|
|
362a92c158 | ||
|
|
c27b659bce | ||
|
|
049cbd3783 | ||
|
|
8b5b5aa3a7 | ||
|
|
f85b9ac664 | ||
|
|
ee5a41e21e | ||
|
|
d49fc43791 | ||
|
|
9ec7930eb1 | ||
|
|
26dd597a1b | ||
|
|
040f8d9a9f | ||
|
|
f107321d06 | ||
|
|
64313d5aa6 | ||
|
|
71845a11bb | ||
|
|
e3adda8ff9 | ||
|
|
85e79a8224 | ||
|
|
9ef3e080fa | ||
|
|
4b5f63dc6d | ||
|
|
730e9d215c | ||
|
|
efa1cbd49a | ||
|
|
91798194d5 | ||
|
|
d550f9384c | ||
|
|
d59d531f14 | ||
|
|
c9369c5ea1 | ||
|
|
05fd25d3bb | ||
|
|
2b75a0de55 | ||
|
|
59e1da5f74 | ||
|
|
639466d45a | ||
|
|
95bdaf6eca | ||
|
|
9dc10bdc47 | ||
|
|
bf212a7b52 | ||
|
|
40d83ad882 | ||
|
|
baa9efeaa6 | ||
|
|
0c17b55e28 | ||
|
|
e2f4ab7700 | ||
|
|
84982ff86f | ||
|
|
cfd17e59ac | ||
|
|
af0b0c6c9d | ||
|
|
0e588e444f | ||
|
|
f575a7846e | ||
|
|
c7ff0f658b | ||
|
|
b8cc8594f6 | ||
|
|
6197b70a9a | ||
|
|
60396f58c0 | ||
|
|
ee83ef4c01 | ||
|
|
4b7e116aa7 | ||
|
|
785d3ed5ab | ||
|
|
33d1727925 | ||
|
|
a50d34e4ba | ||
|
|
7e0c4dcee5 | ||
|
|
f5174d12aa | ||
|
|
2cb25c095a | ||
|
|
d0039c65b4 | ||
|
|
099bd148cb | ||
|
|
20885702b9 | ||
|
|
751582df05 | ||
|
|
5212de0d66 | ||
|
|
056bb38607 | ||
|
|
1a01adb2ef | ||
|
|
797731e9e2 | ||
|
|
3e2c698710 | ||
|
|
58b24c85a2 | ||
|
|
28ebc1a0b7 | ||
|
|
65487dac51 | ||
|
|
592af6db3b | ||
|
|
997140f500 | ||
|
|
16f0adec6f | ||
|
|
ba6ff73c69 | ||
|
|
2bf78ea18c | ||
|
|
fc6efb220b | ||
|
|
523bfbdf3b | ||
|
|
46ad2261e7 | ||
|
|
6c60ad4695 | ||
|
|
37697e2ec7 | ||
|
|
f5eb3c1e9b | ||
|
|
5cfd379e97 | ||
|
|
fecaf3111b | ||
|
|
ff6f34aadf | ||
|
|
4c3d55fb5c | ||
|
|
d2a5005dcc | ||
|
|
05e1b422d3 | ||
|
|
69f49f79e4 | ||
|
|
2453eb9b2d | ||
|
|
93b4813ee2 | ||
|
|
7cbe71c218 | ||
|
|
8bb53e1001 | ||
|
|
f79af5afd4 | ||
|
|
7c27085bd3 | ||
|
|
53834f2b29 | ||
|
|
7c09957263 | ||
|
|
242832fa3c | ||
|
|
9beb6b4f63 | ||
|
|
0861a88d6e | ||
|
|
1c0dc8ec7c | ||
|
|
b21776f9b0 | ||
|
|
998f164aa3 | ||
|
|
58d8627cea | ||
|
|
877ca41451 | ||
|
|
94dedd47c6 | ||
|
|
1173c1d23f | ||
|
|
d9c9575e6a | ||
|
|
2239f92816 | ||
|
|
637e177408 | ||
|
|
bb653e6888 | ||
|
|
09e07973dd | ||
|
|
6b7afd7f8e | ||
|
|
eb7858d23a | ||
|
|
1db09fe897 | ||
|
|
22a5b573d5 | ||
|
|
f12f366a3d | ||
|
|
b51ab081ae | ||
|
|
50fcaf04b4 | ||
|
|
96bca6eac3 | ||
|
|
ed7147e598 | ||
|
|
4892c68f17 | ||
|
|
3ab56994da | ||
|
|
a54afc8e04 | ||
|
|
01b5ee9c78 | ||
|
|
a513cd847b | ||
|
|
06b6871c80 | ||
|
|
f5dc038621 | ||
|
|
38dce9138d | ||
|
|
2aa5c5f337 | ||
|
|
e6d2c12792 | ||
|
|
c3dbdf419d | ||
|
|
c566ba970d | ||
|
|
81925643e8 | ||
|
|
285c874e53 | ||
|
|
ba078c63a8 | ||
|
|
a54959a6e3 | ||
|
|
c573742845 | ||
|
|
dab01b8b9f | ||
|
|
9e58047980 | ||
|
|
6f8f37e8ff | ||
|
|
3ec950726b | ||
|
|
cec62dad44 | ||
|
|
89eca28d3a | ||
|
|
313e4854a0 | ||
|
|
8c1ffca530 | ||
|
|
7099774a3c | ||
|
|
925f6a9922 | ||
|
|
356200159a | ||
|
|
f0d8712275 | ||
|
|
fe3b66b018 | ||
|
|
83af8c6cdf | ||
|
|
ad5b5ea617 | ||
|
|
b439817467 | ||
|
|
276191cdcf | ||
|
|
8438b61747 | ||
|
|
f4a9f8dd79 | ||
|
|
f235c7f702 | ||
|
|
8e1e2c7840 | ||
|
|
0b632afbfe | ||
|
|
89dcd2566b | ||
|
|
314edea645 | ||
|
|
fe28bd93bd | ||
|
|
d882a5c8fe | ||
|
|
044dec0bfa | ||
|
|
ed8b6fe9db | ||
|
|
c98b4c8f45 | ||
|
|
b78d81d319 | ||
|
|
9f3be89e12 | ||
|
|
9e0b300354 | ||
|
|
dde6d26236 | ||
|
|
e6eac39759 | ||
|
|
5654e77625 | ||
|
|
c9f01d975d | ||
|
|
1fe213f900 | ||
|
|
802002b7a3 | ||
|
|
69a7c00841 | ||
|
|
c24f040888 | ||
|
|
0f225fc1a0 | ||
|
|
666506e834 | ||
|
|
21c0a2e7d7 | ||
|
|
03204f709e | ||
|
|
6827fc6cc9 | ||
|
|
cff4798249 | ||
|
|
93bf308179 | ||
|
|
166c4858a1 | ||
|
|
4b8fb02198 | ||
|
|
8432f7d8e2 | ||
|
|
ec675564c6 | ||
|
|
8c71178238 | ||
|
|
72df0bd1a0 | ||
|
|
6035cbd5c1 | ||
|
|
d7007dd3cc | ||
|
|
9c5daf5954 | ||
|
|
a57bc9e780 | ||
|
|
2e2bed4374 | ||
|
|
4eeaddf490 | ||
|
|
0cd53ca748 | ||
|
|
fa2bd920bd | ||
|
|
613f2cccf1 | ||
|
|
d91461f468 | ||
|
|
bcc497c865 | ||
|
|
2414f82c38 | ||
|
|
fd7d811b29 | ||
|
|
e533cd0ea1 | ||
|
|
9b7e5d69b2 | ||
|
|
0c5e6d867f | ||
|
|
32c646d0d2 | ||
|
|
35a6828209 | ||
|
|
2b66675a08 | ||
|
|
93638ac95a | ||
|
|
f489761e68 | ||
|
|
56ccde005e | ||
|
|
47e4aa0b84 | ||
|
|
b977d84f11 | ||
|
|
b7f14ff338 | ||
|
|
86211e5970 | ||
|
|
d8669d7c7d | ||
|
|
0d8e02a3fe | ||
|
|
1e681cead0 | ||
|
|
53f2423578 | ||
|
|
6cdfa05604 | ||
|
|
d55e879879 | ||
|
|
d377433997 | ||
|
|
207073bf36 | ||
|
|
316f31a4bb | ||
|
|
ada8efcdef | ||
|
|
99d0889cfd | ||
|
|
653a67c8ad | ||
|
|
b99893d1c3 | ||
|
|
a5c4d01649 | ||
|
|
82105a1543 | ||
|
|
c65910fd25 | ||
|
|
b5de464e85 | ||
|
|
81eb0b45b3 | ||
|
|
c772d1ab49 | ||
|
|
1af7c15801 | ||
|
|
e11901a7a6 | ||
|
|
0b2f84df54 | ||
|
|
a1ff40733b | ||
|
|
a61888e06c | ||
|
|
691259ec0d | ||
|
|
91e678da5b | ||
|
|
8a7c2b5228 | ||
|
|
e7710f59fa | ||
|
|
4039f3c249 | ||
|
|
6f46ccdd5a | ||
|
|
b79ba11d95 | ||
|
|
5a35184ba7 | ||
|
|
db801da658 | ||
|
|
f160fe3300 | ||
|
|
5d5dd3a3bc | ||
|
|
5fa65a4b38 | ||
|
|
cc34c75fc3 | ||
|
|
7fb1a34947 | ||
|
|
d087020139 | ||
|
|
4065e61ec5 | ||
|
|
da6b799a10 | ||
|
|
967c73efd1 | ||
|
|
6a35cd2a56 | ||
|
|
ebf03f8878 | ||
|
|
d7dbee5126 | ||
|
|
08930381e9 | ||
|
|
495c98a488 | ||
|
|
80a4b61e5c | ||
|
|
1d20968f82 | ||
|
|
ca8d569e63 | ||
|
|
670770e24a | ||
|
|
b55b138303 | ||
|
|
d0c7cb46e7 | ||
|
|
6e1e7de52b | ||
|
|
bb0a445a6b | ||
|
|
7157803c03 | ||
|
|
b7c5adae3d | ||
|
|
809b663350 | ||
|
|
1c4f1cb8c2 | ||
|
|
cace5f0ccb | ||
|
|
4aaa0b5d24 | ||
|
|
c0829b807c | ||
|
|
7d3cdb06e3 | ||
|
|
42f3884478 | ||
|
|
fcd46e2cdc | ||
|
|
f36f9d290d | ||
|
|
ae512cc4ed | ||
|
|
4fd59da003 | ||
|
|
e2d7cc5011 | ||
|
|
79413a4147 | ||
|
|
80b357da41 | ||
|
|
a54f516447 | ||
|
|
26ba1148e8 | ||
|
|
8b2b96d5c5 | ||
|
|
e21a506936 | ||
|
|
e86c6359d6 | ||
|
|
acce64b268 | ||
|
|
89713993cb | ||
|
|
cf24eaf9d2 | ||
|
|
cd1ac51b79 | ||
|
|
a7ded59393 | ||
|
|
205ef4ddeb | ||
|
|
145689783f | ||
|
|
21a21b04e6 | ||
|
|
87e19076ad | ||
|
|
9492b6ca66 | ||
|
|
4a45db781f | ||
|
|
0329d5fcc2 | ||
|
|
f39b5514c5 | ||
|
|
4700a6322e | ||
|
|
91a8fef1bb | ||
|
|
a56a66a227 | ||
|
|
1b262dac29 | ||
|
|
3b15ef1cb5 | ||
|
|
9ac695b9be | ||
|
|
05060803b2 | ||
|
|
e84f2e4a8b | ||
|
|
6fac9ee35b | ||
|
|
93cc31bc48 | ||
|
|
13ee4acd59 | ||
|
|
1360e7112c | ||
|
|
12987af561 | ||
|
|
e071a70ec2 | ||
|
|
48db75961e | ||
|
|
da0820ce0a | ||
|
|
ac81132435 | ||
|
|
946da43038 | ||
|
|
cad9450e16 | ||
|
|
0c7cc657cc | ||
|
|
ce4590f5ba | ||
|
|
cd3f5ca97d | ||
|
|
fc2a6d4dd1 | ||
|
|
85fe4c628e | ||
|
|
1bb7d9efd8 | ||
|
|
25b4dd1457 | ||
|
|
ea13414083 | ||
|
|
3e745474d3 | ||
|
|
5ad2f155c1 | ||
|
|
945b4192b1 | ||
|
|
3b71ba6090 | ||
|
|
9fc4697233 | ||
|
|
8a37b12f81 | ||
|
|
6ac7d7a1db | ||
|
|
291db1530c | ||
|
|
e77ea1b45c | ||
|
|
80db0175e0 | ||
|
|
15f90899eb | ||
|
|
e2ce483e0d | ||
|
|
41b31dc58d | ||
|
|
f8b9c7b2b7 | ||
|
|
a8000cb629 | ||
|
|
17f2371804 | ||
|
|
4d377de5ab | ||
|
|
956f6ffc15 | ||
|
|
600ae18d4b | ||
|
|
39aa02c19c | ||
|
|
7dcb86f500 | ||
|
|
f873255a19 | ||
|
|
4662ab1c80 | ||
|
|
b0b34e3a2a | ||
|
|
631da8a532 | ||
|
|
f80886fd68 | ||
|
|
cbe7ced335 | ||
|
|
955f6e74ab | ||
|
|
8a982e8b5e | ||
|
|
47f5fe7caf | ||
|
|
6e0f32f4ca | ||
|
|
62eca11bee | ||
|
|
13f5ec1524 | ||
|
|
e751d41ba7 | ||
|
|
7fd884b9c1 | ||
|
|
a98887589d | ||
|
|
0882f910df | ||
|
|
f65c22d329 | ||
|
|
485959195e | ||
|
|
28fb1bb0c0 | ||
|
|
cc12620868 | ||
|
|
9c89e64691 | ||
|
|
d432b18d23 | ||
|
|
98c0811525 | ||
|
|
77b16ae30d | ||
|
|
f4a4bdd006 | ||
|
|
ed7dddc3d8 | ||
|
|
4c6401c66b | ||
|
|
42441c99cc | ||
|
|
f775474062 | ||
|
|
c30e012e8d | ||
|
|
d90522bc4e | ||
|
|
0f7bec0d38 | ||
|
|
201b971ad7 | ||
|
|
1c72527dc8 | ||
|
|
5ce3e29913 | ||
|
|
1a7cff559a | ||
|
|
c28b0629fa | ||
|
|
6a3c56c131 | ||
|
|
d03c85da90 | ||
|
|
6a5d831331 | ||
|
|
2164c564f2 | ||
|
|
2a33cf4e60 | ||
|
|
6698a844f6 | ||
|
|
1c5ccefdef | ||
|
|
64bfd06be4 | ||
|
|
5bf154195d | ||
|
|
0239305f69 | ||
|
|
3ee5558c70 | ||
|
|
059dc12adc | ||
|
|
610c63cd15 | ||
|
|
fa3db3df11 | ||
|
|
4b4c0143d9 | ||
|
|
fa76ce1f05 | ||
|
|
59bb9c2083 | ||
|
|
689d64b62a | ||
|
|
f6c3386960 | ||
|
|
5055866a5a | ||
|
|
9f7d0c4404 | ||
|
|
7e5aa3e7c6 | ||
|
|
c7afc0b3df | ||
|
|
566ff08109 | ||
|
|
2247b61ed3 | ||
|
|
55d6971a23 | ||
|
|
7168167400 | ||
|
|
7e17c862cf | ||
|
|
bb60cc8568 | ||
|
|
857c4600dc | ||
|
|
88bd65998f | ||
|
|
ecbd382ae4 | ||
|
|
16f63a94c3 | ||
|
|
bd7ff2efd6 | ||
|
|
ed21342995 | ||
|
|
4c238f0e17 | ||
|
|
7c000adb87 | ||
|
|
2d4f073925 | ||
|
|
a25aab1426 | ||
|
|
54f593fa75 | ||
|
|
054de8e83f | ||
|
|
e6d1bf78a6 | ||
|
|
b4b8617a92 | ||
|
|
20bad4e126 | ||
|
|
3650609975 | ||
|
|
fe3b30ccbb | ||
|
|
ccae82e1f5 | ||
|
|
f1addb8b28 | ||
|
|
96f5108a37 | ||
|
|
3eeb10c0a6 | ||
|
|
ce3d2afad2 | ||
|
|
bdee719767 | ||
|
|
42263e0be9 | ||
|
|
ca08012bbf | ||
|
|
ca47ee273e | ||
|
|
eb299f500b | ||
|
|
a25b50d3aa | ||
|
|
b735a8663e | ||
|
|
769c6c8f61 | ||
|
|
b250056a61 | ||
|
|
e305e5f1bb | ||
|
|
18ce48e2c0 | ||
|
|
06c93c93fe | ||
|
|
869ddcfdda | ||
|
|
65e5e86c2b | ||
|
|
122b5e64e8 | ||
|
|
6c66d66b02 | ||
|
|
85d694b36e | ||
|
|
44cff3ae25 | ||
|
|
c2d7dc573a | ||
|
|
a30433ea12 | ||
|
|
6f7b462d53 | ||
|
|
95e5724117 | ||
|
|
1eaef70d2d | ||
|
|
3ed1e565f8 | ||
|
|
8d0c976a18 | ||
|
|
9165ec875a | ||
|
|
6a7997b41e | ||
|
|
2a9d863131 | ||
|
|
e3e9a86088 | ||
|
|
d5c787c213 | ||
|
|
559040e290 | ||
|
|
59ba5b7f0e | ||
|
|
474a43a424 | ||
|
|
fb276bdc6b | ||
|
|
1c1a26626b | ||
|
|
93f29d8cd9 | ||
|
|
0054dde600 | ||
|
|
794f2104bc | ||
|
|
036af9f55f | ||
|
|
5bde45cc86 | ||
|
|
ae1739f330 | ||
|
|
cfc09e0965 | ||
|
|
26c9b3426f | ||
|
|
963da34562 | ||
|
|
4adad381ce | ||
|
|
e561196f44 | ||
|
|
14bd1368cc | ||
|
|
415fc458be | ||
|
|
f2822f1a05 | ||
|
|
646dd718f5 | ||
|
|
83ed8ebb22 | ||
|
|
88aab487f1 | ||
|
|
6d1e30cd3c | ||
|
|
ab73969ea4 | ||
|
|
93b371eb8c | ||
|
|
b7007a1bdd | ||
|
|
a26c108464 | ||
|
|
2971e9729c | ||
|
|
6b2d923041 | ||
|
|
cb30db320e | ||
|
|
e1ae914a1d | ||
|
|
51aa4b0416 | ||
|
|
b0db168fb5 | ||
|
|
3b3338d132 | ||
|
|
cc50331745 | ||
|
|
2777bc142f | ||
|
|
c73545e25b | ||
|
|
b862e74ae4 | ||
|
|
0d662b8543 | ||
|
|
ea0b23b783 | ||
|
|
f15a187087 | ||
|
|
12a82cf91f | ||
|
|
5af2fa49c3 | ||
|
|
843fe30e46 | ||
|
|
0da561cd20 | ||
|
|
fd613de55e | ||
|
|
b2dc460db9 | ||
|
|
e5b7dfb524 | ||
|
|
de0b602748 | ||
|
|
d0d85e684d | ||
|
|
05b322414a | ||
|
|
38ee050a09 | ||
|
|
1ee4959c05 | ||
|
|
bc9086551b | ||
|
|
f9f0c99c1b | ||
|
|
a1b46711c4 | ||
|
|
f6bb071f84 | ||
|
|
746a0031f8 | ||
|
|
f78d0ae471 | ||
|
|
7879a33cdc | ||
|
|
a84a9847be | ||
|
|
0c54e19c5f | ||
|
|
d507f8a6d0 | ||
|
|
b18efe4e40 | ||
|
|
83d69939f3 | ||
|
|
aee5032597 | ||
|
|
c7cc78194f | ||
|
|
089db91b39 | ||
|
|
cb33043dd4 | ||
|
|
b207ecad6a | ||
|
|
48461001d2 | ||
|
|
12649d04c7 | ||
|
|
5033738f73 | ||
|
|
df80b9c5de | ||
|
|
ffa94268d7 | ||
|
|
b7f0996459 | ||
|
|
dcf196c2ae | ||
|
|
a71856801b | ||
|
|
84608fc581 | ||
|
|
c30a392fe8 | ||
|
|
d8c16de2ec | ||
|
|
2d04cbe97c | ||
|
|
ab65422034 | ||
|
|
3bde222242 | ||
|
|
d0af86d5bf | ||
|
|
73b17d4add | ||
|
|
93fa5323c5 | ||
|
|
b0c10c9ae5 | ||
|
|
b8ed1b9646 | ||
|
|
0912e8f16d | ||
|
|
327dc2c835 | ||
|
|
8f937788ce | ||
|
|
52ba725fa5 | ||
|
|
a39249454e | ||
|
|
c1f2304c88 | ||
|
|
85c6e28d47 | ||
|
|
d1a253f469 | ||
|
|
6aa57f5c73 | ||
|
|
023aeae9e6 | ||
|
|
38880ab5a4 | ||
|
|
4e19324177 | ||
|
|
9757d1b67a | ||
|
|
5422b108af | ||
|
|
0d650b183f | ||
|
|
fa432bb9d1 | ||
|
|
81e4e26dc5 | ||
|
|
4f6a66f9c6 | ||
|
|
127d273ada | ||
|
|
469d4f81eb | ||
|
|
8f08a14115 | ||
|
|
4ac43047d0 | ||
|
|
4257fdded3 | ||
|
|
56298870f6 | ||
|
|
48354185dd | ||
|
|
5f0cbcf26d | ||
|
|
ffc875c2d6 | ||
|
|
8a180e3892 | ||
|
|
c4d3d734b1 | ||
|
|
6e8c244b77 | ||
|
|
ac2ed68228 | ||
|
|
fb27c89282 | ||
|
|
74bed6edcb | ||
|
|
49a854fa7e | ||
|
|
5adabbbcaa | ||
|
|
42eae3e1b4 | ||
|
|
518d2b0129 | ||
|
|
bc8c786b80 | ||
|
|
5ab8a6f6f4 | ||
|
|
385a31ec11 | ||
|
|
5c49954f69 | ||
|
|
6ce7a1ba1f | ||
|
|
8c1335626f | ||
|
|
8b0eec097b | ||
|
|
a39c8aa5c5 | ||
|
|
27745ceebb | ||
|
|
64b213fe42 | ||
|
|
eaca84e9ba | ||
|
|
bca0f4d66d | ||
|
|
8c17a37d1a | ||
|
|
979a3232f9 | ||
|
|
47dbbe030c | ||
|
|
d05e719ce3 | ||
|
|
12f4afcba2 | ||
|
|
cd2638d11a | ||
|
|
c87796e51c | ||
|
|
d47b555e12 | ||
|
|
4e568e1fdf | ||
|
|
0688c53675 | ||
|
|
6d523f9c7f | ||
|
|
0f4f274bc7 | ||
|
|
09b8c3b94e | ||
|
|
1dbb676f38 | ||
|
|
331866bd1d | ||
|
|
2515096f56 | ||
|
|
8868023ce9 | ||
|
|
dd9d6f8f83 | ||
|
|
21e403c908 | ||
|
|
f66aa57594 | ||
|
|
506cb980b1 | ||
|
|
937e2cf853 | ||
|
|
82bf71ee19 | ||
|
|
eb9e7b9fee | ||
|
|
b02942c0b0 | ||
|
|
56e813ccb7 | ||
|
|
cf5b94d471 | ||
|
|
5d941f702a | ||
|
|
b46925e7e0 | ||
|
|
e676756cda | ||
|
|
591958c59c | ||
|
|
63a80ff696 | ||
|
|
ee6e3a7a96 | ||
|
|
1d607cb937 | ||
|
|
c5ced39665 | ||
|
|
7b2e77807d | ||
|
|
7a623ef19c | ||
|
|
f292be40b2 | ||
|
|
0166330c73 | ||
|
|
3cc9d47032 | ||
|
|
128708db2d | ||
|
|
3027ee9f3e | ||
|
|
51c673e62d | ||
|
|
56bd83f6fb | ||
|
|
2473bb6902 | ||
|
|
da0e153a05 | ||
|
|
394e81af45 | ||
|
|
6af8d70cc1 | ||
|
|
2dea11a9e3 | ||
|
|
cd55c12e44 | ||
|
|
cb2cf7c9b1 | ||
|
|
494786be26 | ||
|
|
27013d6a03 | ||
|
|
3ba91a6513 | ||
|
|
c547090ee0 | ||
|
|
f87b9c15d3 | ||
|
|
3d76bcde2e | ||
|
|
1a6f49ce45 | ||
|
|
745a7fc034 | ||
|
|
6158a0ad45 | ||
|
|
a51f684c41 | ||
|
|
681e207af5 | ||
|
|
f651b7bfb0 | ||
|
|
6c53e12b49 | ||
|
|
01c9157fce | ||
|
|
3448e94171 | ||
|
|
08085be360 | ||
|
|
3809866d99 | ||
|
|
52a05c9f67 | ||
|
|
ba5aa0c83b | ||
|
|
939486fa05 | ||
|
|
c8d98f6901 | ||
|
|
38cfeeb558 | ||
|
|
cf9f8d0535 | ||
|
|
9e43737e18 | ||
|
|
5d03ad24c3 | ||
|
|
ac6721edac | ||
|
|
126cf27972 | ||
|
|
0a677c7f83 | ||
|
|
63e35941e2 | ||
|
|
3ae6992641 | ||
|
|
a243532730 | ||
|
|
ed99f5e6d2 | ||
|
|
7d1bf95d93 | ||
|
|
93cbf59e9e | ||
|
|
e8f9796752 | ||
|
|
adb423d96b | ||
|
|
74acad3628 | ||
|
|
541adff4d4 | ||
|
|
39189a746b | ||
|
|
f82e938ae8 | ||
|
|
34520c0b4f | ||
|
|
121148da72 | ||
|
|
1e34db98a8 | ||
|
|
9f821d6406 | ||
|
|
70a6d96748 | ||
|
|
4a440b6f0a | ||
|
|
fdfc5c4a41 | ||
|
|
6699c0ee7f | ||
|
|
8807b1aa3c | ||
|
|
2aff4239cc | ||
|
|
d99d18759b | ||
|
|
68c3be3e16 | ||
|
|
f148b106a5 | ||
|
|
9ffabf4c85 | ||
|
|
aebfd61539 | ||
|
|
8dee79d380 | ||
|
|
d3c1ea5b0f | ||
|
|
2835a2f87d | ||
|
|
062a098ac5 | ||
|
|
5563103453 | ||
|
|
a1d62eb92b | ||
|
|
138a021fad | ||
|
|
bdf0e95a12 | ||
|
|
90674b825a | ||
|
|
b3bc09f898 | ||
|
|
320459c2c6 | ||
|
|
8d14c10b8c | ||
|
|
2c2b252dac | ||
|
|
8efd1e3ae0 | ||
|
|
e7adc6b7f9 | ||
|
|
fc7d204d4b | ||
|
|
2153e7098c | ||
|
|
29beabd683 | ||
|
|
80c346060f | ||
|
|
4e10cd654f | ||
|
|
a12653a25d | ||
|
|
f683ae95c3 | ||
|
|
6bdeb18253 | ||
|
|
8f1f23c991 | ||
|
|
42345af443 | ||
|
|
a5797da100 | ||
|
|
0821e6acc2 | ||
|
|
0fb87c7926 | ||
|
|
b578487d01 | ||
|
|
cdf81eb1d7 | ||
|
|
97491658c6 | ||
|
|
b2b3653d67 | ||
|
|
de102bec5e | ||
|
|
3598f2855f | ||
|
|
f36a479d0f | ||
|
|
5363c013e6 | ||
|
|
b609328ac1 | ||
|
|
65c2b103b1 | ||
|
|
22a89ba914 | ||
|
|
fda9b6f75d | ||
|
|
b29e9b706e | ||
|
|
bd145ad6b2 | ||
|
|
fc71ec9785 | ||
|
|
cce43790d2 | ||
|
|
1e31e1fff8 | ||
|
|
af2a0c9747 | ||
|
|
d30488da87 | ||
|
|
59ba2fc7ab | ||
|
|
1936052e79 | ||
|
|
103ec5d72a | ||
|
|
9139ec3e5c | ||
|
|
7430463b33 | ||
|
|
6f2d067f3a | ||
|
|
d31b9c9caa | ||
|
|
2670d37542 | ||
|
|
617fd69bcc | ||
|
|
5fcd9d45a3 | ||
|
|
b6cd19b78b | ||
|
|
6a3a19da68 | ||
|
|
efd103004c | ||
|
|
18e033cdd8 | ||
|
|
2a4ecc1d28 | ||
|
|
c0c91678ba | ||
|
|
7a531ed272 | ||
|
|
93e3fcb386 | ||
|
|
143fc90a4c | ||
|
|
f65feaf9da | ||
|
|
a17b0effa1 | ||
|
|
b0d5c7a1a5 | ||
|
|
9c4a407fdc | ||
|
|
67b2151e3c | ||
|
|
b8024469da | ||
|
|
7f5c826bb1 | ||
|
|
acad3f3963 | ||
|
|
1f6ce24eaa | ||
|
|
4a82f21cc3 | ||
|
|
0cf707599d | ||
|
|
e2e6bdc4cb | ||
|
|
8136186554 | ||
|
|
9b733041af | ||
|
|
9e01876747 | ||
|
|
ee909b8c08 | ||
|
|
fdf1982982 | ||
|
|
88ccd7f537 | ||
|
|
c6cd9ceb75 | ||
|
|
ce735357d6 | ||
|
|
887dee83eb | ||
|
|
fd73a2bc8b | ||
|
|
21b5f90a33 | ||
|
|
d1c5cd7b0a | ||
|
|
656a36061a | ||
|
|
05384f581f | ||
|
|
84f3c104b2 | ||
|
|
761f7e40de | ||
|
|
b760c21414 | ||
|
|
bb651298c4 | ||
|
|
8850a11072 | ||
|
|
499338e80d | ||
|
|
c12f8fa254 | ||
|
|
7ae36b8667 | ||
|
|
591e2db712 | ||
|
|
8414563ad0 | ||
|
|
85fc57faa3 | ||
|
|
c8e10a004b | ||
|
|
e1fac2404c | ||
|
|
65adf2a860 | ||
|
|
dea6906ae9 | ||
|
|
22ccae3301 | ||
|
|
58d58b0af7 | ||
|
|
ce5daaa835 | ||
|
|
8fe0681681 | ||
|
|
3987e644a8 | ||
|
|
f073415510 | ||
|
|
4c69bcd97a | ||
|
|
05aac0879e | ||
|
|
cb5dafe8db | ||
|
|
82c7d45c4b | ||
|
|
f81677278f | ||
|
|
2ef6011c7a | ||
|
|
6e0b5358fb | ||
|
|
e783e3c794 | ||
|
|
8965d9bd70 | ||
|
|
37fe9bad6d | ||
|
|
a4daf4c228 | ||
|
|
ae080c3ad3 | ||
|
|
ad0c08c2de | ||
|
|
7b93791c3f | ||
|
|
172df2cd0c | ||
|
|
b395cd7ccc | ||
|
|
8ec6b15dc2 | ||
|
|
2a2f82a745 | ||
|
|
13a7801421 | ||
|
|
1a5cd1c1ff | ||
|
|
224974f218 | ||
|
|
b96556f80f | ||
|
|
c29be5b945 | ||
|
|
21b60db107 | ||
|
|
baa3f573ae | ||
|
|
0243e93e97 | ||
|
|
778bbc6d08 | ||
|
|
6ae502f181 | ||
|
|
088720db22 | ||
|
|
3d6ecc064f | ||
|
|
333bf19c00 | ||
|
|
25599b91b2 | ||
|
|
18305a1994 | ||
|
|
e6f56bf5fa | ||
|
|
681c6f4e5e | ||
|
|
11f1c3c4ff | ||
|
|
9f4eb36c99 | ||
|
|
cbbafafb46 | ||
|
|
9e853e487d | ||
|
|
0e91ad3ed3 | ||
|
|
c5e894aab2 | ||
|
|
49aaeb3080 | ||
|
|
1c7ac8c761 | ||
|
|
e2492a1426 | ||
|
|
f750391c2e | ||
|
|
95d65a02bc | ||
|
|
2685037c82 | ||
|
|
61c46994cd | ||
|
|
8b8e6501bc | ||
|
|
c4184ef733 | ||
|
|
6a5049b22c | ||
|
|
6cbcfc7ab8 | ||
|
|
564d06e84c | ||
|
|
8398799e1c | ||
|
|
c43d34d0cf | ||
|
|
a188f4ebfe | ||
|
|
e59063a13c | ||
|
|
2f95534bd0 | ||
|
|
2b0c8d45fa | ||
|
|
c88cf6359e | ||
|
|
62405c79c3 | ||
|
|
28dedd66b3 | ||
|
|
f26146bc23 | ||
|
|
2a0489a21c | ||
|
|
0980c4438a | ||
|
|
f7c93b68d8 | ||
|
|
f7e769f8c4 | ||
|
|
7f1ce6ebfd | ||
|
|
4715ef2633 | ||
|
|
703d19b256 | ||
|
|
f7d7fbb9b0 | ||
|
|
a6baf1f370 | ||
|
|
874238f61e | ||
|
|
9968963b97 | ||
|
|
5b68e46bb7 | ||
|
|
9a83521ad6 | ||
|
|
2a7eabfb1c | ||
|
|
b4a0ae20c9 | ||
|
|
87493a9bc9 | ||
|
|
0f9dac511c | ||
|
|
11724fd2ad | ||
|
|
c0955d33de | ||
|
|
bc5e686fde | ||
|
|
541489da4d | ||
|
|
79200d4df6 | ||
|
|
578bae3c37 | ||
|
|
37490d1a44 | ||
|
|
3919bb2e7d | ||
|
|
93e8434a87 | ||
|
|
97a1983c59 | ||
|
|
42e60bc7c5 | ||
|
|
93dc8fce10 | ||
|
|
34d4cde7c4 | ||
|
|
66788af44d | ||
|
|
1a8df98cf2 | ||
|
|
0fb0ac7994 | ||
|
|
24f278c961 | ||
|
|
d45001e4c9 | ||
|
|
95a0e669a2 | ||
|
|
b80e4c552a | ||
|
|
933dc0f5c8 | ||
|
|
6a3904fc48 | ||
|
|
b045dbde0f | ||
|
|
b85ebc73c9 | ||
|
|
7d76fc4945 | ||
|
|
90332ecf6e | ||
|
|
0c4c89f3ca | ||
|
|
62177d2ca3 | ||
|
|
144830bc05 | ||
|
|
24a5917b44 | ||
|
|
b38c5f095c | ||
|
|
d7ad7f0c70 | ||
|
|
dc391439ba | ||
|
|
e44c43deeb | ||
|
|
c795faf167 | ||
|
|
dad0913dcb | ||
|
|
e5db9aa874 | ||
|
|
2d0b60898c | ||
|
|
c25fc8cc24 | ||
|
|
bddeac4b45 | ||
|
|
1aa42a6779 | ||
|
|
73b3aec3ed | ||
|
|
9568cbac0a | ||
|
|
a60c742fa4 | ||
|
|
6313a31668 | ||
|
|
15a4be2db1 | ||
|
|
0c71d8d4e6 | ||
|
|
4409374c47 | ||
|
|
4299e0a3a3 | ||
|
|
c4af15c2e2 | ||
|
|
eacde4008e | ||
|
|
358e24ace5 | ||
|
|
7317472b5f | ||
|
|
9271684e5a | ||
|
|
929d462d05 | ||
|
|
e0ce06483c | ||
|
|
95e78088d6 | ||
|
|
dd72a4542e | ||
|
|
5fe0a68b46 | ||
|
|
61486749f8 | ||
|
|
31f574ed36 | ||
|
|
d9ff07b605 | ||
|
|
dbdb3d6af6 | ||
|
|
4c0a213840 | ||
|
|
aa65bad62b | ||
|
|
60c469ed06 | ||
|
|
cf87ae2e71 | ||
|
|
ea443cfa21 | ||
|
|
5e49e3cfaa | ||
|
|
8574c575f5 | ||
|
|
d2aecc0412 | ||
|
|
710d537f39 | ||
|
|
9e44c65391 | ||
|
|
c36491cfb6 | ||
|
|
c2be0268b1 | ||
|
|
4cda6dbcfb | ||
|
|
e34afea346 | ||
|
|
1ea71c89a8 | ||
|
|
856ffea797 | ||
|
|
9efae57162 | ||
|
|
09d4cb7b38 | ||
|
|
fb4f580922 | ||
|
|
15842f3464 | ||
|
|
e18846fac5 | ||
|
|
4aeb8ea1b0 | ||
|
|
6a415b54d0 | ||
|
|
5abdfd9751 | ||
|
|
ab65619b99 | ||
|
|
88629f7aa6 | ||
|
|
fb11af5859 | ||
|
|
550b72200d | ||
|
|
cd9d19a2bb | ||
|
|
ca9e43d0f0 | ||
|
|
04d2f90ab3 | ||
|
|
906cdb1584 | ||
|
|
1978ec8b71 | ||
|
|
28f32a3ca6 | ||
|
|
3b7a448b07 | ||
|
|
8f0c1efc6f | ||
|
|
c10b673fef | ||
|
|
bfd9f79267 | ||
|
|
f7c596317b | ||
|
|
e4debaf4ba | ||
|
|
4eeba053d5 | ||
|
|
7263a2e7ab | ||
|
|
ef7f25481c | ||
|
|
35d17abeb0 | ||
|
|
33472d3a8e | ||
|
|
e60ddf7ecd | ||
|
|
579332db7d | ||
|
|
b34c031139 | ||
|
|
46bc2e7183 | ||
|
|
26ddbf9466 | ||
|
|
b67dc452b2 | ||
|
|
b37b6addac | ||
|
|
a2dfe70cd8 | ||
|
|
20a2b4e051 | ||
|
|
d7c3c3fcf9 | ||
|
|
7d77a4b31f | ||
|
|
59217ccbbe | ||
|
|
f674953b87 | ||
|
|
b8798c580f | ||
|
|
2b58e8a253 | ||
|
|
f744513941 | ||
|
|
e8ecbbdc6a | ||
|
|
1f7c69e19e | ||
|
|
de4044d5b1 | ||
|
|
1503241c7a | ||
|
|
37a1261693 | ||
|
|
446d57122c | ||
|
|
1e8807ac0a | ||
|
|
40ac1bca84 | ||
|
|
bff3b935fb | ||
|
|
9faa9f41e0 | ||
|
|
9fa43f2386 | ||
|
|
f2397256e2 | ||
|
|
e5ad7c36ec | ||
|
|
3b8ba5dfa6 | ||
|
|
2e1b58a876 | ||
|
|
de7baa0b41 | ||
|
|
b361a0d2ff | ||
|
|
0acd849f18 | ||
|
|
ed4ff15682 | ||
|
|
de276ddfa9 | ||
|
|
192347ea3a | ||
|
|
d618cfdf0e | ||
|
|
0f0762a24c | ||
|
|
89a49db558 | ||
|
|
1ee51a54de | ||
|
|
68f394a38b | ||
|
|
32c94ac31a | ||
|
|
af476e0d10 | ||
|
|
b504d07afe | ||
|
|
9544fbdff9 | ||
|
|
431365d1f8 | ||
|
|
693b4adb4b | ||
|
|
1a637cb1d8 | ||
|
|
0d952641ed | ||
|
|
418e2a00ce | ||
|
|
d1d2de33e6 | ||
|
|
ab84faa3ca | ||
|
|
fc7f83c60b | ||
|
|
af028c9bad | ||
|
|
29daae551c | ||
|
|
e1a91ea420 | ||
|
|
bd60ed8df0 | ||
|
|
6b6d20732e | ||
|
|
4d60b75240 | ||
|
|
fc9900c8f6 | ||
|
|
629346b6a7 | ||
|
|
e95be7cd3f | ||
|
|
1bfb50f29a | ||
|
|
8187c35ea8 | ||
|
|
0d6028d837 | ||
|
|
2127eaea22 | ||
|
|
7794a623aa | ||
|
|
0443edc034 | ||
|
|
a7f8dbac56 | ||
|
|
b0ec124329 | ||
|
|
b40121c9b0 | ||
|
|
cc9984a082 | ||
|
|
c22758d794 | ||
|
|
1b48cd157a | ||
|
|
362402ffbf | ||
|
|
5ce868b100 | ||
|
|
823d1cc004 | ||
|
|
2ce5beae56 | ||
|
|
34fcbbd7b7 | ||
|
|
bdde96be95 | ||
|
|
26b7a49d82 | ||
|
|
fa8a5a2033 | ||
|
|
c87a56ef37 | ||
|
|
2e04ff93ca | ||
|
|
a9f96b9d62 | ||
|
|
8f855f5dde | ||
|
|
6d3fa25d5f | ||
|
|
57b7bcf8f4 | ||
|
|
f30d75ae5d | ||
|
|
e087e7782c | ||
|
|
17fa93035a | ||
|
|
f0d7582845 | ||
|
|
75bdb32828 | ||
|
|
fd633d2cee | ||
|
|
a6d7d83fb3 | ||
|
|
a450b9d12f | ||
|
|
5ac3eeef11 | ||
|
|
9838c2ccff | ||
|
|
16cee6feb2 | ||
|
|
21c86f9ac6 | ||
|
|
6044feb7fd | ||
|
|
7dc59ac342 | ||
|
|
16f156be3f | ||
|
|
64dd09becc | ||
|
|
19dc18f7c5 | ||
|
|
4e63b82f5e | ||
|
|
6bc2abae3b | ||
|
|
6c7f306baa | ||
|
|
c56517b801 | ||
|
|
b5e405b2b4 | ||
|
|
354f46f41b | ||
|
|
b34a50b381 | ||
|
|
a973c53ea2 | ||
|
|
ee7b10f064 | ||
|
|
c1ad6b5829 | ||
|
|
9eaaaaa1e3 | ||
|
|
115707a0f1 | ||
|
|
3179357666 | ||
|
|
cb7433d70a | ||
|
|
62021fc291 | ||
|
|
ab3ff07c93 | ||
|
|
22ab62a729 | ||
|
|
ff7a8bfdae | ||
|
|
27ed109394 | ||
|
|
ea807eda04 | ||
|
|
36321f809d | ||
|
|
254df70148 | ||
|
|
759cef6e01 | ||
|
|
02364151bc | ||
|
|
9178effd9f | ||
|
|
cce9e280ce | ||
|
|
5468d8b08e | ||
|
|
497f629761 | ||
|
|
6f08601479 | ||
|
|
6d6739ccea | ||
|
|
d2511e66fb | ||
|
|
e23eb14809 | ||
|
|
f5dbe2156c | ||
|
|
723b94da05 | ||
|
|
7ecdced486 | ||
|
|
13b72df762 | ||
|
|
95b38b7f79 | ||
|
|
3fb5052223 | ||
|
|
62b93a0785 | ||
|
|
371b45c420 | ||
|
|
4dcf14d026 | ||
|
|
854ee95d69 | ||
|
|
9ac536a1dd | ||
|
|
9820bee5e7 | ||
|
|
b02302a5cf | ||
|
|
9633ad35a8 | ||
|
|
4bd6294862 | ||
|
|
63e525697f | ||
|
|
4cdd46819f | ||
|
|
0450371e28 | ||
|
|
d9e5f8183f | ||
|
|
abbaf9b593 | ||
|
|
126c59b4a4 | ||
|
|
b7be225846 | ||
|
|
041eb4e69d | ||
|
|
04157f2502 | ||
|
|
189222cb66 | ||
|
|
6835c4aaf5 | ||
|
|
875a2ef3a9 | ||
|
|
bfbf18688b | ||
|
|
9de694c46b | ||
|
|
220c5ee47d | ||
|
|
99f2207fd4 | ||
|
|
50623f32f6 | ||
|
|
b5105a1e57 | ||
|
|
9beb745765 | ||
|
|
0b1dd757be | ||
|
|
a7c61d8e20 | ||
|
|
4988fb27dc | ||
|
|
db1f0825ce | ||
|
|
c7b2a5f2df | ||
|
|
b9cbd29bc4 | ||
|
|
84b53ecb42 | ||
|
|
66da28a02f | ||
|
|
15f6bbebe1 | ||
|
|
2daef545dd | ||
|
|
aac6b3d02d | ||
|
|
fda0e9a4cb | ||
|
|
f1da5d433a | ||
|
|
dead2003fa | ||
|
|
44dfa53d45 | ||
|
|
769a9f65a9 | ||
|
|
5b78159cb5 | ||
|
|
c384d53d75 | ||
|
|
683e44baf9 | ||
|
|
c845d0cf81 | ||
|
|
243a4deae7 | ||
|
|
fe80d6305c | ||
|
|
a0e7113397 | ||
|
|
d47b1b0e56 | ||
|
|
fa87b0fcef | ||
|
|
0f1bce0f32 | ||
|
|
bc0b5b1181 | ||
|
|
38833b9cf4 | ||
|
|
dda4f48397 | ||
|
|
bb712b1ad5 | ||
|
|
6ddb5b3477 | ||
|
|
c4253b73fa | ||
|
|
3c1f6c2436 | ||
|
|
83484cfb60 | ||
|
|
a106082397 | ||
|
|
6498248cef | ||
|
|
b2f94b274c | ||
|
|
34b85b3560 | ||
|
|
7bb30efb50 | ||
|
|
7df2b6b252 | ||
|
|
017d13a7b0 | ||
|
|
513647b272 | ||
|
|
280b1576c3 | ||
|
|
2dfd449561 | ||
|
|
65b1b9256a | ||
|
|
7866f116df | ||
|
|
4544e1556a | ||
|
|
8c7d96ad63 | ||
|
|
bd23e1f7fc | ||
|
|
99187a2d22 | ||
|
|
8974caf162 | ||
|
|
f364c03964 | ||
|
|
730eb1f472 | ||
|
|
3760be946f | ||
|
|
7db74b84cf | ||
|
|
4c0a25db2a | ||
|
|
67af8c2bad | ||
|
|
92531929f3 | ||
|
|
0256a6332c | ||
|
|
bd4454d8ad | ||
|
|
4187581be5 | ||
|
|
2a07636623 | ||
|
|
8893344b76 | ||
|
|
f0ea65dc36 | ||
|
|
53756ee966 | ||
|
|
8a2ee1ed59 | ||
|
|
9bc9c10fb3 | ||
|
|
4407a17551 | ||
|
|
c7d6395aa6 | ||
|
|
649a65b8ee | ||
|
|
949b64ca53 | ||
|
|
cef906b24d | ||
|
|
040c2c3d1b | ||
|
|
91ed6a83c1 | ||
|
|
d8ac8a5f1c | ||
|
|
18954abf54 | ||
|
|
ed7ee12e7e | ||
|
|
42d99d2b2a | ||
|
|
d24f13cd73 | ||
|
|
e8fad11128 | ||
|
|
27a8d19f31 | ||
|
|
387a3eeba3 | ||
|
|
3a3578aecc | ||
|
|
a8784eff9f | ||
|
|
b26ae5886d | ||
|
|
e6696f8d23 | ||
|
|
2989afdf84 | ||
|
|
9c1b015689 | ||
|
|
3b1fbef95c | ||
|
|
2e6acc86e1 | ||
|
|
c6e981a363 | ||
|
|
43de5afcf6 | ||
|
|
fb40035957 | ||
|
|
93549259a0 | ||
|
|
f39d3ea43e | ||
|
|
7ad169c7a8 | ||
|
|
052bba4578 | ||
|
|
d1eb01e535 | ||
|
|
3e20a60c37 | ||
|
|
984c136349 | ||
|
|
81f92d8f62 | ||
|
|
427051d04c | ||
|
|
c1a14f93d8 | ||
|
|
f07ee85078 | ||
|
|
51b118d516 | ||
|
|
d5ec4692d3 | ||
|
|
a62336d433 | ||
|
|
abb2cbeeaa | ||
|
|
33381857ff | ||
|
|
f1abd95ed0 | ||
|
|
43b155e8b4 | ||
|
|
6ee5415ea4 | ||
|
|
886ae378c5 | ||
|
|
60d886c052 | ||
|
|
d700cc1f55 | ||
|
|
5c212e92c3 | ||
|
|
1dde4ee959 | ||
|
|
9fe450f2dc | ||
|
|
b84e5f25f2 | ||
|
|
b52ff061b4 | ||
|
|
b7ae79514f | ||
|
|
a90c7af708 | ||
|
|
176e092a6c | ||
|
|
94ccde160a | ||
|
|
d8746c6c70 | ||
|
|
4ff4ca72d3 | ||
|
|
47055f92df | ||
|
|
7a4a44292c | ||
|
|
98270a8601 | ||
|
|
182ca255f7 | ||
|
|
3d33713c2b | ||
|
|
ebf698fdb6 | ||
|
|
9d089f9b18 | ||
|
|
c976833f46 | ||
|
|
1819b7563a | ||
|
|
548a21a5ec | ||
|
|
ad1dce7fb1 | ||
|
|
302a358476 | ||
|
|
74dd9f2778 | ||
|
|
495262f902 | ||
|
|
d10a078473 | ||
|
|
8d9fd7cb0e | ||
|
|
8bd8a923ba | ||
|
|
764a0c31e5 | ||
|
|
1ea0382055 | ||
|
|
bd673dc791 | ||
|
|
4fa00ba283 | ||
|
|
deef011dbf | ||
|
|
afeecf9d9f | ||
|
|
e792f00363 | ||
|
|
f7d9dd4824 | ||
|
|
dfc60e8bf1 | ||
|
|
655e752c07 | ||
|
|
ebdbd1767a | ||
|
|
4eca49697a | ||
|
|
7fa2371bbd | ||
|
|
60c41cadba | ||
|
|
97769b63ad | ||
|
|
bc482e29b0 | ||
|
|
62695ceed4 | ||
|
|
605d5a29c0 | ||
|
|
fdc7e9d1e4 | ||
|
|
dcc7ad45bc | ||
|
|
265f153449 | ||
|
|
ba9aa3657c | ||
|
|
115d666fff | ||
|
|
42ce1a3b61 | ||
|
|
a7b912393c | ||
|
|
e82f17842e | ||
|
|
4838c86ca9 | ||
|
|
d6b9fd2860 | ||
|
|
60dac1aa29 | ||
|
|
8dd071bcfa | ||
|
|
d92d693df3 | ||
|
|
d16bd5104e | ||
|
|
d7e8da6321 | ||
|
|
aec3fd524a | ||
|
|
14b0323bf6 | ||
|
|
b482847779 | ||
|
|
8c5752de23 | ||
|
|
267bffb0ec | ||
|
|
0546216228 | ||
|
|
a46ea2c07f | ||
|
|
ed4e1ee0ba | ||
|
|
6ac3716594 | ||
|
|
42bad3ea6b | ||
|
|
f9c4eda1fc | ||
|
|
688665e730 | ||
|
|
a676255231 | ||
|
|
d227edeefd | ||
|
|
34c3e2dab3 | ||
|
|
2c0bbc06b7 | ||
|
|
299551428f | ||
|
|
d0ac9c2a5a | ||
|
|
a69368e855 | ||
|
|
84b0e2f113 | ||
|
|
eb695d5553 | ||
|
|
b5946f3752 | ||
|
|
371435afd0 | ||
|
|
0ba46403c6 | ||
|
|
cac43a1f5f | ||
|
|
7771a67abe | ||
|
|
9cd8812d8b | ||
|
|
4b0b3fc98a | ||
|
|
c6afd44c1c | ||
|
|
dbb84245a0 | ||
|
|
15a7c4d8dd | ||
|
|
a842938cfe | ||
|
|
3f83038061 | ||
|
|
01568f8fd3 | ||
|
|
1ee4d5aaf4 | ||
|
|
f9b74642a2 | ||
|
|
401e3a7282 | ||
|
|
32b2b388c8 | ||
|
|
013643782f | ||
|
|
cb064f9e5a | ||
|
|
52c97c47ab | ||
|
|
5f06d066e7 | ||
|
|
a7a211fc85 | ||
|
|
5540601918 | ||
|
|
22f99601d9 | ||
|
|
2fe2e52249 | ||
|
|
6caa598dd7 | ||
|
|
aeeb9b719a | ||
|
|
36f1808615 | ||
|
|
0ce5f34f8c | ||
|
|
579ae99d1b | ||
|
|
fa702c0240 | ||
|
|
34bc807bd5 | ||
|
|
71d49badcc | ||
|
|
3dfcc278e0 | ||
|
|
e312fa392d | ||
|
|
bda28e5882 | ||
|
|
68c2abc429 | ||
|
|
b0727d6f2b | ||
|
|
c66be063aa | ||
|
|
1f0165f895 | ||
|
|
b1ae5dc2b6 | ||
|
|
df228f8829 | ||
|
|
dc2d54edf2 | ||
|
|
d39c554541 | ||
|
|
314b2a5583 | ||
|
|
ce30c1179e | ||
|
|
cbb3126b28 | ||
|
|
a3413ba96d | ||
|
|
2b625e4aa5 | ||
|
|
df74626ca2 | ||
|
|
10373ca6fc | ||
|
|
3dcd08bd4a | ||
|
|
a945daf96d | ||
|
|
22116dabc3 | ||
|
|
5494d95b6b | ||
|
|
9ab686b3e0 | ||
|
|
5b24440e8c | ||
|
|
44deff987c | ||
|
|
7273ac0d34 | ||
|
|
ceb9834a27 | ||
|
|
4eebf25f1c | ||
|
|
865ef2ff6e | ||
|
|
8138ba6ecb | ||
|
|
f1c0b52677 | ||
|
|
a4cb62d6d6 | ||
|
|
e4062c6031 | ||
|
|
08844f31c9 | ||
|
|
4dfdba001b | ||
|
|
8dbf982ebe | ||
|
|
031255a946 | ||
|
|
8dfbe80b41 | ||
|
|
2bcc997e4b | ||
|
|
263e79be53 | ||
|
|
d031a8b423 | ||
|
|
7bec96e4b2 | ||
|
|
6bb1bacfba | ||
|
|
95a4aaf8fd | ||
|
|
387c64b74c | ||
|
|
4d068eee26 | ||
|
|
ece732ba41 | ||
|
|
8f40dc1a8c | ||
|
|
c9a6d4c05a | ||
|
|
a66b4e257a | ||
|
|
3796805d98 | ||
|
|
a3d09e95d5 | ||
|
|
626846c37b | ||
|
|
8bf1ac6577 | ||
|
|
58c0bce4cf | ||
|
|
3a82dc6aad | ||
|
|
e42b9e2866 | ||
|
|
8a85acff32 | ||
|
|
b450ea24a2 | ||
|
|
4fa92dc069 | ||
|
|
61a80c9b2d | ||
|
|
bcfd0f7ea3 | ||
|
|
c404b3e0ab | ||
|
|
b246133b3b | ||
|
|
5b28d7bc03 | ||
|
|
8adaefcdb9 | ||
|
|
e64b4d5c04 | ||
|
|
59caccfeae | ||
|
|
bbd3333b5f | ||
|
|
1ce7f32b5d | ||
|
|
95f18dbf15 | ||
|
|
9ed2e3bbf2 | ||
|
|
8b3cd23045 | ||
|
|
072241eb10 | ||
|
|
84a8500323 | ||
|
|
a8911fc979 | ||
|
|
04ba0b2f67 | ||
|
|
d1e5bc5c19 | ||
|
|
38364ef07f | ||
|
|
b25d8db994 | ||
|
|
989ed95891 | ||
|
|
d15ffc48a3 | ||
|
|
06df8c7bed | ||
|
|
950241d52f | ||
|
|
a147c12f72 | ||
|
|
874828c2ac | ||
|
|
3369e5e755 | ||
|
|
9b3930ea62 | ||
|
|
987d0db806 | ||
|
|
97530e4095 | ||
|
|
4c285d4d8a | ||
|
|
cd5fbc1492 | ||
|
|
2e379300a6 | ||
|
|
65c19d073c | ||
|
|
eb013f3492 | ||
|
|
b2fd651abe | ||
|
|
d4b02e6a3f | ||
|
|
537cb65f26 | ||
|
|
f61367fc9a | ||
|
|
46e0505336 | ||
|
|
75004d0b56 | ||
|
|
0dc5761ca6 | ||
|
|
df47fb5be8 | ||
|
|
0cedc70eb3 | ||
|
|
1612687acf | ||
|
|
67d587cd9b | ||
|
|
9e97e96b87 | ||
|
|
79c1ad1431 | ||
|
|
c0ebe09521 | ||
|
|
b568cc529e | ||
|
|
dc8e24c7b7 | ||
|
|
ba411303e9 | ||
|
|
8848bc2e7f | ||
|
|
f7798f361a | ||
|
|
6a25427cb6 | ||
|
|
a6c283f4ce | ||
|
|
48bb907d2d | ||
|
|
c2ce5d5557 | ||
|
|
0d30fe90f8 | ||
|
|
c434cef45e | ||
|
|
d01970f731 | ||
|
|
bb9beb75d1 | ||
|
|
ad3a9e6c55 | ||
|
|
9a30b65180 | ||
|
|
cb548fe1fa | ||
|
|
0a8f049ced | ||
|
|
890809069e | ||
|
|
ca9a6fe019 | ||
|
|
94ccae727b | ||
|
|
001e77952e | ||
|
|
ac6a453833 | ||
|
|
307915130c | ||
|
|
3d225ef908 | ||
|
|
1c9123637a | ||
|
|
f1f690552f | ||
|
|
57dcf3401c | ||
|
|
9e5df7957e | ||
|
|
ca63389ea3 | ||
|
|
7b7ee070b9 | ||
|
|
3aee16e9a0 | ||
|
|
06cb3624e2 | ||
|
|
a1f83418b9 | ||
|
|
e5a32ea129 | ||
|
|
eb209abe62 | ||
|
|
13551fd410 | ||
|
|
2493706315 | ||
|
|
b49273c079 | ||
|
|
7c1b161277 | ||
|
|
d8a1dcc1b4 | ||
|
|
f44d60c58f | ||
|
|
dc71840a5a | ||
|
|
07b17cd0f6 | ||
|
|
cf37e8ea83 | ||
|
|
5384489702 | ||
|
|
1ad69d785f | ||
|
|
ef3acd9f33 | ||
|
|
083b42fead | ||
|
|
c6814a6f97 | ||
|
|
9dbd7fc7e0 | ||
|
|
a79eff3b0d | ||
|
|
a89d7a2e2a | ||
|
|
0336f6a987 | ||
|
|
6d68975ba5 | ||
|
|
2b07fd7c6a | ||
|
|
f8cc423f3d | ||
|
|
f4667fa3cf | ||
|
|
d8f929755a | ||
|
|
031685e0a7 | ||
|
|
9f260eb86c | ||
|
|
75878b24cd | ||
|
|
fe0425eb80 | ||
|
|
453003da23 | ||
|
|
eec08973bf | ||
|
|
c65f8da90f | ||
|
|
2970ed5bfd | ||
|
|
bfebcba431 | ||
|
|
dde85b761b | ||
|
|
34809e48d8 | ||
|
|
6749c2d1a6 | ||
|
|
7eb24ff514 | ||
|
|
e367a2bcc9 | ||
|
|
a02283264a | ||
|
|
7a7e9ee9af | ||
|
|
b7f25a48c2 | ||
|
|
4477aa3159 | ||
|
|
4fd23c752c | ||
|
|
60b625bc0f | ||
|
|
d1703b9bc0 | ||
|
|
eb9da7417f | ||
|
|
782f497b20 | ||
|
|
003a83b40b | ||
|
|
2f8d28e7da | ||
|
|
fa591589c7 | ||
|
|
f0ea459c57 | ||
|
|
f3d733c3ff | ||
|
|
19ca78769f | ||
|
|
3e5784cbc5 | ||
|
|
98d9f36f9c | ||
|
|
22bc6872f4 | ||
|
|
f6fe84afad | ||
|
|
4744534fc9 | ||
|
|
af05d7439f | ||
|
|
6e22f4fd6d | ||
|
|
0e3d92148b | ||
|
|
06cf6d2ecc | ||
|
|
7b5654eea4 | ||
|
|
503eb41939 | ||
|
|
a77db3c6a5 | ||
|
|
4e0889469a | ||
|
|
7c5bf62fc0 | ||
|
|
b79f86b8d1 | ||
|
|
b9f5929439 | ||
|
|
3dc396a647 | ||
|
|
c358bf448f | ||
|
|
abd1d56d7f | ||
|
|
22b9c16351 | ||
|
|
0131958136 | ||
|
|
9f70767acf | ||
|
|
bdeb8d7ee2 | ||
|
|
de831ee5ac | ||
|
|
da1cb42f2a | ||
|
|
2c366ef4bd | ||
|
|
bc0f31407f | ||
|
|
0d755e610b | ||
|
|
55ee7fcc33 | ||
|
|
10200d7b55 | ||
|
|
1eab6a0c8e | ||
|
|
fc2d50c7d3 | ||
|
|
aaed0364bd | ||
|
|
9e0139f3c3 | ||
|
|
ec3c3b7eed | ||
|
|
c67632722b | ||
|
|
580fbf47b2 | ||
|
|
4bffdce8af | ||
|
|
f22e9bf1d2 | ||
|
|
95b516127a | ||
|
|
da7474b1de | ||
|
|
27aa9011ce | ||
|
|
d09a48fd03 | ||
|
|
b5c0a857ca | ||
|
|
ab9f848dcd | ||
|
|
1b3350437c | ||
|
|
03749788e8 | ||
|
|
9a571cfb72 | ||
|
|
39303611ef | ||
|
|
fcf0cf00d0 | ||
|
|
2ee846f48e | ||
|
|
9c846a3e40 | ||
|
|
712e8315f8 | ||
|
|
604ab22526 | ||
|
|
85d09df938 | ||
|
|
5ae93f8431 | ||
|
|
3aab8dd332 | ||
|
|
bf9d297dcd | ||
|
|
080cc77208 | ||
|
|
7ebd92be7d | ||
|
|
22b2f63917 | ||
|
|
5bcfa34bea | ||
|
|
48c47423a4 | ||
|
|
229cae16d1 | ||
|
|
9edb89fc22 | ||
|
|
3faabb478d | ||
|
|
2c127fe69c | ||
|
|
3765d9e6f7 | ||
|
|
8545d0505f | ||
|
|
28b101aaf7 | ||
|
|
24d1250e66 | ||
|
|
706ca3649e | ||
|
|
bb537e4dd5 | ||
|
|
eb59ff2ebd | ||
|
|
7842c9e34d | ||
|
|
3882a98755 | ||
|
|
14c9dc5bdb | ||
|
|
181457b69f | ||
|
|
0b6f543bbd | ||
|
|
01a386445c | ||
|
|
3fce669f6e | ||
|
|
8a701755d8 | ||
|
|
aead503f02 | ||
|
|
7ef2af2549 | ||
|
|
1e44a93c87 | ||
|
|
2e55dec949 | ||
|
|
c80a83485d | ||
|
|
8915484251 | ||
|
|
ed3450388b | ||
|
|
a2d580e926 | ||
|
|
47085bb9c9 | ||
|
|
73619f4d75 | ||
|
|
5228338f97 | ||
|
|
71c0aff78f | ||
|
|
4d7e106088 | ||
|
|
d7127ccc3d | ||
|
|
04e960b0da | ||
|
|
8d199cfc6c | ||
|
|
ffa58e23f1 | ||
|
|
289f94599d | ||
|
|
d0b51ae18f | ||
|
|
cea459d1e3 | ||
|
|
f6cd825ab9 | ||
|
|
f8fa438728 | ||
|
|
07aacc9b08 | ||
|
|
50325785f5 | ||
|
|
ef49b97c75 | ||
|
|
75110ac028 | ||
|
|
57bfa38328 | ||
|
|
2c00386e99 | ||
|
|
3b03b7aee6 | ||
|
|
1491270f1d | ||
|
|
46dfaab639 | ||
|
|
ff755facc0 | ||
|
|
d38f659f42 | ||
|
|
6d95a64412 | ||
|
|
21336c527a | ||
|
|
3db2362c86 | ||
|
|
99b7ef0c92 | ||
|
|
ff030fcbec | ||
|
|
ecf19029f5 | ||
|
|
9494801d0b | ||
|
|
1501592fa8 | ||
|
|
12467916a4 | ||
|
|
6f0eb56621 | ||
|
|
31dabf51ae | ||
|
|
22fd100b04 | ||
|
|
20092ef1ac | ||
|
|
aad6a16984 | ||
|
|
9b00df93c2 | ||
|
|
f1da71a8fe | ||
|
|
efd182971a | ||
|
|
40c5125a92 | ||
|
|
0f6654bf95 | ||
|
|
fa27ddecc5 | ||
|
|
e5be67b005 | ||
|
|
85458d1f20 | ||
|
|
5b5723c5a5 | ||
|
|
e148e89091 | ||
|
|
1d0614f0f3 | ||
|
|
2405e6c8e8 | ||
|
|
817408d247 | ||
|
|
8d77e39f4a | ||
|
|
0fe7e7a88d | ||
|
|
08bc57045a | ||
|
|
ee58b6a734 | ||
|
|
2907e5a0bd | ||
|
|
4f229629c0 | ||
|
|
f0fd2bc30c | ||
|
|
86e9a38384 | ||
|
|
322f97ddbc | ||
|
|
695865f408 | ||
|
|
1f9834dc6b | ||
|
|
d1555a4c78 | ||
|
|
5fc4477a94 | ||
|
|
a5753ec0b5 | ||
|
|
f256c48505 | ||
|
|
71c5447b8a | ||
|
|
a9a338ff42 | ||
|
|
06a21d490b | ||
|
|
ef0c9bd429 | ||
|
|
f619df2773 | ||
|
|
41ae74757e | ||
|
|
2304738336 | ||
|
|
e70a9ba485 | ||
|
|
61a759f802 | ||
|
|
3cb61ff840 | ||
|
|
b7a07c3816 | ||
|
|
ae386b3a7d | ||
|
|
2b8a8314c5 | ||
|
|
eb28edbe58 | ||
|
|
8d683fc19c | ||
|
|
0c50f724e6 | ||
|
|
d406946c2d | ||
|
|
1c7e620a86 | ||
|
|
c40096e128 | ||
|
|
43d2817407 | ||
|
|
ff14ccc0a5 | ||
|
|
1222fee0d0 | ||
|
|
b184a184c4 | ||
|
|
e5dcb3f100 | ||
|
|
411fe19ee5 | ||
|
|
1c040117ec | ||
|
|
856d2653bc | ||
|
|
2a79b60454 | ||
|
|
db32e49879 | ||
|
|
65d83bb6f4 | ||
|
|
17b7ec6358 | ||
|
|
73c3190c86 | ||
|
|
b6f58caf24 | ||
|
|
8c19c3a72c | ||
|
|
c017d3e894 | ||
|
|
35696508fb | ||
|
|
7e3996b0d9 | ||
|
|
a7ec8e7c55 | ||
|
|
dfaa6896c1 | ||
|
|
b64e6bdbba | ||
|
|
e0ef248943 | ||
|
|
cdcb0a46dc | ||
|
|
e82e1f9905 | ||
|
|
cb6616bba1 | ||
|
|
e0f0afdf91 | ||
|
|
5120e74b36 | ||
|
|
8f5fa863bf | ||
|
|
d4e32fdbc0 | ||
|
|
067cf75c65 | ||
|
|
7f16ddacf7 | ||
|
|
d936c072ea | ||
|
|
7dee075c10 | ||
|
|
b9ea2408c2 | ||
|
|
6ce570f4a5 | ||
|
|
b95b99b3c9 | ||
|
|
139197230d | ||
|
|
1d0e0307c4 | ||
|
|
f94ab1be6f | ||
|
|
05c7596acb | ||
|
|
b38d51ce37 | ||
|
|
5c0d765f59 | ||
|
|
db35542706 | ||
|
|
eda857cb10 | ||
|
|
b77c8fe5f1 | ||
|
|
0d864ed848 | ||
|
|
7c613198ce | ||
|
|
1ca68a58fd | ||
|
|
b96139274f | ||
|
|
d84faf57ab | ||
|
|
89f0c494e4 | ||
|
|
24f9263fa4 | ||
|
|
5f4f9337cd | ||
|
|
2a75d28386 | ||
|
|
3e41289167 | ||
|
|
9cf5373724 | ||
|
|
6c5d35df6b | ||
|
|
4d26021705 | ||
|
|
2e9b8eff59 | ||
|
|
a4142f68ce | ||
|
|
4a889e39ad | ||
|
|
d206d69b25 | ||
|
|
83e92d6298 | ||
|
|
e080551d54 | ||
|
|
b40195d26d | ||
|
|
316abec693 | ||
|
|
af685a263b | ||
|
|
31e8afa622 | ||
|
|
1d500ad965 | ||
|
|
a8866c3f41 | ||
|
|
f64eca5d9b | ||
|
|
bdd5e7018a | ||
|
|
3d211143e0 | ||
|
|
c1c11d8daa | ||
|
|
0505b19378 | ||
|
|
e18e532846 | ||
|
|
10cec3de2f | ||
|
|
76c0992d02 | ||
|
|
e32a78a944 | ||
|
|
68d710cd94 | ||
|
|
da64a3eeab | ||
|
|
912622bf1f | ||
|
|
70fec208d8 | ||
|
|
e1f69b9c61 | ||
|
|
81f25b219f | ||
|
|
d191b8c090 | ||
|
|
d53ff127ed | ||
|
|
50caca8fdc | ||
|
|
1dca97b4d3 | ||
|
|
14cf474167 | ||
|
|
47b1203805 | ||
|
|
81ca016581 | ||
|
|
cd8bda7a29 | ||
|
|
8115b47051 | ||
|
|
6384cc6e86 | ||
|
|
2f68df2b5f | ||
|
|
ed2697d6ad | ||
|
|
df928fd2d0 | ||
|
|
52c50a2fd4 | ||
|
|
666d051806 | ||
|
|
1e80316a7d | ||
|
|
65404cba33 | ||
|
|
ac0519a046 | ||
|
|
90a6306bbe | ||
|
|
a5a7d9382e | ||
|
|
bc770d908a | ||
|
|
20724ceb17 | ||
|
|
6ae6ac0272 | ||
|
|
5aa5015348 | ||
|
|
411aecde6f | ||
|
|
e89b93285e | ||
|
|
4e702cfeda | ||
|
|
33846405d8 | ||
|
|
378eb79ad3 | ||
|
|
da71b81d01 | ||
|
|
35d734e6ac | ||
|
|
3937fc4b71 | ||
|
|
5debac4c98 | ||
|
|
3737abe081 | ||
|
|
d0013c0700 | ||
|
|
460277289b | ||
|
|
35ed305718 | ||
|
|
d3c57eecbc | ||
|
|
ad75da8502 | ||
|
|
c7c6880a01 | ||
|
|
5ed3ef918d | ||
|
|
c0f78342e1 | ||
|
|
75494978ad | ||
|
|
602c015321 | ||
|
|
55c2c9ee59 | ||
|
|
8fef5f2c69 | ||
|
|
9a4a62ff2d | ||
|
|
4ebc462e23 | ||
|
|
08e93a0fe9 | ||
|
|
4096869c50 | ||
|
|
3cd87e68c7 | ||
|
|
7165ff7b84 | ||
|
|
81d906fd3b | ||
|
|
b51bdf3d5e | ||
|
|
c8ca7876c3 | ||
|
|
c181a6dcc8 | ||
|
|
b763c22ef4 | ||
|
|
5c83475c95 | ||
|
|
1d1670864b | ||
|
|
5e980767b9 | ||
|
|
2b3c9b95af | ||
|
|
09232ad0b6 | ||
|
|
2533197a3c | ||
|
|
71c43b0de7 | ||
|
|
6606b7b097 | ||
|
|
5c994ff222 | ||
|
|
9372b96e47 | ||
|
|
24e133e006 | ||
|
|
995fa013a6 | ||
|
|
4af1f56713 | ||
|
|
584b258241 | ||
|
|
fb13ce2baf | ||
|
|
f910a70c8a | ||
|
|
fedb8bd816 | ||
|
|
c3f97dd730 | ||
|
|
b1ebf9dc79 | ||
|
|
d07ea96570 | ||
|
|
dc3bdd89c1 | ||
|
|
7e92c912b2 | ||
|
|
5d5c3aec3c | ||
|
|
0ba63ea272 | ||
|
|
a242a8e277 | ||
|
|
cc86e94cd5 | ||
|
|
1c10ae443d | ||
|
|
d44f3d9bae | ||
|
|
d71e5f968a | ||
|
|
4aa9fba4fa | ||
|
|
8aaaddde03 | ||
|
|
d5176ba278 | ||
|
|
13a8108e1e | ||
|
|
82b19f6f69 | ||
|
|
9e37dd008d | ||
|
|
5b1057fe08 | ||
|
|
460fa3f3d7 | ||
|
|
61de3532c2 | ||
|
|
ddfc699809 | ||
|
|
d0edf2e8dd | ||
|
|
a159cb5efe | ||
|
|
26371bb9dd | ||
|
|
de4ffcc8bc | ||
|
|
ebaedca708 | ||
|
|
a86f597239 | ||
|
|
b72d3a77e9 | ||
|
|
64fdf54156 | ||
|
|
463e31251f | ||
|
|
9032f24a56 | ||
|
|
c5828803c6 | ||
|
|
9883c6464e | ||
|
|
67006f2809 | ||
|
|
e49728aa82 | ||
|
|
829c254b1f | ||
|
|
8bf54eda56 | ||
|
|
c58adce8f6 | ||
|
|
92532b0fd1 | ||
|
|
8cba5d55ce | ||
|
|
da1ac7beee | ||
|
|
28b79626d9 | ||
|
|
867059dfae | ||
|
|
50250bd2ca | ||
|
|
0e71c3a2ac | ||
|
|
db01a92edf | ||
|
|
6a9836912d | ||
|
|
bdcfd69795 | ||
|
|
dbe1bb0ec4 | ||
|
|
d76841bdc1 | ||
|
|
0251a29841 | ||
|
|
32b0c173f0 | ||
|
|
90167afc2b | ||
|
|
6a4a58185e | ||
|
|
6cffabacb3 | ||
|
|
d658c47cd0 | ||
|
|
21b06ace43 | ||
|
|
7a27b95df7 | ||
|
|
a730935e6e | ||
|
|
ef705ed494 | ||
|
|
fb6915b059 | ||
|
|
20d675ea48 | ||
|
|
900dbc2a47 | ||
|
|
d8affd8564 | ||
|
|
f3d4a1e1c3 | ||
|
|
d5ebea7928 | ||
|
|
bd95c7a366 | ||
|
|
20fc160230 | ||
|
|
c786e6d576 | ||
|
|
e9ce6a4f80 | ||
|
|
0024e4b970 | ||
|
|
cf8ea5953e | ||
|
|
65ddcdeabb | ||
|
|
6576686b36 | ||
|
|
13404ed090 | ||
|
|
ff6cc84482 | ||
|
|
02caee0c02 | ||
|
|
7260da63af | ||
|
|
ec0d333d81 | ||
|
|
d3eb6b8a11 | ||
|
|
cc0ce73d39 | ||
|
|
2eb92951af | ||
|
|
f8202096f1 | ||
|
|
f470d552cf | ||
|
|
be50bbc149 | ||
|
|
50c49a1692 | ||
|
|
70496c9bde | ||
|
|
f7f7c1c9af | ||
|
|
f02d5fc28f | ||
|
|
422a982917 | ||
|
|
ce60a8cfa2 | ||
|
|
f0026927e3 | ||
|
|
d1388dd7eb | ||
|
|
ffda782c3d | ||
|
|
3a6df996dc | ||
|
|
6141376977 | ||
|
|
3ec2ebabfc | ||
|
|
77dcb025fd | ||
|
|
bbaa01af79 | ||
|
|
d033f34a45 | ||
|
|
f2eb5326af | ||
|
|
f09b541ab7 | ||
|
|
e71df7eb67 | ||
|
|
9d1e6b9b96 | ||
|
|
0d43b16fd5 | ||
|
|
b179bd2415 | ||
|
|
64fbd3db46 | ||
|
|
ea096cd593 | ||
|
|
7934e3ad5c | ||
|
|
52a5335770 | ||
|
|
f3d1ffbe01 | ||
|
|
b40a17fc51 | ||
|
|
02fadef9e7 | ||
|
|
6e4d2470d2 | ||
|
|
8e4faa3de2 | ||
|
|
4f3b9f19a7 | ||
|
|
e562baf30b | ||
|
|
efefd13bf5 | ||
|
|
4314ef1ca8 | ||
|
|
477e531af9 | ||
|
|
47b8e2a983 | ||
|
|
cc01018223 | ||
|
|
7a28084b63 | ||
|
|
ea86b0e32f | ||
|
|
96169af71e | ||
|
|
4633817374 | ||
|
|
a190910cbf | ||
|
|
6170fc8e43 | ||
|
|
aa279c332d | ||
|
|
a79e1be034 | ||
|
|
5924a8eca1 | ||
|
|
fc920b0838 | ||
|
|
e33d51641f | ||
|
|
4b979bf206 | ||
|
|
bc5afbea89 | ||
|
|
65f75b0cc0 | ||
|
|
c50b0ef9e8 | ||
|
|
10c479034f | ||
|
|
3c95826c5c | ||
|
|
fa11368599 | ||
|
|
f4fd01c777 | ||
|
|
96941c9978 | ||
|
|
c5a6875de9 | ||
|
|
549e042e67 | ||
|
|
c70581abc9 | ||
|
|
5e6af37532 | ||
|
|
c0184f926d | ||
|
|
a69e81f034 | ||
|
|
5c01fbabac | ||
|
|
fed47bea4a | ||
|
|
213c063895 | ||
|
|
632af46137 | ||
|
|
b527ebbf5b | ||
|
|
ad55cfde7f | ||
|
|
44e77de620 | ||
|
|
40de8e16ec | ||
|
|
d36f9e4dbb | ||
|
|
a65f448856 | ||
|
|
8cba593882 | ||
|
|
0715dd145f | ||
|
|
5a20322251 | ||
|
|
89b5e1163d | ||
|
|
6a9dbe3d89 | ||
|
|
8e6ae3aa01 | ||
|
|
e46707750b | ||
|
|
b1f6ea8ae6 | ||
|
|
82ae65f477 | ||
|
|
4a3595133a | ||
|
|
4c9a6a5d98 | ||
|
|
a2e01c36ba | ||
|
|
774d872f41 | ||
|
|
fa19435d24 | ||
|
|
902186bdff | ||
|
|
6996c06909 | ||
|
|
315068b111 | ||
|
|
4047d1ba3c | ||
|
|
d74bee3596 | ||
|
|
aea1049223 | ||
|
|
3548195fbe | ||
|
|
8d0cc15eb0 | ||
|
|
ee2580a57f | ||
|
|
255d5c661e | ||
|
|
a60d945968 | ||
|
|
f8fa53aa3b | ||
|
|
1642327015 | ||
|
|
399478d635 | ||
|
|
608c13ebba | ||
|
|
99694d67ca | ||
|
|
bde279f2fa | ||
|
|
e4f56f0b23 | ||
|
|
3e8da0cc1a | ||
|
|
ca0e12d93f | ||
|
|
0c41d9810f | ||
|
|
165961f27e | ||
|
|
81386b7a56 | ||
|
|
5bf2a7d51b | ||
|
|
3fa527b45b | ||
|
|
121d986b11 | ||
|
|
f18f5c9b85 | ||
|
|
d5808f6be3 | ||
|
|
2984d30118 | ||
|
|
efbb5a2ae5 | ||
|
|
31aafe23b7 | ||
|
|
09779e294c | ||
|
|
2fe872de3d | ||
|
|
153d8d2cf0 | ||
|
|
1b07a10b5d | ||
|
|
d743c8235f | ||
|
|
7781bfcbac | ||
|
|
0fd81e067f | ||
|
|
acc2f2e3d5 | ||
|
|
a2be60cce8 | ||
|
|
1344b18379 | ||
|
|
1deec05f3d | ||
|
|
2ee5bcf933 | ||
|
|
5f57de017c | ||
|
|
508a153973 | ||
|
|
5d8b70cc0d | ||
|
|
d60ba04cf4 | ||
|
|
8b3949497a | ||
|
|
754b69f746 | ||
|
|
55c99e9ad7 | ||
|
|
aa2e212480 | ||
|
|
96c6abc889 | ||
|
|
74a73dfc97 | ||
|
|
d3b5553433 | ||
|
|
b8856af18c | ||
|
|
63428d0b2e | ||
|
|
22afd245a8 | ||
|
|
26fdf2275a | ||
|
|
1ad38124df | ||
|
|
aaa4fd1265 | ||
|
|
9793c3b142 | ||
|
|
5a753761dd | ||
|
|
37be26e539 | ||
|
|
96023f2274 | ||
|
|
30b83f4f9c | ||
|
|
265f969a44 | ||
|
|
d5b182cac0 | ||
|
|
ce296f0e32 | ||
|
|
6d5c3489c9 | ||
|
|
d48ab49437 | ||
|
|
8ee250e9ac | ||
|
|
e485fe1d18 | ||
|
|
35a32481c6 | ||
|
|
beaf543012 | ||
|
|
c40e31f374 | ||
|
|
f9c09293bf | ||
|
|
cdffe2388e | ||
|
|
6c0af2dbb9 | ||
|
|
eee428afe5 | ||
|
|
047815c764 | ||
|
|
3b8e0d69a3 | ||
|
|
56f2749da0 | ||
|
|
7d85753350 | ||
|
|
367363a8bd | ||
|
|
30d0836329 | ||
|
|
1680dc63d9 | ||
|
|
806298843f | ||
|
|
7cee4e2453 | ||
|
|
82f21de83e | ||
|
|
65c4f9d9c3 | ||
|
|
8043f53d7d | ||
|
|
124672b811 | ||
|
|
28ef6cdefc | ||
|
|
5e38ea28b6 | ||
|
|
1d0d7e9e09 | ||
|
|
aab6bc0869 | ||
|
|
77213bee1d | ||
|
|
90fc1d93ad | ||
|
|
e51f36c651 | ||
|
|
fc63442ded | ||
|
|
0ee5174e18 | ||
|
|
0004f19325 | ||
|
|
da724e3dd5 | ||
|
|
96ccf0dab9 | ||
|
|
aba3e4a460 | ||
|
|
bc852aebeb | ||
|
|
89da530898 | ||
|
|
2367e7df50 | ||
|
|
2ca85a4976 | ||
|
|
e3860cf09c | ||
|
|
07be405f48 | ||
|
|
92d5210e37 | ||
|
|
01bf7aa774 | ||
|
|
427ca732fe | ||
|
|
ca92a0b90a | ||
|
|
db4547115c | ||
|
|
3ad4a3ae3a | ||
|
|
7bef772488 | ||
|
|
e4c64073c5 | ||
|
|
0ff15e91d9 | ||
|
|
a584aa7df8 | ||
|
|
57ca9dfdbc | ||
|
|
3a2073f785 | ||
|
|
e963d99d5e | ||
|
|
bbe188d4f9 | ||
|
|
9df1ed0b3b | ||
|
|
742998b477 | ||
|
|
a577fac1c5 | ||
|
|
d08abf05ff | ||
|
|
cd6af18183 | ||
|
|
a425275108 | ||
|
|
92f7b6fd9e | ||
|
|
68c7586c4c | ||
|
|
9549a3599c | ||
|
|
b826049893 | ||
|
|
88d950bafb | ||
|
|
50242c6eaa | ||
|
|
e5649d90e7 | ||
|
|
d22e6f28a1 | ||
|
|
307acee9d3 | ||
|
|
184b2cc26b | ||
|
|
613781e6c0 | ||
|
|
92c3c1f829 | ||
|
|
6268367b22 | ||
|
|
4c174a42f8 | ||
|
|
71463476f6 | ||
|
|
20b388c1d2 | ||
|
|
3ab7648384 | ||
|
|
9fb84e3ef2 | ||
|
|
d6bfce9a5d | ||
|
|
328d5c6275 | ||
|
|
19be6b5e17 | ||
|
|
499f9633ba | ||
|
|
774ca6cd80 | ||
|
|
22b5cf3536 | ||
|
|
18fa8af728 | ||
|
|
0f01bdad13 | ||
|
|
d787f67ab8 | ||
|
|
16de80f46a | ||
|
|
294bc51f83 | ||
|
|
70987fc55f | ||
|
|
5b700cb6e6 | ||
|
|
dcb31fa783 | ||
|
|
411a52e16f | ||
|
|
41bfd757ad | ||
|
|
d94c6f2132 | ||
|
|
29052c7a90 | ||
|
|
48de41137d | ||
|
|
203d06831e | ||
|
|
3e9c435ed1 | ||
|
|
e65fda875a | ||
|
|
70c745dd84 | ||
|
|
870b71afec | ||
|
|
18e0af6b38 | ||
|
|
ed87cc1b1e | ||
|
|
5d6ff69e8d | ||
|
|
cbea2b5443 | ||
|
|
a891e1f85d | ||
|
|
ade0aa770a | ||
|
|
a5f2f3b3f1 | ||
|
|
077ba65f7e | ||
|
|
6f6a426424 | ||
|
|
163158cf12 | ||
|
|
e4821aa9e1 | ||
|
|
9b23c3272b | ||
|
|
3454afb3e4 | ||
|
|
ab99ae6951 | ||
|
|
a609452cfd | ||
|
|
ee1256a676 | ||
|
|
a9837a3aaf | ||
|
|
499492e10a | ||
|
|
6e77ce999a | ||
|
|
dd05eeb821 | ||
|
|
919f8faeee | ||
|
|
b0db8e1ae0 | ||
|
|
3e0f2bfc4a | ||
|
|
5e9e1faedc | ||
|
|
dba6a88341 | ||
|
|
ee0b86c0c2 | ||
|
|
7ea2e1bf51 | ||
|
|
c801f2d4a5 | ||
|
|
ae84f02bd0 | ||
|
|
a6c73e2840 | ||
|
|
e6bc1d7c22 | ||
|
|
e2abb6b6db | ||
|
|
cb63cdcd42 | ||
|
|
1f28b9f98d | ||
|
|
7fcc0ba8a4 | ||
|
|
6773ac88af | ||
|
|
46bee1d532 | ||
|
|
10062373d1 | ||
|
|
68e3c2be9b | ||
|
|
099df7a0ee | ||
|
|
21b6537215 | ||
|
|
eb70f6d18e | ||
|
|
4ee6ae5da1 | ||
|
|
2c8d2d8643 | ||
|
|
0582b45389 | ||
|
|
f7cbe71bd9 | ||
|
|
1b87600658 | ||
|
|
446fb9c99f | ||
|
|
c774cb0c27 | ||
|
|
8ff9427a04 | ||
|
|
b427e67619 | ||
|
|
6163f98020 | ||
|
|
316b2fc98a | ||
|
|
9c73204224 | ||
|
|
7da59d5a39 | ||
|
|
a34b63b80d | ||
|
|
5b335f0f26 | ||
|
|
28af18f36e | ||
|
|
10bb9f7079 | ||
|
|
ed7006bbf4 | ||
|
|
b272f6bf15 | ||
|
|
715ce5dbe9 | ||
|
|
7d0f807880 | ||
|
|
b66eccedc0 | ||
|
|
f79e725aa3 | ||
|
|
66c4b6815f | ||
|
|
f073da1d27 | ||
|
|
dad0d648a1 | ||
|
|
f20262c5c8 | ||
|
|
23b6617a3f | ||
|
|
ab5c02c2ae | ||
|
|
1005cee4bc | ||
|
|
95a1b12c07 | ||
|
|
23542bbfee | ||
|
|
ec65c26b3c | ||
|
|
837cc9dd93 | ||
|
|
88a8d1c209 | ||
|
|
f4b780b806 | ||
|
|
3a296d237f | ||
|
|
db64c02bee | ||
|
|
97023ce1dd | ||
|
|
3a87a2665d | ||
|
|
6a2f4fb30d | ||
|
|
49b9b70c29 | ||
|
|
356340ad09 | ||
|
|
986bff1c22 |
No files matched your search
@@ -11,4 +11,8 @@ SortIncludes: false
|
||||
MaxEmptyLinesToKeep: 2
|
||||
IndentCaseLabels: true
|
||||
AlignConsecutiveMacros: true
|
||||
WhitespaceSensitiveMacros: ['QUOTE']
|
||||
IfMacros: ['IFX', 'IFXORNAT', 'IFX2', 'IFXA', 'IFX_PENDOR0', 'IFXX', 'IFX2X', 'IFXN', 'UFLAG_IF', 'PASS2IF', 'IF_UNALIGNED', 'IF_ALIGNED']
|
||||
UseTab: Never
|
||||
IndentPPDirectives: None
|
||||
---
|
||||
@@ -49,7 +49,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: "Checkout Box64 Repository"
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: "Environment preparation"
|
||||
run: |
|
||||
@@ -90,7 +90,7 @@ jobs:
|
||||
make -j$(nproc) VERBOSE=1
|
||||
|
||||
- name: "Upload Artifact"
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: box64-${{ github.event.inputs.platform }}-${{ github.event.inputs.build_type }}
|
||||
path: build/box64
|
||||
|
||||
+252
-37
@@ -27,37 +27,95 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [X64, OTHER_ARM, RISCV, RPI4ARM64, RPI5ARM64, RK3326, RK3399, RK3588, PHYTIUM, SD845, SD888, ADLINK, ARM64, ANDROID]
|
||||
type: [Release, Trace]
|
||||
os: [ubuntu-latest]
|
||||
include:
|
||||
- platform: TEGRAX1
|
||||
type: Release
|
||||
os: ubuntu-20.04
|
||||
- platform: TEGRAX1
|
||||
platform: [X64, RISCV, RK3588, ARM64, ANDROID, TERMUX, LARCH64, ANDROID_GLIBC, WOW64]
|
||||
type: [Release, Trace, StaticBuild, Box32]
|
||||
os: [ubuntu-latest, ubuntu-22.04-arm]
|
||||
exclude:
|
||||
- platform: ANDROID
|
||||
type: StaticBuild
|
||||
- platform: TERMUX
|
||||
type: StaticBuild
|
||||
- platform: X64
|
||||
type: StaticBuild
|
||||
- platform: ANDROID
|
||||
type: Box32
|
||||
- platform: TERMUX
|
||||
type: Box32
|
||||
- platform: X64
|
||||
os: ubuntu-22.04-arm
|
||||
- platform: RISCV
|
||||
os: ubuntu-22.04-arm
|
||||
- platform: RK3588
|
||||
os: ubuntu-latest
|
||||
- platform: ARM64
|
||||
os: ubuntu-latest
|
||||
- platform: ANDROID
|
||||
os: ubuntu-22.04-arm
|
||||
- platform: TERMUX
|
||||
os: ubuntu-22.04-arm
|
||||
- platform: LARCH64
|
||||
os: ubuntu-22.04-arm
|
||||
- platform: ANDROID_GLIBC
|
||||
os: ubuntu-latest
|
||||
- platform: WOW64
|
||||
os: ubuntu-latest
|
||||
- platform: WOW64
|
||||
type: Trace
|
||||
os: ubuntu-20.04
|
||||
- platform: WOW64
|
||||
type: StaticBuild
|
||||
- platform: WOW64
|
||||
type: Box32
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: "Checkout Box64 Repository"
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: "Environment preparation"
|
||||
run: |
|
||||
sudo apt-get update
|
||||
if [[ ${{ matrix.platform }} != 'X64' && ${{ matrix.platform }} != 'OTHER_ARM' && ${{ matrix.platform }} != 'RISCV' ]]; then
|
||||
sudo apt-get -y install git cmake make python3
|
||||
if [[ ${{ matrix.platform }} == 'ANDROID' ]]; then
|
||||
wget https://dl.google.com/android/repository/android-ndk-r23b-linux.zip
|
||||
unzip android-ndk-r23b-linux.zip
|
||||
echo "BOX64_COMPILER=$PWD/android-ndk-r23b/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android31-clang" >> $GITHUB_ENV
|
||||
echo "BOX64_PLATFORM_MARCRO=-DANDROID=1 -DARM_DYNAREC=1 -DNOLOADADDR=1" >> $GITHUB_ENV
|
||||
if [[ ${{ matrix.platform }} != 'X64' && ${{ matrix.platform }} != 'RISCV' && ${{ matrix.platform }} != 'LARCH64' ]]; then
|
||||
sudo apt-get -y install git cmake make python3 patchelf
|
||||
if [[ ${{ matrix.platform }} == 'ANDROID' || ${{ matrix.platform }} == 'TERMUX' ]]; then
|
||||
sudo apt-get -y install p7zip
|
||||
wget -q https://dl.google.com/android/repository/android-ndk-r26b-linux.zip
|
||||
unzip -qq android-ndk-r26b-linux.zip
|
||||
echo "BOX64_COMPILER=$PWD/android-ndk-r26b/toolchains/llvm/prebuilt/linux-x86_64/bin/aarch64-linux-android31-clang" >> $GITHUB_ENV
|
||||
echo "BOX64_PLATFORM_MARCRO=-DANDROID=1 -DARM_DYNAREC=1 -DBAD_SIGNAL=1" >> $GITHUB_ENV
|
||||
git clone https://github.com/termux/termux-docker.git
|
||||
sudo cp -rf termux-docker/system/arm /system
|
||||
sudo chown -R $(whoami):$(whoami) /system
|
||||
sudo chmod 755 -R /system
|
||||
elif [[ ${{ matrix.platform }} == 'ANDROID_GLIBC' ]]; then
|
||||
sudo apt-get -y install git gcc-aarch64-linux-gnu
|
||||
echo "BOX64_PLATFORM_MARCRO=-DARM64=1 -DWINLATOR_GLIBC=1 -DARM_DYNAREC=1 -DBAD_SIGNAL=1" >> $GITHUB_ENV
|
||||
echo "BOX64_COMPILER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
|
||||
elif [[ ${{ matrix.platform }} == 'WOW64' ]]; then
|
||||
sudo apt-get -y install git gcc-aarch64-linux-gnu
|
||||
echo "BOX64_PLATFORM_MARCRO=-DWOW64=1 -DARM_DYNAREC=1" >> $GITHUB_ENV
|
||||
echo "BOX64_COMPILER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
|
||||
export LLVM_MINGW_VERSION=20250430
|
||||
wget -q https://github.com/mstorsjo/llvm-mingw/releases/download/${LLVM_MINGW_VERSION}/llvm-mingw-${LLVM_MINGW_VERSION}-ucrt-ubuntu-22.04-aarch64.tar.xz
|
||||
tar -xf llvm-mingw-${LLVM_MINGW_VERSION}-ucrt-ubuntu-22.04-aarch64.tar.xz
|
||||
echo "MINGW_COMPILER_PATH=$PWD/llvm-mingw-${LLVM_MINGW_VERSION}-ucrt-ubuntu-22.04-aarch64/bin" >> $GITHUB_ENV
|
||||
else
|
||||
sudo apt-get -y install git gcc-aarch64-linux-gnu
|
||||
echo "BOX64_PLATFORM_MARCRO=-D${{ matrix.platform }}=1" >> $GITHUB_ENV
|
||||
echo "BOX64_COMPILER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
|
||||
fi
|
||||
if [[ ${{ matrix.platform }} == 'TERMUX' ]]; then
|
||||
wget https://packages.termux.dev/apt/termux-main/pool/main/liba/libandroid-sysv-semaphore/libandroid-sysv-semaphore_0.1_aarch64.deb
|
||||
7z x libandroid-sysv-semaphore_0.1_aarch64.deb
|
||||
tar -xf data.tar.xz
|
||||
sudo cp -rf data /
|
||||
sudo chmod 755 -R /data
|
||||
sudo chown -R $(whoami):$(whoami) /data
|
||||
echo "CFLAGS=-L/data/data/com.termux/files/usr/lib" >> $GITHUB_ENV
|
||||
echo "IS_TERMUX=1" >> $GITHUB_ENV
|
||||
echo "QEMU_SET_ENV=LD_LIBRARY_PATH=/data/data/com.termux/files/usr/lib" >> $GITHUB_ENV
|
||||
else
|
||||
echo "IS_TERMUX=0" >> $GITHUB_ENV
|
||||
fi
|
||||
else
|
||||
if [[ ${{ matrix.platform }} == 'X64' ]]; then
|
||||
echo "BOX64_PLATFORM_MARCRO=-DLD80BITS=1 -DNOALIGN=1" >> $GITHUB_ENV
|
||||
@@ -66,7 +124,22 @@ jobs:
|
||||
elif [[ ${{ matrix.platform }} == 'RISCV' ]]; then
|
||||
echo BOX64_PLATFORM_MARCRO="-DRV64=ON" >> $GITHUB_ENV
|
||||
echo "BOX64_COMPILER=riscv64-linux-gnu-gcc" >> $GITHUB_ENV
|
||||
sudo apt-get -y install git gcc-riscv64-linux-gnu cmake make python3
|
||||
sudo apt-get -y install git gcc-riscv64-linux-gnu cmake make python3 ninja-build libglib2.0-dev
|
||||
elif [[ ${{ matrix.platform }} == 'LARCH64' ]]; then
|
||||
sudo mkdir /usr/local/larch
|
||||
wget -O- -q https://github.com/loongson/build-tools/releases/download/2023.08.08/CLFS-loongarch64-8.1-x86_64-cross-tools-gcc-glibc.tar.xz | sudo tar -C /usr/local/larch --strip-components=1 --xz -xf -
|
||||
sudo ln -sf /usr/local/larch/target /usr/loongarch64-linux-gnu
|
||||
sudo cp -r /usr/local/larch/loongarch64-unknown-linux-gnu/lib/* /usr/loongarch64-linux-gnu/lib64/
|
||||
for i in objdump objcopy strip; do
|
||||
sudo ln -sf /usr/local/larch/bin/loongarch64-unknown-linux-gnu-$i /usr/bin/loongarch64-linux-gnu-$i
|
||||
done
|
||||
echo '/usr/local/larch/bin/loongarch64-unknown-linux-gnu-gcc -L/usr/local/larch/loongarch64-unknown-linux-gnu "$@"' | sudo tee /usr/bin/loongarch64-linux-gnu-gcc
|
||||
echo '/usr/local/larch/bin/loongarch64-unknown-linux-gnu-g++ -L/usr/local/larch/loongarch64-unknown-linux-gnu "$@"' | sudo tee /usr/bin/loongarch64-linux-gnu-g++
|
||||
sudo chmod 755 /usr/bin/loongarch64-linux-gnu-{gcc,g++}
|
||||
|
||||
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
|
||||
else
|
||||
echo BOX64_PLATFORM_MARCRO="-DARM_DYNAREC=ON" >> $GITHUB_ENV
|
||||
echo "BOX64_COMPILER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
|
||||
@@ -76,57 +149,199 @@ jobs:
|
||||
if [[ ${{ matrix.type }} == 'Release' ]]; then
|
||||
echo BOX64_BUILD_TYPE=Release >> $GITHUB_ENV
|
||||
echo BOX64_HAVE_TRACE=0 >> $GITHUB_ENV
|
||||
echo BOX64_STATICBUILD=0 >> $GITHUB_ENV
|
||||
echo BOX64_BOX32=0 >> $GITHUB_ENV
|
||||
elif [[ ${{ matrix.type }} == 'StaticBuild' ]]; then
|
||||
echo BOX64_BUILD_TYPE=Release >> $GITHUB_ENV
|
||||
echo BOX64_HAVE_TRACE=0 >> $GITHUB_ENV
|
||||
echo BOX64_STATICBUILD=1 >> $GITHUB_ENV
|
||||
echo BOX64_BOX32=0 >> $GITHUB_ENV
|
||||
elif [[ ${{ matrix.type }} == 'Box32' ]]; then
|
||||
echo BOX64_BUILD_TYPE=Release >> $GITHUB_ENV
|
||||
echo BOX64_HAVE_TRACE=0 >> $GITHUB_ENV
|
||||
echo BOX64_STATICBUILD=0 >> $GITHUB_ENV
|
||||
echo BOX64_BOX32=1 >> $GITHUB_ENV
|
||||
else
|
||||
echo BOX64_BUILD_TYPE=RelWithDebInfo >> $GITHUB_ENV
|
||||
echo BOX64_HAVE_TRACE=1 >> $GITHUB_ENV
|
||||
echo BOX64_STATICBUILD=0 >> $GITHUB_ENV
|
||||
echo BOX64_BOX32=0 >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
- name: "Get XuanTie QEMU Cache Key"
|
||||
if: matrix.platform == 'RISCV'
|
||||
id: get-xuantie-qemu-cache-key
|
||||
run: |
|
||||
echo "key=f2dfdd13014d51f957c7172acc2e791cb42dc400" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: "Cache XuanTie QEMU"
|
||||
if: matrix.platform == 'RISCV'
|
||||
id: cache-xuantie-qemu
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ github.workspace }}/xuantie_qemu_install
|
||||
key: ${{ runner.os }}-${{ steps.get-xuantie-qemu-cache-key.outputs.key }}-xuantie-qemu
|
||||
|
||||
- name: "Checkout XuanTie QEMU"
|
||||
if: matrix.platform == 'RISCV' && steps.cache-xuantie-qemu.outputs.cache-hit != 'true'
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: revyos/qemu
|
||||
path: xuantie_qemu
|
||||
ref: f2dfdd13014d51f957c7172acc2e791cb42dc400
|
||||
|
||||
- name: "Build XuanTie QEMU for XTheadVector"
|
||||
if: matrix.platform == 'RISCV' && steps.cache-xuantie-qemu.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
cd xuantie_qemu
|
||||
./configure --prefix=$GITHUB_WORKSPACE/xuantie_qemu_install --target-list=riscv64-linux-user --disable-system
|
||||
make -j$(nproc)
|
||||
make install
|
||||
|
||||
- name: "Display Build info"
|
||||
run: |
|
||||
echo "CMake Platform Macro: ${{ env.BOX64_PLATFORM_MARCRO }}"
|
||||
echo "CMake C Compiler: ${{ env.BOX64_COMPILER }}"
|
||||
echo "Build type: ${{ env.BOX64_BUILD_TYPE }}"
|
||||
echo "Trace Enabled: ${{ env.BOX64_HAVE_TRACE }}"
|
||||
echo "StaticBuild Enabled: ${{ env.BOX64_STATICBUILD }}"
|
||||
echo "Box32 Enabled: ${{ env.BOX64_BOX32 }}"
|
||||
|
||||
- name: "Build Box64"
|
||||
run: |
|
||||
export PATH=$PATH:${{ env.MINGW_COMPILER_PATH }}
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_C_COMPILER=${{ env.BOX64_COMPILER }}\
|
||||
-DTERMUX=${{ env.IS_TERMUX }}\
|
||||
${{ env.BOX64_PLATFORM_MARCRO }}\
|
||||
-DCMAKE_BUILD_TYPE=${{ env.BOX64_BUILD_TYPE }}\
|
||||
-DHAVE_TRACE=${{ env.BOX64_HAVE_TRACE }}\
|
||||
-DSTATICBUILD=${{ env.BOX64_STATICBUILD }}\
|
||||
-DBOX32=${{ env.BOX64_BOX32 }}\
|
||||
-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON\
|
||||
-DCI=${{ matrix.platform != 'ANDROID' }}
|
||||
make -j$(nproc) VERBOSE=1
|
||||
|
||||
- name: "Test Box64"
|
||||
if: ${{ matrix.platform != 'TEGRAX1' }}
|
||||
run: |
|
||||
if [[ ${{ matrix.platform }} != 'X64' && ${{ matrix.platform }} != 'ANDROID' ]]; then
|
||||
mkdir qemu8.1.0
|
||||
wget -O- -q https://archive.archlinux.org/packages/q/qemu-user-static/qemu-user-static-8.1.0-2-x86_64.pkg.tar.zst | tar -I zstd -C qemu8.1.0 -xf -
|
||||
sudo cp qemu8.1.0/usr/bin/* /usr/bin/
|
||||
if [[ ${{ matrix.platform }} != 'X64' ]]; then
|
||||
mkdir qemu9
|
||||
wget -O- -q https://archive.archlinux.org/packages/q/qemu-user-static/qemu-user-static-9.0.2-1-x86_64.pkg.tar.zst | tar -I zstd -C qemu9 -xf -
|
||||
sudo cp qemu9/usr/bin/* /usr/bin/
|
||||
fi
|
||||
|
||||
cd build
|
||||
export CTEST_OPTIONS="-j$(nproc) --timeout 120 --output-on-failure --repeat until-pass:20"
|
||||
if [[ ${{ matrix.platform }} == 'RISCV' ]]; then
|
||||
INTERPRETER=qemu-riscv64-static QEMU_LD_PREFIX=/usr/riscv64-linux-gnu/ ctest -j$(nproc) --rerun-failed --output-on-failure
|
||||
INTERPRETER=qemu-riscv64-static QEMU_LD_PREFIX=/usr/riscv64-linux-gnu/ BOX64_DYNAREC=0 ctest -j$(nproc) --rerun-failed --output-on-failure
|
||||
INTERPRETER=qemu-riscv64-static QEMU_LD_PREFIX=/usr/riscv64-linux-gnu/ QEMU_CPU=rv64,zba=true,zbb=true,zbc=true,zbs=true ctest -j$(nproc) --rerun-failed --output-on-failure
|
||||
INTERPRETER=qemu-riscv64-static QEMU_LD_PREFIX=/usr/riscv64-linux-gnu/ QEMU_CPU=rv64,xtheadba=true,xtheadba=true,xtheadbb=true,xtheadbs=true,xtheadcondmov=true,xtheadmemidx=true,xtheadmempair=true,xtheadfmemidx=true,xtheadmac=true,xtheadfmv=true ctest -j$(nproc) --rerun-failed --output-on-failure
|
||||
elif [[ ${{ matrix.platform }} != 'X64' && ${{ matrix.platform }} != 'ANDROID' ]]; then # AArch64
|
||||
INTERPRETER=qemu-aarch64-static QEMU_LD_PREFIX=/usr/aarch64-linux-gnu/ BOX64_DYNAREC=0 ctest -j$(nproc) --rerun-failed --output-on-failure
|
||||
INTERPRETER=qemu-aarch64-static QEMU_LD_PREFIX=/usr/aarch64-linux-gnu/ ctest -j$(nproc) --rerun-failed --output-on-failure
|
||||
export INTERPRETER=qemu-riscv64-static
|
||||
export QEMU_LD_PREFIX=/usr/riscv64-linux-gnu/
|
||||
|
||||
ctest $CTEST_OPTIONS
|
||||
QEMU_CPU=rv64,v=false BOX64_DYNAREC=0 ctest $CTEST_OPTIONS
|
||||
QEMU_CPU=rv64,v=false,zba=true,zbb=true,zbc=true,zbs=true ctest $CTEST_OPTIONS
|
||||
QEMU_CPU=rv64,v=true,vlen=128,vext_spec=v1.0 ctest $CTEST_OPTIONS
|
||||
QEMU_CPU=rv64,v=true,vlen=256,vext_spec=v1.0 ctest $CTEST_OPTIONS
|
||||
QEMU_CPU=thead-c906 ctest $CTEST_OPTIONS
|
||||
|
||||
BOX64_DYNAREC_TEST=1 ctest $CTEST_OPTIONS -E nocosim
|
||||
BOX64_DYNAREC_TEST=1 QEMU_CPU=rv64,v=false,zba=true,zbb=true,zbc=true,zbs=true ctest $CTEST_OPTIONS -E nocosim
|
||||
BOX64_DYNAREC_TEST=1 QEMU_CPU=rv64,v=true,vlen=128,vext_spec=v1.0 ctest $CTEST_OPTIONS -E nocosim
|
||||
BOX64_DYNAREC_TEST=1 QEMU_CPU=rv64,v=true,vlen=256,vext_spec=v1.0 ctest $CTEST_OPTIONS -E nocosim
|
||||
BOX64_DYNAREC_TEST=1 QEMU_CPU=thead-c906 ctest $CTEST_OPTIONS -E nocosim
|
||||
|
||||
export INTERPRETER=$GITHUB_WORKSPACE/xuantie_qemu_install/bin/qemu-riscv64
|
||||
QEMU_CPU=c910v ctest $CTEST_OPTIONS
|
||||
BOX64_DYNAREC_TEST=1 QEMU_CPU=c910v ctest $CTEST_OPTIONS -E nocosim
|
||||
elif [[ ${{ matrix.platform }} == 'LARCH64' ]]; then
|
||||
export INTERPRETER=qemu-loongarch64-static
|
||||
export QEMU_LD_PREFIX=/usr/loongarch64-linux-gnu/
|
||||
|
||||
BOX64_DYNAREC_LA64NOEXT=1 ctest $CTEST_OPTIONS -E nocosim
|
||||
BOX64_DYNAREC=0 ctest $CTEST_OPTIONS -E nocosim
|
||||
|
||||
BOX64_DYNAREC_TEST=1 BOX64_DYNAREC_LA64NOEXT=1 ctest $CTEST_OPTIONS -E nocosim
|
||||
elif [[ ${{ matrix.platform }} == 'ANDROID' ]]; then
|
||||
true
|
||||
export INTERPRETER=qemu-aarch64-static
|
||||
export QEMU_LD_PREFIX=/system/lib64
|
||||
|
||||
BOX64_DYNAREC=0 ctest $CTEST_OPTIONS
|
||||
ctest $CTEST_OPTIONS
|
||||
elif [[ ${{ matrix.platform }} == 'TERMUX' ]]; then
|
||||
export INTERPRETER=qemu-aarch64-static
|
||||
export QEMU_SET_ENV=LD_LIBRARY_PATH=/data/data/com.termux/files/usr/lib
|
||||
export QEMU_LD_PREFIX=/system/lib64:/data/data/com.termux/files/usr/lib
|
||||
|
||||
BOX64_DYNAREC=0 ctest $CTEST_OPTIONS
|
||||
ctest $CTEST_OPTIONS
|
||||
elif [[ ${{matrix.type}} == 'Box32' ]]; then
|
||||
ctest $CTEST_OPTIONS
|
||||
else
|
||||
BOX64_DYNAREC=0 ctest -j$(nproc) --rerun-failed --output-on-failure
|
||||
ctest -j$(nproc) --rerun-failed --output-on-failure
|
||||
ctest -j$(nproc)
|
||||
fi
|
||||
|
||||
- name: "Upload Artifact"
|
||||
uses: actions/upload-artifact@v3
|
||||
- name: "Get short Git commit"
|
||||
id: git-info
|
||||
run: echo "SHORT_COMMIT=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
|
||||
|
||||
- name: "Get Box64 Version"
|
||||
run: echo "BOX64_VERSION=$(cat src/box64version.h | grep BOX64_MAJOR | cut -d " " -f 3).$(cat src/box64version.h | grep BOX64_MINOR | cut -d " " -f 3).$(cat src/box64version.h | grep BOX64_REVISION | cut -d " " -f 3)" >> $GITHUB_ENV
|
||||
|
||||
- name: "Packaging WCP file for Winlator"
|
||||
if: matrix.platform == 'ANDROID_GLIBC' && matrix.type != 'StaticBuild'
|
||||
run: |
|
||||
cd build
|
||||
cat <<EOF > profile.json
|
||||
{
|
||||
"type": "Box64",
|
||||
"versionName": "latest-${SHORT_COMMIT}",
|
||||
"versionCode": 1,
|
||||
"description": "Box64-latest-${SHORT_COMMIT}. Built from [https://github.com/ptitSeb/box64].",
|
||||
"files": [
|
||||
{
|
||||
"source": "box64",
|
||||
"target": "\${localbin}/box64"
|
||||
}
|
||||
]
|
||||
}
|
||||
EOF
|
||||
patchelf --set-interpreter /data/data/com.winlator/files/imagefs/usr/lib/ld-linux-aarch64.so.1 ./box64
|
||||
tar --zstd -cf box64-latest.wcp box64 profile.json
|
||||
|
||||
- name: "Package Rat File for MiceWine"
|
||||
if: matrix.platform == 'ANDROID' && matrix.type != 'StaticBuild'
|
||||
run: |
|
||||
cd build
|
||||
|
||||
mkdir -p files/usr/bin
|
||||
|
||||
cp box64 files/usr/bin
|
||||
|
||||
echo "name=Box64 (CI Build)" > pkg-header
|
||||
echo "category=Box64" >> pkg-header
|
||||
echo "version=${BOX64_VERSION}-${SHORT_COMMIT}" >> pkg-header
|
||||
echo "architecture=aarch64" >> pkg-header
|
||||
echo "vkDriverLib=" >> pkg-header
|
||||
|
||||
7z -tzip -mx=5 a box64-latest.rat files pkg-header
|
||||
|
||||
- name: "Upload WCP file"
|
||||
if: matrix.platform == 'ANDROID_GLIBC' && matrix.type != 'StaticBuild'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: box64-${{ matrix.platform }}-${{ matrix.type }}
|
||||
path: build/box64
|
||||
name: box64-latest-${{ matrix.type }}-wcp
|
||||
path: build/box64-latest.wcp
|
||||
|
||||
- name: "Upload Rat File"
|
||||
if: matrix.platform == 'ANDROID' && matrix.type != 'StaticBuild'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: box64-MiceWine-${{ matrix.type }}
|
||||
path: build/box64-latest.rat
|
||||
|
||||
- name: "Upload WowBox64 file"
|
||||
if: matrix.platform == 'WOW64' && matrix.type == 'Release'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: wowbox64-${{ matrix.type }}
|
||||
path: build/wowbox64-prefix/src/wowbox64-build/wowbox64.dll
|
||||
+24
-5
@@ -60,11 +60,30 @@ build*/
|
||||
src/git_head.h
|
||||
backup/
|
||||
|
||||
# LLVMprivateGenerator
|
||||
/LLVMprivateGenerator/*
|
||||
!/LLVMprivateGenerator/Makefile
|
||||
!/LLVMprivateGenerator/main.cpp
|
||||
!/LLVMprivateGenerator/registered_structs.cpp
|
||||
# Wrapper helper
|
||||
/wrapperhelper/bin
|
||||
/wrapperhelper/makedir
|
||||
/wrapperhelper/obj
|
||||
/wrapperhelper/sanaddress
|
||||
/wrapperhelper/sanleak
|
||||
/wrapperhelper/sanundefined
|
||||
/wrapperhelper/src/machine.gen
|
||||
/wrapperhelper/*.h
|
||||
!/wrapperhelper/example-libc.h
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
|
||||
# Archives
|
||||
*.7z
|
||||
*.deb
|
||||
*.eopkg
|
||||
*.gz
|
||||
*.rar
|
||||
*.rpm
|
||||
*.tar*
|
||||
*.xbps
|
||||
*.xz
|
||||
*.zip
|
||||
*.zst
|
||||
*.zstd
|
||||
+882
-122
File diff suppressed because it is too large.
Load diff
@@ -1,12 +0,0 @@
|
||||
all: dumpSigs
|
||||
|
||||
dumpSigs: main.o registered_structs.o
|
||||
g++ -g3 -std=gnu++17 -fno-rtti main.o registered_structs.o -o dumpSigs "-L$(LLVM_install_dir)/lib" -lclang-cpp -lclangTooling -Wl,-rpath "-Wl,$(LLVM_install_dir)/lib"
|
||||
|
||||
main.o: main.cpp
|
||||
g++ -g3 -std=gnu++17 -fno-rtti -c main.cpp -Wfatal-errors "-I$(LLVM_install_dir)/include" -o main.o
|
||||
registered_structs.o: registered_structs.cpp
|
||||
g++ -g3 -std=gnu++17 -fno-rtti -c registered_structs.cpp -Wfatal-errors -o registered_structs.o
|
||||
|
||||
clean:
|
||||
$(RM) dumpSigs main.o registered_structs.o
|
||||
@@ -1,458 +0,0 @@
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <numeric>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <llvm/Support/raw_ostream.h>
|
||||
#include <clang/AST/ASTConsumer.h>
|
||||
#include <clang/AST/Decl.h>
|
||||
#include <clang/AST/Mangle.h>
|
||||
#include <clang/AST/PrettyPrinter.h>
|
||||
#include <clang/AST/RecursiveASTVisitor.h>
|
||||
#include <clang/Frontend/CompilerInstance.h>
|
||||
#include <clang/Frontend/FrontendActions.h>
|
||||
#include <clang/Tooling/CommonOptionsParser.h>
|
||||
#include <clang/Tooling/Tooling.h>
|
||||
|
||||
clang::MangleContext *mangler = nullptr;
|
||||
|
||||
std::unordered_map<std::string, std::pair<std::string, bool>> funMap;
|
||||
std::vector<std::string> funList;
|
||||
|
||||
bool isTypeTrivial(const clang::QualType &q, const clang::QualType *qorig);
|
||||
clang::QualType getPointedType(const clang::QualType q) {
|
||||
if (const clang::PointerType *p = q->getAs<clang::PointerType>())
|
||||
return getPointedType(p->getPointeeType());
|
||||
else if (const clang::ReferenceType *r = q->getAs<clang::ReferenceType>())
|
||||
return getPointedType(r->getPointeeType());
|
||||
else
|
||||
return q;
|
||||
}
|
||||
|
||||
std::string record2name(const clang::RecordDecl &q, const clang::QualType *qorig) {
|
||||
std::string s = q.getNameAsString();
|
||||
if (s == "") {
|
||||
if (!qorig) return "????.!";
|
||||
if (const clang::TypedefType *tt = (*qorig)->getAs<clang::TypedefType>()) {
|
||||
// Typedef
|
||||
if (clang::TypedefNameDecl *td = tt->getDecl()) {
|
||||
return td->getNameAsString();
|
||||
} else {
|
||||
return "<typedef with no declaration>";
|
||||
}
|
||||
} else {
|
||||
return std::string("<unknown type ") + (*qorig)->getTypeClassName() + ">";
|
||||
}
|
||||
} else {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
char ptr2char(const std::string &str) __attribute__((const));
|
||||
const char *ptr2str(const std::string &str) __attribute__((const));
|
||||
char type2char(const clang::QualType &qual /* Canonical */, const clang::QualType *qorig) {
|
||||
if (qual->isBuiltinType()) {
|
||||
switch (static_cast<const clang::BuiltinType&>(*qual).getKind()) {
|
||||
case clang::BuiltinType::Kind::Void:
|
||||
return 'v';
|
||||
case clang::BuiltinType::Kind::Bool:
|
||||
return 'i';
|
||||
case clang::BuiltinType::Kind::Char_U:
|
||||
return 'C';
|
||||
case clang::BuiltinType::Kind::Char_S:
|
||||
return 'c';
|
||||
case clang::BuiltinType::Kind::Char8:
|
||||
return 'c';
|
||||
case clang::BuiltinType::Kind::UChar:
|
||||
return 'C';
|
||||
case clang::BuiltinType::Kind::SChar:
|
||||
return 'c';
|
||||
case clang::BuiltinType::Kind::WChar_U:
|
||||
return 'W';
|
||||
case clang::BuiltinType::Kind::UShort:
|
||||
return 'W';
|
||||
case clang::BuiltinType::Kind::WChar_S:
|
||||
return 'w';
|
||||
case clang::BuiltinType::Kind::Char16:
|
||||
return 'w';
|
||||
case clang::BuiltinType::Kind::Short:
|
||||
return 'w';
|
||||
case clang::BuiltinType::Kind::UInt:
|
||||
return 'u';
|
||||
case clang::BuiltinType::Kind::Char32:
|
||||
return 'i';
|
||||
case clang::BuiltinType::Kind::Int:
|
||||
return 'i';
|
||||
case clang::BuiltinType::Kind::ULong:
|
||||
return 'L';
|
||||
case clang::BuiltinType::Kind::Long:
|
||||
return 'l';
|
||||
case clang::BuiltinType::Kind::ULongLong:
|
||||
return 'U';
|
||||
case clang::BuiltinType::Kind::LongLong:
|
||||
return 'I';
|
||||
case clang::BuiltinType::Kind::UInt128:
|
||||
return 'H';
|
||||
case clang::BuiltinType::Kind::Int128:
|
||||
return 'H';
|
||||
case clang::BuiltinType::Kind::Float:
|
||||
return 'f';
|
||||
case clang::BuiltinType::Kind::Double:
|
||||
return 'd';
|
||||
case clang::BuiltinType::Kind::LongDouble:
|
||||
return 'D';
|
||||
case clang::BuiltinType::Kind::NullPtr:
|
||||
return 'p'; // nullptr_t
|
||||
|
||||
case clang::BuiltinType::Kind::Half:
|
||||
case clang::BuiltinType::Kind::BFloat16:
|
||||
case clang::BuiltinType::Kind::ShortAccum:
|
||||
case clang::BuiltinType::Kind::Accum:
|
||||
case clang::BuiltinType::Kind::LongAccum:
|
||||
case clang::BuiltinType::Kind::UShortAccum:
|
||||
case clang::BuiltinType::Kind::UAccum:
|
||||
case clang::BuiltinType::Kind::ULongAccum:
|
||||
case clang::BuiltinType::Kind::ShortFract:
|
||||
case clang::BuiltinType::Kind::Fract:
|
||||
case clang::BuiltinType::Kind::LongFract:
|
||||
case clang::BuiltinType::Kind::UShortFract:
|
||||
case clang::BuiltinType::Kind::UFract:
|
||||
case clang::BuiltinType::Kind::ULongFract:
|
||||
case clang::BuiltinType::Kind::SatShortAccum:
|
||||
case clang::BuiltinType::Kind::SatAccum:
|
||||
case clang::BuiltinType::Kind::SatLongAccum:
|
||||
case clang::BuiltinType::Kind::SatUShortAccum:
|
||||
case clang::BuiltinType::Kind::SatUAccum:
|
||||
case clang::BuiltinType::Kind::SatULongAccum:
|
||||
case clang::BuiltinType::Kind::SatShortFract:
|
||||
case clang::BuiltinType::Kind::SatFract:
|
||||
case clang::BuiltinType::Kind::SatLongFract:
|
||||
case clang::BuiltinType::Kind::SatUShortFract:
|
||||
case clang::BuiltinType::Kind::SatUFract:
|
||||
case clang::BuiltinType::Kind::SatULongFract:
|
||||
case clang::BuiltinType::Kind::Float16:
|
||||
case clang::BuiltinType::Kind::Float128:
|
||||
case clang::BuiltinType::Kind::Overload:
|
||||
case clang::BuiltinType::Kind::BoundMember:
|
||||
case clang::BuiltinType::Kind::PseudoObject:
|
||||
case clang::BuiltinType::Kind::Dependent:
|
||||
case clang::BuiltinType::Kind::UnknownAny:
|
||||
case clang::BuiltinType::Kind::ARCUnbridgedCast:
|
||||
case clang::BuiltinType::Kind::BuiltinFn:
|
||||
case clang::BuiltinType::Kind::ObjCId:
|
||||
case clang::BuiltinType::Kind::ObjCClass:
|
||||
case clang::BuiltinType::Kind::ObjCSel:
|
||||
#define IMAGE_TYPE(it, id, si, a, s) case clang::BuiltinType::Kind::id:
|
||||
#include <clang/Basic/OpenCLImageTypes.def>
|
||||
#undef IMAGE_TYPE
|
||||
case clang::BuiltinType::Kind::OCLSampler:
|
||||
case clang::BuiltinType::Kind::OCLEvent:
|
||||
case clang::BuiltinType::Kind::OCLClkEvent:
|
||||
case clang::BuiltinType::Kind::OCLQueue:
|
||||
case clang::BuiltinType::Kind::OCLReserveID:
|
||||
case clang::BuiltinType::Kind::IncompleteMatrixIdx:
|
||||
case clang::BuiltinType::Kind::OMPArraySection:
|
||||
case clang::BuiltinType::Kind::OMPArrayShaping:
|
||||
case clang::BuiltinType::Kind::OMPIterator:
|
||||
#define EXT_OPAQUE_TYPE(et, id, e) case clang::BuiltinType::Kind::id:
|
||||
#include <clang/Basic/OpenCLExtensionTypes.def>
|
||||
#define SVE_TYPE(n, id, si) case clang::BuiltinType::Kind::id:
|
||||
#include <clang/Basic/AArch64SVEACLETypes.def>
|
||||
#define PPC_VECTOR_TYPE(n, id, s) case clang::BuiltinType::Kind::id:
|
||||
#include <clang/Basic/PPCTypes.def>
|
||||
#undef EXT_OPAQUE_TYPE
|
||||
#undef SVE_TYPE
|
||||
#undef PPC_VECTOR_TYPE
|
||||
return '!';
|
||||
default:
|
||||
return ':';
|
||||
}
|
||||
} else if (qual->isEnumeralType()) {
|
||||
const clang::EnumDecl *ed = qual->getAs<clang::EnumType>()->getDecl();
|
||||
if (!ed) {
|
||||
return 'i';
|
||||
} else {
|
||||
return type2char(ed->getIntegerType().getCanonicalType(), qorig);
|
||||
}
|
||||
} else if (qual->isFunctionPointerType()) {
|
||||
return '@';
|
||||
} else if (qual->isAnyPointerType() || qual->isReferenceType()) {
|
||||
const clang::QualType &pointed = getPointedType(qual);
|
||||
if (isTypeTrivial(pointed, qorig)) {
|
||||
return 'p';
|
||||
} else if (const clang::RecordType *rct = pointed->getAs<clang::RecordType>()) {
|
||||
clang::RecordDecl *rc = rct->getDecl();
|
||||
if (!rc) {
|
||||
return '!';
|
||||
} else if (!rc->isCompleteDefinition()) {
|
||||
return 'p';
|
||||
} else {
|
||||
std::string str;
|
||||
if (qorig) {
|
||||
const clang::QualType qpted = getPointedType(*qorig);
|
||||
str = record2name(*rc, &qpted);
|
||||
} else {
|
||||
str = record2name(*rc, nullptr);
|
||||
}
|
||||
char ret = ptr2char(str);
|
||||
if (ret) return ret;
|
||||
else {
|
||||
return '!';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return '!';
|
||||
}
|
||||
} else if (const clang::RecordType *rct = qual->getAs<clang::RecordType>()) {
|
||||
clang::RecordDecl *rc = rct->getDecl();
|
||||
if (!rc) {
|
||||
return '?';
|
||||
} else if (rc->getNameAsString() == "__builtin_va_list") {
|
||||
// va_list
|
||||
return 'A';
|
||||
} else {
|
||||
return '?';
|
||||
}
|
||||
} else {
|
||||
return '?';
|
||||
}
|
||||
}
|
||||
bool isTypeTrivial(const clang::QualType &q, const clang::QualType *qorig) {
|
||||
const char c = type2char(q, qorig);
|
||||
#define GO(chr) || (c == chr)
|
||||
return (c == 'v')
|
||||
GO('i') GO('u')
|
||||
GO('I') GO('U')
|
||||
GO('l') GO('L')
|
||||
GO('f') GO('d')
|
||||
GO('D') GO('K')
|
||||
GO('0') GO('1')
|
||||
GO('C') GO('c')
|
||||
GO('W') GO('w')
|
||||
GO('H')
|
||||
GO('p');
|
||||
#undef GO
|
||||
}
|
||||
bool isTypeValid(const clang::QualType &q, const clang::QualType *qorig) {
|
||||
const char c = type2char(q, qorig);
|
||||
if (c == 'A') return false;
|
||||
if (c == 'V') return false;
|
||||
return ((c >= '0') && (c <= '9')) || ((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z'));
|
||||
}
|
||||
|
||||
const std::string type2string(const clang::QualType &qual, const clang::QualType *qorig) {
|
||||
if (qual->isBuiltinType()) {
|
||||
return std::string("(builtin) ") + static_cast<const clang::BuiltinType&>(*qual).getName(clang::PrintingPolicy{{}}).data();
|
||||
} else if (qual->isFunctionPointerType()) {
|
||||
return "Callback (function pointer)";
|
||||
} else if (qual->isAnyPointerType() || qual->isReferenceType()) {
|
||||
std::string prefix = qual->isAnyPointerType() ? "Pointer to " : "Reference to ";
|
||||
const clang::QualType &pointed = getPointedType(qual);
|
||||
if (isTypeTrivial(pointed, qorig)) {
|
||||
return prefix + "trivial object " + type2string(pointed, qorig) + " (" + type2char(pointed, qorig) + ")";
|
||||
} else if (const clang::RecordType *rct = pointed->getAs<clang::RecordType>()) {
|
||||
clang::RecordDecl *rc = rct->getDecl();
|
||||
if (!rc) {
|
||||
return prefix + "unknown record";
|
||||
} else if (!rc->isCompleteDefinition()) {
|
||||
return prefix + "incomplete record " + rc->getNameAsString();
|
||||
} else {
|
||||
std::string str;
|
||||
if (qorig) {
|
||||
const clang::QualType qpted = getPointedType(*qorig);
|
||||
str = record2name(*rc, &qpted);
|
||||
} else {
|
||||
str = record2name(*rc, nullptr);
|
||||
}
|
||||
const char *ret = ptr2str(str);
|
||||
if (ret[0] != '\0') {
|
||||
return prefix + ret;
|
||||
} else {
|
||||
if (mangler && mangler->shouldMangleDeclName(rc)) {
|
||||
std::string mangled;
|
||||
{
|
||||
llvm::raw_string_ostream strstr{mangled};
|
||||
mangler->mangleName(rc, strstr);
|
||||
}
|
||||
return prefix + "unknown record " + str + " (=== " + mangled + ")";
|
||||
} else {
|
||||
return prefix + "unknown record " + str;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return prefix + "non-trivial or typedef'ed object " + type2string(pointed, qorig) + " (" + type2char(pointed, qorig) + ")";
|
||||
//return "Pointer (maybe to callback)";
|
||||
}
|
||||
} else if (qual->isEnumeralType()) {
|
||||
const clang::EnumDecl *ed = qual->getAs<clang::EnumType>()->getDecl();
|
||||
if (!ed) {
|
||||
return "Enumeration with unknown underlying integer type (assuming int)";
|
||||
} else {
|
||||
return "Enumeration with underlying type " + type2string(ed->getIntegerType().getCanonicalType(), nullptr);
|
||||
}
|
||||
} else if (const clang::RecordType *rct = qual->getAs<clang::RecordType>()) {
|
||||
clang::RecordDecl *rc = rct->getDecl();
|
||||
if (!rc) {
|
||||
return "Unknown record";
|
||||
} else if (rc->getNameAsString() == "__builtin_va_list") {
|
||||
return "va_list";
|
||||
} else {
|
||||
return "Unknown record " + std::string(rc->getName().data());
|
||||
}
|
||||
} else {
|
||||
return std::string("??? ") + qual->getTypeClassName();
|
||||
}
|
||||
}
|
||||
|
||||
class Visitor : public clang::RecursiveASTVisitor<Visitor> {
|
||||
public:
|
||||
clang::ASTContext &context;
|
||||
|
||||
bool shouldVisitTemplateInstantiations() const /* override */ { return true; }
|
||||
|
||||
Visitor(clang::CompilerInstance &ci) : context(ci.getASTContext()) {
|
||||
if (!mangler) {
|
||||
mangler = clang::ItaniumMangleContext::create(context, ci.getDiagnostics());
|
||||
}
|
||||
}
|
||||
|
||||
~Visitor() {
|
||||
if (mangler) {
|
||||
delete mangler;
|
||||
mangler = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool VisitDecl(clang::Decl *decl) /* override */ {
|
||||
std::cerr << std::flush;
|
||||
if (!decl) return true;
|
||||
|
||||
if ((decl->getKind() >= clang::Decl::Kind::firstFunction) && (decl->getKind() <= clang::Decl::Kind::lastFunction)) {
|
||||
clang::DeclaratorDecl *ddecl = static_cast<clang::DeclaratorDecl*>(decl);
|
||||
std::cout << "Function detected!\n";
|
||||
|
||||
std::string funName{ddecl->getName()};
|
||||
|
||||
auto niceprint = [](const std::string &infotype, const auto &dat){ std::cout << " " << infotype << ": " << dat << "\n"; };
|
||||
niceprint("Function name", funName);
|
||||
if (mangler && mangler->shouldMangleDeclName(ddecl)) {
|
||||
std::string mangled;
|
||||
{
|
||||
llvm::raw_string_ostream strstr{mangled};
|
||||
mangler->mangleName(ddecl, strstr);
|
||||
}
|
||||
niceprint("Function mangled name", mangled);
|
||||
funName = std::move(mangled);
|
||||
}
|
||||
|
||||
bool valid;
|
||||
std::string funTypeStr{""};
|
||||
if (ddecl->getFunctionType()->isFunctionNoProtoType()) {
|
||||
const clang::FunctionNoProtoType *funType = static_cast<const clang::FunctionNoProtoType*>(ddecl->getFunctionType());
|
||||
const auto &retType = funType->getReturnType();
|
||||
|
||||
niceprint("Function return type", type2string(retType, &retType));
|
||||
niceprint("Canonical function return type",
|
||||
type2string(retType.getCanonicalType(), &retType) +
|
||||
" (" + type2char(retType.getCanonicalType(), &retType) + ")");
|
||||
niceprint("Is sugared", funType->isSugared());
|
||||
if (funType->isSugared()) {
|
||||
clang::QualType qft{funType, 0};
|
||||
niceprint("Desugared", type2string(funType->desugar(), &qft));
|
||||
}
|
||||
|
||||
funTypeStr = type2char(retType.getCanonicalType(), &retType) + std::string("Fv");
|
||||
valid = isTypeValid(retType.getCanonicalType(), &retType);
|
||||
} else {
|
||||
const clang::FunctionProtoType *funType = static_cast<const clang::FunctionProtoType*>(ddecl->getFunctionType());
|
||||
const auto &retType = funType->getReturnType();
|
||||
|
||||
niceprint("Function return type", type2string(retType, &retType));
|
||||
niceprint("Canonical function return type",
|
||||
type2string(retType.getCanonicalType(), &retType)
|
||||
+ " (" + type2char(retType.getCanonicalType(), &retType) + ")");
|
||||
niceprint("Parameter count", funType->getNumParams());
|
||||
for (const clang::QualType &type : funType->getParamTypes()) {
|
||||
niceprint(" " + type2string(type, &type),
|
||||
type2string(type.getCanonicalType(), &type) + " (" + type2char(type.getCanonicalType(), &type) + ")");
|
||||
}
|
||||
niceprint("Variadic function", funType->isVariadic() ? "yes" : "no");
|
||||
|
||||
funTypeStr =
|
||||
type2char(retType.getCanonicalType(), &retType) +
|
||||
((funType->getNumParams() == 0)
|
||||
? std::string("Fv") : std::accumulate(funType->getParamTypes().begin(), funType->getParamTypes().end(), std::string("F"),
|
||||
[](const std::string &acc, const clang::QualType &qual){ return acc + type2char(qual.getCanonicalType(), &qual); }));
|
||||
if (funType->isVariadic()) funTypeStr += "V";
|
||||
valid = !funType->isVariadic() &&
|
||||
std::accumulate(funType->getParamTypes().begin(), funType->getParamTypes().end(), isTypeValid(retType.getCanonicalType(), &retType),
|
||||
[](bool acc, const clang::QualType &qual){ return acc && isTypeValid(qual.getCanonicalType(), &qual); });
|
||||
}
|
||||
|
||||
niceprint("Conclusion", "");
|
||||
niceprint("Function final name", funName);
|
||||
niceprint("Function type", funTypeStr);
|
||||
niceprint("Valid function type", valid ? "yes" : "no");
|
||||
std::cout << "\n";
|
||||
|
||||
funMap[funName] = std::make_pair(funTypeStr, valid);
|
||||
funList.push_back(funName);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class Consumer : public clang::ASTConsumer {
|
||||
public:
|
||||
Visitor visitor;
|
||||
|
||||
Consumer(clang::CompilerInstance &ci) : visitor(ci) {
|
||||
}
|
||||
|
||||
void HandleTranslationUnit(clang::ASTContext &context) override {
|
||||
visitor.TraverseDecl(context.getTranslationUnitDecl());
|
||||
}
|
||||
};
|
||||
|
||||
class Action : public clang::ASTFrontendAction {
|
||||
public:
|
||||
virtual std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(clang::CompilerInstance &ci, llvm::StringRef inFile) override {
|
||||
return std::make_unique<Consumer>(ci);
|
||||
}
|
||||
};
|
||||
|
||||
int main(int argc, const char **argv) {
|
||||
if (argc < 2) {
|
||||
std::cerr << "Usage: " << argv[0] << " (filenames) -- [-I...]" << std::endl;
|
||||
return 2;
|
||||
}
|
||||
|
||||
/*int fakeargc = argc + 1;
|
||||
const char **fakeargv = new const char*[fakeargc];
|
||||
memcpy(fakeargv, argv, argc * sizeof(char*));
|
||||
fakeargv[fakeargc - 1] = "--";*/
|
||||
llvm::cl::OptionCategory opcat{""};
|
||||
clang::tooling::CommonOptionsParser op{argc, argv, opcat};
|
||||
std::vector<std::string> paths; for (int i = 1; i < argc; ++i) paths.push_back(argv[i]);
|
||||
|
||||
clang::tooling::ClangTool tool{op.getCompilations(), paths};
|
||||
|
||||
tool.run(clang::tooling::newFrontendActionFactory<Action>().get());
|
||||
|
||||
std::cout << "Done, outputing output.h" << std::endl;
|
||||
std::sort(funList.begin(), funList.end());
|
||||
std::fstream file{"output.h", std::ios_base::out};
|
||||
for (const std::string &funName : funList) {
|
||||
if (!funMap[funName].second) {
|
||||
file << "//";
|
||||
}
|
||||
file << "GO(" << funName << ", " << funMap[funName].first << ")\n";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,267 +0,0 @@
|
||||
#include <string>
|
||||
|
||||
#define ALL START() \
|
||||
/* libc */ \
|
||||
STRUCT("_IO_FILE", "a FILE") \
|
||||
STRUCT("_G_fpos_t", "a file position") \
|
||||
STRUCT("sockaddr", "a socket address") \
|
||||
STRUCT("itimerspec", "an itimerspec") \
|
||||
STRUCT("timespec", "a timespec") \
|
||||
STRUCT("itimerval", "an itimerval") \
|
||||
STRUCT("timeval", "a timeval") \
|
||||
STRUCT("timex", "a timex") \
|
||||
STRUCT("timezone", "a timezone") \
|
||||
STRUCT("dirent", "a dirent") \
|
||||
STRUCT("dirent64", "a dirent64") \
|
||||
STRUCT("__dirstream", "a dir stream") \
|
||||
STRUCT("tm", "a time structure (tm)") \
|
||||
STRUCT("cmsghdr", "a cmsghdr") \
|
||||
STRUCT("msghdr", "a msghdr") \
|
||||
STRUCT("rpcent", "an rpcent") \
|
||||
STRUCT("random_data", "a random_data structure") \
|
||||
STRUCT("drand48_data", "a drand48_data structure") \
|
||||
STRUCT("termios", "a termios") \
|
||||
STRUCT("iovec", "an iovec") \
|
||||
STRUCT("file_handle", "a file handle") \
|
||||
STRUCT("lconv", "an lconv") \
|
||||
STRUCT("__locale_struct", "a locale structure") \
|
||||
STRUCT("aliasent", "an alias") \
|
||||
STRUCT("fstab", "an fstab") \
|
||||
STRUCT("group", "a group") \
|
||||
STRUCT("hostent", "a hostent") \
|
||||
STRUCT("protoent", "a protoent") \
|
||||
STRUCT("passwd", "a password") \
|
||||
STRUCT("spwd", "an spwd") \
|
||||
STRUCT("ttyent", "a ttyent") \
|
||||
STRUCT("utmp", "an utmp structure") \
|
||||
STRUCT("utmpx", "an utmpx structure") \
|
||||
STRUCT("ifaddrs", "an ifaddrs structure") \
|
||||
STRUCT("statfs", "a statfs structure") \
|
||||
STRUCT("statfs64", "a statfs64 structure") \
|
||||
STRUCT("statvfs", "a statvfs structure") \
|
||||
STRUCT("statvfs64", "a statvfs64 structure") \
|
||||
STRUCT("timeb", "a timeb structure") \
|
||||
STRUCT("_ftsent", "an _ftsent structure") \
|
||||
STRUCT("sysinfo", "a sysinfo structure") \
|
||||
STRUCT("rlimit", "an rlimit structure") \
|
||||
STRUCT("rlimit64", "an rlimit64 structure") \
|
||||
STRUCT("rusage", "an rusage structure") \
|
||||
STRUCT("entry", "an entry structure") \
|
||||
STRUCT("pollfd", "a pollfd structure") \
|
||||
STRUCT("re_pattern_buffer", "a re_pattern_buffer structure") \
|
||||
STRUCT("sembuf", "a sembuf structure") \
|
||||
STRUCT("tms", "a tms structure") \
|
||||
STRUCT("utsname", "an utsname structure") \
|
||||
STRUCT("utimbuf", "an utimbuf structure") \
|
||||
STRUCT2("__va_list_tag", "__va_list_tag (aka, a va_list)", 'A') \
|
||||
/* ncurses */ \
|
||||
STRUCT("_win_st", "a _win_st structure") \
|
||||
STRUCT("MEVENT", "an MEVENT structure") \
|
||||
TYPEDEF("cchar_t", "a cchar_t") \
|
||||
/* zlib */ \
|
||||
STRUCT("gz_header_s", "a gz_header_s structure") \
|
||||
STRUCT("gzFile_s", "a gzFile_s structure") \
|
||||
STRUCT("z_stream_s", "a z_stream_s structure") \
|
||||
\
|
||||
END()
|
||||
|
||||
#define START()
|
||||
#define STRUCT(s, ret) if (str == s) { return 'p'; } else
|
||||
#define STRUCT2(s, ret, c) if (str == s) { return c; } else
|
||||
#define TYPEDEF(s, ret) if (str == s) { return 'p'; } else
|
||||
#define END() { return 0; }
|
||||
char ptr2char(const std::string &str) {
|
||||
/*if ((str == "_IO_FILE")
|
||||
|| (str == "_G_fpos_t")
|
||||
|| (str == "sockaddr")
|
||||
|| (str == "itimerspec")
|
||||
|| (str == "timespec")
|
||||
|| (str == "itimerval")
|
||||
|| (str == "timeval")
|
||||
|| (str == "timex")
|
||||
|| (str == "timezone")
|
||||
|| (str == "dirent")
|
||||
|| (str == "dirent64")
|
||||
|| (str == "__dirstream")
|
||||
|| (str == "tm")
|
||||
|| (str == "cmsghdr")
|
||||
|| (str == "msghdr")
|
||||
|| (str == "rpcent")
|
||||
|| (str == "random_data")
|
||||
|| (str == "drand48_data")
|
||||
|| (str == "termios")
|
||||
|| (str == "iovec")
|
||||
|| (str == "file_handle")
|
||||
|| (str == "lconv")
|
||||
|| (str == "__locale_struct")
|
||||
|| (str == "aliasent")
|
||||
|| (str == "fstab")
|
||||
|| (str == "group")
|
||||
|| (str == "hostent")
|
||||
|| (str == "protoent")
|
||||
|| (str == "passwd")
|
||||
|| (str == "spwd")
|
||||
|| (str == "ttyent")
|
||||
|| (str == "utmp")
|
||||
|| (str == "utmpx")
|
||||
|| (str == "ifaddrs")
|
||||
|| (str == "statfs")
|
||||
|| (str == "statfs64")
|
||||
|| (str == "statvfs")
|
||||
|| (str == "timeb")
|
||||
|| (str == "_ftsent")
|
||||
|| (str == "sysinfo")
|
||||
|| (str == "rlimit")
|
||||
|| (str == "rlimit64")
|
||||
|| (str == "rusage")
|
||||
|| (str == "entry")
|
||||
|| (str == "pollfd")
|
||||
|| (str == "re_pattern_buffer")
|
||||
|| (str == "sembuf")
|
||||
|| (str == "tms")
|
||||
|| (str == "utsname")
|
||||
|| (str == "utimbuf")
|
||||
// ncurses
|
||||
|| (str == "_win_st")
|
||||
|
||||
|| (str == "cchar_t")
|
||||
) {
|
||||
// FILE*, fpos_t*, ...
|
||||
return 'p';
|
||||
} else if (str == "__va_list_tag") {
|
||||
return 'A';
|
||||
} else {
|
||||
return 0;
|
||||
}*/
|
||||
ALL
|
||||
}
|
||||
#undef END
|
||||
#undef TYPEDEF
|
||||
#undef STRUCT2
|
||||
#undef STRUCT
|
||||
#undef START
|
||||
|
||||
#define START()
|
||||
#define STRUCT(s, ret) if (str == s) { return ret; } else
|
||||
#define STRUCT2(s, ret, c) if (str == s) { return ret; } else
|
||||
#define TYPEDEF(s, ret) if (str == s) { return ret; } else
|
||||
#define END() return "";
|
||||
const char *ptr2str(const std::string &str) {
|
||||
/*if (str == "_IO_FILE") {
|
||||
return "a FILE";
|
||||
} else if (str == "_G_fpos_t") {
|
||||
return "a file position";
|
||||
} else if (str == "sockaddr") {
|
||||
return "a socket address";
|
||||
} else if (str == "itimerspec") {
|
||||
return "an itimerspec";
|
||||
} else if (str == "timespec") {
|
||||
return "a timespec";
|
||||
} else if (str == "itimerval") {
|
||||
return "an itimerval";
|
||||
} else if (str == "timeval") {
|
||||
return "a timeval";
|
||||
} else if (str == "timex") {
|
||||
return "a timex";
|
||||
} else if (str == "timezone") {
|
||||
return "a timezone";
|
||||
} else if (str == "dirent") {
|
||||
return "a dirent";
|
||||
} else if (str == "dirent64") {
|
||||
return "a dirent64";
|
||||
} else if (str == "__dirstream") {
|
||||
return "a dir stream";
|
||||
} else if (str == "tm") {
|
||||
return "a time structure (tm)";
|
||||
} else if (str == "cmsghdr") {
|
||||
return "a cmsghdr";
|
||||
} else if (str == "msghdr") {
|
||||
return "a msghdr";
|
||||
} else if (str == "rpcent") {
|
||||
return "an rpcent";
|
||||
} else if (str == "random_data") {
|
||||
return "a random_data structure";
|
||||
} else if (str == "drand48_data") {
|
||||
return "a drand48_data structure";
|
||||
} else if (str == "termios") {
|
||||
return "a termios";
|
||||
} else if (str == "iovec") {
|
||||
return "an iovec";
|
||||
} else if (str == "file_handle") {
|
||||
return "a file handle";
|
||||
} else if (str == "lconv") {
|
||||
return "an lconv";
|
||||
} else if (str == "__locale_struct") {
|
||||
return "a locale structure";
|
||||
} else if (str == "aliasent") {
|
||||
return "an alias";
|
||||
} else if (str == "fstab") {
|
||||
return "an fstab";
|
||||
} else if (str == "group") {
|
||||
return "a group";
|
||||
} else if (str == "hostent") {
|
||||
return "a hostent";
|
||||
} else if (str == "protoent") {
|
||||
return "a protoent";
|
||||
} else if (str == "passwd") {
|
||||
return "a password";
|
||||
} else if (str == "spwd") {
|
||||
return "an spwd";
|
||||
} else if (str == "ttyent") {
|
||||
return "a ttyent";
|
||||
} else if (str == "utmp") {
|
||||
return "an utmp structure";
|
||||
} else if (str == "utmpx") {
|
||||
return "an utmpx structure";
|
||||
} else if (str == "ifaddrs") {
|
||||
return "an ifaddrs structure";
|
||||
} else if (str == "statfs") {
|
||||
return "a statfs structure";
|
||||
} else if (str == "statfs64") {
|
||||
return "a statfs64 structure";
|
||||
} else if (str == "statvfs") {
|
||||
return "a statvfs structure";
|
||||
} else if (str == "statvfs64") {
|
||||
return "a statvfs64 structure";
|
||||
} else if (str == "timeb") {
|
||||
return "a timeb structure";
|
||||
} else if (str == "_ftsent") {
|
||||
return "an _ftsent structure";
|
||||
} else if (str == "sysinfo") {
|
||||
return "a sysinfo structure";
|
||||
} else if (str == "rlimit") {
|
||||
return "an rlimit structure";
|
||||
} else if (str == "rlimit64") {
|
||||
return "an rlimit64 structure";
|
||||
} else if (str == "rusage") {
|
||||
return "an rusage structure";
|
||||
} else if (str == "entry") {
|
||||
return "an entry structure";
|
||||
} else if (str == "pollfd") {
|
||||
return "a pollfd structure";
|
||||
} else if (str == "re_pattern_buffer") {
|
||||
return "a re_pattern_buffer structure";
|
||||
} else if (str == "sembuf") {
|
||||
return "a sembuf structure";
|
||||
} else if (str == "tms") {
|
||||
return "a tms structure";
|
||||
} else if (str == "utsname") {
|
||||
return "an utsname structure";
|
||||
} else if (str == "utimbuf") {
|
||||
return "an utimbuf structure";
|
||||
} else if (str == "__va_list_tag") {
|
||||
return "__va_list_tag (aka, a va_list)";
|
||||
// ncurses
|
||||
} else if (str == "_win_st") {
|
||||
return "a _win_st structure";
|
||||
|
||||
} else if (str == "cchar_t") {
|
||||
return "a cchar_t";
|
||||
} else return "";*/
|
||||
ALL
|
||||
}
|
||||
#undef END
|
||||
#undef TYPEDEF
|
||||
#undef STRUCT2
|
||||
#undef STRUCT
|
||||
#undef START
|
||||
@@ -1,123 +1,109 @@
|
||||

|
||||
|
||||
Linux Userspace x86_64 Emulator with a twist
|
||||
# Box64: Linux Userspace x86-64 Emulator with a Twist
|
||||
|
||||
[View changelog](https://github.com/ptitSeb/box64/blob/main/docs/CHANGELOG.md) | [中文](https://github.com/ptitSeb/box64/blob/main/README_CN.md) | [Українська](https://github.com/ptitSeb/box64/blob/main/README_UK.md) | [Report an error](https://github.com/ptitSeb/box64/issues/new)
|
||||
[Changelog](https://github.com/ptitSeb/box64/blob/main/docs/CHANGELOG.md) | [中文](https://github.com/ptitSeb/box64/blob/main/README_CN.md) | [Українська](https://github.com/ptitSeb/box64/blob/main/README_UK.md) | [Report an Error](https://github.com/ptitSeb/box64/issues/new)
|
||||
|
||||
     
|
||||
     
|
||||
|
||||
---
|
||||
|
||||
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 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 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/).
|
||||
|
||||
<img src="docs/img/Box64Icon.png" width="96" height="96" alt="Box64 Icon">
|
||||
|
||||
_Logo and icon by @grayduck - Thank you!_
|
||||
|
||||
---
|
||||
|
||||
## 📖 Usage
|
||||
|
||||
Box64 offers environment variables to control its behavior. For details, see [Usage Documentation](docs/USAGE.md).
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Compiling and Installation
|
||||
|
||||
- [Compilation Instructions](https://github.com/ptitSeb/box64/blob/main/docs/COMPILE.md)
|
||||
- [Bundle x86 Libraries](https://github.com/ptitSeb/box64/blob/main/docs/BUNDLE-X86-LIBS.md)
|
||||
- [Wine Installation for Box64](https://github.com/ptitSeb/box64/blob/main/docs/X64WINE.md)
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Version History
|
||||
|
||||
See the [Changelog](docs/CHANGELOG.md) for version updates.
|
||||
|
||||
---
|
||||
|
||||
## 🖥️ Platform Compatibility Notes
|
||||
|
||||
Box64 requires 64-bit libraries on the host system, as it directly translates x86_64 function calls. For 32-bit binaries, use Box86.
|
||||
|
||||
**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`.
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ 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.
|
||||
|
||||
Settings priority: `~/.box64rc` > `/etc/box64.box64rc` > Command line.
|
||||
|
||||
---
|
||||
|
||||
## 📄 Additional Platform-Specific Notes
|
||||
|
||||
### Unity Game Emulation
|
||||
|
||||
- Many Unity games require OpenGL 3+, which may be challenging on ARM/RISC-V SBCs.
|
||||
- **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
|
||||
|
||||
Steam requires Box86 due to its 32-bit client app, but uses 64-bit local server binaries. Systems with less than 6GB RAM may need a swap file for optimal performance.
|
||||
|
||||
### Wine
|
||||
|
||||
Box64 supports Wine64 and Proton. For 32-bit components, Box86 is required. Systems with both Box64 and Box86 can run 32- and 64-bit Windows programs.
|
||||
|
||||
**Note**: You can use Wine WOW64 build to run x86 Windows programs in Box64-only environments, this is still experimental, but it works in most cases.
|
||||
|
||||
### Vulkan
|
||||
|
||||
Box64 wraps Vulkan libraries.
|
||||
|
||||
----
|
||||
|
||||
Box64 lets you run x86_64 Linux programs (such as games) on non-x86_64 Linux systems, like ARM (host system needs to be 64-bit little-endian).
|
||||
|
||||
You can find many Box64 videos on the [MicroLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ), [Pi Labs](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g) or [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA) YouTube channels.
|
||||
|
||||
Since Box64 uses the native versions of some "system" libraries, like libc, libm, SDL, and OpenGL, it's easy to integrate and use with most applications, and performance can be surprisingly high in many cases. Take a look at thoses bench analysis for an example [here](https://box86.org/index.php/2021/06/game-performances/).
|
||||
|
||||
Box64 integrates with DynaRec (dynamic recompiler) for the ARM64 and RV64 platform, providing a speed boost between 5 to 10 times faster than using only the interpreter. Some high level information on how DynaRec works can be found [here](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/).
|
||||
|
||||
Some x64 internal opcodes use parts of "Realmode X86 Emulator Library", see [x64primop.c](src/emu/x64primop.c) for copyright details
|
||||
|
||||
<img src="docs/img/Box64Icon.png" width="96" height="96">
|
||||
|
||||
Logo and Icon made by @grayduck, thanks!
|
||||
|
||||
----
|
||||
|
||||
Usage
|
||||
----
|
||||
|
||||
There are a few environment variables to control the behaviour of Box64.
|
||||
|
||||
See [here](docs/USAGE.md) for all the environment variables and what they do.
|
||||
|
||||
Note: Box64's Dynarec uses a mechanism with Memory Protection and a SegFault signal handler to handle JIT code. In simpler terms, if you want to use GDB to debug a running program that use JIT'd code (like mono/Unity3D), you will still have many "normal" segfaults triggering. It is suggested to use something like `handle SIGSEGV nostop` in GDB to not stop at each segfault, and maybe put a breakpoint inside `my_memprotectionhandler` in `signals.c` if you want to trap SegFaults.
|
||||
|
||||
----
|
||||
|
||||
Compiling/Installation
|
||||
----
|
||||
> Compilation instructions can be found [here](https://github.com/ptitSeb/box64/blob/main/docs/COMPILE.md) \
|
||||
> Instructions for installing Wine for Box64 can be found [here](https://github.com/ptitSeb/box64/blob/main/docs/X64WINE.md)
|
||||
|
||||
----
|
||||
|
||||
Version history/Change log
|
||||
----
|
||||
|
||||
The change log is available [here](docs/CHANGELOG.md).
|
||||
|
||||
----
|
||||
|
||||
Notes about 32-bit platforms
|
||||
----
|
||||
|
||||
Because Box64 works by directly translating function calls from x86_64 to host system, the host system (the one Box64 is running on) needs to have 64-bit libraries. Box64 doesn't include any 64-bit <-> 32-bit translation.
|
||||
|
||||
So understand that box64 will only run 64-bit linux binaries. For 32-bit binaries, you need box86 (with all the multiarch or proot trickery it implies on a 64-bit OS).
|
||||
Note that many installer (mojo setup based) will fall back to "x86" when detecting ARM64 OS, and so will try to use box86 for the setup, even if an x86_64 version exist. You can hack your way around with a fake "uname" that return "x86_64" when the argument is "-m"
|
||||
|
||||
----
|
||||
|
||||
Notes about Box64 configuration
|
||||
----
|
||||
|
||||
Box64 now have configurations files. There are 2 files loaded. `/etc/box4.box64rc` and `~/.box64rc`. Both files have the same syntax, and is basicaly an ini files. Section in square brakets define the process name, and the rest is the env. var. to set. Looke at [Usage](USAGE.md) for detail on what parameters can be put. Box64 comes with a default file that should be installed for better stability. The file in in `system/box64.box64rc` and should be installed to `/etc/box64.box64rc` If, for some reason, you don't want to install that file here, at least copy it to `~/.box64rc` or some game may not function correctly.
|
||||
Note that the priority is: `~/.box64rc` > `/etc/box64.box64rc` > command line
|
||||
So, your settings in `~/.box64rc` may override the setting from your command line...
|
||||
|
||||
----
|
||||
|
||||
Notes about Unity game emulation
|
||||
----
|
||||
|
||||
Running Unity games should just work, but you should also note that many Unity3D games require OpenGL 3+ which can be tricky to provide on ARM SBC (single-board computers). Also many newer Unity3D (like KSP) games use the BC7 compressed textures, which is not supported on many ARM integrated GPU.
|
||||
Hint: on Pi4, use `MESA_GL_VERSION_OVERRIDE=3.2` and with Panfrost use `PAN_MESA_DEBUG=gl3` to use higher profile if the game starts then quits before showing anything.
|
||||
|
||||
----
|
||||
|
||||
Notes about GTK programs
|
||||
----
|
||||
|
||||
GTK libraries are now wrapped on box64, both gtk2 and gtk3.
|
||||
|
||||
----
|
||||
|
||||
Notes about Steam
|
||||
----
|
||||
|
||||
Note that Steam is a hybrid 32-bit / 64-bit. You NEED box86 to run Steam, as the client app is a 32-bit binary. It also uses a 64-bit local server binaries, and that steamwebhelper process is now mandatory, even on the "small mode". And that process will eat lots of memory. So machine with less the 6Gb of RAM will need a swapfile to use Steam.
|
||||
|
||||
----
|
||||
|
||||
Notes about Wine
|
||||
----
|
||||
|
||||
Wine64 is supported on box64. Proton too. Be aware that 64-bit Wine also includes 32-bit components, to be able to run 32-bit Windows programs. The 32-bit apps will need box86 and will not run without it. On a system where both box64 and box86 are present and working, a wine 64-bit setup can run both 32-bit and 64-bit Windows programs (just use `wine` and `wine64` respectively).
|
||||
Note that the new 32-bit PE in 64-bit processes that the Wine team is currently implementing in Wine 7.+ is now supported, but the support is quite young so there might be some residual issues.
|
||||
|
||||
----
|
||||
|
||||
Notes about Vulkan
|
||||
----
|
||||
|
||||
Box64 wraps Vulkan libraries, but note that it as mostly been tested with an AMD RX550 card and on the Freedreno driver, so some extensions may be missing depending on your graphics card.
|
||||
|
||||
----
|
||||
|
||||
Final word
|
||||
----
|
||||
|
||||
I want to thank everyone who has contributed to box64 development.
|
||||
There are many ways to contribute: code contribution, financial, hardware and advertisement!
|
||||
So, in no particular order, I want to thank:
|
||||
* For their major code contribution: rajdakin, mogery
|
||||
* For their major financial contribution: FlyingFathead, stormchaser3000, dennis1248, sll00, [libre-computer-project](https://libre.computer/), [CubeCoders Limited](http://cubecoders.com/)
|
||||
* For their major code contribution: rajdakin, mogery, ksco, xctan
|
||||
* For their major financial contribution: [Playtron](https://playtron.one), tohodakilla, FlyingFathead, stormchaser3000, dennis1248, sll00, [libre-computer-project](https://libre.computer/), [CubeCoders Limited](http://cubecoders.com/)
|
||||
* For hardware contribution and LoongArch migration: [xiaoji](https://www.linuxgame.cn/), Deepin Beijing Develop Team
|
||||
* For their major code contribution on the RV64 Dynarec: ksco, xctan
|
||||
* For their hardware contribution: [ADLINK](https://www.adlinktech.com/Products/Computer_on_Modules/COM-HPC-Server-Carrier-and-Starter-Kit/Ampere_Altra_Developer_Platform?lang=en) with [Ampere](https://amperecomputing.com/home/edge), [Radxa](https://rockpi.org/), [StarFive](https://rvspace.org/), [Pine64](https://www.pine64.org/), [AYN](https://www.ayntec.com/)
|
||||
* For their hardware contribution: [ADLINK](https://www.adlinktech.com/Products/Computer_on_Modules/COM-HPC-Server-Carrier-and-Starter-Kit/Ampere_Altra_Developer_Platform?lang=en) with [Ampere](https://amperecomputing.com/home/edge), [SOPHGO](https://www.sophon.ai/), [Radxa](https://rockpi.org/), [StarFive](https://rvspace.org/), [Pine64](https://www.pine64.org/), [AYN](https://www.ayntec.com/), [AYANEO](https://ayaneo.com/), [jiangcuo](https://github.com/jiangcuo)
|
||||
* For their continuous advertisements for the box64 project: salva ([microLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ)), [PILab](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g)/[TwisterOS](https://twisteros.com/) team, [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA), [NicoD](https://www.youtube.com/channel/UCpv7NFr0-9AB5xoklh3Snhg), ekianjo ([Boilingsteam](https://boilingsteam.com/))
|
||||
|
||||
And I also thank the many other people who participated even once in this project.
|
||||
|
||||
(If you use Box64 in your project, please don't forget to mention it!)
|
||||
|
||||
+52
-57
@@ -1,97 +1,92 @@
|
||||
# box64
|
||||

|
||||
|
||||

|
||||
Linux 上用户空间的 x86_64 应用模拟器(支持运行原生库)
|
||||
# Box64:Linux 用户空间 x86-64 模拟器(支持原生库)
|
||||
|
||||
----
|
||||

|
||||
[更新日志](https://github.com/ptitSeb/box64/blob/main/docs/CHANGELOG.md) | [English](https://github.com/ptitSeb/box64/blob/main/README.md) | [Українська](https://github.com/ptitSeb/box64/blob/main/README_UK.md) | [Report an Error](https://github.com/ptitSeb/box64/issues/new)
|
||||
|
||||
[English](docs/README.md) | [Українська](https://github.com/ptitSeb/box64/blob/main/README_UK.md)
|
||||
     
|
||||
|
||||
Box64 可以在非 x86_64 Linux 系统(比如 ARM64)上运行 x86_64 Linux 程序(比如游戏),注意主机系统需要是 64 位小端。
|
||||
---
|
||||
|
||||
您可以在 [MicroLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ)、[Pi Labs](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g) 和 [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA) YouTube 频道上找到许多 Box64 视频。
|
||||
Box64 可以在非 x86_64 Linux 主机系统(比如 Arm)上运行 x86_64 Linux 程序(比如游戏),目前仅支持 64 位小端主机系统。
|
||||
|
||||
由于 Box64 使用一些“系统”库的原生版本,如 libc、libm、SDL 和 OpenGL 等,因此很容易与大多数应用程序集成和使用,并且在许多情况下性能会相当不错。可以在[这里](https://box86.org/index.php/2021/06/game-performances/)查看一些性能测试的样例。
|
||||
在 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 集成了适用于 ARM64 和 RV64 平台的 DynaRec(动态重编译器),速度可以比纯解释模式快 5 到 10 倍。可以在[这里](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/)找到有关 DynaRec 工作原理的一些信息。
|
||||
Box64 可以使用本机原生的系统库(libc、libm、SDL、OpenGL),有着易于集成的特性和令人惊讶的性能。如需性能基准测试,请查看[此分析](https://box86.org/index.php/2021/06/game-performances/)。
|
||||
|
||||
一些 x64 内部操作码使用 “Realmode X86 Emulator Library” 的部分内容,有关版权详细信息,请参见 [x64primop.c](../src/emu/x64primop.c)。
|
||||
借助适用于 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/)。
|
||||
|
||||
<img src="docs/img/Box64Icon.png" width="96" height="96">
|
||||
<img src="docs/img/Box64Icon.png" width="96" height="96" alt="Box64 Icon">
|
||||
|
||||
LOGO 由 @grayduck 制作,感谢!
|
||||
_Logo 由 @grayduck 制作,感谢!_
|
||||
|
||||
----
|
||||
---
|
||||
|
||||
使用方法
|
||||
----
|
||||
## 📖 使用方法
|
||||
|
||||
有若干环境变量可以控制 Box64 的行为。
|
||||
Box64 提供了环境变量来控制其行为。有关详细信息请参阅[使用文档](docs/USAGE.md)。
|
||||
|
||||
可在[这里](docs/USAGE.md)查看所有环境变量及其作用。
|
||||
---
|
||||
|
||||
注意:Box64 的 Dynarec 使用具有内存保护和段错误信号处理的机制来执行 JIT 代码。所以,如果想使用 GDB 调试使用 JIT 代码的程序(如 Mono/Unity3D),这会触发许多“正常”的段错误。建议在 GDB 中使用类似 `handle SIGSEGV nostop` 来防止它每个段错误处停止。如果你想捕获段错误,可以在 `signals.c` 的 `my_memprotectionhandler` 中设置断点。
|
||||
## 🚀 编译和安装
|
||||
|
||||
----
|
||||
- [编译说明](https://github.com/ptitSeb/box64/blob/main/docs/COMPILE.md)
|
||||
- [安装 Wine](https://github.com/ptitSeb/box64/blob/main/docs/X64WINE.md)
|
||||
|
||||
编译/安装
|
||||
----
|
||||
---
|
||||
|
||||
编译说明可以在[这里](docs/COMPILE.md)查看。
|
||||
## 🔄 版本历史
|
||||
|
||||
----
|
||||
请参阅[变更日志](docs/CHANGELOG.md)了解版本更新说明。
|
||||
|
||||
版本历史
|
||||
----
|
||||
---
|
||||
|
||||
版本日志在[这里](docs/CHANGELOG.md)。
|
||||
## 🖥️ 平台兼容性说明
|
||||
|
||||
----
|
||||
Box64 直接转换 x86_64 函数调用到本机原生库,因此需要主机系统上的 64 位库。对于 32 位二进制文件,请使用 Box86。
|
||||
|
||||
32位平台的注意事项
|
||||
----
|
||||
**注意事项**
|
||||
|
||||
因为 Box64 的工作原理是直接将函数调用从 x86_64 转换为主机系统,所以主机系统(运行 Box64 的系统)需要有 64 位库。Box64 不包含任何 64 位 <-> 32 位的转换。
|
||||
1. Box32 模式正在制作中,旨在支持 Box64 上运行 32 位二进制文件,敬请期待!
|
||||
2. 某些安装程序可能会将 64 位的主机操作系统判定为 x86 导致兼容性问题。解决方法:使用假的 `uname` ,并使它在运行参数为 `-m` 时返回 `x86_64`。
|
||||
|
||||
所以 box64 只能运行 64 位的 Linux 二进制。对于 32 位二进制则需要使用 box86 来运行(它在 64 位操作系统上使用了 multiarch 和 proot 等技巧来实现运行)。请注意,许多(基于 mojo 的)安装程序在检测到 ARM64 操作系统时将回退到 “x86”,因此即使存在 x86_64 版本,也会尝试使用 box86。这时你可以使用一个假的 `uname` ,并使它在运行参数为 `-m` 时返回 `x86_64`。
|
||||
---
|
||||
|
||||
----
|
||||
## ⚙️ 配置
|
||||
|
||||
关于 Unity 游戏模拟的注意事项
|
||||
----
|
||||
Box64 的配置文件位于 `/etc/box64.box64rc` 和 `~/.box64rc`,均为 `.ini` 格式的文件。如果您不想使用默认的 `/etc/box64.box64rc` 文件,请将其复制到 `~/.box64rc` 以确保兼容性。
|
||||
|
||||
运行 Unity 游戏应该没什么问题,但还应该注意,许多 Unity3D 游戏需要 OpenGL 3+,这在 ARM SBC 上可能会比较棘手。同时许多较新的 Unity3D游戏(如 KSP)也使用 BC7 压缩纹理,很多 ARM 的集成显卡并不支持。
|
||||
配置项的优先级:`~/.box64rc` > `/etc/box64.box64rc` > 命令行。
|
||||
|
||||
> 提示:如果游戏开始后没有显示任何东西就退出了,在 Pi4 上可以使用 `MESA_GL_VERSION_OVERRIDE=3.2`,在 Panfrost 上则可以使用 `PAN_MESA_DEBUG=gl3` 来使用更高的配置。
|
||||
---
|
||||
|
||||
----
|
||||
## 📄 特定平台的其他说明
|
||||
|
||||
关于GTK程序的注意事项
|
||||
----
|
||||
### 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。如果游戏可以启动但在显示任何内容之前意外退出,这个设置可能会有所帮助。
|
||||
|
||||
box64 封装了 GTK,包括 gtk2 和 gtk3。
|
||||
### GTK 程序
|
||||
|
||||
----
|
||||
Box64 包装了 GTK 库,支持 gtk2 和 gtk3。
|
||||
|
||||
关于 Steam 的注意事项
|
||||
----
|
||||
### Steam
|
||||
|
||||
请注意,Steam 是 32/64 位混合的应用,所以你需要 box86 才能运行,因为客户端应用程序是 32 位的。它还使用 64 位本地服务器,它的 steamwebhelper 无法被关闭(即使是在最小模式)而且会吃掉大量的内存。对于内存小于 6 GB 的机型,你将会需要创建 swapfile 来运行 Steam。
|
||||
由于 Steam 客户端应用是 32 位的,需要使用 Box86,但其本地服务器是 64 位的二进制文件。对于内存少于 6GB 的系统,可能需要使用交换文件以获得最佳性能。
|
||||
|
||||
----
|
||||
### Wine
|
||||
|
||||
关于 Wine 的注意事项
|
||||
----
|
||||
Box64 支持 Wine64 和 Proton。对于 32 位组件,需要 Box86。配备 Box64 和 Box86 的系统可以运行 32 位和 64 位的 Windows 程序。
|
||||
|
||||
box64 支持 Wine64,Proton 应该也能运行。请注意,64 位 Wine 包含有 32 位组件,以便能够运行 32 位 Windows 程序。32 位应用程序需要 box86,否则无法运行。在 box64 和 box86 都存在并工作的系统上,64 位的 Wine 可以同时运行 32 位和 64 位 Windows 程序(分别使用 `wine` 和 `wine64`)。请注意,目前在 Wine 7.+ 中实现的 Wine 时间在 64 位进程中的新 32bit PE 尚不支持。我测试了 Wine 7.5 64 位可以正常工作,但是更新的版本可能还不行。
|
||||
**提示**:您可以使用 Wine WOW64 版本在仅限 Box64 的环境中运行 x86 Windows 程序,这项支持仍处于实验阶段,但在大多数情况下都可以工作。
|
||||
|
||||
----
|
||||
### Vulkan
|
||||
|
||||
关于 Vulkan 注意事项
|
||||
----
|
||||
|
||||
Box64 封装了 Vulkan 库,但请注意,它仅在 RX550 显卡上进行过测试,因此根据您的显卡,某些扩展可能会丢失。
|
||||
Box64 包装了 Vulkan 库。
|
||||
|
||||
----
|
||||
|
||||
@@ -102,10 +97,10 @@ Box64 封装了 Vulkan 库,但请注意,它仅在 RX550 显卡上进行过
|
||||
贡献方式有很多种:代码贡献、财务帮助、捐赠捐赠和广告合作!
|
||||
以下感谢不分先后:
|
||||
|
||||
* 代码贡献:rajdakin, mogery
|
||||
* 财务帮助:FlyingFathead, stormchaser3000, dennis1248, sll00, [libre-computer-project](https://libre.computer/)
|
||||
* 代码贡献:rajdakin, mogery, ksco, xctan
|
||||
* 财务支持:[Playtron](https://playtron.one), tohodakilla, FlyingFathead, stormchaser3000, dennis1248, sll00, [libre-computer-project](https://libre.computer/), [CubeCoders Limited](http://cubecoders.com/)
|
||||
* 硬件捐赠和 LoongArch 迁移:[xiaoji](https://www.linuxgame.cn/), Deepin Beijing Develop Team
|
||||
* 硬件捐赠:[ADLink](https://www.adlinktech.com/Products/Computer_on_Modules/COM-HPC-Server-Carrier-and-Starter-Kit/Ampere_Altra_Developer_Platform?lang=en), [Radxa](https://rockpi.org/), [Pine64](https://www.pine64.org/), [StarFive](https://rvspace.org/)
|
||||
* 硬件捐赠:[ADLINK](https://www.adlinktech.com/Products/Computer_on_Modules/COM-HPC-Server-Carrier-and-Starter-Kit/Ampere_Altra_Developer_Platform?lang=en) with [Ampere](https://amperecomputing.com/home/edge), [SOPHGO](https://www.sophon.ai/), [Radxa](https://rockpi.org/), [StarFive](https://rvspace.org/), [Pine64](https://www.pine64.org/), [AYN](https://www.ayntec.com/), [AYANEO](https://ayaneo.com/), [jiangcuo](https://github.com/jiangcuo)
|
||||
* 为本项目持续的宣传:salva ([microLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ)), [PILab](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g)/[TwisterOS](https://twisteros.com/) team, [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA), [NicoD](https://www.youtube.com/channel/UCpv7NFr0-9AB5xoklh3Snhg), ekianjo ([Boilingsteam](https://boilingsteam.com/))
|
||||
|
||||
我还要感谢很多人,即使他们只参与了一次本项目。
|
||||
|
||||
+5
-7
@@ -2,7 +2,7 @@
|
||||
|
||||
Емулятор простіра користувача x86_64 із родзинкою
|
||||
|
||||
[Дивитись журнал змін](https://github.com/ptitSeb/box64/blob/main/docs/CHANGELOG.md) | [中文](https://github.com/ptitSeb/box64/blob/main/README_CN.md) | [Українська](https://github.com/ptitSeb/box64/blob/main/README_UK.md) | [Повідомити про помилку](https://github.com/ptitSeb/box64/issues/new)
|
||||
[Дивитись журнал змін](https://github.com/ptitSeb/box64/blob/main/docs/CHANGELOG.md) | [中文](https://github.com/ptitSeb/box64/blob/main/README_CN.md) | [English](https://github.com/ptitSeb/box64/blob/main/README.md) | [Повідомити про помилку](https://github.com/ptitSeb/box64/issues/new)
|
||||
|
||||
     
|
||||
|
||||
@@ -40,7 +40,6 @@ Box64 інтегрується з DynaRec (динамічний рекомпіл
|
||||
> Інструкцію з встановлення Wine для Box64 можна знайти [тут](docs/X64WINE.md).
|
||||
|
||||
----
|
||||
|
||||
Історія версій/Журнал змін
|
||||
----
|
||||
|
||||
@@ -68,7 +67,7 @@ Box64 інтегрується з DynaRec (динамічний рекомпіл
|
||||
----
|
||||
|
||||
Запуск ігор Unity має працювати, але ви також повинні зауважити, що для багатьох ігор Unity3D потрібен OpenGL 3+, який може бути складно забезпечити на ARM SBC (одноплатних комп’ютерах). Крім того, багато нових ігор Unity3D (наприклад, KSP) використовують стиснуті текстури BC7, які не підтримуються багатьма інтегрованими GPU ARM.
|
||||
Підказка: в Pi4 використовуйте `MESA_GL_VERSION_OVERRIDE=3.2`, а в Panfrost — `PAN_MESA_DEBUG=gl3`, щоб використовувати вищий профіль, якщо гра запускається, а потім завершується, перш ніж щось показує.
|
||||
Підказка: на Pi4 і Pi5 використовуйте `MESA_GL_VERSION_OVERRIDE=3.2` з `BOX64_DYNAREC_STRONGMEM=1`, щоб запобігти зависанням і ввімкнути режим сильної пам’яті, і використовуйте Panfrost `PAN_MESA_DEBUG=gl3`, щоб використовувати вищий профіль, якщо гра починається, а потім завершується, перш ніж щось показати.
|
||||
|
||||
----
|
||||
|
||||
@@ -107,11 +106,10 @@ Box64 використовує бібліотеки Vulkan, але зауваж
|
||||
Я хочу подякувати всім, хто зробив внесок у розвиток box64.
|
||||
Є багато способів зробити внесок: внесок коду, фінансовий внесок, апаратне забезпечення та реклама!
|
||||
Отже, без особливого порядку, я хочу подякувати:
|
||||
* За основний внесок у код: rajdakin, mogery
|
||||
* За великий фінансовий внесок: FlyingFathead, stormchaser3000, dennis1248, sll00, [libre-computer-project](https://libre.computer/)
|
||||
* За основний внесок у код: rajdakin, mogery, ksco, xctan
|
||||
* За великий фінансовий внесок: [Playtron](https://playtron.one), tohodakilla, FlyingFathead, stormchaser3000, dennis1248, sll00, [libre-computer-project](https://libre.computer/)
|
||||
* За апаратне забезпечення та міграцію LoongArch: [xiaoji](https://www.linuxgame.cn/), команда розробників Deepin Beijing
|
||||
* За основний внесок у код RV64 Dynarec: ksco, xctan
|
||||
* За внесок у апаратне забезпечення: [ADLink](https://www.adlinktech.com/Products/Computer_on_Modules/COM-HPC-Server-Carrier-and-Starter-Kit/Ampere_Altra_Developer_Platform?lang=en), [Radxa](https://rockpi.org/), [Pine64](https://www.pine64.org/), [StarFive](https://rvspace.org/)
|
||||
* За внесок у апаратне забезпечення: [ADLINK](https://www.adlinktech.com/Products/Computer_on_Modules/COM-HPC-Server-Carrier-and-Starter-Kit/Ampere_Altra_Developer_Platform?lang=en) with [Ampere](https://amperecomputing.com/home/edge), [SOPHGO](https://www.sophon.ai/), [Radxa](https://rockpi.org/), [StarFive](https://rvspace.org/), [Pine64](https://www.pine64.org/), [AYN](https://www.ayntec.com/), [AYANEO](https://ayaneo.com/), [jiangcuo](https://github.com/jiangcuo)
|
||||
* За безперервну рекламу Box64: salva ([microLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ)), [PILab](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g)/Команда [TwisterOS](https://twisteros.com/), [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA), [NicoD](https://www.youtube.com/channel/UCpv7NFr0-9AB5xoklh3Snhg), ekianjo ([Boilingsteam](https://boilingsteam.com/))
|
||||
|
||||
І я також дякую багатьом іншим людям, які хоч раз брали участь у цьому проекті.
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/bluez-libs-5.72-2.el9.i686.rpm,af1aba8e6fa5ccf33032d58a3acc59368c07d532293396db205fb9a4bc1241ae
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/bluez-libs-5.72-2.el9.x86_64.rpm,49c273813b4616240acdae8dae893192658c7541482f9bbb2c46dfe19b61877d
|
||||
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/fribidi-1.0.10-6.el9.2.i686.rpm,75f808f0f5f93aceb4e477aa5f302edbed07a605a0644f0ea929d4ea609e36a0
|
||||
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/fribidi-1.0.10-6.el9.2.x86_64.rpm,b4763ca410f8479b2775efb55ba09e6722948af7526180a56309e3e090c27010
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/gmp-6.2.0-13.el9.i686.rpm,fe352f7d197ebdf2c92bbd6e548f9f6b7ac9e69e7a9d6c9861a6274482e79d73
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/gmp-6.2.0-13.el9.x86_64.rpm,babe0b1385e723476a216d5f4b72453e031c3d683b19344786c2bddf7203cb04
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/gnutls-3.8.3-4.el9_4.i686.rpm,64cf0b0136d3f9b80b07ce2d4b8ce6a4ab86617e8ef9baf560bdfa5edef825ea
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/gnutls-3.8.3-4.el9_4.x86_64.rpm,16c48c504fe62f8e19cac7c6442d3e08bba487f610c2f533116dac32357cda86
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/harfbuzz-2.7.4-10.el9.i686.rpm,5157daf2ab0a03b403d37c60b150b8f0f866754714f81e3d96368e06a16339ce
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/harfbuzz-2.7.4-10.el9.x86_64.rpm,1f81073019abe4176d4496723a89b55a349c31f507e96397a0b3efa7cea0ff61
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libblkid-2.37.4-20.el9.i686.rpm,f9e62d2768c31948b53268b7de51bd1c7342cdf39a328a0d89d933b4aa0c5dd1
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libblkid-2.37.4-20.el9.x86_64.rpm,ed02d978a36488b38bad62af21d4045367c1f0b00d00c90ded01e2fc8e190536
|
||||
https://archive.debian.org/debian/pool/main/c/curl/libcurl3-gnutls_7.74.0-1.3+deb11u7~bpo11+1_amd64.deb,d5ae55e3a9838d12358530cd03218cc0d18127a84e9cfc73bdf79dacd40b25e4
|
||||
https://archive.debian.org/debian/pool/main/c/curl/libcurl3-gnutls_7.74.0-1.3+deb11u7~bpo11+1_i386.deb,625e5189304d4d3bfb27cb821e257816c5ce761b1696b5da5ca4fa1035c48463
|
||||
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libepoxy-1.5.5-4.el9.i686.rpm,fe35e8de9b68c8d7e7b6b525580fc36cf9c86412cdb2b022dc01f95801771981
|
||||
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libepoxy-1.5.5-4.el9.x86_64.rpm,b6d1e7f1c832882ceb05187cbc2d8fe1f459bcd88c7160487ee6f734e1a5d017
|
||||
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libffi-devel-3.4.2-8.el9.i686.rpm,0c6f2ecc324680c6424bee4b1dbbdad2863f0f7f3130b196fc6e2b2823f07bc4
|
||||
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libffi-devel-3.4.2-8.el9.x86_64.rpm,483e4c58cb8af94143a0ff4b3e49b62cb7d6896766c8c0d9fe3659e68945b50e
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libgomp-11.5.0-2.el9.alma.1.i686.rpm,686ac26afe2073a3607f26fd1592a8ccd9b78f6eec6e872528634b43c4e04dd7
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libgomp-11.5.0-2.el9.alma.1.x86_64.rpm,9a2bdc6807b22ffb6294b30dcc13e20198abe5facaeefcf1bfacec3e1013e3c2
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libgpg-error-1.42-5.el9.i686.rpm,23f828674bc30752687452dacf4a25ca8c25ef0d25e3e6953d0714b5b33cef08
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libgpg-error-1.42-5.el9.x86_64.rpm,f28fabeb02add41b8156c394427da9dbf99882d8c42055367f872130ee424c97
|
||||
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libICE-1.0.10-8.el9.i686.rpm,d9c44bb34c990fdcc6987feefacfc9e1e7997ca25f1e0a59c9adc9c16f2266d1
|
||||
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libICE-1.0.10-8.el9.x86_64.rpm,d0b867203384942985c3c4ad6fc9ec0000fcc9965408451a6cdef8df06a3833c
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libidn2-2.3.0-7.el9.i686.rpm,4458e2d416b5e6714ec664c4f88791eee7d1e707026a5854d948a6159911465b
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libidn2-2.3.0-7.el9.x86_64.rpm,c3ff43237c05258ee0dd77c28540fc8d0d824f1567b115ddfd555b78d2ee0e7a
|
||||
https://cdn.getsol.us/repo/shannon/libj/libjpeg-turbo/libjpeg-turbo-32bit-3.0.3-21-1-x86_64.eopkg,5624990281f6520026aa2252c711f02d4916099aeac63accc83bd2135b9d3220
|
||||
https://cdn.getsol.us/repo/shannon/libj/libjpeg-turbo/libjpeg-turbo-3.0.3-21-1-x86_64.eopkg,c92f19d446b4c2450306f13b1a908f2552400da09301996fe349fee243d964d2
|
||||
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libogg-1.3.4-6.el9.i686.rpm,9e4ff6fa0251c5357ae8f648b3e396d0043d5b3f2fb28d23325f5bd592c67aee
|
||||
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libogg-1.3.4-6.el9.x86_64.rpm,83b4b333e335654674032d1cda4d7deb328b5a409f95e3952c3dc482b684fd8f
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libpng-1.6.37-12.el9.i686.rpm,66bf967e84f0d8e7a0059f2b7dda33482ff5e4fe088d0e3bc86dc54e6c7c97be
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libpng-1.6.37-12.el9.x86_64.rpm,ebb3e927dfafa0b199e00e2bef4c10c85fc82a70c359faf9aeb599eda70bfa5e
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libbrotli-1.0.9-7.el9_5.i686.rpm,d18c20fccbb9497222059d475161a55c0c6279344f214fe551b8b0f87d3c054a
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libbrotli-1.0.9-7.el9_5.x86_64.rpm,77906ae44bcd42a9f6646d814874768e8befaabf413133d44f71a95ac6c6d68c
|
||||
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libsigc%2B%2B20-2.10.7-2.el9.i686.rpm,7c33f4c18cbd51dc0a7c9ae0190b1a27d0540ce2fd92ced4776dde66162d1a88
|
||||
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libsigc%2B%2B20-2.10.7-2.el9.x86_64.rpm,8600132b9e4efadfe23d3125e90287f5a7114165fd9ecb064d9930fcca446ef2
|
||||
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libSM-1.2.3-10.el9.i686.rpm,ec68b3def828ba442248f3cff495f42c4af3dd58f38c8daad07dfddc109d999a
|
||||
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libSM-1.2.3-10.el9.x86_64.rpm,d00318843a50138829b470a97b8db1a00723b10bca23c16a8386d9ab670e4c64
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libstdc%2B%2B-11.5.0-5.el9_5.alma.1.i686.rpm,05fd29569c312a661374aa69e28ed5cad20812822070a3138265c92a446e2c80
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libstdc%2B%2B-11.5.0-5.el9_5.alma.1.x86_64.rpm,7efb1ded0ec2763589dd3bc6a9d52fa9f898cc1f3db6e8761e1d223ce4506424
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libtasn1-4.16.0-8.el9_1.i686.rpm,9cbd11277e89bd0d4a80900bee01ca71b0c582c9cb5744f5035135b2ed907c85
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libtasn1-4.16.0-8.el9_1.x86_64.rpm,2dd3a1ad2785df642cb03dfed6dfbeec929ff8b14e52e61272ca7e89f86ba3cd
|
||||
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libtheora-1.1.1-31.el9.i686.rpm,2155c688b516ab359d0c47be6d73e51d3c65f199ed5591f7bb7ce6d5d9799977
|
||||
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libtheora-1.1.1-31.el9.x86_64.rpm,25ab4a8ad997b450b4a34a777f5a0678eea72ca1665944a7a461ac63de4b25bf
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libunistring-0.9.10-15.el9.i686.rpm,792600a879fbd94ce4bf249713b0cb3a166c147cfad397e8a15e6b4f01c75997
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libunistring-0.9.10-15.el9.x86_64.rpm,d2f86fbee729a4900a433a6c52a3cb95d9b52b1d79c9e719ee3ef509813eb6d9
|
||||
https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/34/Everything/x86_64/os/Packages/l/libunwind-1.4.0-5.fc34.i686.rpm,eb518e9d073c36fd29862c7afd00a8a7cb186074a0e162983f18fb6c9dc71d2c
|
||||
https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/34/Everything/x86_64/os/Packages/l/libunwind-1.4.0-5.fc34.x86_64.rpm,0f44e37e4eb472508e0dba8505ebbb04c2c1390c6a43970a6af80aad886037e3
|
||||
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libvorbis-1.3.7-5.el9.i686.rpm,e38c5185fea611330ea253db020315dd564507bf95c48a81dbe7db186ce4214b
|
||||
https://repo.almalinux.org/almalinux/9.5/AppStream/x86_64/os/Packages/libvorbis-1.3.7-5.el9.x86_64.rpm,3c340337a073975636d198a282503f32a54bf85fb5345522a2c22e530b8d6c9e
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libzstd-1.5.1-2.el9.i686.rpm,e98f253d6f5f9acf2ded628cd98f50a54a031e354bf7bb2efc3fe39f9899fe49
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/libzstd-1.5.1-2.el9.x86_64.rpm,2e5215e225cec2db43d92c3b3380812a6f8684e881ed415670299e1e0fe7d1ce
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/lz4-libs-1.9.3-5.el9.i686.rpm,c308ba7380a3b5c5337c919150f0234342b64c1ea696d6207c2b790b82ba4669
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/lz4-libs-1.9.3-5.el9.x86_64.rpm,439e701491af6a957ac4d7dc69cccee1a945333f19d8bfcbd896b5119af01aab
|
||||
https://repo.almalinux.org/almalinux/8.10/BaseOS/x86_64/os/Packages/nettle-3.4.1-7.el8.i686.rpm,13bc8758355c3ec885f414e0e86efad29a7fe82c0999cdb3754d666949c06cc5
|
||||
https://repo.almalinux.org/almalinux/8.10/BaseOS/x86_64/os/Packages/nettle-3.4.1-7.el8.x86_64.rpm,fb4aaa22b2e2f2fc0c451b87ac464e8746d240397d64e79f6bfd38f4e9128a5a
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/nettle-3.9.1-1.el9.i686.rpm,e5610fe3b25cfca1616440e1a8a7489fd37b0852f182fdda87ab8e196d981970
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/nettle-3.9.1-1.el9.x86_64.rpm,9786b6610d17aa495fb640ba6d046bf73704915b82d12e6d8339090ff4891de5
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/p11-kit-0.25.3-3.el9_5.i686.rpm,abe4ab924b405c236eaf3fa067fed50ac66d15d0ef42c782a745788c1a9c5b91
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/p11-kit-0.25.3-3.el9_5.x86_64.rpm,0e1bd97e697a9fa3b4e508b945cf352b73b06e4e8218c14ac5fb912b0022c646
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/pam-1.5.1-22.el9_5.i686.rpm,f2ae4441fc667cdcb930e7a2cfe90f7342e7d1c8848d6d18cb350ba68e025862
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/pam-1.5.1-22.el9_5.x86_64.rpm,15bfe177d3c10982c75e81d7b274883a9fb53322011c8d829667c983ee419b18
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/pciutils-libs-3.7.0-5.el9.i686.rpm,2cf468da5ecf307cc325c9a5da0a288aafd25dec0951af2b4d0954a77bdf900d
|
||||
https://repo.almalinux.org/almalinux/9.5/BaseOS/x86_64/os/Packages/pciutils-libs-3.7.0-5.el9.x86_64.rpm,308bd897d8f9a36020d70edc79089a3595b22b149200d67c37e2d4e6147a9f75
|
||||
https://dl.fedoraproject.org/pub/fedora/linux/updates/40/Everything/x86_64/Packages/s/SDL3-3.2.4-1.fc40.i686.rpm,f4776f6f56a8d3e62e95c06fb885832e22116323c0c2e0f57f918cd4b92e16a2
|
||||
https://dl.fedoraproject.org/pub/fedora/linux/updates/40/Everything/x86_64/Packages/s/SDL3-3.2.4-1.fc40.x86_64.rpm,96f52b7cf293ce335e2bf726c8b6aefd82ed76fbe9d9f0db1fe603780477c2d0
|
||||
|
@@ -0,0 +1,96 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -x
|
||||
|
||||
extract_pkg_auto() {
|
||||
# Example x86_64 package name: libcurl3-gnutls_7.74.0-1.3+deb11u7~bpo11+1_amd64.deb
|
||||
# Example x86 package name: libcurl3-gnutls_7.74.0-1.3+deb11u7~bpo11+1_i386.deb
|
||||
if echo "${1}" | grep -q -P ".deb$"; then
|
||||
echo "DEB (Debian) package detected."
|
||||
ar x "$(basename "${1}")"
|
||||
tar --extract --file data.tar*
|
||||
# Example x86_64 package name: curl-gnutls-8.1.2-44-1-x86_64.eopkg
|
||||
# Example x86 package name: curl-gnutls-32bit-8.1.2-44-1-x86_64.eopkg
|
||||
elif echo "${1}" | grep -q -P ".eopkg$"; then
|
||||
echo "EOPKG (Solus Linux) package detected."
|
||||
unzip -o "$(basename "${1}")"
|
||||
tar --extract --file install.tar.xz
|
||||
# Example x86_64 package name: bluez-libs-5.63-1.el8.x86_64.rpm
|
||||
# Example x86 package name: bluez-libs-5.63-1.el8.i686.rpm
|
||||
elif echo "${1}" | grep -q -P ".rpm$"; then
|
||||
echo "RPM (Fedora) detected."
|
||||
rpm2cpio "$(basename "${1}")" | cpio -idmv
|
||||
# Example x86_64 package name: libjpeg-turbo-3.0.1_1.x86_64.xbps
|
||||
# Example x86 package name: libjpeg-turbo-32bit-3.0.1_1.x86_64.xbps
|
||||
elif echo "${1}" | grep -q -P ".xbps$"; then
|
||||
echo "XBPS (Void Linux) package detected."
|
||||
tar --extract --file "$(basename "${1}")"
|
||||
else
|
||||
echo "Unsupported package type detected."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
box64_dir=$(pwd)
|
||||
dir_tmp_local="$(mktemp --directory)"
|
||||
cd "${dir_tmp_local}"
|
||||
|
||||
for line in $(cat "${box64_dir}/box64-bundle-x86-libs.csv");
|
||||
do pkg_url="$(echo "${line}" | cut -d, -f1)"
|
||||
pkg_checksum_expected="$(echo "${line}" | cut -d, -f2)"
|
||||
pkg_name="$(basename "${pkg_url}")"
|
||||
curl --silent --location --remote-name "${pkg_url}"
|
||||
pkg_checksum_actual="$(sha256sum ${pkg_name} | awk '{print $1}')"
|
||||
if [[ "${pkg_checksum_expected}" -ne "${pkg_checksum_actual}" ]];
|
||||
then echo "Invalid checksum for ${pkg_name}"
|
||||
echo "Expected: ${pkg_checksum_expected}"
|
||||
echo "Actual: ${pkg_checksum_actual}"
|
||||
exit 1
|
||||
fi
|
||||
extract_pkg_auto "${pkg_name}"
|
||||
done
|
||||
|
||||
# Start preperation of bundles.
|
||||
mkdir -p \
|
||||
"${dir_tmp_local}/bundle-libs/usr/lib/box64-i386-linux-gnu" \
|
||||
"${dir_tmp_local}/bundle-libs/usr/lib/box64-x86_64-linux-gnu" \
|
||||
"${dir_tmp_local}/bundle-pkgs" \
|
||||
|
||||
# Copy Debian family libraries.
|
||||
cp --archive "${dir_tmp_local}"/usr/lib/i386-linux-gnu/*.so* "${dir_tmp_local}/bundle-libs/usr/lib/box64-i386-linux-gnu"
|
||||
cp --archive "${dir_tmp_local}"/usr/lib/x86_64-linux-gnu/*.so* "${dir_tmp_local}/bundle-libs/usr/lib/box64-x86_64-linux-gnu"
|
||||
# Copy Fedora family libraries.
|
||||
cp --archive "${dir_tmp_local}"/usr/lib/*.so* "${dir_tmp_local}/bundle-libs/usr/lib/box64-i386-linux-gnu"
|
||||
cp --archive "${dir_tmp_local}"/usr/lib64/*.so* "${dir_tmp_local}/bundle-libs/usr/lib/box64-x86_64-linux-gnu"
|
||||
## This location is used by a few special packages such as "glibc".
|
||||
cp --archive "${dir_tmp_local}"/lib/*.so* "${dir_tmp_local}/bundle-libs/usr/lib/box64-i386-linux-gnu"
|
||||
cp --archive "${dir_tmp_local}"/lib64/*.so* "${dir_tmp_local}/bundle-libs/usr/lib/box64-x86_64-linux-gnu"
|
||||
# Copy Solus and Void Linux family libraries.
|
||||
cp --archive "${dir_tmp_local}"/usr/lib32/*.so* "${dir_tmp_local}/bundle-libs/usr/lib/box64-i386-linux-gnu"
|
||||
|
||||
# Create "<LIBRARY_FILE>.so" symlinks.
|
||||
for dir_lib in \
|
||||
"${dir_tmp_local}/bundle-libs/usr/lib/box64-i386-linux-gnu" \
|
||||
"${dir_tmp_local}/bundle-libs/usr/lib/box64-x86_64-linux-gnu"
|
||||
# If two or more libraries of the same name exist, this will symlink the oldest version.
|
||||
# Pipe this into a reverse sort `| sort -r` to symlink the newest version.
|
||||
do for lib in $(ls -1 "${dir_lib}")
|
||||
# Example output: libbluetooth.so
|
||||
do lib_base="$(echo "${lib}" | cut -d. -f1,2)"
|
||||
if ! ls "${dir_lib}/${lib_base}" 2> /dev/null
|
||||
then ln -s "${lib}" "${dir_lib}/${lib_base}"
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
mv "${dir_tmp_local}"/*.deb "${dir_tmp_local}/bundle-pkgs/"
|
||||
mv "${dir_tmp_local}"/*.eopkg "${dir_tmp_local}/bundle-pkgs/"
|
||||
mv "${dir_tmp_local}"/*.rpm "${dir_tmp_local}/bundle-pkgs/"
|
||||
mv "${dir_tmp_local}"/*.xbps "${dir_tmp_local}/bundle-pkgs/"
|
||||
|
||||
tar --directory "${dir_tmp_local}/bundle-libs" --create --file "${box64_dir}/box64-bundle-x86-libs.tar.gz" .
|
||||
tar --directory "${dir_tmp_local}/bundle-pkgs" --create --file "${box64_dir}/box64-bundle-x86-pkgs.tar.gz" .
|
||||
|
||||
# Clean up.
|
||||
cd -
|
||||
rm -r -f "${dir_tmp_local}"
|
||||
Vendored
+105
@@ -1,3 +1,108 @@
|
||||
box64 (0.3.6) unstable; urgency=low
|
||||
|
||||
This version introduces wowbox64.dll for Hangover; the ability to use the Volatile Metadata of Windows executables for x64 wine; and some better x87/SSE/AVX handling
|
||||
|
||||
=> WowBox64 can be built directly from Box64 repo, and can be found in the CI artifacts also
|
||||
=> it also supports a subset of BOX64_XXXX settings, which can be set from command line or via a setting file ".box64rc" in the Wine prefix home
|
||||
=> Volatile Metadata, when present, allows only applying strong memory ordering when needed, as marked by the compiler, giving overall better performances
|
||||
=> The precision control bit of x87 is now handled, allowing some older games to run correctly
|
||||
=> More work has been done in the handling of precise NaN and Round handling in SSE & AVX opcodes
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 6 Jun 2025 10:30:33 -0100
|
||||
|
||||
box64 (0.3.4) unstable; urgency=low
|
||||
|
||||
* This version is Faster and more compatible
|
||||
* => The RV64 backend got faster and more stable, with lots of RVV 1.0 / xThreadVector support to emulate SSE/SSE2+ opcode (no AVX yet)
|
||||
* => On ARM64, Box64 now support more DRM types than before.
|
||||
* => BOX32 can run steam now. At least on ARM64 backend, it's still not working on RV64 and LA64 for now.
|
||||
* Please check CHAGELOG.md for more details
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 10 Mar 2025 10:30:33 -0100
|
||||
|
||||
box64 (0.3.2) unstable; urgency=low
|
||||
|
||||
* Introduced Box32 to run 32bits apps on 64bits OS
|
||||
* => Box32 is a build option for Box64, and is disabled by default
|
||||
* => Optionnal binfmt integration available for Box32
|
||||
* => Wrapped some basics libs, including graphics and sounds so a few games already works
|
||||
* => Work In Progress, many issues remain to be fixed, but some Linux games are playable
|
||||
* Introduced Native Flags. Can be controled with BOX64_DYNAREC_NATIVEFLAGS, but enabled by default
|
||||
* => Available on the 3 Dynarec backend, with different implementations
|
||||
* => ARM64 Dynarec build have all AVX/AVX2 extensions enabled by default
|
||||
* +> Can lead to large speedup on certain cases
|
||||
* Improved Strong Memory Model emulation, with better default options and a more efficiant emulation
|
||||
* Dynarec: RV64: using RVV (and XThreadVector) to implement SSEx opcodes, with some massive speedup when used!
|
||||
* Some bugfix and improvment in the Signal handler and internal memory tracking
|
||||
* Improvment to TRAP signal generation and Handling
|
||||
* Improved CPUID opcodes again, and the various virtual file in /proc that represent those data
|
||||
* Improved some x87 operations, like long double handling and infinity comparisons...
|
||||
* Dynarec: ARM64 fixes to a few opcodes
|
||||
* Dynarec: RV64 fixes to many opcodes
|
||||
* Dynarec: LA64 fixes to a few opcodes
|
||||
* Dynarec: RV64 fixes and improvments on LOCK prefixes opcodes
|
||||
* Dynarec: Many optimisation on some individual opcodes, an all 3 backends
|
||||
* WRAPPING: More libs and functions wrapped. Some wrapping fixes too
|
||||
* WREPPING: New wrapperhelper to help coding new wrapping & fixing/enhancing existing one
|
||||
* ElfLoader: Improved object fetching
|
||||
* New build profile for SD865 and ORYON
|
||||
* Changed the installation folder of x86 libs to avoid conflict with linux distro
|
||||
* Added a few syscalls
|
||||
* Some more Vulkan extensions wrapped
|
||||
* More work on build system, and github CI (generating WCP archive), with some fixes on the Android version (still not 100% operational)
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 6 Dec 2024 10:30:33 -0100
|
||||
|
||||
box64 (0.3.0) unstable; urgency=low
|
||||
|
||||
* AVX and AVX2 implemented, along with BMI1, BMI2, ADX, FMA, F16C and RDANDR extension!
|
||||
* Introduced BOX64_AVX env. var. to enable/disable AVX extension:
|
||||
* => BOX64_AVX=1 enable AVX, BMI1, F16C and VAES extension
|
||||
* => BOX64_AVX=2 also enable AVX2, BMI2, FMA, ADX,VPCLMULQDQ and RDRAND
|
||||
* Dynarec: Implemented most AVX/AVX2 and friends in ARM64 Dynarec (using only NEON, so available on all ARM64 CPU)
|
||||
* => ARM64 Dynarec build have all AVX/AVX2 extensions enabled by default
|
||||
* Improved CPUID opcodes, adding a few leaf, fixing same. Returnning an Haswell type of CPU now (was Pentium IV before)
|
||||
* Dynarec: Small optim in the emit_pf helper, on all 3 backends
|
||||
* Dynarec: ARM64 some fixes to a few opcodes
|
||||
* Dynarec: LA64 many new opcodes added, and fixes.
|
||||
* Dynarec: RV64 some new opcodes added, many fixes.
|
||||
* Dynarec: RV64 Adding some infrastructure to use RVV (if available) for SIMD emulation.
|
||||
* Dynarec: Many small changes and fixes around handling of x87, registers and internal jump.
|
||||
* WRAPPING: Added a workaround on SDL_GetThreadID to fix a race condition that was happening mostly on LA64 and broke many SDL games
|
||||
* WRAPPING: More libs and functions wrapped. Some wrapping fixes too (including a nasty error on some rare libGL functions)
|
||||
* WRAPPING: Wayland is now supported. Wine-wayland at least works now
|
||||
* Dynarec: LA64 improved LOCK CMPXCHG handling, and better 16Byte LOCK handling too (fixes many Unity3D games)
|
||||
* Dynarec: RV64 improved LOCK CMPXCHG handling
|
||||
* COSIM: Many fixes and improvment, to make BOX64_DYNAREC_TEST more usable
|
||||
* Detect when a Wine program use UnityPlayer.dll to atumaticaly use BOX64_DYNAREC_STRONGMEM=1 (unless it's already set), so more games just work
|
||||
* ElfLoader: Added a new type of relocation
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 9 Jul 2024 10:30:33 -0100
|
||||
|
||||
box64 (0.2.8) unstable; urgency=low
|
||||
|
||||
* Wrapping: More libs and function wrapping (gtk3, vulkan...)
|
||||
* Reworked X11 Callback handling, for better stability
|
||||
* Reworked exit and the load/unload of libs and symbol resolution
|
||||
* Some more profiles in box64rc
|
||||
* Better way to rename executable (including wine ones) so driver like mesa can apply the correct profile
|
||||
* Reworked memory managment in the Dynarec, limiting amount of dynamic allocation
|
||||
* Improved memory tracking and managment. Also introduce BOX64_MMAP32 to force 32bits compatible mmap for external libs (like mesa)
|
||||
* => Allow Vulkan drvier on Wine/WOW64 games to allocate 32bits compatible memory, allowing dxvk on 32bits.
|
||||
* Reworked memory managment in the Dynarec, limiting amount of dynamic allocation
|
||||
* Lots of improvments in x87 handling (virtual stack, rounding, ffree, etc.)
|
||||
* => should improve games stability
|
||||
* Dynarec: ARM64 some opcodes optimisation, especialy shift and rotation ones
|
||||
* Dynarec: RV64 lots of opcoded added.
|
||||
* => Some games on linux now have a good speed. Game on Wine are still a bit slow, and dxvk still have issues
|
||||
* Dynarec: Added Loogarch backend! Note that Loongarch are 16K pagesize platform by default.
|
||||
* => Linux games are running, and with good speed, especialy on 3A6000 platforms. Games on Wine are not working yet due to 16k pagesize limitation
|
||||
* Dynarec: Better handling of large block in the dynarec
|
||||
* Dynarec: Lots of improvments and fixes to BOX86_DYNAREC_CALLRET optimisation.
|
||||
* => It can be used on more software now, and combine with BOX64_DYNAREC_BOGBLOCKS 2 or 3 can gives some good speed boosts.
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 31 May 2024 17:30:33 -0100
|
||||
|
||||
box64 (0.2.6) unstable; urgency=low
|
||||
|
||||
* X64Libs: Updated libstdc++ & libgcc_s
|
||||
|
||||
Vendored
+13
-1
@@ -10,4 +10,16 @@ override_dh_auto_configure:
|
||||
-DNOGIT=1
|
||||
|
||||
override_dh_shlibdeps:
|
||||
dh_shlibdeps --exclude=libgcc_s.so.1 --exclude=libpng12.so.0 --exclude=libstdc++.so.5 --exclude=libstdc++.so.6
|
||||
dh_shlibdeps --exclude=libgcc_s.so.1 \
|
||||
--exclude=libpng12.so.0 \
|
||||
--exclude=libstdc++.so.5 \
|
||||
--exclude=libstdc++.so.6 \
|
||||
--exclude=libmbedcrypto.so.7 \
|
||||
--exclude=libssl.so.1.1 \
|
||||
--exclude=libunwind.so.8 \
|
||||
--exclude=libmbedtls.so.14 \
|
||||
--exclude=libcrypto.so.1.1 \
|
||||
--exclude=libmbedx509.so.1 \
|
||||
--exclude=libcrypto.so.1.0.0 \
|
||||
--exclude=libssl.so.1.0.0 \
|
||||
--exclude=box64-bash
|
||||
@@ -0,0 +1,73 @@
|
||||
# Bundling x86 Libraries
|
||||
|
||||
The script `box64-bundle-x86-libs.sh` is provided to download, extract, and re-bundle x86_64 and x86 libraries for use with Box64/Box32 and Box86. These libraries improve Box emulation. This bundle provides a much smaller size compared to using a full root file system of an operating system.
|
||||
|
||||
## Usage
|
||||
|
||||
### Administrator
|
||||
|
||||
Install required dependencies for the bundle script.
|
||||
|
||||
- Debian
|
||||
```
|
||||
sudo apt-get update
|
||||
sudo apt-get install coreutils curl binutils rpm2cpio tar zstd
|
||||
```
|
||||
- Fedora
|
||||
```
|
||||
sudo dnf install coreutils curl binutils tar zstd
|
||||
```
|
||||
|
||||
Run `box64-bundle-x86-libs.sh`. This will create two archives:
|
||||
- `box64-bundle-x86-libs.tar.gz` = All of the extracted library files in the directory structure of `usr/lib/box64-i386-linux-gnu` and `usr/lib/box64-x86_64-linux-gnu`.
|
||||
- `box64-bundle-x86-pkgs.tar.gz` = All of the Linux distribution packages used to extract the library files. This is only created for preservation purposes and is otherwise unused.
|
||||
|
||||
Extract the library archive. Box will automatically search these paths for library files to emulate.
|
||||
|
||||
```
|
||||
sudo tar --extract --file box64-bundle-x86-libs.tar.gz --directory /
|
||||
```
|
||||
|
||||
### Developer
|
||||
|
||||
Add new packages to the `box64-bundle-x86-libs.csv` file in the format of `<PACKAGE_URL>,<SHA256_CHECKSUM>`.
|
||||
|
||||
Supported packages:
|
||||
- DEB (Debian)
|
||||
- EOPKG (Solus)
|
||||
- RPM (Fedora)
|
||||
- XBPS (Void Linux)
|
||||
|
||||
Preference of operating system packages that provide a library:
|
||||
1. RPMs from AlmaLinux 9 provide 10 years of updates.
|
||||
2. DEBs from Debian 11 provide 5 years of updates.
|
||||
3. EOPKG from Solus provide old variants of obscure 32-bit libraries.
|
||||
4. XBPS from Void Linux provide updated variants of obscure 32-bit libraries.
|
||||
5. Other (whereever a library is packaged)
|
||||
|
||||
Some essential library files will never be emulated (only wrapped) and should not be bundled. This includes glibc, OpenGL, Vulkan, and X11/Xorg libraries. The full list can be found [here](https://github.com/ptitSeb/box64/blob/v0.3.2/src/librarian/library.c#L427). Other libraries with lots of dependencies, such as GTK, require all dependencies to be installed for emulation to work. This becomes dependency hell and should be avoided.
|
||||
|
||||
For finding package names that contian a specific library file, use the [pkgs.org](https://pkgs.org/) website. Otherwise, use one of these package manager commands on a x86_64 Linux distribution:
|
||||
- DEB
|
||||
- `apt-file <LIBRARY_FILE>`
|
||||
- EOPKG
|
||||
- Does not support file search. Use pkgs.org instead.
|
||||
- RPM
|
||||
- `dnf provides "*/<LIBRARY_FILE>*"`
|
||||
- XBPS
|
||||
- `xbps-query --repository --ownedby <LIBRARY_FILE>`
|
||||
|
||||
Once the package name is found, find the exact URL for downloading it.
|
||||
- DEB = Explore "main" and "contrib". Search for packages with the name "deb11" in it. Use the "amd64.deb" and "i386.deb" packages.
|
||||
- https://archive.debian.org/debian/pool/
|
||||
- EOPKG = Use the "`<VERSION>-<RELEASE>-x86_64.eopkg`" and "`32bit-<VERSION>-<RELEASE>-x86_64.eopkg`" packages.
|
||||
- https://cdn.getsol.us/repo/shannon/
|
||||
- RPM = Navigate to the "`<MAJOR>.<MINOR>`" version directory first. Then explore "AppStream" and "BaseOS". Use the "x86_64.rpm" and "i686.rpm" packages.
|
||||
- https://repo.almalinux.org/almalinux/
|
||||
- Enterprise Linux (EL) distributions, such as AlamaLinux, sometimes are missing 32-bit packages. Use the Fedora 34 [update](https://archives.fedoraproject.org/pub/archive/fedora/linux/updates/34/Everything/x86_64/Packages/) and [release](https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/34/Everything/x86_64/os/Packages/) archives for compatible packages with EL 9.
|
||||
- XBPS = There are too many files in the repository to display on a web browser. Use pkgs.org instead to find the exact URL for downloading it.
|
||||
- https://repo-default.voidlinux.org/current/
|
||||
|
||||
Download the package and then find the checksum with the `sha256sum` command.
|
||||
|
||||
Major Linux distributions such as AlmaLinux and Debian provide archives of packages. Rolling distributions such as Solus and Void Linux do not. In those cases, use the [Internet Archive](https://web.archive.org/) to archive any rolling release package used by Box by using the "Save Page Now" feature. If the error "Save Page Now browser crashed" appears, it can be safely ignored. The archive will still have been saved.
|
||||
@@ -1,3 +1,162 @@
|
||||
v0.3.6
|
||||
======
|
||||
|
||||
Highlights:
|
||||
|
||||
* This version introduces wowbox64.dll for Hangover; the ability to use the Volatile Metadata of Windows executables for x64 wine; and some better x87/SSE/AVX handling
|
||||
|
||||
=> WowBox64 can be built directly from Box64 repo, and can be found in the CI artifacts also
|
||||
=> it also supports a subset of BOX64_XXXX settings, which can be set from command line or via a setting file ".box64rc" in the Wine prefix home
|
||||
=> Volatile Metadata, when present, allows only applying strong memory ordering when needed, as marked by the compiler, giving overall better performances
|
||||
=> The precision control bit of x87 is now handled, allowing some older games to run correctly
|
||||
=> More work has been done in the handling of precise NaN and Round handling in SSE & AVX opcodes
|
||||
|
||||
Version summary:
|
||||
|
||||
* Added/fixed some Syscalls, helping Go programs
|
||||
* Wrapper: more functions added, and some fixes too. Vulkan is 1.4 now, among other things
|
||||
* Wrapper: Added a few more wrapped libs (like some avcodec and friends)
|
||||
* Improve internal memory allocator (with a dedicated allocator for small memory allocations), and fixed some issues around it
|
||||
* Improve internal mmaped file tracking
|
||||
* Box32: Some small refactoring around memory management and internal memory allocations
|
||||
* Box32: More functions wrapped
|
||||
* Box32: More libraries wrapped
|
||||
* ARM64: Added support for Atomic extension in many internal functions (not related to Dynarec).
|
||||
* ARM64: Added support for CRC2 extension for internal CRC functions
|
||||
* Interp: A few fixes to some opcodes, and better NAN handling on some selected SSE/AVX opcodes
|
||||
* Interp: Added a few opcodes with exotic prefixes
|
||||
* Dynarec: Introcude BOX64_DYNAREC_ROUND=2 to handle x87 precision control bit (ARM64 and RV64, LA64 still doesn't handle x87 yet)
|
||||
* Dynarec: Some small optimizations on Strongmem emulation, making it more efficient
|
||||
* Dynarec: Some speed optimizations on code that do SMC and waiting slot
|
||||
* Dynarec: Added CALLRET=2 to improve call/ret optimization compatibility with SMC code
|
||||
* Dynarec: ARM64: Various optimizations and fixes on some opcodes, especially AVX ones
|
||||
* Dynarec: ARM64: Added missing FASTNAN=0 handling on some SSE/AVX opcodes
|
||||
* Dynarec: ARM64: Added some exotic prefixed opcodes
|
||||
* Dynarec: ARM64: Avoid purging XMM/YMM register on intra-block loop if possible
|
||||
* Dynarec: RV64: Many fixes and improvments around x87 emulation
|
||||
* Dynarec: RV64: Added some more missing opcodes, especially some LOCK prefixed ones and many MMX ones
|
||||
* Dynarec: RV64: Various fixes on some existing opcodes
|
||||
* Dynarec: RV64: Improved nativeflags handling, allowing for more cases to use it
|
||||
* Dynarec: LA64: Added some more opcodes and MMX handling
|
||||
* Dynarec: LA64: Various fixes to some existing opcodes
|
||||
* Android: Improved signal handling, structure alignment, and transformation
|
||||
* WowBox64: Created the dll, with RcFile, Env. Var. handling and log printout (both ARM64 Dynarec and Interpreter available)
|
||||
* Cosim: Various fixes and improvements to limit false negatives and improve readability of logs
|
||||
* RcFile: A few fixes for some values that would be ignored
|
||||
|
||||
v0.3.4
|
||||
======
|
||||
* This version is Faster and more compatible:
|
||||
=> The RV64 backend got faster and more stable, with lots of RVV 1.0 / xThreadVector support to emulate SSE/SSE2+ opcode (no AVX yet)
|
||||
=> On ARM64, Box64 now support more DRM types than before.
|
||||
=> BOX32 can run steam now. At least on ARM64 backend, it's still not working on RV64 and LA64 for now.
|
||||
* Added support to emulate Windows Syscall (needs Proton and a 48bits address space for now)
|
||||
* Added BOX64_DYNAREC_DIRTY to have a faster (but less safe) way to handle code that write in it's current page
|
||||
* Added a few rarely used opcodes
|
||||
* Added experimental support for GDBJIT, that allow an x86/x86_64 program to be debugged on ARM/RV64/LA64 platform with x86 regs and opcode view (might generate a lot of file tho)
|
||||
* Added support for Perf tools in a similar way if GDBJIT, to have an x86 fine view of the performances
|
||||
* Reworked undefined flags for common operations, to be similar to real CPU
|
||||
* Reworked cpuid handling, adding BOX64_CPUTYPE support to select Intel/AMD emulation (no 3DNow! support on AMD for now)
|
||||
* Reworked ucontext link to be closer to the real thing (and make it more simple)
|
||||
* Improved memory traking, file descriptor backed memory map, and detect wine loaded dll
|
||||
* Introduced settings per library and dll (mostly for Dynarec)
|
||||
* Wrapper: More functions addes, and some fixes too
|
||||
* BOX32: Many fixes around pthreads wrapping
|
||||
* BOX32: More functions wrapped.
|
||||
* BOX32: More libraies wrapped.
|
||||
* BOX32: Some reworks on how high memory (higher than 32bits) is masked, and can be used for Dynarec blocks.
|
||||
* Dynarec: The usual batch of fixes, improvments and opcodes additions on all 3 supported backend
|
||||
* Dynarec: Some fixes to NativeFlags handling, both on ARM64 and RV64
|
||||
* Dynarec: Added optimized REP MOVSB (expected for default CPUTYPE=0, according to new cpuid return)
|
||||
* Dynarec: LA64: more opcoded addes, using hardware extensions like AES
|
||||
* Dynarec: RV64: More work on using RVV 1.0 and xTheadVector extension to emulate SSE/SSE2+ opcodes
|
||||
* Dynarec: RV64: Added informations on flags when building blocks, to be used when a signal happens to rebuild a x86 context more accurate
|
||||
* Dynarec: ARM64: Reworked undefined flags for common operations, to be similar to real CPU
|
||||
* Dynarec: ARM64: Added informations on flags and xmm/ymm/x87 register when building blocks, to be used when a signal happens to rebuild a x86 context 100% accurate
|
||||
* TRACE: Reworked how trace for wrapped function call is printed.
|
||||
* TRACE: Reworked logs to prefix each line with a (optionaly colored) BOX32 or BOX64
|
||||
* COSIM: Some rework on cosim to limit false negative, especialy when handling x87 operations
|
||||
* LA64: Added limited support for ABI 1.0
|
||||
* CI: github CI now also generate MiceWine .rat archive, along with Winlator .wcp archive and regular linux builds.
|
||||
* RCFile: Added many new games profiles (both for speed improvment or for compatibilty)
|
||||
|
||||
v0.3.2
|
||||
======
|
||||
* Introduced Box32 to run 32bits apps on 64bits OS
|
||||
=> Box32 is a build option for Box64, and is disabled by default
|
||||
=> Optionnal binfmt integration available for Box32
|
||||
=> Wrapped some basics libs, including graphics and sounds so a few games already works
|
||||
=> Work In Progress, many issues remain to be fixed, but some Linux games are playable
|
||||
* Introduced Native Flags. Can be controled with BOX64_DYNAREC_NATIVEFLAGS, but enabled by default
|
||||
=> Available on the 3 Dynarec backend, with different implementations
|
||||
=> ARM64 Dynarec build have all AVX/AVX2 extensions enabled by default
|
||||
+> Can lead to large speedup on certain cases
|
||||
* Improved Strong Memory Model emulation, with better default options and a more efficiant emulation
|
||||
* Dynarec: RV64: using RVV (and XThreadVector) to implement SSEx opcodes, with some massive speedup when used!
|
||||
* Some bugfix and improvment in the Signal handler and internal memory tracking
|
||||
* Improvment to TRAP signal generation and Handling
|
||||
* Improved CPUID opcodes again, and the various virtual file in /proc that represent those data
|
||||
* Improved some x87 operations, like long double handling and infinity comparisons...
|
||||
* Dynarec: ARM64 fixes to a few opcodes
|
||||
* Dynarec: RV64 fixes to many opcodes
|
||||
* Dynarec: LA64 fixes to a few opcodes
|
||||
* Dynarec: RV64 fixes and improvments on LOCK prefixes opcodes
|
||||
* Dynarec: Many optimisation on some individual opcodes, an all 3 backends
|
||||
* WRAPPING: More libs and functions wrapped. Some wrapping fixes too
|
||||
* WREPPING: New wrapperhelper to help coding new wrapping & fixing/enhancing existing one
|
||||
* ElfLoader: Improved object fetching
|
||||
* New build profile for SD865 and ORYON
|
||||
* Changed the installation folder of x86 libs to avoid conflict with linux distro
|
||||
* Added a few syscalls
|
||||
* Some more Vulkan extensions wrapped
|
||||
* More work on build system, and github CI (generating WCP archive), with some fixes on the Android version (still not 100% operational)
|
||||
|
||||
v0.3.0
|
||||
======
|
||||
* AVX and AVX2 implemented, along with BMI1, BMI2, ADX, FMA, F16C and RDANDR extension!
|
||||
* Introduced BOX64_AVX env. var. to enable/disable AVX extension:
|
||||
=> BOX64_AVX=1 enable AVX, BMI1, F16C and VAES extension
|
||||
=> BOX64_AVX=2 also enable AVX2, BMI2, FMA, ADX,VPCLMULQDQ and RDRAND
|
||||
* Dynarec: Implemented most AVX/AVX2 and friends in ARM64 Dynarec (using only NEON, so available on all ARM64 CPU)
|
||||
=> ARM64 Dynarec build have all AVX/AVX2 extensions enabled by default
|
||||
* Improved CPUID opcodes, adding a few leaf, fixing same. Returnning an Haswell type of CPU now (was Pentium IV before)
|
||||
* Dynarec: Small optim in the emit_pf helper, on all 3 backends
|
||||
* Dynarec: ARM64 some fixes to a few opcodes
|
||||
* Dynarec: LA64 many new opcodes added, and fixes.
|
||||
* Dynarec: RV64 some new opcodes added, many fixes.
|
||||
* Dynarec: RV64 Adding some infrastructure to use RVV (if available) for SIMD emulation.
|
||||
* Dynarec: Many small changes and fixes around handling of x87, registers and internal jump.
|
||||
* WRAPPING: Added a workaround on SDL_GetThreadID to fix a race condition that was happening mostly on LA64 and broke many SDL games
|
||||
* WRAPPING: More libs and functions wrapped. Some wrapping fixes too (including a nasty error on some rare libGL functions)
|
||||
* WRAPPING: Wayland is now supported. Wine-wayland at least works now
|
||||
* Dynarec: LA64 improved LOCK CMPXCHG handling, and better 16Byte LOCK handling too (fixes many Unity3D games)
|
||||
* Dynarec: RV64 improved LOCK CMPXCHG handling
|
||||
* COSIM: Many fixes and improvment, to make BOX64_DYNAREC_TEST more usable
|
||||
* Detect when a Wine program use UnityPlayer.dll to atumaticaly use BOX64_DYNAREC_STRONGMEM=1 (unless it's already set), so more games just work
|
||||
* ElfLoader: Added a new type of relocation
|
||||
|
||||
v0.2.8
|
||||
======
|
||||
* Wrapping: More libs and function wrapping (gtk3, vulkan...)
|
||||
* Reworked X11 Callback handling, for better stability
|
||||
* Reworked exit and the load/unload of libs and symbol resolution
|
||||
* Some more profiles in box64rc
|
||||
* Better way to rename executable (including wine ones) so driver like mesa can apply the correct profile
|
||||
* Reworked memory managment in the Dynarec, limiting amount of dynamic allocation
|
||||
* Improved memory tracking and managment. Also introduce BOX64_MMAP32 to force 32bits compatible mmap for external libs (like mesa)
|
||||
=> Allow Vulkan drvier on Wine/WOW64 games to allocate 32bits compatible memory, allowing dxvk on 32bits.
|
||||
* Reworked memory managment in the Dynarec, limiting amount of dynamic allocation
|
||||
* Lots of improvments in x87 handling (virtual stack, rounding, ffree, etc.)
|
||||
=> should improve games stability
|
||||
* Dynarec: ARM64 some opcodes optimisation, especialy shift and rotation ones
|
||||
* Dynarec: RV64 lots of opcoded added.
|
||||
=> Some games on linux now have a good speed. Game on Wine are still a bit slow, and dxvk still have issues
|
||||
* Dynarec: Added Loogarch backend! Note that Loongarch are 16K pagesize platform by default.
|
||||
=> Linux games are running, and with good speed, especialy on 3A6000 platforms. Games on Wine are not working yet due to 16k pagesize limitation
|
||||
* Dynarec: Better handling of large block in the dynarec
|
||||
* Dynarec: Lots of improvments and fixes to BOX86_DYNAREC_CALLRET optimisation.
|
||||
=> It can be used on more software now, and combine with BOX64_DYNAREC_BOGBLOCKS 2 or 3 can gives some good speed boosts.
|
||||
|
||||
v0.2.6
|
||||
======
|
||||
* X64Libs: Updated libstdc++ & libgcc_s
|
||||
|
||||
+167
-52
@@ -1,20 +1,16 @@
|
||||
Compiling/Installing
|
||||
----
|
||||
|
||||
### Debian-based Linux
|
||||
You can use [@ryanfortner](https://github.com/ryanfortner)'s apt repository to install precompiled box64 debs, updated every 24 hours.
|
||||
If you don't want to compile box64 yourself and prefer to use third-party pre-build version, go to the [end of the document](#pre-build-packages) for alternatives.
|
||||
|
||||
```
|
||||
sudo wget https://ryanfortner.github.io/box64-debs/box64.list -O /etc/apt/sources.list.d/box64.list
|
||||
wget -qO- https://ryanfortner.github.io/box64-debs/KEY.gpg | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/box64-debs-archive-keyring.gpg
|
||||
sudo apt update && sudo apt install box64-arm64 -y
|
||||
```
|
||||
You can also generate your own package using the [instructions below](https://github.com/ptitSeb/box64/blob/main/docs/COMPILE.md#debian-packaging).
|
||||
|
||||
Alternatively, you can generate your own package using the [instructions below](https://github.com/ptitSeb/box64/blob/main/docs/COMPILE.md#debian-packaging).
|
||||
Additional installation steps may be necessary when copying only the box64 executable file without running make install in cross-build environments. See [Cross-compiling](https://github.com/ptitSeb/box64/blob/main/docs/COMPILE.md#Cross-compiling)
|
||||
|
||||
----
|
||||
## Per-platform compiling instructions
|
||||
|
||||
### The general approach
|
||||
|
||||
### The general approach is:
|
||||
```
|
||||
git clone https://github.com/ptitSeb/box64
|
||||
cd box64
|
||||
@@ -26,10 +22,30 @@ If it's the first install, you also need:
|
||||
```
|
||||
sudo systemctl restart systemd-binfmt
|
||||
```
|
||||
- You can use `make -j1`, `make -j2` to prevent running out of memory
|
||||
- You can also add `-DBAD_SIGNAL=ON` to the cmake command if you are on Linux Kernel mixed with Android, like on RK3588.
|
||||
- You can use `make -j1`, `make -j2` with less jobs to prevent running out of memory
|
||||
- You can also add `-DBAD_SIGNAL=ON` to the cmake command if you are on a Linux Kernel mixed with Android, like on RK3588.
|
||||
|
||||
### Note about Box32
|
||||
|
||||
If you want to build Box64 with the Box32 option, you will need to add `-DBOX32=ON` to the cmake command. That will enable 32bits process to be run with Box64.
|
||||
If you also want binfmt integration on 32bits binaries, you also need to add `-DBOX32_BINFMT=ON` to the cmake command.
|
||||
|
||||
### Note about WowBox64
|
||||
|
||||
A highly experimantal subproject named WowBox64 has been added as a build option, add `-DWOW64=ON` to the cmake command to enable it.
|
||||
It will build alongside the regular Box64, and produce a `wowbox64.dll` file in `build/wowbox64-prefix/src/wowbox64-build/` directory.
|
||||
|
||||
### Note about binfmt_misc on Android
|
||||
|
||||
[binfmt_misc](https://en.wikipedia.org/wiki/Binfmt_misc) is a capability of the Linux kernel which allows arbitrary executable file formats to be recognized and passed to certain user space applications such as Box64 usually used with systemd but systems like Android can't run/use systemd so you will need to register Box64 manually, this will also work inside a CHRoot.
|
||||
```
|
||||
sudo mount -t binfmt_misc none /proc/sys/fs/binfmt_misc
|
||||
sudo echo ':box64:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x3e\x00:\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/box64:' | sudo tee /proc/sys/fs/binfmt_misc/register
|
||||
```
|
||||
|
||||
|
||||
#### Example of generic ARM64 build for linux platforms
|
||||
|
||||
#### For Instance, if you want to build box64 for Generic ARM64 Linux platforms, it would look like this:
|
||||
```
|
||||
git clone https://github.com/ptitSeb/box64
|
||||
cd box64
|
||||
@@ -38,25 +54,37 @@ make -j4
|
||||
sudo make install
|
||||
sudo systemctl restart systemd-binfmt
|
||||
```
|
||||
|
||||
#### Example of generic ARM64 build for linux platforms with full box32 integration
|
||||
|
||||
```
|
||||
git clone https://github.com/ptitSeb/box64
|
||||
cd box64
|
||||
mkdir build; cd build; cmake .. -D ARM_DYNAREC=ON -D CMAKE_BUILD_TYPE=RelWithDebInfo -D BOX32=ON -D BOX32_BINFMT=ON
|
||||
make -j4
|
||||
sudo make install
|
||||
sudo systemctl restart systemd-binfmt
|
||||
```
|
||||
|
||||
----
|
||||
|
||||
#### for RK3399
|
||||
|
||||
Using a 64bit OS:
|
||||
On a 64bit OS:
|
||||
```
|
||||
-D RK3399=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
|
||||
#### for RK3588 / RK3588S
|
||||
|
||||
Using a 64bit OS:
|
||||
On a 64bit OS:
|
||||
```
|
||||
-D RK3588=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
|
||||
#### for Raspberry Pi 3
|
||||
|
||||
Warning, you need a 64bit OS:
|
||||
On a 64bit OS:
|
||||
|
||||
If building on the Pi, you will also need a large swap (3 GB+)
|
||||
[optionally reduce GPU memory to a minimum (e.g. 16 MB) using `raspi-config`
|
||||
@@ -72,7 +100,7 @@ Still, this can be faster if your build is attended.
|
||||
|
||||
#### for Raspberry Pi 4
|
||||
|
||||
Warning, you need a 64bit OS:
|
||||
On a 64bit OS:
|
||||
|
||||
```
|
||||
-D RPI4ARM64=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
@@ -80,23 +108,38 @@ Warning, you need a 64bit OS:
|
||||
|
||||
#### for Raspberry Pi 5
|
||||
|
||||
If your Raspberry Pi OS use 16K pages use `RPI5ARM64PS16K` instead of `RPI5ARM64`:
|
||||
```
|
||||
-D RPI5ARM64=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
|
||||
#### for TEGRA X1
|
||||
|
||||
Using a 64bit OS:
|
||||
On a 64bit OS:
|
||||
|
||||
```
|
||||
-D TEGRAX1=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
|
||||
#### for Jetson Xavier/T194
|
||||
|
||||
On a 64bit OS:
|
||||
|
||||
```
|
||||
-D TEGRA_T194=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
|
||||
#### for Jetson Orin/T234
|
||||
|
||||
On a 64bit OS:
|
||||
|
||||
Note: use gcc-11 or higher, older gcc doesn't know cortex-a78ae
|
||||
```
|
||||
-D TEGRA_T234=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
|
||||
#### for ODROID N2/N2+
|
||||
|
||||
Using a 64bit OS:
|
||||
On a 64bit OS:
|
||||
|
||||
```
|
||||
-D ODROIDN2=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
@@ -104,7 +147,7 @@ Using a 64bit OS:
|
||||
|
||||
#### for Snapdragon
|
||||
|
||||
Using a 64bit OS:
|
||||
On a 64bit OS:
|
||||
|
||||
```
|
||||
-D SD845=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
@@ -116,25 +159,25 @@ or
|
||||
-D SD888=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
|
||||
Depending how recent your Snapdragon is
|
||||
Depending on how recent your Snapdragon is
|
||||
|
||||
#### for Phytium
|
||||
|
||||
Using a 64bit OS:
|
||||
On a 64bit OS:
|
||||
```
|
||||
-D PHYTIUM=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
|
||||
#### for ADLink machines
|
||||
|
||||
Using a 64bit OS:
|
||||
On a 64bit OS:
|
||||
```
|
||||
-D ADLINK=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
|
||||
#### for M1
|
||||
|
||||
Only test on Asahi for now, using the default "16K page" kernel
|
||||
Only test on Asahi with Fedora, using the default "16K page" kernel
|
||||
|
||||
```
|
||||
-D M1=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
@@ -142,7 +185,7 @@ Only test on Asahi for now, using the default "16K page" kernel
|
||||
|
||||
#### for LoongArch
|
||||
|
||||
Using a 64bit OS:
|
||||
On a 64bit OS:
|
||||
|
||||
```
|
||||
-D LARCH64=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
@@ -150,7 +193,7 @@ Using a 64bit OS:
|
||||
|
||||
#### for RISC-V
|
||||
|
||||
Using a 64bit OS:
|
||||
On a 64bit OS:
|
||||
|
||||
```
|
||||
-D RV64=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
@@ -158,7 +201,7 @@ Using a 64bit OS:
|
||||
|
||||
#### for PowerPC 64 LE
|
||||
|
||||
Using a 64bit OS:
|
||||
On a 64bit OS:
|
||||
|
||||
```
|
||||
-D PPC64LE=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
@@ -166,7 +209,7 @@ Using a 64bit OS:
|
||||
|
||||
#### for LX2160A
|
||||
|
||||
Using a 64bit OS:
|
||||
On a 64bit OS:
|
||||
|
||||
```
|
||||
-D LX2160A=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
@@ -174,7 +217,7 @@ Using a 64bit OS:
|
||||
|
||||
#### for Termux
|
||||
|
||||
You must have ARM64 Device for build box64.
|
||||
You must have ARM64 machine to build box64.
|
||||
|
||||
##### in CHRoot/PRoot
|
||||
|
||||
@@ -184,15 +227,16 @@ You must have ARM64 Device for build box64.
|
||||
|
||||
##### in Termux (Native)
|
||||
|
||||
NOTE: BUILDING BOX64 IN TERMUX NATIVE IS EXPERIMENTAL AND DOESN'T GONNA RUN LINUX BINARIES IN NATIVE TERMUX BOX64!!!
|
||||
Note: Box64 in native termux is experimental and won't run linux binaries!
|
||||
|
||||
You also needed have `libandroid-sysv-semaphore` and `libandroid-spawn` libraries:
|
||||
You also need `libandroid-sysv-semaphore` and `libandroid-spawn` libraries.
|
||||
|
||||
```
|
||||
-D TERMUX=1 -D -DCMAKE_C_COMPILER=clang CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
-D TERMUX=1 -DCMAKE_C_COMPILER=clang -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
|
||||
#### for x86_64 Linux
|
||||
|
||||
```
|
||||
-D LD80BITS=1 -D NOALIGN=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
@@ -202,50 +246,121 @@ If you encounter some linking errors, try using `NOLOADADDR=ON` (`cmake -D NOLOA
|
||||
|
||||
### Use ccmake
|
||||
|
||||
Alternatively, you can **use the curses-bases ccmake (or any other gui frontend for cmake)** to select wich platform to use interactively.
|
||||
Alternatively, you can **use the curses-based ccmake (or any other gui frontend for cmake)** to select which platform to use interactively.
|
||||
|
||||
### Customize your build
|
||||
|
||||
#### Use ccache if you have it
|
||||
#### Use ccache when present
|
||||
|
||||
Add `-DUSE_CCACHE=1` if you have ccache (it's better if you plan to touch the sources)
|
||||
Add `-DUSE_CCACHE=1` option if you have ccache and plan to touch the sources.
|
||||
|
||||
#### To have some debug info
|
||||
#### Include debug information
|
||||
|
||||
The `-DCMAKE_BUILD_TYPE=RelWithDebInfo` argument makes a build that is both optimized for speed, and has debug information embedded. That way, if you have a crash or try to analyse performance, you'll have some symbols.
|
||||
Add `-DCMAKE_BUILD_TYPE=RelWithDebInfo` option for an optimized build with debug information embedded. That way, if you want to debug a crash or analyze performance, you have symbols.
|
||||
|
||||
#### To have a Trace Enabled build
|
||||
#### Build with trace
|
||||
|
||||
To have a trace enabled build (***the interpreter will be slightly slower***), add `-DHAVE_TRACE=1`. But you will need to have the [Zydis library](https://github.com/zyantific/zydis) in your `LD_LIBRARY_PATH` or in the system library folders at runtime. Use version v3.2.1, as later version changed the API and will no longer work with box64
|
||||
To have a trace enabled build (***the interpreter will be slightly slower***), add `-DHAVE_TRACE=1`. You will need the [Zydis library](https://github.com/zyantific/zydis) in your `LD_LIBRARY_PATH` or in the system library folders at runtime to get x86 trace. Use version v3.2.1, as later versions have changed the API and no longer work with box64.
|
||||
|
||||
#### To have ARM Dynarec
|
||||
#### Build DynaRec
|
||||
|
||||
Dynarec is only available on ARM (for the meantime), Activate it by using `-DARM_DYNAREC=1`.
|
||||
Add `-D ARM_DYNAREC=ON` option to enable DynaRec on ARM machines.
|
||||
Add `-D RV64_DYNAREC=ON` option to enable DynaRec on RV64 machines.
|
||||
Add `-D LARCH64_DYNAREC=ON` option to enable DynaRec on LARCH64 machines.
|
||||
|
||||
#### To have a build using less memory
|
||||
#### Save memory at run time
|
||||
|
||||
You can use `-DSAVE_MEM` to have a build that will try to save some memory. It's, for now, only increasing the jumptable from 4 level to 5 levels. The added granularity avoid wasting space, but the 1 level more to the jumptable means there is on read from memory more when jumping between blocks.
|
||||
You can use `-DSAVE_MEM` to have a build that will try to save some memory. For now, it only increases the jumptable from 4 levels to 5. The added granularity avoids wasting space, but adds one more read from memory when jumping between blocks.
|
||||
|
||||
#### Not building from a git clone
|
||||
#### Build outside of a git repo
|
||||
|
||||
If you are not building from a git clone (for example, downloading a release source code zip from github), you need to use `-DNOGIT=1` from cmake to be able to build (box64 uses git SHA1 to show last commit in version number).
|
||||
Box64 uses git SHA1 to show last commit in version number, use `-DNOGIT=1` option when building outside of a git repo (for example, downloading a release source code zip from github).
|
||||
|
||||
#### Use faster linker
|
||||
|
||||
You need to add `-DWITH_MOLD=1` if GNU ld is extremely slow. Then run `mold -run make -j4` to build (make sure [Mold](https://github.com/rui314/mold) is installed).
|
||||
Add `-DWITH_MOLD=1` option when GNU ld is extremely slow. Then run `mold -run make -j4` to build (make sure [Mold](https://github.com/rui314/mold) is installed).
|
||||
|
||||
#### Build a statically linked box64
|
||||
|
||||
You can now build box64 statically linked, with `-DSTATICBUILD` to use inside of a x86_64 chroot. Note that this version of box64 will only have the minimal wrapped libs, such as libc, libm and libpthread. Other libs (like libGL or libvulkan, SDL2, etc...) will use x86_64 versions. A static build is intended to be used in a docker image, or in a headless server. It is highly experimental, but feedback is always welcome.
|
||||
|
||||
----
|
||||
|
||||
Testing
|
||||
----
|
||||
## Testing
|
||||
|
||||
A few tests are included with box64.
|
||||
|
||||
They can be launched using the `ctest` command.
|
||||
|
||||
The tests are very basic and only tests some functionality for now.
|
||||
The tests are very basic and only test some functionality for now.
|
||||
|
||||
----
|
||||
|
||||
Debian Packaging
|
||||
## Debian Packaging
|
||||
|
||||
Box64 can also be packaged into a .deb file ***using the source code zip from the releases page*** with `DEB_BUILD_OPTIONS=nostrip dpkg-buildpackage -us -uc -nc`. Configure any additional cmake options you want in `debian/rules`.
|
||||
|
||||
## Pre-built packages
|
||||
|
||||
### Debian-based Linux
|
||||
|
||||
You can use the [Pi-Apps-Coders apt repository](https://github.com/Pi-Apps-Coders/box64-debs) to install precompiled box64 debs, updated every 24 hours.
|
||||
|
||||
```
|
||||
# check if .list file already exists
|
||||
if [ -f /etc/apt/sources.list.d/box64.list ]; then
|
||||
sudo rm -f /etc/apt/sources.list.d/box64.list || exit 1
|
||||
fi
|
||||
|
||||
# check if .sources file already exists
|
||||
if [ -f /etc/apt/sources.list.d/box64.sources ]; then
|
||||
sudo rm -f /etc/apt/sources.list.d/box64.sources || exit 1
|
||||
fi
|
||||
|
||||
# download gpg key from specified url
|
||||
if [ -f /usr/share/keyrings/box64-archive-keyring.gpg ]; then
|
||||
sudo rm -f /usr/share/keyrings/box64-archive-keyring.gpg
|
||||
fi
|
||||
sudo mkdir -p /usr/share/keyrings
|
||||
wget -qO- "https://pi-apps-coders.github.io/box64-debs/KEY.gpg" | sudo gpg --dearmor -o /usr/share/keyrings/box64-archive-keyring.gpg
|
||||
|
||||
# create .sources file
|
||||
echo "Types: deb
|
||||
URIs: https://Pi-Apps-Coders.github.io/box64-debs/debian
|
||||
Suites: ./
|
||||
Signed-By: /usr/share/keyrings/box64-archive-keyring.gpg" | sudo tee /etc/apt/sources.list.d/box64.sources >/dev/null
|
||||
|
||||
sudo apt update
|
||||
sudo apt install box64-generic-arm -y
|
||||
```
|
||||
|
||||
## Cross-compiling
|
||||
----
|
||||
Box64 can also be packaged into a .deb file ***using the source code zip from the releases page*** with `DEB_BUILD_OPTIONS=nostrip dpkg-buildpackage -us -uc -nc`. Configure any additional cmake options you might want in `debian/rules`.
|
||||
### Set Up the Cross-Compiler
|
||||
For example, to compile Box64 for RISC-V on an x86 machine, you can get prebuilt GNU toolchain from the [riscv-gnu-toolchain](https://github.com/riscv-collab/riscv-gnu-toolchain/releases)
|
||||
|
||||
### Run CMake with Cross-Compilation Options
|
||||
Follow the per-platform compilation instructions to configure the CMake options for your target architecture.
|
||||
In particular, you must specify the cross-compiler. For example:
|
||||
```
|
||||
-DCMAKE_C_COMPILER=riscv64-unknown-linux-gnu-gcc # Or whichever cross-compiler you use
|
||||
```
|
||||
|
||||
### Running tests with QEMU (optional)
|
||||
To do a quick check, run:
|
||||
```
|
||||
qemu-riscv64 -L path/to/your/riscv64/sysroot box64 --help
|
||||
```
|
||||
You can run `dirname $(find -name libc.so.6)` to determine whether sysroot is provided by the prebuilt GNU toolchain or not.
|
||||
|
||||
To run CTest-based tests under QEMU:
|
||||
```
|
||||
ctest -j$(nproc)
|
||||
```
|
||||
|
||||
### Installing on the Target Machine
|
||||
After successfully cross-compiling, copy the box64 executable to your RISC-V device. Note that simply copying the binary does not automatically install Box64’s shared libraries. Because `make install` does not run on the target during cross-compilation, libraries required for emulation may be missing.
|
||||
|
||||
To fix this, copy the shared libraries folder from the Box64 repository (`x64lib` or `x86lib`) to your target. Place them into the proper library search paths, for example:
|
||||
- `/usr/lib/box64-x86_64-linux-gnu/` (for x86_64)
|
||||
- `/usr/lib/box64-i386-linux-gnu/` (for i386)
|
||||
+738
-356
File diff suppressed because it is too large.
Load diff
+777
-432
File diff suppressed because it is too large.
Load diff
+328
@@ -0,0 +1,328 @@
|
||||
# Usage: python gen.py
|
||||
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
from collections import defaultdict
|
||||
|
||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
usage_file = os.path.join(script_dir, 'usage.json')
|
||||
|
||||
with open(usage_file, 'r') as file:
|
||||
data = json.load(file)
|
||||
|
||||
with open(os.path.join(script_dir, '../USAGE.md'), 'w') as md_file:
|
||||
md_file.write("""<!--- This file is generated by gen.py, do not edit it directly. -->
|
||||
Usage
|
||||
----
|
||||
|
||||
There are many environment variables to control Box64's behaviour, which will be listed below by category.
|
||||
|
||||
There are 2 types of Box64 builds: the Wine WOW64 build (WowBox64) and the regular Linux build. Beware only some of the environment variables are available in WowBox64.
|
||||
|
||||
### Configuration files
|
||||
|
||||
In addition to environment variables, if you're using the regular Linux build, Box64 also looks for 2 places for rcfile by default: the system-wide `/etc/box64.box64rc` and user-specific `~/.box64rc`.
|
||||
While in WowBox64, the configuration file is checked at `%USERPROFILE%/.box64rc` only.
|
||||
Settings priority follows this order (from highest to lowest): `~/.box64rc` > `/etc/box64.box64rc` > environment variables.
|
||||
|
||||
Example configuration:
|
||||
|
||||
```
|
||||
[factorio]
|
||||
BOX64_DYNAREC_SAFEFLAGS=0
|
||||
BOX64_DYNAREC_BIGBLOCK=2
|
||||
BOX64_DYNAREC_FORWARD=1024
|
||||
BOX64_DYNAREC_CALLRET=1
|
||||
```
|
||||
|
||||
This configuration will apply the specified settings application-wide to any executable named `factorio`.
|
||||
|
||||
### Advanced usage for Linux build
|
||||
|
||||
1. **Wildcard Matching**
|
||||
|
||||
Asterisks (`*`) can be used for basic pattern matching in application names. For instance, `[*setup*]` will match any program containing "setup" in its name. Note this implements simple wildcard matching rather than full regex support.
|
||||
2. **Custom Configuration File**
|
||||
|
||||
The `BOX64_RCFILE` environment variable can specify an alternative configuration file instead of the default `/etc/box64.box64rc`.
|
||||
3. **Per-File Settings**
|
||||
|
||||
Sections starting with `/` apply to specific files. For example:
|
||||
```
|
||||
[/d3d9.dll]
|
||||
BOX64_DYNAREC_SAFEFLAGS=0
|
||||
```
|
||||
These settings will only affect the `d3d9.dll` file. This syntax also works for **emulated** Linux libraries, e.g., `[/libstdc++.so.6]`.
|
||||
|
||||
----
|
||||
|
||||
""")
|
||||
|
||||
categories = defaultdict(list)
|
||||
for entry in data:
|
||||
categories[entry["category"]].append(entry)
|
||||
|
||||
for category, entries in categories.items():
|
||||
md_file.write(f"## {category}\n\n")
|
||||
for entry in entries:
|
||||
md_file.write(f"### {entry['name']}\n\n{entry['description']}{' Availble in WowBox64.' if entry['wine'] else ''}\n\n")
|
||||
for option in entry['options']:
|
||||
md_file.write(f" * {option['key']}: {option['description']} {'[Default]' if option['default'] else ''}\n")
|
||||
md_file.write("\n")
|
||||
|
||||
|
||||
with open(os.path.join(script_dir, '../box64.pod'), 'w') as pod_file:
|
||||
pod_file.write("""=head1 NAME
|
||||
|
||||
box64 - Linux Userspace x86_64 Emulator with a twist
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
B<box64> [B<--help>] [B<--version>] I<executable>
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
B<Box64> lets you run x86_64 Linux programs (such as games) on non-x86_64 Linux
|
||||
systems, like ARM (host system needs to be 64-bit little-endian). Since B<Box64>
|
||||
uses the native versions of some "system" libraries, like libc, libm, SDL, and
|
||||
OpenGL, it's easy to integrate and use with most applications, and performance
|
||||
can be surprisingly high in many cases. B<Box64> integrates with DynaRec (dynamic
|
||||
recompiler) for the ARM64 platform, providing a speed boost between 5 to 10
|
||||
times faster than using only the interpreter.
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
=over 8
|
||||
|
||||
=item B<-h,--help>
|
||||
|
||||
Print box64 help and quit.
|
||||
|
||||
=item B<-v,--version>
|
||||
|
||||
Print box64 version and quit.
|
||||
|
||||
=back
|
||||
|
||||
=head1 BRIEF USAGE
|
||||
|
||||
There are many environment variables to control B<Box64>'s behaviour. In
|
||||
addition to environment variables, B<Box64> also looks for 2 places for rcfile:
|
||||
F</etc/box64.box64rc> and F<~/.box64rc>, in the format of .ini files.
|
||||
Settings priority: F<~/.box64rc> > F</etc/box64.box64rc> > environment variables.
|
||||
Example:
|
||||
|
||||
[factorio]
|
||||
BOX64_DYNAREC_SAFEFLAGS=0
|
||||
BOX64_DYNAREC_BIGBLOCK=2
|
||||
BOX64_DYNAREC_FORWARD=1024
|
||||
BOX64_DYNAREC_CALLRET=1
|
||||
|
||||
=head1 ENVIRONMENT VARIABLES
|
||||
|
||||
=over 8
|
||||
|
||||
""")
|
||||
|
||||
for entry in data:
|
||||
pod_file.write(f"\n=item B<{entry['name']}> =I<{ '|'.join(option['key'] for option in entry['options']) }>\n\n{entry['description']}{' Availble in WowBox64.' if entry['wine'] else ''}\n\n")
|
||||
for option in entry['options']:
|
||||
pod_file.write(f" * {option['key']} : {option['description']} {'[Default]' if option['default'] else ''}\n")
|
||||
pod_file.write("\n")
|
||||
|
||||
pod_file.write("""
|
||||
=back
|
||||
|
||||
=cut
|
||||
""")
|
||||
|
||||
####################
|
||||
# Validation
|
||||
####################
|
||||
|
||||
PADDING = 30
|
||||
INCLUDE_BLANK = False
|
||||
|
||||
def get_usage_entry(usage, define):
|
||||
entry = list(e for e in usage if e["name"] == define)
|
||||
if len(entry) == 0:
|
||||
print(f"{define:<{PADDING}}: missing usage.json entry")
|
||||
elif len(entry) > 1:
|
||||
print(f"{define:<{PADDING}}: multiple usage entries found", len(entry))
|
||||
else:
|
||||
return entry[0]
|
||||
return None
|
||||
|
||||
# check `default` uniqueness
|
||||
for entry in data:
|
||||
i = list(d["default"] for d in entry["options"]).count(True)
|
||||
if i > 1:
|
||||
print(f"{entry['name']:<{PADDING}}: multiple default values usage.json")
|
||||
|
||||
|
||||
# regex to match env.h C code
|
||||
regex = {
|
||||
"INTEGER": re.compile(
|
||||
r"^\s*INTEGER\((?P<define>\w+), (?P<name>\w+), (?P<default>\w+), (?P<min>\w+), (?P<max>\w+), (?P<wine>\w+)\)"
|
||||
),
|
||||
"INTEGER64": re.compile(
|
||||
r"^\s*INTEGER64\((?P<define>\w+), (?P<name>\w+), (?P<default>\w+), (?P<wine>\w+)\)"
|
||||
),
|
||||
"BOOLEAN": re.compile(
|
||||
r"^\s*BOOLEAN\((?P<define>\w+), (?P<name>\w+), (?P<default>\w+), (?P<wine>\w+)\)"
|
||||
),
|
||||
"ADDRESS": re.compile(r"^\s*ADDRESS\((?P<define>\w+), (?P<name>\w+), (?P<wine>\w+)\)"),
|
||||
"STRING": re.compile(r"^\s*STRING\((?P<define>\w+), (?P<name>\w+), (?P<wine>\w+)\)"),
|
||||
}
|
||||
|
||||
env_file = os.path.join(script_dir, "../../src/include/env.h")
|
||||
with open(env_file, "r") as file:
|
||||
matches = {}
|
||||
for line in file.readlines():
|
||||
for t, r in regex.items():
|
||||
m = r.search(line)
|
||||
if m:
|
||||
# filter out comments and other non useful code
|
||||
if m.group("define") == "NAME":
|
||||
continue
|
||||
|
||||
if t not in matches:
|
||||
matches[t] = {}
|
||||
if (m.group("define") in matches[t]):
|
||||
# multiple definitions, no default
|
||||
matches[t][m.group("define")]['no_default'] = True
|
||||
break
|
||||
matches[t][m.group("define")] = m.groupdict()
|
||||
matches[t][m.group("define")]['no_default'] = False
|
||||
|
||||
for define, m in matches["INTEGER"].items():
|
||||
name = m["name"]
|
||||
default = None if m["no_default"] or not m["default"].isdigit() else int(m["default"])
|
||||
min = int(m["min"])
|
||||
max = int(m["max"])
|
||||
|
||||
# Check default in valid range
|
||||
if default and (default < min or default > max):
|
||||
print(f"{define:<{PADDING}}: default lays outside of min/max range")
|
||||
|
||||
# Check consistency with usage.json
|
||||
if e := get_usage_entry(data, define):
|
||||
# guess min/max values if possible
|
||||
min2 = max2 = None
|
||||
# blank means that the entry has an 'XXXX' entry which usually indicated that arbitrary values are valid
|
||||
blank = False
|
||||
default2 = None
|
||||
|
||||
if int(m["wine"]) != int(e["wine"]):
|
||||
print(f"{define:<{PADDING}}: wine mismatch: env.h={int(m['wine'])}, usage.json={int(e['wine'])}")
|
||||
|
||||
for o in e["options"]:
|
||||
if o["key"] == "XXXX":
|
||||
blank = True
|
||||
continue
|
||||
|
||||
val = int(o["key"]) # not supposed to fail
|
||||
|
||||
min2 = min2 if min2 is not None and min2 < val else val
|
||||
max2 = max2 if max2 is not None and max2 > val else val
|
||||
|
||||
if o["default"]:
|
||||
default2 = val
|
||||
|
||||
if min2 and min2 != min:
|
||||
if not blank or (blank and INCLUDE_BLANK):
|
||||
print(
|
||||
f"{define:<{PADDING}}: min value mismatch: env.h={min}, usage.json={min2}{(' (possible false positive)' if blank else '')}"
|
||||
)
|
||||
if max2 and max2 != max:
|
||||
if not blank or (blank and INCLUDE_BLANK):
|
||||
print(
|
||||
f"{define:<{PADDING}}: max value mismatch: env.h={max}, usage.json={max2}{(' (possible false positive)' if blank else '')}"
|
||||
)
|
||||
if default2 != default:
|
||||
print(
|
||||
f"{define:<{PADDING}}: default value mismatch: env.h={default}, usage.json={default2}"
|
||||
)
|
||||
|
||||
for define, m in matches['INTEGER64'].items():
|
||||
# similar to INTEGER but without min/max
|
||||
name = m["name"]
|
||||
default = None if m["no_default"] or not m["default"].isdigit() else int(m["default"])
|
||||
|
||||
# Check consistency with usage.json
|
||||
if e := get_usage_entry(data, define):
|
||||
default2 = None
|
||||
|
||||
if int(m["wine"]) != int(e["wine"]):
|
||||
print(f"{define:<{PADDING}}: wine mismatch: env.h={int(m['wine'])}, usage.json={int(e['wine'])}")
|
||||
|
||||
for o in e["options"]:
|
||||
if o["key"] == "XXXX":
|
||||
continue
|
||||
|
||||
val = int(o["key"])
|
||||
|
||||
if o["default"]:
|
||||
default2 = val
|
||||
|
||||
if default2 != default:
|
||||
print(
|
||||
f"{define:<{PADDING}}: default value mismatch: env.h={default}, usage.json={default2}"
|
||||
)
|
||||
|
||||
for define, m in matches["BOOLEAN"].items():
|
||||
name = m["name"]
|
||||
default = None if m["no_default"] or m["default"] not in ["0", "1"] else bool(m["default"])
|
||||
|
||||
# Check consistency with usage.json
|
||||
if e := get_usage_entry(data, define):
|
||||
default2 = None
|
||||
|
||||
if int(m["wine"]) != int(e["wine"]):
|
||||
print(f"{define:<{PADDING}}: wine mismatch: env.h={int(m['wine'])}, usage.json={int(e['wine'])}")
|
||||
|
||||
for o in e["options"]:
|
||||
try:
|
||||
val = bool(o["key"])
|
||||
except ValueError:
|
||||
print(f"{define:<{PADDING}}: failed to parse boolean {o['key']}")
|
||||
|
||||
if o["default"]:
|
||||
default2 = val
|
||||
|
||||
if default2 != default:
|
||||
print(
|
||||
f"{define:<{PADDING}}: default value mismatch: env.h={default}, usage.json={default2}"
|
||||
)
|
||||
|
||||
# ADDRESS and STRING are not that interesting
|
||||
for define, m in matches["ADDRESS"].items():
|
||||
if e := get_usage_entry(data, define):
|
||||
if int(m["wine"]) != int(e["wine"]):
|
||||
print(f"{define:<{PADDING}}: wine mismatch: env.h={int(m['wine'])}, usage.json={int(e['wine'])}")
|
||||
|
||||
for define, m in matches["STRING"].items():
|
||||
# skip BOX64_ENV[1-5] entries, they mismatch but this is fine
|
||||
if define.startswith("BOX64_ENV"):
|
||||
continue
|
||||
if e := get_usage_entry(data, define):
|
||||
if int(m["wine"]) != int(e["wine"]):
|
||||
print(f"{define:<{PADDING}}: wine mismatch: env.h={int(m['wine'])}, usage.json={int(e['wine'])}")
|
||||
|
||||
# check that everything from usage.json is in env.h
|
||||
for e in data:
|
||||
define = e["name"]
|
||||
|
||||
# skip BOX64_ENV[1-5] entries, they mismatch but this is fine
|
||||
if define.startswith("BOX64_ENV"):
|
||||
continue
|
||||
|
||||
found = False
|
||||
for t in matches:
|
||||
for d in matches[t]:
|
||||
if d == define:
|
||||
found = True
|
||||
|
||||
if not found:
|
||||
print(f"{define:<{PADDING}}: missing env.h entry")
|
||||
+1809
File diff suppressed because it is too large.
Load diff
Vendored
+71
@@ -0,0 +1,71 @@
|
||||
/* origin: FreeBSD /usr/src/lib/msun/src/k_cos.c */
|
||||
/*
|
||||
* ====================================================
|
||||
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
||||
*
|
||||
* Developed at SunSoft, a Sun Microsystems, Inc. business.
|
||||
* Permission to use, copy, modify, and distribute this
|
||||
* software is freely granted, provided that this notice
|
||||
* is preserved.
|
||||
* ====================================================
|
||||
*/
|
||||
/*
|
||||
* __cos( x, y )
|
||||
* kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164
|
||||
* Input x is assumed to be bounded by ~pi/4 in magnitude.
|
||||
* Input y is the tail of x.
|
||||
*
|
||||
* Algorithm
|
||||
* 1. Since cos(-x) = cos(x), we need only to consider positive x.
|
||||
* 2. if x < 2^-27 (hx<0x3e400000 0), return 1 with inexact if x!=0.
|
||||
* 3. cos(x) is approximated by a polynomial of degree 14 on
|
||||
* [0,pi/4]
|
||||
* 4 14
|
||||
* cos(x) ~ 1 - x*x/2 + C1*x + ... + C6*x
|
||||
* where the remez error is
|
||||
*
|
||||
* | 2 4 6 8 10 12 14 | -58
|
||||
* |cos(x)-(1-.5*x +C1*x +C2*x +C3*x +C4*x +C5*x +C6*x )| <= 2
|
||||
* | |
|
||||
*
|
||||
* 4 6 8 10 12 14
|
||||
* 4. let r = C1*x +C2*x +C3*x +C4*x +C5*x +C6*x , then
|
||||
* cos(x) ~ 1 - x*x/2 + r
|
||||
* since cos(x+y) ~ cos(x) - sin(x)*y
|
||||
* ~ cos(x) - x*y,
|
||||
* a correction term is necessary in cos(x) and hence
|
||||
* cos(x+y) = 1 - (x*x/2 - (r - x*y))
|
||||
* For better accuracy, rearrange to
|
||||
* cos(x+y) ~ w + (tmp + (r-x*y))
|
||||
* where w = 1 - x*x/2 and tmp is a tiny correction term
|
||||
* (1 - x*x/2 == w + tmp exactly in infinite precision).
|
||||
* The exactness of w + tmp in infinite precision depends on w
|
||||
* and tmp having the same precision as x. If they have extra
|
||||
* precision due to compiler bugs, then the extra precision is
|
||||
* only good provided it is retained in all terms of the final
|
||||
* expression for cos(). Retention happens in all cases tested
|
||||
* under FreeBSD, so don't pessimize things by forcibly clipping
|
||||
* any extra precision in w.
|
||||
*/
|
||||
|
||||
#include "libm.h"
|
||||
|
||||
static const double
|
||||
C1 = 4.16666666666666019037e-02, /* 0x3FA55555, 0x5555554C */
|
||||
C2 = -1.38888888888741095749e-03, /* 0xBF56C16C, 0x16C15177 */
|
||||
C3 = 2.48015872894767294178e-05, /* 0x3EFA01A0, 0x19CB1590 */
|
||||
C4 = -2.75573143513906633035e-07, /* 0xBE927E4F, 0x809C52AD */
|
||||
C5 = 2.08757232129817482790e-09, /* 0x3E21EE9E, 0xBDB4B1C4 */
|
||||
C6 = -1.13596475577881948265e-11; /* 0xBDA8FAE9, 0xBE8838D4 */
|
||||
|
||||
double __cos(double x, double y)
|
||||
{
|
||||
double_t hz,z,r,w;
|
||||
|
||||
z = x*x;
|
||||
w = z*z;
|
||||
r = z*(C1+z*(C2+z*C3)) + w*w*(C4+z*(C5+z*C6));
|
||||
hz = 0.5*z;
|
||||
w = 1.0-hz;
|
||||
return w + (((1.0-w)-hz) + (z*r-x*y));
|
||||
}
|
||||
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
#include "libm.h"
|
||||
|
||||
double __math_divzero(uint32_t sign)
|
||||
{
|
||||
return fp_barrier(sign ? -1.0 : 1.0) / 0.0;
|
||||
}
|
||||
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
#include "libm.h"
|
||||
|
||||
double __math_invalid(double x)
|
||||
{
|
||||
return (x - x) / (x - x);
|
||||
}
|
||||
Vendored
+190
@@ -0,0 +1,190 @@
|
||||
/* origin: FreeBSD /usr/src/lib/msun/src/e_rem_pio2.c */
|
||||
/*
|
||||
* ====================================================
|
||||
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
||||
*
|
||||
* Developed at SunSoft, a Sun Microsystems, Inc. business.
|
||||
* Permission to use, copy, modify, and distribute this
|
||||
* software is freely granted, provided that this notice
|
||||
* is preserved.
|
||||
* ====================================================
|
||||
*
|
||||
* Optimized by Bruce D. Evans.
|
||||
*/
|
||||
/* __rem_pio2(x,y)
|
||||
*
|
||||
* return the remainder of x rem pi/2 in y[0]+y[1]
|
||||
* use __rem_pio2_large() for large x
|
||||
*/
|
||||
|
||||
#include "libm.h"
|
||||
|
||||
#if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1
|
||||
#define EPS DBL_EPSILON
|
||||
#elif FLT_EVAL_METHOD==2
|
||||
#define EPS LDBL_EPSILON
|
||||
#endif
|
||||
|
||||
/*
|
||||
* invpio2: 53 bits of 2/pi
|
||||
* pio2_1: first 33 bit of pi/2
|
||||
* pio2_1t: pi/2 - pio2_1
|
||||
* pio2_2: second 33 bit of pi/2
|
||||
* pio2_2t: pi/2 - (pio2_1+pio2_2)
|
||||
* pio2_3: third 33 bit of pi/2
|
||||
* pio2_3t: pi/2 - (pio2_1+pio2_2+pio2_3)
|
||||
*/
|
||||
static const double
|
||||
toint = 1.5/EPS,
|
||||
pio4 = 0x1.921fb54442d18p-1,
|
||||
invpio2 = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */
|
||||
pio2_1 = 1.57079632673412561417e+00, /* 0x3FF921FB, 0x54400000 */
|
||||
pio2_1t = 6.07710050650619224932e-11, /* 0x3DD0B461, 0x1A626331 */
|
||||
pio2_2 = 6.07710050630396597660e-11, /* 0x3DD0B461, 0x1A600000 */
|
||||
pio2_2t = 2.02226624879595063154e-21, /* 0x3BA3198A, 0x2E037073 */
|
||||
pio2_3 = 2.02226624871116645580e-21, /* 0x3BA3198A, 0x2E000000 */
|
||||
pio2_3t = 8.47842766036889956997e-32; /* 0x397B839A, 0x252049C1 */
|
||||
|
||||
/* caller must handle the case when reduction is not needed: |x| ~<= pi/4 */
|
||||
int __rem_pio2(double x, double *y)
|
||||
{
|
||||
union {double f; uint64_t i;} u = {x};
|
||||
double_t z,w,t,r,fn;
|
||||
double tx[3],ty[2];
|
||||
uint32_t ix;
|
||||
int sign, n, ex, ey, i;
|
||||
|
||||
sign = u.i>>63;
|
||||
ix = u.i>>32 & 0x7fffffff;
|
||||
if (ix <= 0x400f6a7a) { /* |x| ~<= 5pi/4 */
|
||||
if ((ix & 0xfffff) == 0x921fb) /* |x| ~= pi/2 or 2pi/2 */
|
||||
goto medium; /* cancellation -- use medium case */
|
||||
if (ix <= 0x4002d97c) { /* |x| ~<= 3pi/4 */
|
||||
if (!sign) {
|
||||
z = x - pio2_1; /* one round good to 85 bits */
|
||||
y[0] = z - pio2_1t;
|
||||
y[1] = (z-y[0]) - pio2_1t;
|
||||
return 1;
|
||||
} else {
|
||||
z = x + pio2_1;
|
||||
y[0] = z + pio2_1t;
|
||||
y[1] = (z-y[0]) + pio2_1t;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
if (!sign) {
|
||||
z = x - 2*pio2_1;
|
||||
y[0] = z - 2*pio2_1t;
|
||||
y[1] = (z-y[0]) - 2*pio2_1t;
|
||||
return 2;
|
||||
} else {
|
||||
z = x + 2*pio2_1;
|
||||
y[0] = z + 2*pio2_1t;
|
||||
y[1] = (z-y[0]) + 2*pio2_1t;
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ix <= 0x401c463b) { /* |x| ~<= 9pi/4 */
|
||||
if (ix <= 0x4015fdbc) { /* |x| ~<= 7pi/4 */
|
||||
if (ix == 0x4012d97c) /* |x| ~= 3pi/2 */
|
||||
goto medium;
|
||||
if (!sign) {
|
||||
z = x - 3*pio2_1;
|
||||
y[0] = z - 3*pio2_1t;
|
||||
y[1] = (z-y[0]) - 3*pio2_1t;
|
||||
return 3;
|
||||
} else {
|
||||
z = x + 3*pio2_1;
|
||||
y[0] = z + 3*pio2_1t;
|
||||
y[1] = (z-y[0]) + 3*pio2_1t;
|
||||
return -3;
|
||||
}
|
||||
} else {
|
||||
if (ix == 0x401921fb) /* |x| ~= 4pi/2 */
|
||||
goto medium;
|
||||
if (!sign) {
|
||||
z = x - 4*pio2_1;
|
||||
y[0] = z - 4*pio2_1t;
|
||||
y[1] = (z-y[0]) - 4*pio2_1t;
|
||||
return 4;
|
||||
} else {
|
||||
z = x + 4*pio2_1;
|
||||
y[0] = z + 4*pio2_1t;
|
||||
y[1] = (z-y[0]) + 4*pio2_1t;
|
||||
return -4;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ix < 0x413921fb) { /* |x| ~< 2^20*(pi/2), medium size */
|
||||
medium:
|
||||
/* rint(x/(pi/2)) */
|
||||
fn = rint(x * invpio2);
|
||||
n = (int32_t)fn;
|
||||
r = x - fn*pio2_1;
|
||||
w = fn*pio2_1t; /* 1st round, good to 85 bits */
|
||||
/* Matters with directed rounding. */
|
||||
if (predict_false(r - w < -pio4)) {
|
||||
n--;
|
||||
fn--;
|
||||
r = x - fn*pio2_1;
|
||||
w = fn*pio2_1t;
|
||||
} else if (predict_false(r - w > pio4)) {
|
||||
n++;
|
||||
fn++;
|
||||
r = x - fn*pio2_1;
|
||||
w = fn*pio2_1t;
|
||||
}
|
||||
y[0] = r - w;
|
||||
u.f = y[0];
|
||||
ey = u.i>>52 & 0x7ff;
|
||||
ex = ix>>20;
|
||||
if (ex - ey > 16) { /* 2nd round, good to 118 bits */
|
||||
t = r;
|
||||
w = fn*pio2_2;
|
||||
r = t - w;
|
||||
w = fn*pio2_2t - ((t-r)-w);
|
||||
y[0] = r - w;
|
||||
u.f = y[0];
|
||||
ey = u.i>>52 & 0x7ff;
|
||||
if (ex - ey > 49) { /* 3rd round, good to 151 bits, covers all cases */
|
||||
t = r;
|
||||
w = fn*pio2_3;
|
||||
r = t - w;
|
||||
w = fn*pio2_3t - ((t-r)-w);
|
||||
y[0] = r - w;
|
||||
}
|
||||
}
|
||||
y[1] = (r - y[0]) - w;
|
||||
return n;
|
||||
}
|
||||
/*
|
||||
* all other (large) arguments
|
||||
*/
|
||||
if (ix >= 0x7ff00000) { /* x is inf or NaN */
|
||||
y[0] = y[1] = x - x;
|
||||
return 0;
|
||||
}
|
||||
/* set z = scalbn(|x|,-ilogb(x)+23) */
|
||||
u.f = x;
|
||||
u.i &= (uint64_t)-1>>12;
|
||||
u.i |= (uint64_t)(0x3ff + 23)<<52;
|
||||
z = u.f;
|
||||
for (i=0; i < 2; i++) {
|
||||
tx[i] = (double)(int32_t)z;
|
||||
z = (z-tx[i])*0x1p24;
|
||||
}
|
||||
tx[i] = z;
|
||||
/* skip zero terms, first term is non-zero */
|
||||
while (tx[i] == 0.0)
|
||||
i--;
|
||||
n = __rem_pio2_large(tx,ty,(int)(ix>>20)-(0x3ff+23),i+1,1);
|
||||
if (sign) {
|
||||
y[0] = -ty[0];
|
||||
y[1] = -ty[1];
|
||||
return -n;
|
||||
}
|
||||
y[0] = ty[0];
|
||||
y[1] = ty[1];
|
||||
return n;
|
||||
}
|
||||
Vendored
+442
@@ -0,0 +1,442 @@
|
||||
/* origin: FreeBSD /usr/src/lib/msun/src/k_rem_pio2.c */
|
||||
/*
|
||||
* ====================================================
|
||||
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
||||
*
|
||||
* Developed at SunSoft, a Sun Microsystems, Inc. business.
|
||||
* Permission to use, copy, modify, and distribute this
|
||||
* software is freely granted, provided that this notice
|
||||
* is preserved.
|
||||
* ====================================================
|
||||
*/
|
||||
/*
|
||||
* __rem_pio2_large(x,y,e0,nx,prec)
|
||||
* double x[],y[]; int e0,nx,prec;
|
||||
*
|
||||
* __rem_pio2_large return the last three digits of N with
|
||||
* y = x - N*pi/2
|
||||
* so that |y| < pi/2.
|
||||
*
|
||||
* The method is to compute the integer (mod 8) and fraction parts of
|
||||
* (2/pi)*x without doing the full multiplication. In general we
|
||||
* skip the part of the product that are known to be a huge integer (
|
||||
* more accurately, = 0 mod 8 ). Thus the number of operations are
|
||||
* independent of the exponent of the input.
|
||||
*
|
||||
* (2/pi) is represented by an array of 24-bit integers in ipio2[].
|
||||
*
|
||||
* Input parameters:
|
||||
* x[] The input value (must be positive) is broken into nx
|
||||
* pieces of 24-bit integers in double precision format.
|
||||
* x[i] will be the i-th 24 bit of x. The scaled exponent
|
||||
* of x[0] is given in input parameter e0 (i.e., x[0]*2^e0
|
||||
* match x's up to 24 bits.
|
||||
*
|
||||
* Example of breaking a double positive z into x[0]+x[1]+x[2]:
|
||||
* e0 = ilogb(z)-23
|
||||
* z = scalbn(z,-e0)
|
||||
* for i = 0,1,2
|
||||
* x[i] = floor(z)
|
||||
* z = (z-x[i])*2**24
|
||||
*
|
||||
*
|
||||
* y[] ouput result in an array of double precision numbers.
|
||||
* The dimension of y[] is:
|
||||
* 24-bit precision 1
|
||||
* 53-bit precision 2
|
||||
* 64-bit precision 2
|
||||
* 113-bit precision 3
|
||||
* The actual value is the sum of them. Thus for 113-bit
|
||||
* precison, one may have to do something like:
|
||||
*
|
||||
* long double t,w,r_head, r_tail;
|
||||
* t = (long double)y[2] + (long double)y[1];
|
||||
* w = (long double)y[0];
|
||||
* r_head = t+w;
|
||||
* r_tail = w - (r_head - t);
|
||||
*
|
||||
* e0 The exponent of x[0]. Must be <= 16360 or you need to
|
||||
* expand the ipio2 table.
|
||||
*
|
||||
* nx dimension of x[]
|
||||
*
|
||||
* prec an integer indicating the precision:
|
||||
* 0 24 bits (single)
|
||||
* 1 53 bits (double)
|
||||
* 2 64 bits (extended)
|
||||
* 3 113 bits (quad)
|
||||
*
|
||||
* External function:
|
||||
* double scalbn(), floor();
|
||||
*
|
||||
*
|
||||
* Here is the description of some local variables:
|
||||
*
|
||||
* jk jk+1 is the initial number of terms of ipio2[] needed
|
||||
* in the computation. The minimum and recommended value
|
||||
* for jk is 3,4,4,6 for single, double, extended, and quad.
|
||||
* jk+1 must be 2 larger than you might expect so that our
|
||||
* recomputation test works. (Up to 24 bits in the integer
|
||||
* part (the 24 bits of it that we compute) and 23 bits in
|
||||
* the fraction part may be lost to cancelation before we
|
||||
* recompute.)
|
||||
*
|
||||
* jz local integer variable indicating the number of
|
||||
* terms of ipio2[] used.
|
||||
*
|
||||
* jx nx - 1
|
||||
*
|
||||
* jv index for pointing to the suitable ipio2[] for the
|
||||
* computation. In general, we want
|
||||
* ( 2^e0*x[0] * ipio2[jv-1]*2^(-24jv) )/8
|
||||
* is an integer. Thus
|
||||
* e0-3-24*jv >= 0 or (e0-3)/24 >= jv
|
||||
* Hence jv = max(0,(e0-3)/24).
|
||||
*
|
||||
* jp jp+1 is the number of terms in PIo2[] needed, jp = jk.
|
||||
*
|
||||
* q[] double array with integral value, representing the
|
||||
* 24-bits chunk of the product of x and 2/pi.
|
||||
*
|
||||
* q0 the corresponding exponent of q[0]. Note that the
|
||||
* exponent for q[i] would be q0-24*i.
|
||||
*
|
||||
* PIo2[] double precision array, obtained by cutting pi/2
|
||||
* into 24 bits chunks.
|
||||
*
|
||||
* f[] ipio2[] in floating point
|
||||
*
|
||||
* iq[] integer array by breaking up q[] in 24-bits chunk.
|
||||
*
|
||||
* fq[] final product of x*(2/pi) in fq[0],..,fq[jk]
|
||||
*
|
||||
* ih integer. If >0 it indicates q[] is >= 0.5, hence
|
||||
* it also indicates the *sign* of the result.
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Constants:
|
||||
* The hexadecimal values are the intended ones for the following
|
||||
* constants. The decimal values may be used, provided that the
|
||||
* compiler will convert from decimal to binary accurately enough
|
||||
* to produce the hexadecimal values shown.
|
||||
*/
|
||||
|
||||
#include "libm.h"
|
||||
|
||||
static const int init_jk[] = {3,4,4,6}; /* initial value for jk */
|
||||
|
||||
/*
|
||||
* Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi
|
||||
*
|
||||
* integer array, contains the (24*i)-th to (24*i+23)-th
|
||||
* bit of 2/pi after binary point. The corresponding
|
||||
* floating value is
|
||||
*
|
||||
* ipio2[i] * 2^(-24(i+1)).
|
||||
*
|
||||
* NB: This table must have at least (e0-3)/24 + jk terms.
|
||||
* For quad precision (e0 <= 16360, jk = 6), this is 686.
|
||||
*/
|
||||
static const int32_t ipio2[] = {
|
||||
0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62,
|
||||
0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A,
|
||||
0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129,
|
||||
0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41,
|
||||
0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8,
|
||||
0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF,
|
||||
0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5,
|
||||
0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08,
|
||||
0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3,
|
||||
0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880,
|
||||
0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B,
|
||||
|
||||
#if LDBL_MAX_EXP > 1024
|
||||
0x47C419, 0xC367CD, 0xDCE809, 0x2A8359, 0xC4768B, 0x961CA6,
|
||||
0xDDAF44, 0xD15719, 0x053EA5, 0xFF0705, 0x3F7E33, 0xE832C2,
|
||||
0xDE4F98, 0x327DBB, 0xC33D26, 0xEF6B1E, 0x5EF89F, 0x3A1F35,
|
||||
0xCAF27F, 0x1D87F1, 0x21907C, 0x7C246A, 0xFA6ED5, 0x772D30,
|
||||
0x433B15, 0xC614B5, 0x9D19C3, 0xC2C4AD, 0x414D2C, 0x5D000C,
|
||||
0x467D86, 0x2D71E3, 0x9AC69B, 0x006233, 0x7CD2B4, 0x97A7B4,
|
||||
0xD55537, 0xF63ED7, 0x1810A3, 0xFC764D, 0x2A9D64, 0xABD770,
|
||||
0xF87C63, 0x57B07A, 0xE71517, 0x5649C0, 0xD9D63B, 0x3884A7,
|
||||
0xCB2324, 0x778AD6, 0x23545A, 0xB91F00, 0x1B0AF1, 0xDFCE19,
|
||||
0xFF319F, 0x6A1E66, 0x615799, 0x47FBAC, 0xD87F7E, 0xB76522,
|
||||
0x89E832, 0x60BFE6, 0xCDC4EF, 0x09366C, 0xD43F5D, 0xD7DE16,
|
||||
0xDE3B58, 0x929BDE, 0x2822D2, 0xE88628, 0x4D58E2, 0x32CAC6,
|
||||
0x16E308, 0xCB7DE0, 0x50C017, 0xA71DF3, 0x5BE018, 0x34132E,
|
||||
0x621283, 0x014883, 0x5B8EF5, 0x7FB0AD, 0xF2E91E, 0x434A48,
|
||||
0xD36710, 0xD8DDAA, 0x425FAE, 0xCE616A, 0xA4280A, 0xB499D3,
|
||||
0xF2A606, 0x7F775C, 0x83C2A3, 0x883C61, 0x78738A, 0x5A8CAF,
|
||||
0xBDD76F, 0x63A62D, 0xCBBFF4, 0xEF818D, 0x67C126, 0x45CA55,
|
||||
0x36D9CA, 0xD2A828, 0x8D61C2, 0x77C912, 0x142604, 0x9B4612,
|
||||
0xC459C4, 0x44C5C8, 0x91B24D, 0xF31700, 0xAD43D4, 0xE54929,
|
||||
0x10D5FD, 0xFCBE00, 0xCC941E, 0xEECE70, 0xF53E13, 0x80F1EC,
|
||||
0xC3E7B3, 0x28F8C7, 0x940593, 0x3E71C1, 0xB3092E, 0xF3450B,
|
||||
0x9C1288, 0x7B20AB, 0x9FB52E, 0xC29247, 0x2F327B, 0x6D550C,
|
||||
0x90A772, 0x1FE76B, 0x96CB31, 0x4A1679, 0xE27941, 0x89DFF4,
|
||||
0x9794E8, 0x84E6E2, 0x973199, 0x6BED88, 0x365F5F, 0x0EFDBB,
|
||||
0xB49A48, 0x6CA467, 0x427271, 0x325D8D, 0xB8159F, 0x09E5BC,
|
||||
0x25318D, 0x3974F7, 0x1C0530, 0x010C0D, 0x68084B, 0x58EE2C,
|
||||
0x90AA47, 0x02E774, 0x24D6BD, 0xA67DF7, 0x72486E, 0xEF169F,
|
||||
0xA6948E, 0xF691B4, 0x5153D1, 0xF20ACF, 0x339820, 0x7E4BF5,
|
||||
0x6863B2, 0x5F3EDD, 0x035D40, 0x7F8985, 0x295255, 0xC06437,
|
||||
0x10D86D, 0x324832, 0x754C5B, 0xD4714E, 0x6E5445, 0xC1090B,
|
||||
0x69F52A, 0xD56614, 0x9D0727, 0x50045D, 0xDB3BB4, 0xC576EA,
|
||||
0x17F987, 0x7D6B49, 0xBA271D, 0x296996, 0xACCCC6, 0x5414AD,
|
||||
0x6AE290, 0x89D988, 0x50722C, 0xBEA404, 0x940777, 0x7030F3,
|
||||
0x27FC00, 0xA871EA, 0x49C266, 0x3DE064, 0x83DD97, 0x973FA3,
|
||||
0xFD9443, 0x8C860D, 0xDE4131, 0x9D3992, 0x8C70DD, 0xE7B717,
|
||||
0x3BDF08, 0x2B3715, 0xA0805C, 0x93805A, 0x921110, 0xD8E80F,
|
||||
0xAF806C, 0x4BFFDB, 0x0F9038, 0x761859, 0x15A562, 0xBBCB61,
|
||||
0xB989C7, 0xBD4010, 0x04F2D2, 0x277549, 0xF6B6EB, 0xBB22DB,
|
||||
0xAA140A, 0x2F2689, 0x768364, 0x333B09, 0x1A940E, 0xAA3A51,
|
||||
0xC2A31D, 0xAEEDAF, 0x12265C, 0x4DC26D, 0x9C7A2D, 0x9756C0,
|
||||
0x833F03, 0xF6F009, 0x8C402B, 0x99316D, 0x07B439, 0x15200C,
|
||||
0x5BC3D8, 0xC492F5, 0x4BADC6, 0xA5CA4E, 0xCD37A7, 0x36A9E6,
|
||||
0x9492AB, 0x6842DD, 0xDE6319, 0xEF8C76, 0x528B68, 0x37DBFC,
|
||||
0xABA1AE, 0x3115DF, 0xA1AE00, 0xDAFB0C, 0x664D64, 0xB705ED,
|
||||
0x306529, 0xBF5657, 0x3AFF47, 0xB9F96A, 0xF3BE75, 0xDF9328,
|
||||
0x3080AB, 0xF68C66, 0x15CB04, 0x0622FA, 0x1DE4D9, 0xA4B33D,
|
||||
0x8F1B57, 0x09CD36, 0xE9424E, 0xA4BE13, 0xB52333, 0x1AAAF0,
|
||||
0xA8654F, 0xA5C1D2, 0x0F3F0B, 0xCD785B, 0x76F923, 0x048B7B,
|
||||
0x721789, 0x53A6C6, 0xE26E6F, 0x00EBEF, 0x584A9B, 0xB7DAC4,
|
||||
0xBA66AA, 0xCFCF76, 0x1D02D1, 0x2DF1B1, 0xC1998C, 0x77ADC3,
|
||||
0xDA4886, 0xA05DF7, 0xF480C6, 0x2FF0AC, 0x9AECDD, 0xBC5C3F,
|
||||
0x6DDED0, 0x1FC790, 0xB6DB2A, 0x3A25A3, 0x9AAF00, 0x9353AD,
|
||||
0x0457B6, 0xB42D29, 0x7E804B, 0xA707DA, 0x0EAA76, 0xA1597B,
|
||||
0x2A1216, 0x2DB7DC, 0xFDE5FA, 0xFEDB89, 0xFDBE89, 0x6C76E4,
|
||||
0xFCA906, 0x70803E, 0x156E85, 0xFF87FD, 0x073E28, 0x336761,
|
||||
0x86182A, 0xEABD4D, 0xAFE7B3, 0x6E6D8F, 0x396795, 0x5BBF31,
|
||||
0x48D784, 0x16DF30, 0x432DC7, 0x356125, 0xCE70C9, 0xB8CB30,
|
||||
0xFD6CBF, 0xA200A4, 0xE46C05, 0xA0DD5A, 0x476F21, 0xD21262,
|
||||
0x845CB9, 0x496170, 0xE0566B, 0x015299, 0x375550, 0xB7D51E,
|
||||
0xC4F133, 0x5F6E13, 0xE4305D, 0xA92E85, 0xC3B21D, 0x3632A1,
|
||||
0xA4B708, 0xD4B1EA, 0x21F716, 0xE4698F, 0x77FF27, 0x80030C,
|
||||
0x2D408D, 0xA0CD4F, 0x99A520, 0xD3A2B3, 0x0A5D2F, 0x42F9B4,
|
||||
0xCBDA11, 0xD0BE7D, 0xC1DB9B, 0xBD17AB, 0x81A2CA, 0x5C6A08,
|
||||
0x17552E, 0x550027, 0xF0147F, 0x8607E1, 0x640B14, 0x8D4196,
|
||||
0xDEBE87, 0x2AFDDA, 0xB6256B, 0x34897B, 0xFEF305, 0x9EBFB9,
|
||||
0x4F6A68, 0xA82A4A, 0x5AC44F, 0xBCF82D, 0x985AD7, 0x95C7F4,
|
||||
0x8D4D0D, 0xA63A20, 0x5F57A4, 0xB13F14, 0x953880, 0x0120CC,
|
||||
0x86DD71, 0xB6DEC9, 0xF560BF, 0x11654D, 0x6B0701, 0xACB08C,
|
||||
0xD0C0B2, 0x485551, 0x0EFB1E, 0xC37295, 0x3B06A3, 0x3540C0,
|
||||
0x7BDC06, 0xCC45E0, 0xFA294E, 0xC8CAD6, 0x41F3E8, 0xDE647C,
|
||||
0xD8649B, 0x31BED9, 0xC397A4, 0xD45877, 0xC5E369, 0x13DAF0,
|
||||
0x3C3ABA, 0x461846, 0x5F7555, 0xF5BDD2, 0xC6926E, 0x5D2EAC,
|
||||
0xED440E, 0x423E1C, 0x87C461, 0xE9FD29, 0xF3D6E7, 0xCA7C22,
|
||||
0x35916F, 0xC5E008, 0x8DD7FF, 0xE26A6E, 0xC6FDB0, 0xC10893,
|
||||
0x745D7C, 0xB2AD6B, 0x9D6ECD, 0x7B723E, 0x6A11C6, 0xA9CFF7,
|
||||
0xDF7329, 0xBAC9B5, 0x5100B7, 0x0DB2E2, 0x24BA74, 0x607DE5,
|
||||
0x8AD874, 0x2C150D, 0x0C1881, 0x94667E, 0x162901, 0x767A9F,
|
||||
0xBEFDFD, 0xEF4556, 0x367ED9, 0x13D9EC, 0xB9BA8B, 0xFC97C4,
|
||||
0x27A831, 0xC36EF1, 0x36C594, 0x56A8D8, 0xB5A8B4, 0x0ECCCF,
|
||||
0x2D8912, 0x34576F, 0x89562C, 0xE3CE99, 0xB920D6, 0xAA5E6B,
|
||||
0x9C2A3E, 0xCC5F11, 0x4A0BFD, 0xFBF4E1, 0x6D3B8E, 0x2C86E2,
|
||||
0x84D4E9, 0xA9B4FC, 0xD1EEEF, 0xC9352E, 0x61392F, 0x442138,
|
||||
0xC8D91B, 0x0AFC81, 0x6A4AFB, 0xD81C2F, 0x84B453, 0x8C994E,
|
||||
0xCC2254, 0xDC552A, 0xD6C6C0, 0x96190B, 0xB8701A, 0x649569,
|
||||
0x605A26, 0xEE523F, 0x0F117F, 0x11B5F4, 0xF5CBFC, 0x2DBC34,
|
||||
0xEEBC34, 0xCC5DE8, 0x605EDD, 0x9B8E67, 0xEF3392, 0xB817C9,
|
||||
0x9B5861, 0xBC57E1, 0xC68351, 0x103ED8, 0x4871DD, 0xDD1C2D,
|
||||
0xA118AF, 0x462C21, 0xD7F359, 0x987AD9, 0xC0549E, 0xFA864F,
|
||||
0xFC0656, 0xAE79E5, 0x362289, 0x22AD38, 0xDC9367, 0xAAE855,
|
||||
0x382682, 0x9BE7CA, 0xA40D51, 0xB13399, 0x0ED7A9, 0x480569,
|
||||
0xF0B265, 0xA7887F, 0x974C88, 0x36D1F9, 0xB39221, 0x4A827B,
|
||||
0x21CF98, 0xDC9F40, 0x5547DC, 0x3A74E1, 0x42EB67, 0xDF9DFE,
|
||||
0x5FD45E, 0xA4677B, 0x7AACBA, 0xA2F655, 0x23882B, 0x55BA41,
|
||||
0x086E59, 0x862A21, 0x834739, 0xE6E389, 0xD49EE5, 0x40FB49,
|
||||
0xE956FF, 0xCA0F1C, 0x8A59C5, 0x2BFA94, 0xC5C1D3, 0xCFC50F,
|
||||
0xAE5ADB, 0x86C547, 0x624385, 0x3B8621, 0x94792C, 0x876110,
|
||||
0x7B4C2A, 0x1A2C80, 0x12BF43, 0x902688, 0x893C78, 0xE4C4A8,
|
||||
0x7BDBE5, 0xC23AC4, 0xEAF426, 0x8A67F7, 0xBF920D, 0x2BA365,
|
||||
0xB1933D, 0x0B7CBD, 0xDC51A4, 0x63DD27, 0xDDE169, 0x19949A,
|
||||
0x9529A8, 0x28CE68, 0xB4ED09, 0x209F44, 0xCA984E, 0x638270,
|
||||
0x237C7E, 0x32B90F, 0x8EF5A7, 0xE75614, 0x08F121, 0x2A9DB5,
|
||||
0x4D7E6F, 0x5119A5, 0xABF9B5, 0xD6DF82, 0x61DD96, 0x023616,
|
||||
0x9F3AC4, 0xA1A283, 0x6DED72, 0x7A8D39, 0xA9B882, 0x5C326B,
|
||||
0x5B2746, 0xED3400, 0x7700D2, 0x55F4FC, 0x4D5901, 0x8071E0,
|
||||
#endif
|
||||
};
|
||||
|
||||
static const double PIo2[] = {
|
||||
1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */
|
||||
7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */
|
||||
5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */
|
||||
3.28200341580791294123e-22, /* 0x3B78CC51, 0x60000000 */
|
||||
1.27065575308067607349e-29, /* 0x39F01B83, 0x80000000 */
|
||||
1.22933308981111328932e-36, /* 0x387A2520, 0x40000000 */
|
||||
2.73370053816464559624e-44, /* 0x36E38222, 0x80000000 */
|
||||
2.16741683877804819444e-51, /* 0x3569F31D, 0x00000000 */
|
||||
};
|
||||
|
||||
int __rem_pio2_large(double *x, double *y, int e0, int nx, int prec)
|
||||
{
|
||||
int32_t jz,jx,jv,jp,jk,carry,n,iq[20],i,j,k,m,q0,ih;
|
||||
double z,fw,f[20],fq[20],q[20];
|
||||
|
||||
/* initialize jk*/
|
||||
jk = init_jk[prec];
|
||||
jp = jk;
|
||||
|
||||
/* determine jx,jv,q0, note that 3>q0 */
|
||||
jx = nx-1;
|
||||
jv = (e0-3)/24; if(jv<0) jv=0;
|
||||
q0 = e0-24*(jv+1);
|
||||
|
||||
/* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */
|
||||
j = jv-jx; m = jx+jk;
|
||||
for (i=0; i<=m; i++,j++)
|
||||
f[i] = j<0 ? 0.0 : (double)ipio2[j];
|
||||
|
||||
/* compute q[0],q[1],...q[jk] */
|
||||
for (i=0; i<=jk; i++) {
|
||||
for (j=0,fw=0.0; j<=jx; j++)
|
||||
fw += x[j]*f[jx+i-j];
|
||||
q[i] = fw;
|
||||
}
|
||||
|
||||
jz = jk;
|
||||
recompute:
|
||||
/* distill q[] into iq[] reversingly */
|
||||
for (i=0,j=jz,z=q[jz]; j>0; i++,j--) {
|
||||
fw = (double)(int32_t)(0x1p-24*z);
|
||||
iq[i] = (int32_t)(z - 0x1p24*fw);
|
||||
z = q[j-1]+fw;
|
||||
}
|
||||
|
||||
/* compute n */
|
||||
z = scalbn(z,q0); /* actual value of z */
|
||||
z -= 8.0*floor(z*0.125); /* trim off integer >= 8 */
|
||||
n = (int32_t)z;
|
||||
z -= (double)n;
|
||||
ih = 0;
|
||||
if (q0 > 0) { /* need iq[jz-1] to determine n */
|
||||
i = iq[jz-1]>>(24-q0); n += i;
|
||||
iq[jz-1] -= i<<(24-q0);
|
||||
ih = iq[jz-1]>>(23-q0);
|
||||
}
|
||||
else if (q0 == 0) ih = iq[jz-1]>>23;
|
||||
else if (z >= 0.5) ih = 2;
|
||||
|
||||
if (ih > 0) { /* q > 0.5 */
|
||||
n += 1; carry = 0;
|
||||
for (i=0; i<jz; i++) { /* compute 1-q */
|
||||
j = iq[i];
|
||||
if (carry == 0) {
|
||||
if (j != 0) {
|
||||
carry = 1;
|
||||
iq[i] = 0x1000000 - j;
|
||||
}
|
||||
} else
|
||||
iq[i] = 0xffffff - j;
|
||||
}
|
||||
if (q0 > 0) { /* rare case: chance is 1 in 12 */
|
||||
switch(q0) {
|
||||
case 1:
|
||||
iq[jz-1] &= 0x7fffff; break;
|
||||
case 2:
|
||||
iq[jz-1] &= 0x3fffff; break;
|
||||
}
|
||||
}
|
||||
if (ih == 2) {
|
||||
z = 1.0 - z;
|
||||
if (carry != 0)
|
||||
z -= scalbn(1.0,q0);
|
||||
}
|
||||
}
|
||||
|
||||
/* check if recomputation is needed */
|
||||
if (z == 0.0) {
|
||||
j = 0;
|
||||
for (i=jz-1; i>=jk; i--) j |= iq[i];
|
||||
if (j == 0) { /* need recomputation */
|
||||
for (k=1; iq[jk-k]==0; k++); /* k = no. of terms needed */
|
||||
|
||||
for (i=jz+1; i<=jz+k; i++) { /* add q[jz+1] to q[jz+k] */
|
||||
f[jx+i] = (double)ipio2[jv+i];
|
||||
for (j=0,fw=0.0; j<=jx; j++)
|
||||
fw += x[j]*f[jx+i-j];
|
||||
q[i] = fw;
|
||||
}
|
||||
jz += k;
|
||||
goto recompute;
|
||||
}
|
||||
}
|
||||
|
||||
/* chop off zero terms */
|
||||
if (z == 0.0) {
|
||||
jz -= 1;
|
||||
q0 -= 24;
|
||||
while (iq[jz] == 0) {
|
||||
jz--;
|
||||
q0 -= 24;
|
||||
}
|
||||
} else { /* break z into 24-bit if necessary */
|
||||
z = scalbn(z,-q0);
|
||||
if (z >= 0x1p24) {
|
||||
fw = (double)(int32_t)(0x1p-24*z);
|
||||
iq[jz] = (int32_t)(z - 0x1p24*fw);
|
||||
jz += 1;
|
||||
q0 += 24;
|
||||
iq[jz] = (int32_t)fw;
|
||||
} else
|
||||
iq[jz] = (int32_t)z;
|
||||
}
|
||||
|
||||
/* convert integer "bit" chunk to floating-point value */
|
||||
fw = scalbn(1.0,q0);
|
||||
for (i=jz; i>=0; i--) {
|
||||
q[i] = fw*(double)iq[i];
|
||||
fw *= 0x1p-24;
|
||||
}
|
||||
|
||||
/* compute PIo2[0,...,jp]*q[jz,...,0] */
|
||||
for(i=jz; i>=0; i--) {
|
||||
for (fw=0.0,k=0; k<=jp && k<=jz-i; k++)
|
||||
fw += PIo2[k]*q[i+k];
|
||||
fq[jz-i] = fw;
|
||||
}
|
||||
|
||||
/* compress fq[] into y[] */
|
||||
switch(prec) {
|
||||
case 0:
|
||||
fw = 0.0;
|
||||
for (i=jz; i>=0; i--)
|
||||
fw += fq[i];
|
||||
y[0] = ih==0 ? fw : -fw;
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
fw = 0.0;
|
||||
for (i=jz; i>=0; i--)
|
||||
fw += fq[i];
|
||||
// TODO: drop excess precision here once double_t is used
|
||||
fw = (double)fw;
|
||||
y[0] = ih==0 ? fw : -fw;
|
||||
fw = fq[0]-fw;
|
||||
for (i=1; i<=jz; i++)
|
||||
fw += fq[i];
|
||||
y[1] = ih==0 ? fw : -fw;
|
||||
break;
|
||||
case 3: /* painful */
|
||||
for (i=jz; i>0; i--) {
|
||||
fw = fq[i-1]+fq[i];
|
||||
fq[i] += fq[i-1]-fw;
|
||||
fq[i-1] = fw;
|
||||
}
|
||||
for (i=jz; i>1; i--) {
|
||||
fw = fq[i-1]+fq[i];
|
||||
fq[i] += fq[i-1]-fw;
|
||||
fq[i-1] = fw;
|
||||
}
|
||||
for (fw=0.0,i=jz; i>=2; i--)
|
||||
fw += fq[i];
|
||||
if (ih==0) {
|
||||
y[0] = fq[0]; y[1] = fq[1]; y[2] = fw;
|
||||
} else {
|
||||
y[0] = -fq[0]; y[1] = -fq[1]; y[2] = -fw;
|
||||
}
|
||||
}
|
||||
return n&7;
|
||||
}
|
||||
Vendored
+64
@@ -0,0 +1,64 @@
|
||||
/* origin: FreeBSD /usr/src/lib/msun/src/k_sin.c */
|
||||
/*
|
||||
* ====================================================
|
||||
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
||||
*
|
||||
* Developed at SunSoft, a Sun Microsystems, Inc. business.
|
||||
* Permission to use, copy, modify, and distribute this
|
||||
* software is freely granted, provided that this notice
|
||||
* is preserved.
|
||||
* ====================================================
|
||||
*/
|
||||
/* __sin( x, y, iy)
|
||||
* kernel sin function on ~[-pi/4, pi/4] (except on -0), pi/4 ~ 0.7854
|
||||
* Input x is assumed to be bounded by ~pi/4 in magnitude.
|
||||
* Input y is the tail of x.
|
||||
* Input iy indicates whether y is 0. (if iy=0, y assume to be 0).
|
||||
*
|
||||
* Algorithm
|
||||
* 1. Since sin(-x) = -sin(x), we need only to consider positive x.
|
||||
* 2. Callers must return sin(-0) = -0 without calling here since our
|
||||
* odd polynomial is not evaluated in a way that preserves -0.
|
||||
* Callers may do the optimization sin(x) ~ x for tiny x.
|
||||
* 3. sin(x) is approximated by a polynomial of degree 13 on
|
||||
* [0,pi/4]
|
||||
* 3 13
|
||||
* sin(x) ~ x + S1*x + ... + S6*x
|
||||
* where
|
||||
*
|
||||
* |sin(x) 2 4 6 8 10 12 | -58
|
||||
* |----- - (1+S1*x +S2*x +S3*x +S4*x +S5*x +S6*x )| <= 2
|
||||
* | x |
|
||||
*
|
||||
* 4. sin(x+y) = sin(x) + sin'(x')*y
|
||||
* ~ sin(x) + (1-x*x/2)*y
|
||||
* For better accuracy, let
|
||||
* 3 2 2 2 2
|
||||
* r = x *(S2+x *(S3+x *(S4+x *(S5+x *S6))))
|
||||
* then 3 2
|
||||
* sin(x) = x + (S1*x + (x *(r-y/2)+y))
|
||||
*/
|
||||
|
||||
#include "libm.h"
|
||||
|
||||
static const double
|
||||
S1 = -1.66666666666666324348e-01, /* 0xBFC55555, 0x55555549 */
|
||||
S2 = 8.33333333332248946124e-03, /* 0x3F811111, 0x1110F8A6 */
|
||||
S3 = -1.98412698298579493134e-04, /* 0xBF2A01A0, 0x19C161D5 */
|
||||
S4 = 2.75573137070700676789e-06, /* 0x3EC71DE3, 0x57B1FE7D */
|
||||
S5 = -2.50507602534068634195e-08, /* 0xBE5AE5E6, 0x8A2B9CEB */
|
||||
S6 = 1.58969099521155010221e-10; /* 0x3DE5D93A, 0x5ACFD57C */
|
||||
|
||||
double __sin(double x, double y, int iy)
|
||||
{
|
||||
double_t z,r,v,w;
|
||||
|
||||
z = x*x;
|
||||
w = z*z;
|
||||
r = S2 + z*(S3 + z*S4) + z*w*(S5 + z*S6);
|
||||
v = z*x;
|
||||
if (iy == 0)
|
||||
return x + v*(S1 + z*r);
|
||||
else
|
||||
return x - ((z*(0.5*y - v*r) - y) - v*S1);
|
||||
}
|
||||
Vendored
+79
@@ -0,0 +1,79 @@
|
||||
/* origin: FreeBSD /usr/src/lib/msun/src/s_cos.c */
|
||||
/*
|
||||
* ====================================================
|
||||
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
||||
*
|
||||
* Developed at SunPro, a Sun Microsystems, Inc. business.
|
||||
* Permission to use, copy, modify, and distribute this
|
||||
* software is freely granted, provided that this notice
|
||||
* is preserved.
|
||||
* ====================================================
|
||||
*/
|
||||
/* cos(x)
|
||||
* Return cosine function of x.
|
||||
*
|
||||
* kernel function:
|
||||
* __sin ... sine function on [-pi/4,pi/4]
|
||||
* __cos ... cosine function on [-pi/4,pi/4]
|
||||
* __rem_pio2 ... argument reduction routine
|
||||
*
|
||||
* Method.
|
||||
* Let S,C and T denote the sin, cos and tan respectively on
|
||||
* [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2
|
||||
* in [-pi/4 , +pi/4], and let n = k mod 4.
|
||||
* We have
|
||||
*
|
||||
* n sin(x) cos(x) tan(x)
|
||||
* ----------------------------------------------------------
|
||||
* 0 S C T
|
||||
* 1 C -S -1/T
|
||||
* 2 -S -C T
|
||||
* 3 -C S -1/T
|
||||
* ----------------------------------------------------------
|
||||
*
|
||||
* Special cases:
|
||||
* Let trig be any of sin, cos, or tan.
|
||||
* trig(+-INF) is NaN, with signals;
|
||||
* trig(NaN) is that NaN;
|
||||
*
|
||||
* Accuracy:
|
||||
* TRIG(x) returns trig(x) nearly rounded
|
||||
*/
|
||||
|
||||
#include "libm.h"
|
||||
|
||||
double __cdecl cos(double x)
|
||||
{
|
||||
double y[2];
|
||||
uint32_t ix;
|
||||
unsigned n;
|
||||
|
||||
GET_HIGH_WORD(ix, x);
|
||||
ix &= 0x7fffffff;
|
||||
|
||||
/* |x| ~< pi/4 */
|
||||
if (ix <= 0x3fe921fb) {
|
||||
if (ix < 0x3e46a09e) { /* |x| < 2**-27 * sqrt(2) */
|
||||
/* raise inexact if x!=0 */
|
||||
FORCE_EVAL(x + 0x1p120f);
|
||||
return 1.0;
|
||||
}
|
||||
return __cos(x, 0);
|
||||
}
|
||||
|
||||
/* cos(Inf or NaN) is NaN */
|
||||
if (isinf(x))
|
||||
return math_error(_DOMAIN, "cos", x, 0, x - x);
|
||||
if (ix >= 0x7ff00000)
|
||||
return x-x;
|
||||
|
||||
/* argument reduction */
|
||||
n = __rem_pio2(x, y);
|
||||
switch (n&3) {
|
||||
case 0: return __cos(y[0], y[1]);
|
||||
case 1: return -__sin(y[0], y[1], 1);
|
||||
case 2: return -__cos(y[0], y[1]);
|
||||
default:
|
||||
return __sin(y[0], y[1], 1);
|
||||
}
|
||||
}
|
||||
Vendored
+130
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Double-precision 2^x function.
|
||||
*
|
||||
* Copyright (c) 2018, Arm Limited.
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include "libm.h"
|
||||
#include "exp_data.h"
|
||||
|
||||
#define N (1 << EXP_TABLE_BITS)
|
||||
#define Shift __exp_data.exp2_shift
|
||||
#define T __exp_data.tab
|
||||
#define C1 __exp_data.exp2_poly[0]
|
||||
#define C2 __exp_data.exp2_poly[1]
|
||||
#define C3 __exp_data.exp2_poly[2]
|
||||
#define C4 __exp_data.exp2_poly[3]
|
||||
#define C5 __exp_data.exp2_poly[4]
|
||||
|
||||
/* Handle cases that may overflow or underflow when computing the result that
|
||||
is scale*(1+TMP) without intermediate rounding. The bit representation of
|
||||
scale is in SBITS, however it has a computed exponent that may have
|
||||
overflown into the sign bit so that needs to be adjusted before using it as
|
||||
a double. (int32_t)KI is the k used in the argument reduction and exponent
|
||||
adjustment of scale, positive k here means the result may overflow and
|
||||
negative k means the result may underflow. */
|
||||
static inline double specialcase(double_t tmp, uint64_t sbits, uint64_t ki)
|
||||
{
|
||||
double_t scale, y;
|
||||
|
||||
if ((ki & 0x80000000) == 0) {
|
||||
/* k > 0, the exponent of scale might have overflowed by 1. */
|
||||
sbits -= 1ull << 52;
|
||||
scale = asdouble(sbits);
|
||||
y = 2 * (scale + scale * tmp);
|
||||
return eval_as_double(y);
|
||||
}
|
||||
/* k < 0, need special care in the subnormal range. */
|
||||
sbits += 1022ull << 52;
|
||||
scale = asdouble(sbits);
|
||||
y = scale + scale * tmp;
|
||||
if (y < 1.0) {
|
||||
/* Round y to the right precision before scaling it into the subnormal
|
||||
range to avoid double rounding that can cause 0.5+E/2 ulp error where
|
||||
E is the worst-case ulp error outside the subnormal range. So this
|
||||
is only useful if the goal is better than 1 ulp worst-case error. */
|
||||
double_t hi, lo;
|
||||
lo = scale - y + scale * tmp;
|
||||
hi = 1.0 + y;
|
||||
lo = 1.0 - hi + y + lo;
|
||||
y = eval_as_double(hi + lo) - 1.0;
|
||||
/* Avoid -0.0 with downward rounding. */
|
||||
if (WANT_ROUNDING && y == 0.0)
|
||||
y = 0.0;
|
||||
/* The underflow exception needs to be signaled explicitly. */
|
||||
fp_force_eval(fp_barrier(0x1p-1022) * 0x1p-1022);
|
||||
}
|
||||
y = 0x1p-1022 * y;
|
||||
return eval_as_double(y);
|
||||
}
|
||||
|
||||
/* Top 12 bits of a double (sign and exponent bits). */
|
||||
static inline uint32_t top12(double x)
|
||||
{
|
||||
return asuint64(x) >> 52;
|
||||
}
|
||||
|
||||
double __cdecl exp2(double x)
|
||||
{
|
||||
uint32_t abstop;
|
||||
uint64_t ki, idx, top, sbits;
|
||||
double_t kd, r, r2, scale, tail, tmp;
|
||||
|
||||
abstop = top12(x) & 0x7ff;
|
||||
if (predict_false(abstop - top12(0x1p-54) >= top12(512.0) - top12(0x1p-54))) {
|
||||
if (abstop - top12(0x1p-54) >= 0x80000000)
|
||||
/* Avoid spurious underflow for tiny x. */
|
||||
/* Note: 0 is common input. */
|
||||
return WANT_ROUNDING ? 1.0 + x : 1.0;
|
||||
if (abstop >= top12(1024.0)) {
|
||||
if (asuint64(x) == asuint64(-INFINITY))
|
||||
return 0.0;
|
||||
if (abstop >= top12(INFINITY))
|
||||
return 1.0 + x;
|
||||
if (!(asuint64(x) >> 63)) {
|
||||
errno = ERANGE;
|
||||
return fp_barrier(DBL_MAX) * DBL_MAX;
|
||||
}
|
||||
else if (x <= -2147483648.0) {
|
||||
fp_barrier(x + 0x1p120f);
|
||||
return 0;
|
||||
}
|
||||
else if (asuint64(x) >= asuint64(-1075.0)) {
|
||||
errno = ERANGE;
|
||||
fp_barrier(x + 0x1p120f);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (2 * asuint64(x) > 2 * asuint64(928.0))
|
||||
/* Large x is special cased below. */
|
||||
abstop = 0;
|
||||
}
|
||||
|
||||
/* exp2(x) = 2^(k/N) * 2^r, with 2^r in [2^(-1/2N),2^(1/2N)]. */
|
||||
/* x = k/N + r, with int k and r in [-1/2N, 1/2N]. */
|
||||
kd = eval_as_double(x + Shift);
|
||||
ki = asuint64(kd); /* k. */
|
||||
kd -= Shift; /* k/N for int k. */
|
||||
r = x - kd;
|
||||
/* 2^(k/N) ~= scale * (1 + tail). */
|
||||
idx = 2 * (ki % N);
|
||||
top = ki << (52 - EXP_TABLE_BITS);
|
||||
tail = asdouble(T[idx]);
|
||||
/* This is only a valid scale when -1023*N < k < 1024*N. */
|
||||
sbits = T[idx + 1] + top;
|
||||
/* exp2(x) = 2^(k/N) * 2^r ~= scale + scale * (tail + 2^r - 1). */
|
||||
/* Evaluation is optimized assuming superscalar pipelined execution. */
|
||||
r2 = r * r;
|
||||
/* Without fma the worst case error is 0.5/N ulp larger. */
|
||||
/* Worst case error is less than 0.5+0.86/N+(abs poly error * 2^53) ulp. */
|
||||
tmp = tail + r * C1 + r2 * (C2 + r * C3) + r2 * r2 * (C4 + r * C5);
|
||||
if (predict_false(abstop == 0))
|
||||
return specialcase(tmp, sbits, ki);
|
||||
scale = asdouble(sbits);
|
||||
/* Note: tmp == 0 or |tmp| > 2^-65 and scale > 2^-928, so there
|
||||
is no spurious underflow here even without fma. */
|
||||
return eval_as_double(scale + scale * tmp);
|
||||
}
|
||||
Vendored
+182
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Shared data between exp, exp2 and pow.
|
||||
*
|
||||
* Copyright (c) 2018, Arm Limited.
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "exp_data.h"
|
||||
|
||||
#define N (1 << EXP_TABLE_BITS)
|
||||
|
||||
const struct exp_data __exp_data = {
|
||||
// N/ln2
|
||||
.invln2N = 0x1.71547652b82fep0 * N,
|
||||
// -ln2/N
|
||||
.negln2hiN = -0x1.62e42fefa0000p-8,
|
||||
.negln2loN = -0x1.cf79abc9e3b3ap-47,
|
||||
// Used for rounding when !TOINT_INTRINSICS
|
||||
#if EXP_USE_TOINT_NARROW
|
||||
.shift = 0x1800000000.8p0,
|
||||
#else
|
||||
.shift = 0x1.8p52,
|
||||
#endif
|
||||
// exp polynomial coefficients.
|
||||
.poly = {
|
||||
// abs error: 1.555*2^-66
|
||||
// ulp error: 0.509 (0.511 without fma)
|
||||
// if |x| < ln2/256+eps
|
||||
// abs error if |x| < ln2/256+0x1p-15: 1.09*2^-65
|
||||
// abs error if |x| < ln2/128: 1.7145*2^-56
|
||||
0x1.ffffffffffdbdp-2,
|
||||
0x1.555555555543cp-3,
|
||||
0x1.55555cf172b91p-5,
|
||||
0x1.1111167a4d017p-7,
|
||||
},
|
||||
.exp2_shift = 0x1.8p52 / N,
|
||||
// exp2 polynomial coefficients.
|
||||
.exp2_poly = {
|
||||
// abs error: 1.2195*2^-65
|
||||
// ulp error: 0.507 (0.511 without fma)
|
||||
// if |x| < 1/256
|
||||
// abs error if |x| < 1/128: 1.9941*2^-56
|
||||
0x1.62e42fefa39efp-1,
|
||||
0x1.ebfbdff82c424p-3,
|
||||
0x1.c6b08d70cf4b5p-5,
|
||||
0x1.3b2abd24650ccp-7,
|
||||
0x1.5d7e09b4e3a84p-10,
|
||||
},
|
||||
// 2^(k/N) ~= H[k]*(1 + T[k]) for int k in [0,N)
|
||||
// tab[2*k] = asuint64(T[k])
|
||||
// tab[2*k+1] = asuint64(H[k]) - (k << 52)/N
|
||||
.tab = {
|
||||
0x0, 0x3ff0000000000000,
|
||||
0x3c9b3b4f1a88bf6e, 0x3feff63da9fb3335,
|
||||
0xbc7160139cd8dc5d, 0x3fefec9a3e778061,
|
||||
0xbc905e7a108766d1, 0x3fefe315e86e7f85,
|
||||
0x3c8cd2523567f613, 0x3fefd9b0d3158574,
|
||||
0xbc8bce8023f98efa, 0x3fefd06b29ddf6de,
|
||||
0x3c60f74e61e6c861, 0x3fefc74518759bc8,
|
||||
0x3c90a3e45b33d399, 0x3fefbe3ecac6f383,
|
||||
0x3c979aa65d837b6d, 0x3fefb5586cf9890f,
|
||||
0x3c8eb51a92fdeffc, 0x3fefac922b7247f7,
|
||||
0x3c3ebe3d702f9cd1, 0x3fefa3ec32d3d1a2,
|
||||
0xbc6a033489906e0b, 0x3fef9b66affed31b,
|
||||
0xbc9556522a2fbd0e, 0x3fef9301d0125b51,
|
||||
0xbc5080ef8c4eea55, 0x3fef8abdc06c31cc,
|
||||
0xbc91c923b9d5f416, 0x3fef829aaea92de0,
|
||||
0x3c80d3e3e95c55af, 0x3fef7a98c8a58e51,
|
||||
0xbc801b15eaa59348, 0x3fef72b83c7d517b,
|
||||
0xbc8f1ff055de323d, 0x3fef6af9388c8dea,
|
||||
0x3c8b898c3f1353bf, 0x3fef635beb6fcb75,
|
||||
0xbc96d99c7611eb26, 0x3fef5be084045cd4,
|
||||
0x3c9aecf73e3a2f60, 0x3fef54873168b9aa,
|
||||
0xbc8fe782cb86389d, 0x3fef4d5022fcd91d,
|
||||
0x3c8a6f4144a6c38d, 0x3fef463b88628cd6,
|
||||
0x3c807a05b0e4047d, 0x3fef3f49917ddc96,
|
||||
0x3c968efde3a8a894, 0x3fef387a6e756238,
|
||||
0x3c875e18f274487d, 0x3fef31ce4fb2a63f,
|
||||
0x3c80472b981fe7f2, 0x3fef2b4565e27cdd,
|
||||
0xbc96b87b3f71085e, 0x3fef24dfe1f56381,
|
||||
0x3c82f7e16d09ab31, 0x3fef1e9df51fdee1,
|
||||
0xbc3d219b1a6fbffa, 0x3fef187fd0dad990,
|
||||
0x3c8b3782720c0ab4, 0x3fef1285a6e4030b,
|
||||
0x3c6e149289cecb8f, 0x3fef0cafa93e2f56,
|
||||
0x3c834d754db0abb6, 0x3fef06fe0a31b715,
|
||||
0x3c864201e2ac744c, 0x3fef0170fc4cd831,
|
||||
0x3c8fdd395dd3f84a, 0x3feefc08b26416ff,
|
||||
0xbc86a3803b8e5b04, 0x3feef6c55f929ff1,
|
||||
0xbc924aedcc4b5068, 0x3feef1a7373aa9cb,
|
||||
0xbc9907f81b512d8e, 0x3feeecae6d05d866,
|
||||
0xbc71d1e83e9436d2, 0x3feee7db34e59ff7,
|
||||
0xbc991919b3ce1b15, 0x3feee32dc313a8e5,
|
||||
0x3c859f48a72a4c6d, 0x3feedea64c123422,
|
||||
0xbc9312607a28698a, 0x3feeda4504ac801c,
|
||||
0xbc58a78f4817895b, 0x3feed60a21f72e2a,
|
||||
0xbc7c2c9b67499a1b, 0x3feed1f5d950a897,
|
||||
0x3c4363ed60c2ac11, 0x3feece086061892d,
|
||||
0x3c9666093b0664ef, 0x3feeca41ed1d0057,
|
||||
0x3c6ecce1daa10379, 0x3feec6a2b5c13cd0,
|
||||
0x3c93ff8e3f0f1230, 0x3feec32af0d7d3de,
|
||||
0x3c7690cebb7aafb0, 0x3feebfdad5362a27,
|
||||
0x3c931dbdeb54e077, 0x3feebcb299fddd0d,
|
||||
0xbc8f94340071a38e, 0x3feeb9b2769d2ca7,
|
||||
0xbc87deccdc93a349, 0x3feeb6daa2cf6642,
|
||||
0xbc78dec6bd0f385f, 0x3feeb42b569d4f82,
|
||||
0xbc861246ec7b5cf6, 0x3feeb1a4ca5d920f,
|
||||
0x3c93350518fdd78e, 0x3feeaf4736b527da,
|
||||
0x3c7b98b72f8a9b05, 0x3feead12d497c7fd,
|
||||
0x3c9063e1e21c5409, 0x3feeab07dd485429,
|
||||
0x3c34c7855019c6ea, 0x3feea9268a5946b7,
|
||||
0x3c9432e62b64c035, 0x3feea76f15ad2148,
|
||||
0xbc8ce44a6199769f, 0x3feea5e1b976dc09,
|
||||
0xbc8c33c53bef4da8, 0x3feea47eb03a5585,
|
||||
0xbc845378892be9ae, 0x3feea34634ccc320,
|
||||
0xbc93cedd78565858, 0x3feea23882552225,
|
||||
0x3c5710aa807e1964, 0x3feea155d44ca973,
|
||||
0xbc93b3efbf5e2228, 0x3feea09e667f3bcd,
|
||||
0xbc6a12ad8734b982, 0x3feea012750bdabf,
|
||||
0xbc6367efb86da9ee, 0x3fee9fb23c651a2f,
|
||||
0xbc80dc3d54e08851, 0x3fee9f7df9519484,
|
||||
0xbc781f647e5a3ecf, 0x3fee9f75e8ec5f74,
|
||||
0xbc86ee4ac08b7db0, 0x3fee9f9a48a58174,
|
||||
0xbc8619321e55e68a, 0x3fee9feb564267c9,
|
||||
0x3c909ccb5e09d4d3, 0x3feea0694fde5d3f,
|
||||
0xbc7b32dcb94da51d, 0x3feea11473eb0187,
|
||||
0x3c94ecfd5467c06b, 0x3feea1ed0130c132,
|
||||
0x3c65ebe1abd66c55, 0x3feea2f336cf4e62,
|
||||
0xbc88a1c52fb3cf42, 0x3feea427543e1a12,
|
||||
0xbc9369b6f13b3734, 0x3feea589994cce13,
|
||||
0xbc805e843a19ff1e, 0x3feea71a4623c7ad,
|
||||
0xbc94d450d872576e, 0x3feea8d99b4492ed,
|
||||
0x3c90ad675b0e8a00, 0x3feeaac7d98a6699,
|
||||
0x3c8db72fc1f0eab4, 0x3feeace5422aa0db,
|
||||
0xbc65b6609cc5e7ff, 0x3feeaf3216b5448c,
|
||||
0x3c7bf68359f35f44, 0x3feeb1ae99157736,
|
||||
0xbc93091fa71e3d83, 0x3feeb45b0b91ffc6,
|
||||
0xbc5da9b88b6c1e29, 0x3feeb737b0cdc5e5,
|
||||
0xbc6c23f97c90b959, 0x3feeba44cbc8520f,
|
||||
0xbc92434322f4f9aa, 0x3feebd829fde4e50,
|
||||
0xbc85ca6cd7668e4b, 0x3feec0f170ca07ba,
|
||||
0x3c71affc2b91ce27, 0x3feec49182a3f090,
|
||||
0x3c6dd235e10a73bb, 0x3feec86319e32323,
|
||||
0xbc87c50422622263, 0x3feecc667b5de565,
|
||||
0x3c8b1c86e3e231d5, 0x3feed09bec4a2d33,
|
||||
0xbc91bbd1d3bcbb15, 0x3feed503b23e255d,
|
||||
0x3c90cc319cee31d2, 0x3feed99e1330b358,
|
||||
0x3c8469846e735ab3, 0x3feede6b5579fdbf,
|
||||
0xbc82dfcd978e9db4, 0x3feee36bbfd3f37a,
|
||||
0x3c8c1a7792cb3387, 0x3feee89f995ad3ad,
|
||||
0xbc907b8f4ad1d9fa, 0x3feeee07298db666,
|
||||
0xbc55c3d956dcaeba, 0x3feef3a2b84f15fb,
|
||||
0xbc90a40e3da6f640, 0x3feef9728de5593a,
|
||||
0xbc68d6f438ad9334, 0x3feeff76f2fb5e47,
|
||||
0xbc91eee26b588a35, 0x3fef05b030a1064a,
|
||||
0x3c74ffd70a5fddcd, 0x3fef0c1e904bc1d2,
|
||||
0xbc91bdfbfa9298ac, 0x3fef12c25bd71e09,
|
||||
0x3c736eae30af0cb3, 0x3fef199bdd85529c,
|
||||
0x3c8ee3325c9ffd94, 0x3fef20ab5fffd07a,
|
||||
0x3c84e08fd10959ac, 0x3fef27f12e57d14b,
|
||||
0x3c63cdaf384e1a67, 0x3fef2f6d9406e7b5,
|
||||
0x3c676b2c6c921968, 0x3fef3720dcef9069,
|
||||
0xbc808a1883ccb5d2, 0x3fef3f0b555dc3fa,
|
||||
0xbc8fad5d3ffffa6f, 0x3fef472d4a07897c,
|
||||
0xbc900dae3875a949, 0x3fef4f87080d89f2,
|
||||
0x3c74a385a63d07a7, 0x3fef5818dcfba487,
|
||||
0xbc82919e2040220f, 0x3fef60e316c98398,
|
||||
0x3c8e5a50d5c192ac, 0x3fef69e603db3285,
|
||||
0x3c843a59ac016b4b, 0x3fef7321f301b460,
|
||||
0xbc82d52107b43e1f, 0x3fef7c97337b9b5f,
|
||||
0xbc892ab93b470dc9, 0x3fef864614f5a129,
|
||||
0x3c74b604603a88d3, 0x3fef902ee78b3ff6,
|
||||
0x3c83c5ec519d7271, 0x3fef9a51fbc74c83,
|
||||
0xbc8ff7128fd391f0, 0x3fefa4afa2a490da,
|
||||
0xbc8dae98e223747d, 0x3fefaf482d8e67f1,
|
||||
0x3c8ec3bc41aa2008, 0x3fefba1bee615a27,
|
||||
0x3c842b94c3a9eb32, 0x3fefc52b376bba97,
|
||||
0x3c8a64a931d185ee, 0x3fefd0765b6e4540,
|
||||
0xbc8e37bae43be3ed, 0x3fefdbfdad9cbe14,
|
||||
0x3c77893b4d91cd9d, 0x3fefe7c1819e90d8,
|
||||
0x3c5305c14160cc89, 0x3feff3c22b8f71f1,
|
||||
},
|
||||
};
|
||||
Vendored
+26
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Arm Limited.
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
#ifndef _EXP_DATA_H
|
||||
#define _EXP_DATA_H
|
||||
|
||||
#include <features.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define EXP_TABLE_BITS 7
|
||||
#define EXP_POLY_ORDER 5
|
||||
#define EXP_USE_TOINT_NARROW 0
|
||||
#define EXP2_POLY_ORDER 5
|
||||
extern hidden const struct exp_data {
|
||||
double invln2N;
|
||||
double shift;
|
||||
double negln2hiN;
|
||||
double negln2loN;
|
||||
double poly[4]; /* Last four coefficients. */
|
||||
double exp2_shift;
|
||||
double exp2_poly[EXP2_POLY_ORDER];
|
||||
uint64_t tab[2*(1 << EXP_TABLE_BITS)];
|
||||
} __exp_data;
|
||||
|
||||
#endif
|
||||
Vendored
+202
@@ -0,0 +1,202 @@
|
||||
/* origin: FreeBSD /usr/src/lib/msun/src/s_expm1.c */
|
||||
/*
|
||||
* ====================================================
|
||||
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
||||
*
|
||||
* Developed at SunPro, a Sun Microsystems, Inc. business.
|
||||
* Permission to use, copy, modify, and distribute this
|
||||
* software is freely granted, provided that this notice
|
||||
* is preserved.
|
||||
* ====================================================
|
||||
*/
|
||||
/* expm1(x)
|
||||
* Returns exp(x)-1, the exponential of x minus 1.
|
||||
*
|
||||
* Method
|
||||
* 1. Argument reduction:
|
||||
* Given x, find r and integer k such that
|
||||
*
|
||||
* x = k*ln2 + r, |r| <= 0.5*ln2 ~ 0.34658
|
||||
*
|
||||
* Here a correction term c will be computed to compensate
|
||||
* the error in r when rounded to a floating-point number.
|
||||
*
|
||||
* 2. Approximating expm1(r) by a special rational function on
|
||||
* the interval [0,0.34658]:
|
||||
* Since
|
||||
* r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 - r^4/360 + ...
|
||||
* we define R1(r*r) by
|
||||
* r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 * R1(r*r)
|
||||
* That is,
|
||||
* R1(r**2) = 6/r *((exp(r)+1)/(exp(r)-1) - 2/r)
|
||||
* = 6/r * ( 1 + 2.0*(1/(exp(r)-1) - 1/r))
|
||||
* = 1 - r^2/60 + r^4/2520 - r^6/100800 + ...
|
||||
* We use a special Remez algorithm on [0,0.347] to generate
|
||||
* a polynomial of degree 5 in r*r to approximate R1. The
|
||||
* maximum error of this polynomial approximation is bounded
|
||||
* by 2**-61. In other words,
|
||||
* R1(z) ~ 1.0 + Q1*z + Q2*z**2 + Q3*z**3 + Q4*z**4 + Q5*z**5
|
||||
* where Q1 = -1.6666666666666567384E-2,
|
||||
* Q2 = 3.9682539681370365873E-4,
|
||||
* Q3 = -9.9206344733435987357E-6,
|
||||
* Q4 = 2.5051361420808517002E-7,
|
||||
* Q5 = -6.2843505682382617102E-9;
|
||||
* z = r*r,
|
||||
* with error bounded by
|
||||
* | 5 | -61
|
||||
* | 1.0+Q1*z+...+Q5*z - R1(z) | <= 2
|
||||
* | |
|
||||
*
|
||||
* expm1(r) = exp(r)-1 is then computed by the following
|
||||
* specific way which minimize the accumulation rounding error:
|
||||
* 2 3
|
||||
* r r [ 3 - (R1 + R1*r/2) ]
|
||||
* expm1(r) = r + --- + --- * [--------------------]
|
||||
* 2 2 [ 6 - r*(3 - R1*r/2) ]
|
||||
*
|
||||
* To compensate the error in the argument reduction, we use
|
||||
* expm1(r+c) = expm1(r) + c + expm1(r)*c
|
||||
* ~ expm1(r) + c + r*c
|
||||
* Thus c+r*c will be added in as the correction terms for
|
||||
* expm1(r+c). Now rearrange the term to avoid optimization
|
||||
* screw up:
|
||||
* ( 2 2 )
|
||||
* ({ ( r [ R1 - (3 - R1*r/2) ] ) } r )
|
||||
* expm1(r+c)~r - ({r*(--- * [--------------------]-c)-c} - --- )
|
||||
* ({ ( 2 [ 6 - r*(3 - R1*r/2) ] ) } 2 )
|
||||
* ( )
|
||||
*
|
||||
* = r - E
|
||||
* 3. Scale back to obtain expm1(x):
|
||||
* From step 1, we have
|
||||
* expm1(x) = either 2^k*[expm1(r)+1] - 1
|
||||
* = or 2^k*[expm1(r) + (1-2^-k)]
|
||||
* 4. Implementation notes:
|
||||
* (A). To save one multiplication, we scale the coefficient Qi
|
||||
* to Qi*2^i, and replace z by (x^2)/2.
|
||||
* (B). To achieve maximum accuracy, we compute expm1(x) by
|
||||
* (i) if x < -56*ln2, return -1.0, (raise inexact if x!=inf)
|
||||
* (ii) if k=0, return r-E
|
||||
* (iii) if k=-1, return 0.5*(r-E)-0.5
|
||||
* (iv) if k=1 if r < -0.25, return 2*((r+0.5)- E)
|
||||
* else return 1.0+2.0*(r-E);
|
||||
* (v) if (k<-2||k>56) return 2^k(1-(E-r)) - 1 (or exp(x)-1)
|
||||
* (vi) if k <= 20, return 2^k((1-2^-k)-(E-r)), else
|
||||
* (vii) return 2^k(1-((E+2^-k)-r))
|
||||
*
|
||||
* Special cases:
|
||||
* expm1(INF) is INF, expm1(NaN) is NaN;
|
||||
* expm1(-INF) is -1, and
|
||||
* for finite argument, only expm1(0)=0 is exact.
|
||||
*
|
||||
* Accuracy:
|
||||
* according to an error analysis, the error is always less than
|
||||
* 1 ulp (unit in the last place).
|
||||
*
|
||||
* Misc. info.
|
||||
* For IEEE double
|
||||
* if x > 7.09782712893383973096e+02 then expm1(x) overflow
|
||||
*
|
||||
* Constants:
|
||||
* The hexadecimal values are the intended ones for the following
|
||||
* constants. The decimal values may be used, provided that the
|
||||
* compiler will convert from decimal to binary accurately enough
|
||||
* to produce the hexadecimal values shown.
|
||||
*/
|
||||
|
||||
#include "libm.h"
|
||||
|
||||
static const double
|
||||
o_threshold = 7.09782712893383973096e+02, /* 0x40862E42, 0xFEFA39EF */
|
||||
ln2_hi = 6.93147180369123816490e-01, /* 0x3fe62e42, 0xfee00000 */
|
||||
ln2_lo = 1.90821492927058770002e-10, /* 0x3dea39ef, 0x35793c76 */
|
||||
invln2 = 1.44269504088896338700e+00, /* 0x3ff71547, 0x652b82fe */
|
||||
/* Scaled Q's: Qn_here = 2**n * Qn_above, for R(2*z) where z = hxs = x*x/2: */
|
||||
Q1 = -3.33333333333331316428e-02, /* BFA11111 111110F4 */
|
||||
Q2 = 1.58730158725481460165e-03, /* 3F5A01A0 19FE5585 */
|
||||
Q3 = -7.93650757867487942473e-05, /* BF14CE19 9EAADBB7 */
|
||||
Q4 = 4.00821782732936239552e-06, /* 3ED0CFCA 86E65239 */
|
||||
Q5 = -2.01099218183624371326e-07; /* BE8AFDB7 6E09C32D */
|
||||
|
||||
double __cdecl expm1(double x)
|
||||
{
|
||||
double_t y,hi,lo,c,t,e,hxs,hfx,r1,twopk;
|
||||
union {double f; uint64_t i;} u = {x};
|
||||
uint32_t hx = u.i>>32 & 0x7fffffff;
|
||||
int k, sign = u.i>>63;
|
||||
|
||||
/* filter out huge and non-finite argument */
|
||||
if (hx >= 0x4043687A) { /* if |x|>=56*ln2 */
|
||||
if (isnan(x))
|
||||
return x;
|
||||
if (isinf(x))
|
||||
return sign ? -1 : x;
|
||||
if (sign)
|
||||
return math_error(_UNDERFLOW, "exp", x, 0, -1);
|
||||
if (x > o_threshold) {
|
||||
return math_error(_OVERFLOW, "exp", x, 0, x * 0x1p1023);
|
||||
}
|
||||
}
|
||||
|
||||
/* argument reduction */
|
||||
if (hx > 0x3fd62e42) { /* if |x| > 0.5 ln2 */
|
||||
if (hx < 0x3FF0A2B2) { /* and |x| < 1.5 ln2 */
|
||||
if (!sign) {
|
||||
hi = x - ln2_hi;
|
||||
lo = ln2_lo;
|
||||
k = 1;
|
||||
} else {
|
||||
hi = x + ln2_hi;
|
||||
lo = -ln2_lo;
|
||||
k = -1;
|
||||
}
|
||||
} else {
|
||||
k = invln2*x + (sign ? -0.5 : 0.5);
|
||||
t = k;
|
||||
hi = x - t*ln2_hi; /* t*ln2_hi is exact here */
|
||||
lo = t*ln2_lo;
|
||||
}
|
||||
x = hi-lo;
|
||||
c = (hi-x)-lo;
|
||||
} else if (hx < 0x3c900000) { /* |x| < 2**-54, return x */
|
||||
if (hx < 0x00100000)
|
||||
FORCE_EVAL((float)x);
|
||||
return x;
|
||||
} else
|
||||
k = 0;
|
||||
|
||||
/* x is now in primary range */
|
||||
hfx = 0.5*x;
|
||||
hxs = x*hfx;
|
||||
r1 = 1.0+hxs*(Q1+hxs*(Q2+hxs*(Q3+hxs*(Q4+hxs*Q5))));
|
||||
t = 3.0-r1*hfx;
|
||||
e = hxs*((r1-t)/(6.0 - x*t));
|
||||
if (k == 0) /* c is 0 */
|
||||
return x - (x*e-hxs);
|
||||
e = x*(e-c) - c;
|
||||
e -= hxs;
|
||||
/* exp(x) ~ 2^k (x_reduced - e + 1) */
|
||||
if (k == -1)
|
||||
return 0.5*(x-e) - 0.5;
|
||||
if (k == 1) {
|
||||
if (x < -0.25)
|
||||
return -2.0*(e-(x+0.5));
|
||||
return 1.0+2.0*(x-e);
|
||||
}
|
||||
u.i = (uint64_t)(0x3ff + k)<<52; /* 2^k */
|
||||
twopk = u.f;
|
||||
if (k < 0 || k > 56) { /* suffice to return exp(x)-1 */
|
||||
y = x - e + 1.0;
|
||||
if (k == 1024)
|
||||
y = y*2.0*0x1p1023;
|
||||
else
|
||||
y = y*twopk;
|
||||
return y - 1.0;
|
||||
}
|
||||
u.i = (uint64_t)(0x3ff - k)<<52; /* 2^-k */
|
||||
if (k < 20)
|
||||
y = (x-e+(1-u.f))*twopk;
|
||||
else
|
||||
y = (x-(e+u.f)+1)*twopk;
|
||||
return y;
|
||||
}
|
||||
Vendored
+23
@@ -0,0 +1,23 @@
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
|
||||
double __cdecl frexp(double x, int *e)
|
||||
{
|
||||
union { double d; uint64_t i; } y = { x };
|
||||
int ee = y.i>>52 & 0x7ff;
|
||||
|
||||
if (!ee) {
|
||||
if (x) {
|
||||
x = frexp(x*0x1p64, e);
|
||||
*e -= 64;
|
||||
} else *e = 0;
|
||||
return x;
|
||||
} else if (ee == 0x7ff) {
|
||||
return x;
|
||||
}
|
||||
|
||||
*e = ee - 0x3fe;
|
||||
y.i &= 0x800fffffffffffffull;
|
||||
y.i |= 0x3fe0000000000000ull;
|
||||
return y.d;
|
||||
}
|
||||
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
#ifndef FEATURES_H
|
||||
#define FEATURES_H
|
||||
|
||||
#define weak
|
||||
#define hidden
|
||||
#define weak_alias(old, new)
|
||||
|
||||
#endif
|
||||
Vendored
+282
@@ -0,0 +1,282 @@
|
||||
#ifndef _LIBM_H
|
||||
#define _LIBM_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
#include <errno.h>
|
||||
#include <features.h>
|
||||
|
||||
typedef float float_t;
|
||||
typedef double double_t;
|
||||
|
||||
hidden double math_error(int type, const char *name, double arg1, double arg2, double retval);
|
||||
|
||||
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
|
||||
#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
union ldshape {
|
||||
long double f;
|
||||
struct {
|
||||
uint64_t m;
|
||||
uint16_t se;
|
||||
} i;
|
||||
};
|
||||
#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER == __BIG_ENDIAN
|
||||
/* This is the m68k variant of 80-bit long double, and this definition only works
|
||||
* on archs where the alignment requirement of uint64_t is <= 4. */
|
||||
union ldshape {
|
||||
long double f;
|
||||
struct {
|
||||
uint16_t se;
|
||||
uint16_t pad;
|
||||
uint64_t m;
|
||||
} i;
|
||||
};
|
||||
#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
union ldshape {
|
||||
long double f;
|
||||
struct {
|
||||
uint64_t lo;
|
||||
uint32_t mid;
|
||||
uint16_t top;
|
||||
uint16_t se;
|
||||
} i;
|
||||
struct {
|
||||
uint64_t lo;
|
||||
uint64_t hi;
|
||||
} i2;
|
||||
};
|
||||
#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER == __BIG_ENDIAN
|
||||
union ldshape {
|
||||
long double f;
|
||||
struct {
|
||||
uint16_t se;
|
||||
uint16_t top;
|
||||
uint32_t mid;
|
||||
uint64_t lo;
|
||||
} i;
|
||||
struct {
|
||||
uint64_t hi;
|
||||
uint64_t lo;
|
||||
} i2;
|
||||
};
|
||||
#else
|
||||
#error Unsupported long double representation
|
||||
#endif
|
||||
|
||||
/* Support non-nearest rounding mode. */
|
||||
#define WANT_ROUNDING 1
|
||||
/* Support signaling NaNs. */
|
||||
#define WANT_SNAN 0
|
||||
|
||||
#if WANT_SNAN
|
||||
#error SNaN is unsupported
|
||||
#else
|
||||
#define issignalingf_inline(x) 0
|
||||
#define issignaling_inline(x) 0
|
||||
#endif
|
||||
|
||||
#ifndef TOINT_INTRINSICS
|
||||
#define TOINT_INTRINSICS 0
|
||||
#endif
|
||||
|
||||
#if TOINT_INTRINSICS
|
||||
/* Round x to nearest int in all rounding modes, ties have to be rounded
|
||||
consistently with converttoint so the results match. If the result
|
||||
would be outside of [-2^31, 2^31-1] then the semantics is unspecified. */
|
||||
static double_t roundtoint(double_t);
|
||||
|
||||
/* Convert x to nearest int in all rounding modes, ties have to be rounded
|
||||
consistently with roundtoint. If the result is not representible in an
|
||||
int32_t then the semantics is unspecified. */
|
||||
static int32_t converttoint(double_t);
|
||||
#endif
|
||||
|
||||
/* Helps static branch prediction so hot path can be better optimized. */
|
||||
#ifdef __GNUC__
|
||||
#define predict_true(x) __builtin_expect(!!(x), 1)
|
||||
#define predict_false(x) __builtin_expect(x, 0)
|
||||
#else
|
||||
#define predict_true(x) (x)
|
||||
#define predict_false(x) (x)
|
||||
#endif
|
||||
|
||||
/* Evaluate an expression as the specified type. With standard excess
|
||||
precision handling a type cast or assignment is enough (with
|
||||
-ffloat-store an assignment is required, in old compilers argument
|
||||
passing and return statement may not drop excess precision).
|
||||
|
||||
If compiled without -ffloat-store or -fexcess-precision=standard,
|
||||
an extra volatile qualifier here will force limiting the precision. */
|
||||
|
||||
static inline float eval_as_float(float x)
|
||||
{
|
||||
volatile float y = x;
|
||||
return y;
|
||||
}
|
||||
|
||||
static inline double eval_as_double(double x)
|
||||
{
|
||||
volatile double y = x;
|
||||
return y;
|
||||
}
|
||||
|
||||
/* fp_barrier returns its input, but limits code transformations
|
||||
as if it had a side-effect (e.g. observable io) and returned
|
||||
an arbitrary value. */
|
||||
|
||||
#ifndef fp_barrierf
|
||||
#define fp_barrierf fp_barrierf
|
||||
static inline float fp_barrierf(float x)
|
||||
{
|
||||
volatile float y = x;
|
||||
return y;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef fp_barrier
|
||||
#define fp_barrier fp_barrier
|
||||
static inline double fp_barrier(double x)
|
||||
{
|
||||
volatile double y = x;
|
||||
return y;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef fp_barrierl
|
||||
#define fp_barrierl fp_barrierl
|
||||
static inline long double fp_barrierl(long double x)
|
||||
{
|
||||
volatile long double y = x;
|
||||
return y;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* fp_force_eval ensures that the input value is computed when that's
|
||||
otherwise unused. To prevent the constant folding of the input
|
||||
expression, an additional fp_barrier may be needed or a compilation
|
||||
mode that does so (e.g. -frounding-math in gcc). Then it can be
|
||||
used to evaluate an expression for its fenv side-effects only. */
|
||||
|
||||
#ifndef fp_force_evalf
|
||||
#define fp_force_evalf fp_force_evalf
|
||||
static inline void fp_force_evalf(float x)
|
||||
{
|
||||
volatile float y;
|
||||
y = x;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef fp_force_eval
|
||||
#define fp_force_eval fp_force_eval
|
||||
static inline void fp_force_eval(double x)
|
||||
{
|
||||
volatile double y;
|
||||
y = x;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef fp_force_evall
|
||||
#define fp_force_evall fp_force_evall
|
||||
static inline void fp_force_evall(long double x)
|
||||
{
|
||||
volatile long double y;
|
||||
y = x;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define FORCE_EVAL(x) do { \
|
||||
if (sizeof(x) == sizeof(float)) { \
|
||||
fp_force_evalf(x); \
|
||||
} else if (sizeof(x) == sizeof(double)) { \
|
||||
fp_force_eval(x); \
|
||||
} else { \
|
||||
fp_force_evall(x); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define asuint(f) ((union{float _f; uint32_t _i;}){f})._i
|
||||
#define asfloat(i) ((union{uint32_t _i; float _f;}){i})._f
|
||||
#define asuint64(f) ((union{double _f; uint64_t _i;}){f})._i
|
||||
#define asdouble(i) ((union{uint64_t _i; double _f;}){i})._f
|
||||
|
||||
#define EXTRACT_WORDS(hi,lo,d) \
|
||||
do { \
|
||||
uint64_t __u = asuint64(d); \
|
||||
(hi) = __u >> 32; \
|
||||
(lo) = (uint32_t)__u; \
|
||||
} while (0)
|
||||
|
||||
#define GET_HIGH_WORD(hi,d) \
|
||||
do { \
|
||||
(hi) = asuint64(d) >> 32; \
|
||||
} while (0)
|
||||
|
||||
#define GET_LOW_WORD(lo,d) \
|
||||
do { \
|
||||
(lo) = (uint32_t)asuint64(d); \
|
||||
} while (0)
|
||||
|
||||
#define INSERT_WORDS(d,hi,lo) \
|
||||
do { \
|
||||
(d) = asdouble(((uint64_t)(hi)<<32) | (uint32_t)(lo)); \
|
||||
} while (0)
|
||||
|
||||
#define SET_HIGH_WORD(d,hi) \
|
||||
INSERT_WORDS(d, hi, (uint32_t)asuint64(d))
|
||||
|
||||
#define SET_LOW_WORD(d,lo) \
|
||||
INSERT_WORDS(d, asuint64(d)>>32, lo)
|
||||
|
||||
#define GET_FLOAT_WORD(w,d) \
|
||||
do { \
|
||||
(w) = asuint(d); \
|
||||
} while (0)
|
||||
|
||||
#define SET_FLOAT_WORD(d,w) \
|
||||
do { \
|
||||
(d) = asfloat(w); \
|
||||
} while (0)
|
||||
|
||||
hidden int __rem_pio2_large(double*,double*,int,int,int);
|
||||
|
||||
hidden int __rem_pio2(double,double*);
|
||||
hidden double __sin(double,double,int);
|
||||
hidden double __cos(double,double);
|
||||
hidden double __tan(double,double,int);
|
||||
hidden double __expo2(double,double);
|
||||
|
||||
hidden int __rem_pio2f(float,double*);
|
||||
hidden float __sindf(double);
|
||||
hidden float __cosdf(double);
|
||||
hidden float __tandf(double,int);
|
||||
hidden float __expo2f(float,float);
|
||||
|
||||
hidden int __rem_pio2l(long double, long double *);
|
||||
hidden long double __sinl(long double, long double, int);
|
||||
hidden long double __cosl(long double, long double);
|
||||
hidden long double __tanl(long double, long double, int);
|
||||
|
||||
hidden long double __polevll(long double, const long double *, int);
|
||||
hidden long double __p1evll(long double, const long double *, int);
|
||||
|
||||
extern int __signgam;
|
||||
hidden double __lgamma_r(double, int *);
|
||||
hidden float __lgammaf_r(float, int *);
|
||||
|
||||
/* error handling functions */
|
||||
hidden float __math_xflowf(uint32_t, float);
|
||||
hidden float __math_uflowf(uint32_t);
|
||||
hidden float __math_oflowf(uint32_t);
|
||||
hidden float __math_divzerof(uint32_t);
|
||||
hidden float __math_invalidf(float);
|
||||
hidden double __math_xflow(uint32_t, double);
|
||||
hidden double __math_uflow(uint32_t);
|
||||
hidden double __math_oflow(uint32_t);
|
||||
hidden double __math_divzero(uint32_t);
|
||||
hidden double __math_invalid(double);
|
||||
#if LDBL_MANT_DIG != DBL_MANT_DIG
|
||||
hidden long double __math_invalidl(long double);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
#include <math.h>
|
||||
|
||||
double __cdecl ldexp(double x, int n)
|
||||
{
|
||||
return scalbn(x, n);
|
||||
}
|
||||
Vendored
+126
@@ -0,0 +1,126 @@
|
||||
/* origin: FreeBSD /usr/src/lib/msun/src/s_log1p.c */
|
||||
/*
|
||||
* ====================================================
|
||||
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
||||
*
|
||||
* Developed at SunPro, a Sun Microsystems, Inc. business.
|
||||
* Permission to use, copy, modify, and distribute this
|
||||
* software is freely granted, provided that this notice
|
||||
* is preserved.
|
||||
* ====================================================
|
||||
*/
|
||||
/* double log1p(double x)
|
||||
* Return the natural logarithm of 1+x.
|
||||
*
|
||||
* Method :
|
||||
* 1. Argument Reduction: find k and f such that
|
||||
* 1+x = 2^k * (1+f),
|
||||
* where sqrt(2)/2 < 1+f < sqrt(2) .
|
||||
*
|
||||
* Note. If k=0, then f=x is exact. However, if k!=0, then f
|
||||
* may not be representable exactly. In that case, a correction
|
||||
* term is need. Let u=1+x rounded. Let c = (1+x)-u, then
|
||||
* log(1+x) - log(u) ~ c/u. Thus, we proceed to compute log(u),
|
||||
* and add back the correction term c/u.
|
||||
* (Note: when x > 2**53, one can simply return log(x))
|
||||
*
|
||||
* 2. Approximation of log(1+f): See log.c
|
||||
*
|
||||
* 3. Finally, log1p(x) = k*ln2 + log(1+f) + c/u. See log.c
|
||||
*
|
||||
* Special cases:
|
||||
* log1p(x) is NaN with signal if x < -1 (including -INF) ;
|
||||
* log1p(+INF) is +INF; log1p(-1) is -INF with signal;
|
||||
* log1p(NaN) is that NaN with no signal.
|
||||
*
|
||||
* Accuracy:
|
||||
* according to an error analysis, the error is always less than
|
||||
* 1 ulp (unit in the last place).
|
||||
*
|
||||
* Constants:
|
||||
* The hexadecimal values are the intended ones for the following
|
||||
* constants. The decimal values may be used, provided that the
|
||||
* compiler will convert from decimal to binary accurately enough
|
||||
* to produce the hexadecimal values shown.
|
||||
*
|
||||
* Note: Assuming log() return accurate answer, the following
|
||||
* algorithm can be used to compute log1p(x) to within a few ULP:
|
||||
*
|
||||
* u = 1+x;
|
||||
* if(u==1.0) return x ; else
|
||||
* return log(u)*(x/(u-1.0));
|
||||
*
|
||||
* See HP-15C Advanced Functions Handbook, p.193.
|
||||
*/
|
||||
|
||||
#include "libm.h"
|
||||
|
||||
static const double
|
||||
ln2_hi = 6.93147180369123816490e-01, /* 3fe62e42 fee00000 */
|
||||
ln2_lo = 1.90821492927058770002e-10, /* 3dea39ef 35793c76 */
|
||||
Lg1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */
|
||||
Lg2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */
|
||||
Lg3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */
|
||||
Lg4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */
|
||||
Lg5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */
|
||||
Lg6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */
|
||||
Lg7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */
|
||||
|
||||
double __cdecl log1p(double x)
|
||||
{
|
||||
union {double f; uint64_t i;} u = {x};
|
||||
double_t hfsq,f,c,s,z,R,w,t1,t2,dk;
|
||||
uint32_t hx,hu;
|
||||
int k;
|
||||
|
||||
hx = u.i>>32;
|
||||
k = 1;
|
||||
if (hx < 0x3fda827a || hx>>31) { /* 1+x < sqrt(2)+ */
|
||||
if (hx >= 0xbff00000) { /* x <= -1.0 */
|
||||
if (x == -1) {
|
||||
errno = ERANGE;
|
||||
return x/0.0; /* log1p(-1) = -inf */
|
||||
}
|
||||
errno = EDOM;
|
||||
return (x-x)/0.0; /* log1p(x<-1) = NaN */
|
||||
}
|
||||
if (hx<<1 < 0x3ca00000<<1) { /* |x| < 2**-53 */
|
||||
fp_barrier(x + 0x1p120f);
|
||||
/* underflow if subnormal */
|
||||
if ((hx&0x7ff00000) == 0)
|
||||
FORCE_EVAL((float)x);
|
||||
return x;
|
||||
}
|
||||
if (hx <= 0xbfd2bec4) { /* sqrt(2)/2- <= 1+x < sqrt(2)+ */
|
||||
k = 0;
|
||||
c = 0;
|
||||
f = x;
|
||||
}
|
||||
} else if (hx >= 0x7ff00000)
|
||||
return x;
|
||||
if (k) {
|
||||
u.f = 1 + x;
|
||||
hu = u.i>>32;
|
||||
hu += 0x3ff00000 - 0x3fe6a09e;
|
||||
k = (int)(hu>>20) - 0x3ff;
|
||||
/* correction term ~ log(1+x)-log(u), avoid underflow in c/u */
|
||||
if (k < 54) {
|
||||
c = k >= 2 ? 1-(u.f-x) : x-(u.f-1);
|
||||
c /= u.f;
|
||||
} else
|
||||
c = 0;
|
||||
/* reduce u into [sqrt(2)/2, sqrt(2)] */
|
||||
hu = (hu&0x000fffff) + 0x3fe6a09e;
|
||||
u.i = (uint64_t)hu<<32 | (u.i&0xffffffff);
|
||||
f = u.f - 1;
|
||||
}
|
||||
hfsq = 0.5*f*f;
|
||||
s = f/(2.0+f);
|
||||
z = s*s;
|
||||
w = z*z;
|
||||
t1 = w*(Lg2+w*(Lg4+w*Lg6));
|
||||
t2 = z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7)));
|
||||
R = t2 + t1;
|
||||
dk = k;
|
||||
return s*(hfsq+R) + (dk*ln2_lo+c) - hfsq + f + dk*ln2_hi;
|
||||
}
|
||||
Vendored
+128
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Double-precision log2(x) function.
|
||||
*
|
||||
* Copyright (c) 2018, Arm Limited.
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include "libm.h"
|
||||
#include "log2_data.h"
|
||||
|
||||
#define T __log2_data.tab
|
||||
#define T2 __log2_data.tab2
|
||||
#define B __log2_data.poly1
|
||||
#define A __log2_data.poly
|
||||
#define InvLn2hi __log2_data.invln2hi
|
||||
#define InvLn2lo __log2_data.invln2lo
|
||||
#define N (1 << LOG2_TABLE_BITS)
|
||||
#define OFF 0x3fe6000000000000
|
||||
|
||||
/* Top 16 bits of a double. */
|
||||
static inline uint32_t top16(double x)
|
||||
{
|
||||
return asuint64(x) >> 48;
|
||||
}
|
||||
|
||||
double __cdecl log2(double x)
|
||||
{
|
||||
double_t z, r, r2, r4, y, invc, logc, kd, hi, lo, t1, t2, t3, p;
|
||||
uint64_t ix, iz, tmp;
|
||||
uint32_t top;
|
||||
int k, i;
|
||||
|
||||
ix = asuint64(x);
|
||||
top = top16(x);
|
||||
#define LO asuint64(1.0 - 0x1.5b51p-5)
|
||||
#define HI asuint64(1.0 + 0x1.6ab2p-5)
|
||||
if (predict_false(ix - LO < HI - LO)) {
|
||||
/* Handle close to 1.0 inputs separately. */
|
||||
/* Fix sign of zero with downward rounding when x==1. */
|
||||
if (WANT_ROUNDING && predict_false(ix == asuint64(1.0)))
|
||||
return 0;
|
||||
r = x - 1.0;
|
||||
#if __FP_FAST_FMA
|
||||
hi = r * InvLn2hi;
|
||||
lo = r * InvLn2lo + __builtin_fma(r, InvLn2hi, -hi);
|
||||
#else
|
||||
double_t rhi, rlo;
|
||||
rhi = asdouble(asuint64(r) & -1ULL << 32);
|
||||
rlo = r - rhi;
|
||||
hi = rhi * InvLn2hi;
|
||||
lo = rlo * InvLn2hi + r * InvLn2lo;
|
||||
#endif
|
||||
r2 = r * r; /* rounding error: 0x1p-62. */
|
||||
r4 = r2 * r2;
|
||||
/* Worst-case error is less than 0.54 ULP (0.55 ULP without fma). */
|
||||
p = r2 * (B[0] + r * B[1]);
|
||||
y = hi + p;
|
||||
lo += hi - y + p;
|
||||
lo += r4 * (B[2] + r * B[3] + r2 * (B[4] + r * B[5]) +
|
||||
r4 * (B[6] + r * B[7] + r2 * (B[8] + r * B[9])));
|
||||
y += lo;
|
||||
return eval_as_double(y);
|
||||
}
|
||||
if (predict_false(top - 0x0010 >= 0x7ff0 - 0x0010)) {
|
||||
/* x < 0x1p-1022 or inf or nan. */
|
||||
if (ix * 2 == 0) {
|
||||
errno = ERANGE;
|
||||
return __math_divzero(1);
|
||||
}
|
||||
if (ix == asuint64(INFINITY)) /* log(inf) == inf. */
|
||||
return x;
|
||||
if ((top & 0x7ff0) == 0x7ff0 && (ix & 0xfffffffffffffULL))
|
||||
return x;
|
||||
if (top & 0x8000) {
|
||||
errno = EDOM;
|
||||
return __math_invalid(x);
|
||||
}
|
||||
/* x is subnormal, normalize it. */
|
||||
ix = asuint64(x * 0x1p52);
|
||||
ix -= 52ULL << 52;
|
||||
}
|
||||
|
||||
/* x = 2^k z; where z is in range [OFF,2*OFF) and exact.
|
||||
The range is split into N subintervals.
|
||||
The ith subinterval contains z and c is near its center. */
|
||||
tmp = ix - OFF;
|
||||
i = (tmp >> (52 - LOG2_TABLE_BITS)) % N;
|
||||
k = (int64_t)tmp >> 52; /* arithmetic shift */
|
||||
iz = ix - (tmp & 0xfffULL << 52);
|
||||
invc = T[i].invc;
|
||||
logc = T[i].logc;
|
||||
z = asdouble(iz);
|
||||
kd = (double_t)k;
|
||||
|
||||
/* log2(x) = log2(z/c) + log2(c) + k. */
|
||||
/* r ~= z/c - 1, |r| < 1/(2*N). */
|
||||
#if __FP_FAST_FMA
|
||||
/* rounding error: 0x1p-55/N. */
|
||||
r = __builtin_fma(z, invc, -1.0);
|
||||
t1 = r * InvLn2hi;
|
||||
t2 = r * InvLn2lo + __builtin_fma(r, InvLn2hi, -t1);
|
||||
#else
|
||||
double_t rhi, rlo;
|
||||
/* rounding error: 0x1p-55/N + 0x1p-65. */
|
||||
r = (z - T2[i].chi - T2[i].clo) * invc;
|
||||
rhi = asdouble(asuint64(r) & -1ULL << 32);
|
||||
rlo = r - rhi;
|
||||
t1 = rhi * InvLn2hi;
|
||||
t2 = rlo * InvLn2hi + r * InvLn2lo;
|
||||
#endif
|
||||
|
||||
/* hi + lo = r/ln2 + log2(c) + k. */
|
||||
t3 = kd + logc;
|
||||
hi = t3 + t1;
|
||||
lo = t3 - hi + t1 + t2;
|
||||
|
||||
/* log2(r+1) = r/ln2 + r^2*poly(r). */
|
||||
/* Evaluation is optimized assuming superscalar pipelined execution. */
|
||||
r2 = r * r; /* rounding error: 0x1p-54/N^2. */
|
||||
r4 = r2 * r2;
|
||||
/* Worst-case error if |y| > 0x1p-4: 0.547 ULP (0.550 ULP without fma).
|
||||
~ 0.5 + 2/N/ln2 + abs-poly-error*0x1p56 ULP (+ 0.003 ULP without fma). */
|
||||
p = A[0] + r * A[1] + r2 * (A[2] + r * A[3]) + r4 * (A[4] + r * A[5]);
|
||||
y = lo + r2 * p + hi;
|
||||
return eval_as_double(y);
|
||||
}
|
||||
Vendored
+201
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* Data for log2.
|
||||
*
|
||||
* Copyright (c) 2018, Arm Limited.
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "log2_data.h"
|
||||
|
||||
#define N (1 << LOG2_TABLE_BITS)
|
||||
|
||||
const struct log2_data __log2_data = {
|
||||
// First coefficient: 0x1.71547652b82fe1777d0ffda0d24p0
|
||||
.invln2hi = 0x1.7154765200000p+0,
|
||||
.invln2lo = 0x1.705fc2eefa200p-33,
|
||||
.poly1 = {
|
||||
// relative error: 0x1.2fad8188p-63
|
||||
// in -0x1.5b51p-5 0x1.6ab2p-5
|
||||
-0x1.71547652b82fep-1,
|
||||
0x1.ec709dc3a03f7p-2,
|
||||
-0x1.71547652b7c3fp-2,
|
||||
0x1.2776c50f05be4p-2,
|
||||
-0x1.ec709dd768fe5p-3,
|
||||
0x1.a61761ec4e736p-3,
|
||||
-0x1.7153fbc64a79bp-3,
|
||||
0x1.484d154f01b4ap-3,
|
||||
-0x1.289e4a72c383cp-3,
|
||||
0x1.0b32f285aee66p-3,
|
||||
},
|
||||
.poly = {
|
||||
// relative error: 0x1.a72c2bf8p-58
|
||||
// abs error: 0x1.67a552c8p-66
|
||||
// in -0x1.f45p-8 0x1.f45p-8
|
||||
-0x1.71547652b8339p-1,
|
||||
0x1.ec709dc3a04bep-2,
|
||||
-0x1.7154764702ffbp-2,
|
||||
0x1.2776c50034c48p-2,
|
||||
-0x1.ec7b328ea92bcp-3,
|
||||
0x1.a6225e117f92ep-3,
|
||||
},
|
||||
/* Algorithm:
|
||||
|
||||
x = 2^k z
|
||||
log2(x) = k + log2(c) + log2(z/c)
|
||||
log2(z/c) = poly(z/c - 1)
|
||||
|
||||
where z is in [1.6p-1; 1.6p0] which is split into N subintervals and z falls
|
||||
into the ith one, then table entries are computed as
|
||||
|
||||
tab[i].invc = 1/c
|
||||
tab[i].logc = (double)log2(c)
|
||||
tab2[i].chi = (double)c
|
||||
tab2[i].clo = (double)(c - (double)c)
|
||||
|
||||
where c is near the center of the subinterval and is chosen by trying +-2^29
|
||||
floating point invc candidates around 1/center and selecting one for which
|
||||
|
||||
1) the rounding error in 0x1.8p10 + logc is 0,
|
||||
2) the rounding error in z - chi - clo is < 0x1p-64 and
|
||||
3) the rounding error in (double)log2(c) is minimized (< 0x1p-68).
|
||||
|
||||
Note: 1) ensures that k + logc can be computed without rounding error, 2)
|
||||
ensures that z/c - 1 can be computed as (z - chi - clo)*invc with close to a
|
||||
single rounding error when there is no fast fma for z*invc - 1, 3) ensures
|
||||
that logc + poly(z/c - 1) has small error, however near x == 1 when
|
||||
|log2(x)| < 0x1p-4, this is not enough so that is special cased. */
|
||||
.tab = {
|
||||
{0x1.724286bb1acf8p+0, -0x1.1095feecdb000p-1},
|
||||
{0x1.6e1f766d2cca1p+0, -0x1.08494bd76d000p-1},
|
||||
{0x1.6a13d0e30d48ap+0, -0x1.00143aee8f800p-1},
|
||||
{0x1.661ec32d06c85p+0, -0x1.efec5360b4000p-2},
|
||||
{0x1.623fa951198f8p+0, -0x1.dfdd91ab7e000p-2},
|
||||
{0x1.5e75ba4cf026cp+0, -0x1.cffae0cc79000p-2},
|
||||
{0x1.5ac055a214fb8p+0, -0x1.c043811fda000p-2},
|
||||
{0x1.571ed0f166e1ep+0, -0x1.b0b67323ae000p-2},
|
||||
{0x1.53909590bf835p+0, -0x1.a152f5a2db000p-2},
|
||||
{0x1.5014fed61adddp+0, -0x1.9217f5af86000p-2},
|
||||
{0x1.4cab88e487bd0p+0, -0x1.8304db0719000p-2},
|
||||
{0x1.49539b4334feep+0, -0x1.74189f9a9e000p-2},
|
||||
{0x1.460cbdfafd569p+0, -0x1.6552bb5199000p-2},
|
||||
{0x1.42d664ee4b953p+0, -0x1.56b23a29b1000p-2},
|
||||
{0x1.3fb01111dd8a6p+0, -0x1.483650f5fa000p-2},
|
||||
{0x1.3c995b70c5836p+0, -0x1.39de937f6a000p-2},
|
||||
{0x1.3991c4ab6fd4ap+0, -0x1.2baa1538d6000p-2},
|
||||
{0x1.3698e0ce099b5p+0, -0x1.1d98340ca4000p-2},
|
||||
{0x1.33ae48213e7b2p+0, -0x1.0fa853a40e000p-2},
|
||||
{0x1.30d191985bdb1p+0, -0x1.01d9c32e73000p-2},
|
||||
{0x1.2e025cab271d7p+0, -0x1.e857da2fa6000p-3},
|
||||
{0x1.2b404cf13cd82p+0, -0x1.cd3c8633d8000p-3},
|
||||
{0x1.288b02c7ccb50p+0, -0x1.b26034c14a000p-3},
|
||||
{0x1.25e2263944de5p+0, -0x1.97c1c2f4fe000p-3},
|
||||
{0x1.234563d8615b1p+0, -0x1.7d6023f800000p-3},
|
||||
{0x1.20b46e33eaf38p+0, -0x1.633a71a05e000p-3},
|
||||
{0x1.1e2eefdcda3ddp+0, -0x1.494f5e9570000p-3},
|
||||
{0x1.1bb4a580b3930p+0, -0x1.2f9e424e0a000p-3},
|
||||
{0x1.19453847f2200p+0, -0x1.162595afdc000p-3},
|
||||
{0x1.16e06c0d5d73cp+0, -0x1.f9c9a75bd8000p-4},
|
||||
{0x1.1485f47b7e4c2p+0, -0x1.c7b575bf9c000p-4},
|
||||
{0x1.12358ad0085d1p+0, -0x1.960c60ff48000p-4},
|
||||
{0x1.0fef00f532227p+0, -0x1.64ce247b60000p-4},
|
||||
{0x1.0db2077d03a8fp+0, -0x1.33f78b2014000p-4},
|
||||
{0x1.0b7e6d65980d9p+0, -0x1.0387d1a42c000p-4},
|
||||
{0x1.0953efe7b408dp+0, -0x1.a6f9208b50000p-5},
|
||||
{0x1.07325cac53b83p+0, -0x1.47a954f770000p-5},
|
||||
{0x1.05197e40d1b5cp+0, -0x1.d23a8c50c0000p-6},
|
||||
{0x1.03091c1208ea2p+0, -0x1.16a2629780000p-6},
|
||||
{0x1.0101025b37e21p+0, -0x1.720f8d8e80000p-8},
|
||||
{0x1.fc07ef9caa76bp-1, 0x1.6fe53b1500000p-7},
|
||||
{0x1.f4465d3f6f184p-1, 0x1.11ccce10f8000p-5},
|
||||
{0x1.ecc079f84107fp-1, 0x1.c4dfc8c8b8000p-5},
|
||||
{0x1.e573a99975ae8p-1, 0x1.3aa321e574000p-4},
|
||||
{0x1.de5d6f0bd3de6p-1, 0x1.918a0d08b8000p-4},
|
||||
{0x1.d77b681ff38b3p-1, 0x1.e72e9da044000p-4},
|
||||
{0x1.d0cb5724de943p-1, 0x1.1dcd2507f6000p-3},
|
||||
{0x1.ca4b2dc0e7563p-1, 0x1.476ab03dea000p-3},
|
||||
{0x1.c3f8ee8d6cb51p-1, 0x1.7074377e22000p-3},
|
||||
{0x1.bdd2b4f020c4cp-1, 0x1.98ede8ba94000p-3},
|
||||
{0x1.b7d6c006015cap-1, 0x1.c0db86ad2e000p-3},
|
||||
{0x1.b20366e2e338fp-1, 0x1.e840aafcee000p-3},
|
||||
{0x1.ac57026295039p-1, 0x1.0790ab4678000p-2},
|
||||
{0x1.a6d01bc2731ddp-1, 0x1.1ac056801c000p-2},
|
||||
{0x1.a16d3bc3ff18bp-1, 0x1.2db11d4fee000p-2},
|
||||
{0x1.9c2d14967feadp-1, 0x1.406464ec58000p-2},
|
||||
{0x1.970e4f47c9902p-1, 0x1.52dbe093af000p-2},
|
||||
{0x1.920fb3982bcf2p-1, 0x1.651902050d000p-2},
|
||||
{0x1.8d30187f759f1p-1, 0x1.771d2cdeaf000p-2},
|
||||
{0x1.886e5ebb9f66dp-1, 0x1.88e9c857d9000p-2},
|
||||
{0x1.83c97b658b994p-1, 0x1.9a80155e16000p-2},
|
||||
{0x1.7f405ffc61022p-1, 0x1.abe186ed3d000p-2},
|
||||
{0x1.7ad22181415cap-1, 0x1.bd0f2aea0e000p-2},
|
||||
{0x1.767dcf99eff8cp-1, 0x1.ce0a43dbf4000p-2},
|
||||
},
|
||||
#if !__FP_FAST_FMA
|
||||
.tab2 = {
|
||||
{0x1.6200012b90a8ep-1, 0x1.904ab0644b605p-55},
|
||||
{0x1.66000045734a6p-1, 0x1.1ff9bea62f7a9p-57},
|
||||
{0x1.69fffc325f2c5p-1, 0x1.27ecfcb3c90bap-55},
|
||||
{0x1.6e00038b95a04p-1, 0x1.8ff8856739326p-55},
|
||||
{0x1.71fffe09994e3p-1, 0x1.afd40275f82b1p-55},
|
||||
{0x1.7600015590e1p-1, -0x1.2fd75b4238341p-56},
|
||||
{0x1.7a00012655bd5p-1, 0x1.808e67c242b76p-56},
|
||||
{0x1.7e0003259e9a6p-1, -0x1.208e426f622b7p-57},
|
||||
{0x1.81fffedb4b2d2p-1, -0x1.402461ea5c92fp-55},
|
||||
{0x1.860002dfafcc3p-1, 0x1.df7f4a2f29a1fp-57},
|
||||
{0x1.89ffff78c6b5p-1, -0x1.e0453094995fdp-55},
|
||||
{0x1.8e00039671566p-1, -0x1.a04f3bec77b45p-55},
|
||||
{0x1.91fffe2bf1745p-1, -0x1.7fa34400e203cp-56},
|
||||
{0x1.95fffcc5c9fd1p-1, -0x1.6ff8005a0695dp-56},
|
||||
{0x1.9a0003bba4767p-1, 0x1.0f8c4c4ec7e03p-56},
|
||||
{0x1.9dfffe7b92da5p-1, 0x1.e7fd9478c4602p-55},
|
||||
{0x1.a1fffd72efdafp-1, -0x1.a0c554dcdae7ep-57},
|
||||
{0x1.a5fffde04ff95p-1, 0x1.67da98ce9b26bp-55},
|
||||
{0x1.a9fffca5e8d2bp-1, -0x1.284c9b54c13dep-55},
|
||||
{0x1.adfffddad03eap-1, 0x1.812c8ea602e3cp-58},
|
||||
{0x1.b1ffff10d3d4dp-1, -0x1.efaddad27789cp-55},
|
||||
{0x1.b5fffce21165ap-1, 0x1.3cb1719c61237p-58},
|
||||
{0x1.b9fffd950e674p-1, 0x1.3f7d94194cep-56},
|
||||
{0x1.be000139ca8afp-1, 0x1.50ac4215d9bcp-56},
|
||||
{0x1.c20005b46df99p-1, 0x1.beea653e9c1c9p-57},
|
||||
{0x1.c600040b9f7aep-1, -0x1.c079f274a70d6p-56},
|
||||
{0x1.ca0006255fd8ap-1, -0x1.a0b4076e84c1fp-56},
|
||||
{0x1.cdfffd94c095dp-1, 0x1.8f933f99ab5d7p-55},
|
||||
{0x1.d1ffff975d6cfp-1, -0x1.82c08665fe1bep-58},
|
||||
{0x1.d5fffa2561c93p-1, -0x1.b04289bd295f3p-56},
|
||||
{0x1.d9fff9d228b0cp-1, 0x1.70251340fa236p-55},
|
||||
{0x1.de00065bc7e16p-1, -0x1.5011e16a4d80cp-56},
|
||||
{0x1.e200002f64791p-1, 0x1.9802f09ef62ep-55},
|
||||
{0x1.e600057d7a6d8p-1, -0x1.e0b75580cf7fap-56},
|
||||
{0x1.ea00027edc00cp-1, -0x1.c848309459811p-55},
|
||||
{0x1.ee0006cf5cb7cp-1, -0x1.f8027951576f4p-55},
|
||||
{0x1.f2000782b7dccp-1, -0x1.f81d97274538fp-55},
|
||||
{0x1.f6000260c450ap-1, -0x1.071002727ffdcp-59},
|
||||
{0x1.f9fffe88cd533p-1, -0x1.81bdce1fda8bp-58},
|
||||
{0x1.fdfffd50f8689p-1, 0x1.7f91acb918e6ep-55},
|
||||
{0x1.0200004292367p+0, 0x1.b7ff365324681p-54},
|
||||
{0x1.05fffe3e3d668p+0, 0x1.6fa08ddae957bp-55},
|
||||
{0x1.0a0000a85a757p+0, -0x1.7e2de80d3fb91p-58},
|
||||
{0x1.0e0001a5f3fccp+0, -0x1.1823305c5f014p-54},
|
||||
{0x1.11ffff8afbaf5p+0, -0x1.bfabb6680bac2p-55},
|
||||
{0x1.15fffe54d91adp+0, -0x1.d7f121737e7efp-54},
|
||||
{0x1.1a00011ac36e1p+0, 0x1.c000a0516f5ffp-54},
|
||||
{0x1.1e00019c84248p+0, -0x1.082fbe4da5dap-54},
|
||||
{0x1.220000ffe5e6ep+0, -0x1.8fdd04c9cfb43p-55},
|
||||
{0x1.26000269fd891p+0, 0x1.cfe2a7994d182p-55},
|
||||
{0x1.2a00029a6e6dap+0, -0x1.00273715e8bc5p-56},
|
||||
{0x1.2dfffe0293e39p+0, 0x1.b7c39dab2a6f9p-54},
|
||||
{0x1.31ffff7dcf082p+0, 0x1.df1336edc5254p-56},
|
||||
{0x1.35ffff05a8b6p+0, -0x1.e03564ccd31ebp-54},
|
||||
{0x1.3a0002e0eaeccp+0, 0x1.5f0e74bd3a477p-56},
|
||||
{0x1.3e000043bb236p+0, 0x1.c7dcb149d8833p-54},
|
||||
{0x1.4200002d187ffp+0, 0x1.e08afcf2d3d28p-56},
|
||||
{0x1.460000d387cb1p+0, 0x1.20837856599a6p-55},
|
||||
{0x1.4a00004569f89p+0, -0x1.9fa5c904fbcd2p-55},
|
||||
{0x1.4e000043543f3p+0, -0x1.81125ed175329p-56},
|
||||
{0x1.51fffcc027f0fp+0, 0x1.883d8847754dcp-54},
|
||||
{0x1.55ffffd87b36fp+0, -0x1.709e731d02807p-55},
|
||||
{0x1.59ffff21df7bap+0, 0x1.7f79f68727b02p-55},
|
||||
{0x1.5dfffebfc3481p+0, -0x1.180902e30e93ep-54},
|
||||
},
|
||||
#endif
|
||||
};
|
||||
Vendored
+28
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Arm Limited.
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
#ifndef _LOG2_DATA_H
|
||||
#define _LOG2_DATA_H
|
||||
|
||||
#include <features.h>
|
||||
|
||||
#define LOG2_TABLE_BITS 6
|
||||
#define LOG2_POLY_ORDER 7
|
||||
#define LOG2_POLY1_ORDER 11
|
||||
extern hidden const struct log2_data {
|
||||
double invln2hi;
|
||||
double invln2lo;
|
||||
double poly[LOG2_POLY_ORDER - 1];
|
||||
double poly1[LOG2_POLY1_ORDER - 1];
|
||||
struct {
|
||||
double invc, logc;
|
||||
} tab[1 << LOG2_TABLE_BITS];
|
||||
#if !__FP_FAST_FMA
|
||||
struct {
|
||||
double chi, clo;
|
||||
} tab2[1 << LOG2_TABLE_BITS];
|
||||
#endif
|
||||
} __log2_data;
|
||||
|
||||
#endif
|
||||
Vendored
+34
@@ -0,0 +1,34 @@
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include "libm.h"
|
||||
|
||||
double __cdecl scalbn(double x, int n)
|
||||
{
|
||||
union {double f; uint64_t i;} u;
|
||||
double_t y = x;
|
||||
|
||||
if (n > 1023) {
|
||||
y *= 0x1p1023;
|
||||
n -= 1023;
|
||||
if (n > 1023) {
|
||||
y *= 0x1p1023;
|
||||
n -= 1023;
|
||||
if (n > 1023)
|
||||
n = 1023;
|
||||
}
|
||||
} else if (n < -1022) {
|
||||
/* make sure final n < -53 to avoid double
|
||||
rounding in the subnormal range */
|
||||
y *= 0x1p-1022 * 0x1p53;
|
||||
n += 1022 - 53;
|
||||
if (n < -1022) {
|
||||
y *= 0x1p-1022 * 0x1p53;
|
||||
n += 1022 - 53;
|
||||
if (n < -1022)
|
||||
n = -1022;
|
||||
}
|
||||
}
|
||||
u.i = (uint64_t)(0x3ff+n)<<52;
|
||||
x = y * u.f;
|
||||
return x;
|
||||
}
|
||||
Vendored
+80
@@ -0,0 +1,80 @@
|
||||
/* origin: FreeBSD /usr/src/lib/msun/src/s_sin.c */
|
||||
/*
|
||||
* ====================================================
|
||||
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
||||
*
|
||||
* Developed at SunPro, a Sun Microsystems, Inc. business.
|
||||
* Permission to use, copy, modify, and distribute this
|
||||
* software is freely granted, provided that this notice
|
||||
* is preserved.
|
||||
* ====================================================
|
||||
*/
|
||||
/* sin(x)
|
||||
* Return sine function of x.
|
||||
*
|
||||
* kernel function:
|
||||
* __sin ... sine function on [-pi/4,pi/4]
|
||||
* __cos ... cose function on [-pi/4,pi/4]
|
||||
* __rem_pio2 ... argument reduction routine
|
||||
*
|
||||
* Method.
|
||||
* Let S,C and T denote the sin, cos and tan respectively on
|
||||
* [-PI/4, +PI/4]. Reduce the argument x to y1+y2 = x-k*pi/2
|
||||
* in [-pi/4 , +pi/4], and let n = k mod 4.
|
||||
* We have
|
||||
*
|
||||
* n sin(x) cos(x) tan(x)
|
||||
* ----------------------------------------------------------
|
||||
* 0 S C T
|
||||
* 1 C -S -1/T
|
||||
* 2 -S -C T
|
||||
* 3 -C S -1/T
|
||||
* ----------------------------------------------------------
|
||||
*
|
||||
* Special cases:
|
||||
* Let trig be any of sin, cos, or tan.
|
||||
* trig(+-INF) is NaN, with signals;
|
||||
* trig(NaN) is that NaN;
|
||||
*
|
||||
* Accuracy:
|
||||
* TRIG(x) returns trig(x) nearly rounded
|
||||
*/
|
||||
|
||||
#include "libm.h"
|
||||
|
||||
double __cdecl sin(double x)
|
||||
{
|
||||
double y[2];
|
||||
uint32_t ix;
|
||||
unsigned n;
|
||||
|
||||
/* High word of x. */
|
||||
GET_HIGH_WORD(ix, x);
|
||||
ix &= 0x7fffffff;
|
||||
|
||||
/* |x| ~< pi/4 */
|
||||
if (ix <= 0x3fe921fb) {
|
||||
if (ix < 0x3e500000) { /* |x| < 2**-26 */
|
||||
/* raise inexact if x != 0 and underflow if subnormal*/
|
||||
FORCE_EVAL(ix < 0x00100000 ? x/0x1p120f : x+0x1p120f);
|
||||
return x;
|
||||
}
|
||||
return __sin(x, 0.0, 0);
|
||||
}
|
||||
|
||||
/* sin(Inf or NaN) is NaN */
|
||||
if (isinf(x))
|
||||
return math_error(_DOMAIN, "sin", x, 0, x - x);
|
||||
if (ix >= 0x7ff00000)
|
||||
return x - x;
|
||||
|
||||
/* argument reduction needed */
|
||||
n = __rem_pio2(x, y);
|
||||
switch (n&3) {
|
||||
case 0: return __sin(y[0], y[1], 1);
|
||||
case 1: return __cos(y[0], y[1]);
|
||||
case 2: return -__sin(y[0], y[1], 1);
|
||||
default:
|
||||
return -__cos(y[0], y[1]);
|
||||
}
|
||||
}
|
||||
Vendored
+69
@@ -0,0 +1,69 @@
|
||||
/* origin: FreeBSD /usr/src/lib/msun/src/s_sin.c */
|
||||
/*
|
||||
* ====================================================
|
||||
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
|
||||
*
|
||||
* Developed at SunPro, a Sun Microsystems, Inc. business.
|
||||
* Permission to use, copy, modify, and distribute this
|
||||
* software is freely granted, provided that this notice
|
||||
* is preserved.
|
||||
* ====================================================
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include "libm.h"
|
||||
|
||||
void __cdecl sincos(double x, double *sin, double *cos)
|
||||
{
|
||||
double y[2], s, c;
|
||||
uint32_t ix;
|
||||
unsigned n;
|
||||
|
||||
GET_HIGH_WORD(ix, x);
|
||||
ix &= 0x7fffffff;
|
||||
|
||||
/* |x| ~< pi/4 */
|
||||
if (ix <= 0x3fe921fb) {
|
||||
/* if |x| < 2**-27 * sqrt(2) */
|
||||
if (ix < 0x3e46a09e) {
|
||||
/* raise inexact if x!=0 and underflow if subnormal */
|
||||
FORCE_EVAL(ix < 0x00100000 ? x/0x1p120f : x+0x1p120f);
|
||||
*sin = x;
|
||||
*cos = 1.0;
|
||||
return;
|
||||
}
|
||||
*sin = __sin(x, 0.0, 0);
|
||||
*cos = __cos(x, 0.0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* sincos(Inf or NaN) is NaN */
|
||||
if (ix >= 0x7ff00000) {
|
||||
*sin = *cos = x - x;
|
||||
return;
|
||||
}
|
||||
|
||||
/* argument reduction needed */
|
||||
n = __rem_pio2(x, y);
|
||||
s = __sin(y[0], y[1], 1);
|
||||
c = __cos(y[0], y[1]);
|
||||
switch (n&3) {
|
||||
case 0:
|
||||
*sin = s;
|
||||
*cos = c;
|
||||
break;
|
||||
case 1:
|
||||
*sin = c;
|
||||
*cos = -s;
|
||||
break;
|
||||
case 2:
|
||||
*sin = -s;
|
||||
*cos = -c;
|
||||
break;
|
||||
case 3:
|
||||
default:
|
||||
*sin = -c;
|
||||
*cos = s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Vendored
+158
@@ -0,0 +1,158 @@
|
||||
#include <stdint.h>
|
||||
#include <math.h>
|
||||
#include "libm.h"
|
||||
#include "sqrt_data.h"
|
||||
|
||||
#define FENV_SUPPORT 1
|
||||
|
||||
/* returns a*b*2^-32 - e, with error 0 <= e < 1. */
|
||||
static inline uint32_t mul32(uint32_t a, uint32_t b)
|
||||
{
|
||||
return (uint64_t)a*b >> 32;
|
||||
}
|
||||
|
||||
/* returns a*b*2^-64 - e, with error 0 <= e < 3. */
|
||||
static inline uint64_t mul64(uint64_t a, uint64_t b)
|
||||
{
|
||||
uint64_t ahi = a>>32;
|
||||
uint64_t alo = a&0xffffffff;
|
||||
uint64_t bhi = b>>32;
|
||||
uint64_t blo = b&0xffffffff;
|
||||
return ahi*bhi + (ahi*blo >> 32) + (alo*bhi >> 32);
|
||||
}
|
||||
|
||||
double __cdecl sqrt(double x)
|
||||
{
|
||||
uint64_t ix, top, m;
|
||||
|
||||
/* special case handling. */
|
||||
ix = asuint64(x);
|
||||
top = ix >> 52;
|
||||
if (predict_false(top - 0x001 >= 0x7ff - 0x001)) {
|
||||
/* x < 0x1p-1022 or inf or nan. */
|
||||
if (ix * 2 == 0)
|
||||
return x;
|
||||
if (ix == 0x7ff0000000000000)
|
||||
return x;
|
||||
if (ix > 0x7ff0000000000000)
|
||||
return math_error(_DOMAIN, "sqrt", x, 0, (x - x) / (x - x));
|
||||
/* x is subnormal, normalize it. */
|
||||
ix = asuint64(x * 0x1p52);
|
||||
top = ix >> 52;
|
||||
top -= 52;
|
||||
}
|
||||
|
||||
/* argument reduction:
|
||||
x = 4^e m; with integer e, and m in [1, 4)
|
||||
m: fixed point representation [2.62]
|
||||
2^e is the exponent part of the result. */
|
||||
int even = top & 1;
|
||||
m = (ix << 11) | 0x8000000000000000;
|
||||
if (even) m >>= 1;
|
||||
top = (top + 0x3ff) >> 1;
|
||||
|
||||
/* approximate r ~ 1/sqrt(m) and s ~ sqrt(m) when m in [1,4)
|
||||
|
||||
initial estimate:
|
||||
7bit table lookup (1bit exponent and 6bit significand).
|
||||
|
||||
iterative approximation:
|
||||
using 2 goldschmidt iterations with 32bit int arithmetics
|
||||
and a final iteration with 64bit int arithmetics.
|
||||
|
||||
details:
|
||||
|
||||
the relative error (e = r0 sqrt(m)-1) of a linear estimate
|
||||
(r0 = a m + b) is |e| < 0.085955 ~ 0x1.6p-4 at best,
|
||||
a table lookup is faster and needs one less iteration
|
||||
6 bit lookup table (128b) gives |e| < 0x1.f9p-8
|
||||
7 bit lookup table (256b) gives |e| < 0x1.fdp-9
|
||||
for single and double prec 6bit is enough but for quad
|
||||
prec 7bit is needed (or modified iterations). to avoid
|
||||
one more iteration >=13bit table would be needed (16k).
|
||||
|
||||
a newton-raphson iteration for r is
|
||||
w = r*r
|
||||
u = 3 - m*w
|
||||
r = r*u/2
|
||||
can use a goldschmidt iteration for s at the end or
|
||||
s = m*r
|
||||
|
||||
first goldschmidt iteration is
|
||||
s = m*r
|
||||
u = 3 - s*r
|
||||
r = r*u/2
|
||||
s = s*u/2
|
||||
next goldschmidt iteration is
|
||||
u = 3 - s*r
|
||||
r = r*u/2
|
||||
s = s*u/2
|
||||
and at the end r is not computed only s.
|
||||
|
||||
they use the same amount of operations and converge at the
|
||||
same quadratic rate, i.e. if
|
||||
r1 sqrt(m) - 1 = e, then
|
||||
r2 sqrt(m) - 1 = -3/2 e^2 - 1/2 e^3
|
||||
the advantage of goldschmidt is that the mul for s and r
|
||||
are independent (computed in parallel), however it is not
|
||||
"self synchronizing": it only uses the input m in the
|
||||
first iteration so rounding errors accumulate. at the end
|
||||
or when switching to larger precision arithmetics rounding
|
||||
errors dominate so the first iteration should be used.
|
||||
|
||||
the fixed point representations are
|
||||
m: 2.30 r: 0.32, s: 2.30, d: 2.30, u: 2.30, three: 2.30
|
||||
and after switching to 64 bit
|
||||
m: 2.62 r: 0.64, s: 2.62, d: 2.62, u: 2.62, three: 2.62 */
|
||||
|
||||
static const uint64_t three = 0xc0000000;
|
||||
uint64_t r, s, d, u, i;
|
||||
|
||||
i = (ix >> 46) % 128;
|
||||
r = (uint32_t)__rsqrt_tab[i] << 16;
|
||||
/* |r sqrt(m) - 1| < 0x1.fdp-9 */
|
||||
s = mul32(m>>32, r);
|
||||
/* |s/sqrt(m) - 1| < 0x1.fdp-9 */
|
||||
d = mul32(s, r);
|
||||
u = three - d;
|
||||
r = mul32(r, u) << 1;
|
||||
/* |r sqrt(m) - 1| < 0x1.7bp-16 */
|
||||
s = mul32(s, u) << 1;
|
||||
/* |s/sqrt(m) - 1| < 0x1.7bp-16 */
|
||||
d = mul32(s, r);
|
||||
u = three - d;
|
||||
r = mul32(r, u) << 1;
|
||||
/* |r sqrt(m) - 1| < 0x1.3704p-29 (measured worst-case) */
|
||||
r = r << 32;
|
||||
s = mul64(m, r);
|
||||
d = mul64(s, r);
|
||||
u = (three<<32) - d;
|
||||
s = mul64(s, u); /* repr: 3.61 */
|
||||
/* -0x1p-57 < s - sqrt(m) < 0x1.8001p-61 */
|
||||
s = (s - 2) >> 9; /* repr: 12.52 */
|
||||
/* -0x1.09p-52 < s - sqrt(m) < -0x1.fffcp-63 */
|
||||
|
||||
/* s < sqrt(m) < s + 0x1.09p-52,
|
||||
compute nearest rounded result:
|
||||
the nearest result to 52 bits is either s or s+0x1p-52,
|
||||
we can decide by comparing (2^52 s + 0.5)^2 to 2^104 m. */
|
||||
uint64_t d0, d1, d2;
|
||||
double y, t;
|
||||
d0 = (m << 42) - s*s;
|
||||
d1 = s - d0;
|
||||
d2 = d1 + s + 1;
|
||||
s += d1 >> 63;
|
||||
s &= 0x000fffffffffffff;
|
||||
s |= top << 52;
|
||||
y = asdouble(s);
|
||||
if (FENV_SUPPORT) {
|
||||
/* handle rounding modes and inexact exception:
|
||||
only (s+1)^2 == 2^42 m case is exact otherwise
|
||||
add a tiny value to cause the fenv effects. */
|
||||
uint64_t tiny = predict_false(d2==0) ? 0 : 0x0010000000000000;
|
||||
tiny |= (d1^d2) & 0x8000000000000000;
|
||||
t = asdouble(tiny);
|
||||
y = eval_as_double(y + t);
|
||||
}
|
||||
return y;
|
||||
}
|
||||
Vendored
+19
@@ -0,0 +1,19 @@
|
||||
#include "sqrt_data.h"
|
||||
const uint16_t __rsqrt_tab[128] = {
|
||||
0xb451,0xb2f0,0xb196,0xb044,0xaef9,0xadb6,0xac79,0xab43,
|
||||
0xaa14,0xa8eb,0xa7c8,0xa6aa,0xa592,0xa480,0xa373,0xa26b,
|
||||
0xa168,0xa06a,0x9f70,0x9e7b,0x9d8a,0x9c9d,0x9bb5,0x9ad1,
|
||||
0x99f0,0x9913,0x983a,0x9765,0x9693,0x95c4,0x94f8,0x9430,
|
||||
0x936b,0x92a9,0x91ea,0x912e,0x9075,0x8fbe,0x8f0a,0x8e59,
|
||||
0x8daa,0x8cfe,0x8c54,0x8bac,0x8b07,0x8a64,0x89c4,0x8925,
|
||||
0x8889,0x87ee,0x8756,0x86c0,0x862b,0x8599,0x8508,0x8479,
|
||||
0x83ec,0x8361,0x82d8,0x8250,0x81c9,0x8145,0x80c2,0x8040,
|
||||
0xff02,0xfd0e,0xfb25,0xf947,0xf773,0xf5aa,0xf3ea,0xf234,
|
||||
0xf087,0xeee3,0xed47,0xebb3,0xea27,0xe8a3,0xe727,0xe5b2,
|
||||
0xe443,0xe2dc,0xe17a,0xe020,0xdecb,0xdd7d,0xdc34,0xdaf1,
|
||||
0xd9b3,0xd87b,0xd748,0xd61a,0xd4f1,0xd3cd,0xd2ad,0xd192,
|
||||
0xd07b,0xcf69,0xce5b,0xcd51,0xcc4a,0xcb48,0xca4a,0xc94f,
|
||||
0xc858,0xc764,0xc674,0xc587,0xc49d,0xc3b7,0xc2d4,0xc1f4,
|
||||
0xc116,0xc03c,0xbf65,0xbe90,0xbdbe,0xbcef,0xbc23,0xbb59,
|
||||
0xba91,0xb9cc,0xb90a,0xb84a,0xb78c,0xb6d0,0xb617,0xb560,
|
||||
};
|
||||
Vendored
+13
@@ -0,0 +1,13 @@
|
||||
#ifndef _SQRT_DATA_H
|
||||
#define _SQRT_DATA_H
|
||||
|
||||
#include <features.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* if x in [1,2): i = (int)(64*x);
|
||||
if x in [2,4): i = (int)(32*x-64);
|
||||
__rsqrt_tab[i]*2^-16 is estimating 1/sqrt(x) with small relative error:
|
||||
|__rsqrt_tab[i]*0x1p-16*sqrt(x) - 1| < -0x1.fdp-9 < 2^-8 */
|
||||
extern hidden const uint16_t __rsqrt_tab[128];
|
||||
|
||||
#endif
|
||||
Vendored
+83
@@ -0,0 +1,83 @@
|
||||
#include <stdint.h>
|
||||
#include <math.h>
|
||||
#include "libm.h"
|
||||
#include "sqrt_data.h"
|
||||
|
||||
#define FENV_SUPPORT 1
|
||||
|
||||
static inline uint32_t mul32(uint32_t a, uint32_t b)
|
||||
{
|
||||
return (uint64_t)a*b >> 32;
|
||||
}
|
||||
|
||||
/* see sqrt.c for more detailed comments. */
|
||||
|
||||
float __cdecl sqrtf(float x)
|
||||
{
|
||||
uint32_t ix, m, m1, m0, even, ey;
|
||||
|
||||
ix = asuint(x);
|
||||
if (predict_false(ix - 0x00800000 >= 0x7f800000 - 0x00800000)) {
|
||||
/* x < 0x1p-126 or inf or nan. */
|
||||
if (ix * 2 == 0)
|
||||
return x;
|
||||
if (ix == 0x7f800000)
|
||||
return x;
|
||||
if (ix > 0x7f800000)
|
||||
return math_error(_DOMAIN, "sqrtf", x, 0, (x - x) / (x - x));
|
||||
/* x is subnormal, normalize it. */
|
||||
ix = asuint(x * 0x1p23f);
|
||||
ix -= 23 << 23;
|
||||
}
|
||||
|
||||
/* x = 4^e m; with int e and m in [1, 4). */
|
||||
even = ix & 0x00800000;
|
||||
m1 = (ix << 8) | 0x80000000;
|
||||
m0 = (ix << 7) & 0x7fffffff;
|
||||
m = even ? m0 : m1;
|
||||
|
||||
/* 2^e is the exponent part of the return value. */
|
||||
ey = ix >> 1;
|
||||
ey += 0x3f800000 >> 1;
|
||||
ey &= 0x7f800000;
|
||||
|
||||
/* compute r ~ 1/sqrt(m), s ~ sqrt(m) with 2 goldschmidt iterations. */
|
||||
static const uint32_t three = 0xc0000000;
|
||||
uint32_t r, s, d, u, i;
|
||||
i = (ix >> 17) % 128;
|
||||
r = (uint32_t)__rsqrt_tab[i] << 16;
|
||||
/* |r*sqrt(m) - 1| < 0x1p-8 */
|
||||
s = mul32(m, r);
|
||||
/* |s/sqrt(m) - 1| < 0x1p-8 */
|
||||
d = mul32(s, r);
|
||||
u = three - d;
|
||||
r = mul32(r, u) << 1;
|
||||
/* |r*sqrt(m) - 1| < 0x1.7bp-16 */
|
||||
s = mul32(s, u) << 1;
|
||||
/* |s/sqrt(m) - 1| < 0x1.7bp-16 */
|
||||
d = mul32(s, r);
|
||||
u = three - d;
|
||||
s = mul32(s, u);
|
||||
/* -0x1.03p-28 < s/sqrt(m) - 1 < 0x1.fp-31 */
|
||||
s = (s - 1)>>6;
|
||||
/* s < sqrt(m) < s + 0x1.08p-23 */
|
||||
|
||||
/* compute nearest rounded result. */
|
||||
uint32_t d0, d1, d2;
|
||||
float y, t;
|
||||
d0 = (m << 16) - s*s;
|
||||
d1 = s - d0;
|
||||
d2 = d1 + s + 1;
|
||||
s += d1 >> 31;
|
||||
s &= 0x007fffff;
|
||||
s |= ey;
|
||||
y = asfloat(s);
|
||||
if (FENV_SUPPORT) {
|
||||
/* handle rounding and inexact exception. */
|
||||
uint32_t tiny = predict_false(d2==0) ? 0 : 0x01000000;
|
||||
tiny |= (d1^d2) & 0x80000000;
|
||||
t = asfloat(tiny);
|
||||
y = eval_as_float(y + t);
|
||||
}
|
||||
return y;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
#include "gdbjit.h"
|
||||
#include <stdio.h>
|
||||
|
||||
static char block_name_buffer[16];
|
||||
|
||||
static enum gdb_status read_debug_info(struct gdb_reader_funcs* self, struct gdb_symbol_callbacks* cbs, void* memory, long memory_sz)
|
||||
{
|
||||
gdbjit_block_t* block = (gdbjit_block_t*)memory;
|
||||
|
||||
struct gdb_object* object = cbs->object_open(cbs);
|
||||
struct gdb_symtab* symtab = cbs->symtab_open(cbs, object, block->filename);
|
||||
sprintf(block_name_buffer, "%x", block->x64start);
|
||||
cbs->block_open(cbs, symtab, NULL, block->start, block->end, block_name_buffer);
|
||||
|
||||
cbs->line_mapping_add(cbs, symtab, block->nlines, block->lines);
|
||||
|
||||
cbs->symtab_close(cbs, symtab);
|
||||
cbs->object_close(cbs, object);
|
||||
|
||||
return GDB_SUCCESS;
|
||||
}
|
||||
|
||||
enum gdb_status unwind_frame(struct gdb_reader_funcs* self, struct gdb_unwind_callbacks* cbs)
|
||||
{
|
||||
return GDB_SUCCESS;
|
||||
}
|
||||
|
||||
struct gdb_frame_id get_frame_id(struct gdb_reader_funcs* self, struct gdb_unwind_callbacks* cbs)
|
||||
{
|
||||
struct gdb_frame_id frame = {0xdeadbeef, 0};
|
||||
return frame;
|
||||
}
|
||||
|
||||
void destroy_reader(struct gdb_reader_funcs* self) {}
|
||||
|
||||
__attribute__((visibility("default"))) struct gdb_reader_funcs* gdb_init_reader(void)
|
||||
{
|
||||
static struct gdb_reader_funcs funcs = {GDB_READER_INTERFACE_VERSION, NULL, read_debug_info, unwind_frame, get_frame_id, destroy_reader};
|
||||
return &funcs;
|
||||
}
|
||||
|
||||
__attribute__((visibility("default"))) int plugin_is_GPL_compatible (void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
Executable
+31
@@ -0,0 +1,31 @@
|
||||
#!/bin/bash
|
||||
|
||||
# create necessary directories
|
||||
mkdir -p ~/steam
|
||||
mkdir -p ~/steam/tmp
|
||||
cd ~/steam/tmp
|
||||
|
||||
# download latest deb and unpack
|
||||
wget https://cdn.cloudflare.steamstatic.com/client/installer/steam.deb
|
||||
ar x steam.deb
|
||||
tar xf data.tar.xz
|
||||
|
||||
# remove deb archives, not needed anymore
|
||||
rm ./*.tar.xz ./steam.deb
|
||||
|
||||
# move deb contents to steam folder
|
||||
mv ./usr/* ../
|
||||
cd ../ && rm -rf ./tmp/
|
||||
|
||||
# create run script
|
||||
echo '#!/bin/bash
|
||||
export STEAMOS=1
|
||||
export STEAM_RUNTIME=1
|
||||
export DBUS_FATAL_WARNINGS=0
|
||||
~/steam/bin/steam $@' > steam
|
||||
|
||||
# make script executable and move
|
||||
chmod +x steam
|
||||
sudo mv steam /usr/local/bin/
|
||||
|
||||
echo "Script complete."
|
||||
@@ -1,6 +1,6 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-rk3xxx-git
|
||||
pkgname=box64-rk3xxx-git
|
||||
pkgver=r2431.60c6858
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86_64 Emulator with a twist, targeted at ARM64 Linux devices."
|
||||
|
||||
+507
-156
@@ -150,14 +150,18 @@ class FunctionConvention(object):
|
||||
self.ident = ident
|
||||
self.name = convname
|
||||
self.values = valid_chars
|
||||
# Free letters: B FG J QR T XYZab e gh jk mno qrst xyz
|
||||
# Free letters: B FG JK QR T YZa e gh jk mno qrst yz
|
||||
conventions = {
|
||||
'F': FunctionConvention('F', "System V", ['E', 'v', 'c', 'w', 'i', 'I', 'C', 'W', 'u', 'U', 'f', 'd', 'D', 'K', 'l', 'L', 'p', 'V', 'O', 'S', 'N', 'M', 'H', 'P', 'A', 'x', 'X']),
|
||||
'W': FunctionConvention('W', "Windows", ['E', 'v', 'c', 'w', 'i', 'I', 'C', 'W', 'u', 'U', 'f', 'd', 'K', 'l', 'L', 'p', 'V', 'O', 'S', 'N', 'M', 'P', 'A'])
|
||||
'F': FunctionConvention('F', "System V", ['E', 'v', 'c', 'w', 'i', 'I', 'C', 'W', 'u', 'U', 'f', 'd', 'D', 'l', 'L', 'p', 'V', 'O', 'S', 'N', 'H', 'P', 'A', 'x', 'X', 'Y', 'b']),
|
||||
'W': FunctionConvention('W', "Windows", ['E', 'v', 'c', 'w', 'i', 'I', 'C', 'W', 'u', 'U', 'f', 'd', 'l', 'L', 'p', 'V', 'O', 'S', 'N', 'P', 'A'])
|
||||
}
|
||||
sortedvalues = ['E', 'v', 'c', 'w', 'i', 'I', 'C', 'W', 'u', 'U', 'f', 'd', 'D', 'K', 'l', 'L', 'p', 'V', 'O', 'S', 'N', 'M', 'H', 'P', 'A', 'x', 'X', '0', '1']
|
||||
sortedvalues = ['E', 'v', 'c', 'w', 'i', 'I', 'C', 'W', 'u', 'U', 'f', 'd', 'D', 'l', 'L', 'p', 'V', 'O', 'S', 'N', 'H', 'P', 'A', 'x', 'X', 'Y', 'b', '0', '1']
|
||||
assert(all(all(c not in conv.values[:i] and c in sortedvalues for i, c in enumerate(conv.values)) for conv in conventions.values()))
|
||||
|
||||
# Some type depend on HAVE_LD80BITS; define this here so we can use it in readFiles and main
|
||||
depends_on_ld: str = "DY"
|
||||
assert(all(c in sortedvalues for c in depends_on_ld))
|
||||
|
||||
class FunctionType(str):
|
||||
@staticmethod
|
||||
def validate(s: str, post: str) -> bool:
|
||||
@@ -197,7 +201,7 @@ class FunctionType(str):
|
||||
except ValueError as e:
|
||||
raise ValueError("Value is " + self) from e
|
||||
|
||||
def __getitem__(self, i: Union[int, slice]) -> 'FunctionType':
|
||||
def __getitem__(self, i: Union[int, slice]) -> 'FunctionType': # type: ignore [override]
|
||||
return FunctionType(super().__getitem__(i))
|
||||
|
||||
RedirectType = NewType('RedirectType', FunctionType)
|
||||
@@ -359,7 +363,7 @@ def readFiles(files: Iterable[Filename]) -> Tuple[JumbledGlobals, JumbledRedirec
|
||||
gbl : JumbledGlobals = {}
|
||||
redirects: JumbledRedirects = {}
|
||||
filespec : JumbledFilesSpecific = {}
|
||||
|
||||
|
||||
functions: Dict[str, Filename] = {}
|
||||
halt_required = False # Is there a GO(*, .FE*) or similar in-batch error(s)?
|
||||
# First read the files inside the headers
|
||||
@@ -369,7 +373,7 @@ def readFiles(files: Iterable[Filename]) -> Tuple[JumbledGlobals, JumbledRedirec
|
||||
|
||||
# typedefs is a list of all "*FE*" types for the current file
|
||||
# mystructs is a map of all char -> (structure C name, replacement) for structures
|
||||
typedefs : JumbledTypedefs = {}
|
||||
typedefs : JumbledTypedefs = {}
|
||||
mystructs : JumbledStructures = {}
|
||||
mystructuses: JumbledStructUses = {}
|
||||
filespec[filename[:-10]] = (typedefs, mystructs, mystructuses)
|
||||
@@ -399,10 +403,14 @@ def readFiles(files: Iterable[Filename]) -> Tuple[JumbledGlobals, JumbledRedirec
|
||||
or match("sdl1mixer", "sdl2mixer") \
|
||||
or match("sdl1net", "sdl2net") \
|
||||
or match("sdl1ttf", "sdl2ttf") \
|
||||
or match("libGL", "libEGL") \
|
||||
or match("libgl", "libegl") \
|
||||
or match("libgl", "glesv2") \
|
||||
or match("libegl", "glesv2") \
|
||||
or match("softokn3", "p11kit") \
|
||||
or match("libc", "tcmallocminimal") \
|
||||
or match("libc", "tbbmallocproxy") \
|
||||
or match("libc", "androidshmem") \
|
||||
or match("crypto", "libssl3") \
|
||||
or match("tcmallocminimal", "tbbmallocproxy"):
|
||||
continue
|
||||
|
||||
@@ -528,9 +536,22 @@ def readFiles(files: Iterable[Filename]) -> Tuple[JumbledGlobals, JumbledRedirec
|
||||
if ln not in gbl[str(dependants)]:
|
||||
gbl[str(dependants)].append(FunctionType(ln))
|
||||
|
||||
if any(c in origLine for c in depends_on_ld):
|
||||
if (gotype != "GOM") and (gotype != "GOWM") and (gotype != "GOD") and (gotype != "GOWD"):
|
||||
print("\033[91mError:\033[m type depends on HAVE_LD80BITS but the GO type doesn't support that ({0}:{1})"
|
||||
.format(filename, line[:-1]))
|
||||
halt_required = True
|
||||
if (gotype == "GO2") or (gotype == "GOW2") or (gotype == "GOD") or (gotype == "GODW"):
|
||||
altfun = line.split(',')[2].split(')')[0].strip()
|
||||
if altfun == "":
|
||||
print("\033[91mError:\033[m empty alt function ({0}:{1})".format(filename, line[:-1]))
|
||||
halt_required = True
|
||||
elif altfun == funname:
|
||||
print("\033[91mError:\033[m alt function is the original function ({0}:{1})".format(filename, line[:-1]))
|
||||
halt_required = True
|
||||
if origLine[2] == "E":
|
||||
if (gotype != "GOM") and (gotype != "GOWM"):
|
||||
if (gotype != "GO2") or not (line.split(',')[2].split(')')[0].strip().startswith('my_')):
|
||||
if ((gotype != "GO2") and (gotype != "GOW2")) or not (line.split(',')[2].split(')')[0].strip().startswith('my_')):
|
||||
print("\033[91mThis is probably not what you meant!\033[m ({0}:{1})".format(filename, line[:-1]))
|
||||
halt_required = True
|
||||
if len(origLine) > 3:
|
||||
@@ -816,62 +837,82 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
return 0
|
||||
|
||||
# Detect simple wrappings
|
||||
simple_wraps: Dict[ClausesStr, List[Tuple[FunctionType, int]]] = {}
|
||||
allowed_conv_ident = "F"
|
||||
allowed_conv = conventions[allowed_conv_ident]
|
||||
|
||||
# H could be allowed maybe?
|
||||
allowed_simply: str = "v"
|
||||
allowed_regs : str = "cCwWiuIUlLp"
|
||||
allowed_fpr : str = "fd"
|
||||
allowed_simply: Dict[str, str] = {"ARM64": "v", "RV64": "v"}
|
||||
allowed_regs : Dict[str, str] = {"ARM64": "cCwWiuIUlLp", "RV64": "CWIUlLp"}
|
||||
allowed_fpr : Dict[str, str] = {"ARM64": "fd", "RV64": "fd"}
|
||||
allowed_sextw : Dict[str, str] = {"ARM64": "", "RV64": "cwiu"}
|
||||
|
||||
# Detect functions which return in an x87 register
|
||||
retx87_wraps: Dict[ClausesStr, List[FunctionType]] = {}
|
||||
return_x87: str = "DK"
|
||||
return_x87: str = "D"
|
||||
|
||||
# Sanity checks
|
||||
forbidden_simple: str = "EDKVOSNMHPAxX"
|
||||
assert(len(allowed_simply) + len(allowed_regs) + len(allowed_fpr) + len(forbidden_simple) == len(allowed_conv.values))
|
||||
assert(all(c not in allowed_regs for c in allowed_simply))
|
||||
assert(all(c not in allowed_simply + allowed_regs for c in allowed_fpr))
|
||||
assert(all(c not in allowed_simply + allowed_regs + allowed_fpr for c in forbidden_simple))
|
||||
assert(all(c in allowed_simply + allowed_regs + allowed_fpr + forbidden_simple for c in allowed_conv.values))
|
||||
forbidden_simple: Dict[str, str] = {"ARM64": "EDVOSNHPAxXYb", "RV64": "EDVOSNHPAxXYb"}
|
||||
assert(all(k in allowed_simply for k in forbidden_simple))
|
||||
assert(all(k in allowed_regs for k in forbidden_simple))
|
||||
assert(all(k in allowed_fpr for k in forbidden_simple))
|
||||
for k1 in forbidden_simple:
|
||||
assert(len(allowed_simply[k1]) + len(allowed_regs[k1]) + len(allowed_fpr[k1]) + len(allowed_sextw[k1]) + len(forbidden_simple[k1]) == len(allowed_conv.values))
|
||||
assert(all(c not in allowed_regs[k1] for c in allowed_simply[k1]))
|
||||
assert(all(c not in allowed_simply[k1] + allowed_regs[k1] for c in allowed_fpr[k1]))
|
||||
assert(all(c not in allowed_simply[k1] + allowed_regs[k1] + allowed_fpr[k1] for c in forbidden_simple[k1]))
|
||||
assert(all(c in allowed_simply[k1] + allowed_regs[k1] + allowed_fpr[k1] + allowed_sextw[k1] + forbidden_simple[k1] for c in allowed_conv.values))
|
||||
assert(all(c in allowed_conv.values for c in return_x87))
|
||||
assert(all(c in forbidden_simple[k] for c in depends_on_ld for k in forbidden_simple))
|
||||
|
||||
def check_simple(v: FunctionType) -> Optional[int]:
|
||||
regs_count: int = 0
|
||||
fpr_count : int = 0
|
||||
|
||||
if v.get_convention() is not allowed_conv:
|
||||
return None
|
||||
if v[0] in forbidden_simple:
|
||||
return None
|
||||
for c in v[2:]:
|
||||
if c in allowed_regs:
|
||||
regs_count = regs_count + 1
|
||||
elif c in allowed_fpr:
|
||||
fpr_count = fpr_count + 1
|
||||
elif c in allowed_simply:
|
||||
simple_wraps: Dict[str, Dict[ClausesStr, List[Tuple[FunctionType, int]]]] = {
|
||||
k1: {} for k1 in forbidden_simple
|
||||
}
|
||||
|
||||
def check_simple(v: FunctionType) -> Dict[str, int]:
|
||||
ret: Dict[str, int] = {}
|
||||
for k in forbidden_simple:
|
||||
regs_count: int = 0
|
||||
fpr_count : int = 0
|
||||
sextw_mask: int = 0
|
||||
|
||||
if v.get_convention() is not allowed_conv:
|
||||
continue
|
||||
if v[0] in forbidden_simple[k]:
|
||||
continue
|
||||
for c in v[2:]:
|
||||
if c in allowed_regs[k]:
|
||||
regs_count = regs_count + 1
|
||||
elif c in allowed_fpr[k]:
|
||||
fpr_count = fpr_count + 1
|
||||
elif c in allowed_simply[k]:
|
||||
continue
|
||||
elif c in allowed_sextw[k]:
|
||||
sextw_mask |= 1 << regs_count
|
||||
regs_count += 1
|
||||
else:
|
||||
break
|
||||
else:
|
||||
return None
|
||||
# No character in forbidden_simply
|
||||
if (regs_count <= 6) and (fpr_count <= 8):
|
||||
# All checks passed!
|
||||
ret_val = 1 + fpr_count
|
||||
if v[0] in allowed_fpr:
|
||||
ret_val = -ret_val
|
||||
return ret_val
|
||||
else:
|
||||
# Too many arguments...
|
||||
return None
|
||||
# No character in forbidden_simply
|
||||
if (regs_count <= 6) and (fpr_count <= 8):
|
||||
# All checks passed!
|
||||
ret_val = 1 + fpr_count
|
||||
ret_val |= sextw_mask << 4
|
||||
if v[0] in allowed_fpr[k]:
|
||||
ret_val = -ret_val
|
||||
ret[k] = ret_val
|
||||
# Else, too many arguments
|
||||
return ret
|
||||
|
||||
# Only search in real wrappers (mapped ones are nearly always not simple)
|
||||
for k in gbls:
|
||||
tmp = [ (v, ret_val) for v, ret_val in map(lambda v: (v, check_simple(v)), gbls[k]) if ret_val is not None ]
|
||||
if tmp:
|
||||
simple_wraps[k] = tmp
|
||||
simple_idxs = sorted(simple_wraps.keys(), key=lambda x: Clauses(x).splitdef())
|
||||
for v in gbls[k]:
|
||||
simples = check_simple(v)
|
||||
for k1, i in simples.items():
|
||||
if k in simple_wraps[k1]:
|
||||
simple_wraps[k1][k].append((v, i))
|
||||
else:
|
||||
simple_wraps[k1][k] = [(v, i)]
|
||||
simple_idxs = { k1: sorted(v1.keys(), key=lambda x: Clauses(x).splitdef()) for k1, v1 in simple_wraps.items() }
|
||||
|
||||
def check_return_x87(v: FunctionType) -> bool:
|
||||
return v[0] in return_x87
|
||||
@@ -915,9 +956,24 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
return v;
|
||||
{rbr}
|
||||
|
||||
static void* io_convert_back(void* v)
|
||||
{lbr}
|
||||
if(!v)
|
||||
return v;
|
||||
if(v == stdin)
|
||||
return my__IO_2_1_stdin_;
|
||||
if(v == stdout)
|
||||
return my__IO_2_1_stdout_;
|
||||
if(v == stderr)
|
||||
return my__IO_2_1_stderr_;
|
||||
return v;
|
||||
{rbr}
|
||||
|
||||
#define ST0val ST0.d
|
||||
|
||||
int of_convert(int);
|
||||
void* align_xcb_connection(void* src);
|
||||
void unalign_xcb_connection(void* src, void* dst);
|
||||
|
||||
""",
|
||||
"wrapper.h": """
|
||||
@@ -949,11 +1005,11 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
// o = stdout
|
||||
// S = _IO_2_1_stdXXX_ pointer (or FILE*)
|
||||
// N = ... automatically sending 1 arg
|
||||
// M = ... automatically sending 2 args
|
||||
// A = va_list
|
||||
// 0 = constant 0, 1 = constant 1
|
||||
// x = float complex
|
||||
// X = double complex
|
||||
// b = xcb_connection_t*
|
||||
|
||||
""",
|
||||
"fntypes.h": """
|
||||
@@ -977,6 +1033,26 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
#ifndef __{filename}UNDEFS_H_
|
||||
#define __{filename}UNDEFS_H_
|
||||
|
||||
""",
|
||||
"x64printer.c": """
|
||||
#include <inttypes.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "x64emu.h"
|
||||
#include "x64emu_private.h"
|
||||
#include "wrapper.h"
|
||||
|
||||
#define PRIp "p"
|
||||
#define PRIf "f"
|
||||
#define PRILf "Lf"
|
||||
#define PRIs "s"
|
||||
|
||||
void x64Print(x64emu_t* emu, char* buff, size_t buffsz, const char* func, int tid, wrapper_t w)
|
||||
{lbr}
|
||||
#ifdef HAVE_TRACE
|
||||
if (0) {lbr}
|
||||
"""
|
||||
}
|
||||
files_guard = {
|
||||
@@ -999,6 +1075,14 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
"fnundefs.h": """
|
||||
|
||||
#endif // __{filename}UNDEFS_H_
|
||||
""",
|
||||
"x64printer.c": """
|
||||
else
|
||||
#endif // HAVE_TRACE
|
||||
{lbr}
|
||||
snprintf(buff, buffsz, "%04d|%p: Calling %s(0x%lX, 0x%lX, 0x%lX, ...)", tid, *(void**)(R_RSP), func, R_RDI, R_RSI, R_RDX);
|
||||
{rbr}
|
||||
{rbr}
|
||||
"""
|
||||
}
|
||||
|
||||
@@ -1015,20 +1099,59 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
# Rewrite the wrapper.c file:
|
||||
# i and u should only be 32 bits
|
||||
td_types = {
|
||||
# E v c w i I C W u U f d D K l L p V O S N M H P A x X
|
||||
'F': ["x64emu_t*", "void", "int8_t", "int16_t", "int32_t", "int64_t", "uint8_t", "uint16_t", "uint32_t", "uint64_t", "float", "double", "long double", "double", "intptr_t", "uintptr_t", "void*", "void*", "int32_t", "void*", "...", "...", "unsigned __int128", "void*", "void*", "complexf_t", "complex_t"],
|
||||
# E v c w i I C W u U f d K l L p V O S N M P A
|
||||
'W': ["x64emu_t*", "void", "int8_t", "int16_t", "int32_t", "int64_t", "uint8_t", "uint16_t", "uint32_t", "uint64_t", "float", "double", "double", "intptr_t", "uintptr_t", "void*", "void*", "int32_t", "void*", "...", "...", "void*", "void*"]
|
||||
# E v c w i I C W u U f d D l L p V O S N H P A x X Y b
|
||||
'F': ["x64emu_t*", "void", "int8_t", "int16_t", "int32_t", "int64_t", "uint8_t", "uint16_t", "uint32_t", "uint64_t", "float", "double", "long double", "intptr_t", "uintptr_t", "void*", "void*", "int32_t", "void*", "...", "unsigned __int128", "void*", "void*", "complexf_t", "complex_t", "complexl_t", "void*"],
|
||||
# E v c w i I C W u U f d l L p V O S N P A
|
||||
'W': ["x64emu_t*", "void", "int8_t", "int16_t", "int32_t", "int64_t", "uint8_t", "uint16_t", "uint32_t", "uint64_t", "float", "double", "intptr_t", "uintptr_t", "void*", "void*", "int32_t", "void*", "...", "void*", "void*"]
|
||||
}
|
||||
td_types_nold = {
|
||||
'F': {'D': "double", 'Y': "complex_t"},
|
||||
'W': {}
|
||||
}
|
||||
td_types_ld = {
|
||||
k: {t: td_types[k][conventions[k].values.index(t)] for t in td_types_nold[k]} for k in td_types_nold
|
||||
}
|
||||
assert(all(k in conventions for k in td_types))
|
||||
assert(all(k in conventions for k in td_types_nold))
|
||||
assert(all(t in depends_on_ld for k in td_types_nold for t in td_types_nold[k]))
|
||||
for k in conventions:
|
||||
if len(conventions[k].values) != len(td_types[k]):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(td_types) = {lentypes}".format(lenval=len(conventions[k].values), lentypes=len(td_types[k])))
|
||||
|
||||
def generate_typedefs(arr: Iterable[FunctionType], file) -> None:
|
||||
any_depends_on_ld = False
|
||||
for v in arr:
|
||||
file.write("typedef " + td_types[v.get_convention().ident][v.get_convention().values.index(v[0])] + " (*" + v + "_t)"
|
||||
if any(c in v for c in depends_on_ld):
|
||||
any_depends_on_ld = True
|
||||
continue
|
||||
name = v + "_t"
|
||||
v = v[:-1] if v.endswith('NN') else v # FIXME
|
||||
file.write("typedef " + td_types[v.get_convention().ident][v.get_convention().values.index(v[0])] + " (*" + name + ")"
|
||||
+ "(" + ', '.join(td_types[v.get_convention().ident][v.get_convention().values.index(t)] for t in v[2:]) + ");\n")
|
||||
if any_depends_on_ld:
|
||||
file.write("\n#if defined(HAVE_LD80BITS) || defined(ANDROID)\n")
|
||||
for v in arr:
|
||||
if all(c not in v for c in depends_on_ld):
|
||||
continue
|
||||
name = v + "_t"
|
||||
v = v[:-1] if v.endswith('NN') else v # FIXME
|
||||
file.write("typedef " + td_types[v.get_convention().ident][v.get_convention().values.index(v[0])] + " (*" + name + ")"
|
||||
+ "(" + ', '.join(td_types[v.get_convention().ident][v.get_convention().values.index(t)] for t in v[2:]) + ");\n")
|
||||
file.write("#else // !HAVE_LD80BITS && !ANDROID\n")
|
||||
for k in td_types_nold:
|
||||
for t in td_types_nold[k]:
|
||||
td_types[k][conventions[k].values.index(t)] = td_types_nold[k][t]
|
||||
for v in arr:
|
||||
if all(c not in v for c in depends_on_ld):
|
||||
continue
|
||||
name = v + "_t"
|
||||
v = v[:-1] if v.endswith('NN') else v # FIXME
|
||||
file.write("typedef " + td_types[v.get_convention().ident][v.get_convention().values.index(v[0])] + " (*" + name + ")"
|
||||
+ "(" + ', '.join(td_types[v.get_convention().ident][v.get_convention().values.index(t)] for t in v[2:]) + ");\n")
|
||||
for k in td_types_nold:
|
||||
for t in td_types_ld[k]:
|
||||
td_types[k][conventions[k].values.index(t)] = td_types_ld[k][t]
|
||||
file.write("#endif\n")
|
||||
|
||||
with open(os.path.join(root, "src", "wrapped", "generated", "wrapper.c"), 'w') as file:
|
||||
file.write(files_header["wrapper.c"].format(lbr="{", rbr="}", version=ver))
|
||||
@@ -1051,10 +1174,10 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
conventions['F']: [
|
||||
"\n#error Invalid return type: emulator\n", # E
|
||||
"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=(uint8_t)fn({0});", # c
|
||||
"R_RAX=(uint16_t)fn({0});", # w
|
||||
"R_RAX=(uint32_t)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
|
||||
@@ -1062,20 +1185,20 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
"emu->xmm[0].f[0]=fn({0});", # f
|
||||
"emu->xmm[0].d[0]=fn({0});", # d
|
||||
"long double ld=fn({0}); fpu_do_push(emu); ST0val = ld;", # D
|
||||
"double db=fn({0}); fpu_do_push(emu); ST0val = db;", # K
|
||||
"R_RAX=(intptr_t)fn({0});", # l
|
||||
"R_RAX=(uintptr_t)fn({0});", # L
|
||||
"R_RAX=(uintptr_t)fn({0});", # p
|
||||
"\n#error Invalid return type: va_list\n", # V
|
||||
"\n#error Invalid return type: at_flags\n", # O
|
||||
"\n#error Invalid return type: _io_file*\n", # S
|
||||
"R_RAX=(uintptr_t)io_convert_back(fn({0}));", # S
|
||||
"\n#error Invalid return type: ... with 1 arg\n", # N
|
||||
"\n#error Invalid return type: ... with 2 args\n", # M
|
||||
"unsigned __int128 u128 = fn({0}); R_RAX=(u128&0xFFFFFFFFFFFFFFFFL); R_RDX=(u128>>64)&0xFFFFFFFFFFFFFFFFL;", # H
|
||||
"\n#error Invalid return type: pointer in the stack\n", # P
|
||||
"\n#error Invalid return type: va_list\n", # A
|
||||
'from_complexf(emu, fn({0})));', # x
|
||||
'from_complex(emu, fn({0})));' # X
|
||||
"from_complexf(emu, fn({0}));", # x
|
||||
"from_complex(emu, fn({0}));", # X
|
||||
"from_complexl(emu, fn({0}));", # Y
|
||||
"\n#error Invalid return type: xcb_connection_t*\n", # b
|
||||
],
|
||||
conventions['W']: [
|
||||
"\n#error Invalid return type: emulator\n", # E
|
||||
@@ -1090,32 +1213,47 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
"R_RAX=fn({0});", # U
|
||||
"emu->xmm[0].f[0]=fn({0});", # f
|
||||
"emu->xmm[0].d[0]=fn({0});", # d
|
||||
"double db=fn({0}); fpu_do_push(emu); ST0val = db;", # K
|
||||
"R_RAX=(intptr_t)fn({0});", # l
|
||||
"R_RAX=(uintptr_t)fn({0});", # L
|
||||
"R_RAX=(uintptr_t)fn({0});", # p
|
||||
"\n#error Invalid return type: va_list\n", # V
|
||||
"\n#error Invalid return type: at_flags\n", # O
|
||||
"\n#error Invalid return type: _io_file*\n", # S
|
||||
"R_RAX=io_convert_back(fn({0}));", # S
|
||||
"\n#error Invalid return type: ... with 1 arg\n", # N
|
||||
"\n#error Invalid return type: ... with 2 args\n", # M
|
||||
"\n#error Invalid return type: pointer in the stack\n", # P
|
||||
"\n#error Invalid return type: va_list\n", # A
|
||||
]
|
||||
}
|
||||
vals_nold = {
|
||||
conventions['F']: {
|
||||
'D': "double db=fn({0}); fpu_do_push(emu); ST0val = db;",
|
||||
'Y': "from_complexk(emu, fn({0}));",
|
||||
},
|
||||
conventions['W']: {}
|
||||
}
|
||||
vals_android = {
|
||||
conventions['F']: {
|
||||
"D": "long double ld=fn({0}); emu->xmm[0].u128=*(__uint128_t*)&ld;",
|
||||
"Y": "from_complexl(emu, fn({0}));",
|
||||
},
|
||||
conventions['W']: {}
|
||||
}
|
||||
vals_ld = {
|
||||
k: {t: vals[k][k.values.index(t)] for t in vals_nold[k]} for k in vals_nold
|
||||
}
|
||||
|
||||
# vreg: value is in a general register
|
||||
# E v c w i I C W u U f d D K l L p V O S N M H P A x X
|
||||
vreg = [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 2, 2, 0, 1, 0, 0]
|
||||
# E v c w i I C W u U f d D l L p V O S N H P A x X Y b
|
||||
vreg = [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 2, 0, 1, 0, 0, 0, 1]
|
||||
# vxmm: value is in a XMM register
|
||||
# E v c w i I C W u U f d D K l L p V O S N M H P A x X
|
||||
vxmm = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2]
|
||||
# E v c w i I C W u U f d D l L p V O S N H P A x X Y b
|
||||
vxmm = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0]
|
||||
# vother: value is elsewere
|
||||
# E v c w i I C W u U f d D K l L p V O S N M H P A x X
|
||||
vother = [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
# E v c w i I C W u U f d D l L p V O S N H P A x X Y b
|
||||
vother = [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
# vstack: value is on the stack (or out of register)
|
||||
# E v c w i I C W u U f d D K l L p V O S N M H P A x X
|
||||
vstack = [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 0, 1, 1, 1, 2, 2, 1, 1, 1, 2]
|
||||
# E v c w i I C W u U f d D l L p V O S N H P A x X Y b
|
||||
vstack = [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 0, 1, 1, 1, 2, 1, 1, 1, 2, 4, 1]
|
||||
arg_r = [
|
||||
"", # E
|
||||
"", # v
|
||||
@@ -1130,7 +1268,6 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
"", # f
|
||||
"", # d
|
||||
"", # D
|
||||
"", # K
|
||||
"(intptr_t){p}, ", # l
|
||||
"(uintptr_t){p}, ", # L
|
||||
"(void*){p}, ", # p
|
||||
@@ -1138,70 +1275,71 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
"of_convert((int32_t){p}), ", # O
|
||||
"io_convert((void*){p}), ", # S
|
||||
"(void*){p}, ", # N
|
||||
"(void*){p}, ", # M
|
||||
"\n#error Use pp instead\n", # H
|
||||
"(unsigned __int128){p} + ((unsigned __int128){p2} << 64), ", # H
|
||||
"", # P
|
||||
"(void*){p}, ", # A
|
||||
"", # x
|
||||
"", # x
|
||||
"", # X
|
||||
"", # Y
|
||||
"aligned_xcb, ", # b
|
||||
]
|
||||
arg_x = [
|
||||
"", # E
|
||||
"", # v
|
||||
"", # c
|
||||
"", # w
|
||||
"", # i
|
||||
"", # I
|
||||
"", # C
|
||||
"", # W
|
||||
"", # u
|
||||
"", # U
|
||||
"emu->xmm[{p}].f[0], ", # f
|
||||
"emu->xmm[{p}].d[0], ", # d
|
||||
"", # D
|
||||
"", # K
|
||||
"", # l
|
||||
"", # L
|
||||
"", # p
|
||||
"", # V
|
||||
"", # O
|
||||
"", # S
|
||||
"", # N
|
||||
"", # M
|
||||
"", # H
|
||||
"", # P
|
||||
"", # A
|
||||
"to_complexf(emu, {p}),",# x
|
||||
"to_complex(emu, {p})," # X
|
||||
"", # E
|
||||
"", # v
|
||||
"", # c
|
||||
"", # w
|
||||
"", # i
|
||||
"", # I
|
||||
"", # C
|
||||
"", # W
|
||||
"", # u
|
||||
"", # U
|
||||
"emu->xmm[{p}].f[0], ", # f
|
||||
"emu->xmm[{p}].d[0], ", # d
|
||||
"", # D
|
||||
"", # l
|
||||
"", # L
|
||||
"", # p
|
||||
"", # V
|
||||
"", # O
|
||||
"", # S
|
||||
"", # N
|
||||
"", # H
|
||||
"", # P
|
||||
"", # A
|
||||
"to_complexf(emu, {p}), ", # x
|
||||
"to_complex(emu, {p}), ", # X
|
||||
"", # Y
|
||||
"", # b
|
||||
]
|
||||
arg_o = [
|
||||
"emu, ", # E
|
||||
"", # v
|
||||
"", # c
|
||||
"", # w
|
||||
"", # i
|
||||
"", # I
|
||||
"", # C
|
||||
"", # W
|
||||
"", # u
|
||||
"", # U
|
||||
"", # f
|
||||
"", # d
|
||||
"", # D
|
||||
"", # K
|
||||
"", # l
|
||||
"", # L
|
||||
"", # p
|
||||
"(void*)(R_RSP + {p}), ", # V
|
||||
"", # O
|
||||
"", # S
|
||||
"", # N
|
||||
"", # M
|
||||
"", # H
|
||||
"", # P
|
||||
"", # A
|
||||
"", # x
|
||||
"", # X
|
||||
"emu, ", # E
|
||||
"", # v
|
||||
"", # c
|
||||
"", # w
|
||||
"", # i
|
||||
"", # I
|
||||
"", # C
|
||||
"", # W
|
||||
"", # u
|
||||
"", # U
|
||||
"", # f
|
||||
"", # d
|
||||
"", # D
|
||||
"", # l
|
||||
"", # L
|
||||
"", # p
|
||||
"(void*)(R_RSP + {p}), ", # V
|
||||
"", # O
|
||||
"", # S
|
||||
"", # N
|
||||
"", # H
|
||||
"", # P
|
||||
"", # A
|
||||
"", # x
|
||||
"", # X
|
||||
"", # Y
|
||||
"", # b
|
||||
]
|
||||
arg_s = [
|
||||
"", # E
|
||||
@@ -1217,7 +1355,6 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
"*(float*)(R_RSP + {p}), ", # f
|
||||
"*(double*)(R_RSP + {p}), ", # d
|
||||
"LD2localLD((void*)(R_RSP + {p})), ", # D
|
||||
"FromLD((void*)(R_RSP + {p})), ", # K
|
||||
"*(intptr_t*)(R_RSP + {p}), ", # l
|
||||
"*(uintptr_t*)(R_RSP + {p}), ", # L
|
||||
"*(void**)(R_RSP + {p}), ", # p
|
||||
@@ -1225,13 +1362,36 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
"of_convert(*(int32_t*)(R_RSP + {p})), ", # O
|
||||
"io_convert(*(void**)(R_RSP + {p})), ", # S
|
||||
"*(void**)(R_RSP + {p}), ", # N
|
||||
"*(void**)(R_RSP + {p}),*(void**)(R_RSP + {p} + 8), ", # M
|
||||
"*(unsigned __int128)(R_RSP + {p}), ", # H
|
||||
"*(unsigned __int128*)(R_RSP + {p}), ", # H
|
||||
"*(void**)(R_RSP + {p}), ", # P
|
||||
"*(void**)(R_RSP + {p}), ", # A
|
||||
"*(complexf_t*)(R_RSP + {p}), ", # x
|
||||
"*(complex_t*)(R_RSP + {p}), ", # X
|
||||
"to_complexl(emu, R_RSP + {p}), ", # Y
|
||||
"aligned_xcb, ", # b
|
||||
]
|
||||
arg_s_nold = {
|
||||
'D': "FromLD((void*)(R_RSP + {p})), ", # K
|
||||
'Y': "to_complexk(emu, R_RSP + {p}), ", # y
|
||||
}
|
||||
arg_s_android = {
|
||||
'D': "*(long double*)(R_RSP + {p})], ",
|
||||
'Y': "to_complexl(emu, R_RSP + {p}), ",
|
||||
}
|
||||
arg_s_ld = {
|
||||
t: arg_s[conventions['F'].values.index(t)] for t in arg_s_nold
|
||||
}
|
||||
vxmm_noandroid = vxmm[:]
|
||||
vxmm_android = vxmm[:]
|
||||
vxmm_android[conventions['F'].values.index('D')] = 1
|
||||
vxmm_android[conventions['F'].values.index('Y')] = 1
|
||||
arg_x_android = {
|
||||
'D': "*(long double*)&emu->xmm[{p}], ",
|
||||
'Y': "to_complexl(emu, (uintptr_t)&emu->xmm[{p}]), ",
|
||||
}
|
||||
arg_x_ld = {
|
||||
t: arg_x[conventions['F'].values.index(t)] for t in arg_x_android
|
||||
}
|
||||
|
||||
# Asserts
|
||||
for k in conventions:
|
||||
@@ -1258,7 +1418,7 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
for k in conventions:
|
||||
c = conventions[k]
|
||||
if c not in vals:
|
||||
raise NotImplementedError("[{k}]values not in vals".format(k=k, lenval=len(c.values), lenvals=len(vals[c])))
|
||||
raise NotImplementedError("convention {k} not in vals".format(k=k))
|
||||
if len(c.values) != len(vals[c]):
|
||||
raise NotImplementedError("len([{k}]values) = {lenval} != len(vals[...]) = {lenvals}".format(k=k, lenval=len(c.values), lenvals=len(vals[c])))
|
||||
# When arg_* is not empty, v* should not be 0
|
||||
@@ -1282,6 +1442,50 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
|
||||
# Helper functions to write the function definitions
|
||||
systemVconv = conventions['F']
|
||||
def function_pre_systemV(args: FunctionType, d: int = 8, r: int = 0, x: int = 0) -> Tuple[Optional[str], str]:
|
||||
# args: string of argument types
|
||||
# d: delta (in the stack)
|
||||
# r: general register no
|
||||
# x: XMM register no
|
||||
if len(args) == 0:
|
||||
return None, ""
|
||||
|
||||
# Redirections
|
||||
if args[0] == "0":
|
||||
return function_pre_systemV(args[1:], d, r, x)
|
||||
elif args[0] == "1":
|
||||
return function_pre_systemV(args[1:], d, r, x)
|
||||
|
||||
idx = systemVconv.values.index(args[0])
|
||||
# Name of the registers
|
||||
reg_arg = ["R_RDI", "R_RSI", "R_RDX", "R_RCX", "R_R8", "R_R9"]
|
||||
if args[0] == "b":
|
||||
if 'b' in args[1:]:
|
||||
raise NotImplementedError("Multiple XCB connections unsupported")
|
||||
content = ""
|
||||
if r < len(reg_arg):
|
||||
content = reg_arg[r]
|
||||
else:
|
||||
content = "(R_RSP + " + str(d) + ")"
|
||||
return "(void*)" + content, f"void *aligned_xcb = align_xcb_connection((void*){content}); "
|
||||
elif (r < len(reg_arg)) and (vreg[idx] > 0):
|
||||
for _ in range(vreg[idx]):
|
||||
if r < len(reg_arg):
|
||||
r = r + 1
|
||||
else:
|
||||
d = d + 8
|
||||
return function_pre_systemV(args[1:], d, r, x)
|
||||
elif (x < 8) and (vxmm[idx] > 0):
|
||||
return function_pre_systemV(args[1:], d, r, x+1)
|
||||
elif vstack[idx] > 0:
|
||||
return function_pre_systemV(args[1:], d+8*vstack[idx], r, x)
|
||||
else:
|
||||
return function_pre_systemV(args[1:], d, r, x)
|
||||
def function_post_systemV(content: Optional[str]) -> str:
|
||||
if content is not None:
|
||||
return f" unalign_xcb_connection(aligned_xcb, {content});"
|
||||
else:
|
||||
return ""
|
||||
def function_args_systemV(args: FunctionType, d: int = 8, r: int = 0, x: int = 0) -> str:
|
||||
# args: string of argument types
|
||||
# d: delta (in the stack)
|
||||
@@ -1301,20 +1505,30 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
reg_arg = ["R_RDI", "R_RSI", "R_RDX", "R_RCX", "R_R8", "R_R9"]
|
||||
if (r < len(reg_arg)) and (vreg[idx] > 0):
|
||||
ret = ""
|
||||
for _ in range(vreg[idx]):
|
||||
# There may be values in multiple registers
|
||||
if (vreg[idx] == 2) and ("{p2}" in arg_r[idx]):
|
||||
if r < len(reg_arg):
|
||||
# Value is in a general register
|
||||
ret = ret + arg_r[idx].format(p=reg_arg[r])
|
||||
r = r + 1
|
||||
ret = ret + arg_r[idx].format(p=reg_arg[r], p2=reg_arg[r+1])
|
||||
r = r + 2
|
||||
else:
|
||||
# Remaining is in the stack
|
||||
ret = ret + arg_s[idx].format(p=d)
|
||||
d = d + 8
|
||||
else:
|
||||
for _ in range(vreg[idx]):
|
||||
# There may be values in multiple registers
|
||||
if r < len(reg_arg):
|
||||
# Value is in a general register
|
||||
ret = ret + arg_r[idx].format(p=reg_arg[r])
|
||||
r = r + 1
|
||||
else:
|
||||
# Remaining is in the stack
|
||||
ret = ret + arg_s[idx].format(p=d)
|
||||
d = d + 8
|
||||
return ret + function_args_systemV(args[1:], d, r, x)
|
||||
elif (x < 8) and (vxmm[idx] > 0):
|
||||
# Value is in an XMM register
|
||||
return arg_x[idx].format(p=x) + function_args_systemV(args[1:], d, r, x+1)
|
||||
return arg_x[idx].format(p=x) + function_args_systemV(args[1:], d, r, x+vxmm[idx])
|
||||
elif vstack[idx] > 0:
|
||||
# Value is in the stack
|
||||
return arg_s[idx].format(p=d) + function_args_systemV(args[1:], d+8*vstack[idx], r, x)
|
||||
@@ -1361,42 +1575,156 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
# Generic function
|
||||
conv = N.get_convention()
|
||||
if conv is systemVconv:
|
||||
f.write(vals[conv][conv.values.index(N[0])].format(function_args_systemV(N[2:])[:-2]) + " }\n")
|
||||
prepost, pre = function_pre_systemV(N[2:])
|
||||
f.write(pre + vals[conv][conv.values.index(N[0])].format(function_args_systemV(N[2:])[:-2]) + function_post_systemV(prepost))
|
||||
else:
|
||||
f.write(vals[conv][conv.values.index(N[0])].format(function_args_windows(N[2:])[:-2]) + " }\n")
|
||||
f.write(vals[conv][conv.values.index(N[0])].format(function_args_windows(N[2:])[:-2]))
|
||||
f.write(" }\n")
|
||||
|
||||
for k in gbls:
|
||||
any_depends_on_ld = False
|
||||
if k != str(Clauses()):
|
||||
file.write("\n#if " + k + "\n")
|
||||
for v in gbls[k]:
|
||||
if any(c in v for c in depends_on_ld):
|
||||
any_depends_on_ld = True
|
||||
continue
|
||||
if v == FunctionType("vFv"):
|
||||
# Suppress all warnings...
|
||||
file.write("void vFv(x64emu_t *emu, uintptr_t fcn) { vFv_t fn = (vFv_t)fcn; fn(); (void)emu; }\n")
|
||||
else:
|
||||
function_writer(file, v, v + "_t")
|
||||
if any_depends_on_ld:
|
||||
file.write("\n#if defined(ANDROID)\n")
|
||||
for c in vals_android:
|
||||
for t in vals_android[c]:
|
||||
vals[c][c.values.index(t)] = vals_android[c][t]
|
||||
for t in arg_s_android:
|
||||
arg_s[conventions['F'].values.index(t)] = arg_s_android[t]
|
||||
for t in arg_x_android:
|
||||
arg_x[conventions['F'].values.index(t)] = arg_x_android[t]
|
||||
vxmm = vxmm_android
|
||||
for v in gbls[k]:
|
||||
if all(c not in v for c in depends_on_ld):
|
||||
continue
|
||||
if v == FunctionType("vFv"):
|
||||
# Suppress all warnings...
|
||||
file.write("void vFv(x64emu_t *emu, uintptr_t fcn) { vFv_t fn = (vFv_t)fcn; fn(); (void)emu; }\n")
|
||||
else:
|
||||
function_writer(file, v, v + "_t")
|
||||
file.write("#elif !defined(HAVE_LD80BITS)\n")
|
||||
for c in vals_android:
|
||||
for t in vals_ld[c]:
|
||||
vals[c][c.values.index(t)] = vals_ld[c][t]
|
||||
for c in vals_nold:
|
||||
for t in vals_nold[c]:
|
||||
vals[c][c.values.index(t)] = vals_nold[c][t]
|
||||
for t in arg_s_android:
|
||||
arg_s[conventions['F'].values.index(t)] = arg_s_ld[t]
|
||||
for t in arg_s_nold:
|
||||
arg_s[conventions['F'].values.index(t)] = arg_s_nold[t]
|
||||
for t in arg_x_android:
|
||||
arg_x[conventions['F'].values.index(t)] = arg_x_ld[t]
|
||||
vxmm = vxmm_noandroid
|
||||
for v in gbls[k]:
|
||||
if all(c not in v for c in depends_on_ld):
|
||||
continue
|
||||
if v == FunctionType("vFv"):
|
||||
# Suppress all warnings...
|
||||
file.write("void vFv(x64emu_t *emu, uintptr_t fcn) { vFv_t fn = (vFv_t)fcn; fn(); (void)emu; }\n")
|
||||
else:
|
||||
function_writer(file, v, v + "_t")
|
||||
for c in vals_nold:
|
||||
for t in vals_nold[c]:
|
||||
vals[c][c.values.index(t)] = vals_ld[c][t]
|
||||
for t in arg_s_nold:
|
||||
arg_s[conventions['F'].values.index(t)] = arg_s_ld[t]
|
||||
file.write("#else // defined(HAVE_LD80BITS) && !defined(ANDROID)\n")
|
||||
for v in gbls[k]:
|
||||
if all(c not in v for c in depends_on_ld):
|
||||
continue
|
||||
if v == FunctionType("vFv"):
|
||||
# Suppress all warnings...
|
||||
file.write("void vFv(x64emu_t *emu, uintptr_t fcn) { vFv_t fn = (vFv_t)fcn; fn(); (void)emu; }\n")
|
||||
else:
|
||||
function_writer(file, v, v + "_t")
|
||||
file.write("#endif\n")
|
||||
if k != str(Clauses()):
|
||||
file.write("#endif\n")
|
||||
file.write("\n")
|
||||
for k in redirects:
|
||||
any_depends_on_ld = False
|
||||
if k != str(Clauses()):
|
||||
file.write("\n#if " + k + "\n")
|
||||
for vr, vf in redirects[k]:
|
||||
if any(c in vr for c in depends_on_ld):
|
||||
any_depends_on_ld = True
|
||||
continue
|
||||
function_writer(file, vr, vf + "_t")
|
||||
if any_depends_on_ld:
|
||||
file.write("\n#if defined(ANDROID)\n")
|
||||
for c in vals_android:
|
||||
for t in vals_android[c]:
|
||||
vals[c][c.values.index(t)] = vals_android[c][t]
|
||||
for t in arg_s_android:
|
||||
arg_s[conventions['F'].values.index(t)] = arg_s_android[t]
|
||||
for t in arg_x_android:
|
||||
arg_x[conventions['F'].values.index(t)] = arg_x_android[t]
|
||||
vxmm = vxmm_android
|
||||
for vr, vf in redirects[k]:
|
||||
if all(c not in vr for c in depends_on_ld):
|
||||
continue
|
||||
function_writer(file, vr, vf + "_t")
|
||||
file.write("#elif !defined(HAVE_LD80BITS)\n")
|
||||
for c in vals_android:
|
||||
for t in vals_ld[c]:
|
||||
vals[c][c.values.index(t)] = vals_ld[c][t]
|
||||
for c in vals_nold:
|
||||
for t in vals_nold[c]:
|
||||
vals[c][c.values.index(t)] = vals_nold[c][t]
|
||||
for t in arg_s_android:
|
||||
arg_s[conventions['F'].values.index(t)] = arg_s_ld[t]
|
||||
for t in arg_s_nold:
|
||||
arg_s[conventions['F'].values.index(t)] = arg_s_nold[t]
|
||||
for t in arg_x_android:
|
||||
arg_x[conventions['F'].values.index(t)] = arg_x_ld[t]
|
||||
vxmm = vxmm_noandroid
|
||||
for vr, vf in redirects[k]:
|
||||
if all(c not in vr for c in depends_on_ld):
|
||||
continue
|
||||
function_writer(file, vr, vf + "_t")
|
||||
for c in vals_nold:
|
||||
for t in vals_nold[c]:
|
||||
vals[c][c.values.index(t)] = vals_ld[c][t]
|
||||
for t in arg_s_nold:
|
||||
arg_s[conventions['F'].values.index(t)] = arg_s_ld[t]
|
||||
file.write("#else // defined(HAVE_LD80BITS) && !defined(ANDROID)\n")
|
||||
for vr, vf in redirects[k]:
|
||||
if all(c not in vr for c in depends_on_ld):
|
||||
continue
|
||||
function_writer(file, vr, vf + "_t")
|
||||
file.write("#endif\n")
|
||||
if k != str(Clauses()):
|
||||
file.write("#endif\n")
|
||||
|
||||
# Write the isSimpleWrapper function
|
||||
file.write("\nint isSimpleWrapper(wrapper_t fun) {\n")
|
||||
for k in simple_idxs:
|
||||
if k != str(Clauses()):
|
||||
file.write("#if " + k + "\n")
|
||||
for vf, val in simple_wraps[k]:
|
||||
file.write("\tif (fun == &" + vf + ") return " + str(val) + ";\n")
|
||||
if k != str(Clauses()):
|
||||
file.write("#endif\n")
|
||||
file.write("\treturn 0;\n}\n")
|
||||
inttext = ""
|
||||
file.write("\n")
|
||||
for k1 in simple_idxs:
|
||||
file.write("#{inttext}if defined({k1})\nint isSimpleWrapper(wrapper_t fun) {{\n\tif (box64_is32bits) return 0;\n".format(inttext=inttext, k1=k1))
|
||||
inttext = "el"
|
||||
for k in simple_idxs[k1]:
|
||||
if k != str(Clauses()):
|
||||
file.write("#if " + k + "\n")
|
||||
for vf, val in simple_wraps[k1][k]:
|
||||
file.write("\tif (fun == &" + vf + ") return " + str(val) + ";\n")
|
||||
if k != str(Clauses()):
|
||||
file.write("#endif\n")
|
||||
file.write("\treturn 0;\n}\n")
|
||||
file.write("#else\nint isSimpleWrapper(wrapper_t fun) {\n\treturn 0;\n}\n#endif\n")
|
||||
|
||||
# Write the isRetX87Wrapper function
|
||||
file.write("\nint isRetX87Wrapper32(wrapper_t fun)\n#ifndef BOX32\n{ return 0; }\n#else\n ;\n#endif\n")
|
||||
file.write("\nint isRetX87Wrapper(wrapper_t fun) {\n")
|
||||
for k in retx87_idxs:
|
||||
if k != str(Clauses()):
|
||||
@@ -1430,7 +1758,30 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
if k != str(Clauses()):
|
||||
file.write("#endif\n")
|
||||
file.write(files_guard["wrapper.h"].format(lbr="{", rbr="}", version=ver))
|
||||
|
||||
# E v c w i I C W u U f d D l L p V O S N H P A x X Y b
|
||||
formats_map = ["(error)", "(error)", "i8", "i16", "i32", "i64", "u8", "u16", "u32", "u64", "f", "f", "Lf", "i64", "u64", "p", "p", "(error)", "(error)", "(error)", "u64", "p", "p", "(error)", "(error)", "(error)", "(error)"]
|
||||
|
||||
# Rewrite the x64printer.c file:
|
||||
with open(os.path.join(root, "src", "emu", "x64printer.c"), 'w') as file:
|
||||
file.write(files_header["x64printer.c"].format(lbr="{", rbr="}", version=ver))
|
||||
|
||||
for k in gbls:
|
||||
if k != str(Clauses()):
|
||||
file.write("#if {k}\n".format(k=k))
|
||||
for signature in gbls[k]:
|
||||
sig = signature if signature[2] != "E" else (signature[:2]+signature[3:])
|
||||
if any(letter in sig[2:] for letter in "OSNHxXYb") or signature.endswith('FE') or signature[1] == 'W':
|
||||
continue
|
||||
formats = sig[2:].replace("G", "UU")
|
||||
params = '' if formats == "v" else ", " + function_args_systemV(FunctionType(formats))[:-2]
|
||||
formats = '' if formats == "v" else ', '.join("%\" PRI{x} \"".format(x=formats_map[FunctionType(sig).get_convention().values.index(t)]) for t in formats)
|
||||
file.write(" {rbr} else if (w == {signature}) {lbr}\n".format(signature=signature, lbr="{", rbr="}"))
|
||||
file.write(" snprintf(buff, buffsz, \"%04d|%p: Calling %s({formats})\", tid, *(void**)(R_RSP), func{params});\n".format(formats=formats, params=params))
|
||||
if k != str(Clauses()):
|
||||
file.write("#endif\n")
|
||||
file.write(" }\n")
|
||||
file.write(files_guard["x64printer.c"].format(lbr="{", rbr="}", version=ver))
|
||||
|
||||
# Rewrite the *types.h files:
|
||||
for k in conventions:
|
||||
td_types[k][conventions[k].values.index('A')] = "va_list"
|
||||
@@ -1475,11 +1826,11 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
return 0
|
||||
|
||||
if __name__ == '__main__':
|
||||
limit = []
|
||||
limit: List[int] = []
|
||||
for i, v in enumerate(sys.argv):
|
||||
if v == "--":
|
||||
limit.append(i)
|
||||
Define.defines = list(map(DefineType, sys.argv[2:limit[0]]))
|
||||
if main(sys.argv[1], sys.argv[limit[0]+1:], "2.2.0.18") != 0:
|
||||
if main(sys.argv[1], sys.argv[limit[0]+1:], "2.5.0.24") != 0:
|
||||
exit(2)
|
||||
exit(0)
|
||||
Executable
+1657
File diff suppressed because it is too large.
Load diff
@@ -17,13 +17,6 @@ endif()
|
||||
|
||||
set(ENV{BOX64_LOG} 0)
|
||||
set(ENV{BOX64_NOBANNER} 1)
|
||||
if( EXISTS ${CMAKE_SOURCE_DIR}/x64lib )
|
||||
# we are inside box64 folder
|
||||
set(ENV{LD_LIBRARY_PATH} ${CMAKE_SOURCE_DIR}/x64lib)
|
||||
else()
|
||||
# we are inside build folder
|
||||
set(ENV{LD_LIBRARY_PATH} ${CMAKE_SOURCE_DIR}/../x64lib)
|
||||
endif( EXISTS ${CMAKE_SOURCE_DIR}/x64lib )
|
||||
|
||||
# run the test program, capture the stdout/stderr and the result var
|
||||
execute_process(
|
||||
|
||||
+342
@@ -0,0 +1,342 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box32.h"
|
||||
#include "custommem.h"
|
||||
#include "converter32.h"
|
||||
|
||||
#include "khash.h"
|
||||
|
||||
KHASH_MAP_INIT_INT64(to, ulong_t);
|
||||
KHASH_MAP_INIT_INT(from, uintptr_t);
|
||||
KHASH_MAP_INIT_STR(strings, ptr_t);
|
||||
|
||||
static kh_from_t* hash_from = NULL;
|
||||
static kh_to_t* hash_to = NULL;
|
||||
#define HASH_MSK 0xf000000f
|
||||
#define HASH_VAL 0x00ffffff
|
||||
#define HASH_SHIFT 4
|
||||
static uint32_t hash_cnt = 1;
|
||||
static pthread_rwlock_t hash_lock = {0};
|
||||
static int hash_running = 0;
|
||||
// locale
|
||||
static kh_from_t* locale_from = NULL;
|
||||
static kh_to_t* locale_to = NULL;
|
||||
static kh_strings_t* const_strings = NULL;
|
||||
|
||||
|
||||
void init_hash_helper() {
|
||||
hash_from = kh_init(from);
|
||||
hash_to = kh_init(to);
|
||||
locale_from = kh_init(from);
|
||||
locale_to = kh_init(to);
|
||||
const_strings = kh_init(strings);
|
||||
pthread_rwlock_init(&hash_lock, NULL);
|
||||
hash_running = 1;
|
||||
}
|
||||
void fini_hash_helper() {
|
||||
if(!hash_running)
|
||||
return;
|
||||
hash_running = 0;
|
||||
kh_destroy(from, hash_from);
|
||||
hash_from = NULL;
|
||||
kh_destroy(to, hash_to);
|
||||
hash_to = NULL;
|
||||
hash_cnt = 1;
|
||||
kh_destroy(from, locale_from);
|
||||
locale_from = NULL;
|
||||
kh_destroy(to, locale_to);
|
||||
locale_to = NULL;
|
||||
kh_destroy(strings, const_strings); //TODO: does not free memory correctly
|
||||
const_strings = NULL;
|
||||
pthread_rwlock_destroy(&hash_lock);
|
||||
}
|
||||
|
||||
// Convert from hash key to original 64bits value
|
||||
uintptr_t from_hash(ulong_t l) {
|
||||
// easy case first
|
||||
if((l&HASH_MSK)!=HASH_MSK) {
|
||||
return (uintptr_t)l;
|
||||
}
|
||||
if(l==0xffffffff) {
|
||||
return 0xffffffffffffffffll;
|
||||
}
|
||||
// get value from hash table second
|
||||
uintptr_t ret = 0;
|
||||
if(!hash_running) {
|
||||
//printf_log(LOG_INFO, "Warning, from_hash used but hash not running\n");
|
||||
return ret;
|
||||
}
|
||||
pthread_rwlock_rdlock(&hash_lock);
|
||||
khint_t k = kh_get(from, hash_from, l);
|
||||
if (k==kh_end(hash_from)) {
|
||||
ret = (uintptr_t)l;
|
||||
} else {
|
||||
ret = kh_value(hash_from, k);
|
||||
}
|
||||
pthread_rwlock_unlock(&hash_lock);
|
||||
return ret;
|
||||
}
|
||||
// same as from_hash
|
||||
uintptr_t from_hash_d(ulong_t l) {
|
||||
return from_hash(l);
|
||||
}
|
||||
|
||||
// Convert from 64bits to hash key, creating it if needed
|
||||
ulong_t to_hash(uintptr_t p) {
|
||||
if((p<0x100000000LL) && ((p&HASH_MSK)!=HASH_MSK))
|
||||
return (ulong_t)p;
|
||||
if(p==0xffffffffffffffffll) {
|
||||
return 0xffffffff;
|
||||
}
|
||||
ulong_t ret = 0;
|
||||
if(!hash_running) {
|
||||
//printf_log(LOG_INFO, "Warning, to_hash used but hash not running\n");
|
||||
return ret;
|
||||
}
|
||||
khint_t k;
|
||||
pthread_rwlock_rdlock(&hash_lock);
|
||||
k = kh_get(to, hash_to, p);
|
||||
if(k==kh_end(hash_to)) {
|
||||
// create a new key, but need write lock!
|
||||
pthread_rwlock_unlock(&hash_lock);
|
||||
pthread_rwlock_wrlock(&hash_lock);
|
||||
ret = HASH_MSK | (((hash_cnt++)&HASH_VAL)<<HASH_SHIFT);
|
||||
int r;
|
||||
k = kh_put(to, hash_to, p, &r);
|
||||
kh_value(hash_to, k) = ret;
|
||||
k = kh_put(from, hash_from, ret, &r);
|
||||
kh_value(hash_from, k) = p;
|
||||
} else {
|
||||
ret = kh_value(hash_to, k);
|
||||
}
|
||||
pthread_rwlock_unlock(&hash_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Convert from 64bits to hash key and delete the entry from both hash table
|
||||
ulong_t to_hash_d(uintptr_t p) {
|
||||
if((p<0x100000000LL) && ((p&HASH_MSK)!=HASH_MSK))
|
||||
return (ulong_t)p;
|
||||
if(p==0xffffffffffffffffll)
|
||||
return 0xffffffff;
|
||||
ulong_t ret = 0;
|
||||
if(!hash_running) {
|
||||
//printf_log(LOG_INFO, "Warning, to_hash_d used but hash not running\n");
|
||||
return ret;
|
||||
}
|
||||
khint_t k;
|
||||
pthread_rwlock_wrlock(&hash_lock);
|
||||
k = kh_get(to, hash_to, p);
|
||||
if(k==kh_end(hash_to)) {
|
||||
/// should this be an assert?
|
||||
} else {
|
||||
ret = kh_value(hash_to, k);
|
||||
// delete both entries
|
||||
//k = kh_get(to, hash_to, p);
|
||||
kh_del(to, hash_to, k);
|
||||
k = kh_get(from, hash_from, ret);
|
||||
kh_del(from, hash_from, k);
|
||||
}
|
||||
pthread_rwlock_unlock(&hash_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
typedef struct struct_locale_s {
|
||||
void* p0[13]; // struct __locale_data *
|
||||
void* p1; //const unsigned short int *__ctype_b;
|
||||
void* p2; //const int *__ctype_tolower;
|
||||
void* p3; //const int *__ctype_toupper;
|
||||
void* p4[13]; //const char*
|
||||
} struct_locale_t;
|
||||
// not a real structure
|
||||
#define LOCALE_SIGN 0x54abcd845412LL
|
||||
typedef struct struct_locale_32_s {
|
||||
ptr_t p0[13];
|
||||
ptr_t p1;
|
||||
ptr_t p2;
|
||||
ptr_t p3;
|
||||
ptr_t p4[13];
|
||||
uint64_t sign;
|
||||
struct_locale_t* org; // save the orginal locale
|
||||
// copy of the array, in case some apps use them
|
||||
unsigned short int type_b[384];
|
||||
int tolower[384];
|
||||
int tohigher[384];
|
||||
} struct_locale_32_t;
|
||||
|
||||
void to_struct_locale(ptr_t d, const struct_locale_t *src) {
|
||||
if (!src) return;
|
||||
struct_locale_32_t* dest = from_ptrv(d);
|
||||
// save the original locale
|
||||
dest->sign = LOCALE_SIGN;
|
||||
dest->org = (void*)src;
|
||||
//copy the 2 arrays
|
||||
for(int i=0; i<13; ++i) {
|
||||
dest->p0[i] = to_hashv(src->p0[i]);
|
||||
}
|
||||
for(int i=0; i<13; ++i) {
|
||||
dest->p4[i] = to_cstring(src->p4[i]);
|
||||
}
|
||||
// copy the 3 ctype int (1st is short int, but int will do)
|
||||
memcpy(dest->type_b, src->p1-128*sizeof(short), 384*sizeof(short));
|
||||
memcpy(dest->tolower, src->p2-128*sizeof(int), 384*sizeof(int));
|
||||
memcpy(dest->tohigher, src->p3-128*sizeof(int), 384*sizeof(int));
|
||||
dest->p1 = to_ptrv(dest->type_b)+128*sizeof(short);
|
||||
dest->p2 = to_ptrv(dest->tolower)+128*sizeof(int);
|
||||
dest->p3 = to_ptrv(dest->tohigher)+128*sizeof(int);
|
||||
}
|
||||
void free_struct_locale(const struct_locale_t *src) {
|
||||
for(int i=0; i<13; ++i) {
|
||||
to_hash_d((uintptr_t)src->p0[i]);
|
||||
}
|
||||
/*for(int i=0; i<13; ++i) {
|
||||
to_hash_d((uintptr_t)src->p4[i]);
|
||||
}*/
|
||||
}
|
||||
|
||||
// Convert from locale key to original 64bits value
|
||||
void* from_locale(ptr_t l) {
|
||||
// easy case first
|
||||
if(l < 0x100) {
|
||||
return from_ptrv(l);
|
||||
}
|
||||
if(l == 0xffffffff) {
|
||||
return (void*)-1;
|
||||
}
|
||||
// get value from hash table second
|
||||
void* ret = 0;
|
||||
if(!hash_running) {
|
||||
//printf_log(LOG_INFO, "Warning, from_locale used but hash not running\n");
|
||||
return ret;
|
||||
}
|
||||
struct_locale_32_t* loc = from_ptrv(l);
|
||||
if(loc->sign==LOCALE_SIGN)
|
||||
return loc->org;
|
||||
pthread_rwlock_rdlock(&hash_lock);
|
||||
khint_t k = kh_get(from, locale_from, l);
|
||||
if (k==kh_end(locale_from)) {
|
||||
ret = from_ptrv(l);
|
||||
} else {
|
||||
ret = (void*)kh_value(locale_from, k);
|
||||
}
|
||||
pthread_rwlock_unlock(&hash_lock);
|
||||
//from_struct_locale((struct_locale_t*)ret, l);
|
||||
return ret;
|
||||
}
|
||||
// same as from_locale
|
||||
void* from_locale_d(ptr_t l) {
|
||||
return from_locale(l);
|
||||
}
|
||||
|
||||
// Convert from 64bits to locale key, creating it if needed
|
||||
ptr_t to_locale(void* p) {
|
||||
if((uintptr_t)p < 0x100) {
|
||||
return to_ptrv(p);
|
||||
}
|
||||
if(p == (void*)-1) {
|
||||
return 0xffffffff;
|
||||
}
|
||||
ptr_t ret = 0;
|
||||
if(!hash_running) {
|
||||
//printf_log(LOG_INFO, "Warning, to_locale used but hash not running\n");
|
||||
return ret;
|
||||
}
|
||||
khint_t k;
|
||||
pthread_rwlock_rdlock(&hash_lock);
|
||||
k = kh_get(to, locale_to, (uintptr_t)p);
|
||||
int conv = 0;
|
||||
if(k==kh_end(locale_to)) {
|
||||
// create a new key, but need write lock!
|
||||
pthread_rwlock_unlock(&hash_lock);
|
||||
pthread_rwlock_wrlock(&hash_lock);
|
||||
// a locale_t is 5 pointer!
|
||||
void* m = calloc(1, sizeof(struct_locale_32_t)); // the 3 ctype value are also inside the locale struct
|
||||
ret = to_ptrv(m);
|
||||
// add to hash maps
|
||||
int r;
|
||||
k = kh_put(to, locale_to, (uintptr_t)p, &r);
|
||||
kh_value(locale_to, k) = ret;
|
||||
k = kh_put(from, locale_from, ret, &r);
|
||||
kh_value(locale_from, k) = (uintptr_t)p;
|
||||
conv = 1;
|
||||
} else {
|
||||
ret = kh_value(locale_to, k);
|
||||
}
|
||||
pthread_rwlock_unlock(&hash_lock);
|
||||
if(conv)
|
||||
to_struct_locale(ret, (struct_locale_t*)p);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Convert from 64bits to hash key and delete the entry from both hash table
|
||||
ptr_t to_locale_d(void* p) {
|
||||
if((uintptr_t)p < 0x100)
|
||||
return to_ptrv(p);
|
||||
ptr_t ret = 0;
|
||||
if(!hash_running)
|
||||
return ret;
|
||||
khint_t k;
|
||||
pthread_rwlock_wrlock(&hash_lock);
|
||||
k = kh_get(to, locale_to, (uintptr_t)p);
|
||||
if(k==kh_end(locale_to)) {
|
||||
/// should this be an assert?
|
||||
} else {
|
||||
ret = kh_value(locale_to, k);
|
||||
// free the memory
|
||||
free_struct_locale(p);
|
||||
free(from_ptrv(ret));
|
||||
// delete both entries
|
||||
k = kh_get(to, locale_to, (uintptr_t)p);
|
||||
kh_del(to, locale_to, k);
|
||||
k = kh_get(from, locale_from, ret);
|
||||
kh_del(from, locale_from, k);
|
||||
}
|
||||
pthread_rwlock_unlock(&hash_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
char* from_cstring(ptr_t p) {
|
||||
return (char*)from_ptrv(p);
|
||||
}
|
||||
|
||||
ptr_t to_cstring(char* p) {
|
||||
if((uintptr_t)p<0x100000000LL)
|
||||
return to_ptrv(p);
|
||||
ptr_t ret = 0;
|
||||
pthread_rwlock_rdlock(&hash_lock);
|
||||
khint_t k = kh_get(strings, const_strings, p);
|
||||
if(k==kh_end(const_strings)) {
|
||||
// create a new key, but need write lock!
|
||||
pthread_rwlock_unlock(&hash_lock);
|
||||
pthread_rwlock_wrlock(&hash_lock);
|
||||
ret = to_ptrv(box32_strdup(p));
|
||||
int r;
|
||||
k = kh_put(strings, const_strings, (char*)from_ptrv(ret), &r);
|
||||
kh_value(const_strings, k) = ret;
|
||||
} else
|
||||
ret = kh_value(const_strings, k);
|
||||
pthread_rwlock_unlock(&hash_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ptr_t to_cstring_d(char* p) {
|
||||
if((uintptr_t)p<0x100000000LL)
|
||||
return to_ptrv(p);
|
||||
ptr_t ret = 0;
|
||||
pthread_rwlock_wrlock(&hash_lock);
|
||||
khint_t k = kh_get(strings, const_strings, p);
|
||||
if(k==kh_end(const_strings)) {
|
||||
// assert?
|
||||
} else {
|
||||
ret = kh_value(const_strings, k);
|
||||
kh_del(strings, const_strings, k);
|
||||
box32_free(from_ptrv(ret));
|
||||
}
|
||||
pthread_rwlock_unlock(&hash_lock);
|
||||
return ret;
|
||||
}
|
||||
+57
-55
@@ -7,6 +7,7 @@
|
||||
#include <sys/mman.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "os.h"
|
||||
#include "box64context.h"
|
||||
#include "debug.h"
|
||||
#include "elfloader.h"
|
||||
@@ -14,13 +15,18 @@
|
||||
#include "threads.h"
|
||||
#include "x64trace.h"
|
||||
#include "bridge.h"
|
||||
#include "alternate.h"
|
||||
#include "librarian.h"
|
||||
#include "library.h"
|
||||
#include "wrapper.h"
|
||||
#include "x64emu.h"
|
||||
#include "signals.h"
|
||||
#include "rcfile.h"
|
||||
#include "gltools.h"
|
||||
#include "rbtree.h"
|
||||
#include "box64cpu.h"
|
||||
#ifdef BOX32
|
||||
#include "box32.h"
|
||||
#endif
|
||||
|
||||
EXPORTDYN
|
||||
void initAllHelpers(box64context_t* context)
|
||||
@@ -29,6 +35,9 @@ void initAllHelpers(box64context_t* context)
|
||||
if(inited)
|
||||
return;
|
||||
my_context = context;
|
||||
#ifdef BOX32
|
||||
init_hash_helper();
|
||||
#endif
|
||||
init_pthread_helper();
|
||||
init_bridge_helper();
|
||||
init_signal_helper(context);
|
||||
@@ -41,10 +50,12 @@ void finiAllHelpers(box64context_t* context)
|
||||
static int finied = 0;
|
||||
if(finied)
|
||||
return;
|
||||
DeleteParams();
|
||||
fini_pthread_helper(context);
|
||||
fini_signal_helper();
|
||||
fini_bridge_helper();
|
||||
#ifdef BOX32
|
||||
fini_hash_helper();
|
||||
#endif
|
||||
fini_custommem_helper(context);
|
||||
finied = 1;
|
||||
}
|
||||
@@ -66,46 +77,14 @@ void free_tlsdatasize(void* p)
|
||||
if(!p)
|
||||
return;
|
||||
tlsdatasize_t *data = (tlsdatasize_t*)p;
|
||||
box_free(data->ptr);
|
||||
box_free(p);
|
||||
actual_free(data->ptr);
|
||||
actual_free(p);
|
||||
if(my_context)
|
||||
pthread_setspecific(my_context->tlskey, NULL);
|
||||
}
|
||||
|
||||
void x64Syscall(x64emu_t *emu);
|
||||
|
||||
int unlockMutex()
|
||||
{
|
||||
int ret = unlockCustommemMutex();
|
||||
int i;
|
||||
#ifdef USE_CUSTOM_MUTEX
|
||||
uint32_t tid = (uint32_t)GetTID();
|
||||
#define GO(A, B) \
|
||||
i = (native_lock_storeifref2_d(&A, 0, tid)==tid); \
|
||||
if(i) { \
|
||||
ret|=(1<<B); \
|
||||
}
|
||||
#else
|
||||
#define GO(A, B) \
|
||||
i = checkUnlockMutex(&A); \
|
||||
if(i) { \
|
||||
ret|=(1<<B); \
|
||||
}
|
||||
#endif
|
||||
|
||||
GO(my_context->mutex_trace, 7)
|
||||
#ifdef DYNAREC
|
||||
GO(my_context->mutex_dyndump, 8)
|
||||
#else
|
||||
GO(my_context->mutex_lock, 8)
|
||||
#endif
|
||||
GO(my_context->mutex_tls, 9)
|
||||
GO(my_context->mutex_thread, 10)
|
||||
GO(my_context->mutex_bridge, 11)
|
||||
#undef GO
|
||||
|
||||
return ret;
|
||||
}
|
||||
void x86Syscall(x64emu_t *emu);
|
||||
|
||||
void relockMutex(int locks)
|
||||
{
|
||||
@@ -126,7 +105,7 @@ void relockMutex(int locks)
|
||||
#undef GO
|
||||
}
|
||||
|
||||
static void init_mutexes(box64context_t* context)
|
||||
void init_mutexes(box64context_t* context)
|
||||
{
|
||||
#ifndef DYNAREC
|
||||
pthread_mutexattr_t attr;
|
||||
@@ -169,8 +148,8 @@ static void atfork_child_box64context(void)
|
||||
|
||||
void freeCycleLog(box64context_t* ctx)
|
||||
{
|
||||
if(cycle_log) {
|
||||
for(int i=0; i<cycle_log; ++i) {
|
||||
if(BOX64ENV(rolling_log)) {
|
||||
for(int i=0; i<BOX64ENV(rolling_log); ++i) {
|
||||
box_free(ctx->log_call[i]);
|
||||
box_free(ctx->log_ret[i]);
|
||||
}
|
||||
@@ -182,10 +161,10 @@ void freeCycleLog(box64context_t* ctx)
|
||||
}
|
||||
void initCycleLog(box64context_t* context)
|
||||
{
|
||||
if(cycle_log) {
|
||||
context->log_call = (char**)box_calloc(cycle_log, sizeof(char*));
|
||||
context->log_ret = (char**)box_calloc(cycle_log, sizeof(char*));
|
||||
for(int i=0; i<cycle_log; ++i) {
|
||||
if(context && BOX64ENV(rolling_log)) {
|
||||
context->log_call = (char**)box_calloc(BOX64ENV(rolling_log), sizeof(char*));
|
||||
context->log_ret = (char**)box_calloc(BOX64ENV(rolling_log), sizeof(char*));
|
||||
for(int i=0; i<BOX64ENV(rolling_log); ++i) {
|
||||
context->log_call[i] = (char*)box_calloc(256, 1);
|
||||
context->log_ret[i] = (char*)box_calloc(128, 1);
|
||||
}
|
||||
@@ -211,25 +190,33 @@ box64context_t *NewBox64Context(int argc)
|
||||
|
||||
init_custommem_helper(context);
|
||||
|
||||
context->maplib = NewLibrarian(context, 1);
|
||||
context->local_maplib = NewLibrarian(context, 1);
|
||||
context->maplib = NewLibrarian(context);
|
||||
context->local_maplib = NewLibrarian(context);
|
||||
context->versym = NewDictionnary();
|
||||
context->system = NewBridge();
|
||||
// Cannot use Bridge name as the map is not initialized yet
|
||||
// create vsyscall
|
||||
context->vsyscall = AddBridge(context->system, vFEv, x64Syscall, 0, NULL);
|
||||
context->vsyscall = AddBridge(context->system, vFEv, box64_is32bits?x86Syscall:x64Syscall, 0, NULL);
|
||||
// create the vsyscalls
|
||||
context->vsyscalls[0] = AddVSyscall(context->system, 96);
|
||||
context->vsyscalls[1] = AddVSyscall(context->system, 201);
|
||||
context->vsyscalls[2] = AddVSyscall(context->system, 309);
|
||||
// create the alternate to map at address
|
||||
addAlternate((void*)0xffffffffff600000, (void*)context->vsyscalls[0]);
|
||||
addAlternate((void*)0xffffffffff600400, (void*)context->vsyscalls[1]);
|
||||
addAlternate((void*)0xffffffffff600800, (void*)context->vsyscalls[2]);
|
||||
if(box64_is32bits) {
|
||||
#ifdef BOX32
|
||||
addAlternate((void*)0xffffe400, from_ptrv(context->vsyscall));
|
||||
#endif
|
||||
} else {
|
||||
context->vsyscalls[0] = AddVSyscall(context->system, 96);
|
||||
context->vsyscalls[1] = AddVSyscall(context->system, 201);
|
||||
context->vsyscalls[2] = AddVSyscall(context->system, 309);
|
||||
// create the alternate to map at address
|
||||
addAlternate((void*)0xffffffffff600000, (void*)context->vsyscalls[0]);
|
||||
addAlternate((void*)0xffffffffff600400, (void*)context->vsyscalls[1]);
|
||||
addAlternate((void*)0xffffffffff600800, (void*)context->vsyscalls[2]);
|
||||
}
|
||||
// create exit bridge
|
||||
context->exit_bridge = AddBridge(context->system, NULL, NULL, 0, NULL);
|
||||
// get handle to box64 itself
|
||||
#ifndef STATICBUILD
|
||||
context->box64lib = dlopen(NULL, RTLD_NOW|RTLD_GLOBAL);
|
||||
#endif
|
||||
context->dlprivate = NewDLPrivate();
|
||||
|
||||
context->argc = argc;
|
||||
@@ -262,8 +249,13 @@ box64context_t *NewBox64Context(int argc)
|
||||
context->segtls[4].is32bits = 1;
|
||||
|
||||
context->globdata = NewMapSymbols();
|
||||
context->uniques = NewMapSymbols();
|
||||
|
||||
initAllHelpers(context);
|
||||
|
||||
#ifdef DYNAREC
|
||||
context->db_sizes = rbtree_init("db_sizes");
|
||||
#endif
|
||||
|
||||
return context;
|
||||
}
|
||||
@@ -278,7 +270,7 @@ void FreeBox64Context(box64context_t** context)
|
||||
if(--(*context)->forked >= 0)
|
||||
return;
|
||||
|
||||
box64context_t* ctx = *context; // local copy to do the cleanning
|
||||
box64context_t* ctx = *context; // local copy to do the cleaning
|
||||
|
||||
//clean_current_emuthread(); // cleaning main thread seems a bad idea
|
||||
if(ctx->local_maplib)
|
||||
@@ -335,8 +327,12 @@ void FreeBox64Context(box64context_t** context)
|
||||
|
||||
FreeBridge(&ctx->system);
|
||||
|
||||
#ifndef STATICBUILD
|
||||
freeGLProcWrapper(ctx);
|
||||
freeALProcWrapper(ctx);
|
||||
#ifdef BOX32
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if(ctx->stack_clone)
|
||||
box_free(ctx->stack_clone);
|
||||
@@ -358,6 +354,12 @@ void FreeBox64Context(box64context_t** context)
|
||||
FreeX64Emu(&ctx->emu_sig);
|
||||
|
||||
FreeMapSymbols(&ctx->globdata);
|
||||
FreeMapSymbols(&ctx->uniques);
|
||||
|
||||
#ifdef DYNAREC
|
||||
//dynarec_log(LOG_INFO, "BOX64 Dynarec at exit: Max DB=%d, righter=%d\n", ctx->max_db_size, rb_get_righter(ctx->db_sizes));
|
||||
rbtree_delete(ctx->db_sizes);
|
||||
#endif
|
||||
|
||||
finiAllHelpers(ctx);
|
||||
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
#define __BOX64_VERSION_H_
|
||||
|
||||
#define BOX64_MAJOR 0
|
||||
#define BOX64_MINOR 2
|
||||
#define BOX64_MINOR 3
|
||||
#define BOX64_REVISION 6
|
||||
|
||||
#endif //__BOX64_VERSION_H_
|
||||
+15
-17
@@ -1,27 +1,25 @@
|
||||
#include <stdio.h>
|
||||
#include "debug.h"
|
||||
#include "box64version.h"
|
||||
#ifdef NOGIT
|
||||
#define GITREV "nogit"
|
||||
#include "build_info.h"
|
||||
|
||||
#if defined(DYNAREC)
|
||||
#define WITH_DYNAREC_STR " with Dynarec"
|
||||
#else
|
||||
#include "git_head.h"
|
||||
#define WITH_DYNAREC_STR ""
|
||||
#endif
|
||||
|
||||
void PrintBox64Version()
|
||||
#ifdef HAVE_TRACE
|
||||
#define WITH_TRACE_STR " with trace"
|
||||
#else
|
||||
#define WITH_TRACE_STR ""
|
||||
#endif
|
||||
|
||||
void PrintBox64Version(int prefix)
|
||||
{
|
||||
printf("Box64%s%s v%d.%d.%d %s built on %s %s\n",
|
||||
#ifdef HAVE_TRACE
|
||||
" with trace",
|
||||
#else
|
||||
"",
|
||||
#endif
|
||||
#ifdef DYNAREC
|
||||
" with Dynarec",
|
||||
#else
|
||||
"",
|
||||
#endif
|
||||
BOX64_MAJOR, BOX64_MINOR, BOX64_REVISION,
|
||||
GITREV,
|
||||
PrintfFtrace(prefix, BOX64_BUILD_INFO_STRING WITH_DYNAREC_STR WITH_TRACE_STR " built on %s %s\n",
|
||||
__DATE__, __TIME__);
|
||||
}
|
||||
|
||||
#undef WITH_TRACE
|
||||
#undef WITH_DYNAREC
|
||||
+35
-2
@@ -1,6 +1,39 @@
|
||||
#include "box64version.h"
|
||||
#ifdef NOGIT
|
||||
#define GITREV "nogit"
|
||||
#else
|
||||
#include "git_head.h"
|
||||
#endif
|
||||
|
||||
#ifndef __BUILD_INFO_H__
|
||||
#define __BUILD_INFO_H__
|
||||
|
||||
void PrintBox64Version(void);
|
||||
|
||||
#endif //__BUILD_INFO_H__
|
||||
#if defined(DYNAREC) && (defined(ARM64) || defined(RV64) || defined(LA64))
|
||||
#if defined(ARM64)
|
||||
#define ARCH_STR " arm64"
|
||||
#elif defined(RV64)
|
||||
#define ARCH_STR " riscv64"
|
||||
#elif defined(LA64)
|
||||
#define ARCH_STR " loongarch64"
|
||||
#endif
|
||||
#else
|
||||
#define ARCH_STR ""
|
||||
#endif
|
||||
|
||||
void PrintBox64Version(int prefix);
|
||||
|
||||
#define BOX64_BUILD_INFO_STR_HELPER(x) #x
|
||||
#define BOX64_BUILD_INFO_STR(x) BOX64_BUILD_INFO_STR_HELPER(x)
|
||||
|
||||
#ifdef _WIN32
|
||||
#define BOX64_STR "WowBox64"
|
||||
#else
|
||||
#define BOX64_STR "Box64"
|
||||
#endif
|
||||
|
||||
#define BOX64_BUILD_INFO_STRING \
|
||||
BOX64_STR ARCH_STR \
|
||||
" v" BOX64_BUILD_INFO_STR(BOX64_MAJOR) "." BOX64_BUILD_INFO_STR(BOX64_MINOR) "." BOX64_BUILD_INFO_STR(BOX64_REVISION) " " GITREV
|
||||
|
||||
#endif //__BUILD_INFO_H__
|
||||
+1623
File diff suppressed because it is too large.
Load diff
+1418
-892
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,56 @@
|
||||
#define _GNU_SOURCE /* See feature_test_macros(7) */
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "env.h"
|
||||
|
||||
#ifndef MAP_FAILED
|
||||
#define MAP_FAILED ((void *) -1)
|
||||
#endif
|
||||
|
||||
#define EXPORT __attribute__((visibility("default")))
|
||||
#ifdef BUILD_DYNAMIC
|
||||
#define EXPORTDYN __attribute__((visibility("default")))
|
||||
#else
|
||||
#define EXPORTDYN
|
||||
#endif
|
||||
|
||||
#ifndef MAP_32BIT
|
||||
#define MAP_32BIT 0x40
|
||||
#endif
|
||||
|
||||
typedef void x64emu_t;
|
||||
extern void* mapallmem;
|
||||
extern int box64_is32bits;
|
||||
void setProtection(uintptr_t addr, size_t size, uint32_t prot);
|
||||
void freeProtection(uintptr_t addr, size_t size);
|
||||
void* InternalMmap(void* addr, unsigned long length, int prot, int flags, int fd, ssize_t offset);
|
||||
int InternalMunmap(void* addr, unsigned long length);
|
||||
void* box_mmap(void *addr, unsigned long length, int prot, int flags, int fd, ssize_t offset);
|
||||
|
||||
void* my_mmap64(x64emu_t* emu, void *addr, unsigned long length, int prot, int flags, int fd, ssize_t offset);
|
||||
|
||||
extern int running32bits;
|
||||
extern box64env_t box64env;
|
||||
|
||||
EXPORT void* mmap64(void *addr, unsigned long length, int prot, int flags, int fd, ssize_t offset)
|
||||
{
|
||||
void* ret;
|
||||
if(!addr && ((running32bits && BOX64ENV(mmap32)) || (flags&MAP_32BIT) || box64_is32bits))
|
||||
ret = box_mmap(addr, length, prot, flags | MAP_32BIT, fd, offset);
|
||||
else
|
||||
ret = InternalMmap(addr, length, prot, flags, fd, offset);
|
||||
if(ret!=MAP_FAILED && mapallmem)
|
||||
setProtection((uintptr_t)ret, length, prot);
|
||||
return ret;
|
||||
}
|
||||
EXPORT void* mmap(void *addr, unsigned long length, int prot, int flags, int fd, ssize_t offset) __attribute__((alias("mmap64")));
|
||||
|
||||
EXPORT int munmap(void* addr, unsigned long length)
|
||||
{
|
||||
int ret = InternalMunmap(addr, length);
|
||||
if(!ret && mapallmem) {
|
||||
freeProtection((uintptr_t)addr, length);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -5,6 +5,41 @@
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
ARM64 Linux Call Convention
|
||||
|
||||
SP The Stack Pointer.
|
||||
r30 LR The Link Register.
|
||||
r29 FP The Frame Pointer
|
||||
r19…r28 Callee-saved registers
|
||||
r18 The Platform Register, if needed; otherwise a temporary register. See notes.
|
||||
r17 IP1 The second intra-procedure-call temporary register (can be used by call veneers and PLT code); at other times may be used as a temporary register.
|
||||
r16 IP0 The first intra-procedure-call scratch register (can be used by call veneers and PLT code); at other times may be used as a temporary register.
|
||||
r9…r15 Temporary registers
|
||||
r8 Indirect result location register
|
||||
r0…r7 Parameter/result registers
|
||||
|
||||
For SIMD:
|
||||
The first eight registers, v0-v7, are used to pass argument values into a subroutine and to return result values from a function.
|
||||
They may also be used to hold intermediate values within a routine (but, in general, only between subroutine calls).
|
||||
|
||||
Registers v8-v15 must be preserved by a callee across subroutine calls;
|
||||
the remaining registers (v0-v7, v16-v31) do not need to be preserved (or should be preserved by the caller).
|
||||
Additionally, only the bottom 64 bits of each value stored in v8-v15 need to be preserved [8];
|
||||
it is the responsibility of the caller to preserve larger values.
|
||||
|
||||
For SVE:
|
||||
z0-z7 are used to pass scalable vector arguments to a subroutine, and to return scalable vector results from a function.
|
||||
If a subroutine takes at least one argument in scalable vector registers or scalable predicate registers,
|
||||
or returns results in such regisers, the subroutine must ensure that the entire contents of z8-z23 are preserved across the call.
|
||||
In other cases it need only preserve the low 64 bits of z8-z15, as described in SIMD and Floating-Point registers.
|
||||
p0-p3 are used to pass scalable predicate arguments to a subroutine and to return scalable predicate results from a function.
|
||||
If a subroutine takes at least one argument in scalable vector registers or scalable predicate registers,
|
||||
or returns results in such registers, the subroutine must ensure that p4-p15 are preserved across the call.
|
||||
In other cases it need not preserve any scalable predicate register contents.
|
||||
|
||||
*/
|
||||
|
||||
// x86 Register mapping
|
||||
#define xRAX 10
|
||||
#define xRCX 11
|
||||
@@ -25,6 +60,10 @@
|
||||
#define xFlags 26
|
||||
#define xRIP 27
|
||||
#define xSavedSP 28
|
||||
|
||||
// convert a x86 register to native according to the register mapping
|
||||
#define TO_NAT(A) (xRAX + (A))
|
||||
|
||||
// 32bits version
|
||||
#define wEAX xRAX
|
||||
#define wECX xRCX
|
||||
@@ -50,7 +89,8 @@
|
||||
#define x4 4
|
||||
#define x5 5
|
||||
#define x6 6
|
||||
#define x7 7
|
||||
#define x87pc 7
|
||||
// x87 can be a scratch, but check if it's used as x87 PC and restore if needed in that case
|
||||
// 32bits version of scratch
|
||||
#define w1 x1
|
||||
#define w2 x2
|
||||
@@ -58,7 +98,7 @@
|
||||
#define w4 x4
|
||||
#define w5 x5
|
||||
#define w6 x6
|
||||
#define w7 x7
|
||||
#define w87pc x87pc
|
||||
// emu is r0
|
||||
#define xEmu 0
|
||||
// ARM64 LR
|
||||
@@ -70,24 +110,49 @@
|
||||
#define wZR xZR
|
||||
|
||||
// conditions
|
||||
// Z == 1
|
||||
#define cEQ 0b0000
|
||||
// Z != 1
|
||||
#define cNE 0b0001
|
||||
// C == 1
|
||||
#define cCS 0b0010
|
||||
// C == 1
|
||||
#define cHS cCS
|
||||
// C != 1
|
||||
#define cCC 0b0011
|
||||
// C != 1
|
||||
#define cLO cCC
|
||||
// N == 1
|
||||
#define cMI 0b0100
|
||||
// N != 1
|
||||
#define cPL 0b0101
|
||||
// V == 1
|
||||
#define cVS 0b0110
|
||||
// V != 1
|
||||
#define cVC 0b0111
|
||||
// C == 1 && Z == 0
|
||||
#define cHI 0b1000
|
||||
// C !=1 || Z == 1
|
||||
#define cLS 0b1001
|
||||
// N == V
|
||||
#define cGE 0b1010
|
||||
// N != V
|
||||
#define cLT 0b1011
|
||||
// N == V && Z == 0
|
||||
#define cGT 0b1100
|
||||
// N != V || Z == 1
|
||||
#define cLE 0b1101
|
||||
// always
|
||||
#define c__ 0b1110
|
||||
|
||||
//FCMP type of opcode produce:
|
||||
// if any NAN: CV / v1 == v2: ZC / v1 < v2: N / v1 > v2: C
|
||||
|
||||
int convert_bitmask(uint64_t bitmask);
|
||||
#define convert_bitmask_w(A) convert_bitmask(((uint64_t)(A) << 32) + (uint32_t)(A))
|
||||
#define convert_bitmask_x(A) convert_bitmask((uint64_t)A)
|
||||
#define convert_bitmask_xw(A) convert_bitmask(rex.w?((uint64_t)(A)):(((uint64_t)(A) << 32) + (uint32_t)(A)))
|
||||
|
||||
#define invCond(cond) ((cond)^0b0001)
|
||||
|
||||
// MOVZ
|
||||
@@ -111,23 +176,8 @@
|
||||
#define MOVKw(Rd, imm16) EMIT(MOVK_gen(0, 0, ((uint16_t)(imm16))&0xffff, Rd))
|
||||
#define MOVKw_LSL(Rd, imm16, shift) EMIT(MOVK_gen(0, (shift)/16, ((uint16_t)(imm16))&0xffff, Rd))
|
||||
|
||||
// This macro will give a -Wsign-compare warning, probably bug #38341
|
||||
#define MOV32w(Rd, imm32) \
|
||||
if(~((uint32_t)(imm32))<0xffffu) { \
|
||||
MOVNw(Rd, (~(uint32_t)(imm32))&0xffff); \
|
||||
} else { \
|
||||
MOVZw(Rd, (imm32)&0xffff); \
|
||||
if((imm32)&0xffff0000) {MOVKw_LSL(Rd, ((imm32)>>16)&0xffff, 16);} \
|
||||
}
|
||||
#define MOV64x(Rd, imm64) \
|
||||
if(~((uint64_t)(imm64))<0xffff) { \
|
||||
MOVNx(Rd, (~(uint64_t)(imm64))&0xffff); \
|
||||
} else { \
|
||||
MOVZx(Rd, ((uint64_t)(imm64))&0xffff); \
|
||||
if(((uint64_t)(imm64))&0xffff0000) {MOVKx_LSL(Rd, (((uint64_t)(imm64))>>16)&0xffff, 16);} \
|
||||
if(((uint64_t)(imm64))&0xffff00000000LL) {MOVKx_LSL(Rd, (((uint64_t)(imm64))>>32)&0xffff, 32);} \
|
||||
if(((uint64_t)(imm64))&0xffff000000000000LL) {MOVKx_LSL(Rd, (((uint64_t)(imm64))>>48)&0xffff, 48);} \
|
||||
}
|
||||
#define MOV32w(Rd, imm32) arm64_move32(dyn, ninst, Rd, imm32)
|
||||
#define MOV64x(Rd, imm64) arm64_move64(dyn, ninst, Rd, imm64)
|
||||
|
||||
#define MOV64xw(Rd, imm64) if(rex.w) {MOV64x(Rd, imm64);} else {MOV32w(Rd, imm64);}
|
||||
#define MOV64z(Rd, imm64) if(rex.is32bits) {MOV32w(Rd, imm64);} else {MOV64x(Rd, imm64);}
|
||||
@@ -136,38 +186,49 @@
|
||||
// ADD / SUB
|
||||
#define ADDSUB_REG_gen(sf, op, S, shift, Rm, imm6, Rn, Rd) ((sf)<<31 | (op)<<30 | (S)<<29 | 0b01011<<24 | (shift)<<22 | (Rm)<<16 | (imm6)<<10 | (Rn)<<5 | (Rd))
|
||||
#define ADDx_REG(Rd, Rn, Rm) EMIT(ADDSUB_REG_gen(1, 0, 0, 0b00, Rm, 0, Rn, Rd))
|
||||
#define ADDSx_REG(Rd, Rn, Rm) EMIT(ADDSUB_REG_gen(1, 0, 1, 0b00, Rm, 0, Rn, Rd))
|
||||
#define ADDSx_REG(Rd, Rn, Rm) FEMIT(ADDSUB_REG_gen(1, 0, 1, 0b00, Rm, 0, Rn, Rd))
|
||||
#define ADDx_REG_LSL(Rd, Rn, Rm, lsl) EMIT(ADDSUB_REG_gen(1, 0, 0, 0b00, Rm, lsl, Rn, Rd))
|
||||
#define ADDz_REG_LSL(Rd, Rn, Rm, lsl) EMIT(ADDSUB_REG_gen(rex.is32bits?0:1, 0, 0, 0b00, Rm, lsl, Rn, Rd))
|
||||
#define ADDw_REG(Rd, Rn, Rm) EMIT(ADDSUB_REG_gen(0, 0, 0, 0b00, Rm, 0, Rn, Rd))
|
||||
#define ADDSw_REG(Rd, Rn, Rm) EMIT(ADDSUB_REG_gen(0, 0, 1, 0b00, Rm, 0, Rn, Rd))
|
||||
#define ADDSw_REG(Rd, Rn, Rm) FEMIT(ADDSUB_REG_gen(0, 0, 1, 0b00, Rm, 0, Rn, Rd))
|
||||
#define ADDw_REG_LSL(Rd, Rn, Rm, lsl) EMIT(ADDSUB_REG_gen(0, 0, 0, 0b00, Rm, lsl, Rn, Rd))
|
||||
#define ADDSw_REG_LSL(Rd, Rn, Rm, lsl) FEMIT(ADDSUB_REG_gen(0, 0, 1, 0b00, Rm, lsl, Rn, Rd))
|
||||
#define ADDxw_REG(Rd, Rn, Rm) EMIT(ADDSUB_REG_gen(rex.w, 0, 0, 0b00, Rm, 0, Rn, Rd))
|
||||
#define ADDz_REG(Rd, Rn, Rm) EMIT(ADDSUB_REG_gen(rex.is32bits?0:1, 0, 0, 0b00, Rm, 0, Rn, Rd))
|
||||
#define ADDSxw_REG(Rd, Rn, Rm) EMIT(ADDSUB_REG_gen(rex.w, 0, 1, 0b00, Rm, 0, Rn, Rd))
|
||||
#define ADDSxw_REG(Rd, Rn, Rm) FEMIT(ADDSUB_REG_gen(rex.w, 0, 1, 0b00, Rm, 0, Rn, Rd))
|
||||
#define ADDxw_REG_LSR(Rd, Rn, Rm, lsr) EMIT(ADDSUB_REG_gen(rex.w, 0, 0, 0b01, Rm, lsr, Rn, Rd))
|
||||
|
||||
#define ADDSUB_IMM_gen(sf, op, S, shift, imm12, Rn, Rd) ((sf)<<31 | (op)<<30 | (S)<<29 | 0b10001<<24 | (shift)<<22 | (imm12)<<10 | (Rn)<<5 | (Rd))
|
||||
#define ADDx_U12(Rd, Rn, imm12) EMIT(ADDSUB_IMM_gen(1, 0, 0, 0b00, (imm12)&0xfff, Rn, Rd))
|
||||
#define ADDSx_U12(Rd, Rn, imm12) EMIT(ADDSUB_IMM_gen(1, 0, 1, 0b00, (imm12)&0xfff, Rn, Rd))
|
||||
#define ADDSx_U12(Rd, Rn, imm12) FEMIT(ADDSUB_IMM_gen(1, 0, 1, 0b00, (imm12)&0xfff, Rn, Rd))
|
||||
#define ADDw_U12(Rd, Rn, imm12) EMIT(ADDSUB_IMM_gen(0, 0, 0, 0b00, (imm12)&0xfff, Rn, Rd))
|
||||
#define ADDSw_U12(Rd, Rn, imm12) EMIT(ADDSUB_IMM_gen(0, 0, 1, 0b00, (imm12)&0xfff, Rn, Rd))
|
||||
#define ADDSw_U12(Rd, Rn, imm12) FEMIT(ADDSUB_IMM_gen(0, 0, 1, 0b00, (imm12)&0xfff, Rn, Rd))
|
||||
#define ADDxw_U12(Rd, Rn, imm12) EMIT(ADDSUB_IMM_gen(rex.w, 0, 0, 0b00, (imm12)&0xfff, Rn, Rd))
|
||||
#define ADDSxw_U12(Rd, Rn, imm12) EMIT(ADDSUB_IMM_gen(rex.w, 0, 1, 0b00, (imm12)&0xfff, Rn, Rd))
|
||||
#define ADDSxw_U12(Rd, Rn, imm12) FEMIT(ADDSUB_IMM_gen(rex.w, 0, 1, 0b00, (imm12)&0xfff, Rn, Rd))
|
||||
#define ADDz_U12(Rd, Rn, imm12) EMIT(ADDSUB_IMM_gen(rex.is32bits?0:1, 0, 0, 0b00, (imm12)&0xfff, Rn, Rd))
|
||||
|
||||
#define SUBx_REG(Rd, Rn, Rm) EMIT(ADDSUB_REG_gen(1, 1, 0, 0b00, Rm, 0, Rn, Rd))
|
||||
#define SUBSx_REG(Rd, Rn, Rm) EMIT(ADDSUB_REG_gen(1, 1, 1, 0b00, Rm, 0, Rn, Rd))
|
||||
#define SUBSx_REG(Rd, Rn, Rm) FEMIT(ADDSUB_REG_gen(1, 1, 1, 0b00, Rm, 0, Rn, Rd))
|
||||
#define SUBSx_REG_ASR(Rd, Rn, Rm, asr) FEMIT(ADDSUB_REG_gen(1, 1, 1, 0b10, Rm, asr, Rn, Rd))
|
||||
#define SUBx_REG_LSL(Rd, Rn, Rm, lsl) EMIT(ADDSUB_REG_gen(1, 1, 0, 0b00, Rm, lsl, Rn, Rd))
|
||||
#define SUBw_REG(Rd, Rn, Rm) EMIT(ADDSUB_REG_gen(0, 1, 0, 0b00, Rm, 0, Rn, Rd))
|
||||
#define SUBw_REG_LSL(Rd, Rn, Rm, lsl) EMIT(ADDSUB_REG_gen(0, 1, 0, 0b00, Rm, lsl, Rn, Rd))
|
||||
#define SUBSw_REG(Rd, Rn, Rm) EMIT(ADDSUB_REG_gen(0, 1, 1, 0b00, Rm, 0, Rn, Rd))
|
||||
#define SUBSw_REG_LSL(Rd, Rn, Rm, lsl) EMIT(ADDSUB_REG_gen(0, 1, 1, 0b00, Rm, lsl, Rn, Rd))
|
||||
#define SUBw_REG_ASR(Rd, Rn, Rm, asr) EMIT(ADDSUB_REG_gen(0, 1, 0, 0b10, Rm, asr, Rn, Rd))
|
||||
#define SUBSw_REG(Rd, Rn, Rm) FEMIT(ADDSUB_REG_gen(0, 1, 1, 0b00, Rm, 0, Rn, Rd))
|
||||
#define SUBSw_REG_LSL(Rd, Rn, Rm, lsl) FEMIT(ADDSUB_REG_gen(0, 1, 1, 0b00, Rm, lsl, Rn, Rd))
|
||||
#define SUBSw_REG_LSR(Rd, Rn, Rm, lsr) FEMIT(ADDSUB_REG_gen(0, 1, 1, 0b01, Rm, lsr, Rn, Rd))
|
||||
#define SUBSw_REG_ASR(Rd, Rn, Rm, asr) FEMIT(ADDSUB_REG_gen(0, 1, 1, 0b10, Rm, asr, Rn, Rd))
|
||||
#define SUBxw_REG(Rd, Rn, Rm) EMIT(ADDSUB_REG_gen(rex.w, 1, 0, 0b00, Rm, 0, Rn, Rd))
|
||||
#define SUBz_REG(Rd, Rn, Rm) EMIT(ADDSUB_REG_gen(rex.is32bits?0:1, 1, 0, 0b00, Rm, 0, Rn, Rd))
|
||||
#define SUBSxw_REG(Rd, Rn, Rm) EMIT(ADDSUB_REG_gen(rex.w, 1, 1, 0b00, Rm, 0, Rn, Rd))
|
||||
#define SUBSxw_REG(Rd, Rn, Rm) FEMIT(ADDSUB_REG_gen(rex.w, 1, 1, 0b00, Rm, 0, Rn, Rd))
|
||||
#define SUBSxw_REG_ASR(Rd, Rn, Rm, asr) FEMIT(ADDSUB_REG_gen(rex.w, 1, 1, 0b10, Rm, asr, Rn, Rd))
|
||||
#define CMPSx_REG(Rn, Rm) SUBSx_REG(xZR, Rn, Rm)
|
||||
#define CMPSx_REG_ASR(Rn, Rm, asr) SUBSx_REG_ASR(xZR, Rn, Rm, asr)
|
||||
#define CMPSw_REG(Rn, Rm) SUBSw_REG(wZR, Rn, Rm)
|
||||
#define CMPSw_REG_LSR(Rn, Rm, lsr) SUBSw_REG_LSR(wZR, Rn, Rm, lsr)
|
||||
#define CMPSw_REG_ASR(Rn, Rm, asr) SUBSw_REG_ASR(wZR, Rn, Rm, asr)
|
||||
#define CMPSxw_REG(Rn, Rm) SUBSxw_REG(xZR, Rn, Rm)
|
||||
#define CMPSxw_REG_ASR(Rn, Rm, asr) SUBSxw_REG_ASR(xZR, Rn, Rm, asr)
|
||||
#define NEGx_REG(Rd, Rm) SUBx_REG(Rd, xZR, Rm);
|
||||
#define NEGw_REG(Rd, Rm) SUBw_REG(Rd, wZR, Rm);
|
||||
#define NEGxw_REG(Rd, Rm) SUBxw_REG(Rd, xZR, Rm);
|
||||
@@ -176,12 +237,12 @@
|
||||
#define NEGSxw_REG(Rd, Rm) SUBSxw_REG(Rd, xZR, Rm);
|
||||
|
||||
#define SUBx_U12(Rd, Rn, imm12) EMIT(ADDSUB_IMM_gen(1, 1, 0, 0b00, (imm12)&0xfff, Rn, Rd))
|
||||
#define SUBSx_U12(Rd, Rn, imm12) EMIT(ADDSUB_IMM_gen(1, 1, 1, 0b00, (imm12)&0xfff, Rn, Rd))
|
||||
#define SUBSx_U12(Rd, Rn, imm12) FEMIT(ADDSUB_IMM_gen(1, 1, 1, 0b00, (imm12)&0xfff, Rn, Rd))
|
||||
#define SUBw_U12(Rd, Rn, imm12) EMIT(ADDSUB_IMM_gen(0, 1, 0, 0b00, (imm12)&0xfff, Rn, Rd))
|
||||
#define SUBSw_U12(Rd, Rn, imm12) EMIT(ADDSUB_IMM_gen(0, 1, 1, 0b00, (imm12)&0xfff, Rn, Rd))
|
||||
#define SUBSw_U12(Rd, Rn, imm12) FEMIT(ADDSUB_IMM_gen(0, 1, 1, 0b00, (imm12)&0xfff, Rn, Rd))
|
||||
#define SUBxw_U12(Rd, Rn, imm12) EMIT(ADDSUB_IMM_gen(rex.w, 1, 0, 0b00, (imm12)&0xfff, Rn, Rd))
|
||||
#define SUBz_U12(Rd, Rn, imm12) EMIT(ADDSUB_IMM_gen(rex.is32bits?0:1, 1, 0, 0b00, (imm12)&0xfff, Rn, Rd))
|
||||
#define SUBSxw_U12(Rd, Rn, imm12) EMIT(ADDSUB_IMM_gen(rex.w, 1, 1, 0b00, (imm12)&0xfff, Rn, Rd))
|
||||
#define SUBSxw_U12(Rd, Rn, imm12) FEMIT(ADDSUB_IMM_gen(rex.w, 1, 1, 0b00, (imm12)&0xfff, Rn, Rd))
|
||||
#define CMPSx_U12(Rn, imm12) SUBSx_U12(xZR, Rn, imm12)
|
||||
#define CMPSw_U12(Rn, imm12) SUBSw_U12(wZR, Rn, imm12)
|
||||
#define CMPSxw_U12(Rn, imm12) SUBSxw_U12(xZR, Rn, imm12)
|
||||
@@ -193,18 +254,22 @@
|
||||
#define SBCx_REG(Rd, Rn, Rm) EMIT(ADDSUBC_gen(1, 1, 0, Rm, Rn, Rd))
|
||||
#define SBCw_REG(Rd, Rn, Rm) EMIT(ADDSUBC_gen(0, 1, 0, Rm, Rn, Rd))
|
||||
#define SBCxw_REG(Rd, Rn, Rm) EMIT(ADDSUBC_gen(rex.w, 1, 0, Rm, Rn, Rd))
|
||||
#define ADCSx_REG(Rd, Rn, Rm) EMIT(ADDSUBC_gen(1, 0, 1, Rm, Rn, Rd))
|
||||
#define ADCSw_REG(Rd, Rn, Rm) EMIT(ADDSUBC_gen(0, 0, 1, Rm, Rn, Rd))
|
||||
#define ADCSxw_REG(Rd, Rn, Rm) EMIT(ADDSUBC_gen(rex.w, 0, 1, Rm, Rn, Rd))
|
||||
#define SBCSx_REG(Rd, Rn, Rm) EMIT(ADDSUBC_gen(1, 1, 1, Rm, Rn, Rd))
|
||||
#define SBCSw_REG(Rd, Rn, Rm) EMIT(ADDSUBC_gen(0, 1, 1, Rm, Rn, Rd))
|
||||
#define SBCSxw_REG(Rd, Rn, Rm) EMIT(ADDSUBC_gen(rex.w, 1, 1, Rm, Rn, Rd))
|
||||
#define ADCSx_REG(Rd, Rn, Rm) FEMIT(ADDSUBC_gen(1, 0, 1, Rm, Rn, Rd))
|
||||
#define ADCSw_REG(Rd, Rn, Rm) FEMIT(ADDSUBC_gen(0, 0, 1, Rm, Rn, Rd))
|
||||
#define ADCSxw_REG(Rd, Rn, Rm) FEMIT(ADDSUBC_gen(rex.w, 0, 1, Rm, Rn, Rd))
|
||||
#define SBCSx_REG(Rd, Rn, Rm) FEMIT(ADDSUBC_gen(1, 1, 1, Rm, Rn, Rd))
|
||||
#define SBCSw_REG(Rd, Rn, Rm) FEMIT(ADDSUBC_gen(0, 1, 1, Rm, Rn, Rd))
|
||||
#define SBCSxw_REG(Rd, Rn, Rm) FEMIT(ADDSUBC_gen(rex.w, 1, 1, Rm, Rn, Rd))
|
||||
|
||||
#define SUB_ext(sf, op, S, Rm, option, imm3, Rn, Rd) ((sf)<<31 | (op)<<30 | (S)<<29 | 0b01011<<24 | 1<<21 | (Rm)<<16 | (option)<<13 | (imm3)<<10 | (Rn)<<5 | (Rd))
|
||||
#define SUBxw_UXTB(Rd, Rn, Rm) EMIT(SUB_ext(rex.w, 1, 0, Rm, 0b000, 0, Rn, Rd))
|
||||
#define SUBw_UXTB(Rd, Rn, Rm) EMIT(SUB_ext(0, 1, 0, Rm, 0b000, 0, Rn, Rd))
|
||||
|
||||
// CCMP compare if cond is true, set nzcv if false
|
||||
#define CCMP_reg(sf, Rm, cond, Rn, nzcv) ((sf)<<31 | 1<<30 | 1<<29 | 0b11010010<<21 | (Rm)<<16 | (cond)<<12 | (Rn)<<5 | (nzcv))
|
||||
#define CCMPw(Wn, Wm, nzcv, cond) EMIT(CCMP_reg(0, Wm, cond, Wn, nzcv))
|
||||
#define CCMPx(Xn, Xm, nzcv, cond) EMIT(CCMP_reg(1, Xm, cond, Xn, nzcv))
|
||||
#define CCMPxw(Xn, Xm, nzcv, cond) EMIT(CCMP_reg(rex.w, Xm, cond, Xn, nzcv))
|
||||
#define CCMPw(Wn, Wm, nzcv, cond) FEMIT(CCMP_reg(0, Wm, cond, Wn, nzcv))
|
||||
#define CCMPx(Xn, Xm, nzcv, cond) FEMIT(CCMP_reg(1, Xm, cond, Xn, nzcv))
|
||||
#define CCMPxw(Xn, Xm, nzcv, cond) FEMIT(CCMP_reg(rex.w, Xm, cond, Xn, nzcv))
|
||||
|
||||
// ADR
|
||||
#define ADR_gen(immlo, immhi, Rd) ((immlo)<<29 | 0b10000<<24 | (immhi)<<5 | (Rd))
|
||||
@@ -241,13 +306,25 @@
|
||||
#define LDRx_REG(Rt, Rn, Rm) EMIT(LDR_REG_gen(0b11, Rm, 0b011, 0, Rn, Rt))
|
||||
#define LDRx_REG_LSL3(Rt, Rn, Rm) EMIT(LDR_REG_gen(0b11, Rm, 0b011, 1, Rn, Rt))
|
||||
#define LDRx_REG_UXTW3(Rt, Rn, Rm) EMIT(LDR_REG_gen(0b11, Rm, 0b010, 1, Rn, Rt))
|
||||
#define LDRx_REG_SXTW(Rt, Rn, Rm) EMIT(LDR_REG_gen(0b11, Rm, 0b110, 0, Rn, Rt))
|
||||
#define LDRx_REGz(Rt, Rn, Rm) EMIT(LDR_REG_gen(0b11, Rm, rex.is32bits?0b110:0b011, 0, Rn, Rt))
|
||||
#define LDRw_REG(Rt, Rn, Rm) EMIT(LDR_REG_gen(0b10, Rm, 0b011, 0, Rn, Rt))
|
||||
#define LDRw_REG_LSL2(Rt, Rn, Rm) EMIT(LDR_REG_gen(0b10, Rm, 0b011, 1, Rn, Rt))
|
||||
#define LDRw_REG_SXTW(Rt, Rn, Rm) EMIT(LDR_REG_gen(0b10, Rm, 0b110, 0, Rn, Rt))
|
||||
#define LDRw_REGz(Rt, Rn, Rm) EMIT(LDR_REG_gen(0b10, Rm, rex.is32bits?0b110:0b011, 0, Rn, Rt))
|
||||
#define LDRxw_REG(Rt, Rn, Rm) EMIT(LDR_REG_gen(0b10+rex.w, Rm, 0b011, 0, Rn, Rt))
|
||||
#define LDRz_REG(Rt, Rn, Rm) EMIT(LDR_REG_gen(rex.is32bits?0b10:0b11, Rm, 0b011, 0, Rn, Rt))
|
||||
#define LDRxw_REG_SXTW(Rt, Rn, Rm) EMIT(LDR_REG_gen(0b10+rex.w, Rm, 0b110, 0, Rn, Rt))
|
||||
#define LDRxw_REGz(Rt, Rn, Rm) EMIT(LDR_REG_gen(0b10+rex.w, Rm, rex.is32bits?0b110:0b011, 0, Rn, Rt))
|
||||
#define LDRz_REG_SXTW(Rt, Rn, Rm) EMIT(LDR_REG_gen(rex.is32bits?0b10:0b11, Rm, 0b110, 0, Rn, Rt))
|
||||
#define LDRz_REGz(Rt, Rn, Rm) EMIT(LDR_REG_gen(rex.is32bits?0b10:0b11, Rm, rex.is32bits?0b110:0b011, 0, Rn, Rt))
|
||||
#define LDRB_REG(Rt, Rn, Rm) EMIT(LDR_REG_gen(0b00, Rm, 0b011, 0, Rn, Rt))
|
||||
#define LDRB_REG_UXTW(Rt, Rn, Rm) EMIT(LDR_REG_gen(0b00, Rm, 0b010, 0, Rn, Rt))
|
||||
#define LDRB_REG_SXTW(Rt, Rn, Rm) EMIT(LDR_REG_gen(0b00, Rm, 0b110, 0, Rn, Rt))
|
||||
#define LDRB_REGz(Rt, Rn, Rm) EMIT(LDR_REG_gen(0b00, Rm, rex.is32bits?0b110:0b011, 0, Rn, Rt))
|
||||
#define LDRH_REG(Rt, Rn, Rm) EMIT(LDR_REG_gen(0b01, Rm, 0b011, 0, Rn, Rt))
|
||||
#define LDRH_REG_SXTW(Rt, Rn, Rm) EMIT(LDR_REG_gen(0b01, Rm, 0b110, 0, Rn, Rt))
|
||||
#define LDRH_REGz(Rt, Rn, Rm) EMIT(LDR_REG_gen(0b01, Rm, rex.is32bits?0b110:0b011, 0, Rn, Rt))
|
||||
|
||||
#define LDRS_U12_gen(size, op1, opc, imm12, Rn, Rt) ((size)<<30 | 0b111<<27 | (op1)<<24 | (opc)<<22 | (imm12)<<10 | (Rn)<<5 | (Rt))
|
||||
#define LDRSHx_U12(Rt, Rn, imm12) EMIT(LDRS_U12_gen(0b01, 0b01, 0b10, ((uint32_t)(imm12>>1))&0xfff, Rn, Rt))
|
||||
@@ -259,9 +336,11 @@
|
||||
|
||||
#define LDRS_REG_gen(size, Rm, option, S, Rn, Rt) ((size)<<30 | 0b111<<27 | 0b10<<22 | 1<<21 | (Rm)<<16 | (option)<<13 | (S)<<12 | (0b10)<<10 | (Rn)<<5 | (Rt))
|
||||
#define LDRSW_REG(Rt, Rn, Rm) EMIT(LDRS_REG_gen(0b10, Rm, 0b011, 0, Rn, Rt))
|
||||
#define LDRSW_REG_SXTW(Rt, Rn, Rm) EMIT(LDRS_REG_gen(0b10, Rm, 0b110, 0, Rn, Rt))
|
||||
#define LDRSW_REGz(Rt, Rn, Rm) EMIT(LDRS_REG_gen(0b10, Rm, rex.is32bits?0b110:0b011, 0, Rn, Rt))
|
||||
|
||||
#define LDR_PC_gen(opc, imm19, Rt) ((opc)<<30 | 0b011<<27 | (imm19)<<5 | (Rt))
|
||||
#define LDRx_literal(Rt, imm19) EMIT(LDR_PC_gen(0b01, ((imm19)>>2)&0x7FFFF, Rt))
|
||||
#define LDRx_literal(Rt, imm21) EMIT(LDR_PC_gen(0b01, (((int64_t)(imm21))>>2)&0x7FFFF, Rt))
|
||||
|
||||
#define LDU_gen(size, opc, imm9, Rn, Rt) ((size)<<30 | 0b111<<27 | (opc)<<22 | ((imm9)&0x1ff)<<12 | (Rn)<<5 | (Rt))
|
||||
#define LDURx_I9(Rt, Rn, imm9) EMIT(LDU_gen(0b11, 0b01, imm9, Rn, Rt))
|
||||
@@ -329,12 +408,21 @@
|
||||
#define STRx_REG(Rt, Rn, Rm) EMIT(STR_REG_gen(0b11, Rm, 0b011, 0, Rn, Rt))
|
||||
#define STRx_REG_LSL3(Rt, Rn, Rm) EMIT(STR_REG_gen(0b11, Rm, 0b011, 1, Rn, Rt))
|
||||
#define STRx_REG_UXTW(Rt, Rn, Rm) EMIT(STR_REG_gen(0b11, Rm, 0b010, 0, Rn, Rt))
|
||||
#define STRx_REG_SXTW(Rt, Rn, Rm) EMIT(STR_REG_gen(0b11, Rm, 0b110, 0, Rn, Rt))
|
||||
#define STRw_REG(Rt, Rn, Rm) EMIT(STR_REG_gen(0b10, Rm, 0b011, 0, Rn, Rt))
|
||||
#define STRw_REG_LSL2(Rt, Rn, Rm) EMIT(STR_REG_gen(0b10, Rm, 0b011, 1, Rn, Rt))
|
||||
#define STRw_REG_SXTW(Rt, Rn, Rm) EMIT(STR_REG_gen(0b10, Rm, 0b110, 0, Rn, Rt))
|
||||
#define STRB_REG(Rt, Rn, Rm) EMIT(STR_REG_gen(0b00, Rm, 0b011, 0, Rn, Rt))
|
||||
#define STRB_REG_SXTW(Rt, Rn, Rm) EMIT(STR_REG_gen(0b00, Rm, 0b110, 0, Rn, Rt))
|
||||
#define STRB_REGz(Rt, Rn, Rm) EMIT(STR_REG_gen(0b00, Rm, rex.is32bits?0b110:0b011, 0, Rn, Rt))
|
||||
#define STRH_REG(Rt, Rn, Rm) EMIT(STR_REG_gen(0b01, Rm, 0b011, 0, Rn, Rt))
|
||||
#define STRH_REG_SXTW(Rt, Rn, Rm) EMIT(STR_REG_gen(0b01, Rm, 0b110, 0, Rn, Rt))
|
||||
#define STRxw_REG(Rt, Rn, Rm) EMIT(STR_REG_gen(rex.w?0b11:0b10, Rm, 0b011, 0, Rn, Rt))
|
||||
#define STRxw_REG_SXTW(Rt, Rn, Rm) EMIT(STR_REG_gen(rex.w?0b11:0b10, Rm, 0b110, 0, Rn, Rt))
|
||||
#define STRxw_REGz(Rt, Rn, Rm) EMIT(STR_REG_gen(rex.w?0b11:0b10, Rm, rex.is32bits?0b110:0b011, 0, Rn, Rt))
|
||||
#define STRz_REG(Rt, Rn, Rm) EMIT(STR_REG_gen(rex.is32bits?0b10:0b11, Rm, 0b011, 0, Rn, Rt))
|
||||
#define STRz_REG_SXTW(Rt, Rn, Rm) EMIT(STR_REG_gen(rex.is32bits?0b10:0b11, Rm, 0b110, 0, Rn, Rt))
|
||||
#define STRz_REGz(Rt, Rn, Rm) EMIT(STR_REG_gen(rex.is32bits?0b10:0b11, Rm, rex.is32bits?0b110:0b011, 0, Rn, Rt))
|
||||
|
||||
// LOAD/STORE PAIR
|
||||
#define MEMPAIR_gen(size, L, op2, imm7, Rt2, Rn, Rt) ((size)<<31 | 0b101<<27 | (op2)<<23 | (L)<<22 | (imm7)<<15 | (Rt2)<<10 | (Rn)<<5 | (Rt))
|
||||
@@ -434,12 +522,19 @@
|
||||
// Data Memory Barrier
|
||||
#define DMB_gen(CRm) (0b1101010100<<22 | 0b011<<16 | 0b0011<<12 | (CRm)<<8 | 1<<7 | 0b01<<5 | 0b11111)
|
||||
#define DMB_ISH() EMIT(DMB_gen(0b1011))
|
||||
#define DMB_ISHLD() EMIT(DMB_gen(0b1001))
|
||||
#define DMB_ISHST() EMIT(DMB_gen(0b1010))
|
||||
#define DMB_LD() EMIT(DMB_gen(0b1101))
|
||||
#define DMB_ST() EMIT(DMB_gen(0b1110))
|
||||
#define DMB_SY() EMIT(DMB_gen(0b1111))
|
||||
|
||||
// Data Synchronization Barrier
|
||||
#define DSB_gen(CRm) (0b1101010100<<22 | 0b011<<16 | 0b0011<<12 | (CRm)<<8 | 1<<7 | 0b00<<5 | 0b11111)
|
||||
#define DSB_ISH() EMIT(DSB_gen(0b1011))
|
||||
#define DSB_ISHLD() EMIT(DSB_gen(0b1001))
|
||||
#define DSB_ISHST() EMIT(DSB_gen(0b1010))
|
||||
#define DSB_LD() EMIT(DSB_gen(0b1101))
|
||||
#define DSB_ST() EMIT(DSB_gen(0b1110))
|
||||
#define DSB_SY() EMIT(DSB_gen(0b1111))
|
||||
|
||||
// Break
|
||||
@@ -450,6 +545,7 @@
|
||||
#define BR_gen(Z, op, A, M, Rn, Rm) (0b1101011<<25 | (Z)<<24 | (op)<<21 | 0b11111<<16 | (A)<<11 | (M)<<10 | (Rn)<<5 | (Rm))
|
||||
#define BR(Rn) EMIT(BR_gen(0, 0b00, 0, 0, Rn, 0))
|
||||
#define BLR(Rn) EMIT(BR_gen(0, 0b01, 0, 0, Rn, 0))
|
||||
#define RET(Rn) EMIT(BR_gen(0, 0b10, 0, 0, Rn, 0))
|
||||
|
||||
#define CB_gen(sf, op, imm19, Rt) ((sf)<<31 | 0b011010<<25 | (op)<<24 | (imm19)<<5 | (Rt))
|
||||
#define CBNZx(Rt, imm19) EMIT(CB_gen(1, 1, ((imm19)>>2)&0x7FFFF, Rt))
|
||||
@@ -475,6 +571,10 @@
|
||||
#define BL(imm26) EMIT(BL_gen(((imm26)>>2)&0x3ffffff))
|
||||
|
||||
#define NOP EMIT(0b11010101000000110010000000011111)
|
||||
#define WFE EMIT(0b11010101000000110010000001011111)
|
||||
#define WFI EMIT(0b11010101000000110010000001111111)
|
||||
#define YIELD EMIT(0b11010101000000110010000000111111)
|
||||
#define SEVL EMIT(0b11010101000000110010000010111111)
|
||||
|
||||
#define CSINC_gen(sf, Rm, cond, Rn, Rd) ((sf)<<31 | 0b11010100<<21 | (Rm)<<16 | (cond)<<12 | 1<<10 | (Rn)<<5 | (Rd))
|
||||
#define CSINCx(Rd, Rn, Rm, cond) EMIT(CSINC_gen(1, Rm, cond, Rn, Rd))
|
||||
@@ -487,7 +587,7 @@
|
||||
#define CSINV_gen(sf, Rm, cond, Rn, Rd) ((sf)<<31 | 1<<30 | 0b11010100<<21 | (Rm)<<16 | (cond)<<12 | (Rn)<<5 | (Rd))
|
||||
#define CSINVx(Rd, Rn, Rm, cond) EMIT(CSINV_gen(1, Rm, cond, Rn, Rd))
|
||||
#define CSINVw(Rd, Rn, Rm, cond) EMIT(CSINV_gen(0, Rm, cond, Rn, Rd))
|
||||
#define CSINVxw(Rd, Rn, Rm, cond) EMIT(CSINV_gen(rex.w?, Rm, cond, Rn, Rd))
|
||||
#define CSINVxw(Rd, Rn, Rm, cond) EMIT(CSINV_gen(rex.w, Rm, cond, Rn, Rd))
|
||||
#define CINVx(Rd, Rn, cond) CSINVx(Rd, Rn, Rn, invertCond(cond))
|
||||
#define CINVw(Rd, Rn, cond) CSINVw(Rd, Rn, Rn, invertCond(cond))
|
||||
#define CINVxw(Rd, Rn, cond) CSINVxw(Rd, Rn, Rn, invertCond(cond))
|
||||
@@ -513,22 +613,29 @@
|
||||
// logic to get the mask is ... convoluted... list of possible value there: https://gist.github.com/dinfuehr/51a01ac58c0b23e4de9aac313ed6a06a
|
||||
#define ANDx_mask(Rd, Rn, N, immr, imms) EMIT(LOGIC_gen(1, 0b00, N, immr, imms, Rn, Rd))
|
||||
#define ANDw_mask(Rd, Rn, immr, imms) EMIT(LOGIC_gen(0, 0b00, 0, immr, imms, Rn, Rd))
|
||||
#define ANDSx_mask(Rd, Rn, N, immr, imms) EMIT(LOGIC_gen(1, 0b11, N, immr, imms, Rn, Rd))
|
||||
#define ANDSw_mask(Rd, Rn, immr, imms) EMIT(LOGIC_gen(0, 0b11, 0, immr, imms, Rn, Rd))
|
||||
#define ANDxw_mask(Rd, Rn, N, immr, imms) EMIT(LOGIC_gen(rex.w, 0b00, rex.w?(N):0, immr, imms, Rn, Rd))
|
||||
#define ANDSx_mask(Rd, Rn, N, immr, imms) FEMIT(LOGIC_gen(1, 0b11, N, immr, imms, Rn, Rd))
|
||||
#define ANDSw_mask(Rd, Rn, immr, imms) FEMIT(LOGIC_gen(0, 0b11, 0, immr, imms, Rn, Rd))
|
||||
#define ANDSxw_mask(Rd, Rn, N, immr, imms) FEMIT(LOGIC_gen(rex.w, 0b11, rex.w?(N):0, immr, imms, Rn, Rd))
|
||||
#define ORRx_mask(Rd, Rn, N, immr, imms) EMIT(LOGIC_gen(1, 0b01, N, immr, imms, Rn, Rd))
|
||||
#define ORRw_mask(Rd, Rn, immr, imms) EMIT(LOGIC_gen(0, 0b01, 0, immr, imms, Rn, Rd))
|
||||
#define ORRxw_mask(Rd, Rn, N, immr, imms) EMIT(LOGIC_gen(rex.w, 0b01, rex.w?(N):0, immr, imms, Rn, Rd))
|
||||
#define EORx_mask(Rd, Rn, N, immr, imms) EMIT(LOGIC_gen(1, 0b10, N, immr, imms, Rn, Rd))
|
||||
#define EORw_mask(Rd, Rn, immr, imms) EMIT(LOGIC_gen(0, 0b10, 0, immr, imms, Rn, Rd))
|
||||
#define EORxw_mask(Rd, Rn, N, immr, imms) EMIT(LOGIC_gen(rex.w, 0b10, rex.w?(N):0, immr, imms, Rn, Rd))
|
||||
#define TSTx_mask(Rn, N, immr, imms) ANDSx_mask(xZR, Rn, N, immr, imms)
|
||||
#define TSTw_mask(Rn, immr, imms) ANDSw_mask(wZR, Rn, immr, imms)
|
||||
#define TSTxw_mask(Rn, N, immr, imms) ANDSxw_mask(xZR, Rn, N, immr, imms)
|
||||
|
||||
#define LOGIC_REG_gen(sf, opc, shift, N, Rm, imm6, Rn, Rd) ((sf)<<31 | (opc)<<29 | 0b01010<<24 | (shift)<<22 | (N)<<21 | (Rm)<<16 | (imm6)<<10 | (Rn)<<5 | (Rd))
|
||||
#define ANDx_REG(Rd, Rn, Rm) EMIT(LOGIC_REG_gen(1, 0b00, 0b00, 0, Rm, 0, Rn, Rd))
|
||||
#define ANDw_REG(Rd, Rn, Rm) EMIT(LOGIC_REG_gen(0, 0b00, 0b00, 0, Rm, 0, Rn, Rd))
|
||||
#define ANDw_REG_LSR(Rd, Rn, Rm, lsr) EMIT(LOGIC_REG_gen(0, 0b00, 0b01, 0, Rm, lsr, Rn, Rd))
|
||||
#define ANDxw_REG(Rd, Rn, Rm) EMIT(LOGIC_REG_gen(rex.w, 0b00, 0b00, 0, Rm, 0, Rn, Rd))
|
||||
#define ANDSx_REG(Rd, Rn, Rm) EMIT(LOGIC_REG_gen(1, 0b11, 0b00, 0, Rm, 0, Rn, Rd))
|
||||
#define ANDSw_REG(Rd, Rn, Rm) EMIT(LOGIC_REG_gen(0, 0b11, 0b00, 0, Rm, 0, Rn, Rd))
|
||||
#define ANDSxw_REG(Rd, Rn, Rm) EMIT(LOGIC_REG_gen(rex.w, 0b11, 0b00, 0, Rm, 0, Rn, Rd))
|
||||
#define ANDSx_REG(Rd, Rn, Rm) FEMIT(LOGIC_REG_gen(1, 0b11, 0b00, 0, Rm, 0, Rn, Rd))
|
||||
#define ANDSw_REG(Rd, Rn, Rm) FEMIT(LOGIC_REG_gen(0, 0b11, 0b00, 0, Rm, 0, Rn, Rd))
|
||||
#define ANDSxw_REG(Rd, Rn, Rm) FEMIT(LOGIC_REG_gen(rex.w, 0b11, 0b00, 0, Rm, 0, Rn, Rd))
|
||||
#define ANDSw_REG_LSL(Rd, Rn, Rm, lsl) FEMIT(LOGIC_REG_gen(0, 0b11, 0b00, 0, Rm, lsl, Rn, Rd))
|
||||
#define ORRx_REG(Rd, Rn, Rm) EMIT(LOGIC_REG_gen(1, 0b01, 0b00, 0, Rm, 0, Rn, Rd))
|
||||
#define ORRx_REG_LSL(Rd, Rn, Rm, lsl) EMIT(LOGIC_REG_gen(1, 0b01, 0b00, 0, Rm, lsl, Rn, Rd))
|
||||
#define ORRw_REG_LSL(Rd, Rn, Rm, lsl) EMIT(LOGIC_REG_gen(0, 0b01, 0b00, 0, Rm, lsl, Rn, Rd))
|
||||
@@ -579,10 +686,10 @@
|
||||
#define BICx(Rd, Rn, Rm) EMIT(LOGIC_REG_gen(1, 0b00, 0b00, 1, Rm, 0, Rn, Rd))
|
||||
#define BICw(Rd, Rn, Rm) EMIT(LOGIC_REG_gen(0, 0b00, 0b00, 1, Rm, 0, Rn, Rd))
|
||||
#define BICw_LSL(Rd, Rn, Rm, lsl) EMIT(LOGIC_REG_gen(0, 0b00, 0b00, 1, Rm, lsl, Rn, Rd))
|
||||
#define BICSx(Rd, Rn, Rm) EMIT(LOGIC_REG_gen(1, 0b00, 0b00, 1, Rm, 0, Rn, Rd))
|
||||
#define BICSw(Rd, Rn, Rm) EMIT(LOGIC_REG_gen(0, 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) EMIT(LOGIC_REG_gen(rex.w, 0b00, 0b00, 1, Rm, 0, 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 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
|
||||
#define BICxw_REG BICxw
|
||||
@@ -610,9 +717,11 @@
|
||||
#define BFIx(Rd, Rn, lsb, width) BFMx(Rd, Rn, ((-(lsb))%64)&0x3f, (width)-1)
|
||||
#define BFIw(Rd, Rn, lsb, width) BFMw(Rd, Rn, ((-(lsb))%32)&0x1f, (width)-1)
|
||||
#define BFIxw(Rd, Rn, lsb, width) if(rex.w) {BFIx(Rd, Rn, lsb, width);} else {BFIw(Rd, Rn, lsb, width);}
|
||||
#define BFIz(Rd, Rn, lsb, width) if(rex.is32bits) {BFIw(Rd, Rn, lsb, width);} else {BFIx(Rd, Rn, lsb, width);}
|
||||
#define BFCx(Rd, lsb, width) BFMx(Rd, xZR, ((-(lsb))%64)&0x3f, (width)-1)
|
||||
#define BFCw(Rd, lsb, width) BFMw(Rd, xZR, ((-(lsb))%32)&0x1f, (width)-1)
|
||||
#define BFCxw(Rd, lsb, width) BFMxw(Rd, xZR, rex.w?(((-(lsb))%64)&0x3f):(((-(lsb))%32)&0x1f), (width)-1)
|
||||
#define BFCz(Rd, lsb, width) if(rex.is32bits) {BFCw(Rd, lsb, width);} else {BFCx(Rd, lsb, width);}
|
||||
// Insert lsb:width part of Rn into low part of Rd (leaving rest of Rd untouched)
|
||||
#define BFXILx(Rd, Rn, lsb, width) EMIT(BFM_gen(1, 0b01, 1, (lsb), (lsb)+(width)-1, Rn, Rd))
|
||||
// Insert lsb:width part of Rn into low part of Rd (leaving rest of Rd untouched)
|
||||
@@ -757,15 +866,21 @@
|
||||
#define MRS_gen(L, o0, op1, CRn, CRm, op2, Rt) (0b1101010100<<22 | (L)<<21 | 1<<20 | (o0)<<19 | (op1)<<16 | (CRn)<<12 | (CRm)<<8 | (op2)<<5 | (Rt))
|
||||
// mrs x0, nzcv : 1101010100 1 1 1 011 0100 0010 000 00000 o0=1(op0=3), op1=0b011(3) CRn=0b0100(4) CRm=0b0010(2) op2=0
|
||||
// MRS : from System register
|
||||
#define MRS_nzvc(Rt) EMIT(MRS_gen(1, 1, 3, 4, 2, 0, Rt))
|
||||
#define MRS_nzcv(Rt) EMIT(MRS_gen(1, 1, 3, 4, 2, 0, Rt))
|
||||
// MSR : to System register
|
||||
#define MSR_nzvc(Rt) EMIT(MRS_gen(0, 1, 3, 4, 2, 0, Rt))
|
||||
#define MSR_nzcv(Rt) FEMIT(MRS_gen(0, 1, 3, 4, 2, 0, Rt))
|
||||
// mrs x0, fpcr : 1101010100 1 1 1 011 0100 0100 000 00000 o0=1(op0=3), op1=0b011(3) CRn=0b0100(4) CRm=0b0100(4) op2=0
|
||||
#define MRS_fpcr(Rt) EMIT(MRS_gen(1, 1, 3, 4, 4, 0, Rt))
|
||||
#define MSR_fpcr(Rt) EMIT(MRS_gen(0, 1, 3, 4, 4, 0, Rt))
|
||||
// mrs x0, fpsr : 1101010100 1 1 1 011 0100 0100 001 00000 o0=1(op0=3), op1=0b011(3) CRn=0b0100(4) CRm=0b0100(4) op2=1
|
||||
#define MRS_fpsr(Rt) EMIT(MRS_gen(1, 1, 3, 4, 4, 1, Rt))
|
||||
#define MSR_fpsr(Rt) EMIT(MRS_gen(0, 1, 3, 4, 4, 1, Rt))
|
||||
// mrs x0, cntvct_el0 op0=0b11 op1=0b011 CRn=0b1110 CRm=0b0000 op2=0b010
|
||||
#define MRS_cntvct_el0(Rt) EMIT(MRS_gen(1, 1, 0b011, 0b1110, 0b0000, 0b010, Rt))
|
||||
// mrs x0, cntpctss_el0 op0=0b11 op1=0b011 CRn=0b1110 CRm=0b0000 op2=0b101
|
||||
#define MRS_cntpctss_el0(Rt) EMIT(MRS_gen(1, 1, 0b011, 0b1110, 0b0000, 0b101, Rt))
|
||||
// mrs rt, rndr op0=0b11 op1=0b011 CRn=0b0010 CRm=0b0100 op2=0b000
|
||||
#define MRS_rndr(Rt) EMIT(MRS_gen(1, 1, 0b011, 0b0010, 0b0100, 0b000, Rt))
|
||||
// NEON Saturation Bit
|
||||
#define FPSR_QC 27
|
||||
// NEON Input Denormal Cumulative
|
||||
@@ -780,13 +895,21 @@
|
||||
#define FPSR_DZC 1
|
||||
// NEON Invalid Operation Cumulative
|
||||
#define FPSR_IOC 0
|
||||
// NZCV N
|
||||
#define NZCV_N 31
|
||||
// NZCV Z
|
||||
#define NZCV_Z 30
|
||||
// NZCV C
|
||||
#define NZCV_C 29
|
||||
// NZCV V
|
||||
#define NZCV_V 28
|
||||
|
||||
// FCSEL
|
||||
#define FCSEL_scalar(type, Rm, cond, Rn, Rd) (0b11110<<24 | (type)<<22 | 1<<21 | (Rm)<<16 | (cond)<<12 | 0b11<<10 | (Rn)<<5 | (Rd))
|
||||
#define FCSELS(Sd, Sn, Sm, cond) EMIT(FCSEL_scalar(0b00, Sm, cond, Sn, Sd))
|
||||
#define FCSELD(Dd, Dn, Dm, cond) EMIT(FCSEL_scalar(0b01, Dm, cond, Dn, Dd))
|
||||
|
||||
// VLDR
|
||||
// VLDR/VSTR
|
||||
#define VMEM_gen(size, opc, imm12, Rn, Rt) ((size)<<30 | 0b111<<27 | 1<<26 | 0b01<<24 | (opc)<<22 | (imm12)<<10 | (Rn)<<5 | (Rt))
|
||||
// imm13 must be 1-aligned
|
||||
#define VLDR16_U12(Ht, Rn, imm13) EMIT(VMEM_gen(0b01, 0b01, ((uint32_t)((imm13)>>1))&0xfff, Rn, Ht))
|
||||
@@ -805,6 +928,15 @@
|
||||
// (imm13) must be 1-aligned
|
||||
#define VSTR16_U12(Ht, Rn, imm13) EMIT(VMEM_gen(0b01, 0b00, ((uint32_t)((imm13)>>1))&0xfff, Rn, Ht))
|
||||
|
||||
//VLDP/VSTP
|
||||
#define VMEMP_vector(opc, L, imm7, Rt2, Rn, Rt) ((opc)<<30 | 0b101<<27 | 1<<26 | 0b010<<23 | (L)<<22 | (imm7)<<15 | (Rt2)<<10 | (Rn)<<5 | (Rt))
|
||||
#define VLDP32_I7(Rt1, Rt2, Rn, imm9) EMIT(VMEMP_vector(0b00, 1, (((int64_t)(imm9))>>2)&0x7f, Rt2, Rn, Rt1))
|
||||
#define VLDP64_I7(Rt1, Rt2, Rn, imm10) EMIT(VMEMP_vector(0b01, 1, (((int64_t)(imm10))>>3)&0x7f, Rt2, Rn, Rt1))
|
||||
#define VLDP128_I7(Rt1, Rt2, Rn, imm11) EMIT(VMEMP_vector(0b10, 1, (((int64_t)(imm11))>>4)&0x7f, Rt2, Rn, Rt1))
|
||||
#define VSTP32_I7(Rt1, Rt2, Rn, imm9) EMIT(VMEMP_vector(0b00, 0, (((int64_t)(imm9))>>2)&0x7f, Rt2, Rn, Rt1))
|
||||
#define VSTP64_I7(Rt1, Rt2, Rn, imm10) EMIT(VMEMP_vector(0b01, 0, (((int64_t)(imm10))>>3)&0x7f, Rt2, Rn, Rt1))
|
||||
#define VSTP128_I7(Rt1, Rt2, Rn, imm11) EMIT(VMEMP_vector(0b10, 0, (((int64_t)(imm11))>>4)&0x7f, Rt2, Rn, Rt1))
|
||||
|
||||
#define VMEMUR_vector(size, opc, imm9, Rn, Rt) ((size)<<30 | 0b111<<27 | 1<<26 | (opc)<<22 | (imm9)<<12 | (Rn)<<5 | (Rt))
|
||||
// signed offset, no alignement!
|
||||
#define VLDR8_I9(Vt, Rn, imm9) EMIT(VMEMUR_vector(0b00, 0b01, (imm9)&0b111111111, Rn, Vt))
|
||||
@@ -823,10 +955,12 @@
|
||||
#define VLD64(A, B, C) if(unscaled) {VLDR64_I9(A, B, C);} else {VLDR64_U12(A, B, C);}
|
||||
#define VLD32(A, B, C) if(unscaled) {VLDR32_I9(A, B, C);} else {VLDR32_U12(A, B, C);}
|
||||
#define VLD16(A, B, C) if(unscaled) {VLDR16_I9(A, B, C);} else {VLDR16_U12(A, B, C);}
|
||||
#define VLD8(A, B, C) if(unscaled) {VLDR8_I9(A, B, C);} else {VLDR8_U12(A, B, C);}
|
||||
#define VST128(A, B, C) if(unscaled) {VSTR128_I9(A, B, C);} else {VSTR128_U12(A, B, C);}
|
||||
#define VST64(A, B, C) if(unscaled) {VSTR64_I9(A, B, C);} else {VSTR64_U12(A, B, C);}
|
||||
#define VST32(A, B, C) if(unscaled) {VSTR32_I9(A, B, C);} else {VSTR32_U12(A, B, C);}
|
||||
#define VST16(A, B, C) if(unscaled) {VSTR16_I9(A, B, C);} else {VSTR16_U12(A, B, C);}
|
||||
#define VST8(A, B, C) if(unscaled) {VSTR8_I9(A, B, C);} else {VSTR8_U12(A, B, C);}
|
||||
|
||||
#define VMEMW_gen(size, opc, imm9, op2, Rn, Rt) ((size)<<30 | 0b111<<27 | 1<<26 | (opc)<<22 | (imm9)<<12 | (op2)<<10 | 0b01<<10 | (Rn)<<5 | (Rt))
|
||||
#define VLDR64_S9_postindex(Rt, Rn, imm9) EMIT(VMEMW_gen(0b11, 0b01, (imm9)&0x1ff, 0b01, Rn, Rt))
|
||||
@@ -841,18 +975,24 @@
|
||||
#define VMEM_REG_gen(size, opc, Rm, option, S, Rn, Rt) ((size)<<30 | 0b111<<27 | 1<<26 | (opc)<<22 | 1<<21 | (Rm)<<16 | (option)<<13 | (S)<<12 | 0b10<<10 | (Rn)<<5 | (Rt))
|
||||
|
||||
#define VLDR32_REG(Dt, Rn, Rm) EMIT(VMEM_REG_gen(0b10, 0b01, Rm, 0b011, 0, Rn, Dt))
|
||||
#define VLDR32_REG_SXTW(Dt, Rn, Rm) EMIT(VMEM_REG_gen(0b10, 0b01, Rm, 0b110, 0, Rn, Dt))
|
||||
#define VLDR32_REG_LSL2(Dt, Rn, Rm) EMIT(VMEM_REG_gen(0b10, 0b01, Rm, 0b011, 1, Rn, Dt))
|
||||
#define VLDR64_REG(Dt, Rn, Rm) EMIT(VMEM_REG_gen(0b11, 0b01, Rm, 0b011, 0, Rn, Dt))
|
||||
#define VLDR64_REG_SXTW(Dt, Rn, Rm) EMIT(VMEM_REG_gen(0b11, 0b01, Rm, 0b110, 0, Rn, Dt))
|
||||
#define VLDR64_REG_LSL3(Dt, Rn, Rm) EMIT(VMEM_REG_gen(0b11, 0b01, Rm, 0b011, 1, Rn, Dt))
|
||||
#define VLDR128_REG(Qt, Rn, Rm) EMIT(VMEM_REG_gen(0b00, 0b11, Rm, 0b011, 0, Rn, Qt))
|
||||
#define VLDR128_REG_LSL4(Qt, Rn, Rm) EMIT(VMEM_REG_gen(0b00, 0b11, Rm, 0b011, 1, Rn, Qt))
|
||||
#define VLDR128_REG_SXTW(Qt, Rn, Rm) EMIT(VMEM_REG_gen(0b00, 0b11, Rm, 0b110, 0, Rn, Qt))
|
||||
|
||||
#define VSTR32_REG(Dt, Rn, Rm) EMIT(VMEM_REG_gen(0b10, 0b00, Rm, 0b011, 0, Rn, Dt))
|
||||
#define VSTR32_REG_LSL2(Dt, Rn, Rm) EMIT(VMEM_REG_gen(0b10, 0b00, Rm, 0b011, 1, Rn, Dt))
|
||||
#define VSTR32_REG_SXTW(Dt, Rn, Rm) EMIT(VMEM_REG_gen(0b10, 0b00, Rm, 0b110, 0, Rn, Dt))
|
||||
#define VSTR64_REG(Dt, Rn, Rm) EMIT(VMEM_REG_gen(0b11, 0b00, Rm, 0b011, 0, Rn, Dt))
|
||||
#define VSTR64_REG_LSL3(Dt, Rn, Rm) EMIT(VMEM_REG_gen(0b11, 0b00, Rm, 0b011, 1, Rn, Dt))
|
||||
#define VSTR64_REG_SXTW(Dt, Rn, Rm) EMIT(VMEM_REG_gen(0b11, 0b00, Rm, 0b110, 0, Rn, Dt))
|
||||
#define VSTR128_REG(Qt, Rn, Rm) EMIT(VMEM_REG_gen(0b00, 0b10, Rm, 0b011, 0, Rn, Qt))
|
||||
#define VSTR128_REG_LSL4(Qt, Rn, Rm) EMIT(VMEM_REG_gen(0b00, 0b10, Rm, 0b011, 1, Rn, Qt))
|
||||
#define VSTR128_REG_SXTW(Qt, Rn, Rm) EMIT(VMEM_REG_gen(0b00, 0b10, Rm, 0b110, 0, Rn, Qt))
|
||||
|
||||
#define VLDR_PC_gen(opc, imm19, Rt) ((opc)<<30 | 0b011<<27 | 1<<26 | (imm19)<<5 | (Rt))
|
||||
#define VLDR32_literal(Vt, imm19) EMIT(VLDR_PC_gen(0b00, ((imm19)>>2)&0x7FFFF, Vt))
|
||||
@@ -1040,7 +1180,9 @@
|
||||
#define VFMOVDQ_8(Vd, u8) EMIT(FMOV_vector_imm(1, 1, ((u8)>>5)&0b111, (u8)&0b11111, Vd))
|
||||
|
||||
#define FMOV_scalar_imm(type, imm8, Rd) (0b11110<<24 | (type)<<22 | 1<<21 | (imm8)<<13 | 0b100<<10 | (Rd))
|
||||
// FMOV to Sd, imm=7 :~6:6:6:6:6:6:5:4 :3:2:1:0....
|
||||
#define FMOVS_8(Sd, u8) EMIT(FMOV_scalar_imm(0b00, u8, Sd))
|
||||
// FMOV to Dd, imm=7 :~6:6:6:6:6:6:6:6:6:5:4 :3:2:1:0....
|
||||
#define FMOVD_8(Dd, u8) EMIT(FMOV_scalar_imm(0b01, u8, Dd))
|
||||
|
||||
// VMOV
|
||||
@@ -1062,6 +1204,12 @@
|
||||
#define VMOVHto(Wd, Vn, index) EMIT(UMOV_gen(0, ((index)<<2) | 2, Vn, Wd))
|
||||
#define VMOVSto(Wd, Vn, index) EMIT(UMOV_gen(0, ((index)<<3) | 4, Vn, Wd))
|
||||
|
||||
#define SMOV_gen(Q, imm5, Rn, Rd) ((Q)<<30 | 0b01110000<<21 | (imm5)<<16 | 0b01<<13 | 0<<12 | 1<<11 | 1<<10 | (Rn)<<5 | (Rd))
|
||||
#define SMOVQDto(Xd, Vn, index) EMIT(SMOV_gen(1, ((index)<<4) | 8, Vn, Xd))
|
||||
#define SMOVQBto(Xd, Vn, index) EMIT(SMOV_gen(1, ((index)<<1) | 1, Vn, Xd))
|
||||
#define SMOVQHto(Xd, Vn, index) EMIT(SMOV_gen(1, ((index)<<2) | 2, Vn, Xd))
|
||||
#define SMOVQSto(Xd, Vn, index) EMIT(SMOV_gen(1, ((index)<<3) | 4, Vn, Xd))
|
||||
|
||||
#define MVN_vector(Q, Rn, Rd) ((Q)<<30 | 1<<29 | 0b01110<<24 | 0b10000<<17 | 0b00101<<12 | 0b10<<10 | (Rn)<<5 | (Rd))
|
||||
#define VMVNQ(Rd, Rn) EMIT(MVN_vector(1, Rn, Rd))
|
||||
|
||||
@@ -1132,6 +1280,13 @@
|
||||
#define FABSS(Sd, Sn) EMIT(FNEGABS_scalar(0b00, 0b01, Sn, Sd))
|
||||
#define FABSD(Dd, Dn) EMIT(FNEGABS_scalar(0b01, 0b01, Dn, Dd))
|
||||
|
||||
#define FNEGABS_vector(Q, U, sz, Rn, Rd) ((Q)<<30 | (U)<<29 | 0b01110<<24 | 1<<23 | (sz)<<22 | 0b10000<<17 | 0b01111<<12 | 0b10<<10 | (Rn)<<5 | (Rd))
|
||||
#define VFNEGS(Vd, Vn) EMIT(FNEGABS_vector(0, 1, 0, Vn, Vd))
|
||||
#define VFNEGQS(Vd, Vn) EMIT(FNEGABS_vector(1, 1, 0, Vn, Vd))
|
||||
#define VFNEGQD(Vd, Vn) EMIT(FNEGABS_vector(1, 1, 1, Vn, Vd))
|
||||
#define VFABSS(Vd, Vn) EMIT(FNEGABS_vector(0, 0, 0, Vn, Vd))
|
||||
#define VFABSQS(Vd, Vn) EMIT(FNEGABS_vector(1, 0, 0, Vn, Vd))
|
||||
#define VFABSQD(Vd, Vn) EMIT(FNEGABS_vector(1, 0, 1, Vn, Vd))
|
||||
|
||||
// MUL
|
||||
#define FMUL_vector(Q, sz, Rm, Rn, Rd) ((Q)<<30 | 1<<29 | 0b01110<<24 | (sz)<<22 | 1<<21 | (Rm)<<16 | 0b11011<<11 | 1<<10 | (Rn)<<5 | (Rd))
|
||||
@@ -1143,11 +1298,6 @@
|
||||
#define FMULS(Sd, Sn, Sm) EMIT(FMUL_scalar(0b00, Sm, Sn, Sd))
|
||||
#define FMULD(Dd, Dn, Dm) EMIT(FMUL_scalar(0b01, Dm, Dn, Dd))
|
||||
|
||||
#define FMLA_vector(Q, op, sz, Rm, Rn, Rd) ((Q)<<30 | 0b01110<<24 | (op)<<23 | (sz)<<22 | 1<<21 | (Rm)<<16 | 0b11001<<11 | 1<<10 | (Rn)<<5 | (Rd))
|
||||
#define VFMLAS(Sd, Sn, Sm) EMIT(FMLA_vector(0, 0, 0, Sm, Sn, Sd))
|
||||
#define VFMLAQS(Sd, Sn, Sm) EMIT(FMLA_vector(1, 0, 0, Sm, Sn, Sd))
|
||||
#define VFMLAQD(Dd, Dn, Dm) EMIT(FMLA_vector(1, 0, 1, Dm, Dn, Dd))
|
||||
|
||||
// DIV
|
||||
#define FDIV_vector(Q, sz, Rm, Rn, Rd) ((Q)<<30 | 1<<29 | 0b01110<<24 | (sz)<<22 | 1<<21 | (Rm)<<16 | 0b11111<<11 | 1<<10 | (Rn)<<5 | (Rd))
|
||||
#define VFDIVS(Sd, Sn, Sm) EMIT(FDIV_vector(0, 0, Sm, Sn, Sd))
|
||||
@@ -1188,12 +1338,12 @@
|
||||
#define VFRSQRTSQS(Vd, Vn, Vm) EMIT(FRSQRTS_vector(1, 0, Vm, Vn, Vd))
|
||||
#define VFRSQRTSQD(Vd, Vn, Vm) EMIT(FRSQRTS_vector(1, 0, Vm, Vn, Vd))
|
||||
|
||||
// CMP
|
||||
// CMP . NZCV: unordere=0011, eq=0110, inf=1000, sup=0010
|
||||
#define FCMP_scalar(type, Rn, Rm, opc) (0b11110<<24 | (type)<<22 | 1<<21 | (Rm)<<16 | 0b1000<<10 | (Rn)<<5 | (opc)<<3)
|
||||
#define FCMPS(Sn, Sm) EMIT(FCMP_scalar(0b00, Sn, Sm, 0b00))
|
||||
#define FCMPD(Dn, Dm) EMIT(FCMP_scalar(0b01, Dn, Dm, 0b00))
|
||||
#define FCMPS_0(Sn) EMIT(FCMP_scalar(0b00, 0, Sn, 0b01))
|
||||
#define FCMPD_0(Dn) EMIT(FCMP_scalar(0b01, 0, Dn, 0b01))
|
||||
#define FCMPS(Sn, Sm) FEMIT(FCMP_scalar(0b00, Sn, Sm, 0b00))
|
||||
#define FCMPD(Dn, Dm) FEMIT(FCMP_scalar(0b01, Dn, Dm, 0b00))
|
||||
#define FCMPS_0(Sn) FEMIT(FCMP_scalar(0b00, Sn, 0, 0b01))
|
||||
#define FCMPD_0(Dn) FEMIT(FCMP_scalar(0b01, Dn, 0, 0b01))
|
||||
|
||||
// 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))
|
||||
@@ -1349,18 +1499,30 @@
|
||||
#define FCVTN(Vd, Vn) EMIT(FCVTN_vector(0, 1, Vn, Vd))
|
||||
// Convert Vn from 2*Double to higher Vd as 2*float, use FPCR rounding
|
||||
#define FCVTN2(Vd, Vn) EMIT(FCVTN_vector(1, 1, Vn, Vd))
|
||||
// Convert Vn from 2*Float to lower Vd as 2*float16 and clears the upper half, use FPCR rounding
|
||||
#define FCVTN16(Vd, Vn) EMIT(FCVTN_vector(0, 0, Vn, Vd))
|
||||
// Convert Vn from 2*Float to higher Vd as 2*float16, use FPCR rounding
|
||||
#define FCVTN162(Vd, Vn) EMIT(FCVTN_vector(1, 0, Vn, Vd))
|
||||
|
||||
#define FCVTXN_vector(Q, sz, Rn, Rd) ((Q)<<30 | 1<<29 | 0b01110<<24 | (sz)<<22 | 0b10000<<17 | 0b10110<<12 | 0b10<<10 | (Rn)<<5 | (Rd))
|
||||
// Convert Vn from 2*Double to lower Vd as 2*float and clears the upper half
|
||||
#define FCVTXN(Vd, Vn) EMIT(FCVTXN_vector(0, 1, Vn, Vd))
|
||||
// Convert Vn from 2*Double to higher Vd as 2*float
|
||||
#define FCVTXN2(Vd, Vn) EMIT(FCVTXN_vector(1, 1, Vn, Vd))
|
||||
// Convert Vn from 2*Float to lower Vd as 2*float16 and clears the upper half
|
||||
#define FCVTXN16(Vd, Vn) EMIT(FCVTXN_vector(0, 0, Vn, Vd))
|
||||
// Convert Vn from 2*Float to higher Vd as 2*float16
|
||||
#define FCVTXN162(Vd, Vn) EMIT(FCVTXN_vector(1, 0, Vn, Vd))
|
||||
|
||||
#define FCVTL_vector(Q, sz, Rn, Rd) ((Q)<<30 | 0<<29 | 0b01110<<24 | (sz)<<22 | 0b10000<<17 | 0b10111<<12 | 0b10<<10 | (Rn)<<5 | (Rd))
|
||||
// Convert lower Vn from 2*float to Vd as 2*double
|
||||
#define FCVTL(Vd, Vn) EMIT(FCVTL_vector(0, 1, Vn, Vd))
|
||||
// Convert higher Vn from 2*float to Vd as 2*double
|
||||
#define FCVTL2(Vd, Vn) EMIT(FCVTL_vector(1, 1, Vn, Vd))
|
||||
// Convert lower Vn from 2*float16 to Vd as 2*float
|
||||
#define FCVTL16(Vd, Vn) EMIT(FCVTL_vector(0, 0, Vn, Vd))
|
||||
// Convert higher Vn from 2*float16 to Vd as 2*float
|
||||
#define FCVTL162(Vd, Vn) EMIT(FCVTL_vector(1, 0, Vn, Vd))
|
||||
|
||||
#define SCVTF_scalar(sf, type, rmode, opcode, Rn, Rd) ((sf)<<31 | 0b11110<<24 | (type)<<22 | 1<<21 | (rmode)<<19 | (opcode)<<16 | (Rn)<<5 | (Rd))
|
||||
#define SCVTFSw(Sd, Wn) EMIT(SCVTF_scalar(0, 0b00, 0b00, 0b010, Wn, Sd))
|
||||
@@ -1417,6 +1579,12 @@
|
||||
#define VFMAXQS(Vd, Vn, Vm) EMIT(FMINMAX_vector(1, 0, 0, 0, Vm, Vn, Vd))
|
||||
#define VFMINQD(Vd, Vn, Vm) EMIT(FMINMAX_vector(1, 0, 1, 1, Vm, Vn, Vd))
|
||||
#define VFMAXQD(Vd, Vn, Vm) EMIT(FMINMAX_vector(1, 0, 0, 1, Vm, Vn, Vd))
|
||||
#define VFMINPS(Vd, Vn, Vm) EMIT(FMINMAX_vector(0, 1, 1, 0, Vm, Vn, Vd))
|
||||
#define VFMAXPS(Vd, Vn, Vm) EMIT(FMINMAX_vector(0, 1, 0, 0, Vm, Vn, Vd))
|
||||
#define VFMINPQS(Vd, Vn, Vm) EMIT(FMINMAX_vector(1, 1, 1, 0, Vm, Vn, Vd))
|
||||
#define VFMAXPQS(Vd, Vn, Vm) EMIT(FMINMAX_vector(1, 1, 0, 0, Vm, Vn, Vd))
|
||||
#define VFMINPQD(Vd, Vn, Vm) EMIT(FMINMAX_vector(1, 1, 1, 1, Vm, Vn, Vd))
|
||||
#define VFMAXPQD(Vd, Vn, Vm) EMIT(FMINMAX_vector(1, 1, 0, 1, Vm, Vn, Vd))
|
||||
|
||||
#define FMINMAX_scalar(type, Rm, op, Rn, Rd) (0b11110<<24 | (type)<<22 | 1<<21 | (Rm)<<16 | 0b01<<14 | (op)<<12 | 0b10<<10 | (Rn)<<5 | (Rd))
|
||||
#define FMINS(Sd, Sn, Sm) EMIT(FMINMAX_scalar(0b00, Sm, 0b01, Sn, Sd))
|
||||
@@ -1432,6 +1600,37 @@
|
||||
// FMAXNM NaN vs Number: number is picked
|
||||
#define FMAXNMD(Dd, Dn, Dm) EMIT(FMINMAX_scalar(0b01, Dm, 0b10, Dn, Dd))
|
||||
|
||||
// Fused Add Multiply
|
||||
#define FMADD_gen(type, o1, Rm, o0, Ra, Rn, Rd) (0b11111<<24 | (type)<<22 | (o1)<<21 | (Rm)<<16 | (o0)<<15 | (Ra)<<10 | (Rn)<<5 | (Rd))
|
||||
// scalar Rd = Ra + Rn*Rm
|
||||
#define FMADD_32(Sd, Sa, Sn, Sm) EMIT(FMADD_gen(0b00, 0, Sm, 0, Sa, Sn, Sd))
|
||||
// scalar Rd = Ra + Rn*Rm
|
||||
#define FMADD_64(Dd, Da, Dn, Dm) EMIT(FMADD_gen(0b01, 0, Dm, 0, Da, Dn, Dd))
|
||||
// scalar Rd = -Ra - Rn*Rm
|
||||
#define FNMADD_32(Sd, Sa, Sn, Sm) EMIT(FMADD_gen(0b00, 1, Sm, 0, Sa, Sn, Sd))
|
||||
// scalar Rd = -Ra - Rn*Rm
|
||||
#define FNMADD_64(Dd, Da, Dn, Dm) EMIT(FMADD_gen(0b01, 1, Dm, 0, Da, Dn, Dd))
|
||||
// scalar Rd = Ra - Rn*Rm
|
||||
#define FMSUB_32(Sd, Sa, Sn, Sm) EMIT(FMADD_gen(0b00, 0, Sm, 1, Sa, Sn, Sd))
|
||||
// scalar Rd = Ra - Rn*Rm
|
||||
#define FMSUB_64(Dd, Da, Dn, Dm) EMIT(FMADD_gen(0b01, 0, Dm, 1, Da, Dn, Dd))
|
||||
// scalar Rd = -Ra + Rn*Rm
|
||||
#define FNMSUB_32(Sd, Sa, Sn, Sm) EMIT(FMADD_gen(0b00, 1, Sm, 1, Sa, Sn, Sd))
|
||||
// scalar Rd = -Ra + Rn*Rm
|
||||
#define FNMSUB_64(Dd, Da, Dn, Dm) EMIT(FMADD_gen(0b01, 1, Dm, 1, Da, Dn, Dd))
|
||||
|
||||
#define FMLA_vector(Q, op, sz, Rm, Rn, Rd) ((Q)<<30 | 0b01110<<24 | (op)<<23 | (sz)<<22 | 1<<21 | (Rm)<<16 | 0b11001<<11 | 1<<10 | (Rn)<<5 | (Rd))
|
||||
// Vd += Vn*Vm
|
||||
#define VFMLAS(Vd, Vn, Vm) EMIT(FMLA_vector(0, 0, 0, Vm, Vn, Vd))
|
||||
// Vd += Vn*Vm
|
||||
#define VFMLAQS(Vd, Vn, Vm) EMIT(FMLA_vector(1, 0, 0, Vm, Vn, Vd))
|
||||
// Vd += Vn*Vm
|
||||
#define VFMLAQD(Vd, Vn, Vm) EMIT(FMLA_vector(1, 0, 1, Vm, Vn, Vd))
|
||||
// Vd -= Vn*Vm
|
||||
#define VFMLSQS(Vd, Vn, Vm) EMIT(FMLA_vector(1, 1, 0, Vm, Vn, Vd))
|
||||
// Vd -= Vn*Vm
|
||||
#define VFMLSQD(Vd, Vn, Vm) EMIT(FMLA_vector(1, 1, 1, Vm, Vn, Vd))
|
||||
|
||||
// ZIP / UZP
|
||||
#define ZIP_gen(Q, size, Rm, op, Rn, Rd) ((Q)<<30 | 0b001110<<24 | (size)<<22 | (Rm)<<16 | (op)<<14 | 0b11<<12 | 0b10<<10 | (Rn)<<5 | (Rd))
|
||||
#define VZIP1Q_8(Rt, Rn, Rm) EMIT(ZIP_gen(1, 0b00, Rm, 0, Rn, Rt))
|
||||
@@ -1465,6 +1664,16 @@
|
||||
#define VUZP1Q_64(Rt, Rn, Rm) EMIT(UZP_gen(1, 0b11, Rm, 0, Rn, Rt))
|
||||
#define VUZP2Q_64(Rt, Rn, Rm) EMIT(UZP_gen(1, 0b11, Rm, 1, Rn, Rt))
|
||||
|
||||
#define BITBIF_gen(Q, opc2, Rm, Rn, Rd) ((Q)<<30 | 0b101110<<24 | (opc2)<<22 | 1<<21 | (Rm)<<16 | 0b000111<<10 | (Rn)<<5 | (Rd))
|
||||
// Bitwise insert Vn in Vd if Vm is "0"
|
||||
#define VBIF(Vd, Vn,Vm) EMIT(BITBIF_gen(0, 0b11, Vm, Vn, Vd))
|
||||
// Bitwise insert Vn in Vd if Vm is "0"
|
||||
#define VBIFQ(Vd, Vn,Vm) EMIT(BITBIF_gen(1, 0b11, Vm, Vn, Vd))
|
||||
// Bitwise insert Vn in Vd if Vm is "1"
|
||||
#define VBIT(Vd, Vn,Vm) EMIT(BITBIF_gen(0, 0b10, Vm, Vn, Vd))
|
||||
// Bitwise insert Vn in Vd if Vm is "1"
|
||||
#define VBITQ(Vd, Vn,Vm) EMIT(BITBIF_gen(1, 0b10, Vm, Vn, Vd))
|
||||
|
||||
#define DUP_element(Q, imm5, Rn, Rd) ((Q)<<30 | 0b01110000<<21 | (imm5)<<16 | 1<<10 | (Rn)<<5 | (Rd))
|
||||
#define VDUP_8(Vd, Vn, idx) EMIT(DUP_element(0, ((idx)<<1|1), Vn, Vd))
|
||||
#define VDUPQ_8(Vd, Vn, idx) EMIT(DUP_element(1, ((idx)<<1|1), Vn, Vd))
|
||||
@@ -1563,6 +1772,15 @@
|
||||
// Signed saturating extract Unsigned Narrow, takes Rn element and reduce 16->8 with Unsigned saturation and fit higher part of Rd
|
||||
#define SQXTUN2_8(Rd, Rn) EMIT(QXTUN_vector(1, 1, 0b00, Rn, Rd))
|
||||
|
||||
#define XTN_vector(Q, size, Rn, Rd) ((Q)<<30 | 0b01110<<24 | (size)<<22 | 0b10000<<17 | 0b10010<<12 | 0b10<<10 | (Rn)<<5 | (Rd))
|
||||
// Xtract narrow to X bits
|
||||
#define XTN_8(Vd, Vn) EMIT(XTN_vector(0, 0b00, Vn, Vd))
|
||||
#define XTN_16(Vd, Vn) EMIT(XTN_vector(0, 0b01, Vn, Vd))
|
||||
#define XTN_32(Vd, Vn) EMIT(XTN_vector(0, 0b10, Vn, Vd))
|
||||
#define XTN2_8(Vd, Vn) EMIT(XTN_vector(1, 0b00, Vn, Vd))
|
||||
#define XTN2_16(Vd, Vn) EMIT(XTN_vector(1, 0b01, Vn, Vd))
|
||||
#define XTN2_32(Vd, Vn) EMIT(XTN_vector(1, 0b10, Vn, Vd))
|
||||
|
||||
// Integer CMP
|
||||
// EQual
|
||||
#define CMEQ_vector(Q, U, size, Rm, Rn, Rd) ((Q)<<30 | (U)<<29 | 0b01110<<24 | (size)<<22 | 1<<21 | (Rm)<<16 | 0b10001<<11 | 1<<10 | (Rn)<<5 | (Rd))
|
||||
@@ -1600,8 +1818,8 @@
|
||||
#define VCHIQQ_64(Rd, Rn, Rm) EMIT(CMG_vector(1, 1, 0b11, 0, Rm, Rn, Rd))
|
||||
|
||||
// Less Than 0
|
||||
#define CMLT_0_vector(Q, size, Rn, Rd) ((Q)<<30 | 0b01110<<24 | (size)<<22 | 0b10000<<17 | 0b01010<<12 | 0b10<<10 | (Rn)<<5 | (Rd))
|
||||
#define CMLT_0_8(Rd, Rn) EMIT(CMLT_0_vector(0, 0b00, Rn, Rd))
|
||||
#define CMLT_0_vector(Q, size, Rn, Rd) ((Q)<<30 | 0b01110<<24 | (size)<<22 | 0b10000<<17 | 0b01010<<12 | 0b10<<10 | (Rn)<<5 | (Rd))
|
||||
#define CMLT_0_8(Rd, Rn) EMIT(CMLT_0_vector(0, 0b00, Rn, Rd))
|
||||
#define CMLT_0_16(Rd, Rn) EMIT(CMLT_0_vector(0, 0b01, Rn, Rd))
|
||||
#define CMLT_0_32(Rd, Rn) EMIT(CMLT_0_vector(0, 0b10, Rn, Rd))
|
||||
#define CMLTQ_0_8(Rd, Rn) EMIT(CMLT_0_vector(1, 0b00, Rn, Rd))
|
||||
@@ -1655,7 +1873,7 @@
|
||||
#define FCMLTS_0(Rd, Rn) EMIT(FCMP_0_scalar(0, 0, 0b10, (Rn), (Rd)))
|
||||
#define FCMLTD_0(Rd, Rn) EMIT(FCMP_0_scalar(0, 1, 0b10, (Rn), (Rd)))
|
||||
|
||||
// Scalar Float CMP
|
||||
// Scalar Float CMEQ
|
||||
#define FCMP_op_scalar(U, E, sz, Rm, ac, Rn, Rd) (0b01<<30 | (U)<<29 | 0b11110<<24 | (E)<<23 | (sz)<<22 | 1<<21 | (Rm)<<16 | 0b1110<<12 | (ac)<<11 | 1<<10 | (Rn)<<5 | (Rd))
|
||||
#define FCMEQS(Rd, Rn, Rm) EMIT(FCMP_op_scalar(0, 0, 0, (Rm), 0, (Rn), (Rd)))
|
||||
#define FCMEQD(Rd, Rn, Rm) EMIT(FCMP_op_scalar(0, 0, 1, (Rm), 0, (Rn), (Rd)))
|
||||
@@ -1785,8 +2003,12 @@
|
||||
#define MOVI_vector(Q, op, abc, cmode, defgh, Rd) ((Q)<<30 | (op)<<29 | 0b0111100000<<19 | (abc)<<16 | (cmode)<<12 | 1<<10 | (defgh)<<5 | (Rd))
|
||||
#define MOVIQ_8(Rd, imm8) EMIT(MOVI_vector(1, 0, (((imm8)>>5)&0b111), 0b1110, ((imm8)&0b11111), Rd))
|
||||
#define MOVIQ_16(Rd, imm8, lsl8) EMIT(MOVI_vector(1, 0, (((imm8)>>5)&0b111), 0b1000|((lsl8)?0b10:0), ((imm8)&0b11111), Rd))
|
||||
#define MOVIQ_32(Rd, imm8) EMIT(MOVI_vector(1, 0, (((imm8)>>5)&0b111), 0b0000, ((imm8)&0b11111), Rd))
|
||||
#define MOVIQ_32_lsl(Rd, imm8, lsl8) EMIT(MOVI_vector(1, 0, (((imm8)>>5)&0b111), (lsl8<<1), ((imm8)&0b11111), Rd))
|
||||
#define MOVIQ_64(Rd, imm8) EMIT(MOVI_vector(1, 1, (((imm8)>>5)&0b111), 0b1110, ((imm8)&0b11111), Rd))
|
||||
#define MOVI_8(Rd, imm8) EMIT(MOVI_vector(0, 0, (((imm8)>>5)&0b111), 0b1110, ((imm8)&0b11111), Rd))
|
||||
#define MOVI_16(Rd, imm8, lsl8) EMIT(MOVI_vector(0, 0, (((imm8)>>5)&0b111), 0b1000|((lsl8)?0b10:0), ((imm8)&0b11111), Rd))
|
||||
#define MOVI_32_lsl(Rd, imm8, lsl8) EMIT(MOVI_vector(0, 0, (((imm8)>>5)&0b111), (lsl8<<1), ((imm8)&0b11111), Rd))
|
||||
#define MOVI_32(Rd, imm8) EMIT(MOVI_vector(0, 0, (((imm8)>>5)&0b111), 0b0000, ((imm8)&0b11111), Rd))
|
||||
#define MOVI_64(Rd, imm8) EMIT(MOVI_vector(0, 1, (((imm8)>>5)&0b111), 0b1110, ((imm8)&0b11111), Rd))
|
||||
|
||||
@@ -1888,6 +2110,33 @@
|
||||
#define UMINQ_32(Vd, Vn, Vm) EMIT(MINMAX_vector(1, 1, 0b10, Vm, 1, Vn, Vd))
|
||||
//#define UMINQ_64(Vd, Vn, Vm) EMIT(MINMAX_vector(1, 1, 0b11, Vm, 1, Vn, Vd))
|
||||
|
||||
// MIN or MAX accros vector
|
||||
#define MAXMINV_vector(Q, U, size, op, Rn, Rd) ((Q)<<30 | (U)<<29 | 0b01110<<24 | (size)<<22 | 0b11000<<17 | (op)<<16 | 0b1010<<12 | 0b10<<10 | (Rn)<<5 | (Rd))
|
||||
#define SMAXV_8(Vd, Vn) EMIT(MAXMINV_vector(0, 0, 0b00, 0, Vn, Vd))
|
||||
#define SMINV_8(Vd, Vn) EMIT(MAXMINV_vector(0, 0, 0b00, 1, Vn, Vd))
|
||||
#define UMAXV_8(Vd, Vn) EMIT(MAXMINV_vector(0, 1, 0b00, 0, Vn, Vd))
|
||||
#define UMINV_8(Vd, Vn) EMIT(MAXMINV_vector(0, 1, 0b00, 1, Vn, Vd))
|
||||
#define SMAXV_16(Vd, Vn) EMIT(MAXMINV_vector(0, 0, 0b01, 0, Vn, Vd))
|
||||
#define SMINV_16(Vd, Vn) EMIT(MAXMINV_vector(0, 0, 0b01, 1, Vn, Vd))
|
||||
#define UMAXV_16(Vd, Vn) EMIT(MAXMINV_vector(0, 1, 0b01, 0, Vn, Vd))
|
||||
#define UMINV_16(Vd, Vn) EMIT(MAXMINV_vector(0, 1, 0b01, 1, Vn, Vd))
|
||||
#define SMAXV_32(Vd, Vn) EMIT(MAXMINV_vector(0, 0, 0b10, 0, Vn, Vd))
|
||||
#define SMINV_32(Vd, Vn) EMIT(MAXMINV_vector(0, 0, 0b10, 1, Vn, Vd))
|
||||
#define UMAXV_32(Vd, Vn) EMIT(MAXMINV_vector(0, 1, 0b10, 0, Vn, Vd))
|
||||
#define UMINV_32(Vd, Vn) EMIT(MAXMINV_vector(0, 1, 0b10, 1, Vn, Vd))
|
||||
#define SMAXVQ_8(Vd, Vn) EMIT(MAXMINV_vector(1, 0, 0b00, 0, Vn, Vd))
|
||||
#define SMINVQ_8(Vd, Vn) EMIT(MAXMINV_vector(1, 0, 0b00, 1, Vn, Vd))
|
||||
#define UMAXVQ_8(Vd, Vn) EMIT(MAXMINV_vector(1, 1, 0b00, 0, Vn, Vd))
|
||||
#define UMINVQ_8(Vd, Vn) EMIT(MAXMINV_vector(1, 1, 0b00, 1, Vn, Vd))
|
||||
#define SMAXVQ_16(Vd, Vn) EMIT(MAXMINV_vector(1, 0, 0b01, 0, Vn, Vd))
|
||||
#define SMINVQ_16(Vd, Vn) EMIT(MAXMINV_vector(1, 0, 0b01, 1, Vn, Vd))
|
||||
#define UMAXVQ_16(Vd, Vn) EMIT(MAXMINV_vector(1, 1, 0b01, 0, Vn, Vd))
|
||||
#define UMINVQ_16(Vd, Vn) EMIT(MAXMINV_vector(1, 1, 0b01, 1, Vn, Vd))
|
||||
#define SMAXVQ_32(Vd, Vn) EMIT(MAXMINV_vector(1, 0, 0b10, 0, Vn, Vd))
|
||||
#define SMINVQ_32(Vd, Vn) EMIT(MAXMINV_vector(1, 0, 0b10, 1, Vn, Vd))
|
||||
#define UMAXVQ_32(Vd, Vn) EMIT(MAXMINV_vector(1, 1, 0b10, 0, Vn, Vd))
|
||||
#define UMINVQ_32(Vd, Vn) EMIT(MAXMINV_vector(1, 1, 0b10, 1, Vn, Vd))
|
||||
|
||||
// HADD vector
|
||||
#define HADD_vector(Q, U, size, Rm, Rn, Rd) ((Q)<<30 | (U)<<29 | 0b01110<<24 | (size)<<22 | 1<<21 | (Rm)<<16 | 1<<10 | (Rn)<<5 | (Rd))
|
||||
#define SHADD_8(Vd, Vn, Vm) EMIT(HADD_vector(0, 0, 0b00, Vm, Vn, Vd))
|
||||
@@ -1917,6 +2166,10 @@
|
||||
#define URHADDQ_16(Vd, Vn, Vm) EMIT(RHADD_vector(1, 1, 0b01, Vm, Vn, Vd))
|
||||
#define URHADDQ_32(Vd, Vn, Vm) EMIT(RHADD_vector(1, 1, 0b10, Vm, Vn, Vd))
|
||||
|
||||
//SRSHR/URSHR
|
||||
#define RSHR(Q, U, immh, immb, Rn, Rd) ((Q)<<30 | (U)<<29 | 0b011110<<23 | (immh)<<19 | (immb)<<16 | 1<<13 | 0<<12 | 1<<10 | (Rn)<<5 | (Rd))
|
||||
#define SRSHRQ_32(Vd, Vn, shift) EMIT(RSHR(1, 0, 0b0100 | (((32-(shift))>>3)&0b11), (32-(shift))&0b111, Vn, Vd))
|
||||
|
||||
// QRDMULH Signed saturating (Rounding) Doubling Multiply returning High half
|
||||
#define QDMULH_vector(Q, U, size, Rm, Rn, Rd) ((Q)<<30 | (U)<<29 | 0b01110<<24 | (size)<<22 | 1<<21 | (Rm)<<16 | 0b10110<<11 | 1<<10 | (Rn)<<5 | (Rd))
|
||||
#define SQRDMULH_8(Vd, Vn, Vm) EMIT(QDMULH_vector(0, 1, 0b00, Vm, Vn, Vd))
|
||||
@@ -2026,7 +2279,7 @@
|
||||
#define LDSETLH(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b01, 0, 1, Rs, 0b011, Rn, Rt))
|
||||
#define STSETH(Rs, Rn) EMIT(ATOMIC_gen(0b01, 0, 0, Rs, 0b011, Rn, 0b11111))
|
||||
#define STSETLH(Rs, Rn) EMIT(ATOMIC_gen(0b01, 0, 1, Rs, 0b011, Rn, 0b11111))
|
||||
// Atomic Signel Max
|
||||
// Atomic Signed Max
|
||||
#define LDSMAXxw(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 0, 0, Rs, 0b100, Rn, Rt))
|
||||
#define LDSMAXAxw(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 1, 0, Rs, 0b100, Rn, Rt))
|
||||
#define LDSMAXALxw(Rs, Rt, Rn) EMIT(ATOMIC_gen(0b10+rex.w, 1, 1, Rs, 0b100, Rn, Rt))
|
||||
@@ -2142,23 +2395,23 @@
|
||||
|
||||
// FLAGM extension
|
||||
// Invert Carry Flag
|
||||
#define CFINV() EMIT(0b1101010100<<22 | 0b0100<<12 | 0b000<<5 | 0b11111)
|
||||
#define CFINV() FEMIT(0b1101010100<<22 | 0b0100<<12 | 0b000<<5 | 0b11111)
|
||||
|
||||
#define RMIF_gen(imm6, Rn, mask) (0b10111010000<<21 | (imm6)<<15 | 0b00001<<10 | (Rn)<<5 | (mask))
|
||||
// Rotate right reg and use as NZCV
|
||||
#define RMIF(Xn, shift, mask) EMIT(RMIF_gen(shift, Xn, mask))
|
||||
#define RMIF(Xn, shift, mask) FEMIT(RMIF_gen(shift, Xn, mask))
|
||||
|
||||
#define SETF_gen(sz, Rn) (0b00111010000<<21 | (sz)<<14 | 0b0010<<10 | (Rn)<<5 | 0b1101)
|
||||
// Set NZVc with 8bit value of reg: N=bit7, Z=[0..7]==0, V=bit8 eor bit7, C unchanged
|
||||
#define SETF8(Wn) EMIT(SETF_gen(0, Wn))
|
||||
#define SETF8(Wn) FEMIT(SETF_gen(0, Wn))
|
||||
// Set NZVc with 16bit value of reg: N=bit15, Z=[0..15]==0, V=bit16 eor bit15, C unchanged
|
||||
#define SETF16(Wn) EMIT(SETF_gen(1, Wn))
|
||||
#define SETF16(Wn) FEMIT(SETF_gen(1, Wn))
|
||||
|
||||
// FLAGM2 extension
|
||||
// NZCV -> N=0 Z=C|V C=C&!V V=0
|
||||
#define AXFLAG() EMIT(0b1101010100<<22 | 0b0100<<12 | 0b010<<5 | 0b11111)
|
||||
#define AXFLAG() FEMIT(0b1101010100<<22 | 0b0100<<12 | 0b010<<5 | 0b11111)
|
||||
// NZCV -> N=!C&!Z Z=Z&C C=C|Z V=!C&Z
|
||||
#define XAFLAG() EMIT(0b1101010100<<22 | 0b0100<<12 | 0b001<<5 | 0b11111)
|
||||
#define XAFLAG() FEMIT(0b1101010100<<22 | 0b0100<<12 | 0b001<<5 | 0b11111)
|
||||
|
||||
// FRINTTS extension
|
||||
#define FRINTxx_scalar(type, op, Rn, Rd) (0b11110<<24 | (type)<<22 | 1<<21 | 0b0100<<17 | (op)<<15 | 0b10000<<10 | (Rn)<<5 | (Rd))
|
||||
@@ -2171,6 +2424,24 @@
|
||||
#define FRINT64XS(Sd, Sn) EMIT(FRINTxx_scalar(0b00, 0b11, Sn, Sd))
|
||||
#define FRINT64XD(Dd, Dn) EMIT(FRINTxx_scalar(0b01, 0b11, Dn, Dd))
|
||||
|
||||
#define FRINTxx_vector(Q, U, sz, op, Rn, Rd) ((Q)<<30 | (U)<<29 | 0b01110<<24 | (sz)<<22 | 0b10000<<17 | 0b1111<<13 | (op)<<12 | 0b10<<10 | (Rn)<<5 | (Rd))
|
||||
#define VFRINT32ZS(Vd, Vn) EMIT(FRINTxx_vector(0, 0, 0, 0, Vn, Vd))
|
||||
#define VFRINT32ZSQ(Vd, Vn) EMIT(FRINTxx_vector(1, 0, 0, 0, Vn, Vd))
|
||||
#define VFRINT32XS(Vd, Vn) EMIT(FRINTxx_vector(0, 1, 0, 0, Vn, Vd))
|
||||
#define VFRINT32XSQ(Vd, Vn) EMIT(FRINTxx_vector(1, 1, 0, 0, Vn, Vd))
|
||||
#define VFRINT32ZD(Vd, Vn) EMIT(FRINTxx_vector(0, 0, 1, 0, Vn, Vd))
|
||||
#define VFRINT32ZDQ(Vd, Vn) EMIT(FRINTxx_vector(1, 0, 1, 0, Vn, Vd))
|
||||
#define VFRINT32XD(Vd, Vn) EMIT(FRINTxx_vector(0, 1, 1, 0, Vn, Vd))
|
||||
#define VFRINT32XDQ(Vd, Vn) EMIT(FRINTxx_vector(1, 1, 1, 0, Vn, Vd))
|
||||
#define VFRINT64ZS(Vd, Vn) EMIT(FRINTxx_vector(0, 0, 0, 1, Vn, Vd))
|
||||
#define VFRINT64ZSQ(Vd, Vn) EMIT(FRINTxx_vector(1, 0, 0, 1, Vn, Vd))
|
||||
#define VFRINT64XS(Vd, Vn) EMIT(FRINTxx_vector(0, 1, 0, 1, Vn, Vd))
|
||||
#define VFRINT64XSQ(Vd, Vn) EMIT(FRINTxx_vector(1, 1, 0, 1, Vn, Vd))
|
||||
#define VFRINT64ZD(Vd, Vn) EMIT(FRINTxx_vector(0, 0, 1, 1, Vn, Vd))
|
||||
#define VFRINT64ZDQ(Vd, Vn) EMIT(FRINTxx_vector(1, 0, 1, 1, Vn, Vd))
|
||||
#define VFRINT64XD(Vd, Vn) EMIT(FRINTxx_vector(0, 1, 1, 1, Vn, Vd))
|
||||
#define VFRINT64XDQ(Vd, Vn) EMIT(FRINTxx_vector(1, 1, 1, 1, Vn, Vd))
|
||||
|
||||
// CRC32 extension
|
||||
#define CRC32C_gen(sf, Rm, sz, Rn, Rd) ((sf)<<31 | 0b11010110<<21 | (Rm)<<16 | 0b010<<13 | 1<<12 | (sz)<<10 | (Rn)<<5 | (Rd))
|
||||
#define CRC32CB(Wd, Wn, Wm) EMIT(CRC32C_gen(0, Wm, 0b00, Wn, Wd))
|
||||
|
||||
@@ -19,26 +19,9 @@ arm64_epilog:
|
||||
stp x24, x25, [x0, (8 * 14)]
|
||||
stp x26, x27, [x0, (8 * 16)] // put back reg value in emu, including EIP (so x27 must be EIP now)
|
||||
//restore all used register
|
||||
add sp, x28, 0
|
||||
//vpop {d8-d15}
|
||||
ldp x19, x20, [sp, (8 * 0)]
|
||||
ldp x21, x22, [sp, (8 * 2)]
|
||||
ldp x23, x24, [sp, (8 * 4)]
|
||||
ldp x25, x26, [sp, (8 * 6)]
|
||||
ldp x27, x28, [sp, (8 * 8)]
|
||||
ldp d8, d9, [sp, (8 *10)]
|
||||
ldp d10, d11, [sp, (8 *12)]
|
||||
ldp d12, d13, [sp, (8 *14)]
|
||||
ldp d14, d15, [sp, (8 *16)]
|
||||
add sp, sp, (8 * 18)
|
||||
ldp x30, x29, [sp], 16 // saved lr
|
||||
//end, return...
|
||||
ret
|
||||
|
||||
|
||||
.global arm64_epilog_fast
|
||||
arm64_epilog_fast:
|
||||
//restore all used register
|
||||
#ifdef _WIN32
|
||||
ldr x18, [x0, 3120]
|
||||
#endif
|
||||
add sp, x28, 0
|
||||
//vpop {d8-d15}
|
||||
ldp x19, x20, [sp, (8 * 0)]
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
#include <stdint.h>
|
||||
#include "arm64_immenc.h"
|
||||
|
||||
#define one (uint64_t)1
|
||||
|
||||
// Returns the packed valid-N-imms-immr (1-1-6-6 bits); returns 0 if bitmask is not encodable
|
||||
int convert_bitmask(uint64_t bitmask) {
|
||||
if (bitmask == 0 || bitmask == ~0ULL) return 0;
|
||||
|
||||
uint64_t size, mask, pat;
|
||||
|
||||
for (size = 6; size > 1; --size) {
|
||||
mask = (one << (1 << (size - 1))) - 1;
|
||||
pat = bitmask & mask;
|
||||
|
||||
if (pat != ((bitmask >> (1 << (size - 1))) & mask)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mask = (size >= 6) ? ~0ULL : ((one << (1 << size)) - 1);
|
||||
pat = bitmask & mask;
|
||||
|
||||
for (uint64_t i = 1; i < 7 - size; ++i) {
|
||||
uint64_t boff = i * (1 << size);
|
||||
if (((bitmask >> boff) & mask) != pat) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int immr = 0;
|
||||
uint64_t last_bit = one << ((1 << size) - 1);
|
||||
|
||||
if (pat & 1) {
|
||||
while (pat & last_bit) {
|
||||
pat = ((pat - last_bit) << 1) | 1;
|
||||
++immr;
|
||||
}
|
||||
} else {
|
||||
immr = 1 << size;
|
||||
while (!(pat & 1)) {
|
||||
pat >>= 1;
|
||||
--immr;
|
||||
}
|
||||
}
|
||||
|
||||
if (pat & (pat + 1)) return 0;
|
||||
|
||||
int to = 1;
|
||||
while (pat & (one << to)) ++to;
|
||||
|
||||
return 0x2000 + ((size == 6) << 12) + ((((0x1E << size) & 0x3F) + (to - 1)) << 6) + immr;
|
||||
}
|
||||
|
||||
#if 0
|
||||
#include <unordered_set>
|
||||
int main() {
|
||||
std::unordered_set<uint64_t> okvals;
|
||||
uint64_t val;
|
||||
|
||||
for (int n = 1; n < 7; ++n) {
|
||||
int imms0 = ((n == 6) ? 0xC0 : 0x80) + ((0x1E << n) & 0x3F);
|
||||
for (int nones = 0; nones < (1 << n) - 1; ++nones) {
|
||||
val = (one << (nones + 1)) - 1;
|
||||
for (int j = 0; j < 6 - n; ++j) {
|
||||
val += val << (1 << (n + j));
|
||||
}
|
||||
for (int immr = 0; immr < (1 << n); ++immr) {
|
||||
int exp = ((imms0 + nones) << 6) + immr;
|
||||
int got = convert_bitmask(val);
|
||||
if (exp != got) {
|
||||
printf("0x%016lX: expected %04X, got %04X\n", val, exp, got);
|
||||
}
|
||||
okvals.emplace(val);
|
||||
val = (val >> 1) | ((val & 1) << 63);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma omp parallel for
|
||||
for (uint64_t i = 1; i < 0xFFFFFFFFFFFFFFFFu; ++i) {
|
||||
int got = convert_bitmask(i);
|
||||
if (!!got != (okvals.find(i) != okvals.cend())) {
|
||||
printf("0x%016lX: expected %s, got %04X\n", i, (!!got ? "non0" : "0000"), got);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,8 @@
|
||||
#ifndef __ARM64_IMMENC_H__
|
||||
#define __ARM64_IMMENC_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
int convert_bitmask(uint64_t bitmask);
|
||||
|
||||
#endif // __ARM64_IMMENC_H__
|
||||
@@ -5,6 +5,7 @@
|
||||
.text
|
||||
.align 4
|
||||
|
||||
.extern arm64_atomics
|
||||
.global arm64_lock_read_b
|
||||
.global arm64_lock_write_b
|
||||
.global arm64_lock_read_h
|
||||
@@ -33,6 +34,7 @@
|
||||
.global arm64_lock_get_b
|
||||
.global arm64_lock_get_d
|
||||
.global arm64_lock_get_dd
|
||||
.global arm64_crc
|
||||
|
||||
arm64_lock_read_b:
|
||||
dmb ish
|
||||
@@ -104,6 +106,10 @@ arm64_lock_write_dq:
|
||||
|
||||
|
||||
arm64_lock_xchg_dd:
|
||||
adrp x3, arm64_atomics
|
||||
add x3, x3, #:lo12:arm64_atomics
|
||||
ldr w3, [x3]
|
||||
cbnz w3, arm64_atomic_xchg_dd
|
||||
dmb ish
|
||||
arm64_lock_xchg_dd_0:
|
||||
// address is x0, value is x1, return old value in x0
|
||||
@@ -113,7 +119,17 @@ arm64_lock_xchg_dd_0:
|
||||
mov x0, x2
|
||||
ret
|
||||
|
||||
arm64_atomic_xchg_dd:
|
||||
dmb ish
|
||||
// address is x0, value is x1, return old value in x0
|
||||
swpal x1, x0, [x0]
|
||||
ret
|
||||
|
||||
arm64_lock_xchg_d:
|
||||
adrp x3, arm64_atomics
|
||||
add x3, x3, #:lo12:arm64_atomics
|
||||
ldr w3, [x3]
|
||||
cbnz w3, arm64_atomic_xchg_d
|
||||
dmb ish
|
||||
arm64_lock_xchg_d_0:
|
||||
// address is x0, value is x1, return old value in x0
|
||||
@@ -123,7 +139,17 @@ arm64_lock_xchg_d_0:
|
||||
mov w0, w2
|
||||
ret
|
||||
|
||||
arm64_atomic_xchg_d:
|
||||
dmb ish
|
||||
// address is x0, value is x1, return old value in x0
|
||||
swpal w1, w0, [x0]
|
||||
ret
|
||||
|
||||
arm64_lock_xchg_h:
|
||||
adrp x3, arm64_atomics
|
||||
add x3, x3, #:lo12:arm64_atomics
|
||||
ldr w3, [x3]
|
||||
cbnz w3, arm64_atomic_xchg_h
|
||||
dmb ish
|
||||
arm64_lock_xchg_h_0:
|
||||
// address is x0, value is x1, return old value in x0
|
||||
@@ -133,7 +159,17 @@ arm64_lock_xchg_h_0:
|
||||
mov w0, w2
|
||||
ret
|
||||
|
||||
arm64_atomic_xchg_h:
|
||||
dmb ish
|
||||
// address is x0, value is x1, return old value in x0
|
||||
swpalh w1, w0, [x0]
|
||||
ret
|
||||
|
||||
arm64_lock_xchg_b:
|
||||
adrp x3, arm64_atomics
|
||||
add x3, x3, #:lo12:arm64_atomics
|
||||
ldr w3, [x3]
|
||||
cbnz w3, arm64_atomic_xchg_b
|
||||
dmb ish
|
||||
arm64_lock_xchg_b_0:
|
||||
// address is x0, value is x1, return old value in x0
|
||||
@@ -143,7 +179,17 @@ arm64_lock_xchg_b_0:
|
||||
mov w0, w2
|
||||
ret
|
||||
|
||||
arm64_atomic_xchg_b:
|
||||
dmb ish
|
||||
// address is x0, value is x1, return old value in x0
|
||||
swpalb w1, w0, [x0]
|
||||
ret
|
||||
|
||||
arm64_lock_storeifnull:
|
||||
adrp x3, arm64_atomics
|
||||
add x3, x3, #:lo12:arm64_atomics
|
||||
ldr w3, [x3]
|
||||
cbnz w3, arm64_atomic_storeifnull
|
||||
dmb ish
|
||||
1:
|
||||
// address is x0, value is x1, x1 store to x0 only if [x0] is 0. return old [x0] value
|
||||
@@ -155,7 +201,20 @@ arm64_lock_storeifnull:
|
||||
mov x0, x2
|
||||
ret
|
||||
|
||||
arm64_atomic_storeifnull:
|
||||
dmb ish
|
||||
// address is x0, value is x1, x1 store to x0 only if [x0] is 0. return old [x0] value
|
||||
mov x2, xzr
|
||||
casal x2, x1, [x0]
|
||||
mov x0, x2
|
||||
ret
|
||||
|
||||
|
||||
arm64_lock_storeifnull_d:
|
||||
adrp x3, arm64_atomics
|
||||
add x3, x3, #:lo12:arm64_atomics
|
||||
ldr w3, [x3]
|
||||
cbnz w3, arm64_atomic_storeifnull_d
|
||||
dmb ish
|
||||
1:
|
||||
// address is x0, value is w1, w1 store to x0 only if [x0] is 0. return old [x0] value
|
||||
@@ -168,7 +227,19 @@ arm64_lock_storeifnull_d:
|
||||
mov w0, w2
|
||||
ret
|
||||
|
||||
arm64_atomic_storeifnull_d:
|
||||
dmb ish
|
||||
// address is x0, value is w1, w1 store to x0 only if [x0] is 0. return old [x0] value
|
||||
mov x2, xzr
|
||||
casal w2, w1, [x0]
|
||||
mov w0, w2
|
||||
ret
|
||||
|
||||
arm64_lock_storeifref:
|
||||
adrp x3, arm64_atomics
|
||||
add x3, x3, #:lo12:arm64_atomics
|
||||
ldr w3, [x3]
|
||||
cbnz w3, arm64_atomic_storeifref
|
||||
dmb ish
|
||||
1:
|
||||
// address is x0, value is x1, x1 store to x0 only if [x0] is x2. return new [x0] value (so x1 or old value)
|
||||
@@ -183,7 +254,23 @@ arm64_lock_storeifref:
|
||||
mov x0, x3
|
||||
ret
|
||||
|
||||
arm64_atomic_storeifref:
|
||||
dmb ish
|
||||
// address is x0, value is x1, x1 store to x0 only if [x0] is x2. return new [x0] value (so x1 or old value)
|
||||
mov x3, x2
|
||||
casal x2, x1, [x0]
|
||||
cmp x2, x3
|
||||
mov x0, x1
|
||||
ret
|
||||
2:
|
||||
mov x0, x3
|
||||
ret
|
||||
|
||||
arm64_lock_storeifref_d:
|
||||
adrp x3, arm64_atomics
|
||||
add x3, x3, #:lo12:arm64_atomics
|
||||
ldr w3, [x3]
|
||||
cbnz w3, arm64_atomic_storeifref_d
|
||||
dmb ish
|
||||
1:
|
||||
// address is x0, value is w1, w1 store to x0 only if [x0] is w2. return new [x0] value (so x1 or old value)
|
||||
@@ -198,7 +285,23 @@ arm64_lock_storeifref_d:
|
||||
mov w0, w3
|
||||
ret
|
||||
|
||||
arm64_atomic_storeifref_d:
|
||||
dmb ish
|
||||
// address is x0, value is w1, w1 store to x0 only if [x0] is w2. return new [x0] value (so w1 or old value)
|
||||
mov w3, w2
|
||||
casal w2, w1, [x0]
|
||||
cmp w2, w3
|
||||
mov w0, w1
|
||||
ret
|
||||
2:
|
||||
mov w0, w3
|
||||
ret
|
||||
|
||||
arm64_lock_storeifref2_d:
|
||||
adrp x3, arm64_atomics
|
||||
add x3, x3, #:lo12:arm64_atomics
|
||||
ldr w3, [x3]
|
||||
cbnz w3, arm64_atomic_storeifref2_d
|
||||
dmb ish
|
||||
1:
|
||||
// address is x0, value is w1, w1 store to x0 only if [x0] is w2. return old [x0] value
|
||||
@@ -211,6 +314,13 @@ arm64_lock_storeifref2_d:
|
||||
mov w0, w3
|
||||
ret
|
||||
|
||||
arm64_atomic_storeifref2_d:
|
||||
dmb ish
|
||||
// address is x0, value is w1, w1 store to x0 only if [x0] is w2. return old [x0] value
|
||||
casal w2, w1, [x0]
|
||||
mov w0, w2
|
||||
ret
|
||||
|
||||
arm64_lock_decifnot0b:
|
||||
dmb ish
|
||||
1:
|
||||
@@ -242,6 +352,10 @@ arm64_lock_decifnot0:
|
||||
ret
|
||||
|
||||
arm64_lock_incif0:
|
||||
adrp x3, arm64_atomics
|
||||
add x3, x3, #:lo12:arm64_atomics
|
||||
ldr w3, [x3]
|
||||
cbnz w3, arm64_atomic_incif0
|
||||
dmb ish
|
||||
1:
|
||||
ldaxr w1, [x0]
|
||||
@@ -254,6 +368,13 @@ arm64_lock_incif0:
|
||||
mov w0, w1
|
||||
ret
|
||||
|
||||
arm64_atomic_incif0:
|
||||
mov w1, #1
|
||||
dmb ish
|
||||
swpal w1, wzr, [x0]
|
||||
mov w0, w1
|
||||
ret
|
||||
|
||||
arm64_lock_store:
|
||||
str w1, [x0]
|
||||
dmb ish
|
||||
@@ -275,3 +396,24 @@ arm64_lock_get_d:
|
||||
arm64_lock_get_dd:
|
||||
ldaxr x0, [x0]
|
||||
ret
|
||||
|
||||
arm64_crc:
|
||||
//x0 is address, w1 is len
|
||||
mov x2, x0 // address is x2 now
|
||||
mov w0, wzr // crc is w0
|
||||
1:
|
||||
cmp w1, #8
|
||||
blo 2f
|
||||
ldr x3, [x2], #8
|
||||
crc32x w0, w0, x3
|
||||
subs w1, w1, #8
|
||||
bne 1b
|
||||
2:
|
||||
cbz w1, 4f
|
||||
3:
|
||||
ldrb w3, [x2], #1
|
||||
crc32b w0, w0, w3
|
||||
subs w1, w1, #1
|
||||
bne 3b
|
||||
4:
|
||||
ret
|
||||
@@ -29,30 +29,39 @@ extern int arm64_lock_write_dq(uint64_t a, uint64_t b, void* addr);
|
||||
|
||||
// Atomically exchange value at [p] with val, return old p
|
||||
extern uintptr_t arm64_lock_xchg_dd(void* p, uintptr_t val);
|
||||
extern uintptr_t arm64_atomic_xchg_dd(void* p, uintptr_t val);
|
||||
|
||||
// Atomically exchange value at [p] with val, return old p
|
||||
extern uint32_t arm64_lock_xchg_d(void* p, uint32_t val);
|
||||
extern uint32_t arm64_atomic_xchg_d(void* p, uint32_t val);
|
||||
|
||||
// Atomically exchange value at [p] with val, return old p
|
||||
extern uint32_t arm64_lock_xchg_h(void* p, uint32_t val);
|
||||
extern uint32_t arm64_atomic_xchg_h(void* p, uint32_t val);
|
||||
|
||||
// Atomically exchange value at [p] with val, return old p
|
||||
extern uint32_t arm64_lock_xchg_b(void* p, uint32_t val);
|
||||
extern uint32_t arm64_atomic_xchg_b(void* p, uint32_t val);
|
||||
|
||||
// Atomically store value to [p] only if [p] is NULL. Return old [p] value
|
||||
extern uint32_t arm64_lock_storeifnull_d(void*p, uint32_t val);
|
||||
extern uint32_t arm64_atomic_storeifnull_d(void*p, uint32_t val);
|
||||
|
||||
// Atomically store value to [p] only if [p] is NULL. Return old [p] value
|
||||
extern void* arm64_lock_storeifnull(void*p, void* val);
|
||||
extern void* arm64_atomic_storeifnull(void*p, void* val);
|
||||
|
||||
// Atomically store value to [p] only if [p] is ref. Return new [p] value (so val or old)
|
||||
extern void* arm64_lock_storeifref(void*p, void* val, void* ref);
|
||||
extern void* arm64_atomic_storeifref(void*p, void* val, void* ref);
|
||||
|
||||
// Atomically store value to [p] only if [p] is ref. Return new [p] value (so val or old)
|
||||
extern uint32_t arm64_lock_storeifref_d(void*p, uint32_t val, uint32_t ref);
|
||||
extern uint32_t arm64_atomic_storeifref_d(void*p, uint32_t val, uint32_t ref);
|
||||
|
||||
// Atomically store value to [p] only if [p] is ref. Return new [p] value (so val or old)
|
||||
extern uint32_t arm64_lock_storeifref2_d(void*p, uint32_t val, uint32_t ref);
|
||||
extern uint32_t arm64_atomic_storeifref2_d(void*p, uint32_t val, uint32_t ref);
|
||||
|
||||
// decrement atomically the byte at [p] (but only if p not 0)
|
||||
extern void arm64_lock_decifnot0b(void*p);
|
||||
|
||||
@@ -22,6 +22,9 @@ arm64_next:
|
||||
stp x16, x17, [sp, (8 * 8)]
|
||||
stp x18, x27, [sp, (8 * 10)] // also save x27(rip) to allow change in LinkNext
|
||||
|
||||
#ifdef _WIN32
|
||||
ldr x18, [x0, 3120]
|
||||
#endif
|
||||
mov x2, x30 // "from" is in lr, so put in x2
|
||||
add x3, sp, 8*11 // x3 is address to change rip
|
||||
// call the function
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "debug.h"
|
||||
@@ -34,10 +35,12 @@ uint64_t DecodeBitMasks(int N, int imms, int immr)
|
||||
if(s==levels) return 0;
|
||||
uint64_t mask = (1LL<<(s+1))-1;
|
||||
if(r) { // rotate
|
||||
mask=(mask>>r)|(mask<<(e-r));
|
||||
mask&=((1LL<<e)-1);
|
||||
mask=(mask>>r)|(mask<<(e-r));
|
||||
if(e<64) {
|
||||
mask&=((1LL<<e)-1);
|
||||
}
|
||||
}
|
||||
while (e<64) { // replicate
|
||||
while(e<64) { // replicate
|
||||
mask|=(mask<<e);
|
||||
e<<=1;
|
||||
}
|
||||
@@ -122,6 +125,22 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
snprintf(buff, sizeof(buff), "NOP");
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "11010101000000110010000001011111", &a)) {
|
||||
snprintf(buff, sizeof(buff), "WFE");
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "11010101000000110010000001111111", &a)) {
|
||||
snprintf(buff, sizeof(buff), "WFI");
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "11010101000000110010000000111111", &a)) {
|
||||
snprintf(buff, sizeof(buff), "YIELD");
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "11010101000000110010000010111111", &a)) {
|
||||
snprintf(buff, sizeof(buff), "SEVL");
|
||||
return buff;
|
||||
}
|
||||
// --- LDR / STR
|
||||
if(isMask(opcode, "f010100011iiiiiii22222nnnnnttttt", &a)) {
|
||||
int offset = signExtend(imm, 7)<<(2+sf);
|
||||
@@ -387,13 +406,13 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
}
|
||||
if(isMask(opcode, "f00100101wwiiiiiiiiiiiiiiiiddddd", &a)) {
|
||||
if(sf) {
|
||||
uint64_t noti=~(uint64_t)imm;
|
||||
uint64_t noti=~(((uint64_t)imm)<<(hw*16));
|
||||
if(!hw)
|
||||
snprintf(buff, sizeof(buff), "MOVN %s, 0x%x\t; 0x%lx", Xt[Rd], imm, noti);
|
||||
snprintf(buff, sizeof(buff), "MOVN %s, 0x%x\t; 0x%"PRIx64, Xt[Rd], imm, noti);
|
||||
else
|
||||
snprintf(buff, sizeof(buff), "MOVN %s, 0x%x LSL %d\t; 0x%lx", Xt[Rd], imm, 16*hw, noti);
|
||||
snprintf(buff, sizeof(buff), "MOVN %s, 0x%x LSL %d\t; 0x%"PRIx64, Xt[Rd], imm, 16*hw, noti);
|
||||
} else {
|
||||
uint32_t noti=~(uint32_t)imm;
|
||||
uint32_t noti=~(((uint32_t)imm)<<(hw*16));
|
||||
if(!hw)
|
||||
snprintf(buff, sizeof(buff), "MOVN %s, 0x%x\t; 0x%x", Wt[Rd], imm, noti);
|
||||
else
|
||||
@@ -536,16 +555,26 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
snprintf(buff, sizeof(buff), "SUBS %s, %s, %s %s %d", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm], shifts[shift], imm);
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "f1001011001mmmmmoooiiinnnnnddddd", &a)) {
|
||||
const char* shifts[2][8] = {{ "UXTB", "UXTH", "LSL", "UXTX", "SXTB", "SXTH", "SXTW", "SXTX"}, {"UXTB", "UXTH", "UXTW", "LSL", "SXTB", "SXTH", "SXTW", "SXTX" }};
|
||||
if(((sf==0 && shift==2) || (sf==1 && shift==3)) && imm==0)
|
||||
snprintf(buff, sizeof(buff), "SUB %s, %s, %s", sf?XtSp[Rd]:WtSp[Rd], sf?XtSp[Rn]:WtSp[Rn], sf?XtSp[Rm]:WtSp[Rm]);
|
||||
else if(shift==0)
|
||||
snprintf(buff, sizeof(buff), "SUB %s, %s, %s %s", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm], shifts[sf][shift]);
|
||||
else
|
||||
snprintf(buff, sizeof(buff), "SUB %s, %s, %s %s %d", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm], shifts[sf][shift], imm);
|
||||
return buff;
|
||||
}
|
||||
// ---- LOGIC
|
||||
if(isMask(opcode, "f11100100Nrrrrrrssssssnnnnnddddd", &a)) {
|
||||
uint64_t i = DecodeBitMasks(a.N, imms, immr);
|
||||
if(!sf) i&=0xffffffff;
|
||||
if(sf==0 && a.N==1)
|
||||
snprintf(buff, sizeof(buff), "invalid ANDS %s, %s, 0x%lx", Wt[Rd], Wt[Rn], i);
|
||||
snprintf(buff, sizeof(buff), "invalid ANDS %s, %s, 0x%"PRIx64, Wt[Rd], Wt[Rn], i);
|
||||
else if(Rd==31)
|
||||
snprintf(buff, sizeof(buff), "TST %s, 0x%lx", sf?Xt[Rn]:Wt[Rn], i);
|
||||
snprintf(buff, sizeof(buff), "TST %s, 0x%"PRIx64, sf?Xt[Rn]:Wt[Rn], i);
|
||||
else
|
||||
snprintf(buff, sizeof(buff), "ANDS %s, %s, 0x%lx", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], i);
|
||||
snprintf(buff, sizeof(buff), "ANDS %s, %s, 0x%"PRIx64, sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], i);
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "f1101010hh0mmmmmiiiiiinnnnnddddd", &a)) {
|
||||
@@ -571,13 +600,21 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
snprintf(buff, sizeof(buff), "BIC %s, %s, %s, %s %d", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm], shifts[shift], imm);
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "f1101010hh1mmmmmiiiiiinnnnnddddd", &a)) {
|
||||
const char* shifts[] = { "LSL", "LSR", "ASR", "ROR" };
|
||||
if(shift==0 && imm==0)
|
||||
snprintf(buff, sizeof(buff), "BICS %s, %s, %s", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm]);
|
||||
else
|
||||
snprintf(buff, sizeof(buff), "BICS %s, %s, %s, %s %d", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm], shifts[shift], imm);
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "f01100100Nrrrrrrssssssnnnnnddddd", &a)) {
|
||||
uint64_t i = DecodeBitMasks(a.N, imms, immr);
|
||||
if(!sf) i&=0xffffffff;
|
||||
if(sf==0 && a.N==1)
|
||||
snprintf(buff, sizeof(buff), "invalid ORR %s, %s, 0x%lx", Wt[Rd], Wt[Rn], i);
|
||||
snprintf(buff, sizeof(buff), "invalid ORR %s, %s, 0x%"PRIx64, Wt[Rd], Wt[Rn], i);
|
||||
else
|
||||
snprintf(buff, sizeof(buff), "ORR %s, %s, 0x%lx", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], i);
|
||||
snprintf(buff, sizeof(buff), "ORR %s, %s, 0x%"PRIx64, sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], i);
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "f0101010hh1mmmmmiiiiiinnnnnddddd", &a)) {
|
||||
@@ -610,9 +647,9 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
uint64_t i = DecodeBitMasks(a.N, imms, immr);
|
||||
if(!sf) i&=0xffffffff;
|
||||
if(sf==0 && a.N==1)
|
||||
snprintf(buff, sizeof(buff), "invalid EOR %s, %s, 0x%lx", Wt[Rd], Wt[Rn], i);
|
||||
snprintf(buff, sizeof(buff), "invalid EOR %s, %s, 0x%"PRIx64, Wt[Rd], Wt[Rn], i);
|
||||
else
|
||||
snprintf(buff, sizeof(buff), "EOR %s, %s, 0x%lx", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], i);
|
||||
snprintf(buff, sizeof(buff), "EOR %s, %s, 0x%"PRIx64, sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], i);
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "f1001010hh0mmmmmiiiiiinnnnnddddd", &a)) {
|
||||
@@ -627,9 +664,9 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
uint64_t i = DecodeBitMasks(a.N, imms, immr);
|
||||
if(!sf) i&=0xffffffff;
|
||||
if(sf==0 && a.N==1)
|
||||
snprintf(buff, sizeof(buff), "invalid AND %s, %s, 0x%lx", Wt[Rd], Wt[Rn], i);
|
||||
snprintf(buff, sizeof(buff), "invalid AND %s, %s, 0x%"PRIx64, Wt[Rd], Wt[Rn], i);
|
||||
else
|
||||
snprintf(buff, sizeof(buff), "AND %s, %s, 0x%lx", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], i);
|
||||
snprintf(buff, sizeof(buff), "AND %s, %s, 0x%"PRIx64, sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], i);
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "f0001010hh0mmmmmiiiiiinnnnnddddd", &a)) {
|
||||
@@ -717,8 +754,12 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
snprintf(buff, sizeof(buff), "BFC %s, %d, %d", sf?Xt[Rd]:Wt[Rd], lsb, width);
|
||||
else
|
||||
snprintf(buff, sizeof(buff), "BFI %s, %s, %d, %d", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], lsb, width);
|
||||
} else
|
||||
snprintf(buff, sizeof(buff), "BFXIL %s, %s, %d, %d", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], immr, imms-immr+1);
|
||||
} else {
|
||||
if(Rn==31 && immr==0)
|
||||
snprintf(buff, sizeof(buff), "BFC %s, %d, %d", sf?Xt[Rd]:Wt[Rd], immr, imms-immr+1);
|
||||
else
|
||||
snprintf(buff, sizeof(buff), "BFXIL %s, %s, %d, %d", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], immr, imms-immr+1);
|
||||
}
|
||||
return buff;
|
||||
}
|
||||
// ---- BRANCH / TEST
|
||||
@@ -730,6 +771,13 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
snprintf(buff, sizeof(buff), "BLR %s", Xt[Rn]);
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "1101011001011111000000nnnnn00000", &a)) {
|
||||
if(Rn==30)
|
||||
snprintf(buff, sizeof(buff), "RET");
|
||||
else
|
||||
snprintf(buff, sizeof(buff), "RET %s", Xt[Rn]);
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "01010100iiiiiiiiiiiiiiiiiii0cccc", &a)) {
|
||||
int offset = signExtend(imm, 19)<<2;
|
||||
snprintf(buff, sizeof(buff), "B.%s #+%di\t; %p", conds[cond], offset>>2, (void*)(addr + offset));
|
||||
@@ -742,27 +790,22 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
}
|
||||
if(isMask(opcode, "f0110100iiiiiiiiiiiiiiiiiiittttt", &a)) {
|
||||
int offset = signExtend(imm, 19)<<2;
|
||||
snprintf(buff, sizeof(buff), "CBZ %s, #%+di\t; %p", Xt[Rt], offset>>2, (void*)(addr + offset));
|
||||
snprintf(buff, sizeof(buff), "CBZ %s, #%+di\t; %p", sf?Xt[Rt]:Wt[Rt], offset>>2, (void*)(addr + offset));
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "f0110101iiiiiiiiiiiiiiiiiiittttt", &a)) {
|
||||
int offset = signExtend(imm, 19)<<2;
|
||||
snprintf(buff, sizeof(buff), "CBNZ %s, #%+di\t; %p", Xt[Rt], offset>>2, (void*)(addr + offset));
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "f0110100iiiiiiiiiiiiiiiiiiittttt", &a)) {
|
||||
int offset = signExtend(imm, 19)<<2;
|
||||
snprintf(buff, sizeof(buff), "CBZ %s, #%+di\t; %p", Xt[Rt], offset>>2, (void*)(addr + offset));
|
||||
snprintf(buff, sizeof(buff), "CBNZ %s, #%+di\t; %p", sf?Xt[Rt]:Wt[Rt], offset>>2, (void*)(addr + offset));
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "s0110110sssssiiiiiiiiiiiiiittttt", &a)) {
|
||||
int offset = signExtend(imm, 14)<<2;
|
||||
snprintf(buff, sizeof(buff), "TBZ %s, 0x%x, #%+di\t; %p", (imms<31)?Xt[Rt]:Wt[Rt], imms, offset>>2, (void*)(addr + offset));
|
||||
snprintf(buff, sizeof(buff), "TBZ %s, %d, #%+di\t; %p", (imms<31)?Xt[Rt]:Wt[Rt], imms, offset>>2, (void*)(addr + offset));
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "s0110111sssssiiiiiiiiiiiiiittttt", &a)) {
|
||||
int offset = signExtend(imm, 14)<<2;
|
||||
snprintf(buff, sizeof(buff), "TBNZ %s, 0x%x, #%+di\t; %p", (imms<31)?Xt[Rt]:Wt[Rt], imms, offset>>2, (void*)(addr + offset));
|
||||
snprintf(buff, sizeof(buff), "TBNZ %s, %d, #%+di\t; %p", (imms<31)?Xt[Rt]:Wt[Rt], imms, offset>>2, (void*)(addr + offset));
|
||||
return buff;
|
||||
}
|
||||
|
||||
@@ -914,7 +957,6 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
}
|
||||
// UMOV
|
||||
if(isMask(opcode, "0Q001110000rrrrr001111nnnnnddddd", &a)) {
|
||||
char q = a.Q?'Q':'D';
|
||||
char s = '?';
|
||||
int sz=0;
|
||||
if(a.Q==0 && immr&1) {s='B'; sz=0; }
|
||||
@@ -923,9 +965,24 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
else if(a.Q==1 && (immr&15)==8) {s='D'; sz=3; }
|
||||
int index = (immr)>>(sz+1);
|
||||
if(sz>2)
|
||||
snprintf(buff, sizeof(buff), "MOV %s, %c%d.%c[%d]", a.Q?Xt[Rd]:Wt[Rd], q, Rn, s, index);
|
||||
snprintf(buff, sizeof(buff), "MOV %s, V%d.%c[%d]", a.Q?Xt[Rd]:Wt[Rd], Rn, s, index);
|
||||
else
|
||||
snprintf(buff, sizeof(buff), "UMOV %s, %c%d.%c[%d]", a.Q?Xt[Rd]:Wt[Rd], q, Rn, s, index);
|
||||
snprintf(buff, sizeof(buff), "UMOV %s, V%d.%c[%d]", a.Q?Xt[Rd]:Wt[Rd], Rn, s, index);
|
||||
return buff;
|
||||
}
|
||||
// SMOV
|
||||
if(isMask(opcode, "0Q001110000rrrrr001011nnnnnddddd", &a)) {
|
||||
char s = '?';
|
||||
int sz=0;
|
||||
if(a.Q==0 && immr&1) {s='B'; sz=0; }
|
||||
else if(/*a.Q==0 &&*/ (immr&3)==2) {s='H'; sz=1; }
|
||||
else if(/*a.Q==0 &&*/ (immr&7)==4) {s='S'; sz=2; }
|
||||
else if(a.Q==1 && (immr&15)==8) {s='D'; sz=3; }
|
||||
int index = (immr)>>(sz+1);
|
||||
if(sz>2)
|
||||
snprintf(buff, sizeof(buff), "MOV %s, V%d.%c[%d]", a.Q?Xt[Rd]:Wt[Rd], Rn, s, index);
|
||||
else
|
||||
snprintf(buff, sizeof(buff), "SMOV %s, V%d.%c[%d]", a.Q?Xt[Rd]:Wt[Rd], Rn, s, index);
|
||||
return buff;
|
||||
}
|
||||
// VEOR
|
||||
@@ -950,6 +1007,12 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
snprintf(buff, sizeof(buff), "VMUL V%d.%s, V%d.%s, V%d.%s", Rd, Vd, Rn, Vd, Rm, Vd);
|
||||
return buff;
|
||||
}
|
||||
// VBIT / VBIF
|
||||
if(isMask(opcode, "0Q1011101o1mmmmm000111nnnnnddddd", &a)) {
|
||||
char q = a.Q?'Q':'D';
|
||||
snprintf(buff, sizeof(buff), "VBI%c %c%d, %c%d, %c%d", a.o?'F':'T', q, Rd, q, Rn, q, Rm);
|
||||
return buff;
|
||||
}
|
||||
// CMP
|
||||
if(isMask(opcode, "0Q101110ff1mmmmm100011nnnnnddddd", &a)) {
|
||||
const char* Y[] = {"8B", "16B", "4H", "8H", "2S", "4S", "??", "2D"};
|
||||
@@ -1005,6 +1068,19 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
snprintf(buff, sizeof(buff), "MOVI V%d.%s, #0x%x", Rd, Vd, imm<<8);
|
||||
return buff;
|
||||
}
|
||||
// MOV immediate 64bits
|
||||
if(isMask(opcode, "0Q10111100000iii111001iiiiiddddd", &a)) {
|
||||
uint64_t tmp64u = 0;
|
||||
for(int i=0; i<8; ++i)
|
||||
if((imm)&(1<<i))
|
||||
tmp64u |= 0xffLL<<(i*8);
|
||||
|
||||
if(a.Q)
|
||||
snprintf(buff, sizeof(buff), "MOVI V%d.2D, #0x%016"PRIx64, Rd, tmp64u);
|
||||
else
|
||||
snprintf(buff, sizeof(buff), "MOVI D%d, #0x%016"PRIx64, Rd, tmp64u);
|
||||
return buff;
|
||||
}
|
||||
|
||||
// Shift
|
||||
if(isMask(opcode, "0QU011110hhhhrrr000001nnnnnddddd", &a)) {
|
||||
@@ -1043,7 +1119,7 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
|
||||
// ADR
|
||||
if(isMask(opcode, "0ss10000iiiiiiiiiiiiiiiiiiiddddd", &a)) {
|
||||
snprintf(buff, sizeof(buff), "ADR, %s, %ld", Xt[Rd], signExtend((imm)<<2|(imms), 20));
|
||||
snprintf(buff, sizeof(buff), "ADR, %s, %"PRId64, Xt[Rd], signExtend((imm)<<2|(imms), 20));
|
||||
return buff;
|
||||
}
|
||||
|
||||
@@ -1265,6 +1341,12 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
snprintf(buff, sizeof(buff), "FCMP %c%d, %c%d", s, Rn, s, Rm);
|
||||
return buff;
|
||||
}
|
||||
//FCMEQ
|
||||
if(isMask(opcode, "010111100f1mmmmm111001nnnnnddddd", &a)) {
|
||||
char s = (sf==0)?'S':'D';
|
||||
snprintf(buff, sizeof(buff), "FCMEQ %c%d, %c%d, %c%d", s, Rd, s, Rn, s, Rm);
|
||||
return buff;
|
||||
}
|
||||
//FCMP vector
|
||||
if(isMask(opcode, "0QU01110cf1mmmmm111001nnnnnddddd", &a)) {
|
||||
char s = (sf==0)?'S':((sf==1)?'D':'?');
|
||||
@@ -1281,18 +1363,40 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
snprintf(buff, sizeof(buff), "F%s %c%d, %c%d, %c%d", (option==3)?"MINNM":((option==2)?"MAXNM":((!option)?"MAX":"MIN")), s, Rd, s, Rn, s, Rm);
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "0Q001110of1mmmmm110001nnnnnddddd", &a)) {
|
||||
if(isMask(opcode, "0QU01110of1mmmmm110001nnnnnddddd", &a)) {
|
||||
char s = (sf==0)?'S':((sf==1)?'D':'?');
|
||||
int n = (sf==0)?2:1;
|
||||
n *= a.Q?2:1;
|
||||
snprintf(buff, sizeof(buff), "F%sNM%s V%d.%d%c, V%d.%d%c, V%d.%d%c", option?"MIN":"MAX", a.Q?"Q":"", Rd, n, s, Rn, n, s, Rm, n, s);
|
||||
snprintf(buff, sizeof(buff), "F%sNM%s%s V%d.%d%c, V%d.%d%c, V%d.%d%c", option?"MIN":"MAX", a.U?"P":"", a.Q?"Q":"", Rd, n, s, Rn, n, s, Rm, n, s);
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "0Q001110of1mmmmm111101nnnnnddddd", &a)) {
|
||||
if(isMask(opcode, "0QU01110of1mmmmm111101nnnnnddddd", &a)) {
|
||||
char s = (sf==0)?'S':((sf==1)?'D':'?');
|
||||
int n = (sf==0)?2:1;
|
||||
n *= a.Q?2:1;
|
||||
snprintf(buff, sizeof(buff), "F%s%s V%d.%d%c, V%d.%d%c, V%d.%d%c", option?"MIN":"MAX", a.Q?"Q":"", Rd, n, s, Rn, n, s, Rm, n, s);
|
||||
snprintf(buff, sizeof(buff), "F%s%s%s V%d.%d%c, V%d.%d%c, V%d.%d%c", option?"MIN":"MAX", a.U?"P":"", a.Q?"Q":"", Rd, n, s, Rn, n, s, Rm, n, s);
|
||||
return buff;
|
||||
}
|
||||
// FMADD
|
||||
if(isMask(opcode, "00011111tt0mmmmmoaaaaannnnnddddd", &a)) {
|
||||
char s = (a.t==0b00)?'S':((a.t==0b01)?'D':'?');
|
||||
int n = (a.t==0)?1:2;
|
||||
snprintf(buff, sizeof(buff), "FM%s V%d.%d%c, V%d.%d%c, V%d.%d%c, V%d.%d%c", option?"SUB":"ADD", Rd, n, s, Ra, n, s, Rn, n, s, Rm, n, s);
|
||||
return buff;
|
||||
}
|
||||
// FNMADD
|
||||
if(isMask(opcode, "00011111tt1mmmmmoaaaaannnnnddddd", &a)) {
|
||||
char s = (a.t==0b00)?'S':((a.t==0b01)?'D':'?');
|
||||
int n = (a.t==0)?1:2;
|
||||
snprintf(buff, sizeof(buff), "FNM%s V%d.%d%c, V%d.%d%c, V%d.%d%c, V%d.%d%c", option?"SUB":"ADD", Rd, n, s, Ra, n, s, Rn, n, s, Rm, n, s);
|
||||
return buff;
|
||||
}
|
||||
// FMLA
|
||||
if(isMask(opcode, "0Q001110of1mmmmm110011nnnnnddddd", &a)) {
|
||||
char s = (sf==0)?'S':((sf==1)?'D':'?');
|
||||
int n = (sf==0)?2:1;
|
||||
n *= a.Q?2:1;
|
||||
snprintf(buff, sizeof(buff), "FML%s%s V%d.%d%c, V%d.%d%c, V%d.%d%c", option?"S":"A", a.Q?"Q":"", Rd, n, s, Rn, n, s, Rm, n, s);
|
||||
return buff;
|
||||
}
|
||||
// NEG
|
||||
@@ -1484,6 +1588,28 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
snprintf(buff, sizeof(buff), "%cRHADD V%d.%s, V%d.%s, V%d.%s", a.U?'U':'S', Rd, Vd, Rn, Vd, Rm, Vd);
|
||||
return buff;
|
||||
}
|
||||
//S/URSHR
|
||||
if(isMask(opcode, "0QU011110iiiiiii001001nnnnnddddd", &a)) {
|
||||
int shft = 0;
|
||||
int sz = 0;
|
||||
const char* Y[] = {"8B", "16B", "4H", "8H", "2S", "4S", "??", "2D"};
|
||||
if(imm&0b1000000) {
|
||||
sz = 3;
|
||||
shft = imm&0b111111;
|
||||
} else if(imm&0b100000) {
|
||||
sz = 2;
|
||||
shft = imm&0b1111;
|
||||
} else if(imm&0b10000) {
|
||||
sz = 1;
|
||||
shft = imm&0b111;
|
||||
} else if(imm&0b1000) {
|
||||
sz = 0;
|
||||
shft = imm&0b111;
|
||||
}
|
||||
const char* Vd = Y[(sz<<1) | a.Q];
|
||||
snprintf(buff, sizeof(buff), "%cRSHR V%d.%s, V%d.%s, #%d", a.U?'U':'S', Rd, Vd, Rn, Vd, shft);
|
||||
return buff;
|
||||
}
|
||||
//SQ(R)DMULH
|
||||
if(isMask(opcode, "0QU01110ff1mmmmm101101nnnnnddddd", &a)) {
|
||||
const char* Y[] = {"8B", "16B", "4H", "8H", "2S", "4S", "??", "???"};
|
||||
@@ -1493,12 +1619,12 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
}
|
||||
|
||||
// LD1/ST1 single structure
|
||||
if(isMask(opcode, "0Q0011010L000000cc0Sffnnnnnttttt", &a)) {
|
||||
if(isMask(opcode, "0Q0011010Lo00000cc0Sffnnnnnttttt", &a)) {
|
||||
int scale = a.c;
|
||||
int idx = 0;
|
||||
const char* Y[] = {"B", "H", "S", "D"};
|
||||
switch(scale) {
|
||||
case 3: scale = sf; /* rep = 1; */ break;
|
||||
case 3: scale = sf; /* rep = 1; */ idx=(8*(a.Q+1))>>scale; break;
|
||||
case 0: idx = (a.Q<<3) | (a.S<<2) | sf; break;
|
||||
case 1: idx = (a.Q<<2) | (a.S<<1) | (sf>>1); break;
|
||||
case 2: if(!(sf&1))
|
||||
@@ -1509,7 +1635,10 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
}
|
||||
break;
|
||||
}
|
||||
snprintf(buff, sizeof(buff), "%s1 {V%d.%s}[%d], [%s]", a.L?"LD":"ST", Rt, Y[scale], idx, XtSp[Rn]);
|
||||
if(!option && a.L && scale==3)
|
||||
snprintf(buff, sizeof(buff), "LD1R {V%d.%d%s}, [%s]", Rt, idx, Y[scale], XtSp[Rn]);
|
||||
else
|
||||
snprintf(buff, sizeof(buff), "%s1 {V%d.%s}[%d], [%s]", a.L?"LD":"ST", Rt, Y[scale], idx, XtSp[Rn]);
|
||||
return buff;
|
||||
}
|
||||
// LDUR/STUR
|
||||
@@ -1538,6 +1667,17 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
snprintf(buff, sizeof(buff), "%sR %s%d, [%s, %+d]", a.L?"LD":"ST", Y[sz], Rt, XtSp[Rn], imm);
|
||||
return buff;
|
||||
}
|
||||
// LDP/STP vector
|
||||
if(isMask(opcode, "ff1011010Liiiiiii22222nnnnnttttt", &a)) {
|
||||
const char* Y[] = {"S", "D", "Q", "?"};
|
||||
int sz = sf;
|
||||
int offset = signExtend(imm, 7)<<(2+sz);
|
||||
if(!offset)
|
||||
snprintf(buff, sizeof(buff), "%sP %s%d, %s%d, [%s]", a.L?"LD":"ST", Y[sz], Rt, Y[sz], Rt2, XtSp[Rn]);
|
||||
else
|
||||
snprintf(buff, sizeof(buff), "%sP %s%d, %s%d, [%s, %s0x%x]", a.L?"LD":"ST", Y[sz], Rt, Y[sz], Rt2, XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
return buff;
|
||||
}
|
||||
|
||||
// (S/U)QXT(U)N
|
||||
if(isMask(opcode, "0Q101110ff100001001010nnnnnddddd", &a)) {
|
||||
@@ -1556,6 +1696,11 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
snprintf(buff, sizeof(buff), "%cQXTN%s V%d.%s, V%d.%s", a.U?'U':'S', a.Q?"2":"", Rd, Vd, Rn, Va);
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "01U11110ff100001010010nnnnnddddd", &a)) {
|
||||
const char Z[] = {'B', 'H', 'S', 'D', '?'};
|
||||
snprintf(buff, sizeof(buff), "SQXT%sN %c%d, %c%d", a.U?"U":"", Z[sf], Rd, Z[sf+1], Rn);
|
||||
return buff;
|
||||
}
|
||||
|
||||
// (S/U)SSHL(2) / (U/S)XTL(2)
|
||||
if(isMask(opcode, "0QU011110hhhhiii101001nnnnnddddd", &a)) {
|
||||
@@ -1574,6 +1719,26 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
snprintf(buff, sizeof(buff), "%cSHLL%s V%d.%s, V%d.%s, #%d", a.U?'U':'S', a.Q?"2":"", Rd, Va, Rn, Vd, sh);
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "0Q0011110hhhhiii010101nnnnnddddd", &a) && (a.h != 0b1000)) {
|
||||
const char* Y[] = {"8B", "16B", "4H", "8H", "2S", "4S", "??", "2D"};
|
||||
int sz = 3;
|
||||
if((a.h&0b1111)==0b0001) sz=0;
|
||||
else if((a.h&0b1110)==0b0010) sz=1;
|
||||
else if((a.h&0b1100)==0b0100) sz=2;
|
||||
int sh=(((a.h)<<3)|(imm)) - (8<<sz);
|
||||
const char* Vd = Y[(sz<<1)|a.Q];
|
||||
snprintf(buff, sizeof(buff), "SHL%s V%d.%s, V%d.%s, #%d", a.Q?"Q":"", Rd, Vd, Rn, Vd, sh);
|
||||
return buff;
|
||||
}
|
||||
|
||||
// CNT
|
||||
if(isMask(opcode, "0Q00111000100000010110nnnnnddddd", &a)) {
|
||||
const char* Y[] = {"8B", "16B"};
|
||||
const char* Vd = Y[a.Q];
|
||||
const char* Va = Y[a.Q];
|
||||
snprintf(buff, sizeof(buff), "CNT V%d.%s, V%d.%s", Rd, Vd, Rn, Va);
|
||||
return buff;
|
||||
}
|
||||
|
||||
// DUP
|
||||
if(isMask(opcode, "0Q001110000iiiii000001nnnnnddddd", &a)) {
|
||||
@@ -1583,7 +1748,7 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
if((imm&0b0001)==0b0001) sz=0;
|
||||
else if((imm&0b0011)==0b0010) sz=1;
|
||||
else if((imm&0b0111)==0b0100) sz=2;
|
||||
int sh=imm - (1<<sz);
|
||||
int sh=(imm>>sz) - 1;
|
||||
const char* Vd = Y[(sz<<1)|a.Q];
|
||||
const char* Vn = Z[sz];
|
||||
snprintf(buff, sizeof(buff), "DUP V%d.%s, V%d.%s[%d]", Rd, Vd, Rn, Vn, sh);
|
||||
@@ -1620,15 +1785,47 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
snprintf(buff, sizeof(buff), "PMULL%s V%d.%s, V%d.%s, V%d.%s", a.Q?"2":"", Rd, Vd, Rn, Vn, Rm, Vn);
|
||||
return buff;
|
||||
}
|
||||
|
||||
// DMB ISH
|
||||
if(isMask(opcode, "11010101000000110011nnnn10111111", &a)) {
|
||||
snprintf(buff, sizeof(buff), "DMB %s", (Rn==0b1011)?"ISH":"???");
|
||||
// [S/U]MULL
|
||||
if(isMask(opcode, "0QU01110ff1mmmmm110000nnnnnddddd", &a)) {
|
||||
const char* Y[] = {"8B", "16B", "4H", "8H", "2S", "4S", "??", "??"};
|
||||
const char* Z[] = {"8H", "4S", "2D", "??"};
|
||||
int sz = sf;
|
||||
const char* Vn = Y[(sz<<1)|a.Q];
|
||||
const char* Vd = Z[sz];
|
||||
snprintf(buff, sizeof(buff), "%cMULL%s V%d.%s, V%d.%s, V%d.%s", a.U?'U':'S', a.Q?"2":"", Rd, Vd, Rn, Vn, Rm, Vn);
|
||||
return buff;
|
||||
}
|
||||
// DSB ISH/ISHST
|
||||
//XTN(2)
|
||||
if(isMask(opcode, "0Q001110ff100001001010nnnnnddddd", &a)) {
|
||||
const char* Y[] = {"8B", "16B", "4H", "8H", "2S", "4S", "??", "??"};
|
||||
const char* Z[] = {"8H", "4S", "2D", "??"};
|
||||
int sz = sf;
|
||||
const char* Vd = Y[(sz<<1)|a.Q];
|
||||
const char* Vn = Z[sz];
|
||||
snprintf(buff, sizeof(buff), "XTN%s V%d.%s, V%d.%s", a.Q?"2":"", Rd, Vd, Rn, Vn);
|
||||
return buff;
|
||||
}
|
||||
|
||||
// DMB
|
||||
if(isMask(opcode, "11010101000000110011nnnn10111111", &a)) {
|
||||
const char* barrier[] = {
|
||||
"???", "???", "???", "???", // 0-3
|
||||
"???", "???", "???", "???", // 4-7
|
||||
"???", "ISHLD", "ISHST", "ISH", // 8-11
|
||||
"???", "LD", "ST", "SY" // 12-15
|
||||
};
|
||||
snprintf(buff, sizeof(buff), "DMB %s", barrier[Rn]);
|
||||
return buff;
|
||||
}
|
||||
// DSB
|
||||
if(isMask(opcode, "11010101000000110011nnnn10011111", &a)) {
|
||||
snprintf(buff, sizeof(buff), "DSB %s", (Rn==0b1011)?"ISH":((Rn==0b1010)?"ISHST":"???"));
|
||||
const char* barrier[] = {
|
||||
"???", "???", "???", "???", // 0-3
|
||||
"???", "???", "???", "???", // 4-7
|
||||
"???", "ISHLD", "ISHST", "ISH", // 8-11
|
||||
"???", "LD", "ST", "SY" // 12-15
|
||||
};
|
||||
snprintf(buff, sizeof(buff), "DSB %s", barrier[Rn]);
|
||||
return buff;
|
||||
}
|
||||
|
||||
@@ -1759,6 +1956,11 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
snprintf(buff, sizeof(buff), "SHA256H2 Q%d, Q%d, V%d.4S", Rd, Rn, Rm);
|
||||
return buff;
|
||||
}
|
||||
// UDF
|
||||
if(isMask(opcode, "0000000000000000iiiiiiiiiiiiiiii", &a)) {
|
||||
snprintf(buff, sizeof(buff), "UDF 0x%x", a.i);
|
||||
return buff;
|
||||
}
|
||||
|
||||
snprintf(buff, sizeof(buff), "%08X ???", __builtin_bswap32(opcode));
|
||||
return buff;
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
.text
|
||||
.align 4
|
||||
|
||||
.extern arm64_next
|
||||
|
||||
.global arm64_prolog
|
||||
arm64_prolog:
|
||||
//save all 18 used register
|
||||
@@ -34,8 +32,7 @@ arm64_prolog:
|
||||
ldp x24, x25, [x0, (8 * 14)]
|
||||
ldp x26, x27, [x0, (8 * 16)]
|
||||
// Push a jump next on the stack
|
||||
adr x28, arm64_next
|
||||
stp x28, xzr, [sp, -16]!
|
||||
stp xzr, xzr, [sp, -16]!
|
||||
// Save old xSP in x28
|
||||
add x28, sp, 16
|
||||
//jump to function
|
||||
|
||||
+1587
-581
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -5,10 +5,8 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
@@ -18,7 +16,7 @@
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "../dynarec_helper.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
|
||||
uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int seg, int* ok, int* need_epilog)
|
||||
@@ -27,8 +25,9 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop;
|
||||
uint8_t gd, ed;
|
||||
uint8_t gd, ed, wb1, wback;
|
||||
int64_t j64;
|
||||
int16_t i16;
|
||||
int v0, v1;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
@@ -57,42 +56,166 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3), 0);
|
||||
} else {
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
VLDR64_REG(v1, ed, x4);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
ADDz_REG(x4, x4, ed);
|
||||
ed = x4;
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
VLD64(v1, ed, fixedaddress);
|
||||
}
|
||||
FCMPD(v0, v1);
|
||||
FCOMI(x1, x2);
|
||||
break;
|
||||
case 0xD6:
|
||||
INST_NAME("MOVQ Ex, Gx");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, (nextop&7) + (rex.b<<3));
|
||||
FMOVD(v1, v0);
|
||||
} else {
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
VSTR64_REG(v0, ed, x4);
|
||||
SMWRITE();
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x6F:
|
||||
INST_NAME("MOVDQA Gx,Ex");
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
GETGX_empty(v0);
|
||||
VMOVQ(v0, v1);
|
||||
} else {
|
||||
GETGX_empty(v0);
|
||||
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
SMREAD();
|
||||
ADDz_REG(x4, x4, ed);
|
||||
VLD128(v0, x4, fixedaddress);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x7F:
|
||||
INST_NAME("MOVDQA Ex,Gx");
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 1);
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
ADDz_REG(x4, x4, ed);
|
||||
VST128(v0, x4, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xD6:
|
||||
INST_NAME("MOVQ Ex, Gx");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, (nextop&7) + (rex.b<<3));
|
||||
FMOVD(v1, v0);
|
||||
} else {
|
||||
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
ADDz_REG(x4, x4, ed);
|
||||
VST64(v0, x4, fixedaddress);
|
||||
SMWRITE();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x83:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: //ADD
|
||||
if(opcode==0x81) {INST_NAME("ADD Ew, Iw");} else {INST_NAME("ADD Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_segdata(dyn, addr, ninst, x1, seg, (MODREG));
|
||||
GETEWO(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOVZw(x5, i16);
|
||||
emit_add16(dyn, ninst, ed, x5, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 1: //OR
|
||||
if(opcode==0x81) {INST_NAME("OR Ew, Iw");} else {INST_NAME("OR Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_segdata(dyn, addr, ninst, x1, seg, (MODREG));
|
||||
GETEWO(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
emit_or16c(dyn, ninst, x1, i16, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 2: //ADC
|
||||
if(opcode==0x81) {INST_NAME("ADC Ew, Iw");} else {INST_NAME("ADC Ew, Ib");}
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_segdata(dyn, addr, ninst, x1, seg, (MODREG));
|
||||
GETEWO(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOVZw(x5, i16);
|
||||
emit_adc16(dyn, ninst, x1, x5, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 3: //SBB
|
||||
if(opcode==0x81) {INST_NAME("SBB Ew, Iw");} else {INST_NAME("SBB Ew, Ib");}
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_segdata(dyn, addr, ninst, x1, seg, (MODREG));
|
||||
GETEWO(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOVZw(x5, i16);
|
||||
emit_sbb16(dyn, ninst, x1, x5, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 4: //AND
|
||||
if(opcode==0x81) {INST_NAME("AND Ew, Iw");} else {INST_NAME("AND Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_segdata(dyn, addr, ninst, x1, seg, (MODREG));
|
||||
GETEWO(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
emit_and16c(dyn, ninst, x1, i16, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 5: //SUB
|
||||
if(opcode==0x81) {INST_NAME("SUB Ew, Iw");} else {INST_NAME("SUB Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_segdata(dyn, addr, ninst, x1, seg, (MODREG));
|
||||
GETEWO(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOVZw(x5, i16);
|
||||
emit_sub16(dyn, ninst, x1, x5, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 6: //XOR
|
||||
if(opcode==0x81) {INST_NAME("XOR Ew, Iw");} else {INST_NAME("XOR Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_segdata(dyn, addr, ninst, x1, seg, (MODREG));
|
||||
GETEWO(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
emit_xor16c(dyn, ninst, x1, i16, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 7: //CMP
|
||||
if(opcode==0x81) {INST_NAME("CMP Ew, Iw");} else {INST_NAME("CMP Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_segdata(dyn, addr, ninst, x1, seg, (MODREG));
|
||||
GETEWO(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
if(i16) {
|
||||
MOVZw(x2, i16);
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
} else
|
||||
emit_cmp16_0(dyn, ninst, x1, x3, x4);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x89:
|
||||
INST_NAME("MOV FS:Ew, Gw");
|
||||
nextop = F8;
|
||||
GETGD; // don't need GETGW here
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
if(rex.w) {
|
||||
MOVx_REG(ed, gd);
|
||||
} else {
|
||||
@@ -101,23 +224,25 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
}
|
||||
} else {
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<(rex.w?3:1), rex.w?7:1, rex, NULL, 0, 0);
|
||||
ADDz_REG(x4, x4, ed);
|
||||
ed = x4;
|
||||
if(rex.w) {
|
||||
STRx_REG(gd, ed, x4);
|
||||
STx(gd, ed, fixedaddress);
|
||||
} else {
|
||||
STRH_REG(gd, ed, x4);
|
||||
STH(gd, ed, fixedaddress);
|
||||
}
|
||||
SMWRITE();
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x8B:
|
||||
INST_NAME("MOV Gd, FS:Ed");
|
||||
INST_NAME("MOV Gw, FS:Ew");
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if(MODREG) { // reg <= reg
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
if(rex.w) {
|
||||
MOVx_REG(gd, ed);
|
||||
} else {
|
||||
@@ -126,13 +251,15 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
}
|
||||
} else { // mem <= reg
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<(rex.w?3:1), rex.w?7:1, rex, NULL, 0, 0);
|
||||
ADDz_REG(x4, x4, ed);
|
||||
ed = x4;
|
||||
if(rex.w) {
|
||||
LDRx_REG(gd, ed, x4);
|
||||
LDx(gd, ed, fixedaddress);
|
||||
} else {
|
||||
LDRH_REG(x1, ed, x4);
|
||||
LDH(x1, ed, fixedaddress);
|
||||
BFIx(gd, x1, 0, 16);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,10 +5,9 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
@@ -18,7 +17,7 @@
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "../dynarec_helper.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
|
||||
|
||||
@@ -30,7 +29,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
uint8_t nextop;
|
||||
uint8_t gd, ed, u8;
|
||||
uint8_t wback, wb1, wb2, gb1, gb2;
|
||||
int32_t i32;
|
||||
int16_t i16;
|
||||
int64_t i64, j64;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
@@ -48,13 +47,44 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETREX();
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0x01:
|
||||
INST_NAME("LOCK ADD Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x5);
|
||||
if(MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
UXTHw(x6, ed);
|
||||
emit_add16(dyn, ninst, x6, x5, x3, x4);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
if(arm64_atomics) {
|
||||
UFLAG_IF {
|
||||
LDADDALH(x5, x1, wback);
|
||||
emit_add16(dyn, ninst, x1, x5, x3, x4);
|
||||
} else {
|
||||
STADDLH(x5, wback);
|
||||
}
|
||||
} else {
|
||||
MARKLOCK;
|
||||
LDAXRH(x1, wback);
|
||||
emit_add16(dyn, ninst, x1, x5, x3, x4);
|
||||
STLXRH(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
SMDMB();
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x09:
|
||||
INST_NAME("LOCK OR Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x5);
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
UXTHw(x6, ed);
|
||||
emit_or16(dyn, ninst, x6, x5, x3, x4);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
@@ -89,7 +119,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGD;
|
||||
UXTHw(x6, xRAX);
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
wback = 0;
|
||||
UXTHw(x1, ed);
|
||||
CMPSxw_REG(x6, x1);
|
||||
@@ -98,8 +128,14 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
if(!ALIGNED_ATOMICH) {
|
||||
TSTx_mask(wback, 1, 0, 0); // mask=1
|
||||
B_MARK3(cNE);
|
||||
if(arm64_uscat) {
|
||||
ANDx_mask(x1, wback, 1, 0, 3); // mask = F
|
||||
CMPSw_U12(x1, 0xF);
|
||||
B_MARK3(cGE);
|
||||
} else {
|
||||
TSTx_mask(wback, 1, 0, 0); // mask=1
|
||||
B_MARK3(cNE);
|
||||
}
|
||||
}
|
||||
// Aligned version
|
||||
if(arm64_atomics) {
|
||||
@@ -121,6 +157,8 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
MARK3;
|
||||
LDRH_U12(x1, wback, 0);
|
||||
LDAXRB(x3, wback); // dummy read, to arm the write...
|
||||
SUBw_UXTB(x3, x3, x1);
|
||||
CBNZw_MARK3(x3);
|
||||
CMPSw_REG(x6, x1);
|
||||
B_MARK(cNE);
|
||||
// EAX == Ed
|
||||
@@ -129,8 +167,8 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
STRH_U12(gd, wback, 0);
|
||||
}
|
||||
}
|
||||
SMDMB();
|
||||
MARK;
|
||||
SMDMB();
|
||||
// Common part (and fallback for EAX != Ed)
|
||||
UFLAG_IF {emit_cmp16(dyn, ninst, x6, x1, x3, x4, x5);}
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
@@ -140,10 +178,10 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
INST_NAME("LOCK XADD Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
gd = xRAX+((nextop&0x38)>>3)+(rex.r<<3);
|
||||
gd = TO_NAT(((nextop & 0x38) >> 3) + (rex.r << 3));
|
||||
UXTHx(x5, gd);
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
BFIx(gd, ed, 0, 16);
|
||||
emit_add16(dyn, ninst, x5, gd, x3, x4);
|
||||
BFIx(ed, x5, 0, 16);
|
||||
@@ -171,6 +209,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x11:
|
||||
INST_NAME("LOCK ADC Ew, Gw");
|
||||
READFLAGS(X_CF);
|
||||
@@ -178,7 +217,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGW(x5);
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
UXTHw(x6, ed);
|
||||
emit_adc16(dyn, ninst, x6, x5, x3, x4);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
@@ -192,6 +231,38 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
SMDMB();
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x21:
|
||||
INST_NAME("LOCK AND Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x5);
|
||||
if(MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
UXTHw(x6, ed);
|
||||
emit_and16(dyn, ninst, x6, gd, x3, x4);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
if(arm64_atomics) {
|
||||
MVNw_REG(x3, gd);
|
||||
UFLAG_IF {
|
||||
LDCLRALH(x3, x1, wback);
|
||||
emit_and16(dyn, ninst, x1, gd, x3, x4);
|
||||
} else {
|
||||
STCLRLH(x3, wback);
|
||||
}
|
||||
} else {
|
||||
MARKLOCK;
|
||||
LDAXRH(x1, wback);
|
||||
emit_and16(dyn, ninst, x1, gd, x3, x4);
|
||||
STLXRH(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
SMDMB();
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x81:
|
||||
case 0x83:
|
||||
nextop = F8;
|
||||
@@ -204,72 +275,89 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
MOV32w(x5, i32);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
MOV32w(x5, i16);
|
||||
UXTHw(x6, ed);
|
||||
emit_add16(dyn, ninst, x6, x5, x3, x4);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
MOV32w(x5, i32);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOV32w(x5, i16);
|
||||
if(!ALIGNED_ATOMICH) {
|
||||
TSTx_mask(wback, 1, 0, 0); // mask=1
|
||||
B_MARK(cNE);
|
||||
if(arm64_uscat) {
|
||||
ANDx_mask(x1, wback, 1, 0, 3); // mask = F
|
||||
CMPSw_U12(x1, 0xF);
|
||||
B_MARK(cGE);
|
||||
} else {
|
||||
TSTx_mask(wback, 1, 0, 0); // mask=1
|
||||
B_MARK(cNE);
|
||||
}
|
||||
}
|
||||
if(arm64_atomics) {
|
||||
LDADDALH(x5, x1, wback);
|
||||
UFLAG_IF {
|
||||
emit_add16(dyn, ninst, x1, x5, x3, x4);
|
||||
LDADDALH(x5, x1, wback);
|
||||
} else {
|
||||
STADDLH(x5, wback);
|
||||
}
|
||||
} else {
|
||||
MARKLOCK;
|
||||
LDAXRH(x1, wback);
|
||||
emit_add16(dyn, ninst, x1, x5, x3, x4);
|
||||
STLXRH(x3, x1, wback);
|
||||
ADDw_REG(x4, x1, x5);
|
||||
STLXRH(x3, x4, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
SMDMB();
|
||||
if(!ALIGNED_ATOMICH) {
|
||||
B_NEXT_nocond;
|
||||
B_MARK2_nocond;
|
||||
MARK; // unaligned! also, not enough
|
||||
LDRH_U12(x1, wback, 0);
|
||||
LDAXRB(x4, wback);
|
||||
BFIw(x1, x4, 0, 8); // re-inject
|
||||
emit_add16(dyn, ninst, x1, x5, x3, x4);
|
||||
STLXRB(x3, x1, wback);
|
||||
SUBw_UXTB(x4, x4, x1);
|
||||
CBNZw_MARK(x4);
|
||||
ADDw_REG(x4, x1, x5);
|
||||
STLXRB(x3, x4, wback);
|
||||
CBNZx_MARK(x3);
|
||||
STRH_U12(x1, wback, 0); // put the whole value
|
||||
STRH_U12(x4, wback, 0); // put the whole value
|
||||
SMDMB();
|
||||
}
|
||||
MARK2;
|
||||
UFLAG_IF {
|
||||
emit_add16(dyn, ninst, x1, x5, x3, x4);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1: //OR
|
||||
if(opcode==0x81) {INST_NAME("LOCK OR Ew, Iw");} else {INST_NAME("LOCK OR Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
MOV32w(x5, i32);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
UXTHw(x6, ed);
|
||||
emit_or16(dyn, ninst, x6, x5, x3, x4);
|
||||
emit_or16c(dyn, ninst, x6, i16, x3, x4);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
MOV32w(x5, i32);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
if(!i64) {MOV32w(x5, i16);}
|
||||
if(arm64_atomics) {
|
||||
UFLAG_IF {
|
||||
LDSETALH(x5, x1, wback);
|
||||
emit_or16(dyn, ninst, x1, x5, x3, x4);
|
||||
emit_or16c(dyn, ninst, x1, i16, x3, x4);
|
||||
} else {
|
||||
STSETLH(x5, wback);
|
||||
}
|
||||
} else {
|
||||
i64 = convert_bitmask_w(i16);
|
||||
if(!i64) {MOV32w(x5, i16);}
|
||||
MARKLOCK;
|
||||
LDAXRH(x1, wback);
|
||||
emit_or16(dyn, ninst, x1, x5, x3, x4);
|
||||
if(i64) {
|
||||
emit_or16c(dyn, ninst, x1, i16, x3, x4);
|
||||
} else {
|
||||
emit_or16(dyn, ninst, x1, x5, x3, x4);
|
||||
}
|
||||
STLXRH(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
@@ -281,16 +369,16 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
MOV32w(x5, i32);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
MOV32w(x5, i16);
|
||||
UXTHw(x6, ed);
|
||||
emit_adc16(dyn, ninst, x6, x5, x3, x4);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
MOV32w(x5, i32);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOV32w(x5, i16);
|
||||
MARKLOCK;
|
||||
LDAXRH(x1, wback);
|
||||
emit_adc16(dyn, ninst, x1, x5, x3, x4);
|
||||
@@ -304,16 +392,16 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
MOV32w(x5, i32);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
MOV32w(x5, i16);
|
||||
UXTHw(x6, ed);
|
||||
emit_sbb16(dyn, ninst, x6, x5, x3, x4);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
MOV32w(x5, i32);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOV32w(x5, i16);
|
||||
MARKLOCK;
|
||||
LDAXRH(x1, wback);
|
||||
emit_sbb16(dyn, ninst, x1, x5, x3, x4);
|
||||
@@ -326,29 +414,37 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(opcode==0x81) {INST_NAME("LOCK AND Ew, Iw");} else {INST_NAME("LOCK AND Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
MOV32w(x5, i32);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
UXTHw(x6, ed);
|
||||
emit_and16(dyn, ninst, x6, x5, x3, x4);
|
||||
emit_and16c(dyn, ninst, x6, i16, x3, x4);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
i64 = convert_bitmask_w(i16);
|
||||
if(arm64_atomics) {
|
||||
MOV32w(x5, ~i32);
|
||||
MOV32w(x5, ~i16);
|
||||
UFLAG_IF {
|
||||
LDCLRALH(x5, x1, wback);
|
||||
MVNw_REG(x5, x5);
|
||||
emit_and16(dyn, ninst, x1, x5, x3, x4);
|
||||
if(i64) {
|
||||
emit_and16c(dyn, ninst, x1, i16, x3, x4);
|
||||
} else {
|
||||
MVNw_REG(x5, x5);
|
||||
emit_and16(dyn, ninst, x1, x5, x3, x4);
|
||||
}
|
||||
} else {
|
||||
STCLRLH(x5, wback);
|
||||
}
|
||||
} else {
|
||||
MOV32w(x5, i32);
|
||||
if(!i64) {MOV32w(x5, i16);}
|
||||
MARKLOCK;
|
||||
LDAXRH(x1, wback);
|
||||
emit_and16(dyn, ninst, x1, x5, x3, x4);
|
||||
if(i64) {
|
||||
emit_and16c(dyn, ninst, x1, i16, x3, x4);
|
||||
} else {
|
||||
emit_and16(dyn, ninst, x1, x5, x3, x4);
|
||||
}
|
||||
STLXRH(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
SMDMB();
|
||||
@@ -359,75 +455,88 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(opcode==0x81) {INST_NAME("LOCK SUB Ew, Iw");} else {INST_NAME("LOCK SUB Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
MOV32w(x5, i32);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
MOV32w(x5, i16);
|
||||
UXTHw(x6, ed);
|
||||
emit_sub16(dyn, ninst, x6, x5, x3, x4);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
MOV32w(x5, i32);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOV32w(x5, i16);
|
||||
if(!ALIGNED_ATOMICH) {
|
||||
TSTx_mask(wback, 1, 0, 0); // mask=1
|
||||
B_MARK(cNE);
|
||||
if(arm64_uscat) {
|
||||
ANDx_mask(x1, wback, 1, 0, 3); // mask = F
|
||||
CMPSw_U12(x1, 0xF);
|
||||
B_MARK(cGE);
|
||||
} else {
|
||||
TSTx_mask(wback, 1, 0, 0); // mask=1
|
||||
B_MARK(cNE);
|
||||
}
|
||||
}
|
||||
if(arm64_atomics) {
|
||||
NEGw_REG(x4, x5);
|
||||
UFLAG_IF {
|
||||
LDADDALH(x4, x1, wback);
|
||||
emit_sub16(dyn, ninst, x1, x5, x3, x4);
|
||||
} else {
|
||||
STADDLH(x4, wback);
|
||||
}
|
||||
} else {
|
||||
MARKLOCK;
|
||||
LDAXRH(x1, wback);
|
||||
emit_sub16(dyn, ninst, x1, x5, x3, x4);
|
||||
SUBw_REG(x4, x1, x5);
|
||||
STLXRH(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
}
|
||||
SMDMB();
|
||||
if(!ALIGNED_ATOMICH) {
|
||||
B_NEXT_nocond;
|
||||
B_MARK2_nocond;
|
||||
MARK; // unaligned! also, not enough
|
||||
LDRH_U12(x1, wback, 0);
|
||||
LDAXRB(x4, wback);
|
||||
BFIw(x1, x4, 0, 8); // re-inject
|
||||
emit_sub16(dyn, ninst, x1, x5, x3, x4);
|
||||
STLXRB(x3, x1, wback);
|
||||
SUBw_UXTB(x4, x4, x1);
|
||||
CBNZw_MARK(x4);
|
||||
SUBw_REG(x4, x1, x5);
|
||||
STLXRB(x3, x4, wback);
|
||||
CBNZx_MARK(x3);
|
||||
STRH_U12(x1, wback, 0); // put the whole value
|
||||
STRH_U12(x4, wback, 0); // put the whole value
|
||||
SMDMB();
|
||||
}
|
||||
MARK2;
|
||||
UFLAG_IF {
|
||||
emit_sub16(dyn, ninst, x1, x5, x3, x4);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 6: //XOR
|
||||
if(opcode==0x81) {INST_NAME("LOCK XOR Ew, Iw");} else {INST_NAME("LOCK XOR Ew, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
MOV32w(x5, i32);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
UXTHw(x6, ed);
|
||||
emit_xor16(dyn, ninst, x6, x5, x3, x4);
|
||||
emit_xor16c(dyn, ninst, x6, i16, x3, x4);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
MOV32w(x5, i32);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
i64 = convert_bitmask_w(i16);
|
||||
if(arm64_atomics) {
|
||||
UFLAG_IF {
|
||||
LDEORALH(x5, x1, wback);
|
||||
emit_xor16(dyn, ninst, x1, x5, x3, x4);
|
||||
emit_xor16c(dyn, ninst, x1, i16, x3, x4);
|
||||
} else {
|
||||
STEORLH(x5, wback);
|
||||
}
|
||||
} else {
|
||||
if(!i64) {MOV32w(x5, i16);}
|
||||
MARKLOCK;
|
||||
LDAXRH(x1, wback);
|
||||
emit_xor16(dyn, ninst, x1, x5, x3, x4);
|
||||
if(i64)
|
||||
emit_xor16c(dyn, ninst, x1, i16, x3, x4);
|
||||
else
|
||||
emit_xor16(dyn, ninst, x1, x5, x3, x4);
|
||||
STLXRH(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
SMDMB();
|
||||
@@ -440,9 +549,9 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETEW(x6, (opcode==0x81)?2:1);
|
||||
(void)wb1;
|
||||
// No need to LOCK, this is readonly
|
||||
if(opcode==0x81) i32 = F16S; else i32 = F8S;
|
||||
if(i32) {
|
||||
MOV32w(x5, i32);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
if(i16) {
|
||||
MOV32w(x5, i16);
|
||||
emit_cmp16(dyn, ninst, x6, x5, x3, x4, x6);
|
||||
} else {
|
||||
emit_cmp16_0(dyn, ninst, ed, x3, x4);
|
||||
@@ -457,9 +566,9 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
{
|
||||
case 0: // INC Ew
|
||||
INST_NAME("LOCK INC Ew");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
UXTHw(x6, ed);
|
||||
emit_inc16(dyn, ninst, x6, x5, x3);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
@@ -485,9 +594,9 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
break;
|
||||
case 1: //DEC Ew
|
||||
INST_NAME("LOCK DEC Ew");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
UXTHw(x6, ed);
|
||||
emit_dec16(dyn, ninst, x6, x5, x3);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
|
||||
@@ -5,10 +5,8 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
@@ -19,7 +17,7 @@
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "../dynarec_helper.h"
|
||||
#include "emu/x64compstrings.h"
|
||||
|
||||
uintptr_t dynarec64_66F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog)
|
||||
|
||||
@@ -5,10 +5,8 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
@@ -19,7 +17,7 @@
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "../dynarec_helper.h"
|
||||
#include "emu/x64compstrings.h"
|
||||
|
||||
uintptr_t dynarec64_66F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog)
|
||||
@@ -55,7 +53,109 @@ uintptr_t dynarec64_66F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
#endif
|
||||
|
||||
switch(opcode) {
|
||||
case 0xB8:
|
||||
INST_NAME("POPCNT Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
VEORQ(v1, v1, v1);
|
||||
VMOVQDfrom(v1, 0, ed);
|
||||
CNT_8(v1, v1);
|
||||
UADDLV_8(v1, v1);
|
||||
VMOVHto(gd, v1, 0);
|
||||
IFX(X_ALL) {
|
||||
IFX(X_AF|X_PF|X_SF|X_OF|X_CF) {
|
||||
MOV32w(x1, (1<<F_OF) | (1<<F_SF) | (1<<F_ZF) | (1<<F_AF) | (1<<F_CF) | (1<<F_PF));
|
||||
BICw(xFlags, xFlags, x1);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CMPSw_U12(gd, 0);
|
||||
IFNATIVE(NF_EQ) {}
|
||||
else {
|
||||
CSETw(x1, cEQ);
|
||||
BFIw(xFlags, x1, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
GWBACK;
|
||||
break;
|
||||
|
||||
case 0xBC:
|
||||
INST_NAME("TZCNT Gw, Ew");
|
||||
if(!BOX64ENV(dynarec_safeflags)) {
|
||||
SETFLAGS(X_CF|X_ZF, SF_SUBSET);
|
||||
} else {
|
||||
if(BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_ALL&~X_OF, SF_SUBSET);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
}
|
||||
}
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETEW(x1, 0);
|
||||
GETGW(x2);
|
||||
TSTxw_REG(ed, ed);
|
||||
IFX(X_CF) {
|
||||
CSETw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_CF, 1); // CF = is source 0?
|
||||
}
|
||||
RBITw(x3, ed); // reverse
|
||||
CLZw(gd, x3); // x2 gets leading 0 == TZCNT
|
||||
MOV32w(x3, 16);
|
||||
CSELw(gd, x3, gd, cEQ); // if src is zero, use bit width as res
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(gd, gd);
|
||||
CSETw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_ZF, 1); // ZF = is dest 0?
|
||||
}
|
||||
if(BOX64ENV(dynarec_safeflags)) {
|
||||
IFX(X_AF) BFCw(xFlags, F_AF, 1);
|
||||
IFX(X_PF) BFCw(xFlags, F_PF, 1);
|
||||
IFX(X_SF) BFCw(xFlags, F_SF, 1);
|
||||
IFX2(X_OF, && !BOX64ENV(cputype)) BFCw(xFlags, F_OF, 1);
|
||||
}
|
||||
GWBACK;
|
||||
break;
|
||||
|
||||
case 0xBD:
|
||||
INST_NAME("LZCNT Gw, Ew");
|
||||
if(!BOX64ENV(dynarec_safeflags)) {
|
||||
SETFLAGS(X_CF|X_ZF, SF_SUBSET);
|
||||
} else {
|
||||
if(BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_ALL&~X_OF, SF_SUBSET);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
}
|
||||
}
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETEW(x1, 0);
|
||||
GETGW(x2);
|
||||
IFX(X_CF) {
|
||||
TSTxw_REG(ed, ed);
|
||||
CSETw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_CF, 1); // CF = is source 0?
|
||||
}
|
||||
CLZw(gd, ed);
|
||||
SUBw_U12(gd, gd, 16); // sub zero cnt of high word
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(gd, gd);
|
||||
CSETw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_ZF, 1); // ZF = is dest 0?
|
||||
}
|
||||
if(BOX64ENV(dynarec_safeflags)) {
|
||||
IFX(X_AF) BFCw(xFlags, F_AF, 1);
|
||||
IFX(X_PF) BFCw(xFlags, F_PF, 1);
|
||||
IFX(X_SF) BFCw(xFlags, F_SF, 1);
|
||||
IFX2(X_OF, && !BOX64ENV(cputype)) BFCw(xFlags, F_OF, 1);
|
||||
}
|
||||
GWBACK;
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -5,10 +5,8 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
@@ -18,7 +16,7 @@
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "../dynarec_helper.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
|
||||
#define GETGm gd = ((nextop&0x38)>>3)
|
||||
@@ -61,10 +59,67 @@ uintptr_t dynarec64_6764_32(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, in
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0x89:
|
||||
INST_NAME("MOV Seg:Ed, Gd");
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if(MODREG) { // reg <= reg
|
||||
MOVxw_REG(TO_NAT((nextop & 7) + (rex.b << 3)), gd);
|
||||
} else { // mem <= reg
|
||||
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
|
||||
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, 0);
|
||||
ADDz_REG(x4, x4, ed);
|
||||
STz(gd, x4, fixedaddress);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x8B:
|
||||
INST_NAME("MOV Gd, Seg:Ed");
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if(MODREG) { // reg => reg
|
||||
MOVxw_REG(gd, TO_NAT((nextop & 7) + (rex.b << 3)));
|
||||
} else { // mem => reg
|
||||
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
|
||||
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, 0);
|
||||
ADDz_REG(x4, x4, ed);
|
||||
LDz(gd, x4, fixedaddress);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x8F:
|
||||
INST_NAME("POP Seg:Ed");
|
||||
nextop=F8;
|
||||
if(MODREG) { // reg <= reg
|
||||
POP1_32(x1);
|
||||
MOVxw_REG(TO_NAT((nextop & 7) + (rex.b << 3)), x1);
|
||||
} else { // mem <= reg
|
||||
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
|
||||
POP1_32(x1);
|
||||
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, 0);
|
||||
ADDz_REG(x4, x4, ed);
|
||||
STz(x1, x4, fixedaddress);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xA1:
|
||||
INST_NAME("MOV EAX, Seg:[Od]");
|
||||
i32 = F16;
|
||||
grab_segdata(dyn, addr, ninst, x4, seg, 0);
|
||||
if(i32<4096 && !(i32&3)) {
|
||||
LDRw_U12(xRAX, x4, i32);
|
||||
} else if(i32<256) {
|
||||
LDURw_I9(xRAX, x4, i32);
|
||||
} else {
|
||||
MOV32w(x1, i32);
|
||||
LDRw_REG(xRAX, x4, x1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xA3:
|
||||
INST_NAME("MOV Seg:[Od], EAX");
|
||||
i32 = F16;
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
grab_segdata(dyn, addr, ninst, x4, seg, 0);
|
||||
if(i32<4096 && !(i32&3)) {
|
||||
STRw_U12(xRAX, x4, i32);
|
||||
} else if(i32<256) {
|
||||
@@ -77,16 +132,17 @@ uintptr_t dynarec64_6764_32(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, in
|
||||
|
||||
case 0xFF:
|
||||
nextop = F8;
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
grab_segdata(dyn, addr, ninst, x4, seg, (MODREG));
|
||||
switch((nextop>>3)&7) {
|
||||
case 6: // Push Ed
|
||||
INST_NAME("PUSH FS:Ew");
|
||||
if((nextop&0xC0)==0xC0) { // reg
|
||||
if (MODREG) {
|
||||
DEFAULT;
|
||||
} else { // mem <= i32
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0, 0, 0);
|
||||
LDRw_REG(x3, ed, x4);
|
||||
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, 0);
|
||||
ADDz_REG(x4, x4, ed);
|
||||
LDW(x3, x4, fixedaddress);
|
||||
PUSH1_32(x3);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -5,10 +5,8 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
@@ -18,7 +16,7 @@
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "../dynarec_helper.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
|
||||
#define GETGm gd = ((nextop&0x38)>>3)
|
||||
@@ -61,10 +59,97 @@ uintptr_t dynarec64_67_32(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0x0F:
|
||||
opcode=F8;
|
||||
switch(opcode) {
|
||||
|
||||
case 0x29:
|
||||
INST_NAME("MOVAPS Ex,Gx");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if(MODREG) {
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, ed);
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
addr = geted16(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, 0);
|
||||
VST128(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 64:
|
||||
addr = dynarec64_6764_32(dyn, addr, ip, ninst, rex, rep, _FS, ok, need_epilog);
|
||||
break;
|
||||
|
||||
#define GO(NO, YES) \
|
||||
BARRIER(BARRIER_MAYBE); \
|
||||
JUMP(addr+i8, 1); \
|
||||
if(dyn->insts[ninst].x64.jmp_insts==-1 || \
|
||||
CHECK_CACHE()) { \
|
||||
/* out of the block */ \
|
||||
i32 = dyn->insts[ninst].epilog-(dyn->native_size); \
|
||||
Bcond(NO, i32); \
|
||||
if(dyn->insts[ninst].x64.jmp_insts==-1) { \
|
||||
if(!(dyn->insts[ninst].x64.barrier&BARRIER_FLOAT)) \
|
||||
fpu_purgecache(dyn, ninst, 1, x1, x2, x3); \
|
||||
jump_to_next(dyn, addr+i8, 0, ninst, rex.is32bits); \
|
||||
} else { \
|
||||
CacheTransform(dyn, ninst, cacheupd, x1, x2, x3); \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size);\
|
||||
SKIP_SEVL(i32); \
|
||||
B(i32); \
|
||||
} \
|
||||
} else { \
|
||||
/* inside the block */ \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size); \
|
||||
SKIP_SEVL(i32); \
|
||||
Bcond(YES, i32); \
|
||||
}
|
||||
case 0xE0:
|
||||
INST_NAME("LOOPNZ (16bits)");
|
||||
READFLAGS(X_ZF);
|
||||
i8 = F8S;
|
||||
UXTHw(x1, xRCX);
|
||||
SUBw_U12(x1, x1, 1);
|
||||
BFIx(xRCX, x1, 0, 16);
|
||||
CBZw_NEXT(x1); // ECX is 0, no LOOP
|
||||
TSTw_mask(xFlags, 0b011010, 0); //mask=0x40
|
||||
GO(cNE, cEQ);
|
||||
break;
|
||||
case 0xE1:
|
||||
INST_NAME("LOOPZ (16bits)");
|
||||
READFLAGS(X_ZF);
|
||||
i8 = F8S;
|
||||
UXTHw(x1, xRCX);
|
||||
SUBw_U12(x1, x1, 1);
|
||||
BFIx(xRCX, x1, 0, 16);
|
||||
CBZw_NEXT(x1); // ECX is 0, no LOOP
|
||||
TSTw_mask(xFlags, 0b011010, 0); //mask=0x40
|
||||
GO(cEQ, cNE);
|
||||
break;
|
||||
case 0xE2:
|
||||
INST_NAME("LOOP (16bits)");
|
||||
i8 = F8S;
|
||||
UXTHw(x1, xRCX);
|
||||
SUBSw_U12(x1, x1, 1);
|
||||
BFIx(xRCX, x1, 0, 16);
|
||||
GO(cEQ, cNE);
|
||||
break;
|
||||
case 0xE3:
|
||||
INST_NAME("JCXZ");
|
||||
i8 = F8S;
|
||||
TSTw_mask(xRCX, 0, 15); //mask=0xffff
|
||||
GO(cNE, cEQ);
|
||||
break;
|
||||
#undef GO
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "../dynarec_helper.h"
|
||||
|
||||
static const char* avx_prefix_string(uint16_t p)
|
||||
{
|
||||
switch(p) {
|
||||
case VEX_P_NONE: return "0";
|
||||
case VEX_P_66: return "66";
|
||||
case VEX_P_F2: return "F2";
|
||||
case VEX_P_F3: return "F3";
|
||||
default: return "??";
|
||||
}
|
||||
}
|
||||
static const char* avx_map_string(uint16_t m)
|
||||
{
|
||||
switch(m) {
|
||||
case VEX_M_NONE: return "0";
|
||||
case VEX_M_0F: return "0F";
|
||||
case VEX_M_0F38: return "0F38";
|
||||
case VEX_M_0F3A: return "0F3A";
|
||||
default: return "??";
|
||||
}
|
||||
}
|
||||
|
||||
uintptr_t dynarec64_67_AVX(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)need_epilog;
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop, u8;
|
||||
uint8_t gd, ed, vd;
|
||||
uint8_t wback, wb1, wb2;
|
||||
uint8_t eb1, eb2, gb1, gb2;
|
||||
int32_t i32, i32_;
|
||||
int cacheupd = 0;
|
||||
int v0, v1, v2;
|
||||
int q0, q1, q2;
|
||||
int d0, d1, d2;
|
||||
int s0;
|
||||
uint64_t tmp64u;
|
||||
int64_t j64;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
MAYUSE(wb1);
|
||||
MAYUSE(wb2);
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
MAYUSE(gb1);
|
||||
MAYUSE(gb2);
|
||||
MAYUSE(q0);
|
||||
MAYUSE(q1);
|
||||
MAYUSE(d0);
|
||||
MAYUSE(d1);
|
||||
MAYUSE(s0);
|
||||
MAYUSE(j64);
|
||||
MAYUSE(cacheupd);
|
||||
|
||||
rex_t rex = vex.rex;
|
||||
|
||||
if( (vex.m==VEX_M_0F38) && (vex.p==VEX_P_F2)) {
|
||||
switch(opcode) {
|
||||
|
||||
case 0xF6:
|
||||
INST_NAME("MULX Gd, Vd, Ed (,RDX)");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED32(0);
|
||||
GETVD;
|
||||
if(rex.w) {
|
||||
// 64bits mul
|
||||
if((gd==xRDX) || (gd==ed) || (gd==vd))
|
||||
gb1 = x3;
|
||||
else
|
||||
gb1 = gd;
|
||||
UMULH(gb1, xRDX, ed);
|
||||
if(gd!=vd) {MULx(vd, xRDX, ed);}
|
||||
if(gb1==x3) {
|
||||
MOVx_REG(gd, gb1);
|
||||
}
|
||||
} else {
|
||||
// 32bits mul
|
||||
UMULL(x3, xRDX, ed);
|
||||
if(gd!=vd) {MOVw_REG(vd, x3);}
|
||||
LSRx(gd, x3, 32);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
|
||||
}
|
||||
else if((vex.m==VEX_M_0F) && (vex.p==VEX_P_66)) {
|
||||
switch(opcode) {
|
||||
case 0xD6:
|
||||
INST_NAME("VMOVQ 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);
|
||||
VMOV(v1, v0);
|
||||
YMM0(ed);
|
||||
} else {
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VST64(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x6E:
|
||||
INST_NAME("VMOVD Gx, Ed");
|
||||
nextop = F8;
|
||||
GETGX_empty(v0);
|
||||
GETED(0);
|
||||
VEORQ(v0, v0, v0); // RAZ vector
|
||||
if(rex.w) {
|
||||
FMOVDx(v0, ed);
|
||||
} else {
|
||||
FMOVSw(v0, ed);
|
||||
}
|
||||
YMM0(gd);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
}
|
||||
else {DEFAULT;}
|
||||
|
||||
if((*ok==-1) && (BOX64ENV(dynarec_log)>=LOG_INFO || dyn->need_dump || BOX64ENV(dynarec_missing)==1))
|
||||
if(!dyn->size || BOX64ENV(dynarec_log)>LOG_INFO || dyn->need_dump) {
|
||||
dynarec_log(LOG_NONE, " Dynarec unimplemented VEX opcode size %d prefix %s map %s opcode %02X\n", 128 << vex.l, avx_prefix_string(vex.p), avx_map_string(vex.m), opcode);
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,415 @@
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "dynablock.h"
|
||||
#include "x64emu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "dynarec/dynablock_private.h"
|
||||
#include "dynarec_arm64_arch.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_native.h"
|
||||
|
||||
//order might be important, so define SUPER for the right one
|
||||
#define SUPER() \
|
||||
GO(flags) \
|
||||
GO(x87) \
|
||||
GO(mmx) \
|
||||
GO(sse) \
|
||||
GO(ymm) \
|
||||
|
||||
|
||||
typedef struct arch_flags_s
|
||||
{
|
||||
uint8_t defered:1;
|
||||
uint8_t nf:1;
|
||||
uint8_t eq:1;
|
||||
uint8_t vf:1;
|
||||
uint8_t cf:1;
|
||||
uint8_t inv_cf:1;
|
||||
} arch_flags_t;
|
||||
|
||||
#define X87_ST_D 0
|
||||
#define X87_ST_F 1
|
||||
#define X87_ST_I64 2
|
||||
typedef struct arch_x87_s
|
||||
{
|
||||
int8_t delta; //up to +/-7
|
||||
uint8_t x87; // 1bit is STx present
|
||||
uint16_t x87_type; // 2bits per STx type
|
||||
uint32_t x87_pos; //4bits per STx position (well, 3 would be enough)
|
||||
} arch_x87_t;
|
||||
|
||||
typedef struct arch_mmx_s
|
||||
{
|
||||
uint8_t mmx; //1bit for each mmx reg present
|
||||
} arch_mmx_t;
|
||||
|
||||
typedef struct arch_sse_s
|
||||
{
|
||||
uint16_t sse; //1bit for each sse reg present
|
||||
} arch_sse_t;
|
||||
|
||||
typedef struct arch_ymm_s
|
||||
{
|
||||
uint16_t ymm0; // 1bit for ymm0
|
||||
uint16_t ymm; // 1bit for each ymm present
|
||||
uint64_t ymm_pos; // 4bits for position of each ymm present
|
||||
} arch_ymm_t;
|
||||
|
||||
typedef struct arch_arch_s
|
||||
{
|
||||
#define GO(A) uint16_t A:1;
|
||||
SUPER()
|
||||
#undef GO
|
||||
uint16_t unaligned:1;
|
||||
uint16_t seq:10; // how many instruction on the same values
|
||||
} arch_arch_t;
|
||||
|
||||
typedef struct arch_build_s
|
||||
{
|
||||
#define GO(A) uint8_t A:1;
|
||||
SUPER()
|
||||
#undef GO
|
||||
uint8_t unaligned;
|
||||
#define GO(A) arch_##A##_t A##_;
|
||||
SUPER()
|
||||
#undef GO
|
||||
} arch_build_t;
|
||||
|
||||
static arch_build_t static_build[MAX_INSTS+2] = {0};
|
||||
|
||||
static int arch_build(dynarec_arm_t* dyn, int ninst, arch_build_t* arch)
|
||||
{
|
||||
memset(arch, 0, sizeof(arch_build_t));
|
||||
// flags
|
||||
if((dyn->insts[ninst].f_entry.dfnone==0) || dyn->insts[ninst].need_nat_flags || dyn->insts[ninst].before_nat_flags) {
|
||||
arch->flags = 1;
|
||||
arch->flags_.defered = dyn->insts[ninst].f_entry.dfnone==0;
|
||||
uint8_t flags = dyn->insts[ninst].need_nat_flags | dyn->insts[ninst].before_nat_flags;
|
||||
arch->flags_.vf = flags&NF_VF;
|
||||
arch->flags_.nf = flags&NF_SF;
|
||||
arch->flags_.eq = flags&NF_EQ;
|
||||
arch->flags_.cf = flags&NF_CF;
|
||||
if(arch->flags_.cf)
|
||||
arch->flags_.inv_cf = !dyn->insts[ninst].normal_carry;
|
||||
}
|
||||
// got through all naoncache to gather regs assignments
|
||||
int idx;
|
||||
for(int i=0; i<32; ++i)
|
||||
if(dyn->insts[ninst].n.neoncache[i].v!=-1)
|
||||
switch(dyn->insts[ninst].n.neoncache[i].t) {
|
||||
case NEON_CACHE_XMMW:
|
||||
arch->sse = 1;
|
||||
arch->sse_.sse |= 1<<dyn->insts[ninst].n.neoncache[i].n;
|
||||
break;
|
||||
case NEON_CACHE_MM:
|
||||
arch->mmx = 1;
|
||||
arch->mmx_.mmx |= 1<<dyn->insts[ninst].n.neoncache[i].n;
|
||||
break;
|
||||
case NEON_CACHE_YMMW:
|
||||
arch->ymm = 1;
|
||||
arch->ymm_.ymm |= 1<<dyn->insts[ninst].n.neoncache[i].n;
|
||||
idx = i;
|
||||
if(idx>=EMM0 && idx<=EMM0+8)
|
||||
idx-=EMM0;
|
||||
else
|
||||
idx-=SCRATCH0-8;
|
||||
arch->ymm_.ymm_pos |= idx<<(dyn->insts[ninst].n.neoncache[i].n*4);
|
||||
break;
|
||||
case NEON_CACHE_ST_D:
|
||||
arch->x87 = 1;
|
||||
arch->x87_.x87 |= 1<<dyn->insts[ninst].n.neoncache[i].n;
|
||||
arch->x87_.x87_pos = (i-EMM0)<<(dyn->insts[ninst].n.neoncache[i].n*4);
|
||||
arch->x87_.x87_type = (X87_ST_D)<<(dyn->insts[ninst].n.neoncache[i].n*2);
|
||||
break;
|
||||
case NEON_CACHE_ST_F:
|
||||
arch->x87 = 1;
|
||||
arch->x87_.x87 |= 1<<dyn->insts[ninst].n.neoncache[i].n;
|
||||
arch->x87_.x87_pos = (i-EMM0)<<(dyn->insts[ninst].n.neoncache[i].n*4);
|
||||
arch->x87_.x87_type = (X87_ST_F)<<(dyn->insts[ninst].n.neoncache[i].n*2);
|
||||
break;
|
||||
case NEON_CACHE_ST_I64:
|
||||
arch->x87 = 1;
|
||||
arch->x87_.x87 |= 1<<dyn->insts[ninst].n.neoncache[i].n;
|
||||
arch->x87_.x87_pos = (i-EMM0)<<(dyn->insts[ninst].n.neoncache[i].n*4);
|
||||
arch->x87_.x87_type = (X87_ST_I64)<<(dyn->insts[ninst].n.neoncache[i].n*2);
|
||||
break;
|
||||
case NEON_CACHE_XMMR:
|
||||
case NEON_CACHE_YMMR:
|
||||
default:
|
||||
// doing nothing, it's just a value read in memory
|
||||
break;
|
||||
}
|
||||
// ymm0
|
||||
if(dyn->insts[ninst].ymm0_out) {
|
||||
arch->ymm = 1;
|
||||
arch->ymm_.ymm0 = dyn->insts[ninst].ymm0_out;
|
||||
}
|
||||
// x87 top
|
||||
if(dyn->insts[ninst].n.x87stack) {
|
||||
arch->x87 = 1;
|
||||
arch->x87_.delta = dyn->insts[ninst].n.x87stack;
|
||||
}
|
||||
// opcode can handle unaligned
|
||||
arch->unaligned = dyn->insts[ninst].unaligned;
|
||||
return arch->flags + arch->x87 + arch->mmx + arch->sse + arch->ymm + arch->unaligned;
|
||||
}
|
||||
|
||||
static int sizeof_arch(arch_arch_t* arch)
|
||||
{
|
||||
int sz = sizeof(arch_arch_t);
|
||||
#define GO(A) if(arch->A) sz+=sizeof(arch_##A##_t);
|
||||
SUPER()
|
||||
#undef GO
|
||||
return sz;
|
||||
}
|
||||
|
||||
static int sizeof_arch_build(arch_build_t* build)
|
||||
{
|
||||
int sz = sizeof(arch_arch_t);
|
||||
#define GO(A) if(build->A) sz+=sizeof(arch_##A##_t);
|
||||
SUPER()
|
||||
#undef GO
|
||||
return sz;
|
||||
}
|
||||
|
||||
size_t get_size_arch(dynarec_arm_t* dyn)
|
||||
{
|
||||
arch_build_t* previous = NULL;
|
||||
size_t sz = 0;
|
||||
int seq = 0;
|
||||
int nseq = 0;
|
||||
int last = 0;
|
||||
if(!dyn->size) return 0;
|
||||
for(int i=0; i<dyn->size; ++i) {
|
||||
arch_build_t* build = static_build+i;
|
||||
last = arch_build(dyn, i, build);
|
||||
if(i && (!memcmp(build, previous, sizeof(arch_build_t))) && (seq<((1<<10)-1))) {
|
||||
// same sequence, increment
|
||||
++seq;
|
||||
} else {
|
||||
seq = 0;
|
||||
++nseq;
|
||||
previous = build;
|
||||
sz += sizeof_arch_build(build);
|
||||
}
|
||||
}
|
||||
if(nseq==1 && !last)
|
||||
return 0; //empty, no flags, no nothing
|
||||
return sz;
|
||||
}
|
||||
|
||||
static void build_next(arch_arch_t* arch, arch_build_t* build)
|
||||
{
|
||||
#define GO(A) arch->A = build->A;
|
||||
SUPER()
|
||||
#undef GO
|
||||
arch->unaligned = build->unaligned;
|
||||
arch->seq = 0;
|
||||
void* p = ((void*)arch)+sizeof(arch_arch_t);
|
||||
#define GO(A) \
|
||||
if(build->A) { \
|
||||
memcpy(p, &(build->A##_), sizeof(arch_ ##A##_t)); \
|
||||
p+=sizeof(arch_##A##_t); \
|
||||
}
|
||||
SUPER()
|
||||
#undef GO
|
||||
}
|
||||
|
||||
void* populate_arch(dynarec_arm_t* dyn, void* p, size_t tot_sz)
|
||||
{
|
||||
arch_build_t* previous = NULL;
|
||||
arch_arch_t* arch = p;
|
||||
arch_arch_t* next = p;
|
||||
int seq = 0;
|
||||
size_t total = 0;
|
||||
if(!tot_sz) return NULL;
|
||||
for(int i=0; i<dyn->size; ++i) {
|
||||
arch_build_t* build = static_build+i;
|
||||
if(i && (!memcmp(build, previous, sizeof(arch_build_t))) && (seq<((1<<10)-1))) {
|
||||
// same sequence, increment
|
||||
arch->seq = ++seq;
|
||||
} else {
|
||||
int sz = sizeof_arch_build(build);
|
||||
if(total+sz>tot_sz) {
|
||||
printf_log(LOG_INFO, "Warning: populate_arch on undersized buffer (%d+%d/%d, inst %d/%d)\n", total, sz, tot_sz, i, dyn->size);
|
||||
return NULL;
|
||||
}
|
||||
arch = next;
|
||||
build_next(arch, build);
|
||||
seq = 0;
|
||||
previous = build;
|
||||
total += sz;
|
||||
next = (arch_arch_t*)((uintptr_t)arch+sz);
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
// NZCV N
|
||||
#define NZCV_N 31
|
||||
// NZCV Z
|
||||
#define NZCV_Z 30
|
||||
// NZCV C
|
||||
#define NZCV_C 29
|
||||
// NZCV V
|
||||
#define NZCV_V 28
|
||||
|
||||
#ifndef _WIN32 // TODO: Implemented this for Win32
|
||||
void adjust_arch(dynablock_t* db, x64emu_t* emu, ucontext_t* p, uintptr_t x64pc)
|
||||
{
|
||||
if(!db->arch_size || !db->arch)
|
||||
return;
|
||||
int ninst = getX64AddressInst(db, x64pc);
|
||||
dynarec_log(LOG_INFO, "adjust_arch(...), db=%p, x64pc=%p, nints=%d", db, (void*)x64pc, ninst);
|
||||
if(ninst<0) {
|
||||
dynarec_log_prefix(0, LOG_INFO, "\n");
|
||||
return;
|
||||
}
|
||||
if(ninst==0) {
|
||||
dynarec_log_prefix(0, LOG_INFO, "\n");
|
||||
CHECK_FLAGS(emu);
|
||||
return;
|
||||
}
|
||||
// look for state at ninst-1
|
||||
arch_arch_t* arch = db->arch;
|
||||
arch_arch_t* next = arch;
|
||||
#define GO(A) arch_##A##_t* A = NULL;
|
||||
SUPER()
|
||||
#undef GO
|
||||
int i = 0;
|
||||
while(i<ninst-1) {
|
||||
arch = next;
|
||||
i += 1+arch->seq;
|
||||
dynarec_log_prefix(0, (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);
|
||||
#define GO(A) \
|
||||
if(arch->A) { \
|
||||
A = (arch_##A##_t*)((uintptr_t)arch + sz); \
|
||||
sz+=sizeof(arch_##A##_t); \
|
||||
}
|
||||
SUPER()
|
||||
#undef GO
|
||||
if(flags) {
|
||||
dynarec_log_prefix(0, LOG_INFO, " flags[%s-%s%s%s%s] ", flags->defered?"defered":"", flags->nf?"S":"", flags->vf?"O":"", flags->eq?"Z":"", flags->cf?(flags->inv_cf?"C(inv)":"C"):"");
|
||||
if(flags->defered) {
|
||||
CHECK_FLAGS(emu);
|
||||
//return;
|
||||
}
|
||||
if(flags->nf) {
|
||||
CONDITIONAL_SET_FLAG(p->uc_mcontext.pstate&(1<<NZCV_N), F_SF);
|
||||
}
|
||||
if(flags->vf) {
|
||||
CONDITIONAL_SET_FLAG(p->uc_mcontext.pstate&(1<<NZCV_V), F_OF);
|
||||
}
|
||||
if(flags->eq) {
|
||||
CONDITIONAL_SET_FLAG(p->uc_mcontext.pstate&(1<<NZCV_Z), F_ZF);
|
||||
}
|
||||
if(flags->cf) {
|
||||
if(flags->inv_cf) {
|
||||
CONDITIONAL_SET_FLAG((p->uc_mcontext.pstate&(1<<NZCV_C))==0, F_CF);
|
||||
} else {
|
||||
CONDITIONAL_SET_FLAG(p->uc_mcontext.pstate&(1<<NZCV_C), F_CF);
|
||||
}
|
||||
}
|
||||
}
|
||||
struct fpsimd_context *fpsimd = NULL;
|
||||
// find fpsimd struct
|
||||
{
|
||||
struct _aarch64_ctx * ff = (struct _aarch64_ctx*)p->uc_mcontext.__reserved;
|
||||
while (ff->magic && !fpsimd) {
|
||||
if(ff->magic==FPSIMD_MAGIC)
|
||||
fpsimd = (struct fpsimd_context*)ff;
|
||||
else
|
||||
ff = (struct _aarch64_ctx*)((uintptr_t)ff + ff->size);
|
||||
}
|
||||
}
|
||||
if(sse) {
|
||||
dynarec_log_prefix(0, LOG_INFO, " sse[%x (fpsimd=%p)] ", sse->sse, fpsimd);
|
||||
for(int i=0; i<16; ++i)
|
||||
if(fpsimd && (sse->sse>>i)&1) {
|
||||
int idx = 0;
|
||||
if(i>7) {
|
||||
idx = XMM8 + i - 8;
|
||||
} else {
|
||||
idx = XMM0 + i;
|
||||
}
|
||||
emu->xmm[i].u128 = fpsimd->vregs[idx];
|
||||
}
|
||||
}
|
||||
if(ymm) {
|
||||
dynarec_log_prefix(0, LOG_INFO, " ymm[%x, pos=%x, 0=%x (fpsimd=%p)] ", ymm->ymm, ymm->ymm_pos, ymm->ymm0, fpsimd);
|
||||
for(int i=0; i<16; ++i) {
|
||||
if(fpsimd && (ymm->ymm>>i)&1) {
|
||||
int idx = (ymm->ymm_pos>>(i*4))&0xf;
|
||||
if(i>7) {
|
||||
idx = SCRATCH0 + i - 8;
|
||||
} else {
|
||||
idx = EMM0 + i;
|
||||
}
|
||||
emu->ymm[i].u128 = fpsimd->vregs[idx];
|
||||
}
|
||||
if(ymm->ymm0&(1<<i))
|
||||
emu->ymm[i].u128 = 0;
|
||||
}
|
||||
}
|
||||
if(mmx) {
|
||||
dynarec_log_prefix(0, LOG_INFO, " mmx[%x (fpsimd=%p)] ", mmx->mmx, fpsimd);
|
||||
for(int i=0; i<8; ++i)
|
||||
if(fpsimd && (mmx->mmx>>i)&1) {
|
||||
int idx = EMM0 + i;
|
||||
emu->mmx[i].q = fpsimd->vregs[idx]&0xffffffffffffffffLL;
|
||||
}
|
||||
}
|
||||
if(x87) {
|
||||
dynarec_log_prefix(0, LOG_INFO, " x87[%x, pos=%x, type=%x (fpsimd=%p)] ", x87->x87, x87->x87_pos, x87->x87_type, fpsimd);
|
||||
emu->top -= x87->delta;
|
||||
for(int i=0; i<8; ++i) {
|
||||
if(x87->x87&(1<<i)) {
|
||||
int idx = EMM0 + (x87->x87_pos>>(i*4))&0x0f;
|
||||
int t = (x87->x87_type>>(i*2))&0x3;
|
||||
switch (t) {
|
||||
case X87_ST_F:
|
||||
emu->x87[(emu->top+i)&7].d = *(float*)&fpsimd->vregs[idx];
|
||||
break;
|
||||
case X87_ST_I64:
|
||||
emu->x87[(emu->top+i)&7].d = *(int64_t*)&fpsimd->vregs[idx];
|
||||
break;
|
||||
case X87_ST_D:
|
||||
emu->x87[(emu->top+i)&7].d = *(double*)&fpsimd->vregs[idx];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
dynarec_log_prefix(0, LOG_INFO, "\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
int arch_unaligned(dynablock_t* db, uintptr_t x64pc)
|
||||
{
|
||||
if(!db)
|
||||
return 0;
|
||||
if(!db->arch_size || !db->arch)
|
||||
return 0;
|
||||
int ninst = getX64AddressInst(db, x64pc);
|
||||
if(ninst<0) {
|
||||
return 0;
|
||||
}
|
||||
// look for state at ninst
|
||||
arch_arch_t* arch = db->arch;
|
||||
arch_arch_t* next = arch;
|
||||
int i = -1;
|
||||
while(i<ninst) {
|
||||
arch = next;
|
||||
i += 1+arch->seq;
|
||||
next = (arch_arch_t*)((uintptr_t)next + sizeof_arch(arch));
|
||||
}
|
||||
return arch->unaligned;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#ifndef __DYNAREC_ARM_ARCH_H__
|
||||
#define __DYNAREC_ARM_ARCH_H__
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "x64emu.h"
|
||||
#include "box64context.h"
|
||||
#include "box64cpu.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
|
||||
// get size of arch specific info (can be 0)
|
||||
size_t get_size_arch(dynarec_arm_t* dyn);
|
||||
//populate the array
|
||||
void* populate_arch(dynarec_arm_t* dyn, void* p, size_t sz);
|
||||
#ifndef _WIN32
|
||||
#include <ucontext.h>
|
||||
//adjust flags and more
|
||||
void adjust_arch(dynablock_t* db, x64emu_t* emu, ucontext_t* p, uintptr_t x64pc);
|
||||
#else
|
||||
#define adjust_arch(db, emu, p, x64pc)
|
||||
#endif
|
||||
// get if instruction can be regenerated for unaligned access
|
||||
int arch_unaligned(dynablock_t* db, uintptr_t x64pc);
|
||||
#endif // __DYNAREC_ARM_ARCH_H__
|
||||
@@ -0,0 +1,77 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "../dynarec_helper.h"
|
||||
|
||||
static const char* avx_prefix_string(uint16_t p)
|
||||
{
|
||||
switch(p) {
|
||||
case VEX_P_NONE: return "0";
|
||||
case VEX_P_66: return "66";
|
||||
case VEX_P_F2: return "F2";
|
||||
case VEX_P_F3: return "F3";
|
||||
default: return "??";
|
||||
}
|
||||
}
|
||||
static const char* avx_map_string(uint16_t m)
|
||||
{
|
||||
switch(m) {
|
||||
case VEX_M_NONE: return "0";
|
||||
case VEX_M_0F: return "0F";
|
||||
case VEX_M_0F38: return "0F38";
|
||||
case VEX_M_0F3A: return "0F3A";
|
||||
default: return "??";
|
||||
}
|
||||
}
|
||||
|
||||
uintptr_t dynarec64_AVX(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)need_epilog;
|
||||
|
||||
uint8_t opcode = PK(0);
|
||||
rex_t rex = vex.rex;
|
||||
|
||||
if( (vex.m==VEX_M_0F) && (vex.p==VEX_P_NONE))
|
||||
addr = dynarec64_AVX_0F(dyn, addr, ip, ninst, vex, ok, need_epilog);
|
||||
else if( (vex.m==VEX_M_0F38) && (vex.p==VEX_P_NONE))
|
||||
addr = dynarec64_AVX_0F38(dyn, addr, ip, ninst, vex, ok, need_epilog);
|
||||
else if( (vex.m==VEX_M_0F) && (vex.p==VEX_P_66))
|
||||
addr = dynarec64_AVX_66_0F(dyn, addr, ip, ninst, vex, ok, need_epilog);
|
||||
else if( (vex.m==VEX_M_0F) && (vex.p==VEX_P_F2))
|
||||
addr = dynarec64_AVX_F2_0F(dyn, addr, ip, ninst, vex, ok, need_epilog);
|
||||
else if( (vex.m==VEX_M_0F) && (vex.p==VEX_P_F3))
|
||||
addr = dynarec64_AVX_F3_0F(dyn, addr, ip, ninst, vex, ok, need_epilog);
|
||||
else if( (vex.m==VEX_M_0F38) && (vex.p==VEX_P_66))
|
||||
addr = dynarec64_AVX_66_0F38(dyn, addr, ip, ninst, vex, ok, need_epilog);
|
||||
else if( (vex.m==VEX_M_0F3A) && (vex.p==VEX_P_66))
|
||||
addr = dynarec64_AVX_66_0F3A(dyn, addr, ip, ninst, vex, ok, need_epilog);
|
||||
else if( (vex.m==VEX_M_0F38) && (vex.p==VEX_P_F2))
|
||||
addr = dynarec64_AVX_F2_0F38(dyn, addr, ip, ninst, vex, ok, need_epilog);
|
||||
else if( (vex.m==VEX_M_0F3A) && (vex.p==VEX_P_F2))
|
||||
addr = dynarec64_AVX_F2_0F3A(dyn, addr, ip, ninst, vex, ok, need_epilog);
|
||||
else if( (vex.m==VEX_M_0F38) && (vex.p==VEX_P_F3))
|
||||
addr = dynarec64_AVX_F3_0F38(dyn, addr, ip, ninst, vex, ok, need_epilog);
|
||||
else {DEFAULT;}
|
||||
|
||||
if((*ok==-1) && (BOX64ENV(dynarec_log)>=LOG_INFO || dyn->need_dump || BOX64ENV(dynarec_missing)))
|
||||
if(!dyn->size || BOX64ENV(dynarec_log)>LOG_INFO || dyn->need_dump) {
|
||||
dynarec_log(LOG_NONE, " Dynarec unimplemented VEX opcode size %d prefix %s map %s opcode %02X\n", 128<<vex.l, avx_prefix_string(vex.p), avx_map_string(vex.m), opcode);
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,838 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
#include "my_cpuid.h"
|
||||
#include "emu/x87emu_private.h"
|
||||
#include "emu/x64shaext.h"
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "../dynarec_helper.h"
|
||||
|
||||
uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop, u8;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback, wb1, wb2;
|
||||
uint8_t eb1, eb2, gb1, gb2;
|
||||
int32_t i32, i32_;
|
||||
int cacheupd = 0;
|
||||
int v0, v1, v2;
|
||||
int q0, q1, q2;
|
||||
int d0, d1, d2;
|
||||
int s0;
|
||||
uint64_t tmp64u;
|
||||
int64_t j64;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
MAYUSE(wb1);
|
||||
MAYUSE(wb2);
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
MAYUSE(gb1);
|
||||
MAYUSE(gb2);
|
||||
MAYUSE(q0);
|
||||
MAYUSE(q1);
|
||||
MAYUSE(d0);
|
||||
MAYUSE(d1);
|
||||
MAYUSE(s0);
|
||||
MAYUSE(j64);
|
||||
MAYUSE(cacheupd);
|
||||
#if STEP > 1
|
||||
static const int8_t mask_shift8[] = { -7, -6, -5, -4, -3, -2, -1, 0 };
|
||||
#endif
|
||||
|
||||
rex_t rex = vex.rex;
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0x10:
|
||||
INST_NAME("VMOVUPS Gx,Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
v1 = sse_get_reg(dyn, ninst, x1, ed, 0);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
if(v0!=v1) VMOVQ(v0, v1);
|
||||
if(vex.l) {
|
||||
v1 = ymm_get_reg(dyn, ninst, x1, ed, 0, gd, -1, -1);
|
||||
v0 = ymm_get_reg_empty(dyn, ninst, x1, gd, ed, -1, -1);
|
||||
if(v0!=v1) VMOVQ(v0, v1);
|
||||
}
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
SMREAD();
|
||||
if(vex.l) {
|
||||
v1 = ymm_get_reg_empty(dyn, ninst, x1, gd, -1, -1, -1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0x3f<<4, 15, rex, NULL, 1, 0);
|
||||
VLDP128_I7(v0, v1, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VLD128(v0, ed, fixedaddress); // no alignment issue with ARMv8 NEON :)
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x11:
|
||||
INST_NAME("VMOVUPS 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) {
|
||||
v0 = ymm_get_reg(dyn, ninst, x1, gd, 0, ed, -1, -1);
|
||||
v1 = ymm_get_reg_empty(dyn, ninst, x1, ed, gd, -1, -1);
|
||||
VMOVQ(v1, v0);
|
||||
} else YMM0(ed);
|
||||
} else {
|
||||
if(vex.l) {
|
||||
v1 = ymm_get_reg(dyn, ninst, x1, gd, 0, ed, -1, -1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0x3f<<4, 15, rex, NULL, 1, 0);
|
||||
VSTP128_I7(v0, v1, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VST128(v0, ed, fixedaddress);
|
||||
}
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x12:
|
||||
nextop = F8;
|
||||
GETVX(v2, 0);
|
||||
if(MODREG) {
|
||||
INST_NAME("VMOVHLPS Gx, Vx, Ex");
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
GETGX_empty(v0);
|
||||
if((v0!=v2) && (v0!=v1))
|
||||
VMOVQ(v0, v2);
|
||||
VMOVeD(v0, 0, v1, 1);
|
||||
if((v0!=v2) && (v0==v1))
|
||||
VMOVeD(v0, 1, v2, 1);
|
||||
} else {
|
||||
INST_NAME("VMOVLPS Gx, Vx, Ex");
|
||||
GETGX_empty(v0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(v0!=v2)
|
||||
VMOVQ(v0, v2);
|
||||
VLD1_64(v0, 0, ed);
|
||||
}
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x13:
|
||||
nextop = F8;
|
||||
INST_NAME("VMOVLPS Ex, Gx");
|
||||
GETGX(v0, 0);
|
||||
if(MODREG) {
|
||||
DEFAULT;
|
||||
return addr;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
VST1_64(v0, 0, ed);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x14:
|
||||
INST_NAME("VUNPCKLPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
SMREAD();
|
||||
GETGX_empty_VXEX(v0, v2, v1, 0);
|
||||
VZIP1Q_32(v0, v2, v1);
|
||||
if(vex.l) {
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
VZIP1Q_32(v0, v2, v1);
|
||||
} else YMM0(gd);
|
||||
break;
|
||||
case 0x15:
|
||||
INST_NAME("VUNPCKHPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
SMREAD();
|
||||
GETGX_empty_VXEX(v0, v2, v1, 0);
|
||||
VZIP2Q_32(v0, v2, v1);
|
||||
if(vex.l) {
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
VZIP2Q_32(v0, v2, v1);
|
||||
} else YMM0(gd);
|
||||
break;
|
||||
case 0x16:
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
INST_NAME("VMOVLHPS Gx, Vx, Ex");
|
||||
GETGX(v0, 1);
|
||||
GETVX(v2, 0);
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
if(v0!=v2 && v0!=v1) VMOVQ(v0, v2);
|
||||
VMOVeD(v0, 1, v1, 0);
|
||||
if(v0!=v2 && v0==v1) VMOVeD(v0, 0, v2, 0);
|
||||
} else {
|
||||
INST_NAME("VMOVHPS Gx, Vx, Ex");
|
||||
SMREAD();
|
||||
GETGX(v0, 1);
|
||||
GETVX(v2, 0);
|
||||
if(v0!=v2) VMOVQ(v0, v2);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
VLD1_64(v0, 1, ed);
|
||||
}
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x17:
|
||||
INST_NAME("VMOVHPS Ex, Gx");
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
if(MODREG) {
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
v1 = sse_get_reg(dyn, ninst, x1, ed, 1);
|
||||
VMOVeD(v1, 0, v0, 1);
|
||||
YMM0(ed);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
VST1_64(v0, 1, ed);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x28:
|
||||
INST_NAME("VMOVAPS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
v1 = sse_get_reg(dyn, ninst, x1, ed, 0);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VMOVQ(v0, v1);
|
||||
if(vex.l) {
|
||||
GETGY_empty_EY(v0, v1);
|
||||
VMOVQ(v0, v1);
|
||||
}
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
SMREAD();
|
||||
if(vex.l) {
|
||||
GETGY_empty(v1, -1, -1, -1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0x3f<<4, 15, rex, NULL, 1, 0);
|
||||
VLDP128_I7(v0, v1, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VLD128(v0, ed, fixedaddress);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x29:
|
||||
INST_NAME("VMOVAPS 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);
|
||||
} else {
|
||||
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);
|
||||
VSTP128_I7(v0, v1, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VST128(v0, ed, fixedaddress);
|
||||
}
|
||||
SMWRITE2();
|
||||
}
|
||||
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);
|
||||
} else {
|
||||
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);
|
||||
VSTP128_I7(v0, v1, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VST128(v0, ed, fixedaddress);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x2E:
|
||||
// no special check...
|
||||
case 0x2F:
|
||||
if(opcode==0x2F) {INST_NAME("VCOMISS Gx, Ex");} else {INST_NAME("VUCOMISS Gx, Ex");}
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
GETEXSS(s0, 0, 0);
|
||||
FCMPS(v0, s0);
|
||||
FCOMI(x1, x2);
|
||||
break;
|
||||
|
||||
case 0x50:
|
||||
INST_NAME("VMOVMSKPS Gd, Ex");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
MOV32w(gd, 0);
|
||||
if(MODREG) {
|
||||
// EX is an xmm reg
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETEX_Y(v0, 0, 0); } else { GETEY(v0); }
|
||||
SQXTN_16(q0, v0); // reduces the 4 32bits to 4 16bits
|
||||
VMOVQDto(x1, q0, 0);
|
||||
LSRx(x1, x1, 15);
|
||||
BFIx(gd, x1, 0+(l*4), 1);
|
||||
LSRx(x1, x1, 16);
|
||||
BFIx(gd, x1, 1+(l*4), 1);
|
||||
LSRx(x1, x1, 16);
|
||||
BFIx(gd, x1, 2+(l*4), 1);
|
||||
LSRx(x1, x1, 16);
|
||||
BFIx(gd, x1, 3+(l*4), 1);
|
||||
}
|
||||
} else {
|
||||
// EX is memory
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, (0x3f<<3)-16, 7, rex, NULL, 1, 0);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
LDPx_S7_offset(x1, x2, ed, fixedaddress+16*l);
|
||||
LSRx(x1, x1, 31);
|
||||
BFIx(gd, x1, 0+(l*4), 1);
|
||||
LSRx(x1, x1, 32);
|
||||
BFIx(gd, x1, 1+(l*4), 1);
|
||||
LSRx(x1, x2, 31);
|
||||
BFIx(gd, x1, 2+(l*4), 1);
|
||||
LSRx(x1, x1, 32);
|
||||
BFIx(gd, x1, 3+(l*4), 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x51:
|
||||
INST_NAME("VSQRTPS Gx, Ex");
|
||||
nextop = F8;
|
||||
SKIPTEST(x1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
}
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_EX(v0, v1, 0); } else { GETGY_empty_EY(v0, v1); }
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
// check if any input value was NAN
|
||||
VFCMEQQS(d0, v1, v1); // 0 if NAN, 1 if not NAN
|
||||
VFSQRTQS(v0, v1);
|
||||
VFCMEQQS(d1, v0, v0); // 0 => out is NAN
|
||||
VBICQ(d1, d0, d1); // forget it in any input was a NAN already
|
||||
VSHLQ_32(d1, d1, 31); // only keep the sign bit
|
||||
VORRQ(v0, v0, d1); // NAN -> -NAN
|
||||
} else {
|
||||
VFSQRTQS(v0, v1);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x52:
|
||||
INST_NAME("VRSQRTPS Gx, Ex");
|
||||
nextop = F8;
|
||||
SKIPTEST(x1);
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
VFMOVSQ_8(v0, 0b01110000); //1.0f
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_EX(q0, q1, 0); } else { GETGY_empty_EY(q0, q1); }
|
||||
#if 0
|
||||
// the aproximation doesn't not work on Death Stranding. code around 0x1419c9100 fail...
|
||||
if(!l) {
|
||||
if(q1==q0)
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
else
|
||||
v1 = q1;
|
||||
}
|
||||
// more precise
|
||||
VFRSQRTEQS(v0, q1);
|
||||
VFMULQS(v1, v0, q1);
|
||||
VFRSQRTSQS(v1, v1, v0);
|
||||
VFMULQS(q0, v1, v0);
|
||||
#else
|
||||
VFSQRTQS(q0, q1);
|
||||
VFDIVQS(q0, v0, q0);
|
||||
#endif
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x53:
|
||||
INST_NAME("VRCPPS Gx, Ex");
|
||||
nextop = F8;
|
||||
SKIPTEST(x1);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
VFMOVSQ_8(q0, 0b01110000); //1.0f
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) {
|
||||
GETGX_empty_EX(v0, v1, 0);
|
||||
#if 0
|
||||
if(v0==v1)
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
#endif
|
||||
} else {
|
||||
GETGY_empty_EY(v0, v1);
|
||||
}
|
||||
#if 0
|
||||
if(v0!=v1) q1 = v0;
|
||||
VFRECPEQS(q0, v1);
|
||||
VFRECPSQS(q1, q0, v1);
|
||||
VFMULQS(v0, q0, q1);
|
||||
#else
|
||||
VFDIVQS(v0, q0, v1);
|
||||
#endif
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x54:
|
||||
INST_NAME("VANDPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETGX_empty_VXEX(v0, v2, v1, 0);
|
||||
VANDQ(v0, v2, v1);
|
||||
if(vex.l) {
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
VANDQ(v0, v2, v1);
|
||||
} else YMM0(gd)
|
||||
break;
|
||||
case 0x55:
|
||||
INST_NAME("VANDNPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETGX_empty_VXEX(v0, v2, v1, 0);
|
||||
VBICQ(v0, v1, v2);
|
||||
if(vex.l) {
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
VBICQ(v0, v1, v2);
|
||||
} else YMM0(gd)
|
||||
break;
|
||||
case 0x56:
|
||||
INST_NAME("VORPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETGX_empty_VXEX(v0, v2, v1, 0);
|
||||
VORRQ(v0, v2, v1);
|
||||
if(vex.l) {
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
VORRQ(v0, v2, v1);
|
||||
} else YMM0(gd)
|
||||
break;
|
||||
case 0x57:
|
||||
INST_NAME("VXORPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETGX_empty_VXEX(v0, v2, v1, 0);
|
||||
VEORQ(v0, v2, v1);
|
||||
if(vex.l) {
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
VEORQ(v0, v2, v1);
|
||||
} else YMM0(gd)
|
||||
break;
|
||||
case 0x58:
|
||||
INST_NAME("VADDPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
}
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
// check if any input value was NAN
|
||||
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
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd)
|
||||
break;
|
||||
case 0x59:
|
||||
INST_NAME("VMULPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
}
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
// check if any input value was NAN
|
||||
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
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd)
|
||||
break;
|
||||
case 0x5A:
|
||||
INST_NAME("VCVTPS2PD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX_empty_EX(v0, v1, 0);
|
||||
if(vex.l) {
|
||||
GETGY_empty(q0, -1, -1, -1);
|
||||
FCVTL2(q0, v1);
|
||||
} else YMM0(gd)
|
||||
FCVTL(v0, v1);
|
||||
break;
|
||||
case 0x5B:
|
||||
INST_NAME("VCVTDQ2PS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX_empty_EX(v0, v1, 0);
|
||||
SCVTQFS(v0, v1);
|
||||
if(vex.l) {
|
||||
GETGY_empty_EY(v0, v1);
|
||||
SCVTQFS(v0, v1);
|
||||
} else YMM0(gd)
|
||||
break;
|
||||
case 0x5C:
|
||||
INST_NAME("VSUBPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
}
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
// check if any input value was NAN
|
||||
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
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd)
|
||||
break;
|
||||
case 0x5D:
|
||||
INST_NAME("VMINPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
}
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
|
||||
// FMIN/FMAX wll not copy a NaN if either is NaN
|
||||
// but x86 will copy src2 if either value is NaN, so lets force a copy of Src2 (Ex) if result is NaN
|
||||
if(BOX64ENV(dynarec_fastnan)) {
|
||||
VFMINQS(v0, v2, v1);
|
||||
} else {
|
||||
VFCMGTQS(q0, v1, v2); // 0 if NaN or v1 GT v2, so invert mask for copy
|
||||
if(v0!=v1) VBIFQ(v0, v1, q0);
|
||||
if(v0!=v2) VBITQ(v0, v2, q0);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x5E:
|
||||
INST_NAME("VDIVPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
}
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
// check if any input value was NAN
|
||||
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
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd)
|
||||
break;
|
||||
case 0x5F:
|
||||
INST_NAME("VMAXPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
}
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
|
||||
// FMIN/FMAX wll not copy a NaN if either is NaN
|
||||
// but x86 will copy src2 if either value is NaN, so lets force a copy of Src2 (Ex) if result is NaN
|
||||
if(BOX64ENV(dynarec_fastnan)) {
|
||||
VFMAXQS(v0, v2, v1);
|
||||
} else {
|
||||
VFCMGTQS(q0, v2, v1); // 0 if NaN or v2 GT v1, so invert mask for copy
|
||||
if(v0!=v1) VBIFQ(v0, v1, q0);
|
||||
if(v0!=v2) VBITQ(v0, v2, q0);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0x77:
|
||||
if(!vex.l) {
|
||||
INST_NAME("VZEROUPPER");
|
||||
if(vex.v!=0) {
|
||||
UDF(0);
|
||||
} else {
|
||||
for(int i=0; i<(rex.is32bits?8:16); ++i) {
|
||||
YMM0(i);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
INST_NAME("VZEROALL");
|
||||
if(vex.v!=0) {
|
||||
UDF(0);
|
||||
} else {
|
||||
for(int i=0; i<(rex.is32bits?8:16); ++i) {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, i);
|
||||
VEORQ(v0, v0, v0);
|
||||
YMM0(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xAE:
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
DEFAULT;
|
||||
} else
|
||||
switch((nextop>>3)&7) {
|
||||
case 2:
|
||||
INST_NAME("VLDMXCSR Md");
|
||||
GETED(0);
|
||||
STRw_U12(ed, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
if(BOX64ENV(sse_flushto0)) {
|
||||
MRS_fpcr(x2); // get fpscr
|
||||
LSRw_IMM(x3, ed, 15); // get FZ bit
|
||||
BFIw(x2, x3, 24, 1); // inject FZ bit
|
||||
EORw_REG_LSR(x3, x3, ed, 1); // FZ xor DAZ
|
||||
BFIw(x2, x3, 1, 1); // inject AH bit
|
||||
MSR_fpcr(x2); // put new fpscr
|
||||
}
|
||||
if(BOX64ENV(sse_flushto0)) {
|
||||
// try to sync mxcsr with fpsr on the flag side
|
||||
/* mapping is
|
||||
ARM -> X86
|
||||
0 -> 0 // Invalid operation
|
||||
1 -> 2 // Divide by 0
|
||||
2 -> 3 // Overflow
|
||||
3 -> 4 // underflow
|
||||
4 -> 5 // Inexact
|
||||
5 -> 1 // denormal
|
||||
*/
|
||||
// doing X86 -> ARM here, 0 1 2 3 4 5 -> 0 2 3 4 5 1
|
||||
if(ed!=x1)
|
||||
MOVw_REG(x1, ed); // x1 = 543210
|
||||
RORw(x3, x1, 2); // x3 = 10.....5432
|
||||
BFIw(x1, x3, 1, 4); // x1 = 54320
|
||||
RORw(x3, x3, 32-1); // x3 = 0.....54321
|
||||
BFIw(x1, x3, 5, 1); // x1 = 154320
|
||||
MRS_fpsr(x2);
|
||||
BFIx(x2, x1, 0, 6);
|
||||
MSR_fpsr(x2);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("VSTMXCSR Md");
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
LDRw_U12(x4, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
STW(x4, ed, fixedaddress);
|
||||
if(BOX64ENV(sse_flushto0)) {
|
||||
// sync with fpsr, with mask from mxcsr
|
||||
MRS_fpsr(x1);
|
||||
// doing ARM -> X86 here, 543210 => 432150
|
||||
UBFXw(x2, x1, 1, 5); // x2 = 54321
|
||||
BFIw(x1, x2, 2, 4); // x1 = 432110
|
||||
LSRw(x2, x2, 4); // x2 = 5
|
||||
BFIw(x1, x2, 1, 1); // x1 = 432150
|
||||
//BFXILw(x3, x4, 7, 6); // this would the mask, but let's ignore that for now
|
||||
BFIw(x4, x1, 0, 6); // inject back the flags
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC2:
|
||||
INST_NAME("VCMPPS Gx, Vx, Ex, Ib");
|
||||
nextop = F8;
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 1); u8 = F8; } else { GETGY_empty_VYEY(v0, v2, v1); }
|
||||
if(((u8&15)==3) || ((u8&15)==7) || ((u8&15)==8) || ((u8&15)==9) || ((u8&15)==10) || ((u8&15)==12)) {
|
||||
VFMAXQS(q0, v2, v1); // propagate NAN
|
||||
VFCMEQQS(((u8&15)==7)?v0:q0, q0, q0); // 0 if NAN, 1 if not NAN
|
||||
}
|
||||
switch(u8&0xf) {
|
||||
// the inversion of the params in the comparison is there to handle NaN the same way SSE does
|
||||
case 0x00: VFCMEQQS(v0, v2, v1); break; // Equal, not unordered
|
||||
case 0x01: VFCMGTQS(v0, v1, v2); break; // Less than
|
||||
case 0x02: VFCMGEQS(v0, v1, v2); break; // Less or equal
|
||||
case 0x03: VMVNQ(v0, q0); break; // unordered
|
||||
case 0x04: VFCMEQQS(v0, v2, v1); VMVNQ(v0, v0); break; // Not Equal (or unordered on ARM, not on X86...)
|
||||
case 0x05: VFCMGTQS(v0, v1, v2); VMVNQ(v0, v0); break; // Greater or equal or unordered
|
||||
case 0x06: VFCMGEQS(v0, v1, v2); VMVNQ(v0, v0); break; // Greater or unordered
|
||||
case 0x07: break; // ordered
|
||||
case 0x08: VFCMEQQS(v0, v2, v1); VORNQ(v0, v0, q0); break; // Equal, or unordered
|
||||
case 0x09: VFCMGTQS(v0, v1, v2); VORNQ(v0, v0, q0); break; // Less than or unordered
|
||||
case 0x0a: VFCMGEQS(v0, v1, v2); VORNQ(v0, v0, q0); break; // Less or equal or unordered
|
||||
case 0x0b: VEORQ(v0, v0, v0); break; // false
|
||||
case 0x0c: VFCMEQQS(v0, v2, v1); VBICQ(v0, q0, v0); break;
|
||||
case 0x0d: VFCMGEQS(v0, v2, v1); break;
|
||||
case 0x0e: VFCMGTQS(v0, v2, v1); break;
|
||||
case 0x0f: MOVIQ_64(v0, 0xff); break; //true
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0xC6:
|
||||
INST_NAME("VSHUFPS Gx, Vx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETVX(v2, 0);
|
||||
if(!MODREG) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 1);
|
||||
v1 = -1; // to avoid a warning
|
||||
} else
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
GETGX_empty(v0);
|
||||
u8 = F8;
|
||||
if(v2==v1 && (u8&0x3)==((u8>>2)&3) && (u8&0xf)==((u8>>4)&0xf)) {
|
||||
VDUPQ_32(v0, v2, u8&3);
|
||||
} else if(v2==v1 && (u8==0xe0)) { // elements 3 2 0 0
|
||||
VMOVQ(v0, v2);
|
||||
VMOVeS(v0, 1, v0, 0);
|
||||
} else if(v2==v1 && (u8==0xe5)) { // elements 3 2 1 1
|
||||
VMOVQ(v0, v2);
|
||||
VMOVeS(v0, 0, v0, 1);
|
||||
} else if(v2==v1 && (u8==0xa0)) { // elements 2 2 0 0
|
||||
VTRNQ1_32(v0, v1, v2);
|
||||
} else if(v2==v1 && (u8==0xf5)) { // elements 3 3 1 1
|
||||
VTRNQ2_32(v0, v1, v2);
|
||||
} else if(v2==v1 && (u8==0xb1)) { // elements 2 3 0 1
|
||||
VREV64Q_32(v0, v1);
|
||||
} else if(MODREG && u8==0x88) { // elements 2 0 2 0
|
||||
VUZP1Q_32(v0, v2, v1);
|
||||
} else if(MODREG && u8==0xdd) { // elements 3 1 3 1
|
||||
VUZP2Q_32(v0, v2, v1);
|
||||
} else {
|
||||
if((v0==v1) || (v0==v2)) {
|
||||
d0 = fpu_get_scratch(dyn, ninst); s0 = 0;
|
||||
} else {
|
||||
d0 = v0; s0 = 1;
|
||||
}
|
||||
// first two elements from Vx
|
||||
for(int i=0; i<2; ++i) {
|
||||
VMOVeS(d0, i, v2, (u8>>(i*2))&3);
|
||||
}
|
||||
// second two from Ex
|
||||
if(MODREG) {
|
||||
for(int i=2; i<4; ++i) {
|
||||
VMOVeS(d0, i, v1, (u8>>(i*2))&3);
|
||||
}
|
||||
} else {
|
||||
SMREAD();
|
||||
for(int i=2; i<4; ++i) {
|
||||
ADDx_U12(x2, ed, ((u8>>(i*2))&3)*4);
|
||||
VLD1_32(d0, i, x2);
|
||||
}
|
||||
}
|
||||
if(v0!=d0) VMOVQ(v0, d0);
|
||||
}
|
||||
if(vex.l) {
|
||||
if(MODREG)
|
||||
v1 = ymm_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0, gd, vex.v, -1);
|
||||
GETGY_empty_VY(v0, v2, 0, (MODREG)?((nextop&7)+(rex.b<<3)):-1, -1);
|
||||
if(v2==v1 && (u8&0x3)==((u8>>2)&3) && (u8&0xf)==((u8>>4)&0xf)) {
|
||||
VDUPQ_32(v0, v2, u8&3);
|
||||
} else if(v2==v1 && (u8==0xe0)) { // elements 3 2 0 0
|
||||
VMOVQ(v0, v2);
|
||||
VMOVeS(v0, 1, v0, 0);
|
||||
} else if(v2==v1 && (u8==0xe5)) { // elements 3 2 1 1
|
||||
VMOVQ(v0, v2);
|
||||
VMOVeS(v0, 0, v0, 1);
|
||||
} else if(v2==v1 && (u8==0xa0)) { // elements 2 2 0 0
|
||||
VTRNQ1_32(v0, v1, v2);
|
||||
} else if(v2==v1 && (u8==0xf5)) { // elements 3 3 1 1
|
||||
VTRNQ2_32(v0, v1, v2);
|
||||
} else if(v2==v1 && (u8==0xb1)) { // elements 2 3 0 1
|
||||
VREV64Q_32(v0, v1);
|
||||
} else if(MODREG && u8==0x88) { // elements 2 0 2 0
|
||||
VUZP1Q_32(v0, v2, v1);
|
||||
} else if(MODREG && u8==0xdd) { // elements 3 1 3 1
|
||||
VUZP2Q_32(v0, v2, v1);
|
||||
} else {
|
||||
if(s0) d0 = v0;
|
||||
for(int i=0; i<2; ++i) {
|
||||
VMOVeS(d0, i, v2, (u8>>(i*2))&3);
|
||||
}
|
||||
if(MODREG) {
|
||||
for(int i=2; i<4; ++i) {
|
||||
VMOVeS(d0, i, v1, (u8>>(i*2))&3);
|
||||
}
|
||||
} else {
|
||||
SMREAD();
|
||||
for(int i=2; i<4; ++i) {
|
||||
ADDx_U12(x2, ed, 16+((u8>>(i*2))&3)*4);
|
||||
VLD1_32(d0, i, x2);
|
||||
}
|
||||
}
|
||||
VMOVQ(v0, d0);
|
||||
}
|
||||
} else YMM0(gd);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,312 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
#include "my_cpuid.h"
|
||||
#include "emu/x87emu_private.h"
|
||||
#include "emu/x64shaext.h"
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "../dynarec_helper.h"
|
||||
|
||||
uintptr_t dynarec64_AVX_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop, u8;
|
||||
uint8_t gd, ed, vd;
|
||||
uint8_t wback, wb1, wb2;
|
||||
uint8_t eb1, eb2, gb1, gb2;
|
||||
int32_t i32, i32_;
|
||||
int cacheupd = 0;
|
||||
int v0, v1, v2;
|
||||
int q0, q1, q2;
|
||||
int d0, d1, d2;
|
||||
int s0;
|
||||
int need_tst;
|
||||
uint64_t tmp64u;
|
||||
int64_t j64;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
MAYUSE(wb1);
|
||||
MAYUSE(wb2);
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
MAYUSE(gb1);
|
||||
MAYUSE(gb2);
|
||||
MAYUSE(q0);
|
||||
MAYUSE(q1);
|
||||
MAYUSE(d0);
|
||||
MAYUSE(d1);
|
||||
MAYUSE(s0);
|
||||
MAYUSE(j64);
|
||||
MAYUSE(cacheupd);
|
||||
|
||||
rex_t rex = vex.rex;
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0xF2:
|
||||
INST_NAME("ANDN Gd, Vd, Ed");
|
||||
nextop = F8;
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETGD;
|
||||
GETED(0);
|
||||
GETVD;
|
||||
need_tst = 0;
|
||||
IFX(X_ZF) need_tst = 1;
|
||||
IFXNATIVE(X_SF, NF_SF) need_tst = 1;
|
||||
IFXNATIVE(X_OF, NF_VF) need_tst = 1;
|
||||
IFXNATIVE(X_CF, NF_CF) need_tst = 1;
|
||||
if(need_tst)
|
||||
BICSxw(gd, ed, vd);
|
||||
else
|
||||
BICxw(gd, ed, vd);
|
||||
IFX(X_ZF) {
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(x1, cEQ);
|
||||
BFIw(xFlags, x1, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_OF) {
|
||||
IFNATIVE(NF_VF) {} else {BFCw(xFlags, F_OF, 1);}
|
||||
}
|
||||
IFX(X_CF) {
|
||||
IFNATIVE(NF_CF) {} else {BFCw(xFlags, F_CF, 1);}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
IFNATIVE(NF_SF) {} else {
|
||||
LSRxw_IMM(x1, gd, rex.w?63:31);
|
||||
BFIw(xFlags, x1, F_SF, 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xF3:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 1:
|
||||
INST_NAME("BLSR Vd, Ed");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETED(0);
|
||||
GETVD;
|
||||
IFX(X_CF) {
|
||||
TSTxw_REG(ed, ed);
|
||||
CSETMw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_CF, 1);
|
||||
}
|
||||
SUBxw_U12(x3, ed, 1);
|
||||
need_tst = 0;
|
||||
IFX(X_ZF) need_tst = 1;
|
||||
IFXNATIVE(X_SF, NF_SF) need_tst = 1;
|
||||
IFXNATIVE(X_OF, NF_VF) need_tst = 1;
|
||||
if(need_tst)
|
||||
ANDSxw_REG(vd, ed, x3);
|
||||
else
|
||||
ANDxw_REG(vd, ed, x3);
|
||||
IFX(X_ZF) {
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETMw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
IFNATIVE(NF_SF) {} else {
|
||||
LSRxw(x3, vd, rex.w?63:31);
|
||||
BFIw(xFlags, x3, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_OF) {
|
||||
IFNATIVE(NF_VF) {} else { BFCw(xFlags, F_OF, 1); }
|
||||
}
|
||||
if (BOX64ENV(dynarec_test)) {
|
||||
IFX(X_AF) BFCw(xFlags, F_AF, 1);
|
||||
IFX(X_PF) BFCw(xFlags, F_PF, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
INST_NAME("BLSMSK Vd, Ed");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETED(0);
|
||||
GETVD;
|
||||
IFX(X_CF) {
|
||||
TSTxw_REG(ed, ed);
|
||||
CSETMw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_CF, 1);
|
||||
}
|
||||
SUBxw_U12(x3, ed, 1);
|
||||
need_tst = 0;
|
||||
IFX(X_ZF) need_tst = 1;
|
||||
IFXNATIVE(X_SF, NF_SF) need_tst = 1;
|
||||
IFXNATIVE(X_OF, NF_VF) need_tst = 1;
|
||||
EORxw_REG(vd, ed, x3);
|
||||
if(need_tst)
|
||||
TSTxw_REG(vd, vd);
|
||||
IFX(X_ZF) {
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETMw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
IFNATIVE(NF_SF) {} else {
|
||||
LSRxw(x3, vd, rex.w?63:31);
|
||||
BFIw(xFlags, x3, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_OF) {
|
||||
IFNATIVE(NF_VF) {} else { BFCw(xFlags, F_OF, 1); }
|
||||
}
|
||||
if (BOX64ENV(dynarec_test)) {
|
||||
IFX(X_AF) BFCw(xFlags, F_AF, 1);
|
||||
IFX(X_PF) BFCw(xFlags, F_PF, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
INST_NAME("BLSI Vd, Ed");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETED(0);
|
||||
GETVD;
|
||||
IFX(X_CF) {
|
||||
TSTxw_REG(ed, ed);
|
||||
CSETMw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_CF, 1);
|
||||
}
|
||||
NEGxw_REG(x3, ed);
|
||||
need_tst = 0;
|
||||
IFX(X_ZF) need_tst = 1;
|
||||
IFXNATIVE(X_SF, NF_SF) need_tst = 1;
|
||||
IFXNATIVE(X_OF, NF_VF) need_tst = 1;
|
||||
if(need_tst)
|
||||
ANDSxw_REG(vd, ed, x3);
|
||||
else
|
||||
ANDxw_REG(vd, ed, x3);
|
||||
IFX(X_ZF) {
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETMw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
IFNATIVE(NF_SF) {} else {
|
||||
LSRxw(x3, vd, rex.w?63:31);
|
||||
BFIw(xFlags, x3, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_OF) {
|
||||
IFNATIVE(NF_VF) {} else { BFCw(xFlags, F_OF, 1); }
|
||||
}
|
||||
if (BOX64ENV(dynarec_test)) {
|
||||
IFX(X_AF) BFCw(xFlags, F_AF, 1);
|
||||
IFX(X_PF) BFCw(xFlags, F_PF, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xF5:
|
||||
INST_NAME("BZHI Gd, Ed, Vd");
|
||||
nextop = F8;
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETGD;
|
||||
GETED(0);
|
||||
GETVD;
|
||||
UXTBw(x1, vd);
|
||||
CMPSw_U12(x1, 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);
|
||||
MARK;
|
||||
need_tst = 0;
|
||||
IFX(X_ZF) need_tst = 1;
|
||||
IFXNATIVE(X_SF, NF_SF) need_tst = 1;
|
||||
IFXNATIVE(X_OF, NF_VF) need_tst = 1;
|
||||
if(need_tst) {
|
||||
BICSxw(gd, ed, x2);
|
||||
} else
|
||||
BICxw(gd, ed, x2);
|
||||
IFX(X_ZF) {
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
IFNATIVE(NF_SF) {} else {
|
||||
LSRxw(x3, gd, rex.w?63:31);
|
||||
BFIw(xFlags, x3, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_AF) BFCw(xFlags, F_AF, 1);
|
||||
IFX(X_PF) BFCw(xFlags, F_PF, 1);
|
||||
IFX(X_OF) {
|
||||
IFNATIVE(NF_VF) {} else { BFCw(xFlags, F_OF, 1); }
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xF7:
|
||||
INST_NAME("BEXTR Gd, Ed, Vd");
|
||||
nextop = F8;
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETGD;
|
||||
GETED(0);
|
||||
GETVD;
|
||||
MOV64xw(x1, 0);
|
||||
UXTBw(x2, vd); // start
|
||||
BFXILw(x3, vd, 8, 8); // length
|
||||
TSTw_REG(x3, x3);
|
||||
B_MARK(cEQ);
|
||||
LSRxw_REG(x1, ed, x2);
|
||||
CMPSw_U12(x3, rex.w?64:32);
|
||||
B_MARK(cGE);
|
||||
MOV32w(x2, rex.w?64:32);
|
||||
SUBw_REG(x2, x2, x3);
|
||||
LSLxw_REG(x1, x1, x2);
|
||||
LSRxw_REG(x1, x1, x2);
|
||||
TSTxw_REG(x1, x1);
|
||||
MARK;
|
||||
MOVxw_REG(gd, x1);
|
||||
IFX(X_ZF) {
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_AF) BFCw(xFlags, F_AF, 1);
|
||||
IFX(X_PF) BFCw(xFlags, F_PF, 1);
|
||||
IFX(X_CF) BFCw(xFlags, F_CF, 1);
|
||||
IFX(X_OF) {
|
||||
IFNATIVE(NF_VF) {} else { BFCw(xFlags, F_OF, 1); }
|
||||
}
|
||||
IFX(X_SF) {
|
||||
IFNATIVE(NF_SF) {} else { BFCw(xFlags, F_SF, 1); }
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,821 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
#include "my_cpuid.h"
|
||||
#include "emu/x87emu_private.h"
|
||||
#include "emu/x64shaext.h"
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "../dynarec_helper.h"
|
||||
|
||||
uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop, u8;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback, wb1, wb2;
|
||||
uint8_t eb1, eb2, gb1, gb2;
|
||||
int32_t i32, i32_;
|
||||
int cacheupd = 0;
|
||||
int v0, v1, v2;
|
||||
int q0, q1, q2;
|
||||
int d0, d1, d2;
|
||||
int s0;
|
||||
uint64_t tmp64u;
|
||||
int64_t j64;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
MAYUSE(wb1);
|
||||
MAYUSE(wb2);
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
MAYUSE(gb1);
|
||||
MAYUSE(gb2);
|
||||
MAYUSE(q0);
|
||||
MAYUSE(q1);
|
||||
MAYUSE(d0);
|
||||
MAYUSE(d1);
|
||||
MAYUSE(s0);
|
||||
MAYUSE(j64);
|
||||
MAYUSE(cacheupd);
|
||||
#if STEP > 1
|
||||
static const int8_t round_round[] = { 0, 2, 1, 3};
|
||||
#endif
|
||||
|
||||
rex_t rex = vex.rex;
|
||||
|
||||
switch(opcode) {
|
||||
case 0x00:
|
||||
case 0x01:
|
||||
if(opcode) {INST_NAME("VPERMPD Gx, Ex, Imm8");} else {INST_NAME("VPERMQ Gx, Ex, Imm8");}
|
||||
nextop = F8;
|
||||
GETGX_empty_EX(v0, q0, 1);
|
||||
u8 = F8;
|
||||
if(v0==q0) d0 = fpu_get_scratch(dyn, ninst);
|
||||
if(v0==q0 || !MODREG) d1 = fpu_get_scratch(dyn, ninst);
|
||||
q1 = d1;
|
||||
GETGY_empty_EY(v1, q1);
|
||||
if(v0==q0) { VMOVQ(d0, q0); VMOVQ(d1, q1); } else {d1 = q1; d0 = q0;}
|
||||
VMOVeD(v0, 0, ((u8>>1)&1)?d1:d0, (u8>>0)&1);
|
||||
VMOVeD(v0, 1, ((u8>>3)&1)?d1:d0, (u8>>2)&1);
|
||||
VMOVeD(v1, 0, ((u8>>5)&1)?d1:d0, (u8>>4)&1);
|
||||
VMOVeD(v1, 1, ((u8>>7)&1)?d1:d0, (u8>>6)&1);
|
||||
break;
|
||||
case 0x02:
|
||||
INST_NAME("VPBLENDD Gx, Vx, Ex, u8");
|
||||
nextop = F8;
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 1); u8 = F8;} else { GETGY_empty_VYEY(v0, v2, v1); u8 >>=4;}
|
||||
wb1 = 0; // mask
|
||||
for(int i=0; i<4; ++i)
|
||||
if(u8&(1<<i))
|
||||
wb1 |= (3<<(i*2));
|
||||
MOVI_64(q0, wb1); // load 8bits value as a 8bytes mask
|
||||
SXTL_16(q0, q0); // expand 16bits to 32bits...
|
||||
if(v0==v1) {
|
||||
VBIFQ(v0, v2, q0);
|
||||
} else {
|
||||
if(v0!=v2) VMOVQ(v0, v2);
|
||||
VBITQ(v0, v1, q0);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0x04:
|
||||
INST_NAME("VPERMILPS Gx, Ex, Imm8");
|
||||
nextop = F8;
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) {
|
||||
GETGX_empty_EX(v0, v1, 1);
|
||||
u8 = F8;
|
||||
if(v0==v1) {q1 = fpu_get_scratch(dyn, ninst); VMOVQ(q1, v1);}
|
||||
} else {
|
||||
GETGY_empty_EY(v0, v1);
|
||||
if(v0==v1) {VMOVQ(q1, v1);}
|
||||
}
|
||||
if(u8==0x00 || u8==0x55 || u8==0xAA || u8==0xFF)
|
||||
VDUPQ_32(v0, (v0==v1)?q1:v1, u8&3);
|
||||
else if(u8==0x50)
|
||||
VZIP1Q_32(v0, v1, v1);
|
||||
else if(u8==0xFA)
|
||||
VZIP2Q_32(v0, v1, v1);
|
||||
else if(u8==0xA0)
|
||||
VTRNQ1_32(v0, v1, v1);
|
||||
else if(u8==0xF5)
|
||||
VTRNQ2_32(v0, v1, v1);
|
||||
else for(int i=0; i<4; ++i)
|
||||
VMOVeS(v0, i, (v0==v1)?q1:v1, (u8>>(i*2))&3);
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x05:
|
||||
INST_NAME("VPERMILD Gx, Ex, Imm8");
|
||||
nextop = F8;
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) {
|
||||
GETGX_empty_EX(v0, v1, 1);
|
||||
u8 = F8;
|
||||
} else {
|
||||
GETGY_empty_EY(v0, v1);
|
||||
}
|
||||
switch(((u8>>(l*2))&3)) {
|
||||
case 0b00:
|
||||
case 0b11:
|
||||
VDUPQ_64(v0, v1, ((u8>>(l*2))&1));
|
||||
break;
|
||||
case 0b10:
|
||||
if(v0!=v1) VMOVQ(v0, v1);
|
||||
break;
|
||||
case 0b01:
|
||||
VEXTQ_8(v0, v1, v1, 8); // invert 64bits values
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x06:
|
||||
case 0x46:
|
||||
if(opcode==0x06) { INST_NAME("VPERM2F128 Gx, Vx, Ex, Imm8"); } else { INST_NAME("VPERM2I128 Gx, Vx, Ex, Imm8"); }
|
||||
nextop = F8;
|
||||
if(!vex.l) UDF(0);
|
||||
if(MODREG) {
|
||||
s0 = (nextop&7)+(rex.b<<3);
|
||||
v1 = sse_get_reg(dyn, ninst, x1, s0, 0);
|
||||
} else {
|
||||
s0 = -1;
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0xffe<<4, 15, rex, NULL, 0, 0);
|
||||
}
|
||||
u8 = F8;
|
||||
GETVX(v2, 0);
|
||||
GETGX_empty(v0);
|
||||
if((v0==v2) && ((u8&0xf0)==0)) {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
VMOVQ(q0, v2);
|
||||
v2 = q0;
|
||||
}
|
||||
if((v0==v1) && ((u8&0xf0)==0x20)) {
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
VMOVQ(q1, v1);
|
||||
v1 = q1;
|
||||
}
|
||||
switch(u8&0b1011) {
|
||||
case 0: if(v0!=v2) VMOVQ(v0, v2); break;
|
||||
case 1: d2 = ymm_get_reg(dyn, ninst, x1, vex.v, 0, gd, s0, -1); VMOVQ(v0, d2); break;
|
||||
case 2: if(MODREG) { if(v0!=v1) VMOVQ(v0, v1); } else { VLDR128_U12(v0, ed, fixedaddress); } break;
|
||||
case 3: if(MODREG) { d1 = ymm_get_reg(dyn, ninst, x1, s0, 0, gd, vex.v, -1); VMOVQ(v0, d1); } else { VLDR128_U12(v0, ed, fixedaddress+16); } break;
|
||||
default: VEORQ(v0, v0, v0);
|
||||
}
|
||||
if((u8&0xf0)==0x10) { if((u8&0x0f)!=1) d2 = ymm_get_reg(dyn, ninst, x1, vex.v, 0, gd, s0, -1); }
|
||||
if(MODREG && ((u8&0xf0)==0x30)) { if((u8&0x0f)!=3) d1 = ymm_get_reg(dyn, ninst, x1, s0, 0, gd, vex.v, -1); }
|
||||
v0 = ymm_get_reg_empty(dyn, ninst, x1, gd, vex.v, s0, -1);
|
||||
switch((u8>>4)&0b1011) {
|
||||
case 0: VMOVQ(v0, v2); break;
|
||||
case 1: if(v0!=d2) VMOVQ(v0, d2); break;
|
||||
case 2: if(MODREG) { if(v0!=v1) VMOVQ(v0, v1); } else { VLDR128_U12(v0, ed, fixedaddress); } break;
|
||||
case 3: if(MODREG) { if(v0!=d1) VMOVQ(v0, d1); } else { VLDR128_U12(v0, ed, fixedaddress+16); } break;
|
||||
default: VEORQ(v0, v0, v0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x08:
|
||||
INST_NAME("VROUNDPS Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_EX(v0, v1, 1); u8 = F8; } else { GETGY_empty_EY(v0, v1); }
|
||||
if(u8&4) {
|
||||
if(!l) wb1 = sse_setround(dyn, ninst, x1, x2, x4);
|
||||
VFRINTISQ(v0, v1);
|
||||
if(l || !vex.l) x87_restoreround(dyn, ninst, wb1);
|
||||
} else {
|
||||
VFRINTRSQ(v0, v1, round_round[u8&3]);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x09:
|
||||
INST_NAME("VROUNDPD Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_EX(v0, v1, 1); u8 = F8; } else { GETGY_empty_EY(v0, v1); }
|
||||
if(u8&4) {
|
||||
if(!l) wb1 = sse_setround(dyn, ninst, x1, x2, x4);
|
||||
VFRINTIDQ(v0, v1);
|
||||
if(l || !vex.l) x87_restoreround(dyn, ninst, wb1);
|
||||
} else {
|
||||
VFRINTRDQ(v0, v1, round_round[u8&3]);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x0A:
|
||||
INST_NAME("VROUNDSS Gx, Vx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETEXSS(v1, 0, 1);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
u8 = F8;
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
if(u8&4) {
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x3);
|
||||
FRINTXS(d1, v1);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
} else {
|
||||
FRINTRRS(d1, v1, round_round[u8&3]);
|
||||
}
|
||||
if(v0!=v2) VMOVQ(v0, v2);
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x0B:
|
||||
INST_NAME("VROUNDSD Gx, Vx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETEXSD(v1, 0, 1);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
u8 = F8;
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
if(u8&4) {
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x3);
|
||||
FRINTXD(d1, v1);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
} else {
|
||||
FRINTRRD(d1, v1, round_round[u8&3]);
|
||||
}
|
||||
if(v0!=v2) VMOVQ(v0, v2);
|
||||
VMOVeD(v0, 0, d1, 0);
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x0C:
|
||||
INST_NAME("VBLENDPS Gx, Vx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGX_empty_VXEX(q0, q2, q1, 1);
|
||||
u8 = F8;
|
||||
if((u8&0xf)==0xf) {
|
||||
if(q0!=q1) VMOVQ(q0, q1);
|
||||
} else if(q0==q1) {
|
||||
for(int i=0; i<4; ++i)
|
||||
if(u8&(1<<i)) {
|
||||
//VMOVeS(q0, i, q1, i);
|
||||
} else if(q0!=q2)
|
||||
VMOVeS(q0, i, q2, i);
|
||||
} else {
|
||||
if(q0!=q2)
|
||||
VMOVQ(q0, q2);
|
||||
if((u8&0b0011)==0b0011) {
|
||||
VMOVeD(q0, 0, q1, 0);
|
||||
u8&=~0b0011;
|
||||
}
|
||||
if((u8&0b1100)==0b1100) {
|
||||
VMOVeD(q0, 1, q1, 1);
|
||||
u8&=~0b1100;
|
||||
}
|
||||
for(int i=0; i<4; ++i)
|
||||
if(u8&(1<<i)) {
|
||||
VMOVeS(q0, i, q1, i);
|
||||
}
|
||||
}
|
||||
if(vex.l) {
|
||||
GETGY_empty_VYEY(q0, q2, q1);
|
||||
if((u8&0xf0)==0xf0) {
|
||||
if(q0!=q1) VMOVQ(q0, q1);
|
||||
} else if(q0==q1) {
|
||||
for(int i=0; i<4; ++i)
|
||||
if(u8&(1<<(i+4))) {
|
||||
//VMOVeS(q0, i, q1, i);
|
||||
} else if(q0!=q2)
|
||||
VMOVeS(q0, i, q2, i);
|
||||
} else {
|
||||
if(q0!=q2)
|
||||
VMOVQ(q0, q2);
|
||||
if(((u8>>4)&0b0011)==0b0011) {
|
||||
VMOVeD(q0, 0, q1, 0);
|
||||
u8&=~0b00110000;
|
||||
}
|
||||
if(((u8>>4)&0b1100)==0b1100) {
|
||||
VMOVeD(q0, 1, q1, 1);
|
||||
u8&=~0b11000000;
|
||||
}
|
||||
for(int i=0; i<4; ++i)
|
||||
if(u8&(1<<(i+4))) {
|
||||
VMOVeS(q0, i, q1, i);
|
||||
}
|
||||
}
|
||||
} else YMM0(gd);
|
||||
break;
|
||||
case 0x0D:
|
||||
INST_NAME("VBLENDPD Gx, Vx, Ex, Ib");
|
||||
nextop = F8;
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_VXEX(q0, q2, q1, 1); u8 = F8; } else { GETGY_empty_VYEY(q0, q2, q1); }
|
||||
switch((u8>>(l*2))&3) {
|
||||
case 0b00: if(q0!=q2) VMOVQ(q0, q2); break; // VxVx
|
||||
case 0b01: if(q0!=q1) VMOVeD(q0, 0, q1, 0); if(q0!=q2) VMOVeD(q0, 1, q2, 1); break; // Ex[0]Vx[1]
|
||||
case 0b10: if(q0!=q2) VMOVeD(q0, 0, q2, 0); if(q0!=q1) VMOVeD(q0, 1, q1, 1); break; // Vx[0]Ex[1]
|
||||
case 0b11: if(q0!=q1) VMOVQ(q0, q1); break; // ExEx
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x0E:
|
||||
INST_NAME("VPBLENDW Gx, Vx, Ex, u8");
|
||||
nextop = F8;
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 1); u8 = F8;} else { GETGY_empty_VYEY(v0, v2, v1); }
|
||||
if(!l) {
|
||||
MOVI_64(q0, u8);
|
||||
SXTL_8(q0, q0); // expand 8bits to 16bits...
|
||||
}
|
||||
if(v0!=v2) VBIFQ(v0, v2, q0);
|
||||
if(v0!=v1) VBITQ(v0, v1, q0);
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x0F:
|
||||
INST_NAME("VPALIGNR Gx, Vx, Ex, Ib");
|
||||
nextop = F8;
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) {
|
||||
GETGX_empty_VXEX(v0, v2, v1, 1);
|
||||
u8 = F8;
|
||||
} else {
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
}
|
||||
if(u8>31) {
|
||||
VEORQ(v0, v0, v0);
|
||||
} else if(u8>15) {
|
||||
if(!l) VEORQ(d0, d0, d0);
|
||||
VEXTQ_8(v0, v2, d0, u8-16);
|
||||
} else {
|
||||
VEXTQ_8(v0, v1, v2, u8);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0x14:
|
||||
INST_NAME("VPEXTRB Ed, Gx, imm8");
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
if(MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff, 0, rex, NULL, 0, 1);
|
||||
ed = x1;
|
||||
}
|
||||
u8 = F8;
|
||||
VMOVBto(ed, v0, u8&0x0f);
|
||||
if(!MODREG) {
|
||||
STB(ed, wback, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x15:
|
||||
INST_NAME("VPEXTRW Ed, Gx, imm8");
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
if(MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 1);
|
||||
ed = x1;
|
||||
}
|
||||
u8 = F8;
|
||||
VMOVHto(ed, v0, u8&7);
|
||||
if(!MODREG) {
|
||||
STH(ed, wback, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x16:
|
||||
INST_NAME("VPEXTRD/Q Ed, Gx, imm8");
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
if(MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 1);
|
||||
ed = x1;
|
||||
}
|
||||
u8 = F8;
|
||||
if(rex.w) {
|
||||
VMOVQDto(ed, v0, u8&1);
|
||||
} else {
|
||||
VMOVSto(ed, v0, u8&3);
|
||||
}
|
||||
if(!MODREG) {
|
||||
STxw(ed, wback, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x17:
|
||||
INST_NAME("VEXTRACTPS Ed, Gx, imm8");
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
if(MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 1);
|
||||
ed = x1;
|
||||
}
|
||||
u8 = F8;
|
||||
VMOVSto(ed, v0, u8&3);
|
||||
if(!MODREG) {
|
||||
STW(ed, wback, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x18:
|
||||
case 0x38:
|
||||
if(opcode==0x18) {INST_NAME("VINSERTF128 Gx, Vx, Ex, imm8");} else {INST_NAME("VINSERTI128 Gx, Vx, Ex, imm8");}
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 1);
|
||||
v1 = -1; // to avoid a warning
|
||||
}
|
||||
u8 = F8;
|
||||
GETVX(v2, 0);
|
||||
GETGX_empty(v0);
|
||||
if(v0==v2 && u8==1) {
|
||||
GETGY_empty(q0, 0, (MODREG)?((nextop&7)+(rex.b<<3)):-1, -1);
|
||||
q2 = q0;
|
||||
} else {
|
||||
GETGY_empty_VY(q0, q2, 0, (MODREG)?((nextop&7)+(rex.b<<3)):-1, -1);
|
||||
}
|
||||
if(MODREG)
|
||||
VMOVQ((u8&1)?q0:v0, v1);
|
||||
else
|
||||
VLD128((u8&1)?q0:v0, ed, fixedaddress);
|
||||
if(v0!=v2)
|
||||
VMOVQ((u8&1)?v0:q0, (u8&1)?v2:q2);
|
||||
break;
|
||||
case 0x19:
|
||||
case 0x39:
|
||||
if(opcode==0x19) {INST_NAME("VEXTRACTF128 Ex, Gx, imm8");} else {INST_NAME("VEXTRACTI128 Ex, Gx, imm8");}
|
||||
nextop = F8;
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop);
|
||||
GETGX(v0, 0);
|
||||
if(u8&1) {GETGY(v0, ((nextop&7)+(rex.b<<3)==gd && MODREG)?1:0, -1, -1, -1);}
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, (nextop&7)+(rex.b<<3));
|
||||
VMOVQ(v1, v0);
|
||||
if((nextop&7)+(rex.b<<3)==gd && (u8&1))
|
||||
VEORQ(v0, v0, v0); // special case like vextractf128 xmm3, ymm3, 0x01
|
||||
else
|
||||
YMM0((nextop&7)+(rex.b<<3));
|
||||
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 1);
|
||||
VST128(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
F8; // read u8, but it's been already handled
|
||||
break;
|
||||
|
||||
case 0x1D:
|
||||
INST_NAME("VCVTPS2PH Ex, Gx");
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x3, (nextop&7)+(rex.b<<3));
|
||||
} else {
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, &unscaled, 0xfff<<(3+vex.l), vex.l?15:7, rex, NULL, 0, 1);
|
||||
}
|
||||
if(vex.l && v0==v1) {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
VMOVQ(q0, v0);
|
||||
v0 = q0;
|
||||
}
|
||||
u8 = F8;
|
||||
if(u8&4) {
|
||||
s0 = sse_setround(dyn, ninst, x1, x2, x6);
|
||||
} else {
|
||||
u8&=3;
|
||||
if(u8==1) u8=2;
|
||||
else if(u8==2) u8=1;
|
||||
MRS_fpcr(x1); // get fpscr
|
||||
MOV32w(x2, u8);
|
||||
MOVx_REG(x6, x1);
|
||||
BFIx(x1, x2, 22, 2); // inject new round
|
||||
MSR_fpcr(x1); // put new fpscr
|
||||
s0 = x6;
|
||||
}
|
||||
FCVTN16(v1, v0);
|
||||
if(vex.l) {
|
||||
GETGY(v0, 0, MODREG?((nextop&7)+(rex.b<<3)):-1, -1,-1);
|
||||
FCVTN162(v1, v0);
|
||||
}
|
||||
x87_restoreround(dyn, ninst, s0);
|
||||
if(MODREG) {
|
||||
YMM0((nextop&7)+(rex.b<<3));
|
||||
} else {
|
||||
if(vex.l) {
|
||||
VST128(v1, ed, fixedaddress);
|
||||
} else {
|
||||
VST64(v1, ed, fixedaddress);
|
||||
}
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x20:
|
||||
INST_NAME("VINSERTD Gx, Vx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGX_empty_VX(v0, v2);
|
||||
GETED(1);
|
||||
u8 = F8;
|
||||
if(v0!=v2) VMOVQ(v0, v2);
|
||||
VMOVQBfrom(v0, u8&0xf, ed);
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x21:
|
||||
INST_NAME("VINSERTPS Gx, Vx, Ex, Ib");
|
||||
nextop = F8;
|
||||
if (MODREG) {
|
||||
GETGX_empty_VXEX(v0, v2, v1, 1);
|
||||
u8 = F8;
|
||||
if(v0==v1) {
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
VMOVQ(d0, v1);
|
||||
if(v0!=v2) VMOVQ(v0, v2);
|
||||
VMOVeS(v0, (u8>>4)&3, d0, (u8>>6)&3);
|
||||
} else {
|
||||
if(v0!=v2) VMOVQ(v0, v2);
|
||||
VMOVeS(v0, (u8>>4)&3, v1, (u8>>6)&3);
|
||||
}
|
||||
} else {
|
||||
GETGX_empty_VX(v0, v2);
|
||||
if(v0!=v2) VMOVQ(v0, v2);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 1);
|
||||
u8 = F8;
|
||||
LDW(x2, wback, fixedaddress);
|
||||
VMOVQSfrom(v0, (u8>>4)&3, x2);
|
||||
}
|
||||
uint8_t zmask = u8 & 0xf;
|
||||
for (uint8_t i=0; i<4; i++) {
|
||||
if (zmask & (1<<i)) {
|
||||
VMOVQSfrom(v0, i, wZR);
|
||||
}
|
||||
}
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x22:
|
||||
INST_NAME("VINSERTD Gx, Vx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGX_empty_VX(v0, v2);
|
||||
GETED(1);
|
||||
u8 = F8;
|
||||
if(v0!=v2) VMOVQ(v0, v2);
|
||||
if(rex.w)
|
||||
VMOVQDfrom(v0, u8&1, ed);
|
||||
else
|
||||
VMOVQSfrom(v0, u8&3, ed);
|
||||
YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0x40:
|
||||
INST_NAME("VDPPS Gx, Vx, Ex, Ib");
|
||||
nextop = F8;
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
// first mask
|
||||
if((u8&0x0f)!=0x0f) {
|
||||
wb1 = 0; // mask
|
||||
for(int i=0; i<4; ++i)
|
||||
if(u8&(1<<i))
|
||||
wb1 |= (3<<(i*2));
|
||||
MOVI_64(q0, wb1); // load 8bits value as a 8bytes mask
|
||||
SXTL_16(q0, q0); // expand 16bits to 32bits...
|
||||
}
|
||||
if((u8&0xf0)!=0xf0) {
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
// second mask
|
||||
wb1 = 0; // mask
|
||||
for(int i=0; i<4; ++i)
|
||||
if((u8>>4)&(1<<i))
|
||||
wb1 |= (3<<(i*2));
|
||||
MOVI_64(q1, wb1); // load 8bits value as a 8bytes mask
|
||||
SXTL_16(q1, q1); // expand 16bits to 32bits...
|
||||
}
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 1); u8 = F8; } else { GETGY_empty_VYEY(v0, v2, v1); }
|
||||
VFMULQS(v0, v2, v1);
|
||||
if((u8&0xf0)!=0xf0) {
|
||||
VANDQ(v0, v0, q1); // second mask
|
||||
}
|
||||
VFADDPQS(v0, v0, v0);
|
||||
FADDPS(v0, v0);
|
||||
VDUPQ_32(v0, v0, 0);
|
||||
if((u8&0x0f)!=0x0f) {
|
||||
VANDQ(v0, v0, q0); // first mask
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0x41:
|
||||
INST_NAME("VDPPD Gx, Vx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGX_empty_VXEX(v0, v1, v2, 0);
|
||||
u8 = F8;
|
||||
VFMULQD(v0, v1, v2);
|
||||
// mask some, duplicate all, mask some
|
||||
for(int i=0; i<2; ++i)
|
||||
if(!(u8&(1<<(4+i)))) {
|
||||
VMOVQDfrom(v0, i, xZR);
|
||||
}
|
||||
FADDPD(v0, v0);
|
||||
VDUPQ_64(v0, v0, 0);
|
||||
for(int i=0; i<2; ++i)
|
||||
if(!(u8&(1<<i))) {
|
||||
VMOVQDfrom(v0, i, xZR);
|
||||
}
|
||||
YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0x44:
|
||||
INST_NAME("VPCLMULQDQ Gx, Vx, Ex, Ib");
|
||||
nextop = F8;
|
||||
if(arm64_pmull) {
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) {
|
||||
GETGX_empty_VXEX(v0, v2, v1, 1);
|
||||
u8 = F8;
|
||||
} else {
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
}
|
||||
switch (u8&0b00010001) {
|
||||
case 0b00000000:
|
||||
PMULL_128(v0, v2, v1);
|
||||
break;
|
||||
case 0b00010001:
|
||||
PMULL2_128(v0, v2, v1);
|
||||
break;
|
||||
case 0b00000001:
|
||||
VEXTQ_8(d0, v2, v2, 8); // Swap Up/Lower 64bits parts
|
||||
PMULL_128(v0, d0, v1);
|
||||
break;
|
||||
case 0b00010000:
|
||||
VEXTQ_8(d0, v2, v2, 8); // Swap Up/Lower 64bits parts
|
||||
PMULL2_128(v0, d0, v1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
GETG;
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
sse_reflect_reg(dyn, ninst, vex.v);
|
||||
MOV32w(x1, gd); // gx
|
||||
MOV32w(x2, vex.v); // vx
|
||||
if(MODREG) {
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
sse_forget_reg(dyn, ninst, ed);
|
||||
MOV32w(x3, ed);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 1);
|
||||
if(ed!=x3) {
|
||||
MOVx_REG(x3, ed);
|
||||
}
|
||||
}
|
||||
u8 = F8;
|
||||
MOV32w(x4, u8);
|
||||
CALL_(vex.l?native_pclmul_y:native_pclmul_x, -1, x3);
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
|
||||
//case 0x46: // see 0x06
|
||||
|
||||
case 0x4A:
|
||||
INST_NAME("VBLENDVPS Gx, Vx, Ex, XMMImm8");
|
||||
nextop = F8;
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop)>>4;
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) {
|
||||
q1 = sse_get_reg(dyn, ninst, x1, u8, 0);
|
||||
GETGX_empty_VXEX(v0, v2, v1, 1);
|
||||
F8;
|
||||
} else {
|
||||
v2 = ymm_get_reg(dyn, ninst, x1, vex.v, 0, gd, u8, (MODREG)?((nextop&7)+(rex.b<<3)):-1);
|
||||
if(MODREG)
|
||||
v1 = ymm_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0, gd, vex.v, u8);
|
||||
else
|
||||
VLDR128_U12(v1, ed, fixedaddress+16);
|
||||
q1 = ymm_get_reg(dyn, ninst, x1, u8, 0, vex.v, gd, (MODREG)?((nextop&7)+(rex.b<<3)):-1);
|
||||
v0 = ymm_get_reg_empty(dyn, ninst, x1, gd, vex.v, u8, (MODREG)?((nextop&7)+(rex.b<<3)):-1);
|
||||
}
|
||||
VSSHRQ_32(q0, q1, 31); // create mask
|
||||
if(v0!=v2) VBIFQ(v0, v2, q0);
|
||||
if(v0!=v1) VBITQ(v0, v1, q0);
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x4B:
|
||||
INST_NAME("VBLENDVPD Gx, Vx, Ex, XMMImm8");
|
||||
nextop = F8;
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop)>>4;
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) {
|
||||
q1 = sse_get_reg(dyn, ninst, x1, u8, 0);
|
||||
GETGX_empty_VXEX(v0, v2, v1, 1);
|
||||
F8;
|
||||
} else {
|
||||
v2 = ymm_get_reg(dyn, ninst, x1, vex.v, 0, gd, u8, (MODREG)?((nextop&7)+(rex.b<<3)):-1);
|
||||
if(MODREG)
|
||||
v1 = ymm_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0, gd, vex.v, u8);
|
||||
else
|
||||
VLDR128_U12(v1, ed, fixedaddress+16);
|
||||
q1 = ymm_get_reg(dyn, ninst, x1, u8, 0, vex.v, gd, (MODREG)?((nextop&7)+(rex.b<<3)):-1);
|
||||
v0 = ymm_get_reg_empty(dyn, ninst, x1, gd, vex.v, u8, (MODREG)?((nextop&7)+(rex.b<<3)):-1);
|
||||
}
|
||||
VSSHRQ_64(q0, q1, 63); // create mask
|
||||
if(v0!=v2) VBIFQ(v0, v2, q0);
|
||||
if(v0!=v1) VBITQ(v0, v1, q0);
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x4C:
|
||||
INST_NAME("VPBLENDVB Gx, Vx, Ex, XMMImm8");
|
||||
nextop = F8;
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop)>>4;
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) {
|
||||
q1 = sse_get_reg(dyn, ninst, x1, u8, 0);
|
||||
GETGX_empty_VXEX(v0, v2, v1, 1);
|
||||
F8;
|
||||
} else {
|
||||
v2 = ymm_get_reg(dyn, ninst, x1, vex.v, 0, gd, u8, (MODREG)?ed:-1);
|
||||
if(MODREG)
|
||||
v1 = ymm_get_reg(dyn, ninst, x1, ed, 0, gd, vex.v, u8);
|
||||
else
|
||||
VLDR128_U12(v1, ed, fixedaddress+16);
|
||||
q1 = ymm_get_reg(dyn, ninst, x1, u8, 0, vex.v, gd, (MODREG)?ed:-1);
|
||||
v0 = ymm_get_reg_empty(dyn, ninst, x1, gd, vex.v, u8, (MODREG)?ed:-1);
|
||||
}
|
||||
VSSHRQ_8(q0, q1, 7); // create mask
|
||||
if(v0!=v2) VBIFQ(v0, v2, q0);
|
||||
if(v0!=v1) VBITQ(v0, v1, q0);
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0xDF:
|
||||
INST_NAME("VAESKEYGENASSIST Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
sse_forget_reg(dyn, ninst, gd);
|
||||
MOV32w(x1, gd); // gx
|
||||
if(MODREG) {
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
sse_forget_reg(dyn, ninst, ed);
|
||||
MOV32w(x2, ed);
|
||||
MOV32w(x3, 0); //p = NULL
|
||||
} else {
|
||||
MOV32w(x2, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 1);
|
||||
if(ed!=x3) {
|
||||
MOVx_REG(x3, ed);
|
||||
}
|
||||
}
|
||||
u8 = F8;
|
||||
MOV32w(x4, u8);
|
||||
CALL(native_aeskeygenassist, -1);
|
||||
YMM0(gd);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,614 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
#include "my_cpuid.h"
|
||||
#include "emu/x87emu_private.h"
|
||||
#include "emu/x64shaext.h"
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "../dynarec_helper.h"
|
||||
|
||||
uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop, u8;
|
||||
uint8_t gd, ed, vd;
|
||||
uint8_t wback, wb1, wb2;
|
||||
uint8_t eb1, eb2, gb1, gb2;
|
||||
int32_t i32, i32_;
|
||||
int cacheupd = 0;
|
||||
int v0, v1, v2;
|
||||
int q0, q1, q2;
|
||||
int d0, d1, d2;
|
||||
int s0;
|
||||
uint64_t tmp64u, u64;
|
||||
int64_t j64;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
MAYUSE(wb1);
|
||||
MAYUSE(wb2);
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
MAYUSE(gb1);
|
||||
MAYUSE(gb2);
|
||||
MAYUSE(q0);
|
||||
MAYUSE(q1);
|
||||
MAYUSE(d0);
|
||||
MAYUSE(d1);
|
||||
MAYUSE(s0);
|
||||
MAYUSE(j64);
|
||||
MAYUSE(cacheupd);
|
||||
|
||||
rex_t rex = vex.rex;
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0x10:
|
||||
INST_NAME("VMOVSD Gx, [Vx,] Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
GETGX_empty_VXEX(v0, v2, v1, 0);
|
||||
if(v0!=v1) VMOVeD(v0, 0, v1, 0);
|
||||
if(v0!=v2) VMOVeD(v0, 1, v2, 1);
|
||||
} else {
|
||||
SMREAD();
|
||||
GETGX_empty(v0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v0, ed, fixedaddress); // upper part reseted
|
||||
}
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x11:
|
||||
INST_NAME("VMOVSD Ex, Vx, Gx");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if(MODREG) {
|
||||
GETVXEX(v2, 0, v1, 1, 0);
|
||||
if(v0!=v1) VMOVeD(v1, 0, v0, 0);
|
||||
if(v1!=v2) VMOVeD(v1, 1, v2, 1);
|
||||
YMM0((nextop&7)+(rex.b<<3));
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VST64(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x12:
|
||||
INST_NAME("VMOVDDUP Gx, Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
GETGX_empty(v0);
|
||||
VDUPQ_64(v0, v1, 0);
|
||||
if(vex.l) {
|
||||
GETGY_empty_EY(v0, v1);
|
||||
VDUPQ_64(v0, v1, 0);
|
||||
}
|
||||
} else {
|
||||
SMREAD();
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
VLDQ1R_64(v0, ed);
|
||||
if(vex.l) {
|
||||
GETGY_empty(v0, -1, -1, -1);
|
||||
ADDx_U12(x3, ed, 16);
|
||||
VLDQ1R_64(v0, x3);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0x2A:
|
||||
INST_NAME("VCVTSI2SD Gx, Vx, Ed");
|
||||
nextop = F8;
|
||||
GETGX_empty_VX(v0, v1);
|
||||
GETED(0);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
if(BOX64ENV(dynarec_fastround)<2) {
|
||||
u8 = sse_setround(dyn, ninst, x3, x4, x5);
|
||||
}
|
||||
if(rex.w) {
|
||||
SCVTFDx(d1, ed);
|
||||
} else {
|
||||
SCVTFDw(d1, ed);
|
||||
}
|
||||
if(BOX64ENV(dynarec_fastround)<2) {
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
}
|
||||
if(v0!=v1) VMOVQ(v0, v1);
|
||||
VMOVeD(v0, 0, d1, 0);
|
||||
YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0x2C:
|
||||
INST_NAME("VCVTTSD2SI Gd, Ex");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEXSD(q0, 0, 0);
|
||||
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
}
|
||||
if(!BOX64ENV(dynarec_fastround) && arm64_frintts) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
if(rex.w) {
|
||||
FRINT64ZD(v0, q0);
|
||||
} else {
|
||||
FRINT32ZD(v0, q0);
|
||||
}
|
||||
FCVTZSxwD(gd, v0);
|
||||
} else {
|
||||
FCVTZSxwD(gd, q0);
|
||||
}
|
||||
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_NEXT(x5, FPSR_IOC);
|
||||
if(rex.w) {
|
||||
ORRx_mask(gd, xZR, 1, 1, 0); //0x8000000000000000
|
||||
} else {
|
||||
MOV32w(gd, 0x80000000);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x2D:
|
||||
INST_NAME("VCVTSD2SI Gd, Ex");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEXSD(q0, 0, 0);
|
||||
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
}
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x3);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
if(!BOX64ENV(dynarec_fastround) && arm64_frintts) {
|
||||
if(rex.w) {
|
||||
FRINT64XD(d1, q0);
|
||||
} else {
|
||||
FRINT32XD(d1, q0);
|
||||
}
|
||||
} else {
|
||||
FRINTID(d1, q0);
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
FCVTZSxwD(gd, d1);
|
||||
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_NEXT(x5, FPSR_IOC);
|
||||
if(rex.w) {
|
||||
ORRx_mask(gd, xZR, 1, 1, 0); //0x8000000000000000
|
||||
} else {
|
||||
MOV32w(gd, 0x80000000);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x51:
|
||||
INST_NAME("VSQRTSD Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSD(v1, 0, 0);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
FCMEQD(q0, v1, v1); // 0 if NAN, 1 if not NAN
|
||||
}
|
||||
FSQRTD(d1, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
FCMEQD(q1, d1, d1); // 0 => out is NAN
|
||||
VBIC(q1, q0, q1); // forget it in any input was a NAN already
|
||||
SHL_64(q1, q1, 63); // only keep the sign bit
|
||||
VORR(d1, d1, q1); // NAN -> -NAN
|
||||
}
|
||||
if(v0!=v2) {
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeD(v0, 0, d1, 0);
|
||||
YMM0(gd)
|
||||
break;
|
||||
|
||||
case 0x58:
|
||||
INST_NAME("VADDSD Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
q2 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSD(v1, 0, 0);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
FMAXD(q1, v0, v1); // propagate NAN
|
||||
FCMEQD(q1, q1, q1); // 0 if NAN, 1 if not NAN
|
||||
FADDD(q2, v1, v2); // the high part of the vector is erased...
|
||||
FCMEQD(q0, q2, q2); // 0 => out is NAN
|
||||
VBIC(q0, q1, q0); // forget it in any input was a NAN already
|
||||
SHL_64(q0, q0, 63); // only keep the sign bit
|
||||
VORR(q2, q2, q0); // NAN -> -NAN
|
||||
} else {
|
||||
FADDD(q2, v1, v2); // the high part of the vector is erased...
|
||||
}
|
||||
if(v0!=v2) {
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeD(v0, 0, q2, 0);
|
||||
YMM0(gd)
|
||||
break;
|
||||
case 0x59:
|
||||
INST_NAME("VMULSD Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
q2 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSD(v1, 0, 0);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
FMAXD(q1, v0, v1); // propagate NAN
|
||||
FCMEQD(q1, q1, q1); // 0 if NAN, 1 if not NAN
|
||||
FMULD(q2, v1, v2); // the high part of the vector is erased...
|
||||
FCMEQD(q0, q2, q2); // 0 => out is NAN
|
||||
VBIC(q0, q1, q0); // forget it in any input was a NAN already
|
||||
SHL_64(q0, q0, 63); // only keep the sign bit
|
||||
VORR(q2, q2, q0); // NAN -> -NAN
|
||||
} else {
|
||||
FMULD(q2, v1, v2); // the high part of the vector is erased...
|
||||
}
|
||||
if(v0!=v2) {
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeD(v0, 0, q2, 0);
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x5A:
|
||||
INST_NAME("VCVTSD2SS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSD(v1, 0, 0);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
if(BOX64ENV(dynarec_fastround)==2) {
|
||||
FCVT_S_D(d1, v1);
|
||||
} else {
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x3);
|
||||
FCVT_S_D(d1, v1);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
}
|
||||
if(v0!=v2) {
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
YMM0(gd)
|
||||
break;
|
||||
|
||||
case 0x5C:
|
||||
INST_NAME("VSUBSD Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
q2 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSD(v1, 0, 0);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
FMAXD(q1, v0, v1); // propagate NAN
|
||||
FCMEQD(q1, q1, q1); // 0 if NAN, 1 if not NAN
|
||||
FSUBD(q2, v2, v1); // the high part of the vector is erased...
|
||||
FCMEQD(q0, q2, q2); // 0 => out is NAN
|
||||
VBIC(q0, q1, q0); // forget it in any input was a NAN already
|
||||
SHL_64(q0, q0, 63); // only keep the sign bit
|
||||
VORR(q2, q2, q0); // NAN -> -NAN
|
||||
} else {
|
||||
FSUBD(q2, v2, v1); // the high part of the vector is erased...
|
||||
}
|
||||
if(v0!=v2) {
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeD(v0, 0, q2, 0);
|
||||
YMM0(gd)
|
||||
break;
|
||||
case 0x5D:
|
||||
INST_NAME("VMINSD Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSD(v1, 0, 0);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
// VMINSD: if any input is NaN, or Ex[0]<Gx[0], copy Ex[0] -> Gx[0]
|
||||
FCMPD(v2, v1);
|
||||
FCSELD(d1, v1, v2, cCS); //CS: NAN or == or Vx > Ex
|
||||
if(v0!=v2) {
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeD(v0, 0, d1, 0); // to not erase uper part
|
||||
YMM0(gd)
|
||||
break;
|
||||
case 0x5E:
|
||||
INST_NAME("VDIVSD Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
q2 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSD(v1, 0, 0);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
FMAXD(q1, v0, v1); // propagate NAN
|
||||
FCMEQD(q1, q1, q1); // 0 if NAN, 1 if not NAN
|
||||
FDIVD(q2, v2, v1); // the high part of the vector is erased...
|
||||
FCMEQD(q0, q2, q2); // 0 => out is NAN
|
||||
VBIC(q0, q1, q0); // forget it in any input was a NAN already
|
||||
SHL_64(q0, q0, 63); // only keep the sign bit
|
||||
VORR(q2, q2, q0); // NAN -> -NAN
|
||||
} else {
|
||||
FDIVD(q2, v2, v1); // the high part of the vector is erased...
|
||||
}
|
||||
if(v0!=v2) {
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeD(v0, 0, q2, 0);
|
||||
YMM0(gd)
|
||||
break;
|
||||
case 0x5F:
|
||||
INST_NAME("VMAXSD Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSD(v1, 0, 0);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
FCMPD(v1, v2);
|
||||
FCSELD(d1, v1, v2, cCS); //CS: NAN or == or Ex > Vx
|
||||
if(v0!=v2) {
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeD(v0, 0, d1, 0); // to not erase uper part
|
||||
YMM0(gd)
|
||||
break;
|
||||
|
||||
case 0x70:
|
||||
INST_NAME("VPSHUFLW Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETEX_Y(v1, 0, 1); GETGX(v0, 1); u8 = F8; } else { GETGY(v0, 1, MODREG?((nextop&7)+(rex.b<<3)):-1, -1, -1); GETEY(v1); }
|
||||
if(u8==0b00000000 || u8==0b01010101 || u8==0b10101010 || u8==0b11111111) {
|
||||
if(v0==v1) {
|
||||
VMOVQ(d0, v1);
|
||||
}
|
||||
VDUP_16(v0, v1, u8&3);
|
||||
if(v0==v1)
|
||||
v1 = d0;
|
||||
} else {
|
||||
// only low part need to be suffled. VTBL only handle 8bits value, so the 16bits suffles need to be changed in 8bits
|
||||
if(!l) {
|
||||
u64 = 0;
|
||||
for (int i=0; i<4; ++i) {
|
||||
u64 |= ((uint64_t)((u8>>(i*2))&3)*2+0)<<(i*16+0);
|
||||
u64 |= ((uint64_t)((u8>>(i*2))&3)*2+1)<<(i*16+8);
|
||||
}
|
||||
MOV64x(x2, u64);
|
||||
}
|
||||
VMOVQDfrom(d0, 0, x2);
|
||||
VTBL1_8(d0, v1, d0);
|
||||
VMOVeD(v0, 0, d0, 0);
|
||||
}
|
||||
if(v0!=v1) {
|
||||
VMOVeD(v0, 1, v1, 1);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0x7C:
|
||||
INST_NAME("VHADDPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
}
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
// check if any input value was NAN
|
||||
VFMAXPQS(q0, v2, v1); // propagate NAN
|
||||
VFCMEQQS(q0, q0, q0); // 0 if NAN, 1 if not NAN
|
||||
}
|
||||
VFADDPQS(v0, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
VFCMEQQS(q1, v0, v0); // 0 => out is NAN
|
||||
VBICQ(q1, q0, q1); // forget it in any input was a NAN already
|
||||
VSHLQ_32(q1, q1, 31); // only keep the sign bit
|
||||
VORRQ(v0, v0, q1); // NAN -> -NAN
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x7D:
|
||||
INST_NAME("VHSUBPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
if(!BOX64ENV(dynarec_fastnan))
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_VXEX(v0, v2, v1, 0); } else { GETGY_empty_VYEY(v0, v2, v1); }
|
||||
VUZP1Q_32(q0, v2, v1);
|
||||
VUZP2Q_32(v0, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
// check if any input value was NAN
|
||||
// but need to mix low/high part
|
||||
VFMAXQS(q1, v0, q0); // propagate NAN
|
||||
VFCMEQQS(q1, q1, q1); // 0 if NAN, 1 if not NAN
|
||||
}
|
||||
VFSUBQS(v0, q0, v0);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
VFCMEQQS(q0, v0, v0); // 0 => out is NAN
|
||||
VBICQ(q1, q1, q0); // forget it in any input was a NAN already
|
||||
VSHLQ_32(q1, q1, 31); // only keep the sign bit
|
||||
VORRQ(v0, v0, q1); // NAN -> -NAN
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0xC2:
|
||||
INST_NAME("VCMPSD Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETEXSD(v1, 0, 1);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
u8 = F8;
|
||||
if(((u8&15)!=0x0b) && ((u8&15)!=0x0f)) {
|
||||
if((u8&15)>7)
|
||||
FCMPD(v1, v2);
|
||||
else
|
||||
FCMPD(v2, v1);
|
||||
}
|
||||
// TODO: create a test for this one, there might be an issue with cases 9, 10 and 13
|
||||
if(v0!=v2) VMOVQ(v0, v2);
|
||||
switch(u8&15) {
|
||||
case 0x00: CSETMx(x2, cEQ); break; // Equal
|
||||
case 0x01: CSETMx(x2, cCC); break; // Less than
|
||||
case 0x02: CSETMx(x2, cLS); break; // Less or equal
|
||||
case 0x03: CSETMx(x2, cVS); break; // NaN
|
||||
case 0x04: CSETMx(x2, cNE); break; // Not Equal or unordered
|
||||
case 0x05: CSETMx(x2, cCS); break; // Greater or equal or unordered
|
||||
case 0x06: CSETMx(x2, cHI); break; // Greater or unordered
|
||||
case 0x07: CSETMx(x2, cVC); break; // not NaN
|
||||
case 0x08: CSETMx(x2, cEQ); CSETMx(x3, cVS); ORRx_REG(x2, x2, x3); break; // Equal or unordered
|
||||
case 0x09: CSETMx(x2, cHI); break; // Less than or unordered
|
||||
case 0x0a: CSETMx(x2, cCS); break; // Less or equal or unordered
|
||||
case 0x0b: MOV32w(x2, 0); break; // false
|
||||
case 0x0c: CSETMw(x2, cNE); CSETMx(x3, cVS); BICx(x2, x2, x3); break; // Not Equal not unordered
|
||||
case 0x0d: CSETMw(x2, cLS); break; // Greater or equal not unordered
|
||||
case 0x0e: CSETMw(x2, cCC); break; // Greater not unordered
|
||||
case 0x0f: MOV64x(x2, 0xffffffffffffffffLL); break; // true
|
||||
}
|
||||
VMOVQDfrom(v0, 0, x2);
|
||||
YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0xD0:
|
||||
INST_NAME("VADDSUBPS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
static float addsubps[4] = {-1.f, 1.f, -1.f, 1.f};
|
||||
MAYUSE(addsubps);
|
||||
MOV64x(x2, (uintptr_t)&addsubps);
|
||||
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(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);
|
||||
} else {
|
||||
if(v0!=v2) VMOVQ(v0, v2);
|
||||
VFMLAQS(v0, v1, q0);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0xE6:
|
||||
INST_NAME("VCVTPD2DQ Gx, Ex");
|
||||
nextop = F8;
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x6);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) {
|
||||
GETEX_Y(v1, 0, 0);
|
||||
GETGX_empty(v0);
|
||||
if(!BOX64ENV(dynarec_fastround) || vex.l)
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
} else {
|
||||
GETEY(v1);
|
||||
}
|
||||
if(BOX64ENV(dynarec_fastround)) {
|
||||
VFRINTIDQ(l?d0:v0, v1);
|
||||
VFCVTNSQD(l?d0:v0, l?d0:v0); // convert double -> int64
|
||||
if(!l)
|
||||
SQXTN_32(v0, v0); // convert int64 -> int32 with saturation in lower part, RaZ high part
|
||||
else
|
||||
SQXTN2_32(v0, d0); // convert int64 -> int32 with saturation in higher part
|
||||
} else {
|
||||
if(arm64_frintts) {
|
||||
VFRINT32XDQ(l?d0:v0, v1); // round, handling of overflow and Nan to 0x80000000
|
||||
VFCVTNSQD(l?d0:v0, l?d0:v0); // convert double -> int64
|
||||
if(!l)
|
||||
SQXTN_32(v0, v0); // convert int64 -> int32 with saturation in lower part, RaZ high part
|
||||
else
|
||||
SQXTN2_32(v0, d0); // convert int64 -> int32 with saturation in higher part
|
||||
} else {
|
||||
if(!l) {
|
||||
MRS_fpsr(x5);
|
||||
ORRw_mask(x4, xZR, 1, 0); //0x80000000
|
||||
}
|
||||
for(int i=0; i<2; ++i) {
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
if(i) {
|
||||
VMOVeD(d0, 0, v1, i);
|
||||
FRINTID(d0, d0);
|
||||
} else {
|
||||
FRINTID(d0, v1);
|
||||
}
|
||||
FCVTZSwD(x1, d0);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TSTw_mask(x5, 0, 0); // mask = 1 = FPSR_IOC
|
||||
CSELx(x1, x1, x4, cEQ);
|
||||
VMOVQSfrom(v0, i+l*2, x1);
|
||||
}
|
||||
if(!vex.l && !l) VMOVQDfrom(v0, 1, xZR);
|
||||
}
|
||||
}
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0xF0:
|
||||
INST_NAME("VLDDQU Gx,Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VMOVQ(v0, v1);
|
||||
if(vex.l) {
|
||||
GETGY_empty_EY(v0, v1);
|
||||
VMOVQ(v0, v1);
|
||||
}
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
v1 = ymm_get_reg_empty(dyn, ninst, x1, gd, -1, -1, -1);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0x3f<<4, 15, rex, NULL, 1, 0);
|
||||
VLDP128_I7(v0, v1, ed, fixedaddress);
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
#include "my_cpuid.h"
|
||||
#include "emu/x87emu_private.h"
|
||||
#include "emu/x64shaext.h"
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "../dynarec_helper.h"
|
||||
|
||||
uintptr_t dynarec64_AVX_F2_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop, u8;
|
||||
uint8_t gd, ed, vd;
|
||||
uint8_t wback, wb1, wb2;
|
||||
uint8_t eb1, eb2, gb1, gb2;
|
||||
int32_t i32, i32_;
|
||||
int cacheupd = 0;
|
||||
int v0, v1, v2;
|
||||
int q0, q1, q2;
|
||||
int d0, d1, d2;
|
||||
int s0;
|
||||
uint64_t tmp64u;
|
||||
int64_t j64;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
MAYUSE(wb1);
|
||||
MAYUSE(wb2);
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
MAYUSE(gb1);
|
||||
MAYUSE(gb2);
|
||||
MAYUSE(q0);
|
||||
MAYUSE(q1);
|
||||
MAYUSE(d0);
|
||||
MAYUSE(d1);
|
||||
MAYUSE(s0);
|
||||
MAYUSE(j64);
|
||||
MAYUSE(cacheupd);
|
||||
|
||||
rex_t rex = vex.rex;
|
||||
|
||||
switch(opcode) {
|
||||
case 0xF5:
|
||||
INST_NAME("PDEP Gd, Ed, Vd");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED(0);
|
||||
GETVD;
|
||||
if(gd==ed || gd==vd) {
|
||||
gb1 = gd;
|
||||
gd = x4;
|
||||
} else {
|
||||
gb1 = 0;
|
||||
}
|
||||
// x3 = mask of mask, loop while not 0
|
||||
MOV32w(gd, 0);
|
||||
MOV64x(x2, 1);
|
||||
MOV64x(x3, 1);
|
||||
MARK;
|
||||
TSTxw_REG(ed, x3);
|
||||
B_MARK2(cEQ);
|
||||
TSTxw_REG(vd, x2);
|
||||
B_MARK3(cEQ);
|
||||
ORRxw_REG(gd, gd, x3);
|
||||
MARK3;
|
||||
LSLxw_IMM(x2, x2, 1);
|
||||
MARK2;
|
||||
LSLxw_IMM(x3, x3, 1);
|
||||
CBNZxw_MARK(x3);
|
||||
if(gb1)
|
||||
MOVxw_REG(gb1, gd);
|
||||
break;
|
||||
case 0xF6:
|
||||
INST_NAME("MULX Gd, Vd, Ed (,RDX)");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED(0);
|
||||
GETVD;
|
||||
if(rex.w) {
|
||||
// 64bits mul
|
||||
if((gd==xRDX) || (gd==ed) || (gd==vd))
|
||||
gb1 = x3;
|
||||
else
|
||||
gb1 = gd;
|
||||
UMULH(gb1, xRDX, ed);
|
||||
if(gd!=vd) {MULx(vd, xRDX, ed);}
|
||||
if(gb1==x3) {
|
||||
MOVx_REG(gd, gb1);
|
||||
}
|
||||
} else {
|
||||
// 32bits mul
|
||||
UMULL(x3, xRDX, ed);
|
||||
if(gd!=vd) {MOVw_REG(vd, x3);}
|
||||
LSRx(gd, x3, 32);
|
||||
}
|
||||
break;
|
||||
case 0xF7:
|
||||
INST_NAME("SHRX Gd, Ed, Vd");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED(0);
|
||||
GETVD;
|
||||
ANDx_mask(x3, vd, 1, 0, rex.w?5:4); // mask 0x3f/0x1f
|
||||
LSRxw_REG(gd, ed, x3);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
#include "my_cpuid.h"
|
||||
#include "emu/x87emu_private.h"
|
||||
#include "emu/x64shaext.h"
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "../dynarec_helper.h"
|
||||
|
||||
uintptr_t dynarec64_AVX_F2_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop, u8;
|
||||
uint8_t gd, ed, vd;
|
||||
uint8_t wback, wb1, wb2;
|
||||
uint8_t eb1, eb2, gb1, gb2;
|
||||
int32_t i32, i32_;
|
||||
int cacheupd = 0;
|
||||
int v0, v1, v2;
|
||||
int q0, q1, q2;
|
||||
int d0, d1, d2;
|
||||
int s0;
|
||||
uint64_t tmp64u;
|
||||
int64_t j64;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
MAYUSE(wb1);
|
||||
MAYUSE(wb2);
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
MAYUSE(gb1);
|
||||
MAYUSE(gb2);
|
||||
MAYUSE(q0);
|
||||
MAYUSE(q1);
|
||||
MAYUSE(d0);
|
||||
MAYUSE(d1);
|
||||
MAYUSE(s0);
|
||||
MAYUSE(j64);
|
||||
MAYUSE(cacheupd);
|
||||
|
||||
rex_t rex = vex.rex;
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0xF0:
|
||||
INST_NAME("RORX Gd, Ed, Ib");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED(1);
|
||||
u8 = F8;
|
||||
u8&=rex.w?0x3f:0x1f;
|
||||
RORxw(gd, ed, u8);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,618 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
#include "my_cpuid.h"
|
||||
#include "emu/x87emu_private.h"
|
||||
#include "emu/x64shaext.h"
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "../dynarec_helper.h"
|
||||
|
||||
uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop, u8;
|
||||
uint8_t gd, ed, vd;
|
||||
uint8_t wback, wb1, wb2;
|
||||
uint8_t eb1, eb2, gb1, gb2;
|
||||
int32_t i32, i32_;
|
||||
int cacheupd = 0;
|
||||
int v0, v1, v2;
|
||||
int q0, q1, q2;
|
||||
int d0, d1, d2;
|
||||
int s0;
|
||||
uint64_t tmp64u, u64;
|
||||
int64_t j64;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
MAYUSE(wb1);
|
||||
MAYUSE(wb2);
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
MAYUSE(gb1);
|
||||
MAYUSE(gb2);
|
||||
MAYUSE(q0);
|
||||
MAYUSE(q1);
|
||||
MAYUSE(d0);
|
||||
MAYUSE(d1);
|
||||
MAYUSE(s0);
|
||||
MAYUSE(j64);
|
||||
MAYUSE(cacheupd);
|
||||
|
||||
rex_t rex = vex.rex;
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0x10:
|
||||
INST_NAME("VMOVSS Gx, Ex [,Vx]");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
GETGX_empty_VXEX(v0, v2, v1, 0);
|
||||
if((v0!=v2) && (v0!=v1)) VMOVQ(v0, v2);
|
||||
if(v0!=v1) VMOVeS(v0, 0, v1, 0);
|
||||
if((v0!=v2) && (v0==v1)) { VMOVeS(v0, 1, v2, 1); VMOVeD(v0, 1, v2, 1);}
|
||||
} else {
|
||||
GETGX_empty(v0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v0, ed, fixedaddress);
|
||||
}
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x11:
|
||||
INST_NAME("VMOVSS Ex, Gx [,Vx]");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
GETGXVXEX_empty(v0, v2, v1, 0);
|
||||
if((v2!=v1) && (v2!=v0)) VMOVQ(v2, v1);
|
||||
if(v2!=v0) VMOVeS(v2, 0, v0, 0);
|
||||
if((v2!=v1) && (v2==v0)) { VMOVeS(v2, 1, v0, 1); VMOVeD(v2, 1, v0, 1);}
|
||||
YMM0((nextop&7)+(rex.b<<3));
|
||||
} else {
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VST32(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x12:
|
||||
INST_NAME("VMOVSLDUP Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX_Y(q1, 0, 0);
|
||||
GETGX_empty(q0);
|
||||
VTRNQ1_32(q0, q1, q1);
|
||||
if(vex.l) {
|
||||
GETGY_empty_EY(q0, q1);
|
||||
VTRNQ1_32(q0, q1, q1);
|
||||
} else YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0x16:
|
||||
INST_NAME("VMOVSHDUP Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX_Y(q1, 0, 0);
|
||||
GETGX_empty(q0);
|
||||
VTRNQ2_32(q0, q1, q1);
|
||||
if(vex.l) {
|
||||
GETGY_empty_EY(q0, q1);
|
||||
VTRNQ2_32(q0, q1, q1);
|
||||
} else YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0x2A:
|
||||
INST_NAME("VCVTSI2SS Gx, Vx, Ed");
|
||||
nextop = F8;
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
GETGX_empty_VX(v0, v1);
|
||||
GETED(0);
|
||||
if(BOX64ENV(dynarec_fastround)<2) {
|
||||
u8 = sse_setround(dyn, ninst, x3, x4, x5);
|
||||
}
|
||||
if(rex.w) {
|
||||
SCVTFSx(d1, ed);
|
||||
} else {
|
||||
SCVTFSw(d1, ed);
|
||||
}
|
||||
if(BOX64ENV(dynarec_fastround)<2) {
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
}
|
||||
if(v0!=v1) VMOVQ(v0, v1);
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0x2C:
|
||||
INST_NAME("VCVTTSS2SI Gd, Ex");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEXSS(d0, 0, 0);
|
||||
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
}
|
||||
if(!BOX64ENV(dynarec_fastround) && arm64_frintts) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
if(rex.w) {
|
||||
FRINT64ZS(v0, d0);
|
||||
} else {
|
||||
FRINT32ZS(v0, d0);
|
||||
}
|
||||
FCVTZSxwS(gd, v0);
|
||||
} else {
|
||||
FCVTZSxwS(gd, d0);
|
||||
}
|
||||
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_NEXT(x5, FPSR_IOC);
|
||||
if(rex.w) {
|
||||
ORRx_mask(gd, xZR, 1, 1, 0); //0x8000000000000000
|
||||
} else {
|
||||
ORRw_mask(gd, xZR, 1, 0); //0x80000000
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x2D:
|
||||
INST_NAME("VCVTSS2SI Gd, Ex");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEXSS(q0, 0, 0);
|
||||
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
}
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x3);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
if(!BOX64ENV(dynarec_fastround) && arm64_frintts) {
|
||||
if(rex.w) {
|
||||
FRINT64XS(d1, q0);
|
||||
} else {
|
||||
FRINT32XS(d1, q0);
|
||||
}
|
||||
} else {
|
||||
FRINTIS(d1, q0);
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
FCVTZSxwS(gd, d1);
|
||||
if(!BOX64ENV(dynarec_fastround) && !arm64_frintts) {
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ_NEXT(x5, FPSR_IOC);
|
||||
if(rex.w) {
|
||||
ORRx_mask(gd, xZR, 1, 1, 0); //0x8000000000000000
|
||||
} else {
|
||||
ORRw_mask(gd, xZR, 1, 0); //0x80000000
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x51:
|
||||
INST_NAME("VSQRTSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEXSS(d0, 0, 0);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
FCMEQS(q0, v1, v1); // 0 if NAN, 1 if not NAN
|
||||
}
|
||||
FSQRTS(d1, d0);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
FCMEQS(q1, d1, d1); // 0 => out is NAN
|
||||
VBIC(q1, q0, q1); // forget it in any input was a NAN already
|
||||
VSHL_32(q1, q1, 31); // only keep the sign bit
|
||||
VORR(d1, d1, q1); // NAN -> -NAN
|
||||
}
|
||||
if(v0!=v2) VMOVQ(v0, v2);
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x52:
|
||||
INST_NAME("VRSQRTSS Gx, Vx Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETVX(v2, 0);
|
||||
GETEXSS(v1, 0, 0);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
// so here: F32: Imm8 = abcd efgh that gives => aBbbbbbc defgh000 00000000 00000000
|
||||
// and want 1.0f = 0x3f800000
|
||||
// so 00111111 10000000 00000000 00000000
|
||||
// a = 0, b = 1, c = 1, d = 1, efgh=0
|
||||
// 0b01110000
|
||||
FMOVS_8(d0, 0b01110000);
|
||||
FSQRTS(d1, v1);
|
||||
FDIVS(d0, d0, d1);
|
||||
if(v0!=v2) {
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeS(v0, 0, d0, 0);
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x53:
|
||||
INST_NAME("VRCPSS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETVX(v2, 0);
|
||||
GETEXSS(v1, 0, 0);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
FMOVS_8(d0, 0b01110000); //1.0f
|
||||
FDIVS(d0, d0, v1);
|
||||
if(v0!=v2) {
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeS(v0, 0, d0, 0);
|
||||
YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0x58:
|
||||
INST_NAME("VADDSS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
q2 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSS(v1, 0, 0);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
FMAXS(q1, v0, v1); // propagate NAN
|
||||
FCMEQS(q1, q1, q1); // 0 if NAN, 1 if not NAN
|
||||
FADDS(q2, v1, v2); // the high part of the vector is erased...
|
||||
FCMEQS(q0, q2, q2); // 0 => out is NAN
|
||||
VBIC(q0, q1, q0); // forget it in any input was a NAN already
|
||||
VSHL_32(q0, q0, 31); // only keep the sign bit
|
||||
VORR(q2, q2, q0); // NAN -> -NAN
|
||||
} else {
|
||||
FADDS(q2, v1, v2); // the high part of the vector is erased...
|
||||
}
|
||||
if(v0!=v2) {
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeS(v0, 0, q2, 0);
|
||||
YMM0(gd)
|
||||
break;
|
||||
case 0x59:
|
||||
INST_NAME("VMULSS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
q2 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSS(v1, 0, 0);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
FMAXS(q1, v0, v1); // propagate NAN
|
||||
FCMEQS(q1, q1, q1); // 0 if NAN, 1 if not NAN
|
||||
FMULS(q2, v1, v2); // the high part of the vector is erased...
|
||||
FCMEQS(q0, q2, q2); // 0 => out is NAN
|
||||
VBIC(q0, q1, q0); // forget it in any input was a NAN already
|
||||
VSHL_32(q0, q0, 31); // only keep the sign bit
|
||||
VORR(q2, q2, q0); // NAN -> -NAN
|
||||
} else {
|
||||
FMULS(q2, v1, v2); // the high part of the vector is erased...
|
||||
}
|
||||
if(v0!=v2) {
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeS(v0, 0, q2, 0);
|
||||
YMM0(gd)
|
||||
break;
|
||||
case 0x5A:
|
||||
INST_NAME("VCVTSS2SD Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSS(v1, 0, 0);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
FCVT_D_S(d1, v1);
|
||||
VMOVeD(v0, 0, d1, 0);
|
||||
if(v0!=v2)
|
||||
VMOVeD(v0, 1, v2, 1);
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x5B:
|
||||
INST_NAME("VCVTTPS2DQ Gx, Ex");
|
||||
nextop = F8;
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
if(!BOX64ENV(dynarec_fastround)) {
|
||||
MRS_fpsr(x5);
|
||||
ORRw_mask(x4, xZR, 1, 0); //0x80000000
|
||||
}
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_EX(v0, v1, 0); } else { GETGY_empty_EY(v0, v1); }
|
||||
if(BOX64ENV(dynarec_fastround)) {
|
||||
VFCVTZSQS(v0, v1);
|
||||
} else {
|
||||
if(arm64_frintts) {
|
||||
VFRINT32ZSQ(v0, v1);
|
||||
VFCVTZSQS(v0, v0);
|
||||
} else {
|
||||
for(int i=0; i<4; ++i) {
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
if(i) {
|
||||
VMOVeS(d0, 0, v1, i);
|
||||
VFCVTZSs(d0, d0);
|
||||
} else {
|
||||
VFCVTZSs(d0, v1);
|
||||
}
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ(x5, FPSR_IOC, 4+4);
|
||||
VMOVQSfrom(d0, 0, x4);
|
||||
VMOVeS(v0, i, d0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x5C:
|
||||
INST_NAME("VSUBSS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
q2 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSS(v1, 0, 0);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
FMAXS(q1, v0, v1); // propagate NAN
|
||||
FCMEQS(q1, q1, q1); // 0 if NAN, 1 if not NAN
|
||||
FSUBS(q2, v2, v1); // the high part of the vector is erased...
|
||||
FCMEQS(q0, q2, q2); // 0 => out is NAN
|
||||
VBIC(q0, q1, q0); // forget it in any input was a NAN already
|
||||
VSHL_32(q0, q0, 31); // only keep the sign bit
|
||||
VORR(q2, q2, q0); // NAN -> -NAN
|
||||
} else {
|
||||
FSUBS(q2, v2, v1); // the high part of the vector is erased...
|
||||
}
|
||||
if(v0!=v2) {
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeS(v0, 0, q2, 0);
|
||||
YMM0(gd)
|
||||
break;
|
||||
case 0x5D:
|
||||
INST_NAME("VMINSS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSS(v1, 0, 0);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
FCMPS(v2, v1);
|
||||
FCSELS(d1, v1, v2, cCS); //CS: NAN or == or Ex > Vx
|
||||
if(v0!=v2) {
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeS(v0, 0, d1, 0); // to not erase uper part
|
||||
YMM0(gd)
|
||||
break;
|
||||
case 0x5E:
|
||||
INST_NAME("VDIVSS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
q2 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSS(v1, 0, 0);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
FMAXS(q1, v0, v1); // propagate NAN
|
||||
FCMEQS(q1, q1, q1); // 0 if NAN, 1 if not NAN
|
||||
FDIVS(q2, v2, v1); // the high part of the vector is erased...
|
||||
FCMEQS(q0, q2, q2); // 0 => out is NAN
|
||||
VBIC(q0, q1, q0); // forget it in any input was a NAN already
|
||||
VSHL_32(q0, q0, 31); // only keep the sign bit
|
||||
VORR(q2, q2, q0); // NAN -> -NAN
|
||||
} else {
|
||||
FDIVS(q2, v2, v1); // the high part of the vector is erased...
|
||||
}
|
||||
if(v0!=v2) {
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeS(v0, 0, q2, 0);
|
||||
YMM0(gd)
|
||||
break;
|
||||
case 0x5F:
|
||||
INST_NAME("VMAXSS Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSS(v1, 0, 0);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
FCMPS(v1, v2);
|
||||
FCSELS(d1, v1, v2, cCS); //CS: NAN or == or Ex > Vx
|
||||
if(v0!=v2) {
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeS(v0, 0, d1, 0); // to not erase uper part
|
||||
YMM0(gd)
|
||||
break;
|
||||
|
||||
case 0x6F:
|
||||
INST_NAME("VMOVDQU Gx, Ex");// no alignment constraint on NEON here, so same as MOVDQA
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
GETGX_empty_EX(v0, v1, 0);
|
||||
VMOVQ(v0, v1);
|
||||
if(vex.l) {
|
||||
GETGY_empty_EY(v0, v1);
|
||||
VMOVQ(v0, v1);
|
||||
}
|
||||
} else {
|
||||
GETGX_empty(v0);
|
||||
SMREAD();
|
||||
if(vex.l) {
|
||||
GETGY_empty(v1, -1, -1, -1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0x3f<<4, 15, rex, NULL, 1, 0);
|
||||
VLDP128_I7(v0, v1, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VLD128(v0, ed, fixedaddress);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x70:
|
||||
INST_NAME("VPSHUFHW Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETEX_Y(v1, 0, 1); GETGX(v0, 1); u8 = F8; } else { GETGY(v0, 1, MODREG?((nextop&7)+(rex.b<<3)):-1, -1, -1); GETEY(v1); }
|
||||
if(u8==0b00000000 || u8==0b01010101 || u8==0b10101010 || u8==0b11111111) {
|
||||
VDUP_16(d0, v1, 4+(u8&3));
|
||||
} else {
|
||||
// only high part need to be suffled. VTBL only handle 8bits value, so the 16bits suffles need to be changed in 8bits
|
||||
if(!l) {
|
||||
u64 = 0;
|
||||
for (int i=0; i<4; ++i) {
|
||||
u64 |= ((uint64_t)((u8>>(i*2))&3)*2+8)<<(i*16+0);
|
||||
u64 |= ((uint64_t)((u8>>(i*2))&3)*2+9)<<(i*16+8);
|
||||
}
|
||||
MOV64x(x2, u64);
|
||||
}
|
||||
VMOVQDfrom(d0, 0, x2);
|
||||
VTBL1_8(d0, v1, d0);
|
||||
}
|
||||
VMOVeD(v0, 1, d0, 0);
|
||||
if(v0!=v1) {
|
||||
VMOVeD(v0, 0, v1, 0);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0x7E:
|
||||
INST_NAME("VMOVQ Gx, Ex");
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3), 0);
|
||||
GETGX_empty(v0);
|
||||
FMOVD(v0, v1);
|
||||
} else {
|
||||
GETGX_empty(v0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v0, ed, fixedaddress);
|
||||
}
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x7F:
|
||||
INST_NAME("VMOVDQU Ex, Gx");
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
if(MODREG) {
|
||||
ed = (nextop&7) + (rex.b<<3);
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, ed);
|
||||
VMOVQ(v1, v0);
|
||||
if(vex.l) {
|
||||
GETGY(v0, 0, ed, -1, -1);
|
||||
v1 = ymm_get_reg_empty(dyn, ninst, x1, ed, gd, -1, -1);
|
||||
VMOVQ(v1, v0);
|
||||
} else YMM0(ed);
|
||||
} else {
|
||||
IF_UNALIGNED(ip) {
|
||||
MESSAGE(LOG_DEBUG, "\tUnaligned path");
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
for(int i=0; i<16; ++i) {
|
||||
VST1_8(v0, i, i?x1:wback);
|
||||
ADDx_U12(x1, i?x1:wback, 1);
|
||||
}
|
||||
if(vex.l) {
|
||||
GETGY(v0, 0, -1, -1, -1);
|
||||
for(int i=0; i<16; ++i) {
|
||||
VST1_8(v0, i, x1);
|
||||
ADDx_U12(x1, x1, 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
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);
|
||||
VSTP128_I7(v0, v1, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VST128(v0, ed, fixedaddress);
|
||||
}
|
||||
}
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC2:
|
||||
INST_NAME("VCMPSS Gx, Vx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETEXSS(v1, 0, 1);
|
||||
GETGX_empty_VX(v0, v2);
|
||||
u8 = F8;
|
||||
if(((u8&15)!=11) && ((u8&15)!=15)) {
|
||||
if((u8&15)>7)
|
||||
FCMPS(v1, v2);
|
||||
else
|
||||
FCMPS(v2, v1);
|
||||
}
|
||||
// TODO: create a test for this one, there might be an issue with cases 9, 10 and 13
|
||||
if(v0!=v2) VMOVQ(v0, v2);
|
||||
switch(u8&15) {
|
||||
case 0x00: CSETMw(x2, cEQ); break; // Equal
|
||||
case 0x01: CSETMw(x2, cCC); break; // Less than
|
||||
case 0x02: CSETMw(x2, cLS); break; // Less or equal
|
||||
case 0x03: CSETMw(x2, cVS); break; // NaN
|
||||
case 0x04: CSETMw(x2, cNE); break; // Not Equal or unordered
|
||||
case 0x05: CSETMw(x2, cCS); break; // Greater or equal or unordered
|
||||
case 0x06: CSETMw(x2, cHI); break; // Greater or unordered
|
||||
case 0x07: CSETMw(x2, cVC); break; // not NaN
|
||||
case 0x08: CSETMw(x2, cEQ); CSETMw(x3, cVS); ORRw_REG(x2, x2, x3); break; // Equal or unordered
|
||||
case 0x09: CSETMw(x2, cHI); break; // Less than or unordered
|
||||
case 0x0a: CSETMw(x2, cCS); break; // Less or equal or unordered
|
||||
case 0x0b: MOV32w(x2, 0); break; // false
|
||||
case 0x0c: CSETMw(x2, cNE); CSETMw(x3, cVS); BICw(x2, x2, x3); break; // Not Equal not unordered
|
||||
case 0x0d: CSETMw(x2, cLS); break; // Greater or equal not unordered
|
||||
case 0x0e: CSETMw(x2, cCC); break; // Greater not unordered
|
||||
case 0x0f: MOV32w(x2, 0xffffffff); break; // true
|
||||
}
|
||||
VMOVQSfrom(v0, 0, x2);
|
||||
YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0xE6:
|
||||
INST_NAME("VCVTDQ2PD Gx, Ex");
|
||||
nextop = F8;
|
||||
if(vex.l) {
|
||||
GETEX_Y(v1, 0, 0);
|
||||
} else {
|
||||
GETEXSD(v1, 0, 0);
|
||||
}
|
||||
GETGX_empty(v0);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
if(vex.l) {
|
||||
q0 = ymm_get_reg_empty(dyn, ninst, x1, gd, -1, -1, -1);
|
||||
SXTL2_32(q0, v1);
|
||||
SCVTQFD(q0, q0);
|
||||
} else YMM0(gd);
|
||||
SXTL_32(v0, v1);
|
||||
SCVTQFD(v0, v0);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64trace.h"
|
||||
#include "dynarec_native.h"
|
||||
#include "my_cpuid.h"
|
||||
#include "emu/x87emu_private.h"
|
||||
#include "emu/x64shaext.h"
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "../dynarec_helper.h"
|
||||
|
||||
uintptr_t dynarec64_AVX_F3_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop, u8;
|
||||
uint8_t gd, ed, vd;
|
||||
uint8_t wback, wb1, wb2;
|
||||
uint8_t eb1, eb2, gb1, gb2;
|
||||
int32_t i32, i32_;
|
||||
int cacheupd = 0;
|
||||
int v0, v1, v2;
|
||||
int q0, q1, q2;
|
||||
int d0, d1, d2;
|
||||
int s0;
|
||||
uint64_t tmp64u;
|
||||
int64_t j64;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
MAYUSE(wb1);
|
||||
MAYUSE(wb2);
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
MAYUSE(gb1);
|
||||
MAYUSE(gb2);
|
||||
MAYUSE(q0);
|
||||
MAYUSE(q1);
|
||||
MAYUSE(d0);
|
||||
MAYUSE(d1);
|
||||
MAYUSE(s0);
|
||||
MAYUSE(j64);
|
||||
MAYUSE(cacheupd);
|
||||
|
||||
rex_t rex = vex.rex;
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0xF5:
|
||||
INST_NAME("PEXT Gd, Ed, Vd");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED(0);
|
||||
GETVD;
|
||||
if(gd==ed || gd==vd) {
|
||||
gb1 = gd;
|
||||
gd = x4;
|
||||
} else {
|
||||
gb1 = 0;
|
||||
}
|
||||
// x3 = mask of mask, loop while not 0
|
||||
MOV32w(gd, 0);
|
||||
MOV64x(x3, 1LL<<(rex.w?63:31));
|
||||
MARK;
|
||||
TSTxw_REG(ed, x3);
|
||||
B_MARK2(cEQ); // mask not set
|
||||
TSTxw_REG(vd, x3);
|
||||
CSINCxw(gd, gd, gd, cEQ); // return gd if TRUE, else gd+1
|
||||
RORxw(gd, gd, 1);
|
||||
MARK2;
|
||||
LSRxw_IMM(x3, x3, 1);
|
||||
CBNZxw_MARK(x3);
|
||||
RBITxw(gd, gd);
|
||||
if(gb1)
|
||||
MOVxw_REG(gb1, gd);
|
||||
break;
|
||||
|
||||
case 0xF7:
|
||||
INST_NAME("SARX Gd, Ed, Vd");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED(0);
|
||||
GETVD;
|
||||
ANDx_mask(x3, vd, 1, 0, rex.w?5:4); // mask 0x3f/0x1f
|
||||
ASRxw_REG(gd, ed, x3);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -5,10 +5,8 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
@@ -19,7 +17,7 @@
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "../dynarec_helper.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
|
||||
|
||||
@@ -29,6 +27,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
|
||||
uint8_t nextop = F8;
|
||||
uint8_t ed;
|
||||
uint8_t u8;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
int v1, v2;
|
||||
@@ -38,6 +37,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
|
||||
if(MODREG)
|
||||
switch(nextop) {
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
@@ -50,11 +50,16 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FADD ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
FADDS(v1, v1, v2);
|
||||
} else {
|
||||
FADDD(v1, v1, v2);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
@@ -67,11 +72,16 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FMUL ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
FMULS(v1, v1, v2);
|
||||
} else {
|
||||
FMULD(v1, v1, v2);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
@@ -121,11 +131,16 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FSUB ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
FSUBS(v1, v1, v2);
|
||||
} else {
|
||||
FSUBD(v1, v1, v2);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 0xE8:
|
||||
case 0xE9:
|
||||
@@ -138,11 +153,16 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FSUBR ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
FSUBS(v1, v2, v1);
|
||||
} else {
|
||||
FSUBD(v1, v2, v1);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
@@ -155,11 +175,16 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FDIV ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
FDIVS(v1, v1, v2);
|
||||
} else {
|
||||
FDIVD(v1, v1, v2);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 0xF8:
|
||||
case 0xF9:
|
||||
@@ -172,125 +197,161 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("FDIVR ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
FDIVS(v1, v2, v1);
|
||||
} else {
|
||||
FDIVD(v1, v2, v1);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FADD ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
FADDS(v1, v1, s0);
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
FADDD(v1, v1, s0);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FMUL ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
FMULS(v1, v1, s0);
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
FMULD(v1, v1, s0);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FCOM ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
FCMPS(v1, s0);
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
FCMPD(v1, s0);
|
||||
}
|
||||
FCOM(x1, x2, x3);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FCOMP ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
FCMPS(v1, s0);
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
FCMPD(v1, s0);
|
||||
}
|
||||
FCOM(x1, x2, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FSUB ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
FSUBS(v1, v1, s0);
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
FSUBD(v1, v1, s0);
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FSUBR ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
FSUBS(v1, s0, v1);
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
FSUBD(v1, s0, v1);
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FDIV ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
FDIVS(v1, v1, s0);
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
FDIVD(v1, v1, s0);
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FDIVR ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
FDIVS(v1, s0, v1);
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
FDIVD(v1, s0, v1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
}
|
||||
DEFAULT;
|
||||
break;
|
||||
} else
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FADD ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
FADDS(v1, v1, s0);
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
FADDD(v1, v1, s0);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FMUL ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
FMULS(v1, v1, s0);
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
FMULD(v1, v1, s0);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FCOM ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
FCMPS(v1, s0);
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
FCMPD(v1, s0);
|
||||
}
|
||||
FCOM(x1, x2, x3);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FCOMP ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
FCMPS(v1, s0);
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
FCMPD(v1, s0);
|
||||
}
|
||||
FCOM(x1, x2, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FSUB ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
FSUBS(v1, v1, s0);
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
FSUBD(v1, v1, s0);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FSUBR ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
FSUBS(v1, s0, v1);
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
FSUBD(v1, s0, v1);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FDIV ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
FDIVS(v1, v1, s0);
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
FDIVD(v1, v1, s0);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FDIVR ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
FDIVS(v1, s0, v1);
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
FDIVD(v1, s0, v1);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -5,10 +5,8 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
@@ -19,7 +17,7 @@
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "../dynarec_helper.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
|
||||
|
||||
@@ -31,7 +29,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
uint8_t ed;
|
||||
uint8_t wback, wb1;
|
||||
uint8_t u8;
|
||||
int64_t fixedaddress;
|
||||
int64_t fixedaddress, j64;
|
||||
int unscaled;
|
||||
int v1, v2;
|
||||
int s0;
|
||||
@@ -41,6 +39,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
|
||||
if(MODREG)
|
||||
switch(nextop) {
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
@@ -131,18 +130,109 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0xE5:
|
||||
INST_NAME("FXAM");
|
||||
#if 1
|
||||
i1 = x87_get_current_cache(dyn, ninst, 0, NEON_CACHE_ST_D);
|
||||
// value put in x14
|
||||
if(i1==-1) {
|
||||
if(fpu_is_st_freed(dyn, ninst, 0)) {
|
||||
MOV32w(x4, 0b100000100000000);
|
||||
B_MARK3_nocond;
|
||||
} else {
|
||||
// not in cache, so check Empty status and load it
|
||||
i2 = -dyn->n.x87stack;
|
||||
LDRw_U12(x3, xEmu, offsetof(x64emu_t, fpu_stack));
|
||||
if(i2) {
|
||||
if(i2<0) {
|
||||
ADDw_U12(x3, x3, -i2);
|
||||
} else {
|
||||
SUBw_U12(x3, x3, i2);
|
||||
}
|
||||
}
|
||||
CMPSw_U12(x3, 0);
|
||||
MOV32w(x4, 0b100000100000000); // empty: C3,C2,C0 = 101
|
||||
B_MARK3(cLE);
|
||||
// x5 will be the actual top
|
||||
LDRw_U12(x5, xEmu, offsetof(x64emu_t, top));
|
||||
if(i2) {
|
||||
if(i2<0) {
|
||||
SUBw_U12(x5, x5, -i2);
|
||||
} else {
|
||||
ADDw_U12(x5, x5, i2);
|
||||
}
|
||||
ANDw_mask(x5, x5, 0, 2); // (emu->top + i)&7
|
||||
}
|
||||
// load x2 with ST0 anyway, for sign extraction
|
||||
ADDx_REG_LSL(x1, xEmu, x5, 3);
|
||||
LDRx_U12(x2, x1, offsetof(x64emu_t, x87));
|
||||
// load tag
|
||||
if(i2>=0) {
|
||||
LDRH_U12(x3, xEmu, offsetof(x64emu_t, fpu_tags));
|
||||
if(i2>0) {
|
||||
ORRw_mask(x3, x3, 0b010000, 0b001111); // 0xffff0000
|
||||
LSRw_IMM(x3, x3, i2*2);
|
||||
}
|
||||
TSTw_mask(x3, 0, 1); // 0b11
|
||||
B_MARK3(cNE); // empty: C3,C2,C0 = 101
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// simply move from cache reg to x2
|
||||
v1 = dyn->n.x87reg[i1];
|
||||
VMOVQDto(x2, v1, 0);
|
||||
}
|
||||
// get exponant in x1
|
||||
LSRx_IMM(x1, x2, 20+32);
|
||||
ANDSx_mask(x1, x1, 1, 0b00000, 0b001010); // 0x7ff
|
||||
B_MARK(cNE); // not zero or denormal
|
||||
ANDSx_mask(x1, x2, 1, 0, 0b111110); // 0x7fffffffffffffff
|
||||
MOV32w(x4, 0b100000000000000); // Zero: C3,C2,C0 = 100
|
||||
MOV32w(x5, 0b100010000000000); // Denormal: C3,C2,C0 = 110
|
||||
CSELx(x4, x4, x5, cEQ);
|
||||
B_MARK3(c__);
|
||||
MARK;
|
||||
CMPSx_U12(x1, 0x7ff); // infinite/NaN?
|
||||
MOV32w(x5, 0b000010000000000); // normal: C3,C2,C0 = 010
|
||||
CSELx(x4, x5, x4, cNE);
|
||||
B_MARK3(cNE);
|
||||
TSTx_mask(x2, 1, 0b000000, 0b110011); // 0x000fffffffffffff
|
||||
MOV32w(x4, 0b000010100000000); // infinity: C3,C2,C0 = 011
|
||||
MOV32w(x3, 0b000000100000000); // NaN: C3,C2,C0 = 001
|
||||
CSELx(x4, x4, x3, cEQ);
|
||||
MARK3;
|
||||
// Extract signa & Update SW
|
||||
LSRx_IMM(x1, x2, 63);
|
||||
BFIx(x4, x1, 9, 1); //C1
|
||||
LDRH_U12(x1, xEmu, offsetof(x64emu_t, sw));
|
||||
MOV32w(x2, 0b01000111);
|
||||
BICw_REG_LSL(x1, x1, x2, 8);
|
||||
ORRw_REG(x4, x4, x1);
|
||||
STRH_U12(x4, xEmu, offsetof(x64emu_t, sw));
|
||||
#else
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_refresh(dyn, ninst, x1, x2, 0);
|
||||
i1 = x87_stackcount(dyn, ninst, x1);
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
CALL(fpu_fxam, -1); // should be possible inline, but is it worth it?
|
||||
x87_unstackcount(dyn, ninst, x1, i1);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 0xE8:
|
||||
INST_NAME("FLD1");
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0)) {
|
||||
FMOVS_8(v1, 0b01110000);
|
||||
if(ninst<dyn->size+2 && (dyn->insts[ninst+1].pred_sz==1) && (dyn->insts[ninst+2].pred_sz==1)
|
||||
&& PK(0)==0xD9 && PK(1)==0xE8
|
||||
&& PK(2)==0xD9 && PK(3)==0xF3
|
||||
) {
|
||||
MESSAGE(LOG_DUMP, "Hack for FLD1 FLD1 FPATAN");
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
FTABLE64(v1, PI/4.0);
|
||||
addr+=4;
|
||||
} else {
|
||||
FMOVD_8(v1, 0b01110000);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0)) {
|
||||
FMOVS_8(v1, 0b01110000);
|
||||
} else {
|
||||
FMOVD_8(v1, 0b01110000);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xE9:
|
||||
@@ -178,7 +268,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
|
||||
case 0xF0:
|
||||
INST_NAME("F2XM1");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (F2XM1)\n");
|
||||
i1 = x87_stackcount(dyn, ninst, x1);
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
CALL(native_f2xm1, -1);
|
||||
@@ -186,7 +276,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0xF1:
|
||||
INST_NAME("FYL2X");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (FYL2X)\n");
|
||||
i1 = x87_stackcount(dyn, ninst, x1);
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
@@ -196,13 +286,17 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0xF2:
|
||||
INST_NAME("FPTAN");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (FPTAN)\n");
|
||||
i1 = x87_stackcount(dyn, ninst, x1);
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
CALL(native_ftan, -1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
CALL_(native_ftan, -1, BOX64ENV(dynarec_fastround) ? 0 : u8);
|
||||
x87_unstackcount(dyn, ninst, x1, i1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
if(PK(0)==0xdd && PK(1)==0xd8) {
|
||||
MESSAGE(LOG_DUMP, "Optimized next DD D8 fstp st0, st0, not emiting 1\n");
|
||||
MESSAGE(LOG_DUMP, "Optimized next DD D8 fstp st0, st0, not emitting 1\n");
|
||||
u8 = F8;
|
||||
u8 = F8;
|
||||
} else {
|
||||
@@ -216,17 +310,21 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0xF3:
|
||||
INST_NAME("FPATAN");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (FPATAN)\n");
|
||||
i1 = x87_stackcount(dyn, ninst, x1);
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(native_fpatan, -1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
CALL_(native_fpatan, -1, BOX64ENV(dynarec_fastround) ? 0 : u8);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
x87_unstackcount(dyn, ninst, x1, i1);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xF4:
|
||||
INST_NAME("FXTRACT");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (FXTRACT)\n");
|
||||
X87_PUSH_EMPTY_OR_FAIL(dyn, ninst, 0);
|
||||
i1 = x87_stackcount(dyn, ninst, x1);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
@@ -235,8 +333,8 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0xF5:
|
||||
INST_NAME("FPREM1");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
#if 0
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
i1 = x87_stackcount(dyn, ninst, x1);
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
@@ -245,7 +343,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
#else
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 1, NEON_CACHE_ST_D);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
FDIVD(s0, v1, v2);
|
||||
FRINTRRD(s0, s0, 0b00); // Nearest == TieToEven?
|
||||
FCVTZSxD(x4, s0);
|
||||
@@ -293,7 +391,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
#else
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 1, NEON_CACHE_ST_D);
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
FDIVD(s0, v1, v2);
|
||||
FRINTZD(s0, s0);
|
||||
FCVTZSxD(x4, s0);
|
||||
@@ -315,7 +413,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0xF9:
|
||||
INST_NAME("FYL2XP1");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (FYL2XP1)\n");
|
||||
i1 = x87_stackcount(dyn, ninst, x1);
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
@@ -326,19 +424,28 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0xFA:
|
||||
INST_NAME("FSQRT");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
FSQRTS(v1, v1);
|
||||
} else {
|
||||
FSQRTD(v1, v1);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 0xFB:
|
||||
INST_NAME("FSINCOS");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (FSINCOS)\n");
|
||||
X87_PUSH_EMPTY_OR_FAIL(dyn, ninst, 0);
|
||||
i1 = x87_stackcount(dyn, ninst, x1);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(native_fsincos, -1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
CALL_(native_fsincos, -1, BOX64ENV(dynarec_fastround) ? 0 : u8);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
x87_unstackcount(dyn, ninst, x1, i1);
|
||||
break;
|
||||
case 0xFC:
|
||||
@@ -361,115 +468,125 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0xFD:
|
||||
INST_NAME("FSCALE");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (FSCALE)\n");
|
||||
i1 = x87_stackcount(dyn, ninst, x1);
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(native_fscale, -1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
CALL_(native_fscale, -1, BOX64ENV(dynarec_fastround) ? 0 : u8);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
x87_unstackcount(dyn, ninst, x1, i1);
|
||||
break;
|
||||
case 0xFE:
|
||||
INST_NAME("FSIN");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (FSIN)\n");
|
||||
i1 = x87_stackcount(dyn, ninst, x1);
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
CALL(native_fsin, -1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
CALL_(native_fsin, -1, BOX64ENV(dynarec_fastround) ? 0 : u8);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
x87_unstackcount(dyn, ninst, x1, i1);
|
||||
break;
|
||||
case 0xFF:
|
||||
INST_NAME("FCOS");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (FCOS)\n");
|
||||
i1 = x87_stackcount(dyn, ninst, x1);
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
CALL(native_fcos, -1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
CALL_(native_fcos, -1, BOX64ENV(dynarec_fastround) ? 0 : u8);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
x87_unstackcount(dyn, ninst, x1, i1);
|
||||
break;
|
||||
|
||||
|
||||
case 0xD1:
|
||||
case 0xD4:
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
case 0xE2:
|
||||
case 0xE3:
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
case 0xEF:
|
||||
default:
|
||||
DEFAULT;
|
||||
break;
|
||||
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FLD ST0, float[ED]");
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, box64_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v1, ed, fixedaddress);
|
||||
if(!ST_IS_F(0)) {
|
||||
FCVT_D_S(v1, v1);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FST float[ED], ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0))
|
||||
s0 = v1;
|
||||
else {
|
||||
s0 = fpu_get_scratch(dyn);
|
||||
FCVT_S_D(s0, v1);
|
||||
}
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VST32(s0, ed, fixedaddress);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FSTP float[ED], ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_F);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
if(!ST_IS_F(0)) {
|
||||
FCVT_S_D(v1, v1);
|
||||
}
|
||||
VST32(v1, ed, fixedaddress);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FLDENV Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3); // maybe only x87, not SSE?
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {
|
||||
MOVx_REG(x1, ed);
|
||||
}
|
||||
MOV32w(x2, 0);
|
||||
CALL(fpu_loadenv, -1);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FLDCW Ew");
|
||||
GETEW(x1, 0);
|
||||
STRH_U12(x1, xEmu, offsetof(x64emu_t, cw)); // hopefully cw is not too far for an imm8
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FNSTENV Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3); // maybe only x87, not SSE?
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {
|
||||
MOVx_REG(x1, ed);
|
||||
}
|
||||
MOV32w(x2, 0);
|
||||
CALL(fpu_savenv, -1);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FNSTCW Ew");
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
ed = x1;
|
||||
wb1 = 1;
|
||||
LDRH_U12(x1, xEmu, offsetof(x64emu_t, cw));
|
||||
EWBACK;
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
}
|
||||
} else
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FLD ST0, float[ED]");
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, (BOX64ENV(dynarec_x87double)==1)?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v1, ed, fixedaddress);
|
||||
if(!ST_IS_F(0)) {
|
||||
FCVT_D_S(v1, v1);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FST float[ED], ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0))
|
||||
s0 = v1;
|
||||
else {
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
FCVT_S_D(s0, v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
}
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VST32(s0, ed, fixedaddress);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FSTP float[ED], ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_F);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
if(!ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
FCVT_S_D(v1, v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
}
|
||||
VST32(v1, ed, fixedaddress);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FLDENV Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (FLDENV)\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3); // maybe only x87, not SSE?
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {
|
||||
MOVx_REG(x1, ed);
|
||||
}
|
||||
MOV32w(x2, 0);
|
||||
CALL(fpu_loadenv, -1);
|
||||
NATIVE_RESTORE_X87PC();
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FLDCW Ew");
|
||||
GETEW(x1, 0);
|
||||
STRH_U12(x1, xEmu, offsetof(x64emu_t, cw)); // hopefully cw is not too far for an imm8
|
||||
if(dyn->need_x87check)
|
||||
UBFXw(x87pc, x1, 8, 2);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FNSTENV Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization (FNSTENV)\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3); // maybe only x87, not SSE?
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {
|
||||
MOVx_REG(x1, ed);
|
||||
}
|
||||
MOV32w(x2, 0);
|
||||
CALL(fpu_savenv, -1);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FNSTCW Ew");
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
ed = x1;
|
||||
wb1 = 1;
|
||||
LDRH_U12(x1, xEmu, offsetof(x64emu_t, cw));
|
||||
EWBACK;
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
@@ -5,10 +5,8 @@
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "box64cpu.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.h"
|
||||
#include "x64emu.h"
|
||||
#include "box64stack.h"
|
||||
#include "callback.h"
|
||||
@@ -19,7 +17,7 @@
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "../dynarec_helper.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
|
||||
|
||||
@@ -29,6 +27,7 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
int64_t j64;
|
||||
uint8_t ed;
|
||||
uint8_t wback;
|
||||
uint8_t u8;
|
||||
int v1, v2;
|
||||
int d0;
|
||||
int s0;
|
||||
@@ -42,6 +41,7 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MAYUSE(ed);
|
||||
MAYUSE(j64);
|
||||
|
||||
if(MODREG)
|
||||
switch(nextop) {
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
@@ -134,106 +134,125 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
case 0xE4:
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
case 0xF4:
|
||||
case 0xF5:
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
case 0xF8:
|
||||
case 0xF9:
|
||||
case 0xFD:
|
||||
default:
|
||||
DEFAULT;
|
||||
break;
|
||||
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FIADD ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
FADDD(v1, v1, v2);
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FIMUL ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
FMULD(v1, v1, v2);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FICOM ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
FCMPD(v1, v2);
|
||||
FCOM(x1, x2, x3);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FICOMP ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
FCMPD(v1, v2);
|
||||
FCOM(x1, x2, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FISUB ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
FSUBD(v1, v1, v2);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FISUBR ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
FSUBD(v1, v2, v1);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FIDIV ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
FDIVD(v1, v1, v2);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FIDIVR ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
FDIVD(v1, v2, v1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FIADD ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
FADDD(v1, v1, v2);
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FIMUL ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
FMULD(v1, v1, v2);
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FICOM ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
FCMPD(v1, v2);
|
||||
FCOM(x1, x2, x3);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FICOMP ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
FCMPD(v1, v2);
|
||||
FCOM(x1, x2, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FISUB ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
FSUBD(v1, v1, v2);
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FISUBR ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
FSUBD(v1, v2, v1);
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FIDIV ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
FDIVD(v1, v1, v2);
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FIDIVR ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
FDIVD(v1, v2, v1);
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
Loaded 100 of 2054 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user