mirror of
https://github.com/ptitSeb/box86.git
synced 2026-11-07 17:43:14 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb716a2a65 | ||
|
|
7dec0819b5 | ||
|
|
b05cb3ab54 | ||
|
|
dea645b38d | ||
|
|
707a141e0d | ||
|
|
14181b503b | ||
|
|
9a67cb9355 | ||
|
|
39d3ed2033 | ||
|
|
646fc2d3a8 | ||
|
|
0579f8b9c4 | ||
|
|
50a2603027 | ||
|
|
10224524df | ||
|
|
0886bb79c4 | ||
|
|
fa14e0ab14 | ||
|
|
ac48800fbb | ||
|
|
b197194e2d | ||
|
|
2796d6ef92 | ||
|
|
d60937b1ac | ||
|
|
d0aad67ba0 | ||
|
|
66fc843ae8 | ||
|
|
7e56375859 | ||
|
|
c13b3cc9cd | ||
|
|
ba5b9e9954 | ||
|
|
fa59e748f9 | ||
|
|
c467c05112 | ||
|
|
bb164a299f | ||
|
|
eaf2e84e19 | ||
|
|
7dcba89c71 | ||
|
|
5c5639be09 | ||
|
|
ee0c949bc2 | ||
|
|
d9402213f6 | ||
|
|
efe8bb4e6c | ||
|
|
ec278bd784 | ||
|
|
f1559b066c | ||
|
|
c9d20f60c8 | ||
|
|
512f0a6c92 | ||
|
|
1c280bd8a0 | ||
|
|
20432122de | ||
|
|
e754df0fb1 | ||
|
|
b9d565f444 | ||
|
|
58f1b5d1e3 | ||
|
|
f921c0cdbe | ||
|
|
1e749beb2e | ||
|
|
4caece4c0c | ||
|
|
d6b76922e7 | ||
|
|
69a021454a | ||
|
|
336dc5b676 | ||
|
|
450347f099 | ||
|
|
30c72e23bd | ||
|
|
ce0b4d1884 | ||
|
|
72d934b34c | ||
|
|
4e8d4a2bff | ||
|
|
c993aacd04 | ||
|
|
a7855d3bcb | ||
|
|
7b8a6aa91d | ||
|
|
c65c514882 | ||
|
|
62bc6bb1f3 | ||
|
|
0504c042f4 | ||
|
|
54c806c576 | ||
|
|
55e08ab0be | ||
|
|
e717b959c6 | ||
|
|
f97763cacd | ||
|
|
fc43e4c22b | ||
|
|
b01829b7d6 | ||
|
|
d1fcdee8a8 | ||
|
|
56b23e0668 | ||
|
|
d927dae7e7 | ||
|
|
a49c286214 | ||
|
|
80e092ae44 | ||
|
|
05017f46d2 | ||
|
|
0caa80f9f1 | ||
|
|
66a91b8580 | ||
|
|
bcd36a3152 | ||
|
|
6aba6364c4 | ||
|
|
0cf5179d7f | ||
|
|
3c9823198c | ||
|
|
664956aaa0 | ||
|
|
9811f140ce | ||
|
|
26ddd6e9ef | ||
|
|
c5bccdf300 | ||
|
|
4b20581753 | ||
|
|
a4f38779eb | ||
|
|
27c21f6979 | ||
|
|
e14d8abb61 | ||
|
|
54ed80f68a | ||
|
|
a187c7ccd3 | ||
|
|
f6a5322cf3 | ||
|
|
5da8235b18 | ||
|
|
21e9a43d21 | ||
|
|
dcc0355113 | ||
|
|
666b5a6ce6 | ||
|
|
fcbebfa8c8 | ||
|
|
9354744f68 | ||
|
|
fc0b51f3b8 | ||
|
|
cd88702516 | ||
|
|
223fa8ea17 | ||
|
|
d3d971d449 | ||
|
|
2e589f42fe | ||
|
|
96a34a2a40 | ||
|
|
69f0c979d4 | ||
|
|
ff702c0318 | ||
|
|
968fc3fcfe | ||
|
|
4abaa3d835 | ||
|
|
121c67655b | ||
|
|
9f8b96b749 | ||
|
|
a9c50ef238 | ||
|
|
984da28f40 | ||
|
|
a8babcba8d | ||
|
|
13c7029de5 | ||
|
|
148722dac4 | ||
|
|
dd5bba2aac | ||
|
|
b044c19329 | ||
|
|
fb1dbb3821 | ||
|
|
4f21d83e62 | ||
|
|
b145080d37 | ||
|
|
0829c14a73 | ||
|
|
4141748f9a | ||
|
|
25e1d8bae8 | ||
|
|
79e622a839 | ||
|
|
932045054f | ||
|
|
f5f1e1413d | ||
|
|
24f2c68805 | ||
|
|
7748d10246 | ||
|
|
22ee4685a1 | ||
|
|
35ea6fd109 | ||
|
|
3744603bcc | ||
|
|
4861b78dc4 | ||
|
|
ba017657ad | ||
|
|
811c4fccd8 | ||
|
|
3992ab5931 | ||
|
|
266392e315 | ||
|
|
83e550b122 | ||
|
|
b5f2b9c936 | ||
|
|
82f610faee | ||
|
|
ec77755952 | ||
|
|
14c9cb148d | ||
|
|
f48aeaac60 | ||
|
|
74eb4ed9d5 | ||
|
|
68503a37cf | ||
|
|
49e6609182 | ||
|
|
966bb72e9e | ||
|
|
14b978a568 | ||
|
|
8378f9b307 | ||
|
|
9dc0f8243a | ||
|
|
eaeacc6706 | ||
|
|
031dba2904 | ||
|
|
f8229ea561 | ||
|
|
e5bfe84394 | ||
|
|
5e926a266f | ||
|
|
29e97a88a2 | ||
|
|
a94e8ed659 | ||
|
|
b013c86338 | ||
|
|
29926438a8 | ||
|
|
87097f437b | ||
|
|
35f266ea94 | ||
|
|
88fd555ef0 | ||
|
|
107d792ab1 | ||
|
|
30f364f166 | ||
|
|
e259ffcf66 | ||
|
|
027605e4d5 | ||
|
|
2c58b45d8e | ||
|
|
159351fc3c | ||
|
|
d4cf4ee521 | ||
|
|
7d90fff7cd | ||
|
|
68dcf9d0bf | ||
|
|
d89c10415a | ||
|
|
99310cc9c6 | ||
|
|
57d126cddc | ||
|
|
2b35400dc5 | ||
|
|
d1d899babd | ||
|
|
fe112fece8 | ||
|
|
74a338df94 | ||
|
|
f2496984d5 | ||
|
|
3ebcc84d52 | ||
|
|
c878264ede | ||
|
|
fbf3e1b1cc | ||
|
|
e23d2167b4 | ||
|
|
3d485c6159 | ||
|
|
9af5916104 | ||
|
|
80e93dcee4 | ||
|
|
90f21fb710 | ||
|
|
41a8bc0da9 | ||
|
|
06e40a2379 | ||
|
|
78104d1b5f | ||
|
|
9626291470 | ||
|
|
6f4a8fbd5d | ||
|
|
f191228318 | ||
|
|
7c3730f4e6 | ||
|
|
772aca08b8 | ||
|
|
0f19b73dfe | ||
|
|
b7dccd065f | ||
|
|
57c1ed7118 | ||
|
|
5a348e1de9 | ||
|
|
76a5f3b7c9 | ||
|
|
c317bf94c8 | ||
|
|
cbe0ef830b | ||
|
|
5c54463c32 | ||
|
|
531ccfaf6a | ||
|
|
339af4a13e | ||
|
|
d4f7ec6ee4 | ||
|
|
2de4ce82f3 | ||
|
|
d2f033e97a | ||
|
|
c2375d030b | ||
|
|
786680a288 | ||
|
|
0883cdc9ac | ||
|
|
e35d6d22a4 | ||
|
|
14a53affc0 | ||
|
|
18e8b06dfb | ||
|
|
ac8ae8f0ec | ||
|
|
274fe75017 | ||
|
|
278d8fe8d9 | ||
|
|
dcf89339b8 | ||
|
|
1c3c3a209a | ||
|
|
d91ac13592 | ||
|
|
aafa791f4a | ||
|
|
3b08ace904 | ||
|
|
fefa13f655 | ||
|
|
949e7b7809 | ||
|
|
7fe38de5f6 | ||
|
|
9803591643 | ||
|
|
d87033837b | ||
|
|
507b68358f | ||
|
|
1b721a536e | ||
|
|
77706f8142 | ||
|
|
8a71575487 | ||
|
|
dd0a57ab30 | ||
|
|
07b0f6673a | ||
|
|
88e84a6c1c | ||
|
|
767e94aae1 | ||
|
|
0c211a0164 | ||
|
|
be6e2fe1da | ||
|
|
d94dce18c5 | ||
|
|
a0f180e86b | ||
|
|
8f2fe64afc | ||
|
|
d64248b1f8 | ||
|
|
cc67b01aa8 | ||
|
|
90a18265b9 | ||
|
|
08f8d8d721 | ||
|
|
df2504f976 | ||
|
|
117fe48b5e | ||
|
|
e02844fb93 | ||
|
|
ca1f0d0cf2 | ||
|
|
2e6bc42a49 | ||
|
|
cf2e754447 | ||
|
|
708986a3c6 | ||
|
|
e8fabe23ec | ||
|
|
fa2374a7a7 | ||
|
|
a70e5d7aa7 | ||
|
|
e87915bcfb | ||
|
|
c540942294 | ||
|
|
3869cc2bc0 | ||
|
|
f3ddb6bcf4 | ||
|
|
26f30a3c09 | ||
|
|
b831475d1b | ||
|
|
431eb604e4 | ||
|
|
0d2bf2fe30 | ||
|
|
94f9f5d0b5 | ||
|
|
8349acb93a | ||
|
|
8c00a1100f | ||
|
|
0cdd36bac6 | ||
|
|
fd3dcf3873 | ||
|
|
72d3098ba4 | ||
|
|
177abf2e44 | ||
|
|
077764251d | ||
|
|
90fbf7237f | ||
|
|
d9ec366ce4 | ||
|
|
c854b23d35 | ||
|
|
fd137915b6 | ||
|
|
dad0e5ef2f | ||
|
|
5abf1fa24e | ||
|
|
b5bc46e13a | ||
|
|
c39a8ebd51 | ||
|
|
38d35cbef0 | ||
|
|
3058fefe93 | ||
|
|
f03d09b949 | ||
|
|
2343533b41 | ||
|
|
fa2f3c0577 | ||
|
|
6c28b3584e | ||
|
|
8fa5ec74ec | ||
|
|
868ad666ed | ||
|
|
150b035a1b | ||
|
|
fdd775790a | ||
|
|
68ff10a18e | ||
|
|
3f072c8aa8 | ||
|
|
7b0c1689bb | ||
|
|
6946198045 | ||
|
|
8f76973fcf | ||
|
|
b9ded7320a | ||
|
|
fc14382a07 | ||
|
|
35cc9af4ff | ||
|
|
0c2d9acd99 | ||
|
|
9c0ecf0427 | ||
|
|
10529d007c | ||
|
|
ac356fc146 | ||
|
|
0b584bbb48 | ||
|
|
c10b105f5f | ||
|
|
236de084ea | ||
|
|
72e917bb06 | ||
|
|
0d64ab09bb | ||
|
|
ff0b7683e7 | ||
|
|
d210f12f25 | ||
|
|
87d346230c | ||
|
|
47c65e1e3a | ||
|
|
57440bd102 | ||
|
|
389c803929 | ||
|
|
08d8407056 | ||
|
|
3f12bde9ff | ||
|
|
a47a9d95d7 | ||
|
|
f2a4125ab8 | ||
|
|
2d3f244935 | ||
|
|
2a1342c5b3 | ||
|
|
82bf0a99d2 | ||
|
|
c6275bcb62 | ||
|
|
7a175a9733 | ||
|
|
75759f9ba7 | ||
|
|
6f966fe468 | ||
|
|
f716212932 | ||
|
|
4b1b214663 | ||
|
|
5e7a7db60d | ||
|
|
968da3a4d4 | ||
|
|
347c645e95 | ||
|
|
e50f152355 | ||
|
|
59f85c8fbb | ||
|
|
9fbab85232 | ||
|
|
a0a3389651 | ||
|
|
6e51e73a1e | ||
|
|
35e64fd56c | ||
|
|
402496c93e | ||
|
|
84d415c211 | ||
|
|
020b2ba8d0 | ||
|
|
2890c05fba | ||
|
|
829d39f8a3 | ||
|
|
197cdafa22 | ||
|
|
aa75d5a434 | ||
|
|
38b8d9b8a5 | ||
|
|
a1091a9a72 | ||
|
|
8d1561f6e5 | ||
|
|
375bc45b51 | ||
|
|
334b891364 | ||
|
|
a8f3d57afb | ||
|
|
3023c8262d | ||
|
|
bc166ae3b3 | ||
|
|
4e29df8a56 | ||
|
|
e24c1f048b | ||
|
|
daef5cbdc9 | ||
|
|
699af54183 | ||
|
|
731d9a249d | ||
|
|
3e67c4573b | ||
|
|
ef25a75b86 | ||
|
|
c4b182048c | ||
|
|
6079f39655 | ||
|
|
2dcd2741c7 | ||
|
|
399b2c7f8a | ||
|
|
7ae3200c6f | ||
|
|
299ddb22a5 | ||
|
|
df8930a78a | ||
|
|
a37cd0bd91 | ||
|
|
ee10226614 | ||
|
|
ad934455c1 | ||
|
|
c0e7062b03 | ||
|
|
04d03af8ac | ||
|
|
32accd0e77 | ||
|
|
c4b3fc25e0 | ||
|
|
676b02b5aa | ||
|
|
3c8e34f691 | ||
|
|
630f42e9e2 | ||
|
|
58b0338dff | ||
|
|
80c77bad96 | ||
|
|
771ff1b2e2 | ||
|
|
cef87f7f7d | ||
|
|
e8d4ffc782 | ||
|
|
85397e9895 | ||
|
|
8194ad9728 | ||
|
|
b82f203a9d | ||
|
|
151e2ae3a4 | ||
|
|
0072524d5d | ||
|
|
949417f412 | ||
|
|
21fea0f195 | ||
|
|
9c1317f899 | ||
|
|
127a48f199 | ||
|
|
66b8c58cc1 | ||
|
|
39bb606c06 | ||
|
|
626826f33e | ||
|
|
a9082f60b6 | ||
|
|
3b394b8f0d | ||
|
|
a108a23c56 | ||
|
|
51baede9c1 | ||
|
|
d601b42ddc | ||
|
|
d430332c45 | ||
|
|
63fae1b6c8 | ||
|
|
c45d3d80ab | ||
|
|
57e9e95411 | ||
|
|
68fb291c83 | ||
|
|
f3ee727bc4 | ||
|
|
21ed47c4cb | ||
|
|
2147d92d9d | ||
|
|
1465ff8aad | ||
|
|
ac895e3dad | ||
|
|
983a3d9926 | ||
|
|
ecec73547f | ||
|
|
6ed82e7f7d | ||
|
|
83a9b2cab5 | ||
|
|
666e41a0cb | ||
|
|
c78be09d7f | ||
|
|
21023e9802 | ||
|
|
38c07f2a2f | ||
|
|
e6d124aed4 | ||
|
|
8335a8c2d9 | ||
|
|
6f7a513051 | ||
|
|
43189a2914 | ||
|
|
3bf9e4d989 | ||
|
|
fe3419957e | ||
|
|
f8c8a5d596 | ||
|
|
9ee7f84015 | ||
|
|
36b316746b | ||
|
|
0131572edf | ||
|
|
d74e873a85 | ||
|
|
be53b823d3 | ||
|
|
e5b6c8b6e0 | ||
|
|
ecf7bfd848 | ||
|
|
2a7b848d0e | ||
|
|
fa5fa7b5c0 | ||
|
|
b7283b8d9d | ||
|
|
b8d72023c5 | ||
|
|
e10a710591 | ||
|
|
9ee030a566 | ||
|
|
a8e96764b5 | ||
|
|
c43f1d882c | ||
|
|
1e67cefc43 | ||
|
|
5cdc1b9fa2 | ||
|
|
ab75a3e2d3 | ||
|
|
21d097853b | ||
|
|
2e3bdbefc7 | ||
|
|
a19773cfb0 | ||
|
|
1988eb0366 | ||
|
|
54d5aaa11d | ||
|
|
205ec1f4dc | ||
|
|
005367ea3c | ||
|
|
8ac9bc30a2 | ||
|
|
f0691e56fc | ||
|
|
bc06c277ec | ||
|
|
1341a4a55f | ||
|
|
82cf77b9d9 | ||
|
|
10db79df4a | ||
|
|
bce188e217 | ||
|
|
220a64af1f | ||
|
|
e73fa8f3fb | ||
|
|
053a75f5d5 | ||
|
|
bcb19dbe5d | ||
|
|
039c62f740 | ||
|
|
7663aacd1b | ||
|
|
fd5bf804ec | ||
|
|
70d18cfb7c | ||
|
|
1e32ccc9c7 | ||
|
|
23fa99d148 | ||
|
|
0e3ce6d8b1 | ||
|
|
970384559f | ||
|
|
2f8a939485 | ||
|
|
4f13c33628 | ||
|
|
4ef5da404c | ||
|
|
15fa9f687c | ||
|
|
331e5700a2 | ||
|
|
1411d44b51 | ||
|
|
bf53a76223 | ||
|
|
ecbc1e6642 | ||
|
|
7dc5b501f3 | ||
|
|
af67f69ee2 | ||
|
|
8f2a4ea880 | ||
|
|
eb44fd62fb | ||
|
|
46f015da9d | ||
|
|
705414a3d0 | ||
|
|
4591d337cb | ||
|
|
54e13be02a | ||
|
|
1524e883cd | ||
|
|
7a65bd60e9 | ||
|
|
8c1694e530 | ||
|
|
292d1455b6 | ||
|
|
9c69702011 | ||
|
|
3554d6decb | ||
|
|
7fb36acf85 | ||
|
|
ed3296978e | ||
|
|
4b212f91bf | ||
|
|
94f451c4b7 | ||
|
|
13bbf105ad | ||
|
|
3eb16fb7bd | ||
|
|
e85bcb671a | ||
|
|
1a0888ca51 | ||
|
|
3043f5066f | ||
|
|
b3b55d2d74 | ||
|
|
58426cbfb6 | ||
|
|
4a88ff38ea | ||
|
|
8d96ff02e3 | ||
|
|
eaa6ecb9cc | ||
|
|
027909bddc | ||
|
|
0eca6a8b94 | ||
|
|
24494ba143 | ||
|
|
a813321ad4 | ||
|
|
a43884ff66 | ||
|
|
27b269f53a | ||
|
|
d698861478 | ||
|
|
be02c88792 | ||
|
|
99059ffb19 | ||
|
|
a4752afacf | ||
|
|
a320c37681 | ||
|
|
42a9a40ac4 | ||
|
|
6320a07d17 | ||
|
|
5e251cf478 | ||
|
|
355a2fa8e5 | ||
|
|
78ed9d07f2 | ||
|
|
8c38d5dd36 | ||
|
|
f682ca6bf0 | ||
|
|
70a2a2dd1b | ||
|
|
3678f44945 | ||
|
|
5bb473158b | ||
|
|
3f549749c1 | ||
|
|
11535dabe0 | ||
|
|
1c2d36f98a | ||
|
|
8563ba8b70 | ||
|
|
4b43da2081 | ||
|
|
49c650781f | ||
|
|
36e5bf731c | ||
|
|
f4d4116590 | ||
|
|
11281589e0 | ||
|
|
756811a901 | ||
|
|
dd405c7c49 | ||
|
|
20237019e4 | ||
|
|
7682cdce57 | ||
|
|
1dcac1b868 | ||
|
|
5f0add0e82 | ||
|
|
8f2ef48e25 | ||
|
|
4f98f568a7 | ||
|
|
0e0e346e45 | ||
|
|
4388092f11 | ||
|
|
b83c693192 | ||
|
|
9de1bd884f | ||
|
|
1b462b8200 | ||
|
|
d7c75be001 | ||
|
|
957fcc2449 | ||
|
|
328794e4d6 | ||
|
|
af519f6046 | ||
|
|
fa9a059921 | ||
|
|
771d65dc10 | ||
|
|
1dc92c216f | ||
|
|
db4ff551cc | ||
|
|
7abb9a1893 | ||
|
|
60f987ff90 | ||
|
|
f38d122b67 | ||
|
|
a654193f1d | ||
|
|
632a01dbe6 | ||
|
|
ae2e3aed0f | ||
|
|
244b273250 | ||
|
|
27756113ef | ||
|
|
d550293ccc | ||
|
|
74bb2e84f2 | ||
|
|
09d2b067b5 | ||
|
|
6d7f901167 | ||
|
|
bdc839ef87 | ||
|
|
52f7e89fdb | ||
|
|
6a2b45ec5c | ||
|
|
ac0fd0278b | ||
|
|
db06cec325 | ||
|
|
d93e7f92f2 | ||
|
|
d8e94908ff | ||
|
|
8e9d31e670 | ||
|
|
6ed7bbdb21 | ||
|
|
8338ebaa46 | ||
|
|
d4c08eb083 | ||
|
|
c62dc24155 | ||
|
|
f8e2b81160 | ||
|
|
06b38df650 | ||
|
|
00e6ed3feb | ||
|
|
6ffbacd808 | ||
|
|
8e88ca6985 | ||
|
|
ada65fc0da | ||
|
|
52002ebc64 | ||
|
|
a3e25e32a4 | ||
|
|
8aedf8957e | ||
|
|
db7924e26a | ||
|
|
2b2478381a | ||
|
|
59b1e323f7 | ||
|
|
31e7957362 | ||
|
|
917a9ba11f | ||
|
|
71f6654062 | ||
|
|
5b1670390a | ||
|
|
f4999d71f3 | ||
|
|
64f52cb1b9 | ||
|
|
905780e47d | ||
|
|
6f176bceae | ||
|
|
21a8e20b94 | ||
|
|
20b2b083f5 | ||
|
|
bfeedef03b | ||
|
|
d42767414d | ||
|
|
c83f21cc38 | ||
|
|
f1ce0668f8 | ||
|
|
20e6869e53 | ||
|
|
75a3fb0d89 | ||
|
|
0145c5bb34 | ||
|
|
8e3d0835a2 | ||
|
|
9fe432ac60 | ||
|
|
5e46f8825b | ||
|
|
359ba4836d | ||
|
|
fe57003477 | ||
|
|
067eb6d7da | ||
|
|
69ec807d56 | ||
|
|
8462b62c0b | ||
|
|
3313d7a158 | ||
|
|
47581ddb50 | ||
|
|
ccf1249b24 | ||
|
|
ebab21f211 | ||
|
|
0de956191b | ||
|
|
1e648aa3d6 | ||
|
|
89e5517961 | ||
|
|
a4cfa477d6 | ||
|
|
66d5fa5ef8 | ||
|
|
cb09b0978a | ||
|
|
dbd5e1b565 | ||
|
|
66ef165184 | ||
|
|
f92b5851d0 | ||
|
|
36b62b9464 | ||
|
|
d867acd295 | ||
|
|
f0d525ddcc | ||
|
|
f82ea51a2b | ||
|
|
1be3d617c7 | ||
|
|
8bc26298a0 | ||
|
|
e6cf41c381 | ||
|
|
657f19d357 | ||
|
|
e681acaf36 | ||
|
|
5142245b1f | ||
|
|
6a49000bc5 | ||
|
|
8d06a36508 | ||
|
|
f120154675 | ||
|
|
ef84c8a635 | ||
|
|
33a2716c43 | ||
|
|
3fcdee46b9 | ||
|
|
8b28872b0e | ||
|
|
29158238bc | ||
|
|
a0191247b9 | ||
|
|
f07af5825c | ||
|
|
fcc5528d77 | ||
|
|
ab13305bc0 | ||
|
|
61075afbb9 | ||
|
|
b4ee108c9c | ||
|
|
e31348b6d5 | ||
|
|
d76efc849f | ||
|
|
76700c1dab | ||
|
|
3f58046288 | ||
|
|
069f488f7b | ||
|
|
320977d84a | ||
|
|
2e7af32cd9 | ||
|
|
c10c86e1d4 | ||
|
|
a4bf1d2c72 | ||
|
|
b3d45c348d | ||
|
|
a4ce2bd549 | ||
|
|
891593c1c9 | ||
|
|
b43e4acc3e | ||
|
|
9cbc531502 | ||
|
|
41c9d92593 | ||
|
|
c2a782839d | ||
|
|
e7653bdda8 | ||
|
|
00a2b44be3 | ||
|
|
bb2d5d43cd | ||
|
|
97aae9521b | ||
|
|
9f2745ad53 | ||
|
|
ec4783bb6f | ||
|
|
5760c04de4 | ||
|
|
4250c61e0f | ||
|
|
c16317850a | ||
|
|
3d325747a5 | ||
|
|
21abac8b06 | ||
|
|
89f05a35e3 | ||
|
|
116e700248 | ||
|
|
db3a80b089 | ||
|
|
09b234e719 | ||
|
|
5f0ca6f03e | ||
|
|
bf3da2d1b5 | ||
|
|
caf0bb9d4d | ||
|
|
753f738368 | ||
|
|
06a19ba790 | ||
|
|
d63a846748 | ||
|
|
3f46f9fb68 | ||
|
|
521dae4695 | ||
|
|
4b7a3046ce | ||
|
|
b0ac567e7a | ||
|
|
455fce9ff5 | ||
|
|
e0ba315761 | ||
|
|
e41be11e9f | ||
|
|
9f0c33016f | ||
|
|
faa13945eb | ||
|
|
989952a873 | ||
|
|
bc9f8df2c2 | ||
|
|
ddface22a8 | ||
|
|
cf18090431 | ||
|
|
cd27cf03e1 | ||
|
|
c0f643dcbe | ||
|
|
84ffab7354 | ||
|
|
cbfd949756 | ||
|
|
55ce03844f | ||
|
|
1451fa8c65 | ||
|
|
d87f90dca3 | ||
|
|
6f8164da52 | ||
|
|
aace0531ab | ||
|
|
91609788d4 | ||
|
|
b5b7019b79 | ||
|
|
2bcafd6ef7 | ||
|
|
0f1092200c | ||
|
|
ccf612a711 | ||
|
|
d8ec77da69 | ||
|
|
aa3efd01cc | ||
|
|
58ca96e2a5 | ||
|
|
5bf7a15f8e | ||
|
|
7d863efcf8 | ||
|
|
6f43a14ddd | ||
|
|
369aa14bff | ||
|
|
4bd4f320bc | ||
|
|
e0340b2a74 | ||
|
|
508b2aa580 | ||
|
|
b8ec0f910c | ||
|
|
c716b3b481 | ||
|
|
ddecd61771 | ||
|
|
88c490b843 | ||
|
|
5998ae57ea | ||
|
|
94c99353fa | ||
|
|
b993866def | ||
|
|
b292efc741 | ||
|
|
bc78375816 | ||
|
|
82e4997624 | ||
|
|
51c64e7dce | ||
|
|
294adeae11 | ||
|
|
95c4c277a1 | ||
|
|
3d517c0bf5 | ||
|
|
2bd3a670e8 | ||
|
|
a621a2b61f | ||
|
|
bc810d16f1 | ||
|
|
fd3f8f5990 | ||
|
|
c713f64d7e | ||
|
|
ed2a8ff73d | ||
|
|
31524ed90b | ||
|
|
1c5aef19ae | ||
|
|
1932f8320a | ||
|
|
ae590d8378 | ||
|
|
124ca7fdc2 | ||
|
|
21128f51f5 | ||
|
|
1af9666622 | ||
|
|
abf66a9cd7 | ||
|
|
5ba8672ac8 | ||
|
|
4616ed9bc3 | ||
|
|
047b9f2eac | ||
|
|
14113faaba | ||
|
|
03b20c3f52 | ||
|
|
26a6eb1922 | ||
|
|
a2f00c5c91 | ||
|
|
dea480e10f | ||
|
|
b7fc2cd5ba | ||
|
|
2aad95726c | ||
|
|
105c56a817 | ||
|
|
3da1ed0a8e | ||
|
|
f46068314c | ||
|
|
914df83ba5 | ||
|
|
d7f5290f14 | ||
|
|
9d37471e4e | ||
|
|
57e75a2fa3 | ||
|
|
3fab879089 | ||
|
|
16cb3d36ba | ||
|
|
74ef17ee94 | ||
|
|
f1c540d877 | ||
|
|
6018e65ab9 | ||
|
|
43190d413c | ||
|
|
a156166a8e | ||
|
|
c8141c63ad | ||
|
|
8dd940804c | ||
|
|
d16f956068 | ||
|
|
082b25d81f | ||
|
|
a0e29198f6 | ||
|
|
b4c5a4c531 | ||
|
|
3a1e6ae5df | ||
|
|
3f7464bf6c | ||
|
|
6aef4501f8 | ||
|
|
3024f27b7a | ||
|
|
e8e1b52a9b | ||
|
|
1c8c76d389 | ||
|
|
a30eedf1e2 | ||
|
|
0b3314607f | ||
|
|
8e7c203772 | ||
|
|
399854342f | ||
|
|
bb692f26d0 | ||
|
|
da5a4c9fbe | ||
|
|
37fc3d0daf | ||
|
|
76a86e2e45 | ||
|
|
a25c32a60b | ||
|
|
4946642fc4 | ||
|
|
2ac59458f3 | ||
|
|
6d329e885f | ||
|
|
902da5c619 | ||
|
|
e9fcef3de5 | ||
|
|
b43ddd46ea | ||
|
|
9c3002928a | ||
|
|
17ec8d8a75 | ||
|
|
d241c818df | ||
|
|
6ff1375e44 | ||
|
|
bb3a13db3b | ||
|
|
ea439a7183 | ||
|
|
fa8355eccc | ||
|
|
62340ea5d8 | ||
|
|
e6deec89f8 | ||
|
|
65fae25715 | ||
|
|
f735f2cbdd | ||
|
|
f5658a6079 | ||
|
|
2b1580b73f | ||
|
|
3c519517c7 | ||
|
|
7389dc616b | ||
|
|
2ff0562a82 | ||
|
|
2ecdc3bb09 | ||
|
|
c1eb7cbfa8 | ||
|
|
45d2ac757e | ||
|
|
875f1d094d | ||
|
|
dc1c986c2c | ||
|
|
32db820b3d | ||
|
|
7bde8a55b4 | ||
|
|
dd083b1e66 | ||
|
|
6199c17441 | ||
|
|
064eb2112d | ||
|
|
10578fb7ee | ||
|
|
ea57c6a212 | ||
|
|
d38c59d3a0 | ||
|
|
36f82eb364 | ||
|
|
9d01904145 | ||
|
|
bb74a811e8 | ||
|
|
d70961afa3 | ||
|
|
3c8bd9c0fb | ||
|
|
e0f37bdde9 | ||
|
|
b638262e12 | ||
|
|
9cd4e70a42 | ||
|
|
c7a4d7dc6f | ||
|
|
582503697e | ||
|
|
308a546cc7 | ||
|
|
3a8ea7de1e | ||
|
|
e2690480d9 | ||
|
|
a48a0499b7 | ||
|
|
1bc817c48a | ||
|
|
317c2f0bf4 | ||
|
|
c4aacb4348 | ||
|
|
978ed8da50 | ||
|
|
13b7202dbb | ||
|
|
70280b7346 | ||
|
|
f00653f216 | ||
|
|
70982f4807 | ||
|
|
b629bd409b | ||
|
|
68c7902bf3 | ||
|
|
721b4bbaf8 | ||
|
|
67aa570b4d | ||
|
|
4be1b75a89 | ||
|
|
05d499d99b | ||
|
|
432e09c37b | ||
|
|
c33683c9df | ||
|
|
b0ea5de0ae | ||
|
|
3e3744cb94 | ||
|
|
9a7fe334b5 | ||
|
|
11c5982a26 | ||
|
|
d91fdc0dcd | ||
|
|
5f4f7bec6c | ||
|
|
4a2ff61fc8 | ||
|
|
3606ef8814 | ||
|
|
734aa87904 | ||
|
|
367235dbd3 | ||
|
|
8050fbd3ca | ||
|
|
b4c664b979 | ||
|
|
22b66a71f4 | ||
|
|
2ed43c3c16 | ||
|
|
2b3983b2e2 | ||
|
|
b85fd74144 | ||
|
|
58565cb40f | ||
|
|
2e9ce77612 | ||
|
|
6925b89c13 | ||
|
|
7c75cc3af8 | ||
|
|
56c540ae13 | ||
|
|
da19b4461f | ||
|
|
c1c3674519 | ||
|
|
e5297fa81a | ||
|
|
7fcbbbe5b6 | ||
|
|
ea49f740c0 | ||
|
|
d29fcfa667 | ||
|
|
b1c8e3dc93 | ||
|
|
3c8b70f224 | ||
|
|
0600886d22 | ||
|
|
6af8045c46 | ||
|
|
582977f20e | ||
|
|
4c72e3c910 | ||
|
|
a0aa2e2458 | ||
|
|
f6a92d6909 | ||
|
|
11c6afa687 | ||
|
|
062207c1fe | ||
|
|
f49b70750a | ||
|
|
15be8fb329 | ||
|
|
0c96d9ecde | ||
|
|
e01134a9c0 | ||
|
|
770f709a24 | ||
|
|
e2a37141da | ||
|
|
5accd2f847 | ||
|
|
46eaabf722 | ||
|
|
807da66d87 | ||
|
|
06861f8577 | ||
|
|
44ee38a868 | ||
|
|
89652e9ff2 | ||
|
|
6f1f35217f | ||
|
|
22c6e81e68 | ||
|
|
ab57dfc5c7 | ||
|
|
8d609ed881 | ||
|
|
0e9a422335 | ||
|
|
5cdd2d4947 | ||
|
|
f946cddd45 | ||
|
|
d45aa0dae9 | ||
|
|
464c7e6b47 | ||
|
|
9e4468acb6 | ||
|
|
dcb49fe731 | ||
|
|
03259e67d9 | ||
|
|
0ea662f57f | ||
|
|
4b629b9b28 | ||
|
|
a8b5ebba18 | ||
|
|
c904d9f66c | ||
|
|
f52c5bc6da | ||
|
|
a074ea8ba6 | ||
|
|
3a3f55f9a2 | ||
|
|
490cabcbe3 | ||
|
|
367c5bcfb1 | ||
|
|
d10de8d7df | ||
|
|
41749db028 | ||
|
|
e30f302de9 | ||
|
|
d119ed10b9 | ||
|
|
9281289a1b | ||
|
|
1683c0c679 | ||
|
|
88a8b9569d | ||
|
|
18aaa03381 | ||
|
|
aa3474d06e | ||
|
|
0accab638f | ||
|
|
29b52bc12e | ||
|
|
5840cd3402 | ||
|
|
926ff0f4f8 | ||
|
|
13689e7eac | ||
|
|
e4ed4ad3a8 | ||
|
|
25e4072fef | ||
|
|
1e6037019e | ||
|
|
da083aaab4 | ||
|
|
7a7853d434 | ||
|
|
eebe12ca27 | ||
|
|
7aaade8780 | ||
|
|
cb185d4d44 | ||
|
|
3f691dc4f0 | ||
|
|
d4c33f71eb | ||
|
|
ad106a07ea | ||
|
|
2ad3a0a7f5 | ||
|
|
dc461d4de6 | ||
|
|
d1a9b50dfe | ||
|
|
9a0da8d011 | ||
|
|
2d7e3877e7 | ||
|
|
0248ae0a96 | ||
|
|
9fd27f3b2c | ||
|
|
4152fcc934 | ||
|
|
53c887a06a | ||
|
|
316e10baa0 | ||
|
|
8a71c6bc4a | ||
|
|
9b806de7b0 | ||
|
|
a14dadc228 | ||
|
|
ca850b3d30 | ||
|
|
c01dbbea0e | ||
|
|
b883307881 | ||
|
|
ab9bcb1e0b | ||
|
|
3dc22ff0b8 | ||
|
|
5e382e12ad | ||
|
|
103e55ff97 | ||
|
|
6140b3eee8 | ||
|
|
09574a69e9 | ||
|
|
c53f961e12 | ||
|
|
a1d370fc04 | ||
|
|
471b679d3f | ||
|
|
e60caa8648 | ||
|
|
ccfc8a8d30 | ||
|
|
6a7b7bec6a | ||
|
|
0926c48aea | ||
|
|
d10a9e40ed | ||
|
|
4df12ee5ea | ||
|
|
433294fb40 | ||
|
|
298fe50dd1 | ||
|
|
1717fffe8f | ||
|
|
41521913d5 | ||
|
|
e75ca5d2ff | ||
|
|
0d2081ed30 | ||
|
|
d6abdc2a55 | ||
|
|
0a0cf77461 | ||
|
|
a5c438068c | ||
|
|
d2c8839a69 | ||
|
|
21b560a3b9 | ||
|
|
b1d8de62d4 | ||
|
|
1e41857d37 | ||
|
|
63920e95d3 | ||
|
|
7856b2b7ee | ||
|
|
5daf34ba29 | ||
|
|
e513cbeaaa | ||
|
|
c782ba2429 | ||
|
|
50dae3f5d8 | ||
|
|
d3e6551b40 | ||
|
|
0e1d1a788d | ||
|
|
dfafce7f05 | ||
|
|
eb7381457a | ||
|
|
2f8baf9559 | ||
|
|
34cb03c7df | ||
|
|
d76ecb8a38 | ||
|
|
943c2a0bd9 | ||
|
|
a7552c8bb8 | ||
|
|
8cd78041a2 | ||
|
|
3fe3499ec2 | ||
|
|
70c49f67c4 | ||
|
|
308c316dbf | ||
|
|
c660b3a9aa | ||
|
|
642bb357d3 | ||
|
|
4978177584 | ||
|
|
ae8a69a840 | ||
|
|
383c2be9fc | ||
|
|
1cc4653672 | ||
|
|
6b6daba17a | ||
|
|
d8eb090a7a | ||
|
|
eb2e96f13b | ||
|
|
41201cbb96 | ||
|
|
151115ed10 | ||
|
|
7d4154e0d4 | ||
|
|
7a470daa26 | ||
|
|
a4e40d06ac | ||
|
|
875efd2a42 | ||
|
|
9ee0ac92c3 | ||
|
|
c7f554bebb | ||
|
|
6fe8d71e61 | ||
|
|
f6f24bce25 | ||
|
|
8b81151ec1 | ||
|
|
55033ed25e | ||
|
|
a829a60341 | ||
|
|
0a25e78964 | ||
|
|
dec1acdfb1 | ||
|
|
4f0970138b | ||
|
|
4707997aec | ||
|
|
ae5a4b5f4f | ||
|
|
5187b55a2e | ||
|
|
60078852bd | ||
|
|
580bacaf93 | ||
|
|
eb1ab920cf | ||
|
|
6c0aabd36e | ||
|
|
a3d2443b70 | ||
|
|
313ca172a5 | ||
|
|
ceb4e53f15 | ||
|
|
4510b4997a | ||
|
|
12cc43bd7c | ||
|
|
21069c107a | ||
|
|
93032afe0f | ||
|
|
f422fe13f4 | ||
|
|
ed551d1eb3 | ||
|
|
58cd4119a6 | ||
|
|
c8147ce3d4 | ||
|
|
00df171604 | ||
|
|
50ca38d4d0 | ||
|
|
e31e5c1a5b | ||
|
|
c80356a90a | ||
|
|
4909b039c0 | ||
|
|
dc8ee2718b | ||
|
|
8118f4ad18 | ||
|
|
de422a0d93 | ||
|
|
cbffa01014 | ||
|
|
f8688c33a0 | ||
|
|
6e0e56b85e | ||
|
|
7e81522ed4 | ||
|
|
0c8a76fceb | ||
|
|
35273abff7 | ||
|
|
6c1f3ea4bf | ||
|
|
5e261e0d7f | ||
|
|
53553ece6f | ||
|
|
33d47ff1c8 | ||
|
|
16b8657a47 | ||
|
|
264c834c2c | ||
|
|
28b05465ea | ||
|
|
b903e57ef9 | ||
|
|
d5ffba47a2 | ||
|
|
34b99bfede | ||
|
|
4f5aac8f50 | ||
|
|
fe53eeb010 | ||
|
|
67b6f69926 | ||
|
|
6bf62a3d4e | ||
|
|
54b911550f | ||
|
|
31a988877a | ||
|
|
88642d81c0 | ||
|
|
135e8d98e9 | ||
|
|
bd5c8fd403 | ||
|
|
3b112793aa | ||
|
|
2fc8d9ae4f | ||
|
|
afe63f02fa | ||
|
|
6aa744dff9 | ||
|
|
095b04d31c | ||
|
|
6136fe0c8b | ||
|
|
e2f3752018 | ||
|
|
5d0fdf01f3 | ||
|
|
cb4b6bc76d | ||
|
|
bb0f57b5ab | ||
|
|
c23981b97f | ||
|
|
c005fc6754 | ||
|
|
8d24048c26 | ||
|
|
ac1ae9f9db | ||
|
|
53e8a40e1b | ||
|
|
a7d803bc82 | ||
|
|
944ae100fa | ||
|
|
b68fd36476 | ||
|
|
74d530d65e | ||
|
|
b5cf71c7af | ||
|
|
8d663f80bd | ||
|
|
77257e2532 | ||
|
|
44d6719107 | ||
|
|
05ddaa6356 | ||
|
|
d8a6b6528a | ||
|
|
478c781822 | ||
|
|
93039252f2 | ||
|
|
3efc3ebe25 | ||
|
|
1f5824a55b | ||
|
|
d364c2f53e | ||
|
|
7d0bc98e3e | ||
|
|
85e0b26a53 | ||
|
|
c3f21c8af2 | ||
|
|
8bd2148ae4 | ||
|
|
2c74cef483 | ||
|
|
3a1911f5cd | ||
|
|
d871886ec5 | ||
|
|
146a2e8aae | ||
|
|
727784d90a | ||
|
|
67647bc51e | ||
|
|
3ce9d84669 | ||
|
|
af6ed6c296 | ||
|
|
3f65c0593f | ||
|
|
98e7941371 | ||
|
|
3fb5eb3ec9 | ||
|
|
497c748955 | ||
|
|
230247af17 | ||
|
|
bbea40833b | ||
|
|
146ca6a9c9 | ||
|
|
fb7e8c730c | ||
|
|
e5135ae67b | ||
|
|
f1b524460e | ||
|
|
9c9c910fa8 | ||
|
|
63330cbb84 | ||
|
|
5c6816f8ab | ||
|
|
4c0366e340 | ||
|
|
38e2e4e16a | ||
|
|
430b24c0f3 | ||
|
|
b22b187ce0 | ||
|
|
cc32d6cb98 | ||
|
|
66332ae9e2 | ||
|
|
b6dd3acfea | ||
|
|
b655e89af0 | ||
|
|
2879cf51cd | ||
|
|
725dabea88 | ||
|
|
35f133cacd | ||
|
|
b0e4f2c696 | ||
|
|
65c423917e | ||
|
|
f128af26ec | ||
|
|
1bf955baa8 | ||
|
|
cee2ff2641 | ||
|
|
819cd6c3e2 | ||
|
|
67da32857a | ||
|
|
6796145fa9 | ||
|
|
fea1bcc123 | ||
|
|
b6125b8063 | ||
|
|
ad397bb1b6 | ||
|
|
dc333f052d | ||
|
|
a77e120fc2 | ||
|
|
07166e591e | ||
|
|
a1aac43a4e | ||
|
|
cc69471576 | ||
|
|
ed8e01ea0c | ||
|
|
4fb847196c | ||
|
|
40ee2cb868 | ||
|
|
8d0b2edba2 | ||
|
|
3b6e10a1f9 | ||
|
|
4d4a849c9b | ||
|
|
58f94fe9ec | ||
|
|
ebff6f995a | ||
|
|
5a8a4bb25b | ||
|
|
6d8e781c72 | ||
|
|
834374d0f2 | ||
|
|
f0d17b1f86 | ||
|
|
5478879a37 | ||
|
|
4e2f50eee7 | ||
|
|
c47e25bef3 | ||
|
|
b5203b97bb | ||
|
|
a7ac9a0aa8 | ||
|
|
0540efa171 | ||
|
|
b3b274acf7 | ||
|
|
944ffcb788 | ||
|
|
865baf0d5f | ||
|
|
8b555503c1 | ||
|
|
11bb6bb2aa | ||
|
|
63864adbda | ||
|
|
0d89989c20 | ||
|
|
59d4821bdc | ||
|
|
24ecba3e9e | ||
|
|
d9f9b86996 | ||
|
|
c27febf172 | ||
|
|
d18af9daf8 | ||
|
|
4813a35eec | ||
|
|
5bd33084dd | ||
|
|
939c54792f | ||
|
|
28f6f58dd7 | ||
|
|
27fd1d11b8 | ||
|
|
39355d3bd6 | ||
|
|
1582b486db | ||
|
|
e4d58dd9cb | ||
|
|
f417d640e0 | ||
|
|
f79e16f48d | ||
|
|
365daab33c | ||
|
|
62fceaaa3c | ||
|
|
5af78fb18a | ||
|
|
2dae632d24 | ||
|
|
680e460ecd | ||
|
|
07e715bb6d | ||
|
|
e255bc0874 | ||
|
|
0d0129e7c3 | ||
|
|
3ca24bd45c | ||
|
|
a627363afa | ||
|
|
bcf6ca9e52 | ||
|
|
561579a7d6 |
No files matched your search
@@ -0,0 +1,103 @@
|
||||
### Manual build Box86 with Github Action
|
||||
name: Custom build Box86
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
platform:
|
||||
description: 'Target platform name'
|
||||
required: true
|
||||
default: 'GENERIC_ARM'
|
||||
type: choice
|
||||
options:
|
||||
- I386
|
||||
- GENERIC_ARM
|
||||
- A64
|
||||
- GAMESHELL
|
||||
- ODROIDXU4
|
||||
- PANDORA
|
||||
- PHYTIUM
|
||||
- PYRA
|
||||
- RK3288
|
||||
- RK3399
|
||||
- RPI4
|
||||
- RPI4ARM64
|
||||
- SD845
|
||||
- SD888
|
||||
- ADLINK
|
||||
- PHYTIUM
|
||||
build_type:
|
||||
description: 'Build type'
|
||||
required: true
|
||||
default: 'RelWithDebInfo'
|
||||
type: choice
|
||||
options:
|
||||
- RelWithDebInfo
|
||||
- Release
|
||||
- Debug
|
||||
- MinSizeRel
|
||||
dynarec:
|
||||
description: 'Enable dynarec'
|
||||
required: false
|
||||
default: 'true'
|
||||
type: boolean
|
||||
trace:
|
||||
description: 'Enable trace'
|
||||
required: false
|
||||
default: 'false'
|
||||
type: boolean
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: "Checkout Box86 Repository"
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: "Environment preparation"
|
||||
run: |
|
||||
sudo apt-get update
|
||||
|
||||
if [[ ${{ github.event.inputs.platform }} != 'I386' && ${{ github.event.inputs.platform }} != 'GENERIC_ARM' ]]; then
|
||||
echo "BOX86_PLATFORM_MARCRO=-D${{ github.event.inputs.platform }}=1" >> $GITHUB_ENV
|
||||
echo "BOX86_COMPILER=arm-linux-gnueabihf-gcc" >> $GITHUB_ENV
|
||||
sudo apt-get -y install git gcc-arm-linux-gnueabihf cmake make python3
|
||||
else
|
||||
if [[ ${{ github.event.inputs.platform }} == 'I386' ]]; then
|
||||
echo "BOX86_PLATFORM_MARCRO=-DLD80BITS=1 -DNOALIGN=1" >> $GITHUB_ENV
|
||||
echo "BOX86_COMPILER=/bin/i686-linux-gnu-gcc-10" >> $GITHUB_ENV
|
||||
sudo apt-get -y install git libc6-dev-i386-amd64-cross gcc-10-i686-linux-gnu cmake make python3
|
||||
else
|
||||
echo "BOX86_PLATFORM_MARCRO=-DCMAKE_C_FLAGS=-marm" >> $GITHUB_ENV
|
||||
echo "BOX86_COMPILER=arm-linux-gnueabihf-gcc" >> $GITHUB_ENV
|
||||
sudo apt-get -y install git gcc-arm-linux-gnueabihf cmake make python3
|
||||
fi
|
||||
fi
|
||||
|
||||
- name: "Display Build info"
|
||||
run: |
|
||||
echo "CMake Platform Macro: ${{ env.BOX86_PLATFORM_MARCRO }}"
|
||||
echo "CMake C Compiler: ${{ env.BOX86_COMPILER }}"
|
||||
echo "Build type: ${{ github.event.inputs.build_type }}"
|
||||
echo "Dynarec Enabled: ${{ github.event.inputs.dynarec }}"
|
||||
echo "Trace Enabled: ${{ github.event.inputs.trace }}"
|
||||
|
||||
- name: "Build Box86"
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_C_COMPILER=${{ env.BOX86_COMPILER }} ${{ env.BOX86_PLATFORM_MARCRO }}\
|
||||
-DCMAKE_BUILD_TYPE=${{ github.event.inputs.build_type }}\
|
||||
-DARM_DYNAREC:BOOL=${{ github.event.inputs.dynarec }}\
|
||||
-DHAVE_TRACE:BOOL=${{ github.event.inputs.trace }}\
|
||||
-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON
|
||||
make -j$(nproc) VERBOSE=1
|
||||
|
||||
- name: "Upload Artifact"
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: box86-${{ github.event.inputs.platform }}-${{ github.event.inputs.build_type }}
|
||||
path: build/box86
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
### Auto build Box86 and release its binary with Github Action
|
||||
name: Build and Release Box86
|
||||
|
||||
on:
|
||||
on:
|
||||
workflow_dispatch:
|
||||
release:
|
||||
push:
|
||||
@@ -10,16 +10,16 @@ on:
|
||||
- "**/*.h"
|
||||
- "**/*.S"
|
||||
- "**/*.py"
|
||||
- "CMakeList.txt"
|
||||
- "CMakeLists.txt"
|
||||
- "**/*.yml"
|
||||
pull_request:
|
||||
pull_request:
|
||||
types: [assigned, opened, synchronize, reopened]
|
||||
paths:
|
||||
- "**/*.c"
|
||||
- "**/*.h"
|
||||
- "**/*.S"
|
||||
- "**/*.py"
|
||||
- "CMakeList.txt"
|
||||
- "CMakeLists.txt"
|
||||
- "**/*.yml"
|
||||
|
||||
jobs:
|
||||
@@ -27,28 +27,50 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [I386, OTHER_ARM, PANDORA, PYRA, GAMESHELL, RPI4, RPI4ARM64, ODROID, RK3399, RK3288, A64, SD845, PHYTIUM]
|
||||
platform: [I386, OTHER_ARM, PANDORA, PYRA, GAMESHELL, RPI4, RPI4ARM64, ODROIDXU4, RK3399, RK3288, A64, SD845, SD888, ADLINK, PHYTIUM, ANDROID]
|
||||
type: [Release, Trace]
|
||||
os: [ubuntu-latest]
|
||||
|
||||
include:
|
||||
- platform: TEGRAX1
|
||||
type: Release
|
||||
os: ubuntu-22.04
|
||||
- platform: TEGRAX1
|
||||
type: Trace
|
||||
os: ubuntu-22.04
|
||||
- platform: TEGRAX1ARM32
|
||||
type: Release
|
||||
os: ubuntu-22.04
|
||||
- platform: TEGRAX1ARM32
|
||||
type: Trace
|
||||
os: ubuntu-22.04
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: "Checkout Box86 Repository"
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: "Environment preparation"
|
||||
run: |
|
||||
sudo apt-get update
|
||||
|
||||
if [[ ${{ matrix.platform }} != 'I386' && ${{ matrix.platform }} != 'OTHER_ARM' ]]; then
|
||||
echo "BOX86_PLATFORM_MARCRO=-D${{ matrix.platform }}=1" >> $GITHUB_ENV
|
||||
echo "BOX86_COMPILER=arm-linux-gnueabihf-gcc" >> $GITHUB_ENV
|
||||
sudo apt-get -y install git gcc-arm-linux-gnueabihf cmake make python3
|
||||
sudo apt-get -y install git cmake make python3
|
||||
if [[ ${{ matrix.platform }} == 'ANDROID' ]]; then
|
||||
wget https://dl.google.com/android/repository/android-ndk-r25b-linux.zip
|
||||
unzip android-ndk-r25b-linux.zip
|
||||
echo "BOX86_COMPILER=$PWD/android-ndk-r25b/toolchains/llvm/prebuilt/linux-x86_64/bin/armv7a-linux-androideabi31-clang" >> $GITHUB_ENV
|
||||
echo "BOX86_PLATFORM_MARCRO=-DANDROID=1 -DARM_DYNAREC=ON -DBAD_SIGNAL=1" >> $GITHUB_ENV
|
||||
else
|
||||
sudo apt-get -y install gcc-arm-linux-gnueabihf
|
||||
echo "BOX86_COMPILER=arm-linux-gnueabihf-gcc" >> $GITHUB_ENV
|
||||
echo "BOX86_PLATFORM_MARCRO=-D${{ matrix.platform }}=1" >> $GITHUB_ENV
|
||||
fi
|
||||
else
|
||||
if [[ ${{ matrix.platform }} == 'I386' ]]; then
|
||||
echo "BOX86_PLATFORM_MARCRO=-DLD80BITS=1 -DNOALIGN=1" >> $GITHUB_ENV
|
||||
echo "BOX86_COMPILER=/bin/i686-linux-gnu-gcc-10" >> $GITHUB_ENV
|
||||
sudo apt-get -y install git libc6-dev-i386-amd64-cross gcc-10-i686-linux-gnu cmake make python3
|
||||
ls /bin/*gcc*
|
||||
else
|
||||
echo BOX86_PLATFORM_MARCRO="-DARM_DYNAREC=ON -DCMAKE_C_FLAGS=-marm" >> $GITHUB_ENV
|
||||
echo "BOX86_COMPILER=arm-linux-gnueabihf-gcc" >> $GITHUB_ENV
|
||||
@@ -63,26 +85,36 @@ jobs:
|
||||
echo BOX86_BUILD_TYPE=RelWithDebInfo >> $GITHUB_ENV
|
||||
echo BOX86_HAVE_TRACE=1 >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
|
||||
- name: "Display Build info"
|
||||
run: |
|
||||
echo "CMake Platform Macro: ${{ env.BOX86_PLATFORM_MARCRO }}"
|
||||
echo "CMake C Compiler: ${{ env.BOX86_COMPILER }}"
|
||||
echo "Build type: ${{ env.BOX86_BUILD_TYPE }}"
|
||||
echo "Trace Enabled: ${{ env.BOX86_HAVE_TRACE }}"
|
||||
|
||||
|
||||
- name: "Build Box86"
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_C_COMPILER=${{ env.BOX86_COMPILER }} ${{ env.BOX86_PLATFORM_MARCRO }} -DCMAKE_BUILD_TYPE=${{ env.BOX86_BUILD_TYPE }} -DHAVE_TRACE=${{ env.BOX86_HAVE_TRACE }} -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON
|
||||
cmake .. -DCMAKE_C_COMPILER=${{ env.BOX86_COMPILER }}\
|
||||
${{ env.BOX86_PLATFORM_MARCRO }}\
|
||||
-DCMAKE_BUILD_TYPE=${{ env.BOX86_BUILD_TYPE }}\
|
||||
-DHAVE_TRACE=${{ env.BOX86_HAVE_TRACE }}\
|
||||
-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON
|
||||
make -j$(nproc) VERBOSE=1
|
||||
|
||||
|
||||
- name: "Test Box86"
|
||||
if: ${{ matrix.platform == 'I386' }}
|
||||
run: |
|
||||
cd build
|
||||
ctest -j$(nproc)
|
||||
|
||||
- name: "Upload Artifact"
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: box86-${{ matrix.platform }}-${{ matrix.type }}
|
||||
path: build/box86
|
||||
|
||||
|
||||
|
||||
|
||||
+2
-1
@@ -5,4 +5,5 @@ build*/
|
||||
src/git_head.h
|
||||
backup/
|
||||
box86_update.sh
|
||||
restore_backup.sh
|
||||
restore_backup.sh
|
||||
.cache
|
||||
+352
-67
@@ -1,33 +1,58 @@
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
option(PANDORA "Set to ON if targeting an OpenPandora device" ${PANDORA})
|
||||
option(PYRA "Set to ON if targeting an OpenPandora device" ${PYRA})
|
||||
option(RPI2 "Set to ON if targeting an RaspberryPI2 device" ${RPI2})
|
||||
option(RPI3 "Set to ON if targeting an RaspberryPI3 device" ${RPI3})
|
||||
option(RPI4 "Set to ON if targeting an RaspberryPI4 device" ${RPI4})
|
||||
option(RPI3ARM64 "Set to ON if targeting an RaspberryPI3 device with multiarch arm64 and armhf" ${RPI3ARM64})
|
||||
option(RPI4ARM64 "Set to ON if targeting an RaspberryPI4 device with multiarch arm64 and armhf" ${RPI4ARM64})
|
||||
option(GOA_CLONE "Set to ON if targeting GO Advance clones, like RG351p/v, Gameforce Chi, RGB10..." ${GOA_CLONE})
|
||||
option(RK3288 "Set to ON if targeting an Rockchip RK3288 based device" ${RK3288})
|
||||
option(RK3399 "Set to ON if targeting an Rockchip RK3399 based device" ${RK3399})
|
||||
option(RK3588 "Set to ON if targeting an Rockchip RK3588 / RK3588S based device" ${RK3588})
|
||||
option(ODROIDN2 "Set to ON if targeting an ODROID-N2 device" ${ODROIDN2})
|
||||
option(TEGRAX1 "Set to ON if targeting an Tegra X1 (ARM64) based device" ${TEGRAX1})
|
||||
option(TEGRAX1ARM32 "Set to ON if targeting an Tegra X1 (ARM32) based device" ${TEGRAX1ARM32})
|
||||
option(TEGRA_T194 "Set to ON if targeting an Tegra Xavier based device" ${TEGRA_T194})
|
||||
option(TEGRA_T234 "Set to ON if targeting an Tegra Orin based device" ${TEGRA_T234})
|
||||
option(PHYTIUM "Set to ON if targeting an Phytium (D2000 or FT2000/4) based device" ${PHYTIUM})
|
||||
option(GAMESHELL "Set to ON if targeting a GameShell device" ${GAMESHELL})
|
||||
option(ODROID "Set to ON if targeting an ODroid device" ${ODROID})
|
||||
option(ODROIDXU4 "Set to ON if targeting an ODROID-XU4 device" ${ODROIDXU4})
|
||||
option(POWER9 "Set to ON if targeting a POWER9 processor" ${POWER9})
|
||||
option(SD845 "Set to ON if targeting a Snapragon 845 based device" ${SD845})
|
||||
option(SD845 "Set to ON if targeting a Snapdragon 845 based device" ${SD845})
|
||||
option(SD865 "Set to ON if targeting a Snapdragon 865 based device" ${SD865})
|
||||
option(SD888 "Set to ON if targeting a Snapdragon 888 based device" ${SD888})
|
||||
option(ADLINK "Set to ON if targeting an ADLink AmpereAltra based device" ${ADLINK})
|
||||
option(A64 "Set to ON if targeting an Allwinner A64 based device" ${A64})
|
||||
option(ARM64 "Set to ON if targeting a generic ARM64 based device" ${ARM64})
|
||||
option(BAD_SIGNAL "Set to ON to activate the workaround for incoherent si_info on SIGSEGV" ${BAD_SIGNAL})
|
||||
option(LX2160A "Set to ON if targeting an LX2160A based device" ${LX2160A})
|
||||
option(ANDROID "Set to ON if targeting an Android device" ${ANDROID})
|
||||
option(TERMUX "Set to ON if targeting an Android device with Termux" ${TERMUX})
|
||||
option(USE_CCACHE "Set to ON to use ccache if present in the system" ${USE_CCACHE})
|
||||
option(HAVE_TRACE "Set to ON to have Trace ability (needs ZydisInfo library)" ${HAVE_TRACE})
|
||||
option(NOLOADADDR "Set to ON to avoid fixing the load address of Box86" ${NO_LOADAADR})
|
||||
option(NOGETCLOCK "Set to ON to avoid using clock_gettime with CLOCK_MONOTONIC_COARSE for RDTSC opcode (use gltimeofday instead)" ${NOGETCLOCK})
|
||||
option(NOGIT "Set to ON if not building from a git clone repo (like when building from a zip download from github)" ${NOGIT})
|
||||
if(PANDORA OR PYRA OR RPI2 OR RPI3 OR RPI4 OR GAMESHELL OR ODROID OR GOA_CLONE OR RK3288 OR RK3399 OR RPI4ARM64 OR PHYTIUM OR SD845 OR A64)
|
||||
option(NO_LIB_INSTALL "Set ON to not install a few x86 libs that are used by many program" ${NO_LIB_INSTALL})
|
||||
option(NO_CONF_INSTALL "Set ON to not install config files" ${NO_CONF_INSTALL})
|
||||
|
||||
if(PANDORA OR PYRA OR RPI2 OR RPI3 OR RPI4 OR GAMESHELL OR ODROIDXU4 OR GOA_CLONE OR RK3288 OR RK3399 OR ODROIDN2 OR TEGRAX1 OR TEGRAX1ARM32 OR TEGRA_T194 OR TEGRA_T234 OR RPI3ARM64 OR RPI4ARM64 OR PHYTIUM OR SD845 OR SD865 OR SD888 OR ADLINK OR A64 OR LX2160A OR ARM64 OR RK3588)
|
||||
set(LD80BITS OFF CACHE BOOL "")
|
||||
set(NOALIGN OFF CACHE BOOL "")
|
||||
set(ARM_DYNAREC ON CACHE BOOL "")
|
||||
if(RK3588)
|
||||
set(BAD_SIGNAL ON CACHE BOOL "")
|
||||
endif()
|
||||
endif()
|
||||
if(TERMUX)
|
||||
set(ANDROID ON CACHE BOOL "")
|
||||
set(TERMUX_PATH "/data/data/com.termux/files")
|
||||
endif()
|
||||
if(ANDROID)
|
||||
set(NOLOADADDR ON CACHE BOOL "")
|
||||
set(BAD_SIGNAL ON CACHE BOOL "")
|
||||
endif()
|
||||
option(LD80BITS "Set to ON if host device have 80bits long double (i.e. i386)" ${LD80BITS})
|
||||
option(NOALIGN "Set to ON if host device doesn't need re-align (i.e. i386)" ${NOALIGN})
|
||||
@@ -51,16 +76,30 @@ else()
|
||||
set(PYTHON_EXECUTABLE ${Python3_EXECUTABLE} CACHE INTERNAL "The Python3 executable" FORCE)
|
||||
endif()
|
||||
|
||||
if(RK3399 OR RPI4ARM64 OR PHYTIUM OR SD845 OR A64)
|
||||
set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
|
||||
#set(CMAKE_ASM_COMPILER arm-linux-gnueabihf-as) #will use gcc in fact
|
||||
set(CMAKE_C_COMPILER_TARGET arm-linux-gnueabihf)
|
||||
cmake_host_system_information(RESULT CMAKE_HOST_SYSTEM_PROCESSOR QUERY OS_PLATFORM)
|
||||
|
||||
if("${CMAKE_HOST_SYSTEM_PROCESSOR}" STREQUAL "aarch64" AND (RK3399 OR ODROIDN2 OR TEGRAX1 OR TEGRA_T194 OR TEGRA_T234 OR RPI3ARM64 OR RPI4ARM64 OR PHYTIUM OR SD845 OR SD888 OR ADLINK OR A64 OR LX2160A OR RK3588 OR ARM64))
|
||||
set(COMPILER_TRIPLE arm-linux-gnueabihf-gcc)
|
||||
find_program(COMPILER_FOUND ${COMPILER_TRIPLE})
|
||||
|
||||
if(COMPILER_FOUND)
|
||||
set(CMAKE_C_COMPILER ${COMPILER_FOUND})
|
||||
else()
|
||||
message(STATUS "Cross compiler ${COMPILER_TRIPLE} not found, using CC or -DCMAKE_C_COMPILER")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
project(box86 C ASM)
|
||||
|
||||
enable_testing()
|
||||
|
||||
string(COMPARE EQUAL "${CMAKE_SYSTEM_PROCESSOR}" "i686" _x86)
|
||||
string(COMPARE EQUAL "${CMAKE_SYSTEM_PROCESSOR}" "x86_64" _x86_64)
|
||||
string(COMPARE EQUAL "${CMAKE_SYSTEM_PROCESSOR}" "aarch64" _aarch64)
|
||||
string(COMPARE EQUAL "${CMAKE_SYSTEM_PROCESSOR}" "armhf" _armhf)
|
||||
string(COMPARE EQUAL "${CMAKE_SYSTEM_PROCESSOR}" "arm" _arm)
|
||||
string(COMPARE EQUAL "${CMAKE_SYSTEM_PROCESSOR}" "armv8l" _armv8l)
|
||||
|
||||
set(default_build_type "RelwithDebInfo")
|
||||
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||
message(STATUS "Setting build type to '${default_build_type}' as none was specified.")
|
||||
@@ -71,6 +110,7 @@ endif()
|
||||
if(PANDORA)
|
||||
add_definitions(-DPANDORA)
|
||||
#add_definitions(-mcpu=cortex-a8 -mfpu=neon -mfloat-abi=softfp -ftree-vectorize -fsingle-precision-constant -ffast-math)
|
||||
set(CMAKE_ASM_FLAGS "-marm -mcpu=cortex-a8 -mfpu=neon -mfloat-abi=softfp")
|
||||
elseif(GAMESHELL)
|
||||
add_definitions(-DGAMESHELL)
|
||||
add_definitions(-marm -mcpu=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard)
|
||||
@@ -94,15 +134,20 @@ elseif(RPI4)
|
||||
add_definitions(-DRPI4)
|
||||
add_definitions(-marm -march=armv8-a+crc -mtune=cortex-a72 -mfpu=neon-fp-armv8 -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-marm -march=armv8-a+crc -mtune=cortex-a72 -mfpu=neon-fp-armv8 -mfloat-abi=hard")
|
||||
elseif(RPI3ARM64)
|
||||
add_definitions(-DRPI)
|
||||
add_definitions(-DRPI3ARM64)
|
||||
add_definitions(-marm -march=armv8-a+crc -mtune=cortex-a53 -mfpu=neon-fp-armv8 -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-marm -march=armv8-a+crc -mtune=cortex-a53 -mfpu=neon-fp-armv8 -mfloat-abi=hard")
|
||||
elseif(RPI4ARM64)
|
||||
add_definitions(-DRPI)
|
||||
add_definitions(-DRPI4ARM64)
|
||||
add_definitions(-marm -march=armv8-a+crc -mtune=cortex-a72 -mfpu=neon-fp-armv8 -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-marm -march=armv8-a+crc -mtune=cortex-a72 -mfpu=neon-fp-armv8 -mfloat-abi=hard")
|
||||
elseif(ODROID)
|
||||
add_definitions(-DODROID)
|
||||
add_definitions(-mcpu=cortex-a9 -mfpu=neon-vfpv4 -mfloat-abi=hard -marm)
|
||||
set(CMAKE_ASM_FLAGS "-marm -mcpu=cortex-a9 -mfpu=neon-vfpv4 -mfloat-abi=hard")
|
||||
elseif(ODROIDXU4)
|
||||
add_definitions(-DODROIDXU4)
|
||||
add_definitions(-marm -mcpu=cortex-a15.cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-marm -mcpu=cortex-a15.cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard")
|
||||
elseif(RK3288)
|
||||
add_definitions(-DRK3288)
|
||||
add_definitions(-mcpu=cortex-a17 -mfpu=neon -mfloat-abi=hard -marm)
|
||||
@@ -111,6 +156,19 @@ elseif(SD845)
|
||||
add_definitions(-DSD845)
|
||||
add_definitions(-marm -march=armv8.2-a+simd+crypto -mtune=cortex-a75.cortex-a55 -mfpu=neon-fp-armv8 -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-marm -march=armv8.2-a+simd+crypto -mtune=cortex-a75.cortex-a55 -mfpu=neon-fp-armv8 -mfloat-abi=hard")
|
||||
elseif(SD865)
|
||||
add_definitions(-DSD865)
|
||||
#note that cortex-a77.cortex-a55 is not supported, so fall back to a76 instead
|
||||
add_definitions(-marm -march=armv8.2-a+simd+crypto -mtune=cortex-a76.cortex-a55 -mfpu=neon-fp-armv8 -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-marm -march=armv8.2-a+simd+crypto -mtune=cortex-a76.cortex-a55 -mfpu=neon-fp-armv8 -mfloat-abi=hard")
|
||||
elseif(SD888)
|
||||
add_definitions(-DSD888)
|
||||
add_definitions(-marm -march=armv8.4-a+simd+crypto -mfpu=neon-fp-armv8 -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-marm -march=armv8.4-a+simd+crypto -mfpu=neon-fp-armv8 -mfloat-abi=hard")
|
||||
elseif(ADLINK)
|
||||
add_definitions(-DADLINK)
|
||||
add_definitions(-marm -mcpu=neoverse-n1 -mfpu=neon-fp-armv8 -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-marm -mcpu=neoverse-n1 -mfpu=neon-fp-armv8 -mfloat-abi=hard")
|
||||
elseif(A64)
|
||||
add_definitions(-DA64)
|
||||
add_definitions(-marm -march=armv8-a+crc+simd+crypto -mcpu=cortex-a53+crypto -mfpu=neon-fp-armv8 -mfloat-abi=hard)
|
||||
@@ -123,13 +181,57 @@ elseif(RK3399)
|
||||
add_definitions(-DRK3399)
|
||||
add_definitions(-pipe -march=armv8-a+crc+simd+crypto -mcpu=cortex-a72+crypto -mfpu=neon-fp-armv8 -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8-a+crc+simd+crypto -mcpu=cortex-a72+crypto -mfpu=neon-fp-armv8 -mfloat-abi=hard")
|
||||
elseif(RK3588)
|
||||
add_definitions(-DRK3588)
|
||||
add_definitions(-pipe -mcpu=cortex-a76.cortex-a55+crypto -mfpu=neon-fp-armv8 -mfloat-abi=hard)
|
||||
add_definitions(-DBAD_SIGNAL)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -mcpu=cortex-a76.cortex-a55+crypto -mfpu=neon-fp-armv8 -mfloat-abi=hard")
|
||||
elseif(ARM64)
|
||||
add_definitions(-DARM64)
|
||||
add_definitions(-pipe -march=armv8-a+crc+simd+crypto -mfpu=neon-fp-armv8 -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8-a+crc+simd+crypto -mfpu=neon-fp-armv8 -mfloat-abi=hard")
|
||||
elseif(ODROIDN2)
|
||||
add_definitions(-DODROIDN2)
|
||||
add_definitions(-pipe -march=armv8-a+crc+simd+crypto -mcpu=cortex-a73.cortex-a53+crypto -mfpu=crypto-neon-fp-armv8 -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8-a+crc+simd+crypto -mcpu=cortex-a73.cortex-a53+crypto -mfpu=crypto-neon-fp-armv8 -mfloat-abi=hard")
|
||||
elseif(TEGRAX1)
|
||||
add_definitions(-DTEGRAX1)
|
||||
add_definitions(-marm -pipe -march=armv8-a+crc -mcpu=cortex-a57 -mfpu=neon-fp-armv8 -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-marm -pipe -march=armv8-a+crc -mcpu=cortex-a57 -mfpu=neon-fp-armv8 -mfloat-abi=hard")
|
||||
elseif(TEGRAX1ARM32)
|
||||
add_definitions(-DTEGRAX1ARM32)
|
||||
add_definitions(-marm -pipe -march=armv8-a+crc -mcpu=cortex-a57 -mfpu=neon-fp-armv8 -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-marm -pipe -march=armv8-a+crc -mcpu=cortex-a57 -mfpu=neon-fp-armv8 -mfloat-abi=hard")
|
||||
elseif(TEGRA_T194)
|
||||
add_definitions(-DTEGRA_T194)
|
||||
add_definitions(-marm -pipe -march=armv8.2-a+fp16+simd+crypto+predres -mfpu=crypto-neon-fp-armv8 -mcpu=cortex-a76+crypto -mtune=cortex-a76 -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-marm -pipe -march=armv8.2-a+fp16+simd+crypto+predres -mfpu=crypto-neon-fp-armv8 -mcpu=cortex-a76+crypto -mtune=cortex-a76 -mfloat-abi=hard")
|
||||
elseif(TEGRA_T234)
|
||||
add_definitions(-DTEGRA_T234)
|
||||
add_definitions(-marm -pipe -march=armv8.2-a+fp16+simd+crypto+predres -mfpu=crypto-neon-fp-armv8 -mcpu=cortex-a78ae+crypto -mtune=cortex-a78ae -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-marm -pipe -march=armv8.2-a+fp16+simd+crypto+predres -mfpu=crypto-neon-fp-armv8 -mcpu=cortex-a78ae+crypto -mtune=cortex-a78ae -mfloat-abi=hard")
|
||||
elseif(PHYTIUM)
|
||||
add_definitions(-DPHYTIUM)
|
||||
add_definitions(-pipe -march=armv8.1-a+simd+crypto -mfpu=neon-fp-armv8 -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8.1-a+simd+crypto -mfpu=neon-fp-armv8 -mfloat-abi=hard")
|
||||
elseif(LX2160A)
|
||||
add_definitions(-DLX2160A)
|
||||
add_definitions(-pipe -march=armv8-a+crypto+crc -mcpu=cortex-a72+crypto -mfpu=neon-fp-armv8 -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8-a+crypto+crc -mcpu=cortex-a72+crypto -mfpu=neon-fp-armv8 -mfloat-abi=hard")
|
||||
elseif(ARM_DYNAREC)
|
||||
#if DYNAREC is selected alone, without any arch
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv7-a+simd -mfpu=neon")
|
||||
if(NOT ANDROID)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv7-a+simd -mfpu=neon")
|
||||
endif()
|
||||
endif()
|
||||
if(ANDROID)
|
||||
add_definitions(-DANDROID)
|
||||
endif()
|
||||
if(TERMUX)
|
||||
add_definitions(-DTERMUX)
|
||||
endif()
|
||||
if(BAD_SIGNAL)
|
||||
add_definitions(-DBAD_SIGNAL)
|
||||
endif()
|
||||
|
||||
if(POWER9)
|
||||
@@ -148,6 +250,12 @@ else()
|
||||
set(BOX86 box86)
|
||||
endif()
|
||||
|
||||
try_compile(HAVE_ST_INO ${CMAKE_BINARY_DIR}/compile_tests ${CMAKE_SOURCE_DIR}/tests/test_st_ino.c)
|
||||
|
||||
if(HAVE_ST_INO)
|
||||
message("stat64 has __st_info field")
|
||||
add_definitions(-DHAVE_ST_INO)
|
||||
endif()
|
||||
|
||||
set(BOX86_ELF_ADDRESS "0x62800000")
|
||||
|
||||
@@ -157,6 +265,7 @@ endif()
|
||||
|
||||
if(NOALIGN)
|
||||
add_definitions(-DNOALIGN)
|
||||
add_definitions(-pipe -march=core2 -msse2)
|
||||
endif()
|
||||
|
||||
if(HAVE_TRACE)
|
||||
@@ -223,6 +332,7 @@ set(ELFLOADER_SRC
|
||||
"${BOX86_ROOT}/src/box86context.c"
|
||||
"${BOX86_ROOT}/src/build_info.c"
|
||||
"${BOX86_ROOT}/src/custommem.c"
|
||||
"${BOX86_ROOT}/src/mallochook.c"
|
||||
"${BOX86_ROOT}/src/tools/bridge.c"
|
||||
"${BOX86_ROOT}/src/tools/pathcoll.c"
|
||||
"${BOX86_ROOT}/src/tools/fileutils.c"
|
||||
@@ -230,6 +340,8 @@ set(ELFLOADER_SRC
|
||||
"${BOX86_ROOT}/src/tools/box86stack.c"
|
||||
"${BOX86_ROOT}/src/tools/my_cpuid.c"
|
||||
"${BOX86_ROOT}/src/tools/gtkclass.c"
|
||||
"${BOX86_ROOT}/src/tools/rcfile.c"
|
||||
"${BOX86_ROOT}/src/tools/rbtree.c"
|
||||
"${BOX86_ROOT}/src/tools/wine_tools.c"
|
||||
"${BOX86_ROOT}/src/elfs/elfloader.c"
|
||||
"${BOX86_ROOT}/src/elfs/elfparser.c"
|
||||
@@ -239,10 +351,8 @@ set(ELFLOADER_SRC
|
||||
"${BOX86_ROOT}/src/librarian/dictionnary.c"
|
||||
"${BOX86_ROOT}/src/librarian/symbols.c"
|
||||
"${BOX86_ROOT}/src/librarian/globalsymbols.c"
|
||||
"${BOX86_ROOT}/src/emu/x86compstrings.c"
|
||||
"${BOX86_ROOT}/src/emu/x86emu.c"
|
||||
"${BOX86_ROOT}/src/emu/x86run.c"
|
||||
"${BOX86_ROOT}/src/emu/x86run66.c"
|
||||
"${BOX86_ROOT}/src/emu/x86run660f.c"
|
||||
"${BOX86_ROOT}/src/emu/x86run_private.c"
|
||||
"${BOX86_ROOT}/src/emu/x86syscall.c"
|
||||
"${BOX86_ROOT}/src/emu/x86primop.c"
|
||||
@@ -250,10 +360,11 @@ set(ELFLOADER_SRC
|
||||
"${BOX86_ROOT}/src/emu/x86int3.c"
|
||||
"${BOX86_ROOT}/src/emu/x86tls.c"
|
||||
"${BOX86_ROOT}/src/emu/x87emu_private.c"
|
||||
"${BOX86_ROOT}/src/emu/x87run.c"
|
||||
"${BOX86_ROOT}/src/libtools/auxval.c"
|
||||
"${BOX86_ROOT}/src/libtools/myalign.c"
|
||||
"${BOX86_ROOT}/src/libtools/myalign64.c"
|
||||
"${BOX86_ROOT}/src/libtools/myalignsys64.c"
|
||||
"${BOX86_ROOT}/src/libtools/stat64_helper.c"
|
||||
"${BOX86_ROOT}/src/libtools/myfts.c"
|
||||
"${BOX86_ROOT}/src/libtools/sdl1rwops.c"
|
||||
"${BOX86_ROOT}/src/libtools/sdl2rwops.c"
|
||||
@@ -267,12 +378,42 @@ if(NOT ANDROID)
|
||||
list(APPEND ELFLOADER_SRC "${BOX86_ROOT}/src/libtools/obstack.c")
|
||||
endif()
|
||||
|
||||
set(INTERPRETER
|
||||
"${BOX86_ROOT}/src/emu/x86run.c"
|
||||
"${BOX86_ROOT}/src/emu/x86run0f.c"
|
||||
"${BOX86_ROOT}/src/emu/x86run64.c"
|
||||
"${BOX86_ROOT}/src/emu/x86run640f.c"
|
||||
"${BOX86_ROOT}/src/emu/x86run6466.c"
|
||||
"${BOX86_ROOT}/src/emu/x86run6467.c"
|
||||
"${BOX86_ROOT}/src/emu/x86run66.c"
|
||||
"${BOX86_ROOT}/src/emu/x86run660f.c"
|
||||
"${BOX86_ROOT}/src/emu/x86run66d9.c"
|
||||
"${BOX86_ROOT}/src/emu/x86run66dd.c"
|
||||
"${BOX86_ROOT}/src/emu/x86run66f20f.c"
|
||||
"${BOX86_ROOT}/src/emu/x86run67.c"
|
||||
"${BOX86_ROOT}/src/emu/x86run6766.c"
|
||||
"${BOX86_ROOT}/src/emu/x86rund8.c"
|
||||
"${BOX86_ROOT}/src/emu/x86rund9.c"
|
||||
"${BOX86_ROOT}/src/emu/x86runda.c"
|
||||
"${BOX86_ROOT}/src/emu/x86rundb.c"
|
||||
"${BOX86_ROOT}/src/emu/x86rundc.c"
|
||||
"${BOX86_ROOT}/src/emu/x86rundd.c"
|
||||
"${BOX86_ROOT}/src/emu/x86runde.c"
|
||||
"${BOX86_ROOT}/src/emu/x86rundf.c"
|
||||
"${BOX86_ROOT}/src/emu/x86runf0.c"
|
||||
"${BOX86_ROOT}/src/emu/x86runf066.c"
|
||||
"${BOX86_ROOT}/src/emu/x86runf20f.c"
|
||||
"${BOX86_ROOT}/src/emu/x86runf30f.c"
|
||||
)
|
||||
|
||||
set(WRAPPEDS
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibc.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibpthread.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibrt.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibbsd.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibgl.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibglu.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibglx.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibx11.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibasound.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibdl.c"
|
||||
@@ -297,6 +438,7 @@ set(WRAPPEDS
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedpng16.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxxf86vm.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxrandr.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxpresent.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxext.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedxinerama.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxfixes.c"
|
||||
@@ -329,6 +471,7 @@ set(WRAPPEDS
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedopenal.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedalure.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedalut.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedopencl.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedcurl.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedudev0.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedudev1.c"
|
||||
@@ -358,6 +501,8 @@ set(WRAPPEDS
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibpanel.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibncurses6.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibtinfo6.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgmp.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgcrypt.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgtkx112.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgdkx112.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgtk3.c"
|
||||
@@ -370,15 +515,25 @@ set(WRAPPEDS
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgconf2.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgstreamer010.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgstinterfaces010.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgstreamer.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgstaudio.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgstvideo.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgsttag.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgstbase.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgstapp.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibibus.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappeddbusmenugtk.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappeddbusmenuglib.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedappindicator.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedappindicator3.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedayatanaappindicator3.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedatk.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedatkbridge.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedpangoft2.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedpangocairo.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgthread2.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedcairo.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedcairogobject.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedpango.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappeddbusglib1.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgudev1.c"
|
||||
@@ -409,8 +564,23 @@ set(WRAPPEDS
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedplds4.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedplc4.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedssl3.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedsoftokn3.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedfreebl3.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedsecret1.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedtbbmalloc.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedmimalloc.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedselinux.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibharfbuzz.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibcairogobject.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibvkd3d.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgomp.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedcap.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedpcap.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedfaudio.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedtbbmallocproxy.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibfuse.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedatomic.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibpcre.c"
|
||||
)
|
||||
if(ANDROID)
|
||||
list(APPEND WRAPPEDS
|
||||
@@ -440,7 +610,7 @@ add_custom_command(
|
||||
OUTPUT "${BOX86_ROOT}/src/wrapped/generated/functions_list.txt"
|
||||
COMMAND "${PYTHON_EXECUTABLE}" "${BOX86_ROOT}/rebuild_wrappers.py"
|
||||
"${BOX86_ROOT}"
|
||||
"PANDORA" "HAVE_LD80BITS" "NOALIGN" "HAVE_TRACE" "POWERPCLE" "ANDROID" "--"
|
||||
"PANDORA" "HAVE_LD80BITS" "NOALIGN" "HAVE_TRACE" "POWERPCLE" "ANDROID" "TERMUX" "--"
|
||||
${WRAPPEDS_HEAD}
|
||||
MAIN_DEPENDENCY "${BOX86_ROOT}/rebuild_wrappers.py"
|
||||
DEPENDS ${WRAPPEDS} ${WRAPPEDS_HEAD}
|
||||
@@ -464,7 +634,9 @@ if(ARM_DYNAREC)
|
||||
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_functions.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_jmpnext.c"
|
||||
"${BOX86_ROOT}/src/dynarec/arm_printer.c"
|
||||
"${BOX86_ROOT}/src/emu/x86test.c"
|
||||
|
||||
"${BOX86_ROOT}/src/dynarec/arm_prolog.S"
|
||||
"${BOX86_ROOT}/src/dynarec/arm_epilog.S"
|
||||
@@ -495,6 +667,7 @@ if(ARM_DYNAREC)
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_df.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_f0.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_660f.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_66f0.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_f20f.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_f30f.c"
|
||||
)
|
||||
@@ -511,6 +684,8 @@ if(ARM_DYNAREC)
|
||||
set_target_properties(arm_pass2 PROPERTIES COMPILE_FLAGS "-DSTEP=2")
|
||||
add_library(arm_pass3 OBJECT ${DYNAREC_PASS})
|
||||
set_target_properties(arm_pass3 PROPERTIES COMPILE_FLAGS "-DSTEP=3")
|
||||
add_library(test_interpreter OBJECT ${INTERPRETER})
|
||||
set_target_properties(test_interpreter PROPERTIES COMPILE_FLAGS "-DTEST_INTERPRETER")
|
||||
add_dependencies(arm_pass0 WRAPPERS)
|
||||
add_dependencies(arm_pass1 WRAPPERS)
|
||||
add_dependencies(arm_pass2 WRAPPERS)
|
||||
@@ -522,6 +697,7 @@ if(ARM_DYNAREC)
|
||||
$<TARGET_OBJECTS:arm_pass1>
|
||||
$<TARGET_OBJECTS:arm_pass2>
|
||||
$<TARGET_OBJECTS:arm_pass3>
|
||||
$<TARGET_OBJECTS:test_interpreter>
|
||||
)
|
||||
|
||||
endif()
|
||||
@@ -531,16 +707,18 @@ if(ARM_DYNAREC)
|
||||
add_custom_command(
|
||||
OUTPUT "${BOX86_ROOT}/src/git_head.h"
|
||||
COMMAND bash -c "echo \\\#define GITREV \\\"$(git rev-parse --short HEAD)\\\">\"${BOX86_ROOT}/src/git_head.h\""
|
||||
DEPENDS dynarec ${ELFLOADER_SRC} ${WRAPPEDS}
|
||||
DEPENDS dynarec ${ELFLOADER_SRC} ${INTERPRETER} ${WRAPPEDS}
|
||||
VERBATIM)
|
||||
else()
|
||||
add_custom_command(
|
||||
OUTPUT "${BOX86_ROOT}/src/git_head.h"
|
||||
COMMAND bash -c "echo \\\#define GITREV \\\"$(git rev-parse --short HEAD)\\\">\"${BOX86_ROOT}/src/git_head.h\""
|
||||
DEPENDS ${ELFLOADER_SRC} ${WRAPPEDS}
|
||||
DEPENDS ${ELFLOADER_SRC} ${INTERPRETER} ${WRAPPEDS}
|
||||
VERBATIM)
|
||||
endif()
|
||||
|
||||
add_library(interpreter OBJECT ${INTERPRETER})
|
||||
|
||||
if(BOX86LIB)
|
||||
#build a static or dynamic lib...
|
||||
if(BOX86DYNAMIC)
|
||||
@@ -550,9 +728,13 @@ else()
|
||||
endif()
|
||||
if(ARM_DYNAREC)
|
||||
if(ANDROID)
|
||||
target_link_libraries(${BOX86} dynarec m dl)
|
||||
if(TERMUX)
|
||||
target_link_libraries(${BOX86} dynarec interpreter m dl android-sysv-semaphore android-spawn)
|
||||
else()
|
||||
target_link_libraries(${BOX86} dynarec interpreter m dl)
|
||||
endif()
|
||||
else()
|
||||
target_link_libraries(${BOX86} dynarec m dl rt pthread)
|
||||
target_link_libraries(${BOX86} dynarec interpreter m dl rt pthread resolv)
|
||||
endif()
|
||||
endif()
|
||||
if(${CMAKE_VERSION} VERSION_LESS "3.13")
|
||||
@@ -572,40 +754,78 @@ add_executable(${BOX86} ${ELFLOADER_SRC} ${WRAPPEDS} "${BOX86_ROOT}/src/git_head
|
||||
add_dependencies(${BOX86} WRAPPERS)
|
||||
add_dependencies(${BOX86} PRINTER)
|
||||
if(ANDROID)
|
||||
target_link_libraries(${BOX86} m dl)
|
||||
if(TERMUX)
|
||||
target_link_libraries(${BOX86} dynarec interpreter m dl android-complex-math android-sysv-semaphore android-spawn )
|
||||
else()
|
||||
target_link_libraries(${BOX86} dynarec interpreter m dl)
|
||||
endif()
|
||||
target_link_libraries(${BOX86} c m dl)
|
||||
else()
|
||||
target_link_libraries(${BOX86} m dl rt pthread)
|
||||
#target_link_libraries(${BOX86} c m dl rt pthread resolv)
|
||||
set_target_properties(${BOX86} PROPERTIES LINK_FLAGS "-Wl,--no-as-needed -lc -lm -ldl -lrt -lpthread -lresolv -Wl,--as-needed -pthread")
|
||||
endif()
|
||||
if(ARM_DYNAREC)
|
||||
target_link_libraries(${BOX86} dynarec)
|
||||
target_link_libraries(${BOX86} dynarec interpreter)
|
||||
else()
|
||||
target_link_libraries(${BOX86} interpreter)
|
||||
endif()
|
||||
|
||||
if(${CMAKE_VERSION} VERSION_LESS "3.13")
|
||||
if(NOT NOLOADADDR)
|
||||
set_target_properties(${BOX86} PROPERTIES LINK_FLAGS "-rdynamic -Wl,-Ttext-segment,${BOX86_ELF_ADDRESS}")
|
||||
if(CMAKE_C_COMPILER_ID STREQUAL "Clang")
|
||||
set_target_properties(${BOX86} PROPERTIES LINK_FLAGS "-rdynamic -Wl,--image-base,${BOX86_ELF_ADDRESS}")
|
||||
else()
|
||||
set_target_properties(${BOX86} PROPERTIES LINK_FLAGS "-rdynamic -Wl,-Ttext-segment,${BOX86_ELF_ADDRESS}")
|
||||
endif()
|
||||
else()
|
||||
set_target_properties(${BOX86} PROPERTIES LINK_FLAGS -rdynamic)
|
||||
endif()
|
||||
else()
|
||||
target_link_options(${BOX86} PUBLIC -rdynamic)
|
||||
if(NOT NOLOADADDR)
|
||||
target_link_options(${BOX86} PUBLIC -Wl,-Ttext-segment,${BOX86_ELF_ADDRESS})
|
||||
if(CMAKE_C_COMPILER_ID STREQUAL "Clang")
|
||||
target_link_options(${BOX86} PUBLIC -Wl,--image-base,${BOX86_ELF_ADDRESS})
|
||||
else()
|
||||
target_link_options(${BOX86} PUBLIC -Wl,-Ttext-segment,${BOX86_ELF_ADDRESS})
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
string(COMPARE EQUAL "${CMAKE_HOST_SYSTEM_PROCESSOR}" "i686" _x86)
|
||||
string(COMPARE EQUAL "${CMAKE_HOST_SYSTEM_PROCESSOR}" "x86_64" _x86_64)
|
||||
string(COMPARE EQUAL "${CMAKE_HOST_SYSTEM_PROCESSOR}" "aarch64" _aarch64)
|
||||
string(COMPARE EQUAL "${CMAKE_HOST_SYSTEM_PROCESSOR}" "armhf" _armhf)
|
||||
|
||||
if(NOT _x86 AND NOT _x86_64)
|
||||
install(TARGETS ${BOX86}
|
||||
if(NOT TERMUX)
|
||||
install(TARGETS ${BOX86}
|
||||
RUNTIME DESTINATION bin)
|
||||
configure_file(system/box86.conf.cmake system/box86.conf)
|
||||
install(FILES ${CMAKE_BINARY_DIR}/system/box86.conf DESTINATION /etc/binfmt.d/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libstdc++.so.6 DESTINATION /usr/lib/i386-linux-gnu/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libstdc++.so.5 DESTINATION /usr/lib/i386-linux-gnu/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libgcc_s.so.1 DESTINATION /usr/lib/i386-linux-gnu/)
|
||||
else()
|
||||
install(TARGETS ${BOX86}
|
||||
RUNTIME DESTINATION ${TERMUX_PATH}/usr/bin)
|
||||
endif()
|
||||
if(NOT NO_CONF_INSTALL)
|
||||
configure_file(system/box86.conf.cmake system/box86.conf)
|
||||
if(NOT TERMUX)
|
||||
install(FILES ${CMAKE_BINARY_DIR}/system/box86.conf DESTINATION /etc/binfmt.d/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/system/box86.box86rc DESTINATION /etc/)
|
||||
else()
|
||||
#install(FILES ${CMAKE_BINARY_DIR}/system/box86.conf DESTINATION ${TERMUX_PATH}/usr/etc/binfmt.d/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/system/box86.box86rc DESTINATION ${TERMUX_PATH}/usr/etc/)
|
||||
endif()
|
||||
endif()
|
||||
set(INSTALL_PATH "/usr/lib/box86-i386-linux-gnu/")
|
||||
if(NOT NO_LIB_INSTALL)
|
||||
if(NOT TERMUX)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libstdc++.so.6 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libstdc++.so.5 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libgcc_s.so.1 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libpng12.so.0 DESTINATION ${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libunwind.so.8 DESTINATION ${INSTALL_PATH})
|
||||
else()
|
||||
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libstdc++.so.6 DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libstdc++.so.5 DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libgcc_s.so.1 DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libpng12.so.0 DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libunwind.so.8 DESTINATION ${TERMUX_PATH}${INSTALL_PATH})
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT TARGET uninstall)
|
||||
@@ -622,7 +842,11 @@ set(CPACK_GENERATOR "DEB")
|
||||
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "ptitSeb")
|
||||
set(CPACK_PACKAGE_CONTACT "[email protected]")
|
||||
set(CPACK_PACKAGE_DESCRIPTION "Box86 - Linux Userspace x86 Emulator with a twist")
|
||||
if(TERMUX)
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libandroid-sysv-semaphore, libandroid-spawn")
|
||||
else()
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6")
|
||||
endif()
|
||||
set(CPACK_PACKAGE_HOMEPAGE_URL, "https://box86.org")
|
||||
file(STRINGS "${BOX86_ROOT}/src/box86version.h" TEMP_STRING REGEX "BOX86_MAJOR\\s*")
|
||||
string(REGEX REPLACE "BOX86_MAJOR" "" TEMP_STRING ${TEMP_STRING})
|
||||
@@ -636,120 +860,181 @@ string(REGEX MATCH "[0-9]" BOX86_REVISION ${TEMP_STRING})
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR ${BOX86_MAJOR})
|
||||
set(CPACK_PACKAGE_VERSION_MINOR ${BOX86_MINOR})
|
||||
set(CPACK_PACKAGE_VERSION_PATCH ${BOX86_REVISION})
|
||||
if(NOT TERMUX)
|
||||
set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_CURRENT_SOURCE_DIR}/postinst")
|
||||
if(_aarch64 OR _armhf)
|
||||
endif()
|
||||
if(_aarch64 OR _armhf OR _arm OR _armv8l)
|
||||
if(TERMUX)
|
||||
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "arm")
|
||||
else()
|
||||
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "armhf")
|
||||
endif()
|
||||
elseif(_x86_64 OR _x86)
|
||||
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "i386")
|
||||
else()
|
||||
#probably wrong...
|
||||
execute_process(COMMAND "dpkg --print-architecture" OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE)
|
||||
endif()
|
||||
set(CPACK_DEBIAN_FILE_NAME "${BOX86}-${BOX86_MAJOR}.${BOX86_MINOR}.${BOX86_REVISION}_Linux-${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}.deb")
|
||||
if(TERMUX)
|
||||
set(CPACK_PACKAGING_INSTALL_PREFIX "${TERMUX_PATH}/usr")
|
||||
endif()
|
||||
if(NOT TERMUX)
|
||||
set(CPACK_DEBIAN_FILE_NAME "${BOX86}-${BOX86_MAJOR}.${BOX86_MINOR}.${BOX86_REVISION}_${CMAKE_SYSTEM_NAME}-${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}.deb")
|
||||
else()
|
||||
set(CPACK_DEBIAN_FILE_NAME "${BOX86}-${BOX86_MAJOR}.${BOX86_MINOR}.${BOX86_REVISION}_Termux-${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}.deb")
|
||||
endif()
|
||||
INCLUDE(CPack)
|
||||
|
||||
add_test(NAME bootSyscall COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test01 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test01 -D TEST_OUTPUT=tmpfile01.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref01.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME bootSyscallC COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test02 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test02 -D TEST_OUTPUT=tmpfile02.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref02.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME printf COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test03 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test03 -D TEST_OUTPUT=tmpfile03.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref03.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME args COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test04 -D TEST_ARGS2=yeah -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test04 -D TEST_ARGS2=yeah -D TEST_OUTPUT=tmpfile04.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref04.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME maths1 COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test05 -D TEST_ARGS2=7 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test05 -D TEST_ARGS2=7 -D TEST_OUTPUT=tmpfile05.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref05.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME threadsStart COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test06 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test06 -D TEST_OUTPUT=tmpfile06.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref06.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME trig COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test07 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test07 -D TEST_OUTPUT=tmpfile07.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref07.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME pi COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test08 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test08 -D TEST_OUTPUT=tmpfile08.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref08.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME fork COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test09 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test09 -D TEST_OUTPUT=tmpfile09.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref09.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME cppThreads COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test10 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test10 -D TEST_OUTPUT=tmpfile10.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref10.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME tlsData COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test11 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test11 -D TEST_OUTPUT=tmpfile11.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref11.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME fpu COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test12 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test12 -D TEST_OUTPUT=tmpfile12.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref12.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME contexts COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test13 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test13 -D TEST_OUTPUT=tmpfile13.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref13.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME conditionalThreads COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test14 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref14.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
if(NOT LD80BITS)
|
||||
add_test(NAME conditionalThreads COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test14 -D TEST_OUTPUT=tmpfile14.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref14.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
endif()
|
||||
|
||||
add_test(NAME linkingIndirectNoversion COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test15 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test15 -D TEST_OUTPUT=tmpfile15.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref15.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME linkingIndirectVersion COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test16 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test16 -D TEST_OUTPUT=tmpfile16.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref16.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME ucomiss COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test17 -D TEST_OUTPUT=tmpfile.txt
|
||||
add_test(NAME sse COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test17 -D TEST_OUTPUT=tmpfile17.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref17.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
set_tests_properties(sse PROPERTIES ENVIRONMENT "BOX86_DYNAREC_FASTNAN=0;BOX86_DYNAREC_FASTROUND=0")
|
||||
|
||||
add_test(NAME longjumpInSignals COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test18 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test18 -D TEST_OUTPUT=tmpfile18.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref18.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME x87 COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test19 -D TEST_OUTPUT=tmpfile.txt
|
||||
add_test(NAME x87 COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test19 -D TEST_OUTPUT=tmpfile19.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref19.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
file(GLOB extension_tests "${CMAKE_SOURCE_DIR}/tests/extensions/*.c")
|
||||
add_test(NAME idiv COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test20 -D TEST_OUTPUT=tmpfile20.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref20.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME multiple_dlopen COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test21 -D TEST_OUTPUT=tmpfile21.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref21.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME aes COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test22 -D TEST_OUTPUT=tmpfile22.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref22.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
file(GLOB extension_tests "${CMAKE_SOURCE_DIR}/tests/extensions/*.c")
|
||||
foreach(file ${extension_tests})
|
||||
get_filename_component(testname "${file}" NAME_WE)
|
||||
add_test(NAME "${testname}" COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/extensions/${testname} -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/extensions/${testname} -D TEST_OUTPUT=tmpfile-${testname}.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/extensions/${testname}.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake)
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
||||
add_test(NAME sse_optimized COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test17_o2 -D TEST_OUTPUT=tmpfile17_o2.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref17_o2.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
set_tests_properties(sse_optimized PROPERTIES ENVIRONMENT "BOX86_DYNAREC_FASTNAN=0;BOX86_DYNAREC_FASTROUND=0")
|
||||
|
||||
add_test(bswap ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test23 -D TEST_OUTPUT=tmpfile23.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref23.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(feround ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test24 -D TEST_OUTPUT=tmpfile24.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref24.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(sse4_2 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test25 -D TEST_OUTPUT=tmpfile25.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref25.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(fpu_rounding ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test26 -D TEST_OUTPUT=tmpfile26.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref26.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
set_tests_properties(fpu_rounding PROPERTIES ENVIRONMENT "BOX86_DYNAREC_FASTROUND=0")
|
||||
|
||||
endif(BOX86LIB)
|
||||
Vendored
+150
@@ -0,0 +1,150 @@
|
||||
box86 (0.3.8) unstable; urgency=low
|
||||
* Some optimisation of x86 P flags handling
|
||||
* Some x87 fixes and improvments
|
||||
* Added some of the tim64 wrapped functions to libc and friends
|
||||
* Changed the installation folder of x86 libs to avoid conflict with linux distro
|
||||
* Some fixes to internal memory tracking
|
||||
* Some more Vulkan extensions wrapped
|
||||
* Better handling of BOX86_MAXCPU
|
||||
* Some changes and improvments on Signal handling
|
||||
* More wrapped functions, and fix to some existing ones
|
||||
* A few more syscall, and fix to some existing ones
|
||||
* New build profile for SD865
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Fri, 06 Dec 2024 14:06:00 -0100
|
||||
|
||||
box86 (0.3.6) unstable; urgency=low
|
||||
* Wrapping: More libs and and function wrapping (gtk3, vulkan...)
|
||||
* Reworked X11 Callback handling, for better stability
|
||||
* Reworked exit and the load/unload of libs
|
||||
* Some more profiles in box86rc
|
||||
* More SSE3+ opcodes in dynarec
|
||||
* Better way to rename executable (including wine ones) so driver like mesa can apply the correct profile
|
||||
* Lots of improvments in x87 handling (virtual stack, rounding, ffree, etc.)
|
||||
* => should improve games stability
|
||||
* Better handling of large block in the dynarec
|
||||
* => should speedup dynarec, and allow use of BIGBLOCK 2 or 3 on more software
|
||||
* Added suport for BOX86_DYNAREC_CALLRET optimisation.
|
||||
* => backported from box64, can give 10% or more speed increase (but can also decrease speed in some cases). Still a bit crashy so use with care.
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 31 May 2024 17:30:33 -0100
|
||||
|
||||
box86 (0.3.4) unstable; urgency=low
|
||||
|
||||
* X86Libs: Updated libstdc++ & libgcc_s
|
||||
* X86Libs: Use x86 vrsion of libunwind (it's needed by wine)
|
||||
* Dynarec: Fixed some flags propagation issues inside blocks
|
||||
* Dynarec: Improved Strong Memory Model emulation, introducing a 3rd level
|
||||
* CPU: Remoworked how INT, priviliged opcodes and teh Trace flags works
|
||||
* CPU: Added full support for SSE4.2
|
||||
* ElfLoader: rework how elf memory is handled
|
||||
* 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 for ADLink Ampere Altra
|
||||
* OS: Added profile to build for Android and Termux.
|
||||
* => Mostly a stability update with improved elfloader again, and added SSE 4.2 support (still need to work on the Dynarec part of this)
|
||||
* => Some work also to reduce the memory footprint
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 15 Dec 2023 17:30:33 -0100
|
||||
|
||||
box86 (0.3.2) unstable; urgency=low
|
||||
|
||||
* Better syscall handling
|
||||
* Fixed some wrapped functions, added some others
|
||||
* Introduced another wrapper helper
|
||||
* Added some more opcodes
|
||||
* Added a cosimulation mode (to compare the behaviour of the dynarec against the interpreter)
|
||||
* Added support of FASTNAN for some more opcodes
|
||||
* Reduced memory footprint
|
||||
* Added BOX86_NOSANDBOX (adds an argument to the command line)
|
||||
* Added an ukrainian translation
|
||||
* => Mostly a stability update with improved elfloader, fixed opcodes and refined profiles
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 10 Mar 2023 10:20:33 -0500
|
||||
|
||||
box86 (0.3.0) unstable; urgency=low
|
||||
|
||||
* Added rcfile handling: box86 now read "/etc/box86.box86rc" and "~/.box86rc" and apply per process parameters
|
||||
* Added BOX86_DYNAREC_FORWARD to allow bigger Dynarec block to be build
|
||||
* Refactored Strong Memory Model emulation (faster and more accurate)
|
||||
* Box86 now return a custom name for the CPU instal of P4, build with Box86 and the cpu name it's running on
|
||||
* Improved memory protection tracking and signal handling, again
|
||||
* More wrapped libs (especially on the gtk familly)
|
||||
* More wrapped functions
|
||||
* Added support for CreateDeviceEx in d3dadapter9, for better gallium nine support
|
||||
* Improved dladdr/dladdr1 wrapped function
|
||||
* Some fixes to flags handling in the Dynarec on some special cases
|
||||
* Added specific suppport for RK3588 board (needed some hack in signal handling, probably due to the use of a non mainlined kernel)
|
||||
* Lots of improvment in the Rounding of float & double (Dynarec and Interpretor), 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)
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 10 Mar 2023 10:20:33 -0500
|
||||
|
||||
box86 (0.2.8) unstable; urgency=low
|
||||
|
||||
* Wrapped more Vulkan functions, dxvk2.0 now works
|
||||
* Added support for overridden malloc/free functions
|
||||
* Improved elf loader
|
||||
* Improved dlsym handling with RTLD_NEXT
|
||||
* Added BOX86_DYNAREC_SAFEFLAGS to allow finetuning Dynarec generated code handling of flags accross function calls and returns.
|
||||
* Added BOX86_BASH to setup x86 bash binary, so shell script can be run in x86 world
|
||||
* Added BOX86_ROLLING_LOG to have details log only on crash
|
||||
* Improved TLS Size handling (Unity3D games now works)
|
||||
* Improved execv family of function to have better box86 integration
|
||||
* Added a few more wrapped libs, like FAudio
|
||||
* Improved gtk, SDL2, GL, vulkan (and more) wrapping
|
||||
* Improved Signal Handling and memory protection traking
|
||||
* Added some basic support for statically linked program. Thread are not working yet, but memory allocation and file access does.
|
||||
* add LX2160A config by @lizthegrey in #612
|
||||
* Grammar and formatting COMPILE.md by @Radiicall in #615
|
||||
* Update README.md by @everypizza1 in #617
|
||||
* docs: add instructions for Debian-based Linux by @ryanfortner in #622
|
||||
* Fix typoes in readme by @ryanfortner in #621
|
||||
* Various improvements to install_steam.sh by @ryanfortner in #620
|
||||
* docs: remove unnecessary newline by @ryanfortner in #624
|
||||
* fix: the first parameter of realpath may be null by @ye-yeshun in #630
|
||||
* Add 6 wrapped function to libdrm, and 2 to libexpat. by @cjy880927 in #632
|
||||
* Fix #610 by @rajdakin in #634
|
||||
* some floating point instructions by @ye-yeshun in #637
|
||||
* Fix Typo in readme x86_64 -> x86 by @Jai-JAP in #642
|
||||
* Fix grammar by @Jai-JAP in #645
|
||||
* Test wine preload by @ptitSeb in #649
|
||||
* Align address when call mprotect by @wannacu in #651
|
||||
* Added 66 0F 7D HSUBPD opcode by @wannacu in #652
|
||||
* add TEGRAX1 and TEGRAX1ARM32 targets on ubuntu-18.04 by @theofficialgman in #654
|
||||
* automatically install 32 bit libraries if 64 bit OS is detected in install_steam.sh by @Moldytzu in #659
|
||||
* mention gcc-arm-linux-gnueabihf in compile.md by @Moldytzu in #660
|
||||
* Add libc6:armhf install to RPi4 aarch64 build info by @WheezyE in #685
|
||||
* Updated wine install for RPiOS bullseye 32/64bit by @WheezyE in #689
|
||||
* Add atomic add opcodes by @Trass3r in #695
|
||||
* steam: disable modern login and pass arguments to client by @Moldytzu in #700
|
||||
* Modify sizeof(instsize_t) to 1 byte by @liuli0217 in #721
|
||||
* Add MOV GS:od, AL by @liuli0217 in #722
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Thu, 17 Nov 2022 11:20:33 -0500
|
||||
|
||||
box86 (0.2.6) unstable; urgency=low
|
||||
|
||||
* Added an option to get generated -NAN on SSE2 operation
|
||||
* Many small fixes and improvement to get steam and SteamPlay working (along with box64)
|
||||
* Added some workaround for program calling uname to mimic x86 system
|
||||
* Added some more Vulkan extensions
|
||||
* Added some granularity to mmap64, and generic memory protection tracking improvment, to mimic x86 system (for wine stagging and proton)
|
||||
* Better clone syscall and libc implementation
|
||||
* Improved wrapping of GTK libs
|
||||
* More wrapped libs (more gtk libs, like gstreamer-1.0 among other non-gtk libs too)
|
||||
* More wrapped functions(with some tricky one, like dladdr1)
|
||||
* Some fixes and improvment to some wrapped functions
|
||||
* Refactor Dynarec:
|
||||
* - better handling of SSE/x87 registers
|
||||
* - optimisation to limit float/double conversion
|
||||
* - better handling of "internal" jump inside a dynablock
|
||||
* Improved elfloader
|
||||
* Improved some tests
|
||||
* A few fixes in some Dynarec opcodes
|
||||
* Don't quit on unsupported syscall, return -1 / ENOSYS error
|
||||
* A bit more optimisation in some Dynarec opcodes
|
||||
|
||||
-- Sebastien Chevalier <[email protected]> Tue, 18 Jan 2022 11:20:33 -0500
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
11
|
||||
Vendored
+14
@@ -0,0 +1,14 @@
|
||||
Source: box86
|
||||
Section: utils
|
||||
Priority: optional
|
||||
Maintainer: Ryan Fortner <[email protected]>
|
||||
Build-Depends: cmake, debhelper (>=11~)
|
||||
Standards-Version: 4.1.4
|
||||
Homepage: https://github.com/ptitSeb/box86
|
||||
|
||||
Package: box86
|
||||
Architecture: any
|
||||
Multi-Arch: foreign
|
||||
Depends: ${misc:Depends}, ${shlibs:Depends}
|
||||
Description: Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices
|
||||
Box86 lets you run x86 Linux programs (such as games) on non-x86 Linux systems, like ARM (host system needs to be 32bit little-endian).
|
||||
Vendored
+26
@@ -0,0 +1,26 @@
|
||||
Format-Specification: http://dep.debian.net/deps/dep5/
|
||||
|
||||
Files: *
|
||||
Copyright: © 2022 Sebastien Chevalier
|
||||
License: MIT
|
||||
|
||||
License: MIT
|
||||
Copyright (c) 2018-2021 Sebastien Chevalier ("ptitSeb")
|
||||
.
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
.
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
box86: no-manual-page
|
||||
Vendored
+18
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/make -f
|
||||
|
||||
%:
|
||||
dh $@
|
||||
|
||||
override_dh_auto_configure:
|
||||
dh_auto_configure -- \
|
||||
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
|
||||
-DARM_DYNAREC=1 \
|
||||
-DNOGIT=1
|
||||
|
||||
override_dh_shlibdeps:
|
||||
dh_shlibdeps \
|
||||
--exclude=libgcc_s.so.1 \
|
||||
--exclude=libpng12.so.0 \
|
||||
--exclude=libstdc++.so.5 \
|
||||
--exclude=libstdc++.so.6 \
|
||||
--exclude=libunwind.so.8
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
3.0 (quilt)
|
||||
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
Bug-Database: https://github.com/ptitSeb/box86/issues
|
||||
Bug-Submit: https://github.com/ptitSeb/box86/issues/new
|
||||
Repository: https://github.com/ptitSeb/box86.git
|
||||
Repository-Browse: https://github.com/ptitSeb/box86
|
||||
Security-Contact: [email protected]
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
version=3
|
||||
@@ -1,3 +1,126 @@
|
||||
v0.3.8
|
||||
======
|
||||
* Some optimisation of x86 P flags handling
|
||||
* Some x87 fixes and improvments
|
||||
* Added some of the tim64 wrapped functions to libc and friends
|
||||
* Changed the installation folder of x86 libs to avoid conflict with linux distro
|
||||
* Some fixes to internal memory tracking
|
||||
* Some more Vulkan extensions wrapped
|
||||
* Better handling of BOX86_MAXCPU
|
||||
* Some changes and improvments on Signal handling
|
||||
* More wrapped functions, and fix to some existing ones
|
||||
* A few more syscall, and fix to some existing ones
|
||||
* New build profile for SD865
|
||||
|
||||
v0.3.6
|
||||
======
|
||||
* Wrapping: More libs and function wrapping (gtk3, vulkan...)
|
||||
* Reworked X11 Callback handling, for better stability
|
||||
* Reworked exit and the load/unload of libs
|
||||
* Some more profiles in box86rc
|
||||
* More SSE3+ opcodes in dynarec
|
||||
* Better way to rename executable (including wine ones) so driver like mesa can apply the correct profile
|
||||
* Better handling of the Hardware Counter and TSC emulation
|
||||
* Reworked memory managment in the Dynarec, limiting amount of dynamic allocation
|
||||
* PageSize detection and handling dynamic. Larger than 4K pagesize will be handled automaticaly. Note that box64 does not emulate 4K page size, so some program might still refuse to work on larger page (like Wine for example)
|
||||
=> Linux Games can now load even on a 16K pagesize machine like a mac M1, and games (including Unity3D ones) can be played with no issues.
|
||||
* Lots of improvments in x87 handling (virtual stack, rounding, ffree, etc.)
|
||||
=> should improve games stability
|
||||
* Better handling of large block in the dynarec
|
||||
=> should speedup dynarec, and allow use of BIGBLOCK 2 or 3 on more software
|
||||
* Added suport for BOX86_DYNAREC_CALLRET optimisation.
|
||||
=> backported from box64, can give 10% or more speed increase (but can also decrease speed in some cases). Still a bit crashy so use with care.
|
||||
|
||||
v0.3.4
|
||||
======
|
||||
* X86Libs: Updated libstdc++ & libgcc_s
|
||||
* X86Libs: Use x86 vrsion of libunwind (it's needed by wine)
|
||||
* Dynarec: Fixed some flags propagation issues inside blocks
|
||||
* Dynarec: Improved Strong Memory Model emulation, introducing a 3rd level
|
||||
* CPU: Remoworked how INT, priviliged opcodes and teh Trace flags works
|
||||
* CPU: Added full support for SSE4.2
|
||||
* ElfLoader: rework how elf memory is handled
|
||||
* 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 for ADLink Ampere Altra
|
||||
* OS: Added profile to build for Android and Termux.
|
||||
=> Mostly a stability update with improved elfloader again, and added SSE 4.2 support (still need to work on the Dynarec part of this)
|
||||
=> Some work also to reduce the memory footprint
|
||||
|
||||
v0.3.2
|
||||
======
|
||||
* Better syscall handling
|
||||
* Fixed some wrapped functions, added some others
|
||||
* Introduced another wrapper helper
|
||||
* Added some more opcodes
|
||||
* Added a cosimulation mode (to compare the behaviour of the dynarec against the interpreter)
|
||||
* Added support of FASTNAN for some more opcodes
|
||||
* Reduced memory footprint
|
||||
* Added BOX86_NOSANDBOX (adds an argument to the command line)
|
||||
* Added an ukrainian translation
|
||||
=> Mostly a stability update with improved elfloader, fixed opcodes and refined profiles
|
||||
|
||||
v0.3.0
|
||||
======
|
||||
* Added rcfile handling: box86 now read `/etc/box86.box86rc` and `~/.box86rc` and apply per process parameters
|
||||
=> Every program can be finetuned, for speed or just to make them work
|
||||
* Added BOX86_DYNAREC_FORWARD to allow bigger Dynarec block to be build
|
||||
* Refactored Strong Memory Model emulation (faster and more accurate)
|
||||
* Box86 now return a custom name for the CPU instal of P4, build with Box86 and the cpu name it's running on
|
||||
* Improved memory protection tracking and signal handling, again
|
||||
* More wrapped libs (especially on the gtk familly)
|
||||
* More wrapped functions
|
||||
* Added support for CreateDeviceEx in d3dadapter9, for better gallium nine support
|
||||
* Improved dladdr/dladdr1 wrapped function
|
||||
* Some fixes to flags handling in the Dynarec on some special cases
|
||||
* Added specific suppport for RK3588 board (needed some hack in signal handling, probably due to the use of a non mainlined kernel)
|
||||
* Lots of improvment in the Rounding of float & double (Dynarec and Interpretor), 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)
|
||||
|
||||
|
||||
v0.2.8
|
||||
======
|
||||
* Wrapped more vulkan function, dxvk 2.0 now works
|
||||
* Added support for overriden malloc/free functions
|
||||
* Improved elf loader
|
||||
* Improved dlsym handling with RTLD_NEXT
|
||||
* Added BOX86_DYNAREC_SAFEFLAGS to allow finetuning Dynarec generated code handling of flags accross function calls and returns.
|
||||
* Added BOX86_BASH to setup x86 bash binary, so shell script can be run in x86 world
|
||||
* Added BOX86_ROLLING_LOG to have details log only on crash
|
||||
* Improved TLS Size handling (Unity3D games now works)
|
||||
* Improved `execv` family of function to have better box86 integration
|
||||
* Added a few more wrapped libs, like FAudio
|
||||
* Improved gtk, SDL2, GL, vulkan (and more) wrapping
|
||||
* Improved Signal Handling and memory protection traking
|
||||
* Added some basic support for statically linked program. Thread are not working yet, but memory allocation and file access does.
|
||||
=> with the use of the new SafeFlags, some C# Windows program now runs fine (it's forced when the Vara family of software is detected)
|
||||
=> With the basic support of statcaly linked program, old emulator like modeler for linux works. Program with threads like mugen for linux still doesn't
|
||||
=> The bash integration is usefull for device with no binfmt integration or for script that check the machine it's running on
|
||||
|
||||
v0.2.6
|
||||
======
|
||||
* Added an option to get generated -NAN on SSE2 operation
|
||||
* Many small fixes and improvement to get steam and SteamPlay working (along with box64)
|
||||
* Added some workaround for program calling uname to mimic x86 system
|
||||
* Added some more Vulkan extensions
|
||||
* Added some granularity to mmap64, and generic memory protection tracking improvment, to mimic x86 system (for wine stagging and proton)
|
||||
* Better clone syscall and libc implementation
|
||||
* Improved wrapping of GTK libs
|
||||
* More wrapped libs (more gtk libs, like gstreamer-1.0 among other non-gtk libs too)
|
||||
* More wrapped functions(with some tricky one, like dladdr1)
|
||||
* Some fixes and improvment to some wrapped functions
|
||||
* Refactor Dynarec:
|
||||
* better handling of SSE/x87 registers
|
||||
* optimisation to limit float/double conversion
|
||||
* better handling of "internal" jump inside a dynablock
|
||||
* Improved elfloader
|
||||
* Improved some tests
|
||||
* A few fixes in some Dynarec opcodes
|
||||
* Don't quit on unsupported syscall, return -1 / ENOSYS error
|
||||
* A bit more optimisation in some Dynarec opcodes
|
||||
|
||||
v0.2.4
|
||||
======
|
||||
* Some work on Dynarec to limit the number of mutex use, and also allow smaller block to be built (for JIT'd programs)
|
||||
|
||||
+159
-30
@@ -1,5 +1,22 @@
|
||||
Compiling
|
||||
Compiling/Installing
|
||||
----
|
||||
|
||||
If you don't want to compile box86 yourself and prefer to use third-party pre-build version, go to the [end of the document](#pre-build-packages) for alternatives.
|
||||
|
||||
You can also generate your own debian package using the [instructions below](https://github.com/ptitSeb/box86/blob/master/docs/COMPILE.md#debian-packaging).
|
||||
|
||||
Important note, if you are using a 64bits OS, you need to have multi-arch enabled, with armhf support, for box86 to works. On Debian/Ubuntu/Armbian OS, you need to do:
|
||||
|
||||
```bash
|
||||
sudo dpkg --add-architecture armhf && sudo apt-get update
|
||||
sudo apt-get install libc6:armhf -y
|
||||
```
|
||||
|
||||
And of course you will need to install much more library to be able to run software and games (like X11, mesa, SDL, pulseaudio...)
|
||||
|
||||
## Per-platform compiling instructions
|
||||
----
|
||||
|
||||
#### for Pandora
|
||||
|
||||
`mkdir build; cd build; cmake .. -DPANDORA=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make`
|
||||
@@ -14,40 +31,65 @@ Compiling
|
||||
|
||||
#### for Raspberry Pi
|
||||
|
||||
_a build for model 2, 3 and 4 can be done. Model 1 and 0 cannot (at least not with Dynarec, as they lack NEON support)_
|
||||
_A build for model 2, 3 and 4 can be done. Model 1 and 0 cannot (at least not with Dynarec, as they lack NEON support)_
|
||||
|
||||
```
|
||||
git clone https://github.com/ptitSeb/box86
|
||||
cd box86
|
||||
mkdir build; cd build; cmake .. -DRPI4=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
make
|
||||
mkdir build; cd build; cmake .. -DRPI4=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo # -DRPI4=1 for Pi4 (use `-DRPI2=1` etc for other models)
|
||||
make # can use `make -j2`, `make -j3`, etc to speed up 1st build (but beware of running out of memory if going too high)
|
||||
sudo make install
|
||||
sudo systemctl restart systemd-binfmt
|
||||
```
|
||||
Note that you can use `make -j2` or more to speed up 1st build, but beware of the memory requirement if you go to high.
|
||||
|
||||
#### for Raspberry Pi on 64bits OS
|
||||
#### for Raspberry Pi on 64bit OS
|
||||
|
||||
_For Pi4. Change to RPI2 or RPI3 for other models. Change `-DRPI4=1` to `-DRPI4ARM64=1` for compiling on arm64. (armhf multiarch or chroot required alongside armhf gcc. Install it with 'sudo apt install gcc-arm-linux-gnueabihf'.)_
|
||||
_armhf multiarch or chroot required for running box86 (armhf) on aarch64_
|
||||
|
||||
```
|
||||
# example of enabling multiarch & installing libc6:armhf (to run box86:armhf on aarch64)
|
||||
# (running i386-wine on aarch64 requires more armhf libraries)
|
||||
sudo dpkg --add-architecture armhf && sudo apt-get update
|
||||
sudo apt-get install libc6:armhf -y
|
||||
```
|
||||
_Build box86:armhf on RPiOS 64-bit ARM (aarch64)_
|
||||
```
|
||||
sudo apt install gcc-arm-linux-gnueabihf # building 32-bit ARM code on aarch64 requires this armhf gcc cross-compiler toolchain
|
||||
git clone https://github.com/ptitSeb/box86
|
||||
cd box86
|
||||
mkdir build; cd build; cmake .. -DRPI4ARM64=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
mkdir build; cd build; cmake .. -DRPI4ARM64=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo # -DRPI4ARM64=1 for Pi4 aarch64 (use `-DRPI3ARM64=1` for a PI3 model)
|
||||
make -j2
|
||||
sudo make install
|
||||
sudo systemctl restart systemd-binfmt
|
||||
```
|
||||
|
||||
#### for ODROID
|
||||
#### for ODROID-XU3/XU4/MC1/HC1/HC2
|
||||
|
||||
`mkdir build; cd build; cmake .. -DODROID=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j3`
|
||||
`mkdir build; cd build; cmake .. -DODROIDXU4=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j3`
|
||||
|
||||
#### for RK3399
|
||||
|
||||
`mkdir build; cd build; cmake .. -DRK3399=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j3`
|
||||
|
||||
As most RK3399 device run AARCH64 OS, you'll need an `armhf` multiarch environment, and an armhf gcc: On debian, install it with `sudo apt install gcc-arm-linux-gnueabihf`.
|
||||
As most RK3399 devices run an AARCH64 OS, you'll need an `armhf` multiarch environment, and an armhf gcc: On debian, install it with `sudo apt install gcc-arm-linux-gnueabihf`.
|
||||
|
||||
Also, on armbian, you may need to install `libc6-dev-armhf-cross` or you may have an issue with `crt1.o` and a few other files not included with box86.
|
||||
|
||||
#### for RK3588 / RK3588S
|
||||
|
||||
`mkdir build; cd build; cmake .. -DRK3588=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j4`
|
||||
|
||||
As most RK3588 devices run an AARCH64 OS, you'll need an `armhf` multiarch environment, and an armhf gcc: On debian, install it with `sudo apt install gcc-arm-linux-gnueabihf`.
|
||||
|
||||
Also, on armbian, you may need to install `libc6-dev-armhf-cross` or you may have an issue with `crt1.o` and a few other files not included with box86.
|
||||
|
||||
#### for ODROID-N2/N2+
|
||||
|
||||
`mkdir build; cd build; cmake .. -DODROIDN2=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j3`
|
||||
|
||||
As most ODROID-N2/N2+ devices run an AARCH64 OS, you'll need an `armhf` multiarch environment, and an armhf gcc: On debian, install it with `sudo apt install gcc-arm-linux-gnueabihf`.
|
||||
|
||||
Also, on armbian, you may need to install `libc6-dev-armhf-cross` or you may have an issue with `crt1.o` and a few other files not included with box86.
|
||||
|
||||
#### for Tinker Board (1/1S) or RK3288
|
||||
|
||||
@@ -57,64 +99,151 @@ As most RK3399 device run AARCH64 OS, you'll need an `armhf` multiarch environme
|
||||
|
||||
`mkdir build; cd build; cmake .. -DA64=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j3`
|
||||
|
||||
As most Allwinner A64 device run AARCH64 OS, you'll need an `armhf` multiarch environment, and an armhf gcc: On debian, install it with `sudo apt install gcc-arm-linux-gnueabihf`.
|
||||
As most Allwinner A64 devices run an AARCH64 OS, you'll need an `armhf` multiarch environment, and an armhf gcc: On debian, install it with `sudo apt install gcc-arm-linux-gnueabihf`.
|
||||
|
||||
#### for Snapdragon 845
|
||||
Also, on armbian, you may need to install `libc6-dev-armhf-cross` or you may have an issue with `crt1.o` and a few other files not included with box86.
|
||||
|
||||
#### for Snapdragon
|
||||
|
||||
`mkdir build; cd build; cmake .. -DSD845=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j4`
|
||||
or
|
||||
`mkdir build; cd build; cmake .. -DSD888=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j4`
|
||||
|
||||
As most Snapdragon 845 device run AARCH64 OS, in most cases you'll need an `armhf` multiarch environment, and an armhf gcc: On mobian, install it with `sudo apt install gcc-arm-linux-gnueabihf`.
|
||||
Depending how old/recent you SD is. As most Snapdragon devices run an AARCH64 OS, you'll need an `armhf` multiarch environment, and an armhf gcc: On mobian, install it with `sudo apt install gcc-arm-linux-gnueabihf`.
|
||||
|
||||
#### for Phytium
|
||||
|
||||
`mkdir build; cd build; cmake .. -DPHYTIUM=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j4`
|
||||
|
||||
As most Phytium (D2000 or FT2000/4) device run AARCH64 OS, you'll need an `armhf` multiarch environment, and an armhf gcc: On debian/ubuntu, install it with `sudo apt install gcc-arm-linux-gnueabihf`.
|
||||
As most Phytium (D2000 or FT2000/4) devices run an AARCH64 OS, you'll need an `armhf` multiarch environment, and an armhf gcc: On debian, install it with `sudo apt install gcc-arm-linux-gnueabihf`.
|
||||
|
||||
|
||||
Also, on armbian, you may need to install `libc6-dev-armhf-cross` or you may have an issue with `crt1.o` and a few other files not included with box86.
|
||||
|
||||
#### for ADLink AmpereAltra
|
||||
|
||||
`mkdir build; cd build; cmake .. -DADLINK=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j`
|
||||
|
||||
As ADLINK AmpereAltra computers run an AARCH64 OS, you'll need an `armhf` multiarch environment, and an armhf gcc: On debian, install it with `sudo apt install gcc-arm-linux-gnueabihf`.
|
||||
|
||||
#### for Other ARM64 64bits Linux platform
|
||||
|
||||
`mkdir build; cd build; cmake .. -DARM64=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j3`
|
||||
|
||||
You can also add `-DBAD_SIGNAL=ON` to the cmake command if you are on Linux Kernel mixed with Android, like on RK3588 or maybe Termux
|
||||
|
||||
You'll need an `armhf` multiarch environment, and an armhf gcc: On debian, install it with `sudo apt install gcc-arm-linux-gnueabihf`.
|
||||
|
||||
Also, on armbian, you may need to install `libc6-dev-armhf-cross` or you may have an issue with `crt1.o` and a few other files not included with box86.
|
||||
|
||||
#### for Other ARM Linux platforms
|
||||
|
||||
`mkdir build; cd build; cmake .. -DARM_DYNAREC=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j3`
|
||||
|
||||
You can also add `-DBAD_SIGNAL=ON` to the cmake command if you are on Linux Kernel mixed with Android, like on RK3588 or maybe Termux
|
||||
|
||||
#### for x86 Linux
|
||||
|
||||
`mkdir build; cd build; cmake .. -DCMAKE_C_FLAGS="-m32" -DLD80BITS=1 -DNOALIGN=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j3`
|
||||
|
||||
#### use ccmake
|
||||
### use ccmake
|
||||
|
||||
Alternatively, you can use the curses-bases ccmake (or any other gui frontend for cmake) to select wich platform to use interactively.
|
||||
|
||||
#### Customize your build
|
||||
### Customize your build
|
||||
|
||||
*use ccache if you have it*
|
||||
#### use ccache if you have it
|
||||
|
||||
Add `-DUSE_CCACHE=1` if you have ccache (it's better if you plan to touch the sources)
|
||||
|
||||
*have some debug info*
|
||||
#### To have some debug info
|
||||
|
||||
The `-DCMAKE_BUILD_TYPE=RelWithDebInfo` argument makes a build that is both optimized for speed, and has debug information embedded. That way, if you have a crash or try to analyse performance, you'll have some symbols.
|
||||
|
||||
*to have a Trace Enabled build*
|
||||
#### To have a Trace Enabled build
|
||||
|
||||
To have a trace enabled build ( ***it will be slower***), add `-DHAVE_TRACE=1` but you will need, at runtime, to have the [Zydis library](https://github.com/zyantific/zydis) library in your `LD_LIBRARY_PATH` or in the system library folders.
|
||||
To have a trace enabled build (***the interpreter will be slightly slower***), add `-DHAVE_TRACE=1`. But you will need the [Zydis library](https://github.com/zyantific/zydis) in your `LD_LIBRARY_PATH` or in the system library folders at runtime.
|
||||
|
||||
*to have ARM Dynarec*
|
||||
#### to have ARM Dynarec
|
||||
|
||||
The Dynarec is only available on the ARM architecture(Right now, anyways.). Notes also that VFPv3 and NEON are required for the Dynarec. Activate it by using `-DARM_DYNAREC=1`. Also, be sure to use `-marm` in compilation flags (because many compileur use Thumb as default, and the dynarec will not work in this mode). Note that compiling with `ARM_DYNAREC` but without hardware profile is not advise. If you get error building that "target CPU does not support ARM mode", then try to pick hardware profile (like ODROID for armv7 or PI4 for armv8). Also, if you are using a 64bits with armhf multiarch, it's much easier to pick one of the hardware profile like `RPI4ARM64`, `RK3399`, `PHYTIUM` or `SD845`.
|
||||
###### *Note: VFPv3 and NEON are required for Dynarec.*
|
||||
###### You might need to `sudo apt install neon-support` package for CMAKE to correctly detect them.
|
||||
|
||||
*not building from a git clone*
|
||||
###### *Note: Compiling with `ARM_DYNAREC` without selecting a hardware profile is not advised.*
|
||||
|
||||
If you are not building from a git clone (for example, downloading a release source zipped from github), you need to activate `-DNOGIT=1` from cmake to be able to build (normal process include git sha1 of HEAD in the version that box86 print).
|
||||
Dynarec is only available on the ARM architecture (for the meantime anyways). Activate it by using `-DARM_DYNAREC=1`.
|
||||
|
||||
You will most likely need `-marm` in compilation flags (Many compilers default to the Thumb instruction set and Dynarec does not support this).
|
||||
|
||||
###### *Note: If you get error building that "target CPU does not support ARM mode", then try to pick a hardware profile (like ODROIDXU4 for armv7 or PI4 for armv8).*
|
||||
|
||||
##### 64bit OS with Dynarec
|
||||
|
||||
If you are using a 64bit OS with armhf multiarch, it's much easier to pick one of the hardware profiles.
|
||||
|
||||
`RPI4ARM64`, `RK3399`, `PHYTIUM` or `SD845`.
|
||||
|
||||
#### Not building from a git clone
|
||||
If you are not building from a git clone (for example, downloading a release source code zip from github), you need to use `-DNOGIT=1` from cmake to be able to build (box86 uses git SHA1 to show last commit in version number).
|
||||
|
||||
----
|
||||
|
||||
Testing
|
||||
## Testing
|
||||
----
|
||||
A few tests are included.
|
||||
They can be launched with `ctest`
|
||||
They are very basic and don't test much for now.
|
||||
A few tests are included with box86.
|
||||
|
||||
They can be launched using the `ctest` command.
|
||||
|
||||
The tests are very basic and only tests some functionality for now.
|
||||
|
||||
----
|
||||
|
||||
Note about devices with Tegra X1 and newer.
|
||||
|
||||
Nvidia don't provide armhf libraries for their GPU drivers at this moment so there is no special variable to compile it for them as it would be missleading for many people. If you still want to use it wihout GPU acceleration, building it with RPI4 configuration should work just fine. As instalation of Mesa can break Nvidia driver, safest option is usage of chroot.
|
||||
NVIDIA doesn't provide armhf libraries for their GPU drivers at this time. There is no special variable to compile box86 for them, as it would be misleading to many people. If you still want to use it wihout GPU acceleration, building it with RPI4 configuration should work just fine. Installation of Mesa can break the NVIDIA driver, so the safest option is to use a chroot environment.
|
||||
|
||||
----
|
||||
|
||||
## Debian Packaging
|
||||
----
|
||||
Box86 can also be packaged into a .deb file ***using the source code zip from the releases page*** with `DEB_BUILD_OPTIONS=nostrip dpkg-buildpackage -us -uc -nc`. Configure any additional cmake options you might want in `debian/rules`.
|
||||
|
||||
## Pre-build packages
|
||||
----
|
||||
#### Debian-based Linux
|
||||
You can use the [Pi-Apps-Coders apt repository](https://github.com/Pi-Apps-Coders/box86-debs) to install precompiled box86 debs, updated every 24 hours.
|
||||
|
||||
```
|
||||
# check if .list file already exists
|
||||
if [ -f /etc/apt/sources.list.d/box86.list ]; then
|
||||
sudo rm -f /etc/apt/sources.list.d/box86.list || exit 1
|
||||
fi
|
||||
# check if .sources file already exists
|
||||
if [ -f /etc/apt/sources.list.d/box86.sources ]; then
|
||||
sudo rm -f /etc/apt/sources.list.d/box86.sources || exit 1
|
||||
fi
|
||||
# download gpg key from specified url
|
||||
if [ -f /usr/share/keyrings/box86-archive-keyring.gpg ]; then
|
||||
sudo rm -f /usr/share/keyrings/box86-archive-keyring.gpg
|
||||
fi
|
||||
sudo mkdir -p /usr/share/keyrings
|
||||
wget -qO- "https://pi-apps-coders.github.io/box86-debs/KEY.gpg" | sudo gpg --dearmor -o /usr/share/keyrings/box86-archive-keyring.gpg
|
||||
# create .sources file
|
||||
echo "Types: deb
|
||||
URIs: https://Pi-Apps-Coders.github.io/box86-debs/debian
|
||||
Suites: ./
|
||||
Signed-By: /usr/share/keyrings/box86-archive-keyring.gpg" | sudo tee /etc/apt/sources.list.d/box86.sources >/dev/null
|
||||
```
|
||||
|
||||
On a 32bit OS, run the following additional commands
|
||||
```
|
||||
sudo apt update
|
||||
sudo apt install box86-generic-arm -y
|
||||
```
|
||||
|
||||
On a 64bit OS, run the following additional commands
|
||||
```
|
||||
sudo dpkg --add-architecture armhf
|
||||
sudo apt update
|
||||
sudo apt install box86-generic-arm:armhf -y
|
||||
```
|
||||
+44
-32
@@ -1,41 +1,45 @@
|
||||
# box86
|
||||
|
||||

|
||||
|
||||
Linux Userspace x86 Emulator with a twist
|
||||
|
||||
[](https://app.travis-ci.com/ptitSeb/box86)
|
||||
[View changelog](https://github.com/ptitSeb/box86/blob/master/docs/CHANGELOG.md) | [中文](https://github.com/ptitSeb/box86/blob/master/docs/README_CN.md) | [Українська](https://github.com/ptitSeb/box86/blob/master/docs/README_UK.md) | [Report an error](https://github.com/ptitSeb/box86/issues/new)
|
||||
|
||||
     
|
||||
|
||||
----
|
||||
|
||||
Compiling/Installation
|
||||
----
|
||||
> Compilation instructions can be found [here](COMPILE.md)
|
||||
> Instructions for installing Wine for Box86 can be found [here](X86WINE.md)
|
||||
|
||||
Box86 lets you run x86 Linux programs (such as games) on non-x86 Linux systems, like ARM (host system needs to be 32bit little-endian).
|
||||
|
||||
You *NEED* a 32-bit subsystem to run and build Box86. Box86 is useless on 64-bit only systems. Also, you *NEED* a 32-bit toolchain to build Box86. A toolchain that only supports 64-bit will not compile Box86, and you'll get errors (typically on aarch64, you get "-marm" not recognized, and you'll need a multiarch or chroot environnement).
|
||||
You *NEED* a 32-bit subsystem to run and build Box86. Box86 is useless on 64-bit only systems. Also, you *NEED* a 32-bit toolchain to build Box86. A toolchain that only supports 64-bit will not compile Box86, and you'll get errors (typically on aarch64, you get "-marm" not recognized, and you'll need a multiarch or chroot environment).
|
||||
|
||||
Because Box86 uses the native versions of some "system" libraries, like libc, libm, SDL, and OpenGL, it's easy to integrate and use with most applications, and performance can be surprisingly high in many cases. Take a look at thoses bench analysis for an example [here](https://box86.org/index.php/2021/06/game-performances/).
|
||||
Because Box86 uses the native versions of some "system" libraries, like libc, libm, SDL, and OpenGL, it's easy to integrate and use with most applications, and performance can be surprisingly high in many cases. Take a look at those bench analysis for an example [here](https://box86.org/index.php/2021/06/game-performances/). That also means that you will need a 32bits userspace on 64bits OS, like `armhf` on top an `aarch64` 64bits OS.
|
||||
|
||||
Most x86 Games need OpenGL, so on ARM platforms a solution like [gl4es](https://github.com/ptitSeb/gl4es) is usually necessary. (Most ARM platforms only support OpenGL ES and/or their OpenGL implementation is dodgy (see OpenGL on Android).)
|
||||
Most x86 Games need OpenGL, so on ARM platforms a solution like [gl4es](https://github.com/ptitSeb/gl4es) might be necessary. (Some ARM platforms only support OpenGL ES and/or their OpenGL implementation is dodgy. (see OpenGL on Android))
|
||||
|
||||
Box86 now integrates a DynaRec (dynamic recompiler) for the ARM platform, providing a speed boost between 5 to 10 times faster than only using the interpreter. Some high level information on how the Dynarec work can be found [here](https://box86.org/2021/07/inner-workings-a-high%e2%80%91level-view-of-box86-and-a-low%e2%80%91level-view-of-the-dynarec/).
|
||||
|
||||
Many games already work without much tweaking, for example: WorldOfGoo, Airline Tycoon Deluxe, and FTL. Many of the GameMaker Linux games also run fine. (there's a long list, among them are UNDERTALE, A Risk of Rain, and Cook Serve Delicious)
|
||||
Many games just work without much tweaking, for example: WorldOfGoo, Airline Tycoon Deluxe, and FTL. Many of the GameMaker Linux games also run fine. (there's a long list, among them are UNDERTALE, A Risk of Rain, and Cook Serve Delicious). Unity3D games also works fine, but the OpenGL requirement might be an issue on some ARM platforms.
|
||||
|
||||
If you are serious about developing Box86, you should install ccache and build Box86 with it. (Use ccmake for example.)
|
||||
To enable TRACE (i.e. dumping to stdout all individual x86 instructions executed, with dump of registers), you'll also need [Zydis library](https://github.com/zyantific/zydis) available on your system.
|
||||
|
||||
Some x86 internal opcodes use parts of "Realmode X86 Emulator Library", see [x86primop.c](../src/emu/x86primop.c) for copyright details
|
||||
|
||||
Here's 6 videos, the first 2 videos are videos of "Airline Tycoon Deluxe" and "Heretic 2" running on a GigaHertz OpenPandora (the second one is using the dynarec), and the next 2 videos are videos of of "Bit.Trip.Runner" and "Neverwinter Night" running on an ODroid XU4 (without dynarec), and the last 2 videos are on on a Pi4: Shovel Knight (video from @ITotalJustice) and Freedom Planet (video from @djazz), also without dynarec.
|
||||
----
|
||||
Compiling/Installation
|
||||
----
|
||||
> Compilation instructions can be found [here](https://github.com/ptitSeb/box86/blob/master/docs/COMPILE.md)
|
||||
> Instructions for installing Wine for Box86 can be found [here](https://github.com/ptitSeb/box86/blob/master/docs/X86WINE.md)
|
||||
|
||||
----
|
||||
|
||||
Here are 6 videos, the first 2 videos are videos of "Airline Tycoon Deluxe" and "Heretic 2" running on a GigaHertz OpenPandora (the second one is using the dynarec), and the next 2 videos are videos of of "Bit.Trip.Runner" and "Neverwinter Night" running on an ODroid XU4 (without dynarec), and the last 2 videos are on on a Pi4: Shovel Knight (video from @ITotalJustice) and Freedom Planet (video from @djazz), also without dynarec.
|
||||
|
||||
[](https://www.youtube.com/watch?v=bLt0hMoFDLk) [](https://www.youtube.com/watch?v=MM7kWYts7IA) [](https://www.youtube.com/watch?v=8hr71S029Hg) [](https://www.youtube.com/watch?v=B4YN37z3-ws) [](https://www.youtube.com/watch?v=xk8Q30mxqPg) [](https://www.youtube.com/watch?v=_QMRMVvYrqU)
|
||||
|
||||
You can find many more Box86 video on Youtube in the [MicroLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ), [Pi Labs](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g) or [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA) Channels
|
||||
You can find many more Box86 videos on the [MicroLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ), [Pi Labs](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g) or [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA) YouTube channels.
|
||||
|
||||
Compatibility list is there: https://github.com/ptitSeb/box86-compatibility-list/issues
|
||||
Compatibility list is here: https://github.com/ptitSeb/box86-compatibility-list/issues
|
||||
|
||||
<img src="img/Box86Icon.png" width="96" height="96">
|
||||
|
||||
@@ -52,7 +56,7 @@ There are a few environment variables to control the behaviour of Box86.
|
||||
|
||||
See [here](USAGE.md) for all environment variables and what they do.
|
||||
|
||||
Note: Box86's Dynarec uses a mechanism with Memory Protection and a SegFault signal handler to handle JIT code. In simpler terms, if you want to use GDB to debug a running program that use JIT'd code (like mono/Unity3D), you will still have many "normal" segfaults triggering. It is suggested to use something like `handle SIGSEGV nostop` in GDB to not stop at each segfault, and maybe put a breakpoint inside `my_memprotectionhandler` in `signals.c` if you want to trap SegFaults.
|
||||
Note: Box86's Dynarec uses a mechanism with Memory Protection and a SegFault signal handler to handle JIT code. In simpler terms, if you want to use GDB to debug a running program that use JIT'd code (like mono/Unity3D), you will still have many "normal" segfaults triggering. It is suggested to use something like `handle SIGSEGV nostop` in GDB to not stop at each segfault, and maybe put a breakpoint inside `my_box86signalhandler` in `signals.c` if you want to trap SegFaults.
|
||||
|
||||
----
|
||||
|
||||
@@ -72,27 +76,35 @@ If you look at a 64bits version of box86, look at [Box64](https://github.com/pti
|
||||
|
||||
----
|
||||
|
||||
Notes about Box86 configuration
|
||||
----
|
||||
|
||||
Box86 now have configurations files. There are 2 files loaded. `/etc/box4.box86rc` and `~/.box86rc`. Both files have the same syntax, and is basicaly an ini files. Section in square brakets define the process name, and the rest is the env. var. to set. Looke at [Usage](USAGE.md) for detail on what parameters can be put. Box86 comes with a default file that should be installed for better stability. The file in in `system/box86.box86rc` and should be installed to `/etc/box86.box86rc` If, for some reasons, you don't want to install that file here, at least copy it to `~/.box86rc` or some game may not function correctly.
|
||||
Note that the priority is: `~/.box86rc` > `/etc/box86.box86rc` > command line
|
||||
So, your settings in `~/.box86rc` may override the setting from your command line...
|
||||
|
||||
----
|
||||
|
||||
Notes about Unity game emulation
|
||||
----
|
||||
|
||||
Running Unity games is a hit or miss for now. Unity uses Mono (which uses signals that are not well emulated enough), and a runtime embedded in the main binary. A solution would be to use a native version of the libmono library used by Unity (it can be found here: https://github.com/Unity-Technologies/mono and needs to be built from source). But the wrapping of this lib is tricky, and not done for now, so the only solution is to emulate everything. The tricky part is to emulate the "JIT" code emitted by Mono, however with the new "protected memory" mechanism implemented it should be running with correct performance now.
|
||||
You should also note that some Unity3D games require OpenGL 3+ which can be tricky to provide on ARM SBC (single-board computers) for now.
|
||||
|
||||
TL;DR: Not all Unity games work and can require a high OpenGL profile, but the speed, for the ones running, should be correct now.
|
||||
Running Unity games should generaly work now, but you should also note that many Unity3D games require OpenGL 3+ which can be tricky to provide on ARM SBC (single-board computers) for now.
|
||||
Hint: on Pi4, use `MESA_GL_VERSION_OVERRIDE=3.2` and with Panfrost use `PAN_MESA_DEBUG=gl3` to use higher profile if the game starts then quits before showing anything.
|
||||
|
||||
----
|
||||
|
||||
Notes about Steam
|
||||
----
|
||||
|
||||
Linux Steam's can run now with box86. But it's still a bit unstable, and not everything works:
|
||||
- First problem is Steam crashing after the sign-in window, if you encounter this issue, you may need to add libappindicator. To install it on Debian, run `sudo apt install libappindicator1`.
|
||||
- If you select to "Remember password", Steam is crashing on subsequent starts, unless you have libnm intalled. To install it on Debian, run `sudo apt install libnm0`.
|
||||
- Once open, Steam will only work on "Small Mode" and in "Big Picture", not in the regular "Large Mode". This is because some Steam components used in the browser view are only 64-bit now. So go in the "View" menu and switch to "Small view", else the list will stay empty. Alternatively, Steam can be started in small mode directly by using `+open steam://open/minigameslist` command line arguments.
|
||||
- To avoid the "libc.so.6 is absent" message, you can use `STEAMOS=1` and `STEAM_RUNTIME=1` as environment variables.
|
||||
- Some Steam games (most Source engine games, like "Portal" or "Half-Life 2") use libtcmalloc. Box86 will detect it and will try to LD_PRELOAD it, for better compatibility. While it should work without the aformentionned feature, it is safer to add it to your system if you intend to play those game. To install it on Debian, run `sudo apt install libtcmalloc-minimal4`.
|
||||
Linux Steam's can run now with box86. but you also need box64 for it to completly usable.
|
||||
It is advised to run steam in the Small mode, as it use the less memory, but steamwebhelper (a 64bits process) will still be loaded even if not used.
|
||||
The login screen cannot run without steamwebhelper, and will just show a blank windows without box64 properly setup in the system.
|
||||
File note, Steam will use a lot of memory, and barely fit on system with 4GB of RAM. It will not work anymore on system with less memory (as a workaround, create a swap file, login and check "remember me", the use box64rc to disable steamwebhelper and run only in small mode without swap after the 1st login)
|
||||
Final note: the Steam BigPicture will work, but also need steamwebhelper (and so box64), and lots of memory. It will not start on system with only 4GB of RAM without swap.
|
||||
- If you have trouble installing Steam, you can find `install_steam.sh` in the root folder of the box86 repo. This simple script will download and install steam in your home folder, and then create a shortcut to steam in `/usr/local/bin` (and for this it will ask for sudo permission). Simply use `steam` to launch once it's installed. Note that the installation, being in the Home folder, will only work for a single user. Don't use this script if you need a multi-user installation.
|
||||
- To avoid the "libc.so.6 is absent" message, you can use `STEAMOS=1` and `STEAM_RUNTIME=1` as environment variables (it's automatically there if you used the `install_steam.sh` script)
|
||||
|
||||
Steam for Windows installs fine but doesn't work yet.
|
||||
If you have issue with steam starting, with `steamwebhelper` not starting, you'll need to start steam with `-cef-disable-gpu` or `-cef-disable-gpu-compositor`.
|
||||
|
||||
----
|
||||
|
||||
@@ -107,19 +119,19 @@ Note: if you plan to use box86 with Wine on Raspberry Pi 3 or earlier, those mod
|
||||
Notes about Vulkan
|
||||
----
|
||||
|
||||
Box86 already wrap vulikan. If your system has a 32bits vulkan driver, box86 will use it when needed. Note that vulkan wrapping has not been tested much, due to the limited vulkan support on the hardware I currently own. Profile 1.0 and 1.1, whith some extension, should be OK. 1.2 is not really wrapped. I know some demos work on Pi4 (Sascha Willems demos build for x86 work the same as if build on armhf directly). Note that the Vulkan driver of the Pi4 DOES NOT support dxvk for now (wine DirectX->Vulkan wrapper). It's not a box86 issue, it's missing extensions (hardxware support) and a few other things that make dxvk not working on pi4. On Panfrost side, PanVK is a bit young and I haven't tested dxvk with it yet.
|
||||
Box86 already wrap Vulkan. If your system has a 32bits Vulkan driver, box86 will use it when needed. Profile 1.0, 1.1, 1.2 and 1.3, with some extensions, should be OK. DXVK, including the 2.0, works. I know some demos work on Pi4 (Sascha Willems demos build for x86 work the same as if build on armhf directly). Note that the Vulkan driver of the Pi4 DOES NOT support dxvk for now (wine DirectX->Vulkan wrapper). It's not a box86 issue, it's missing extensions (hardware support) and a few other things that make dxvk not working on pi4. On Panfrost side, PanVK is a bit young and I haven't tested dxvk with it yet.
|
||||
|
||||
----
|
||||
Final word
|
||||
----
|
||||
|
||||
I want to thank everyone who has contributed to box86 developpement.
|
||||
I want to thank everyone who has contributed to box86 development.
|
||||
There are many ways to contribute: code, financial, hardware and advertisement!
|
||||
So, in no particular order, I want to thank:
|
||||
* For their major code contribution: rajdakin, icecream95, M-HT
|
||||
* For their major financial contribution: FlyingFathead, stormchaser3000
|
||||
* For their hardware contribution: [Radxa](https://rockpi.org/), [Pine64](https://www.pine64.org/), [DragonBox](https://pyra-handheld.com/), [Novaspirit](https://www.youtube.com/channel/UCrjKdwxaQMSV_NDywgKXVmw), [HardKernel](https://www.hardkernel.com/), [TwisterOS team](https://twisteros.com/)
|
||||
* For their continous advertisement of box86 project: salva ([microLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ)), [PILab](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g)/[TwisterOS team](https://twisteros.com/), [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA), [NicoD](https://www.youtube.com/channel/UCpv7NFr0-9AB5xoklh3Snhg)
|
||||
* For their major financial contribution: FlyingFathead, stormchaser3000, dennis1248, sll00, [libre-computer-project](https://libre.computer/), [CubeCoders Limited](http://cubecoders.com/)
|
||||
* For their hardware contribution: [ADLink](https://www.adlinktech.com/Products/Computer_on_Modules/COM-HPC-Server-Carrier-and-Starter-Kit/Ampere_Altra_Developer_Platform?lang=en), [Radxa](https://rockpi.org/), [Pine64](https://www.pine64.org/), [DragonBox](https://pyra-handheld.com/), [Novaspirit](https://www.youtube.com/channel/UCrjKdwxaQMSV_NDywgKXVmw), [HardKernel](https://www.hardkernel.com/), [TwisterOS team](https://twisteros.com/), [AYN](https://www.ayntec.com/)
|
||||
* For their continuous advertisement of box86 project: salva ([microLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ)), [PILab](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g)/[TwisterOS team](https://twisteros.com/), [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA), [NicoD](https://www.youtube.com/channel/UCpv7NFr0-9AB5xoklh3Snhg)
|
||||
|
||||
And I also thank the many other people who participated even once in the project.
|
||||
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||

|
||||
|
||||
Linux用户空间的x86应用模拟器
|
||||
|
||||
[更新历史](https://github.com/ptitSeb/box86/blob/master/docs/CHANGELOG.md) | [English](https://github.com/ptitSeb/box86/blob/master/docs/README.md) | [Українська](https://github.com/ptitSeb/box86/blob/master/docs/README_UK.md) | [报告错误](https://github.com/ptitSeb/box86/issues/new)
|
||||
|
||||
     
|
||||
|
||||
----
|
||||
|
||||
使用Box86可以在ARM或其他非x86架构的Linux操作系统上运行x86 Linux程序(例如游戏),请注意,主机系统需要是**32位小端**的。
|
||||
|
||||
你需要一个**32位**的子系统来运行Box86,因为Box86在纯64位系统上无法使用,同时你也需要一个**32位**的Linux编译工具链来编译Box86,例如**arm-linux-gnueabihf-gcc**, 否则你将无法编译Box86 (一般的64位ARM编译工具链如 aarch64-linux-gnu-gcc 不支持"-marm"编译选项,会编译失败并报错)。
|
||||
|
||||
因为Box86使用了一些“系统”库的原生版本,例如libc、libm、SDL和OpenGL,所以在很多情况下性能很不错,也可以方便地与其他应用集成使用。点击[此处](https://box86.org/index.php/2021/06/game-performances/)查看Benchmark示例。
|
||||
|
||||
大多数x86游戏都用到了OpenGL,所以在ARM平台上类似于[gl4es](https://github.com/ptitSeb/gl4es)的解决方案通常是必要的。(许多ARM平台仅提供OpenGL ES支持,又或者他们的OpenGL实现很不可靠(例如Android上的OpenGL)。)
|
||||
|
||||
Box86为ARM平台集成了DynaRec(动态重编译器),比仅使用解释器提升5到10倍性能。关于Dynarec如何工作的更多信息,可以在[这里](https://box86.org/2021/07/inner-workings-a-high%e2%80%91level-view-of-box86-and-a-low%e2%80%91level-view-of-the-dynarec/)找到。
|
||||
|
||||
许多游戏已可在不做多少改动的情况下直接运行,例如:《粘粘世界》(WorldOfGoo)、《航空大亨豪华版》(Airline Tycoon Deluxe)、《超越光速》(FTL)等、基于GameMaker的游戏(《传说之下》(UNDERTALE)等)。
|
||||
|
||||
如果你想开发Box86,最好安装ccache,以缓存编译结果。
|
||||
如果你需要启用Trace跟踪(例如输出寄存器值与各条被执行的x86指令),你也需要安装[Zydis](https://github.com/zyantific/zydis)。
|
||||
|
||||
一些x86内部操作码使用“Realmode X86 Emulator Library”的部分内容,请参阅[x86primop.c](../src/emu/x86primop.c)了解版权详情
|
||||
|
||||
----
|
||||
|
||||
编译与安装
|
||||
----
|
||||
> [Box86编译指南](COMPILE.md)
|
||||
>
|
||||
> [Box86 Wine安装指南](X86WINE.md)
|
||||
|
||||
一些示例视频
|
||||
----
|
||||
|
||||
[](https://www.youtube.com/watch?v=bLt0hMoFDLk) [](https://www.youtube.com/watch?v=MM7kWYts7IA) [](https://www.youtube.com/watch?v=8hr71S029Hg) [](https://www.youtube.com/watch?v=B4YN37z3-ws) [](https://www.youtube.com/watch?v=xk8Q30mxqPg) [](https://www.youtube.com/watch?v=_QMRMVvYrqU)
|
||||
|
||||
在这几个Youtube频道可以找到更多Box86的相关视频
|
||||
|
||||
[MicroLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ)
|
||||
|
||||
[Pi Labs](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g)
|
||||
|
||||
[The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA)
|
||||
|
||||
程序兼容性列表: https://github.com/ptitSeb/box86-compatibility-list/issues
|
||||
|
||||
<img src="img/Box86Icon.png" width="96" height="96">
|
||||
|
||||
感谢制作Logo和图标的grayduck!
|
||||
|
||||
注意:
|
||||
不要把本项目和[86box](https://github.com/86Box/86Box)搞混了,后者是一个"**全量**"的x86 PC模拟器。
|
||||
|
||||
----
|
||||
|
||||
使用方法
|
||||
----
|
||||
|
||||
有若干环境变量可以设置Box86的行为。
|
||||
|
||||
点击[这里](USAGE.md)了解所有的环境变量和它们的作用。
|
||||
|
||||
请注意:Box86的Dynarec提供了一种包含"内存保护"和段错误信号处理程序的机制来处理JIT代码。简单来说,如果你想用GDB来调试一个使用JIT代码的运行程序(比如mono/Unity3D),就会触发很多“正常”的段错误。建议在GDB中使用类似于`handle SIGSEGV nostop`的命令,来防止在每个段错误时都停止程序运行,如果你想捕获段错误,可以在`signals.c`中的`my_memprotectionhandler`中放置一个断点。
|
||||
|
||||
----
|
||||
|
||||
关于64位平台的注意事项
|
||||
----
|
||||
|
||||
Box86的工作原理是直接将函数调用从x86_转换到主机系统,主机系统(Box86运行的系统)需要有32位的库。Box86并不包括任何64位<->32位的转换。所以如果你需要在64位平台上运行Box86,那么你需要建立一个32位的库环境,并以32位ARM为目标系统编译Box86(例如使用arm-linux-gnueabihf-gcc工具链交叉编译或直接在armhf chroot环境中编译运行)。
|
||||
|
||||
如果你需要运行64位应用,请考虑使用[Box64](https://github.com/ptitSeb/box64),它可以在64位平台上运行x86_64程序,但请再一次注意运行x86程序需要Box86与32位库环境(就像在x86_64的Linux上运行x86程序需要x86 multiarch库一样)。
|
||||
|
||||
----
|
||||
|
||||
关于Unity游戏的注意事项
|
||||
----
|
||||
|
||||
当前对于Unity游戏的模拟仍不完善。Unity使用Mono,但它所使用的信号机制还没有被完美模拟。理论上可以使用原生Mono库(在[这里](https://github.com/Unity-Technologies/mono)可以找到),但Mono的封装比较麻烦,现在还没完成,所以我们使用了模拟的Mono库,目前Mono的JIT动态编译代码已由"内存保护"(Protected memory)机制实现,应该能正常运行。
|
||||
|
||||
同时,一些Unity3D游戏需要OpenGL 3+,目前在大部分Arm开发板上提供OpenGL 3+是很困难的。
|
||||
|
||||
所以,并不是所有的Unity游戏都能运行,尤其是那些需要提供很高的OpenGL配置(3.2+)的游戏更有可能不行,但除此之外应该问题不大,而且能运行的游戏的性能应该不错。
|
||||
|
||||
提示:如果游戏开始后在显示任何东西之前退出,在Raspberry Pi4上使用`MESA_GL_VERSION_OVERRIDE=3.2`,在Panfrost上使用`PAN_MESA_DEBUG=gl3`来使用更高的配置文件。
|
||||
|
||||
----
|
||||
|
||||
关于Steam的注意事项
|
||||
----
|
||||
|
||||
Linux Steam 现在可以在Box86上运行,但还是有点不稳定,而且有些功能可能不正常:
|
||||
- 如果Steam在显示登录界面后崩溃,你可能需要安装libappindicator库,例如运行`sudo apt install libappindicator1`。
|
||||
- 如果你选择记住密码,而Steam在下次启动时崩溃,你可能需要安装libnm库,例如运行`sudo apt install libnm0`。
|
||||
- Steam不能在正常的大界面模式下工作,因为Steam在浏览器模式使用的一些组件只能在64位平台上运行。所以请在查看选项卡中选择"小模式",否则Steam将无法正常显示列表。或者在启动Steam添加`+open steam://open/minigameslist`参数,这样Steam将会直接在小模式下启动。
|
||||
- 为了避免"libc.so.6 is absent"的错误,请添加环境变量`STEAMOS=1` 与 `STEAM_RUNTIME=1`。
|
||||
- 一些游戏(例如基于起源引擎的游戏:《传送门》、《半衰期2》)使用了libtcmalloc库,Box86会尝试检测它们并通过LD_PRELOAD预加载它们来获得更好的兼容性,虽然应该可以在没有上述功能的情况下工作,但保险起见,我们还是建议你安装它,例如运行`sudo apt install libtcmalloc-minimal4`。
|
||||
|
||||
Windows Steam 可以安装但目前不能运行。
|
||||
|
||||
----
|
||||
|
||||
关于Wine的注意事项
|
||||
----
|
||||
|
||||
Box86现在已经支持Wine。Wine的内建程序全部能运行,许多Windows 程序和游戏也运行良好。但是不要忘记大多数 Windows 游戏都使用 Direct3D,这可能需要完整的 OpenGL 驱动程序和尽可能高的配置文件(基于 ES2 后端的 gl4es 现在不能运行 Wine 的Direct3D组件)。
|
||||
注意:如果你想在 Raspberry Pi 3 或更早版本上用 Box86 运行 Wine,由于这些设备的内核默认使用 2G/2G 虚拟内存分配(2G 空间用于用户态程序,2G 空间用于内核),与需要访问内存地址 > 2G 的 Wine 程序不兼容。 因此,你需要重新配置内核以使用 3G/1G 的内存分配方式。
|
||||
|
||||
----
|
||||
|
||||
关于Vulkan的注意事项
|
||||
----
|
||||
|
||||
Box86已经封装了Vulkan。如果设备的系统有32位的Vulkan驱动程序,Box86会在需要时使用它。但请注意,由于作者目前拥有的硬件上的Vulkan支持有限,因此Vulkan封装库尚未经过太多测试。 Vulkan 1.0、1.1与一些扩展应该能工作。 但Vulkan 1.2还没有被实现。已经有一些在树莓派4上的Vulkan演示 (Sascha Willems 的演示中,为x86构建的demo与与直接为armhf构建的demo工作均正常)。但请注意,Pi4的Vulkan驱动程序目前不支持 dxvk(wine DirectX->Vulkan 兼容层),这不是Box86的问题,而是由于缺少扩展(硬件支持)与一些其他驱动问题。而在Panfrost上,PanVK尚不成熟,暂时没有用它测试dxvk。
|
||||
|
||||
----
|
||||
|
||||
结语
|
||||
----
|
||||
|
||||
我要感谢所有为 box86 开发做出贡献的人。
|
||||
贡献方式有很多种:代码贡献、财务帮助、捐赠捐赠和广告合作!
|
||||
以下感谢不分先后:
|
||||
* 代码贡献:rajdakin, icecream95, M-HT
|
||||
* 财务帮助:FlyingFathead, stormchaser3000, dennis1248, sll00, [libre-computer-project](https://libre.computer/)
|
||||
* 硬件捐赠:[ADLink](https://www.adlinktech.com/Products/Computer_on_Modules/COM-HPC-Server-Carrier-and-Starter-Kit/Ampere_Altra_Developer_Platform?lang=en), [Radxa](https://rockpi.org/), [Pine64](https://www.pine64.org/), [DragonBox](https://pyra-handheld.com/), [Novaspirit](https://www.youtube.com/channel/UCrjKdwxaQMSV_NDywgKXVmw), [HardKernel](https://www.hardkernel.com/), [TwisterOS team](https://twisteros.com/)
|
||||
* 为本项目持续的宣传:([microLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ)), [PILab](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g)/[TwisterOS team](https://twisteros.com/), [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA), [NicoD](https://www.youtube.com/channel/UCpv7NFr0-9AB5xoklh3Snhg)
|
||||
|
||||
我还要感谢很多人,即使他们只参与了一次本项目。
|
||||
|
||||
(如果你的项目中使用了Box86,请不要忘记提及!)
|
||||
@@ -0,0 +1,138 @@
|
||||

|
||||
|
||||
Емулятор простіра користувача x86_64 із родзинкою
|
||||
|
||||
[Дивитись журнал змін](https://github.com/ptitSeb/box86/blob/master/docs/CHANGELOG.md) | [中文](https://github.com/ptitSeb/box86/blob/master/docs/README_CN.md) | [English](https://github.com/ptitSeb/box86/blob/master/docs/README.md) | [Повідомити про помилку](https://github.com/ptitSeb/box86/issues/new)
|
||||
|
||||
     
|
||||
|
||||
----
|
||||
|
||||
Box86 дозволяє запускати x86 Linux програми (наприклад, ігри) на системах Linux відмінних від x86, наприклад ARM (хост-система має мати 32-розрядний порядок редагування).
|
||||
|
||||
Вам *ПОТРІБНА* 32-розрядна підсистема для запуску та створення Box86. Box86 марний лише на 64-розрядних системах. Крім того, вам *ПОТРІБЕН* 32-розрядний інструментарій для створення Box86. Ланцюжок інструментів, який підтримує лише 64-розрядні версії, не компілює Box86, і ви отримаєте помилки (зазвичай на aarch64 ви отримуєте що «-marm» не розпізнається, і вам знадобиться середовище з мультиархітектурою або chroot).
|
||||
|
||||
Оскільки Box86 використовує рідні версії деяких «системних» бібліотек, таких як libc, libm, SDL і OpenGL, його легко інтегрувати та використовувати з більшістю програм, а продуктивність у багатьох випадках може бути напрочуд високою. Подивіться на цей стендовий аналіз для прикладу [тут](https://box86.org/index.php/2021/06/game-performances/). Це також означає, що вам знадобиться 32-бітний простір користувача на 64-бітній ОС, наприклад `armhf` поверх `aarch64` 64-бітної ОС.
|
||||
|
||||
Більшість x86-ігор потребують OpenGL, тому на платформах ARM може знадобитися таке рішення, як [gl4es](https://github.com/ptitSeb/gl4es). (Деякі платформи ARM підтримують лише OpenGL ES і/або їх реалізація OpenGL хитра. (див. OpenGL на Android))
|
||||
|
||||
Box86 інтегрується з DynaRec (динамічний рекомпілятор) для платформ ARM64 і RV64 забезпечуючи підвищення швидкості в 5-10 разів, ніж використання лише інтерпретатора. Деякі високорівневі відомості про те, як працює DynaRec, можна знайти [тут](https://box86.org/2021/07/inner-workings-a-high%e2%80%91level-view-of-box86-and-a-low%e2%80%91level-view-of-the-dynarec/).
|
||||
|
||||
Багато ігор просто працюють без особливих налаштувань, наприклад: WorldOfGoo, Airline Tycoon Deluxe і FTL. Багато ігор GameMaker Linux також працюють нормально. (є довгий список, серед них UNDERTALE, A Risk of Rain і Cook Serve Delicious). Ігри Unity3D також працюють добре, але вимога OpenGL може бути проблемою на деяких платформах ARM.
|
||||
|
||||
Якщо ви серйозно ставитеся до розробки Box86, вам слід встановити ccache та створити Box86 з ним. (Використовуйте, наприклад, ccmake.)
|
||||
Щоб увімкнути TRACE (тобто скидання в stdout усіх окремих виконаних інструкцій x86 із дампом регістрів), вам також знадобиться [бібліотека Zydis](https://github.com/zyantific/zydis), доступна у вашій системі.
|
||||
|
||||
Деякі внутрішні коди операцій x86 використовують частини «Бібліотеки емулятора Realmode X86», дивіться [x86primop.c](../src/emu/x86primop.c) для детальної інформації про авторські права.
|
||||
|
||||
----
|
||||
Компіляція/Встановлення
|
||||
----
|
||||
> Інструкцію зі складання Box86 можна знайти [тут](COMPILE.md).\
|
||||
> Інструкцію з встановлення Wine для Box86 можна знайти [тут](X86WINE.md).
|
||||
|
||||
----
|
||||
|
||||
Ось 6 відео, перші 2 відео – це відео "Airline Tycoon Deluxe" і "Heretic 2", які працюють на GigaHertz OpenPandora (друге використовує Dynarec), а наступні 2 відео – це відео "Bit.Trip.Runner" і "Neverwinter Night", які працюють на ODroid XU4 (без dynarec), а останні 2 відео на Pi4: Shovel Knight (відео від @ITotalJustice) і Freedom Planet (відео від @djazz), також без Dynarec.
|
||||
|
||||
|
||||
[](https://www.youtube.com/watch?v=bLt0hMoFDLk) [](https://www.youtube.com/watch?v=MM7kWYts7IA) [](https://www.youtube.com/watch?v=8hr71S029Hg) [](https://www.youtube.com/watch?v=B4YN37z3-ws) [](https://www.youtube.com/watch?v=xk8Q30mxqPg) [](https://www.youtube.com/watch?v=_QMRMVvYrqU)
|
||||
|
||||
Ви можете знайти багато інших відео про Box86 у YouTube каналах [MicroLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ), [Pi Labs](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g) або [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA).
|
||||
|
||||
Список сумісності доступний тут: https://github.com/ptitSeb/box86-compatibility-list/issues
|
||||
|
||||
<img src="img/Box86Icon.png" width="96" height="96">
|
||||
|
||||
Логотип і піктограма зроблені @grayduck, дякую!
|
||||
|
||||
Зауважте, що цей проект не слід плутати з [86box](https://github.com/86Box/86Box), гарним емулятором "повної системи", що спеціалізується на ранньому (до відносно недавньому) апаратному забезпеченні ПК.
|
||||
|
||||
----
|
||||
|
||||
Використання
|
||||
----
|
||||
|
||||
Є кілька змінних середовища для керування поведінкою Box86.
|
||||
|
||||
Дивіться [тут](USAGE.md) для перегляду всіх змінних середовища та того, що вони роблять.
|
||||
|
||||
Примітка: Dynarec від Box86 використовує механізм із захистом пам’яті та обробником сигналу помилки сегментів для обробки JIT коду. Простіше кажучи, якщо ви хочете використовувати GDB для налагодження запущеної програми, яка використовує JIT-код (наприклад, mono/Unity3D), ви все одно матимете багато «звичайних» помилок сегментів. Пропонується використовувати щось на зразок `handle SIGSEGV nostop` в GDB, щоб не зупинятися на кожній помилці сегмента, і, можливо, поставити точку зупину всередині `my_memprotectionhandler` в `signals.c`, якщо ви хочете перехопити помилки сегментів.
|
||||
|
||||
----
|
||||
|
||||
Історія версій/Журнал змін
|
||||
----
|
||||
|
||||
Історія версій доступна [тут](docs/CHANGELOG.md).
|
||||
|
||||
----
|
||||
|
||||
Примітки щодо 64-розрядних платформ
|
||||
----
|
||||
|
||||
Оскільки Box86 працює шляхом прямого перекладу викликів функцій із x86 на хост-систему, хост-система (на якій працює Box86) повинна мати 32-розрядні бібліотеки. Box86 не містить 32-біт <-> 64-біт перекладу. Отже, щоб запустити Box86, наприклад, на платформі ARM64, вам потрібно буде зібрати Box86 для 32-бітної ARM, а також потрібно мати chroot з 32-бітними бібліотеками.
|
||||
|
||||
Якщо ви дивитесь на 64-розрядну версію box86, подивіться на [Box64](https://github.com/ptitSeb/box64): він може запускати двійкові файли x86_64 на 64-розрядних платформах. Але зауважте, що вам все одно потрібен Box86 (і 32-розрядний chroot) для запуску бінарних файлів x86 (як це також трапляється в реальному Linux x86_64, для запуску якого потрібні бібліотеки x86 і двійковий файл в multiarch).
|
||||
|
||||
----
|
||||
|
||||
Примітки щодо конфігурації Box86
|
||||
----
|
||||
|
||||
Box86 тепер має конфігураційні файли. Завантажуються 2 файли: `/etc/box4.box86rc` і `~/.box86rc`. Обидва файли мають однаковий синтаксис і в основному є файлами ini. Розділ у квадратних дужках визначає назву процесу, а решта — встановлють змінну середовища. Подивіться на [використання](docs/USAGE.md), щоб дізнатися, які параметри можна використовувати. Box86 поставляється з файлом за замовчуванням, який слід інсталювати для кращої стабільності. Файл знаходиться в `system/box86.box86rc` і має бути встановлено в `/etc/box86.box86rc`. Якщо з певних причин ви не хочете встановлювати цей файл у `/etc`, принаймні скопіюйте його в `~/.box86rc` або гра може не працювати належним чином. Зауважте, що пріоритетом є: `~/.bashrc` > `/etc/box86.box86rc` > командний рядок
|
||||
Таким чином, ваші налаштування в `~/.bashrc` можуть замінити налаштування з вашого командного рядка...
|
||||
|
||||
----
|
||||
|
||||
Примітки щодо емуляції ігор Unity
|
||||
----
|
||||
|
||||
Запуск ігор Unity має працювати, але ви також повинні зауважити, що для багатьох ігор Unity3D потрібен OpenGL 3+, який може бути складно забезпечити на ARM SBC (одноплатних комп’ютерах). Крім того, багато нових ігор Unity3D (наприклад, KSP) використовують стиснуті текстури BC7, які не підтримуються багатьма інтегрованими GPU ARM.
|
||||
Підказка: в Pi4 використовуйте `MESA_GL_VERSION_OVERRIDE=3.2`, а в Panfrost — `PAN_MESA_DEBUG=gl3`, щоб використовувати вищий профіль, якщо гра запускається, а потім завершується, перш ніж щось показує.
|
||||
|
||||
----
|
||||
|
||||
Примітки щодо Steam
|
||||
----
|
||||
|
||||
Linux версія Steam тепер може працювати з Box86, але вам також потрібен Box64, щоб його можна було повністю використовувати.
|
||||
Рекомендується запускати Steam у small режимі, оскільки він використовує менше пам’яті, але steamwebhelper (64-бітний процес) усе одно завантажуватиметься, навіть якщо він не використовується.
|
||||
Екран входу не може працювати без steamwebhelper, і буде показувати лише порожні вікна без належного налаштування box64 у системі.
|
||||
Зауважте, що Steam використовуватиме багато пам’яті та ледве поміститься в систему з 4 ГБ оперативної пам’яті. Він більше не працюватиме в системі з меншим об’ємом пам’яті (як обхідний шлях, створіть файл підкачки, увійдіть і поставте прапорець «запам’ятати мене», використовуйте box64rc, щоб вимкнути steamwebhelper і запускати лише в малому режимі без підкачки після першого входу в систему)
|
||||
Останнє зауваження: Steam BigPicture працюватиме, але також потрібен steamwebhelper (і box64) і багато пам’яті. Він не запуститься в системі лише з 4 ГБ оперативної пам’яті без файлу підкачки.
|
||||
- Якщо у вас виникли проблеми зі встановленням Steam, ви можете знайти `install_steam.sh` у кореневій папці сховища box86. Цей простий скрипт завантажить і встановить Steam у вашу домашню папку, а потім створить ярлик steam у `/usr/local/bin` (для цього він запитає дозвіл sudo). Просто використовуйте `steam` для запуску після встановлення. Зауважте, що інсталяція, яка знаходиться в папці Home, працюватиме лише для одного користувача. Не використовуйте цей скрипт, якщо вам потрібна багатокористувацька інсталяція.
|
||||
- Щоб уникнути повідомлення «libc.so.6 відсутній», ви можете використовувати `STEAMOS=1` і `STEAM_RUNTIME=1` як змінні середовища (воно автоматично з’являється, якщо ви використовували сценарій `install_steam.sh`)
|
||||
|
||||
Якщо у вас виникла проблема із запуском Steam (не запускається `steamwebhelper`), вам потрібно запустити Steam за допомогою `-cef-disable-gpu` або `-cef-disable-gpu-compositor`.
|
||||
|
||||
----
|
||||
|
||||
Примітки щодо Wine
|
||||
----
|
||||
|
||||
Wine тепер підтримується. Інтегровани програми Wine працює як і багато програм та ігор для Windows. Не забувайте, що більшість ігор для Windows використовують Direct3D, для цього може знадобитися повний драйвер OpenGL і якомога більш високий профіль (і gl4es з бекендом ES2 наразі мають проблеми з Wine).
|
||||
Примітка: якщо ви плануєте використовувати box86 з Wine на Raspberry Pi 3 або ранішої версії, ці моделі використовують ОС за замовчуванням, яка має ядро з розділенням 2/2 (тобто 2G місця для програми користувача та 2 Г місця для ядра). Це несумісно з програмами Wine, яким потрібен доступ до пам’яті > 2 Гб адреси. Тож вам потрібно буде переналаштувати ядро для розділення 3G/1G.
|
||||
|
||||
----
|
||||
|
||||
Примітки щодо Vulkan
|
||||
----
|
||||
|
||||
Box86 вже використовує Vulkan. Якщо у вашій системі є 32-розрядний драйвер Vulkan, Box86 використовуватиме його за потреби. Профіль 1.0, 1.1, 1.2 і 1.3, з деякими розширеннями, має бути в порядку. DXVK, включаючи 2.0, працює. Я знаю, що деякі демонстраційні версії працюють на Pi4 (демонстраційні версії Sascha Willems для x86 працюють так само, як якщо б створювати безпосередньо на armhf). Зауважте, що драйвер Vulkan для Pi4 наразі НЕ підтримує DXVK (обгортка Wine DirectX->Vulkan). Це не проблема Box86, у драйвері відсутні розширення (підтримка апаратного забезпечення) та кілька інших речей, через які DXVK не працює на pi4. З боку Panfrost, PanVK трохи молодий, і я ще не тестував DXVK з ним.
|
||||
|
||||
----
|
||||
Останнє слово
|
||||
----
|
||||
|
||||
Я хочу подякувати всім, хто зробив внесок у розвиток box86.
|
||||
Є багато способів зробити свій внесок: код, фінанси, апаратне забезпечення та реклама!
|
||||
Отже, без особливого порядку, я хочу подякувати:
|
||||
* За основний внесок у код: rajdakin, icecream95, M-HT
|
||||
* За великий фінансовий внесок: FlyingFathead, stormchaser3000, dennis1248, sll00, [libre-computer-project](https://libre.computer/)
|
||||
* За внесок у апаратне забезпечення: [ADLink](https://www.adlinktech.com/Products/Computer_on_Modules/COM-HPC-Server-Carrier-and-Starter-Kit/Ampere_Altra_Developer_Platform?lang=en), [Radxa](https://rockpi.org/), [Pine64](https://www.pine64.org/), [DragonBox](https://pyra-handheld.com/), [Novaspirit](https://www.youtube.com/channel/UCrjKdwxaQMSV_NDywgKXVmw), [HardKernel](https://www.hardkernel.com/), [Команда TwisterOS](https://twisteros.com/)
|
||||
* За постійну рекламу Box86: 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)
|
||||
|
||||
І я також дякую багатьом іншим людям, які хоч раз брали участь у проекті.
|
||||
|
||||
(Якщо ви використовуєте Box86 у своєму проекті, будь ласка, не забудьте згадати про це!)
|
||||
+205
-38
@@ -3,169 +3,327 @@ Usage
|
||||
----
|
||||
|
||||
There are many environment variables to control Box86 behaviour.
|
||||
Env. var with * can also be put inside box64rc files
|
||||
|
||||
#### BOX86_LOG
|
||||
#### BOX86_LOG *
|
||||
Controls the Verbosity level of the logs
|
||||
* 0: NONE : No message (except some fatal error). (Default.)
|
||||
* 1: INFO : Show some minimum log (Example: librairies not found)
|
||||
* 2: DEBUG : Details a lot of stuff (Example: relocations or functions called).
|
||||
* 3: DUMP : All DEBUG plus DUMP of all ELF Info (so same as `BOX86_LOG=2 BOX86_DUMP=1`)
|
||||
|
||||
#### BOX86_DUMP
|
||||
#### BOX86_DUMP *
|
||||
Controls the Dump of elf content
|
||||
* 0: No dump of elf information (Default)
|
||||
* 1: Dump elf sections and relocations and other information (also active if using `BOX86_LOG=3`)
|
||||
|
||||
#### BOX86_ROLLING_LOG *
|
||||
Show last few wrapped function call when a Signal is caught
|
||||
* 0: No last function call printed (Default.)
|
||||
* 1: Last 16 wrapped functions calls printed when a signal is printed. Incompatible with BOX86_LOG>1 (may need BOX86_SHOWSEGV=1 also)
|
||||
* N: Last N wrapped functions calls printed when a signal is printed. Incompatible with BOX86_LOG>1 (may need BOX86_SHOWSEGV=1 also)
|
||||
|
||||
#### BOX86_NOBANNER
|
||||
Disables Box86 printing its version and build
|
||||
* 0 : Enable printing its banner. (Default.)
|
||||
* 1 : Disable printing its banner.
|
||||
|
||||
#### BOX86_LD_LIBRARY_PATH
|
||||
#### BOX86_LD_LIBRARY_PATH *
|
||||
Path to look for x86 libraries. Default is current folder and `lib` in current folder.
|
||||
Also, `/usr/lib/i386-linux-gnu` and `/lib/i386-linux-gnu` are added if they exist.
|
||||
Also, `/usr/lib/i386-linux-gnu`, `/lib/i386-linux-gnu`, and `/usr/lib/box86-i386-linux-gnu` are added if they exist.
|
||||
|
||||
#### BOX86_PATH
|
||||
#### BOX86_PATH *
|
||||
Path to look for x86 executable. Default is current folder and `bin` in current folder.
|
||||
|
||||
#### BOX86_DLSYM_ERROR
|
||||
#### BOX86_DLSYM_ERROR *
|
||||
Enables/Disables the logging of `dlsym` errors.
|
||||
* 0 : Don't log `dlsym` errors. (Default.)
|
||||
* 1 : Log dlsym errors.
|
||||
|
||||
#### BOX86_TRACE_FILE
|
||||
#### BOX86_TRACE_FILE *
|
||||
Send all log and trace to a file instead of `stdout`
|
||||
Also, if name contains `%pid` then this is replaced by the actual PID of box86 instance
|
||||
Use `stderr` to use this instead of default `stdout`
|
||||
|
||||
#### BOX86_TRACE
|
||||
#### BOX86_TRACE *
|
||||
Only on build with trace enabled. Trace allow the logging of all instruction executed, along with register dump
|
||||
* 0 : No trace. (Default.)
|
||||
* 1 : Trace enabled. Trace start after the initialisation of all depending libraries is done.
|
||||
* symbolname : Trace only `symbolname` (trace is disable if the symbol is not found).
|
||||
* 0xXXXXXXX-0xYYYYYYY : Trace only between the 2 addresses.
|
||||
|
||||
#### BOX86_TRACE_INIT
|
||||
#### BOX86_TRACE_INIT *
|
||||
Use BOX86_TRACE_INIT instead of BOX_TRACE to start trace before the initialisation of libraries and the running program
|
||||
* 0 : No trace. (Default.)
|
||||
* 1 : Trace enabled. The trace start with the initialisation of all depending libraries is done.
|
||||
|
||||
#### BOX86_TRACE_START
|
||||
#### BOX86_TRACE_START *
|
||||
Only on builds with trace enabled.
|
||||
* NNNNNNN : Start trace only after NNNNNNNN opcode execute (number is an `uint64_t`).
|
||||
|
||||
#### BOX86_TRACE_XMM
|
||||
#### BOX86_TRACE_XMM *
|
||||
Only on builds with trace enabled.
|
||||
* 0 : The XMM (i.e. SSE/SSE2) register will not be logged with the general and x86 registers. (Default.)
|
||||
* 1 : Dump the XMM registers.
|
||||
|
||||
#### BOX86_LOAD_ADDR
|
||||
#### BOX86_TRACE_EMM *
|
||||
Only on builds with trace enabled.
|
||||
* 0 : The EMM (i.e. MMX) register will not be logged with the general and x86 registers. (Default.)
|
||||
* 1 : Dump the EMM registers.
|
||||
|
||||
#### BOX86_LOAD_ADDR *
|
||||
Try to load at 0xXXXXXX main binary (if binary is a PIE)
|
||||
* 0xXXXXXXXX : The load address . (Only active on PIE programs.)
|
||||
|
||||
#### BOX86_NOSIGSEGV
|
||||
#### BOX86_NOSIGSEGV *
|
||||
Disable handling of SigSEGV. (Very useful for debugging.)
|
||||
* 0 : Let the x86 program set sighandler for SEGV (Default.)
|
||||
* 1 : Disable the handling of SigSEGV.
|
||||
|
||||
#### BOX86_NOSIGILL
|
||||
#### BOX86_NOSIGILL *
|
||||
Disable handling of SigILL (to ease debugging mainly).
|
||||
* 0 : Let x86 program set sighandler for Illegal Instruction
|
||||
* 1 : Disables the handling of SigILL
|
||||
|
||||
#### BOX86_X11COLOR16
|
||||
#### BOX86_X11COLOR16 *
|
||||
PANDORA only: Try converting X11 color from 32 bits to 16 bits (to avoid light green on light cyan windows).
|
||||
* 0 : Don't touch X11 colors. (Default.)
|
||||
* 1 : Change colors arguments in XSetForeground, XSetBackground and XCreateGC.
|
||||
|
||||
#### BOX86_X11THREADS
|
||||
#### BOX86_X11THREADS *
|
||||
Call XInitThreads when loading X11. (This is mostly for old Loki games with the Loki_Compat library.)
|
||||
* 0 : Don't force call XInitThreads. (Default.)
|
||||
* 1 : Call XInitThreads as soon as libX11 is loaded.
|
||||
|
||||
#### BOX86_X11GLX
|
||||
#### BOX86_X11GLX *
|
||||
Force libX11's GLX extension to be present.
|
||||
* 0 : Do not force libX11's GLX extension to be present.
|
||||
* 1 : GLX will always be present when using XQueryExtension. (Default.)
|
||||
|
||||
#### BOX86_DYNAREC_DUMP
|
||||
#### BOX86_DYNAREC_DUMP *
|
||||
Enables/disables Box86's Dynarec's dump.
|
||||
* 0 : Disable Dynarec's blocks dump. (Default.)
|
||||
* 1 : Enable Dynarec's blocks dump.
|
||||
* 2 : Enable Dynarec's blocks dump with some colors.
|
||||
|
||||
#### BOX86_DYNAREC_LOG
|
||||
#### BOX86_DYNAREC_LOG *
|
||||
Set the level of DynaRec's logs.
|
||||
* 0 : NONE : No Logs for DynaRec. (Default.)
|
||||
* 1 :INFO : Minimum Dynarec Logs (only unimplemented OpCode).
|
||||
* 2 : DEBUG : Debug Logs for Dynarec (with details on block created / executed).
|
||||
* 3 : VERBOSE : All of the above plus more.
|
||||
|
||||
#### BOX86_DYNAREC
|
||||
#### BOX86_DYNAREC *
|
||||
Enables/Disables Box86's Dynarec.
|
||||
* 0 : Disables Dynarec.
|
||||
* 1 : Enable Dynarec. (Default.)
|
||||
|
||||
#### BOX86_DYNAREC_TRACE
|
||||
#### BOX86_DYNAREC_TRACE *
|
||||
Enables/Disables trace for generated code.
|
||||
* 0 : Disable trace for generated code. (Default.)
|
||||
* 1 : Enable trace for generated code (like regular Trace, this will slow down the program a lot and generate huge logs).
|
||||
|
||||
#### BOX86_NODYNAREC
|
||||
#### BOX86_NODYNAREC *
|
||||
Forbid dynablock creation in the interval specified (helpfull for debugging behaviour difference between Dynarec and Interpretor)
|
||||
* 0xXXXXXXXX-0xYYYYYYYY : define the interval where dynablock cannot start (inclusive-exclusive)
|
||||
|
||||
#### BOX86_DYNAREC_BIGBLOCK
|
||||
#### BOX86_DYNAREC_TEST *
|
||||
Dynarec will compare it's execution with the interpreter (super slow, only for testing)
|
||||
* 0 : No comparison
|
||||
* 1 : Each opcode runs on interepter and on Dynarec, and regs and memory are compared and print if different
|
||||
|
||||
#### BOX86_DYNAREC_BIGBLOCK *
|
||||
Enables/Disables Box86's Dynarec building BigBlock.
|
||||
* 0 : Don't try to build block as big as possible (can help program using lots of thread and a JIT, like C#/Unity) (Default when libmonobdwgc-2.0.so is loaded)
|
||||
* 1 : Build Dynarec block as big as possible (Default.)
|
||||
* 2 : Build Dynarec block bigger (don't stop when block overlaps)
|
||||
|
||||
#### BOX86_DYNAREC_STRONGMEM
|
||||
#### BOX86_DYNAREC_FORWARD *
|
||||
Define Box86's Dynarec max allowed forward value when building Block.
|
||||
* 0 : No forward value. When current block end, don't try to go further even if there are previous forward jumps
|
||||
* XXX : Allow up to XXXX bytes of gap when building a Block after the block end to next forward jump (Default: 128)
|
||||
|
||||
#### BOX86_DYNAREC_STRONGMEM *
|
||||
Enable/Disable simulation of Strong Memory model
|
||||
* 0 : Don't try anything special (Default.)
|
||||
* 1 : Enable some Memory Barrier when reading from memory (on some MOV opcode) to simulate Strong Memory Model while trying to limit performance impact (Default when libmonobdwgc-2.0.so is loaded)
|
||||
* 2 : Enable some Memory Barrier when reading from memory (on some MOV opcode) to simulate Strong Memory Model
|
||||
* 1 : Enable some Memory Barrier when writting to memory (on some MOV opcode) to simulate Strong Memory Model while trying to limit performance impact (Default when libmonobdwgc-2.0.so is loaded)
|
||||
* 2 : All 1. plus a memory barrier on every write to memory using MOV
|
||||
* 3 : All 2. plus Memory Barrier when reading from memory and on some SSE/SSE2 opcodes too
|
||||
|
||||
#### BOX86_LIBGL
|
||||
#### BOX86_DYNAREC_X87DOUBLE *
|
||||
Force the use of Double for x87 emulation
|
||||
* 0 : Try to use float when possible for x87 emulation (faster, Default)
|
||||
* 1 : Only use Double for x87 emulation (slower, may be needed for some specific games, like Crysis were it's enable automatically)
|
||||
|
||||
#### BOX86_DYNAREC_FASTNAN *
|
||||
Enable/Disable generation of -NAN
|
||||
* 0 : Generate -NAN like on x86 (slower, more x86 accurate)
|
||||
* 1 : Don't do anything special with NAN, to go as fast as possible (Default)
|
||||
|
||||
#### BOX86_DYNAREC_FASTROUND *
|
||||
Enable/Disable generation of precise x86 rounding
|
||||
* 0 : Generate float/double -> int rounding and use current rounding mode for float/double compution like on x86
|
||||
* 1 : Don't do anything special with edge case Rounding, to go as fast as possible (no INF/NAN/Overflow -> MIN_INT conversion, and no set rounding mode) (faster, Default)
|
||||
|
||||
#### BOX86_DYNAREC_SAFEFLAGS *
|
||||
Handling of flags on CALL/RET opcodes
|
||||
* 0 : Treat CALL/RET as if it never needs any flags (faster but may have side-effects)
|
||||
* 1 : most of RET will need flags, most of CALLS will not (Default)
|
||||
* 2 : All CALL/RET will need flags (slower, but might be needed. Automatically enabled for Vara.exe)
|
||||
|
||||
#### BOX86_DYNAREC_CALLRET *
|
||||
Optimisation of CALL/RET opcodes (not compatible with jit/dynarec/smc)
|
||||
* 0 : Don't optimize CALL/RET, use Jump Table for boths (Default)
|
||||
* 1 : Try to optimized CALL/RET, skipping the use of the JumpTable when possible
|
||||
|
||||
#### BOX86_DYNAREC_BLEEDING_EDGE *
|
||||
Detect MonoBleedingEdge and apply conservative settings
|
||||
* 0 : Don't detect MonoBleedingEdge
|
||||
* 1 : Detect MonoBleedingEdge, and apply BIGBLOCK=0 STRONGMEM=1 if detected (Default)
|
||||
|
||||
#### BOX86_DYNAREC_JVM *
|
||||
Detect libjvm and apply conservative settings
|
||||
* 0 : Don't detect libjvm
|
||||
* 1 : Detect libjvm, and apply BIGBLOCK=0 STRONGMEM=1 if detected (Default)
|
||||
|
||||
#### BOX86_DYNAREC_WAIT *
|
||||
Behavior with FillBlock is not availble (FillBlock build Dynarec blocks and is not multithreaded)
|
||||
* 0 : Dynarec will not wait for FillBlock to ready and use Interpreter instead (might speedup a bit massive multithread or JIT programs)
|
||||
* 1 : Dynarec will wait for FillBlock to be ready (Default)
|
||||
|
||||
#### BOX86_DYNAREC_MISSING *
|
||||
Dynarec print the missing opcodes
|
||||
* 0 : not print the missing opcode (Default, unless DYNAREC_LOG>=1 or DYNAREC_DUMP>=1 is used)
|
||||
* 1 : Will print the missing opcodes
|
||||
|
||||
#### BOX86_SSE_FLUSHTO0 *
|
||||
Handling of SSE Flush to 0 flags
|
||||
* 0 : Just track the flag (Default)
|
||||
* 1 : Direct apply of SSE Flush to 0 flag
|
||||
|
||||
#### BOX86_X87_NO80BITS *
|
||||
Handling of x87 80bits long double
|
||||
* 0 : Try to handle 80bits long double as precise as possible (Default)
|
||||
* 1 : Handle them as double
|
||||
|
||||
#### BOX86_MAXCPU
|
||||
Maximum CPU Core exposed
|
||||
* 0 : Don't cap the number of cpu core exposed (Default)
|
||||
* XXX : Cap the maximum CPU Core exposed to XXX (usefull with wine64 or GridAutosport for example)
|
||||
|
||||
#### BOX86_LIBCEF *
|
||||
Detect libcef and apply malloc_hack settings
|
||||
* 0 : Don't detect libcef
|
||||
* 1 : Detect libcef, and apply MALLOC_HACK=2 if detected (Default)
|
||||
|
||||
#### BOX86_SDL2_JGUID *
|
||||
Need a workaround for SDL_GetJoystickGUIDInfo function for wrapped SDL2
|
||||
* 0 : Don't use any workaround
|
||||
* 1 : Use a workaround for program that use the private SDL_GetJoystickGUIDInfo function with 1 missing argument
|
||||
|
||||
#### BOX86_MUTEX_ALIGNED *
|
||||
Will mutex are used as-is or wrapped to handle unaligned used
|
||||
* 0 : Mutex will be wrapped in case unaligned mutexes are used (Default)
|
||||
* 1 : Do no wrap mutex and use them as-is (faster, but might crash with SEGBUS error)
|
||||
|
||||
#### BOX86_LIBGL *
|
||||
* libXXXX set the name for libGL (defaults to libGL.so.1).
|
||||
* /PATH/TO/libGLXXX : Sets the name and path for libGL
|
||||
You can also use SDL_VIDEO_GL_DRIVER
|
||||
|
||||
#### BOX86_LD_PRELOAD
|
||||
#### BOX86_LD_PRELOAD *
|
||||
* XXXX[:YYYYY] force loading XXXX (and YYYY...) libraries with the binary
|
||||
PreLoaded libs can be emulated or native, and are treated the same way as if they were comming from the binary
|
||||
PreLoaded libs can be emulated or native, and are treated the same way as if they were comming from the binary (not that using this inside a rcfile might not work if the process needs to be renamed, for example for Wine process)
|
||||
|
||||
#### BOX86_EMULATED_LIBS
|
||||
#### BOX86_EMULATED_LIBS *
|
||||
* XXXX[:YYYYY] force lib XXXX (and YYYY...) to be emulated (and not wrapped)
|
||||
Some games uses an old version of some libraries, with an ABI incompatible with native version.
|
||||
Note that LittleInferno for example is auto detected, and libvorbis.so.0 is automatical added to emulated libs, and same for Don't Starve (and Together / Server variant) that use an old SDL2 too
|
||||
|
||||
#### BOX86_ALLOWMISSINGLIBS
|
||||
Allow Box86 to continue even if a library is missing.
|
||||
#### BOX86_ALLOWMISSING_LIBS *
|
||||
Allow Box86 to continue even if a library is missing (renamed from BOX86_ALLOWMISSINGLIBS).
|
||||
* 0 : Box86 will stop if a library cannot be loaded. (Default.)
|
||||
* 1 : Continue even if a needed library cannot be loaded. Unadvised, this will, in most cases, crash later on.
|
||||
|
||||
#### BOX86_NOPULSE
|
||||
#### BOX86_ALLOWMISSING_SYMBOLS *
|
||||
Allow dlopen with RTLD_NOW flag to not resolve all symbols.
|
||||
* 0 : Box86 will stop if a library have unresolved symbols. (Default.)
|
||||
* 1 : Continue even if a needed library have unresolved symbols (like symbols not yet wrapped).
|
||||
|
||||
#### BOX86_PREFER_WRAPPED *
|
||||
Box86 will use wrapped libs even if the lib is specified with absolute path
|
||||
* 0 : Try to use emulated libs when they are defined with absolute path (Default.)
|
||||
* 1 : Use Wrapped native libs even if path is absolute
|
||||
|
||||
#### BOX86_PREFER_EMULATED *
|
||||
Box86 will prefer emulated libs first (execpt for glibc, alsa, pulse, GL, vulkan and X11
|
||||
* 0 : Native libs are prefered (Default.)
|
||||
* 1 : Emulated libs are prefered (Default for program running inside pressure-vessel)
|
||||
|
||||
#### BOX86_NOPULSE *
|
||||
Disables the load of pulseaudio libraries.
|
||||
* 0 : Load pulseaudio libraries if found. (Default.)
|
||||
* 1 : Disables the load of pulse audio libraries (libpulse and libpulse-simple), both the native library and the x86 library
|
||||
|
||||
#### BOX86_NOGTK
|
||||
#### BOX86_NOGTK *
|
||||
Disables the loading of wrapped GTK libraries.
|
||||
* 0 : Load wrapped GTK libraries if found. (Default.)
|
||||
* 1 : Disables loading wrapped GTK libraries (can be used with Steam, along with STEAM_RUNTIME=1 to use the i386 version of GTK).
|
||||
* 1 : Disables loading wrapped GTK libraries.
|
||||
|
||||
#### BOX86_NOVULKAN
|
||||
#### BOX86_NOVULKAN *
|
||||
Disables the load of vulkan libraries.
|
||||
* 0 : Load vulkan libraries if found.
|
||||
* 1 : Disables the load of vulkan libraries, both the native and the i386 version (can be useful on Pi4, where the vulkan driver is not quite there yet.)
|
||||
|
||||
#### BOX86_FIX_64BIT_INODES
|
||||
#### BOX86_NOCRASHHANDLER *
|
||||
Diables crashhandler.so
|
||||
* 0 : Regular process for crashhandler.so (Default)
|
||||
* 1 : Do not load crashhandler.so, even if present
|
||||
|
||||
#### BOX86_FUTEX_WAITV *
|
||||
Use of the new fuext_waitc syscall
|
||||
* 0 : Do not try to use it, return unsupported (Default for BAD_SIGNAL build)
|
||||
* 1 : let program use the syscall if the host system support it (Default for other build)
|
||||
|
||||
#### BOX86_ENV
|
||||
* XXX=yyyy
|
||||
will add XXX=yyyy env. var.
|
||||
|
||||
#### BOX86_ENV1
|
||||
* XXX=yyyy
|
||||
will add XXX=yyyy env. var. and continue with BOX86_ENV2 ... until var doesn't exist
|
||||
|
||||
#### BOX86_ARG0
|
||||
Define argv[0] of the executable.
|
||||
* yyyy
|
||||
Will rewrite argv[0] instead of using program path.
|
||||
|
||||
#### BOX86_FIX_64BIT_INODES *
|
||||
Fix/Don't fix 64bit inodes
|
||||
* 0 : Don't fix 64bit inodes. (Default.)
|
||||
* 1 : Fix 64bit inodes. Helps when running on Filesystems with 64bit inodes. Is useful when a program uses API functions which doesn't support it and the program doesn't use inodes information.
|
||||
|
||||
#### BOX86_JITGDB
|
||||
#### BOX86_SHOWSEGV *
|
||||
Show Segfault signal even if a signal handler is present
|
||||
* 0 : Don't force segfault details when a signal handler is install (Default, to limit message spamming)
|
||||
* 1 : Show segfault details
|
||||
|
||||
#### BOX86_SHOWBT *
|
||||
Show a backtrace (native and emulated) on Signal
|
||||
* 0 : Don't show any backtrace (Default.)
|
||||
* 1 : Show native backtrace when a signal is dumped (not available on Andoid build)
|
||||
|
||||
#### BOX86_BASH *
|
||||
Define x86 bash to launch script
|
||||
* yyyy
|
||||
Will use yyyy as x86 bash to launch script. yyyy needs to be a full path to a valid x86 version of bash. Note that is Box64 is available, an x86_64 version of bash can also be used. Also, BOX64_BASH env. var. will also be read if BOX86_BASH is not defined.
|
||||
|
||||
#### BOX86_BOX64
|
||||
Define where to find box64 binary
|
||||
* yyyy
|
||||
Will use yyyy as x86_64 interpreter, to launch x64_64 binaries
|
||||
|
||||
#### BOX86_JITGDB *
|
||||
|
||||
* 0 : Just print the Segfault message on segfault (default)
|
||||
* 1 : Launch `gdb` when a segfault, bus error or illegal instruction signal is trapped, attached to the offending process and go in an endless loop, waiting.
|
||||
@@ -176,3 +334,12 @@ Fix/Don't fix 64bit inodes
|
||||
* 2 : Launch `gdbserver` when a segfault, bus error or illegal instruction signal is trapped, attached to the offending process, and go in an endless loop, waiting.
|
||||
Use `gdb /PATH/TO/box86` and then `target remote 127.0.0.1:1234` to connect to the gdbserver (or use actual IP if not on the machine). After that, the procedure is the same as with ` BOX86_JITGDB=1`.
|
||||
This mode can be usefullwhen programs redirect all console output to a file (like Unity3D Games)
|
||||
* 3 : Launch `lldb` when a segfault, bus error or illegal instruction signal is trapped, attached to the offending process and go in an endless loop, waiting.
|
||||
|
||||
#### BOX86_NORCFILES
|
||||
If the env var exist, no rc files (like /etc/box86.box86rc and ~/.box86rc) will be loaded
|
||||
|
||||
#### BOX86_NOSANDBOX
|
||||
* 0 : Nothing special
|
||||
* 1 : Added "--no-sandbox" to command line arguments (usefull for chrome based programs)
|
||||
|
||||
+50
-13
@@ -3,10 +3,11 @@ _TwisterOS users: Wine, winetricks, and Box86 are already installed in TwisterOS
|
||||
|
||||
_Raspberry Pi users: Wine requires a 3G/1G split memory kernel. Raspberry Pi OS for the Pi 4 already has a 3G/1G split kernel and works with Wine, but **the Pi 3B+ and earlier models have a 2G/2G kernel and require a custom-compiled 3G/1G kernel to get Wine working.**_
|
||||
|
||||
Using Wine with Box86 allows (x86) Windows programs to run on ARM Linux computers (x64 is not yet implemented).
|
||||
See installation steps below (in the [Examples](#examples) section).
|
||||
|
||||
Box86 needs `wine-i386` to be installed **manually** on ARM devices. Even though `wine-armhf` is available in many repo's on ARM devices (ie using _apt-get_ will attempt to install `wine-armhf` by default), `wine-armhf` will not work with Box86. Note that manual installation is required since using `multiarch` will result in your ARM device thinking it needs to install lots of i386 dependencies to make `wine-i386` work. The "twist" in Box86 is that Box86 "wraps" many of Wine's core Linux i386 libraries (.so files) so that their calls are interpretable by your ARM devices other armhf Linux system libraries. Also note that wrapping libraries is an ongoing process throughout Box86 development and that some programs may not run properly until all of their i386 library dependencies are wrapped.
|
||||
Using Wine with Box86 allows (x86) Windows programs to run on ARM Linux computers (for x64, use [box64](https://github.com/ptitSeb/box64) & wine-amd64 with an `aarch64` processor).
|
||||
|
||||
Box86 needs `wine-i386` to be installed **manually** on ARM devices. Even though `wine-armhf` is available in many repo's on ARM devices (ie using _apt-get_ will attempt to install `wine-armhf` by default), `wine-armhf` will not work with Box86. Note that manual installation is required since using `multiarch` will result in your ARM device thinking it needs to install lots of i386 dependencies to make `wine-i386` work. The "twist" in Box86 is that Box86 "wraps" many of Wine's core Linux i386 libraries (.so files) so that their calls are interpretable by your ARM device's other armhf Linux system libraries. Also note that wrapping libraries is an ongoing process throughout Box86 development and that some programs may not run properly until all of their i386 library dependencies are wrapped.
|
||||
|
||||
Installation files for Wine can be found in the [WineHQ repository](https://dl.winehq.org/wine-builds/debian/dists/buster/main/binary-i386/), the [TwisterOS FAQ](https://twisteros.com/faq.html) page, or the [PlayOnLinux website repository](https://www.playonlinux.com/wine/). Box86 requires the "i386" (x86) version of Wine even though we are installing it on an ARM processor.
|
||||
|
||||
@@ -15,6 +16,7 @@ The general procedure for installing Wine for Box86 is to...
|
||||
- Download all the install files (.deb, .zip, or even .pol files) for the version of Wine you wish to install
|
||||
- Unzip or dpkg the install files into one folder
|
||||
- Move that folder to the directory that you wish Wine to run from (in TwisterOS, this is `~/wine/` by default)
|
||||
- If you are running box86/i386-wine on a 64bit ARM OS (aarch64), you will also have to install some extra armhf libraries.
|
||||
- Go to `/usr/local/bin` and make symlinks or scripts that will point to your main wine binaries (`wine`, `winecfg`, and `wineserver`).
|
||||
- Boot wine to create a new wineprefix (`wine wineboot`).
|
||||
- Download winetricks (which is simply a very complicated bash script), make it executable, then copy it to `/usr/local/bin`.
|
||||
@@ -40,7 +42,7 @@ rm ~/wine.tgz # clean up
|
||||
|
||||
# Install shortcuts (make launcher & symlinks. Credits: grayduck, Botspot)
|
||||
echo -e '#!/bin/bash\nsetarch linux32 -L '"$HOME/wine/bin/wine "'"$@"' | sudo tee -a /usr/local/bin/wine >/dev/null # Create a script to launch wine programs as 32bit only
|
||||
#sudo ln -s ~/wine/bin/wine /usr/local/bin/wine # You could aslo just make a symlink, but box86 only works for 32bit apps at the moment
|
||||
#sudo ln -s ~/wine/bin/wine /usr/local/bin/wine # You could also just make a symlink, but box86 only works for 32bit apps at the moment
|
||||
sudo ln -s ~/wine/bin/wineboot /usr/local/bin/wineboot
|
||||
sudo ln -s ~/wine/bin/winecfg /usr/local/bin/winecfg
|
||||
sudo ln -s ~/wine/bin/wineserver /usr/local/bin/wineserver
|
||||
@@ -50,11 +52,29 @@ sudo chmod +x /usr/local/bin/wine /usr/local/bin/wineboot /usr/local/bin/winecfg
|
||||
wine wineboot
|
||||
```
|
||||
|
||||
### Installing Wine for Box86 on Raspberry Pi OS Buster from WineHQ .deb files
|
||||
### Installing Wine for Box86 on Raspberry Pi OS from WineHQ .deb files
|
||||
_Links from the [WineHQ repo](https://dl.winehq.org/wine-builds/debian/dists/buster/main/binary-i386/)_
|
||||
|
||||
This install method allows you to install different versions of Wine. You may install any version and any branch of Wine that you wish (wine-devel, wine-stable, or wine-staging).
|
||||
This install method allows you to install different versions of Wine. You may install any version/branch of Wine that you wish.
|
||||
```
|
||||
### User-defined Wine version variables ################
|
||||
# - Replace the variables below with your system's info.
|
||||
# - Note that we need the i386 version for Box86 even though we're installing it on our ARM processor.
|
||||
# - Wine download links from WineHQ: https://dl.winehq.org/wine-builds/
|
||||
|
||||
wbranch="devel" #example: devel, staging, or stable (wine-staging 4.5+ requires libfaudio0:i386 - see below)
|
||||
wversion="7.1" #example: 7.1
|
||||
wid="debian" #example: debian, ubuntu
|
||||
wdist="bullseye" #example (for debian): bullseye, buster, jessie, wheezy, etc
|
||||
wtag="-1" #example: -1 (some wine .deb files have -1 tag on the end and some don't)
|
||||
|
||||
########################################################
|
||||
|
||||
# Clean up any old wine instances
|
||||
wineserver -k # stop any old wine installations from running
|
||||
rm -rf ~/.cache/wine # remove old wine-mono/wine-gecko install files
|
||||
rm -rf ~/.local/share/applications/wine # remove old program shortcuts
|
||||
|
||||
# Backup any old wine installations
|
||||
sudo mv ~/wine ~/wine-old
|
||||
sudo mv ~/.wine ~/.wine-old
|
||||
@@ -64,14 +84,12 @@ sudo mv /usr/local/bin/winecfg /usr/local/bin/winecfg-old
|
||||
sudo mv /usr/local/bin/wineserver /usr/local/bin/wineserver-old
|
||||
|
||||
# Download, extract wine, and install wine
|
||||
# (Replace the links/versions below with links/versions from the WineHQ site for the version of wine you wish to install. Note that we need the i386 version for Box86 even though we're installing it on our ARM processor.)
|
||||
# (Pick an i386 version of wine-devel, wine-staging, or wine-stable)
|
||||
cd ~/Downloads
|
||||
wget https://dl.winehq.org/wine-builds/debian/dists/buster/main/binary-i386/wine-devel-i386_5.21~buster_i386.deb # NOTE: Replace this link with the version you want
|
||||
wget https://dl.winehq.org/wine-builds/debian/dists/buster/main/binary-i386/wine-devel_5.21~buster_i386.deb # NOTE: Also replace this link with the version you want
|
||||
dpkg-deb -xv wine-devel-i386_5.21~buster_i386.deb wine-installer # NOTE: Make sure these dpkg command matches the filename of the deb package you just downloaded
|
||||
dpkg-deb -xv wine-devel_5.21~buster_i386.deb wine-installer
|
||||
mv ~/Downloads/wine-installer/opt/wine* ~/wine
|
||||
wget https://dl.winehq.org/wine-builds/${wid}/dists/${wdist}/main/binary-i386/wine-${wbranch}-i386_${wversion}~${wdist}${wtag}_i386.deb # download
|
||||
wget https://dl.winehq.org/wine-builds/${wid}/dists/${wdist}/main/binary-i386/wine-${wbranch}_${wversion}~${wdist}${wtag}_i386.deb # (required for wine_i386 if no wine64 / CONFLICTS WITH wine64 support files)
|
||||
dpkg-deb -x wine-${wbranch}-i386_${wversion}~${wdist}${wtag}_i386.deb wine-installer # extract
|
||||
dpkg-deb -x wine-${wbranch}_${wversion}~${wdist}${wtag}_i386.deb wine-installer
|
||||
mv wine-installer/opt/wine* ~/wine # install
|
||||
rm wine*.deb # clean up
|
||||
rm -rf wine-installer # clean up
|
||||
|
||||
@@ -83,7 +101,26 @@ sudo ln -s ~/wine/bin/winecfg /usr/local/bin/winecfg
|
||||
sudo ln -s ~/wine/bin/wineserver /usr/local/bin/wineserver
|
||||
sudo chmod +x /usr/local/bin/wine /usr/local/bin/wineboot /usr/local/bin/winecfg /usr/local/bin/wineserver
|
||||
|
||||
# These packages are needed for running wine-staging on RPi 4 (Credits: chills340)
|
||||
# These packages are needed for running wine on a 64-bit RPiOS via multiarch
|
||||
karch=$(uname -m)
|
||||
if [ "$karch" = "aarch64" ] || [ "$karch" = "aarch64-linux-gnu" ] || [ "$karch" = "arm64" ] || [ "$karch" = "aarch64_be" ]; then
|
||||
sudo dpkg --add-architecture armhf && sudo apt-get update # enable multi-arch
|
||||
sudo apt-get install -y libasound2:armhf libc6:armhf libglib2.0-0:armhf libgphoto2-6:armhf libgphoto2-port12:armhf \
|
||||
libgstreamer-plugins-base1.0-0:armhf libgstreamer1.0-0:armhf libldap-2.4-2:armhf libopenal1:armhf libpcap0.8:armhf \
|
||||
libpulse0:armhf libsane1:armhf libudev1:armhf libusb-1.0-0:armhf libvkd3d1:armhf libx11-6:armhf libxext6:armhf \
|
||||
libasound2-plugins:armhf ocl-icd-libopencl1:armhf libncurses6:armhf libncurses5:armhf libcap2-bin:armhf libcups2:armhf \
|
||||
libdbus-1-3:armhf libfontconfig1:armhf libfreetype6:armhf libglu1-mesa:armhf libglu1:armhf libgnutls30:armhf \
|
||||
libgssapi-krb5-2:armhf libkrb5-3:armhf libodbc1:armhf libosmesa6:armhf libsdl2-2.0-0:armhf libv4l-0:armhf \
|
||||
libxcomposite1:armhf libxcursor1:armhf libxfixes3:armhf libxi6:armhf libxinerama1:armhf libxrandr2:armhf \
|
||||
libxrender1:armhf libxxf86vm1:armhf libc6:armhf libcap2-bin:armhf # to run wine-i386 through box86:armhf on aarch64
|
||||
# This list found by downloading...
|
||||
# wget https://dl.winehq.org/wine-builds/debian/dists/bullseye/main/binary-i386/wine-devel-i386_7.1~bullseye-1_i386.deb
|
||||
# wget https://dl.winehq.org/wine-builds/debian/dists/bullseye/main/binary-i386/winehq-devel_7.1~bullseye-1_i386.deb
|
||||
# wget https://dl.winehq.org/wine-builds/debian/dists/bullseye/main/binary-i386/wine-devel_7.1~bullseye-1_i386.deb
|
||||
# then `dpkg-deb -I package.deb`. Read output, add `:armhf` to packages in dep list, then try installing them on Pi aarch64.
|
||||
fi
|
||||
|
||||
# These packages are needed for running wine-staging on RPiOS (Credits: chills340)
|
||||
sudo apt install libstb0 -y
|
||||
cd ~/Downloads
|
||||
wget -r -l1 -np -nd -A "libfaudio0_*~bpo10+1_i386.deb" http://ftp.us.debian.org/debian/pool/main/f/faudio/ # Download libfaudio i386 no matter its version number
|
||||
|
||||
Executable → Regular
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 58 KiB |
Executable → Regular
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 171 KiB After Width: | Height: | Size: 169 KiB |
Executable
+51
@@ -0,0 +1,51 @@
|
||||
#!/bin/bash
|
||||
|
||||
# create necessary directories
|
||||
mkdir -p ~/steam
|
||||
mkdir -p ~/steam/tmp
|
||||
cd ~/steam/tmp
|
||||
|
||||
# download latest deb and unpack
|
||||
wget https://cdn.cloudflare.steamstatic.com/client/installer/steam.deb
|
||||
ar x steam.deb
|
||||
tar xf data.tar.xz
|
||||
|
||||
# remove deb archives, not needed anymore
|
||||
rm ./*.tar.xz ./steam.deb
|
||||
|
||||
# move deb contents to steam folder
|
||||
mv ./usr/* ../
|
||||
cd ../ && rm -rf ./tmp/
|
||||
|
||||
# create run script
|
||||
echo '#!/bin/bash
|
||||
export STEAMOS=1
|
||||
export STEAM_RUNTIME=1
|
||||
export DBUS_FATAL_WARNINGS=0
|
||||
~/steam/bin/steam $@' > steam
|
||||
|
||||
# make script executable and move
|
||||
chmod +x steam
|
||||
sudo mv steam /usr/local/bin/
|
||||
|
||||
# detect if we're running on 64 bit Debian (maybe this can be moved in another script then mentioned in documentation for the people that don't use steam but don't want a headache)
|
||||
MACHINE_TYPE=`uname -m`
|
||||
if [ ${MACHINE_TYPE} == 'aarch64' ] && [ -f '/etc/debian_version' ]; then
|
||||
echo "Detected 64 bit ARM Debian. Installing 32 bit libraries"
|
||||
sudo dpkg --add-architecture armhf # enable installation of armhf libraries
|
||||
sudo apt update # update package lists with the newly added arch
|
||||
# install the libraries that Steam requires
|
||||
sudo apt install libc6:armhf libsdl2-2.0-0:armhf libsdl2-image-2.0-0:armhf libsdl2-mixer-2.0-0:armhf libsdl2-ttf-2.0-0:armhf libopenal1:armhf libpng16-16:armhf libfontconfig1:armhf libxcomposite1:armhf libbz2-1.0:armhf libxtst6:armhf libsm6:armhf libice6:armhf libgl1:armhf libxinerama1:armhf libxdamage1:armhf libibus-1.0-5
|
||||
# this one is not there all the time, so just try it...
|
||||
sudo apt install libncurses5:armhf
|
||||
|
||||
# install mesa for armhf if already installed
|
||||
if dpkg-query -W libgl1-mesa-dri 2>/dev/null; then
|
||||
echo "Detected mesa driver for 64 bit ARM. Installing complementary 32 bit one"
|
||||
sudo apt install libgl1-mesa-dri:armhf
|
||||
fi
|
||||
|
||||
echo "Don't forget to compile/install Box64!"
|
||||
fi
|
||||
|
||||
echo "Script complete."
|
||||
@@ -0,0 +1,36 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-a64-git
|
||||
pkgver=r4581.d698861
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
url="https://github.com/ptitSeb/box86"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-a64-git}-git" "${pkgname%-a64-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-a64-git}-git" "${pkgname%-a64-git}")
|
||||
source=('git+https://github.com/ptitSeb/box86')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "${srcdir}/${pkgname%-a64-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-a64-git}"
|
||||
[[ ! -d ./build ]] && mkdir build
|
||||
cmake -B build -DA64=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "${srcdir}/${pkgname%-a64-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "${srcdir}/${pkgname%-a64-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
+8
-16
@@ -1,7 +1,7 @@
|
||||
# Maintainer: Jai-JAP <parjailu@gmail.com>, SpacingBat3 <[email protected]>
|
||||
# Maintainer: Jai-JAP <jai.jap.318@gmail.com>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-arm-git
|
||||
pkgver=3494.bedacef
|
||||
pkgver=r4581.d698861
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
@@ -15,30 +15,22 @@ source=('git+https://github.com/ptitSeb/box86')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-arm-git}"
|
||||
cd "${srcdir}/${pkgname%-arm-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-arm-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DARM_DYNAREC=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
fi
|
||||
[[ ! -d ./build ]] && mkdir build
|
||||
cmake -B build -DARM_DYNAREC=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-arm-git}/build"
|
||||
cd "${srcdir}/${pkgname%-arm-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-arm-git}/build"
|
||||
cd "${srcdir}/${pkgname%-arm-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-arm64-git
|
||||
pkgver=r4581.d698861
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('aarch64')
|
||||
url="https://github.com/ptitSeb/box86"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-arm64-git}-git" "${pkgname%-arm64-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-arm64-git}-git" "${pkgname%-arm64-git}")
|
||||
source=('git+https://github.com/ptitSeb/box86')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "${srcdir}/${pkgname%-arm64-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-arm64-git}"
|
||||
[[ ! -d ./build ]] && mkdir build
|
||||
cmake -B build -DARM64=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "${srcdir}/${pkgname%-arm64-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "${srcdir}/${pkgname%-arm64-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
# Maintainer: Jai-JAP <parjailu@gmail.com>, SpacingBat3 <[email protected]>
|
||||
# Maintainer: Jai-JAP <jai.jap.318@gmail.com>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-gameshell-git
|
||||
pkgver=3494.bedacef
|
||||
pkgver=r4581.d698861
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
@@ -15,30 +15,22 @@ source=('git+https://github.com/ptitSeb/box86')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-gameshell-git}"
|
||||
cd "${srcdir}/${pkgname%-gameshell-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-gameshell-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DGAMESHELL=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
fi
|
||||
[[ ! -d ./build ]] && mkdir build
|
||||
cmake -B build -DGAMESHELL=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-gameshell-git}/build"
|
||||
cd "${srcdir}/${pkgname%-gameshell-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-gameshell-git}/build"
|
||||
cd "${srcdir}/${pkgname%-gameshell-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-goaclone-git
|
||||
pkgver=r4581.d698861
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
url="https://github.com/ptitSeb/box86"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-goaclone-git}-git" "${pkgname%-goaclone-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-goaclone-git}-git" "${pkgname%-goaclone-git}")
|
||||
source=('git+https://github.com/ptitSeb/box86')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "${srcdir}/${pkgname%-goaclone-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-goaclone-git}"
|
||||
[[ ! -d ./build ]] && mkdir build
|
||||
cmake -B build -DGOA_CLONE=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "${srcdir}/${pkgname%-goaclone-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "${srcdir}/${pkgname%-goaclone-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-lx2610a-git
|
||||
pkgver=r4581.d698861
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
url="https://github.com/ptitSeb/box86"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-lx2610a-git}-git" "${pkgname%-lx2610a-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-lx2610a-git}-git" "${pkgname%-lx2610a-git}")
|
||||
source=('git+https://github.com/ptitSeb/box86')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "${srcdir}/${pkgname%-lx2610a-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-lx2610a-git}"
|
||||
[[ ! -d ./build ]] && mkdir build
|
||||
cmake -B build -DLX2610A=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "${srcdir}/${pkgname%-lx2610a-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "${srcdir}/${pkgname%-lx2610a-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
# Maintainer: Jai-JAP <parjailu@gmail.com>, SpacingBat3 <[email protected]>
|
||||
# Maintainer: Jai-JAP <jai.jap.318@gmail.com>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-odroid-git
|
||||
pkgver=3494.bedacef
|
||||
pkgver=r4581.d698861
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
@@ -15,30 +15,22 @@ source=('git+https://github.com/ptitSeb/box86')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-odroid-git}"
|
||||
cd "${srcdir}/${pkgname%-odroid-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-odroid-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DODROID=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
fi
|
||||
[[ ! -d ./build ]] && mkdir build
|
||||
cmake -B build -DODROID=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-odroid-git}/build"
|
||||
cd "${srcdir}/${pkgname%-odroid-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-odroid-git}/build"
|
||||
cd "${srcdir}/${pkgname%-odroid-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-odroidn2-git
|
||||
pkgver=r4581.d698861
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
url="https://github.com/ptitSeb/box86"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-odroidn2-git}-git" "${pkgname%-odroidn2-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-odroidn2-git}-git" "${pkgname%-odroidn2-git}")
|
||||
source=('git+https://github.com/ptitSeb/box86')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "${srcdir}/${pkgname%-odroidn2-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-odroidn2-git}"
|
||||
[[ ! -d ./build ]] && mkdir build
|
||||
cmake -B build -DODROID=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "${srcdir}/${pkgname%-odroidn2-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "${srcdir}/${pkgname%-odroidn2-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
# Maintainer: Jai-JAP <parjailu@gmail.com>, SpacingBat3 <[email protected]>
|
||||
# Maintainer: Jai-JAP <jai.jap.318@gmail.com>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-pandora-git
|
||||
pkgver=3494.bedacef
|
||||
pkgver=r4581.d698861
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
@@ -15,30 +15,22 @@ source=('git+https://github.com/ptitSeb/box86')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-pandora-git}"
|
||||
cd "${srcdir}/${pkgname%-pandora-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-pandora-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DPANDORA=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
fi
|
||||
[[ ! -d ./build ]] && mkdir build
|
||||
cmake -B build -DPANDORA=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-pandora-git}/build"
|
||||
cd "${srcdir}/${pkgname%-pandora-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-git}/build"
|
||||
cd "${srcdir}/${pkgname%-pandora-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-phytium-git
|
||||
pkgver=r4581.d698861
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
url="https://github.com/ptitSeb/box86"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-phytium-git}"-git "${pkgname%-phytium-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-phytium-git}"-git "${pkgname%-phytium-git}")
|
||||
source=('git+https://github.com/ptitSeb/box86')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "${srcdir}/${pkgname%-phytium-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-phytium-git}"
|
||||
[[ ! -d ./build ]] && mkdir build
|
||||
cmake -B build -DPHYTIUM=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "${srcdir}/${pkgname%-phytium-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "${srcdir}/${pkgname%-phytium-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
+8
-16
@@ -1,7 +1,7 @@
|
||||
# Maintainer: Jai-JAP <parjailu@gmail.com>, SpacingBat3 <[email protected]>
|
||||
# Maintainer: Jai-JAP <jai.jap.318@gmail.com>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-pyra-git
|
||||
pkgver=3494.bedacef
|
||||
pkgver=r4581.d698861
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
@@ -15,30 +15,22 @@ source=('git+https://github.com/ptitSeb/box86')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-pyra-git}"
|
||||
cd "${srcdir}/${pkgname%-pyra-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-pyra-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DPYRA=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
fi
|
||||
[[ ! -d ./build ]] && mkdir build
|
||||
cmake -B build -DPYRA=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-pyra-git}/build"
|
||||
cd "${srcdir}/${pkgname%-pyra-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-pyra-git}/build"
|
||||
cd "${srcdir}/${pkgname%-pyra-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
# Maintainer: Jai-JAP <parjailu@gmail.com>, SpacingBat3 <[email protected]>
|
||||
# Maintainer: Jai-JAP <jai.jap.318@gmail.com>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-rpi-git
|
||||
pkgver=3494.bedacef
|
||||
pkgver=r4581.d698861
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
@@ -16,7 +16,7 @@ md5sums=('SKIP')
|
||||
_pimodel=`tr -d '\0' < /sys/firmware/devicetree/base/model`
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-rpi-git}"
|
||||
cd "${srcdir}/${pkgname%-rpi-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
@@ -32,28 +32,20 @@ prepare() {
|
||||
else
|
||||
# This RPI is not supported or this device is not a pi.
|
||||
# We should cancel then the build.
|
||||
echo -e "\033[01m\033[01;31m==> ERROR:\033[00;01m Your device is not supported! This script is for RPi model 4/3/2 (1/0 isn't supported yet).\033[00m"
|
||||
echo -e "\033[01m\033[01;31m==> ERROR:\033[00;01m Your device is not supported! This script is for RPi model 4/3/2 (1/0 isn't supported).\033[00m"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "\033[01m\033[01;34m==> INFO:\033[00;01m Your detected Pi verion number is: \033[01;31m${_piversion}\033[01m.\033[00m"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DRPI${_piversion}=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
fi
|
||||
[[ ! -d ./build ]] && mkdir build
|
||||
cmake -B build -DRPI${_piversion}=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-rpi-git}/build"
|
||||
cd "${srcdir}/${pkgname%-rpi-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-rpi-git}/build"
|
||||
cd "${srcdir}/${pkgname%-rpi-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-rk3399-git
|
||||
pkgver=3494.bedacef
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
url="https://github.com/ptitSeb/box86"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-rk3399-git}-git" "${pkgname%-rk3399-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-rk3399-git}-git" "${pkgname%-rk3399-git}")
|
||||
source=('git+https://github.com/ptitSeb/box86')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-rk3399-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-rk3399-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DRK3399=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
fi
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-rk3399-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-arm-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-rk3xxx-git
|
||||
pkgver=r4581.d698861
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
url="https://github.com/ptitSeb/box86"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-rk3xxx-git}-git" "${pkgname%-rk3xxx-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-rk3xxx-git}-git" "${pkgname%-rk3xxx-git}")
|
||||
source=('git+https://github.com/ptitSeb/box86')
|
||||
md5sums=('SKIP')
|
||||
_rkmodel=`tr -d '\0' < /proc/device-tree/compatible`
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-rk3xxx-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-rk3xxx-git}"
|
||||
# Check for RockChip version number
|
||||
if [[ ${_rkmodel} =~ "rk3288" ]]; then
|
||||
_rksuffix=3288
|
||||
elif [[ ${_rkmodel} =~ "rk3399" ]]; then
|
||||
_rksuffix=3399
|
||||
elif [[ ${_rkmodel} =~ "rk3588" ]]; then
|
||||
_rksuffix=3588
|
||||
else
|
||||
# This RKxxxx is not supported or this device is not RockChip based.
|
||||
# We should cancel then the build.
|
||||
echo -e "\033[01m\033[01;31m==> ERROR:\033[00;01m Your device is not supported! This script is for RockChip model 3399/3588.\033[00m"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "\033[01m\033[01;34m==> INFO:\033[00;01m Your detected RockChip verion number is: \033[01;31m${_rksuffix}\033[01m.\033[00m"
|
||||
[[ ! -d ./build ]] && mkdir build
|
||||
cmake -B build -DRK${_rksuffix}=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "${srcdir}/${pkgname%-rk3xxx-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "${srcdir}/${pkgname%-rk3xxx-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-sd845-git
|
||||
pkgver=r4581.d698861
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
url="https://github.com/ptitSeb/box86"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-sd845-git}-git" "${pkgname%-sd845-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-sd845-git}-git" "${pkgname%-sd845-git}")
|
||||
source=('git+https://github.com/ptitSeb/box86')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "${srcdir}/${pkgname%-sd845-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-sd845-git}"
|
||||
[[ ! -d ./build ]] && mkdir build
|
||||
cmake -B build -DSD845=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "${srcdir}/${pkgname%-sd845-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "${srcdir}/${pkgname%-sd845-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-tegra-git
|
||||
pkgver=r4581.d698861
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
url="https://github.com/ptitSeb/box86"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-tegra-git}"-git "${pkgname%-tegra-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-tegra-git}"-git "${pkgname%-tegra-git}")
|
||||
source=('git+https://github.com/ptitSeb/box86')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "${srcdir}/${pkgname%-tegra-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-tegra-git}"
|
||||
[[ ! -d ./build ]] && mkdir build
|
||||
cmake -B build -DTEGRAX1ARM32=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "${srcdir}/${pkgname%-tegra-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "${srcdir}/${pkgname%-tegra-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
}
|
||||
+8
-16
@@ -1,7 +1,7 @@
|
||||
# Maintainer: Jai-JAP <parjailu@gmail.com>, SpacingBat3 <[email protected]>
|
||||
# Maintainer: Jai-JAP <jai.jap.318@gmail.com>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-x86-git
|
||||
pkgver=3494.bedacef
|
||||
pkgver=r4581.d698861
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('i386')
|
||||
@@ -14,30 +14,22 @@ source=('git+https://github.com/ptitSeb/box86')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-x86-git}"
|
||||
cd "${srcdir}/${pkgname%-x86-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-x86-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DLD80BITS=1 -DNOALIGN=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
fi
|
||||
[[ ! -d ./build ]] && mkdir build
|
||||
cmake -B build -DLD80BITS=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX=/usr
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-x86-git}/build"
|
||||
cd "${srcdir}/${pkgname%-x86-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-x86-git}/build"
|
||||
cd "${srcdir}/${pkgname%-x86-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -12,7 +12,7 @@ This will copy the PKGBUILD for your platform (where you type your platform name
|
||||
In the future, I might try to do an unified PKGBUILD for all platforms that will recognize your platform automatically.
|
||||
|
||||
### 2. What platforms are currently supported.
|
||||
All specified in [COMPILE.md](../COMPILE.md).
|
||||
Most specified in [COMPILE.md](../docs/COMPILE.md). Except PowerPC based.
|
||||
|
||||
### 3. Any advantages with that sollution?
|
||||
This might give you some advantages like those:
|
||||
|
||||
@@ -1,2 +1,6 @@
|
||||
#!/bin/sh
|
||||
systemctl restart systemd-binfmt
|
||||
# Restart the systemd-binfmt service to load new binary format rules.
|
||||
# This ensures the system is immediately ready to run programs with Box86.
|
||||
if [ -d '/run/systemd/system' ]; then
|
||||
systemctl restart systemd-binfmt || :
|
||||
fi
|
||||
+279
-287
@@ -72,7 +72,7 @@ def main(root, ver, __debug_forceAllDebugging=False):
|
||||
|
||||
# Get all actual instructions
|
||||
# Ignore white lines and lines beginning with either !, ; or #
|
||||
insts = list(filter(lambda l: not re.match("^\s*$", l) and not re.match("^([!;#])", l), insts.split('\n')))
|
||||
insts = list(filter(lambda l: not re.match("^\\s*$", l) and not re.match("^([!;#])", l), insts.split('\n')))
|
||||
|
||||
try:
|
||||
# Do not open with `with` to be able to open it in writing mode
|
||||
@@ -106,7 +106,7 @@ def main(root, ver, __debug_forceAllDebugging=False):
|
||||
alreadyChanged = 0
|
||||
csp = 0
|
||||
while csp < curSplt:
|
||||
if spltln[csp] == '\x00':
|
||||
if spltln[csp] == '\x01':
|
||||
alreadyChanged = 1
|
||||
curSplt = curSplt + 1
|
||||
else:
|
||||
@@ -119,7 +119,7 @@ def main(root, ver, __debug_forceAllDebugging=False):
|
||||
line = line + spltln[csp] + ">"
|
||||
alreadyChanged = 1
|
||||
csp = csp + 1
|
||||
if spltln[csp] == '\x00':
|
||||
if spltln[csp] == '\x01':
|
||||
alreadyChanged = 1
|
||||
curSplt = curSplt + 1
|
||||
csp = csp + 1
|
||||
@@ -134,7 +134,7 @@ def main(root, ver, __debug_forceAllDebugging=False):
|
||||
alreadyChanged = 1
|
||||
csp = csp + 1
|
||||
while csp < len(spltln):
|
||||
if spltln[csp] == '\x00':
|
||||
if spltln[csp] == '\x01':
|
||||
alreadyChanged = 1
|
||||
curSplt = curSplt + 1
|
||||
else:
|
||||
@@ -605,7 +605,7 @@ def main(root, ver, __debug_forceAllDebugging=False):
|
||||
instText = [itp for itp2 in instText for itp in itp2]
|
||||
|
||||
# Make the failures nicer
|
||||
spltln = spltln[:curSplt] + ["\x00"] + instText
|
||||
spltln = spltln[:curSplt] + ["\x01"] + instText
|
||||
|
||||
printf_args = ""
|
||||
for idx, text in enumerate(instText):
|
||||
@@ -729,7 +729,7 @@ def main(root, ver, __debug_forceAllDebugging=False):
|
||||
|
||||
variables["u"] = -1 # Unsigned shift
|
||||
|
||||
variables["w"] = -1 # wback (used in adressing)
|
||||
variables["w"] = -1 # wback (used in addressing)
|
||||
|
||||
variables["shift"] = False # Shift already detected?
|
||||
|
||||
@@ -858,7 +858,7 @@ def main(root, ver, __debug_forceAllDebugging=False):
|
||||
instText = [itp for itp2 in instText for itp in itp2]
|
||||
|
||||
# Make the failures nicer
|
||||
spltln = spltln[:curSplt] + ["\x00"] + instText
|
||||
spltln = spltln[:curSplt] + ["\x01"] + instText
|
||||
|
||||
printf_args = ""
|
||||
for idx, text in enumerate(instText):
|
||||
@@ -1156,7 +1156,7 @@ def main(root, ver, __debug_forceAllDebugging=False):
|
||||
instText = [itp for itp2 in instText for itp in itp2]
|
||||
|
||||
# Make the failures nicer
|
||||
spltln = spltln[:curSplt] + ["\x00"] + instText
|
||||
spltln = spltln[:curSplt] + ["\x01"] + instText
|
||||
|
||||
printf_args = ""
|
||||
for idx, text in enumerate(instText):
|
||||
@@ -1456,7 +1456,7 @@ def main(root, ver, __debug_forceAllDebugging=False):
|
||||
instText = [itp for itp2 in instText for itp in itp2]
|
||||
|
||||
# Make the failures nicer
|
||||
spltln = spltln[:curSplt] + ["\x00"] + instText
|
||||
spltln = spltln[:curSplt] + ["\x01"] + instText
|
||||
|
||||
# inside '{, '...'}'?
|
||||
hasOpened = False
|
||||
@@ -1675,308 +1675,300 @@ def main(root, ver, __debug_forceAllDebugging=False):
|
||||
|
||||
# Now the files rebuilding part
|
||||
# File header and guard
|
||||
files_header = {
|
||||
"arm_printer.c": """
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
header = """
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "arm_printer.h"
|
||||
|
||||
// conditions
|
||||
#define cEQ (0b0000<<28)
|
||||
#define cNE (0b0001<<28)
|
||||
#define cCS (0b0010<<28)
|
||||
#define cCC (0b0011<<28)
|
||||
#define cMI (0b0100<<28)
|
||||
#define cPL (0b0101<<28)
|
||||
#define cVS (0b0110<<28)
|
||||
#define cVC (0b0111<<28)
|
||||
#define cHI (0b1000<<28)
|
||||
#define cLS (0b1001<<28)
|
||||
#define cGE (0b1010<<28)
|
||||
#define cLT (0b1011<<28)
|
||||
#define cGT (0b1100<<28)
|
||||
#define cLE (0b1101<<28)
|
||||
#define c__ (0b1110<<28) // means all
|
||||
|
||||
static const char* conds[16] = {
|
||||
"EQ", "NE", "CS", "CC",
|
||||
"MI", "PL", "VS", "VC",
|
||||
"HI", "LS", "GE", "LT",
|
||||
"GT", "LE", "", "##"
|
||||
};
|
||||
|
||||
static const char* regname[16] = {
|
||||
"r0", "r1", "r2", "r3", "r4",
|
||||
"r5", "r6", "r7", "r8", "r9",
|
||||
"r10", "r11", "r12", "SP", "LR", "PC"
|
||||
};
|
||||
|
||||
// Single precision are V_:_
|
||||
// Double and quad precision are _:V_
|
||||
// So we always use _:V_ and invert the corresponding single-precision (cleaner? code)
|
||||
static const char* vecname[96] = {
|
||||
"S0", "S2", "S4", "S6", "S8", "S10", "S12", "S14",
|
||||
"S16", "S18", "S20", "S22", "S24", "S26", "S28", "S30",
|
||||
"S1", "S3", "S5", "S7", "S9", "S11", "S13", "S15",
|
||||
"S17", "S19", "S21", "S23", "S25", "S27", "S29", "S31",
|
||||
"D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
|
||||
"D8", "D9", "D10", "D11", "D12", "D13", "D14", "D15",
|
||||
"D16", "D17", "D18", "D19", "D20", "D21", "D22", "D23",
|
||||
"D24", "D25", "D26", "D27", "D28", "D29", "D30", "D31",
|
||||
"Q0", "!!!", "Q1", "!!!", "Q2", "!!!", "Q3", "!!!",
|
||||
"Q4", "!!!", "Q5", "!!!", "Q6", "!!!", "Q7", "!!!",
|
||||
"Q8", "!!!", "Q9", "!!!", "Q10", "!!!", "Q11", "!!!",
|
||||
"Q12", "!!!", "Q13", "!!!", "Q14", "!!!", "Q15", "!!!"
|
||||
};
|
||||
|
||||
static const char* dts[16] = {
|
||||
"S8", "S16", "S32", "S64",
|
||||
"U8", "U16", "U32", "U64",
|
||||
"I8", "I16", "I32", "I64",
|
||||
"F8", "F16", "F32", "F64"
|
||||
};
|
||||
|
||||
static const char* shift_type[4] = {
|
||||
"lsl ", "lsr ", "asr ", "ror "
|
||||
};
|
||||
|
||||
const char* print_shift(int shift, int comma) {
|
||||
static __thread char ret[20];
|
||||
ret[0] = '\\0';
|
||||
|
||||
#include "arm_printer.h"
|
||||
|
||||
// conditions
|
||||
#define cEQ (0b0000<<28)
|
||||
#define cNE (0b0001<<28)
|
||||
#define cCS (0b0010<<28)
|
||||
#define cCC (0b0011<<28)
|
||||
#define cMI (0b0100<<28)
|
||||
#define cPL (0b0101<<28)
|
||||
#define cVS (0b0110<<28)
|
||||
#define cVC (0b0111<<28)
|
||||
#define cHI (0b1000<<28)
|
||||
#define cLS (0b1001<<28)
|
||||
#define cGE (0b1010<<28)
|
||||
#define cLT (0b1011<<28)
|
||||
#define cGT (0b1100<<28)
|
||||
#define cLE (0b1101<<28)
|
||||
#define c__ (0b1110<<28) // means all
|
||||
|
||||
static const char* conds[16] = {
|
||||
"EQ", "NE", "CS", "CC",
|
||||
"MI", "PL", "VS", "VC",
|
||||
"HI", "LS", "GE", "LT",
|
||||
"GT", "LE", "", "##"
|
||||
};
|
||||
|
||||
static const char* regname[16] = {
|
||||
"r0", "r1", "r2", "r3", "r4",
|
||||
"r5", "r6", "r7", "r8", "r9",
|
||||
"r10", "r11", "r12", "SP", "LR", "PC"
|
||||
};
|
||||
|
||||
// Single precision are V_:_
|
||||
// Double and quad precision are _:V_
|
||||
// So we always use _:V_ and invert the corresponding single-precision (cleaner? code)
|
||||
static const char* vecname[96] = {
|
||||
"S0", "S2", "S4", "S6", "S8", "S10", "S12", "S14",
|
||||
"S16", "S18", "S20", "S22", "S24", "S26", "S28", "S30",
|
||||
"S1", "S3", "S5", "S7", "S9", "S11", "S13", "S15",
|
||||
"S17", "S19", "S21", "S23", "S25", "S27", "S29", "S31",
|
||||
"D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
|
||||
"D8", "D9", "D10", "D11", "D12", "D13", "D14", "D15",
|
||||
"D16", "D17", "D18", "D19", "D20", "D21", "D22", "D23",
|
||||
"D24", "D25", "D26", "D27", "D28", "D29", "D30", "D31",
|
||||
"Q0", "!!!", "Q1", "!!!", "Q2", "!!!", "Q3", "!!!",
|
||||
"Q4", "!!!", "Q5", "!!!", "Q6", "!!!", "Q7", "!!!",
|
||||
"Q8", "!!!", "Q9", "!!!", "Q10", "!!!", "Q11", "!!!",
|
||||
"Q12", "!!!", "Q13", "!!!", "Q14", "!!!", "Q15", "!!!"
|
||||
};
|
||||
|
||||
static const char* dts[16] = {
|
||||
"S8", "S16", "S32", "S64",
|
||||
"U8", "U16", "U32", "U64",
|
||||
"I8", "I16", "I32", "I64",
|
||||
"F8", "F16", "F32", "F64"
|
||||
};
|
||||
|
||||
static const char* shift_type[4] = {
|
||||
"lsl ", "lsr ", "asr ", "ror "
|
||||
};
|
||||
|
||||
const char* print_shift(int shift, int comma) {
|
||||
static __thread char ret[20];
|
||||
ret[0] = '\\0';
|
||||
|
||||
int sh_op = (shift >> 1) & 3;
|
||||
if(shift & 1) {
|
||||
int rs = shift >> 4;
|
||||
sprintf(ret, "%s%s%s", (comma ? ", " : ""), shift_type[sh_op], regname[rs]);
|
||||
} else {
|
||||
uint8_t amount = shift >> 3;
|
||||
if (!amount) {
|
||||
switch (sh_op) {
|
||||
case 0b00:
|
||||
break;
|
||||
case 0b01:
|
||||
case 0b10:
|
||||
sprintf(ret, "%s%s#32", (comma ? ", " : ""), shift_type[sh_op]);
|
||||
break;
|
||||
case 0b11:
|
||||
sprintf(ret, "%srrx", (comma ? ", " : ""));
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
sprintf(ret, "%s%s#%u", (comma ? ", " : ""), shift_type[sh_op], amount);
|
||||
int sh_op = (shift >> 1) & 3;
|
||||
if(shift & 1) {
|
||||
int rs = shift >> 4;
|
||||
sprintf(ret, "%s%s%s", (comma ? ", " : ""), shift_type[sh_op], regname[rs]);
|
||||
} else {
|
||||
uint8_t amount = shift >> 3;
|
||||
if (!amount) {
|
||||
switch (sh_op) {
|
||||
case 0b00:
|
||||
break;
|
||||
case 0b01:
|
||||
case 0b10:
|
||||
sprintf(ret, "%s%s#32", (comma ? ", " : ""), shift_type[sh_op]);
|
||||
break;
|
||||
case 0b11:
|
||||
sprintf(ret, "%srrx", (comma ? ", " : ""));
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
sprintf(ret, "%s%s#%u", (comma ? ", " : ""), shift_type[sh_op], amount);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define print_modified_imm_ARM(imm12) (((imm12 & 0xFF) >> (2*(imm12 >> 8))) | ((imm12 & 0xFF) << (32 - 2*(imm12 >> 8))))
|
||||
|
||||
const char* print_register_list(int list, int size) {
|
||||
int last = -2;
|
||||
int cnt = 0;
|
||||
static __thread char ret[68];
|
||||
|
||||
#define print_modified_imm_ARM(imm12) (((imm12 & 0xFF) >> (2*(imm12 >> 8))) | ((imm12 & 0xFF) << (32 - 2*(imm12 >> 8))))
|
||||
ret[0] = '{';
|
||||
ret[1] = '\\0';
|
||||
for (int i = 0; i < size; ++i) {
|
||||
if (list & (1 << i)) {
|
||||
if (last >= 0) {
|
||||
++cnt;
|
||||
} else {
|
||||
if (last == -1)
|
||||
strcat(ret, ", ");
|
||||
strcat(ret, regname[i]);
|
||||
last = i;
|
||||
}
|
||||
} else {
|
||||
if (cnt) {
|
||||
strcat(ret, "-");
|
||||
strcat(ret, regname[i - 1]);
|
||||
}
|
||||
if (last != -2) last = -1;
|
||||
cnt = 0;
|
||||
}
|
||||
}
|
||||
if (cnt) {
|
||||
strcat(ret, "-");
|
||||
strcat(ret, regname[size - 1]);
|
||||
}
|
||||
strcat(ret, "}");
|
||||
|
||||
const char* print_register_list(int list, int size) {
|
||||
int last = -2;
|
||||
int cnt = 0;
|
||||
static __thread char ret[68];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char* print_register_list_fpu(uint8_t start, uint8_t size, uint8_t double_prec) {
|
||||
static __thread char ret[68];
|
||||
|
||||
// Assume VFPSmallRegisterBank(), so no D16 and no S32 (and above)
|
||||
if (start + (double_prec + 1) * size > 32) {
|
||||
return "!!!";
|
||||
}
|
||||
if (size == 0) {
|
||||
return "!!!";
|
||||
}
|
||||
if (double_prec && (size % 2 == 1)) {
|
||||
strcpy(ret, "!! {");
|
||||
} else {
|
||||
ret[0] = '{';
|
||||
ret[1] = '\\0';
|
||||
for (int i = 0; i < size; ++i) {
|
||||
if (list & (1 << i)) {
|
||||
if (last >= 0) {
|
||||
++cnt;
|
||||
} else {
|
||||
if (last == -1)
|
||||
strcat(ret, ", ");
|
||||
strcat(ret, regname[i]);
|
||||
last = i;
|
||||
}
|
||||
} else {
|
||||
if (cnt) {
|
||||
strcat(ret, "-");
|
||||
strcat(ret, regname[i - 1]);
|
||||
}
|
||||
if (last != -2) last = -1;
|
||||
cnt = 0;
|
||||
}
|
||||
}
|
||||
if (cnt) {
|
||||
strcat(ret, "-");
|
||||
strcat(ret, regname[size - 1]);
|
||||
}
|
||||
strcat(ret, "}");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char* print_register_list_fpu(uint8_t start, uint8_t size, uint8_t double_prec) {
|
||||
static __thread char ret[68];
|
||||
|
||||
// Assume VFPSmallRegisterBank(), so no D16 and no S32 (and above)
|
||||
if (start + (double_prec + 1) * size > 32) {
|
||||
return "!!!";
|
||||
}
|
||||
if (size == 0) {
|
||||
return "!!!";
|
||||
}
|
||||
if (double_prec && (size % 2 == 1)) {
|
||||
strcpy(ret, "!! {");
|
||||
} else {
|
||||
ret[0] = '{';
|
||||
ret[1] = '\\0';
|
||||
}
|
||||
|
||||
char regChr;
|
||||
if (double_prec) {
|
||||
regChr = 'D';
|
||||
size /= 2;
|
||||
} else {
|
||||
regChr = 'S';
|
||||
start = (start >> 4) + ((start & 0xF) << 1);
|
||||
}
|
||||
|
||||
char tmp[6];
|
||||
for (int cur = start; cur < start + size - 1; ++cur) {
|
||||
sprintf(tmp, "%c%d, ", regChr, cur);
|
||||
strcat(ret, tmp);
|
||||
}
|
||||
sprintf(tmp, "%c%d}", regChr, start + size - 1);
|
||||
char regChr;
|
||||
if (double_prec) {
|
||||
regChr = 'D';
|
||||
size /= 2;
|
||||
} else {
|
||||
regChr = 'S';
|
||||
start = (start >> 4) + ((start & 0xF) << 1);
|
||||
}
|
||||
|
||||
char tmp[7];
|
||||
for (int cur = start; cur < start + size - 1; ++cur) {
|
||||
sprintf(tmp, "%c%d, ", regChr, cur);
|
||||
strcat(ret, tmp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
sprintf(tmp, "%c%d}", regChr, start + size - 1);
|
||||
strcat(ret, tmp);
|
||||
|
||||
static const char* _print_modified_imm_I64_bytes[2] = {"00", "FF"};
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const char* _print_modified_imm_I64_bytes[2] = {"00", "FF"};
|
||||
|
||||
const char* print_modified_imm_NEON(int op_cmode, int imm) {
|
||||
static __thread char ret[34] = "???\\0-"; // [dt: 4][imm: 30]
|
||||
|
||||
const char* print_modified_imm_NEON(int op_cmode, int imm) {
|
||||
static __thread char ret[34] = "???\\0-"; // [dt: 4][imm: 30]
|
||||
|
||||
strcpy(&ret[4], "UNPREDICTABLE");
|
||||
|
||||
switch (op_cmode) {
|
||||
case 0b00000: // VMOV.I32
|
||||
case 0b00001: // VORR.I32
|
||||
case 0b10000: // VMVN.I32
|
||||
case 0b10001: // VBIC.I32
|
||||
strcpy(&ret[4], "UNPREDICTABLE");
|
||||
|
||||
switch (op_cmode) {
|
||||
case 0b00000: // VMOV.I32
|
||||
case 0b00001: // VORR.I32
|
||||
case 0b10000: // VMVN.I32
|
||||
case 0b10001: // VBIC.I32
|
||||
strcpy(ret, "I32");
|
||||
sprintf(&ret[4], "0x%02X", imm);
|
||||
break;
|
||||
case 0b00010: // VMOV.I32
|
||||
case 0b00011: // VORR.I32
|
||||
case 0b10010: // VMVN.I32
|
||||
case 0b10011: // VBIC.I32
|
||||
if (imm) {
|
||||
strcpy(ret, "I32");
|
||||
sprintf(&ret[4], "0x%02X", imm);
|
||||
break;
|
||||
case 0b00010: // VMOV.I32
|
||||
case 0b00011: // VORR.I32
|
||||
case 0b10010: // VMVN.I32
|
||||
case 0b10011: // VBIC.I32
|
||||
if (imm) {
|
||||
strcpy(ret, "I32");
|
||||
sprintf(&ret[4], "0x%02X00", imm);
|
||||
}
|
||||
break;
|
||||
case 0b00100: // VMOV.I32
|
||||
case 0b00101: // VORR.I32
|
||||
case 0b10100: // VMVN.I32
|
||||
case 0b10101: // VBIC.I32
|
||||
if (imm) {
|
||||
strcpy(ret, "I32");
|
||||
sprintf(&ret[4], "0x%02X0000", imm);
|
||||
}
|
||||
break;
|
||||
case 0b00110: // VMOV.I32
|
||||
case 0b00111: // VORR.I32
|
||||
case 0b10110: // VMVN.I32
|
||||
case 0b10111: // VBIC.I32
|
||||
if (imm) {
|
||||
strcpy(ret, "I32");
|
||||
sprintf(&ret[4], "0x%02X000000", imm);
|
||||
}
|
||||
break;
|
||||
case 0b01000: // VMOV.I16
|
||||
case 0b01001: // VORR.I16
|
||||
case 0b11000: // VMVN.I16
|
||||
case 0b11001: // VBIC.I16
|
||||
strcpy(ret, "I16");
|
||||
sprintf(&ret[4], "0x%02X", imm);
|
||||
break;
|
||||
case 0b01010: // VMOV.I16
|
||||
case 0b01011: // VORR.I16
|
||||
case 0b11010: // VMVN.I16
|
||||
case 0b11011: // VBIC.I16
|
||||
if (imm) {
|
||||
strcpy(ret, "I16");
|
||||
sprintf(&ret[4], "0x%02X00", imm);
|
||||
}
|
||||
break;
|
||||
case 0b01100: // VMOV.I32
|
||||
case 0b11100: // VMVN.I32
|
||||
if (imm) {
|
||||
strcpy(ret, "I32");
|
||||
sprintf(&ret[4], "0x%02XFF", imm);
|
||||
}
|
||||
break;
|
||||
case 0b01101: // VMOV.I32
|
||||
case 0b11101: // VMVN.I32
|
||||
if (imm) {
|
||||
strcpy(ret, "I32");
|
||||
sprintf(&ret[4], "0x%02XFFFF", imm);
|
||||
}
|
||||
break;
|
||||
case 0b01110: // VMOV.I8
|
||||
strcpy(ret, "I8");
|
||||
sprintf(&ret[4], "0x%02X", imm);
|
||||
break;
|
||||
case 0b01111: // VMOV.F32
|
||||
strcpy(ret, "F32");
|
||||
sprintf(&ret[4], "%e", (imm & 0x80 ? -1 : 1) * (1 << (((imm >> 4) & 0x7) ^ 0b100)) * (float) (16 + (imm & 0xF)) / 128.);
|
||||
break;
|
||||
case 0b11110: // VMOV.I64
|
||||
{
|
||||
strcpy(ret, "I64");
|
||||
sprintf(&ret[4], "#0x%s%s%s%s%s%s%s%s",
|
||||
_print_modified_imm_I64_bytes[(imm >> 7) & 1], _print_modified_imm_I64_bytes[(imm >> 6) & 1],
|
||||
_print_modified_imm_I64_bytes[(imm >> 5) & 1], _print_modified_imm_I64_bytes[(imm >> 4) & 1],
|
||||
_print_modified_imm_I64_bytes[(imm >> 3) & 1], _print_modified_imm_I64_bytes[(imm >> 2) & 1],
|
||||
_print_modified_imm_I64_bytes[(imm >> 1) & 1], _print_modified_imm_I64_bytes[(imm >> 0) & 1]);
|
||||
}
|
||||
break;
|
||||
case 0b11111: // V???.-
|
||||
default:
|
||||
strcpy(ret, "-");
|
||||
strcpy(&ret[4], "UNDEFINED");
|
||||
break;
|
||||
sprintf(&ret[4], "0x%02X00", imm);
|
||||
}
|
||||
|
||||
return ret;
|
||||
break;
|
||||
case 0b00100: // VMOV.I32
|
||||
case 0b00101: // VORR.I32
|
||||
case 0b10100: // VMVN.I32
|
||||
case 0b10101: // VBIC.I32
|
||||
if (imm) {
|
||||
strcpy(ret, "I32");
|
||||
sprintf(&ret[4], "0x%02X0000", imm);
|
||||
}
|
||||
break;
|
||||
case 0b00110: // VMOV.I32
|
||||
case 0b00111: // VORR.I32
|
||||
case 0b10110: // VMVN.I32
|
||||
case 0b10111: // VBIC.I32
|
||||
if (imm) {
|
||||
strcpy(ret, "I32");
|
||||
sprintf(&ret[4], "0x%02X000000", imm);
|
||||
}
|
||||
break;
|
||||
case 0b01000: // VMOV.I16
|
||||
case 0b01001: // VORR.I16
|
||||
case 0b11000: // VMVN.I16
|
||||
case 0b11001: // VBIC.I16
|
||||
strcpy(ret, "I16");
|
||||
sprintf(&ret[4], "0x%02X", imm);
|
||||
break;
|
||||
case 0b01010: // VMOV.I16
|
||||
case 0b01011: // VORR.I16
|
||||
case 0b11010: // VMVN.I16
|
||||
case 0b11011: // VBIC.I16
|
||||
if (imm) {
|
||||
strcpy(ret, "I16");
|
||||
sprintf(&ret[4], "0x%02X00", imm);
|
||||
}
|
||||
break;
|
||||
case 0b01100: // VMOV.I32
|
||||
case 0b11100: // VMVN.I32
|
||||
if (imm) {
|
||||
strcpy(ret, "I32");
|
||||
sprintf(&ret[4], "0x%02XFF", imm);
|
||||
}
|
||||
break;
|
||||
case 0b01101: // VMOV.I32
|
||||
case 0b11101: // VMVN.I32
|
||||
if (imm) {
|
||||
strcpy(ret, "I32");
|
||||
sprintf(&ret[4], "0x%02XFFFF", imm);
|
||||
}
|
||||
break;
|
||||
case 0b01110: // VMOV.I8
|
||||
strcpy(ret, "I8");
|
||||
sprintf(&ret[4], "0x%02X", imm);
|
||||
break;
|
||||
case 0b01111: // VMOV.F32
|
||||
strcpy(ret, "F32");
|
||||
sprintf(&ret[4], "%e", (imm & 0x80 ? -1 : 1) * (1 << (((imm >> 4) & 0x7) ^ 0b100)) * (float) (16 + (imm & 0xF)) / 128.);
|
||||
break;
|
||||
case 0b11110: // VMOV.I64
|
||||
{
|
||||
strcpy(ret, "I64");
|
||||
sprintf(&ret[4], "#0x%s%s%s%s%s%s%s%s",
|
||||
_print_modified_imm_I64_bytes[(imm >> 7) & 1], _print_modified_imm_I64_bytes[(imm >> 6) & 1],
|
||||
_print_modified_imm_I64_bytes[(imm >> 5) & 1], _print_modified_imm_I64_bytes[(imm >> 4) & 1],
|
||||
_print_modified_imm_I64_bytes[(imm >> 3) & 1], _print_modified_imm_I64_bytes[(imm >> 2) & 1],
|
||||
_print_modified_imm_I64_bytes[(imm >> 1) & 1], _print_modified_imm_I64_bytes[(imm >> 0) & 1]);
|
||||
}
|
||||
break;
|
||||
case 0b11111: // V???.-
|
||||
default:
|
||||
strcpy(ret, "-");
|
||||
strcpy(&ret[4], "UNDEFINED");
|
||||
break;
|
||||
}
|
||||
|
||||
const char* arm_print(uint32_t opcode) {
|
||||
static __thread char ret[100];
|
||||
memset(ret, 0, sizeof(ret));
|
||||
|
||||
"""
|
||||
return ret;
|
||||
}
|
||||
files_guard = {
|
||||
"arm_printer.c": """
|
||||
{
|
||||
strcpy(ret, "???");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char* arm_print(uint32_t opcode) {
|
||||
static __thread char ret[100];
|
||||
memset(ret, 0, sizeof(ret));
|
||||
|
||||
"""
|
||||
footer = """
|
||||
{
|
||||
strcpy(ret, "???");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
"""
|
||||
banner = "/*******************************************************" + ('*'*len(ver)) + "***\n" \
|
||||
" * File automatically generated by rebuild_printer.py (v" + ver + ") *\n" \
|
||||
" *******************************************************" + ('*'*len(ver)) + "***/\n"
|
||||
trim = lambda string: '\n'.join(line[2:] for line in string.splitlines())[1:]
|
||||
# Yes, the for loops are inverted. This is because both dicts should have the same keys.
|
||||
for fhdr in files_guard:
|
||||
files_header[fhdr] = banner + trim(files_header[fhdr])
|
||||
for fhdr in files_header:
|
||||
files_guard[fhdr] = trim(files_guard[fhdr])
|
||||
trim = lambda string: '\n'.join(line[1:] for line in string.splitlines())[1:]
|
||||
header = banner + trim(header)
|
||||
footer = trim(footer)
|
||||
|
||||
for f in files_header:
|
||||
with open(os.path.join(root, "src", "dynarec", f), 'w') as file:
|
||||
file.write(files_header[f])
|
||||
file.write(output)
|
||||
file.write(files_guard[f])
|
||||
with open(os.path.join(root, "src", "dynarec", "arm_printer.c"), 'w') as file:
|
||||
file.write(header)
|
||||
file.write(output)
|
||||
file.write(footer)
|
||||
# Save the string for the next iteration, writing was successful
|
||||
with open(os.path.join(root, "src", "dynarec", "last_run.txt"), 'w') as file:
|
||||
file.write('\n'.join(insts))
|
||||
@@ -1988,6 +1980,6 @@ if __name__ == '__main__':
|
||||
for i, v in enumerate(sys.argv):
|
||||
if v == "--":
|
||||
limit.append(i)
|
||||
if main(sys.argv[1], "1.2.0.05") != 0:
|
||||
if main(sys.argv[1], "1.2.0.06") != 0:
|
||||
exit(2)
|
||||
exit(0)
|
||||
+63
-32
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import sys
|
||||
@@ -74,7 +74,7 @@ For each of them:
|
||||
NOTE: Those structure letters are "fake types" that are accepted in the macros.
|
||||
|
||||
`gbl` contains the first list, `redirects` the second and
|
||||
`filespec` constains file specific informations (eg, structures, typedefs required...).
|
||||
`filespec` contains file specific information (eg, structures, typedefs required...).
|
||||
|
||||
After sorting the data, it generates:
|
||||
|
||||
@@ -166,8 +166,8 @@ U = TypeVar('U')
|
||||
Filename = str
|
||||
|
||||
class CustOrderedDict(Generic[T, U], Iterable[T]):
|
||||
__keys__: List[T]
|
||||
__actdict__: Dict[T, U]
|
||||
__keys__: List[T] = []
|
||||
__actdict__: Dict[T, U] = {}
|
||||
|
||||
def __init__(self, src: Optional[Dict[T, U]] = None) -> None:
|
||||
if src is None:
|
||||
@@ -195,7 +195,7 @@ class CustOrderedDictList(CustOrderedDict[T, List[U]]):
|
||||
return super().__getitem__(k)
|
||||
|
||||
class FirstArgumentSingletonMeta(Generic[T], type):
|
||||
_singletons: Dict[T, Type['FirstArgumentSingletonMeta']]
|
||||
_singletons: Dict[T, Type['FirstArgumentSingletonMeta']] = {}
|
||||
|
||||
@classmethod
|
||||
def __prepare__(metacls, __name: str, __bases: Tuple[type, ...], **kwds: Any) -> Dict[str, Any]:
|
||||
@@ -227,10 +227,9 @@ class FileSpec:
|
||||
values: Sequence[str] = ['E', 'v', 'c', 'w', 'i', 'I', 'C', 'W', 'u', 'U', 'f', 'd', 'D', 'K', 'l', 'L', 'p', 'V', 'O', 'S', '2', 'P', 'G', 'N', 'M', 's']
|
||||
rvalues: Sequence[str] = ['E', 'v', 'c', 'w', 'i', 'I', 'C', 'W', 'u', 'U', 'f', 'd', 'D', 'K', 'l', 'L', 'p', 'V', 'O', 'S', '2', 'P', 'G', 'N', 'M', 's']
|
||||
validrepl: Sequence[str] = ['c', 'w', 'i', 'I', 'C', 'W', 'u', 'U', 'f', 'd', 'D', 'K', 'l', 'L', 'p', 'V', 'O', 'S', '2', 'P', 'G', 'N', 'M', 's']
|
||||
structs: CustOrderedDict[str, Struct]
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.structs = CustOrderedDict()
|
||||
self.structs: CustOrderedDict[str, FileSpec.Struct] = CustOrderedDict()
|
||||
|
||||
self.typedefs: CustOrderedDictList[_BareFunctionType, Function] = CustOrderedDictList()
|
||||
self.structsuses: List[FunctionType] = []
|
||||
@@ -441,8 +440,8 @@ class Function:
|
||||
DefineType = NewType('DefineType', str)
|
||||
@final
|
||||
class Define:
|
||||
name: DefineType
|
||||
inverted_: bool
|
||||
name: DefineType = DefineType("")
|
||||
inverted_: bool = False
|
||||
|
||||
defines: List[DefineType] = []
|
||||
|
||||
@@ -480,7 +479,7 @@ class Define:
|
||||
return isinstance(o, Define) and (self.name == o.name) and (self.inverted_ == o.inverted_)
|
||||
@final
|
||||
class Clause:
|
||||
defines: List[Define]
|
||||
defines: List[Define] = []
|
||||
|
||||
def __init__(self, defines: Union[List[Define], str] = []) -> None:
|
||||
if isinstance(defines, str):
|
||||
@@ -528,7 +527,7 @@ class Clauses:
|
||||
Represent a list of clauses, aka a list of or-ed together and-ed "defined()"
|
||||
conditions
|
||||
"""
|
||||
clauses: List[Clause]
|
||||
clauses: List[Clause] = []
|
||||
|
||||
def __init__(self, clauses: Union[List[Clause], str] = []) -> None:
|
||||
if isinstance(clauses, str):
|
||||
@@ -632,7 +631,7 @@ class Clauses:
|
||||
combinable[len(last_combined) - 1] = True
|
||||
add = (i | attempt[0], m | (i ^ attempt[0]))
|
||||
if add in combined:
|
||||
continue # Aleady added
|
||||
continue # Already added
|
||||
combined.append(add)
|
||||
last_combined.pop()
|
||||
last_combined = combined
|
||||
@@ -680,12 +679,12 @@ class Clauses:
|
||||
return isinstance(o, Clauses) and (self.clauses == o.clauses)
|
||||
|
||||
JumbledFunctions = CustOrderedDictList[Clause, Function]
|
||||
FilesSpecific = Dict[Filename, FileSpec]
|
||||
FileSpecifics = Dict[Filename, FileSpec]
|
||||
|
||||
SortedGlobals = CustOrderedDictList[Clauses, FunctionType]
|
||||
SortedRedirects = CustOrderedDictList[Clauses, FunctionType]
|
||||
|
||||
def readFiles(files: Iterable[str]) -> Tuple[JumbledFunctions, JumbledFunctions, FilesSpecific]:
|
||||
def readFiles(files: Iterable[str]) -> Tuple[JumbledFunctions, JumbledFunctions, FileSpecifics]:
|
||||
"""
|
||||
readFiles
|
||||
|
||||
@@ -694,7 +693,7 @@ def readFiles(files: Iterable[str]) -> Tuple[JumbledFunctions, JumbledFunctions,
|
||||
|
||||
gbls: JumbledFunctions = CustOrderedDictList()
|
||||
redirects: JumbledFunctions = CustOrderedDictList()
|
||||
filespecs: FilesSpecific = {}
|
||||
filespecs: FileSpecifics = {}
|
||||
|
||||
symbols: Dict[str, Filename] = {}
|
||||
need_halt: bool = False
|
||||
@@ -748,9 +747,18 @@ def readFiles(files: Iterable[str]) -> Tuple[JumbledFunctions, JumbledFunctions,
|
||||
or match("sdl1ttf", "sdl2ttf") \
|
||||
or match("smpeg", "smpeg2") \
|
||||
or match("udev0", "udev1") \
|
||||
or match("gstinterfaces010","gstvideo")\
|
||||
or match("gstinterfaces010","gstaudio")\
|
||||
or match("gstreamer010","gstreamer") \
|
||||
or match("appindicator","appindicator3")\
|
||||
or match("appindicator","ayatanaappindicator3")\
|
||||
or match("appindicator3","ayatanaappindicator3")\
|
||||
or match("libgl", "libglx") \
|
||||
\
|
||||
or match("libc", "tcmallocminimal") \
|
||||
or match("libc", "ldlinux") \
|
||||
or match("libc", "ldlinux") \
|
||||
or match("libc", "tbbmallocproxy") \
|
||||
or match("tcmallocminimal","tbbmallocproxy") \
|
||||
:
|
||||
# libc and ldlinux have some "__libc_" data symbols in common... TODO check if ok
|
||||
continue
|
||||
@@ -875,7 +883,7 @@ def readFiles(files: Iterable[str]) -> Tuple[JumbledFunctions, JumbledFunctions,
|
||||
|
||||
return gbls, redirects, filespecs
|
||||
|
||||
def sortArrays(gbl_funcs: JumbledFunctions, red_funcs: JumbledFunctions, filespecs: FilesSpecific) \
|
||||
def sortArrays(gbl_funcs: JumbledFunctions, red_funcs: JumbledFunctions, filespecs: FileSpecifics) \
|
||||
-> Tuple[SortedGlobals, SortedRedirects]:
|
||||
# First sort file specific stuff
|
||||
for fn in filespecs:
|
||||
@@ -939,13 +947,13 @@ def sortArrays(gbl_funcs: JumbledFunctions, red_funcs: JumbledFunctions, filespe
|
||||
redirects[red_vals[funtype]].append(funtype)
|
||||
redirects.sort(key=Clauses.splitdef)
|
||||
|
||||
def fail(): assert(False)
|
||||
def fail(): assert False
|
||||
for clauses in redirects:
|
||||
redirects[clauses].sort(key=lambda v: fail() if v.redirected is None else v.splitchar() + v.redirected.splitchar())
|
||||
|
||||
return gbls, redirects
|
||||
|
||||
def checkRun(root: str, gbls: SortedGlobals, redirects: SortedRedirects, filesspec: FilesSpecific) -> Optional[str]:
|
||||
def checkRun(root: str, gbls: SortedGlobals, redirects: SortedRedirects, filespecs: FileSpecifics) -> Optional[str]:
|
||||
# Check if there was any new functions compared to last run
|
||||
functions_list: str = ""
|
||||
for clauses in gbls:
|
||||
@@ -955,18 +963,18 @@ def checkRun(root: str, gbls: SortedGlobals, redirects: SortedRedirects, filessp
|
||||
for v in redirects[clauses]:
|
||||
assert(v.redirected is not None)
|
||||
functions_list = functions_list + "#" + str(clauses) + " " + v.orig + " -> " + v.redirected.orig + "\n"
|
||||
for filename in sorted(filesspec.keys()):
|
||||
for filename in sorted(filespecs.keys()):
|
||||
functions_list = functions_list + filename + ":\n"
|
||||
for st in filesspec[filename].structs:
|
||||
struct = filesspec[filename].structs[st]
|
||||
for st in filespecs[filename].structs:
|
||||
struct = filespecs[filename].structs[st]
|
||||
functions_list = functions_list + \
|
||||
"% " + st + " " + struct.name + " " + struct.repl + "\n"
|
||||
for _bare in filesspec[filename].typedefs:
|
||||
for _bare in filespecs[filename].typedefs:
|
||||
functions_list = functions_list + "- " + _bare.orig + ":\n"
|
||||
for fn in filesspec[filename].typedefs[_bare]:
|
||||
for fn in filespecs[filename].typedefs[_bare]:
|
||||
if fn.no_dlsym: continue
|
||||
functions_list = functions_list + " - " + fn.name + "\n"
|
||||
for funtype in filesspec[filename].structsuses:
|
||||
for funtype in filespecs[filename].structsuses:
|
||||
assert(funtype.redirected is not None)
|
||||
functions_list = functions_list + "% " + funtype.orig + " -> " + funtype.redirected.orig + "\n"
|
||||
|
||||
@@ -987,7 +995,7 @@ def checkRun(root: str, gbls: SortedGlobals, redirects: SortedRedirects, filessp
|
||||
return functions_list
|
||||
|
||||
def generate_files(root: str, files: Iterable[str], ver: str, gbls: SortedGlobals, redirects: SortedRedirects, \
|
||||
filespecs: FilesSpecific) -> None:
|
||||
filespecs: FileSpecifics) -> None:
|
||||
# Files header and guard
|
||||
files_header = {
|
||||
"wrapper.c": """
|
||||
@@ -1053,8 +1061,8 @@ def generate_files(root: str, files: Iterable[str], ver: str, gbls: SortedGlobal
|
||||
memcpy(value+4, v->data, 2*sizeof(double));
|
||||
{rbr}
|
||||
|
||||
void* VulkanFromx86(void* src, void** save);
|
||||
void VulkanTox86(void* src, void* save);
|
||||
void* VulkanFromx86(void* src);
|
||||
void VulkanTox86(void* src);
|
||||
|
||||
#define ST0val ST0.d
|
||||
|
||||
@@ -1143,6 +1151,13 @@ def generate_files(root: str, files: Iterable[str], ver: str, gbls: SortedGlobal
|
||||
for fhdr in files_header:
|
||||
files_guard[fhdr] = trim(files_guard[fhdr])
|
||||
|
||||
# TODO: put the information below in a structure (like in box64, where
|
||||
# typedefs & co. are stored in an ABI-specific structure)
|
||||
|
||||
return_x87: str = "DKdf"
|
||||
if any(c not in FileSpec.values for c in return_x87):
|
||||
raise NotImplementedError("Invalid character")
|
||||
|
||||
# Typedefs
|
||||
# E v c w i I C W u U f d D K l L p V O S 2 P G N M s
|
||||
tdtypes = ["x86emu_t*", "void", "int8_t", "int16_t", "int32_t", "int64_t", "uint8_t", "uint16_t", "uint32_t", "uint64_t", "float", "double", "long double", "double", "intptr_t", "uintptr_t", "void*", "void*", "int32_t", "void*", "_2uint_struct_t", "void*", "void*", "...", "...", "void*"]
|
||||
@@ -1244,7 +1259,7 @@ def generate_files(root: str, files: Iterable[str], ver: str, gbls: SortedGlobal
|
||||
f.write("void {0}(x86emu_t *emu, uintptr_t fcn) {2} {1} fn = ({1})fcn; ".format(N.orig, W, "{"))
|
||||
|
||||
if N.orig == 'vFv':
|
||||
f.write("(void)fcn; ")
|
||||
f.write("(void)emu; ")
|
||||
|
||||
args = N.orig[2:]
|
||||
if args == 'Ev': args = 'E'
|
||||
@@ -1254,7 +1269,7 @@ def generate_files(root: str, files: Iterable[str], ver: str, gbls: SortedGlobal
|
||||
delta = 4
|
||||
for c in args:
|
||||
if c == 'P':
|
||||
f.write("void* save{d} = NULL; void *arg{d} = VulkanFromx86(*(void**)(R_ESP + {d}), &save{d}); ".format(d=delta))
|
||||
f.write("void *arg{d} = VulkanFromx86(*(void**)(R_ESP + {d})); ".format(d=delta))
|
||||
if c == 'G':
|
||||
f.write("my_GValue_t arg{d}; alignGValue(&arg{d}, *(void**)(R_ESP + {d})); ".format(d=delta))
|
||||
delta = delta + deltas[FileSpec.values.index(c)]
|
||||
@@ -1262,7 +1277,7 @@ def generate_files(root: str, files: Iterable[str], ver: str, gbls: SortedGlobal
|
||||
delta = 4
|
||||
for c in args:
|
||||
if c == 'P':
|
||||
f.write("VulkanTox86(arg{d}, save{d}); ".format(d=delta))
|
||||
f.write("VulkanTox86(arg{d}); ".format(d=delta))
|
||||
if c == 'G':
|
||||
f.write("unalignGValue(*(void**)(R_ESP + {d}), &arg{d}); ".format(d=delta))
|
||||
delta = delta + deltas[FileSpec.values.index(c)]
|
||||
@@ -1304,6 +1319,22 @@ def generate_files(root: str, files: Iterable[str], ver: str, gbls: SortedGlobal
|
||||
if not clauses.empty():
|
||||
file.write("#endif\n")
|
||||
|
||||
# Finally, write predicate functions
|
||||
|
||||
# isRetX87Wrapper
|
||||
file.write("\nint isRetX87Wrapper(wrapper_t fun) {\n")
|
||||
for clauses in gbls:
|
||||
empty = True
|
||||
for funtype in gbls[clauses]:
|
||||
if funtype.orig[0] in return_x87: # TODO: put this in a function (functions would request the ABI for more info)
|
||||
if empty and (not clauses.empty()):
|
||||
file.write("#if " + str(clauses) + "\n")
|
||||
empty = False
|
||||
file.write("\tif (fun == &" + funtype.orig + ") return 1;\n")
|
||||
if not empty:
|
||||
file.write("#endif\n")
|
||||
file.write("\treturn 0;\n}\n")
|
||||
|
||||
file.write(files_guard["wrapper.c"].format(lbr="{", rbr="}", version=ver))
|
||||
|
||||
# Rewrite the wrapper.h file:
|
||||
@@ -1393,6 +1424,6 @@ if __name__ == '__main__':
|
||||
if v == "--":
|
||||
limit.append(i)
|
||||
Define.defines = list(map(DefineType, sys.argv[2:limit[0]]))
|
||||
if main(sys.argv[1], sys.argv[limit[0]+1:], "2.0.0.10") != 0:
|
||||
if main(sys.argv[1], sys.argv[limit[0]+1:], "2.0.0.11") != 0:
|
||||
exit(2)
|
||||
exit(0)
|
||||
@@ -52,5 +52,10 @@ if( TEST_RESULT )
|
||||
message( FATAL_ERROR "Failed: The output of ${TEST_PROGRAM} did not match ${TEST_REFERENCE}")
|
||||
endif( TEST_RESULT )
|
||||
|
||||
# remove the temporary files if they exist
|
||||
if( EXISTS ${TEST_OUTPUT} )
|
||||
file(REMOVE "${TEST_OUTPUT}")
|
||||
endif()
|
||||
|
||||
# everything went fine...
|
||||
message( "Passed: The output of ${TEST_PROGRAM} matches ${TEST_REFERENCE}" )
|
||||
+142
-42
@@ -22,6 +22,8 @@
|
||||
#include <sys/mman.h>
|
||||
#include "custommem.h"
|
||||
#include "dictionnary.h"
|
||||
#include "rcfile.h"
|
||||
#include "gltools.h"
|
||||
#ifdef DYNAREC
|
||||
#include "dynablock.h"
|
||||
#include "dynarec/arm_lock_helper.h"
|
||||
@@ -48,6 +50,7 @@ void finiAllHelpers(box86context_t* context)
|
||||
static int finied = 0;
|
||||
if(finied)
|
||||
return;
|
||||
DeleteParams();
|
||||
fini_pthread_helper(context);
|
||||
fini_signal_helper();
|
||||
fini_bridge_helper();
|
||||
@@ -74,19 +77,30 @@ void free_tlsdatasize(void* p)
|
||||
if(!p)
|
||||
return;
|
||||
tlsdatasize_t *data = (tlsdatasize_t*)p;
|
||||
free(data->tlsdata);
|
||||
free(p);
|
||||
box_free(data->ptr);
|
||||
box_free(p);
|
||||
if(my_context)
|
||||
pthread_setspecific(my_context->tlskey, NULL);
|
||||
}
|
||||
|
||||
int unlockMutex()
|
||||
{
|
||||
int ret = unlockCustommemMutex();
|
||||
int i;
|
||||
#ifdef USE_CUSTOM_MUTEX
|
||||
void* tid = (void*)GetTID();
|
||||
#define GO(A, B) \
|
||||
i = (arm_lock_storeifref2(&A, NULL, tid)==tid); \
|
||||
if(i) { \
|
||||
ret|=(1<<B); \
|
||||
}
|
||||
#else
|
||||
#define GO(A, B) \
|
||||
i = checkUnlockMutex(&A); \
|
||||
if(i) { \
|
||||
ret|=(1<<B); \
|
||||
}
|
||||
#endif
|
||||
|
||||
GO(my_context->mutex_once, 5)
|
||||
GO(my_context->mutex_once2, 6)
|
||||
@@ -100,7 +114,6 @@ int unlockMutex()
|
||||
GO(my_context->mutex_thread, 10)
|
||||
GO(my_context->mutex_bridge, 11)
|
||||
#undef GO
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -108,7 +121,7 @@ void relockMutex(int locks)
|
||||
{
|
||||
#define GO(A, B) \
|
||||
if(locks&(1<<B)) \
|
||||
pthread_mutex_lock(&A); \
|
||||
mutex_lock(&A); \
|
||||
|
||||
GO(my_context->mutex_once, 5)
|
||||
GO(my_context->mutex_once2, 6)
|
||||
@@ -127,22 +140,45 @@ void relockMutex(int locks)
|
||||
|
||||
static void init_mutexes(box86context_t* context)
|
||||
{
|
||||
|
||||
#ifdef DYNAREC
|
||||
#ifdef USE_CUSTOM_MUTEX
|
||||
arm_lock_stored(&context->mutex_dyndump, 0);
|
||||
arm_lock_stored(&context->mutex_once, 0);
|
||||
arm_lock_stored(&context->mutex_once2, 0);
|
||||
arm_lock_stored(&context->mutex_trace, 0);
|
||||
arm_lock_stored(&context->mutex_tls, 0);
|
||||
arm_lock_stored(&context->mutex_thread, 0);
|
||||
arm_lock_stored(&context->mutex_bridge, 0);
|
||||
#else
|
||||
pthread_mutexattr_t attr;
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
|
||||
pthread_mutex_init(&context->mutex_dyndump, &attr);
|
||||
pthread_mutex_init(&context->mutex_once, &attr);
|
||||
pthread_mutex_init(&context->mutex_once2, &attr);
|
||||
pthread_mutex_init(&context->mutex_trace, &attr);
|
||||
pthread_mutex_init(&context->mutex_tls, &attr);
|
||||
pthread_mutex_init(&context->mutex_thread, &attr);
|
||||
pthread_mutex_init(&context->mutex_bridge, &attr);
|
||||
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
#endif
|
||||
pthread_mutex_init(&context->mutex_lock, NULL);
|
||||
#else
|
||||
pthread_mutexattr_t attr;
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
|
||||
pthread_mutex_init(&context->mutex_once, &attr);
|
||||
pthread_mutex_init(&context->mutex_once2, &attr);
|
||||
pthread_mutex_init(&context->mutex_trace, &attr);
|
||||
#ifdef DYNAREC
|
||||
pthread_mutex_init(&context->mutex_dyndump, &attr);
|
||||
#else
|
||||
pthread_mutex_init(&context->mutex_lock, &attr);
|
||||
#endif
|
||||
pthread_mutex_init(&context->mutex_tls, &attr);
|
||||
pthread_mutex_init(&context->mutex_thread, &attr);
|
||||
pthread_mutex_init(&context->mutex_bridge, &attr);
|
||||
pthread_mutex_init(&context->mutex_lock, &attr);
|
||||
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void atfork_child_box64context(void)
|
||||
@@ -151,6 +187,31 @@ static void atfork_child_box64context(void)
|
||||
init_mutexes(my_context);
|
||||
}
|
||||
|
||||
void freeCycleLog(box86context_t* ctx)
|
||||
{
|
||||
if(cycle_log) {
|
||||
for(int i=0; i<cycle_log; ++i) {
|
||||
box_free(ctx->log_call[i]);
|
||||
box_free(ctx->log_ret[i]);
|
||||
}
|
||||
box_free(ctx->log_call);
|
||||
box_free(ctx->log_ret);
|
||||
ctx->log_call = NULL;
|
||||
ctx->log_ret = NULL;
|
||||
}
|
||||
}
|
||||
void initCycleLog(box86context_t* context)
|
||||
{
|
||||
if(cycle_log) {
|
||||
context->log_call = (char**)box_calloc(cycle_log, sizeof(char*));
|
||||
context->log_ret = (char**)box_calloc(cycle_log, sizeof(char*));
|
||||
for(int i=0; i<cycle_log; ++i) {
|
||||
context->log_call[i] = (char*)box_calloc(256, 1);
|
||||
context->log_ret[i] = (char*)box_calloc(128, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EXPORTDYN
|
||||
box86context_t *NewBox86Context(int argc)
|
||||
{
|
||||
@@ -161,12 +222,14 @@ box86context_t *NewBox86Context(int argc)
|
||||
}
|
||||
#endif
|
||||
// init and put default values
|
||||
box86context_t *context = my_context = (box86context_t*)calloc(1, sizeof(box86context_t));
|
||||
box86context_t *context = my_context = (box86context_t*)box_calloc(1, sizeof(box86context_t));
|
||||
|
||||
initCycleLog(context);
|
||||
|
||||
#ifdef BUILD_LIB
|
||||
context->deferedInit = 0;
|
||||
#else
|
||||
context->deferedInit = 1;
|
||||
context->deferredInit = 1;
|
||||
#endif
|
||||
context->sel_serial = 1;
|
||||
|
||||
@@ -176,9 +239,12 @@ box86context_t *NewBox86Context(int argc)
|
||||
context->local_maplib = NewLibrarian(context, 1);
|
||||
context->versym = NewDictionnary();
|
||||
context->system = NewBridge();
|
||||
// Cannot use Bridge name as the map is not initialized yet
|
||||
// create vsyscall
|
||||
context->vsyscall = AddBridge(context->system, iFEv, x86Syscall, 0, NULL);
|
||||
addAlternate((void*)0xffffe400, (void*)context->vsyscall);
|
||||
// create exit bridge
|
||||
context->exit_bridge = AddBridge(context->system, NULL, NULL, 0, NULL);
|
||||
#ifdef BUILD_LIB
|
||||
context->box86lib = RTLD_DEFAULT; // not ideal
|
||||
#else
|
||||
@@ -187,12 +253,12 @@ box86context_t *NewBox86Context(int argc)
|
||||
context->dlprivate = NewDLPrivate();
|
||||
|
||||
context->argc = argc;
|
||||
context->argv = (char**)calloc(context->argc+1, sizeof(char*));
|
||||
context->argv = (char**)box_calloc(context->argc+1, sizeof(char*));
|
||||
|
||||
init_mutexes(context);
|
||||
pthread_atfork(NULL, NULL, atfork_child_box64context);
|
||||
|
||||
pthread_key_create(&context->tlskey, free_tlsdatasize);
|
||||
pthread_key_create(&context->tlskey, NULL/*free_tlsdatasize*/);
|
||||
|
||||
InitFTSMap(context);
|
||||
|
||||
@@ -200,11 +266,13 @@ box86context_t *NewBox86Context(int argc)
|
||||
context->canary[/*getrand(4)*/0] = 0;
|
||||
printf_log(LOG_DEBUG, "Setting up canary (for Stack protector) at GS:0x14, value:%08X\n", *(uint32_t*)context->canary);
|
||||
|
||||
context->globdata = NewMapSymbols();
|
||||
|
||||
initAllHelpers(context);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
void freeALProcWrapper(box86context_t* context);
|
||||
EXPORTDYN
|
||||
void FreeBox86Context(box86context_t** context)
|
||||
{
|
||||
@@ -220,6 +288,7 @@ void FreeBox86Context(box86context_t** context)
|
||||
|
||||
box86context_t* ctx = *context; // local copy to do the cleanning
|
||||
|
||||
//clean_current_emuthread(); // cleaning main thread seems a bad idea
|
||||
if(ctx->local_maplib)
|
||||
FreeLibrarian(&ctx->local_maplib, NULL);
|
||||
if(ctx->maplib)
|
||||
@@ -229,7 +298,7 @@ void FreeBox86Context(box86context_t** context)
|
||||
for(int i=0; i<ctx->elfsize; ++i) {
|
||||
FreeElfHeader(&ctx->elfs[i]);
|
||||
}
|
||||
free(ctx->elfs);
|
||||
box_free(ctx->elfs);
|
||||
|
||||
FreeFTSMap(ctx);
|
||||
|
||||
@@ -242,17 +311,17 @@ void FreeBox86Context(box86context_t** context)
|
||||
if(ctx->zydis)
|
||||
DeleteX86Trace(ctx);
|
||||
|
||||
if(ctx->deferedInitList)
|
||||
free(ctx->deferedInitList);
|
||||
if(ctx->deferredInitList)
|
||||
box_free(ctx->deferredInitList);
|
||||
|
||||
free(ctx->argv);
|
||||
/*box_free(ctx->argv);*/
|
||||
|
||||
for (int i=0; i<ctx->envc; ++i)
|
||||
free(ctx->envv[i]);
|
||||
free(ctx->envv);
|
||||
/*for (int i=0; i<ctx->envc; ++i)
|
||||
box_free(ctx->envv[i]);
|
||||
box_free(ctx->envv);*/
|
||||
|
||||
if(ctx->atfork_sz) {
|
||||
free(ctx->atforks);
|
||||
box_free(ctx->atforks);
|
||||
ctx->atforks = NULL;
|
||||
ctx->atfork_sz = ctx->atfork_cap = 0;
|
||||
}
|
||||
@@ -273,25 +342,28 @@ void FreeBox86Context(box86context_t** context)
|
||||
|
||||
FreeDLPrivate(&ctx->dlprivate);
|
||||
|
||||
// free(ctx->stack); // don't free the stack, it's owned by main emu!
|
||||
// box_free(ctx->stack); // don't free the stack, it's owned by main emu!
|
||||
|
||||
free(ctx->fullpath);
|
||||
free(ctx->box86path);
|
||||
box_free(ctx->fullpath);
|
||||
box_free(ctx->box86path);
|
||||
box_free(ctx->bashpath);
|
||||
|
||||
FreeBridge(&ctx->system);
|
||||
|
||||
freeGLProcWrapper(ctx);
|
||||
freeALProcWrapper(ctx);
|
||||
|
||||
if(ctx->stack_clone)
|
||||
box_free(ctx->stack_clone);
|
||||
|
||||
void* ptr;
|
||||
if ((ptr = pthread_getspecific(ctx->tlskey)) != NULL) {
|
||||
free_tlsdatasize(ptr);
|
||||
pthread_setspecific(ctx->tlskey, NULL);
|
||||
}
|
||||
pthread_key_delete(ctx->tlskey);
|
||||
|
||||
if(ctx->tlsdata)
|
||||
free(ctx->tlsdata);
|
||||
box_free(ctx->tlsdata);
|
||||
|
||||
for(int i=0; i<3; ++i) {
|
||||
if(ctx->segtls[i].present) {
|
||||
@@ -300,45 +372,73 @@ void FreeBox86Context(box86context_t** context)
|
||||
}
|
||||
}
|
||||
|
||||
free_neededlib(&ctx->neededlibs);
|
||||
free_neededlib(ctx->neededlibs);
|
||||
ctx->neededlibs = NULL;
|
||||
|
||||
if(ctx->emu_sig)
|
||||
FreeX86Emu(&ctx->emu_sig);
|
||||
|
||||
FreeMapSymbols(&ctx->globdata);
|
||||
|
||||
finiAllHelpers(ctx);
|
||||
|
||||
#ifndef USE_CUSTOM_MUTEX
|
||||
pthread_mutex_destroy(&ctx->mutex_once);
|
||||
pthread_mutex_destroy(&ctx->mutex_once2);
|
||||
pthread_mutex_destroy(&ctx->mutex_trace);
|
||||
#ifdef DYNAREC
|
||||
pthread_mutex_destroy(&ctx->mutex_dyndump);
|
||||
#else
|
||||
pthread_mutex_destroy(&ctx->mutex_lock);
|
||||
#endif
|
||||
pthread_mutex_destroy(&ctx->mutex_tls);
|
||||
pthread_mutex_destroy(&ctx->mutex_thread);
|
||||
pthread_mutex_destroy(&ctx->mutex_bridge);
|
||||
#endif
|
||||
pthread_mutex_destroy(&ctx->mutex_lock);
|
||||
|
||||
free(ctx);
|
||||
freeCycleLog(ctx);
|
||||
|
||||
box_free(ctx);
|
||||
}
|
||||
|
||||
int AddElfHeader(box86context_t* ctx, elfheader_t* head) {
|
||||
int idx = ctx->elfsize;
|
||||
if(idx==ctx->elfcap) {
|
||||
// resize...
|
||||
ctx->elfcap += 16;
|
||||
ctx->elfs = (elfheader_t**)realloc(ctx->elfs, sizeof(elfheader_t*) * ctx->elfcap);
|
||||
int idx = 0;
|
||||
while(idx<ctx->elfsize && ctx->elfs[idx]) idx++;
|
||||
if(idx == ctx->elfsize) {
|
||||
if(idx==ctx->elfcap) {
|
||||
// resize...
|
||||
ctx->elfcap += 16;
|
||||
ctx->elfs = (elfheader_t**)box_realloc(ctx->elfs, sizeof(elfheader_t*) * ctx->elfcap);
|
||||
}
|
||||
ctx->elfs[idx] = head;
|
||||
ctx->elfsize++;
|
||||
} else {
|
||||
ctx->elfs[idx] = head;
|
||||
}
|
||||
ctx->elfs[idx] = head;
|
||||
ctx->elfsize++;
|
||||
printf_log(LOG_DEBUG, "Adding \"%s\" as #%d in elf collection\n", ElfName(head), idx);
|
||||
return idx;
|
||||
}
|
||||
|
||||
void RemoveElfHeader(box86context_t* ctx, elfheader_t* head) {
|
||||
if(GetTLSBase(head)) {
|
||||
// should remove the tls info
|
||||
int tlsbase = GetTLSBase(head);
|
||||
/*if(tlsbase == -ctx->tlssize) {
|
||||
// not really correct, but will do for now
|
||||
ctx->tlssize -= GetTLSSize(head);
|
||||
if(!(++ctx->sel_serial))
|
||||
++ctx->sel_serial;
|
||||
}*/
|
||||
}
|
||||
for(int i=0; i<ctx->elfsize; ++i)
|
||||
if(ctx->elfs[i] == head) {
|
||||
ctx->elfs[i] = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int AddTLSPartition(box86context_t* context, int tlssize) {
|
||||
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 = realloc(context->tlsdata, context->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)
|
||||
// clean GS segment for current emu
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@
|
||||
#define __BOX86_VERSION_H_
|
||||
|
||||
#define BOX86_MAJOR 0
|
||||
#define BOX86_MINOR 2
|
||||
#define BOX86_REVISION 4
|
||||
#define BOX86_MINOR 3
|
||||
#define BOX86_REVISION 9
|
||||
|
||||
#endif //__BOX86_VERSION_H_
|
||||
+833
-367
File diff suppressed because it is too large.
Load diff
+154
-13
@@ -66,7 +66,7 @@ Op is 20-27
|
||||
#define c__ (0b1110<<28) // means all
|
||||
|
||||
// nop
|
||||
#define NOP EMIT(0xe1a00000)
|
||||
#define NOP EMIT(0xe320f000)
|
||||
|
||||
// mov dst, src
|
||||
#define MOV_REG(dst, src) EMIT(0xe1a00000 | ((dst) << 12) | (src) )
|
||||
@@ -192,6 +192,9 @@ Op is 20-27
|
||||
// and dst, src1, #imm ror rot*2
|
||||
#define AND_IMM8_ROR(dst, src, imm8, rot) \
|
||||
EMIT(0xe2000000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | brIMM(imm8) )
|
||||
// and.c dst, src, #(imm8)
|
||||
#define AND_IMM8_COND(cond, dst, src, imm8) \
|
||||
EMIT((cond) | 0x02000000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
|
||||
// and.s dst, src, #(imm8)
|
||||
#define ANDS_IMM8(dst, src, imm8) \
|
||||
EMIT(0xe2100000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
|
||||
@@ -213,12 +216,17 @@ Op is 20-27
|
||||
// add dst, src1, src2, lsl #imm
|
||||
#define ADD_REG_LSL_IMM5(dst, src1, src2, imm5) \
|
||||
EMIT(0xe0800000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
|
||||
// add.c dst, src1, src2, lsl #imm
|
||||
#define ADD_REG_LSL_IMM5_COND(cond, dst, src1, src2, imm5) \
|
||||
EMIT((cond) | 0x00800000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
|
||||
// add.s dst, src1, src2, lsl #imm
|
||||
#define ADDS_REG_LSL_IMM5(dst, src1, src2, imm5) \
|
||||
EMIT(0xe0900000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
|
||||
// add dst, src1, src2, lsr #imm
|
||||
#define ADD_REG_LSR_IMM5(dst, src1, src2, imm5) \
|
||||
EMIT(0xe0800000 | ((dst) << 12) | ((src1) << 16) | brLSR(imm5, src2) )
|
||||
#define ADD_REG_LSR_IMM5_COND(cond, dst, src1, src2, imm5) \
|
||||
EMIT((cond) | 0x00800000 | ((dst) << 12) | ((src1) << 16) | brLSR(imm5, src2) )
|
||||
#define ADC_IMM8(dst, src, imm8) \
|
||||
EMIT(0xe2a00000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
|
||||
// add.s dst, src, #(imm8)
|
||||
@@ -242,9 +250,12 @@ Op is 20-27
|
||||
// cmp.s dst, src, #imm
|
||||
#define CMPS_IMM8(src, imm8) \
|
||||
EMIT(0xe3500000 | ((0) << 12) | ((src) << 16) | brIMM(imm8) )
|
||||
// cmn.s dst, src, #imm
|
||||
// cmn.s.cond dst, src, #imm
|
||||
#define CMNS_IMM8_COND(cond, src, imm8) \
|
||||
EMIT((cond) | 0x03700000 | ((0) << 12) | ((src) << 16) | brIMM(imm8) )
|
||||
// cmn.s dst, src, #imm
|
||||
#define CMNS_IMM8(src, imm8) \
|
||||
EMIT(c__ | 0x03700000 | ((0) << 12) | ((src) << 16) | brIMM(imm8) )
|
||||
// tst.s dst, src1, src2, lsl #imm
|
||||
#define TSTS_REG_LSL_IMM5(src1, src2, imm5) \
|
||||
EMIT(0xe1100000 | ((0) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
|
||||
@@ -254,21 +265,33 @@ Op is 20-27
|
||||
// tst.s dst, src1, #imm ror rot*2
|
||||
#define TSTS_IMM8_ROR(src, imm8, rot) \
|
||||
EMIT(0xe3100000 | ((0) << 12) | ((src) << 16) | ((rot)<<8) | brIMM(imm8) )
|
||||
// tst.s.cond dst, src1, #imm ror rot*2
|
||||
#define TSTS_IMM8_ROR_COND(cond, src, imm8, rot) \
|
||||
EMIT((cond) | 0x03100000 | ((0) << 12) | ((src) << 16) | ((rot)<<8) | brIMM(imm8) )
|
||||
// orr dst, src1, src2, lsl #imm
|
||||
#define ORR_REG_LSL_IMM5(dst, src1, src2, imm5) \
|
||||
EMIT(0xe1800000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
|
||||
// orr.cond dst, src1, src2, lsl #imm
|
||||
#define ORR_REG_LSL_IMM5_COND(cond, dst, src1, src2, imm5) \
|
||||
EMIT(cond | 0x01800000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
|
||||
// orr.s dst, src1, src2, lsl #imm
|
||||
#define ORRS_REG_LSL_IMM5(dst, src1, src2, imm5) \
|
||||
EMIT(0xe1900000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
|
||||
// orr dst, src1, src2, lsr #imm
|
||||
#define ORR_REG_LSR_IMM5(dst, src1, src2, imm5) \
|
||||
EMIT(0xe1800000 | ((dst) << 12) | ((src1) << 16) | brLSR(imm5, src2) )
|
||||
// orr.cond dst, src1, src2, lsr #imm
|
||||
#define ORR_REG_LSR_IMM5_COND(cond, dst, src1, src2, imm5) \
|
||||
EMIT(cond | 0x01800000 | ((dst) << 12) | ((src1) << 16) | brLSR(imm5, src2) )
|
||||
// orr.s dst, src1, src2, lsr #imm
|
||||
#define ORRS_REG_LSR_IMM5(dst, src1, src2, imm5) \
|
||||
EMIT(0xe1900000 | ((dst) << 12) | ((src1) << 16) | brLSR(imm5, src2) )
|
||||
// orr.s dst, src1, src2, lsl rs
|
||||
#define ORRS_REG_LSL_REG(dst, src1, src2, rs) \
|
||||
EMIT(0xe1900000 | ((dst) << 12) | ((src1) << 16) | brRLSL(rs, src2) )
|
||||
// orr.s dst, src1, src2, lsr rs
|
||||
#define ORRS_REG_LSR_REG(dst, src1, src2, rs) \
|
||||
EMIT(0xe1900000 | ((dst) << 12) | ((src1) << 16) | brRLSR(rs, src2) )
|
||||
// orr dst, src1, #imm8
|
||||
#define ORR_IMM8(dst, src, imm8, rot) \
|
||||
EMIT(0xe3800000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | imm8 )
|
||||
@@ -281,6 +304,9 @@ Op is 20-27
|
||||
// orr dst, src1, src2, lsl rs
|
||||
#define ORR_REG_LSL_REG(dst, src1, src2, rs) \
|
||||
EMIT(0xe1800000 | ((dst) << 12) | ((src1) << 16) | brRLSL(rs, src2) )
|
||||
// orr dst, src1, src2, lsr rs
|
||||
#define ORR_REG_LSR_REG(dst, src1, src2, rs) \
|
||||
EMIT(0xe1800000 | ((dst) << 12) | ((src1) << 16) | brRLSR(rs, src2) )
|
||||
// xor dst, src1, src2, lsl #imm
|
||||
#define XOR_REG_LSL_IMM5(dst, src1, src2, imm5) \
|
||||
EMIT(0xe0200000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
|
||||
@@ -369,6 +395,8 @@ Op is 20-27
|
||||
#define LDRD_IMM8(reg, addr, imm8) EMIT(c__ | 0b000<<25 | 1<<24 | (((imm8)<0)?0:1)<<23 | 1<<22 | 0<<21 | 0<<20 | ((reg) << 12) | ((addr) << 16) | ((abs(imm8))&0xf0)<<(8-4) | (0b1101<<4) | ((abs(imm8))&0x0f) )
|
||||
// ldrd reg, reg+1, [addr, +rm], reg must be even, reg+1 is implicit
|
||||
#define LDRD_REG(reg, addr, rm) EMIT(c__ | 0b000<<25 | 1<<24 | 1<<23 | 0<<22 | 0<<21 | 0<<20 | ((reg) << 12) | ((addr) << 16) | 0b1101<<4 | (rm) )
|
||||
// ldr reg, [pc+imm]
|
||||
#define LDR_literal(reg, imm12) EMIT(c__ | 0b010<<25 | 1<<24 | (((imm12)>=0)?1:0)<<23 | 0<<21 | 1<<20 | 0b1111<<16 | (reg)<<12 | (abs(imm12)))
|
||||
|
||||
// str reg, [addr, #+/-imm9]
|
||||
#define STR_IMM9(reg, addr, imm9) EMIT(0xe5000000 | (((imm9)<0)?0:1)<<23 | ((reg) << 12) | ((addr) << 16) | brIMM(imm9) )
|
||||
@@ -402,6 +430,8 @@ Op is 20-27
|
||||
|
||||
// blx reg
|
||||
#define BLX(reg) EMIT(0xe12fff30 | (reg) )
|
||||
// blx cond reg
|
||||
#define BLXcond(C, reg) EMIT(C | 0x012fff30 | (reg) )
|
||||
|
||||
// b cond offset
|
||||
#define Bcond(C, O) EMIT(C | (0b101<<25) | (0<<24) | (((O)>>2)&0xffffff))
|
||||
@@ -409,6 +439,10 @@ Op is 20-27
|
||||
// bl cond offset
|
||||
#define BLcond(C, O) EMIT(C | (0b101<<25) | (1<<24) | (((O)>>2)&0xffffff))
|
||||
|
||||
// adr
|
||||
#define ADR_gen(cond, P, Rd, Imm12) (cond | (1<<25) | (((P)?0b0100:0b0010)<<21) | (0b1111<<16) | ((Rd)<<12) | (Imm12))
|
||||
#define ADR(cond, Rd, Imm) EMIT(ADR_gen(cond, (Imm>=0), Rd, ((Imm>=0)?Imm:-Imm)&0b111111111111))
|
||||
|
||||
// push reg!, {list}
|
||||
// all | const |pre-index| subs | no PSR |writeback| store | base |reg list
|
||||
#define PUSH(reg, list) EMIT(c__ | (0b100<<25) | (1<<24) | (0<<23) | (0<<22) | (1<<21) | (0<<20) | ((reg)<<16) | (list))
|
||||
@@ -443,7 +477,6 @@ Op is 20-27
|
||||
#define LDRH_IMM8(reg, addr, imm8) EMIT(HWS_OFF(c__, 1, (((imm8)<0)?0:1), 0, 1, addr, reg, 0, 1, abs(imm8)))
|
||||
#define LDRH_IMM8_COND(cond, reg, addr, imm8) EMIT(HWS_OFF(cond, 1, (((imm8)<0)?0:1), 0, 1, addr, reg, 0, 1, abs(imm8)))
|
||||
#define STRH_IMM8(reg, addr, imm8) EMIT(HWS_OFF(c__, 1, (((imm8)<0)?0:1), 0, 0, addr, reg, 0, 1, abs(imm8)))
|
||||
#define STRSH_IMM8(reg, addr, imm8) EMIT(HWS_OFF(c__, 1, (((imm8)<0)?0:1), 0, 0, addr, reg, 1, 1, abs(imm8)))
|
||||
|
||||
#define LDRH_REG(reg, addr, rm) EMIT(HWS_REG(c__, 1, 1, 0, 1, addr, reg, 0, 1, rm))
|
||||
#define STRH_REG(reg, addr, rm) EMIT(HWS_REG(c__, 1, 1, 0, 0, addr, reg, 0, 1, rm))
|
||||
@@ -466,6 +499,7 @@ Op is 20-27
|
||||
// Mul and MulA
|
||||
#define MULMULA(Cond, A, S, Rd, Rn, Rs, Rm) (Cond | 0b000000<<22 | (A)<<21 | (S)<<20 | (Rd)<<16 | (Rn)<<12 | (Rs)<<8 | 0b1001<<4 | (Rm))
|
||||
#define MUL(Rd, Rm, Rn) EMIT(MULMULA(c__, 0, 0, (Rd), 0, (Rm), (Rn)))
|
||||
#define MLA(Rd, Rn, Rm, Ra) EMIT(MULMULA(c__, 1, 0, (Rd), (Ra), (Rm), (Rn)))
|
||||
|
||||
#define MLS_gen(Cond, Rd, Ra, Rm, Rn) (Cond | 0b00000110<<20 | (Rd)<<16 | (Ra)<<12 | (Rm)<<8 | 0b1001<<4 | (Rn))
|
||||
//MLS : Rd = Ra - Rm*Rn
|
||||
@@ -486,6 +520,8 @@ Op is 20-27
|
||||
|
||||
// UBFX: Unsigned Bit Field Extract: extract any number of bits from Rn, zero extend and put in Rd
|
||||
#define UBFX(rd, rn, lsb, width) EMIT(c__ | (0b0111111<<21) | (((width)-1)<<16) | ((rd)<<12) | ((lsb)<<7) | (0b101<<4) | (rn))
|
||||
// UBFX: Unsigned Bit Field Extract: extract any number of bits from Rn, zero extend and put in Rd
|
||||
#define UBFX_COND(cond, rd, rn, lsb, width) EMIT(cond | (0b0111111<<21) | (((width)-1)<<16) | ((rd)<<12) | ((lsb)<<7) | (0b101<<4) | (rn))
|
||||
// SBFX: Signed Bit Field Extract: extract any number of bits from Rn, zero extend and put in Rd
|
||||
#define SBFX(rd, rn, lsb, width) EMIT(c__ | (0b0111101<<21) | (((width)-1)<<16) | ((rd)<<12) | ((lsb)<<7) | (0b101<<4) | (rn))
|
||||
|
||||
@@ -554,10 +590,24 @@ Op is 20-27
|
||||
#define STREXB(Rd, Rt, Rn) EMIT(STREXB_gen(c__, Rd, Rn, Rt))
|
||||
#define STREXB_COND(cond, Rd, Rt, Rn) EMIT(STREXB_gen(cond, Rd, Rn, Rt))
|
||||
|
||||
#define LDREXH_gen(cond, Rn, Rt) (cond | 0b0001111<<21 | 1<<20 | (Rn)<<16 | (Rt)<<12 | 0b1111<<8 | 0b1001<<4 | 0b1111)
|
||||
// Load Exclusive Half-Word Rt from Rn (tagging the memory)
|
||||
#define LDREXH(Rt, Rn) EMIT(LDREXH_gen(c__, Rn, Rt))
|
||||
#define LDREXH_COND(cond, Rt, Rn) EMIT(LDREXH_gen(cond, Rn, Rt))
|
||||
|
||||
#define STREXH_gen(cond, Rd, Rn, Rt) (cond | 0b0001111<<21 | 0<<20 | (Rn)<<16 | (Rd)<<12 | 0b1111<<8 | 0b1001<<4 | (Rt))
|
||||
// Store Exclusive Half-Word Rt to Rn, with result in Rd=0 if tag is ok, Rd==1 if store failed (Rd!=Rn && Rd!=Rt)
|
||||
#define STREXH(Rd, Rt, Rn) EMIT(STREXH_gen(c__, Rd, Rn, Rt))
|
||||
#define STREXH_COND(cond, Rd, Rt, Rn) EMIT(STREXH_gen(cond, Rd, Rn, Rt))
|
||||
|
||||
// Count leading 0 bit of Rm, store result in Rd
|
||||
#define CLZ(Rd, Rm) EMIT(c__ | 0b00010110<<20 | 0b1111<<16 | (Rd)<<12 | 0b1111<<8 | 0b0001<<4 | (Rm))
|
||||
// Count leading 0 bit of Rm, store result in Rd with cond
|
||||
#define CLZ_COND(cond, Rd, Rm) EMIT(cond | 0b00010110<<20 | 0b1111<<16 | (Rd)<<12 | 0b1111<<8 | 0b0001<<4 | (Rm))
|
||||
// Reverse bits of Rm, store result in Rd
|
||||
#define RBIT(Rd, Rm) EMIT(c__ | 0b01101111<<20 | 0b1111<<16 | (Rd)<<12 | 0b1111<<8 | 0b0011<<4 | (Rm))
|
||||
// Reverse bits of Rm, store result in Rd with cond
|
||||
#define RBIT_COND(cond, Rd, Rm) EMIT(cond | 0b01101111<<20 | 0b1111<<16 | (Rd)<<12 | 0b1111<<8 | 0b0011<<4 | (Rm))
|
||||
|
||||
#define PLD_gen(U, R, Rn, Imm5, type, Rm) (0b1111<<28 | 0b0111<<24 | (U)<<23 | (R)<<22 | 0b01<<20 | (Rn)<<16 | 0b1111<<12 | (Imm5)<<7 | (type)<<5 | (Rm))
|
||||
// Preload Cache Rn+Rm
|
||||
@@ -567,7 +617,21 @@ Op is 20-27
|
||||
|
||||
#define DMB_gen(opt) (0b1111<<28 | 0b01010111<<20 | 0b1111<<16 | 0b1111<<12 | 0b0000<<8 | 0b0101<<4 | (opt))
|
||||
// Data memory barrier Inner Sharable
|
||||
#ifdef PANDORA
|
||||
// The Pandora is single core and ordered, DMB is not usefull here so just emit nothing
|
||||
#define DMB_ISH()
|
||||
#else
|
||||
#define DMB_ISH() EMIT(DMB_gen(0b1011))
|
||||
#endif
|
||||
|
||||
#define DSB_gen(opt) (0b1111<<28 | 0b01010111<<20 | 0b1111<<16 | 0b1111<<12 | 0b0000<<8 | 0b0100<<4 | (opt))
|
||||
// Data memory barrier Inner Sharable
|
||||
#ifdef PANDORA
|
||||
// The Pandora is single core and ordered, DSB is not usefull here so just emit nothing
|
||||
#define DSB_ISH()
|
||||
#else
|
||||
#define DSB_ISH() EMIT(DSB_gen(0b1011))
|
||||
#endif
|
||||
|
||||
#define SWP_gen(cond, B, Rn, Rt, Rt2) (cond | 0b0001<<24 | (B)<<22 | (Rn)<<16 | (Rt)<<12 | 0b1001<<4 | (Rt2))
|
||||
// SWAP (atomic) [Rn]->Rt2 / Rt->[Rn], Rt can be same as Rt2
|
||||
@@ -593,11 +657,15 @@ Op is 20-27
|
||||
#define VMRS(Rt) EMIT(c__ | (0b1110<<24) | (0b1111<<20) | (0b0001<<16) | ((Rt)<<12) | (0b1010<<8) | (0b0001<<4) | (0b0000))
|
||||
// Move to FPSCR from Arm register
|
||||
#define VMSR(Rt) EMIT(c__ | (0b1110<<24) | (0b1110<<20) | (0b0001<<16) | ((Rt)<<12) | (0b1010<<8) | (0b0001<<4) | (0b0000))
|
||||
// Move to FPSCR from Arm register with cond
|
||||
#define VMSR_cond(cond, Rt) EMIT(cond | (0b1110<<24) | (0b1110<<20) | (0b0001<<16) | ((Rt)<<12) | (0b1010<<8) | (0b0001<<4) | (0b0000))
|
||||
// Move to FPSCR from Arm flags APSR
|
||||
#define VMRS_APSR() VMRS(15)
|
||||
|
||||
// Move between Rt to Sm
|
||||
#define VMOVtoV(Sm, Rt) EMIT(c__ | (0b1110<<24) | (0b000<<21) | (0<<20) | ((((Sm)&0b11110)>>1)<<16) | ((Rt)<<12) | (0b1010<<8) | (((Sm)&1)<<7) |(0b00<<6) | (1<<4))
|
||||
// Move between Rt to Sm with condition
|
||||
#define VMOVtoVcond(cond, Sm, Rt) EMIT(cond | (0b1110<<24) | (0b000<<21) | (0<<20) | ((((Sm)&0b11110)>>1)<<16) | ((Rt)<<12) | (0b1010<<8) | (((Sm)&1)<<7) |(0b00<<6) | (1<<4))
|
||||
// Move between Sm to Rt
|
||||
#define VMOVfrV(Rt, Sm) EMIT(c__ | (0b1110<<24) | (0b000<<21) | (1<<20) | ((((Sm)&0b11110)>>1)<<16) | ((Rt)<<12) | (0b1010<<8) | (((Sm)&1)<<7) |(0b00<<6) | (1<<4))
|
||||
|
||||
@@ -654,6 +722,10 @@ Op is 20-27
|
||||
// Store to memory to single VSTR Sd, [Rn, #+/-imm8], imm8&3 ignored!
|
||||
#define VSTR_32(Sd, Rn, Imm8) EMIT(c__ | (0b1101<<24) | (((Imm8)<0)?0:1)<<23 | (((Sd)&1)<<22) | (0<<20) | ((Rn)<<16) | ((((Sd)>>1)&15)<<12) | (0b1010<<8) | ((abs(Imm8)>>2)&255))
|
||||
|
||||
#define VSTM_64_gen(cond, P, U, D, W, Rn, Vd, imm8) (cond | 0b110<<25 | (P)<<24 | (U)<<23 | (D)<<22 | (W)<<21 | (Rn)<<16 | (Vd)<<12 | 0b1011<<8 | (imm8))
|
||||
// Store a sery of Dx, post imcrementing Rn
|
||||
#define VSTM_64_W(Dd, Rn) EMIT(VSTM_64_gen(c__, 0, 1, ((Dd)>>4)&1, 1, Rn, (Dd)&15, 2))
|
||||
|
||||
// Convert from single Sm to double Dd
|
||||
#define VCVT_F64_F32(Dd, Sm) EMIT(c__ | (0b1110<<24) | (1<<23) | ((((Dd)>>4)&1)<<22) | (0b11<<20) | (0b0111<<16) | (((Dd)&15)<<12) | (0b101<<9) | (0<<8) | (0b11<<6) | (((Sm)&1)<<5) | (0<<4) | (((Sm)>>1)&15))
|
||||
// Convert from double Dm to single Sd
|
||||
@@ -680,6 +752,42 @@ Op is 20-27
|
||||
// Inplace convert from F64 to S16. Rounding is not selectable
|
||||
#define VCVT_S16_F64(Dd) EMIT(VCVT_FP_gen(c__, ((Dd)>>4)&1, 1, 0, (Dd)&15, 1, 0, 16&1, (16>>1)&15))
|
||||
|
||||
#define VRINT_FP_gen(D, RM, Vd, size, M, Vm) (0b111111101<<23 | (D)<<22 | 0b111<<19 | (RM)<<16 | (Vd)<<12 | 0b10<<10 | (size)<<8 | 1<<6 | (M)<<4 | (Vm))
|
||||
// Round floating-point to integer to Nearest with Ties to Away
|
||||
#define VRINTA_F32(Sd, Sm) EMIT(VRINT_FP_gen(((Sd)&1), 0b00, ((Sd)>>1)&15, 0b10, (Sm)&1, ((Sm)>>1)&15))
|
||||
// Round floating-point to integer to Nearest with Ties to Away
|
||||
#define VRINTA_F64(Dd, Dm) EMIT(VRINT_FP_gen(((Dd)>>4)&1, 0b00, (Dd)&15, 0b11, ((Dm)>>4)&1, (Dm)&15))
|
||||
// Round floating-point to integer towards -Infinity
|
||||
#define VRINTM_F32(Sd, Sm) EMIT(VRINT_FP_gen(((Sd)&1), 0b11, ((Sd)>>1)&15, 0b10, (Sm)&1, ((Sm)>>1)&15))
|
||||
// Round floating-point to integer towards -Infinity
|
||||
#define VRINTM_F64(Dd, Dm) EMIT(VRINT_FP_gen(((Dd)>>4)&1, 0b11, (Dd)&15, 0b11, ((Dm)>>4)&1, (Dm)&15))
|
||||
// Round floating-point to integer to Nearest
|
||||
#define VRINTN_F32(Sd, Sm) EMIT(VRINT_FP_gen(((Sd)&1), 0b01, ((Sd)>>1)&15, 0b10, (Sm)&1, ((Sm)>>1)&15))
|
||||
// Round floating-point to integer to Nearest
|
||||
#define VRINTN_F64(Dd, Dm) EMIT(VRINT_FP_gen(((Dd)>>4)&1, 0b01, (Dd)&15, 0b11, ((Dm)>>4)&1, (Dm)&15))
|
||||
// Round floating-point to integer towards +Infinity
|
||||
#define VRINTP_F32(Sd, Sm) EMIT(VRINT_FP_gen(((Sd)&1), 0b10, ((Sd)>>1)&15, 0b10, (Sm)&1, ((Sm)>>1)&15))
|
||||
// Round floating-point to integer towards +Infinity
|
||||
#define VRINTP_F64(Dd, Dm) EMIT(VRINT_FP_gen(((Dd)>>4)&1, 0b10, (Dd)&15, 0b11, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#define VRINTR_gen(cond, D, Vd, size, M, Vm) (cond | 0b11101<<23 | (D)<<22 | 0b11<<20 | 0b110<<16 | (Vd)<<12 | 0b10<<10 | (size)<<8 | 1<<6 | (M)<<5 | (Vm))
|
||||
// Round floating-point to integer rounds a floating-point value to an integral floating-point value of the same size using the rounding mode specified in the FPSCR
|
||||
#define VRINTR_F32(Sd, Sm) EMIT(VRINTR_gen(c__, (Sd)&1, ((Sd)>>1)&15, 0b10, (Sm)&1, ((Sm)>>1)&15))
|
||||
// Round floating-point to integer rounds a floating-point value to an integral floating-point value of the same size using the rounding mode specified in the FPSCR
|
||||
#define VRINTR_F64(Dd, Dm) EMIT(VRINTR_gen(c__, ((Dd)>>4)&1, (Dd)&15, 0b11, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#define VRINTX_gen(cond, D, Vd, size, M, Vm) (cond | 0b11101<<23 | (D)<<22 | 0b11<<20 | 0b111<<16 | (Vd)<<12 | 0b10<<10 | (size)<<8 | 1<<6 | (M)<<5 | (Vm))
|
||||
// Round floating-point to integer rounds a floating-point value to an integral floating-point value of the same size using the rounding mode specified in the FPSCR with eXecptions if inexact
|
||||
#define VRINTX_F32(Sd, Sm) EMIT(VRINTX_gen(c__, (Sd)&1, ((Sd)>>1)&15, 0b10, (Sm)&1, ((Sm)>>1)&15))
|
||||
// Round floating-point to integer rounds a floating-point value to an integral floating-point value of the same size using the rounding mode specified in the FPSCR with eXecptions if inexact
|
||||
#define VRINTX_F64(Dd, Dm) EMIT(VRINTX_gen(c__, ((Dd)>>4)&1, (Dd)&15, 0b11, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#define VRINTZ_gen(cond, D, Vd, size, M, Vm) (cond | 0b11101<<23 | (D)<<22 | 0b11<<20 | 0b110<<16 | (Vd)<<12 | 0b10<<10 | (size)<<8 | 1<<7 | 1<<6 | (M)<<5 | (Vm))
|
||||
// Round floating-point to integer towards Zero
|
||||
#define VRINTZ_F32(Sd, Sm) EMIT(VRINTZ_gen(c__, (Sd)&1, ((Sd)>>1)&15, 0b10, (Sm)&1, ((Sm)>>1)&15))
|
||||
// Round floating-point to integer towards Zero
|
||||
#define VRINTZ_F64(Dd, Dm) EMIT(VRINTZ_gen(c__, ((Dd)>>4)&1, (Dd)&15, 0b11, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
// Mutiply F64 Dd = Dn*Dm
|
||||
#define VMUL_F64(Dd, Dn, Dm) EMIT(c__ | (0b1110<<24) | (0<<23) | ((((Dd)>>4)&1)<<22) | (0b10<<20) | (((Dn)&15)<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | ((((Dn)>>4)&1)<<7) | ((((Dm)>>4)&1)<<5) | ((Dm)&15) )
|
||||
|
||||
@@ -719,6 +827,8 @@ Op is 20-27
|
||||
#define VNEG_F64_cond(cond, Dd, Dm) EMIT((cond) | (0b1110<<24) | (1<<23) | ((((Dd)>>4)&1)<<22) | (0b11<<20) | (0b0001<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | (0b01<<6) | ((((Dm)>>4)&1)<<5) | ((Dm)&15) )
|
||||
// Neg F32 Dd = - Dm
|
||||
#define VNEG_F32(Sd, Sm) EMIT(c__ | (0b1110<<24) | (1<<23) | (((Sd)&1)<<22) | (0b11<<20) | (0b0001<<16) | ((((Sd)>>1)&15)<<12) | (0b101<<9) | (0<<8) | (0b01<<6) | (((Sm)&1)<<5) | (((Sm)>>1)&15) )
|
||||
// Neg F32 Dd = - Dm
|
||||
#define VNEG_F32_cond(cond, Sd, Sm) EMIT((cond) | (0b1110<<24) | (1<<23) | (((Sd)&1)<<22) | (0b11<<20) | (0b0001<<16) | ((((Sd)>>1)&15)<<12) | (0b101<<9) | (0<<8) | (0b01<<6) | (((Sm)&1)<<5) | (((Sm)>>1)&15) )
|
||||
|
||||
// Sqrt F64 Dd = - Dm
|
||||
#define VSQRT_F64(Dd, Dm) EMIT(c__ | (0b1110<<24) | (1<<23) | ((((Dd)>>4)&1)<<22) | (0b11<<20) | (0b0001<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | (0b11<<6) | ((((Dm)>>4)&1)<<5) | ((Dm)&15) )
|
||||
@@ -745,6 +855,8 @@ Op is 20-27
|
||||
#define VLD1_32(Dd, Rn) EMIT(Vxx1gen(1, ((Dd)>>4)&1, Rn, ((Dd)&0x0f), 0b0111, 2, 0, 15))
|
||||
// Load [Rn]! => Dd. Align is 4
|
||||
#define VLD1_32_W(Dd, Rn) EMIT(Vxx1gen(1, ((Dd)>>4)&1, Rn, ((Dd)&0x0f), 0b0111, 2, 0, 13))
|
||||
// Load [Rn]! => Dd. Align is 8
|
||||
#define VLD1_64_W(Dd, Rn) EMIT(Vxx1gen(1, ((Dd)>>4)&1, Rn, ((Dd)&0x0f), 0b0111, 3, 0, 13))
|
||||
// Load [Rn]! => Dd/Dd+1. Align is 4
|
||||
#define VLD1Q_32_W(Dd, Rn) EMIT(Vxx1gen(1, ((Dd)>>4)&1, Rn, ((Dd)&0x0f), 0b1010, 2, 0, 13))
|
||||
// Load [Rn, Rm]! => Dd/Dd+1. If Rm==15, no writeback, Rm ignored, else writeback Rn <- Rn+Rm. Align is 4
|
||||
@@ -766,6 +878,8 @@ Op is 20-27
|
||||
|
||||
// Store [Rn]! => Dd. Align is 4
|
||||
#define VST1_32_W(Dd, Rn) EMIT(Vxx1gen(0, ((Dd)>>4)&1, Rn, ((Dd)&0x0f), 0b0111, 2, 0, 13))
|
||||
// Store [Rn]! => Dd. Align is 8
|
||||
#define VST1_64_W(Dd, Rn) EMIT(Vxx1gen(0, ((Dd)>>4)&1, Rn, ((Dd)&0x0f), 0b0111, 3, 0, 13))
|
||||
// Store [Rn] => Dd/Dd+1. Align is 4
|
||||
#define VST1Q_32(Dd, Rn) EMIT(Vxx1gen(0, ((Dd)>>4)&1, Rn, ((Dd)&0x0f), 0b1010, 2, 0, 15))
|
||||
// Store [Rn]! => Dd/Dd+1. Align is 4
|
||||
@@ -804,6 +918,8 @@ Op is 20-27
|
||||
#define VMOV_igen(i, D, imm3, Vd, cmode, Q, op, imm4) (0b1111<<28 | 0b001<<25 | (i)<<24 | 1<<23 | (D)<<22 | (imm3)<<16 | (Vd)<<12 | (cmode)<<8 | (Q)<<6 | (op)<<5 | 1<<4 | (imm4))
|
||||
#define VMOV_8(Dd, imm) EMIT(VMOV_igen(((imm)>>7)&1, ((Dd)>>4)&1, ((imm)>>4)&7, (Dd)&15, 0b1110, 0, 0, (imm)&15))
|
||||
#define VMOVQ_8(Dd, imm) EMIT(VMOV_igen(((imm)>>7)&1, ((Dd)>>4)&1, ((imm)>>4)&7, (Dd)&15, 0b1110, 1, 0, (imm)&15))
|
||||
// Dd <= imm8 6bits duplicated 1bit -> 1byte
|
||||
#define VMOV_D64(Dd, imm) EMIT(VMOV_igen(((imm)>>7)&1, ((Dd)>>4)&1, ((imm)>>4)&7, (Dd)&15, 0b1110, 0, 1, (imm)&15))
|
||||
// Dd <= imm8 in high bits
|
||||
#define VMOV_H32(Dd, imm8) EMIT(VMOV_igen(((imm8)>>7)&1, ((Dd)>>4)&1, ((imm8)>>4)&7, (Dd)&15, 0b0110, 0, 0, (imm8)&15))
|
||||
// Dd <= imm8 in high bits
|
||||
@@ -814,19 +930,19 @@ Op is 20-27
|
||||
#define VMOVQ_H16(Dd, imm8) EMIT(VMOV_igen(((imm8)>>7)&1, ((Dd)>>4)&1, ((imm8)>>4)&7, (Dd)&15, 0b1010, 1, 0, (imm8)&15))
|
||||
|
||||
#define VLD1LANE_gen(D, Rn, Vd, size, index_align, Rm) (0b1111<<28 | 0b0100<<24 | 1<<23 | (D)<<22 | 0b10<<20 | (Rn)<<16 | (Vd)<<12 | (size)<<10 | (index_align)<<4 | (Rm))
|
||||
#define VLD1LANE_8(Dd, Rn, index) EMIT(VLD1LANE_gen(((Dd)>>4)&1, Rn, (Dd)&15, 0, (index)<<1, 15))
|
||||
#define VLD1LANE_16(Dd, Rn, index) EMIT(VLD1LANE_gen(((Dd)>>4)&1, Rn, (Dd)&15, 1, (index)<<2, 15))
|
||||
#define VLD1LANE_32(Dd, Rn, index) EMIT(VLD1LANE_gen(((Dd)>>4)&1, Rn, (Dd)&15, 2, (index)<<3, 15))
|
||||
#define VLD1LANE_8(Dd, Rn, index) EMIT(VLD1LANE_gen(((Dd)>>4)&1, (Rn), (Dd)&15, 0, (index)<<1, 15))
|
||||
#define VLD1LANE_16(Dd, Rn, index) EMIT(VLD1LANE_gen(((Dd)>>4)&1, (Rn), (Dd)&15, 1, (index)<<2, 15))
|
||||
#define VLD1LANE_32(Dd, Rn, index) EMIT(VLD1LANE_gen(((Dd)>>4)&1, (Rn), (Dd)&15, 2, (index)<<3, 15))
|
||||
|
||||
#define VLD1ALL_gen(D, Rn, Vd, size, T, a, Rm) (0b1111<<28 | 0b0100<<24 | 1<<23 | (D)<<22 | 0b10<<20 | (Rn)<<16 | (Vd)<<12 | 0b11<<10| (size)<<6 | (T)<<5 | (a)<<4 | (Rm))
|
||||
#define VLD1ALL_16(Dd, Rn) EMIT(VLD1ALL_gen(((Dd)>>4)&1, Rn, (Dd)&15, 1, 0, 0, 15))
|
||||
#define VLD1ALL_32(Dd, Rn) EMIT(VLD1ALL_gen(((Dd)>>4)&1, Rn, (Dd)&15, 2, 0, 0, 15))
|
||||
#define VLD1QALL_32(Dd, Rn) EMIT(VLD1ALL_gen(((Dd)>>4)&1, Rn, (Dd)&15, 2, 1, 0, 15))
|
||||
#define VLD1ALL_16(Dd, Rn) EMIT(VLD1ALL_gen(((Dd)>>4)&1, (Rn), (Dd)&15, 1, 0, 0, 15))
|
||||
#define VLD1ALL_32(Dd, Rn) EMIT(VLD1ALL_gen(((Dd)>>4)&1, (Rn), (Dd)&15, 2, 0, 0, 15))
|
||||
#define VLD1QALL_32(Dd, Rn) EMIT(VLD1ALL_gen(((Dd)>>4)&1, (Rn), (Dd)&15, 2, 1, 0, 15))
|
||||
|
||||
#define VST1LANE_gen(D, Rn, Vd, size, index_align, Rm) (0b1111<<28 | 0b0100<<24 | 1<<23 | (D)<<22 | 0b00<<20 | (Rn)<<16 | (Vd)<<12 | (size)<<10 | (index_align)<<4 | (Rm))
|
||||
#define VST1LANE_8(Dd, Rn, index) EMIT(VST1LANE_gen(((Dd)>>4)&1, Rn, (Dd)&15, 0, (index)<<1, 15))
|
||||
#define VST1LANE_16(Dd, Rn, index) EMIT(VST1LANE_gen(((Dd)>>4)&1, Rn, (Dd)&15, 1, (index)<<2, 15))
|
||||
#define VST1LANE_32(Dd, Rn, index) EMIT(VST1LANE_gen(((Dd)>>4)&1, Rn, (Dd)&15, 2, (index)<<3, 15))
|
||||
#define VST1LANE_8(Dd, Rn, index) EMIT(VST1LANE_gen(((Dd)>>4)&1, (Rn), (Dd)&15, 0, (index)<<1, 15))
|
||||
#define VST1LANE_16(Dd, Rn, index) EMIT(VST1LANE_gen(((Dd)>>4)&1, (Rn), (Dd)&15, 1, (index)<<2, 15))
|
||||
#define VST1LANE_32(Dd, Rn, index) EMIT(VST1LANE_gen(((Dd)>>4)&1, (Rn), (Dd)&15, 2, (index)<<3, 15))
|
||||
|
||||
#define VADD_gen(size, D, Vn, Vd, N, Q, M, Vm) (0b1111<<28 | 0b0010<<24 | 0<<23 | (D)<<22 | (size)<<20 | (Vn)<<16 | (Vd)<<12 | 0b1000<<8 | (N)<<7 | (Q)<<6 | (M)<<5 | 0<<4 | (Vm))
|
||||
#define VADD_8(Dd, Dn, Dm) EMIT(VADD_gen(0, ((Dd)>>4)&1, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
@@ -870,7 +986,7 @@ Op is 20-27
|
||||
#define VCEQQ_16(Dd, Dn, Dm) EMIT(VCEQ_I_gen(1, ((Dd)>>4)&1, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VCEQ_32(Dd, Dn, Dm) EMIT(VCEQ_I_gen(2, ((Dd)>>4)&1, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VCEQQ_32(Dd, Dn, Dm) EMIT(VCEQ_I_gen(2, ((Dd)>>4)&1, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VCEQ_64(Dd, Dn, Dm) EMIT(VCEQ_I_gen(3, ((Dd)>>4)&1, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
//#define VCEQ_64(Dd, Dn, Dm) EMIT(VCEQ_I_gen(3, ((Dd)>>4)&1, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15)) // doesn't exist
|
||||
#define VCEQQ_64(Dd, Dn, Dm) EMIT(VCEQ_I_gen(3, ((Dd)>>4)&1, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VCEQ_F_gen(sz, D, Vn, Vd, N, Q, M, Vm) (0b1111<<28 | 0b0010<<24 | 0<<23 | (D)<<22 | (sz)<<20 | (Vn)<<16 | (Vd)<<12 | 0b1110<<8 | (N)<<7 | (Q)<<6 | (M)<<5 | 0<<4 | (Vm))
|
||||
#define VCEQ_F32(Dd, Dn, Dm) EMIT(VCEQ_F_gen(0, ((Dd)>>4)&1, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
@@ -883,6 +999,7 @@ Op is 20-27
|
||||
#define VCEQQ_0_8(Dd, Dm) EMIT(VCEQ_0_gen(((Dd)>>4)&1, 0, (Dd)&15, 0, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VCEQQ_0_16(Dd, Dm) EMIT(VCEQ_0_gen(((Dd)>>4)&1, 1, (Dd)&15, 0, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VCEQQ_0_32(Dd, Dm) EMIT(VCEQ_0_gen(((Dd)>>4)&1, 2, (Dd)&15, 0, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VCEQQ_0_F32(Dd, Dm) EMIT(VCEQ_0_gen(((Dd)>>4)&1, 2, (Dd)&15, 1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#define VCGT_I_gen(U, D, size, Vn, Vd, N, Q, M, Vm) (0b1111<<28 | 0b001<<25 | (U)<<24 | 0<<23 | (D)<<22 | (size)<<20 | (Vn)<<16 | (Vd)<<12 | 0b0011<<8 | (N)<<7 | (Q)<<6 | (M)<<5 | (Vm))
|
||||
#define VCGT_U8(Dd, Dn, Dm) EMIT(VCGT_I_gen(1, ((Dd)>>4)&1, 0, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
@@ -1013,6 +1130,7 @@ Op is 20-27
|
||||
#define VMULL_U32_U16(Dd, Dn, Dm) EMIT(VMULL_NEON_gen(1, ((Dd)>>4)&1, 1, (Dn)&15, (Dd)&15, 0, ((Dn)>>4)&1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VMULL_S64_S32(Dd, Dn, Dm) EMIT(VMULL_NEON_gen(0, ((Dd)>>4)&1, 2, (Dn)&15, (Dd)&15, 0, ((Dn)>>4)&1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VMULL_U64_U32(Dd, Dn, Dm) EMIT(VMULL_NEON_gen(1, ((Dd)>>4)&1, 2, (Dn)&15, (Dd)&15, 0, ((Dn)>>4)&1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VMULL_P64(Dd, Dn, Dm) EMIT(VMULL_NEON_gen(0, ((Dd)>>4)&1, 2, (Dn)&15, (Dd)&15, 1, ((Dn)>>4)&1, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#define VMUL_NEON_gen(op, D, size, Vn, Vd, N, Q, M, Vm) (0b1111<<28 | 0b001<<25 | (op)<<24 | 0<<23 | (D)<<22 | (size)<<20 | (Vn)<<16 | (Vd)<<12 | 0b1001<<8 | (N)<<7 | (Q)<<6 | (M)<<5 | 1<<4 | (Vm))
|
||||
#define VMULQ_32(Dd, Dn, Dm) EMIT(VMUL_NEON_gen(0, ((Dd)>>4)&1, 0b10, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
@@ -1288,7 +1406,17 @@ Op is 20-27
|
||||
|
||||
#define VDUP_sgen(D, imm4, Vd, Q, M, Vm) (0b1111<<28 | 0b0011<<24 | 1<<23 | (D)<<22 | 0b11<<20 | (imm4)<<16 | (Vd)<<12 | 0b1100<<8 | (Q)<<6 | (M)<<5 | (Vm))
|
||||
// Dd <= Dup(Dm[x])
|
||||
#define VDUP_8(Dd, Dm, x) EMIT(VDUP_sgen(((Dd)>>4)&1, (((x)<<1)|0b1), (Dd)&15, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VDUPQ_8(Dd, Dm, x) EMIT(VDUP_sgen(((Dd)>>4)&1, (((x)<<1)|0b1), (Dd)&15, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VDUP_16(Dd, Dm, x) EMIT(VDUP_sgen(((Dd)>>4)&1, (((x)<<2)|0b10), (Dd)&15, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VDUPQ_16(Dd, Dm, x) EMIT(VDUP_sgen(((Dd)>>4)&1, (((x)<<2)|0b10), (Dd)&15, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VDUP_32(Dd, Dm, x) EMIT(VDUP_sgen(((Dd)>>4)&1, (((x)<<3)|0b100), (Dd)&15, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VDUPQ_32(Dd, Dm, x) EMIT(VDUP_sgen(((Dd)>>4)&1, (((x)<<3)|0b100), (Dd)&15, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VDUPQ_64(Dd, Dm, x) EMIT(VDUP_sgen(((Dd)>>4)&1, (((x)<<4)|0b1000), (Dd)&15, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#define VREV64_gen(D, size, Vd, Q, M, Vm) (0b1111<<28 | 0b0011<<24 | 1<<23 | (D)<<22 | 0b11<<20 | (size)<<18 | (Vd)<<12 | (Q)<<6 | (M)<<5 | (Vm))
|
||||
#define VREV64_32(Dd, Dm) EMIT(VREV64_gen(((Dd)>>4)&1, 0b10, (Dd)&15, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VREV64Q_32(Dd, Dm) EMIT(VREV64_gen(((Dd)>>4)&1, 0b10, (Dd)&15, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#define VABS_vgen(D, size, Vd, F, Q, M, Vm) (0b1111<<28 | 0b0011<<24 | 1<<23 | (D)<<22 | 0b11<<20 | (size)<<18 | 0b01<<16 | (Vd)<<12 | (F)<<10 | 0b110<<7 | (Q)<<6 | (M)<<5 | (Vm))
|
||||
#define VABS_S32(Dd, Dm) EMIT(VABS_vgen(((Dd)>>4)&1, 2, (Dd)&15, 0, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
@@ -1300,4 +1428,17 @@ Op is 20-27
|
||||
#define VABSQ_S8(Dd, Dm) EMIT(VABS_vgen(((Dd)>>4)&1, 0, (Dd)&15, 0, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VABSQ_F(Dd, Dm) EMIT(VABS_vgen(((Dd)>>4)&1, 2, (Dd)&15, 1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
// AES
|
||||
#define AESD_gen(D, size, Vd, M, Vm) (0b1111<<28 | 0b0011<<24 | 1<<23 | (D)<<22 | 0b11<<20 | (size)<<18 | (Vd)<<12 | 0b0110<<7 | 1<<6 | (M)<<5 | (Vm))
|
||||
#define AESD(Dd, Dm) EMIT(AESD_gen(((Dd)>>4)&1, 0, (Dd)&15, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#define AESE_gen(D, size, Vd, M, Vm) (0b1111<<28 | 0b0011<<24 | 1<<23 | (D)<<22 | 0b11<<20 | (size)<<18 | (Vd)<<12 | 0b0110<<7 | 0<<6 | (M)<<5 | (Vm))
|
||||
#define AESE(Dd, Dm) EMIT(AESE_gen(((Dd)>>4)&1, 0, (Dd)&15, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#define AESIMC_gen(D, size, Vd, M, Vm) (0b1111<<28 | 0b0011<<24 | 1<<23 | (D)<<22 | 0b11<<20 | (size)<<18 | (Vd)<<12 | 0b0111<<7 | 1<<6 | (M)<<5 | (Vm))
|
||||
#define AESIMC(Dd, Dm) EMIT(AESIMC_gen(((Dd)>>4)&1, 0, (Dd)&15, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#define AESMC_gen(D, size, Vd, M, Vm) (0b1111<<28 | 0b0011<<24 | 1<<23 | (D)<<22 | 0b11<<20 | (size)<<18 | (Vd)<<12 | 0b0111<<7 | 0<<6 | (M)<<5 | (Vm))
|
||||
#define AESMC(Dd, Dm) EMIT(AESMC_gen(((Dd)>>4)&1, 0, (Dd)&15, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#endif //__ARM_EMITTER_H__
|
||||
@@ -9,8 +9,11 @@
|
||||
.global arm_epilog
|
||||
arm_epilog:
|
||||
//update register -> emu
|
||||
//pop {r0}
|
||||
stm r0, {r4-r12,r14} // put back reg value in emu, including EIP (so r14 must be Flags now)
|
||||
// restore stack pointer
|
||||
ldr sp, [r0, #(8*4+2*4)]
|
||||
pop {r4, r5}
|
||||
str r4, [r0, #(8*4+2*4)] // put back old value
|
||||
//restore all used register
|
||||
vpop {d8-d15}
|
||||
pop {r4-r12, pc}
|
||||
@@ -20,6 +23,10 @@ arm_epilog:
|
||||
|
||||
.global arm_epilog_fast
|
||||
arm_epilog_fast:
|
||||
// restore stack pointer
|
||||
ldr sp, [r0, #(8*4+2*4)]
|
||||
pop {r4, r5}
|
||||
str r4, [r0, #(8*4+2*4)] // put back old value
|
||||
//restore all used register
|
||||
vpop {d8-d15}
|
||||
pop {r4-r12, pc}
|
||||
|
||||
@@ -179,7 +179,7 @@ INVALIDATE 1 1 1 1 0 0 1 1 1 <1> 1 1 <2>/=10 0 0 <4> 0 0 0 <2>/11 <2> 0 <4>
|
||||
INVALIDATE 1 1 1 1 0 0 1 1 1 <1> 1 1 <2>/=10 0 0 <4> 0 0 0 <2>/01 <2> 0 <4>
|
||||
INVALIDATE 1 1 1 1 0 0 1 1 1 <1> 1 1 <2>/=01 0 0 <4> 0 0 0 <2>/11 <2> 0 <4>
|
||||
INVALIDATE 1 1 1 1 0 0 1 1 1 <1> 1 1 <2>/=00 0 0 <4> 0 0 0 <2>/=11 <2> 0 <4>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 0 0 @<2> Q M 0 Vm VREV\%d16 &l&l param\<c>.\%d8 &l&l size\ <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 0 0 @<2> Q M 0 Vm VREV\%d64 &g&g param\<c>.\%d8 &l&l size\ <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 0 1 0 U Q M 0 Vm VPADDL<c>.<dt> <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 1 0 0 0 Q M 0 Vm VCLS<c>.<dt> <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 1 0 0 1 Q M 0 Vm VCLZ<c>.<dt> <Qd>, <Qm>
|
||||
@@ -335,9 +335,9 @@ NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 0 size 1 @<1> Rm @ param=1 char align[4
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 0 @<4> 1 1 0 1 @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 0 @<4> 1 1 1 1 @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 0 @<4> Rm @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 1 size @<1> @<1> 1 1 0 1 @ param2_1=1 char align[4] !@ %@ sprintf(align, ":%d", 16 << size)@ align[0] = '\0'@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[]}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 1 size @<1> @<1> 1 1 1 1 @ param2_1=1 char align[4] !@ %@ sprintf(align, ":%d", 16 << size)@ align[0] = '\0'@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[]}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 1 size @<1> @<1> Rm @ param2_1=1 char align[4] !@ %@ sprintf(align, ":%d", 16 << size)@ align[0] = '\0'@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[]}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 1 size @<1> @<1> 1 1 0 1 @ param2_1=1 char align[5] !@ %@ sprintf(align, ":%d", 16 << size)@ align[0] = '\0'@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[]}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 1 size @<1> @<1> 1 1 1 1 @ param2_1=1 char align[5] !@ %@ sprintf(align, ":%d", 16 << size)@ align[0] = '\0'@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[]}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 1 size @<1> @<1> Rm @ param2_1=1 char align[5] !@ %@ sprintf(align, ":%d", 16 << size)@ align[0] = '\0'@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[]}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> 1 1 0 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> 1 1 1 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> Rm @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\], <Rm>
|
||||
@@ -471,8 +471,10 @@ ARM_ cond 0 0 0 1 1 1 1 0 Rn Rd (1) (1) (1) (1) 1 0 0 1 Rt STREXH<c> <Rd>, <Rt>,
|
||||
ARM_ cond 0 0 0 1 1 1 1 1 Rn Rt (1) (1) (1) (1) 1 0 0 1 (1) (1) (1) (1) LDREXH<c> <Rt>, [<Rn>]
|
||||
ARM_ cond 0 0 1 0 0 0 0 S Rn Rd imm12 AND{S}<c> <Rd>, <Rn>, #<const>
|
||||
ARM_ cond 0 0 1 0 0 0 1 S Rn Rd imm12 EOR{S}<c> <Rd>, <Rn>, #<const>
|
||||
ARM_ cond 0 0 1 0 0 1 0 0 1 1 1 1 Rd imm12 ADR<c> <Rd>, #-<const>
|
||||
ARM_ cond 0 0 1 0 0 1 0 S Rn Rd imm12 SUB{S}<c> <Rd>, <Rn>, #<const>
|
||||
ARM_ cond 0 0 1 0 0 1 1 S Rn Rd imm12 RSB{S}<c> <Rd>, <Rn>, #<const>
|
||||
ARM_ cond 0 0 1 0 1 0 0 0 1 1 1 1 Rd imm12 ADR<c> <Rd>, #<const>
|
||||
ARM_ cond 0 0 1 0 1 0 0 S Rn Rd imm12 ADD{S}<c> <Rd>, <Rn>, #<const>
|
||||
ARM_ cond 0 0 1 0 1 0 1 S Rn Rd imm12 ADC{S}<c> <Rd>, <Rn>, #<const>
|
||||
ARM_ cond 0 0 1 0 1 1 0 S Rn Rd imm12 SBC{S}<c> <Rd>, <Rn>, #<const>
|
||||
|
||||
+104
-10
@@ -16,7 +16,14 @@
|
||||
.global arm_lock_xchg
|
||||
.global arm_lock_storeifnull
|
||||
.global arm_lock_storeifref
|
||||
|
||||
.global arm_lock_storeifref2
|
||||
.global arm_lock_decifnot0b
|
||||
.global arm_lock_incb
|
||||
.global arm_lock_incif0b
|
||||
.global arm_lock_stored
|
||||
.global arm_lock_storeb
|
||||
.global arm_lock_storeif0b
|
||||
.global arm_lock_readb
|
||||
|
||||
arm_lock_read_b:
|
||||
// address is r0, return is r0
|
||||
@@ -83,33 +90,120 @@ arm_lock_xchg:
|
||||
bx lr
|
||||
|
||||
arm_lock_storeifnull:
|
||||
// address is r0, value is r1, r1 store to r0 only if [r0] is 0. return new [r0] value (so r1 or old value)
|
||||
// address is r0, value is r1, r1 store to r0 only if [r0] is 0. return old [r0] value
|
||||
// r0 needs to be aligned
|
||||
dmb ish
|
||||
ldrex r2, [r0]
|
||||
cmp r2, #0
|
||||
bne arm_lock_storeifnull_exit
|
||||
mov r2, r1
|
||||
strex r3, r2, [r0]
|
||||
strex r3, r1, [r0]
|
||||
cmp r3, #1
|
||||
beq arm_lock_storeifnull
|
||||
arm_lock_storeifnull_exit:
|
||||
mov r0, r2
|
||||
dmb ish
|
||||
bx lr
|
||||
|
||||
arm_lock_storeifref2:
|
||||
dmb ish
|
||||
arm_lock_storeifref2_loop:
|
||||
// address is r0, value is r1, r1 store to r0 only if [r0] is r2. return old [r0] value (so r2 or old value)
|
||||
ldrex r3, [r0]
|
||||
cmp r3, r2
|
||||
movne r0, r3
|
||||
bne arm_lock_storeifref2_exit
|
||||
strex r3, r1, [r0]
|
||||
cmp r3, #1
|
||||
beq arm_lock_storeifref_loop
|
||||
mov r0, r2
|
||||
arm_lock_storeifref2_exit:
|
||||
dmb ish
|
||||
bx lr
|
||||
|
||||
arm_lock_storeifref:
|
||||
push {r4}
|
||||
dmb ish
|
||||
arm_lock_storeifref_loop:
|
||||
// address is r0, value is r1, r1 store to r0 only if [r0] is r2. return new [r0] value (so r1 or old value)
|
||||
ldrex r3, [r0]
|
||||
cmp r3, r2
|
||||
movne r0, r3
|
||||
bne arm_lock_storeifref_exit
|
||||
mov r3, r1
|
||||
strex r4, r3, [r0]
|
||||
cmp r4, #1
|
||||
strex r3, r1, [r0]
|
||||
cmp r3, #1
|
||||
beq arm_lock_storeifref_loop
|
||||
mov r0, r1
|
||||
arm_lock_storeifref_exit:
|
||||
mov r0, r3
|
||||
pop {r4}
|
||||
dmb ish
|
||||
bx lr
|
||||
|
||||
arm_lock_decifnot0b:
|
||||
dmb ish
|
||||
arm_lock_decifnot0b_0:
|
||||
ldrexb r1, [r0]
|
||||
cmp r1, #0
|
||||
subne r3, r1, #1
|
||||
moveq r3, r1
|
||||
strexb r2, r3, [r0]
|
||||
cmp r2, #1
|
||||
beq arm_lock_decifnot0b_0
|
||||
dmb ish
|
||||
mov r0, r1
|
||||
bx lr
|
||||
|
||||
arm_lock_incb:
|
||||
dmb ish
|
||||
arm_lock_incb_0:
|
||||
ldrexb r1, [r0]
|
||||
add r1, r1, #1
|
||||
strexb r2, r1, [r0]
|
||||
cmp r2, #1
|
||||
beq arm_lock_incb_0
|
||||
arm_lock_incb_exit:
|
||||
dmb ish
|
||||
bx lr
|
||||
|
||||
arm_lock_incif0b:
|
||||
dmb ish
|
||||
arm_lock_incif0b_0:
|
||||
ldrexb r1, [r0]
|
||||
cmp r1, #0
|
||||
addeq r3, r1, #1
|
||||
movne r3, r1
|
||||
strexb r2, r3, [r0]
|
||||
cmp r2, #1
|
||||
beq arm_lock_incif0b_0
|
||||
dmb ish
|
||||
mov r0, r1
|
||||
bx lr
|
||||
|
||||
arm_lock_stored:
|
||||
dmb ish
|
||||
str r1, [r0]
|
||||
dmb ish
|
||||
bx lr
|
||||
|
||||
arm_lock_storeb:
|
||||
dmb ish
|
||||
strb r1, [r0]
|
||||
dmb ish
|
||||
bx lr
|
||||
|
||||
arm_lock_storeif0b:
|
||||
dmb ish
|
||||
arm_lock_storeif0b_0:
|
||||
ldrexb r2, [r0]
|
||||
cmp r2, #0
|
||||
bne arm_lock_storeif0b_exit
|
||||
strexb r3, r1, [r0]
|
||||
cmp r3, #1
|
||||
beq arm_lock_storeif0b_0
|
||||
mov r2, #0
|
||||
dmb ish
|
||||
arm_lock_storeif0b_exit:
|
||||
mov r0, r2
|
||||
bx lr
|
||||
|
||||
arm_lock_readb:
|
||||
dmb ish
|
||||
ldrb r0, [r0]
|
||||
bx lr
|
||||
@@ -25,10 +25,34 @@ extern int arm_lock_write_dd(uint32_t a, uint32_t b, void* addr);
|
||||
// Atomically exchange value at [p] with val, return old p
|
||||
extern uintptr_t arm_lock_xchg(void* p, uintptr_t val);
|
||||
|
||||
// Atomically store value to [p] only if [p] is NULL. Return new [p] value (so val or old)
|
||||
// Atomically store value to [p] only if [p] is NULL. Return old [p] value
|
||||
extern void* arm_lock_storeifnull(void* p, void* val);
|
||||
|
||||
// Atomically store value to [p] only if [p] is ref. Return new [p] value (so val or old)
|
||||
extern void* arm_lock_storeifref(void* p, void* val, void* ref);
|
||||
|
||||
// Atomically store value to [p] only if [p] is ref. Return old [p] value
|
||||
extern void* arm_lock_storeifref2(void* p, void* val, void* ref);
|
||||
|
||||
// decrement atomicaly the byte at [p] (but only if p not 0). Return old [p] value
|
||||
extern int arm_lock_decifnot0b(void*p);
|
||||
|
||||
// increment atomicaly the byte at [p]
|
||||
extern void arm_lock_incb(void*p);
|
||||
|
||||
// increment atomicaly the byte at [p] only if it was 0. Return the old value of [p]
|
||||
extern int arm_lock_incif0b(void*p);
|
||||
|
||||
// atomic store (with memory barrier)
|
||||
extern void arm_lock_stored(void*p, uint32_t d);
|
||||
|
||||
// atomic store (with memory barrier)
|
||||
extern void arm_lock_storeb(void*p, uint8_t b);
|
||||
|
||||
// atomic store (with memory barrier) only if it was 0. Return the old value of [p]
|
||||
extern int arm_lock_storeif0b(void*p, uint8_t b);
|
||||
|
||||
// atomic load (with memory barrier)
|
||||
extern int arm_lock_readb(void*p);
|
||||
|
||||
#endif //__ARM_LOCK_HELPER__H__
|
||||
@@ -9,6 +9,7 @@
|
||||
.extern LinkNext
|
||||
|
||||
.global arm_next
|
||||
.4byte 0 // NULL pointer before arm64_next, for getDB
|
||||
arm_next:
|
||||
// emu is r0
|
||||
//stm r0, {r4-r12,r14} // don't put put back reg value in emu, faster but more tricky to debug
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/******************************************************************
|
||||
* File automatically generated by rebuild_printer.py (v1.2.0.05) *
|
||||
* File automatically generated by rebuild_printer.py (v1.2.0.06) *
|
||||
******************************************************************/
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
@@ -159,7 +159,7 @@ const char* print_register_list_fpu(uint8_t start, uint8_t size, uint8_t double_
|
||||
start = (start >> 4) + ((start & 0xF) << 1);
|
||||
}
|
||||
|
||||
char tmp[6];
|
||||
char tmp[7];
|
||||
for (int cur = start; cur < start + size - 1; ++cur) {
|
||||
sprintf(tmp, "%c%d, ", regChr, cur);
|
||||
strcat(ret, tmp);
|
||||
@@ -1164,7 +1164,7 @@ const char* arm_print(uint32_t opcode) {
|
||||
int m = ((opcode >> 5) & 1) << 4 | ((opcode >> 0) & 0xF);
|
||||
int param = (opcode >> 7) & 0x3;
|
||||
|
||||
sprintf(ret, "VREV%d.%d %s, %s", 16 << param, 8 << size, vecname[(q << 5) + 0x20 + d], vecname[(q << 5) + 0x20 + m]);
|
||||
sprintf(ret, "VREV%d.%d %s, %s", 64 >> param, 8 << size, vecname[(q << 5) + 0x20 + d], vecname[(q << 5) + 0x20 + m]);
|
||||
} else if ((opcode & 0xFFB30F10) == 0xF3B00200) {
|
||||
int u = (opcode >> 7) & 1;
|
||||
int size = (opcode >> 18) & 0x3;
|
||||
@@ -3049,7 +3049,7 @@ const char* arm_print(uint32_t opcode) {
|
||||
int param1_1 = (opcode >> 5) & 0x1;
|
||||
int param2_1 = (opcode >> 4) & 0x1;
|
||||
|
||||
char align[4];
|
||||
char align[5];
|
||||
if (param2_1 == 1) {
|
||||
sprintf(align, ":%d", 16 << size);
|
||||
} else {
|
||||
@@ -3064,7 +3064,7 @@ const char* arm_print(uint32_t opcode) {
|
||||
int param1_1 = (opcode >> 5) & 0x1;
|
||||
int param2_1 = (opcode >> 4) & 0x1;
|
||||
|
||||
char align[4];
|
||||
char align[5];
|
||||
if (param2_1 == 1) {
|
||||
sprintf(align, ":%d", 16 << size);
|
||||
} else {
|
||||
@@ -3080,7 +3080,7 @@ const char* arm_print(uint32_t opcode) {
|
||||
int param1_1 = (opcode >> 5) & 0x1;
|
||||
int param2_1 = (opcode >> 4) & 0x1;
|
||||
|
||||
char align[4];
|
||||
char align[5];
|
||||
if (param2_1 == 1) {
|
||||
sprintf(align, ":%d", 16 << size);
|
||||
} else {
|
||||
@@ -4197,6 +4197,12 @@ const char* arm_print(uint32_t opcode) {
|
||||
uint16_t imm12 = ((opcode >> 0) & 0xFFF);
|
||||
|
||||
sprintf(ret, "EOR%s%s %s, %s, #0x%x", (s ? "S" : ""), cond, regname[rd], regname[rn], print_modified_imm_ARM(imm12));
|
||||
} else if ((opcode & 0x0FFF0000) == 0x024F0000) {
|
||||
const char* cond = conds[(opcode >> 28) & 0xF];
|
||||
int rd = (opcode >> 12) & 0xF;
|
||||
uint16_t imm12 = ((opcode >> 0) & 0xFFF);
|
||||
|
||||
sprintf(ret, "ADR%s %s, #-0x%x", cond, regname[rd], print_modified_imm_ARM(imm12));
|
||||
} else if ((opcode & 0x0FE00000) == 0x02400000) {
|
||||
int s = (opcode >> 20) & 1;
|
||||
const char* cond = conds[(opcode >> 28) & 0xF];
|
||||
@@ -4213,6 +4219,12 @@ const char* arm_print(uint32_t opcode) {
|
||||
uint16_t imm12 = ((opcode >> 0) & 0xFFF);
|
||||
|
||||
sprintf(ret, "RSB%s%s %s, %s, #0x%x", (s ? "S" : ""), cond, regname[rd], regname[rn], print_modified_imm_ARM(imm12));
|
||||
} else if ((opcode & 0x0FFF0000) == 0x028F0000) {
|
||||
const char* cond = conds[(opcode >> 28) & 0xF];
|
||||
int rd = (opcode >> 12) & 0xF;
|
||||
uint16_t imm12 = ((opcode >> 0) & 0xFFF);
|
||||
|
||||
sprintf(ret, "ADR%s %s, #0x%x", cond, regname[rd], print_modified_imm_ARM(imm12));
|
||||
} else if ((opcode & 0x0FE00000) == 0x02800000) {
|
||||
int s = (opcode >> 20) & 1;
|
||||
const char* cond = conds[(opcode >> 28) & 0xF];
|
||||
|
||||
@@ -11,9 +11,12 @@ arm_prolog:
|
||||
//save all used register
|
||||
push {r4-r12, lr}
|
||||
vpush {d8-d15}
|
||||
// save Sp and setup stack for optionnal callret
|
||||
ldr r4, [r0, #(8*4+2*4)] // grab old value of xSPSave
|
||||
mov r5, #0
|
||||
push {r4-r5}
|
||||
str sp, [r0, #(8*4+2*4)]
|
||||
//setup emu -> register
|
||||
//push {r0}
|
||||
ldm r0, {r4-r12} // all 8 register in direct access, plus flags, no EIP (so r14 can be used as scratch)
|
||||
//TODO
|
||||
//jump to function
|
||||
bx r1
|
||||
+193
-303
@@ -20,6 +20,7 @@
|
||||
#include "dynablock_private.h"
|
||||
#include "dynarec_private.h"
|
||||
#include "elfloader.h"
|
||||
#include "bridge.h"
|
||||
#ifdef ARM
|
||||
#include "dynarec_arm.h"
|
||||
#include "arm_lock_helper.h"
|
||||
@@ -40,21 +41,37 @@ uint32_t X31_hash_code(void* addr, int len)
|
||||
return (uint32_t)h;
|
||||
}
|
||||
|
||||
dynablocklist_t* NewDynablockList(uintptr_t text, int textsz, int direct)
|
||||
dynablock_t* InvalidDynablock(dynablock_t* db, int need_lock)
|
||||
{
|
||||
if(!textsz) {
|
||||
printf_log(LOG_NONE, "Error, creating a NULL sized Dynablock\n");
|
||||
return NULL;
|
||||
if(db) {
|
||||
if(db->gone)
|
||||
return NULL; // already in the process of deletion!
|
||||
dynarec_log(LOG_DEBUG, "InvalidDynablock(%p), db->block=%p x86=%p:%p already gone=%d\n", db, db->block, db->x86_addr, db->x86_addr+db->x86_size-1, db->gone);
|
||||
if(need_lock)
|
||||
mutex_lock(&my_context->mutex_dyndump);
|
||||
// remove jumptable
|
||||
setJumpTableDefault(db->x86_addr);
|
||||
db->done = 0;
|
||||
db->gone = 1;
|
||||
if(need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
}
|
||||
dynablocklist_t* ret = (dynablocklist_t*)calloc(1, sizeof(dynablocklist_t));
|
||||
ret->text = text;
|
||||
ret->textsz = textsz;
|
||||
if(direct && textsz) {
|
||||
ret->direct = (dynablock_t**)calloc(textsz, sizeof(dynablock_t*));
|
||||
if(!ret->direct) {printf_log(LOG_NONE, "Warning, fail to create direct block for dynablock @%p\n", (void*)text);}
|
||||
return db;
|
||||
}
|
||||
|
||||
void FreeInvalidDynablock(dynablock_t* db, int need_lock)
|
||||
{
|
||||
if(db) {
|
||||
if(!db->gone)
|
||||
return; // already in the process of deletion!
|
||||
dynarec_log(LOG_DEBUG, "FreeInvalidDynablock(%p), db->block=%p x86=%p:%p already gone=%d\n", db, db->block, db->x86_addr, db->x86_addr+db->x86_size-1, db->gone);
|
||||
if(need_lock)
|
||||
mutex_lock(&my_context->mutex_dyndump);
|
||||
FreeDynarecMap((uintptr_t)db->actual_block);
|
||||
customFree(db);
|
||||
if(need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
}
|
||||
dynarec_log(LOG_DEBUG, "New Dynablocklist %p, from %p->%p\n", ret, (void*)text, (void*)(text+textsz));
|
||||
return ret;
|
||||
}
|
||||
|
||||
void FreeDynablock(dynablock_t* db, int need_lock)
|
||||
@@ -62,359 +79,223 @@ void FreeDynablock(dynablock_t* db, int need_lock)
|
||||
if(db) {
|
||||
if(db->gone)
|
||||
return; // already in the process of deletion!
|
||||
dynarec_log(LOG_DEBUG, "FreeDynablock(%p), db->block=%p x86=%p:%p father=%p, with %d son(s) already gone=%d\n", db, db->block, db->x86_addr, db->x86_addr+db->x86_size, db->father, db->sons_size, db->gone);
|
||||
dynarec_log(LOG_DEBUG, "FreeDynablock(%p), db->block=%p x86=%p:%p already gone=%d\n", db, db->block, db->x86_addr, db->x86_addr+db->x86_size-1, db->gone);
|
||||
if(need_lock)
|
||||
pthread_mutex_lock(&my_context->mutex_dyndump);
|
||||
db->done = 0;
|
||||
db->gone = 1;
|
||||
// remove from direct if there
|
||||
uintptr_t startdb = db->parent->text;
|
||||
uintptr_t enddb = db->parent->text + db->parent->textsz;
|
||||
if(db->parent->direct) {
|
||||
uintptr_t addr = (uintptr_t)db->x86_addr;
|
||||
if(addr>=startdb && addr<enddb)
|
||||
db->parent->direct[addr-startdb] = NULL;
|
||||
}
|
||||
mutex_lock(&my_context->mutex_dyndump);
|
||||
// remove jumptable
|
||||
setJumpTableDefault(db->x86_addr);
|
||||
// remove and free the sons
|
||||
for (int i=0; i<db->sons_size; ++i) {
|
||||
dynablock_t *son = (dynablock_t*)arm_lock_xchg(&db->sons[i], 0);
|
||||
FreeDynablock(son, 0);
|
||||
}
|
||||
// only the father free the DynarecMap
|
||||
if(!db->father) {
|
||||
dynarec_log(LOG_DEBUG, " -- FreeDyrecMap(%p, %d)\n", db->block, db->size);
|
||||
FreeDynarecMap(db, (uintptr_t)db->block, db->size);
|
||||
free(db->sons);
|
||||
free(db->instsize);
|
||||
}
|
||||
free(db);
|
||||
dynarec_log(LOG_DEBUG, " -- FreeDyrecMap(%p, %d)\n", db->actual_block, db->size);
|
||||
db->done = 0;
|
||||
db->gone = 1;
|
||||
if(db->previous)
|
||||
FreeInvalidDynablock(db->previous, 0);
|
||||
FreeDynarecMap((uintptr_t)db->actual_block);
|
||||
customFree(db);
|
||||
if(need_lock)
|
||||
pthread_mutex_unlock(&my_context->mutex_dyndump);
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
}
|
||||
}
|
||||
|
||||
void FreeDynablockList(dynablocklist_t** dynablocks)
|
||||
{
|
||||
if(!dynablocks)
|
||||
return;
|
||||
if(!*dynablocks)
|
||||
return;
|
||||
dynarec_log(LOG_DEBUG, "Free Dynablocklist %p, with Direct Blocks %p\n", *dynablocks, (*dynablocks)->direct);
|
||||
if((*dynablocks)->direct) {
|
||||
for (int i=0; i<(*dynablocks)->textsz; ++i) {
|
||||
if((*dynablocks)->direct[i] && !(*dynablocks)->direct[i]->father)
|
||||
FreeDynablock((*dynablocks)->direct[i], my_context?1:0);
|
||||
}
|
||||
free((*dynablocks)->direct);
|
||||
}
|
||||
(*dynablocks)->direct = NULL;
|
||||
|
||||
free(*dynablocks);
|
||||
*dynablocks = NULL;
|
||||
}
|
||||
|
||||
void MarkDynablock(dynablock_t* db)
|
||||
{
|
||||
if(db) {
|
||||
if(db->father)
|
||||
db = db->father; // mark only father
|
||||
if(db->need_test)
|
||||
return; // already done
|
||||
db->need_test = 1;
|
||||
setJumpTableDefault(db->x86_addr);
|
||||
for(int i=0; i<db->sons_size; ++i)
|
||||
setJumpTableDefault(db->sons[i]->x86_addr);
|
||||
dynarec_log(LOG_DEBUG, "MarkDynablock %p %p-%p\n", db, db->x86_addr, db->x86_addr+db->x86_size-1);
|
||||
if(!setJumpTableIfRef(db->x86_addr, db->jmpnext, db->block)) {
|
||||
dynablock_t* old = db;
|
||||
db = getDB((uintptr_t)old->x86_addr);
|
||||
if(!old->gone && db!=old) {
|
||||
printf_log(LOG_INFO, "Warning, couldn't mark block as dirty for %p, block=%p, current_block=%p\n", old->x86_addr, old, db);
|
||||
// the block is lost, need to invalidate it...
|
||||
old->gone = 1;
|
||||
old->done = 0;
|
||||
if(!db || db->previous)
|
||||
FreeInvalidDynablock(old, 1);
|
||||
else
|
||||
db->previous = old;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uintptr_t StartDynablockList(dynablocklist_t* db)
|
||||
{
|
||||
if(db)
|
||||
return db->text;
|
||||
return 0;
|
||||
}
|
||||
uintptr_t EndDynablockList(dynablocklist_t* db)
|
||||
{
|
||||
if(db)
|
||||
return db->text+db->textsz-1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int IntervalIntersects(uintptr_t start1, uintptr_t end1, uintptr_t start2, uintptr_t end2)
|
||||
static int IntervalIntersects(uintptr_t start1, uintptr_t end1, uintptr_t start2, uintptr_t end2)
|
||||
{
|
||||
if(start1 > end2 || start2 > end1)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void MarkDirectDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size)
|
||||
static int MarkedDynablock(dynablock_t* db)
|
||||
{
|
||||
if(!dynablocks)
|
||||
return;
|
||||
if(!dynablocks->direct)
|
||||
return;
|
||||
uintptr_t startdb = dynablocks->text;
|
||||
uintptr_t enddb = startdb + dynablocks->textsz -1;
|
||||
uintptr_t start = addr;
|
||||
uintptr_t end = addr+size-1;
|
||||
if(start<startdb)
|
||||
start = startdb;
|
||||
if(end>enddb)
|
||||
end = enddb;
|
||||
dynablock_t *db;
|
||||
if(end>startdb && start<enddb)
|
||||
for(uintptr_t i = start; i<end; ++i)
|
||||
if((db=dynablocks->direct[i-startdb]))
|
||||
if(IntervalIntersects((uintptr_t)db->x86_addr, (uintptr_t)db->x86_addr+db->x86_size-1, addr, addr+size+1))
|
||||
MarkDynablock(db);
|
||||
}
|
||||
|
||||
void FreeRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
if(!dynablocks)
|
||||
return;
|
||||
|
||||
if(dynablocks->direct) {
|
||||
dynablock_t* db;
|
||||
int ret;
|
||||
khint_t k;
|
||||
kh_dynablocks_t *blocks = kh_init(dynablocks);
|
||||
// copy in a temporary list
|
||||
if(dynablocks->direct) {
|
||||
uintptr_t startdb = dynablocks->text;
|
||||
uintptr_t enddb = startdb + dynablocks->textsz;
|
||||
uintptr_t start = addr;
|
||||
uintptr_t end = addr+size;
|
||||
if(start<startdb)
|
||||
start = startdb;
|
||||
if(end>enddb)
|
||||
end = enddb;
|
||||
if(end>startdb && start<enddb)
|
||||
for(uintptr_t i = start; i<end; ++i) {
|
||||
db = (dynablock_t*)arm_lock_xchg(&dynablocks->direct[i-startdb], 0);
|
||||
if(db) {
|
||||
if(db->father)
|
||||
db = db->father;
|
||||
if(db->parent==dynablocks) {
|
||||
k = kh_put(dynablocks, blocks, (uintptr_t)db, &ret);
|
||||
kh_value(blocks, k) = db;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// purge the list
|
||||
kh_foreach_value(blocks, db,
|
||||
FreeDynablock(db, 1);
|
||||
);
|
||||
kh_destroy(dynablocks, blocks);
|
||||
if(db) {
|
||||
if(getNeedTest((uintptr_t)db->x86_addr))
|
||||
return 1; // already done
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
void MarkRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size)
|
||||
|
||||
void MarkRangeDynablock(dynablock_t* db, uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
if(!dynablocks)
|
||||
// Mark will try to find *any* blocks that intersect the range to mark
|
||||
if(!db)
|
||||
return;
|
||||
if(dynablocks->direct) {
|
||||
uintptr_t new_addr = addr - dynablocks->maxsz;
|
||||
uintptr_t new_size = size + dynablocks->maxsz;
|
||||
MarkDirectDynablock(dynablocks, new_addr, new_size);
|
||||
// the blocks check before
|
||||
for(int idx=(new_addr)>>DYNAMAP_SHIFT; idx<(addr>>DYNAMAP_SHIFT); ++idx)
|
||||
MarkDirectDynablock(getDB(idx), new_addr, new_size);
|
||||
dynarec_log(LOG_DEBUG, "MarkRangeDynablock %p-%p .. startdb=%p, sizedb=%p\n", (void*)addr, (void*)addr+size-1, (void*)db->x86_addr, (void*)db->x86_size);
|
||||
if(IntervalIntersects((uintptr_t)db->x86_addr, (uintptr_t)db->x86_addr+db->x86_size-1, addr, addr+size+1))
|
||||
MarkDynablock(db);
|
||||
}
|
||||
|
||||
int FreeRangeDynablock(dynablock_t* db, uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
if(!db)
|
||||
return 1;
|
||||
|
||||
int need_lock = my_context?1:0;
|
||||
if(IntervalIntersects((uintptr_t)db->x86_addr, (uintptr_t)db->x86_addr+db->x86_size-1, addr, addr+size+1)) {
|
||||
FreeDynablock(db, need_lock);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
dynablock_t* FindDynablockDynablocklist(void* addr, kh_dynablocks_t* dynablocks)
|
||||
dynablock_t *AddNewDynablock(uintptr_t addr)
|
||||
{
|
||||
if(!dynablocks)
|
||||
return NULL;
|
||||
dynablock_t* db;
|
||||
kh_foreach_value(dynablocks, db,
|
||||
const uintptr_t s = (uintptr_t)db->block;
|
||||
const uintptr_t e = (uintptr_t)db->block+db->size;
|
||||
if((uintptr_t)addr>=s && (uintptr_t)addr<e)
|
||||
return db->father?db->father:db;
|
||||
)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static dynablocklist_t* getDBFromAddress(uintptr_t addr)
|
||||
{
|
||||
const int idx = (addr>>DYNAMAP_SHIFT);
|
||||
return getDB(idx);
|
||||
}
|
||||
|
||||
dynablock_t *AddNewDynablock(dynablocklist_t* dynablocks, uintptr_t addr, int* created)
|
||||
{
|
||||
if(!dynablocks) {
|
||||
dynarec_log(LOG_INFO, "Warning: Ask to create a dynablock with a NULL dynablocklist (addr=%p)\n", (void*)addr);
|
||||
*created = 0;
|
||||
dynablock_t* block;
|
||||
#if 0
|
||||
// check if memory as the correct flags
|
||||
int prot = getProtection(addr);
|
||||
if(!(prot&(PROT_EXEC|PROT_DYNAREC|PROT_DYNAREC_R))) {
|
||||
dynarec_log(LOG_VERBOSE, "Block asked on a memory with no execution flags 0x%02X\n", prot);
|
||||
return NULL;
|
||||
}
|
||||
if((addr<dynablocks->text) || (addr>=(dynablocks->text+dynablocks->textsz))) {
|
||||
// this should be useless
|
||||
//dynarec_log(LOG_INFO, "Warning: Refused to create a Direct Block that is out-of-bound: dynablocks=%p (%p:%p), addr=%p\n", dynablocks, (void*)(dynablocks->text), (void*)(dynablocks->text+dynablocks->textsz), (void*)addr);
|
||||
//*created = 0;
|
||||
//return NULL;
|
||||
return AddNewDynablock(getDBFromAddress(addr), addr, created);
|
||||
}
|
||||
dynablock_t* block = NULL;
|
||||
// first, check if it exist in direct access mode
|
||||
if(dynablocks->direct) {
|
||||
block = dynablocks->direct[addr-dynablocks->text];
|
||||
if(block) {
|
||||
dynarec_log(LOG_VERBOSE, "Block already exist in Direct Map\n");
|
||||
*created = 0;
|
||||
return block;
|
||||
}
|
||||
}
|
||||
|
||||
if (!*created)
|
||||
return block;
|
||||
|
||||
pthread_mutex_lock(&my_context->mutex_dyndump);
|
||||
if(!dynablocks->direct) {
|
||||
dynablock_t** p = (dynablock_t**)calloc(dynablocks->textsz, sizeof(dynablock_t*));
|
||||
if(arm_lock_storeifnull(&dynablocks->direct, p)!=p)
|
||||
free(p); // someone already create the direct array, too late...
|
||||
}
|
||||
|
||||
#endif
|
||||
// create and add new block
|
||||
dynarec_log(LOG_VERBOSE, "Ask for DynaRec Block creation @%p\n", (void*)addr);
|
||||
|
||||
block = (dynablock_t*)calloc(1, sizeof(dynablock_t));
|
||||
block->parent = dynablocks;
|
||||
dynablock_t* tmp = (dynablock_t*)arm_lock_storeifnull(&dynablocks->direct[addr-dynablocks->text], block);
|
||||
pthread_mutex_unlock(&my_context->mutex_dyndump);
|
||||
if(tmp != block) {
|
||||
// a block appeard!
|
||||
free(block);
|
||||
*created = 0;
|
||||
return tmp;
|
||||
}
|
||||
*created = 1;
|
||||
block = (dynablock_t*)customCalloc(1, sizeof(dynablock_t));
|
||||
return block;
|
||||
}
|
||||
|
||||
//TODO: move this to dynrec_arm.c and track allocated structure to avoid memory leak
|
||||
static __thread struct __jmp_buf_tag dynarec_jmpbuf;
|
||||
#ifdef ANDROID
|
||||
#define JUMPBUFF sigjmp_buf
|
||||
#else
|
||||
#define JUMPBUFF struct __jmp_buf_tag
|
||||
#endif
|
||||
static __thread JUMPBUFF dynarec_jmpbuf;
|
||||
#ifdef ANDROID
|
||||
#define DYN_JMPBUF dynarec_jmpbuf
|
||||
#else
|
||||
#define DYN_JMPBUF &dynarec_jmpbuf
|
||||
#endif
|
||||
|
||||
void cancelFillBlock()
|
||||
{
|
||||
longjmp(&dynarec_jmpbuf, 1);
|
||||
longjmp(DYN_JMPBUF, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
return NULL if block is not found / cannot be created.
|
||||
Don't create if create==0
|
||||
*/
|
||||
static dynablock_t* internalDBGetBlock(x86emu_t* emu, uintptr_t addr, uintptr_t filladdr, int create, dynablock_t* current, int need_lock)
|
||||
static dynablock_t* internalDBGetBlock(x86emu_t* emu, uintptr_t addr, uintptr_t filladdr, int create, int need_lock)
|
||||
{
|
||||
// try the quickest way first: get parent of current and check if ok!
|
||||
dynablocklist_t *dynablocks = NULL;
|
||||
dynablock_t* block = NULL;
|
||||
if(current) {
|
||||
dynablocks = current->parent;
|
||||
if(dynablocks && !(addr>=dynablocks->text && addr<(dynablocks->text+dynablocks->textsz)))
|
||||
dynablocks = NULL;
|
||||
}
|
||||
// nope, lets do the long way
|
||||
if(!dynablocks) {
|
||||
dynablocks = getDBFromAddress(addr);
|
||||
if(!dynablocks) {
|
||||
dynablocks = GetDynablocksFromAddress(emu->context, addr);
|
||||
if(!dynablocks)
|
||||
if(hasAlternate((void*)addr))
|
||||
return NULL;
|
||||
dynablock_t* block = getDB(addr);
|
||||
if(block || !create)
|
||||
return block;
|
||||
|
||||
if(need_lock) {
|
||||
if(box86_dynarec_wait) {
|
||||
mutex_lock(&my_context->mutex_dyndump);
|
||||
} else {
|
||||
if(mutex_trylock(&my_context->mutex_dyndump)) // FillBlock not available for now
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
// check direct first, without lock
|
||||
if(dynablocks->direct/* && (addr>=dynablocks->text) && (addr<(dynablocks->text+dynablocks->textsz))*/)
|
||||
if((block = dynablocks->direct[addr-dynablocks->text]))
|
||||
block = getDB(addr); // just in case
|
||||
if(block) {
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
return block;
|
||||
|
||||
int created = create;
|
||||
block = AddNewDynablock(dynablocks, addr, &created);
|
||||
if(!created)
|
||||
return block; // existing block...
|
||||
}
|
||||
}
|
||||
|
||||
block = AddNewDynablock(addr);
|
||||
|
||||
// fill the block
|
||||
block->x86_addr = (void*)addr;
|
||||
if(need_lock)
|
||||
pthread_mutex_lock(&my_context->mutex_dyndump);
|
||||
if(sigsetjmp(&dynarec_jmpbuf, 1)) {
|
||||
if(sigsetjmp(DYN_JMPBUF, 1)) {
|
||||
printf_log(LOG_INFO, "FillBlock at %p triggered a segfault, cancelling\n", (void*)addr);
|
||||
FreeDynablock(block, 0);
|
||||
if(need_lock)
|
||||
pthread_mutex_unlock(&my_context->mutex_dyndump);
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
return NULL;
|
||||
}
|
||||
void* ret = FillBlock(block, filladdr);
|
||||
if(need_lock)
|
||||
pthread_mutex_unlock(&my_context->mutex_dyndump);
|
||||
if(!ret) {
|
||||
dynarec_log(LOG_DEBUG, "Fillblock of block %p for %p returned an error\n", block, (void*)addr);
|
||||
void* old = (void*)arm_lock_storeifref(&dynablocks->direct[addr-dynablocks->text], 0, block);
|
||||
if(old!=block && old) { // put it back in place, strange things are happening here!
|
||||
dynarec_log(LOG_INFO, "Warning, a wild block appeared at %p: %p\n", (void*)addr, old);
|
||||
// Doing nothing else, the block has not been written
|
||||
}
|
||||
free(block);
|
||||
customFree(block);
|
||||
block = NULL;
|
||||
}
|
||||
// check size
|
||||
if(block && block->x86_size) {
|
||||
if(block) {
|
||||
int blocksz = block->x86_size;
|
||||
if(dynablocks->maxsz<blocksz) {
|
||||
dynablocks->maxsz = blocksz;
|
||||
for(int idx=(addr>>DYNAMAP_SHIFT)+1; idx<=((addr+blocksz)>>DYNAMAP_SHIFT); ++idx) {
|
||||
dynablocklist_t* dblist;
|
||||
if((dblist = getDB(idx)))
|
||||
if(dblist->maxsz<blocksz)
|
||||
dblist->maxsz = blocksz;
|
||||
}
|
||||
}
|
||||
//protectDB((uintptr_t)block->x86_addr, block->x86_size); // already protected in FillBlock
|
||||
// but check if it already need test
|
||||
if(block->need_test || (block->father && block->father->need_test))
|
||||
return NULL;
|
||||
if(blocksz>my_context->max_db_size)
|
||||
my_context->max_db_size = blocksz;
|
||||
// fill-in jumptable
|
||||
addJumpTableIfDefault(block->x86_addr, block->block);
|
||||
for(int i=0; i<block->sons_size; ++i)
|
||||
addJumpTableIfDefault(block->sons[i]->x86_addr, block->sons[i]->block);
|
||||
if(!addJumpTableIfDefault(block->x86_addr, block->dirty?block->jmpnext:block->block)) {
|
||||
FreeDynablock(block, 0);
|
||||
block = getDB(addr);
|
||||
MarkDynablock(block); // just in case...
|
||||
} else {
|
||||
if(block->x86_size)
|
||||
block->done = 1; // don't validate the block if the size is null, but keep the block
|
||||
}
|
||||
}
|
||||
if(need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
|
||||
dynarec_log(LOG_DEBUG, " --- DynaRec Block %s @%p:%p (%p, 0x%x bytes, with %d son(s))\n", created?"created":"recycled", (void*)addr, (void*)(addr+((block)?block->x86_size:0)), (block)?block->block:0, (block)?block->size:0, (block)?block->sons_size:0);
|
||||
dynarec_log(LOG_DEBUG, "%04d| --- DynaRec Block created @%p:%p (%p, 0x%x bytes)\n", GetTID(), (void*)addr, (void*)(addr+((block)?block->x86_size:1)-1), (block)?block->block:0, (block)?block->size:0);
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
dynablock_t* DBGetBlock(x86emu_t* emu, uintptr_t addr, int create, dynablock_t** current)
|
||||
dynablock_t* DBGetBlock(x86emu_t* emu, uintptr_t addr, int create)
|
||||
{
|
||||
dynablock_t *db = internalDBGetBlock(emu, addr, addr, create, *current, 1);
|
||||
if(db && db->done && db->block && (db->need_test || (db->father && db->father->need_test))) {
|
||||
if(pthread_mutex_trylock(&my_context->mutex_dyndump))
|
||||
return NULL;
|
||||
dynablock_t *father = db->father?db->father:db;
|
||||
uint32_t hash = (getProtection((uintptr_t)father->x86_addr)&PROT_READ)?X31_hash_code(father->x86_addr, father->x86_size):0;
|
||||
if(hash!=father->hash) {
|
||||
dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X/%X) with %d son(s) for %p\n", father, father->x86_addr, father->x86_addr+father->x86_size, hash, father->hash, father->sons_size, (void*)addr);
|
||||
// no more current if it gets invalidated too
|
||||
if(*current && father->x86_addr>=(*current)->x86_addr && (father->x86_addr+father->x86_size)<(*current)->x86_addr)
|
||||
*current = NULL;
|
||||
// Free father, it's now invalid!
|
||||
FreeDynablock(father, 0);
|
||||
if(isInHotPage(addr))
|
||||
return NULL;
|
||||
dynablock_t *db = internalDBGetBlock(emu, addr, addr, create, 1);
|
||||
if(db && db->done && db->block && getNeedTest(addr)) {
|
||||
if(db->always_test)
|
||||
sched_yield(); // just calm down...
|
||||
uint32_t hash = X31_hash_code(db->x86_addr, db->x86_size);
|
||||
int need_lock = mutex_trylock(&my_context->mutex_dyndump);
|
||||
if(hash!=db->hash) {
|
||||
db->done = 0; // invalidating the block
|
||||
dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X/%X, always_test:%d) for %p\n", db, db->x86_addr, db->x86_addr+db->x86_size-1, hash, db->hash, db->always_test, (void*)addr);
|
||||
// Free db, it's now invalid!
|
||||
dynablock_t* old = InvalidDynablock(db, need_lock);
|
||||
// start again... (will create a new block)
|
||||
db = internalDBGetBlock(emu, addr, addr, create, *current, 0);
|
||||
db = internalDBGetBlock(emu, addr, addr, create, need_lock);
|
||||
if(db) {
|
||||
if(db->previous)
|
||||
FreeInvalidDynablock(db->previous, need_lock);
|
||||
db->previous = old;
|
||||
} else
|
||||
FreeInvalidDynablock(old, need_lock);
|
||||
} else {
|
||||
father->need_test = 0;
|
||||
protectDB((uintptr_t)father->x86_addr, father->x86_size);
|
||||
dynarec_log(LOG_DEBUG, "Validating block %p from %p:%p (hash:%X, always_test:%d) for %p\n", db, db->x86_addr, db->x86_addr+db->x86_size-1, db->hash, db->always_test, (void*)addr);
|
||||
protectDB((uintptr_t)db->x86_addr, db->x86_size);
|
||||
// fill back jumptable
|
||||
addJumpTableIfDefault(father->x86_addr, father->block);
|
||||
for(int i=0; i<father->sons_size; ++i)
|
||||
addJumpTableIfDefault(father->sons[i]->x86_addr, father->sons[i]->block);
|
||||
if(isprotectedDB((uintptr_t)db->x86_addr, db->x86_size) && !db->always_test) {
|
||||
setJumpTableIfRef(db->x86_addr, db->block, db->jmpnext);
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&my_context->mutex_dyndump);
|
||||
if(!need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
}
|
||||
if(!db || !db->block || !db->done)
|
||||
emu->test.test = 0;
|
||||
return db;
|
||||
}
|
||||
|
||||
@@ -422,27 +303,36 @@ dynablock_t* DBAlternateBlock(x86emu_t* emu, uintptr_t addr, uintptr_t filladdr)
|
||||
{
|
||||
dynarec_log(LOG_DEBUG, "Creating AlternateBlock at %p for %p\n", (void*)addr, (void*)filladdr);
|
||||
int create = 1;
|
||||
dynablock_t *db = internalDBGetBlock(emu, addr, filladdr, create, NULL, 1);
|
||||
if(db && db->done && db->block && (db->need_test || (db->father && db->father->need_test))) {
|
||||
if(pthread_mutex_trylock(&my_context->mutex_dyndump))
|
||||
return NULL;
|
||||
dynablock_t *father = db->father?db->father:db;
|
||||
uint32_t hash = (getProtection((uintptr_t)father->x86_addr)&PROT_READ)?X31_hash_code(father->x86_addr, father->x86_size):0;
|
||||
if(hash!=father->hash) {
|
||||
dynarec_log(LOG_DEBUG, "Invalidating alt block %p from %p:%p (hash:%X/%X) with %d son(s) for %p\n", father, father->x86_addr, father->x86_addr+father->x86_size, hash, father->hash, father->sons_size, (void*)addr);
|
||||
// Free father, it's now invalid!
|
||||
FreeDynablock(father, 0);
|
||||
dynablock_t *db = internalDBGetBlock(emu, addr, filladdr, create, 1);
|
||||
if(db && db->done && db->block && getNeedTest(filladdr)) {
|
||||
if(db->always_test)
|
||||
sched_yield(); // just calm down...
|
||||
int need_lock = mutex_trylock(&my_context->mutex_dyndump);
|
||||
uint32_t hash = X31_hash_code(db->x86_addr, db->x86_size);
|
||||
if(hash!=db->hash) {
|
||||
db->done = 0; // invalidating the block
|
||||
dynarec_log(LOG_DEBUG, "Invalidating alt block %p from %p:%p (hash:%X/%X) for %p\n", db, db->x86_addr, db->x86_addr+db->x86_size, hash, db->hash, (void*)addr);
|
||||
// Free db, it's now invalid!
|
||||
dynablock_t* old = InvalidDynablock(db, need_lock);
|
||||
// start again... (will create a new block)
|
||||
db = internalDBGetBlock(emu, addr, filladdr, create, NULL, 0);
|
||||
db = internalDBGetBlock(emu, addr, filladdr, create, need_lock);
|
||||
if(db) {
|
||||
if(db->previous)
|
||||
FreeInvalidDynablock(db->previous, need_lock);
|
||||
db->previous = old;
|
||||
} else
|
||||
FreeInvalidDynablock(old, need_lock);
|
||||
} else {
|
||||
father->need_test = 0;
|
||||
protectDB((uintptr_t)father->x86_addr, father->x86_size);
|
||||
protectDB((uintptr_t)db->x86_addr, db->x86_size);
|
||||
// fill back jumptable
|
||||
addJumpTableIfDefault(father->x86_addr, father->block);
|
||||
for(int i=0; i<father->sons_size; ++i)
|
||||
addJumpTableIfDefault(father->sons[i]->x86_addr, father->sons[i]->block);
|
||||
if(isprotectedDB((uintptr_t)db->x86_addr, db->x86_size) && !db->always_test) {
|
||||
setJumpTableIfRef(db->x86_addr, db->block, db->jmpnext);
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&my_context->mutex_dyndump);
|
||||
if(!need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
}
|
||||
if(!db || !db->block || !db->done)
|
||||
emu->test.test = 0;
|
||||
return db;
|
||||
}
|
||||
@@ -1,36 +1,26 @@
|
||||
#ifndef __DYNABLOCK_PRIVATE_H_
|
||||
#define __DYNABLOCK_PRIVATE_H_
|
||||
|
||||
typedef struct dynablocklist_s dynablocklist_t;
|
||||
|
||||
typedef struct instsize_s {
|
||||
unsigned int x86:4;
|
||||
unsigned int nat:4;
|
||||
unsigned char x86:4;
|
||||
unsigned char nat:4;
|
||||
} instsize_t;
|
||||
|
||||
typedef struct dynablock_s {
|
||||
dynablocklist_t* parent;
|
||||
void* block;
|
||||
void* block; // block-sizeof(void*) == self
|
||||
void* actual_block; // the actual start of the block (so block-sizeof(void*))
|
||||
struct dynablock_s* previous; // a previous block that might need to be freed
|
||||
int size;
|
||||
void* x86_addr;
|
||||
uintptr_t x86_size;
|
||||
uint32_t hash;
|
||||
uint8_t need_test;
|
||||
uint8_t done;
|
||||
uint8_t gone;
|
||||
uint8_t dummy;
|
||||
uint8_t always_test;
|
||||
uint8_t dirty; // if need to be tested as soon as it's created
|
||||
int isize;
|
||||
dynablock_t** sons; // sons (kind-of dummy dynablock...)
|
||||
int sons_size;
|
||||
dynablock_t* father; // set only in the case of a son
|
||||
instsize_t* instsize;
|
||||
void* jmpnext; // a branch jmpnext code when block is marked
|
||||
} dynablock_t;
|
||||
|
||||
typedef struct dynablocklist_s {
|
||||
uintptr_t text;
|
||||
int textsz;
|
||||
int maxsz; // maxblock size (for this block or previous block)
|
||||
dynablock_t** direct; // direct mapping (waste of space, so the array is created at first write)
|
||||
} dynablocklist_t;
|
||||
|
||||
#endif //__DYNABLOCK_PRIVATE_H_
|
||||
+120
-146
@@ -20,6 +20,8 @@
|
||||
#include "dynablock.h"
|
||||
#include "dynablock_private.h"
|
||||
#include "bridge.h"
|
||||
#include "custommem.h"
|
||||
void x86test_check(x86emu_t* ref, uintptr_t ip);
|
||||
#endif
|
||||
|
||||
#ifdef ARM
|
||||
@@ -30,6 +32,7 @@ void arm_epilog_fast() EXPORTDYN;
|
||||
|
||||
#ifdef DYNAREC
|
||||
#ifdef HAVE_TRACE
|
||||
#include "elfloader.h"
|
||||
uintptr_t getX86Address(dynablock_t* db, uintptr_t arm_addr);
|
||||
#endif
|
||||
void* LinkNext(x86emu_t* emu, uintptr_t addr, void* x2)
|
||||
@@ -38,29 +41,36 @@ void* LinkNext(x86emu_t* emu, uintptr_t addr, void* x2)
|
||||
if(!addr) {
|
||||
x2-=8; // actual PC is 2 instructions ahead
|
||||
dynablock_t* db = FindDynablockFromNativeAddress(x2);
|
||||
printf_log(LOG_NONE, "Warning, jumping to NULL address from %p (db=%p, x86addr=%p)\n", x2, db, db?(void*)getX86Address(db, (uintptr_t)x2):NULL);
|
||||
void* x86addr = db?(void*)getX86Address(db, (uintptr_t)x2):NULL;
|
||||
const char* pcname = getAddrFunctionName((uintptr_t)x86addr);
|
||||
printf_log(LOG_NONE, "Warning, jumping to NULL address from %p (db=%p, x86addr=%p/%s)\n", x2, db, x86addr, pcname);
|
||||
}
|
||||
#endif
|
||||
dynablock_t* current = NULL;
|
||||
void * jblock;
|
||||
dynablock_t* block = DBGetBlock(emu, addr, 1, ¤t);
|
||||
dynablock_t* block = NULL;
|
||||
if(hasAlternate((void*)addr)) {
|
||||
printf_log(LOG_INFO, "Jmp address has alternate: %p", (void*)addr);
|
||||
addr = (uintptr_t)getAlternate((void*)addr);
|
||||
R_EIP = addr;
|
||||
printf_log(LOG_INFO, " -> %p\n", (void*)addr);
|
||||
block = DBGetBlock(emu, addr, 1);
|
||||
} else
|
||||
block = DBGetBlock(emu, addr, 1);
|
||||
if(!block) {
|
||||
// no block, let link table as is...
|
||||
if(hasAlternate((void*)addr)) {
|
||||
printf_log(LOG_INFO, "Jmp address has alternate: %p", (void*)addr);
|
||||
addr = (uintptr_t)getAlternate((void*)addr);
|
||||
R_EIP = addr;
|
||||
printf_log(LOG_INFO, " -> %p\n", (void*)addr);
|
||||
block = DBGetBlock(emu, addr, 1, ¤t);
|
||||
}
|
||||
if(!block) {
|
||||
#ifdef HAVE_TRACE
|
||||
dynablock_t* db = FindDynablockFromNativeAddress(x2);
|
||||
dynarec_log(LOG_INFO, "Warning, jumping to a no-block address %p from %p (db=%p, x86addr=%p)\n", (void*)addr, x2, db, db?(void*)getX86Address(db, (uintptr_t)x2):NULL);
|
||||
#endif
|
||||
//tableupdate(arm_epilog, addr, table);
|
||||
return arm_epilog;
|
||||
#ifdef HAVE_TRACE
|
||||
if(LOG_INFO<=box86_dynarec_log) {
|
||||
if(checkInHotPage(addr)) {
|
||||
dynarec_log(LOG_INFO, "Not trying to run a block from a Hotpage at %p\n", (void*)addr);
|
||||
} else {
|
||||
dynablock_t* db = FindDynablockFromNativeAddress(x2-4);
|
||||
elfheader_t* h = FindElfAddress(my_context, (uintptr_t)x2-4);
|
||||
dynarec_log(LOG_INFO, "Warning, jumping to a no-block address %p from %p (db=%p, x86addr=%p(elf=%s))\n", (void*)addr, x2-4, db, db?(void*)getX86Address(db, (uintptr_t)x2-4):NULL, h?ElfName(h):"(none)");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
//tableupdate(arm_epilog, addr, table);
|
||||
return arm_epilog;
|
||||
}
|
||||
if(!block->done) {
|
||||
// not finished yet... leave linker
|
||||
@@ -76,161 +86,125 @@ void* LinkNext(x86emu_t* emu, uintptr_t addr, void* x2)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ANDROID
|
||||
#define JUMPBUFF sigjmp_buf
|
||||
#else
|
||||
#define JUMPBUFF struct __jmp_buf_tag
|
||||
#endif
|
||||
|
||||
void DynaCall(x86emu_t* emu, uintptr_t addr)
|
||||
{
|
||||
// prepare setjump for signal handling
|
||||
emu_jmpbuf_t *ejb = NULL;
|
||||
int jmpbuf_reset = 0;
|
||||
if(emu->type == EMUTYPE_MAIN) {
|
||||
ejb = GetJmpBuf();
|
||||
if(!ejb->jmpbuf_ok) {
|
||||
ejb->emu = emu;
|
||||
ejb->jmpbuf_ok = 1;
|
||||
jmpbuf_reset = 1;
|
||||
int a;
|
||||
if((a=sigsetjmp((struct __jmp_buf_tag*)ejb->jmpbuf, 1))) {
|
||||
printf_log(LOG_DEBUG, "Setjmp DynaCall %d, fs=0x%x\n", a, ejb->emu->segs[_FS]);
|
||||
addr = R_EIP; // not sure if it should still be inside DynaCall!
|
||||
if(a==2)
|
||||
Run(emu, 1); // "single step" next instruction that is doing auto-smc
|
||||
}
|
||||
}
|
||||
uint32_t old_esp = R_ESP;
|
||||
uint32_t old_ebx = R_EBX;
|
||||
uint32_t old_edi = R_EDI;
|
||||
uint32_t old_esi = R_ESI;
|
||||
uint32_t old_ebp = R_EBP;
|
||||
uint32_t old_eip = R_EIP;
|
||||
// save defered flags
|
||||
defered_flags_t old_df = emu->df;
|
||||
uint32_t old_op1 = emu->op1;
|
||||
uint32_t old_op2 = emu->op2;
|
||||
uint32_t old_res = emu->res;
|
||||
// uc_link
|
||||
i386_ucontext_t* old_uc_link = emu->uc_link;
|
||||
emu->uc_link = NULL;
|
||||
|
||||
PushExit(emu);
|
||||
R_EIP = addr;
|
||||
emu->df = d_none;
|
||||
DynaRun(emu);
|
||||
emu->quit = 0; // reset Quit flags...
|
||||
emu->df = d_none;
|
||||
emu->uc_link = old_uc_link;
|
||||
if(emu->flags.quitonlongjmp && emu->flags.longjmp) {
|
||||
if(emu->flags.quitonlongjmp==1)
|
||||
emu->flags.longjmp = 0; // don't change anything because of the longjmp
|
||||
} else {
|
||||
// restore defered flags
|
||||
emu->df = old_df;
|
||||
emu->op1 = old_op1;
|
||||
emu->op2 = old_op2;
|
||||
emu->res = old_res;
|
||||
// and the old registers
|
||||
R_EBX = old_ebx;
|
||||
R_EDI = old_edi;
|
||||
R_ESI = old_esi;
|
||||
R_EBP = old_ebp;
|
||||
R_ESP = old_esp;
|
||||
R_EIP = old_eip; // and set back instruction pointer
|
||||
}
|
||||
#ifdef DYNAREC
|
||||
if(!box86_dynarec)
|
||||
#endif
|
||||
EmuCall(emu, addr);
|
||||
#ifdef DYNAREC
|
||||
else {
|
||||
uint32_t old_esp = R_ESP;
|
||||
uint32_t old_ebx = R_EBX;
|
||||
uint32_t old_edi = R_EDI;
|
||||
uint32_t old_esi = R_ESI;
|
||||
uint32_t old_ebp = R_EBP;
|
||||
uint32_t old_eip = R_EIP;
|
||||
PushExit(emu);
|
||||
R_EIP = addr;
|
||||
emu->df = d_none;
|
||||
dynablock_t* block = NULL;
|
||||
dynablock_t* current = NULL;
|
||||
while(!emu->quit) {
|
||||
block = DBGetBlock(emu, R_EIP, 1, ¤t);
|
||||
current = block;
|
||||
if(!block || !block->block || !block->done) {
|
||||
// no block, of block doesn't have DynaRec content (yet, temp is not null)
|
||||
// Use interpreter (should use single instruction step...)
|
||||
dynarec_log(LOG_DEBUG, "%04d|Calling Interpretor @%p, emu=%p\n", GetTID(), (void*)R_EIP, emu);
|
||||
Run(emu, 1);
|
||||
} else {
|
||||
dynarec_log(LOG_DEBUG, "%04d|Calling DynaRec Block @%p (%p) of %d x86 instructions (father=%p) emu=%p\n", GetTID(), (void*)R_EIP, block->block, block->isize ,block->father, emu);
|
||||
CHECK_FLAGS(emu);
|
||||
// block is here, let's run it!
|
||||
#ifdef ARM
|
||||
arm_prolog(emu, block->block);
|
||||
#endif
|
||||
}
|
||||
if(emu->fork) {
|
||||
int forktype = emu->fork;
|
||||
emu->quit = 0;
|
||||
emu->fork = 0;
|
||||
emu = x86emu_fork(emu, forktype);
|
||||
if(emu->type == EMUTYPE_MAIN) {
|
||||
ejb = GetJmpBuf();
|
||||
ejb->emu = emu;
|
||||
ejb->jmpbuf_ok = 1;
|
||||
jmpbuf_reset = 1;
|
||||
if(sigsetjmp((struct __jmp_buf_tag*)ejb->jmpbuf, 1)) {
|
||||
printf_log(LOG_DEBUG, "Setjmp inner DynaCall, fs=0x%x\n", ejb->emu->segs[_FS]);
|
||||
addr = R_EIP;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
emu->quit = 0; // reset Quit flags...
|
||||
emu->df = d_none;
|
||||
if(emu->quitonlongjmp && emu->longjmp) {
|
||||
emu->longjmp = 0; // don't change anything because of the longjmp
|
||||
} else {
|
||||
R_EBX = old_ebx;
|
||||
R_EDI = old_edi;
|
||||
R_ESI = old_esi;
|
||||
R_EBP = old_ebp;
|
||||
R_ESP = old_esp;
|
||||
R_EIP = old_eip; // and set back instruction pointer
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// clear the setjmp
|
||||
if(ejb && jmpbuf_reset)
|
||||
ejb->jmpbuf_ok = 0;
|
||||
}
|
||||
|
||||
int my_setcontext(x86emu_t* emu, void* ucp);
|
||||
int DynaRun(x86emu_t* emu)
|
||||
{
|
||||
// prepare setjump for signal handling
|
||||
emu_jmpbuf_t *ejb = NULL;
|
||||
#ifdef DYNAREC
|
||||
int jmpbuf_reset = 1;
|
||||
#endif
|
||||
if(emu->type == EMUTYPE_MAIN) {
|
||||
ejb = GetJmpBuf();
|
||||
if(!ejb->jmpbuf_ok) {
|
||||
ejb->emu = emu;
|
||||
ejb->jmpbuf_ok = 1;
|
||||
int a;
|
||||
#ifdef DYNAREC
|
||||
jmpbuf_reset = 1;
|
||||
#endif
|
||||
if((a=sigsetjmp((struct __jmp_buf_tag*)ejb->jmpbuf, 1))) {
|
||||
printf_log(LOG_DEBUG, "Setjmp DynaRun %d, fs=0x%x\n", a, ejb->emu->segs[_FS]);
|
||||
if(a==2)
|
||||
Run(emu, 1); // "single step" next instruction that is doing auto-smc
|
||||
JUMPBUFF jmpbuf[1] = {0};
|
||||
int skip = 0;
|
||||
JUMPBUFF *old_jmpbuf = emu->jmpbuf;
|
||||
uintptr_t old_savesp = emu->xSPSave;
|
||||
emu->flags.jmpbuf_ready = 0;
|
||||
|
||||
while(!(emu->quit)) {
|
||||
if(!emu->jmpbuf || (emu->flags.need_jmpbuf && emu->jmpbuf!=jmpbuf)) {
|
||||
emu->jmpbuf = jmpbuf;
|
||||
emu->old_savedsp = emu->xSPSave;
|
||||
emu->flags.jmpbuf_ready = 1;
|
||||
#ifdef ANDROID
|
||||
if((skip=sigsetjmp(*(JUMPBUFF*)emu->jmpbuf, 1)))
|
||||
#else
|
||||
if((skip=sigsetjmp(emu->jmpbuf, 1)))
|
||||
#endif
|
||||
{
|
||||
printf_log(LOG_DEBUG, "Setjmp DynaRun\n");
|
||||
#ifdef DYNAREC
|
||||
if(box86_dynarec_test) {
|
||||
if(emu->test.clean)
|
||||
x86test_check(emu, R_EIP);
|
||||
emu->test.clean = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef DYNAREC
|
||||
if(!box86_dynarec)
|
||||
#endif
|
||||
return Run(emu, 0);
|
||||
#ifdef DYNAREC
|
||||
else {
|
||||
dynablock_t* block = NULL;
|
||||
dynablock_t* current = NULL;
|
||||
while(!emu->quit) {
|
||||
block = DBGetBlock(emu, R_EIP, 1, ¤t);
|
||||
current = block;
|
||||
if(emu->flags.need_jmpbuf)
|
||||
emu->flags.need_jmpbuf = 0;
|
||||
|
||||
#ifndef DYNAREC
|
||||
Run(emu, 0);
|
||||
#else
|
||||
if(!box86_dynarec)
|
||||
Run(emu, 0);
|
||||
else {
|
||||
dynablock_t* block = (skip || ACCESS_FLAG(F_TF))?NULL:DBGetBlock(emu, R_EIP, 1);
|
||||
if(!block || !block->block || !block->done) {
|
||||
skip = 0;
|
||||
// no block, of block doesn't have DynaRec content (yet, temp is not null)
|
||||
// Use interpreter (should use single instruction step...)
|
||||
dynarec_log(LOG_DEBUG, "%04d|Running Interpretor @%p, emu=%p\n", GetTID(), (void*)R_EIP, emu);
|
||||
dynarec_log(LOG_DEBUG, "%04d|Running Interpreter @%p, emu=%p\n", GetTID(), (void*)R_EIP, emu);
|
||||
if(box86_dynarec_test)
|
||||
emu->test.clean = 0;
|
||||
Run(emu, 1);
|
||||
} else {
|
||||
dynarec_log(LOG_DEBUG, "%04d|Running DynaRec Block @%p (%p) of %d x86 insts (father=%p) emu=%p\n", GetTID(), (void*)R_EIP, block->block, block->isize, block->father, emu);
|
||||
dynarec_log(LOG_DEBUG, "%04d|Running DynaRec Block @%p (%p) of %d x86 insts (hash=0x%x) emu=%p\n", GetTID(), (void*)R_EIP, block->block, block->isize, block->hash, emu);
|
||||
// block is here, let's run it!
|
||||
#ifdef ARM
|
||||
arm_prolog(emu, block->block);
|
||||
#endif
|
||||
}
|
||||
if(emu->fork) {
|
||||
int forktype = emu->fork;
|
||||
emu->quit = 0;
|
||||
emu->fork = 0;
|
||||
emu = x86emu_fork(emu, forktype);
|
||||
if(emu->type == EMUTYPE_MAIN) {
|
||||
ejb = GetJmpBuf();
|
||||
ejb->emu = emu;
|
||||
ejb->jmpbuf_ok = 1;
|
||||
jmpbuf_reset = 1;
|
||||
if(sigsetjmp((struct __jmp_buf_tag*)ejb->jmpbuf, 1))
|
||||
printf_log(LOG_DEBUG, "Setjmp inner DynaRun, fs=0x%x\n", ejb->emu->segs[_FS]);
|
||||
}
|
||||
}
|
||||
if(emu->quit && emu->uc_link) {
|
||||
emu->quit = 0;
|
||||
my_setcontext(emu, emu->uc_link);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if(emu->flags.need_jmpbuf)
|
||||
emu->quit = 0;
|
||||
}
|
||||
// clear the setjmp
|
||||
if(ejb && jmpbuf_reset)
|
||||
ejb->jmpbuf_ok = 0;
|
||||
return 0;
|
||||
#endif
|
||||
emu->jmpbuf = old_jmpbuf;
|
||||
emu->xSPSave = old_savesp;
|
||||
}
|
||||
+378
-220
@@ -3,6 +3,7 @@
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86context.h"
|
||||
@@ -28,15 +29,15 @@ void printf_x86_instruction(zydis_dec_t* dec, instruction_x86_t* inst, const cha
|
||||
if(ip[0]==0xcc && ip[1]=='S' && ip[2]=='C') {
|
||||
uint32_t a = *(uint32_t*)(ip+3);
|
||||
if(a==0) {
|
||||
dynarec_log(LOG_NONE, "%s%p: Exit x86emu%s\n", (box86_dynarec_dump>1)?"\e[1m":"", (void*)ip, (box86_dynarec_dump>1)?"\e[m":"");
|
||||
dynarec_log(LOG_NONE, "%s%p: Exit x86emu%s\n", (box86_dynarec_dump>1)?"\e[01;33m":"", (void*)ip, (box86_dynarec_dump>1)?"\e[m":"");
|
||||
} else {
|
||||
dynarec_log(LOG_NONE, "%s%p: Native call to %p%s\n", (box86_dynarec_dump>1)?"\e[1m":"", (void*)ip, (void*)a, (box86_dynarec_dump>1)?"\e[m":"");
|
||||
dynarec_log(LOG_NONE, "%s%p: Native call to %p%s\n", (box86_dynarec_dump>1)?"\e[01;33m":"", (void*)ip, (void*)a, (box86_dynarec_dump>1)?"\e[m":"");
|
||||
}
|
||||
} else {
|
||||
if(dec) {
|
||||
dynarec_log(LOG_NONE, "%s%p: %s", (box86_dynarec_dump>1)?"\e[1m":"", ip, DecodeX86Trace(dec, inst->addr));
|
||||
dynarec_log(LOG_NONE, "%s%p: %s", (box86_dynarec_dump>1)?"\e[01;33m":"", ip, DecodeX86Trace(dec, inst->addr));
|
||||
} else {
|
||||
dynarec_log(LOG_NONE, "%s%p: ", (box86_dynarec_dump>1)?"\e[1m":"", ip);
|
||||
dynarec_log(LOG_NONE, "%s%p: ", (box86_dynarec_dump>1)?"\e[01;33m":"", ip);
|
||||
for(int i=0; i<inst->size; ++i) {
|
||||
dynarec_log(LOG_NONE, "%02X ", ip[i]);
|
||||
}
|
||||
@@ -60,12 +61,19 @@ void printf_x86_instruction(zydis_dec_t* dec, instruction_x86_t* inst, const cha
|
||||
void add_next(dynarec_arm_t *dyn, uintptr_t addr) {
|
||||
if(!box86_dynarec_bigblock)
|
||||
return;
|
||||
// exist?
|
||||
for(int i=0; i<dyn->next_sz; ++i)
|
||||
if(dyn->next[i]==addr)
|
||||
return;
|
||||
// put in a free slot
|
||||
for(int i=0; i<dyn->next_sz; ++i)
|
||||
if(!dyn->next[i]) {
|
||||
dyn->next[i] = addr;
|
||||
return;
|
||||
}
|
||||
// add slots
|
||||
if(dyn->next_sz == dyn->next_cap) {
|
||||
dyn->next_cap += 16;
|
||||
dyn->next = (uintptr_t*)realloc(dyn->next, dyn->next_cap*sizeof(uintptr_t));
|
||||
printf_log(LOG_NONE, "Warning, overallocating next\n");
|
||||
}
|
||||
dyn->next[dyn->next_sz++] = addr;
|
||||
}
|
||||
@@ -74,17 +82,32 @@ uintptr_t get_closest_next(dynarec_arm_t *dyn, uintptr_t addr) {
|
||||
uintptr_t best = 0;
|
||||
int i = 0;
|
||||
while((i<dyn->next_sz) && (best!=addr)) {
|
||||
if(dyn->next[i]<addr) { // remove the address, it's before current address
|
||||
memmove(dyn->next+i, dyn->next+i+1, (dyn->next_sz-i-1)*sizeof(uintptr_t));
|
||||
--dyn->next_sz;
|
||||
} else {
|
||||
if((dyn->next[i]<best) || !best)
|
||||
best = dyn->next[i];
|
||||
++i;
|
||||
if(dyn->next[i]) {
|
||||
if(dyn->next[i]<addr) { // remove the address, it's before current address
|
||||
dyn->next[i] = 0;
|
||||
} else {
|
||||
if((dyn->next[i]<best) || !best)
|
||||
best = dyn->next[i];
|
||||
}
|
||||
}
|
||||
++i;
|
||||
}
|
||||
return best;
|
||||
}
|
||||
void add_jump(dynarec_arm_t *dyn, int ninst) {
|
||||
// add slots
|
||||
if(dyn->jmp_sz == dyn->jmp_cap) {
|
||||
printf_log(LOG_NONE, "Warning, overallocating jmps\n");
|
||||
}
|
||||
dyn->jmps[dyn->jmp_sz++] = ninst;
|
||||
}
|
||||
int get_first_jump(dynarec_arm_t *dyn, int next) {
|
||||
for(int i=0; i<dyn->jmp_sz; ++i)
|
||||
if(dyn->insts[dyn->jmps[i]].x86.jmp == next)
|
||||
return dyn->jmps[i];
|
||||
return -2;
|
||||
}
|
||||
|
||||
#define PK(A) (*((uint8_t*)(addr+(A))))
|
||||
int is_nops(dynarec_arm_t *dyn, uintptr_t addr, int n)
|
||||
{
|
||||
@@ -92,7 +115,9 @@ int is_nops(dynarec_arm_t *dyn, uintptr_t addr, int n)
|
||||
return 1;
|
||||
if(PK(0)==0x90)
|
||||
return is_nops(dyn, addr+1, n-1);
|
||||
if(n>1 && PK(0)==0x66) // if opcode start with 0x66, and there is more after, than is *can* be a NOP
|
||||
if(n>1 && PK(0)==0x2E) // if opcode start with 0x2E, and there is more after, than this *can* be a NOP
|
||||
return is_nops(dyn, addr+1, n-1);
|
||||
if(n>1 && PK(0)==0x66) // if opcode start with 0x66, and there is more after, than this *can* be a NOP
|
||||
return is_nops(dyn, addr+1, n-1);
|
||||
if(n>2 && PK(0)==0x0f && PK(1)==0x1f && PK(2)==0x00)
|
||||
return is_nops(dyn, addr+3, n-3);
|
||||
@@ -206,7 +231,7 @@ int next_instruction(dynarec_arm_t *dyn, uintptr_t addr)
|
||||
nextop = PK(1);
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: // INC Ed
|
||||
case 1: //DEC Ed
|
||||
case 1: // DEC Ed
|
||||
case 2: // CALL Ed
|
||||
case 4: // JMP Ed
|
||||
case 6: // Push Ed
|
||||
@@ -231,216 +256,393 @@ int is_instructions(dynarec_arm_t *dyn, uintptr_t addr, int n)
|
||||
return (i==n)?1:0;
|
||||
}
|
||||
|
||||
instsize_t* addInst(instsize_t* insts, size_t* size, size_t* cap, int x86_size, int arm_size)
|
||||
void addInst(instsize_t* insts, size_t* size, int x86_size, int native_size)
|
||||
{
|
||||
// x86 instruction is <16 bytes
|
||||
int toadd;
|
||||
if(x86_size>arm_size)
|
||||
if(x86_size>native_size)
|
||||
toadd = 1 + x86_size/15;
|
||||
else
|
||||
toadd = 1 + arm_size/15;
|
||||
if((*size)+toadd>(*cap)) {
|
||||
*cap = (*size)+toadd;
|
||||
insts = (instsize_t*)realloc(insts, (*cap)*sizeof(instsize_t));
|
||||
}
|
||||
toadd = 1 + native_size/15;
|
||||
while(toadd) {
|
||||
if(x86_size>15)
|
||||
insts[*size].x86 = 15;
|
||||
else
|
||||
insts[*size].x86 = x86_size;
|
||||
x86_size -= insts[*size].x86;
|
||||
if(arm_size>15)
|
||||
if(native_size>15)
|
||||
insts[*size].nat = 15;
|
||||
else
|
||||
insts[*size].nat = arm_size;
|
||||
arm_size -= insts[*size].nat;
|
||||
insts[*size].nat = native_size;
|
||||
native_size -= insts[*size].nat;
|
||||
++(*size);
|
||||
--toadd;
|
||||
}
|
||||
return insts;
|
||||
}
|
||||
|
||||
static void recurse_mark_alive(dynarec_arm_t* dyn, int i)
|
||||
{
|
||||
if(dyn->insts[i].x86.alive)
|
||||
return;
|
||||
dyn->insts[i].x86.alive = 1;
|
||||
if(dyn->insts[i].x86.jmp && dyn->insts[i].x86.jmp_insts!=-1)
|
||||
recurse_mark_alive(dyn, dyn->insts[i].x86.jmp_insts);
|
||||
if(i<dyn->size-1 && dyn->insts[i].x86.has_next)
|
||||
recurse_mark_alive(dyn, i+1);
|
||||
}
|
||||
|
||||
static int sizePredecessors(dynarec_arm_t* dyn)
|
||||
{
|
||||
int pred_sz = 1; // to be safe
|
||||
// compute total size of predecessor to allocate the array
|
||||
// mark alive...
|
||||
recurse_mark_alive(dyn, 0);
|
||||
// first compute the jumps
|
||||
int jmpto;
|
||||
for(int i=0; i<dyn->size; ++i) {
|
||||
if(dyn->insts[i].x86.alive && dyn->insts[i].x86.jmp && ((jmpto=dyn->insts[i].x86.jmp_insts)!=-1)) {
|
||||
pred_sz++;
|
||||
dyn->insts[jmpto].pred_sz++;
|
||||
}
|
||||
}
|
||||
// remove "has_next" from orphan branch
|
||||
for(int i=0; i<dyn->size-1; ++i) {
|
||||
if(dyn->insts[i].x86.has_next && !dyn->insts[i+1].x86.alive)
|
||||
dyn->insts[i].x86.has_next = 0;
|
||||
}
|
||||
// second the "has_next"
|
||||
for(int i=0; i<dyn->size-1; ++i) {
|
||||
if(dyn->insts[i].x86.has_next) {
|
||||
pred_sz++;
|
||||
dyn->insts[i+1].pred_sz++;
|
||||
}
|
||||
}
|
||||
return pred_sz;
|
||||
}
|
||||
static void fillPredecessors(dynarec_arm_t* dyn)
|
||||
{
|
||||
// fill pred pointer
|
||||
int* p = dyn->predecessor;
|
||||
for(int i=0; i<dyn->size; ++i) {
|
||||
dyn->insts[i].pred = p;
|
||||
p += dyn->insts[i].pred_sz;
|
||||
dyn->insts[i].pred_sz=0; // reset size, it's reused to actually fill pred[]
|
||||
}
|
||||
// fill pred
|
||||
for(int i=0; i<dyn->size; ++i) if(dyn->insts[i].x86.alive) {
|
||||
if((i!=dyn->size-1) && dyn->insts[i].x86.has_next)
|
||||
dyn->insts[i+1].pred[dyn->insts[i+1].pred_sz++] = i;
|
||||
if(dyn->insts[i].x86.jmp && (dyn->insts[i].x86.jmp_insts!=-1)) {
|
||||
int j = dyn->insts[i].x86.jmp_insts;
|
||||
dyn->insts[j].pred[dyn->insts[j].pred_sz++] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// updateNeed goes backward, from last intruction to top
|
||||
static int updateNeed(dynarec_arm_t* dyn, int ninst, uint8_t need) {
|
||||
while (ninst>=0) {
|
||||
// need pending but instruction is only a subset: remove pend and use an X_ALL instead
|
||||
need |= dyn->insts[ninst].x86.need_after;
|
||||
if((need&X_PEND) && (dyn->insts[ninst].x86.state_flags==SF_SUBSET || dyn->insts[ninst].x86.state_flags==SF_SET || dyn->insts[ninst].x86.state_flags==SF_SET_NODF)) {
|
||||
need &=~X_PEND;
|
||||
need |= X_ALL;
|
||||
}
|
||||
if((need&X_PEND) && dyn->insts[ninst].x86.state_flags==SF_SUBSET_PENDING) {
|
||||
need |= X_ALL&~(dyn->insts[ninst].x86.set_flags);
|
||||
}
|
||||
dyn->insts[ninst].x86.gen_flags = need&dyn->insts[ninst].x86.set_flags;
|
||||
if((need&X_PEND) && (dyn->insts[ninst].x86.state_flags&SF_PENDING))
|
||||
dyn->insts[ninst].x86.gen_flags |= X_PEND;
|
||||
dyn->insts[ninst].x86.need_after = need;
|
||||
need = dyn->insts[ninst].x86.need_after&~dyn->insts[ninst].x86.gen_flags;
|
||||
|
||||
if(dyn->insts[ninst].x86.may_set)
|
||||
need |= dyn->insts[ninst].x86.gen_flags; // forward the flags
|
||||
else if((need&X_PEND) && (dyn->insts[ninst].x86.set_flags&SF_PENDING))
|
||||
need &=~X_PEND; // Consume X_PEND if relevant
|
||||
need |= dyn->insts[ninst].x86.use_flags;
|
||||
if(dyn->insts[ninst].x86.need_before == need)
|
||||
return ninst - 1;
|
||||
dyn->insts[ninst].x86.need_before = need;
|
||||
if(dyn->insts[ninst].x86.barrier&BARRIER_FLAGS) {
|
||||
need = need?X_PEND:0;
|
||||
}
|
||||
int ok = 0;
|
||||
for(int i=0; i<dyn->insts[ninst].pred_sz; ++i) {
|
||||
if(dyn->insts[ninst].pred[i] == ninst-1)
|
||||
ok = 1;
|
||||
else
|
||||
updateNeed(dyn, dyn->insts[ninst].pred[i], need);
|
||||
}
|
||||
--ninst;
|
||||
if(!ok)
|
||||
return ninst;
|
||||
}
|
||||
return ninst;
|
||||
}
|
||||
|
||||
void* current_helper = NULL;
|
||||
static int static_jmps[MAX_INSTS+2];
|
||||
static uintptr_t static_next[MAX_INSTS+2];
|
||||
static instruction_arm_t static_insts[MAX_INSTS+2] = {0};
|
||||
// TODO: ninst could be a uint16_t instead of an int, that could same some temp. memory
|
||||
|
||||
void CancelBlock(int need_lock)
|
||||
{
|
||||
if(need_lock)
|
||||
mutex_lock(&my_context->mutex_dyndump);
|
||||
dynarec_arm_t* helper = (dynarec_arm_t*)current_helper;
|
||||
if(helper) {
|
||||
if(helper->dynablock && helper->dynablock->actual_block) {
|
||||
FreeDynarecMap((uintptr_t)helper->dynablock->actual_block);
|
||||
helper->dynablock->actual_block = NULL;
|
||||
}
|
||||
}
|
||||
current_helper = NULL;
|
||||
if(need_lock)
|
||||
mutex_unlock(&my_context->mutex_dyndump);
|
||||
}
|
||||
|
||||
uintptr_t arm_pass0(dynarec_arm_t* dyn, uintptr_t addr);
|
||||
uintptr_t arm_pass1(dynarec_arm_t* dyn, uintptr_t addr);
|
||||
uintptr_t arm_pass2(dynarec_arm_t* dyn, uintptr_t addr);
|
||||
uintptr_t arm_pass3(dynarec_arm_t* dyn, uintptr_t addr);
|
||||
void arm_epilog();
|
||||
void arm_next();
|
||||
|
||||
__thread void* current_helper = NULL;
|
||||
|
||||
void CancelBlock()
|
||||
{
|
||||
dynarec_arm_t* helper = (dynarec_arm_t*)current_helper;
|
||||
current_helper = NULL;
|
||||
if(!helper)
|
||||
return;
|
||||
free(helper->next);
|
||||
free(helper->insts);
|
||||
free(helper->sons_x86);
|
||||
free(helper->sons_arm);
|
||||
if(helper->dynablock && helper->dynablock->block)
|
||||
FreeDynarecMap(helper->dynablock, (uintptr_t)helper->dynablock->block, helper->dynablock->size);
|
||||
void* CreateEmptyBlock(dynablock_t* block, uintptr_t addr) {
|
||||
block->isize = 0;
|
||||
block->done = 0;
|
||||
size_t sz = 8*sizeof(void*);
|
||||
void* actual_p = (void*)AllocDynarecMap(sz);
|
||||
void* p = actual_p + sizeof(void*);
|
||||
if(actual_p==NULL) {
|
||||
dynarec_log(LOG_INFO, "AllocDynarecMap(%p, %zu) failed, cancelling block\n", block, sz);
|
||||
CancelBlock(0);
|
||||
return NULL;
|
||||
}
|
||||
block->size = sz;
|
||||
block->actual_block = actual_p;
|
||||
block->block = p;
|
||||
block->jmpnext = p;
|
||||
*(dynablock_t**)actual_p = block;
|
||||
*(void**)(p+4*sizeof(void*)) = arm_epilog;
|
||||
CreateJmpNext(block->jmpnext, p+4*sizeof(void*));
|
||||
// all done...
|
||||
__clear_cache(actual_p, actual_p+sz); // need to clear the cache before execution...
|
||||
return block;
|
||||
}
|
||||
|
||||
void* FillBlock(dynablock_t* block, uintptr_t addr) {
|
||||
/*
|
||||
A Block must have this layout:
|
||||
|
||||
0x0000..0x0003 : dynablock_t* : self
|
||||
0x0004..4+4*n : actual Native instructions, (n is the total number)
|
||||
B .. B+3 : dynablock_t* : self (as part of JmpNext, that simulate another block)
|
||||
B+4 .. B+15 : 3 Native code for jmpnext (or jmp epilog in case of empty block)
|
||||
B+16 .. B+19 : jmpnext (or jmp_epilog) address
|
||||
B+20 .. B+31 : empty (in case an architecture needs more than 3 opcodes)
|
||||
B+32 .. B+32+sz : instsize (compressed array with each instruction lenght on x86 and native side)
|
||||
|
||||
*/
|
||||
dynarec_log(LOG_DEBUG, "Asked to Fill block %p with %p\n", block, (void*)addr);
|
||||
if(addr>=box86_nodynarec_start && addr<box86_nodynarec_end) {
|
||||
dynarec_log(LOG_DEBUG, "Asked to fill a block in fobidden zone\n");
|
||||
return CreateEmptyBlock(block, addr);
|
||||
}
|
||||
if(current_helper) {
|
||||
dynarec_log(LOG_DEBUG, "Cancelling dynarec FillBlock at %p as anothor one is going on\n", (void*)addr);
|
||||
return NULL;
|
||||
}
|
||||
if(!isJumpTableDefault((void*)addr)) {
|
||||
dynarec_log(LOG_DEBUG, "Asked to fill a block at %p, but JumpTable is not default\n", (void*)addr);
|
||||
return NULL;
|
||||
}
|
||||
// protect the 1st page
|
||||
protectDB(addr, 1);
|
||||
// init the helper
|
||||
dynarec_arm_t helper = {0};
|
||||
current_helper = &helper;
|
||||
helper.dynablock = block;
|
||||
helper.start = addr;
|
||||
uintptr_t start = addr;
|
||||
helper.cap = 64; // needs epilog handling
|
||||
helper.insts = (instruction_arm_t*)calloc(helper.cap, sizeof(instruction_arm_t));
|
||||
helper.cap = MAX_INSTS;
|
||||
helper.insts = static_insts;
|
||||
helper.jmps = static_jmps;
|
||||
helper.jmp_cap = MAX_INSTS;
|
||||
helper.next = static_next;
|
||||
helper.next_cap = MAX_INSTS;
|
||||
// pass 0, addresses, x86 jump addresses, overall size of the block
|
||||
uintptr_t end = arm_pass0(&helper, addr);
|
||||
// no need for next anymore
|
||||
free(helper.next);
|
||||
helper.next_sz = helper.next_cap = 0;
|
||||
helper.next = NULL;
|
||||
if(helper.abort) {
|
||||
if(box86_dynarec_dump || box86_dynarec_log)dynarec_log(LOG_NONE, "Abort dynablock on pass0\n");
|
||||
CancelBlock(0);
|
||||
return NULL;
|
||||
}
|
||||
// basic checks
|
||||
if(!helper.size) {
|
||||
dynarec_log(LOG_DEBUG, "Warning, null-sized dynarec block (%p)\n", (void*)addr);
|
||||
CancelBlock();
|
||||
return (void*)block;
|
||||
CancelBlock(0);
|
||||
return CreateEmptyBlock(block, addr);
|
||||
}
|
||||
if(!isprotectedDB(addr, 1)) {
|
||||
dynarec_log(LOG_INFO, "Warning, write on current page on pass0, aborting dynablock creation (%p)\n", (void*)addr);
|
||||
CancelBlock(0);
|
||||
return NULL;
|
||||
}
|
||||
// already protect the block and compute hash signature
|
||||
protectDB(addr, end-addr); //end is 1byte after actual end
|
||||
// protect the block of it goes over the 1st page
|
||||
if((addr&~box86_pagesize)!=(end&~box86_pagesize)) // need to protect some other pages too
|
||||
protectDB(addr, end-addr); //end is 1byte after actual end
|
||||
uint32_t hash = X31_hash_code((void*)addr, end-addr);
|
||||
// Compute flag_need, without taking into account any barriers
|
||||
uint32_t last_need = X_PEND;
|
||||
for(int i = helper.size; i-- > 0;) {
|
||||
last_need |= helper.insts[i].x86.use_flags;
|
||||
if((helper.insts[i].x86.state_flags == SF_SUBSET) && (last_need&X_PEND))
|
||||
last_need = (X_ALL & (~helper.insts[i].x86.set_flags) ) | helper.insts[i].x86.use_flags;
|
||||
if (last_need == (X_PEND | X_ALL)) {
|
||||
last_need = X_ALL;
|
||||
}
|
||||
helper.insts[i].x86.need_flags = last_need;
|
||||
if ((helper.insts[i].x86.set_flags) && !(helper.insts[i].x86.state_flags & SF_MAYSET)) {
|
||||
if (last_need & X_PEND) {
|
||||
last_need = (~helper.insts[i].x86.set_flags) & X_ALL;
|
||||
} else {
|
||||
last_need &= ~helper.insts[i].x86.set_flags;
|
||||
}
|
||||
}
|
||||
}
|
||||
// calculate barriers
|
||||
for(int i=0; i<helper.size; ++i)
|
||||
if(helper.insts[i].x86.jmp) {
|
||||
uintptr_t j = helper.insts[i].x86.jmp;
|
||||
if(j<start || j>=end) {
|
||||
helper.insts[i].x86.jmp_insts = -1;
|
||||
} else {
|
||||
// find jump address instruction
|
||||
int k=-1;
|
||||
for(int i2=0; i2<helper.size && k==-1; ++i2) {
|
||||
if(helper.insts[i2].x86.addr==j)
|
||||
k=i2;
|
||||
for(int ii=0; ii<helper.jmp_sz; ++ii) {
|
||||
int i = helper.jmps[ii];
|
||||
uintptr_t j = helper.insts[i].x86.jmp;
|
||||
helper.insts[i].x86.jmp_insts = -1;
|
||||
if(j<start || j>=end || j==helper.insts[i].x86.addr) {
|
||||
if(j==helper.insts[i].x86.addr) // if there is a loop on some opcode, make the block "always to tested"
|
||||
helper.always_test = 1;
|
||||
helper.insts[i].x86.need_after |= X_PEND;
|
||||
} else {
|
||||
// find jump address instruction
|
||||
int k=-1;
|
||||
int search = ((j>=helper.insts[0].x86.addr) && j<helper.insts[0].x86.addr+helper.isize)?1:0;
|
||||
int imin = 0;
|
||||
int imax = helper.size-1;
|
||||
int i2 = helper.size/2;
|
||||
// dichotomy search
|
||||
while(search) {
|
||||
if(helper.insts[i2].x86.addr == j) {
|
||||
k = i2;
|
||||
search = 0;
|
||||
} else if(helper.insts[i2].x86.addr>j) {
|
||||
imax = i2;
|
||||
i2 = (imax+imin)/2;
|
||||
} else {
|
||||
imin = i2;
|
||||
i2 = (imax+imin)/2;
|
||||
}
|
||||
if(k!=-1) // -1 if not found, mmm, probably wrong, exit anyway
|
||||
helper.insts[k].x86.barrier = 1;
|
||||
if(search && (imax-imin)<2) {
|
||||
search = 0;
|
||||
if(helper.insts[imin].x86.addr==j)
|
||||
k = imin;
|
||||
else if(helper.insts[imax].x86.addr==j)
|
||||
k = imax;
|
||||
}
|
||||
}
|
||||
/*for(int i2=0; i2<helper.size && k==-1; ++i2) {
|
||||
if(helper.insts[i2].x86.addr==j)
|
||||
k=i2;
|
||||
}*/
|
||||
if(k!=-1) {
|
||||
if(k!=-1 && !helper.insts[i].barrier_maybe)
|
||||
helper.insts[k].x86.barrier |= BARRIER_FULL;
|
||||
helper.insts[i].x86.jmp_insts = k;
|
||||
}
|
||||
}
|
||||
// check for the optionnal barriers now
|
||||
for(int i=helper.size-1; i>=0; --i) {
|
||||
if(helper.insts[i].x86.barrier==3)
|
||||
if(helper.insts[i].x86.jmp_insts == -1) {
|
||||
if(i==helper.size-1 || helper.insts[i+1].x86.barrier)
|
||||
helper.insts[i].x86.barrier=2; // nope, end of block or barrier just after
|
||||
else
|
||||
helper.insts[i].x86.barrier=0; // ok, no need for a barrier here after all
|
||||
} else
|
||||
helper.insts[i].x86.barrier=2;
|
||||
}
|
||||
// check to remove useless barrier, in case of jump when destination doesn't needs flags
|
||||
for(int i=helper.size-1; i>=0; --i) {
|
||||
if(helper.insts[i].x86.jmp
|
||||
&& helper.insts[i].x86.jmp_insts>=0
|
||||
&& helper.insts[helper.insts[i].x86.jmp_insts].x86.barrier==1) {
|
||||
int k = helper.insts[i].x86.jmp_insts;
|
||||
//TODO: optimize FPU barrier too
|
||||
if((!helper.insts[k].x86.need_flags)
|
||||
||(helper.insts[k].x86.set_flags==X_ALL
|
||||
&& helper.insts[k].x86.state_flags==SF_SET)
|
||||
||(helper.insts[k].x86.state_flags==SF_SET_PENDING)) {
|
||||
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "Removed barrier for inst %d\n", k);
|
||||
helper.insts[k].x86.barrier = 4; // remove barrier (keep FPU barrier, and still reset state flag)
|
||||
}
|
||||
}
|
||||
}
|
||||
// reset need_flags and compute again, now taking barrier into account (because barrier change use_flags)
|
||||
for(int i = helper.size; i-- > 0;) {
|
||||
if(helper.insts[i].x86.barrier==1)
|
||||
// immediate barrier
|
||||
helper.insts[i].x86.use_flags |= X_PEND;
|
||||
else if(helper.insts[i].x86.jmp
|
||||
&& helper.insts[i].x86.jmp_insts>=0
|
||||
) {
|
||||
if(helper.insts[helper.insts[i].x86.jmp_insts].x86.barrier==1)
|
||||
// jumpto barrier
|
||||
helper.insts[i].x86.use_flags |= X_PEND;
|
||||
else
|
||||
helper.insts[i].x86.use_flags |= helper.insts[helper.insts[i].x86.jmp_insts].x86.need_flags;
|
||||
}
|
||||
}
|
||||
for(int i = helper.size; i-- > 0;)
|
||||
helper.insts[i].x86.need_flags = 0;
|
||||
last_need = X_PEND;
|
||||
for(int i = helper.size; i-- > 0;) {
|
||||
helper.insts[i].x86.need_flags = last_need;
|
||||
if((helper.insts[i].x86.state_flags == SF_SUBSET) && (last_need&X_PEND))
|
||||
last_need = (X_ALL & (~helper.insts[i].x86.set_flags) ) | helper.insts[i].x86.use_flags;
|
||||
if ((helper.insts[i].x86.set_flags) && !(helper.insts[i].x86.state_flags & SF_MAYSET)) {
|
||||
if (last_need & X_PEND) {
|
||||
last_need = (~helper.insts[i].x86.set_flags) & X_ALL;
|
||||
} else {
|
||||
last_need &= ~helper.insts[i].x86.set_flags;
|
||||
}
|
||||
}
|
||||
last_need |= helper.insts[i].x86.use_flags;
|
||||
if (last_need == (X_PEND | X_ALL)) {
|
||||
last_need = X_ALL;
|
||||
// no need for next and jmps anymore
|
||||
helper.next_sz = helper.next_cap = 0;
|
||||
helper.next = NULL;
|
||||
helper.jmp_sz = helper.jmp_cap = 0;
|
||||
helper.jmps = NULL;
|
||||
// fill predecessors with the jump address
|
||||
int alloc_size = sizePredecessors(&helper);
|
||||
helper.predecessor = (int*)alloca(alloc_size*sizeof(int));
|
||||
fillPredecessors(&helper);
|
||||
|
||||
int pos = helper.size;
|
||||
while (pos>=0)
|
||||
pos = updateNeed(&helper, pos, 0);
|
||||
// remove fpu stuff on non-executed code
|
||||
for(int i=1; i<helper.size-1; ++i)
|
||||
if(!helper.insts[i].pred_sz) {
|
||||
int ii = i;
|
||||
while(ii<helper.size && !helper.insts[ii].pred_sz)
|
||||
fpu_reset_ninst(&helper, ii++);
|
||||
i = ii;
|
||||
}
|
||||
|
||||
// pass 1, float optimisations, first pass for flags
|
||||
arm_pass1(&helper, addr);
|
||||
if(helper.abort) {
|
||||
if(box86_dynarec_dump || box86_dynarec_log)dynarec_log(LOG_NONE, "Abort dynablock on pass0\n");
|
||||
CancelBlock(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// pass 1, float optimisations
|
||||
arm_pass1(&helper, addr);
|
||||
|
||||
// pass 2, instruction size
|
||||
arm_pass2(&helper, addr);
|
||||
if(helper.abort) {
|
||||
if(box86_dynarec_dump || box86_dynarec_log)dynarec_log(LOG_NONE, "Abort dynablock on pass0\n");
|
||||
CancelBlock(0);
|
||||
return NULL;
|
||||
}
|
||||
// ok, now allocate mapped memory, with executable flag on
|
||||
int sz = helper.arm_size;
|
||||
void* p = (void*)AllocDynarecMap(block, sz);
|
||||
if(p==NULL) {
|
||||
dynarec_log(LOG_DEBUG, "AllocDynarecMap(%p, %d) failed, cancelling block\n", block, sz);
|
||||
CancelBlock();
|
||||
size_t insts_rsize = (helper.insts_size+2)*sizeof(instsize_t);
|
||||
insts_rsize = (insts_rsize+7)&~7; // round the size...
|
||||
size_t arm_size = (helper.arm_size+7)&~7; // round the size...
|
||||
// ok, now allocate mapped memory, with executable flag on
|
||||
size_t sz = sizeof(void*) + arm_size + 8*sizeof(void*) + insts_rsize;
|
||||
// dynablock_t* block (arm insts) jmpnext code instsize
|
||||
void* actual_p = (void*)AllocDynarecMap(sz);
|
||||
void* p = (void*)(((uintptr_t)actual_p) + sizeof(void*));
|
||||
void* next = p + arm_size;
|
||||
void* instsize = next + 8*sizeof(void*);
|
||||
if(actual_p==NULL) {
|
||||
dynarec_log(LOG_INFO, "AllocDynarecMap(%p, %zu) failed, cancelling block\n", block, sz);
|
||||
CancelBlock(0);
|
||||
return NULL;
|
||||
}
|
||||
helper.block = p;
|
||||
block->actual_block = actual_p;
|
||||
helper.arm_start = (uintptr_t)p;
|
||||
if(helper.sons_size) {
|
||||
helper.sons_x86 = (uintptr_t*)calloc(helper.sons_size, sizeof(uintptr_t));
|
||||
helper.sons_arm = (void**)calloc(helper.sons_size, sizeof(void*));
|
||||
}
|
||||
// pass 3, emit (log emit arm opcode)
|
||||
helper.jmp_next = (uintptr_t)next+sizeof(void*);
|
||||
helper.instsize = (instsize_t*)instsize;
|
||||
*(dynablock_t**)actual_p = block;
|
||||
// pass 3, emit (log emit native opcode)
|
||||
if(box86_dynarec_dump) {
|
||||
dynarec_log(LOG_NONE, "%s%04d|Emitting %d bytes for %d x86 bytes", (box86_dynarec_dump>1)?"\e[01;36m":"", GetTID(), helper.arm_size, helper.isize);
|
||||
printFunctionAddr(helper.start, " => ");
|
||||
dynarec_log(LOG_NONE, "%s\n", (box86_dynarec_dump>1)?"\e[m":"");
|
||||
}
|
||||
size_t oldarmsize = helper.arm_size;
|
||||
size_t oldinstsize = helper.insts_size;
|
||||
helper.arm_size = 0;
|
||||
helper.insts_size = 0; // reset
|
||||
arm_pass3(&helper, addr);
|
||||
if(sz!=helper.arm_size) {
|
||||
printf_log(LOG_NONE, "BOX86: Warning, size difference in block between pass2 (%d) & pass3 (%d)!\n", sz, helper.arm_size);
|
||||
if(helper.abort) {
|
||||
if(box86_dynarec_dump || box86_dynarec_log)dynarec_log(LOG_NONE, "Abort dynablock on pass0\n");
|
||||
CancelBlock(0);
|
||||
return NULL;
|
||||
}
|
||||
// keep size of instructions for signal handling
|
||||
block->instsize = instsize;
|
||||
// ok, free the helper now
|
||||
helper.insts = NULL;
|
||||
helper.instsize = NULL;
|
||||
helper.predecessor = NULL;
|
||||
block->size = sz;
|
||||
block->isize = helper.size;
|
||||
block->block = p;
|
||||
block->jmpnext = next+sizeof(void*);
|
||||
block->always_test = helper.always_test;
|
||||
block->dirty = block->always_test;
|
||||
*(dynablock_t**)next = block;
|
||||
*(void**)(next+5*sizeof(void*)) = arm_next;
|
||||
CreateJmpNext(block->jmpnext, next+5*sizeof(void*));
|
||||
//block->x86_addr = (void*)start;
|
||||
block->x86_size = end-start;
|
||||
// all done...
|
||||
__clear_cache(actual_p, actual_p+sz); // need to clear the cache before execution...
|
||||
block->hash = X31_hash_code(block->x86_addr, block->x86_size);
|
||||
// Check if something changed, to abbort if it as
|
||||
if((block->hash != hash)) {
|
||||
dynarec_log(LOG_DEBUG, "Warning, a block changed while being processed hash(%p:%zu)=%x/%x\n", block->x86_addr, block->x86_size, block->hash, hash);
|
||||
CancelBlock(0);
|
||||
return NULL;
|
||||
}
|
||||
if((oldarmsize!=helper.arm_size)) {
|
||||
printf_log(LOG_NONE, "BOx86: Warning, size difference in block between pass2 (%zu) & pass3 (%zu)!\n", sz, helper.arm_size);
|
||||
uint8_t *dump = (uint8_t*)helper.start;
|
||||
printf_log(LOG_NONE, "Dump of %d x86 opcodes:\n", helper.size);
|
||||
for(int i=0; i<helper.size; ++i) {
|
||||
@@ -450,71 +652,27 @@ dynarec_log(LOG_DEBUG, "Asked to Fill block %p with %p\n", block, (void*)addr);
|
||||
printf_log(LOG_NONE, "\t%d -> %d\n", helper.insts[i].size2, helper.insts[i].size);
|
||||
}
|
||||
printf_log(LOG_NONE, " ------------\n");
|
||||
}
|
||||
// all done...
|
||||
__clear_cache(p, p+sz); // need to clear the cache before execution...
|
||||
// keep size of instructions for signal handling
|
||||
{
|
||||
size_t cap = 1;
|
||||
for(int i=0; i<helper.size; ++i)
|
||||
cap += 1 + ((helper.insts[i].x86.size>helper.insts[i].size)?helper.insts[i].x86.size:helper.insts[i].size)/15;
|
||||
size_t size = 0;
|
||||
block->instsize = (instsize_t*)calloc(cap, sizeof(instsize_t));
|
||||
for(int i=0; i<helper.size; ++i)
|
||||
block->instsize = addInst(block->instsize, &size, &cap, helper.insts[i].x86.size, helper.insts[i].size/4);
|
||||
block->instsize = addInst(block->instsize, &size, &cap, 0, 0); // add a "end of block" mark, just in case
|
||||
}
|
||||
// ok, free the helper now
|
||||
free(helper.insts);
|
||||
helper.insts = NULL;
|
||||
free(helper.next);
|
||||
helper.next = NULL;
|
||||
block->size = sz;
|
||||
block->isize = helper.size;
|
||||
block->block = p;
|
||||
block->need_test = 0;
|
||||
//block->x86_addr = (void*)start;
|
||||
block->x86_size = end-start;
|
||||
if(box86_dynarec_largest<block->x86_size)
|
||||
box86_dynarec_largest = block->x86_size;
|
||||
block->hash = X31_hash_code(block->x86_addr, block->x86_size);
|
||||
// Check if something changed, to abbort if it as
|
||||
if(block->hash != hash) {
|
||||
dynarec_log(LOG_INFO, "Warning, a block changed while beeing processed hash(%p:%d)=%x/%x\n", block->x86_addr, block->x86_size, block->hash, hash);
|
||||
CancelBlock();
|
||||
CancelBlock(0);
|
||||
return NULL;
|
||||
}
|
||||
// fill sons if any
|
||||
dynablock_t** sons = NULL;
|
||||
int sons_size = 0;
|
||||
if(helper.sons_size) {
|
||||
sons = (dynablock_t**)calloc(helper.sons_size, sizeof(dynablock_t*));
|
||||
for (int i=0; i<helper.sons_size; ++i) {
|
||||
int created = 1;
|
||||
dynablock_t *son = AddNewDynablock(block->parent, helper.sons_x86[i], &created);
|
||||
if(created) { // avoid breaking a working block!
|
||||
son->block = helper.sons_arm[i];
|
||||
son->x86_addr = (void*)helper.sons_x86[i];
|
||||
son->x86_size = end-helper.sons_x86[i];
|
||||
if(!son->x86_size) {printf_log(LOG_NONE, "Warning, son with null x86 size! (@%p / ARM=%p)", son->x86_addr, son->block);}
|
||||
son->father = block;
|
||||
son->done = 1;
|
||||
sons[sons_size++] = son;
|
||||
if(!son->parent)
|
||||
son->parent = block->parent;
|
||||
}
|
||||
}
|
||||
if(sons_size) {
|
||||
block->sons = sons;
|
||||
block->sons_size = sons_size;
|
||||
} else
|
||||
free(sons);
|
||||
// ok, free the helper now
|
||||
helper.insts = NULL;
|
||||
if(insts_rsize/sizeof(instsize_t)<helper.insts_size) {
|
||||
printf_log(LOG_NONE, "BOX86: Warning, ists_size difference in block between pass2 (%zu) and pass3 (%zu), allocated: %zu\n", oldinstsize, helper.insts_size, insts_rsize/sizeof(instsize_t));
|
||||
}
|
||||
if(!isprotectedDB(addr, end-addr)) {
|
||||
dynarec_log(LOG_DEBUG, "Warning, block unprotected while being processed %p:%zu, marking as need_test\n", block->x86_addr, block->x86_size);
|
||||
block->dirty = 1;
|
||||
//protectDB(addr, end-addr);
|
||||
}
|
||||
if(getProtection(addr)&PROT_NEVERCLEAN) {
|
||||
block->dirty = 1;
|
||||
block->always_test = 1;
|
||||
}
|
||||
if(block->always_test) {
|
||||
dynarec_log(LOG_DEBUG, "Note: block marked as always dirty %p:%ld\n", block->x86_addr, block->x86_size);
|
||||
}
|
||||
free(helper.sons_x86);
|
||||
helper.sons_x86 = NULL;
|
||||
free(helper.sons_arm);
|
||||
helper.sons_arm = NULL;
|
||||
current_helper = NULL;
|
||||
block->done = 1;
|
||||
//block->done = 1;
|
||||
return (void*)block;
|
||||
}
|
||||
}
|
||||
+589
-324
File diff suppressed because it is too large.
Load diff
+637
-236
File diff suppressed because it is too large.
Load diff
+115
-23
@@ -18,7 +18,9 @@
|
||||
#include "dynarec_arm.h"
|
||||
#include "dynarec_arm_private.h"
|
||||
#include "arm_printer.h"
|
||||
#include "custommem.h"
|
||||
|
||||
#include "dynarec_arm_functions.h"
|
||||
#include "dynarec_arm_helper.h"
|
||||
|
||||
uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
|
||||
@@ -28,7 +30,8 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
int32_t i32, j32;
|
||||
uint32_t u32;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback;
|
||||
uint8_t wback, u8, wb1, wb2;
|
||||
uint8_t gb1, gb2, eb1, eb2;
|
||||
int fixedaddress;
|
||||
|
||||
MAYUSE(j32);
|
||||
@@ -45,6 +48,17 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
emit_add32(dyn, ninst, gd, ed, x3, x14);
|
||||
break;
|
||||
|
||||
case 0x20:
|
||||
INST_NAME("AND Eb, Gb");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
nextop = F8;
|
||||
GETGB(x2);
|
||||
GETEBO(x14);
|
||||
emit_and8(dyn, ninst, x1, x2, x14, x2);
|
||||
EBBACK;
|
||||
break;
|
||||
|
||||
case 0x2B:
|
||||
INST_NAME("SUB Gd, FS:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
@@ -85,6 +99,13 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
emit_cmp32(dyn, ninst, gd, ed, x3, x14);
|
||||
break;
|
||||
|
||||
case 0x64:
|
||||
addr = dynarecFS(dyn, addr, ip, ninst, ok, need_epilog);
|
||||
break;
|
||||
case 0x65:
|
||||
addr = dynarecGS(dyn, addr, ip, ninst, ok, need_epilog);
|
||||
break;
|
||||
|
||||
case 0x67:
|
||||
// reduced EA size...
|
||||
opcode = F8;
|
||||
@@ -94,7 +115,7 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop = F8;
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
GETGD; // don't need GETGW here
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
if(ed!=gd) {
|
||||
BFI(ed, gd, 0, 16);
|
||||
@@ -102,6 +123,7 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
} else {
|
||||
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
|
||||
STRH_REG(gd, x14, ed);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -110,9 +132,10 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop=F8;
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) { // reg <= reg
|
||||
if(MODREG) { // reg <= reg
|
||||
MOV_REG(gd, xEAX+(nextop&7));
|
||||
} else { // mem <= reg
|
||||
SMREAD();
|
||||
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
|
||||
LDR_REG_LSL_IMM5(gd, ed, x14, 0);
|
||||
}
|
||||
@@ -122,12 +145,13 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("POP FS:Ew16");
|
||||
nextop=F8;
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
POP1(xEAX+(nextop&7)); // 67 ignored
|
||||
} else {
|
||||
addr = geted16(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
|
||||
POP1(x2);
|
||||
STR_REG_LSL_IMM5(x2, x1, x14, 0);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -139,6 +163,7 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
MOV32(x2, u32);
|
||||
ADD_REG_LSL_IMM5(x1, x1, x2, 0);
|
||||
}
|
||||
SMREAD();
|
||||
LDR_IMM9(xEAX, x1, 0);
|
||||
break;
|
||||
|
||||
@@ -151,6 +176,7 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
ADD_REG_LSL_IMM5(x1, x1, x2, 0);
|
||||
}
|
||||
STR_IMM9(xEAX, x1, 0);
|
||||
SMWRITE2();
|
||||
break;
|
||||
|
||||
case 0xFF:
|
||||
@@ -159,9 +185,10 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
switch((nextop>>3)&7) {
|
||||
case 6: // Push Ed
|
||||
INST_NAME("PUSH FS:Ew");
|
||||
if((nextop&0xC0)==0xC0) { // reg
|
||||
if(MODREG) { // reg
|
||||
DEFAULT;
|
||||
} else { // mem <= i32
|
||||
SMREAD();
|
||||
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
|
||||
LDR_REG_LSL_IMM5(x3, ed, x14, 0);
|
||||
PUSH1(x3);
|
||||
@@ -175,17 +202,41 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x88:
|
||||
INST_NAME("MOV Eb, Gb");
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
gb2 = ((gd&4)>>2);
|
||||
gb1 = xEAX+(gd&3);
|
||||
if(gb2) {
|
||||
gd = x3;
|
||||
UXTB(gd, gb1, gb2);
|
||||
} else {
|
||||
gd = gb1; // no need to extract
|
||||
}
|
||||
if(MODREG) {
|
||||
ed = (nextop&7);
|
||||
eb1 = xEAX+(ed&3); // Ax, Cx, Dx or Bx
|
||||
eb2 = ((ed&4)<<1); // L or H
|
||||
BFI(eb1, gd, eb2, 8);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0, NULL);
|
||||
STRB_REG_LSL_IMM5(gd, ed, x14, 0);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x89:
|
||||
INST_NAME("MOV FS:Ed, Gd");
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) { // reg <= reg
|
||||
if(MODREG) { // reg <= reg
|
||||
MOV_REG(xEAX+(nextop&7), gd);
|
||||
} else { // mem <= reg
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0, NULL);
|
||||
STR_REG_LSL_IMM5(gd, ed, x14, 0);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -194,10 +245,11 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) { // reg <= reg
|
||||
if(MODREG) { // reg <= reg
|
||||
MOV_REG(gd, xEAX+(nextop&7));
|
||||
} else { // mem <= reg
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0, NULL);
|
||||
LDR_REG_LSL_IMM5(gd, ed, x14, 0);
|
||||
}
|
||||
break;
|
||||
@@ -206,14 +258,18 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("POP FS:Ed");
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
nextop = F8;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
POP1(xEAX+(nextop&7));
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
POP1(x2);
|
||||
STR_REG_LSL_IMM5(x2, ed, x14, 0);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x90:
|
||||
INST_NAME("NOP");
|
||||
break;
|
||||
|
||||
case 0xA0:
|
||||
INST_NAME("MOV AL, FS:Id");
|
||||
@@ -223,6 +279,7 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
LDRB_IMM9(xEAX, x1, i32);
|
||||
} else {
|
||||
MOV32(x2, i32);
|
||||
SMREAD();
|
||||
LDRB_REG_LSL_IMM5(xEAX, x1, x2, 0);
|
||||
}
|
||||
break;
|
||||
@@ -234,6 +291,7 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
LDR_IMM9(xEAX, x1, i32);
|
||||
} else {
|
||||
MOV32(x2, i32);
|
||||
SMREAD();
|
||||
LDR_REG_LSL_IMM5(xEAX, x1, x2, 0);
|
||||
}
|
||||
break;
|
||||
@@ -246,6 +304,7 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
} else {
|
||||
MOV32(x2, i32);
|
||||
STRB_REG_LSL_IMM5(xEAX, x1, x2, 0);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0xA3:
|
||||
@@ -254,25 +313,37 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
i32 = F32S;
|
||||
if(i32>-4096 && i32<4096) {
|
||||
STR_IMM9(xEAX, x1, i32);
|
||||
SMWRITE2();
|
||||
} else {
|
||||
MOV32(x2, i32);
|
||||
STR_REG_LSL_IMM5(xEAX, x2, x1, 0);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xA8:
|
||||
INST_NAME("TEST AL, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
UXTB(x1, xEAX, 0);
|
||||
u8 = F8;
|
||||
MOVW(x2, u8);
|
||||
emit_test8(dyn, ninst, x1, x2, x3, x14);
|
||||
break;
|
||||
|
||||
case 0xC7:
|
||||
INST_NAME("MOV FS:Ed, Id");
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
nextop=F8;
|
||||
if((nextop&0xC0)==0xC0) { // reg <= i32
|
||||
if(MODREG) { // reg <= i32
|
||||
i32 = F32S;
|
||||
ed = xEAX+(nextop&7);
|
||||
MOV32(ed, i32);
|
||||
} else { // mem <= i32
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0, NULL);
|
||||
i32 = F32S;
|
||||
MOV32(x3, i32);
|
||||
STR_REG_LSL_IMM5(x3, ed, x14, 0);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -288,34 +359,55 @@ uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
switch((nextop>>3)&7) {
|
||||
case 2: // CALL Ed
|
||||
INST_NAME("CALL FS:Ed");
|
||||
PASS2IF(ninst && dyn->insts[ninst-1].x86.set_flags, 1) {
|
||||
PASS2IF((box86_dynarec_safeflags>1) ||
|
||||
((ninst && dyn->insts[ninst-1].x86.set_flags)
|
||||
|| ((ninst>1) && dyn->insts[ninst-2].x86.set_flags)), 1)
|
||||
{
|
||||
READFLAGS(X_PEND); // that's suspicious
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET); //Hack to put flag in "don't care" state
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); //Hack to put flag in "don't care" state
|
||||
}
|
||||
if((nextop&0xC0)==0xC0) { // reg
|
||||
if(MODREG) { // reg
|
||||
MOV_REG(xEIP, xEAX+(nextop&7));
|
||||
} else { // mem
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0, NULL);
|
||||
LDR_REG_LSL_IMM5(xEIP, ed, x14, 0);
|
||||
}
|
||||
BARRIER(1);
|
||||
BARRIER_NEXT(1);
|
||||
if(!dyn->insts || ninst!=dyn->size-1) {
|
||||
if(box86_dynarec_callret && box86_dynarec_bigblock>1) {
|
||||
BARRIER(BARRIER_FULL);
|
||||
BARRIER_NEXT(BARRIER_FULL);
|
||||
} else {
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
}
|
||||
MOV32(x2, addr);
|
||||
if(box86_dynarec_callret) {
|
||||
SET_HASCALLRET();
|
||||
// Push actual return address
|
||||
if(addr < (dyn->start+dyn->isize)) {
|
||||
// there is a next...
|
||||
j32 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->arm_size)-8):0;
|
||||
MESSAGE(LOG_NONE, "\tCALLRET set return to +%di\n", j32>>2);
|
||||
ADR(c__, x3, j32);
|
||||
} else {
|
||||
MESSAGE(LOG_NONE, "\tCALLRET set return to Jmptable(%p)\n", (void*)addr);
|
||||
j32 = getJumpTableAddress(addr);
|
||||
MOV32(x3, j32);
|
||||
LDR_IMM9(x3, x3, 0);
|
||||
}
|
||||
PUSH(xSP, (1<<x2)|(1<<x3));
|
||||
}
|
||||
PUSH1(x2);
|
||||
jump_to_next(dyn, 0, xEIP, ninst);
|
||||
break;
|
||||
case 6: // Push Ed
|
||||
INST_NAME("PUSH FS:Ed");
|
||||
if((nextop&0xC0)==0xC0) { // reg
|
||||
if(MODREG) { // reg
|
||||
DEFAULT;
|
||||
} else { // mem <= i32
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0, NULL);
|
||||
LDR_REG_LSL_IMM5(x3, ed, x14, 0);
|
||||
PUSH1(x3);
|
||||
}
|
||||
|
||||
+122
-55
@@ -19,6 +19,7 @@
|
||||
#include "dynarec_arm_private.h"
|
||||
#include "arm_printer.h"
|
||||
|
||||
#include "dynarec_arm_functions.h"
|
||||
#include "dynarec_arm_helper.h"
|
||||
|
||||
uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
|
||||
@@ -28,16 +29,30 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
int32_t i32, j32;
|
||||
uint32_t u32;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback, wb1, wb2, wb;
|
||||
uint8_t wback, wb1, wb2, wb, eb1, eb2;
|
||||
uint8_t u8;
|
||||
int fixedaddress;
|
||||
|
||||
MAYUSE(j32);
|
||||
MAYUSE(wback);
|
||||
MAYUSE(wb2);
|
||||
MAYUSE(wb);
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0x01:
|
||||
INST_NAME("ADD GS:Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO2(x14);
|
||||
emit_add32(dyn, ninst, ed, gd, x3, x14);
|
||||
WBACK2;
|
||||
break;
|
||||
|
||||
case 0x03:
|
||||
INST_NAME("ADD Gd, GS:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
@@ -82,7 +97,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
GETGD;
|
||||
GETEDO2(x14);
|
||||
emit_and32(dyn, ninst, ed, gd, x3, x14);
|
||||
WBACK;
|
||||
WBACK2;
|
||||
break;
|
||||
|
||||
case 0x23:
|
||||
@@ -103,7 +118,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
GETGD;
|
||||
GETEDO2(x14);
|
||||
emit_sub32(dyn, ninst, ed, gd, x3, x14);
|
||||
WBACK;
|
||||
WBACK2;
|
||||
break;
|
||||
|
||||
case 0x2B:
|
||||
@@ -124,7 +139,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
GETGD;
|
||||
GETEDO2(x14);
|
||||
emit_xor32(dyn, ninst, gd, ed, x3, x14);
|
||||
WBACK;
|
||||
WBACK2;
|
||||
break;
|
||||
|
||||
case 0x33:
|
||||
@@ -137,6 +152,16 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
emit_xor32(dyn, ninst, gd, ed, x3, x14);
|
||||
break;
|
||||
|
||||
case 0x39:
|
||||
INST_NAME("CMP GS:Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO(x14);
|
||||
emit_cmp32(dyn, ninst, ed, gd, x3, x14);
|
||||
break;
|
||||
|
||||
case 0x3B:
|
||||
INST_NAME("CMP Gd, GS:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
@@ -147,6 +172,13 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
emit_cmp32(dyn, ninst, gd, ed, x3, x14);
|
||||
break;
|
||||
|
||||
case 0x64:
|
||||
addr = dynarecFS(dyn, addr, ip, ninst, ok, need_epilog);
|
||||
break;
|
||||
case 0x65:
|
||||
addr = dynarecGS(dyn, addr, ip, ninst, ok, need_epilog);
|
||||
break;
|
||||
|
||||
case 0x69:
|
||||
INST_NAME("IMUL Gd, GS:Ed, Id");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
@@ -177,7 +209,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
GETEBO(x1);
|
||||
u8 = F8;
|
||||
emit_add8c(dyn, ninst, x1, u8, x2, x14);
|
||||
EBBACK;
|
||||
EBBACK2;
|
||||
break;
|
||||
case 1: //OR
|
||||
INST_NAME("OR GS:Eb, Ib");
|
||||
@@ -186,7 +218,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
GETEBO(x1);
|
||||
u8 = F8;
|
||||
emit_or8c(dyn, ninst, x1, u8, x2, x14);
|
||||
EBBACK;
|
||||
EBBACK2;
|
||||
break;
|
||||
case 2: //ADC
|
||||
INST_NAME("ADC GS:Eb, Ib");
|
||||
@@ -196,7 +228,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
GETEBO(x1);
|
||||
u8 = F8;
|
||||
emit_adc8c(dyn, ninst, x1, u8, x2, x14);
|
||||
EBBACK;
|
||||
EBBACK2;
|
||||
break;
|
||||
case 3: //SBB
|
||||
INST_NAME("SBB GS:Eb, Ib");
|
||||
@@ -206,7 +238,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
GETEBO(x1);
|
||||
u8 = F8;
|
||||
emit_sbb8c(dyn, ninst, x1, u8, x2, x14);
|
||||
EBBACK;
|
||||
EBBACK2;
|
||||
break;
|
||||
case 4: //AND
|
||||
INST_NAME("AND GS:Eb, Ib");
|
||||
@@ -215,7 +247,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
GETEBO(x1);
|
||||
u8 = F8;
|
||||
emit_and8c(dyn, ninst, x1, u8, x2, x14);
|
||||
EBBACK;
|
||||
EBBACK2;
|
||||
break;
|
||||
case 5: //SUB
|
||||
INST_NAME("SUB GS:Eb, Ib");
|
||||
@@ -224,7 +256,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
GETEBO(x1);
|
||||
u8 = F8;
|
||||
emit_sub8c(dyn, ninst, x1, u8, x2, x14);
|
||||
EBBACK;
|
||||
EBBACK2;
|
||||
break;
|
||||
case 6: //XOR
|
||||
INST_NAME("XOR GS:Eb, Ib");
|
||||
@@ -233,7 +265,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
GETEBO(x1);
|
||||
u8 = F8;
|
||||
emit_xor8c(dyn, ninst, x1, u8, x2, x14);
|
||||
EBBACK;
|
||||
EBBACK2;
|
||||
break;
|
||||
case 7: //CMP
|
||||
INST_NAME("CMP GS:Eb, Ib");
|
||||
@@ -265,7 +297,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
GETEDO2(x14);
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
emit_add32c(dyn, ninst, ed, i32, x3, x14);
|
||||
WBACK;
|
||||
WBACK2;
|
||||
break;
|
||||
case 1: //OR
|
||||
if(opcode==0x81) {INST_NAME("OR Ed, Id");} else {INST_NAME("OR Ed, Ib");}
|
||||
@@ -274,7 +306,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
GETEDO2(x14);
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
emit_or32c(dyn, ninst, ed, i32, x3, x14);
|
||||
WBACK;
|
||||
WBACK2;
|
||||
break;
|
||||
case 2: //ADC
|
||||
if(opcode==0x81) {INST_NAME("ADC Ed, Id");} else {INST_NAME("ADC Ed, Ib");}
|
||||
@@ -284,7 +316,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
GETEDO2(x14);
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
emit_adc32c(dyn, ninst, ed, i32, x3, x14);
|
||||
WBACK;
|
||||
WBACK2;
|
||||
break;
|
||||
case 3: //SBB
|
||||
if(opcode==0x81) {INST_NAME("SBB Ed, Id");} else {INST_NAME("SBB Ed, Ib");}
|
||||
@@ -294,7 +326,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
GETEDO2(x14);
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
emit_sbb32c(dyn, ninst, ed, i32, x3, x14);
|
||||
WBACK;
|
||||
WBACK2;
|
||||
break;
|
||||
case 4: //AND
|
||||
if(opcode==0x81) {INST_NAME("AND Ed, Id");} else {INST_NAME("AND Ed, Ib");}
|
||||
@@ -303,7 +335,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
GETEDO2(x14);
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
emit_and32c(dyn, ninst, ed, i32, x3, x14);
|
||||
WBACK;
|
||||
WBACK2;
|
||||
break;
|
||||
case 5: //SUB
|
||||
if(opcode==0x81) {INST_NAME("SUB Ed, Id");} else {INST_NAME("SUB Ed, Ib");}
|
||||
@@ -312,7 +344,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
GETEDO2(x14);
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
emit_sub32c(dyn, ninst, ed, i32, x3, x14);
|
||||
WBACK;
|
||||
WBACK2;
|
||||
break;
|
||||
case 6: //XOR
|
||||
if(opcode==0x81) {INST_NAME("XOR Ed, Id");} else {INST_NAME("XOR Ed, Ib");}
|
||||
@@ -321,7 +353,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
GETEDO2(x14);
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
emit_xor32c(dyn, ninst, ed, i32, x3, x14);
|
||||
WBACK;
|
||||
WBACK2;
|
||||
break;
|
||||
case 7: //CMP
|
||||
if(opcode==0x81) {INST_NAME("CMP Ed, Id");} else {INST_NAME("CMP Ed, Ib");}
|
||||
@@ -344,11 +376,12 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) { // reg <= reg
|
||||
if(MODREG) { // reg <= reg
|
||||
MOV_REG(xEAX+(nextop&7), gd);
|
||||
} else { // mem <= reg
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0, NULL);
|
||||
STR_REG_LSL_IMM5(gd, ed, x14, 0);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -357,10 +390,11 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) { // reg <= reg
|
||||
if(MODREG) { // reg <= reg
|
||||
MOV_REG(gd, xEAX+(nextop&7));
|
||||
} else { // mem <= reg
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0, NULL);
|
||||
LDR_REG_LSL_IMM5(gd, ed, x14, 0);
|
||||
}
|
||||
break;
|
||||
@@ -369,19 +403,24 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("POP GS:Ed");
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
nextop = F8;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
POP1((xEAX+(nextop&7)));
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
POP1(x2);
|
||||
STR_REG_LSL_IMM5(x2, ed, x14, 0);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x90:
|
||||
INST_NAME("NOP");
|
||||
break;
|
||||
|
||||
case 0xA1:
|
||||
INST_NAME("MOV EAX, GS:Id");
|
||||
grab_tlsdata(dyn, addr, ninst, x1);
|
||||
i32 = F32S;
|
||||
SMREAD();
|
||||
if(i32>-4096 && i32<4096) {
|
||||
LDR_IMM9(xEAX, x1, i32);
|
||||
} else {
|
||||
@@ -391,6 +430,16 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xA2:
|
||||
INST_NAME("MOV GS:Od, AL");
|
||||
grab_tlsdata(dyn, addr, ninst, x1);
|
||||
u32 = F32;
|
||||
MOV32(x2, u32);
|
||||
ADD_REG_LSL_IMM5(x2, x1, x2, 0);
|
||||
STRB_IMM9(xEAX, x2, 0);
|
||||
SMWRITE2();
|
||||
break;
|
||||
|
||||
case 0xA3:
|
||||
INST_NAME("MOV GS:Od, EAX");
|
||||
grab_tlsdata(dyn, addr, ninst, x1);
|
||||
@@ -398,21 +447,42 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
MOV32(x2, u32);
|
||||
ADD_REG_LSL_IMM5(x2, x1, x2, 0);
|
||||
STR_IMM9(xEAX, x2, 0);
|
||||
SMWRITE2();
|
||||
break;
|
||||
|
||||
case 0xC6:
|
||||
INST_NAME("MOV GS:Eb, Ib");
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
nextop=F8;
|
||||
if(MODREG) { // reg <= u8
|
||||
u8 = F8;
|
||||
ed = (nextop&7);
|
||||
eb1 = xEAX+(ed&3); // Ax, Cx, Dx or Bx
|
||||
eb2 = (ed&4)>>2; // L or H
|
||||
MOVW(x3, u8);
|
||||
BFI(eb1, x3, eb2*8, 8);
|
||||
} else { // mem <= u8
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
u8 = F8;
|
||||
MOVW(x3, u8);
|
||||
STRB_REG_LSL_IMM5(x3, ed, x14, 0);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0xC7:
|
||||
INST_NAME("MOV GS:Ed, Id");
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
nextop=F8;
|
||||
if((nextop&0xC0)==0xC0) { // reg <= i32
|
||||
if(MODREG) { // reg <= i32
|
||||
i32 = F32S;
|
||||
ed = xEAX+(nextop&7);
|
||||
MOV32(ed, i32);
|
||||
} else { // mem <= i32
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0, NULL);
|
||||
i32 = F32S;
|
||||
MOV32(x3, i32);
|
||||
STR_REG_LSL_IMM5(x3, ed, x14, 0);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -422,40 +492,38 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("ROL Ed, 1");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
|
||||
GETEDO2(x14);
|
||||
emit_rol32c(dyn, ninst, ed, 1, x3, x14);
|
||||
WBACK;
|
||||
WBACK2;
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("ROR Ed, 1");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
|
||||
GETEDO2(x14);
|
||||
emit_ror32c(dyn, ninst, ed, 1, x3, x14);
|
||||
WBACK;
|
||||
WBACK2;
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("RCL Ed, 1");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
MOVW(x2, 1);
|
||||
GETEDO2(x14);
|
||||
wb = ed;
|
||||
if(ed!=x1) {MOV_REG(x1, ed); wb = x1;}
|
||||
CALL_(rcl32, ed, (1<<x14));
|
||||
SBACK(wb);
|
||||
CALL_(rcl32, ed, (1<<x2));
|
||||
WBACK2;
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("RCR Ed, 1");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
MOVW(x2, 1);
|
||||
wb = ed;
|
||||
if(ed!=x1) {MOV_REG(x1, ed); wb = x1;}
|
||||
CALL_(rcr32, ed, (1<<x14));
|
||||
SBACK(wb);
|
||||
CALL_(rcr32, ed, (1<<x2));
|
||||
WBACK2;
|
||||
break;
|
||||
case 4:
|
||||
case 6:
|
||||
@@ -463,21 +531,21 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
GETEDO2(x14);
|
||||
emit_shl32c(dyn, ninst, ed, 1, x3, x14);
|
||||
WBACK;
|
||||
WBACK2;
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("SHR Ed, 1");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
GETEDO2(x14);
|
||||
emit_shr32c(dyn, ninst, ed, 1, x3, x14);
|
||||
WBACK;
|
||||
WBACK2;
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("SAR Ed, 1");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
GETEDO2(x14);
|
||||
emit_sar32c(dyn, ninst, ed, 1, x3, x14);
|
||||
WBACK;
|
||||
WBACK2;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -494,7 +562,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
RSB_IMM8(x3, x3, 0x20);
|
||||
GETEDO2(x14);
|
||||
MOV_REG_ROR_REG(ed, ed, x3);
|
||||
WBACK;
|
||||
WBACK2;
|
||||
UFLAG_IF { // calculate flags directly
|
||||
CMPS_IMM8(x3, 31);
|
||||
B_MARK(cNE);
|
||||
@@ -515,7 +583,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
B_MARK2(cEQ);
|
||||
GETEDO2(x14);
|
||||
MOV_REG_ROR_REG(ed, ed, x3);
|
||||
WBACK;
|
||||
WBACK2;
|
||||
UFLAG_IF { // calculate flags directly
|
||||
CMPS_IMM8(x3, 1);
|
||||
B_MARK(cNE);
|
||||
@@ -533,23 +601,21 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("RCL Ed, CL");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
AND_IMM8(x2, xECX, 0x1f);
|
||||
wb = ed;
|
||||
if(ed!=x1) {MOV_REG(x1, ed); wb = x1;}
|
||||
CALL_(rcl32, ed, (1<<x14));
|
||||
SBACK(wb);
|
||||
CALL_(rcl32, ed, (1<<x2));
|
||||
WBACK2;
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("RCR Ed, CL");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
AND_IMM8(x2, xECX, 0x1f);
|
||||
wb = ed;
|
||||
if(ed!=x1) {MOV_REG(x1, ed); wb = x1;}
|
||||
CALL_(rcr32, ed, (1<<x14));
|
||||
SBACK(wb);
|
||||
WBACK2;
|
||||
break;
|
||||
case 4:
|
||||
case 6:
|
||||
@@ -558,7 +624,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
AND_IMM8(x3, xECX, 0x1f);
|
||||
GETEDO2(x14);
|
||||
emit_shl32(dyn, ninst, ed, x3, x3, x14);
|
||||
WBACK;
|
||||
WBACK2;
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("SHR Ed, CL");
|
||||
@@ -566,7 +632,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
AND_IMM8(x3, xECX, 0x1f);
|
||||
GETEDO2(x14);
|
||||
emit_shr32(dyn, ninst, ed, x3, x3, x14);
|
||||
WBACK;
|
||||
WBACK2;
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("SAR Ed, CL");
|
||||
@@ -575,7 +641,7 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
GETEDO2(x14);
|
||||
UFLAG_OP12(ed, x3);
|
||||
MOV_REG_ASR_REG(ed, ed, x3);
|
||||
WBACK;
|
||||
WBACK2;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_sar32);
|
||||
break;
|
||||
@@ -594,10 +660,11 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
switch((nextop>>3)&7) {
|
||||
case 6: // Push Ed
|
||||
INST_NAME("PUSH GS:Ed");
|
||||
if((nextop&0xC0)==0xC0) { // reg
|
||||
if(MODREG) { // reg
|
||||
DEFAULT;
|
||||
} else { // mem <= i32
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0, NULL);
|
||||
LDR_REG_LSL_IMM5(x3, ed, x14, 0);
|
||||
PUSH1(x3);
|
||||
}
|
||||
|
||||
+260
-133
@@ -18,6 +18,7 @@
|
||||
#include "dynarec_arm.h"
|
||||
#include "dynarec_arm_private.h"
|
||||
#include "arm_printer.h"
|
||||
#include "custommem.h"
|
||||
|
||||
#include "dynarec_arm_helper.h"
|
||||
#include "dynarec_arm_functions.h"
|
||||
@@ -33,12 +34,14 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
uint16_t u16;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback, wb1;
|
||||
int lock;
|
||||
int fixedaddress;
|
||||
MAYUSE(u16);
|
||||
MAYUSE(u8);
|
||||
MAYUSE(j32);
|
||||
MAYUSE(lock);
|
||||
while(opcode==0x66) opcode = F8; // "unlimited" 0x66 as prefix for variable sized NOP
|
||||
if(opcode==0x2E) opcode = F8; // cs: is ignored
|
||||
if((opcode==0x26) || (opcode==0x2E) || (opcode==0x36) || (opcode==0x3E)) opcode = F8; // segment prefix are ignored
|
||||
switch(opcode) {
|
||||
|
||||
case 0x01:
|
||||
@@ -170,11 +173,17 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("SBB AX, Iw");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
i16 = F16;
|
||||
i32 = F16;
|
||||
UXTH(x1, xEAX, 0);
|
||||
emit_sbb16c(dyn, ninst, x1, i16, x3, x14);
|
||||
emit_sbb16c(dyn, ninst, x1, i32, x3, x14);
|
||||
BFI(xEAX, x1, 0, 16);
|
||||
break;
|
||||
case 0x1E:
|
||||
INST_NAME("PUSH DS");
|
||||
MOVW(x1, offsetof(x86emu_t, segs[_DS]));
|
||||
LDRH_REG(x2, xEmu, x1);
|
||||
PUSH16(x2, xESP);
|
||||
break;
|
||||
|
||||
case 0x21:
|
||||
INST_NAME("AND Ew, Gw");
|
||||
@@ -295,7 +304,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0x46:
|
||||
case 0x47:
|
||||
INST_NAME("INC Reg16");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
gd = xEAX+(opcode&7);
|
||||
UXTH(x1, gd, 0);
|
||||
emit_inc16(dyn, ninst, x1, x3, x14);
|
||||
@@ -310,7 +319,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0x4E:
|
||||
case 0x4F:
|
||||
INST_NAME("DEC Reg16");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
gd = xEAX+(opcode&7);
|
||||
UXTH(x1, gd, 0);
|
||||
emit_dec16(dyn, ninst, x1, x3, x14);
|
||||
@@ -380,13 +389,13 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("IMUL Gw,Ew,Iw");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
nextop = F8;
|
||||
UFLAG_DF(x1, d_imul16);
|
||||
GETEW(x1);
|
||||
i16 = F16S;
|
||||
MOVW(x2, i16);
|
||||
SMULBB(x2, ed, x2);
|
||||
UFLAG_RES(x2);
|
||||
BFI(xEAX+((nextop&0x38)>>3), x2, 0, 16);
|
||||
UFLAG_DF(x1, d_imul16);
|
||||
break;
|
||||
case 0x6A:
|
||||
INST_NAME("PUSH Ib");
|
||||
@@ -398,13 +407,13 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("IMUL Gw,Ew,Ib");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
nextop = F8;
|
||||
UFLAG_DF(x1, d_imul16);
|
||||
GETEW(x1);
|
||||
i16 = F8S;
|
||||
MOVW(x2, i16);
|
||||
SMULBB(x2, ed, x2);
|
||||
UFLAG_RES(x2);
|
||||
BFI(xEAX+((nextop&0x38)>>3), x2, 0, 16);
|
||||
UFLAG_DF(x1, d_imul16);
|
||||
break;
|
||||
|
||||
case 0x81:
|
||||
@@ -497,9 +506,9 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
|
||||
case 0x87:
|
||||
INST_NAME("XCHG Ew, Gw");
|
||||
INST_NAME("(LOCK) XCHG Ew, Gw");
|
||||
nextop = F8;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
GETGD;
|
||||
UXTH(x14, gd, 0);
|
||||
ed = xEAX + (nextop&7);
|
||||
@@ -510,7 +519,8 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
} else {
|
||||
GETGD;
|
||||
UXTH(x14, gd, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0);
|
||||
SMDMB();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0, LOCK_LOCK);
|
||||
#if 0
|
||||
MARKLOCK;
|
||||
// do the swap with exclusive locking
|
||||
@@ -523,6 +533,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
LDRH_IMM8(x1, ed, fixedaddress);
|
||||
STRH_IMM8(x14, ed, fixedaddress);
|
||||
#endif
|
||||
SMDMB();
|
||||
BFI(gd, x1, 0, 16);
|
||||
}
|
||||
break;
|
||||
@@ -531,27 +542,29 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("MOV Ew, Gw");
|
||||
nextop = F8;
|
||||
GETGD; // don't need GETGW here
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
if(ed!=gd) {
|
||||
BFI(ed, gd, 0, 16);
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 255, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 255, 0, 0, &lock);
|
||||
STRH_IMM8(gd, ed, fixedaddress);
|
||||
SMWRITELOCK(lock);
|
||||
}
|
||||
break;
|
||||
case 0x8B:
|
||||
INST_NAME("MOV Gw, Ew");
|
||||
nextop = F8;
|
||||
GETGD; // don't need GETGW neither
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
if(ed!=gd) {
|
||||
BFI(gd, ed, 0, 16);
|
||||
}
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 255, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 255, 0, 0, &lock);
|
||||
SMREADLOCK(lock);
|
||||
LDRH_IMM8(x1, ed, fixedaddress);
|
||||
BFI(gd, x1, 0, 16);
|
||||
}
|
||||
@@ -561,24 +574,26 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop = F8;
|
||||
MOV32(x2, offsetof(x86emu_t, segs[(nextop&0x38)>>3]));
|
||||
LDRH_REG(x1, xEmu, x2);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
BFI(ed, x1, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 255, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 255, 0, 0, NULL);
|
||||
STRH_IMM8(x1, ed, fixedaddress);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x8E:
|
||||
INST_NAME("MOV Seg,Ew");
|
||||
nextop = F8;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
MOV32(x2, offsetof(x86emu_t, segs[(nextop&0x38)>>3]));
|
||||
STRH_REG(ed, xEmu, x2);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 255, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 255, 0, 0, NULL);
|
||||
LDRH_IMM8(x1, ed, fixedaddress);
|
||||
MOV32(x2, offsetof(x86emu_t, segs[(nextop&0x38)>>3]));
|
||||
STRH_REG(x1, xEmu, x2);
|
||||
@@ -622,7 +637,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 0x9D:
|
||||
INST_NAME("POPF (16b)");
|
||||
SETFLAGS(X_ALL, SF_SET); // lower 16bits is all flags handled in dynarec
|
||||
SETFLAGS(X_ALL, SF_SET_NODF); // lower 16bits is all flags handled in dynarec
|
||||
LDRHA_IMM8(x2, xESP, 2);
|
||||
MOV32(x1, 0x7FD7);
|
||||
AND_REG_LSL_IMM5(x2, x2, x1, 0);
|
||||
@@ -635,6 +650,8 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("MOV, AX, Od");
|
||||
u32 = F32;
|
||||
MOV32(x2, u32);
|
||||
if(isLockAddress(u32)) lock=1; else lock = 0;
|
||||
SMREADLOCK(lock);
|
||||
LDRH_IMM8(x2, x2, 0);
|
||||
BFI(xEAX, x2, 0, 16);
|
||||
break;
|
||||
@@ -642,7 +659,9 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("MOV Od, AX");
|
||||
u32 = F32;
|
||||
MOV32(x2, u32);
|
||||
if(isLockAddress(u32)) lock=1; else lock = 0;
|
||||
STRH_IMM8(xEAX, x2, 0);
|
||||
SMWRITELOCK(lock);
|
||||
break;
|
||||
case 0xA5:
|
||||
INST_NAME("MOVSW");
|
||||
@@ -681,6 +700,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 0xAF:
|
||||
INST_NAME("SCASW");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
GETDIR(x3, 2);
|
||||
UXTH(x1, xEAX, 0);
|
||||
LDRHAI_REG_LSL_IMM5(x2, xEDI, x3);
|
||||
@@ -706,26 +726,34 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("ROL Ew, Ib");
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
GETEW(x1);
|
||||
u8 = F8;
|
||||
MOVW(x2, u8);
|
||||
CALL_(rol16, x1, (1<<x3));
|
||||
EWBACK;
|
||||
if(geted_ib(dyn, addr, ninst, nextop)&31) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
|
||||
GETEW(x1);
|
||||
u8 = F8;
|
||||
emit_rol16c(dyn, ninst, x1, u8&15, x2, x14);
|
||||
EWBACK;
|
||||
} else {
|
||||
FAKEED;
|
||||
F8;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("ROR Ew, Ib");
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
GETEW(x1);
|
||||
u8 = F8;
|
||||
MOVW(x2, u8);
|
||||
CALL_(ror16, x1, (1<<x3));
|
||||
EWBACK;
|
||||
if(geted_ib(dyn, addr, ninst, nextop)&31) {
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
|
||||
GETEW(x1);
|
||||
u8 = F8;
|
||||
emit_ror16c(dyn, ninst, x1, u8&15, x2, x14);
|
||||
EWBACK;
|
||||
} else {
|
||||
FAKEED;
|
||||
F8;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("RCL Ew, Ib");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
GETEW(x1);
|
||||
u8 = F8;
|
||||
MOVW(x2, u8);
|
||||
@@ -735,7 +763,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 3:
|
||||
INST_NAME("RCR Ew, Ib");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
GETEW(x1);
|
||||
u8 = F8;
|
||||
MOVW(x2, u8);
|
||||
@@ -745,39 +773,42 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 4:
|
||||
case 6:
|
||||
INST_NAME("SHL Ew, Ib");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
GETEW(x1);
|
||||
u8 = F8;
|
||||
MOVW(x2, (u8&0x1f));
|
||||
UFLAG_OP12(ed, x2)
|
||||
MOV_REG_LSL_REG(ed, ed, x2);
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_shl16);
|
||||
if(geted_ib(dyn, addr, ninst, nextop)&31) {
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
GETEW(x1);
|
||||
u8 = F8;
|
||||
emit_shl16c(dyn, ninst, x1, u8&31, x2, x14);
|
||||
EWBACK;
|
||||
} else {
|
||||
FAKEED;
|
||||
F8;
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("SHR Ed, Ib");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
GETEW(x1);
|
||||
u8 = F8;
|
||||
MOVW(x2, (u8&0x1f));
|
||||
UFLAG_OP12(ed, x2)
|
||||
MOV_REG_LSR_REG(ed, ed, x2);
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_shr16);
|
||||
if(geted_ib(dyn, addr, ninst, nextop)&31) {
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
GETEW(x1);
|
||||
u8 = F8;
|
||||
emit_shr16c(dyn, ninst, x1, u8&31, x2, x14);
|
||||
EWBACK;
|
||||
} else {
|
||||
FAKEED;
|
||||
F8;
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("SAR Ed, Ib");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
GETSEW(x1);
|
||||
u8 = F8;
|
||||
MOVW(x2, (u8&0x1f));
|
||||
UFLAG_OP12(ed, x2)
|
||||
MOV_REG_ASR_REG(ed, ed, x2);
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_sar16);
|
||||
if(geted_ib(dyn, addr, ninst, nextop)&31) {
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
GETSEW(x1);
|
||||
u8 = F8;
|
||||
emit_sar16c(dyn, ninst, x1, u8&31, x2, x14);
|
||||
EWBACK;
|
||||
} else {
|
||||
FAKEED;
|
||||
F8;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -785,13 +816,13 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xC7:
|
||||
INST_NAME("MOV Ew, Iw");
|
||||
nextop = F8;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
u16 = F16;
|
||||
MOVW(x1, u16);
|
||||
BFI(ed, x1, 0, 16);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 255, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 255, 0, 0, NULL);
|
||||
u16 = F16;
|
||||
MOVW(x1, u16);
|
||||
STRH_IMM8(x1, ed, fixedaddress);
|
||||
@@ -799,104 +830,185 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
|
||||
case 0xD1:
|
||||
case 0xD3:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
if(opcode==0xD1) {
|
||||
INST_NAME("ROL Ew, 1");
|
||||
MOVW(x2, 1);
|
||||
} else {
|
||||
INST_NAME("ROL Ew, CL");
|
||||
AND_IMM8(x2, xECX, 0x1f);
|
||||
}
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
INST_NAME("ROL Ew, 1");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
|
||||
GETEW(x1);
|
||||
CALL_(rol16, x1, (1<<x3));
|
||||
emit_rol16c(dyn, ninst, x1, 1, x2, x14);
|
||||
EWBACK;
|
||||
break;
|
||||
case 1:
|
||||
if(opcode==0xD1) {
|
||||
INST_NAME("ROR Ew, 1");
|
||||
MOVW(x2, 1);
|
||||
} else {
|
||||
INST_NAME("ROR Ew, CL");
|
||||
AND_IMM8(x2, xECX, 0x1f);
|
||||
}
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
INST_NAME("ROR Ew, 1");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET_PENDING);
|
||||
GETEW(x1);
|
||||
CALL_(ror16, x1, (1<<x3));
|
||||
emit_ror16c(dyn, ninst, x1, 1, x2, x14);
|
||||
EWBACK;
|
||||
break;
|
||||
case 2:
|
||||
if(opcode==0xD1) {INST_NAME("RCL Ew, 1"); } else { INST_NAME("RCL Ew, CL");}
|
||||
INST_NAME("RCL Ew, 1");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
if(opcode==0xD1) {MOVW(x2, 1);} else {AND_IMM8(x2, xECX, 0x1f);}
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
MOVW(x2, 1);
|
||||
GETEW(x1);
|
||||
CALL_(rcl16, x1, (1<<x3));
|
||||
EWBACK;
|
||||
break;
|
||||
case 3:
|
||||
if(opcode==0xD1) {INST_NAME("RCR Ew, 1");} else {INST_NAME("RCR Ew, CL");}
|
||||
INST_NAME("RCR Ew, 1");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
if(opcode==0xD1) {MOVW(x2, 1);} else {AND_IMM8(x2, xECX, 0x1f);}
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
MOVW(x2, 1);
|
||||
GETEW(x1);
|
||||
CALL_(rcr16, x1, (1<<x3));
|
||||
EWBACK;
|
||||
break;
|
||||
case 4:
|
||||
case 6:
|
||||
if(opcode==0xD1) {
|
||||
INST_NAME("SHL Ew, 1");
|
||||
MOVW(x14, 1);
|
||||
} else {
|
||||
INST_NAME("SHL Ew, CL");
|
||||
AND_IMM8(x14, xECX, 0x1f);
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
INST_NAME("SHL Ew, 1");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
GETEW(x1);
|
||||
UFLAG_OP12(ed, x14)
|
||||
MOV_REG_LSL_REG(ed, ed, x14);
|
||||
emit_shl16c(dyn, ninst, x1, 1, x2, x14);
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_shl16);
|
||||
break;
|
||||
case 5:
|
||||
if(opcode==0xD1) {
|
||||
INST_NAME("SHR Ew, 1");
|
||||
MOVW(x14, 1);
|
||||
} else {
|
||||
INST_NAME("SHR Ew, CL");
|
||||
AND_IMM8(x14, xECX, 0x1f);
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
INST_NAME("SHR Ew, 1");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
GETEW(x1);
|
||||
UFLAG_OP12(ed, x14)
|
||||
MOV_REG_LSR_REG(ed, ed, x14);
|
||||
emit_shr16c(dyn, ninst, x1, 1, x2, x14);
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_shr16);
|
||||
break;
|
||||
case 7:
|
||||
if(opcode==0xD1) {
|
||||
INST_NAME("SAR Ew, 1");
|
||||
MOVW(x14, 1);
|
||||
} else {
|
||||
INST_NAME("SAR Ew, CL");
|
||||
AND_IMM8(x14, xECX, 0x1f);
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
INST_NAME("SAR Ew, 1");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
GETSEW(x1);
|
||||
UFLAG_OP12(ed, x14)
|
||||
MOV_REG_ASR_REG(ed, ed, x14);
|
||||
emit_sar16c(dyn, ninst, x1, 1, x2, x14);
|
||||
EWBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_sar16);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xD3:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("ROL Ew, CL");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET);
|
||||
if(box86_dynarec_safeflags>1)
|
||||
MAYSETFLAGS();
|
||||
UFLAG_IF {
|
||||
TSTS_IMM8(xECX, 0x1f);
|
||||
B_NEXT(cEQ);
|
||||
}
|
||||
AND_IMM8(x2, xECX, 0x0f);
|
||||
RSB_IMM8(x2, x2, 16);
|
||||
GETEW(x1);
|
||||
ORR_REG_LSL_IMM5(ed, ed, ed, 16);
|
||||
MOV_REG_LSR_REG(ed, ed, x2);
|
||||
EWBACK;
|
||||
UFLAG_IF { // calculate flags directly
|
||||
CMPS_IMM8(x2, 15);
|
||||
ADD_REG_LSR_IMM5_COND(cEQ, x3, ed, ed, 15);
|
||||
BFI_COND(cEQ, xFlags, x3, F_OF, 1);
|
||||
BFI(xFlags, ed, F_CF, 1);
|
||||
UFLAG_DF(x2, d_none);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("ROR Ew, CL");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET);
|
||||
if(box86_dynarec_safeflags>1)
|
||||
MAYSETFLAGS();
|
||||
UFLAG_IF {
|
||||
TSTS_IMM8(xECX, 0x1f);
|
||||
B_NEXT(cEQ);
|
||||
}
|
||||
AND_IMM8(x2, xECX, 0x0f);
|
||||
GETEW(x1);
|
||||
ORR_REG_LSL_IMM5(ed, ed, ed, 16);
|
||||
MOV_REG_LSR_REG(ed, ed, x2);
|
||||
EWBACK;
|
||||
UFLAG_IF { // calculate flags directly
|
||||
CMPS_IMM8(x2, 1);
|
||||
MOV_REG_LSR_IMM5_COND(cEQ, x2, ed, 14); // x2 = d>>14
|
||||
XOR_REG_LSR_IMM8_COND(cEQ, x2, x2, x2, 1); // x2 = ((d>>14) ^ ((d>>14)>>1))
|
||||
BFI_COND(cEQ, xFlags, x2, F_OF, 1);
|
||||
MOV_REG_LSR_IMM5(x2, ed, 15);
|
||||
BFI(xFlags, x2, F_CF, 1);
|
||||
UFLAG_DF(x2, d_none);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("RCL Ew, CL");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
AND_IMM8(x2, xECX, 0x1f);
|
||||
GETEW(x1);
|
||||
CALL_(rcl16, x1, (1<<x3));
|
||||
EWBACK;
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("RCR Ew, CL");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET_DF);
|
||||
AND_IMM8(x2, xECX, 0x1f);
|
||||
GETEW(x1);
|
||||
CALL_(rcr16, x1, (1<<x3));
|
||||
EWBACK;
|
||||
break;
|
||||
case 4:
|
||||
case 6:
|
||||
INST_NAME("SHL Ew, CL");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
if(box86_dynarec_safeflags>1)
|
||||
MAYSETFLAGS();
|
||||
UFLAG_IF {
|
||||
ANDS_IMM8(x2, xECX, 0x1f);
|
||||
B_NEXT(cEQ);
|
||||
} else {
|
||||
AND_IMM8(x2, xECX, 0x1f);
|
||||
}
|
||||
GETEW(x1);
|
||||
emit_shl16(dyn, ninst, x1, x2, x2, x14);
|
||||
EWBACK;
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("SHR Ew, CL");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
if(box86_dynarec_safeflags>1)
|
||||
MAYSETFLAGS();
|
||||
UFLAG_IF {
|
||||
ANDS_IMM8(x2, xECX, 0x1f);
|
||||
B_NEXT(cEQ);
|
||||
} else {
|
||||
AND_IMM8(x2, xECX, 0x1f);
|
||||
}
|
||||
GETEW(x1);
|
||||
emit_shr16(dyn, ninst, x1, x2, x2, x14);
|
||||
EWBACK;
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("SAR Ew, CL");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
if(box86_dynarec_safeflags>1)
|
||||
MAYSETFLAGS();
|
||||
UFLAG_IF {
|
||||
ANDS_IMM8(x2, xECX, 0x1f);
|
||||
B_NEXT(cEQ);
|
||||
} else {
|
||||
AND_IMM8(x2, xECX, 0x1f);
|
||||
}
|
||||
GETSEW(x1);
|
||||
emit_sar16(dyn, ninst, x1, x2, x2, x14);
|
||||
EWBACK;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xF0:
|
||||
return dynarec66F0(dyn, addr, ip, ninst, ok, need_epilog);
|
||||
break;
|
||||
|
||||
case 0xF2:
|
||||
case 0xF3:
|
||||
@@ -928,7 +1040,8 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
|
||||
case 0xA7:
|
||||
if(opcode==0xF2) {INST_NAME("REPNZ CMPSW");} else {INST_NAME("REPZ CMPSW");}
|
||||
SETFLAGS(X_ALL, SF_MAYSET);
|
||||
MAYSETFLAGS();
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
TSTS_REG_LSL_IMM5(xECX, xECX, 0);
|
||||
B_NEXT(cEQ); // end of loop
|
||||
GETDIR(x3, 2);
|
||||
@@ -964,7 +1077,8 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
|
||||
case 0xAF:
|
||||
if(opcode==0xF2) {INST_NAME("REPNZ SCASW");} else {INST_NAME("REPZ SCASW");}
|
||||
SETFLAGS(X_ALL, SF_MAYSET);
|
||||
MAYSETFLAGS();
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
TSTS_REG_LSL_IMM5(xECX, xECX, 0);
|
||||
B_NEXT(cEQ); // end of loop
|
||||
GETDIR(x3, 2);
|
||||
@@ -991,6 +1105,13 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xF5:
|
||||
INST_NAME("CMC");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_CF, SF_SUBSET);
|
||||
XOR_IMM8(xFlags, xFlags, 1<<F_CF);
|
||||
break;
|
||||
|
||||
case 0xF7:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
@@ -1028,28 +1149,29 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 5:
|
||||
INST_NAME("IMUL AX, Ew");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
UFLAG_DF(x1, d_imul16);
|
||||
GETEW(x1);
|
||||
SMULBB(x2, xEAX, ed);
|
||||
UFLAG_RES(x2);
|
||||
BFI(xEAX, x2, 0, 16);
|
||||
MOV_REG_LSR_IMM5(x2, x2, 16);
|
||||
BFI(xEDX, x2, 0, 16);
|
||||
UFLAG_DF(x1, d_imul16);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("DIV Ew");
|
||||
if(arm_div) {
|
||||
GETEW(x1);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_NODF);
|
||||
SET_DFNONE(x2);
|
||||
UXTH(x2, xEAX, 0);
|
||||
ORR_REG_LSL_IMM5(x2, x2, xEDX, 16);
|
||||
UDIV(x3, x2, ed);
|
||||
MLS(x14, x3, ed, x2); // x14 = x2 mod ed (i.e. x2 - x3*ed)
|
||||
BFI(xEAX, x3, 1, 16);
|
||||
BFI(xEDX, x14, 1, 16);
|
||||
BFI(xEAX, x3, 0, 16);
|
||||
BFI(xEDX, x14, 0, 16);
|
||||
} else {
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_DF);
|
||||
GETEW(x1);
|
||||
STM(xEmu, (1<<xEAX) | (1<<xECX) | (1<<xEDX));
|
||||
CALL(div16, -1, 0);
|
||||
@@ -1059,7 +1181,7 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 7:
|
||||
INST_NAME("IDIV Ew");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
SETFLAGS(X_ALL, SF_SET_DF);
|
||||
GETEW(x1);
|
||||
STM(xEmu, (1<<xEAX) | (1<<xECX) | (1<<xEDX));
|
||||
CALL(idiv16, -1, 0);
|
||||
@@ -1086,18 +1208,23 @@ uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("INC Ew");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
GETEW(x1);
|
||||
emit_inc16(dyn, ninst, x1, x2, x14);
|
||||
EWBACK;
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("DEC Ew");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET);
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
GETEW(x1);
|
||||
emit_dec16(dyn, ninst, x1, x2, x14);
|
||||
EWBACK;
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("PUSH Ew");
|
||||
GETEW(x1);
|
||||
PUSH16(x1, xESP);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
|
||||
+850
-225
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,188 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x86emu_private.h"
|
||||
#include "emu/x86run_private.h"
|
||||
#include "x86run.h"
|
||||
#include "x86emu.h"
|
||||
#include "box86stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x86run_private.h"
|
||||
#include "x86trace.h"
|
||||
#include "dynarec_arm.h"
|
||||
#include "dynarec_arm_private.h"
|
||||
#include "arm_printer.h"
|
||||
|
||||
#include "dynarec_arm_functions.h"
|
||||
#include "dynarec_arm_helper.h"
|
||||
|
||||
|
||||
uintptr_t dynarec66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
|
||||
{
|
||||
uint8_t nextop, opcode = F8;
|
||||
uint8_t wback, wb1, wb2, gb1, gb2;
|
||||
uint8_t ed, gd, u8;
|
||||
int fixedaddress;
|
||||
int32_t i32, j32;
|
||||
int16_t i16;
|
||||
MAYUSE(i32);
|
||||
MAYUSE(j32);
|
||||
MAYUSE(gb1);
|
||||
MAYUSE(gb2);
|
||||
MAYUSE(wb1);
|
||||
MAYUSE(wb2);
|
||||
switch(opcode) {
|
||||
case 0x81:
|
||||
case 0x83:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: //ADD
|
||||
if(opcode==0x81) {
|
||||
INST_NAME("LOCK ADD Ew, Iw");
|
||||
} else {
|
||||
INST_NAME("LOCK ADD Ew, Ib");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
if(MODREG) {
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
ed = xEAX+(nextop&7);
|
||||
emit_add16c(dyn, ninst, ed, i16, x3, x14);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 1, LOCK_LOCK);
|
||||
if(opcode==0x81) i16 = F16S; else i16 = F8S;
|
||||
if(!fixedaddress) {
|
||||
TSTS_IMM8(wback, 0x1);
|
||||
B_MARK(cNE);
|
||||
}
|
||||
if(!fixedaddress || (fixedaddress && !(fixedaddress&1))) {
|
||||
MARKLOCK;
|
||||
LDREXH(x1, wback);
|
||||
emit_add16c(dyn, ninst, x1, i16, x3, x14);
|
||||
STREXH(x3, x1, wback);
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
SMDMB();
|
||||
}
|
||||
if(!fixedaddress) {
|
||||
B_NEXT(c__);
|
||||
}
|
||||
if(!fixedaddress || (fixedaddress && (fixedaddress&1))) {
|
||||
MARK; // unaligned! also, not enough
|
||||
LDRH_IMM8(x1, wback, 0);
|
||||
LDREXB(x14, wback);
|
||||
BFI(x1, x14, 0, 8); // re-inject
|
||||
emit_add16c(dyn, ninst, x1, i16, x3, x14);
|
||||
STREXB(x3, x1, wback);
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARK(cNE);
|
||||
STRH_IMM8(x1, wback, 0); // put the whole value
|
||||
SMDMB();
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
SMDMB();
|
||||
break;
|
||||
case 0xFF:
|
||||
nextop = F8;
|
||||
SMDMB();
|
||||
switch((nextop>>3)&7)
|
||||
{
|
||||
case 0: // INC Ew
|
||||
INST_NAME("INC Ew");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
if(MODREG) {
|
||||
GETEW(x1);
|
||||
emit_inc16(dyn, ninst, ed, x3, x14);
|
||||
EWBACK(x1);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 1, LOCK_LOCK);
|
||||
if(!fixedaddress) {
|
||||
TSTS_IMM8(wback, 1);
|
||||
B_MARK(cNE); // unaligned
|
||||
}
|
||||
if(!fixedaddress || (fixedaddress && !(fixedaddress&1))) {
|
||||
MARKLOCK;
|
||||
LDREXH(x1, wback);
|
||||
emit_inc16(dyn, ninst, x1, x3, x14);
|
||||
STREXH(x3, x1, wback);
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
SMDMB();
|
||||
}
|
||||
if(!fixedaddress) {
|
||||
B_NEXT(c__);
|
||||
}
|
||||
if(!fixedaddress || (fixedaddress && (fixedaddress&1))) {
|
||||
MARK;
|
||||
LDRH_IMM8(x1, wback, 0);
|
||||
LDREXB(x3, wback);
|
||||
BFI(x1, x3, 0, 8);
|
||||
emit_inc16(dyn, ninst, x1, x3, x14);
|
||||
STREXB(x3, x1, wback);
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARK(cNE);
|
||||
STRH_IMM8(x1, wback, 0);
|
||||
SMDMB();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 1: //DEC Ew
|
||||
INST_NAME("DEC Ew");
|
||||
SETFLAGS(X_ALL&~X_CF, SF_SUBSET_PENDING);
|
||||
if(MODREG) {
|
||||
GETEW(x1);
|
||||
emit_dec32(dyn, ninst, ed, x3, x14);
|
||||
EWBACK(x1);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 1, LOCK_LOCK);
|
||||
if(!fixedaddress) {
|
||||
TSTS_IMM8(wback, 1);
|
||||
B_MARK(cNE); // unaligned
|
||||
}
|
||||
if(!fixedaddress || (fixedaddress && !(fixedaddress&1))) {
|
||||
MARKLOCK;
|
||||
LDREXH(x1, wback);
|
||||
emit_dec16(dyn, ninst, x1, x3, x14);
|
||||
STREXH(x3, x1, wback);
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARKLOCK(cNE);
|
||||
SMDMB();
|
||||
}
|
||||
if(!fixedaddress) {
|
||||
B_NEXT(c__);
|
||||
}
|
||||
if(!fixedaddress || (fixedaddress && (fixedaddress&3))) {
|
||||
MARK;
|
||||
LDRH_IMM8(x1, wback, 0);
|
||||
LDREXB(x3, wback);
|
||||
BFI(x1, x3, 0, 8);
|
||||
emit_dec16(dyn, ninst, x1, x3, x14);
|
||||
STREXB(x3, x1, wback);
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARK(cNE);
|
||||
STRH_IMM8(x1, wback, 0);
|
||||
SMDMB();
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// default to NO LOCK
|
||||
addr-=2;
|
||||
}
|
||||
SMDMB();
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "dynarec_arm_private.h"
|
||||
#include "arm_printer.h"
|
||||
|
||||
#include "dynarec_arm_functions.h"
|
||||
#include "dynarec_arm_helper.h"
|
||||
|
||||
uintptr_t dynarec67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
|
||||
@@ -29,9 +30,11 @@ uintptr_t dynarec67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
uint32_t u32;
|
||||
uint8_t gd, ed;
|
||||
int fixedaddress;
|
||||
int cacheupd;
|
||||
|
||||
MAYUSE(i32);
|
||||
MAYUSE(j32);
|
||||
MAYUSE(cacheupd);
|
||||
|
||||
nextop = F8;
|
||||
|
||||
@@ -47,7 +50,7 @@ uintptr_t dynarec67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop = F8;
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
GETGD; // don't need GETGW here
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
ed = xEAX+(nextop&7);
|
||||
if(ed!=gd) {
|
||||
BFI(ed, gd, 0, 16);
|
||||
@@ -55,6 +58,7 @@ uintptr_t dynarec67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
} else {
|
||||
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
|
||||
STRH_REG(gd, x14, ed);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -63,12 +67,13 @@ uintptr_t dynarec67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
nextop=F8;
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) { // reg <= reg
|
||||
if(MODREG) { // reg <= reg
|
||||
ed = xEAX+(nextop&7);
|
||||
if(ed!=gd) {
|
||||
BFI(gd, ed, 0, 16);
|
||||
}
|
||||
} else { // mem <= reg
|
||||
SMREAD();
|
||||
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
|
||||
LDR_REG_LSL_IMM5(gd, x14, ed, 0);
|
||||
}
|
||||
@@ -78,12 +83,13 @@ uintptr_t dynarec67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("POP FS:Ew16");
|
||||
nextop=F8;
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
POP1(xEAX+(nextop&7)); // 67 ignored
|
||||
} else {
|
||||
addr = geted16(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
|
||||
POP1(x2);
|
||||
STR_REG_LSL_IMM5(x2, x14, ed, 0);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -95,6 +101,7 @@ uintptr_t dynarec67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
MOV32(x2, u32);
|
||||
ADD_REG_LSL_IMM5(x1, x1, x2, 0);
|
||||
}
|
||||
SMREAD();
|
||||
LDR_IMM9(xEAX, x1, 0);
|
||||
break;
|
||||
|
||||
@@ -107,6 +114,7 @@ uintptr_t dynarec67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
ADD_REG_LSL_IMM5(x1, x1, x2, 0);
|
||||
}
|
||||
STR_IMM9(xEAX, x1, 0);
|
||||
SMWRITE2();
|
||||
break;
|
||||
|
||||
case 0xFF:
|
||||
@@ -115,9 +123,10 @@ uintptr_t dynarec67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
switch((nextop>>3)&7) {
|
||||
case 6: // Push Ed
|
||||
INST_NAME("PUSH FS:Ew");
|
||||
if((nextop&0xC0)==0xC0) { // reg
|
||||
if(MODREG) { // reg
|
||||
DEFAULT;
|
||||
} else { // mem <= i32
|
||||
SMREAD();
|
||||
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
|
||||
LDR_REG_LSL_IMM5(x3, ed, x14, 0);
|
||||
PUSH1(x3);
|
||||
@@ -132,20 +141,27 @@ uintptr_t dynarec67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
}
|
||||
break;
|
||||
|
||||
#define GO(NO, YES) \
|
||||
BARRIER(2); \
|
||||
JUMP(addr+i8, 1); \
|
||||
if(dyn->insts) { \
|
||||
if(dyn->insts[ninst].x86.jmp_insts==-1) { \
|
||||
/* out of the block */ \
|
||||
i32 = dyn->insts[ninst+1].address-(dyn->arm_size+8); \
|
||||
Bcond(NO, i32); \
|
||||
jump_to_next(dyn, addr+i8, 0, ninst); \
|
||||
} else { \
|
||||
/* inside the block */ \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x86.jmp_insts].address-(dyn->arm_size+8); \
|
||||
Bcond(YES, i32); \
|
||||
} \
|
||||
#define GO(NO, YES) \
|
||||
BARRIER(BARRIER_MAYBE); \
|
||||
JUMP(addr+i8, 1); \
|
||||
if(dyn->insts[ninst].x86.jmp_insts==-1 || \
|
||||
CHECK_CACHE()) { \
|
||||
/* out of the block */ \
|
||||
i32 = dyn->insts[ninst].epilog-(dyn->arm_size+8); \
|
||||
Bcond(NO, i32); \
|
||||
if(dyn->insts[ninst].x86.jmp_insts==-1) { \
|
||||
if(!(dyn->insts[ninst].x86.barrier&BARRIER_FLOAT)) \
|
||||
fpu_purgecache(dyn, ninst, 1, x1, x2, x3); \
|
||||
jump_to_next(dyn, addr+i8, 0, ninst); \
|
||||
} else { \
|
||||
CacheTransform(dyn, ninst, cacheupd, x1, x2, x3); \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x86.jmp_insts].address-(dyn->arm_size+8);\
|
||||
Bcond(c__, i32); \
|
||||
} \
|
||||
} else { \
|
||||
/* inside the block */ \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x86.jmp_insts].address-(dyn->arm_size+8); \
|
||||
Bcond(YES, i32); \
|
||||
}
|
||||
case 0xE0:
|
||||
INST_NAME("LOOPNZ (16bits)");
|
||||
|
||||
@@ -33,6 +33,7 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
int d1;
|
||||
int fixedaddress;
|
||||
int parity;
|
||||
uint8_t u8;
|
||||
|
||||
MAYUSE(d1);
|
||||
MAYUSE(s0);
|
||||
@@ -52,11 +53,15 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FADD ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
if(ST_IS_F(0)) {
|
||||
VADD_F32(v1, v1, v2);
|
||||
} else {
|
||||
VADD_F64(v1, v1, v2);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
@@ -69,11 +74,15 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FMUL ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
if(ST_IS_F(0)) {
|
||||
VMUL_F32(v1, v1, v2);
|
||||
} else {
|
||||
VMUL_F64(v1, v1, v2);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
@@ -110,7 +119,7 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
VCMP_F64(v1, v2);
|
||||
}
|
||||
FCOM(x1, x2);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xE0:
|
||||
case 0xE1:
|
||||
@@ -123,11 +132,15 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FSUB ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
if(ST_IS_F(0)) {
|
||||
VSUB_F32(v1, v1, v2);
|
||||
} else {
|
||||
VSUB_F64(v1, v1, v2);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 0xE8:
|
||||
case 0xE9:
|
||||
@@ -140,11 +153,15 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FSUBR ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
if(ST_IS_F(0)) {
|
||||
VSUB_F32(v1, v2, v1);
|
||||
} else {
|
||||
VSUB_F64(v1, v2, v1);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
@@ -157,11 +174,15 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FDIV ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
if(ST_IS_F(0)) {
|
||||
VDIV_F32(v1, v1, v2);
|
||||
} else {
|
||||
VDIV_F64(v1, v1, v2);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 0xF8:
|
||||
case 0xF9:
|
||||
@@ -174,11 +195,15 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FDIVR ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
if(ST_IS_F(0)) {
|
||||
VDIV_F32(v1, v2, v1);
|
||||
} else {
|
||||
VDIV_F64(v1, v2, v1);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -190,18 +215,22 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0, NULL);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
GETED;
|
||||
VMOVtoV(s0, ed);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
if(ST_IS_F(0)) {
|
||||
VADD_F32(v1, v1, s0);
|
||||
} else {
|
||||
VCVT_F64_F32(d1, s0);
|
||||
VADD_F64(v1, v1, d1);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FMUL ST0, float[ED]");
|
||||
@@ -210,18 +239,22 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0, NULL);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
GETED;
|
||||
VMOVtoV(s0, ed);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
if(ST_IS_F(0)) {
|
||||
VMUL_F32(v1, v1, s0);
|
||||
} else {
|
||||
VCVT_F64_F32(d1, s0);
|
||||
VMUL_F64(v1, v1, d1);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FCOM ST0, float[ED]");
|
||||
@@ -230,7 +263,7 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0, NULL);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
GETED;
|
||||
@@ -251,7 +284,7 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0, NULL);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
GETED;
|
||||
@@ -264,7 +297,7 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
VCMP_F64(v1, d1);
|
||||
}
|
||||
FCOM(x1, x2);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FSUB ST0, float[ED]");
|
||||
@@ -273,18 +306,22 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0, NULL);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
GETED;
|
||||
VMOVtoV(s0, ed);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
if(ST_IS_F(0)) {
|
||||
VSUB_F32(v1, v1, s0);
|
||||
} else {
|
||||
VCVT_F64_F32(d1, s0);
|
||||
VSUB_F64(v1, v1, d1);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FSUBR ST0, float[ED]");
|
||||
@@ -293,18 +330,22 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0, NULL);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
GETED;
|
||||
VMOVtoV(s0, ed);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
if(ST_IS_F(0)) {
|
||||
VSUB_F32(v1, s0, v1);
|
||||
} else {
|
||||
VCVT_F64_F32(d1, s0);
|
||||
VSUB_F64(v1, d1, v1);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FDIV ST0, float[ED]");
|
||||
@@ -313,18 +354,22 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0, NULL);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
GETED;
|
||||
VMOVtoV(s0, ed);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
if(ST_IS_F(0)) {
|
||||
VDIV_F32(v1, v1, s0);
|
||||
} else {
|
||||
VCVT_F64_F32(d1, s0);
|
||||
VDIV_F64(v1, v1, d1);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FDIVR ST0, float[ED]");
|
||||
@@ -333,18 +378,22 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0, NULL);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
GETED;
|
||||
VMOVtoV(s0, ed);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
if(ST_IS_F(0)) {
|
||||
VDIV_F32(v1, s0, v1);
|
||||
} else {
|
||||
VCVT_F64_F32(d1, s0);
|
||||
VDIV_F64(v1, d1, v1);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
|
||||
+301
-119
@@ -34,11 +34,15 @@ static const float f_pi = PI;
|
||||
static const float f_lg2 = LG2;
|
||||
static const float f_ln2 = LN2;
|
||||
|
||||
extern int arm_v8;
|
||||
|
||||
static const void* round_map[4] = {nearbyint, floor, ceil, trunc};
|
||||
uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
|
||||
{
|
||||
uint8_t nextop = F8;
|
||||
uint8_t ed;
|
||||
uint8_t wback, wb1;
|
||||
uint8_t u8;
|
||||
int fixedaddress;
|
||||
int v1, v2;
|
||||
int s0;
|
||||
@@ -50,6 +54,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
MAYUSE(j32);
|
||||
(void)u8;
|
||||
|
||||
switch(nextop) {
|
||||
|
||||
@@ -62,16 +67,19 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
INST_NAME("FLD STx");
|
||||
v2 = x87_do_push(dyn, ninst, x3, X87_ST(nextop&7));
|
||||
X87_PUSH_OR_FAIL(v2, dyn, ninst, x3, X87_ST(nextop&7));
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, (nextop&7)+1, X87_COMBINE(0, (nextop&7)+1));
|
||||
if(ST_IS_F(0)) {
|
||||
VMOV_32(v2, v1);
|
||||
} else {
|
||||
VMOV_64(v2, v1);
|
||||
}
|
||||
// should set C1 to 0
|
||||
break;
|
||||
|
||||
case 0xC8:
|
||||
INST_NAME("FXCH ST0");
|
||||
break;
|
||||
case 0xC9:
|
||||
case 0xCA:
|
||||
case 0xCB:
|
||||
@@ -81,17 +89,8 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xCF:
|
||||
INST_NAME("FXCH STx");
|
||||
// swap the cache value, not the double value itself :p
|
||||
i1 = x87_get_cache(dyn, ninst, 1, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
i2 = x87_get_cache(dyn, ninst, 1, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
i3 = dyn->x87cache[i1];
|
||||
dyn->x87cache[i1] = dyn->x87cache[i2];
|
||||
dyn->x87cache[i2] = i3;
|
||||
// swap those too
|
||||
i1 = x87_get_neoncache(dyn, ninst, x1, x2, nextop&7);
|
||||
i2 = x87_get_neoncache(dyn, ninst, x1, x2, 0);
|
||||
i3 = dyn->n.neoncache[i1].v;
|
||||
dyn->n.neoncache[i1].v = dyn->n.neoncache[i2].v;
|
||||
dyn->n.neoncache[i2].v = i3;
|
||||
x87_swapreg(dyn, ninst, x1, x2, 0, nextop&7);
|
||||
// should set C1 to 0
|
||||
break;
|
||||
|
||||
case 0xD0:
|
||||
@@ -106,6 +105,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
} else {
|
||||
VNEG_F64(v1, v1);
|
||||
}
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xE1:
|
||||
INST_NAME("FABS");
|
||||
@@ -115,6 +115,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
} else {
|
||||
VABS_F64(v1, v1);
|
||||
}
|
||||
// should set C1 to 0
|
||||
break;
|
||||
|
||||
case 0xE4:
|
||||
@@ -133,28 +134,52 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
i1 = x87_get_current_cache(dyn, ninst, 0, NEON_CACHE_ST_D);
|
||||
// value put in x14
|
||||
if(i1==-1) {
|
||||
// not in cache, so check Empty status and load it
|
||||
// x14 will be the actual top
|
||||
LDR_IMM9(x14, xEmu, offsetof(x86emu_t, top));
|
||||
i2 = -dyn->x87stack;
|
||||
if(i2) {
|
||||
if(i2<0) {
|
||||
SUB_IMM8(x14, x14, -i2);
|
||||
} else {
|
||||
ADD_IMM8(x14, x14, i2);
|
||||
if(fpu_is_st_freed(dyn, ninst, 0)) {
|
||||
MOV32(x14, 0b100000100000000);
|
||||
B_MARK3(c__);
|
||||
} else { // not in cache, so check Empty status and load it
|
||||
// load tag
|
||||
LDRH_IMM8(x3, xEmu, offsetof(x86emu_t, fpu_tags));
|
||||
if(i2) {
|
||||
if(i2<0) {
|
||||
MOV_REG_LSL_IMM5(x3, x3, -i2*2);
|
||||
} else {
|
||||
MOV32(x14, 0xffff);
|
||||
ORR_REG_LSL_IMM5(x3, x3, x14, 16);
|
||||
MOV_REG_LSR_IMM5(x3, x3, i2*2);
|
||||
}
|
||||
}
|
||||
AND_IMM8(x14, x14, 7); // (emu->top + i)&7
|
||||
TSTS_IMM8(x3, 0b11);
|
||||
MOVW(x14, 0b100000100000000); // empty
|
||||
B_MARK3(cNE);
|
||||
// check stack TODO: this test should not be needed, something is wrong with tag handling
|
||||
LDR_IMM9(x3, xEmu, offsetof(x86emu_t, fpu_stack));
|
||||
if(i2) {
|
||||
if(i2<0) {
|
||||
ADD_IMM8(x3, x3, -i2);
|
||||
} else {
|
||||
SUB_IMM8(x3, x3, i2);
|
||||
}
|
||||
}
|
||||
CMPS_IMM8(x3, 0);
|
||||
B_MARK3(cLE);
|
||||
// x14 will be the actual top
|
||||
LDR_IMM9(x14, xEmu, offsetof(x86emu_t, top));
|
||||
i2 = -dyn->n.x87stack;
|
||||
if(i2) {
|
||||
if(i2<0) {
|
||||
SUB_IMM8(x14, x14, -i2);
|
||||
} else {
|
||||
ADD_IMM8(x14, x14, i2);
|
||||
}
|
||||
AND_IMM8(x14, x14, 7); // (emu->top + i)&7
|
||||
}
|
||||
ADD_REG_LSL_IMM5(x1, xEmu, x14, 3);
|
||||
LDRD_IMM8(x2, x1, offsetof(x86emu_t, x87)); // load r2/r3 with ST0 anyway, for sign extraction
|
||||
}
|
||||
ADD_REG_LSL_IMM5(x1, xEmu, x14, 3);
|
||||
LDRD_IMM8(x2, x1, offsetof(x86emu_t, x87)); // load r2/r3 with ST0 anyway, for sign extraction
|
||||
ADD_REG_LSL_IMM5(x1, xEmu, x14, 2);
|
||||
LDR_IMM9(x1, x1, offsetof(x86emu_t, p_regs));
|
||||
CMPS_IMM8(x1, 0b11);
|
||||
MOVW_COND(cEQ, x14, 0b100000100000000); // empty: C3,C2,C0 = 101
|
||||
B_MARK3(cEQ);
|
||||
} else {
|
||||
// simply move from cache reg to r2/r3
|
||||
v1 = dyn->x87reg[i1];
|
||||
v1 = dyn->n.x87reg[i1];
|
||||
VMOVfrV_D(x2, x3, v1);
|
||||
}
|
||||
// get exponant in r1
|
||||
@@ -193,16 +218,17 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
|
||||
case 0xE8:
|
||||
INST_NAME("FLD1");
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0)) {
|
||||
VMOV_i_32(v1, 0b01110000);
|
||||
} else {
|
||||
VMOV_i_64(v1, 0b01110000);
|
||||
}
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xE9:
|
||||
INST_NAME("FLDL2T");
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0)) {
|
||||
MOV32(x2, (&f_l2t));
|
||||
VLDR_32(v1, x2, 0);
|
||||
@@ -210,10 +236,11 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
MOV32(x2, (&d_l2t));
|
||||
VLDR_64(v1, x2, 0);
|
||||
}
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xEA:
|
||||
INST_NAME("FLDL2E");
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0)) {
|
||||
MOV32(x2, (&f_l2e));
|
||||
VLDR_32(v1, x2, 0);
|
||||
@@ -221,10 +248,11 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
MOV32(x2, (&d_l2e));
|
||||
VLDR_64(v1, x2, 0);
|
||||
}
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xEB:
|
||||
INST_NAME("FLDPI");
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0)) {
|
||||
MOV32(x2, (&f_pi));
|
||||
VLDR_32(v1, x2, 0);
|
||||
@@ -232,10 +260,11 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
MOV32(x2, (&d_pi));
|
||||
VLDR_64(v1, x2, 0);
|
||||
}
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xEC:
|
||||
INST_NAME("FLDLG2");
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0)) {
|
||||
MOV32(x2, (&f_lg2));
|
||||
VLDR_32(v1, x2, 0);
|
||||
@@ -243,10 +272,11 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
MOV32(x2, (&d_lg2));
|
||||
VLDR_64(v1, x2, 0);
|
||||
}
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xED:
|
||||
INST_NAME("FLDLN2");
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0)) {
|
||||
MOV32(x2, (&f_ln2));
|
||||
VLDR_32(v1, x2, 0);
|
||||
@@ -254,101 +284,153 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
MOV32(x2, (&d_ln2));
|
||||
VLDR_64(v1, x2, 0);
|
||||
}
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xEE:
|
||||
INST_NAME("FLDZ");
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0)) {
|
||||
VMOV_8(v1/2, 0); // float is *2...
|
||||
} else {
|
||||
VMOV_8(v1, 0); // cannot use VMOV_i_F64
|
||||
}
|
||||
// should set C1 to 0
|
||||
break;
|
||||
|
||||
case 0xFA:
|
||||
INST_NAME("FSQRT");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
if(ST_IS_F(0)) {
|
||||
VSQRT_F32(v1, v1);
|
||||
} else {
|
||||
VSQRT_F64(v1, v1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xFC:
|
||||
INST_NAME("FRNDINT");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
// use C helper for now, nothing staightforward is available
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
CALL(arm_frndint, -1, 0);
|
||||
/*
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
VCMP_F64_0(v1);
|
||||
VMRS_APSR();
|
||||
B_NEXT(cVS); // Unordered, skip
|
||||
B_NEXT(cEQ); // Zero, skip
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x3);
|
||||
VCVT_S32_F64(x1, v1); // limit to 32bits....
|
||||
VCVT_F64_S32(v1, x1);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
*/
|
||||
break;
|
||||
case 0xF0:
|
||||
INST_NAME("F2XM1");
|
||||
#if 0
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
CALL(arm_f2xm1, -1, 0);
|
||||
#else
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
if((PK(0)==0xD9 && PK(1)==0xE8) && // next inst is FLD1
|
||||
(PK(2)==0xDE && PK(3)==0xC1)) {
|
||||
MESSAGE(LOG_DUMP, "Hack for fld1 / faddp st1, st0\n");
|
||||
VMOV_64(0, v1);
|
||||
CALL_1D(exp2, 0); // return is d0
|
||||
VMOV_64(v1, 0);
|
||||
addr+=4;
|
||||
} else {
|
||||
//ST0.d = expm1(LN2 * ST0.d);
|
||||
MOV32(x2, (&d_ln2));
|
||||
VLDR_64(0, x2, 0);
|
||||
VMUL_F64(0, 0, v1);
|
||||
CALL_1D(expm1, 0); // return is d0
|
||||
VMOV_64(v1, 0);
|
||||
}
|
||||
#endif
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xF1:
|
||||
INST_NAME("FYL2X");
|
||||
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);
|
||||
|
||||
VMOV_64(0, v1); // prepare call to log2
|
||||
CALL_1D(log2, 0);
|
||||
VMUL_F64(v2, v2, 0); //ST(1).d = log2(ST0.d)*ST(1).d
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xF2:
|
||||
INST_NAME("FTAN");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
INST_NAME("FPTAN");
|
||||
X87_PUSH_OR_FAIL(v2, dyn, ninst, x1, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 1, NEON_CACHE_ST_D);
|
||||
// seems that tan of glib doesn't follow the rounding direction mode
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
VMOV_64(0, v1); // prepare call to tan
|
||||
CALL_1D(tan, 0);
|
||||
CALL_1D(tan, box86_dynarec_fastround ? 0 : (1 << u8));
|
||||
VMOV_64(v1, 0);
|
||||
//emu->sw.f.F87_C2 = 0;
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
//emu->sw.f.F87_C2 = 0;
|
||||
//emu->sw.f.F87_C1 = 0;
|
||||
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
BFC(x1, 10, 1); //C2 = 0
|
||||
BFC(x1, 9, 2); //C1 C2 = 0 0
|
||||
STRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
v2 = x87_do_push(dyn, ninst, x3, NEON_CACHE_ST_D);
|
||||
// so here: F64: Imm8 = abcd efgh that gives => aBbbbbbb bbcdefgh 0000000 00000000 00000000...
|
||||
// and want 1.0 = 0x3ff0000000000000
|
||||
// so 00111111 11110000 00000000 00000000....
|
||||
// a = 0, b = 1, c = 1, d = 1, efgh=0
|
||||
// 0b01110000
|
||||
VMOV_i_64(v2, 0b01110000);
|
||||
if(PK(0)==0xdd && PK(1)==0xd8) {
|
||||
MESSAGE(LOG_DUMP, "Optimized next DD D8 fstp st0, st0, not emiting 1\n");
|
||||
} else {
|
||||
// so here: F64: Imm8 = abcd efgh that gives => aBbbbbbb bbcdefgh 0000000 00000000 00000000...
|
||||
// and want 1.0 = 0x3ff0000000000000
|
||||
// so 00111111 11110000 00000000 00000000....
|
||||
// a = 0, b = 1, c = 1, d = 1, efgh=0
|
||||
// 0b01110000
|
||||
if(ST_IS_F(0)) {
|
||||
VMOV_i_32(v2, 0b01110000);
|
||||
} else {
|
||||
VMOV_i_64(v2, 0b01110000);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xF3:
|
||||
INST_NAME("FPATAN");
|
||||
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);
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
VMOV_64(0, v2); // prepare call to atan2
|
||||
VMOV_64(1, v1);
|
||||
CALL_2D(atan2, 0);
|
||||
CALL_2D(atan2, box86_dynarec_fastround ? 0 : (1 << u8));
|
||||
VMOV_64(v2, 0); //ST(1).d = atan2(ST1.d, ST0.d);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xF4:
|
||||
INST_NAME("FXTRACT");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_do_push_empty(dyn, ninst, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
s0 = x87_stackcount(dyn, ninst, x3);
|
||||
CALL(arm_fxtract, -1, 0);
|
||||
x87_unstackcount(dyn, ninst, x3, s0);
|
||||
// C1 set only if stack under/overflow occurs
|
||||
break;
|
||||
case 0xF5:
|
||||
INST_NAME("FPREM1");
|
||||
#if 0
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fprem1, -1, 0);
|
||||
#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_double(dyn);
|
||||
VDIV_F64(s0, v1, v2);
|
||||
// set rounding to Nearest
|
||||
MOVW(x2, 1); // Nearest
|
||||
VMRS(x1); // get fpscr
|
||||
MOV_REG(x14, x1);
|
||||
BFI(x1, x2, 22, 2); // inject new round
|
||||
VMSR(x1); // put new fpscr
|
||||
VCVTR_S32_F64(s0*2, s0); // => Q
|
||||
// set back rounding
|
||||
VMSR(x14);
|
||||
// get Q
|
||||
VMOVfrV(x14, s0*2);
|
||||
// Put back Q in a double
|
||||
VCVT_F64_S32(s0, s0*2);
|
||||
VMUL_F64(s0, s0, v2);
|
||||
VSUB_F64(v1, v1, s0);
|
||||
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
// set C2 = 0
|
||||
BFC(x1, 10, 1);
|
||||
// set C1 = Q0
|
||||
BFI(x1, x14, 9, 1);
|
||||
// set C3 = Q1
|
||||
MOV_REG_LSR_IMM5(x14, x14, 1);
|
||||
BFI(x1, x14, 14, 1);
|
||||
// Set C0 = Q2
|
||||
MOV_REG_LSR_IMM5(x14, x14, 1);
|
||||
BFI(x1, x14, 8, 1);
|
||||
STR_IMM9(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
#endif
|
||||
break;
|
||||
case 0xF6:
|
||||
INST_NAME("FDECSTP");
|
||||
@@ -357,6 +439,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
SUB_IMM8(x2, x2, 1);
|
||||
AND_IMM8(x2, x2, 7);
|
||||
STR_IMM9(x2, xEmu, offsetof(x86emu_t, top));
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xF7:
|
||||
INST_NAME("FINCSTP");
|
||||
@@ -365,71 +448,163 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
ADD_IMM8(x2, x2, 1);
|
||||
AND_IMM8(x2, x2, 7);
|
||||
STR_IMM9(x2, xEmu, offsetof(x86emu_t, top));
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xF8:
|
||||
INST_NAME("FPREM");
|
||||
#if 0
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fprem, -1, 0);
|
||||
#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_double(dyn);
|
||||
VDIV_F64(s0, v1, v2);
|
||||
VCVT_S32_F64(s0*2, s0); // => Q
|
||||
// get Q
|
||||
VMOVfrV(x14, s0*2);
|
||||
// Put back Q in a double
|
||||
VCVT_F64_S32(s0, s0*2);
|
||||
VMUL_F64(s0, s0, v2);
|
||||
VSUB_F64(v1, v1, s0);
|
||||
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
// set C2 = 0
|
||||
BFC(x1, 10, 1);
|
||||
// set C1 = Q0
|
||||
BFI(x1, x14, 9, 1);
|
||||
// set C3 = Q1
|
||||
MOV_REG_LSR_IMM5(x14, x14, 1);
|
||||
BFI(x1, x14, 14, 1);
|
||||
// Set C0 = Q2
|
||||
MOV_REG_LSR_IMM5(x14, x14, 1);
|
||||
BFI(x1, x14, 8, 1);
|
||||
STR_IMM9(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
#endif
|
||||
break;
|
||||
case 0xF9:
|
||||
INST_NAME("FYL2XP1");
|
||||
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);
|
||||
VMOV_i_64(0, 0b01110000); // D0 = 1.0
|
||||
VADD_F64(0, 0, v1); // prepare call to log2
|
||||
CALL_1D(log2, 0);
|
||||
VMUL_F64(v2, v2, 0); //ST(1).d = log2(ST0.d + 1.0)*ST(1).d;
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
|
||||
//ST(1).d = (ST(1).d * log1p(ST0.d)) / M_LN2;
|
||||
VMOV_64(0, v1); // prepare call to log1p
|
||||
CALL_1D(log1p, 0);
|
||||
VMUL_F64(v2, v2, 0);
|
||||
MOV32(x2, (&d_ln2));
|
||||
VLDR_64(0, x2, 0);
|
||||
VDIV_F64(v2, v2, 0);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xFA:
|
||||
INST_NAME("FSQRT");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
if(ST_IS_F(0)) {
|
||||
VSQRT_F32(v1, v1);
|
||||
} else {
|
||||
VSQRT_F64(v1, v1);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xFB:
|
||||
INST_NAME("FSINCOS");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = x87_do_push(dyn, ninst, x3, NEON_CACHE_ST_D);
|
||||
X87_PUSH_OR_FAIL(v2, dyn, ninst, x3, NEON_CACHE_ST_D);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 1, NEON_CACHE_ST_D);
|
||||
// seems that sin and cos function of glibc don't follow the rounding mode
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
VMOV_64(0, v1);
|
||||
CALL_1D(sin, 0);
|
||||
CALL_1D(sin, box86_dynarec_fastround ? 0 : (1 << u8));
|
||||
VSWP(v1, 0);
|
||||
CALL_1D(cos, 0);
|
||||
CALL_1D(cos, box86_dynarec_fastround ? 0 : (1 << u8)); // would it be faster to do sqrt(1-sin()²) ???
|
||||
VMOV_64(v2, 0);
|
||||
//emu->sw.f.F87_C2 = 0;
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
//emu->sw.f.F87_C2 = 0; C1 too
|
||||
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
BFC(x1, 10, 1); //C2 = 0
|
||||
BFC(x1, 9, 2); //C2 C1 = 0 0
|
||||
STRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
break;
|
||||
case 0xFC:
|
||||
INST_NAME("FRNDINT");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
if(!arm_v8) {
|
||||
// check if finite first
|
||||
VCMP_F64_0(v1);
|
||||
VMRS_APSR();
|
||||
B_NEXT(cVS); // Unordered, skip
|
||||
B_NEXT(cEQ); // Zero, skip
|
||||
// load round mode
|
||||
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, cw)); // hopefully cw is not too far for an imm8
|
||||
UBFX(x2, x1, 10, 2); // extract round...
|
||||
MOV32(x1, round_map);
|
||||
LDR_REG_LSL_IMM5(x2, x1, x2, 2);
|
||||
VMOV_64(0, v1); // prepare call to fpu_round
|
||||
CALL_1DR(x2, x3, 0);
|
||||
VMOV_64(v1, 0);
|
||||
} else {
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
VRINTR_F64(v1, v1);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
}
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xFD:
|
||||
INST_NAME("FSCALE");
|
||||
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);
|
||||
//if(ST0.d!=0.0)
|
||||
// ST0.d *= exp2(trunc(ST1.d));
|
||||
VCMP_F64_0(v1);
|
||||
VMRS_APSR();
|
||||
B_NEXT(cEQ);
|
||||
VMOV_64(0, v2);
|
||||
CALL_1DD(trunc, exp2, 0);
|
||||
VMUL_F64(v1, v1, 0);
|
||||
// ST0.d = ldexp(ST0.d, trunc(ST1.d));
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
// value of s0 =
|
||||
// 2^31-1 (ST1 >= 2^31), -2^31 (ST1 < -2^31) or int(ST1) (other situations)
|
||||
VCVT_S32_F64(s0 , v2);
|
||||
VMOVfrV(x2, s0);
|
||||
VMOV_64(0, v1);
|
||||
CALL_1DDR(ldexp, x2, x3, box86_dynarec_fastround ? 0 : (1 << u8));
|
||||
VMOV_64(v1, 0);
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 0xFE:
|
||||
INST_NAME("FSIN");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
// seems that sin of glib doesn't follow the rounding direction mode
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
VMOV_64(0, v1); // prepare call to sin
|
||||
CALL_1D(sin, 0);
|
||||
CALL_1D(sin, box86_dynarec_fastround ? 0 : (1 << u8));
|
||||
VMOV_64(v1, 0);
|
||||
//emu->sw.f.F87_C2 = 0;
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
//emu->sw.f.F87_C2 = 0; C1 too
|
||||
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
BFC(x1, 10, 1); //C2 = 0
|
||||
BFC(x1, 9, 2); //C2 C1 = 0 0
|
||||
STRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
break;
|
||||
case 0xFF:
|
||||
INST_NAME("FCOS");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
// seems that cos of glib doesn't follow the rounding direction mode
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
VMOV_64(0, v1); // prepare call to cos
|
||||
CALL_1D(cos, 0);
|
||||
CALL_1D(cos, box86_dynarec_fastround ? 0 : (1 << u8));
|
||||
VMOV_64(v1, 0);
|
||||
//emu->sw.f.F87_C2 = 0;
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
//emu->sw.f.F87_C2 = 0; C1 too
|
||||
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
BFC(x1, 10, 1); //C2 = 0
|
||||
BFC(x1, 9, 2); //C2 C1 = 0 0
|
||||
STRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
break;
|
||||
|
||||
@@ -459,68 +634,77 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FLD ST0, float[ED]");
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0))
|
||||
s0 = v1;
|
||||
else
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0, NULL);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0, NULL);
|
||||
LDR_IMM9(x2, ed, fixedaddress);
|
||||
VMOVtoV(s0, x2);
|
||||
}
|
||||
if(!ST_IS_F(0)) {
|
||||
VCVT_F64_F32(v1, s0);
|
||||
}
|
||||
// should set C1 to 0
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FST float[ED], ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_F);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0))
|
||||
s0 = v1;
|
||||
else {
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
VCVT_F32_F64(s0, v1);
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
}
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0, NULL);
|
||||
VSTR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0, NULL);
|
||||
VMOVfrV(x2, s0);
|
||||
STR_IMM9(x2, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FSTP float[ED], ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_F);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0))
|
||||
s0 = v1;
|
||||
else {
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
VCVT_F32_F64(s0, v1);
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
}
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0, NULL);
|
||||
VSTR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0, NULL);
|
||||
VMOVfrV(x2, s0);
|
||||
STR_IMM9(x2, ed, fixedaddress);
|
||||
}
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FLDENV Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3); // maybe only x87, not SSE?
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
if(ed!=x1) {
|
||||
MOV_REG(x1, ed);
|
||||
}
|
||||
@@ -531,14 +715,12 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FLDCW Ew");
|
||||
GETEW(x1);
|
||||
STRH_IMM8(x1, xEmu, offsetof(x86emu_t, cw)); // hopefully cw is not too far for an imm8
|
||||
UBFX(x1, x1, 10, 2); // extract round
|
||||
STR_IMM9(x1, xEmu, offsetof(x86emu_t, round));
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FNSTENV Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3); // maybe only x87, not SSE?
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
if(ed!=x1) {
|
||||
MOV_REG(x1, ed);
|
||||
}
|
||||
@@ -547,7 +729,7 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FNSTCW Ew");
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0, NULL);
|
||||
ed = x1;
|
||||
wb1 = 1;
|
||||
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, cw));
|
||||
|
||||
@@ -33,6 +33,7 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
int d0;
|
||||
int s0;
|
||||
int fixedaddress;
|
||||
uint8_t u8;
|
||||
|
||||
MAYUSE(s0);
|
||||
MAYUSE(d0);
|
||||
@@ -128,8 +129,8 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
VCMP_F64(v1, v2);
|
||||
}
|
||||
FCOM(x1, x2);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
case 0xE4:
|
||||
@@ -155,7 +156,11 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
VMOVtoV(s0, ed);
|
||||
VCVT_F64_S32(d0, s0);
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
VADD_F64(v1, v1, d0);
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FIMUL ST0, Ed");
|
||||
@@ -165,7 +170,11 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
VMOVtoV(s0, ed);
|
||||
VCVT_F64_S32(d0, s0);
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
VMUL_F64(v1, v1, d0);
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FICOM ST0, Ed");
|
||||
@@ -188,7 +197,7 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
VCVT_F64_S32(d0, s0);
|
||||
VCMP_F64(v1, d0);
|
||||
FCOM(x1, x2);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FISUB ST0, Ed");
|
||||
@@ -198,7 +207,11 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
VMOVtoV(s0, ed);
|
||||
VCVT_F64_S32(d0, s0);
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
VSUB_F64(v1, v1, d0);
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FISUBR ST0, Ed");
|
||||
@@ -208,7 +221,11 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
VMOVtoV(s0, ed);
|
||||
VCVT_F64_S32(d0, s0);
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
VSUB_F64(v1, d0, v1);
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FIDIV ST0, Ed");
|
||||
@@ -218,7 +235,11 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
VMOVtoV(s0, ed);
|
||||
VCVT_F64_S32(d0, s0);
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
VDIV_F64(v1, v1, d0);
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FIDIVR ST0, Ed");
|
||||
@@ -228,7 +249,11 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
VMOVtoV(s0, ed);
|
||||
VCVT_F64_S32(d0, s0);
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
VDIV_F64(v1, d0, v1);
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
+141
-42
@@ -122,9 +122,8 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xE2:
|
||||
INST_NAME("FNCLEX");
|
||||
LDRH_IMM8(x2, xEmu, offsetof(x86emu_t, sw));
|
||||
MOVW(x1, 0);
|
||||
BFI(x2, x1, 0, 8); // IE .. PE, SF, ES
|
||||
BFI(x2, x1, 15, 1); // B
|
||||
BFC(x2, 0, 8); // IE .. PE, SF, ES
|
||||
BFC(x2, 15, 1); // B
|
||||
STRH_IMM8(x2, xEmu, offsetof(x86emu_t, sw));
|
||||
break;
|
||||
case 0xE3:
|
||||
@@ -142,7 +141,7 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
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));
|
||||
if(ST_IS_F(0)) {
|
||||
@@ -161,7 +160,7 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
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));
|
||||
if(ST_IS_F(0)) {
|
||||
@@ -184,11 +183,11 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FILD ST0, Ed");
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0, NULL);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
GETED;
|
||||
@@ -203,13 +202,13 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
ed = xEAX+(nextop&7);
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 4095, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 4095, 0, 0, NULL);
|
||||
ed = x1;
|
||||
}
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
MSR_nzcvq_0();
|
||||
VMRS(x14); // Get FPCSR reg to clear exceptions flags
|
||||
ORR_IMM8(x3, x14, 0b001, 6); // enable exceptions
|
||||
ORR_IMM8(x3, x14, 0b010, 9); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
VCVT_S32_F64(s0, v1);
|
||||
@@ -219,25 +218,21 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
MOV_IMM_COND(cNE, ed, 0b10, 1); // 0x80000000
|
||||
WBACK;
|
||||
VMSR(x14); // put back values
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FIST Ed, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14); // x1 have the modified RPSCR reg
|
||||
u8 = x87_setround_reset(dyn, ninst, x1, x2, x14); // x1 have the modified RPSCR reg
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xEAX+(nextop&7);
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 4095, 0, 0);
|
||||
ed = x1;
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 4095, 0, 0, NULL);
|
||||
ed = x1; // will not be writen immediatly, so x1 is safe for now
|
||||
}
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
MSR_nzcvq_0();
|
||||
// x1 already have FPCSR reg to clear exceptions flags
|
||||
ORR_IMM8(x3, x1, 0b001, 6); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
VCVTR_S32_F64(s0, v1);
|
||||
VMRS(x3); // get the FPCSR reg and test FPU execption (invalid operation only)
|
||||
VMOVfrV(ed, s0);
|
||||
@@ -249,64 +244,168 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 3:
|
||||
INST_NAME("FISTP Ed, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14); // x1 have the modified RPSCR reg
|
||||
u8 = x87_setround_reset(dyn, ninst, x1, x2, x14); // x1 have the modified RPSCR reg
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xEAX+(nextop&7);
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 4095, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 4095, 0, 0, NULL);
|
||||
ed = x1;
|
||||
}
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
MSR_nzcvq_0();
|
||||
// The FPCSR reg to clear exceptions flags
|
||||
ORR_IMM8(x3, x1, 0b001, 6); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
VCVTR_S32_F64(s0, v1);
|
||||
VMRS(x3); // get the FPCSR reg and test FPU execption (denormal and overflow only)
|
||||
VMOVfrV(ed, s0);
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
MOV_IMM_COND(cNE, ed, 0b10, 1); // 0x80000000
|
||||
WBACK;
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FLD tbyte");
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
if(PK(0)==0xDB && ((PK(1)>>3)&7)==7) {
|
||||
// the FLD is immediatly followed by an FSTP
|
||||
LDR_IMM9(x2, ed, 0);
|
||||
LDR_IMM9(x3, ed, 4);
|
||||
LDM(ed, (1<<x2)|(1<<x3));
|
||||
LDRH_IMM8(x14, ed, 8);
|
||||
// no persistant scratch register, so unrool both instruction here...
|
||||
MESSAGE(LOG_DUMP, "\tHack: FSTP tbyte\n");
|
||||
nextop = F8; //0xDB
|
||||
nextop = F8; //modrm
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
STR_IMM9(x2, ed, 0);
|
||||
STR_IMM9(x3, ed, 4);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
STM(ed, (1<<x2)|(1<<x3));
|
||||
STRH_IMM8(x14, ed, 8);
|
||||
} else {
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
if(ed!=x1) {
|
||||
MOV_REG(x1, ed);
|
||||
if(box86_x87_no80bits) {
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 3);
|
||||
if (parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0, NULL);
|
||||
VLDR_64(v1, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0, NULL);
|
||||
LDR_IMM9(x2, ed, fixedaddress);
|
||||
LDR_IMM9(x3, ed, fixedaddress + 4);
|
||||
VMOVtoV_D(v1, x2, x3);
|
||||
}
|
||||
} else {
|
||||
#if 0
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
if(ed!=x1) {
|
||||
MOV_REG(x1, ed);
|
||||
}
|
||||
X87_PUSH_OR_FAIL_empty( , dyn, ninst, x3);
|
||||
CALL(arm_fld, -1, 0);
|
||||
#else
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x2, NEON_CACHE_ST_D);
|
||||
// copy 10bytes of *ED to STld(0)
|
||||
LDR_IMM9(x3, xEmu, offsetof(x86emu_t, top));
|
||||
int a = -dyn->n.x87stack;
|
||||
if(a) {
|
||||
if(a<0) {
|
||||
SUB_IMM8(x3, x3, -a);
|
||||
} else {
|
||||
ADD_IMM8(x3, x3, a);
|
||||
}
|
||||
AND_IMM8(x3, x3, 7);
|
||||
}
|
||||
ADD_IMM8(x2, xEmu, offsetof(x86emu_t, fpu_ld)+offsetof(fpu_ld_t, ld));
|
||||
MOVW(x14, sizeof(fpu_ld_t));
|
||||
MLA(x2, x3, x14, x2);
|
||||
LDR_IMM9(x14, ed, 0);
|
||||
STR_IMM9(x14, x2, 0);
|
||||
LDR_IMM9(x14, ed, 4);
|
||||
STR_IMM9(x14, x2, 4);
|
||||
LDRH_IMM8(x14, ed, 8);
|
||||
STRH_IMM8(x14, x2, 8);
|
||||
// convert 10bytes -> double
|
||||
CALL_1RD(FromLD, ed, x2, (1<<x3)|(1<<xFlags)|(1<<x2));
|
||||
// store ref to STld(0).uref, but can be unaligned...
|
||||
VMOVfrV_D(x3, x14, 0);
|
||||
// also, store result to ST0
|
||||
VMOVD(v1, 0);
|
||||
STR_IMM9(x3, x2, offsetof(fpu_ld_t, uref)-offsetof(fpu_ld_t, ld));
|
||||
STR_IMM9(x14, x2, offsetof(fpu_ld_t, uref)-offsetof(fpu_ld_t, ld)+4);
|
||||
#endif
|
||||
}
|
||||
x87_do_push_empty(dyn, ninst, x3);
|
||||
CALL(arm_fld, -1, 0);
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FSTP tbyte");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
if(ed!=x1) {
|
||||
MOV_REG(x1, ed);
|
||||
if(box86_x87_no80bits) {
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 3);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0, NULL);
|
||||
VSTR_64(v1, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0, NULL);
|
||||
VMOVfrV_D(x2, x3, v1);
|
||||
STR_IMM9(x2, ed, fixedaddress);
|
||||
STR_IMM9(x3, ed, fixedaddress+4);
|
||||
}
|
||||
} else {
|
||||
#if 0
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
if(ed!=x1) {
|
||||
MOV_REG(x1, ed);
|
||||
}
|
||||
CALL(arm_fstp, -1, 0);
|
||||
#else
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch_double(dyn);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
// get top in x3
|
||||
LDR_IMM9(x3, xEmu, offsetof(x86emu_t, top));
|
||||
int a = -dyn->n.x87stack;
|
||||
if(a) {
|
||||
if(a<0) {
|
||||
SUB_IMM8(x3, x3, -a);
|
||||
} else {
|
||||
ADD_IMM8(x3, x3, a);
|
||||
}
|
||||
AND_IMM8(x3, x3, 7);
|
||||
}
|
||||
// get STld(0)
|
||||
ADD_IMM8(x2, xEmu, offsetof(x86emu_t, fpu_ld)+offsetof(fpu_ld_t, ld));
|
||||
MOVW(x14, sizeof(fpu_ld_t));
|
||||
MLA(x2, x3, x14, x2);
|
||||
// compare uref with actual value, top is not used anymore, so x3 is free
|
||||
LDR_IMM9(x14, x2, offsetof(fpu_ld_t, uref)-offsetof(fpu_ld_t, ld));
|
||||
LDR_IMM9(x3, x2, offsetof(fpu_ld_t, uref)-offsetof(fpu_ld_t, ld)+4);
|
||||
VMOVtoV_D(v2, x14, x3);
|
||||
VCEQ_32(v2, v2, v1); // same?
|
||||
VMOVfrV_D(x14, x3, v2);
|
||||
TSTS_REG_LSL_IMM5(x14, x3, 0);
|
||||
B_MARK(cEQ); // different, do the conversion
|
||||
// same... copy STld(0).ld
|
||||
LDR_IMM9(x14, x2, 0);
|
||||
LDR_IMM9(x3, x2, 4);
|
||||
STR_IMM9(x14, ed, 0);
|
||||
STR_IMM9(x3, ed, 4);
|
||||
LDRH_IMM8(x14, x2, 8);
|
||||
STRH_IMM8(x14, ed, 8);
|
||||
B_MARK2(c__);
|
||||
MARK;
|
||||
// different, call D2LD
|
||||
SUB_IMM8(xSP, xSP, 8);
|
||||
VSTR_64(v1, xSP, 0);
|
||||
PUSH(xSP, (1<<xEmu)|(1<<xFlags));
|
||||
ADD_IMM8(0, xSP, 8); //1st arg is &d
|
||||
if(ed!=x1) {
|
||||
MOV_REG_LSL_IMM5(x1, ed, 0); //2nd arg is ed
|
||||
}
|
||||
CALL_S(D2LD, -2, 0);
|
||||
POP(xSP, (1<<xEmu)|(1<<xFlags));
|
||||
ADD_IMM8(xSP, xSP, 8);
|
||||
MARK2;
|
||||
#endif
|
||||
}
|
||||
CALL(arm_fstp, -1, 0);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
|
||||
@@ -31,6 +31,7 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
int d1;
|
||||
int fixedaddress;
|
||||
int parity;
|
||||
uint8_t u8;
|
||||
|
||||
MAYUSE(d1);
|
||||
MAYUSE(v2);
|
||||
@@ -48,11 +49,15 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FADD STx, ST0");
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
if(ST_IS_F(0)) {
|
||||
VADD_F32(v1, v1, v2);
|
||||
} else {
|
||||
VADD_F64(v1, v1, v2);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
@@ -65,11 +70,15 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FMUL STx, ST0");
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
if(ST_IS_F(0)) {
|
||||
VMUL_F32(v1, v1, v2);
|
||||
} else {
|
||||
VMUL_F64(v1, v1, v2);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
@@ -106,7 +115,7 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
VCMP_F64(v1, v2);
|
||||
}
|
||||
FCOM(x1, x2);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xE0:
|
||||
case 0xE1:
|
||||
@@ -119,11 +128,15 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FSUBR STx, ST0");
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
if(ST_IS_F(0)) {
|
||||
VSUB_F32(v1, v2, v1);
|
||||
} else {
|
||||
VSUB_F64(v1, v2, v1);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 0xE8:
|
||||
case 0xE9:
|
||||
@@ -136,11 +149,15 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FSUB STx, ST0");
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
if(ST_IS_F(0)) {
|
||||
VSUB_F32(v1, v1, v2);
|
||||
} else {
|
||||
VSUB_F64(v1, v1, v2);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
@@ -153,11 +170,15 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FDIVR STx, ST0");
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
if(ST_IS_F(0)) {
|
||||
VDIV_F32(v1, v2, v1);
|
||||
} else {
|
||||
VDIV_F64(v1, v2, v1);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 0xF8:
|
||||
case 0xF9:
|
||||
@@ -170,11 +191,15 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FDIV STx, ST0");
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
if(ST_IS_F(0)) {
|
||||
VDIV_F32(v1, v1, v2);
|
||||
} else {
|
||||
VDIV_F64(v1, v1, v2);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
@@ -184,15 +209,19 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3, 0, NULL);
|
||||
VLDR_64(d1, wback, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0, 0, NULL);
|
||||
LDR_IMM9(x2, wback, fixedaddress);
|
||||
LDR_IMM9(x3, wback, fixedaddress+4);
|
||||
VMOVtoV_D(d1, x2, x3);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
VADD_F64(v1, v1, d1);
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FMUL ST0, double[ED]");
|
||||
@@ -200,15 +229,19 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3, 0, NULL);
|
||||
VLDR_64(d1, wback, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0, 0, NULL);
|
||||
LDR_IMM9(x2, wback, fixedaddress);
|
||||
LDR_IMM9(x3, wback, fixedaddress+4);
|
||||
VMOVtoV_D(d1, x2, x3);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
VMUL_F64(v1, v1, d1);
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FCOM ST0, double[ED]");
|
||||
@@ -216,10 +249,10 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3, 0, NULL);
|
||||
VLDR_64(d1, wback, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0, 0, NULL);
|
||||
LDR_IMM9(x2, wback, fixedaddress);
|
||||
LDR_IMM9(x3, wback, fixedaddress+4);
|
||||
VMOVtoV_D(d1, x2, x3);
|
||||
@@ -233,17 +266,17 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3, 0, NULL);
|
||||
VLDR_64(d1, wback, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0, 0, NULL);
|
||||
LDR_IMM9(x2, wback, fixedaddress);
|
||||
LDR_IMM9(x3, wback, fixedaddress+4);
|
||||
VMOVtoV_D(d1, x2, x3);
|
||||
}
|
||||
VCMP_F64(v1, d1);
|
||||
FCOM(x1, x2);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FSUB ST0, double[ED]");
|
||||
@@ -251,15 +284,19 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3, 0, NULL);
|
||||
VLDR_64(d1, wback, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0, 0, NULL);
|
||||
LDR_IMM9(x2, wback, fixedaddress);
|
||||
LDR_IMM9(x3, wback, fixedaddress+4);
|
||||
VMOVtoV_D(d1, x2, x3);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
VSUB_F64(v1, v1, d1);
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FSUBR ST0, double[ED]");
|
||||
@@ -267,15 +304,19 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3, 0, NULL);
|
||||
VLDR_64(d1, wback, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0, 0, NULL);
|
||||
LDR_IMM9(x2, wback, fixedaddress);
|
||||
LDR_IMM9(x3, wback, fixedaddress+4);
|
||||
VMOVtoV_D(d1, x2, x3);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
VSUB_F64(v1, d1, v1);
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FDIV ST0, double[ED]");
|
||||
@@ -283,15 +324,19 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3, 0, NULL);
|
||||
VLDR_64(d1, wback, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0, 0, NULL);
|
||||
LDR_IMM9(x2, wback, fixedaddress);
|
||||
LDR_IMM9(x3, wback, fixedaddress+4);
|
||||
VMOVtoV_D(d1, x2, x3);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
VDIV_F64(v1, v1, d1);
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FDIVR ST0, double[ED]");
|
||||
@@ -299,15 +344,19 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3, 0, NULL);
|
||||
VLDR_64(d1, wback, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0, 0, NULL);
|
||||
LDR_IMM9(x2, wback, fixedaddress);
|
||||
LDR_IMM9(x3, wback, fixedaddress+4);
|
||||
VMOVtoV_D(d1, x2, x3);
|
||||
}
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
VDIV_F64(v1, d1, v1);
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
uint8_t ed;
|
||||
int v1, v2;
|
||||
int i1, i2, i3;
|
||||
int j32;
|
||||
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
@@ -45,10 +46,21 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
INST_NAME("FFREE STx");
|
||||
#if 1
|
||||
if((nextop&7)==0 && PK(0)==0xD9 && PK(1)==0xF7) {
|
||||
MESSAGE(LOG_DUMP, "Hack for FFREE ST0 / FINCSTP\n");
|
||||
X87_POP_OR_FAIL(dyn, ninst, x1);
|
||||
addr+=2;
|
||||
SKIPTEST(x1, x14);
|
||||
} else
|
||||
x87_free(dyn, ninst, x1, x2, x3, nextop&7);
|
||||
#else
|
||||
INST_NAME("FFREE STx");
|
||||
x87_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
MOVW(x1, nextop&7);
|
||||
CALL(fpu_do_free, -1, 0);
|
||||
#endif
|
||||
break;
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
@@ -69,7 +81,7 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 0xD8:
|
||||
INST_NAME("FSTP ST0, ST0");
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xD9:
|
||||
case 0xDA:
|
||||
@@ -80,18 +92,8 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xDF:
|
||||
INST_NAME("FSTP ST0, STx");
|
||||
// copy the cache value for st0 to stx
|
||||
i1 = x87_get_cache(dyn, ninst, 0, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
i2 = x87_get_cache(dyn, ninst, 1, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
i3 = dyn->x87cache[i1];
|
||||
dyn->x87cache[i1] = dyn->x87cache[i2];
|
||||
dyn->x87cache[i2] = i3;
|
||||
// swap those too
|
||||
i1 = x87_get_neoncache(dyn, ninst, x1, x2, nextop&7);
|
||||
i2 = x87_get_neoncache(dyn, ninst, x1, x2, 0);
|
||||
i3 = dyn->n.neoncache[i1].v;
|
||||
dyn->n.neoncache[i1].v = dyn->n.neoncache[i2].v;
|
||||
dyn->n.neoncache[i2].v = i3;
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
x87_swapreg(dyn, ninst, x1, x2, 0, nextop&7);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
case 0xE0:
|
||||
@@ -129,7 +131,7 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
VCMP_F64(v1, v2);
|
||||
}
|
||||
FCOM(x1, x2);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
case 0xC8:
|
||||
@@ -163,13 +165,13 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FLD double");
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 3);
|
||||
if (parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0, NULL);
|
||||
VLDR_64(v1, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0, NULL);
|
||||
LDR_IMM9(x2, ed, fixedaddress);
|
||||
LDR_IMM9(x3, ed, fixedaddress + 4);
|
||||
VMOVtoV_D(v1, x2, x3);
|
||||
@@ -177,21 +179,64 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FISTTP i64, ST0");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
if(ed!=x1) {MOV_REG(x1, ed);}
|
||||
CALL(arm_fistt64, -1, 0);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
if(ninst
|
||||
&& dyn->insts[ninst-1].x86.addr
|
||||
&& *(uint8_t*)dyn->insts[ninst-1].x86.addr==0xDF
|
||||
&& (((*(uint8_t*)(dyn->insts[ninst-1].x86.addr+1))>>3)&7)==5)
|
||||
{
|
||||
if(parity) {
|
||||
STRD_IMM8(x2, ed, 0); // x2/x3 is 64bits
|
||||
} else {
|
||||
STR_IMM9(x2, ed, 0);
|
||||
STR_IMM9(x3, ed, 4);
|
||||
}
|
||||
} else {
|
||||
v1 = x87_get_st(dyn, ninst, x2, x3, 0, NEON_CACHE_ST_D);
|
||||
//addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
fpu_get_scratch_double(dyn); // to alocate v0
|
||||
v2 = fpu_get_scratch_double(dyn);
|
||||
// get TOP
|
||||
LDR_IMM9(x14, xEmu, offsetof(x86emu_t, top));
|
||||
int a = 0 - dyn->n.x87stack;
|
||||
if(a<0) {
|
||||
SUB_IMM8(x14, x14, -a);
|
||||
AND_IMM8(x14, x14, 7); // (emu->top + i)&7
|
||||
} else if(a>0) {
|
||||
ADD_IMM8(x14, x14, a);
|
||||
AND_IMM8(x14, x14, 7); // (emu->top + i)&7
|
||||
}
|
||||
ADD_REG_LSL_IMM5(x14, xEmu, x14, 4); // each fpu_ll is 2 int64: ref than ll
|
||||
MOVW(x2, offsetof(x86emu_t, fpu_ll)); //can be optimized?
|
||||
ADD_REG_LSL_IMM5(x14, x14, x2, offsetof(fpu_ll_t, sref));
|
||||
VLDR_64(v2, x14, 0);
|
||||
VCEQ_32(v2, v2, v1); // compare
|
||||
VMOVfrV_D(x2, x3, v2);
|
||||
ANDS_REG_LSL_IMM5(x2, x2, x3, 0); // if NE then values are the same!
|
||||
B_MARK(cEQ); // do the i64 conversion
|
||||
// memcpy(ed, &STll(0).ll, sizeof(int64_t));
|
||||
LDRD_IMM8(x2, x14, offsetof(fpu_ll_t, sq)); // load ll
|
||||
B_MARK3(c__);
|
||||
MARK;
|
||||
MOV32(x2, arm_fist64_3);
|
||||
VMOV_64(0, v1); // prepare call to log2
|
||||
CALL_1DR_U64(x2, x2, x3, x14, (1<<x1));
|
||||
MARK3;
|
||||
STR_IMM9(x2, ed, 0);
|
||||
STR_IMM9(x3, ed, 4);
|
||||
}
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FST double");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 3);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0, NULL);
|
||||
VSTR_64(v1, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0, NULL);
|
||||
VMOVfrV_D(x2, x3, v1);
|
||||
STR_IMM9(x2, ed, fixedaddress);
|
||||
STR_IMM9(x3, ed, fixedaddress+4);
|
||||
@@ -202,41 +247,42 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 3);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0, NULL);
|
||||
VSTR_64(v1, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0, NULL);
|
||||
VMOVfrV_D(x2, x3, v1);
|
||||
STR_IMM9(x2, ed, fixedaddress);
|
||||
STR_IMM9(x3, ed, fixedaddress+4);
|
||||
}
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FRSTOR m108byte");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
if(ed!=x1) {MOV_REG(x1, ed);}
|
||||
CALL(arm_frstor, -1, 0);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FSAVE m108byte");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
if(ed!=x1) {MOV_REG(x1, ed);}
|
||||
CALL(arm_fsave, -1, 0);
|
||||
CALL(reset_fpu, -1, 0);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FNSTSW m2byte");
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x14, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x14, &fixedaddress, 0, 0, 0, NULL);
|
||||
LDR_IMM9(x2, xEmu, offsetof(x86emu_t, top));
|
||||
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
if(dyn->x87stack) {
|
||||
if(dyn->n.x87stack) {
|
||||
// update top
|
||||
if(dyn->x87stack>0) {
|
||||
SUB_IMM8(x2, x2, dyn->x87stack);
|
||||
if(dyn->n.x87stack>0) {
|
||||
SUB_IMM8(x2, x2, dyn->n.x87stack);
|
||||
} else {
|
||||
ADD_IMM8(x2, x2, -dyn->x87stack);
|
||||
ADD_IMM8(x2, x2, -dyn->n.x87stack);
|
||||
}
|
||||
AND_IMM8(x2, x2, 7);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "debug.h"
|
||||
#include "box86context.h"
|
||||
#include "dynarec.h"
|
||||
#include "dynarec/arm_emitter.h"
|
||||
#include "emu/x86emu_private.h"
|
||||
#include "emu/x86run_private.h"
|
||||
#include "x86run.h"
|
||||
@@ -27,6 +28,7 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
{
|
||||
uint8_t nextop = F8;
|
||||
int v1, v2;
|
||||
uint8_t u8;
|
||||
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
@@ -43,12 +45,16 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FADDP STx, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
if(ST_IS_F(0)) {
|
||||
VADD_F32(v2, v2, v1);
|
||||
} else {
|
||||
VADD_F64(v2, v2, v1);
|
||||
}
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
@@ -61,12 +67,16 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FMULP STx, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
if(ST_IS_F(0)) {
|
||||
VMUL_F32(v2, v2, v1);
|
||||
} else {
|
||||
VMUL_F64(v2, v2, v1);
|
||||
}
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
@@ -85,7 +95,7 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
VCMP_F64(v1, v2);
|
||||
}
|
||||
FCOM(x1, x2);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
case 0xD9:
|
||||
@@ -98,8 +108,8 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
VCMP_F64(v1, v2);
|
||||
}
|
||||
FCOM(x1, x2);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xE0:
|
||||
case 0xE1:
|
||||
@@ -112,12 +122,16 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FSUBRP STx, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
if(ST_IS_F(0)) {
|
||||
VSUB_F32(v2, v1, v2);
|
||||
} else {
|
||||
VSUB_F64(v2, v1, v2);
|
||||
}
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xE8:
|
||||
case 0xE9:
|
||||
@@ -130,12 +144,16 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FSUBP STx, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
if(ST_IS_F(0)) {
|
||||
VSUB_F32(v2, v2, v1);
|
||||
} else {
|
||||
VSUB_F64(v2, v2, v1);
|
||||
}
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
@@ -148,12 +166,16 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FDIVRP STx, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
if(ST_IS_F(0)) {
|
||||
VDIV_F32(v2, v1, v2);
|
||||
} else {
|
||||
VDIV_F64(v2, v1, v2);
|
||||
}
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
if(!box86_dynarec_fastround)
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xF8:
|
||||
case 0xF9:
|
||||
@@ -166,12 +188,39 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
INST_NAME("FDIVP STx, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(!box86_dynarec_fastround || !box86_dynarec_fastnan) {
|
||||
VMRS(x14); // get fpscr
|
||||
if(!box86_dynarec_fastnan) {
|
||||
ORR_IMM8(x3, x14, 0b010, 9); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
} else if(!box86_dynarec_fastround)
|
||||
MOV_REG(x3, x14);
|
||||
if(!box86_dynarec_fastround){
|
||||
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, cw)); // hopefully cw is not too far for an imm8
|
||||
UBFX(x1, x1, 10, 2); // extract round...
|
||||
UBFX(x2, x1, 1, 1); // swap bits 0 and 1
|
||||
BFI(x2, x1, 1, 1);
|
||||
BFI(x3, x2, 22, 2); // inject new round
|
||||
}
|
||||
VMSR(x3); // put new fpscr
|
||||
}
|
||||
if(ST_IS_F(0)) {
|
||||
VDIV_F32(v2, v2, v1);
|
||||
} else {
|
||||
VDIV_F64(v2, v2, v1);
|
||||
}
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x3); // get the FPCSR reg and test FPU execption (invalid operation only)
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
if(ST_IS_F(0)) {
|
||||
VNEG_F32_cond(cNE, v2, v2);
|
||||
} else {
|
||||
VNEG_F64_cond(cNE, v2, v2);
|
||||
}
|
||||
}
|
||||
if(!box86_dynarec_fastround || !box86_dynarec_fastnan)
|
||||
VMSR(x14); // restore fpscr
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
case 0xD8:
|
||||
|
||||
+68
-108
@@ -23,7 +23,7 @@
|
||||
#include "dynarec_arm_functions.h"
|
||||
#include "dynarec_arm_helper.h"
|
||||
|
||||
|
||||
static const void* round_map[4] = {arm_fist64_0, arm_fist64_1, arm_fist64_2, arm_fist64_3};
|
||||
uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
|
||||
{
|
||||
uint8_t nextop = F8;
|
||||
@@ -31,7 +31,7 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
int32_t j32;
|
||||
uint8_t wback;
|
||||
uint8_t ed;
|
||||
int v0, v1, v2;
|
||||
int /*v0, */v1, v2;
|
||||
int s0;
|
||||
int fixedaddress;
|
||||
int parity;
|
||||
@@ -39,7 +39,7 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
MAYUSE(s0);
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
MAYUSE(v0);
|
||||
//MAYUSE(v0);
|
||||
MAYUSE(j32);
|
||||
|
||||
switch(nextop) {
|
||||
@@ -53,19 +53,19 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xC7:
|
||||
INST_NAME("FFREEP STx");
|
||||
// not handling Tag...
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
case 0xE0:
|
||||
INST_NAME("FNSTSW AX");
|
||||
LDR_IMM9(x2, xEmu, offsetof(x86emu_t, top));
|
||||
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
if(dyn->x87stack) {
|
||||
if(dyn->n.x87stack) {
|
||||
// update top
|
||||
if(dyn->x87stack>0) {
|
||||
SUB_IMM8(x2, x2, dyn->x87stack);
|
||||
if(dyn->n.x87stack>0) {
|
||||
SUB_IMM8(x2, x2, dyn->n.x87stack);
|
||||
} else {
|
||||
ADD_IMM8(x2, x2, -dyn->x87stack);
|
||||
ADD_IMM8(x2, x2, -dyn->n.x87stack);
|
||||
}
|
||||
AND_IMM8(x2, x2, 7);
|
||||
}
|
||||
@@ -81,7 +81,7 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
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));
|
||||
if(ST_IS_F(0))
|
||||
@@ -91,7 +91,7 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
VCMP_F64(v1, v2);
|
||||
}
|
||||
FCOMI(x1, x2);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
@@ -102,7 +102,7 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
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));
|
||||
if(ST_IS_F(0))
|
||||
@@ -112,7 +112,7 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
VCMP_F64(v1, v2);
|
||||
}
|
||||
FCOMI(x1, x2);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
case 0xC8:
|
||||
@@ -161,8 +161,8 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FILD ST0, Ew");
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0, NULL);
|
||||
LDRSH_IMM8(x1, wback, fixedaddress);
|
||||
if(ST_IS_F(0)) {
|
||||
VMOVtoV(v1, x1);
|
||||
@@ -175,20 +175,20 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FISTTP Ew, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_F);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 255, 0, 0);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 255, 0, 0, NULL);
|
||||
ed = x1;
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
MSR_nzcvq_0();
|
||||
VMRS(x14); // get fpscr
|
||||
// x1 already have FPCSR reg to clear exceptions flags
|
||||
ORR_IMM8(x3, x14, 0b001, 6); // enable exceptions
|
||||
ORR_IMM8(x3, x14, 0b010, 9); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
if(ST_IS_F(0)) {
|
||||
VCVTR_S32_F32(s0, v1);
|
||||
VCVT_S32_F32(s0, v1);
|
||||
} else {
|
||||
VCVTR_S32_F64(s0, v1);
|
||||
VCVT_S32_F64(s0, v1);
|
||||
}
|
||||
VMRS(x3); // get the FPCSR reg and test FPU execption (invalid operation only)
|
||||
VMOVfrV(ed, s0);
|
||||
@@ -197,21 +197,17 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
CMPS_REG_LSL_IMM5_COND(cEQ, ed, x3, 0);
|
||||
MOVW_COND(cNE, x3, 0x8000); // saturated
|
||||
STRH_IMM8(x3, wback, fixedaddress);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
VMSR(x14);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FIST Ew, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_F);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 255, 0, 0);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
u8 = x87_setround_reset(dyn, ninst, x1, x2, x14);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 255, 0, 0, NULL);
|
||||
ed = x1;
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
MSR_nzcvq_0();
|
||||
// x1 already have FPCSR reg to clear exceptions flags
|
||||
ORR_IMM8(x3, x1, 0b001, 6); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
if(ST_IS_F(0)) {
|
||||
VCVTR_S32_F32(s0, v1);
|
||||
} else {
|
||||
@@ -228,16 +224,12 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FISTP Ew, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_F);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 255, 0, 0);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, box86_dynarec_x87double?NEON_CACHE_ST_D:NEON_CACHE_ST_F);
|
||||
u8 = x87_setround_reset(dyn, ninst, x1, x2, x14);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 255, 0, 0, NULL);
|
||||
ed = x1;
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
MSR_nzcvq_0();
|
||||
// x1 already have FPCSR reg to clear exceptions flags
|
||||
ORR_IMM8(x3, x1, 0b001, 6); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
if(ST_IS_F(0)) {
|
||||
VCVTR_S32_F32(s0, v1);
|
||||
} else {
|
||||
@@ -250,24 +242,26 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
CMPS_REG_LSL_IMM5_COND(cEQ, ed, x3, 0);
|
||||
MOVW_COND(cNE, x3, 0x8000); // saturated
|
||||
STRH_IMM8(x3, wback, fixedaddress);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FBLD ST0, tbytes");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_do_push_empty(dyn, ninst, x1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
X87_PUSH_EMPTY_OR_FAIL(dyn, ninst, x1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
if(ed!=x1) {MOV_REG(x1, ed);}
|
||||
s0 = x87_stackcount(dyn, ninst, x3);
|
||||
CALL(fpu_fbld, -1, 0);
|
||||
x87_unstackcount(dyn, ninst, x3, s0);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FILD ST0, i64");
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
X87_PUSH_OR_FAIL(v1, dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch_double(dyn);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
if(parity) {
|
||||
LDRD_IMM8(x2, wback, 0); // x2/x3 is 64bits
|
||||
} else {
|
||||
@@ -281,56 +275,56 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
{
|
||||
MESSAGE(LOG_DUMP, "Hack for FILD/FISTP i64");
|
||||
} else {
|
||||
// Save xFlags to use it as scratch...
|
||||
STR_IMM9(xFlags, xEmu, offsetof(x86emu_t, eflags));
|
||||
// set STll(0).ll=i64 and ref=ST(0).q later (emu->fpu_ll[emu->top].ref == emu->mmx87[emu->top])
|
||||
// get TOP
|
||||
LDR_IMM9(xFlags, xEmu, offsetof(x86emu_t, top));
|
||||
int a = 0 - dyn->x87stack;
|
||||
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, top));
|
||||
int a = 0 - dyn->n.x87stack;
|
||||
if(a<0) {
|
||||
SUB_IMM8(xFlags, xFlags, -a);
|
||||
AND_IMM8(xFlags, xFlags, 7);
|
||||
SUB_IMM8(x1, x1, -a);
|
||||
AND_IMM8(x1, x1, 7);
|
||||
} else if(a>0) {
|
||||
ADD_IMM8(xFlags, xFlags, a);
|
||||
AND_IMM8(xFlags, xFlags, 7);
|
||||
ADD_IMM8(x1, x1, a);
|
||||
AND_IMM8(x1, x1, 7);
|
||||
}
|
||||
ADD_REG_LSL_IMM5(xFlags, xEmu, xFlags, 4); // each fpu_ll is 2 int64: ref than ll
|
||||
ADD_IMM8_ROR(xFlags, xFlags, offsetof(x86emu_t, fpu_ll)>>2, 15);
|
||||
STRD_IMM8(x2, xFlags, 8); // save ll
|
||||
// ed (and so x1) is not use anymore.
|
||||
ADD_REG_LSL_IMM5(x1, xEmu, x1, 4); // each fpu_ll is 2 int64: ref than ll
|
||||
ADD_IMM8_ROR(x1, x1, offsetof(x86emu_t, fpu_ll)>>2, 15);
|
||||
STRD_IMM8(x2, x1, 8); // save ll
|
||||
// continue with conversion
|
||||
MOVS_REG_LSR_IMM5(x14, x3, 31); // x14 is sign bit
|
||||
B_MARK(cEQ); // no NEG is no sign bit
|
||||
RSBS_IMM8(x2, x2, 0);
|
||||
RSC_IMM8(x3, x3, 0);
|
||||
MARK;
|
||||
VMOVtoV(s0, x3);
|
||||
VMOVtoV(s0, x3); // last time x3 is used
|
||||
VCVT_F64_U32(v1, s0);
|
||||
VEOR(v2, v2, v2);
|
||||
MOVW(x1, 0x41F0);
|
||||
VMOVtoDx_16(v2, 3, x1);
|
||||
MOVW(x3, 0x41F0);
|
||||
VMOVtoDx_16(v2, 3, x3);
|
||||
VMUL_F64(v1, v1, v2); // v1 = double high part of i64
|
||||
VMOVtoV(s0, x2);
|
||||
VCVT_F64_U32(v2, s0);
|
||||
VADD_F64(v1, v1, v2);
|
||||
TSTS_IMM8(x14, 1);
|
||||
VNEG_F64_cond(cNE, v1, v1);
|
||||
VST1_64(v1, xFlags); // Store STll(0).ref
|
||||
LDR_IMM9(xFlags, xEmu, offsetof(x86emu_t, eflags));
|
||||
VST1_64(v1, x1); // Store STll(0).ref
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FBSTP tbytes, ST0");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
if(ed!=x1) {MOV_REG(x1, ed);}
|
||||
s0 = x87_stackcount(dyn, ninst, x3);
|
||||
CALL(fpu_fbst, -1, 0);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
x87_unstackcount(dyn, ninst, x3, s0);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
case 7: // could be inlined for most thing, but is it usefull?
|
||||
INST_NAME("FISTP i64, ST0");
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
if(ninst
|
||||
&& dyn->insts[ninst-1].x86.addr
|
||||
&& *(uint8_t*)dyn->insts[ninst-1].x86.addr==0xDF
|
||||
@@ -343,16 +337,13 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
STR_IMM9(x3, ed, 4);
|
||||
}
|
||||
} else {
|
||||
#if 0
|
||||
v1 = x87_get_st(dyn, ninst, x2, x3, 0);
|
||||
//addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
v1 = x87_get_st(dyn, ninst, x2, x3, 0, NEON_CACHE_ST_D);
|
||||
//addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
fpu_get_scratch_double(dyn); // to alocate v0
|
||||
v2 = fpu_get_scratch_double(dyn);
|
||||
v0 = fpu_get_scratch_double(dyn);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
// check STll(0).ref==ST(0).q so emu->fpu_ll[emu->top].ref == emu->mmx87[emu->top]
|
||||
// get TOP
|
||||
LDR_IMM9(x14, xEmu, offsetof(x86emu_t, top));
|
||||
int a = 0 - dyn->x87stack;
|
||||
int a = 0 - dyn->n.x87stack;
|
||||
if(a<0) {
|
||||
SUB_IMM8(x14, x14, -a);
|
||||
AND_IMM8(x14, x14, 7); // (emu->top + i)&7
|
||||
@@ -362,59 +353,28 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
}
|
||||
ADD_REG_LSL_IMM5(x14, xEmu, x14, 4); // each fpu_ll is 2 int64: ref than ll
|
||||
MOVW(x2, offsetof(x86emu_t, fpu_ll)); //can be optimized?
|
||||
ADD_REG_LSL_IMM5(x14, x14, x2, 0);
|
||||
ADD_REG_LSL_IMM5(x14, x14, x2, offsetof(fpu_ll_t, sref));
|
||||
VLDR_64(v2, x14, 0);
|
||||
VCEQ_32(v2, v2, v1); // compare
|
||||
VMOVfrV_D(x2, x3, v2);
|
||||
ANDS_REG_LSL_IMM5(x2, x2, x3, 0); // if NE then values are the same!
|
||||
B_MARK(cEQ); // do the i64 conversion
|
||||
// memcpy(ed, &STll(0).ll, sizeof(int64_t));
|
||||
LDRD_IMM8(x2, x14, 8); // load ll
|
||||
LDRD_IMM8(x2, x14, offsetof(fpu_ll_t, sq)); // load ll
|
||||
B_MARK3(c__);
|
||||
MARK;
|
||||
VEOR(v0, v0, v0);
|
||||
MOVW(x2, 0x41F0);
|
||||
VMOVtoDx_16(v0, 3, x2); // V0 = (1<<32) as double
|
||||
VMOVfrDx_32(x14, v1, 1); // get high part to extract sign
|
||||
VABS_F64(v1 ,v1); //ST0 will be poped, so lost...
|
||||
VDIV_F64(v2, v1, v0); // v2 = abs(ST0)/(1<<32) : so 32 bits high part
|
||||
MSR_nzcvq_0();
|
||||
VMRS(x2); // get fpscr
|
||||
ORR_IMM8(x3, x2, 0b001, 6); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
VCVT_U32_F64(s0, v2); // convert high part to U32
|
||||
VMRS(x3); // get the FPCSR reg and test FPU execption (invalid operation only)
|
||||
VMSR(x2); // put back fpscr
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
B_MARK2(cEQ); // not overflow...
|
||||
MARKLOCK;
|
||||
MOV_IMM(x3, 0b10, 1); // 0x80000000
|
||||
MOVW(x2, 0);
|
||||
B_MARK3(c__);
|
||||
MARK2; // continue conversion, it fits an int64!
|
||||
VCVT_F64_U32(v2, s0); // int part now
|
||||
VMLS_F64(v1, v2, v0); // compute low part
|
||||
VMOVfrV(x3, s0); // transfert high path
|
||||
TSTS_IMM8_ROR(x14, 0b10, 1); // test high part with 0x800000000
|
||||
B_MARKLOCK(cNE); // int overflow...
|
||||
VCVT_U32_F64(s0, v1); // convert low part
|
||||
VMOVfrV(x2, s0); // transfert low part
|
||||
TSTS_IMM8_ROR(x14, 0b10, 1); // 0x800000000
|
||||
B_MARK3(cEQ);
|
||||
RSBS_IMM8(x2, x2, 0); // NEG(i64)
|
||||
RSC_IMM8(x3, x3, 0);
|
||||
// load round mode
|
||||
LDRH_IMM8(x14, xEmu, offsetof(x86emu_t, cw)); // hopefully cw is not too far for an imm8
|
||||
UBFX(x2, x14, 10, 2); // extract round...
|
||||
MOV32(x14, round_map);
|
||||
LDR_REG_LSL_IMM5(x2, x14, x2, 2);
|
||||
VMOV_64(0, v1); // prepare call to log2
|
||||
CALL_1DR_U64(x2, x2, x3, x14, (1<<x1));
|
||||
MARK3;
|
||||
STR_IMM9(x2, x1, 0);
|
||||
STR_IMM9(x3, x1, 4);
|
||||
#else
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x2, x3, 0);
|
||||
if(ed!=x1) {MOV_REG(x1, ed);}
|
||||
CALL(arm_fistp64, -1, 0);
|
||||
#endif
|
||||
STR_IMM9(x2, ed, 0);
|
||||
STR_IMM9(x3, ed, 4);
|
||||
}
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
X87_POP_OR_FAIL(dyn, ninst, x3);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
|
||||
@@ -27,8 +27,6 @@
|
||||
void emit_or32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_or32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
@@ -55,7 +53,7 @@ void emit_or32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,9 +61,6 @@ void emit_or32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
void emit_or32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOV32(s3, c);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_or32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
@@ -77,7 +72,7 @@ void emit_or32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4
|
||||
ORR_IMM8(s1, s1, c, 0);
|
||||
}
|
||||
} else {
|
||||
IFX(X_PEND) {} else {MOV32(s3, c);}
|
||||
MOV32(s3, c);
|
||||
IFX(X_ALL) {
|
||||
ORRS_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
} else {
|
||||
@@ -101,7 +96,7 @@ void emit_or32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,8 +104,6 @@ void emit_or32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4
|
||||
void emit_xor32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_xor32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
@@ -137,7 +130,7 @@ void emit_xor32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,9 +138,6 @@ void emit_xor32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
void emit_xor32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOV32(s3, c);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_xor32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
@@ -159,7 +149,7 @@ void emit_xor32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
XOR_IMM8(s1, s1, c);
|
||||
}
|
||||
} else {
|
||||
IFX(X_PEND) {} else {MOV32(s3, c);}
|
||||
MOV32(s3, c);
|
||||
IFX(X_ALL) {
|
||||
XORS_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
} else {
|
||||
@@ -183,7 +173,7 @@ void emit_xor32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,8 +181,6 @@ void emit_xor32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
void emit_and32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_and32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
@@ -219,7 +207,7 @@ void emit_and32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -227,9 +215,6 @@ void emit_and32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
void emit_and32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOV32(s3, c);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_and32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
@@ -248,7 +233,7 @@ void emit_and32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
BIC_IMM8(s1, s1, ~c, 0);
|
||||
}
|
||||
} else {
|
||||
IFX(X_PEND) {} else {MOV32(s3, c);}
|
||||
MOV32(s3, c);
|
||||
IFX(X_ALL) {
|
||||
ANDS_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
} else {
|
||||
@@ -273,7 +258,7 @@ void emit_and32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,8 +266,6 @@ void emit_and32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
void emit_or8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s3, d_or8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
@@ -309,7 +292,7 @@ void emit_or8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,9 +300,6 @@ void emit_or8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
void emit_or8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOV32(s3, c&0xff);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_or8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
@@ -346,7 +326,7 @@ void emit_or8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -354,8 +334,6 @@ void emit_or8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
void emit_xor8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s3, d_xor8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
@@ -382,7 +360,7 @@ void emit_xor8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -390,9 +368,6 @@ void emit_xor8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
void emit_xor8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOV32(s3, c&0xff);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_xor8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
@@ -419,7 +394,7 @@ void emit_xor8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -427,8 +402,6 @@ void emit_xor8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4
|
||||
void emit_and8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s3, d_and8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
@@ -455,7 +428,7 @@ void emit_and8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -463,9 +436,6 @@ void emit_and8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
void emit_and8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOV32(s3, c&0xff);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_and8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
@@ -492,7 +462,7 @@ void emit_and8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -501,8 +471,6 @@ void emit_and8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4
|
||||
void emit_or16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s3, d_or16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
@@ -529,7 +497,7 @@ void emit_or16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -537,9 +505,6 @@ void emit_or16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
void emit_or16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOVW(s3, c);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_or16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
@@ -551,7 +516,7 @@ void emit_or16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4
|
||||
ORR_IMM8(s1, s1, c, 0);
|
||||
}
|
||||
} else {
|
||||
IFX(X_PEND) {} else {MOVW(s3, c);}
|
||||
MOVW(s3, c);
|
||||
IFX(X_ALL) {
|
||||
ORRS_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
} else {
|
||||
@@ -575,7 +540,7 @@ void emit_or16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -583,8 +548,6 @@ void emit_or16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4
|
||||
void emit_xor16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s3, d_xor16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
@@ -611,7 +574,7 @@ void emit_xor16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -619,9 +582,6 @@ void emit_xor16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
void emit_xor16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOVW(s3, c);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_xor16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
@@ -633,7 +593,7 @@ void emit_xor16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
XOR_IMM8(s1, s1, c);
|
||||
}
|
||||
} else {
|
||||
IFX(X_PEND) {} else {MOVW(s3, c);}
|
||||
MOVW(s3, c);
|
||||
IFX(X_ALL) {
|
||||
XORS_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
} else {
|
||||
@@ -657,7 +617,7 @@ void emit_xor16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -665,8 +625,6 @@ void emit_xor16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
void emit_and16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s3, d_and16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
@@ -693,7 +651,7 @@ void emit_and16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -701,9 +659,6 @@ void emit_and16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
void emit_and16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOVW(s3, c);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_and16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
@@ -715,7 +670,7 @@ void emit_and16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
AND_IMM8(s1, s1, c);
|
||||
}
|
||||
} else {
|
||||
IFX(X_PEND) {} else {MOVW(s3, c);}
|
||||
MOVW(s3, c);
|
||||
IFX(X_ALL) {
|
||||
ANDS_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
} else {
|
||||
@@ -739,6 +694,6 @@ void emit_and16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
@@ -69,14 +69,14 @@ void emit_add32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit ADD32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_add32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
if(s1==xESP && (!dyn->insts || (dyn->insts[ninst].x86.need_flags==X_PEND || dyn->insts[ninst].x86.need_flags==X_ALL)))
|
||||
if(s1==xESP && (!dyn->insts || (dyn->insts[ninst].x86.gen_flags==X_PEND || dyn->insts[ninst].x86.gen_flags==X_ALL)))
|
||||
{
|
||||
// special case when doing math on ESP and only PEND is needed: ignoring it!
|
||||
if(c>=0 && c<256) {
|
||||
@@ -151,7 +151,7 @@ void emit_add32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,14 +203,14 @@ void emit_sub32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit SUB32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_sub32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
if(s1==xESP && (!dyn->insts || (dyn->insts[ninst].x86.need_flags==X_PEND || dyn->insts[ninst].x86.need_flags==X_ALL)))
|
||||
if(s1==xESP && (!dyn->insts || (dyn->insts[ninst].x86.gen_flags==X_PEND || dyn->insts[ninst].x86.gen_flags==X_ALL)))
|
||||
{
|
||||
// special case when doing math on ESP and only PEND is needed: ignoring it!
|
||||
if(c>=0 && c<256) {
|
||||
@@ -288,7 +288,7 @@ void emit_sub32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -338,7 +338,7 @@ void emit_add8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, in
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
IFX(X_AF|X_OF|X_PF){if(save_s4) {POP(xSP, 1<<s4);}}
|
||||
}
|
||||
@@ -390,7 +390,7 @@ void emit_add8c(dynarec_arm_t* dyn, int ninst, int s1, int c, int s3, int s4)
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -442,7 +442,7 @@ void emit_sub8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, in
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
IFX(X_AF|X_OF|X_CF|X_PF){if(save_s4) {POP(xSP, 1<<s4);}}
|
||||
}
|
||||
@@ -495,7 +495,7 @@ void emit_sub8c(dynarec_arm_t* dyn, int ninst, int s1, int c, int s3, int s4)
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -547,7 +547,7 @@ void emit_add16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, i
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
IFX(X_AF|X_OF|X_PF){if(save_s4) {POP(xSP, 1<<s4);}}
|
||||
}
|
||||
@@ -615,7 +615,7 @@ void emit_add16c(dynarec_arm_t* dyn, int ninst, int s1, int c, int s3, int s4)
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -668,7 +668,7 @@ void emit_sub16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, i
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
IFX(X_AF|X_OF|X_CF|X_PF){if(save_s4) {POP(xSP, 1<<s4);}}
|
||||
}
|
||||
@@ -734,7 +734,7 @@ void emit_sub16c(dynarec_arm_t* dyn, int ninst, int s1, int c, int s3, int s4)
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -778,7 +778,7 @@ void emit_inc32(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -823,7 +823,7 @@ void emit_inc8(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -870,7 +870,7 @@ void emit_inc16(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -915,7 +915,7 @@ void emit_dec32(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -923,7 +923,7 @@ void emit_dec32(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
void emit_dec8(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
SET_DF(s3, d_dec8);
|
||||
} else IFX(X_ZF|X_OF|X_AF|X_SF|X_PF) {
|
||||
SET_DFNONE(s3);
|
||||
@@ -960,7 +960,7 @@ void emit_dec8(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1006,7 +1006,7 @@ void emit_dec16(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1057,7 +1057,7 @@ void emit_adc32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1127,7 +1127,7 @@ void emit_adc32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1179,7 +1179,7 @@ void emit_adc8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, in
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
IFX(X_AF|X_OF|X_PF){if(save_s4) {POP(xSP, 1<<s4);}}
|
||||
}
|
||||
@@ -1232,7 +1232,7 @@ void emit_adc8c(dynarec_arm_t* dyn, int ninst, int s1, int c, int s3, int s4)
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1285,7 +1285,7 @@ void emit_adc16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, i
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
IFX(X_AF|X_OF|X_PF){if(save_s4) {POP(xSP, 1<<s4);}}
|
||||
}
|
||||
@@ -1353,7 +1353,7 @@ void emit_adc16c(dynarec_arm_t* dyn, int ninst, int s1, int c, int s3, int s4)
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1407,7 +1407,7 @@ void emit_sbb32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1479,7 +1479,7 @@ void emit_sbb32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1533,7 +1533,7 @@ void emit_sbb8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, in
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
IFX(X_AF|X_OF|X_CF|X_PF){if(save_s4) {POP(xSP, 1<<s4);}}
|
||||
}
|
||||
@@ -1587,7 +1587,7 @@ void emit_sbb8c(dynarec_arm_t* dyn, int ninst, int s1, int c, int s3, int s4)
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1642,7 +1642,7 @@ void emit_sbb16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, i
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
IFX(X_AF|X_OF|X_CF|X_PF){if(save_s4) {POP(xSP, 1<<s4);}}
|
||||
}
|
||||
@@ -1710,7 +1710,7 @@ void emit_sbb16c(dynarec_arm_t* dyn, int ninst, int s1, int c, int s3, int s4)
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1758,7 +1758,7 @@ void emit_neg32(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1807,7 +1807,7 @@ void emit_neg16(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1855,6 +1855,6 @@ void emit_neg8(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
@@ -76,7 +76,7 @@ void emit_shl32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
BFC_COND(cNE, xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ void emit_shl32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,7 +154,17 @@ void emit_shr32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
B_NEXT(cEQ);
|
||||
}
|
||||
IFX(X_ZF|X_CF) {
|
||||
IFX(X_CF) {
|
||||
SUB_IMM8(s4, s2, 1);
|
||||
MOV_REG_LSR_REG(s4, s1, s4);
|
||||
BFI(xFlags, s4, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CMPS_IMM8(s2, 1); // if s2==1
|
||||
MOV_REG_LSR_IMM5_COND(cEQ, s4, s1, 31);
|
||||
BFI_COND(cEQ, xFlags, s4, F_OF, 1);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
MOVS_REG_LSR_REG(s1, s1, s2);
|
||||
} else {
|
||||
MOV_REG_LSR_REG(s1, s1, s2);
|
||||
@@ -162,27 +172,16 @@ void emit_shr32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF|X_CF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_ZF), 0);
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
ORR_IMM8_COND(cCS, xFlags, xFlags, 1<<F_CF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 31);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CMPS_IMM8(s2, 1);
|
||||
MOV_REG_LSR_IMM5_COND(cEQ, s4, s1, 30);
|
||||
XOR_REG_LSR_IMM8_COND(cEQ, s4, s4, s4, 1);
|
||||
BFI_COND(cEQ, xFlags, s4, F_OF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,7 +202,21 @@ void emit_shr32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
}
|
||||
return;
|
||||
}
|
||||
IFX(X_ZF|X_CF) {
|
||||
IFX(X_CF) {
|
||||
if(c==1) {
|
||||
BFI(xFlags, s1, F_CF, 1);
|
||||
} else {
|
||||
MOV_REG_LSR_IMM5(s3, s1, c-1);
|
||||
BFI(xFlags, s3, F_CF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 31);
|
||||
BFI(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
MOVS_REG_LSR_IMM5(s1, s1, c);
|
||||
} else {
|
||||
MOV_REG_LSR_IMM5(s1, s1, c);
|
||||
@@ -211,28 +224,16 @@ void emit_shr32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF|X_CF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_ZF), 0);
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
ORR_IMM8_COND(cCS, xFlags, xFlags, 1<<F_CF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s3, s1, 31);
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 30);
|
||||
XOR_REG_LSR_IMM8(s4, s4, s4, 1);
|
||||
BFI(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,8 +275,567 @@ void emit_sar32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
MOV_REG_LSR_IMM5(s3, s1, 31);
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF)
|
||||
if(c==1) {
|
||||
BFC(xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit SHL8 instruction, from s1 , shift s2, store result in s1 using s3 and s4 as scratch. s3 can be same as s2
|
||||
void emit_shl8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_shl8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_CF | X_OF) {
|
||||
RSB_IMM8(s4, s2, 8);
|
||||
MOV_REG_LSR_REG(s4, s1, s4);
|
||||
BFI(xFlags, s4, F_CF, 1);
|
||||
}
|
||||
MOV_REG_LSL_REG(s1, s1, s2);
|
||||
IFX(X_ZF) {
|
||||
ANDS_IMM8(s1, s1, 0xff);
|
||||
} else IFX(X_PEND) {
|
||||
AND_IMM8(s1, s1, 0xff);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
MOV32(s4, 1);
|
||||
BFI_COND(cEQ, xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 7);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CMPS_IMM8(s2, 1); // if s2==1
|
||||
IFX(X_SF) {} else {MOV_REG_LSR_IMM5_COND(cEQ, s4, s1, 7);}
|
||||
XOR_REG_LSL_IMM5_COND(cEQ, s4, s4, xFlags, 0); // CF is set if OF is asked
|
||||
BFI_COND(cEQ, xFlags, s4, F_OF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit SHL8 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_shl8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
if(!c)
|
||||
return;
|
||||
IFX(X_PEND) {
|
||||
MOV32(s3, c);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_shl8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(c<8) {
|
||||
IFX(X_CF|X_OF) {
|
||||
MOV_REG_LSR_IMM5(s3, s1, 8-c);
|
||||
BFI(xFlags, s3, F_CF, 1);
|
||||
}
|
||||
MOV_REG_LSL_IMM5(s1, s1, c);
|
||||
|
||||
IFX(X_PEND) {
|
||||
AND_IMM8(s1, s1, 0xff);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTS_IMM8(s1, 0xff);
|
||||
MOVW_COND(cNE, s4, 0);
|
||||
MOVW_COND(cEQ, s4, 1);
|
||||
BFI(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 7);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
IFX(X_SF) {} else {MOV_REG_LSR_IMM5(s4, s1, 7);}
|
||||
XOR_REG_LSL_IMM5(s4, s4, xFlags, 0); // CF is set if OF is asked
|
||||
BFI(xFlags, s4, F_OF, 1);
|
||||
} else {
|
||||
BFC(xFlags, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
} else {
|
||||
IFX(X_CF) {
|
||||
MOV_REG_LSL_IMM5(s3, s1, c-1);
|
||||
MOV_REG_LSR_IMM5(s4, s3, 7);
|
||||
BFI(xFlags, s4, F_CF, 1);
|
||||
}
|
||||
MOVW(s1, 0);
|
||||
IFX(X_OF) {
|
||||
BFC(xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
BFC(xFlags, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF | X_ZF) {
|
||||
MOVW(s3, 1);
|
||||
IFX(X_ZF) {
|
||||
BFI(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
BFI(xFlags, s3, F_PF, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// emit SHR8 instruction, from s1 , s2, store result in s1 using s3 and s4 as scratch, s2 can be same as s3
|
||||
void emit_shr8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_shr8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
SUB_IMM8(s4, s2, 1);
|
||||
MOV_REG_LSR_REG(s4, s1, s4);
|
||||
BFI(xFlags, s4, 0, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CMPS_IMM8(s2, 1); // if s2==1
|
||||
MOV_REG_LSR_IMM5_COND(cEQ, s4, s1, 7);
|
||||
BFI_COND(cEQ, xFlags, s4, F_OF, 1);
|
||||
}
|
||||
MOV_REG_LSR_REG(s1, s1, s2);
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTS_IMM8(s1, 0xff);
|
||||
MOVW_COND(cNE, s4, 0);
|
||||
MOVW_COND(cEQ, s4, 1);
|
||||
BFI(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 7);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit SHR8 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_shr8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
if(!c)
|
||||
return;
|
||||
IFX(X_PEND) {
|
||||
MOV32(s3, c);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_shr8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
if(c==1) {
|
||||
BFI(xFlags, s1, 0, 1);
|
||||
} else {
|
||||
MOV_REG_LSR_IMM5(s3, s1, c-1);
|
||||
BFI(xFlags, s3, 0, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 7);
|
||||
BFI(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
}
|
||||
MOV_REG_LSR_IMM5(s1, s1, c);
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTS_IMM8(s1, 0xff);
|
||||
MOVW_COND(cNE, s4, 0);
|
||||
MOVW_COND(cEQ, s4, 1);
|
||||
BFI(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 7);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit SAR8 instruction, from s1 , shift s2, store result in s1 using s3 and s4 as scratch, s2 can be same as s3
|
||||
void emit_sar8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_sar8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
SUB_IMM8(s4, s2, 1);
|
||||
MOV_REG_ASR_REG(s4, s1, s4);
|
||||
BFI(xFlags, s4, 0, 1);
|
||||
}
|
||||
MOV_REG_ASR_REG(s1, s1, s2);
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTS_IMM8(s1, 0xff);
|
||||
MOVW_COND(cNE, s4, 0);
|
||||
MOVW_COND(cEQ, s4, 1);
|
||||
BFI(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 7);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CMPS_IMM8(s2, 1);
|
||||
BFC_COND(cEQ, xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit SAR8 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_sar8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
if(!c)
|
||||
return;
|
||||
IFX(X_PEND) {
|
||||
MOV32(s3, c);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_sar8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
MOV_REG_ASR_IMM5(s3, s1, c-1);
|
||||
BFI(xFlags, s3, 0, 1);
|
||||
}
|
||||
MOV_REG_ASR_IMM5(s1, s1, c);
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTS_IMM8(s1, 0xff);
|
||||
MOVW_COND(cNE, s4, 0);
|
||||
MOVW_COND(cEQ, s4, 1);
|
||||
BFI(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 7);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF)
|
||||
if(c==1) {
|
||||
BFC(xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit SHL16 instruction, from s1 , shift s2, store result in s1 using s3 and s4 as scratch. s3 can be same as s2
|
||||
void emit_shl16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_shl16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_CF | X_OF) {
|
||||
RSB_IMM8(s4, s2, 16);
|
||||
MOV_REG_LSR_REG(s4, s1, s4);
|
||||
BFI(xFlags, s4, F_CF, 1);
|
||||
}
|
||||
MOV_REG_LSL_REG(s1, s1, s2);
|
||||
UBFX(s1, s1, 0, 16);
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTS_REG_LSL_IMM5(s1, s1, 0);
|
||||
MOV32(s4, 1);
|
||||
BFI_COND(cEQ, xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 15);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CMPS_IMM8(s2, 1); // if s2==1
|
||||
IFX(X_SF) {} else {MOV_REG_LSR_IMM5_COND(cEQ, s4, s1, 15);}
|
||||
XOR_REG_LSL_IMM5_COND(cEQ, s4, s4, xFlags, 0); // CF is set if OF is asked
|
||||
BFI_COND(cEQ, xFlags, s4, F_OF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit SHL16 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_shl16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
if(!c)
|
||||
return;
|
||||
IFX(X_PEND) {
|
||||
MOV32(s3, c);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_shl16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(c<16) {
|
||||
IFX(X_CF|X_OF) {
|
||||
MOV_REG_LSR_IMM5(s3, s1, 16-c);
|
||||
BFI(xFlags, s3, F_CF, 1);
|
||||
}
|
||||
MOV_REG_LSL_IMM5(s1, s1, c);
|
||||
|
||||
UBFX(s1, s1, 0, 16);
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTS_REG_LSL_IMM5(s1, s1, 0);
|
||||
MOVW_COND(cNE, s4, 0);
|
||||
MOVW_COND(cEQ, s4, 1);
|
||||
BFI(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 15);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
IFX(X_SF) {} else {MOV_REG_LSR_IMM5(s4, s1, 15);}
|
||||
XOR_REG_LSL_IMM5(s4, s4, xFlags, 0); // CF is set if OF is asked
|
||||
BFI(xFlags, s4, F_OF, 1);
|
||||
} else {
|
||||
BFC(xFlags, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
} else {
|
||||
IFX(X_CF) {
|
||||
MOV_REG_LSL_IMM5(s3, s1, c-1);
|
||||
MOV_REG_LSR_IMM5(s4, s3, 15);
|
||||
BFI(xFlags, s4, F_CF, 1);
|
||||
}
|
||||
MOVW(s1, 0);
|
||||
IFX(X_OF) {
|
||||
BFC(xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
BFC(xFlags, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF | X_ZF) {
|
||||
MOVW(s3, 1);
|
||||
IFX(X_ZF) {
|
||||
BFI(xFlags, s3, F_ZF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
BFI(xFlags, s3, F_PF, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// emit SHR16 instruction, from s1 , s2, store result in s1 using s3 and s4 as scratch, s2 can be same as s3
|
||||
void emit_shr16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_shr16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
SUB_IMM8(s4, s2, 1);
|
||||
MOV_REG_LSR_REG(s4, s1, s4);
|
||||
BFI(xFlags, s4, 0, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CMPS_IMM8(s2, 1); // if s2==1
|
||||
MOV_REG_LSR_IMM5_COND(cEQ, s4, s1, 16);
|
||||
BFI_COND(cEQ, xFlags, s4, F_OF, 1);
|
||||
}
|
||||
MOV_REG_LSR_REG(s1, s1, s2);
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTS_REG_LSL_IMM5(s1, s1, 0);
|
||||
MOVW_COND(cNE, s4, 0);
|
||||
MOVW_COND(cEQ, s4, 1);
|
||||
BFI(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 15);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit SHR16 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_shr16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
if(!c)
|
||||
return;
|
||||
IFX(X_PEND) {
|
||||
MOV32(s3, c);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_shr16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
if(c==1) {
|
||||
BFI(xFlags, s1, 0, 1);
|
||||
} else {
|
||||
MOV_REG_LSR_IMM5(s3, s1, c-1);
|
||||
BFI(xFlags, s3, 0, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 15);
|
||||
BFI(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
}
|
||||
MOV_REG_LSR_IMM5(s1, s1, c);
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTS_REG_LSL_IMM5(s1, s1, 0);
|
||||
MOVW_COND(cNE, s4, 0);
|
||||
MOVW_COND(cEQ, s4, 1);
|
||||
BFI(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 15);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit SAR16 instruction, from s1 , shift s2, store result in s1 using s3 and s4 as scratch, s2 can be same as s3
|
||||
void emit_sar16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_sar16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
SUB_IMM8(s4, s2, 1);
|
||||
MOV_REG_ASR_REG(s4, s1, s4);
|
||||
BFI(xFlags, s4, 0, 1);
|
||||
}
|
||||
MOV_REG_ASR_REG(s1, s1, s2);
|
||||
UBFX(s1, s1, 0, 16);
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTS_REG_LSL_IMM5(s1, s1, 0);
|
||||
MOVW_COND(cNE, s4, 0);
|
||||
MOVW_COND(cEQ, s4, 1);
|
||||
BFI(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 15);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CMPS_IMM8(s2, 1);
|
||||
BFC_COND(cEQ, xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit SAR16 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_sar16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
if(!c)
|
||||
return;
|
||||
IFX(X_PEND) {
|
||||
MOV32(s3, c);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_sar16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
MOV_REG_ASR_IMM5(s3, s1, c-1);
|
||||
BFI(xFlags, s3, 0, 1);
|
||||
}
|
||||
MOV_REG_ASR_IMM5(s1, s1, c);
|
||||
IFX(X_PEND | X_ZF) {
|
||||
UXTH(s1, s1, 0);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTS_REG_LSL_IMM5(s1, s1, 0);
|
||||
MOVW_COND(cNE, s4, 0);
|
||||
MOVW_COND(cEQ, s4, 1);
|
||||
BFI(xFlags, s4, F_ZF, 1);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 15);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF)
|
||||
if(c==1) {
|
||||
BFC(xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -366,6 +926,12 @@ void emit_shrd32c(dynarec_arm_t* dyn, int ninst, int s1, int s2, int32_t c, int
|
||||
}
|
||||
return;
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 31);
|
||||
BFI(xFlags, s4, F_OF, 1); // store sign for later use
|
||||
}
|
||||
}
|
||||
IFX(X_CF) {
|
||||
MOVS_REG_LSR_IMM5(s1, s1, c);
|
||||
} else {
|
||||
@@ -394,13 +960,15 @@ void emit_shrd32c(dynarec_arm_t* dyn, int ninst, int s1, int s2, int32_t c, int
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 30);
|
||||
XOR_REG_LSR_IMM8(s4, s4, s4, 1);
|
||||
MOV_REG_LSR_IMM5(s4, s1, 31);
|
||||
XOR_REG_LSR_IMM8(s4, s4, xFlags, F_OF); // set if sign changed
|
||||
BFI(xFlags, s4, F_OF, 1);
|
||||
} else {
|
||||
BFC(xFlags, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -425,6 +993,12 @@ void emit_shld32c(dynarec_arm_t* dyn, int ninst, int s1, int s2, int32_t c, int
|
||||
}
|
||||
return;
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 31);
|
||||
BFI(xFlags, s4, F_OF, 1); // store sign for later use
|
||||
}
|
||||
}
|
||||
IFX(X_CF) {
|
||||
MOV_REG_LSR_IMM5(s3, s1, 32-c);
|
||||
BFI(xFlags, s3, F_CF, 1);
|
||||
@@ -436,9 +1010,9 @@ void emit_shld32c(dynarec_arm_t* dyn, int ninst, int s1, int s2, int32_t c, int
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
UBFX(s3, s1, (31-c), 1);
|
||||
XOR_IMM8_COND(cCS, s3, s3, 1);
|
||||
BFI(xFlags, s3, F_OF, 1);
|
||||
MOV_REG_LSR_IMM5(s4, s1, 31);
|
||||
XOR_REG_LSR_IMM8(s4, s4, xFlags, F_OF); // set if sign changed
|
||||
BFI(xFlags, s4, F_OF, 1);
|
||||
} else {
|
||||
BFC(xFlags, F_OF, 1);
|
||||
}
|
||||
@@ -461,7 +1035,7 @@ void emit_shld32c(dynarec_arm_t* dyn, int ninst, int s1, int s2, int32_t c, int
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -469,11 +1043,12 @@ void emit_shld32c(dynarec_arm_t* dyn, int ninst, int s1, int s2, int32_t c, int
|
||||
void emit_shrd32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
int j32;
|
||||
MAYUSE(j32);
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
// same flags calc as shr32
|
||||
SET_DF(s4, d_shr32);
|
||||
SET_DF(s4, d_shrd32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
@@ -483,6 +1058,10 @@ void emit_shrd32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
B_NEXT(cEQ);
|
||||
|
||||
IFX(X_OF) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 31);
|
||||
BFI(xFlags, s4, F_OF, 1); // store sign for later use
|
||||
}
|
||||
IFX(X_CF) {
|
||||
MOVS_REG_LSR_REG(s1, s1, s3);
|
||||
} else {
|
||||
@@ -512,12 +1091,76 @@ void emit_shrd32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CMPS_IMM8(s3, 31); // 32-c
|
||||
MOV_REG_LSR_IMM5_COND(cEQ, s4, s1, 30);
|
||||
XOR_REG_LSR_IMM8_COND(cEQ, s4, s4, s4, 1);
|
||||
MOV_REG_LSR_IMM5_COND(cEQ, s4, s1, 31);
|
||||
XOR_REG_LSR_IMM8_COND(cEQ, s4, s4, xFlags, F_OF);
|
||||
BFI_COND(cEQ, xFlags, s4, F_OF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit SHLD32 instruction, from s1, fill s2 , shift s3, store result in s1 using s4 and s3 as scratch
|
||||
void emit_shld32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
int j32;
|
||||
MAYUSE(j32);
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
// same flags calc as shl32
|
||||
SET_DF(s4, d_shld32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
CMPS_IMM8(s3, 0);
|
||||
IFX(F_OF) {
|
||||
BFC_COND(cEQ, xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9_COND(cEQ, s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
B_NEXT(cEQ);
|
||||
|
||||
IFX(X_OF) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 31);
|
||||
BFI(xFlags, s4, F_OF, 1); // store sign for later use
|
||||
}
|
||||
IFX(X_CF) {
|
||||
RSB_IMM8(s4, s3, 32);
|
||||
MOV_REG_LSR_REG(s4, s1, s4);
|
||||
BFI(xFlags, s4, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
MOVS_REG_LSL_REG(s1, s1, s3);
|
||||
} else {
|
||||
MOV_REG_LSL_REG(s1, s1, s3);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CMPS_IMM8(s3, 31); // 32-c
|
||||
MOV_REG_LSR_IMM5_COND(cEQ, s4, s1, 31);
|
||||
XOR_REG_LSR_IMM8_COND(cEQ, s4, s4, xFlags, F_OF);
|
||||
BFI_COND(cEQ, xFlags, s4, F_OF, 1);
|
||||
}
|
||||
RSB_IMM8(s3, s3, 32);
|
||||
IFX(X_ZF) {
|
||||
ORRS_REG_LSR_REG(s1, s1, s2, s3);
|
||||
} else {
|
||||
ORR_REG_LSR_REG(s1, s1, s2, s3);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 31);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -538,8 +1181,8 @@ void emit_rol8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4
|
||||
return;
|
||||
}
|
||||
if(c&7) {
|
||||
BFI(s1, s1, 24, 8); // duplicate the value for rotate left
|
||||
MOV_REG_ROR_IMM5(s1, s1, 32-(c&7));
|
||||
BFI(s1, s1, 8, 8);
|
||||
MOV_REG_LSR_IMM5(s1, s1, 8-(c&7));
|
||||
}
|
||||
//AND_IMM8(s1, s1, 0xff);
|
||||
IFX(X_PEND) {
|
||||
@@ -550,7 +1193,7 @@ void emit_rol8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
ADD_REG_LSR_IMM5(s3, s1, s1, 7);
|
||||
XOR_REG_LSR_IMM8(s3, s1, s1, 7);
|
||||
BFI(xFlags, s3, F_OF, 1);
|
||||
}
|
||||
}
|
||||
@@ -574,7 +1217,7 @@ void emit_ror8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4
|
||||
}
|
||||
if(c&7) {
|
||||
BFI(s1, s1, 8, 8); // duplicate the value for Rotate right
|
||||
MOV_REG_ROR_IMM5(s1, s1, c&7);
|
||||
MOV_REG_LSR_IMM5(s1, s1, c&7);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
AND_IMM8(s1, s1, 0xff);
|
||||
@@ -592,3 +1235,75 @@ void emit_ror8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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, int32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOVW(s3, c);
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_rol16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(!c) {
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(c&15) {
|
||||
BFI(s1, s1, 16, 16);
|
||||
MOV_REG_LSR_IMM5(s1, s1, 16-(c&15));
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
UBFX(s1, s1, 0, 16);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_CF) {
|
||||
BFI(xFlags, s1, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
XOR_REG_LSR_IMM8(s3, s1, s1, 15);
|
||||
BFI(xFlags, s3, F_OF, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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, int32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOVW(s3, c);
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_ror16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(!c) {
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(c&15) {
|
||||
BFI(s1, s1, 16, 16); // duplicate the value for Rotate right
|
||||
MOV_REG_LSR_IMM5(s1, s1, c&15);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
UBFX(s1, s1, 0, 16);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_CF) {
|
||||
MOV_REG_LSR_IMM5(s3, s1, 15);
|
||||
BFI(xFlags, s3, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 14);
|
||||
XOR_REG_LSR_IMM8(s4, s4, s4, 1);
|
||||
BFI(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -55,7 +55,10 @@ void emit_cmp32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
MOV_REG_LSR_IMM5(s4, s3, 31);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
// and now the tricky ones (and mostly unused), PF and AF
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s3, s4);
|
||||
}
|
||||
// and now the tricky ones (and mostly unused), AF
|
||||
IFX(X_AF) {
|
||||
// bc = (res & (~d | s)) | (~d & s)
|
||||
MVN_REG_LSL_IMM5(s4, s1, 0); // s4 = ~d
|
||||
@@ -68,19 +71,6 @@ void emit_cmp32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
BFI(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
IFX(X_CF|X_AF) {
|
||||
SUB_REG_LSL_IMM5(s3, s1, s2, 0);
|
||||
}
|
||||
AND_IMM8(s3, s3, 0xE0); // lsr 5 masking pre-applied
|
||||
MOV32(s4, GetParityTab());
|
||||
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
|
||||
SUB_REG_LSL_IMM5(s3, s1, s2, 0);
|
||||
AND_IMM8(s3, s3, 31);
|
||||
MVN_REG_LSR_REG(s4, s4, s3);
|
||||
BFI(xFlags, s4, F_PF, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// emit CMP32 instruction, from cmp s1 , 0, using s3 and s4 as scratch
|
||||
@@ -112,7 +102,7 @@ void emit_cmp32_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,6 +130,9 @@ void emit_cmp16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
MOV_REG_LSR_IMM5(s4, s3, 15);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s3, s4);
|
||||
}
|
||||
// bc = (res & (~d | s)) | (~d & s)
|
||||
IFX(X_CF|X_AF|X_OF) {
|
||||
MVN_REG_LSL_IMM5(s4, s1, 0); // s4 = ~d
|
||||
@@ -161,18 +154,6 @@ void emit_cmp16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
BFI(xFlags, s4, F_OF, 1); // OF: ((bc >> 14) ^ ((bc>>14)>>1)) & 1
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
IFX(X_CF|X_AF|X_OF) {
|
||||
SUB_REG_LSL_IMM5(s3, s1, s2, 0);
|
||||
}
|
||||
AND_IMM8(s3, s3, 0xE0); // lsr 5 masking pre-applied
|
||||
MOV32(s4, GetParityTab());
|
||||
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
|
||||
SUB_REG_LSL_IMM5(s3, s1, s2, 0);
|
||||
AND_IMM8(s3, s3, 31);
|
||||
MVN_REG_LSR_REG(s4, s4, s3);
|
||||
BFI(xFlags, s4, F_PF, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// emit CMP16 instruction, from cmp s1 , #0, using s3 and s4 as scratch
|
||||
@@ -204,7 +185,7 @@ void emit_cmp16_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
// emit CMP8 instruction, from cmp s1 , s2, using s3 and s4 as scratch
|
||||
@@ -230,6 +211,9 @@ void emit_cmp8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
MOV_REG_LSR_IMM5(s4, s3, 7);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s3, s4);
|
||||
}
|
||||
// bc = (res & (~d | s)) | (~d & s)
|
||||
IFX(X_CF|X_AF|X_OF) {
|
||||
MVN_REG_LSL_IMM5(s4, s1, 0); // s4 = ~d
|
||||
@@ -251,18 +235,6 @@ void emit_cmp8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
BFI(xFlags, s4, F_OF, 1); // OF: ((bc >> 6) ^ ((bc>>6)>>1)) & 1
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
IFX(X_CF|X_AF|X_OF) {
|
||||
SUB_REG_LSL_IMM5(s3, s1, s2, 0);
|
||||
}
|
||||
AND_IMM8(s3, s3, 0xE0); // lsr 5 masking pre-applied
|
||||
MOV32(s4, GetParityTab());
|
||||
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
|
||||
SUB_REG_LSL_IMM5(s3, s1, s2, 0);
|
||||
AND_IMM8(s3, s3, 31);
|
||||
MVN_REG_LSR_REG(s4, s4, s3);
|
||||
BFI(xFlags, s4, F_PF, 1);
|
||||
}
|
||||
}
|
||||
// emit CMP8 instruction, from cmp s1 , 0, using s3 and s4 as scratch
|
||||
void emit_cmp8_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
@@ -292,7 +264,7 @@ void emit_cmp8_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
emit_pf(dyn, ninst, s1, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -321,19 +293,8 @@ void emit_test32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
MOV_REG_LSR_IMM5(s4, s3, 31);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
IFX(X_PF) {
|
||||
AND_IMM8(s3, s3, 0xE0); // lsr 5 masking pre-applied
|
||||
MOV32(s4, GetParityTab());
|
||||
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
|
||||
if(s1==s2) {
|
||||
AND_IMM8(s3, s1, 31);
|
||||
} else {
|
||||
AND_REG_LSL_IMM5(s3, s1, s2, 0);
|
||||
AND_IMM8(s3, s3, 31);
|
||||
}
|
||||
MVN_REG_LSR_REG(s4, s4, s3);
|
||||
BFI(xFlags, s4, F_PF, 1);
|
||||
emit_pf(dyn, ninst, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -362,19 +323,12 @@ void emit_test16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
MOV_REG_LSR_IMM5(s4, s3, 15);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
IFX(X_PF) {
|
||||
AND_IMM8(s3, s3, 0xE0); // lsr 5 masking pre-applied
|
||||
MOV32(s4, GetParityTab());
|
||||
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
|
||||
AND_REG_LSL_IMM5(s3, s1, s2, 0);
|
||||
AND_IMM8(s3, s3, 31);
|
||||
MVN_REG_LSR_REG(s4, s4, s3);
|
||||
BFI(xFlags, s4, F_PF, 1);
|
||||
emit_pf(dyn, ninst, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit TEST8 instruction, from test s1 , s2, using s3 and s4 as scratch
|
||||
// emit TEST8 instruction, from test s1 , s2, using s3 and s4 as scratch. May destroy s2 also
|
||||
void emit_test8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX_PENDOR0 {
|
||||
@@ -399,14 +353,7 @@ void emit_test8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
MOV_REG_LSR_IMM5(s4, s3, 7);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
IFX(X_PF) {
|
||||
AND_IMM8(s3, s3, 0xE0); // lsr 5 masking pre-applied
|
||||
MOV32(s4, GetParityTab());
|
||||
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
|
||||
AND_REG_LSL_IMM5(s3, s1, s2, 0);
|
||||
AND_IMM8(s3, s3, 31);
|
||||
MVN_REG_LSR_REG(s4, s4, s3);
|
||||
BFI(xFlags, s4, F_PF, 1);
|
||||
emit_pf(dyn, ninst, s3, s4);
|
||||
}
|
||||
}
|
||||
+298
-252
File diff suppressed because it is too large.
Load diff
+166
-20
@@ -24,22 +24,27 @@
|
||||
|
||||
// Get Ex as a double, not a quad (warning, x2 and x3 may get used)
|
||||
#define GETEX(a, w) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
if(MODREG) { \
|
||||
a = sse_get_reg(dyn, ninst, x1, nextop&7,w);\
|
||||
} else { \
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 3); \
|
||||
a = fpu_get_scratch_double(dyn); \
|
||||
SMREAD(); \
|
||||
if(parity) { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0, NULL); \
|
||||
VLDR_64(a, ed, fixedaddress); \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0);\
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0, NULL);\
|
||||
LDR_IMM9(x2, ed, fixedaddress+0); \
|
||||
LDR_IMM9(x3, ed, fixedaddress+4); \
|
||||
VMOVtoV_D(a, x2, x3); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define GETGM(a) \
|
||||
gd = (nextop&0x38)>>3; \
|
||||
a = mmx_get_reg(dyn, ninst, x1, x2, x3, gd)
|
||||
|
||||
uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
|
||||
{
|
||||
uint8_t nextop = F8;
|
||||
@@ -63,13 +68,14 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("MOVSD Gx, Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
d0 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
VMOVD(v0, d0);
|
||||
} else {
|
||||
SMREAD();
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0, NULL);
|
||||
LDR_IMM9(x2, ed, fixedaddress+0);
|
||||
LDR_IMM9(x3, ed, fixedaddress+4);
|
||||
VMOVtoV_D(v0, x2, x3);
|
||||
@@ -81,27 +87,29 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
d0 = sse_get_reg(dyn, ninst, x1, nextop&7, 1);
|
||||
VMOVD(d0, v0);
|
||||
} else {
|
||||
VMOVfrV_D(x2, x3, v0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0, NULL);
|
||||
STR_IMM9(x2, ed, fixedaddress+0);
|
||||
STR_IMM9(x3, ed, fixedaddress+4);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x12:
|
||||
INST_NAME("MOVDDUP Gx, Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
d0 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VMOVD(v0, d0);
|
||||
} else {
|
||||
SMREAD();
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0, NULL);
|
||||
LDR_IMM9(x2, ed, fixedaddress+0);
|
||||
LDR_IMM9(x3, ed, fixedaddress+4);
|
||||
VMOVtoV_D(v0, x2, x3);
|
||||
@@ -125,31 +133,53 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
d0 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0, NULL);
|
||||
d0 = fpu_get_scratch_double(dyn);
|
||||
VLDR_64(d0, ed, fixedaddress);
|
||||
}
|
||||
if(!box86_dynarec_fastround) {
|
||||
VMRS(x14); // Get FPCSR reg to clear exceptions flags
|
||||
ORR_IMM8(x3, x14, 0b010, 9); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
}
|
||||
VCVT_S32_F64(s0, d0);
|
||||
VMOVfrV(gd, s0);
|
||||
if(!box86_dynarec_fastround) {
|
||||
VMRS(x3); // get the FPCSR reg and test FPU exception (IO only)
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
MOV_IMM_COND(cNE, gd, 0b10, 1); // 0x80000000
|
||||
VMSR(x14); // put back values
|
||||
}
|
||||
break;
|
||||
case 0x2D:
|
||||
INST_NAME("CVTSD2SI Gd, Ex");
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x14);
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = sse_setround_reset(dyn, ninst, x1, x2, x14);
|
||||
else
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x14);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
d0 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0, NULL);
|
||||
d0 = fpu_get_scratch_double(dyn);
|
||||
VLDR_64(d0, ed, fixedaddress);
|
||||
}
|
||||
VCVTR_S32_F64(s0, d0);
|
||||
VMOVfrV(gd, s0);
|
||||
if(!box86_dynarec_fastround) {
|
||||
VMRS(x3); // get the FPCSR reg and test FPU exception (IO only)
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
MOV_IMM_COND(cNE, gd, 0b10, 1); // 0x80000000
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
|
||||
@@ -159,7 +189,19 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
GETEX(d0, 0);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x14); // get fpscr
|
||||
ORR_IMM8(x3, x14, 0b010, 9); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
}
|
||||
VSQRT_F64(v0, d0);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x3); // get the FPCSR reg and test FPU execption (invalid operation only)
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
VNEG_F64_cond(cNE, v0, v0);
|
||||
VMSR(x14); // restore FPSCR
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x58:
|
||||
@@ -168,7 +210,19 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
GETEX(d0, 0);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x14); // get fpscr
|
||||
ORR_IMM8(x3, x14, 0b010, 9); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
}
|
||||
VADD_F64(v0, v0, d0);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x3); // get the FPCSR reg and test FPU execption (invalid operation only)
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
VNEG_F64_cond(cNE, v0, v0);
|
||||
VMSR(x14); // restore FPSCR
|
||||
}
|
||||
break;
|
||||
case 0x59:
|
||||
INST_NAME("MULSD Gx, Ex");
|
||||
@@ -176,7 +230,19 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
GETEX(d0, 0);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x14); // get fpscr
|
||||
ORR_IMM8(x3, x14, 0b010, 9); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
}
|
||||
VMUL_F64(v0, v0, d0);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x3); // get the FPCSR reg and test FPU execption (invalid operation only)
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
VNEG_F64_cond(cNE, v0, v0);
|
||||
VMSR(x14); // restore FPSCR
|
||||
}
|
||||
break;
|
||||
case 0x5A:
|
||||
INST_NAME("CVTSD2SS Gx, Ex");
|
||||
@@ -200,7 +266,19 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
GETEX(d0, 0);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x14); // get fpscr
|
||||
ORR_IMM8(x3, x14, 0b010, 9); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
}
|
||||
VSUB_F64(v0, v0, d0);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x3); // get the FPCSR reg and test FPU execption (invalid operation only)
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
VNEG_F64_cond(cNE, v0, v0);
|
||||
VMSR(x14); // restore FPSCR
|
||||
}
|
||||
break;
|
||||
case 0x5D:
|
||||
INST_NAME("MINSD Gx, Ex");
|
||||
@@ -219,7 +297,19 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
GETEX(d0, 0);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x14); // get fpscr
|
||||
ORR_IMM8(x3, x14, 0b010, 9); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
}
|
||||
VDIV_F64(v0, v0, d0);
|
||||
if(!box86_dynarec_fastnan) {
|
||||
VMRS(x3); // get the FPCSR reg and test FPU execption (invalid operation only)
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
VNEG_F64_cond(cNE, v0, v0);
|
||||
VMSR(x14); // restore FPSCR
|
||||
}
|
||||
break;
|
||||
case 0x5F:
|
||||
INST_NAME("MAXSD Gx, Ex");
|
||||
@@ -238,10 +328,11 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
v1 = fpu_get_scratch_quad(dyn);
|
||||
VLD1Q_64(v1, ed);
|
||||
}
|
||||
@@ -273,10 +364,11 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
v1 = fpu_get_scratch_quad(dyn);
|
||||
VLD1Q_64(v1, ed);
|
||||
}
|
||||
@@ -288,6 +380,24 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x80:
|
||||
case 0x81:
|
||||
case 0x82:
|
||||
case 0x83:
|
||||
case 0x84:
|
||||
case 0x85:
|
||||
case 0x86:
|
||||
case 0x87:
|
||||
case 0x88:
|
||||
case 0x89:
|
||||
case 0x8A:
|
||||
case 0x8B:
|
||||
case 0x8C:
|
||||
case 0x8D:
|
||||
case 0x8E:
|
||||
case 0x8F:
|
||||
return dynarec0F(dyn, addr-1, ip, ninst, ok, need_epilog);
|
||||
|
||||
case 0xC2:
|
||||
INST_NAME("CMPSD Gx, Ex");
|
||||
nextop = F8;
|
||||
@@ -311,17 +421,53 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
VMOVtoV_D(v0, x2, x2);
|
||||
break;
|
||||
|
||||
case 0xD6:
|
||||
INST_NAME("MOVDQ2Q Gm, Ex");
|
||||
nextop = F8;
|
||||
GETGM(v0);
|
||||
GETEX(v1, 0);
|
||||
VMOV_64(v0, v1);
|
||||
break;
|
||||
|
||||
case 0xE6:
|
||||
INST_NAME("CVTPD2DQ Gx, Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
} else {
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
v1 = fpu_get_scratch_quad(dyn);
|
||||
VLD1Q_8(v1, ed);
|
||||
}
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x14);
|
||||
if(v0<16) {
|
||||
VCVTR_S32_F64(v0*2, v1);
|
||||
VCVTR_S32_F64(v0*2+1, v1+1);
|
||||
} else {
|
||||
d0 = fpu_get_scratch_double(dyn);
|
||||
VCVTR_S32_F64(d0*2, v1);
|
||||
VCVTR_S32_F64(d0*2+1, v1+1);
|
||||
VMOVD(v0, d0);
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
VEOR(v0+1, v0+1, v0+1);
|
||||
break;
|
||||
|
||||
case 0xF0:
|
||||
INST_NAME("LDDQ Gx,Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VMOVQ(v0, v1);
|
||||
} else {
|
||||
SMREAD();
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-12, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-12, 0, 0, NULL);
|
||||
LDR_IMM9(x2, ed, fixedaddress+0);
|
||||
LDR_IMM9(x3, ed, fixedaddress+4);
|
||||
VMOVtoV_D(v0, x2, x3);
|
||||
|
||||
+108
-36
@@ -24,7 +24,7 @@
|
||||
|
||||
// Get Ex as a single, not a quad, with b a intermediary double
|
||||
#define GETEX(a, b) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
if(MODREG) { \
|
||||
b = sse_get_reg(dyn, ninst, x1, nextop&7,0);\
|
||||
if(b<16) \
|
||||
a = b; \
|
||||
@@ -37,8 +37,9 @@
|
||||
b = fpu_get_scratch_double(dyn); \
|
||||
a = b*2; \
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2); \
|
||||
SMREAD(); \
|
||||
if(parity) { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 0, 0); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 0, 0, NULL); \
|
||||
VLDR_32(a, ed, fixedaddress); \
|
||||
} else { \
|
||||
GETED; \
|
||||
@@ -50,6 +51,9 @@
|
||||
gd = (nextop&0x38)>>3; \
|
||||
a = sse_get_reg(dyn, ninst, x1, gd, w)
|
||||
|
||||
#define GETGX_empty(a) gd = ((nextop&0x38)>>3); \
|
||||
a = sse_get_reg_empty(dyn, ninst, x1, gd)
|
||||
|
||||
|
||||
uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
|
||||
{
|
||||
@@ -77,7 +81,7 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("MOVSS Gx, Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
q0 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
if(v0<16)
|
||||
@@ -98,10 +102,18 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
}
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0);
|
||||
LDR_IMM9(x2, ed, fixedaddress); // to avoid bus errors
|
||||
VEORQ(v0, v0, v0);
|
||||
VMOVtoDx_32(v0, 0, x2);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
SMREAD();
|
||||
if(parity && (v0<16)) {
|
||||
VEORQ(v0, v0, v0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 0, 0, NULL);
|
||||
VLDR_32(v0*2, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0, NULL);
|
||||
LDR_IMM9(x2, ed, fixedaddress); // to avoid bus errors
|
||||
VEORQ(v0, v0, v0);
|
||||
VMOVtoDx_32(v0, 0, x2);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x11:
|
||||
@@ -109,7 +121,7 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
q0 = sse_get_reg(dyn, ninst, x1, nextop&7, 1);
|
||||
if(v0<16)
|
||||
d0 = v0;
|
||||
@@ -128,19 +140,27 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
VMOVD(q0, d1);
|
||||
}
|
||||
} else {
|
||||
VMOVfrDx_32(x2, v0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0);
|
||||
STR_IMM9(x2, ed, fixedaddress);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity && (v0<16)) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 0, 0, NULL);
|
||||
VSTR_32(v0*2, ed, fixedaddress);
|
||||
} else {
|
||||
VMOVfrDx_32(x2, v0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0, NULL);
|
||||
STR_IMM9(x2, ed, fixedaddress);
|
||||
}
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
case 0x12:
|
||||
INST_NAME("MOVSLDUP Gx, Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
q1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
q1 = fpu_get_scratch_quad(dyn);
|
||||
VLD1Q_64(q1, ed);
|
||||
}
|
||||
@@ -153,10 +173,11 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("MOVSHDUP Gx, Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
q1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
q1 = fpu_get_scratch_quad(dyn);
|
||||
VLD1Q_64(q1, ed);
|
||||
}
|
||||
@@ -202,7 +223,7 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v0 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
if(v0<16)
|
||||
d0 = v0;
|
||||
@@ -213,25 +234,41 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
VMOV_32(s0, d0*2);
|
||||
} else {
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 3);
|
||||
SMREAD();
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0, NULL);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0, NULL);
|
||||
LDR_IMM9(x2, ed, fixedaddress);
|
||||
VMOVtoV(s0, x2);
|
||||
}
|
||||
}
|
||||
if(!box86_dynarec_fastround) {
|
||||
VMRS(x14); // Get FPCSR reg to clear exceptions flags
|
||||
ORR_IMM8(x3, x14, 0b010, 9); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
}
|
||||
VCVT_S32_F32(s0, s0);
|
||||
VMOVfrV(gd, s0);
|
||||
if(!box86_dynarec_fastround) {
|
||||
VMRS(x3); // get the FPCSR reg and test FPU exception (IO only)
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
MOV_IMM_COND(cNE, gd, 0b10, 1); // 0x80000000
|
||||
VMSR(x14); // put back values
|
||||
}
|
||||
break;
|
||||
case 0x2D:
|
||||
INST_NAME("CVTSS2SI Gd, Ex");
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x14);
|
||||
if(!box86_dynarec_fastround)
|
||||
u8 = sse_setround_reset(dyn, ninst, x1, x2, x14);
|
||||
else
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x14);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v0 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
if(v0<16)
|
||||
d0 = v0;
|
||||
@@ -242,17 +279,23 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
VMOV_32(s0, d0*2);
|
||||
} else {
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 3);
|
||||
SMREAD();
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0, NULL);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0, NULL);
|
||||
LDR_IMM9(x2, ed, fixedaddress);
|
||||
VMOVtoV(s0, x2);
|
||||
}
|
||||
}
|
||||
VCVTR_S32_F32(s0, s0);
|
||||
VMOVfrV(gd, s0);
|
||||
if(!box86_dynarec_fastround) {
|
||||
VMRS(x3); // get the FPCSR reg and test FPU exception (IO only)
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
MOV_IMM_COND(cNE, gd, 0b10, 1); // 0x80000000
|
||||
}
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
|
||||
@@ -377,10 +420,11 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
case 0x5B:
|
||||
INST_NAME("CVTTPS2DQ Gx, Ex");
|
||||
nextop = F8;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
v1 = fpu_get_scratch_quad(dyn);
|
||||
VLD1Q_64(v1, ed);
|
||||
}
|
||||
@@ -479,13 +523,14 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("MOVDQU Gx,Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VMOVQ(v0, v1);
|
||||
} else {
|
||||
SMREAD();
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-12, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-12, 0, 0, NULL);
|
||||
LDR_IMM9(x2, ed, fixedaddress+0);
|
||||
LDR_IMM9(x3, ed, fixedaddress+4);
|
||||
VMOVtoV_D(v0, x2, x3);
|
||||
@@ -498,14 +543,15 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("PSHUFHW Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
SMREAD();
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
v1 = fpu_get_scratch_quad(dyn);
|
||||
VLD1Q_64(v1, ed);
|
||||
}
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
u8 = F8;
|
||||
// only high part need to be shuffled. VTBL only handle 8bits value, so the 16bits shuffles need to be changed in 8bits
|
||||
u32 = 0;
|
||||
@@ -533,13 +579,14 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("MOVQ Gx, Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VMOVD(v0, v1);
|
||||
} else {
|
||||
SMREAD();
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0, NULL);
|
||||
VLD1_64(v0, ed);
|
||||
}
|
||||
VEOR(v0+1, v0+1, v0+1);
|
||||
@@ -549,17 +596,18 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, nextop&7);
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-12, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-12, 0, 0, NULL);
|
||||
VMOVfrV_D(x2, x3, v0);
|
||||
STR_IMM9(x2, ed, fixedaddress+0);
|
||||
STR_IMM9(x3, ed, fixedaddress+4);
|
||||
VMOVfrV_D(x2, x3, v0+1);
|
||||
STR_IMM9(x2, ed, fixedaddress+8);
|
||||
STR_IMM9(x3, ed, fixedaddress+12);
|
||||
SMWRITE2();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -614,10 +662,33 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
VMOVtoDx_32(v0, 0, x2);
|
||||
break;
|
||||
|
||||
case 0xD6:
|
||||
INST_NAME("MOVQ2DQ Gx, Em");
|
||||
nextop = F8;
|
||||
GETGX_empty(v0);
|
||||
if(MODREG) {
|
||||
v1 = mmx_get_reg(dyn, ninst, x1, x2, x3, (nextop&7));
|
||||
VEORQ(v0, v0, v0); // usefull?
|
||||
VMOV_64(v0, v1);
|
||||
} else {
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 3);
|
||||
SMREAD();
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0, NULL);
|
||||
VLDR_64(v0, ed, fixedaddress); // vfpu opcode here
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-8, 0, 0, NULL);
|
||||
LDR_IMM9(x2, ed, fixedaddress);
|
||||
LDR_IMM9(x3, ed, fixedaddress+4);
|
||||
VMOVtoV_D(v0, x2, x3);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xE6:
|
||||
INST_NAME("CVTDQ2PD Gx, Ex");
|
||||
nextop = F8;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
if(MODREG) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
if(v1<16)
|
||||
v0 = v1;
|
||||
@@ -628,11 +699,12 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
} else {
|
||||
v0 = fpu_get_scratch_double(dyn);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 3);
|
||||
SMREAD();
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0, NULL);
|
||||
VLDR_64(v0, ed, fixedaddress); // vfpu opcode here
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-8, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-8, 0, 0, NULL);
|
||||
LDR_IMM9(x2, ed, fixedaddress);
|
||||
LDR_IMM9(x3, ed, fixedaddress+4);
|
||||
VMOVtoV_D(v0, x2, x3);
|
||||
|
||||
+713
-122
File diff suppressed because it is too large.
Load diff
@@ -16,14 +16,29 @@ void arm_fscale(x86emu_t* emu);
|
||||
void arm_fbld(x86emu_t* emu, uint8_t* ed);
|
||||
void arm_fild64(x86emu_t* emu, int64_t* ed);
|
||||
void arm_fbst(x86emu_t* emu, uint8_t* ed);
|
||||
void arm_fistp64(x86emu_t* emu, int64_t* ed);
|
||||
void arm_fistt64(x86emu_t* emu, int64_t* ed);
|
||||
void arm_fld(x86emu_t* emu, uint8_t* ed);
|
||||
void arm_fsave(x86emu_t* emu, uint8_t* ed);
|
||||
void arm_frstor(x86emu_t* emu, uint8_t* ed);
|
||||
void arm_fprem1(x86emu_t* emu);
|
||||
|
||||
void arm_aesd(x86emu_t* emu, int xmm);
|
||||
void arm_aese(x86emu_t* emu, int xmm);
|
||||
void arm_aesdlast(x86emu_t* emu, int xmm);
|
||||
void arm_aeselast(x86emu_t* emu, int xmm);
|
||||
void arm_aesimc(x86emu_t* emu, int xmm);
|
||||
void arm_aeskeygenassist(x86emu_t* emu, int gx, void* p, uint32_t u8);
|
||||
void arm_pclmul(x86emu_t* emu, int gx, void* p, uint32_t u8);
|
||||
|
||||
void arm_clflush(x86emu_t* emu, void* p);
|
||||
|
||||
int64_t arm_fist64_0(double d);
|
||||
int64_t arm_fist64_1(double d);
|
||||
int64_t arm_fist64_2(double d);
|
||||
int64_t arm_fist64_3(double d);
|
||||
|
||||
void arm_ud(x86emu_t* emu);
|
||||
void arm_priv(x86emu_t* emu);
|
||||
void arm_singlestep(x86emu_t* emu);
|
||||
|
||||
#define FPUFIRST 8
|
||||
|
||||
@@ -50,19 +65,44 @@ void fpu_reset_reg(dynarec_arm_t* dyn);
|
||||
// Get type for STx
|
||||
int neoncache_get_st(dynarec_arm_t* dyn, int ninst, int a);
|
||||
// Get if STx is FLOAT or DOUBLE
|
||||
int neoncache_get_st_f(dynarec_arm_t* dyn, int ninst, int a, int st);
|
||||
int neoncache_get_st_f(dynarec_arm_t* dyn, int ninst, int a);
|
||||
// Get actual type for STx
|
||||
int neoncache_get_current_st(dynarec_arm_t* dyn, int ninst, int a);
|
||||
// Get actual STx is FLOAT or DOUBLE
|
||||
int neoncache_get_current_st_f(dynarec_arm_t* dyn, int a);
|
||||
// Back-propagate a change float->double
|
||||
void neoncache_promote_double(dynarec_arm_t* dyn, int ninst, int a, int st);
|
||||
void neoncache_promote_double(dynarec_arm_t* dyn, int ninst, int a);
|
||||
// Combine and propagate if needed (pass 1 only)
|
||||
int neoncache_combine_st(dynarec_arm_t* dyn, int ninst, int a, int b); // with stack current dyn->n_stack*
|
||||
|
||||
// FPU Cache transformation (for loops)
|
||||
int CacheNeedsTransform(dynarec_arm_t* dyn, int i1);
|
||||
|
||||
// Undo the changes of a neoncache to get the status before the instruction
|
||||
void neoncacheUnwind(neoncache_t* cache);
|
||||
|
||||
// predecessor access
|
||||
int isPred(dynarec_arm_t* dyn, int ninst, int pred);
|
||||
int getNominalPred(dynarec_arm_t* dyn, int ninst);
|
||||
|
||||
// Get if ED will have the correct parity. Not emiting 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);
|
||||
// Do the GETED, but don't emit anything...
|
||||
uintptr_t fakeed(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop);
|
||||
uint8_t geted_ib(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop);
|
||||
|
||||
// Is what pointed at addr a native call? And if yes, to what function?
|
||||
int isNativeCall(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t* calladdress, int* retn);
|
||||
|
||||
const char* getCacheName(int t, int n);
|
||||
|
||||
void inst_name_pass3(dynarec_arm_t* dyn, int ninst, const char* name);
|
||||
void print_opcode(dynarec_arm_t* dyn, int ninst, uint32_t opcode);
|
||||
|
||||
// reset the cache
|
||||
void fpu_reset(dynarec_arm_t* dyn);
|
||||
void fpu_reset_ninst(dynarec_arm_t* dyn, int ninst);
|
||||
|
||||
// is st freed
|
||||
int fpu_is_st_freed(dynarec_arm_t* dyn, int ninst, int st);
|
||||
#endif //__DYNAREC_ARM_FUNCTIONS_H__
|
||||
+1259
-365
File diff suppressed because it is too large.
Load diff
@@ -27,6 +27,38 @@
|
||||
#define PKip(a) *(uint8_t*)(ip+a)
|
||||
#define PKa(a) *(uint8_t*)(a)
|
||||
|
||||
#define MODREG ((nextop&0xC0)==0xC0)
|
||||
|
||||
// Strong mem emulation helpers
|
||||
#define SMREAD_MIN 2
|
||||
#define SMWRITE_MIN 1
|
||||
// Sequence of Read will trigger a DMB on "first" read if strongmem is >= SMREAD_MIN
|
||||
// Sequence of Write will trigger a DMB on "last" write if strongmem is >= 1
|
||||
// All Write operation that might use a lock all have a memory barrier if strongmem is >= SMWRITE_MIN
|
||||
// Opcode will read
|
||||
#define SMREAD() if((dyn->smread==0) && (box86_dynarec_strongmem>SMREAD_MIN)) {SMDMB();} else dyn->smread=1
|
||||
// Opcode will read with option forced lock
|
||||
#define SMREADLOCK(lock) if((lock) || ((dyn->smread==0) && (box86_dynarec_strongmem>SMREAD_MIN))) {SMDMB();}
|
||||
// Opcode might read (depend on nextop)
|
||||
#define SMMIGHTREAD() if(!MODREG) {SMREAD();}
|
||||
// Opcode has wrote
|
||||
#define SMWRITE() dyn->smwrite=1
|
||||
// Opcode has wrote (strongmem>1 only)
|
||||
#define SMWRITE2() if(box86_dynarec_strongmem>SMREAD_MIN) dyn->smwrite=1
|
||||
// Opcode has wrote with option forced lock
|
||||
#define SMWRITELOCK(lock) if(lock || (box86_dynarec_strongmem>SMWRITE_MIN)) {SMDMB();} else dyn->smwrite=1
|
||||
// Opcode might have wrote (depend on nextop)
|
||||
#define SMMIGHTWRITE() if(!MODREG) {SMWRITE();}
|
||||
// Start of sequence
|
||||
#define SMSTART() SMEND()
|
||||
// End of sequence
|
||||
#define SMEND() if(dyn->smwrite && box86_dynarec_strongmem) {if(box86_dynarec_strongmem){DSB_ISH();}else{DMB_ISH();}} dyn->smwrite=0; dyn->smread=0;
|
||||
// Force a Data memory barrier (for LOCK: prefix)
|
||||
#define SMDMB() if(box86_dynarec_strongmem){DSB_ISH();}else{DMB_ISH();} dyn->smwrite=0; dyn->smread=1
|
||||
|
||||
//LOCK_* define
|
||||
#define LOCK_LOCK (int*)1
|
||||
|
||||
// GETGD get x86 register in gd
|
||||
#define GETGD gd = xEAX+((nextop&0x38)>>3)
|
||||
//GETED can use r1 for ed, and r2 for wback. wback is 0 if ed is xEAX..xEDI
|
||||
@@ -34,7 +66,8 @@
|
||||
ed = xEAX+(nextop&7); \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 4095, 0, 0); \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 4095, 0, 0, NULL); \
|
||||
LDR_IMM9(x1, wback, fixedaddress); \
|
||||
ed = x1; \
|
||||
}
|
||||
@@ -43,7 +76,8 @@
|
||||
ed = xEAX+(nextop&7); \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, (hint==x2)?x1:x2, &fixedaddress, 4095, 0, 0); \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, (hint==x2)?x1:x2, &fixedaddress, 4095, 0, 0, NULL); \
|
||||
LDR_IMM9(hint, wback, fixedaddress); \
|
||||
ed = hint; \
|
||||
}
|
||||
@@ -53,20 +87,22 @@
|
||||
MOV_REG(ret, ed); \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, hint, &fixedaddress, 4095, 0, 0); \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, hint, &fixedaddress, 4095, 0, 0, NULL); \
|
||||
ed = ret; \
|
||||
LDR_IMM9(ed, wback, fixedaddress); \
|
||||
}
|
||||
// Write back ed in wback (if wback not 0)
|
||||
#define WBACK if(wback) {STR_IMM9(ed, wback, fixedaddress);}
|
||||
// Send back wb to either ed or wback
|
||||
#define SBACK(wb) if(wback) {STR_IMM9(wb, wback, fixedaddress);} else {MOV_REG(ed, wb);}
|
||||
#define WBACK if(wback) {STR_IMM9(ed, wback, fixedaddress); SMWRITE();}
|
||||
// Write back ed in wback (if wback not 0) (SMWRITE2 version)
|
||||
#define WBACK2 if(wback) {STR_IMM9(ed, wback, fixedaddress); SMWRITE2();}
|
||||
//GETEDO can use r1 for ed, and r2 for wback. wback is 0 if ed is xEAX..xEDI
|
||||
#define GETEDO(O) if((nextop&0xC0)==0xC0) { \
|
||||
ed = xEAX+(nextop&7); \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 0); \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 0, NULL); \
|
||||
LDR_REG_LSL_IMM5(x1, wback, O, 0); \
|
||||
ed = x1; \
|
||||
}
|
||||
@@ -75,18 +111,22 @@
|
||||
ed = xEAX+(nextop&7); \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 0); \
|
||||
ADD_REG_LSL_IMM5(wback, wback, O, 0);\
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 0, NULL); \
|
||||
ADD_REG_LSL_IMM5(x2, wback, O, 0); \
|
||||
if(wback != x2) wback = x2; \
|
||||
LDR_IMM9(x1, wback, 0); \
|
||||
ed = x1; \
|
||||
}
|
||||
#define WBACKO(O) if(wback) {STR_REG_LSL_IMM5(ed, wback, O, 0);}
|
||||
#define WBACKO(O) if(wback) {STR_REG_LSL_IMM5(ed, wback, O, 0); SMWRITE();}
|
||||
//FAKEELike GETED, but doesn't get anything
|
||||
#define FAKEED if((nextop&0xC0)!=0xC0) { \
|
||||
addr = fakeed(dyn, addr, ninst, nextop); \
|
||||
}
|
||||
// GETGW extract x86 register in gd, that is i
|
||||
#define GETGW(i) gd = xEAX+((nextop&0x38)>>3); UXTH(i, gd, 0); gd = i;
|
||||
// GETSGW extract x86 signed register in gd, that is i
|
||||
#define GETSGW(i) gd = xEAX+((nextop&0x38)>>3); SXTH(i, gd, 0); gd = i;
|
||||
//GETEWW will use i for ed, and can use w for wback.
|
||||
#define GETEWW(w, i) if((nextop&0xC0)==0xC0) { \
|
||||
wback = xEAX+(nextop&7);\
|
||||
@@ -94,7 +134,8 @@
|
||||
ed = i; \
|
||||
wb1 = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, w, &fixedaddress, 255, 0, 0); \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, w, &fixedaddress, 255, 0, 0, NULL); \
|
||||
LDRH_IMM8(i, wback, fixedaddress); \
|
||||
ed = i; \
|
||||
wb1 = 1; \
|
||||
@@ -106,7 +147,8 @@
|
||||
ed = i; \
|
||||
wb1 = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0); \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0, NULL); \
|
||||
LDRH_IMM8(i, wback, fixedaddress); \
|
||||
ed = i; \
|
||||
wb1 = 1; \
|
||||
@@ -118,15 +160,16 @@
|
||||
ed = i; \
|
||||
wb1 = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0); \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0, NULL); \
|
||||
LDRSH_IMM8(i, wback, fixedaddress);\
|
||||
ed = i; \
|
||||
wb1 = 1; \
|
||||
}
|
||||
// Write ed back to original register / memory
|
||||
#define EWBACK if(wb1) {STRH_IMM8(ed, wback, fixedaddress);} else {BFI(wback, ed, 0, 16);}
|
||||
#define EWBACK if(wb1) {STRH_IMM8(ed, wback, fixedaddress); SMWRITE();} else {BFI(wback, ed, 0, 16);}
|
||||
// Write w back to original register / memory
|
||||
#define EWBACKW(w) if(wb1) {STRH_IMM8(w, wback, fixedaddress);} else {BFI(wback, w, 0, 16);}
|
||||
#define EWBACKW(w) if(wb1) {STRH_IMM8(w, wback, fixedaddress); SMWRITE();} else {BFI(wback, w, 0, 16);}
|
||||
// Write back gd in correct register
|
||||
#define GWBACK BFI((xEAX+((nextop&0x38)>>3)), gd, 0, 16);
|
||||
//GETEB will use i for ed, and can use r3 for wback.
|
||||
@@ -138,7 +181,8 @@
|
||||
wb1 = 0; \
|
||||
ed = i; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 4095, 0, 0); \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 4095, 0, 0, NULL); \
|
||||
LDRB_IMM9(i, wback, fixedaddress); \
|
||||
wb1 = 1; \
|
||||
ed = i; \
|
||||
@@ -152,9 +196,11 @@
|
||||
wb1 = 0; \
|
||||
ed = i; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, 0); \
|
||||
ADD_REG_LSL_IMM5(wback, wback, i, 0); \
|
||||
LDRB_IMM9(i, wback, fixedaddress); \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, 0, NULL); \
|
||||
ADD_REG_LSL_IMM5(x3, wback, i, 0); \
|
||||
if(wback!=x3) wback = x3; \
|
||||
LDRB_IMM9(i, wback, fixedaddress); \
|
||||
wb1 = 1; \
|
||||
ed = i; \
|
||||
}
|
||||
@@ -167,13 +213,16 @@
|
||||
wb1 = 0; \
|
||||
ed = i; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0); \
|
||||
SMREAD(); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0, NULL); \
|
||||
LDRSB_IMM8(i, wback, fixedaddress);\
|
||||
wb1 = 1; \
|
||||
ed = i; \
|
||||
}
|
||||
// Write eb (ed) back to original register / memory
|
||||
#define EBBACK if(wb1) {STRB_IMM9(ed, wback, fixedaddress);} else {BFI(wback, ed, wb2*8, 8);}
|
||||
#define EBBACK if(wb1) {STRB_IMM9(ed, wback, fixedaddress); SMWRITE();} else {BFI(wback, ed, wb2*8, 8);}
|
||||
// Write eb (ed) back to original register / memory (SMWRITE2 version)
|
||||
#define EBBACK2 if(wb1) {STRB_IMM9(ed, wback, fixedaddress); SMWRITE2();} else {BFI(wback, ed, wb2*8, 8);}
|
||||
//GETGB will use i for gd
|
||||
#define GETGB(i) gd = (nextop&0x38)>>3; \
|
||||
gb2 = ((gd&4)>>2); \
|
||||
@@ -211,18 +260,28 @@
|
||||
#define CALL_2D(F, M) call_d(dyn, ninst, F, NULL, 2, x3, -1, M, 0)
|
||||
// CALL_1DD will use x3 for the call address. Return value in D0, 1 ARG in D0, cals 2 functions in a row
|
||||
#define CALL_1DD(F, F2, M) call_d(dyn, ninst, F, F2, 1, x3, -1, M, 0)
|
||||
// CALL_1D_U64 will use S as scratch. Return value in ret/ret2, 1 ARG in D0
|
||||
#define CALL_1DR_U64(R, ret, ret2, S, M) call_dr(dyn, ninst, R, 1, S, ret, ret2, M, 1)
|
||||
// CALL_1DR will use S as scratch. Return value in D0, 1 ARG in D0
|
||||
#define CALL_1DR(R, S, M) call_dr(dyn, ninst, R, 1, S, -1, -1, M, 0)
|
||||
// CALL_1DI will use S as scratch. Return value in D0, 1 ARG in D0, 1 ARG in R0
|
||||
#define CALL_1DDR(F, R, S, M) call_ddr(dyn, ninst, F, NULL, R, S, -1, M, 0)
|
||||
// CALL_1RD will use S as scratch. Return value in D0, 1 ARG in R
|
||||
#define CALL_1RD(F, R, S, M) call_rd(dyn, ninst, F, R, S, M, 0);
|
||||
|
||||
#define MARK if(dyn->insts) {dyn->insts[ninst].mark = (uintptr_t)dyn->arm_size;}
|
||||
#define GETMARK ((dyn->insts)?dyn->insts[ninst].mark:(dyn->arm_size+4))
|
||||
#define MARK2 if(dyn->insts) {dyn->insts[ninst].mark2 = (uintptr_t)dyn->arm_size;}
|
||||
#define GETMARK2 ((dyn->insts)?dyn->insts[ninst].mark2:(dyn->arm_size+4))
|
||||
#define MARK3 if(dyn->insts) {dyn->insts[ninst].mark3 = (uintptr_t)dyn->arm_size;}
|
||||
#define GETMARK3 ((dyn->insts)?dyn->insts[ninst].mark3:(dyn->arm_size+4))
|
||||
#define MARKF if(dyn->insts) {dyn->insts[ninst].markf = (uintptr_t)dyn->arm_size;}
|
||||
#define GETMARKF ((dyn->insts)?dyn->insts[ninst].markf:(dyn->arm_size+4))
|
||||
#define MARKSEG if(dyn->insts) {dyn->insts[ninst].markseg = (uintptr_t)dyn->arm_size;}
|
||||
#define GETMARKSEG ((dyn->insts)?dyn->insts[ninst].markseg:(dyn->arm_size+4))
|
||||
#define MARKLOCK if(dyn->insts) {dyn->insts[ninst].marklock = (uintptr_t)dyn->arm_size;}
|
||||
#define MARK if(dyn->insts) {dyn->insts[ninst].mark = (uintptr_t)dyn->arm_size;}
|
||||
#define GETMARK ((dyn->insts)?dyn->insts[ninst].mark:(dyn->arm_size+4))
|
||||
#define MARK2 if(dyn->insts) {dyn->insts[ninst].mark2 = (uintptr_t)dyn->arm_size;}
|
||||
#define GETMARK2 ((dyn->insts)?dyn->insts[ninst].mark2:(dyn->arm_size+4))
|
||||
#define MARK3 if(dyn->insts) {dyn->insts[ninst].mark3 = (uintptr_t)dyn->arm_size;}
|
||||
#define GETMARK3 ((dyn->insts)?dyn->insts[ninst].mark3:(dyn->arm_size+4))
|
||||
#define MARKF if(dyn->insts) {dyn->insts[ninst].markf = (uintptr_t)dyn->arm_size;}
|
||||
#define GETMARKF ((dyn->insts)?dyn->insts[ninst].markf:(dyn->arm_size+4))
|
||||
#define MARKF2 if(dyn->insts) {dyn->insts[ninst].markf2 = (uintptr_t)dyn->arm_size;}
|
||||
#define GETMARKF2 ((dyn->insts)?dyn->insts[ninst].markf2:(dyn->arm_size+4))
|
||||
#define MARKSEG if(dyn->insts) {dyn->insts[ninst].markseg = (uintptr_t)dyn->arm_size;}
|
||||
#define GETMARKSEG ((dyn->insts)?dyn->insts[ninst].markseg:(dyn->arm_size+4))
|
||||
#define MARKLOCK if(dyn->insts) {dyn->insts[ninst].marklock = (uintptr_t)dyn->arm_size;}
|
||||
#define GETMARKLOCK ((dyn->insts)?dyn->insts[ninst].marklock:(dyn->arm_size+4))
|
||||
|
||||
// Branch to MARK if cond (use j32)
|
||||
@@ -239,7 +298,7 @@
|
||||
Bcond(cond, j32)
|
||||
// Branch to next instruction if cond (use j32)
|
||||
#define B_NEXT(cond) \
|
||||
j32 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->arm_size+8)):0; \
|
||||
j32 = dyn->insts[ninst].epilog-(dyn->arm_size+8); \
|
||||
Bcond(cond, j32)
|
||||
// Branch to MARKSEG if cond (use j32)
|
||||
#define B_MARKSEG(cond) \
|
||||
@@ -250,14 +309,14 @@
|
||||
j32 = GETMARKLOCK-(dyn->arm_size+8); \
|
||||
Bcond(cond, j32)
|
||||
|
||||
#define IFX(A) if((dyn->insts[ninst].x86.need_flags&(A)))
|
||||
#define IFX_PENDOR0 if((dyn->insts[ninst].x86.need_flags&(X_PEND) || !dyn->insts[ninst].x86.need_flags))
|
||||
#define IFXX(A) if((dyn->insts[ninst].x86.need_flags==(A)))
|
||||
#define IFX2X(A, B) if((dyn->insts[ninst].x86.need_flags==(A) || dyn->insts[ninst].x86.need_flags==(B) || dyn->insts[ninst].x86.need_flags==((A)|(B))))
|
||||
#define IFXN(A, B) if((dyn->insts[ninst].x86.need_flags&(A) && !(dyn->insts[ninst].x86.need_flags&(B))))
|
||||
#define IFX(A) if((dyn->insts[ninst].x86.gen_flags&(A)))
|
||||
#define IFX_PENDOR0 if((dyn->insts[ninst].x86.gen_flags&(X_PEND) || !dyn->insts[ninst].x86.gen_flags))
|
||||
#define IFXX(A) if((dyn->insts[ninst].x86.gen_flags==(A)))
|
||||
#define IFX2X(A, B) if((dyn->insts[ninst].x86.gen_flags==(A) || dyn->insts[ninst].x86.gen_flags==(B) || dyn->insts[ninst].x86.gen_flags==((A)|(B))))
|
||||
#define IFXN(A, B) if((dyn->insts[ninst].x86.gen_flags&(A) && !(dyn->insts[ninst].x86.gen_flags&(B))))
|
||||
|
||||
// Generate FCOM with s1 and s2 scratch regs (the VCMP is already done)
|
||||
#define FCOM(s1, s2) \
|
||||
#define FCOM(s1, s2) \
|
||||
VMRS_APSR(); /* 0b0100011100000000 */ \
|
||||
LDRH_IMM8(s1, xEmu, offsetof(x86emu_t, sw)); /*offset is 8bits right?*/ \
|
||||
BIC_IMM8(s1, s1, 0b01000111, 12); \
|
||||
@@ -268,7 +327,7 @@
|
||||
STRH_IMM8(s1, xEmu, offsetof(x86emu_t, sw))
|
||||
|
||||
// Generate FCOMI with s1 and s2 scratch regs (the VCMP is already done)
|
||||
#define FCOMI(s1, s2) \
|
||||
#define FCOMI(s1, s2) \
|
||||
IFX(X_CF|X_PF|X_ZF|X_PEND) { \
|
||||
VMRS_APSR(); /* 0b111 */ \
|
||||
BIC_IMM8(xFlags, xFlags, 0b1000101, 0); \
|
||||
@@ -276,23 +335,67 @@
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 0b01000000, 0); /* zero */ \
|
||||
ORR_IMM8_COND(cMI, xFlags, xFlags, 0b00000001, 0); /* less than */ \
|
||||
/* greater than leave 0 */ \
|
||||
} \
|
||||
SET_DFNONE(s1); \
|
||||
IFX(X_OF|X_AF|X_SF|X_PEND) { \
|
||||
/* clear 0b100010010000 */ \
|
||||
BIC_IMM8(xFlags, xFlags, 0b10001001, 14); \
|
||||
} \
|
||||
SET_DFNONE(s1); \
|
||||
|
||||
|
||||
#define SET_DFNONE(S) if(!dyn->dfnone) {MOVW(S, d_none); STR_IMM9(S, xEmu, offsetof(x86emu_t, df)); dyn->dfnone=1;}
|
||||
#define SET_DF(S, N) if(N) {MOVW(S, N); STR_IMM9(S, xEmu, offsetof(x86emu_t, df)); dyn->dfnone=0;} else SET_DFNONE(S)
|
||||
#define SET_NODF() dyn->dfnone = 0
|
||||
#define SET_DFOK() dyn->dfnone = 1
|
||||
#if STEP == 0
|
||||
#define X87_PUSH_OR_FAIL(var, dyn, ninst, scratch, t) var = x87_do_push(dyn, ninst, scratch, t)
|
||||
#define X87_PUSH_EMPTY_OR_FAIL(dyn, ninst, scratch) x87_do_push_empty(dyn, ninst, scratch)
|
||||
#define X87_POP_OR_FAIL(dyn, ninst, scratch) x87_do_pop(dyn, ninst, scratch)
|
||||
#else
|
||||
#define X87_PUSH_OR_FAIL(var, dyn, ninst, scratch, t) \
|
||||
if ((dyn->n.x87stack==8) || (dyn->n.pushed==8)) { \
|
||||
if(box86_dynarec_dump) dynarec_log(LOG_NONE, " Warning, suspicious x87 Push, stack=%d/%d on inst %d\n", dyn->n.x87stack, dyn->n.pushed, ninst); \
|
||||
dyn->abort = 1; \
|
||||
return addr; \
|
||||
} \
|
||||
var = x87_do_push(dyn, ninst, scratch, t)
|
||||
|
||||
#define X87_PUSH_EMPTY_OR_FAIL(dyn, ninst, scratch) \
|
||||
if ((dyn->n.x87stack==8) || (dyn->n.pushed==8)) { \
|
||||
if(box86_dynarec_dump) dynarec_log(LOG_NONE, " Warning, suspicious x87 Push, stack=%d/%d on inst %d\n", dyn->n.x87stack, dyn->n.pushed, ninst); \
|
||||
dyn->abort = 1; \
|
||||
return addr; \
|
||||
} \
|
||||
x87_do_push_empty(dyn, ninst, scratch)
|
||||
|
||||
#define X87_POP_OR_FAIL(dyn, ninst, scratch) \
|
||||
if ((dyn->n.x87stack==-8) || (dyn->n.poped==8)) { \
|
||||
if(box86_dynarec_dump) dynarec_log(LOG_NONE, " Warning, suspicious x87 Pop, stack=%d/%d on inst %d\n", dyn->n.x87stack, dyn->n.poped, ninst); \
|
||||
dyn->abort = 1; \
|
||||
return addr; \
|
||||
} \
|
||||
x87_do_pop(dyn, ninst, scratch)
|
||||
#endif
|
||||
|
||||
|
||||
#define SET_DFNONE(S) if(!dyn->f.dfnone) {MOVW(S, d_none); STR_IMM9(S, xEmu, offsetof(x86emu_t, df)); dyn->f.dfnone=1;}
|
||||
#define SET_DF(S, N) \
|
||||
if(N) { \
|
||||
MOVW(S, N);\
|
||||
STR_IMM9(S, xEmu, offsetof(x86emu_t, df)); \
|
||||
if(dyn->f.pending==SF_PENDING && dyn->insts[ninst].x86.need_after && !(dyn->insts[ninst].x86.need_after&X_PEND)) { \
|
||||
CALL_(UpdateFlags, -1, 0); \
|
||||
dyn->f.pending = SF_SET; \
|
||||
SET_NODF(); \
|
||||
} \
|
||||
dyn->f.dfnone=0;\
|
||||
} else SET_DFNONE(S)
|
||||
#define SET_NODF() dyn->f.dfnone = 0
|
||||
#define SET_DFOK() dyn->f.dfnone = 1
|
||||
|
||||
#ifndef MAYSETFLAGS
|
||||
#define MAYSETFLAGS()
|
||||
#endif
|
||||
|
||||
#ifndef READFLAGS
|
||||
#define READFLAGS(A) \
|
||||
if(((A)!=X_PEND) && dyn->state_flags!=SF_SET && dyn->state_flags!=SF_SET_PENDING) { \
|
||||
if(dyn->state_flags!=SF_PENDING) { \
|
||||
if(((A)!=X_PEND && dyn->f.pending!=SF_SET) \
|
||||
&& (dyn->f.pending!=SF_SET_PENDING)) { \
|
||||
if(dyn->f.pending!=SF_PENDING) { \
|
||||
LDR_IMM9(x3, xEmu, offsetof(x86emu_t, df)); \
|
||||
TSTS_REG_LSL_IMM5(x3, x3, 0); \
|
||||
j32 = (GETMARKF)-(dyn->arm_size+8); \
|
||||
@@ -300,19 +403,31 @@
|
||||
} \
|
||||
CALL_(UpdateFlags, -1, 0); \
|
||||
MARKF; \
|
||||
dyn->state_flags = SF_SET; \
|
||||
dyn->f.pending = SF_SET; \
|
||||
SET_DFOK(); \
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef SETFLAGS
|
||||
#define SETFLAGS(A, B) \
|
||||
if(dyn->state_flags!=SF_SET && B==SF_SUBSET && (dyn->insts[ninst].x86.need_flags&(~((A)/*|X_PEND*/)))) \
|
||||
READFLAGS(dyn->insts[ninst].x86.need_flags&(~(A)|X_PEND)); \
|
||||
dyn->state_flags = (B==SF_SUBSET)?SF_SET: \
|
||||
((B==SF_SET_PENDING && !(dyn->insts[ninst].x86.need_flags&X_PEND)?SF_SET:B))
|
||||
#define SETFLAGS(A, B) \
|
||||
if(dyn->f.pending!=SF_SET \
|
||||
&& ((B)&SF_SUB) \
|
||||
&& (dyn->insts[ninst].x86.gen_flags&(~(A)))) \
|
||||
READFLAGS(((dyn->insts[ninst].x86.gen_flags&X_PEND)?X_ALL:dyn->insts[ninst].x86.gen_flags)&(~(A)));\
|
||||
if(dyn->insts[ninst].x86.gen_flags) switch(B) { \
|
||||
case SF_SUBSET: \
|
||||
case SF_SET: dyn->f.pending = SF_SET; break; \
|
||||
case SF_SET_DF: dyn->f.pending = SF_SET; dyn->f.dfnone = 1; break; \
|
||||
case SF_SET_NODF: dyn->f.pending = SF_SET; dyn->f.dfnone = 0; break; \
|
||||
case SF_PENDING: dyn->f.pending = SF_PENDING; break; \
|
||||
case SF_SUBSET_PENDING: \
|
||||
case SF_SET_PENDING: \
|
||||
dyn->f.pending = (dyn->insts[ninst].x86.gen_flags&X_PEND)?SF_SET_PENDING:SF_SET; \
|
||||
break; \
|
||||
} else dyn->f.pending = SF_SET
|
||||
#endif
|
||||
#ifndef JUMP
|
||||
#define JUMP(A, C)
|
||||
#define JUMP(A, C) SMEND()
|
||||
#endif
|
||||
#ifndef BARRIER
|
||||
#define BARRIER(A)
|
||||
@@ -320,17 +435,17 @@
|
||||
#ifndef BARRIER_NEXT
|
||||
#define BARRIER_NEXT(A)
|
||||
#endif
|
||||
#define UFLAG_OP1(A) if(dyn->insts[ninst].x86.need_flags) {STR_IMM9(A, xEmu, offsetof(x86emu_t, op1));}
|
||||
#define UFLAG_OP2(A) if(dyn->insts[ninst].x86.need_flags) {STR_IMM9(A, xEmu, offsetof(x86emu_t, op2));}
|
||||
#define UFLAG_OP12(A1, A2) if(dyn->insts[ninst].x86.need_flags) {STR_IMM9(A1, xEmu, offsetof(x86emu_t, op1));STR_IMM9(A2, 0, offsetof(x86emu_t, op2));}
|
||||
#define UFLAG_RES(A) if(dyn->insts[ninst].x86.need_flags) {STR_IMM9(A, xEmu, offsetof(x86emu_t, res));}
|
||||
#define UFLAG_DF(r, A) if(dyn->insts[ninst].x86.need_flags) {SET_DF(r, A)}
|
||||
#define UFLAG_IF if(dyn->insts[ninst].x86.need_flags)
|
||||
#ifndef DEFAULT
|
||||
#define DEFAULT *ok = -1; BARRIER(2)
|
||||
#ifndef SET_HASCALLRET
|
||||
#define SET_HASCALLRET()
|
||||
#endif
|
||||
#ifndef NEW_BARRIER_INST
|
||||
#define NEW_BARRIER_INST
|
||||
#define UFLAG_OP1(A) if(dyn->insts[ninst].x86.gen_flags) {STR_IMM9(A, xEmu, offsetof(x86emu_t, op1));}
|
||||
#define UFLAG_OP2(A) if(dyn->insts[ninst].x86.gen_flags) {STR_IMM9(A, xEmu, offsetof(x86emu_t, op2));}
|
||||
#define UFLAG_OP12(A1, A2) if(dyn->insts[ninst].x86.gen_flags) {STR_IMM9(A1, xEmu, offsetof(x86emu_t, op1));STR_IMM9(A2, 0, offsetof(x86emu_t, op2));}
|
||||
#define UFLAG_RES(A) if(dyn->insts[ninst].x86.gen_flags) {STR_IMM9(A, xEmu, offsetof(x86emu_t, res));}
|
||||
#define UFLAG_DF(r, A) if(dyn->insts[ninst].x86.gen_flags) {SET_DF(r, A)}
|
||||
#define UFLAG_IF if(dyn->insts[ninst].x86.gen_flags)
|
||||
#ifndef DEFAULT
|
||||
#define DEFAULT *ok = -1; BARRIER(BARRIER_NOFLAGS)
|
||||
#endif
|
||||
|
||||
#if STEP < 2
|
||||
@@ -368,6 +483,7 @@ void* arm_next(x86emu_t* emu, uintptr_t addr);
|
||||
#define dynarecDF STEPNAME(dynarecDF)
|
||||
#define dynarecF0 STEPNAME(dynarecF0)
|
||||
#define dynarec660F STEPNAME(dynarec660F)
|
||||
#define dynarec66F0 STEPNAME(dynarec66F0)
|
||||
#define dynarecF20F STEPNAME(dynarecF20F)
|
||||
#define dynarecF30F STEPNAME(dynarecF30F)
|
||||
|
||||
@@ -380,6 +496,9 @@ void* arm_next(x86emu_t* emu, uintptr_t addr);
|
||||
#define iret_to_epilog STEPNAME(iret_to_epilog_)
|
||||
#define call_c STEPNAME(call_c_)
|
||||
#define call_d STEPNAME(call_d_)
|
||||
#define call_ddr STEPNAME(call_ddr_)
|
||||
#define call_dr STEPNAME(call_dr_)
|
||||
#define call_rd STEPNAME(call_rd_)
|
||||
#define grab_fsdata STEPNAME(grab_fsdata_)
|
||||
#define grab_tlsdata STEPNAME(grab_tlsdata_)
|
||||
#define emit_cmp8 STEPNAME(emit_cmp8)
|
||||
@@ -447,13 +566,28 @@ void* arm_next(x86emu_t* emu, uintptr_t addr);
|
||||
#define emit_shr32 STEPNAME(emit_shr32)
|
||||
#define emit_shr32c STEPNAME(emit_shr32c)
|
||||
#define emit_sar32c STEPNAME(emit_sar32c)
|
||||
#define emit_shl8 STEPNAME(emit_shl8)
|
||||
#define emit_shl8c STEPNAME(emit_shl8c)
|
||||
#define emit_shr8 STEPNAME(emit_shr8)
|
||||
#define emit_shr8c STEPNAME(emit_shr8c)
|
||||
#define emit_sar8 STEPNAME(emit_sar8)
|
||||
#define emit_sar8c STEPNAME(emit_sar8c)
|
||||
#define emit_shl16 STEPNAME(emit_shl16)
|
||||
#define emit_shl16c STEPNAME(emit_shl16c)
|
||||
#define emit_shr16 STEPNAME(emit_shr16)
|
||||
#define emit_shr16c STEPNAME(emit_shr16c)
|
||||
#define emit_sar16 STEPNAME(emit_sar16)
|
||||
#define emit_sar16c STEPNAME(emit_sar16c)
|
||||
#define emit_rol32c STEPNAME(emit_rol32c)
|
||||
#define emit_rol8c STEPNAME(emit_rol8c)
|
||||
#define emit_ror32c STEPNAME(emit_ror32c)
|
||||
#define emit_ror8c STEPNAME(emit_ror8c)
|
||||
#define emit_rol16c STEPNAME(emit_rol16c)
|
||||
#define emit_ror16c STEPNAME(emit_ror16c)
|
||||
#define emit_shrd32c STEPNAME(emit_shrd32c)
|
||||
#define emit_shld32c STEPNAME(emit_shld32c)
|
||||
#define emit_shrd32 STEPNAME(emit_shrd32)
|
||||
#define emit_shld32 STEPNAME(emit_shld32)
|
||||
|
||||
#define emit_pf STEPNAME(emit_pf)
|
||||
|
||||
@@ -465,35 +599,44 @@ void* arm_next(x86emu_t* emu, uintptr_t addr);
|
||||
#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_free STEPNAME(x87_free)
|
||||
#define x87_refresh STEPNAME(x87_refresh)
|
||||
#define x87_forget STEPNAME(x87_forget)
|
||||
#define x87_reget_st STEPNAME(x87_reget_st)
|
||||
#define x87_stackcount STEPNAME(x87_stackcount)
|
||||
#define x87_unstackcount STEPNAME(x87_unstackcount)
|
||||
#define x87_setround STEPNAME(x87_setround)
|
||||
#define x87_setround_reset STEPNAME(x87_setround_reset)
|
||||
#define x87_restoreround STEPNAME(x87_restoreround)
|
||||
#define x87_swapreg STEPNAME(x87_swapreg)
|
||||
#define sse_setround STEPNAME(sse_setround)
|
||||
#define sse_setround_reset STEPNAME(sse_setround_reset)
|
||||
#define mmx_get_reg STEPNAME(mmx_get_reg)
|
||||
#define mmx_get_reg_empty STEPNAME(mmx_get_reg_empty)
|
||||
#define sse_get_reg STEPNAME(sse_get_reg)
|
||||
#define sse_get_reg_empty STEPNAME(sse_get_reg_empty)
|
||||
#define sse_forget_reg STEPNAME(sse_forget_reg)
|
||||
#define sse_reflect_reg STEPNAME(sse_reflect_reg)
|
||||
|
||||
#define fpu_pushcache STEPNAME(fpu_pushcache)
|
||||
#define fpu_popcache STEPNAME(fpu_popcache)
|
||||
#define fpu_reset STEPNAME(fpu_reset)
|
||||
#define fpu_reset_cache STEPNAME(fpu_reset_cache)
|
||||
#define fpu_propagate_stack STEPNAME(fpu_propagate_stack)
|
||||
#define fpu_purgecache STEPNAME(fpu_purgecache)
|
||||
#define x87_purgecache STEPNAME(x87_purgecache)
|
||||
#define mmx_purgecache STEPNAME(mmx_purgecache)
|
||||
#ifdef HAVE_TRACE
|
||||
#define fpu_reflectcache STEPNAME(fpu_reflectcache)
|
||||
#endif
|
||||
#define fpu_unreflectcache STEPNAME(fpu_unreflectcache)
|
||||
|
||||
// get the single reg that from the double "reg" (so Dx[idx])
|
||||
#define fpu_get_single_reg STEPNAME(fpu_get_single_reg)
|
||||
// put back (if needed) the single reg in place
|
||||
#define fpu_putback_single_reg STEPNAME(fpu_putback_single_reg)
|
||||
|
||||
#define CacheTransform STEPNAME(CacheTransform)
|
||||
|
||||
/* setup r2 to address pointed by */
|
||||
uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int* fixedaddress, uint32_t absmax, uint32_t mask, int getfixonly);
|
||||
uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int* fixedaddress, uint32_t absmax, uint32_t mask, int getfixonly, int* l);
|
||||
|
||||
/* setup r2 to address pointed by */
|
||||
uintptr_t geted16(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int* fixedaddress, uint32_t absmax, uint32_t mask);
|
||||
@@ -507,10 +650,11 @@ void retn_to_epilog(dynarec_arm_t* dyn, int ninst, int n);
|
||||
void iret_to_epilog(dynarec_arm_t* dyn, int ninst);
|
||||
void call_c(dynarec_arm_t* dyn, int ninst, void* fnc, int reg, int ret, uint32_t mask, int saveflags);
|
||||
void call_d(dynarec_arm_t* dyn, int ninst, void* fnc, void* fnc2, int n, int reg, int ret, uint32_t mask, int saveflags);
|
||||
void call_dr(dynarec_arm_t* dyn, int ninst, int reg, int n, int s1, int ret, int ret2, uint32_t mask, int saveflags);
|
||||
void call_ddr(dynarec_arm_t* dyn, int ninst, void* fnc, void* fnc2, int arg, int reg, int ret, uint32_t mask, int saveflags);
|
||||
void call_rd(dynarec_arm_t* dyn, int ninst, void* fnc, int reg, int s1, uint32_t mask, int saveflags);
|
||||
void grab_fsdata(dynarec_arm_t* dyn, uintptr_t addr, int ninst, int reg);
|
||||
void grab_tlsdata(dynarec_arm_t* dyn, uintptr_t addr, int ninst, int reg);
|
||||
void emit_lock(dynarec_arm_t* dyn, uintptr_t addr, int ninst);
|
||||
void emit_unlock(dynarec_arm_t* dyn, uintptr_t addr, int ninst);
|
||||
void emit_cmp8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_cmp16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_cmp32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
@@ -576,19 +720,36 @@ void emit_shl32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s
|
||||
void emit_shr32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_shr32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_sar32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_shl8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_shl8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_shr8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_shr8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_sar8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_sar8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_shl16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_shl16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_shr16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_shr16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
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, int32_t c, int s3, int s4);
|
||||
void emit_rol32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_rol8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_ror32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_ror8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_rol16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_ror16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_shrd32c(dynarec_arm_t* dyn, int ninst, int s1, int s2, int32_t c, int s3, int s4);
|
||||
void emit_shld32c(dynarec_arm_t* dyn, int ninst, int s1, int s2, int32_t c, int s3, int s4);
|
||||
void emit_shrd32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_shld32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
|
||||
void emit_pf(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
|
||||
void emit_pf(dynarec_arm_t* dyn, int ninst, int s1, int s4);
|
||||
|
||||
// x87 helper
|
||||
// cache of the local stack counter, to avoid upadte at every call
|
||||
void x87_stackcount(dynarec_arm_t* dyn, int ninst, int scratch);
|
||||
int x87_stackcount(dynarec_arm_t* dyn, int ninst, int scratch);
|
||||
// restore the local stack counter
|
||||
void x87_unstackcount(dynarec_arm_t* dyn, int ninst, int scratch, int count);
|
||||
// fpu push. Return the Dd value to be used
|
||||
int x87_do_push(dynarec_arm_t* dyn, int ninst, int s1, int t);
|
||||
// fpu push. Do not allocate a cache register. Needs a scratch register to do x87stack synch (or 0 to not do it)
|
||||
@@ -605,6 +766,8 @@ int x87_get_neoncache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int a);
|
||||
int x87_get_st(dynarec_arm_t* dyn, int ninst, int s1, int s2, int a, int t);
|
||||
// get vfpu register for a x87 reg, create the entry if needed. Do not fetch the Stx if not already in cache
|
||||
int x87_get_st_empty(dynarec_arm_t* dyn, int ninst, int s1, int s2, int a, int t);
|
||||
// Free st, using the FFREE opcode (so it's freed but stack is not moved)
|
||||
void x87_free(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int st);
|
||||
// refresh a value from the cache ->emu (nothing done if value is not cached)
|
||||
void x87_refresh(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st);
|
||||
// refresh a value from the cache ->emu and then forget the cache (nothing done if value is not cached)
|
||||
@@ -613,10 +776,24 @@ void x87_forget(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st);
|
||||
void x87_reget_st(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st);
|
||||
// Set rounding according to cw flags, return reg to restore flags
|
||||
int x87_setround(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
// Set rounding according to cw flags, return reg to restore flags, also enable exceptions and reset counters
|
||||
int x87_setround_reset(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
// Restore round flag
|
||||
void x87_restoreround(dynarec_arm_t* dyn, int ninst, int s1);
|
||||
// swap 2 x87 regs
|
||||
void x87_swapreg(dynarec_arm_t* dyn, int ninst, int s1, int s2, int a, int b);
|
||||
// Set rounding according to mxcsr flags, return reg to restore flags
|
||||
int sse_setround(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
// Set rounding according to mxcsr flags, return reg to restore flags, also enable exceptions and reset counters
|
||||
int sse_setround_reset(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
|
||||
void CacheTransform(dynarec_arm_t* dyn, int ninst, int cacheupd, int s1, int s2, int s3);
|
||||
|
||||
#if STEP < 2
|
||||
#define CHECK_CACHE() 0
|
||||
#else
|
||||
#define CHECK_CACHE() (cacheupd = CacheNeedsTransform(dyn, ninst))
|
||||
#endif
|
||||
|
||||
#define neoncache_st_coherency STEPNAME(neoncache_st_coherency)
|
||||
int neoncache_st_coherency(dynarec_arm_t* dyn, int ninst, int a, int b);
|
||||
@@ -653,17 +830,22 @@ int mmx_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int
|
||||
int sse_get_reg(dynarec_arm_t* dyn, int ninst, int s1, int a, int forwrite);
|
||||
// get neon register for a SSE reg, but don't try to synch it if it needed to be created
|
||||
int sse_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int a);
|
||||
// forget an SSE reg
|
||||
void sse_forget_reg(dynarec_arm_t* dyn, int ninst, int a, int s1);
|
||||
// sync reg with emu for sse reg (return 1 if reflect was done, s1 = &xmm[a] then)
|
||||
int sse_reflect_reg(dynarec_arm_t* dyn, int ninst, int a, int s1);
|
||||
|
||||
// common coproc helpers
|
||||
// reset the cache
|
||||
void fpu_reset(dynarec_arm_t* dyn, int ninst);
|
||||
// reset the cache with n
|
||||
void fpu_reset_cache(dynarec_arm_t* dyn, int ninst, int reset_n);
|
||||
// propagate stack state
|
||||
void fpu_propagate_stack(dynarec_arm_t* dyn, int ninst);
|
||||
// purge the FPU cache (needs 3 scratch registers) next=1 if for a conditionnal branch jumping out of block (no tracking updated)
|
||||
void fpu_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1, int s2, int s3);
|
||||
void x87_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1, int s2, int s3);
|
||||
void mmx_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1);
|
||||
#ifdef HAVE_TRACE
|
||||
void fpu_reflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
#endif
|
||||
void fpu_unreflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
void fpu_pushcache(dynarec_arm_t* dyn, int ninst, int s1);
|
||||
void fpu_popcache(dynarec_arm_t* dyn, int ninst, int s1);
|
||||
|
||||
@@ -688,6 +870,7 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog);
|
||||
uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec66F0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog);
|
||||
uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog);
|
||||
uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog);
|
||||
|
||||
@@ -709,4 +892,25 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
#define MAYUSE(A)
|
||||
#endif
|
||||
|
||||
#define NOTEST(s1, s2) \
|
||||
if(box86_dynarec_test) { \
|
||||
MOVW(s1, 0); \
|
||||
MOVW(s2, offsetof(x86emu_t, test.test)); \
|
||||
STR_REG_LSL_IMM5(s1, xEmu, s2, 0); \
|
||||
ADD_IMM8(s2, s2, offsetof(x86emu_t, test.clean)-offsetof(x86emu_t, test.test));\
|
||||
STR_REG_LSL_IMM5(s1, xEmu, s2, 0); \
|
||||
}
|
||||
#define SKIPTEST(s1, s2) \
|
||||
if(box86_dynarec_test) { \
|
||||
MOVW(s1, 0); \
|
||||
MOVW(s2, offsetof(x86emu_t, test.clean)); \
|
||||
STR_REG_LSL_IMM5(s1, xEmu, s2, 0); \
|
||||
}
|
||||
#define GOTEST(s1, s2) \
|
||||
if(box86_dynarec_test) { \
|
||||
MOVW(s2, 1); \
|
||||
MOVW(s1, offsetof(x86emu_t, test.test)); \
|
||||
STR_REG_LSL_IMM5(s2, xEmu, s1, 0); \
|
||||
}
|
||||
|
||||
#endif //__DYNAREC_ARM_HELPER_H__
|
||||
@@ -0,0 +1,12 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "arm_emitter.h"
|
||||
|
||||
#define EMIT(A) *block = (A); ++block
|
||||
void CreateJmpNext(void* addr, void* next)
|
||||
{
|
||||
uint32_t* block = (uint32_t*)addr;
|
||||
LDR_literal(x2, ((intptr_t)next - (intptr_t)addr)-8);
|
||||
BX(x2);
|
||||
}
|
||||
+229
-37
@@ -21,47 +21,104 @@
|
||||
#include "dynarec_arm_functions.h"
|
||||
#include "dynarec_arm_helper.h"
|
||||
#include "custommem.h"
|
||||
#include "elfloader.h"
|
||||
|
||||
#ifndef STEP
|
||||
#error No STEP defined
|
||||
#endif
|
||||
|
||||
#if STEP == 0
|
||||
#ifndef PROT_READ
|
||||
#define PROT_READ 0x1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
uintptr_t arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
|
||||
{
|
||||
int ok = 1;
|
||||
int ninst = 0;
|
||||
int j32;
|
||||
uintptr_t ip = addr;
|
||||
uintptr_t init_addr = addr;
|
||||
MAYUSE(init_addr);
|
||||
int need_epilog = 1;
|
||||
dyn->sons_size = 0;
|
||||
// Clean up (because there are multiple passes)
|
||||
dyn->state_flags = 0;
|
||||
dyn->dfnone = 0;
|
||||
fpu_reset(dyn, ninst);
|
||||
// ok, go now
|
||||
dyn->f.pending = 0;
|
||||
dyn->f.dfnone = 0;
|
||||
dyn->forward = 0;
|
||||
dyn->forward_to = 0;
|
||||
dyn->forward_size = 0;
|
||||
dyn->forward_ninst = 0;
|
||||
#if STEP == 0
|
||||
memset(&dyn->insts[ninst], 0, sizeof(instruction_arm_t));
|
||||
#endif
|
||||
fpu_reset(dyn);
|
||||
int reset_n = -1;
|
||||
int stopblock = 2+(FindElfAddress(my_context, addr)?0:1); // if block is in elf_memory, it can be extended with bligblocks==2, else it needs 3 // ok, go now
|
||||
INIT;
|
||||
#if STEP == 0
|
||||
uintptr_t cur_page = (addr)&~box86_pagesize;
|
||||
#endif
|
||||
while(ok) {
|
||||
#if STEP == 0
|
||||
if(cur_page != (addr)&~box86_pagesize) {
|
||||
cur_page = (addr)&~box86_pagesize;
|
||||
if(!(getProtection(addr)&PROT_READ)) {
|
||||
need_epilog = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
ip = addr;
|
||||
if((dyn->insts[ninst].x86.barrier==1)) {
|
||||
NEW_BARRIER_INST;
|
||||
}
|
||||
// propagate ST stack state, especial stack pop that are defered
|
||||
if(dyn->n.stack_pop) {
|
||||
for(int j=0; j<24; ++j)
|
||||
if((dyn->n.neoncache[j].t == NEON_CACHE_ST_D || dyn->n.neoncache[j].t == NEON_CACHE_ST_F)) {
|
||||
if(dyn->n.neoncache[j].n<dyn->n.stack_pop)
|
||||
dyn->n.neoncache[j].v = 0;
|
||||
else
|
||||
dyn->n.neoncache[j].n-=dyn->n.stack_pop;
|
||||
fpu_propagate_stack(dyn, ninst);
|
||||
if (reset_n!=-1) {
|
||||
if(reset_n==-2) {
|
||||
MESSAGE(LOG_DEBUG, "Reset Caches to zero\n");
|
||||
dyn->f.dfnone = 0;
|
||||
dyn->f.pending = 0;
|
||||
fpu_reset(dyn);
|
||||
} else {
|
||||
fpu_reset_cache(dyn, ninst, reset_n);
|
||||
dyn->f = dyn->insts[reset_n].f_exit;
|
||||
if(dyn->insts[ninst].x86.barrier&BARRIER_FLOAT) {
|
||||
MESSAGE(LOG_DEBUG, "Apply Barrier Float\n");
|
||||
fpu_reset(dyn);
|
||||
}
|
||||
dyn->n.stack_pop = 0;
|
||||
if(dyn->insts[ninst].x86.barrier&BARRIER_FLAGS) {
|
||||
MESSAGE(LOG_DEBUG, "Apply Barrier Flags\n");
|
||||
dyn->f.dfnone = 0;
|
||||
dyn->f.pending = 0;
|
||||
}
|
||||
}
|
||||
reset_n = -1;
|
||||
}
|
||||
dyn->n.stack = dyn->n.stack_next;
|
||||
NEW_INST;
|
||||
#if STEP == 0
|
||||
if(ninst && dyn->insts[ninst-1].x86.barrier_next) {
|
||||
BARRIER(dyn->insts[ninst-1].x86.barrier_next);
|
||||
}
|
||||
#endif
|
||||
if(!ninst) {
|
||||
GOTEST(x1, x2);
|
||||
}
|
||||
if(dyn->insts[ninst].pred_sz>1) {SMSTART();}
|
||||
fpu_reset_scratch(dyn);
|
||||
if((dyn->insts[ninst].x86.need_before&~X_PEND) && !dyn->insts[ninst].pred_sz) {
|
||||
READFLAGS(dyn->insts[ninst].x86.need_before&~X_PEND);
|
||||
}
|
||||
if(box86_dynarec_test) {
|
||||
MESSAGE(LOG_DUMP, "TEST INIT ----\n");
|
||||
fpu_reflectcache(dyn, ninst, x1, x2, x3);
|
||||
MOV32(x1, ip);
|
||||
STM(xEmu, (1<<xEAX)|(1<<xEBX)|(1<<xECX)|(1<<xEDX)|(1<<xESI)|(1<<xEDI)|(1<<xESP)|(1<<xEBP));
|
||||
STR_IMM9(x1, xEmu, offsetof(x86emu_t, ip));
|
||||
MOVW(x2, 1);
|
||||
CALL(x86test_init, -1, 0);
|
||||
fpu_unreflectcache(dyn, ninst, x1, x2, x3);
|
||||
MESSAGE(LOG_DUMP, "----------\n");
|
||||
}
|
||||
#ifdef HAVE_TRACE
|
||||
if(my_context->dec && box86_dynarec_trace) {
|
||||
else if(my_context->dec && box86_dynarec_trace) {
|
||||
if((trace_end == 0)
|
||||
|| ((ip >= trace_start) && (ip < trace_end))) {
|
||||
MESSAGE(LOG_DUMP, "TRACE ----\n");
|
||||
@@ -71,6 +128,7 @@ uintptr_t arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
|
||||
STR_IMM9(x1, xEmu, offsetof(x86emu_t, ip));
|
||||
MOVW(x2, 1);
|
||||
CALL(PrintTrace, -1, 0);
|
||||
fpu_unreflectcache(dyn, ninst, x1, x2, x3);
|
||||
MESSAGE(LOG_DUMP, "----------\n");
|
||||
}
|
||||
}
|
||||
@@ -80,53 +138,187 @@ uintptr_t arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
|
||||
|
||||
INST_EPILOG;
|
||||
|
||||
if(dyn->insts[ninst+1].x86.barrier) {
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
if(dyn->insts[ninst+1].x86.barrier!=2) {
|
||||
dyn->state_flags = 0;
|
||||
dyn->dfnone = 0;
|
||||
int next = ninst+1;
|
||||
#if STEP > 0
|
||||
if(!dyn->insts[ninst].x86.has_next && dyn->insts[ninst].x86.jmp && dyn->insts[ninst].x86.jmp_insts!=-1)
|
||||
next = dyn->insts[ninst].x86.jmp_insts;
|
||||
if(dyn->insts[ninst].x86.has_next && dyn->insts[next].x86.barrier) {
|
||||
if(dyn->insts[next].x86.barrier&BARRIER_FLOAT)
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
if(dyn->insts[next].x86.barrier&BARRIER_FLAGS) {
|
||||
dyn->f.pending = 0;
|
||||
dyn->f.dfnone = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifndef PROT_READ
|
||||
#define PROT_READ 1
|
||||
#endif
|
||||
#if STEP != 0
|
||||
if(!ok && !need_epilog && (addr < (dyn->start+dyn->isize))) {
|
||||
ok = 1;
|
||||
// we use the 1st predecessor here
|
||||
int ii = ninst+1;
|
||||
if(ii<dyn->size && !dyn->insts[ii].x86.alive) {
|
||||
while(ii<dyn->size && !dyn->insts[ii].x86.alive) {
|
||||
// may need to skip opcodes to advance
|
||||
++ninst;
|
||||
NEW_INST;
|
||||
MESSAGE(LOG_DEBUG, "Skipping unused opcode\n");
|
||||
INST_NAME("Skipped opcode");
|
||||
INST_EPILOG;
|
||||
addr += dyn->insts[ii].x86.size;
|
||||
++ii;
|
||||
}
|
||||
}
|
||||
if((dyn->insts[ii].x86.barrier&BARRIER_FULL)==BARRIER_FULL)
|
||||
reset_n = -2; // hack to say Barrier!
|
||||
else {
|
||||
reset_n = getNominalPred(dyn, ii); // may get -1 if no predecessor are availble
|
||||
if(reset_n==-1) {
|
||||
reset_n = -2;
|
||||
MESSAGE(LOG_DEBUG, "Warning, Reset Caches mark not found\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
#if STEP == 0
|
||||
if(!ok && !need_epilog && box86_dynarec_bigblock && getProtection(addr+3))
|
||||
#else
|
||||
// check if block need to be stopped, because it's a 00 00 opcode (unreadeable is already checked earlier)
|
||||
if((ok>0) && !dyn->forward && !(*(uint8_t*)addr) && !(*(uint8_t*)(addr+1))) {
|
||||
if(box86_dynarec_dump) dynarec_log(LOG_NONE, "Stopping block at %p reason: %s\n", (void*)addr, "Next opcode is 00 00");
|
||||
ok = 0;
|
||||
need_epilog = 1;
|
||||
}
|
||||
if(dyn->forward) {
|
||||
if(dyn->forward_to == addr && !need_epilog && ok>=0) {
|
||||
// we made it!
|
||||
reset_n = get_first_jump(dyn, addr);
|
||||
if(box86_dynarec_dump) dynarec_log(LOG_NONE, "Forward extend block for %d bytes %s%p -> %p (ninst %d - %d)\n", dyn->forward_to-dyn->forward, dyn->insts[dyn->forward_ninst].x86.has_callret?"(opt. call) ":"", (void*)dyn->forward, (void*)dyn->forward_to, reset_n, ninst);
|
||||
if(dyn->insts[dyn->forward_ninst].x86.has_callret && !dyn->insts[dyn->forward_ninst].x86.has_next)
|
||||
dyn->insts[dyn->forward_ninst].x86.has_next = 1; // this block actually continue
|
||||
dyn->forward = 0;
|
||||
dyn->forward_to = 0;
|
||||
dyn->forward_size = 0;
|
||||
dyn->forward_ninst = 0;
|
||||
ok = 1; // in case it was 0
|
||||
} else if ((dyn->forward_to < addr) || ok<=0) {
|
||||
// something when wrong! rollback
|
||||
if(box86_dynarec_dump) dynarec_log(LOG_NONE, "Could not forward extend block for %d bytes %p -> %p\n", dyn->forward_to-dyn->forward, (void*)dyn->forward, (void*)dyn->forward_to);
|
||||
ok = 0;
|
||||
dyn->size = dyn->forward_size;
|
||||
ninst = dyn->forward_ninst;
|
||||
addr = dyn->forward;
|
||||
dyn->forward = 0;
|
||||
dyn->forward_to = 0;
|
||||
dyn->forward_size = 0;
|
||||
dyn->forward_ninst = 0;
|
||||
}
|
||||
// else just continue
|
||||
} else if(!ok && !need_epilog && box86_dynarec_bigblock && (getProtection(addr+3)&~PROT_READ))
|
||||
if(*(uint32_t*)addr!=0) { // check if need to continue (but is next 4 bytes are 0, stop)
|
||||
uintptr_t next = get_closest_next(dyn, addr);
|
||||
if(next && (
|
||||
(((next-addr)<15) && is_nops(dyn, addr, next-addr))
|
||||
||(((next-addr)<30) && is_instructions(dyn, addr, next-addr)) ))
|
||||
/*||(((next-addr)<30) && is_instructions(dyn, addr, next-addr))*/ ))
|
||||
{
|
||||
dynarec_log(LOG_DEBUG, "Extend block %p, %p -> %p (ninst=%d)\n", dyn, (void*)addr, (void*)next, ninst);
|
||||
ok = 1;
|
||||
} else if(next && (next-addr)<30) {
|
||||
dynarec_log(LOG_DEBUG, "Cannot extend block %p -> %p (%02X %02X %02X %02X %02X %02X %02X %02x)\n", (void*)addr, (void*)next, PK(0), PK(1), PK(2), PK(3), PK(4), PK(5), PK(6), PK(7));
|
||||
if(dyn->insts[ninst].x86.has_callret && !dyn->insts[ninst].x86.has_next) {
|
||||
dyn->insts[ninst].x86.has_next = 1; // this block actually continue
|
||||
} else {
|
||||
// need to find back that instruction to copy the caches, as previous version cannot be used anymore
|
||||
// and pred table is not ready yet
|
||||
reset_n = get_first_jump(dyn, next);
|
||||
}
|
||||
if(box86_dynarec_dump) dynarec_log(LOG_NONE, "Extend block %p, %s%p -> %p (ninst=%d, jump from %d)\n", dyn, dyn->insts[ninst].x86.has_callret?"(opt. call) ":"", (void*)addr, (void*)next, ninst, dyn->insts[ninst].x86.has_callret?ninst:reset_n);
|
||||
} else if(next && (next-addr)<box86_dynarec_forward && (getProtection(next)&PROT_READ)/*box86_dynarec_bigblock>=stopblock*/) {
|
||||
if(!((box86_dynarec_bigblock<stopblock) && !isJumpTableDefault((void*)next))) {
|
||||
if(dyn->forward) {
|
||||
if(next<dyn->forward_to)
|
||||
dyn->forward_to = next;
|
||||
reset_n = -2;
|
||||
ok = 1;
|
||||
} else {
|
||||
dyn->forward = addr;
|
||||
dyn->forward_to = next;
|
||||
dyn->forward_size = dyn->size;
|
||||
dyn->forward_ninst = ninst;
|
||||
reset_n = -2;
|
||||
ok = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if(ok<0) {ok = 0; need_epilog=1;}
|
||||
if(ok<0) {
|
||||
ok = 0; need_epilog=1;
|
||||
#if STEP == 0
|
||||
if(ninst) {
|
||||
--ninst;
|
||||
if(!dyn->insts[ninst].x86.barrier) {
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
}
|
||||
dyn->insts[ninst].x86.need_after |= X_PEND;
|
||||
++ninst;
|
||||
}
|
||||
if(dyn->forward) {
|
||||
// stopping too soon
|
||||
dyn->size = dyn->forward_size;
|
||||
ninst = dyn->forward_ninst+1;
|
||||
addr = dyn->forward;
|
||||
dyn->forward = 0;
|
||||
dyn->forward_to = 0;
|
||||
dyn->forward_size = 0;
|
||||
dyn->forward_ninst = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if((ok>0) && dyn->insts[ninst].x86.has_callret)
|
||||
reset_n = -2;
|
||||
++ninst;
|
||||
#if STEP == 0
|
||||
if(ok && !isJumpTableDefault((void*)addr))
|
||||
memset(&dyn->insts[ninst], 0, sizeof(instruction_arm_t));
|
||||
if((ok>0) && (((box86_dynarec_bigblock<stopblock) && !isJumpTableDefault((void*)addr))
|
||||
|| (addr>=box86_nodynarec_start && addr<box86_nodynarec_end)))
|
||||
#else
|
||||
if(ok && (ninst==dyn->size))
|
||||
if((ok>0) && (ninst==dyn->size))
|
||||
#endif
|
||||
{
|
||||
#if STEP == 3
|
||||
dynarec_log(LOG_DEBUG, "Stopping block %p (%d / %d)\n",(void*)init_addr, ninst, dyn->size);
|
||||
#if STEP == 0
|
||||
if(dyn->forward) {
|
||||
// stopping too soon
|
||||
dyn->size = dyn->forward_size;
|
||||
ninst = dyn->forward_ninst+1;
|
||||
addr = dyn->forward;
|
||||
dyn->forward = 0;
|
||||
dyn->forward_to = 0;
|
||||
dyn->forward_size = 0;
|
||||
dyn->forward_ninst = 0;
|
||||
}
|
||||
#endif
|
||||
BARRIER(2);
|
||||
int j32;
|
||||
MAYUSE(j32);
|
||||
MESSAGE(LOG_DEBUG, "Stopping block %p (%d / %d)\n",(void*)init_addr, ninst, dyn->size);
|
||||
if(!box86_dynarec_dump && addr>=box86_nodynarec_start && addr<box86_nodynarec_end)
|
||||
dynarec_log(LOG_INFO, "Stopping block in no-dynarec zone\n");
|
||||
--ninst;
|
||||
if(!dyn->insts[ninst].x86.barrier) {
|
||||
BARRIER(BARRIER_FLOAT);
|
||||
}
|
||||
#if STEP == 0
|
||||
dyn->insts[ninst].x86.need_after |= X_PEND;
|
||||
#endif
|
||||
++ninst;
|
||||
NOTEST(x1, x3);
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
jump_to_next(dyn, addr, 0, ninst);
|
||||
ok=0; need_epilog=0;
|
||||
}
|
||||
}
|
||||
if(need_epilog) {
|
||||
NOTEST(x1, x3);
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
jump_to_epilog(dyn, ip, 0, ninst); // no linker here, it's an unknow instruction
|
||||
}
|
||||
FINI;
|
||||
MESSAGE(LOG_DUMP, "---- END OF BLOCK ---- (%d, %d sons)\n", dyn->size, dyn->sons_size);
|
||||
MESSAGE(LOG_DUMP, "---- END OF BLOCK ---- (%d)\n", dyn->size);
|
||||
return addr;
|
||||
}
|
||||
@@ -4,31 +4,41 @@
|
||||
dyn->isize = addr-sav_addr;\
|
||||
dyn->insts[ninst].x86.addr = addr;\
|
||||
if(ninst) dyn->insts[ninst-1].x86.size = dyn->insts[ninst].x86.addr - dyn->insts[ninst-1].x86.addr
|
||||
|
||||
#define MESSAGE(A, ...)
|
||||
#define READFLAGS(A) dyn->insts[ninst].x86.use_flags = A
|
||||
#define SETFLAGS(A,B) {dyn->insts[ninst].x86.set_flags = A; dyn->insts[ninst].x86.state_flags = B;}
|
||||
#define MAYSETFLAGS() dyn->insts[ninst].x86.may_set = 1
|
||||
#define READFLAGS(A) \
|
||||
dyn->insts[ninst].x86.use_flags = A; dyn->f.dfnone = 1;\
|
||||
dyn->f.pending=SF_SET
|
||||
#define SETFLAGS(A,B) \
|
||||
dyn->insts[ninst].x86.set_flags = A; \
|
||||
dyn->insts[ninst].x86.state_flags = (B)&~SF_DF; \
|
||||
dyn->f.pending=(B)&SF_SET_PENDING; \
|
||||
dyn->f.dfnone=((B)&SF_SET)?(((B)==SF_SET_NODF)?0:1):0;
|
||||
#define EMIT(A)
|
||||
#define JUMP(A, C) if((A)>addr) add_next(dyn, (uintptr_t)A); dyn->insts[ninst].x86.jmp = A; dyn->insts[ninst].x86.jmp_cond = C
|
||||
#define BARRIER(A) dyn->insts[ninst].x86.barrier = A
|
||||
#define BARRIER_NEXT(A) if(ninst<dyn->size) dyn->insts[ninst+1].x86.barrier = A
|
||||
#define JUMP(A, C) add_jump(dyn, ninst); add_next(dyn, (uintptr_t)A); SMEND(); dyn->insts[ninst].x86.jmp = A; dyn->insts[ninst].x86.jmp_cond = C; dyn->insts[ninst].x86.jmp_insts = 0
|
||||
#define BARRIER(A) if(A!=BARRIER_MAYBE) {fpu_purgecache(dyn, ninst, 0, x1, x2, x3); dyn->insts[ninst].x86.barrier = A;} else dyn->insts[ninst].barrier_maybe = 1
|
||||
#define BARRIER_NEXT(A) dyn->insts[ninst].x86.barrier_next = A
|
||||
#define SET_HASCALLRET() dyn->insts[ninst].x86.has_callret = 1
|
||||
#define NEW_INST \
|
||||
++dyn->size; \
|
||||
if(dyn->size+3>=dyn->cap) { \
|
||||
dyn->insts = (instruction_arm_t*)realloc(dyn->insts, sizeof(instruction_arm_t)*dyn->cap*2); \
|
||||
memset(&dyn->insts[dyn->cap], 0, sizeof(instruction_arm_t)*dyn->cap); \
|
||||
dyn->cap *= 2; \
|
||||
} \
|
||||
dyn->insts[ninst].x86.addr = ip; \
|
||||
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].x86.size = dyn->insts[ninst].x86.addr - dyn->insts[ninst-1].x86.addr;}
|
||||
|
||||
#define INST_EPILOG
|
||||
#define INST_EPILOG \
|
||||
dyn->insts[ninst].f_exit = dyn->f; \
|
||||
dyn->insts[ninst].n = dyn->n; \
|
||||
dyn->insts[ninst].x86.has_next = (ok>0)?1:0;
|
||||
#define INST_NAME(name)
|
||||
#define DEFAULT \
|
||||
--dyn->size; \
|
||||
*ok = -1; \
|
||||
if(box86_dynarec_log>=LOG_INFO) {\
|
||||
dynarec_log(LOG_NONE, "%p: Dynarec stopped because of Opcode %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", \
|
||||
(void*)ip, PKip(0), \
|
||||
if(box86_dynarec_log>=LOG_INFO || box86_dynarec_dump || box86_dynarec_missing) {\
|
||||
dynarec_log(LOG_NONE, "%p: Dynarec stopped @ %s (%s:%u) because of Opcode %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", \
|
||||
(void*)ip, __FUNCTION__, __FILE__, __LINE__, PKip(0), \
|
||||
PKip(1), PKip(2), PKip(3), \
|
||||
PKip(4), PKip(5), PKip(6), \
|
||||
PKip(7), PKip(8), PKip(9), \
|
||||
|
||||
@@ -2,11 +2,13 @@
|
||||
#define FINI
|
||||
#define MESSAGE(A, ...)
|
||||
#define EMIT(A)
|
||||
#define READFLAGS(A)
|
||||
#define SETFLAGS(A,B)
|
||||
#define NEW_INST \
|
||||
dyn->insts[ninst].f_entry = dyn->f; \
|
||||
dyn->n.combined1 = dyn->n.combined2 = 0;\
|
||||
dyn->n.swapped = 0; dyn->n.barrier = 0
|
||||
|
||||
#define NEW_INST dyn->n.combined1 = dyn->n.combined2 = 0
|
||||
|
||||
#define INST_EPILOG dyn->insts[ninst].n = dyn->n
|
||||
#define INST_EPILOG \
|
||||
dyn->insts[ninst].n = dyn->n; \
|
||||
dyn->insts[ninst].f_exit = dyn->f
|
||||
|
||||
#define INST_NAME(name)
|
||||
@@ -1,9 +1,16 @@
|
||||
#define INIT dyn->arm_size = 0
|
||||
#define FINI if(ninst) {dyn->insts[ninst].address = (dyn->insts[ninst-1].address+dyn->insts[ninst-1].size);}
|
||||
#define FINI \
|
||||
if(ninst) { \
|
||||
dyn->insts[ninst].address = (dyn->insts[ninst-1].address+dyn->insts[ninst-1].size); \
|
||||
dyn->insts_size += 1+((dyn->insts[ninst].x86.size>dyn->insts[ninst].size)?dyn->insts[ninst].x86.size:dyn->insts[ninst].size)/15; \
|
||||
}
|
||||
|
||||
#define MESSAGE(A, ...)
|
||||
#define EMIT(A) dyn->insts[ninst].size+=4; dyn->arm_size+=4
|
||||
#define NEW_INST if(ninst) {dyn->insts[ninst].address = (dyn->insts[ninst-1].address+dyn->insts[ninst-1].size);}
|
||||
#define EMIT(A) do{dyn->insts[ninst].size+=4; dyn->arm_size+=4;}while(0)
|
||||
#define NEW_INST \
|
||||
if(ninst) { \
|
||||
dyn->insts[ninst].address = (dyn->insts[ninst-1].address+dyn->insts[ninst-1].size); \
|
||||
dyn->insts_size += 1+((dyn->insts[ninst-1].x86.size>dyn->insts[ninst-1].size)?dyn->insts[ninst-1].x86.size:dyn->insts[ninst-1].size)/15; \
|
||||
}
|
||||
#define INST_EPILOG dyn->insts[ninst].epilog = dyn->arm_size;
|
||||
#define INST_NAME(name)
|
||||
#define NEW_BARRIER_INST if(ninst) ++dyn->sons_size
|
||||
@@ -1,52 +1,20 @@
|
||||
#define INIT
|
||||
#define FINI
|
||||
#define EMIT(A) \
|
||||
if(box86_dynarec_dump) {dynarec_log(LOG_NONE, "\t%08x\t%s\n", (A), arm_print(A));} \
|
||||
*(uint32_t*)(dyn->block) = A; \
|
||||
dyn->block += 4; dyn->arm_size += 4;\
|
||||
dyn->insts[ninst].size2 += 4
|
||||
#define FINI \
|
||||
if(ninst) \
|
||||
addInst(dyn->instsize, &dyn->insts_size, dyn->insts[ninst].x86.size, dyn->insts[ninst].size/4); \
|
||||
addInst(dyn->instsize, &dyn->insts_size, 0, 0);
|
||||
#define EMIT(A) \
|
||||
do{ \
|
||||
if(box86_dynarec_dump) print_opcode(dyn, ninst, (uint32_t)(A)); \
|
||||
if((uintptr_t)dyn->block<(uintptr_t)dyn->next-sizeof(void*))\
|
||||
*(uint32_t*)(dyn->block) = (uint32_t)(A); \
|
||||
dyn->block += 4; dyn->arm_size += 4; \
|
||||
dyn->insts[ninst].size2 += 4; \
|
||||
}while(0)
|
||||
|
||||
#define MESSAGE(A, ...) if(box86_dynarec_dump) dynarec_log(LOG_NONE, __VA_ARGS__)
|
||||
#define NEW_INST
|
||||
#define NEW_INST \
|
||||
if(ninst) \
|
||||
addInst(dyn->instsize, &dyn->insts_size, dyn->insts[ninst-1].x86.size, dyn->insts[ninst-1].size/4);
|
||||
#define INST_EPILOG
|
||||
#define INST_NAME(name) \
|
||||
if(box86_dynarec_dump) {\
|
||||
printf_x86_instruction(my_context->dec, &dyn->insts[ninst].x86, name); \
|
||||
dynarec_log(LOG_NONE, "%s%p: %d emited opcodes, inst=%d, barrier=%d state=%d/%d, set=%X, use=%X, need=%X", \
|
||||
(box86_dynarec_dump>1)?"\e[32m":"", \
|
||||
(void*)(dyn->arm_start+dyn->insts[ninst].address), \
|
||||
dyn->insts[ninst].size/4, \
|
||||
ninst, \
|
||||
dyn->insts[ninst].x86.barrier, \
|
||||
dyn->insts[ninst].x86.state_flags, \
|
||||
dyn->state_flags, \
|
||||
dyn->insts[ninst].x86.set_flags, \
|
||||
dyn->insts[ninst].x86.use_flags, \
|
||||
dyn->insts[ninst].x86.need_flags); \
|
||||
for(int ii=0; ii<24; ++ii) { \
|
||||
switch(dyn->insts[ninst].n.neoncache[ii].t) { \
|
||||
case NEON_CACHE_ST_D: dynarec_log(LOG_NONE, " D%d:ST%d", ii+8, dyn->insts[ninst].n.neoncache[ii].n); break; \
|
||||
case NEON_CACHE_ST_F: dynarec_log(LOG_NONE, " S%d:st%d", (ii+8)*2, dyn->insts[ninst].n.neoncache[ii].n); break; \
|
||||
case NEON_CACHE_MM: dynarec_log(LOG_NONE, " D%d:MM%d", ii+8, dyn->insts[ninst].n.neoncache[ii].n); break; \
|
||||
case NEON_CACHE_XMMW: dynarec_log(LOG_NONE, " Q%d:XMM%d", (ii+8)/2, dyn->insts[ninst].n.neoncache[ii].n); ++ii; break; \
|
||||
case NEON_CACHE_XMMR: dynarec_log(LOG_NONE, " Q%d:xmm%d", (ii+8)/2, dyn->insts[ninst].n.neoncache[ii].n); ++ii; break; \
|
||||
case NEON_CACHE_SCR: dynarec_log(LOG_NONE, " D%d:Scratch", ii+8); break; \
|
||||
case NEON_CACHE_NONE: \
|
||||
default: break; \
|
||||
} \
|
||||
} \
|
||||
if(dyn->n.stack || dyn->insts[ninst].n.stack_next) \
|
||||
printf_log(LOG_NONE, " X87:%d/%d", dyn->n.stack, dyn->insts[ninst].n.stack_next);\
|
||||
if(dyn->insts[ninst].n.combined1 || dyn->insts[ninst].n.combined2) \
|
||||
printf_log(LOG_NONE, " CMB:%d/%d", dyn->insts[ninst].n.combined1, dyn->insts[ninst].n.combined2); \
|
||||
dynarec_log(LOG_NONE, "%s\n", (box86_dynarec_dump>1)?"\e[m":""); \
|
||||
}
|
||||
|
||||
#define NEW_BARRIER_INST \
|
||||
if(ninst) { \
|
||||
dyn->sons_x86[dyn->sons_size] = (uintptr_t)ip; \
|
||||
dyn->sons_arm[dyn->sons_size] = dyn->block; \
|
||||
MESSAGE(LOG_DUMP, "----> potential Son here\n");\
|
||||
++dyn->sons_size; \
|
||||
}
|
||||
|
||||
#define INST_NAME(name) inst_name_pass3(dyn, ninst, name)
|
||||
@@ -5,6 +5,9 @@
|
||||
|
||||
typedef struct x86emu_s x86emu_t;
|
||||
typedef struct dynablock_s dynablock_t;
|
||||
typedef struct instsize_s instsize_t;
|
||||
|
||||
#define BARRIER_MAYBE 8
|
||||
|
||||
#define NEON_CACHE_NONE 0
|
||||
#define NEON_CACHE_ST_D 1
|
||||
@@ -16,42 +19,71 @@ typedef struct dynablock_s dynablock_t;
|
||||
typedef union neon_cache_s {
|
||||
int8_t v;
|
||||
struct {
|
||||
unsigned int t:4; // reg type
|
||||
unsigned int n:4; // reg number
|
||||
uint8_t t:4; // reg type
|
||||
uint8_t n:4; // reg number
|
||||
};
|
||||
} neon_cache_t;
|
||||
typedef union sse_cache_s {
|
||||
int8_t v;
|
||||
struct {
|
||||
uint8_t reg;
|
||||
uint8_t write;
|
||||
};
|
||||
} sse_cache_t;
|
||||
typedef struct neoncache_s {
|
||||
neon_cache_t neoncache[24];
|
||||
int8_t stack;
|
||||
int8_t stack_next;
|
||||
int8_t stack_pop;
|
||||
uint8_t combined1;
|
||||
uint8_t combined2;
|
||||
// Neon cache
|
||||
neon_cache_t neoncache[24];
|
||||
int8_t stack;
|
||||
int8_t stack_next;
|
||||
int8_t stack_pop;
|
||||
int8_t stack_push;
|
||||
uint8_t combined1;
|
||||
uint8_t combined2;
|
||||
uint8_t swapped; // the combined reg were swapped
|
||||
uint8_t barrier; // is there a barrier at instruction epilog?
|
||||
uint8_t pushed; // positive pushed value (to check for overflow)
|
||||
uint8_t poped; // positive poped value (to check for underflow)
|
||||
uint32_t news; // bitmask, wich neoncache are new for this opcode
|
||||
// fpu cache
|
||||
int8_t x87cache[8];// cache status for the 8 x87 register behind the fpu stack
|
||||
int8_t x87reg[8]; // reg used for x87cache entry
|
||||
int16_t tags; // similar to fpu_tags
|
||||
int8_t mmxcache[8];// cache status for the 8 MMX registers
|
||||
sse_cache_t ssecache[8];// cache status for the 8 SSE(2) registers
|
||||
int8_t fpuused[24];// all 8..31 double reg from fpu, used by x87, sse and mmx
|
||||
int8_t x87stack; // cache stack counter
|
||||
int8_t mmxcount; // number of mmx register used (not both mmx and x87 at the same time)
|
||||
int8_t fpu_scratch;// scratch counter
|
||||
int8_t fpu_extra_qscratch; // some opcode need an extra quad scratch register
|
||||
int8_t fpu_reg; // x87/sse/mmx reg counter
|
||||
} neoncache_t;
|
||||
|
||||
typedef struct flagcache_s {
|
||||
int pending; // is there a pending flags here, or to check?
|
||||
int dfnone; // if defered flags is already set to df_none
|
||||
} flagcache_t;
|
||||
|
||||
typedef struct instruction_arm_s {
|
||||
instruction_x86_t x86;
|
||||
uintptr_t address; // (start) address of the arm emited instruction
|
||||
uintptr_t epilog; // epilog of current instruction (can be start of next, of barrier stuff)
|
||||
int size; // size of the arm emited instruction
|
||||
int size2; // size of the arm emited instrucion after pass2
|
||||
int pred_sz; // size of predecessor list
|
||||
int *pred; // predecessor array
|
||||
uintptr_t mark, mark2, mark3;
|
||||
uintptr_t markf;
|
||||
uintptr_t markf, markf2;
|
||||
uintptr_t markseg;
|
||||
uintptr_t marklock;
|
||||
int pass2choice;// value for choices that are fixed on pass2 for pass3
|
||||
uintptr_t natcall;
|
||||
int retn;
|
||||
neoncache_t n;
|
||||
int barrier_maybe;
|
||||
flagcache_t f_exit; // flags status at end of intruction
|
||||
neoncache_t n; // neoncache at end of intruction (but before poping)
|
||||
flagcache_t f_entry; // flags status before the instruction begin
|
||||
} instruction_arm_t;
|
||||
|
||||
typedef union sse_cache_s {
|
||||
int v;
|
||||
struct {
|
||||
uint8_t reg;
|
||||
uint8_t write;
|
||||
};
|
||||
} sse_cache_t;
|
||||
|
||||
typedef struct dynarec_arm_s {
|
||||
instruction_arm_t *insts;
|
||||
@@ -62,31 +94,36 @@ typedef struct dynarec_arm_s {
|
||||
void* block; // memory pointer where next instruction is emited
|
||||
uintptr_t arm_start; // start of the arm code
|
||||
int arm_size; // size of emitted arm code
|
||||
int state_flags;// actual state for on-demand flags
|
||||
int x87cache[8];// cache status for the 8 x87 register behind the fpu stack
|
||||
int x87reg[8]; // reg used for x87cache entry
|
||||
int mmxcache[8];// cache status for the 8 MMX registers
|
||||
sse_cache_t ssecache[8];// cache status for the 8 SSE(2) registers
|
||||
int fpuused[24];// all 8..31 double reg from fpu, used by x87, sse and mmx
|
||||
uintptr_t jmp_next; // address of the jump_next address
|
||||
flagcache_t f;
|
||||
neoncache_t n; // cache for the 8..31 double reg from fpu, plus x87 stack delta
|
||||
int x87stack; // cache stack counter
|
||||
int mmxcount; // number of mmx register used (not both mmx and x87 at the same time)
|
||||
int fpu_scratch;// scratch counter
|
||||
int fpu_extra_qscratch; // some opcode need an extra quad scratch register
|
||||
int fpu_reg; // x87/sse/mmx reg counter
|
||||
int dfnone; // if defered flags is already set to df_none
|
||||
uintptr_t* next; // variable array of "next" jump address
|
||||
int next_sz;
|
||||
int next_cap;
|
||||
uintptr_t* sons_x86; // the x86 address of potential dynablock sons
|
||||
void** sons_arm; // the arm address of potential dynablock sons
|
||||
int sons_size; // number of potential dynablock sons
|
||||
int* jmps; // variable array of jump instructions
|
||||
int jmp_sz;
|
||||
int jmp_cap;
|
||||
int* predecessor;// single array of all predecessor
|
||||
dynablock_t* dynablock;
|
||||
instsize_t* instsize;
|
||||
size_t insts_size; // size of the instruction size array (calculated)
|
||||
uint8_t smread; // for strongmem model emulation
|
||||
uint8_t smwrite; // for strongmem model emulation
|
||||
uintptr_t forward; // address of the last end of code while testing forward
|
||||
uintptr_t forward_to; // address of the next jump to (to check if everything is ok)
|
||||
int32_t forward_size; // size at the forward point
|
||||
int forward_ninst; // ninst at the forward point
|
||||
uint8_t always_test;
|
||||
uint8_t abort; // abort the creation of the block
|
||||
} dynarec_arm_t;
|
||||
|
||||
void add_next(dynarec_arm_t *dyn, uintptr_t addr);
|
||||
uintptr_t get_closest_next(dynarec_arm_t *dyn, uintptr_t addr);
|
||||
void add_jump(dynarec_arm_t *dyn, int ninst);
|
||||
int get_first_jump(dynarec_arm_t *dyn, int next);
|
||||
int is_nops(dynarec_arm_t *dyn, uintptr_t addr, int n);
|
||||
int is_instructions(dynarec_arm_t *dyn, uintptr_t addr, int n);
|
||||
|
||||
void CreateJmpNext(void* addr, void* next);
|
||||
|
||||
#endif //__DYNAREC_ARM_PRIVATE_H_
|
||||
@@ -1,6 +1,11 @@
|
||||
#ifndef __DYNAREC_PRIVATE_H_
|
||||
#define __DYNAREC_PRIVATE_H_
|
||||
|
||||
#define BARRIER_NONE 0
|
||||
#define BARRIER_FLAGS 1
|
||||
#define BARRIER_FLOAT 2
|
||||
#define BARRIER_FULL 3
|
||||
|
||||
// all flags for the use_flags field
|
||||
#define X_CF (1<<0)
|
||||
#define X_PF (1<<1)
|
||||
@@ -9,29 +14,54 @@
|
||||
#define X_SF (1<<4)
|
||||
#define X_OF (1<<5)
|
||||
#define X_ALL ((1<<6)-1)
|
||||
#define X_PEND (0x1000)
|
||||
#define X_PEND (0x80)
|
||||
|
||||
// all state flags
|
||||
#define SF_UNKNOWN 0
|
||||
#define SF_SET 1
|
||||
#define SF_PENDING 2
|
||||
#define SF_SET_PENDING 3
|
||||
#define SF_MAYSET 4
|
||||
#define SF_SUBSET 5
|
||||
#define SF_SET_PENDING (SF_SET|SF_PENDING)
|
||||
#define SF_SUB 4
|
||||
#define SF_SUBSET (SF_SUB|SF_SET)
|
||||
#define SF_SUBSET_PENDING (SF_SUBSET|SF_PENDING)
|
||||
#define SF_DF 8
|
||||
#define SF_SET_DF (SF_SET|SF_DF)
|
||||
#define SF_NODF 16
|
||||
#define SF_SET_NODF (SF_SET|SF_NODF)
|
||||
|
||||
typedef struct instruction_x86_s {
|
||||
uintptr_t addr; //address of the instruction
|
||||
int32_t size; // size of the instruction
|
||||
int barrier; // next instruction is a jump point, so no optim allowed
|
||||
uintptr_t jmp; // offset to jump to, even if conditionnal (0 if not), no relative offset here
|
||||
int jmp_cond; // 1 of conditionnal jump
|
||||
int jmp_insts; // instuction to jump to (-1 if out of the block)
|
||||
uint32_t use_flags; // 0 or combination of X_?F
|
||||
uint32_t set_flags; // 0 or combination of X_?F
|
||||
uint32_t need_flags; // calculated
|
||||
int state_flags; // One of SF_XXX state
|
||||
uint8_t jmp_cond:1; // 1 of conditionnal jump
|
||||
uint8_t has_next:1; // does this opcode can continue to the next?
|
||||
uint8_t has_callret:1; // this instruction have an optimised call setup
|
||||
uint8_t alive:1; // this opcode gets executed (0 if dead code in that block)
|
||||
uint8_t barrier; // next instruction is a jump point, so no optim allowed
|
||||
uint8_t barrier_next; // next instruction needs a barrier
|
||||
uint8_t state_flags;// One of SF_XXX state
|
||||
uint8_t use_flags; // 0 or combination of X_?F
|
||||
uint8_t set_flags; // 0 or combination of X_?F
|
||||
uint8_t may_set; // 1 if the flags may not be set
|
||||
uint8_t gen_flags; // calculated
|
||||
uint8_t need_before; // calculated
|
||||
uint8_t need_after; // calculated
|
||||
} instruction_x86_t;
|
||||
|
||||
void printf_x86_instruction(zydis_dec_t* dec, instruction_x86_t* inst, const char* name);
|
||||
|
||||
//#define USE_CUSTOM_MEM
|
||||
#ifdef USE_CUSTOM_MEM
|
||||
#define dynaMalloc customMalloc
|
||||
#define dynaCalloc customCalloc
|
||||
#define dynaRealloc customRealloc
|
||||
#define dynaFree customFree
|
||||
#else
|
||||
#define dynaMalloc box_malloc
|
||||
#define dynaCalloc box_calloc
|
||||
#define dynaRealloc box_realloc
|
||||
#define dynaFree box_free
|
||||
#endif
|
||||
|
||||
#endif //__DYNAREC_PRIVATE_H_
|
||||
@@ -83,7 +83,7 @@ INVALIDATE 1 1 1 1 0 0 1 1 1 <1> 1 1 <2>/=10 0 0 <4> 0 0 0 <2>/11 <2> 0 <4>
|
||||
INVALIDATE 1 1 1 1 0 0 1 1 1 <1> 1 1 <2>/=10 0 0 <4> 0 0 0 <2>/01 <2> 0 <4>
|
||||
INVALIDATE 1 1 1 1 0 0 1 1 1 <1> 1 1 <2>/=01 0 0 <4> 0 0 0 <2>/11 <2> 0 <4>
|
||||
INVALIDATE 1 1 1 1 0 0 1 1 1 <1> 1 1 <2>/=00 0 0 <4> 0 0 0 <2>/=11 <2> 0 <4>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 0 0 @<2> Q M 0 Vm VREV\%d16 &l&l param\<c>.\%d8 &l&l size\ <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 0 0 @<2> Q M 0 Vm VREV\%d64 &g&g param\<c>.\%d8 &l&l size\ <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 0 1 0 U Q M 0 Vm VPADDL<c>.<dt> <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 1 0 0 0 Q M 0 Vm VCLS<c>.<dt> <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 1 0 0 1 Q M 0 Vm VCLZ<c>.<dt> <Qd>, <Qm>
|
||||
@@ -233,9 +233,9 @@ NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 0 size 1 @<1> Rm @ param=1 char align[4
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 0 @<4> 1 1 0 1 @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 0 @<4> 1 1 1 1 @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 0 @<4> Rm @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 1 size @<1> @<1> 1 1 0 1 @ param2_1=1 char align[4] !@ %@ sprintf(align, ":%d", 16 << size)@ align[0] = '\0'@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[]}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 1 size @<1> @<1> 1 1 1 1 @ param2_1=1 char align[4] !@ %@ sprintf(align, ":%d", 16 << size)@ align[0] = '\0'@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[]}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 1 size @<1> @<1> Rm @ param2_1=1 char align[4] !@ %@ sprintf(align, ":%d", 16 << size)@ align[0] = '\0'@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[]}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 1 size @<1> @<1> 1 1 0 1 @ param2_1=1 char align[5] !@ %@ sprintf(align, ":%d", 16 << size)@ align[0] = '\0'@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[]}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 1 size @<1> @<1> 1 1 1 1 @ param2_1=1 char align[5] !@ %@ sprintf(align, ":%d", 16 << size)@ align[0] = '\0'@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[]}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 1 size @<1> @<1> Rm @ param2_1=1 char align[5] !@ %@ sprintf(align, ":%d", 16 << size)@ align[0] = '\0'@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[]}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> 1 1 0 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> 1 1 1 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> Rm @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\], <Rm>
|
||||
@@ -353,8 +353,10 @@ ARM_ cond 0 0 0 1 1 1 1 0 Rn Rd (1) (1) (1) (1) 1 0 0 1 Rt STREXH<c> <Rd>, <Rt>,
|
||||
ARM_ cond 0 0 0 1 1 1 1 1 Rn Rt (1) (1) (1) (1) 1 0 0 1 (1) (1) (1) (1) LDREXH<c> <Rt>, [<Rn>]
|
||||
ARM_ cond 0 0 1 0 0 0 0 S Rn Rd imm12 AND{S}<c> <Rd>, <Rn>, #<const>
|
||||
ARM_ cond 0 0 1 0 0 0 1 S Rn Rd imm12 EOR{S}<c> <Rd>, <Rn>, #<const>
|
||||
ARM_ cond 0 0 1 0 0 1 0 0 1 1 1 1 Rd imm12 ADR<c> <Rd>, #-<const>
|
||||
ARM_ cond 0 0 1 0 0 1 0 S Rn Rd imm12 SUB{S}<c> <Rd>, <Rn>, #<const>
|
||||
ARM_ cond 0 0 1 0 0 1 1 S Rn Rd imm12 RSB{S}<c> <Rd>, <Rn>, #<const>
|
||||
ARM_ cond 0 0 1 0 1 0 0 0 1 1 1 1 Rd imm12 ADR<c> <Rd>, #<const>
|
||||
ARM_ cond 0 0 1 0 1 0 0 S Rn Rd imm12 ADD{S}<c> <Rd>, <Rn>, #<const>
|
||||
ARM_ cond 0 0 1 0 1 0 1 S Rn Rd imm12 ADC{S}<c> <Rd>, <Rn>, #<const>
|
||||
ARM_ cond 0 0 1 0 1 1 0 S Rn Rd imm12 SBC{S}<c> <Rd>, <Rn>, #<const>
|
||||
|
||||
+10
-8
@@ -45,7 +45,9 @@ const char* DumpSection(Elf32_Shdr *s, char* SST) {
|
||||
GO(SHT_GNU_ATTRIBUTES);
|
||||
GO(SHT_GNU_HASH);
|
||||
GO(SHT_GNU_LIBLIST);
|
||||
GO(SHT_CHECKSUM);
|
||||
#ifndef TERMUX
|
||||
GO(SHT_CHECKSUM);
|
||||
#endif
|
||||
GO(SHT_LOSUNW);
|
||||
//GO(SHT_SUNW_move);
|
||||
GO(SHT_SUNW_COMDAT);
|
||||
@@ -235,12 +237,12 @@ void DumpMainHeader(Elf32_Ehdr *header, elfheader_t *h)
|
||||
printf_dump(LOG_NEVER, "ELF Dump ==========\n");
|
||||
|
||||
printf_dump(LOG_NEVER, "ELF Dump PEntries (%d)\n", h->numSHEntries);
|
||||
for (int i=0; i<h->numPHEntries; ++i)
|
||||
for (uint16_t i=0; i<h->numPHEntries; ++i)
|
||||
printf_dump(LOG_NEVER, " PHEntry %04d : %s\n", i, DumpPHEntry(h->PHEntries+i));
|
||||
printf_dump(LOG_NEVER, "ELF Dump PEntries ====\n");
|
||||
|
||||
printf_dump(LOG_NEVER, "ELF Dump Sections (%d)\n", h->numSHEntries);
|
||||
for (int i=0; i<h->numSHEntries; ++i)
|
||||
for (uint16_t i=0; i<h->numSHEntries; ++i)
|
||||
printf_dump(LOG_NEVER, " Section %04d : %s\n", i, DumpSection(h->SHEntries+i, h->SHStrTab));
|
||||
printf_dump(LOG_NEVER, "ELF Dump Sections ====\n");
|
||||
}
|
||||
@@ -251,7 +253,7 @@ void DumpSymTab(elfheader_t *h)
|
||||
if(box86_dump && h->SymTab) {
|
||||
const char* name = ElfName(h);
|
||||
printf_dump(LOG_NEVER, "ELF Dump SymTab(%d)=\n", h->numSymTab);
|
||||
for (int i=0; i<h->numSymTab; ++i)
|
||||
for (uint32_t i=0; i<h->numSymTab; ++i)
|
||||
printf_dump(LOG_NEVER, " %s:SymTab[%d] = \"%s\", value=%p, size=%d, info/other=%d/%d index=%d\n", name,
|
||||
i, h->StrTab+h->SymTab[i].st_name, (void*)h->SymTab[i].st_value, h->SymTab[i].st_size,
|
||||
h->SymTab[i].st_info, h->SymTab[i].st_other, h->SymTab[i].st_shndx);
|
||||
@@ -263,7 +265,7 @@ void DumpDynamicSections(elfheader_t *h)
|
||||
{
|
||||
if(box86_dump && h->Dynamic) {
|
||||
printf_dump(LOG_NEVER, "ELF Dump Dynamic(%d)=\n", h->numDynamic);
|
||||
for (int i=0; i<h->numDynamic; ++i)
|
||||
for (uint32_t i=0; i<h->numDynamic; ++i)
|
||||
printf_dump(LOG_NEVER, " Dynamic %04d : %s\n", i, DumpDynamic(h->Dynamic+i));
|
||||
printf_dump(LOG_NEVER, "ELF Dump Dynamic=====\n");
|
||||
}
|
||||
@@ -274,7 +276,7 @@ void DumpDynSym(elfheader_t *h)
|
||||
if(box86_dump && h->DynSym) {
|
||||
const char* name = ElfName(h);
|
||||
printf_dump(LOG_NEVER, "ELF Dump DynSym(%d)=\n", h->numDynSym);
|
||||
for (int i=0; i<h->numDynSym; ++i) {
|
||||
for (uint32_t i=0; i<h->numDynSym; ++i) {
|
||||
int version = h->VerSym?((Elf32_Half*)((uintptr_t)h->VerSym+h->delta))[i]:-1;
|
||||
printf_dump(LOG_NEVER, " %s:DynSym[%d] = %s\n", name, i, DumpSym(h, h->DynSym+i, version));
|
||||
}
|
||||
@@ -286,7 +288,7 @@ void DumpDynamicNeeded(elfheader_t *h)
|
||||
{
|
||||
if(box86_dump && h->DynStrTab) {
|
||||
printf_dump(LOG_NEVER, "ELF Dump DT_NEEDED=====\n");
|
||||
for (int i=0; i<h->numDynamic; ++i)
|
||||
for (uint32_t i=0; i<h->numDynamic; ++i)
|
||||
if(h->Dynamic[i].d_tag==DT_NEEDED) {
|
||||
printf_dump(LOG_NEVER, " Needed : %s\n", h->DynStrTab+h->Dynamic[i].d_un.d_val + h->delta);
|
||||
}
|
||||
@@ -298,7 +300,7 @@ void DumpDynamicRPath(elfheader_t *h)
|
||||
{
|
||||
if(box86_dump && h->DynStrTab) {
|
||||
printf_dump(LOG_NEVER, "ELF Dump DT_RPATH/DT_RUNPATH=====\n");
|
||||
for (int i=0; i<h->numDynamic; ++i) {
|
||||
for (uint32_t i=0; i<h->numDynamic; ++i) {
|
||||
if(h->Dynamic[i].d_tag==DT_RPATH) {
|
||||
printf_dump(LOG_NEVER, " RPATH : %s\n", h->DynStrTab+h->Dynamic[i].d_un.d_val + h->delta);
|
||||
}
|
||||
|
||||
+1173
-555
File diff suppressed because it is too large.
Load diff
@@ -1,33 +1,43 @@
|
||||
#ifndef __ELFLOADER_PRIVATE_H_
|
||||
#define __ELFLOADER_PRIVATE_H_
|
||||
|
||||
#ifdef DYNAREC
|
||||
typedef struct dynablocklist_s dynablocklist_t;
|
||||
#endif
|
||||
|
||||
typedef struct library_s library_t;
|
||||
typedef struct needed_libs_s needed_libs_t;
|
||||
typedef struct kh_mapsymbols_s kh_mapsymbols_t;
|
||||
|
||||
#include <pthread.h>
|
||||
#include <elf.h>
|
||||
#include "elfloader.h"
|
||||
|
||||
struct elfheader_s {
|
||||
|
||||
typedef struct multiblock_s {
|
||||
void* p;
|
||||
uintptr_t offs;
|
||||
uintptr_t paddr;
|
||||
uintptr_t align;
|
||||
size_t size;
|
||||
size_t asize;
|
||||
uint8_t flags;
|
||||
} multiblock_t;
|
||||
|
||||
typedef struct elfheader_s {
|
||||
char* name;
|
||||
char* path; // Resolved path to file
|
||||
int numPHEntries;
|
||||
char* soname; // soname of the elf
|
||||
uint16_t numPHEntries;
|
||||
Elf32_Phdr *PHEntries;
|
||||
int numSHEntries;
|
||||
uint16_t numSHEntries;
|
||||
Elf32_Shdr *SHEntries;
|
||||
int SHIdx;
|
||||
int numSST;
|
||||
char* SHStrTab;
|
||||
char* StrTab;
|
||||
Elf32_Sym* SymTab;
|
||||
int numSymTab;
|
||||
uint32_t numSymTab;
|
||||
char* DynStr;
|
||||
Elf32_Sym* DynSym;
|
||||
int numDynSym;
|
||||
uint32_t numDynSym;
|
||||
Elf32_Dyn* Dynamic;
|
||||
int numDynamic;
|
||||
uint32_t numDynamic;
|
||||
char* DynStrTab;
|
||||
int szDynStrTab;
|
||||
Elf32_Half* VerSym;
|
||||
@@ -36,8 +46,12 @@ struct elfheader_s {
|
||||
Elf32_Verdef* VerDef;
|
||||
int szVerDef;
|
||||
int e_type;
|
||||
uint32_t flags;
|
||||
|
||||
intptr_t delta; // should be 0
|
||||
void* image;
|
||||
void* raw; // raw pointer (might be unaligned vs image and max_align of elf)
|
||||
size_t raw_size;
|
||||
|
||||
uintptr_t entrypoint;
|
||||
uintptr_t initentry;
|
||||
@@ -66,32 +80,47 @@ struct elfheader_s {
|
||||
uintptr_t plt_end;
|
||||
uintptr_t text;
|
||||
int textsz;
|
||||
uintptr_t bss;
|
||||
int bsssz;
|
||||
uintptr_t ehframe;
|
||||
uintptr_t ehframe_end;
|
||||
uintptr_t ehframehdr;
|
||||
|
||||
uintptr_t paddr;
|
||||
uintptr_t vaddr;
|
||||
int align;
|
||||
uint32_t align;
|
||||
uint32_t memsz;
|
||||
uint32_t reserve;
|
||||
uint32_t stacksz;
|
||||
int stackalign;
|
||||
uint32_t stackalign;
|
||||
uintptr_t tlsaddr;
|
||||
uint32_t tlssize;
|
||||
uint32_t tlsfilesize;
|
||||
int tlsalign;
|
||||
uint32_t tlsalign;
|
||||
|
||||
int32_t tlsbase; // the base of the tlsdata in the global tlsdata (always negative)
|
||||
|
||||
int init_done;
|
||||
int fini_done;
|
||||
int refcnt; // ref count for the elf
|
||||
int malloc_hook_2; // this elf hook malloc, hacking it
|
||||
|
||||
char* memory; // char* and not void* to allow math on memory pointer
|
||||
void** multiblock;
|
||||
uintptr_t* multiblock_offs;
|
||||
uint32_t* multiblock_size;
|
||||
multiblock_t* multiblocks;
|
||||
int multiblock_n;
|
||||
|
||||
library_t *lib;
|
||||
needed_libs_t *neededlibs;
|
||||
};
|
||||
needed_libs_t *needed;
|
||||
|
||||
FILE* file;
|
||||
int fileno;
|
||||
|
||||
kh_mapsymbols_t *mapsymbols;
|
||||
kh_mapsymbols_t *weaksymbols;
|
||||
kh_mapsymbols_t *localsymbols;
|
||||
kh_defaultversion_t *globaldefver; // the global default version for symbols (the XXX@@vvvv of symbols)
|
||||
kh_defaultversion_t *weakdefver; // the weak default version for symbols (the XXX@@vvvv of symbols)
|
||||
} elfheader_t;
|
||||
|
||||
#define R_386_NONE 0
|
||||
#define R_386_32 1
|
||||
@@ -107,4 +136,4 @@ struct elfheader_s {
|
||||
|
||||
elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec);
|
||||
|
||||
#endif //__ELFLOADER_PRIVATE_H_
|
||||
#endif //__ELFLOADER_PRIVATE_H_
|
||||
+168
-66
@@ -17,16 +17,16 @@
|
||||
int LoadSH(FILE *f, Elf32_Shdr *s, void** SH, const char* name, uint32_t type)
|
||||
{
|
||||
if(type && (s->sh_type != type)) {
|
||||
printf_log(LOG_INFO, "Section Header \"%s\" (off=%d, size=%d) has incorect type (%d != %d)\n", name, s->sh_offset, s->sh_size, s->sh_type, type);
|
||||
printf_dump(LOG_INFO, "Section Header \"%s\" (off=%d, size=%d) has incorect type (%d != %d)\n", name, s->sh_offset, s->sh_size, s->sh_type, type);
|
||||
return -1;
|
||||
}
|
||||
if (type==SHT_SYMTAB && s->sh_size%sizeof(Elf32_Sym)) {
|
||||
printf_log(LOG_INFO, "Section Header \"%s\" (off=%d, size=%d) has size (not multiple of %d)\n", name, s->sh_offset, s->sh_size, sizeof(Elf32_Sym));
|
||||
printf_dump(LOG_INFO, "Section Header \"%s\" (off=%d, size=%d) has size (not multiple of %d)\n", name, s->sh_offset, s->sh_size, sizeof(Elf32_Sym));
|
||||
}
|
||||
*SH = calloc(1, s->sh_size);
|
||||
*SH = box_calloc(1, s->sh_size);
|
||||
fseeko64(f, s->sh_offset ,SEEK_SET);
|
||||
if(fread(*SH, s->sh_size, 1, f)!=1) {
|
||||
printf_log(LOG_INFO, "Cannot read Section Header \"%s\" (off=%d, size=%d)\n", name, s->sh_offset, s->sh_size);
|
||||
printf_dump(LOG_INFO, "Cannot read Section Header \"%s\" (off=%d, size=%d)\n", name, s->sh_offset, s->sh_size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -43,10 +43,10 @@ int FindSection(Elf32_Shdr *s, int n, char* SHStrTab, const char* name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void LoadNamedSection(FILE *f, Elf32_Shdr *s, int size, char* SHStrTab, const char* name, const char* clearname, uint32_t type, void** what, int* num)
|
||||
void LoadNamedSection(FILE *f, Elf32_Shdr *s, int size, char* SHStrTab, const char* name, const char* clearname, uint32_t type, void** what, uint32_t* num)
|
||||
{
|
||||
int n = FindSection(s, size, SHStrTab, name);
|
||||
printf_log(LOG_DEBUG, "Loading %s (idx = %d)\n", clearname, n);
|
||||
printf_dump(LOG_DEBUG, "Loading %s (idx = %d)\n", clearname, n);
|
||||
if(n)
|
||||
LoadSH(f, s+n, what, name, type);
|
||||
if(type==SHT_SYMTAB || type==SHT_DYNSYM) {
|
||||
@@ -63,59 +63,59 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
Elf32_Ehdr header;
|
||||
int level = (exec)?LOG_INFO:LOG_DEBUG;
|
||||
if(fread(&header, sizeof(Elf32_Ehdr), 1, f)!=1) {
|
||||
printf_log(level, "Cannot read ELF Header\n");
|
||||
printf_dump(level, "Cannot read ELF Header\n");
|
||||
return NULL;
|
||||
}
|
||||
if(memcmp(header.e_ident, ELFMAG, SELFMAG)!=0) {
|
||||
printf_log(LOG_INFO, "Not an ELF file (sign=%c%c%c%c)\n", header.e_ident[0], header.e_ident[1], header.e_ident[2], header.e_ident[3]);
|
||||
printf_dump(LOG_INFO, "Not an ELF file (sign=%c%c%c%c)\n", header.e_ident[0], header.e_ident[1], header.e_ident[2], header.e_ident[3]);
|
||||
return NULL;
|
||||
}
|
||||
if(header.e_ident[EI_CLASS]!=ELFCLASS32) {
|
||||
if(header.e_ident[EI_CLASS]==ELFCLASS64) {
|
||||
printf_log(LOG_INFO, "This is a 64bits ELF! box86 can only run 32bits ELF!\n");
|
||||
printf_dump(LOG_INFO, "This is a 64bits ELF! box86 can only run 32bits ELF!\n");
|
||||
} else {
|
||||
printf_log(LOG_INFO, "Not a 32bits ELF (%d)\n", header.e_ident[EI_CLASS]);
|
||||
printf_dump(LOG_INFO, "Not a 32bits ELF (%d)\n", header.e_ident[EI_CLASS]);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
if(header.e_ident[EI_DATA]!=ELFDATA2LSB) {
|
||||
printf_log(LOG_INFO, "Not a LittleEndian ELF (%d)\n", header.e_ident[EI_DATA]);
|
||||
printf_dump(LOG_INFO, "Not a LittleEndian ELF (%d)\n", header.e_ident[EI_DATA]);
|
||||
return NULL;
|
||||
}
|
||||
if(header.e_ident[EI_VERSION]!=EV_CURRENT) {
|
||||
printf_log(LOG_INFO, "Incorrect ELF version (%d)\n", header.e_ident[EI_VERSION]);
|
||||
printf_dump(LOG_INFO, "Incorrect ELF version (%d)\n", header.e_ident[EI_VERSION]);
|
||||
return NULL;
|
||||
}
|
||||
if(header.e_ident[EI_OSABI]!=ELFOSABI_LINUX && header.e_ident[EI_OSABI]!=ELFOSABI_NONE && header.e_ident[EI_OSABI]!=ELFOSABI_SYSV) {
|
||||
printf_log(LOG_INFO, "Not a Linux ELF (%d)\n",header.e_ident[EI_OSABI]);
|
||||
printf_dump(LOG_INFO, "Not a Linux ELF (%d)\n",header.e_ident[EI_OSABI]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(header.e_type != ET_EXEC && header.e_type != ET_DYN) {
|
||||
printf_log(LOG_INFO, "Not an Executable (%d)\n", header.e_type);
|
||||
printf_dump(LOG_INFO, "Not an Executable (%d)\n", header.e_type);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(header.e_machine != EM_386) {
|
||||
printf_log(level, "Not an i386 ELF (%d)\n", header.e_machine);
|
||||
printf_dump(level, "Not an i386 ELF (%d)\n", header.e_machine);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(header.e_entry == 0 && exec) {
|
||||
printf_log(LOG_INFO, "No entry point in ELF\n");
|
||||
printf_dump(LOG_INFO, "No entry point in ELF\n");
|
||||
return NULL;
|
||||
}
|
||||
if(header.e_phentsize != sizeof(Elf32_Phdr)) {
|
||||
printf_log(LOG_INFO, "Program Header Entry size incorrect (%d != %d)\n", header.e_phentsize, sizeof(Elf32_Phdr));
|
||||
printf_dump(LOG_INFO, "Program Header Entry size incorrect (%d != %d)\n", header.e_phentsize, sizeof(Elf32_Phdr));
|
||||
return NULL;
|
||||
}
|
||||
if(header.e_shentsize != sizeof(Elf32_Shdr) && header.e_shentsize != 0) {
|
||||
printf_log(LOG_INFO, "Section Header Entry size incorrect (%d != %d)\n", header.e_shentsize, sizeof(Elf32_Shdr));
|
||||
printf_dump(LOG_INFO, "Section Header Entry size incorrect (%d != %d)\n", header.e_shentsize, sizeof(Elf32_Shdr));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
elfheader_t *h = calloc(1, sizeof(elfheader_t));
|
||||
h->name = strdup(name);
|
||||
elfheader_t *h = box_calloc(1, sizeof(elfheader_t));
|
||||
h->name = box_strdup(name);
|
||||
h->entrypoint = header.e_entry;
|
||||
h->numPHEntries = header.e_phnum;
|
||||
h->numSHEntries = header.e_shnum;
|
||||
@@ -124,55 +124,55 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
if(header.e_shentsize && header.e_shnum) {
|
||||
// special cases for nums
|
||||
if(h->numSHEntries == 0) {
|
||||
printf_log(LOG_DEBUG, "Read number of Sections in 1st Section\n");
|
||||
printf_dump(LOG_DEBUG, "Read number of Sections in 1st Section\n");
|
||||
// read 1st section header and grab actual number from here
|
||||
fseeko64(f, header.e_shoff, SEEK_SET);
|
||||
Elf32_Shdr section;
|
||||
if(fread(§ion, sizeof(Elf32_Shdr), 1, f)!=1) {
|
||||
free(h);
|
||||
printf_log(LOG_INFO, "Cannot read Initial Section Header\n");
|
||||
box_free(h);
|
||||
printf_dump(LOG_INFO, "Cannot read Initial Section Header\n");
|
||||
return NULL;
|
||||
}
|
||||
h->numSHEntries = section.sh_size;
|
||||
}
|
||||
// now read all section headers
|
||||
printf_log(LOG_DEBUG, "Read %d Section header\n", h->numSHEntries);
|
||||
h->SHEntries = (Elf32_Shdr*)calloc(h->numSHEntries, sizeof(Elf32_Shdr));
|
||||
printf_dump(LOG_DEBUG, "Read %u Section header\n", h->numSHEntries);
|
||||
h->SHEntries = (Elf32_Shdr*)box_calloc(h->numSHEntries, sizeof(Elf32_Shdr));
|
||||
fseeko64(f, header.e_shoff ,SEEK_SET);
|
||||
if(fread(h->SHEntries, sizeof(Elf32_Shdr), h->numSHEntries, f)!=h->numSHEntries) {
|
||||
FreeElfHeader(&h);
|
||||
printf_log(LOG_INFO, "Cannot read all Section Header\n");
|
||||
printf_dump(LOG_INFO, "Cannot read all Section Header\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(h->numPHEntries == PN_XNUM) {
|
||||
printf_log(LOG_DEBUG, "Read number of Program Header in 1st Section\n");
|
||||
printf_dump(LOG_DEBUG, "Read number of Program Header in 1st Section\n");
|
||||
// read 1st section header and grab actual number from here
|
||||
h->numPHEntries = h->SHEntries[0].sh_info;
|
||||
}
|
||||
}
|
||||
|
||||
printf_log(LOG_DEBUG, "Read %d Program header\n", h->numPHEntries);
|
||||
h->PHEntries = (Elf32_Phdr*)calloc(h->numPHEntries, sizeof(Elf32_Phdr));
|
||||
printf_dump(LOG_DEBUG, "Read %d Program header\n", h->numPHEntries);
|
||||
h->PHEntries = (Elf32_Phdr*)box_calloc(h->numPHEntries, sizeof(Elf32_Phdr));
|
||||
fseeko64(f, header.e_phoff ,SEEK_SET);
|
||||
if(fread(h->PHEntries, sizeof(Elf32_Phdr), h->numPHEntries, f)!=h->numPHEntries) {
|
||||
FreeElfHeader(&h);
|
||||
printf_log(LOG_INFO, "Cannot read all Program Header\n");
|
||||
printf_dump(LOG_INFO, "Cannot read all Program Header\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(header.e_shentsize && header.e_shnum) {
|
||||
if(h->SHIdx == SHN_XINDEX) {
|
||||
printf_log(LOG_DEBUG, "Read number of String Table in 1st Section\n");
|
||||
printf_dump(LOG_DEBUG, "Read number of String Table in 1st Section\n");
|
||||
h->SHIdx = h->SHEntries[0].sh_link;
|
||||
}
|
||||
if(h->SHIdx > h->numSHEntries) {
|
||||
printf_log(LOG_INFO, "Incoherent Section String Table Index : %d / %d\n", h->SHIdx, h->numSHEntries);
|
||||
printf_dump(LOG_INFO, "Incoherent Section String Table Index : %d / %d\n", h->SHIdx, h->numSHEntries);
|
||||
FreeElfHeader(&h);
|
||||
return NULL;
|
||||
}
|
||||
// load Section table
|
||||
printf_log(LOG_DEBUG, "Loading Sections Table String (idx = %d)\n", h->SHIdx);
|
||||
printf_dump(LOG_DEBUG, "Loading Sections Table String (idx = %d)\n", h->SHIdx);
|
||||
if(LoadSH(f, h->SHEntries+h->SHIdx, (void*)&h->SHStrTab, ".shstrtab", SHT_STRTAB)) {
|
||||
FreeElfHeader(&h);
|
||||
return NULL;
|
||||
@@ -188,7 +188,7 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
// grab DT_REL & DT_RELA stuffs
|
||||
// also grab the DT_STRTAB string table
|
||||
{
|
||||
for (int i=0; i<h->numDynamic; ++i) {
|
||||
for (uint32_t i=0; i<h->numDynamic; ++i) {
|
||||
Elf32_Dyn d = h->Dynamic[i];
|
||||
Elf32_Word val = d.d_un.d_val;
|
||||
Elf32_Addr ptr = d.d_un.d_ptr;
|
||||
@@ -231,61 +231,71 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
break;
|
||||
case DT_INIT: // Entry point
|
||||
h->initentry = ptr;
|
||||
printf_log(LOG_DEBUG, "The DT_INIT is at address %p\n", (void*)h->initentry);
|
||||
printf_dump(LOG_DEBUG, "The DT_INIT is at address %p\n", (void*)h->initentry);
|
||||
break;
|
||||
case DT_INIT_ARRAY:
|
||||
h->initarray = ptr;
|
||||
printf_log(LOG_DEBUG, "The DT_INIT_ARRAY is at address %p\n", (void*)h->initarray);
|
||||
printf_dump(LOG_DEBUG, "The DT_INIT_ARRAY is at address %p\n", (void*)h->initarray);
|
||||
break;
|
||||
case DT_INIT_ARRAYSZ:
|
||||
h->initarray_sz = val / sizeof(Elf32_Addr);
|
||||
printf_log(LOG_DEBUG, "The DT_INIT_ARRAYSZ is %d\n", h->initarray_sz);
|
||||
printf_dump(LOG_DEBUG, "The DT_INIT_ARRAYSZ is %d\n", h->initarray_sz);
|
||||
break;
|
||||
case DT_PREINIT_ARRAYSZ:
|
||||
#ifndef ANDROID
|
||||
if(val)
|
||||
printf_dump(LOG_NONE, "Warning, PreInit Array (size=%d) present and ignored!\n", val);
|
||||
#endif
|
||||
break;
|
||||
case DT_FINI: // Exit hook
|
||||
h->finientry = ptr;
|
||||
printf_log(LOG_DEBUG, "The DT_FINI is at address %p\n", (void*)h->finientry);
|
||||
printf_dump(LOG_DEBUG, "The DT_FINI is at address %p\n", (void*)h->finientry);
|
||||
break;
|
||||
case DT_FINI_ARRAY:
|
||||
h->finiarray = ptr;
|
||||
printf_log(LOG_DEBUG, "The DT_FINI_ARRAY is at address %p\n", (void*)h->finiarray);
|
||||
printf_dump(LOG_DEBUG, "The DT_FINI_ARRAY is at address %p\n", (void*)h->finiarray);
|
||||
break;
|
||||
case DT_FINI_ARRAYSZ:
|
||||
h->finiarray_sz = val / sizeof(Elf32_Addr);
|
||||
printf_log(LOG_DEBUG, "The DT_FINI_ARRAYSZ is %d\n", h->finiarray_sz);
|
||||
printf_dump(LOG_DEBUG, "The DT_FINI_ARRAYSZ is %d\n", h->finiarray_sz);
|
||||
break;
|
||||
case DT_VERNEEDNUM:
|
||||
h->szVerNeed = val;
|
||||
printf_log(LOG_DEBUG, "The DT_VERNEEDNUM is %d\n", h->szVerNeed);
|
||||
printf_dump(LOG_DEBUG, "The DT_VERNEEDNUM is %d\n", h->szVerNeed);
|
||||
break;
|
||||
case DT_VERNEED:
|
||||
h->VerNeed = (Elf32_Verneed*)ptr;
|
||||
printf_log(LOG_DEBUG, "The DT_VERNEED is at address %p\n", h->VerNeed);
|
||||
printf_dump(LOG_DEBUG, "The DT_VERNEED is at address %p\n", h->VerNeed);
|
||||
break;
|
||||
case DT_VERDEFNUM:
|
||||
h->szVerDef = val;
|
||||
printf_log(LOG_DEBUG, "The DT_VERDEFNUM is %d\n", h->szVerDef);
|
||||
printf_dump(LOG_DEBUG, "The DT_VERDEFNUM is %d\n", h->szVerDef);
|
||||
break;
|
||||
case DT_VERDEF:
|
||||
h->VerDef = (Elf32_Verdef*)ptr;
|
||||
printf_log(LOG_DEBUG, "The DT_VERDEF is at address %p\n", h->VerDef);
|
||||
printf_dump(LOG_DEBUG, "The DT_VERDEF is at address %p\n", h->VerDef);
|
||||
break;
|
||||
case DT_FLAGS:
|
||||
h->flags = val;
|
||||
printf_dump(LOG_DEBUG, "The DT_FLAGS is 0x%x\n", h->flags);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(h->rel) {
|
||||
if(h->relent != sizeof(Elf32_Rel)) {
|
||||
printf_log(LOG_NONE, "Rel Table Entry size invalid (0x%x should be 0x%x)\n", h->relent, sizeof(Elf32_Rel));
|
||||
printf_dump(LOG_NONE, "Rel Table Entry size invalid (0x%x should be 0x%x)\n", h->relent, sizeof(Elf32_Rel));
|
||||
FreeElfHeader(&h);
|
||||
return NULL;
|
||||
}
|
||||
printf_log(LOG_DEBUG, "Rel Table @%p (0x%x/0x%x)\n", (void*)h->rel, h->relsz, h->relent);
|
||||
printf_dump(LOG_DEBUG, "Rel Table @%p (0x%x/0x%x)\n", (void*)h->rel, h->relsz, h->relent);
|
||||
}
|
||||
if(h->rela) {
|
||||
if(h->relaent != sizeof(Elf32_Rela)) {
|
||||
printf_log(LOG_NONE, "RelA Table Entry size invalid (0x%x should be 0x%x)\n", h->relaent, sizeof(Elf32_Rela));
|
||||
printf_dump(LOG_NONE, "RelA Table Entry size invalid (0x%x should be 0x%x)\n", h->relaent, sizeof(Elf32_Rela));
|
||||
FreeElfHeader(&h);
|
||||
return NULL;
|
||||
}
|
||||
printf_log(LOG_DEBUG, "RelA Table @%p (0x%x/0x%x)\n", (void*)h->rela, h->relasz, h->relaent);
|
||||
printf_dump(LOG_DEBUG, "RelA Table @%p (0x%x/0x%x)\n", (void*)h->rela, h->relasz, h->relaent);
|
||||
}
|
||||
if(h->jmprel) {
|
||||
if(h->pltrel == DT_REL) {
|
||||
@@ -293,16 +303,16 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
} else if(h->pltrel == DT_RELA) {
|
||||
h->pltent = sizeof(Elf32_Rela);
|
||||
} else {
|
||||
printf_log(LOG_NONE, "PLT Table type is unknown (size = 0x%x, type=%d)\n", h->pltsz, h->pltrel);
|
||||
printf_dump(LOG_NONE, "PLT Table type is unknown (size = 0x%x, type=%d)\n", h->pltsz, h->pltrel);
|
||||
FreeElfHeader(&h);
|
||||
return NULL;
|
||||
}
|
||||
if((h->pltsz / h->pltent)*h->pltent != h->pltsz) {
|
||||
printf_log(LOG_NONE, "PLT Table Entry size invalid (0x%x, ent=0x%x, type=%d)\n", h->pltsz, h->pltent, h->pltrel);
|
||||
printf_dump(LOG_NONE, "PLT Table Entry size invalid (0x%x, ent=0x%x, type=%d)\n", h->pltsz, h->pltent, h->pltrel);
|
||||
FreeElfHeader(&h);
|
||||
return NULL;
|
||||
}
|
||||
printf_log(LOG_DEBUG, "PLT Table @%p (type=%d 0x%x/0x%0x)\n", (void*)h->jmprel, h->pltrel, h->pltsz, h->pltent);
|
||||
printf_dump(LOG_DEBUG, "PLT Table @%p (type=%d 0x%x/0x%0x)\n", (void*)h->jmprel, h->pltrel, h->pltsz, h->pltent);
|
||||
}
|
||||
if(h->DynStrTab && h->szDynStrTab) {
|
||||
//DumpDynamicNeeded(h); cannot dump now, it's not loaded yet
|
||||
@@ -313,32 +323,50 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
if(ii) {
|
||||
h->gotplt = h->SHEntries[ii].sh_addr;
|
||||
h->gotplt_end = h->gotplt + h->SHEntries[ii].sh_size;
|
||||
printf_log(LOG_DEBUG, "The GOT.PLT Table is at address %p\n", (void*)h->gotplt);
|
||||
printf_dump(LOG_DEBUG, "The GOT.PLT Table is at address %p\n", (void*)h->gotplt);
|
||||
}
|
||||
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".got");
|
||||
if(ii) {
|
||||
h->got = h->SHEntries[ii].sh_addr;
|
||||
h->got_end = h->got + h->SHEntries[ii].sh_size;
|
||||
printf_log(LOG_DEBUG, "The GOT Table is at address %p..%p\n", (void*)h->got, (void*)h->got_end);
|
||||
printf_dump(LOG_DEBUG, "The GOT Table is at address %p..%p\n", (void*)h->got, (void*)h->got_end);
|
||||
}
|
||||
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".plt");
|
||||
if(ii) {
|
||||
h->plt = h->SHEntries[ii].sh_addr;
|
||||
h->plt_end = h->plt + h->SHEntries[ii].sh_size;
|
||||
printf_log(LOG_DEBUG, "The PLT Table is at address %p..%p\n", (void*)h->plt, (void*)h->plt_end);
|
||||
printf_dump(LOG_DEBUG, "The PLT Table is at address %p..%p\n", (void*)h->plt, (void*)h->plt_end);
|
||||
}
|
||||
// grab version of symbols
|
||||
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".gnu.version");
|
||||
if(ii) {
|
||||
h->VerSym = (Elf32_Half*)(h->SHEntries[ii].sh_addr);
|
||||
printf_log(LOG_DEBUG, "The .gnu.version is at address %p\n", h->VerSym);
|
||||
printf_dump(LOG_DEBUG, "The .gnu.version is at address %p\n", h->VerSym);
|
||||
}
|
||||
// grab .text for main code
|
||||
// grab .bss for main code
|
||||
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".text");
|
||||
if(ii) {
|
||||
h->text = (uintptr_t)(h->SHEntries[ii].sh_addr);
|
||||
h->textsz = h->SHEntries[ii].sh_size;
|
||||
printf_log(LOG_DEBUG, "The .text is at address %p, and is %d big\n", (void*)h->text, h->textsz);
|
||||
printf_dump(LOG_DEBUG, "The .text is at address %p, and is %d big\n", (void*)h->text, h->textsz);
|
||||
}
|
||||
// grab .bss to find brk
|
||||
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".bss");
|
||||
if(ii) {
|
||||
h->bss = (uintptr_t)(h->SHEntries[ii].sh_addr);
|
||||
h->bsssz = h->SHEntries[ii].sh_size;
|
||||
printf_dump(LOG_DEBUG, "The .bss is at address %p, and is %d big\n", (void*)h->bss, h->bsssz);
|
||||
}
|
||||
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".eh_frame");
|
||||
if(ii) {
|
||||
h->ehframe = (uintptr_t)(h->SHEntries[ii].sh_addr);
|
||||
h->ehframe_end = h->ehframe + h->SHEntries[ii].sh_size;
|
||||
printf_dump(LOG_DEBUG, "The .eh_frame section is at address %p..%p\n", (void*)h->ehframe, (void*)h->ehframe_end);
|
||||
}
|
||||
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".eh_frame_hdr");
|
||||
if(ii) {
|
||||
h->ehframehdr = (uintptr_t)(h->SHEntries[ii].sh_addr);
|
||||
printf_dump(LOG_DEBUG, "The .eh_frame_hdr section is at address %p\n", (void*)h->ehframehdr);
|
||||
}
|
||||
|
||||
LoadNamedSection(f, h->SHEntries, h->numSHEntries, h->SHStrTab, ".dynstr", "DynSym Strings", SHT_STRTAB, (void**)&h->DynStr, NULL);
|
||||
@@ -350,19 +378,22 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
|
||||
const char* GetSymbolVersion(elfheader_t* h, int version)
|
||||
{
|
||||
if(!h->VerNeed || (version<2))
|
||||
version&=0x7fff; // remove bit15 that switch between hidden/public
|
||||
if(version<2)
|
||||
return NULL;
|
||||
/*if(version==1)
|
||||
return "*";*/
|
||||
Elf32_Verneed *ver = (Elf32_Verneed*)((uintptr_t)h->VerNeed + h->delta);
|
||||
while(ver) {
|
||||
Elf32_Vernaux *aux = (Elf32_Vernaux*)((uintptr_t)ver + ver->vn_aux);
|
||||
for(int j=0; j<ver->vn_cnt; ++j) {
|
||||
if(aux->vna_other==version)
|
||||
return h->DynStr+aux->vna_name;
|
||||
aux = (Elf32_Vernaux*)((uintptr_t)aux + aux->vna_next);
|
||||
if(h->VerNeed) {
|
||||
Elf32_Verneed *ver = (Elf32_Verneed*)((uintptr_t)h->VerNeed + h->delta);
|
||||
while(ver) {
|
||||
Elf32_Vernaux *aux = (Elf32_Vernaux*)((uintptr_t)ver + ver->vn_aux);
|
||||
for(int j=0; j<ver->vn_cnt; ++j) {
|
||||
if(aux->vna_other==version)
|
||||
return h->DynStr+aux->vna_name;
|
||||
aux = (Elf32_Vernaux*)((uintptr_t)aux + aux->vna_next);
|
||||
}
|
||||
ver = ver->vn_next?((Elf32_Verneed*)((uintptr_t)ver + ver->vn_next)):NULL;
|
||||
}
|
||||
ver = ver->vn_next?((Elf32_Verneed*)((uintptr_t)ver + ver->vn_next)):NULL;
|
||||
}
|
||||
return GetParentSymbolVersion(h, version); // if symbol is "internal", use Def table instead
|
||||
}
|
||||
@@ -385,3 +416,74 @@ const char* GetParentSymbolVersion(elfheader_t* h, int index)
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int GetVersionIndice(elfheader_t* h, const char* vername)
|
||||
{
|
||||
if(!vername)
|
||||
return 0;
|
||||
if(h->VerDef) {
|
||||
Elf32_Verdef *def = (Elf32_Verdef*)((uintptr_t)h->VerDef + h->delta);
|
||||
while(def) {
|
||||
Elf32_Verdaux *aux = (Elf32_Verdaux*)((uintptr_t)def + def->vd_aux);
|
||||
if(!strcmp(h->DynStr+aux->vda_name, vername))
|
||||
return def->vd_ndx;
|
||||
def = def->vd_next?((Elf32_Verdef*)((uintptr_t)def + def->vd_next)):NULL;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int GetNeededVersionCnt(elfheader_t* h, const char* libname)
|
||||
{
|
||||
if(!libname)
|
||||
return 0;
|
||||
if(h->VerNeed) {
|
||||
Elf32_Verneed *ver = (Elf32_Verneed*)((uintptr_t)h->VerNeed + h->delta);
|
||||
while(ver) {
|
||||
char *filename = h->DynStr + ver->vn_file;
|
||||
Elf32_Vernaux *aux = (Elf32_Vernaux*)((uintptr_t)ver + ver->vn_aux);
|
||||
if(!strcmp(filename, libname))
|
||||
return ver->vn_cnt;
|
||||
ver = ver->vn_next?((Elf32_Verneed*)((uintptr_t)ver + ver->vn_next)):NULL;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* GetNeededVersionString(elfheader_t* h, const char* libname, int idx)
|
||||
{
|
||||
if(!libname)
|
||||
return 0;
|
||||
if(h->VerNeed) {
|
||||
Elf32_Verneed *ver = (Elf32_Verneed*)((uintptr_t)h->VerNeed + h->delta);
|
||||
while(ver) {
|
||||
char *filename = h->DynStr + ver->vn_file;
|
||||
Elf32_Vernaux *aux = (Elf32_Vernaux*)((uintptr_t)ver + ver->vn_aux);
|
||||
if(!strcmp(filename, libname)) {
|
||||
for(int j=0; j<ver->vn_cnt; ++j) {
|
||||
if(j==idx)
|
||||
return h->DynStr+aux->vna_name;
|
||||
aux = (Elf32_Vernaux*)((uintptr_t)aux + aux->vna_next);
|
||||
}
|
||||
return NULL; // idx out of bound, return NULL...
|
||||
}
|
||||
ver = ver->vn_next?((Elf32_Verneed*)((uintptr_t)ver + ver->vn_next)):NULL;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int GetNeededVersionForLib(elfheader_t* h, const char* libname, const char* ver)
|
||||
{
|
||||
if(!libname || !ver)
|
||||
return 0;
|
||||
int n = GetNeededVersionCnt(h, libname);
|
||||
if(!n)
|
||||
return 0;
|
||||
for(int i=0; i<n; ++i) {
|
||||
const char* vername = GetNeededVersionString(h, libname, i);
|
||||
if(vername && !strcmp(ver, vername))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Loaded 100 of 1060 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user