mirror of
https://github.com/ptitSeb/box64.git
synced 2026-11-09 17:43:18 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
No files matched your search
+2
-1
@@ -12,6 +12,7 @@ MaxEmptyLinesToKeep: 2
|
||||
IndentCaseLabels: true
|
||||
AlignConsecutiveMacros: true
|
||||
WhitespaceSensitiveMacros: ['QUOTE']
|
||||
IfMacros: ['IFX', 'IFX2', 'IFXA', 'IFX_PENDOR0', 'IFXX', 'IFX2X', 'IFXN', 'UFLAG_IF', 'PASS2IF']
|
||||
IfMacros: ['IFX', 'IFXORNAT', 'IFX2', 'IFXA', 'IFX_PENDOR0', 'IFXX', 'IFX2X', 'IFXN', 'UFLAG_IF', 'PASS2IF']
|
||||
UseTab: Never
|
||||
IndentPPDirectives: None
|
||||
---
|
||||
+148
-32
@@ -27,16 +27,20 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [X64, OTHER_ARM, RISCV, RPI4ARM64, RPI5ARM64, RK3326, RK3399, RK3588, PHYTIUM, SD845, SD888, ADLINK, ARM64, ANDROID, TERMUX, LARCH64]
|
||||
type: [Release, Trace]
|
||||
platform: [X64, RISCV, RK3588, ARM64, ANDROID, TERMUX, LARCH64, ANDROID_GLIBC]
|
||||
type: [Release, Trace, StaticBuild, Box32]
|
||||
os: [ubuntu-latest]
|
||||
include:
|
||||
- platform: TEGRAX1
|
||||
type: Release
|
||||
os: ubuntu-20.04
|
||||
- platform: TEGRAX1
|
||||
type: Trace
|
||||
os: ubuntu-20.04
|
||||
exclude:
|
||||
- platform: ANDROID
|
||||
type: StaticBuild
|
||||
- platform: TERMUX
|
||||
type: StaticBuild
|
||||
- platform: X64
|
||||
type: StaticBuild
|
||||
- platform: ANDROID
|
||||
type: Box32
|
||||
- platform: TERMUX
|
||||
type: Box32
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
@@ -46,8 +50,8 @@ jobs:
|
||||
- name: "Environment preparation"
|
||||
run: |
|
||||
sudo apt-get update
|
||||
if [[ ${{ matrix.platform }} != 'X64' && ${{ matrix.platform }} != 'OTHER_ARM' && ${{ matrix.platform }} != 'RISCV' && ${{ matrix.platform }} != 'LARCH64' ]]; then
|
||||
sudo apt-get -y install git cmake make python3
|
||||
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
|
||||
wget https://dl.google.com/android/repository/android-ndk-r26b-linux.zip
|
||||
unzip android-ndk-r26b-linux.zip
|
||||
@@ -57,6 +61,10 @@ jobs:
|
||||
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 -DARM_DYNAREC=1 -DBAD_SIGNAL=1" >> $GITHUB_ENV
|
||||
echo "BOX64_COMPILER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
|
||||
else
|
||||
sudo apt-get -y install git gcc-aarch64-linux-gnu
|
||||
echo "BOX64_PLATFORM_MARCRO=-D${{ matrix.platform }}=1" >> $GITHUB_ENV
|
||||
@@ -84,7 +92,7 @@ jobs:
|
||||
elif [[ ${{ matrix.platform }} == 'RISCV' ]]; then
|
||||
echo BOX64_PLATFORM_MARCRO="-DRV64=ON" >> $GITHUB_ENV
|
||||
echo "BOX64_COMPILER=riscv64-linux-gnu-gcc" >> $GITHUB_ENV
|
||||
sudo apt-get -y install git gcc-riscv64-linux-gnu cmake make python3
|
||||
sudo apt-get -y install git gcc-riscv64-linux-gnu cmake make python3 ninja-build
|
||||
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 -
|
||||
@@ -109,17 +117,63 @@ 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: |
|
||||
@@ -130,46 +184,108 @@ jobs:
|
||||
${{ 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' ]]; then
|
||||
mkdir qemu9.0.0
|
||||
wget -O- -q https://archive.archlinux.org/packages/q/qemu-user-static/qemu-user-static-9.0.0-1-x86_64.pkg.tar.zst | tar -I zstd -C qemu9.0.0 -xf -
|
||||
sudo cp qemu9.0.0/usr/bin/* /usr/bin/
|
||||
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) --output-on-failure
|
||||
INTERPRETER=qemu-riscv64-static QEMU_LD_PREFIX=/usr/riscv64-linux-gnu/ QEMU_CPU=rv64,v=false BOX64_DYNAREC=0 ctest -j$(nproc) --output-on-failure
|
||||
INTERPRETER=qemu-riscv64-static QEMU_LD_PREFIX=/usr/riscv64-linux-gnu/ QEMU_CPU=rv64,v=false,zba=true,zbb=true,zbc=true,zbs=true ctest -j$(nproc) --output-on-failure
|
||||
INTERPRETER=qemu-riscv64-static QEMU_LD_PREFIX=/usr/riscv64-linux-gnu/ QEMU_CPU=rv64,v=true,vlen=128,vext_spec=v1.0 ctest -j$(nproc) --output-on-failure
|
||||
INTERPRETER=qemu-riscv64-static QEMU_LD_PREFIX=/usr/riscv64-linux-gnu/ QEMU_CPU=rv64,v=false,xtheadba=true,xtheadba=true,xtheadbb=true,xtheadbs=true,xtheadcondmov=true,xtheadmemidx=true,xtheadmempair=true,xtheadfmemidx=true,xtheadmac=true,xtheadfmv=true ctest -j$(nproc) --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
|
||||
INTERPRETER=qemu-loongarch64-static QEMU_LD_PREFIX=/usr/loongarch64-linux-gnu/ BOX64_DYNAREC_LA64NOEXT=1 ctest -j$(nproc) --repeat until-pass:20 --output-on-failure
|
||||
INTERPRETER=qemu-loongarch64-static QEMU_LD_PREFIX=/usr/loongarch64-linux-gnu/ BOX64_DYNAREC_TEST=2 BOX64_DYNAREC_LA64NOEXT=1 ctest -j$(nproc) --repeat until-pass:20 --output-on-failure
|
||||
INTERPRETER=qemu-loongarch64-static QEMU_LD_PREFIX=/usr/loongarch64-linux-gnu/ BOX64_DYNAREC=0 ctest -j$(nproc) --repeat until-pass:20 --output-on-failure
|
||||
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
|
||||
INTERPRETER=qemu-aarch64-static QEMU_LD_PREFIX=/system/lib64 BOX64_DYNAREC=0 ctest -j$(nproc) --repeat until-pass:20 --output-on-failure
|
||||
INTERPRETER=qemu-aarch64-static QEMU_LD_PREFIX=/system/lib64 ctest -j$(nproc) --repeat until-pass:20 --output-on-failure
|
||||
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
|
||||
INTERPRETER=qemu-aarch64-static QEMU_SET_ENV=LD_LIBRARY_PATH=/data/data/com.termux/files/usr/lib QEMU_LD_PREFIX=/system/lib64:/data/data/com.termux/files/usr/lib BOX64_DYNAREC=0 ctest -j$(nproc) --repeat until-pass:20 --output-on-failure
|
||||
INTERPRETER=qemu-aarch64-static QEMU_SET_ENV=LD_LIBRARY_PATH=/data/data/com.termux/files/usr/lib QEMU_LD_PREFIX=/system/lib64:/data/data/com.termux/files/usr/lib ctest -j$(nproc) --repeat until-pass:20 --output-on-failure
|
||||
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.platform }} != 'X64' ]]; then # AArch64
|
||||
INTERPRETER=qemu-aarch64-static QEMU_LD_PREFIX=/usr/aarch64-linux-gnu/ BOX64_DYNAREC=0 ctest -j$(nproc) --output-on-failure
|
||||
INTERPRETER=qemu-aarch64-static QEMU_LD_PREFIX=/usr/aarch64-linux-gnu/ ctest -j$(nproc) --output-on-failure
|
||||
INTERPRETER=qemu-aarch64-static QEMU_LD_PREFIX=/usr/aarch64-linux-gnu/ BOX64_DYNAREC_TEST=2 ctest -j$(nproc) --output-on-failure
|
||||
export INTERPRETER=qemu-aarch64-static
|
||||
export QEMU_LD_PREFIX=/usr/aarch64-linux-gnu/
|
||||
|
||||
BOX64_DYNAREC=0 ctest $CTEST_OPTIONS
|
||||
ctest $CTEST_OPTIONS
|
||||
BOX64_DYNAREC_TEST=1 ctest $CTEST_OPTIONS -E nocosim
|
||||
else
|
||||
ctest -j$(nproc) --output-on-failure
|
||||
ctest -j$(nproc)
|
||||
fi
|
||||
|
||||
- name: "Get short Git commit"
|
||||
id: git-info
|
||||
run: echo "SHORT_COMMIT=$(git rev-parse --short HEAD)" >> $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: "Upload Artifact"
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: box64-${{ matrix.platform }}-${{ matrix.type }}
|
||||
path: build/box64
|
||||
|
||||
- name: "Upload WCP file"
|
||||
if: matrix.platform == 'ANDROID_GLIBC' && matrix.type != 'StaticBuild'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: box64-latest-${{ matrix.type }}-wcp
|
||||
path: build/box64-latest.wcp
|
||||
+10
-5
@@ -60,11 +60,16 @@ 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
|
||||
+402
-45
@@ -17,8 +17,10 @@ option(TEGRA_T194 "Set to ON if targeting an Tegra Xavier based device" ${TEGRA_
|
||||
option(TEGRA_T234 "Set to ON if targeting an Tegra Orin based device" ${TEGRA_T234})
|
||||
option(PHYTIUM "Set to ON if targeting an Phytium (D2000 or FT2000/4) based device" ${PHYTIUM})
|
||||
option(SD845 "Set to ON if targeting a Snapragon 845 based device" ${SD845})
|
||||
option(SD865 "Set to ON if targeting a Snapragon 865 based device" ${SD865})
|
||||
option(SD888 "Set to ON if targeting a Snapragon 888 based device" ${SD888})
|
||||
option(SD8G2 "Set to ON if targeting a Snapragon 8 Gen 2 based device" ${SD8G2})
|
||||
option(SDORYON1 "Set to ON if targeting a Snapdragon Oryon 1 (X1E80100/X1E78100) based device" ${SDORYON1})
|
||||
option(ADLINK "Set to ON if targeting an ADLink AmpereAltra based device" ${ADLINK})
|
||||
option(M1 "Set to ON if targeting a AppleM1 running on Asahi computer" ${M1})
|
||||
option(LARCH64 "Set to ON if targeting an Loongarch64 based device" ${LARCH64})
|
||||
@@ -37,6 +39,8 @@ option(BAD_SIGNAL "Set to ON to activate the workaround for incoherent si_info o
|
||||
option(SW64 "Set ON if targeting an SW64 based device" ${SW64})
|
||||
option(CI "Set to ON if running in CI" ${CI})
|
||||
option(WITH_MOLD "Set to ON to use with mold" ${WITH_MOLD})
|
||||
option(BOX32 "Set to ON to add Linux 32bits support (experimental, do not use)" ${BOX32})
|
||||
option(BOX32_BINFMT "Also setup binfmt integration for box32" ${BOX32_BINFMT})
|
||||
|
||||
if(TERMUX)
|
||||
set(TERMUX_PATH "/data/data/com.termux/files")
|
||||
@@ -63,7 +67,7 @@ if(PPC64LE)
|
||||
set(RV64_DYNAREC OFF CACHE BOOL "")
|
||||
set(LARCH64_DYNAREC OFF CACHE BOOL "")
|
||||
endif()
|
||||
if(RK3399 OR RK3588 OR ODROIDN2 OR RPI3ARM64 OR RPI4ARM64 OR RPI5ARM64 OR RK3326 OR TEGRAX1 OR TEGRA_T194 OR TEGRA_T234 OR PHYTIUM OR SD845 OR SD888 OR SD8G2 OR LX2160A OR M1 OR ARM64 OR ADLINK)
|
||||
if(RK3399 OR RK3588 OR ODROIDN2 OR RPI3ARM64 OR RPI4ARM64 OR RPI5ARM64 OR RK3326 OR TEGRAX1 OR TEGRA_T194 OR TEGRA_T234 OR PHYTIUM OR SD845 OR SD865 OR SD888 OR SD8G2 OR SDORYON1 OR LX2160A OR M1 OR ARM64 OR ADLINK)
|
||||
set(LD80BITS OFF CACHE BOOL "")
|
||||
set(NOALIGN OFF CACHE BOOL "")
|
||||
set(ARM_DYNAREC ON CACHE BOOL "")
|
||||
@@ -81,6 +85,7 @@ if(SW64)
|
||||
set(NOALIGN OFF CACHE BOOL "")
|
||||
endif()
|
||||
if(ANDROID)
|
||||
set(TERMUX_PATH "/data/data/com.termux/files")
|
||||
set(NOLOADADDR ON CACHE BOOL "")
|
||||
set(BAD_SIGNAL ON CACHE BOOL "")
|
||||
endif()
|
||||
@@ -173,6 +178,11 @@ elseif(SD845)
|
||||
add_definitions(-DSD845)
|
||||
add_definitions(-pipe -march=armv8.2-a+simd+crypto -mtune=cortex-a75.cortex-a55)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8.2-a+simd+crypto -mtune=cortex-a75.cortex-a55")
|
||||
elseif(SD865)
|
||||
add_definitions(-DSD865)
|
||||
#note that cortex-a77.cortex-a55 is not supported, so fall back to a76 instead
|
||||
add_definitions(-pipe -march=armv8.2-a+simd+crypto -mtune=cortex-a76.cortex-a55)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8.2-a+simd+crypto -mtune=cortex-a76.cortex-a55")
|
||||
elseif(SD888)
|
||||
add_definitions(-DSD888)
|
||||
add_definitions(-pipe -march=armv8.4-a+simd+crypto)
|
||||
@@ -181,6 +191,24 @@ elseif(SD8G2)
|
||||
add_definitions(-DSD8G2)
|
||||
add_definitions(-pipe -march=armv9-a+i8mm+sm4+sha3+rcpc+crypto+nosve+nosve2)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv9-a+i8mm+sm4+sha3+rcpc+crypto+nosve+nosve2")
|
||||
elseif(SDORYON1)
|
||||
add_definitions(-DSDORYON1)
|
||||
# NOTE
|
||||
#
|
||||
# 1.
|
||||
# GCC 14 and Clang 19 support oryon-1 as a -mcpu/-mtune argument,
|
||||
# however it seems like fedora (the system I tested this on) does not work.
|
||||
# see https://gcc.gnu.org/onlinedocs/gcc-14.2.0/gcc/AArch64-Options.html if you're interested
|
||||
#
|
||||
# 2.
|
||||
# gcc/gcc/config/aarch64/aarch64-cores.def:157 defines oryon1 as
|
||||
# AARCH64_CORE("oryon-1", oryon1, cortexa57, V8_6A, (CRYPTO, SM4, SHA3, F16), cortexa72, 0x51, 0x001, -1)
|
||||
# where
|
||||
# * the 3rd positional argument is represented as the "scheduler"
|
||||
# * the 6th positional argument is represented as the "cost"
|
||||
# I've chosen the a57 because I don't know if I should choose the a72
|
||||
add_definitions(-pipe -march=armv8.6-a+crypto+sm4+sha3+fp16 -mtune=cortex-a57)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8.6-a+crypto+sm4+sha3+fp16 -mtune=cortex-a57")
|
||||
elseif(ADLINK)
|
||||
add_definitions(-DADLINK)
|
||||
add_definitions(-pipe -mcpu=neoverse-n1 -fuse-ld=gold -fuse-linker-plugin)
|
||||
@@ -231,10 +259,17 @@ if(STATICBUILD)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "-static")
|
||||
set(HAVE_TRACE OFF)
|
||||
endif()
|
||||
if(BOX32)
|
||||
add_definitions(-DBOX32)
|
||||
add_definitions(-Wno-address-of-packed-member) #32bits might generated unaligned pointers
|
||||
endif()
|
||||
|
||||
if(NOGIT)
|
||||
add_definitions(-DNOGIT)
|
||||
endif()
|
||||
if(CI)
|
||||
add_definitions(-Wno-pointer-type-mismatch)
|
||||
endif()
|
||||
|
||||
if(HAVE_TRACE)
|
||||
set(BOX64 box64)
|
||||
@@ -298,6 +333,11 @@ include_directories(
|
||||
"${BOX64_ROOT}/src"
|
||||
"${BOX64_ROOT}/src/wrapped/generated"
|
||||
)
|
||||
if(BOX32)
|
||||
include_directories(
|
||||
"${BOX64_ROOT}/src/wrapped32/generated"
|
||||
)
|
||||
endif()
|
||||
|
||||
# git_head.h is a generated file
|
||||
set_source_files_properties(
|
||||
@@ -326,7 +366,6 @@ set(ELFLOADER_SRC
|
||||
"${BOX64_ROOT}/src/emu/x64run_private.c"
|
||||
"${BOX64_ROOT}/src/emu/x64shaext.c"
|
||||
"${BOX64_ROOT}/src/emu/x64syscall.c"
|
||||
"${BOX64_ROOT}/src/emu/x86syscall.c"
|
||||
"${BOX64_ROOT}/src/emu/x64tls.c"
|
||||
"${BOX64_ROOT}/src/emu/x64trace.c"
|
||||
"${BOX64_ROOT}/src/librarian/librarian.c"
|
||||
@@ -336,6 +375,7 @@ set(ELFLOADER_SRC
|
||||
"${BOX64_ROOT}/src/libtools/auxval.c"
|
||||
"${BOX64_ROOT}/src/libtools/myalign.c"
|
||||
"${BOX64_ROOT}/src/libtools/signals.c"
|
||||
"${BOX64_ROOT}/src/libtools/decopcode.c"
|
||||
"${BOX64_ROOT}/src/libtools/threads.c"
|
||||
"${BOX64_ROOT}/src/tools/bitutils.c"
|
||||
"${BOX64_ROOT}/src/tools/box64stack.c"
|
||||
@@ -359,6 +399,34 @@ if(NOT STATICBUILD)
|
||||
"${BOX64_ROOT}/src/librarian/globalsymbols.c"
|
||||
)
|
||||
endif()
|
||||
if(BOX32)
|
||||
list(APPEND ELFLOADER_SRC
|
||||
"${BOX64_ROOT}/src/box32.c"
|
||||
"${BOX64_ROOT}/src/elfs/elfhash32.c"
|
||||
"${BOX64_ROOT}/src/elfs/elfloader32.c"
|
||||
"${BOX64_ROOT}/src/elfs/elfparser32.c"
|
||||
"${BOX64_ROOT}/src/elfs/elfload_dump32.c"
|
||||
"${BOX64_ROOT}/src/tools/box32stack.c"
|
||||
"${BOX64_ROOT}/src/emu/x86int3.c"
|
||||
"${BOX64_ROOT}/src/librarian/globalsymbols32.c"
|
||||
"${BOX64_ROOT}/src/libtools/myalign32.c"
|
||||
"${BOX64_ROOT}/src/libtools/myalign64_32.c"
|
||||
"${BOX64_ROOT}/src/libtools/signal32.c"
|
||||
"${BOX64_ROOT}/src/libtools/threads32.c"
|
||||
"${BOX64_ROOT}/src/libtools/libc_net32.c"
|
||||
"${BOX64_ROOT}/src/libtools/sdl1align32.c"
|
||||
"${BOX64_ROOT}/src/libtools/sdl2align32.c"
|
||||
"${BOX64_ROOT}/src/libtools/my_x11_conv.c"
|
||||
"${BOX64_ROOT}/src/libtools/my_x11_xevent.c"
|
||||
"${BOX64_ROOT}/src/emu/x86syscall_32.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/generated/wrapper32.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/generated/converter32.c"
|
||||
)
|
||||
else()
|
||||
list(APPEND ELFLOADER_SRC
|
||||
"${BOX64_ROOT}/src/emu/x86syscall.c"
|
||||
)
|
||||
endif()
|
||||
if(NOT ANDROID)
|
||||
list(APPEND ELFLOADER_SRC
|
||||
"${BOX64_ROOT}/src/libtools/obstack.c"
|
||||
@@ -412,7 +480,7 @@ set(INTERPRETER
|
||||
if(STATICBUILD)
|
||||
set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedldlinux.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibbsd.c"
|
||||
#"${BOX64_ROOT}/src/wrapped/wrappedlibbsd.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibc.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibcmusl.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibdl.c"
|
||||
@@ -497,6 +565,7 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibcups.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibdl.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibdrm.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibdrmamdgpu.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibegl.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibform.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibformw.c"
|
||||
@@ -538,6 +607,7 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibx11.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibx11xcb.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxau.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxaw.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxcb.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxcbcursor.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibxcbdri2.c"
|
||||
@@ -649,6 +719,8 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedicui18n73.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedicuuc74.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedicui18n74.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedicuuc75.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedicui18n75.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedidn2.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedanl.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedpsl5.c"
|
||||
@@ -659,6 +731,9 @@ set(WRAPPEDS
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibunistring2.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibhogweed6.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibsqlite3.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedlibtiff5.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedbrotlidec.c"
|
||||
"${BOX64_ROOT}/src/wrapped/wrappedzstd.c"
|
||||
)
|
||||
endif()
|
||||
if(ANDROID)
|
||||
@@ -711,6 +786,83 @@ endif ()
|
||||
add_custom_target(WRAPPERS DEPENDS "${BOX64_ROOT}/src/wrapped/generated/functions_list.txt")
|
||||
#add_custom_target(PRINTER DEPENDS "${BOX64_ROOT}/src/dynarec/last_run.txt")
|
||||
|
||||
if(BOX32)
|
||||
if(STATICBUILD)
|
||||
set(WRAPPEDS32
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedldlinux.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibc.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibdl.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibm.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibpthread.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibrt.c"
|
||||
)
|
||||
else()
|
||||
set(WRAPPEDS32
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedldlinux.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibc.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibdl.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibm.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibpthread.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibrt.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibresolv.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedcrashhandler.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibgl.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibglu.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedsdl1.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedsdl2.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedsdl2image.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibasound.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedopenal.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedfreetype.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedfontconfig.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibx11.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibxext.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibxfixes.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibxrender.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibxi.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibxcomposite.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibxcursor.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibxrandr.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibxss.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibxxf86vm.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedxinerama.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedexpat.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedudev0.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedudev1.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedlibuuid.c"
|
||||
"${BOX64_ROOT}/src/wrapped32/wrappedtcmallocminimal.c"
|
||||
)
|
||||
endif()
|
||||
string(REPLACE ".c" "_private.h" MODROOT ${BOX64_ROOT})
|
||||
#set(WRAPPEDS32_HEAD "${BOX64_ROOT}/src/wrapped/wrappedd3dadapter9_genvate.h")
|
||||
foreach(A ${WRAPPEDS32})
|
||||
string(REPLACE ".c" "_private.h" C ${A})
|
||||
string(REPLACE "${MODROOT}" "${BOX64_ROOT}" B ${C})
|
||||
set(WRAPPEDS32_HEAD ${WRAPPEDS32_HEAD} ${B})
|
||||
set_source_files_properties(${A} PROPERTIES OBJECT_DEPENDS ${B})
|
||||
endforeach()
|
||||
|
||||
set(WRAPPER32 "${BOX64_ROOT}/src/wrapped32/generated/wrapper32.c" "${BOX64_ROOT}/src/wrapped32/generated/wrapper32.h")
|
||||
|
||||
if(NOT CI)
|
||||
add_custom_command(
|
||||
OUTPUT "${BOX64_ROOT}/src/wrapped32/generated/functions_list.txt"
|
||||
COMMAND "${PYTHON_EXECUTABLE}" "${BOX64_ROOT}/rebuild_wrappers_32.py"
|
||||
"${BOX64_ROOT}"
|
||||
"PANDORA" "HAVE_LD80BITS" "NOALIGN" "HAVE_TRACE" "ANDROID" "TERMUX" "STATICBUILD" "--"
|
||||
${WRAPPEDS32_HEAD}
|
||||
MAIN_DEPENDENCY "${BOX64_ROOT}/rebuild_wrappers_32.py"
|
||||
DEPENDS ${WRAPPEDS32} ${WRAPPEDS32_HEAD}
|
||||
BYPRODUCTS ${WRAPPER32}
|
||||
)
|
||||
endif()
|
||||
|
||||
add_custom_target(WRAPPERS32 DEPENDS "${BOX64_ROOT}/src/wrapped32/generated/functions_list.txt")
|
||||
else()
|
||||
set(WRAPPEDS32)
|
||||
endif()
|
||||
|
||||
|
||||
if(DYNAREC)
|
||||
set(DYNAREC_SRC
|
||||
"${BOX64_ROOT}/src/dynarec/dynablock.c"
|
||||
@@ -776,6 +928,7 @@ if(ARM_DYNAREC)
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_avx_66_0f3a.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_avx_f2_0f38.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_avx_f2_0f3a.c"
|
||||
"${BOX64_ROOT}/src/dynarec/arm64/dynarec_arm64_avx_f3_0f38.c"
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -806,10 +959,12 @@ if(RV64_DYNAREC)
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_00_2.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_00_3.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_0f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_0f_vector.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_64.c"
|
||||
#"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_65.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_64_vector.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_66.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_67.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_67_vector.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_67_32.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_d8.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_d9.c"
|
||||
@@ -821,13 +976,18 @@ if(RV64_DYNAREC)
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_df.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_f0.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_660f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_660f38.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_660f_vector.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_66f20f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_66f30f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_6664.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_66f0.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_f20f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_f20f_vector.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_f30f.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_f30f_vector.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx.c"
|
||||
"${BOX64_ROOT}/src/dynarec/rv64/dynarec_rv64_avx_f3_0f.c"
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -870,6 +1030,11 @@ if(DYNAREC)
|
||||
${DYNAREC_PASS}
|
||||
"${BOX64_ROOT}/src/dynarec/dynarec_native_pass.c"
|
||||
)
|
||||
if(BOX32)
|
||||
list(APPEND DYNAREC_PASS
|
||||
"${BOX64_ROOT}/src/wrapped32/generated/wrapper32.h"
|
||||
)
|
||||
endif()
|
||||
|
||||
add_library(dynarec_native OBJECT ${DYNAREC_SRC})
|
||||
|
||||
@@ -887,6 +1052,12 @@ if(DYNAREC)
|
||||
add_dependencies(native_pass1 WRAPPERS)
|
||||
add_dependencies(native_pass2 WRAPPERS)
|
||||
add_dependencies(native_pass3 WRAPPERS)
|
||||
if(BOX32)
|
||||
add_dependencies(native_pass0 WRAPPERS32)
|
||||
add_dependencies(native_pass1 WRAPPERS32)
|
||||
add_dependencies(native_pass2 WRAPPERS32)
|
||||
add_dependencies(native_pass3 WRAPPERS32)
|
||||
endif()
|
||||
|
||||
add_library(dynarec STATIC
|
||||
$<TARGET_OBJECTS:dynarec_native>
|
||||
@@ -903,26 +1074,29 @@ if(DYNAREC)
|
||||
add_custom_command(
|
||||
OUTPUT "${BOX64_ROOT}/src/git_head.h"
|
||||
COMMAND sh -c "echo \\\#define GITREV \\\"$(git rev-parse --short HEAD)\\\">\"${BOX64_ROOT}/src/git_head.h\""
|
||||
DEPENDS dynarec ${ELFLOADER_SRC} ${INTERPRETER} ${WRAPPEDS}
|
||||
DEPENDS dynarec ${ELFLOADER_SRC} ${INTERPRETER} ${WRAPPEDS} ${WRAPPEDS32}
|
||||
VERBATIM)
|
||||
else()
|
||||
add_custom_command(
|
||||
OUTPUT "${BOX64_ROOT}/src/git_head.h"
|
||||
COMMAND sh -c "echo \\\#define GITREV \\\"$(git rev-parse --short HEAD)\\\">\"${BOX64_ROOT}/src/git_head.h\""
|
||||
DEPENDS ${ELFLOADER_SRC} ${INTERPRETER} ${WRAPPEDS}
|
||||
DEPENDS ${ELFLOADER_SRC} ${INTERPRETER} ${WRAPPEDS} ${WRAPPEDS32}
|
||||
VERBATIM)
|
||||
endif()
|
||||
|
||||
add_library(interpreter OBJECT ${INTERPRETER})
|
||||
|
||||
add_executable(${BOX64} ${ELFLOADER_SRC} ${WRAPPEDS} "${BOX64_ROOT}/src/git_head.h")
|
||||
add_executable(${BOX64} ${ELFLOADER_SRC} ${WRAPPEDS} ${WRAPPEDS32} "${BOX64_ROOT}/src/git_head.h")
|
||||
set_target_properties(${BOX64} PROPERTIES ENABLE_EXPORTS ON)
|
||||
add_dependencies(${BOX64} WRAPPERS)
|
||||
if(BOX32)
|
||||
add_dependencies(${BOX64} WRAPPERS32)
|
||||
endif()
|
||||
#add_dependencies(${BOX64} PRINTER)
|
||||
#target_link_libraries(${BOX64} c m dl rt pthread resolv)
|
||||
if(STATICBUILD)
|
||||
#set_target_properties(${BOX64} PROPERTIES LINK_FLAGS "-fuse-ld=gold -static -Wl,--no-relax -Wl,--allow-multiple-definition -ldl -lrt -lpthread -lresolv -lc -lutil -lm -Wl,-defsym,_DYNAMIC=0 -pthread")
|
||||
target_link_libraries(${BOX64} c m dl pthread resolv util bsd c)
|
||||
target_link_libraries(${BOX64} c m dl pthread resolv util c)
|
||||
else()
|
||||
if(ANDROID)
|
||||
if(TERMUX)
|
||||
@@ -942,7 +1116,7 @@ target_link_libraries(${BOX64} interpreter)
|
||||
if(${CMAKE_VERSION} VERSION_LESS "3.13")
|
||||
if(NOT NOLOADADDR)
|
||||
if(CMAKE_C_COMPILER_ID STREQUAL "Clang" OR WITH_MOLD)
|
||||
set_target_properties(${BOX64} PROPERTIES LINK_FLAGS "-Wl,--image-base=${BOX64_ELF_ADDRESS}")
|
||||
set_target_properties(${BOX64} PROPERTIES LINK_FLAGS "-no-pie -Wl,--image-base=${BOX64_ELF_ADDRESS}")
|
||||
else()
|
||||
set_target_properties(${BOX64} PROPERTIES LINK_FLAGS "-Wl,-Ttext-segment,${BOX64_ELF_ADDRESS}")
|
||||
endif()
|
||||
@@ -951,6 +1125,9 @@ else()
|
||||
# If symbols are missing, try this: target_link_options(${BOX64} PUBLIC -rdynamic)
|
||||
if(NOT NOLOADADDR)
|
||||
if(CMAKE_C_COMPILER_ID STREQUAL "Clang" OR WITH_MOLD)
|
||||
if(WITH_MOLD) # --image-base requires -no-pie in mold!
|
||||
set_target_properties(${BOX64} PROPERTIES LINK_FLAGS "-no-pie -lm")
|
||||
endif()
|
||||
target_link_options(${BOX64} PUBLIC LINKER:--image-base=${BOX64_ELF_ADDRESS})
|
||||
else()
|
||||
target_link_options(${BOX64} PUBLIC LINKER:-Ttext-segment,${BOX64_ELF_ADDRESS})
|
||||
@@ -969,42 +1146,54 @@ endif()
|
||||
|
||||
if(NOT _x86 AND NOT _x86_64)
|
||||
if(NOT TERMUX)
|
||||
install(TARGETS ${BOX64}
|
||||
RUNTIME DESTINATION bin)
|
||||
install(TARGETS ${BOX64} RUNTIME DESTINATION bin)
|
||||
if(NOT NO_LIB_INSTALL)
|
||||
install(PROGRAMS ${CMAKE_SOURCE_DIR}/tests/box64-bash DESTINATION bin)
|
||||
endif()
|
||||
else()
|
||||
install(TARGETS ${BOX64}
|
||||
RUNTIME DESTINATION ${TERMUX_PATH}/usr/bin)
|
||||
install(TARGETS ${BOX64} RUNTIME DESTINATION ${TERMUX_PATH}/usr/bin)
|
||||
if(NOT NO_LIB_INSTALL)
|
||||
install(PROGRAMS ${CMAKE_SOURCE_DIR}/tests/box64-bash DESTINATION ${TERMUX_PATH}/usr/bin)
|
||||
endif()
|
||||
endif()
|
||||
if(NOT NO_CONF_INSTALL)
|
||||
configure_file(system/box64.conf.cmake system/box64.conf)
|
||||
if(NOT TERMUX)
|
||||
install(FILES ${CMAKE_BINARY_DIR}/system/box64.conf DESTINATION /etc/binfmt.d/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/system/box64.box64rc DESTINATION /etc/)
|
||||
else()
|
||||
install(FILES ${CMAKE_BINARY_DIR}/system/box64.conf DESTINATION ${TERMUX_PATH}/usr/etc/binfmt.d/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/system/box64.box64rc DESTINATION ${TERMUX_PATH}/usr/etc/)
|
||||
install(FILES ${CMAKE_BINARY_DIR}/system/box64.conf DESTINATION /etc/binfmt.d/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/system/box64.box64rc DESTINATION /etc/)
|
||||
if(BOX32_BINFMT)
|
||||
configure_file(system/box32.conf.cmake system/box32.conf)
|
||||
install(FILES ${CMAKE_BINARY_DIR}/system/box32.conf DESTINATION /etc/binfmt.d/)
|
||||
endif()
|
||||
else()
|
||||
install(FILES ${CMAKE_BINARY_DIR}/system/box64.conf DESTINATION ${TERMUX_PATH}/usr/etc/binfmt.d/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/system/box64.box64rc DESTINATION ${TERMUX_PATH}/usr/etc/)
|
||||
if(BOX32_BINFMT)
|
||||
configure_file(system/box32.conf.cmake system/box32.conf)
|
||||
install(FILES ${CMAKE_BINARY_DIR}/system/box32.conf DESTINATION ${TERMUX_PATH}/usr/etc/binfmt.d/)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
endif()
|
||||
set(INSTALL_PATH "/usr/lib/x86_64-linux-gnu/")
|
||||
set(INSTALL_PATH "/usr/lib/box64-x86_64-linux-gnu/")
|
||||
if(NOT NO_LIB_INSTALL)
|
||||
if(NOT TERMUX)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libstdc++.so.5 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libstdc++.so.6 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libgcc_s.so.1 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libpng12.so.0 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libcrypto.so.1.1 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libcrypto.so.1.0.0 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libssl.so.1.1 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libssl.so.1.0.0 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libunwind.so.8 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libmbedx509.so.1 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libmbedx509.so.0 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libmbedtls.so.14 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libmbedtls.so.12 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libmbedcrypto.so.7 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libmbedcrypto.so.3 DESTINATION ${INSTALL_PATH})
|
||||
else()
|
||||
if(NOT TERMUX AND NOT ANDROID)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libstdc++.so.5 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libstdc++.so.6 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libgcc_s.so.1 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libpng12.so.0 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libcrypto.so.1.1 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libcrypto.so.1.0.0 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libssl.so.1.1 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libssl.so.1.0.0 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libunwind.so.8 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libmbedx509.so.1 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libmbedx509.so.0 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libmbedtls.so.14 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libmbedtls.so.12 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libmbedcrypto.so.7 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libmbedcrypto.so.3 DESTINATION ${INSTALL_PATH})
|
||||
elseif(TERMUX)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libstdc++.so.5 DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libstdc++.so.6 DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libgcc_s.so.1 DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
@@ -1020,8 +1209,36 @@ if(NOT _x86 AND NOT _x86_64)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libmbedtls.so.12 DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libmbedcrypto.so.7 DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64lib/libmbedcrypto.so.3 DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
elseif(ANDROID)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x64android/libc++_shared.so DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
endif()
|
||||
endif()
|
||||
if(BOX32)
|
||||
set(INSTALL_PATH "/usr/lib/box64-i386-linux-gnu/")
|
||||
if(NOT NO_LIB_INSTALL)
|
||||
if(NOT TERMUX AND NOT ANDROID)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libstdc++.so.5 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libstdc++.so.6 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libgcc_s.so.1 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libpng12.so.0 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libunwind.so.8 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libcrypto.so.1.0.0 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libssl.so.1.0.0 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libz.so.1 DESTINATION ${INSTALL_PATH})
|
||||
elseif(TERMUX)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libstdc++.so.5 DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libstdc++.so.6 DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libgcc_s.so.1 DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libpng12.so.0 DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libunwind.so.8 DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libcrypto.so.1.0.0 DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libssl.so.1.0.0 DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libz.so.1 DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
elseif(ANDROID)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86android/libc++_shared.so DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT TARGET uninstall)
|
||||
@@ -1129,11 +1346,13 @@ add_test(fork ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref09.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(cppThreads ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
add_test(cppThreads_nocosim ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test10 -D TEST_OUTPUT=tmpfile10.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref10.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
set_tests_properties(cppThreads_nocosim PROPERTIES ENVIRONMENT "BOX64_LD_LIBRARY_PATH=${CMAKE_SOURCE_DIR}/x64lib")
|
||||
|
||||
add_test(tlsData ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test11 -D TEST_OUTPUT=tmpfile11.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref11.txt
|
||||
@@ -1275,10 +1494,10 @@ add_test(threadsStart ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref06.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
#add_test(trig ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
# -D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test07_android -D TEST_OUTPUT=tmpfile07.txt
|
||||
# -D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref07.txt
|
||||
# -P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
add_test(trig ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test07_android -D TEST_OUTPUT=tmpfile07.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref07.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(pi ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test08_android -D TEST_OUTPUT=tmpfile08.txt
|
||||
@@ -1330,10 +1549,10 @@ add_test(irelative_reloc ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref20.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(longjumpInSignals ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test21_android -D TEST_OUTPUT=tmpfile21.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref21.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
# add_test(longjumpInSignals ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
# -D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test21_android -D TEST_OUTPUT=tmpfile21.txt
|
||||
# -D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref21.txt
|
||||
# -P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(x87 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test22_android -D TEST_OUTPUT=tmpfile22.txt
|
||||
@@ -1410,3 +1629,141 @@ foreach(file ${extension_tests})
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake)
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if(BOX32)
|
||||
add_test(NAME bootSyscall_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test01 -D TEST_OUTPUT=tmpfile32_01.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref01.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME bootSyscallC_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test02 -D TEST_OUTPUT=tmpfile32_02.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref02.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME printf_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test03 -D TEST_OUTPUT=tmpfile32_03.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref03.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME args_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test04 -D TEST_ARGS2=yeah -D TEST_OUTPUT=tmpfile32_04.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref04.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME maths1_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test05 -D TEST_ARGS2=7 -D TEST_OUTPUT=tmpfile32_05.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref05.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME threadsStart_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test06 -D TEST_OUTPUT=tmpfile32_06.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref06.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME trig_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test07 -D TEST_OUTPUT=tmpfile32_07.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref07.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME pi_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test08 -D TEST_OUTPUT=tmpfile32_08.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref08.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME fork_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test09 -D TEST_OUTPUT=tmpfile32_09.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref09.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
if(NOT CI)
|
||||
add_test(NAME cppThreads_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test10 -D TEST_OUTPUT=tmpfile32_10.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref10.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
set_tests_properties(cppThreads_32bits PROPERTIES ENVIRONMENT "BOX64_LD_LIBRARY_PATH=${CMAKE_SOURCE_DIR}/x86lib")
|
||||
endif()
|
||||
|
||||
add_test(NAME tlsData_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test11 -D TEST_OUTPUT=tmpfile32_11.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref11.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME fpu_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test12 -D TEST_OUTPUT=tmpfile32_12.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref12.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME contexts_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test13 -D TEST_OUTPUT=tmpfile32_13.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref13.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
if(NOT LD80BITS)
|
||||
add_test(NAME conditionalThreads_32bits_nocosim COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test14 -D TEST_OUTPUT=tmpfile32_14.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref14.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
endif()
|
||||
|
||||
add_test(NAME linkingIndirectNoversion_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test15 -D TEST_OUTPUT=tmpfile32_15.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref15.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME linkingIndirectVersion_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test16 -D TEST_OUTPUT=tmpfile32_16.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref16.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME sse_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test17 -D TEST_OUTPUT=tmpfile32_17.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref17.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
set_tests_properties(sse_32bits PROPERTIES ENVIRONMENT "BOX64_DYNAREC_FASTNAN=0;BOX64_DYNAREC_FASTROUND=0")
|
||||
|
||||
add_test(NAME longjumpInSignals_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test18 -D TEST_OUTPUT=tmpfile32_18.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref18.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME x87_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test19 -D TEST_OUTPUT=tmpfile32_19.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref19.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
set_tests_properties(x87_32bits PROPERTIES ENVIRONMENT "BOX64_DYNAREC_FASTROUND=0")
|
||||
|
||||
add_test(NAME idiv_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test20 -D TEST_OUTPUT=tmpfile32_20.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref20.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME multiple_dlopen_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test21 -D TEST_OUTPUT=tmpfile32_21.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref21.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
file(GLOB extension_tests "${CMAKE_SOURCE_DIR}/tests32/extensions/*.c")
|
||||
foreach(file ${extension_tests})
|
||||
get_filename_component(testname "${file}" NAME_WE)
|
||||
add_test(NAME "${testname}_32bits" COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/extensions/${testname} -D TEST_OUTPUT=tmpfile32_-${testname}.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/extensions/${testname}.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake)
|
||||
endforeach()
|
||||
|
||||
#add_test(NAME sse_optimized_32bits COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
# -D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test17_o2 -D TEST_OUTPUT=tmpfile32_17_o2.txt
|
||||
# -D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref17_o2.txt
|
||||
# -P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
#set_tests_properties(sse_optimized_32bits PROPERTIES ENVIRONMENT "BOX64_DYNAREC_FASTNAN=0;BOX64_DYNAREC_FASTROUND=0")
|
||||
|
||||
add_test(bswap_32bits ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX64}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests32/test23 -D TEST_OUTPUT=tmpfile32_23.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests32/ref23.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
endif()
|
||||
@@ -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,112 +1,95 @@
|
||||

|
||||
|
||||
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)
|
||||
- [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 works, amny 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"
|
||||
|
||||
An alternative solution is to use Wine with new WoW64, but you will be limited to 32bits windows apps and games.
|
||||
|
||||
----
|
||||
|
||||
Notes about Box64 configuration
|
||||
----
|
||||
|
||||
Box64 now have configurations files. There are 2 files loaded. `/etc/box64.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](https://github.com/ptitSeb/box64/blob/main/docs/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 and Pi5 use `MESA_GL_VERSION_OVERRIDE=3.2`, with `BOX64_DYNAREC_STRONGMEM=1` to prevent freezes and enable strong memory mode, and use Panfrost `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. It's called "new WoW64" and it's working fine on box64, allowing the use of 32bits windows program on 64bits only system.
|
||||
|
||||
----
|
||||
|
||||
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
|
||||
----
|
||||
|
||||
@@ -114,7 +97,7 @@ 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, ksco, xctan
|
||||
* For their major financial contribution: [Playtron](https://playtron.one), FlyingFathead, stormchaser3000, dennis1248, sll00, [libre-computer-project](https://libre.computer/), [CubeCoders Limited](http://cubecoders.com/)
|
||||
* 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 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/))
|
||||
@@ -122,3 +105,4 @@ So, in no particular order, I want to thank:
|
||||
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!)
|
||||
|
||||
+50
-55
@@ -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 库。
|
||||
|
||||
----
|
||||
|
||||
@@ -103,7 +98,7 @@ Box64 封装了 Vulkan 库,但请注意,它仅在 RX550 显卡上进行过
|
||||
以下感谢不分先后:
|
||||
|
||||
* 代码贡献:rajdakin, mogery, ksco, xctan
|
||||
* 财务帮助:[Playtron](https://playtron.one), FlyingFathead, stormchaser3000, dennis1248, sll00, [libre-computer-project](https://libre.computer/)
|
||||
* 财务支持:[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) 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/))
|
||||
|
||||
+3
-4
@@ -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`, щоб використовувати вищий профіль, якщо гра починається, а потім завершується, перш ніж щось показати.
|
||||
|
||||
----
|
||||
|
||||
@@ -108,7 +107,7 @@ Box64 використовує бібліотеки Vulkan, але зауваж
|
||||
Є багато способів зробити внесок: внесок коду, фінансовий внесок, апаратне забезпечення та реклама!
|
||||
Отже, без особливого порядку, я хочу подякувати:
|
||||
* За основний внесок у код: rajdakin, mogery, ksco, xctan
|
||||
* За великий фінансовий внесок: [Playtron](https://playtron.one), FlyingFathead, stormchaser3000, dennis1248, sll00, [libre-computer-project](https://libre.computer/)
|
||||
* За великий фінансовий внесок: [Playtron](https://playtron.one), tohodakilla, FlyingFathead, stormchaser3000, dennis1248, sll00, [libre-computer-project](https://libre.computer/)
|
||||
* За апаратне забезпечення та міграцію LoongArch: [xiaoji](https://www.linuxgame.cn/), команда розробників Deepin Beijing
|
||||
* За внесок у апаратне забезпечення: [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/))
|
||||
|
||||
Vendored
+33
@@ -1,3 +1,36 @@
|
||||
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!
|
||||
|
||||
@@ -1,3 +1,34 @@
|
||||
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!
|
||||
|
||||
+3
-3
@@ -98,7 +98,7 @@ Using a 64bit OS:
|
||||
|
||||
Using a 64bit OS:
|
||||
|
||||
Caution: please use gcc-11 or higher, older gcc dosen't know cortex-a78ae
|
||||
Caution: please use gcc-11 or higher, older gcc doesn't know cortex-a78ae
|
||||
```
|
||||
-D TEGRA_T234=1 -D CMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
```
|
||||
@@ -211,7 +211,7 @@ 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
|
||||
|
||||
@@ -245,7 +245,7 @@ You need to add `-DWITH_MOLD=1` if GNU ld is extremely slow. Then run `mold -run
|
||||
|
||||
#### Build a statically linked box64
|
||||
|
||||
You can now build box64 staticaly linked, with `-DSTATICBUILD`. This is to use inside an x86_64 chroot. Note that this version of box64 will have just the minimum of wrapped libs. So only libc, libm and libpthread basically are wrapped. Other libs (like libGL or libvulkan, SDL2, etc...) will not be wrapped and x86_64 version will be used. It's designed to be used in docker image, or in headless server.
|
||||
You can now build box64 statically linked, with `-DSTATICBUILD`. This is to use inside an x86_64 chroot. Note that this version of box64 will have just the minimum of wrapped libs. So only libc, libm and libpthread basically are wrapped. Other libs (like libGL or libvulkan, SDL2, etc...) will not be wrapped and x86_64 version will be used. It's designed to be used in docker image, or in headless server.
|
||||
Also, the Static Build is highly experimental, but feedback are always welcomed.
|
||||
|
||||
----
|
||||
|
||||
+58
-21
@@ -7,6 +7,8 @@ Env. var with * can also be put inside box64rc files.
|
||||
Box64 look for 2 places for rcfile: `/etc/box64.box64rc` and `~/.box64rc`
|
||||
The second takes precedence to the first, on an APP level
|
||||
(that means if an [MYAPP] my appears in both file, only the settings in `~/.box64rc` will be applied)
|
||||
There is also some égeneric" name, like [*SETUP*] that will be applied to every program containing "setup" in the name
|
||||
(Note that this is not a full regex rules, it's just a name between '[*' and '*]', nothing else)
|
||||
|
||||
#### BOX64_LOG *
|
||||
Controls the Verbosity level of the logs
|
||||
@@ -28,7 +30,7 @@ Disables Box64 printing its version and build
|
||||
|
||||
#### BOX64_LD_LIBRARY_PATH *
|
||||
Path to look for x86_64 libraries. Default is current folder and `lib` in current folder.
|
||||
Also, `/usr/lib/x86_64-linux-gnu` and `/lib/x86_64-linux-gnu` are added if they exist.
|
||||
Also, `/usr/lib/x86_64-linux-gnu`, `/lib/x86_64-linux-gnu` and `/usr/lib/box64-x86_64-linux-gnu` are added if they exist.
|
||||
|
||||
#### BOX64_PATH *
|
||||
Path to look for x86_64 executable. Default is current folder and `bin` in current folder.
|
||||
@@ -41,7 +43,7 @@ Enables/Disables the logging of `dlsym` errors.
|
||||
#### BOX64_TRACE_FILE *
|
||||
Send all log and trace to a file instead of `stdout`
|
||||
Also, if name contains `%pid` then this is replaced by the actual PID of box64 instance
|
||||
End the filename with `+` to have thetrace appended instead of overwritten
|
||||
End the filename with `+` to have the trace appended instead of overwritten
|
||||
Use `stderr` to use this instead of default `stdout`
|
||||
|
||||
#### BOX64_TRACE *
|
||||
@@ -95,7 +97,7 @@ Show Segfault signal even if a signal handler is present
|
||||
* 1 : Show SIGSEGV detail, even if a signal handler is present
|
||||
|
||||
#### BOX64_SHOWBT *
|
||||
Show some Backtrace (Nativ e and Emulated) whgen a signal (SEGV, ILL or BUS) is caught
|
||||
Show some Backtrace (Native and Emulated) when a signal (SEGV, ILL or BUS) is caught
|
||||
* 0 : Don"t show backtraces (Default.)
|
||||
* 1 : Show Backtrace detail (for native, box64 is rename as the x86_64 binary run)
|
||||
|
||||
@@ -143,14 +145,13 @@ Enables/Disables trace for generated code.
|
||||
* 1 : Enable trace for generated code (like regular Trace, this will slow down the program a lot and generate huge logs).
|
||||
|
||||
#### BOX64_NODYNAREC *
|
||||
Forbid dynablock creation in the interval specified (helpfull for debugging behaviour difference between Dynarec and Interpreter)
|
||||
Forbid dynablock creation in the interval specified (helpful for debugging behaviour difference between Dynarec and Interpreter)
|
||||
* 0xXXXXXXXX-0xYYYYYYYY : define the interval where dynablock cannot start (inclusive-exclusive)
|
||||
|
||||
#### BOX64_DYNAREC_TEST *
|
||||
Dynarec will compare it's execution with the interpreter (super slow, only for testing)
|
||||
* 0 : No comparison. (Default.)
|
||||
* 1 : Each opcode runs on interepter and on Dynarec, and regs and memory are compared and print if different.
|
||||
* 2 : Thread-safe tests, extremely slow.
|
||||
* 1 : Each opcode runs on interpreter and on Dynarec, and regs and memory are compared and print if different.
|
||||
* 0xXXXXXXXX-0xYYYYYYYY : define the interval where dynarec is tested (inclusive-exclusive)
|
||||
|
||||
#### BOX64_DYNAREC_BIGBLOCK *
|
||||
@@ -168,9 +169,22 @@ Define Box64's Dynarec max allowed forward value when building Block.
|
||||
#### BOX64_DYNAREC_STRONGMEM *
|
||||
Enable/Disable simulation of Strong Memory model
|
||||
* 0 : Don't try anything special (Default.)
|
||||
* 1 : Enable some Memory Barrier when writting to memory (on some MOV opcode) to simulate Strong Memory Model while trying to limit performance impact (Default when libmonobdwgc-2.0.so is loaded)
|
||||
* 2 : All 1. plus a memory barrier on every write to memory using MOV
|
||||
* 3 : All 2. plus Memory Barrier when reading from memory and on some SSE/SSE2 opcodes too
|
||||
* 1 : Enable some memory barriers when writing to memory to simulate the Strong Memory Model in a limited way (Default when libmonobdwgc-2.0.so is loaded)
|
||||
* 2 : All 1. plus memory barriers on SIMD instructions
|
||||
* 3 : All 2. plus more memory barriers on a regular basis
|
||||
|
||||
#### BOX64_DYNAREC_WEAKBARRIER *
|
||||
Tweaking the memory barriers to reduce the performance impact by STRONGMEM
|
||||
* 0 : Use regular safe barrier (Default.)
|
||||
* 1 : Use weak barriers to have more performance boost
|
||||
* 2 : All 1. Plus disabled the last write barriers
|
||||
|
||||
#### BOX64_DYNAREC_PAUSE *
|
||||
Enable/Disable x86 PAUSE emulation, which may help the performance of spinlocks
|
||||
* 0 : Ignore x86 PAUSE instruction (Default.)
|
||||
* 1 : Use YIELD to emulate x86 PAUSE instruction
|
||||
* 2 : Use WFI to emulate x86 PAUSE instruction
|
||||
* 3 : Use SEVL+WFE to emulate x86 PAUSE instruction
|
||||
|
||||
#### BOX64_DYNAREC_X87DOUBLE *
|
||||
Force the use of Double for x87 emulation
|
||||
@@ -186,6 +200,7 @@ Enable/Disable generation of -NAN
|
||||
Enable/Disable generation of precise x86 rounding
|
||||
* 0 : Generate float/double -> int rounding like on x86
|
||||
* 1 : Don't do anything special with edge case Rounding, to go as fast as possible (no INF/NAN/Overflow -> MIN_INT conversion) (default, faster)
|
||||
* 2 : Everything from 1 plus also fast round of double->float (not taking into account current rounding mode)
|
||||
|
||||
#### BOX64_DYNAREC_SAFEFLAGS *
|
||||
Handling of flags on CALL/RET opcodes
|
||||
@@ -201,7 +216,12 @@ Optimisation of CALL/RET opcodes (not compatible with jit/dynarec/smc)
|
||||
#### BOX64_DYNAREC_ALIGNED_ATOMICS *
|
||||
Generated code for aligned atomics only
|
||||
* 0 : The code generated can handle unaligned atomics (Default)
|
||||
* 1 : Generated code only for aligned atomics (faster and less code generated, but will SEGBUS if LOCK prefix is unsed on unaligned data)
|
||||
* 1 : Generated code only for aligned atomics (faster and less code generated, but will SEGBUS if LOCK prefix is unused on unaligned data)
|
||||
|
||||
#### BOX64_DYNAREC_NATIVEFLAGS *
|
||||
Generate code will use native flags if possible
|
||||
* 0 : The code generated whill not use native flags even when possible
|
||||
* 1 : Generated code will use native flags when possible (Arm64 only for now) (Default)
|
||||
|
||||
#### BOX64_DYNAREC_BLEEDING_EDGE *
|
||||
Detect MonoBleedingEdge and apply conservative settings
|
||||
@@ -214,7 +234,7 @@ Detect libjvm and apply conservative settings. Obsolete, use BOX64_JVM instead.
|
||||
* 1 : Detect libjvm, and apply BIGBLOCK=0 STRONGMEM=1 SSE42=0 if detected (Default)
|
||||
|
||||
#### BOX64_DYNAREC_WAIT *
|
||||
Behavior with FillBlock is not availble (FillBlock build Dynarec blocks and is not multithreaded)
|
||||
Behavior with FillBlock is not available (FillBlock build Dynarec blocks and is not multithreaded)
|
||||
* 0 : Dynarec will not wait for FillBlock to ready and use Interpreter instead (might speedup a bit massive multithread or JIT programs)
|
||||
* 1 : Dynarec will wait for FillBlock to be ready (Default)
|
||||
|
||||
@@ -222,6 +242,7 @@ Behavior with FillBlock is not availble (FillBlock build Dynarec blocks and is n
|
||||
Dynarec print the missing opcodes
|
||||
* 0 : not print the missing opcode (Default, unless DYNAREC_LOG>=1 or DYNAREC_DUMP>=1 is used)
|
||||
* 1 : Will print the missing opcodes
|
||||
* 2 : Will print the fallback to scalar opcodes (only valid on RISC-V)
|
||||
|
||||
#### BOX64_SSE_FLUSHTO0 *
|
||||
Handling of SSE Flush to 0 flags
|
||||
@@ -270,12 +291,12 @@ Need a workaround for SDL_GetJoystickGUIDInfo function for wrapped SDL2
|
||||
|
||||
#### BOX64_LD_PRELOAD
|
||||
* XXXX[:YYYYY] force loading XXXX (and YYYY...) libraries with the binary
|
||||
PreLoaded libs can be emulated or native, and are treated the same way as if they were comming from the binary
|
||||
PreLoaded libs can be emulated or native, and are treated the same way as if they were coming from the binary
|
||||
|
||||
#### BOX64_EMULATED_LIBS *
|
||||
* XXXX[:YYYYY] force lib XXXX (and YYYY...) to be emulated (and not wrapped)
|
||||
Some games uses an old version of some libraries, with an ABI incompatible with native version.
|
||||
Note that LittleInferno for example is auto detected, and libvorbis.so.0 is automatical added to emulated libs, and same for Don't Starve (and Together / Server variant) that use an old SDL2 too
|
||||
Note that LittleInferno for example is auto detected, and libvorbis.so.0 is automatically added to emulated libs, and same for Don't Starve (and Together / Server variant) that use an old SDL2 too
|
||||
|
||||
#### BOX64_ALLOWMISSINGLIBS *
|
||||
Allow Box64 to continue even if a library is missing.
|
||||
@@ -288,14 +309,19 @@ Box64 will use wrapped libs even if the lib is specified with absolute path
|
||||
* 1 : Use Wrapped native libs even if path is absolute
|
||||
|
||||
#### BOX64_PREFER_EMULATED *
|
||||
Box64 will prefer emulated libs first (execpt for glibc, alsa, pulse, GL, vulkan and X11
|
||||
* 0 : Native libs are prefered (Default.)
|
||||
* 1 : Emulated libs are prefered (Default for program running inside pressure-vessel)
|
||||
Box64 will prefer emulated libs first (except for glibc, alsa, pulse, GL, vulkan and X11
|
||||
* 0 : Native libs are preferred (Default.)
|
||||
* 1 : Emulated libs are preferred (Default for program running inside pressure-vessel)
|
||||
|
||||
#### BOX64_WRAP_EGL *
|
||||
Box64 will prefer wrapped libs for EGL and GLESv2
|
||||
* 0 : Emulated libs are preferred (Default)
|
||||
* 1 : Native libs are preferred
|
||||
|
||||
#### BOX64_CRASHHANDLER *
|
||||
Box64 will use a dummy crashhandler.so library
|
||||
* 0 : Use Emulated crashhandler.so library if needed
|
||||
* 1 : Use an internal dummy (completly empty) crashhandler.so library (defaut)
|
||||
* 1 : Use an internal dummy (completely empty) crashhandler.so library (default)
|
||||
|
||||
#### BOX64_MALLOC_HACK *
|
||||
How Box64 will handle hooking of malloc operators
|
||||
@@ -318,10 +344,15 @@ Disables the load of vulkan libraries.
|
||||
* 0 : Load vulkan libraries if found.
|
||||
* 1 : Disables the load of vulkan libraries, both the native and the i386 version (can be useful on Pi4, where the vulkan driver is not quite there yet.)
|
||||
|
||||
#### BOX64_SHAEXT *
|
||||
Expose or not SHAEXT (a.k.a. SHA_NI) capabilities
|
||||
* 0 : Do not expose SHAEXT capabilities
|
||||
* 1 : Expose SHAEXT capabilities (Default.)
|
||||
|
||||
#### BOX64_SSE42 *
|
||||
Expose or not SSE 4.2 capabilites
|
||||
* 0 : Do not expose SSE 4.2 capabilites (default when libjvm is detected)
|
||||
* 1 : Expose SSE 4.2 capabilites (Default.)
|
||||
Expose or not SSE 4.2 capabilities
|
||||
* 0 : Do not expose SSE 4.2 capabilities (default when libjvm is detected)
|
||||
* 1 : Expose SSE 4.2 capabilities (Default.)
|
||||
|
||||
#### BOX64_FUTEX_WAITV *
|
||||
Use of the new fuext_waitc syscall
|
||||
@@ -354,7 +385,7 @@ Define x86_64 bash to launch script
|
||||
`set waiting=0` to exit the infinite loop.
|
||||
* 2 : Launch `gdbserver` when a segfault, bus error or illegal instruction signal is trapped, attached to the offending process, and go in an endless loop, waiting.
|
||||
Use `gdb /PATH/TO/box64` and then `target remote 127.0.0.1:1234` to connect to the gdbserver (or use actual IP if not on the machine). After that, the procedure is the same as with ` BOX64_JITGDB=1`.
|
||||
This mode can be usefullwhen programs redirect all console output to a file (like Unity3D Games)
|
||||
This mode can be usefull when programs redirect all console output to a file (like Unity3D Games)
|
||||
* 3 : Launch `lldb` when a segfault, bus error or illegal instruction signal is trapped, attached to the offending process and go in an endless loop, waiting.
|
||||
|
||||
#### BOX64_NORCFILES
|
||||
@@ -384,6 +415,12 @@ Those variables are only valid inside a rcfile:
|
||||
* 0 : Nothing special
|
||||
* 1 : Added "-cef-disable-gpu-compositor" to command line arguments (usefull for steamwebhelper/cef based programs)
|
||||
|
||||
#### BOX64_ARGS
|
||||
If that var exist, it will be added as argument(s) to the command line if there is no current argument (it's ignored else). Note that "" are supported, but not ''
|
||||
|
||||
#### BOX64_INSERT_ARGS
|
||||
If that var exist, it will be inserted as firsts argument(s) to the command line. Note that "" are supported, but not ''
|
||||
|
||||
#### BOX64_EXIT
|
||||
* 0 : Nothing special
|
||||
* 1 : Just exit, don't try to run the program
|
||||
+37
-18
@@ -77,7 +77,7 @@ When set to 1, don't prints the banner including version and build.
|
||||
=item B<BOX64_LD_PRELOAD>=I<lib1>[:I<lib2>:...]
|
||||
|
||||
Force loading libraries with the binary. PreLoaded libs can be emulated or
|
||||
native, and are treated the same way as if they were comming from the binary.
|
||||
native, and are treated the same way as if they were coming from the binary.
|
||||
|
||||
=item B<BOX64_ENV>=I<env=val>
|
||||
|
||||
@@ -118,8 +118,8 @@ B<BOX64_LOG> > 1 (may need B<BOX64_SHOWSEGV=1> also)
|
||||
=item B<BOX64_LD_LIBRARY_PATH>=I</path/to/libs>
|
||||
|
||||
Path to look for x86_64 libraries. Default is current folder and C<lib> in
|
||||
current folder. Also, F</usr/lib/x86_64-linux-gnu> and
|
||||
F</lib/x86_64-linux-gnu> are added if they exist.
|
||||
current folder. Also, F</usr/lib/x86_64-linux-gnu>,
|
||||
F</lib/x86_64-linux-gnu> and F</usr/lib/box64-x86_64-linux-gnu> are added if they exist.
|
||||
|
||||
=item B<BOX64_PATH>=I</path/to/bins>
|
||||
|
||||
@@ -205,14 +205,14 @@ Disable handling of SigILL (to ease debugging mainly).
|
||||
|
||||
Show Segfault signal even if a signal handler is present
|
||||
|
||||
* 0 : Don"t force show the SIGSEGV analysis (Default.)
|
||||
* 0 : Don't force show the SIGSEGV analysis (Default.)
|
||||
* 1 : Show SIGSEGV detail, even if a signal handler is present
|
||||
|
||||
=item B<BOX64_SHOWBT>=I<0|1>
|
||||
|
||||
Show some Backtrace (Nativ e and Emulated) whgen a signal (SEGV, ILL or BUS) is caught
|
||||
Show some Backtrace (Nativ e and Emulated) when a signal (SEGV, ILL or BUS) is caught
|
||||
|
||||
* 0 : Don"t show backtraces (Default.)
|
||||
* 0 : Don't show backtraces (Default.)
|
||||
* 1 : Show Backtrace detail (for native, box64 is rename as the x86_64 binary run)
|
||||
|
||||
=item B<BOX64_X11THREADS>=I<0|1>
|
||||
@@ -263,7 +263,7 @@ down the program a lot and generate huge logs.
|
||||
|
||||
=item B<BOX64_NODYNAREC>=I<0xXXXXXXXX-0xYYYYYYYY>
|
||||
|
||||
Forbid dynablock creation in the interval specified (helpfull for debugging
|
||||
Forbid dynablock creation in the interval specified (helpful for debugging
|
||||
behaviour difference between Dynarec and Interpreter)
|
||||
|
||||
=item B<BOX64_DYNAREC_TEST>=I<0|1>
|
||||
@@ -272,7 +272,8 @@ Dynarec will compare it's execution with the interpreter (super slow, only for t
|
||||
|
||||
* 0 : No comparison. (Default.)
|
||||
* 1 : Each opcode runs on interepter and on Dynarec, and regs and memory are compared and print if different.
|
||||
* 2 : Thread-safe tests, extremely slow.
|
||||
* 0xXXXXXXXX-0xYYYYYYYY : Define the interval where dynarec is tested (inclusive-exclusive)
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_BIGBLOCK>=I<0|1|2|3>
|
||||
|
||||
@@ -290,13 +291,31 @@ Define Box64's Dynarec max allowed forward value when building Block.
|
||||
* 0 : No forward value. When current block end, don't try to go further even if there are previous forward jumps
|
||||
* XXX : Allow up to XXXX bytes of gap when building a Block after the block end to next forward jump (Default: 128)
|
||||
|
||||
=item B<BOX64_DYNAREC_STRONGMEM>=I<0|1|2>
|
||||
=item B<BOX64_DYNAREC_STRONGMEM>=I<0|1|2|3>
|
||||
|
||||
Enable/Disable simulation of Strong Memory model
|
||||
|
||||
* 0 : Don't try anything special (Default.)
|
||||
* 1 : Enable some Memory Barrier when reading from memory (on some MOV opcode) to simulate Strong Memory Model while trying to limit performance impact (Default when libmonobdwgc-2.0.so is loaded)
|
||||
* 2 : Enable some Memory Barrier when reading from memory (on some MOV opcode) to simulate Strong Memory Model
|
||||
* 1 : Enable some memory barriers when writing to memory to simulate the Strong Memory Model in a limited way (Default when libmonobdwgc-2.0.so is loaded)
|
||||
* 2 : All 1. plus memory barriers on SIMD instructions
|
||||
* 3 : All 2. plus more memory barriers on a regular basis
|
||||
|
||||
=item B<BOX64_DYNAREC_WEAKBARRIER>=I<0|1|2>
|
||||
|
||||
Tweaking the memory barriers to reduce the performance impact by STRONGMEM
|
||||
|
||||
* 0 : Use regular safe barrier (Default.)
|
||||
* 1 : Use weak barriers to have more performance boost
|
||||
* 2 : All 1. Plus disabled the last write barriers
|
||||
|
||||
=item B<BOX64_DYNAREC_PAUSE>=I<0|1|2|3>
|
||||
|
||||
Enable/Disable x86 PAUSE emulation, which may help the performance of spinlocks
|
||||
|
||||
* 0 : Ignore x86 PAUSE instruction (Default.)
|
||||
* 1 : Use YIELD to emulate x86 PAUSE instruction
|
||||
* 2 : Use WFI to emulate x86 PAUSE instruction
|
||||
* 3 : Use SEVL+WFE to emulate x86 PAUSE instruction
|
||||
|
||||
=item B<BOX64_DYNAREC_X87DOUBLE>=I<0|1>
|
||||
|
||||
@@ -343,7 +362,7 @@ Detect MonoBleedingEdge and apply conservative settings
|
||||
|
||||
=item B<BOX64_DYNAREC_WAIT>=I<0|1>
|
||||
|
||||
Behavior with FillBlock is not availble (FillBlock build Dynarec blocks and is not multithreaded)
|
||||
Behavior with FillBlock is not available (FillBlock build Dynarec blocks and is not multithreaded)
|
||||
|
||||
* 0 : Dynarec will not wait for FillBlock to ready and use Interpreter instead (might speedup a bit massive multithread or JIT programs)
|
||||
* 1 : Dynarec will wait for FillBlock to be ready (Default)
|
||||
@@ -388,7 +407,7 @@ You can also use B<SDL_VIDEO_GL_DRIVER>
|
||||
Force lib XXXX (and YYYY...) to be emulated (and not wrapped) Some games uses
|
||||
an old version of some libraries, with an ABI incompatible with native version.
|
||||
Note that LittleInferno for example is auto detected, and libvorbis.so.0 is
|
||||
automatical added to emulated libs, and same for Don't Starve (and Together /
|
||||
automatically added to emulated libs, and same for Don't Starve (and Together /
|
||||
Server variant) that use an old SDL2 too
|
||||
|
||||
=item B<BOX64_ALLOWMISSINGLIBS>=I<0|1>
|
||||
@@ -407,18 +426,18 @@ Box64 will use wrapped libs even if the lib is specified with absolute path
|
||||
|
||||
=item B<BOX64_PREFER_EMULATED>=I<0|1>
|
||||
|
||||
Box64 will prefer emulated libs first (execpt for glibc, alsa, pulse, GL,
|
||||
Box64 will prefer emulated libs first (except for glibc, alsa, pulse, GL,
|
||||
vulkan and X11
|
||||
|
||||
* 0 : Native libs are prefered (Default.)
|
||||
* 1 : Emulated libs are prefered (Default for program running inside pressure-vessel)
|
||||
* 0 : Native libs are preferred (Default.)
|
||||
* 1 : Emulated libs are preferred (Default for program running inside pressure-vessel)
|
||||
|
||||
=item B<BOX64_CRASHHANDLER>=I<0|1>
|
||||
|
||||
Box64 will use a dummy crashhandler.so library
|
||||
|
||||
* 0 : Use Emulated crashhandler.so library if needed
|
||||
* 1 : Use an internal dummy (completly empty) crashhandler.so library (defaut)
|
||||
* 1 : Use an internal dummy (completely empty) crashhandler.so library (default)
|
||||
|
||||
=item B<BOX64_MALLOC_HACK>=I<0|1|2>
|
||||
|
||||
@@ -465,7 +484,7 @@ script. yyyy needs to be a full path to a valid x86_64 version of bash
|
||||
|
||||
* 0 : Just print the Segfault message on segfault (default)
|
||||
* 1 : Launch `gdb` when a segfault, bus error or illegal instruction signal is trapped, attached to the offending process and go in an endless loop, waiting. When in gdb, you need to find the correct thread yourself (the one with `my_box64signalhandler` in is stack) then probably need to `finish` 1 or 2 functions (inside `usleep(..)`) and then you'll be in `my_box64signalhandler`, just before the printf of the Segfault message. Then simply `set waiting=0` to exit the infinite loop.
|
||||
* 2 : Launch `gdbserver` when a segfault, bus error or illegal instruction signal is trapped, attached to the offending process, and go in an endless loop, waiting. Use `gdb /PATH/TO/box64` and then `target remote 127.0.0.1:1234` to connect to the gdbserver (or use actual IP if not on the machine). After that, the procedure is the same as with ` BOX64_JITGDB=1`. This mode can be usefullwhen programs redirect all console output to a file (like Unity3D Games)
|
||||
* 2 : Launch `gdbserver` when a segfault, bus error or illegal instruction signal is trapped, attached to the offending process, and go in an endless loop, waiting. Use `gdb /PATH/TO/box64` and then `target remote 127.0.0.1:1234` to connect to the gdbserver (or use actual IP if not on the machine). After that, the procedure is the same as with ` BOX64_JITGDB=1`. This mode can be usefull when programs redirect all console output to a file (like Unity3D Games)
|
||||
|
||||
=back
|
||||
|
||||
|
||||
@@ -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."
|
||||
|
||||
+276
-66
@@ -150,14 +150,18 @@ class FunctionConvention(object):
|
||||
self.ident = ident
|
||||
self.name = convname
|
||||
self.values = valid_chars
|
||||
# Free letters: B FG J QR T YZa e gh jk mno qrst z
|
||||
# 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', 'Y', 'y', 'b']),
|
||||
'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', 'Y', 'y', 'b', '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:
|
||||
@@ -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)
|
||||
@@ -402,9 +406,11 @@ def readFiles(files: Iterable[Filename]) -> Tuple[JumbledGlobals, JumbledRedirec
|
||||
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
|
||||
|
||||
@@ -530,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:
|
||||
@@ -828,10 +847,10 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
|
||||
# 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: Dict[str, str] = {"ARM64": "EDKVOSNMHPAxXYyb", "RV64": "EcwiDKVOSNMHPAxXYyb"}
|
||||
forbidden_simple: Dict[str, str] = {"ARM64": "EDVOSNHPAxXYb", "RV64": "EcwiDVOSNHPAxXYb"}
|
||||
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))
|
||||
@@ -842,17 +861,18 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
assert(all(c not in allowed_simply[k1] + allowed_regs[k1] + allowed_fpr[k1] for c in forbidden_simple[k1]))
|
||||
assert(all(c in allowed_simply[k1] + allowed_regs[k1] + allowed_fpr[k1] + forbidden_simple[k1] for c in allowed_conv.values))
|
||||
assert(all(c in allowed_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))
|
||||
|
||||
simple_wraps: Dict[str, Dict[ClausesStr, List[Tuple[FunctionType, int]]]] = {
|
||||
k1: {} for k1 in forbidden_simple
|
||||
}
|
||||
|
||||
def check_simple(v: FunctionType) -> Dict[str, int]:
|
||||
regs_count: int = 0
|
||||
fpr_count : int = 0
|
||||
|
||||
ret = {}
|
||||
ret: Dict[str, int] = {}
|
||||
for k in forbidden_simple:
|
||||
regs_count: int = 0
|
||||
fpr_count : int = 0
|
||||
|
||||
if v.get_convention() is not allowed_conv:
|
||||
continue
|
||||
if v[0] in forbidden_simple[k]:
|
||||
@@ -930,6 +950,19 @@ 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);
|
||||
@@ -966,7 +999,6 @@ 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
|
||||
@@ -1033,20 +1065,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 Y 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", "double", "intptr_t", "uintptr_t", "void*", "void*", "int32_t", "void*", "...", "...", "unsigned __int128", "void*", "void*", "complexf_t", "complex_t", "complexl_t", "complex_t", "void*"],
|
||||
# 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))
|
||||
@@ -1069,10 +1140,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
|
||||
@@ -1080,22 +1151,19 @@ 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_complexl(emu, fn({0}));', # Y
|
||||
'from_complexk(emu, fn({0}));', # y
|
||||
"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']: [
|
||||
@@ -1111,32 +1179,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 Y y b
|
||||
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, 0, 0, 1]
|
||||
# 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 Y 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, 0, 0, 1, 2, 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
|
||||
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 Y y b
|
||||
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, 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 Y y b
|
||||
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, 4, 4, 1]
|
||||
# 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
|
||||
@@ -1151,7 +1234,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
|
||||
@@ -1159,14 +1241,12 @@ 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
|
||||
"", # y
|
||||
"", # Y
|
||||
"aligned_xcb, ", # b
|
||||
]
|
||||
arg_x = [
|
||||
@@ -1183,7 +1263,6 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
"emu->xmm[{p}].f[0], ", # f
|
||||
"emu->xmm[{p}].d[0], ", # d
|
||||
"", # D
|
||||
"", # K
|
||||
"", # l
|
||||
"", # L
|
||||
"", # p
|
||||
@@ -1191,14 +1270,12 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
"", # O
|
||||
"", # S
|
||||
"", # N
|
||||
"", # M
|
||||
"", # H
|
||||
"", # P
|
||||
"", # A
|
||||
"to_complexf(emu, {p}), ", # x
|
||||
"to_complex(emu, {p}), ", # X
|
||||
"", # Y
|
||||
"", # y
|
||||
"", # Y
|
||||
"", # b
|
||||
]
|
||||
arg_o = [
|
||||
@@ -1215,7 +1292,6 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
"", # f
|
||||
"", # d
|
||||
"", # D
|
||||
"", # K
|
||||
"", # l
|
||||
"", # L
|
||||
"", # p
|
||||
@@ -1223,14 +1299,12 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
"", # O
|
||||
"", # S
|
||||
"", # N
|
||||
"", # M
|
||||
"", # H
|
||||
"", # P
|
||||
"", # A
|
||||
"", # x
|
||||
"", # X
|
||||
"", # Y
|
||||
"", # y
|
||||
"", # Y
|
||||
"", # b
|
||||
]
|
||||
arg_s = [
|
||||
@@ -1247,7 +1321,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
|
||||
@@ -1255,16 +1328,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
|
||||
"*(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
|
||||
"to_complexk(emu, R_RSP + {p}), ", # y
|
||||
"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:
|
||||
@@ -1378,16 +1471,26 @@ 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
|
||||
@@ -1445,22 +1548,128 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
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")
|
||||
|
||||
@@ -1468,7 +1677,7 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
inttext = ""
|
||||
file.write("\n")
|
||||
for k1 in simple_idxs:
|
||||
file.write("#{inttext}if defined({k1})\nint isSimpleWrapper(wrapper_t fun) {{\n".format(inttext=inttext, k1=k1))
|
||||
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()):
|
||||
@@ -1478,9 +1687,10 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
if k != str(Clauses()):
|
||||
file.write("#endif\n")
|
||||
file.write("\treturn 0;\n}\n")
|
||||
file.write("\n#else\nint isSimpleWrapper(wrapper_t fun) {\n\treturn 0;\n}\n#endif\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()):
|
||||
@@ -1559,11 +1769,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.4.0.21") != 0:
|
||||
if main(sys.argv[1], sys.argv[limit[0]+1:], "2.5.0.24") != 0:
|
||||
exit(2)
|
||||
exit(0)
|
||||
Executable
+1647
File diff suppressed because it is too large.
Load diff
+2
-2
@@ -19,10 +19,10 @@ 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)
|
||||
set(ENV{BOX64_LD_LIBRARY_PATH} ${CMAKE_SOURCE_DIR}/x64lib)
|
||||
else()
|
||||
# we are inside build folder
|
||||
set(ENV{LD_LIBRARY_PATH} ${CMAKE_SOURCE_DIR}/../x64lib)
|
||||
set(ENV{BOX64_LD_LIBRARY_PATH} ${CMAKE_SOURCE_DIR}/../x64lib)
|
||||
endif( EXISTS ${CMAKE_SOURCE_DIR}/x64lib )
|
||||
|
||||
# run the test program, capture the stdout/stderr and the result var
|
||||
|
||||
+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];
|
||||
void* p1; //const unsigned short int *__ctype_b;
|
||||
void* p2; //const int *__ctype_tolower;
|
||||
void* p3; //const int *__ctype_toupper;
|
||||
void* p4[13];
|
||||
} 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_hashv(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(box_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);
|
||||
free(from_ptrv(ret));
|
||||
}
|
||||
pthread_rwlock_unlock(&hash_lock);
|
||||
return ret;
|
||||
}
|
||||
+29
-15
@@ -23,6 +23,9 @@
|
||||
#include "gltools.h"
|
||||
#include "rbtree.h"
|
||||
#include "dynarec.h"
|
||||
#ifdef BOX32
|
||||
#include "box32.h"
|
||||
#endif
|
||||
|
||||
EXPORTDYN
|
||||
void initAllHelpers(box64context_t* context)
|
||||
@@ -31,6 +34,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);
|
||||
@@ -47,6 +53,9 @@ void finiAllHelpers(box64context_t* context)
|
||||
fini_pthread_helper(context);
|
||||
fini_signal_helper();
|
||||
fini_bridge_helper();
|
||||
#ifdef BOX32
|
||||
fini_hash_helper();
|
||||
#endif
|
||||
fini_custommem_helper(context);
|
||||
finied = 1;
|
||||
}
|
||||
@@ -75,6 +84,7 @@ void free_tlsdatasize(void* p)
|
||||
}
|
||||
|
||||
void x64Syscall(x64emu_t *emu);
|
||||
void x86Syscall(x64emu_t *emu);
|
||||
|
||||
int unlockMutex()
|
||||
{
|
||||
@@ -128,7 +138,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;
|
||||
@@ -213,25 +223,27 @@ box64context_t *NewBox64Context(int argc)
|
||||
|
||||
init_custommem_helper(context);
|
||||
|
||||
#ifdef DYNAREC
|
||||
x64test_init();
|
||||
#endif
|
||||
|
||||
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
|
||||
@@ -275,7 +287,7 @@ box64context_t *NewBox64Context(int argc)
|
||||
initAllHelpers(context);
|
||||
|
||||
#ifdef DYNAREC
|
||||
context->db_sizes = init_rbtree();
|
||||
context->db_sizes = rbtree_init("db_sizes");
|
||||
#endif
|
||||
|
||||
return context;
|
||||
@@ -351,6 +363,8 @@ void FreeBox64Context(box64context_t** context)
|
||||
#ifndef STATICBUILD
|
||||
freeGLProcWrapper(ctx);
|
||||
freeALProcWrapper(ctx);
|
||||
#ifdef BOX32
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if(ctx->stack_clone)
|
||||
@@ -377,7 +391,7 @@ void FreeBox64Context(box64context_t** context)
|
||||
|
||||
#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));
|
||||
delete_rbtree(ctx->db_sizes);
|
||||
rbtree_delete(ctx->db_sizes);
|
||||
#endif
|
||||
|
||||
finiAllHelpers(ctx);
|
||||
|
||||
+1
-1
@@ -3,6 +3,6 @@
|
||||
|
||||
#define BOX64_MAJOR 0
|
||||
#define BOX64_MINOR 3
|
||||
#define BOX64_REVISION 0
|
||||
#define BOX64_REVISION 2
|
||||
|
||||
#endif //__BOX64_VERSION_H_
|
||||
+412
-134
@@ -46,6 +46,7 @@ int box64_exit_code = 0;
|
||||
int box64_log = LOG_INFO; //LOG_NONE;
|
||||
int box64_dump = 0;
|
||||
int box64_nobanner = 0;
|
||||
int box64_stdout_no_w = 0;
|
||||
int box64_dynarec_log = LOG_NONE;
|
||||
uintptr_t box64_pagesize;
|
||||
uintptr_t box64_load_addr = 0;
|
||||
@@ -55,9 +56,11 @@ int box64_cefdisablegpu = 0;
|
||||
int box64_cefdisablegpucompositor = 0;
|
||||
int box64_malloc_hack = 0;
|
||||
int box64_dynarec_test = 0;
|
||||
int box64_x11sync = 0;
|
||||
path_collection_t box64_addlibs = {0};
|
||||
int box64_maxcpu = 0;
|
||||
int box64_maxcpu_immutable = 0;
|
||||
int box64_is32bits = 0;
|
||||
#if defined(SD845) || defined(SD888) || defined(SD8G2) || defined(TEGRAX1)
|
||||
int box64_mmap32 = 1;
|
||||
#else
|
||||
@@ -67,6 +70,8 @@ int box64_ignoreint3 = 0;
|
||||
int box64_rdtsc = 0;
|
||||
int box64_rdtsc_1ghz = 0;
|
||||
uint8_t box64_rdtsc_shift = 0;
|
||||
char* box64_insert_args = NULL;
|
||||
char* box64_new_args = NULL;
|
||||
#ifdef DYNAREC
|
||||
int box64_dynarec = 1;
|
||||
int box64_dynarec_dump = 0;
|
||||
@@ -74,6 +79,8 @@ int box64_dynarec_forced = 0;
|
||||
int box64_dynarec_bigblock = 1;
|
||||
int box64_dynarec_forward = 128;
|
||||
int box64_dynarec_strongmem = 0;
|
||||
int box64_dynarec_weakbarrier = 1;
|
||||
int box64_dynarec_pause = 3;
|
||||
int box64_dynarec_x87double = 0;
|
||||
int box64_dynarec_div0 = 0;
|
||||
int box64_dynarec_fastnan = 1;
|
||||
@@ -85,6 +92,7 @@ int box64_dynarec_tbb = 1;
|
||||
int box64_dynarec_wait = 1;
|
||||
int box64_dynarec_missing = 0;
|
||||
int box64_dynarec_aligned_atomics = 0;
|
||||
int box64_dynarec_nativeflags = 1;
|
||||
uintptr_t box64_nodynarec_start = 0;
|
||||
uintptr_t box64_nodynarec_end = 0;
|
||||
uintptr_t box64_dynarec_test_start = 0;
|
||||
@@ -108,7 +116,9 @@ int rv64_zba = 0;
|
||||
int rv64_zbb = 0;
|
||||
int rv64_zbc = 0;
|
||||
int rv64_zbs = 0;
|
||||
int rv64_vector = 0;
|
||||
int rv64_vector = 0; // rvv 1.0 or xtheadvector
|
||||
int rv64_xtheadvector = 0;
|
||||
int rv64_vlen = 0;
|
||||
int rv64_xtheadba = 0;
|
||||
int rv64_xtheadbb = 0;
|
||||
int rv64_xtheadbs = 0;
|
||||
@@ -151,9 +161,11 @@ int box64_x11glx = 1;
|
||||
int allow_missing_libs = 0;
|
||||
int box64_prefer_emulated = 0;
|
||||
int box64_prefer_wrapped = 0;
|
||||
int box64_wrap_egl = 0;
|
||||
int box64_sse_flushto0 = 0;
|
||||
int box64_x87_no80bits = 0;
|
||||
int box64_sync_rounding = 0;
|
||||
int box64_shaext = 1;
|
||||
int box64_sse42 = 1;
|
||||
#if defined(DYNAREC) && defined(ARM64)
|
||||
int box64_avx = 1;
|
||||
@@ -167,6 +179,7 @@ int box64_dummy_crashhandler = 1;
|
||||
int box64_mapclean = 0;
|
||||
int box64_zoom = 0;
|
||||
int box64_steam = 0;
|
||||
int box64_steamcmd = 0;
|
||||
int box64_wine = 0;
|
||||
int box64_musl = 0;
|
||||
int box64_nopulse = 0;
|
||||
@@ -185,6 +198,7 @@ char* box64_custom_gstreamer = NULL;
|
||||
uintptr_t fmod_smc_start = 0;
|
||||
uintptr_t fmod_smc_end = 0;
|
||||
uint32_t default_gs = 0x53;
|
||||
uint32_t default_fs = 0;
|
||||
int jit_gdb = 0;
|
||||
int box64_tcmalloc_minimal = 0;
|
||||
|
||||
@@ -192,7 +206,7 @@ FILE* ftrace = NULL;
|
||||
char* ftrace_name = NULL;
|
||||
int ftrace_has_pid = 0;
|
||||
|
||||
void openFTrace(const char* newtrace)
|
||||
void openFTrace(const char* newtrace, int reopen)
|
||||
{
|
||||
const char* t = newtrace?newtrace:getenv("BOX64_TRACE_FILE");
|
||||
#ifndef MAX_PATH
|
||||
@@ -206,30 +220,35 @@ void openFTrace(const char* newtrace)
|
||||
strncpy(tmp2, p, sizeof(tmp2));
|
||||
tmp2[strlen(p)-1]='\0';
|
||||
p = tmp2;
|
||||
append=1;
|
||||
append = 1;
|
||||
}
|
||||
if(p && strstr(p, "%pid")) {
|
||||
int next = 0;
|
||||
do {
|
||||
strcpy(tmp, p);
|
||||
char* c = strstr(tmp, "%pid");
|
||||
*c = 0; // cut
|
||||
char pid[16];
|
||||
if(next)
|
||||
sprintf(pid, "%d-%d", getpid(), next);
|
||||
else
|
||||
sprintf(pid, "%d", getpid());
|
||||
strcat(tmp, pid);
|
||||
c = strstr(p, "%pid") + strlen("%pid");
|
||||
strcat(tmp, c);
|
||||
++next;
|
||||
} while (FileExist(tmp, IS_FILE) && !append);
|
||||
p = tmp;
|
||||
ftrace_has_pid = 1;
|
||||
if (reopen) {
|
||||
p = ftrace_name;
|
||||
append = 1;
|
||||
} else {
|
||||
if (p && strstr(p, "%pid")) {
|
||||
int next = 0;
|
||||
do {
|
||||
strcpy(tmp, p);
|
||||
char* c = strstr(tmp, "%pid");
|
||||
*c = 0; // cut
|
||||
char pid[16];
|
||||
if (next)
|
||||
sprintf(pid, "%d-%d", getpid(), next);
|
||||
else
|
||||
sprintf(pid, "%d", getpid());
|
||||
strcat(tmp, pid);
|
||||
c = strstr(p, "%pid") + strlen("%pid");
|
||||
strcat(tmp, c);
|
||||
++next;
|
||||
} while (FileExist(tmp, IS_FILE) && !append);
|
||||
p = tmp;
|
||||
ftrace_has_pid = 1;
|
||||
}
|
||||
if (ftrace_name)
|
||||
free(ftrace_name);
|
||||
ftrace_name = NULL;
|
||||
}
|
||||
if(ftrace_name)
|
||||
free(ftrace_name);
|
||||
ftrace_name = NULL;
|
||||
if(p) {
|
||||
if(!strcmp(p, "stderr"))
|
||||
ftrace = stderr;
|
||||
@@ -242,11 +261,13 @@ void openFTrace(const char* newtrace)
|
||||
ftrace = stdout;
|
||||
printf_log(LOG_INFO, "Cannot open trace file \"%s\" for writing (error=%s)\n", p, strerror(errno));
|
||||
} else {
|
||||
ftrace_name = strdup(p);
|
||||
if (!reopen) ftrace_name = strdup(p);
|
||||
/*fclose(ftrace);
|
||||
ftrace = NULL;*/
|
||||
if(!box64_nobanner)
|
||||
if(!box64_nobanner) {
|
||||
printf("BOX64 Trace %s to \"%s\"\n", append?"appended":"redirected", p);
|
||||
box64_stdout_no_w = 1;
|
||||
}
|
||||
PrintBox64Version();
|
||||
}
|
||||
}
|
||||
@@ -270,14 +291,27 @@ void printf_ftrace(const char* fmt, ...)
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void my_prepare_fork()
|
||||
{
|
||||
if (ftrace_has_pid && ftrace && ftrace != stdout && ftrace != stderr) {
|
||||
fclose(ftrace);
|
||||
printf_log(LOG_INFO, "Closed trace file of %s at prepare\n", GetLastApplyName());
|
||||
}
|
||||
}
|
||||
|
||||
void my_parent_fork()
|
||||
{
|
||||
if (ftrace_has_pid) {
|
||||
openFTrace(NULL, 1);
|
||||
printf_log(LOG_INFO, "Reopened trace file of %s at parent\n", GetLastApplyName());
|
||||
}
|
||||
}
|
||||
|
||||
void my_child_fork()
|
||||
{
|
||||
if(ftrace_has_pid) {
|
||||
// open a new ftrace...
|
||||
if(!ftrace_name)
|
||||
fclose(ftrace);
|
||||
openFTrace(NULL);
|
||||
printf_log(/*LOG_DEBUG*/LOG_INFO, "Forked child of %s\n", GetLastApplyName());
|
||||
if (ftrace_has_pid) {
|
||||
openFTrace(NULL, 0);
|
||||
printf_log(LOG_INFO, "Created trace file of %s at child\n", GetLastApplyName());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -480,15 +514,15 @@ HWCAP2_AFP
|
||||
if(p == NULL || p[0] == '0') {
|
||||
uint32_t cpucfg2 = 0, idx = 2;
|
||||
asm volatile("cpucfg %0, %1" : "=r"(cpucfg2) : "r"(idx));
|
||||
if ((cpucfg2 >> 6) & 0b1) {
|
||||
printf_log(LOG_INFO, "with extension LSX");
|
||||
if (((cpucfg2 >> 6) & 0b11) == 3) {
|
||||
printf_log(LOG_INFO, "with extension LSX LASX");
|
||||
} else {
|
||||
printf_log(LOG_INFO, "\nMissing LSX extension support, disabling Dynarec\n");
|
||||
printf_log(LOG_INFO, "\nMissing LSX and/or LASX extension support, disabling Dynarec\n");
|
||||
box64_dynarec = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if ((la64_lbt = (cpucfg2 >> 18) & 0b1))
|
||||
if (la64_lbt = (((cpucfg2 >> 18) & 0b1) && box64_dynarec_nativeflags))
|
||||
printf_log(LOG_INFO, " LBT_X86");
|
||||
if ((la64_lam_bh = (cpucfg2 >> 27) & 0b1))
|
||||
printf_log(LOG_INFO, " LAM_BH");
|
||||
@@ -499,25 +533,53 @@ HWCAP2_AFP
|
||||
}
|
||||
#elif defined(RV64)
|
||||
void RV64_Detect_Function();
|
||||
// private env. variable for the developer ;)
|
||||
char *p = getenv("BOX64_DYNAREC_RV64NOEXT");
|
||||
if(p == NULL || p[0] == '0')
|
||||
if(p == NULL || strcasecmp(p, "1")) {
|
||||
RV64_Detect_Function();
|
||||
if (p) {
|
||||
p = strtok(p, ",");
|
||||
while (p) {
|
||||
if (!strcasecmp(p, "zba")) rv64_zba = 0;
|
||||
if (!strcasecmp(p, "zbb")) rv64_zbb = 0;
|
||||
if (!strcasecmp(p, "zbc")) rv64_zbc = 0;
|
||||
if (!strcasecmp(p, "zbs")) rv64_zbs = 0;
|
||||
if (!strcasecmp(p, "vector")) {
|
||||
rv64_vector = 0;
|
||||
rv64_xtheadvector = 0;
|
||||
}
|
||||
if (!strcasecmp(p, "xtheadba")) rv64_xtheadba = 0;
|
||||
if (!strcasecmp(p, "xtheadbb")) rv64_xtheadbb = 0;
|
||||
if (!strcasecmp(p, "xtheadbs")) rv64_xtheadbs = 0;
|
||||
// if (!strcasecmp(p, "xtheadmemidx")) rv64_xtheadmemidx = 0;
|
||||
// if (!strcasecmp(p, "xtheadfmemidx")) rv64_xtheadfmemidx = 0;
|
||||
// if (!strcasecmp(p, "xtheadmac")) rv64_xtheadmac = 0;
|
||||
// if (!strcasecmp(p, "xtheadfmv")) rv64_xtheadfmv = 0;
|
||||
if (!strcasecmp(p, "xtheadmempair")) rv64_xtheadmempair = 0;
|
||||
if (!strcasecmp(p, "xtheadcondmov")) rv64_xtheadcondmov = 0;
|
||||
p = strtok(NULL, ",");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf_log(LOG_INFO, "Dynarec for RISC-V ");
|
||||
printf_log(LOG_INFO, "With extension: I M A F D C");
|
||||
if(rv64_zba) printf_log(LOG_INFO, " Zba");
|
||||
if(rv64_zbb) printf_log(LOG_INFO, " Zbb");
|
||||
if(rv64_zbc) printf_log(LOG_INFO, " Zbc");
|
||||
if(rv64_zbs) printf_log(LOG_INFO, " Zbs");
|
||||
if(rv64_vector) printf_log(LOG_INFO, " Vector");
|
||||
if (rv64_vector && !rv64_xtheadvector) printf_log(LOG_INFO, " Vector (vlen: %d)", rv64_vlen);
|
||||
if (rv64_xtheadvector) printf_log(LOG_INFO, " XTheadVector (vlen: %d)", rv64_vlen);
|
||||
if(rv64_xtheadba) printf_log(LOG_INFO, " XTheadBa");
|
||||
if(rv64_xtheadbb) printf_log(LOG_INFO, " XTheadBb");
|
||||
if(rv64_xtheadbs) printf_log(LOG_INFO, " XTheadBs");
|
||||
if(rv64_xtheadcondmov) printf_log(LOG_INFO, " XTheadCondMov");
|
||||
if(rv64_xtheadmemidx) printf_log(LOG_INFO, " XTheadMemIdx");
|
||||
if(rv64_xtheadmempair) printf_log(LOG_INFO, " XTheadMemPair");
|
||||
if(rv64_xtheadfmemidx) printf_log(LOG_INFO, " XTheadFMemIdx");
|
||||
if(rv64_xtheadmac) printf_log(LOG_INFO, " XTheadMac");
|
||||
if(rv64_xtheadfmv) printf_log(LOG_INFO, " XTheadFmv");
|
||||
if (rv64_xtheadmempair) printf_log(LOG_INFO, " XTheadMemPair");
|
||||
if (rv64_xtheadcondmov) printf_log(LOG_INFO, " XTheadCondMov");
|
||||
// Disable the display since these are only detected but never used.
|
||||
// if(rv64_xtheadmemidx) printf_log(LOG_INFO, " XTheadMemIdx");
|
||||
// if(rv64_xtheadfmemidx) printf_log(LOG_INFO, " XTheadFMemIdx");
|
||||
// if(rv64_xtheadmac) printf_log(LOG_INFO, " XTheadMac");
|
||||
// if(rv64_xtheadfmv) printf_log(LOG_INFO, " XTheadFmv");
|
||||
#else
|
||||
#error Unsupported architecture
|
||||
#endif
|
||||
@@ -577,7 +639,7 @@ void LoadLogEnv()
|
||||
}
|
||||
}
|
||||
// grab BOX64_TRACE_FILE envvar, and change %pid to actual pid is present in the name
|
||||
openFTrace(NULL);
|
||||
openFTrace(NULL, 0);
|
||||
box64_log = ftrace_name?LOG_INFO:(isatty(fileno(stdout))?LOG_INFO:LOG_NONE); //default LOG value different if stdout is redirected or not
|
||||
p = getenv("BOX64_LOG");
|
||||
if(p) {
|
||||
@@ -604,6 +666,8 @@ void LoadLogEnv()
|
||||
if(!box64_nobanner)
|
||||
printf_log(LOG_INFO, "Debug level is %d\n", box64_log);
|
||||
}
|
||||
if((box64_nobanner || box64_log) && ftrace==stdout)
|
||||
box64_stdout_no_w = 1;
|
||||
|
||||
#if !defined(DYNAREC) && (defined(ARM64) || defined(RV64) || defined(LA64))
|
||||
printf_log(LOG_INFO, "Warning: DynaRec is available on this host architecture, an interpreter-only build is probably not intended.\n");
|
||||
@@ -643,7 +707,7 @@ void LoadLogEnv()
|
||||
p = getenv("BOX64_DYNAREC_DUMP");
|
||||
if(p) {
|
||||
if(strlen(p)==1) {
|
||||
if(p[0]>='0' && p[0]<='2')
|
||||
if (p[0] >= '0' && p[0] <= '2')
|
||||
box64_dynarec_dump = p[0]-'0';
|
||||
}
|
||||
if (box64_dynarec_dump) printf_log(LOG_INFO, "Dynarec blocks are dumped%s\n", (box64_dynarec_dump>1)?" in color":"");
|
||||
@@ -715,6 +779,31 @@ void LoadLogEnv()
|
||||
if(box64_dynarec_strongmem)
|
||||
printf_log(LOG_INFO, "Dynarec will try to emulate a strong memory model%s\n", (box64_dynarec_strongmem==1)?" with limited performance loss":((box64_dynarec_strongmem>1)?" with more performance loss":""));
|
||||
}
|
||||
p = getenv("BOX64_DYNAREC_WEAKBARRIER");
|
||||
if (p) {
|
||||
if (strlen(p) == 1) {
|
||||
if (p[0] >= '0' && p[0] <= '2')
|
||||
box64_dynarec_weakbarrier = p[0] - '0';
|
||||
}
|
||||
if (box64_dynarec_weakbarrier)
|
||||
printf_log(LOG_INFO, "Dynarec will try to use weaker memory barriers to reduce the performance loss introduce by strong memory emulation\n");
|
||||
else
|
||||
printf_log(LOG_INFO, "Dynarec will not use weakbarrier on strong memory emulation\n");
|
||||
}
|
||||
#ifdef ARM64
|
||||
p = getenv("BOX64_DYNAREC_PAUSE");
|
||||
if (p) {
|
||||
if (strlen(p) == 1) {
|
||||
if (p[0] >= '0' && p[0] <= '3')
|
||||
box64_dynarec_pause = p[0] - '0';
|
||||
}
|
||||
if (box64_dynarec_pause)
|
||||
printf_log(LOG_INFO, "Dynarec will use %s to emulate pause instruction\n",
|
||||
box64_dynarec_pause == 1 ? "yield" : (box64_dynarec_pause == 2 ? "wfi" : "wfe"));
|
||||
else
|
||||
printf_log(LOG_INFO, "Dynarec will generate nothing for the pause instuction\n");
|
||||
}
|
||||
#endif
|
||||
p = getenv("BOX64_DYNAREC_X87DOUBLE");
|
||||
if(p) {
|
||||
if(strlen(p)==1) {
|
||||
@@ -745,11 +834,13 @@ void LoadLogEnv()
|
||||
p = getenv("BOX64_DYNAREC_FASTROUND");
|
||||
if(p) {
|
||||
if(strlen(p)==1) {
|
||||
if(p[0]>='0' && p[0]<='1')
|
||||
if(p[0]>='0' && p[0]<='2')
|
||||
box64_dynarec_fastround = p[0]-'0';
|
||||
}
|
||||
if(!box64_dynarec_fastround)
|
||||
printf_log(LOG_INFO, "Dynarec will try to generate x86 precise IEEE->int rounding\n");
|
||||
else if(box64_dynarec_fastround==2)
|
||||
printf_log(LOG_INFO, "Dynarec will generate x86 very imprecise double->float rounding\n");
|
||||
}
|
||||
p = getenv("BOX64_DYNAREC_SAFEFLAGS");
|
||||
if(p) {
|
||||
@@ -818,14 +909,25 @@ void LoadLogEnv()
|
||||
if(box64_dynarec_aligned_atomics)
|
||||
printf_log(LOG_INFO, "Dynarec will generate only aligned atomics code\n");
|
||||
}
|
||||
p = getenv("BOX64_DYNAREC_MISSING");
|
||||
p = getenv("BOX64_DYNAREC_NATIVEFLAGS");
|
||||
if(p) {
|
||||
if(strlen(p)==1) {
|
||||
if(p[0]>='0' && p[0]<='1')
|
||||
box64_dynarec_nativeflags = p[0]-'0';
|
||||
}
|
||||
if(!box64_dynarec_nativeflags)
|
||||
printf_log(LOG_INFO, "Dynarec will not use native flags if possible\n");
|
||||
}
|
||||
p = getenv("BOX64_DYNAREC_MISSING");
|
||||
if(p) {
|
||||
if(strlen(p)==1) {
|
||||
if(p[0]>='0' && p[0]<='2')
|
||||
box64_dynarec_missing = p[0]-'0';
|
||||
}
|
||||
if(box64_dynarec_missing)
|
||||
if(box64_dynarec_missing==1)
|
||||
printf_log(LOG_INFO, "Dynarec will print missing opcodes\n");
|
||||
else if (box64_dynarec_missing==2)
|
||||
printf_log(LOG_INFO, "Dynarec will print fallback to scalar opcodes\n");
|
||||
}
|
||||
p = getenv("BOX64_NODYNAREC");
|
||||
if(p) {
|
||||
@@ -840,7 +942,7 @@ void LoadLogEnv()
|
||||
p = getenv("BOX64_DYNAREC_TEST");
|
||||
if(p) {
|
||||
if(strlen(p)==1) {
|
||||
if(p[0]>='0' && p[0]<='2')
|
||||
if(p[0]>='0' && p[0]<='1')
|
||||
box64_dynarec_test = p[0]-'0';
|
||||
box64_dynarec_test_start = 0x0;
|
||||
box64_dynarec_test_end = 0x0;
|
||||
@@ -864,9 +966,10 @@ void LoadLogEnv()
|
||||
box64_dynarec_x87double = 1;
|
||||
box64_dynarec_div0 = 1;
|
||||
box64_dynarec_callret = 0;
|
||||
printf_log(LOG_INFO, "Dynarec will compare it's execution with the interpreter%s (%s slow, only for testing)\n",
|
||||
box64_dynarec_test == 2 ? " thread-safely" : "",
|
||||
box64_dynarec_test == 2 ? "extremely" : "super");
|
||||
#ifdef RV64
|
||||
box64_dynarec_nativeflags = 0;
|
||||
#endif
|
||||
printf_log(LOG_INFO, "Dynarec will compare it's execution with the interpreter (super slow, only for testing)\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1065,6 +1168,15 @@ void LoadLogEnv()
|
||||
printf_log(LOG_INFO, "Disable the use of futex waitv syscall\n");
|
||||
#endif
|
||||
}
|
||||
p = getenv("BOX64_SHAEXT");
|
||||
if(p) {
|
||||
if(strlen(p)==1) {
|
||||
if(p[0]>='0' && p[0]<='0'+1)
|
||||
box64_shaext = p[0]-'0';
|
||||
}
|
||||
if(!box64_shaext)
|
||||
printf_log(LOG_INFO, "Do not expose SHAEXT capabilities\n");
|
||||
}
|
||||
p = getenv("BOX64_SSE42");
|
||||
if(p) {
|
||||
if(strlen(p)==1) {
|
||||
@@ -1170,6 +1282,13 @@ void LoadLogEnv()
|
||||
if(box64_ignoreint3)
|
||||
printf_log(LOG_INFO, "Will silently ignore INT3 in the code\n");
|
||||
}
|
||||
p = getenv("BOX64_X11SYNC");
|
||||
if(p) {
|
||||
if(strlen(p)==1) {
|
||||
if(p[0]>='0' && p[0]<='0'+1)
|
||||
box64_x11sync = p[0]-'0';
|
||||
}
|
||||
}
|
||||
// grab pagesize
|
||||
box64_pagesize = sysconf(_SC_PAGESIZE);
|
||||
if(!box64_pagesize)
|
||||
@@ -1256,7 +1375,11 @@ int GatherEnv(char*** dest, char** env, char* prog)
|
||||
(*dest)[idx++] = box_strdup("BOX64_PATH=.:bin");
|
||||
}
|
||||
if(!ld_path) {
|
||||
#ifdef BOX32
|
||||
(*dest)[idx++] = box_strdup("BOX64_LD_LIBRARY_PATH=.:lib:lib64:x86_64:bin64:libs64:i386:libs:bin");
|
||||
#else
|
||||
(*dest)[idx++] = box_strdup("BOX64_LD_LIBRARY_PATH=.:lib:lib64:x86_64:bin64:libs64");
|
||||
#endif
|
||||
}
|
||||
// add "_=prog" at the end...
|
||||
if(prog) {
|
||||
@@ -1369,24 +1492,7 @@ void LoadEnvVars(box64context_t *context)
|
||||
}
|
||||
} while(p);
|
||||
}
|
||||
// check BOX64_LD_LIBRARY_PATH and load it
|
||||
LoadEnvPath(&context->box64_ld_lib, ".:lib:lib64:x86_64:bin64:libs64", "BOX64_LD_LIBRARY_PATH");
|
||||
#ifndef TERMUX
|
||||
if(FileExist("/lib/x86_64-linux-gnu", 0))
|
||||
AddPath("/lib/x86_64-linux-gnu", &context->box64_ld_lib, 1);
|
||||
if(FileExist("/usr/lib/x86_64-linux-gnu", 0))
|
||||
AddPath("/usr/lib/x86_64-linux-gnu", &context->box64_ld_lib, 1);
|
||||
if(FileExist("/usr/x86_64-linux-gnu/lib", 0))
|
||||
AddPath("/usr/x86_64-linux-gnu/lib", &context->box64_ld_lib, 1);
|
||||
if(FileExist("/data/data/com.termux/files/usr/glibc/lib/x86_64-linux-gnu", 0))
|
||||
AddPath("/data/data/com.termux/files/usr/glibc/lib/x86_64-linux-gnu", &context->box64_ld_lib, 1);
|
||||
#else
|
||||
//TODO: Add Termux Library Path - Lily
|
||||
if(FileExist("/data/data/com.termux/files/usr/lib/x86_64-linux-gnu", 0))
|
||||
AddPath("/data/data/com.termux/files/usr/lib/x86_64-linux-gnu", &context->box64_ld_lib, 1);
|
||||
#endif
|
||||
if(getenv("LD_LIBRARY_PATH"))
|
||||
PrependList(&context->box64_ld_lib, getenv("LD_LIBRARY_PATH"), 1); // in case some of the path are for x86 world
|
||||
|
||||
if(getenv("BOX64_EMULATED_LIBS")) {
|
||||
char* p = getenv("BOX64_EMULATED_LIBS");
|
||||
ParseList(p, &context->box64_emulated_libs, 0);
|
||||
@@ -1405,6 +1511,7 @@ void LoadEnvVars(box64context_t *context)
|
||||
AddPath("libunwind.so.8", &context->box64_emulated_libs, 0);
|
||||
AddPath("libpng12.so.0", &context->box64_emulated_libs, 0);
|
||||
AddPath("libcurl.so.4", &context->box64_emulated_libs, 0);
|
||||
//AddPath("libgnutls.so.30", &context->box64_emulated_libs, 0);
|
||||
AddPath("libtbbmalloc.so.2", &context->box64_emulated_libs, 0);
|
||||
AddPath("libtbbmalloc_proxy.so.2", &context->box64_emulated_libs, 0);
|
||||
|
||||
@@ -1423,7 +1530,7 @@ void LoadEnvVars(box64context_t *context)
|
||||
if(getenv("BOX64_SYNC_ROUNDING")) {
|
||||
if (strcmp(getenv("BOX64_SYNC_ROUNDING"), "1")==0) {
|
||||
box64_sync_rounding = 1;
|
||||
printf_log(LOG_INFO, "BOX64: Rouding mode with be synced with fesetround/fegetround\n");
|
||||
printf_log(LOG_INFO, "BOX64: Rounding mode will be synced with fesetround/fegetround\n");
|
||||
}
|
||||
}
|
||||
if(getenv("BOX64_PREFER_WRAPPED")) {
|
||||
@@ -1438,6 +1545,13 @@ void LoadEnvVars(box64context_t *context)
|
||||
printf_log(LOG_INFO, "BOX64: Prefering Emulated libs\n");
|
||||
}
|
||||
}
|
||||
if(getenv("BOX64_WRAP_EGL")) {
|
||||
char* p = getenv("BOX64_WRAP_EGL");
|
||||
if (*p>='0' && *p<='1') {
|
||||
box64_wrap_egl = *p - '0';
|
||||
if(box64_wrap_egl) printf_log(LOG_INFO, "BOX64: Prefering Native(Wrapped) EGL/GLESv2\n");
|
||||
}
|
||||
}
|
||||
|
||||
if(getenv("BOX64_NOSIGSEGV")) {
|
||||
if (strcmp(getenv("BOX64_NOSIGSEGV"), "1")==0) {
|
||||
@@ -1483,6 +1597,66 @@ void LoadEnvVars(box64context_t *context)
|
||||
#endif
|
||||
}
|
||||
|
||||
EXPORTDYN
|
||||
void LoadLDPath(box64context_t *context)
|
||||
{
|
||||
// check BOX64_LD_LIBRARY_PATH and load it
|
||||
#ifdef BOX32
|
||||
if(box64_is32bits)
|
||||
LoadEnvPath(&context->box64_ld_lib, ".:lib:i386:bin:libs", "BOX64_LD_LIBRARY_PATH");
|
||||
else
|
||||
#endif
|
||||
LoadEnvPath(&context->box64_ld_lib, ".:lib:lib64:x86_64:bin64:libs64", "BOX64_LD_LIBRARY_PATH");
|
||||
#ifndef TERMUX
|
||||
if(box64_is32bits) {
|
||||
#ifdef BOX32
|
||||
if(FileExist("/lib/i386-linux-gnu", 0))
|
||||
AddPath("/lib/i386-linux-gnu", &context->box64_ld_lib, 1);
|
||||
if(FileExist("/usr/lib/i386-linux-gnu", 0))
|
||||
AddPath("/usr/lib/i386-linux-gnu", &context->box64_ld_lib, 1);
|
||||
if(FileExist("/usr/i386-linux-gnu/lib", 0))
|
||||
AddPath("/usr/i386-linux-gnu/lib", &context->box64_ld_lib, 1);
|
||||
if(FileExist("/usr/lib/box64-i386-linux-gnu", 0))
|
||||
AddPath("/usr/lib/box64-i386-linux-gnu", &context->box64_ld_lib, 1);
|
||||
if(FileExist("/data/data/com.termux/files/usr/glibc/lib/i386-linux-gnu", 0))
|
||||
AddPath("/data/data/com.termux/files/usr/glibc/lib/i386-linux-gnu", &context->box64_ld_lib, 1);
|
||||
if(FileExist("/data/data/com.termux/files/usr/glibc/lib/box64-i386-linux-gnu", 0))
|
||||
AddPath("/data/data/com.termux/files/usr/glibc/lib/box64-i386-linux-gnu", &context->box64_ld_lib, 1);
|
||||
if(FileExist("/data/data/com.termux/files/usr/lib/box64-i386-linux-gnu", 0))
|
||||
AddPath("/data/data/com.termux/files/usr/lib/box64-i386-linux-gnu", &context->box64_ld_lib, 1);
|
||||
#endif
|
||||
} else {
|
||||
if(FileExist("/lib/x86_64-linux-gnu", 0))
|
||||
AddPath("/lib/x86_64-linux-gnu", &context->box64_ld_lib, 1);
|
||||
if(FileExist("/usr/lib/x86_64-linux-gnu", 0))
|
||||
AddPath("/usr/lib/x86_64-linux-gnu", &context->box64_ld_lib, 1);
|
||||
if(FileExist("/usr/x86_64-linux-gnu/lib", 0))
|
||||
AddPath("/usr/x86_64-linux-gnu/lib", &context->box64_ld_lib, 1);
|
||||
if(FileExist("/usr/lib/box64-x86_64-linux-gnu", 0))
|
||||
AddPath("/usr/lib/box64-x86_64-linux-gnu", &context->box64_ld_lib, 1);
|
||||
if(FileExist("/data/data/com.termux/files/usr/glibc/lib/x86_64-linux-gnu", 0))
|
||||
AddPath("/data/data/com.termux/files/usr/glibc/lib/x86_64-linux-gnu", &context->box64_ld_lib, 1);
|
||||
if(FileExist("/data/data/com.termux/files/usr/glibc/lib/box64-x86_64-linux-gnu", 0))
|
||||
AddPath("/data/data/com.termux/files/usr/glibc/lib/box64-x86_64-linux-gnu", &context->box64_ld_lib, 1);
|
||||
if(FileExist("/data/data/com.termux/files/usr/lib/box64-x86_64-linux-gnu", 0))
|
||||
AddPath("/data/data/com.termux/files/usr/lib/box64-x86_64-linux-gnu", &context->box64_ld_lib, 1);
|
||||
}
|
||||
#else
|
||||
//TODO: Add Termux Library Path - Lily
|
||||
if(box64_is32bits) {
|
||||
#ifdef BOX32
|
||||
if(FileExist("/data/data/com.termux/files/usr/lib/i386-linux-gnu", 0))
|
||||
AddPath("/data/data/com.termux/files/usr/lib/i386-linux-gnu", &context->box64_ld_lib, 1);
|
||||
#endif
|
||||
} else {
|
||||
if(FileExist("/data/data/com.termux/files/usr/lib/x86_64-linux-gnu", 0))
|
||||
AddPath("/data/data/com.termux/files/usr/lib/x86_64-linux-gnu", &context->box64_ld_lib, 1);
|
||||
}
|
||||
#endif
|
||||
if(getenv("LD_LIBRARY_PATH"))
|
||||
PrependList(&context->box64_ld_lib, getenv("LD_LIBRARY_PATH"), 1); // in case some of the path are for x86 world
|
||||
}
|
||||
|
||||
EXPORTDYN
|
||||
void setupTraceInit()
|
||||
{
|
||||
@@ -1501,10 +1675,16 @@ void setupTraceInit()
|
||||
if(s_trace_start || s_trace_end)
|
||||
SetTraceEmu(s_trace_start, s_trace_end);
|
||||
} else {
|
||||
if (GetGlobalSymbolStartEnd(my_context->maplib, p, &s_trace_start, &s_trace_end, NULL, -1, NULL, 0, NULL)) {
|
||||
SetTraceEmu(s_trace_start, s_trace_end);
|
||||
printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", p, (void*)s_trace_start, (void*)s_trace_end);
|
||||
} else if(GetLocalSymbolStartEnd(my_context->maplib, p, &s_trace_start, &s_trace_end, NULL, -1, NULL, 0, NULL)) {
|
||||
int veropt = 1;
|
||||
int ver = 0;
|
||||
const char* vername = NULL;
|
||||
int search = 0;
|
||||
for(int i=0; i<my_context->elfsize && !search; ++i) {
|
||||
search = ElfGetSymbolStartEnd(my_context->elfs[i], &s_trace_start, &s_trace_end, p, &ver, &vername, 1, &veropt)?1:0;
|
||||
if(!search)
|
||||
search = ElfGetSymTabStartEnd(my_context->elfs[i], &s_trace_start, &s_trace_end, p);
|
||||
}
|
||||
if(search) {
|
||||
SetTraceEmu(s_trace_start, s_trace_end);
|
||||
printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", p, (void*)s_trace_start, (void*)s_trace_end);
|
||||
} else {
|
||||
@@ -1528,42 +1708,19 @@ void setupTraceMapLib(lib_t* maplib)
|
||||
return;
|
||||
char* p = trace_func;
|
||||
uintptr_t s_trace_start=0, s_trace_end=0;
|
||||
if(maplib) {
|
||||
if (GetGlobalSymbolStartEnd(maplib, p, &s_trace_start, &s_trace_end, NULL, -1, NULL, 0, NULL)) {
|
||||
SetTraceEmu(s_trace_start, s_trace_end);
|
||||
printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", p, (void*)s_trace_start, (void*)s_trace_end);
|
||||
box_free(trace_func);
|
||||
trace_func = NULL;
|
||||
return;
|
||||
} else if(GetLocalSymbolStartEnd(maplib, p, &s_trace_start, &s_trace_end, NULL, -1, NULL, 0, NULL)) {
|
||||
SetTraceEmu(s_trace_start, s_trace_end);
|
||||
printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", p, (void*)s_trace_start, (void*)s_trace_end);
|
||||
box_free(trace_func);
|
||||
trace_func = NULL;
|
||||
return;
|
||||
} else if(GetSymTabStartEnd(maplib, p, &s_trace_start, &s_trace_end)) {
|
||||
SetTraceEmu(s_trace_start, s_trace_end);
|
||||
printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", p, (void*)s_trace_start, (void*)s_trace_end);
|
||||
box_free(trace_func);
|
||||
trace_func = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (my_context->elfs && GetGlobalSymbolStartEnd(my_context->maplib, p, &s_trace_start, &s_trace_end, NULL, -1, NULL, 0, NULL)) {
|
||||
void* search = NULL;
|
||||
if(GetAnySymbolStartEnd(maplib, p, &s_trace_start, &s_trace_end, 0, NULL, 1)) {
|
||||
SetTraceEmu(s_trace_start, s_trace_end);
|
||||
printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", p, (void*)s_trace_start, (void*)s_trace_end);
|
||||
box_free(trace_func);
|
||||
trace_func = NULL;
|
||||
} else if(my_context->elfs && GetLocalSymbolStartEnd(my_context->maplib, p, &s_trace_start, &s_trace_end, NULL, -1, NULL, 0, NULL)) {
|
||||
SetTraceEmu(s_trace_start, s_trace_end);
|
||||
printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", p, (void*)s_trace_start, (void*)s_trace_end);
|
||||
box_free(trace_func);
|
||||
trace_func = NULL;
|
||||
} else if(GetSymTabStartEnd(my_context->maplib, p, &s_trace_start, &s_trace_end)) {
|
||||
return;
|
||||
} else if(GetSymTabStartEnd(maplib, p, &s_trace_start, &s_trace_end)) {
|
||||
SetTraceEmu(s_trace_start, s_trace_end);
|
||||
printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", p, (void*)s_trace_start, (void*)s_trace_end);
|
||||
box_free(trace_func);
|
||||
trace_func = NULL;
|
||||
return;
|
||||
} else {
|
||||
printf_log(LOG_NONE, "Warning, Symbol to trace (\"%s\") not found. Trying to set trace later\n", p);
|
||||
SetTraceEmu(0, 1); // disabling trace, mostly
|
||||
@@ -1595,10 +1752,18 @@ void setupTrace()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (my_context->elfs && GetGlobalSymbolStartEnd(my_context->maplib, p, &s_trace_start, &s_trace_end, NULL, -1, NULL, 0, NULL)) {
|
||||
SetTraceEmu(s_trace_start, s_trace_end);
|
||||
printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", p, (void*)s_trace_start, (void*)s_trace_end);
|
||||
} else if(my_context->elfs && GetLocalSymbolStartEnd(my_context->maplib, p, &s_trace_start, &s_trace_end, NULL, -1, NULL, 0, NULL)) {
|
||||
int search = 0;
|
||||
if (my_context->elfs) {
|
||||
int veropt = 1;
|
||||
int ver = 0;
|
||||
const char* vername = NULL;
|
||||
for(int i=0; i<my_context->elfsize && !search; ++i) {
|
||||
search = ElfGetSymbolStartEnd(my_context->elfs[i], &s_trace_start, &s_trace_end, p, &ver, &vername, 1, &veropt)?1:0;
|
||||
if(!search)
|
||||
search = ElfGetSymTabStartEnd(my_context->elfs[i], &s_trace_start, &s_trace_end, p);
|
||||
}
|
||||
}
|
||||
if(search) {
|
||||
SetTraceEmu(s_trace_start, s_trace_end);
|
||||
printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", p, (void*)s_trace_start, (void*)s_trace_end);
|
||||
} else {
|
||||
@@ -1672,10 +1837,16 @@ static void add_argv(const char* what) {
|
||||
if(!strcmp(my_context->argv[i], what))
|
||||
there = 1;
|
||||
if(!there) {
|
||||
printf_log(LOG_INFO, "Inserting \"%s\" to the argments\n", what);
|
||||
// try to prepend the arg, not appending
|
||||
static int where = 0;
|
||||
if(!where)
|
||||
where = (box64_wine)?2:1;
|
||||
printf_log(LOG_INFO, "Inserting \"%s\" to the argument %d\n", what, where);
|
||||
my_context->argv = (char**)box_realloc(my_context->argv, (my_context->argc+1)*sizeof(char*));
|
||||
my_context->argv[my_context->argc] = box_strdup(what);
|
||||
memmove(my_context->argv+where+1, my_context->argv+where, (my_context->argc-where)*sizeof(char*));
|
||||
my_context->argv[where] = box_strdup(what);
|
||||
my_context->argc++;
|
||||
where++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1791,19 +1962,27 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
|
||||
if(!box64_nobanner)
|
||||
PrintBox64Version();
|
||||
// precheck, for win-preload
|
||||
if(strstr(prog, "wine-preloader")==(prog+strlen(prog)-strlen("wine-preloader"))
|
||||
|| strstr(prog, "wine64-preloader")==(prog+strlen(prog)-strlen("wine64-preloader"))) {
|
||||
const char* prog_ = strrchr(prog, '/');
|
||||
if(!prog_) prog_ = prog; else ++prog_;
|
||||
if(!strcmp(prog_, "wine-preloader") || !strcmp(prog_, "wine64-preloader")) {
|
||||
// wine-preloader detecter, skipping it if next arg exist and is an x86 binary
|
||||
int x64 = (nextarg<argc)?FileIsX64ELF(argv[nextarg]):0;
|
||||
if(x64) {
|
||||
#ifdef BOX32
|
||||
int x86 = (nextarg<argc)?FileIsX86ELF(argv[nextarg]):0;
|
||||
#else
|
||||
int x86 = 0;
|
||||
#endif
|
||||
if(x64 || x86) {
|
||||
prog = argv[++nextarg];
|
||||
printf_log(LOG_INFO, "BOX64: Wine preloader detected, loading \"%s\" directly\n", prog);
|
||||
wine_preloaded = 1;
|
||||
prog_ = strrchr(prog, '/');
|
||||
if(!prog_) prog_ = prog; else ++prog_;
|
||||
}
|
||||
}
|
||||
#ifndef STATICBUILD
|
||||
// pre-check for pressure-vessel-wrap
|
||||
if(strstr(prog, "pressure-vessel-wrap")==(prog+strlen(prog)-strlen("pressure-vessel-wrap"))) {
|
||||
if(!strcmp(prog_, "pressure-vessel-wrap")) {
|
||||
printf_log(LOG_INFO, "BOX64: pressure-vessel-wrap detected\n");
|
||||
pressure_vessel(argc, argv, nextarg+1, prog);
|
||||
}
|
||||
@@ -1812,11 +1991,9 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
|
||||
int is_custom_gstreamer = 0;
|
||||
const char* wine_prog = NULL;
|
||||
// check if this is wine
|
||||
if(!strcmp(prog, "wine64")
|
||||
|| !strcmp(prog, "wine64-development")
|
||||
|| !strcmp(prog, "wine")
|
||||
|| (strrchr(prog, '/') && !strcmp(strrchr(prog,'/'), "/wine"))
|
||||
|| (strrchr(prog, '/') && !strcmp(strrchr(prog,'/'), "/wine64"))) {
|
||||
if(!strcmp(prog_, "wine64")
|
||||
|| !strcmp(prog_, "wine64-development")
|
||||
|| !strcmp(prog_, "wine")) {
|
||||
const char* prereserve = getenv("WINEPRELOADRESERVE");
|
||||
printf_log(LOG_INFO, "BOX64: Wine64 detected, WINEPRELOADRESERVE=\"%s\"\n", prereserve?prereserve:"");
|
||||
if(wine_preloaded || 1) {
|
||||
@@ -1877,9 +2054,14 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
|
||||
}
|
||||
++nextarg;
|
||||
prog = argv[nextarg];
|
||||
}
|
||||
// check if this is wineserver
|
||||
if(!strcmp(prog, "wineserver") || !strcmp(prog, "wineserver64") || (strlen(prog)>9 && !strcmp(prog+strlen(prog)-strlen("/wineserver"), "/wineserver"))) {
|
||||
} else if(!strcmp(prog_, "steam") ) {
|
||||
printf_log(LOG_INFO, "steam detected\n");
|
||||
box64_steam = 1;
|
||||
} else if(!strcmp(prog_, "steamcmd")) {
|
||||
printf_log(LOG_INFO, "steamcmd detected\n");
|
||||
box64_steamcmd = 1;
|
||||
} else if(!strcmp(prog_, "wineserver")) {
|
||||
// check if this is wineserver
|
||||
box64_wine = 1;
|
||||
}
|
||||
// Create a new context
|
||||
@@ -1890,7 +2072,7 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
|
||||
// Append ld_list if it exist
|
||||
if(ld_libs_args!=-1)
|
||||
PrependList(&my_context->box64_ld_lib, argv[ld_libs_args], 1);
|
||||
if(is_custom_gstreamer)
|
||||
if(is_custom_gstreamer) //TODO: is this still needed?
|
||||
AddPath("libwayland-client.so.0", &my_context->box64_emulated_libs, 0);
|
||||
|
||||
my_context->box64path = ResolveFile(argv[0], &my_context->box64_path);
|
||||
@@ -1939,16 +2121,21 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
|
||||
PrintCollection(&my_context->box64_path, "BOX64 BIN PATH");
|
||||
// lets build argc/argv stuff
|
||||
printf_log(LOG_INFO, "Looking for %s\n", prog);
|
||||
my_context->argv[0] = ResolveFileSoft(prog, &my_context->box64_path);
|
||||
if(strchr(prog, '/'))
|
||||
my_context->argv[0] = box_strdup(prog);
|
||||
else
|
||||
my_context->argv[0] = ResolveFileSoft(prog, &my_context->box64_path);
|
||||
// check if box86 is present
|
||||
{
|
||||
my_context->box86path = box_strdup(my_context->box64path);
|
||||
#ifndef BOX32
|
||||
char* p = strrchr(my_context->box86path, '6'); // get the 6 of box64
|
||||
p[0] = '8'; p[1] = '6'; // change 64 to 86
|
||||
if(!FileExist(my_context->box86path, IS_FILE)) {
|
||||
box_free(my_context->box86path);
|
||||
my_context->box86path = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
const char* prgname = strrchr(prog, '/');
|
||||
if(!prgname)
|
||||
@@ -1968,7 +2155,7 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
|
||||
box64_zoom = 1;
|
||||
}
|
||||
// special case for bash (add BOX86_NOBANNER=1 if not there)
|
||||
if(!strcmp(prgname, "bash")) {
|
||||
if(!strcmp(prgname, "bash") || !strcmp(prgname, "box64-bash")) {
|
||||
printf_log(LOG_INFO, "bash detected, disabling banner\n");
|
||||
if (!box64_nobanner) {
|
||||
setenv("BOX86_NOBANNER", "1", 0);
|
||||
@@ -1979,6 +2166,8 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
|
||||
setenv("BOX64_BASH", prog, 1);
|
||||
}
|
||||
}
|
||||
if(!bashpath)
|
||||
bashpath = ResolveFile("box64-bash", &my_context->box64_path);
|
||||
if(bashpath)
|
||||
my_context->bashpath = box_strdup(bashpath);
|
||||
|
||||
@@ -2018,7 +2207,60 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
|
||||
{
|
||||
add_argv("-cef-disable-gpu-compositor");
|
||||
}
|
||||
|
||||
// add new args only if there is no args already
|
||||
if(box64_new_args) {
|
||||
char tmp[256];
|
||||
char* p = box64_new_args;
|
||||
int state = 0;
|
||||
char* p2 = p;
|
||||
if(my_context->argc==1 || (my_context->argc==2 && box64_wine))
|
||||
while(state>=0) {
|
||||
switch(*p2) {
|
||||
case 0: // end of flux
|
||||
if(state && (p2!=p)) add_argv(p);
|
||||
state = -1;
|
||||
break;
|
||||
case '"': // start/end of quotes
|
||||
if(state<2) {if(!state) p=p2; state=2;} else state=1;
|
||||
break;
|
||||
case ' ':
|
||||
if(state==1) {strncpy(tmp, p, p2-p); tmp[p2-p]='\0'; add_argv(tmp); state=0;}
|
||||
break;
|
||||
default:
|
||||
if(state==0) {state=1; p=p2;}
|
||||
break;
|
||||
}
|
||||
++p2;
|
||||
}
|
||||
box_free(box64_new_args);
|
||||
box64_new_args = NULL;
|
||||
}
|
||||
if(box64_insert_args) {
|
||||
char tmp[256];
|
||||
char* p = box64_insert_args;
|
||||
int state = 0;
|
||||
char* p2 = p;
|
||||
while(state>=0) {
|
||||
switch(*p2) {
|
||||
case 0: // end of flux
|
||||
if(state && (p2!=p)) add_argv(p);
|
||||
state = -1;
|
||||
break;
|
||||
case '"': // start/end of quotes
|
||||
if(state<2) {if(!state) p=p2; state=2;} else state=1;
|
||||
break;
|
||||
case ' ':
|
||||
if(state==1) {strncpy(tmp, p, p2-p); tmp[p2-p]='\0'; add_argv(tmp); state=0;}
|
||||
break;
|
||||
default:
|
||||
if(state==0) {state=1; p=p2;}
|
||||
break;
|
||||
}
|
||||
++p2;
|
||||
}
|
||||
box_free(box64_insert_args);
|
||||
box64_insert_args = NULL;
|
||||
}
|
||||
// check if file exist
|
||||
if(!my_context->argv[0] || !FileExist(my_context->argv[0], IS_FILE)) {
|
||||
printf_log(LOG_NONE, "Error: File is not found. (check BOX64_PATH)\n");
|
||||
@@ -2046,6 +2288,16 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
|
||||
FreeCollection(&ld_preload);
|
||||
return -1;
|
||||
}
|
||||
#ifdef BOX32
|
||||
box64_is32bits = FileIsX86ELF(my_context->fullpath);
|
||||
if(box64_is32bits) {
|
||||
printf_log(LOG_INFO, "BOX64: Using Box32 to load 32bits elf\n");
|
||||
loadProtectionFromMap();
|
||||
reserveHighMem();
|
||||
init_pthread_helper_32();
|
||||
}
|
||||
#endif
|
||||
LoadLDPath(my_context);
|
||||
elfheader_t *elf_header = LoadAndCheckElfHeader(f, my_context->fullpath, 1);
|
||||
if(!elf_header) {
|
||||
int x86 = my_context->box86path?FileIsX86ELF(my_context->fullpath):0;
|
||||
@@ -2099,6 +2351,18 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
|
||||
FreeCollection(&ld_preload);
|
||||
return -1;
|
||||
}
|
||||
if(!strcmp(prgname, "heroic")) {
|
||||
// check if heroic needs patching (for the 2.15.1 version)
|
||||
uint8_t* address = GetBaseAddress(elf_header);
|
||||
if(address[0x422f6e1]==0x72 && address[0x422f6e2]==0x44 && address[0x422f6e0]==0xF8 && address[0x422f727]==0xcc) {
|
||||
printf_log(LOG_INFO, "Patched heroic!\n");
|
||||
uintptr_t page = ((uintptr_t)&address[0x422f6e1])&~(box64_pagesize-1);
|
||||
int prot = getProtection(page);
|
||||
mprotect((void*)page, box64_pagesize, PROT_READ|PROT_WRITE|PROT_EXEC);
|
||||
address[0x422f6e1]=0x90; address[0x422f6e2]=0x90;
|
||||
mprotect((void*)page, box64_pagesize, prot);
|
||||
}
|
||||
}
|
||||
if(ElfCheckIfUseTCMallocMinimal(elf_header)) {
|
||||
if(!box64_tcmalloc_minimal) {
|
||||
// need to reload with tcmalloc_minimal as a LD_PRELOAD!
|
||||
@@ -2194,10 +2458,15 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
|
||||
// stack setup is much more complicated then just that!
|
||||
SetupInitialStack(emu); // starting here, the argv[] don't need free anymore
|
||||
SetupX64Emu(emu, NULL);
|
||||
SetRSI(emu, my_context->argc);
|
||||
SetRDX(emu, (uint64_t)my_context->argv);
|
||||
SetRCX(emu, (uint64_t)my_context->envv);
|
||||
SetRBP(emu, 0); // Frame pointer so to "No more frame pointer"
|
||||
if(box64_is32bits) {
|
||||
SetEAX(emu, my_context->argc);
|
||||
SetEBX(emu, my_context->argv32);
|
||||
} else {
|
||||
SetRSI(emu, my_context->argc);
|
||||
SetRDX(emu, (uint64_t)my_context->argv);
|
||||
SetRCX(emu, (uint64_t)my_context->envv);
|
||||
SetRBP(emu, 0); // Frame pointer so to "No more frame pointer"
|
||||
}
|
||||
|
||||
// child fork to handle traces
|
||||
pthread_atfork(NULL, NULL, my_child_fork);
|
||||
@@ -2281,11 +2550,20 @@ int emulate(x64emu_t* emu, elfheader_t* elf_header)
|
||||
// emulate!
|
||||
printf_log(LOG_DEBUG, "Start x64emu on Main\n");
|
||||
// Stack is ready, with stacked: NULL env NULL argv argc
|
||||
SetRIP(emu, my_context->ep);
|
||||
ResetFlags(emu);
|
||||
Push64(emu, my_context->exit_bridge); // push to pop it just after
|
||||
SetRDX(emu, Pop64(emu)); // RDX is exit function
|
||||
Run(emu, 0);
|
||||
#ifdef BOX32
|
||||
if(box64_is32bits) {
|
||||
SetEIP(emu, my_context->ep);
|
||||
Push32(emu, my_context->exit_bridge); // push to pop it just after
|
||||
SetEDX(emu, Pop32(emu)); // RDX is exit function
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
SetRIP(emu, my_context->ep);
|
||||
Push64(emu, my_context->exit_bridge); // push to pop it just after
|
||||
SetRDX(emu, Pop64(emu)); // RDX is exit function
|
||||
}
|
||||
DynaRun(emu);
|
||||
// Get EAX
|
||||
int ret = GetEAX(emu);
|
||||
printf_log(LOG_DEBUG, "Emulation finished, EAX=%d\n", ret);
|
||||
|
||||
+606
-183
File diff suppressed because it is too large.
Load diff
+7
-2
@@ -13,8 +13,13 @@
|
||||
#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* internal_mmap(void *addr, unsigned long length, int prot, int flags, int fd, ssize_t offset);
|
||||
@@ -28,8 +33,8 @@ extern int box64_mmap32;
|
||||
EXPORT void* mmap64(void *addr, unsigned long length, int prot, int flags, int fd, ssize_t offset)
|
||||
{
|
||||
void* ret;
|
||||
if(!addr && ((running32bits && box64_mmap32) || (flags&0x40)))
|
||||
ret = my_mmap64(NULL, addr, length, prot, flags | 0x40, fd, offset);
|
||||
if(!addr && ((running32bits && box64_mmap32) || (flags&MAP_32BIT) || box64_is32bits))
|
||||
ret = my_mmap64(NULL, addr, length, prot, flags | MAP_32BIT, fd, offset);
|
||||
else
|
||||
ret = internal_mmap(addr, length, prot, flags, fd, offset);
|
||||
if(ret!=MAP_FAILED && mapallmem)
|
||||
|
||||
@@ -60,6 +60,10 @@ p0-p3 are used to pass scalable predicate arguments to a subroutine and to retur
|
||||
#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
|
||||
@@ -178,35 +182,37 @@ int convert_bitmask(uint64_t bitmask);
|
||||
// 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 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 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 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 CMPSx_REG(Rn, Rm) SUBSx_REG(xZR, Rn, Rm)
|
||||
#define CMPSw_REG(Rn, Rm) SUBSw_REG(wZR, Rn, Rm)
|
||||
#define CMPSxw_REG(Rn, Rm) SUBSxw_REG(xZR, Rn, Rm)
|
||||
@@ -218,12 +224,12 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#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)
|
||||
@@ -235,18 +241,18 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#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))
|
||||
|
||||
// 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))
|
||||
@@ -283,13 +289,19 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#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 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 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 LDRz_REG_SXTW(Rt, Rn, Rm) EMIT(LDR_REG_gen(rex.is32bits?0b10:0b11, Rm, 0b110, 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 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 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))
|
||||
@@ -301,6 +313,7 @@ int convert_bitmask(uint64_t bitmask);
|
||||
|
||||
#define LDRS_REG_gen(size, Rm, option, S, Rn, Rt) ((size)<<30 | 0b111<<27 | 0b10<<22 | 1<<21 | (Rm)<<16 | (option)<<13 | (S)<<12 | (0b10)<<10 | (Rn)<<5 | (Rt))
|
||||
#define LDRSW_REG(Rt, Rn, Rm) EMIT(LDRS_REG_gen(0b10, Rm, 0b011, 0, Rn, Rt))
|
||||
#define LDRSW_REG_SXTW(Rt, Rn, Rm) EMIT(LDRS_REG_gen(0b10, Rm, 0b110, 0, Rn, Rt))
|
||||
|
||||
#define 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))
|
||||
@@ -371,12 +384,18 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#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 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 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))
|
||||
|
||||
// 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))
|
||||
@@ -476,12 +495,19 @@ int convert_bitmask(uint64_t bitmask);
|
||||
// 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
|
||||
@@ -492,6 +518,7 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#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))
|
||||
@@ -517,6 +544,10 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#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))
|
||||
@@ -556,9 +587,9 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#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 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) 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 ANDSxw_mask(Rd, Rn, N, immr, imms) EMIT(LOGIC_gen(rex.w, 0b11, 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))
|
||||
@@ -574,9 +605,10 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#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))
|
||||
@@ -627,10 +659,10 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#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
|
||||
@@ -806,9 +838,9 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#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))
|
||||
@@ -835,6 +867,14 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#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))
|
||||
@@ -896,18 +936,24 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#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))
|
||||
@@ -1253,10 +1299,10 @@ int convert_bitmask(uint64_t bitmask);
|
||||
|
||||
// CMP
|
||||
#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, Sn, 0, 0b01))
|
||||
#define FCMPD_0(Dn) EMIT(FCMP_scalar(0b01, Dn, 0, 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))
|
||||
@@ -2182,7 +2228,7 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#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))
|
||||
@@ -2298,23 +2344,23 @@ int convert_bitmask(uint64_t bitmask);
|
||||
|
||||
// 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))
|
||||
|
||||
@@ -124,6 +124,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);
|
||||
@@ -573,6 +589,14 @@ 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;
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -22,7 +22,7 @@
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "../dynarec_helper.h"
|
||||
|
||||
uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog)
|
||||
{
|
||||
@@ -39,6 +39,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
int q0, q1;
|
||||
int d0, d1;
|
||||
int s0;
|
||||
int mask;
|
||||
uint64_t tmp64u;
|
||||
int64_t j64;
|
||||
int64_t fixedaddress;
|
||||
@@ -69,8 +70,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
switch(nextop) {
|
||||
case 0xD0:
|
||||
INST_NAME("XGETBV");
|
||||
CMPSw_REG(xRCX, xZR);
|
||||
B_MARK(cEQ);
|
||||
CBZw_MARK(xRCX);
|
||||
UDF(0);
|
||||
MARK;
|
||||
MOV32w(xRAX, 0b111);
|
||||
@@ -85,7 +85,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
INST_NAME("SMSW Ed");
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
MOV32w(ed, (1<<0) | (1<<4)); // only PE and ET set...
|
||||
break;
|
||||
case 0xF9:
|
||||
@@ -154,8 +154,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
CALL_S(x64Syscall, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
TABLE64(x3, addr); // expected return address
|
||||
CMPSx_REG(xRIP, x3);
|
||||
B_MARK(cNE);
|
||||
SUBx_REG(x3, x3, xRIP);
|
||||
CBNZx_MARK(x3);
|
||||
LDRw_U12(w1, xEmu, offsetof(x64emu_t, quit));
|
||||
CBZw_NEXT(w1);
|
||||
MARK;
|
||||
@@ -190,13 +190,24 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0x0D:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("PREFETCH");
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0xfff, 7, rex, NULL, 0, 0);
|
||||
PLD_L1_STREAM_U12(ed, fixedaddress);
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("PREFETCHW");
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0xfff, 7, rex, NULL, 0, 0);
|
||||
PST_L1_STREAM_U12(ed, fixedaddress);
|
||||
break;
|
||||
default: //???
|
||||
DEFAULT;
|
||||
case 2:
|
||||
INST_NAME("PREFETCHWT1");
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0xfff, 7, rex, NULL, 0, 0);
|
||||
PST_L1_STREAM_U12(ed, fixedaddress);
|
||||
break;
|
||||
default: //NOP
|
||||
FAKEED;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x0E:
|
||||
@@ -273,7 +284,6 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0x14:
|
||||
INST_NAME("UNPCKLPS Gx, Ex");
|
||||
nextop = F8;
|
||||
SMREAD();
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX(v0, 1);
|
||||
VZIP1Q_32(v0, v0, q0);
|
||||
@@ -281,7 +291,6 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0x15:
|
||||
INST_NAME("UNPCKHPS Gx, Ex");
|
||||
nextop = F8;
|
||||
SMREAD();
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX(v0, 1);
|
||||
VZIP2Q_32(v0, v0, q0);
|
||||
@@ -490,9 +499,18 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETGX(v0, 0);
|
||||
GETEXSS(s0, 0, 0);
|
||||
FCMPS(v0, s0);
|
||||
FCOMI(x1, x2);
|
||||
FCOMI(x1, x2, 0, v0, s0, 1); // disabled precise cmp
|
||||
break;
|
||||
case 0x30:
|
||||
INST_NAME("WRMSR");
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_priv, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
// continue the block
|
||||
break;
|
||||
|
||||
case 0x31:
|
||||
INST_NAME("RDTSC");
|
||||
NOTEST(x1);
|
||||
@@ -838,7 +856,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
REVxw(gd, xRAX+(nextop&7)+(rex.b<<3));
|
||||
REVxw(gd, TO_NAT((nextop & 7) + (rex.b << 3)));
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 0);
|
||||
@@ -851,7 +869,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if(MODREG) { // reg <= reg
|
||||
REVxw(xRAX+(nextop&7)+(rex.b<<3), gd);
|
||||
REVxw(TO_NAT((nextop & 7) + (rex.b << 3)), gd);
|
||||
} else { // mem <= reg
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 0);
|
||||
REVxw(x1, gd);
|
||||
@@ -961,19 +979,19 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
break;
|
||||
|
||||
#define GO(GETFLAGS, NO, YES, F) \
|
||||
READFLAGS(F); \
|
||||
GETFLAGS; \
|
||||
nextop=F8; \
|
||||
GETGD; \
|
||||
if(MODREG) { \
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3); \
|
||||
CSELxw(gd, ed, gd, YES); \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 0); \
|
||||
Bcond(NO, +8); \
|
||||
LDxw(gd, ed, fixedaddress); \
|
||||
if(!rex.w) {MOVw_REG(gd, gd);} \
|
||||
#define GO(GETFLAGS, NO, YES, F) \
|
||||
READFLAGS(F); \
|
||||
GETFLAGS; \
|
||||
nextop = F8; \
|
||||
GETGD; \
|
||||
if (MODREG) { \
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3)); \
|
||||
CSELxw(gd, ed, gd, YES); \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff << (2 + rex.w), (1 << (2 + rex.w)) - 1, rex, NULL, 0, 0); \
|
||||
Bcond(NO, +8); \
|
||||
LDxw(gd, ed, fixedaddress); \
|
||||
if (!rex.w) { MOVw_REG(gd, gd); } \
|
||||
}
|
||||
|
||||
GOCOND(0x40, "CMOV", "Gd, Ed");
|
||||
@@ -1266,7 +1284,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = mmx_get_reg_empty(dyn, ninst, x1, x2, x3, gd);
|
||||
if(MODREG) {
|
||||
ed = xRAX + (nextop&7) + (rex.b<<3);
|
||||
ed = TO_NAT((nextop & 0x07) + (rex.b << 3));
|
||||
if(rex.w) {
|
||||
FMOVDx(v0, ed);
|
||||
} else {
|
||||
@@ -1515,7 +1533,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGM(v0);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xRAX + (nextop&7) + (rex.b<<3);
|
||||
ed = TO_NAT((nextop & 0x07) + (rex.b << 3));
|
||||
if(rex.w) {
|
||||
FMOVxD(ed, v0);
|
||||
} else {
|
||||
@@ -1547,11 +1565,14 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
|
||||
#define GO(GETFLAGS, NO, YES, F) \
|
||||
if (box64_dynarec_test == 2) { NOTEST(x1); } \
|
||||
READFLAGS(F); \
|
||||
i32_ = F32S; \
|
||||
if(rex.is32bits) \
|
||||
j64 = (uint32_t)(addr+i32_); \
|
||||
else \
|
||||
j64 = addr+i32_; \
|
||||
BARRIER(BARRIER_MAYBE); \
|
||||
JUMP(addr+i32_, 1); \
|
||||
JUMP(j64, 1); \
|
||||
GETFLAGS; \
|
||||
if(dyn->insts[ninst].x64.jmp_insts==-1 || \
|
||||
CHECK_CACHE()) { \
|
||||
@@ -1561,40 +1582,42 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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+i32_, 0, ninst, rex.is32bits); \
|
||||
jump_to_next(dyn, j64, 0, ninst, rex.is32bits); \
|
||||
} else { \
|
||||
CacheTransform(dyn, ninst, cacheupd, x1, x2, x3); \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size); \
|
||||
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); \
|
||||
}
|
||||
|
||||
GOCOND(0x80, "J", "Id");
|
||||
#undef GO
|
||||
|
||||
#define GO(GETFLAGS, NO, YES, F) \
|
||||
READFLAGS(F); \
|
||||
GETFLAGS; \
|
||||
nextop=F8; \
|
||||
CSETw(x3, YES); \
|
||||
if(MODREG) { \
|
||||
if(rex.rex) { \
|
||||
eb1= xRAX+(nextop&7)+(rex.b<<3); \
|
||||
eb2 = 0; \
|
||||
} else { \
|
||||
ed = (nextop&7); \
|
||||
eb2 = (ed>>2)*8; \
|
||||
eb1 = xRAX+(ed&3); \
|
||||
} \
|
||||
BFIx(eb1, x3, eb2, 8); \
|
||||
} else { \
|
||||
#define GO(GETFLAGS, NO, YES, F) \
|
||||
READFLAGS(F); \
|
||||
GETFLAGS; \
|
||||
nextop = F8; \
|
||||
CSETw(x3, YES); \
|
||||
if (MODREG) { \
|
||||
if (rex.rex) { \
|
||||
eb1 = TO_NAT((nextop & 7) + (rex.b << 3)); \
|
||||
eb2 = 0; \
|
||||
} else { \
|
||||
ed = (nextop & 7); \
|
||||
eb2 = (ed >> 2) * 8; \
|
||||
eb1 = TO_NAT (ed & 3); \
|
||||
} \
|
||||
BFIx(eb1, x3, eb2, 8); \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff, 0, rex, NULL, 0, 0); \
|
||||
STB(x3, ed, fixedaddress); \
|
||||
SMWRITE(); \
|
||||
STB(x3, ed, fixedaddress); \
|
||||
SMWRITE(); \
|
||||
}
|
||||
|
||||
GOCOND(0x90, "SET", "Eb");
|
||||
@@ -1623,32 +1646,40 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 0);
|
||||
ASRx(x1, gd, 5+rex.w); // r1 = (gd>>5)
|
||||
ADDx_REG_LSL(x3, wback, x1, 2+rex.w); //(&ed)+=r1*4;
|
||||
ASRxw(x1, gd, 5+rex.w); // r1 = (gd>>5)
|
||||
if(!rex.w && !rex.is32bits) {SXTWx(x1, x1);}
|
||||
ADDz_REG_LSL(x3, wback, x1, 2+rex.w); //(&ed)+=r1*4;
|
||||
LDxw(x1, x3, fixedaddress);
|
||||
ed = x1;
|
||||
}
|
||||
if(rex.w) {
|
||||
ANDx_mask(x2, gd, 1, 0, 0b00101); //mask=0x000000000000003f
|
||||
} else {
|
||||
ANDw_mask(x2, gd, 0, 0b00100); //mask=0x00000001f
|
||||
IFX(X_CF) {
|
||||
if(rex.w) {
|
||||
ANDx_mask(x2, gd, 1, 0, 0b00101); //mask=0x000000000000003f
|
||||
} else {
|
||||
ANDw_mask(x2, gd, 0, 0b00100); //mask=0x00000001f
|
||||
}
|
||||
LSRxw_REG(x4, ed, x2);
|
||||
BFIw(xFlags, x4, F_CF, 1);
|
||||
}
|
||||
LSRxw_REG(x4, ed, x2);
|
||||
BFIw(xFlags, x4, F_CF, 1);
|
||||
break;
|
||||
case 0xA4:
|
||||
nextop = F8;
|
||||
INST_NAME("SHLD Ed, Gd, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETED(1);
|
||||
GETGD;
|
||||
u8 = F8;
|
||||
emit_shld32c(dyn, ninst, rex, ed, gd, u8, x3, x4);
|
||||
WBACK;
|
||||
if(geted_ib(dyn, addr, ninst, nextop)) {
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETED(1);
|
||||
GETGD;
|
||||
u8 = F8;
|
||||
emit_shld32c(dyn, ninst, rex, ed, gd, u8, x3, x4);
|
||||
WBACK;
|
||||
} else {
|
||||
FAKEED;
|
||||
F8;
|
||||
}
|
||||
break;
|
||||
case 0xA5:
|
||||
nextop = F8;
|
||||
@@ -1660,11 +1691,11 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETED(0);
|
||||
if(!rex.w && !rex.is32bits && MODREG) {MOVw_REG(ed, ed);}
|
||||
if(rex.w) {
|
||||
ANDSx_mask(x3, xRCX, 1, 0, 0b00101); //mask=0x000000000000003f
|
||||
ANDx_mask(x3, xRCX, 1, 0, 0b00101); //mask=0x000000000000003f
|
||||
} else {
|
||||
ANDSw_mask(x3, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
ANDw_mask(x3, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
}
|
||||
B_NEXT(cEQ);
|
||||
CBZw_NEXT(x3);
|
||||
emit_shld32(dyn, ninst, rex, ed, gd, x3, x5, x4);
|
||||
WBACK;
|
||||
break;
|
||||
@@ -1688,13 +1719,14 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
wback = 0;
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 0);
|
||||
ASRx(x1, gd, 5+rex.w); // r1 = (gd>>5)
|
||||
ADDx_REG_LSL(x3, wback, x1, 2+rex.w); //(&ed)+=r1*4;
|
||||
ASRxw(x1, gd, 5+rex.w); // r1 = (gd>>5)
|
||||
if(!rex.w && !rex.is32bits) {SXTWx(x1, x1);}
|
||||
ADDz_REG_LSL(x3, wback, x1, 2+rex.w); //(&ed)+=r1*4;
|
||||
LDxw(x1, x3, fixedaddress);
|
||||
ed = x1;
|
||||
wback = x3;
|
||||
@@ -1712,19 +1744,24 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
LSLxw_REG(x4, x4, x2);
|
||||
ORRxw_REG(ed, ed, x4);
|
||||
if(wback) {
|
||||
STRxw_U12(ed, wback, fixedaddress);
|
||||
STxw(ed, wback, fixedaddress);
|
||||
SMWRITE();
|
||||
}
|
||||
break;
|
||||
case 0xAC:
|
||||
nextop = F8;
|
||||
INST_NAME("SHRD Ed, Gd, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETED(1);
|
||||
GETGD;
|
||||
u8 = F8;
|
||||
emit_shrd32c(dyn, ninst, rex, ed, gd, u8, x3, x4);
|
||||
WBACK;
|
||||
if(geted_ib(dyn, addr, ninst, nextop)) {
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETED(1);
|
||||
GETGD;
|
||||
u8 = F8;
|
||||
emit_shrd32c(dyn, ninst, rex, ed, gd, u8, x3, x4);
|
||||
WBACK;
|
||||
} else {
|
||||
FAKEED;
|
||||
F8;
|
||||
}
|
||||
break;
|
||||
case 0xAD:
|
||||
nextop = F8;
|
||||
@@ -1736,11 +1773,11 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETED(0);
|
||||
if(!rex.w && !rex.is32bits && MODREG) {MOVw_REG(ed, ed);}
|
||||
if(rex.w) {
|
||||
ANDSx_mask(x3, xRCX, 1, 0, 0b00101); //mask=0x000000000000003f
|
||||
ANDx_mask(x3, xRCX, 1, 0, 0b00101); //mask=0x000000000000003f
|
||||
} else {
|
||||
ANDSw_mask(x3, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
ANDw_mask(x3, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
}
|
||||
B_NEXT(cEQ);
|
||||
CBZw_NEXT(x3);
|
||||
emit_shrd32(dyn, ninst, rex, ed, gd, x3, x5, x4);
|
||||
WBACK;
|
||||
break;
|
||||
@@ -1772,7 +1809,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
CALL(rex.w?((void*)fpu_fxsave64):((void*)fpu_fxsave32), -1);
|
||||
CALL(rex.is32bits?((void*)fpu_fxsave32):((void*)fpu_fxsave64), -1);
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FXRSTOR Ed");
|
||||
@@ -1780,7 +1817,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
CALL(rex.w?((void*)fpu_fxrstor64):((void*)fpu_fxrstor32), -1);
|
||||
CALL(rex.is32bits?((void*)fpu_fxrstor32):((void*)fpu_fxrstor64), -1);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("LDMXCSR Md");
|
||||
@@ -1807,7 +1844,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
MOV32w(x2, rex.is32bits);
|
||||
MOV32w(x2, rex.w?0:1);
|
||||
CALL((void*)fpu_xsave, -1);
|
||||
break;
|
||||
case 5:
|
||||
@@ -1816,7 +1853,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
MOV32w(x2, rex.is32bits);
|
||||
MOV32w(x2, rex.w?0:1);
|
||||
CALL((void*)fpu_xrstor, -1);
|
||||
break;
|
||||
case 7:
|
||||
@@ -1834,7 +1871,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0xAF:
|
||||
INST_NAME("IMUL Gd, Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED(0);
|
||||
@@ -1843,13 +1880,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
UFLAG_IF {
|
||||
SMULH(x3, gd, ed);
|
||||
MULx(gd, gd, ed);
|
||||
IFX(X_PEND) {
|
||||
UFLAG_OP1(x3);
|
||||
UFLAG_RES(gd);
|
||||
UFLAG_DF(x4, d_imul64);
|
||||
} else IFX(X_CF|X_OF) {
|
||||
SET_DFNONE(x4);
|
||||
}
|
||||
SET_DFNONE(x4);
|
||||
IFX(X_CF|X_OF) {
|
||||
ASRx(x4, gd, 63);
|
||||
CMPSx_REG(x3, x4);
|
||||
@@ -1870,13 +1901,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SMULL(gd, gd, ed);
|
||||
LSRx(x3, gd, 32);
|
||||
MOVw_REG(gd, gd);
|
||||
IFX(X_PEND) {
|
||||
UFLAG_RES(gd);
|
||||
UFLAG_OP1(x3);
|
||||
UFLAG_DF(x4, d_imul32);
|
||||
} else IFX(X_CF|X_OF) {
|
||||
SET_DFNONE(x4);
|
||||
}
|
||||
SET_DFNONE(x4);
|
||||
IFX(X_CF|X_OF) {
|
||||
ASRw(x4, gd, 31);
|
||||
CMPSw_REG(x3, x4);
|
||||
@@ -1888,17 +1913,16 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
BFIw(xFlags, x3, F_OF, 1);
|
||||
}
|
||||
}
|
||||
if(box64_dynarec_test) {
|
||||
// to avoid noise during test
|
||||
BFCw(xFlags, F_AF, 1);
|
||||
BFCw(xFlags, F_PF, 1);
|
||||
BFCw(xFlags, F_ZF, 1);
|
||||
BFCw(xFlags, F_SF, 1);
|
||||
}
|
||||
} else {
|
||||
MULxw(gd, gd, ed);
|
||||
}
|
||||
}
|
||||
IFX(X_AF | X_PF | X_ZF | X_SF)
|
||||
if(box64_dynarec_test) {
|
||||
// to avoid noise during test
|
||||
MOV32w(x1, (1<<F_ZF)|(1<<F_AF)|(1<<F_PF)|(1<<F_SF));
|
||||
BICw(xFlags, xFlags, x1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xB1:
|
||||
@@ -1908,28 +1932,23 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
wback = 0;
|
||||
UFLAG_IF {emit_cmp32(dyn, ninst, rex, xRAX, ed, x3, x4, x5);}
|
||||
MOVxw_REG(x1, ed); // save value
|
||||
CMPSxw_REG(xRAX, x1);
|
||||
if(rex.w) {
|
||||
CSELxw(ed, gd, ed, cEQ);
|
||||
} else {
|
||||
B_MARK2(cNE);
|
||||
MOVw_REG(ed, gd);
|
||||
MARK2;
|
||||
}
|
||||
SUBxw_REG(x4, xRAX, x1);
|
||||
CBNZxw_MARK(x4);
|
||||
MOVxw_REG(ed, gd);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 0);
|
||||
LDxw(x1, wback, fixedaddress);
|
||||
UFLAG_IF {emit_cmp32(dyn, ninst, rex, xRAX, x1, x3, x4, x5);}
|
||||
CMPSxw_REG(xRAX, x1);
|
||||
B_MARK(cNE);
|
||||
SUBxw_REG(x4, xRAX, x1);
|
||||
CBNZxw_MARK(x4);
|
||||
// EAX == Ed
|
||||
STxw(gd, wback, fixedaddress);
|
||||
MARK;
|
||||
}
|
||||
MARK;
|
||||
MOVxw_REG(xRAX, x1); // upper part of RAX will be erase on 32bits, no mater what
|
||||
break;
|
||||
|
||||
@@ -1940,13 +1959,14 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
wback = 0;
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 0);
|
||||
ASRx(x1, gd, 5+rex.w); // r1 = (gd>>5)
|
||||
ADDx_REG_LSL(x3, wback, x1, 2+rex.w); //(&ed)+=r1*4;
|
||||
ASRxw(x1, gd, 5+rex.w); // r1 = (gd>>5)
|
||||
if(!rex.w && !rex.is32bits) {SXTWx(x1, x1);}
|
||||
ADDz_REG_LSL(x3, wback, x1, 2+rex.w); //(&ed)+=r1*4;
|
||||
LDxw(x1, x3, fixedaddress);
|
||||
ed = x1;
|
||||
wback = x3;
|
||||
@@ -1964,7 +1984,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
LSLxw_REG(x4, x4, x2);
|
||||
BICxw_REG(ed, ed, x4);
|
||||
if(wback) {
|
||||
STRxw_U12(ed, wback, fixedaddress);
|
||||
STxw(ed, wback, fixedaddress);
|
||||
SMWRITE();
|
||||
}
|
||||
break;
|
||||
@@ -1975,11 +1995,11 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
if(rex.rex) {
|
||||
eb1 = xRAX+(nextop&7)+(rex.b<<3);
|
||||
eb1 = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
eb2 = 0; \
|
||||
} else {
|
||||
ed = (nextop&7);
|
||||
eb1 = xRAX+(ed&3); // Ax, Cx, Dx or Bx
|
||||
eb1 = TO_NAT(ed&3); // Ax, Cx, Dx or Bx
|
||||
eb2 = (ed&4)>>2; // L or H
|
||||
}
|
||||
UBFXxw(gd, eb1, eb2*8, 8);
|
||||
@@ -1994,7 +2014,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
UBFXxw(gd, ed, 0, 16);
|
||||
} else {
|
||||
SMREAD();
|
||||
@@ -2012,7 +2032,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SET_DFNONE(x1);
|
||||
gd = x2;
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 1);
|
||||
@@ -2028,7 +2048,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
wback = 0;
|
||||
} else {
|
||||
SMREAD();
|
||||
@@ -2041,8 +2061,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
IFX(X_CF) {
|
||||
BFXILxw(xFlags, ed, u8, 1); // inject 1 bit from u8 to F_CF (i.e. pos 0)
|
||||
}
|
||||
MOV32w(x4, 1);
|
||||
ORRxw_REG_LSL(ed, ed, x4, u8);
|
||||
mask = convert_bitmask_xw(1LL<<u8);
|
||||
ORRxw_mask(ed, ed, (mask>>12)&1, mask&0x3F, (mask>>6)&0x3F);
|
||||
if(wback) {
|
||||
STxw(ed, wback, fixedaddress);
|
||||
SMWRITE();
|
||||
@@ -2053,7 +2073,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
wback = 0;
|
||||
} else {
|
||||
SMREAD();
|
||||
@@ -2077,7 +2097,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
wback = 0;
|
||||
} else {
|
||||
SMREAD();
|
||||
@@ -2090,8 +2110,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
IFX(X_CF) {
|
||||
BFXILxw(xFlags, ed, u8, 1); // inject 1 bit from u8 to F_CF (i.e. pos 0)
|
||||
}
|
||||
MOV32w(x4, 1);
|
||||
EORxw_REG_LSL(ed, ed, x4, u8);
|
||||
mask = convert_bitmask_xw(1LL<<u8);
|
||||
EORxw_mask(ed, ed, (mask>>12)&1, mask&0x3F, (mask>>6)&0x3F);
|
||||
if(wback) {
|
||||
STxw(ed, wback, fixedaddress);
|
||||
SMWRITE();
|
||||
@@ -2108,13 +2128,14 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
wback = 0;
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 0);
|
||||
ASRx(x1, gd, 5+rex.w); // r1 = (gd>>5)
|
||||
ADDx_REG_LSL(x3, wback, x1, 2+rex.w); //(&ed)+=r1*4;
|
||||
ASRxw(x1, gd, 5+rex.w); // r1 = (gd>>5)
|
||||
if(!rex.w && !rex.is32bits) {SXTWx(x1, x1);}
|
||||
ADDz_REG_LSL(x3, wback, x1, 2+rex.w); //(&ed)+=r1*4;
|
||||
LDxw(x1, x3, fixedaddress);
|
||||
ed = x1;
|
||||
wback = x3;
|
||||
@@ -2143,14 +2164,20 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
GETGD;
|
||||
TSTxw_REG(ed, ed);
|
||||
B_MARK(cEQ);
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(ed, ed);
|
||||
B_MARK(cEQ);
|
||||
} else {
|
||||
CBZxw_MARK(ed);
|
||||
}
|
||||
RBITxw(x1, ed); // reverse
|
||||
CLZxw(gd, x1); // x2 gets leading 0 == BSF
|
||||
MARK;
|
||||
IFX(X_ZF) {
|
||||
CSETw(x1, cEQ); //other flags are undefined
|
||||
BFIw(xFlags, x1, F_ZF, 1);
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(x1, cEQ); //other flags are undefined
|
||||
BFIw(xFlags, x1, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xBD:
|
||||
@@ -2160,15 +2187,21 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETED(0);
|
||||
GETGD;
|
||||
TSTxw_REG(ed, ed);
|
||||
B_MARK(cEQ);
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(ed, ed);
|
||||
B_MARK(cEQ);
|
||||
} else {
|
||||
CBZxw_MARK(ed);
|
||||
}
|
||||
CLZxw(gd, ed); // x2 gets leading 0
|
||||
SUBxw_U12(gd, gd, rex.w?63:31);
|
||||
NEGxw_REG(gd, gd); // complement
|
||||
MARK;
|
||||
IFX(X_ZF) {
|
||||
CSETw(x1, cEQ); //other flags are undefined
|
||||
BFIw(xFlags, x1, F_ZF, 1);
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(x1, cEQ); //other flags are undefined
|
||||
BFIw(xFlags, x1, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xBE:
|
||||
@@ -2177,12 +2210,12 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
if(rex.rex) {
|
||||
wback = xRAX+(nextop&7)+(rex.b<<3);
|
||||
wback = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
wb2 = 0;
|
||||
} else {
|
||||
wback = (nextop&7);
|
||||
wb2 = (wback>>2)*8;
|
||||
wback = xRAX+(wback&3);
|
||||
wback = TO_NAT(wback&3);
|
||||
}
|
||||
SBFXxw(gd, wback, wb2, 8);
|
||||
} else {
|
||||
@@ -2196,7 +2229,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
SXTHxw(gd, ed);
|
||||
} else {
|
||||
SMREAD();
|
||||
@@ -2263,7 +2296,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if(MODREG) { // reg <= reg
|
||||
MOVxw_REG(xRAX+(nextop&7)+(rex.b<<3), gd);
|
||||
MOVxw_REG(TO_NAT((nextop & 7) + (rex.b << 3)), gd);
|
||||
} else { // mem <= reg
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, NULL, 0, 0);
|
||||
STxw(gd, ed, fixedaddress);
|
||||
@@ -2275,7 +2308,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETGM(v0);
|
||||
if(MODREG) {
|
||||
u8 = (F8)&3;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
VMOVQHfrom(v0, u8, ed);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 1);
|
||||
@@ -2313,16 +2346,30 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VMOVeS(v0, 1, v0, 0);
|
||||
} else if(v0==v1 && (u8==0xe5)) { // easy special case
|
||||
VMOVeS(v0, 0, v0, 1);
|
||||
} else if(v0==v1 && (u8==0x39)) {
|
||||
VEXTQ_8(v0, v0, v0, 4);
|
||||
} else if(u8==0x4E && MODREG) {
|
||||
VEXTQ_8(v0, v0, v1, 8);
|
||||
} else {
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
// first two elements from Gx
|
||||
for(int i=0; i<2; ++i) {
|
||||
VMOVeS(d0, i, v0, (u8>>(i*2))&3);
|
||||
if((u8&0xf)==0x04)
|
||||
VMOVeD(d0, 0, v0, 0);
|
||||
else if((u8&0xf)==0x0e)
|
||||
VMOVeD(d0, 0, v0, 1);
|
||||
else
|
||||
for(int i=0; i<2; ++i) {
|
||||
VMOVeS(d0, i, v0, (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);
|
||||
if((u8&0xf0)==0x40)
|
||||
VMOVeD(d0, 1, v1, 0);
|
||||
else if((u8&0xf0)==0xe0)
|
||||
VMOVeD(d0, 1, v1, 1);
|
||||
else
|
||||
for(int i=2; i<4; ++i) {
|
||||
VMOVeS(d0, i, v1, (u8>>(i*2))&3);
|
||||
}
|
||||
} else {
|
||||
SMREAD();
|
||||
@@ -2371,18 +2418,20 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
B_MARK(cNE); // EAX!=ED[0] || EDX!=Ed[1]
|
||||
STPxw_S7_offset(xRBX, xRCX, wback, 0);
|
||||
UFLAG_IF {
|
||||
MOV32w(x1, 1);
|
||||
IFNATIVE(NF_EQ) {} else {MOV32w(x1, 1);}
|
||||
}
|
||||
B_MARK3_nocond;
|
||||
MARK;
|
||||
MOVxw_REG(xRAX, x2);
|
||||
MOVxw_REG(xRDX, x3);
|
||||
UFLAG_IF {
|
||||
MOV32w(x1, 0);
|
||||
IFNATIVE(NF_EQ) {} else {MOV32w(x1, 0);}
|
||||
}
|
||||
MARK3;
|
||||
UFLAG_IF {
|
||||
BFIw(xFlags, x1, F_ZF, 1);
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
BFIw(xFlags, x1, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
SMWRITE();
|
||||
break;
|
||||
@@ -2423,7 +2472,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0xCE:
|
||||
case 0xCF: /* BSWAP reg */
|
||||
INST_NAME("BSWAP Reg");
|
||||
gd = xRAX+(opcode&7)+(rex.b<<3);
|
||||
gd = TO_NAT((opcode&7)+(rex.b<<3));
|
||||
REVxw(gd, gd);
|
||||
break;
|
||||
case 0xD1:
|
||||
|
||||
@@ -19,7 +19,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_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int seg, int* ok, int* need_epilog)
|
||||
@@ -108,7 +108,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
ADDx_REG(x4, x4, ed);
|
||||
ADDz_REG(x4, x4, ed);
|
||||
VLD64(v0, x4, fixedaddress); // upper part reseted
|
||||
}
|
||||
break;
|
||||
@@ -126,7 +126,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
ADDx_REG(x4, x4, ed);
|
||||
ADDz_REG(x4, x4, ed);
|
||||
VLD32(v0, x4, fixedaddress);
|
||||
}
|
||||
break;
|
||||
@@ -140,15 +140,16 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("MOVUPS Ex,Gx");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if(MODREG) {
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, ed);
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
ADDx_REG(x4, x4, ed);
|
||||
ADDz_REG(x4, x4, ed);
|
||||
VST128(v0, x4, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
@@ -157,15 +158,16 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("MOVSD Ex, Gx");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if(MODREG) {
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
ed = (nextop&7)+ (rex.b<<3);
|
||||
d0 = sse_get_reg(dyn, ninst, x1, ed, 1);
|
||||
VMOVeD(d0, 0, v0, 0);
|
||||
} else {
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
ADDx_REG(x4, x4, ed);
|
||||
ADDz_REG(x4, x4, ed);
|
||||
VST64(v0, x4, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
@@ -174,15 +176,16 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("MOVSS Ex, Gx");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if(MODREG) {
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
ed = (nextop&7)+ (rex.b<<3);
|
||||
q0 = sse_get_reg(dyn, ninst, x1, ed, 1);
|
||||
VMOVeS(q0, 0, v0, 0);
|
||||
} else {
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
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);
|
||||
ADDx_REG(x4, x4, ed);
|
||||
ADDz_REG(x4, x4, ed);
|
||||
VST32(v0, x4, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
@@ -192,21 +195,69 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x28:
|
||||
switch(rep) {
|
||||
case 0:
|
||||
INST_NAME("MOVAPS Gx,Seg:Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
VMOVQ(v0, v1);
|
||||
} else {
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
ADDz_REG(x4, x4, ed);
|
||||
VLD128(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0x29:
|
||||
switch(rep) {
|
||||
case 0:
|
||||
INST_NAME("MOVAPS Seg: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 {
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
ADDz_REG(x4, x4, ed);
|
||||
VST128(v0, x4, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x6F:
|
||||
switch(rep) {
|
||||
case 2:
|
||||
INST_NAME("MOVDQU Gx,Ex");// no alignment constraint on NEON here, so same as MOVDQA
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
if(MODREG) {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 0);
|
||||
VMOVQ(v0, v1);
|
||||
} else {
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
ADDx_REG(x4, x4, ed);
|
||||
ADDz_REG(x4, x4, ed);
|
||||
VLD128(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
@@ -220,7 +271,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
switch(rep) {
|
||||
case 0:
|
||||
INST_NAME("IMUL Gd, Ed");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
nextop = F8;
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
GETGD;
|
||||
@@ -230,9 +281,18 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
UFLAG_IF {
|
||||
SMULH(x3, gd, ed);
|
||||
MULx(gd, gd, ed);
|
||||
UFLAG_OP1(x3);
|
||||
UFLAG_RES(gd);
|
||||
UFLAG_DF(x3, d_imul64);
|
||||
SET_DFNONE(x4);
|
||||
IFX(X_CF|X_OF) {
|
||||
ASRx(x4, x3, 63);
|
||||
CMPSx_REG(x3, x4);
|
||||
CSETw(x3, cNE);
|
||||
IFX(X_CF) {
|
||||
BFIw(xFlags, x3, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BFIw(xFlags, x3, F_OF, 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
MULxw(gd, gd, ed);
|
||||
}
|
||||
@@ -242,13 +302,29 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SMULL(gd, gd, ed);
|
||||
UFLAG_RES(gd);
|
||||
LSRx(x3, gd, 32);
|
||||
UFLAG_OP1(x3);
|
||||
MOVw_REG(gd, gd);
|
||||
UFLAG_DF(x3, d_imul32);
|
||||
SET_DFNONE(x4);
|
||||
IFX(X_CF|X_OF) {
|
||||
ASRw(x4, gd, 31);
|
||||
CMPSw_REG(x3, x4);
|
||||
CSETw(x3, cNE);
|
||||
IFX(X_CF) {
|
||||
BFIw(xFlags, x3, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BFIw(xFlags, x3, F_OF, 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
MULxw(gd, gd, ed);
|
||||
}
|
||||
}
|
||||
IFX(X_AF | X_PF | X_ZF | X_SF)
|
||||
if(box64_dynarec_test) {
|
||||
// to avoid noise during test
|
||||
MOV32w(x1, (1<<F_ZF)|(1<<F_AF)|(1<<F_PF)|(1<<F_SF));
|
||||
BICw(xFlags, xFlags, x1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
@@ -264,18 +340,21 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
if(rex.rex) {
|
||||
eb1 = xRAX+(nextop&7)+(rex.b<<3);
|
||||
eb1 = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
eb2 = 0; \
|
||||
} else {
|
||||
ed = (nextop&7);
|
||||
eb1 = xRAX+(ed&3); // Ax, Cx, Dx or Bx
|
||||
eb1 = TO_NAT(ed & 3); // Ax, Cx, Dx or Bx
|
||||
eb2 = (ed&4)>>2; // L or H
|
||||
}
|
||||
UBFXxw(gd, eb1, eb2*8, 8);
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
LDRB_REG(gd, ed, x4);
|
||||
if(rex.is32bits)
|
||||
LDRB_REG_SXTW(gd, x4, ed);
|
||||
else
|
||||
LDRB_REG(gd, ed, x4);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -382,6 +461,25 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
emit_cmp32(dyn, ninst, rex, gd, ed, x3, x4, x5);
|
||||
break;
|
||||
|
||||
case 0x50:
|
||||
case 0x51:
|
||||
case 0x52:
|
||||
case 0x53:
|
||||
case 0x54:
|
||||
case 0x55:
|
||||
case 0x56:
|
||||
case 0x57:
|
||||
case 0x58:
|
||||
case 0x59:
|
||||
case 0x5A:
|
||||
case 0x5B:
|
||||
case 0x5C:
|
||||
case 0x5D:
|
||||
case 0x5E:
|
||||
case 0x5F:
|
||||
// just use regular conditional jump
|
||||
return dynarec64_00(dyn, addr-1, ip, ninst, rex, rep, ok, need_epilog);
|
||||
|
||||
case 0x63:
|
||||
if(rex.is32bits) {
|
||||
// ARPL here
|
||||
@@ -392,21 +490,27 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETGD;
|
||||
if(rex.w) {
|
||||
if(MODREG) { // reg <= reg
|
||||
SXTWx(gd, xRAX+(nextop&7)+(rex.b<<3));
|
||||
SXTWx(gd, TO_NAT((nextop & 7) + (rex.b << 3)));
|
||||
} else { // mem <= reg
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
LDRSW_REG(gd, ed, x4);
|
||||
if(rex.is32bits)
|
||||
LDRSW_REG_SXTW(gd, x4, ed);
|
||||
else
|
||||
LDRSW_REG(gd, ed, x4);
|
||||
}
|
||||
} else {
|
||||
if(MODREG) { // reg <= reg
|
||||
MOVw_REG(gd, xRAX+(nextop&7)+(rex.b<<3));
|
||||
MOVw_REG(gd, TO_NAT((nextop & 7) + (rex.b << 3)));
|
||||
} else { // mem <= reg
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
LDRw_REG(gd, ed, x4);
|
||||
if(rex.is32bits)
|
||||
LDRw_REG_SXTW(gd, x4, ed);
|
||||
else
|
||||
LDRw_REG(gd, ed, x4);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -428,6 +532,91 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x69:
|
||||
INST_NAME("IMUL Gd, Ed, Id");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
nextop = F8;
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
GETGD;
|
||||
GETEDO(x4, 4);
|
||||
i64 = F32S;
|
||||
MOV64xw(x4, i64);
|
||||
if(rex.w) {
|
||||
// 64bits imul
|
||||
UFLAG_IF {
|
||||
SMULH(x3, ed, x4);
|
||||
MULx(gd, ed, x4);
|
||||
SET_DFNONE(x1);
|
||||
IFX(X_ZF | X_PF | X_AF | X_SF) {
|
||||
MOV32w(x1, (1<<F_ZF)|(1<<F_AF)|(1<<F_PF)|(1<<F_SF));
|
||||
BICw(xFlags, xFlags, x1);
|
||||
}
|
||||
IFX(X_CF | X_OF) {
|
||||
ASRx(x4, gd, 63);
|
||||
CMPSx_REG(x3, x4);
|
||||
CSETw(x1, cNE);
|
||||
IFX(X_CF) {
|
||||
BFIw(xFlags, x1, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BFIw(xFlags, x1, F_OF, 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
MULxw(gd, ed, x4);
|
||||
}
|
||||
} else {
|
||||
// 32bits imul
|
||||
UFLAG_IF {
|
||||
SMULL(gd, ed, x4);
|
||||
LSRx(x3, gd, 32);
|
||||
MOVw_REG(gd, gd);
|
||||
SET_DFNONE(x1);
|
||||
IFX(X_ZF | X_PF | X_AF | X_SF) {
|
||||
MOV32w(x1, (1<<F_ZF)|(1<<F_AF)|(1<<F_PF)|(1<<F_SF));
|
||||
BICw(xFlags, xFlags, x1);
|
||||
}
|
||||
IFX(X_CF | X_OF) {
|
||||
ASRw(x4, gd, 31);
|
||||
CMPSw_REG(x3, x4);
|
||||
CSETw(x1, cNE);
|
||||
IFX(X_CF) {
|
||||
BFIw(xFlags, x1, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BFIw(xFlags, x1, F_OF, 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
MULxw(gd, ed, x4);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x6C:
|
||||
case 0x6D:
|
||||
INST_NAME(opcode == 0x6C ? "INSB" : "INSD");
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_priv, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
break;
|
||||
case 0x6E:
|
||||
case 0x6F:
|
||||
INST_NAME(opcode == 0x6C ? "OUTSB" : "OUTSD");
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(native_priv, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
break;
|
||||
case 0x70:
|
||||
case 0x71:
|
||||
case 0x72:
|
||||
@@ -609,25 +798,88 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x85:
|
||||
INST_NAME("TEST Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop=F8;
|
||||
grab_segdata(dyn, addr, ninst, x6, seg);
|
||||
GETGD;
|
||||
GETEDO(x6, 0);
|
||||
emit_test32(dyn, ninst, rex, ed, gd, x3, x5, x6);
|
||||
break;
|
||||
|
||||
case 0x88:
|
||||
INST_NAME("MOV Eb, Gb");
|
||||
nextop = F8;
|
||||
gd = ((nextop&0x38)>>3)+(rex.r<<3);
|
||||
if(rex.rex) {
|
||||
gb2 = 0;
|
||||
gb1 = TO_NAT(gd);
|
||||
} else {
|
||||
gb2 = ((gd&4)<<1);
|
||||
gb1 = TO_NAT(gd & 3);
|
||||
}
|
||||
if(gb2) {
|
||||
gd = x4;
|
||||
UBFXw(gd, gb1, gb2, 8);
|
||||
} else {
|
||||
gd = gb1; // no need to extract
|
||||
}
|
||||
if(MODREG) {
|
||||
ed = (nextop&7) + (rex.b<<3);
|
||||
if(rex.rex) {
|
||||
eb1 = TO_NAT(ed);
|
||||
eb2 = 0;
|
||||
} else {
|
||||
eb1 = TO_NAT(ed & 3); // Ax, Cx, Dx or Bx
|
||||
eb2 = ((ed&4)>>2); // L or H
|
||||
}
|
||||
BFIx(eb1, gd, eb2*8, 8);
|
||||
} else {
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(rex.is32bits)
|
||||
STRB_REG_SXTW(gd, x4, wback);
|
||||
else
|
||||
STRB_REG(gd, wback, x4);
|
||||
}
|
||||
break;
|
||||
case 0x89:
|
||||
INST_NAME("MOV Seg:Ed, Gd");
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if(MODREG) { // reg <= reg
|
||||
MOVxw_REG(TO_NAT((nextop & 7) + (rex.b << 3)), gd);
|
||||
} else { // mem <= reg
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(rex.is32bits)
|
||||
STRxw_REG_SXTW(gd, x4, ed);
|
||||
else
|
||||
STRxw_REG(gd, ed, x4);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x8A:
|
||||
INST_NAME("MOV Gb, Eb");
|
||||
nextop = F8;
|
||||
if(rex.rex) {
|
||||
gb1 = gd = xRAX+((nextop&0x38)>>3)+(rex.r<<3);
|
||||
gb1 = gd = TO_NAT(((nextop & 0x38) >> 3) + (rex.r << 3));
|
||||
gb2=0;
|
||||
} else {
|
||||
gd = (nextop&0x38)>>3;
|
||||
gb1 = xRAX+(gd&3);
|
||||
gb1 = TO_NAT(gd & 3);
|
||||
gb2 = ((gd&4)<<1);
|
||||
}
|
||||
if(MODREG) {
|
||||
if(rex.rex) {
|
||||
wback = xRAX+(nextop&7)+(rex.b<<3);
|
||||
wback = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
wb2 = 0;
|
||||
} else {
|
||||
wback = (nextop&7);
|
||||
wb2 = (wback>>2);
|
||||
wback = xRAX+(wback&3);
|
||||
wback = TO_NAT(wback & 3);
|
||||
}
|
||||
if(wb2) {
|
||||
UBFXw(x4, wback, wb2*8, 8);
|
||||
@@ -639,36 +891,28 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
LDRB_REG(x4, wback, x4);
|
||||
if(rex.is32bits)
|
||||
LDRB_REG_SXTW(x4, x4, wback);
|
||||
else
|
||||
LDRB_REG(x4, wback, x4);
|
||||
ed = x4;
|
||||
}
|
||||
BFIx(gb1, ed, gb2, 8);
|
||||
break;
|
||||
case 0x89:
|
||||
INST_NAME("MOV Seg:Ed, Gd");
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if(MODREG) { // reg <= reg
|
||||
MOVxw_REG(xRAX+(nextop&7)+(rex.b<<3), gd);
|
||||
} else { // mem <= reg
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
STRxw_REG(gd, ed, x4);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x8B:
|
||||
INST_NAME("MOV Gd, Seg:Ed");
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if(MODREG) { // reg <= reg
|
||||
MOVxw_REG(gd, xRAX+(nextop&7)+(rex.b<<3));
|
||||
MOVxw_REG(gd, TO_NAT((nextop & 7) + (rex.b << 3)));
|
||||
} else { // mem <= reg
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
LDRxw_REG(gd, ed, x4);
|
||||
if(rex.is32bits)
|
||||
LDRxw_REG_SXTW(gd, x4, ed);
|
||||
else
|
||||
LDRxw_REG(gd, ed, x4);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -694,11 +938,14 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
u8 = (nextop&0x38)>>3;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
LDRH_REG(x1, wback, x4);
|
||||
if(rex.is32bits)
|
||||
LDRH_REG_SXTW(x1, x4, wback);
|
||||
else
|
||||
LDRH_REG(x1, wback, x4);
|
||||
ed = x1;
|
||||
}
|
||||
STRH_U12(ed, xEmu, offsetof(x64emu_t, segs[u8]));
|
||||
@@ -709,16 +956,22 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
POP1z(xRAX+(nextop&7)+(rex.b<<3));
|
||||
POP1z(TO_NAT((nextop & 7) + (rex.b << 3)));
|
||||
} else {
|
||||
POP1z(x2); // so this can handle POP [ESP] and maybe some variant too
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed==xRSP) {
|
||||
STRz_REG(x2, ed, x4);
|
||||
if(rex.is32bits)
|
||||
STRz_REG_SXTW(x2, x4, ed);
|
||||
else
|
||||
STRz_REG(x2, ed, x4);
|
||||
} else {
|
||||
// complicated to just allow a segfault that can be recovered correctly
|
||||
SUBz_U12(xRSP, xRSP, rex.is32bits?4:8);
|
||||
STRz_REG(x2, ed, x4);
|
||||
if(rex.is32bits)
|
||||
STRz_REG_SXTW(x2, x4, ed);
|
||||
else
|
||||
STRz_REG(x2, ed, x4);
|
||||
ADDz_U12(xRSP, xRSP, rex.is32bits?4:8);
|
||||
}
|
||||
}
|
||||
@@ -727,6 +980,22 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("NOP");
|
||||
break;
|
||||
|
||||
case 0x9D:
|
||||
INST_NAME("POPF");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
POP1z(xFlags);
|
||||
MOV32w(x1, 0x3F7FD7);
|
||||
ANDw_REG(xFlags, xFlags, x1);
|
||||
MOV32w(x1, 0x202);
|
||||
ORRw_REG(xFlags, xFlags, x1);
|
||||
SET_DFNONE(x1);
|
||||
if(box64_wine) { // should this be done all the time?
|
||||
TBZ_NEXT(xFlags, F_TF);
|
||||
// go to epilog, TF should trigger at end of next opcode, so using Interpreter only
|
||||
jump_to_epilog(dyn, addr, 0, ninst);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xA1:
|
||||
INST_NAME("MOV EAX,FS:Od");
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
@@ -735,9 +1004,25 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
else
|
||||
u64 = F64;
|
||||
MOV64z(x1, u64);
|
||||
LDRxw_REG(xRAX, x1, x4);
|
||||
if(rex.is32bits)
|
||||
LDRxw_REG_SXTW(xRAX, x4, x1);
|
||||
else
|
||||
LDRxw_REG(xRAX, x4, x1);
|
||||
break;
|
||||
case 0xA2:
|
||||
INST_NAME("MOV FS:Od,AL");
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
if(rex.is32bits)
|
||||
u64 = F32;
|
||||
else
|
||||
u64 = F64;
|
||||
MOV64z(x1, u64);
|
||||
if(rex.is32bits)
|
||||
STRB_REG_SXTW(xRAX, x4, x1);
|
||||
else
|
||||
STRB_REG(xRAX, x4, x1);
|
||||
SMWRITE2();
|
||||
break;
|
||||
|
||||
case 0xA3:
|
||||
INST_NAME("MOV FS:Od,EAX");
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
@@ -746,10 +1031,22 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
else
|
||||
u64 = F64;
|
||||
MOV64z(x1, u64);
|
||||
STRxw_REG(xRAX, x1, x4);
|
||||
if(rex.is32bits)
|
||||
STRxw_REG_SXTW(xRAX, x4, x1);
|
||||
else
|
||||
STRxw_REG(xRAX, x4, x1);
|
||||
SMWRITE2();
|
||||
break;
|
||||
|
||||
case 0xA8:
|
||||
INST_NAME("TEST AL, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
UXTBx(x1, xRAX);
|
||||
u8 = F8;
|
||||
MOV32w(x2, u8);
|
||||
emit_test8(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
break;
|
||||
|
||||
case 0xC6:
|
||||
INST_NAME("MOV Seg:Eb, Ib");
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
@@ -758,10 +1055,10 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
u8 = F8;
|
||||
if(!rex.rex) {
|
||||
ed = (nextop&7);
|
||||
eb1 = xRAX+(ed&3); // Ax, Cx, Dx or Bx
|
||||
eb1 = TO_NAT(ed & 3); // Ax, Cx, Dx or Bx
|
||||
eb2 = (ed&4)>>2; // L or H
|
||||
} else {
|
||||
eb1 = xRAX+(nextop&7)+(rex.b<<3);
|
||||
eb1 = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
eb2 = 0;
|
||||
}
|
||||
MOV32w(x3, u8);
|
||||
@@ -770,7 +1067,10 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 1);
|
||||
u8 = F8;
|
||||
MOV32w(x3, u8);
|
||||
STRB_REG(x3, ed, x4);
|
||||
if(rex.is32bits)
|
||||
STRB_REG_SXTW(x3, x4, ed);
|
||||
else
|
||||
STRB_REG(x3, ed, x4);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
@@ -780,13 +1080,16 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop=F8;
|
||||
if(MODREG) { // reg <= i32
|
||||
i64 = F32S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
MOV64xw(ed, i64);
|
||||
} else { // mem <= i32
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 4);
|
||||
i64 = F32S;
|
||||
MOV64xw(x3, i64);
|
||||
STRxw_REG(x3, ed, x4);
|
||||
if(rex.is32bits)
|
||||
STRxw_REG_SXTW(x3, x4, ed);
|
||||
else
|
||||
STRxw_REG(x3, ed, x4);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
@@ -797,14 +1100,14 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("ROL Ed, 1");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
|
||||
GETEDO(x6, 0);
|
||||
emit_rol32c(dyn, ninst, rex, ed, 1, x3, x4);
|
||||
WBACKO(x6);
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("ROR Ed, 1");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
|
||||
GETEDO(x6, 0);
|
||||
emit_ror32c(dyn, ninst, rex, ed, 1, x3, x4);
|
||||
WBACKO(x6);
|
||||
@@ -857,22 +1160,21 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("ROL Ed, CL");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET);
|
||||
if(rex.w) {
|
||||
ANDSx_mask(x3, xRCX, 1, 0, 0b00101); //mask=0x000000000000003f
|
||||
ANDx_mask(x3, xRCX, 1, 0, 0b00101); //mask=0x000000000000003f
|
||||
} else {
|
||||
ANDSw_mask(x3, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
ANDw_mask(x3, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
}
|
||||
MOV64xw(x4, (rex.w?64:32));
|
||||
SUBx_REG(x3, x4, x3);
|
||||
GETEDO(x6, 0);
|
||||
if(!rex.w && MODREG) {MOVw_REG(ed, ed);}
|
||||
B_NEXT(cEQ);
|
||||
CBZw_NEXT(x3);
|
||||
RORxw_REG(ed, ed, x3);
|
||||
WBACKO(x6);
|
||||
UFLAG_IF { // calculate flags directly
|
||||
CMPSw_U12(x3, rex.w?63:31);
|
||||
B_MARK(cNE);
|
||||
LSRxw(x4, ed, rex.w?63:31);
|
||||
ADDxw_REG(x4, x4, ed);
|
||||
SUBw_U12(x4, x3, rex.w?63:31);
|
||||
CBNZw_MARK(x4);
|
||||
EORw_REG_LSR(x4, ed, ed, rex.w?63:31);
|
||||
BFIw(xFlags, x4, F_OF, 1);
|
||||
MARK;
|
||||
BFIw(xFlags, ed, F_CF, 1);
|
||||
@@ -883,18 +1185,18 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("ROR Ed, CL");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET);
|
||||
if(rex.w) {
|
||||
ANDSx_mask(x3, xRCX, 1, 0, 0b00101); //mask=0x000000000000003f
|
||||
ANDx_mask(x3, xRCX, 1, 0, 0b00101); //mask=0x000000000000003f
|
||||
} else {
|
||||
ANDSw_mask(x3, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
ANDw_mask(x3, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
}
|
||||
GETEDO(x6, 0);
|
||||
if(!rex.w && MODREG) {MOVw_REG(ed, ed);}
|
||||
B_NEXT(cEQ);
|
||||
CBZw_NEXT(x3);
|
||||
RORxw_REG(ed, ed, x3);
|
||||
WBACKO(x6);
|
||||
UFLAG_IF { // calculate flags directly
|
||||
CMPSw_U12(x3, 1);
|
||||
B_MARK(cNE);
|
||||
SUBw_U12(x2, x3, 1);
|
||||
CBNZw_MARK(x2);
|
||||
LSRxw(x2, ed, rex.w?62:30); // x2 = d>>30
|
||||
EORw_REG_LSR(x2, x2, x2, 1); // x2 = ((d>>30) ^ ((d>>30)>>1))
|
||||
BFIw(xFlags, x2, F_OF, 1);
|
||||
@@ -910,14 +1212,14 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
if(rex.w) {
|
||||
ANDSx_mask(x2, xRCX, 1, 0, 0b00101); //mask=0x000000000000003f
|
||||
ANDx_mask(x2, xRCX, 1, 0, 0b00101); //mask=0x000000000000003f
|
||||
} else {
|
||||
ANDSw_mask(x2, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
ANDw_mask(x2, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
}
|
||||
GETEDO(x6, 0);
|
||||
if(wback) {ADDx_REG(x6, x6, wback); wback=x6;}
|
||||
if(!rex.w && MODREG) {MOVw_REG(ed, ed);}
|
||||
B_NEXT(cEQ);
|
||||
CBZw_NEXT(x2);
|
||||
CALL_(rex.w?((void*)rcl64):((void*)rcl32), ed, x6);
|
||||
WBACK;
|
||||
break;
|
||||
@@ -927,14 +1229,14 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
if(rex.w) {
|
||||
ANDSx_mask(x2, xRCX, 1, 0, 0b00101); //mask=0x000000000000003f
|
||||
ANDx_mask(x2, xRCX, 1, 0, 0b00101); //mask=0x000000000000003f
|
||||
} else {
|
||||
ANDSw_mask(x2, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
ANDw_mask(x2, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
}
|
||||
GETEDO(x6, 0);
|
||||
if(wback) {ADDx_REG(x6, x6, wback); wback=x6;}
|
||||
if(!rex.w && MODREG) {MOVw_REG(ed, ed);}
|
||||
B_NEXT(cEQ);
|
||||
CBZw_NEXT(x2);
|
||||
CALL_(rex.w?((void*)rcr64):((void*)rcr32), ed, x6);
|
||||
WBACK;
|
||||
break;
|
||||
@@ -942,47 +1244,50 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 6:
|
||||
INST_NAME("SHL Ed, CL");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
if(box64_dynarec_safeflags>1)
|
||||
MAYSETFLAGS();
|
||||
if(rex.w) {
|
||||
ANDSx_mask(x3, xRCX, 1, 0, 0b00101); //mask=0x000000000000003f
|
||||
ANDx_mask(x3, xRCX, 1, 0, 0b00101); //mask=0x000000000000003f
|
||||
} else {
|
||||
ANDSw_mask(x3, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
ANDw_mask(x3, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
}
|
||||
GETEDO(x6, 0);
|
||||
if(!rex.w && MODREG) {MOVw_REG(ed, ed);}
|
||||
B_NEXT(cEQ);
|
||||
CBZw_NEXT(x3);
|
||||
emit_shl32(dyn, ninst, rex, ed, x3, x5, x4);
|
||||
WBACKO(x6);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("SHR Ed, CL");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
if(box64_dynarec_safeflags>1)
|
||||
MAYSETFLAGS();
|
||||
if(rex.w) {
|
||||
ANDSx_mask(x3, xRCX, 1, 0, 0b00101); //mask=0x000000000000003f
|
||||
ANDx_mask(x3, xRCX, 1, 0, 0b00101); //mask=0x000000000000003f
|
||||
} else {
|
||||
ANDSw_mask(x3, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
ANDw_mask(x3, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
}
|
||||
GETEDO(x6, 0);
|
||||
if(!rex.w && MODREG) {MOVw_REG(ed, ed);}
|
||||
B_NEXT(cEQ);
|
||||
CBZw_NEXT(x3);
|
||||
emit_shr32(dyn, ninst, rex, ed, x3, x5, x4);
|
||||
WBACKO(x6);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("SAR Ed, CL");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(box64_dynarec_safeflags>1)
|
||||
MAYSETFLAGS();
|
||||
if(rex.w) {
|
||||
ANDSx_mask(x3, xRCX, 1, 0, 0b00101); //mask=0x000000000000003f
|
||||
ANDx_mask(x3, xRCX, 1, 0, 0b00101); //mask=0x000000000000003f
|
||||
} else {
|
||||
ANDSw_mask(x3, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
ANDw_mask(x3, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
}
|
||||
GETEDO(x6, 0);
|
||||
if(!rex.w && MODREG) {MOVw_REG(ed, ed);}
|
||||
B_NEXT(cEQ);
|
||||
UFLAG_OP12(ed, x3);
|
||||
ASRxw_REG(ed, ed, x3);
|
||||
CBZw_NEXT(x3);
|
||||
emit_sar32(dyn, ninst, rex, ed, x3, x5, x4);
|
||||
WBACKO(x6);
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, rex.w?d_sar64:d_sar32);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -1001,8 +1306,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEDO(x6, 4);
|
||||
i64 = F32S;
|
||||
MOV64xw(x2, i64);
|
||||
emit_test32(dyn, ninst, rex, ed, x2, x3, x4, x5);
|
||||
emit_test32c(dyn, ninst, rex, ed, i64, x3, x4, x5);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("NOT Ed");
|
||||
@@ -1019,7 +1323,7 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("MUL EAX, Ed");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETEDO(x6, 0);
|
||||
if(rex.w) {
|
||||
if(ed==xRDX) gd=x3; else gd=xRDX;
|
||||
@@ -1031,13 +1335,29 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOVw_REG(xRAX, xRDX);
|
||||
LSRx(xRDX, xRDX, 32);
|
||||
}
|
||||
UFLAG_RES(xRAX);
|
||||
UFLAG_OP1(xRDX);
|
||||
UFLAG_DF(x2, rex.w?d_mul64:d_mul32);
|
||||
UFLAG_IF {
|
||||
SET_DFNONE(x4);
|
||||
IFX(X_CF|X_OF) {
|
||||
CMPSxw_U12(xRDX, 0);
|
||||
CSETw(x3, cNE);
|
||||
IFX(X_CF) {
|
||||
BFIw(xFlags, x3, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BFIw(xFlags, x3, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_AF | X_PF | X_ZF | X_SF)
|
||||
if(box64_dynarec_test) {
|
||||
// to avoid noise during test
|
||||
MOV32w(x3, (1<<F_ZF)|(1<<F_AF)|(1<<F_PF)|(1<<F_SF));
|
||||
BICw(xFlags, xFlags, x3);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("IMUL EAX, Ed");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETEDO(x6, 0);
|
||||
if(rex.w) {
|
||||
if(ed==xRDX) gd=x3; else gd=xRDX;
|
||||
@@ -1049,14 +1369,30 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOVw_REG(xRAX, xRDX);
|
||||
LSRx(xRDX, xRDX, 32);
|
||||
}
|
||||
UFLAG_RES(xRAX);
|
||||
UFLAG_OP1(xRDX);
|
||||
UFLAG_DF(x2, rex.w?d_imul64:d_imul32);
|
||||
UFLAG_IF {
|
||||
SET_DFNONE(x4);
|
||||
IFX(X_CF|X_OF) {
|
||||
ASRxw(x4, xRAX, rex.w?63:31);
|
||||
CMPSxw_REG(xRDX, x4);
|
||||
CSETw(x3, cNE);
|
||||
IFX(X_CF) {
|
||||
BFIw(xFlags, x3, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BFIw(xFlags, x3, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_AF | X_PF | X_ZF | X_SF)
|
||||
if(box64_dynarec_test) {
|
||||
// to avoid noise during test
|
||||
MOV32w(x3, (1<<F_ZF)|(1<<F_AF)|(1<<F_PF)|(1<<F_SF));
|
||||
BICw(xFlags, xFlags, x3);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("DIV Ed");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SET_DFNONE(x2);
|
||||
if(!rex.w) {
|
||||
GETEDO(x6, 0);
|
||||
if(box64_dynarec_div0) {
|
||||
@@ -1120,12 +1456,17 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOVx_REG(xRAX, x2);
|
||||
}
|
||||
}
|
||||
SET_DFNONE(x2);
|
||||
IFX(X_AF | X_SF | X_CF | X_PF | X_ZF | X_OF)
|
||||
if(box64_dynarec_test) {
|
||||
MOV32w(x1, (1<<F_AF) | (1<<F_SF) | (1<<F_CF) | (1<<F_PF) | (1<<F_ZF) | (1<<F_OF));
|
||||
BICw(xFlags, xFlags, x1);
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("IDIV Ed");
|
||||
NOTEST(x1);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SET_DFNONE(x2)
|
||||
if(!rex.w) {
|
||||
GETSEDOw(x6, 0);
|
||||
MOVw_REG(x3, xRAX);
|
||||
@@ -1187,6 +1528,12 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOVx_REG(xRAX, x2);
|
||||
}
|
||||
}
|
||||
SET_DFNONE(x2);
|
||||
IFX(X_AF | X_SF | X_CF | X_PF | X_ZF | X_OF)
|
||||
if(box64_dynarec_test) {
|
||||
MOV32w(x1, (1<<F_AF) | (1<<F_SF) | (1<<F_CF) | (1<<F_PF) | (1<<F_ZF) | (1<<F_OF));
|
||||
BICw(xFlags, xFlags, x1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -1197,14 +1544,14 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: // INC Ed
|
||||
INST_NAME("INC Ed");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
GETEDO(x6, 0);
|
||||
emit_inc32(dyn, ninst, rex, ed, x3, x4);
|
||||
WBACKO(x6);
|
||||
break;
|
||||
case 1: //DEC Ed
|
||||
INST_NAME("DEC Ed");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
GETEDO(x6, 0);
|
||||
emit_dec32(dyn, ninst, rex, ed, x3, x4);
|
||||
WBACKO(x6);
|
||||
@@ -1222,7 +1569,6 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETEDOz(x6, 0);
|
||||
if(box64_dynarec_callret && box64_dynarec_bigblock>1) {
|
||||
BARRIER(BARRIER_FULL);
|
||||
BARRIER_NEXT(BARRIER_FULL);
|
||||
} else {
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
*need_epilog = 0;
|
||||
@@ -1238,15 +1584,22 @@ uintptr_t dynarec64_64(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ADR_S20(x4, j64);
|
||||
MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
|
||||
} else {
|
||||
MESSAGE(LOG_NONE, "\tCALLRET set return to Jmptable(%p)\n", (void*)addr);
|
||||
j64 = getJumpTableAddress64(addr);
|
||||
TABLE64(x4, j64);
|
||||
LDRx_U12(x4, x4, 0);
|
||||
j64 = (dyn->insts)?(GETMARK-(dyn->native_size)):0;
|
||||
ADR_S20(x4, j64);
|
||||
MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
|
||||
}
|
||||
STPx_S7_preindex(x4, xRIP, xSP, -16);
|
||||
}
|
||||
PUSH1z(xRIP);
|
||||
jump_to_next(dyn, 0, ed, ninst, rex.is32bits);
|
||||
if(box64_dynarec_callret && addr >= (dyn->start + dyn->isize)) {
|
||||
// jumps out of current dynablock...
|
||||
MARK;
|
||||
j64 = getJumpTableAddress64(addr);
|
||||
TABLE64(x4, j64);
|
||||
LDRx_U12(x4, x4, 0);
|
||||
BR(x4);
|
||||
}
|
||||
break;
|
||||
case 4: // JMP Ed
|
||||
INST_NAME("JMP Ed");
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "../dynarec_helper.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
|
||||
|
||||
@@ -78,9 +78,9 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0x05:
|
||||
INST_NAME("ADD AX, Iw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i32 = F16;
|
||||
i16 = F16;
|
||||
UXTHw(x1, xRAX);
|
||||
MOV32w(x2, i32);
|
||||
MOV32w(x2, i16);
|
||||
emit_add16(dyn, ninst, x1, x2, x3, x4);
|
||||
BFIz(xRAX, x1, 0, 16);
|
||||
break;
|
||||
@@ -102,7 +102,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
emit_or16(dyn, ninst, x1, x2, x4, x2);
|
||||
emit_or16(dyn, ninst, x1, x2, x4, x5);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0x0B:
|
||||
@@ -117,10 +117,9 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0x0D:
|
||||
INST_NAME("OR AX, Iw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i32 = F16;
|
||||
i16 = F16;
|
||||
UXTHw(x1, xRAX);
|
||||
MOV32w(x2, i32);
|
||||
emit_or16(dyn, ninst, x1, x2, x3, x4);
|
||||
emit_or16c(dyn, ninst, x1, i16, x3, x4);
|
||||
BFIz(xRAX, x1, 0, 16);
|
||||
break;
|
||||
|
||||
@@ -155,9 +154,9 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("ADC AX, Iw");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i32 = F16;
|
||||
u16 = F16;
|
||||
UXTHw(x1, xRAX);
|
||||
MOV32w(x2, i32);
|
||||
MOV32w(x2, u16);
|
||||
emit_adc16(dyn, ninst, x1, x2, x3, x4);
|
||||
BFIz(xRAX, x1, 0, 16);
|
||||
break;
|
||||
@@ -225,10 +224,9 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0x25:
|
||||
INST_NAME("AND AX, Iw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i32 = F16;
|
||||
i16 = F16;
|
||||
UXTHw(x1, xRAX);
|
||||
MOV32w(x2, i32);
|
||||
emit_and16(dyn, ninst, x1, x2, x3, x4);
|
||||
emit_and16c(dyn, ninst, x1, i16, x3, x4);
|
||||
BFIz(xRAX, x1, 0, 16);
|
||||
break;
|
||||
|
||||
@@ -253,9 +251,9 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0x2D:
|
||||
INST_NAME("SUB AX, Iw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i32 = F16;
|
||||
i16 = F16;
|
||||
UXTHw(x1, xRAX);
|
||||
MOV32w(x2, i32);
|
||||
MOV32w(x2, i16);
|
||||
emit_sub16(dyn, ninst, x1, x2, x3, x4);
|
||||
BFIz(xRAX, x1, 0, 16);
|
||||
break;
|
||||
@@ -281,10 +279,9 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0x35:
|
||||
INST_NAME("XOR AX, Iw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i32 = F16;
|
||||
i16 = F16;
|
||||
UXTHw(x1, xRAX);
|
||||
MOV32w(x2, i32);
|
||||
emit_xor16(dyn, ninst, x1, x2, x3, x4);
|
||||
emit_xor16c(dyn, ninst, x1, i16, x3, x4);
|
||||
BFIz(xRAX, x1, 0, 16);
|
||||
break;
|
||||
|
||||
@@ -307,10 +304,10 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0x3D:
|
||||
INST_NAME("CMP AX, Iw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i32 = F16;
|
||||
u16 = F16;
|
||||
UXTHw(x1, xRAX);
|
||||
if(i32) {
|
||||
MOV32w(x2, i32);
|
||||
if(u16) {
|
||||
MOV32w(x2, u16);
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
} else {
|
||||
emit_cmp16_0(dyn, ninst, x1, x3, x4);
|
||||
@@ -326,11 +323,11 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0x46:
|
||||
case 0x47:
|
||||
INST_NAME("INC Reg16 (32bits)");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
gd = xRAX + (opcode&7);
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
gd = TO_NAT (opcode&7);
|
||||
UXTHw(x1, gd);
|
||||
emit_inc16(dyn, ninst, x1, x2, x3);
|
||||
BFIw(gd, x1, 0, 16);
|
||||
BFIz(gd, x1, 0, 16);
|
||||
break;
|
||||
case 0x48:
|
||||
case 0x49:
|
||||
@@ -341,11 +338,11 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0x4E:
|
||||
case 0x4F:
|
||||
INST_NAME("DEC Reg16 (32bits)");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
gd = xRAX + (opcode&7);
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
gd = TO_NAT (opcode&7);
|
||||
UXTHw(x1, gd);
|
||||
emit_dec16(dyn, ninst, x1, x2, x3);
|
||||
BFIw(gd, x1, 0, 16);
|
||||
BFIz(gd, x1, 0, 16);
|
||||
break;
|
||||
case 0x50:
|
||||
case 0x51:
|
||||
@@ -356,7 +353,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0x56:
|
||||
case 0x57:
|
||||
INST_NAME("PUSH reg");
|
||||
gd = xRAX+(opcode&0x07)+(rex.b<<3);
|
||||
gd = TO_NAT((opcode & 0x07) + (rex.b << 3));
|
||||
if (gd==xRSP) {
|
||||
MOVw_REG(x1, xRSP);
|
||||
PUSH1_16(x1);
|
||||
@@ -373,9 +370,9 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0x5E:
|
||||
case 0x5F:
|
||||
INST_NAME("POP reg");
|
||||
gd = xRAX+(opcode&0x07)+(rex.b<<3);
|
||||
gd = TO_NAT((opcode & 0x07) + (rex.b << 3));
|
||||
POP1_16(x1);
|
||||
BFIw(gd, x1, 0, 16);
|
||||
BFIz(gd, x1, 0, 16);
|
||||
break;
|
||||
case 0x60:
|
||||
if(rex.is32bits) {
|
||||
@@ -397,20 +394,20 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(rex.is32bits) {
|
||||
INST_NAME("POPA 16bits (32bits)");
|
||||
POP1_16(x1);
|
||||
BFIw(xRDI, x1, 0, 16);
|
||||
BFIz(xRDI, x1, 0, 16);
|
||||
POP1_16(x1);
|
||||
BFIw(xRSI, x1, 0, 16);
|
||||
BFIz(xRSI, x1, 0, 16);
|
||||
POP1_16(x1);
|
||||
BFIw(xRBP, x1, 0, 16);
|
||||
BFIz(xRBP, x1, 0, 16);
|
||||
POP1_16(x1); // RSP ignored
|
||||
POP1_16(x1);
|
||||
BFIw(xRBX, x1, 0, 16);
|
||||
BFIz(xRBX, x1, 0, 16);
|
||||
POP1_16(x1);
|
||||
BFIw(xRDX, x1, 0, 16);
|
||||
BFIz(xRDX, x1, 0, 16);
|
||||
POP1_16(x1);
|
||||
BFIw(xRCX, x1, 0, 16);
|
||||
BFIz(xRCX, x1, 0, 16);
|
||||
POP1_16(x1);
|
||||
BFIw(xRAX, x1, 0, 16);
|
||||
BFIz(xRAX, x1, 0, 16);
|
||||
} else {
|
||||
DEFAULT;
|
||||
}
|
||||
@@ -450,6 +447,12 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GWBACK;
|
||||
UFLAG_DF(x1, d_imul16);
|
||||
break;
|
||||
case 0x6A:
|
||||
INST_NAME("PUSH Ib");
|
||||
u16 = (uint16_t)F8S;
|
||||
MOV32w(x2, u16);
|
||||
PUSH1_16(x2);
|
||||
break;
|
||||
|
||||
case 0x70:
|
||||
case 0x71:
|
||||
@@ -488,8 +491,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOVZw(x5, i16);
|
||||
emit_or16(dyn, ninst, x1, x5, x2, x4);
|
||||
emit_or16c(dyn, ninst, x1, i16, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 2: //ADC
|
||||
@@ -498,7 +500,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOVZw(x5, i16);
|
||||
MOVZw(x5, (uint16_t)i16);
|
||||
emit_adc16(dyn, ninst, x1, x5, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
@@ -508,7 +510,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOVZw(x5, i16);
|
||||
MOVZw(x5, (uint16_t)i16);
|
||||
emit_sbb16(dyn, ninst, x1, x5, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
@@ -517,8 +519,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOVZw(x5, i16);
|
||||
emit_and16(dyn, ninst, x1, x5, x2, x4);
|
||||
emit_and16c(dyn, ninst, x1, i16, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 5: //SUB
|
||||
@@ -535,8 +536,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOVZw(x5, i16);
|
||||
emit_xor16(dyn, ninst, x1, x5, x2, x4);
|
||||
emit_xor16c(dyn, ninst, x1, i16, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 7: //CMP
|
||||
@@ -575,8 +575,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETGD;
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
if(!ALIGNED_ATOMICH) {
|
||||
TSTx_mask(ed, 1, 0, 0); // mask=1
|
||||
B_MARK(cNE);
|
||||
TBNZ_MARK(ed, 0);
|
||||
}
|
||||
if(arm64_atomics) {
|
||||
SWPALH(gd, x1, ed);
|
||||
@@ -613,7 +612,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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(ed!=gd) {
|
||||
BFIz(ed, gd, 0, 16);
|
||||
}
|
||||
@@ -628,7 +627,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGD; // don't need GETGW neither
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
if(ed!=gd) {
|
||||
BFIz(gd, ed, 0, 16);
|
||||
}
|
||||
@@ -645,7 +644,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
u8 = (nextop&0x38)>>3;
|
||||
LDRH_U12(x3, xEmu, offsetof(x64emu_t, segs[u8]));
|
||||
if((nextop&0xC0)==0xC0) { // reg <= seg
|
||||
BFIz(xRAX+(nextop&7)+(rex.b<<3), x3, 0, 16);
|
||||
BFIz(TO_NAT((nextop & 7) + (rex.b << 3)), x3, 0, 16);
|
||||
} else { // mem <= seg
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
STH(x3, wback, fixedaddress);
|
||||
@@ -658,7 +657,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
u8 = (nextop&0x38)>>3;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
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, 0);
|
||||
@@ -673,7 +672,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
POP1_16(x1);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
wback = xRAX+(nextop&7)+(rex.b<<3);
|
||||
wback = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
BFIz(wback, x1, 0, 16);
|
||||
} else {
|
||||
SMREAD();
|
||||
@@ -689,7 +688,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0x95:
|
||||
case 0x96:
|
||||
case 0x97:
|
||||
gd = xRAX+(opcode&0x07)+(rex.b<<3);
|
||||
gd = TO_NAT((opcode & 0x07) + (rex.b << 3));
|
||||
if(gd==xRAX) {
|
||||
INST_NAME("NOP");
|
||||
} else {
|
||||
@@ -706,13 +705,12 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0x99:
|
||||
INST_NAME("CWD");
|
||||
SXTHw(x1, xRAX);
|
||||
BFXILx(xRDX, x1, 16, 16);
|
||||
SXTHw(x1, xRAX); // sign extend ax to x1
|
||||
BFXILx(xRDX, x1, 16, 16); // insert high 16bits of x1 as low DX
|
||||
break;
|
||||
case 0x9C:
|
||||
INST_NAME("PUSHF");
|
||||
READFLAGS(X_ALL);
|
||||
WILLWRITE();
|
||||
PUSH1_16(xFlags);
|
||||
SMWRITE();
|
||||
break;
|
||||
@@ -728,7 +726,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SET_DFNONE(x1);
|
||||
if(box64_wine) { // should this be done all the time?
|
||||
TBZ_NEXT(xFlags, F_TF);
|
||||
// go to epilog, TF should trigger at end of next opcode, so using Interpretor only
|
||||
// go to epilog, TF should trigger at end of next opcode, so using Interpreter only
|
||||
jump_to_epilog(dyn, addr, 0, ninst);
|
||||
}
|
||||
break;
|
||||
@@ -753,8 +751,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
else
|
||||
u64 = F64;
|
||||
MOV64z(x1, u64);
|
||||
if(isLockAddress(u64)) lock=1; else lock = 0;
|
||||
WILLWRITELOCK(lock);
|
||||
lock = isLockAddress(u64);
|
||||
STRH_U12(xRAX, x1, 0);
|
||||
SMWRITELOCK(lock);
|
||||
break;
|
||||
@@ -821,7 +818,8 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 1:
|
||||
case 2:
|
||||
if(rep==1) {INST_NAME("REPNZ CMPSW");} else {INST_NAME("REPZ CMPSW");}
|
||||
MAYSETFLAGS();
|
||||
if(box64_dynarec_safeflags>1)
|
||||
MAYSETFLAGS();
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
CBZx_NEXT(xRCX);
|
||||
TBNZ_MARK2(xFlags, F_DF);
|
||||
@@ -860,13 +858,11 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("TEST AX,Iw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
u16 = F16;
|
||||
MOV32w(x2, u16);
|
||||
UBFXx(x1, xRAX, 0, 16);
|
||||
emit_test16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
emit_test16c(dyn, ninst, x1, u16, x3, x4, x5);
|
||||
break;
|
||||
|
||||
case 0xAB:
|
||||
WILLWRITE();
|
||||
if(rep) {
|
||||
INST_NAME("REP STOSW");
|
||||
CBZx_NEXT(xRCX);
|
||||
@@ -922,7 +918,8 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 1:
|
||||
case 2:
|
||||
if(rep==1) {INST_NAME("REPNZ SCASW");} else {INST_NAME("REPZ SCASW");}
|
||||
MAYSETFLAGS();
|
||||
if(box64_dynarec_safeflags>1)
|
||||
MAYSETFLAGS();
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
CBZx_NEXT(xRCX);
|
||||
UXTHw(x1, xRAX);
|
||||
@@ -966,7 +963,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("MOV Reg16, Iw");
|
||||
u16 = F16;
|
||||
MOV32w(x1, u16);
|
||||
gd = xRAX+(opcode&7)+(rex.b<<3);
|
||||
gd = TO_NAT((opcode & 7) + (rex.b << 3));
|
||||
BFIz(gd, x1, 0, 16);
|
||||
break;
|
||||
|
||||
@@ -977,7 +974,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("ROL Ew, Ib");
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop) & 15;
|
||||
if (u8) {
|
||||
SETFLAGS(X_CF | X_OF, SF_SUBSET_PENDING);
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
|
||||
GETEW(x1, 1);
|
||||
u8 = (F8)&0x1f;
|
||||
emit_rol16c(dyn, ninst, x1, u8, x4, x5);
|
||||
@@ -990,7 +987,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 1:
|
||||
INST_NAME("ROR Ew, Ib");
|
||||
if (geted_ib(dyn, addr, ninst, nextop) & 15) {
|
||||
SETFLAGS(X_CF | X_OF, SF_SUBSET_PENDING);
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
|
||||
GETEW(x1, 1);
|
||||
u8 = (F8)&0x1f;
|
||||
emit_ror16c(dyn, ninst, x1, u8, x4, x5);
|
||||
@@ -1006,7 +1003,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
u8 = (F8)&0x1f;
|
||||
emit_rcl16c(dyn, ninst, ed, u8, x4, x5);
|
||||
EWBACK;
|
||||
} else {
|
||||
@@ -1020,7 +1017,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
u8 = (F8)&0x1f;
|
||||
emit_rcr16c(dyn, ninst, ed, u8, x4, x5);
|
||||
EWBACK;
|
||||
} else {
|
||||
@@ -1075,7 +1072,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("MOV Ew, Iw");
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
u16 = F16;
|
||||
MOV32w(x1, u16);
|
||||
BFIz(ed, x1, 0, 16);
|
||||
@@ -1093,14 +1090,14 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("ROL Ew, 1");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
|
||||
GETEW(x1, 0);
|
||||
emit_rol16c(dyn, ninst, x1, 1, x5, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("ROR Ew, 1");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
|
||||
GETEW(x1, 0);
|
||||
emit_ror16c(dyn, ninst, x1, 1, x5, x4);
|
||||
EWBACK;
|
||||
@@ -1155,8 +1152,8 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(box64_dynarec_safeflags>1)
|
||||
MAYSETFLAGS();
|
||||
UFLAG_IF {
|
||||
TSTw_mask(xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
B_NEXT(cEQ);
|
||||
ANDw_mask(x2, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
CBZw_NEXT(x2);
|
||||
}
|
||||
ANDw_mask(x2, xRCX, 0, 0b00011); //mask=0x00000000f
|
||||
MOV32w(x4, 16);
|
||||
@@ -1166,9 +1163,9 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
LSRw_REG(ed, ed, x2);
|
||||
EWBACK;
|
||||
UFLAG_IF { // calculate flags directly
|
||||
CMPSw_U12(x2, 15);
|
||||
B_MARK(cNE);
|
||||
ADDxw_REG_LSR(x3, ed, ed, 15);
|
||||
SUBw_U12(x2, x2, 15);
|
||||
CBNZw_MARK(x2);
|
||||
EORw_REG_LSR(x3, ed, ed, 15);
|
||||
BFIw(xFlags, x3, F_OF, 1);
|
||||
MARK;
|
||||
BFIw(xFlags, ed, F_CF, 1);
|
||||
@@ -1181,8 +1178,8 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(box64_dynarec_safeflags>1)
|
||||
MAYSETFLAGS();
|
||||
UFLAG_IF {
|
||||
TSTw_mask(xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
B_NEXT(cEQ);
|
||||
ANDw_mask(x2, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
CBZw_NEXT(x2);
|
||||
}
|
||||
ANDw_mask(x2, xRCX, 0, 0b00011); //mask=0x00000000f
|
||||
GETEW(x1, 0);
|
||||
@@ -1190,8 +1187,8 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
LSRw_REG(ed, ed, x2);
|
||||
EWBACK;
|
||||
UFLAG_IF { // calculate flags directly
|
||||
CMPSw_U12(x2, 1);
|
||||
B_MARK(cNE);
|
||||
SUBw_U12(x2, x2, 1);
|
||||
CBNZw_MARK(x2);
|
||||
LSRxw(x2, ed, 14); // x2 = d>>14
|
||||
EORw_REG_LSR(x2, x2, x2, 1); // x2 = ((d>>14) ^ ((d>>14)>>1))
|
||||
BFIw(xFlags, x2, F_OF, 1);
|
||||
@@ -1230,11 +1227,9 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
if(box64_dynarec_safeflags>1)
|
||||
MAYSETFLAGS();
|
||||
ANDw_mask(x2, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
UFLAG_IF {
|
||||
ANDSw_mask(x2, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
B_NEXT(cEQ);
|
||||
} else {
|
||||
ANDw_mask(x2, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
CBZw_NEXT(x2);
|
||||
}
|
||||
GETEW(x1, 0);
|
||||
emit_shl16(dyn, ninst, x1, x2, x5, x4);
|
||||
@@ -1245,11 +1240,9 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
if(box64_dynarec_safeflags>1)
|
||||
MAYSETFLAGS();
|
||||
ANDw_mask(x2, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
UFLAG_IF {
|
||||
ANDSw_mask(x2, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
B_NEXT(cEQ);
|
||||
} else {
|
||||
ANDw_mask(x2, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
CBZw_NEXT(x2);
|
||||
}
|
||||
GETEW(x1, 0);
|
||||
emit_shr16(dyn, ninst, x1, x2, x5, x4);
|
||||
@@ -1260,11 +1253,10 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
if(box64_dynarec_safeflags>1)
|
||||
MAYSETFLAGS();
|
||||
ANDw_mask(x2, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
UFLAG_IF {
|
||||
ANDSw_mask(x2, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
B_NEXT(cEQ);
|
||||
CBZw_NEXT(x2);
|
||||
} else {
|
||||
ANDw_mask(x2, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
}
|
||||
GETSEW(x1, 0);
|
||||
emit_sar16(dyn, ninst, x1, x2, x5, x4);
|
||||
@@ -1333,8 +1325,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, 2);
|
||||
u16 = F16;
|
||||
MOV32w(x2, u16);
|
||||
emit_test16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
emit_test16c(dyn, ninst, x1, u16, x3, x4, x5);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("NOT Ew");
|
||||
@@ -1374,7 +1365,6 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 6:
|
||||
INST_NAME("DIV Ew");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SET_DFNONE(x1);
|
||||
GETEW(x1, 0);
|
||||
UXTHw(x2, xRAX);
|
||||
BFIw(x2, xRDX, 16, 16);
|
||||
@@ -1392,12 +1382,17 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MSUBw(x4, x3, ed, x2); // x4 = x2 mod ed (i.e. x2 - x3*ed)
|
||||
BFIz(xRAX, x3, 0, 16);
|
||||
BFIz(xRDX, x4, 0, 16);
|
||||
SET_DFNONE(x2);
|
||||
IFX(X_AF | X_SF | X_CF | X_PF | X_ZF | X_OF)
|
||||
if(box64_dynarec_test) {
|
||||
MOV32w(x1, (1<<F_AF) | (1<<F_SF) | (1<<F_CF) | (1<<F_PF) | (1<<F_ZF) | (1<<F_OF));
|
||||
BICw(xFlags, xFlags, x1);
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("IDIV Ew");
|
||||
SKIPTEST(x1);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SET_DFNONE(x1);
|
||||
GETSEW(x1, 0);
|
||||
if(box64_dynarec_div0) {
|
||||
CBNZw_MARK3(ed);
|
||||
@@ -1415,6 +1410,12 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MSUBw(x4, x3, ed, x2); // x4 = x2 mod ed (i.e. x2 - x3*ed)
|
||||
BFIz(xRAX, x3, 0, 16);
|
||||
BFIz(xRDX, x4, 0, 16);
|
||||
SET_DFNONE(x2);
|
||||
IFX(X_AF | X_SF | X_CF | X_PF | X_ZF | X_OF)
|
||||
if(box64_dynarec_test) {
|
||||
MOV32w(x1, (1<<F_AF) | (1<<F_SF) | (1<<F_CF) | (1<<F_PF) | (1<<F_ZF) | (1<<F_OF));
|
||||
BICw(xFlags, xFlags, x1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -1436,14 +1437,14 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("INC Ew");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
GETEW(x1, 0);
|
||||
emit_inc16(dyn, ninst, x1, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("DEC Ew");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
GETEW(x1, 0);
|
||||
emit_dec16(dyn, ninst, x1, x2, x4);
|
||||
EWBACK;
|
||||
|
||||
@@ -19,7 +19,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_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog)
|
||||
@@ -34,6 +34,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
uint8_t eb1, eb2;
|
||||
int64_t j64;
|
||||
uint64_t tmp64u, tmp64u2;
|
||||
int mask;
|
||||
int v0, v1;
|
||||
int q0, q1;
|
||||
int d0, d1;
|
||||
@@ -235,7 +236,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
SQXTN_32(q0, q0);
|
||||
} else {
|
||||
if(arm64_frintts) {
|
||||
VFRINT32ZD(q0, q0);
|
||||
VFRINT32ZDQ(q0, v1);
|
||||
VFCVTZSQD(q0, q0);
|
||||
SQXTN_32(q0, q0);
|
||||
} else {
|
||||
@@ -275,7 +276,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
} else {
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x3);
|
||||
if(arm64_frintts) {
|
||||
VFRINT32XD(q0, q0);
|
||||
VFRINT32XDQ(q0, v1);
|
||||
VFCVTZSQD(q0, q0);
|
||||
SQXTN_32(q0, q0);
|
||||
} else {
|
||||
@@ -311,7 +312,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(v0, 0);
|
||||
GETEXSD(q0, 0, 0);
|
||||
FCMPD(v0, q0);
|
||||
FCOMI(x1, x2);
|
||||
FCOMI(x1, x2, 0, v0, q0, 0); //disable precise cmp
|
||||
break;
|
||||
|
||||
case 0x38: // SSSE3 opcodes
|
||||
@@ -887,9 +888,9 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
case 0xF0:
|
||||
INST_NAME("MOVBE Gw, Ew");
|
||||
nextop=F8;
|
||||
gd = xRAX+((nextop&0x38)>>3)+(rex.r<<3);
|
||||
gd = TO_NAT(((nextop & 0x38) >> 3) + (rex.r << 3));
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
REV16x(x1, ed);
|
||||
BFIx(gd, x1, 0, 16);
|
||||
} else {
|
||||
@@ -903,9 +904,9 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
case 0xF1:
|
||||
INST_NAME("MOVBE Ew, Gw");
|
||||
nextop=F8;
|
||||
gd = xRAX+((nextop&0x38)>>3)+(rex.r<<3);
|
||||
gd = TO_NAT(((nextop & 0x38) >> 3) + (rex.r << 3));
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
REV16x(x1, gd);
|
||||
BFIx(ed, x1, 0, 16);
|
||||
} else {
|
||||
@@ -923,9 +924,9 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
GETED(0);
|
||||
GETGD;
|
||||
MRS_nzvc(x3);
|
||||
MRS_nzcv(x3);
|
||||
BFIx(x3, xFlags, 29, 1); // set C
|
||||
MSR_nzvc(x3); // load CC into ARM CF
|
||||
MSR_nzcv(x3); // load CC into ARM CF
|
||||
IFX(X_CF) {
|
||||
ADCSxw_REG(gd, gd, ed);
|
||||
CSETw(x3, cCS);
|
||||
@@ -1006,7 +1007,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VMOVeD(q0, 0, v1, 0);
|
||||
break;
|
||||
case 0x0C:
|
||||
INST_NAME("PBLENDPS Gx, Ex, Ib");
|
||||
INST_NAME("BLENDPS Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 1);
|
||||
@@ -1021,7 +1022,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
break;
|
||||
case 0x0D:
|
||||
INST_NAME("PBLENDPD Gx, Ex, Ib");
|
||||
INST_NAME("BLENDPD Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 1);
|
||||
@@ -1092,7 +1093,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(q0, 0);
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
u8 = F8;
|
||||
VMOVBto(ed, q0, (u8&15));
|
||||
} else {
|
||||
@@ -1107,7 +1108,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(q0, 0);
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
u8 = F8;
|
||||
VMOVHto(ed, q0, (u8&7));
|
||||
} else {
|
||||
@@ -1122,7 +1123,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(q0, 0);
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
u8 = F8;
|
||||
if(rex.w) {
|
||||
VMOVQDto(ed, q0, (u8&1));
|
||||
@@ -1145,7 +1146,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(q0, 0);
|
||||
if (MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
u8 = F8&0b11;
|
||||
MOVx_REG(ed, xZR);
|
||||
VMOVSto(ed, q0, u8);
|
||||
@@ -1591,20 +1592,20 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
break;
|
||||
|
||||
#define GO(GETFLAGS, NO, YES, F) \
|
||||
READFLAGS(F); \
|
||||
GETFLAGS; \
|
||||
nextop=F8; \
|
||||
GETGD; \
|
||||
if(MODREG) { \
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3); \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0); \
|
||||
LDH(x1, ed, fixedaddress); \
|
||||
ed = x1; \
|
||||
} \
|
||||
Bcond(NO, +8); \
|
||||
#define GO(GETFLAGS, NO, YES, F) \
|
||||
READFLAGS(F); \
|
||||
GETFLAGS; \
|
||||
nextop = F8; \
|
||||
GETGD; \
|
||||
if (MODREG) { \
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3)); \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff << 1, 1, rex, NULL, 0, 0); \
|
||||
LDH(x1, ed, fixedaddress); \
|
||||
ed = x1; \
|
||||
} \
|
||||
Bcond(NO, +8); \
|
||||
BFIx(gd, ed, 0, 16);
|
||||
|
||||
GOCOND(0x40, "CMOV", "Gw, Ew");
|
||||
@@ -1720,7 +1721,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETEX(v1, 0, 0);
|
||||
GETGX_empty(v0);
|
||||
if(box64_dynarec_fastround) {
|
||||
if(box64_dynarec_fastround==2) {
|
||||
FCVTXN(v0, v1);
|
||||
} else {
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x3);
|
||||
@@ -1739,20 +1740,26 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
VFCVTZSQS(v0, v0);
|
||||
} else {
|
||||
MRS_fpsr(x5);
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x3);
|
||||
MOV32w(x4, 0x80000000);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
for(int i=0; i<4; ++i) {
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
VMOVeS(d0, 0, v1, i);
|
||||
FRINTIS(d0, d0);
|
||||
VFCVTZSs(d0, d0);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ(x5, FPSR_IOC, 4+4);
|
||||
VMOVQSfrom(d0, 0, x4);
|
||||
VMOVeS(v0, i, d0, 0);
|
||||
if(arm64_frintts) {
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x3);
|
||||
VFRINT32XSQ(v0, v1); // handle overflow
|
||||
VFCVTZSQS(v0, v0);
|
||||
} else {
|
||||
MRS_fpsr(x5);
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x3);
|
||||
MOV32w(x4, 0x80000000);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
for(int i=0; i<4; ++i) {
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
VMOVeS(d0, 0, v1, i);
|
||||
FRINTIS(d0, d0);
|
||||
VFCVTZSs(d0, d0);
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ(x5, FPSR_IOC, 4+4);
|
||||
VMOVQSfrom(d0, 0, x4);
|
||||
VMOVeS(v0, i, d0, 0);
|
||||
}
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
}
|
||||
@@ -2274,7 +2281,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(v0, 0);
|
||||
if(rex.w) {
|
||||
if(MODREG) {
|
||||
ed = xRAX + (nextop&7) + (rex.b<<3);
|
||||
ed = TO_NAT((nextop & 0x07) + (rex.b << 3));
|
||||
VMOVQDto(ed, v0, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
@@ -2283,7 +2290,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
} else {
|
||||
if(MODREG) {
|
||||
ed = xRAX + (nextop&7) + (rex.b<<3);
|
||||
ed = TO_NAT((nextop & 0x07) + (rex.b << 3));
|
||||
VMOVSto(ed, v0, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
@@ -2311,9 +2318,9 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
nextop = F8;
|
||||
gd = xRAX+((nextop&0x38)>>3)+(rex.r<<3); // GETGD
|
||||
gd = TO_NAT(((nextop & 0x38) >> 3) + (rex.r << 3)); // GETGD
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<2, (1<<2)-1, rex, NULL, 0, 0);
|
||||
@@ -2322,19 +2329,27 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
LDH(x1, x3, fixedaddress);
|
||||
ed = x1;
|
||||
}
|
||||
ANDw_mask(x2, gd, 0, 0b000011); // mask=0x0f
|
||||
LSRw_REG(x1, ed, x2);
|
||||
BFIw(xFlags, x1, F_CF, 1);
|
||||
IFX(X_CF) {
|
||||
ANDw_mask(x2, gd, 0, 0b000011); // mask=0x0f
|
||||
LSRw_REG(x1, ed, x2);
|
||||
BFIw(xFlags, x1, F_CF, 1);
|
||||
}
|
||||
break;
|
||||
case 0xA4:
|
||||
INST_NAME("SHLD Ew, Gw, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEW(x1, 1);
|
||||
GETGW(x2);
|
||||
u8 = F8;
|
||||
emit_shld16c(dyn, ninst, ed, gd, u8, x4, x5);
|
||||
EWBACK;
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop)&0x1f;
|
||||
if(u8) {
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, 1);
|
||||
GETGW(x2);
|
||||
u8 = F8;
|
||||
emit_shld16c(dyn, ninst, ed, gd, u8, x4, x5);
|
||||
EWBACK;
|
||||
} else {
|
||||
FAKEED;
|
||||
F8;
|
||||
}
|
||||
break;
|
||||
case 0xA5:
|
||||
nextop = F8;
|
||||
@@ -2344,11 +2359,9 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
MAYSETFLAGS();
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
ANDw_mask(x4, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
UFLAG_IF {
|
||||
ANDSw_mask(x4, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
B_NEXT(cEQ);
|
||||
} else {
|
||||
ANDw_mask(x4, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
CBZw_NEXT(x4);
|
||||
}
|
||||
emit_shld16(dyn, ninst, ed, gd, x4, x5, x6);
|
||||
EWBACK;
|
||||
@@ -2359,9 +2372,9 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
nextop = F8;
|
||||
gd = xRAX+((nextop&0x38)>>3)+(rex.r<<3); // GETGD
|
||||
gd = TO_NAT(((nextop & 0x38) >> 3) + (rex.r << 3)); // GETGD
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<2, (1<<2)-1, rex, NULL, 0, 0);
|
||||
@@ -2380,18 +2393,24 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
LSLw_REG(x1, x1, x2);
|
||||
ORRx_REG(ed, ed, x1);
|
||||
if(wback) {
|
||||
STRH_U12(ed, wback, fixedaddress);
|
||||
STH(ed, wback, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0xAC:
|
||||
nextop = F8;
|
||||
INST_NAME("SHRD Ew, Gw, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, 1);
|
||||
GETGW(x2);
|
||||
u8 = F8;
|
||||
emit_shrd16c(dyn, ninst, ed, gd, u8, x4, x5);
|
||||
EWBACK;
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop)&0x1f;
|
||||
if(u8) {
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, 1);
|
||||
GETGW(x2);
|
||||
u8 = F8;
|
||||
emit_shrd16c(dyn, ninst, ed, gd, u8, x4, x5);
|
||||
EWBACK;
|
||||
} else {
|
||||
FAKEED;
|
||||
F8;
|
||||
}
|
||||
break;
|
||||
case 0xAD:
|
||||
nextop = F8;
|
||||
@@ -2401,11 +2420,10 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
MAYSETFLAGS();
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
ANDw_mask(x4, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
UFLAG_IF {
|
||||
ANDSw_mask(x4, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
B_NEXT(cEQ);
|
||||
CBZw_NEXT(x4);
|
||||
} else {
|
||||
ANDw_mask(x4, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
}
|
||||
emit_shrd16(dyn, ninst, ed, gd, x4, x5, x6);
|
||||
EWBACK;
|
||||
@@ -2428,9 +2446,9 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
nextop = F8;
|
||||
gd = xRAX+((nextop&0x38)>>3)+(rex.r<<3); // GETGD
|
||||
gd = TO_NAT(((nextop & 0x38) >> 3) + (rex.r << 3)); // GETGD
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
wback = 0;
|
||||
} else {
|
||||
SMREAD();
|
||||
@@ -2458,11 +2476,11 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
if(rex.rex) {
|
||||
eb1 = xRAX+(nextop&7)+(rex.b<<3);
|
||||
eb1 = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
eb2 = 0;
|
||||
} else {
|
||||
ed = (nextop&7);
|
||||
eb1 = xRAX+(ed&3); // Ax, Cx, Dx or Bx
|
||||
eb1 = TO_NAT(ed & 3); // Ax, Cx, Dx or Bx
|
||||
eb2 = (ed&4)>>2; // L or H
|
||||
}
|
||||
UBFXxw(x1, eb1, eb2*8, 8);
|
||||
@@ -2471,21 +2489,21 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff, 0, rex, NULL, 0, 0);
|
||||
LDB(x1, ed, fixedaddress);
|
||||
}
|
||||
gd = xRAX+((nextop&0x38)>>3)+(rex.r<<3); // GETGW
|
||||
gd = TO_NAT(((nextop & 0x38) >> 3) + (rex.r << 3)); // GETGW
|
||||
BFIx(gd, x1, 0, 16); // insert in Gw
|
||||
break;
|
||||
case 0xB7:
|
||||
INST_NAME("MOVZX Gw, Ew");
|
||||
nextop = F8;
|
||||
if(MODREG) {
|
||||
eb1 = xRAX+(nextop&7)+(rex.b<<3);
|
||||
eb1 = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
UBFXxw(x1, eb1, 0, 16);
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff>>1, 1, rex, NULL, 0, 0);
|
||||
LDH(x1, ed, fixedaddress);
|
||||
}
|
||||
gd = xRAX+((nextop&0x38)>>3)+(rex.r<<3); // GETGW
|
||||
gd = TO_NAT(((nextop & 0x38) >> 3) + (rex.r << 3)); // GETGW
|
||||
BFIx(gd, x1, 0, 16); // insert in Gw
|
||||
break;
|
||||
|
||||
@@ -2513,8 +2531,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
IFX(X_CF) {
|
||||
BFXILxw(xFlags, ed, u8, 1); // inject 1 bit from u8 to F_CF (i.e. pos 0)
|
||||
}
|
||||
MOV32w(x4, 1);
|
||||
BFIxw(ed, x4, u8, 1);
|
||||
mask = convert_bitmask_xw(1<<u8);
|
||||
ORRxw_mask(ed, ed, (mask>>12)&1, mask&0x3F, (mask>>6)&0x3F);
|
||||
EWBACK;
|
||||
break;
|
||||
case 6:
|
||||
@@ -2540,8 +2558,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
IFX(X_CF) {
|
||||
BFXILxw(xFlags, ed, u8, 1); // inject 1 bit from u8 to F_CF (i.e. pos 0)
|
||||
}
|
||||
MOV32w(x4, 1);
|
||||
EORxw_REG_LSL(ed, ed, x4, u8);
|
||||
mask = convert_bitmask_xw(1<<u8);
|
||||
EORxw_mask(ed, ed, (mask>>12)&1, mask&0x3F, (mask>>6)&0x3F);
|
||||
EWBACK;
|
||||
break;
|
||||
default:
|
||||
@@ -2553,9 +2571,9 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
nextop = F8;
|
||||
gd = xRAX+((nextop&0x38)>>3)+(rex.r<<3); // GETGD
|
||||
gd = TO_NAT(((nextop & 0x38) >> 3) + (rex.r << 3)); // GETGD
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
wback = 0;
|
||||
} else {
|
||||
SMREAD();
|
||||
@@ -2575,7 +2593,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
LSLxw_REG(x1, x1, x2);
|
||||
EORx_REG(ed, ed, x1);
|
||||
if(wback) {
|
||||
STRH_U12(ed, wback, fixedaddress);
|
||||
STH(ed, wback, fixedaddress);
|
||||
SMWRITE();
|
||||
}
|
||||
break;
|
||||
@@ -2586,14 +2604,22 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEW(x1, 0); // Get EW
|
||||
TSTw_REG(x1, x1);
|
||||
B_MARK(cEQ);
|
||||
IFX(X_ZF) {
|
||||
TSTw_REG(x1, x1);
|
||||
B_MARK(cEQ);
|
||||
} else {
|
||||
CBZw_MARK(x1);
|
||||
}
|
||||
RBITw(x1, x1); // reverse
|
||||
CLZw(x2, x1); // x2 gets leading 0 == BSF
|
||||
BFIx(gd, x2, 0, 16);
|
||||
MARK;
|
||||
CSETw(x1, cEQ); //ZF not set
|
||||
BFIw(xFlags, x1, F_ZF, 1);
|
||||
IFX(X_ZF) {
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(x1, cEQ); //ZF not set
|
||||
BFIw(xFlags, x1, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xBD:
|
||||
INST_NAME("BSR Gw,Ew");
|
||||
@@ -2602,16 +2628,24 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEW(x1, 0); // Get EW
|
||||
TSTw_REG(x1, x1); // Don't use CBZ here, as the flag is reused later
|
||||
B_MARK(cEQ);
|
||||
IFX(X_ZF) {
|
||||
TSTw_REG(x1, x1); // Don't use CBZ here, as the flag is reused later
|
||||
B_MARK(cEQ);
|
||||
} else {
|
||||
CBZw_MARK(x1);
|
||||
}
|
||||
LSLw(x1, x1, 16); // put bits on top
|
||||
CLZw(x2, x1); // x2 gets leading 0
|
||||
SUBw_U12(x2, x2, 15);
|
||||
NEGw_REG(x2, x2); // complement
|
||||
BFIx(gd, x2, 0, 16);
|
||||
MARK;
|
||||
CSETw(x1, cEQ); //ZF not set
|
||||
BFIw(xFlags, x1, F_ZF, 1);
|
||||
IFX(X_ZF) {
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(x1, cEQ); //ZF not set
|
||||
BFIw(xFlags, x1, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xBE:
|
||||
INST_NAME("MOVSX Gw, Eb");
|
||||
@@ -2619,12 +2653,12 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
if(rex.rex) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
eb1=ed;
|
||||
eb2=0;
|
||||
} else {
|
||||
ed = (nextop&7);
|
||||
eb1 = xRAX+(ed&3); // Ax, Cx, Dx or Bx
|
||||
eb1 = TO_NAT(ed & 3); // Ax, Cx, Dx or Bx
|
||||
eb2 = (ed&4)>>2; // L or H
|
||||
}
|
||||
SBFXw(x1, eb1, eb2*8, 8);
|
||||
@@ -2635,6 +2669,20 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
BFIx(gd, x1, 0, 16);
|
||||
break;
|
||||
case 0xBF:
|
||||
INST_NAME("MOVSX Gw, Ew");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
SXTHxw(x1, ed);
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
LDSHxw(x1, ed, fixedaddress);
|
||||
}
|
||||
BFIx(gd, x1, 0, 16);
|
||||
break;
|
||||
|
||||
case 0xC1:
|
||||
INST_NAME("XADD Gw, Ew");
|
||||
@@ -2642,7 +2690,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
BFIx(xRAX+((nextop&0x38)>>3)+(rex.r<<3), ed, 0, 16);
|
||||
BFIx(TO_NAT(((nextop & 0x38) >> 3) + (rex.r << 3)), ed, 0, 16);
|
||||
emit_add16(dyn, ninst, ed, gd, x4, x5);
|
||||
EWBACK;
|
||||
break;
|
||||
@@ -2684,7 +2732,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(v0, 1);
|
||||
if(MODREG) {
|
||||
u8 = (F8)&7;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
VMOVQHfrom(v0, u8, ed);
|
||||
} else {
|
||||
SMREAD();
|
||||
@@ -2738,7 +2786,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
case 0xCE:
|
||||
case 0xCF: /* BSWAP reg */
|
||||
INST_NAME("BSWAP Reg");
|
||||
gd = xRAX+(opcode&7)+(rex.b<<3);
|
||||
gd = TO_NAT((opcode & 7) + (rex.b << 3));
|
||||
if(rex.w) {
|
||||
REV64x(gd, gd);
|
||||
} else {
|
||||
@@ -2821,7 +2869,6 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, (nextop&7) + (rex.b<<3));
|
||||
FMOVD(v1, v0);
|
||||
} else {
|
||||
WILLWRITE2();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VST64(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
@@ -2981,26 +3028,32 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VFCVTZSQD(v0, v1); // convert double -> int64
|
||||
SQXTN_32(v0, v0); // convert int64 -> int32 with saturation in lower part, RaZ high part
|
||||
} else {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
ORRw_mask(x4, xZR, 1, 0); //0x80000000
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
for(int i=0; i<2; ++i) {
|
||||
if(arm64_frintts) {
|
||||
VFRINT32ZDQ(v0, v1); // handle overflow
|
||||
VFCVTZSQD(v0, v0); // convert double -> int64
|
||||
SQXTN_32(v0, v0); // convert int64 -> int32 with saturation in lower part, RaZ high part
|
||||
} else {
|
||||
MRS_fpsr(x5);
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
if(i) {
|
||||
VMOVeD(d0, 0, v1, i);
|
||||
FCVTZSwD(x1, d0);
|
||||
} else {
|
||||
FCVTZSwD(x1, v1);
|
||||
ORRw_mask(x4, xZR, 1, 0); //0x80000000
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
for(int i=0; i<2; ++i) {
|
||||
BFCw(x5, FPSR_IOC, 1); // reset IOC bit
|
||||
MSR_fpsr(x5);
|
||||
if(i) {
|
||||
VMOVeD(d0, 0, v1, i);
|
||||
FCVTZSwD(x1, d0);
|
||||
} else {
|
||||
FCVTZSwD(x1, v1);
|
||||
}
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ(x5, FPSR_IOC, 4+4);
|
||||
MOVw_REG(x1, x4);
|
||||
VMOVQSfrom(v0, i, x1);
|
||||
}
|
||||
MRS_fpsr(x5); // get back FPSR to check the IOC bit
|
||||
TBZ(x5, FPSR_IOC, 4+4);
|
||||
MOVw_REG(x1, x4);
|
||||
VMOVQSfrom(v0, i, x1);
|
||||
VMOVQDfrom(v0, 1, xZR);
|
||||
}
|
||||
VMOVQDfrom(v0, 1, xZR);
|
||||
}
|
||||
break;
|
||||
case 0xE7:
|
||||
|
||||
@@ -18,7 +18,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)
|
||||
@@ -62,10 +62,13 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
VLDR64_REG(v1, ed, x4);
|
||||
if(rex.is32bits)
|
||||
VLDR64_REG_SXTW(v1, x4, ed);
|
||||
else
|
||||
VLDR64_REG(v1, ed, x4);
|
||||
}
|
||||
FCMPD(v0, v1);
|
||||
FCOMI(x1, x2);
|
||||
FCOMI(x1, x2, 0, v0, v1, 0); //disable precise cmp
|
||||
break;
|
||||
|
||||
case 0x6F:
|
||||
@@ -80,7 +83,10 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
SMREAD();
|
||||
VLDR128_REG(v0, ed, x4);
|
||||
if(rex.is32bits)
|
||||
VLDR128_REG_SXTW(v0, x4, ed);
|
||||
else
|
||||
VLDR128_REG(v0, ed, x4);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -94,7 +100,10 @@ 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, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
VSTR128_REG(v0, ed, x4);
|
||||
if(rex.is32bits)
|
||||
VSTR128_REG_SXTW(v0, x4, ed);
|
||||
else
|
||||
VSTR128_REG(v0, ed, x4);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
@@ -110,7 +119,10 @@ 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, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
VSTR64_REG(v0, ed, x4);
|
||||
if(rex.is32bits)
|
||||
VSTR64_REG_SXTW(v0, x4, ed);
|
||||
else
|
||||
VSTR64_REG(v0, ed, x4);
|
||||
SMWRITE();
|
||||
}
|
||||
break;
|
||||
@@ -139,8 +151,7 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
grab_segdata(dyn, addr, ninst, x1, seg);
|
||||
GETEWO(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOVZw(x5, i16);
|
||||
emit_or16(dyn, ninst, x1, x5, x2, x4);
|
||||
emit_or16c(dyn, ninst, x1, i16, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 2: //ADC
|
||||
@@ -171,8 +182,7 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
grab_segdata(dyn, addr, ninst, x1, seg);
|
||||
GETEWO(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOVZw(x5, i16);
|
||||
emit_and16(dyn, ninst, x1, x5, x2, x4);
|
||||
emit_and16c(dyn, ninst, x1, i16, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 5: //SUB
|
||||
@@ -191,8 +201,7 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
grab_segdata(dyn, addr, ninst, x1, seg);
|
||||
GETEWO(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOVZw(x5, i16);
|
||||
emit_xor16(dyn, ninst, x1, x5, x2, x4);
|
||||
emit_xor16c(dyn, ninst, x1, i16, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 7: //CMP
|
||||
@@ -215,7 +224,7 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
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 {
|
||||
@@ -229,18 +238,21 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(rex.w) {
|
||||
STRx_REG(gd, ed, x4);
|
||||
} else {
|
||||
STRH_REG(gd, ed, x4);
|
||||
if(rex.is32bits)
|
||||
STRH_REG_SXTW(gd, x4, ed);
|
||||
else
|
||||
STRH_REG(gd, ed, x4);
|
||||
}
|
||||
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 {
|
||||
@@ -255,7 +267,10 @@ uintptr_t dynarec64_6664(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(rex.w) {
|
||||
LDRx_REG(gd, ed, x4);
|
||||
} else {
|
||||
LDRH_REG(x1, ed, x4);
|
||||
if(rex.is32bits)
|
||||
LDRH_REG_SXTW(x1, x4, ed);
|
||||
else
|
||||
LDRH_REG(x1, ed, x4);
|
||||
BFIx(gd, x1, 0, 16);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,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 +30,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;
|
||||
@@ -55,7 +55,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_add16(dyn, ninst, x6, x5, x3, x4);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
@@ -85,7 +85,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_or16(dyn, ninst, x6, x5, x3, x4);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
@@ -120,7 +120,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);
|
||||
@@ -177,10 +177,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);
|
||||
@@ -216,7 +216,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);
|
||||
@@ -237,7 +237,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_and16(dyn, ninst, x6, gd, x3, x4);
|
||||
BFIx(ed, x6, 0, 16);
|
||||
@@ -274,16 +274,16 @@ 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) {
|
||||
if(arm64_uscat) {
|
||||
ANDx_mask(x1, wback, 1, 0, 3); // mask = F
|
||||
@@ -325,27 +325,32 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
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);
|
||||
}
|
||||
@@ -357,16 +362,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);
|
||||
@@ -380,16 +385,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);
|
||||
@@ -402,29 +407,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();
|
||||
@@ -435,16 +448,16 @@ 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) {
|
||||
if(arm64_uscat) {
|
||||
ANDx_mask(x1, wback, 1, 0, 3); // mask = F
|
||||
@@ -489,27 +502,30 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
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();
|
||||
@@ -522,9 +538,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);
|
||||
@@ -539,9 +555,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);
|
||||
@@ -567,9 +583,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);
|
||||
|
||||
@@ -19,7 +19,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)
|
||||
|
||||
@@ -19,7 +19,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)
|
||||
@@ -56,6 +56,27 @@ uintptr_t dynarec64_66F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0xBD:
|
||||
INST_NAME("LZCNT Gw, Ew");
|
||||
SETFLAGS(X_CF|X_ZF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
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?
|
||||
}
|
||||
LSLw_IMM(ed, ed, 16);
|
||||
CLZw(gd, ed);
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(gd, gd);
|
||||
CSETw(x3, cEQ);
|
||||
BFIw(xFlags, x3, F_ZF, 1); // ZF = is dest 0?
|
||||
}
|
||||
EWBACK;
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
|
||||
@@ -19,7 +19,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)
|
||||
@@ -55,10 +55,12 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
return addr;
|
||||
}
|
||||
|
||||
GETREX();
|
||||
|
||||
while(opcode==0x67) opcode = F8;
|
||||
|
||||
// reset rex after 67
|
||||
GETREX();
|
||||
|
||||
rep = 0;
|
||||
while((opcode==0xF2) || (opcode==0xF3) || (opcode>=0x40 && opcode<=0x4F)) {
|
||||
if((opcode==0xF2) || (opcode==0xF3))
|
||||
@@ -213,7 +215,40 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VLD32(s0, ed, fixedaddress);
|
||||
}
|
||||
FCMPS(v0, s0);
|
||||
FCOMI(x1, x2);
|
||||
FCOMI(x1, x2, 0, v0, s0, 1); //disabled precise cmp
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x38: /* MAP 0F38 */
|
||||
opcode = F8;
|
||||
switch(opcode) {
|
||||
case 0xF6:
|
||||
switch(rep) {
|
||||
case 2:
|
||||
INST_NAME("ADOX Gd, Ed");
|
||||
nextop = F8;
|
||||
READFLAGS(X_OF);
|
||||
SETFLAGS(X_OF, SF_SUBSET);
|
||||
GETED32(0);
|
||||
GETGD;
|
||||
MRS_nzcv(x3);
|
||||
LSRw(x4, xFlags, F_OF);
|
||||
BFIx(x3, x4, 29, 1); // set C
|
||||
MSR_nzcv(x3); // load CC into ARM CF
|
||||
IFX(X_OF) {
|
||||
ADCSxw_REG(gd, gd, ed);
|
||||
CSETw(x3, cCS);
|
||||
BFIw(xFlags, x3, F_OF, 1);
|
||||
} else {
|
||||
ADCxw_REG(gd, gd, ed);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
@@ -271,6 +306,19 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SMWRITE();
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("MOVDQU Ex, Gx");
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, nextop&7);
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VST128(v0, ed, fixedaddress);
|
||||
SMWRITE();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
@@ -282,11 +330,11 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
if(rex.rex) {
|
||||
eb1 = xRAX+(nextop&7)+(rex.b<<3);
|
||||
eb1 = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
eb2 = 0;
|
||||
} else {
|
||||
ed = (nextop&7);
|
||||
eb1 = xRAX+(ed&3); // Ax, Cx, Dx or Bx
|
||||
eb1 = TO_NAT(ed & 3); // Ax, Cx, Dx or Bx
|
||||
eb2 = (ed&4)>>2; // L or H
|
||||
}
|
||||
UBFXxw(gd, eb1, eb2*8, 8);
|
||||
@@ -301,7 +349,7 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
UBFXxw(gd, ed, 0, 16);
|
||||
} else {
|
||||
SMREAD();
|
||||
@@ -634,13 +682,32 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
emit_cmp32_0(dyn, ninst, rex, xRAX, x3, x4);
|
||||
break;
|
||||
|
||||
case 0x50:
|
||||
case 0x51:
|
||||
case 0x52:
|
||||
case 0x53:
|
||||
case 0x54:
|
||||
case 0x55:
|
||||
case 0x56:
|
||||
case 0x57:
|
||||
case 0x58:
|
||||
case 0x59:
|
||||
case 0x5A:
|
||||
case 0x5B:
|
||||
case 0x5C:
|
||||
case 0x5D:
|
||||
case 0x5E:
|
||||
case 0x5F:
|
||||
// just use regular conditional jump
|
||||
return dynarec64_00(dyn, addr-1, ip, ninst, rex, rep, ok, need_epilog);
|
||||
|
||||
case 0x63:
|
||||
INST_NAME("MOVSXD Gd, Ed");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(rex.w) {
|
||||
if(MODREG) { // reg <= reg
|
||||
SXTWx(gd, xRAX+(nextop&7)+(rex.b<<3));
|
||||
SXTWx(gd, TO_NAT((nextop & 7) + (rex.b << 3)));
|
||||
} else { // mem <= reg
|
||||
SMREAD();
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
@@ -648,7 +715,7 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
} else {
|
||||
if(MODREG) { // reg <= reg
|
||||
MOVw_REG(gd, xRAX+(nextop&7)+(rex.b<<3));
|
||||
MOVw_REG(gd, TO_NAT((nextop & 7) + (rex.b << 3)));
|
||||
} else { // mem <= reg
|
||||
SMREAD();
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
@@ -665,6 +732,46 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0x0F:
|
||||
nextop = F8;
|
||||
switch(nextop) {
|
||||
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);
|
||||
SMREAD();
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
VLD128(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x7E:
|
||||
INST_NAME("MOVD Ed,Gx");
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
if(rex.w) {
|
||||
if(MODREG) {
|
||||
ed = TO_NAT((nextop & 0x07) + (rex.b << 3));
|
||||
VMOVQDto(ed, v0, 0);
|
||||
} else {
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VST64(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
} else {
|
||||
if(MODREG) {
|
||||
ed = TO_NAT((nextop & 0x07) + (rex.b << 3));
|
||||
VMOVSto(ed, v0, 0);
|
||||
} else {
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
VST32(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xD6:
|
||||
INST_NAME("MOVQ Ex, Gx");
|
||||
nextop = F8;
|
||||
@@ -673,13 +780,20 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, (nextop&7) + (rex.b<<3));
|
||||
FMOVD(v1, v0);
|
||||
} else {
|
||||
WILLWRITE2();
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VST64(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xFE:
|
||||
INST_NAME("PADDD Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX32(v1, 0, 0);
|
||||
VADDQ_32(v0, v0, v1);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
@@ -703,8 +817,7 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW32(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOVZw(x5, i16);
|
||||
emit_or16(dyn, ninst, x1, x5, x2, x4);
|
||||
emit_or16c(dyn, ninst, x1, i16, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 2: //ADC
|
||||
@@ -732,8 +845,7 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW32(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOVZw(x5, i16);
|
||||
emit_and16(dyn, ninst, x1, x5, x2, x4);
|
||||
emit_and16c(dyn, ninst, x1, i16, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 5: //SUB
|
||||
@@ -750,8 +862,7 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW32(x1, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOVZw(x5, i16);
|
||||
emit_xor16(dyn, ninst, x1, x5, x2, x4);
|
||||
emit_xor16c(dyn, ninst, x1, i16, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 7: //CMP
|
||||
@@ -772,13 +883,12 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
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(ed!=gd) {
|
||||
BFIx(ed, gd, 0, 16);
|
||||
}
|
||||
} else {
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, &lock, 0, 0);
|
||||
WILLWRITELOCK(lock);
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff << 1, 1, rex, &lock, 0, 0);
|
||||
STH(gd, ed, fixedaddress);
|
||||
SMWRITELOCK(lock);
|
||||
}
|
||||
@@ -817,9 +927,22 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
UFLAG_IF {
|
||||
SMULH(x3, ed, x4);
|
||||
MULx(gd, ed, x4);
|
||||
UFLAG_OP1(x3);
|
||||
UFLAG_RES(gd);
|
||||
UFLAG_DF(x3, d_imul64);
|
||||
SET_DFNONE(x1);
|
||||
IFX(X_ZF | X_PF | X_AF | X_SF) {
|
||||
MOV32w(x1, (1<<F_ZF)|(1<<F_AF)|(1<<F_PF)|(1<<F_SF));
|
||||
BICw(xFlags, xFlags, x1);
|
||||
}
|
||||
IFX(X_CF | X_OF) {
|
||||
ASRx(x4, gd, 63);
|
||||
CMPSx_REG(x3, x4);
|
||||
CSETw(x1, cNE);
|
||||
IFX(X_CF) {
|
||||
BFIw(xFlags, x1, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BFIw(xFlags, x1, F_OF, 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
MULxw(gd, ed, x4);
|
||||
}
|
||||
@@ -827,17 +950,49 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
// 32bits imul
|
||||
UFLAG_IF {
|
||||
SMULL(gd, ed, x4);
|
||||
UFLAG_RES(gd);
|
||||
LSRx(x3, gd, 32);
|
||||
UFLAG_OP1(x3);
|
||||
UFLAG_DF(x3, d_imul32);
|
||||
MOVw_REG(gd, gd);
|
||||
SET_DFNONE(x1);
|
||||
IFX(X_ZF | X_PF | X_AF | X_SF) {
|
||||
MOV32w(x1, (1<<F_ZF)|(1<<F_AF)|(1<<F_PF)|(1<<F_SF));
|
||||
BICw(xFlags, xFlags, x1);
|
||||
}
|
||||
IFX(X_CF | X_OF) {
|
||||
ASRw(x4, gd, 31);
|
||||
CMPSw_REG(x3, x4);
|
||||
CSETw(x1, cNE);
|
||||
IFX(X_CF) {
|
||||
BFIw(xFlags, x1, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BFIw(xFlags, x1, F_OF, 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
MULxw(gd, ed, x4);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x70:
|
||||
case 0x71:
|
||||
case 0x72:
|
||||
case 0x73:
|
||||
case 0x74:
|
||||
case 0x75:
|
||||
case 0x76:
|
||||
case 0x77:
|
||||
case 0x78:
|
||||
case 0x79:
|
||||
case 0x7A:
|
||||
case 0x7B:
|
||||
case 0x7C:
|
||||
case 0x7D:
|
||||
case 0x7E:
|
||||
case 0x7F:
|
||||
// just use regular conditional jump
|
||||
return dynarec64_00(dyn, addr-1, ip, ninst, rex, rep, ok, need_epilog);
|
||||
|
||||
case 0x81:
|
||||
case 0x83:
|
||||
nextop = F8;
|
||||
@@ -922,10 +1077,10 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
gd = ((nextop&0x38)>>3)+(rex.r<<3);
|
||||
if(rex.rex) {
|
||||
gb2 = 0;
|
||||
gb1 = xRAX + gd;
|
||||
gb1 = TO_NAT(gd);
|
||||
} else {
|
||||
gb2 = ((gd&4)<<1);
|
||||
gb1 = xRAX+(gd&3);
|
||||
gb1 = TO_NAT(gd & 3);
|
||||
}
|
||||
if(gb2) {
|
||||
gd = x4;
|
||||
@@ -936,16 +1091,15 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(MODREG) {
|
||||
ed = (nextop&7) + (rex.b<<3);
|
||||
if(rex.rex) {
|
||||
eb1 = xRAX+ed;
|
||||
eb1 = TO_NAT(ed);
|
||||
eb2 = 0;
|
||||
} else {
|
||||
eb1 = xRAX+(ed&3); // Ax, Cx, Dx or Bx
|
||||
eb1 = TO_NAT(ed & 3); // Ax, Cx, Dx or Bx
|
||||
eb2 = ((ed&4)>>2); // L or H
|
||||
}
|
||||
BFIx(eb1, gd, eb2*8, 8);
|
||||
} else {
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff, 0, rex, &lock, 0, 0);
|
||||
WILLWRITELOCK(lock);
|
||||
STB(gd, ed, fixedaddress);
|
||||
SMWRITELOCK(lock);
|
||||
}
|
||||
@@ -955,10 +1109,9 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if(MODREG) { // reg <= reg
|
||||
MOVxw_REG(xRAX+(nextop&7)+(rex.b<<3), gd);
|
||||
MOVxw_REG(TO_NAT((nextop & 7) + (rex.b << 3)), gd);
|
||||
} else { // mem <= reg
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, &lock, 0, 0);
|
||||
WILLWRITELOCK(lock);
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff << (2 + rex.w), (1 << (2 + rex.w)) - 1, rex, &lock, 0, 0);
|
||||
STxw(gd, ed, fixedaddress);
|
||||
SMWRITELOCK(lock);
|
||||
}
|
||||
@@ -967,21 +1120,21 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("MOV Gb, Eb");
|
||||
nextop = F8;
|
||||
if(rex.rex) {
|
||||
gb1 = gd = xRAX+((nextop&0x38)>>3)+(rex.r<<3);
|
||||
gb1 = gd = TO_NAT(((nextop & 0x38) >> 3) + (rex.r << 3));
|
||||
gb2=0;
|
||||
} else {
|
||||
gd = (nextop&0x38)>>3;
|
||||
gb1 = xRAX+(gd&3);
|
||||
gb1 = TO_NAT(gd & 3);
|
||||
gb2 = ((gd&4)<<1);
|
||||
}
|
||||
if(MODREG) {
|
||||
if(rex.rex) {
|
||||
wback = xRAX+(nextop&7)+(rex.b<<3);
|
||||
wback = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
wb2 = 0;
|
||||
} else {
|
||||
wback = (nextop&7);
|
||||
wb2 = (wback>>2);
|
||||
wback = xRAX+(wback&3);
|
||||
wback = TO_NAT(wback & 3);
|
||||
}
|
||||
if(wb2) {
|
||||
UBFXw(x4, wback, wb2*8, 8);
|
||||
@@ -1002,7 +1155,7 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
MOVxw_REG(gd, xRAX+(nextop&7)+(rex.b<<3));
|
||||
MOVxw_REG(gd, TO_NAT((nextop & 7) + (rex.b << 3)));
|
||||
} else {
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, &lock, 0, 0);
|
||||
SMREADLOCK(lock);
|
||||
@@ -1024,12 +1177,38 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x90:
|
||||
case 0x91:
|
||||
case 0x92:
|
||||
case 0x93:
|
||||
case 0x94:
|
||||
case 0x95:
|
||||
case 0x96:
|
||||
case 0x97:
|
||||
gd = TO_NAT((opcode & 0x07) + (rex.b << 3));
|
||||
if(gd==xRAX) {
|
||||
INST_NAME("NOP");
|
||||
} else {
|
||||
INST_NAME("XCHG EAX, Reg");
|
||||
MOVxw_REG(x2, xRAX);
|
||||
MOVxw_REG(xRAX, gd);
|
||||
MOVxw_REG(gd, x2);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xA9:
|
||||
INST_NAME("TEST EAX, Id");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i64 = F32S;
|
||||
emit_test32c(dyn, ninst, rex, xRAX, i64, x3, x4, x5);
|
||||
break;
|
||||
|
||||
case 0xC1:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("ROL Ed, Ib");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
|
||||
GETED32(1);
|
||||
u8 = (F8)&(rex.w?0x3f:0x1f);
|
||||
emit_rol32c(dyn, ninst, rex, ed, u8, x3, x4);
|
||||
@@ -1037,7 +1216,7 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("ROR Ed, Ib");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
|
||||
GETED32(1);
|
||||
u8 = (F8)&(rex.w?0x3f:0x1f);
|
||||
emit_ror32c(dyn, ninst, rex, ed, u8, x3, x4);
|
||||
@@ -1064,11 +1243,13 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 4:
|
||||
case 6:
|
||||
INST_NAME("SHL Ed, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
GETED32(1);
|
||||
u8 = (F8)&(rex.w?0x3f:0x1f);
|
||||
emit_shl32c(dyn, ninst, rex, ed, u8, x3, x4);
|
||||
WBACK;
|
||||
if(u8) { //should create the geted32_ib utility function for that
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
emit_shl32c(dyn, ninst, rex, ed, u8, x3, x4);
|
||||
WBACK;
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("SHR Ed, Ib");
|
||||
@@ -1147,10 +1328,10 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
u8 = F8;
|
||||
if(!rex.rex) {
|
||||
ed = (nextop&7);
|
||||
eb1 = xRAX+(ed&3); // Ax, Cx, Dx or Bx
|
||||
eb1 = TO_NAT(ed & 3); // Ax, Cx, Dx or Bx
|
||||
eb2 = (ed&4)>>2; // L or H
|
||||
} else {
|
||||
eb1 = xRAX+(nextop&7)+(rex.b<<3);
|
||||
eb1 = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
eb2 = 0;
|
||||
}
|
||||
MOV32w(x3, u8);
|
||||
@@ -1163,7 +1344,6 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ed = x3;
|
||||
} else
|
||||
ed = xZR;
|
||||
WILLWRITELOCK(lock);
|
||||
STB(ed, wback, fixedaddress);
|
||||
SMWRITELOCK(lock);
|
||||
}
|
||||
@@ -1173,13 +1353,12 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop=F8;
|
||||
if(MODREG) { // reg <= i32
|
||||
i64 = F32S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
MOV64xw(ed, i64);
|
||||
} else { // mem <= i32
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, &lock, 0, 4);
|
||||
i64 = F32S;
|
||||
MOV64xw(x3, i64);
|
||||
WILLWRITELOCK(lock);
|
||||
STxw(x3, ed, fixedaddress);
|
||||
SMWRITELOCK(lock);
|
||||
}
|
||||
@@ -1201,21 +1380,23 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} 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 */ \
|
||||
} else { \
|
||||
/* inside the block */ \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size); \
|
||||
Bcond(YES, i32); \
|
||||
SKIP_SEVL(i32); \
|
||||
Bcond(YES, i32); \
|
||||
}
|
||||
case 0xE0:
|
||||
INST_NAME("LOOPNZ (32bits)");
|
||||
READFLAGS(X_ZF);
|
||||
i8 = F8S;
|
||||
MOVw_REG(x1, xRCX);
|
||||
SUBSw_U12(x1, x1, 1);
|
||||
SUBw_U12(x1, x1, 1);
|
||||
BFIx(xRCX, x1, 0, 32);
|
||||
B_NEXT(cEQ); // ECX is 0, no LOOP
|
||||
CBZw_NEXT(x1); // ECX is 0, no LOOP
|
||||
TSTw_mask(xFlags, 0b011010, 0); //mask=0x40
|
||||
GO(cNE, cEQ);
|
||||
break;
|
||||
@@ -1224,9 +1405,9 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
READFLAGS(X_ZF);
|
||||
i8 = F8S;
|
||||
MOVw_REG(x1, xRCX);
|
||||
SUBSw_U12(x1, x1, 1);
|
||||
SUBw_U12(x1, x1, 1);
|
||||
BFIx(xRCX, x1, 0, 32);
|
||||
B_NEXT(cEQ); // ECX is 0, no LOOP
|
||||
CBZw_NEXT(x1); // ECX is 0, no LOOP
|
||||
TSTw_mask(xFlags, 0b011010, 0); //mask=0x40
|
||||
GO(cEQ, cNE);
|
||||
break;
|
||||
@@ -1259,8 +1440,7 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETED32H(x1, 4);
|
||||
i64 = F32S;
|
||||
MOV64xw(x2, i64);
|
||||
emit_test32(dyn, ninst, rex, ed, x2, x3, x4, x5);
|
||||
emit_test32c(dyn, ninst, rex, ed, i64, x3, x4, x5);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("NOT Ed");
|
||||
@@ -1277,7 +1457,7 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("MUL EAX, Ed");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETED32(0);
|
||||
if(rex.w) {
|
||||
if(ed==xRDX) gd=x3; else gd=xRDX;
|
||||
@@ -1289,9 +1469,25 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOVw_REG(xRAX, xRDX);
|
||||
LSRx(xRDX, xRDX, 32);
|
||||
}
|
||||
UFLAG_RES(xRAX);
|
||||
UFLAG_OP1(xRDX);
|
||||
UFLAG_DF(x2, rex.w?d_mul64:d_mul32);
|
||||
UFLAG_IF {
|
||||
SET_DFNONE(x4);
|
||||
IFX(X_CF|X_OF) {
|
||||
CMPSxw_U12(xRDX, 0);
|
||||
CSETw(x3, cNE);
|
||||
IFX(X_CF) {
|
||||
BFIw(xFlags, x3, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BFIw(xFlags, x3, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_AF | X_PF | X_ZF | X_SF)
|
||||
if(box64_dynarec_test) {
|
||||
// to avoid noise during test
|
||||
MOV32w(x3, (1<<F_ZF)|(1<<F_AF)|(1<<F_PF)|(1<<F_SF));
|
||||
BICw(xFlags, xFlags, x3);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("IMUL EAX, Ed");
|
||||
@@ -1314,7 +1510,6 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 6:
|
||||
INST_NAME("DIV Ed");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SET_DFNONE(x2);
|
||||
if(!rex.w) {
|
||||
GETED32(0);
|
||||
MOVw_REG(x3, xRAX);
|
||||
@@ -1348,12 +1543,17 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOVx_REG(xRAX, x2);
|
||||
}
|
||||
}
|
||||
SET_DFNONE(x2);
|
||||
IFX(X_AF | X_SF | X_CF | X_PF | X_ZF | X_OF)
|
||||
if(box64_dynarec_test) {
|
||||
MOV32w(x1, (1<<F_AF) | (1<<F_SF) | (1<<F_CF) | (1<<F_PF) | (1<<F_ZF) | (1<<F_OF));
|
||||
BICw(xFlags, xFlags, x1);
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("IDIV Ed");
|
||||
NOTEST(x1);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SET_DFNONE(x2);
|
||||
if(!rex.w) {
|
||||
GETSED32w(0);
|
||||
MOVw_REG(x3, xRAX);
|
||||
@@ -1385,6 +1585,12 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOVx_REG(xRAX, x2);
|
||||
}
|
||||
}
|
||||
SET_DFNONE(x2);
|
||||
IFX(X_AF | X_SF | X_CF | X_PF | X_ZF | X_OF)
|
||||
if(box64_dynarec_test) {
|
||||
MOV32w(x1, (1<<F_AF) | (1<<F_SF) | (1<<F_CF) | (1<<F_PF) | (1<<F_ZF) | (1<<F_OF));
|
||||
BICw(xFlags, xFlags, x1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -1393,14 +1599,14 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: // INC Ed
|
||||
INST_NAME("INC Ed");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
GETED32(0);
|
||||
emit_inc32(dyn, ninst, rex, ed, x3, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 1: //DEC Ed
|
||||
INST_NAME("DEC Ed");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
GETED32(0);
|
||||
emit_dec32(dyn, ninst, rex, ed, x3, x4);
|
||||
WBACK;
|
||||
@@ -1418,7 +1624,6 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETED32(0);
|
||||
if(box64_dynarec_callret && box64_dynarec_bigblock>1) {
|
||||
BARRIER(BARRIER_FULL);
|
||||
BARRIER_NEXT(BARRIER_FULL);
|
||||
} else {
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
*need_epilog = 0;
|
||||
@@ -1434,15 +1639,22 @@ uintptr_t dynarec64_67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ADR_S20(x4, j64);
|
||||
MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
|
||||
} else {
|
||||
MESSAGE(LOG_NONE, "\tCALLRET set return to Jmptable(%p)\n", (void*)addr);
|
||||
j64 = getJumpTableAddress64(addr);
|
||||
TABLE64(x4, j64);
|
||||
LDRx_U12(x4, x4, 0);
|
||||
j64 = (dyn->insts)?(GETMARK-(dyn->native_size)):0;
|
||||
ADR_S20(x4, j64);
|
||||
MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
|
||||
}
|
||||
STPx_S7_preindex(x4, xRIP, xSP, -16);
|
||||
}
|
||||
PUSH1z(xRIP);
|
||||
jump_to_next(dyn, 0, ed, ninst, rex.is32bits);
|
||||
if(box64_dynarec_callret && addr >= (dyn->start + dyn->isize)) {
|
||||
// jumps out of current dynablock...
|
||||
MARK;
|
||||
j64 = getJumpTableAddress64(addr);
|
||||
TABLE64(x4, j64);
|
||||
LDRx_U12(x4, x4, 0);
|
||||
BR(x4);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
|
||||
@@ -18,7 +18,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)
|
||||
@@ -66,7 +66,7 @@ uintptr_t dynarec64_6764_32(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, in
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if(MODREG) { // reg <= reg
|
||||
MOVxw_REG(xRAX+(nextop&7)+(rex.b<<3), gd);
|
||||
MOVxw_REG(TO_NAT((nextop & 7) + (rex.b << 3)), gd);
|
||||
} else { // mem <= reg
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0, 0, 0);
|
||||
@@ -79,7 +79,7 @@ uintptr_t dynarec64_6764_32(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, in
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if(MODREG) { // reg => reg
|
||||
MOVxw_REG(gd, xRAX+(nextop&7)+(rex.b<<3));
|
||||
MOVxw_REG(gd, TO_NAT((nextop & 7) + (rex.b << 3)));
|
||||
} else { // mem => reg
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, NULL, 0, 0, 0);
|
||||
@@ -92,7 +92,7 @@ uintptr_t dynarec64_6764_32(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, in
|
||||
nextop=F8;
|
||||
if(MODREG) { // reg <= reg
|
||||
POP1_32(x1);
|
||||
MOVxw_REG(xRAX+(nextop&7)+(rex.b<<3), x1);
|
||||
MOVxw_REG(TO_NAT((nextop & 7) + (rex.b << 3)), x1);
|
||||
} else { // mem <= reg
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
POP1_32(x1);
|
||||
|
||||
@@ -18,7 +18,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)
|
||||
@@ -80,21 +80,23 @@ uintptr_t dynarec64_67_32(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
} 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 */ \
|
||||
} else { \
|
||||
/* inside the block */ \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size); \
|
||||
Bcond(YES, i32); \
|
||||
SKIP_SEVL(i32); \
|
||||
Bcond(YES, i32); \
|
||||
}
|
||||
case 0xE0:
|
||||
INST_NAME("LOOPNZ (16bits)");
|
||||
READFLAGS(X_ZF);
|
||||
i8 = F8S;
|
||||
UXTHw(x1, xRCX);
|
||||
SUBSw_U12(x1, x1, 1);
|
||||
SUBw_U12(x1, x1, 1);
|
||||
BFIx(xRCX, x1, 0, 16);
|
||||
B_NEXT(cEQ); // ECX is 0, no LOOP
|
||||
CBZw_NEXT(x1); // ECX is 0, no LOOP
|
||||
TSTw_mask(xFlags, 0b011010, 0); //mask=0x40
|
||||
GO(cNE, cEQ);
|
||||
break;
|
||||
@@ -103,9 +105,9 @@ uintptr_t dynarec64_67_32(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
READFLAGS(X_ZF);
|
||||
i8 = F8S;
|
||||
UXTHw(x1, xRCX);
|
||||
SUBSw_U12(x1, x1, 1);
|
||||
SUBw_U12(x1, x1, 1);
|
||||
BFIx(xRCX, x1, 0, 16);
|
||||
B_NEXT(cEQ); // ECX is 0, no LOOP
|
||||
CBZw_NEXT(x1); // ECX is 0, no LOOP
|
||||
TSTw_mask(xFlags, 0b011010, 0); //mask=0x40
|
||||
GO(cEQ, cNE);
|
||||
break;
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "../dynarec_helper.h"
|
||||
|
||||
static const char* avx_prefix_string(uint16_t p)
|
||||
{
|
||||
@@ -103,9 +103,30 @@ uintptr_t dynarec64_67_AVX(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
}
|
||||
|
||||
}
|
||||
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) {
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, (nextop&7)+(rex.b<<3));
|
||||
VMOV(v1, v0);
|
||||
YMM0((nextop&7)+(rex.b<<3));
|
||||
} else {
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VSTR64_U12(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
}
|
||||
else {DEFAULT;}
|
||||
|
||||
if((*ok==-1) && (box64_dynarec_log>=LOG_INFO || box64_dynarec_dump || box64_dynarec_missing)) {
|
||||
if((*ok==-1) && (box64_dynarec_log>=LOG_INFO || box64_dynarec_dump || box64_dynarec_missing==1)) {
|
||||
dynarec_log(LOG_NONE, "Dynarec unimplemented AVX opcode size %d prefix %s map %s opcode %02X ", 128<<vex.l, avx_prefix_string(vex.p), avx_map_string(vex.m), opcode);
|
||||
}
|
||||
return addr;
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "../dynarec_helper.h"
|
||||
|
||||
static const char* avx_prefix_string(uint16_t p)
|
||||
{
|
||||
@@ -67,9 +67,11 @@ uintptr_t dynarec64_AVX(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
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) && (box64_dynarec_log>=LOG_INFO || box64_dynarec_dump || box64_dynarec_missing)) {
|
||||
if((*ok==-1) && (box64_dynarec_log>=LOG_INFO || box64_dynarec_dump || box64_dynarec_missing==1)) {
|
||||
dynarec_log(LOG_NONE, "Dynarec unimplemented AVX opcode size %d prefix %s map %s opcode %02X ", 128<<vex.l, avx_prefix_string(vex.p), avx_map_string(vex.m), opcode);
|
||||
}
|
||||
return addr;
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.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)
|
||||
{
|
||||
@@ -290,7 +290,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETGX(v0, 0);
|
||||
GETEXSS(s0, 0, 0);
|
||||
FCMPS(v0, s0);
|
||||
FCOMI(x1, x2);
|
||||
FCOMI(x1, x2, 0, v0, s0, 1); //disable precise cmp
|
||||
break;
|
||||
|
||||
case 0x50:
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.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)
|
||||
{
|
||||
@@ -68,7 +68,22 @@ uintptr_t dynarec64_AVX_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, i
|
||||
GETGD;
|
||||
GETED(0);
|
||||
GETVD;
|
||||
BICxw(gd, ed, vd);
|
||||
IFX(X_ZF)
|
||||
BICSxw(gd, ed, vd);
|
||||
else
|
||||
BICxw(gd, ed, vd);
|
||||
IFX(X_ZF) {
|
||||
CSETw(x1, cEQ);
|
||||
BFIw(xFlags, x1, F_ZF, 1);
|
||||
}
|
||||
IFX(X_OF)
|
||||
BFCw(xFlags, F_OF, 1);
|
||||
IFX(X_CF)
|
||||
BFCw(xFlags, F_CF, 1);
|
||||
IFX(X_SF) {
|
||||
LSRxw_IMM(x1, gd, rex.w?63:31);
|
||||
BFIw(xFlags, x1, F_SF, 1);
|
||||
}
|
||||
break;
|
||||
case 0xF3:
|
||||
nextop = F8;
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "../dynarec_helper.h"
|
||||
|
||||
uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
|
||||
{
|
||||
@@ -273,7 +273,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
GETGX(v0, 0);
|
||||
GETEXSD(q0, 0, 0);
|
||||
FCMPD(v0, q0);
|
||||
FCOMI(x1, x2);
|
||||
FCOMI(x1, x2, 0, v0, q0, 0); //disable precise cmp
|
||||
break;
|
||||
|
||||
case 0x50:
|
||||
@@ -295,6 +295,29 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
BFIx(gd, x2, 3, 1);
|
||||
}
|
||||
break;
|
||||
case 0x51:
|
||||
INST_NAME("VSQRTPD Gx, Ex");
|
||||
nextop = F8;
|
||||
if(!box64_dynarec_fastnan) {
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
}
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_empty_EX(v0, v1, 0); } else { GETGY_empty_EY(v0, v1); }
|
||||
if(!box64_dynarec_fastnan) {
|
||||
// check if any input value was NAN
|
||||
VFCMEQQD(d0, v1, v1); // 0 if NAN, 1 if not NAN
|
||||
VFSQRTQD(v0, v1);
|
||||
VFCMEQQD(d1, v0, v0); // 0 => out is NAN
|
||||
VBICQ(d1, d0, d1); // forget it in any input was a NAN already
|
||||
VSHLQ_64(d1, d1, 63); // only keep the sign bit
|
||||
VORRQ(v0, v0, d1); // NAN -> -NAN
|
||||
} else {
|
||||
VFSQRTQD(v0, v1);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0x54:
|
||||
INST_NAME("VANDPD Gx, Vx, Ex");
|
||||
@@ -389,7 +412,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
nextop = F8;
|
||||
GETEX(v1, 0, 0);
|
||||
GETGX_empty(v0);
|
||||
if(box64_dynarec_fastround) {
|
||||
if(box64_dynarec_fastround==2) {
|
||||
FCVTXN(v0, v1);
|
||||
} else {
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x4);
|
||||
@@ -398,7 +421,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
}
|
||||
if(vex.l) {
|
||||
GETEY(v1);
|
||||
if(box64_dynarec_fastround) {
|
||||
if(box64_dynarec_fastround==2) {
|
||||
FCVTXN2(v0, v1);
|
||||
} else {
|
||||
FCVTN2(v0, v1);
|
||||
@@ -1136,7 +1159,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
GETGX(v0, 0);
|
||||
if(rex.w) {
|
||||
if(MODREG) {
|
||||
ed = xRAX + (nextop&7) + (rex.b<<3);
|
||||
ed = TO_NAT((nextop & 0x07) + (rex.b << 3));
|
||||
VMOVQDto(ed, v0, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
@@ -1145,7 +1168,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
}
|
||||
} else {
|
||||
if(MODREG) {
|
||||
ed = xRAX + (nextop&7) + (rex.b<<3);
|
||||
ed = TO_NAT((nextop & 0x07) + (rex.b << 3));
|
||||
VMOVSto(ed, v0, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<2, 3, rex, NULL, 0, 0);
|
||||
@@ -1216,7 +1239,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
if(v0!=v2) VMOVQ(v0, v2);
|
||||
if(MODREG) {
|
||||
u8 = (F8)&7;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
VMOVQHfrom(v0, u8, ed);
|
||||
} else {
|
||||
SMREAD();
|
||||
|
||||
@@ -22,7 +22,10 @@
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "../dynarec_helper.h"
|
||||
|
||||
static const float addsubps[4] = {-1.f, 1.f, -1.f, 1.f};
|
||||
static const double addsubpd[2] = {-1., 1.};
|
||||
|
||||
uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, vex_t vex, int* ok, int* need_epilog)
|
||||
{
|
||||
@@ -555,11 +558,10 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x3, (nextop&7)+(rex.b<<3), 1);
|
||||
} else {
|
||||
WILLWRITE2();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0xffe<<4, 15, rex, NULL, 0, 0);
|
||||
unscaled = 0;
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
// check if mask as anything, else scipt the whole read/write to avoid a SEGFAULT.
|
||||
// check if mask as anything, else skip the whole read/write to avoid a SEGFAULT.
|
||||
// TODO: let a segfault trigger and check if the mask is null instead and ignore the segfault / actually triger: needs to implement SSE reg tracking first!
|
||||
SQXTN_32(v1, q0);
|
||||
VMOVQDto(x4, v1, 0);
|
||||
@@ -600,11 +602,10 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x3, (nextop&7)+(rex.b<<3), 1);
|
||||
} else {
|
||||
WILLWRITE2();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0xffe<<4, 15, rex, NULL, 0, 0);
|
||||
unscaled = 0;
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
// check if mask as anything, else scipt the whole read/write to avoid a SEGFAULT.
|
||||
// check if mask as anything, else skip the whole read/write to avoid a SEGFAULT.
|
||||
// TODO: let a segfault trigger and check if the mask is null instead and ignore the segfault / actually triger: needs to implement SSE reg tracking first!
|
||||
SQXTN_32(q1, q0);
|
||||
VMOVQDto(x4, q1, 0);
|
||||
@@ -994,26 +995,72 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
break;
|
||||
|
||||
case 0x8C:
|
||||
INST_NAME("VMASKMOVD/Q Vx, Ex, Gx");
|
||||
INST_NAME("VPMASKMOVD/Q Gx, Vx, Ex");
|
||||
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, 0);
|
||||
if(MODREG) {
|
||||
if(!l) {
|
||||
GETGX_empty_VXEX(v0, v2, v1, 0);
|
||||
} else {
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
}
|
||||
if(rex.w)
|
||||
VSSHRQ_64(q0, v2, 63);
|
||||
else
|
||||
VSSHRQ_32(q0, v2, 31);
|
||||
VANDQ(v0, v1, q0);
|
||||
} else {
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
if(!l) {
|
||||
GETGX_empty_VX(v0, v2);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
} else {
|
||||
GETGY_empty_VY(v0, v2, 0, -1, -1);
|
||||
}
|
||||
unscaled = 0;
|
||||
// check if mask as anything, else skip the whole read/write to avoid a SEGFAULT.
|
||||
// TODO: let a segfault trigger and check if the mask is null instead and ignore the segfault / actually triger: needs to implement SSE reg tracking first!
|
||||
VEORQ(v1, v1, v1);
|
||||
if(rex.w) {
|
||||
VSSHRQ_64(q0, v2, 63);
|
||||
VMOVQDto(x4, q0, 0);
|
||||
CBZx(x4, 4+1*4);
|
||||
VLD1_64(v1, 0, ed);
|
||||
ADDx_U12(ed, ed, 4);
|
||||
VMOVQDto(x4, q0, 1);
|
||||
CBZx(x4, 4+1*4);
|
||||
VLD1_64(v1, 1, ed);
|
||||
if(!l && vex.l)
|
||||
ADDx_U12(ed, ed, 4);
|
||||
} else {
|
||||
VSSHRQ_32(q0, v2, 31);
|
||||
VMOVSto(x4, q0, 0);
|
||||
CBZx(x4, 4+1*4);
|
||||
VLD1_32(v1, 0, ed);
|
||||
ADDx_U12(ed, ed, 4);
|
||||
VMOVSto(x4, q0, 1);
|
||||
CBZx(x4, 4+1*4);
|
||||
VLD1_32(v1, 1, ed);
|
||||
ADDx_U12(ed, ed, 4);
|
||||
VMOVSto(x4, q0, 2);
|
||||
CBZx(x4, 4+1*4);
|
||||
VLD1_32(v1, 2, ed);
|
||||
ADDx_U12(ed, ed, 4);
|
||||
VMOVSto(x4, q0, 3);
|
||||
CBZx(x4, 4+1*4);
|
||||
VLD1_32(v1, 3, ed);
|
||||
if(!l && vex.l)
|
||||
ADDx_U12(ed, ed, 4);
|
||||
}
|
||||
VMOVQ(v0, v1);
|
||||
}
|
||||
if(rex.w)
|
||||
VSSHRQ_64(q0, v2, 63);
|
||||
else
|
||||
VSSHRQ_32(q0, v2, 31);
|
||||
VANDQ(v0, v1, q0);
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0x8E:
|
||||
INST_NAME("VMASKMOVD/Q Ex, Vx, Gx");
|
||||
INST_NAME("VPMASKMOVD/Q Ex, Vx, Gx");
|
||||
nextop = F8;
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
@@ -1057,7 +1104,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
MOV64x(x5, F32S64);
|
||||
eb1 = x5;
|
||||
} else
|
||||
eb1 = xRAX + (u8&0x7)+(rex.b<<3); // base
|
||||
eb1 = TO_NAT((u8 & 0x7) + (rex.b << 3)); // base
|
||||
eb2 = ((u8>>3)&7)+(rex.x<<3); // index
|
||||
if(nextop&0x40)
|
||||
i32 = F8S;
|
||||
@@ -1116,7 +1163,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
MOV64x(x5, F32S64);
|
||||
eb1 = x5;
|
||||
} else
|
||||
eb1 = xRAX + (u8&0x7)+(rex.b<<3); // base
|
||||
eb1 = TO_NAT((u8 & 0x7) + (rex.b << 3)); // base
|
||||
eb2 = ((u8>>3)&7)+(rex.x<<3); // index
|
||||
if(nextop&0x40)
|
||||
i32 = F8S;
|
||||
@@ -1208,7 +1255,18 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
}
|
||||
YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0x9A:
|
||||
INST_NAME("VFNMSUB132PS/D Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_VXEX(v0, v2, v1, 0); } else { GETGY_VYEY(v0, v2, v1); }
|
||||
if(rex.w) VFNEGQD(q0, v2); else VFNEGQS(q0, v2);
|
||||
if(rex.w) VFMLAQD(q0, v0, v1); else VFMLAQS(q0, v0, v1);
|
||||
VMOVQ(v0, q0);
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x9B:
|
||||
INST_NAME("VFMSUB132SS/D Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
@@ -1233,7 +1291,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
if(!l && v0!=v2) q0 = fpu_get_scratch(dyn, ninst);
|
||||
if(v0!=v2) VMOVQ(q0, v2); else q0 = v2;
|
||||
if(rex.w) VFMLSQD(q0, v0, v1); else VFMLSQS(q0, v0, v1);
|
||||
VMOVQ(v0, q0);
|
||||
if(q0!=v0) VMOVQ(v0, q0);
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
@@ -1271,6 +1329,27 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0xA6:
|
||||
INST_NAME("VFMADDSUB213PS/D Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
TABLE64(x2, (rex.w)?((uintptr_t)&addsubpd):((uintptr_t)&addsubps));
|
||||
VLDR128_U12(q0, x2, 0);
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) { GETGX_VXEX(v0, v2, v1, 0); } else { GETGY_VYEY(v0, v2, v1); }
|
||||
if(rex.w) {
|
||||
VFMULQD(q1, v1, q0);
|
||||
VFMLAQD(q1, v0, v2);
|
||||
} else {
|
||||
VFMULQS(q1, v1, q0);
|
||||
VFMLAQS(q1, v0, v2);
|
||||
}
|
||||
VMOVQ(v0, q1);
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0xA8:
|
||||
INST_NAME("VFMADD213PS/D Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
@@ -1404,9 +1483,6 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
INST_NAME("VFMADDSUB231PS/D Gx, Vx, Ex");
|
||||
nextop = F8;
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
static float addsubps[4] = {-1.f, 1.f, -1.f, 1.f};
|
||||
static double addsubpd[2] = {-1., 1.};
|
||||
MAYUSE(addsubps); MAYUSE(addsubpd);
|
||||
TABLE64(x2, (rex.w)?((uintptr_t)&addsubpd):((uintptr_t)&addsubps));
|
||||
VLDR128_U12(q0, x2, 0);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.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)
|
||||
{
|
||||
@@ -368,7 +368,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
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);
|
||||
@@ -385,7 +385,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
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);
|
||||
@@ -402,7 +402,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
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);
|
||||
@@ -423,7 +423,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
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);
|
||||
@@ -490,7 +490,6 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x3, (nextop&7)+(rex.b<<3));
|
||||
} else {
|
||||
WILLWRITE2();
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.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)
|
||||
{
|
||||
@@ -88,7 +88,6 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
if(v1!=v2) VMOVeD(v1, 1, v2, 1);
|
||||
YMM0((nextop&7)+(rex.b<<3));
|
||||
} else {
|
||||
WILLWRITE2();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VST64(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.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)
|
||||
{
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.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)
|
||||
{
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.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)
|
||||
{
|
||||
@@ -215,6 +215,21 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
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");
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box64context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x64emu_private.h"
|
||||
#include "emu/x64run_private.h"
|
||||
#include "x64run.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 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;
|
||||
}
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "../dynarec_helper.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
FCMPD(v1, v2);
|
||||
}
|
||||
FCOM(x1, x2, x3);
|
||||
FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0));
|
||||
break;
|
||||
case 0xD8:
|
||||
case 0xD9:
|
||||
@@ -108,7 +108,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
FCMPD(v1, v2);
|
||||
}
|
||||
FCOM(x1, x2, x3);
|
||||
FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0));
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xE0:
|
||||
@@ -222,7 +222,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
FCVT_D_S(s0, s0);
|
||||
FCMPD(v1, s0);
|
||||
}
|
||||
FCOM(x1, x2, x3);
|
||||
FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0));
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FCOMP ST0, float[ED]");
|
||||
@@ -236,7 +236,7 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
FCVT_D_S(s0, s0);
|
||||
FCMPD(v1, s0);
|
||||
}
|
||||
FCOM(x1, x2, x3);
|
||||
FCOM(x1, x2, x3, x4, v1, s0, ST_IS_F(0));
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "../dynarec_helper.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
|
||||
|
||||
@@ -128,7 +128,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
FCMPD_0(v1);
|
||||
}
|
||||
FCOM(x1, x2, x3); // same flags...
|
||||
FCOM(x1, x2, x3, x4, 0, 0, ST_IS_F(0)); // same flags...
|
||||
break;
|
||||
case 0xE5:
|
||||
INST_NAME("FXAM");
|
||||
@@ -161,21 +161,21 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
ADDw_U12(x5, x5, i2);
|
||||
}
|
||||
ANDw_mask(x5, x5, 0, 3); // (emu->top + i)&7
|
||||
ANDw_mask(x5, x5, 0, 2); // (emu->top + i)&7
|
||||
}
|
||||
// load tag
|
||||
LDRH_U12(x3, xEmu, offsetof(x64emu_t, fpu_tags));
|
||||
if(i2<0) {
|
||||
LSLw_IMM(x3, x3, -i2*2);
|
||||
} else 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
|
||||
// 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
|
||||
@@ -294,7 +294,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
CALL(native_ftan, -1);
|
||||
x87_unstackcount(dyn, ninst, x1, i1);
|
||||
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 {
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "../dynarec_helper.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
|
||||
|
||||
@@ -130,7 +130,7 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
FCMPD(v1, v2);
|
||||
}
|
||||
FCOM(x1, x2, x3);
|
||||
FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0));
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
@@ -169,7 +169,7 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
FCMPD(v1, v2);
|
||||
FCOM(x1, x2, x3);
|
||||
FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0));
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FICOMP ST0, Ed");
|
||||
@@ -180,7 +180,7 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
FCMPD(v1, v2);
|
||||
FCOM(x1, x2, x3);
|
||||
FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0));
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "../dynarec_helper.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
|
||||
|
||||
@@ -155,7 +155,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
FCMPD(v1, v2);
|
||||
}
|
||||
FCOMI(x1, x2);
|
||||
FCOMI(x1, x2, x4, v1, v2, ST_IS_F(0));
|
||||
break;
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
@@ -174,7 +174,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
FCMPD(v1, v2);
|
||||
}
|
||||
FCOMI(x1, x2);
|
||||
FCOMI(x1, x2, x4, v1, v2, ST_IS_F(0));
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "../dynarec_helper.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
FCMPD(v1, v2);
|
||||
}
|
||||
FCOM(x1, x2, x3);
|
||||
FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0));
|
||||
break;
|
||||
case 0xD8:
|
||||
case 0xD9:
|
||||
@@ -106,7 +106,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
FCMPD(v1, v2);
|
||||
}
|
||||
FCOM(x1, x2, x3);
|
||||
FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0));
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xE0:
|
||||
@@ -205,7 +205,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v2, wback, fixedaddress);
|
||||
FCMPD(v1, v2);
|
||||
FCOM(x1, x2, x3);
|
||||
FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0));
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FCOMP ST0, double[ED]");
|
||||
@@ -214,7 +214,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VLD64(v2, wback, fixedaddress);
|
||||
FCMPD(v1, v2);
|
||||
FCOM(x1, x2, x3);
|
||||
FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0));
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "../dynarec_helper.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@ uintptr_t dynarec64_DD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
FCMPD(v1, v2);
|
||||
}
|
||||
FCOM(x1, x2, x3);
|
||||
FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0));
|
||||
break;
|
||||
case 0xE8:
|
||||
case 0xE9:
|
||||
@@ -136,7 +136,7 @@ uintptr_t dynarec64_DD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
FCMPD(v1, v2);
|
||||
}
|
||||
FCOM(x1, x2, x3);
|
||||
FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0));
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "../dynarec_helper.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
FCMPD(v1, v2);
|
||||
}
|
||||
FCOM(x1, x2, x3);
|
||||
FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0));
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xD9:
|
||||
@@ -102,7 +102,7 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
FCMPD(v1, v2);
|
||||
}
|
||||
FCOM(x1, x2, x3);
|
||||
FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0));
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
@@ -215,7 +215,7 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
FCMPD(v1, v2);
|
||||
FCOM(x1, x2, x3);
|
||||
FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0));
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FICOMP ST0, word[ED]");
|
||||
@@ -227,7 +227,7 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
FCMPD(v1, v2);
|
||||
FCOM(x1, x2, x3);
|
||||
FCOM(x1, x2, x3, x4, v1, v2, ST_IS_F(0));
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "../dynarec_helper.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
|
||||
|
||||
@@ -109,7 +109,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
FCMPD(v1, v2);
|
||||
}
|
||||
FCOMI(x1, x2);
|
||||
FCOMI(x1, x2, x4, v1, v2, ST_IS_F(0));
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xF0:
|
||||
@@ -130,7 +130,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
FCMPD(v1, v2);
|
||||
}
|
||||
FCOMI(x1, x2);
|
||||
FCOMI(x1, x2, x4, v1, v2, ST_IS_F(0));
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "../dynarec_helper.h"
|
||||
|
||||
// emit OR32 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
|
||||
void emit_or32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
|
||||
@@ -34,18 +34,36 @@ void emit_or32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3,
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
int 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) TSTxw_REG(s1, s1);
|
||||
IFX(X_CF) {
|
||||
IFNATIVE(NF_CF) {} else {
|
||||
BFCw(xFlags, F_CF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_OF) {
|
||||
IFNATIVE(NF_VF) {} else {
|
||||
BFCw(xFlags, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_AF) {
|
||||
BFCw(xFlags, F_AF, 1);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(s1, s1);
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
IFNATIVE(NF_SF) {} else {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
@@ -55,33 +73,51 @@ void emit_or32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3,
|
||||
// emit OR32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_or32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4)
|
||||
{
|
||||
int mask = convert_bitmask_xw(c);
|
||||
if(!mask) {
|
||||
MOV64xw(s3, c);
|
||||
emit_or32(dyn, ninst, rex, s1, s3, s3, s4);
|
||||
return;
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, rex.w?d_or64:d_or32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
int mask = convert_bitmask_xw(c);
|
||||
if(mask) {
|
||||
ORRxw_mask(s1, s1, (mask>>12)&1, mask&0x3F, (mask>>6)&0x3F);
|
||||
} else {
|
||||
MOV64xw(s3, c);
|
||||
ORRxw_REG(s1, s1, s3);
|
||||
}
|
||||
ORRxw_mask(s1, s1, (mask>>12)&1, mask&0x3F, (mask>>6)&0x3F);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
int 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) TSTxw_REG(s1, s1);
|
||||
IFX(X_CF) {
|
||||
IFNATIVE(NF_CF) {} else {
|
||||
BFCw(xFlags, F_CF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_OF) {
|
||||
IFNATIVE(NF_VF) {} else {
|
||||
BFCw(xFlags, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_AF) {
|
||||
BFCw(xFlags, F_AF, 1);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(s1, s1);
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
IFNATIVE(NF_SF) {} else {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
@@ -101,18 +137,36 @@ void emit_xor32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
int 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) TSTxw_REG(s1, s1);
|
||||
IFX(X_CF) {
|
||||
IFNATIVE(NF_CF) {} else {
|
||||
BFCw(xFlags, F_CF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_OF) {
|
||||
IFNATIVE(NF_VF) {} else {
|
||||
BFCw(xFlags, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_AF) {
|
||||
BFCw(xFlags, F_AF, 1);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(s1, s1);
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
IFNATIVE(NF_SF) {} else {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
@@ -122,33 +176,51 @@ void emit_xor32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
// emit XOR32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_xor32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4)
|
||||
{
|
||||
int mask = convert_bitmask_xw(c);
|
||||
if(!mask) {
|
||||
MOV64xw(s3, c);
|
||||
emit_xor32(dyn, ninst, rex, s1, s3, s3, s4);
|
||||
return;
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, rex.w?d_xor64:d_xor32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
int mask = convert_bitmask_xw(c);
|
||||
if(mask) {
|
||||
EORxw_mask(s1, s1, (mask>>12)&1, mask&0x3F, (mask>>6)&0x3F);
|
||||
} else {
|
||||
MOV64xw(s3, c);
|
||||
EORxw_REG(s1, s1, s3);
|
||||
}
|
||||
EORxw_mask(s1, s1, (mask>>12)&1, mask&0x3F, (mask>>6)&0x3F);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
int 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) TSTxw_REG(s1, s1);
|
||||
IFX(X_CF) {
|
||||
IFNATIVE(NF_CF) {} else {
|
||||
BFCw(xFlags, F_CF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_OF) {
|
||||
IFNATIVE(NF_VF) {} else {
|
||||
BFCw(xFlags, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_AF) {
|
||||
BFCw(xFlags, F_AF, 1);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(s1, s1);
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
IFNATIVE(NF_SF) {} else {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
@@ -164,7 +236,7 @@ void emit_and32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
IFX(X_ZF|X_SF|X_CF|X_OF) {
|
||||
ANDSxw_REG(s1, s1, s2);
|
||||
} else {
|
||||
ANDxw_REG(s1, s1, s2);
|
||||
@@ -172,17 +244,30 @@ void emit_and32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
IFX(X_CF) {
|
||||
IFNATIVE(NF_CF) {} else {
|
||||
BFCw(xFlags, F_CF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_OF) {
|
||||
IFNATIVE(NF_VF) {} else {
|
||||
BFCw(xFlags, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_AF) {
|
||||
BFCw(xFlags, F_AF, 1);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
IFNATIVE(NF_SF) {} else {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
@@ -192,40 +277,49 @@ void emit_and32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
// emit AND32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_and32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4)
|
||||
{
|
||||
int mask = convert_bitmask_xw(c);
|
||||
if(!mask) {
|
||||
MOV64xw(s3, c);
|
||||
emit_and32(dyn, ninst, rex, s1, s3, s3, s4);
|
||||
return;
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, rex.w?d_and64:d_and32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
int mask = convert_bitmask_xw(c);
|
||||
if(mask) {
|
||||
IFX(X_ALL) {
|
||||
ANDSxw_mask(s1, s1, (mask>>12)&1, mask&0x3F, (mask>>6)&0x3F);
|
||||
} else {
|
||||
ANDxw_mask(s1, s1, (mask>>12)&1, mask&0x3F, (mask>>6)&0x3F);
|
||||
}
|
||||
IFX(X_ZF|X_SF|X_CF|X_OF) {
|
||||
ANDSxw_mask(s1, s1, (mask>>12)&1, mask&0x3F, (mask>>6)&0x3F);
|
||||
} else {
|
||||
MOV64xw(s3, c);
|
||||
IFX(X_ALL) {
|
||||
ANDSxw_REG(s1, s1, s3);
|
||||
} else {
|
||||
ANDxw_REG(s1, s1, s3);
|
||||
}
|
||||
ANDxw_mask(s1, s1, (mask>>12)&1, mask&0x3F, (mask>>6)&0x3F);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
IFX(X_CF) {
|
||||
IFNATIVE(NF_CF) {} else {
|
||||
BFCw(xFlags, F_CF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_OF) {
|
||||
IFNATIVE(NF_VF) {} else {
|
||||
BFCw(xFlags, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_AF) {
|
||||
BFCw(xFlags, F_AF, 1);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
IFNATIVE(NF_SF) {} else {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
@@ -237,9 +331,9 @@ void emit_or8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s2);
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s3, d_or8);
|
||||
SET_DF(s4, d_or8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
ORRw_REG(s1, s1, s2);
|
||||
IFX(X_PEND) {
|
||||
@@ -256,20 +350,20 @@ void emit_or8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
|
||||
// emit OR8 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_or8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
void emit_or8c(dynarec_arm_t* dyn, int ninst, int s1, uint8_t c, int s3, int s4)
|
||||
{
|
||||
int mask = convert_bitmask_w(c);
|
||||
if(!mask) {
|
||||
MOV32w(s3, c);
|
||||
emit_or8(dyn, ninst, s1, s3, s3, s4);
|
||||
return;
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, d_or8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
int mask = convert_bitmask_w(c);
|
||||
if(mask) {
|
||||
ORRw_mask(s1, s1, mask&0x3F, (mask>>6)&0x3F);
|
||||
} else {
|
||||
MOV32w(s3, c&0xff);
|
||||
ORRw_REG(s1, s1, s3);
|
||||
}
|
||||
ORRw_mask(s1, s1, mask&0x3F, (mask>>6)&0x3F);
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
@@ -288,9 +382,9 @@ void emit_xor8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s2);
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s3, d_xor8);
|
||||
SET_DF(s4, d_xor8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
EORx_REG(s1, s1, s2);
|
||||
IFX(X_PEND) {
|
||||
@@ -307,20 +401,20 @@ void emit_xor8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
|
||||
// emit XOR8 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_xor8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
void emit_xor8c(dynarec_arm_t* dyn, int ninst, int s1, uint8_t c, int s3, int s4)
|
||||
{
|
||||
int mask = convert_bitmask_w(c);
|
||||
if(!mask) {
|
||||
MOV32w(s3, c&0xff);
|
||||
emit_xor8(dyn, ninst, s1, s3, s3, s4);
|
||||
return;
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, d_xor8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
int mask = convert_bitmask_w(c);
|
||||
if(mask) {
|
||||
EORw_mask(s1, s1, mask&0x3F, (mask>>6)&0x3F);
|
||||
} else {
|
||||
MOV32w(s3, c&0xff);
|
||||
EORw_REG(s1, s1, s3);
|
||||
}
|
||||
EORw_mask(s1, s1, mask&0x3F, (mask>>6)&0x3F);
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
@@ -339,9 +433,9 @@ void emit_and8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s2);
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s3, d_and8);
|
||||
SET_DF(s4, d_and8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ANDSw_REG(s1, s1, s2);
|
||||
@@ -355,13 +449,19 @@ void emit_and8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw_REG(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 7);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
if(arm64_flagm) {
|
||||
COMP_ZFSF(s1, 8)
|
||||
} else {
|
||||
IFX(X_ZF) {
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 7);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
@@ -369,27 +469,23 @@ void emit_and8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
|
||||
// emit AND8 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_and8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
void emit_and8c(dynarec_arm_t* dyn, int ninst, int s1, uint8_t c, int s3, int s4)
|
||||
{
|
||||
int mask = convert_bitmask_w(c);
|
||||
if(!mask) {
|
||||
MOV32w(s3, c);
|
||||
emit_and8(dyn, ninst, s1, s3, s3, s4);
|
||||
return;
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, d_and8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
int mask = convert_bitmask_w(c);
|
||||
if(mask) {
|
||||
IFX(X_ZF) {
|
||||
ANDSw_mask(s1, s1, mask&0x3F, (mask>>6)&0x3F);
|
||||
} else {
|
||||
ANDw_mask(s1, s1, mask&0x3F, (mask>>6)&0x3F);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ANDSw_mask(s1, s1, mask&0x3F, (mask>>6)&0x3F);
|
||||
} else {
|
||||
MOV32w(s3, c&0xff);
|
||||
IFX(X_ZF) {
|
||||
ANDSw_REG(s1, s1, s3);
|
||||
} else {
|
||||
ANDw_REG(s1, s1, s3);
|
||||
}
|
||||
ANDw_mask(s1, s1, mask&0x3F, (mask>>6)&0x3F);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
@@ -398,28 +494,33 @@ void emit_and8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 7);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
if(arm64_flagm) {
|
||||
COMP_ZFSF(s1, 8)
|
||||
} else {
|
||||
IFX(X_ZF) {
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 7);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// emit OR16 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed)
|
||||
void emit_or16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s2);
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s3, d_or16);
|
||||
SET_DF(s4, d_or16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
ORRw_REG(s1, s1, s2);
|
||||
IFX(X_PEND) {
|
||||
@@ -436,59 +537,41 @@ void emit_or16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
|
||||
// emit OR16 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
//void emit_or16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
//{
|
||||
// IFX(X_PEND) {
|
||||
// MOVW(s3, c);
|
||||
// STR_IMM9(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
// STR_IMM9(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
// SET_DF(s4, d_or16);
|
||||
// } else IFX(X_ALL) {
|
||||
// SET_DFNONE(s4);
|
||||
// }
|
||||
// if(c>=0 && c<256) {
|
||||
// IFX(X_ALL) {
|
||||
// ORRS_IMM8(s1, s1, c, 0);
|
||||
// } else {
|
||||
// ORR_IMM8(s1, s1, c, 0);
|
||||
// }
|
||||
// } else {
|
||||
// IFX(X_PEND) {} else {MOVW(s3, c);}
|
||||
// IFX(X_ALL) {
|
||||
// ORRS_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
// } else {
|
||||
// ORR_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
// }
|
||||
// }
|
||||
// IFX(X_PEND) {
|
||||
// STR_IMM9(s1, xEmu, offsetof(x64emu_t, res));
|
||||
// }
|
||||
// IFX(X_CF | X_AF | X_ZF) {
|
||||
// BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
|
||||
// }
|
||||
// IFX(X_OF) {
|
||||
// BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
|
||||
// }
|
||||
// IFX(X_ZF) {
|
||||
// ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
// }
|
||||
// IFX(X_SF) {
|
||||
// MOV_REG_LSR_IMM5(s3, s1, 15);
|
||||
// BFI(xFlags, s3, F_SF, 1);
|
||||
// }
|
||||
// IFX(X_PF) {
|
||||
// emit_pf(dyn, ninst, s1, s4);
|
||||
// }
|
||||
//}
|
||||
void emit_or16c(dynarec_arm_t* dyn, int ninst, int s1, int16_t c, int s3, int s4)
|
||||
{
|
||||
int mask = convert_bitmask_w((uint16_t)c);
|
||||
if(!mask) {
|
||||
MOV32w(s3, (uint16_t)c);
|
||||
emit_or16(dyn, ninst, s1, s3, s3, s4);
|
||||
return;
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, d_or16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
ORRw_mask(s1, s1, mask&0x3F, (mask>>6)&0x3F);
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
COMP_ZFSF(s1, 16)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit XOR16 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed)
|
||||
void emit_xor16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s2);
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s3, d_xor16);
|
||||
SET_DF(s4, d_xor16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
EORw_REG(s1, s1, s2);
|
||||
IFX(X_PEND) {
|
||||
@@ -505,61 +588,44 @@ void emit_xor16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
|
||||
// emit XOR16 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
//void emit_xor16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
//{
|
||||
// IFX(X_PEND) {
|
||||
// MOVW(s3, c);
|
||||
// STR_IMM9(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
// STR_IMM9(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
// SET_DF(s4, d_xor16);
|
||||
// } else IFX(X_ALL) {
|
||||
// SET_DFNONE(s4);
|
||||
// }
|
||||
// if(c>=0 && c<256) {
|
||||
// IFX(X_ALL) {
|
||||
// XORS_IMM8(s1, s1, c);
|
||||
// } else {
|
||||
// XOR_IMM8(s1, s1, c);
|
||||
// }
|
||||
// } else {
|
||||
// IFX(X_PEND) {} else {MOVW(s3, c);}
|
||||
// IFX(X_ALL) {
|
||||
// XORS_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
// } else {
|
||||
// XOR_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
// }
|
||||
// }
|
||||
// IFX(X_PEND) {
|
||||
// STR_IMM9(s1, xEmu, offsetof(x64emu_t, res));
|
||||
// }
|
||||
// IFX(X_CF | X_AF | X_ZF) {
|
||||
// BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
|
||||
// }
|
||||
// IFX(X_OF) {
|
||||
// BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
|
||||
// }
|
||||
// IFX(X_ZF) {
|
||||
// ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
// }
|
||||
// IFX(X_SF) {
|
||||
// MOV_REG_LSR_IMM5(s3, s1, 15);
|
||||
// BFI(xFlags, s3, F_SF, 1);
|
||||
// }
|
||||
// IFX(X_PF) {
|
||||
// emit_pf(dyn, ninst, s1, s4);
|
||||
// }
|
||||
//}
|
||||
void emit_xor16c(dynarec_arm_t* dyn, int ninst, int s1, int16_t c, int s3, int s4)
|
||||
{
|
||||
int mask = convert_bitmask_w((uint16_t)c);
|
||||
if(!mask) {
|
||||
MOV32w(s3, (uint16_t)c);
|
||||
emit_xor16(dyn, ninst, s1, s3, s3, s4);
|
||||
return;
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, d_xor16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
EORw_mask(s1, s1, mask&0x3F, (mask>>6)&0x3F);
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
COMP_ZFSF(s1, 16)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// emit AND16 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed)
|
||||
void emit_and16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s2);
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s3, d_and16);
|
||||
SET_DF(s4, d_and16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_ALL) {
|
||||
IFX(X_ZF) {
|
||||
ANDSw_REG(s1, s1, s2);
|
||||
} else {
|
||||
ANDw_REG(s1, s1, s2);
|
||||
@@ -571,13 +637,19 @@ void emit_and16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw_REG(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 15);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
if(arm64_flagm) {
|
||||
COMP_ZFSF(s1, 16)
|
||||
} else {
|
||||
IFX(X_ZF) {
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 15);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
@@ -585,47 +657,46 @@ void emit_and16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
|
||||
// emit AND16 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
//void emit_and16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
//{
|
||||
// IFX(X_PEND) {
|
||||
// MOVW(s3, c);
|
||||
// STR_IMM9(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
// STR_IMM9(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
// SET_DF(s4, d_and16);
|
||||
// } else IFX(X_ALL) {
|
||||
// SET_DFNONE(s4);
|
||||
// }
|
||||
// if(c>=0 && c<256) {
|
||||
// IFX(X_ALL) {
|
||||
// ANDS_IMM8(s1, s1, c);
|
||||
// } else {
|
||||
// AND_IMM8(s1, s1, c);
|
||||
// }
|
||||
// } else {
|
||||
// IFX(X_PEND) {} else {MOVW(s3, c);}
|
||||
// IFX(X_ALL) {
|
||||
// ANDS_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
// } else {
|
||||
// AND_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
// }
|
||||
// }
|
||||
// IFX(X_PEND) {
|
||||
// STR_IMM9(s1, xEmu, offsetof(x64emu_t, res));
|
||||
// }
|
||||
// IFX(X_CF | X_AF | X_ZF) {
|
||||
// BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
|
||||
// }
|
||||
// IFX(X_OF) {
|
||||
// BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
|
||||
// }
|
||||
// IFX(X_ZF) {
|
||||
// ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
// }
|
||||
// IFX(X_SF) {
|
||||
// MOV_REG_LSR_IMM5(s3, s1, 15);
|
||||
// BFI(xFlags, s3, F_SF, 1);
|
||||
// }
|
||||
// IFX(X_PF) {
|
||||
// emit_pf(dyn, ninst, s1, s4);
|
||||
// }
|
||||
//}
|
||||
void emit_and16c(dynarec_arm_t* dyn, int ninst, int s1, int16_t c, int s3, int s4)
|
||||
{
|
||||
int mask = convert_bitmask_w((uint16_t)c);
|
||||
if(!mask) {
|
||||
MOV32w(s3, (uint16_t)c);
|
||||
emit_and16(dyn, ninst, s1, s3, s3, s4);
|
||||
return;
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
SET_DF(s4, d_and16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ANDSw_mask(s1, s1, mask&0x3F, (mask>>6)&0x3F);
|
||||
} else {
|
||||
ANDw_mask(s1, s1, mask&0x3F, (mask>>6)&0x3F);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
}
|
||||
if(arm64_flagm) {
|
||||
COMP_ZFSF(s1, 16)
|
||||
} else {
|
||||
IFX(X_ZF) {
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 15);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "../dynarec_helper.h"
|
||||
|
||||
// emit ADD32 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
|
||||
void emit_add32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
|
||||
@@ -51,20 +51,28 @@ void emit_add32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
BFIxw(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_CF) {
|
||||
CSETw(s4, cCS);
|
||||
BFIw(xFlags, s4, F_CF, 1);
|
||||
IFNATIVE(NF_CF) {} else {
|
||||
CSETw(s4, cCS);
|
||||
BFIw(xFlags, s4, F_CF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CSETw(s4, cVS);
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
IFNATIVE(NF_VF) {} else {
|
||||
CSETw(s4, cVS);
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s3, F_SF, 1);
|
||||
IFNATIVE(NF_SF) {} else {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
@@ -123,20 +131,28 @@ void emit_add32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, in
|
||||
BFIxw(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_CF) {
|
||||
CSETw(s4, cCS);
|
||||
BFIw(xFlags, s4, F_CF, 1);
|
||||
IFNATIVE(NF_CF) {} else {
|
||||
CSETw(s4, cCS);
|
||||
BFIw(xFlags, s4, F_CF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CSETw(s4, cVS);
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
IFNATIVE(NF_VF) {} else {
|
||||
CSETw(s4, cVS);
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s3, F_SF, 1);
|
||||
IFNATIVE(NF_SF) {} else {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
@@ -173,21 +189,31 @@ void emit_sub32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
BFIx(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_CF) {
|
||||
// inverted carry
|
||||
CSETw(s4, cCC);
|
||||
BFIw(xFlags, s4, F_CF, 1);
|
||||
IFNATIVE(NF_CF) {
|
||||
GEN_INVERTED_CARRY();
|
||||
} else {
|
||||
CSETw(s4, cCC);
|
||||
BFIw(xFlags, s4, F_CF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CSETw(s4, cVS);
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
IFNATIVE(NF_VF) {} else {
|
||||
CSETw(s4, cVS);
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s3, F_SF, 1);
|
||||
IFNATIVE(NF_SF) {} else {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
@@ -246,21 +272,31 @@ void emit_sub32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, in
|
||||
BFIw(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_CF) {
|
||||
// inverted carry
|
||||
CSETw(s4, cCC);
|
||||
BFIw(xFlags, s4, F_CF, 1);
|
||||
IFNATIVE(NF_CF) {
|
||||
GEN_INVERTED_CARRY();
|
||||
} else {
|
||||
CSETw(s4, cCC);
|
||||
BFIw(xFlags, s4, F_CF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CSETw(s4, cVS);
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
IFNATIVE(NF_VF) {} else {
|
||||
CSETw(s4, cVS);
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s3, F_SF, 1);
|
||||
IFNATIVE(NF_SF) {} else {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
@@ -274,7 +310,7 @@ void emit_add8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRB_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_add8);
|
||||
SET_DF(s3, d_add8b);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
@@ -282,37 +318,62 @@ void emit_add8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
ORRw_REG(s3, s1, s2); // s3 = op1 | op2
|
||||
ANDw_REG(s4, s1, s2); // s4 = op1 & op2
|
||||
}
|
||||
ADDw_REG(s1, s1, s2);
|
||||
IFX(X_AF|X_OF) {
|
||||
BICw_REG(s3, s3, s1); // s3 = (op1 | op2) & ~ res
|
||||
ORRw_REG(s3, s3, s4); // s3 = (op1 & op2) | ((op1 | op2) & ~ res)
|
||||
IFX(X_CF|X_SF|X_OF|X_ZF) {
|
||||
LSLw(s1, s1, 24);
|
||||
ADDSw_REG_LSL(s1, s1, s2, 24);
|
||||
IFX(X_AF) {
|
||||
BICw_REG_LSR(s3, s3, s1, 24); // s3 = (op1 | op2) & ~ res
|
||||
ORRw_REG(s3, s3, s4); // s3 = (op1 & op2) | ((op1 | op2) & ~ res)
|
||||
LSRw(s4, s3, 3);
|
||||
BFIw(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_CF) {
|
||||
IFNATIVE(NF_CF) {} else {
|
||||
CSETw(s4, cCS);
|
||||
BFIw(xFlags, s4, F_CF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_OF) {
|
||||
LSRw(s4, s3, 6);
|
||||
EORw_REG_LSR(s4, s4, s4, 1);
|
||||
BFIw(xFlags, s4, F_OF, 1); // OF: ((bc >> 6) ^ ((bc>>6)>>1)) & 1
|
||||
IFNATIVE(NF_VF) {} else {
|
||||
CSETw(s4, cVS);
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
IFNATIVE(NF_SF) {} else {
|
||||
CSETw(s4, cMI);
|
||||
BFIx(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
}
|
||||
LSRw(s1, s1, 24);
|
||||
} else {
|
||||
ADDw_REG(s1, s1, s2);
|
||||
IFX(X_AF) {
|
||||
BICw_REG(s3, s3, s1); // s3 = (op1 | op2) & ~ res
|
||||
ORRw_REG(s3, s3, s4); // s3 = (op1 & op2) | ((op1 | op2) & ~ res)
|
||||
LSRw(s4, s3, 3);
|
||||
BFIw(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
}
|
||||
}
|
||||
IFX(X_CF) {
|
||||
BFXILw(xFlags, s1, 8, 1);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
COMP_ZFSF(s1, 8)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit ADD8 instruction, from s1, const c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_add8c(dynarec_arm_t* dyn, int ninst, int s1, int c, int s3, int s4)
|
||||
void emit_add8c(dynarec_arm_t* dyn, int ninst, int s1, uint8_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOV32w(s4, c&0xff);
|
||||
MOV32w(s4, c);
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRB_U12(s4, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_add8);
|
||||
@@ -320,7 +381,7 @@ void emit_add8c(dynarec_arm_t* dyn, int ninst, int s1, int c, int s3, int s4)
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
IFX(X_AF | X_OF) {
|
||||
IFX(X_PEND) {} else {MOV32w(s4, c&0xff);}
|
||||
IFX(X_PEND) {} else {MOV32w(s4, c);}
|
||||
ORRw_REG(s3, s1, s4); // s3 = op1 | op2
|
||||
ANDw_REG(s4, s1, s4); // s4 = op1 & op2
|
||||
}
|
||||
@@ -396,11 +457,11 @@ void emit_sub8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
|
||||
// emit SUB8 instruction, from s1, constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_sub8c(dynarec_arm_t* dyn, int ninst, int s1, int c, int s3, int s4, int s5)
|
||||
void emit_sub8c(dynarec_arm_t* dyn, int ninst, int s1, uint8_t c, int s3, int s4, int s5)
|
||||
{
|
||||
MAYUSE(s5);
|
||||
IFX(X_ALL|X_PEND) {
|
||||
MOV32w(s5, c&0xff);
|
||||
MOV32w(s5, c);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
@@ -417,7 +478,7 @@ void emit_sub8c(dynarec_arm_t* dyn, int ninst, int s1, int c, int s3, int s4, in
|
||||
IFX(X_ALL) {
|
||||
SUBw_REG(s1, s1, s5);
|
||||
} else {
|
||||
SUBw_U12(s1, s1, c&0xff);
|
||||
SUBw_U12(s1, s1, c);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
@@ -452,36 +513,60 @@ void emit_add16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRH_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_add16);
|
||||
SET_DF(s3, d_add16b);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
IFX(X_AF | X_OF) {
|
||||
IFX(X_AF) {
|
||||
ORRw_REG(s3, s1, s2); // s3 = op1 | op2
|
||||
ANDw_REG(s4, s1, s2); // s4 = op1 & op2
|
||||
}
|
||||
ADDw_REG(s1, s1, s2);
|
||||
|
||||
IFX(X_AF|X_OF) {
|
||||
BICw_REG(s3, s3, s1); // s3 = (op1 | op2) & ~ res
|
||||
ORRw_REG(s3, s3, s4); // s3 = (op1 & op2) | ((op1 | op2) & ~ res)
|
||||
IFX(X_CF|X_SF|X_OF|X_ZF) {
|
||||
LSLw(s1, s1, 16);
|
||||
ADDSw_REG_LSL(s1, s1, s2, 16);
|
||||
IFX(X_AF) {
|
||||
BICw_REG_LSR(s3, s3, s1, 16); // s3 = (op1 | op2) & ~ res
|
||||
ORRw_REG(s3, s3, s4); // s3 = (op1 & op2) | ((op1 | op2) & ~ res)
|
||||
LSRw(s4, s3, 3);
|
||||
BFIw(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_CF) {
|
||||
IFNATIVE(NF_CF) {} else {
|
||||
CSETw(s4, cCS);
|
||||
BFIw(xFlags, s4, F_CF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_OF) {
|
||||
LSRw(s4, s3, 14);
|
||||
EORw_REG_LSR(s4, s4, s4, 1);
|
||||
BFIw(xFlags, s4, F_OF, 1); // OF: ((bc >> 14) ^ ((bc>>14)>>1)) & 1
|
||||
IFNATIVE(NF_VF) {} else {
|
||||
CSETw(s4, cVS);
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
IFNATIVE(NF_SF) {} else {
|
||||
CSETw(s4, cMI);
|
||||
BFIx(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
}
|
||||
LSRw(s1, s1, 16);
|
||||
} else {
|
||||
ADDw_REG(s1, s1, s2);
|
||||
IFX(X_AF) {
|
||||
BICw_REG(s3, s3, s1); // s3 = (op1 | op2) & ~ res
|
||||
ORRw_REG(s3, s3, s4); // s3 = (op1 & op2) | ((op1 | op2) & ~ res)
|
||||
LSRw(s4, s3, 3);
|
||||
BFIw(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
}
|
||||
}
|
||||
IFX(X_CF) {
|
||||
BFXILw(xFlags, s1, 16, 1);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
COMP_ZFSF(s1, 16)
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
@@ -665,12 +750,7 @@ void emit_sub16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
// emit INC32 instruction, from s1, store result in s1 using s3 and s4 as scratch
|
||||
void emit_inc32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s4, rex.w?d_inc64:d_inc32);
|
||||
} else IFX(X_ZF|X_OF|X_AF|X_SF|X_PF) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
SET_DFNONE(s4);
|
||||
IFX(X_AF) {
|
||||
if(rex.w) {
|
||||
ORRx_mask(s3, s1, 1, 0, 0); // s3 = op1 | op2
|
||||
@@ -680,14 +760,11 @@ void emit_inc32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s3, int s4
|
||||
ANDw_mask(s4, s1, 0, 0); // s4 = op1 & op2
|
||||
}
|
||||
}
|
||||
IFX(X_ZF|X_OF) {
|
||||
IFX(X_ZF|X_OF|X_SF) {
|
||||
ADDSxw_U12(s1, s1, 1);
|
||||
} else {
|
||||
ADDxw_U12(s1, s1, 1);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_AF) {
|
||||
BICxw_REG(s3, s3, s1); // s3 = (op1 | op2) & ~ res
|
||||
ORRxw_REG(s3, s3, s4); // s3 = (op1 & op2) | ((op1 | op2) & ~ res)
|
||||
@@ -695,16 +772,22 @@ void emit_inc32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s3, int s4
|
||||
BFIxw(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CSETw(s4, cVS);
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
IFNATIVE(NF_VF) {} else {
|
||||
CSETw(s4, cVS);
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s1, rex.w?63:31);
|
||||
BFIxw(xFlags, s3, F_SF, 1);
|
||||
IFNATIVE(NF_SF) {} else {
|
||||
LSRxw(s3, s1, rex.w?63:31);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
@@ -714,20 +797,12 @@ void emit_inc32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s3, int s4
|
||||
// emit INC8 instruction, from s1, store result in s1 using s3 and s4 as scratch
|
||||
void emit_inc8(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s3, d_inc8);
|
||||
} else IFX(X_ZF|X_OF|X_AF|X_SF|X_PF) {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
SET_DFNONE(s3);
|
||||
IFX(X_AF | X_OF) {
|
||||
ORRw_mask(s3, s1, 0, 0); // s3 = op1 | op2
|
||||
ANDw_mask(s4, s1, 0, 0); // s4 = op1 & op2
|
||||
}
|
||||
ADDw_U12(s1, s1, 1);
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_AF|X_OF) {
|
||||
BICw_REG(s3, s3, s1); // s3 = (op1 | op2) & ~ res
|
||||
ORRw_REG(s3, s3, s4); // s4 = (op1 & op2) | ((op1 | op2) & ~ res)
|
||||
@@ -750,22 +825,13 @@ void emit_inc8(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
// emit INC16 instruction, from s1, store result in s1 using s3 and s4 as scratch
|
||||
void emit_inc16(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s3, d_inc16);
|
||||
} else IFX(X_ZF|X_OF|X_AF|X_SF|X_PF) {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
SET_DFNONE(s3);
|
||||
IFX(X_AF | X_OF) {
|
||||
MOVw_REG(s4, s1);
|
||||
ORRw_mask(s3, s1, 0, 0); // s3 = op1 | op2
|
||||
ANDw_mask(s4, s1, 0, 0); // s4 = op1 & op2
|
||||
}
|
||||
ADDw_U12(s1, s1, 1);
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_AF|X_OF) {
|
||||
ORRw_mask(s3, s4, 0, 0); // s3 = op1 | op2
|
||||
ANDw_mask(s4, s4, 0, 0); // s4 = op1 & op2
|
||||
BICw_REG(s3, s3, s1); // s3 = (op1 | op2) & ~ res
|
||||
ORRw_REG(s3, s3, s4); // s3 = (op1 & op2) | ((op1 | op2) & ~ res)
|
||||
IFX(X_AF) {
|
||||
@@ -787,12 +853,7 @@ void emit_inc16(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
// emit DEC32 instruction, from s1, store result in s1 using s3 and s4 as scratch
|
||||
void emit_dec32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s4, rex.w?d_dec64:d_dec32);
|
||||
} else IFX(X_ZF|X_OF|X_AF|X_SF|X_PF) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
SET_DFNONE(s4);
|
||||
IFX(X_AF) {
|
||||
MVNxw_REG(s3, s1);
|
||||
if(rex.w) {
|
||||
@@ -803,14 +864,11 @@ void emit_dec32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s3, int s4
|
||||
ORRw_mask(s3, s3, 0, 0); // s3 = ~op1 | op2
|
||||
}
|
||||
}
|
||||
IFX(X_ZF|X_OF) {
|
||||
IFX(X_ZF|X_OF|X_SF) {
|
||||
SUBSxw_U12(s1, s1, 1);
|
||||
} else {
|
||||
SUBxw_U12(s1, s1, 1);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_AF) {
|
||||
ANDxw_REG(s3, s3, s1); // s3 = (~op1 | op2) & res
|
||||
ORRxw_REG(s3, s3, s4); // s4 = (~op1 & op2) | ((~op1 | op2) & ~ res)
|
||||
@@ -818,16 +876,22 @@ void emit_dec32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s3, int s4
|
||||
BFIw(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CSETw(s4, cVS);
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
IFNATIVE(NF_VF) {} else {
|
||||
CSETw(s4, cVS);
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s1, rex.w?63:31);
|
||||
BFIxw(xFlags, s3, F_SF, 1);
|
||||
IFNATIVE(NF_SF) {} else {
|
||||
LSRxw(s3, s1, rex.w?63:31);
|
||||
BFIxw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
@@ -837,12 +901,7 @@ void emit_dec32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s3, int s4
|
||||
// emit DEC8 instruction, from s1, store result in s1 using s3 and s4 as scratch
|
||||
void emit_dec8(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s3, d_dec8);
|
||||
} else IFX(X_ZF|X_OF|X_AF|X_SF|X_PF) {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
SET_DFNONE(s3);
|
||||
IFX(X_AF|X_OF) {
|
||||
MVNw_REG(s3, s1);
|
||||
ANDw_mask(s4, s3, 0, 0); // s4 = ~op1 & op2
|
||||
@@ -853,9 +912,6 @@ void emit_dec8(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
} else {
|
||||
SUBw_U12(s1, s1, 1);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_AF|X_OF) {
|
||||
ANDw_REG(s3, s3, s1); // s3 = (~op1 | op2) & res
|
||||
ORRw_REG(s3, s3, s4); // s3 = (~op1 & op2) | ((~op1 | op2) & res)
|
||||
@@ -870,8 +926,10 @@ void emit_dec8(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
}
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 7);
|
||||
@@ -885,12 +943,7 @@ void emit_dec8(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
// emit DEC16 instruction, from s1, store result in s1 using s3 and s4 as scratch
|
||||
void emit_dec16(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s3, d_dec16);
|
||||
} else IFX(X_ZF|X_OF|X_AF|X_SF|X_PF) {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
SET_DFNONE(s3);
|
||||
IFX(X_AF|X_OF) {
|
||||
MVNw_REG(s4, s1);
|
||||
}
|
||||
@@ -899,9 +952,6 @@ void emit_dec16(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
} else {
|
||||
SUBw_U12(s1, s1, 1);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_AF|X_OF) {
|
||||
ORRw_mask(s3, s4, 0, 0); // s3 = ~op1 | op2
|
||||
ANDw_mask(s4, s4, 0, 0); // s4 = ~op1 & op2
|
||||
@@ -918,8 +968,10 @@ void emit_dec16(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
}
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s3, s1, 15);
|
||||
@@ -941,13 +993,26 @@ void emit_adc32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
IFX(X_AF) {
|
||||
MOVxw_REG(s4, s1);
|
||||
IFNATIVE_BEFORE(NF_CF) {
|
||||
if(INVERTED_CARRY_BEFORE) {
|
||||
if(arm64_flagm)
|
||||
CFINV();
|
||||
else {
|
||||
MRS_nzcv(s3);
|
||||
EORx_mask(s3, s3, 1, 35, 0); //mask=1<<NZCV_C
|
||||
MSR_nzcv(s3);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
MRS_nzcv(s3);
|
||||
BFIx(s3, xFlags, 29, 1); // set C
|
||||
MSR_nzcv(s3); // load CC into ARM CF
|
||||
}
|
||||
MRS_nzvc(s3);
|
||||
BFIx(s3, xFlags, 29, 1); // set C
|
||||
MSR_nzvc(s3); // load CC into ARM CF
|
||||
IFX(X_ZF|X_CF|X_OF) {
|
||||
IFX(X_AF) {
|
||||
ORRxw_REG(s3, s1, s2); // s3 = op1 | op2
|
||||
ANDxw_REG(s4, s1, s2); // s4 = op1 & op2
|
||||
}
|
||||
IFX(X_ZF|X_CF|X_OF|X_SF) {
|
||||
ADCSxw_REG(s1, s1, s2);
|
||||
} else {
|
||||
ADCxw_REG(s1, s1, s2);
|
||||
@@ -956,28 +1021,34 @@ void emit_adc32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_AF) {
|
||||
ORRxw_REG(s3, s4, s2); // s3 = op1 | op2
|
||||
ANDxw_REG(s4, s4, s2); // s4 = op1 & op2
|
||||
BICxw_REG(s3, s3, s1); // s3 = (op1 | op2) & ~ res
|
||||
ORRxw_REG(s3, s3, s4); // s4 = (op1 & op2) | ((op1 | op2) & ~ res)
|
||||
LSRxw(s4, s3, 3);
|
||||
BFIw(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_CF) {
|
||||
CSETw(s3, cCS);
|
||||
BFIw(xFlags, s3, F_CF, 1);
|
||||
IFNATIVE(NF_CF) {} else {
|
||||
CSETw(s3, cCS);
|
||||
BFIw(xFlags, s3, F_CF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CSETw(s3, cVS);
|
||||
BFIw(xFlags, s3, F_OF, 1);
|
||||
IFNATIVE(NF_VF) {} else {
|
||||
CSETw(s3, cVS);
|
||||
BFIw(xFlags, s3, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRx(s3, s1, rex.w?63:31);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
IFNATIVE(NF_SF) {} else {
|
||||
LSRx(s3, s1, rex.w?63:31);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
@@ -1065,19 +1136,30 @@ void emit_adc8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
IFNATIVE_BEFORE(NF_CF) {
|
||||
if(INVERTED_CARRY_BEFORE) {
|
||||
if(arm64_flagm)
|
||||
CFINV();
|
||||
else {
|
||||
MRS_nzcv(s3);
|
||||
EORx_mask(s3, s3, 1, 35, 0); //mask=1<<NZCV_C
|
||||
MSR_nzcv(s3);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
MRS_nzcv(s3);
|
||||
BFIx(s3, xFlags, 29, 1); // set C
|
||||
MSR_nzcv(s3); // load CC into ARM CF
|
||||
}
|
||||
IFX(X_AF | X_OF) {
|
||||
MOVw_REG(s4, s1);
|
||||
ORRw_REG(s3, s1, s2); // s3 = op1 | op2
|
||||
ANDw_REG(s4, s1, s2); // s4 = op1 & op2
|
||||
}
|
||||
MRS_nzvc(s3);
|
||||
BFIx(s3, xFlags, 29, 1); // set C
|
||||
MSR_nzvc(s3); // load CC into ARM CF
|
||||
ADCw_REG(s1, s1, s2);
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_AF|X_OF) {
|
||||
ORRw_REG(s3, s4, s2); // s3 = op1 | op2
|
||||
ANDw_REG(s4, s4, s2); // s4 = op1 & op2
|
||||
BICw_REG(s3, s3, s1); // s3 = (op1 | op2) & ~ res
|
||||
ORRw_REG(s3, s3, s4); // s3 = (op1 & op2) | ((op1 | op2) & ~ res)
|
||||
IFX(X_AF) {
|
||||
@@ -1091,8 +1173,7 @@ void emit_adc8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
}
|
||||
IFX(X_CF) {
|
||||
LSRw(s3, s1, 8);
|
||||
BFIw(xFlags, s3, F_CF, 1);
|
||||
BFXILw(xFlags, s1, 8, 1);
|
||||
}
|
||||
COMP_ZFSF(s1, 8)
|
||||
IFX(X_PF) {
|
||||
@@ -1101,10 +1182,10 @@ void emit_adc8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
|
||||
// emit ADC8 instruction, from s1, const c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_adc8c(dynarec_arm_t* dyn, int ninst, int s1, int c, int s3, int s4, int s5)
|
||||
void emit_adc8c(dynarec_arm_t* dyn, int ninst, int s1, uint8_t c, int s3, int s4, int s5)
|
||||
{
|
||||
MAYUSE(s5);
|
||||
MOV32w(s5, c&0xff);
|
||||
MOV32w(s5, c);
|
||||
emit_adc8(dyn, ninst, s1, s5, s3, s4);
|
||||
}
|
||||
|
||||
@@ -1119,19 +1200,30 @@ void emit_adc16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
IFNATIVE_BEFORE(NF_CF) {
|
||||
if(INVERTED_CARRY_BEFORE) {
|
||||
if(arm64_flagm)
|
||||
CFINV();
|
||||
else {
|
||||
MRS_nzcv(s3);
|
||||
EORx_mask(s3, s3, 1, 35, 0); //mask=1<<NZCV_C
|
||||
MSR_nzcv(s3);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
MRS_nzcv(s3);
|
||||
BFIx(s3, xFlags, 29, 1); // set C
|
||||
MSR_nzcv(s3); // load CC into ARM CF
|
||||
}
|
||||
IFX(X_AF | X_OF) {
|
||||
MOVw_REG(s4, s1);
|
||||
ORRw_REG(s3, s1, s2); // s3 = op1 | op2
|
||||
ANDw_REG(s4, s1, s2); // s4 = op1 & op2
|
||||
}
|
||||
MRS_nzvc(s3);
|
||||
BFIx(s3, xFlags, 29, 1); // set C
|
||||
MSR_nzvc(s3); // load CC into ARM CF
|
||||
ADCw_REG(s1, s1, s2);
|
||||
IFX(X_PEND) {
|
||||
STRw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_AF|X_OF) {
|
||||
ORRw_REG(s3, s4, s2); // s3 = op1 | op2
|
||||
ANDw_REG(s4, s4, s2); // s4 = op1 & op2
|
||||
BICw_REG(s3, s3, s1); // s3 = (op1 | op2) & ~ res
|
||||
ORRw_REG(s3, s3, s4); // s3 = (op1 & op2) | ((op1 | op2) & ~ res)
|
||||
IFX(X_AF) {
|
||||
@@ -1145,8 +1237,7 @@ void emit_adc16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
}
|
||||
IFX(X_CF) {
|
||||
LSRw(s3, s1, 16);
|
||||
BFIw(xFlags, s3, F_CF, 1);
|
||||
BFXILw(xFlags, s1, 16, 1);
|
||||
}
|
||||
COMP_ZFSF(s1, 16)
|
||||
IFX(X_PF) {
|
||||
@@ -1232,14 +1323,27 @@ void emit_sbb32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
EORw_mask(s4, xFlags, 0, 0); // invert CC because it's reverted for SUB on ARM
|
||||
MRS_nzvc(s3);
|
||||
BFIx(s3, s4, 29, 1); // set C
|
||||
MSR_nzvc(s3); // load CC into ARM CF
|
||||
IFX(X_AF) {
|
||||
MVNxw_REG(s4, s1);
|
||||
IFNATIVE_BEFORE(NF_CF) {
|
||||
if(!INVERTED_CARRY_BEFORE) {
|
||||
if(arm64_flagm)
|
||||
CFINV();
|
||||
else {
|
||||
MRS_nzcv(s3);
|
||||
EORx_mask(s3, s3, 1, 35, 0); //mask=1<<NZCV_C
|
||||
MSR_nzcv(s3);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
EORw_mask(s4, xFlags, 0, 0); // invert CC because it's reverted for SUB on ARM
|
||||
MRS_nzcv(s3);
|
||||
BFIx(s3, s4, 29, 1); // set C
|
||||
MSR_nzcv(s3); // load CC into ARM CF
|
||||
}
|
||||
IFX(X_ZF|X_CF|X_OF) {
|
||||
IFX(X_AF) {
|
||||
ORNxw_REG(s3, s2, s1); // s3 = ~op1 | op2
|
||||
BICxw_REG(s4, s2, s1); // s4 = ~op1 & op2
|
||||
}
|
||||
IFX(X_ZF|X_CF|X_OF|X_SF) {
|
||||
SBCSxw_REG(s1, s1, s2);
|
||||
} else {
|
||||
SBCxw_REG(s1, s1, s2);
|
||||
@@ -1248,29 +1352,37 @@ void emit_sbb32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_AF) {
|
||||
ORRxw_REG(s3, s4, s2); // s3 = ~op1 | op2
|
||||
ANDxw_REG(s4, s2, s4); // s4 = ~op1 & op2
|
||||
ANDxw_REG(s3, s3, s1); // s3 = (~op1 | op2) & res
|
||||
ORRxw_REG(s3, s3, s4); // s4 = (~op1 & op2) | ((~op1 | op2) & res)
|
||||
UBFXw(s4, s3, 3, 1);
|
||||
LSRw_IMM(s4, s3, 3);
|
||||
BFIw(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(s3, cEQ);
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_CF) {
|
||||
// Inverted carry
|
||||
CSETw(s3, cCC);
|
||||
BFIw(xFlags, s3, F_CF, 1);
|
||||
IFNATIVE(NF_CF) {
|
||||
GEN_INVERTED_CARRY();
|
||||
} else {
|
||||
CSETw(s3, cCC);
|
||||
BFIw(xFlags, s3, F_CF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CSETw(s3, cVS);
|
||||
BFIw(xFlags, s3, F_OF, 1);
|
||||
IFNATIVE(NF_VF) {} else {
|
||||
CSETw(s3, cVS);
|
||||
BFIw(xFlags, s3, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s1, rex.w?63:31);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
IFNATIVE(NF_SF) {} else {
|
||||
LSRxw(s3, s1, rex.w?63:31);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
@@ -1360,25 +1472,35 @@ void emit_sbb8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
EORw_mask(s4, xFlags, 0, 0); // invert CC because it's reverted for SUB on ARM
|
||||
MRS_nzvc(s3);
|
||||
BFIx(s3, s4, 29, 1); // set C
|
||||
MSR_nzvc(s3); // load CC into ARM CF
|
||||
IFNATIVE_BEFORE(NF_CF) {
|
||||
if(!INVERTED_CARRY_BEFORE) {
|
||||
if(arm64_flagm)
|
||||
CFINV();
|
||||
else {
|
||||
MRS_nzcv(s3);
|
||||
EORx_mask(s3, s3, 1, 35, 0); //mask=1<<NZCV_C
|
||||
MSR_nzcv(s3);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
EORw_mask(s4, xFlags, 0, 0); // invert CC because it's reverted for SUB on ARM
|
||||
MRS_nzcv(s3);
|
||||
BFIx(s3, s4, 29, 1); // set C
|
||||
MSR_nzcv(s3); // load CC into ARM CF
|
||||
}
|
||||
IFX(X_AF|X_OF|X_CF) {
|
||||
MVNw_REG(s4, s1);
|
||||
ORNw_REG(s3, s2, s1); // s3 = ~op1 | op2
|
||||
BICw_REG(s4, s2, s1); // s4 = ~op1 & op2
|
||||
}
|
||||
SBCw_REG(s1, s1, s2);
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_AF|X_OF|X_CF) {
|
||||
ORRw_REG(s3, s4, s2); // s3 = ~op1 | op2
|
||||
ANDw_REG(s4, s2, s4); // s4 = ~op1 & op2
|
||||
ANDw_REG(s3, s3, s1); // s3 = (~op1 | op2) & res
|
||||
ORRw_REG(s3, s3, s4); // s3 = (~op1 & op2) | ((~op1 | op2) & res)
|
||||
IFX(X_CF) {
|
||||
LSRw(s4, s3, 7);
|
||||
BFIw(xFlags, s4, F_CF, 1); // CF : bc & 0x80
|
||||
BFXILw(xFlags, s3, 7, 1); // CF : bc & 0x80
|
||||
}
|
||||
IFX(X_AF) {
|
||||
LSRw(s4, s3, 3);
|
||||
@@ -1397,10 +1519,10 @@ void emit_sbb8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
|
||||
// emit SBB8 instruction, from s1, constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_sbb8c(dynarec_arm_t* dyn, int ninst, int s1, int c, int s3, int s4, int s5)
|
||||
void emit_sbb8c(dynarec_arm_t* dyn, int ninst, int s1, uint8_t c, int s3, int s4, int s5)
|
||||
{
|
||||
MAYUSE(s5);
|
||||
MOV32w(s5, c&0xff);
|
||||
MOV32w(s5, c);
|
||||
emit_sbb8(dyn, ninst, s1, s5, s3, s4);
|
||||
}
|
||||
|
||||
@@ -1415,25 +1537,35 @@ void emit_sbb16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
EORw_mask(s4, xFlags, 0, 0); // invert CC because it's reverted for SUB on ARM
|
||||
MRS_nzvc(s3);
|
||||
BFIx(s3, s4, 29, 1); // set C, bit 29
|
||||
MSR_nzvc(s3); // load CC into ARM CF
|
||||
IFNATIVE_BEFORE(NF_CF) {
|
||||
if(!INVERTED_CARRY_BEFORE) {
|
||||
if(arm64_flagm)
|
||||
CFINV();
|
||||
else {
|
||||
MRS_nzcv(s3);
|
||||
EORx_mask(s3, s3, 1, 35, 0); //mask=1<<NZCV_C
|
||||
MSR_nzcv(s3);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
EORw_mask(s4, xFlags, 0, 0); // invert CC because it's reverted for SUB on ARM
|
||||
MRS_nzcv(s3);
|
||||
BFIx(s3, s4, 29, 1); // set C, bit 29
|
||||
MSR_nzcv(s3); // load CC into ARM CF
|
||||
}
|
||||
IFX(X_AF|X_OF|X_CF) {
|
||||
MVNw_REG(s4, s1);
|
||||
ORNw_REG(s3, s2, s1); // s3 = ~op1 | op2
|
||||
BICw_REG(s4, s2, s1); // s4 = ~op1 & op2
|
||||
}
|
||||
SBCw_REG(s1, s1, s2);
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_AF|X_OF|X_CF) {
|
||||
ORRw_REG(s3, s4, s2); // s3 = ~op1 | op2
|
||||
ANDw_REG(s4, s2, s4); // s4 = ~op1 & op2
|
||||
ANDw_REG(s3, s3, s1); // s3 = (~op1 | op2) & res
|
||||
ORRw_REG(s3, s3, s4); // s3 = (~op1 & op2) | ((~op1 | op2) & res)
|
||||
IFX(X_CF) {
|
||||
LSRw(s4, s3, 15);
|
||||
BFIw(xFlags, s4, F_CF, 1); // CF : bc & 0x8000
|
||||
BFXILw(xFlags, s3, 15, 1); // CF : bc & 0x8000
|
||||
}
|
||||
IFX(X_AF) {
|
||||
LSRw(s4, s3, 3);
|
||||
@@ -1535,7 +1667,7 @@ void emit_neg32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s3, int s4
|
||||
IFX(X_AF) {
|
||||
MOVxw_REG(s3, s1);
|
||||
}
|
||||
IFX(X_ZF|X_OF) {
|
||||
IFX(X_ZF|X_OF|X_SF) {
|
||||
NEGSxw_REG(s1, s1);
|
||||
} else {
|
||||
NEGxw_REG(s1, s1);
|
||||
@@ -1544,12 +1676,16 @@ void emit_neg32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s3, int s4
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CSETw(s4, cVS);
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
IFNATIVE(NF_VF) {} else {
|
||||
CSETw(s4, cVS);
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_AF) {
|
||||
ORRxw_REG(s3, s3, s1); // bc = op1 | res
|
||||
@@ -1557,8 +1693,10 @@ void emit_neg32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s3, int s4
|
||||
BFIw(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s1, rex.w?63:31);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
IFNATIVE(NF_SF) {} else {
|
||||
LSRxw(s3, s1, rex.w?63:31);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
@@ -1582,10 +1720,9 @@ void emit_neg16(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
IFX(X_AF|X_OF) {
|
||||
MOVw_REG(s3, s1);
|
||||
}
|
||||
NEGw_REG(s1, s1);
|
||||
IFX(X_ZF) {
|
||||
NEGSw_REG(s1, s1);
|
||||
} else {
|
||||
NEGw_REG(s1, s1);
|
||||
ANDSw_mask(s1, s1, 0, 15); //mask=0xffff
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
|
||||
@@ -19,9 +19,9 @@
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "../dynarec_helper.h"
|
||||
|
||||
// emit SHL32 instruction, from s1 , shift s2, store result in s1 using s3 and s4 as scratch. s3 can be same as s2
|
||||
// emit SHL32 instruction, from s1 , shift s2, store result in s1 using s3 and s4 as scratch. s3 can be same as s2. s2 must be non-0
|
||||
void emit_shl32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s2);
|
||||
@@ -35,15 +35,6 @@ void emit_shl32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CMPSxw_U12(s2, 0);
|
||||
Bcond(cNE, +8+((dyn->insts[ninst].x64.gen_flags&X_PEND)?4:0));
|
||||
BFCw(xFlags, F_OF, 1);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
B_NEXT(cEQ);
|
||||
}
|
||||
IFX(X_CF | X_OF) {
|
||||
MOV32w(s4, rex.w?64:32);
|
||||
SUBxw_REG(s4, s4, s2);
|
||||
@@ -54,21 +45,28 @@ void emit_shl32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(s1, s1);
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s4, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CMPSxw_U12(s2, 1); // if s2==1
|
||||
IFX(X_SF) {} else {LSRxw(s4, s1, (rex.w)?63:31);}
|
||||
EORxw_REG(s4, s4, xFlags); // CF is set if OF is asked
|
||||
CSELw(s4, s4, wZR, cEQ);
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
LSRxw(s4, s1, (rex.w)?63:31);
|
||||
EORxw_REG(s3, s4, xFlags); // CF is set if OF is asked
|
||||
CSELw(s3, s3, wZR, cEQ);
|
||||
BFIw(xFlags, s3, F_OF, 1);
|
||||
}
|
||||
int need_tst = 0;
|
||||
IFX(X_ZF) need_tst = 1;
|
||||
IFXNATIVE(X_SF, NF_SF) need_tst = 1;
|
||||
if(need_tst) TSTxw_REG(s1, s1);
|
||||
IFX(X_SF) {
|
||||
IFNATIVE(NF_SF) {} else {
|
||||
IFX(X_OF) {} else {LSRxw(s4, s1, (rex.w)?63:31);}
|
||||
BFIw(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
if(box64_dynarec_test)
|
||||
IFX(X_AF) {
|
||||
@@ -92,15 +90,6 @@ void emit_shl32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, i
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(c==0) {
|
||||
IFX(X_OF) {
|
||||
BFCw(xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
IFX(X_CF|X_OF) {
|
||||
LSRxw(s3, s1, (rex.w?64:32)-c);
|
||||
BFIxw(xFlags, s3, F_CF, 1);
|
||||
@@ -110,14 +99,21 @@ void emit_shl32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, i
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
int need_tst = 0;
|
||||
IFX(X_ZF) need_tst = 1;
|
||||
IFXNATIVE(X_SF, NF_SF) need_tst = 1;
|
||||
if(need_tst) TSTxw_REG(s1, s1);
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(s1, s1);
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s4, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s4, F_SF, 1);
|
||||
IFNATIVE(NF_SF) {} else {
|
||||
LSRxw(s4, s1, (rex.w)?63:31);
|
||||
BFIw(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
@@ -171,14 +167,21 @@ void emit_shr32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
int need_tst = 0;
|
||||
IFX(X_ZF) need_tst = 1;
|
||||
IFXNATIVE(X_SF, NF_SF) need_tst = 1;
|
||||
if(need_tst) TSTxw_REG(s1, s1);
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(s1, s1);
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s4, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s4, F_SF, 1);
|
||||
IFNATIVE(NF_SF) {} else {
|
||||
LSRxw(s4, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
}
|
||||
if(box64_dynarec_test)
|
||||
IFX(X_AF) {
|
||||
@@ -220,14 +223,72 @@ void emit_shr32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, i
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
int need_tst = 0;
|
||||
IFX(X_ZF) need_tst = 1;
|
||||
IFXNATIVE(X_SF, NF_SF) need_tst = 1;
|
||||
if(need_tst) TSTxw_REG(s1, s1);
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(s1, s1);
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
// no sign if c>0
|
||||
BFCw(xFlags, F_SF, 1);
|
||||
IFNATIVE(NF_SF) {} else {
|
||||
// no sign if c>0
|
||||
BFCw(xFlags, F_SF, 1);
|
||||
}
|
||||
}
|
||||
if(box64_dynarec_test)
|
||||
IFX(X_AF) {
|
||||
BFCw(xFlags, F_AF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit SAR32 instruction, from s1 , s2, store result in s1 using s3 and s4 as scratch, s2 can be same as s3
|
||||
void emit_sar32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s2);
|
||||
int64_t j64;
|
||||
MAYUSE(j64);
|
||||
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRxw_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w?d_sar64:d_sar32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
SUBxw_U12(s3, s2, 1);
|
||||
ASRxw_REG(s3, s1, s3);
|
||||
BFIw(xFlags, s3, 0, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BFCw(xFlags, F_OF, 1);
|
||||
}
|
||||
ASRxw_REG(s1, s1, s2);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
int need_tst = 0;
|
||||
IFX(X_ZF) need_tst = 1;
|
||||
IFXNATIVE(X_SF, NF_SF) need_tst = 1;
|
||||
if(need_tst) TSTxw_REG(s1, s1);
|
||||
IFX(X_ZF) {
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
IFNATIVE(NF_SF) {} else {
|
||||
LSRxw(s4, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
}
|
||||
if(box64_dynarec_test)
|
||||
IFX(X_AF) {
|
||||
@@ -259,17 +320,24 @@ void emit_sar32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, i
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
int need_tst = 0;
|
||||
IFX(X_ZF) need_tst = 1;
|
||||
IFXNATIVE(X_SF, NF_SF) need_tst = 1;
|
||||
if(need_tst) TSTxw_REG(s1, s1);
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(s1, s1);
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s4, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s4, F_SF, 1);
|
||||
IFNATIVE(NF_SF) {} else {
|
||||
LSRxw(s4, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_OF)
|
||||
if(c==1) {
|
||||
if(c==1 || box64_dynarec_test) {
|
||||
BFCw(xFlags, F_OF, 1);
|
||||
}
|
||||
if(box64_dynarec_test)
|
||||
@@ -305,14 +373,14 @@ void emit_shl8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
COMP_ZFSF(s1, 8)
|
||||
IFX(X_OF) {
|
||||
CMPSw_U12(s2, 1); // if s2==1
|
||||
IFX2(X_SF, && !arm64_flagm) {} else {LSRw(s3, s1, 7);}
|
||||
LSRw(s3, s1, 7);
|
||||
EORw_REG(s4, s3, xFlags); // CF is set if OF is asked
|
||||
CSELw(s4, s4, wZR, cEQ);
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
COMP_ZFSF(s1, 8)
|
||||
if(box64_dynarec_test)
|
||||
IFX(X_AF) {
|
||||
BFCw(xFlags, F_AF, 1);
|
||||
@@ -347,7 +415,7 @@ void emit_shl8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s
|
||||
COMP_ZFSF(s1, 8)
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
IFX2(X_SF, && !arm64_flagm) {} else {LSRw(s3, s1, 7);}
|
||||
IFX2(X_SF, && !arm64_flagm) {} else {LSRw(s3, s1, 7);} //use COMP_ZFSF operation
|
||||
EORw_REG(s4, s3, xFlags); // CF is set if OF is asked
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
} else {
|
||||
@@ -361,29 +429,35 @@ void emit_shl8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
} else {
|
||||
IFXNATIVE(X_ZF|X_SF|X_CF, NF_EQ|NF_SF|NF_CF) {
|
||||
SUBSw_REG(s1, s1, s1);
|
||||
} else {
|
||||
MOVw_REG(s1, xZR);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF) {
|
||||
LSLw(s3, s1, c-1);
|
||||
BFXILw(xFlags, s3, 7, 1); // insert F_CF from s3[7:1]
|
||||
// sub X, X will generate a carry flags
|
||||
IFNATIVE(NF_CF) {GEN_INVERTED_CARRY();} else {BFCw(xFlags, F_CF, 1);}
|
||||
}
|
||||
MOVw_REG(s1, xZR);
|
||||
IFX(X_OF) {
|
||||
BFCw(xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
BFCw(xFlags, F_SF, 1);
|
||||
IFNATIVE(NF_SF) {} else BFCw(xFlags, F_SF, 1);
|
||||
}
|
||||
if(box64_dynarec_test) IFX(X_AF) {
|
||||
BFCw(xFlags, F_AF, 1);
|
||||
}
|
||||
IFX(X_PF | X_ZF) {
|
||||
MOV32w(s3, 1);
|
||||
IFX(X_ZF) {
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
BFIw(xFlags, s3, F_PF, 1);
|
||||
IFX(X_ZF) {
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
ORRw_mask(xFlags, xFlags, 26, 0); //1<<F_ZF
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
ORRw_mask(xFlags, xFlags, 30, 0); //1<<F_PF
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -487,8 +561,8 @@ void emit_sar8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
COMP_ZFSF(s1, 8)
|
||||
IFX(X_OF) {
|
||||
CMPSw_U12(s2, 1);
|
||||
Bcond(cNE, 4+4);
|
||||
SUBw_U12(s4, s2, 1);
|
||||
CBNZw(s4, 4+4);
|
||||
BFCw(xFlags, F_OF, 1);
|
||||
}
|
||||
if(box64_dynarec_test)
|
||||
@@ -513,8 +587,7 @@ void emit_sar8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(c<8) IFX(X_CF) {
|
||||
ASRw(s3, s1, c-1);
|
||||
BFIw(xFlags, s3, 0, 1);
|
||||
BFXILw(xFlags, s1, c-1, 1);
|
||||
}
|
||||
ASRw(s1, s1, c);
|
||||
IFX(X_PEND) {
|
||||
@@ -530,13 +603,18 @@ void emit_sar8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
} else {
|
||||
LSRw(s3, s1, 7);
|
||||
BFIw(xFlags, s3, F_CF, 1);
|
||||
BFIw(wFlags, s3, F_SF, 1);
|
||||
EORw_mask(s3, s3, 0, 0); //1
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
MOV32w(s3, 1);
|
||||
BFIw(xFlags, s3, F_PF, 1);
|
||||
IFX(X_CF|X_ZF|X_SF|X_PF) {
|
||||
LSRw(s3, s1, 7);
|
||||
IFX(X_CF){ BFIw(xFlags, s3, F_CF, 1); }
|
||||
IFX(X_SF){ BFIw(wFlags, s3, F_SF, 1); }
|
||||
IFX(X_ZF) {
|
||||
EORw_mask(s3, s3, 0, 0); //1
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
ORRw_mask(xFlags, xFlags, 30, 0); //1<<F_PF
|
||||
}
|
||||
}
|
||||
}
|
||||
if(box64_dynarec_test)
|
||||
IFX(X_AF) {
|
||||
@@ -564,14 +642,14 @@ void emit_shl16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
COMP_ZFSF(s1, 16)
|
||||
IFX(X_OF) {
|
||||
CMPSw_U12(s2, 1); // if s2==1
|
||||
IFX2(X_SF, && !arm64_flagm) {} else {LSRw(s3, s1, 15);}
|
||||
LSRw(s3, s1, 15);
|
||||
EORw_REG(s4, s3, xFlags); // CF is set if OF is asked
|
||||
CSELw(s4, s4, wZR, cEQ);
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
COMP_ZFSF(s1, 16)
|
||||
if(box64_dynarec_test)
|
||||
IFX(X_AF) {
|
||||
BFCw(xFlags, F_AF, 1);
|
||||
@@ -606,7 +684,7 @@ void emit_shl16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int
|
||||
COMP_ZFSF(s1, 16)
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
IFX2(X_SF, && !arm64_flagm) {} else {LSRw(s3, s1, 15);}
|
||||
IFX2(X_SF, && !arm64_flagm) {} else {LSRw(s3, s1, 15);} // use COMP_ZFSF operation
|
||||
EORw_REG(s4, s3, xFlags); // CF is set if OF is asked
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
} else {
|
||||
@@ -619,32 +697,40 @@ void emit_shl16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int
|
||||
IFX(X_PF) {
|
||||
if(c>7) {
|
||||
// the 0xff area will be 0, so PF is known
|
||||
MOV32w(s3, 1);
|
||||
BFIw(xFlags, s3, F_PF, 1);
|
||||
ORRw_mask(xFlags, xFlags, 30, 0); //1<<F_PF
|
||||
} else
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
} else {
|
||||
IFX(X_CF) {
|
||||
LSLw(s3, s1, c-1);
|
||||
BFXILw(xFlags, s3, 15, 1); // insert F_CF from s3[15:1]
|
||||
IFXNATIVE(X_ZF|X_SF|X_CF, NF_EQ|NF_SF|NF_CF) {
|
||||
SUBSw_REG(s1, s1, s1);
|
||||
} else {
|
||||
MOVw_REG(s1, xZR);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
MOVw_REG(s1, xZR);
|
||||
IFX(X_OF) {
|
||||
BFCw(xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
BFCw(xFlags, F_SF, 1);
|
||||
IFX(X_CF) {
|
||||
// sub X, X will generate a carry flags
|
||||
IFNATIVE(NF_CF) {GEN_INVERTED_CARRY();} else {BFCw(xFlags, F_CF, 1);}
|
||||
}
|
||||
IFX(X_PF | X_ZF) {
|
||||
MOV32w(s3, 1);
|
||||
IFX(X_ZF) {
|
||||
BFIw(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
BFIw(xFlags, s3, F_PF, 1);
|
||||
IFX(X_SF) {
|
||||
IFNATIVE(NF_SF) {} else BFCw(xFlags, F_SF, 1);
|
||||
}
|
||||
if(box64_dynarec_test) IFX(X_AF) {
|
||||
BFCw(xFlags, F_AF, 1);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
ORRw_mask(xFlags, xFlags, 26, 0); //1<<F_ZF
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
ORRw_mask(xFlags, xFlags, 30, 0); //1<<F_PF
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -664,8 +750,8 @@ void emit_shr16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
BFIw(xFlags, s4, 0, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CMPSw_U12(s2, 1); // if s2==1
|
||||
Bcond(cNE, 4+2*4);
|
||||
SUBw_U12(s4, s2, 1); // if s2==1
|
||||
CBNZw(s4, 4+2*4);
|
||||
LSRw(s4, s1, 15);
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
@@ -743,12 +829,12 @@ void emit_sar16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
COMP_ZFSF(s1, 16)
|
||||
IFX(X_OF) {
|
||||
CMPSw_U12(s2, 1);
|
||||
Bcond(cNE, 4+4);
|
||||
SUBw_U12(s4, s2, 1);
|
||||
CBNZw(s4, 4+4);
|
||||
BFCw(xFlags, F_OF, 1);
|
||||
}
|
||||
COMP_ZFSF(s1, 16)
|
||||
if(box64_dynarec_test)
|
||||
IFX(X_AF) {
|
||||
BFCw(xFlags, F_AF, 1);
|
||||
@@ -798,29 +884,15 @@ void emit_rol32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, i
|
||||
|
||||
if (!c) return;
|
||||
|
||||
IFX(X_PEND) {
|
||||
MOV32w(s3, c);
|
||||
STRxw_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w?d_rol64:d_rol32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(!c) {
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
SET_DFNONE(s4);
|
||||
|
||||
RORxw(s1, s1, (rex.w?64:32)-c);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF) {
|
||||
BFIw(xFlags, s1, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
ADDxw_REG_LSR(s3, s1, s1, rex.w?63:31);
|
||||
EORxw_REG_LSR(s3, s1, s1, rex.w?63:31);
|
||||
BFIw(xFlags, s3, F_OF, 1);
|
||||
}
|
||||
}
|
||||
@@ -833,23 +905,9 @@ void emit_ror32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, i
|
||||
|
||||
if (!c) return;
|
||||
|
||||
IFX(X_PEND) {
|
||||
MOV32w(s3, c);
|
||||
STRxw_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w?d_ror64:d_ror32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(!c) {
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
SET_DFNONE(s4);
|
||||
|
||||
RORxw(s1, s1, c);
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF) {
|
||||
BFXILxw(xFlags, s1, rex.w?63:31, 1);
|
||||
}
|
||||
@@ -869,21 +927,13 @@ void emit_rol8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s
|
||||
|
||||
if (!c) return;
|
||||
|
||||
IFX(X_PEND) {
|
||||
MOV32w(s3, c);
|
||||
STRB_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, d_rol8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
SET_DFNONE(s4);
|
||||
|
||||
if(c&7) {
|
||||
int rc = 8-(c&7);
|
||||
ORRw_REG_LSL(s1, s1, s1, 8);
|
||||
LSRw(s1, s1, rc);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF) {
|
||||
BFIw(xFlags, s1, F_CF, 1);
|
||||
}
|
||||
@@ -902,20 +952,12 @@ void emit_ror8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s
|
||||
|
||||
if (!c) return;
|
||||
|
||||
IFX(X_PEND) {
|
||||
MOV32w(s3, c);
|
||||
STRB_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, d_ror8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
SET_DFNONE(s4);
|
||||
|
||||
if(c&7) {
|
||||
ORRw_REG_LSL(s1, s1, s1, 8);
|
||||
LSRw(s1, s1, c&7);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF) {
|
||||
BFXILw(xFlags, s1, 7, 1);
|
||||
}
|
||||
@@ -935,21 +977,13 @@ void emit_rol16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int
|
||||
|
||||
if (!c) return;
|
||||
|
||||
IFX(X_PEND) {
|
||||
MOV32w(s3, c);
|
||||
STRH_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, d_rol16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
SET_DFNONE(s4);
|
||||
|
||||
if(c&15) {
|
||||
int rc = 16-(c&15);
|
||||
ORRw_REG_LSL(s1, s1, s1, 16);
|
||||
LSRw(s1, s1, rc);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF) {
|
||||
BFIw(xFlags, s1, F_CF, 1);
|
||||
}
|
||||
@@ -968,20 +1002,12 @@ void emit_ror16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int
|
||||
|
||||
if (!c) return;
|
||||
|
||||
IFX(X_PEND) {
|
||||
MOV32w(s3, c);
|
||||
STRH_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, d_ror16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
SET_DFNONE(s4);
|
||||
|
||||
if(c&15) {
|
||||
ORRw_REG_LSL(s1, s1, s1, 16);
|
||||
LSRw(s1, s1, c&15);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF) {
|
||||
BFXILw(xFlags, s1, 15, 1);
|
||||
}
|
||||
@@ -1014,9 +1040,6 @@ void emit_rcl8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s
|
||||
}
|
||||
ORRw_REG_LSL(s1, s1, s1, 9); // insert s1 again
|
||||
LSRw_IMM(s1, s1, 9-c); // do the rcl
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_OF|X_CF) {
|
||||
IFX(X_CF) {
|
||||
BFIw(xFlags, s3, F_CF, 1);
|
||||
@@ -1057,9 +1080,6 @@ void emit_rcr8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s
|
||||
BFIw(xFlags, s3, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
}
|
||||
|
||||
// emit RCL16 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
@@ -1082,9 +1102,6 @@ void emit_rcl16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int
|
||||
}
|
||||
ORRx_REG_LSL(s1, s1, s1, 17); // insert s1 again
|
||||
LSRx_IMM(s1, s1, 17-c); // do the rcl
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF) {
|
||||
BFIw(xFlags, s3, F_CF, 1);
|
||||
}
|
||||
@@ -1123,9 +1140,6 @@ void emit_rcr16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int
|
||||
BFIw(xFlags, s3, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
}
|
||||
|
||||
// emit RCL32/RCL64 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
@@ -1133,6 +1147,8 @@ void emit_rcl32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, i
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s3); MAYUSE(s4);
|
||||
|
||||
if(!c) return;
|
||||
|
||||
SET_DFNONE(s4);
|
||||
|
||||
IFX(X_OF|X_CF) {
|
||||
@@ -1146,9 +1162,6 @@ void emit_rcl32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, i
|
||||
BFIxw(s4, xFlags, c-1, 1);
|
||||
ORRxw_REG_LSR(s1, s4, s1, (rex.w?65:33)-c);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_CF) {
|
||||
BFIw(xFlags, s3, F_CF, 1);
|
||||
}
|
||||
@@ -1164,6 +1177,8 @@ void emit_rcr32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, i
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s3); MAYUSE(s4);
|
||||
|
||||
if(!c) return;
|
||||
|
||||
SET_DFNONE(s4);
|
||||
|
||||
IFX(X_OF) {
|
||||
@@ -1186,9 +1201,6 @@ void emit_rcr32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, i
|
||||
IFX(X_CF) {
|
||||
BFIw(wFlags, s3, 0, 1);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
}
|
||||
|
||||
// emit SHRD32 instruction, from s1, fill s2 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
@@ -1213,7 +1225,7 @@ void emit_shrd32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, uint
|
||||
BFXILxw(xFlags, s1, c-1, 1); // set CF
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
if((c==1) || box64_dynarec_test) {
|
||||
LSRxw(s4, s1, rex.w?63:31);
|
||||
BFIw(xFlags, s4, F_OF, 1); // store sign for later use
|
||||
}
|
||||
@@ -1222,14 +1234,21 @@ void emit_shrd32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, uint
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
int need_tst = 0;
|
||||
IFX(X_ZF) need_tst = 1;
|
||||
IFXNATIVE(X_SF, NF_SF) need_tst = 1;
|
||||
if(need_tst) TSTxw_REG(s1, s1);
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(s1, s1);
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s4, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s4, F_SF, 1);
|
||||
IFNATIVE(NF_SF) {} else {
|
||||
LSRxw(s4, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
@@ -1263,8 +1282,7 @@ void emit_shld32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, uint
|
||||
return;
|
||||
}
|
||||
IFX(X_CF) {
|
||||
LSRxw(s3, s1, (rex.w?64:32)-c);
|
||||
BFIxw(xFlags, s3, F_CF, 1);
|
||||
BFXILx(xFlags, s1, (rex.w?64:32)-c, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
LSRxw(s3, s1, rex.w?63:31);
|
||||
@@ -1325,18 +1343,25 @@ void emit_shrd32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
int need_tst = 0;
|
||||
IFX(X_ZF) need_tst = 1;
|
||||
IFXNATIVE(X_SF, NF_SF) need_tst = 1;
|
||||
if(need_tst) TSTxw_REG(s1, s1);
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(s1, s1);
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s4, s1, (rex.w)?63:31);
|
||||
BFIw(xFlags, s4, F_SF, 1);
|
||||
IFNATIVE(NF_SF) {} else {
|
||||
LSRxw(s4, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CMPSw_U12(s5, 1);
|
||||
Bcond(cNE, 4+2*4);
|
||||
SUBw_U12(s3, s5, 1);
|
||||
CBNZw(s3, 4+2*4); //flagless jump
|
||||
UBFXx(s3, s1, rex.w?63:31, 1);
|
||||
EORw_REG_LSL(xFlags, xFlags, s3, F_OF); // OF is set if sign changed
|
||||
}
|
||||
@@ -1371,18 +1396,25 @@ void emit_shld32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
IFX(X_PEND) {
|
||||
STRxw_U12(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
int need_tst = 0;
|
||||
IFX(X_ZF) need_tst = 1;
|
||||
IFXNATIVE(X_SF, NF_SF) need_tst = 1;
|
||||
if(need_tst) TSTxw_REG(s1, s1);
|
||||
IFX(X_ZF) {
|
||||
TSTxw_REG(s1, s1);
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s4, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s4, F_SF, 1);
|
||||
IFNATIVE(NF_SF) {} else {
|
||||
LSRxw(s4, s1, (rex.w)?63:31);
|
||||
BFIx(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CMPSw_U12(s5, 1);
|
||||
Bcond(cNE, 4+2*4);
|
||||
SUBw_U12(s3, s5, 1);
|
||||
CBNZw(s3, 4+2*4); //flagless jump
|
||||
UBFXx(s3, s1, rex.w?63:31, 1);
|
||||
EORw_REG_LSL(xFlags, xFlags, s3, F_OF); // OF is set if sign changed
|
||||
}
|
||||
@@ -1462,8 +1494,8 @@ void emit_shrd16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s5, int s3,
|
||||
}
|
||||
COMP_ZFSF(s1, 16)
|
||||
IFX(X_OF) {
|
||||
CMPSw_U12(s5, 1);
|
||||
Bcond(cNE, 4+2*4);
|
||||
SUBw_U12(s3, s5, 1);
|
||||
CBNZw(s3, 4+2*4);
|
||||
UBFXw(s3, s1, 15, 1);
|
||||
EORw_REG_LSL(xFlags, xFlags, s3, F_OF); // OF is set if sign changed
|
||||
}
|
||||
@@ -1553,8 +1585,8 @@ void emit_shld16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s5, int s3,
|
||||
}
|
||||
COMP_ZFSF(s1, 16)
|
||||
IFX(X_OF) {
|
||||
CMPSw_U12(s5, 1);
|
||||
Bcond(cNE, 4+2*4);
|
||||
SUBw_U12(s3, s5, 1);
|
||||
CBNZw(s3, 4+2*4);
|
||||
UBFXw(s3, s1, 15, 1);
|
||||
EORw_REG_LSL(xFlags, xFlags, s3, F_OF); // OF is set if sign changed
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "../dynarec_helper.h"
|
||||
|
||||
// emit CMP32 instruction, from cmp s1, s2, using s3 and s4 as scratch
|
||||
void emit_cmp32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5)
|
||||
@@ -47,21 +47,31 @@ void emit_cmp32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
BFIx(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_CF) {
|
||||
// inverted carry
|
||||
CSETw(s4, cCC);
|
||||
BFIw(xFlags, s4, F_CF, 1);
|
||||
IFNATIVE(NF_CF) {
|
||||
GEN_INVERTED_CARRY();
|
||||
} else {
|
||||
CSETw(s4, cCC);
|
||||
BFIw(xFlags, s4, F_CF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CSETw(s4, cVS);
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
IFNATIVE(NF_VF) {} else {
|
||||
CSETw(s4, cVS);
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s5, (rex.w)?63:31);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
IFNATIVE(NF_SF) {} else {
|
||||
LSRxw(s3, s5, (rex.w)?63:31);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s5, s4);
|
||||
@@ -83,17 +93,32 @@ void emit_cmp32_0(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s3, int
|
||||
SUBSxw_U12(s3, s1, 0); // res = s1 - 0
|
||||
// and now the tricky ones (and mostly unused), PF and AF
|
||||
// bc = (res & (~d | s)) | (~d & s) => is 0 here...
|
||||
IFX(X_OF|X_AF|X_CF) {
|
||||
MOV32w(s4, (1<<F_OF)|(1<<F_AF)|(1<<F_CF));
|
||||
BICw(xFlags, xFlags, s4);
|
||||
IFX(X_CF) {
|
||||
IFNATIVE(NF_CF) {
|
||||
GEN_INVERTED_CARRY();
|
||||
} else {
|
||||
BFCw(xFlags, F_CF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_OF) {
|
||||
IFNATIVE(NF_VF) {} else {
|
||||
BFCw(xFlags, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_AF) {
|
||||
BFCw(xFlags, F_AF, 1);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
IFNATIVE(NF_SF) {} else {
|
||||
LSRxw(s3, s1, (rex.w)?63:31);
|
||||
BFIw(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
@@ -111,31 +136,60 @@ void emit_cmp16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, i
|
||||
} else {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
SUBw_REG(s5, s1, s2); // res = s1 - s2
|
||||
IFX_PENDOR0 {
|
||||
STRH_U12(s5, xEmu, offsetof(x64emu_t, res));
|
||||
IFX(X_AF) {
|
||||
ORNw_REG(s3, s2, s1); // s3 = ~op1 | op2
|
||||
BICw(s4, s2, s1); // s4 = ~op1 & op2
|
||||
}
|
||||
COMP_ZFSF(s5, 16)
|
||||
// bc = (res & (~d | s)) | (~d & s)
|
||||
IFX(X_CF|X_AF|X_OF) {
|
||||
MVNw_REG(s4, s1); // s4 = ~d
|
||||
ORRw_REG(s4, s4, s2); // s4 = ~d | s
|
||||
ANDw_REG(s4, s4, s5); // s4 = res & (~d | s)
|
||||
BICw_REG(s3, s2, s1); // s3 = s & ~d
|
||||
ORRw_REG(s3, s4, s3); // s3 = (res & (~d | s)) | (s & ~d)
|
||||
IFX(X_CF) {
|
||||
LSRw(s4, s3, 15);
|
||||
BFIw(xFlags, s4, F_CF, 1); // CF : bc & 0x8000
|
||||
}
|
||||
IFX(X_CF|X_ZF|X_SF|X_OF) {
|
||||
LSLw(s5, s1, 16);
|
||||
SUBSw_REG_LSL(s5, s5, s2, 16);
|
||||
IFX(X_AF) {
|
||||
ANDw_REG_LSR(s3, s3, s5, 16); // s3 = (~op1 | op2) & res
|
||||
ORRw_REG(s3, s3, s4); // s3 = (~op1 & op2) | ((~op1 | op2) & res)
|
||||
LSRw(s4, s3, 3);
|
||||
BFIw(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
BFIx(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_CF) {
|
||||
// inverted carry
|
||||
IFNATIVE(NF_CF) {
|
||||
GEN_INVERTED_CARRY();
|
||||
} else {
|
||||
CSETw(s4, cCC);
|
||||
BFIw(xFlags, s4, F_CF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_OF) {
|
||||
LSRw(s4, s3, 14);
|
||||
EORw_REG_LSR(s4, s4, s4, 1);
|
||||
BFIw(xFlags, s4, F_OF, 1); // OF: ((bc >> 14) ^ ((bc>>14)>>1)) & 1
|
||||
IFNATIVE(NF_VF) {} else {
|
||||
CSETw(s4, cVS);
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
IFNATIVE(NF_SF) {} else {
|
||||
CSETw(s4, cMI);
|
||||
BFIw(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF|X_PEND) {
|
||||
LSRw(s5, s5, 16);
|
||||
}
|
||||
} else {
|
||||
SUBw_REG(s5, s1, s2); // res = s1 - s2
|
||||
IFX(X_AF) {
|
||||
ANDw_REG(s3, s3, s5); // s3 = (~op1 | op2) & res
|
||||
ORRw_REG(s3, s3, s4); // s3 = (~op1 & op2) | ((~op1 | op2) & res)
|
||||
LSRw(s4, s3, 3);
|
||||
BFIx(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
}
|
||||
}
|
||||
IFX_PENDOR0 {
|
||||
STRH_U12(s5, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s5, s4);
|
||||
@@ -171,34 +225,64 @@ void emit_cmp8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, in
|
||||
IFX_PENDOR0 {
|
||||
STRB_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRB_U12(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, d_cmp8);
|
||||
SET_DF(s3, d_cmp8);
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
SUBw_REG(s5, s1, s2); // res = s1 - s2
|
||||
IFX_PENDOR0 {
|
||||
STRB_U12(s5, xEmu, offsetof(x64emu_t, res));
|
||||
IFX(X_AF) {
|
||||
ORNw_REG(s3, s2, s1); // s3 = ~op1 | op2
|
||||
BICw(s4, s2, s1); // s4 = ~op1 & op2
|
||||
}
|
||||
COMP_ZFSF(s5, 8)
|
||||
// bc = (res & (~d | s)) | (~d & s)
|
||||
IFX(X_CF|X_AF|X_OF) {
|
||||
ORNw_REG(s4, s2, s1); // s4 = ~d | s
|
||||
ANDw_REG(s4, s4, s5); // s4 = res & (~d | s)
|
||||
BICw_REG(s3, s2, s1); // s3 = s & ~d
|
||||
ORRw_REG(s3, s4, s3); // s3 = (res & (~d | s)) | (s & ~d)
|
||||
IFX(X_CF) {
|
||||
LSRw(s4, s3, 7);
|
||||
BFIw(xFlags, s4, F_CF, 1); // CF : bc & 0x80
|
||||
}
|
||||
IFX(X_CF|X_ZF|X_SF|X_OF) {
|
||||
LSLw(s5, s1, 24);
|
||||
SUBSw_REG_LSL(s5, s5, s2, 24);
|
||||
IFX(X_AF) {
|
||||
ANDw_REG_LSR(s3, s3, s5, 24); // s3 = (~op1 | op2) & res
|
||||
ORRw_REG(s3, s3, s4); // s3 = (~op1 & op2) | ((~op1 | op2) & res)
|
||||
LSRw(s4, s3, 3);
|
||||
BFIw(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
BFIx(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_CF) {
|
||||
// inverted carry
|
||||
IFNATIVE(NF_CF) {
|
||||
GEN_INVERTED_CARRY();
|
||||
} else {
|
||||
CSETw(s4, cCC);
|
||||
BFIw(xFlags, s4, F_CF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_OF) {
|
||||
LSRw(s4, s3, 6);
|
||||
EORw_REG_LSR(s4, s4, s4, 1);
|
||||
BFIw(xFlags, s4, F_OF, 1); // OF: ((bc >> 6) ^ ((bc>>6)>>1)) & 1
|
||||
IFNATIVE(NF_VF) {} else {
|
||||
CSETw(s4, cVS);
|
||||
BFIw(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
IFNATIVE(NF_SF) {} else {
|
||||
CSETw(s4, cMI);
|
||||
BFIw(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF|X_PEND) {
|
||||
LSRw(s5, s5, 24);
|
||||
}
|
||||
} else {
|
||||
SUBw_REG(s5, s1, s2); // res = s1 - s2
|
||||
IFX(X_AF) {
|
||||
ANDw_REG(s3, s3, s5); // s3 = (~op1 | op2) & res
|
||||
ORRw_REG(s3, s3, s4); // s3 = (~op1 & op2) | ((~op1 | op2) & res)
|
||||
LSRw(s4, s3, 3);
|
||||
BFIx(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
}
|
||||
}
|
||||
IFX_PENDOR0 {
|
||||
STRB_U12(s5, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s5, s4);
|
||||
@@ -236,21 +320,83 @@ void emit_test32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
IFX(X_CF) {
|
||||
IFNATIVE(NF_CF) {} else {
|
||||
BFCw(xFlags, F_CF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_OF) {
|
||||
IFNATIVE(NF_VF) {} else {
|
||||
BFCw(xFlags, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_AF) {
|
||||
BFCw(xFlags, F_AF, 1);
|
||||
}
|
||||
ANDSxw_REG(s3, s1, s2); // res = s1 & s2
|
||||
IFX_PENDOR0 {
|
||||
STRxw_U12(s3, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRxw(s4, s3, rex.w?63:31);
|
||||
BFIw(xFlags, s4, F_SF, 1);
|
||||
IFNATIVE(NF_SF) {} else {
|
||||
LSRxw(s4, s3, rex.w?63:31);
|
||||
BFIw(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s3, s5);
|
||||
}
|
||||
}
|
||||
|
||||
// emit TEST32 instruction, from test s1, s2, using s3, s4 and s5 as scratch
|
||||
void emit_test32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4, int s5)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s3); MAYUSE(s4);
|
||||
int mask = convert_bitmask_xw(c);
|
||||
IFX_PENDOR0 {
|
||||
SET_DF(s3, rex.w?d_tst64:d_tst32);
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
IFNATIVE(NF_CF) {} else {
|
||||
BFCw(xFlags, F_CF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_OF) {
|
||||
IFNATIVE(NF_VF) {} else {
|
||||
BFCw(xFlags, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_AF) {
|
||||
BFCw(xFlags, F_AF, 1);
|
||||
}
|
||||
if(mask) {
|
||||
ANDSxw_mask(s3, s1, (mask>>12)&1, mask&0x3F, (mask>>6)&0x3F);
|
||||
} else {
|
||||
MOV64xw(s3, c);
|
||||
ANDSxw_REG(s3, s1, s3); // res = s1 & s2
|
||||
}
|
||||
IFX_PENDOR0 {
|
||||
STRxw_U12(s3, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
IFNATIVE(NF_SF) {} else {
|
||||
LSRxw(s4, s3, rex.w?63:31);
|
||||
BFIw(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s3, s5);
|
||||
@@ -266,21 +412,98 @@ void emit_test16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4,
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
IFX(X_CF|X_ZF|X_SF|X_OF) {
|
||||
LSLw(s5, s1, 16);
|
||||
ANDSw_REG_LSL(s5, s5, s2, 16);
|
||||
IFX(X_ZF) {
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_CF) {
|
||||
IFNATIVE(NF_CF) {} else {BFCw(xFlags, F_CF, 1);}
|
||||
}
|
||||
IFX(X_OF) {
|
||||
IFNATIVE(NF_VF) {} else {BFCw(xFlags, F_OF, 1);}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
IFNATIVE(NF_SF) {} else {
|
||||
CSETw(s4, cMI);
|
||||
BFIw(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF|X_PEND) {
|
||||
LSRw(s5, s5, 16);
|
||||
}
|
||||
} else {
|
||||
ANDw_REG(s5, s1, s2); // res = s1 & s2
|
||||
}
|
||||
IFX(X_AF) {
|
||||
BFCw(xFlags, F_AF, 1);
|
||||
}
|
||||
ANDSw_REG(s5, s1, s2); // res = s1 & s2
|
||||
IFX_PENDOR0 {
|
||||
STRH_U12(s5, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s5, s4);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s4, s5, 15);
|
||||
BFIw(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
|
||||
// emit TEST16 instruction, from test s1, s2, using s3, s4 and s5 as scratch
|
||||
void emit_test16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4, int s5)
|
||||
{
|
||||
MAYUSE(s1);
|
||||
int mask = 0;
|
||||
IFX_PENDOR0 {
|
||||
SET_DF(s3, d_tst16);
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_CF|X_ZF|X_SF|X_OF) {
|
||||
LSLw(s5, s1, 16);
|
||||
mask = convert_bitmask_w(c<<16);
|
||||
if(mask) {
|
||||
ANDSw_mask(s5, s5, mask&0x3F, (mask>>6)&0x3F);
|
||||
} else {
|
||||
MOV32w(s3, c);
|
||||
ANDSw_REG_LSL(s5, s5, s3, 16);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_CF) {
|
||||
IFNATIVE(NF_CF) {} else {BFCw(xFlags, F_CF, 1);}
|
||||
}
|
||||
IFX(X_OF) {
|
||||
IFNATIVE(NF_VF) {} else {BFCw(xFlags, F_OF, 1);}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
IFNATIVE(NF_SF) {} else {
|
||||
CSETw(s4, cMI);
|
||||
BFIw(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF|X_PEND) {
|
||||
LSRw(s5, s5, 16);
|
||||
}
|
||||
} else {
|
||||
mask = convert_bitmask_w(c);
|
||||
if(mask) {
|
||||
ANDw_mask(s5, s1, mask&0x3F, (mask>>6)&0x3F);
|
||||
} else {
|
||||
MOV32w(s5, c);
|
||||
ANDw_REG(s5, s1, s5); // res = s1 & s2
|
||||
}
|
||||
}
|
||||
IFX(X_AF) {
|
||||
BFCw(xFlags, F_AF, 1);
|
||||
}
|
||||
IFX_PENDOR0 {
|
||||
STRH_U12(s5, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s5, s4);
|
||||
@@ -296,22 +519,99 @@ void emit_test8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, i
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_CF | X_AF | X_OF) {
|
||||
MOV32w(s3, (1<<F_CF)|(1<<F_AF)|(1<<F_OF));
|
||||
BICw(xFlags, xFlags, s3);
|
||||
IFX(X_CF|X_ZF|X_SF|X_OF) {
|
||||
LSLw(s5, s1, 24);
|
||||
ANDSw_REG_LSL(s5, s5, s2, 24);
|
||||
IFX(X_ZF) {
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_CF) {
|
||||
IFNATIVE(NF_CF) {} else {BFCw(xFlags, F_CF, 1);}
|
||||
}
|
||||
IFX(X_OF) {
|
||||
IFNATIVE(NF_VF) {} else {BFCw(xFlags, F_OF, 1);}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
IFNATIVE(NF_SF) {} else {
|
||||
CSETw(s4, cMI);
|
||||
BFIw(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF|X_PEND) {
|
||||
LSRw(s5, s5, 24);
|
||||
}
|
||||
} else {
|
||||
ANDw_REG(s5, s1, s2); // res = s1 & s2
|
||||
}
|
||||
IFX(X_AF) {
|
||||
BFCw(xFlags, F_AF, 1);
|
||||
}
|
||||
IFX_PENDOR0 {
|
||||
STRB_U12(s5, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s5, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit TEST8 instruction, from test s1, s2, using s3, s4 and s5 as scratch
|
||||
void emit_test8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4, int s5)
|
||||
{
|
||||
MAYUSE(s1);
|
||||
int mask = 0;
|
||||
IFX_PENDOR0 {
|
||||
SET_DF(s3, d_tst8);
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_CF|X_ZF|X_SF|X_OF) {
|
||||
LSLw(s5, s1, 24);
|
||||
mask = convert_bitmask_w(c<<24);
|
||||
if(mask) {
|
||||
ANDSw_mask(s5, s5, mask&0x3F, (mask>>6)&0x3F);
|
||||
} else {
|
||||
MOV32w(s3, c);
|
||||
ANDSw_REG_LSL(s5, s5, s3, 24);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_CF) {
|
||||
IFNATIVE(NF_CF) {} else {BFCw(xFlags, F_CF, 1);}
|
||||
}
|
||||
IFX(X_OF) {
|
||||
IFNATIVE(NF_VF) {} else {BFCw(xFlags, F_OF, 1);}
|
||||
}
|
||||
IFX(X_SF) {
|
||||
IFNATIVE(NF_SF) {} else {
|
||||
CSETw(s4, cMI);
|
||||
BFIw(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF|X_PEND) {
|
||||
LSRw(s5, s5, 24);
|
||||
}
|
||||
} else {
|
||||
mask = convert_bitmask_w(c);
|
||||
if(mask) {
|
||||
ANDw_mask(s5, s1, mask&0x3F, (mask>>6)&0x3F);
|
||||
} else {
|
||||
MOV32w(s5, c);
|
||||
ANDw_REG(s5, s1, s5); // res = s1 & s2
|
||||
}
|
||||
}
|
||||
IFX(X_AF) {
|
||||
BFCw(xFlags, F_AF, 1);
|
||||
}
|
||||
ANDSw_REG(s5, s1, s2); // res = s1 & s2
|
||||
IFX_PENDOR0 {
|
||||
STRB_U12(s5, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
CSETw(s4, cEQ);
|
||||
BFIw(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
LSRw(s4, s5, 7);
|
||||
BFIw(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s5, s4);
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "../dynarec_helper.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
|
||||
|
||||
@@ -62,12 +62,12 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETGB(x2);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(rex.rex) {
|
||||
wback = xRAX + (nextop&7) + (rex.b<<3);
|
||||
wback = TO_NAT((nextop & 0x07) + (rex.b << 3));
|
||||
wb2 = 0;
|
||||
} else {
|
||||
wback = (nextop&7);
|
||||
wb2 = (wback>>2);
|
||||
wback = xRAX+(wback&3);
|
||||
wback = TO_NAT(wback & 3);
|
||||
}
|
||||
UBFXw(x1, wback, wb2*8, 8);
|
||||
emit_add8(dyn, ninst, x1, x2, x4, x3);
|
||||
@@ -96,8 +96,8 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
if(MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
emit_add32(dyn, ninst, rex, ed, gd, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
@@ -149,12 +149,12 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETGB(x2);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(rex.rex) {
|
||||
wback = xRAX + (nextop&7) + (rex.b<<3);
|
||||
wback = TO_NAT((nextop & 0x07) + (rex.b << 3));
|
||||
wb2 = 0;
|
||||
} else {
|
||||
wback = (nextop&7);
|
||||
wb2 = (wback>>2);
|
||||
wback = xRAX+(wback&3);
|
||||
wback = TO_NAT(wback & 3);
|
||||
}
|
||||
UBFXw(x1, wback, wb2*8, 8);
|
||||
emit_or8(dyn, ninst, x1, x2, x4, x3);
|
||||
@@ -182,7 +182,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
emit_or32(dyn, ninst, rex, ed, gd, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
@@ -213,7 +213,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
wback = 0;
|
||||
if(rex.w) {
|
||||
ANDx_mask(x2, gd, 1, 0, 0b00101); //mask=0x000000000000003f
|
||||
@@ -260,19 +260,19 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
UBFXx(x6, xRAX, 0, 8);
|
||||
if(MODREG) {
|
||||
if(rex.rex) {
|
||||
wback = xRAX+(nextop&7)+(rex.b<<3);
|
||||
wback = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
wb2 = 0;
|
||||
} else {
|
||||
wback = (nextop&7);
|
||||
wb2 = (wback>>2)*8;
|
||||
wback = xRAX+(wback&3);
|
||||
wback = TO_NAT(wback & 3);
|
||||
}
|
||||
UBFXx(x2, wback, wb2, 8);
|
||||
wb1 = 0;
|
||||
ed = x2;
|
||||
UFLAG_IF {emit_cmp8(dyn, ninst, x6, ed, x3, x4, x5);}
|
||||
CMPSxw_REG(x6, x2);
|
||||
B_MARK2(cNE);
|
||||
SUBxw_REG(x6, x6, x2);
|
||||
CBNZxw_MARK2(x6);
|
||||
BFIx(wback, x2, wb2, 8);
|
||||
MOVxw_REG(ed, gd);
|
||||
MARK2;
|
||||
@@ -317,12 +317,12 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
wback = 0;
|
||||
UFLAG_IF {emit_cmp32(dyn, ninst, rex, xRAX, ed, x3, x4, x5);}
|
||||
MOVxw_REG(x1, ed); // save value
|
||||
CMPSxw_REG(xRAX, x1);
|
||||
B_MARK2(cNE);
|
||||
SUBxw_REG(x3, xRAX, x1);
|
||||
CBNZxw_MARK2(x3);
|
||||
MOVxw_REG(ed, gd);
|
||||
MARK2;
|
||||
MOVxw_REG(xRAX, x1);
|
||||
@@ -400,7 +400,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
wback = 0;
|
||||
if(rex.w) {
|
||||
ANDx_mask(x2, gd, 1, 0, 0b00101); //mask=0x000000000000003f
|
||||
@@ -447,7 +447,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SET_DFNONE(x1);
|
||||
gd = x2;
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
u8 = F8;
|
||||
u8&=rex.w?0x3f:0x1f;
|
||||
BFXILxw(xFlags, ed, u8, 1); // inject 1 bit from u8 to F_CF (i.e. pos 0)
|
||||
@@ -471,7 +471,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
wback = 0;
|
||||
u8 = F8;
|
||||
u8&=(rex.w?0x3f:0x1f);
|
||||
@@ -503,7 +503,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
wback = 0;
|
||||
u8 = F8;
|
||||
u8&=(rex.w?0x3f:0x1f);
|
||||
@@ -532,7 +532,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE(x1);
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
wback = 0;
|
||||
u8 = F8;
|
||||
u8&=(rex.w?0x3f:0x1f);
|
||||
@@ -570,7 +570,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGB(x1);
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
GETEB(x2, 0);
|
||||
gd = x2; ed = x1; // swap gd/ed
|
||||
emit_add8(dyn, ninst, x1, x2, x4, x5);
|
||||
@@ -616,7 +616,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
MOVxw_REG(x1, ed);
|
||||
MOVxw_REG(ed, gd);
|
||||
MOVxw_REG(gd, x1);
|
||||
@@ -688,7 +688,11 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 1:
|
||||
INST_NAME("LOCK CMPXCHG8B Gq, Eq");
|
||||
if (rex.w) {
|
||||
INST_NAME("LOCK CMPXCHG16B Gq, Eq");
|
||||
} else {
|
||||
INST_NAME("LOCK CMPXCHG8B Gq, Eq");
|
||||
}
|
||||
SETFLAGS(X_ZF, SF_SUBSET);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
if(!ALIGNED_ATOMICxw) {
|
||||
@@ -715,7 +719,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
UFLAG_IF {
|
||||
CMPSxw_REG(x2, xRAX);
|
||||
CCMPxw(x3, xRDX, 0, cEQ);
|
||||
CSETw(x1, cEQ);
|
||||
IFNATIVE(NF_EQ) {} else {CSETw(x1, cEQ);}
|
||||
}
|
||||
MOVx_REG(xRAX, x2);
|
||||
MOVx_REG(xRDX, x3);
|
||||
@@ -731,7 +735,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
STLXPxw(x4, xRBX, xRCX, wback);
|
||||
CBNZx_MARKLOCK(x4);
|
||||
UFLAG_IF {
|
||||
MOV32w(x1, 1);
|
||||
IFNATIVE(NF_EQ) {} else {MOV32w(x1, 1);}
|
||||
}
|
||||
B_MARK3_nocond;
|
||||
MARK;
|
||||
@@ -740,7 +744,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOVxw_REG(xRAX, x2);
|
||||
MOVxw_REG(xRDX, x3);
|
||||
UFLAG_IF {
|
||||
MOV32w(x1, 0);
|
||||
IFNATIVE(NF_EQ) {} else {MOV32w(x1, 0);}
|
||||
}
|
||||
if(!ALIGNED_ATOMICxw) {
|
||||
B_MARK3_nocond;
|
||||
@@ -757,7 +761,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
CBNZx_MARK2(x4);
|
||||
STPxw_S7_offset(xRBX, xRCX, wback, 0);
|
||||
UFLAG_IF {
|
||||
MOV32w(x1, 1);
|
||||
IFNATIVE(NF_EQ) {} else {MOV32w(x1, 1);}
|
||||
}
|
||||
B_MARK3_nocond;
|
||||
MARKSEG;
|
||||
@@ -766,13 +770,13 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOVxw_REG(xRAX, x2);
|
||||
MOVxw_REG(xRDX, x3);
|
||||
UFLAG_IF {
|
||||
MOV32w(x1, 0);
|
||||
IFNATIVE(NF_EQ) {} else {MOV32w(x1, 0);}
|
||||
}
|
||||
}
|
||||
MARK3;
|
||||
SMDMB();
|
||||
UFLAG_IF {
|
||||
BFIw(xFlags, x1, F_ZF, 1);
|
||||
IFNATIVE(NF_EQ) {} else {BFIw(xFlags, x1, F_ZF, 1);}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -792,12 +796,12 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETGB(x2);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(rex.rex) {
|
||||
wback = xRAX + (nextop&7) + (rex.b<<3);
|
||||
wback = TO_NAT((nextop & 0x07) + (rex.b << 3));
|
||||
wb2 = 0;
|
||||
} else {
|
||||
wback = (nextop&7);
|
||||
wb2 = (wback>>2);
|
||||
wback = xRAX+(wback&3);
|
||||
wback = TO_NAT(wback & 3);
|
||||
}
|
||||
UBFXw(x1, wback, wb2*8, 8);
|
||||
emit_adc8(dyn, ninst, x1, x2, x4, x5);
|
||||
@@ -819,7 +823,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
emit_adc32(dyn, ninst, rex, ed, gd, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
@@ -831,13 +835,44 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SMDMB();
|
||||
}
|
||||
break;
|
||||
case 0x20:
|
||||
INST_NAME("LOCK AND Eb, Gb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
GETEB(x1, 0);
|
||||
GETGB(x2);
|
||||
emit_and8(dyn, ninst, x1, x2, x4, x5);
|
||||
EBBACK;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
GETGB(x5);
|
||||
if(arm64_atomics) {
|
||||
MVNxw_REG(x1, gd);
|
||||
UFLAG_IF {
|
||||
LDCLRALB(x1, x1, wback);
|
||||
emit_and8(dyn, ninst, x1, gd, x3, x4);
|
||||
} else {
|
||||
STCLRLB(x1, wback);
|
||||
}
|
||||
} else {
|
||||
MARKLOCK;
|
||||
LDAXRB(x1, wback);
|
||||
emit_and8(dyn, ninst, x1, gd, x3, x4);
|
||||
STLXRB(x3, x1, wback);
|
||||
CBNZx_MARKLOCK(x3);
|
||||
SMDMB();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x21:
|
||||
INST_NAME("LOCK AND Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
emit_and32(dyn, ninst, rex, ed, gd, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
@@ -866,7 +901,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if(MODREG) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
emit_sub32(dyn, ninst, rex, ed, gd, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
@@ -917,7 +952,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
emit_xor32(dyn, ninst, rex, ed, gd, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
@@ -1197,7 +1232,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
MOV64xw(x5, i64);
|
||||
emit_add32(dyn, ninst, rex, ed, x5, x3, x4);
|
||||
} else {
|
||||
@@ -1250,7 +1285,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
MOV64xw(x5, i64);
|
||||
emit_or32(dyn, ninst, rex, ed, x5, x3, x4);
|
||||
} else {
|
||||
@@ -1280,7 +1315,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
MOV64xw(x5, i64);
|
||||
emit_adc32(dyn, ninst, rex, ed, x5, x3, x4);
|
||||
} else {
|
||||
@@ -1301,7 +1336,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
MOV64xw(x5, i64);
|
||||
emit_sbb32(dyn, ninst, rex, ed, x5, x3, x4);
|
||||
} else {
|
||||
@@ -1321,7 +1356,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
MOV64xw(x5, i64);
|
||||
emit_and32(dyn, ninst, rex, ed, x5, x3, x4);
|
||||
} else {
|
||||
@@ -1352,7 +1387,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
MOV64xw(x5, i64);
|
||||
emit_sub32(dyn, ninst, rex, ed, x5, x3, x4);
|
||||
} else {
|
||||
@@ -1406,7 +1441,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
MOV64xw(x5, i64);
|
||||
emit_xor32(dyn, ninst, rex, ed, x5, x3, x4);
|
||||
} else {
|
||||
@@ -1453,12 +1488,12 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(MODREG) {
|
||||
GETGB(x4);
|
||||
if(rex.rex) {
|
||||
ed = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
eb1 = ed;
|
||||
eb2 = 0;
|
||||
} else {
|
||||
ed = (nextop&7);
|
||||
eb1 = xRAX+(ed&3);
|
||||
eb1 = TO_NAT(ed & 3);
|
||||
eb2 = ((ed&4)<<1);
|
||||
}
|
||||
UBFXw(x1, eb1, eb2, 8);
|
||||
@@ -1544,8 +1579,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SMDMB();
|
||||
GETEB(x1, 1);
|
||||
u8 = F8;
|
||||
MOV32w(x2, u8);
|
||||
emit_test8(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
emit_test8c(dyn, ninst, x1, u8, x3, x4, x5);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("LOCK NOT Eb");
|
||||
@@ -1574,7 +1608,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
{
|
||||
case 0: // INC Eb
|
||||
INST_NAME("LOCK INC Eb");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
if(MODREG) {
|
||||
GETEB(x1, 0);
|
||||
emit_inc8(dyn, ninst, x1, x2, x4);
|
||||
@@ -1601,7 +1635,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 1: //DEC Eb
|
||||
INST_NAME("LOCK DEC Eb");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
if(MODREG) {
|
||||
GETEB(x1, 0);
|
||||
emit_dec8(dyn, ninst, x1, x2, x4);
|
||||
@@ -1636,9 +1670,9 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
{
|
||||
case 0: // INC Ed
|
||||
INST_NAME("LOCK INC Ed");
|
||||
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));
|
||||
emit_inc32(dyn, ninst, rex, ed, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
@@ -1684,9 +1718,9 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 1: //DEC Ed
|
||||
INST_NAME("LOCK DEC Ed");
|
||||
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));
|
||||
emit_dec32(dyn, ninst, rex, ed, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "../dynarec_helper.h"
|
||||
|
||||
uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog)
|
||||
{
|
||||
@@ -31,6 +31,8 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
uint8_t wback, wb1, wb2;
|
||||
uint8_t u8;
|
||||
uint64_t u64, j64;
|
||||
int32_t i32, i32_;
|
||||
int cacheupd = 0;
|
||||
int v0, v1;
|
||||
int q0;
|
||||
int d0, d1;
|
||||
@@ -71,7 +73,6 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
d0 = sse_get_reg(dyn, ninst, x1, ed, 1);
|
||||
VMOVeD(d0, 0, v0, 0);
|
||||
} else {
|
||||
WILLWRITE2();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VST64(v0, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
@@ -414,6 +415,41 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VFSUBQS(v0, d0, v0);
|
||||
break;
|
||||
|
||||
#define GO(GETFLAGS, NO, YES, F) \
|
||||
READFLAGS(F); \
|
||||
i32_ = F32S; \
|
||||
if(rex.is32bits) \
|
||||
j64 = (uint32_t)(addr+i32_); \
|
||||
else \
|
||||
j64 = addr+i32_; \
|
||||
BARRIER(BARRIER_MAYBE); \
|
||||
JUMP(j64, 1); \
|
||||
GETFLAGS; \
|
||||
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, j64, 0, ninst, rex.is32bits); \
|
||||
} else { \
|
||||
CacheTransform(dyn, ninst, cacheupd, x1, x2, x3); \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address-(dyn->native_size); \
|
||||
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); \
|
||||
}
|
||||
|
||||
GOCOND(0x80, "J", "Id");
|
||||
#undef GO
|
||||
|
||||
case 0xAE:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "../dynarec_helper.h"
|
||||
|
||||
uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog)
|
||||
{
|
||||
@@ -184,10 +184,10 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
SETFLAGS(X_OF, SF_SUBSET);
|
||||
GETED(0);
|
||||
GETGD;
|
||||
MRS_nzvc(x3);
|
||||
MRS_nzcv(x3);
|
||||
LSRw(x4, xFlags, F_OF);
|
||||
BFIx(x3, x4, 29, 1); // set C
|
||||
MSR_nzvc(x3); // load CC into ARM CF
|
||||
MSR_nzcv(x3); // load CC into ARM CF
|
||||
IFX(X_OF) {
|
||||
ADCSxw_REG(gd, gd, ed);
|
||||
CSETw(x3, cCS);
|
||||
@@ -251,11 +251,24 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
case 0x59:
|
||||
INST_NAME("MULSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
GETGX(d1, 1);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSS(d0, 0, 0);
|
||||
FMULS(d1, v0, d0);
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
if(!box64_dynarec_fastnan) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
// check if any input value was NAN
|
||||
FMAXS(v0, d0, d1); // propagate NAN
|
||||
FCMEQS(v0, v0, v0); // 0 if NAN, 1 if not NAN
|
||||
FMULS(v1, d1, d0);
|
||||
FCMEQS(q0, v1, v1); // 0 => out is NAN
|
||||
VBIC(q0, v0, q0); // forget it in any input was a NAN already
|
||||
VSHL_32(q0, q0, 31); // only keep the sign bit
|
||||
VORR(v1, v1, q0); // NAN -> -NAN
|
||||
} else {
|
||||
FMULS(v1, d1, d0);
|
||||
}
|
||||
VMOVeS(d1, 0, v1, 0);
|
||||
break;
|
||||
case 0x5A:
|
||||
INST_NAME("CVTSS2SD Gx, Ex");
|
||||
@@ -312,7 +325,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VMOVeS(v0, 0, d0, 0); // to not erase uper part
|
||||
#else
|
||||
FCMPS(v0, v1);
|
||||
B_NEXT(cLS); //Less than or equal
|
||||
B_NEXT(cCC); //Less than
|
||||
VMOVeS(v0, 0, v1, 0); // to not erase uper part
|
||||
#endif
|
||||
break;
|
||||
@@ -337,7 +350,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VMOVeS(v0, 0, d0, 0); // to not erase uper part
|
||||
#else
|
||||
FCMPS(v0, v1);
|
||||
B_NEXT(cGE); //Greater than or equal
|
||||
B_NEXT(cGT); //Greater than
|
||||
VMOVeS(v0, 0, v1, 0); // to not erase uper part
|
||||
#endif
|
||||
break;
|
||||
|
||||
@@ -143,6 +143,7 @@ int internal_mark_ymm(dynarec_arm_t* dyn, int t, int ymm, int reg)
|
||||
// found a slot!
|
||||
dyn->n.neoncache[reg].t=t;
|
||||
dyn->n.neoncache[reg].n=ymm;
|
||||
dyn->n.news |= (1<<reg);
|
||||
return reg;
|
||||
}
|
||||
return -1;
|
||||
@@ -493,7 +494,7 @@ void neoncacheUnwind(neoncache_t* cache)
|
||||
}
|
||||
if(cache->news) {
|
||||
// remove the newly created neoncache
|
||||
for(int i=0; i<24; ++i)
|
||||
for(int i=0; i<32; ++i)
|
||||
if(cache->news&(1<<i))
|
||||
cache->neoncache[i].v = 0;
|
||||
cache->news = 0;
|
||||
@@ -598,7 +599,7 @@ void neoncacheUnwind(neoncache_t* cache)
|
||||
|
||||
#define F8 *(uint8_t*)(addr++)
|
||||
#define F32S64 (uint64_t)(int64_t)*(int32_t*)(addr+=4, addr-4)
|
||||
// Get if ED will have the correct parity. Not emiting anything. Parity is 2 for DWORD or 3 for QWORD
|
||||
// Get if ED will have the correct parity. Not emitting anything. Parity is 2 for DWORD or 3 for QWORD
|
||||
int getedparity(dynarec_arm_t* dyn, int ninst, uintptr_t addr, uint8_t nextop, int parity, int delta)
|
||||
{
|
||||
(void)dyn; (void)ninst;
|
||||
@@ -661,7 +662,7 @@ void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t r
|
||||
{
|
||||
if(box64_dynarec_dump) {
|
||||
printf_x64_instruction(rex.is32bits?my_context->dec32:my_context->dec, &dyn->insts[ninst].x64, name);
|
||||
dynarec_log(LOG_NONE, "%s%p: %d emitted opcodes, inst=%d, barrier=%d state=%d/%d(%d), %s=%X/%X, use=%X, need=%X/%X, sm=%d(%d/%d)",
|
||||
dynarec_log(LOG_NONE, "%s%p: %d emitted opcodes, inst=%d, barrier=%d state=%d/%d/%d(%d:%d->%d:%d), %s=%X/%X, use=%X, need=%X/%X, sm=%d(%d/%d)",
|
||||
(box64_dynarec_dump>1)?"\e[32m":"",
|
||||
(void*)(dyn->native_start+dyn->insts[ninst].address),
|
||||
dyn->insts[ninst].size/4,
|
||||
@@ -670,6 +671,10 @@ void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t r
|
||||
dyn->insts[ninst].x64.state_flags,
|
||||
dyn->f.pending,
|
||||
dyn->f.dfnone,
|
||||
dyn->insts[ninst].f_entry.pending,
|
||||
dyn->insts[ninst].f_entry.dfnone,
|
||||
dyn->insts[ninst].f_exit.pending,
|
||||
dyn->insts[ninst].f_exit.dfnone,
|
||||
dyn->insts[ninst].x64.may_set?"may":"set",
|
||||
dyn->insts[ninst].x64.set_flags,
|
||||
dyn->insts[ninst].x64.gen_flags,
|
||||
@@ -677,6 +682,22 @@ void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t r
|
||||
dyn->insts[ninst].x64.need_before,
|
||||
dyn->insts[ninst].x64.need_after,
|
||||
dyn->smwrite, dyn->insts[ninst].will_write, dyn->insts[ninst].last_write);
|
||||
if(dyn->insts[ninst].nat_flags_op) {
|
||||
if(dyn->insts[ninst].nat_flags_op==NAT_FLAG_OP_TOUCH && dyn->insts[ninst].before_nat_flags)
|
||||
printf_log(LOG_NONE, " NF:%d/read:%x", dyn->insts[ninst].nat_flags_op, dyn->insts[ninst].before_nat_flags);
|
||||
else
|
||||
printf_log(LOG_NONE, " NF:%d", dyn->insts[ninst].nat_flags_op);
|
||||
}
|
||||
if(dyn->insts[ninst].use_nat_flags || dyn->insts[ninst].set_nat_flags || dyn->insts[ninst].need_nat_flags)
|
||||
printf_log(LOG_NONE, " nf:%hhx/%hhx/%hhx", dyn->insts[ninst].set_nat_flags, dyn->insts[ninst].use_nat_flags, dyn->insts[ninst].need_nat_flags);
|
||||
if(dyn->insts[ninst].invert_carry)
|
||||
printf_log(LOG_NONE, " CI");
|
||||
if(dyn->insts[ninst].gen_inverted_carry)
|
||||
printf_log(LOG_NONE, " gic");
|
||||
if(dyn->insts[ninst].before_nat_flags&NF_CF)
|
||||
printf_log(LOG_NONE, " %ccb", dyn->insts[ninst].normal_carry_before?'n':'i');
|
||||
if(dyn->insts[ninst].need_nat_flags&NF_CF)
|
||||
printf_log(LOG_NONE, " %cc", dyn->insts[ninst].normal_carry?'n':'i');
|
||||
if(dyn->insts[ninst].pred_sz) {
|
||||
dynarec_log(LOG_NONE, ", pred=");
|
||||
for(int ii=0; ii<dyn->insts[ninst].pred_sz; ++ii)
|
||||
@@ -794,4 +815,208 @@ void fpu_reset_ninst(dynarec_native_t* dyn, int ninst)
|
||||
int fpu_is_st_freed(dynarec_native_t* dyn, int ninst, int st)
|
||||
{
|
||||
return (dyn->n.tags&(0b11<<(st*2)))?1:0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint8_t mark_natflag(dynarec_arm_t* dyn, int ninst, uint8_t flag, int before)
|
||||
{
|
||||
if(dyn->insts[ninst].x64.set_flags && !before) {
|
||||
dyn->insts[ninst].set_nat_flags |= flag;
|
||||
if(dyn->insts[ninst].x64.use_flags) {
|
||||
dyn->insts[ninst].use_nat_flags |= flag;
|
||||
}
|
||||
} else {
|
||||
if(before)
|
||||
dyn->insts[ninst].use_nat_flags_before |= flag;
|
||||
else
|
||||
dyn->insts[ninst].use_nat_flags |= flag;
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
uint8_t flag2native(uint8_t flags)
|
||||
{
|
||||
uint8_t ret = 0;
|
||||
#ifdef ARM64
|
||||
if(flags&X_ZF) ret|=NF_EQ;
|
||||
if(flags&X_SF) ret|=NF_SF;
|
||||
if(flags&X_OF) ret|=NF_VF;
|
||||
if(flags&X_CF) ret|=NF_CF;
|
||||
#else
|
||||
// no native flags on rv64 or la64
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
int flagIsNative(uint8_t flags)
|
||||
{
|
||||
if(flags&(X_AF|X_PF)) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static uint8_t getNativeFlagsUsed(dynarec_arm_t* dyn, int start, uint8_t flags)
|
||||
{
|
||||
// propagate and check wich flags are actually used
|
||||
uint8_t used_flags = 0;
|
||||
int nat_flags_used = 0;
|
||||
int ninst = start;
|
||||
while(ninst<dyn->size) {
|
||||
//printf_log(LOG_INFO, "getNativeFlagsUsed ninst:%d/%d, flags=%x, used_flags=%x(%d), nat_flags_op_before:%x, nat_flags_op:%x, need_after:%x\n", ninst, start, flags, used_flags, nat_flags_used, dyn->insts[ninst].nat_flags_op_before, dyn->insts[ninst].nat_flags_op, flag2native(dyn->insts[ninst].x64.need_after));
|
||||
// check if this is an opcode that generate flags but consume flags before
|
||||
if(dyn->insts[ninst].nat_flags_op_before)
|
||||
return 0;
|
||||
// check if nat flags are used "before"
|
||||
if(dyn->insts[ninst].use_nat_flags_before)
|
||||
nat_flags_used = 1;
|
||||
if(dyn->insts[ninst].nat_flags_op==NAT_FLAG_OP_TOUCH && dyn->insts[ninst].use_nat_flags_before)
|
||||
used_flags|=dyn->insts[ninst].use_nat_flags_before&flags;
|
||||
// if the opcode generate flags, return
|
||||
if(dyn->insts[ninst].nat_flags_op==NAT_FLAG_OP_TOUCH && (start!=ninst)) {
|
||||
if(used_flags&~dyn->insts[ninst].set_nat_flags) {
|
||||
// check partial changes that would destroy flag state
|
||||
if(dyn->insts[ninst].use_nat_flags_before&flags)
|
||||
return nat_flags_used?used_flags:0;
|
||||
// but also check if there is before needed
|
||||
return 0;
|
||||
}
|
||||
return nat_flags_used?used_flags:0;
|
||||
}
|
||||
// check if there is a callret barrier
|
||||
if(dyn->insts[ninst].x64.has_callret)
|
||||
return 0;
|
||||
// check if nat flags are used
|
||||
if(dyn->insts[ninst].use_nat_flags)
|
||||
nat_flags_used = 1;
|
||||
// check if flags are used, but not the natives ones
|
||||
if(ninst!=start && dyn->insts[ninst].x64.use_flags) {
|
||||
if((flag2native(dyn->insts[ninst].x64.use_flags)&~(dyn->insts[ninst].use_nat_flags))&used_flags)
|
||||
return 0;
|
||||
// also check if the gen flags are compatible
|
||||
if((dyn->insts[ninst].use_nat_flags)&~flags)
|
||||
return 0;
|
||||
}
|
||||
// check if flags are generated without native option
|
||||
if((start!=ninst) && dyn->insts[ninst].x64.gen_flags && (flag2native(dyn->insts[ninst].x64.gen_flags&dyn->insts[ninst].x64.need_after)&used_flags)) {
|
||||
if(used_flags&~flag2native(dyn->insts[ninst].x64.gen_flags&dyn->insts[ninst].x64.need_after))
|
||||
return 0; // partial covert, not supported for now (TODO: this might be fixable)
|
||||
else
|
||||
return nat_flags_used?used_flags:0; // full covert... End of propagation
|
||||
}
|
||||
// check if flags are still needed
|
||||
if(!(flag2native(dyn->insts[ninst].x64.need_after)&flags))
|
||||
return nat_flags_used?used_flags:0;
|
||||
// check if flags are destroyed, cancel the use then
|
||||
if(dyn->insts[ninst].nat_flags_op && (start!=ninst))
|
||||
return 0;
|
||||
// update used flags
|
||||
used_flags |= (flag2native(dyn->insts[ninst].x64.need_after)&flags);
|
||||
// go next
|
||||
if(!dyn->insts[ninst].x64.has_next) {
|
||||
// check if it's a jump to an opcode with only 1 preds, then just follow the jump
|
||||
int jmp = dyn->insts[ninst].x64.jmp_insts;
|
||||
if(dyn->insts[ninst].x64.jmp && (jmp!=-1) && (getNominalPred(dyn, jmp)==ninst))
|
||||
ninst = jmp;
|
||||
else
|
||||
return nat_flags_used?used_flags:0;
|
||||
} else
|
||||
++ninst;
|
||||
}
|
||||
return nat_flags_used?used_flags:0;
|
||||
}
|
||||
|
||||
static void propagateNativeFlags(dynarec_arm_t* dyn, int start)
|
||||
{
|
||||
int ninst = start;
|
||||
// those are the flags generated by the opcode and used later on
|
||||
uint8_t flags = dyn->insts[ninst].set_nat_flags&flag2native(dyn->insts[ninst].x64.need_after);
|
||||
//check if they are actualy used before starting
|
||||
//printf_log(LOG_INFO, "propagateNativeFlags called for start=%d, flags=%x, will need:%x\n", start, flags, flag2native(dyn->insts[ninst].x64.need_after));
|
||||
if(!flags) return;
|
||||
// also check if some native flags are used but not genereated here
|
||||
if(flag2native(dyn->insts[ninst].x64.need_after)&~flags) return;
|
||||
uint8_t used_flags = getNativeFlagsUsed(dyn, start, flags);
|
||||
//printf_log(LOG_INFO, " will use:%x, carry:%d, generate inverted carry:%d\n", used_flags, used_flags&NF_CF, dyn->insts[ninst].gen_inverted_carry);
|
||||
if(!used_flags) return; // the flags wont be used, so just cancel
|
||||
int nc = dyn->insts[ninst].gen_inverted_carry?0:1;
|
||||
int carry = used_flags&NF_CF;
|
||||
// propagate
|
||||
while(ninst<dyn->size) {
|
||||
// check if this is an opcode that generate flags but consume flags before
|
||||
if((start!=ninst) && dyn->insts[ninst].nat_flags_op==NAT_FLAG_OP_TOUCH) {
|
||||
if(dyn->insts[ninst].use_nat_flags_before) {
|
||||
dyn->insts[ninst].before_nat_flags |= used_flags;
|
||||
if(carry) dyn->insts[ninst].normal_carry_before = nc;
|
||||
}
|
||||
// if the opcode generate flags, return
|
||||
return;
|
||||
}
|
||||
// check if flags are generated without native option
|
||||
if((start!=ninst) && dyn->insts[ninst].x64.gen_flags && (flag2native(dyn->insts[ninst].x64.gen_flags&dyn->insts[ninst].x64.need_after)&used_flags))
|
||||
return;
|
||||
// mark the opcode
|
||||
uint8_t use_flags = flag2native(dyn->insts[ninst].x64.need_before|dyn->insts[ninst].x64.need_after);
|
||||
if(dyn->insts[ninst].x64.use_flags) use_flags |= flag2native(dyn->insts[ninst].x64.use_flags); // should not change anything
|
||||
//printf_log(LOG_INFO, " marking ninst=%d with %x | %x&%x => %x\n", ninst, dyn->insts[ninst].need_nat_flags, used_flags, use_flags, dyn->insts[ninst].need_nat_flags | (used_flags&use_flags));
|
||||
dyn->insts[ninst].need_nat_flags |= used_flags&use_flags;
|
||||
if(carry) dyn->insts[ninst].normal_carry = nc;
|
||||
if(carry && dyn->insts[ninst].invert_carry) nc = 0;
|
||||
// check if flags are still needed
|
||||
if(!(flag2native(dyn->insts[ninst].x64.need_after)&used_flags))
|
||||
return;
|
||||
// go next
|
||||
if(!dyn->insts[ninst].x64.has_next) {
|
||||
// check if it's a jump to an opcode with only 1 preds, then just follow the jump
|
||||
int jmp = dyn->insts[ninst].x64.jmp_insts;
|
||||
if(dyn->insts[ninst].x64.jmp && (jmp!=-1) && (getNominalPred(dyn, jmp)==ninst))
|
||||
ninst = jmp;
|
||||
else
|
||||
return;
|
||||
} else
|
||||
++ninst;
|
||||
}
|
||||
}
|
||||
|
||||
void updateNativeFlags(dynarec_native_t* dyn)
|
||||
{
|
||||
if(!box64_dynarec_nativeflags)
|
||||
return;
|
||||
// backward check if native flags are used
|
||||
for(int ninst=0; ninst<dyn->size; ++ninst)
|
||||
if(flag2native(dyn->insts[ninst].x64.gen_flags) && (dyn->insts[ninst].nat_flags_op==NAT_FLAG_OP_TOUCH)) {
|
||||
propagateNativeFlags(dyn, ninst);
|
||||
}
|
||||
}
|
||||
|
||||
void rasNativeState(dynarec_arm_t* dyn, int ninst)
|
||||
{
|
||||
dyn->insts[ninst].nat_flags_op = dyn->insts[ninst].set_nat_flags = dyn->insts[ninst].use_nat_flags = dyn->insts[ninst].need_nat_flags = 0;
|
||||
}
|
||||
|
||||
int nativeFlagsNeedsTransform(dynarec_arm_t* dyn, int ninst)
|
||||
{
|
||||
int jmp = dyn->insts[ninst].x64.jmp_insts;
|
||||
if(jmp<0)
|
||||
return 0;
|
||||
if(!dyn->insts[ninst].x64.need_after || !dyn->insts[jmp].x64.need_before)
|
||||
return 0;
|
||||
if(dyn->insts[ninst].set_nat_flags)
|
||||
return 0;
|
||||
uint8_t flags_before = dyn->insts[ninst].need_nat_flags;
|
||||
uint8_t nc_before = dyn->insts[ninst].normal_carry;
|
||||
if(dyn->insts[ninst].invert_carry)
|
||||
nc_before = 0;
|
||||
uint8_t flags_after = dyn->insts[jmp].need_nat_flags;
|
||||
uint8_t nc_after = dyn->insts[jmp].normal_carry;
|
||||
if(dyn->insts[jmp].nat_flags_op==NAT_FLAG_OP_TOUCH) {
|
||||
flags_after = dyn->insts[jmp].before_nat_flags;
|
||||
nc_after = dyn->insts[jmp].normal_carry_before;
|
||||
}
|
||||
uint8_t flags_x86 = flag2native(dyn->insts[jmp].x64.need_before);
|
||||
flags_x86 &= ~flags_after;
|
||||
if((flags_before&NF_CF) && (flags_after&NF_CF) && (nc_before!=nc_after))
|
||||
return 1;
|
||||
// all flags_after should be present and none remaining flags_x86
|
||||
if(((flags_before&flags_after)!=flags_after) || (flags_before&flags_x86))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
@@ -51,6 +51,16 @@ int neoncache_combine_st(dynarec_arm_t* dyn, int ninst, int a, int b); // with
|
||||
// Do not allow i64 type
|
||||
int neoncache_no_i64(dynarec_arm_t* dyn, int ninst, int st, int a);
|
||||
|
||||
// transform x86 flags to native flags
|
||||
uint8_t flag2native(uint8_t flags);
|
||||
// mark a instruction as using/generating flags. return flag
|
||||
uint8_t mark_natflag(dynarec_arm_t* dyn, int ninst, uint8_t flag, int before);
|
||||
// propage the use of nativeflags or not (done between step 0 and step 1)
|
||||
void updateNativeFlags(dynarec_arm_t* dyn);
|
||||
// raz arm speicifc state when an opcode is unused
|
||||
void rasNativeState(dynarec_arm_t* dyn, int ninst);
|
||||
// check if natives flags needs some tranform to/from x86 flags
|
||||
int nativeFlagsNeedsTransform(dynarec_arm_t* dyn, int ninst);
|
||||
|
||||
// FPU Cache transformation (for loops) // Specific, need to be written by backend
|
||||
int fpuCacheNeedsTransform(dynarec_arm_t* dyn, int ninst);
|
||||
@@ -58,7 +68,7 @@ int fpuCacheNeedsTransform(dynarec_arm_t* dyn, int ninst);
|
||||
// Undo the changes of a neoncache to get the status before the instruction
|
||||
void neoncacheUnwind(neoncache_t* cache);
|
||||
|
||||
// Get if ED will have the correct parity. Not emiting anything. Parity is 2 for DWORD or 3 for QWORD
|
||||
// Get if ED will have the correct parity. Not emitting anything. Parity is 2 for DWORD or 3 for QWORD
|
||||
int getedparity(dynarec_native_t* dyn, int ninst, uintptr_t addr, uint8_t nextop, int parity, int delta);
|
||||
|
||||
const char* getCacheName(int t, int n);
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#include "arm64_printer.h"
|
||||
#include "dynarec_arm64_private.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_arm64_helper.h"
|
||||
#include "../dynarec_helper.h"
|
||||
|
||||
static uintptr_t geted_32(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int64_t* fixaddress, int* unscaled, int absmax, uint32_t mask, int* l, int s);
|
||||
|
||||
@@ -59,12 +59,12 @@ uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, u
|
||||
if (sib_reg!=4) {
|
||||
if(tmp && ((!((tmp>=absmin) && (tmp<=absmax) && !(tmp&mask))) || !(unscaled && (tmp>-256) && (tmp<256)))) {
|
||||
MOV64x(scratch, tmp);
|
||||
ADDx_REG_LSL(ret, scratch, xRAX+sib_reg, (sib>>6));
|
||||
ADDx_REG_LSL(ret, scratch, TO_NAT(sib_reg), (sib>>6));
|
||||
} else {
|
||||
if(sib>>6) {
|
||||
LSLx(ret, xRAX+sib_reg, (sib>>6));
|
||||
LSLx(ret, TO_NAT(sib_reg), (sib>>6));
|
||||
} else
|
||||
ret = xRAX+sib_reg;
|
||||
ret = TO_NAT(sib_reg);
|
||||
if(unscaled && (tmp>-256) && (tmp<256))
|
||||
*unscaled = 1;
|
||||
*fixaddress = tmp;
|
||||
@@ -78,9 +78,9 @@ uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, u
|
||||
}
|
||||
} else {
|
||||
if (sib_reg!=4) {
|
||||
ADDx_REG_LSL(ret, xRAX+(sib&0x7)+(rex.b<<3), xRAX+sib_reg, (sib>>6));
|
||||
ADDx_REG_LSL(ret, TO_NAT((sib&0x7)+(rex.b<<3)), TO_NAT(sib_reg), (sib>>6));
|
||||
} else {
|
||||
ret = xRAX+(sib&0x7)+(rex.b<<3);
|
||||
ret = TO_NAT((sib&0x7)+(rex.b<<3));
|
||||
}
|
||||
}
|
||||
} else if((nextop&7)==5) {
|
||||
@@ -112,7 +112,7 @@ uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, u
|
||||
case 2: if(isLockAddress(addr+delta+tmp)) *l=1; break;
|
||||
}
|
||||
} else {
|
||||
ret = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ret = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
}
|
||||
} else {
|
||||
int64_t i64;
|
||||
@@ -132,24 +132,24 @@ uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, u
|
||||
*unscaled = 1;
|
||||
if((nextop&7)==4) {
|
||||
if (sib_reg!=4) {
|
||||
ADDx_REG_LSL(ret, xRAX+(sib&0x07)+(rex.b<<3), xRAX+sib_reg, (sib>>6));
|
||||
ADDx_REG_LSL(ret, TO_NAT((sib&0x07)+(rex.b<<3)), TO_NAT(sib_reg), (sib>>6));
|
||||
} else {
|
||||
ret = xRAX+(sib&0x07)+(rex.b<<3);
|
||||
ret = TO_NAT((sib&0x07)+(rex.b<<3));
|
||||
}
|
||||
} else
|
||||
ret = xRAX+(nextop&0x07)+(rex.b<<3);
|
||||
ret = TO_NAT((nextop & 0x07) + (rex.b << 3));
|
||||
} else {
|
||||
int64_t sub = (i64<0)?1:0;
|
||||
if(sub) i64 = -i64;
|
||||
if(i64<0x1000) {
|
||||
if((nextop&7)==4) {
|
||||
if (sib_reg!=4) {
|
||||
ADDx_REG_LSL(scratch, xRAX+(sib&0x07)+(rex.b<<3), xRAX+sib_reg, (sib>>6));
|
||||
ADDx_REG_LSL(scratch, TO_NAT((sib&0x07)+(rex.b<<3)), TO_NAT(sib_reg), (sib>>6));
|
||||
} else {
|
||||
scratch = xRAX+(sib&0x07)+(rex.b<<3);
|
||||
scratch = TO_NAT((sib&0x07)+(rex.b<<3));
|
||||
}
|
||||
} else
|
||||
scratch = xRAX+(nextop&0x07)+(rex.b<<3);
|
||||
scratch = TO_NAT((nextop & 0x07) + (rex.b << 3));
|
||||
if(sub) {
|
||||
SUBx_U12(ret, scratch, i64);
|
||||
} else {
|
||||
@@ -160,13 +160,13 @@ uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, u
|
||||
if((nextop&7)==4) {
|
||||
if (sib_reg!=4) {
|
||||
if(sub) {
|
||||
SUBx_REG(scratch, xRAX+(sib&0x07)+(rex.b<<3), scratch);
|
||||
SUBx_REG(scratch, TO_NAT((sib&0x07)+(rex.b<<3)), scratch);
|
||||
} else {
|
||||
ADDx_REG(scratch, scratch, xRAX+(sib&0x07)+(rex.b<<3));
|
||||
ADDx_REG(scratch, scratch, TO_NAT((sib&0x07)+(rex.b<<3)));
|
||||
}
|
||||
ADDx_REG_LSL(ret, scratch, xRAX+sib_reg, (sib>>6));
|
||||
ADDx_REG_LSL(ret, scratch, TO_NAT(sib_reg), (sib>>6));
|
||||
} else {
|
||||
PASS3(int tmp = xRAX+(sib&0x07)+(rex.b<<3));
|
||||
PASS3(int tmp = TO_NAT(sib & 0x07) + (rex.b << 3));
|
||||
if(sub) {
|
||||
SUBx_REG(ret, tmp, scratch);
|
||||
} else {
|
||||
@@ -174,7 +174,7 @@ uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, u
|
||||
}
|
||||
}
|
||||
} else {
|
||||
PASS3(int tmp = xRAX+(nextop&0x07)+(rex.b<<3));
|
||||
PASS3(int tmp = TO_NAT((nextop & 0x07) + (rex.b << 3)));
|
||||
if(sub) {
|
||||
SUBx_REG(ret, tmp, scratch);
|
||||
} else {
|
||||
@@ -214,9 +214,9 @@ static uintptr_t geted_32(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t
|
||||
if (sib_reg!=4) {
|
||||
if(tmp && ((!((tmp>=absmin) && (tmp<=absmax) && !(tmp&mask))) || !(unscaled && (tmp>-256) && (tmp<256)))) {
|
||||
MOV32w(scratch, tmp);
|
||||
ADDw_REG_LSL(ret, scratch, xRAX+sib_reg, (sib>>6));
|
||||
ADDw_REG_LSL(ret, scratch, TO_NAT(sib_reg), (sib >> 6));
|
||||
} else {
|
||||
LSLw(ret, xRAX+sib_reg, (sib>>6));
|
||||
LSLw(ret, TO_NAT(sib_reg), (sib >> 6));
|
||||
*fixaddress = tmp;
|
||||
if(unscaled && (tmp>-256) && (tmp<256))
|
||||
*unscaled = 1;
|
||||
@@ -230,9 +230,9 @@ static uintptr_t geted_32(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t
|
||||
}
|
||||
} else {
|
||||
if (sib_reg!=4) {
|
||||
ADDw_REG_LSL(ret, xRAX+(sib&0x7), xRAX+sib_reg, (sib>>6));
|
||||
ADDw_REG_LSL(ret, TO_NAT(sib & 0x7), TO_NAT(sib_reg), (sib >> 6));
|
||||
} else {
|
||||
ret = xRAX+(sib&0x7);
|
||||
ret = TO_NAT(sib & 0x7);
|
||||
}
|
||||
}
|
||||
} else if((nextop&7)==5) {
|
||||
@@ -243,7 +243,7 @@ static uintptr_t geted_32(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t
|
||||
case 2: if(isLockAddress(tmp)) *l=1; break;
|
||||
}
|
||||
} else {
|
||||
ret = xRAX+(nextop&7);
|
||||
ret = TO_NAT(nextop & 7);
|
||||
if(ret==hint) {
|
||||
MOVw_REG(hint, ret); //to clear upper part
|
||||
}
|
||||
@@ -266,12 +266,12 @@ static uintptr_t geted_32(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t
|
||||
*unscaled = 1;
|
||||
if((nextop&7)==4) {
|
||||
if (sib_reg!=4) {
|
||||
ADDw_REG_LSL(ret, xRAX+(sib&0x07), xRAX+sib_reg, (sib>>6));
|
||||
ADDw_REG_LSL(ret, TO_NAT(sib & 0x07), TO_NAT(sib_reg), (sib >> 6));
|
||||
} else {
|
||||
ret = xRAX+(sib&0x07);
|
||||
ret = TO_NAT(sib & 0x07);
|
||||
}
|
||||
} else {
|
||||
ret = xRAX+(nextop&0x07);
|
||||
ret = TO_NAT(nextop & 0x07);
|
||||
}
|
||||
} else {
|
||||
int64_t sub = (i32<0)?1:0;
|
||||
@@ -279,12 +279,12 @@ static uintptr_t geted_32(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t
|
||||
if(i32<0x1000) {
|
||||
if((nextop&7)==4) {
|
||||
if (sib_reg!=4) {
|
||||
ADDw_REG_LSL(scratch, xRAX+(sib&0x07), xRAX+sib_reg, (sib>>6));
|
||||
ADDw_REG_LSL(scratch, TO_NAT(sib & 0x07), TO_NAT(sib_reg), (sib >> 6));
|
||||
} else {
|
||||
scratch = xRAX+(sib&0x07);
|
||||
scratch = TO_NAT(sib & 0x07);
|
||||
}
|
||||
} else
|
||||
scratch = xRAX+(nextop&0x07);
|
||||
scratch = TO_NAT(nextop & 0x07);
|
||||
if(sub) {
|
||||
SUBw_U12(ret, scratch, i32);
|
||||
} else {
|
||||
@@ -295,13 +295,13 @@ static uintptr_t geted_32(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t
|
||||
if((nextop&7)==4) {
|
||||
if (sib_reg!=4) {
|
||||
if(sub) {
|
||||
SUBw_REG(scratch, xRAX+(sib&0x07), scratch);
|
||||
SUBw_REG(scratch, TO_NAT(sib & 0x07), scratch);
|
||||
} else {
|
||||
ADDw_REG(scratch, scratch, xRAX+(sib&0x07));
|
||||
ADDw_REG(scratch, scratch, TO_NAT(sib & 0x07));
|
||||
}
|
||||
ADDw_REG_LSL(ret, scratch, xRAX+sib_reg, (sib>>6));
|
||||
ADDw_REG_LSL(ret, scratch, TO_NAT(sib_reg), (sib >> 6));
|
||||
} else {
|
||||
PASS3(int tmp = xRAX+(sib&0x07));
|
||||
PASS3(int tmp = TO_NAT(sib & 0x07));
|
||||
if(sub) {
|
||||
SUBw_REG(ret, tmp, scratch);
|
||||
} else {
|
||||
@@ -309,7 +309,7 @@ static uintptr_t geted_32(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t
|
||||
}
|
||||
}
|
||||
} else {
|
||||
PASS3(int tmp = xRAX+(nextop&0x07));
|
||||
PASS3(int tmp = TO_NAT(nextop & 0x07));
|
||||
if(sub) {
|
||||
SUBw_REG(ret, tmp, scratch);
|
||||
} else {
|
||||
@@ -350,9 +350,9 @@ uintptr_t geted32(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop,
|
||||
if (sib_reg!=4) {
|
||||
if(tmp && ((!((tmp>=absmin) && (tmp<=absmax) && !(tmp&mask))) || !(unscaled && (tmp>-256) && (tmp<256)))) {
|
||||
MOV64x(scratch, tmp);
|
||||
ADDw_REG_LSL(ret, scratch, xRAX+sib_reg, (sib>>6));
|
||||
ADDw_REG_LSL(ret, scratch, TO_NAT(sib_reg), (sib >> 6));
|
||||
} else {
|
||||
LSLw(ret, xRAX+sib_reg, (sib>>6));
|
||||
LSLw(ret, TO_NAT(sib_reg), (sib >> 6));
|
||||
*fixaddress = tmp;
|
||||
if(unscaled && (tmp>-256) && (tmp<256))
|
||||
*unscaled = 1;
|
||||
@@ -366,9 +366,9 @@ uintptr_t geted32(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop,
|
||||
}
|
||||
} else {
|
||||
if (sib_reg!=4) {
|
||||
ADDw_REG_LSL(ret, xRAX+(sib&0x7)+(rex.b<<3), xRAX+sib_reg, (sib>>6));
|
||||
ADDw_REG_LSL(ret, TO_NAT((sib & 0x7) + (rex.b << 3)), TO_NAT(sib_reg), (sib >> 6));
|
||||
} else {
|
||||
ret = xRAX+(sib&0x7)+(rex.b<<3);
|
||||
ret = TO_NAT((sib & 0x7)) + (rex.b << 3);
|
||||
}
|
||||
}
|
||||
} else if((nextop&7)==5) {
|
||||
@@ -381,7 +381,7 @@ uintptr_t geted32(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop,
|
||||
case 2: if(isLockAddress(addr+delta+tmp)) *l=1; break;
|
||||
}
|
||||
} else {
|
||||
ret = xRAX+(nextop&7)+(rex.b<<3);
|
||||
ret = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
if(ret==hint) {
|
||||
MOVw_REG(hint, ret); //to clear upper part
|
||||
}
|
||||
@@ -404,12 +404,12 @@ uintptr_t geted32(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop,
|
||||
*unscaled = 1;
|
||||
if((nextop&7)==4) {
|
||||
if (sib_reg!=4) {
|
||||
ADDw_REG_LSL(ret, xRAX+(sib&0x07)+(rex.b<<3), xRAX+sib_reg, (sib>>6));
|
||||
ADDw_REG_LSL(ret, TO_NAT((sib & 0x07) + (rex.b << 3)), TO_NAT(sib_reg), (sib >> 6));
|
||||
} else {
|
||||
ret = xRAX+(sib&0x07)+(rex.b<<3);
|
||||
ret = TO_NAT((sib & 0x07) + (rex.b << 3));
|
||||
}
|
||||
} else {
|
||||
ret = xRAX+(nextop&0x07)+(rex.b<<3);
|
||||
ret = TO_NAT((nextop & 0x07) + (rex.b << 3));
|
||||
}
|
||||
} else {
|
||||
int64_t sub = (i64<0)?1:0;
|
||||
@@ -417,12 +417,12 @@ uintptr_t geted32(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop,
|
||||
if(i64<0x1000) {
|
||||
if((nextop&7)==4) {
|
||||
if (sib_reg!=4) {
|
||||
ADDw_REG_LSL(scratch, xRAX+(sib&0x07)+(rex.b<<3), xRAX+sib_reg, (sib>>6));
|
||||
ADDw_REG_LSL(scratch, TO_NAT((sib & 0x07) + (rex.b << 3)), TO_NAT(sib_reg), (sib >> 6));
|
||||
} else {
|
||||
scratch = xRAX+(sib&0x07)+(rex.b<<3);
|
||||
scratch = TO_NAT((sib & 0x07) + (rex.b << 3));
|
||||
}
|
||||
} else
|
||||
scratch = xRAX+(nextop&0x07)+(rex.b<<3);
|
||||
scratch = TO_NAT((nextop & 0x07) + (rex.b << 3));
|
||||
if(sub) {
|
||||
SUBw_U12(ret, scratch, i64);
|
||||
} else {
|
||||
@@ -433,13 +433,13 @@ uintptr_t geted32(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop,
|
||||
if((nextop&7)==4) {
|
||||
if (sib_reg!=4) {
|
||||
if(sub) {
|
||||
SUBw_REG(scratch, xRAX+(sib&0x07)+(rex.b<<3), scratch);
|
||||
SUBw_REG(scratch, TO_NAT((sib & 0x07) + (rex.b << 3)), scratch);
|
||||
} else {
|
||||
ADDw_REG(scratch, scratch, xRAX+(sib&0x07)+(rex.b<<3));
|
||||
ADDw_REG(scratch, scratch, TO_NAT((sib & 0x07) + (rex.b << 3)));
|
||||
}
|
||||
ADDw_REG_LSL(ret, scratch, xRAX+sib_reg, (sib>>6));
|
||||
ADDw_REG_LSL(ret, scratch, TO_NAT(sib_reg), (sib >> 6));
|
||||
} else {
|
||||
PASS3(int tmp = xRAX+(sib&0x07)+(rex.b<<3));
|
||||
PASS3(int tmp = TO_NAT((sib & 0x07) + (rex.b << 3)));
|
||||
if(sub) {
|
||||
SUBw_REG(ret, tmp, scratch);
|
||||
} else {
|
||||
@@ -447,7 +447,7 @@ uintptr_t geted32(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
PASS3(int tmp = xRAX+(nextop&0x07)+(rex.b<<3));
|
||||
PASS3(int tmp = TO_NAT((nextop & 0x07) + (rex.b << 3)));
|
||||
if(sub) {
|
||||
SUBw_REG(ret, tmp, scratch);
|
||||
} else {
|
||||
@@ -569,6 +569,9 @@ void jump_to_next(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst, int is32
|
||||
MAYUSE(dyn); MAYUSE(ninst);
|
||||
MESSAGE(LOG_DUMP, "Jump to next\n");
|
||||
|
||||
if(is32bits)
|
||||
ip &= 0xffffffffLL;
|
||||
|
||||
SMEND();
|
||||
if(reg) {
|
||||
if(reg!=xRIP) {
|
||||
@@ -606,8 +609,14 @@ void jump_to_next(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst, int is32
|
||||
CLEARIP();
|
||||
#ifdef HAVE_TRACE
|
||||
//MOVx(x3, 15); no access to PC reg
|
||||
#endif
|
||||
BLR(x2); // save LR...
|
||||
#else
|
||||
if (dyn->insts[ninst].x64.has_callret) {
|
||||
BLR(x2); // save LR...
|
||||
} else {
|
||||
BR(x2);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void ret_to_epilog(dynarec_arm_t* dyn, int ninst, rex_t rex)
|
||||
@@ -619,10 +628,10 @@ void ret_to_epilog(dynarec_arm_t* dyn, int ninst, rex_t rex)
|
||||
SMEND();
|
||||
if(box64_dynarec_callret) {
|
||||
// pop the actual return address for ARM stack
|
||||
LDPx_S7_postindex(x2, x6, xSP, 16);
|
||||
LDPx_S7_postindex(xLR, x6, xSP, 16);
|
||||
SUBx_REG(x6, x6, xRIP); // is it the right address?
|
||||
CBNZx(x6, 2*4);
|
||||
BLR(x2);
|
||||
RET(xLR);
|
||||
// not the correct return address, regular jump, but purge the stack first, it's unsync now...
|
||||
SUBx_U12(xSP, xSavedSP, 16);
|
||||
}
|
||||
@@ -643,7 +652,11 @@ void ret_to_epilog(dynarec_arm_t* dyn, int ninst, rex_t rex)
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
UBFXx(x3, xRIP, JMPTABL_START0, JMPTABL_SHIFT0);
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
BLR(x2); // save LR
|
||||
#ifdef HAVE_TRACE
|
||||
BLR(x2);
|
||||
#else
|
||||
BR(x2);
|
||||
#endif
|
||||
CLEARIP();
|
||||
}
|
||||
|
||||
@@ -662,10 +675,10 @@ void retn_to_epilog(dynarec_arm_t* dyn, int ninst, rex_t rex, int n)
|
||||
SMEND();
|
||||
if(box64_dynarec_callret) {
|
||||
// pop the actual return address for ARM stack
|
||||
LDPx_S7_postindex(x2, x6, xSP, 16);
|
||||
LDPx_S7_postindex(xLR, x6, xSP, 16);
|
||||
SUBx_REG(x6, x6, xRIP); // is it the right address?
|
||||
CBNZx(x6, 2*4);
|
||||
BLR(x2);
|
||||
RET(xLR);
|
||||
// not the correct return address, regular jump
|
||||
SUBx_U12(xSP, xSavedSP, 16);
|
||||
}
|
||||
@@ -686,14 +699,20 @@ void retn_to_epilog(dynarec_arm_t* dyn, int ninst, rex_t rex, int n)
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
UBFXx(x3, xRIP, JMPTABL_START0, JMPTABL_SHIFT0);
|
||||
LDRx_REG_LSL3(x2, x2, x3);
|
||||
BLR(x2); // save LR
|
||||
#ifdef HAVE_TRACE
|
||||
BLR(x2);
|
||||
#else
|
||||
BR(x2);
|
||||
#endif
|
||||
CLEARIP();
|
||||
}
|
||||
|
||||
void iret_to_epilog(dynarec_arm_t* dyn, int ninst, int is64bits)
|
||||
void iret_to_epilog(dynarec_arm_t* dyn, int ninst, int is32bits, int is64bits)
|
||||
{
|
||||
int64_t j64;
|
||||
//#warning TODO: is64bits
|
||||
MAYUSE(ninst);
|
||||
MAYUSE(j64);
|
||||
MESSAGE(LOG_DUMP, "IRet to epilog\n");
|
||||
SMEND();
|
||||
SET_DFNONE(x2);
|
||||
@@ -716,6 +735,12 @@ void iret_to_epilog(dynarec_arm_t* dyn, int ninst, int is64bits)
|
||||
ANDx_REG(xFlags, xFlags, x1);
|
||||
ORRx_mask(xFlags, xFlags, 1, 0b111111, 0); // xFlags | 0b10
|
||||
SET_DFNONE(x1);
|
||||
if(is32bits) {
|
||||
ANDw_mask(x2, x2, 0, 7); // mask 0xff
|
||||
// check if return segment is 64bits, then restore rsp too
|
||||
CMPSw_U12(x2, 0x23);
|
||||
B_MARKSEG(cEQ);
|
||||
}
|
||||
// POP RSP
|
||||
if(is64bits) {
|
||||
POP1(x3); //rsp
|
||||
@@ -729,6 +754,7 @@ void iret_to_epilog(dynarec_arm_t* dyn, int ninst, int is64bits)
|
||||
STRw_U12(xZR, xEmu, offsetof(x64emu_t, segs_serial[_SS]));
|
||||
// set new RSP
|
||||
MOVx_REG(xRSP, x3);
|
||||
MARKSEG;
|
||||
// Ret....
|
||||
MOV64x(x2, (uintptr_t)arm64_epilog); // epilog on purpose, CS might have changed!
|
||||
BR(x2);
|
||||
@@ -738,6 +764,9 @@ void iret_to_epilog(dynarec_arm_t* dyn, int ninst, int is64bits)
|
||||
void call_c(dynarec_arm_t* dyn, int ninst, void* fnc, int reg, int ret, int saveflags, int savereg)
|
||||
{
|
||||
MAYUSE(fnc);
|
||||
#if STEP == 0
|
||||
dyn->insts[ninst].nat_flags_op = NAT_FLAG_OP_UNUSABLE;
|
||||
#endif
|
||||
if(savereg==0)
|
||||
savereg = 7;
|
||||
if(saveflags) {
|
||||
@@ -783,6 +812,9 @@ void call_c(dynarec_arm_t* dyn, int ninst, void* fnc, int reg, int ret, int save
|
||||
void call_n(dynarec_arm_t* dyn, int ninst, void* fnc, int w)
|
||||
{
|
||||
MAYUSE(fnc);
|
||||
#if STEP == 0
|
||||
dyn->insts[ninst].nat_flags_op = NAT_FLAG_OP_UNUSABLE;
|
||||
#endif
|
||||
STRx_U12(xFlags, xEmu, offsetof(x64emu_t, eflags));
|
||||
fpu_pushcache(dyn, ninst, x3, 1);
|
||||
// x9..x15, x16,x17,x18 those needs to be saved by caller
|
||||
@@ -832,18 +864,18 @@ void grab_segdata(dynarec_arm_t* dyn, uintptr_t addr, int ninst, int reg, int se
|
||||
int64_t j64;
|
||||
MAYUSE(j64);
|
||||
MESSAGE(LOG_DUMP, "Get %s Offset\n", (segment==_FS)?"FS":"GS");
|
||||
int t1 = x1, t2 = x4;
|
||||
if(reg==t1) ++t1;
|
||||
int t2 = x4;
|
||||
if(reg==t2) ++t2;
|
||||
LDRw_U12(t2, xEmu, offsetof(x64emu_t, segs_serial[segment]));
|
||||
LDRx_U12(reg, xEmu, offsetof(x64emu_t, segs_offs[segment]));
|
||||
if(segment==_GS) {
|
||||
LDRx_U12(reg, xEmu, offsetof(x64emu_t, segs_offs[segment]));
|
||||
CBNZw_MARKSEG(t2); // fast check
|
||||
} else {
|
||||
LDRx_U12(t1, xEmu, offsetof(x64emu_t, context));
|
||||
LDRw_U12(t1, t1, offsetof(box64context_t, sel_serial));
|
||||
SUBw_REG(t1, t1, t2);
|
||||
CBZw_MARKSEG(t1);
|
||||
LDRx_U12(reg, xEmu, offsetof(x64emu_t, context));
|
||||
LDRw_U12(reg, reg, offsetof(box64context_t, sel_serial));
|
||||
SUBw_REG(t2, reg, t2);
|
||||
LDRx_U12(reg, xEmu, offsetof(x64emu_t, segs_offs[segment]));
|
||||
CBZw_MARKSEG(t2);
|
||||
}
|
||||
MOVZw(x1, segment);
|
||||
call_c(dyn, ninst, GetSegmentBaseEmu, t2, reg, 1, 0);
|
||||
@@ -2322,7 +2354,7 @@ static void flagsCacheTransform(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
if(dyn->f.dfnone || (dyn->insts[jmp].f_exit.dfnone_here && !dyn->insts[jmp].x64.use_flags)) // flags are fully known, nothing we can do more
|
||||
return;
|
||||
MESSAGE(LOG_DUMP, "\tFlags fetch ---- ninst=%d -> %d\n", ninst, jmp);
|
||||
int go = (dyn->insts[jmp].f_entry.dfnone && !dyn->f.dfnone)?1:0;
|
||||
int go = (dyn->insts[jmp].f_entry.dfnone && !dyn->f.dfnone && !dyn->insts[jmp].df_notneeded)?1:0;
|
||||
switch (dyn->insts[jmp].f_entry.pending) {
|
||||
case SF_UNKNOWN: break;
|
||||
case SF_SET:
|
||||
@@ -2332,8 +2364,17 @@ static void flagsCacheTransform(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
case SF_SET_PENDING:
|
||||
if(dyn->f.pending!=SF_SET
|
||||
&& dyn->f.pending!=SF_SET_PENDING
|
||||
&& dyn->f.pending!=SF_PENDING)
|
||||
go = 1;
|
||||
&& dyn->f.pending!=SF_PENDING
|
||||
) {
|
||||
// only sync if some previous flags are used or if all flags are not regenerated at the instuction
|
||||
if(dyn->insts[jmp].x64.use_flags || (dyn->insts[jmp].x64.set_flags!=X_ALL))
|
||||
go = 1;
|
||||
else if(go) {
|
||||
// just clear df flags
|
||||
go = 0;
|
||||
STRw_U12(xZR, xEmu, offsetof(x64emu_t, df));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SF_PENDING:
|
||||
if(dyn->f.pending!=SF_SET
|
||||
@@ -2350,16 +2391,100 @@ static void flagsCacheTransform(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
j64 = (GETMARKF2)-(dyn->native_size);
|
||||
CBZw(s1, j64);
|
||||
}
|
||||
CALL_(UpdateFlags, -1, 0);
|
||||
if(dyn->insts[ninst].need_nat_flags)
|
||||
MRS_nzcv(s1);
|
||||
CALL_(UpdateFlags, -1, s1);
|
||||
if(dyn->insts[ninst].need_nat_flags)
|
||||
MSR_nzcv(s1);
|
||||
MARKF2;
|
||||
}
|
||||
}
|
||||
|
||||
static void nativeFlagsTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2)
|
||||
{
|
||||
int j64;
|
||||
int jmp = dyn->insts[ninst].x64.jmp_insts;
|
||||
if(jmp<0)
|
||||
return;
|
||||
uint8_t flags_before = dyn->insts[ninst].need_nat_flags;
|
||||
uint8_t nc_before = dyn->insts[ninst].normal_carry;
|
||||
if(dyn->insts[ninst].invert_carry)
|
||||
nc_before = 0;
|
||||
uint8_t flags_after = dyn->insts[jmp].need_nat_flags;
|
||||
uint8_t nc_after = dyn->insts[jmp].normal_carry;
|
||||
if(dyn->insts[jmp].nat_flags_op==NAT_FLAG_OP_TOUCH) {
|
||||
flags_after = dyn->insts[jmp].before_nat_flags;
|
||||
nc_after = dyn->insts[jmp].normal_carry_before;
|
||||
}
|
||||
uint8_t flags_x86 = flag2native(dyn->insts[jmp].x64.need_before);
|
||||
flags_x86 &= ~flags_after;
|
||||
MESSAGE(LOG_DUMP, "\tNative Flags transform ---- ninst=%d -> %d %hhx -> %hhx/%hhx\n", ninst, jmp, flags_before, flags_after, flags_x86);
|
||||
// flags present in before and missing in after
|
||||
if((flags_before&NF_EQ) && (flags_x86&NF_EQ)) {
|
||||
CSETw(s1, cEQ);
|
||||
BFIw(xFlags, s1, F_ZF, 1);
|
||||
}
|
||||
if((flags_before&NF_SF) && (flags_x86&NF_SF)) {
|
||||
CSETw(s1, cMI);
|
||||
BFIw(xFlags, s1, F_SF, 1);
|
||||
}
|
||||
if((flags_before&NF_VF) && (flags_x86&NF_VF)) {
|
||||
CSETw(s1, cVS);
|
||||
BFIw(xFlags, s1, F_OF, 1);
|
||||
}
|
||||
if((flags_before&NF_CF) && (flags_x86&NF_CF)) {
|
||||
if(nc_before) // might need to invert carry
|
||||
CSETw(s1, cCS);
|
||||
else
|
||||
CSETw(s1, cCC);
|
||||
BFIw(xFlags, s1, F_CF, 1);
|
||||
}
|
||||
// flags missing and needed later
|
||||
int mrs = 0;
|
||||
#define GO_MRS(A) if(!mrs) {mrs=1; MRS_nzcv(s2); }
|
||||
if(!(flags_before&NF_EQ) && (flags_after&NF_EQ)) {
|
||||
GO_MRS(s2);
|
||||
UBFXw(s1, xFlags, F_ZF, 1);
|
||||
BFIx(s2, s1, NZCV_Z, 1);
|
||||
}
|
||||
if(!(flags_before&NF_SF) && (flags_after&NF_SF)) {
|
||||
GO_MRS(s2);
|
||||
UBFXw(s1, xFlags, F_SF, 1);
|
||||
BFIx(s2, s1, NZCV_N, 1);
|
||||
}
|
||||
if(!(flags_before&NF_VF) && (flags_after&NF_VF)) {
|
||||
GO_MRS(s2);
|
||||
UBFXw(s1, xFlags, F_OF, 1);
|
||||
BFIx(s2, s1, NZCV_V, 1);
|
||||
}
|
||||
if(!(flags_before&NF_CF) && (flags_after&NF_CF)) {
|
||||
GO_MRS(s2);
|
||||
BFIx(s2, xFlags, NZCV_C, 1); // F_CF is bit 0
|
||||
if(!nc_after)
|
||||
EORx_mask(s2, s2, 1, 35, 0); //mask=1<<NZCV_C
|
||||
}
|
||||
// special case for NF_CF changing state
|
||||
if((flags_before&NF_CF) && (flags_after&NF_CF) && (nc_before!=nc_after)) {
|
||||
if(arm64_flagm && !mrs) {
|
||||
CFINV();
|
||||
} else {
|
||||
GO_MRS(s2);
|
||||
EORx_mask(s2, s2, 1, 35, 0); //mask=1<<NZCV_C
|
||||
}
|
||||
}
|
||||
#undef GL_MRS
|
||||
if(mrs) MSR_nzcv(s2);
|
||||
|
||||
MESSAGE(LOG_DUMP, "\t---- Native Flags transform\n");
|
||||
}
|
||||
|
||||
void CacheTransform(dynarec_arm_t* dyn, int ninst, int cacheupd, int s1, int s2, int s3) {
|
||||
if(cacheupd&1)
|
||||
flagsCacheTransform(dyn, ninst, s1);
|
||||
if(cacheupd&2)
|
||||
fpuCacheTransform(dyn, ninst, s1, s2, s3);
|
||||
if(cacheupd&4)
|
||||
nativeFlagsTransform(dyn, ninst, s1, s2);
|
||||
}
|
||||
|
||||
void fpu_reflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -2,10 +2,14 @@
|
||||
|
||||
#include "arm64_emitter.h"
|
||||
|
||||
#define EMIT(A) *block = (A); ++block
|
||||
#define EMIT(A) \
|
||||
do { \
|
||||
*block = (A); \
|
||||
++block; \
|
||||
} while (0)
|
||||
void CreateJmpNext(void* addr, void* next)
|
||||
{
|
||||
uint32_t* block = (uint32_t*)addr;
|
||||
LDRx_literal(x2, (intptr_t)next - (intptr_t)addr);
|
||||
BR(x2);
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,6 @@
|
||||
#define EMIT(A) dyn->native_size+=4
|
||||
#define JUMP(A, C) add_jump(dyn, ninst); add_next(dyn, (uintptr_t)A); SMEND(); dyn->insts[ninst].x64.jmp = A; dyn->insts[ninst].x64.jmp_cond = C; dyn->insts[ninst].x64.jmp_insts = 0
|
||||
#define BARRIER(A) if(A!=BARRIER_MAYBE) {fpu_purgecache(dyn, ninst, 0, x1, x2, x3); dyn->insts[ninst].x64.barrier = A;} else dyn->insts[ninst].barrier_maybe = 1
|
||||
#define BARRIER_NEXT(A) dyn->insts[ninst].x64.barrier_next = A
|
||||
#define SET_HASCALLRET() dyn->insts[ninst].x64.has_callret = 1
|
||||
#define NEW_INST \
|
||||
++dyn->size; \
|
||||
@@ -31,12 +30,14 @@
|
||||
#define INST_EPILOG \
|
||||
dyn->insts[ninst].f_exit = dyn->f; \
|
||||
dyn->insts[ninst].n = dyn->n; \
|
||||
if(dyn->insts[ninst].nat_flags_op==NAT_FLAG_OP_TOUCH && !dyn->insts[ninst].set_nat_flags) \
|
||||
dyn->insts[ninst].nat_flags_op=NAT_FLAG_OP_UNUSABLE; \
|
||||
dyn->insts[ninst].x64.has_next = (ok>0)?1:0;
|
||||
#define INST_NAME(name)
|
||||
#define DEFAULT \
|
||||
--dyn->size; \
|
||||
*ok = -1; \
|
||||
if(box64_dynarec_log>=LOG_INFO || box64_dynarec_dump || box64_dynarec_missing) {\
|
||||
if(box64_dynarec_log>=LOG_INFO || box64_dynarec_dump || box64_dynarec_missing==1) {\
|
||||
dynarec_log(LOG_NONE, "%p: Dynarec stopped because of %sOpcode %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", \
|
||||
(void*)ip, rex.is32bits?"x86 ":"x64 ",\
|
||||
PKip(0), \
|
||||
@@ -48,3 +49,18 @@
|
||||
printFunctionAddr(ip, " => "); \
|
||||
dynarec_log(LOG_NONE, "\n"); \
|
||||
}
|
||||
|
||||
#define FEMIT(A) dyn->insts[ninst].nat_flags_op = dyn->insts[ninst].x64.set_flags?NAT_FLAG_OP_TOUCH:NAT_FLAG_OP_UNUSABLE
|
||||
#define IFNATIVE(A) if(mark_natflag(dyn, ninst, A, 0))
|
||||
#define IFNATIVEN(A) if(mark_natflag(dyn, ninst, A, 0))
|
||||
#define IFX(A) if((dyn->insts[ninst].x64.set_flags&(A)))
|
||||
#define IFX2(A, B) if((dyn->insts[ninst].x64.set_flags&(A)) B)
|
||||
#define IFX_PENDOR0 if((dyn->insts[ninst].x64.set_flags&(X_PEND) || !dyn->insts[ninst].x64.set_flags))
|
||||
#define IFXX(A) if((dyn->insts[ninst].x64.set_flags==(A)))
|
||||
#define IFX2X(A, B) if((dyn->insts[ninst].x64.set_flags==(A) || dyn->insts[ninst].x64.set_flags==(B) || dyn->insts[ninst].x64.set_flags==((A)|(B))))
|
||||
#define IFXN(A, B) if((dyn->insts[ninst].x64.set_flags&(A) && !(dyn->insts[ninst].x64.set_flags&(B))))
|
||||
#define IFXNATIVE(X, N) if((dyn->insts[ninst].x64.set_flags&(X)) && mark_natflag(dyn, ninst, N, 0))
|
||||
#define GEN_INVERTED_CARRY() dyn->insts[ninst].gen_inverted_carry = 1
|
||||
#define IFNATIVE_BEFORE(A) if(mark_natflag(dyn, ninst, A, 1))
|
||||
#define INVERT_CARRY(A) dyn->insts[ninst].invert_carry = 1
|
||||
#define INVERT_CARRY_BEFORE(A) dyn->insts[ninst].invert_carry_before = 1
|
||||
@@ -2,6 +2,16 @@
|
||||
#define FINI
|
||||
#define MESSAGE(A, ...) do {} while (0)
|
||||
#define EMIT(A) do {} while (0)
|
||||
#define MAYSETFLAGS() dyn->insts[ninst].x64.may_set = 1
|
||||
#define SET_NODF() \
|
||||
if(!dyn->insts[ninst].x64.gen_flags && !dyn->insts[ninst].x64.use_flags) \
|
||||
propagate_nodf(dyn, ninst); \
|
||||
dyn->f.dfnone = 0
|
||||
#define SETFLAGS(A,B) \
|
||||
dyn->insts[ninst].x64.set_flags = A; \
|
||||
dyn->insts[ninst].x64.state_flags = (B)&~SF_DF; \
|
||||
dyn->f.pending=(B)&SF_SET_PENDING; \
|
||||
dyn->f.dfnone=((B)&SF_SET)?(((B)==SF_SET_NODF)?0:1):0;
|
||||
#define NEW_INST \
|
||||
dyn->insts[ninst].f_entry = dyn->f; \
|
||||
dyn->n.combined1 = dyn->n.combined2 = 0;\
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#define MESSAGE(A, ...) if(box64_dynarec_dump) dynarec_log(LOG_NONE, __VA_ARGS__)
|
||||
#define NEW_INST \
|
||||
if(ninst) { \
|
||||
if(dyn->insts[ninst].address!=(uintptr_t)dyn->block-(uintptr_t)dyn->native_start) dyn->abort = 1; \
|
||||
addInst(dyn->instsize, &dyn->insts_size, dyn->insts[ninst-1].x64.size, dyn->insts[ninst-1].size/4); \
|
||||
dyn->insts[ninst].ymm0_pass3 = dyn->ymm_zero; \
|
||||
}
|
||||
|
||||
@@ -9,6 +9,20 @@ typedef struct instsize_s instsize_t;
|
||||
|
||||
#define BARRIER_MAYBE 8
|
||||
|
||||
#define NF_EQ (1<<0)
|
||||
#define NF_SF (1<<1)
|
||||
#define NF_VF (1<<2)
|
||||
#define NF_CF (1<<3)
|
||||
|
||||
// Nothing happens to the native flags
|
||||
#define NAT_FLAG_OP_NONE 0
|
||||
// Native flags are touched on this opcode
|
||||
#define NAT_FLAG_OP_TOUCH 1
|
||||
// Native flags are destroyed and unusable
|
||||
#define NAT_FLAG_OP_UNUSABLE 2
|
||||
// Native flags usaged are canceled here
|
||||
#define NAT_FLAG_OP_CANCELED 3
|
||||
|
||||
#define NEON_CACHE_NONE 0
|
||||
#define NEON_CACHE_ST_D 1
|
||||
#define NEON_CACHE_ST_F 2
|
||||
@@ -89,11 +103,25 @@ typedef struct instruction_arm64_s {
|
||||
uint16_t ymm0_in; // bitmap of ymm to zero at purge
|
||||
uint16_t ymm0_add; // the ymm0 added by the opcode
|
||||
uint16_t ymm0_sub; // the ymm0 removed by the opcode
|
||||
uint16_t ymm0_out; // the ymmm0 at th end of the opcode
|
||||
uint16_t ymm0_out; // the ymm0 at th end of the opcode
|
||||
uint16_t ymm0_pass2, ymm0_pass3;
|
||||
uint8_t barrier_maybe;
|
||||
uint8_t will_write;
|
||||
uint8_t last_write;
|
||||
uint8_t will_write:2; // [strongmem] will write to memory
|
||||
uint8_t last_write:1; // [strongmem] the last write in a SEQ
|
||||
uint8_t lock:1; // [strongmem] lock semantic
|
||||
uint8_t wfe:1; // opcode uses sevl + wfe
|
||||
uint8_t set_nat_flags; // 0 or combinaison of native flags define
|
||||
uint8_t use_nat_flags; // 0 or combinaison of native flags define
|
||||
uint8_t use_nat_flags_before; // 0 or combinaison of native flags define
|
||||
uint8_t nat_flags_op:4;// what happens to native flags here
|
||||
uint8_t nat_flags_op_before:4;// what happens to native flags here
|
||||
uint8_t before_nat_flags; // 0 or combinaison of native flags define
|
||||
uint8_t need_nat_flags;
|
||||
unsigned gen_inverted_carry:1;
|
||||
unsigned normal_carry:1;
|
||||
unsigned normal_carry_before:1;
|
||||
unsigned invert_carry:1; // this opcode force an inverted carry
|
||||
unsigned df_notneeded:1;
|
||||
flagcache_t f_exit; // flags status at end of instruction
|
||||
neoncache_t n; // neoncache at end of instruction (but before poping)
|
||||
flagcache_t f_entry; // flags status before the instruction begin
|
||||
@@ -132,7 +160,6 @@ typedef struct dynarec_arm_s {
|
||||
int forward_ninst; // ninst at the forward point
|
||||
uint16_t ymm_zero; // bitmap of ymm to zero at purge
|
||||
uint8_t smwrite; // for strongmem model emulation
|
||||
uint8_t smread;
|
||||
uint8_t doublepush;
|
||||
uint8_t doublepop;
|
||||
uint8_t always_test;
|
||||
@@ -154,9 +181,11 @@ void CreateJmpNext(void* addr, void* next);
|
||||
#define GO_TRACE(A, B, s0) \
|
||||
GETIP(addr); \
|
||||
MOVx_REG(x1, xRIP); \
|
||||
MRS_nzcv(s0); \
|
||||
STORE_XEMU_CALL(xRIP); \
|
||||
MOV32w(x2, B); \
|
||||
CALL(A, -1); \
|
||||
CALL_(A, -1, s0); \
|
||||
MSR_nzcv(s0); \
|
||||
LOAD_XEMU_CALL(xRIP)
|
||||
|
||||
#endif //__DYNAREC_ARM_PRIVATE_H_
|
||||
+13
-2
@@ -19,6 +19,7 @@
|
||||
#include "dynarec_private.h"
|
||||
#include "elfloader.h"
|
||||
#include "bridge.h"
|
||||
#include "signals.h"
|
||||
|
||||
#include "dynarec_native.h"
|
||||
#include "native_lock.h"
|
||||
@@ -198,9 +199,13 @@ static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t
|
||||
{
|
||||
if(hasAlternate((void*)addr))
|
||||
return NULL;
|
||||
const uint32_t req_prot = (box64_pagesize==4096)?(PROT_EXEC|PROT_READ):PROT_READ;
|
||||
dynablock_t* block = getDB(addr);
|
||||
if(block || !create)
|
||||
if(block || !create) {
|
||||
if(block && getNeedTest(addr) && (getProtection(addr)&req_prot)!=req_prot)
|
||||
block = NULL;
|
||||
return block;
|
||||
}
|
||||
|
||||
if(need_lock) {
|
||||
if(box64_dynarec_wait) {
|
||||
@@ -211,11 +216,17 @@ static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t
|
||||
}
|
||||
block = getDB(addr); // just in case
|
||||
if(block) {
|
||||
if(block && getNeedTest(addr) && (getProtection_fast(addr)&req_prot)!=req_prot)
|
||||
block = NULL;
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
return block;
|
||||
}
|
||||
}
|
||||
|
||||
if((getProtection_fast(addr)&req_prot)!=req_prot) {// cannot be run, get out of the Dynarec
|
||||
if(need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
return NULL;
|
||||
}
|
||||
block = AddNewDynablock(addr);
|
||||
|
||||
// fill the block
|
||||
|
||||
@@ -10,14 +10,15 @@ typedef struct dynablock_s {
|
||||
void* block; // block-sizeof(void*) == self
|
||||
void* actual_block; // the actual start of the block (so block-sizeof(void*))
|
||||
struct dynablock_s* previous; // a previous block that might need to be freed
|
||||
int size;
|
||||
void* x64_addr;
|
||||
uintptr_t x64_size;
|
||||
int size;
|
||||
uint32_t hash;
|
||||
uint8_t done;
|
||||
uint8_t gone;
|
||||
uint8_t always_test;
|
||||
uint8_t dirty; // if need to be tested as soon as it's created
|
||||
uint8_t always_test:1;
|
||||
uint8_t is32bits:1;
|
||||
int isize;
|
||||
instsize_t* instsize;
|
||||
void* jmpnext; // a branch jmpnext code when block is marked
|
||||
|
||||
+46
-16
@@ -34,10 +34,18 @@ void* LinkNext(x64emu_t* emu, uintptr_t addr, void* x2, uintptr_t* x3)
|
||||
#ifdef HAVE_TRACE
|
||||
if(!addr) {
|
||||
dynablock_t* db = FindDynablockFromNativeAddress(x2-4);
|
||||
printf_log(LOG_NONE, "Warning, jumping to NULL address from %p (db=%p, x64addr=%p/%s)\n", x2-4, db, db?(void*)getX64Address(db, (uintptr_t)x2-4):NULL, db?getAddrFunctionName(getX64Address(db, (uintptr_t)x2-4)):"(nil)");
|
||||
printf_log(LOG_INFO, "Warning, jumping to NULL address from %p (db=%p, x64addr=%p/%s)\n", x2-4, db, db?(void*)getX64Address(db, (uintptr_t)x2-4):NULL, db?getAddrFunctionName(getX64Address(db, (uintptr_t)x2-4)):"(nil)");
|
||||
} else if(addr<0x10000) {
|
||||
dynablock_t* db = FindDynablockFromNativeAddress(x2-4);
|
||||
printf_log(LOG_NONE, "Warning, jumping to low address %p from %p (db=%p, x64addr=%p/%s)\n", (void*)addr, x2-4, db, db?(void*)getX64Address(db, (uintptr_t)x2-4):NULL, db?getAddrFunctionName(getX64Address(db, (uintptr_t)x2-4)):"(nil)");
|
||||
printf_log(LOG_INFO, "Warning, jumping to low address %p from %p (db=%p, x64addr=%p/%s)\n", (void*)addr, x2-4, db, db?(void*)getX64Address(db, (uintptr_t)x2-4):NULL, db?getAddrFunctionName(getX64Address(db, (uintptr_t)x2-4)):"(nil)");
|
||||
#ifdef BOX32
|
||||
} else if(emu->segs[_CS]==0x23 && addr>0x100000000LL) {
|
||||
dynablock_t* db = FindDynablockFromNativeAddress(x2-4);
|
||||
printf_log(LOG_INFO, "Warning, jumping to high address %p from %p (db=%p, x64addr=%p/%s)\n", (void*)addr, x2-4, db, db?(void*)getX64Address(db, (uintptr_t)x2-4):NULL, db?getAddrFunctionName(getX64Address(db, (uintptr_t)x2-4)):"(nil)");
|
||||
} else if(!memExist(addr)) {
|
||||
dynablock_t* db = FindDynablockFromNativeAddress(x2-4);
|
||||
printf_log(LOG_INFO, "Warning, jumping to an unmapped address %p from %p (db=%p, x64addr=%p/%s)\n", (void*)addr, x2-4, db, db?(void*)getX64Address(db, (uintptr_t)x2-4):NULL, db?getAddrFunctionName(getX64Address(db, (uintptr_t)x2-4)):"(nil)");
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
void * jblock;
|
||||
@@ -95,19 +103,22 @@ void DynaCall(x64emu_t* emu, uintptr_t addr)
|
||||
uint64_t old_rsi = R_RSI;
|
||||
uint64_t old_rbp = R_RBP;
|
||||
uint64_t old_rip = R_RIP;
|
||||
x64flags_t old_eflags = emu->eflags;
|
||||
// save defered flags
|
||||
deferred_flags_t old_df = emu->df;
|
||||
multiuint_t old_op1 = emu->op1;
|
||||
multiuint_t old_op2 = emu->op2;
|
||||
multiuint_t old_res = emu->res;
|
||||
multiuint_t old_op1_sav= emu->op1_sav;
|
||||
multiuint_t old_res_sav= emu->res_sav;
|
||||
deferred_flags_t old_df_sav= emu->df_sav;
|
||||
// uc_link
|
||||
x64_ucontext_t* old_uc_link = emu->uc_link;
|
||||
void* old_uc_link = emu->uc_link;
|
||||
emu->uc_link = NULL;
|
||||
|
||||
PushExit(emu);
|
||||
#ifdef BOX32
|
||||
if(box64_is32bits)
|
||||
PushExit_32(emu);
|
||||
else
|
||||
#endif
|
||||
PushExit(emu);
|
||||
R_RIP = addr;
|
||||
emu->df = d_none;
|
||||
DynaRun(emu);
|
||||
@@ -123,10 +134,8 @@ void DynaCall(x64emu_t* emu, uintptr_t addr)
|
||||
emu->op1 = old_op1;
|
||||
emu->op2 = old_op2;
|
||||
emu->res = old_res;
|
||||
emu->op1_sav = old_op1_sav;
|
||||
emu->res_sav = old_res_sav;
|
||||
emu->df_sav = old_df_sav;
|
||||
// and the old registers
|
||||
emu->eflags = old_eflags;
|
||||
R_RBX = old_rbx;
|
||||
R_RDI = old_rdi;
|
||||
R_RSI = old_rsi;
|
||||
@@ -137,6 +146,10 @@ void DynaCall(x64emu_t* emu, uintptr_t addr)
|
||||
}
|
||||
|
||||
int my_setcontext(x64emu_t* emu, void* ucp);
|
||||
#ifdef BOX32
|
||||
int my32_setcontext(x64emu_t* emu, void* ucp);
|
||||
#endif
|
||||
extern int running32bits;
|
||||
void DynaRun(x64emu_t* emu)
|
||||
{
|
||||
// prepare setjump for signal handling
|
||||
@@ -147,7 +160,7 @@ void DynaRun(x64emu_t* emu)
|
||||
uintptr_t old_savesp = emu->xSPSave;
|
||||
#endif
|
||||
emu->flags.jmpbuf_ready = 0;
|
||||
|
||||
int is32bits = (emu->segs[_CS]==0x23);
|
||||
while(!(emu->quit)) {
|
||||
if(!emu->jmpbuf || (emu->flags.need_jmpbuf && emu->jmpbuf!=jmpbuf)) {
|
||||
emu->jmpbuf = jmpbuf;
|
||||
@@ -180,7 +193,22 @@ void DynaRun(x64emu_t* emu)
|
||||
Run(emu, 0);
|
||||
#ifdef DYNAREC
|
||||
else {
|
||||
int is32bits = (emu->segs[_CS]==0x23);
|
||||
int newis32bits = (emu->segs[_CS]==0x23);
|
||||
if(newis32bits!=is32bits) {
|
||||
is32bits = newis32bits;
|
||||
if(is32bits) {
|
||||
// Zero upper part of the 32bits regs
|
||||
R_RAX = R_EAX;
|
||||
R_RBX = R_EBX;
|
||||
R_RCX = R_ECX;
|
||||
R_RDX = R_EDX;
|
||||
R_RSP = R_ESP;
|
||||
R_RBP = R_EBP;
|
||||
R_RSI = R_ESI;
|
||||
R_RDI = R_EDI;
|
||||
running32bits = 1;
|
||||
}
|
||||
}
|
||||
dynablock_t* block = (skip)?NULL:DBGetBlock(emu, R_RIP, 1, is32bits);
|
||||
if(!block || !block->block || !block->done || ACCESS_FLAG(F_TF)) {
|
||||
skip = 0;
|
||||
@@ -194,9 +222,6 @@ void DynaRun(x64emu_t* emu)
|
||||
dynarec_log(LOG_DEBUG, "%04d|Running DynaRec Block @%p (%p) of %d x64 insts (hash=0x%x) emu=%p\n", GetTID(), (void*)R_RIP, block->block, block->isize, block->hash, emu);
|
||||
// block is here, let's run it!
|
||||
native_prolog(emu, block->block);
|
||||
extern int running32bits;
|
||||
if(emu->segs[_CS]==0x23)
|
||||
running32bits = 1;
|
||||
}
|
||||
if(emu->fork) {
|
||||
int forktype = emu->fork;
|
||||
@@ -206,7 +231,12 @@ void DynaRun(x64emu_t* emu)
|
||||
}
|
||||
if(emu->quit && emu->uc_link) {
|
||||
emu->quit = 0;
|
||||
my_setcontext(emu, emu->uc_link);
|
||||
#ifdef BOX32
|
||||
if(box64_is32bits)
|
||||
my32_setcontext(emu, emu->uc_link);
|
||||
else
|
||||
#endif
|
||||
my_setcontext(emu, emu->uc_link);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -9,14 +9,20 @@
|
||||
#define ADDITIONNAL_DEFINITION() \
|
||||
int fpuCacheNeedsTransform(dynarec_native_t* dyn, int ninst);
|
||||
|
||||
#define OTHER_CACHE() \
|
||||
if (fpuCacheNeedsTransform(dyn, ninst)) ret|=2;
|
||||
#define OTHER_CACHE() \
|
||||
if (fpuCacheNeedsTransform(dyn, ninst)) ret|=2; \
|
||||
if (nativeFlagsNeedsTransform(dyn, ninst)) ret|=4;
|
||||
|
||||
#include "arm64/arm64_printer.h"
|
||||
#include "arm64/dynarec_arm64_private.h"
|
||||
#include "arm64/dynarec_arm64_functions.h"
|
||||
// Limit here is defined by LD litteral, that is 19bits
|
||||
#define MAXBLOCK_SIZE ((1<<19)-200)
|
||||
|
||||
#define RAZ_SPECIFIC(A, N) rasNativeState(A, N)
|
||||
#define UPDATE_SPECIFICS(A) updateNativeFlags(A)
|
||||
#define PREUPDATE_SPECIFICS(A)
|
||||
|
||||
#elif defined(LA64)
|
||||
|
||||
#define instruction_native_t instruction_la64_t
|
||||
@@ -33,22 +39,32 @@
|
||||
#include "la64/dynarec_la64_functions.h"
|
||||
// Limit here is unconditionnal jump, that is signed 28bits
|
||||
#define MAXBLOCK_SIZE ((1 << 27) - 200)
|
||||
|
||||
#define RAZ_SPECIFIC(A, N)
|
||||
#define UPDATE_SPECIFICS(A)
|
||||
#define PREUPDATE_SPECIFICS(A)
|
||||
#elif defined(RV64)
|
||||
|
||||
#define instruction_native_t instruction_rv64_t
|
||||
#define dynarec_native_t dynarec_rv64_t
|
||||
|
||||
#define ADDITIONNAL_DEFINITION() \
|
||||
int fpuCacheNeedsTransform(dynarec_native_t* dyn, int ninst);
|
||||
#define ADDITIONNAL_DEFINITION() \
|
||||
int fpuCacheNeedsTransform(dynarec_native_t* dyn, int ninst); \
|
||||
int sewNeedsTransform(dynarec_rv64_t* dyn, int ninst);
|
||||
|
||||
#define OTHER_CACHE() \
|
||||
if (fpuCacheNeedsTransform(dyn, ninst)) ret|=2;
|
||||
#define OTHER_CACHE() \
|
||||
if (fpuCacheNeedsTransform(dyn, ninst)) ret |= 2; \
|
||||
if (sewNeedsTransform(dyn, ninst)) ret |= 4;
|
||||
|
||||
#include "rv64/rv64_printer.h"
|
||||
#include "rv64/dynarec_rv64_private.h"
|
||||
#include "rv64/dynarec_rv64_functions.h"
|
||||
// Limit here is unconditionnal jump, that is signed 21bits
|
||||
#define MAXBLOCK_SIZE ((1<<20)-200)
|
||||
|
||||
#define RAZ_SPECIFIC(A, N)
|
||||
#define UPDATE_SPECIFICS(A)
|
||||
#define PREUPDATE_SPECIFICS(A) updateNativeFlags(A)
|
||||
#else
|
||||
#error Unsupported platform
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,189 @@
|
||||
#ifndef __DYNAREC_HELPER__H_
|
||||
#define __DYNAREC_HELPER__H_
|
||||
|
||||
/* Box64 Strong Memory Model Emulation
|
||||
*
|
||||
* Definition of a SEQ:
|
||||
* A SEQ is a sequence of opcodes that writes to guest memory, terminated by JMP, RET, CALL, etc.
|
||||
*
|
||||
* Memory barriers are added in the following cases to emulate the strong memory model:
|
||||
* 1. End of a SEQ:
|
||||
* - Scalar operations (a1)
|
||||
* - SIMD operations (a2)
|
||||
* 2. Start of a SEQ:
|
||||
* - Scalar operations (b1)
|
||||
* - SIMD operations (b2)
|
||||
* 3. Right before the last guest memory store in a SEQ:
|
||||
* - Scalar operations (c1)
|
||||
* - SIMD operations (c2)
|
||||
* 4. After every third guest memory store in a SEQ (d)
|
||||
*
|
||||
* STRONGMEM levels (coarse-grained):
|
||||
* 1: Includes a1, b1, c1
|
||||
* 2: Includes LEVEL1, plus a2, b2, c2
|
||||
* 3: Includes LEVEL2, plus d
|
||||
*
|
||||
* WEAKBARRIER levels (fine-grained):
|
||||
* 1: Use dmb.ishld and dmb.ishst over dmb.ish for more performance
|
||||
* 2. All 1. Plus disabled the last write barriers (c1, c2)
|
||||
*/
|
||||
|
||||
#define STRONGMEM_SIMD_WRITE 2 // The level of SIMD memory writes will be tracked
|
||||
#define STRONGMEM_LAST_WRITE 1 // The level of a barrier before the last guest memory store will be put
|
||||
#define STRONGMEM_SEQ_WRITE 3 // The level of a barrier at every third memory store will be put
|
||||
|
||||
#if STEP == 1
|
||||
|
||||
#define SMWRITE() \
|
||||
do { \
|
||||
/* Mark that current sequence writes to guest memory. */ \
|
||||
/* This will be used in SMEND for last_write. */ \
|
||||
dyn->smwrite = 1; \
|
||||
/* Mark that current opcode writes to guest memory. */ \
|
||||
dyn->insts[ninst].will_write = 1; \
|
||||
} while (0)
|
||||
|
||||
#define SMWRITELOCK(lock) \
|
||||
do { \
|
||||
dyn->insts[ninst].lock = lock; \
|
||||
SMWRITE(); \
|
||||
} while (0)
|
||||
|
||||
#define SMWRITE2() \
|
||||
do { \
|
||||
if (box64_dynarec_strongmem >= STRONGMEM_SIMD_WRITE) { \
|
||||
dyn->smwrite = 1; \
|
||||
dyn->insts[ninst].will_write = 2; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define SMREAD()
|
||||
#define SMREADLOCK(lock)
|
||||
#define WILLWRITE()
|
||||
#define WILLWRITELOCK(lock)
|
||||
|
||||
#define SMSTART() \
|
||||
do { \
|
||||
/* Clear current state at the start of a potential SEQ. */ \
|
||||
dyn->smwrite = 0; \
|
||||
} while (0)
|
||||
|
||||
#define SMEND() \
|
||||
do { \
|
||||
/* If there is any guest memory write, which is a SEQ, then compute the last_write. */ \
|
||||
if (dyn->smwrite && (box64_dynarec_strongmem >= STRONGMEM_LAST_WRITE)) { \
|
||||
int i = ninst; \
|
||||
while (i >= 0 && !dyn->insts[i].will_write) \
|
||||
--i; \
|
||||
if (i >= 0) { dyn->insts[i].last_write = 1; } \
|
||||
} \
|
||||
dyn->smwrite = 0; \
|
||||
} while (0)
|
||||
|
||||
#define SMDMB()
|
||||
|
||||
#else
|
||||
|
||||
// An opcode writes guest memory, this need to be put after the STORE instruction manually.
|
||||
#define SMWRITE() \
|
||||
do { \
|
||||
/* Put a barrier at every third memory write. */ \
|
||||
if (box64_dynarec_strongmem >= STRONGMEM_SEQ_WRITE) { \
|
||||
if (++dyn->smwrite >= 3 /* Every third memory write */) { \
|
||||
DMB_ISH(); \
|
||||
dyn->smwrite = 1; \
|
||||
} \
|
||||
} else { \
|
||||
/* Mark that current sequence writes to guest memory. */ \
|
||||
dyn->smwrite = 1; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// Similar to SMWRITE, but checks lock.
|
||||
#define SMWRITELOCK(lock) \
|
||||
do { \
|
||||
if (lock) { \
|
||||
DMB_ISH(); \
|
||||
} else { \
|
||||
SMWRITE(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// Similar to SMWRITE, but for SIMD instructions.
|
||||
#define SMWRITE2() \
|
||||
do { \
|
||||
if (box64_dynarec_strongmem >= STRONGMEM_SIMD_WRITE) \
|
||||
SMWRITE(); \
|
||||
} while (0)
|
||||
|
||||
// An opcode reads guest memory, this need to be put before the LOAD instruction manually.
|
||||
#define SMREAD()
|
||||
|
||||
// Similar to SMREAD, but checks lock.
|
||||
#define SMREADLOCK(lock) \
|
||||
do { \
|
||||
if (lock) { \
|
||||
DMB_ISH(); \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// An opcode will write memory, this will be put before the STORE instruction automatically.
|
||||
#define WILLWRITE() \
|
||||
do { \
|
||||
if (box64_dynarec_strongmem >= dyn->insts[ninst].will_write && dyn->smwrite == 0) { \
|
||||
/* Will write but never written, this is the start of a SEQ, put a barrier. */ \
|
||||
if (box64_dynarec_weakbarrier) \
|
||||
DMB_ISHLD(); \
|
||||
else \
|
||||
DMB_ISH(); \
|
||||
} else if (box64_dynarec_strongmem >= STRONGMEM_LAST_WRITE && box64_dynarec_weakbarrier != 2 \
|
||||
&& dyn->insts[ninst].last_write) { \
|
||||
/* Last write, put a barrier */ \
|
||||
if (box64_dynarec_weakbarrier) \
|
||||
DMB_ISHST(); \
|
||||
else \
|
||||
DMB_ISH(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// Similar to WILLWRITE, but checks lock.
|
||||
#define WILLWRITELOCK(lock) \
|
||||
do { \
|
||||
if (lock) { \
|
||||
DMB_ISH(); \
|
||||
} else { \
|
||||
WILLWRITE(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// Used to clear the state at the start of a SEQ
|
||||
#define SMSTART() \
|
||||
do { \
|
||||
dyn->smwrite = 0; \
|
||||
} while (0)
|
||||
|
||||
// Will be put at the end of the SEQ
|
||||
#define SMEND() \
|
||||
do { \
|
||||
if (box64_dynarec_strongmem) { \
|
||||
/* It's a SEQ, put a barrier here. */ \
|
||||
if (dyn->smwrite) { \
|
||||
/* Check if the next instruction has a end loop mark */ \
|
||||
if (box64_dynarec_weakbarrier) \
|
||||
DMB_ISHST(); \
|
||||
else \
|
||||
DMB_ISH(); \
|
||||
} \
|
||||
} \
|
||||
dyn->smwrite = 0; \
|
||||
} while (0)
|
||||
|
||||
// The barrier.
|
||||
#define SMDMB() DMB_ISH()
|
||||
#endif
|
||||
|
||||
#ifdef ARM64
|
||||
#include "arm64/dynarec_arm64_helper.h"
|
||||
#elif defined(LA64)
|
||||
@@ -11,4 +194,4 @@
|
||||
#error Unsupported architecture
|
||||
#endif
|
||||
|
||||
#endif //__DYNAREC_HELPER__H_
|
||||
#endif //__DYNAREC_HELPER__H_
|
||||
@@ -121,6 +121,8 @@ int is_nops(dynarec_native_t *dyn, uintptr_t addr, int n)
|
||||
return is_nops(dyn, addr+1, n-1);
|
||||
if(n>1 && PK(0)==0x66) // if opcode start with 0x66, and there is more after, than is *can* be a NOP
|
||||
return is_nops(dyn, addr+1, n-1);
|
||||
if(n>1 && PK(0)==0xF3 && PK(1)==0x90)
|
||||
return is_nops(dyn, addr+2, n-2);
|
||||
if(n>2 && PK(0)==0x0f && PK(1)==0x1f && PK(2)==0x00)
|
||||
return is_nops(dyn, addr+3, n-3);
|
||||
if(n>2 && PK(0)==0x8d && PK(1)==0x76 && PK(2)==0x00) // lea esi, [esi]
|
||||
@@ -229,6 +231,14 @@ int next_instruction(dynarec_native_t *dyn, uintptr_t addr)
|
||||
case 0xBE:
|
||||
case 0xBF:
|
||||
return 5;
|
||||
case 0xF3:
|
||||
nextop = PK(1);
|
||||
switch(nextop) {
|
||||
case 0x90:
|
||||
return 2;
|
||||
default: break;
|
||||
}
|
||||
break;
|
||||
case 0xFF:
|
||||
nextop = PK(1);
|
||||
switch((nextop>>3)&7) {
|
||||
@@ -412,8 +422,12 @@ static void updateYmm0s(dynarec_native_t* dyn, int ninst, int max_ninst_reached)
|
||||
//if(box64_dynarec_dump) dynarec_log(LOG_NONE, "update ninst=%d (%d): can_incr=%d\n", ninst, max_ninst_reached, can_incr);
|
||||
uint16_t new_purge_ymm, new_ymm0_in, new_ymm0_out;
|
||||
|
||||
if (ninst && dyn->insts[ninst].pred_sz && dyn->insts[ninst].x64.alive) {
|
||||
uint16_t ymm0_union = 0, ymm0_inter = (uint16_t)-1; // The union of the empty set is empty, the intersection is the universe
|
||||
if (dyn->insts[ninst].pred_sz && dyn->insts[ninst].x64.alive) {
|
||||
// The union of the empty set is empty (0), the intersection is the universe (-1)
|
||||
// The first instruction is the entry point, which has a virtual pred with ymm0_out = 0
|
||||
// Similarly, float barriers reset ymm0s
|
||||
uint16_t ymm0_union = 0;
|
||||
uint16_t ymm0_inter = (ninst && !(dyn->insts[ninst].x64.barrier & BARRIER_FLOAT)) ? ((uint16_t)-1) : (uint16_t)0;
|
||||
for (int i = 0; i < dyn->insts[ninst].pred_sz; ++i) {
|
||||
int pred = dyn->insts[ninst].pred[i];
|
||||
//if(box64_dynarec_dump) dynarec_log(LOG_NONE, "\twith pred[%d] = %d", i, pred);
|
||||
@@ -510,7 +524,7 @@ uintptr_t native_pass1(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
uintptr_t native_pass2(dynarec_native_t* dyn, uintptr_t addr, int alternate, int is32bits);
|
||||
uintptr_t native_pass3(dynarec_native_t* dyn, uintptr_t addr, int alternate, int is32bits);
|
||||
|
||||
void* CreateEmptyBlock(dynablock_t* block, uintptr_t addr) {
|
||||
void* CreateEmptyBlock(dynablock_t* block, uintptr_t addr, int is32bits) {
|
||||
block->isize = 0;
|
||||
block->done = 0;
|
||||
size_t sz = 4*sizeof(void*);
|
||||
@@ -525,6 +539,7 @@ void* CreateEmptyBlock(dynablock_t* block, uintptr_t addr) {
|
||||
block->actual_block = actual_p;
|
||||
block->block = p;
|
||||
block->jmpnext = p;
|
||||
block->is32bits = is32bits;
|
||||
*(dynablock_t**)actual_p = block;
|
||||
*(void**)(p+2*sizeof(void*)) = native_epilog;
|
||||
CreateJmpNext(block->jmpnext, p+2*sizeof(void*));
|
||||
@@ -549,7 +564,7 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
*/
|
||||
if(addr>=box64_nodynarec_start && addr<box64_nodynarec_end) {
|
||||
dynarec_log(LOG_INFO, "Create empty block in no-dynarec zone\n");
|
||||
return CreateEmptyBlock(block, addr);
|
||||
return CreateEmptyBlock(block, addr, is32bits);
|
||||
}
|
||||
if(current_helper) {
|
||||
dynarec_log(LOG_DEBUG, "Canceling dynarec FillBlock at %p as another one is going on\n", (void*)addr);
|
||||
@@ -582,7 +597,7 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
if(!helper.size) {
|
||||
dynarec_log(LOG_INFO, "Warning, null-sized dynarec block (%p)\n", (void*)addr);
|
||||
CancelBlock64(0);
|
||||
return CreateEmptyBlock(block, addr);
|
||||
return CreateEmptyBlock(block, addr, is32bits);
|
||||
}
|
||||
if(!isprotectedDB(addr, 1)) {
|
||||
dynarec_log(LOG_INFO, "Warning, write on current page on pass0, aborting dynablock creation (%p)\n", (void*)addr);
|
||||
@@ -637,6 +652,11 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
if(k!=-1) {
|
||||
if(!helper.insts[i].barrier_maybe)
|
||||
helper.insts[k].x64.barrier |= BARRIER_FULL;
|
||||
// special case, loop on itself with some nop in between
|
||||
if(k<i && !helper.insts[i].x64.has_next && is_nops(&helper, helper.insts[k].x64.addr, helper.insts[i].x64.addr-helper.insts[k].x64.addr)) {
|
||||
helper.always_test = 1;
|
||||
k = -1;
|
||||
}
|
||||
helper.insts[i].x64.jmp_insts = k;
|
||||
}
|
||||
}
|
||||
@@ -649,6 +669,8 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
helper.predecessor = (int*)alloca(alloc_size*sizeof(int));
|
||||
fillPredecessors(&helper);
|
||||
|
||||
PREUPDATE_SPECIFICS(&helper);
|
||||
|
||||
int pos = helper.size;
|
||||
while (pos>=0)
|
||||
pos = updateNeed(&helper, pos, 0);
|
||||
@@ -659,6 +681,7 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
while(ii<helper.size && !helper.insts[ii].pred_sz) {
|
||||
fpu_reset_ninst(&helper, ii);
|
||||
helper.insts[ii].ymm0_in = helper.insts[ii].ymm0_sub = helper.insts[ii].ymm0_add = helper.insts[ii].ymm0_out = helper.insts[ii].purge_ymm = 0;
|
||||
RAZ_SPECIFIC(&helper, ii);
|
||||
++ii;
|
||||
}
|
||||
i = ii;
|
||||
@@ -672,9 +695,10 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
// NULL block after removing dead code, how is that possible?
|
||||
dynarec_log(LOG_INFO, "Warning, null-sized dynarec block after trimming dead code (%p)\n", (void*)addr);
|
||||
CancelBlock64(0);
|
||||
return CreateEmptyBlock(block, addr);
|
||||
return CreateEmptyBlock(block, addr, is32bits);
|
||||
}
|
||||
updateYmm0s(&helper, 0, 0);
|
||||
UPDATE_SPECIFICS(&helper);
|
||||
|
||||
|
||||
// pass 1, float optimizations, first pass for flags
|
||||
@@ -733,7 +757,7 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
helper.insts_size = 0; // reset
|
||||
native_pass3(&helper, addr, alternate, is32bits);
|
||||
if(helper.abort) {
|
||||
if(box64_dynarec_dump || box64_dynarec_log)dynarec_log(LOG_NONE, "Abort dynablock on pass1\n");
|
||||
if(box64_dynarec_dump || box64_dynarec_log)dynarec_log(LOG_NONE, "Abort dynablock on pass3\n");
|
||||
CancelBlock64(0);
|
||||
return NULL;
|
||||
}
|
||||
@@ -751,6 +775,7 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
block->jmpnext = next+sizeof(void*);
|
||||
block->always_test = helper.always_test;
|
||||
block->dirty = block->always_test;
|
||||
block->is32bits = is32bits;
|
||||
*(dynablock_t**)next = block;
|
||||
*(void**)(next+3*sizeof(void*)) = native_next;
|
||||
CreateJmpNext(block->jmpnext, next+3*sizeof(void*));
|
||||
@@ -760,7 +785,7 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
|
||||
__clear_cache(actual_p, actual_p+sz); // need to clear the cache before execution...
|
||||
block->hash = X31_hash_code(block->x64_addr, block->x64_size);
|
||||
// Check if something changed, to abort if it is
|
||||
if((block->hash != hash)) {
|
||||
if((helper.abort || (block->hash != hash))) {
|
||||
dynarec_log(LOG_DEBUG, "Warning, a block changed while being processed hash(%p:%ld)=%x/%x\n", block->x64_addr, block->x64_size, block->hash, hash);
|
||||
CancelBlock64(0);
|
||||
return NULL;
|
||||
|
||||
@@ -59,10 +59,20 @@ void native_fpatan(x64emu_t* emu)
|
||||
}
|
||||
void native_fxtract(x64emu_t* emu)
|
||||
{
|
||||
int32_t tmp32s = (ST1.q&0x7ff0000000000000LL)>>52;
|
||||
tmp32s -= 1023;
|
||||
ST1.d /= exp2(tmp32s);
|
||||
ST0.d = tmp32s;
|
||||
int tmp32s;
|
||||
if(isnan(ST1.d)) {
|
||||
ST0.d = ST1.d;
|
||||
} else if(isinf(ST1.d)) {
|
||||
ST0.d = ST1.d;
|
||||
ST1.d = INFINITY;
|
||||
} else if(ST1.d==0.0) {
|
||||
ST0.d = ST1.d;
|
||||
ST1.d = -INFINITY;
|
||||
} else {
|
||||
// LD80bits doesn't have implicit "1" bit, so need to adjust for that
|
||||
ST0.d = frexp(ST1.d, &tmp32s)*2;
|
||||
ST1.d = tmp32s-1;
|
||||
}
|
||||
}
|
||||
void native_fprem(x64emu_t* emu)
|
||||
{
|
||||
@@ -172,7 +182,7 @@ void native_ud(x64emu_t* emu)
|
||||
void native_priv(x64emu_t* emu)
|
||||
{
|
||||
emu->test.test = 0;
|
||||
emit_signal(emu, SIGSEGV, (void*)R_RIP, 0);
|
||||
emit_signal(emu, SIGSEGV, (void*)R_RIP, 0xbad0);
|
||||
}
|
||||
|
||||
void native_int(x64emu_t* emu, int num)
|
||||
@@ -188,13 +198,13 @@ void native_singlestep(x64emu_t* emu)
|
||||
|
||||
void native_int3(x64emu_t* emu)
|
||||
{
|
||||
emit_signal(emu, SIGTRAP, (void*)R_RIP, 128);
|
||||
emit_signal(emu, SIGTRAP, NULL, 3);
|
||||
}
|
||||
|
||||
void native_div0(x64emu_t* emu)
|
||||
{
|
||||
emu->test.test = 0;
|
||||
emit_div0(emu, (void*)R_RIP, 0);
|
||||
emit_div0(emu, (void*)R_RIP, 1);
|
||||
}
|
||||
|
||||
void native_fsave(x64emu_t* emu, uint8_t* ed)
|
||||
@@ -513,7 +523,7 @@ static int flagsCacheNeedsTransform(dynarec_native_t* dyn, int ninst) {
|
||||
return 0;
|
||||
if(dyn->insts[ninst].f_exit.dfnone) // flags are fully known, nothing we can do more
|
||||
return 0;
|
||||
if(dyn->insts[jmp].f_entry.dfnone && !dyn->insts[ninst].f_exit.dfnone)
|
||||
if(dyn->insts[jmp].f_entry.dfnone && !dyn->insts[ninst].f_exit.dfnone && !dyn->insts[jmp].df_notneeded)
|
||||
return 1;
|
||||
switch (dyn->insts[jmp].f_entry.pending) {
|
||||
case SF_UNKNOWN: return 0;
|
||||
@@ -584,7 +594,7 @@ uintptr_t fakeed(dynarec_native_t* dyn, uintptr_t addr, int ninst, uint8_t nexto
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
// return Ib on a mod/rm opcode without emiting anything
|
||||
// return Ib on a mod/rm opcode without emitting anything
|
||||
uint8_t geted_ib(dynarec_native_t* dyn, uintptr_t addr, int ninst, uint8_t nextop)
|
||||
{
|
||||
addr = fakeed(dyn, addr, ninst, nextop);
|
||||
@@ -592,9 +602,11 @@ uint8_t geted_ib(dynarec_native_t* dyn, uintptr_t addr, int ninst, uint8_t nexto
|
||||
}
|
||||
#undef F8
|
||||
|
||||
int isNativeCall(dynarec_native_t* dyn, uintptr_t addr, uintptr_t* calladdress, uint16_t* retn)
|
||||
int isNativeCall(dynarec_native_t* dyn, uintptr_t addr, int is32bits, uintptr_t* calladdress, uint16_t* retn)
|
||||
{
|
||||
(void)dyn;
|
||||
if(is32bits)
|
||||
addr &= 0xFFFFFFFFLL;
|
||||
|
||||
#define PK(a) *(uint8_t*)(addr+a)
|
||||
#define PK32(a) *(int32_t*)(addr+a)
|
||||
@@ -608,7 +620,7 @@ int isNativeCall(dynarec_native_t* dyn, uintptr_t addr, uintptr_t* calladdress,
|
||||
if(!addr || !getProtection(addr))
|
||||
return 0;
|
||||
onebridge_t *b = (onebridge_t*)(addr);
|
||||
if(b->CC==0xCC && b->S=='S' && b->C=='C' && b->w!=(wrapper_t)0 && b->f!=(uintptr_t)PltResolver) {
|
||||
if(b->CC==0xCC && b->S=='S' && b->C=='C' && b->w!=(wrapper_t)0 && b->f!=(uintptr_t)PltResolver64) {
|
||||
// found !
|
||||
if(retn) *retn = (b->C3==0xC2)?b->N:0;
|
||||
if(calladdress) *calladdress = addr+1;
|
||||
@@ -646,3 +658,15 @@ void avx_unmark_zero(dynarec_native_t* dyn, int ninst, int reg)
|
||||
{
|
||||
dyn->ymm_zero &= ~(1<<reg);
|
||||
}
|
||||
|
||||
void propagate_nodf(dynarec_native_t* dyn, int ninst)
|
||||
{
|
||||
while(ninst>=0) {
|
||||
if(dyn->insts[ninst].df_notneeded)
|
||||
return; // already flagged
|
||||
if(dyn->insts[ninst].x64.gen_flags || dyn->insts[ninst].x64.use_flags)
|
||||
return; // flags are use, so maybe it's needed
|
||||
dyn->insts[ninst].df_notneeded = 1;
|
||||
--ninst;
|
||||
}
|
||||
}
|
||||
@@ -61,6 +61,8 @@ void native_div0(x64emu_t* emu);
|
||||
|
||||
// Caches transformation (for loops) // Specific, need to be written par backend
|
||||
int CacheNeedsTransform(dynarec_native_t* dyn, int i1);
|
||||
// propagete defererd to unknow, as state is not needed
|
||||
void propagate_nodf(dynarec_native_t* dyn, int ninst);
|
||||
|
||||
// predecessor access
|
||||
int isPred(dynarec_native_t* dyn, int ninst, int pred);
|
||||
@@ -68,11 +70,11 @@ int getNominalPred(dynarec_native_t* dyn, int ninst);
|
||||
|
||||
// Do the GETED, but don't emit anything...
|
||||
uintptr_t fakeed(dynarec_native_t* dyn, uintptr_t addr, int ninst, uint8_t nextop);
|
||||
// return Ib on a mod/rm opcode without emiting anything
|
||||
// return Ib on a mod/rm opcode without emitting anything
|
||||
uint8_t geted_ib(dynarec_native_t* dyn, uintptr_t addr, int ninst, uint8_t nextop);
|
||||
|
||||
// Is what pointed at addr a native call? And if yes, to what function?
|
||||
int isNativeCall(dynarec_native_t* dyn, uintptr_t addr, uintptr_t* calladdress, uint16_t* retn);
|
||||
int isNativeCall(dynarec_native_t* dyn, uintptr_t addr, int is32bits, uintptr_t* calladdress, uint16_t* retn);
|
||||
|
||||
// AVX utilities
|
||||
void avx_mark_zero(dynarec_native_t* dyn, int ninst, int reg);
|
||||
|
||||
@@ -55,18 +55,18 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
#endif
|
||||
fpu_reset(dyn);
|
||||
ARCH_INIT();
|
||||
int reset_n = -1;
|
||||
int reset_n = -1; // -1 no reset; -2 reset to 0; else reset to the state of reset_n
|
||||
dyn->last_ip = (alternate || (dyn->insts && dyn->insts[0].pred_sz))?0:ip; // RIP is always set at start of block unless there is a predecessor!
|
||||
int stopblock = 2+(FindElfAddress(my_context, addr)?0:1); // if block is in elf_memory, it can be extended with box64_dynarec_bigblock==2, else it needs 3
|
||||
// ok, go now
|
||||
INIT;
|
||||
#if STEP == 0
|
||||
uintptr_t cur_page = (addr)&~box64_pagesize;
|
||||
uintptr_t cur_page = (addr)&~(box64_pagesize-1);
|
||||
#endif
|
||||
while(ok) {
|
||||
#if STEP == 0
|
||||
if(cur_page != ((addr)&~box64_pagesize)) {
|
||||
cur_page = (addr)&~box64_pagesize;
|
||||
if(cur_page != ((addr)&~(box64_pagesize-1))) {
|
||||
cur_page = (addr)&~(box64_pagesize-1);
|
||||
if(!(getProtection(addr)&PROT_READ)) {
|
||||
need_epilog = 1;
|
||||
break;
|
||||
@@ -89,6 +89,7 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
dyn->f.dfnone = 0;
|
||||
dyn->f.pending = 0;
|
||||
fpu_reset(dyn);
|
||||
ARCH_RESET();
|
||||
} else {
|
||||
fpu_reset_cache(dyn, ninst, reset_n);
|
||||
dyn->f = dyn->insts[reset_n].f_exit;
|
||||
@@ -110,16 +111,18 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
#endif
|
||||
dyn->f.dfnone_here = 0;
|
||||
NEW_INST;
|
||||
MESSAGE(LOG_DUMP, "New Instruction x64:%p, native:%p\n", (void*)addr, (void*)dyn->block);
|
||||
#if STEP == 0
|
||||
if(ninst && dyn->insts[ninst-1].x64.barrier_next) {
|
||||
BARRIER(dyn->insts[ninst-1].x64.barrier_next);
|
||||
}
|
||||
#endif
|
||||
MESSAGE(LOG_DUMP, "New Instruction %s:%p, native:%p\n", is32bits?"x86":"x64",(void*)addr, (void*)dyn->block);
|
||||
if(!ninst) {
|
||||
GOTEST(x1, x2);
|
||||
}
|
||||
if(dyn->insts[ninst].pred_sz>1) {SMSTART();}
|
||||
#if STEP > 1
|
||||
if (dyn->insts[ninst].lock) {
|
||||
WILLWRITELOCK(dyn->insts[ninst].lock);
|
||||
} else if (dyn->insts[ninst].will_write) {
|
||||
WILLWRITE();
|
||||
}
|
||||
#endif
|
||||
if((dyn->insts[ninst].x64.need_before&~X_PEND) && !dyn->insts[ninst].pred_sz) {
|
||||
READFLAGS(dyn->insts[ninst].x64.need_before&~X_PEND);
|
||||
}
|
||||
@@ -173,7 +176,14 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
|
||||
#if STEP > 0
|
||||
if(dyn->insts[ninst].x64.has_next && dyn->insts[next].x64.barrier) {
|
||||
if(dyn->insts[next].x64.barrier&BARRIER_FLOAT) {
|
||||
#ifdef RV64
|
||||
uint8_t tmp1, tmp2, tmp3;
|
||||
if(dyn->insts[next].nat_flags_fusion) get_free_scratch(dyn, next, &tmp1, &tmp2, &tmp3, x1, x2, x3, x4, x5);
|
||||
else { tmp1=x1; tmp2=x2; tmp3=x3; }
|
||||
fpu_purgecache(dyn, ninst, 0, tmp1, tmp2, tmp3);
|
||||
#else
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
#endif
|
||||
}
|
||||
if(dyn->insts[next].x64.barrier&BARRIER_FLAGS) {
|
||||
dyn->f.pending = 0;
|
||||
|
||||
@@ -29,6 +29,9 @@
|
||||
#define SF_NODF 16
|
||||
#define SF_SET_NODF (SF_SET|SF_NODF)
|
||||
|
||||
#define NAT_FLAGS_FUSION 0
|
||||
#define NAT_FLAGS_NOFUSION 1
|
||||
|
||||
typedef struct instruction_x64_s {
|
||||
uintptr_t addr; //address of the instruction
|
||||
int32_t size; // size of the instruction
|
||||
@@ -39,7 +42,6 @@ typedef struct instruction_x64_s {
|
||||
uint8_t has_callret:1; // this instruction have an optimised call setup
|
||||
uint8_t alive:1; // this opcode gets executed (0 if dead code in that block)
|
||||
uint8_t barrier; // next instruction is a jump point, so no optim allowed
|
||||
uint8_t barrier_next; // next instruction needs a barrier
|
||||
uint8_t state_flags;// One of SF_XXX state
|
||||
uint8_t use_flags; // 0 or combination of X_?F
|
||||
uint8_t set_flags; // 0 or combination of X_?F
|
||||
|
||||
+432
-121
File diff suppressed because it is too large.
Load diff
@@ -24,7 +24,7 @@
|
||||
#include "la64_printer.h"
|
||||
#include "dynarec_la64_private.h"
|
||||
#include "dynarec_la64_functions.h"
|
||||
#include "dynarec_la64_helper.h"
|
||||
#include "../dynarec_helper.h"
|
||||
|
||||
uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog)
|
||||
{
|
||||
@@ -93,8 +93,8 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
LOAD_XEMU_CALL();
|
||||
TABLE64(x3, addr); // expected return address
|
||||
BNE_MARK(xRIP, x3);
|
||||
LD_W(w1, xEmu, offsetof(x64emu_t, quit));
|
||||
CBZ_NEXT(w1);
|
||||
LD_W(x1, xEmu, offsetof(x64emu_t, quit));
|
||||
CBZ_NEXT(x1);
|
||||
MARK;
|
||||
LOAD_XEMU_REM();
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
@@ -110,6 +110,17 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
break;
|
||||
case 0x0D:
|
||||
nextop = F8;
|
||||
switch ((nextop >> 3) & 7) {
|
||||
case 1:
|
||||
INST_NAME("PREFETCHW");
|
||||
FAKEED;
|
||||
break;
|
||||
default: //???
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0x10:
|
||||
INST_NAME("MOVUPS Gx,Ex");
|
||||
nextop = F8;
|
||||
@@ -325,6 +336,17 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
SPILL_EFLAGS();
|
||||
}
|
||||
break;
|
||||
case 0x31:
|
||||
INST_NAME("RDTSC");
|
||||
NOTEST(x1);
|
||||
// TODO: how to read the wall-clock real time on LoongArch?
|
||||
CALL(ReadTSC, x3); // will return the u64 in x3
|
||||
if (box64_rdtsc_shift) {
|
||||
SRLI_D(x3, x3, box64_rdtsc_shift);
|
||||
}
|
||||
SRLI_D(xRDX, x3, 32);
|
||||
ZEROUP2(xRDX, x3);
|
||||
break;
|
||||
case 0x38:
|
||||
// SSE3
|
||||
nextop = F8;
|
||||
@@ -393,31 +415,31 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
}
|
||||
break;
|
||||
|
||||
#define GO(GETFLAGS, NO, YES, F, I) \
|
||||
READFLAGS(F); \
|
||||
if (la64_lbt) { \
|
||||
X64_SETJ(x1, I); \
|
||||
} else { \
|
||||
GETFLAGS; \
|
||||
} \
|
||||
nextop = F8; \
|
||||
GETGD; \
|
||||
if (MODREG) { \
|
||||
ed = TO_LA64((nextop & 7) + (rex.b << 3)); \
|
||||
if (la64_lbt) \
|
||||
BEQZ(x1, 8); \
|
||||
else \
|
||||
B##NO(x1, 8); \
|
||||
MV(gd, ed); \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x4, &fixedaddress, rex, NULL, 1, 0); \
|
||||
if (la64_lbt) \
|
||||
BEQZ(x1, 8); \
|
||||
else \
|
||||
B##NO(x1, 8); \
|
||||
LDxw(gd, ed, fixedaddress); \
|
||||
} \
|
||||
if (!rex.w) ZEROUP(gd);
|
||||
#define GO(GETFLAGS, NO, YES, F, I) \
|
||||
READFLAGS(F); \
|
||||
if (la64_lbt) { \
|
||||
X64_SETJ(x1, I); \
|
||||
} else { \
|
||||
GETFLAGS; \
|
||||
} \
|
||||
nextop = F8; \
|
||||
GETGD; \
|
||||
if (MODREG) { \
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3)); \
|
||||
if (la64_lbt) \
|
||||
BEQZ(x1, 8); \
|
||||
else \
|
||||
B##NO(x1, 8); \
|
||||
MV(gd, ed); \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x4, &fixedaddress, rex, NULL, 1, 0); \
|
||||
if (la64_lbt) \
|
||||
BEQZ(x1, 8); \
|
||||
else \
|
||||
B##NO(x1, 8); \
|
||||
LDxw(gd, ed, fixedaddress); \
|
||||
} \
|
||||
if (!rex.w) ZEROUP(gd);
|
||||
|
||||
GOCOND(0x40, "CMOV", "Gd, Ed");
|
||||
|
||||
@@ -566,11 +588,14 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
break;
|
||||
|
||||
#define GO(GETFLAGS, NO, YES, F, I) \
|
||||
if (box64_dynarec_test == 2) { NOTEST(x1); } \
|
||||
READFLAGS(F); \
|
||||
i32_ = F32S; \
|
||||
if(rex.is32bits) \
|
||||
j64 = (uint32_t)(addr+i32_); \
|
||||
else \
|
||||
j64 = addr+i32_; \
|
||||
BARRIER(BARRIER_MAYBE); \
|
||||
JUMP(addr + i32_, 1); \
|
||||
JUMP(j64, 1); \
|
||||
if (la64_lbt) { \
|
||||
X64_SETJ(x1, I); \
|
||||
} else { \
|
||||
@@ -586,7 +611,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
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 + i32_, 0, ninst, rex.is32bits); \
|
||||
jump_to_next(dyn, j64, 0, ninst, rex.is32bits); \
|
||||
} else { \
|
||||
CacheTransform(dyn, ninst, cacheupd, x1, x2, x3); \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x64.jmp_insts].address - (dyn->native_size); \
|
||||
@@ -606,30 +631,30 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
#undef GO
|
||||
|
||||
|
||||
#define GO(GETFLAGS, NO, YES, F, I) \
|
||||
READFLAGS(F); \
|
||||
if (la64_lbt) { \
|
||||
X64_SETJ(x3, I); \
|
||||
} else { \
|
||||
GETFLAGS; \
|
||||
S##YES(x3, x1); \
|
||||
} \
|
||||
nextop = F8; \
|
||||
if (MODREG) { \
|
||||
if (rex.rex) { \
|
||||
eb1 = TO_LA64((nextop & 7) + (rex.b << 3)); \
|
||||
eb2 = 0; \
|
||||
} else { \
|
||||
ed = (nextop & 7); \
|
||||
eb2 = (ed >> 2) * 8; \
|
||||
eb1 = TO_LA64(ed & 3); \
|
||||
} \
|
||||
BSTRINS_D(eb1, x3, eb2 + 7, eb2); \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0); \
|
||||
ST_B(x3, ed, fixedaddress); \
|
||||
SMWRITE(); \
|
||||
}
|
||||
#define GO(GETFLAGS, NO, YES, F, I) \
|
||||
READFLAGS(F); \
|
||||
if (la64_lbt) { \
|
||||
X64_SETJ(x3, I); \
|
||||
} else { \
|
||||
GETFLAGS; \
|
||||
S##YES(x3, x1); \
|
||||
} \
|
||||
nextop = F8; \
|
||||
if (MODREG) { \
|
||||
if (rex.rex) { \
|
||||
eb1 = TO_NAT((nextop & 7) + (rex.b << 3)); \
|
||||
eb2 = 0; \
|
||||
} else { \
|
||||
ed = (nextop & 7); \
|
||||
eb2 = (ed >> 2) * 8; \
|
||||
eb1 = TO_NAT(ed & 3); \
|
||||
} \
|
||||
BSTRINS_D(eb1, x3, eb2 + 7, eb2); \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0); \
|
||||
ST_B(x3, ed, fixedaddress); \
|
||||
SMWRITE(); \
|
||||
}
|
||||
|
||||
GOCOND(0x90, "SET", "Eb");
|
||||
#undef GO
|
||||
@@ -650,7 +675,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if (MODREG) {
|
||||
ed = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
@@ -669,23 +694,70 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 0xA4:
|
||||
nextop = F8;
|
||||
INST_NAME("SHLD Ed, Gd, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETED(1);
|
||||
if (geted_ib(dyn, addr, ninst, nextop)) {
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETED(1);
|
||||
GETGD;
|
||||
u8 = F8;
|
||||
emit_shld32c(dyn, ninst, rex, ed, gd, u8, x3, x4);
|
||||
WBACK;
|
||||
} else {
|
||||
FAKEED;
|
||||
F8;
|
||||
}
|
||||
break;
|
||||
case 0xAB:
|
||||
INST_NAME("BTS Ed, Gd");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
u8 = F8;
|
||||
emit_shld32c(dyn, ninst, rex, ed, gd, u8, x3, x4);
|
||||
WBACK;
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
wback = 0;
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
SRAI_D(x1, gd, 5 + rex.w);
|
||||
ALSL_D(x3, x1, wback, 2 + rex.w);
|
||||
LDxw(x1, x3, fixedaddress);
|
||||
ed = x1;
|
||||
wback = x3;
|
||||
}
|
||||
ANDI(x2, gd, rex.w ? 0x3f : 0x1f);
|
||||
IFX (X_CF) {
|
||||
SRL_D(x4, ed, x2);
|
||||
if (la64_lbt) {
|
||||
X64_SET_EFLAGS(x4, X_CF);
|
||||
} else {
|
||||
BSTRINS_D(xFlags, x4, F_CF, F_CF);
|
||||
}
|
||||
}
|
||||
ADDI_D(x4, xZR, 1);
|
||||
SLL_D(x4, x4, x2);
|
||||
OR(ed, ed, x4);
|
||||
if (wback) {
|
||||
SDxw(ed, wback, fixedaddress);
|
||||
SMWRITE();
|
||||
} else if (!rex.w) {
|
||||
ZEROUP(ed);
|
||||
}
|
||||
break;
|
||||
case 0xAC:
|
||||
nextop = F8;
|
||||
INST_NAME("SHRD Ed, Gd, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETED(1);
|
||||
GETGD;
|
||||
u8 = F8;
|
||||
u8 &= (rex.w ? 0x3f : 0x1f);
|
||||
emit_shrd32c(dyn, ninst, rex, ed, gd, u8, x3, x4);
|
||||
WBACK;
|
||||
if (geted_ib(dyn, addr, ninst, nextop)) {
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETED(1);
|
||||
GETGD;
|
||||
u8 = F8;
|
||||
u8 &= (rex.w ? 0x3f : 0x1f);
|
||||
emit_shrd32c(dyn, ninst, rex, ed, gd, u8, x3, x4);
|
||||
WBACK;
|
||||
} else {
|
||||
FAKEED;
|
||||
F8;
|
||||
}
|
||||
break;
|
||||
case 0xAE:
|
||||
nextop = F8;
|
||||
@@ -718,9 +790,18 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x3, &fixedaddress, rex, NULL, 0, 0);
|
||||
if (ed != x1) { MV(x1, ed); }
|
||||
CALL(rex.w ? ((void*)fpu_fxsave64) : ((void*)fpu_fxsave32), -1);
|
||||
CALL(rex.is32bits ? ((void*)fpu_fxsave32) : ((void*)fpu_fxsave64), -1);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FXRSTOR Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
SKIPTEST(x1);
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x3, &fixedaddress, rex, NULL, 0, 0);
|
||||
if (ed != x1) { MV(x1, ed); }
|
||||
CALL(rex.is32bits ? ((void*)fpu_fxrstor32) : ((void*)fpu_fxrstor64), -1);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("LDMXCSR Md");
|
||||
GETED(0);
|
||||
@@ -735,6 +816,33 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
LD_WU(x4, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
ST_W(x4, wback, fixedaddress);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("XSAVE Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, x2, &fixedaddress, rex, NULL, 0, 0);
|
||||
if (ed != x1) { MV(x1, ed); }
|
||||
MOV32w(x2, rex.w?0:1);
|
||||
CALL((void*)fpu_xsave, -1);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("XRSTOR Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, x2, &fixedaddress, rex, NULL, 0, 0);
|
||||
if (ed != x1) { MV(x1, ed); }
|
||||
MOV32w(x2, rex.w?0:1);
|
||||
CALL((void*)fpu_xrstor, -1);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("CLFLUSH Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization?\n");
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, x2, &fixedaddress, rex, NULL, 0, 0);
|
||||
if (wback != A1) {
|
||||
MV(A1, wback);
|
||||
}
|
||||
CALL_(native_clflush, -1, 0);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
@@ -819,11 +927,11 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
GETGD;
|
||||
if (MODREG) {
|
||||
if (rex.rex) {
|
||||
eb1 = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
eb1 = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
eb2 = 0;
|
||||
} else {
|
||||
ed = (nextop & 7);
|
||||
eb1 = TO_LA64(ed & 3); // Ax, Cx, Dx or Bx
|
||||
eb1 = TO_NAT(ed & 3); // Ax, Cx, Dx or Bx
|
||||
eb2 = (ed & 4) >> 2; // L or H
|
||||
}
|
||||
BSTRPICK_D(gd, eb1, eb2 * 8 + 7, eb2 * 8);
|
||||
@@ -838,7 +946,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if (MODREG) {
|
||||
ed = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
BSTRPICK_D(gd, ed, 15, 0);
|
||||
} else {
|
||||
SMREAD();
|
||||
@@ -879,6 +987,8 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
if (wback) {
|
||||
SDxw(ed, wback, fixedaddress);
|
||||
SMWRITE();
|
||||
} else if (!rex.w) {
|
||||
ZEROUP(ed);
|
||||
}
|
||||
MARK;
|
||||
break;
|
||||
@@ -898,9 +1008,33 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
if (wback) {
|
||||
SDxw(ed, wback, fixedaddress);
|
||||
SMWRITE();
|
||||
} else if (!rex.w) {
|
||||
ZEROUP(ed);
|
||||
}
|
||||
MARK;
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("BTC Ed, Ib");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
SET_DFNONE();
|
||||
GETED(1);
|
||||
u8 = F8;
|
||||
u8 &= rex.w ? 0x3f : 0x1f;
|
||||
BSTRPICK_D(x3, ed, u8, u8);
|
||||
BSTRINS_D(xFlags, x3, 0, 0);
|
||||
if (u8 <= 10) {
|
||||
XORI(ed, ed, (1LL << u8));
|
||||
} else {
|
||||
MOV64xw(x3, (1LL << u8));
|
||||
XOR(ed, ed, x3);
|
||||
}
|
||||
if (wback) {
|
||||
SDxw(ed, wback, fixedaddress);
|
||||
SMWRITE();
|
||||
} else if (!rex.w) {
|
||||
ZEROUP(ed);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
@@ -913,7 +1047,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
GETED(0);
|
||||
GETGD;
|
||||
if (!rex.w && MODREG) {
|
||||
AND(x4, ed, xMASK);
|
||||
ZEROUP2(x4, ed);
|
||||
ed = x4;
|
||||
}
|
||||
BNE_MARK(ed, xZR);
|
||||
@@ -945,7 +1079,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
GETED(0);
|
||||
GETGD;
|
||||
if (!rex.w && MODREG) {
|
||||
AND(x4, ed, xMASK);
|
||||
ZEROUP2(x4, ed);
|
||||
ed = x4;
|
||||
}
|
||||
BNE_MARK(ed, xZR);
|
||||
@@ -976,12 +1110,12 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
GETGD;
|
||||
if (MODREG) {
|
||||
if (rex.rex) {
|
||||
wback = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
wback = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
wb2 = 0;
|
||||
} else {
|
||||
wback = (nextop & 7);
|
||||
wb2 = (wback >> 2) * 8;
|
||||
wback = TO_LA64(wback & 3);
|
||||
wback = TO_NAT(wback & 3);
|
||||
}
|
||||
BSTRPICK_D(gd, wback, wb2 + 7, wb2);
|
||||
EXT_W_B(gd, gd);
|
||||
@@ -997,7 +1131,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if (MODREG) {
|
||||
ed = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
EXT_W_H(gd, ed);
|
||||
} else {
|
||||
SMREAD();
|
||||
@@ -1047,7 +1181,7 @@ uintptr_t dynarec64_0F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 0xCE:
|
||||
case 0xCF:
|
||||
INST_NAME("BSWAP Reg");
|
||||
gd = TO_LA64((opcode & 7) + (rex.b << 3));
|
||||
gd = TO_NAT((opcode & 7) + (rex.b << 3));
|
||||
REVBxw(gd, gd);
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
#include "la64_printer.h"
|
||||
#include "dynarec_la64_private.h"
|
||||
#include "dynarec_la64_helper.h"
|
||||
#include "../dynarec_helper.h"
|
||||
#include "dynarec_la64_functions.h"
|
||||
|
||||
uintptr_t dynarec64_64(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int seg, int* ok, int* need_epilog)
|
||||
@@ -70,6 +70,15 @@ uintptr_t dynarec64_64(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
GETEDO(x4, 0);
|
||||
emit_add32(dyn, ninst, rex, gd, ed, x3, x4, x5);
|
||||
break;
|
||||
case 0x2B:
|
||||
INST_NAME("SUB Gd, Seg:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO(x4, 0);
|
||||
emit_sub32(dyn, ninst, rex, gd, ed, x3, x4, x5);
|
||||
break;
|
||||
case 0x33:
|
||||
INST_NAME("XOR Gd, Seg:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
@@ -109,6 +118,16 @@ uintptr_t dynarec64_64(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
emit_or8c(dyn, ninst, x1, u8, x2, x4, x5);
|
||||
EBBACK();
|
||||
break;
|
||||
case 2: // ADC
|
||||
INST_NAME("ADC Eb, Ib");
|
||||
grab_segdata(dyn, addr, ninst, x1, seg);
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEBO(x1, 1);
|
||||
u8 = F8;
|
||||
emit_adc8c(dyn, ninst, x1, u8, x2, x4, x5, x6);
|
||||
EBBACK();
|
||||
break;
|
||||
case 3: // SBB
|
||||
INST_NAME("SBB Eb, Ib");
|
||||
grab_segdata(dyn, addr, ninst, x1, seg);
|
||||
@@ -180,9 +199,7 @@ uintptr_t dynarec64_64(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
i64 = F32S;
|
||||
else
|
||||
i64 = F8S;
|
||||
emit_add32c(dyn, ninst, rex, ed, i64, x3, x4, x5, xMASK);
|
||||
IFXA (X_CF, !la64_lbt)
|
||||
REGENERATE_MASK(); // use xMASK as a scratch
|
||||
emit_add32c(dyn, ninst, rex, ed, i64, x3, x4, x5, x7);
|
||||
WBACKO(x6);
|
||||
break;
|
||||
case 1:
|
||||
@@ -216,10 +233,9 @@ uintptr_t dynarec64_64(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
MOV64xw(x5, i64);
|
||||
IFXA (X_ALL, !la64_lbt)
|
||||
ST_D(x6, xEmu, offsetof(x64emu_t, scratch));
|
||||
emit_adc32(dyn, ninst, rex, ed, x5, x3, x4, x6, xMASK);
|
||||
emit_adc32(dyn, ninst, rex, ed, x5, x3, x4, x6, x7);
|
||||
IFXA (X_ALL, !la64_lbt) {
|
||||
LD_D(x6, xEmu, offsetof(x64emu_t, scratch));
|
||||
REGENERATE_MASK(); // use xMASK as a scratch
|
||||
}
|
||||
WBACKO(x6);
|
||||
break;
|
||||
@@ -237,9 +253,7 @@ uintptr_t dynarec64_64(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
else
|
||||
i64 = F8S;
|
||||
MOV64xw(x5, i64);
|
||||
emit_sbb32(dyn, ninst, rex, ed, x5, x3, x4, xMASK);
|
||||
IFXA (X_CF, !la64_lbt)
|
||||
REGENERATE_MASK(); // use xMASK as a scratch
|
||||
emit_sbb32(dyn, ninst, rex, ed, x5, x3, x4, x7);
|
||||
WBACKO(x6);
|
||||
break;
|
||||
case 4:
|
||||
@@ -269,9 +283,7 @@ uintptr_t dynarec64_64(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
i64 = F32S;
|
||||
else
|
||||
i64 = F8S;
|
||||
emit_sub32c(dyn, ninst, rex, ed, i64, x3, x4, x5, xMASK);
|
||||
IFXA (X_CF, !la64_lbt)
|
||||
REGENERATE_MASK(); // use xMASK as a scratch
|
||||
emit_sub32c(dyn, ninst, rex, ed, i64, x3, x4, x5, x7);
|
||||
WBACKO(x6);
|
||||
break;
|
||||
case 6:
|
||||
@@ -315,11 +327,16 @@ uintptr_t dynarec64_64(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if (MODREG) { // reg <= reg
|
||||
MVxw(TO_LA64((nextop & 7) + (rex.b << 3)), gd);
|
||||
MVxw(TO_NAT((nextop & 7) + (rex.b << 3)), gd);
|
||||
} else { // mem <= reg
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
ADD_D(x4, ed, x4);
|
||||
SDxw(gd, x4, fixedaddress);
|
||||
if (rex.is32bits) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
ADDz(x4, ed, x4);
|
||||
SDxw(gd, x4, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 0, 0);
|
||||
SDXxw(gd, ed, x4);
|
||||
}
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
@@ -329,14 +346,33 @@ uintptr_t dynarec64_64(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if (MODREG) { // reg <= reg
|
||||
MVxw(gd, TO_LA64((nextop & 7) + (rex.b << 3)));
|
||||
MVxw(gd, TO_NAT((nextop & 7) + (rex.b << 3)));
|
||||
} else { // mem <= reg
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
ADD_D(x4, ed, x4);
|
||||
LDxw(gd, x4, fixedaddress);
|
||||
if (rex.is32bits) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
ADDz(x4, ed, x4);
|
||||
LDxw(gd, x4, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 0, 0);
|
||||
LDXxw(gd, ed, x4);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xA1:
|
||||
INST_NAME("MOV EAX, FS:Od");
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
if (rex.is32bits)
|
||||
u64 = F32;
|
||||
else
|
||||
u64 = F64;
|
||||
MOV64z(x1, u64);
|
||||
if (rex.is32bits) {
|
||||
ADDz(x4, x1, x4);
|
||||
LDxw(xRAX, x4, 0);
|
||||
} else
|
||||
LDXxw(xRAX, x4, x1);
|
||||
break;
|
||||
case 0xC6:
|
||||
INST_NAME("MOV Seg:Eb, Ib");
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
@@ -345,23 +381,28 @@ uintptr_t dynarec64_64(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
u8 = F8;
|
||||
if (!rex.rex) {
|
||||
ed = (nextop & 7);
|
||||
eb1 = TO_LA64(ed & 3); // Ax, Cx, Dx or Bx
|
||||
eb1 = TO_NAT(ed & 3); // Ax, Cx, Dx or Bx
|
||||
eb2 = (ed & 4) >> 2; // L or H
|
||||
} else {
|
||||
eb1 = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
eb1 = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
eb2 = 0;
|
||||
}
|
||||
MOV32w(x3, u8);
|
||||
BSTRINS_D(eb1, x3, eb2 * 8 + 7, eb2 * 8);
|
||||
} else { // mem <= u8
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, NULL, 1, 1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, NULL, 0, 1);
|
||||
u8 = F8;
|
||||
if (u8) {
|
||||
ADDI_D(x3, xZR, u8);
|
||||
ed = x3;
|
||||
} else
|
||||
ed = xZR;
|
||||
STX_B(x3, wback, x4);
|
||||
if (rex.is32bits) {
|
||||
ADDz(x4, wback, x4);
|
||||
ST_B(ed, x4, 0);
|
||||
} else {
|
||||
STX_B(ed, wback, x4);
|
||||
}
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
@@ -371,18 +412,22 @@ uintptr_t dynarec64_64(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
nextop = F8;
|
||||
if (MODREG) { // reg <= i32
|
||||
i64 = F32S;
|
||||
ed = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
MOV64xw(ed, i64);
|
||||
} else { // mem <= i32
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, NULL, 1, 4);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, NULL, 0, 4);
|
||||
i64 = F32S;
|
||||
if (i64) {
|
||||
MOV64xw(x3, i64);
|
||||
MOV64x(x3, i64);
|
||||
ed = x3;
|
||||
} else
|
||||
ed = xZR;
|
||||
ADD_D(x4, wback, x4);
|
||||
SDxw(ed, x4, fixedaddress);
|
||||
if (rex.is32bits) {
|
||||
ADDz(x4, wback, x4);
|
||||
SDxw(ed, x4, 0);
|
||||
} else {
|
||||
SDXxw(ed, wback, x4);
|
||||
}
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
#include "la64_printer.h"
|
||||
#include "dynarec_la64_private.h"
|
||||
#include "dynarec_la64_helper.h"
|
||||
#include "../dynarec_helper.h"
|
||||
#include "dynarec_la64_functions.h"
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
BSTRPICK_D(x1, xRAX, 15, 0);
|
||||
MOV32w(x2, i32);
|
||||
emit_add16(dyn, ninst, x1, x2, x3, x4, x6);
|
||||
BSTRINS_D(xRAX, x1, 15, 0);
|
||||
BSTRINSz(xRAX, x1, 15, 0);
|
||||
break;
|
||||
case 0x09:
|
||||
INST_NAME("OR Ew, Gw");
|
||||
@@ -91,7 +91,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
emit_or16(dyn, ninst, x1, x2, x4, x2);
|
||||
emit_or16(dyn, ninst, x1, x2, x4, x5);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0x0B:
|
||||
@@ -110,7 +110,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
BSTRPICK_D(x1, xRAX, 15, 0);
|
||||
MOV32w(x2, i32);
|
||||
emit_or16(dyn, ninst, x1, x2, x3, x4);
|
||||
BSTRINS_D(xRAX, x1, 15, 0);
|
||||
BSTRINSz(xRAX, x1, 15, 0);
|
||||
break;
|
||||
case 0x0F:
|
||||
switch (rep) {
|
||||
@@ -119,6 +119,36 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0x11:
|
||||
INST_NAME("ADC Ew, Gw");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
GETEW(x1, 0);
|
||||
emit_adc16(dyn, ninst, x1, x2, x4, x6, x5);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0x13:
|
||||
INST_NAME("ADC Gw, Ew");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
emit_adc16(dyn, ninst, x1, x2, x4, x6, x5);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x15:
|
||||
INST_NAME("ADC AX, Iw");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
u64 = F16;
|
||||
BSTRPICK_D(x1, xRAX, 15, 0);
|
||||
MOV64x(x2, u64);
|
||||
emit_adc16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
BSTRINSz(xRAX, x1, 15, 0);
|
||||
break;
|
||||
case 0x19:
|
||||
INST_NAME("SBB Ew, Gw");
|
||||
READFLAGS(X_CF);
|
||||
@@ -129,6 +159,26 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
emit_sbb16(dyn, ninst, x1, x2, x4, x5, x6);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0x1B:
|
||||
INST_NAME("SBB Gw, Ew");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
emit_sbb16(dyn, ninst, x1, x2, x6, x4, x5);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x1D:
|
||||
INST_NAME("SBB AX, Iw");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
BSTRPICK_D(x1, xRAX, 15, 0);
|
||||
u64 = F16;
|
||||
MOV64x(x2, u64);
|
||||
emit_sbb16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
BSTRINSz(xRAX, x1, 15, 0);
|
||||
break;
|
||||
case 0x21:
|
||||
INST_NAME("AND Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
@@ -154,7 +204,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
BSTRPICK_D(x1, xRAX, 15, 0);
|
||||
MOV32w(x2, i32);
|
||||
emit_and16(dyn, ninst, x1, x2, x3, x4);
|
||||
BSTRINS_D(xRAX, x1, 15, 0);
|
||||
BSTRINSz(xRAX, x1, 15, 0);
|
||||
break;
|
||||
case 0x29:
|
||||
INST_NAME("SUB Ew, Gw");
|
||||
@@ -181,7 +231,7 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
BSTRPICK_D(x1, xRAX, 15, 0);
|
||||
MOV32w(x2, i32);
|
||||
emit_sub16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
BSTRINS_D(xRAX, x1, 15, 0);
|
||||
BSTRINSz(xRAX, x1, 15, 0);
|
||||
break;
|
||||
case 0x31:
|
||||
INST_NAME("XOR Ew, Gw");
|
||||
@@ -192,6 +242,24 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
emit_xor16(dyn, ninst, x1, x2, x4, x5, x6);
|
||||
EWBACK;
|
||||
break;
|
||||
case 0x33:
|
||||
INST_NAME("XOR Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
emit_xor16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
GWBACK;
|
||||
break;
|
||||
case 0x35:
|
||||
INST_NAME("XOR AX, Iw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i32 = F16;
|
||||
BSTRPICK_D(x1, xRAX, 15, 0);
|
||||
MOV32w(x2, i32);
|
||||
emit_xor16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
BSTRINSz(xRAX, x1, 15, 0);
|
||||
break;
|
||||
case 0x39:
|
||||
INST_NAME("CMP Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
@@ -263,10 +331,10 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, (opcode == 0x81) ? 2 : 1);
|
||||
if (opcode == 0x81)
|
||||
i16 = F16S;
|
||||
u64 = F16;
|
||||
else
|
||||
i16 = F8S;
|
||||
MOV64x(x5, i16);
|
||||
u64 = (uint16_t)(int16_t)F8S;
|
||||
MOV64x(x5, u64);
|
||||
emit_add16(dyn, ninst, ed, x5, x2, x4, x6);
|
||||
EWBACK;
|
||||
break;
|
||||
@@ -279,13 +347,47 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, (opcode == 0x81) ? 2 : 1);
|
||||
if (opcode == 0x81)
|
||||
i16 = F16S;
|
||||
u64 = F16;
|
||||
else
|
||||
i16 = F8S;
|
||||
MOV64x(x5, i16);
|
||||
u64 = (uint16_t)(int16_t)F8S;
|
||||
MOV64x(x5, u64);
|
||||
emit_or16(dyn, ninst, x1, x5, 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);
|
||||
GETEW(x1, (opcode == 0x81) ? 2 : 1);
|
||||
if (opcode == 0x81)
|
||||
u64 = F16;
|
||||
else
|
||||
u64 = (uint16_t)(int16_t)F8S;
|
||||
MOV64x(x5, u64);
|
||||
emit_adc16(dyn, ninst, x1, x5, x2, x4, x6);
|
||||
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);
|
||||
GETEW(x1, (opcode == 0x81) ? 2 : 1);
|
||||
if (opcode == 0x81)
|
||||
u64 = F16;
|
||||
else
|
||||
u64 = (uint16_t)(int16_t)F8S;
|
||||
MOV64x(x5, u64);
|
||||
emit_sbb16(dyn, ninst, x1, x5, x2, x4, x6);
|
||||
EWBACK;
|
||||
break;
|
||||
case 4: // AND
|
||||
if (opcode == 0x81) {
|
||||
INST_NAME("AND Ew, Iw");
|
||||
@@ -295,10 +397,10 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, (opcode == 0x81) ? 2 : 1);
|
||||
if (opcode == 0x81)
|
||||
i16 = F16S;
|
||||
u64 = F16;
|
||||
else
|
||||
i16 = F8S;
|
||||
MOV64x(x5, i16);
|
||||
u64 = (uint16_t)(int16_t)F8S;
|
||||
MOV64x(x5, u64);
|
||||
emit_and16(dyn, ninst, x1, x5, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
@@ -311,10 +413,10 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, (opcode == 0x81) ? 2 : 1);
|
||||
if (opcode == 0x81)
|
||||
i16 = F16S;
|
||||
u64 = F16;
|
||||
else
|
||||
i16 = F8S;
|
||||
MOV32w(x5, i16);
|
||||
u64 = (uint16_t)(int16_t)F8S;
|
||||
MOV32w(x5, u64);
|
||||
emit_sub16(dyn, ninst, x1, x5, x2, x4, x6);
|
||||
EWBACK;
|
||||
break;
|
||||
@@ -327,10 +429,10 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, (opcode == 0x81) ? 2 : 1);
|
||||
if (opcode == 0x81)
|
||||
i16 = F16S;
|
||||
u64 = F16;
|
||||
else
|
||||
i16 = F8S;
|
||||
MOV32w(x5, i16);
|
||||
u64 = (uint16_t)(int16_t)F8S;
|
||||
MOV32w(x5, u64);
|
||||
emit_xor16(dyn, ninst, x1, x5, x2, x4, x6);
|
||||
EWBACK;
|
||||
break;
|
||||
@@ -343,11 +445,11 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEW(x1, (opcode == 0x81) ? 2 : 1);
|
||||
if (opcode == 0x81)
|
||||
i16 = F16S;
|
||||
u64 = F16;
|
||||
else
|
||||
i16 = F8S;
|
||||
if (i16) {
|
||||
MOV64x(x2, i16);
|
||||
u64 = (uint16_t)(int16_t)F8S;
|
||||
if (u64) {
|
||||
MOV64x(x2, u64);
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5, x6);
|
||||
} else
|
||||
emit_cmp16_0(dyn, ninst, x1, x3, x4);
|
||||
@@ -369,9 +471,9 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if (MODREG) {
|
||||
ed = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
if (ed != gd) {
|
||||
BSTRINS_D(ed, gd, 15, 0);
|
||||
BSTRINSz(ed, gd, 15, 0);
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, &lock, 1, 0);
|
||||
@@ -384,15 +486,15 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if (MODREG) {
|
||||
ed = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
if (ed != gd) {
|
||||
BSTRINS_D(gd, ed, 15, 0);
|
||||
BSTRINSz(gd, ed, 15, 0);
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, &lock, 1, 0);
|
||||
SMREADLOCK(lock);
|
||||
LD_HU(x1, ed, fixedaddress);
|
||||
BSTRINS_D(gd, x1, 15, 0);
|
||||
BSTRINSz(gd, x1, 15, 0);
|
||||
}
|
||||
break;
|
||||
case 0x90:
|
||||
@@ -403,17 +505,16 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
case 0x95:
|
||||
case 0x96:
|
||||
case 0x97:
|
||||
gd = TO_LA64((opcode & 0x07) + (rex.b << 3));
|
||||
gd = TO_NAT((opcode & 0x07) + (rex.b << 3));
|
||||
if (gd == xRAX) {
|
||||
INST_NAME("NOP");
|
||||
} else {
|
||||
INST_NAME("XCHG AX, Reg");
|
||||
MV(x2, xRAX);
|
||||
BSTRINS_D(xRAX, gd, 15, 0);
|
||||
BSTRINS_D(gd, x2, 15, 0);
|
||||
BSTRINSz(xRAX, gd, 15, 0);
|
||||
BSTRINSz(gd, x2, 15, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xA4:
|
||||
if (rep) {
|
||||
INST_NAME("REP MOVSB");
|
||||
@@ -520,8 +621,8 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("MOV Reg16, Iw");
|
||||
u16 = F16;
|
||||
MOV32w(x1, u16);
|
||||
gd = TO_LA64((opcode & 7) + (rex.b << 3));
|
||||
BSTRINS_D(gd, x1, 15, 0);
|
||||
gd = TO_NAT((opcode & 7) + (rex.b << 3));
|
||||
BSTRINSz(gd, x1, 15, 0);
|
||||
break;
|
||||
case 0xC1:
|
||||
nextop = F8;
|
||||
@@ -600,10 +701,10 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
INST_NAME("MOV Ew, Iw");
|
||||
nextop = F8;
|
||||
if (MODREG) {
|
||||
ed = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
u16 = F16;
|
||||
MOV32w(x1, u16);
|
||||
BSTRINS_D(ed, x1, 15, 0);
|
||||
BSTRINSz(ed, x1, 15, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, &lock, 1, 2);
|
||||
u16 = F16;
|
||||
@@ -687,6 +788,54 @@ uintptr_t dynarec64_66(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
emit_neg16(dyn, ninst, ed, x2, x4);
|
||||
EWBACK;
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("DIV Ew");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SET_DFNONE();
|
||||
GETEW(x1, 0);
|
||||
BSTRPICK_D(x2, xRAX, 15, 0);
|
||||
SLLI_D(x7, xRDX, 48);
|
||||
SRLI_D(x7, x7, 32);
|
||||
OR(x2, x2, x7);
|
||||
if(box64_dynarec_div0) {
|
||||
BNE_MARK3(ed, xZR);
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL();
|
||||
CALL(native_div0, -1);
|
||||
CLEARIP();
|
||||
LOAD_XEMU_CALL();
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
MARK3;
|
||||
}
|
||||
DIV_WU(x7, x2, ed);
|
||||
MOD_WU(x4, x2, ed);
|
||||
BSTRINSz(xRAX, x7, 15, 0);
|
||||
BSTRINSz(xRDX, x4, 15, 0);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("IDIV Ew");
|
||||
NOTEST(x1);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SET_DFNONE();
|
||||
GETSEW(x1, 0);
|
||||
if (box64_dynarec_div0) {
|
||||
BNE_MARK3(ed, xZR);
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL();
|
||||
CALL(native_div0, -1);
|
||||
CLEARIP();
|
||||
LOAD_XEMU_CALL();
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
MARK3;
|
||||
}
|
||||
BSTRPICK_D(x2, xRAX, 15, 0);
|
||||
SLLI_D(x3, xRDX, 16);
|
||||
OR(x2, x2, x3);
|
||||
DIV_W(x3, x2, ed);
|
||||
MOD_W(x4, x2, ed);
|
||||
BSTRINSz(xRAX, x3, 15, 0);
|
||||
BSTRINSz(xRDX, x4, 15, 0);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#include "la64_printer.h"
|
||||
#include "dynarec_la64_private.h"
|
||||
#include "dynarec_la64_functions.h"
|
||||
#include "dynarec_la64_helper.h"
|
||||
#include "../dynarec_helper.h"
|
||||
|
||||
uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog)
|
||||
{
|
||||
@@ -51,6 +51,20 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
MAYUSE(j64);
|
||||
|
||||
switch (opcode) {
|
||||
case 0x10:
|
||||
INST_NAME("MOVUPD Gx,Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
if (MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop & 7) + (rex.b << 3), 0);
|
||||
VOR_V(v0, v1, v1);
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x3, &fixedaddress, rex, NULL, 1, 0);
|
||||
VLD(v0, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0x11:
|
||||
INST_NAME("MOVUPD Ex,Gx");
|
||||
nextop = F8;
|
||||
@@ -93,6 +107,21 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
}
|
||||
VEXTRINS_D(v0, v1, 0x10);
|
||||
break;
|
||||
case 0x16:
|
||||
INST_NAME("MOVHPD Gx, Eq");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
if (MODREG) {
|
||||
// access register instead of memory is bad opcode!
|
||||
DEFAULT;
|
||||
return addr;
|
||||
}
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x3, &fixedaddress, rex, NULL, 1, 0);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
FLD_D(v1, ed, fixedaddress);
|
||||
VEXTRINS_D(v0, v1, 0x10);
|
||||
break;
|
||||
case 0x1F:
|
||||
INST_NAME("NOP (multibyte)");
|
||||
nextop = F8;
|
||||
@@ -313,6 +342,54 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
VOR_V(q0, q0, d0);
|
||||
}
|
||||
break;
|
||||
case 0x16:
|
||||
if (rex.w) {
|
||||
INST_NAME("PEXTRQ Ed, Gx, Ib");
|
||||
} else {
|
||||
INST_NAME("PEXTRD Ed, Gx, Ib");
|
||||
}
|
||||
nextop = F8;
|
||||
GETGX(q0, 0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
u8 = F8;
|
||||
if (rex.w) {
|
||||
VBSRL_V(d0, q0, (u8 & 1) * 8);
|
||||
MOVFR2GR_D(ed, d0);
|
||||
} else {
|
||||
VBSRL_V(d0, q0, (u8 & 3) * 4);
|
||||
MOVFR2GR_S(ed, d0);
|
||||
ZEROUP(ed);
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, x5, &fixedaddress, rex, NULL, 1, 1);
|
||||
u8 = F8;
|
||||
if (rex.w) {
|
||||
VBSRL_V(d0, q0, (u8 & 1) * 8);
|
||||
FST_D(d0, ed, fixedaddress);
|
||||
} else {
|
||||
VBSRL_V(d0, q0, (u8 & 3) * 4);
|
||||
FST_S(d0, ed, fixedaddress);
|
||||
}
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x22:
|
||||
INST_NAME("PINSRD Gx, ED, Ib");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETED(1);
|
||||
u8 = F8;
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
if (rex.w) {
|
||||
MOVGR2FR_D(d0, ed);
|
||||
VEXTRINS_D(q0, d0, (u8 & 1) << 4);
|
||||
} else {
|
||||
MOVGR2FR_W(d0, ed);
|
||||
VEXTRINS_W(q0, d0, (u8 & 3) << 4);
|
||||
}
|
||||
break;
|
||||
case 0x44:
|
||||
INST_NAME("PCLMULQDQ Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
@@ -362,29 +439,29 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
}
|
||||
break;
|
||||
|
||||
#define GO(GETFLAGS, NO, YES, F, I) \
|
||||
READFLAGS(F); \
|
||||
if (la64_lbt) { \
|
||||
X64_SETJ(x1, I); \
|
||||
} else { \
|
||||
GETFLAGS; \
|
||||
} \
|
||||
nextop = F8; \
|
||||
GETGD; \
|
||||
if (MODREG) { \
|
||||
ed = TO_LA64((nextop & 7) + (rex.b << 3)); \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x4, &fixedaddress, rex, NULL, 1, 0); \
|
||||
LD_HU(x4, ed, fixedaddress); \
|
||||
ed = x4; \
|
||||
} \
|
||||
if (la64_lbt) \
|
||||
BEQZ(x1, 4 + 4); \
|
||||
else \
|
||||
B##NO(x1, 4 + 4); \
|
||||
BSTRINS_D(gd, ed, 15, 0);
|
||||
#define GO(GETFLAGS, NO, YES, F, I) \
|
||||
READFLAGS(F); \
|
||||
if (la64_lbt) { \
|
||||
X64_SETJ(x1, I); \
|
||||
} else { \
|
||||
GETFLAGS; \
|
||||
} \
|
||||
nextop = F8; \
|
||||
GETGD; \
|
||||
if (MODREG) { \
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3)); \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x4, &fixedaddress, rex, NULL, 1, 0); \
|
||||
LD_HU(x4, ed, fixedaddress); \
|
||||
ed = x4; \
|
||||
} \
|
||||
if (la64_lbt) \
|
||||
BEQZ(x1, 4 + 4); \
|
||||
else \
|
||||
B##NO(x1, 4 + 4); \
|
||||
BSTRINS_D(gd, ed, 15, 0);
|
||||
|
||||
GOCOND(0x40, "CMOV", "Gd, Ed");
|
||||
GOCOND(0x40, "CMOV", "Gd, Ed");
|
||||
#undef GO
|
||||
|
||||
case 0x54:
|
||||
@@ -427,8 +504,42 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
nextop = F8;
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX(q1, 1);
|
||||
// TODO: fastnan handling
|
||||
if (!box64_dynarec_fastnan) {
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
VFCMP_D(v0, q0, q1, cUN);
|
||||
}
|
||||
VFADD_D(q1, q1, q0);
|
||||
if (!box64_dynarec_fastnan) {
|
||||
VFCMP_D(v1, q1, q1, cUN);
|
||||
VANDN_V(v0, v0, v1);
|
||||
VLDI(v1, 0b011111111000); // broadcast 0xFFFFFFFFFFFFFFF8
|
||||
VSLLI_D(v1, v1, 48);
|
||||
VAND_V(v1, v0, v1);
|
||||
VANDN_V(v0, v0, q1);
|
||||
VOR_V(q1, v0, v1);
|
||||
}
|
||||
break;
|
||||
case 0x59:
|
||||
INST_NAME("MULPD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX(q1, 1);
|
||||
if (!box64_dynarec_fastnan) {
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
VFCMP_D(v0, q0, q1, cUN);
|
||||
}
|
||||
VFMUL_D(q1, q1, q0);
|
||||
if (!box64_dynarec_fastnan) {
|
||||
VFCMP_D(v1, q1, q1, cUN);
|
||||
VANDN_V(v0, v0, v1);
|
||||
VLDI(v1, 0b011111111000); // broadcast 0xFFFFFFFFFFFFFFF8
|
||||
VSLLI_D(v1, v1, 48);
|
||||
VAND_V(v1, v0, v1);
|
||||
VANDN_V(v0, v0, q1);
|
||||
VOR_V(q1, v0, v1);
|
||||
}
|
||||
break;
|
||||
case 0x5A:
|
||||
INST_NAME("CVTPD2PS Gx, Ex");
|
||||
@@ -447,6 +558,10 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETEX(v1, 0, 0);
|
||||
GETGX_empty(v0);
|
||||
u8 = sse_setround(dyn, ninst, x6, x4);
|
||||
if (v0 == v1 && !box64_dynarec_fastround) {
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
VOR_V(v1, v0, v0);
|
||||
}
|
||||
VFTINT_W_S(v0, v1);
|
||||
if (!box64_dynarec_fastround) {
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
@@ -469,8 +584,42 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
nextop = F8;
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX(q1, 1);
|
||||
// TODO: fastnan handling
|
||||
if (!box64_dynarec_fastnan) {
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
VFCMP_D(v0, q0, q1, cUN);
|
||||
}
|
||||
VFSUB_D(q1, q1, q0);
|
||||
if (!box64_dynarec_fastnan) {
|
||||
VFCMP_D(v1, q1, q1, cUN);
|
||||
VANDN_V(v0, v0, v1);
|
||||
VLDI(v1, 0b011111111000); // broadcast 0xFFFFFFFFFFFFFFF8
|
||||
VSLLI_D(v1, v1, 48);
|
||||
VAND_V(v1, v0, v1);
|
||||
VANDN_V(v0, v0, q1);
|
||||
VOR_V(q1, v0, v1);
|
||||
}
|
||||
break;
|
||||
case 0x5E:
|
||||
INST_NAME("DIVPD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0, 0, 0);
|
||||
GETGX(q1, 1);
|
||||
if (!box64_dynarec_fastnan) {
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
VFCMP_D(v0, q0, q1, cUN);
|
||||
}
|
||||
VFDIV_D(q1, q1, q0);
|
||||
if (!box64_dynarec_fastnan) {
|
||||
VFCMP_D(v1, q1, q1, cUN);
|
||||
VANDN_V(v0, v0, v1);
|
||||
VLDI(v1, 0b011111111000); // broadcast 0xFFFFFFFFFFFFFFF8
|
||||
VSLLI_D(v1, v1, 48);
|
||||
VAND_V(v1, v0, v1);
|
||||
VANDN_V(v0, v0, q1);
|
||||
VOR_V(q1, v0, v1);
|
||||
}
|
||||
break;
|
||||
case 0x60:
|
||||
INST_NAME("PUNPCKLBW Gx,Ex");
|
||||
@@ -493,6 +642,21 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETEX(q0, 0, 0);
|
||||
VILVL_W(v0, q0, v0);
|
||||
break;
|
||||
case 0x63:
|
||||
INST_NAME("PACKSSWB Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
if (v0 == v1) {
|
||||
VSAT_H(v0, v0, 7);
|
||||
VPICKEV_B(v0, v0, v0);
|
||||
} else {
|
||||
VSAT_H(v0, v0, 7);
|
||||
VSAT_H(q0, v1, 7);
|
||||
VPICKEV_B(v0, q0, v0);
|
||||
}
|
||||
break;
|
||||
case 0x64:
|
||||
INST_NAME("PCMPGTB Gx,Ex");
|
||||
nextop = F8;
|
||||
@@ -555,6 +719,16 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETEX(q1, 0, 0);
|
||||
VILVH_W(q0, q1, q0);
|
||||
break;
|
||||
case 0x6B:
|
||||
INST_NAME("PACKSSDW Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
VOR_V(d0, v1, v1);
|
||||
VSSRANI_H_W(d0, v0, 0);
|
||||
VOR_V(v0, d0, d0);
|
||||
break;
|
||||
case 0x6C:
|
||||
INST_NAME("PUNPCKLQDQ Gx,Ex");
|
||||
nextop = F8;
|
||||
@@ -588,7 +762,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETGX_empty(v0);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
if (MODREG) {
|
||||
ed = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
if (rex.w) {
|
||||
MOVGR2FR_D(v1, ed);
|
||||
} else {
|
||||
@@ -774,6 +948,20 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0x74:
|
||||
INST_NAME("PCMPEQB Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(q0, 0, 0);
|
||||
VSEQ_B(v0, v0, q0);
|
||||
break;
|
||||
case 0x75:
|
||||
INST_NAME("PCMPEQW Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(q0, 0, 0);
|
||||
VSEQ_H(v0, v0, q0);
|
||||
break;
|
||||
case 0x76:
|
||||
INST_NAME("PCMPEQD Gx,Ex");
|
||||
nextop = F8;
|
||||
@@ -787,7 +975,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETGX(v0, 0);
|
||||
if (rex.w) {
|
||||
if (MODREG) {
|
||||
ed = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
MOVFR2GR_D(ed, v0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x3, &fixedaddress, rex, NULL, 1, 0);
|
||||
@@ -796,7 +984,7 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
}
|
||||
} else {
|
||||
if (MODREG) {
|
||||
ed = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
MOVFR2GR_S(ed, v0);
|
||||
ZEROUP(ed);
|
||||
} else {
|
||||
@@ -823,13 +1011,13 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
INST_NAME("IMUL Gw,Ew");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
nextop = F8;
|
||||
UFLAG_DF(x1, d_imul16);
|
||||
GETSEW(x1, 0);
|
||||
GETSGW(x2);
|
||||
MUL_W(x2, x2, x1);
|
||||
UFLAG_RES(x2);
|
||||
BSTRPICK_D(x2, x2, 15, 0);
|
||||
GWBACK;
|
||||
UFLAG_DF(x1, d_imul16);
|
||||
break;
|
||||
case 0xBE:
|
||||
INST_NAME("MOVSX Gw, Eb");
|
||||
@@ -837,12 +1025,12 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETGD;
|
||||
if (MODREG) {
|
||||
if (rex.rex) {
|
||||
ed = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
eb1 = ed;
|
||||
eb2 = 0;
|
||||
} else {
|
||||
ed = (nextop & 7);
|
||||
eb1 = TO_LA64(ed & 3); // Ax, Cx, Dx or Bx
|
||||
eb1 = TO_NAT(ed & 3); // Ax, Cx, Dx or Bx
|
||||
eb2 = (ed & 4) >> 2; // L or H
|
||||
}
|
||||
if (eb2) {
|
||||
@@ -858,6 +1046,80 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
}
|
||||
BSTRINS_D(gd, x1, 15, 0);
|
||||
break;
|
||||
case 0xC4:
|
||||
INST_NAME("PINSRW Gx, Ed, Ib");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
if (MODREG) {
|
||||
u8 = (F8) & 7;
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x4, &fixedaddress, rex, NULL, 1, 1);
|
||||
u8 = (F8) & 7;
|
||||
ed = x3;
|
||||
LD_HU(ed, wback, fixedaddress);
|
||||
}
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
MOVGR2FR_D(d0, ed);
|
||||
VEXTRINS_H(v0, d0, (u8 << 4));
|
||||
break;
|
||||
case 0xC5:
|
||||
INST_NAME("PEXTRW Gd, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if (MODREG) {
|
||||
GETEX(v0, 0, 1);
|
||||
u8 = (F8) & 7;
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
VBSRL_V(v1, v0, (u8 << 1));
|
||||
MOVFR2GR_D(gd, v1);
|
||||
BSTRPICK_D(gd, gd, 15, 0);
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x4, &fixedaddress, rex, NULL, 1, 1);
|
||||
u8 = (F8) & 7;
|
||||
LD_HU(gd, wback, (u8 << 1));
|
||||
}
|
||||
break;
|
||||
case 0xC6:
|
||||
INST_NAME("SHUFPD Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 1);
|
||||
u8 = F8;
|
||||
VSHUF4I_D(v0, v1, 0x8 | (u8 & 1) | ((u8 & 2) << 1));
|
||||
break;
|
||||
case 0xD2:
|
||||
INST_NAME("PSRLD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
VSAT_DU(v0, q1, 31);
|
||||
VREPLVEI_W(v0, v0, 0);
|
||||
VLDI(v1, 0b1000000011111); // broadcast 31 as uint32
|
||||
VSLT_WU(v1, v1, v0);
|
||||
VMINI_WU(v0, v0, 31);
|
||||
VSRL_W(q0, q0, v0);
|
||||
VSRL_W(q0, q0, v1);
|
||||
break;
|
||||
case 0xD3:
|
||||
INST_NAME("PSRLQ Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
v1 = fpu_get_scratch(dyn);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
VREPLVEI_D(v0, q1, 0);
|
||||
VLDI(v1, 0b0110000111111); // broadcast 63 as uint64
|
||||
VMIN_DU(d0, v0, v1);
|
||||
VSLT_DU(v1, v1, v0);
|
||||
VSRL_D(q0, q0, d0);
|
||||
VSRL_D(q0, q0, v1);
|
||||
break;
|
||||
case 0xD4:
|
||||
INST_NAME("PADDQ Gx, Ex");
|
||||
nextop = F8;
|
||||
@@ -902,7 +1164,14 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
VMSKLTZ_B(v0, q0);
|
||||
MOVFR2GR_D(x1, v0);
|
||||
BSTRINS_D(gd, x1, 15, 0);
|
||||
BSTRPICK_D(gd, x1, 15, 0);
|
||||
break;
|
||||
case 0xD9:
|
||||
INST_NAME("PSUBUSW Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
VSSUB_HU(q0, q0, q1);
|
||||
break;
|
||||
case 0xDB:
|
||||
INST_NAME("PAND Gx,Ex");
|
||||
@@ -925,6 +1194,30 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETEX(q0, 0, 0);
|
||||
VANDN_V(v0, v0, q0);
|
||||
break;
|
||||
case 0xE0:
|
||||
INST_NAME("PAVGB Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
VAVGR_BU(v0, v0, v1);
|
||||
break;
|
||||
case 0xE1:
|
||||
INST_NAME("PSRAW Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
v0 = fpu_get_scratch(dyn);
|
||||
VMINI_HU(v0, q1, 15);
|
||||
VREPLVEI_H(v0, v0, 0);
|
||||
VSRA_H(q0, q0, v0);
|
||||
break;
|
||||
case 0xE3:
|
||||
INST_NAME("PAVGW Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEX(v1, 0, 0);
|
||||
VAVGR_HU(v0, v0, v1);
|
||||
break;
|
||||
case 0xE4:
|
||||
INST_NAME("PMULHUW Gx,Ex");
|
||||
nextop = F8;
|
||||
@@ -939,6 +1232,14 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETEX(v1, 0, 0);
|
||||
VMUH_H(v0, v0, v1);
|
||||
break;
|
||||
case 0xE6:
|
||||
INST_NAME("CVTTPD2DQ Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(v1, 0, 0);
|
||||
GETGX_empty(v0);
|
||||
// TODO: fastround
|
||||
VFTINTRZ_W_D(v0, v1, v1);
|
||||
break;
|
||||
case 0xE7:
|
||||
INST_NAME("MOVNTDQ Ex, Gx");
|
||||
nextop = F8;
|
||||
@@ -979,6 +1280,36 @@ uintptr_t dynarec64_660F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETEX(v1, 0, 0);
|
||||
VMULWEV_D_WU(v0, v0, v1);
|
||||
break;
|
||||
case 0xF6:
|
||||
INST_NAME("PSADBW Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0, 1);
|
||||
GETEX(q1, 0, 0);
|
||||
d0 = fpu_get_scratch(dyn);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
VABSD_BU(q0, q0, q1);
|
||||
|
||||
// 8bit -> 16bit merge
|
||||
VPICKEV_B(d0, q0, q0);
|
||||
VPICKOD_B(d1, q0, q0);
|
||||
VEXTH_HU_BU(d0, d0);
|
||||
VEXTH_HU_BU(d1, d1);
|
||||
VADD_H(q0, d0, d1);
|
||||
|
||||
// 16bit to 32bit merge
|
||||
VPICKEV_H(d0, q0, q0);
|
||||
VPICKOD_H(d1, q0, q0);
|
||||
VEXTH_WU_HU(d0, d0);
|
||||
VEXTH_WU_HU(d1, d1);
|
||||
VADD_W(q0, d0, d1);
|
||||
|
||||
// 32bit to 64bit merge
|
||||
VPICKEV_W(d0, q0, q0);
|
||||
VPICKOD_W(d1, q0, q0);
|
||||
VEXTH_DU_WU(d0, d0);
|
||||
VEXTH_DU_WU(d1, d1);
|
||||
VADD_D(q0, d0, d1);
|
||||
break;
|
||||
case 0xF8:
|
||||
INST_NAME("PSUBB Gx,Ex");
|
||||
nextop = F8;
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
#include "la64_printer.h"
|
||||
#include "dynarec_la64_private.h"
|
||||
#include "dynarec_la64_helper.h"
|
||||
#include "../dynarec_helper.h"
|
||||
#include "dynarec_la64_functions.h"
|
||||
|
||||
uintptr_t dynarec64_6664(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int seg, int* ok, int* need_epilog)
|
||||
@@ -44,7 +44,7 @@ uintptr_t dynarec64_6664(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if (MODREG) { // reg <= reg
|
||||
ed = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
if (rex.w) {
|
||||
MV(gd, ed);
|
||||
} else {
|
||||
@@ -54,10 +54,11 @@ uintptr_t dynarec64_6664(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
grab_segdata(dyn, addr, ninst, x4, seg);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, NULL, 1, 0);
|
||||
ADDz(x4, ed, x4);
|
||||
if (rex.w) {
|
||||
LDX_D(gd, ed, x4);
|
||||
LD_D(gd, x4, fixedaddress);
|
||||
} else {
|
||||
LDX_HU(x1, ed, x4);
|
||||
LD_HU(x1, x4, fixedaddress);
|
||||
BSTRINS_D(gd, x1, 15, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
#include "la64_printer.h"
|
||||
#include "dynarec_la64_private.h"
|
||||
#include "dynarec_la64_helper.h"
|
||||
#include "../dynarec_helper.h"
|
||||
#include "dynarec_la64_functions.h"
|
||||
|
||||
uintptr_t dynarec64_67(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int rep, int* ok, int* need_epilog)
|
||||
@@ -62,16 +62,53 @@ uintptr_t dynarec64_67(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
}
|
||||
|
||||
switch(opcode) {
|
||||
case 0x19:
|
||||
INST_NAME("SBB Ed, Gd");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED32(0);
|
||||
emit_sbb32(dyn, ninst, rex, ed, gd, x3, x4, x5);
|
||||
WBACK;
|
||||
break;
|
||||
case 0x1A:
|
||||
INST_NAME("SBB Gb, Eb");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETEB32(x2, 0);
|
||||
GETGB(x1);
|
||||
emit_sbb8(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
GBBACK();
|
||||
break;
|
||||
case 0x1B:
|
||||
INST_NAME("SBB Gd, Ed");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETED32(0);
|
||||
emit_sbb32(dyn, ninst, rex, gd, ed, x3, x4, x5);
|
||||
break;
|
||||
case 0x1D:
|
||||
INST_NAME("SBB EAX, Id");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i64 = F32S;
|
||||
MOV64xw(x2, i64);
|
||||
emit_sbb32(dyn, ninst, rex, xRAX, x2, x3, x4, x5);
|
||||
break;
|
||||
case 0x88:
|
||||
INST_NAME("MOV Eb, Gb");
|
||||
nextop = F8;
|
||||
gd = ((nextop & 0x38) >> 3) + (rex.r << 3);
|
||||
if (rex.rex) {
|
||||
gb2 = 0;
|
||||
gb1 = TO_LA64(gd);
|
||||
gb1 = TO_NAT(gd);
|
||||
} else {
|
||||
gb2 = ((gd & 4) << 1);
|
||||
gb1 = TO_LA64(gd & 3);
|
||||
gb1 = TO_NAT(gd & 3);
|
||||
}
|
||||
if (gb2) {
|
||||
gd = x4;
|
||||
@@ -82,10 +119,10 @@ uintptr_t dynarec64_67(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
if (MODREG) {
|
||||
ed = (nextop & 7) + (rex.b << 3);
|
||||
if (rex.rex) {
|
||||
eb1 = TO_LA64(ed);
|
||||
eb1 = TO_NAT(ed);
|
||||
eb2 = 0;
|
||||
} else {
|
||||
eb1 = TO_LA64(ed & 3); // Ax, Cx, Dx or Bx
|
||||
eb1 = TO_NAT(ed & 3); // Ax, Cx, Dx or Bx
|
||||
eb2 = ((ed & 4) >> 2); // L or H
|
||||
}
|
||||
BSTRINS_D(eb1, gd, eb2 * 8 + 7, eb2 * 8);
|
||||
@@ -100,13 +137,24 @@ uintptr_t dynarec64_67(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if (MODREG) { // reg <= reg
|
||||
MVxw(TO_LA64((nextop & 7) + (rex.b << 3)), gd);
|
||||
MVxw(TO_NAT((nextop & 7) + (rex.b << 3)), gd);
|
||||
} else { // mem <= reg
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, x2, x1, &fixedaddress, rex, &lock, 1, 0);
|
||||
SDxw(gd, ed, fixedaddress);
|
||||
SMWRITELOCK(lock);
|
||||
}
|
||||
break;
|
||||
case 0x8D:
|
||||
INST_NAME("LEA Gd, Ed");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if (MODREG) { // reg <= reg? that's an invalid operation
|
||||
DEFAULT;
|
||||
} else { // mem <= reg
|
||||
addr = geted32(dyn, addr, ninst, nextop, &ed, gd, x1, &fixedaddress, rex, NULL, 0, 0);
|
||||
ZEROUP2(gd, ed);
|
||||
}
|
||||
break;
|
||||
case 0xF7:
|
||||
nextop = F8;
|
||||
switch ((nextop >> 3) & 7) {
|
||||
@@ -124,7 +172,7 @@ uintptr_t dynarec64_67(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
if (gd != xRDX) MV(xRDX, gd);
|
||||
} else {
|
||||
MUL_D(xRDX, xRAX, ed); // 64 <- 32x32
|
||||
AND(xRAX, xRDX, xMASK);
|
||||
ZEROUP2(xRAX, xRDX);
|
||||
SRLI_W(xRDX, xRDX, 32);
|
||||
}
|
||||
UFLAG_RES(xRAX);
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#include "la64_printer.h"
|
||||
#include "dynarec_la64_private.h"
|
||||
#include "dynarec_la64_functions.h"
|
||||
#include "dynarec_la64_helper.h"
|
||||
#include "../dynarec_helper.h"
|
||||
|
||||
// emit XOR8 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed)
|
||||
void emit_xor8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#include "la64_printer.h"
|
||||
#include "dynarec_la64_private.h"
|
||||
#include "dynarec_la64_functions.h"
|
||||
#include "dynarec_la64_helper.h"
|
||||
#include "../dynarec_helper.h"
|
||||
|
||||
// emit ADD32 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
|
||||
void emit_add32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5)
|
||||
@@ -57,8 +57,8 @@ void emit_add32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
IFX(X_CF)
|
||||
{
|
||||
if (rex.w) {
|
||||
AND(s5, xMASK, s1);
|
||||
AND(s4, xMASK, s2);
|
||||
ZEROUP2(s5, s1);
|
||||
ZEROUP2(s4, s2);
|
||||
ADD_D(s5, s5, s4);
|
||||
SRLI_D(s3, s1, 0x20);
|
||||
SRLI_D(s4, s2, 0x20);
|
||||
@@ -69,8 +69,8 @@ void emit_add32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
BEQZ(s5, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_CF);
|
||||
} else {
|
||||
AND(s3, s1, xMASK);
|
||||
AND(s4, s2, xMASK);
|
||||
ZEROUP2(s3, s1);
|
||||
ZEROUP2(s4, s2);
|
||||
ADD_D(s5, s3, s4);
|
||||
SRLI_D(s5, s5, 0x20);
|
||||
BEQZ(s5, 8);
|
||||
@@ -134,11 +134,12 @@ void emit_add32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i
|
||||
if (s1 == xRSP && (!dyn->insts || dyn->insts[ninst].x64.gen_flags == X_PEND)) {
|
||||
// special case when doing math on ESP and only PEND is needed: ignoring it!
|
||||
if (c >= -2048 && c < 2048) {
|
||||
ADDIxw(s1, s1, c);
|
||||
ADDI_D(s1, s1, c);
|
||||
} else {
|
||||
MOV64xw(s2, c);
|
||||
ADDxw(s1, s1, s2);
|
||||
MOV64x(s2, c);
|
||||
ADD_D(s1, s1, s2);
|
||||
}
|
||||
if (!rex.w) { ZEROUP(s1); }
|
||||
return;
|
||||
}
|
||||
IFX(X_PEND | X_AF | X_CF | X_OF)
|
||||
@@ -177,8 +178,8 @@ void emit_add32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i
|
||||
IFX(X_CF)
|
||||
{
|
||||
if (rex.w) {
|
||||
AND(s5, xMASK, s1);
|
||||
AND(s4, xMASK, s2);
|
||||
ZEROUP2(s5, s1);
|
||||
ZEROUP2(s4, s2);
|
||||
ADD_D(s5, s5, s4);
|
||||
SRLI_D(s3, s1, 0x20);
|
||||
SRLI_D(s4, s2, 0x20);
|
||||
@@ -189,8 +190,8 @@ void emit_add32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i
|
||||
BEQZ(s5, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_CF);
|
||||
} else {
|
||||
AND(s3, s1, xMASK);
|
||||
AND(s4, s2, xMASK);
|
||||
ZEROUP2(s3, s1);
|
||||
ZEROUP2(s4, s2);
|
||||
ADD_D(s5, s3, s4);
|
||||
SRLI_D(s5, s5, 0x20);
|
||||
BEQZ(s5, 8);
|
||||
@@ -422,7 +423,7 @@ void emit_add16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4,
|
||||
}
|
||||
|
||||
IFXA (X_ALL, la64_lbt) {
|
||||
X64_ADD_DU(s1, s2);
|
||||
X64_ADD_H(s1, s2);
|
||||
}
|
||||
|
||||
ADD_D(s1, s1, s2);
|
||||
@@ -642,6 +643,7 @@ void emit_sub32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i
|
||||
MOV64xw(s2, c);
|
||||
SUBxw(s1, s1, s2);
|
||||
}
|
||||
if (!rex.w) { ZEROUP(s1); }
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -729,7 +731,7 @@ void emit_sbb8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, i
|
||||
X64_SBC_B(s1, s2);
|
||||
}
|
||||
|
||||
MV(s1, s3);
|
||||
ANDI(s1, s3, 0xff);
|
||||
IFX (X_PEND)
|
||||
ST_B(s1, xEmu, offsetof(x64emu_t, res));
|
||||
return;
|
||||
@@ -1027,6 +1029,165 @@ void emit_neg32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
}
|
||||
}
|
||||
|
||||
// emit ADC8 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
|
||||
void emit_adc8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
IFX (X_PEND) {
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
ST_H(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_adc8);
|
||||
} else IFX (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
ADC_B(s3, s1, s2);
|
||||
|
||||
IFX (X_ALL) {
|
||||
X64_ADC_B(s1, s2);
|
||||
}
|
||||
MV(s1, s3);
|
||||
IFX (X_PEND) {
|
||||
ST_W(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
IFX (X_AF | X_OF) {
|
||||
OR(s4, s1, s2); // s4 = op1 | op2
|
||||
AND(s5, s1, s2); // s5 = op1 & op2
|
||||
}
|
||||
|
||||
ADD_D(s1, s1, s2);
|
||||
ANDI(s3, xFlags, 1 << F_CF);
|
||||
ADD_D(s1, s1, s3);
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX (X_PEND) {
|
||||
ST_W(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX (X_AF | X_OF) {
|
||||
ANDN(s3, s4, s1); // s3 = ~res & (op1 | op2)
|
||||
OR(s3, s3, s5); // cc = (~res & (op1 | op2)) | (op1 & op2)
|
||||
IFX (X_AF) {
|
||||
ANDI(s4, s3, 0x08); // AF: cc & 0x08
|
||||
BEQZ(s4, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_AF);
|
||||
}
|
||||
IFX (X_OF) {
|
||||
SRLI_D(s3, s3, 6);
|
||||
SRLI_D(s4, s3, 1);
|
||||
XOR(s3, s3, s4);
|
||||
ANDI(s3, s3, 1); // OF: xor of two MSB's of cc
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_OF);
|
||||
}
|
||||
}
|
||||
IFX (X_CF) {
|
||||
SRLI_D(s3, s1, 8);
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_CF);
|
||||
}
|
||||
|
||||
ANDI(s1, s1, 0xff);
|
||||
|
||||
IFX (X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX (X_SF) {
|
||||
SRLI_D(s3, s1, 7);
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
IFX (X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit ADC8 instruction, from s1, const c, store result in s1 using s3, s4, s5 and s6 as scratch
|
||||
void emit_adc8c(dynarec_la64_t* dyn, int ninst, int s1, int32_t c, int s3, int s4, int s5, int s6)
|
||||
{
|
||||
MOV32w(s5, c & 0xff);
|
||||
emit_adc8(dyn, ninst, s1, s5, s3, s4, s6);
|
||||
}
|
||||
|
||||
// emit ADC16 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
|
||||
void emit_adc16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
|
||||
{
|
||||
IFX (X_PEND) {
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
ST_H(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s3, d_adc16);
|
||||
} else IFX (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
ADC_H(s3, s1, s2);
|
||||
|
||||
IFX (X_ALL) {
|
||||
X64_ADC_H(s1, s2);
|
||||
}
|
||||
MV(s1, s3);
|
||||
IFX (X_PEND) {
|
||||
ST_W(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
IFX (X_AF | X_OF) {
|
||||
OR(s4, s1, s2); // s4 = op1 | op2
|
||||
AND(s5, s1, s2); // s5 = op1 & op2
|
||||
}
|
||||
|
||||
ADD_D(s1, s1, s2);
|
||||
ANDI(s3, xFlags, 1 << F_CF);
|
||||
ADD_D(s1, s1, s3);
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX (X_PEND) {
|
||||
ST_W(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX (X_AF | X_OF) {
|
||||
ANDN(s3, s4, s1); // s3 = ~res & (op1 | op2)
|
||||
OR(s3, s3, s5); // cc = (~res & (op1 | op2)) | (op1 & op2)
|
||||
IFX (X_AF) {
|
||||
ANDI(s4, s3, 0x08); // AF: cc & 0x08
|
||||
BEQZ(s4, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_AF);
|
||||
}
|
||||
IFX (X_OF) {
|
||||
SRLI_D(s3, s3, 14);
|
||||
SRLI_D(s4, s3, 1);
|
||||
XOR(s3, s3, s4);
|
||||
ANDI(s3, s3, 1); // OF: xor of two MSB's of cc
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_OF);
|
||||
}
|
||||
}
|
||||
IFX (X_CF) {
|
||||
SRLI_D(s3, s1, 16);
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_CF);
|
||||
}
|
||||
|
||||
BSTRPICK_D(s1, s1, 15, 0);
|
||||
|
||||
IFX (X_ZF) {
|
||||
BNEZ(s1, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
IFX (X_SF) {
|
||||
SRLI_D(s3, s1, 15);
|
||||
BEQZ(s3, 8);
|
||||
ORI(xFlags, xFlags, 1 << F_SF);
|
||||
}
|
||||
IFX (X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit ADC32 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
|
||||
void emit_adc32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5, int s6)
|
||||
{
|
||||
@@ -1059,8 +1220,8 @@ void emit_adc32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
|
||||
IFX (X_CF) {
|
||||
if (rex.w) {
|
||||
AND(s5, xMASK, s1);
|
||||
AND(s4, xMASK, s2);
|
||||
ZEROUP2(s5, s1);
|
||||
ZEROUP2(s4, s2);
|
||||
ADD_D(s5, s5, s4); // lo
|
||||
ANDI(s3, xFlags, 1);
|
||||
ADD_D(s5, s5, s3); // add carry
|
||||
@@ -1071,8 +1232,8 @@ void emit_adc32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
ADD_D(s5, s5, s4); // hi
|
||||
SRAI_D(s6, s5, 0x20);
|
||||
} else {
|
||||
AND(s3, s1, xMASK);
|
||||
AND(s4, s2, xMASK);
|
||||
ZEROUP2(s3, s1);
|
||||
ZEROUP2(s4, s2);
|
||||
ADD_D(s5, s3, s4);
|
||||
ANDI(s3, xFlags, 1);
|
||||
ADD_D(s5, s5, s3); // add carry
|
||||
@@ -1558,7 +1719,7 @@ void emit_neg16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
MV(s3, s1); // s3 = op1
|
||||
}
|
||||
|
||||
NOR(s1, s1, xZR);
|
||||
NEG_D(s1, s1);
|
||||
BSTRPICK_D(s1, s1, 15, 0);
|
||||
IFX (X_PEND) {
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, res));
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#include "la64_printer.h"
|
||||
#include "dynarec_la64_private.h"
|
||||
#include "dynarec_la64_functions.h"
|
||||
#include "dynarec_la64_helper.h"
|
||||
#include "../dynarec_helper.h"
|
||||
|
||||
// emit SHL16 instruction, from s1 , shift s2, store result in s1 using s3, s4 and s5 as scratch
|
||||
void emit_shl16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
|
||||
@@ -514,7 +514,7 @@ void emit_sar16(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4,
|
||||
IFX (X_PEND) {
|
||||
ST_H(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
ST_H(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
SET_DF(s4, d_sar8);
|
||||
SET_DF(s4, d_sar16);
|
||||
} else IFX (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
@@ -612,6 +612,8 @@ void emit_sar32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
|
||||
}
|
||||
OR(xFlags, xFlags, s3);
|
||||
}
|
||||
// For the SAR instruction, the OF flag is cleared for all 1-bit shifts.
|
||||
// OF nop
|
||||
|
||||
if (rex.w) {
|
||||
SRAI_D(s1, s1, c);
|
||||
@@ -659,13 +661,11 @@ void emit_ror32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
|
||||
return;
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
IFX (X_ALL) {
|
||||
if (rex.w)
|
||||
X64_ROTRI_D(s1, c);
|
||||
else
|
||||
X64_ROTRI_W(s1, c);
|
||||
}
|
||||
IFXA ((X_CF | X_OF), la64_lbt) {
|
||||
if (rex.w)
|
||||
X64_ROTRI_D(s1, c);
|
||||
else
|
||||
X64_ROTRI_W(s1, c);
|
||||
}
|
||||
|
||||
ROTRIxw(s1, s1, c);
|
||||
@@ -676,7 +676,10 @@ void emit_ror32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
|
||||
|
||||
if (la64_lbt) return;
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX (X_CF | X_OF) {
|
||||
MOV64x(s4, ((1UL << F_CF) | (1UL << F_OF)));
|
||||
ANDN(xFlags, xFlags, s4);
|
||||
}
|
||||
IFX (X_CF) {
|
||||
SRLIxw(s3, s1, rex.w ? 63 : 31);
|
||||
OR(xFlags, xFlags, s3);
|
||||
@@ -706,26 +709,18 @@ void emit_rol32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
IFX (X_ALL) {
|
||||
if (rex.w)
|
||||
X64_ROTL_D(s1, s2);
|
||||
else
|
||||
X64_ROTL_W(s1, s2);
|
||||
}
|
||||
}
|
||||
|
||||
if (rex.w) {
|
||||
ANDI(s4, s2, 0x3f);
|
||||
} else {
|
||||
ANDI(s4, s2, 0x1f);
|
||||
IFXA ((X_CF | X_OF), la64_lbt) {
|
||||
if (rex.w)
|
||||
X64_ROTL_D(s1, s2);
|
||||
else
|
||||
X64_ROTL_W(s1, s2);
|
||||
}
|
||||
|
||||
if (!rex.w) ZEROUP(s1);
|
||||
BEQ_NEXT(s4, xZR);
|
||||
BEQ_NEXT(s2, xZR);
|
||||
|
||||
SLLxw(s3, s1, s4);
|
||||
NEG_D(s4, s4);
|
||||
SLLxw(s3, s1, s2);
|
||||
NEG_D(s4, s2);
|
||||
ADDI_D(s4, s4, rex.w ? 64 : 32);
|
||||
SRLxw(s1, s1, s4);
|
||||
OR(s1, s3, s1);
|
||||
@@ -736,19 +731,80 @@ void emit_rol32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
|
||||
if (la64_lbt) return;
|
||||
|
||||
CLEAR_FLAGS(s3);
|
||||
IFX (X_CF | X_OF) {
|
||||
MOV64x(s4, ((1UL << F_CF) | (1UL << F_OF)));
|
||||
ANDN(xFlags, xFlags, s4);
|
||||
}
|
||||
IFX (X_CF | X_OF) {
|
||||
ANDI(s4, s1, 1); // LSB == F_CF
|
||||
IFX (X_CF) OR(xFlags, xFlags, s4);
|
||||
}
|
||||
IFX (X_OF) {
|
||||
// the OF flag is set to the exclusive OR of the CF bit (after the rotate) and the most-significant bit of the result.
|
||||
ADDI_D(s3, xZR, 1);
|
||||
BNE_NEXT(s2, s3);
|
||||
ADDI_D(s3, s2, -1);
|
||||
BNEZ_MARK(s3);
|
||||
SRLIxw(s3, s1, rex.w ? 63 : 31);
|
||||
XOR(s3, s3, s4); // s3: MSB, s4: CF bit
|
||||
SLLI_D(s3, s3, F_OF);
|
||||
OR(xFlags, xFlags, s3);
|
||||
MARK;
|
||||
}
|
||||
}
|
||||
|
||||
// emit ROR32 instruction, from s1, s2, store result in s1 using s3 and s4 as scratch
|
||||
void emit_ror32(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
int64_t j64;
|
||||
|
||||
if (!rex.w) {
|
||||
ZEROUP(s1);
|
||||
}
|
||||
BEQ_NEXT(s2, xZR);
|
||||
IFX (X_PEND) {
|
||||
SDxw(s2, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, rex.w ? d_ror64 : d_ror32);
|
||||
} else IFX (X_ALL) {
|
||||
SET_DFNONE();
|
||||
}
|
||||
|
||||
IFXA ((X_CF | X_OF), la64_lbt) {
|
||||
if (rex.w)
|
||||
X64_ROTR_D(s1, s2);
|
||||
else
|
||||
X64_ROTR_W(s1, s2);
|
||||
}
|
||||
|
||||
if (rex.w) {
|
||||
ROTR_D(s1, s1, s2);
|
||||
} else {
|
||||
ROTR_W(s1, s1, s2);
|
||||
}
|
||||
|
||||
IFX (X_PEND) {
|
||||
SDxw(s1, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
|
||||
if (la64_lbt) return;
|
||||
|
||||
IFX (X_CF | X_OF) {
|
||||
MOV64x(s4, ((1UL << F_CF) | (1UL << F_OF)));
|
||||
ANDN(xFlags, xFlags, s4);
|
||||
}
|
||||
IFX (X_CF) {
|
||||
SRLIxw(s3, s1, rex.w ? 63 : 31);
|
||||
OR(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX (X_OF) {
|
||||
// the OF flag is set to the exclusive OR of the two most-significant bits of the result
|
||||
ADDI_D(s3, s2, -1);
|
||||
BNEZ_MARK(s3);
|
||||
SRLIxw(s3, s1, rex.w ? 63 : 31);
|
||||
SRLIxw(s4, s1, rex.w ? 62 : 30);
|
||||
XOR(s3, s3, s4);
|
||||
ANDI(s3, s3, 1);
|
||||
SLLI_D(s3, s3, F_OF);
|
||||
OR(xFlags, xFlags, s3);
|
||||
MARK;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -772,13 +828,11 @@ void emit_rol32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
|
||||
return;
|
||||
}
|
||||
|
||||
if (la64_lbt) {
|
||||
IFX (X_CF | X_OF) {
|
||||
if (rex.w)
|
||||
X64_ROTLI_D(s1, c);
|
||||
else
|
||||
X64_ROTLI_W(s1, c);
|
||||
}
|
||||
IFXA ((X_CF | X_OF), la64_lbt) {
|
||||
if (rex.w)
|
||||
X64_ROTLI_D(s1, c);
|
||||
else
|
||||
X64_ROTLI_W(s1, c);
|
||||
}
|
||||
|
||||
ROTRIxw(s1, s1, (rex.w ? 64 : 32) - c);
|
||||
@@ -792,7 +846,7 @@ void emit_rol32c(dynarec_la64_t* dyn, int ninst, rex_t rex, int s1, uint32_t c,
|
||||
if (la64_lbt) return;
|
||||
|
||||
IFX (X_CF | X_OF) {
|
||||
MOV64x(s3, (1UL << F_CF | 1UL << F_OF));
|
||||
MOV64x(s3, ((1UL << F_CF) | (1UL << F_OF)));
|
||||
ANDN(xFlags, xFlags, s3);
|
||||
}
|
||||
IFX (X_CF | X_OF) {
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#include "la64_printer.h"
|
||||
#include "dynarec_la64_private.h"
|
||||
#include "dynarec_la64_functions.h"
|
||||
#include "dynarec_la64_helper.h"
|
||||
#include "../dynarec_helper.h"
|
||||
|
||||
|
||||
// emit CMP8 instruction, from cmp s1, s2, using s3, s4, s5 and s6 as scratch
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
#include "la64_printer.h"
|
||||
#include "dynarec_la64_private.h"
|
||||
#include "dynarec_la64_helper.h"
|
||||
#include "../dynarec_helper.h"
|
||||
#include "dynarec_la64_functions.h"
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
GETGD;
|
||||
SMDMB();
|
||||
if ((nextop & 0xC0) == 0xC0) {
|
||||
ed = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
emit_add32(dyn, ninst, rex, ed, gd, x3, x4, x5);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
|
||||
@@ -75,9 +75,103 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
}
|
||||
SMDMB();
|
||||
break;
|
||||
case 0x09:
|
||||
INST_NAME("LOCK OR Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
SMDMB();
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
emit_or32(dyn, ninst, rex, ed, gd, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
|
||||
MARKLOCK;
|
||||
LLxw(x1, wback, 0);
|
||||
OR(x4, x1, gd);
|
||||
SCxw(x4, wback, 0);
|
||||
BEQZ_MARKLOCK(x4);
|
||||
IFX (X_ALL | X_PEND)
|
||||
emit_or32(dyn, ninst, rex, x1, gd, x3, x4);
|
||||
}
|
||||
SMDMB();
|
||||
break;
|
||||
case 0x0F:
|
||||
nextop = F8;
|
||||
switch (nextop) {
|
||||
case 0xB0:
|
||||
switch (rep) {
|
||||
case 0:
|
||||
INST_NAME("LOCK CMPXCHG Eb, Gb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
ANDI(x6, xRAX, 0xff); // AL
|
||||
SMDMB();
|
||||
if (MODREG) {
|
||||
if (rex.rex) {
|
||||
wback = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
wb2 = 0;
|
||||
} else {
|
||||
wback = (nextop & 7);
|
||||
wb2 = (wback >> 2) * 8;
|
||||
wback = TO_NAT(wback & 3);
|
||||
}
|
||||
BSTRPICK_D(x2, wback, wb2 + 7, wb2);
|
||||
wb1 = 0;
|
||||
ed = x2;
|
||||
UFLAG_IF {
|
||||
emit_cmp8(dyn, ninst, x6, ed, x3, x4, x5, x1);
|
||||
}
|
||||
BNE_MARK2(x6, x2);
|
||||
BSTRPICK_D(wback, x2, wb2 + 7, wb2);
|
||||
GETGB(x1);
|
||||
MV(ed, gd);
|
||||
MARK2;
|
||||
BSTRINS_D(xRAX, x2, 7, 0);
|
||||
B_NEXT_nocond;
|
||||
} else {
|
||||
if (rex.rex) {
|
||||
gb1 = TO_NAT(((nextop & 0x38) >> 3) + (rex.r << 3));
|
||||
gb2 = 0;
|
||||
} else {
|
||||
gd = (nextop & 0x38) >> 3;
|
||||
gb2 = ((gd & 4) >> 2) * 8;
|
||||
gb1 = TO_NAT(gd & 3);
|
||||
}
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, x2, &fixedaddress, rex, LOCK_LOCK, 0, 0);
|
||||
ANDI(x5, wback, 0b11);
|
||||
SLLI_D(x5, x5, 3); // shamt
|
||||
MARKLOCK;
|
||||
ADDI_D(x7, xZR, ~0b11);
|
||||
AND(x7, wback, x7); // align to 32bit
|
||||
LD_WU(x1, x7, 0);
|
||||
LL_W(x4, x7, 0);
|
||||
SRL_D(x4, x4, x5);
|
||||
ANDI(x4, x4, 0xff);
|
||||
BNE_MARK(x6, x4); // compare AL with m8
|
||||
// AL == m8, r8 is loaded into m8
|
||||
ADDI_D(x2, xZR, 0xff);
|
||||
SLL_D(x2, x2, x5);
|
||||
NOR(x2, x2, xZR);
|
||||
AND(x2, x1, x2);
|
||||
BSTRPICK_D(x1, gb1, gb2 + 7, gb2);
|
||||
SLL_D(x1, x1, x5);
|
||||
OR(x1, x1, x2);
|
||||
SC_W(x1, x7, 0);
|
||||
BEQZ_MARKLOCK(x1);
|
||||
// done
|
||||
MARK;
|
||||
UFLAG_IF { emit_cmp8(dyn, ninst, x6, x4, x1, x2, x3, x5); }
|
||||
// load m8 into AL
|
||||
ANDI(xRAX, xRAX, ~0xff);
|
||||
OR(xRAX, xRAX, x4);
|
||||
}
|
||||
SMDMB();
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0xB1:
|
||||
switch (rep) {
|
||||
case 0:
|
||||
@@ -86,7 +180,7 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
if (MODREG) {
|
||||
ed = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
wback = 0;
|
||||
UFLAG_IF { emit_cmp32(dyn, ninst, rex, xRAX, ed, x3, x4, x5, x6); }
|
||||
MV(x1, ed); // save value
|
||||
@@ -142,7 +236,7 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
GETGD;
|
||||
SMDMB();
|
||||
if (MODREG) {
|
||||
ed = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
MVxw(x1, ed);
|
||||
MVxw(ed, gd);
|
||||
MVxw(gd, x1);
|
||||
@@ -167,21 +261,29 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
}
|
||||
break;
|
||||
case 0xC7:
|
||||
switch (rep) {
|
||||
case 0:
|
||||
// rep has no impact here
|
||||
nextop = F8;
|
||||
switch ((nextop >> 3) & 7) {
|
||||
case 1:
|
||||
if (rex.w) {
|
||||
INST_NAME("LOCK CMPXCHG16B Gq, Eq");
|
||||
if (!la64_scq) {
|
||||
static int warned = 0;
|
||||
PASS3(if (!warned) dynarec_log(LOG_INFO, "Warning, LOCK CMPXCHG16B is not well supported on LoongArch without SCQ and issues are expected.\n"));
|
||||
warned = 1;
|
||||
}
|
||||
} else {
|
||||
INST_NAME("LOCK CMPXCHG8B Gq, Eq");
|
||||
}
|
||||
SETFLAGS(X_ZF, SF_SUBSET);
|
||||
nextop = F8;
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, x2, &fixedaddress, rex, LOCK_LOCK, 0, 0);
|
||||
if (la64_lbt) {
|
||||
X64_SET_EFLAGS(xZR, X_ZF);
|
||||
} else {
|
||||
ADDI_D(x2, xZR, ~(1 << F_ZF));
|
||||
AND(xFlags, xFlags, x2);
|
||||
UFLAG_IF {
|
||||
if (la64_lbt) {
|
||||
X64_SET_EFLAGS(xZR, X_ZF);
|
||||
} else {
|
||||
ADDI_D(x2, xZR, ~(1 << F_ZF));
|
||||
AND(xFlags, xFlags, x2);
|
||||
}
|
||||
}
|
||||
if (rex.w) {
|
||||
if (la64_scq) {
|
||||
@@ -194,11 +296,13 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
MV(x5, xRBX);
|
||||
SC_Q(x5, xRCX, wback);
|
||||
BEQZ_MARKLOCK(x5);
|
||||
if (la64_lbt) {
|
||||
ADDI_D(x5, xZR, -1);
|
||||
X64_SET_EFLAGS(x5, X_ZF);
|
||||
} else {
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
UFLAG_IF {
|
||||
if (la64_lbt) {
|
||||
ADDI_D(x5, xZR, -1);
|
||||
X64_SET_EFLAGS(x5, X_ZF);
|
||||
} else {
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
}
|
||||
B_MARK3_nocond;
|
||||
MARK;
|
||||
@@ -222,11 +326,13 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
BNE_MARK(x3, xRDX);
|
||||
ST_D(xRBX, wback, 0);
|
||||
ST_D(xRCX, wback, 8);
|
||||
if (la64_lbt) {
|
||||
ADDI_D(x5, xZR, -1);
|
||||
X64_SET_EFLAGS(x5, X_ZF);
|
||||
} else {
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
UFLAG_IF {
|
||||
if (la64_lbt) {
|
||||
ADDI_D(x5, xZR, -1);
|
||||
X64_SET_EFLAGS(x5, X_ZF);
|
||||
} else {
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
}
|
||||
B_MARK3_nocond;
|
||||
MARK;
|
||||
@@ -239,28 +345,51 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
}
|
||||
} else {
|
||||
SMDMB();
|
||||
AND(x3, xRAX, xMASK);
|
||||
SLLI_D(x2, xRDX, 32);
|
||||
OR(x3, x3, x2);
|
||||
AND(x4, xRBX, xMASK);
|
||||
SLLI_D(x2, xRCX, 32);
|
||||
OR(x4, x4, x2);
|
||||
BSTRINS_D(x3, xRAX, 31, 0);
|
||||
BSTRINS_D(x3, xRDX, 63, 32);
|
||||
BSTRINS_D(x4, xRBX, 31, 0);
|
||||
BSTRINS_D(x4, xRCX, 63, 32);
|
||||
ANDI(x2, wback, 7);
|
||||
BNEZ_MARK2(x2);
|
||||
// Aligned
|
||||
MARKLOCK;
|
||||
LL_D(x2, wback, 0);
|
||||
BNE_MARK(x2, x3); // EDX_EAX != Ed
|
||||
MV(x5, x4);
|
||||
SC_D(x5, wback, 0);
|
||||
BEQZ_MARKLOCK(x5);
|
||||
if (la64_lbt) {
|
||||
ADDI_D(x5, xZR, -1);
|
||||
X64_SET_EFLAGS(x5, X_ZF);
|
||||
} else {
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
UFLAG_IF {
|
||||
if (la64_lbt) {
|
||||
ADDI_D(x5, xZR, -1);
|
||||
X64_SET_EFLAGS(x5, X_ZF);
|
||||
} else {
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
}
|
||||
B_MARK3_nocond;
|
||||
MARK2;
|
||||
// Unaligned
|
||||
ADDI_W(x5, xZR, 0xFF8);
|
||||
AND(x5, wback, x5);
|
||||
MARKLOCK2;
|
||||
LD_D(x2, wback, 0);
|
||||
LL_D(x6, x5, 0);
|
||||
BNE_MARK(x2, x3); // EDX_EAX != Ed
|
||||
SC_D(x6, x5, 0);
|
||||
BEQZ_MARKLOCK2(x6);
|
||||
ST_D(x4, wback, 0);
|
||||
UFLAG_IF {
|
||||
if (la64_lbt) {
|
||||
ADDI_D(x5, xZR, -1);
|
||||
X64_SET_EFLAGS(x5, X_ZF);
|
||||
} else {
|
||||
ORI(xFlags, xFlags, 1 << F_ZF);
|
||||
}
|
||||
}
|
||||
B_MARK3_nocond;
|
||||
MARK;
|
||||
SLLI_D(xRDX, x2, 32);
|
||||
AND(xRAX, x2, xMASK);
|
||||
ZEROUP2(xRAX, x2);
|
||||
MARK3;
|
||||
SMDMB();
|
||||
}
|
||||
@@ -273,6 +402,31 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
case 0x11:
|
||||
INST_NAME("LOCK ADC Ed, Gd");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
SMDMB();
|
||||
if (MODREG) {
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
emit_adc32(dyn, ninst, rex, ed, gd, x3, x4, x5, x6);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
|
||||
MARKLOCK;
|
||||
LLxw(x1, wback, 0);
|
||||
ADDxw(x3, x1, gd);
|
||||
ANDI(x4, xFlags, 1 << F_CF);
|
||||
ADDxw(x3, x3, x4);
|
||||
SCxw(x3, wback, 0);
|
||||
BEQZ_MARKLOCK(x3);
|
||||
IFX (X_ALL | X_PEND) {
|
||||
emit_adc32(dyn, ninst, rex, x1, gd, x3, x4, x5, x6);
|
||||
}
|
||||
}
|
||||
SMDMB();
|
||||
break;
|
||||
case 0x29:
|
||||
INST_NAME("LOCK SUB Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
@@ -280,7 +434,7 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
GETGD;
|
||||
SMDMB();
|
||||
if (MODREG) {
|
||||
ed = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
emit_sub32(dyn, ninst, rex, ed, gd, x3, x4, x5);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
|
||||
@@ -311,7 +465,7 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
i64 = F32S;
|
||||
else
|
||||
i64 = F8S;
|
||||
ed = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
emit_add32c(dyn, ninst, rex, ed, i64, x3, x4, x5, x6);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, (opcode == 0x81) ? 4 : 1);
|
||||
@@ -349,7 +503,7 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
i64 = F32S;
|
||||
else
|
||||
i64 = F8S;
|
||||
ed = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
emit_or32c(dyn, ninst, rex, ed, i64, x3, x4);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, (opcode == 0x81) ? 4 : 1);
|
||||
@@ -387,7 +541,7 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
i64 = F32S;
|
||||
else
|
||||
i64 = F8S;
|
||||
ed = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
emit_sub32c(dyn, ninst, rex, ed, i64, x3, x4, x5, x6);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, (opcode == 0x81) ? 4 : 1);
|
||||
@@ -446,7 +600,7 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
SETFLAGS(X_ALL & ~X_CF, SF_SUBSET_PENDING);
|
||||
SMDMB();
|
||||
if (MODREG) {
|
||||
ed = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
emit_inc32(dyn, ninst, rex, ed, x3, x4, x5, x6);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
|
||||
@@ -464,7 +618,7 @@ uintptr_t dynarec64_F0(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
SETFLAGS(X_ALL & ~X_CF, SF_SUBSET_PENDING);
|
||||
SMDMB();
|
||||
if (MODREG) {
|
||||
ed = TO_LA64((nextop & 7) + (rex.b << 3));
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3));
|
||||
emit_dec32(dyn, ninst, rex, ed, x3, x4, x5, x6);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, x1, &fixedaddress, rex, LOCK_LOCK, 0, 0);
|
||||
|
||||
@@ -20,11 +20,12 @@
|
||||
#include "la64_printer.h"
|
||||
#include "dynarec_la64_private.h"
|
||||
#include "dynarec_la64_functions.h"
|
||||
#include "dynarec_la64_helper.h"
|
||||
#include "../dynarec_helper.h"
|
||||
|
||||
uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog)
|
||||
{
|
||||
(void)ip; (void)need_epilog;
|
||||
(void)ip;
|
||||
(void)need_epilog;
|
||||
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop;
|
||||
@@ -44,12 +45,12 @@ uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
MAYUSE(v0);
|
||||
MAYUSE(v1);
|
||||
|
||||
switch(opcode) {
|
||||
switch (opcode) {
|
||||
case 0x10:
|
||||
INST_NAME("MOVSD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
if (MODREG) {
|
||||
ed = (nextop & 7) + (rex.b << 3);
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
v1 = sse_get_reg(dyn, ninst, x1, ed, 0);
|
||||
@@ -68,7 +69,7 @@ uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if(MODREG) {
|
||||
if (MODREG) {
|
||||
ed = (nextop & 7) + (rex.b << 3);
|
||||
d0 = sse_get_reg(dyn, ninst, x1, ed, 0);
|
||||
VEXTRINS_D(d0, v0, 0); // d0[63:0] = v0[63:0]
|
||||
@@ -78,6 +79,21 @@ uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x12:
|
||||
INST_NAME("MOVDDUP Gx, Ex");
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if (MODREG) {
|
||||
d0 = sse_get_reg(dyn, ninst, x1, (nextop & 7) + (rex.b << 3), 0);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VREPLVE_D(v0, d0, xZR);
|
||||
} else {
|
||||
SMREAD();
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, x2, &fixedaddress, rex, NULL, 0, 0);
|
||||
VLDREPL_D(v0, ed, 0);
|
||||
}
|
||||
break;
|
||||
case 0x2A:
|
||||
INST_NAME("CVTSI2SD Gx, Ed");
|
||||
nextop = F8;
|
||||
@@ -292,7 +308,7 @@ uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
INST_NAME("CMPSD Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEXSS(v1, 0, 1);
|
||||
GETEXSD(v1, 0, 1);
|
||||
u8 = F8;
|
||||
switch (u8 & 7) {
|
||||
case 0: FCMP_D(fcc0, v0, v1, cEQ); break; // Equal
|
||||
@@ -314,4 +330,4 @@ uintptr_t dynarec64_F20F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,7 @@
|
||||
#include "la64_printer.h"
|
||||
#include "dynarec_la64_private.h"
|
||||
#include "dynarec_la64_functions.h"
|
||||
#include "dynarec_la64_helper.h"
|
||||
#include "../dynarec_helper.h"
|
||||
|
||||
uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, rex_t rex, int* ok, int* need_epilog)
|
||||
{
|
||||
@@ -116,7 +116,39 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
MOVFR2GR_S(gd, d1);
|
||||
ZEROUP(gd);
|
||||
}
|
||||
if (!rex.w) ZEROUP(gd);
|
||||
if (!box64_dynarec_fastround) {
|
||||
MOVFCSR2GR(x5, FCSR2); // get back FPSR to check
|
||||
MOV32w(x3, (1 << FR_V) | (1 << FR_O));
|
||||
AND(x5, x5, x3);
|
||||
CBZ_NEXT(x5);
|
||||
if (rex.w) {
|
||||
MOV64x(gd, 0x8000000000000000LL);
|
||||
} else {
|
||||
MOV32w(gd, 0x80000000);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x2D:
|
||||
INST_NAME("CVTSS2SI Gd, Ex");
|
||||
if (addr >= 0x1033f98d && addr <= 0x1033f98d + 8)
|
||||
EMIT(0);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEXSS(d0, 0, 0);
|
||||
if (!box64_dynarec_fastround) {
|
||||
MOVGR2FCSR(FCSR2, xZR); // reset all bits
|
||||
}
|
||||
u8 = sse_setround(dyn, ninst, x5, x6);
|
||||
d1 = fpu_get_scratch(dyn);
|
||||
if (rex.w) {
|
||||
FTINT_L_S(d1, d0);
|
||||
MOVFR2GR_D(gd, d1);
|
||||
} else {
|
||||
FTINT_W_S(d1, d0);
|
||||
MOVFR2GR_S(gd, d1);
|
||||
ZEROUP(gd);
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
if (!box64_dynarec_fastround) {
|
||||
MOVFCSR2GR(x5, FCSR2); // get back FPSR to check
|
||||
MOV32w(x3, (1 << FR_V) | (1 << FR_O));
|
||||
@@ -254,8 +286,14 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETEX(v1, 0, 1);
|
||||
GETGX(v0, 1);
|
||||
u8 = F8;
|
||||
VSHUF4I_H(v0, v1, u8);
|
||||
VEXTRINS_D(v0, v1, 0); // v0[63:0] = v1[63:0]
|
||||
if (v0 == v1) {
|
||||
q0 = fpu_get_scratch(dyn);
|
||||
VSHUF4I_H(q0, v1, u8);
|
||||
VEXTRINS_D(v0, q0, 0x11); // v0[127:64] = q0[127:64]
|
||||
} else {
|
||||
VSHUF4I_H(v0, v1, u8);
|
||||
VEXTRINS_D(v0, v1, 0); // v0[63:0] = v1[63:0]
|
||||
}
|
||||
break;
|
||||
case 0x7E:
|
||||
INST_NAME("MOVQ Gx, Ex");
|
||||
@@ -301,7 +339,7 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
GETED(0);
|
||||
GETGD;
|
||||
if (!rex.w && MODREG) {
|
||||
AND(x4, ed, xMASK);
|
||||
ZEROUP2(x4, ed);
|
||||
ed = x4;
|
||||
}
|
||||
RESTORE_EFLAGS(x1);
|
||||
@@ -343,4 +381,4 @@ uintptr_t dynarec64_F30F(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
}
|
||||
@@ -260,7 +260,7 @@ void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t r
|
||||
{
|
||||
if (box64_dynarec_dump) {
|
||||
printf_x64_instruction(rex.is32bits ? my_context->dec32 : my_context->dec, &dyn->insts[ninst].x64, name);
|
||||
dynarec_log(LOG_NONE, "%s%p: %d emitted opcodes, inst=%d, barrier=%d state=%d/%d(%d), %s=%X/%X, use=%X, need=%X/%X, sm=%d/%d",
|
||||
dynarec_log(LOG_NONE, "%s%p: %d emitted opcodes, inst=%d, barrier=%d state=%d/%d(%d), %s=%X/%X, use=%X, need=%X/%X, sm=%d(%d/%d)",
|
||||
(box64_dynarec_dump > 1) ? "\e[32m" : "",
|
||||
(void*)(dyn->native_start + dyn->insts[ninst].address),
|
||||
dyn->insts[ninst].size / 4,
|
||||
@@ -275,7 +275,7 @@ void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t r
|
||||
dyn->insts[ninst].x64.use_flags,
|
||||
dyn->insts[ninst].x64.need_before,
|
||||
dyn->insts[ninst].x64.need_after,
|
||||
dyn->smread, dyn->smwrite);
|
||||
dyn->smwrite, dyn->insts[ninst].will_write, dyn->insts[ninst].last_write);
|
||||
if (dyn->insts[ninst].pred_sz) {
|
||||
dynarec_log(LOG_NONE, ", pred=");
|
||||
for (int ii = 0; ii < dyn->insts[ninst].pred_sz; ++ii)
|
||||
@@ -384,4 +384,4 @@ void fpu_reset_ninst(dynarec_la64_t* dyn, int ninst)
|
||||
// TODO: x87 and mmx
|
||||
sse_reset(&dyn->insts[ninst].lsx);
|
||||
fpu_reset_reg_lsxcache(&dyn->insts[ninst].lsx);
|
||||
}
|
||||
}
|
||||
Loaded 100 of 1555 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user