mirror of
https://github.com/ptitSeb/box64.git
synced 2026-11-08 10:10:25 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c8ad5c3782 | ||
|
|
5daced4476 | ||
|
|
20cff3b264 | ||
|
|
37f5e4b7b0 | ||
|
|
70cdfdb2c2 | ||
|
|
50855a1e2b | ||
|
|
0b5002e8df | ||
|
|
4049ceacf0 | ||
|
|
5c60cf8f42 | ||
|
|
59b3eb1555 | ||
|
|
83935bc134 | ||
|
|
27a2d1f81d | ||
|
|
b71b00322e | ||
|
|
b640a570b3 | ||
|
|
9c5e8a541a | ||
|
|
6bee368bd2 | ||
|
|
3d48b55edb | ||
|
|
03d689bf56 | ||
|
|
b8171c2402 | ||
|
|
d338d4660e | ||
|
|
20807c208c | ||
|
|
23597f62fd | ||
|
|
27fd407318 | ||
|
|
22f67f2b20 | ||
|
|
74d9149095 | ||
|
|
37d91ce5ee | ||
|
|
59955e15bb | ||
|
|
5cc72d9d7a | ||
|
|
9f0814e08f | ||
|
|
89566077a7 | ||
|
|
0b046f594c | ||
|
|
93c68acd37 | ||
|
|
5177ca4732 | ||
|
|
e86a766cbe | ||
|
|
f60dea9b4b | ||
|
|
d7124fdd64 | ||
|
|
d74ec762c6 | ||
|
|
a7f9094034 | ||
|
|
6dfbebd2d4 | ||
|
|
6367180c2c | ||
|
|
81e0246b2a | ||
|
|
8a7a148bdd | ||
|
|
6c88bbda42 | ||
|
|
75cff5c584 | ||
|
|
fb0b267f53 | ||
|
|
d318afe1b9 | ||
|
|
5250c6e7a5 | ||
|
|
7e06f2bd28 | ||
|
|
25418aa192 | ||
|
|
07e9e5c344 | ||
|
|
5055f947eb | ||
|
|
4df6988c9f | ||
|
|
4e8f73c277 | ||
|
|
30d5c77188 | ||
|
|
ea513ac125 | ||
|
|
3795fe40fb | ||
|
|
2da641175c | ||
|
|
ec2f98e95a | ||
|
|
4c6be6cb23 | ||
|
|
78217d33fe | ||
|
|
c4eb274b9a | ||
|
|
61bbb76bdc | ||
|
|
13f5aea7d2 | ||
|
|
9cb238fd92 | ||
|
|
11a20e37c8 | ||
|
|
63ed07ac83 | ||
|
|
4b7d2eaabe | ||
|
|
74ee4280db | ||
|
|
11effee660 | ||
|
|
21c14f1c04 | ||
|
|
61add52ed5 | ||
|
|
e9f705df0c | ||
|
|
319a1a8ad6 | ||
|
|
be6e39cdeb | ||
|
|
49341072c8 | ||
|
|
a62e03fc7f | ||
|
|
3c563ba603 | ||
|
|
e8a2f7f9c9 | ||
|
|
1a49e47075 | ||
|
|
1d2083fe59 | ||
|
|
d04c270fa9 | ||
|
|
7fffe8dfb5 | ||
|
|
a46ad9dfe9 | ||
|
|
420eda69ff | ||
|
|
5735c8b7c8 | ||
|
|
827f0ee54e | ||
|
|
0b0a31c53c | ||
|
|
39aae76ddf | ||
|
|
f267770d75 | ||
|
|
082ecb92b1 | ||
|
|
fbba162d7c | ||
|
|
8851be9278 | ||
|
|
a111fcafee | ||
|
|
d96343fbb1 | ||
|
|
ae3412c1bf | ||
|
|
db0615cbb0 | ||
|
|
3835fe369e | ||
|
|
d07e3def9c | ||
|
|
d0c7da583d | ||
|
|
259ba9f554 | ||
|
|
2c3ac5ff08 | ||
|
|
d11def2d5b | ||
|
|
d166be5dcc | ||
|
|
30449e9255 | ||
|
|
b9bf3c344d | ||
|
|
3ee377b444 | ||
|
|
75ff158c4c | ||
|
|
66dafa5330 | ||
|
|
27860e6aee | ||
|
|
437900559a | ||
|
|
4e91870c51 | ||
|
|
b99d44309e | ||
|
|
e296745e82 | ||
|
|
157dd83ef3 | ||
|
|
d653d0ebef | ||
|
|
c51e58b34a | ||
|
|
1f7fd2afb0 | ||
|
|
4437c9b8b1 | ||
|
|
986c69cc3e | ||
|
|
868e020d59 | ||
|
|
45f85efc52 | ||
|
|
ef7005d9ea | ||
|
|
a95f10cb66 | ||
|
|
93cda37aa6 | ||
|
|
0684e43871 | ||
|
|
7de6142c98 | ||
|
|
ee03a07a17 | ||
|
|
c6a8c4472f | ||
|
|
397f1f1594 | ||
|
|
343ff5f1bc | ||
|
|
c5ddad2a1f | ||
|
|
630c40324c | ||
|
|
f9bc4a4170 | ||
|
|
84972663c5 | ||
|
|
72cbb140c8 | ||
|
|
a489cfe7d0 | ||
|
|
937d39e71c | ||
|
|
779d69f2ec | ||
|
|
55caa39c60 | ||
|
|
935b6d090f | ||
|
|
6ece2e87f2 | ||
|
|
bffb9ee4d1 | ||
|
|
f3bec61f27 | ||
|
|
78ae59d67b | ||
|
|
76f318d453 | ||
|
|
b00d767d1a | ||
|
|
2a30952898 | ||
|
|
89453f420d | ||
|
|
cf250c5661 | ||
|
|
a43469d7a5 | ||
|
|
430a408f0a | ||
|
|
c269865bb2 | ||
|
|
2f47bdff3a | ||
|
|
8f6ab59fc6 | ||
|
|
bc41dacc8c | ||
|
|
b1fc0735bb | ||
|
|
0c2de1f7f2 | ||
|
|
d58d619e84 | ||
|
|
abfb8c3b2f | ||
|
|
9ad27f276d | ||
|
|
e5afb47da8 | ||
|
|
66e4dafa8b | ||
|
|
f5ffcd0a04 | ||
|
|
77117b80ae | ||
|
|
a342e5c9ee | ||
|
|
2558cfa20b | ||
|
|
45378965aa | ||
|
|
e6f795ed9c | ||
|
|
2f0b5b2100 | ||
|
|
d3acacac95 | ||
|
|
a56756600a | ||
|
|
1b53452856 | ||
|
|
2cb3abdedb | ||
|
|
c78eea5fee | ||
|
|
e0c5937777 | ||
|
|
4e572b7b86 | ||
|
|
baf179bd46 | ||
|
|
1b16bc1a3b | ||
|
|
232ec8f9e1 | ||
|
|
48ff0ddebc | ||
|
|
40ff0e3688 | ||
|
|
970ba62254 | ||
|
|
02fc0325c8 | ||
|
|
0ee43100e1 | ||
|
|
8397d31268 | ||
|
|
ce74770e22 | ||
|
|
3787548a9a | ||
|
|
c4632305ca | ||
|
|
b4c92227b1 | ||
|
|
a028bd0e91 | ||
|
|
3ce98ac36a | ||
|
|
9c72206aae | ||
|
|
4d303a7c48 | ||
|
|
2a06231169 | ||
|
|
2ad3ee9151 | ||
|
|
557f76cb46 | ||
|
|
c1d62abf8c | ||
|
|
50069bcf69 | ||
|
|
e1eee0855a | ||
|
|
0f35bd7e3d | ||
|
|
7914fed533 | ||
|
|
1a478ee6ae | ||
|
|
7b23f2b5a7 | ||
|
|
ddd8ff7379 | ||
|
|
6650ba5b68 | ||
|
|
486ebebfc2 | ||
|
|
4f253fd85c | ||
|
|
4a2f139b1c | ||
|
|
c4e9a19fc9 | ||
|
|
b80b3304c3 | ||
|
|
7895d298c4 | ||
|
|
4238c8eb6f | ||
|
|
4c231eb087 | ||
|
|
c61543e47b | ||
|
|
a8e529c6c0 | ||
|
|
537c562c7c | ||
|
|
906dc9636d | ||
|
|
9f285eab00 | ||
|
|
d5da4d32ed | ||
|
|
967bccf7f3 | ||
|
|
ac9b13a54f | ||
|
|
685314c56e | ||
|
|
5d797f351d | ||
|
|
e3ab37bd05 | ||
|
|
58c9082b10 | ||
|
|
0b89f9d9b5 | ||
|
|
494430c6ff | ||
|
|
db3cc44adc | ||
|
|
e4dc7b5e3c | ||
|
|
806d23db92 | ||
|
|
851933bde9 | ||
|
|
c3b5282050 | ||
|
|
7df4af9983 | ||
|
|
729c25da67 | ||
|
|
51b5f8cfc2 | ||
|
|
34f858f1bd | ||
|
|
a3124f3001 | ||
|
|
9e6cf49acf | ||
|
|
0209199922 | ||
|
|
572cdff98b | ||
|
|
66a60835a7 | ||
|
|
6290f2b6a4 | ||
|
|
477a00df49 | ||
|
|
944a6f8c55 | ||
|
|
6a8433a019 | ||
|
|
9c5c904adf | ||
|
|
fbbb0544f7 | ||
|
|
cd3cea460c | ||
|
|
d5054d6cb8 | ||
|
|
18bd20f56d | ||
|
|
b192486245 | ||
|
|
6add5c1406 | ||
|
|
de761a83e9 | ||
|
|
a0017eac98 | ||
|
|
db0873caec | ||
|
|
f332ae2ba2 | ||
|
|
3f34d1e7e6 | ||
|
|
002d10833d | ||
|
|
a92a0263eb | ||
|
|
07c37e1c4d | ||
|
|
90efb9a7d8 | ||
|
|
454d538757 | ||
|
|
38f4831b24 | ||
|
|
e5ff132dc3 | ||
|
|
b4bc7c2e46 | ||
|
|
6f7a215578 | ||
|
|
5fb1da8cd6 | ||
|
|
86c7a8f354 | ||
|
|
9f69ee9310 | ||
|
|
9dd0bb4b40 | ||
|
|
e74c6438b7 | ||
|
|
ba0d84bd9e | ||
|
|
560bfed198 | ||
|
|
8f5d6e7be1 | ||
|
|
1e51dbdcae | ||
|
|
3bb457940a | ||
|
|
422a9f9d19 | ||
|
|
496fb4bebf | ||
|
|
1e771b2496 | ||
|
|
242228de83 | ||
|
|
ae8a2eb85e | ||
|
|
94b4f93540 | ||
|
|
92527ded34 | ||
|
|
b30ad56e97 | ||
|
|
cc07741a6c | ||
|
|
b40b2f1293 | ||
|
|
5da0996aee | ||
|
|
3ad88dc2e1 | ||
|
|
fef3a9702f | ||
|
|
77fdc0bafb | ||
|
|
f9d58352e9 | ||
|
|
e4eb6dcc3f | ||
|
|
a420817e62 | ||
|
|
793848f551 | ||
|
|
583b5b6e11 | ||
|
|
23807cdbe7 | ||
|
|
8396169efd | ||
|
|
384167084a | ||
|
|
04f21d33fe | ||
|
|
74276a3ff9 | ||
|
|
36738670ee | ||
|
|
c540e82aef | ||
|
|
0b689c4bd4 | ||
|
|
64a882ab38 | ||
|
|
f7a42e850b | ||
|
|
e5c9d55b8b | ||
|
|
2c188cfc35 | ||
|
|
eb3a37a5e6 | ||
|
|
eb49d3d97f | ||
|
|
b4f78a1cea | ||
|
|
e4e5cba58c | ||
|
|
a83b0accf8 | ||
|
|
c79152cb46 | ||
|
|
5524b62033 | ||
|
|
a99eed9a38 | ||
|
|
1a0a128272 | ||
|
|
92f5a7fe5f | ||
|
|
a4bbaa525c | ||
|
|
e2219d8fac | ||
|
|
4e5f1806dc | ||
|
|
ad64e829e5 | ||
|
|
36d1cd790a | ||
|
|
797bd01859 | ||
|
|
b5697f4107 | ||
|
|
b9bd355e12 | ||
|
|
7e886595c7 | ||
|
|
a4cc147ec4 | ||
|
|
40d820b27f | ||
|
|
fffc39881a | ||
|
|
b9fd03e3a2 | ||
|
|
0d261b6e90 | ||
|
|
6ff9276b1b | ||
|
|
f21db8d170 | ||
|
|
5905dc5639 | ||
|
|
49ce9e5bd5 | ||
|
|
2add381bf7 | ||
|
|
1eb97e51a2 | ||
|
|
31106cd00e | ||
|
|
e4c9577f32 | ||
|
|
e367134e7f | ||
|
|
a01ded9351 | ||
|
|
0708e6f9fd | ||
|
|
d79d0efad8 | ||
|
|
4de091016b | ||
|
|
65702d61c3 | ||
|
|
3f74c742c6 | ||
|
|
fc1f3419a6 | ||
|
|
bc19066a29 | ||
|
|
022a637136 | ||
|
|
ebae9d1db6 | ||
|
|
cd9b0358b3 | ||
|
|
12636eb321 | ||
|
|
1e7121e48f | ||
|
|
6f9ed4cc1e | ||
|
|
4e144ee147 | ||
|
|
c383d0313e | ||
|
|
1cc0874b0c | ||
|
|
b68905249e | ||
|
|
f39cedc9c5 | ||
|
|
16c3d08bb5 | ||
|
|
0f6603ed42 | ||
|
|
b238f4f1b8 | ||
|
|
55083ea13d | ||
|
|
fa94836a96 | ||
|
|
171d7b2144 | ||
|
|
0b5d30b9a8 | ||
|
|
4e3bb8861b | ||
|
|
31c8d836fc | ||
|
|
0b0fb69c9f | ||
|
|
babdc6961f | ||
|
|
36260684e4 | ||
|
|
c305b57c6f | ||
|
|
96b70f8737 | ||
|
|
e6ddae9f54 | ||
|
|
27fbe43d92 | ||
|
|
f79640e527 | ||
|
|
6f6fc3bc25 | ||
|
|
59d8dc6051 | ||
|
|
d36e574be1 | ||
|
|
77964a083f | ||
|
|
944776384a | ||
|
|
d51e72eca8 | ||
|
|
711b07a7d8 | ||
|
|
acec20bfc5 | ||
|
|
aab716ff6e | ||
|
|
2f7b82bef1 | ||
|
|
951808acd1 | ||
|
|
5b352263af | ||
|
|
7e98945d1d | ||
|
|
90b02b9a41 | ||
|
|
dc57589aac | ||
|
|
1f7ff4b968 | ||
|
|
9cd1d38751 | ||
|
|
91b7fa7eea | ||
|
|
ec1d5a6ac2 | ||
|
|
a793cd52c2 | ||
|
|
9e8d8193dc | ||
|
|
d50beea87b | ||
|
|
455bc1c4a2 | ||
|
|
76fda7910e | ||
|
|
67e8c97ca1 | ||
|
|
64367de6bf | ||
|
|
060b5d6bdb | ||
|
|
6d039e5df1 | ||
|
|
b32ea75869 | ||
|
|
499d038626 | ||
|
|
7fbbcd3468 | ||
|
|
4aa4f6f70d | ||
|
|
d1bb1d1e05 | ||
|
|
9e13288ed2 | ||
|
|
72cd18a8bc | ||
|
|
caf201fec9 | ||
|
|
2bb936b5fd | ||
|
|
d2df252722 | ||
|
|
bdc7138c7c | ||
|
|
023d96ec17 | ||
|
|
db05d0e664 | ||
|
|
777af102a5 | ||
|
|
2598e8c7e8 | ||
|
|
ba23a5e8e2 | ||
|
|
e852f2539f | ||
|
|
d69e4a9684 | ||
|
|
f204ae6900 | ||
|
|
6271ae2fd3 | ||
|
|
b38a33c00d | ||
|
|
1227cf2e6b | ||
|
|
ed8c6b2e82 | ||
|
|
2969b05414 | ||
|
|
af7eb3177f | ||
|
|
3a2f1727c3 | ||
|
|
ceea1465ab | ||
|
|
750a8775b9 | ||
|
|
ff1771d134 | ||
|
|
64d2204635 | ||
|
|
8ed77f3d93 | ||
|
|
b5108ce468 | ||
|
|
fb73285312 | ||
|
|
60693dc374 | ||
|
|
2617c97492 | ||
|
|
3c6704a909 | ||
|
|
554b84068b | ||
|
|
d74598aaa8 | ||
|
|
5b3259491b | ||
|
|
6fec414a72 | ||
|
|
80e10e696a | ||
|
|
9f3671b8ec | ||
|
|
3601698aa7 | ||
|
|
83a9d67e15 | ||
|
|
0b9b6322de | ||
|
|
199f00ebff | ||
|
|
d6806f0ecc | ||
|
|
e8b1004112 | ||
|
|
2595c1e98f | ||
|
|
5847f2f193 | ||
|
|
303bceba3f | ||
|
|
1cb3a71c05 | ||
|
|
09124eb6ef | ||
|
|
78bf553c62 | ||
|
|
da05e01235 | ||
|
|
e809d29035 | ||
|
|
d691d07bd9 | ||
|
|
b552ab5f8f | ||
|
|
c3294588f9 | ||
|
|
73e3a97009 | ||
|
|
986846bb7c | ||
|
|
43acf32c85 | ||
|
|
e99ca51299 | ||
|
|
e51e9c84a3 | ||
|
|
9cf3ceaa86 | ||
|
|
e0d9d9be29 | ||
|
|
e13e3cb1f2 | ||
|
|
491ab0e304 | ||
|
|
0e9d41ce15 | ||
|
|
fa5fbe6acd | ||
|
|
ba373ab4b3 | ||
|
|
8ee669331e | ||
|
|
98459539dc | ||
|
|
607c22d22a | ||
|
|
5e5e598a6b | ||
|
|
62cb8170cc | ||
|
|
39d0b82094 | ||
|
|
fa6868c5bd | ||
|
|
5ca4b91e00 | ||
|
|
5d881fd59d | ||
|
|
cec0f61e0e | ||
|
|
b277c76d6d | ||
|
|
5bbafe7562 | ||
|
|
ddd3bd602f | ||
|
|
5afc665420 | ||
|
|
b63f650694 | ||
|
|
61d01a4c2c | ||
|
|
3c670efe6f | ||
|
|
55ed7e9edb | ||
|
|
9c11c5671c | ||
|
|
5656decbde | ||
|
|
1b79a0c060 | ||
|
|
0db8df7757 | ||
|
|
8ef7ef3209 | ||
|
|
372739d07f | ||
|
|
34f949bf5d | ||
|
|
dd9743513e | ||
|
|
f6617364cd | ||
|
|
b5d45778c4 | ||
|
|
064c9222ed | ||
|
|
392502fd11 | ||
|
|
b5066f8ab4 | ||
|
|
e0ae94d742 | ||
|
|
bd47c3da04 | ||
|
|
bae1de053e | ||
|
|
1058aae561 | ||
|
|
c569c55494 | ||
|
|
744e2bb4ec | ||
|
|
2f130fab1d | ||
|
|
08f8666596 | ||
|
|
fb5294a125 | ||
|
|
b3384b5c81 | ||
|
|
7058d990c4 | ||
|
|
8557ede0e9 | ||
|
|
78383901f2 | ||
|
|
ebccae45e3 | ||
|
|
80b5e387d2 | ||
|
|
15e065ae5d | ||
|
|
00ca85606d | ||
|
|
bc181e7812 | ||
|
|
0f6b8ccc68 | ||
|
|
ffeff6599b | ||
|
|
3e71996209 | ||
|
|
bbb2560ff8 | ||
|
|
30b1bf210d | ||
|
|
178e344b98 | ||
|
|
1c2fc72c20 | ||
|
|
b7ed2c57f5 | ||
|
|
23f8db631d | ||
|
|
f22f5adb55 | ||
|
|
f02526fdbb | ||
|
|
675814f912 | ||
|
|
c44264eba0 | ||
|
|
35ea2eedcd | ||
|
|
25f49cbf25 | ||
|
|
2dd1600cdd | ||
|
|
327b0870f0 | ||
|
|
7097ead476 | ||
|
|
887d5ca523 | ||
|
|
54c35ef172 | ||
|
|
a78eec4ebf | ||
|
|
ed140eade7 | ||
|
|
7c6c963168 | ||
|
|
e058be73ca | ||
|
|
d9a136d31c | ||
|
|
5910a52a60 | ||
|
|
e67bd4b6f6 | ||
|
|
9270fc3727 | ||
|
|
5101489d21 | ||
|
|
41c3a0caa5 | ||
|
|
382065544d | ||
|
|
e2a2c801f2 | ||
|
|
9e2fa9e360 | ||
|
|
588f1d9c93 | ||
|
|
347f3b1a13 | ||
|
|
c32ebc76fd | ||
|
|
a2ae0500d8 | ||
|
|
478972a34b | ||
|
|
f4ee1c1b53 | ||
|
|
93fe536549 | ||
|
|
3698562aae | ||
|
|
d8df33a9cb | ||
|
|
0de71be3e5 | ||
|
|
fd895bd142 | ||
|
|
edc68c032a | ||
|
|
40a841df8f | ||
|
|
df697c683c | ||
|
|
e3cb94f490 | ||
|
|
88f6cb97c7 | ||
|
|
bdd226b9d3 | ||
|
|
537d92bf57 | ||
|
|
c08644a729 | ||
|
|
7b07789173 | ||
|
|
585e0a6308 | ||
|
|
fd6bdfe69e | ||
|
|
654e36622f | ||
|
|
38df9afcf2 | ||
|
|
b442786811 | ||
|
|
ff943b5d5a | ||
|
|
ef8b463a25 | ||
|
|
02a9f25707 | ||
|
|
9a4b78d35a | ||
|
|
7d8ae5f7e2 | ||
|
|
f7208a7241 | ||
|
|
da25b06705 | ||
|
|
66e9f120bb | ||
|
|
79b72348c2 | ||
|
|
6994c012b8 | ||
|
|
26ab7ad6b0 | ||
|
|
67962cd10d | ||
|
|
603730dd3c | ||
|
|
7c3c5dd0d9 | ||
|
|
121cf70278 | ||
|
|
c8a5246766 | ||
|
|
9c0214dd34 | ||
|
|
d9df72e602 | ||
|
|
8b1fbc150d | ||
|
|
0cec433211 | ||
|
|
31cb8b5d61 | ||
|
|
f681291c1d | ||
|
|
099982d356 | ||
|
|
2e7a8867cb | ||
|
|
d22f9e6169 | ||
|
|
f79babc541 | ||
|
|
5640228909 | ||
|
|
3e2ab21e70 | ||
|
|
f19936e53b | ||
|
|
d8cb528a2d | ||
|
|
2544543b3a | ||
|
|
ceb5c13822 | ||
|
|
8ace9188e8 | ||
|
|
5a20e40e29 | ||
|
|
0dc712cec0 | ||
|
|
0d8356702b | ||
|
|
cf633e161a | ||
|
|
3ac45c1ac6 | ||
|
|
86f3d6d316 | ||
|
|
290dc73a3a | ||
|
|
c5215cb2f5 | ||
|
|
a107c2a52b | ||
|
|
373e1306ad | ||
|
|
0910384e6f | ||
|
|
894a183180 | ||
|
|
e016c5a6cd | ||
|
|
900d327aa1 | ||
|
|
eb3cd0c1bd | ||
|
|
4280f4b259 | ||
|
|
07b76e6f99 | ||
|
|
5134a414a8 | ||
|
|
919e426d03 | ||
|
|
4bf60dec65 | ||
|
|
3e9dc054af | ||
|
|
a5a320ae3c | ||
|
|
1dd0323f8f | ||
|
|
4b482fb0e1 | ||
|
|
0ccd7513b4 | ||
|
|
a96396985e | ||
|
|
8ee3d8f2c8 | ||
|
|
bc61374812 | ||
|
|
862fef5e0f | ||
|
|
65898277e9 | ||
|
|
bd0131e973 | ||
|
|
f7aa4942de | ||
|
|
1953db9145 | ||
|
|
2d5d7d1a41 | ||
|
|
d53d99ebcf | ||
|
|
32f966210b | ||
|
|
24d550147f | ||
|
|
384972df38 | ||
|
|
7fb6dc4353 | ||
|
|
5a1114c76e | ||
|
|
86a850cfcd | ||
|
|
f5c0d135d0 | ||
|
|
17b0ca1d43 | ||
|
|
462b3c0d78 | ||
|
|
2a5480652a | ||
|
|
ecc6b95a75 | ||
|
|
c08554e3f3 | ||
|
|
d6e43153db | ||
|
|
d701932fe6 | ||
|
|
b47131c1e4 | ||
|
|
70dc4e4897 | ||
|
|
5a6419d322 | ||
|
|
0c3d2391f0 | ||
|
|
baacff1811 | ||
|
|
39e75158ee | ||
|
|
b1d094f9bd | ||
|
|
89a2e7d66a | ||
|
|
90dffce78a | ||
|
|
55922238d3 | ||
|
|
38a4a2c751 | ||
|
|
e6de218979 | ||
|
|
d9fca2f365 | ||
|
|
2f850d4e88 | ||
|
|
dd180478f1 | ||
|
|
fc8a8d0b83 | ||
|
|
83d9c30aa4 | ||
|
|
ffa7c1a77b | ||
|
|
148a1a21e8 | ||
|
|
d7b78a092f | ||
|
|
7da44e5d7e | ||
|
|
3bf34a77c7 | ||
|
|
2cc903bbe0 | ||
|
|
f1f572a087 | ||
|
|
8e96a34da3 | ||
|
|
38d64baba2 | ||
|
|
896b965325 | ||
|
|
17865c3a9e | ||
|
|
8e661d2907 | ||
|
|
46459ebee1 | ||
|
|
75464e9d94 | ||
|
|
49e248923e | ||
|
|
6656708831 | ||
|
|
153b6613cc | ||
|
|
2d74207bb7 | ||
|
|
61131566bb | ||
|
|
915a28f84c | ||
|
|
75c0edc100 | ||
|
|
0053799955 | ||
|
|
95b02080ec | ||
|
|
12ba6c1c3c | ||
|
|
a6f44ac2bd | ||
|
|
758f352bf5 | ||
|
|
274c5a8f11 | ||
|
|
fdabd38e7b | ||
|
|
59c6aa4932 | ||
|
|
9ddbc50844 | ||
|
|
093e6353d7 | ||
|
|
6597bef108 | ||
|
|
5fa5298977 | ||
|
|
15cced707b | ||
|
|
50c8b90b09 | ||
|
|
53968e0d4e | ||
|
|
03157ce442 | ||
|
|
c018889389 | ||
|
|
3ac87fd225 | ||
|
|
63c956d8ac | ||
|
|
00ee467812 | ||
|
|
75a1456bc3 | ||
|
|
4b669fbe99 | ||
|
|
d39bf05f39 | ||
|
|
df36391e74 | ||
|
|
0873ab1824 | ||
|
|
514d5cd770 | ||
|
|
87d06d3afd | ||
|
|
956c89d820 | ||
|
|
cd15d459b1 | ||
|
|
befc90de1c | ||
|
|
05136b7bfb | ||
|
|
f1bbd6f8c6 | ||
|
|
e823292457 | ||
|
|
8a3ecb8cc5 | ||
|
|
4ececfb100 | ||
|
|
e424cdb940 | ||
|
|
fe86cb68f2 | ||
|
|
83a3b787e6 | ||
|
|
7031e700b3 | ||
|
|
64ac6bc0a2 | ||
|
|
efa5a51365 | ||
|
|
80bdf9bac7 | ||
|
|
d0ab518074 | ||
|
|
17f57e6804 | ||
|
|
771672e6d4 | ||
|
|
d4f675e7bd | ||
|
|
1a66f7ee40 | ||
|
|
3f747727f2 | ||
|
|
f5e1ebb554 | ||
|
|
8f445d9a0c | ||
|
|
0292a66f37 | ||
|
|
4f5d171032 | ||
|
|
8d7f6a54d7 | ||
|
|
d6e26bc9aa | ||
|
|
be4db11199 | ||
|
|
326784b81e | ||
|
|
b9ce9049a2 | ||
|
|
ad6b10f060 | ||
|
|
34fc743599 | ||
|
|
c7d6dad1a8 | ||
|
|
c14f0eca84 | ||
|
|
b15badbc53 | ||
|
|
e731c91204 | ||
|
|
15a165f842 | ||
|
|
422007abd9 | ||
|
|
665cacbe7c |
No files matched your search
@@ -1 +0,0 @@
|
||||
{ "contextFileName": "AGENTS.md" }
|
||||
@@ -37,7 +37,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [X64, RISCV, RK3588, ARM64, ANDROID, TERMUX, LARCH64, PPC64LE, ANDROID_GLIBC, WOW64]
|
||||
platform: [X64, RISCV, RK3588, ARM64, ANDROID, TERMUX, LARCH64, PPC64LE, ANDROID_GLIBC, WOW64, ARM64EC]
|
||||
type: [Release, Trace, StaticBuild, Box32]
|
||||
exclude:
|
||||
- platform: ANDROID
|
||||
@@ -56,6 +56,12 @@ jobs:
|
||||
type: StaticBuild
|
||||
- platform: WOW64
|
||||
type: Box32
|
||||
- platform: ARM64EC
|
||||
type: Box32
|
||||
- platform: ARM64EC
|
||||
type: Trace
|
||||
- platform: ARM64EC
|
||||
type: StaticBuild
|
||||
- platform: ANDROID
|
||||
type: Trace
|
||||
- platform: TERMUX
|
||||
@@ -95,6 +101,9 @@ jobs:
|
||||
- platform: WOW64
|
||||
os: ubuntu-22.04-arm
|
||||
|
||||
- platform: ARM64EC
|
||||
os: ubuntu-22.04-arm
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
container:
|
||||
image: ${{ matrix.image || '' }}
|
||||
@@ -195,9 +204,17 @@ jobs:
|
||||
echo "BOX64_COMPILER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
|
||||
elif [[ ${{ matrix.platform }} == 'WOW64' ]]; then
|
||||
sudo apt-get -y install git gcc-aarch64-linux-gnu
|
||||
echo "BOX64_PLATFORM_MARCRO=-DWOW64=1 -DARM_DYNAREC=1" >> $GITHUB_ENV
|
||||
echo "BOX64_PLATFORM_MARCRO=-DWOW64=1 -DARM_DYNAREC=1 -DNOBOX64=1" >> $GITHUB_ENV
|
||||
echo "BOX64_COMPILER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
|
||||
export LLVM_MINGW_VERSION=20260311
|
||||
export LLVM_MINGW_VERSION=20260616
|
||||
wget -q https://github.com/mstorsjo/llvm-mingw/releases/download/${LLVM_MINGW_VERSION}/llvm-mingw-${LLVM_MINGW_VERSION}-ucrt-ubuntu-22.04-aarch64.tar.xz
|
||||
tar -xf llvm-mingw-${LLVM_MINGW_VERSION}-ucrt-ubuntu-22.04-aarch64.tar.xz
|
||||
echo "MINGW_COMPILER_PATH=$PWD/llvm-mingw-${LLVM_MINGW_VERSION}-ucrt-ubuntu-22.04-aarch64/bin" >> $GITHUB_ENV
|
||||
elif [[ ${{ matrix.platform }} == 'ARM64EC' ]]; then
|
||||
sudo apt-get -y install git gcc-aarch64-linux-gnu
|
||||
echo "BOX64_PLATFORM_MARCRO=-DARM64EC=1 -DARM_DYNAREC=1 -DNOBOX64=1" >> $GITHUB_ENV
|
||||
echo "BOX64_COMPILER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV
|
||||
export LLVM_MINGW_VERSION=20260616
|
||||
wget -q https://github.com/mstorsjo/llvm-mingw/releases/download/${LLVM_MINGW_VERSION}/llvm-mingw-${LLVM_MINGW_VERSION}-ucrt-ubuntu-22.04-aarch64.tar.xz
|
||||
tar -xf llvm-mingw-${LLVM_MINGW_VERSION}-ucrt-ubuntu-22.04-aarch64.tar.xz
|
||||
echo "MINGW_COMPILER_PATH=$PWD/llvm-mingw-${LLVM_MINGW_VERSION}-ucrt-ubuntu-22.04-aarch64/bin" >> $GITHUB_ENV
|
||||
@@ -244,7 +261,7 @@ jobs:
|
||||
echo "BOX64_COMPILER=loongarch64-linux-gnu-gcc" >> $GITHUB_ENV
|
||||
sudo apt-get -y install git cmake make python3 libzydis-dev
|
||||
elif [[ ${{ matrix.platform }} == 'PPC64LE' ]]; then
|
||||
echo BOX64_PLATFORM_MARCRO="-DPPC64LE=ON" >> $GITHUB_ENV
|
||||
echo BOX64_PLATFORM_MARCRO="-DPPC64LE=ON -DBAD_SIGNAL=ON" >> $GITHUB_ENV
|
||||
echo "BOX64_COMPILER=powerpc64le-linux-gnu-gcc" >> $GITHUB_ENV
|
||||
sudo apt-get -y install git gcc-powerpc64le-linux-gnu cmake make python3 libzydis-dev
|
||||
else
|
||||
|
||||
+5
-1
@@ -51,7 +51,7 @@ Module.symvers
|
||||
Mkfile.old
|
||||
dkms.conf
|
||||
|
||||
# from box86
|
||||
# Box64
|
||||
build/
|
||||
build*/
|
||||
.vscode
|
||||
@@ -60,6 +60,7 @@ build*/
|
||||
src/git_head.h
|
||||
src/dynacache_hashes.h
|
||||
backup/
|
||||
box64-bundle-x86-libs.sha256
|
||||
|
||||
# Wrapper helper
|
||||
/wrapperhelper/bin
|
||||
@@ -90,3 +91,6 @@ backup/
|
||||
*.zip
|
||||
*.zst
|
||||
*.zstd
|
||||
|
||||
# Python
|
||||
__pycache__/
|
||||
@@ -20,7 +20,7 @@ These use cases are **permitted** when making a contribution with the help of AI
|
||||
- Formatting code for consistency and readability (but do not overload code with comments)
|
||||
- Completing code segments based on established patterns
|
||||
- Drafting documentation for project components with which the contributor is already familiar
|
||||
- Writting Wrappers Callback handling and/or wrappers structures conversion when needed
|
||||
- Writing Wrappers Callback handling and/or wrappers structures conversion when needed
|
||||
|
||||
AI-generated code that has undergone extensive human editing may be accepted, provided you (1) fully understand the AI's initial output, (2) can debug any issues independently (with or without further AI assistance), and (3) are prepared to discuss it directly with human reviewers.
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
IMPORTANT: Ensure you’ve thoroughly reviewed the [AGENTS.md](AGENTS.md) file before beginning any work.
|
||||
+272
-612
File diff suppressed because it is too large.
Load diff
+2
-1
@@ -28,4 +28,5 @@ Before submitting your PR:
|
||||
|
||||
# Coding guidelines
|
||||
|
||||
- Avoid adding third-party dependencies, extra files, extra headers, etc.
|
||||
- Avoid adding third-party dependencies, extra files, extra headers, etc.
|
||||
- New C source files must start with the license header `// SPDX-License-Identifier: MIT` or `# SPDX-License-Identifier: MIT` for Bash and Python scripts. Do not add headers to third-party files in `external/` or `src/include/`.
|
||||
@@ -55,17 +55,17 @@ Box64 requires 64-bit libraries on the host system, as it directly translates x8
|
||||
|
||||
**Notes**
|
||||
|
||||
1. Box32 is still experimental.
|
||||
1. Box32 is still experimental, but it's pretty stable now and can be used.
|
||||
2. Some shell scripts (such as the GOG game installer) may rely on `uname -m` to determine the current architecture. Please run them as `box64 script.sh` to allow Box64 to take over.
|
||||
|
||||
Note that DynaCache is now enabled by default (with compression). This will creates files in `~/.cache/box64` to save generated code for executed binaries and libraries, so launch time can be greatly reduced on second run. The files are compressed and will take up to 2Gb by default. You can disable DynaCache writting, by switching it to a Read-only mode by creating (or modifying) `~/.box64rc` and writting there
|
||||
Note that DynaCache is now enabled by default (with compression). This will creates files in `~/.cache/box64` to save generated code for executed binaries and libraries, so launch time can be greatly reduced on second run. The files are compressed and will take up to 2Gb by default. You can disable DynaCache writing, by switching it to a Read-only mode by creating (or modifying) `~/.box64rc` and writing there
|
||||
|
||||
```ini
|
||||
[*]
|
||||
BOX64_DYNACACHE=2
|
||||
```
|
||||
|
||||
(or 0 to completly disabled it). Please refer to [Usage Documentation](docs/USAGE.md) for more details on how to configure Box64.
|
||||
(or 0 to completely disabled it). Please refer to [Usage Documentation](docs/USAGE.md) for more details on how to configure Box64.
|
||||
|
||||
---
|
||||
|
||||
@@ -109,7 +109,7 @@ 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), 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 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), [SpacemiT](https://www.spacemit.com/), [SOPHGO](https://www.sophon.ai/), [Radxa](https://rockpi.org/), [StarFive](https://rvspace.org/), [Pine64](https://www.pine64.org/), [AYN](https://www.ayntec.com/), [AYANEO](https://ayaneo.com/), [jiangcuo](https://github.com/jiangcuo)
|
||||
* For their continuous advertisements for the box64 project: salva ([microLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ)), [PILab](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g)/[TwisterOS](https://twisteros.com/) team, [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA), [NicoD](https://www.youtube.com/channel/UCpv7NFr0-9AB5xoklh3Snhg), ekianjo ([Boilingsteam](https://boilingsteam.com/))
|
||||
|
||||
And I also thank the many other people who participated even once in this project.
|
||||
|
||||
+7
-7
@@ -29,16 +29,16 @@ _Logo 由 @grayduck 制作,感谢!_
|
||||
- `$ box64 ./program [args]` 运行 Linux x86_64 程序。
|
||||
- `$ box64 -k` 杀死所有模拟的进程。
|
||||
- `$ box64-bash` 进入 x86_64 bash 环境。
|
||||
- 想要使用 wine?请参阅 [Wine 使用说明](docs/WINE.md)。
|
||||
- 想要使用 wine?请参阅 [Wine 使用说明](docs/WINE_CN.md)。
|
||||
|
||||
Box64 还提供了环境变量和 Rc 文件来控制其行为。有关详细信息请参阅[使用文档](docs/USAGE.md)。
|
||||
Box64 还提供了环境变量和 Rc 文件来控制其行为。有关详细信息请参阅[使用文档](docs/USAGE_CN.md)。
|
||||
|
||||
---
|
||||
|
||||
## 编译和安装
|
||||
|
||||
- [编译说明](https://github.com/ptitSeb/box64/blob/main/docs/COMPILE.md)
|
||||
- [安装 Wine](https://github.com/ptitSeb/box64/blob/main/docs/WINE.md)
|
||||
- [编译说明](docs/COMPILE.md)
|
||||
- [安装 Wine](docs/WINE_CN.md)
|
||||
|
||||
---
|
||||
|
||||
@@ -65,7 +65,7 @@ Box64 的配置文件位于 `/etc/box64.box64rc` 和 `~/.box64rc`,均为 `.ini
|
||||
|
||||
配置项的优先级:`~/.box64rc` > `/etc/box64.box64rc` > 命令行。
|
||||
|
||||
更多信息,请参阅[使用文档](docs/USAGE.md)。
|
||||
更多信息,请参阅[使用文档](docs/USAGE_CN.md)。
|
||||
|
||||
---
|
||||
|
||||
@@ -88,7 +88,7 @@ Box64 支持 Wine64 和 Proton。对于 32 位组件,需要 Box86。配备 Box
|
||||
|
||||
**提示**:您可以使用 Wine WOW64 版本在仅限 Box64 的环境中运行 x86 Windows 程序,这项支持仍处于实验阶段,但在大多数情况下都可以工作。
|
||||
|
||||
有关更多信息,请参阅 [Wine 使用说明](docs/WINE.md)。
|
||||
有关更多信息,请参阅 [Wine 使用说明](docs/WINE_CN.md)。
|
||||
|
||||
----
|
||||
|
||||
@@ -102,7 +102,7 @@ Box64 支持 Wine64 和 Proton。对于 32 位组件,需要 Box86。配备 Box
|
||||
* 代码贡献:rajdakin, mogery, ksco, xctan
|
||||
* 财务支持:[Playtron](https://playtron.one), tohodakilla, FlyingFathead, stormchaser3000, dennis1248, sll00, [libre-computer-project](https://libre.computer/), [CubeCoders Limited](http://cubecoders.com/)
|
||||
* 硬件捐赠和 LoongArch 迁移:[xiaoji](https://www.linuxgame.cn/), Deepin Beijing Develop Team
|
||||
* 硬件捐赠:[ADLINK](https://www.adlinktech.com/Products/Computer_on_Modules/COM-HPC-Server-Carrier-and-Starter-Kit/Ampere_Altra_Developer_Platform?lang=en) 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)
|
||||
* 硬件捐赠:[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), [SpacemiT](https://www.spacemit.com/), [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/))
|
||||
|
||||
我还要感谢很多人,即使他们只参与了一次本项目。
|
||||
|
||||
+1
-1
@@ -109,7 +109,7 @@ Box64 використовує бібліотеки Vulkan, але зауваж
|
||||
* За основний внесок у код: rajdakin, mogery, ksco, xctan
|
||||
* За великий фінансовий внесок: [Playtron](https://playtron.one), tohodakilla, FlyingFathead, stormchaser3000, dennis1248, sll00, [libre-computer-project](https://libre.computer/)
|
||||
* За апаратне забезпечення та міграцію LoongArch: [xiaoji](https://www.linuxgame.cn/), команда розробників Deepin Beijing
|
||||
* За внесок у апаратне забезпечення: [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)
|
||||
* За внесок у апаратне забезпечення: [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), [SpacemiT](https://www.spacemit.com/), [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/))
|
||||
|
||||
І я також дякую багатьом іншим людям, які хоч раз брали участь у цьому проекті.
|
||||
|
||||
@@ -1,7 +1,17 @@
|
||||
https://archive.debian.org/debian/pool/main/c/curl/libcurl3-gnutls_7.74.0-1.3+deb11u7~bpo11+1_amd64.deb,d5ae55e3a9838d12358530cd03218cc0d18127a84e9cfc73bdf79dacd40b25e4
|
||||
https://archive.debian.org/debian/pool/main/c/curl/libcurl3-gnutls_7.74.0-1.3+deb11u7~bpo11+1_i386.deb,625e5189304d4d3bfb27cb821e257816c5ce761b1696b5da5ca4fa1035c48463
|
||||
https://archive.debian.org/debian/pool/main/g/gcc-10/libgfortran5_10.2.1-6_amd64.deb,6fe41d04ea9ef8c5c684b14585caa7a4a7e04ad6805d59cdd29016960b737123
|
||||
https://archive.debian.org/debian/pool/main/g/gcc-10/libgfortran5_10.2.1-6_i386.deb,6d72a7ac94c0e3faa32f7dc07a1f4bc8a782d0ab39defca6e9322dd06afd638f
|
||||
https://archive.debian.org/debian/pool/main/g/gcc-10/libquadmath0_10.2.1-6_amd64.deb,a9a5e1f53b7e27a3f2b8388929bb622d3c6c35a4e42ac166697444e5ed662fd5
|
||||
https://archive.debian.org/debian/pool/main/g/gcc-10/libquadmath0_10.2.1-6_i386.deb,15f81212576c500e47e72ff05b1b705ef62640ef0a1b8e2c34d848c16ee30728
|
||||
https://archive.debian.org/debian/pool/main/o/openssl/libssl1.0.0_1.0.2l-1~bpo8+1_amd64.deb,6e85968afe1a6643f4e82e1cc168f848c5967a131bb1c7392f11974953db0e67
|
||||
https://archive.debian.org/debian/pool/main/o/openssl/libssl1.0.0_1.0.2l-1~bpo8+1_i386.deb,4e8b924286a064c257ca50b8ecd44fe71226443daef62b6836010590e2157329
|
||||
https://archive.debian.org/debian/pool/main/p/pipewire/libpipewire-0.3-0_0.3.65-2~bpo11+1_amd64.deb,b49a24743eb2b6d1198c7cf014ee791bccd5d3223ed8a1e4769d899e1f894a5b
|
||||
https://archive.debian.org/debian/pool/main/p/pipewire/libpipewire-0.3-0_0.3.65-2~bpo11+1_i386.deb,1d032b638081704393bc847e2e1f7a00c6894fa262ed0272fb7282962e8915a9
|
||||
https://archive.debian.org/debian/pool/main/p/pipewire/libpipewire-0.3-modules_0.3.65-2~bpo11+1_amd64.deb,6a4c2d7b127ed18c8c2a558e4d63fcd56de4a154bb9db5fafa7e497f4771dc4a
|
||||
https://archive.debian.org/debian/pool/main/p/pipewire/libpipewire-0.3-modules_0.3.65-2~bpo11+1_i386.deb,4585064f220490562c132e6fe6a2c46a66d319f6862f60f26e21bccbaadcbd90
|
||||
https://archive.debian.org/debian/pool/main/p/pipewire/libspa-0.2-modules_0.3.65-2~bpo11+1_amd64.deb,833a024051fcfa79208462486c2761b6e1c464676da96e0d3664f4a189449e34
|
||||
https://archive.debian.org/debian/pool/main/p/pipewire/libspa-0.2-modules_0.3.65-2~bpo11+1_i386.deb,5cbd85ab559d99dc5907898488c87b8cf0e117412e0d7981ca7e69e35fbc3f84
|
||||
https://archives.fedoraproject.org/pub/archive/epel/9.5/Everything/x86_64/Packages/m/mbedtls-2.28.8-1.el9.x86_64.rpm,54cb7e43e902a7378e912ecfec470ee30fe69af323d3812cbc39ddebd64790ff
|
||||
https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/34/Everything/x86_64/os/Packages/l/libpng12-1.2.57-13.fc34.i686.rpm,5e4f525f44d538e3467dd13c66010d54f3d12ec4a319829e15a23ff2d0195b5b
|
||||
https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/34/Everything/x86_64/os/Packages/l/libpng12-1.2.57-13.fc34.x86_64.rpm,49f956ad143399c29f5ddf6da6b6fc108ce130d1ed598b4ec5a68b1ff26091de
|
||||
@@ -79,6 +89,8 @@ https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/pam-1.5.1-22.el9_5.i68
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/pam-1.5.1-22.el9_5.x86_64.rpm,15bfe177d3c10982c75e81d7b274883a9fb53322011c8d829667c983ee419b18
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/pciutils-libs-3.7.0-5.el9.i686.rpm,2cf468da5ecf307cc325c9a5da0a288aafd25dec0951af2b4d0954a77bdf900d
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/pciutils-libs-3.7.0-5.el9.x86_64.rpm,308bd897d8f9a36020d70edc79089a3595b22b149200d67c37e2d4e6147a9f75
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/polkit-libs-0.117-13.el9.i686.rpm,4079b9fe93cef0d2ec5b74502ade41a175e1f95e72bace30af29cdcaab037cae
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/polkit-libs-0.117-13.el9.x86_64.rpm,5ff471276dcb8c38fe16bf91f963ec4f051954107c3f0ca28fbb3bd2c6521f2b
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/sqlite-libs-3.34.1-7.el9_3.i686.rpm,dc6946a8344b8f4f476fef9479d1786c86fdcd045e988ab5d85fef7780e1fae4
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/sqlite-libs-3.34.1-7.el9_3.x86_64.rpm,e7f87444f24a03b37caa02942082b6d4283067ecbbd3f7798f882d22b55713cf
|
||||
https://vault.almalinux.org/9.5/BaseOS/x86_64/os/Packages/zlib-1.2.11-40.el9.i686.rpm,659ee5222028744806be3f822369a726c721aa346eed2882dcf019d83c111e67
|
||||
|
||||
|
+144
-17
@@ -1,26 +1,143 @@
|
||||
#!/bin/sh
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
set -ex
|
||||
set -e
|
||||
|
||||
trap cleanup_exit INT TERM EXIT
|
||||
|
||||
cleanup_exit()
|
||||
{
|
||||
echo "Running cleanup_exit..."
|
||||
log "Running cleanup_exit..."
|
||||
rm -rf /tmp/box64-bundle.*
|
||||
}
|
||||
|
||||
# progress messages are only printed with --debug
|
||||
log()
|
||||
{
|
||||
if [ -n "${verbose}" ]; then
|
||||
echo "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
usage()
|
||||
{
|
||||
cat << EOF
|
||||
Usage: ${0} [OPTION]
|
||||
|
||||
Options:
|
||||
--build Build the x86 library bundle archives from Linux distribution
|
||||
packages.
|
||||
--install Install the x86 library bundle from the latest GitHub release.
|
||||
The bundle is only downloaded when at least one local file does
|
||||
not match the checksums of the latest release. It is extracted
|
||||
to the root of the file system or into DESTDIR when that
|
||||
environment variable is set.
|
||||
--debug Log every command that is run and every file that is extracted
|
||||
or archived. Without it, --build is silent unless it fails. Can
|
||||
be combined with --build or --install.
|
||||
--help Show this help message.
|
||||
EOF
|
||||
}
|
||||
|
||||
# parse the arguments before anything else so that --debug logs everything
|
||||
mode=""
|
||||
verbose=""
|
||||
quiet="q"
|
||||
for arg in "$@"; do
|
||||
case "${arg}" in
|
||||
--build|--install)
|
||||
mode="${arg}"
|
||||
;;
|
||||
--debug)
|
||||
set -x
|
||||
verbose="v"
|
||||
quiet=""
|
||||
;;
|
||||
--help|-h)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "E: Unknown argument (${arg})"
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
if [ -z "${mode}" ]; then
|
||||
echo "E: A --build or --install argument is required"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
repo_url="https://github.com/ptitSeb/box64"
|
||||
|
||||
# compare the local files to the latest release and, on any mismatch, install it
|
||||
install_bundle()
|
||||
{
|
||||
# find the latest release
|
||||
release=$(basename "$(${curl} -Ls -o /dev/null -w '%{url_effective}' "${repo_url}/releases/latest")")
|
||||
case "${release}" in
|
||||
v*) ;;
|
||||
*)
|
||||
echo "E: Unable to determine the latest release"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
bundle_url="${repo_url}/releases/download/${release}/box64-bundle-x86-libs-${release}"
|
||||
bundle_checksums="${dir_tmp}/box64-bundle-x86-libs-${release}.sha256"
|
||||
bundle_archive="${dir_tmp}/box64-bundle-x86-libs-${release}.tar.gz"
|
||||
|
||||
# the checksum paths are relative to the root of the destination
|
||||
${curl_cmd} "${bundle_checksums}" "${bundle_url}.sha256"
|
||||
if [ ! -d "${dir_dest}" ]; then
|
||||
mkdir -p "${dir_dest}"
|
||||
fi
|
||||
cd "${dir_dest}"
|
||||
if ${sha256sum} --check --quiet "${bundle_checksums}" \
|
||||
> "${dir_tmp}/mismatches" 2> /dev/null; then
|
||||
echo "I: The x86 library bundle ${release} is already installed in ${dir_dest}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# a single mismatch means the whole bundle is downloaded and extracted again
|
||||
echo "I: $(wc -l < "${dir_tmp}/mismatches") file(s) do not match the latest bundle"
|
||||
if [ ! -w "${dir_dest}" ]; then
|
||||
echo "E: ${dir_dest} is not writable, run as root to install the x86 library bundle ${release}"
|
||||
exit 1
|
||||
fi
|
||||
${curl_cmd} "${bundle_archive}" "${bundle_url}.tar.gz"
|
||||
${tar} --extract --no-same-owner --file "${bundle_archive}" --directory "${dir_dest}"
|
||||
|
||||
# verify the installation
|
||||
cd "${dir_dest}"
|
||||
if ! ${sha256sum} --check --quiet "${bundle_checksums}"; then
|
||||
echo "E: Invalid checksums after installing the x86 library bundle ${release}"
|
||||
exit 1
|
||||
fi
|
||||
echo "I: Installed the x86 library bundle ${release} into ${dir_dest}"
|
||||
}
|
||||
|
||||
# we must have few tools
|
||||
awk=$(which awk) || { echo "E: You must have awk" && exit 1; }
|
||||
cpio=$(which cpio) || { echo "E: You must have cpio" && exit 1; }
|
||||
curl=$(which curl) || { echo "E: You must have curl" && exit 1; }
|
||||
curl_cmd="${curl} --connect-timeout 5 --retry 5 --retry-delay 1 --create-dirs -fsSLo"
|
||||
rpm2cpio=$(which rpm2cpio) || { echo "E: You must have rpm2cpio" && exit 1; }
|
||||
sha256sum=$(which sha256sum) || { echo "E: You must have sha256sum" && exit 1; }
|
||||
unzip=$(which unzip) || { echo "E: You must have unzip" && exit 1; }
|
||||
tar=$(which tar) || { echo "E: You must have tar" && exit 1; }
|
||||
|
||||
current_dir=$(pwd)
|
||||
dir_tmp="$(mktemp -d /tmp/box64-bundle.XXXXXX)"
|
||||
dir_dest="${DESTDIR:-/}"
|
||||
|
||||
if [ "${mode}" = "--install" ]; then
|
||||
install_bundle
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# we must have few more tools to build the bundle
|
||||
cpio=$(which cpio) || { echo "E: You must have cpio" && exit 1; }
|
||||
rpm2cpio=$(which rpm2cpio) || { echo "E: You must have rpm2cpio" && exit 1; }
|
||||
unzip=$(which unzip) || { echo "E: You must have unzip" && exit 1; }
|
||||
|
||||
# download the packages
|
||||
while IFS= read -r line; do
|
||||
@@ -41,7 +158,7 @@ while IFS= read -r line; do
|
||||
done < box64-bundle-x86-libs.csv
|
||||
|
||||
# generate the bundle packages archive
|
||||
tar -C "${dir_tmp}"/bundle-pkgs -czvf "${current_dir}"/box64-bundle-x86-pkgs.tar.gz .
|
||||
tar -C "${dir_tmp}"/bundle-pkgs -cz"${verbose}"f "${current_dir}"/box64-bundle-x86-pkgs.tar.gz .
|
||||
|
||||
# extract the packages
|
||||
cd "${dir_tmp}"/bundle-pkgs
|
||||
@@ -54,21 +171,26 @@ for file in *.deb *.eopkg *.rpm *.xbps; do
|
||||
cd "${dir_tmp}"/bundle-libs
|
||||
case "${extension}" in
|
||||
deb)
|
||||
echo "I: DEB (Debian) package detected (${file})"
|
||||
log "I: DEB (Debian) package detected (${file})"
|
||||
ar x "${dir_tmp}"/bundle-pkgs/"${file}"
|
||||
tar -xf data.tar*
|
||||
;;
|
||||
eopkg)
|
||||
echo "I: EOPKG (Solus Linux) package detected (${file})"
|
||||
${unzip} -o "${dir_tmp}"/bundle-pkgs/"${file}"
|
||||
log "I: EOPKG (Solus Linux) package detected (${file})"
|
||||
${unzip} -o"${quiet}" "${dir_tmp}"/bundle-pkgs/"${file}"
|
||||
tar -xf install.tar.xz
|
||||
;;
|
||||
rpm)
|
||||
echo "I: RPM (Fedora) detected (${file})"
|
||||
${rpm2cpio} "${dir_tmp}"/bundle-pkgs/"${file}" | ${cpio} -idmv
|
||||
log "I: RPM (Fedora) detected (${file})"
|
||||
if [ -n "${verbose}" ]; then
|
||||
${rpm2cpio} "${dir_tmp}"/bundle-pkgs/"${file}" | ${cpio} -idmv
|
||||
else
|
||||
${rpm2cpio} "${dir_tmp}"/bundle-pkgs/"${file}" \
|
||||
| ${cpio} -idm --quiet 2> /dev/null
|
||||
fi
|
||||
;;
|
||||
xbps)
|
||||
echo "I: XBPS (Void Linux) package detected (${file})"
|
||||
log "I: XBPS (Void Linux) package detected (${file})"
|
||||
tar -xf "${dir_tmp}"/bundle-pkgs/"${file}"
|
||||
;;
|
||||
esac
|
||||
@@ -77,10 +199,10 @@ done
|
||||
# reorganize the files
|
||||
cd "${dir_tmp}"/bundle-libs
|
||||
mkdir -p "${dir_tmp}"/bundle-libs/box64-i386-linux-gnu
|
||||
mv lib/*.so* usr/lib/*.so* usr/lib/i386-linux-gnu/*.so* usr/lib32/*.so* \
|
||||
mv lib/*.so* usr/lib/*.so* usr/lib/i386-linux-gnu/* usr/lib32/*.so* \
|
||||
"${dir_tmp}"/bundle-libs/box64-i386-linux-gnu
|
||||
mkdir -p "${dir_tmp}"/bundle-libs/box64-x86_64-linux-gnu
|
||||
mv lib64/*.so* usr/lib/x86_64-linux-gnu/*.so* usr/lib64/*.so* \
|
||||
mv lib64/*.so* usr/lib/x86_64-linux-gnu/* usr/lib64/*.so* \
|
||||
"${dir_tmp}"/bundle-libs/box64-x86_64-linux-gnu
|
||||
rm -f ./*.tar.* debian-binary files.xml metadata.xml
|
||||
rm -rf ./lib* etc run sbin usr var
|
||||
@@ -95,7 +217,7 @@ set -- libc libpthread librt libGL libX11 libasound libdl libm libbsd libutil \
|
||||
libxcb-xfixes libxcb-shape libxcb-shm libxcb-randr libxcb-image \
|
||||
libxcb-keysyms libxcb-xtest libxcb-glx libxcb-dri2 libxcb-dri3 libXtst libXt \
|
||||
libXcomposite libXdamage libXmu libxkbcommon libxkbcommon-x11 \
|
||||
libpulse-simple libpulse libvulkan ld-linux-x86-64 crashhandler \
|
||||
libpulse-simple libpulse libvulkan ld-linux-x86-64 \
|
||||
libtcmalloc_minimal libanl ld-linux libthread_db
|
||||
for file in "$@"; do
|
||||
rm -f "${dir_tmp}"/bundle-libs/usr/lib/box64-*-linux-gnu/"${file}".so*
|
||||
@@ -124,11 +246,16 @@ for dir_lib in "${dir_tmp}"/bundle-libs/usr/lib/box64-*-linux-gnu; do
|
||||
cd "${dir_lib}"
|
||||
for lib in lib*.so*; do
|
||||
lib_base="$(echo "${lib}" | awk -F'.' '{print $1"."$2}')"
|
||||
if ! ls "${dir_lib}/${lib_base}" 2> /dev/null; then
|
||||
if ! ls "${dir_lib}/${lib_base}" > /dev/null 2>&1; then
|
||||
ln -s "${lib}" "${lib_base}"
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
# generate a SHA256 checksum of every file and symlink in the bundle
|
||||
cd "${dir_tmp}"/bundle-libs
|
||||
find usr \( -type f -o -type l \) -exec "${sha256sum}" {} + \
|
||||
| LC_ALL=C sort --key 2 > "${current_dir}"/box64-bundle-x86-libs.sha256
|
||||
|
||||
# generate the bundle libraries archive
|
||||
tar -C "${dir_tmp}"/bundle-libs -czvf "${current_dir}"/box64-bundle-x86-libs.tar.gz .
|
||||
tar -C "${dir_tmp}"/bundle-libs -cz"${verbose}"f "${current_dir}"/box64-bundle-x86-libs.tar.gz .
|
||||
@@ -0,0 +1,245 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import Dict, Iterable, List, Optional, Tuple
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class SectionKey:
|
||||
kind: str
|
||||
name: str
|
||||
arch: str = ""
|
||||
|
||||
def sort_key(self) -> Tuple[int, str, str]:
|
||||
order = {"shared": 0, "exact": 1, "wildcard": 2, "file": 3}
|
||||
return (order.get(self.kind, 9), self.name.lower(), self.arch.lower())
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Assignment:
|
||||
key: str
|
||||
value: str
|
||||
line_index: int
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class RcSection:
|
||||
header: str
|
||||
start: int
|
||||
end: int
|
||||
key: SectionKey
|
||||
assignments: Tuple[Assignment, ...]
|
||||
|
||||
def last_value(self, key: str) -> Optional[str]:
|
||||
return next((item.value for item in reversed(self.assignments) if item.key == key), None)
|
||||
|
||||
|
||||
def normalize_arch(value: Optional[str]) -> str:
|
||||
value = (value or "").strip().strip("`")
|
||||
if value == "<empty>":
|
||||
return ""
|
||||
return value.lower()
|
||||
|
||||
|
||||
def section_key_from_header(header: str, arch: Optional[str] = None) -> SectionKey:
|
||||
name = header.strip()
|
||||
arch_value = normalize_arch(arch)
|
||||
if name == "*":
|
||||
return SectionKey("shared", "*", arch_value)
|
||||
if name.startswith("*") and name.endswith("*") and len(name) > 2:
|
||||
return SectionKey("wildcard", name[1:-1].strip().lower(), arch_value)
|
||||
if name.startswith("/"):
|
||||
return SectionKey("file", name.lower(), arch_value)
|
||||
return SectionKey("exact", name.lower(), arch_value)
|
||||
|
||||
|
||||
def normalize_section_input(value: str) -> str:
|
||||
name = value.strip()
|
||||
if name.startswith("[") or name.endswith("]"):
|
||||
if not (name.startswith("[") and name.endswith("]")):
|
||||
raise ValueError("Invalid section name")
|
||||
name = name[1:-1].strip()
|
||||
|
||||
if not name or any(char in name for char in "\r\n[]#"):
|
||||
raise ValueError("Invalid section name")
|
||||
return name
|
||||
|
||||
|
||||
def header_from_key(key: SectionKey) -> str:
|
||||
if key.kind == "shared":
|
||||
return "*"
|
||||
if key.kind == "wildcard":
|
||||
return f"*{key.name}*"
|
||||
return key.name
|
||||
|
||||
|
||||
def semantic_line(line: str) -> str:
|
||||
return line.rstrip("\n").split("#", 1)[0].strip()
|
||||
|
||||
|
||||
def parse_section_header(line: str) -> Optional[str]:
|
||||
semantic = semantic_line(line)
|
||||
return semantic[1 : semantic.find("]")].strip() if semantic.startswith("[") and "]" in semantic else None
|
||||
|
||||
|
||||
def parse_assignment(line: str) -> Optional[Tuple[str, str]]:
|
||||
semantic = semantic_line(line)
|
||||
if "=" not in semantic:
|
||||
return None
|
||||
key, value = semantic.split("=", 1)
|
||||
key = key.strip()
|
||||
return (key, value.strip()) if key else None
|
||||
|
||||
|
||||
def render_assignment_line(original: str, key: str, value: str) -> str:
|
||||
text = original.rstrip("\n")
|
||||
newline = "\n" if original.endswith("\n") else ""
|
||||
indent = text[: len(text) - len(text.lstrip())]
|
||||
comment = ""
|
||||
comment_start = text.find("#")
|
||||
if comment_start >= 0:
|
||||
comment = " " + text[comment_start:].strip()
|
||||
return f"{indent}{key}={value}{comment}{newline or os.linesep}"
|
||||
|
||||
|
||||
class RcDocument:
|
||||
def __init__(self, path: Path) -> None:
|
||||
self.path = path
|
||||
self.lines: List[str] = []
|
||||
self.sections: List[RcSection] = []
|
||||
self.sections_by_key: Dict[SectionKey, RcSection] = {}
|
||||
self.reload()
|
||||
|
||||
def reload(self) -> None:
|
||||
self.lines = self.path.read_text(encoding="utf-8").splitlines(True) if self.path.is_file() else []
|
||||
self._parse()
|
||||
|
||||
def _parse(self) -> None:
|
||||
builders: List[Dict[str, object]] = []
|
||||
current: Optional[Dict[str, object]] = None
|
||||
|
||||
for index, line in enumerate(self.lines):
|
||||
header = parse_section_header(line)
|
||||
if header is not None:
|
||||
if current is not None:
|
||||
current["end"] = index
|
||||
current = {
|
||||
"header": header,
|
||||
"start": index,
|
||||
"end": len(self.lines),
|
||||
"assignments": [],
|
||||
}
|
||||
builders.append(current)
|
||||
continue
|
||||
|
||||
if current is None:
|
||||
continue
|
||||
|
||||
parsed = parse_assignment(line)
|
||||
if parsed is None:
|
||||
continue
|
||||
key, value = parsed
|
||||
current["assignments"].append(Assignment(key, value, index))
|
||||
|
||||
if current is not None:
|
||||
current["end"] = len(self.lines)
|
||||
|
||||
sections: List[RcSection] = []
|
||||
for builder in builders:
|
||||
assignments = tuple(builder["assignments"])
|
||||
arch = next((item.value for item in reversed(assignments) if item.key == "BOX64_ARCH"), None)
|
||||
key = section_key_from_header(str(builder["header"]), arch)
|
||||
sections.append(
|
||||
RcSection(
|
||||
header=str(builder["header"]),
|
||||
start=int(builder["start"]),
|
||||
end=int(builder["end"]),
|
||||
key=key,
|
||||
assignments=assignments,
|
||||
)
|
||||
)
|
||||
|
||||
self.sections = sections
|
||||
self.sections_by_key = {section.key: section for section in sections}
|
||||
|
||||
def section_for_key(self, key: SectionKey) -> Optional[RcSection]:
|
||||
return self.sections_by_key.get(key)
|
||||
|
||||
def add_section(self, header: str, assignments: Optional[Dict[str, str]] = None) -> RcSection:
|
||||
if self.lines and self.lines[-1].strip():
|
||||
self.lines.append(os.linesep)
|
||||
self.lines.append(f"[{header}]{os.linesep}")
|
||||
for key, value in (assignments or {}).items():
|
||||
self.lines.append(f"{key}={value}{os.linesep}")
|
||||
self._parse()
|
||||
return self.sections[-1]
|
||||
|
||||
def delete_section(self, key: SectionKey) -> None:
|
||||
section = self.section_for_key(key)
|
||||
if section is None:
|
||||
return
|
||||
delete_end = section.end
|
||||
if section.assignments:
|
||||
delete_end = section.assignments[-1].line_index + 1
|
||||
del self.lines[section.start : delete_end]
|
||||
self._parse()
|
||||
|
||||
def set_assignment(self, section_key: SectionKey, key: str, value: str) -> SectionKey:
|
||||
section = self.section_for_key(section_key)
|
||||
if section is None:
|
||||
raise KeyError(section_key)
|
||||
|
||||
matching = [assignment for assignment in section.assignments if assignment.key == key]
|
||||
if matching:
|
||||
line_index = matching[-1].line_index
|
||||
self.lines[line_index] = render_assignment_line(self.lines[line_index], key, value)
|
||||
start = section.start
|
||||
else:
|
||||
insert_at = section.end
|
||||
self.lines.insert(insert_at, f"{key}={value}{os.linesep}")
|
||||
start = section.start
|
||||
|
||||
self._parse()
|
||||
for updated in self.sections:
|
||||
if updated.start == start:
|
||||
return updated.key
|
||||
raise KeyError(section_key)
|
||||
|
||||
def remove_assignment(self, section_key: SectionKey, key: str) -> SectionKey:
|
||||
section = self.section_for_key(section_key)
|
||||
if section is None:
|
||||
raise KeyError(section_key)
|
||||
|
||||
indexes = [assignment.line_index for assignment in section.assignments if assignment.key == key]
|
||||
start = section.start
|
||||
for line_index in reversed(indexes):
|
||||
del self.lines[line_index]
|
||||
|
||||
self._parse()
|
||||
for updated in self.sections:
|
||||
if updated.start == start:
|
||||
return updated.key
|
||||
return section_key
|
||||
|
||||
def save(self) -> None:
|
||||
self.path.parent.mkdir(parents=True, exist_ok=True)
|
||||
data = "".join(self.lines)
|
||||
tmp_path = self.path.with_name(f"{self.path.name}.tmp")
|
||||
tmp_path.write_text(data, encoding="utf-8")
|
||||
if self.path.exists():
|
||||
mode = self.path.stat().st_mode
|
||||
os.chmod(tmp_path, mode)
|
||||
os.replace(tmp_path, self.path)
|
||||
|
||||
|
||||
def copy_assignments(section: RcSection) -> Dict[str, str]:
|
||||
return {assignment.key: assignment.value for assignment in section.assignments}
|
||||
|
||||
|
||||
def direct_box64_assignments(section: Optional[RcSection]) -> Iterable[Assignment]:
|
||||
return () if section is None else tuple(
|
||||
assignment for assignment in section.assignments if assignment.key.startswith("BOX64_")
|
||||
)
|
||||
Executable
+121
@@ -0,0 +1,121 @@
|
||||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: MIT
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import pprint
|
||||
from pathlib import Path
|
||||
from typing import Dict, Optional, Sequence
|
||||
|
||||
|
||||
MODULES = {
|
||||
"box64rc": "box64rc.py",
|
||||
"usage": "usage.py",
|
||||
"model": "model.py",
|
||||
"configurator": "configurator.py",
|
||||
}
|
||||
|
||||
UI_FILE = "configurator.ui"
|
||||
|
||||
|
||||
def parse_args(argv: Optional[Sequence[str]] = None) -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(description="Build the standalone box64-configurator script")
|
||||
parser.add_argument("--output", required=True, type=Path)
|
||||
parser.add_argument("--configurator-dir", required=True, type=Path)
|
||||
parser.add_argument("--usage", required=True, type=Path)
|
||||
parser.add_argument("--usage-cn", required=True, type=Path)
|
||||
return parser.parse_args(argv)
|
||||
|
||||
|
||||
def read_modules(configurator_dir: Path) -> Dict[str, str]:
|
||||
return {
|
||||
name: (configurator_dir / filename).read_text(encoding="utf-8")
|
||||
for name, filename in MODULES.items()
|
||||
}
|
||||
|
||||
|
||||
def read_texts(configurator_dir: Path) -> Dict[str, Dict[str, str]]:
|
||||
return {language: read_json(configurator_dir / f"text_{language}.json") for language in ("en", "zh")}
|
||||
|
||||
|
||||
def read_ui(configurator_dir: Path) -> str:
|
||||
return (configurator_dir / UI_FILE).read_text(encoding="utf-8")
|
||||
|
||||
|
||||
def read_json(path: Path):
|
||||
with path.open("r", encoding="utf-8") as file:
|
||||
return json.load(file)
|
||||
|
||||
|
||||
def render_script(
|
||||
modules: Dict[str, str],
|
||||
texts: Dict[str, Dict[str, str]],
|
||||
ui: str,
|
||||
usage_data,
|
||||
usage_cn_data,
|
||||
) -> str:
|
||||
return f"""#!/usr/bin/env python3
|
||||
# Generated by configurator/build_standalone.py. Do not edit this file directly.
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
import types
|
||||
|
||||
_MODULES = {pprint.pformat(modules, width=120)}
|
||||
_EMBEDDED_TEXTS = {pprint.pformat(texts, width=120)}
|
||||
_EMBEDDED_UI = {pprint.pformat(ui, width=120)}
|
||||
_EMBEDDED_USAGE_DATA = {pprint.pformat(usage_data, width=120)}
|
||||
_EMBEDDED_USAGE_CN_DATA = {pprint.pformat(usage_cn_data, width=120)}
|
||||
|
||||
|
||||
def _load_module(name: str) -> types.ModuleType:
|
||||
module = types.ModuleType(name)
|
||||
module.__file__ = f"<box64-configurator:{{name}}>"
|
||||
module.__package__ = ""
|
||||
if name == "usage":
|
||||
module._EMBEDDED_USAGE_DATA = _EMBEDDED_USAGE_DATA
|
||||
module._EMBEDDED_USAGE_CN_DATA = _EMBEDDED_USAGE_CN_DATA
|
||||
sys.modules[name] = module
|
||||
exec(compile(_MODULES[name], module.__file__, "exec"), module.__dict__)
|
||||
return module
|
||||
|
||||
|
||||
for _name in ("box64rc", "usage", "model"):
|
||||
_load_module(_name)
|
||||
|
||||
_app = types.ModuleType("box64_configurator_app")
|
||||
_app.__file__ = __file__
|
||||
_app.__package__ = ""
|
||||
_app._EMBEDDED_TEXTS = _EMBEDDED_TEXTS
|
||||
_app._EMBEDDED_UI = _EMBEDDED_UI
|
||||
sys.modules["box64_configurator_app"] = _app
|
||||
exec(compile(_MODULES["configurator"], __file__, "exec"), _app.__dict__)
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(_app.main())
|
||||
"""
|
||||
|
||||
|
||||
def main(argv: Optional[Sequence[str]] = None) -> int:
|
||||
args = parse_args(argv)
|
||||
configurator_dir = args.configurator_dir.resolve()
|
||||
output = args.output.resolve()
|
||||
|
||||
script = render_script(
|
||||
read_modules(configurator_dir),
|
||||
read_texts(configurator_dir),
|
||||
read_ui(configurator_dir),
|
||||
read_json(args.usage),
|
||||
read_json(args.usage_cn),
|
||||
)
|
||||
|
||||
output.parent.mkdir(parents=True, exist_ok=True)
|
||||
output.write_text(script, encoding="utf-8")
|
||||
os.chmod(output, 0o755)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Executable
+1355
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,179 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.40.0 -->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.20"/>
|
||||
<object class="GtkHeaderBar" id="header">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="show-close-button">True</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="reload_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="receives-default">False</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="pack-type">end</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="save_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="receives-default">False</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="pack-type">end</property>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkComboBoxText" id="language_combo">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="pack-type">end</property>
|
||||
<property name="position">4</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<object class="GtkBox" id="root_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkPaned" id="main_paned">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="sidebar">
|
||||
<property name="width-request">285</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="new_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="receives-default">False</property>
|
||||
<property name="margin-start">14</property>
|
||||
<property name="margin-end">14</property>
|
||||
<property name="margin-top">10</property>
|
||||
<property name="margin-bottom">6</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSearchEntry" id="search_entry">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="margin-start">14</property>
|
||||
<property name="margin-end">14</property>
|
||||
<property name="margin-bottom">6</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="mode_box">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="margin-start">14</property>
|
||||
<property name="margin-end">14</property>
|
||||
<property name="margin-bottom">8</property>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="user_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="receives-default">False</property>
|
||||
<property name="active">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="all_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="receives-default">False</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<style>
|
||||
<class name="linked"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="list_scroll">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="hscrollbar-policy">never</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<style>
|
||||
<class name="sidebar"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="resize">False</property>
|
||||
<property name="shrink">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="detail_scroll">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="hscrollbar-policy">never</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="resize">True</property>
|
||||
<property name="shrink">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStatusbar" id="statusbar">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
@@ -0,0 +1,388 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Optional, Tuple
|
||||
|
||||
try:
|
||||
from .box64rc import (
|
||||
Assignment,
|
||||
RcDocument,
|
||||
RcSection,
|
||||
SectionKey,
|
||||
copy_assignments,
|
||||
direct_box64_assignments,
|
||||
header_from_key,
|
||||
normalize_section_input,
|
||||
section_key_from_header,
|
||||
)
|
||||
from .usage import EnvOption, UsageCatalog
|
||||
except ImportError:
|
||||
from box64rc import (
|
||||
Assignment,
|
||||
RcDocument,
|
||||
RcSection,
|
||||
SectionKey,
|
||||
copy_assignments,
|
||||
direct_box64_assignments,
|
||||
header_from_key,
|
||||
normalize_section_input,
|
||||
section_key_from_header,
|
||||
)
|
||||
from usage import EnvOption, UsageCatalog
|
||||
|
||||
|
||||
ARCH_ALIASES = {
|
||||
"aarch64": "arm64",
|
||||
"arm64": "arm64",
|
||||
"amd64": "x86_64",
|
||||
"loong64": "la64",
|
||||
"loongarch64": "la64",
|
||||
"powerpc64le": "ppc64le",
|
||||
"ppc64le": "ppc64le",
|
||||
"x86_64": "x86_64",
|
||||
}
|
||||
|
||||
|
||||
def box64_arch_from_machine(machine: Optional[str]) -> str:
|
||||
value = (machine or "").strip().lower().replace("-", "_")
|
||||
if value.startswith("riscv64"):
|
||||
return "rv64"
|
||||
return ARCH_ALIASES.get(value, value)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class EntryRecord:
|
||||
key: SectionKey
|
||||
display_name: str
|
||||
system_section: Optional[RcSection]
|
||||
user_section: Optional[RcSection]
|
||||
|
||||
@property
|
||||
def editable_source(self) -> str:
|
||||
if self.user_section is not None:
|
||||
return "user"
|
||||
if self.system_section is not None:
|
||||
return "system"
|
||||
return "new"
|
||||
|
||||
@property
|
||||
def arch(self) -> str:
|
||||
return self.key.arch
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ValueState:
|
||||
option: EnvOption
|
||||
value: str
|
||||
source: str
|
||||
|
||||
|
||||
SectionIdentity = Tuple[str, str]
|
||||
|
||||
|
||||
OFTEN_USED_OPTION_NAMES = {
|
||||
"BOX64_DYNAREC_BIGBLOCK",
|
||||
"BOX64_DYNAREC_CALLRET",
|
||||
"BOX64_DYNAREC_SAFEFLAGS",
|
||||
"BOX64_DYNAREC_STRONGMEM",
|
||||
"BOX64_DYNAREC_DIRTY",
|
||||
"BOX64_DYNAREC_FASTROUND",
|
||||
"BOX64_DYNAREC_FASTNAN",
|
||||
"BOX64_MAXCPU",
|
||||
}
|
||||
|
||||
|
||||
PROFILE_OPTION_NAME = "BOX64_PROFILE"
|
||||
PROFILE_DEFAULT_VALUE = "default"
|
||||
PROFILE_SETTINGS = {
|
||||
"safest": (
|
||||
("BOX64_DYNAREC_FASTNAN", "0"),
|
||||
("BOX64_DYNAREC_FASTROUND", "0"),
|
||||
("BOX64_DYNAREC_BIGBLOCK", "0"),
|
||||
("BOX64_DYNAREC_SAFEFLAGS", "2"),
|
||||
("BOX64_DYNAREC_STRONGMEM", "2"),
|
||||
("BOX64_DYNAREC_CALLRET", "3"),
|
||||
),
|
||||
"safe": (
|
||||
("BOX64_DYNAREC_BIGBLOCK", "0"),
|
||||
("BOX64_DYNAREC_SAFEFLAGS", "2"),
|
||||
("BOX64_DYNAREC_STRONGMEM", "1"),
|
||||
),
|
||||
"fast": (
|
||||
("BOX64_DYNAREC_CALLRET", "1"),
|
||||
("BOX64_DYNAREC_BIGBLOCK", "3"),
|
||||
("BOX64_DYNAREC_SAFEFLAGS", "0"),
|
||||
("BOX64_DYNAREC_STRONGMEM", "1"),
|
||||
("BOX64_DYNAREC_DIRTY", "1"),
|
||||
("BOX64_DYNAREC_FORWARD", "1024"),
|
||||
),
|
||||
"fastest": (
|
||||
("BOX64_DYNAREC_CALLRET", "1"),
|
||||
("BOX64_DYNAREC_BIGBLOCK", "3"),
|
||||
("BOX64_DYNAREC_SAFEFLAGS", "0"),
|
||||
("BOX64_DYNAREC_STRONGMEM", "0"),
|
||||
("BOX64_DYNAREC_DIRTY", "1"),
|
||||
("BOX64_DYNAREC_FORWARD", "1024"),
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
class ConfigStore:
|
||||
def __init__(
|
||||
self, system_path: Path, user_path: Path, catalog: UsageCatalog, machine_arch: str = ""
|
||||
) -> None:
|
||||
self.catalog = catalog
|
||||
self.machine_arch = machine_arch
|
||||
self.system = RcDocument(system_path)
|
||||
self.user = RcDocument(user_path)
|
||||
self.dirty = False
|
||||
self._entries: Tuple[EntryRecord, ...] = ()
|
||||
self._entries_by_key: Dict[SectionKey, EntryRecord] = {}
|
||||
self._system_sections_by_identity: Dict[SectionIdentity, RcSection] = {}
|
||||
self._user_sections_by_identity: Dict[SectionIdentity, RcSection] = {}
|
||||
self._rebuild_entry_cache()
|
||||
|
||||
def reload(self) -> None:
|
||||
self.system.reload()
|
||||
self.user.reload()
|
||||
self.dirty = False
|
||||
self._rebuild_entry_cache()
|
||||
|
||||
def save(self) -> None:
|
||||
self.user.save()
|
||||
self.reload()
|
||||
|
||||
def entries(self) -> Tuple[EntryRecord, ...]:
|
||||
return self._entries
|
||||
|
||||
def entry_for_key(self, key: SectionKey) -> Optional[EntryRecord]:
|
||||
return self._entries_by_key.get(key)
|
||||
|
||||
def _rebuild_entry_cache(self) -> None:
|
||||
self._system_sections_by_identity = self._effective_sections(self.system)
|
||||
self._user_sections_by_identity = self._effective_sections(self.user)
|
||||
identities = set(self._system_sections_by_identity)
|
||||
identities.update(self._user_sections_by_identity)
|
||||
|
||||
entries: List[EntryRecord] = []
|
||||
for identity in identities:
|
||||
system_section = self._system_sections_by_identity.get(identity)
|
||||
user_section = self._user_sections_by_identity.get(identity)
|
||||
display_section = user_section or system_section
|
||||
if display_section is None:
|
||||
continue
|
||||
display_name = display_section.header if display_section else header_from_key(display_section.key)
|
||||
entries.append(EntryRecord(display_section.key, display_name, system_section, user_section))
|
||||
|
||||
self._entries = tuple(
|
||||
sorted(entries, key=lambda entry: (entry.key.sort_key(), entry.display_name.lower()))
|
||||
)
|
||||
self._entries_by_key = {entry.key: entry for entry in self._entries}
|
||||
|
||||
def _effective_sections(self, document: RcDocument) -> Dict[SectionIdentity, RcSection]:
|
||||
sections: Dict[SectionIdentity, RcSection] = {}
|
||||
for section in document.sections:
|
||||
if not self._section_matches_arch(section):
|
||||
continue
|
||||
|
||||
identity = self._identity(section.key)
|
||||
current = sections.get(identity)
|
||||
if current is None or self._section_replaces(current, section):
|
||||
sections[identity] = section
|
||||
return sections
|
||||
|
||||
def _section_matches_arch(self, section: RcSection) -> bool:
|
||||
return not section.key.arch or section.key.arch == self.machine_arch
|
||||
|
||||
def _section_replaces(self, current: RcSection, candidate: RcSection) -> bool:
|
||||
if candidate.key.arch:
|
||||
return candidate.key.arch == self.machine_arch
|
||||
return not current.key.arch
|
||||
|
||||
def _identity(self, key: SectionKey) -> SectionIdentity:
|
||||
return key.kind, key.name
|
||||
|
||||
def _mark_dirty(self) -> None:
|
||||
self.dirty = True
|
||||
self._rebuild_entry_cache()
|
||||
|
||||
def create_entry(self, header: str) -> SectionKey:
|
||||
normalized = normalize_section_input(header)
|
||||
requested_key = section_key_from_header(normalized)
|
||||
user_section = self.user.section_for_key(requested_key)
|
||||
if user_section is not None:
|
||||
return user_section.key
|
||||
|
||||
section = self.user.add_section(normalized)
|
||||
self._mark_dirty()
|
||||
return section.key
|
||||
|
||||
def delete_user_entry(self, key: SectionKey) -> None:
|
||||
self.user.delete_section(key)
|
||||
self._mark_dirty()
|
||||
|
||||
def fork_entry(self, entry: EntryRecord) -> Tuple[SectionKey, bool]:
|
||||
section, forked = self._ensure_user_section(entry)
|
||||
if forked:
|
||||
self._mark_dirty()
|
||||
return section.key, forked
|
||||
|
||||
def set_option(self, entry: EntryRecord, option_name: str, value: str) -> Tuple[SectionKey, bool]:
|
||||
section, forked = self._ensure_user_section(entry)
|
||||
if self._is_default_profile(option_name, value):
|
||||
new_key = self.user.remove_assignment(section.key, option_name)
|
||||
else:
|
||||
new_key = self.user.set_assignment(section.key, option_name, value)
|
||||
self._mark_dirty()
|
||||
return new_key, forked
|
||||
|
||||
def reset_option(self, entry: EntryRecord, option_name: str) -> SectionKey:
|
||||
user_section = entry.user_section
|
||||
if user_section is None:
|
||||
return entry.key
|
||||
|
||||
system_value = None
|
||||
if entry.system_section is not None:
|
||||
system_value = entry.system_section.last_value(option_name)
|
||||
|
||||
if system_value is not None and not self._is_default_profile(option_name, system_value):
|
||||
new_key = self.user.set_assignment(user_section.key, option_name, system_value)
|
||||
else:
|
||||
new_key = self.user.remove_assignment(user_section.key, option_name)
|
||||
self._mark_dirty()
|
||||
return new_key
|
||||
|
||||
def unsupported_assignments(self, entry: EntryRecord) -> Tuple[Assignment, ...]:
|
||||
section = entry.user_section or entry.system_section
|
||||
return tuple(
|
||||
assignment for assignment in direct_box64_assignments(section) if assignment.key not in self.catalog
|
||||
)
|
||||
|
||||
def effective_values(
|
||||
self, entry: EntryRecord
|
||||
) -> Tuple[List[ValueState], List[ValueState], List[ValueState]]:
|
||||
states: Dict[str, ValueState] = {}
|
||||
|
||||
if entry.key.kind != "shared":
|
||||
self._apply_shared(states)
|
||||
self._apply_matching_wildcards(states, entry)
|
||||
|
||||
self._apply_direct(states, entry)
|
||||
self._apply_profile(states)
|
||||
|
||||
active: List[ValueState] = []
|
||||
often_used: List[ValueState] = []
|
||||
defaults: List[ValueState] = []
|
||||
for option in self.catalog.options:
|
||||
state = states.get(option.name)
|
||||
if state is None:
|
||||
default_state = ValueState(
|
||||
option=option,
|
||||
value=option.default_value,
|
||||
source="default",
|
||||
)
|
||||
if option.name in OFTEN_USED_OPTION_NAMES:
|
||||
often_used.append(default_state)
|
||||
else:
|
||||
defaults.append(default_state)
|
||||
else:
|
||||
active.append(state)
|
||||
|
||||
active.sort(key=lambda state: state.option.name != PROFILE_OPTION_NAME)
|
||||
return active, often_used, defaults
|
||||
|
||||
def _apply_profile(self, states: Dict[str, ValueState]) -> None:
|
||||
profile_option = self.catalog.by_name.get(PROFILE_OPTION_NAME)
|
||||
if profile_option is None:
|
||||
return
|
||||
|
||||
profile_state = states.get(PROFILE_OPTION_NAME)
|
||||
if profile_state is None:
|
||||
profile_state = ValueState(
|
||||
option=profile_option,
|
||||
value=PROFILE_DEFAULT_VALUE,
|
||||
source="default",
|
||||
)
|
||||
states[PROFILE_OPTION_NAME] = profile_state
|
||||
|
||||
for option_name, value in PROFILE_SETTINGS.get(profile_state.value.lower(), ()):
|
||||
if option_name in states:
|
||||
continue
|
||||
option = self.catalog.by_name.get(option_name)
|
||||
if option is None:
|
||||
continue
|
||||
states[option_name] = ValueState(
|
||||
option=option,
|
||||
value=value,
|
||||
source="profile",
|
||||
)
|
||||
|
||||
def _is_default_profile(self, option_name: str, value: Optional[str]) -> bool:
|
||||
return (
|
||||
option_name == PROFILE_OPTION_NAME
|
||||
and (value or "").strip().lower() == PROFILE_DEFAULT_VALUE
|
||||
)
|
||||
|
||||
def _ensure_user_section(self, entry: EntryRecord) -> Tuple[RcSection, bool]:
|
||||
user_section = self.user.section_for_key(entry.key)
|
||||
if user_section is not None:
|
||||
return user_section, False
|
||||
|
||||
if entry.system_section is not None:
|
||||
assignments = copy_assignments(entry.system_section)
|
||||
user_section = self.user.add_section(entry.system_section.header, assignments)
|
||||
return user_section, True
|
||||
|
||||
user_section = self.user.add_section(entry.display_name)
|
||||
return user_section, True
|
||||
|
||||
def _apply_shared(self, states: Dict[str, ValueState]) -> None:
|
||||
for section, source in (
|
||||
(self._system_sections_by_identity.get(("shared", "*")), "shared-system"),
|
||||
(self._user_sections_by_identity.get(("shared", "*")), "shared-user"),
|
||||
):
|
||||
if section is not None:
|
||||
self._apply_assignments(states, section, source)
|
||||
|
||||
def _apply_matching_wildcards(self, states: Dict[str, ValueState], entry: EntryRecord) -> None:
|
||||
if entry.key.kind not in ("exact", "file"):
|
||||
return
|
||||
|
||||
target = entry.key.name.lower()
|
||||
wildcard_identities = {
|
||||
identity
|
||||
for identity in (
|
||||
*self._system_sections_by_identity.keys(),
|
||||
*self._user_sections_by_identity.keys(),
|
||||
)
|
||||
if identity[0] == "wildcard" and identity[1] in target
|
||||
}
|
||||
|
||||
for identity in sorted(wildcard_identities, key=lambda item: item[1]):
|
||||
user_section = self._user_sections_by_identity.get(identity)
|
||||
system_section = self._system_sections_by_identity.get(identity)
|
||||
if user_section is not None:
|
||||
self._apply_assignments(states, user_section, "wildcard-user")
|
||||
elif system_section is not None:
|
||||
self._apply_assignments(states, system_section, "wildcard-system")
|
||||
|
||||
def _apply_direct(self, states: Dict[str, ValueState], entry: EntryRecord) -> None:
|
||||
if entry.user_section is not None:
|
||||
self._apply_assignments(states, entry.user_section, "user")
|
||||
elif entry.system_section is not None:
|
||||
self._apply_assignments(states, entry.system_section, "system")
|
||||
|
||||
def _apply_assignments(
|
||||
self, states: Dict[str, ValueState], section: RcSection, source: str
|
||||
) -> None:
|
||||
for assignment in section.assignments:
|
||||
option = self.catalog.by_name.get(assignment.key)
|
||||
if option is None:
|
||||
continue
|
||||
states[assignment.key] = ValueState(
|
||||
option=option,
|
||||
value=assignment.value,
|
||||
source=source,
|
||||
)
|
||||
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"title": "Box64 Configurator",
|
||||
"filter_all": "All",
|
||||
"filter_user": "User",
|
||||
"search": "Search entries",
|
||||
"new": "New entry",
|
||||
"delete": "Delete user entry",
|
||||
"reload": "Reload",
|
||||
"save": "Save",
|
||||
"select_entry": "Select an entry on the left.",
|
||||
"effective": "Effective options",
|
||||
"often_used": "Often used options",
|
||||
"defaults": "Default values",
|
||||
"unsupported": "Other rcfile keys",
|
||||
"unsupported_help": "These keys are preserved when a system entry is forked, but this tool does not edit them.",
|
||||
"system_note": "This entry comes from the system rcfile. Fork it to edit it in the user rcfile.",
|
||||
"user_note": "This entry is stored in the user rcfile.",
|
||||
"forked": "Created a user fork; save writes it to the user rcfile.",
|
||||
"dirty": "Unsaved changes",
|
||||
"saved": "Saved user rcfile",
|
||||
"source_user": "User",
|
||||
"source_system": "System",
|
||||
"source_shared-user": "User shared",
|
||||
"source_shared-system": "System shared",
|
||||
"source_wildcard-user": "User wildcard",
|
||||
"source_wildcard-system": "System wildcard",
|
||||
"source_profile": "Profile",
|
||||
"source_default": "Default",
|
||||
"default_dynamic": "build dependent",
|
||||
"apply": "Apply",
|
||||
"edit": "Edit",
|
||||
"reset": "Reset",
|
||||
"default_marker": "Default",
|
||||
"new_title": "New entry",
|
||||
"new_prompt": "Executable name",
|
||||
"new_drop_hint": "You can also drag and drop an executable onto the window to create an emtry entry.",
|
||||
"new_global_hint": "Use * to create a global entry.",
|
||||
"cancel": "Cancel",
|
||||
"create": "Create",
|
||||
"delete_title": "Delete user entry?",
|
||||
"delete_body": "Only the user rcfile section will be removed. The system rcfile is not changed.",
|
||||
"delete_action": "Delete",
|
||||
"fork_action": "Fork",
|
||||
"save_changes_title": "Save changes before closing?",
|
||||
"save_changes_body": "Your user rcfile edits have not been saved.",
|
||||
"discard": "Discard",
|
||||
"error": "Error"
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"title": "Box64 配置器",
|
||||
"filter_all": "全部",
|
||||
"filter_user": "用户",
|
||||
"search": "搜索条目",
|
||||
"new": "新建条目",
|
||||
"delete": "删除用户条目",
|
||||
"reload": "重新载入",
|
||||
"save": "保存",
|
||||
"select_entry": "请在左侧选择一个条目。",
|
||||
"effective": "生效选项",
|
||||
"often_used": "常用选项",
|
||||
"defaults": "默认值",
|
||||
"unsupported": "其他配置项",
|
||||
"unsupported_help": "系统条目复制到用户时会保留这些项,但此工具不会编辑它们。",
|
||||
"system_note": "此条目来自系统配置。请先复制到用户后再编辑。",
|
||||
"user_note": "此条目保存在用户配置中。",
|
||||
"forked": "已复制到用户,保存后写入用户配置。",
|
||||
"dirty": "有未保存的修改",
|
||||
"saved": "已保存用户配置",
|
||||
"source_user": "用户",
|
||||
"source_system": "系统",
|
||||
"source_shared-user": "用户共享",
|
||||
"source_shared-system": "系统共享",
|
||||
"source_wildcard-user": "用户通配",
|
||||
"source_wildcard-system": "系统通配",
|
||||
"source_profile": "预设",
|
||||
"source_default": "默认",
|
||||
"default_dynamic": "随构建而定",
|
||||
"apply": "应用",
|
||||
"edit": "编辑",
|
||||
"reset": "重置",
|
||||
"default_marker": "默认",
|
||||
"new_title": "新建条目",
|
||||
"new_prompt": "可执行文件名",
|
||||
"new_drop_hint": "也可以将可执行文件拖放到窗口中来创建新条目。",
|
||||
"new_global_hint": "输入 * 可创建全局条目。",
|
||||
"cancel": "取消",
|
||||
"create": "创建",
|
||||
"delete_title": "删除用户条目?",
|
||||
"delete_body": "只会移除用户配置中的段,系统配置不会被修改。",
|
||||
"delete_action": "删除",
|
||||
"fork_action": "复制到用户",
|
||||
"save_changes_title": "关闭前保存修改?",
|
||||
"save_changes_body": "用户配置的修改尚未保存。",
|
||||
"discard": "放弃",
|
||||
"error": "错误"
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, Iterable, List, Optional, Tuple
|
||||
|
||||
|
||||
PLACEHOLDER_MARKERS = (
|
||||
"XXXX",
|
||||
"YYYY",
|
||||
"ZZZZ",
|
||||
"xxx",
|
||||
"yyy",
|
||||
"zzz",
|
||||
"symbolname",
|
||||
)
|
||||
|
||||
_EMBEDDED_USAGE_DATA: Optional[List[Dict[str, Any]]] = globals().get("_EMBEDDED_USAGE_DATA")
|
||||
_EMBEDDED_USAGE_CN_DATA: Optional[Dict[str, Any]] = globals().get("_EMBEDDED_USAGE_CN_DATA")
|
||||
ALWAYS_CONFIGURATOR_OPTIONS = {"BOX64_PROFILE"}
|
||||
|
||||
|
||||
def clean_choice_value(raw_key: str) -> str:
|
||||
value = str(raw_key).strip()
|
||||
if value.startswith("`") and value.endswith("`") and len(value) >= 2:
|
||||
value = value[1:-1]
|
||||
return "" if value == "<empty>" else value
|
||||
|
||||
|
||||
def is_placeholder_value(value: str) -> bool:
|
||||
return bool(value) and (
|
||||
any(marker in value for marker in PLACEHOLDER_MARKERS) or value.startswith("0x") and "X" in value
|
||||
)
|
||||
|
||||
|
||||
def localized(language: str, english: str, chinese: str) -> str:
|
||||
return (chinese or english) if language == "zh" else english
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Choice:
|
||||
value: str
|
||||
label: str
|
||||
description_en: str
|
||||
description_cn: str
|
||||
is_default: bool
|
||||
is_placeholder: bool
|
||||
|
||||
def description(self, language: str) -> str:
|
||||
return localized(language, self.description_en, self.description_cn)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class EnvOption:
|
||||
name: str
|
||||
description_en: str
|
||||
description_cn: str
|
||||
choices: Tuple[Choice, ...]
|
||||
|
||||
@property
|
||||
def allows_custom_value(self) -> bool:
|
||||
return any(choice.is_placeholder for choice in self.choices)
|
||||
|
||||
@property
|
||||
def default_value(self) -> str:
|
||||
return next((choice.value for choice in self.choices if choice.is_default), "")
|
||||
|
||||
def description(self, language: str) -> str:
|
||||
return localized(language, self.description_en, self.description_cn)
|
||||
|
||||
|
||||
class UsageCatalog:
|
||||
def __init__(self, options: Iterable[EnvOption]) -> None:
|
||||
self.options: Tuple[EnvOption, ...] = tuple(options)
|
||||
self.by_name: Dict[str, EnvOption] = {option.name: option for option in self.options}
|
||||
|
||||
def __contains__(self, name: str) -> bool:
|
||||
return name in self.by_name
|
||||
|
||||
|
||||
def find_usage_paths(start: Optional[Path] = None) -> Tuple[Path, Path]:
|
||||
here = (start or Path(__file__)).resolve()
|
||||
for parent in (here.parent, *here.parents):
|
||||
for directory in (parent / "docs" / "gen", parent / "share" / "box64"):
|
||||
usage = directory / "usage.json"
|
||||
usage_cn = directory / "usage_cn.json"
|
||||
if usage.is_file() and usage_cn.is_file():
|
||||
return usage, usage_cn
|
||||
|
||||
raise FileNotFoundError("Could not find usage.json and usage_cn.json")
|
||||
|
||||
|
||||
def load_default_usage_catalog() -> UsageCatalog:
|
||||
if _EMBEDDED_USAGE_DATA is not None and _EMBEDDED_USAGE_CN_DATA is not None:
|
||||
return load_usage_catalog_from_data(_EMBEDDED_USAGE_DATA, _EMBEDDED_USAGE_CN_DATA)
|
||||
|
||||
usage_path, usage_cn_path = find_usage_paths()
|
||||
return load_usage_catalog(usage_path, usage_cn_path)
|
||||
|
||||
|
||||
def load_usage_catalog(usage_path: Path, usage_cn_path: Path) -> UsageCatalog:
|
||||
with usage_path.open("r", encoding="utf-8") as file:
|
||||
english_data = json.load(file)
|
||||
with usage_cn_path.open("r", encoding="utf-8") as file:
|
||||
chinese_data = json.load(file)
|
||||
return load_usage_catalog_from_data(english_data, chinese_data)
|
||||
|
||||
|
||||
def load_usage_catalog_from_data(
|
||||
english_data: Iterable[Dict[str, Any]], chinese_data: Dict[str, Any]
|
||||
) -> UsageCatalog:
|
||||
options: List[EnvOption] = []
|
||||
for entry in english_data:
|
||||
name = entry["name"]
|
||||
if not entry.get("configurator", False) and name not in ALWAYS_CONFIGURATOR_OPTIONS:
|
||||
continue
|
||||
|
||||
chinese_entry = chinese_data.get(name, {})
|
||||
chinese_choices = chinese_entry.get("options", {})
|
||||
choices = []
|
||||
|
||||
for option in entry.get("options", []):
|
||||
raw_key = str(option["key"])
|
||||
value = clean_choice_value(raw_key)
|
||||
choices.append(
|
||||
Choice(
|
||||
value=value,
|
||||
label="<empty>" if value == "" else value,
|
||||
description_en=option.get("description", ""),
|
||||
description_cn=chinese_choices.get(raw_key, ""),
|
||||
is_default=bool(option.get("default", False)),
|
||||
is_placeholder=is_placeholder_value(value),
|
||||
)
|
||||
)
|
||||
|
||||
options.append(
|
||||
EnvOption(
|
||||
name=name,
|
||||
description_en=entry.get("description", ""),
|
||||
description_cn=chinese_entry.get("description", ""),
|
||||
choices=tuple(choices),
|
||||
)
|
||||
)
|
||||
|
||||
return UsageCatalog(options)
|
||||
Vendored
+199
-189
@@ -1,168 +1,178 @@
|
||||
box64 (0.4.4) unstable; urgency=low
|
||||
|
||||
* This version adds a lot of refactor and speed improvements to the LoongArch backend, so more opcodes on the RISC-V backend, and many QoL new features!
|
||||
* => A new box64-configurator is now present (a python app) to help managing custom RCFILE profiles. It is available in both english and chinese.
|
||||
* => DynaCache is now enabled by default. It will compress the files and use up to 2GB of disk space.
|
||||
* => You can use box64-configurator on the special `[*]` profile to change default values
|
||||
* => More improvements on emulation accuracy that help running more DRM'd games
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Mon, 2 Aug 2026 10:30:33 -0100
|
||||
|
||||
box64 (0.4.2) unstable; urgency=low
|
||||
|
||||
This version add lots on unconnected new things, like a PPC64LE backend, Vulkan overlay support or more Dynarec finetunning.
|
||||
=> Vulkan x64 overlay support. That means using the linux version of Steam, Fossilize & GameOverlayUI will work.
|
||||
=> Many dynarec refactors, especialy on ARM64 & LA64 with fixes to speed regression introduced with the the last 2 releases and improved compatibility.
|
||||
=> Support for SteamRT3 & new Proton 11
|
||||
=> New PCC64LE in the work. Not finished, but should be usable already (but the platform seems to use a 64k pagesize by default, so compatibility will suffer on this platformm). Note that main Box64 mainteners don't have access to relevent hardware, so support will be limited.
|
||||
* This version add lots on unconnected new things, like a PPC64LE backend, Vulkan overlay support or more Dynarec finetunning.
|
||||
* => Vulkan x64 overlay support. That means using the linux version of Steam, Fossilize & GameOverlayUI will work.
|
||||
* => Many dynarec refactors, especialy on ARM64 & LA64 with fixes to speed regression introduced with the the last 2 releases and improved compatibility.
|
||||
* => Support for SteamRT3 & new Proton 11
|
||||
* => New PCC64LE in the work. Not finished, but should be usable already (but the platform seems to use a 64k pagesize by default, so compatibility will suffer on this platformm). Note that main Box64 mainteners don't have access to relevent hardware, so support will be limited.
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Mon, 20 Apr 2026 10:30:33 -0100
|
||||
-- Sebastien Chevalier <[email protected]> Mon, 20 Apr 2026 10:30:33 -0100
|
||||
|
||||
box64 (0.4.0) unstable; urgency=low
|
||||
|
||||
This version added many important refactors: the opcode prefix decoder for Dynarec, libGL and Vulkan, the FSGSBASE support, making segments handling easier and faster.
|
||||
=> Improved compatibility accross all architecture, allowing more DRM protected game to run
|
||||
=> the prefix refactor helped removed lots of redundant source file, simplifying maintenance
|
||||
=> BOX32 is getting more and more stable, even if still not 100% ok. But Steam is more stable than before, runs on all architecture. And some gameoverlay UI works, on OpenGL games. gameoverlay (and fossilize) support for Vulkan is planned for later.
|
||||
* This version added many important refactors: the opcode prefix decoder for Dynarec, libGL and Vulkan, the FSGSBASE support, making segments handling easier and faster.
|
||||
* => Improved compatibility accross all architecture, allowing more DRM protected game to run
|
||||
* => the prefix refactor helped removed lots of redundant source file, simplifying maintenance
|
||||
* => BOX32 is getting more and more stable, even if still not 100% ok. But Steam is more stable than before, runs on all architecture. And some gameoverlay UI works, on OpenGL games. gameoverlay (and fossilize) support for Vulkan is planned for later.
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Mon, 3 Jan 2026 10:30:33 -0100
|
||||
-- Sebastien Chevalier <[email protected]> Mon, 3 Jan 2026 10:30:33 -0100
|
||||
|
||||
box64 (0.3.8) unstable; urgency=low
|
||||
|
||||
This version introduce DynaCache, a disk cache for the generated native code. It's not enabled by default for now (but it will use cache file if present by default). It can dramaticaly speedup the load of program (try with linux factorio for example). This version also improve in the volatile metadata handling. There is a massive compatiblity improvment for box32 and on all dynarec in general too. And few more function wrapping...
|
||||
* This version introduce DynaCache, a disk cache for the generated native code. It's not enabled by default for now (but it will use cache file if present by default). It can dramaticaly speedup the load of program (try with linux factorio for example). This version also improve in the volatile metadata handling. There is a massive compatiblity improvment for box32 and on all dynarec in general too. And few more function wrapping...
|
||||
|
||||
=> DynaCache for faster loading of program, and avoid runtime hicups
|
||||
=> Batter box32 compatibility (much less "Out of Memory" error)
|
||||
=> Unity3D games on Wayland are working now
|
||||
=> Volatile Metadata fully supported and handled, making games like Starfield to just work.
|
||||
=> More work on AVX support for RV64 & LA64. LA64 almost there, while RV64 has Scalar only support (no hardware vector support yet for AVX)
|
||||
* => DynaCache for faster loading of program, and avoid runtime hicups
|
||||
* => Batter box32 compatibility (much less "Out of Memory" error)
|
||||
* => Unity3D games on Wayland are working now
|
||||
* => Volatile Metadata fully supported and handled, making games like Starfield to just work.
|
||||
* => More work on AVX support for RV64 & LA64. LA64 almost there, while RV64 has Scalar only support (no hardware vector support yet for AVX)
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Mon, 10 Oct 2025 10:30:33 -0100
|
||||
-- Sebastien Chevalier <[email protected]> Mon, 10 Oct 2025 10:30:33 -0100
|
||||
|
||||
box64 (0.3.6) unstable; urgency=low
|
||||
|
||||
This version introduces wowbox64.dll for Hangover; the ability to use the Volatile Metadata of Windows executables for x64 wine; and some better x87/SSE/AVX handling
|
||||
* This version introduces wowbox64.dll for Hangover; the ability to use the Volatile Metadata of Windows executables for x64 wine; and some better x87/SSE/AVX handling
|
||||
|
||||
=> WowBox64 can be built directly from Box64 repo, and can be found in the CI artifacts also
|
||||
=> it also supports a subset of BOX64_XXXX settings, which can be set from command line or via a setting file ".box64rc" in the Wine prefix home
|
||||
=> Volatile Metadata, when present, allows only applying strong memory ordering when needed, as marked by the compiler, giving overall better performances
|
||||
=> The precision control bit of x87 is now handled, allowing some older games to run correctly
|
||||
=> More work has been done in the handling of precise NaN and Round handling in SSE & AVX opcodes
|
||||
* => WowBox64 can be built directly from Box64 repo, and can be found in the CI artifacts also
|
||||
* => it also supports a subset of BOX64_XXXX settings, which can be set from command line or via a setting file ".box64rc" in the Wine prefix home
|
||||
* => Volatile Metadata, when present, allows only applying strong memory ordering when needed, as marked by the compiler, giving overall better performances
|
||||
* => The precision control bit of x87 is now handled, allowing some older games to run correctly
|
||||
* => More work has been done in the handling of precise NaN and Round handling in SSE & AVX opcodes
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 6 Jun 2025 10:30:33 -0100
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 6 Jun 2025 10:30:33 -0100
|
||||
|
||||
box64 (0.3.4) unstable; urgency=low
|
||||
|
||||
* This version is Faster and more compatible
|
||||
* => The RV64 backend got faster and more stable, with lots of RVV 1.0 / xThreadVector support to emulate SSE/SSE2+ opcode (no AVX yet)
|
||||
* => On ARM64, Box64 now support more DRM types than before.
|
||||
* => BOX32 can run steam now. At least on ARM64 backend, it's still not working on RV64 and LA64 for now.
|
||||
* Please check CHAGELOG.md for more details
|
||||
* This version is Faster and more compatible
|
||||
* => The RV64 backend got faster and more stable, with lots of RVV 1.0 / xThreadVector support to emulate SSE/SSE2+ opcode (no AVX yet)
|
||||
* => On ARM64, Box64 now support more DRM types than before.
|
||||
* => BOX32 can run steam now. At least on ARM64 backend, it's still not working on RV64 and LA64 for now.
|
||||
* Please check CHAGELOG.md for more details
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 10 Mar 2025 10:30:33 -0100
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 10 Mar 2025 10:30:33 -0100
|
||||
|
||||
box64 (0.3.2) unstable; urgency=low
|
||||
|
||||
* Introduced Box32 to run 32bits apps on 64bits OS
|
||||
* => Box32 is a build option for Box64, and is disabled by default
|
||||
* => Optionnal binfmt integration available for Box32
|
||||
* => Wrapped some basics libs, including graphics and sounds so a few games already works
|
||||
* => Work In Progress, many issues remain to be fixed, but some Linux games are playable
|
||||
* Introduced Native Flags. Can be controled with BOX64_DYNAREC_NATIVEFLAGS, but enabled by default
|
||||
* => Available on the 3 Dynarec backend, with different implementations
|
||||
* => ARM64 Dynarec build have all AVX/AVX2 extensions enabled by default
|
||||
* +> Can lead to large speedup on certain cases
|
||||
* Improved Strong Memory Model emulation, with better default options and a more efficiant emulation
|
||||
* Dynarec: RV64: using RVV (and XThreadVector) to implement SSEx opcodes, with some massive speedup when used!
|
||||
* Some bugfix and improvment in the Signal handler and internal memory tracking
|
||||
* Improvment to TRAP signal generation and Handling
|
||||
* Improved CPUID opcodes again, and the various virtual file in /proc that represent those data
|
||||
* Improved some x87 operations, like long double handling and infinity comparisons...
|
||||
* Dynarec: ARM64 fixes to a few opcodes
|
||||
* Dynarec: RV64 fixes to many opcodes
|
||||
* Dynarec: LA64 fixes to a few opcodes
|
||||
* Dynarec: RV64 fixes and improvments on LOCK prefixes opcodes
|
||||
* Dynarec: Many optimisation on some individual opcodes, an all 3 backends
|
||||
* WRAPPING: More libs and functions wrapped. Some wrapping fixes too
|
||||
* WREPPING: New wrapperhelper to help coding new wrapping & fixing/enhancing existing one
|
||||
* ElfLoader: Improved object fetching
|
||||
* New build profile for SD865 and ORYON
|
||||
* Changed the installation folder of x86 libs to avoid conflict with linux distro
|
||||
* Added a few syscalls
|
||||
* Some more Vulkan extensions wrapped
|
||||
* More work on build system, and github CI (generating WCP archive), with some fixes on the Android version (still not 100% operational)
|
||||
* 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
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 6 Dec 2024 10:30:33 -0100
|
||||
|
||||
box64 (0.3.0) unstable; urgency=low
|
||||
|
||||
* AVX and AVX2 implemented, along with BMI1, BMI2, ADX, FMA, F16C and RDANDR extension!
|
||||
* Introduced BOX64_AVX env. var. to enable/disable AVX extension:
|
||||
* => BOX64_AVX=1 enable AVX, BMI1, F16C and VAES extension
|
||||
* => BOX64_AVX=2 also enable AVX2, BMI2, FMA, ADX,VPCLMULQDQ and RDRAND
|
||||
* Dynarec: Implemented most AVX/AVX2 and friends in ARM64 Dynarec (using only NEON, so available on all ARM64 CPU)
|
||||
* => ARM64 Dynarec build have all AVX/AVX2 extensions enabled by default
|
||||
* Improved CPUID opcodes, adding a few leaf, fixing same. Returnning an Haswell type of CPU now (was Pentium IV before)
|
||||
* Dynarec: Small optim in the emit_pf helper, on all 3 backends
|
||||
* Dynarec: ARM64 some fixes to a few opcodes
|
||||
* Dynarec: LA64 many new opcodes added, and fixes.
|
||||
* Dynarec: RV64 some new opcodes added, many fixes.
|
||||
* Dynarec: RV64 Adding some infrastructure to use RVV (if available) for SIMD emulation.
|
||||
* Dynarec: Many small changes and fixes around handling of x87, registers and internal jump.
|
||||
* WRAPPING: Added a workaround on SDL_GetThreadID to fix a race condition that was happening mostly on LA64 and broke many SDL games
|
||||
* WRAPPING: More libs and functions wrapped. Some wrapping fixes too (including a nasty error on some rare libGL functions)
|
||||
* WRAPPING: Wayland is now supported. Wine-wayland at least works now
|
||||
* Dynarec: LA64 improved LOCK CMPXCHG handling, and better 16Byte LOCK handling too (fixes many Unity3D games)
|
||||
* Dynarec: RV64 improved LOCK CMPXCHG handling
|
||||
* COSIM: Many fixes and improvment, to make BOX64_DYNAREC_TEST more usable
|
||||
* Detect when a Wine program use UnityPlayer.dll to atumaticaly use BOX64_DYNAREC_STRONGMEM=1 (unless it's already set), so more games just work
|
||||
* ElfLoader: Added a new type of relocation
|
||||
* AVX and AVX2 implemented, along with BMI1, BMI2, ADX, FMA, F16C and RDANDR extension!
|
||||
* Introduced BOX64_AVX env. var. to enable/disable AVX extension:
|
||||
* => BOX64_AVX=1 enable AVX, BMI1, F16C and VAES extension
|
||||
* => BOX64_AVX=2 also enable AVX2, BMI2, FMA, ADX,VPCLMULQDQ and RDRAND
|
||||
* Dynarec: Implemented most AVX/AVX2 and friends in ARM64 Dynarec (using only NEON, so available on all ARM64 CPU)
|
||||
* => ARM64 Dynarec build have all AVX/AVX2 extensions enabled by default
|
||||
* Improved CPUID opcodes, adding a few leaf, fixing same. Returnning an Haswell type of CPU now (was Pentium IV before)
|
||||
* Dynarec: Small optim in the emit_pf helper, on all 3 backends
|
||||
* Dynarec: ARM64 some fixes to a few opcodes
|
||||
* Dynarec: LA64 many new opcodes added, and fixes.
|
||||
* Dynarec: RV64 some new opcodes added, many fixes.
|
||||
* Dynarec: RV64 Adding some infrastructure to use RVV (if available) for SIMD emulation.
|
||||
* Dynarec: Many small changes and fixes around handling of x87, registers and internal jump.
|
||||
* WRAPPING: Added a workaround on SDL_GetThreadID to fix a race condition that was happening mostly on LA64 and broke many SDL games
|
||||
* WRAPPING: More libs and functions wrapped. Some wrapping fixes too (including a nasty error on some rare libGL functions)
|
||||
* WRAPPING: Wayland is now supported. Wine-wayland at least works now
|
||||
* Dynarec: LA64 improved LOCK CMPXCHG handling, and better 16Byte LOCK handling too (fixes many Unity3D games)
|
||||
* Dynarec: RV64 improved LOCK CMPXCHG handling
|
||||
* COSIM: Many fixes and improvment, to make BOX64_DYNAREC_TEST more usable
|
||||
* Detect when a Wine program use UnityPlayer.dll to atumaticaly use BOX64_DYNAREC_STRONGMEM=1 (unless it's already set), so more games just work
|
||||
* ElfLoader: Added a new type of relocation
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 9 Jul 2024 10:30:33 -0100
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 9 Jul 2024 10:30:33 -0100
|
||||
|
||||
box64 (0.2.8) unstable; urgency=low
|
||||
|
||||
* Wrapping: More libs and function wrapping (gtk3, vulkan...)
|
||||
* Reworked X11 Callback handling, for better stability
|
||||
* Reworked exit and the load/unload of libs and symbol resolution
|
||||
* Some more profiles in box64rc
|
||||
* Better way to rename executable (including wine ones) so driver like mesa can apply the correct profile
|
||||
* Reworked memory managment in the Dynarec, limiting amount of dynamic allocation
|
||||
* Improved memory tracking and managment. Also introduce BOX64_MMAP32 to force 32bits compatible mmap for external libs (like mesa)
|
||||
* => Allow Vulkan drvier on Wine/WOW64 games to allocate 32bits compatible memory, allowing dxvk on 32bits.
|
||||
* Reworked memory managment in the Dynarec, limiting amount of dynamic allocation
|
||||
* Lots of improvments in x87 handling (virtual stack, rounding, ffree, etc.)
|
||||
* => should improve games stability
|
||||
* Dynarec: ARM64 some opcodes optimisation, especialy shift and rotation ones
|
||||
* Dynarec: RV64 lots of opcoded added.
|
||||
* => Some games on linux now have a good speed. Game on Wine are still a bit slow, and dxvk still have issues
|
||||
* Dynarec: Added Loogarch backend! Note that Loongarch are 16K pagesize platform by default.
|
||||
* => Linux games are running, and with good speed, especialy on 3A6000 platforms. Games on Wine are not working yet due to 16k pagesize limitation
|
||||
* Dynarec: Better handling of large block in the dynarec
|
||||
* Dynarec: Lots of improvments and fixes to BOX86_DYNAREC_CALLRET optimisation.
|
||||
* => It can be used on more software now, and combine with BOX64_DYNAREC_BOGBLOCKS 2 or 3 can gives some good speed boosts.
|
||||
* Wrapping: More libs and function wrapping (gtk3, vulkan...)
|
||||
* Reworked X11 Callback handling, for better stability
|
||||
* Reworked exit and the load/unload of libs and symbol resolution
|
||||
* Some more profiles in box64rc
|
||||
* Better way to rename executable (including wine ones) so driver like mesa can apply the correct profile
|
||||
* Reworked memory managment in the Dynarec, limiting amount of dynamic allocation
|
||||
* Improved memory tracking and managment. Also introduce BOX64_MMAP32 to force 32bits compatible mmap for external libs (like mesa)
|
||||
* => Allow Vulkan drvier on Wine/WOW64 games to allocate 32bits compatible memory, allowing dxvk on 32bits.
|
||||
* Reworked memory managment in the Dynarec, limiting amount of dynamic allocation
|
||||
* Lots of improvments in x87 handling (virtual stack, rounding, ffree, etc.)
|
||||
* => should improve games stability
|
||||
* Dynarec: ARM64 some opcodes optimisation, especialy shift and rotation ones
|
||||
* Dynarec: RV64 lots of opcoded added.
|
||||
* => Some games on linux now have a good speed. Game on Wine are still a bit slow, and dxvk still have issues
|
||||
* Dynarec: Added Loogarch backend! Note that Loongarch are 16K pagesize platform by default.
|
||||
* => Linux games are running, and with good speed, especialy on 3A6000 platforms. Games on Wine are not working yet due to 16k pagesize limitation
|
||||
* Dynarec: Better handling of large block in the dynarec
|
||||
* Dynarec: Lots of improvments and fixes to BOX86_DYNAREC_CALLRET optimisation.
|
||||
* => It can be used on more software now, and combine with BOX64_DYNAREC_BOGBLOCKS 2 or 3 can gives some good speed boosts.
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 31 May 2024 17:30:33 -0100
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 31 May 2024 17:30:33 -0100
|
||||
|
||||
box64 (0.2.6) unstable; urgency=low
|
||||
|
||||
* X64Libs: Updated libstdc++ & libgcc_s
|
||||
* X64Libs: Use x86_64 vrsion of libunwind (it's needed by wine)
|
||||
* Dynarec: More opcodes on ARM64 & RV64
|
||||
* Dynarec: Fixed some flags propagation issues inside blocks
|
||||
* Dynarec: Improved Strong Memory Model emulation, introducing a 3rd level
|
||||
* Dynarec: ARM64: reworked shift and bit opcodes flags handling
|
||||
* Dynarec: RV64: Many fixes, making Wow64 apps running
|
||||
* Dynarec: ARM64: Added support for SSE4.2 (with CRC32 if supported by CPU)
|
||||
* Dynarec: ARM64: Added support for SHA (with hardware support if CPU allows it)
|
||||
* Dynarec: ARM64: The CALLRET optimisation has been improved and is now default
|
||||
* CPU: Remoworked how INT, priviliged opcodes and teh Trace flags works
|
||||
* CPU: Added full support for SSE4.2
|
||||
* CPU: Added full support for SHA extension
|
||||
* ElfLoader: rework how elf memory is handled
|
||||
* Emulation: Added some more syscalls
|
||||
* Emulation: Better handling of Signal (also handling SIGMAX correctly)
|
||||
* Emulation: Better support for POKEUSER/PEEKUSER (helps Windows Unity games)
|
||||
* Wrapping: More libs and some fixes in function wrapping (gtk3, vulkan...)
|
||||
* Wrapping: Removed faked libunwind wrapping
|
||||
* Hardware: Added more profile, with support ADLink Ampere Altra, Qualcomm 8Gen3, and Pi5 machines
|
||||
* OS: Added profile to build for Android and Termux.
|
||||
* OS: New option to use mold for a high speed link
|
||||
* => More hadware support, more functions wrapped for an improve compatibity
|
||||
* => More CPU extension, with ARM64 hardware support when possible, and improved CALLRET optimisation for an improved speed of emulation
|
||||
* => Some work also to reduce the memory footprint
|
||||
* X64Libs: Updated libstdc++ & libgcc_s
|
||||
* X64Libs: Use x86_64 vrsion of libunwind (it's needed by wine)
|
||||
* Dynarec: More opcodes on ARM64 & RV64
|
||||
* Dynarec: Fixed some flags propagation issues inside blocks
|
||||
* Dynarec: Improved Strong Memory Model emulation, introducing a 3rd level
|
||||
* Dynarec: ARM64: reworked shift and bit opcodes flags handling
|
||||
* Dynarec: RV64: Many fixes, making Wow64 apps running
|
||||
* Dynarec: ARM64: Added support for SSE4.2 (with CRC32 if supported by CPU)
|
||||
* Dynarec: ARM64: Added support for SHA (with hardware support if CPU allows it)
|
||||
* Dynarec: ARM64: The CALLRET optimisation has been improved and is now default
|
||||
* CPU: Remoworked how INT, priviliged opcodes and teh Trace flags works
|
||||
* CPU: Added full support for SSE4.2
|
||||
* CPU: Added full support for SHA extension
|
||||
* ElfLoader: rework how elf memory is handled
|
||||
* Emulation: Added some more syscalls
|
||||
* Emulation: Better handling of Signal (also handling SIGMAX correctly)
|
||||
* Emulation: Better support for POKEUSER/PEEKUSER (helps Windows Unity games)
|
||||
* Wrapping: More libs and some fixes in function wrapping (gtk3, vulkan...)
|
||||
* Wrapping: Removed faked libunwind wrapping
|
||||
* Hardware: Added more profile, with support ADLink Ampere Altra, Qualcomm 8Gen3, and Pi5 machines
|
||||
* OS: Added profile to build for Android and Termux.
|
||||
* OS: New option to use mold for a high speed link
|
||||
* => More hadware support, more functions wrapped for an improve compatibity
|
||||
* => More CPU extension, with ARM64 hardware support when possible, and improved CALLRET optimisation for an improved speed of emulation
|
||||
* => Some work also to reduce the memory footprint
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 15 Dec 2023 17:30:33 -0100
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 15 Dec 2023 17:30:33 -0100
|
||||
|
||||
box64 (0.2.4) unstable; urgency=low
|
||||
|
||||
@@ -189,74 +199,74 @@ box64 (0.2.4) unstable; urgency=low
|
||||
* => Dynarec now support RISC-V, large speedup on RISC-V 64, were games are now playable (like Stardew Valley on a Vision Five 2)
|
||||
* => Improved compatibility with more fixes in elf handling, more wrapped libs and functiond, more fixed opcodes and refined profile
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 10 Mar 2023 10:20:33 -0500
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 10 Mar 2023 10:20:33 -0500
|
||||
|
||||
box64 (0.2.2) unstable; urgency=low
|
||||
|
||||
* Added a hacked version for overridden malloc/free functions, enabling libcef (and derivative) to work.
|
||||
* Added rcfile handling: box64 now read "/etc/box64.box64rc" and "~/.box64rc" and apply per process parameters
|
||||
* Added BOX64_DYNAREC_CALLRET to optimized CALL/RET opcode using semi-direct native CALL/RET (get more than 10% speedup)
|
||||
* Added BOX64_DYNAREC_FORWARD to allow bigger Dynarec block to be build (can get more then 30% of Speedup!)
|
||||
* Improved memory protection tracking and signal handling, again
|
||||
* Simplified mutex handling (faster, cleaner)
|
||||
* Reduce memory used by the memory tracking (memory almost divide by 4 is some critical use case)
|
||||
* Added d3dadaptor9 wrapping
|
||||
* More wrapped libs (especially on the gtk familly)
|
||||
* Improved/fixed some Syscall handling
|
||||
* Refactored Strong Memory Model emulation (faster and more accurate)
|
||||
* Added some more opcode to ARM64 Dynarec, and fixed some other
|
||||
* Some fixes to flags handling in the Dynarec on some special cases
|
||||
* Refactor library loading/unloading, with refcount.
|
||||
* Some special cases fixes for dlopen (fixes deadcells, maybe others too)
|
||||
* Improved mmap mapping, espcially with MAP_32BITS flag
|
||||
* More wrapped functions and syscalls
|
||||
* Lots of improvment in the Rounding of float & double (Dynarec and Interpreter), and proper handling of denormals when converting to/from 80 bits long double
|
||||
* Added specific suppport for RK3588 board (needed some hack in signal handling, probably due to the use of a non mainlined kernel)
|
||||
* More support on the RV64 port
|
||||
* More support to build under musl environment
|
||||
* Added a hacked version for overridden malloc/free functions, enabling libcef (and derivative) to work.
|
||||
* Added rcfile handling: box64 now read "/etc/box64.box64rc" and "~/.box64rc" and apply per process parameters
|
||||
* Added BOX64_DYNAREC_CALLRET to optimized CALL/RET opcode using semi-direct native CALL/RET (get more than 10% speedup)
|
||||
* Added BOX64_DYNAREC_FORWARD to allow bigger Dynarec block to be build (can get more then 30% of Speedup!)
|
||||
* Improved memory protection tracking and signal handling, again
|
||||
* Simplified mutex handling (faster, cleaner)
|
||||
* Reduce memory used by the memory tracking (memory almost divide by 4 is some critical use case)
|
||||
* Added d3dadaptor9 wrapping
|
||||
* More wrapped libs (especially on the gtk familly)
|
||||
* Improved/fixed some Syscall handling
|
||||
* Refactored Strong Memory Model emulation (faster and more accurate)
|
||||
* Added some more opcode to ARM64 Dynarec, and fixed some other
|
||||
* Some fixes to flags handling in the Dynarec on some special cases
|
||||
* Refactor library loading/unloading, with refcount.
|
||||
* Some special cases fixes for dlopen (fixes deadcells, maybe others too)
|
||||
* Improved mmap mapping, espcially with MAP_32BITS flag
|
||||
* More wrapped functions and syscalls
|
||||
* Lots of improvment in the Rounding of float & double (Dynarec and Interpreter), and proper handling of denormals when converting to/from 80 bits long double
|
||||
* Added specific suppport for RK3588 board (needed some hack in signal handling, probably due to the use of a non mainlined kernel)
|
||||
* More support on the RV64 port
|
||||
* More support to build under musl environment
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 10 Mar 2023 10:20:33 -0500
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 10 Mar 2023 10:20:33 -0500
|
||||
|
||||
box64 (0.2.0) unstable; urgency=low
|
||||
|
||||
* Wrapped more vulkan function, dxvk 2.0 now works
|
||||
* Added support for overridden malloc/free functions
|
||||
* Refactor Dynarec memory management, reducing memory footprint (from 20% to 40% of Dynarec size)
|
||||
* Improved elf loader
|
||||
* Improved dlsym handling with RTLD_NEXT
|
||||
* Added BOX64_DYNAREC_SAFEFLAGS to allow finetuning Dynarec generated code handling of flags accross function calls and returns.
|
||||
* Added BOX64_BASH to setup x86_64 bash binary, so shell script can be run in x86_64 world
|
||||
* Added BOX64_ROLLING_LOG to have details log only on crash
|
||||
* Work on alignment for some of pthread structures
|
||||
* More wrapped libraries in the gtk family
|
||||
* Some fixes on the Dynarec x87 code (fixing a bunch of games like ut2004 or Piczle Puzzle)
|
||||
* Improved TLS Size handling (Unity3D games now works)
|
||||
* More PageSize Compile options
|
||||
* Improved execv family of function to have better box64 integration
|
||||
* Added support for wrapped libfuse so AppImage works
|
||||
* Adjusted the binfmt integration so AppImage are automaticaly picked
|
||||
* Improved FAudio, SDL2, GL (and more) wrapping
|
||||
* More wrapped libs, like libEGL.so, to helps emulated Qt4/5 libs to load
|
||||
* Improved Signal Handling and memory protection traking
|
||||
* Some signature fixes to some wrapped functions (in libc)
|
||||
* Added more syscalls
|
||||
* Added a lot of new opcodes to the ARM64 Dynarec
|
||||
* docs: add instructions for Debian-based Linux by @ryanfortner in #306
|
||||
* Fix typos and arch type string by @archanox in #321
|
||||
* Fix grammar by @Jai-JAP in #326
|
||||
* Enable 64k page size by @martinmanyhats in #334
|
||||
* Align address when call mprotect by @wannacu in #336
|
||||
* Add wrapped functions needed for 'ls -l'. by @stiltr in #294
|
||||
* add 18.04 tegra X1 github actions by @theofficialgman in #345
|
||||
* change order of matrix (to preview better under checkmark dropdown by @theofficialgman in #346
|
||||
* Backport SDL_DYNAPI_entry wrapper from box86. by @JohnnyonFlame in #374
|
||||
* Add SW64 base support by @wannacu in #382
|
||||
* fix overzealous replace in wrappers pathnames by @NobodyNada in #415
|
||||
* Create X64WINE.md by @WheezyE in #423
|
||||
* src: asm: Rename lr & fp registers to their x-equivalents by @fredldotme in #426
|
||||
* Malloc override by @ptitSeb in #437
|
||||
* Remove dynablocklist by @ptitSeb in #438
|
||||
* Fix Pkgbuilds by @Jai-JAP in #452
|
||||
* Wrapped more vulkan function, dxvk 2.0 now works
|
||||
* Added support for overridden malloc/free functions
|
||||
* Refactor Dynarec memory management, reducing memory footprint (from 20% to 40% of Dynarec size)
|
||||
* Improved elf loader
|
||||
* Improved dlsym handling with RTLD_NEXT
|
||||
* Added BOX64_DYNAREC_SAFEFLAGS to allow finetuning Dynarec generated code handling of flags accross function calls and returns.
|
||||
* Added BOX64_BASH to setup x86_64 bash binary, so shell script can be run in x86_64 world
|
||||
* Added BOX64_ROLLING_LOG to have details log only on crash
|
||||
* Work on alignment for some of pthread structures
|
||||
* More wrapped libraries in the gtk family
|
||||
* Some fixes on the Dynarec x87 code (fixing a bunch of games like ut2004 or Piczle Puzzle)
|
||||
* Improved TLS Size handling (Unity3D games now works)
|
||||
* More PageSize Compile options
|
||||
* Improved execv family of function to have better box64 integration
|
||||
* Added support for wrapped libfuse so AppImage works
|
||||
* Adjusted the binfmt integration so AppImage are automaticaly picked
|
||||
* Improved FAudio, SDL2, GL (and more) wrapping
|
||||
* More wrapped libs, like libEGL.so, to helps emulated Qt4/5 libs to load
|
||||
* Improved Signal Handling and memory protection traking
|
||||
* Some signature fixes to some wrapped functions (in libc)
|
||||
* Added more syscalls
|
||||
* Added a lot of new opcodes to the ARM64 Dynarec
|
||||
* docs: add instructions for Debian-based Linux by @ryanfortner in #306
|
||||
* Fix typos and arch type string by @archanox in #321
|
||||
* Fix grammar by @Jai-JAP in #326
|
||||
* Enable 64k page size by @martinmanyhats in #334
|
||||
* Align address when call mprotect by @wannacu in #336
|
||||
* Add wrapped functions needed for 'ls -l'. by @stiltr in #294
|
||||
* add 18.04 tegra X1 github actions by @theofficialgman in #345
|
||||
* change order of matrix (to preview better under checkmark dropdown by @theofficialgman in #346
|
||||
* Backport SDL_DYNAPI_entry wrapper from box86. by @JohnnyonFlame in #374
|
||||
* Add SW64 base support by @wannacu in #382
|
||||
* fix overzealous replace in wrappers pathnames by @NobodyNada in #415
|
||||
* Create X64WINE.md by @WheezyE in #423
|
||||
* src: asm: Rename lr & fp registers to their x-equivalents by @fredldotme in #426
|
||||
* Malloc override by @ptitSeb in #437
|
||||
* Remove dynablocklist by @ptitSeb in #438
|
||||
* Fix Pkgbuilds by @Jai-JAP in #452
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 17 Nov 2022 11:20:33 -0500
|
||||
|
||||
|
||||
+35
-5
@@ -4,9 +4,39 @@ The script `box64-bundle-x86-libs.sh` is provided to download, extract, and re-b
|
||||
|
||||
## Usage
|
||||
|
||||
### User
|
||||
|
||||
Add `--debug` to any command to log every command that is run, along with every file that `tar`, `cpio`, and `unzip` handle. Without it, `--build` is silent unless it fails.
|
||||
|
||||
Install the bundle from the latest [GitHub release](https://github.com/ptitSeb/box64/releases/latest). This only requires `coreutils`, `curl`, and `tar`.
|
||||
|
||||
```
|
||||
sudo ./box64-bundle-x86-libs.sh --install
|
||||
```
|
||||
|
||||
The bundle can also be installed as part of a Box64 installation by turning on the `BUNDLE_X86_LIBS` option. It is off by default. From the `build` directory of a [compiled Box64](COMPILE.md):
|
||||
|
||||
```
|
||||
cmake .. -D BUNDLE_X86_LIBS=ON
|
||||
make -j4
|
||||
sudo make install
|
||||
```
|
||||
|
||||
Optionally set the environment variable `DESTDIR` to extract to a different location than `/`.
|
||||
|
||||
```
|
||||
DESTDIR=/tmp/box64 ./box64-bundle-x86-libs.sh --install
|
||||
```
|
||||
|
||||
```
|
||||
make install DESTDIR=/tmp/box64
|
||||
```
|
||||
|
||||
The checksums of the latest release are compared to the local files first. If every file matches, nothing is downloaded. If at least one file is missing or different, the whole bundle is downloaded, extracted, and then verified.
|
||||
|
||||
### Administrator
|
||||
|
||||
Install required dependencies for the bundle script.
|
||||
Build the bundle from Linux distribution packages. Install the required dependencies for the bundle script.
|
||||
|
||||
- Arch Linux
|
||||
```
|
||||
@@ -23,11 +53,11 @@ Install required dependencies for the bundle script.
|
||||
sudo dnf install binutils coreutils curl tar zstd
|
||||
```
|
||||
|
||||
Run `box64-bundle-x86-libs.sh`. This will create two archives:
|
||||
Run `box64-bundle-x86-libs.sh --build`. This will create two archives:
|
||||
- `box64-bundle-x86-libs.tar.gz` = All of the extracted library files in the directory structure of `usr/lib/box64-i386-linux-gnu` and `usr/lib/box64-x86_64-linux-gnu`.
|
||||
- `box64-bundle-x86-pkgs.tar.gz` = All of the Linux distribution packages used to extract the library files. This is only created for preservation purposes and is otherwise unused.
|
||||
|
||||
Extract the library archive. Box will automatically search these paths for library files to emulate.
|
||||
Extract the library archive manually. Box will automatically search these paths for library files to emulate.
|
||||
|
||||
```
|
||||
sudo tar --extract --no-same-owner --file box64-bundle-x86-libs.tar.gz --directory /
|
||||
@@ -48,13 +78,13 @@ Preference of operating system packages that provide a library:
|
||||
2. DEBs from Debian 11 provide 5 years of updates.
|
||||
3. EOPKG from Solus provide old variants of obscure 32-bit libraries.
|
||||
4. XBPS from Void Linux provide updated variants of obscure 32-bit libraries.
|
||||
5. Other (whereever a library is packaged)
|
||||
5. Other (wherever a library is packaged)
|
||||
|
||||
Some essential libraries will always be emulated and should be bundled. The full list can be found in the [in the core source code](https://github.com/ptitSeb/box64/blob/v0.4.0/src/core.c#L413).
|
||||
|
||||
Some essential library files will never be emulated (only natively wrapped instead) and should not be bundled. This includes glibc, OpenGL, Vulkan, and X11/Xorg libraries. The full list can be found [in the library source code](https://github.com/ptitSeb/box64/blob/v0.4.0/src/librarian/library.c#L440). Other libraries with lots of dependencies, such as GTK, require all dependencies to be installed for emulation to work. This becomes dependency hell and should be avoided.
|
||||
|
||||
For finding package names that contian a specific library file, use the [pkgs.org website](https://pkgs.org/). Otherwise, use one of these package manager commands on a x86_64 Linux distribution:
|
||||
For finding package names that contain a specific library file, use the [pkgs.org website](https://pkgs.org/). Otherwise, use one of these package manager commands on a x86_64 Linux distribution:
|
||||
- DEB
|
||||
- `apt-file <LIBRARY_FILE>`
|
||||
- EOPKG
|
||||
|
||||
@@ -1,3 +1,64 @@
|
||||
v0.4.4
|
||||
======
|
||||
|
||||
Highlights:
|
||||
* This version adds a lot of refactor and speed improvements to the LoongArch backend, so more opcodes on the RISC-V backend, and many QoL new features!
|
||||
=> A new box64-configurator is now present (a python app) to help managing custom RCFILE profiles. It is available in both english and chinese.
|
||||
=> DynaCache is now enabled by default. It will compress the files and use up to 2GB of disk space.
|
||||
=> You can use box64-configurator on the special `[*]` profile to change default values
|
||||
=> More improvements on emulation accuracy that help running more DRM'd games
|
||||
|
||||
Version summary:
|
||||
|
||||
* RCFILE: Created a new GUI tools to edit custom rcfile: box64-configurator
|
||||
* RCFILE: Created a KDE plugin to quickly set box64 properties for an executable file
|
||||
* RCFILE: Added more profiles
|
||||
* RCFILE: Added BOX64_SKIPCPU to avoid using N first cores (for big.LITTLE configuration)
|
||||
* ELF: Some more Relocation handling
|
||||
* Wrapping: Improved MALLOC_HACK=2 behaviour
|
||||
* Wrapping: more fixes to some functions signatures
|
||||
* Wrapping: added more wrapped functions
|
||||
* Wrapping: added some more wrapped libraries
|
||||
* Wrapping: Added more Syscall
|
||||
* Wrapping: Some rework on the bridges to avoid unexpected reuse of bridges for different function signature
|
||||
* Wrapping: Box32: Some fixes and improvement on some wrapped functions
|
||||
* Emulation: Some improvement on handling of x87 80bits values
|
||||
* Emulation: Added some deferred signal support for improved stability
|
||||
* Emulation: Improved TF handling
|
||||
* Emulation: Improved CPUID handling
|
||||
* Emulation: optimised some sha1 function
|
||||
* Emulation: LA64: Enabled AVX by default (on par with ARM64)
|
||||
* Interpreter: A few fixes in some opcodes
|
||||
* Interpreter: Added unaligned handling of more lock opcodes
|
||||
* DynaCache: many improvements and fixes
|
||||
* DynaCache: added libz compression of the dynacache files
|
||||
* DynaCache: added disk size limit, to purge old/outdated dynacache once a threshold is reached
|
||||
* Dynarec: Many small opcodes optimisation here and there
|
||||
* Dynarec: Some improvement on handling of x87 80bits values
|
||||
* Dynarec: Optimised the internal jump handling while building a dynablock
|
||||
* Dynarec: Improved TF handling
|
||||
* Dynarec: Reworked Alt Address handling
|
||||
* Dynarec: Reworked a bit the jump table to save some memory
|
||||
* Dynarec: Made BOX64_CALLRET=2 default
|
||||
* Dynarec: ARM64: Some improvement in some x87 opcodes handling
|
||||
* Dynarec: ARM64: A few fixes to some opcodes
|
||||
* Dynarec: LA64: Added optimisation on the zeroing out of the upper 32 bits of registers
|
||||
* Dynarec: LA64: Added a Dynarec version of UpdateFlags (on par with ARM64)
|
||||
* Dynarec: LA64: More work FASTNAN / FASTROUND handling
|
||||
* Dynarec: LA64: Many fixes on many opcodes
|
||||
* Dynarec: LA64: Added a few opcodes
|
||||
* Dynarec: LA64: Added fastpath on many logical opcodes (when no flags are needed)
|
||||
* Dynarec: LA64: AES opcodes optimisations
|
||||
* Dynarec: LA64: Improved Native flags use for more cases
|
||||
* Dynarec: LA64: Improved jump_safe macro (removing many useless NOP)
|
||||
* Dynarec: RV64: Improvement on flags handling (on par with ARM64 & LA64)
|
||||
* Dynarec: RV64: Many fixes on NaN handling
|
||||
* Dynarec: RV64: Some fixes to various opcodes
|
||||
* Dynarec: RV64: Improved Native Flags handling
|
||||
* Dynarec: RV64: Added some opcodes
|
||||
* Dynarec: RV64: Detect and use the new Zicbop/Zicond/Zicbom cpu extension when available
|
||||
* WrapperHelper: some more improvements and fixes
|
||||
|
||||
v0.4.2
|
||||
======
|
||||
|
||||
|
||||
+13
-12
@@ -3,7 +3,7 @@ Compiling/Installing
|
||||
|
||||
If you don't want to compile box64 yourself and prefer to use third-party pre-build version, go to the [end of the document](#pre-built-packages) for alternatives.
|
||||
|
||||
You can also generate your own package using the [instructions below](https://github.com/ptitSeb/box64/blob/main/docs/COMPILE.md#debian-packaging).
|
||||
You can also generate your own package using the [instructions below](https://github.com/ptitSeb/box64/blob/main/docs/COMPILE.md#debian-packaging).
|
||||
|
||||
Additional installation steps may be necessary when copying only the box64 executable file without running make install in cross-build environments. See [Cross-Compiling](https://github.com/ptitSeb/box64/blob/main/docs/COMPILE.md#Cross-Compiling)
|
||||
|
||||
@@ -15,7 +15,7 @@ Additional installation steps may be necessary when copying only the box64 execu
|
||||
git clone https://github.com/ptitSeb/box64
|
||||
cd box64
|
||||
mkdir build; cd build; cmake .. ${OPTIONS}
|
||||
make -j4
|
||||
make -j4
|
||||
sudo make install
|
||||
```
|
||||
If it's the first install, you also need:
|
||||
@@ -32,8 +32,9 @@ If you also want binfmt integration on 32bits binaries, you also need to add `-D
|
||||
|
||||
### Note about WowBox64
|
||||
|
||||
A highly experimantal subproject named WowBox64 has been added as a build option, add `-DWOW64=ON` to the cmake command to enable it.
|
||||
An experimantal subproject named WowBox64 has been added as a build option, add `-DWOW64=ON` to the cmake command to enable it.
|
||||
It will build alongside the regular Box64, and produce a `wowbox64.dll` file in `build/wowbox64-prefix/src/wowbox64-build/` directory.
|
||||
You can also add ̀`-DNOOX64=ON` to not build the main box64 binary to save compilation time if you plan to only use the wowbox64 dll.
|
||||
|
||||
### Note about binfmt_misc on Android
|
||||
|
||||
@@ -288,13 +289,13 @@ To have a trace enabled build (***the interpreter will be slightly slower***), a
|
||||
|
||||
#### Build DynaRec
|
||||
|
||||
Add `-D ARM_DYNAREC=ON` option to enable DynaRec on ARM machines.
|
||||
Add `-D RV64_DYNAREC=ON` option to enable DynaRec on RV64 machines.
|
||||
Add `-D LARCH64_DYNAREC=ON` option to enable DynaRec on LARCH64 machines.
|
||||
Add `-D ARM_DYNAREC=ON` option to enable DynaRec on ARM machines.
|
||||
Add `-D RV64_DYNAREC=ON` option to enable DynaRec on RV64 machines.
|
||||
Add `-D LARCH64_DYNAREC=ON` option to enable DynaRec on LARCH64 machines.
|
||||
|
||||
#### Save memory at run time
|
||||
|
||||
You can use `-DSAVE_MEM` to have a build that will try to save some memory. For now, it only increases the jumptable from 4 levels to 5. The added granularity avoids wasting space, but adds one more read from memory when jumping between blocks.
|
||||
You can use `-DSAVE_MEM=ON` to build Box64 with memory-saving optimizations. This uses a five-level jump table to reduce unused address-space allocations, which may reduce memory usage at the cost of additional memory accesses and lower performance on some workloads.
|
||||
|
||||
#### Build outside of a git repo
|
||||
|
||||
@@ -326,9 +327,9 @@ Box64 can also be packaged into a .deb file ***using the source code zip from th
|
||||
|
||||
## Pre-built packages
|
||||
|
||||
### Debian-based Linux
|
||||
### Debian-based Linux
|
||||
|
||||
You can use the [Pi-Apps-Coders apt repository](https://github.com/Pi-Apps-Coders/box64-debs) to install precompiled box64 debs, updated every 24 hours.
|
||||
You can use the [Pi-Apps-Coders apt repository](https://github.com/Pi-Apps-Coders/box64-debs) to install precompiled box64 debs, updated every 24 hours.
|
||||
|
||||
```
|
||||
# check if .list file already exists
|
||||
@@ -358,12 +359,12 @@ sudo apt update
|
||||
sudo apt install box64-generic-arm -y
|
||||
```
|
||||
|
||||
## Cross-Compiling
|
||||
## Cross-Compiling
|
||||
----
|
||||
### Set Up the Cross-Compiler
|
||||
For example, to compile Box64 for RISC-V on an x86 machine, you can get prebuilt GNU toolchain from the [riscv-gnu-toolchain](https://github.com/riscv-collab/riscv-gnu-toolchain/releases)
|
||||
For example, to compile Box64 for RISC-V on an x86 machine, you can get prebuilt GNU toolchain from the [riscv-gnu-toolchain](https://github.com/riscv-collab/riscv-gnu-toolchain/releases)
|
||||
|
||||
### Run CMake with Cross-Compilation Options
|
||||
### Run CMake with Cross-Compilation Options
|
||||
Follow the per-platform compilation instructions to configure the CMake options for your target architecture.
|
||||
In particular, you must specify the cross-compiler. For example:
|
||||
```
|
||||
|
||||
@@ -14,6 +14,11 @@ Linux Steam requires Box86 or Box32 and it's binfmt enabled, check [Compilation
|
||||
steam
|
||||
```
|
||||
|
||||
For additional stability with Box64 when Box86 is unavailable, it is recommended to use the new 64-bit-only runtime for the Steam client.
|
||||
|
||||
- Steam > Settings > Interface > Client Beta Participation: Steam Beta > Restart Now
|
||||
- Steam > Settings > Interface > Use experimental SteamRT3 Steam Client: On > Restart Now
|
||||
|
||||
## Install and run Windows Steam
|
||||
|
||||
It's simple, just download it from Steam website and install it like other Windows applications.
|
||||
+70
-72
@@ -71,23 +71,16 @@ Enable building bigger DynaRec code blocks for better performance. Available in
|
||||
* 0: Do not try to build block as big as possible, suitable for programs using lots of threads and JIT, like Unity.
|
||||
* 1: Build DynaRec block as big as possible.
|
||||
* 2: Build DynaRec block bigger, do not stop when block overlaps, but only for blocks in elf memory. [Default]
|
||||
* 3: Build DynaRec block bigger, do not stop when block overlaps, for all type of memory, useful for wine programs.
|
||||
* 3: Build DynaRec block bigger, do not stop when block overlaps, for all type of memory, useful for Wine programs.
|
||||
|
||||
### BOX64_DYNAREC_CALLRET
|
||||
|
||||
Optimize CALL/RET opcodes. Available in WowBox64.
|
||||
|
||||
* 0: Do not optimize CALL/RET, use jump table. [Default]
|
||||
* 0: Do not optimize CALL/RET, use jump table.
|
||||
* 1: Try to optimize CALL/RET, skipping the jump table when possible.
|
||||
* 2: Try to optimize CALL/RET, skipping the jump table when possible, adding code to handle return to dirty/modified block. Does not work on WowBox64.
|
||||
|
||||
### BOX64_DYNAREC_SEP
|
||||
|
||||
Optimize CALL/RET further with Secondary Entry Points (SEP). Has no effect if CALLRET is not enabled Available in WowBox64.
|
||||
|
||||
* 0: Do not add SEP at CALLRET return
|
||||
* 1: Add SEP at CALLRET return, on memory that are from known binary files [Default]
|
||||
* 2: Add SEP at CALLRET return for all type of memory.
|
||||
* 2: Try to optimize CALL/RET, skipping the jump table when possible, adding code to handle return to dirty/modified block. Does not work on WowBox64. [Default]
|
||||
* 3: Same as 2, but also track dynablock usage so blocks are not reclaimed while still in use.
|
||||
|
||||
### BOX64_DYNAREC_DF
|
||||
|
||||
@@ -128,11 +121,13 @@ Enable or disable fast rounding. Available in WowBox64.
|
||||
|
||||
### BOX64_DYNAREC_FORWARD
|
||||
|
||||
Define max allowed forward value when building block. Available in WowBox64.
|
||||
Define max allowed forward value when building block. Only 0, 128, 256, 512 and 1024 are valid; other values fall back to 128. Available in WowBox64.
|
||||
|
||||
* 0: No forward value. When current block ends, do not try to go further even if there are previous forward jumps.
|
||||
* 128: Allow up to 128 bytes of gap between end of the block and the next forward jump. [Default]
|
||||
* XXXX: Allow up to XXXX bytes of gap between end of the block and the next forward jump.
|
||||
* 256: Allow up to 256 bytes of gap between end of the block and the next forward jump.
|
||||
* 512: Allow up to 512 bytes of gap between end of the block and the next forward jump.
|
||||
* 1024: Allow up to 1024 bytes of gap between end of the block and the next forward jump.
|
||||
|
||||
### BOX64_DYNAREC_NATIVEFLAGS
|
||||
|
||||
@@ -175,12 +170,49 @@ Use volatile metadata parsed from PE files, only valid for 64bit Windows games.
|
||||
* 0: Do not use volatile metadata.
|
||||
* 1: Use volatile metadata, which will guide Box64 for better strong memory emulation. [Default]
|
||||
|
||||
### BOX64_DYNAREC_WAIT
|
||||
### BOX64_DYNACACHE
|
||||
|
||||
Wait or not for the building of a DynaRec code block to be ready. Available in WowBox64.
|
||||
Enable/disable the Dynamic Recompiler Cache (a.k.a DynaCache). This option defaults to 1 (enable). DynaCache writes files to the home folder by default, and keeps its folder below BOX64_DYNACACHE_LIMIT when generating new cache files.
|
||||
|
||||
* 0: Do not wait and use interpreter instead, might speedup a bit on massive multithread or JIT programs.
|
||||
* 1: Wait for a DynaRec code block to be ready. [Default]
|
||||
* 0: Disable DynaCache.
|
||||
* 1: Enable DynaCache. [Default]
|
||||
* 2: Use DynaCache files if present, but do not generate new one.
|
||||
|
||||
### BOX64_DYNACACHE_FOLDER
|
||||
|
||||
Set the folder for DynaCache files. Default is $XDG_CACHE_HOME/box64 or $HOME/.cache/box64 if $XDG_CACHE_HOME is not set.
|
||||
|
||||
* XXXX: Use folder XXXX for DynaCache files.
|
||||
|
||||
### BOX64_DYNACACHE_LIMIT
|
||||
|
||||
Maximum size, in MiB, for the DynaCache folder. When the limit is exceeded, invalid DynaCache files are removed first, then the oldest valid files are removed if needed. Default size is 2048MiB.
|
||||
|
||||
* 0: Do not limit the DynaCache folder size.
|
||||
* XXXX: Keep the DynaCache folder below XXXX MiB by removing invalid cache files first, then the oldest valid cache files.
|
||||
* 2048: A size of 2048 MiB is the default value. [Default]
|
||||
|
||||
### BOX64_DYNACACHE_COMPRESS
|
||||
|
||||
Compress or not DynaCache files on disk
|
||||
|
||||
* 0: Do not compress dynacache files
|
||||
* 1: Compress dynacache files using Zlib with fastest compression. [Default]
|
||||
* 2: Compress dynacache files using ZLib with default compression.
|
||||
|
||||
### BOX64_DYNACACHE_MIN
|
||||
|
||||
Minimum size, in KB, for a DynaCache to be written to disk. Default size is 30KB
|
||||
|
||||
* XXXX: Set a minimum size of XXXX KB of DynaRec code to write the dynacache to disk. Will not be saved to disk else.
|
||||
* 30: A size of 30 KB is the default value. [Default]
|
||||
|
||||
### BOX64_SKIPCPU
|
||||
|
||||
Skip N first CPU cores (Is apply before MAXCPU) Available in WowBox64.
|
||||
|
||||
* 0: Do not skip any CPU cores. [Default]
|
||||
* XXXX: Skip XXXX first CPU cores (usefull for big.LITTLE configurations).
|
||||
|
||||
### BOX64_MMAP32
|
||||
|
||||
@@ -273,13 +305,6 @@ Specify the CPU type to emulate. Available in WowBox64.
|
||||
* 0: Emulate a Intel CPU Model. [Default]
|
||||
* 1: Emulate a AMD CPU Model.
|
||||
|
||||
### BOX64_CRASHHANDLER
|
||||
|
||||
Use a dummy crash handler or not.
|
||||
|
||||
* 0: Use emulated crashhandler.so library if needed.
|
||||
* 1: Use an internal dummy (empty) crashhandler.so library. [Default]
|
||||
|
||||
### BOX64_DYNAREC_BLEEDING_EDGE
|
||||
|
||||
Detect MonoBleedingEdge and apply conservative settings (Linux only).
|
||||
@@ -380,6 +405,13 @@ Do not load any rc files.
|
||||
* 0: Load rc files. [Default]
|
||||
* 1: Do not load any rc files.
|
||||
|
||||
### BOX64_ONDEMAND_STEAMUI
|
||||
|
||||
Close the Steam UI while a game is running, and reopen it when the game is closed.
|
||||
|
||||
* 0: Disabled. [Default]
|
||||
* 1: Close the Steam UI (steamwebhelper) while a game is running, reopen it when the game is closed.
|
||||
|
||||
### BOX64_PATH
|
||||
|
||||
Path to look for x86_64 binaries.
|
||||
@@ -543,6 +575,7 @@ Enable DynaRec dump. Available in WowBox64.
|
||||
* 0: Do not dump DynaRec blocks. [Default]
|
||||
* 1: Dump DynaRec blocks.
|
||||
* 2: Dump DynaRec blocks with some colors.
|
||||
* 3: Dump only x86 and translated native instructions.
|
||||
|
||||
### BOX64_DYNAREC_DUMP_RANGE
|
||||
|
||||
@@ -550,6 +583,13 @@ Dump DynaRec blocks in the specified range. Available in WowBox64.
|
||||
|
||||
* 0xXXXXXXXX-0xYYYYYYYY: Define the range where DynaBlock gets dumped (inclusive-exclusive).
|
||||
|
||||
### BOX64_DYNAREC_DISASM
|
||||
|
||||
Try to initialize libZydis for more readable x86 disassembly in dump, trace, crash report, etc.
|
||||
|
||||
* 0: Do not load Zydis for Dynarec. [Default]
|
||||
* 1: Try to load Zydis for Dynarec.
|
||||
|
||||
### BOX64_DYNAREC_GDBJIT
|
||||
|
||||
The GDBJIT debugging support, only available on build with `-DGDBJIT=ON`, enable it with gdb command: jit-reader-load /usr/local/lib/libbox64gdbjitreader.so.
|
||||
@@ -732,6 +772,7 @@ Same as BOX64_TRACE but starts the trace immediately.
|
||||
* 1: Enable trace output. Trace starts before the initialization of dependencies.
|
||||
* symbolname: Enable trace output for `symbolname` only. Trace starts before the initialization of dependencies.
|
||||
* 0xXXXXXXX-0xYYYYYYY: Enable trace output for the range of address (inclusive-exclusive). Trace starts before the initialization of dependencies.
|
||||
* 0xXXXXXXX:0xYYYYYYY:0xZZZZZZZ: Enable trace output only for the specified address list. Trace starts before the initialization of dependencies.
|
||||
|
||||
### BOX64_TRACE_START
|
||||
|
||||
@@ -756,6 +797,7 @@ Only available on box64 build with trace. Adds trace of all instructions execute
|
||||
* 1: Enable trace output.
|
||||
* symbolname: Enable trace output for `symbolname` only.
|
||||
* 0xXXXXXXX-0xYYYYYYY: Enable trace output for the range of address (inclusive-exclusive).
|
||||
* 0xXXXXXXX:0xYYYYYYY:0xZZZZZZZ: Enable trace output only for the specified address list.
|
||||
|
||||
## Environment
|
||||
|
||||
@@ -773,19 +815,12 @@ Add an environment variable.
|
||||
|
||||
## Fragile or Legacy
|
||||
|
||||
### BOX64_DYNAREC_PURGE
|
||||
### BOX64_DYNAREC_WAIT
|
||||
|
||||
Purge DynaBlocks that haven't been executed recently, based on tick age threshold (BOX64_DYNAREC_PURGE_AGE).
|
||||
Wait or not for the building of a DynaRec code block to be ready. Available in WowBox64.
|
||||
|
||||
* 0: DynaRec will not purge old unused DynaBlocks. [Default]
|
||||
* 1: DynaRec will purge old unused DynaBlocks based on tick age.
|
||||
|
||||
### BOX64_DYNAREC_PURGE_AGE
|
||||
|
||||
Tick age threshold for DynaBlock purging (requires BOX64_DYNAREC_PURGE=1).
|
||||
|
||||
* 4096: Default age threshold. [Default]
|
||||
* XXXX: Custom age threshold (range: 10-65536).
|
||||
* 0: Do not wait and use interpreter instead, might speedup a bit on massive multithread or JIT programs.
|
||||
* 1: Wait for a DynaRec code block to be ready. [Default]
|
||||
|
||||
### BOX64_DYNAREC_WEAKBARRIER
|
||||
|
||||
@@ -795,43 +830,6 @@ Tweak the memory barriers to reduce the performance impact by strong memory emul
|
||||
* 1: Use weak barriers to have more performance boost. [Default]
|
||||
* 2: All in 1, plus disable the last write barriers.
|
||||
|
||||
### BOX64_DYNACACHE
|
||||
|
||||
Enable/disable the Dynamic Recompiler Cache (a.k.a DynaCache). This option defaults to 2 (to read cache if present but not generate any). DynaCache writes files to the home folder by default, and keeps its folder below BOX64_DYNACACHE_LIMIT when generating new cache files.
|
||||
|
||||
* 0: Disable DynaCache.
|
||||
* 1: Enable DynaCache. [Default]
|
||||
* 2: Use DynaCache files if present, but do not generate new one.
|
||||
|
||||
### BOX64_DYNACACHE_FOLDER
|
||||
|
||||
Set the folder for DynaCache files. Default is $XDG_CACHE_HOME/box64 or $HOME/.cache/box64 if $XDG_CACHE_HOME is not set.
|
||||
|
||||
* XXXX: Use folder XXXX for DynaCache files.
|
||||
|
||||
### BOX64_DYNACACHE_LIMIT
|
||||
|
||||
Maximum size, in MiB, for the DynaCache folder. When the limit is exceeded, invalid DynaCache files are removed first, then the oldest valid files are removed if needed. Default size is 2048MiB.
|
||||
|
||||
* 0: Do not limit the DynaCache folder size.
|
||||
* XXXX: Keep the DynaCache folder below XXXX MiB by removing invalid cache files first, then the oldest valid cache files.
|
||||
* 2048: A size of 2048 MiB is the default value. [Default]
|
||||
|
||||
### BOX64_DYNACACHE_COMPRESS
|
||||
|
||||
Compress or not DynaCache files on disk
|
||||
|
||||
* 0: Do not compress dynacache files
|
||||
* 1: Compress dynacache files using Zlib with fastest compression. [Default]
|
||||
* 2: Compress dynacache files using ZLib with default compression.
|
||||
|
||||
### BOX64_DYNACACHE_MIN
|
||||
|
||||
Minimum size, in KB, for a DynaCache to be written to disk. Default size is 350KB
|
||||
|
||||
* XXXX: Set a minimum size of XXXX KB of DynaRec code to write the dynacache to disk. Will not be saved to disk else.
|
||||
* 350: A size of 350 KB is the default value. [Default]
|
||||
|
||||
## Libraries
|
||||
|
||||
### BOX64_ADDLIBS
|
||||
|
||||
+83
-85
@@ -71,23 +71,16 @@ BOX64_DYNAREC_CALLRET=1
|
||||
* 0: 不尝试构建尽可能大的代码块,适用于使用大量线程和 JIT 的程序(如 Unity)。
|
||||
* 1: 尽可能构建大的代码块。
|
||||
* 2: 构建更大的代码块,代码块重叠时不停止,但仅针对 elf 内存中的代码块。 [默认值]
|
||||
* 3: 构建更大的代码块,代码块重叠时不停止,适用于所有类型的内存,因此也对 wine 程序有用。
|
||||
* 3: 构建更大的代码块,代码块重叠时不停止,适用于所有类型的内存,因此也对 Wine 程序有用。
|
||||
|
||||
### BOX64_DYNAREC_CALLRET
|
||||
|
||||
优化 CALL/RET 指令。 在 WowBox64 中可用。
|
||||
|
||||
* 0: 不优化 CALL/RET,使用跳转表。 [默认值]
|
||||
* 0: 不优化 CALL/RET,使用跳转表。
|
||||
* 1: 尝试优化 CALL/RET,在可能的情况下跳过跳转表。
|
||||
* 2: 尝试优化 CALL/RET,在可能的情况下跳过跳转表,同时增加对返回到脏/已修改代码块的代码的处理。在 WowBox64 上不可用。
|
||||
|
||||
### BOX64_DYNAREC_SEP
|
||||
|
||||
使用二级入口点(SEP)进一步优化 CALL/RET。如果 CALLRET 未启用则无效。 在 WowBox64 中可用。
|
||||
|
||||
* 0: 不在 CALLRET 返回时添加 SEP。
|
||||
* 1: 在 CALLRET 返回时添加 SEP,仅针对来自已知二进制文件的内存。 [默认值]
|
||||
* 2: 在 CALLRET 返回时添加 SEP,适用于所有类型的内存。
|
||||
* 2: 尝试优化 CALL/RET,在可能的情况下跳过跳转表,同时增加对返回到脏/已修改代码块的代码的处理。在 WowBox64 上不可用。 [默认值]
|
||||
* 3: 在 2 的基础上,额外跟踪代码块的使用情况,避免回收仍在使用中的代码块。
|
||||
|
||||
### BOX64_DYNAREC_DF
|
||||
|
||||
@@ -128,11 +121,13 @@ BOX64_DYNAREC_CALLRET=1
|
||||
|
||||
### BOX64_DYNAREC_FORWARD
|
||||
|
||||
定义构建代码块时允许的最大前向跳转值。 在 WowBox64 中可用。
|
||||
定义构建代码块时允许的最大前向跳转值。仅接受 0、128、256、512 和 1024;其他值将回退为 128。 在 WowBox64 中可用。
|
||||
|
||||
* 0: 无前向跳转值。当前代码块结束时,即使存在之前的前向跳转也不尝试继续前进。
|
||||
* 128: 允许代码块结束与下一个前向跳转之间最多 128 字节的间隙。 [默认值]
|
||||
* XXXX: 允许代码块结束与下一个前向跳转之间最多 XXXX 字节的间隙。
|
||||
* 256: 允许代码块结束与下一个前向跳转之间最多 256 字节的间隙。
|
||||
* 512: 允许代码块结束与下一个前向跳转之间最多 512 字节的间隙。
|
||||
* 1024: 允许代码块结束与下一个前向跳转之间最多 1024 字节的间隙。
|
||||
|
||||
### BOX64_DYNAREC_NATIVEFLAGS
|
||||
|
||||
@@ -175,62 +170,9 @@ BOX64_DYNAREC_CALLRET=1
|
||||
* 0: 不使用 volatile 元数据。
|
||||
* 1: 使用 volatile 元数据,将指导 Box64 进行更好的强内存模拟。 [默认值]
|
||||
|
||||
### BOX64_DYNAREC_WAIT
|
||||
|
||||
是否等待代码块构建完成。 在 WowBox64 中可用。
|
||||
|
||||
* 0: 不等待,改用解释器,可能在大量多线程或 JIT 程序上略微加速。
|
||||
* 1: 等待代码块构建完成。 [默认值]
|
||||
|
||||
### BOX64_MMAP32
|
||||
|
||||
在运行 32 位代码的 64 位程序(如 Wine WOW64)上强制使用 32 位兼容的内存映射,可提高性能。
|
||||
|
||||
* 0: 不强制使用 32 位内存映射。
|
||||
* 1: 强制使用 32 位内存映射。 [默认值]
|
||||
|
||||
### BOX64_DYNAREC_NOARCH
|
||||
|
||||
从代码块中移除架构元数据(在信号处理时使用)。 在 WowBox64 中可用。
|
||||
|
||||
* 0: 为每个代码块生成所有架构元数据,包括 x87/mmx/SSE/AVX 寄存器追踪。会使用更多内存。 [默认值]
|
||||
* 1: 仅生成每个代码块的必要元数据(FLAGS、对齐),节省一些内存,但某些加密软件可能会失败。
|
||||
* 2: 不为代码块生成元数据,进一步节省内存,但在信号处理时可能会失败。
|
||||
|
||||
### BOX64_RDTSC_1GHZ
|
||||
|
||||
如果可用,使用硬件计数器实现 rdtsc。
|
||||
|
||||
* 0: 如果可用,使用硬件计数器实现 rdtsc 指令。 [默认值]
|
||||
* 1: 仅当精度至少为 1GHz 时,使用硬件计数器实现 rdtsc。
|
||||
|
||||
## 不稳定或遗留选项
|
||||
|
||||
### BOX64_DYNAREC_PURGE
|
||||
|
||||
根据年龄阈值(BOX64_DYNAREC_PURGE_AGE)清除最近未执行的代码块。
|
||||
|
||||
* 0: DynaRec 不会清除旧的未使用代码块。 [默认值]
|
||||
* 1: DynaRec 将根据年龄阈值清除旧的未使用代码块。
|
||||
|
||||
### BOX64_DYNAREC_PURGE_AGE
|
||||
|
||||
代码块清除的年龄阈值(需要 BOX64_DYNAREC_PURGE=1)。
|
||||
|
||||
* 4096: 默认年龄阈值。 [默认值]
|
||||
* XXXX: 自定义年龄阈值(范围:10-65536)。
|
||||
|
||||
### BOX64_DYNAREC_WEAKBARRIER
|
||||
|
||||
调整内存屏障以减少强内存模拟的性能影响。 在 WowBox64 中可用。
|
||||
|
||||
* 0: 使用常规安全屏障。
|
||||
* 1: 使用弱屏障以获得更多性能提升。 [默认值]
|
||||
* 2: 包含 1 的全部内容,外加禁用最后的写屏障。
|
||||
|
||||
### BOX64_DYNACACHE
|
||||
|
||||
启用或禁用动态重编译器缓存(DynaCache)。此选项默认为 2(读取已有缓存但不生成新的)。DynaCache 默认将文件写入 home 文件夹,生成新缓存文件时会根据 BOX64_DYNACACHE_LIMIT 控制文件夹大小。
|
||||
启用或禁用动态重编译器缓存(DynaCache)。此选项默认为 1(启用)。DynaCache 默认将文件写入 home 文件夹,生成新缓存文件时会根据 BOX64_DYNACACHE_LIMIT 控制文件夹大小。
|
||||
|
||||
* 0: 禁用 DynaCache。
|
||||
* 1: 启用 DynaCache。 [默认值]
|
||||
@@ -260,10 +202,56 @@ DynaCache 文件夹的最大大小(MiB)。超过限制时,会先删除无
|
||||
|
||||
### BOX64_DYNACACHE_MIN
|
||||
|
||||
DynaCache 写入磁盘的最小大小(KB)。默认大小为 350KB。
|
||||
DynaCache 写入磁盘的最小大小(KB)。默认大小为 30KB。
|
||||
|
||||
* XXXX: 设置将缓存写入磁盘的最小 DynaRec 代码大小(XXXX KB),小于此值将不会保存到磁盘。
|
||||
* 350: 默认值为 350 KB。 [默认值]
|
||||
* 30: 默认值为 30 KB。 [默认值]
|
||||
|
||||
### BOX64_SKIPCPU
|
||||
|
||||
Skip N first CPU cores (Is apply before MAXCPU) 在 WowBox64 中可用。
|
||||
|
||||
* 0: Do not skip any CPU cores. [默认值]
|
||||
* XXXX: Skip XXXX first CPU cores (usefull for big.LITTLE configurations).
|
||||
|
||||
### BOX64_MMAP32
|
||||
|
||||
在运行 32 位代码的 64 位程序(如 Wine WOW64)上强制使用 32 位兼容的内存映射,可提高性能。
|
||||
|
||||
* 0: 不强制使用 32 位内存映射。
|
||||
* 1: 强制使用 32 位内存映射。 [默认值]
|
||||
|
||||
### BOX64_DYNAREC_NOARCH
|
||||
|
||||
从代码块中移除架构元数据(在信号处理时使用)。 在 WowBox64 中可用。
|
||||
|
||||
* 0: 为每个代码块生成所有架构元数据,包括 x87/mmx/SSE/AVX 寄存器追踪。会使用更多内存。 [默认值]
|
||||
* 1: 仅生成每个代码块的必要元数据(FLAGS、对齐),节省一些内存,但某些加密软件可能会失败。
|
||||
* 2: 不为代码块生成元数据,进一步节省内存,但在信号处理时可能会失败。
|
||||
|
||||
### BOX64_RDTSC_1GHZ
|
||||
|
||||
如果可用,使用硬件计数器实现 rdtsc。
|
||||
|
||||
* 0: 如果可用,使用硬件计数器实现 rdtsc 指令。 [默认值]
|
||||
* 1: 仅当精度至少为 1GHz 时,使用硬件计数器实现 rdtsc。
|
||||
|
||||
## 不稳定或遗留选项
|
||||
|
||||
### BOX64_DYNAREC_WAIT
|
||||
|
||||
是否等待代码块构建完成。 在 WowBox64 中可用。
|
||||
|
||||
* 0: 不等待,改用解释器,可能在大量多线程或 JIT 程序上略微加速。
|
||||
* 1: 等待代码块构建完成。 [默认值]
|
||||
|
||||
### BOX64_DYNAREC_WEAKBARRIER
|
||||
|
||||
调整内存屏障以减少强内存模拟的性能影响。 在 WowBox64 中可用。
|
||||
|
||||
* 0: 使用常规安全屏障。
|
||||
* 1: 使用弱屏障以获得更多性能提升。 [默认值]
|
||||
* 2: 包含 1 的全部内容,外加禁用最后的写屏障。
|
||||
|
||||
## 兼容性
|
||||
|
||||
@@ -304,19 +292,12 @@ DynaCache 写入磁盘的最小大小(KB)。默认大小为 350KB。
|
||||
* 0: 模拟某个 Intel CPU 型号。 [默认值]
|
||||
* 1: 模拟某个 AMD CPU 型号。
|
||||
|
||||
### BOX64_CRASHHANDLER
|
||||
|
||||
是否使用模拟的 crashhandler.so 库。
|
||||
|
||||
* 0: 在需要时使用模拟的 crashhandler.so 库。
|
||||
* 1: 使用内部定义的空 crashhandler.so 库。 [默认值]
|
||||
|
||||
### BOX64_DYNAREC_BLEEDING_EDGE
|
||||
|
||||
检测 MonoBleedingEdge 并应用保守设置(仅 Linux)。
|
||||
|
||||
* 0: 不检测 MonoBleedingEdge。
|
||||
* 1: 检测 MonoBleedingEdge,并在检测到时应用 BOX64_DYNAREC_BIGBLOCK=0 和 BOX64_DYNAREC_强内存模型=1。 [默认值]
|
||||
* 1: 检测 MonoBleedingEdge,并在检测到时应用 BOX64_DYNAREC_BIGBLOCK=0 和 BOX64_DYNAREC_STRONGMEM=1。 [默认值]
|
||||
|
||||
### BOX64_DYNAREC_DIV0
|
||||
|
||||
@@ -380,7 +361,7 @@ DynaCache 写入磁盘的最小大小(KB)。默认大小为 350KB。
|
||||
检测 libjvm 并应用保守设置。
|
||||
|
||||
* 0: 不执行任何操作。
|
||||
* 1: 检测 libjvm,并在检测到时应用 BOX64_DYNAREC_BIGBLOCK=0 BOX64_DYNAREC_强内存模型=1 BOX64_SSE42=0。 [默认值]
|
||||
* 1: 检测 libjvm,并在检测到时应用 BOX64_DYNAREC_BIGBLOCK=0 BOX64_DYNAREC_STRONGMEM=1 BOX64_SSE42=0。 [默认值]
|
||||
|
||||
### BOX64_LIBCEF
|
||||
|
||||
@@ -411,6 +392,13 @@ DynaCache 写入磁盘的最小大小(KB)。默认大小为 350KB。
|
||||
* 0: 加载 rc 文件。 [默认值]
|
||||
* 1: 不加载任何 rc 文件。
|
||||
|
||||
### BOX64_ONDEMAND_STEAMUI
|
||||
|
||||
在游戏运行时关闭 Steam UI,游戏结束后重新打开。
|
||||
|
||||
* 0: 禁用。 [默认值]
|
||||
* 1: 在游戏运行时关闭 Steam UI,游戏结束后重新打开。
|
||||
|
||||
### BOX64_PATH
|
||||
|
||||
查找 x86_64 二进制文件的路径。
|
||||
@@ -428,10 +416,10 @@ DynaCache 写入磁盘的最小大小(KB)。默认大小为 350KB。
|
||||
|
||||
预定义的环境变量集合,以兼容性或性能为导向。 在 WowBox64 中可用。
|
||||
|
||||
* safest: 禁用所有不安全的 DynaRec 优化的配置文件。
|
||||
* safe: 比 safest 略不安全。
|
||||
* safest: 禁用所有不安全的优化。
|
||||
* safe: 仅启用小部分不安全的优化。
|
||||
* default: 大多数程序都能正常运行且性能适中的默认设置。 [默认值]
|
||||
* fast: 启用许多不安全的优化,但同时启用 强内存模型 模拟。
|
||||
* fast: 启用许多不安全的优化,但同时启用强内存模型模拟。
|
||||
* fastest: 启用许多不安全的优化以获得更好的性能。
|
||||
|
||||
### BOX64_PYTHON3
|
||||
@@ -476,10 +464,10 @@ python3 可执行文件的路径。
|
||||
|
||||
### BOX64_SSE_FLUSHTO0
|
||||
|
||||
SSE Flush to 0 FLAGS的行为,同时追踪 SSE 异常FLAGS。 在 WowBox64 中可用。
|
||||
SSE Flush to 0 FLAGS的行为,同时追踪 SSE 异常 FLAGS。 在 WowBox64 中可用。
|
||||
|
||||
* 0: 仅追踪FLAGS。 [默认值]
|
||||
* 1: 直接应用 SSE Flush to 0 FLAGS。同时在 DynaRec 中反映 SSE 异常FLAGS(如果可用)。
|
||||
* 0: 仅追踪 FLAGS。 [默认值]
|
||||
* 1: 直接应用 SSE Flush to 0 FLAGS。同时在 DynaRec 中反映 SSE 异常 FLAGS(如果可用)。
|
||||
|
||||
### BOX64_SSE42
|
||||
|
||||
@@ -514,7 +502,7 @@ SSE Flush to 0 FLAGS的行为,同时追踪 SSE 异常FLAGS。 在 WowBox64 中
|
||||
告诉 Box64 这是一个 Unity 游戏。
|
||||
|
||||
* 0: 不执行任何操作。
|
||||
* 1: 这是 Unity 游戏,对 Windows 使用特殊的检测代码,对 Linux 应用 BOX64_DYNAREC_强内存模型=1。 [默认值]
|
||||
* 1: 这是 Unity 游戏,对 Windows 使用特殊的检测代码,对 Linux 应用 BOX64_DYNAREC_STRONGMEM=1。 [默认值]
|
||||
|
||||
### BOX64_X11GLX
|
||||
|
||||
@@ -710,6 +698,7 @@ x87 80 位 long double 的行为。 在 WowBox64 中可用。
|
||||
* 0: 不转储代码块。 [默认值]
|
||||
* 1: 转储代码块。
|
||||
* 2: 转储代码块并带有颜色。
|
||||
* 3: 仅转储 x86 指令和翻译后的本机指令。
|
||||
|
||||
### BOX64_DYNAREC_DUMP_RANGE
|
||||
|
||||
@@ -717,6 +706,13 @@ x87 80 位 long double 的行为。 在 WowBox64 中可用。
|
||||
|
||||
* 0xXXXXXXXX-0xYYYYYYYY: 定义代码块 被转储的范围(左闭右开)。
|
||||
|
||||
### BOX64_DYNAREC_DISASM
|
||||
|
||||
尝试初始化 libZydis,以在转储、追踪、崩溃报告等场景中获得更具可读性的 x86 反汇编结果。
|
||||
|
||||
* 0: 不为 Dynarec 加载 Zydis。 [默认值]
|
||||
* 1: 尝试为 Dynarec 加载 Zydis。
|
||||
|
||||
### BOX64_DYNAREC_GDBJIT
|
||||
|
||||
GDBJIT 调试支持,仅在使用 `-DGDBJIT=ON` 构建时可用,通过 gdb 命令启用:jit-reader-load /usr/local/lib/libbox64gdbjitreader.so。
|
||||
@@ -899,6 +895,7 @@ GDBJIT 调试支持,仅在使用 `-DGDBJIT=ON` 构建时可用,通过 gdb
|
||||
* 1: 启用追踪输出。追踪在依赖项初始化之前开始。
|
||||
* symbolname: 仅对 `symbolname` 启用追踪输出。追踪在依赖项初始化之前开始。
|
||||
* 0xXXXXXXX-0xYYYYYYY: 对指定地址范围(左闭右开)启用追踪输出。追踪在依赖项初始化之前开始。
|
||||
* 0xXXXXXXX:0xYYYYYYY:0xZZZZZZZ: 对指定的地址列表启用追踪输出。追踪在依赖项初始化之前开始。
|
||||
|
||||
### BOX64_TRACE_START
|
||||
|
||||
@@ -923,4 +920,5 @@ GDBJIT 调试支持,仅在使用 `-DGDBJIT=ON` 构建时可用,通过 gdb
|
||||
* 1: 启用追踪输出。
|
||||
* symbolname: 仅对 `symbolname` 启用追踪输出。
|
||||
* 0xXXXXXXX-0xYYYYYYY: 对指定地址范围(左闭右开)启用追踪输出。
|
||||
* 0xXXXXXXX:0xYYYYYYY:0xZZZZZZZ: 对指定地址列表启用追踪输出。
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
# 在 Box64 上使用 Wine 的指南
|
||||
|
||||
Wine 不是一个模拟器,但 Box64 是。Box64 以多种方式支持 Wine。在继续阅读之前,你应该对 Wine 有基本的了解。
|
||||
|
||||
## Wine 的变体
|
||||
|
||||
Wine 以多种形式发布:
|
||||
|
||||
|
||||
1. **x86 Wine**
|
||||
|
||||
**x86 Wine** 的可执行文件架构是 x86,它运行 x32 Windows 可执行文件。
|
||||
|
||||
x86 Wine 需要 32 位环境(读取 32 位 Linux 库),因为该架构天然的特点,这在 x86_64 机器上通常可用。
|
||||
|
||||
但是,当你尝试在 RISC 架构上通过模拟器运行它时,情况则有些不同。对于 Arm64,存在 armhf 这样的 32 位环境,也有为 armhf 设计的 Box86,因此你可以使用 Box86 运行 **x86 Wine**。
|
||||
|
||||
然而,对于 RISC-V 64、LoongArch64 以及许多较新的 Arm64 核心,32 位环境并不可用。Box64 引入了一种名为 Box32 的新模式,可以在编译时通过 CMake 选项 `BOX32` 启用。它本质上利用 64 位环境模拟 32 位环境,因此可以用来运行 x86 Wine。但请注意,Box32 仍是高度实验性且不稳定的。
|
||||
|
||||
2. **x86_64 Wine**
|
||||
|
||||
**x86_64 Wine** 的可执行文件架构是 x86_64,它运行 x64 Windows 可执行文件。
|
||||
|
||||
它可以与 Box64 配合使用。注意,**x86_64 Wine** 通常自带 **x86 Wine**。因此你可以结合使用 Box86 + Box64,或者仅使用启用了 Box32 的 Box64,来无缝运行 32 位和 64 位可执行文件。
|
||||
|
||||
3. **x86_64 Wine WOW64**
|
||||
|
||||
**x86_64 Wine WOW64** 的可执行文件架构是 x86_64,它同时能运行 x32 和 x64 Windows 可执行文件。
|
||||
|
||||
**x86_64 Wine WOW64** 的优点在于它运行 32 位 Windows 可执行文件时不需要 32 位环境,因为 32 位环境模拟已由 Wine WOW64 自身处理。
|
||||
|
||||
这意味着你可以只使用 Box64(无需 Box32)来运行 32 位 Windows 可执行文件。然而缺点是,对于 32 位程序,WineD3D 的性能相当差(请使用 DXVK!)。
|
||||
|
||||
4. **Arm64 Wine WOW64**
|
||||
|
||||
**Arm64 Wine WOW64** 的可执行文件架构是 Arm64,它能运行 x32、x64、Arm32 和 Arm64 的 Windows 可执行文件。
|
||||
|
||||
但是,要运行 x32 和 x64 的程序,需要一个 cpu.dll,也就是所谓的 WOW64(用于 32 位)和 Arm64EC(用于 64 位)。
|
||||
|
||||
Box64 现已支持 32 位 WOW64 DLL。你可以通过编译时启用 `WOW64` CMake 选项来启用它。我们计划在未来支持 Arm64EC。
|
||||
|
||||
## Wine 的安装
|
||||
|
||||
对于 x86 Wine,有很多下载渠道,略举几例:
|
||||
|
||||
- https://github.com/Kron4ek/Wine-Builds (Wine \[WOW64\])
|
||||
- https://github.com/GloriousEggroll/proton-ge-custom (Proton,即 Valve 优化过的 Wine)
|
||||
|
||||
下载后,只需以你喜欢的方式将 `bin` 文件夹添加到 `PATH` 环境变量中;Wine 应该能很好地与 Box64 配合工作。
|
||||
|
||||
要安装 DXVK、d3dcompiler_xx 或 cjkfonts 等组件,推荐使用 Winetricks:https://github.com/Winetricks/winetricks
|
||||
|
||||
对于 Arm64 Wine,推荐使用 Hangover:https://github.com/AndreRH/hangover
|
||||
+44
-47
@@ -118,14 +118,6 @@ Specify the CPU type to emulate. Available in WowBox64.
|
||||
* 1 : Emulate a AMD CPU Model.
|
||||
|
||||
|
||||
=item B<BOX64_CRASHHANDLER> =I<0|1>
|
||||
|
||||
Use a dummy crash handler or not.
|
||||
|
||||
* 0 : Use emulated crashhandler.so library if needed.
|
||||
* 1 : Use an internal dummy (empty) crashhandler.so library. [Default]
|
||||
|
||||
|
||||
=item B<BOX64_DLSYM_ERROR> =I<0|1>
|
||||
|
||||
Enable or disable the logging of dlsym errors.
|
||||
@@ -165,7 +157,7 @@ Enable building bigger DynaRec code blocks for better performance. Available in
|
||||
* 0 : Do not try to build block as big as possible, suitable for programs using lots of threads and JIT, like Unity.
|
||||
* 1 : Build DynaRec block as big as possible.
|
||||
* 2 : Build DynaRec block bigger, do not stop when block overlaps, but only for blocks in elf memory. [Default]
|
||||
* 3 : Build DynaRec block bigger, do not stop when block overlaps, for all type of memory, useful for wine programs.
|
||||
* 3 : Build DynaRec block bigger, do not stop when block overlaps, for all type of memory, useful for Wine programs.
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_BLEEDING_EDGE> =I<0|1>
|
||||
@@ -176,22 +168,14 @@ Detect MonoBleedingEdge and apply conservative settings (Linux only).
|
||||
* 1 : Detect MonoBleedingEdge and apply BOX64_DYNAREC_BIGBLOCK=0 BOX64_DYNAREC_STRONGMEM=1 when detected. [Default]
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_CALLRET> =I<0|1|2>
|
||||
=item B<BOX64_DYNAREC_CALLRET> =I<0|1|2|3>
|
||||
|
||||
Optimize CALL/RET opcodes. Available in WowBox64.
|
||||
|
||||
* 0 : Do not optimize CALL/RET, use jump table. [Default]
|
||||
* 0 : Do not optimize CALL/RET, use jump table.
|
||||
* 1 : Try to optimize CALL/RET, skipping the jump table when possible.
|
||||
* 2 : Try to optimize CALL/RET, skipping the jump table when possible, adding code to handle return to dirty/modified block. Does not work on WowBox64.
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_SEP> =I<0|1|2>
|
||||
|
||||
Optimize CALL/RET further with Secondary Entry Points (SEP). Has no effect if CALLRET is not enabled Available in WowBox64.
|
||||
|
||||
* 0 : Do not add SEP at CALLRET return
|
||||
* 1 : Add SEP at CALLRET return, on memory that are from known binary files [Default]
|
||||
* 2 : Add SEP at CALLRET return for all type of memory.
|
||||
* 2 : Try to optimize CALL/RET, skipping the jump table when possible, adding code to handle return to dirty/modified block. Does not work on WowBox64. [Default]
|
||||
* 3 : Same as 2, but also track dynablock usage so blocks are not reclaimed while still in use.
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_DF> =I<0|1>
|
||||
@@ -227,13 +211,14 @@ Enable or disable the generation of division-by-zero exception. Available in Wow
|
||||
* 1 : Generate the division-by-zero exception.
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_DUMP> =I<0|1|2>
|
||||
=item B<BOX64_DYNAREC_DUMP> =I<0|1|2|3>
|
||||
|
||||
Enable DynaRec dump. Available in WowBox64.
|
||||
|
||||
* 0 : Do not dump DynaRec blocks. [Default]
|
||||
* 1 : Dump DynaRec blocks.
|
||||
* 2 : Dump DynaRec blocks with some colors.
|
||||
* 3 : Dump only x86 and translated native instructions.
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_DUMP_RANGE> =I<0xXXXXXXXX-0xYYYYYYYY>
|
||||
@@ -243,6 +228,14 @@ Dump DynaRec blocks in the specified range. Available in WowBox64.
|
||||
* 0xXXXXXXXX-0xYYYYYYYY : Define the range where DynaBlock gets dumped (inclusive-exclusive).
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_DISASM> =I<0|1>
|
||||
|
||||
Try to initialize libZydis for more readable x86 disassembly in dump, trace, crash report, etc.
|
||||
|
||||
* 0 : Do not load Zydis for Dynarec. [Default]
|
||||
* 1 : Try to load Zydis for Dynarec.
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_FASTNAN> =I<0|1>
|
||||
|
||||
Enable or disable fast NaN handling. Available in WowBox64.
|
||||
@@ -260,13 +253,15 @@ Enable or disable fast rounding. Available in WowBox64.
|
||||
* 2 : Generate float/double -> int rounding using current rounding mode for float/double computation like on x86, but use fast int -> float/double conversion.
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_FORWARD> =I<0|128|XXXX>
|
||||
=item B<BOX64_DYNAREC_FORWARD> =I<0|128|256|512|1024>
|
||||
|
||||
Define max allowed forward value when building block. Available in WowBox64.
|
||||
Define max allowed forward value when building block. Only 0, 128, 256, 512 and 1024 are valid; other values fall back to 128. Available in WowBox64.
|
||||
|
||||
* 0 : No forward value. When current block ends, do not try to go further even if there are previous forward jumps.
|
||||
* 128 : Allow up to 128 bytes of gap between end of the block and the next forward jump. [Default]
|
||||
* XXXX : Allow up to XXXX bytes of gap between end of the block and the next forward jump.
|
||||
* 256 : Allow up to 256 bytes of gap between end of the block and the next forward jump.
|
||||
* 512 : Allow up to 512 bytes of gap between end of the block and the next forward jump.
|
||||
* 1024 : Allow up to 1024 bytes of gap between end of the block and the next forward jump.
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_GDBJIT> =I<0|1|2|3|0xXXXXXXX-0xYYYYYYY>
|
||||
@@ -334,22 +329,6 @@ Generate map file for Linux perf tool.
|
||||
* 1 : DynaRec will generate perf map.
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_PURGE> =I<0|1>
|
||||
|
||||
Purge DynaBlocks that haven't been executed recently, based on tick age threshold (BOX64_DYNAREC_PURGE_AGE).
|
||||
|
||||
* 0 : DynaRec will not purge old unused DynaBlocks. [Default]
|
||||
* 1 : DynaRec will purge old unused DynaBlocks based on tick age.
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_PURGE_AGE> =I<4096|XXXX>
|
||||
|
||||
Tick age threshold for DynaBlock purging (requires BOX64_DYNAREC_PURGE=1).
|
||||
|
||||
* 4096 : Default age threshold. [Default]
|
||||
* XXXX : Custom age threshold (range: 10-65536).
|
||||
|
||||
|
||||
=item B<BOX64_DYNAREC_SAFEFLAGS> =I<0|1|2>
|
||||
|
||||
Behaviour of flags emulation on CALL/RET opcodes and other edge cases. Available in WowBox64.
|
||||
@@ -455,7 +434,7 @@ Allow the use of DynaRec in Signal Handlers.
|
||||
|
||||
=item B<BOX64_DYNACACHE> =I<0|1|2>
|
||||
|
||||
Enable/disable the Dynamic Recompiler Cache (a.k.a DynaCache). This option defaults to 2 (to read cache if present but not generate any). DynaCache writes files to the home folder by default, and keeps its folder below BOX64_DYNACACHE_LIMIT when generating new cache files.
|
||||
Enable/disable the Dynamic Recompiler Cache (a.k.a DynaCache). This option defaults to 1 (enable). DynaCache writes files to the home folder by default, and keeps its folder below BOX64_DYNACACHE_LIMIT when generating new cache files.
|
||||
|
||||
* 0 : Disable DynaCache.
|
||||
* 1 : Enable DynaCache. [Default]
|
||||
@@ -487,12 +466,12 @@ Compress or not DynaCache files on disk
|
||||
* 2 : Compress dynacache files using ZLib with default compression.
|
||||
|
||||
|
||||
=item B<BOX64_DYNACACHE_MIN> =I<XXXX|350>
|
||||
=item B<BOX64_DYNACACHE_MIN> =I<XXXX|30>
|
||||
|
||||
Minimum size, in KB, for a DynaCache to be written to disk. Default size is 350KB
|
||||
Minimum size, in KB, for a DynaCache to be written to disk. Default size is 30KB
|
||||
|
||||
* XXXX : Set a minimum size of XXXX KB of DynaRec code to write the dynacache to disk. Will not be saved to disk else.
|
||||
* 350 : A size of 350 KB is the default value. [Default]
|
||||
* 30 : A size of 30 KB is the default value. [Default]
|
||||
|
||||
|
||||
=item B<BOX64_EMULATED_LIBS> =I<XXXX|XXXX:YYYY:ZZZZ>
|
||||
@@ -648,6 +627,14 @@ Maximum CPU cores exposed. Available in WowBox64.
|
||||
* XXXX : Use XXXX CPU cores.
|
||||
|
||||
|
||||
=item B<BOX64_SKIPCPU> =I<0|XXXX>
|
||||
|
||||
Skip N first CPU cores (Is apply before MAXCPU) Available in WowBox64.
|
||||
|
||||
* 0 : Do not skip any CPU cores. [Default]
|
||||
* XXXX : Skip XXXX first CPU cores (usefull for big.LITTLE configurations).
|
||||
|
||||
|
||||
=item B<BOX64_MMAP32> =I<0|1>
|
||||
|
||||
Force 32-bit compatible memory mappings on 64-bit programs that run 32-bit code (like Wine WOW64), can improve performance.
|
||||
@@ -752,6 +739,14 @@ Do not load x64 Vulkan overlay.
|
||||
* 1 : Do not load x64 Vulkan overlay.
|
||||
|
||||
|
||||
=item B<BOX64_ONDEMAND_STEAMUI> =I<0|1>
|
||||
|
||||
Close the Steam UI while a game is running, and reopen it when the game is closed.
|
||||
|
||||
* 0 : Disabled. [Default]
|
||||
* 1 : Close the Steam UI (steamwebhelper) while a game is running, reopen it when the game is closed.
|
||||
|
||||
|
||||
=item B<BOX64_PATH> =I<XXXX>
|
||||
|
||||
Path to look for x86_64 binaries.
|
||||
@@ -931,7 +926,7 @@ Send all log and trace to a file instead of `stdout`.
|
||||
* stdout : Send all log and trace to `stdout`.
|
||||
|
||||
|
||||
=item B<BOX64_TRACE_INIT> =I<0|1|symbolname|0xXXXXXXX-0xYYYYYYY>
|
||||
=item B<BOX64_TRACE_INIT> =I<0|1|symbolname|0xXXXXXXX-0xYYYYYYY|0xXXXXXXX:0xYYYYYYY:0xZZZZZZZ>
|
||||
|
||||
Same as BOX64_TRACE but starts the trace immediately.
|
||||
|
||||
@@ -939,6 +934,7 @@ Same as BOX64_TRACE but starts the trace immediately.
|
||||
* 1 : Enable trace output. Trace starts before the initialization of dependencies.
|
||||
* symbolname : Enable trace output for `symbolname` only. Trace starts before the initialization of dependencies.
|
||||
* 0xXXXXXXX-0xYYYYYYY : Enable trace output for the range of address (inclusive-exclusive). Trace starts before the initialization of dependencies.
|
||||
* 0xXXXXXXX:0xYYYYYYY:0xZZZZZZZ : Enable trace output only for the specified address list. Trace starts before the initialization of dependencies.
|
||||
|
||||
|
||||
=item B<BOX64_TRACE_START> =I<0|1|XXXX>
|
||||
@@ -958,7 +954,7 @@ Enable or disable XMM (i.e. SSE) trace output.
|
||||
* 1 : Enable XMM trace output.
|
||||
|
||||
|
||||
=item B<BOX64_TRACE> =I<0|1|symbolname|0xXXXXXXX-0xYYYYYYY>
|
||||
=item B<BOX64_TRACE> =I<0|1|symbolname|0xXXXXXXX-0xYYYYYYY|0xXXXXXXX:0xYYYYYYY:0xZZZZZZZ>
|
||||
|
||||
Only available on box64 build with trace. Adds trace of all instructions executed, along with a register dump.
|
||||
|
||||
@@ -966,6 +962,7 @@ Only available on box64 build with trace. Adds trace of all instructions execute
|
||||
* 1 : Enable trace output.
|
||||
* symbolname : Enable trace output for `symbolname` only.
|
||||
* 0xXXXXXXX-0xYYYYYYY : Enable trace output for the range of address (inclusive-exclusive).
|
||||
* 0xXXXXXXX:0xYYYYYYY:0xZZZZZZZ : Enable trace output only for the specified address list.
|
||||
|
||||
|
||||
=item B<BOX64_UNITYPLAYER> =I<0|1>
|
||||
|
||||
+6
-5
@@ -1,3 +1,4 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
# Usage: python gen.py
|
||||
|
||||
import json
|
||||
@@ -281,16 +282,16 @@ for entry in data:
|
||||
# regex to match env.h C code
|
||||
regex = {
|
||||
"INTEGER": re.compile(
|
||||
r"^\s*INTEGER\((?P<define>\w+), (?P<name>\w+), (?P<default>\w+), (?P<min>\w+), (?P<max>\w+), (?P<wine>\w+)\)"
|
||||
r"^\s*INTEGER\((?P<define>\w+), (?P<name>\w+), (?P<default>\w+), (?P<min>\w+), (?P<max>\w+), (?P<wine>\w+)(?:, \w+)?\)"
|
||||
),
|
||||
"INTEGER64": re.compile(
|
||||
r"^\s*INTEGER64\((?P<define>\w+), (?P<name>\w+), (?P<default>\w+), (?P<wine>\w+)\)"
|
||||
r"^\s*INTEGER64\((?P<define>\w+), (?P<name>\w+), (?P<default>\w+), (?P<wine>\w+)(?:, \w+)?\)"
|
||||
),
|
||||
"BOOLEAN": re.compile(
|
||||
r"^\s*BOOLEAN\((?P<define>\w+), (?P<name>\w+), (?P<default>\w+), (?P<wine>\w+)\)"
|
||||
r"^\s*BOOLEAN\((?P<define>\w+), (?P<name>\w+), (?P<default>\w+), (?P<wine>\w+)(?:, \w+)?\)"
|
||||
),
|
||||
"ADDRESS": re.compile(r"^\s*ADDRESS\((?P<define>\w+), (?P<name>\w+), (?P<wine>\w+)\)"),
|
||||
"STRING": re.compile(r"^\s*STRING\((?P<define>\w+), (?P<name>\w+), (?P<wine>\w+)\)"),
|
||||
"ADDRESS": re.compile(r"^\s*ADDRESS\((?P<define>\w+), (?P<name>\w+), (?P<wine>\w+)(?:, \w+)?\)"),
|
||||
"STRING": re.compile(r"^\s*STRING\((?P<define>\w+), (?P<name>\w+), (?P<wine>\w+)(?:, \w+)?\)"),
|
||||
}
|
||||
|
||||
env_file = os.path.join(script_dir, "../../src/include/env.h")
|
||||
|
||||
+214
-90
File diff suppressed because it is too large.
Load diff
+40
-49
@@ -57,13 +57,6 @@
|
||||
"1": "模拟某个 AMD CPU 型号。"
|
||||
}
|
||||
},
|
||||
"BOX64_CRASHHANDLER": {
|
||||
"description": "是否使用模拟的 crashhandler.so 库。",
|
||||
"options": {
|
||||
"0": "在需要时使用模拟的 crashhandler.so 库。",
|
||||
"1": "使用内部定义的空 crashhandler.so 库。"
|
||||
}
|
||||
},
|
||||
"BOX64_DLSYM_ERROR": {
|
||||
"description": "启用或禁用 dlsym 错误的日志记录。",
|
||||
"options": {
|
||||
@@ -98,14 +91,14 @@
|
||||
"0": "不尝试构建尽可能大的代码块,适用于使用大量线程和 JIT 的程序(如 Unity)。",
|
||||
"1": "尽可能构建大的代码块。",
|
||||
"2": "构建更大的代码块,代码块重叠时不停止,但仅针对 elf 内存中的代码块。",
|
||||
"3": "构建更大的代码块,代码块重叠时不停止,适用于所有类型的内存,因此也对 wine 程序有用。"
|
||||
"3": "构建更大的代码块,代码块重叠时不停止,适用于所有类型的内存,因此也对 Wine 程序有用。"
|
||||
}
|
||||
},
|
||||
"BOX64_DYNAREC_BLEEDING_EDGE": {
|
||||
"description": "检测 MonoBleedingEdge 并应用保守设置(仅 Linux)。",
|
||||
"options": {
|
||||
"0": "不检测 MonoBleedingEdge。",
|
||||
"1": "检测 MonoBleedingEdge,并在检测到时应用 BOX64_DYNAREC_BIGBLOCK=0 和 BOX64_DYNAREC_强内存模型=1。"
|
||||
"1": "检测 MonoBleedingEdge,并在检测到时应用 BOX64_DYNAREC_BIGBLOCK=0 和 BOX64_DYNAREC_STRONGMEM=1。"
|
||||
}
|
||||
},
|
||||
"BOX64_DYNAREC_CALLRET": {
|
||||
@@ -113,15 +106,8 @@
|
||||
"options": {
|
||||
"0": "不优化 CALL/RET,使用跳转表。",
|
||||
"1": "尝试优化 CALL/RET,在可能的情况下跳过跳转表。",
|
||||
"2": "尝试优化 CALL/RET,在可能的情况下跳过跳转表,同时增加对返回到脏/已修改代码块的代码的处理。在 WowBox64 上不可用。"
|
||||
}
|
||||
},
|
||||
"BOX64_DYNAREC_SEP": {
|
||||
"description": "使用二级入口点(SEP)进一步优化 CALL/RET。如果 CALLRET 未启用则无效。",
|
||||
"options": {
|
||||
"0": "不在 CALLRET 返回时添加 SEP。",
|
||||
"1": "在 CALLRET 返回时添加 SEP,仅针对来自已知二进制文件的内存。",
|
||||
"2": "在 CALLRET 返回时添加 SEP,适用于所有类型的内存。"
|
||||
"2": "尝试优化 CALL/RET,在可能的情况下跳过跳转表,同时增加对返回到脏/已修改代码块的代码的处理。在 WowBox64 上不可用。",
|
||||
"3": "在 2 的基础上,额外跟踪代码块的使用情况,避免回收仍在使用中的代码块。"
|
||||
}
|
||||
},
|
||||
"BOX64_DYNAREC_DF": {
|
||||
@@ -158,7 +144,8 @@
|
||||
"options": {
|
||||
"0": "不转储代码块。",
|
||||
"1": "转储代码块。",
|
||||
"2": "转储代码块并带有颜色。"
|
||||
"2": "转储代码块并带有颜色。",
|
||||
"3": "仅转储 x86 指令和翻译后的本机指令。"
|
||||
}
|
||||
},
|
||||
"BOX64_DYNAREC_DUMP_RANGE": {
|
||||
@@ -167,6 +154,13 @@
|
||||
"0xXXXXXXXX-0xYYYYYYYY": "定义代码块 被转储的范围(左闭右开)。"
|
||||
}
|
||||
},
|
||||
"BOX64_DYNAREC_DISASM": {
|
||||
"description": "尝试初始化 libZydis,以在转储、追踪、崩溃报告等场景中获得更具可读性的 x86 反汇编结果。",
|
||||
"options": {
|
||||
"0": "不为 Dynarec 加载 Zydis。",
|
||||
"1": "尝试为 Dynarec 加载 Zydis。"
|
||||
}
|
||||
},
|
||||
"BOX64_DYNAREC_FASTNAN": {
|
||||
"description": "启用或禁用快速 NaN 处理。",
|
||||
"options": {
|
||||
@@ -183,11 +177,13 @@
|
||||
}
|
||||
},
|
||||
"BOX64_DYNAREC_FORWARD": {
|
||||
"description": "定义构建代码块时允许的最大前向跳转值。",
|
||||
"description": "定义构建代码块时允许的最大前向跳转值。仅接受 0、128、256、512 和 1024;其他值将回退为 128。",
|
||||
"options": {
|
||||
"0": "无前向跳转值。当前代码块结束时,即使存在之前的前向跳转也不尝试继续前进。",
|
||||
"128": "允许代码块结束与下一个前向跳转之间最多 128 字节的间隙。",
|
||||
"XXXX": "允许代码块结束与下一个前向跳转之间最多 XXXX 字节的间隙。"
|
||||
"256": "允许代码块结束与下一个前向跳转之间最多 256 字节的间隙。",
|
||||
"512": "允许代码块结束与下一个前向跳转之间最多 512 字节的间隙。",
|
||||
"1024": "允许代码块结束与下一个前向跳转之间最多 1024 字节的间隙。"
|
||||
}
|
||||
},
|
||||
"BOX64_DYNAREC_GDBJIT": {
|
||||
@@ -248,20 +244,6 @@
|
||||
"1": "DynaRec 将生成 perf 映射。"
|
||||
}
|
||||
},
|
||||
"BOX64_DYNAREC_PURGE": {
|
||||
"description": "根据年龄阈值(BOX64_DYNAREC_PURGE_AGE)清除最近未执行的代码块。",
|
||||
"options": {
|
||||
"0": "DynaRec 不会清除旧的未使用代码块。",
|
||||
"1": "DynaRec 将根据年龄阈值清除旧的未使用代码块。"
|
||||
}
|
||||
},
|
||||
"BOX64_DYNAREC_PURGE_AGE": {
|
||||
"description": "代码块清除的年龄阈值(需要 BOX64_DYNAREC_PURGE=1)。",
|
||||
"options": {
|
||||
"4096": "默认年龄阈值。",
|
||||
"XXXX": "自定义年龄阈值(范围:10-65536)。"
|
||||
}
|
||||
},
|
||||
"BOX64_DYNAREC_SAFEFLAGS": {
|
||||
"description": "在 CALL/RET 指令和其他边缘情况下 FLAGS 模拟的行为。",
|
||||
"options": {
|
||||
@@ -354,7 +336,7 @@
|
||||
}
|
||||
},
|
||||
"BOX64_DYNACACHE": {
|
||||
"description": "启用或禁用动态重编译器缓存(DynaCache)。此选项默认为 2(读取已有缓存但不生成新的)。DynaCache 默认将文件写入 home 文件夹,生成新缓存文件时会根据 BOX64_DYNACACHE_LIMIT 控制文件夹大小。",
|
||||
"description": "启用或禁用动态重编译器缓存(DynaCache)。此选项默认为 1(启用)。DynaCache 默认将文件写入 home 文件夹,生成新缓存文件时会根据 BOX64_DYNACACHE_LIMIT 控制文件夹大小。",
|
||||
"options": {
|
||||
"0": "禁用 DynaCache。",
|
||||
"1": "启用 DynaCache。",
|
||||
@@ -384,10 +366,10 @@
|
||||
}
|
||||
},
|
||||
"BOX64_DYNACACHE_MIN": {
|
||||
"description": "DynaCache 写入磁盘的最小大小(KB)。默认大小为 350KB。",
|
||||
"description": "DynaCache 写入磁盘的最小大小(KB)。默认大小为 30KB。",
|
||||
"options": {
|
||||
"XXXX": "设置将缓存写入磁盘的最小 DynaRec 代码大小(XXXX KB),小于此值将不会保存到磁盘。",
|
||||
"350": "默认值为 350 KB。"
|
||||
"30": "默认值为 30 KB。"
|
||||
}
|
||||
},
|
||||
"BOX64_EMULATED_LIBS": {
|
||||
@@ -464,7 +446,7 @@
|
||||
"description": "检测 libjvm 并应用保守设置。",
|
||||
"options": {
|
||||
"0": "不执行任何操作。",
|
||||
"1": "检测 libjvm,并在检测到时应用 BOX64_DYNAREC_BIGBLOCK=0 BOX64_DYNAREC_强内存模型=1 BOX64_SSE42=0。"
|
||||
"1": "检测 libjvm,并在检测到时应用 BOX64_DYNAREC_BIGBLOCK=0 BOX64_DYNAREC_STRONGMEM=1 BOX64_SSE42=0。"
|
||||
}
|
||||
},
|
||||
"BOX64_LD_LIBRARY_PATH": {
|
||||
@@ -615,6 +597,13 @@
|
||||
"1": "不加载 x64 Vulkan 覆盖层。"
|
||||
}
|
||||
},
|
||||
"BOX64_ONDEMAND_STEAMUI": {
|
||||
"description": "在游戏运行时关闭 Steam UI,游戏结束后重新打开。",
|
||||
"options": {
|
||||
"0": "禁用。",
|
||||
"1": "在游戏运行时关闭 Steam UI,游戏结束后重新打开。"
|
||||
}
|
||||
},
|
||||
"BOX64_PATH": {
|
||||
"description": "查找 x86_64 二进制文件的路径。",
|
||||
"options": {
|
||||
@@ -645,10 +634,10 @@
|
||||
"BOX64_PROFILE": {
|
||||
"description": "预定义的环境变量集合,以兼容性或性能为导向。",
|
||||
"options": {
|
||||
"safest": "禁用所有不安全的 DynaRec 优化的配置文件。",
|
||||
"safe": "比 safest 略不安全。",
|
||||
"safest": "禁用所有不安全的优化。",
|
||||
"safe": "仅启用小部分不安全的优化。",
|
||||
"default": "大多数程序都能正常运行且性能适中的默认设置。",
|
||||
"fast": "启用许多不安全的优化,但同时启用 强内存模型 模拟。",
|
||||
"fast": "启用许多不安全的优化,但同时启用强内存模型模拟。",
|
||||
"fastest": "启用许多不安全的优化以获得更好的性能。"
|
||||
}
|
||||
},
|
||||
@@ -722,10 +711,10 @@
|
||||
}
|
||||
},
|
||||
"BOX64_SSE_FLUSHTO0": {
|
||||
"description": "SSE Flush to 0 FLAGS的行为,同时追踪 SSE 异常FLAGS。",
|
||||
"description": "SSE Flush to 0 FLAGS的行为,同时追踪 SSE 异常 FLAGS。",
|
||||
"options": {
|
||||
"0": "仅追踪FLAGS。",
|
||||
"1": "直接应用 SSE Flush to 0 FLAGS。同时在 DynaRec 中反映 SSE 异常FLAGS(如果可用)。"
|
||||
"0": "仅追踪 FLAGS。",
|
||||
"1": "直接应用 SSE Flush to 0 FLAGS。同时在 DynaRec 中反映 SSE 异常 FLAGS(如果可用)。"
|
||||
}
|
||||
},
|
||||
"BOX64_SSE42": {
|
||||
@@ -778,7 +767,8 @@
|
||||
"0": "禁用追踪输出。",
|
||||
"1": "启用追踪输出。追踪在依赖项初始化之前开始。",
|
||||
"symbolname": "仅对 `symbolname` 启用追踪输出。追踪在依赖项初始化之前开始。",
|
||||
"0xXXXXXXX-0xYYYYYYY": "对指定地址范围(左闭右开)启用追踪输出。追踪在依赖项初始化之前开始。"
|
||||
"0xXXXXXXX-0xYYYYYYY": "对指定地址范围(左闭右开)启用追踪输出。追踪在依赖项初始化之前开始。",
|
||||
"0xXXXXXXX:0xYYYYYYY:0xZZZZZZZ": "对指定的地址列表启用追踪输出。追踪在依赖项初始化之前开始。"
|
||||
}
|
||||
},
|
||||
"BOX64_TRACE_START": {
|
||||
@@ -802,7 +792,8 @@
|
||||
"0": "禁用追踪输出。",
|
||||
"1": "启用追踪输出。",
|
||||
"symbolname": "仅对 `symbolname` 启用追踪输出。",
|
||||
"0xXXXXXXX-0xYYYYYYY": "对指定地址范围(左闭右开)启用追踪输出。"
|
||||
"0xXXXXXXX-0xYYYYYYY": "对指定地址范围(左闭右开)启用追踪输出。",
|
||||
"0xXXXXXXX:0xYYYYYYY:0xZZZZZZZ": "对指定地址列表启用追踪输出。"
|
||||
}
|
||||
},
|
||||
"BOX64_UNITYPLAYER": {
|
||||
@@ -816,7 +807,7 @@
|
||||
"description": "告诉 Box64 这是一个 Unity 游戏。",
|
||||
"options": {
|
||||
"0": "不执行任何操作。",
|
||||
"1": "这是 Unity 游戏,对 Windows 使用特殊的检测代码,对 Linux 应用 BOX64_DYNAREC_强内存模型=1。"
|
||||
"1": "这是 Unity 游戏,对 Windows 使用特殊的检测代码,对 Linux 应用 BOX64_DYNAREC_STRONGMEM=1。"
|
||||
}
|
||||
},
|
||||
"BOX64_WRAP_EGL": {
|
||||
@@ -861,4 +852,4 @@
|
||||
"1": "不为 32 位二进制文件切换 personality。"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-2
@@ -1,7 +1,9 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include "gdbjit.h"
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
static char block_name_buffer[16];
|
||||
static char block_name_buffer[2 * sizeof(uintptr_t) + 1];
|
||||
|
||||
static enum gdb_status read_debug_info(struct gdb_reader_funcs* self, struct gdb_symbol_callbacks* cbs, void* memory, long memory_sz)
|
||||
{
|
||||
@@ -9,7 +11,7 @@ static enum gdb_status read_debug_info(struct gdb_reader_funcs* self, struct gdb
|
||||
|
||||
struct gdb_object* object = cbs->object_open(cbs);
|
||||
struct gdb_symtab* symtab = cbs->symtab_open(cbs, object, block->filename);
|
||||
sprintf(block_name_buffer, "%x", block->x64start);
|
||||
sprintf(block_name_buffer, "%" PRIxPTR, block->x64start);
|
||||
cbs->block_open(cbs, symtab, NULL, block->start, block->end, block_name_buffer);
|
||||
|
||||
cbs->line_mapping_add(cbs, symtab, block->nlines, block->lines);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
# create necessary directories
|
||||
mkdir -p ~/steam/tmp # makes both ~/steam and ~/steam/tmp in one cmd
|
||||
|
||||
+7
-1
@@ -1,4 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
import os
|
||||
import sys
|
||||
@@ -416,8 +417,12 @@ def readFiles(files: Iterable[Filename]) -> Tuple[JumbledGlobals, JumbledRedirec
|
||||
or match("libc", "tcmallocminimal") \
|
||||
or match("libc", "tbbmallocproxy") \
|
||||
or match("libc", "androidshmem") \
|
||||
or match("libc", "mimalloc") \
|
||||
or match("crypto", "libssl3") \
|
||||
or match("tcmallocminimal", "tbbmallocproxy") \
|
||||
or match("tcmallocminimal", "mimalloc") \
|
||||
or match("tbbmallocproxy", "mimalloc") \
|
||||
or match("libbsd", "mimalloc") \
|
||||
or match("iconv", "libunistring2") \
|
||||
or match("gomp", "libomp"):
|
||||
continue
|
||||
@@ -1094,7 +1099,8 @@ def main(root: str, files: Iterable[Filename], ver: str):
|
||||
"""
|
||||
}
|
||||
|
||||
banner = "/********************************************************" + ('*'*len(ver)) + "***\n" \
|
||||
banner = "// SPDX-License-Identifier: MIT\n" \
|
||||
"/********************************************************" + ('*'*len(ver)) + "***\n" \
|
||||
" * File automatically generated by rebuild_wrappers.py (v" + ver + ") *\n" \
|
||||
" ********************************************************" + ('*'*len(ver)) + "***/\n"
|
||||
trim = lambda string: '\n'.join(line[2:] for line in string.splitlines())[1:]
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
import os
|
||||
import sys
|
||||
@@ -1405,7 +1406,8 @@ def generate_files(root: str, files: Iterable[str], ver: str, gbls: SortedGlobal
|
||||
#endif // __{filename}UNDEFS32_H_
|
||||
"""
|
||||
}
|
||||
banner = "/***********************************************************" + ('*'*len(ver)) + "***\n" \
|
||||
banner = "// SPDX-License-Identifier: MIT\n" \
|
||||
"/***********************************************************" + ('*'*len(ver)) + "***\n" \
|
||||
" * File automatically generated by rebuild_wrappers_32.py (v" + ver + ") *\n" \
|
||||
" ***********************************************************" + ('*'*len(ver)) + "***/\n"
|
||||
trim: Callable[[str], str] = lambda string: '\n'.join(line[2:] for line in string.splitlines())[1:]
|
||||
|
||||
@@ -17,6 +17,7 @@ endif()
|
||||
|
||||
set(ENV{BOX64_LOG} 0)
|
||||
set(ENV{BOX64_NOBANNER} 1)
|
||||
set(ENV{BOX64_DYNACACHE} 0)
|
||||
|
||||
# run the test program, capture the stdout/stderr and the result var
|
||||
execute_process(
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
|
||||
+12
-1
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#define _GNU_SOURCE /* See feature_test_macros(7) */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -349,6 +350,8 @@ void FreeBox64Context(box64context_t** context)
|
||||
ctx->atfork_sz = ctx->atfork_cap = 0;
|
||||
}
|
||||
|
||||
box_free(ctx->quick_cleanups);
|
||||
|
||||
for(int i=0; i<MAX_SIGNAL; ++i)
|
||||
if(ctx->signals[i]!=0 && ctx->signals[i]!=1) {
|
||||
signal(i, SIG_DFL);
|
||||
@@ -437,6 +440,7 @@ void FreeBox64Context(box64context_t** context)
|
||||
|
||||
int AddElfHeader(box64context_t* ctx, elfheader_t* head) {
|
||||
int idx = 0;
|
||||
mutex_lock(&ctx->mutex_tls);
|
||||
while(idx<ctx->elfsize && ctx->elfs[idx]) idx++;
|
||||
if(idx == ctx->elfsize) {
|
||||
if(idx==ctx->elfcap) {
|
||||
@@ -449,11 +453,13 @@ int AddElfHeader(box64context_t* ctx, elfheader_t* head) {
|
||||
} else {
|
||||
ctx->elfs[idx] = head;
|
||||
}
|
||||
mutex_unlock(&ctx->mutex_tls);
|
||||
printf_log(LOG_DEBUG, "Adding \"%s\" as #%d in elf collection\n", ElfName(head), idx);
|
||||
return idx;
|
||||
}
|
||||
|
||||
void RemoveElfHeader(box64context_t* ctx, elfheader_t* head) {
|
||||
mutex_lock(&ctx->mutex_tls);
|
||||
if(GetTLSBase(head)) {
|
||||
// should remove the tls info
|
||||
int tlsbase = GetTLSBase(head);
|
||||
@@ -465,19 +471,24 @@ void RemoveElfHeader(box64context_t* ctx, elfheader_t* head) {
|
||||
for(int i=0; i<ctx->elfsize; ++i)
|
||||
if(ctx->elfs[i] == head) {
|
||||
ctx->elfs[i] = NULL;
|
||||
mutex_unlock(&ctx->mutex_tls);
|
||||
return;
|
||||
}
|
||||
mutex_unlock(&ctx->mutex_tls);
|
||||
}
|
||||
|
||||
int AddTLSPartition(box64context_t* context, int tlssize) {
|
||||
mutex_lock(&context->mutex_tls);
|
||||
int oldsize = context->tlssize;
|
||||
// should in fact first try to map a hole, but rewinding all elfs and checking filled space, like with the mapmem utilities
|
||||
context->tlssize += tlssize;
|
||||
context->tlsdata = box_realloc(context->tlsdata, context->tlssize);
|
||||
memmove(context->tlsdata+tlssize, context->tlsdata, oldsize); // move to the top, using memmove as regions will probably overlap
|
||||
memset(context->tlsdata, 0, tlssize); // fill new space with 0 (not mandatory)
|
||||
int ret = -context->tlssize; // negative offset
|
||||
mutex_unlock(&context->mutex_tls);
|
||||
// clean GS segment for current emu?
|
||||
|
||||
return -context->tlssize; // negative offset
|
||||
return ret;
|
||||
}
|
||||
|
||||
+2
-1
@@ -1,8 +1,9 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#ifndef __BOX64_VERSION_H_
|
||||
#define __BOX64_VERSION_H_
|
||||
|
||||
#define BOX64_MAJOR 0
|
||||
#define BOX64_MINOR 4
|
||||
#define BOX64_REVISION 3
|
||||
#define BOX64_REVISION 5
|
||||
|
||||
#endif //__BOX64_VERSION_H_
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include "debug.h"
|
||||
#include "box64version.h"
|
||||
|
||||
+4
-1
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include "box64version.h"
|
||||
#ifdef NOGIT
|
||||
#define GITREV "nogit"
|
||||
@@ -28,7 +29,9 @@ void PrintBox64Version(int prefix);
|
||||
#define BOX64_BUILD_INFO_STR_HELPER(x) #x
|
||||
#define BOX64_BUILD_INFO_STR(x) BOX64_BUILD_INFO_STR_HELPER(x)
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef BOX64EC
|
||||
#define BOX64_STR "Box64EC"
|
||||
#elif defined(_WIN32)
|
||||
#define BOX64_STR "WowBox64"
|
||||
#else
|
||||
#define BOX64_STR "Box64"
|
||||
|
||||
+76
-18
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -11,6 +12,7 @@
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/mman.h>
|
||||
#include <pthread.h>
|
||||
#include <stdatomic.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdarg.h>
|
||||
@@ -29,6 +31,7 @@
|
||||
#include "debug.h"
|
||||
#include "fileutils.h"
|
||||
#include "box64context.h"
|
||||
#include "steamwebhelper.h"
|
||||
#include "box64cpu.h"
|
||||
#include "box64cpu_util.h"
|
||||
#include "wine_tools.h"
|
||||
@@ -57,6 +60,7 @@ extern box64env_t box64env;
|
||||
|
||||
int box64_quit = 0;
|
||||
int box64_exit_code = 0;
|
||||
int box64_in_fatal_handler = 0;
|
||||
int box64_stdout_no_w = 0;
|
||||
uintptr_t box64_pagesize;
|
||||
path_collection_t box64_addlibs = {0};
|
||||
@@ -68,8 +72,10 @@ int box64_mapclean = 0;
|
||||
int box64_zoom = 0;
|
||||
int box64_steam = 0;
|
||||
int box64_steamcmd = 0;
|
||||
int box64_srt_logger = 0;
|
||||
int box64_musl = 0;
|
||||
int box64_nolibs = 0;
|
||||
int box64_hasinterp = 0;
|
||||
char* box64_custom_gstreamer = NULL;
|
||||
int box64_tcmalloc_minimal = 0;
|
||||
uintptr_t fmod_smc_start = 0;
|
||||
@@ -90,6 +96,8 @@ const char* box64_wine_guest_name = NULL;
|
||||
|
||||
#ifdef HAVE_TRACE
|
||||
uintptr_t trace_start = 0, trace_end = 0;
|
||||
uintptr_t* trace_addrs = NULL;
|
||||
int trace_addrs_count = 0;
|
||||
char* trace_func = NULL;
|
||||
#endif
|
||||
|
||||
@@ -232,7 +240,9 @@ static void displayMiscInfo(void)
|
||||
|
||||
printf_log(LOG_INFO, "Running on %s with %d core%s, pagesize: %zd", box64_sysinfo.cpuname, box64_sysinfo.ncpu, box64_sysinfo.ncpu > 1 ? "s" : "", box64_pagesize);
|
||||
if (BOX64ENV(maxcpu))
|
||||
printf_log_prefix(0, LOG_INFO, ", emulating %d core%s\n", BOX64ENV(maxcpu), BOX64ENV(maxcpu) > 1 ? "s" : "");
|
||||
printf_log_prefix(0, LOG_INFO, ", emulating %d core%s", BOX64ENV(maxcpu), BOX64ENV(maxcpu) > 1 ? "s" : "");
|
||||
if (BOX64ENV(skipcpu))
|
||||
printf_log_prefix(0, LOG_INFO, " skipping %d core%s\n", BOX64ENV(skipcpu), BOX64ENV(skipcpu)>1? "s":"");
|
||||
else
|
||||
printf_log_prefix(0, LOG_INFO, "\n");
|
||||
computeRDTSC();
|
||||
@@ -350,10 +360,10 @@ void KillAllInstances()
|
||||
struct dirent* entry;
|
||||
ssize_t len;
|
||||
char proc_path[PATH_MAX];
|
||||
char exe_path[PATH_MAX];
|
||||
char exe_path[PATH_MAX+8];
|
||||
char exe_target[PATH_MAX];
|
||||
char self_name[PATH_MAX];
|
||||
char self_name_with_deleted[PATH_MAX];
|
||||
char self_name_with_deleted[PATH_MAX+16];
|
||||
|
||||
DIR* proc_dir = opendir("/proc");
|
||||
if (proc_dir == NULL) {
|
||||
@@ -467,7 +477,7 @@ static void setupZydis(box64context_t* context)
|
||||
if ((BOX64ENV(trace_init) && strcmp(BOX64ENV(trace_init), "0")) || (BOX64ENV(trace) && strcmp(BOX64ENV(trace), "0"))) {
|
||||
context->x64trace = 1;
|
||||
}
|
||||
if (context->x64trace) {
|
||||
if (context->x64trace || BOX64ENV(dynarec_disasm)) {
|
||||
printf_log(LOG_INFO, "Initializing Zydis lib\n");
|
||||
if (InitX64Trace(context)) {
|
||||
printf_log(LOG_INFO, "Zydis init failed. No x86 trace activated\n");
|
||||
@@ -542,6 +552,39 @@ void LoadLDPath(box64context_t *context)
|
||||
PrependList(&context->box64_ld_lib, getenv("LD_LIBRARY_PATH"), 1); // in case some of the path are for x86 world
|
||||
}
|
||||
|
||||
#ifdef HAVE_TRACE
|
||||
static void setupTraceAddrList(char *p)
|
||||
{
|
||||
int cap = 16;
|
||||
int count = 0;
|
||||
char *saveptr = NULL;
|
||||
|
||||
uintptr_t* addrs = (uintptr_t*)box_malloc(cap * sizeof(uintptr_t));
|
||||
char* tmp = box_strdup(p);
|
||||
char* tok = strtok_r(tmp, ":", &saveptr);
|
||||
|
||||
while (tok) {
|
||||
if (count >= cap) {
|
||||
cap *= 2;
|
||||
addrs = (uintptr_t*)box_realloc(addrs, cap * sizeof(uintptr_t));
|
||||
}
|
||||
|
||||
char* endptr;
|
||||
uintptr_t addr = (uintptr_t)strtoul(tok, &endptr, 0);
|
||||
if (endptr != tok)
|
||||
addrs[count++] = addr;
|
||||
|
||||
tok = strtok_r(NULL, ":", &saveptr);
|
||||
}
|
||||
|
||||
if (count > 0)
|
||||
SetTraceAddrs(addrs, count);
|
||||
|
||||
box_free(tmp);
|
||||
box_free(addrs);
|
||||
}
|
||||
#endif
|
||||
|
||||
EXPORTDYN
|
||||
void setupTraceInit()
|
||||
{
|
||||
@@ -561,6 +604,9 @@ void setupTraceInit()
|
||||
}
|
||||
if(s_trace_start || s_trace_end)
|
||||
SetTraceEmu(s_trace_start, s_trace_end);
|
||||
} else if (strchr(p,':')) {
|
||||
// Parse BOX64_TRACE=0x1000:0x2000:0x3000 format.
|
||||
setupTraceAddrList(p);
|
||||
} else {
|
||||
int veropt = 1;
|
||||
int ver = 0;
|
||||
@@ -638,6 +684,9 @@ void setupTrace()
|
||||
printf_log(LOG_INFO, "TRACE on %s only (%p-%p)\n", p, (void*)s_trace_start, (void*)s_trace_end);
|
||||
}
|
||||
}
|
||||
} else if (strchr(p,':')) {
|
||||
// Parse BOX64_TRACE=0x1000:0x2000:0x3000 format.
|
||||
setupTraceAddrList(p);
|
||||
} else {
|
||||
int search = 0;
|
||||
if (my_context->elfs) {
|
||||
@@ -682,6 +731,8 @@ void endBox64()
|
||||
x64emu_t* emu = thread_get_emu();
|
||||
void startTimedExit();
|
||||
startTimedExit();
|
||||
printf_log(LOG_DEBUG, "Calling thread_local destructors (exiting box64)\n");
|
||||
CallThreadCleanup(emu);
|
||||
// atexit first
|
||||
printf_log(LOG_DEBUG, "Calling atexit registered functions (exiting box64)\n");
|
||||
CallAllCleanup(emu);
|
||||
@@ -694,14 +745,14 @@ void endBox64()
|
||||
// unload needed libs
|
||||
needed_libs_t* needed = my_context->elfs[0]->needed;
|
||||
printf_log(LOG_DEBUG, "Unloaded main elf: Will Dec RefCount of %d libs\n", needed?needed->size:0);
|
||||
int workers = get_active_emu_workers();
|
||||
int workers = atomic_load_explicit(&g_active_emu_workers, memory_order_relaxed);
|
||||
if (workers > 0) {
|
||||
const int sleep_us = 10000; // 10ms
|
||||
const int max_wait_ms = 2000; // 2s
|
||||
int waited_ms = 0;
|
||||
|
||||
printf_log(LOG_DEBUG, "endBox64: waiting emu workers to exit (n=%d)\n", workers);
|
||||
while ((workers = get_active_emu_workers()) > 0 && waited_ms < max_wait_ms) {
|
||||
while ((workers = atomic_load_explicit(&g_active_emu_workers, memory_order_relaxed)) > 0 && waited_ms < max_wait_ms) {
|
||||
usleep(sleep_us);
|
||||
waited_ms += sleep_us / 1000;
|
||||
}
|
||||
@@ -794,14 +845,7 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int is_test = 0;
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (!strcmp(argv[i], "--test") || !strcmp(argv[i], "-t")) {
|
||||
is_test = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (is_test) {
|
||||
if (argc >= 3 && (!strcmp(argv[1], "--test") || !strcmp(argv[1], "-t"))) {
|
||||
box64_unittest_mode = 1;
|
||||
exit(unittest(argc, argv));
|
||||
}
|
||||
@@ -836,14 +880,14 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
|
||||
DynaCacheClean();
|
||||
exit(0);
|
||||
}
|
||||
if(!strcmp(prog, "--dynacache-list")) {
|
||||
if(!strcmp(prog, "-dl") || !strcmp(prog, "--dynacache-list")) {
|
||||
#ifdef DYNAREC
|
||||
DetectHostCpuFeatures();
|
||||
#endif
|
||||
DynaCacheList(argv[nextarg+1]);
|
||||
exit(0);
|
||||
}
|
||||
if(!strcmp(prog, "--dynacache-clean")) {
|
||||
if(!strcmp(prog, "-dc") || !strcmp(prog, "--dynacache-clean")) {
|
||||
#ifdef DYNAREC
|
||||
DetectHostCpuFeatures();
|
||||
#endif
|
||||
@@ -971,11 +1015,16 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
|
||||
} else if(!strcmp(prog_, "steamcmd")) {
|
||||
printf_log(LOG_INFO, "steamcmd detected\n");
|
||||
box64_steamcmd = 1;
|
||||
} else if(!strcmp(prog_, "srt-logger")) {
|
||||
box64_srt_logger = 1;
|
||||
} else if(!strcmp(prog_, "wineserver")) {
|
||||
// check if this is wineserver
|
||||
box64_wine = 1;
|
||||
}
|
||||
// Create a new context
|
||||
#ifdef BOX32
|
||||
box64_is32bits = FileIsX86ELF(prog);
|
||||
#endif
|
||||
my_context = NewBox64Context(argc - nextarg);
|
||||
|
||||
addLibPaths(my_context);
|
||||
@@ -1140,8 +1189,10 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
|
||||
if (applied) {
|
||||
printf_log(LOG_INFO, "Applied settings from rcfile\n");
|
||||
displayMiscInfo();
|
||||
PrintEnvVariables(&box64env, LOG_INFO);
|
||||
}
|
||||
if (BOX64ENV(ondemand_steamui) && (!strcmp(box64_guest_name, "steam") || !strcmp(box64_guest_name, "steamwebhelper")))
|
||||
StartOnDemandSteamUI();
|
||||
PrintEnvVariables(&box64env, LOG_INFO);
|
||||
setupZydis(my_context);
|
||||
|
||||
for(int i=1; i<my_context->argc; ++i) {
|
||||
@@ -1289,6 +1340,10 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
|
||||
int script = my_context->bashpath?FileIsShell(my_context->fullpath):0;
|
||||
int python3 = my_context->pythonpath?FileIsPython(my_context->fullpath):0;
|
||||
printf_log(LOG_NONE, "Error: Reading elf header of %s, Try to launch %s instead\n", my_context->fullpath, x86?"using box86":(script?"using bash":"natively"));
|
||||
#ifndef BOX32
|
||||
if(!x86 && !my_context->box86path && FileIsX86ELF(my_context->fullpath))
|
||||
printf_log(LOG_NONE, "Maybe you should enable BOX32 when building Box64 to enable 32bits program to be run\n");
|
||||
#endif
|
||||
fclose(f);
|
||||
FreeCollection(&ld_preload);
|
||||
int ret;
|
||||
@@ -1437,8 +1492,9 @@ int initialize(int argc, const char **argv, char** env, x64emu_t** emulator, elf
|
||||
my_context->orig_argc = argc;
|
||||
my_context->orig_argv = (char**)argv;
|
||||
}
|
||||
box64_hasinterp = hasElfInterp(elf_header);
|
||||
box64_nolibs = (NeededLibs(elf_header)==0);
|
||||
if(box64_nolibs) printf_log(LOG_INFO, "Warning, box64 is not really compatible with staticaly linked binaries. Expect crash!\n");
|
||||
if(!box64_hasinterp) printf_log(LOG_INFO, "Warning, box64 is not really compatible with staticaly linked binaries. Expect crash!\n");
|
||||
box64_isglibc234 = GetNeededVersionForLib(elf_header, "libc.so.6", "GLIBC_2.34");
|
||||
if(box64_isglibc234)
|
||||
printf_log(LOG_DEBUG, "Program linked with GLIBC 2.34+\n");
|
||||
@@ -1549,12 +1605,14 @@ int emulate(x64emu_t* emu, elfheader_t* elf_header)
|
||||
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
|
||||
if(!box64_hasinterp) SetEDX(emu, 0);
|
||||
} 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
|
||||
if(!box64_hasinterp) SetRDX(emu, 0);
|
||||
}
|
||||
DynaRun(emu);
|
||||
// Get EAX
|
||||
|
||||
+642
-515
File diff suppressed because it is too large.
Load diff
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#define _GNU_SOURCE /* See feature_test_macros(7) */
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#ifndef __ARM64_EMITTER_H__
|
||||
#define __ARM64_EMITTER_H__
|
||||
/*
|
||||
@@ -229,25 +230,25 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#define LDURSBx_I9(Rt, Rn, imm9) EMIT(LDU_gen(0b00, 0b10, imm9, Rn, Rt))
|
||||
#define LDURSBxw_I9(Rt, Rn, imm9) EMIT(LDU_gen(0b00, (rex.w)?0b10:0b11, imm9, Rn, Rt))
|
||||
|
||||
#define LDxw(A, B, C) if(unscaled) {LDURxw_I9(A, B, C);} else {LDRxw_U12(A, B, C);}
|
||||
#define LDz(A, B, C) if(unscaled) {LDURz_I9(A, B, C);} else {LDRz_U12(A, B, C);}
|
||||
#define LDx(A, B, C) if(unscaled) {LDURx_I9(A, B, C);} else {LDRx_U12(A, B, C);}
|
||||
#define LDW(A, B, C) if(unscaled) {LDURw_I9(A, B, C);} else {LDRw_U12(A, B, C);}
|
||||
#define LDH(A, B, C) if(unscaled) {LDURH_I9(A, B, C);} else {LDRH_U12(A, B, C);}
|
||||
#define LDB(A, B, C) if(unscaled) {LDURB_I9(A, B, C);} else {LDRB_U12(A, B, C);}
|
||||
#define LDSW(A, B, C) if(unscaled) {LDURSW_I9(A, B, C);} else {LDRSW_U12(A, B, C);}
|
||||
#define LDSHxw(A, B, C) if(unscaled) {LDURSHxw_I9(A, B, C);} else {LDRSHxw_U12(A, B, C);}
|
||||
#define LDSHx(A, B, C) if(unscaled) {LDURSHx_I9(A, B, C);} else {LDRSHx_U12(A, B, C);}
|
||||
#define LDSHw(A, B, C) if(unscaled) {LDURSHw_I9(A, B, C);} else {LDRSHw_U12(A, B, C);}
|
||||
#define LDSBxw(A, B, C) if(unscaled) {LDURSBxw_I9(A, B, C);} else {LDRSBxw_U12(A, B, C);}
|
||||
#define LDSBx(A, B, C) if(unscaled) {LDURSBx_I9(A, B, C);} else {LDRSBx_U12(A, B, C);}
|
||||
#define LDSBw(A, B, C) if(unscaled) {LDURSBw_I9(A, B, C);} else {LDRSBw_U12(A, B, C);}
|
||||
#define STxw(A, B, C) if(unscaled) {STURxw_I9(A, B, C);} else {STRxw_U12(A, B, C);}
|
||||
#define STz(A, B, C) if(unscaled) {STURz_I9(A, B, C);} else {STRz_U12(A, B, C);}
|
||||
#define STx(A, B, C) if(unscaled) {STURx_I9(A, B, C);} else {STRx_U12(A, B, C);}
|
||||
#define STW(A, B, C) if(unscaled) {STURw_I9(A, B, C);} else {STRw_U12(A, B, C);}
|
||||
#define STH(A, B, C) if(unscaled) {STURH_I9(A, B, C);} else {STRH_U12(A, B, C);}
|
||||
#define STB(A, B, C) if(unscaled) {STURB_I9(A, B, C);} else {STRB_U12(A, B, C);}
|
||||
#define LDxw(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {LDAPURxw(A, B, C);} else if(unscaled) {LDURxw_I9(A, B, C);} else {LDRxw_U12(A, B, C);}} while(0)
|
||||
#define LDz(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {LDAPURz(A, B, C);} else if(unscaled) {LDURz_I9(A, B, C);} else {LDRz_U12(A, B, C);}} while(0)
|
||||
#define LDx(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {LDAPURx(A, B, C);} else if(unscaled) {LDURx_I9(A, B, C);} else {LDRx_U12(A, B, C);}} while(0)
|
||||
#define LDW(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {LDAPURw(A, B, C);} else if(unscaled) {LDURw_I9(A, B, C);} else {LDRw_U12(A, B, C);}} while(0)
|
||||
#define LDH(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {LDAPURH(A, B, C);} else if(unscaled) {LDURH_I9(A, B, C);} else {LDRH_U12(A, B, C);}} while(0)
|
||||
#define LDB(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {LDAPURB(A, B, C);} else if(unscaled) {LDURB_I9(A, B, C);} else {LDRB_U12(A, B, C);}} while(0)
|
||||
#define LDSW(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {LDAPURSW(A, B, C);} else if(unscaled) {LDURSW_I9(A, B, C);} else {LDRSW_U12(A, B, C);}} while (0)
|
||||
#define LDSHxw(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {LDAPURSHxw(A, B, C);} else if(unscaled) {LDURSHxw_I9(A, B, C);} else {LDRSHxw_U12(A, B, C);}} while (0)
|
||||
#define LDSHx(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {LDAPURSHx(A, B, C);} else if(unscaled) {LDURSHx_I9(A, B, C);} else {LDRSHx_U12(A, B, C);}} while (0)
|
||||
#define LDSHw(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {LDAPURSHw(A, B, C);} else if(unscaled) {LDURSHw_I9(A, B, C);} else {LDRSHw_U12(A, B, C);}} while (0)
|
||||
#define LDSBxw(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {LDAPURSBxw(A, B, C);} else if(unscaled) {LDURSBxw_I9(A, B, C);} else {LDRSBxw_U12(A, B, C);}} while (0)
|
||||
#define LDSBx(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {LDAPURSBx(A, B, C);} else if(unscaled) {LDURSBx_I9(A, B, C);} else {LDRSBx_U12(A, B, C);}} while (0)
|
||||
#define LDSBw(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {LDAPURSBw(A, B, C);} else if(unscaled) {LDURSBw_I9(A, B, C);} else {LDRSBw_U12(A, B, C);}} while (0)
|
||||
#define STxw(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {STLURxw(A, B, C);} else if(unscaled) {STURxw_I9(A, B, C);} else {STRxw_U12(A, B, C);}} while(0)
|
||||
#define STz(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {STLURz(A, B, C);} else if(unscaled) {STURz_I9(A, B, C);} else {STRz_U12(A, B, C);}} while(0)
|
||||
#define STx(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {STLURx(A, B, C);} else if(unscaled) {STURx_I9(A, B, C);} else {STRx_U12(A, B, C);}} while(0)
|
||||
#define STW(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {STLURw(A, B, C);} else if(unscaled) {STURw_I9(A, B, C);} else {STRw_U12(A, B, C);}} while(0)
|
||||
#define STH(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {STLURH(A, B, C);} else if(unscaled) {STURH_I9(A, B, C);} else {STRH_U12(A, B, C);}} while(0)
|
||||
#define STB(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {STLURB(A, B, C);} else if(unscaled) {STURB_I9(A, B, C);} else {STRB_U12(A, B, C);}} while(0)
|
||||
|
||||
// STR
|
||||
#define STR_gen(size, op1, imm9, op2, Rn, Rt) ((size)<<30 | 0b111<<27 | (op1)<<24 | 0b00<<22 | (imm9)<<12 | (op2)<<10 | (Rn)<<5 | (Rt))
|
||||
@@ -463,9 +464,9 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#define CSINVx(Rd, Rn, Rm, cond) EMIT(CSINV_gen(1, Rm, cond, Rn, Rd))
|
||||
#define CSINVw(Rd, Rn, Rm, cond) EMIT(CSINV_gen(0, Rm, cond, Rn, Rd))
|
||||
#define CSINVxw(Rd, Rn, Rm, cond) EMIT(CSINV_gen(rex.w, Rm, cond, Rn, Rd))
|
||||
#define CINVx(Rd, Rn, cond) CSINVx(Rd, Rn, Rn, invertCond(cond))
|
||||
#define CINVw(Rd, Rn, cond) CSINVw(Rd, Rn, Rn, invertCond(cond))
|
||||
#define CINVxw(Rd, Rn, cond) CSINVxw(Rd, Rn, Rn, invertCond(cond))
|
||||
#define CINVx(Rd, Rn, cond) CSINVx(Rd, Rn, Rn, invCond(cond))
|
||||
#define CINVw(Rd, Rn, cond) CSINVw(Rd, Rn, Rn, invCond(cond))
|
||||
#define CINVxw(Rd, Rn, cond) CSINVxw(Rd, Rn, Rn, invCond(cond))
|
||||
#define CSETMx(Rd, cond) CSINVx(Rd, xZR, xZR, invCond(cond))
|
||||
#define CSETMw(Rd, cond) CSINVw(Rd, xZR, xZR, invCond(cond))
|
||||
#define CSETMxw(Rd, cond) CSINVxw(Rd, xZR, xZR, invCond(cond))
|
||||
@@ -479,9 +480,9 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#define CSNEGx(Rd, Rn, Rm, cond) EMIT(CSNEG_gen(1, Rm, cond, Rn, Rd))
|
||||
#define CSNEGw(Rd, Rn, Rm, cond) EMIT(CSNEG_gen(0, Rm, cond, Rn, Rd))
|
||||
#define CSNEGxw(Rd, Rn, Rm, cond) EMIT(CSNEG_gen(rex.w, Rm, cond, Rn, Rd))
|
||||
#define CNEGx(Rd, Rn, cond) CSNEGx(Rn, Rn, Rd, invCond(cond))
|
||||
#define CNEGw(Rd, Rn, cond) CSNEGw(Rn, Rn, Rd, invCond(cond))
|
||||
#define CNEGxw(Rd, Rn, cond) CSNEGxw(Rn, Rn, Rd, invCond(cond))
|
||||
#define CNEGx(Rd, Rn, cond) CSNEGx(Rd, Rn, Rn, invCond(cond))
|
||||
#define CNEGw(Rd, Rn, cond) CSNEGw(Rd, Rn, Rn, invCond(cond))
|
||||
#define CNEGxw(Rd, Rn, cond) CSNEGxw(Rd, Rn, Rn, invCond(cond))
|
||||
|
||||
// AND / ORR
|
||||
#define LOGIC_gen(sf, opc, N, immr, imms, Rn, Rd) ((sf)<<31 | (opc)<<29 | 0b100100<<23 | (N)<<22 | (immr)<<16 | (imms)<<10 | (Rn)<<5 | Rd)
|
||||
@@ -648,9 +649,9 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#define ASRx(Rd, Rn, shift) SBFMx(Rd, Rn, shift, 63)
|
||||
#define ASRw(Rd, Rn, shift) SBFMw(Rd, Rn, shift, 31)
|
||||
#define ASRxw(Rd, Rn, shift) SBFMxw(Rd, Rn, shift, rex.w?63:31)
|
||||
#define SBFIZx(Rd, Rn, lsb, width) SFBFMx(Rd, Rn, ((-(lsb))%64), (width)-1)
|
||||
#define SBFIZw(Rd, Rn, lsb, width) SFBFMw(Rd, Rn, ((-(lsb))%32), (width)-1)
|
||||
#define SBFIZxw(Rd, Rn, lsb, width) SFBFMxw(Rd, Rn, ((-(lsb))%(rex.w?64:32)), (width)-1)
|
||||
#define SBFIZx(Rd, Rn, lsb, width) SBFMx(Rd, Rn, ((-(lsb))%64), (width)-1)
|
||||
#define SBFIZw(Rd, Rn, lsb, width) SBFMw(Rd, Rn, ((-(lsb))%32), (width)-1)
|
||||
#define SBFIZxw(Rd, Rn, lsb, width) SBFMxw(Rd, Rn, ((-(lsb))%(rex.w?64:32)), (width)-1)
|
||||
|
||||
// EXTR
|
||||
#define EXTR_gen(sf, N, Rm, imms, Rn, Rd) ((sf)<<31 | 0b00<<29 | 0b100111<<23 | (N)<<22 | (Rm)<<16 | (imms)<<10 | (Rn)<<5 | (Rd))
|
||||
@@ -827,26 +828,26 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#define VSTR64_I9(Vt, Rn, imm9) EMIT(VMEMUR_vector(0b11, 0b00, (imm9)&0b111111111, Rn, Vt))
|
||||
#define VSTR128_I9(Vt, Rn, imm9) EMIT(VMEMUR_vector(0b00, 0b10, (imm9)&0b111111111, Rn, Vt))
|
||||
|
||||
#define VLD128(A, B, C) if(unscaled) {VLDR128_I9(A, B, C);} else {VLDR128_U12(A, B, C);}
|
||||
#define VLD64(A, B, C) if(unscaled) {VLDR64_I9(A, B, C);} else {VLDR64_U12(A, B, C);}
|
||||
#define VLD32(A, B, C) if(unscaled) {VLDR32_I9(A, B, C);} else {VLDR32_U12(A, B, C);}
|
||||
#define VLD16(A, B, C) if(unscaled) {VLDR16_I9(A, B, C);} else {VLDR16_U12(A, B, C);}
|
||||
#define VLD8(A, B, C) if(unscaled) {VLDR8_I9(A, B, C);} else {VLDR8_U12(A, B, C);}
|
||||
#define VST128(A, B, C) if(unscaled) {VSTR128_I9(A, B, C);} else {VSTR128_U12(A, B, C);}
|
||||
#define VST64(A, B, C) if(unscaled) {VSTR64_I9(A, B, C);} else {VSTR64_U12(A, B, C);}
|
||||
#define VST32(A, B, C) if(unscaled) {VSTR32_I9(A, B, C);} else {VSTR32_U12(A, B, C);}
|
||||
#define VST16(A, B, C) if(unscaled) {VSTR16_I9(A, B, C);} else {VSTR16_U12(A, B, C);}
|
||||
#define VST8(A, B, C) if(unscaled) {VSTR8_I9(A, B, C);} else {VSTR8_U12(A, B, C);}
|
||||
#define VLD128(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {VLDAPUR128(A, B, C);} else if(unscaled) {VLDR128_I9(A, B, C);} else {VLDR128_U12(A, B, C);}} while(0)
|
||||
#define VLD64(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {VLDAPUR64(A, B, C);} else if(unscaled) {VLDR64_I9(A, B, C);} else {VLDR64_U12(A, B, C);}} while(0)
|
||||
#define VLD32(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {VLDAPUR32(A, B, C);} else if(unscaled) {VLDR32_I9(A, B, C);} else {VLDR32_U12(A, B, C);}} while(0)
|
||||
#define VLD16(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {VLDAPUR16(A, B, C);} else if(unscaled) {VLDR16_I9(A, B, C);} else {VLDR16_U12(A, B, C);}} while(0)
|
||||
#define VLD8(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {VLDAPUR8(A, B, C);} else if(unscaled) {VLDR8_I9(A, B, C);} else {VLDR8_U12(A, B, C);}} while(0)
|
||||
#define VST128(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {VSTLUR128(A, B, C);} else if(unscaled) {VSTR128_I9(A, B, C);} else {VSTR128_U12(A, B, C);}} while (0)
|
||||
#define VST64(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {VSTLUR64(A, B, C);} else if(unscaled) {VSTR64_I9(A, B, C);} else {VSTR64_U12(A, B, C);}} while (0)
|
||||
#define VST32(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {VSTLUR32(A, B, C);} else if(unscaled) {VSTR32_I9(A, B, C);} else {VSTR32_U12(A, B, C);}} while (0)
|
||||
#define VST16(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {VSTLUR16(A, B, C);} else if(unscaled) {VSTR16_I9(A, B, C);} else {VSTR16_U12(A, B, C);}} while (0)
|
||||
#define VST8(A, B, C) do {if(dyn->insts[ninst].use_lrcpc) {VSTLUR8(A, B, C);} else if(unscaled) {VSTR8_I9(A, B, C);} else {VSTR8_U12(A, B, C);}} while (0)
|
||||
|
||||
#define VMEMW_gen(size, opc, imm9, op2, Rn, Rt) ((size)<<30 | 0b111<<27 | 1<<26 | (opc)<<22 | (imm9)<<12 | (op2)<<10 | 0b01<<10 | (Rn)<<5 | (Rt))
|
||||
#define VLDR64_S9_postindex(Rt, Rn, imm9) EMIT(VMEMW_gen(0b11, 0b01, (imm9)&0x1ff, 0b01, Rn, Rt))
|
||||
#define VLDR64_S9_preindex(Rt, Rn, imm9) EMIT(VMEMW_gen(0b11, 0b01, (imm9)&0x1ff, 0b11, Rn, Rt))
|
||||
#define VLDR128_S9_postindex(Rt, Rn, imm9) EMIT(VMEMW_gen(0b11, 0b11, (imm9)&0x1ff, 0b01, Rn, Rt))
|
||||
#define VLDR128_S9_preindex(Rt, Rn, imm9) EMIT(VMEMW_gen(0b11, 0b11, (imm9)&0x1ff, 0b11, Rn, Rt))
|
||||
#define VLDR128_S9_postindex(Rt, Rn, imm9) EMIT(VMEMW_gen(0b00, 0b11, (imm9)&0x1ff, 0b01, Rn, Rt))
|
||||
#define VLDR128_S9_preindex(Rt, Rn, imm9) EMIT(VMEMW_gen(0b00, 0b11, (imm9)&0x1ff, 0b11, Rn, Rt))
|
||||
#define VSTR64_S9_postindex(Rt, Rn, imm9) EMIT(VMEMW_gen(0b11, 0b00, (imm9)&0x1ff, 0b01, Rn, Rt))
|
||||
#define VSTR64_S9_preindex(Rt, Rn, imm9) EMIT(VMEMW_gen(0b11, 0b00, (imm9)&0x1ff, 0b11, Rn, Rt))
|
||||
#define VSTR128_S9_postindex(Rt, Rn, imm9) EMIT(VMEMW_gen(0b11, 0b10, (imm9)&0x1ff, 0b01, Rn, Rt))
|
||||
#define VSTR128_S9_preindex(Rt, Rn, imm9) EMIT(VMEMW_gen(0b11, 0b10, (imm9)&0x1ff, 0b11, Rn, Rt))
|
||||
#define VSTR128_S9_postindex(Rt, Rn, imm9) EMIT(VMEMW_gen(0b00, 0b10, (imm9)&0x1ff, 0b01, Rn, Rt))
|
||||
#define VSTR128_S9_preindex(Rt, Rn, imm9) EMIT(VMEMW_gen(0b00, 0b10, (imm9)&0x1ff, 0b11, Rn, Rt))
|
||||
|
||||
#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))
|
||||
|
||||
@@ -902,7 +903,7 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#define VEORQ(Vd, Vn, Vm) EMIT(VLOGIC_gen(1, 0b00, Vm, Vn, Vd))
|
||||
#define VEOR(Vd, Vn, Vm) EMIT(VLOGIC_gen(0, 0b00, Vm, Vn, Vd))
|
||||
|
||||
#define VLOGIC_immediate(Q, op, abc, cmade, defgh, Rd) ((Q)<<30 | (op)<<29 | 0b0111100000<<19 | (abc)<<16 | (cmode)<<12 | 1<<10 | (defgh)<<5 | (Rd))
|
||||
#define VLOGIC_immediate(Q, op, abc, cmode, defgh, Rd) ((Q)<<30 | (op)<<29 | 0b0111100000<<19 | (abc)<<16 | (cmode)<<12 | 1<<10 | (defgh)<<5 | (Rd))
|
||||
//#define V
|
||||
|
||||
#define SHL_vector(Q, immh, immb, Rn, Rd) ((Q)<<30 | 0b011110<<23 | (immh)<<19 | (immb)<<16 | 0b01010<<11 | 1<<10 | (Rn)<<5 | (Rd))
|
||||
@@ -962,7 +963,7 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#define VEXTQ_8(Rd, Rn, Rm, index) EMIT(EXT_vector(1, Rm, index, Rn, Rd))
|
||||
|
||||
// Shift Left and Insert (not touching lower part of dest)
|
||||
#define SLI_vector(Q, immh, immb, Rn, Rd) ((Q)<<30 | 1<<29 | 0b011110<<23 | (immh)<<19 | (immb)<<16 | 0b01010<<1 | 1<<10 | (Rn)<<5 | (Rd))
|
||||
#define VSLI_vector(Q, immh, immb, Rn, Rd) ((Q)<<30 | 1<<29 | 0b011110<<23 | (immh)<<19 | (immb)<<16 | 0b01010<<11 | 1<<10 | (Rn)<<5 | (Rd))
|
||||
#define VSLIQ_8(Vd, Vn, shift) EMIT(VSLI_vector(1, 0b0001, (shift)&7, Vn, Vd))
|
||||
#define VSLIQ_16(Vd, Vn, shift) EMIT(VSLI_vector(1, 0b0010 | ((shift)>>3)&1, (shift)&7, Vn, Vd))
|
||||
#define VSLIQ_32(Vd, Vn, shift) EMIT(VSLI_vector(1, 0b0100 | (((shift)>>3)&3), (shift)&7, Vn, Vd))
|
||||
@@ -972,14 +973,14 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#define VSLI_32(Vd, Vn, shift) EMIT(VSLI_vector(0, 0b0100 | (((shift)>>3)&3), (shift)&7, Vn, Vd))
|
||||
|
||||
// Shift Right and Insert (not touching higher part of dest)
|
||||
#define SRI_vector(Q, immh, immb, Rn, Rd) ((Q)<<30 | 1<<29 | 0b011110<<23 | (immh)<<19 | (immb)<<16 | 0b01000<<1 | 1<<10 | (Rn)<<5 | (Rd))
|
||||
#define VSRIQ_8(Vd, Vn, shift) EMIT(VSRI_vector(1, 0b0001, (shift)&7, Vn, Vd))
|
||||
#define VSRIQ_16(Vd, Vn, shift) EMIT(VSRI_vector(1, 0b0010 | ((shift)>>3)&1, (shift)&7, Vn, Vd))
|
||||
#define VSRIQ_32(Vd, Vn, shift) EMIT(VSRI_vector(1, 0b0100 | (((shift)>>3)&3), (shift)&7, Vn, Vd))
|
||||
#define VSRIQ_64(Vd, Vn, shift) EMIT(VSRI_vector(1, 0b1000 | (((shift)>>3)&7), (shift)&7, Vn, Vd))
|
||||
#define VSRI_8(Vd, Vn, shift) EMIT(VSRI_vector(0, 0b0001, (shift)&7, Vn, Vd))
|
||||
#define VSRI_16(Vd, Vn, shift) EMIT(VSRI_vector(0, 0b0010 | ((shift)>>3)&1, (shift)&7, Vn, Vd))
|
||||
#define VSRI_32(Vd, Vn, shift) EMIT(VSRI_vector(0, 0b0100 | (((shift)>>3)&3), (shift)&7, Vn, Vd))
|
||||
#define VSRI_vector(Q, immh, immb, Rn, Rd) ((Q)<<30 | 1<<29 | 0b011110<<23 | (immh)<<19 | (immb)<<16 | 0b01000<<11 | 1<<10 | (Rn)<<5 | (Rd))
|
||||
#define VSRIQ_8(Vd, Vn, shift) EMIT(VSRI_vector(1, 0b0001, (8-(shift))&7, Vn, Vd))
|
||||
#define VSRIQ_16(Vd, Vn, shift) EMIT(VSRI_vector(1, 0b0010 | ((16-(shift))>>3)&1, (16-(shift))&7, Vn, Vd))
|
||||
#define VSRIQ_32(Vd, Vn, shift) EMIT(VSRI_vector(1, 0b0100 | ((32-(shift))>>3)&3, (32-(shift))&7, Vn, Vd))
|
||||
#define VSRIQ_64(Vd, Vn, shift) EMIT(VSRI_vector(1, 0b1000 | ((64-(shift))>>3)&7, (64-(shift))&7, Vn, Vd))
|
||||
#define VSRI_8(Vd, Vn, shift) EMIT(VSRI_vector(0, 0b0001, (8-(shift))&7, Vn, Vd))
|
||||
#define VSRI_16(Vd, Vn, shift) EMIT(VSRI_vector(0, 0b0010 | ((16-(shift))>>3)&1, (16-(shift))&7, Vn, Vd))
|
||||
#define VSRI_32(Vd, Vn, shift) EMIT(VSRI_vector(0, 0b0100 | ((32-(shift))>>3)&3, (32-(shift))&7, Vn, Vd))
|
||||
|
||||
// Reverse elements in 64-bit doublewords (vector). This instruction reverses the order of 8-bit, 16-bit, or 32-bit elements in each doubleword
|
||||
#define VREVx_vector(Q, U, size, o0, Rn, Rd) ((Q)<<30 | (U)<<29 | 0b01110<<24 | (size)<<22 | 0b10000<<17 | (o0)<<12 | 0b10<<10 | (Rn)<<5 | (Rd))
|
||||
@@ -1044,7 +1045,7 @@ int convert_bitmask(uint64_t bitmask);
|
||||
// Double-precision to 64-bit
|
||||
#define FMOVxD(Xd, Dn) EMIT(FMOV_general(1, 0b01, 0b00, 0b110, Dn, Xd))
|
||||
// Top half of 128-bit to 64-bit
|
||||
#define FMOVxD1(Xd, Vn) EMIT(FMOV_general(1, 0b10, 0b01, ob110, Vn, Xd))
|
||||
#define FMOVxD1(Xd, Vn) EMIT(FMOV_general(1, 0b10, 0b01, 0b110, Vn, Xd))
|
||||
|
||||
#define FMOV_register(type, Rn, Rd) (0b11110<<24 | (type)<<22 | 1<<21 | 0b10000<<10 | (Rn)<<5 | (Rd))
|
||||
#define FMOVS(Sd, Sn) EMIT(FMOV_register(0b00, Sn, Sd))
|
||||
@@ -1251,7 +1252,7 @@ int convert_bitmask(uint64_t bitmask);
|
||||
#define FCVTMUxwS(Xd, Sn) EMIT(FCVT_scalar(rex.w, 0b00, 0b10, 0b101, Sn, Xd))
|
||||
#define FCVTMUwD(Wd, Dn) EMIT(FCVT_scalar(0, 0b01, 0b10, 0b101, Dn, Wd))
|
||||
#define FCVTMUxD(Xd, Dn) EMIT(FCVT_scalar(1, 0b01, 0b10, 0b101, Dn, Xd))
|
||||
#define FCVTMUxwD(Xd, Dn) EMIT(FCVT_scalar(rfex.w, 0b01, 0b10, 0b101, Dn, Xd))
|
||||
#define FCVTMUxwD(Xd, Dn) EMIT(FCVT_scalar(rex.w, 0b01, 0b10, 0b101, Dn, Xd))
|
||||
// Floating-point Convert to Signed integer, rounding to nearest with ties to even
|
||||
#define FCVTNSwS(Wd, Sn) EMIT(FCVT_scalar(0, 0b00, 0b00, 0b000, Sn, Wd))
|
||||
#define FCVTNSxS(Xd, Sn) EMIT(FCVT_scalar(1, 0b00, 0b00, 0b000, Sn, Xd))
|
||||
@@ -2372,11 +2373,51 @@ int convert_bitmask(uint64_t bitmask);
|
||||
// LRCPC extension
|
||||
|
||||
#define LDAPR_gen(sz, Rn, Rt) ((sz)<<30 | 0b111<<27 | 1<<23 | 1<<21 | 0b11111<<16 | 1<<15 | 0b100<<12 | (Rn)<<5 | (Rt))
|
||||
#define LDAPRx(Rt, Rn) EMIT(LDAPR_gen(0b11, Rn, Rt))
|
||||
#define LDAPRw(Rt, Rn) EMIT(LDAPR_gen(0b10, Rn, Rt))
|
||||
#define LDAPRxw(Rt, Rn) EMIT(LDAPR_gen(0b10+rex.w, Rn, Rt))
|
||||
#define LDAPRz(Rt, Rn) EMIT(LDAPR_gen(rex.is32bits?0b10:0b11, Rn, Rt))
|
||||
#define LDAPRH(Rt, Rn) EMIT(LDAPR_gen(0b01, Rn, Rt))
|
||||
#define LDAPRB(Rt, Rn) EMIT(LDAPR_gen(0b00, Rn, Rt))
|
||||
#define LDAPRx(Rt, Rn) LEMIT(LDAPR_gen(0b11, Rn, Rt))
|
||||
#define LDAPRw(Rt, Rn) LEMIT(LDAPR_gen(0b10, Rn, Rt))
|
||||
#define LDAPRxw(Rt, Rn) LEMIT(LDAPR_gen(0b10+rex.w, Rn, Rt))
|
||||
#define LDAPRz(Rt, Rn) LEMIT(LDAPR_gen(rex.is32bits?0b10:0b11, Rn, Rt))
|
||||
#define LDAPRH(Rt, Rn) LEMIT(LDAPR_gen(0b01, Rn, Rt))
|
||||
#define LDAPRB(Rt, Rn) LEMIT(LDAPR_gen(0b00, Rn, Rt))
|
||||
|
||||
// LRCPC2 extension
|
||||
|
||||
#define LRCPC2_gen(sz, opc, imm9, Rn, Rt) ((sz)<<30 | 0b011001<<24 | (opc)<<22 | ((imm9)&0b111111111)<<12 | (Rn)<<5 | (Rt))
|
||||
#define STLURx(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b11, 0b00, imm9, Rn, Rt))
|
||||
#define STLURw(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b10, 0b00, imm9, Rn, Rt))
|
||||
#define STLURxw(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b10+rex.w, 0b00, imm9, Rn, Rt))
|
||||
#define STLURz(Rt, Rn, imm9) LEMIT(LRCPC2_gen(rex.is32bits?0b10:0b11, 0b00, imm9, Rn, Rt))
|
||||
#define STLURH(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b01, 0b00, imm9, Rn, Rt))
|
||||
#define STLURB(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b00, 0b00, imm9, Rn, Rt))
|
||||
|
||||
#define LDAPURx(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b11, 0b01, imm9, Rn, Rt))
|
||||
#define LDAPURw(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b10, 0b01, imm9, Rn, Rt))
|
||||
#define LDAPURxw(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b10+rex.w, 0b01, imm9, Rn, Rt))
|
||||
#define LDAPURz(Rt, Rn, imm9) LEMIT(LRCPC2_gen(rex.is32bits?0b10:0b11, 0b01, imm9, Rn, Rt))
|
||||
#define LDAPURH(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b01, 0b01, imm9, Rn, Rt))
|
||||
#define LDAPURB(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b00, 0b01, imm9, Rn, Rt))
|
||||
#define LDAPURSW(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b10, 0b10, imm9, Rn, Rt))
|
||||
#define LDAPURSHw(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b01, 0b11, imm9, Rn, Rt))
|
||||
#define LDAPURSHx(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b01, 0b10, imm9, Rn, Rt))
|
||||
#define LDAPURSHxw(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b01, rex.w?0b10:0b11, imm9, Rn, Rt))
|
||||
#define LDAPURSBw(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b00, 0b11, imm9, Rn, Rt))
|
||||
#define LDAPURSBx(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b00, 0b10, imm9, Rn, Rt))
|
||||
#define LDAPURSBxw(Rt, Rn, imm9) LEMIT(LRCPC2_gen(0b00, rex.w?0b10:0b11, imm9, Rn, Rt))
|
||||
|
||||
#define NOLRCPC() dyn->insts[ninst].use_lrcpc=0
|
||||
|
||||
// LRCPC3 extension
|
||||
#define LRCPC3_gen(sz, opc, imm9, Rn, Rt) ((sz)<<30 | 0b011101<<24 | (opc)<<22 | ((imm9)&0b111111111)<<12 | 0b10<<10 | (Rn)<<5 | (Rt))
|
||||
#define VLDAPUR128(Vt, Vn, imm9) do{if(!cpuext.lrcpc3) NOLRCPC(); else LEMIT(LRCPC3_gen(0b00, 0b11, imm9, Vn, Vt));} while(0)
|
||||
#define VLDAPUR64(Vt, Vn, imm9) do{if(!cpuext.lrcpc3) NOLRCPC(); else LEMIT(LRCPC3_gen(0b11, 0b01, imm9, Vn, Vt));} while(0)
|
||||
#define VLDAPUR32(Vt, Vn, imm9) do{if(!cpuext.lrcpc3) NOLRCPC(); else LEMIT(LRCPC3_gen(0b10, 0b01, imm9, Vn, Vt));} while(0)
|
||||
#define VLDAPUR16(Vt, Vn, imm9) do{if(!cpuext.lrcpc3) NOLRCPC(); else LEMIT(LRCPC3_gen(0b01, 0b01, imm9, Vn, Vt));} while(0)
|
||||
#define VLDAPUR8(Vt, Vn, imm9) do{if(!cpuext.lrcpc3) NOLRCPC(); else LEMIT(LRCPC3_gen(0b00, 0b01, imm9, Vn, Vt));} while(0)
|
||||
|
||||
#define VSTLUR128(Vt, Vn, imm9) do{if(!cpuext.lrcpc3) NOLRCPC(); else LEMIT(LRCPC3_gen(0b00, 0b10, imm9, Vn, Vt));} while(0)
|
||||
#define VSTLUR64(Vt, Vn, imm9) do{if(!cpuext.lrcpc3) NOLRCPC(); else LEMIT(LRCPC3_gen(0b11, 0b00, imm9, Vn, Vt));} while(0)
|
||||
#define VSTLUR32(Vt, Vn, imm9) do{if(!cpuext.lrcpc3) NOLRCPC(); else LEMIT(LRCPC3_gen(0b10, 0b00, imm9, Vn, Vt));} while(0)
|
||||
#define VSTLUR16(Vt, Vn, imm9) do{if(!cpuext.lrcpc3) NOLRCPC(); else LEMIT(LRCPC3_gen(0b01, 0b00, imm9, Vn, Vt));} while(0)
|
||||
#define VSTLUR8(Vt, Vn, imm9) do{if(!cpuext.lrcpc3) NOLRCPC(); else LEMIT(LRCPC3_gen(0b00, 0b00, imm9, Vn, Vt));} while(0)
|
||||
|
||||
#endif //__ARM64_EMITTER_H__
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//arm epilog for dynarec
|
||||
//Save stuff, prepare stack and register
|
||||
//called with pointer to emu as 1st parameter
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdint.h>
|
||||
#include "arm64_immenc.h"
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#ifndef __ARM64_IMMENC_H__
|
||||
#define __ARM64_IMMENC_H__
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//arm lock helper
|
||||
//there is 2 part: read and write
|
||||
// write return 0 on success, 1 on fail (value has been changed)
|
||||
@@ -29,6 +30,7 @@
|
||||
.global arm64_lock_decifnot0b
|
||||
.global arm64_lock_storeb
|
||||
.global arm64_lock_incif0
|
||||
.global arm64_lock_inc
|
||||
.global arm64_lock_decifnot0
|
||||
.global arm64_lock_store
|
||||
.global arm64_lock_store_dd
|
||||
@@ -403,6 +405,28 @@ arm64_atomic_incif0:
|
||||
mov w0, w1
|
||||
ret
|
||||
|
||||
arm64_lock_inc:
|
||||
adrp x3, cpuext
|
||||
add x3, x3, #:lo12:cpuext
|
||||
ldr w3, [x3]
|
||||
tbnz w3, #0, arm64_atomic_inc
|
||||
dmb ish
|
||||
1:
|
||||
ldaxr w1, [x0]
|
||||
add w3, w1, #1
|
||||
stlxr w2, w3, [x0]
|
||||
cbnz w2, 1b
|
||||
2:
|
||||
mov w0, w1
|
||||
ret
|
||||
|
||||
arm64_atomic_inc:
|
||||
mov w1, #1
|
||||
dmb ish
|
||||
ldadd w1, w2, [x0]
|
||||
mov w0, w2
|
||||
ret
|
||||
|
||||
arm64_lock_store:
|
||||
str w1, [x0]
|
||||
dmb ish
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#ifndef __ARM64_LOCK__H__
|
||||
#define __ARM64_LOCK__H__
|
||||
#include <stdint.h>
|
||||
@@ -76,8 +77,11 @@ extern void arm64_lock_storeb(void*p, uint8_t b);
|
||||
// increment atomically the int at [p] only if it was 0. Return the old value of [p]
|
||||
extern int arm64_lock_incif0(void*p);
|
||||
|
||||
// increment atomically the int at [p]. Return the old value of [p]
|
||||
extern int arm64_lock_inc(volatile void*p);
|
||||
|
||||
// decrement atomically the int at [p] (but only if p not 0)
|
||||
extern int arm64_lock_decifnot0(void*p);
|
||||
extern int arm64_lock_decifnot0(volatile void*p);
|
||||
|
||||
// atomic store (with memory barrier)
|
||||
extern void arm64_lock_store(void*p, uint32_t v);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#ifndef __ARM64_MAPPING_H__
|
||||
#define __ARM64_MAPPING_H__
|
||||
|
||||
@@ -38,6 +39,32 @@ p0-p3 are used to pass scalable predicate arguments to a subroutine and to retur
|
||||
*/
|
||||
|
||||
// x86 Register mapping
|
||||
#ifdef BOX64EC
|
||||
// x18 is the TEB and x6 is guest R9, the other scratch registers are x1 to x5
|
||||
#define xRAX 10
|
||||
#define xRCX 11
|
||||
#define xRDX 12
|
||||
#define xRBX 8
|
||||
#define xRSP 20
|
||||
#define xRBP 21
|
||||
#define xRSI 16
|
||||
#define xRDI 17
|
||||
#define xR8 15
|
||||
#define xR9 6
|
||||
#define xR10 23
|
||||
#define xR11 9
|
||||
#define xR12 22
|
||||
#define xR13 25
|
||||
#define xR14 26
|
||||
#define xR15 19
|
||||
#define xFlags 7
|
||||
#define xRIP 27
|
||||
|
||||
// convert a x86 register to native according to the register mapping
|
||||
#define TO_NAT(A) (((uint8_t[]){10, 11, 12, 8, 20, 21, 16, 17, 15, 6, 23, 9, 22, 25, 26, 19})[(A)])
|
||||
#define IS_GPR(A) (((uint8_t[]){0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, \
|
||||
1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0})[(A)])
|
||||
#else
|
||||
#define xRAX 10
|
||||
#define xRCX 11
|
||||
#define xRDX 12
|
||||
@@ -61,6 +88,9 @@ p0-p3 are used to pass scalable predicate arguments to a subroutine and to retur
|
||||
// convert a x86 register to native according to the register mapping
|
||||
#define TO_NAT(A) (xRAX + (A))
|
||||
#define IS_GPR(A) ((A)>=xRAX && (A)<=xRIP)
|
||||
#endif
|
||||
// the Windows platform register, reloaded with the TEB after C calls
|
||||
#define xTEB 18
|
||||
|
||||
// 32bits version
|
||||
#define wEAX xRAX
|
||||
@@ -86,8 +116,14 @@ p0-p3 are used to pass scalable predicate arguments to a subroutine and to retur
|
||||
#define x3 3
|
||||
#define x4 4
|
||||
#define x5 5
|
||||
#ifdef BOX64EC
|
||||
#define x6 BOX64EC_x6_IS_GUEST_R9_USE_xR9
|
||||
// x87pc is x5, a normal scratch: BOX64_DYNAREC_X87DOUBLE=2 precision tracking is not supported on Box64EC
|
||||
#define x87pc 5
|
||||
#else
|
||||
#define x6 6
|
||||
#define x87pc 7
|
||||
#endif
|
||||
// x87 can be a scratch, but check if it's used as x87 PC and restore if needed in that case
|
||||
// 32bits version of scratch
|
||||
#define w1 x1
|
||||
@@ -95,7 +131,11 @@ p0-p3 are used to pass scalable predicate arguments to a subroutine and to retur
|
||||
#define w3 x3
|
||||
#define w4 x4
|
||||
#define w5 x5
|
||||
#ifdef BOX64EC
|
||||
#define w6 BOX64EC_w6_IS_GUEST_R9_USE_wR9
|
||||
#else
|
||||
#define w6 x6
|
||||
#endif
|
||||
#define w87pc x87pc
|
||||
// emu is r0
|
||||
#define xEmu 0
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//arm update linker table for dynarec
|
||||
//called with pointer to emu as 1st parameter
|
||||
|
||||
@@ -14,6 +15,8 @@
|
||||
arm64_next:
|
||||
// emu is r0
|
||||
// IP address is r1
|
||||
str x14, [x0, #(8 * 4)] // RSP
|
||||
str x27, [x0, #(8 * 17)] // RIP
|
||||
sub sp, sp, (8 * 12)
|
||||
stp x0, x1, [sp, (8 * 0)]
|
||||
stp x10, x11, [sp, (8 * 2)]
|
||||
@@ -47,6 +50,8 @@ arm64_next:
|
||||
arm64_next_invalid:
|
||||
// emu is r0
|
||||
// IP address is r1
|
||||
str x14, [x0, #(8 * 4)] // RSP
|
||||
str x27, [x0, #(8 * 17)] // RIP
|
||||
sub sp, sp, (8 * 12)
|
||||
stp x0, x1, [sp, (8 * 0)]
|
||||
stp x10, x11, [sp, (8 * 2)]
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
@@ -208,12 +209,12 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
}
|
||||
if(isMask(opcode, "001110001x0iiiiiiiii00nnnnnttttt", &a)) {
|
||||
int offset = signExtend(imm, 9);
|
||||
snprintf(buff, sizeof(buff), "LDURSB %s, [%s, %s0x%x]", a.x?Xt[Rt]:Wt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
snprintf(buff, sizeof(buff), "LDURSB %s, [%s, %s0x%x]", a.x?Wt[Rt]:Xt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "011110001x0iiiiiiiii00nnnnnttttt", &a)) {
|
||||
int offset = signExtend(imm, 9);
|
||||
snprintf(buff, sizeof(buff), "LDURSH %s, [%s, %s0x%x]", a.x?Xt[Rt]:Wt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
snprintf(buff, sizeof(buff), "LDURSH %s, [%s, %s0x%x]", a.x?Wt[Rt]:Xt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "10111000100iiiiiiiii00nnnnnttttt", &a)) {
|
||||
@@ -221,6 +222,37 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
snprintf(buff, sizeof(buff), "LDURSW %s, [%s, %s0x%x]", Xt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "1x011001010iiiiiiiii00nnnnnttttt", &a)) {
|
||||
int size = (opcode>>30)&3;
|
||||
int offset = signExtend(imm, 9);
|
||||
snprintf(buff, sizeof(buff), "LDAPUR %s, [%s, %s0x%x]", (size==0b10)?Wt[Rt]:Xt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "00011001010iiiiiiiii00nnnnnttttt", &a)) {
|
||||
int offset = signExtend(imm, 9);
|
||||
snprintf(buff, sizeof(buff), "LDAPURB %s, [%s, %s0x%x]", Wt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "01011001010iiiiiiiii00nnnnnttttt", &a)) {
|
||||
int offset = signExtend(imm, 9);
|
||||
snprintf(buff, sizeof(buff), "LDAPURH %s, [%s, %s0x%x]", Wt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "000110011x0iiiiiiiii00nnnnnttttt", &a)) {
|
||||
int offset = signExtend(imm, 9);
|
||||
snprintf(buff, sizeof(buff), "LDAPURSB %s, [%s, %s0x%x]", a.x?Wt[Rt]:Xt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "010110011x0iiiiiiiii00nnnnnttttt", &a)) {
|
||||
int offset = signExtend(imm, 9);
|
||||
snprintf(buff, sizeof(buff), "LDAPURSH %s, [%s, %s0x%x]", a.x?Wt[Rt]:Xt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "10011001100iiiiiiiii00nnnnnttttt", &a)) {
|
||||
int offset = signExtend(imm, 9);
|
||||
snprintf(buff, sizeof(buff), "LDAPURSW %s, [%s, %s0x%x]", Xt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "1x111000000iiiiiiiii00nnnnnttttt", &a)) {
|
||||
int size = (opcode>>30)&3;
|
||||
int offset = signExtend(imm, 9);
|
||||
@@ -237,6 +269,22 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
snprintf(buff, sizeof(buff), "STURH %s, [%s, %s0x%x]", Wt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "1x011001000iiiiiiiii00nnnnnttttt", &a)) {
|
||||
int size = (opcode>>30)&3;
|
||||
int offset = signExtend(imm, 9);
|
||||
snprintf(buff, sizeof(buff), "STLUR %s, [%s, %s0x%x]", (size==0b10)?Wt[Rt]:Xt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "00011001000iiiiiiiii00nnnnnttttt", &a)) {
|
||||
int offset = signExtend(imm, 9);
|
||||
snprintf(buff, sizeof(buff), "STLURB %s, [%s, %s0x%x]", Wt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "01011001000iiiiiiiii00nnnnnttttt", &a)) {
|
||||
int offset = signExtend(imm, 9);
|
||||
snprintf(buff, sizeof(buff), "STLURH %s, [%s, %s0x%x]", Wt[Rt], XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "1x11100101iiiiiiiiiiiinnnnnttttt", &a)) {
|
||||
int size = (opcode>>30)&3;
|
||||
int offset = (imm)<<size;
|
||||
@@ -557,22 +605,22 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
}
|
||||
if(isMask(opcode, "f1001011001mmmmmoooiiinnnnnddddd", &a)) {
|
||||
const char* shifts[2][8] = {{ "UXTB", "UXTH", "LSL", "UXTX", "SXTB", "SXTH", "SXTW", "SXTX"}, {"UXTB", "UXTH", "UXTW", "LSL", "SXTB", "SXTH", "SXTW", "SXTX" }};
|
||||
if(((sf==0 && shift==2) || (sf==1 && shift==3)) && imm==0)
|
||||
if(((sf==0 && option==2) || (sf==1 && option==3)) && imm==0)
|
||||
snprintf(buff, sizeof(buff), "SUB %s, %s, %s", sf?XtSp[Rd]:WtSp[Rd], sf?XtSp[Rn]:WtSp[Rn], sf?XtSp[Rm]:WtSp[Rm]);
|
||||
else if(shift==0)
|
||||
snprintf(buff, sizeof(buff), "SUB %s, %s, %s %s", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm], shifts[sf][shift]);
|
||||
else if(imm==0)
|
||||
snprintf(buff, sizeof(buff), "SUB %s, %s, %s %s", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm], shifts[sf][option]);
|
||||
else
|
||||
snprintf(buff, sizeof(buff), "SUB %s, %s, %s %s %d", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm], shifts[sf][shift], imm);
|
||||
snprintf(buff, sizeof(buff), "SUB %s, %s, %s %s %d", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm], shifts[sf][option], imm);
|
||||
return buff;
|
||||
}
|
||||
if(isMask(opcode, "f0001011001mmmmmoooiiinnnnnddddd", &a)) {
|
||||
const char* shifts[2][8] = {{ "UXTB", "UXTH", "LSL", "UXTX", "SXTB", "SXTH", "SXTW", "SXTX"}, {"UXTB", "UXTH", "UXTW", "LSL", "SXTB", "SXTH", "SXTW", "SXTX" }};
|
||||
if(((sf==0 && shift==2) || (sf==1 && shift==3)) && imm==0)
|
||||
if(((sf==0 && option==2) || (sf==1 && option==3)) && imm==0)
|
||||
snprintf(buff, sizeof(buff), "ADD %s, %s, %s", sf?XtSp[Rd]:WtSp[Rd], sf?XtSp[Rn]:WtSp[Rn], sf?XtSp[Rm]:WtSp[Rm]);
|
||||
else if(shift==0)
|
||||
snprintf(buff, sizeof(buff), "ADD %s, %s, %s %s", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm], shifts[sf][shift]);
|
||||
else if(imm==0)
|
||||
snprintf(buff, sizeof(buff), "ADD %s, %s, %s %s", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm], shifts[sf][option]);
|
||||
else
|
||||
snprintf(buff, sizeof(buff), "ADD %s, %s, %s %s %d", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm], shifts[sf][shift], imm);
|
||||
snprintf(buff, sizeof(buff), "ADD %s, %s, %s %s %d", sf?Xt[Rd]:Wt[Rd], sf?Xt[Rn]:Wt[Rn], sf?Xt[Rm]:Wt[Rm], shifts[sf][option], imm);
|
||||
return buff;
|
||||
}
|
||||
// ---- LOGIC
|
||||
@@ -1664,6 +1712,19 @@ const char* arm64_print(uint32_t opcode, uintptr_t addr)
|
||||
snprintf(buff, sizeof(buff), "%sUR %s%d, [%s, %s0x%x]", a.L?"LD":"ST", Y[sz], Rt, XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
return buff;
|
||||
}
|
||||
// LDAPUR/STLUR
|
||||
if(isMask(opcode, "ff011101cL0iiiiiiiii10nnnnnttttt", &a)) {
|
||||
const char* Y[] = {"B", "H", "S", "D", "Q"};
|
||||
int sz = sf;
|
||||
if(sz==0 && a.c)
|
||||
sz = 4;
|
||||
int offset = signExtend(imm, 9);
|
||||
if(!offset)
|
||||
snprintf(buff, sizeof(buff), "%sUR %s%d, [%s]", a.L?"LDAP":"STL", Y[sz], Rt, XtSp[Rn]);
|
||||
else
|
||||
snprintf(buff, sizeof(buff), "%sUR %s%d, [%s, %s0x%x]", a.L?"LDAP":"STL", Y[sz], Rt, XtSp[Rn], (offset<0)?"-":"", abs(offset));
|
||||
return buff;
|
||||
}
|
||||
// LDR/STR vector immediate
|
||||
if(isMask(opcode, "ff111101cLiiiiiiiiiiiinnnnnttttt", &a)) {
|
||||
const char* Y[] = {"B", "H", "S", "D", "Q"};
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#ifndef _ARM_PRINTER_H_
|
||||
#define _ARM_PRINTER_H_
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
//arm prologue for dynarec
|
||||
//Save stuff, prepare stack and register
|
||||
//called with pointer to emu as 1st parameter
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -36,6 +37,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
int32_t i32, tmp;
|
||||
int64_t i64, j64;
|
||||
uint8_t u8;
|
||||
uint8_t f_save;
|
||||
uint8_t gb1, gb2, eb1, eb2;
|
||||
uint16_t u16;
|
||||
uint32_t u32;
|
||||
@@ -983,8 +985,10 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
B_NEXT_nocond;
|
||||
MARK;
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
f_save = dyn->f;
|
||||
CALL_S(const_native_br, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
dyn->f = f_save;
|
||||
} else {
|
||||
INST_NAME("Illegal 62");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
@@ -1010,10 +1014,10 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETEW(x1, 0);
|
||||
GETGW(x2);
|
||||
// Extract RPL (low 2 bits)
|
||||
UBFXw(x6, ed, 0, 2);
|
||||
UBFXw(x5, ed, 0, 2);
|
||||
UBFXw(x4, gd, 0, 2);
|
||||
// need_update = (dst_rpl < src_rpl)
|
||||
CMPSw_REG(x6, x4);
|
||||
CMPSw_REG(x5, x4);
|
||||
CSETw(x5, cLT);
|
||||
// ZF = need_update
|
||||
BFIw(xFlags, x5, F_ZF, 1);
|
||||
@@ -1054,6 +1058,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
TABLE64(x3, addr-4);
|
||||
LDRSW_U12(x1, x3, 0);
|
||||
PUSH1z(x1);
|
||||
SMWRITE();
|
||||
} else {
|
||||
if (!i64) {
|
||||
PUSH1z(xZR);
|
||||
@@ -1067,9 +1072,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0x69:
|
||||
INST_NAME("IMUL Gd, Ed, Id");
|
||||
if (BOX64DRENV(dynarec_safeflags) > 1 && BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_NODF);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
}
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
@@ -1138,9 +1143,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0x6B:
|
||||
INST_NAME("IMUL Gd, Ed, Ib");
|
||||
if (BOX64DRENV(dynarec_safeflags) > 1 && BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_NODF);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
}
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
@@ -1213,7 +1218,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0x6E:
|
||||
case 0x6F:
|
||||
INST_NAME(opcode == 0x6C ? "OUTSB" : "OUTSD");
|
||||
INST_NAME(opcode == 0x6E ? "OUTSB" : "OUTSD");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_PEND);
|
||||
} else {
|
||||
@@ -1467,7 +1472,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop=F8;
|
||||
GETEB(x1, 0);
|
||||
GETGB(x2);
|
||||
emit_test8(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
emit_test8(dyn, ninst, x1, x2, x3, x4);
|
||||
break;
|
||||
case 0x85:
|
||||
INST_NAME("TEST Ed, Gd");
|
||||
@@ -1475,7 +1480,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
GETED(0);
|
||||
emit_test32(dyn, ninst, rex, ed, gd, x3, x5, x6);
|
||||
emit_test32(dyn, ninst, rex, ed, gd, x3, x5);
|
||||
break;
|
||||
case 0x86:
|
||||
INST_NAME("(LOCK)XCHG Eb, Gb");
|
||||
@@ -1602,6 +1607,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else { // mem <= reg
|
||||
IF_UNALIGNED(ip) {
|
||||
MESSAGE(LOG_DEBUG, "\tUnaligned path");
|
||||
NOLRCPC();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, &lock, 0, 0);
|
||||
if(gd==wback) {
|
||||
MOVx_REG(x2, wback);
|
||||
@@ -1614,9 +1620,13 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
// gd restored after that
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff << (2 + rex.w), (1 << (2 + rex.w)) - 1, rex, &lock, 0, 0);
|
||||
if(!lock && BOX64ENV(unity) && !VolatileRangesContains(ip) && ((fixedaddress==0x80) || (fixedaddress==0x84) || (fixedaddress==0xc0) || (fixedaddress==0xc4))) {
|
||||
DMB_ISH();
|
||||
lock = 1;
|
||||
if(!lock && !dyn->insts[ninst].use_lrcpc && BOX64ENV(unity) && !VolatileRangesContains(ip) && ((fixedaddress==0x80) || (fixedaddress==0x84) || (fixedaddress==0xc0) || (fixedaddress==0xc4))) {
|
||||
if(!dyn->insts[ninst].x64.strongmem && cpuext.lrcpc && cpuext.lrcpc2 && cpuext.uscat)
|
||||
dyn->insts[ninst].use_lrcpc = 1;
|
||||
else {
|
||||
DMB_ISH();
|
||||
lock = 1;
|
||||
}
|
||||
}
|
||||
STxw(gd, ed, fixedaddress);
|
||||
}
|
||||
@@ -1665,8 +1675,11 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOVxw_REG(gd, TO_NAT((nextop & 7) + (rex.b << 3)));
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, &unscaled, 0xfff<<(2+rex.w), (1<<(2+rex.w))-1, rex, &lock, 0, 0);
|
||||
if(!lock && BOX64ENV(unity) && !VolatileRangesContains(ip) && ((fixedaddress==0x80) || (fixedaddress==0x84) || (fixedaddress==0xc0) || (fixedaddress==0xc4))) {
|
||||
lock = 1;
|
||||
if(!lock && !dyn->insts[ninst].use_lrcpc && BOX64ENV(unity) && !VolatileRangesContains(ip) && ((fixedaddress==0x80) || (fixedaddress==0x84) || (fixedaddress==0xc0) || (fixedaddress==0xc4))) {
|
||||
if(!dyn->insts[ninst].x64.strongmem && cpuext.lrcpc && cpuext.lrcpc2 && cpuext.uscat)
|
||||
dyn->insts[ninst].use_lrcpc = 1;
|
||||
else
|
||||
lock = 1;
|
||||
}
|
||||
SMREADLOCK(lock);
|
||||
LDxw(gd, ed, fixedaddress);
|
||||
@@ -1834,6 +1847,22 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0x9B:
|
||||
INST_NAME("FWAIT");
|
||||
if(BOX64ENV(dynarec_div0)) {
|
||||
LDRH_U12(x1, xEmu, offsetof(x64emu_t, sw));
|
||||
LDRH_U12(x2, xEmu, offsetof(x64emu_t, cw));
|
||||
MVNw_REG(x2, x2); // ~CW
|
||||
ANDw_REG(x1, x1, x2); // SW & ~CW
|
||||
MOV32w(x3, 0x3F); // 6 exception flag bits
|
||||
ANDw_REG(x1, x1, x3); // & 0x3F
|
||||
CBZw_MARK3(x1); // no pending unmasked exception
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL_S(const_native_div0, -1);
|
||||
CLEARIP();
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
MARK3;
|
||||
}
|
||||
break;
|
||||
case 0x9C:
|
||||
INST_NAME("PUSHF");
|
||||
@@ -1842,7 +1871,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0x9D:
|
||||
INST_NAME("POPF");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
POP1z(xFlags);
|
||||
MOV32w(x1, 0x3E7FD7);
|
||||
ANDw_REG(xFlags, xFlags, x1);
|
||||
@@ -2006,6 +2035,11 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(rex.rep) {
|
||||
INST_NAME("REP MOVSB");
|
||||
CBZx_NEXT(xRCX);
|
||||
NOLRCPC();
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
MOVw_REG(xRSI, xRSI);
|
||||
}
|
||||
TBNZ_MARK2(xFlags, F_DF);
|
||||
IF_UNALIGNED(ip) {
|
||||
MESSAGE(LOG_DEBUG, "\tUnaligned path");
|
||||
@@ -2058,11 +2092,16 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
// done
|
||||
} else {
|
||||
INST_NAME("MOVSB");
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
MOVw_REG(xRSI, xRSI);
|
||||
}
|
||||
GETDIR(x3, 1);
|
||||
LDRB_U12(x1, xRSI, 0);
|
||||
STRB_U12(x1, xRDI, 0);
|
||||
ADDx_REG(xRSI, xRSI, x3);
|
||||
ADDx_REG(xRDI, xRDI, x3);
|
||||
unscaled = 0;
|
||||
LDB(x1, xRSI, 0);
|
||||
STB(x1, xRDI, 0);
|
||||
ADDy_REG(xRSI, xRSI, x3);
|
||||
ADDy_REG(xRDI, xRDI, x3);
|
||||
}
|
||||
SMWRITE();
|
||||
break;
|
||||
@@ -2071,6 +2110,11 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(rex.rep) {
|
||||
INST_NAME("REP MOVSD");
|
||||
CBZx_NEXT(xRCX);
|
||||
NOLRCPC();
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
MOVw_REG(xRSI, xRSI);
|
||||
}
|
||||
TBNZ_MARK2(xFlags, F_DF);
|
||||
MARK; // Part with DF==0
|
||||
LDRxw_S9_postindex(x1, xRSI, rex.w?8:4);
|
||||
@@ -2086,11 +2130,16 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
// done
|
||||
} else {
|
||||
INST_NAME("MOVSD");
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
MOVw_REG(xRSI, xRSI);
|
||||
}
|
||||
GETDIR(x3, rex.w?8:4);
|
||||
LDRxw_U12(x1, xRSI, 0);
|
||||
STRxw_U12(x1, xRDI, 0);
|
||||
ADDx_REG(xRSI, xRSI, x3);
|
||||
ADDx_REG(xRDI, xRDI, x3);
|
||||
unscaled = 0;
|
||||
LDxw(x1, xRSI, 0);
|
||||
STxw(x1, xRDI, 0);
|
||||
ADDy_REG(xRSI, xRSI, x3);
|
||||
ADDy_REG(xRDI, xRDI, x3);
|
||||
}
|
||||
SMWRITE();
|
||||
break;
|
||||
@@ -2101,11 +2150,16 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(rex.rep==1) {INST_NAME("REPNZ CMPSB");} else {INST_NAME("REPZ CMPSB");}
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SMREAD();
|
||||
CBZx_NEXT(xRCX);
|
||||
NOLRCPC();
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
MOVw_REG(xRSI, xRSI);
|
||||
}
|
||||
TBNZ_MARK2(xFlags, F_DF);
|
||||
MARK; // Part with DF==0
|
||||
LDRB_S9_postindex(x1, xRSI, 1);
|
||||
@@ -2124,16 +2178,22 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
CBNZx_MARK2(xRCX);
|
||||
MARK3; // end
|
||||
emit_cmp8(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
STOP_NATIVE_FLAGS(dyn, ninst);
|
||||
break;
|
||||
default:
|
||||
INST_NAME("CMPSB");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
MOVw_REG(xRSI, xRSI);
|
||||
}
|
||||
GETDIR(x3, 1);
|
||||
SMREAD();
|
||||
LDRB_U12(x1, xRSI, 0);
|
||||
LDRB_U12(x2, xRDI, 0);
|
||||
ADDx_REG(xRSI, xRSI, x3);
|
||||
ADDx_REG(xRDI, xRDI, x3);
|
||||
unscaled = 0;
|
||||
LDB(x1, xRSI, 0);
|
||||
LDB(x2, xRDI, 0);
|
||||
ADDy_REG(xRSI, xRSI, x3);
|
||||
ADDy_REG(xRDI, xRDI, x3);
|
||||
emit_cmp8(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
break;
|
||||
}
|
||||
@@ -2145,11 +2205,16 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(rex.rep==1) {INST_NAME("REPNZ CMPSD");} else {INST_NAME("REPZ CMPSD");}
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SMREAD();
|
||||
CBZx_NEXT(xRCX);
|
||||
NOLRCPC();
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
MOVw_REG(xRSI, xRSI);
|
||||
}
|
||||
TBNZ_MARK2(xFlags, F_DF);
|
||||
MARK; // Part with DF==0
|
||||
LDRxw_S9_postindex(x1, xRSI, rex.w?8:4);
|
||||
@@ -2168,16 +2233,22 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
CBNZx_MARK2(xRCX);
|
||||
MARK3; // end
|
||||
emit_cmp32(dyn, ninst, rex, x1, x2, x3, x4, x5);
|
||||
STOP_NATIVE_FLAGS(dyn, ninst);
|
||||
break;
|
||||
default:
|
||||
INST_NAME("CMPSD");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
MOVw_REG(xRSI, xRSI);
|
||||
}
|
||||
GETDIR(x3, rex.w?8:4);
|
||||
SMREAD();
|
||||
LDRxw_U12(x1, xRSI, 0);
|
||||
LDRxw_U12(x2, xRDI, 0);
|
||||
ADDx_REG(xRSI, xRSI, x3);
|
||||
ADDx_REG(xRDI, xRDI, x3);
|
||||
unscaled = 0;
|
||||
LDxw(x1, xRSI, 0);
|
||||
LDxw(x2, xRDI, 0);
|
||||
ADDy_REG(xRSI, xRSI, x3);
|
||||
ADDy_REG(xRDI, xRDI, x3);
|
||||
emit_cmp32(dyn, ninst, rex, x1, x2, x3, x4, x5);
|
||||
break;
|
||||
}
|
||||
@@ -2187,19 +2258,22 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
UXTBx(x1, xRAX);
|
||||
u8 = F8;
|
||||
MOV32w(x2, u8);
|
||||
emit_test8(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
emit_test8c(dyn, ninst, x1, u8, x3, x4);
|
||||
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);
|
||||
emit_test32c(dyn, ninst, rex, xRAX, i64, x3, x4);
|
||||
break;
|
||||
case 0xAA:
|
||||
if(rex.rep) {
|
||||
INST_NAME("REP STOSB");
|
||||
CBZx_NEXT(xRCX);
|
||||
NOLRCPC();
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
}
|
||||
TBNZ_MARK2(xFlags, F_DF);
|
||||
IF_UNALIGNED(ip) {
|
||||
MESSAGE(LOG_DEBUG, "\tUnaligned path");
|
||||
@@ -2244,9 +2318,13 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
// done
|
||||
} else {
|
||||
INST_NAME("STOSB");
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
}
|
||||
GETDIR(x3, 1);
|
||||
STRB_U12(xRAX, xRDI, 0);
|
||||
ADDx_REG(xRDI, xRDI, x3);
|
||||
unscaled = 0;
|
||||
STB(xRAX, xRDI, 0);
|
||||
ADDy_REG(xRDI, xRDI, x3);
|
||||
}
|
||||
SMWRITE();
|
||||
break;
|
||||
@@ -2254,6 +2332,10 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(rex.rep) {
|
||||
INST_NAME("REP STOSD");
|
||||
CBZx_NEXT(xRCX);
|
||||
NOLRCPC();
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
}
|
||||
TBNZ_MARK2(xFlags, F_DF);
|
||||
MARK; // Part with DF==0
|
||||
STRxw_S9_postindex(xRAX, xRDI, rex.w?8:4);
|
||||
@@ -2268,9 +2350,13 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
// done
|
||||
} else {
|
||||
INST_NAME("STOSD");
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
}
|
||||
GETDIR(x3, rex.w?8:4);
|
||||
STRxw_U12(xRAX, xRDI, 0);
|
||||
ADDx_REG(xRDI, xRDI, x3);
|
||||
unscaled = 0;
|
||||
STxw(xRAX, xRDI, 0);
|
||||
ADDy_REG(xRDI, xRDI, x3);
|
||||
}
|
||||
SMWRITE();
|
||||
break;
|
||||
@@ -2280,14 +2366,18 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
INST_NAME("LODSB");
|
||||
}
|
||||
NOLRCPC();
|
||||
GETDIR(x1, 1);
|
||||
SMREAD();
|
||||
if(rex.rep) {
|
||||
CBZx_NEXT(xRCX);
|
||||
MARK;
|
||||
}
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRSI, xRSI);
|
||||
}
|
||||
LDRB_U12(x2, xRSI, 0);
|
||||
ADDx_REG(xRSI, xRSI, x1);
|
||||
ADDy_REG(xRSI, xRSI, x1);
|
||||
if(rex.rep) {
|
||||
SUBx_U12(xRCX, xRCX, 1);
|
||||
CBNZx_MARK(xRCX);
|
||||
@@ -2300,30 +2390,38 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
INST_NAME("LODSD");
|
||||
}
|
||||
NOLRCPC();
|
||||
GETDIR(x1, rex.w?8:4);
|
||||
if(rex.rep) {
|
||||
CBZx_NEXT(xRCX);
|
||||
MARK;
|
||||
}
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRSI, xRSI);
|
||||
}
|
||||
LDRxw_U12(xRAX, xRSI, 0);
|
||||
ADDx_REG(xRSI, xRSI, x1);
|
||||
ADDy_REG(xRSI, xRSI, x1);
|
||||
if(rex.rep) {
|
||||
SUBx_U12(xRCX, xRCX, 1);
|
||||
CBNZx_MARK(xRCX);
|
||||
}
|
||||
break;
|
||||
case 0xAE:
|
||||
NOLRCPC();
|
||||
switch(rex.rep) {
|
||||
case 1:
|
||||
case 2:
|
||||
if(rex.rep==1) {INST_NAME("REPNZ SCASB");} else {INST_NAME("REPZ SCASB");}
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SMREAD();
|
||||
CBZx_NEXT(xRCX);
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
}
|
||||
UBFXw(x1, xRAX, 0, 8);
|
||||
TBNZ_MARK2(xFlags, F_DF);
|
||||
MARK; // Part with DF==0
|
||||
@@ -2341,30 +2439,38 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
CBNZx_MARK2(xRCX);
|
||||
MARK3; // end
|
||||
emit_cmp8(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
STOP_NATIVE_FLAGS(dyn, ninst);
|
||||
break;
|
||||
default:
|
||||
INST_NAME("SCASB");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
}
|
||||
GETDIR(x3, 1);
|
||||
UBFXw(x1, xRAX, 0, 8);
|
||||
LDRB_U12(x2, xRDI, 0);
|
||||
ADDx_REG(xRDI, xRDI, x3);
|
||||
ADDy_REG(xRDI, xRDI, x3);
|
||||
emit_cmp8(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0xAF:
|
||||
NOLRCPC();
|
||||
switch(rex.rep) {
|
||||
case 1:
|
||||
case 2:
|
||||
if(rex.rep==1) {INST_NAME("REPNZ SCASD");} else {INST_NAME("REPZ SCASD");}
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
SMREAD();
|
||||
CBZx_NEXT(xRCX);
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
}
|
||||
TBNZ_MARK2(xFlags, F_DF);
|
||||
MARK; // Part with DF==0
|
||||
LDRxw_S9_postindex(x2, xRDI, rex.w?8:4);
|
||||
@@ -2381,13 +2487,17 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
CBNZx_MARK2(xRCX);
|
||||
MARK3; // end
|
||||
emit_cmp32(dyn, ninst, rex, xRAX, x2, x3, x4, x5);
|
||||
STOP_NATIVE_FLAGS(dyn, ninst);
|
||||
break;
|
||||
default:
|
||||
INST_NAME("SCASD");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
}
|
||||
GETDIR(x3, rex.w?8:4);
|
||||
LDRxw_U12(x2, xRDI, 0);
|
||||
ADDx_REG(xRDI, xRDI, x3);
|
||||
ADDy_REG(xRDI, xRDI, x3);
|
||||
emit_cmp32(dyn, ninst, rex, xRAX, x2, x3, x4, x5);
|
||||
break;
|
||||
}
|
||||
@@ -2447,10 +2557,10 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("ROL Eb, Ib");
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop)&0x1f;
|
||||
if(u8) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
|
||||
SETFLAGS((!BOX64ENV(cputype) && (u8 > 1) && MODREG) ? X_CF : (X_OF | X_CF), SF_SUBSET); // removed PENDING on purpose
|
||||
GETEB(x1, 1);
|
||||
u8 = F8&0x1f;
|
||||
emit_rol8c(dyn, ninst, x1, u8, x4, x5);
|
||||
emit_rol8c(dyn, ninst, x1, u8, x4, x5, MODREG);
|
||||
EBBACK;
|
||||
} else {
|
||||
FAKEED;
|
||||
@@ -2461,10 +2571,10 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("ROR Eb, Ib");
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop)&0x1f;
|
||||
if(u8) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
|
||||
SETFLAGS((!BOX64ENV(cputype) && (u8 > 1) && MODREG) ? X_CF : (X_OF | X_CF), SF_SUBSET); // removed PENDING on purpose
|
||||
GETEB(x1, 1);
|
||||
u8 = F8&0x1f;
|
||||
emit_ror8c(dyn, ninst, x1, u8, x4, x5);
|
||||
emit_ror8c(dyn, ninst, x1, u8, x4, x5, MODREG);
|
||||
EBBACK;
|
||||
} else {
|
||||
FAKEED;
|
||||
@@ -2553,7 +2663,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("ROL Ed, Ib");
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop)&(0x1f+(rex.w*0x20));
|
||||
if(u8) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
|
||||
SETFLAGS((!BOX64ENV(cputype) && (u8 > 1) && MODREG) ? X_CF : (X_OF | X_CF), SF_SUBSET); // removed PENDING on purpose
|
||||
GETED(1);
|
||||
u8 = (F8)&(rex.w?0x3f:0x1f);
|
||||
emit_rol32c(dyn, ninst, rex, ed, u8, x3, x4);
|
||||
@@ -2572,7 +2682,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("ROR Ed, Ib");
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop)&(0x1f+(rex.w*0x20));
|
||||
if(u8) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
|
||||
SETFLAGS((!BOX64ENV(cputype) && (u8 > 1) && MODREG) ? X_CF : (X_OF | X_CF), SF_SUBSET); // removed PENDING on purpose
|
||||
GETED(1);
|
||||
u8 = (F8)&(rex.w?0x3f:0x1f);
|
||||
emit_ror32c(dyn, ninst, rex, ed, u8, x3, x4);
|
||||
@@ -2812,6 +2922,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else { // mem <= i32
|
||||
IF_UNALIGNED(ip) {
|
||||
MESSAGE(LOG_DEBUG, "\tUnaligned path");
|
||||
NOLRCPC();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, &lock, 0, 4);
|
||||
i64 = F32S;
|
||||
if(i64) {
|
||||
@@ -2875,6 +2986,8 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
READFLAGS(X_PEND);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
if(rex.w) {POP2(xRIP, x3);} else {POP2_32(xRIP, x3);}
|
||||
TBZ_MARK(x3, 0);
|
||||
TBZ_MARK(x3, 1); //GP if CS is incorect
|
||||
STRH_U12(x3, xEmu, offsetof(x64emu_t, segs[_CS]));
|
||||
if(u16<0x1000)
|
||||
ADDz_U12(xRSP, xRSP, u16);
|
||||
@@ -2883,6 +2996,11 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ADDz_REG(xRSP, xRSP, x1);
|
||||
}
|
||||
ret_to_next(dyn, ip, ninst, rex);
|
||||
MARK;
|
||||
ADDx_U12(xRSP, xRSP, (rex.w?8:4)*2);
|
||||
MOV64x(xRIP, ip); // move back RIP to the opcode
|
||||
CALL_S(const_native_priv, -1);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
break;
|
||||
@@ -2891,8 +3009,15 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
READFLAGS(X_PEND);
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
if(rex.w) {POP2(xRIP, x3);} else {POP2_32(xRIP, x3);}
|
||||
TBZ_MARK(x3, 0);
|
||||
TBZ_MARK(x3, 1); //GP if CS is incorect
|
||||
STRH_U12(x3, xEmu, offsetof(x64emu_t, segs[_CS]));
|
||||
ret_to_next(dyn, ip, ninst, rex);
|
||||
MARK;
|
||||
ADDx_U12(xRSP, xRSP, (rex.w?8:4)*2);
|
||||
MOV64x(xRIP, ip); // move back RIP to the opcode
|
||||
CALL_S(const_native_priv, -1);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
break;
|
||||
@@ -2949,20 +3074,11 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
INST_NAME("INT 3");
|
||||
if(!BOX64ENV(ignoreint3)) {
|
||||
// check if TRAP signal is handled
|
||||
TABLE64C(x1, const_context);
|
||||
MOV32w(x2, offsetof(box64context_t, signals[X64_SIGTRAP]));
|
||||
LDRx_REG(x3, x1, x2);
|
||||
//LDRx_U12(x3, x1, offsetof(box64context_t, signals[X64_SIGTRAP]));
|
||||
CMPSx_U12(x3, 0);
|
||||
// commit df before branch, CALL_S in int3 path has FORCE_DFNONE
|
||||
CHECK_DFNONE(0);
|
||||
B_MARK(cEQ);
|
||||
GETIP(addr); // update RIP
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL_S(const_native_int3, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
MARK;
|
||||
jump_to_epilog(dyn, addr, 0, ninst);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
@@ -3087,14 +3203,14 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("ROL Eb, 1");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
|
||||
GETEB(x1, 0);
|
||||
emit_rol8c(dyn, ninst, ed, 1, x4, x5);
|
||||
emit_rol8c(dyn, ninst, ed, 1, x4, x5, 0);
|
||||
EBBACK;
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("ROR Eb, 1");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
|
||||
GETEB(x1, 0);
|
||||
emit_ror8c(dyn, ninst, ed, 1, x4, x5);
|
||||
emit_ror8c(dyn, ninst, ed, 1, x4, x5, 0);
|
||||
EBBACK;
|
||||
break;
|
||||
case 2:
|
||||
@@ -3341,7 +3457,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("SHL Eb, CL");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
ANDw_mask(x2, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
@@ -3356,7 +3472,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("SHR Eb, CL");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
ANDw_mask(x2, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
@@ -3371,7 +3487,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("SAR Eb, CL");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
ANDw_mask(x2, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
@@ -3465,11 +3581,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ANDw_mask(x3, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
}
|
||||
GETED(0);
|
||||
UFLAG_IF {
|
||||
if(!rex.w && !rex.is32bits && MODREG) {MOVw_REG(ed, ed);}
|
||||
}
|
||||
if(!rex.w && !rex.is32bits && MODREG) {MOVw_REG(ed, ed);}
|
||||
CBZw_NEXT(x3);
|
||||
emit_rcl32(dyn, ninst, rex, ed, x3, x5, x4, x6);
|
||||
emit_rcl32(dyn, ninst, rex, ed, x3, x5, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 3:
|
||||
@@ -3486,11 +3600,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ANDw_mask(x3, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
}
|
||||
GETED(0);
|
||||
UFLAG_IF {
|
||||
if(!rex.w && !rex.is32bits && MODREG) {MOVw_REG(ed, ed);}
|
||||
}
|
||||
if(!rex.w && !rex.is32bits && MODREG) {MOVw_REG(ed, ed);}
|
||||
CBZw_NEXT(x3);
|
||||
emit_rcr32(dyn, ninst, rex, ed, x3, x5, x4, x6);
|
||||
emit_rcr32(dyn, ninst, rex, ed, x3, x5, x4);
|
||||
WBACK;
|
||||
break;
|
||||
case 4:
|
||||
@@ -3498,7 +3610,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("SHL Ed, CL");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(rex.w) {
|
||||
@@ -3518,7 +3630,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("SHR Ed, CL");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(rex.w) {
|
||||
@@ -3538,7 +3650,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("SAR Ed, CL");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(rex.w) {
|
||||
@@ -3839,22 +3951,16 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
//fpu_purgecache(dyn, ninst, 0, x1, x3, x4, 0);
|
||||
PUSH1z(x2);
|
||||
int can_continue = (addr < (dyn->start + dyn->isize));
|
||||
if (BOX64DRENV(dynarec_callret)) {
|
||||
SET_HASCALLRET();
|
||||
// Push actual return address
|
||||
if(addr < (dyn->start+dyn->isize)) {
|
||||
// there is a next...
|
||||
if(BOX64DRENV(dynarec_callret)>1 && !dyn->always_test)
|
||||
if(can_continue && BOX64DRENV(dynarec_callret)>1 && !dyn->always_test)
|
||||
j64 = CALLRET_GETRET();
|
||||
else
|
||||
j64 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->native_size)):0;
|
||||
ADR_S20(x4, j64);
|
||||
MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
|
||||
} else {
|
||||
j64 = (dyn->insts)?(GETMARK-(dyn->native_size)):0;
|
||||
ADR_S20(x4, j64);
|
||||
MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
|
||||
}
|
||||
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, x2, xSP, -16);
|
||||
} else {
|
||||
*ok = 0;
|
||||
@@ -3864,12 +3970,12 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
j64 = (uint32_t)(addr+i32);
|
||||
else
|
||||
j64 = addr+i32;
|
||||
j64 = (uintptr_t)getAlternate((void*)j64);
|
||||
jump_to_next(dyn, j64, 0, ninst, rex.is32bits);
|
||||
int can_continue = (addr < (dyn->start + dyn->isize));
|
||||
CALLRET_RET(can_continue);
|
||||
MARK;
|
||||
if (BOX64DRENV(dynarec_callret) && !can_continue) {
|
||||
// jumps out of current dynablock...
|
||||
MARK;
|
||||
j64 = getJumpTableAddress64(addr);
|
||||
if(dyn->need_reloc) {
|
||||
AddRelocTable64JmpTbl(dyn, ninst, addr, STEP);
|
||||
@@ -3878,6 +3984,8 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
MOV64x(x4, j64);
|
||||
}
|
||||
LDRx_U12(x4, x4, 0);
|
||||
if (BOX64DRENV(dynarec_callret) >= 3)
|
||||
doLeaveBlock(dyn, ninst, x1, x2, x3);
|
||||
BR(x4);
|
||||
}
|
||||
CLEARIP();
|
||||
@@ -4016,8 +4124,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
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);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("NOT Eb");
|
||||
@@ -4041,9 +4148,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 4:
|
||||
INST_NAME("MUL AL, Eb");
|
||||
if (BOX64DRENV(dynarec_safeflags) && BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_NODF);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
}
|
||||
GETEB(x1, 0);
|
||||
UXTBw(x2, xRAX);
|
||||
@@ -4071,9 +4178,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 5:
|
||||
INST_NAME("IMUL AL, Eb");
|
||||
if (BOX64DRENV(dynarec_safeflags) && BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_NODF);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
}
|
||||
GETSEB(x1, 0);
|
||||
SXTBw(x2, xRAX);
|
||||
@@ -4102,7 +4209,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("DIV Eb");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
FORCE_DFNONE();
|
||||
GETEB(x1, 0);
|
||||
UXTHw(x2, xRAX);
|
||||
@@ -4140,7 +4247,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("IDIV Eb");
|
||||
SKIPTEST(x1);
|
||||
if (!BOX64DRENV(dynarec_safeflags)) {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
} else if (BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_SF|X_PF|X_ZF|X_AF, SF_SUBSET);
|
||||
}
|
||||
@@ -4182,7 +4289,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETEDH(x1, 4);
|
||||
i64 = F32S;
|
||||
emit_test32c(dyn, ninst, rex, ed, i64, x3, x4, x5);
|
||||
emit_test32c(dyn, ninst, rex, ed, i64, x3, x4);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("NOT Ed");
|
||||
@@ -4200,9 +4307,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 4:
|
||||
INST_NAME("MUL EAX, Ed");
|
||||
if (BOX64DRENV(dynarec_safeflags) && BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_NODF);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
}
|
||||
GETED(0);
|
||||
if(rex.w) {
|
||||
@@ -4237,9 +4344,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 5:
|
||||
INST_NAME("IMUL EAX, Ed");
|
||||
if (BOX64DRENV(dynarec_safeflags) && BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_NODF);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
}
|
||||
GETED(0);
|
||||
if(rex.w) {
|
||||
@@ -4273,7 +4380,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("DIV Ed");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
FORCE_DFNONE();
|
||||
if(!rex.w) {
|
||||
GETED(0);
|
||||
@@ -4371,9 +4478,9 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("IDIV Ed");
|
||||
SKIPTEST(x1);
|
||||
if (!BOX64DRENV(dynarec_safeflags)) {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
} else if (BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_SF|X_PF|X_ZF|X_AF, SF_SET);
|
||||
SETFLAGS(X_SF|X_PF|X_ZF|X_AF, SF_SUBSET);
|
||||
}
|
||||
if(!rex.w) {
|
||||
GETSEDw(0);
|
||||
@@ -4465,8 +4572,8 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SET_DFNONE();
|
||||
ORRx_mask(xFlags, xFlags, 1, 0, 0); // xFlags | 1
|
||||
break;
|
||||
case 0xFA: /* STI */
|
||||
case 0xFB: /* CLI */
|
||||
case 0xFA: /* CLI */
|
||||
case 0xFB: /* STI */
|
||||
INST_NAME(opcode==0xFA?"CLI":"STI");
|
||||
if(rex.is32bits && BOX64ENV(ignoreint3))
|
||||
{} else {
|
||||
@@ -4576,6 +4683,8 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(dyn->need_reloc) AddRelocTable64RetEndBlock(dyn, ninst, addr, STEP);
|
||||
TABLE64_(x4, j64);
|
||||
LDRx_U12(x4, x4, 0);
|
||||
if (BOX64DRENV(dynarec_callret) >= 3)
|
||||
doLeaveBlock(dyn, ninst, x1, x2, x3);
|
||||
BR(x4);
|
||||
}
|
||||
CLEARIP();
|
||||
@@ -4592,6 +4701,12 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
LDxw(x1, wback, 0);
|
||||
ed = x1;
|
||||
LDH(x3, wback, rex.w?8:4);
|
||||
TBZ(x3, 0, 4+4);
|
||||
TBNZ_MARK2(x3, 1);
|
||||
// Bad CS => GP
|
||||
CALL_S(const_native_priv, -1);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
MARK2;
|
||||
LDH(x5, xEmu, offsetof(x64emu_t, segs[_CS]));
|
||||
if (BOX64DRENV(dynarec_callret) && BOX64DRENV(dynarec_bigblock) > 1) {
|
||||
BARRIER(BARRIER_FULL);
|
||||
@@ -4614,17 +4729,14 @@ uintptr_t dynarec64_00(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 {
|
||||
if(BOX64DRENV(dynarec_callret)>1 && !dyn->always_test)
|
||||
j64 = CALLRET_GETRET();
|
||||
else
|
||||
j64 = (dyn->insts)?(GETMARK-(dyn->native_size)):0;
|
||||
j64 = (dyn->insts)?(GETMARK-(dyn->native_size)):0;
|
||||
ADR_S20(x4, j64);
|
||||
MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j64>>2);
|
||||
}
|
||||
STPx_S7_preindex(x4, xRIP, xSP, -16);
|
||||
}
|
||||
if (rex.w) PUSH2(x5, xRIP); else PUSH2_32(x5, xRIP);
|
||||
STH(x3, xEmu, offsetof(x64emu_t, segs[_CS]));
|
||||
STRH_U12(x3, xEmu, offsetof(x64emu_t, segs[_CS]));
|
||||
jump_to_next(dyn, 0, ed, ninst, rex.is32bits);
|
||||
CALLRET_RET(can_continue);
|
||||
if (BOX64DRENV(dynarec_callret) && !can_continue) {
|
||||
@@ -4634,6 +4746,8 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(dyn->need_reloc) AddRelocTable64RetEndBlock(dyn, ninst, addr, STEP);
|
||||
TABLE64_(x4, j64);
|
||||
LDRx_U12(x4, x4, 0);
|
||||
if (BOX64DRENV(dynarec_callret) >= 3)
|
||||
doLeaveBlock(dyn, ninst, x1, x2, x3);
|
||||
BR(x4);
|
||||
}
|
||||
CLEARIP();
|
||||
@@ -4660,7 +4774,7 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
LDxw(x1, wback, 0);
|
||||
ed = x1;
|
||||
LDH(x3, wback, rex.w?8:4);
|
||||
STH(x3, xEmu, offsetof(x64emu_t, segs[_CS]));
|
||||
STRH_U12(x3, xEmu, offsetof(x64emu_t, segs[_CS]));
|
||||
jump_to_next(dyn, 0, ed, ninst, rex.w?0:1);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -160,6 +161,22 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
|
||||
case 0x05:
|
||||
INST_NAME("SYSCALL");
|
||||
if (rex.is32bits) {
|
||||
if (BOX64DRENV(dynarec_safeflags) > 1) {
|
||||
READFLAGS(X_PEND);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // Hack to set flags in "don't care" state
|
||||
}
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
GETIP(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL(const_native_ud, -1);
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
break;
|
||||
}
|
||||
NOTEST(x1);
|
||||
SMEND();
|
||||
GETIP(addr);
|
||||
@@ -281,6 +298,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
IF_UNALIGNED(ip) {
|
||||
MESSAGE(LOG_DEBUG, "\tUnaligned path");
|
||||
NOLRCPC();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(wback!=x1) {
|
||||
MOVx_REG(x1, wback);
|
||||
@@ -359,8 +377,8 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("MOVHPS Ex, Gx");
|
||||
GETGX(v0, 0);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, (nextop&7)+(rex.b<<3), 1);
|
||||
VMOVeD(v1, 0, v0, 1);
|
||||
INST_NAME("Illegal 0F 17");
|
||||
UDF(0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
VST1_64(v0, 1, ed);
|
||||
@@ -485,6 +503,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
UDF(0);
|
||||
} else {
|
||||
INST_NAME("MOVNTPS Ex,Gx");
|
||||
NOLRCPC();
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, &unscaled, 0xfff<<4, 15, rex, NULL, 0, 0);
|
||||
@@ -1596,7 +1615,6 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
break;
|
||||
default:
|
||||
*ok = 0;
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
@@ -1874,7 +1892,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("SHLD Ed, Gd, CL");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETGD;
|
||||
@@ -1964,7 +1982,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("SHRD Ed, Gd, CL");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETGD;
|
||||
@@ -2075,7 +2093,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
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.is32bits);
|
||||
CALL(const_fpu_xsave, -1);
|
||||
break;
|
||||
case 5:
|
||||
@@ -2084,7 +2102,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
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.is32bits);
|
||||
CALL(const_fpu_xrstor, -1);
|
||||
break;
|
||||
case 7:
|
||||
@@ -2100,9 +2118,9 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0xAF:
|
||||
INST_NAME("IMUL Gd, Ed");
|
||||
if (BOX64DRENV(dynarec_safeflags) && BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_NODF);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
}
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
@@ -2421,7 +2439,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if (!BOX64DRENV(dynarec_safeflags) || BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_ZF, SF_SUBSET);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
}
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
@@ -2459,7 +2477,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if (!BOX64DRENV(dynarec_safeflags) || BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_ZF, SF_SUBSET);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
}
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
@@ -2534,8 +2552,9 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
GETEB(x2, 0);
|
||||
gd = x2; ed = x1; // swap gd/ed
|
||||
emit_add8(dyn, ninst, x1, x2, x4, x5);
|
||||
GBBACK; // gb gets x2 (old ed)
|
||||
EBBACK; // eb gets x1 (sum)
|
||||
EBBACK; // Eb writeback must be done first, as Gb writeback can clobber the address register
|
||||
if (!(MODREG && wback == gb1 && wb2 == gb2))
|
||||
GBBACK;
|
||||
break;
|
||||
case 0xC1:
|
||||
INST_NAME("XADD Ed, Gd");
|
||||
@@ -2577,6 +2596,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0xC3:
|
||||
INST_NAME("MOVNTI Ed, Gd");
|
||||
NOLRCPC();
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if(MODREG) { // reg <= reg
|
||||
@@ -2666,32 +2686,43 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
break;
|
||||
case 0xC7:
|
||||
// rep has no impact here
|
||||
nextop = F8;
|
||||
if(MODREG) switch((nextop>>3)&7) {
|
||||
case 6:
|
||||
INST_NAME("RDRAND Ed");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SET_DFNONE();
|
||||
GETED(0);
|
||||
IFX(X_OF|X_SF|X_ZF|X_PF|X_AF) {
|
||||
MOV32w(x1, (1<<F_OF)|(1<<F_SF)|(1<<F_ZF)|(1<<F_PF)|(1<<F_AF));
|
||||
BICw(xFlags, xFlags, x1);
|
||||
}
|
||||
if(cpuext.rndr) {
|
||||
MRS_rndr(x1);
|
||||
IFX(X_CF) { CSETw(x3, cNE); }
|
||||
if(rex.rep==2 || !rex.rep) {
|
||||
if(rex.rep==2)
|
||||
INST_NAME("RDSEED Ed");
|
||||
else
|
||||
INST_NAME("RDRAND Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
SET_DFNONE();
|
||||
GETED(0);
|
||||
IFX(X_OF|X_SF|X_ZF|X_PF|X_AF) {
|
||||
MOV32w(x1, (1<<F_OF)|(1<<F_SF)|(1<<F_ZF)|(1<<F_PF)|(1<<F_AF));
|
||||
BICw(xFlags, xFlags, x1);
|
||||
}
|
||||
if(cpuext.rndr) {
|
||||
MRS_rndr(x1);
|
||||
IFX(X_CF) { CSETw(x3, cNE); }
|
||||
} else {
|
||||
CALL(rex.w?const_random64:const_random32, x1);
|
||||
IFX(X_CF) { MOV32w(x3, 1); }
|
||||
}
|
||||
IFX(X_CF) { BFIw(xFlags, x3, F_CF, 1); }
|
||||
MOVxw_REG(ed, x1);
|
||||
} else {
|
||||
CALL(rex.w?const_random64:const_random32, x1);
|
||||
IFX(X_CF) { MOV32w(x3, 1); }
|
||||
DEFAULT;
|
||||
}
|
||||
IFX(X_CF) { BFIw(xFlags, x3, F_CF, 1); }
|
||||
MOVxw_REG(ed, x1);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("RDPID Ed");
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
GETED(0);
|
||||
CALL_(const_helper_getcpu, ed, x2);
|
||||
IFX(X_CF) {
|
||||
MOV32w(x2, 1);
|
||||
BFIw(xFlags, x2, F_CF, 1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
@@ -2961,6 +2992,7 @@ uintptr_t dynarec64_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
|
||||
case 0xE7:
|
||||
INST_NAME("MOVNTQ Em, Gm");
|
||||
NOLRCPC();
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
if(MODREG) {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -424,9 +425,9 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("IMUL Gw,Ew,Ib");
|
||||
}
|
||||
if (BOX64DRENV(dynarec_safeflags) > 1 && BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_NODF);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
}
|
||||
nextop = F8;
|
||||
GETSEW(x1, (opcode==0x69)?2:1);
|
||||
@@ -604,7 +605,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8;
|
||||
GETEW(x1, 0);
|
||||
GETGW(x2);
|
||||
emit_test16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
emit_test16(dyn, ninst, x1, x2, x3, x4);
|
||||
break;
|
||||
|
||||
case 0x87:
|
||||
@@ -787,7 +788,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0x9D:
|
||||
INST_NAME("POPF");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
SMREAD();
|
||||
POP1_16(x1);
|
||||
MOV32w(x2, 0x7FD7);
|
||||
@@ -883,6 +884,11 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(rex.rep) {
|
||||
INST_NAME("REP MOVSW");
|
||||
CBZx_NEXT(xRCX);
|
||||
NOLRCPC();
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
MOVw_REG(xRSI, xRSI);
|
||||
}
|
||||
TBNZ_MARK2(xFlags, F_DF);
|
||||
MARK; // Part with DF==0
|
||||
LDRH_S9_postindex(x1, xRSI, 2);
|
||||
@@ -898,11 +904,16 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
// done
|
||||
} else {
|
||||
INST_NAME("MOVSW");
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
MOVw_REG(xRSI, xRSI);
|
||||
}
|
||||
GETDIR(x3, 2);
|
||||
LDRH_U12(x1, xRSI, 0);
|
||||
STRH_U12(x1, xRDI, 0);
|
||||
ADDx_REG(xRSI, xRSI, x3);
|
||||
ADDx_REG(xRDI, xRDI, x3);
|
||||
unscaled = 0;
|
||||
LDH(x1, xRSI, 0);
|
||||
STH(x1, xRDI, 0);
|
||||
ADDy_REG(xRSI, xRSI, x3);
|
||||
ADDy_REG(xRDI, xRDI, x3);
|
||||
}
|
||||
SMWRITE();
|
||||
break;
|
||||
@@ -915,10 +926,15 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(rex.rep==1) {INST_NAME("REPNZ CMPSW");} else {INST_NAME("REPZ CMPSW");}
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
CBZx_NEXT(xRCX);
|
||||
NOLRCPC();
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
MOVw_REG(xRSI, xRSI);
|
||||
}
|
||||
TBNZ_MARK2(xFlags, F_DF);
|
||||
MARK; // Part with DF==0
|
||||
LDRH_S9_postindex(x1, xRSI, 2);
|
||||
@@ -937,15 +953,20 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
CBNZx_MARK2(xRCX);
|
||||
MARK3; // end
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
STOP_NATIVE_FLAGS(dyn, ninst);
|
||||
break;
|
||||
default:
|
||||
INST_NAME("CMPSW");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
MOVw_REG(xRSI, xRSI);
|
||||
}
|
||||
GETDIR(x3, 2);
|
||||
LDRH_U12(x1, xRSI, 0);
|
||||
LDRH_U12(x2, xRDI, 0);
|
||||
ADDx_REG(xRSI, xRSI, x3);
|
||||
ADDx_REG(xRDI, xRDI, x3);
|
||||
ADDy_REG(xRSI, xRSI, x3);
|
||||
ADDy_REG(xRDI, xRDI, x3);
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
break;
|
||||
}
|
||||
@@ -956,13 +977,17 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
u16 = F16;
|
||||
UBFXx(x1, xRAX, 0, 16);
|
||||
emit_test16c(dyn, ninst, x1, u16, x3, x4, x5);
|
||||
emit_test16c(dyn, ninst, x1, u16, x3, x4);
|
||||
break;
|
||||
|
||||
case 0xAB:
|
||||
if(rex.rep) {
|
||||
INST_NAME("REP STOSW");
|
||||
CBZx_NEXT(xRCX);
|
||||
NOLRCPC();
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
}
|
||||
TBNZ_MARK2(xFlags, F_DF);
|
||||
MARK; // Part with DF==0
|
||||
STRH_S9_postindex(xRAX, xRDI, 2);
|
||||
@@ -977,9 +1002,13 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
// done
|
||||
} else {
|
||||
INST_NAME("STOSW");
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
}
|
||||
GETDIR(x3, 2);
|
||||
STRH_U12(xRAX, xRDI, 0);
|
||||
ADDx_REG(xRDI, xRDI, x3);
|
||||
unscaled = 0;
|
||||
STH(xRAX, xRDI, 0);
|
||||
ADDy_REG(xRDI, xRDI, x3);
|
||||
}
|
||||
SMWRITE();
|
||||
break;
|
||||
@@ -988,6 +1017,9 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(rex.rep) {
|
||||
INST_NAME("REP LODSW");
|
||||
CBZx_NEXT(xRCX);
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRSI, xRSI);
|
||||
}
|
||||
TBNZ_MARK2(xFlags, F_DF);
|
||||
MARK; // Part with DF==0
|
||||
LDRH_S9_postindex(x2, xRSI, 2);
|
||||
@@ -1003,9 +1035,12 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
// done
|
||||
} else {
|
||||
INST_NAME("LODSW");
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRSI, xRSI);
|
||||
}
|
||||
GETDIR(x3, 2);
|
||||
LDRH_U12(x2, xRSI, 0);
|
||||
ADDx_REG(xRSI, xRSI, x3);
|
||||
ADDy_REG(xRSI, xRSI, x3);
|
||||
BFIz(xRAX, x2, 0, 16);
|
||||
}
|
||||
break;
|
||||
@@ -1017,10 +1052,14 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(rex.rep==1) {INST_NAME("REPNZ SCASW");} else {INST_NAME("REPZ SCASW");}
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
CBZx_NEXT(xRCX);
|
||||
NOLRCPC();
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
}
|
||||
UXTHw(x1, xRAX);
|
||||
TBNZ_MARK2(xFlags, F_DF);
|
||||
MARK; // Part with DF==0
|
||||
@@ -1038,14 +1077,18 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
CBNZx_MARK2(xRCX);
|
||||
MARK3; // end
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
STOP_NATIVE_FLAGS(dyn, ninst);
|
||||
break;
|
||||
default:
|
||||
INST_NAME("SCASW");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(rex.is67 && !rex.is32bits) {
|
||||
MOVw_REG(xRDI, xRDI);
|
||||
}
|
||||
GETDIR(x3, 2);
|
||||
UXTHw(x1, xRAX);
|
||||
LDRH_U12(x2, xRDI, 0);
|
||||
ADDx_REG(xRDI, xRDI, x3);
|
||||
ADDy_REG(xRDI, xRDI, x3);
|
||||
emit_cmp16(dyn, ninst, x1, x2, x3, x4, x5);
|
||||
break;
|
||||
}
|
||||
@@ -1076,10 +1119,10 @@ 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) & 0x1f;
|
||||
if (u8) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
|
||||
SETFLAGS((!BOX64ENV(cputype) && (u8 > 1) && MODREG) ? X_CF : (X_OF | X_CF), SF_SUBSET); // removed PENDING on purpose
|
||||
GETEW(x1, 1);
|
||||
u8 = (F8)&0x1f;
|
||||
emit_rol16c(dyn, ninst, x1, u8, x4, x5);
|
||||
emit_rol16c(dyn, ninst, x1, u8, x4, x5, MODREG);
|
||||
EWBACK;
|
||||
} else {
|
||||
FAKEED;
|
||||
@@ -1088,11 +1131,12 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("ROR Ew, Ib");
|
||||
if (geted_ib(dyn, addr, ninst, nextop) & 0x1f) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop) & 0x1f;
|
||||
if (u8) {
|
||||
SETFLAGS((!BOX64ENV(cputype) && (u8 > 1) && MODREG) ? X_CF : (X_OF | X_CF), SF_SUBSET); // removed PENDING on purpose
|
||||
GETEW(x1, 1);
|
||||
u8 = (F8)&0x1f;
|
||||
emit_ror16c(dyn, ninst, x1, u8, x4, x5);
|
||||
emit_ror16c(dyn, ninst, x1, u8, x4, x5, MODREG);
|
||||
EWBACK;
|
||||
} else {
|
||||
FAKEED;
|
||||
@@ -1207,14 +1251,14 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("ROL Ew, 1");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
|
||||
GETEW(x1, 0);
|
||||
emit_rol16c(dyn, ninst, x1, 1, x5, x4);
|
||||
emit_rol16c(dyn, ninst, x1, 1, x5, x4, 0);
|
||||
EWBACK;
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("ROR Ew, 1");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET); // removed PENDING on purpose
|
||||
GETEW(x1, 0);
|
||||
emit_ror16c(dyn, ninst, x1, 1, x5, x4);
|
||||
emit_ror16c(dyn, ninst, x1, 1, x5, x4, 0);
|
||||
EWBACK;
|
||||
break;
|
||||
case 2:
|
||||
@@ -1405,7 +1449,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("SHL Ew, CL");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
ANDw_mask(x2, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
@@ -1420,7 +1464,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("SHR Ew, CL");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
ANDw_mask(x2, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
@@ -1435,7 +1479,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("SAR Ew, CL");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
ANDw_mask(x2, xRCX, 0, 0b00100); //mask=0x00000001f
|
||||
@@ -1521,7 +1565,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;
|
||||
emit_test16c(dyn, ninst, x1, u16, x3, x4, x5);
|
||||
emit_test16c(dyn, ninst, x1, u16, x3, x4);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("NOT Ew");
|
||||
@@ -1545,9 +1589,9 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 4:
|
||||
INST_NAME("MUL AX, Ew");
|
||||
if (BOX64DRENV(dynarec_safeflags) && BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_NODF);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
}
|
||||
GETEW(x1, 0);
|
||||
UXTHw(x2, xRAX);
|
||||
@@ -1576,9 +1620,9 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 5:
|
||||
INST_NAME("IMUL AX, Ew");
|
||||
if (BOX64DRENV(dynarec_safeflags) && BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_NODF);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
}
|
||||
GETSEW(x1, 0);
|
||||
SXTHw(x2, xRAX);
|
||||
@@ -1607,7 +1651,7 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("DIV Ew");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
GETEW(x1, 0);
|
||||
UXTHw(x2, xRAX);
|
||||
BFIw(x2, xRDX, 16, 16);
|
||||
@@ -1647,9 +1691,9 @@ uintptr_t dynarec64_66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("IDIV Ew");
|
||||
SKIPTEST(x1);
|
||||
if (!BOX64DRENV(dynarec_safeflags)) {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
} else if (BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_SF|X_PF|X_ZF|X_AF, SF_SET);
|
||||
SETFLAGS(X_SF|X_PF|X_ZF|X_AF, SF_SUBSET);
|
||||
}
|
||||
GETSEW(x1, 0);
|
||||
if(BOX64ENV(dynarec_div0)) {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -304,7 +305,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
// no special check...
|
||||
case 0x2F:
|
||||
if(opcode==0x2F) {INST_NAME("COMISD Gx, Ex");} else {INST_NAME("UCOMISD Gx, Ex");}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
GETEXSD(q0, 0, 0);
|
||||
@@ -497,7 +498,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
case 0x17:
|
||||
INST_NAME("PTEST Gx, Ex");
|
||||
nextop = F8;
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
GETGX(v0, 0);
|
||||
GETEX(v1, 0, 0);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
@@ -950,9 +951,13 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
}
|
||||
} else {
|
||||
MRS_nzcv(x3);
|
||||
BFIx(x3, xFlags, 29, 1); // set C
|
||||
MSR_nzcv(x3); // load CC into ARM CF
|
||||
if(cpuext.flagm)
|
||||
RMIF(xFlags, 63, 0b0010);
|
||||
else {
|
||||
MRS_nzcv(x3);
|
||||
BFIx(x3, xFlags, 29, 1); // set C
|
||||
MSR_nzcv(x3); // load CC into ARM CF
|
||||
}
|
||||
}
|
||||
IFX(X_CF) {
|
||||
ADCSxw_REG(gd, gd, ed);
|
||||
@@ -1276,12 +1281,14 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
PMULL2_128(q0, q0, q1);
|
||||
break;
|
||||
case 0b00000001:
|
||||
VEXTQ_8(q0, q0, q0, 8); // Swap Up/Lower 64bits parts
|
||||
PMULL_128(q0, q0, q1);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
VEXTQ_8(d0, q0, q0, 8); // Swap Up/Lower 64bits parts
|
||||
PMULL_128(q0, d0, q1);
|
||||
break;
|
||||
case 0b00010000:
|
||||
VEXTQ_8(q0, q0, q0, 8); // Swap Up/Lower 64bits parts
|
||||
PMULL2_128(q0, q0, q1);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
VEXTQ_8(d0, q0, q0, 8); // Swap Up/Lower 64bits parts
|
||||
PMULL2_128(q0, d0, q1);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
@@ -1317,6 +1324,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
if(ed>7)
|
||||
sse_reflect_reg(dyn, ninst, ed);
|
||||
else
|
||||
sse_mark_used(dyn, ninst, ed);
|
||||
ADDx_U12(x1, xEmu, offsetof(x64emu_t, xmm[ed]));
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 1);
|
||||
@@ -1327,7 +1336,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
MOVx_REG(x2, xRDX);
|
||||
MOVx_REG(x4, xRAX);
|
||||
u8 = F8;
|
||||
MOV32w(x5, u8);
|
||||
MOV32w(x5, u8 | (rex.w << 8)); // REX.W in bit 8 of the imm8 argument
|
||||
CALL(const_sse42_compare_string_explicit_len, x1);
|
||||
q0 = sse_get_reg_empty(dyn, ninst, x2, 0);
|
||||
if(u8&0b1000000) {
|
||||
@@ -1367,7 +1376,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETG;
|
||||
u8 = geted_ib(dyn, addr, ninst, nextop);
|
||||
if((u8&0b1100)==0b1000) {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
// this case is (un)signed word, equal each
|
||||
GETGX(v0, 0);
|
||||
GETEX(v1, 0, 1);
|
||||
@@ -1405,6 +1414,11 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VMOVBto(x2, d0, 0);
|
||||
BFIw(x1, x2, 8, 8); // insert
|
||||
}
|
||||
#ifdef BOX64EC
|
||||
int lreg = x2; // no x6 (guest R9): lreg is lost in min(lmem, lreg) and recomputed for SF
|
||||
#else
|
||||
int lreg = x6;
|
||||
#endif
|
||||
// get abs of eax / edx and find min
|
||||
ADDSxw_U12(x2, xRAX, 0);
|
||||
Bcond(cPL, 4+4);
|
||||
@@ -1413,17 +1427,24 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
Bcond(cPL, 4+4);
|
||||
NEGxw_REG(x3, x3);
|
||||
MOV32w(x4, (u8&1)?8:16);
|
||||
CMPSw_REG(x3, x4);
|
||||
CSELw(x3, x3, x4, cLT); // x3 is lmem
|
||||
CMPSw_REG(x2, x4);
|
||||
CSELw(x6, x2, x4, cLT); // x6 is lreg
|
||||
CMPSw_REG(x6, x3);
|
||||
CSELw(x5, x3, x6, cLT); // x5 is max(lmem, lreg)
|
||||
CSELw(x2, x6, x3, cLT); // x2 is min(lmem, lreg)
|
||||
if(rex.w) {
|
||||
CMPSx_REG(x3, x4);
|
||||
CSELx(x3, x3, x4, cLO); // x3 is lmem
|
||||
CMPSx_REG(x2, x4);
|
||||
CSELx(lreg, x2, x4, cLO);
|
||||
} else {
|
||||
CMPSw_REG(x3, x4);
|
||||
CSELw(x3, x3, x4, cLO); // x3 is lmem
|
||||
CMPSw_REG(x2, x4);
|
||||
CSELw(lreg, x2, x4, cLO);
|
||||
}
|
||||
CMPSw_REG(lreg, x3);
|
||||
CSELw(x5, x3, lreg, cLT); // x5 is max(lmem, lreg)
|
||||
CSELw(x2, lreg, x3, cLT); // x2 is min(lmem, lreg)
|
||||
// x2 is min length 0-n_packed
|
||||
MVNw_REG(x4, xZR);
|
||||
LSLw_REG(x87pc, x4, x2);
|
||||
BICw_REG(x1, x1, x87pc);
|
||||
LSLw_REG(x2, x4, x2);
|
||||
BICw_REG(x1, x1, x2);
|
||||
LSLw_REG(x4, x4, x5);
|
||||
ORRw_REG(x1, x1, x4);
|
||||
ANDw_mask(x1, x1, 0, (u8&1)?7:15);
|
||||
@@ -1455,8 +1476,17 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
BFIw(xFlags, x5, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
#ifdef BOX64EC
|
||||
// lreg was overwritten by min(lmem, lreg), recompute it from abs(RAX)
|
||||
ADDSxw_U12(x2, xRAX, 0);
|
||||
Bcond(cPL, 4+4);
|
||||
NEGxw_REG(x2, x2);
|
||||
CMPSxw_REG(x2, x4);
|
||||
CSETw(x5, cLO);
|
||||
#else
|
||||
CMPSw_REG(x6, x4);
|
||||
CSETw(x5, cLT);
|
||||
#endif
|
||||
BFIw(xFlags, x5, F_SF, 1);
|
||||
}
|
||||
}
|
||||
@@ -1481,11 +1511,15 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
SETFLAGS(X_ALL, SF_SET_DF);
|
||||
if(gd>7) // no need to reflect cache as xmm0-xmm7 will be saved before the function call anyway
|
||||
sse_reflect_reg(dyn, ninst, gd);
|
||||
else
|
||||
sse_mark_used(dyn, ninst, gd);
|
||||
ADDx_U12(x3, xEmu, offsetof(x64emu_t, xmm[gd]));
|
||||
if(MODREG) {
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
if(ed>7)
|
||||
sse_reflect_reg(dyn, ninst, ed);
|
||||
else
|
||||
sse_mark_used(dyn, ninst, ed);
|
||||
ADDx_U12(x1, xEmu, offsetof(x64emu_t, xmm[ed]));
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 1);
|
||||
@@ -1493,10 +1527,10 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
MOVx_REG(x1, ed);
|
||||
}
|
||||
}
|
||||
MOVw_REG(x2, xRDX);
|
||||
MOVw_REG(x4, xRAX);
|
||||
MOVx_REG(x2, xRDX);
|
||||
MOVx_REG(x4, xRAX);
|
||||
u8 = F8;
|
||||
MOV32w(x5, u8);
|
||||
MOV32w(x5, u8 | (rex.w << 8)); // REX.W in bit 8 of the imm8 argument
|
||||
CALL(const_sse42_compare_string_explicit_len, x1);
|
||||
}
|
||||
if(u8&0b1000000) {
|
||||
@@ -1524,6 +1558,8 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
if(ed>7)
|
||||
sse_reflect_reg(dyn, ninst, ed);
|
||||
else
|
||||
sse_mark_used(dyn, ninst, ed);
|
||||
ADDx_U12(x1, xEmu, offsetof(x64emu_t, xmm[ed]));
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 1);
|
||||
@@ -1573,11 +1609,15 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETG;
|
||||
if(gd>7)
|
||||
sse_reflect_reg(dyn, ninst, gd);
|
||||
else
|
||||
sse_mark_used(dyn, ninst, gd);
|
||||
ADDx_U12(x2, xEmu, offsetof(x64emu_t, xmm[gd]));
|
||||
if(MODREG) {
|
||||
ed = (nextop&7)+(rex.b<<3);
|
||||
if(ed>7)
|
||||
sse_reflect_reg(dyn, ninst, ed);
|
||||
else
|
||||
sse_mark_used(dyn, ninst, ed);
|
||||
ADDx_U12(x1, xEmu, offsetof(x64emu_t, xmm[ed]));
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 1);
|
||||
@@ -1597,7 +1637,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
MOV32w(x2, 31);
|
||||
SUBw_REG(xRCX, x2, xRCX);
|
||||
} else {
|
||||
RBITxw(xRCX, x1);
|
||||
RBITw(xRCX, x1);
|
||||
CLZw(xRCX, xRCX);
|
||||
}
|
||||
break;
|
||||
@@ -2058,7 +2098,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 1);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
}
|
||||
u8 = F8;
|
||||
GETGX_empty(v0);
|
||||
@@ -2450,7 +2490,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
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);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, (1<<1)-1, rex, NULL, 0, 0);
|
||||
SBFXx(x1, gd, 4, 12); // r1 = (gw>>4)
|
||||
ADDx_REG_LSL(x3, wback, x1, 1); //(&ed)+=r1*2;
|
||||
LDH(x1, x3, fixedaddress);
|
||||
@@ -2485,7 +2525,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
INST_NAME("SHLD Ew, Gw, CL");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETGW(x2);
|
||||
@@ -2494,7 +2534,14 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
UFLAG_IF {
|
||||
CBZw_NEXT(x4);
|
||||
}
|
||||
#ifdef BOX64EC
|
||||
// x1 to x5 are all in use and x6 is guest R9, so the address in x3 goes through the emu
|
||||
if(wback==x3) STRx_U12(x3, xEmu, offsetof(x64emu_t, scratch[0]));
|
||||
emit_shld16(dyn, ninst, ed, gd, x4, x5, x3);
|
||||
if(wback==x3) LDRx_U12(x3, xEmu, offsetof(x64emu_t, scratch[0]));
|
||||
#else
|
||||
emit_shld16(dyn, ninst, ed, gd, x4, x5, x6);
|
||||
#endif
|
||||
EWBACK;
|
||||
break;
|
||||
|
||||
@@ -2511,7 +2558,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
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);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, (1<<1)-1, rex, NULL, 0, 0);
|
||||
SBFXx(x4, gd, 4, 12); // r1 = (gw>>4)
|
||||
ADDx_REG_LSL(x3, wback, x4, 1); //(&ed)+=r1*2;
|
||||
LDH(x4, x3, fixedaddress);
|
||||
@@ -2554,7 +2601,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
INST_NAME("SHRD Ew, Gw, CL");
|
||||
if(BOX64DRENV(dynarec_safeflags)>1) {
|
||||
READFLAGS(X_ALL);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
} else
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETGW(x2);
|
||||
@@ -2564,7 +2611,14 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
CBZw_NEXT(x4);
|
||||
} else {
|
||||
}
|
||||
#ifdef BOX64EC
|
||||
// as SHLD, the address in x3 goes through the emu
|
||||
if(wback==x3) STRx_U12(x3, xEmu, offsetof(x64emu_t, scratch[0]));
|
||||
emit_shrd16(dyn, ninst, ed, gd, x4, x5, x3);
|
||||
if(wback==x3) LDRx_U12(x3, xEmu, offsetof(x64emu_t, scratch[0]));
|
||||
#else
|
||||
emit_shrd16(dyn, ninst, ed, gd, x4, x5, x6);
|
||||
#endif
|
||||
EWBACK;
|
||||
break;
|
||||
case 0xAE:
|
||||
@@ -2593,9 +2647,9 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
case 0xAF:
|
||||
INST_NAME("IMUL Gw,Ew");
|
||||
if (BOX64DRENV(dynarec_safeflags) && BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_NODF);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
}
|
||||
nextop = F8;
|
||||
GETSEW(x1, 0);
|
||||
@@ -2637,7 +2691,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
wback = 0;
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<2, (1<<2)-1, rex, NULL, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, (1<<1)-1, rex, NULL, 0, 0);
|
||||
SBFXx(x4, gd, 4, 12); // r1 = (gw>>4)
|
||||
ADDx_REG_LSL(x3, wback, x4, 1); //(&ed)+=r1*2;
|
||||
LDH(x4, x3, fixedaddress);
|
||||
@@ -2706,10 +2760,9 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
} else {
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
}
|
||||
gd = x2;
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
u8&=rex.w?0x3f:0x0f;
|
||||
u8&=0x0f;
|
||||
IFX(X_CF) {
|
||||
BFXILxw(xFlags, ed, u8, 1); // inject 1 bit from u8 to F_CF (i.e. pos 0)
|
||||
}
|
||||
@@ -2723,7 +2776,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
u8&=(rex.w?0x3f:0x0f);
|
||||
u8&=0x0f;
|
||||
IFX(X_CF) {
|
||||
BFXILxw(xFlags, ed, u8, 1); // inject 1 bit from u8 to F_CF (i.e. pos 0)
|
||||
}
|
||||
@@ -2740,7 +2793,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
u8&=(rex.w?0x3f:0x0f);
|
||||
u8&=0x0f;
|
||||
IFX(X_CF) {
|
||||
BFXILxw(xFlags, ed, u8, 1); // inject 1 bit from u8 to F_CF (i.e. pos 0)
|
||||
}
|
||||
@@ -2756,7 +2809,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
GETEW(x1, 1);
|
||||
u8 = F8;
|
||||
u8&=(rex.w?0x3f:0x0f);
|
||||
u8&=0x0f;
|
||||
IFX(X_CF) {
|
||||
BFXILxw(xFlags, ed, u8, 1); // inject 1 bit from u8 to F_CF (i.e. pos 0)
|
||||
}
|
||||
@@ -2783,7 +2836,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
wback = 0;
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<2, (1<<2)-1, rex, NULL, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, (1<<1)-1, rex, NULL, 0, 0);
|
||||
SBFXx(x4, gd, 4, 12); // r1 = (gw>>4)
|
||||
ADDx_REG_LSL(x3, wback, x4, 1); //(&ed)+=r1*2;
|
||||
LDH(x4, x3, fixedaddress);
|
||||
@@ -2809,7 +2862,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if (!BOX64DRENV(dynarec_safeflags) || BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_ZF, SF_SUBSET);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
}
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
@@ -2845,7 +2898,7 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if (!BOX64DRENV(dynarec_safeflags) || BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_ZF, SF_SUBSET);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
}
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
@@ -2923,9 +2976,13 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGW(x1);
|
||||
GETEW(x2, 0);
|
||||
BFIx(TO_NAT(((nextop & 0x38) >> 3) + (rex.r << 3)), ed, 0, 16);
|
||||
u8 = TO_NAT(((nextop & 0x38) >> 3) + (rex.r << 3));
|
||||
emit_add16(dyn, ninst, ed, gd, x4, x5);
|
||||
EWBACK;
|
||||
if (!(MODREG && wback == u8)) {
|
||||
SUBw_REG(gd, ed, gd); // the old Ew is the sum minus Gw
|
||||
BFIx(u8, gd, 0, 16);
|
||||
}
|
||||
break;
|
||||
case 0xC2:
|
||||
INST_NAME("CMPPD Gx, Ex, Ib");
|
||||
@@ -3006,6 +3063,40 @@ uintptr_t dynarec64_660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC7:
|
||||
nextop = F8;
|
||||
if (MODREG) switch ((nextop >> 3) & 7) {
|
||||
case 6:
|
||||
case 7:
|
||||
if (((nextop >> 3) & 7) == 7) {
|
||||
INST_NAME("RDSEED Ew");
|
||||
} else {
|
||||
INST_NAME("RDRAND Ew");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
SET_DFNONE();
|
||||
GETEW(x2, 0);
|
||||
IFX(X_OF|X_SF|X_ZF|X_PF|X_AF) {
|
||||
MOV32w(x1, (1<<F_OF)|(1<<F_SF)|(1<<F_ZF)|(1<<F_PF)|(1<<F_AF));
|
||||
BICw(xFlags, xFlags, x1);
|
||||
}
|
||||
if (cpuext.rndr) {
|
||||
MRS_rndr(x1);
|
||||
IFX(X_CF) { CSETw(x3, cNE); }
|
||||
} else {
|
||||
CALL(const_random32, x1);
|
||||
IFX(X_CF) { MOV32w(x3, 1); }
|
||||
}
|
||||
IFX(X_CF) { BFIw(xFlags, x3, F_CF, 1); }
|
||||
EWBACKW(x1);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
} else {
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
case 0xCA:
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -114,7 +115,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
INST_NAME("LOCK CMPXCHG Ew, Gw");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETGD;
|
||||
UXTHw(x6, xRAX);
|
||||
UXTHw(x5, xRAX);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
if(!ALIGNED_ATOMICH) {
|
||||
if(cpuext.uscat) {
|
||||
@@ -128,12 +129,12 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
// Aligned version
|
||||
if(cpuext.atomics) {
|
||||
MOVw_REG(x1, x6);
|
||||
MOVw_REG(x1, x5);
|
||||
CASALH(x1, gd, wback);
|
||||
} else {
|
||||
MARKLOCK;
|
||||
LDAXRH(x1, wback);
|
||||
CMPSw_REG(x6, x1);
|
||||
CMPSw_REG(x5, x1);
|
||||
B_MARK(cNE);
|
||||
// EAX == Ed
|
||||
STLXRH(x4, gd, wback);
|
||||
@@ -148,7 +149,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
LDAXRB(x3, wback); // dummy read, to arm the write...
|
||||
SUBw_UXTB(x3, x3, x1);
|
||||
CBNZw_MARK3(x3);
|
||||
CMPSw_REG(x6, x1);
|
||||
CMPSw_REG(x5, x1);
|
||||
B_MARK(cNE);
|
||||
// EAX == Ed
|
||||
STLXRB(x4, gd, wback);
|
||||
@@ -157,7 +158,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
}
|
||||
MARK;
|
||||
// Common part (and fallback for EAX != Ed)
|
||||
UFLAG_IF {emit_cmp16(dyn, ninst, x6, x1, x3, x4, x5);}
|
||||
UFLAG_IF {emit_cmp16(dyn, ninst, x5, x1, x3, x4, x2);}
|
||||
BFIx(xRAX, x1, 0, 16);
|
||||
}
|
||||
break;
|
||||
@@ -210,11 +211,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETGW(x5);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
MOVx_REG(x6, xFlags);
|
||||
MRS_nzcv(x87pc);
|
||||
MARKLOCK;
|
||||
MOVx_REG(xFlags, x6);
|
||||
MSR_nzcv(x87pc);
|
||||
MARKLOCK_SAVE_FLAGS();
|
||||
LDAXRH(x1, wback);
|
||||
emit_adc16(dyn, ninst, x1, x5, x3, x4);
|
||||
STLXRH(x3, x1, wback);
|
||||
@@ -361,11 +358,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOV32w(x5, (uint16_t)i16);
|
||||
MOVx_REG(x6, xFlags);
|
||||
MRS_nzcv(x87pc);
|
||||
MARKLOCK;
|
||||
MOVx_REG(xFlags, x6);
|
||||
MSR_nzcv(x87pc);
|
||||
MARKLOCK_SAVE_FLAGS();
|
||||
LDAXRH(x1, wback);
|
||||
emit_adc16(dyn, ninst, x1, x5, x3, x4);
|
||||
STLXRH(x3, x1, wback);
|
||||
@@ -386,11 +379,7 @@ uintptr_t dynarec64_66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?2:1);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
MOV32w(x5, (uint16_t)i16);
|
||||
MOVx_REG(x6, xFlags);
|
||||
MRS_nzcv(x87pc);
|
||||
MARKLOCK;
|
||||
MOVx_REG(xFlags, x6);
|
||||
MSR_nzcv(x87pc);
|
||||
MARKLOCK_SAVE_FLAGS();
|
||||
LDAXRH(x1, wback);
|
||||
emit_sbb16(dyn, ninst, x1, x5, x3, x4);
|
||||
STLXRH(x3, x1, wback);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -49,7 +50,7 @@ uintptr_t dynarec64_66F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
switch(opcode) {
|
||||
case 0xB8:
|
||||
INST_NAME("POPCNT Gw, Ew");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
GETGW(x2);
|
||||
@@ -85,7 +86,7 @@ uintptr_t dynarec64_66F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
if(BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_ALL&~X_OF, SF_SUBSET);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
}
|
||||
}
|
||||
SET_DFNONE();
|
||||
@@ -123,7 +124,7 @@ uintptr_t dynarec64_66F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
if(BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_ALL&~X_OF, SF_SUBSET);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
}
|
||||
}
|
||||
SET_DFNONE();
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
@@ -12,6 +13,11 @@
|
||||
#include "dynarec_arm64_arch.h"
|
||||
#include "dynarec_arm64_functions.h"
|
||||
#include "dynarec_native.h"
|
||||
#include "custommem.h"
|
||||
#include "khash.h"
|
||||
|
||||
KHASH_SET_INIT_INT64(lrcpc)
|
||||
static kh_lrcpc_t *lrcpc = NULL;
|
||||
|
||||
//order might be important, so define SUPER for the right one
|
||||
#define SUPER() \
|
||||
@@ -67,6 +73,7 @@ typedef struct arch_arch_s
|
||||
SUPER()
|
||||
#undef GO
|
||||
uint16_t unaligned:1;
|
||||
uint16_t lrcpc:1;
|
||||
uint16_t seq:10; // how many instruction on the same values
|
||||
} arch_arch_t;
|
||||
|
||||
@@ -76,6 +83,7 @@ typedef struct arch_build_s
|
||||
SUPER()
|
||||
#undef GO
|
||||
uint8_t unaligned;
|
||||
uint8_t lrcpc;
|
||||
#define GO(A) arch_##A##_t A##_;
|
||||
SUPER()
|
||||
#undef GO
|
||||
@@ -91,16 +99,18 @@ static int arch_build(dynarec_arm_t* dyn, int ninst, arch_build_t* arch, int noa
|
||||
arch->flags = 1;
|
||||
arch->flags_.defered = (dyn->insts[ninst].f_entry!=status_none && dyn->insts[ninst].f_entry!=status_none_pending);
|
||||
uint8_t flags = dyn->insts[ninst].need_nat_flags | dyn->insts[ninst].before_nat_flags;
|
||||
arch->flags_.vf = flags&NF_VF;
|
||||
arch->flags_.nf = flags&NF_SF;
|
||||
arch->flags_.eq = flags&NF_EQ;
|
||||
arch->flags_.cf = flags&NF_CF;
|
||||
arch->flags_.vf = !!(flags&NF_VF);
|
||||
arch->flags_.nf = !!(flags&NF_SF);
|
||||
arch->flags_.eq = !!(flags&NF_EQ);
|
||||
arch->flags_.cf = !!(flags&NF_CF);
|
||||
if(arch->flags_.cf)
|
||||
arch->flags_.inv_cf = !dyn->insts[ninst].normal_carry;
|
||||
arch->flags_.pf_v = flags&NF_PF_V;
|
||||
arch->flags_.pf_v = !!(flags&NF_PF_V);
|
||||
}
|
||||
// opcode can handle unaligned
|
||||
arch->unaligned = dyn->insts[ninst].unaligned;
|
||||
// opcode has lrcpc opcode in it
|
||||
arch->lrcpc = dyn->insts[ninst].has_lrcpc;
|
||||
if(!noarch) {
|
||||
// got through all naoncache to gather regs assignments
|
||||
if(dyn->use_x87 || dyn->use_mmx || dyn->use_xmm || dyn->use_ymm) {
|
||||
@@ -120,29 +130,29 @@ static int arch_build(dynarec_arm_t* dyn, int ninst, arch_build_t* arch, int noa
|
||||
arch->ymm = 1;
|
||||
arch->ymm_.ymm |= 1<<dyn->insts[ninst].n.neoncache[i].n;
|
||||
idx = i;
|
||||
if(idx>=EMM0 && idx<=EMM0+8)
|
||||
if(idx>=EMM0 && idx<EMM0+8)
|
||||
idx-=EMM0;
|
||||
else
|
||||
idx-=SCRATCH0-8;
|
||||
arch->ymm_.ymm_pos |= idx<<(dyn->insts[ninst].n.neoncache[i].n*4);
|
||||
arch->ymm_.ymm_pos |= (uint64_t)idx<<(dyn->insts[ninst].n.neoncache[i].n*4);
|
||||
break;
|
||||
case NEON_CACHE_ST_D:
|
||||
arch->x87 = 1;
|
||||
arch->x87_.x87 |= 1<<dyn->insts[ninst].n.neoncache[i].n;
|
||||
arch->x87_.x87_pos = (i-EMM0)<<(dyn->insts[ninst].n.neoncache[i].n*4);
|
||||
arch->x87_.x87_type = (X87_ST_D)<<(dyn->insts[ninst].n.neoncache[i].n*2);
|
||||
arch->x87_.x87_pos |= (i-EMM0)<<(dyn->insts[ninst].n.neoncache[i].n*4);
|
||||
arch->x87_.x87_type |= (X87_ST_D)<<(dyn->insts[ninst].n.neoncache[i].n*2);
|
||||
break;
|
||||
case NEON_CACHE_ST_F:
|
||||
arch->x87 = 1;
|
||||
arch->x87_.x87 |= 1<<dyn->insts[ninst].n.neoncache[i].n;
|
||||
arch->x87_.x87_pos = (i-EMM0)<<(dyn->insts[ninst].n.neoncache[i].n*4);
|
||||
arch->x87_.x87_type = (X87_ST_F)<<(dyn->insts[ninst].n.neoncache[i].n*2);
|
||||
arch->x87_.x87_pos |= (i-EMM0)<<(dyn->insts[ninst].n.neoncache[i].n*4);
|
||||
arch->x87_.x87_type |= (X87_ST_F)<<(dyn->insts[ninst].n.neoncache[i].n*2);
|
||||
break;
|
||||
case NEON_CACHE_ST_I64:
|
||||
arch->x87 = 1;
|
||||
arch->x87_.x87 |= 1<<dyn->insts[ninst].n.neoncache[i].n;
|
||||
arch->x87_.x87_pos = (i-EMM0)<<(dyn->insts[ninst].n.neoncache[i].n*4);
|
||||
arch->x87_.x87_type = (X87_ST_I64)<<(dyn->insts[ninst].n.neoncache[i].n*2);
|
||||
arch->x87_.x87_pos |= (i-EMM0)<<(dyn->insts[ninst].n.neoncache[i].n*4);
|
||||
arch->x87_.x87_type |= (X87_ST_I64)<<(dyn->insts[ninst].n.neoncache[i].n*2);
|
||||
break;
|
||||
case NEON_CACHE_XMMR:
|
||||
case NEON_CACHE_YMMR:
|
||||
@@ -162,7 +172,7 @@ static int arch_build(dynarec_arm_t* dyn, int ninst, arch_build_t* arch, int noa
|
||||
arch->x87_.delta = dyn->insts[ninst].n.x87stack;
|
||||
}
|
||||
}
|
||||
return arch->flags + arch->x87 + arch->mmx + arch->sse + arch->ymm + arch->unaligned;
|
||||
return arch->flags + arch->x87 + arch->mmx + arch->sse + arch->ymm + arch->unaligned + arch->lrcpc;
|
||||
}
|
||||
|
||||
static int sizeof_arch(arch_arch_t* arch)
|
||||
@@ -217,6 +227,7 @@ static void build_next(arch_arch_t* arch, arch_build_t* build)
|
||||
SUPER()
|
||||
#undef GO
|
||||
arch->unaligned = build->unaligned;
|
||||
arch->lrcpc = build->lrcpc;
|
||||
arch->seq = 0;
|
||||
void* p = ((void*)arch)+sizeof(arch_arch_t);
|
||||
#define GO(A) \
|
||||
@@ -309,6 +320,8 @@ void adjust_arch(dynablock_t* db, x64emu_t* emu, ucontext_t* p, uintptr_t x64pc)
|
||||
if(flags->defered) {
|
||||
CHECK_FLAGS(emu);
|
||||
//return;
|
||||
} else {
|
||||
emu->df = d_none;
|
||||
}
|
||||
if(flags->nf) {
|
||||
CONDITIONAL_SET_FLAG(p->uc_mcontext.pstate&(1<<NZCV_N), F_SF);
|
||||
@@ -358,12 +371,8 @@ void adjust_arch(dynablock_t* db, x64emu_t* emu, ucontext_t* p, uintptr_t x64pc)
|
||||
dynarec_log_prefix(0, LOG_INFO, " ymm[%x, pos=%x, 0=%x (fpsimd=%p)] ", ymm->ymm, ymm->ymm_pos, ymm->ymm0, fpsimd);
|
||||
for(int i=0; i<16; ++i) {
|
||||
if(fpsimd && (ymm->ymm>>i)&1) {
|
||||
int idx = (ymm->ymm_pos>>(i*4))&0xf;
|
||||
if(i>7) {
|
||||
idx = SCRATCH0 + i - 8;
|
||||
} else {
|
||||
idx = EMM0 + i;
|
||||
}
|
||||
int pos = (ymm->ymm_pos>>(i*4))&0xf;
|
||||
int idx = (pos>7) ? (SCRATCH0 + pos - 8) : (EMM0 + pos);
|
||||
emu->ymm[i].u128 = fpsimd->vregs[idx];
|
||||
}
|
||||
if(ymm->ymm0&(1<<i))
|
||||
@@ -380,10 +389,10 @@ void adjust_arch(dynablock_t* db, x64emu_t* emu, ucontext_t* p, uintptr_t x64pc)
|
||||
}
|
||||
if(x87) {
|
||||
dynarec_log_prefix(0, LOG_INFO, " x87[%x, pos=%x, type=%x (fpsimd=%p)] ", x87->x87, x87->x87_pos, x87->x87_type, fpsimd);
|
||||
emu->top -= x87->delta;
|
||||
if (x87->delta) emu->top = (emu->top - x87->delta) & 7;
|
||||
for(int i=0; i<8; ++i) {
|
||||
if(x87->x87&(1<<i)) {
|
||||
int idx = EMM0 + (x87->x87_pos>>(i*4))&0x0f;
|
||||
int idx = EMM0 + ((x87->x87_pos>>(i*4))&0x0f);
|
||||
int t = (x87->x87_type>>(i*2))&0x3;
|
||||
switch (t) {
|
||||
case X87_ST_F:
|
||||
@@ -424,3 +433,53 @@ int arch_unaligned(dynablock_t* db, uintptr_t x64pc)
|
||||
}
|
||||
return arch->unaligned;
|
||||
}
|
||||
|
||||
int arch_lrcpc(dynablock_t* db, uintptr_t x64pc)
|
||||
{
|
||||
if(!db)
|
||||
return 0;
|
||||
if(!db->arch_size || !db->arch)
|
||||
return 0;
|
||||
int ninst = getX64AddressInst(db, x64pc);
|
||||
if(ninst<0) {
|
||||
return 0;
|
||||
}
|
||||
// look for state at ninst
|
||||
arch_arch_t* arch = db->arch;
|
||||
arch_arch_t* next = arch;
|
||||
int i = -1;
|
||||
while(i<ninst) {
|
||||
arch = next;
|
||||
i += 1+arch->seq;
|
||||
next = (arch_arch_t*)((uintptr_t)next + sizeof_arch(arch));
|
||||
}
|
||||
return arch->lrcpc;
|
||||
}
|
||||
|
||||
void add_lrcpc_address(uintptr_t addr)
|
||||
{
|
||||
if(!lrcpc)
|
||||
lrcpc = kh_init(lrcpc);
|
||||
khint_t k;
|
||||
int ret;
|
||||
k = kh_put(lrcpc, lrcpc, addr, &ret); // just add
|
||||
}
|
||||
|
||||
int is_addr_lrcpc(uintptr_t addr)
|
||||
{
|
||||
if(!lrcpc)
|
||||
return 0;
|
||||
khint_t k = kh_get(lrcpc, lrcpc, addr);
|
||||
return (k==kh_end(lrcpc))?0:1;
|
||||
}
|
||||
|
||||
int mark_db_lrcpc(dynablock_t* db, uintptr_t x64pc)
|
||||
{
|
||||
add_lrcpc_address(x64pc);
|
||||
if(db->to_delete)
|
||||
return 2; // already marked
|
||||
db->to_delete = 1; // mark block for deletion
|
||||
MarkDynablock(db); // and mark it as dirty
|
||||
if(BOX64ENV(showsegv)) printf_log(LOG_INFO, "Marked db %p as dirty, and address %p as avoid lrcpc\n", db, (void*)x64pc);
|
||||
return 2; // marked, exit handling...
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#ifndef __DYNAREC_ARM_ARCH_H__
|
||||
#define __DYNAREC_ARM_ARCH_H__
|
||||
|
||||
@@ -21,4 +22,9 @@ void adjust_arch(dynablock_t* db, x64emu_t* emu, ucontext_t* p, uintptr_t x64pc)
|
||||
#endif
|
||||
// get if instruction can be regenerated for unaligned access
|
||||
int arch_unaligned(dynablock_t* db, uintptr_t x64pc);
|
||||
// get if instruction has lrcpc so it can be regenerated without
|
||||
int arch_lrcpc(dynablock_t* db, uintptr_t x64pc);
|
||||
void add_lrcpc_address(uintptr_t addr);
|
||||
int is_addr_lrcpc(uintptr_t addr);
|
||||
int mark_db_lrcpc(dynablock_t* db, uintptr_t x64pc);
|
||||
#endif // __DYNAREC_ARM_ARCH_H__
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -73,8 +74,8 @@ uintptr_t dynarec64_AVX(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ni
|
||||
DEFAULT;
|
||||
}
|
||||
|
||||
if((*ok==-1) && (BOX64ENV(dynarec_log)>=LOG_INFO || dyn->need_dump || BOX64ENV(dynarec_missing)))
|
||||
if(!dyn->size || BOX64ENV(dynarec_log)>LOG_INFO || dyn->need_dump) {
|
||||
if((*ok==-1) && (BOX64ENV(dynarec_log)>=LOG_INFO || (dyn->need_dump && dyn->need_dump != 3) || BOX64ENV(dynarec_missing)))
|
||||
if(!dyn->size || BOX64ENV(dynarec_log)>LOG_INFO || (dyn->need_dump && dyn->need_dump != 3)) {
|
||||
dynarec_log(LOG_NONE, " Dynarec unimplemented %s opcode size %d prefix %s map %s opcode %02X\n",
|
||||
vex.evex ? "EVEX" : "VEX", 128<<vex.l, avx_prefix_string(vex.p), avx_map_string(vex.m), opcode);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -268,6 +269,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
UDF(0);
|
||||
} else {
|
||||
INST_NAME("VMOVNTPS Ex, Gx");
|
||||
NOLRCPC();
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if(vex.l) {
|
||||
@@ -285,7 +287,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
// no special check...
|
||||
case 0x2F:
|
||||
if(opcode==0x2F) {INST_NAME("VCOMISS Gx, Ex");} else {INST_NAME("VUCOMISS Gx, Ex");}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
GETEXSS(s0, 0, 0);
|
||||
@@ -417,7 +419,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
if(vex.l) {
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
VANDQ(v0, v2, v1);
|
||||
} else YMM0(gd)
|
||||
} else YMM0(gd);
|
||||
break;
|
||||
case 0x55:
|
||||
INST_NAME("VANDNPS Gx, Vx, Ex");
|
||||
@@ -427,7 +429,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
if(vex.l) {
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
VBICQ(v0, v1, v2);
|
||||
} else YMM0(gd)
|
||||
} else YMM0(gd);
|
||||
break;
|
||||
case 0x56:
|
||||
INST_NAME("VORPS Gx, Vx, Ex");
|
||||
@@ -437,7 +439,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
if(vex.l) {
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
VORRQ(v0, v2, v1);
|
||||
} else YMM0(gd)
|
||||
} else YMM0(gd);
|
||||
break;
|
||||
case 0x57:
|
||||
INST_NAME("VXORPS Gx, Vx, Ex");
|
||||
@@ -447,7 +449,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
if(vex.l) {
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
VEORQ(v0, v2, v1);
|
||||
} else YMM0(gd)
|
||||
} else YMM0(gd);
|
||||
break;
|
||||
case 0x58:
|
||||
INST_NAME("VADDPS Gx, Vx, Ex");
|
||||
@@ -477,7 +479,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
VBIFQ(v0, q2, q0); // where src1 NaN, use QNaN(src1)
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd)
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x59:
|
||||
INST_NAME("VMULPS Gx, Vx, Ex");
|
||||
@@ -507,7 +509,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
VBIFQ(v0, q2, q0); // where src1 NaN, use QNaN(src1)
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd)
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x5A:
|
||||
INST_NAME("VCVTPS2PD Gx, Ex");
|
||||
@@ -521,7 +523,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
if(vex.l) {
|
||||
GETGY_empty(q0, -1, -1, -1);
|
||||
FCVTL2(q0, v1);
|
||||
} else YMM0(gd)
|
||||
} else YMM0(gd);
|
||||
FCVTL(v0, v1);
|
||||
break;
|
||||
case 0x5B:
|
||||
@@ -532,7 +534,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
if(vex.l) {
|
||||
GETGY_empty_EY(v0, v1);
|
||||
SCVTQFS(v0, v1);
|
||||
} else YMM0(gd)
|
||||
} else YMM0(gd);
|
||||
break;
|
||||
case 0x5C:
|
||||
INST_NAME("VSUBPS Gx, Vx, Ex");
|
||||
@@ -562,7 +564,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
VBIFQ(v0, q2, q0); // where src1 NaN, use QNaN(src1)
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd)
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x5D:
|
||||
INST_NAME("VMINPS Gx, Vx, Ex");
|
||||
@@ -606,7 +608,7 @@ uintptr_t dynarec64_AVX_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int
|
||||
VBIFQ(v0, q2, q0); // where src1 NaN, use QNaN(src1)
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd)
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x5F:
|
||||
INST_NAME("VMAXPS Gx, Vx, Ex");
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -253,15 +254,15 @@ uintptr_t dynarec64_AVX_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, i
|
||||
GETGD;
|
||||
GETED(0);
|
||||
GETVD;
|
||||
UXTBw(x6, vd);
|
||||
CMPSw_U12(x6, rex.w ? 64 : 32);
|
||||
UXTBw(x5, vd);
|
||||
CMPSw_U12(x5, rex.w ? 64 : 32);
|
||||
CSETMxw(x2, cPL);
|
||||
IFX(X_CF) {
|
||||
BFIw(xFlags, x2, F_CF, 1);
|
||||
}
|
||||
MVNxw_REG(x2, x2); //prepare mask
|
||||
B_MARK(cPL);
|
||||
LSLxw_REG(x2, x2, x6);
|
||||
LSLxw_REG(x2, x2, x5);
|
||||
MARK;
|
||||
need_tst = 0;
|
||||
IFX(X_ZF) need_tst = 1;
|
||||
@@ -326,12 +327,8 @@ uintptr_t dynarec64_AVX_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, i
|
||||
IFX(X_AF) BFCw(xFlags, F_AF, 1);
|
||||
IFX(X_PF) BFCw(xFlags, F_PF, 1);
|
||||
IFX(X_CF) BFCw(xFlags, F_CF, 1);
|
||||
IFX(X_OF) {
|
||||
IFNATIVE(NF_VF) {} else { BFCw(xFlags, F_OF, 1); }
|
||||
}
|
||||
IFX(X_SF) {
|
||||
IFNATIVE(NF_SF) {} else { BFCw(xFlags, F_SF, 1); }
|
||||
}
|
||||
IFX(X_OF) BFCw(xFlags, F_OF, 1);
|
||||
IFX(X_SF) BFCw(xFlags, F_SF, 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -243,6 +244,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
|
||||
case 0x2B:
|
||||
INST_NAME("VMOVNTPD Ex,Gx");
|
||||
NOLRCPC();
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
@@ -264,7 +266,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
// no special check...
|
||||
case 0x2F:
|
||||
if(opcode==0x2F) {INST_NAME("VCOMISD Gx, Ex");} else {INST_NAME("VUCOMISD Gx, Ex");}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
nextop = F8;
|
||||
GETGX(v0, 0);
|
||||
GETEXSD(q0, 0, 0);
|
||||
@@ -321,7 +323,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
if(vex.l) {
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
VANDQ(v0, v2, v1);
|
||||
} else YMM0(gd)
|
||||
} else YMM0(gd);
|
||||
break;
|
||||
case 0x55:
|
||||
INST_NAME("VANDNPD Gx, Vx, Ex");
|
||||
@@ -331,7 +333,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
if(vex.l) {
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
VBICQ(v0, v1, v2);
|
||||
} else YMM0(gd)
|
||||
} else YMM0(gd);
|
||||
break;
|
||||
case 0x56:
|
||||
INST_NAME("VORPD Gx, Vx, Ex");
|
||||
@@ -341,7 +343,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
if(vex.l) {
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
VORRQ(v0, v2, v1);
|
||||
} else YMM0(gd)
|
||||
} else YMM0(gd);
|
||||
break;
|
||||
case 0x57:
|
||||
INST_NAME("VXORPD Gx, Vx, Ex");
|
||||
@@ -351,7 +353,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
if(vex.l) {
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
VEORQ(v0, v2, v1);
|
||||
} else YMM0(gd)
|
||||
} else YMM0(gd);
|
||||
break;
|
||||
case 0x58:
|
||||
INST_NAME("VADDPD Gx, Vx, Ex");
|
||||
@@ -413,7 +415,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
VBIFQ(v0, q2, q0); // where src1 NaN, use QNaN(src1)
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd)
|
||||
if(!vex.l) YMM0(gd);
|
||||
break;
|
||||
case 0x5A:
|
||||
INST_NAME("VCVTPD2PS Gx, Ex");
|
||||
@@ -441,7 +443,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
case 0x5B:
|
||||
INST_NAME("VCVTPS2DQ Gx, Ex");
|
||||
nextop = F8;
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x6);
|
||||
u8 = sse_setround(dyn, ninst, x3, x2, x4); // the address below can use x2 and x3, x4 keeps the old FPCR
|
||||
if(!BOX64ENV(dynarec_fastround) && !cpuext.frintts) {
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
@@ -1783,6 +1785,7 @@ uintptr_t dynarec64_AVX_66_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
break;
|
||||
case 0xE7:
|
||||
INST_NAME("VMOVNTDQ Ex,Gx");
|
||||
NOLRCPC();
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -358,7 +359,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
case 0x13:
|
||||
INST_NAME("VCVTPH2PS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX_Y(v1, 0, 0);
|
||||
if(vex.l) {GETEX_Y(v1, 0, 0);} else {GETEX64(v1, 0, 0);}
|
||||
GETGX_empty(v0);
|
||||
if(vex.l && v0==v1) {
|
||||
q1 = fpu_get_scratch(dyn, ninst);
|
||||
@@ -642,6 +643,7 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
break;
|
||||
case 0x2A:
|
||||
INST_NAME("VMOVNTDQA Gx, Ex");
|
||||
NOLRCPC();
|
||||
nextop = F8;
|
||||
GETG;
|
||||
if(MODREG) {
|
||||
@@ -1904,7 +1906,10 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
if(vex.l)
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
} else d0 = -1;
|
||||
if(vex.l) { GETGY_empty_VYEY(v0, v2, v1); }
|
||||
if(vex.l) {
|
||||
if(!MODREG) v1 = fpu_get_scratch(dyn, ninst);
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
}
|
||||
if(d0!=-1) {
|
||||
VMOVQ(d0, q1);
|
||||
if(vex.l) VMOVQ(d1, v1);
|
||||
@@ -1920,8 +1925,8 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
GETGX(q0, 1);
|
||||
VEORQ(q0, q0, (d0==-1)?q1:d0);
|
||||
if(vex.l) {
|
||||
GETGY_empty(v0, (d0==-1)?(nextop&7)+(rex.b<<3):-1, -1, -1);
|
||||
VEORQ(v0, v0, (d0==-1)?v1:d0);
|
||||
GETGY(v0, 1, -1, -1, -1);
|
||||
VEORQ(v0, v0, (d0==-1)?v1:d1);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
@@ -1944,7 +1949,10 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
if(vex.l)
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
} else d0 = -1;
|
||||
if(vex.l) { GETGY_empty_VYEY(v0, v2, v1); }
|
||||
if(vex.l) {
|
||||
if(!MODREG) v1 = fpu_get_scratch(dyn, ninst);
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
}
|
||||
if(d0!=-1) {
|
||||
VMOVQ(d0, q1);
|
||||
if(vex.l) VMOVQ(d1, v1);
|
||||
@@ -1960,8 +1968,8 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
GETGX(q0, 1);
|
||||
VEORQ(q0, q0, (d0==-1)?q1:d0);
|
||||
if(vex.l) {
|
||||
GETGY_empty(v0, (d0==-1)?(nextop&7)+(rex.b<<3):-1, -1, -1);
|
||||
VEORQ(v0, v0, (d0==-1)?v1:d0);
|
||||
GETGY(v0, 1, -1, -1, -1);
|
||||
VEORQ(v0, v0, (d0==-1)?v1:d1);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
@@ -1985,7 +1993,10 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
if(vex.l)
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
} else d0 = -1;
|
||||
if(vex.l) { GETGY_empty_VYEY(v0, v2, v1); }
|
||||
if(vex.l) {
|
||||
if(!MODREG) v1 = fpu_get_scratch(dyn, ninst);
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
}
|
||||
if(d0!=-1) {
|
||||
VMOVQ(d0, q1);
|
||||
if(vex.l) VMOVQ(d1, v1);
|
||||
@@ -2001,8 +2012,8 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
GETGX(q0, 1);
|
||||
VEORQ(q0, q0, (d0==-1)?q1:d0);
|
||||
if(vex.l) {
|
||||
GETGY_empty(v0, (d0==-1)?(nextop&7)+(rex.b<<3):-1, -1, -1);
|
||||
VEORQ(v0, v0, (d0==-1)?v1:d0);
|
||||
GETGY(v0, 1, -1, -1, -1);
|
||||
VEORQ(v0, v0, (d0==-1)?v1:d1);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
@@ -2025,7 +2036,10 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
if(vex.l)
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
} else d0 = -1;
|
||||
if(vex.l) { GETGY_empty_VYEY(v0, v2, v1); }
|
||||
if(vex.l) {
|
||||
if(!MODREG) v1 = fpu_get_scratch(dyn, ninst);
|
||||
GETGY_empty_VYEY(v0, v2, v1);
|
||||
}
|
||||
if(d0!=-1) {
|
||||
VMOVQ(d0, q1);
|
||||
if(vex.l) VMOVQ(d1, v1);
|
||||
@@ -2041,8 +2055,8 @@ uintptr_t dynarec64_AVX_66_0F38(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
GETGX(q0, 1);
|
||||
VEORQ(q0, q0, (d0==-1)?q1:d0);
|
||||
if(vex.l) {
|
||||
GETGY_empty(v0, (d0==-1)?(nextop&7)+(rex.b<<3):-1, -1, -1);
|
||||
VEORQ(v0, v0, (d0==-1)?v1:d0);
|
||||
GETGY(v0, 1, -1, -1, -1);
|
||||
VEORQ(v0, v0, (d0==-1)?v1:d1);
|
||||
}
|
||||
}
|
||||
if(!vex.l) YMM0(gd);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -162,7 +163,7 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
} else {
|
||||
s0 = -1;
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0xffe<<4, 15, rex, NULL, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x3, &fixedaddress, NULL, 0xffe<<4, 15, rex, NULL, 0, 1);
|
||||
}
|
||||
u8 = F8;
|
||||
GETVX(v2, 0);
|
||||
@@ -509,17 +510,17 @@ uintptr_t dynarec64_AVX_66_0F3A(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip
|
||||
}
|
||||
u8 = F8;
|
||||
if(u8&4) {
|
||||
s0 = sse_setround(dyn, ninst, x1, x2, x6);
|
||||
s0 = sse_setround(dyn, ninst, x1, x2, x5);
|
||||
} else {
|
||||
u8&=3;
|
||||
if(u8==1) u8=2;
|
||||
else if(u8==2) u8=1;
|
||||
MRS_fpcr(x1); // get fpscr
|
||||
MOV32w(x2, u8);
|
||||
MOVx_REG(x6, x1);
|
||||
MOVx_REG(x5, x1);
|
||||
BFIx(x1, x2, 22, 2); // inject new round
|
||||
MSR_fpcr(x1); // put new fpscr
|
||||
s0 = x6;
|
||||
s0 = x5;
|
||||
}
|
||||
FCVTN16(v1, v0);
|
||||
if(vex.l) {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -227,7 +228,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeD(v0, 0, d1, 0);
|
||||
YMM0(gd)
|
||||
YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0x58:
|
||||
@@ -259,7 +260,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeD(v0, 0, q2, 0);
|
||||
YMM0(gd)
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x59:
|
||||
INST_NAME("VMULSD Gx, Vx, Ex");
|
||||
@@ -309,7 +310,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeS(v0, 0, d1, 0);
|
||||
YMM0(gd)
|
||||
YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0x5C:
|
||||
@@ -341,7 +342,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeD(v0, 0, q2, 0);
|
||||
YMM0(gd)
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x5D:
|
||||
INST_NAME("VMINSD Gx, Vx, Ex");
|
||||
@@ -356,7 +357,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeD(v0, 0, d1, 0); // to not erase uper part
|
||||
YMM0(gd)
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x5E:
|
||||
INST_NAME("VDIVSD Gx, Vx, Ex");
|
||||
@@ -387,7 +388,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeD(v0, 0, q2, 0);
|
||||
YMM0(gd)
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x5F:
|
||||
INST_NAME("VMAXSD Gx, Vx, Ex");
|
||||
@@ -401,7 +402,7 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeD(v0, 0, d1, 0); // to not erase uper part
|
||||
YMM0(gd)
|
||||
YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0x70:
|
||||
@@ -585,11 +586,12 @@ uintptr_t dynarec64_AVX_F2_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
case 0xE6:
|
||||
INST_NAME("VCVTPD2DQ Gx, Ex");
|
||||
nextop = F8;
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x6);
|
||||
for(int l=0; l<1+vex.l; ++l) {
|
||||
if(!l) {
|
||||
GETEX_Y(v1, 0, 0);
|
||||
GETGX_empty(v0);
|
||||
// after the address, so x2 can keep the old FPCR
|
||||
u8 = sse_setround(dyn, ninst, x4, x5, x2);
|
||||
if(!BOX64ENV(dynarec_fastround) || vex.l)
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
} else {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -294,7 +295,7 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeS(v0, 0, q2, 0);
|
||||
YMM0(gd)
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x59:
|
||||
INST_NAME("VMULSS Gx, Vx, Ex");
|
||||
@@ -325,7 +326,7 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeS(v0, 0, q2, 0);
|
||||
YMM0(gd)
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x5A:
|
||||
INST_NAME("VCVTSS2SD Gx, Vx, Ex");
|
||||
@@ -404,7 +405,7 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeS(v0, 0, q2, 0);
|
||||
YMM0(gd)
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x5D:
|
||||
INST_NAME("VMINSS Gx, Vx, Ex");
|
||||
@@ -418,7 +419,7 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeS(v0, 0, d1, 0); // to not erase uper part
|
||||
YMM0(gd)
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x5E:
|
||||
INST_NAME("VDIVSS Gx, Vx, Ex");
|
||||
@@ -449,7 +450,7 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeS(v0, 0, q2, 0);
|
||||
YMM0(gd)
|
||||
YMM0(gd);
|
||||
break;
|
||||
case 0x5F:
|
||||
INST_NAME("VMAXSS Gx, Vx, Ex");
|
||||
@@ -463,7 +464,7 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
VMOVQ(v0, v2);
|
||||
}
|
||||
VMOVeS(v0, 0, d1, 0); // to not erase uper part
|
||||
YMM0(gd)
|
||||
YMM0(gd);
|
||||
break;
|
||||
|
||||
case 0x6F:
|
||||
@@ -550,6 +551,7 @@ uintptr_t dynarec64_AVX_F3_0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip,
|
||||
} else {
|
||||
IF_UNALIGNED(ip) {
|
||||
MESSAGE(LOG_DEBUG, "\tUnaligned path");
|
||||
NOLRCPC();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
for(int i=0; i<16; ++i) {
|
||||
VST1_8(v0, i, i?x1:wback);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -76,6 +77,8 @@ uintptr_t getConst(arm64_consts_t which)
|
||||
case const_native_fxtract: return (uintptr_t)native_fxtract;
|
||||
case const_direct_ftan: return (uintptr_t)direct_ftan;
|
||||
case const_direct_fpatan: return (uintptr_t)direct_fpatan;
|
||||
case const_native_fprem: return (uintptr_t)native_fprem;
|
||||
case const_native_fprem1: return (uintptr_t)native_fprem1;
|
||||
case const_direct_fcos: return (uintptr_t)direct_fcos;
|
||||
case const_direct_fsin: return (uintptr_t)direct_fsin;
|
||||
case const_native_fsincos: return (uintptr_t)native_fsincos;
|
||||
@@ -122,7 +125,7 @@ uintptr_t getConst(arm64_consts_t which)
|
||||
case const_fpu_xrstor: return (uintptr_t)fpu_xrstor;
|
||||
case const_fpu_fbld: return (uintptr_t)fpu_fbld;
|
||||
case const_fpu_fbst: return (uintptr_t)fpu_fbst;
|
||||
case const_sse42_compare_string_explicit_len: return (uintptr_t)sse42_compare_string_explicit_len;
|
||||
case const_sse42_compare_string_explicit_len: return (uintptr_t)sse42_compare_string_explicit_len_imm8w;
|
||||
case const_sse42_compare_string_implicit_len: return (uintptr_t)sse42_compare_string_implicit_len;
|
||||
case const_x64test_step: return (uintptr_t)x64test_step;
|
||||
case const_printtrace: return (uintptr_t)PrintTrace;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#ifndef __DYNAREC_ARM64_CONSTS__
|
||||
#define __DYNAREC_ARM64_CONSTS__
|
||||
#include <stdint.h>
|
||||
@@ -39,6 +40,8 @@ typedef enum arm64_consts_s {
|
||||
const_native_fxtract,
|
||||
const_direct_ftan,
|
||||
const_direct_fpatan,
|
||||
const_native_fprem,
|
||||
const_native_fprem1,
|
||||
const_direct_fcos,
|
||||
const_direct_fsin,
|
||||
const_native_fsincos,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -30,12 +31,14 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
uint8_t u8;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
int v1, v2;
|
||||
int v1, v2, s5, s6;
|
||||
int s0;
|
||||
|
||||
MAYUSE(s0);
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
MAYUSE(s5);
|
||||
MAYUSE(s6);
|
||||
|
||||
if(MODREG)
|
||||
switch(nextop) {
|
||||
@@ -53,9 +56,25 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_S(v1, v2, s5);
|
||||
}
|
||||
FADDS(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
|
||||
}
|
||||
} else {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, v2, s5);
|
||||
}
|
||||
FADDD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
@@ -75,9 +94,25 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_S(v1, v2, s5);
|
||||
}
|
||||
FMULS(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
|
||||
}
|
||||
} else {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, v2, s5);
|
||||
}
|
||||
FMULD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
@@ -134,9 +169,25 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_S(v1, v2, s5);
|
||||
}
|
||||
FSUBS(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
|
||||
}
|
||||
} else {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, v2, s5);
|
||||
}
|
||||
FSUBD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
@@ -156,9 +207,25 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_S(v2, v1, s5);
|
||||
}
|
||||
FSUBS(v1, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
|
||||
}
|
||||
} else {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v2, v1, s5);
|
||||
}
|
||||
FSUBD(v1, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
@@ -178,9 +245,25 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_S(v1, v2, s5);
|
||||
}
|
||||
FDIVS(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
|
||||
}
|
||||
} else {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, v2, s5);
|
||||
}
|
||||
FDIVD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
@@ -200,9 +283,25 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_S(v2, v1, s5);
|
||||
}
|
||||
FDIVS(v1, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
|
||||
}
|
||||
} else {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v2, v1, s5);
|
||||
}
|
||||
FDIVD(v1, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
@@ -222,10 +321,26 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_S(v1, s0, s5);
|
||||
}
|
||||
FADDS(v1, v1, s0);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_S(v1, s0, s5, s6);
|
||||
}
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, s0, s5);
|
||||
}
|
||||
FADDD(v1, v1, s0);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, s0, s5, s6);
|
||||
}
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
@@ -240,10 +355,26 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_S(v1, s0, s5);
|
||||
}
|
||||
FMULS(v1, v1, s0);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_S(v1, s0, s5, s6);
|
||||
}
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, s0, s5);
|
||||
}
|
||||
FMULD(v1, v1, s0);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, s0, s5, s6);
|
||||
}
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
@@ -287,10 +418,26 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_S(v1, s0, s5);
|
||||
}
|
||||
FSUBS(v1, v1, s0);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_S(v1, s0, s5, s6);
|
||||
}
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, s0, s5);
|
||||
}
|
||||
FSUBD(v1, v1, s0);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, s0, s5, s6);
|
||||
}
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
@@ -305,10 +452,26 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_S(s0, v1, s5);
|
||||
}
|
||||
FSUBS(v1, s0, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_S(v1, s0, s5, s6);
|
||||
}
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(s0, v1, s5);
|
||||
}
|
||||
FSUBD(v1, s0, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, s0, s5, s6);
|
||||
}
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
@@ -323,10 +486,26 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_S(v1, s0, s5);
|
||||
}
|
||||
FDIVS(v1, v1, s0);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_S(v1, s0, s5, s6);
|
||||
}
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, s0, s5);
|
||||
}
|
||||
FDIVD(v1, v1, s0);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, s0, s5, s6);
|
||||
}
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
@@ -341,10 +520,26 @@ uintptr_t dynarec64_D8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_S(s0, v1, s5);
|
||||
}
|
||||
FDIVS(v1, s0, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_S(v1, s0, s5, s6);
|
||||
}
|
||||
} else {
|
||||
FCVT_D_S(s0, s0);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(s0, v1, s5);
|
||||
}
|
||||
FDIVD(v1, s0, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, s0, s5, s6);
|
||||
}
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -236,11 +237,11 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
&& PK(2)==0xD9 && PK(3)==0xF3
|
||||
) {
|
||||
MESSAGE(LOG_DUMP, "Hack for FLD1 FLD1 FPATAN");
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, (BOX64ENV(dynarec_x87double)==1)?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
FTABLE64(v1, PI/4.0);
|
||||
addr+=4;
|
||||
} else {
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, (BOX64ENV(dynarec_x87double)==1)?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0)) {
|
||||
FMOVS_8(v1, 0b01110000);
|
||||
} else {
|
||||
@@ -275,7 +276,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0xEE:
|
||||
INST_NAME("FLDZ");
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, (BOX64ENV(dynarec_x87double)==1)?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
VEOR(v1, v1, v1);
|
||||
break;
|
||||
|
||||
@@ -302,7 +303,7 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
u8 = F8;
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
} else {
|
||||
X87_PUSH_OR_FAIL(v2, dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
X87_PUSH_OR_FAIL(v2, dyn, ninst, x1, (BOX64ENV(dynarec_x87double)==1)?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0)) {
|
||||
FMOVS_8(v2, 0b01110000);
|
||||
} else {
|
||||
@@ -343,26 +344,42 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0xF5:
|
||||
INST_NAME("FPREM1");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 1, NEON_CACHE_ST_D);
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
FDIVD(s0, v1, v2);
|
||||
FRINTRRD(s0, s0, 0b00); // Nearest == TieToEven?
|
||||
FCVTZSxD(x4, s0);
|
||||
FMULD(s0, s0, v2);
|
||||
FSUBD(v1, v1, s0);
|
||||
LDRw_U12(x1, xEmu, offsetof(x64emu_t, sw));
|
||||
// set C2 = 0
|
||||
BFCw(x1, 10, 1);
|
||||
// set C1 = Q0
|
||||
BFIw(x1, x4, 9, 1);
|
||||
// set C3 = Q1
|
||||
LSRx_IMM(x4, x4, 1);
|
||||
BFIw(x1, x4, 14, 1);
|
||||
// Set C0 = Q2
|
||||
LSRx(x4, x4, 1);
|
||||
BFIw(x1, x4, 8, 1);
|
||||
STRw_U12(x1, xEmu, offsetof(x64emu_t, sw));
|
||||
if(!BOX64ENV(dynarec_fastround)) {
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
i1 = x87_stackcount(dyn, ninst, x3);
|
||||
CALL(const_native_fprem1, -1);
|
||||
x87_unstackcount(dyn, ninst, x3, i1);
|
||||
} else {
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 1, NEON_CACHE_ST_D);
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
FMOVxD(x4, v2);
|
||||
LSLx(x4, x4, 1); // remove sign bit
|
||||
RORx(x4, x4, 53); // put exponant in lower 12bits
|
||||
SUBx_U12(x4, x4, 0x7ff);// test is inifite
|
||||
CBNZx_MARK2(x4);
|
||||
MOV32w(x4, 0); // force q to 0
|
||||
B_MARK_nocond;
|
||||
MARK2;
|
||||
FDIVD(s0, v1, v2);
|
||||
FRINTRRD(s0, s0, 0b00); // Nearest == TieToEven?
|
||||
FCVTZSxD(x4, s0);
|
||||
FMSUB_64(v1, v1, s0, v2);
|
||||
MARK;
|
||||
LDRw_U12(x1, xEmu, offsetof(x64emu_t, sw));
|
||||
// set C2 = 0
|
||||
BFCw(x1, 10, 1);
|
||||
// set C1 = Q0
|
||||
BFIw(x1, x4, 9, 1);
|
||||
// set C3 = Q1
|
||||
LSRx_IMM(x4, x4, 1);
|
||||
BFIw(x1, x4, 14, 1);
|
||||
// Set C0 = Q2
|
||||
LSRx(x4, x4, 1);
|
||||
BFIw(x1, x4, 8, 1);
|
||||
STRw_U12(x1, xEmu, offsetof(x64emu_t, sw));
|
||||
}
|
||||
break;
|
||||
case 0xF6:
|
||||
INST_NAME("FDECSTP");
|
||||
@@ -382,26 +399,42 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
break;
|
||||
case 0xF8:
|
||||
INST_NAME("FPREM");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 1, NEON_CACHE_ST_D);
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
FDIVD(s0, v1, v2);
|
||||
FRINTZD(s0, s0);
|
||||
FCVTZSxD(x4, s0);
|
||||
FMULD(s0, s0, v2);
|
||||
FSUBD(v1, v1, s0);
|
||||
LDRw_U12(x1, xEmu, offsetof(x64emu_t, sw));
|
||||
// set C2 = 0
|
||||
BFCw(x1, 10, 1);
|
||||
// set C1 = Q0
|
||||
BFIw(x1, x4, 9, 1);
|
||||
// set C3 = Q1
|
||||
LSRx_IMM(x4, x4, 1);
|
||||
BFIw(x1, x4, 14, 1);
|
||||
// Set C0 = Q2
|
||||
LSRx(x4, x4, 1);
|
||||
BFIw(x1, x4, 8, 1);
|
||||
STRw_U12(x1, xEmu, offsetof(x64emu_t, sw));
|
||||
if(!rex.is32bits || !BOX64ENV(dynarec_fastround)) {
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
i1 = x87_stackcount(dyn, ninst, x3);
|
||||
CALL(const_native_fprem, -1);
|
||||
x87_unstackcount(dyn, ninst, x3, i1);
|
||||
} else {
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 1, NEON_CACHE_ST_D);
|
||||
s0 = fpu_get_scratch(dyn, ninst);
|
||||
FMOVxD(x4, v2);
|
||||
LSLx(x4, x4, 1); // remove sign bit
|
||||
RORx(x4, x4, 53); // put exponant in lower 12bits
|
||||
SUBx_U12(x4, x4, 0x7ff);// test is inifite
|
||||
CBNZx_MARK2(x4);
|
||||
MOV32w(x4, 0); // force q to 0
|
||||
B_MARK_nocond;
|
||||
MARK2;
|
||||
FDIVD(s0, v1, v2);
|
||||
FRINTZD(s0, s0);
|
||||
FCVTZSxD(x4, s0);
|
||||
FMSUB_64(v1, v1, s0, v2);
|
||||
MARK;
|
||||
LDRw_U12(x1, xEmu, offsetof(x64emu_t, sw));
|
||||
// set C2 = 0
|
||||
BFCw(x1, 10, 1);
|
||||
// set C1 = Q0
|
||||
BFIw(x1, x4, 9, 1);
|
||||
// set C3 = Q1
|
||||
LSRx_IMM(x4, x4, 1);
|
||||
BFIw(x1, x4, 14, 1);
|
||||
// Set C0 = Q2
|
||||
LSRx(x4, x4, 1);
|
||||
BFIw(x1, x4, 8, 1);
|
||||
STRw_U12(x1, xEmu, offsetof(x64emu_t, sw));
|
||||
}
|
||||
break;
|
||||
case 0xF9:
|
||||
INST_NAME("FYL2XP1");
|
||||
@@ -417,9 +450,19 @@ uintptr_t dynarec64_D9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
FCMPS_0(v1);
|
||||
FSQRTS(v1, v1);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
MOV32w(x3, X87_REAL_INDEFINITE_FLOAT);
|
||||
FMOVSw(v2, x3);
|
||||
FCSELS(v1, v2, v1, cMI); // MI: less than, not unordered
|
||||
} else {
|
||||
FCMPD_0(v1);
|
||||
FSQRTD(v1, v1);
|
||||
v2 = fpu_get_scratch(dyn, ninst);
|
||||
MOV64x(x3, X87_REAL_INDEFINITE_DOUBLE);
|
||||
FMOVDx(v2, x3);
|
||||
FCSELD(v1, v2, v1, cMI); // MI: less than, not unordered
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -28,7 +29,7 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
uint8_t ed;
|
||||
uint8_t wback;
|
||||
uint8_t u8;
|
||||
int v1, v2;
|
||||
int v1, v2, s5, s6;
|
||||
int d0;
|
||||
int s0;
|
||||
int64_t fixedaddress;
|
||||
@@ -149,7 +150,15 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, v2, s5);
|
||||
}
|
||||
FADDD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
@@ -164,7 +173,15 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, v2, s5);
|
||||
}
|
||||
FMULD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
@@ -202,7 +219,15 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, v2, s5);
|
||||
}
|
||||
FSUBD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
@@ -217,7 +242,15 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v2, v1, s5);
|
||||
}
|
||||
FSUBD(v1, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
@@ -230,9 +263,35 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VLD32(v2, ed, fixedaddress);
|
||||
SXTL_32(v2, v2); // i32 -> i64
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
if(BOX64ENV(dynarec_div0)) {
|
||||
FCMPD_0(v2);
|
||||
B_MARK3(cNE);
|
||||
LDRH_U12(x5, xEmu, offsetof(x64emu_t, cw));
|
||||
TBNZ_MARK2(x5, 2); // set SW.ZE flag if bit 2 is set
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL_S(const_native_div0, -1);
|
||||
CLEARIP();
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
MARK2;
|
||||
LDRH_U12(x5, xEmu, offsetof(x64emu_t, sw));
|
||||
MOV32w(x4, 0x4); // ZE flag
|
||||
ORRw_REG(x5, x5, x4);
|
||||
STRH_U12(x5, xEmu, offsetof(x64emu_t, sw));
|
||||
MARK3;
|
||||
}
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, v2, s5);
|
||||
}
|
||||
FDIVD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
@@ -247,7 +306,15 @@ uintptr_t dynarec64_DA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SCVTFDD(v2, v2); // i64 -> double
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v2, v1, s5);
|
||||
}
|
||||
FDIVD(v1, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -145,7 +146,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0xEE:
|
||||
case 0xEF:
|
||||
INST_NAME("FUCOMI ST0, STx");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
FCOMI(x1, x2, ST_IS_F(0), v1, v2);
|
||||
@@ -159,7 +160,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
INST_NAME("FCOMI ST0, STx");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
FCOMI(x1, x2,ST_IS_F(0), v1, v2);
|
||||
@@ -275,7 +276,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
NOTEST(x5);
|
||||
// the FLD is immediatly followed by an FSTP
|
||||
LDRx_U12(x5, ed, 0);
|
||||
LDRH_U12(x6, ed, 8);
|
||||
LDRH_U12(x4, ed, 8);
|
||||
// no persistant scratch register, so unrool both instruction here...
|
||||
MESSAGE(LOG_DUMP, "\tHack: FSTP tbyte\n");
|
||||
nextop = F8; // 0xDB or rex
|
||||
@@ -287,7 +288,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
nextop = F8; //modrm
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
STRx_U12(x5, ed, 0);
|
||||
STRH_U12(x6, ed, 8);
|
||||
STRH_U12(x4, ed, 8);
|
||||
} else {
|
||||
if(BOX64ENV(x87_no80bits)) {
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
@@ -312,7 +313,7 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, &unscaled, 0xfff<<3, 7, rex, NULL, 0, 0);
|
||||
VST64(v1, wback, fixedaddress);
|
||||
} else {
|
||||
if(!BOX64ENV(dynarec_fastround)) {
|
||||
if(!BOX64ENV(dynarec_fastround) || !rex.is32bits) {
|
||||
x87_forget(dyn, ninst, x1, x3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
if(ed!=x1) {MOVx_REG(x1, ed);}
|
||||
@@ -356,11 +357,21 @@ uintptr_t dynarec64_DB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
ORRx_mask(x5, x1, 1, 1, 0); //0x8000000000000000 x5 = mantisse
|
||||
B_MARK3_nocond;
|
||||
// denormals
|
||||
#ifdef BOX64EC
|
||||
// no x6 (guest R9) and x2 can be the address: x3 is free here (exp11 == 0), at the cost of the MOV
|
||||
CLZx(x3, x1);
|
||||
ADDw_U12(x3, x3, 1); // "one"
|
||||
SUBw_REG(x4, x4, x3); // x4 = exp16
|
||||
ORRw_REG(x4, x4, x5); // x4 = sign | exp16
|
||||
LSLx_REG(x5, x1, x3); // x5 = mantisse
|
||||
MOVw_REG(x3, x4);
|
||||
#else
|
||||
CLZx(x6, x1);
|
||||
ADDw_U12(x6, x6, 1); // "one"
|
||||
SUBw_REG(x3, x4, x6); // x3 = exp16
|
||||
ORRw_REG(x3, x3, x5); // x3 = sign | exp16
|
||||
LSLx_REG(x5, x1, x6); // x5 = mantisse
|
||||
#endif
|
||||
MARK3;
|
||||
STRx_U12(x5, wback, 0);
|
||||
STRH_U12(x3, wback, 8);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -30,7 +31,7 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
uint8_t u8;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
int v1, v2;
|
||||
int v1, v2, s5, s6;
|
||||
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
@@ -51,9 +52,25 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_S(v1, v2, s5);
|
||||
}
|
||||
FADDS(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
|
||||
}
|
||||
} else {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, v2, s5);
|
||||
}
|
||||
FADDD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
@@ -73,9 +90,25 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_S(v1, v2, s5);
|
||||
}
|
||||
FMULS(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
|
||||
}
|
||||
} else {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, v2, s5);
|
||||
}
|
||||
FMULD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
@@ -132,9 +165,25 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_S(v2, v1, s5);
|
||||
}
|
||||
FSUBS(v1, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
|
||||
}
|
||||
} else {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v2, v1, s5);
|
||||
}
|
||||
FSUBD(v1, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
@@ -154,9 +203,25 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_S(v1, v2, s5);
|
||||
}
|
||||
FSUBS(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
|
||||
}
|
||||
} else {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, v2, s5);
|
||||
}
|
||||
FSUBD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
@@ -176,9 +241,25 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_S(v2, v1, s5);
|
||||
}
|
||||
FDIVS(v1, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
|
||||
}
|
||||
} else {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v2, v1, s5);
|
||||
}
|
||||
FDIVD(v1, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
@@ -198,9 +279,25 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_S(v1, v2, s5);
|
||||
}
|
||||
FDIVS(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
|
||||
}
|
||||
} else {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, v2, s5);
|
||||
}
|
||||
FDIVD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
@@ -219,7 +316,15 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VLD64(v2, wback, fixedaddress);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, v2, s5);
|
||||
}
|
||||
FADDD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
@@ -232,7 +337,15 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VLD64(v2, wback, fixedaddress);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, v2, s5);
|
||||
}
|
||||
FMULD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
@@ -264,7 +377,15 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VLD64(v2, wback, fixedaddress);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, v2, s5);
|
||||
}
|
||||
FSUBD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
@@ -277,7 +398,15 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VLD64(v2, wback, fixedaddress);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v2, v1, s5);
|
||||
}
|
||||
FSUBD(v1, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
@@ -290,7 +419,15 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VLD64(v2, wback, fixedaddress);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, v2, s5);
|
||||
}
|
||||
FDIVD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
@@ -303,7 +440,15 @@ uintptr_t dynarec64_DC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
VLD64(v2, wback, fixedaddress);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v2, v1, s5);
|
||||
}
|
||||
FDIVD(v1, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -30,7 +31,7 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
uint8_t u8;
|
||||
int64_t fixedaddress;
|
||||
int unscaled;
|
||||
int v1, v2;
|
||||
int v1, v2, s5, s6;
|
||||
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
@@ -51,9 +52,25 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_S(v1, v2, s5);
|
||||
}
|
||||
FADDS(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
|
||||
}
|
||||
} else {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, v2, s5);
|
||||
}
|
||||
FADDD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
@@ -74,9 +91,25 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_S(v1, v2, s5);
|
||||
}
|
||||
FMULS(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
|
||||
}
|
||||
} else {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, v2, s5);
|
||||
}
|
||||
FMULD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
@@ -129,9 +162,25 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_S(v2, v1, s5);
|
||||
}
|
||||
FSUBS(v1, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
|
||||
}
|
||||
} else {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v2, v1, s5);
|
||||
}
|
||||
FSUBD(v1, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
@@ -152,9 +201,25 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_S(v1, v2, s5);
|
||||
}
|
||||
FSUBS(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
|
||||
}
|
||||
} else {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, v2, s5);
|
||||
}
|
||||
FSUBD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
@@ -175,9 +240,25 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_S(v2, v1, s5);
|
||||
}
|
||||
FDIVS(v1, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
|
||||
}
|
||||
} else {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v2, v1, s5);
|
||||
}
|
||||
FDIVD(v1, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
@@ -198,9 +279,25 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x4);
|
||||
if(ST_IS_F(0)) {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_S(v1, v2, s5);
|
||||
}
|
||||
FDIVS(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_S(v1, v2, s5, s6);
|
||||
}
|
||||
} else {
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, v2, s5);
|
||||
}
|
||||
FDIVD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
@@ -221,8 +318,20 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SXTL_16(v2, v2);
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, v2, s5);
|
||||
}
|
||||
FADDD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FIMUL ST0, word[ED]");
|
||||
@@ -233,8 +342,20 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SXTL_16(v2, v2);
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, v2, s5);
|
||||
}
|
||||
FMULD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FICOM ST0, word[ED]");
|
||||
@@ -270,8 +391,20 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SXTL_16(v2, v2);
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, v2, s5);
|
||||
}
|
||||
FSUBD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FISUBR ST0, word[ED]");
|
||||
@@ -282,8 +415,20 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SXTL_16(v2, v2);
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v2, v1, s5);
|
||||
}
|
||||
FSUBD(v1, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FIDIV ST0, word[ED]");
|
||||
@@ -294,8 +439,20 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SXTL_16(v2, v2);
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v1, v2, s5);
|
||||
}
|
||||
FDIVD(v1, v1, v2);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FIDIVR ST0, word[ED]");
|
||||
@@ -306,8 +463,20 @@ uintptr_t dynarec64_DE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SXTL_16(v2, v2);
|
||||
SXTL_32(v2, v2);
|
||||
SCVTFDD(v2, v2);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
u8 = x87_setround(dyn, ninst, x1, x5, x4);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
s5 = fpu_get_scratch(dyn, ninst);
|
||||
s6 = fpu_get_scratch(dyn, ninst);
|
||||
X87_ARITH_NAN_START_D(v2, v1, s5);
|
||||
}
|
||||
FDIVD(v1, v2, v1);
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
X87_ARITH_NAN_END_D(v1, v2, s5, s6);
|
||||
}
|
||||
X87_CHECK_PRECISION(v1);
|
||||
if(!BOX64ENV(dynarec_fastround))
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
}
|
||||
return addr;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -98,7 +99,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0xEE:
|
||||
case 0xEF:
|
||||
INST_NAME("FUCOMIP ST0, STx");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
FCOMI(x1, x2,ST_IS_F(0), v1, v2);
|
||||
@@ -113,7 +114,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
INST_NAME("FCOMIP ST0, STx");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
FCOMI(x1, x2, ST_IS_F(0), v1, v2);
|
||||
@@ -127,7 +128,7 @@ uintptr_t dynarec64_DF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FILD ST0, Ew");
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, (BOX64ENV(dynarec_x87double)==1)?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff<<1, 1, rex, NULL, 0, 0);
|
||||
LDSHw(x1, wback, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -1000,9 +1001,13 @@ void emit_adc32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
}
|
||||
}
|
||||
} else {
|
||||
MRS_nzcv(s3);
|
||||
BFIx(s3, xFlags, 29, 1); // set C
|
||||
MSR_nzcv(s3); // load CC into ARM CF
|
||||
if(cpuext.flagm)
|
||||
RMIF(xFlags, 63, 0b0010);
|
||||
else {
|
||||
MRS_nzcv(s3);
|
||||
BFIx(s3, xFlags, 29, 1); // set C
|
||||
MSR_nzcv(s3); // load CC into ARM CF
|
||||
}
|
||||
}
|
||||
IFX(X_AF) {
|
||||
ORRxw_REG(s3, s1, s2); // s3 = op1 | op2
|
||||
@@ -1143,9 +1148,13 @@ void emit_adc8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
MRS_nzcv(s3);
|
||||
BFIx(s3, xFlags, 29, 1); // set C
|
||||
MSR_nzcv(s3); // load CC into ARM CF
|
||||
if(cpuext.flagm)
|
||||
RMIF(xFlags, 63, 0b0010);
|
||||
else {
|
||||
MRS_nzcv(s3);
|
||||
BFIx(s3, xFlags, 29, 1); // set C
|
||||
MSR_nzcv(s3); // load CC into ARM CF
|
||||
}
|
||||
}
|
||||
IFX(X_AF | X_OF) {
|
||||
ORRw_REG(s3, s1, s2); // s3 = op1 | op2
|
||||
@@ -1207,9 +1216,13 @@ void emit_adc16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
MRS_nzcv(s3);
|
||||
BFIx(s3, xFlags, 29, 1); // set C
|
||||
MSR_nzcv(s3); // load CC into ARM CF
|
||||
if(cpuext.flagm)
|
||||
RMIF(xFlags, 63, 0b0010);
|
||||
else {
|
||||
MRS_nzcv(s3);
|
||||
BFIx(s3, xFlags, 29, 1); // set C
|
||||
MSR_nzcv(s3); // load CC into ARM CF
|
||||
}
|
||||
}
|
||||
IFX(X_AF | X_OF) {
|
||||
ORRw_REG(s3, s1, s2); // s3 = op1 | op2
|
||||
@@ -1331,9 +1344,13 @@ void emit_sbb32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int 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
|
||||
if(cpuext.flagm)
|
||||
RMIF(s4, 63, 0b0010);
|
||||
else {
|
||||
MRS_nzcv(s3);
|
||||
BFIx(s3, s4, 29, 1); // set C
|
||||
MSR_nzcv(s3); // load CC into ARM CF
|
||||
}
|
||||
}
|
||||
IFX(X_AF) {
|
||||
ORNxw_REG(s3, s2, s1); // s3 = ~op1 | op2
|
||||
@@ -1480,9 +1497,13 @@ void emit_sbb8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
} 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
|
||||
if(cpuext.flagm)
|
||||
RMIF(s4, 63, 0b0010);
|
||||
else {
|
||||
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) {
|
||||
ORNw_REG(s3, s2, s1); // s3 = ~op1 | op2
|
||||
@@ -1545,9 +1566,13 @@ void emit_sbb16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
} 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
|
||||
if(cpuext.flagm)
|
||||
RMIF(s4, 63, 0b0010);
|
||||
else {
|
||||
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) {
|
||||
ORNw_REG(s3, s2, s1); // s3 = ~op1 | op2
|
||||
@@ -1727,10 +1752,8 @@ void emit_neg16(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
}
|
||||
IFX(X_AF) {
|
||||
ORRw_REG(s3, s3, s1); // bc = op1 | res
|
||||
IFX(X_AF) {
|
||||
LSRw(s4, s3, 3);
|
||||
BFIw(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
}
|
||||
LSRw(s4, s3, 3);
|
||||
BFIw(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
@@ -1783,10 +1806,8 @@ void emit_neg8(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
}
|
||||
IFX(X_AF) {
|
||||
ORRw_REG(s3, s3, s1); // bc = op1 | res
|
||||
IFX(X_AF) {
|
||||
LSRw(s4, s3, 3);
|
||||
BFIw(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
}
|
||||
LSRw(s4, s3, 3);
|
||||
BFIw(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -969,17 +970,18 @@ void emit_ror32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, i
|
||||
}
|
||||
|
||||
// emit ROL8 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_rol8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4)
|
||||
void emit_rol8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4, int modreg)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s3); MAYUSE(s4);
|
||||
|
||||
if (!c) return;
|
||||
|
||||
IFX2(X_OF, && !BOX64ENV(cputype)) {
|
||||
LSRw(s3, s1, 6);
|
||||
EORw_REG_LSR(s3, s3, s3, 1);
|
||||
BFIw(xFlags, s3, F_OF, 1);
|
||||
}
|
||||
if(!BOX64ENV(cputype))
|
||||
IFX2(X_OF, && ((c==1) || !modreg)) {
|
||||
LSRw(s3, s1, 6);
|
||||
EORw_REG_LSR(s3, s3, s3, 1);
|
||||
BFIw(xFlags, s3, F_OF, 1);
|
||||
}
|
||||
if(c&7) {
|
||||
int rc = 8-(c&7);
|
||||
ORRw_REG_LSL(s1, s1, s1, 8);
|
||||
@@ -995,14 +997,14 @@ void emit_rol8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s
|
||||
}
|
||||
|
||||
// emit ROR8 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_ror8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4)
|
||||
void emit_ror8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4, int modreg)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s3); MAYUSE(s4);
|
||||
|
||||
if (!c) return;
|
||||
|
||||
if(!BOX64ENV(cputype))
|
||||
IFX(X_OF) {
|
||||
IFX2(X_OF, && ((c==1) || !modreg)) {
|
||||
EORw_REG_LSR(s3, s1, s1, 7);
|
||||
BFIw(xFlags, s3, F_OF, 1);
|
||||
}
|
||||
@@ -1023,14 +1025,14 @@ void emit_ror8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s
|
||||
}
|
||||
|
||||
// emit ROL16 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_rol16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4)
|
||||
void emit_rol16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4, int modreg)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s3); MAYUSE(s4);
|
||||
|
||||
if (!c) return;
|
||||
|
||||
if(!BOX64ENV(cputype))
|
||||
IFX2(X_OF, && c == 1) {
|
||||
IFX2(X_OF, && ((c==1) || !modreg)) {
|
||||
LSRw(s3, s1, 14);
|
||||
EORw_REG_LSR(s3, s3, s3, 1);
|
||||
BFIw(xFlags, s3, F_OF, 1);
|
||||
@@ -1051,14 +1053,14 @@ void emit_rol16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int
|
||||
}
|
||||
|
||||
// emit ROR16 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_ror16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4)
|
||||
void emit_ror16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4, int modreg)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s3); MAYUSE(s4);
|
||||
|
||||
if (!c) return;
|
||||
|
||||
if(!BOX64ENV(cputype))
|
||||
IFX2(X_OF, && c == 1) {
|
||||
IFX2(X_OF, && ((c==1) || !modreg)) {
|
||||
EORw_REG_LSR(s3, s1, s1, 15);
|
||||
BFIw(xFlags, s3, F_OF, 1);
|
||||
}
|
||||
@@ -1273,9 +1275,14 @@ void emit_rcr32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, i
|
||||
}
|
||||
|
||||
// emit RCL32/RCL64 instruction, from s1 , shift s2 (destroyed), store result in s1 using s3 and s4 as scratch
|
||||
void emit_rcl32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5)
|
||||
void emit_rcl32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s3); MAYUSE(s4);
|
||||
#ifdef BOX64EC
|
||||
int s5 = s3; // no x6 (guest R9), so s3 is reused and the new CF waits in F_res2
|
||||
#else
|
||||
int s5 = x6;
|
||||
#endif
|
||||
|
||||
if(BOX64ENV(cputype)) {
|
||||
IFX(X_OF|X_CF) {
|
||||
@@ -1290,6 +1297,11 @@ void emit_rcl32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
LSRxw_REG(s3, s1, s4);
|
||||
}
|
||||
}
|
||||
#ifdef BOX64EC
|
||||
IFX(BOX64ENV(cputype)?(X_OF|X_CF):X_CF) {
|
||||
BFIw(xFlags, s3, F_res2, 1);
|
||||
}
|
||||
#endif
|
||||
if(!BOX64ENV(cputype))
|
||||
IFX(X_OF) {
|
||||
LSRxw(s4, s1, rex.w?62:30);
|
||||
@@ -1317,15 +1329,27 @@ void emit_rcl32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
ORRxw_REG(s1, s1, s4);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
#ifdef BOX64EC
|
||||
BFXILw(xFlags, xFlags, F_res2, 1);
|
||||
#else
|
||||
BFIw(xFlags, s3, F_CF, 1);
|
||||
#endif
|
||||
}
|
||||
IFX2(X_OF, && BOX64ENV(cputype)) {
|
||||
#ifdef BOX64EC
|
||||
UBFXw(s3, xFlags, F_res2, 1);
|
||||
#endif
|
||||
EORxw_REG_LSR(s3, s3, s1, rex.w?63:31);
|
||||
BFIw(xFlags, s3, F_OF, 1);
|
||||
}
|
||||
#ifdef BOX64EC
|
||||
IFX(BOX64ENV(cputype)?(X_OF|X_CF):X_CF) {
|
||||
BFCw(xFlags, F_res2, 1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
// emit RCR32/RCR64 instruction, from s1 , shift s2, store result in s1 using s3 and s4 as scratch
|
||||
void emit_rcr32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5)
|
||||
// emit RCR32/RCR64 instruction, from s1 , shift s2 (destroyed), store result in s1 using s3 and s4 as scratch
|
||||
void emit_rcr32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s3); MAYUSE(s4);
|
||||
|
||||
@@ -1347,15 +1371,15 @@ void emit_rcr32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
}
|
||||
/*else*/
|
||||
{
|
||||
LSRxw_REG(s5, s1, s2);
|
||||
UBFXw(s4, xFlags, 0, 1);
|
||||
LSRxw_REG(s4, s1, s2);
|
||||
MOVZw(s3, (rex.w?64:32));
|
||||
SUBx_REG(s3, s3, s2);
|
||||
LSLxw_REG(s4, s4, s3);
|
||||
ORRxw_REG(s5, s5, s4);
|
||||
UBFXw(s2, xFlags, 0, 1); // s2 is not needed anymore
|
||||
LSLxw_REG(s2, s2, s3);
|
||||
ORRxw_REG(s4, s4, s2);
|
||||
ADDx_U12(s3, s3, 1);
|
||||
LSLxw_REG(s1, s1, s3);
|
||||
ORRxw_REG(s1, s1, s5);
|
||||
ORRxw_REG(s1, s1, s4);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
BFXILw(xFlags, xFlags, F_res2, 1);
|
||||
@@ -1621,8 +1645,9 @@ void emit_shrd16c(dynarec_arm_t* dyn, int ninst, int s1, int s2, uint32_t c, int
|
||||
c&=0x1f;
|
||||
IFX(X_PEND) {
|
||||
MOV32w(s3, c);
|
||||
ORRw_REG_LSL(s3, s3, s2, 16); // store fill in the upper half, the deferred handler needs it for OF
|
||||
STRw_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRH_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, d_shrd16);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
@@ -1664,7 +1689,8 @@ void emit_shrd16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s5, int s3,
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRH_U12(s5, xEmu, offsetof(x64emu_t, op2));
|
||||
ORRw_REG_LSL(s3, s5, s2, 16); // store fill in the upper half, needed for count > 16
|
||||
STRw_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
// same flags computation as with shl64/shl32
|
||||
SET_DF(s4, d_shrd16);
|
||||
} else {
|
||||
@@ -1713,8 +1739,9 @@ void emit_shld16c(dynarec_arm_t* dyn, int ninst, int s1, int s2, uint32_t c, int
|
||||
c&=0x1f;
|
||||
IFX(X_PEND) {
|
||||
MOV32w(s3, c);
|
||||
ORRw_REG_LSL(s3, s3, s2, 16); // store fill in the upper half, the deferred handler needs it for OF
|
||||
STRw_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRH_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, d_shld16);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
@@ -1768,12 +1795,12 @@ void emit_shld16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s5, int s3,
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STRH_U12(s1, xEmu, offsetof(x64emu_t, op1));
|
||||
STRH_U12(s5, xEmu, offsetof(x64emu_t, op2));
|
||||
ORRw_REG_LSL(s3, s5, s2, 16); // store fill in the upper half, needed for count > 16
|
||||
STRw_U12(s3, xEmu, offsetof(x64emu_t, op2));
|
||||
SET_DF(s4, d_shld16);
|
||||
} else {
|
||||
SET_DFNONE();
|
||||
}
|
||||
uint8_t mask = X_CF;
|
||||
if(BOX64ENV(cputype)) {
|
||||
IFX(X_CF|X_OF) {
|
||||
MOV32w(s3, 16);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -309,8 +310,8 @@ void emit_cmp8_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
}
|
||||
}
|
||||
|
||||
// emit TEST32 instruction, from test s1, s2, using s3, s4 and s5 as scratch
|
||||
void emit_test32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5)
|
||||
// emit TEST32 instruction, from test s1, s2, using s3 and s4 as scratch
|
||||
void emit_test32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s2); MAYUSE(s3); MAYUSE(s4);
|
||||
IFX_PENDOR0 {
|
||||
@@ -348,12 +349,12 @@ void emit_test32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s3, s5);
|
||||
emit_pf(dyn, ninst, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
// emit TEST32 instruction, from test s1, s2, using s3 and s4 as scratch
|
||||
void emit_test32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s3); MAYUSE(s4);
|
||||
int mask = convert_bitmask_xw(c);
|
||||
@@ -397,12 +398,12 @@ void emit_test32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, i
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s3, s5);
|
||||
emit_pf(dyn, ninst, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit TEST16 instruction, from test s1, s2, using s3, s4 and s5 as scratch
|
||||
void emit_test16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
|
||||
// emit TEST16 instruction, from test s1, s2, using s3 and s4 as scratch
|
||||
void emit_test16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s2);
|
||||
IFX_PENDOR0 {
|
||||
@@ -411,8 +412,8 @@ void emit_test16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4,
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFX(X_CF|X_ZF|X_SF|X_OF) {
|
||||
LSLw(s5, s1, 16);
|
||||
ANDSw_REG_LSL(s5, s5, s2, 16);
|
||||
LSLw(s3, s1, 16);
|
||||
ANDSw_REG_LSL(s3, s3, s2, 16);
|
||||
IFX(X_ZF) {
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(s4, cEQ);
|
||||
@@ -432,24 +433,24 @@ void emit_test16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4,
|
||||
}
|
||||
}
|
||||
IFX(X_PF|X_PEND) {
|
||||
LSRw(s5, s5, 16);
|
||||
LSRw(s3, s3, 16);
|
||||
}
|
||||
} else {
|
||||
ANDw_REG(s5, s1, s2); // res = s1 & s2
|
||||
ANDw_REG(s3, s1, s2); // res = s1 & s2
|
||||
}
|
||||
IFX(X_AF) {
|
||||
BFCw(xFlags, F_AF, 1);
|
||||
}
|
||||
IFX_PENDOR0 {
|
||||
STRH_U12(s5, xEmu, offsetof(x64emu_t, res));
|
||||
STRH_U12(s3, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s5, s4);
|
||||
emit_pf(dyn, ninst, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
// emit TEST16 instruction, from test s1, s2, using s3 and s4 as scratch
|
||||
void emit_test16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s1);
|
||||
int mask = 0;
|
||||
@@ -459,13 +460,13 @@ void emit_test16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFX(X_CF|X_ZF|X_SF|X_OF) {
|
||||
LSLw(s5, s1, 16);
|
||||
LSLw(s3, s1, 16);
|
||||
mask = convert_bitmask_w(c<<16);
|
||||
if(mask) {
|
||||
ANDSw_mask(s5, s5, mask&0x3F, (mask>>6)&0x3F);
|
||||
ANDSw_mask(s3, s3, mask&0x3F, (mask>>6)&0x3F);
|
||||
} else {
|
||||
MOV32w(s3, c);
|
||||
ANDSw_REG_LSL(s5, s5, s3, 16);
|
||||
MOV32w(s4, c);
|
||||
ANDSw_REG_LSL(s3, s3, s4, 16);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
@@ -486,30 +487,30 @@ void emit_test16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int
|
||||
}
|
||||
}
|
||||
IFX(X_PF|X_PEND) {
|
||||
LSRw(s5, s5, 16);
|
||||
LSRw(s3, s3, 16);
|
||||
}
|
||||
} else {
|
||||
mask = convert_bitmask_w(c);
|
||||
if(mask) {
|
||||
ANDw_mask(s5, s1, mask&0x3F, (mask>>6)&0x3F);
|
||||
ANDw_mask(s3, s1, mask&0x3F, (mask>>6)&0x3F);
|
||||
} else {
|
||||
MOV32w(s5, c);
|
||||
ANDw_REG(s5, s1, s5); // res = s1 & s2
|
||||
MOV32w(s3, c);
|
||||
ANDw_REG(s3, s1, s3); // res = s1 & s2
|
||||
}
|
||||
}
|
||||
IFX(X_AF) {
|
||||
BFCw(xFlags, F_AF, 1);
|
||||
}
|
||||
IFX_PENDOR0 {
|
||||
STRH_U12(s5, xEmu, offsetof(x64emu_t, res));
|
||||
STRH_U12(s3, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s5, s4);
|
||||
emit_pf(dyn, ninst, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit TEST8 instruction, from test s1, s2, using s3, s4 and s5 as scratch
|
||||
void emit_test8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5)
|
||||
// emit TEST8 instruction, from test s1, s2, using s3 and s4 as scratch
|
||||
void emit_test8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s1); MAYUSE(s2);
|
||||
IFX_PENDOR0 {
|
||||
@@ -518,8 +519,8 @@ void emit_test8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, i
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFX(X_CF|X_ZF|X_SF|X_OF) {
|
||||
LSLw(s5, s1, 24);
|
||||
ANDSw_REG_LSL(s5, s5, s2, 24);
|
||||
LSLw(s3, s1, 24);
|
||||
ANDSw_REG_LSL(s3, s3, s2, 24);
|
||||
IFX(X_ZF) {
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
CSETw(s4, cEQ);
|
||||
@@ -539,24 +540,24 @@ void emit_test8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, i
|
||||
}
|
||||
}
|
||||
IFX(X_PF|X_PEND) {
|
||||
LSRw(s5, s5, 24);
|
||||
LSRw(s3, s3, 24);
|
||||
}
|
||||
} else {
|
||||
ANDw_REG(s5, s1, s2); // res = s1 & s2
|
||||
ANDw_REG(s3, s1, s2); // res = s1 & s2
|
||||
}
|
||||
IFX(X_AF) {
|
||||
BFCw(xFlags, F_AF, 1);
|
||||
}
|
||||
IFX_PENDOR0 {
|
||||
STRB_U12(s5, xEmu, offsetof(x64emu_t, res));
|
||||
STRB_U12(s3, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s5, s4);
|
||||
emit_pf(dyn, ninst, s3, 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)
|
||||
void emit_test8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4)
|
||||
{
|
||||
MAYUSE(s1);
|
||||
int mask = 0;
|
||||
@@ -566,13 +567,13 @@ void emit_test8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int
|
||||
SET_DFNONE();
|
||||
}
|
||||
IFX(X_CF|X_ZF|X_SF|X_OF) {
|
||||
LSLw(s5, s1, 24);
|
||||
LSLw(s3, s1, 24);
|
||||
mask = convert_bitmask_w(c<<24);
|
||||
if(mask) {
|
||||
ANDSw_mask(s5, s5, mask&0x3F, (mask>>6)&0x3F);
|
||||
ANDSw_mask(s3, s3, mask&0x3F, (mask>>6)&0x3F);
|
||||
} else {
|
||||
MOV32w(s3, c);
|
||||
ANDSw_REG_LSL(s5, s5, s3, 24);
|
||||
MOV32w(s4, c);
|
||||
ANDSw_REG_LSL(s3, s3, s4, 24);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
IFNATIVE(NF_EQ) {} else {
|
||||
@@ -593,24 +594,24 @@ void emit_test8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int
|
||||
}
|
||||
}
|
||||
IFX(X_PF|X_PEND) {
|
||||
LSRw(s5, s5, 24);
|
||||
LSRw(s3, s3, 24);
|
||||
}
|
||||
} else {
|
||||
mask = convert_bitmask_w(c);
|
||||
if(mask) {
|
||||
ANDw_mask(s5, s1, mask&0x3F, (mask>>6)&0x3F);
|
||||
ANDw_mask(s3, s1, mask&0x3F, (mask>>6)&0x3F);
|
||||
} else {
|
||||
MOV32w(s5, c);
|
||||
ANDw_REG(s5, s1, s5); // res = s1 & s2
|
||||
MOV32w(s3, c);
|
||||
ANDw_REG(s3, s1, s3); // res = s1 & s2
|
||||
}
|
||||
}
|
||||
IFX(X_AF) {
|
||||
BFCw(xFlags, F_AF, 1);
|
||||
}
|
||||
IFX_PENDOR0 {
|
||||
STRB_U12(s5, xEmu, offsetof(x64emu_t, res));
|
||||
STRB_U12(s3, xEmu, offsetof(x64emu_t, res));
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s5, s4);
|
||||
emit_pf(dyn, ninst, s3, s4);
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -238,28 +239,28 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
INST_NAME("LOCK CMPXCHG Eb, Gb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETGB(x1);
|
||||
UBFXx(x6, xRAX, 0, 8);
|
||||
UBFXx(x5, xRAX, 0, 8);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
if(cpuext.atomics) {
|
||||
UFLAG_IF {
|
||||
MOVw_REG(x2, x6);
|
||||
CASALB(x6, gd, wback);
|
||||
emit_cmp8(dyn, ninst, x2, x6, x3, x4, x5);
|
||||
MOVw_REG(x2, x5);
|
||||
CASALB(x5, gd, wback);
|
||||
emit_cmp8(dyn, ninst, x2, x5, x3, x4, x1);
|
||||
} else {
|
||||
CASALB(x6, gd, wback);
|
||||
CASALB(x5, gd, wback);
|
||||
}
|
||||
BFIx(xRAX, x6, 0, 8);
|
||||
BFIx(xRAX, x5, 0, 8);
|
||||
} else {
|
||||
MARKLOCK;
|
||||
LDAXRB(x2, wback);
|
||||
CMPSxw_REG(x6, x2);
|
||||
CMPSxw_REG(x5, x2);
|
||||
B_MARK(cNE);
|
||||
// EAX == Ed
|
||||
STLXRB(x4, gd, wback);
|
||||
CBNZx_MARKLOCK(x4);
|
||||
// done
|
||||
MARK;
|
||||
UFLAG_IF {emit_cmp8(dyn, ninst, x6, x2, x3, x4, x5);}
|
||||
UFLAG_IF {emit_cmp8(dyn, ninst, x5, x2, x3, x4, x1);}
|
||||
BFIx(xRAX, x2, 0, 8);
|
||||
}
|
||||
}
|
||||
@@ -282,7 +283,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETGD;
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
UFLAG_IF { MOVxw_REG(x6, xRAX); }
|
||||
UFLAG_IF { MOVxw_REG(x5, xRAX); }
|
||||
if(!ALIGNED_ATOMICxw) {
|
||||
if(cpuext.uscat) {
|
||||
ANDx_mask(x1, wback, 1, 0, 3); // mask = F
|
||||
@@ -344,7 +345,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
MARK;
|
||||
UFLAG_IF {
|
||||
emit_cmp32(dyn, ninst, rex, x6, x1, x3, x4, x5);
|
||||
emit_cmp32(dyn, ninst, rex, x5, x1, x3, x4, x2);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -371,7 +372,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
// Will fetch only 1 byte, to avoid alignment issue
|
||||
ANDw_mask(x2, gd, 0, 0b00010); //mask=0x000000007
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
ASRx(x1, gd, 3); // r1 = (gd>>3), there might be an issue for negative 32bits values here
|
||||
ASRxw(x1, gd, 3); // r1 = (gd>>3)
|
||||
if(!rex.w && !rex.is32bits) {SXTWx(x1, x1);}
|
||||
ADDy_REG_LSL(x3, wback, x1, 0); //(&ed)+=r1;
|
||||
ed = x1;
|
||||
@@ -547,7 +548,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
// Will fetch only 1 byte, to avoid alignment issue
|
||||
ANDw_mask(x2, gd, 0, 0b00010); //mask=0x000000007
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
ASRx(x1, gd, 3); // r1 = (gd>>3), there might be an issue for negative 32bits values here
|
||||
ASRxw(x1, gd, 3); // r1 = (gd>>3)
|
||||
if(!rex.w && !rex.is32bits) {SXTWx(x1, x1);}
|
||||
ADDy_REG_LSL(x3, wback, x1, 0); //(&ed)+=r1;
|
||||
ed = x1;
|
||||
@@ -785,7 +786,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
}
|
||||
B_MARK3_nocond;
|
||||
MARKSEG;
|
||||
STLXRB(x4, x5, wback); //write back
|
||||
STLXRB(x4, x2, wback); //write back
|
||||
CBNZx_MARK2(x4);
|
||||
MOVxw_REG(xRAX, x2);
|
||||
MOVxw_REG(xRDX, x3);
|
||||
@@ -822,11 +823,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETGB(x2);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
MOVx_REG(x6, xFlags);
|
||||
MRS_nzcv(x87pc);
|
||||
MARKLOCK;
|
||||
MOVx_REG(xFlags, x6);
|
||||
MSR_nzcv(x87pc);
|
||||
MARKLOCK_SAVE_FLAGS();
|
||||
LDAXRB(x1, wback);
|
||||
emit_adc8(dyn, ninst, x1, x2, x4, x5);
|
||||
STLXRB(x4, x1, wback);
|
||||
@@ -847,11 +844,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETGD;
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
MOVx_REG(x6, xFlags);
|
||||
MRS_nzcv(x87pc);
|
||||
MARKLOCK;
|
||||
MOVx_REG(xFlags, x6);
|
||||
MSR_nzcv(x87pc);
|
||||
MARKLOCK_SAVE_FLAGS();
|
||||
LDAXRxw(x1, wback);
|
||||
emit_adc32(dyn, ninst, rex, x1, gd, x4, x5);
|
||||
STLXRxw(x4, x1, wback);
|
||||
@@ -869,7 +862,6 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
} else {
|
||||
INST_NAME("LOCK AND Eb, Gb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETGD;
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 0);
|
||||
GETGB(x5);
|
||||
if(cpuext.atomics) {
|
||||
@@ -1107,11 +1099,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x5, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 1);
|
||||
u8 = F8;
|
||||
wb1 = 1;
|
||||
MOVx_REG(x6, xFlags);
|
||||
MRS_nzcv(x87pc);
|
||||
MARKLOCK;
|
||||
MOVx_REG(xFlags, x6);
|
||||
MSR_nzcv(x87pc);
|
||||
MARKLOCK_SAVE_FLAGS();
|
||||
LDAXRB(x1, wback);
|
||||
emit_adc8c(dyn, ninst, x1, u8, x2, x4, x3);
|
||||
STLXRB(x3, x1, wback);
|
||||
@@ -1132,11 +1120,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x5, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, 1);
|
||||
u8 = F8;
|
||||
wb1 = 1;
|
||||
MOVx_REG(x6, xFlags);
|
||||
MRS_nzcv(x87pc);
|
||||
MARKLOCK;
|
||||
MOVx_REG(xFlags, x6);
|
||||
MSR_nzcv(x87pc);
|
||||
MARKLOCK_SAVE_FLAGS();
|
||||
LDAXRB(x1, wback);
|
||||
emit_sbb8c(dyn, ninst, x1, u8, x2, x4, x3);
|
||||
STLXRB(x3, x1, wback);
|
||||
@@ -1369,11 +1353,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
MOV64xw(x5, i64);
|
||||
MOVx_REG(x6, xFlags);
|
||||
MRS_nzcv(x87pc);
|
||||
MARKLOCK;
|
||||
MOVx_REG(xFlags, x6);
|
||||
MSR_nzcv(x87pc);
|
||||
MARKLOCK_SAVE_FLAGS();
|
||||
LDAXRxw(x1, wback);
|
||||
emit_adc32(dyn, ninst, rex, x1, x5, x3, x4);
|
||||
STLXRxw(x3, x1, wback);
|
||||
@@ -1394,11 +1374,7 @@ uintptr_t dynarec64_F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, NULL, 0, 0, rex, LOCK_LOCK, 0, (opcode==0x81)?4:1);
|
||||
if(opcode==0x81) i64 = F32S; else i64 = F8S;
|
||||
MOV64xw(x5, i64);
|
||||
MOVx_REG(x6, xFlags);
|
||||
MRS_nzcv(x87pc);
|
||||
MARKLOCK;
|
||||
MOVx_REG(xFlags, x6);
|
||||
MSR_nzcv(x87pc);
|
||||
MARKLOCK_SAVE_FLAGS();
|
||||
LDAXRxw(x1, wback);
|
||||
emit_sbb32(dyn, ninst, rex, x1, x5, x3, x4);
|
||||
STLXRxw(x3, x1, wback);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -68,6 +69,7 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
MARK_XMM_SCALAR(gd);
|
||||
if(MODREG) {
|
||||
ed = (nextop&7)+ (rex.b<<3);
|
||||
d0 = sse_get_reg(dyn, ninst, x1, ed, 1);
|
||||
@@ -237,6 +239,8 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(q0, 1);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSD(d0, 0, 0);
|
||||
MARK_XMM_SCALAR(gd);
|
||||
if(MODREG) MARK_XMM_SCALAR((nextop&7)+(rex.b<<3));
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
@@ -247,10 +251,13 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VBIC(v1, v0, v1); // forget it in any input was a NAN already
|
||||
SHL_64(v1, v1, 63); // only keep the sign bit
|
||||
VORR(d1, d1, v1); // NAN -> -NAN
|
||||
VMOVeD(q0, 0, d1, 0);
|
||||
} else if(XMMH_UNNEEDED(gd)) {
|
||||
FSQRTD(q0, d0); // upper 64 dead: compute in place, skip preserve
|
||||
} else {
|
||||
FSQRTD(d1, d0);
|
||||
VMOVeD(q0, 0, d1, 0);
|
||||
}
|
||||
VMOVeD(q0, 0, d1, 0);
|
||||
break;
|
||||
|
||||
case 0x58:
|
||||
@@ -259,6 +266,8 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(d1, 1);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSD(d0, 0, 0);
|
||||
MARK_XMM_SCALAR(gd);
|
||||
if(MODREG) MARK_XMM_SCALAR((nextop&7)+(rex.b<<3));
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
@@ -277,10 +286,13 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VMOVQDfrom(q0, 0, x5);
|
||||
VORR(v2, v2, q0); // quiet any SNaN in src1
|
||||
VBIF(v1, v2, v0); // where src1 was NaN, use QNaN(src1)
|
||||
VMOVeD(d1, 0, v1, 0);
|
||||
} else if(XMMH_UNNEEDED(gd)) {
|
||||
FADDD(d1, d1, d0); // upper 64 dead: compute in place, skip preserve
|
||||
} else {
|
||||
FADDD(v1, d1, d0); // the high part of the vector is erased...
|
||||
VMOVeD(d1, 0, v1, 0);
|
||||
}
|
||||
VMOVeD(d1, 0, v1, 0);
|
||||
break;
|
||||
case 0x59:
|
||||
INST_NAME("MULSD Gx, Ex");
|
||||
@@ -288,6 +300,8 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(d1, 1);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSD(d0, 0, 0);
|
||||
MARK_XMM_SCALAR(gd);
|
||||
if(MODREG) MARK_XMM_SCALAR((nextop&7)+(rex.b<<3));
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
@@ -306,10 +320,13 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VMOVQDfrom(q0, 0, x5);
|
||||
VORR(v2, v2, q0); // quiet any SNaN in src1
|
||||
VBIF(v1, v2, v0); // where src1 was NaN, use QNaN(src1)
|
||||
VMOVeD(d1, 0, v1, 0);
|
||||
} else if(XMMH_UNNEEDED(gd)) {
|
||||
FMULD(d1, d1, d0); // upper 64 dead: compute in place, skip preserve
|
||||
} else {
|
||||
FMULD(v1, d1, d0);
|
||||
VMOVeD(d1, 0, v1, 0);
|
||||
}
|
||||
VMOVeD(d1, 0, v1, 0);
|
||||
break;
|
||||
case 0x5A:
|
||||
INST_NAME("CVTSD2SS Gx, Ex");
|
||||
@@ -333,6 +350,8 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(d1, 1);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSD(d0, 0, 0);
|
||||
MARK_XMM_SCALAR(gd);
|
||||
if(MODREG) MARK_XMM_SCALAR((nextop&7)+(rex.b<<3));
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
@@ -351,10 +370,13 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VMOVQDfrom(q0, 0, x5);
|
||||
VORR(v2, v2, q0); // quiet any SNaN in src1
|
||||
VBIF(v1, v2, v0); // where src1 was NaN, use QNaN(src1)
|
||||
VMOVeD(d1, 0, v1, 0);
|
||||
} else if(XMMH_UNNEEDED(gd)) {
|
||||
FSUBD(d1, d1, d0); // upper 64 dead: compute in place, skip preserve
|
||||
} else {
|
||||
FSUBD(v1, d1, d0);
|
||||
VMOVeD(d1, 0, v1, 0);
|
||||
}
|
||||
VMOVeD(d1, 0, v1, 0);
|
||||
break;
|
||||
case 0x5D:
|
||||
INST_NAME("MINSD Gx, Ex");
|
||||
@@ -372,6 +394,8 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(v0, 1);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSD(v1, 0, 0);
|
||||
MARK_XMM_SCALAR(gd);
|
||||
if(MODREG) MARK_XMM_SCALAR((nextop&7)+(rex.b<<3));
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
@@ -390,10 +414,13 @@ uintptr_t dynarec64_F20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VMOVQDfrom(q0, 0, x5);
|
||||
VORR(v2, v2, q0); // quiet any SNaN in src1
|
||||
VBIF(d1, v2, d0); // where src1 was NaN, use QNaN(src1)
|
||||
VMOVeD(v0, 0, d1, 0);
|
||||
} else if(XMMH_UNNEEDED(gd)) {
|
||||
FDIVD(v0, v0, v1); // upper 64 dead: compute in place, skip preserve
|
||||
} else {
|
||||
FDIVD(d1, v0, v1);
|
||||
VMOVeD(v0, 0, d1, 0);
|
||||
}
|
||||
VMOVeD(v0, 0, d1, 0);
|
||||
break;
|
||||
case 0x5F:
|
||||
INST_NAME("MAXSD Gx, Ex");
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -52,6 +53,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(MODREG) {
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
q0 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3), 0);
|
||||
MARK_XMM_SCALAR_SINGLE((nextop&7)+(rex.b<<3)); // reg-reg move reads only low-32 of src
|
||||
VMOVeS(v0, 0, q0, 0);
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
@@ -65,6 +67,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETG;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
MARK_XMM_SCALAR_SINGLE(gd); // store reads only low-32 of Gx, upper-96 untouched
|
||||
if(MODREG) {
|
||||
q0 = sse_get_reg(dyn, ninst, x1, (nextop&7) + (rex.b<<3), 1);
|
||||
VMOVeS(q0, 0, v0, 0);
|
||||
@@ -236,6 +239,8 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(q0, 1);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSS(d0, 0, 0);
|
||||
MARK_XMM_SCALAR_SINGLE(gd);
|
||||
if(MODREG) MARK_XMM_SCALAR_SINGLE((nextop&7)+(rex.b<<3));
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
@@ -246,16 +251,21 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VBIC(v1, v0, v1); // forget it in any input was a NAN already
|
||||
VSHL_32(v1, v1, 31); // only keep the sign bit
|
||||
VORR(d1, d1, v1); // NAN -> -NAN
|
||||
VMOVeS(q0, 0, d1, 0);
|
||||
} else if(XMMS_UNNEEDED(gd)) {
|
||||
FSQRTS(q0, d0); // upper 96 dead: compute in place, skip preserve
|
||||
} else {
|
||||
FSQRTS(d1, d0);
|
||||
VMOVeS(q0, 0, d1, 0);
|
||||
}
|
||||
VMOVeS(q0, 0, d1, 0);
|
||||
break;
|
||||
case 0x52:
|
||||
INST_NAME("RSQRTSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEXSS(v1, 0, 0);
|
||||
MARK_XMM_SCALAR_SINGLE(gd);
|
||||
if(MODREG) MARK_XMM_SCALAR_SINGLE((nextop&7)+(rex.b<<3));
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
d1 = fpu_get_scratch(dyn, ninst);
|
||||
// so here: F32: Imm8 = abcd efgh that gives => aBbbbbbc defgh000 00000000 00000000
|
||||
@@ -273,6 +283,8 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEXSS(v1, 0, 0);
|
||||
MARK_XMM_SCALAR_SINGLE(gd);
|
||||
if(MODREG) MARK_XMM_SCALAR_SINGLE((nextop&7)+(rex.b<<3));
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
FMOVS_8(d0, 0b01110000); //1.0f
|
||||
FDIVS(d0, d0, v1);
|
||||
@@ -285,6 +297,8 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(d1, 1);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSS(d0, 0, 0);
|
||||
MARK_XMM_SCALAR_SINGLE(gd);
|
||||
if(MODREG) MARK_XMM_SCALAR_SINGLE((nextop&7)+(rex.b<<3));
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
@@ -304,10 +318,13 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VMOVQSfrom(q0, 0, x5);
|
||||
VORR(v2, v2, q0); // quiet any SNaN in src1
|
||||
VBIF(v1, v2, v0); // where src1 was NaN, use QNaN(src1)
|
||||
VMOVeS(d1, 0, v1, 0);
|
||||
} else if(XMMS_UNNEEDED(gd)) {
|
||||
FADDS(d1, d1, d0); // upper 96 dead: compute in place, skip preserve
|
||||
} else {
|
||||
FADDS(v1, d1, d0); // the high part of the vector is erased...
|
||||
VMOVeS(d1, 0, v1, 0);
|
||||
}
|
||||
VMOVeS(d1, 0, v1, 0);
|
||||
break;
|
||||
case 0x59:
|
||||
INST_NAME("MULSS Gx, Ex");
|
||||
@@ -315,6 +332,8 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(d1, 1);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSS(d0, 0, 0);
|
||||
MARK_XMM_SCALAR_SINGLE(gd);
|
||||
if(MODREG) MARK_XMM_SCALAR_SINGLE((nextop&7)+(rex.b<<3));
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
@@ -334,10 +353,13 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VMOVQSfrom(q0, 0, x5);
|
||||
VORR(v2, v2, q0); // quiet any SNaN in src1
|
||||
VBIF(v1, v2, v0); // where src1 was NaN, use QNaN(src1)
|
||||
VMOVeS(d1, 0, v1, 0);
|
||||
} else if(XMMS_UNNEEDED(gd)) {
|
||||
FMULS(d1, d1, d0); // upper 96 dead: compute in place, skip preserve
|
||||
} else {
|
||||
FMULS(v1, d1, d0); // the high part of the vector is erased...
|
||||
VMOVeS(d1, 0, v1, 0);
|
||||
}
|
||||
VMOVeS(d1, 0, v1, 0);
|
||||
break;
|
||||
case 0x5A:
|
||||
INST_NAME("CVTSS2SD Gx, Ex");
|
||||
@@ -399,6 +421,8 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(d1, 1);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSS(d0, 0, 0);
|
||||
MARK_XMM_SCALAR_SINGLE(gd);
|
||||
if(MODREG) MARK_XMM_SCALAR_SINGLE((nextop&7)+(rex.b<<3));
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
@@ -418,16 +442,21 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VMOVQSfrom(q0, 0, x5);
|
||||
VORR(v2, v2, q0); // quiet any SNaN in src1
|
||||
VBIF(v1, v2, v0); // where src1 was NaN, use QNaN(src1)
|
||||
VMOVeS(d1, 0, v1, 0);
|
||||
} else if(XMMS_UNNEEDED(gd)) {
|
||||
FSUBS(d1, d1, d0); // upper 96 dead: compute in place, skip preserve
|
||||
} else {
|
||||
FSUBS(v1, d1, d0); // the high part of the vector is erased...
|
||||
VMOVeS(d1, 0, v1, 0);
|
||||
}
|
||||
VMOVeS(d1, 0, v1, 0);
|
||||
break;
|
||||
case 0x5D:
|
||||
INST_NAME("MINSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEXSS(v1, 0, 0);
|
||||
MARK_XMM_SCALAR_SINGLE(gd);
|
||||
if(MODREG) MARK_XMM_SCALAR_SINGLE((nextop&7)+(rex.b<<3));
|
||||
// MINSS: if any input is NaN, or Ex[0]<Gx[0], copy Ex[0] -> Gx[0]
|
||||
FCMPS(v0, v1);
|
||||
B_NEXT(cCC); //CC invert of CS: NAN or == or Gx > Ex
|
||||
@@ -439,6 +468,26 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
GETGX(d1, 1);
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
GETEXSS(d0, 0, 0);
|
||||
MARK_XMM_SCALAR_SINGLE(gd);
|
||||
if(MODREG) MARK_XMM_SCALAR_SINGLE((nextop&7)+(rex.b<<3));
|
||||
if(BOX64ENV(dynarec_div0)) {
|
||||
LDRw_U12(x5, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
TBNZ_MARK2(x5, 9); // set ZE flag if bit 9 is set
|
||||
FCMPS_0(d0);
|
||||
B_MARK3(cNE);
|
||||
GETIP_(ip);
|
||||
STORE_XEMU_CALL(xRIP);
|
||||
CALL_S(const_native_div0, -1);
|
||||
CLEARIP();
|
||||
LOAD_XEMU_CALL(xRIP);
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
MARK2;
|
||||
LDRw_U12(x5, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
MOV32w(x4, 0x4); // ZE flag
|
||||
ORRw_REG(x5, x5, x4);
|
||||
STRw_U12(x5, xEmu, offsetof(x64emu_t, mxcsr));
|
||||
MARK3;
|
||||
}
|
||||
if(!BOX64ENV(dynarec_fastnan)) {
|
||||
v0 = fpu_get_scratch(dyn, ninst);
|
||||
q0 = fpu_get_scratch(dyn, ninst);
|
||||
@@ -458,16 +507,21 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
VMOVQSfrom(q0, 0, x5);
|
||||
VORR(v2, v2, q0); // quiet any SNaN in src1
|
||||
VBIF(v1, v2, v0); // where src1 was NaN, use QNaN(src1)
|
||||
VMOVeS(d1, 0, v1, 0);
|
||||
} else if(XMMS_UNNEEDED(gd)) {
|
||||
FDIVS(d1, d1, d0); // upper 96 dead: compute in place, skip preserve
|
||||
} else {
|
||||
FDIVS(v1, d1, d0); // the high part of the vector is erased...
|
||||
VMOVeS(d1, 0, v1, 0);
|
||||
}
|
||||
VMOVeS(d1, 0, v1, 0);
|
||||
break;
|
||||
case 0x5F:
|
||||
INST_NAME("MAXSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0, 1);
|
||||
GETEXSS(v1, 0, 0);
|
||||
MARK_XMM_SCALAR_SINGLE(gd);
|
||||
if(MODREG) MARK_XMM_SCALAR_SINGLE((nextop&7)+(rex.b<<3));
|
||||
// MAXSS: if any input is NaN, or Ex[0]>Gx[0], copy Ex[0] -> Gx[0]
|
||||
FCMPS(v1, v0);
|
||||
B_NEXT(cCC); //CC: invert of CS: NAN or == or Ex > Gx
|
||||
@@ -537,6 +591,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
} else {
|
||||
IF_UNALIGNED(ip) {
|
||||
MESSAGE(LOG_DEBUG, "\tUnaligned path");
|
||||
NOLRCPC();
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, NULL, 0, 0, rex, NULL, 0, 0);
|
||||
for(int i=0; i<16; ++i) {
|
||||
VST1_8(v0, i, i?x1:wback);
|
||||
@@ -602,7 +657,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
|
||||
case 0xB8:
|
||||
INST_NAME("POPCNT Gd, Ed");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
SET_DFNONE();
|
||||
nextop = F8;
|
||||
v1 = fpu_get_scratch(dyn, ninst);
|
||||
@@ -667,7 +722,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_ALL&~X_OF, SF_SUBSET);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
}
|
||||
}
|
||||
SET_DFNONE();
|
||||
@@ -701,7 +756,7 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
if(BOX64ENV(cputype)) {
|
||||
SETFLAGS(X_ALL&~X_OF, SF_SUBSET);
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
}
|
||||
}
|
||||
SET_DFNONE();
|
||||
@@ -767,7 +822,6 @@ uintptr_t dynarec64_F30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int n
|
||||
nextop = F8;
|
||||
GETEXSD(v1, 0, 0);
|
||||
GETGX_empty(v0);
|
||||
d0 = fpu_get_scratch(dyn, ninst);
|
||||
SXTL_32(v0, v1);
|
||||
SCVTQFD(v0, v0); // there is only I64 -> Double vector conversion, not from i32
|
||||
break;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -28,6 +29,11 @@
|
||||
// Get a FPU scratch reg
|
||||
int fpu_get_scratch(dynarec_arm_t* dyn, int ninst)
|
||||
{
|
||||
if(dyn->n.fpu_scratch >= 8) {
|
||||
printf_log(LOG_INFO, "BOX64 Dynarec: out of FPU scratch registers at inst=%d\n", ninst);
|
||||
dyn->abort = 1;
|
||||
return SCRATCH0;
|
||||
}
|
||||
int ret = SCRATCH0 + dyn->n.fpu_scratch++;
|
||||
if(dyn->n.ymm_used) {
|
||||
printf_log(LOG_INFO, "Warning, getting a scratch register after getting some YMM at inst=%d", ninst);
|
||||
@@ -44,6 +50,11 @@ int fpu_get_scratch(dynarec_arm_t* dyn, int ninst)
|
||||
// Get 2 consicutive FPU scratch reg
|
||||
int fpu_get_double_scratch(dynarec_arm_t* dyn, int ninst)
|
||||
{
|
||||
if(dyn->n.fpu_scratch >= 7) {
|
||||
printf_log(LOG_INFO, "BOX64 Dynarec: out of FPU double scratch registers at inst=%d\n", ninst);
|
||||
dyn->abort = 1;
|
||||
return SCRATCH0;
|
||||
}
|
||||
int ret = SCRATCH0 + dyn->n.fpu_scratch;
|
||||
if(dyn->n.ymm_used) {
|
||||
printf_log(LOG_INFO, "Warning, getting a double scratch register after getting some YMM at inst=%d", ninst);
|
||||
@@ -76,12 +87,19 @@ void fpu_reset_scratch(dynarec_arm_t* dyn)
|
||||
dyn->n.xmm_unneeded = 0;
|
||||
dyn->n.ymm_unneeded = 0;
|
||||
dyn->n.xmm_removed = 0;
|
||||
dyn->n.xmm_scalar = 0;
|
||||
dyn->n.xmm_scalar_single = 0;
|
||||
}
|
||||
// Get a x87 double reg
|
||||
int fpu_get_reg_x87(dynarec_arm_t* dyn, int ninst, int t, int n)
|
||||
{
|
||||
int i=X870;
|
||||
while (dyn->n.fpuused[i]) ++i;
|
||||
while (i<32 && dyn->n.fpuused[i]) ++i;
|
||||
if(i==32) {
|
||||
printf_log(LOG_INFO, "BOX64 Dynarec: out of FPU x87 registers at inst=%d\n", ninst);
|
||||
dyn->abort = 1;
|
||||
return X870;
|
||||
}
|
||||
if(dyn->n.neoncache[i].t==NEON_CACHE_YMMR || dyn->n.neoncache[i].t==NEON_CACHE_YMMW) {
|
||||
// should only happens in step 0...
|
||||
dyn->insts[ninst].purge_ymm |= (1<<dyn->n.neoncache[i].n); // mark as purged
|
||||
@@ -109,7 +127,7 @@ void fpu_free_reg(dynarec_arm_t* dyn, int reg)
|
||||
dyn->n.ymm_removed |= 1<<n;
|
||||
if(t==NEON_CACHE_YMMW)
|
||||
dyn->n.ymm_write |= 1<<n;
|
||||
if(reg>SCRATCH0)
|
||||
if(reg>=SCRATCH0)
|
||||
dyn->n.ymm_regs |= (8LL+reg-SCRATCH0)<<(n*4);
|
||||
else
|
||||
dyn->n.ymm_regs |= ((uint64_t)(reg-EMM0))<<(n*4);
|
||||
@@ -429,7 +447,7 @@ static int isCacheEmpty(dynarec_native_t* dyn, int ninst) {
|
||||
if(dyn->insts[ninst].n.stack_next) {
|
||||
return 0;
|
||||
}
|
||||
for(int i=0; i<24; ++i)
|
||||
for(int i=0; i<32; ++i)
|
||||
if(dyn->insts[ninst].n.neoncache[i].v) { // there is something at ninst for i
|
||||
if(!(
|
||||
(dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_ST_F
|
||||
@@ -438,6 +456,8 @@ static int isCacheEmpty(dynarec_native_t* dyn, int ninst) {
|
||||
&& dyn->insts[ninst].n.neoncache[i].n<dyn->insts[ninst].n.stack_pop))
|
||||
return 0;
|
||||
}
|
||||
if(dyn->insts[ninst].ymm0_out)
|
||||
return 0;
|
||||
return 1;
|
||||
|
||||
}
|
||||
@@ -483,7 +503,7 @@ int fpuCacheNeedsTransform(dynarec_arm_t* dyn, int ninst) {
|
||||
if(!cache_i2.neoncache[i].v) { // but there is nothing at i2 for i
|
||||
if(((t==NEON_CACHE_XMMR) || (t==NEON_CACHE_XMMW)) && (cache_i2.xmm_unneeded&(1<<n))) { /* nothing*/}
|
||||
else if(((t==NEON_CACHE_YMMR) || (t==NEON_CACHE_YMMW)) && (cache_i2.ymm_unneeded&(1<<n))) { /* nothing*/}
|
||||
else
|
||||
else
|
||||
return 1;
|
||||
} else if(dyn->insts[ninst].n.neoncache[i].v!=cache_i2.neoncache[i].v) { // there is something different
|
||||
if(n!=cache_i2.neoncache[i].n) { // not the same x64 reg
|
||||
@@ -638,49 +658,6 @@ void neoncacheUnwind(neoncache_t* cache)
|
||||
cache->ymm_used = 0;
|
||||
}
|
||||
|
||||
#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 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;
|
||||
|
||||
uint32_t tested = (1<<parity)-1;
|
||||
if((nextop&0xC0)==0xC0)
|
||||
return 0; // direct register, no parity...
|
||||
if(!(nextop&0xC0)) {
|
||||
if((nextop&7)==4) {
|
||||
uint8_t sib = F8;
|
||||
int sib_reg = (sib>>3)&7;
|
||||
if((sib&0x7)==5) {
|
||||
uint64_t tmp = F32S64;
|
||||
if (sib_reg!=4) {
|
||||
// if XXXXXX+reg<<N then check parity of XXXXX and N should be enough
|
||||
return ((tmp&tested)==0 && (sib>>6)>=parity)?1:0;
|
||||
} else {
|
||||
// just a constant...
|
||||
return (tmp&tested)?0:1;
|
||||
}
|
||||
} else {
|
||||
if(sib_reg==4 && parity<3)
|
||||
return 0; // simple [reg]
|
||||
// don't try [reg1 + reg2<<N], unless reg1 is ESP
|
||||
return ((sib&0x7)==4 && (sib>>6)>=parity)?1:0;
|
||||
}
|
||||
} else if((nextop&7)==5) {
|
||||
uint64_t tmp = F32S64;
|
||||
tmp+=addr+delta;
|
||||
return (tmp&tested)?0:1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
return 0; //Form [reg1 + reg2<<N + XXXXXX]
|
||||
}
|
||||
}
|
||||
#undef F8
|
||||
#undef F32S64
|
||||
|
||||
const char* getCacheName(int t, int n)
|
||||
{
|
||||
static char buff[20];
|
||||
@@ -720,22 +697,22 @@ static register_mapping_t register_mappings[] = {
|
||||
{ "bx", "x13" },
|
||||
{ "bh", "x13" },
|
||||
{ "bl", "x13" },
|
||||
{ "rsi", "x14" },
|
||||
{ "esi", "w14" },
|
||||
{ "si", "x14" },
|
||||
{ "sil", "x14" },
|
||||
{ "rdi", "x15" },
|
||||
{ "edi", "w15" },
|
||||
{ "di", "x15" },
|
||||
{ "dil", "x15" },
|
||||
{ "rsp", "x16" },
|
||||
{ "esp", "w16" },
|
||||
{ "sp", "x16" },
|
||||
{ "spl", "x16" },
|
||||
{ "rbp", "x17" },
|
||||
{ "ebp", "w17" },
|
||||
{ "bp", "x17" },
|
||||
{ "bpl", "x17" },
|
||||
{ "rsp", "x14" },
|
||||
{ "esp", "w14" },
|
||||
{ "sp", "x14" },
|
||||
{ "spl", "x14" },
|
||||
{ "rbp", "x15" },
|
||||
{ "ebp", "w15" },
|
||||
{ "bp", "x15" },
|
||||
{ "bpl", "x15" },
|
||||
{ "rsi", "x16" },
|
||||
{ "esi", "w16" },
|
||||
{ "si", "x16" },
|
||||
{ "sil", "x16" },
|
||||
{ "rdi", "x17" },
|
||||
{ "edi", "w17" },
|
||||
{ "di", "x17" },
|
||||
{ "dil", "x17" },
|
||||
{ "r8", "x18" },
|
||||
{ "r8d", "w18" },
|
||||
{ "r8w", "x18" },
|
||||
@@ -776,6 +753,11 @@ static const char* df_status[] = {"unknown", "set", "none_pending", "none"};
|
||||
void printf_x64_instruction(dynarec_native_t* dyn, zydis_dec_t* dec, instruction_x64_t* inst, const char* name);
|
||||
void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t rex)
|
||||
{
|
||||
if (dyn->need_dump == 3) {
|
||||
printf_x64_instruction(dyn, rex.is32bits ? my_context->dec32 : my_context->dec, &dyn->insts[ninst].x64, name);
|
||||
if (!BOX64ENV(dynarec_gdbjit) && !BOX64ENV(dynarec_perf_map))
|
||||
return;
|
||||
}
|
||||
if (!dyn->need_dump && !BOX64ENV(dynarec_gdbjit) && !BOX64ENV(dynarec_perf_map)) {
|
||||
/*zydis_dec_t* dec = rex.is32bits ? my_context->dec32 : my_context->dec;
|
||||
if(dec && !OpcodeOK(dec, dyn->insts[ninst].x64.addr) && !strstr(name, "Illegal")) {
|
||||
@@ -785,8 +767,8 @@ void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t r
|
||||
return;
|
||||
}
|
||||
|
||||
static char buf[4096];
|
||||
int length = sprintf(buf, "barrier=%d state=%d/%s(%s->%s)/%c, set=%X/%X, use=%X, need=%X/%X, sm=%d(%d/%d/%d)",
|
||||
static char buf[8192];
|
||||
int length = sprintf(buf, "barrier=%d state=%d/%s(%s->%s)/%c, set=%X/%X, use=%X, need=%X/%X, sm=%d(%d/%d/%d)%d",
|
||||
dyn->insts[ninst].x64.barrier,
|
||||
dyn->insts[ninst].x64.state_flags,
|
||||
df_status[dyn->f],
|
||||
@@ -798,15 +780,19 @@ 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->smwrite, dyn->insts[ninst].will_write, dyn->insts[ninst].last_write, dyn->insts[ninst].lock);
|
||||
dyn->smwrite, dyn->insts[ninst].will_write, dyn->insts[ninst].last_write, dyn->insts[ninst].lock,
|
||||
dyn->insts[ninst].x64.strongmem);
|
||||
if(dyn->insts[ninst].use_lrcpc || dyn->insts[ninst].has_lrcpc) {
|
||||
length += sprintf(buf + length, " LRCPC:%d/%d", dyn->insts[ninst].use_lrcpc, dyn->insts[ninst].has_lrcpc);
|
||||
}
|
||||
if (dyn->insts[ninst].nat_flags_op) {
|
||||
if (dyn->insts[ninst].nat_flags_op == NAT_FLAG_OP_TOUCH && dyn->insts[ninst].before_nat_flags)
|
||||
length += sprintf(buf + length, " NF:%d/read:%x", dyn->insts[ninst].nat_flags_op, dyn->insts[ninst].before_nat_flags);
|
||||
else
|
||||
length += sprintf(buf + length, " NF:%d", dyn->insts[ninst].nat_flags_op);
|
||||
}
|
||||
if (dyn->insts[ninst].use_nat_flags || dyn->insts[ninst].set_nat_flags || dyn->insts[ninst].need_nat_flags) {
|
||||
length += sprintf(buf + length, " nf:%hhx/%hhx/%hhx", dyn->insts[ninst].set_nat_flags, dyn->insts[ninst].use_nat_flags, dyn->insts[ninst].need_nat_flags);
|
||||
if (dyn->insts[ninst].use_nat_flags || dyn->insts[ninst].set_nat_flags || dyn->insts[ninst].need_nat_flags || dyn->insts[ninst].nat_flags_in) {
|
||||
length += sprintf(buf + length, " nf:%hhx/%hhx/%hhx->%hhx", dyn->insts[ninst].set_nat_flags, dyn->insts[ninst].use_nat_flags, dyn->insts[ninst].nat_flags_in, dyn->insts[ninst].need_nat_flags);
|
||||
}
|
||||
if (dyn->insts[ninst].invert_carry)
|
||||
length += sprintf(buf + length, " CI");
|
||||
@@ -862,6 +848,12 @@ void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t r
|
||||
if (dyn->insts[ninst].n.xmm_used || dyn->insts[ninst].n.xmm_unneeded || dyn->insts[ninst].n.xmm_needed) {
|
||||
length += sprintf(buf + length, " xmmUsed=%04x/needed=%04x/unneeded=%04x", dyn->insts[ninst].n.xmm_used, dyn->insts[ninst].n.xmm_needed, dyn->insts[ninst].n.xmm_unneeded);
|
||||
}
|
||||
if (dyn->insts[ninst].n.xmmh_used || dyn->insts[ninst].n.xmmh_needed || dyn->insts[ninst].n.xmmh_unneeded) {
|
||||
length += sprintf(buf + length, " xmmHused=%04x/needed=%04x/unneeded=%04x", dyn->insts[ninst].n.xmmh_used, dyn->insts[ninst].n.xmmh_needed, dyn->insts[ninst].n.xmmh_unneeded);
|
||||
}
|
||||
if (dyn->insts[ninst].n.xmms_used || dyn->insts[ninst].n.xmms_needed || dyn->insts[ninst].n.xmms_unneeded) {
|
||||
length += sprintf(buf + length, " xmmSused=%04x/needed=%04x/unneeded=%04x", dyn->insts[ninst].n.xmms_used, dyn->insts[ninst].n.xmms_needed, dyn->insts[ninst].n.xmms_unneeded);
|
||||
}
|
||||
if (dyn->insts[ninst].n.ymm_used || dyn->insts[ninst].n.ymm_unneeded || dyn->insts[ninst].n.ymm_needed) {
|
||||
length += sprintf(buf + length, " ymmUsed=%04x/needed=%04x/unneeded=%04x", dyn->insts[ninst].n.ymm_used, dyn->insts[ninst].n.ymm_needed, dyn->insts[ninst].n.ymm_unneeded);
|
||||
}
|
||||
@@ -882,7 +874,7 @@ void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t r
|
||||
}
|
||||
if(dyn->insts[ninst].x64.self_loop)
|
||||
length += sprintf(buf + length, " self-loop");
|
||||
if (dyn->need_dump) {
|
||||
if (dyn->need_dump && dyn->need_dump != 3) {
|
||||
printf_x64_instruction(dyn, rex.is32bits ? my_context->dec32 : my_context->dec, &dyn->insts[ninst].x64, name);
|
||||
dynarec_log(LOG_NONE, "%s%p: %d emitted opcodes, inst=%d, %s%s\n",
|
||||
(dyn->need_dump > 1) ? "\e[32m" : "",
|
||||
@@ -904,7 +896,7 @@ void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t r
|
||||
dyn->gdbjit_block = GdbJITBlockAddLine(dyn->gdbjit_block, (dyn->native_start + dyn->insts[ninst].address), inst_name);
|
||||
}
|
||||
if (BOX64ENV(dynarec_perf_map) && (BOX64ENV(dynarec_perf_map_fd) != -1) && dyn->insts[ninst].size) {
|
||||
writePerfMap(dyn->insts[ninst].x64.addr, dyn->native_start + dyn->insts[ninst].address, dyn->insts[ninst].size / 4, name);
|
||||
writePerfMap(dyn->insts[ninst].x64.addr, dyn->native_start + dyn->insts[ninst].address, dyn->insts[ninst].size, name);
|
||||
}
|
||||
if(length>sizeof(buf)) printf_log(LOG_NONE, "Warning: buf to small in inst_name_pass3 (%d vs %zd)\n", length, sizeof(buf));
|
||||
}
|
||||
@@ -1110,6 +1102,7 @@ static void propagateNativeFlags(dynarec_arm_t* dyn, int start)
|
||||
//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 oldnc = nc;
|
||||
int carry = used_flags&NF_CF;
|
||||
// propagate
|
||||
while(ninst<dyn->size) {
|
||||
@@ -1145,6 +1138,10 @@ static void propagateNativeFlags(dynarec_arm_t* dyn, int start)
|
||||
return;
|
||||
} else
|
||||
++ninst;
|
||||
if(ninst<dyn->size) {
|
||||
dyn->insts[ninst].nat_flags_in |= used_flags&use_flags;
|
||||
if(carry) dyn->insts[ninst].normal_carry_in = oldnc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1223,26 +1220,32 @@ static uint32_t getXYMMMask(dynarec_arm_t* dyn, int ninst)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void propagateXYMMNeeded(dynarec_arm_t* dyn, int ninst, uint16_t mask_x, uint16_t mask_y)
|
||||
static void propagateXYMMNeeded(dynarec_arm_t* dyn, int ninst, uint16_t mask_x, uint16_t mask_y, uint16_t mask_xh, uint16_t mask_xs)
|
||||
{
|
||||
while(ninst>=0) {
|
||||
// removed unneeded regs
|
||||
mask_x &= ~dyn->insts[ninst].n.xmm_unneeded;
|
||||
mask_y &= ~dyn->insts[ninst].n.ymm_unneeded;
|
||||
mask_xh &= ~dyn->insts[ninst].n.xmmh_unneeded;
|
||||
mask_xs &= ~dyn->insts[ninst].n.xmms_unneeded;
|
||||
// removed already needed from mask
|
||||
mask_x &= ~dyn->insts[ninst].n.xmm_needed;
|
||||
mask_y &= ~dyn->insts[ninst].n.ymm_needed;
|
||||
mask_xh &= ~dyn->insts[ninst].n.xmmh_needed;
|
||||
mask_xs &= ~dyn->insts[ninst].n.xmms_needed;
|
||||
// already handled
|
||||
if(!mask_x && !mask_y) return;
|
||||
if(!mask_x && !mask_y && !mask_xh && !mask_xs) return;
|
||||
// added the unneeded value
|
||||
dyn->insts[ninst].n.xmm_needed |= mask_x;
|
||||
dyn->insts[ninst].n.ymm_needed |= mask_y;
|
||||
dyn->insts[ninst].n.xmmh_needed |= mask_xh;
|
||||
dyn->insts[ninst].n.xmms_needed |= mask_xs;
|
||||
for(int i=1; i<dyn->insts[ninst].pred_sz; ++i) {
|
||||
int j = dyn->insts[ninst].pred[i];
|
||||
// barrier or callret, value is needed
|
||||
if(!(dyn->insts[j].x64.barrier&BARRIER_FLOAT)
|
||||
&& !(dyn->insts[j].x64.has_callret))
|
||||
propagateXYMMNeeded(dyn, j, mask_x, mask_y);
|
||||
propagateXYMMNeeded(dyn, j, mask_x, mask_y, mask_xh, mask_xs);
|
||||
}
|
||||
if(dyn->insts[ninst].pred_sz)
|
||||
ninst = dyn->insts[ninst].pred[0];
|
||||
@@ -1255,25 +1258,31 @@ static void propagateXYMMNeeded(dynarec_arm_t* dyn, int ninst, uint16_t mask_x,
|
||||
}
|
||||
}
|
||||
|
||||
static void propagateXYMMUneeded(dynarec_arm_t* dyn, int ninst, uint16_t mask_x, uint16_t mask_y)
|
||||
static void propagateXYMMUneeded(dynarec_arm_t* dyn, int ninst, uint16_t mask_x, uint16_t mask_y, uint16_t mask_xh, uint16_t mask_xs)
|
||||
{
|
||||
while(ninst>=0) {
|
||||
// removed needed regs
|
||||
mask_x &= ~dyn->insts[ninst].n.xmm_needed;
|
||||
mask_y &= ~dyn->insts[ninst].n.ymm_needed;
|
||||
mask_xh &= ~dyn->insts[ninst].n.xmmh_needed;
|
||||
mask_xs &= ~dyn->insts[ninst].n.xmms_needed;
|
||||
// removed already unneeded from mask
|
||||
mask_x &= ~dyn->insts[ninst].n.xmm_unneeded;
|
||||
mask_y &= ~dyn->insts[ninst].n.ymm_unneeded;
|
||||
mask_xh &= ~dyn->insts[ninst].n.xmmh_unneeded;
|
||||
mask_xs &= ~dyn->insts[ninst].n.xmms_unneeded;
|
||||
// already handled
|
||||
if(!mask_x && !mask_y) return;
|
||||
if(!mask_x && !mask_y && !mask_xh && !mask_xs) return;
|
||||
// barrier or callret, value is needed
|
||||
if(dyn->insts[ninst].x64.barrier&BARRIER_FLOAT) return;
|
||||
if(dyn->insts[ninst].x64.has_callret) return;
|
||||
// added the unneeded value
|
||||
dyn->insts[ninst].n.xmm_unneeded |= mask_x;
|
||||
dyn->insts[ninst].n.ymm_unneeded |= mask_y;
|
||||
dyn->insts[ninst].n.xmmh_unneeded |= mask_xh;
|
||||
dyn->insts[ninst].n.xmms_unneeded |= mask_xs;
|
||||
for(int i=1; i<dyn->insts[ninst].pred_sz; ++i)
|
||||
propagateXYMMUneeded(dyn, dyn->insts[ninst].pred[i], mask_x, mask_y);
|
||||
propagateXYMMUneeded(dyn, dyn->insts[ninst].pred[i], mask_x, mask_y, mask_xh, mask_xs);
|
||||
if(dyn->insts[ninst].pred_sz)
|
||||
ninst = dyn->insts[ninst].pred[0];
|
||||
else
|
||||
@@ -1287,24 +1296,46 @@ void updateUneeded(dynarec_arm_t* dyn)
|
||||
|
||||
if(!dyn->use_xmm && !dyn->use_ymm)
|
||||
return;
|
||||
// Upper-64 liveness of the low 16 XMM, seeded here and propagated by the same
|
||||
// needed/unneeded passes below used for whole-xmm and the ymm upper-128 lanes.
|
||||
// A scalar SD op touches only the low 64, so it sits in xmm_scalar and is masked
|
||||
// out of xmmh_used; every full-width reader keeps its bit and pins the upper lane
|
||||
// live. An op may zero the upper in place (skipping the x86 upper-preserve) only
|
||||
// where xmmh_unneeded proves the lane dead.
|
||||
// xmms is the same, one dword lower: the upper-96 [127:32] used by scalar-single ops.
|
||||
// A scalar SD op still reads [63:32], so only scalar-single ops (xmm_scalar_single) are
|
||||
// masked out of xmms_used. An SS op may zero the upper-96 in place only where xmms_unneeded
|
||||
// proves it dead.
|
||||
for(int ninst=0; ninst<dyn->size; ++ninst) {
|
||||
dyn->insts[ninst].n.xmmh_used = dyn->insts[ninst].n.xmm_used & ~dyn->insts[ninst].n.xmm_scalar;
|
||||
dyn->insts[ninst].n.xmmh_unneeded = dyn->insts[ninst].n.xmm_unneeded;
|
||||
dyn->insts[ninst].n.xmms_used = dyn->insts[ninst].n.xmm_used & ~dyn->insts[ninst].n.xmm_scalar_single;
|
||||
dyn->insts[ninst].n.xmms_unneeded = dyn->insts[ninst].n.xmm_unneeded;
|
||||
}
|
||||
// first propagate the needed regs: those which are used and are not unneeded
|
||||
for(int ninst=dyn->size-1; ninst>=0; --ninst) {
|
||||
uint16_t xmm_needed = dyn->insts[ninst].n.xmm_used&~dyn->insts[ninst].n.xmm_unneeded;
|
||||
uint16_t ymm_needed = dyn->insts[ninst].n.ymm_used&~dyn->insts[ninst].n.ymm_unneeded;
|
||||
uint16_t xmmh_needed = dyn->insts[ninst].n.xmmh_used&~dyn->insts[ninst].n.xmmh_unneeded;
|
||||
uint16_t xmms_needed = dyn->insts[ninst].n.xmms_used&~dyn->insts[ninst].n.xmms_unneeded;
|
||||
// an unresolved exit (float barrier or jump out of the block) can reach code
|
||||
// that reads the full registers, so pin every lane live there, upper-64/96 included
|
||||
if((dyn->insts[ninst].x64.barrier&BARRIER_FLOAT) || (dyn->insts[ninst].x64.jmp && (dyn->insts[ninst].x64.jmp_insts==-1)))
|
||||
{
|
||||
if(dyn->use_xmm) xmm_needed = 0xffff;
|
||||
if(dyn->use_ymm) ymm_needed = 0xffff;
|
||||
if(dyn->use_xmm) xmmh_needed = 0xffff;
|
||||
if(dyn->use_xmm) xmms_needed = 0xffff;
|
||||
}
|
||||
if(xmm_needed || ymm_needed)
|
||||
propagateXYMMNeeded(dyn, ninst, xmm_needed, ymm_needed);
|
||||
if(xmm_needed || ymm_needed || xmmh_needed || xmms_needed)
|
||||
propagateXYMMNeeded(dyn, ninst, xmm_needed, ymm_needed, xmmh_needed, xmms_needed);
|
||||
|
||||
}
|
||||
// then proagate the unneeded one: those which are not needed (not used anymore and will be overwritten)
|
||||
for(int ninst=dyn->size-1; ninst>=0; --ninst) {
|
||||
if(dyn->insts[ninst].n.xmm_unneeded || dyn->insts[ninst].n.ymm_unneeded) {
|
||||
if(dyn->insts[ninst].n.xmm_unneeded || dyn->insts[ninst].n.ymm_unneeded || dyn->insts[ninst].n.xmmh_unneeded || dyn->insts[ninst].n.xmms_unneeded) {
|
||||
for(int i=0; i<dyn->insts[ninst].pred_sz; ++i)
|
||||
propagateXYMMUneeded(dyn, dyn->insts[ninst].pred[i], dyn->insts[ninst].n.xmm_unneeded, dyn->insts[ninst].n.ymm_unneeded);
|
||||
propagateXYMMUneeded(dyn, dyn->insts[ninst].pred[i], dyn->insts[ninst].n.xmm_unneeded, dyn->insts[ninst].n.ymm_unneeded, dyn->insts[ninst].n.xmmh_unneeded, dyn->insts[ninst].n.xmms_unneeded);
|
||||
}
|
||||
}
|
||||
// try to add some preload of XYMM on jump were it would make sense
|
||||
@@ -1355,7 +1386,7 @@ void tryEarlyFpuBarrier(dynarec_arm_t* dyn, int last_fpu_used, int ninst)
|
||||
}
|
||||
// we will stop there, not trying to guess too much thing
|
||||
if((usefull && (i+1)!=ninst)) {
|
||||
if(BOX64ENV(dynarec_dump) || BOX64ENV(dynarec_log)>1) dynarec_log(LOG_NONE, "Putting early Float Barrier in %d for %d\n", i+1, ninst);
|
||||
if((BOX64ENV(dynarec_dump) && BOX64ENV(dynarec_dump) != 3) || BOX64ENV(dynarec_log)>1) dynarec_log(LOG_NONE, "Putting early Float Barrier in %d for %d\n", i+1, ninst);
|
||||
dyn->insts[i+1].x64.barrier|=BARRIER_FLOAT;
|
||||
}
|
||||
return;
|
||||
@@ -1365,7 +1396,7 @@ void tryEarlyFpuBarrier(dynarec_arm_t* dyn, int last_fpu_used, int ninst)
|
||||
for(int pred=0; pred<dyn->insts[i].pred_sz; ++pred) {
|
||||
if(dyn->insts[i].pred[pred]<=last_fpu_used) {
|
||||
if(usefull && ((i+1)!=ninst)) {
|
||||
if(BOX64ENV(dynarec_dump) || BOX64ENV(dynarec_log)>1) dynarec_log(LOG_NONE, "Putting early Float Barrier in %d for %d\n", i+1, ninst);
|
||||
if((BOX64ENV(dynarec_dump) && BOX64ENV(dynarec_dump) != 3) || BOX64ENV(dynarec_log)>1) dynarec_log(LOG_NONE, "Putting early Float Barrier in %d for %d\n", i+1, ninst);
|
||||
dyn->insts[i+1].x64.barrier|=BARRIER_FLOAT;
|
||||
}
|
||||
return;
|
||||
@@ -1375,7 +1406,7 @@ void tryEarlyFpuBarrier(dynarec_arm_t* dyn, int last_fpu_used, int ninst)
|
||||
usefull = 1;
|
||||
}
|
||||
if(usefull) {
|
||||
if(BOX64ENV(dynarec_dump) || BOX64ENV(dynarec_log)>1) dynarec_log(LOG_NONE, "Putting early Float Barrier in %d for %d\n", last_fpu_used, ninst);
|
||||
if((BOX64ENV(dynarec_dump) && BOX64ENV(dynarec_dump) != 3) || BOX64ENV(dynarec_log)>1) dynarec_log(LOG_NONE, "Putting early Float Barrier in %d for %d\n", last_fpu_used, ninst);
|
||||
dyn->insts[last_fpu_used+1].x64.barrier|=BARRIER_FLOAT;
|
||||
}
|
||||
}
|
||||
@@ -1483,6 +1514,11 @@ void updateYmm0s(dynarec_arm_t* dyn, int ninst, int max_ninst_reached)
|
||||
}
|
||||
|
||||
|
||||
void sse_mark_used(dynarec_arm_t* dyn, int ninst, int a)
|
||||
{
|
||||
dyn->n.xmm_used |= 1<<a;
|
||||
}
|
||||
|
||||
// AVX helpers
|
||||
void avx_mark_zero(dynarec_arm_t* dyn, int ninst, int reg)
|
||||
{
|
||||
@@ -1526,7 +1562,7 @@ static int ymm_preload_reg(dynarec_arm_t* dyn, int ninst, int last, int ymm)
|
||||
while((ninst<last) && (i!=-1)) {
|
||||
// check if the reg is always free
|
||||
if(!(!dyn->insts[ninst].n.neoncache[i].v ||
|
||||
(dyn->insts[ninst].n.neoncache[i].n==ymm
|
||||
(dyn->insts[ninst].n.neoncache[i].n==ymm
|
||||
&& (dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_YMMR || dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_YMMW))))
|
||||
i = -1; // nope
|
||||
else
|
||||
@@ -1542,12 +1578,17 @@ void addSSEPreload(dynarec_arm_t* dyn, int ninst, int i2, uint32_t preload)
|
||||
if(i2 && !dyn->insts[i2-1].x64.has_next) // need a previous opcode to set the preload, unless it's the #0
|
||||
return;
|
||||
// check if there is jump out or outside this loop
|
||||
int has_host_call = 0;
|
||||
for(int i=i2; i<ninst; ++i) {
|
||||
if(!dyn->insts[i].x64.has_next || (dyn->insts[i].x64.barrier&BARRIER_FLOAT))
|
||||
return;
|
||||
// for now, unneeded stop at first jump, so this should also stop there
|
||||
if(dyn->insts[i].x64.jmp/* && ((dyn->insts[i].x64.jmp_insts>ninst) || (dyn->insts[i].x64.jmp_insts<i2))*/)
|
||||
return;
|
||||
if(dyn->insts[i].host_call_clobber)
|
||||
return;
|
||||
if(dyn->insts[i].host_call)
|
||||
has_host_call = 1;
|
||||
}
|
||||
uint16_t ymm_mask = 0;
|
||||
for(int i=0; i<16; ++i) {
|
||||
@@ -1586,9 +1627,9 @@ void addSSEPreload(dynarec_arm_t* dyn, int ninst, int i2, uint32_t preload)
|
||||
}
|
||||
}
|
||||
preload = (preload&0xffff) | (ymm_mask<<16); // update ymm_mask
|
||||
//TODO: should check native calls too?
|
||||
dyn->insts[i2].preload_xmmymm = preload;
|
||||
dyn->insts[i2].preload_from = ninst;
|
||||
dyn->insts[i2].preload_host_call = has_host_call;
|
||||
dyn->insts[i2].n.xmm_unneeded |= preload&0xffff;
|
||||
dyn->insts[i2].n.ymm_unneeded |= ymm_mask;
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#ifndef __DYNAREC_ARM_FUNCTIONS_H__
|
||||
#define __DYNAREC_ARM_FUNCTIONS_H__
|
||||
|
||||
@@ -70,10 +71,6 @@ void neoncacheUnwind(neoncache_t* cache);
|
||||
void fpu_save_and_unwind(dynarec_arm_t* dyn, int ninst, neoncache_t* cache);
|
||||
void fpu_unwind_restore(dynarec_arm_t* dyn, int ninst, neoncache_t* cache);
|
||||
|
||||
|
||||
// Get if ED will have the correct parity. Not emitting anything. Parity is 2 for DWORD or 3 for QWORD
|
||||
int getedparity(dynarec_native_t* dyn, int ninst, uintptr_t addr, uint8_t nextop, int parity, int delta);
|
||||
|
||||
const char* getCacheName(int t, int n);
|
||||
|
||||
void inst_name_pass3(dynarec_native_t* dyn, int ninst, const char* name, rex_t rex);
|
||||
@@ -96,6 +93,9 @@ void updateYmm0s(dynarec_arm_t* dyn, int ninst, int max_ninst_reached);
|
||||
// add a preload of SSE/AVX register preload before i2, for a jump in ninst. Might not do it if there is jump in between that goes outside this ninst-i2 interval
|
||||
void addSSEPreload(dynarec_arm_t* dyn, int ninst, int i2, uint32_t preload);
|
||||
|
||||
// mark a SSE reg as read by the current opcode, without touching its cache entry
|
||||
void sse_mark_used(dynarec_arm_t* dyn, int ninst, int a);
|
||||
|
||||
// AVX helpers
|
||||
void avx_mark_zero(dynarec_arm_t* dyn, int ninst, int reg);
|
||||
int is_avx_zero(dynarec_arm_t* dyn, int ninst, int reg);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
@@ -34,6 +35,12 @@ uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, u
|
||||
int lock = l?((l==LOCK_LOCK)?1:2):0;
|
||||
if(lock==2) *l = 0;
|
||||
|
||||
if(dyn->insts[ninst].use_lrcpc) {
|
||||
if(!unscaled) {
|
||||
NOLRCPC();
|
||||
} else { absmax = 0; mask=0;}
|
||||
} // there is no "Scaled" version, only Unscaled
|
||||
|
||||
if(rex.is32bits && rex.is67)
|
||||
return geted16(dyn, addr, ninst, nextop, ed, hint, fixaddress, unscaled, absmax, mask, rex, s);
|
||||
|
||||
@@ -43,7 +50,7 @@ uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, u
|
||||
uint8_t scratch = x2;
|
||||
*fixaddress = 0;
|
||||
if(hint>0) ret = hint;
|
||||
if(hint>0 && hint<xRAX) scratch = hint;
|
||||
if(hint>0 && !IS_GPR(hint)) scratch = hint;
|
||||
int absmin = 0;
|
||||
if(s) absmin=-absmax;
|
||||
int seg_done = 0;
|
||||
@@ -197,7 +204,7 @@ uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, u
|
||||
}
|
||||
ADDy_REG_LSL(ret, scratch, TO_NAT(sib_reg), (sib>>6));
|
||||
} else {
|
||||
PASS3(int tmp = TO_NAT(sib & 0x07) + (rex.b << 3));
|
||||
PASS3(int tmp = TO_NAT((sib & 0x07) + (rex.b << 3)));
|
||||
if(sub) {
|
||||
SUBy_REG(ret, tmp, scratch);
|
||||
} else {
|
||||
@@ -220,8 +227,9 @@ uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, u
|
||||
ret = hint;
|
||||
}
|
||||
if(rex.seg && !seg_done) {
|
||||
scratch = (hint>0 && !IS_GPR(hint)) ? hint : x2;
|
||||
if(scratch==ret)
|
||||
scratch=ret+1;
|
||||
scratch = xLR; // dead between opcodes, ret+1 can be a guest register
|
||||
grab_segdata(dyn, addr, ninst, scratch, rex.seg);
|
||||
//seg offset is 64bits, so no truncation here
|
||||
ADDx_REGy(hint, scratch, ret);
|
||||
@@ -259,7 +267,7 @@ uintptr_t geted16(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop,
|
||||
case 1: offset = F8S; break;
|
||||
case 2: offset = F16S; break;
|
||||
}
|
||||
if(offset && (offset>=absmax && offset<=absmin && !(offset&mask))) {
|
||||
if(offset && (offset>=absmin && offset<=absmax && !(offset&mask))) {
|
||||
*fixaddress = offset;
|
||||
offset = 0;
|
||||
}
|
||||
@@ -313,7 +321,7 @@ uintptr_t geted16(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop,
|
||||
|
||||
if(rex.seg) {
|
||||
if(scratch==ret)
|
||||
scratch=ret+1;
|
||||
scratch = xLR;
|
||||
grab_segdata(dyn, addr, ninst, scratch, rex.seg);
|
||||
//seg offset is 64bits, so no truncation here
|
||||
if(IS_GPR(ret)) {
|
||||
@@ -342,8 +350,10 @@ void jump_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst)
|
||||
TABLE64C(x2, const_epilog);
|
||||
SMEND();
|
||||
CHECK_DFNONE(0);
|
||||
if(dyn->have_purge)
|
||||
#ifndef BOX64EC // no CALLRET on Box64EC yet
|
||||
if (BOX64DRENV(dynarec_callret) >= 3)
|
||||
doLeaveBlock(dyn, ninst, x4, x5, x6);
|
||||
#endif
|
||||
BR(x2);
|
||||
}
|
||||
|
||||
@@ -418,18 +428,22 @@ void jump_to_next(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst, int is32
|
||||
if(reg!=x1) {
|
||||
MOVx_REG(x1, xRIP);
|
||||
}
|
||||
if(dyn->have_purge && !dyn->insts[ninst].x64.has_callret)
|
||||
#ifndef BOX64EC // no CALLRET on Box64EC yet
|
||||
if(BOX64DRENV(dynarec_callret) >= 3 && !dyn->insts[ninst].x64.has_callret)
|
||||
doLeaveBlock(dyn, ninst, x4, x5, x6);
|
||||
#ifdef HAVE_TRACE
|
||||
//MOVx(x3, 15); no access to PC reg
|
||||
BLR(dest); // save LR...
|
||||
#else
|
||||
#endif
|
||||
// #ifdef HAVE_TRACE
|
||||
// The BLR form is only for gdb backtraces, but it breaks the
|
||||
// return-address-stack prediction on every block-to-block jump, which is
|
||||
// not worth it. Uncomment temporarily when debugging with gdb.
|
||||
// BLR(dest); // save LR...
|
||||
// #else
|
||||
if (dyn->insts[ninst].x64.has_callret) {
|
||||
BLR(dest); // save LR...
|
||||
} else {
|
||||
BR(dest);
|
||||
}
|
||||
#endif
|
||||
// #endif
|
||||
}
|
||||
|
||||
void ret_to_next(dynarec_arm_t* dyn, uintptr_t ip, int ninst, rex_t rex)
|
||||
@@ -438,21 +452,21 @@ void ret_to_next(dynarec_arm_t* dyn, uintptr_t ip, int ninst, rex_t rex)
|
||||
CHECK_DFNONE(0);
|
||||
MOVz_REG(x1, xRIP);
|
||||
SMEND();
|
||||
#ifndef BOX64EC // no CALLRET on Box64EC yet
|
||||
if(BOX64DRENV(dynarec_callret)) {
|
||||
// pop the actual return address for ARM stack
|
||||
LDPx_S7_postindex(xLR, x6, xSP, 16);
|
||||
SUBx_REG(x6, x6, xRIP); // is it the right address?
|
||||
if(dyn->have_purge)
|
||||
if (BOX64DRENV(dynarec_callret) >= 3)
|
||||
doLeaveBlock(dyn, ninst, x4, x5, x3);
|
||||
CBNZx(x6, 2*4);
|
||||
RET(xLR);
|
||||
// not the correct return address, regular jump, but purge the stack first, it's unsync now...
|
||||
SUBx_U12(xSP, xSavedSP, 16);
|
||||
}
|
||||
#endif
|
||||
NOTEST(x2);
|
||||
int dest = indirect_lookup(dyn, ninst, rex.is32bits, x2, x3);
|
||||
if(dyn->have_purge && !BOX64DRENV(dynarec_callret))
|
||||
doLeaveBlock(dyn, ninst, x4, x5, x6);
|
||||
#ifdef HAVE_TRACE
|
||||
BLR(dest);
|
||||
#else
|
||||
@@ -517,6 +531,7 @@ void iret_to_next(dynarec_arm_t* dyn, uintptr_t ip, int ninst, int is32bits, int
|
||||
rex_t dummy = {0};
|
||||
dummy.is32bits = is32bits;
|
||||
dummy.w = is64bits;
|
||||
TBNZ_MARK2(xFlags, F_TF);
|
||||
ret_to_next(dyn, ip, ninst, dummy);
|
||||
CLEARIP();
|
||||
MARK;
|
||||
@@ -530,11 +545,17 @@ void iret_to_next(dynarec_arm_t* dyn, uintptr_t ip, int ninst, int is32bits, int
|
||||
else
|
||||
ADDx_U12(xRSP, xRSP, 4*3);
|
||||
CALL_S(const_native_priv, -1);
|
||||
MARK2;
|
||||
LDRw_U12(x4, xEmu, offsetof(x64emu_t, flags));
|
||||
ORRw_mask(x4, x4, 32-FLAGS_NO_TF, 0); //mask=1<<FLAGS_NO_TF
|
||||
STRw_U12(x4, xEmu, offsetof(x64emu_t, flags));
|
||||
jump_to_epilog(dyn, 0, xRIP, ninst);
|
||||
}
|
||||
|
||||
void call_c(dynarec_arm_t* dyn, int ninst, arm64_consts_t fnc, int reg, int ret, int saveflags, int savereg)
|
||||
{
|
||||
MAYUSE(fnc);
|
||||
dyn->insts[ninst].host_call = 1;
|
||||
CHECK_DFNONE(1);
|
||||
#if STEP == 0
|
||||
dyn->insts[ninst].nat_flags_op = NAT_FLAG_OP_UNUSABLE;
|
||||
@@ -551,10 +572,16 @@ void call_c(dynarec_arm_t* dyn, int ninst, arm64_consts_t fnc, int reg, int ret,
|
||||
STPx_S7_offset(xRSP, xRBP, xEmu, offsetof(x64emu_t, regs[_SP]));
|
||||
STPx_S7_offset(xRSI, xRDI, xEmu, offsetof(x64emu_t, regs[_SI]));
|
||||
STPx_S7_offset(xR8, xR9, xEmu, offsetof(x64emu_t, regs[_R8]));
|
||||
#ifdef BOX64EC
|
||||
// R10 and R11 are not preserved by the C call in the EC map
|
||||
STPx_S7_offset(xR10, xR11, xEmu, offsetof(x64emu_t, regs[_R10]));
|
||||
#endif
|
||||
fpu_pushcache(dyn, ninst, savereg, 0);
|
||||
for(int i=0; i<dyn->n.fpu_scratch; ++i)
|
||||
VSTR128_S9_preindex(SCRATCH0+i, xSP, -16);
|
||||
}
|
||||
#ifdef _WIN32
|
||||
LDRx_U12(xR8, xEmu, offsetof(x64emu_t, win64_teb));
|
||||
LDRx_U12(xTEB, xEmu, offsetof(x64emu_t, win64_teb));
|
||||
#endif
|
||||
TABLE64C(reg, fnc);
|
||||
BLR(reg);
|
||||
@@ -562,6 +589,8 @@ void call_c(dynarec_arm_t* dyn, int ninst, arm64_consts_t fnc, int reg, int ret,
|
||||
MOVx_REG(ret, xEmu);
|
||||
}
|
||||
if(ret!=-2) {
|
||||
for(int i=dyn->n.fpu_scratch-1; i>=0; --i)
|
||||
VLDR128_S9_postindex(SCRATCH0+i, xSP, 16);
|
||||
LDPx_S7_postindex(xEmu, savereg, xSP, 16);
|
||||
#define GO(A, B) if(ret==x##A) { \
|
||||
LDRx_U12(x##B, xEmu, offsetof(x64emu_t, regs[_##B])); \
|
||||
@@ -575,21 +604,30 @@ void call_c(dynarec_arm_t* dyn, int ninst, arm64_consts_t fnc, int reg, int ret,
|
||||
GO(RSP, RBP);
|
||||
GO(RSI, RDI);
|
||||
GO(R8, R9);
|
||||
#ifdef BOX64EC
|
||||
GO(R10, R11);
|
||||
#endif
|
||||
#undef GO
|
||||
fpu_popcache(dyn, ninst, savereg, 0); // savereg will not be used
|
||||
}
|
||||
if(saveflags) {
|
||||
LDRx_U12(xFlags, xEmu, offsetof(x64emu_t, eflags));
|
||||
}
|
||||
#ifdef BOX64EC
|
||||
// x87pc is x5, the pop above restored an argument: reload it
|
||||
NATIVE_RESTORE_X87PC();
|
||||
#else
|
||||
if(savereg!=x87pc && dyn->need_x87check) {
|
||||
NATIVE_RESTORE_X87PC();
|
||||
}
|
||||
#endif
|
||||
//SET_NODF();
|
||||
}
|
||||
|
||||
void call_d(dynarec_arm_t* dyn, int ninst, arm64_consts_t fnc, int ret, int arg1, int arg2, int sav1, int sav2)
|
||||
{
|
||||
MAYUSE(fnc);
|
||||
dyn->insts[ninst].host_call = 1;
|
||||
CHECK_DFNONE(1);
|
||||
#if STEP == 0
|
||||
dyn->insts[ninst].nat_flags_op = NAT_FLAG_OP_UNUSABLE;
|
||||
@@ -603,11 +641,14 @@ void call_d(dynarec_arm_t* dyn, int ninst, arm64_consts_t fnc, int ret, int arg1
|
||||
STPx_S7_offset(xRSP, xRBP, xEmu, offsetof(x64emu_t, regs[_SP]));
|
||||
STPx_S7_offset(xRSI, xRDI, xEmu, offsetof(x64emu_t, regs[_SI]));
|
||||
STPx_S7_offset(xR8, xR9, xEmu, offsetof(x64emu_t, regs[_R8]));
|
||||
#ifdef BOX64EC
|
||||
STPx_S7_offset(xR10, xR11, xEmu, offsetof(x64emu_t, regs[_R10])); // not preserved by the C call, as in call_c
|
||||
#endif
|
||||
STRx_U12(xFlags, xEmu, offsetof(x64emu_t, eflags));
|
||||
fpu_pushcache(dyn, ninst, x87pc, 0);
|
||||
|
||||
#ifdef _WIN32
|
||||
LDRx_U12(xR8, xEmu, offsetof(x64emu_t, win64_teb));
|
||||
LDRx_U12(xTEB, xEmu, offsetof(x64emu_t, win64_teb));
|
||||
#endif
|
||||
if(arg1!=-1)
|
||||
FMOVD(0, arg1);
|
||||
@@ -627,6 +668,9 @@ void call_d(dynarec_arm_t* dyn, int ninst, arm64_consts_t fnc, int ret, int arg1
|
||||
GO(RSP, RBP);
|
||||
GO(RSI, RDI);
|
||||
GO(R8, R9);
|
||||
#ifdef BOX64EC
|
||||
GO(R10, R11);
|
||||
#endif
|
||||
#undef GO
|
||||
LDRx_U12(xFlags, xEmu, offsetof(x64emu_t, eflags));
|
||||
fpu_popcache(dyn, ninst, x1, 0); // savereg will not be used
|
||||
@@ -636,6 +680,8 @@ void call_d(dynarec_arm_t* dyn, int ninst, arm64_consts_t fnc, int ret, int arg1
|
||||
void call_n(dynarec_arm_t* dyn, int ninst, void* fnc, int w)
|
||||
{
|
||||
MAYUSE(fnc);
|
||||
dyn->insts[ninst].host_call = 1;
|
||||
dyn->insts[ninst].host_call_clobber = 1;
|
||||
CHECK_DFNONE(1);
|
||||
#if STEP == 0
|
||||
dyn->insts[ninst].nat_flags_op = NAT_FLAG_OP_UNUSABLE;
|
||||
@@ -1156,6 +1202,11 @@ int x87_get_cache(dynarec_arm_t* dyn, int ninst, int populate, int s1, int s2, i
|
||||
for (int i=0; (i<8) && (ret==-1); ++i)
|
||||
if(dyn->n.x87cache[i]==-1)
|
||||
ret = i;
|
||||
if(ret==-1) {
|
||||
MESSAGE(LOG_DUMP, "Incoherent x87 stack cache, aborting\n");
|
||||
dyn->abort = 1;
|
||||
return -1;
|
||||
}
|
||||
// found, setup and grab the value
|
||||
dyn->n.x87cache[ret] = st;
|
||||
dyn->n.x87reg[ret] = fpu_get_reg_x87(dyn, ninst, NEON_CACHE_ST_D, st);
|
||||
@@ -1284,6 +1335,11 @@ void x87_reget_st(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st)
|
||||
for (int i=0; (i<8) && (ret==-1); ++i)
|
||||
if(dyn->n.x87cache[i]==-1)
|
||||
ret = i;
|
||||
if(ret==-1) {
|
||||
MESSAGE(LOG_DUMP, "Incoherent x87 stack cache, aborting\n");
|
||||
dyn->abort = 1;
|
||||
return;
|
||||
}
|
||||
// found, setup and grab the value
|
||||
dyn->n.x87cache[ret] = st;
|
||||
dyn->n.x87reg[ret] = fpu_get_reg_x87(dyn, ninst, NEON_CACHE_ST_D, st);
|
||||
@@ -1437,7 +1493,7 @@ static int isx87Empty(dynarec_arm_t* dyn)
|
||||
int mmx_get_reg(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int a)
|
||||
{
|
||||
dyn->insts[ninst].mmx_used = 1;
|
||||
if(!dyn->n.x87stack && isx87Empty(dyn))
|
||||
if(dyn->n.x87stack || !isx87Empty(dyn))
|
||||
x87_purgecache(dyn, ninst, 0, s1, s2, s3);
|
||||
if(dyn->n.mmxcache[a]!=-1)
|
||||
return dyn->n.mmxcache[a];
|
||||
@@ -1450,7 +1506,7 @@ int mmx_get_reg(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int a)
|
||||
int mmx_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int a)
|
||||
{
|
||||
dyn->insts[ninst].mmx_used = 1;
|
||||
if(!dyn->n.x87stack && isx87Empty(dyn))
|
||||
if(dyn->n.x87stack || !isx87Empty(dyn))
|
||||
x87_purgecache(dyn, ninst, 0, s1, s2, s3);
|
||||
if(dyn->n.mmxcache[a]!=-1)
|
||||
return dyn->n.mmxcache[a];
|
||||
@@ -1521,8 +1577,9 @@ int sse_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int a)
|
||||
dyn->n.xmm_used |= 1<<a;
|
||||
return dyn->n.ssecache[a].reg;
|
||||
}
|
||||
if(!(dyn->n.xmm_used&(1<<a)))
|
||||
dyn->n.xmm_unneeded |= 1<<a;
|
||||
dyn->n.xmm_used |= 1<<a;
|
||||
dyn->n.xmm_unneeded |= 1<<a;
|
||||
dyn->n.ssecache[a].reg = fpu_get_reg_xmm(dyn, NEON_CACHE_XMMW, a);
|
||||
dyn->n.ssecache[a].write = 1; // it will be write...
|
||||
return dyn->n.ssecache[a].reg;
|
||||
@@ -1531,10 +1588,13 @@ int sse_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int a)
|
||||
void sse_forget_reg(dynarec_arm_t* dyn, int ninst, int a)
|
||||
{
|
||||
dyn->n.xmm_used |= 1<<a;
|
||||
if(dyn->n.ssecache[a].v==-1)
|
||||
return;
|
||||
if(dyn->n.neoncache[dyn->n.ssecache[a].reg].t == NEON_CACHE_XMMW) {
|
||||
VSTR128_U12(dyn->n.ssecache[a].reg, xEmu, offsetof(x64emu_t, xmm[a]));
|
||||
dyn->n.ymm_used |= 1<<a;
|
||||
if(dyn->n.ssecache[a].v!=-1) {
|
||||
if(dyn->n.neoncache[dyn->n.ssecache[a].reg].t == NEON_CACHE_XMMW) {
|
||||
VSTR128_U12(dyn->n.ssecache[a].reg, xEmu, offsetof(x64emu_t, xmm[a]));
|
||||
}
|
||||
fpu_free_reg(dyn, dyn->n.ssecache[a].reg);
|
||||
dyn->n.ssecache[a].v = -1;
|
||||
}
|
||||
// YMM part too
|
||||
if(is_avx_zero_unset(dyn, ninst, a)) {
|
||||
@@ -1552,9 +1612,6 @@ void sse_forget_reg(dynarec_arm_t* dyn, int ninst, int a)
|
||||
fpu_free_reg(dyn, i);
|
||||
|
||||
}
|
||||
fpu_free_reg(dyn, dyn->n.ssecache[a].reg);
|
||||
dyn->n.ssecache[a].v = -1;
|
||||
return;
|
||||
}
|
||||
// purge the SSE cache for XMM0..XMM7 (to use before function native call)
|
||||
void sse_purge07cache(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
@@ -1626,7 +1683,7 @@ static void sse_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1, uint
|
||||
if(!next && (dyn->n.neoncache[i].t==NEON_CACHE_YMMW || dyn->n.neoncache[i].t==NEON_CACHE_YMMR))
|
||||
dyn->n.neoncache[i].v = 0;
|
||||
if(next && (dyn->n.neoncache[i].t==NEON_CACHE_YMMW || dyn->n.neoncache[i].t==NEON_CACHE_YMMR))
|
||||
dyn->n.xmm_used |= (1<<dyn->n.neoncache[i].n);
|
||||
dyn->n.ymm_used |= (1<<dyn->n.neoncache[i].n);
|
||||
}
|
||||
// All done
|
||||
if(old!=-1) {
|
||||
@@ -1634,36 +1691,6 @@ static void sse_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1, uint
|
||||
}
|
||||
}
|
||||
|
||||
static void sse_reflectcache(dynarec_arm_t* dyn, int ninst, int s1)
|
||||
{
|
||||
for (int i=0; i<16; ++i) {
|
||||
if(dyn->n.ssecache[i].v!=-1) {
|
||||
dyn->n.xmm_used |= 1<<i;
|
||||
if(dyn->n.ssecache[i].write) {
|
||||
VSTR128_U12(dyn->n.ssecache[i].reg, xEmu, offsetof(x64emu_t, xmm[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
//AVX
|
||||
if(dyn->ymm_zero) {
|
||||
int s1_set = 0;
|
||||
for(int i=0; i<16; ++i)
|
||||
if(is_avx_zero(dyn, ninst, i)) {
|
||||
if(!s1_set) {
|
||||
ADDx_U12(s1, xEmu, offsetof(x64emu_t, ymm[0]));
|
||||
s1_set = 1;
|
||||
}
|
||||
STPx_S7_offset(xZR, xZR, s1, i*16);
|
||||
}
|
||||
}
|
||||
for(int i=0; i<32; ++i) {
|
||||
if(dyn->n.neoncache[i].t == NEON_CACHE_YMMW)
|
||||
VSTR128_U12(i, xEmu, offsetof(x64emu_t, ymm[dyn->n.neoncache[i].n]));
|
||||
if((dyn->n.neoncache[i].t == NEON_CACHE_YMMW) || (dyn->n.neoncache[i].t == NEON_CACHE_YMMR))
|
||||
dyn->n.xmm_used |= 1<<dyn->n.neoncache[i].n;
|
||||
}
|
||||
}
|
||||
|
||||
void sse_reflect_reg(dynarec_arm_t* dyn, int ninst, int a)
|
||||
{
|
||||
dyn->n.xmm_used |= 1<<a;
|
||||
@@ -2128,19 +2155,23 @@ static void fpuCacheTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2, int
|
||||
int i2 = dyn->insts[ninst].x64.jmp_insts;
|
||||
if(i2<0)
|
||||
return;
|
||||
MESSAGE(LOG_DUMP, "\tCache Transform ---- ninst=%d -> %d\n", ninst, i2);
|
||||
MESSAGE(LOG_DUMP, "\tFPU Cache Transform ---- ninst=%d -> %d\n", ninst, i2);
|
||||
uint32_t unneeded = dyn->insts[i2].n.xmm_unneeded | (dyn->insts[i2].n.ymm_unneeded<<16);
|
||||
if((!i2) || (dyn->insts[i2].x64.barrier&BARRIER_FLOAT)) {
|
||||
if(dyn->insts[i2].preload_host_call)
|
||||
unneeded &= ~dyn->insts[i2].preload_xmmymm;
|
||||
int need_purge = 0;
|
||||
if(dyn->n.stack_next)
|
||||
need_purge = 1;
|
||||
for(int i=0; i<24 && !need_purge; ++i)
|
||||
for(int i=0; i<32 && !need_purge; ++i)
|
||||
if(dyn->n.neoncache[i].v)
|
||||
need_purge = 1;
|
||||
if(dyn->ymm_zero)
|
||||
need_purge = 1;
|
||||
if(need_purge) { // there is something at ninst for i
|
||||
fpu_purgecache(dyn, ninst, 1, s1, s2, s3, unneeded);
|
||||
}
|
||||
MESSAGE(LOG_DUMP, "\t---- Cache Transform\n");
|
||||
MESSAGE(LOG_DUMP, "\t---- FPU Cache Transform (purge)\n");
|
||||
return;
|
||||
}
|
||||
neoncache_t cache_i2 = dyn->insts[i2].n;
|
||||
@@ -2167,7 +2198,7 @@ static void fpuCacheTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2, int
|
||||
purge = 0;
|
||||
if(purge) {
|
||||
fpu_purgecache(dyn, ninst, 1, s1, s2, s3, unneeded);
|
||||
MESSAGE(LOG_DUMP, "\t---- Cache Transform\n");
|
||||
MESSAGE(LOG_DUMP, "\t---- FPU Cache Transform (purge)\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -2242,8 +2273,9 @@ static void fpuCacheTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2, int
|
||||
cache.neoncache[i].t = NEON_CACHE_ST_I64;
|
||||
} else if(cache.neoncache[i].t == NEON_CACHE_ST_F && cache_i2.neoncache[i].t == NEON_CACHE_ST_I64) {
|
||||
MESSAGE(LOG_DUMP, "\t - Convert %s\n", getCacheName(cache.neoncache[i].t, cache.neoncache[i].n));
|
||||
VFCVTZSQS(i, i);
|
||||
cache.neoncache[i].t = NEON_CACHE_ST_D;
|
||||
FCVT_D_S(i, i);
|
||||
VFCVTZSQD(i, i);
|
||||
cache.neoncache[i].t = NEON_CACHE_ST_I64;
|
||||
} else if(cache.neoncache[i].t == NEON_CACHE_ST_I64 && cache_i2.neoncache[i].t == NEON_CACHE_ST_F) {
|
||||
MESSAGE(LOG_DUMP, "\t - Convert %s\n", getCacheName(cache.neoncache[i].t, cache.neoncache[i].n));
|
||||
SCVTFDD(i, i);
|
||||
@@ -2271,9 +2303,9 @@ static void fpuCacheTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2, int
|
||||
}
|
||||
}
|
||||
}
|
||||
if(stack_cnt != cache_i2.stack) {
|
||||
MESSAGE(LOG_DUMP, "\t - adjust stack count %d -> %d -\n", stack_cnt, cache_i2.stack);
|
||||
int a = stack_cnt - cache_i2.stack;
|
||||
if(stack_cnt != cache_i2.stack || dyn->n.x87stack != cache_i2.x87stack) {
|
||||
MESSAGE(LOG_DUMP, "\t - adjust stack count %d -> %d / pending %d -> %d -\n", stack_cnt, cache_i2.stack, dyn->n.x87stack, cache_i2.x87stack);
|
||||
int a = dyn->n.x87stack - cache_i2.x87stack;
|
||||
// Add x87stack to emu fpu_stack
|
||||
LDRw_U12(s3, xEmu, offsetof(x64emu_t, fpu_stack));
|
||||
if(a>0) {
|
||||
@@ -2311,7 +2343,7 @@ static void flagsCacheTransform(dynarec_arm_t* dyn, int ninst)
|
||||
int jmp = dyn->insts[ninst].x64.jmp_insts;
|
||||
if(jmp<0)
|
||||
return;
|
||||
if(dyn->insts[jmp].f_exit==dyn->insts[jmp].f_entry) // flags will be fully known, nothing we can do more
|
||||
if(dyn->insts[ninst].f_exit==dyn->insts[jmp].f_entry) // flags will be fully known, nothing we can do more
|
||||
return;
|
||||
if(dyn->insts[jmp].df_notneeded)
|
||||
return;
|
||||
@@ -2347,12 +2379,25 @@ static void flagsCacheTransform(dynarec_arm_t* dyn, int ninst)
|
||||
j64 = (GETMARKF2)-(dyn->native_size);
|
||||
CBZw(x1, j64);
|
||||
}
|
||||
if(dyn->insts[ninst].need_nat_flags)
|
||||
if(dyn->insts[ninst].need_nat_flags) {
|
||||
#ifdef BOX64EC
|
||||
// updateflags uses x1 to x5 and x6 is guest R9: NZCV goes through the emu
|
||||
MRS_nzcv(x1);
|
||||
STRx_U12(x1, xEmu, offsetof(x64emu_t, scratch[0]));
|
||||
#else
|
||||
MRS_nzcv(x6);
|
||||
#endif
|
||||
}
|
||||
TABLE64C(x1, const_updateflags_arm64);
|
||||
BLR(x1);
|
||||
if(dyn->insts[ninst].need_nat_flags)
|
||||
if(dyn->insts[ninst].need_nat_flags) {
|
||||
#ifdef BOX64EC
|
||||
LDRx_U12(x1, xEmu, offsetof(x64emu_t, scratch[0]));
|
||||
MSR_nzcv(x1);
|
||||
#else
|
||||
MSR_nzcv(x6);
|
||||
#endif
|
||||
}
|
||||
MARKF2;
|
||||
}
|
||||
MESSAGE(LOG_DUMP, "\t---- Flags fetch\n");
|
||||
@@ -2439,7 +2484,7 @@ static void nativeFlagsTransform(dynarec_arm_t* dyn, int ninst, int s1, int s2)
|
||||
EORx_mask(s2, s2, 1, 35, 0); //mask=1<<NZCV_C
|
||||
}
|
||||
}
|
||||
#undef GL_MRS
|
||||
#undef GO_MRS
|
||||
if(mrs) MSR_nzcv(s2);
|
||||
|
||||
MESSAGE(LOG_DUMP, "\t---- Native Flags transform\n");
|
||||
@@ -2455,47 +2500,59 @@ void CacheTransform(dynarec_arm_t* dyn, int ninst, int cacheupd) {
|
||||
nativeFlagsTransform(dyn, ninst, x1, x2);
|
||||
}
|
||||
|
||||
static void flush_native_flags(dynarec_arm_t* dyn, int ninst, int s1, uint8_t flags, uint8_t ic)
|
||||
{
|
||||
// some flags disapear, and need to be saved
|
||||
MESSAGE(LOG_DUMP, "\tPurging native flags %hhx\n", flags);
|
||||
if(flags&NF_EQ) {
|
||||
CSETw(s1, cEQ);
|
||||
BFIw(xFlags, s1, F_ZF, 1);
|
||||
}
|
||||
if(flags&NF_SF) {
|
||||
CSETw(s1, cMI);
|
||||
BFIw(xFlags, s1, F_SF, 1);
|
||||
}
|
||||
if(flags&NF_VF) {
|
||||
CSETw(s1, cVS);
|
||||
BFIw(xFlags, s1, F_OF, 1);
|
||||
}
|
||||
if(flags&NF_PF_V) {
|
||||
CSETw(s1, cVS);
|
||||
BFIw(xFlags, s1, F_PF, 1);
|
||||
}
|
||||
if(flags&NF_CF) {
|
||||
if(ic) // might need to invert carry
|
||||
CSETw(s1, cCS);
|
||||
else
|
||||
CSETw(s1, cCC);
|
||||
BFIw(xFlags, s1, F_CF, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void additionnal_checks(dynarec_arm_t* dyn, int ninst)
|
||||
{
|
||||
int s1 = x1;
|
||||
// check if a opcode generate partial flags that may clober existing native flags and see need to be "moved" to xFlags
|
||||
if(dyn->insts[ninst].nat_flags_op || dyn->insts[ninst].nat_flags_op_before) {
|
||||
uint8_t nat_flags = dyn->insts[ninst].need_nat_flags; // that's the native flags that will be generated
|
||||
if(dyn->insts[ninst].nat_flags_op || dyn->insts[ninst].nat_flags_op_before || (dyn->insts[ninst].nat_flags_in!=dyn->insts[ninst].need_nat_flags)) {
|
||||
uint8_t nat_flags_gen = dyn->insts[ninst].set_nat_flags;
|
||||
//TODO: does it need to fetch previous state with getPred?
|
||||
uint8_t nat_flags_before = dyn->insts[ninst].before_nat_flags; //flags before the opcode, but it's only there when opcode also consume natflags
|
||||
uint8_t nat_flags_before = dyn->insts[ninst].nat_flags_in; //flags before the opcode
|
||||
uint8_t nat_flags_flush = nat_flags_before&~nat_flags_gen; // flags present before bu not after the operation and so that needs to be spared
|
||||
if(nat_flags_before && nat_flags_flush) {
|
||||
// some flags disapear, and need to be saved
|
||||
MESSAGE(LOG_DUMP, "\tPurging native flags %hhx\n", nat_flags_flush);
|
||||
uint8_t nc_before = dyn->insts[ninst].normal_carry;
|
||||
if(nat_flags_flush&NF_EQ) {
|
||||
CSETw(s1, cEQ);
|
||||
BFIw(xFlags, s1, F_ZF, 1);
|
||||
}
|
||||
if(nat_flags_flush&NF_SF) {
|
||||
CSETw(s1, cMI);
|
||||
BFIw(xFlags, s1, F_SF, 1);
|
||||
}
|
||||
if(nat_flags_flush&NF_VF) {
|
||||
CSETw(s1, cVS);
|
||||
BFIw(xFlags, s1, F_OF, 1);
|
||||
}
|
||||
if(nat_flags_flush&NF_PF_V) {
|
||||
CSETw(s1, cVS);
|
||||
BFIw(xFlags, s1, F_PF, 1);
|
||||
}
|
||||
if(nat_flags_flush&NF_CF) {
|
||||
if(nc_before) // might need to invert carry
|
||||
CSETw(s1, cCS);
|
||||
else
|
||||
CSETw(s1, cCC);
|
||||
BFIw(xFlags, s1, F_CF, 1);
|
||||
}
|
||||
}
|
||||
if(nat_flags_before && nat_flags_flush)
|
||||
flush_native_flags(dyn, ninst, s1, nat_flags_flush, dyn->insts[ninst].normal_carry_in);
|
||||
}
|
||||
}
|
||||
|
||||
void flushNative(dynarec_arm_t* dyn, int ninst)
|
||||
{
|
||||
int s1 = x1;
|
||||
uint8_t nat_flags = dyn->insts[ninst].need_nat_flags; // that's the native flags that is needed after
|
||||
uint8_t nat_flags_before = dyn->insts[ninst].nat_flags_in; //flags before the opcode
|
||||
uint8_t nat_flags_flush = nat_flags_before&~nat_flags; // flags present before bu not after the operation and so that needs to be spared
|
||||
if(nat_flags_flush)
|
||||
flush_native_flags(dyn, ninst, s1, nat_flags_flush, dyn->insts[ninst].normal_carry_in);
|
||||
}
|
||||
|
||||
void fpu_reflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
{
|
||||
x87_reflectcache(dyn, ninst, s1, s2, s3);
|
||||
@@ -2618,7 +2675,7 @@ void fpu_reset_cache(dynarec_arm_t* dyn, int ninst, int reset_n)
|
||||
dyn->ymm_zero = dyn->insts[reset_n].ymm0_out;
|
||||
#endif
|
||||
#if STEP == 0
|
||||
if(dyn->need_dump && dyn->n.x87stack) dynarec_log(LOG_NONE, "New x87stack=%d at ResetCache in inst %d with %d\n", dyn->n.x87stack, ninst, reset_n);
|
||||
if(dyn->need_dump && dyn->need_dump != 3 && dyn->n.x87stack) dynarec_log(LOG_NONE, "New x87stack=%d at ResetCache in inst %d with %d\n", dyn->n.x87stack, ninst, reset_n);
|
||||
#endif
|
||||
#if defined(HAVE_TRACE) && (STEP>2)
|
||||
if(dyn->need_dump && 0) //disable for now, need more work
|
||||
@@ -2800,7 +2857,8 @@ int fpu_get_reg_ymm(dynarec_arm_t* dyn, int ninst, int t, int ymm, int k1, int k
|
||||
}
|
||||
#endif
|
||||
printf_log(LOG_NONE, "BOX64 Dynarec: Error, unable to free a reg for YMM %d at inst=%d on pass %d\n", ymm, ninst, STEP);
|
||||
return i;
|
||||
dyn->abort = 1;
|
||||
return SCRATCH0;
|
||||
}
|
||||
|
||||
// Get an XMM quad reg and preload it (or do nothing if not possible)
|
||||
@@ -2865,10 +2923,6 @@ void doEnterBlock(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
STLXRw(s3, s2, s1);
|
||||
CBNZw(s3, -3*4);
|
||||
}
|
||||
// set tick
|
||||
LDRx_U12(s2, xEmu, offsetof(x64emu_t, context));
|
||||
LDRw_U12(s2, s2, offsetof(box64context_t, tick));
|
||||
STRw_U12(s2, s1, offsetof(dynablock_t, tick)-offsetof(dynablock_t, in_used));
|
||||
MESSAGE(LOG_INFO, "-------- doEnter\n");
|
||||
}
|
||||
void doLeaveBlock(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3)
|
||||
@@ -2968,8 +3022,8 @@ void checkCRC(dynarec_arm_t* dyn, int ninst)
|
||||
// grab the dynablock address in x5, as this on will not be erased by crc functions
|
||||
int delta = -(dyn->native_size + sizeof(void*));
|
||||
LDRx_literal(x5, delta);
|
||||
// move away xEMU to X6, should be safe there
|
||||
MOVx_REG(x6, xEmu);
|
||||
// move away xEMU to the stack, x6 is guest R9 on Box64EC
|
||||
STPx_S7_preindex(xEmu, xZR, xSP, -16);
|
||||
// prepare and call the crc function
|
||||
TABLE64C(x3, cpuext.crc32?const_native_crc32:const_native_x31);
|
||||
LDRx_U12(xEmu, x5, offsetof(dynablock_t, x64_addr));
|
||||
@@ -2977,10 +3031,14 @@ void checkCRC(dynarec_arm_t* dyn, int ninst)
|
||||
BLR(x3);
|
||||
// done, move away result and restore xEmu
|
||||
MOVw_REG(x1, xEmu);
|
||||
MOVx_REG(xEmu, x6);
|
||||
LDPx_S7_postindex(xEmu, xZR, xSP, 16);
|
||||
LDRw_U12(x2, x5, offsetof(dynablock_t, hash));
|
||||
SUBw_REG(x1, x1, x2);
|
||||
CBZw(x1, 4+2*4);
|
||||
TABLE64C(x3, const_native_next_invalidate);
|
||||
BLR(x3);
|
||||
#ifdef BOX64EC
|
||||
// x5 held the dynablock, which is x87pc here
|
||||
NATIVE_RESTORE_X87PC();
|
||||
#endif
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#ifndef __DYNAREC_ARM64_HELPER_H__
|
||||
#define __DYNAREC_ARM64_HELPER_H__
|
||||
|
||||
@@ -39,6 +40,9 @@
|
||||
#ifndef FEMIT
|
||||
#define FEMIT(A) EMIT(A)
|
||||
#endif
|
||||
#ifndef LEMIT
|
||||
#define LEMIT(A) EMIT(A)
|
||||
#endif
|
||||
#ifndef ENDPREFIX
|
||||
#define ENDPREFIX
|
||||
#endif
|
||||
@@ -83,7 +87,7 @@
|
||||
}
|
||||
#define GETEDw(D) \
|
||||
if (MODREG) { \
|
||||
ed = xEAX + (nextop & 7) + (rex.b << 3); \
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3)); \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
@@ -132,7 +136,7 @@
|
||||
#define WBACKx if(wback) {STx(ed, wback, fixedaddress); SMWRITE();}
|
||||
// Write back ed in wback (if wback not 0)
|
||||
#define WBACKw if(wback) {STW(ed, wback, fixedaddress); SMWRITE();}
|
||||
//FAKEELike GETED, but doesn't get anything
|
||||
//FAKEED like GETED, but doesn't get anything
|
||||
#define FAKEED \
|
||||
if (MODREG) { \
|
||||
ed = TO_NAT((nextop & 7) + (rex.b << 3)); \
|
||||
@@ -167,7 +171,7 @@
|
||||
ed = i; \
|
||||
wb1 = 1; \
|
||||
}
|
||||
//Compute wback for MDREG only, no fetching
|
||||
//Compute wback for MODREG only, no fetching
|
||||
#define CALCEW() \
|
||||
wback = TO_NAT((nextop & 7) + (rex.b << 3)); \
|
||||
//GETEW will use i for ed, and can use r3 for wback.
|
||||
@@ -184,20 +188,6 @@
|
||||
ed = i; \
|
||||
wb1 = 1; \
|
||||
}
|
||||
//GETEW will use i for ed, and can use r3 for wback.
|
||||
#define GETEW32(i, D) \
|
||||
if (MODREG) { \
|
||||
wback = TO_NAT((nextop & 7) + (rex.b << 3)); \
|
||||
UXTHw(i, wback); \
|
||||
ed = i; \
|
||||
wb1 = 0; \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
addr = geted32(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff << 1, (1 << 1) - 1, rex, NULL, 0, D); \
|
||||
LDH(i, wback, fixedaddress); \
|
||||
ed = i; \
|
||||
wb1 = 1; \
|
||||
}
|
||||
//GETSEW will use i for ed, and can use r3 for wback. This is the Signed version
|
||||
#define GETSEW(i, D) \
|
||||
if (MODREG) { \
|
||||
@@ -270,27 +260,6 @@
|
||||
wb1 = 1; \
|
||||
ed = i; \
|
||||
}
|
||||
//GETEB will use i for ed, and can use r3 for wback.
|
||||
#define GETEB32(i, D) \
|
||||
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); \
|
||||
} \
|
||||
UBFXx(i, wback, wb2, 8); \
|
||||
wb1 = 0; \
|
||||
ed = i; \
|
||||
} else { \
|
||||
SMREAD(); \
|
||||
addr = geted32(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, &unscaled, 0xfff, 0, rex, NULL, 0, D); \
|
||||
LDB(i, wback, fixedaddress); \
|
||||
wb1 = 1; \
|
||||
ed = i; \
|
||||
}
|
||||
// Write eb (ed) back to original register / memory
|
||||
#define EBBACK if(wb1) {STB(ed, wback, fixedaddress); SMWRITE();} else {BFIx(wback, ed, wb2, 8);}
|
||||
// no fetch version of GETGB
|
||||
@@ -334,6 +303,14 @@
|
||||
#define GETG gd = ((nextop&0x38)>>3)+(rex.r<<3)
|
||||
|
||||
// Get GX as a quad (might use x1)
|
||||
// mark an XMM reg as accessed scalar-only (upper-64 untouched) in this opcode
|
||||
#define MARK_XMM_SCALAR(a) dyn->n.xmm_scalar |= (1 << (a))
|
||||
// test if the upper-64 of an XMM reg is proven dead in this opcode
|
||||
#define XMMH_UNNEEDED(a) (dyn->insts[ninst].n.xmmh_unneeded & (1 << (a)))
|
||||
// mark an XMM reg as accessed scalar-single (only low-32 touched, upper-96 untouched)
|
||||
#define MARK_XMM_SCALAR_SINGLE(a) ((dyn->n.xmm_scalar |= (1 << (a))), (dyn->n.xmm_scalar_single |= (1 << (a))))
|
||||
// test if the upper-96 of an XMM reg is proven dead in this opcode
|
||||
#define XMMS_UNNEEDED(a) (dyn->insts[ninst].n.xmms_unneeded & (1 << (a)))
|
||||
#define GETGX(a, w) \
|
||||
gd = ((nextop&0x38)>>3)+(rex.r<<3); \
|
||||
a = sse_get_reg(dyn, ninst, x1, gd, w)
|
||||
@@ -498,7 +475,7 @@
|
||||
a = fpu_get_scratch(dyn, ninst); \
|
||||
VLDR128_U12(a, ed, fixedaddress); \
|
||||
}
|
||||
// Get EX as a quad, (x3 is used)
|
||||
// Get EX as a quad but don't load anything, just reserve an empty reg (x3 is used)
|
||||
#define GETEX_empty_Y(a, D) \
|
||||
if(MODREG) { \
|
||||
a = sse_get_reg_empty(dyn, ninst, x3, (nextop&7)+(rex.b<<3)); \
|
||||
@@ -589,7 +566,7 @@
|
||||
SMWRITE2(); \
|
||||
}
|
||||
|
||||
#define YMM0(a) ymm_mark_zero(dyn, ninst, a);
|
||||
#define YMM0(a) ymm_mark_zero(dyn, ninst, a)
|
||||
|
||||
// Get Direction with size Z and based of F_DF flag, on register r ready for LDR/STR fetching
|
||||
// F_DF is 1<<10, so 1 ROR 11*2 (so F_OF)
|
||||
@@ -601,15 +578,15 @@
|
||||
#define ALIGNED_ATOMICxw ((fixedaddress && !(fixedaddress&(((1<<(2+rex.w))-1)))) || BOX64ENV(dynarec_aligned_atomics))
|
||||
#define ALIGNED_ATOMICH ((fixedaddress && !(fixedaddress&1)) || BOX64ENV(dynarec_aligned_atomics))
|
||||
|
||||
// CALL will use x7 for the call address. Return value can be put in ret (unless ret is -1)
|
||||
// CALL will use xLR for the call address. Return value can be put in ret (unless ret is -1)
|
||||
// R0 will not be pushed/popd if ret is -2
|
||||
#define CALL(F, ret) call_c(dyn, ninst, F, x87pc, ret, 1, 0)
|
||||
// CALL_ will use x7 for the call address. Return value can be put in ret (unless ret is -1)
|
||||
#define CALL(F, ret) call_c(dyn, ninst, F, xLR, ret, 1, 0)
|
||||
// CALL_ will use xLR for the call address. Return value can be put in ret (unless ret is -1)
|
||||
// R0 will not be pushed/popd if ret is -2
|
||||
#define CALL_(F, ret, reg) call_c(dyn, ninst, F, x87pc, ret, 1, reg)
|
||||
// CALL_S will use x7 for the call address. Return value can be put in ret (unless ret is -1)
|
||||
#define CALL_(F, ret, reg) call_c(dyn, ninst, F, xLR, ret, 1, reg)
|
||||
// CALL_S will use xLR for the call address. Return value can be put in ret (unless ret is -1)
|
||||
// R0 will not be pushed/popd if ret is -2. Flags are not save/restored
|
||||
#define CALL_S(F, ret) call_c(dyn, ninst, F, x87pc, ret, 0, 0)
|
||||
#define CALL_S(F, ret) call_c(dyn, ninst, F, xLR, ret, 0, 0)
|
||||
// CALL_D will use x7 for the call address. Use for function having 1 or 2 double args and returning 1 double
|
||||
// All regs are saved, including xmm0-7, will move arg1/arg2 to D0, D1, return D0 to ret (unless any is -1)
|
||||
#define CALL_D(F, ret, arg1, arg2, sav1, sav2) call_d(dyn, ninst, F, ret, arg1, arg2, sav1, sav2)
|
||||
@@ -627,6 +604,26 @@
|
||||
#define MARKSEG dyn->insts[ninst].markseg = dyn->native_size
|
||||
#define GETMARKSEG dyn->insts[ninst].markseg
|
||||
#define MARKLOCK dyn->insts[ninst].marklock = dyn->native_size
|
||||
#ifdef BOX64EC
|
||||
// x6 is guest R9 and x87pc is x5, so keep the flags in the emu across the retry loop
|
||||
#define MARKLOCK_SAVE_FLAGS() do { \
|
||||
STRx_U12(xFlags, xEmu, offsetof(x64emu_t, eflags)); \
|
||||
MRS_nzcv(x4); \
|
||||
STRx_U12(x4, xEmu, offsetof(x64emu_t, scratch[0])); \
|
||||
MARKLOCK; \
|
||||
LDRx_U12(xFlags, xEmu, offsetof(x64emu_t, eflags)); \
|
||||
LDRx_U12(x4, xEmu, offsetof(x64emu_t, scratch[0])); \
|
||||
MSR_nzcv(x4); \
|
||||
} while (0)
|
||||
#else
|
||||
#define MARKLOCK_SAVE_FLAGS() do { \
|
||||
MOVx_REG(x6, xFlags); \
|
||||
MRS_nzcv(x87pc); \
|
||||
MARKLOCK; \
|
||||
MOVx_REG(xFlags, x6); \
|
||||
MSR_nzcv(x87pc); \
|
||||
} while (0)
|
||||
#endif
|
||||
#define GETMARKLOCK dyn->insts[ninst].marklock
|
||||
|
||||
// Branch to MARK if cond (use j64)
|
||||
@@ -700,7 +697,7 @@
|
||||
#define B_MARK3(cond) \
|
||||
j64 = GETMARK3-(dyn->native_size); \
|
||||
Bcond(cond, j64)
|
||||
// Test bit N of A and branch to MARK3 if not set
|
||||
// Test bit N of A and branch to MARK2 if not set
|
||||
#define TBZ_MARK2(A, N) \
|
||||
j64 = GETMARK2-(dyn->native_size); \
|
||||
TBZ(A, N, j64)
|
||||
@@ -880,6 +877,56 @@
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef X87_ARITH_NAN_START_D
|
||||
#define X87_ARITH_NAN_START_D(va, vb, tmp) \
|
||||
FMAXD(tmp, va, vb); \
|
||||
FCMEQD(tmp, tmp, tmp)
|
||||
#endif
|
||||
|
||||
#ifndef X87_ARITH_NAN_END_D
|
||||
#define X87_ARITH_NAN_END_D(vres, vb, tmp, tmp2) \
|
||||
FCMEQD(tmp2, vres, vres); \
|
||||
VBIC(tmp2, tmp, tmp2); \
|
||||
VSHLQ_64(tmp2, tmp2, 63); \
|
||||
VORR(vres, vres, tmp2); \
|
||||
VSSHRQ_64(tmp2, vres, 63); \
|
||||
FCMEQD(tmp, vres, vres); \
|
||||
VMVNQ(tmp, tmp); \
|
||||
VANDQ(tmp, tmp, tmp2); \
|
||||
VSSHRQ_64(tmp2, vb, 63); \
|
||||
VMVNQ(tmp2, tmp2); \
|
||||
VANDQ(tmp, tmp, tmp2); \
|
||||
FCMEQD(tmp2, vb, vb); \
|
||||
VMVNQ(tmp2, tmp2); \
|
||||
VANDQ(tmp, tmp, tmp2); \
|
||||
VBIT(vres, vb, tmp)
|
||||
#endif
|
||||
|
||||
#ifndef X87_ARITH_NAN_START_S
|
||||
#define X87_ARITH_NAN_START_S(va, vb, tmp) \
|
||||
FMAXS(tmp, va, vb); \
|
||||
FCMEQS(tmp, tmp, tmp)
|
||||
#endif
|
||||
|
||||
#ifndef X87_ARITH_NAN_END_S
|
||||
#define X87_ARITH_NAN_END_S(vres, vb, tmp, tmp2) \
|
||||
FCMEQS(tmp2, vres, vres); \
|
||||
VBIC(tmp2, tmp, tmp2); \
|
||||
VSHL_32(tmp2, tmp2, 31); \
|
||||
VORR(vres, vres, tmp2); \
|
||||
VSSHR_32(tmp2, vres, 31); \
|
||||
FCMEQS(tmp, vres, vres); \
|
||||
VMVNQ(tmp, tmp); \
|
||||
VANDQ(tmp, tmp, tmp2); \
|
||||
VSSHR_32(tmp2, vb, 31); \
|
||||
VMVNQ(tmp2, tmp2); \
|
||||
VANDQ(tmp, tmp, tmp2); \
|
||||
FCMEQS(tmp2, vb, vb); \
|
||||
VMVNQ(tmp2, tmp2); \
|
||||
VANDQ(tmp, tmp, tmp2); \
|
||||
VBIT(vres, vb, tmp)
|
||||
#endif
|
||||
|
||||
#define STORE_REG(A) STRx_U12(x##A, xEmu, offsetof(x64emu_t, regs[_##A]))
|
||||
#define STP_REGS(A, B) STPx_S7_offset(x##A, x##B, xEmu, offsetof(x64emu_t, regs[_##A]))
|
||||
#define LDP_REGS(A, B) LDPx_S7_offset(x##A, x##B, xEmu, offsetof(x64emu_t, regs[_##A]))
|
||||
@@ -957,7 +1004,7 @@
|
||||
#else
|
||||
#define X87_PUSH_OR_FAIL(var, dyn, ninst, scratch, t) \
|
||||
if ((dyn->n.x87stack==8) || (dyn->n.pushed==8)) { \
|
||||
if(dyn->need_dump) dynarec_log(LOG_NONE, " Warning, suspicious x87 Push, stack=%d/%d on inst %d\n", dyn->n.x87stack, dyn->n.pushed, ninst); \
|
||||
if(dyn->need_dump && dyn->need_dump != 3) dynarec_log(LOG_NONE, " Warning, suspicious x87 Push, stack=%d/%d on inst %d\n", dyn->n.x87stack, dyn->n.pushed, ninst); \
|
||||
dyn->abort = 1; \
|
||||
return addr; \
|
||||
} \
|
||||
@@ -965,7 +1012,7 @@
|
||||
|
||||
#define X87_PUSH_EMPTY_OR_FAIL(dyn, ninst, scratch) \
|
||||
if ((dyn->n.x87stack==8) || (dyn->n.pushed==8)) { \
|
||||
if(dyn->need_dump) dynarec_log(LOG_NONE, " Warning, suspicious x87 Push, stack=%d/%d on inst %d\n", dyn->n.x87stack, dyn->n.pushed, ninst); \
|
||||
if(dyn->need_dump && dyn->need_dump != 3) dynarec_log(LOG_NONE, " Warning, suspicious x87 Push, stack=%d/%d on inst %d\n", dyn->n.x87stack, dyn->n.pushed, ninst); \
|
||||
dyn->abort = 1; \
|
||||
return addr; \
|
||||
} \
|
||||
@@ -973,7 +1020,7 @@
|
||||
|
||||
#define X87_POP_OR_FAIL(dyn, ninst, scratch) \
|
||||
if ((dyn->n.x87stack==-8) || (dyn->n.poped==8)) { \
|
||||
if(dyn->need_dump) dynarec_log(LOG_NONE, " Warning, suspicious x87 Pop, stack=%d/%d on inst %d\n", dyn->n.x87stack, dyn->n.poped, ninst); \
|
||||
if(dyn->need_dump && dyn->need_dump != 3) dynarec_log(LOG_NONE, " Warning, suspicious x87 Pop, stack=%d/%d on inst %d\n", dyn->n.x87stack, dyn->n.poped, ninst); \
|
||||
dyn->abort = 1; \
|
||||
return addr; \
|
||||
} \
|
||||
@@ -1002,17 +1049,17 @@
|
||||
#define READFLAGS(A) \
|
||||
if((A)!=X_PEND \
|
||||
&& (dyn->f==status_unk)) { \
|
||||
TABLE64C(x6, const_updateflags_arm64); \
|
||||
BLR(x6); \
|
||||
TABLE64C(x5, const_updateflags_arm64); \
|
||||
BLR(x5); \
|
||||
dyn->f = status_none; \
|
||||
}
|
||||
} else if((A)==X_ALL) flushNative(dyn, ninst);
|
||||
#endif
|
||||
|
||||
#define GRABFLAGS(A) \
|
||||
if((A)!=X_PEND \
|
||||
&& ((dyn->f==status_unk) || (dyn->f==status_set))) { \
|
||||
TABLE64C(x6, const_updateflags_arm64); \
|
||||
BLR(x6); \
|
||||
TABLE64C(x5, const_updateflags_arm64); \
|
||||
BLR(x5); \
|
||||
dyn->f = status_none; \
|
||||
}
|
||||
|
||||
@@ -1079,7 +1126,7 @@
|
||||
|
||||
#undef PREFLAGSNEEDED
|
||||
#define PREFLAGSNEEDED() \
|
||||
if(dyn->always_test && ninst && (dyn->insts[ninst].sep || (ninst && dyn->insts[ninst-1].x64.has_callret))) \
|
||||
if(dyn->always_test && ninst && (ninst && dyn->insts[ninst-1].x64.has_callret)) \
|
||||
checkCRC(dyn, ninst);
|
||||
|
||||
#if STEP < 2
|
||||
@@ -1301,7 +1348,7 @@
|
||||
#define x87_get_cache STEPNAME(x87_get_cache)
|
||||
#define x87_get_neoncache STEPNAME(x87_get_neoncache)
|
||||
#define x87_get_st STEPNAME(x87_get_st)
|
||||
#define x87_get_st_empty STEPNAME(x87_get_st)
|
||||
#define x87_get_st_empty STEPNAME(x87_get_st_empty)
|
||||
#define x87_free STEPNAME(x87_free)
|
||||
#define x87_forget STEPNAME(x87_forget)
|
||||
#define x87_reget_st STEPNAME(x87_reget_st)
|
||||
@@ -1342,6 +1389,7 @@
|
||||
|
||||
#define CacheTransform STEPNAME(CacheTransform)
|
||||
#define additionnal_checks STEPNAME(additionnal_checks)
|
||||
#define flushNative STEPNAME(flushNative)
|
||||
|
||||
#define arm64_move32 STEPNAME(arm64_move32)
|
||||
#define arm64_move64 STEPNAME(arm64_move64)
|
||||
@@ -1368,12 +1416,12 @@ void emit_cmp32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3
|
||||
void emit_cmp8_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
|
||||
void emit_cmp16_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
|
||||
void emit_cmp32_0(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s3, int s4);
|
||||
void emit_test8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5);
|
||||
void emit_test8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4, int s5);
|
||||
void emit_test16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5);
|
||||
void emit_test16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4, int s5);
|
||||
void emit_test32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5);
|
||||
void emit_test32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4, int s5);
|
||||
void emit_test8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_test8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4);
|
||||
void emit_test16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_test16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4);
|
||||
void emit_test32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4);
|
||||
void emit_test32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4);
|
||||
void emit_add32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4);
|
||||
void emit_add32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int64_t c, int s3, int s4, int s5);
|
||||
void emit_add8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
@@ -1445,18 +1493,18 @@ void emit_sar16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_sar16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4);
|
||||
void emit_rol32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4);
|
||||
void emit_ror32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4);
|
||||
void emit_rol8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4);
|
||||
void emit_ror8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4);
|
||||
void emit_rol16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4);
|
||||
void emit_ror16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4);
|
||||
void emit_rol8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4, int modreg);
|
||||
void emit_ror8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4, int modreg);
|
||||
void emit_rol16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4, int modreg);
|
||||
void emit_ror16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4, int modreg);
|
||||
void emit_rcl8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4);
|
||||
void emit_rcr8c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4);
|
||||
void emit_rcl16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4);
|
||||
void emit_rcr16c(dynarec_arm_t* dyn, int ninst, int s1, uint32_t c, int s3, int s4);
|
||||
void emit_rcl32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4);
|
||||
void emit_rcr32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, uint32_t c, int s3, int s4);
|
||||
void emit_rcl32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5);
|
||||
void emit_rcr32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4, int s5);
|
||||
void emit_rcl32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4);
|
||||
void emit_rcr32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s3, int s4);
|
||||
void emit_shrd32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, uint32_t c, int s3, int s4);
|
||||
void emit_shld32c(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, uint32_t c, int s3, int s4);
|
||||
void emit_shrd32(dynarec_arm_t* dyn, int ninst, rex_t rex, int s1, int s2, int s5, int s3, int s4);
|
||||
@@ -1509,6 +1557,7 @@ void avx_purge_ymm(dynarec_arm_t* dyn, int ninst, uint16_t mask, int s1);
|
||||
|
||||
void CacheTransform(dynarec_arm_t* dyn, int ninst, int cacheupd);
|
||||
void additionnal_checks(dynarec_arm_t* dyn, int ninst);
|
||||
void flushNative(dynarec_arm_t* dyn, int ninst);
|
||||
|
||||
void arm64_move32(dynarec_arm_t* dyn, int ninst, int reg, uint32_t val);
|
||||
void arm64_move64(dynarec_arm_t* dyn, int ninst, int reg, uint64_t val);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include <stdint.h>
|
||||
|
||||
#include "arm64_emitter.h"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#define INIT uintptr_t sav_addr=addr
|
||||
#define FINI \
|
||||
@@ -7,16 +8,28 @@
|
||||
|
||||
#define MESSAGE(A, ...) do {} while (0)
|
||||
#define READFLAGS(A) \
|
||||
do { \
|
||||
dyn->insts[ninst].x64.use_flags = A; if(dyn->f!=status_none_pending) dyn->f = status_none;\
|
||||
if(!BOX64ENV(dynarec_df) && (A)&X_PEND) dyn->insts[ninst].x64.use_flags = X_ALL; \
|
||||
dyn->f = status_none
|
||||
dyn->f = status_none; \
|
||||
} while(0)
|
||||
#define SETFLAGS(A,B) \
|
||||
do { \
|
||||
dyn->insts[ninst].x64.set_flags = A; \
|
||||
dyn->insts[ninst].x64.state_flags = (B)&~SF_DF; \
|
||||
dyn->f=((B)&SF_SET)?(((B)==SF_SET_NODF)?dyn->f:status_none_pending):(((B)&SF_SET_PENDING)?status_set:status_none_pending); \
|
||||
if(!BOX64ENV(dynarec_df)) {dyn->f=status_none; if((A)==SF_PENDING){printf_log(LOG_INFO, "Warning, some opcode use SF_PENDING, forcing deferedflags ON\n"); SET_BOX64ENV(dynarec_df, 1); }}
|
||||
if(!BOX64ENV(dynarec_df)) {dyn->f=status_none; if((A)==SF_PENDING){printf_log(LOG_INFO, "Warning, some opcode use SF_PENDING, forcing deferedflags ON\n"); SET_BOX64ENV(dynarec_df, 1); }} \
|
||||
} while(0)
|
||||
#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 JUMP(A, C) \
|
||||
do { \
|
||||
dyn->insts[ninst].x64.jmp = (uintptr_t)(A); \
|
||||
add_jump(dyn, ninst); \
|
||||
add_next(dyn, dyn->insts[ninst].x64.jmp); \
|
||||
SMEND(); \
|
||||
dyn->insts[ninst].x64.jmp_cond = C; \
|
||||
dyn->insts[ninst].x64.jmp_insts = 0; \
|
||||
} while (0)
|
||||
#define BARRIER(A) if(A!=BARRIER_MAYBE) {fpu_purgecache(dyn, ninst, 0, x1, x2, x3, 0); dyn->insts[ninst].x64.barrier = A;} else dyn->insts[ninst].barrier_maybe = 1
|
||||
#define SET_HASCALLRET() dyn->insts[ninst].x64.has_callret = 1
|
||||
#define NEW_INST \
|
||||
@@ -25,7 +38,11 @@
|
||||
dyn->n.combined1 = dyn->n.combined2 = 0;\
|
||||
dyn->n.swapped = 0; dyn->n.barrier = 0; \
|
||||
dyn->insts[ninst].f_entry = dyn->f; \
|
||||
if(ninst) {dyn->insts[ninst-1].x64.size = dyn->insts[ninst].x64.addr - dyn->insts[ninst-1].x64.addr;} \
|
||||
dyn->insts[ninst].host_call = 0; \
|
||||
dyn->insts[ninst].host_call_clobber = 0;\
|
||||
dyn->insts[ninst].x64.strongmem = ((box64_wine && VolatileRangesContains(ip)) ? 0 : BOX64DRENV(dynarec_strongmem)); \
|
||||
if(dyn->insts[ninst].x64.strongmem && cpuext.lrcpc && cpuext.lrcpc2 && cpuext.uscat) dyn->insts[ninst].use_lrcpc = 1; \
|
||||
if(ninst) {dyn->insts[ninst-1].x64.size = dyn->insts[ninst].x64.addr - dyn->insts[ninst-1].x64.addr;} \
|
||||
AREFLAGSNEEDED()
|
||||
|
||||
#define INST_EPILOG \
|
||||
@@ -33,7 +50,11 @@
|
||||
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;
|
||||
dyn->insts[ninst].x64.has_next = (ok>0)?1:0; \
|
||||
if(dyn->insts[ninst].use_lrcpc && (!dyn->insts[ninst].has_lrcpc || is_addr_lrcpc(ip))) \
|
||||
dyn->insts[ninst].use_lrcpc = 0; \
|
||||
if(dyn->insts[ninst].x64.strongmem && dyn->insts[ninst].use_lrcpc) dyn->insts[ninst].x64.strongmem = 0
|
||||
|
||||
#define INST_NAME(name)
|
||||
#define DEFAULT \
|
||||
--dyn->size; \
|
||||
@@ -45,7 +66,8 @@
|
||||
}
|
||||
|
||||
|
||||
#define FEMIT(A) dyn->insts[ninst].nat_flags_op = dyn->insts[ninst].x64.set_flags?NAT_FLAG_OP_TOUCH:NAT_FLAG_OP_UNUSABLE
|
||||
#define FEMIT(A) do {dyn->insts[ninst].nat_flags_op = dyn->insts[ninst].x64.set_flags?NAT_FLAG_OP_TOUCH:NAT_FLAG_OP_UNUSABLE; EMIT(A);} while(0)
|
||||
#define LEMIT(A) do {dyn->insts[ninst].has_lrcpc = 1; EMIT(A);} while(0)
|
||||
#define IFNATIVE(A) if(mark_natflag(dyn, ninst, A, 0))
|
||||
#define IFNATIVEN(A) if(mark_natflag(dyn, ninst, A, 0))
|
||||
#define UFLAG_IF if(dyn->insts[ninst].x64.set_flags)
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
#define INIT
|
||||
#define FINI
|
||||
#define MESSAGE(A, ...) do {} while (0)
|
||||
#define EMIT(A) do {} while (0)
|
||||
#define LEMIT(A) do {dyn->insts[ninst].has_lrcpc = 1; EMIT(A);} while(0)
|
||||
|
||||
// do not update dyn->f for SETFLAGS(..., SF_SET_PENDING) because it will use either DF_NONE or DF_SET anyway (similar to SF_SET_NODF)
|
||||
#define SETFLAGS(A,B) \
|
||||
do { \
|
||||
dyn->insts[ninst].x64.set_flags = A; \
|
||||
dyn->insts[ninst].x64.state_flags = (B)&~SF_DF; \
|
||||
dyn->f=((B)&SF_SET)?(((B)==SF_SET_NODF)?dyn->f:status_none_pending):(((B)&SF_SET_PENDING)?status_set:status_none_pending); \
|
||||
if(!BOX64ENV(dynarec_df)) {dyn->f = status_none; }
|
||||
if(((B)&SF_SET_PENDING)!=SF_SET_PENDING) dyn->f=((B)&SF_SET)?(((B)==SF_SET_NODF)?dyn->f:status_none_pending):((dyn->f==status_none)?status_none:status_none_pending); \
|
||||
if(!BOX64ENV(dynarec_df)) {dyn->f = status_none; } \
|
||||
} while(0)
|
||||
#define NEW_INST \
|
||||
dyn->insts[ninst].f_entry = dyn->f; \
|
||||
dyn->n.combined1 = dyn->n.combined2 = 0;\
|
||||
@@ -16,7 +21,9 @@
|
||||
|
||||
#define INST_EPILOG \
|
||||
dyn->insts[ninst].n = dyn->n; \
|
||||
dyn->insts[ninst].f_exit = dyn->f
|
||||
dyn->insts[ninst].f_exit = dyn->f; \
|
||||
if(dyn->insts[ninst].use_lrcpc && (!dyn->insts[ninst].has_lrcpc || is_addr_lrcpc(ip))) \
|
||||
dyn->insts[ninst].use_lrcpc = 0
|
||||
|
||||
#define INST_NAME(name)
|
||||
|
||||
|
||||
Loaded 100 of 2368 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user