mirror of
https://github.com/ptitSeb/box86.git
synced 2026-11-08 02:08:33 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f7630dec30 | ||
|
|
031f41a333 | ||
|
|
d18eb1c9c5 | ||
|
|
a666619de7 | ||
|
|
a6d55175ac | ||
|
|
b33d952b47 | ||
|
|
65fc0f36e7 | ||
|
|
4bb743bde0 | ||
|
|
1b8f92249d | ||
|
|
42838834f6 | ||
|
|
83508fa322 | ||
|
|
044d667b9e | ||
|
|
97274871c8 | ||
|
|
e5fabc828c | ||
|
|
e5601cb09c | ||
|
|
6f87bd8570 | ||
|
|
b393923c6e | ||
|
|
37ab148df6 | ||
|
|
2f977f200b | ||
|
|
e674f1a528 | ||
|
|
fc93d47b14 | ||
|
|
3028d096b9 | ||
|
|
e7313a4df4 | ||
|
|
31af5ec181 | ||
|
|
98222c75c2 | ||
|
|
d0380eccf7 | ||
|
|
f570ee0ea2 | ||
|
|
6ac716b8ba | ||
|
|
e8a080f5c0 | ||
|
|
67237e54f9 | ||
|
|
4acf0f080e | ||
|
|
8e576f3f7d | ||
|
|
037859b007 | ||
|
|
e81e7c7ebd | ||
|
|
a50079b920 | ||
|
|
4a38d8199f | ||
|
|
4dd9337528 | ||
|
|
c6db07039f | ||
|
|
9294b59aae | ||
|
|
490f595d6d | ||
|
|
67af7a0baf | ||
|
|
7da89748bb | ||
|
|
72a82ebece | ||
|
|
12e44a3e62 | ||
|
|
5dd94df9dd | ||
|
|
79051e04b4 | ||
|
|
02a0a77bda | ||
|
|
b3c5115707 | ||
|
|
e069681cfd | ||
|
|
c93356fb1a | ||
|
|
c398c938e1 | ||
|
|
f3c6dc31ac | ||
|
|
06403425f9 | ||
|
|
a9fa9095d5 | ||
|
|
617eacfcd3 | ||
|
|
7ba89639da | ||
|
|
2914ed358e | ||
|
|
72041b6873 | ||
|
|
bf8da23a76 | ||
|
|
f3f3d9cdfe | ||
|
|
05c7d8fec9 | ||
|
|
5201aeffa6 | ||
|
|
2fba190d8b | ||
|
|
9e669ad06b | ||
|
|
7f66be599c | ||
|
|
7d1f429ead | ||
|
|
4e602abfcb | ||
|
|
aad016d418 | ||
|
|
3544428e18 | ||
|
|
459c3ef530 | ||
|
|
a01f5b1f3f | ||
|
|
9183391ab0 | ||
|
|
c22ca077ba | ||
|
|
63c224b073 | ||
|
|
f36567593a | ||
|
|
b2efee99fa | ||
|
|
6510dc9e45 | ||
|
|
213beed360 | ||
|
|
801f374a66 | ||
|
|
7f3eecec4c | ||
|
|
bd92f64df9 | ||
|
|
ab2617c20f | ||
|
|
cd958240df | ||
|
|
4254a2a2f7 | ||
|
|
9735f21f65 | ||
|
|
62343cbb77 | ||
|
|
23eca257f4 | ||
|
|
5a3c17e831 | ||
|
|
de1bb7e438 | ||
|
|
6216d06d0e | ||
|
|
cb03a51d40 | ||
|
|
09a65a622a | ||
|
|
95f6ce1f3e | ||
|
|
7ede988cb1 | ||
|
|
a06e05dc9e | ||
|
|
2a3c6dc55c | ||
|
|
814701324c | ||
|
|
01fea9ce3f | ||
|
|
da5e795858 | ||
|
|
b491241307 | ||
|
|
81f6e87416 | ||
|
|
20a680561a | ||
|
|
a4f2a19505 | ||
|
|
a263283c93 | ||
|
|
ac2cdc65a8 | ||
|
|
c1b7740ac4 | ||
|
|
a1c8868159 | ||
|
|
a157acd185 | ||
|
|
12ec1309bb | ||
|
|
042d55f734 | ||
|
|
67f8c6df42 | ||
|
|
c9d6c72fe0 | ||
|
|
e5fcadae30 | ||
|
|
cb0ee7990a | ||
|
|
0eea4c5913 | ||
|
|
5a8466b0d7 | ||
|
|
372d811f66 | ||
|
|
ff2027846b | ||
|
|
8318eb1a0d | ||
|
|
57c0751793 | ||
|
|
86b00ef7fe | ||
|
|
6e12a556ec | ||
|
|
fba165d121 | ||
|
|
68d77636b0 | ||
|
|
394d46f731 | ||
|
|
702a9f6aa5 | ||
|
|
7ae3813ac5 | ||
|
|
34a933af0b | ||
|
|
4ac5d6df7f | ||
|
|
0260548d9c | ||
|
|
5b64623f50 | ||
|
|
233e472503 | ||
|
|
335512e96a | ||
|
|
d451a3fdd7 | ||
|
|
499de4fd60 | ||
|
|
caf9abc16f | ||
|
|
5dfce69c37 | ||
|
|
8f12829e95 | ||
|
|
15a42f5407 | ||
|
|
c8cdd3f432 | ||
|
|
ac7c72396d | ||
|
|
ce3271f095 | ||
|
|
3ff4b04e52 | ||
|
|
ecd90a41d5 | ||
|
|
87695cf84b | ||
|
|
3bb93e1fd9 | ||
|
|
69279b2233 | ||
|
|
7c811666fe | ||
|
|
9a18dd3718 | ||
|
|
3338d26aaa | ||
|
|
167ea1587e | ||
|
|
7ad6399940 | ||
|
|
71db6b3275 | ||
|
|
00626b9f3e | ||
|
|
d0fa79c9ca | ||
|
|
fc1f75c3f6 | ||
|
|
21b9676093 | ||
|
|
ea2a7204df | ||
|
|
bcdd09a2e6 | ||
|
|
7c394ddeee | ||
|
|
50d7e2d1d7 | ||
|
|
395cecb082 | ||
|
|
c8888915d7 | ||
|
|
38740ce1c9 | ||
|
|
73b893215e | ||
|
|
e93c3f0028 | ||
|
|
be2e35381e | ||
|
|
c79f59c86f | ||
|
|
6f02d5f2c4 | ||
|
|
969bd84f1d | ||
|
|
8865b7bfec | ||
|
|
f60ecc3626 | ||
|
|
824b230bd0 | ||
|
|
71a208334d | ||
|
|
1d75d23772 | ||
|
|
6dd848eac5 | ||
|
|
0c0684bfb7 | ||
|
|
b56337df19 | ||
|
|
0f0512c67c | ||
|
|
b677261976 | ||
|
|
0d0a75319c | ||
|
|
0d283757d5 | ||
|
|
c09f477251 | ||
|
|
1d2bf3cb48 | ||
|
|
7057160b3e | ||
|
|
4244f41c41 | ||
|
|
70f587e305 | ||
|
|
97c5119807 | ||
|
|
77a74d64bf | ||
|
|
0547cec24d | ||
|
|
6837f58a0e | ||
|
|
2518377f83 | ||
|
|
d38e67f539 | ||
|
|
a3d16d3c71 | ||
|
|
14e1363930 | ||
|
|
86eba0aaeb | ||
|
|
10d7e28de3 | ||
|
|
082d08755e | ||
|
|
195bbddd6f | ||
|
|
d68cbfd837 | ||
|
|
851d487015 | ||
|
|
0a3ae03043 | ||
|
|
d56fea52f3 | ||
|
|
1de0f14194 | ||
|
|
d3addae744 | ||
|
|
ee0e831efe | ||
|
|
59559efbb5 | ||
|
|
05e2a9c824 | ||
|
|
9038d94184 | ||
|
|
08a93fc5ae | ||
|
|
6b6075ca48 | ||
|
|
51135b9222 | ||
|
|
922c1770a0 | ||
|
|
b9dc8d79e0 | ||
|
|
7b823e4185 | ||
|
|
fbdb4aa619 | ||
|
|
7716936f77 | ||
|
|
9636fec9da | ||
|
|
e15676e946 | ||
|
|
28fb4ed090 | ||
|
|
8b5474d0a8 | ||
|
|
35e5a48e63 | ||
|
|
470446a104 | ||
|
|
c0cc48d129 | ||
|
|
1134294037 | ||
|
|
f0f49d4f8f | ||
|
|
5f361cbd2d | ||
|
|
20d65d3685 | ||
|
|
51f0780c66 | ||
|
|
b3db9aece7 | ||
|
|
4e22fd1a69 | ||
|
|
d290ccee7f | ||
|
|
4d227ef882 | ||
|
|
6f842cea8b | ||
|
|
36da25e08e | ||
|
|
f586bb2617 | ||
|
|
f3a81ac635 | ||
|
|
266fc0961b | ||
|
|
824ae55d77 | ||
|
|
656bfdc569 | ||
|
|
0f45dd5fee | ||
|
|
82e7faf83d | ||
|
|
0c7310b18d | ||
|
|
2cedd0d2c6 | ||
|
|
b63d087d5c | ||
|
|
bccdb36bd3 | ||
|
|
298ef551ce | ||
|
|
9b23a0a7ab | ||
|
|
5e2546dd0c | ||
|
|
4e9bef301d | ||
|
|
be5d718280 | ||
|
|
3bc1d6d0a1 | ||
|
|
2d23169ea5 | ||
|
|
b486c60d5e | ||
|
|
3246d2bbb6 | ||
|
|
7d7765ce14 | ||
|
|
c1f2750b05 | ||
|
|
bb4d44499c | ||
|
|
195ac3e5b6 | ||
|
|
bc9679cad9 | ||
|
|
a603b58970 | ||
|
|
a740dbf871 | ||
|
|
b10e462e03 | ||
|
|
6f28eb16c6 | ||
|
|
140a41141c | ||
|
|
6f00b50c6e | ||
|
|
a9cb19933a | ||
|
|
cbd8ce408e | ||
|
|
9837888e50 | ||
|
|
42176b6593 | ||
|
|
a320528e64 | ||
|
|
69a9175c67 | ||
|
|
9fdc3196d9 | ||
|
|
0b271fc44f | ||
|
|
0fa2f7b8f1 | ||
|
|
41c775fb44 | ||
|
|
28b06f45fe | ||
|
|
083b3d2a1c | ||
|
|
61866f6dae | ||
|
|
39d7274359 | ||
|
|
a9b4d994eb | ||
|
|
3701dcd0b4 | ||
|
|
efe2588fd9 | ||
|
|
3c17d886cc | ||
|
|
83fe3605f6 | ||
|
|
dec474953b | ||
|
|
f80964d8d7 | ||
|
|
a43687ee30 | ||
|
|
e04233a897 | ||
|
|
93cd9b00bd | ||
|
|
3a592ca9c4 | ||
|
|
555d0d51b0 | ||
|
|
a70f29a8c9 | ||
|
|
dad53a84c8 | ||
|
|
d03b21ee19 | ||
|
|
1a1bf5f76a | ||
|
|
0ebc0f19b8 | ||
|
|
d4cfa94aaa | ||
|
|
383d4c8f9a | ||
|
|
48b187edd1 | ||
|
|
316e18f8c5 | ||
|
|
657595d363 | ||
|
|
9cd9ad16b2 | ||
|
|
7d49d0fc8a | ||
|
|
fa9bdbfd64 | ||
|
|
558dc58a52 | ||
|
|
383b1afe0b | ||
|
|
3d757a2af6 | ||
|
|
2cb20b665d | ||
|
|
eadb36bcdd | ||
|
|
a3bbaeb11b | ||
|
|
816ee7e23b | ||
|
|
2a10da129e | ||
|
|
9784c3bf2d | ||
|
|
f64a7e2c5b | ||
|
|
f01359a62e | ||
|
|
729f392148 | ||
|
|
e48802c898 | ||
|
|
34ed9f03e1 | ||
|
|
4990b6db94 | ||
|
|
ecf50c8181 | ||
|
|
927159011c | ||
|
|
640db5e667 | ||
|
|
509f09dfbc | ||
|
|
4f42ae0d81 | ||
|
|
1b4391ac23 | ||
|
|
5cb6894657 | ||
|
|
be66c8bffa | ||
|
|
5f71bcfe9a | ||
|
|
95d786e9a8 | ||
|
|
8b5e977868 | ||
|
|
49a631b475 | ||
|
|
8b98a68d1a | ||
|
|
c03e46814b | ||
|
|
7efac81f8b | ||
|
|
58e98e9580 | ||
|
|
56c211fbeb | ||
|
|
2aa2e53fef | ||
|
|
3993c88fbb | ||
|
|
f706e7eecc | ||
|
|
549de25a49 | ||
|
|
217b05fb80 | ||
|
|
e1b9d40ca6 | ||
|
|
0eeba809f2 | ||
|
|
4a0df1042d | ||
|
|
e7a4274511 | ||
|
|
b3def68a4f | ||
|
|
3c67de08a3 | ||
|
|
cec67ef3e3 | ||
|
|
881501b278 | ||
|
|
d09a949755 | ||
|
|
bf6fa0f335 | ||
|
|
9dcfa322a5 | ||
|
|
a1c21ce05f | ||
|
|
22be56179d | ||
|
|
24da6fcb3b | ||
|
|
8078b27172 | ||
|
|
89d1254106 | ||
|
|
497f66f5dc | ||
|
|
a321d54142 | ||
|
|
8495b461b8 | ||
|
|
35d6354898 | ||
|
|
a2b4af137c | ||
|
|
756d1c12fd | ||
|
|
63f2e52edb | ||
|
|
fd704eca00 | ||
|
|
8c233f1861 | ||
|
|
669bb00590 | ||
|
|
815fd918cb | ||
|
|
4249adbe4e | ||
|
|
1aec17da4d | ||
|
|
3680a3092e | ||
|
|
b11a269867 | ||
|
|
cccbf75878 | ||
|
|
5ce309e64b | ||
|
|
4b48a43413 | ||
|
|
a05df24c8b | ||
|
|
4f599b521a | ||
|
|
44cf2fc4fb | ||
|
|
0ca9f70796 | ||
|
|
83cb2dbc4d | ||
|
|
b09937ad3d | ||
|
|
c88d5d462c | ||
|
|
78c971cb87 | ||
|
|
1bafddcfe2 | ||
|
|
047b2071f5 | ||
|
|
8aca039ca6 | ||
|
|
db8c6b0c9e | ||
|
|
dbc6aa83f3 | ||
|
|
08472aa68b | ||
|
|
3010068660 | ||
|
|
5e2faff01d | ||
|
|
598338809f | ||
|
|
4778760622 | ||
|
|
3a23cc42f6 | ||
|
|
e23283e794 | ||
|
|
4d730a31c4 | ||
|
|
216b6407f3 | ||
|
|
e95988f402 | ||
|
|
1ce3731d7d | ||
|
|
7420d3c8de | ||
|
|
f1edcc06d3 | ||
|
|
ce5c3db346 | ||
|
|
cc0b7b3719 | ||
|
|
7854fa2e18 | ||
|
|
1b7bc825d5 | ||
|
|
e65f58acb2 | ||
|
|
18fe17dc2d | ||
|
|
8098461e0f | ||
|
|
bf8e9f9242 | ||
|
|
4838067440 | ||
|
|
53a080e32e | ||
|
|
3ac41770b8 | ||
|
|
6fe51fd7f4 | ||
|
|
a6cbe15b5e | ||
|
|
3313eba45c | ||
|
|
b01150f707 | ||
|
|
4502948f89 | ||
|
|
8cb2ffbd2e | ||
|
|
be80cb03d6 | ||
|
|
13d6e96cdc | ||
|
|
9f280b1f9c | ||
|
|
786dfa6700 | ||
|
|
e260aee2e6 | ||
|
|
504c27c934 | ||
|
|
c4ba481561 | ||
|
|
841770aed1 | ||
|
|
1a4643f3a2 | ||
|
|
e89702d99d | ||
|
|
250e3820df | ||
|
|
8b2a509a32 | ||
|
|
6db92c56b9 | ||
|
|
e4914a2139 | ||
|
|
704c4b36ab | ||
|
|
b9d61108bf | ||
|
|
e92d2f737b | ||
|
|
6ec36072c4 | ||
|
|
ab18d4d23a | ||
|
|
1e6893a9d9 | ||
|
|
01bcc957e8 | ||
|
|
3c989cfa04 | ||
|
|
bde29ef155 | ||
|
|
cee4cd26e0 | ||
|
|
f774b88211 | ||
|
|
251f9b7338 | ||
|
|
dd5fc10a95 | ||
|
|
5e84efc542 | ||
|
|
b29fd4abbd | ||
|
|
1c6f2254f3 | ||
|
|
73685273f4 | ||
|
|
76d070777f | ||
|
|
42d18f7302 | ||
|
|
963a7a527a | ||
|
|
df61ed3048 | ||
|
|
2a8e6061a2 | ||
|
|
96c4fe7057 | ||
|
|
124df9ae83 | ||
|
|
62b2eecf6e | ||
|
|
9fb6b7bbd9 | ||
|
|
0ac7929230 | ||
|
|
d16e8f1c51 | ||
|
|
4b59f04930 | ||
|
|
7a375136cc | ||
|
|
62a328af45 | ||
|
|
aafe35dca7 | ||
|
|
c73b728255 | ||
|
|
1186072e48 | ||
|
|
141de19804 | ||
|
|
97d71dfe09 | ||
|
|
f05b4fa7ff | ||
|
|
2f36ec82f9 | ||
|
|
c386a0a356 | ||
|
|
4ba1f972b5 | ||
|
|
525eb10854 | ||
|
|
7176b08882 | ||
|
|
a6f4248502 | ||
|
|
f0da6dd64f | ||
|
|
af3c9042c3 | ||
|
|
d8aa65bc17 | ||
|
|
da6ab3f752 | ||
|
|
3cdf7fe742 | ||
|
|
cb54d7e343 | ||
|
|
60611e54f3 | ||
|
|
a4a78681ef | ||
|
|
4d85147077 | ||
|
|
857048f47c | ||
|
|
6084102d20 | ||
|
|
2dc1fcc875 | ||
|
|
584479c10d | ||
|
|
3430550dac | ||
|
|
81f5bc79aa | ||
|
|
e20ccb7991 | ||
|
|
5cf4af83b0 | ||
|
|
e5cb34d1f8 | ||
|
|
91c46f99a0 | ||
|
|
dbdcaf8962 | ||
|
|
230d6246c6 | ||
|
|
066e5f966a | ||
|
|
ff615cba03 | ||
|
|
631fa0f536 | ||
|
|
ce2eb76703 | ||
|
|
9422039e09 | ||
|
|
0f13eb8611 | ||
|
|
196394f666 | ||
|
|
9b2f7029df | ||
|
|
a2e6b57c35 | ||
|
|
e5fdb4ba85 | ||
|
|
0c83522296 | ||
|
|
f59e30442a | ||
|
|
b67b750009 | ||
|
|
61f2a43628 | ||
|
|
769545ccd7 | ||
|
|
c0b9272b82 | ||
|
|
d5e5cbb393 | ||
|
|
d8251ec441 | ||
|
|
0a04ef44d4 | ||
|
|
79ada49fdc | ||
|
|
1bf134c3ef | ||
|
|
38098290b7 | ||
|
|
b66c95d920 | ||
|
|
25ae0f9311 | ||
|
|
f63799ecbb | ||
|
|
f2de080c68 | ||
|
|
4ceaa7bd4b | ||
|
|
5753983f41 | ||
|
|
58768ca886 | ||
|
|
d3d740c38f | ||
|
|
27f99bd3c0 | ||
|
|
230fa96d2b | ||
|
|
1e7f5692ce | ||
|
|
af884e427d | ||
|
|
00b2002855 | ||
|
|
e5d20ea8ae | ||
|
|
3b4ca235d5 | ||
|
|
8633aca6fa | ||
|
|
85dde4b9d0 | ||
|
|
43e981579f | ||
|
|
f12706599e | ||
|
|
650668eaf7 | ||
|
|
6093589e41 | ||
|
|
ce777c9393 | ||
|
|
983523c2f6 | ||
|
|
8f5843e0fe | ||
|
|
98b0602ae5 | ||
|
|
0286e8362e | ||
|
|
bcfc464f24 | ||
|
|
7a9e9df3c0 | ||
|
|
829bf941f4 | ||
|
|
3e42161c35 | ||
|
|
9cdaa5e028 | ||
|
|
34ef7b9b79 | ||
|
|
201677899b | ||
|
|
fd563c5b4b | ||
|
|
d5b5031f5c | ||
|
|
08f2fcd1b9 | ||
|
|
f7da6bc070 | ||
|
|
1414fed3b2 | ||
|
|
13ff5c80be | ||
|
|
782dd645c3 | ||
|
|
020bcd46c2 | ||
|
|
fefb01f930 | ||
|
|
6489a2ca3b | ||
|
|
cbe4ec30d1 | ||
|
|
38a9b04ce0 | ||
|
|
7de59621c4 | ||
|
|
e9560dd916 | ||
|
|
91fec006ae | ||
|
|
82af74c459 | ||
|
|
32dc46efac | ||
|
|
020b94794b | ||
|
|
bb59ef692e | ||
|
|
8280d4628d | ||
|
|
91c6a71353 | ||
|
|
fa9e8223b9 | ||
|
|
7057ce7a2c | ||
|
|
b98febce24 | ||
|
|
11758cfa90 | ||
|
|
a37928110d | ||
|
|
a3c7674676 | ||
|
|
ed68b17bac | ||
|
|
aa86b8ecf4 | ||
|
|
e0c5630ed7 | ||
|
|
c4b4107f57 | ||
|
|
d198f6c64a | ||
|
|
fd3812c27e | ||
|
|
ddbffd874b | ||
|
|
bc1b5bed0b | ||
|
|
f7019e0ff8 | ||
|
|
e47f88f4f3 | ||
|
|
baf750b89a | ||
|
|
bea256ddc6 | ||
|
|
e7f841b71e | ||
|
|
1df10d7a48 | ||
|
|
53c4a0d418 | ||
|
|
883f1990c6 | ||
|
|
c2efed56e0 | ||
|
|
37814194ae | ||
|
|
03cc86c6d1 | ||
|
|
206f5d3aa8 | ||
|
|
d5c71f3dcc | ||
|
|
1ed35d06c7 | ||
|
|
4456ab2ab5 | ||
|
|
645297de61 | ||
|
|
71dbfda219 | ||
|
|
c8977e68d0 | ||
|
|
9b1bfb17b0 | ||
|
|
95858b46b0 | ||
|
|
d7ca13e7f7 | ||
|
|
a17dfe8ed6 | ||
|
|
1d9eb8fa17 | ||
|
|
6d8e64a213 | ||
|
|
c5859a0d92 | ||
|
|
058b199606 | ||
|
|
5b58985fdf | ||
|
|
b9e1192d69 | ||
|
|
1d0a575773 | ||
|
|
72e3e36f1b | ||
|
|
bd2271de86 | ||
|
|
ffa2aa6f1c | ||
|
|
c0d35aa6e7 | ||
|
|
11c1396d83 | ||
|
|
41e6ba1030 | ||
|
|
e92e9043fa | ||
|
|
c53ab30b2e | ||
|
|
c763ca269a | ||
|
|
bf4c05c41c | ||
|
|
9b9130ed57 | ||
|
|
5fde277748 | ||
|
|
7757666a0b | ||
|
|
4bc52873f7 | ||
|
|
a5a38203ae | ||
|
|
1209862996 | ||
|
|
4f0bb1010d | ||
|
|
050b974051 | ||
|
|
88fb7efec3 | ||
|
|
a91c562dcf | ||
|
|
f1a136c9b4 | ||
|
|
57583b39e7 | ||
|
|
3467ea2476 | ||
|
|
0e6daf412d | ||
|
|
8468c5318d | ||
|
|
853f4865ce | ||
|
|
0742c694b0 | ||
|
|
247622a6db | ||
|
|
cbd4b4f73a | ||
|
|
3782d7f4df | ||
|
|
bc13894b31 | ||
|
|
d6ff293d7f | ||
|
|
9e2ba671b8 | ||
|
|
fb56c5f422 | ||
|
|
a45d6bd79b | ||
|
|
28a26db054 | ||
|
|
95782e7311 | ||
|
|
5f6221de7f | ||
|
|
b42ac3eb11 | ||
|
|
2964727959 | ||
|
|
fca7808b55 | ||
|
|
07c98d30ad | ||
|
|
a7c95a783e | ||
|
|
e84ebce421 | ||
|
|
0df765bbbd | ||
|
|
2af2fbfe6d | ||
|
|
96f5f92b09 | ||
|
|
dedd7f4827 | ||
|
|
28a066a7c9 | ||
|
|
6377884c4a | ||
|
|
41cc61e4c7 | ||
|
|
73e13baa84 | ||
|
|
403707bb5b | ||
|
|
873bdd793a | ||
|
|
edbd6cdfa5 | ||
|
|
e7a9679a20 | ||
|
|
b9d09acf92 | ||
|
|
7a02b1720e | ||
|
|
3c88e8aac0 | ||
|
|
df4e93973b | ||
|
|
c3dbe47f3c | ||
|
|
af91d80c94 | ||
|
|
a133621934 | ||
|
|
329bddc4f6 | ||
|
|
31785d6fbe | ||
|
|
c7bf006b49 | ||
|
|
3fc1458cc2 | ||
|
|
53be7dad84 | ||
|
|
7507a0f20f | ||
|
|
32a6711898 | ||
|
|
223c6513ba | ||
|
|
d395df1f37 | ||
|
|
f5a7d96a77 | ||
|
|
81ae020273 | ||
|
|
57024db6e6 | ||
|
|
e507b964a1 | ||
|
|
d2bff48e88 | ||
|
|
ba364f629f | ||
|
|
ae723c42fe | ||
|
|
8cf46bb5a8 | ||
|
|
ffadb9df59 | ||
|
|
87c55d434c | ||
|
|
ae513fd908 | ||
|
|
4683f2194d | ||
|
|
823174af3e | ||
|
|
77c205cd78 | ||
|
|
ea047b1573 | ||
|
|
c4b9c107af | ||
|
|
5bb580a9e0 | ||
|
|
b82e0f124a | ||
|
|
4e5512ecb3 | ||
|
|
48dffd1d6e | ||
|
|
a0820fcd2d | ||
|
|
0819240675 | ||
|
|
1ae7e8f998 | ||
|
|
bfbf7c2d10 | ||
|
|
8fb4d06858 | ||
|
|
0bec217d1e | ||
|
|
a0a7b8b758 | ||
|
|
5e344b7db6 | ||
|
|
a954773ba6 | ||
|
|
ee27dfd927 | ||
|
|
44995a791f | ||
|
|
df69100282 | ||
|
|
c6b6247812 | ||
|
|
466b9e88b0 | ||
|
|
1c51f99ed4 | ||
|
|
2a68db14dc | ||
|
|
b5bbd3e6d9 | ||
|
|
3ccdce5df4 | ||
|
|
6c9195bae8 | ||
|
|
ed324369a0 | ||
|
|
37efbe3f4b | ||
|
|
0e2f4cd25a | ||
|
|
d773410d6b | ||
|
|
1db72cb2fe | ||
|
|
cd952734e5 | ||
|
|
6b134cc102 | ||
|
|
55c399bab6 | ||
|
|
60a3214375 | ||
|
|
f992b50444 | ||
|
|
65a62df0b1 | ||
|
|
a154752c1a | ||
|
|
9ee6dcd27b | ||
|
|
fc5f512d24 | ||
|
|
089ed989f2 | ||
|
|
b26c2253af | ||
|
|
647429d822 | ||
|
|
8c1368a79f | ||
|
|
cf37e29f96 | ||
|
|
ce9a991a28 | ||
|
|
4faf21a899 | ||
|
|
8f2c02ec2a | ||
|
|
872bd0042c | ||
|
|
c8c2d8de61 | ||
|
|
30e8ebccb7 | ||
|
|
7b0efb110f | ||
|
|
e553d93b17 | ||
|
|
41ba98dc84 | ||
|
|
1dd53d4a03 | ||
|
|
00b1132fcf | ||
|
|
4d1fa73ac7 | ||
|
|
5493e5c35c | ||
|
|
e9c5272435 | ||
|
|
807ad56a39 | ||
|
|
472aa40b53 | ||
|
|
64e2b3e6db | ||
|
|
5dc6f268c7 | ||
|
|
931ef0c0c1 | ||
|
|
290adf2434 | ||
|
|
554c1c36bc | ||
|
|
0e5994a0f9 | ||
|
|
e3fb2b63c9 | ||
|
|
82c67783c1 | ||
|
|
9799bbfedb | ||
|
|
e8a1196674 | ||
|
|
48a4e81214 | ||
|
|
bf441d6918 | ||
|
|
aab4089986 | ||
|
|
c7cf40d55e | ||
|
|
b977e3063f | ||
|
|
e5181e75be | ||
|
|
58c903467e | ||
|
|
a615e0b627 | ||
|
|
b6c729f2d3 | ||
|
|
ff437ce8cf | ||
|
|
66a986c76f | ||
|
|
410729e91a | ||
|
|
916f758e8c | ||
|
|
8affc5529e | ||
|
|
efa07f3ad5 | ||
|
|
9a7daf4cd4 | ||
|
|
c5068ea1d1 | ||
|
|
0db1306563 | ||
|
|
6b42fd6a24 | ||
|
|
d418e67c77 | ||
|
|
26bfef4161 | ||
|
|
c64cffa352 | ||
|
|
863019f113 | ||
|
|
c60581d7d3 | ||
|
|
a1abae4717 | ||
|
|
f970138c5f | ||
|
|
560e88f379 | ||
|
|
18ff3c0b2c | ||
|
|
b92f20fa62 | ||
|
|
2d22e18f5a | ||
|
|
82fce8520c | ||
|
|
21ad3afce8 | ||
|
|
5b680d4925 | ||
|
|
cabcf2cc39 | ||
|
|
9cc5f50f95 | ||
|
|
2097af4172 | ||
|
|
141595e2d5 | ||
|
|
461f8d0e84 | ||
|
|
1775f4a47e | ||
|
|
48a271105d | ||
|
|
01bac8e3c4 | ||
|
|
9f6f94d504 | ||
|
|
cd8ceda3ee | ||
|
|
cd6cb90576 | ||
|
|
b69ed41ea6 | ||
|
|
0d66d57806 | ||
|
|
5762d865bb | ||
|
|
bac874ce38 | ||
|
|
fdf0aaacf1 | ||
|
|
f810e7a5f3 | ||
|
|
13fa2c74ef | ||
|
|
f24bbd1e5f | ||
|
|
ab5f21c34d | ||
|
|
ad6ee87e4f | ||
|
|
b9478291bc | ||
|
|
59228657e5 | ||
|
|
3db1ab2b3e | ||
|
|
8d75b56a2c | ||
|
|
1499ef31a9 | ||
|
|
cdc1e4e18e | ||
|
|
6f5102689f | ||
|
|
decc1af534 | ||
|
|
a912c34b9d | ||
|
|
0fc22270b7 | ||
|
|
0ff9da5d4e | ||
|
|
887ef22002 | ||
|
|
c9adb6bf97 | ||
|
|
33f2c63278 | ||
|
|
950e6d99d3 | ||
|
|
d4ab117327 | ||
|
|
419f2a5707 | ||
|
|
0fac701577 | ||
|
|
c3ea1b17ac | ||
|
|
8ad4bd5178 | ||
|
|
c7896186b0 | ||
|
|
43bd57cf4c | ||
|
|
199d9503b3 | ||
|
|
1d2347f742 | ||
|
|
f0c55d2e45 | ||
|
|
60a18f7e2d | ||
|
|
369ffeb64a | ||
|
|
3f624ab813 | ||
|
|
590abc18f9 | ||
|
|
48f4ccce5d | ||
|
|
28787055e0 | ||
|
|
ba42e0e3e4 | ||
|
|
6aabb24b34 | ||
|
|
5ab5e07775 | ||
|
|
f78ea33be6 | ||
|
|
5fbc9b637e | ||
|
|
a0e6a3edb9 | ||
|
|
29c594ad6b | ||
|
|
ed52a461db | ||
|
|
448313858e | ||
|
|
965cc02452 | ||
|
|
2dc3a02623 | ||
|
|
737df4b330 | ||
|
|
c8f66e72b9 | ||
|
|
f9b121034f | ||
|
|
305002c295 | ||
|
|
3ae728ddc2 | ||
|
|
f0b7b36aea | ||
|
|
dbeb70c08f | ||
|
|
7a8e911cf0 | ||
|
|
9a560c2e95 | ||
|
|
befb826287 | ||
|
|
9613686764 | ||
|
|
d4a2c50164 | ||
|
|
e1b83d432a | ||
|
|
fc2ef2b5f1 | ||
|
|
24243ec0e4 | ||
|
|
65ce48c2a1 | ||
|
|
063968bd3a | ||
|
|
0e9fea45fd | ||
|
|
ba10fdc2b7 | ||
|
|
4a9ced0854 | ||
|
|
f1ef36a0e4 | ||
|
|
857b68a22c | ||
|
|
acfd95c0e0 | ||
|
|
a57e4871a3 | ||
|
|
b5754732d9 | ||
|
|
d29f7d6ba8 | ||
|
|
bc928bb412 | ||
|
|
14de9efaff | ||
|
|
2254ba15d3 | ||
|
|
9318f7f596 | ||
|
|
5d1fb26f15 | ||
|
|
e33df891a4 | ||
|
|
243d185a44 | ||
|
|
7729dfa6c0 | ||
|
|
120eb3271d | ||
|
|
7a9f4c2e50 | ||
|
|
eb2f60b8f6 | ||
|
|
e63053ba48 | ||
|
|
bab12a3af3 | ||
|
|
86f36deee7 | ||
|
|
15724a34f6 | ||
|
|
33063f11b3 | ||
|
|
415bcd544f | ||
|
|
5409e8030b | ||
|
|
16aba6c8bb | ||
|
|
026b2593bb | ||
|
|
3e8e0ef0f3 | ||
|
|
a626c79b8b | ||
|
|
dc6dba42c4 | ||
|
|
b98f7a8459 | ||
|
|
4845ab0d40 | ||
|
|
831fead5ed | ||
|
|
658e2c4200 | ||
|
|
83e4df1c79 | ||
|
|
125f204d58 | ||
|
|
94a75a8e71 | ||
|
|
52412e8a23 | ||
|
|
f931db1c8d | ||
|
|
85363c677b | ||
|
|
7634447fda | ||
|
|
660d1e9ccd | ||
|
|
e73d0157df | ||
|
|
92ebb07369 | ||
|
|
ad19ca0f44 | ||
|
|
aacf835609 | ||
|
|
29690127d2 | ||
|
|
5da1de32f0 | ||
|
|
98035453b8 | ||
|
|
2ef3c925db | ||
|
|
e671b8acfa | ||
|
|
58626e9c0b | ||
|
|
650ede22e0 | ||
|
|
a2648ce970 | ||
|
|
fdc587b964 | ||
|
|
537d447a28 | ||
|
|
b8eb8d5b4e | ||
|
|
823dd8f6cc | ||
|
|
80ce6c091c | ||
|
|
ff740f4983 | ||
|
|
5e16c59b72 | ||
|
|
4c0c6a4348 | ||
|
|
587f38be50 | ||
|
|
6e2f5b09f8 | ||
|
|
b238ab7c64 | ||
|
|
6568138155 | ||
|
|
c167acd84c | ||
|
|
cbd0d9b798 | ||
|
|
51902d0ec5 | ||
|
|
1669f5d261 | ||
|
|
1b5500f7dd | ||
|
|
3f273d4362 | ||
|
|
f540c20cde | ||
|
|
042c4f5935 | ||
|
|
134f63ef59 | ||
|
|
731f12e114 | ||
|
|
2eea0b7f7d | ||
|
|
1734916c7a | ||
|
|
c83f1a2f3b | ||
|
|
3497a9e081 | ||
|
|
cb133cef99 | ||
|
|
db2e6a23b8 | ||
|
|
469e8318ac | ||
|
|
91bf052e7c | ||
|
|
f42c6ee7a3 | ||
|
|
395f734c46 | ||
|
|
a990273258 | ||
|
|
d05528ec5c | ||
|
|
3770cc3a5f | ||
|
|
143b5e8ec7 | ||
|
|
dfaa3d6e8a | ||
|
|
9df95f96c2 | ||
|
|
926f2f3dcd | ||
|
|
d275fd3dba | ||
|
|
c986f8749d | ||
|
|
01f055ef31 | ||
|
|
0b2ba32219 | ||
|
|
79f2eb8f1e | ||
|
|
5857eeb532 | ||
|
|
714018b715 | ||
|
|
bf2c2d4f3b | ||
|
|
80a4578bc3 | ||
|
|
1e918f3226 | ||
|
|
51552f232e | ||
|
|
9ebc0463bf | ||
|
|
8b6ce21884 | ||
|
|
3132398bae | ||
|
|
ff8f50cbf8 | ||
|
|
15b0580133 | ||
|
|
eced4f290a | ||
|
|
8b6e6cfbe9 | ||
|
|
3d46df6922 | ||
|
|
71604cf176 | ||
|
|
1ad7a4f6ca | ||
|
|
03be3e23d4 | ||
|
|
3d7ae93e6c | ||
|
|
dc028adc56 | ||
|
|
fc7740a4ce | ||
|
|
2b8b6ee5cc | ||
|
|
081388d4dc | ||
|
|
5259e8f122 | ||
|
|
39284057c8 | ||
|
|
f9a072ada5 | ||
|
|
bff5bdd5dc | ||
|
|
3f9d60238c | ||
|
|
ae457d72c4 | ||
|
|
bd0e7b7f3f | ||
|
|
a955c6ea7e | ||
|
|
ce647c4f90 | ||
|
|
92ea53a218 | ||
|
|
b7a7dce80d | ||
|
|
b6b1667365 | ||
|
|
def9166e43 | ||
|
|
509fc59ede | ||
|
|
c5bfa7db40 | ||
|
|
ca383864bb | ||
|
|
4d6ea9d8f9 | ||
|
|
3859dcea09 | ||
|
|
1c6f7071bf | ||
|
|
bb0714b624 | ||
|
|
992c530ed5 | ||
|
|
9376d776de | ||
|
|
359e5a28c6 | ||
|
|
4262beb545 | ||
|
|
20e3fb7d70 | ||
|
|
cfc08dfea9 | ||
|
|
c288ac6514 | ||
|
|
326c983bf1 | ||
|
|
073ebaadfc | ||
|
|
250145530f | ||
|
|
3eacb55dbc | ||
|
|
b1958a81a3 | ||
|
|
e04324df79 | ||
|
|
d048d4964e | ||
|
|
53b56ba123 | ||
|
|
36dc893334 | ||
|
|
470db114bd | ||
|
|
8e02b0f75a | ||
|
|
2950c0b8dc | ||
|
|
d03f420b92 | ||
|
|
f005e269c9 | ||
|
|
d5cd2b009b | ||
|
|
dd8c5a3b81 | ||
|
|
3f0a82503f | ||
|
|
c82927f841 | ||
|
|
213f5bf616 | ||
|
|
87f5f26ecb | ||
|
|
ec49241cef | ||
|
|
14f1a8f17b | ||
|
|
aee17dc28a | ||
|
|
5828e5a5a7 | ||
|
|
6d13315fdb | ||
|
|
75f224ccf8 | ||
|
|
85646182e0 | ||
|
|
17654cfe24 | ||
|
|
5286f42314 | ||
|
|
ae9bb4e1c5 | ||
|
|
77f041505b | ||
|
|
6d5487da24 | ||
|
|
e4738ab016 | ||
|
|
10d830aba1 | ||
|
|
62e97c8a3e | ||
|
|
83e9d4606a | ||
|
|
d496fd8977 | ||
|
|
f008a397d0 | ||
|
|
d7c636cf23 | ||
|
|
2094122541 | ||
|
|
5b0769fba3 | ||
|
|
5323837c32 | ||
|
|
ade0289e63 | ||
|
|
156e45d5a2 | ||
|
|
2d47c5502d | ||
|
|
2c963e4e63 | ||
|
|
fd890a2eba | ||
|
|
04df667d0c | ||
|
|
1853a0f11c | ||
|
|
f53f22f53b | ||
|
|
08d3239129 | ||
|
|
d4b9134bee | ||
|
|
fce200380c | ||
|
|
a6c82cce5a | ||
|
|
09a1fa0dac | ||
|
|
7b2064fcd8 | ||
|
|
d0f19c9378 | ||
|
|
0c48bc2293 | ||
|
|
e1efc1682b | ||
|
|
fc1dac64d3 | ||
|
|
b1c1558aa3 | ||
|
|
caee60d13b | ||
|
|
26405c2da6 | ||
|
|
78cb58b146 | ||
|
|
3a4c2e5b65 | ||
|
|
0b08c51036 | ||
|
|
2837f63312 | ||
|
|
2119fd8dd3 | ||
|
|
6e2a7cd0ab | ||
|
|
a1b997966e | ||
|
|
11c374a4b3 | ||
|
|
577c5ac45b | ||
|
|
3110ed8df7 | ||
|
|
421d33772b | ||
|
|
c7366c2e5c | ||
|
|
bb59140a06 | ||
|
|
0a89b2777a | ||
|
|
4ae0ef5f0d | ||
|
|
475a3374d9 | ||
|
|
13a0943ce8 | ||
|
|
11de135dbe | ||
|
|
55a4d96814 | ||
|
|
f3fdd52c2a | ||
|
|
04fcdbb989 | ||
|
|
b6882e4c8b | ||
|
|
c18ae816e9 | ||
|
|
fefc0383b8 | ||
|
|
453c26d648 | ||
|
|
eb32c93750 | ||
|
|
d9907f1e88 | ||
|
|
29706f815b | ||
|
|
777d20651e | ||
|
|
c62448e866 | ||
|
|
eabe18ba6f | ||
|
|
2bbc33bf0d | ||
|
|
36f1c54dbf | ||
|
|
0ce8b2321c | ||
|
|
f5668cce2c | ||
|
|
c75d658238 | ||
|
|
718ceacee6 | ||
|
|
1444cf979d | ||
|
|
de4ae72ed7 | ||
|
|
57fa84f9e7 | ||
|
|
7df5001472 | ||
|
|
f1e049e8be | ||
|
|
f664797a36 | ||
|
|
7bb7c5747a | ||
|
|
aad4c91e01 | ||
|
|
9dc1f02d06 | ||
|
|
59be622226 | ||
|
|
30cecc7694 | ||
|
|
18237cbfd9 | ||
|
|
b4a98f67ee | ||
|
|
2fef0f9652 | ||
|
|
48c3f927eb | ||
|
|
b6e9acc3c3 | ||
|
|
0b74e623d9 | ||
|
|
88b2d7933b | ||
|
|
1b97a18d17 | ||
|
|
2279bc7187 | ||
|
|
d1903570de | ||
|
|
92c947e419 | ||
|
|
34061ad32c | ||
|
|
a1e639dce5 | ||
|
|
a29da7ee6a | ||
|
|
1e8291c3ed | ||
|
|
d7d3bcc868 | ||
|
|
a9c45098c7 | ||
|
|
10b1dbefd2 | ||
|
|
0df5881023 | ||
|
|
93c945b2c8 | ||
|
|
8782441b86 | ||
|
|
ab8edf9bec | ||
|
|
2e5b11af1d | ||
|
|
2e6ea6018e | ||
|
|
f84871cf01 | ||
|
|
9648517b15 | ||
|
|
008f612c08 | ||
|
|
9bd2a19901 | ||
|
|
ce8c82042a | ||
|
|
1310eba02c | ||
|
|
2e2b4d4e08 | ||
|
|
41bbdca01d | ||
|
|
0acd350d7f | ||
|
|
e7216d42aa | ||
|
|
3b33059900 | ||
|
|
4c671d9d85 | ||
|
|
5004a5f482 | ||
|
|
daab23978b | ||
|
|
6e0d8e000b | ||
|
|
5dc5aeabb8 | ||
|
|
faf52f39b5 | ||
|
|
5f173bf10a | ||
|
|
14b13b7074 | ||
|
|
a84d4f4fa0 | ||
|
|
f0b49dfce4 | ||
|
|
a199873854 | ||
|
|
0257cbaa14 | ||
|
|
73cb0c9ee5 | ||
|
|
f754b6269e | ||
|
|
22c0ae5a49 | ||
|
|
1b23f36ecd | ||
|
|
35c60d2a11 | ||
|
|
828fb05d52 | ||
|
|
fb983c53bf | ||
|
|
08ef7aa5a0 | ||
|
|
9ac85482ca | ||
|
|
189915f200 | ||
|
|
d68a9cd996 | ||
|
|
1a8fd4a979 | ||
|
|
b45c92cf98 | ||
|
|
11b3d62d16 | ||
|
|
a46ad1e66e | ||
|
|
970135e098 | ||
|
|
ccec11c059 | ||
|
|
40412a5257 | ||
|
|
dc07f8666b | ||
|
|
d622dba733 | ||
|
|
1dd9c2dddf | ||
|
|
979f49a8b9 | ||
|
|
9a11ee556c | ||
|
|
192b9b8f60 | ||
|
|
d6485f88fd | ||
|
|
bbce797c14 | ||
|
|
e978d42834 | ||
|
|
2d9b5d0f20 | ||
|
|
37d2c4ec22 | ||
|
|
4b60120754 | ||
|
|
02ff4614a2 | ||
|
|
a0b15aa6c2 | ||
|
|
ca21c41bfc | ||
|
|
0591033231 | ||
|
|
c984423c4d | ||
|
|
805397b530 | ||
|
|
394c1bd571 | ||
|
|
c1a016baad | ||
|
|
c667bbcaa6 | ||
|
|
38e7165433 | ||
|
|
e02a8a63e4 | ||
|
|
420d6e6648 | ||
|
|
a78380a3b4 | ||
|
|
fe7c2bd388 | ||
|
|
930f7ce973 | ||
|
|
9f0ad317ad | ||
|
|
1a95ca5065 | ||
|
|
5b912fd9b3 | ||
|
|
ec1ddbd646 | ||
|
|
8e4fbe58b5 | ||
|
|
544e8fb582 | ||
|
|
bd7c19520d | ||
|
|
74817f6959 | ||
|
|
6d6d548284 | ||
|
|
4104d6c128 | ||
|
|
312e9c7634 | ||
|
|
a427be2390 | ||
|
|
33215027e6 | ||
|
|
9ed1be3632 | ||
|
|
23d4759e16 | ||
|
|
239acd0733 | ||
|
|
cdd830c256 | ||
|
|
f5f5a7533f | ||
|
|
a87c542d6b | ||
|
|
2470905bf8 | ||
|
|
d1d67b4cf5 | ||
|
|
c010c899b7 | ||
|
|
57f1bb36ea | ||
|
|
8637c3a8cf | ||
|
|
e431c5f4e1 | ||
|
|
84e175b265 | ||
|
|
34facb1bd4 | ||
|
|
710d8b311c | ||
|
|
efa5701654 | ||
|
|
2b3ececc3f | ||
|
|
eec37508f4 | ||
|
|
dd7f508a91 | ||
|
|
d05db1c8d4 | ||
|
|
ef534db878 | ||
|
|
48b4b3d4ae | ||
|
|
a15c4771c8 | ||
|
|
fc929f622b | ||
|
|
707be246e9 | ||
|
|
3eee490042 | ||
|
|
9d3d250545 | ||
|
|
e912e0a98a | ||
|
|
20ca0566be | ||
|
|
d092d2e6e9 | ||
|
|
180e49847b | ||
|
|
62c055f7ac | ||
|
|
3a4753ef70 | ||
|
|
43d02c8f3e | ||
|
|
b7d6955b43 | ||
|
|
2941140df6 | ||
|
|
47bd2db9c3 | ||
|
|
e7460dc878 | ||
|
|
89504ca289 | ||
|
|
652b2d9d86 | ||
|
|
c46dff15dc | ||
|
|
b121064454 | ||
|
|
ce952b9ab9 | ||
|
|
3567d9eccf | ||
|
|
34e24f6fa4 | ||
|
|
4084c5a448 | ||
|
|
e0e426fe53 | ||
|
|
cede4198fa | ||
|
|
249d008272 | ||
|
|
9ba8db83bd | ||
|
|
de3202630d | ||
|
|
db5a19ec82 | ||
|
|
5a140abd05 | ||
|
|
c6b6e9e78f | ||
|
|
f35975e748 | ||
|
|
0056aaf687 | ||
|
|
bf6ccfbf1e | ||
|
|
1467c8f48f | ||
|
|
c334e3b4da | ||
|
|
c7b6dc0762 | ||
|
|
03045e2a78 | ||
|
|
628bbc5810 | ||
|
|
e2ddaa67fa | ||
|
|
dba3675688 | ||
|
|
54073bb12f | ||
|
|
d512a56bb9 | ||
|
|
e2e63d3121 | ||
|
|
e51a5682b5 | ||
|
|
38991a4b2e | ||
|
|
bb368f910c | ||
|
|
a68c9f2f65 | ||
|
|
f3535225ab | ||
|
|
e20f7663f1 | ||
|
|
c222cb4e0d | ||
|
|
bcb03fc62f | ||
|
|
51c0afa1a1 | ||
|
|
6008798b99 | ||
|
|
9e1376657b | ||
|
|
572ebc27fa | ||
|
|
363c851f2b | ||
|
|
516b4bdbbd | ||
|
|
47f4ca2b3a | ||
|
|
4808a19633 | ||
|
|
b2e61ea5f6 | ||
|
|
5f698e971e | ||
|
|
71ed1c374b | ||
|
|
757ee37905 | ||
|
|
eee9899cbe | ||
|
|
ab00993f21 | ||
|
|
29590f0327 | ||
|
|
459f209a20 | ||
|
|
6f2e829e87 | ||
|
|
1d5b98f564 | ||
|
|
f3837e2954 | ||
|
|
99306352a3 | ||
|
|
5e95c04139 | ||
|
|
ae7f6de506 | ||
|
|
650ae663e4 | ||
|
|
88cffdf4ec | ||
|
|
824547a96d | ||
|
|
ad9b6e570b | ||
|
|
9c9e1944f8 | ||
|
|
043db28b00 | ||
|
|
e8c1af8822 | ||
|
|
18316aca9a | ||
|
|
e86df52fbb | ||
|
|
b66d0fe188 | ||
|
|
076fa22486 | ||
|
|
5b433fd6d0 | ||
|
|
1aa37cec89 | ||
|
|
2c8cd5e4fa | ||
|
|
20bd4aed8f | ||
|
|
a01ba37d6c | ||
|
|
79926534cb | ||
|
|
695adb718d | ||
|
|
5284e9270a | ||
|
|
e260019df8 | ||
|
|
6c8c4b3e45 | ||
|
|
295d5db77a | ||
|
|
3e556eae78 | ||
|
|
a97f278bb1 | ||
|
|
6cd864e64e | ||
|
|
1002a23b71 | ||
|
|
694a6052fe | ||
|
|
80bfdf62e9 | ||
|
|
6f58c7200c | ||
|
|
fce629c1f0 | ||
|
|
93dad28d0b | ||
|
|
a7b2a140a9 | ||
|
|
08a4ba0614 | ||
|
|
6275d20fb1 | ||
|
|
1318798124 | ||
|
|
3f86366cfa | ||
|
|
bf5485a268 | ||
|
|
e34934fd92 | ||
|
|
a350f7f955 | ||
|
|
25ddf08f88 | ||
|
|
b131c5ee64 | ||
|
|
6b4b19f9da | ||
|
|
4d7a788598 | ||
|
|
957b85d72e | ||
|
|
beed90e6e9 | ||
|
|
2c561b1e80 | ||
|
|
e9622d7738 | ||
|
|
d285951785 | ||
|
|
b3bf4a161d | ||
|
|
ed187e4513 | ||
|
|
79df27c12b | ||
|
|
1fb9a4297c | ||
|
|
9b914a7791 | ||
|
|
8891cbee05 | ||
|
|
3c36e8bfe6 | ||
|
|
3e55dd04f2 | ||
|
|
96f084d69e | ||
|
|
4c69e02643 | ||
|
|
0b4015fa9f | ||
|
|
3f09f67fca | ||
|
|
b170e39523 | ||
|
|
119a42d696 | ||
|
|
613f46e8a7 | ||
|
|
2f32f36e47 | ||
|
|
754844d4bd | ||
|
|
91dfeba954 | ||
|
|
af24315968 | ||
|
|
af7cb756cd | ||
|
|
de403a57e1 | ||
|
|
386e8e5383 | ||
|
|
19cfbd07b5 | ||
|
|
69e2b511af | ||
|
|
c7b1564a20 | ||
|
|
b313e75ef6 | ||
|
|
d43072e902 | ||
|
|
5d7c1e84bc | ||
|
|
9e57593a79 | ||
|
|
2a8fc16241 | ||
|
|
7c1ca92fcb | ||
|
|
dd81e06d35 | ||
|
|
6f17e1e0e8 | ||
|
|
8c4a4c2999 | ||
|
|
ed92cd0945 | ||
|
|
eeeaa6d339 | ||
|
|
8c8782d1e5 | ||
|
|
6b6b926347 | ||
|
|
2ef3b9689e | ||
|
|
023b0723ea | ||
|
|
97d2e4bc30 | ||
|
|
c2b2a73329 | ||
|
|
4185a6a144 | ||
|
|
3eb2ef6cfd | ||
|
|
0b1fec3927 | ||
|
|
25f8668b88 | ||
|
|
1b47bed603 | ||
|
|
bf418055a3 | ||
|
|
125224f976 | ||
|
|
af34862b9c | ||
|
|
d6121c4d82 | ||
|
|
11f03846ab | ||
|
|
d4ad0bf00a | ||
|
|
ed12f40b32 | ||
|
|
f018edcc5b | ||
|
|
078742c054 | ||
|
|
3e05a60d38 | ||
|
|
6cacba1a67 | ||
|
|
21bb5d5e2a | ||
|
|
57c13b9a73 | ||
|
|
5a41eaaa6f | ||
|
|
71efacc050 | ||
|
|
e64b6cf64a | ||
|
|
bff43a86e8 | ||
|
|
1de4494bc2 | ||
|
|
7edace78f7 | ||
|
|
106ebc1abd | ||
|
|
884aebab48 | ||
|
|
fec4803386 | ||
|
|
c39c8cceef | ||
|
|
34f71cf75a | ||
|
|
c631ee1292 | ||
|
|
df9cbc04a8 | ||
|
|
bd2728399d | ||
|
|
556465529b | ||
|
|
4033c7aef0 | ||
|
|
09609997b3 | ||
|
|
dd510d9086 | ||
|
|
d65e14910b | ||
|
|
fe0809cef8 | ||
|
|
0532f5adc3 | ||
|
|
fadee457ba | ||
|
|
10bda2b797 | ||
|
|
262e93a6b4 | ||
|
|
8c4b2bb777 | ||
|
|
f7fff13094 | ||
|
|
e0b2560ffa | ||
|
|
dc5fc68387 | ||
|
|
b3027741f6 | ||
|
|
ad8c74e0c3 | ||
|
|
7c569f5b80 | ||
|
|
06d07b200e | ||
|
|
19c6e4e79d | ||
|
|
f78ea4d279 | ||
|
|
e95142fffc | ||
|
|
7f181e09da | ||
|
|
5276449269 | ||
|
|
f63cc905d5 | ||
|
|
fa51cb3ea1 | ||
|
|
1fb5dd39ed | ||
|
|
1d85be7bb2 | ||
|
|
e7ffc6d0d3 | ||
|
|
dc9d6ff55a | ||
|
|
335dbf233c | ||
|
|
cb8cb43194 | ||
|
|
c234a4fefc | ||
|
|
682ec6745c | ||
|
|
5de4ec65e2 | ||
|
|
e15e8259a2 | ||
|
|
aac6571998 | ||
|
|
129730e73f | ||
|
|
f9ab62025d | ||
|
|
7a61fff0c8 | ||
|
|
43f407559d | ||
|
|
b2eefc00e8 | ||
|
|
21ca9af789 | ||
|
|
068b259777 | ||
|
|
15225bed69 | ||
|
|
6dd402978f | ||
|
|
717e6ac0f9 | ||
|
|
ed3c1ccf49 | ||
|
|
b8f540474d | ||
|
|
32562b84bf | ||
|
|
488932fa17 | ||
|
|
2e61a2a4db | ||
|
|
fd9f620bab | ||
|
|
ac72791a48 | ||
|
|
171f9b317c | ||
|
|
f311a6f566 | ||
|
|
df0084e037 | ||
|
|
4ec601b537 | ||
|
|
29da3f9408 | ||
|
|
aa014eaf14 | ||
|
|
e2306956a5 | ||
|
|
d604f0f746 | ||
|
|
6fff9c1314 | ||
|
|
faec52284f | ||
|
|
bf1c6ee242 | ||
|
|
330da45dca | ||
|
|
c79bd682e5 | ||
|
|
e9f6992059 | ||
|
|
289d6beb17 | ||
|
|
e11e825c3a | ||
|
|
2916541885 | ||
|
|
3eac50321c | ||
|
|
1f2442f384 | ||
|
|
0ea6c8e1e2 | ||
|
|
0a6d6cee32 | ||
|
|
c8debfd8ed | ||
|
|
c6ef22a226 | ||
|
|
0d8a21e85b | ||
|
|
88f97ebaf3 | ||
|
|
b652e9959c | ||
|
|
cadea596e1 | ||
|
|
f7074bcce9 | ||
|
|
6ab8e78133 | ||
|
|
a8c53255a8 | ||
|
|
aaeb4677e1 | ||
|
|
269535411b | ||
|
|
33f179b78f | ||
|
|
abe6d22870 | ||
|
|
2ac095fd04 | ||
|
|
a319b98daf | ||
|
|
547ed02318 | ||
|
|
15faf7e061 | ||
|
|
afc91dfc4d | ||
|
|
8a6ccf6ddf | ||
|
|
7014b1a1c0 | ||
|
|
6b12ad18ef | ||
|
|
8f6021657f | ||
|
|
185fe1f092 | ||
|
|
ca0d56e33e | ||
|
|
fb1b84c12e | ||
|
|
bfcff3170e | ||
|
|
e864759628 | ||
|
|
14ba777e85 | ||
|
|
268d68927d | ||
|
|
70ac928a78 | ||
|
|
c16987c1b6 | ||
|
|
3f45496b70 | ||
|
|
58ebd0f1a3 | ||
|
|
56ce86b08b | ||
|
|
4d6e6c43fd | ||
|
|
08d8f98742 | ||
|
|
d501c6f321 | ||
|
|
6ff13a1c5d | ||
|
|
35a3cf229a | ||
|
|
9619b023c7 | ||
|
|
c0251d78a2 | ||
|
|
4877ea333d | ||
|
|
e11da4bc5f | ||
|
|
0d0ac4e7f5 | ||
|
|
7b33635997 | ||
|
|
47fd5dc02f | ||
|
|
37568985ac | ||
|
|
0dc1fcebc3 | ||
|
|
ea6d20f154 | ||
|
|
cb430ac2b1 | ||
|
|
fbf7e5b92b | ||
|
|
04bae841bf | ||
|
|
c2ae984b2c | ||
|
|
c78a0c31b5 | ||
|
|
64f519b094 | ||
|
|
4fc50631c1 | ||
|
|
1e0411b303 | ||
|
|
16c77bedde | ||
|
|
5c143cf736 | ||
|
|
ffe8831ff6 | ||
|
|
9395c39d4f | ||
|
|
827c9169f9 | ||
|
|
d3f17d0ced | ||
|
|
a8cfb46964 | ||
|
|
11dbb69635 | ||
|
|
5a8f986748 | ||
|
|
ce766cea74 | ||
|
|
8f2da8fe37 | ||
|
|
360ba93e4c | ||
|
|
f17b1f8e67 | ||
|
|
e52681e3f1 | ||
|
|
6b14acfb93 | ||
|
|
d5c6847d1f | ||
|
|
2fc49d5d68 | ||
|
|
2c68b3933d | ||
|
|
cea91ec477 | ||
|
|
375717346b | ||
|
|
ef856ce1ce | ||
|
|
2da87ea466 | ||
|
|
c1ee773c83 | ||
|
|
ca1f0e11ff | ||
|
|
83cf1a8662 | ||
|
|
a68aef90f5 | ||
|
|
0b432e8139 | ||
|
|
cb795b8089 | ||
|
|
949e781e64 | ||
|
|
8de42fc6d3 | ||
|
|
e9f07fa36a | ||
|
|
5f91619de7 | ||
|
|
df7818bc87 | ||
|
|
e381c79535 | ||
|
|
055dcb8cf5 | ||
|
|
b679fade0b | ||
|
|
b9d35c3327 | ||
|
|
f1a01e7563 | ||
|
|
a2735296b7 | ||
|
|
a4b26be5e7 | ||
|
|
0d4e4081c4 | ||
|
|
2099b0866c | ||
|
|
07cc1a7fc5 | ||
|
|
8ceedc8c9e | ||
|
|
c8735a444e | ||
|
|
352da49fdc | ||
|
|
0285cd1522 | ||
|
|
8d4ff9076d | ||
|
|
5053141678 | ||
|
|
3075400211 | ||
|
|
b301237ac6 | ||
|
|
c6f071d37d | ||
|
|
85011ebd1e | ||
|
|
bb783ca8eb | ||
|
|
61fecbab28 | ||
|
|
fc5562e110 | ||
|
|
82d3bc26ca | ||
|
|
e7d9ec3875 | ||
|
|
6359841f34 | ||
|
|
7d2f002139 | ||
|
|
86fe4487d0 | ||
|
|
b9aebfbe50 | ||
|
|
350f77397d | ||
|
|
5d6a4fc068 | ||
|
|
71ae77070e | ||
|
|
4867096bba | ||
|
|
db495d3331 | ||
|
|
33c34a9f2c | ||
|
|
9024d36bb0 | ||
|
|
083d4d3ebb | ||
|
|
1fc0ac852f | ||
|
|
402f1af78d | ||
|
|
c1b9c43c08 | ||
|
|
08680c30bc | ||
|
|
9db394408c | ||
|
|
1575c15a2b | ||
|
|
a019198997 | ||
|
|
ada81a7129 | ||
|
|
4f833dbf60 | ||
|
|
50fed3ee4b | ||
|
|
429dbd78cc | ||
|
|
3c354dc67b | ||
|
|
79ecafe9a6 | ||
|
|
3a69598d93 | ||
|
|
6f8f539c47 | ||
|
|
ee49cec5ae | ||
|
|
f231f70d7f | ||
|
|
acedd159ad | ||
|
|
8cfdaeeac7 | ||
|
|
059ad7b0c2 | ||
|
|
a05cda5d72 | ||
|
|
82a5870e39 | ||
|
|
77fdb3ad1f | ||
|
|
b1c6cb605e | ||
|
|
13ecf84ae0 | ||
|
|
69e3489ef8 | ||
|
|
f45e64dbb9 | ||
|
|
390b2e0601 | ||
|
|
f7b97e556d | ||
|
|
02dd7f7554 | ||
|
|
eb817d4469 | ||
|
|
55e37b7605 | ||
|
|
7cf51a387c | ||
|
|
a93fb9c690 | ||
|
|
b7e963f005 | ||
|
|
12f2d917d3 | ||
|
|
eb4172c08d | ||
|
|
0bd6a97867 | ||
|
|
52a78b7ac2 | ||
|
|
f8d56351b9 | ||
|
|
5ac9477284 | ||
|
|
73b76d3fd7 | ||
|
|
c835972b8b | ||
|
|
d6341fd2de | ||
|
|
e5140393de | ||
|
|
a24946719c | ||
|
|
c7018d1dac | ||
|
|
015f1551aa | ||
|
|
fe9417f217 | ||
|
|
80d28b50e0 | ||
|
|
9d60c8ef1a | ||
|
|
6aea2acad0 | ||
|
|
31f0efd7cd | ||
|
|
7bb7d8857d | ||
|
|
9f59d66ab7 | ||
|
|
0b16044f1a | ||
|
|
6b45e4886a | ||
|
|
b3472e35f1 | ||
|
|
c42574030d | ||
|
|
6040f1316f | ||
|
|
196a73d416 | ||
|
|
20f3bb2fa0 | ||
|
|
aac73a1476 | ||
|
|
92ec9a8446 | ||
|
|
9c7e5ffc18 | ||
|
|
98eeaebdae | ||
|
|
fafd015424 | ||
|
|
7109034f4b | ||
|
|
df5f152ba8 | ||
|
|
5aa35b98bc | ||
|
|
e362963d2a | ||
|
|
34dc5355bc | ||
|
|
9812c5250d | ||
|
|
0432851f94 | ||
|
|
a8721b637c | ||
|
|
26c2dafaf8 | ||
|
|
e6f85c01bd | ||
|
|
edcc388dd4 | ||
|
|
965bf6af4e | ||
|
|
834b3f7dfb | ||
|
|
141d57f5b0 | ||
|
|
8c285de23c | ||
|
|
034f290d9c | ||
|
|
a38c98dccd | ||
|
|
325582b295 | ||
|
|
f024818d2e | ||
|
|
6699449e9f | ||
|
|
18860e2980 | ||
|
|
7a1cc9925d | ||
|
|
de99a7af47 | ||
|
|
e15647ae1b | ||
|
|
d897087b3d | ||
|
|
b4a788e03a | ||
|
|
fb0928c0f5 | ||
|
|
1e449415b1 | ||
|
|
dc672db867 | ||
|
|
50a300ddd7 | ||
|
|
55224d6f4c | ||
|
|
80d9ce417c | ||
|
|
d28a3b7c30 | ||
|
|
f3b80cbb4b | ||
|
|
5b0d212ba2 | ||
|
|
5741d76b96 | ||
|
|
86d7f65026 | ||
|
|
9f0b1af6b7 | ||
|
|
e9b90ee58e | ||
|
|
8e1ab7d505 | ||
|
|
21a72bd2e5 | ||
|
|
245c4eaacb | ||
|
|
d08a85eeae | ||
|
|
92bb8906ca | ||
|
|
1caf52e02a | ||
|
|
9ac44be751 | ||
|
|
9ace74fee7 | ||
|
|
a8f1d26ea9 | ||
|
|
d8ae82c5f9 | ||
|
|
56552528cb | ||
|
|
0cab13f614 | ||
|
|
020327969f | ||
|
|
e269cdaa6d | ||
|
|
c0f04ccf0e | ||
|
|
d45f94ee2e | ||
|
|
32017cdf6b | ||
|
|
36db516db5 | ||
|
|
1d0bfe643e | ||
|
|
269a96c5eb | ||
|
|
b9a160320b | ||
|
|
bb075ea82e | ||
|
|
fd873f8b8f | ||
|
|
29a33b9836 | ||
|
|
6b01e4226c | ||
|
|
9aa0a6352d | ||
|
|
26f50ca98c | ||
|
|
1e605a9561 | ||
|
|
556ac3db76 | ||
|
|
83d1b68ef5 | ||
|
|
917d6df290 | ||
|
|
65d4af771d | ||
|
|
34ae8d5274 | ||
|
|
f3d20f5605 | ||
|
|
de879d55e0 | ||
|
|
9271efd4ed | ||
|
|
12c2798017 | ||
|
|
e5d0da5042 | ||
|
|
3b29a5d7c6 | ||
|
|
938bdabd26 | ||
|
|
454fd20cf5 | ||
|
|
03277cbf42 | ||
|
|
41433715c1 | ||
|
|
b59e38519b | ||
|
|
7500aa3c6d | ||
|
|
7655700eff | ||
|
|
666cd30c2b | ||
|
|
9a2b00891b | ||
|
|
80c0213543 | ||
|
|
0d9f841123 | ||
|
|
fe0bc588a8 | ||
|
|
9bc2b1fe44 | ||
|
|
912e9388ba | ||
|
|
a4078c5e73 | ||
|
|
b0faec1c87 | ||
|
|
5f2ac78654 | ||
|
|
853552ca3a | ||
|
|
dd00f1b1a1 | ||
|
|
19095d3fd3 | ||
|
|
5cc4da0364 | ||
|
|
565a0fdb1b | ||
|
|
19a4b3188e | ||
|
|
a9f584575a | ||
|
|
3030cb2fdc | ||
|
|
21107c9a42 | ||
|
|
cb19661909 | ||
|
|
70845c2977 | ||
|
|
a2bf66da50 | ||
|
|
2710f621ae | ||
|
|
370fbd6072 | ||
|
|
6ce990ce36 | ||
|
|
235e99de96 | ||
|
|
08a0b537e8 | ||
|
|
285f30c8c0 | ||
|
|
48cea000dc | ||
|
|
b405516719 | ||
|
|
d278f8c77a | ||
|
|
58a731e6fd | ||
|
|
b9f0754140 | ||
|
|
1c0b79d783 | ||
|
|
84ed9f5c50 | ||
|
|
691296bb57 | ||
|
|
6af7acc980 | ||
|
|
b5c0ec57ec | ||
|
|
e3e3aafc29 | ||
|
|
30d585e008 | ||
|
|
fa630b07f8 | ||
|
|
95b32ae801 | ||
|
|
4abc5ca757 | ||
|
|
ddc0523c10 | ||
|
|
af8b188336 | ||
|
|
b6bc5ccef0 | ||
|
|
daca7ac870 | ||
|
|
310c618a48 | ||
|
|
f8ce687308 | ||
|
|
cafc5b07b7 | ||
|
|
18f07083b2 | ||
|
|
d67bba49e4 | ||
|
|
9d4af2ae1f | ||
|
|
76ade17a44 | ||
|
|
238c294a98 | ||
|
|
d0c4223b2d | ||
|
|
c01850ff6a | ||
|
|
bda2fca514 | ||
|
|
8857c4e566 | ||
|
|
26c901a84d | ||
|
|
54382bcb22 | ||
|
|
78a4e7046d | ||
|
|
f8b795b0e6 | ||
|
|
e39bdb0078 | ||
|
|
1656400a08 | ||
|
|
816ee723ad | ||
|
|
b489bc4b54 | ||
|
|
d2ef0f0c6d | ||
|
|
4fe93aef9d | ||
|
|
261e32ab8b | ||
|
|
388eba5d2f | ||
|
|
8196b61a3c | ||
|
|
bfad527fcc | ||
|
|
70c7adb06a | ||
|
|
1aeb73b040 | ||
|
|
ad1a24c541 | ||
|
|
6da33d8192 | ||
|
|
33ad1a998c | ||
|
|
8e96b1e948 | ||
|
|
7eacd670bc | ||
|
|
9a66e188d4 | ||
|
|
469fb711a8 | ||
|
|
b903d208dd | ||
|
|
ca31e209ec | ||
|
|
bff8f2fc19 | ||
|
|
bce1bbd9a2 | ||
|
|
dcccc8bcfd | ||
|
|
fe1bf1b562 | ||
|
|
0c95fc166e | ||
|
|
149d707edb | ||
|
|
37c1fffd97 | ||
|
|
68863455fc | ||
|
|
da8f26e309 | ||
|
|
b49d726835 | ||
|
|
ba4722aeec | ||
|
|
8bbd79a065 | ||
|
|
426fdee8b7 | ||
|
|
0f025df81f | ||
|
|
13c8c97f2a | ||
|
|
5eaccc69c4 | ||
|
|
6c0942d9ca | ||
|
|
c90bfa252f | ||
|
|
d4c5e5e332 | ||
|
|
4cb2ee6803 | ||
|
|
37961f5e4d | ||
|
|
93ec8163f0 | ||
|
|
026520da2f | ||
|
|
09ca4b0398 | ||
|
|
d7e5790cce | ||
|
|
39822d9c20 | ||
|
|
61a4b6bf26 | ||
|
|
fe95e0b4e4 | ||
|
|
f8c53bfd20 | ||
|
|
e5912fda9d | ||
|
|
82f7eb268c | ||
|
|
8abb139f29 | ||
|
|
f48e68402b | ||
|
|
210d571296 | ||
|
|
7b4266f443 | ||
|
|
4db0e4c1ae | ||
|
|
36e8e55522 | ||
|
|
0cb23d957a | ||
|
|
fdea5394df | ||
|
|
8c4bea9e52 | ||
|
|
e4a2fea4df | ||
|
|
cd6b9f69b3 | ||
|
|
54f785888d | ||
|
|
ba44d9c07c | ||
|
|
d84888ec7c | ||
|
|
c760f52e6d | ||
|
|
7e0ce2cbce | ||
|
|
c9868e094b | ||
|
|
76d6dfe2bf | ||
|
|
b0f15ea3ed | ||
|
|
ebb6f3bcdb | ||
|
|
20eb136c76 | ||
|
|
31dea5eccd | ||
|
|
fe2850a50a | ||
|
|
ce16ff49cd | ||
|
|
0af1112020 | ||
|
|
ac441ab136 | ||
|
|
f275040887 | ||
|
|
2f3efa1bec | ||
|
|
d1103f4ac6 | ||
|
|
7a25243cd2 | ||
|
|
5fb5872d0d | ||
|
|
b6ebf9f4ad | ||
|
|
080dc51f4b | ||
|
|
4ff6e20073 | ||
|
|
44c9c28fa3 | ||
|
|
7e8794fcf0 | ||
|
|
76b3afe8f9 | ||
|
|
20db25cf89 | ||
|
|
7abea0870f | ||
|
|
1ab062d899 | ||
|
|
d60f7c319c | ||
|
|
0398803f1b | ||
|
|
2538e7ef8c | ||
|
|
f122665e3c | ||
|
|
3e691791b6 | ||
|
|
430303d9c0 | ||
|
|
ecdb0aab03 | ||
|
|
2522e9bb1d | ||
|
|
822d8f45b6 | ||
|
|
d036cab4c1 | ||
|
|
3ee1c2b282 | ||
|
|
b2b2775504 | ||
|
|
3a5ea0379a | ||
|
|
dc3281203d | ||
|
|
d94a049cfd | ||
|
|
c7b1c337e2 | ||
|
|
116eaefd8f | ||
|
|
8c70a9395d | ||
|
|
29fbe46d41 | ||
|
|
aa4d982d4c | ||
|
|
fa6ab1c8c4 | ||
|
|
a9216705e1 | ||
|
|
20828213b2 | ||
|
|
f4e228730f | ||
|
|
bd9c8f0f12 | ||
|
|
d07db1054a | ||
|
|
18deecddea | ||
|
|
f3991199dd | ||
|
|
007411411b | ||
|
|
75124ba900 | ||
|
|
1d9589c093 | ||
|
|
6974d96f6e | ||
|
|
5584e62db3 | ||
|
|
9b968777a0 | ||
|
|
62b7326a75 | ||
|
|
6b7275f475 | ||
|
|
7f174da3c7 | ||
|
|
5a1c7b50e7 | ||
|
|
39283bf99e | ||
|
|
95ec71bd0a | ||
|
|
756a7fddf2 | ||
|
|
e1f897cab9 | ||
|
|
eb35ed9a1b | ||
|
|
f439a401a0 | ||
|
|
bfd4c8cb5c | ||
|
|
3fca45b256 | ||
|
|
bda27e69ba | ||
|
|
1e88171d45 | ||
|
|
d9a2f6b7bb | ||
|
|
94de344d05 | ||
|
|
3dd188dedd | ||
|
|
a5562ea8bd | ||
|
|
8f86acfef6 | ||
|
|
890cf8841a | ||
|
|
55e0e5571b | ||
|
|
19e062a79c | ||
|
|
916a10fae8 | ||
|
|
4f8849e914 | ||
|
|
713098471e | ||
|
|
bab00e6e42 | ||
|
|
c0836a75ed | ||
|
|
6cb611971a | ||
|
|
3ba09947d2 | ||
|
|
523c3db8c4 | ||
|
|
d94b7fba23 | ||
|
|
ae76bbcafe | ||
|
|
b987e9086a | ||
|
|
47fc82a839 | ||
|
|
fcff7e85fe | ||
|
|
147ec021ea | ||
|
|
cb7f4d373e | ||
|
|
3db9dfd7ea | ||
|
|
18fa4d2134 | ||
|
|
b63ec10cf7 | ||
|
|
c44ce3acbd | ||
|
|
fbd494d348 | ||
|
|
b98412de11 | ||
|
|
cd17162a00 | ||
|
|
dd63e8cc86 | ||
|
|
1d0ca9bf0c | ||
|
|
c0704f6a34 | ||
|
|
a7750a38b9 | ||
|
|
58307888df | ||
|
|
b1ad6f19c0 | ||
|
|
b254c69771 | ||
|
|
0360d2562d | ||
|
|
2df3d1967e | ||
|
|
54c600660b | ||
|
|
4e8e889900 | ||
|
|
66ed58df03 | ||
|
|
a8d4175cd1 | ||
|
|
1c286c1c5e | ||
|
|
011a1057bf | ||
|
|
1d8af4b523 | ||
|
|
cbb12339c9 | ||
|
|
c4c2a525fb | ||
|
|
fd1a581598 | ||
|
|
4902ba83c4 | ||
|
|
5c6453f931 | ||
|
|
880de4491c | ||
|
|
e9ed82bdc5 | ||
|
|
048acfda7b | ||
|
|
ca2013fb97 | ||
|
|
dad24e4fba | ||
|
|
0fea396a1b | ||
|
|
393358d936 | ||
|
|
236e0f1f75 | ||
|
|
cf78416e24 | ||
|
|
80e64bab6d | ||
|
|
98725002e6 | ||
|
|
e834fd31c8 | ||
|
|
53d00d528c | ||
|
|
e6b31b2d7e | ||
|
|
b61ed02ee4 | ||
|
|
512d06ae48 | ||
|
|
66c2faf379 | ||
|
|
4ba2a4ec27 | ||
|
|
6d2d8b8a3c | ||
|
|
e9570fe320 | ||
|
|
97c5983a4e | ||
|
|
4bdbb91d4d | ||
|
|
e84ab5d5dd | ||
|
|
4aaea970cd | ||
|
|
614300d911 | ||
|
|
ab4c78c288 | ||
|
|
d4590ee13e | ||
|
|
456d4f999d | ||
|
|
1ecc2d930a | ||
|
|
7881e1ec14 | ||
|
|
b9184bba5d | ||
|
|
ff51cf7c72 | ||
|
|
18f13de0f0 | ||
|
|
fe1652bf7f | ||
|
|
06c7772c0a | ||
|
|
dd56fd116e | ||
|
|
e7db118ef4 | ||
|
|
14964b55b9 | ||
|
|
cf59aef0f5 | ||
|
|
59ccc7fdef | ||
|
|
5bb72f548f | ||
|
|
58d96434e8 | ||
|
|
a1093a9b37 | ||
|
|
cccf15ce6c | ||
|
|
f977f8067e | ||
|
|
656e407e6d | ||
|
|
0b0309d5c3 | ||
|
|
112cee940e | ||
|
|
82f5a3bff4 | ||
|
|
24c1fae0ce | ||
|
|
9c8f25777c | ||
|
|
3ec4dce187 | ||
|
|
9f7c0fa57a | ||
|
|
fff085a79b | ||
|
|
1ce5dcf37d | ||
|
|
4b6a9486d8 | ||
|
|
8f1096a082 | ||
|
|
bee55277d9 |
No files matched your search
@@ -0,0 +1,12 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||
patreon: # Replace with a single Patreon username
|
||||
open_collective: # Replace with a single Open Collective username
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
otechie: # Replace with a single Otechie username
|
||||
custom: paypal.me/0ptitSeb
|
||||
+4
-2
@@ -1,3 +1,5 @@
|
||||
build
|
||||
build_llvm
|
||||
build/
|
||||
build*/
|
||||
.vscode
|
||||
.gdb_history
|
||||
src/git_head.h
|
||||
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 68 KiB |
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 171 KiB |
Regular → Executable
+43
@@ -1,3 +1,46 @@
|
||||
v0.1.2
|
||||
======
|
||||
* The Dynarec now handle JIT code
|
||||
* Added support for Unity games (not perfect yet)
|
||||
* Added support for Wine (not perfect yet). You need an x86 build of Wine to use it
|
||||
* Added support for Steam (not perfect yet). Note that steam have limited functionnalities on 32bits (only mini-mode is available)
|
||||
* More wrapped libs
|
||||
* Added support for "PltResolver", so order of library is less important and many symbol are resolved at runtime
|
||||
* Added an option to build box86 as a lib (to wrapped dynamic library)
|
||||
* Better Signal handling (not perfect yet)
|
||||
* More opcodes added, more opcode fixes.
|
||||
* More Dynarec opcodes.
|
||||
* Added support for FS:, and creating custom selector (needed by Wine)
|
||||
* There is now 1 x86emu_t structure per thread (simplifying/optimising many callback handling)
|
||||
* Box86 now have a logo!
|
||||
* Added options handling (only version and help for now). Now it's much usefull exept for version printing.
|
||||
|
||||
|
||||
v0.1.0
|
||||
=======
|
||||
* Dynarec!!! Only for ARM (note that dynarec doesn't support JITed code for now)
|
||||
* Added real support for getcontext/set/context/makecontext/swapcontext
|
||||
* Preliminary signal handling
|
||||
* Fixes to SDL(1/2) Image and SDL1 Mixer, and to SDL1.2 RWops usage
|
||||
* Fixed numerous issues in opcodes (both interpretor and dynarec). FTL works fine now, among many others
|
||||
* Added wrapped gtk support (still ongoing, many libs involved)
|
||||
* Make loading of libs more configurable
|
||||
* If a wrapped native libs is not found, try to use emulated one
|
||||
* Add en env. var. to force use of emulated lib for certain libs
|
||||
* Add an env. var. to define wich libGL to use
|
||||
* Added Install / Uninstall target (using systemd binfmt)
|
||||
* Added more hardware target (RPis, GameShell...)
|
||||
* Wrapped more libs (including FreeType, smpeg, ncurses, sndfile...)
|
||||
|
||||
v0.0.4
|
||||
=======
|
||||
* Improved the Init of dependant Libs. More things work now.
|
||||
* Added a lot of wrapped functions.
|
||||
* Added a few wrapped libs (like libz or some other x11 related libs)
|
||||
* For trace enabled build, Trace can be enabled only after a certain amount of opcodes (still, a debugger would be better)
|
||||
* Some fixes in a few opcodes, and implemented x87 rounding (SuperMeatBoy behaves better now)
|
||||
* FTL 1.6.9 still have corrupted music, but older 1.5.13 seems fine (different set of libs)
|
||||
|
||||
v0.0.2
|
||||
=======
|
||||
* A full commercial games runs fine on the Pandora: Airline Tycoon Deluxe
|
||||
|
||||
+480
-68
@@ -3,20 +3,111 @@ cmake_minimum_required(VERSION 2.6)
|
||||
project(box86)
|
||||
|
||||
enable_testing()
|
||||
enable_language(C)
|
||||
|
||||
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(GAMESHELL "Set to ON if targeting a GameShell device" ${GAMESHELL})
|
||||
option(ODROID "Set to ON if targeting an ODroid device" ${ODROID})
|
||||
option(USE_CCACHE "Set to ON to use ccache if present in the system" ${USE_CCACHE})
|
||||
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})
|
||||
option(HAVE_TRACE "Set to ON to have Trace ability (needs ZydisInfo library)" ${HAVE_TRACE})
|
||||
option(USE_FLOAT "Set to ON to use only float, no double, in all x87 Emulation" ${USE_FLOAT})
|
||||
option(NOLOADADDR "Set to ON to avoid fixing the load address of Box86" ${NO_LOADAADR})
|
||||
option(ARM_DYNAREC "Set to ON to use ARM Dynamic Recompilation (WIP, don't use yet)" ${ARM_DYNAREC})
|
||||
option(NOGETCLOCK "Set to ON to avoid using clock_gettime with CLOCK_MONOTONIC_COARSE for RDTSC opcode (use gltimeofday instead)" ${NOGETCLOCK})
|
||||
|
||||
if(${CMAKE_VERSION} VERSION_LESS "3.12.2")
|
||||
find_package(PythonInterp 3)
|
||||
if(NOT PYTHONINTERP_FOUND)
|
||||
message( FATAL_ERROR "You need a Python interpretor, CMake will exit." )
|
||||
endif()
|
||||
if(${PYTHON_VERSION_MAJOR} LESS 3)
|
||||
message( FATAL_ERROR "You need a Python 3 interpretor, CMake will exit." )
|
||||
endif()
|
||||
else()
|
||||
find_package(Python3)
|
||||
if(NOT Python3_Interpreter_FOUND)
|
||||
message( FATAL_ERROR "You need a Python interpretor, CMake will exit." )
|
||||
endif()
|
||||
set(PYTHON_EXECUTABLE ${Python3_EXECUTABLE} CACHE INTERNAL "The Python3 executable" FORCE)
|
||||
endif()
|
||||
|
||||
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.")
|
||||
set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE STRING "Choose the type of build." FORCE)
|
||||
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
|
||||
endif()
|
||||
|
||||
|
||||
# Pandora
|
||||
if(PANDORA)
|
||||
add_definitions(-DPANDORA)
|
||||
#add_definitions(-mcpu=cortex-a8 -mfpu=neon -mfloat-abi=softfp -ftree-vectorize -fsingle-precision-constant -ffast-math)
|
||||
set(ARM_DYNAREC ON)
|
||||
set(LD80BITS OFF)
|
||||
set(NOALIGN OFF)
|
||||
endif()
|
||||
|
||||
# Gameshell
|
||||
if(GAMESHELL)
|
||||
add_definitions(-marm -mcpu=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-marm -mcpu=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard")
|
||||
set(ARM_DYNAREC ON)
|
||||
set(LD80BITS OFF)
|
||||
set(NOALIGN OFF)
|
||||
endif()
|
||||
|
||||
if(PYRA)
|
||||
add_definitions(-mcpu=cortex-a15 -mfpu=neon -mfloat-abi=hard -marm)
|
||||
set(CMAKE_ASM_FLAGS "-marm -mcpu=cortex-a15 -mfpu=neon -mfloat-abi=hard")
|
||||
set(ARM_DYNAREC ON)
|
||||
set(LD80BITS OFF)
|
||||
set(NOALIGN OFF)
|
||||
endif()
|
||||
|
||||
if(RPI2)
|
||||
add_definitions(-DRPI)
|
||||
add_definitions(-DRPI2)
|
||||
add_definitions(-marm -mcpu=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-marm -mcpu=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard")
|
||||
set(ARM_DYNAREC ON)
|
||||
set(LD80BITS OFF)
|
||||
set(NOALIGN OFF)
|
||||
endif()
|
||||
if(RPI3)
|
||||
add_definitions(-DRPI)
|
||||
add_definitions(-DRPI3)
|
||||
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")
|
||||
set(ARM_DYNAREC ON)
|
||||
set(LD80BITS OFF)
|
||||
set(NOALIGN OFF)
|
||||
endif()
|
||||
if(RPI4)
|
||||
add_definitions(-DRPI)
|
||||
add_definitions(-DRPI3)
|
||||
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")
|
||||
set(ARM_DYNAREC ON)
|
||||
set(LD80BITS OFF)
|
||||
set(NOALIGN OFF)
|
||||
endif()
|
||||
if(ODROID)
|
||||
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")
|
||||
set(ARM_DYNAREC ON)
|
||||
set(LD80BITS OFF)
|
||||
set(NOALIGN OFF)
|
||||
endif()
|
||||
|
||||
set(BOX86_ELF_ADDRESS "0x02800000")
|
||||
|
||||
if(LD80BITS)
|
||||
add_definitions(-DHAVE_LD80BITS)
|
||||
endif()
|
||||
@@ -29,7 +120,36 @@ if(HAVE_TRACE)
|
||||
add_definitions(-DHAVE_TRACE)
|
||||
endif()
|
||||
|
||||
add_definitions(-g -std=gnu99 -funwind-tables -O3 -fvisibility=hidden -no-pie -fjump-tables)
|
||||
if(USE_FLOAT)
|
||||
add_definitions(-DUSE_FLOAT)
|
||||
endif()
|
||||
|
||||
if(ARM_DYNAREC)
|
||||
add_definitions(-DDYNAREC)
|
||||
add_definitions(-DARM)
|
||||
add_definitions(-marm)
|
||||
enable_language(ASM)
|
||||
endif()
|
||||
|
||||
if(NOGETCLOCK)
|
||||
add_definitions(-DNOGETCLOCK)
|
||||
endif()
|
||||
|
||||
if(BOX86LIB)
|
||||
add_definitions(-DBUILD_LIB)
|
||||
if(BOX86DYNAMIC)
|
||||
add_definitions(-DBUILD_DYNAMIC)
|
||||
endif()
|
||||
add_definitions(-fPIC)
|
||||
if(NOT BOX86_ROOT)
|
||||
message(FATAL_ERROR "BOX86_ROOT not set when build as lib")
|
||||
endif()
|
||||
else()
|
||||
set(BOX86_ROOT ${CMAKE_HOME_DIRECTORY})
|
||||
endif()
|
||||
|
||||
|
||||
add_definitions(-std=gnu99 -funwind-tables -fvisibility=hidden)
|
||||
|
||||
if(USE_CCACHE)
|
||||
find_program(CCACHE_FOUND ccache)
|
||||
@@ -39,114 +159,406 @@ if(USE_CCACHE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
#include_directories(include)
|
||||
include_directories(
|
||||
"${BOX86_ROOT}/src/include"
|
||||
"${BOX86_ROOT}/src"
|
||||
"${BOX86_ROOT}/src/wrapped/generated"
|
||||
)
|
||||
|
||||
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"
|
||||
DEPEND "${BOX86_ROOT}/src/build_info.c"
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
set(ELFLOADER_SRC
|
||||
"${CMAKE_HOME_DIRECTORY}/src/bridge.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/main.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/pathcoll.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/box86context.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/fileutils.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/elfloader.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/elfparser.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/elfload_dump.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/library.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/librarian.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/stack.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/threads.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/wrapper.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/x86emu.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/x86run.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/x86run66.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/x86run_private.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/x86syscall.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/x86primop.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/x86trace.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/x86int3.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/x87emu_private.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/x87run.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/myalign.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/callback.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/sdl1rwops.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/sdl2rwops.c"
|
||||
"${BOX86_ROOT}/src/git_head.h"
|
||||
"${BOX86_ROOT}/src/main.c"
|
||||
"${BOX86_ROOT}/src/box86context.c"
|
||||
"${BOX86_ROOT}/src/build_info.c"
|
||||
"${BOX86_ROOT}/src/tools/bridge.c"
|
||||
"${BOX86_ROOT}/src/tools/pathcoll.c"
|
||||
"${BOX86_ROOT}/src/tools/fileutils.c"
|
||||
"${BOX86_ROOT}/src/tools/callback.c"
|
||||
"${BOX86_ROOT}/src/tools/box86stack.c"
|
||||
"${BOX86_ROOT}/src/tools/my_cpuid.c"
|
||||
"${BOX86_ROOT}/src/tools/gtkclass.c"
|
||||
"${BOX86_ROOT}/src/tools/wine_tools.c"
|
||||
"${BOX86_ROOT}/src/elfs/elfloader.c"
|
||||
"${BOX86_ROOT}/src/elfs/elfparser.c"
|
||||
"${BOX86_ROOT}/src/elfs/elfload_dump.c"
|
||||
"${BOX86_ROOT}/src/librarian/library.c"
|
||||
"${BOX86_ROOT}/src/librarian/librarian.c"
|
||||
"${BOX86_ROOT}/src/emu/x86emu.c"
|
||||
"${BOX86_ROOT}/src/emu/x86run.c"
|
||||
"${BOX86_ROOT}/src/emu/x86run66.c"
|
||||
"${BOX86_ROOT}/src/emu/x86run_private.c"
|
||||
"${BOX86_ROOT}/src/emu/x86syscall.c"
|
||||
"${BOX86_ROOT}/src/emu/x86primop.c"
|
||||
"${BOX86_ROOT}/src/emu/x86trace.c"
|
||||
"${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/myfts.c"
|
||||
"${BOX86_ROOT}/src/libtools/obstack.c"
|
||||
"${BOX86_ROOT}/src/libtools/sdl1rwops.c"
|
||||
"${BOX86_ROOT}/src/libtools/sdl2rwops.c"
|
||||
"${BOX86_ROOT}/src/libtools/signals.c"
|
||||
"${BOX86_ROOT}/src/libtools/threads.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec.c"
|
||||
"${BOX86_ROOT}/src/wrapped/generated/wrapper.c"
|
||||
)
|
||||
|
||||
set(WRAPPEDS
|
||||
"${CMAKE_HOME_DIRECTORY}/src/wrappedlibc.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/wrappedlibpthread.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/wrappedlibrt.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/wrappedlibgl.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/wrappedlibglu.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/wrappedlibx11.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/wrappedlibasound.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/wrappedlibdl.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/wrappedlibm.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/wrappedsdl1.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/wrappedsdl1mixer.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/wrappedsdl1image.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/wrappedsdl2.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/wrappedsdl2mixer.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/wrappedsdl2image.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/wrappedsmpeg2.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/wrappedvorbisfile.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/wrappedpng16.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/wrappedlibxxf86vm.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/wrappedlibxrandr.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/wrappedlibz.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/wrappedopenal.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/wrappedalut.c"
|
||||
"${CMAKE_HOME_DIRECTORY}/src/wrappedldlinux.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibc.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibpthread.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibrt.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibgl.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibglu.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibx11.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibasound.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibdl.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibm.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedsdl1.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedsdl1mixer.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedsdl1image.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedsdl1ttf.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedsdl2.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedsdl2mixer.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedsdl2image.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedsmpeg.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedsmpeg2.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedvorbisfile.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibvorbis.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibogg.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedpng12.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedpng16.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxxf86vm.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxrandr.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxext.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedxinerama.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxfixes.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxcursor.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxrender.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxi.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxss.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxpm.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxau.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxdmcp.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibx11xcb.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxcb.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxtst.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxt.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxcomposite.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxdamage.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxmu.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibz.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedopenal.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedalut.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibjpeg.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedcurl.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedudev0.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedudev1.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappeddbus.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappediconv.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibdrm.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedcrypto.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibssl.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedutil.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibuuid.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibresolv.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedpulsesimple.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedpulse.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibsndfile.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedfontconfig.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedfreetype.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedbz2.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibsm.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibice.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibusb1.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibncursesw.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibformw.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibncurses.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibtinfo.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibncurses6.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibtinfo6.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgtkx112.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgdkx112.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgdkpixbuf2.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgio2.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgmodule2.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgobject2.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedglib2.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgstreamer010.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgstinterfaces010.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappeddbusmenugtk.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappeddbusmenuglib.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedatk.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/wrappedpango.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappeddbusglib1.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgudev1.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibnm.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedtcmallocminimal.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedmpg123.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgnutls.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedldlinux.c"
|
||||
)
|
||||
set(WRAPPER "${CMAKE_HOME_DIRECTORY}/src/wrapper.c" "${CMAKE_HOME_DIRECTORY}/src/wrapper.h")
|
||||
add_custom_command(OUTPUT ${WRAPPER} COMMAND "${CMAKE_HOME_DIRECTORY}/rebuild_wrappers.py" "${CMAKE_HOME_DIRECTORY}" MAIN_DEPENDENCY "${CMAKE_HOME_DIRECTORY}/rebuild_wrappers.py" DEPENDS ${WRAPPEDS})
|
||||
set_source_files_properties(${WRAPPER} PROPERTIES GENERATED TRUE)
|
||||
|
||||
add_executable(box86 ${ELFLOADER_SRC} ${WRAPPEDS})
|
||||
target_link_libraries(box86 m dl rt pthread)
|
||||
set(WRAPPEDS_HEAD "")
|
||||
foreach(A ${WRAPPEDS})
|
||||
string(REPLACE ".c" "_private.h" B ${A})
|
||||
set(WRAPPEDS_HEAD ${WRAPPEDS_HEAD} ${B})
|
||||
set_source_files_properties(${A} PROPERTIES OBJECT_DEPENDS ${B})
|
||||
endforeach()
|
||||
|
||||
target_link_libraries(box86 -no-pie -Wl,-Ttext-segment,0xA8000000)
|
||||
set(WRAPPER "${BOX86_ROOT}/src/wrapped/generated/wrapper.c" "${BOX86_ROOT}/src/wrapped/generated/wrapper.h")
|
||||
|
||||
add_test(test01 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/box86
|
||||
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" "USE_FLOAT" "--" ${WRAPPEDS_HEAD}
|
||||
MAIN_DEPENDENCY "${BOX86_ROOT}/rebuild_wrappers.py"
|
||||
DEPENDS ${WRAPPEDS} ${WRAPPEDS_HEAD}
|
||||
BYPRODUCTS ${WRAPPER}
|
||||
)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT "${BOX86_ROOT}/src/dynarec/last_run.txt"
|
||||
COMMAND "${PYTHON_EXECUTABLE}" "${BOX86_ROOT}/rebuild_printer.py" "${BOX86_ROOT}"
|
||||
MAIN_DEPENDENCY "${BOX86_ROOT}/rebuild_printer.py"
|
||||
DEPENDS "${BOX86_ROOT}/src/dynarec/arm_instructions.txt"
|
||||
BYPRODUCTS "${BOX86_ROOT}/src/dynarec/arm_printer.c"
|
||||
)
|
||||
|
||||
add_custom_target(WRAPPERS DEPENDS "${BOX86_ROOT}/src/wrapped/generated/functions_list.txt")
|
||||
add_custom_target(PRINTER DEPENDS "${BOX86_ROOT}/src/dynarec/last_run.txt")
|
||||
|
||||
#this is to force build_info.c to be rebuilt all the time
|
||||
set_source_files_properties("${BOX86_ROOT}/src/build_info.c" PROPERTIES OBJECT_OUTPUTS "dummy.c")
|
||||
|
||||
if(ARM_DYNAREC)
|
||||
set(DYNAREC_SRC
|
||||
"${BOX86_ROOT}/src/dynarec/dynablock.c"
|
||||
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_functions.c"
|
||||
"${BOX86_ROOT}/src/dynarec/arm_printer.c"
|
||||
|
||||
"${BOX86_ROOT}/src/dynarec/arm_prolog.S"
|
||||
"${BOX86_ROOT}/src/dynarec/arm_epilog.S"
|
||||
"${BOX86_ROOT}/src/dynarec/arm_linker.S"
|
||||
"${BOX86_ROOT}/src/dynarec/arm_table.S"
|
||||
)
|
||||
|
||||
set(DYNAREC_PASS
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_helper.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_emit_tests.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_emit_math.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_emit_logic.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_emit_shift.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_pass.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_00.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_0f.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_64.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_65.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_66.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_67.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_d8.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_d9.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_da.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_db.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_dc.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_dd.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_de.c"
|
||||
"${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_f20f.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_f30f.c"
|
||||
)
|
||||
|
||||
set(DYNAREC_PASS "${BOX86_ROOT}/src/wrapped/generated/wrapper.h" ${DYNAREC_PASS})
|
||||
|
||||
add_library(dynarec_arm OBJECT ${DYNAREC_SRC})
|
||||
|
||||
add_library(arm_pass0 OBJECT ${DYNAREC_PASS})
|
||||
set_target_properties(arm_pass0 PROPERTIES COMPILE_FLAGS "-DSTEP=0")
|
||||
add_library(arm_pass1 OBJECT ${DYNAREC_PASS})
|
||||
set_target_properties(arm_pass1 PROPERTIES COMPILE_FLAGS "-DSTEP=1")
|
||||
add_library(arm_pass2 OBJECT ${DYNAREC_PASS})
|
||||
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_dependencies(arm_pass0 WRAPPERS)
|
||||
add_dependencies(arm_pass1 WRAPPERS)
|
||||
add_dependencies(arm_pass2 WRAPPERS)
|
||||
add_dependencies(arm_pass3 WRAPPERS)
|
||||
|
||||
add_library(dynarec STATIC
|
||||
$<TARGET_OBJECTS:dynarec_arm>
|
||||
$<TARGET_OBJECTS:arm_pass0>
|
||||
$<TARGET_OBJECTS:arm_pass1>
|
||||
$<TARGET_OBJECTS:arm_pass2>
|
||||
$<TARGET_OBJECTS:arm_pass3>
|
||||
)
|
||||
endif()
|
||||
|
||||
if(BOX86LIB)
|
||||
#build a static or dynamic lib...
|
||||
if(BOX86DYNAMIC)
|
||||
add_library(box86 SHARED ${ELFLOADER_SRC} ${WRAPPEDS})
|
||||
else()
|
||||
add_library(box86 OBJECT ${ELFLOADER_SRC} ${WRAPPEDS})
|
||||
endif()
|
||||
if(ARM_DYNAREC)
|
||||
target_link_libraries(box86 dynarec m dl rt pthread)
|
||||
endif()
|
||||
if(${CMAKE_VERSION} VERSION_LESS "3.13")
|
||||
set_target_properties(box86 PROPERTIES LINK_FLAGS -rdynamic)
|
||||
else()
|
||||
target_link_options(box86 PUBLIC -rdynamic)
|
||||
endif()
|
||||
add_dependencies(box86 WRAPPERS)
|
||||
add_dependencies(box86 PRINTER)
|
||||
|
||||
else(BOX86LIB)
|
||||
|
||||
if(USE_FLOAT)
|
||||
set(BOX86 box86f)
|
||||
elseif(HAVE_TRACE)
|
||||
set(BOX86 box86t)
|
||||
else()
|
||||
set(BOX86 box86)
|
||||
endif()
|
||||
|
||||
add_executable(${BOX86} ${ELFLOADER_SRC} ${WRAPPEDS})
|
||||
add_dependencies(${BOX86} WRAPPERS)
|
||||
add_dependencies(${BOX86} PRINTER)
|
||||
target_link_libraries(${BOX86} m dl rt pthread)
|
||||
if(ARM_DYNAREC)
|
||||
target_link_libraries(${BOX86} dynarec)
|
||||
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}")
|
||||
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})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
string(COMPARE EQUAL "${CMAKE_HOST_SYSTEM_PROCESSOR}" "i686" _x86)
|
||||
string(COMPARE EQUAL "${CMAKE_HOST_SYSTEM_PROCESSOR}" "x86_64" _x86_64)
|
||||
|
||||
if(NOT _x86 AND NOT _x86_64)
|
||||
install(TARGETS ${BOX86}
|
||||
RUNTIME DESTINATION bin)
|
||||
install(FILES ${CMAKE_SOURCE_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/)
|
||||
endif()
|
||||
|
||||
if(NOT TARGET uninstall)
|
||||
configure_file(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
|
||||
IMMEDIATE @ONLY)
|
||||
|
||||
add_custom_target(uninstall
|
||||
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
|
||||
endif()
|
||||
|
||||
add_test(test01 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test01 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref01.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test02 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/box86
|
||||
add_test(test02 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test02 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref02.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test03 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/box86
|
||||
add_test(test03 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test03 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref03.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test04 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/box86
|
||||
add_test(test04 ${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_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref04.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test05 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/box86
|
||||
add_test(test05 ${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_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref05.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test06 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/box86
|
||||
add_test(test06 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test06 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref06.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test07 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/box86
|
||||
add_test(test07 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test07 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref07.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test08 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/box86
|
||||
add_test(test08 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test08 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref08.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test09 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/box86
|
||||
add_test(test09 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test09 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref09.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test10 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test10 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref10.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test11 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test11 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref11.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test12 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test12 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref12.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test13 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test13 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref13.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test14 ${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 )
|
||||
|
||||
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_REFERENCE=${CMAKE_SOURCE_DIR}/tests/extensions/${testname}.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake)
|
||||
endforeach()
|
||||
|
||||
endif(BOX86LIB)
|
||||
Executable
+64
@@ -0,0 +1,64 @@
|
||||
Compiling
|
||||
----
|
||||
#### for Pandora
|
||||
|
||||
`mkdir build; cd build; cmake .. -DPANDORA=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make`
|
||||
|
||||
#### for Pyra
|
||||
|
||||
`mkdir build; cd build; cmake .. -DPYRA=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make`
|
||||
|
||||
#### for Gameshell
|
||||
|
||||
`mkdir build; cd build; cmake .. -DGAMESHELL=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make`
|
||||
|
||||
#### for RaspberryPI
|
||||
|
||||
_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)_
|
||||
|
||||
`mkdir build; cd build; cmake .. -DRPI4=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make`
|
||||
|
||||
_For Pi4. Change to RPI2 or RPI3 for other models._
|
||||
|
||||
#### for ODROID
|
||||
|
||||
`mkdir build; cd build; cmake .. -DODROID=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make`
|
||||
|
||||
#### for Other ARM Linux
|
||||
|
||||
`mkdir build; cd build; cmake .. -DARM_DYNAREC=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo; make`
|
||||
|
||||
#### for x86 Linux
|
||||
|
||||
`mkdir build; cd build; cmake .. -DLD80BITS=1 -DNOALIGN=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make`
|
||||
|
||||
#### 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
|
||||
|
||||
*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*
|
||||
|
||||
The `-DCMAKE_BUILD_TYPE=RelWithDebInfo` argument make a build that is both optimized for speed, and have debug information embedded. That way, if you have a crash or try to analyse performances, you'll have some symbols.
|
||||
|
||||
*to have a Trace Enabled build*
|
||||
|
||||
To have a trace enabled build (warning, 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 lib folders.
|
||||
|
||||
*to have ARM Dynarec*
|
||||
|
||||
The Dynarec is only avaiable on ARM Cpu. 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).
|
||||
|
||||
----
|
||||
|
||||
Testing
|
||||
----
|
||||
A few tests are included.
|
||||
They can be launched with `ctest`
|
||||
They are very basic and don't test much for now.
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2018-2019 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.
|
||||
@@ -1,18 +1,90 @@
|
||||
# box86
|
||||
|
||||

|
||||
Linux Userspace x86 Emulator with a twist
|
||||
|
||||
Box86 will let run x86 Linux program (games) on non-x86 Linux, like ARM (needs to be 32bits little-endian).
|
||||
Box86 lets you run x86 Linux programs (such as games) on non-x86 Linux, like ARM (host system needs to be 32bit little-endian).
|
||||
|
||||
Also, Box86 use native version for some "system" libraries, like libc, libm, or SDL and OpenGL, leading to more performance and easier integration with host system.
|
||||
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 support 64-bit will not compile Box86, and you'll get errors (typically on aarch64, you get "-marm" not recognized).
|
||||
|
||||
Most x86 Games needs OpenGL, so on ARM platform, a solution like gl4es is probably needed.
|
||||
Because Box86 uses the native versions of some "system" libraries, like libc, libm, SDL, and OpenGL, it's easy to integrate and use, and performance can be surprisingly high in some cases.
|
||||
|
||||
Current version is higly experimental and early, and most stuff wont run and run correctly. For now, WorldOfGoo does run correctly. FTL runs but sound is distorted...
|
||||
Most x86 Games need OpenGL, so on ARM platforms a solution like [gl4es](https://github.com/ptitSeb/gl4es) is usually necessary.
|
||||
|
||||
If you are serious about developping Box86, you should install ccache and activate it's support in the cmake project (use ccmake for example)
|
||||
To have the TRACE enabled (i.e. dumping to stdout all individual x86 instruction execute, with dump of registers), you'll also need [Zydis library](https://github.com/zyantific/zydis) accessible on your system.
|
||||
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 x86 internal opcode use parts of "Realmode X86 Emulator Library", see [x86primop.c](src/x86primop.c) for copyright details
|
||||
Many games already work, for example: WorldOfGoo, Airline Tycoon Deluxe, and FTL. Many of the GameMaker Linux games also run fine (there a long list, among them are UNDERTALE, A Risk of Rain, and Cook Server Delicious)
|
||||
|
||||
Change log is accessible [here](CHANGELOG.md)
|
||||
If you are serious about developing Box86, you should install ccache and activate its support in the cmake project (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/x86primop.c) for copyright details
|
||||
|
||||
Here are 6 videos, the first 2 of "Airline Tycoon Deluxe" and "Heretic 2" running on a gigahertz OpenPandora (the second one use the dynarec), and the next 2 of "Bit.Trip.Runner" and "Neverwinter Night" running on an ODroid XU4 (without dynarec), and the last 2 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 [PI Lab Channel](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g) [](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g).
|
||||
|
||||
Compatibility list is there: https://github.com/ptitSeb/box86-compatibility-list/issues
|
||||
|
||||
<img src="Box86Icon.png" width="96" height="96">
|
||||
|
||||
Logo and Icon made by @grayduck, thanks!
|
||||
|
||||
----
|
||||
|
||||
Compiling
|
||||
----
|
||||
Compilation instructions can be found [here](COMPILE.md)
|
||||
|
||||
----
|
||||
|
||||
Usage
|
||||
----
|
||||
|
||||
There are a few environment variables avaiable to control the behaviour of Box86.
|
||||
|
||||
See [here](USAGE.md) for all variables and what they do.
|
||||
|
||||
Note that now the Dynarec of Box86 uses a mecanism with Memory Protection and a SegFault signal handler to handle JIT code. That means if you want to use gdb to debug running a program that use JIT'd code (like mono/Unity3D), you will have many "normal" segfaults triggering. I suggest you 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.
|
||||
|
||||
----
|
||||
|
||||
Version history
|
||||
----
|
||||
|
||||
The change log is available [here](CHANGELOG.md)
|
||||
|
||||
----
|
||||
|
||||
A note about 64-bit platforms
|
||||
----
|
||||
|
||||
Because Box86 works by directly translating function calls from x86 to host system, the host system (the one Box86 is running on) needs to have 32-bit libraries. Box86 doesn't include any 32-bit <-> 64-bit translation. So basically, to run Box86 on, for example, an ARM64 platform, you will need to build Box86 for ARM 32-bit, and also need to have a chroot with 32-bit libraries.
|
||||
|
||||
Also note that, even if, on day, there is a Box86_64, this one will only be able to run x86_64 binaries on 64-bit platforms. You will still need Box86 (and see 32-bit chroot) to run x86 binaries (in fact, the same is the case on actual x86_64 Linux).
|
||||
|
||||
----
|
||||
|
||||
A note 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 he new "protected memory" mechanism implemented it is 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 Mono games work and can require a high OpenGL profile, but the speed, for the ones running, should be correct now.
|
||||
|
||||
----
|
||||
|
||||
A note about Wine
|
||||
----
|
||||
|
||||
Wine is now partly supported. Wine integreted program all runs, annd some windows program and games now run fine. Don't forget most Windows games use Direct3D, that may require a complete OpenGL driver and as high profile as possible (and gl4es with ES2 backend have issue with Wine for now). Also, vulkan is not wrapped on box86, so vk3d is not usable yet, even if supported by the hardware.
|
||||
|
||||
----
|
||||
|
||||
Final words
|
||||
----
|
||||
|
||||
(If you use Box86 in your project, please don't forget to mention Box86)
|
||||
@@ -0,0 +1,132 @@
|
||||
Usage
|
||||
----
|
||||
|
||||
There are many environment variable to control Box86 behaviour.
|
||||
|
||||
##### BOX86_LOG
|
||||
Controls the Verbose level of the log
|
||||
* 0
|
||||
* NONE : No message (except some fatal error)
|
||||
* 1
|
||||
* INFO : Current default. Show some log
|
||||
* 2
|
||||
* DEBUG : Verbose a lot of stuffs (like relocations or function called)
|
||||
* 3
|
||||
* DUMP : All DEBUG plus DUMP of all ELF Info
|
||||
|
||||
#### BOX86_LD_LIBRARY_PATH
|
||||
Controls the folder scanned to look for x86 libs. Default is current folder and `lib` in current folder.
|
||||
Also `/usr/lib/i386-linux-gnu` and `/lib/i386-linux-gnu` are added if they exists
|
||||
|
||||
#### BOX86_PATH
|
||||
Controls the folder scanned to look for x86 executable. Default is current folder and `bin` in current folder.
|
||||
|
||||
#### BOX86_DLSYM_ERROR
|
||||
* 0 : default. Don't log `dlsym` error
|
||||
* 1 : Log dlsym error
|
||||
|
||||
#### BOX86_TRACE_FILE
|
||||
Send all log and trace to a file instead of `stdout`
|
||||
Also, if name contains `%pid` then this is replaced by actual PID of box86 instance
|
||||
|
||||
#### BOX86_TRACE
|
||||
Only on build with trace enabled. Trace allow the logging of all instruction execute, along with register dump
|
||||
* 0 : No trace
|
||||
* 1 : Trace enabled. The trace start after the init of all depending libs 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
|
||||
Use BOX86_TRACE_INIT instead of BOX_TRACE to start trace before init of Libs and main program
|
||||
* 0 : No trace
|
||||
* 1 : Trace enabled. The trace start with the init of all depending libs is done
|
||||
|
||||
#### BOX86_TRACE_START
|
||||
Only on build with trace enabled.
|
||||
* NNNNNNN : Start trace only after NNNNNNNN opcode execute (number is an `uint64_t`)
|
||||
|
||||
#### BOX86_TRACE_XMM
|
||||
Only on build with trace enabled.
|
||||
* 0 : Default, the XMM (i.e. SSE/SSE2) register will not be logged with the general and x87 registers
|
||||
* 1 : Dump the XMM registers
|
||||
|
||||
#### BOX86_LOAD_ADDR
|
||||
Try to load at 0xXXXXXX main binaray (if binary is a PIE)
|
||||
* 0xXXXXXXXX the load address (only active on PIE programs)
|
||||
|
||||
#### BOX86_NOSIGSEGV
|
||||
To disable handling of SigSEGV (to ease debugging mainly)
|
||||
* 0 : default, let x86 program set sighandler for SEGV
|
||||
* 1 : disable handling of SigSEGV
|
||||
|
||||
#### BOX86_NOSIGILL
|
||||
To disable handling of SigILL (to ease debugging mainly)
|
||||
* 0 : default, let x86 program set sighandler for Illegal Instruction
|
||||
* 1 : disable handling of SigILL
|
||||
|
||||
#### BOX86_X11COLOR16
|
||||
PANDORA only: to try convert X11 color from 32 bits to 16 bits (to avoid light green on light cyan windows
|
||||
* 0 : default, don't touch X11 colors
|
||||
* 1 : Change colors arguments in XSetForeground, XSetBackground and XCreateGC
|
||||
|
||||
#### BOX86_X11THREADS
|
||||
To call XInitThreads when loading X11 (for old Loki games with Loki_Compat lib)
|
||||
* 0 : default, don't force call XInitThreads
|
||||
* 1 : Call XInitThreads as soon as libX11 is loaded
|
||||
|
||||
#### BOX86_X11GLX
|
||||
To Force libX11 GLX extension to be present
|
||||
* 0 : Disable the force.
|
||||
* 1 : default, GLX will always be present when using XQueryExtension
|
||||
|
||||
#### BOX86_DYNAREC_DUMP
|
||||
* 0 : Disable Dynarec blocks dump (default)
|
||||
* 1 : Enable Dynarec blocks dump
|
||||
* 2 : Enable Dynarec blocks dump with some colors
|
||||
|
||||
#### BOX86_DYNAREC_LOG
|
||||
Set level of DynaRec log
|
||||
* 0 :
|
||||
* NONE : No Log for DynaRec
|
||||
* 1 :
|
||||
* INFO : Minimum Dynarec Log (only unimplemented OpCode)
|
||||
* 2 :
|
||||
* DEBUG : Debug Log for Dynarec (with detail on block created / executed)
|
||||
* 3 :
|
||||
* VERBOSE : All above plus more
|
||||
|
||||
#### BOX86_DYNAREC
|
||||
* 0 : Disable Dynarec
|
||||
* 1 : Enable Dynarec (default)
|
||||
|
||||
#### BOX86_DYNAREC_LINKER
|
||||
* 0 : Disable Dynarec Linker (use that on debug, with dynarec log >= 2, to have detail on wich block get executed)
|
||||
* 1 : Enable Dynarec Linker (default)
|
||||
|
||||
#### BOX86_DYNAREC_TRACE
|
||||
* 0 : Disable trace for generated code (default)
|
||||
* 1 : Enable trace for generated code (like regular Trace, this will slow down a lot and generate huge logs)
|
||||
|
||||
#### BOX86_LIBGL
|
||||
* libXXXX set the name for libGL (default to libGL.so.1)
|
||||
* /PATH/TO/libGLXXX set the name and path for libGL
|
||||
You can also use SDL_VIDEO_GL_DRIVER
|
||||
|
||||
#### 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
|
||||
|
||||
#### BOX86_EMULATED_LIBS
|
||||
* XXXX[:YYYYY] force lib XXXX (and YYYY...) to be emulated (and not wrapped)
|
||||
Some games use old version of some lib, 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 lib is missing
|
||||
* 0 : default, stop if a lib cannot be loaded
|
||||
* 1 : continue even if a needed lib cannot be loaded. Unadvised, this will, in most cases, crash later on.
|
||||
|
||||
#### BOX86_FIX_64BIT_INODES
|
||||
* 0 : Don't fix 64bit inodes (default)
|
||||
* 1 : Fix 64bit inodes. Helps when running on filesystems with 64bit inodes, the program uses API functions which don't support it and the program doesn't use inodes information.
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
if(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt")
|
||||
message(FATAL_ERROR "Cannot find install manifest: @CMAKE_BINARY_DIR@/install_manifest.txt")
|
||||
endif(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt")
|
||||
|
||||
file(READ "@CMAKE_BINARY_DIR@/install_manifest.txt" files)
|
||||
string(REGEX REPLACE "\n" ";" files "${files}")
|
||||
foreach(file ${files})
|
||||
message(STATUS "Uninstalling $ENV{DESTDIR}${file}")
|
||||
if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
|
||||
exec_program(
|
||||
"@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
|
||||
OUTPUT_VARIABLE rm_out
|
||||
RETURN_VALUE rm_retval
|
||||
)
|
||||
if(NOT "${rm_retval}" STREQUAL 0)
|
||||
message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}")
|
||||
endif(NOT "${rm_retval}" STREQUAL 0)
|
||||
else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
|
||||
message(STATUS "File $ENV{DESTDIR}${file} does not exist.")
|
||||
endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
|
||||
endforeach(file)
|
||||
Executable
+1984
File diff suppressed because it is too large.
Load diff
+304
-89
@@ -1,84 +1,226 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import os
|
||||
import glob
|
||||
import sys
|
||||
|
||||
values = ['E', 'e', 'v', 'c', 'w', 'i', 'I', 'C', 'W', 'u', 'U', 'f', 'd', 'D', 'L', 'p', 'V']
|
||||
values = ['E', 'e', 'v', 'c', 'w', 'i', 'I', 'C', 'W', 'u', 'U', 'f', 'd', 'D', 'K', 'l', 'L', 'p', 'V', 'O', 'S']
|
||||
def splitchar(s):
|
||||
ret = [len(s)]
|
||||
i = 0
|
||||
for c in s:
|
||||
i = i + 1
|
||||
if i == 2:
|
||||
continue
|
||||
ret.append(values.index(c))
|
||||
try:
|
||||
ret = [len(s), values.index(s[0])]
|
||||
for c in s[2:]:
|
||||
ret.append(values.index(c))
|
||||
return ret
|
||||
except ValueError as e:
|
||||
raise ValueError("Value is " + s) from e
|
||||
|
||||
def value(define):
|
||||
return define[9:-1] if define.startswith("!") else define[8:-1]
|
||||
|
||||
def splitdef(dnf, defines):
|
||||
cunjs = dnf.split(" || ")
|
||||
clauses = [c.split(" && ") for c in cunjs]
|
||||
|
||||
ret = [len(cunjs)]
|
||||
|
||||
for cunj in clauses:
|
||||
for c in cunj:
|
||||
ret.append(len(c))
|
||||
for cunj in clauses:
|
||||
for c in cunj:
|
||||
ret.append(defines.index(value(c)) * 2 + (1 if c.startswith("!") else 0))
|
||||
ret.append(0)
|
||||
return ret
|
||||
|
||||
def main(root):
|
||||
# Initialize variables: gbl for all values, vals for file-per-file values, redirects for redirections
|
||||
gbl = []
|
||||
vals = {}
|
||||
def invert(define):
|
||||
return define[1:] if define.startswith("!") else ("!" + define)
|
||||
|
||||
def main(root, defines, files, ver):
|
||||
global values
|
||||
|
||||
# Initialize variables: gbl for all values, redirects for redirections
|
||||
gbl = {}
|
||||
redirects = {}
|
||||
|
||||
# First read the files inside the headers
|
||||
for filepath in glob.glob(os.path.join(root, "src", "wrapped*_private.h")):
|
||||
for filepath in files:
|
||||
filename = filepath.split("/")[-1]
|
||||
locval = []
|
||||
dependants = []
|
||||
with open(filepath, 'r') as file:
|
||||
for line in file:
|
||||
ln = line.strip()
|
||||
# If the line is a `#' line (#ifdef LD80BITS/#ifndef LD80BITS/header)
|
||||
if ln.startswith("#"):
|
||||
preproc_cmd = ln[1:].strip()
|
||||
try:
|
||||
if preproc_cmd.startswith("if defined(GO)"):
|
||||
continue #if defined(GO) && defined(GOM)...
|
||||
elif preproc_cmd.startswith("if !(defined(GO)"):
|
||||
continue #if !(defined(GO) && defined(GOM)...)
|
||||
elif preproc_cmd.startswith("error"):
|
||||
continue #error meh!
|
||||
elif preproc_cmd.startswith("endif"):
|
||||
if dependants != []:
|
||||
dependants.pop()
|
||||
elif preproc_cmd.startswith("ifdef"):
|
||||
if preproc_cmd[5:].strip() not in defines:
|
||||
raise KeyError(preproc_cmd[5:].strip())
|
||||
dependants.append("defined(" + preproc_cmd[5:].strip() + ")")
|
||||
elif preproc_cmd.startswith("ifndef"):
|
||||
if preproc_cmd[6:].strip() not in defines:
|
||||
raise KeyError(preproc_cmd[6:].strip())
|
||||
dependants.append("!defined(" + preproc_cmd[6:].strip() + ")")
|
||||
elif preproc_cmd.startswith("else"):
|
||||
dependants[-1] = invert(dependants[-1])
|
||||
else:
|
||||
raise NotImplementedError("Unknown preprocessor directive: {0} ({1}:{2})".format(
|
||||
preproc_cmd.split(" ")[0], filename, line[:-1]
|
||||
))
|
||||
except KeyError as k:
|
||||
raise NotImplementedError("Unknown key: {0} ({1}:{2})".format(
|
||||
k.args[0], filename, line[:-1]
|
||||
), k)
|
||||
# If the line is a `GO...' line (GO/GOM/GO2/...)...
|
||||
if ln.startswith("GO"):
|
||||
elif ln.startswith("GO"):
|
||||
# ... then look at the second parameter of the line
|
||||
ln = ln.split(",")[1].split(")")[0].strip()
|
||||
|
||||
if ln[1] not in ["F"]:
|
||||
raise NotImplementedError("Bad middle letter {0} ({1}:{2})".format(ln[1], filename, line[:-1]))
|
||||
if any(c not in values for c in ln[2:]) or (('v' in ln[2:]) and (len(ln) > 3)):
|
||||
old = ln
|
||||
# This needs more work
|
||||
acceptables = ['v', 'o', '0', '1'] + values
|
||||
acceptables = ['v', '0', '1'] + values
|
||||
if any(c not in acceptables for c in ln[2:]):
|
||||
raise NotImplementedError("{0} ({1})".format(ln[2:], line))
|
||||
# Ok, this is acceptable: there is 0, 1, stdout and void
|
||||
raise NotImplementedError("{0} ({1}:{2})".format(ln[2:], filename, line[:-1]))
|
||||
# Ok, this is acceptable: there is 0, 1 and/or void
|
||||
ln = (ln
|
||||
.replace("v", "") # void -> nothing
|
||||
.replace("o", "p") # stdout -> pointer
|
||||
.replace("0", "p") # 0 -> pointer
|
||||
.replace("1", "i")) # 1 -> integer
|
||||
redirects[old] = ln
|
||||
redirects.setdefault(" && ".join(dependants), {})
|
||||
redirects[" && ".join(dependants)][old] = ln
|
||||
# Simply append the function name if it's not yet existing
|
||||
if ln not in locval:
|
||||
locval.append(ln)
|
||||
if ln not in gbl:
|
||||
gbl.append(ln)
|
||||
|
||||
# Sort the file local values and add it to the dictionary
|
||||
locval.sort(key=lambda v: splitchar(v))
|
||||
vals[filename] = locval
|
||||
gbl.setdefault(" && ".join(dependants), [])
|
||||
if ln not in gbl[" && ".join(dependants)]:
|
||||
gbl[" && ".join(dependants)].append(ln)
|
||||
|
||||
# Sort the table
|
||||
gbl.sort(key=lambda v: splitchar(v))
|
||||
|
||||
def length(s):
|
||||
l = len(s)
|
||||
if l < 10:
|
||||
ret = "0" + str(l)
|
||||
gbl_vals = {}
|
||||
for k in gbl:
|
||||
ks = k.split(" && ")
|
||||
for v in gbl[k]:
|
||||
if k == "":
|
||||
gbl_vals[v] = []
|
||||
continue
|
||||
if v in gbl_vals:
|
||||
if gbl_vals[v] == []:
|
||||
continue
|
||||
for other_key in gbl_vals[v]:
|
||||
other_key_vals = other_key.split(" && ")
|
||||
for other_key_val in other_key_vals:
|
||||
if other_key_val not in ks:
|
||||
break
|
||||
else:
|
||||
break
|
||||
else:
|
||||
gbl_vals[v].append(k)
|
||||
else:
|
||||
gbl_vals[v] = [k]
|
||||
for v in gbl_vals:
|
||||
for k in gbl_vals[v]:
|
||||
if " && ".join([invert(v2) for v2 in k.split(" && ")]) in gbl_vals[v]:
|
||||
gbl_vals[v] = []
|
||||
break
|
||||
gbl = {}
|
||||
gbl_idxs = []
|
||||
for k in gbl_vals:
|
||||
if len(gbl_vals[k]) == 1:
|
||||
key = gbl_vals[k][0]
|
||||
else:
|
||||
ret = str(l)
|
||||
return ret
|
||||
key = "(" + (") || (".join(gbl_vals[k])) + ")"
|
||||
gbl[key] = gbl.get(key, []) + [k]
|
||||
if (key not in gbl_idxs) and (key != "()"):
|
||||
gbl_idxs.append(key)
|
||||
gbl_idxs.sort(key=lambda v: splitdef(v, defines))
|
||||
|
||||
redirects_vals = {}
|
||||
for k in redirects:
|
||||
ks = k.split(" && ")
|
||||
for v in redirects[k]:
|
||||
if k == "":
|
||||
redirects_vals[(v, redirects[k][v])] = []
|
||||
continue
|
||||
if (v, redirects[k][v]) in redirects_vals:
|
||||
if redirects_vals[(v, redirects[k][v])] == []:
|
||||
continue
|
||||
for other_key in redirects_vals[(v, redirects[k][v])]:
|
||||
if other_key == "()":
|
||||
break
|
||||
other_key_vals = other_key.split(" && ")
|
||||
for other_key_val in other_key_vals:
|
||||
if other_key_val not in ks:
|
||||
break
|
||||
else:
|
||||
break
|
||||
else:
|
||||
redirects_vals[(v, redirects[k][v])].append(k)
|
||||
else:
|
||||
redirects_vals[(v, redirects[k][v])] = [k]
|
||||
redirects = {}
|
||||
redirects_idxs = []
|
||||
for k, v in redirects_vals:
|
||||
key = "(" + (") || (".join(redirects_vals[(k, v)])) + ")"
|
||||
if key in redirects:
|
||||
redirects[key].append([k, v])
|
||||
else:
|
||||
redirects[key] = [[k, v]]
|
||||
if (key not in redirects_idxs) and (key != "()"):
|
||||
redirects_idxs.append(key)
|
||||
redirects_idxs.sort(key=lambda v: splitdef(v, defines))
|
||||
|
||||
# Sort the tables
|
||||
for k in gbl:
|
||||
gbl[k].sort(key=lambda v: splitchar(v))
|
||||
values = values + ['0', '1']
|
||||
for k in redirects:
|
||||
redirects[k].sort(key=lambda v: splitchar(v[0]) + [0] + splitchar(v[1]))
|
||||
values = values[:-2]
|
||||
|
||||
# Check if there was any new functions
|
||||
functions_list = ""
|
||||
for k in ["()"] + gbl_idxs:
|
||||
for v in gbl[k]:
|
||||
functions_list = functions_list + "#" + k + " " + v + "\n"
|
||||
for k in ["()"] + redirects_idxs:
|
||||
for v in redirects[k]:
|
||||
functions_list = functions_list + "#" + k + " " + v[0] + " -> " + v[1] + "\n"
|
||||
|
||||
# functions_list is a unique string, compare it with the last run
|
||||
try:
|
||||
last_run = ""
|
||||
with open(os.path.join(root, "src", "wrapped", "generated", "functions_list.txt"), 'r') as file:
|
||||
last_run = file.read()
|
||||
if last_run == functions_list:
|
||||
# Mark as OK for CMake
|
||||
with open(os.path.join(root, "src", "wrapped", "generated", "functions_list.txt"), 'w') as file:
|
||||
file.write(functions_list)
|
||||
#return 0
|
||||
except IOError:
|
||||
# The file does not exist yet, first run
|
||||
pass
|
||||
|
||||
# Now the files rebuilding part
|
||||
# File headers and guards
|
||||
files_headers = {
|
||||
"wrapper.c": """/*****************************************************************
|
||||
* File automatically generated by rebuild_wrappers.py (v1.0.0.02)
|
||||
* File automatically generated by rebuild_wrappers.py (v%s)
|
||||
*****************************************************************/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "wrapper.h"
|
||||
#include "x86emu_private.h"
|
||||
#include "x87emu_private.h"
|
||||
#include "emu/x86emu_private.h"
|
||||
#include "emu/x87emu_private.h"
|
||||
#include "regs.h"
|
||||
#include "x86emu.h"
|
||||
|
||||
@@ -88,9 +230,32 @@ typedef union ui64_s {
|
||||
uint32_t d[2];
|
||||
} ui64_t;
|
||||
|
||||
extern void* my__IO_2_1_stderr_;
|
||||
extern void* my__IO_2_1_stdin_ ;
|
||||
extern void* my__IO_2_1_stdout_;
|
||||
|
||||
static void* io_convert(void* v)
|
||||
{
|
||||
if(!v)
|
||||
return v;
|
||||
if(v==my__IO_2_1_stderr_)
|
||||
return stderr;
|
||||
if(v==my__IO_2_1_stdin_)
|
||||
return stdin;
|
||||
if(v==my__IO_2_1_stdout_)
|
||||
return stdout;
|
||||
return v;
|
||||
}
|
||||
|
||||
#ifdef USE_FLOAT
|
||||
#define ST0val ST0.f
|
||||
#else
|
||||
#define ST0val ST0.d
|
||||
#endif
|
||||
int of_convert(int);
|
||||
""",
|
||||
"wrapper.h": """/*****************************************************************
|
||||
* File automatically generated by rebuild_wrappers.py (v1.0.0.02)
|
||||
* File automatically generated by rebuild_wrappers.py (v%s)
|
||||
*****************************************************************/
|
||||
#ifndef __WRAPPER_H_
|
||||
#define __WRAPPER_H_
|
||||
@@ -103,13 +268,16 @@ typedef void (*wrapper_t)(x86emu_t* emu, uintptr_t fnc);
|
||||
|
||||
// list of defined wrapper
|
||||
// v = void, i = int32, u = uint32, U/I= (u)int64
|
||||
// l = signed long, L = unsigned long (long is an int with the size of a pointer)
|
||||
// p = pointer, P = callback
|
||||
// f = float, d = double, D = long double, L = fake long double
|
||||
// f = float, d = double, D = long double, K = fake long double
|
||||
// V = vaargs, E = current x86emu struct, e = ref to current x86emu struct
|
||||
// 0 = constant 0, 1 = constant 1
|
||||
// o = stdout
|
||||
// C = unsigned byte c = char
|
||||
// W = unsigned short w = short
|
||||
// O = libc O_ flags bitfield
|
||||
// S = _IO_2_1_stdXXX_ pointer (or FILE*)
|
||||
// Q = ...
|
||||
// S8 = struct, 8 bytes
|
||||
|
||||
@@ -121,32 +289,52 @@ typedef void (*wrapper_t)(x86emu_t* emu, uintptr_t fnc);
|
||||
"""
|
||||
}
|
||||
|
||||
# Transform strings into arrays
|
||||
gbl = [[c for c in v] for v in gbl]
|
||||
|
||||
# Rewrite the wrapper.h file:
|
||||
with open(os.path.join(root, "src", "wrapper.h"), 'w') as file:
|
||||
file.write(files_headers["wrapper.h"])
|
||||
for v in gbl:
|
||||
file.write("void " + ''.join(v) + "(x86emu_t *emu, uintptr_t fnc);\n")
|
||||
for v in redirects:
|
||||
file.write("void " + ''.join(v) + "(x86emu_t *emu, uintptr_t fnc);\n")
|
||||
with open(os.path.join(root, "src", "wrapped", "generated", "wrapper.h"), 'w') as file:
|
||||
file.write(files_headers["wrapper.h"] % ver)
|
||||
for v in gbl["()"]:
|
||||
file.write("void " + v + "(x86emu_t *emu, uintptr_t fnc);\n")
|
||||
for k in gbl_idxs:
|
||||
file.write("\n#if " + k + "\n")
|
||||
for v in gbl[k]:
|
||||
file.write("void " + v + "(x86emu_t *emu, uintptr_t fnc);\n")
|
||||
file.write("#endif\n")
|
||||
file.write("\n")
|
||||
for v in redirects["()"]:
|
||||
file.write("void " + v[0] + "(x86emu_t *emu, uintptr_t fnc);\n")
|
||||
for k in redirects_idxs:
|
||||
file.write("\n#if " + k + "\n")
|
||||
for v in redirects[k]:
|
||||
file.write("void " + v[0] + "(x86emu_t *emu, uintptr_t fnc);\n")
|
||||
file.write("#endif\n")
|
||||
file.write(files_guards["wrapper.h"])
|
||||
|
||||
# Rewrite the wrapper.c file:
|
||||
with open(os.path.join(root, "src", "wrapper.c"), 'w') as file:
|
||||
file.write(files_headers["wrapper.c"])
|
||||
with open(os.path.join(root, "src", "wrapped", "generated", "wrapper.c"), 'w') as file:
|
||||
file.write(files_headers["wrapper.c"] % ver)
|
||||
|
||||
# First part: typedefs
|
||||
for v in gbl:
|
||||
# E e v c w i I C W u U f d D L p V
|
||||
types = ["x86emu_t*", "x86emu_t**", "void", "int8_t", "int16_t", "int32_t", "int64_t", "uint8_t", "uint16_t", "uint32_t", "uint64_t", "float", "double", "long double", "double", "void*", "void*"]
|
||||
for v in gbl["()"]:
|
||||
# E e v c w i I C W u U f d D K l L p V O S
|
||||
types = ["x86emu_t*", "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*"]
|
||||
if len(values) != len(types):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(types) = {lentypes}".format(lenval=len(values), lentypes=len(types)))
|
||||
raise NotImplementedError("len(values) = {lenval} != len(types) = {lentypes}".format(lenval=len(values), lentypes=len(types)))
|
||||
|
||||
file.write("typedef " + types[values.index(v[0])] + " (*" + ''.join(v) + "_t)"
|
||||
file.write("typedef " + types[values.index(v[0])] + " (*" + v + "_t)"
|
||||
+ "(" + ', '.join(types[values.index(t)] for t in v[2:]) + ");\n")
|
||||
for k in gbl_idxs:
|
||||
file.write("\n#if " + k + "\n")
|
||||
for v in gbl[k]:
|
||||
# E e v c w i I C W u U f d D K l L p V O S
|
||||
types = ["x86emu_t*", "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*"]
|
||||
if len(values) != len(types):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(types) = {lentypes}".format(lenval=len(values), lentypes=len(types)))
|
||||
|
||||
file.write("typedef " + types[values.index(v[0])] + " (*" + v + "_t)"
|
||||
+ "(" + ', '.join(types[values.index(t)] for t in v[2:]) + ");\n")
|
||||
file.write("#endif\n")
|
||||
|
||||
file.write("\n")
|
||||
# Next part: function definitions
|
||||
|
||||
# Helper functions to write the function definitions
|
||||
@@ -154,34 +342,38 @@ typedef void (*wrapper_t)(x86emu_t* emu, uintptr_t fnc);
|
||||
if len(args) == 0:
|
||||
return ""
|
||||
if d % 4 != 0:
|
||||
raise ValueError("{d} is not a multiple of 4. Did you try passing a V and something else?")
|
||||
raise ValueError("{d} is not a multiple of 4. Did you try passing a V and something else?".format(d=d))
|
||||
|
||||
if args[0] == "0":
|
||||
return "(void*)(R_ESP + {p}), ".format(p=d) + function_args(args[1:], d + 4)
|
||||
elif args[0] == 1:
|
||||
elif args[0] == "1":
|
||||
return "1, " + function_args(args[1:], d)
|
||||
|
||||
arg = [
|
||||
"emu, ", # E
|
||||
"&emu, ", # e
|
||||
"", # v
|
||||
"*(int8_t*)(R_ESP + {p}), ", # c
|
||||
"*(int16_t*)(R_ESP + {p}), ", # w
|
||||
"*(int32_t*)(R_ESP + {p}), ", # i
|
||||
"*(int64_t*)(R_ESP + {p}), ", # I
|
||||
"*(uint8_t*)(R_ESP + {p}), ", # C
|
||||
"*(uint16_t*)(R_ESP + {p}), ", # W
|
||||
"*(uint32_t*)(R_ESP + {p}), ", # u
|
||||
"*(uint64_t*)(R_ESP + {p}), ", # U
|
||||
"*(float*)(R_ESP + {p}), ", # f
|
||||
"*(double*)(R_ESP + {p}), ", # d
|
||||
"*(long double*)(R_ESP + {p}), ", # D
|
||||
"FromLD((void*)(R_ESP + {p})), ", # L
|
||||
"*(void**)(R_ESP + {p}), ", # p
|
||||
"(void*)(R_ESP + {p}), " # V
|
||||
"emu, ", # E
|
||||
"&emu, ", # e
|
||||
"", # v
|
||||
"*(int8_t*)(R_ESP + {p}), ", # c
|
||||
"*(int16_t*)(R_ESP + {p}), ", # w
|
||||
"*(int32_t*)(R_ESP + {p}), ", # i
|
||||
"*(int64_t*)(R_ESP + {p}), ", # I
|
||||
"*(uint8_t*)(R_ESP + {p}), ", # C
|
||||
"*(uint16_t*)(R_ESP + {p}), ", # W
|
||||
"*(uint32_t*)(R_ESP + {p}), ", # u
|
||||
"*(uint64_t*)(R_ESP + {p}), ", # U
|
||||
"*(float*)(R_ESP + {p}), ", # f
|
||||
"*(double*)(R_ESP + {p}), ", # d
|
||||
"*(long double*)(R_ESP + {p}), ", # D
|
||||
"FromLD((void*)(R_ESP + {p})), ", # K
|
||||
"*(intptr_t*)(R_ESP + {p}), ", # l
|
||||
"*(uintptr_t*)(R_ESP + {p}), ", # L
|
||||
"*(void**)(R_ESP + {p}), ", # p
|
||||
"(void*)(R_ESP + {p}), ", # V
|
||||
"of_convert(*(int32_t*)(R_ESP + {p})), ", # O
|
||||
"io_convert(*(void**)(R_ESP + {p})), ", # S
|
||||
]
|
||||
# E e v c w i I C W u U f d D L p V
|
||||
deltas = [0, 0, 4, 4, 4, 4, 8, 4, 4, 4, 8, 4, 8, 12, 12, 4, 0]
|
||||
# E e v c w i I C W u U f d D K l L p V O S
|
||||
deltas = [0, 0, 4, 4, 4, 4, 8, 4, 4, 4, 8, 4, 8, 12, 12, 4, 4, 4, 0, 4, 4]
|
||||
if len(values) != len(arg):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(arg) = {lenarg}".format(lenval=len(values), lenarg=len(arg)))
|
||||
if len(values) != len(deltas):
|
||||
@@ -202,27 +394,50 @@ typedef void (*wrapper_t)(x86emu_t* emu, uintptr_t fnc);
|
||||
"R_EAX=(unsigned short)fn({0});", # W
|
||||
"R_EAX=(uint32_t)fn({0});", # u
|
||||
"ui64_t r; r.u=(uint64_t)fn({0}); R_EAX=r.d[0]; R_EDX=r.d[1];", # U
|
||||
"float fl=fn({0}); fpu_do_push(emu); ST0.d = fl;", # f
|
||||
"double db=fn({0}); fpu_do_push(emu); ST0.d = db;", # d
|
||||
"long double ld=fn({0}); fpu_do_push(emu); ST0.d = ld;", # D
|
||||
"double db=fn({0}); fpu_do_push(emu); ST0.d = db;", # L
|
||||
"float fl=fn({0}); fpu_do_push(emu); ST0val = fl;", # f
|
||||
"double db=fn({0}); fpu_do_push(emu); ST0val = db;", # d
|
||||
"long double ld=fn({0}); fpu_do_push(emu); ST0val = ld;", # D
|
||||
"double db=fn({0}); fpu_do_push(emu); ST0val = db;", # K
|
||||
"R_EAX=(intptr_t)fn({0});", # l
|
||||
"R_EAX=(uintptr_t)fn({0});", # L
|
||||
"R_EAX=(uintptr_t)fn({0});", # p
|
||||
"\n#error Invalid return type: va_list\n", # V
|
||||
"\n#error Invalid return type: at_flags\n", # O
|
||||
"\n#error Invalid return type: _io_file*\n", # S
|
||||
]
|
||||
if len(values) != len(vals):
|
||||
raise NotImplementedError("len(values) = {lenval} != len(vals) = {lenvals}".format(lenval=len(values), lenvals=len(vals)))
|
||||
f.write(vals[values.index(rettype)].format(function_args(args)[:-2]) + " }\n")
|
||||
|
||||
for v in gbl:
|
||||
function_writer(file, ''.join(v), ''.join(v) + "_t", v[0], v[2:])
|
||||
for v in redirects:
|
||||
function_writer(file, v, redirects[v] + "_t", v[0], v[2:])
|
||||
for v in gbl["()"]:
|
||||
function_writer(file, v, v + "_t", v[0], v[2:])
|
||||
for k in gbl_idxs:
|
||||
file.write("\n#if " + k + "\n")
|
||||
for v in gbl[k]:
|
||||
function_writer(file, v, v + "_t", v[0], v[2:])
|
||||
file.write("#endif\n")
|
||||
file.write("\n")
|
||||
for v in redirects["()"]:
|
||||
function_writer(file, v[0], v[1] + "_t", v[0][0], v[0][2:])
|
||||
for k in redirects_idxs:
|
||||
file.write("\n#if " + k + "\n")
|
||||
for v in redirects[k]:
|
||||
function_writer(file, v[0], v[1] + "_t", v[0][0], v[0][2:])
|
||||
file.write("#endif\n")
|
||||
|
||||
file.write(files_guards["wrapper.c"])
|
||||
|
||||
# Save the string for the next iteration, writing was successful
|
||||
with open(os.path.join(root, "src", "wrapped", "generated", "functions_list.txt"), 'w') as file:
|
||||
file.write(functions_list)
|
||||
|
||||
return 0
|
||||
|
||||
if __name__ == '__main__':
|
||||
if main(sys.argv[1]) != 0:
|
||||
limit = []
|
||||
for i, v in enumerate(sys.argv):
|
||||
if v == "--":
|
||||
limit.append(i)
|
||||
if main(sys.argv[1], sys.argv[2:limit[0]], sys.argv[limit[0]+1:], "1.2.0.09") != 0:
|
||||
exit(2)
|
||||
exit(0)
|
||||
@@ -13,6 +13,14 @@ if( NOT TEST_REFERENCE )
|
||||
endif( NOT TEST_REFERENCE )
|
||||
|
||||
set(ENV{BOX86_LOG} 0)
|
||||
if( EXISTS ${CMAKE_SOURCE_DIR}/x86lib )
|
||||
# we are inside box86 folder
|
||||
set(ENV{LD_LIBRARY_PATH} ${CMAKE_SOURCE_DIR}/x86lib)
|
||||
else()
|
||||
# we are inside build folder
|
||||
set(ENV{LD_LIBRARY_PATH} ${CMAKE_SOURCE_DIR}/../x86lib)
|
||||
endif( EXISTS ${CMAKE_SOURCE_DIR}/x86lib )
|
||||
|
||||
# run the test program, capture the stdout/stderr and the result var
|
||||
execute_process(
|
||||
COMMAND ${TEST_PROGRAM} ${TEST_ARGS} ${TEST_ARGS2}
|
||||
|
||||
+422
-45
@@ -1,8 +1,9 @@
|
||||
#define _GNU_SOURCE /* See feature_test_macros(7) */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#define _GNU_SOURCE /* See feature_test_macros(7) */
|
||||
#include <dlfcn.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "box86context.h"
|
||||
#include "elfloader.h"
|
||||
@@ -13,89 +14,434 @@
|
||||
#include "bridge.h"
|
||||
#include "library.h"
|
||||
#include "callback.h"
|
||||
#include "wrapper.h"
|
||||
#include "myfts.h"
|
||||
#include "threads.h"
|
||||
#include "x86trace.h"
|
||||
#include "signals.h"
|
||||
#ifdef DYNAREC
|
||||
#include <sys/mman.h>
|
||||
#include "dynablock.h"
|
||||
|
||||
#define MMAPSIZE (4*1024*1024) // allocate 4Mo sized blocks
|
||||
#define MMAPBLOCK 256 // minimum size of a block
|
||||
|
||||
typedef struct mmaplist_s {
|
||||
void* block;
|
||||
uint8_t map[MMAPSIZE/(8*MMAPBLOCK)]; // map of allocated sub-block
|
||||
} mmaplist_t;
|
||||
|
||||
// get first subblock free in map, stating at start. return -1 if no block, else first subblock free, filling size (in subblock unit)
|
||||
static int getFirstBlock(mmaplist_t *map, int start, int maxsize, int* size)
|
||||
{
|
||||
#define ISFREE(A) (((map->map[(A)>>3]>>((A)&7))&1)?0:1)
|
||||
if(start<0) start = 0;
|
||||
while(start<MMAPSIZE/(8*MMAPBLOCK)) { // still a chance...
|
||||
if(ISFREE(start)) {
|
||||
// free, now get size...
|
||||
int end = start+1;
|
||||
while(end<MMAPSIZE/(8*MMAPBLOCK)) {
|
||||
if(!ISFREE(end) || (end-start==maxsize)) {
|
||||
if(size) *size = end-start;
|
||||
return start;
|
||||
}
|
||||
++end;
|
||||
}
|
||||
if(size) *size = end-start;
|
||||
return start;
|
||||
}
|
||||
++start;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void allocBlock(mmaplist_t *map, int start, int size)
|
||||
{
|
||||
for(int i=0; i<size; ++i) {
|
||||
map->map[start/8]|=(1<<(start&7));
|
||||
++start;
|
||||
}
|
||||
}
|
||||
static void freeBlock(mmaplist_t *map, int start, int size)
|
||||
{
|
||||
for(int i=0; i<size; ++i) {
|
||||
map->map[start/8]&=~(1<<(start&7));
|
||||
++start;
|
||||
}
|
||||
}
|
||||
|
||||
uintptr_t AllocDynarecMap(int size, int nolinker)
|
||||
{
|
||||
if(size>MMAPSIZE) {
|
||||
void* p = mmap(NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
if(p==MAP_FAILED) {
|
||||
dynarec_log(LOG_DEBUG, "Cannot create dynamic map of %d bytes\n", size);
|
||||
return 0;
|
||||
}
|
||||
return (uintptr_t)p;
|
||||
}
|
||||
pthread_mutex_lock(&my_context->mutex_mmap);
|
||||
int bsize = (size+MMAPBLOCK-1)/MMAPBLOCK;
|
||||
// look for free space
|
||||
for(int i=0; i<my_context->mmapsize; ++i) {
|
||||
int rsize = 0;
|
||||
int start = 0;
|
||||
do {
|
||||
start = getFirstBlock(my_context->mmaplist+i, start, bsize, &rsize);
|
||||
if(start!=-1 && rsize>=bsize) {
|
||||
allocBlock(my_context->mmaplist+i, start, bsize);
|
||||
uintptr_t ret = (uintptr_t)my_context->mmaplist[i].block + start*MMAPBLOCK;
|
||||
pthread_mutex_unlock(&my_context->mutex_mmap);
|
||||
return ret;
|
||||
}
|
||||
if(start!=-1)
|
||||
start += rsize;
|
||||
} while (start!=-1);
|
||||
}
|
||||
// no luck, add a new one !
|
||||
int i = my_context->mmapsize++; // yeah, useful post incrementation
|
||||
dynarec_log(LOG_DEBUG, "Ask for DynaRec Block Alloc #%d\n", my_context->mmapsize);
|
||||
my_context->mmaplist = (mmaplist_t*)realloc(my_context->mmaplist, my_context->mmapsize*sizeof(mmaplist_t));
|
||||
void* p = mmap(NULL, MMAPSIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
if(p==MAP_FAILED) {
|
||||
dynarec_log(LOG_DEBUG, "Cannot create memory map of %d byte for dynarec block #%d\n", MMAPSIZE, i);
|
||||
--my_context->mmapsize;
|
||||
pthread_mutex_unlock(&my_context->mutex_mmap);
|
||||
return 0;
|
||||
}
|
||||
my_context->mmaplist[i].block = p;
|
||||
memset(my_context->mmaplist[i].map, 0, sizeof(my_context->mmaplist[i].map));
|
||||
allocBlock(my_context->mmaplist+i, 0, bsize);
|
||||
pthread_mutex_unlock(&my_context->mutex_mmap);
|
||||
return (uintptr_t)p;
|
||||
}
|
||||
|
||||
void FreeDynarecMap(uintptr_t addr, uint32_t size)
|
||||
{
|
||||
if(size>MMAPSIZE) {
|
||||
munmap((void*)addr, size);
|
||||
return;
|
||||
}
|
||||
pthread_mutex_lock(&my_context->mutex_mmap);
|
||||
int bsize = (size+MMAPBLOCK-1)/MMAPBLOCK;
|
||||
// look for free space
|
||||
for(int i=0; i<my_context->mmapsize; ++i) {
|
||||
if(addr>=(uintptr_t)my_context->mmaplist[i].block && ((uintptr_t)my_context->mmaplist[i].block+MMAPSIZE)>=addr+size) {
|
||||
int start = (addr - (uintptr_t)my_context->mmaplist[i].block) / MMAPBLOCK;
|
||||
freeBlock(my_context->mmaplist+i, start, bsize);
|
||||
pthread_mutex_unlock(&my_context->mutex_mmap);
|
||||
return;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&my_context->mutex_mmap);
|
||||
}
|
||||
|
||||
// each dynmap is 64k of size
|
||||
dynablocklist_t* getDBFromAddress(uintptr_t addr)
|
||||
{
|
||||
int idx = (addr>>16);
|
||||
if(!my_context->dynmap[idx]) {
|
||||
return NULL;
|
||||
}
|
||||
return my_context->dynmap[idx]->dynablocks;
|
||||
}
|
||||
|
||||
void addDBFromAddressRange(uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
dynarec_log(LOG_DEBUG, "addDBFromAddressRange %p -> %p\n", (void*)addr, (void*)(addr+size-1));
|
||||
uintptr_t idx = (addr>>16);
|
||||
uintptr_t end = ((addr+size-1)>>16);
|
||||
for (uintptr_t i=idx; i<=end; ++i) {
|
||||
if(!my_context->dynmap[i]) {
|
||||
my_context->dynmap[i] = (dynmap_t*)calloc(1, sizeof(dynmap_t));
|
||||
my_context->dynmap[i]->dynablocks = NewDynablockList(i<<16, i<<16, 1<<16, 1, 0);
|
||||
}
|
||||
}
|
||||
protectDB(addr, size);
|
||||
}
|
||||
|
||||
void cleanDBFromAddressRange(uintptr_t addr, uintptr_t size, int destroy)
|
||||
{
|
||||
dynarec_log(LOG_DEBUG, "cleanDBFromAddressRange %p -> %p %s\n", (void*)addr, (void*)(addr+size-1), destroy?"destroy":"mark");
|
||||
uintptr_t idx = (addr>box86_dynarec_largest && !destroy)?((addr-box86_dynarec_largest)>>16):(addr>>16);
|
||||
uintptr_t end = ((addr+size-1)>>16);
|
||||
for (uintptr_t i=idx; i<=end; ++i) {
|
||||
dynmap_t* dynmap = my_context->dynmap[i];
|
||||
if(dynmap) {
|
||||
uintptr_t startdb = StartDynablockList(dynmap->dynablocks);
|
||||
uintptr_t enddb = EndDynablockList(dynmap->dynablocks);
|
||||
uintptr_t startaddr = addr;
|
||||
if(startaddr<startdb) startaddr = startdb;
|
||||
uintptr_t endaddr = addr + size - 1;
|
||||
if(endaddr>enddb) endaddr = enddb;
|
||||
if(startaddr==startdb && endaddr==enddb) {
|
||||
if(destroy) {
|
||||
my_context->dynmap[i] = NULL;
|
||||
FreeDynablockList(&dynmap->dynablocks);
|
||||
free(dynmap);
|
||||
} else
|
||||
MarkDynablockList(&dynmap->dynablocks);
|
||||
} else
|
||||
if(destroy)
|
||||
FreeRangeDynablock(dynmap->dynablocks, startaddr, endaddr-startaddr+1);
|
||||
else
|
||||
MarkRangeDynablock(dynmap->dynablocks, startaddr, endaddr-startaddr+1);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the Write flag from an adress range, so DB can be executed
|
||||
// no log, as it can be executed inside a signal handler
|
||||
void protectDB(uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
uintptr_t start = (addr)&~(box86_pagesize-1);
|
||||
uintptr_t end = (addr+size+(box86_pagesize-1))&~(box86_pagesize-1);
|
||||
// should get "end" according to last block inside the window
|
||||
mprotect((void*)start, end-start, PROT_READ|PROT_EXEC);
|
||||
}
|
||||
|
||||
// Add the Write flag from an adress range, and mark all block as dirty
|
||||
// no log, as it can be executed inside a signal handler
|
||||
void unprotectDB(uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
uintptr_t start = (addr)&~(box86_pagesize-1);
|
||||
uintptr_t end = (addr+size+(box86_pagesize-1))&~(box86_pagesize-1);
|
||||
// should get "end" according to last block inside the window
|
||||
mprotect((void*)start, end-start, PROT_READ|PROT_WRITE|PROT_EXEC);
|
||||
cleanDBFromAddressRange(start, end-start, 0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
EXPORTDYN
|
||||
void initAllHelpers(box86context_t* context)
|
||||
{
|
||||
static int inited = 0;
|
||||
if(inited)
|
||||
return;
|
||||
my_context = context;
|
||||
init_pthread_helper();
|
||||
init_signal_helper();
|
||||
inited = 1;
|
||||
}
|
||||
|
||||
EXPORTDYN
|
||||
void finiAllHelpers()
|
||||
{
|
||||
static int finied = 0;
|
||||
if(finied)
|
||||
return;
|
||||
fini_pthread_helper();
|
||||
fini_signal_helper();
|
||||
finied = 1;
|
||||
}
|
||||
|
||||
void x86Syscall(x86emu_t *emu);
|
||||
|
||||
/// maxval not inclusive
|
||||
int getrand(int maxval)
|
||||
{
|
||||
if(maxval<1024) {
|
||||
return ((random()&0x7fff)*maxval)/0x7fff;
|
||||
} else {
|
||||
uint64_t r = random();
|
||||
r = (r*maxval) / RAND_MAX;
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
void free_tlsdatasize(void* p)
|
||||
{
|
||||
if(!p)
|
||||
return;
|
||||
tlsdatasize_t *data = (tlsdatasize_t*)p;
|
||||
free(data->tlsdata);
|
||||
free(p);
|
||||
}
|
||||
|
||||
EXPORTDYN
|
||||
box86context_t *NewBox86Context(int argc)
|
||||
{
|
||||
#ifdef BUILD_DYNAMIC
|
||||
if(my_context) {
|
||||
++my_context->count;
|
||||
return my_context;
|
||||
}
|
||||
#endif
|
||||
// init and put default values
|
||||
box86context_t *context = (box86context_t*)calloc(1, sizeof(box86context_t));
|
||||
|
||||
#ifdef BUILD_LIB
|
||||
context->deferedInit = 0;
|
||||
#else
|
||||
context->deferedInit = 1;
|
||||
|
||||
context->maplib = NewLibrarian();
|
||||
#endif
|
||||
context->maplib = NewLibrarian(context, 1);
|
||||
context->local_maplib = NewLibrarian(context, 1);
|
||||
context->system = NewBridge();
|
||||
// create vsyscall
|
||||
context->vsyscall = AddBridge(context->system, vFv, x86Syscall);
|
||||
|
||||
context->vsyscall = AddBridge(context->system, vFv, x86Syscall, 0);
|
||||
#ifdef BUILD_LIB
|
||||
context->box86lib = RTLD_DEFAULT; // not ideal
|
||||
#else
|
||||
context->box86lib = dlopen(NULL, RTLD_NOW|RTLD_GLOBAL);
|
||||
#endif
|
||||
context->dlprivate = NewDLPrivate();
|
||||
|
||||
context->callbacks = NewCallbackList();
|
||||
|
||||
context->argc = argc;
|
||||
context->argv = (char**)calloc(context->argc, sizeof(char*));
|
||||
context->argv = (char**)calloc(context->argc+1, sizeof(char*));
|
||||
|
||||
pthread_mutex_init(&context->mutex_once, NULL);
|
||||
pthread_mutex_init(&context->mutex_once2, NULL);
|
||||
pthread_mutex_init(&context->mutex_trace, NULL);
|
||||
pthread_mutex_init(&context->mutex_lock, NULL);
|
||||
pthread_mutex_init(&context->mutex_thread, NULL);
|
||||
|
||||
pthread_key_create(&context->tlskey, free_tlsdatasize);
|
||||
|
||||
#ifdef DYNAREC
|
||||
pthread_mutex_init(&context->mutex_blocks, NULL);
|
||||
pthread_mutex_init(&context->mutex_mmap, NULL);
|
||||
context->dynablocks = NewDynablockList(0, 0, 0, 0, 0);
|
||||
#endif
|
||||
InitFTSMap(context);
|
||||
|
||||
for (int i=0; i<4; ++i) context->canary[i] = 1 + getrand(255);
|
||||
context->canary[getrand(4)] = 0;
|
||||
printf_log(LOG_DEBUG, "Setting up canary (for Stack protector) at GS:0x14, value:%08X\n", *(uint32_t*)context->canary);
|
||||
|
||||
initAllHelpers(context);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
EXPORTDYN
|
||||
void FreeBox86Context(box86context_t** context)
|
||||
{
|
||||
#ifdef BUILD_DYNAMIC
|
||||
if(--(*context)->count)
|
||||
return;
|
||||
#endif
|
||||
if(!context)
|
||||
return;
|
||||
|
||||
if(--(*context)->forked >= 0)
|
||||
return;
|
||||
|
||||
if((*context)->emu)
|
||||
FreeX86Emu(&(*context)->emu);
|
||||
box86context_t* ctx = *context; // local copy to do the cleanning
|
||||
|
||||
FreeCollection(&(*context)->box86_path);
|
||||
FreeCollection(&(*context)->box86_ld_lib);
|
||||
if((*context)->zydis)
|
||||
DeleteX86Trace(*context);
|
||||
|
||||
if((*context)->deferedInitList)
|
||||
free((*context)->deferedInitList);
|
||||
|
||||
if((*context)->box86lib)
|
||||
dlclose((*context)->box86lib);
|
||||
|
||||
FreeDLPrivate(&(*context)->dlprivate);
|
||||
|
||||
if((*context)->maplib)
|
||||
FreeLibrarian(&(*context)->maplib);
|
||||
|
||||
for(int i=0; i<(*context)->argc; ++i)
|
||||
free((*context)->argv[i]);
|
||||
free((*context)->argv);
|
||||
|
||||
for (int i=0; i<(*context)->envc; ++i)
|
||||
free((*context)->envv[i]);
|
||||
free((*context)->envv);
|
||||
|
||||
for(int i=0; i<(*context)->elfsize; ++i) {
|
||||
FreeElfHeader(&(*context)->elfs[i]);
|
||||
for(int i=0; i<ctx->elfsize; ++i) {
|
||||
FreeElfHeader(&ctx->elfs[i]);
|
||||
}
|
||||
free((*context)->elfs);
|
||||
free(ctx->elfs);
|
||||
|
||||
free((*context)->stack);
|
||||
FreeFTSMap(ctx);
|
||||
|
||||
FreeBridge(&(*context)->system);
|
||||
if(ctx->maplib)
|
||||
FreeLibrarian(&ctx->maplib);
|
||||
if(ctx->local_maplib)
|
||||
FreeLibrarian(&ctx->local_maplib);
|
||||
|
||||
if((*context)->glwrappers)
|
||||
freeProcWrapper(&(*context)->glwrappers);
|
||||
if((*context)->alwrappers)
|
||||
freeProcWrapper(&(*context)->alwrappers);
|
||||
#ifdef DYNAREC
|
||||
dynarec_log(LOG_DEBUG, "Free global Dynarecblocks\n");
|
||||
if(ctx->dynablocks)
|
||||
FreeDynablockList(&ctx->dynablocks);
|
||||
for (int i=0; i<ctx->mmapsize; ++i)
|
||||
if(ctx->mmaplist[i].block)
|
||||
munmap(ctx->mmaplist[i].block, MMAPSIZE);
|
||||
free(ctx->mmaplist);
|
||||
pthread_mutex_destroy(&ctx->mutex_blocks);
|
||||
pthread_mutex_destroy(&ctx->mutex_mmap);
|
||||
dynarec_log(LOG_DEBUG, "Free dynamic Dynarecblocks\n");
|
||||
cleanDBFromAddressRange(0, 0xffffffff, 1);
|
||||
#endif
|
||||
|
||||
*context = NULL; // bye bye my_context
|
||||
|
||||
FreeCallbackList(&(*context)->callbacks);
|
||||
CleanStackSize(ctx);
|
||||
|
||||
pthread_mutex_destroy(&(*context)->mutex_once);
|
||||
FreeCollection(&ctx->box86_path);
|
||||
FreeCollection(&ctx->box86_ld_lib);
|
||||
FreeCollection(&ctx->box86_emulated_libs);
|
||||
// stop trace now
|
||||
if(ctx->dec)
|
||||
DeleteX86TraceDecoder(&ctx->dec);
|
||||
if(ctx->zydis)
|
||||
DeleteX86Trace(ctx);
|
||||
|
||||
free(*context);
|
||||
*context = NULL;
|
||||
if(ctx->deferedInitList)
|
||||
free(ctx->deferedInitList);
|
||||
|
||||
#ifndef BUILD_LIB
|
||||
if(ctx->box86lib)
|
||||
dlclose(ctx->box86lib);
|
||||
#endif
|
||||
|
||||
FreeDLPrivate(&ctx->dlprivate);
|
||||
|
||||
free(ctx->argv);
|
||||
|
||||
for (int i=0; i<ctx->envc; ++i)
|
||||
free(ctx->envv[i]);
|
||||
free(ctx->envv);
|
||||
|
||||
free(ctx->stack);
|
||||
|
||||
free(ctx->fullpath);
|
||||
free(ctx->box86path);
|
||||
|
||||
FreeBridge(&ctx->system);
|
||||
|
||||
freeGLProcWrapper(ctx);
|
||||
freeALProcWrapper(ctx);
|
||||
|
||||
FreeCallbackList(&ctx->callbacks);
|
||||
|
||||
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);
|
||||
|
||||
for(int i=0; i<3; ++i) {
|
||||
if(ctx->segtls[i].present) {
|
||||
// key content not handled by box86, so not doing anything with it
|
||||
pthread_key_delete(ctx->segtls[i].key);
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_destroy(&ctx->mutex_once);
|
||||
pthread_mutex_destroy(&ctx->mutex_once2);
|
||||
pthread_mutex_destroy(&ctx->mutex_trace);
|
||||
pthread_mutex_destroy(&ctx->mutex_lock);
|
||||
pthread_mutex_destroy(&ctx->mutex_thread);
|
||||
|
||||
free_neededlib(&ctx->neededlibs);
|
||||
|
||||
if(ctx->atfork_sz) {
|
||||
free(ctx->atforks);
|
||||
ctx->atforks = NULL;
|
||||
ctx->atfork_sz = ctx->atfork_cap = 0;
|
||||
}
|
||||
|
||||
for(int i=0; i<MAX_SIGNAL; ++i)
|
||||
if(ctx->signals[i]!=0 && ctx->signals[i]!=1) {
|
||||
signal(i, SIG_DFL);
|
||||
}
|
||||
|
||||
if(ctx->emu_sig)
|
||||
FreeX86Emu(&ctx->emu_sig);
|
||||
|
||||
finiAllHelpers();
|
||||
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
int AddElfHeader(box86context_t* ctx, elfheader_t* head) {
|
||||
@@ -110,3 +456,34 @@ int AddElfHeader(box86context_t* ctx, elfheader_t* head) {
|
||||
printf_log(LOG_DEBUG, "Adding \"%s\" as #%d in elf collection\n", ElfName(head), idx);
|
||||
return idx;
|
||||
}
|
||||
|
||||
int AddTLSPartition(box86context_t* context, int tlssize) {
|
||||
int oldsize = context->tlssize;
|
||||
context->tlssize += tlssize;
|
||||
context->tlsdata = 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)
|
||||
return -context->tlssize; // negative offset
|
||||
}
|
||||
|
||||
void add_neededlib(needed_libs_t* needed, library_t* lib)
|
||||
{
|
||||
if(!needed)
|
||||
return;
|
||||
if(needed->size == needed->cap) {
|
||||
needed->cap += 8;
|
||||
needed->libs = (library_t**)realloc(needed->libs, needed->cap*sizeof(library_t*));
|
||||
}
|
||||
needed->libs[needed->size++] = lib;
|
||||
}
|
||||
|
||||
void free_neededlib(needed_libs_t* needed)
|
||||
{
|
||||
if(!needed)
|
||||
return;
|
||||
needed->cap = 0;
|
||||
needed->size = 0;
|
||||
if(needed->libs)
|
||||
free(needed->libs);
|
||||
needed->libs = NULL;
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
#ifndef __BOX86CONTEXT_H_
|
||||
#define __BOX86CONTEXT_H_
|
||||
#include <stdint.h>
|
||||
#include <pthread.h>
|
||||
#include "pathcoll.h"
|
||||
|
||||
typedef struct elfheader_s elfheader_t;
|
||||
|
||||
typedef struct x86emu_s x86emu_t;
|
||||
typedef struct zydis_s zydis_t;
|
||||
typedef struct lib_s lib_t;
|
||||
typedef struct bridge_s bridge_t;
|
||||
typedef struct dlprivate_s dlprivate_t;
|
||||
typedef struct kh_symbolmap_s kh_symbolmap_t;
|
||||
typedef struct callbacklist_s callbacklist_t;
|
||||
typedef struct library_s library_t;
|
||||
|
||||
typedef void* (*procaddess_t)(const char* name);
|
||||
|
||||
typedef struct box86context_s {
|
||||
path_collection_t box86_path; // PATH env. variable
|
||||
path_collection_t box86_ld_lib; // LD_LIBRARY_PATH env. variable
|
||||
|
||||
int x86trace;
|
||||
zydis_t *zydis; // dlopen the zydis dissasembler
|
||||
void* box86lib; // dlopen on box86 itself
|
||||
|
||||
int argc;
|
||||
char** argv;
|
||||
|
||||
int envc;
|
||||
char** envv;
|
||||
|
||||
char* fullpath;
|
||||
|
||||
uint32_t stacksz;
|
||||
int stackalign;
|
||||
void* stack; // alocated stack
|
||||
|
||||
elfheader_t **elfs; // elf headers and memory
|
||||
int elfcap;
|
||||
int elfsize; // number of elf loaded
|
||||
|
||||
uintptr_t ep; // entry point
|
||||
|
||||
x86emu_t *emu; // CPU / FPU / MMX&SSE regs
|
||||
|
||||
lib_t *maplib; // lib and symbols handling
|
||||
|
||||
bridge_t *threads; // threads
|
||||
bridge_t *system; // other bridges
|
||||
uintptr_t vsyscall; // vsyscall bridge value
|
||||
dlprivate_t *dlprivate; // dlopen library map
|
||||
kh_symbolmap_t *glwrappers; // the map of wrapper for glProcs (for GLX or SDL1/2)
|
||||
procaddess_t glxprocaddress;
|
||||
kh_symbolmap_t *alwrappers; // the map of wrapper for alGetProcAddress
|
||||
|
||||
callbacklist_t *callbacks; // all callbacks
|
||||
|
||||
pthread_mutex_t mutex_once;
|
||||
|
||||
library_t *libclib; // shortcut to libc library (if loaded, so probably yes)
|
||||
library_t *sdl1lib; // shortcut to SDL1 library (if loaded)
|
||||
library_t *sdl1mixerlib;
|
||||
library_t *sdl1imagelib;
|
||||
library_t *sdl2lib; // shortcut to SDL2 library (if loaded)
|
||||
library_t *sdl2mixerlib;
|
||||
library_t *sdl2imagelib;
|
||||
|
||||
int deferedInit;
|
||||
elfheader_t **deferedInitList;
|
||||
int deferedInitSz;
|
||||
int deferedInitCap;
|
||||
|
||||
int forked; // how many forks... cleanup only when < 0
|
||||
} box86context_t;
|
||||
|
||||
box86context_t *NewBox86Context(int argc);
|
||||
void FreeBox86Context(box86context_t** context);
|
||||
|
||||
int AddElfHeader(box86context_t* ctx, elfheader_t* head); // return the index of header
|
||||
|
||||
#endif //__BOX86CONTEXT_H_
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
#define __BOX86_VERSION_H_
|
||||
|
||||
#define BOX86_MAJOR 0
|
||||
#define BOX86_MINOR 0
|
||||
#define BOX86_MINOR 1
|
||||
#define BOX86_REVISION 2
|
||||
|
||||
#endif //__BOX86_VERSION_H_
|
||||
Executable
+28
@@ -0,0 +1,28 @@
|
||||
#include <stdio.h>
|
||||
#include "debug.h"
|
||||
#include "box86version.h"
|
||||
#include "git_head.h"
|
||||
|
||||
void PrintBox86Version()
|
||||
{
|
||||
printf("Box86%s%s%s v%d.%d.%d %s built on %s %s\n",
|
||||
#ifdef HAVE_TRACE
|
||||
" with trace",
|
||||
#else
|
||||
"",
|
||||
#endif
|
||||
#ifdef DYNAREC
|
||||
" with Dynarec",
|
||||
#else
|
||||
"",
|
||||
#endif
|
||||
#ifdef USE_FLOAT
|
||||
" (float only)",
|
||||
#else
|
||||
"",
|
||||
#endif
|
||||
BOX86_MAJOR, BOX86_MINOR, BOX86_REVISION,
|
||||
GITREV,
|
||||
__DATE__, __TIME__);
|
||||
}
|
||||
|
||||
Executable
+6
@@ -0,0 +1,6 @@
|
||||
#ifndef __BUILD_INFO_H__
|
||||
#define __BUILD_INFO_H__
|
||||
|
||||
void PrintBox86Version();
|
||||
|
||||
#endif //__BUILD_INFO_H__
|
||||
-134
@@ -1,134 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "x86emu.h"
|
||||
#include "x86run.h"
|
||||
#include "x86emu_private.h"
|
||||
#include "x86run_private.h"
|
||||
#include "box86context.h"
|
||||
#include "stack.h"
|
||||
#include "khash.h"
|
||||
|
||||
typedef struct onecallback_s {
|
||||
x86emu_t *emu;
|
||||
uintptr_t fnc;
|
||||
int nb_args;
|
||||
void* arg[8];
|
||||
void* stack;
|
||||
} onecallback_t;
|
||||
|
||||
KHASH_MAP_INIT_INT(callbacks, onecallback_t*)
|
||||
|
||||
typedef struct callbacklist_s {
|
||||
kh_callbacks_t *list;
|
||||
int cap;
|
||||
int sz;
|
||||
} callbacklist_t;
|
||||
|
||||
x86emu_t* AddCallback(x86emu_t* emu, uintptr_t fnc, int nb_args, void* arg1, void* arg2, void* arg3, void* arg4)
|
||||
{
|
||||
callbacklist_t *callbacks = emu->context->callbacks;
|
||||
int stsize = 1024*1024;
|
||||
void* stack = malloc(stsize);
|
||||
x86emu_t * newemu = NewX86Emu(emu->context, fnc, (uintptr_t)stack, stsize);
|
||||
SetupX86Emu(newemu, emu->shared_global, emu->globals);
|
||||
newemu->trace_start = emu->trace_start;
|
||||
newemu->trace_end = emu->trace_end;
|
||||
|
||||
onecallback_t * cb;
|
||||
int ret;
|
||||
khint_t k = kh_put(callbacks, callbacks->list, (uintptr_t)newemu, &ret);
|
||||
cb = kh_value(callbacks->list, k) = (onecallback_t*)calloc(1, sizeof(onecallback_t));
|
||||
|
||||
cb->stack = stack;
|
||||
cb->emu = newemu;
|
||||
cb->fnc = fnc;
|
||||
cb->nb_args = nb_args;
|
||||
cb->arg[0] = arg1;
|
||||
cb->arg[1] = arg2;
|
||||
cb->arg[2] = arg3;
|
||||
cb->arg[3] = arg4;
|
||||
|
||||
return newemu;
|
||||
}
|
||||
|
||||
onecallback_t* FindCallback(x86emu_t* emu)
|
||||
{
|
||||
// find the callback first
|
||||
callbacklist_t *callbacks = emu->context->callbacks;
|
||||
khint_t k = kh_get(callbacks, callbacks->list, (uintptr_t)emu);
|
||||
if(k==kh_end(callbacks->list))
|
||||
return NULL;
|
||||
return kh_value(callbacks->list, k);
|
||||
}
|
||||
|
||||
void FreeCallback(x86emu_t* emu)
|
||||
{
|
||||
// find the callback first
|
||||
callbacklist_t *callbacks = emu->context->callbacks;
|
||||
khint_t k = kh_get(callbacks, callbacks->list, (uintptr_t)emu);
|
||||
if(k==kh_end(callbacks->list))
|
||||
return;
|
||||
onecallback_t* cb = kh_value(callbacks->list, k);
|
||||
FreeX86Emu(&cb->emu);
|
||||
free(cb->stack);
|
||||
free(cb);
|
||||
kh_del(callbacks, callbacks->list, k);
|
||||
}
|
||||
|
||||
uint32_t RunCallback(x86emu_t* emu)
|
||||
{
|
||||
onecallback_t *cb = FindCallback(emu);
|
||||
if(cb) {
|
||||
for (int i=cb->nb_args-1; i>=0; --i) // reverse order
|
||||
Push(emu, (uint32_t)cb->arg[i]);
|
||||
EmuCall(emu, cb->fnc);
|
||||
return R_EAX;
|
||||
}
|
||||
printf_log(LOG_INFO, "Warning, Callback not found?!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SetCallbackArg(x86emu_t* emu, int arg, void* val)
|
||||
{
|
||||
onecallback_t *cb = FindCallback(emu);
|
||||
if(cb) {
|
||||
cb->arg[arg] = val;
|
||||
}
|
||||
}
|
||||
|
||||
void SetCallbackNArg(x86emu_t* emu, int narg)
|
||||
{
|
||||
onecallback_t *cb = FindCallback(emu);
|
||||
if(cb) {
|
||||
cb->nb_args = narg;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
callbacklist_t* NewCallbackList()
|
||||
{
|
||||
callbacklist_t* callbacks = (callbacklist_t*)calloc(1, sizeof(callbacklist_t));
|
||||
callbacks->list = kh_init(callbacks);
|
||||
return callbacks;
|
||||
}
|
||||
|
||||
void FreeCallbackList(callbacklist_t** callbacks)
|
||||
{
|
||||
if(!callbacks)
|
||||
return;
|
||||
if(!*callbacks)
|
||||
return;
|
||||
onecallback_t* cb;
|
||||
kh_foreach_value((*callbacks)->list, cb,
|
||||
FreeX86Emu(&cb->emu);
|
||||
free(cb->stack);
|
||||
free(cb);
|
||||
);
|
||||
kh_destroy(callbacks, (*callbacks)->list);
|
||||
free(*callbacks);
|
||||
*callbacks = NULL;
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
#ifndef __CALLBACK_H__
|
||||
#define __CALLBACK_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct callbacklist_s callbacklist_t;
|
||||
typedef struct x86emu_s x86emu_t;
|
||||
|
||||
callbacklist_t* NewCallbackList();
|
||||
void FreeCallbackList(callbacklist_t** callbacks);
|
||||
|
||||
x86emu_t* AddCallback(x86emu_t* emu, uintptr_t fnc, int nb_args, void* arg1, void* arg2, void* arg3, void* arg4);
|
||||
void FreeCallback(x86emu_t* emu);
|
||||
uint32_t RunCallback(x86emu_t* emu);
|
||||
void SetCallbackArg(x86emu_t* emu, int arg, void* val);
|
||||
void SetCallbackNArg(x86emu_t* emu, int narg);
|
||||
|
||||
#endif //__CALLBACK_H__
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
#ifndef __DEBUG_H_
|
||||
#define __DEBUG_H_
|
||||
|
||||
extern int box86_log; // log level
|
||||
extern int trace_xmm; // include XMM reg in trace?
|
||||
#define LOG_NONE 0
|
||||
#define LOG_INFO 1
|
||||
#define LOG_DEBUG 2
|
||||
#define LOG_DUMP 3
|
||||
|
||||
extern FILE* ftrace;
|
||||
|
||||
#define printf_log(L, ...) if(L<=box86_log) fprintf(ftrace, __VA_ARGS__)
|
||||
|
||||
#define EXPORT __attribute__((visibility("default")))
|
||||
|
||||
#endif //__DEBUG_H_
|
||||
Executable
+1116
File diff suppressed because it is too large.
Load diff
Executable
+27
@@ -0,0 +1,27 @@
|
||||
//arm epilog for dynarec
|
||||
//Save stuff, prepare stack and register
|
||||
//called with pointer to emu as 1st parameter
|
||||
//and address to jump to as 2nd parameter
|
||||
|
||||
.text
|
||||
.align 4
|
||||
|
||||
.global arm_epilog
|
||||
arm_epilog:
|
||||
//update register -> emu
|
||||
//pop {r0}
|
||||
stm r0, {r4-r12} // put back reg value in emu, including EIP (so r12 must be EIP now)
|
||||
//restore all used register
|
||||
//vpop {d8-d15}
|
||||
pop {r4-r11, pc}
|
||||
//end, return...
|
||||
//bx lr
|
||||
|
||||
|
||||
.global arm_epilog_fast
|
||||
arm_epilog_fast:
|
||||
//restore all used register
|
||||
//vpop {d8-d15}
|
||||
pop {r4-r11, pc}
|
||||
//end, return...
|
||||
//bx lr
|
||||
@@ -0,0 +1,594 @@
|
||||
; TYPE fields separated by spaces Assembler syntax
|
||||
; When there are mutiple assembler syntax (like for LDR (immediate)), separate them based on the bytes
|
||||
; E.G. for LDR (immediate), there are 3 lines with the 3 different asm syntaxes
|
||||
|
||||
# Field options:
|
||||
# --------------
|
||||
# Syntax: ... field/coption1(coption2)* ... (inside fields)
|
||||
# Where each c correspond to the option character
|
||||
# and optionN to the Nth option value
|
||||
# ---
|
||||
# c = '0'..'9'/'A'..'F': option=[01]
|
||||
# Force the cth bit (hex) of the field (starting from LSB) to be <option>
|
||||
# c = '=': option=[01x]{field_len}
|
||||
# Force the field to have the given bits (where x = anything, starts from MSB)
|
||||
|
||||
# Post-fields option:
|
||||
# -------------------
|
||||
# Syntax: [fields] @ typeoption1 args1 typeoption2 args2 @ [Assembler syntax]
|
||||
# ---
|
||||
# typeoption contains '=' (l=r): args1=((.*) )?([^, ]*),([^, ]*),([^, ]*)@
|
||||
# Changes a value between two other depending on whether l == r
|
||||
|
||||
# \2 is init (suffixed by ';', optional), \3 is set to \4 if true or \5 if false
|
||||
# (cf VMOV/VORR aka V\op\, VEOR/VBIF/VBIT/VBSL aka V\op\)
|
||||
|
||||
# The 'true regex' is typeoption=([^= ]*)(=([^= ]*))+
|
||||
# args1=((.*) )?([^, ]*),(([^, ]*),)+([^, ]*)@
|
||||
# with the number of typeoption:\2 being equal to the number of args1:\4
|
||||
# <a>=<b>[=<c>...] <initialization> <variable-changed>,<changed-into-if-a=b>[,<changed-into-if-a=c>...],<changed-into-else>@
|
||||
|
||||
# OR
|
||||
|
||||
# typeoption is discarded and must be set to '=', args1=((.*) )?(@@ (( ?.*[^@])*)@ )+([^, ]*),(([^, ]*),)+([^, ]*)
|
||||
# \2 is init (suffixed by ';', optional), \6 is set to \7 if true or \8 if false
|
||||
# The difference with the simple switch is that \4 is the test (inside the `if`)
|
||||
# If there are multiple @@s, there are multiple `if`s (separated by `else`s)
|
||||
|
||||
# The 'true regex' is [DISCARDED]typeoption==
|
||||
# args1=((.*) )?(@@ (( ?.*[^@])*)@ )+([^, ]*),([^, ]*),([^, ]*)
|
||||
# <.>=<.>[=<c>...] <initialization> @@ <test>@[ @@ <test2>@...] <variable-changed>,<changed-into-if-a=b>,<changed-into-else>
|
||||
|
||||
# OR
|
||||
|
||||
# args1=((.*) )?!@(( [^%]*[^%@])*)%(( ?[^%]*[^%@])*)@(( .*[^@])*)@(( .*[^@])*)@
|
||||
# Replaced by '\1; if (<equality>) { \3\7\5; } else { \3\9\5; }'
|
||||
# Meaning, <.=.> <initialization> !@ <common-left-part>%<common-right-part>@ <substitute-true>@ <substitute-false>@ <...>
|
||||
# (cf VMOV/VORR, aka V\op\ with the lastop variable)
|
||||
# You can also add more '=' with corresponding substitutes.
|
||||
# You can also add more '%' with corresponding substitutes.
|
||||
|
||||
# ----
|
||||
# Inside the assembler syntax, you can add \var\ to mark a variable to be replaced
|
||||
# (Meaning, %s and `var` as argument to printf)
|
||||
# Full syntax: \\(%[0-9+]*.)?(.*)\\
|
||||
# If \1 != "", add \1 to the string in printf, and in any case append \2 as argument to printf
|
||||
|
||||
! HACKS: (list of notable differences between the doc and this file)
|
||||
! ------
|
||||
! In theory, (0) and (1) bits are as important as 0 and 1:
|
||||
! > An instruction is UNPREDICTABLE if:
|
||||
! > • It is declared as UNPREDICTABLE in an instruction description or in this chapter.
|
||||
! > • The pseudocode for that encoding does not indicate that a different special case applies, and a bit marked (0)
|
||||
! or (1) in the encoding diagram of an instruction is not 0 or 1 respectively.
|
||||
! - ARM Architecture Reference Manual ARMv7-A and ARMv7-R edition
|
||||
! In practice, they are ignored here.
|
||||
|
||||
! SWP, SWPB, VMOV (VFPU): Rt2 (field and assembly) -> Rn (field and assembly)
|
||||
! BKPT: must be AL, so cond (field) -> cond/=1110 (constrained field)
|
||||
! PKHBT and PKHTB: {, LSL/ASR #<imm>} (assembly) -> {, <shift>} (assembly)
|
||||
! PKHBT and PKHTB: immediate shift but shift & 1 -> ARMs (type)
|
||||
! All NEON operations (advanced SIMD): limited, so multiply the lines
|
||||
! VMOV (register): Vm ... Vm VMOV (field, assembly) -> Vn ... Vm @ m=n ...@ @ V\op\ (field, switchable var, assembly)
|
||||
! VMOV is VORR constrained -> (removed VORR)
|
||||
! VEOR, VBSL, VBIT, VBIF differ only depending on 2 bits: 0/1 0/1 ... VEOR -> @<2> ... @ ... @ V\op\ (field, switchable var, assembly)
|
||||
! Three registers of different lengths (when having L and W variants): op (field) -> Q (field)
|
||||
|
||||
; ========== BEGINNING OF REGISTERED INSTRUCTIONS =========
|
||||
|
||||
# This instruction changes the instruction set to Thumb! Disabled (but valid)
|
||||
#ARM_ 1 1 1 1 1 0 1 @<1> imm24 @ set imm24 = (imm24 << 2) + (param << 1)@ @ BLX <label>
|
||||
|
||||
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 0 op 0 N Q M 0 Vm VH\(op ? "SUB" : "ADD")\<c>.<dt> <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 0 0 0 N Q M 1 Vm VQADD<c>.<dt> <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 0 0 1 N Q M 0 Vm VRHADD<c>.<dt> <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 0 0 D 0 0 Vn Vd 0 0 0 1 N Q M 1 Vm VAND<c> <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 0 0 D 0 1 Vn Vd 0 0 0 1 N Q M 1 Vm VBIC<c> <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 0 0 D 1 0 Vn Vd 0 0 0 1 N Q M 1 Vm @ m=n const char* op op,"MOV","ORR"@ m=n char lastop[6] !@ %@ lastop[0] = '\0'@ sprintf(lastop, ", %s", vecname[(q << 5) + 0x20 + n])@ @ V\op\<c> <Qd>, <Qm>\lastop\
|
||||
NEON 1 1 1 1 0 0 1 0 0 D 1 1 Vn Vd 0 0 0 1 N Q M 1 Vm VORN<c> <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 0 D @<2> Vn Vd 0 0 0 1 N Q M 1 Vm @ param=0b00=0b01=0b10 const char* op op,"EOR","BSL","BIT","BIF"@ @ V\op\<c> <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 0 1 0 N Q M 1 Vm VQSUB<c>.<dt> <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 0 1 1 N Q M op Vm @ op=0 const char* strict strict,"T","E"@ @ VCG\strict\<c>.<dt> <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 0 0 N Q M 0 Vm VSHL<c>.<dt> <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 0 0 N Q M 1 Vm VQSHL<c>.<dt> <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 0 1 N Q M 0 Vm VRSHL<c>.<dt> <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 0 1 N Q M 1 Vm VQRSHL<c>.<dt> <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 1 0 N Q M op Vm @ op=0 const char* opname opname,"MAX","MIN"@ @ V\opname\<c>.<dt> <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 1 1 N Q M 0 Vm VABD<c>.<dt> <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 1 1 N Q M 1 Vm VABA<c>.<dt> <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 op 0 D size Vn Vd 1 0 0 0 N Q M 0 Vm @ op=0 const char* opname opname,"ADD","SUB"@ @ V\opname\<c>.<dt> <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 0 0 D size Vn Vd 1 0 0 0 N Q M 1 Vm VTST<c>.<dt> <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 0 D size Vn Vd 1 0 0 0 N Q M 1 Vm VCEQ<c>.<dt> <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 1 0 0 1 N Q M 0 Vm @ set size = 8 << size@ @ VML\(u ? "S" : "A")\<c>.I\%dsize\ <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 1 0 0 1 N Q M 1 Vm VMUL<c>.<dt> <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 1 0 1 0 N Q M op Vm @ op=0 const char* opname opname,"MAX","MIN"@ @ VP\opname\<c>.<dt> <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 0 0 D size Vn Vd 1 0 1 1 N Q M 0 Vm VQDMULH<c>.<dt> <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 0 D size Vn Vd 1 0 1 1 N Q M 0 Vm VQRDMULH<c>.<dt> <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 0 0 D size Vn Vd 1 0 1 1 N Q/=0 M 1 Vm VPADD<c>.<dt> <Dd>, <Dn>, <Dm>
|
||||
NEON 1 1 1 1 0 0 1 0 0 D U sz/=0 Vn Vd 1 1 0 0 N Q M 1 Vm @ u=0 const char* y y,"A","S"@ @ VFM\y\<c>.F32 <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 0 0 D U sz/=0 Vn Vd 1 1 0 1 N Q M 0 Vm @ u=0 const char* op op,"ADD","SUB"@ @ V\op\<c>.F32 <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 0 D 0 sz/=0 Vn Vd 1 1 0 1 N Q/=0 M 0 Vm VPADD.F32 <Dd>, <Dn>, <Dm>
|
||||
NEON 1 1 1 1 0 0 1 1 0 D 1 sz/=0 Vn Vd 1 1 0 1 N Q M 0 Vm VABD.F32 <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 0 0 D op sz/=0 Vn Vd 1 1 0 1 N Q M 1 Vm VML\(op ? "S" : "A")\<c>.F32 <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 0 D 0 sz/=0 Vn Vd 1 1 0 1 N Q M 1 Vm VMUL.F32 <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 0 0 D 0 sz/=0 Vn Vd 1 1 1 0 N Q M 0 Vm VCEQ.F32 <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 0 D op sz/=0 Vn Vd 1 1 1 0 N Q M 0 Vm @ op=1 const char* strict strict,"T","E"@ @ VCG\strict\.F32 <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 0 D op sz/=0 Vn Vd 1 1 1 0 N Q M 1 Vm @ op=1 const char* strict strict,"T","E"@ @ VACG\strict\.F32 <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 0 0 D op sz/=0 Vn Vd 1 1 1 1 N Q M 0 Vm @ op=0 const char* opname opname,"MAX","MIN"@ @ V\opname\.F32 <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 0 D op sz/=0 Vn Vd 1 1 1 1 N Q M 0 Vm @ op=0 const char* opname opname,"MAX","MIN"@ @ VP\opname\.F32 <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 0 0 D 0 sz/=0 Vn Vd 1 1 1 1 N Q M 1 Vm VRECPS.F32 <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 0 0 D 1 sz/=0 Vn Vd 1 1 1 1 N Q M 1 Vm VRSQRTS.F32 <Qd>, <Qn>, <Qm>
|
||||
INVALIDATE 1 1 1 1 0 0 1 <1> 0 <23>
|
||||
|
||||
NEON 1 1 1 1 0 0 1 i 1 D 0 0 0 imm3 Vd cmode/=0xx0 0 Q op/=0 1 imm4 VMOV<c>.<dt> <Qd>, #<imm>
|
||||
NEON 1 1 1 1 0 0 1 i 1 D 0 0 0 imm3 Vd cmode/=0xx1 0 Q op/=0 1 imm4 VORR<c>.<dt> <Qd>, #<imm>
|
||||
NEON 1 1 1 1 0 0 1 i 1 D 0 0 0 imm3 Vd cmode/=10x0 0 Q op/=0 1 imm4 VMOV<c>.<dt> <Qd>, #<imm>
|
||||
NEON 1 1 1 1 0 0 1 i 1 D 0 0 0 imm3 Vd cmode/=10x1 0 Q op/=0 1 imm4 VORR<c>.<dt> <Qd>, #<imm>
|
||||
NEON 1 1 1 1 0 0 1 i 1 D 0 0 0 imm3 Vd cmode/=11xx 0 Q op/=0 1 imm4 VMOV<c>.<dt> <Qd>, #<imm>
|
||||
NEON 1 1 1 1 0 0 1 i 1 D 0 0 0 imm3 Vd cmode/=0xx0 0 Q op/=1 1 imm4 VMVN<c>.<dt> <Qd>, #<imm>
|
||||
NEON 1 1 1 1 0 0 1 i 1 D 0 0 0 imm3 Vd cmode/=0xx1 0 Q op/=1 1 imm4 VBIC<c>.<dt> <Qd>, #<imm>
|
||||
NEON 1 1 1 1 0 0 1 i 1 D 0 0 0 imm3 Vd cmode/=10x0 0 Q op/=1 1 imm4 VMVN<c>.<dt> <Qd>, #<imm>
|
||||
NEON 1 1 1 1 0 0 1 i 1 D 0 0 0 imm3 Vd cmode/=10x1 0 Q op/=1 1 imm4 BIC<c>.<dt> <Qd>, #<imm>
|
||||
NEON 1 1 1 1 0 0 1 i 1 D 0 0 0 imm3 Vd cmode/=110x 0 Q op/=1 1 imm4 VMVN<c>.<dt> <Qd>, #<imm>
|
||||
NEON 1 1 1 1 0 0 1 i 1 D 0 0 0 imm3 Vd cmode/=1110 0 Q op/=1 1 imm4 VMOV<c>.<dt> <Qd>, #<imm>
|
||||
;INVALIDATE 1 1 1 1 0 0 1 <1> 1 <1> 0 0 0 <3> <4> <4>/=1111 0 <1> <1>/=1 1 <4>
|
||||
INVALIDATE 1 1 1 1 0 0 1 <1> 1 <1> 0 0 0 <11> 0 <2> 1 <4>
|
||||
|
||||
# Special case for VMOVL (harder to do it on the documented place)
|
||||
NEON 1 1 1 1 0 0 1 0 1 D 0 0 1 0 0 0 Vd 1 0 1 0 0 0 M 1 Vm VMOVL<c>.S8 <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 0 1 D 0 1 0 0 0 0 Vd 1 0 1 0 0 0 M 1 Vm VMOVL<c>.S16 <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 0 1 D 1 0 0 0 0 0 Vd 1 0 1 0 0 0 M 1 Vm VMOVL<c>.S32 <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 0 0 1 0 0 0 Vd 1 0 1 0 0 0 M 1 Vm VMOVL<c>.U8 <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 0 1 0 0 0 0 Vd 1 0 1 0 0 0 M 1 Vm VMOVL<c>.U16 <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 0 0 0 0 0 Vd 1 0 1 0 0 0 M 1 Vm VMOVL<c>.U32 <Qd>, <Qm>
|
||||
|
||||
NEON 1 1 1 1 0 0 1 U 1 D imm6 Vd 0 0 0 0 L Q M 1 Vm VSHR<c>.<dt> <Qd>, <Qm>, #<imm>
|
||||
NEON 1 1 1 1 0 0 1 U 1 D imm6 Vd 0 0 0 1 L Q M 1 Vm VSRA<c>.<dt> <Qd>, <Qm>, #<imm>
|
||||
NEON 1 1 1 1 0 0 1 U 1 D imm6 Vd 0 0 1 0 L Q M 1 Vm VRSHR<c>.<dt> <Qd>, <Qm>, #<imm>
|
||||
NEON 1 1 1 1 0 0 1 U 1 D imm6 Vd 0 0 1 1 L Q M 1 Vm VRSRA<c>.<dt> <Qd>, <Qm>, #<imm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D imm6 Vd 0 1 0 0 L Q M 1 Vm VSRI<c>.<size> <Qd>, <Qm>, #<imm>
|
||||
NEON 1 1 1 1 0 0 1 0 1 D Imm6 Vd 0 1 0 1 L Q M 1 Vm VSHL<c>.I<size> <Qd>, <Qm>, #<imm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D Imm6 Vd 0 1 0 1 L Q M 1 Vm VSLI<c>.<size> <Qd>, <Qm>, #<imm>
|
||||
NEON 1 1 1 1 0 0 1 U 1 D Imm6 Vd 0 1 1 op L Q M 1 Vm VQSHL\((u & op) ? "U" : "")\<c>.<dt> <Qd>, <Qm>, #<imm>
|
||||
NEON 1 1 1 1 0 0 1 0 1 D imm6 Vd 1 0 0 0 0 0 M 1 Vm VSHRN<c>.I<size> <Dd>, <Qm>, #<imm>
|
||||
NEON 1 1 1 1 0 0 1 0 1 D imm6 Vd 1 0 0 0 0 1 M 1 Vm VRSHRN<c>.I<size> <Dd>, <Qm>, #<imm>
|
||||
NEON 1 1 1 1 0 0 1 U 1 D imm6 Vd 1 0 0 op 0 0 M 1 Vm VQSHR\((u & op) ? "U" : "")\N<c>.<dt> <Dd>, <Qm>, #<imm>
|
||||
NEON 1 1 1 1 0 0 1 U 1 D imm6 Vd 1 0 0 op 0 1 M 1 Vm VQRSHR\((u & op) ? "U" : "")\N<c>.<dt> <Dd>, <Qm>, #<imm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 0 Vd 0 0 1 1 0 0 M 1 Vm VSHLL<c>.<dt> <Qd>, <Dm>, #\%d8 &l&l size\
|
||||
NEON 1 1 1 1 0 0 1 U 1 D Imm6 Vd 1 0 1 0 0 0 M 1 Vm VSHLL<c>.<dt> <Qd>, <Dm>, #<imm>
|
||||
; VCVT: if imm6 IN "0xxxxx" then UNDEFINED;
|
||||
INVALIDATE 1 1 1 1 0 0 1 <1> 1 <1> 0 <9> 1 1 1 <1> 0 <2> 1 <4>
|
||||
NEON 1 1 1 1 0 0 1 0 1 D IMM6 Vd 1 1 1 0 0 Q M 1 Vm VCVT<c>.F32.S32 <Qd>, <Qm>, #<fbits>
|
||||
NEON 1 1 1 1 0 0 1 0 1 D IMM6 Vd 1 1 1 1 0 Q M 1 Vm VCVT<c>.S32.F32 <Qd>, <Qm>, #<fbits>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D IMM6 Vd 1 1 1 0 0 Q M 1 Vm VCVT<c>.F32.U32 <Qd>, <Qm>, #<fbits>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D IMM6 Vd 1 1 1 1 0 Q M 1 Vm VCVT<c>.U32.F32 <Qd>, <Qm>, #<fbits>
|
||||
INVALIDATE 1 1 1 1 0 0 1 <1> 1 <18> 1 <4>
|
||||
|
||||
NEON 1 1 1 1 0 0 1 0 1 D 1 1 Vn Vd IMM4 N Q M 0 Vm VEXT<c>.8 <Qd>, <Qn>, <Qm>, #<imm>
|
||||
|
||||
# size + param < 3
|
||||
INVALIDATE 1 1 1 1 0 0 1 1 1 <1> 1 1 <2>/=11 0 0 <4> 0 0 0 <2> <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>/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 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>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size/=00 0 0 Vd 0 1 0 1 0 Q M 0 Vm VCNT<c>.8 <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size/=00 0 0 Vd 0 1 0 1 1 Q M 0 Vm VMVN<c> <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 1 1 0 U Q M 0 Vm VPADAL<c>.<dt> <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 1 1 1 0 Q M 0 Vm VQABS<c>.<dt> <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 1 1 1 1 Q M 0 Vm VQNEG<c>.<dt> <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 1 Vd 0 F 0 0 0 Q M 0 Vm VCGT<c>.<dt> <Qd>, <Qm>, #0
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 1 Vd 0 F 0 0 1 Q M 0 Vm VCGE<c>.<dt> <Qd>, <Qm>, #0
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 1 Vd 0 F 0 1 0 Q M 0 Vm VCEQ<c>.<dt> <Qd>, <Qm>, #0
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 1 Vd 0 F 0 1 1 Q M 0 Vm VCLE<c>.<dt> <Qd>, <Qm>, #0
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 1 Vd 0 F 1 0 0 Q M 0 Vm VCLT<c>.<dt> <Qd>, <Qm>, #0
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 1 Vd 0 F 1 1 0 Q M 0 Vm VABS<c>.<dt> <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 1 Vd 0 F 1 1 1 Q M 0 Vm VNEG<c>.<dt> <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size/=00 1 0 Vd 0 0 0 0 0 Q M 0 Vm VSWP<c> <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 0 Vd 0 0 0 0 1 Q M 0 Vm VTRN<c>.\%d8 &l&l size\ <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 0 Vd 0 0 0 1 0 Q M 0 Vm VUZP<c>.\%d8 &l&l size\ <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 0 Vd 0 0 0 1 1 Q M 0 Vm VZIP<c>.\%d8 &l&l size\ <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 0 Vd 0 0 1 0 0 0 M 0 Vm VMOVN<c>.<dt> <Dd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 0 Vd 0 0 1 0 0 1 M 0 Vm VQMOVUN<c>.S\%d16 &l&l size\ <Dd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 0 Vd 0 0 1 0 1 U M 0 Vm @ set u = 1 - u@ set ++size@ @ VQMOVN<c>.<dt> <Dd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 0 Vd 0 0 1 1 0 0 M 0 Vm VSHLL<c>.I\%d8 &l&l size\ <Qd>, <Dm>, #\%d8 &l&l size\
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size/=01 1 0 Vd 0 1 1 0 0 0 M 0 Vm VCVT<c>.F16.F32 <Dd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size/=01 1 0 Vd 0 1 1 1 0 0 M 0 Vm VCVT<c>.F32.F16 <Qd>, <Dm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 1 Vd 0 1 0 F 0 Q M 0 Vm VRECPE<c>.<dt> <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 1 Vd 0 1 0 F 1 Q M 0 Vm VRSQRTE<c>.<dt> <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size/=10 1 1 Vd 0 1 1 0 0 Q M 0 Vm VCVT<c>.F32.S32 <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size/=10 1 1 Vd 0 1 1 0 1 Q M 0 Vm VCVT<c>.S32.F32 <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size/=10 1 1 Vd 0 1 1 1 0 Q M 0 Vm VCVT<c>.F32.U32 <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size/=10 1 1 Vd 0 1 1 1 1 Q M 0 Vm VCVT<c>.U32.F32 <Qd>, <Qm>
|
||||
INVALIDATE 1 1 1 1 0 0 1 1 1 <1> 1 1 <8> 0 <6> 0 <4>
|
||||
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 Vn Vd 1 0 @<2> N op M 0 Vm @ param=0b00 char list[10] !@ sprintf(list, %)@ "{%s}", vecname[0x20 + n]@ "{%s-%s}", vecname[0x20 + n], vecname[0x20 + n + param]@ @ VTB\(op ? "X" : "L")\<c>.8 <Dd>, \list\, <Dm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 imm4 Vd 1 1 0 0 0 Q M 0 Vm VDUP<c>.\%dsize\ <Qd>, <Dm[x]>
|
||||
|
||||
; size != 11
|
||||
INVALIDATE 1 1 1 1 0 0 1 <1> 1 <1> 1 1 <13> 0 <1> 0 <4>
|
||||
NEON 1 1 1 1 0 0 1 U 1 D size Vn Vd 0 0 0 Q N 0 M 0 Vm VADD\(q ? "W" : "L")\<c>.<dt> <qd>, <Qn>, <Dm>
|
||||
NEON 1 1 1 1 0 0 1 U 1 D size Vn Vd 0 0 1 Q N 0 M 0 Vm VSUB\(q ? "W" : "L")\<c>.<dt> <qd>, <Qn>, <Dm>
|
||||
NEON 1 1 1 1 0 0 1 0 1 D size Vn Vd 0 1 0 0 N 0 M 0 Vm @ set size = 16 << size@ @ VADDHN<c>.I\%dsize\ <Dd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D size Vn Vd 0 1 0 0 N 0 M 0 Vm VRADDHN<c>.<dt> <Dd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 U 1 D size Vn Vd 0 1 0 1 N 0 M 0 Vm VABAL<c>.<dt> <Qd>, <Dn>, <Dm>
|
||||
NEON 1 1 1 1 0 0 1 0 1 D size Vn Vd 0 1 1 0 N 0 M 0 Vm VSUBHN<c>.<dt> <Dd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D size Vn Vd 0 1 1 0 N 0 M 0 Vm VRSUBHN<c>.<dt> <Dd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 U 1 D size Vn Vd 0 1 1 1 N 0 M 0 Vm VABDL<c>.<dt> <Qd>, <Dn>, <Dm>
|
||||
NEON 1 1 1 1 0 0 1 U 1 D size Vn Vd 1 0 op 0 N 0 M 0 Vm VML\(op ? "S" : "A")\L<c>.<dt> <Qd>, <Dn>, <Dm>
|
||||
NEON 1 1 1 1 0 0 1 0 1 D size Vn Vd 1 0 op 1 N 0 M 0 Vm VQDML\(op ? "S" : "A")\L<c>.<dt> <Qd>, <Dn>, <Dm>
|
||||
NEON 1 1 1 1 0 0 1 U 1 D size Vn Vd 1 1 0 0 N 0 M 0 Vm VMULL<c>.<dt> <Qd>, <Dn>, <Dm>
|
||||
NEON 1 1 1 1 0 0 1 0 1 D size Vn Vd 1 1 0 1 N 0 M 0 Vm VQDMULL<c>.<dt> <Qd>, <Dn>, <Dm>
|
||||
NEON 1 1 1 1 0 0 1 U/=0 1 D size/=00 Vn Vd 1 1 1 0 N 0 M 0 Vm @ set uint8_t size = 0@ @ VMULL<c>.<dt> <Qd>, <Dn>, <Dm>
|
||||
INVALIDATE 1 1 1 1 0 0 1 <1> 1 <16> 0 <1> 0 <4>
|
||||
|
||||
; Put after, otherwise some instructions are shadowed
|
||||
NEON 1 1 1 1 0 0 1 Q 1 D size Vn Vd 0 op 0 F N 1 M 0 Vm @ size=0b01=0b10 unsigned int decodedImm !@ decodedImm = m >> %; m %@ 3@ &= 0x7@ 4@ &= 0xF@ 5@ = 0x21@ @ VML\(op ? "S" : "A")\<c>.<dt> <Qd>, <Qn>, <Dm[x]>
|
||||
NEON 1 1 1 1 0 0 1 U 1 D size Vn Vd 0 op 1 0 N 1 M 0 Vm @ size=0b01=0b10 unsigned int decodedImm !@ decodedImm = m >> %; m %@ 3@ &= 0x7@ 4@ &= 0xF@ 5@ = 0x21@ @ VML\(op ? "S" : "A")\L<c>.<dt> <Qd>, <Dn>, <Dm[x]>
|
||||
NEON 1 1 1 1 0 0 1 0 1 D size Vn Vd 0 op 1 1 N 1 M 0 Vm @ size=0b01=0b10 unsigned int decodedImm !@ decodedImm = m >> %; m %@ 3@ &= 0x7@ 4@ &= 0xF@ 5@ = 0x21@ @ VQDML\(op ? "S" : "A")\L<c>.<dt> <Qd>, <Dn>, <Dm[x]>
|
||||
NEON 1 1 1 1 0 0 1 Q 1 D size Vn Vd 1 0 0 F N 1 M 0 Vm @ size=0b01=0b10 unsigned int decodedImm !@ decodedImm = m >> %; m %@ 3@ &= 0x7@ 4@ &= 0xF@ 5@ = 0x21@ @ VMUL<c>.<dt> <Qd>, <Qn>, <Dm[x]>
|
||||
NEON 1 1 1 1 0 0 1 U 1 D size Vn Vd 1 0 1 0 N 1 M 0 Vm @ size=0b01=0b10 unsigned int decodedImm !@ decodedImm = m >> %; m %@ 3@ &= 0x7@ 4@ &= 0xF@ 5@ = 0x21@ @ VMULL<c>.<dt> <Qd>, <Qn>, <Dm[x]>
|
||||
NEON 1 1 1 1 0 0 1 0 1 D size Vn Vd 1 0 1 1 N 1 M 0 Vm @ size=0b01=0b10 unsigned int decodedImm !@ decodedImm = m >> %; m %@ 3@ &= 0x7@ 4@ &= 0xF@ 5@ = 0x21@ @ VQDMULL<c>.<dt> <Qd>, <Qn>, <Dm[x]>
|
||||
NEON 1 1 1 1 0 0 1 Q 1 D size Vn Vd 1 1 0 0 N 1 M 0 Vm @ size=0b01=0b10 unsigned int decodedImm !@ decodedImm = m >> %; m %@ 3@ &= 0x7@ 4@ &= 0xF@ 5@ = 0x21@ @ VQDMULH<c>.<dt> <Qd>, <Qn>, <Dm[x]>
|
||||
NEON 1 1 1 1 0 0 1 Q 1 D size Vn Vd 1 1 0 1 N 1 M 0 Vm @ size=0b01=0b10 unsigned int decodedImm !@ decodedImm = m >> %; m %@ 3@ &= 0x7@ 4@ &= 0xF@ 5@ = 0x21@ @ VQRDMULH<c>.<dt> <Qd>, <Qn>, <Dm[x]>
|
||||
INVALIDATE 1 1 1 1 0 0 1 <1> 1 <16> 0 <1> 0 <4>
|
||||
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 0 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\, \vecname[0x23 + d]\}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 0 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\, \vecname[0x23 + d]\}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 0 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\, \vecname[0x23 + d]\}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 0 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\, \vecname[0x26 + d]\}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 0 1 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\, \vecname[0x26 + d]\}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 0 1 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\, \vecname[0x26 + d]\}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 1 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 1 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 1 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 1 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 1 1 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 1 1 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 0 0 size @<2> 1 1 1 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 0 0 size @<2> 1 1 0 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 0 0 size @<2> Rm @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 0 1 size @<2> 1 1 1 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 0 1 size @<2> 1 1 0 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 0 1 size @<2> Rm @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 1 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x22 + d]\}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 1 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x22 + d]\}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 1 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x22 + d]\}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 1 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 1 1 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 1 1 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 0 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 0 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 0 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 0 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 0 1 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 0 1 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 1 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 1 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 1 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\], <Rm>
|
||||
;INVALIDATE 1 1 1 1 0 1 0 0 0 <1> 0 0 <22>
|
||||
INVALIDATE 1 1 1 1 0 1 0 0 1 <1> 0 0 <8> 1 1 <10>
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 0 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)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 0 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)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 0 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)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 0 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@ @ VST2<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 0 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@ @ VST2<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 0 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@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 1 @<4> 1 1 1 1 @ set uint8_t temp = param & (1 << size)@ temp=0 uint8_t spacing spacing,0,1@ set uint8_t x = param >> (size + 1)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\]}, [<Rn>]
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 1 @<4> 1 1 0 1 @ set uint8_t temp = param & (1 << size)@ temp=0 uint8_t spacing spacing,0,1@ set uint8_t x = param >> (size + 1)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\]}, [<Rn>]!
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 1 @<4> Rm @ set uint8_t temp = param & (1 << size)@ temp=0 uint8_t spacing spacing,0,1@ set uint8_t x = param >> (size + 1)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\]}, [<Rn>], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 0 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=0b0=0b1=0b10 char align[6] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", (size ? 64 : 32))@ sprintf(align, ":128")@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\], \vecname[0x23 + d + 3*spacing]\[\%dx\]}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 0 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=0b0=0b1=0b10 char align[6] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", (size ? 64 : 32))@ sprintf(align, ":128")@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\], \vecname[0x23 + d + 3*spacing]\[\%dx\]}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 0 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=0b0=0b1=0b10 char align[6] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", (size ? 64 : 32))@ sprintf(align, ":128")@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\], \vecname[0x23 + d + 3*spacing]\[\%dx\]}, [<Rn>\align\], <Rm>
|
||||
;INVALIDATE 1 1 1 1 0 1 0 0 1 <1> 0 0 <20>
|
||||
;INVALIDATE 1 1 1 1 0 1 0 0 <2> 0 0 <20>
|
||||
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 0 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\, \vecname[0x23 + d]\}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 0 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\, \vecname[0x23 + d]\}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 0 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\, \vecname[0x23 + d]\}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 0 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\, \vecname[0x26 + d]\}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 0 1 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\, \vecname[0x26 + d]\}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 0 1 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\, \vecname[0x26 + d]\}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 1 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 1 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 1 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 1 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 1 1 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 1 1 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 0 0 size @<2> 1 1 1 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 0 0 size @<2> 1 1 0 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 0 0 size @<2> Rm @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 0 1 size @<2> 1 1 1 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 0 1 size @<2> 1 1 0 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 0 1 size @<2> Rm @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 1 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x22 + d]\}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 1 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x22 + d]\}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 1 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x22 + d]\}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 1 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 1 1 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 1 1 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 0 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 0 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 0 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 0 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 0 1 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 0 1 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 1 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 1 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 1 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\], <Rm>
|
||||
;INVALIDATE 1 1 1 1 0 1 0 0 0 <1> 1 0 <22>
|
||||
INVALIDATE 1 1 1 1 0 1 0 0 1 <1> 1 0 <8> 1 1 <10>
|
||||
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> 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> 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 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> 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> 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>
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> 1 1 1 1 @ set uint8_t temp = param & (1 << size)@ temp=0 uint8_t spacing spacing,0,1@ set uint8_t x = param >> (size + 1)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\]}, [<Rn>]
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> 1 1 0 1 @ set uint8_t temp = param & (1 << size)@ temp=0 uint8_t spacing spacing,0,1@ set uint8_t x = param >> (size + 1)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\]}, [<Rn>]!
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> Rm @ set uint8_t temp = param & (1 << size)@ temp=0 uint8_t spacing spacing,0,1@ set uint8_t x = param >> (size + 1)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\]}, [<Rn>], <Rm>
|
||||
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=0b0=0b1=0b10 char align[6] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", (size ? 64 : 32))@ sprintf(align, ":128")@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\], \vecname[0x23 + d + 3*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 0 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0b0=0b1=0b10 char align[6] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", (size ? 64 : 32))@ sprintf(align, ":128")@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\], \vecname[0x23 + d + 3*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=0b0=0b1=0b10 char align[6] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", (size ? 64 : 32))@ sprintf(align, ":128")@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\], \vecname[0x23 + d + 3*spacing]\[\%dx\]}, [<Rn>\align\], <Rm>
|
||||
;INVALIDATE 1 1 1 1 0 1 0 0 1 <1> 1 0 <20>
|
||||
;INVALIDATE 1 1 1 1 0 1 0 0 <2> 1 0 <20>
|
||||
INVALIDATE 1 1 1 1 0 1 0 0 <3> 0 <20>
|
||||
|
||||
; ===== No more 1 1 1 1 ..., so invalidate all of them ====
|
||||
INVALIDATE 1 1 1 1 <28>
|
||||
|
||||
|
||||
ARMS cond 0 0 0 0 0 0 0 S Rn Rd imm5 type 0 Rm AND{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
|
||||
ARM_ cond 0 0 0 0 0 0 0 S Rd (0) (0) (0) (0) Rm 1 0 0 1 Rn MUL{S}<c> <Rd>, <Rn>, <Rm>
|
||||
ARM_ cond 0 0 0 0 U 0 0 0 Rn Rt (0) (0) (0) (0) 1 0 1 1 Rm STRH<c> <Rt>, [<Rn>], +/-<Rm>
|
||||
ARM_ cond 0 0 0 0 U 0 0 0 Rn Rt (0) (0) (0) (0) 1 1 0 1 Rm LDRD<c> <Rt>, <Rt2>, [<Rn>], +/-<Rm>
|
||||
ARM_ cond 0 0 0 0 U 0 0 0 Rn Rt (0) (0) (0) (0) 1 1 1 1 Rm STRD<c> <Rt>, <Rt2>, [<Rn>], +/-<Rm>
|
||||
ARM_ cond 0 0 0 0 U 0 0 1 Rn Rt (0) (0) (0) (0) 1 0 1 1 Rm LDRH<c> <Rt>, [<Rn>], +/-<Rm>
|
||||
ARM_ cond 0 0 0 0 U 0 0 1 Rn Rt (0) (0) (0) (0) 1 1 0 1 Rm LDRSB<c> <Rt>, [<Rn>], +/-<Rm>
|
||||
ARM_ cond 0 0 0 0 U 0 0 1 Rn Rt (0) (0) (0) (0) 1 1 1 1 Rm LDRSH<c> <Rt>, [<Rn>], +/-<Rm>
|
||||
ARMS cond 0 0 0 0 0 0 1 S Rn Rd imm5 type 0 Rm EOR{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
|
||||
ARM_ cond 0 0 0 0 0 0 1 S Rd Ra Rm 1 0 0 1 Rn MLA{S}<c> <Rd>, <Rn>, <Rm>, <Ra>
|
||||
ARM_ cond 0 0 0 0 U 0 1 0 Rn Rt (0) (0) (0) (0) 1 0 1 1 Rm STRHT<c> <Rt>, [<Rn>], +/-<Rm>
|
||||
ARM_ cond 0 0 0 0 U 0 1 1 Rn Rt (0) (0) (0) (0) 1 0 1 1 Rm LDRHT<c> <Rt>, [<Rn>], +/-<Rm>
|
||||
ARM_ cond 0 0 0 0 U 0 1 1 Rn Rt (0) (0) (0) (0) 1 1 0 1 Rm LDRSBT<c> <Rt>, [<Rn>], +/-<Rm>
|
||||
ARM_ cond 0 0 0 0 U 0 1 1 Rn Rt (0) (0) (0) (0) 1 1 1 1 Rm LDRSHT<c> <Rt>, [<Rn>], +/-<Rm>
|
||||
ARMS cond 0 0 0 0 0 1 0 S Rn Rd imm5 type 0 Rm SUB{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
|
||||
ARM_ cond 0 0 0 0 0 1 0 0 RdHi RdLo Rm 1 0 0 1 Rn UMAAL<c> <RdLo>, <RdHi>, <Rn>, <Rm>
|
||||
ARM_ cond 0 0 0 0 U 1 0 0 Rn Rt imm4H 1 0 1 1 imm4L STRH<c> <Rt>, [<Rn>], #+/-<imm8>
|
||||
ARM_ cond 0 0 0 0 U 1 0 0 Rn Rt imm4H 1 1 0 1 imm4L LDRD<c> <Rt>, <Rt2>, [<Rn>], #+/-<imm8>
|
||||
ARM_ cond 0 0 0 0 U 1 0 0 Rn Rt imm4H 1 1 1 1 imm4L STRD<c> <Rt>, <Rt2>, [<Rn>], #+/-<imm8>
|
||||
ARM_ cond 0 0 0 0 U 1 0 1 Rn Rt imm4H 1 0 1 1 imm4L LDRH<c> <Rt>, [<Rn>], #+/-<imm8>
|
||||
ARM_ cond 0 0 0 0 U 1 0 1 Rn Rt imm4H 1 1 0 1 imm4L LDRSB<c> <Rt>, [<Rn>], #+/-<imm8>
|
||||
ARM_ cond 0 0 0 0 U 1 0 1 Rn Rt imm4H 1 1 1 1 imm4L LDRSH<c> <Rt>, [<Rn>], #+/-<imm8>
|
||||
ARMS cond 0 0 0 0 0 1 1 S Rn Rd imm5 type 0 Rm RSB{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
|
||||
ARM_ cond 0 0 0 0 0 1 1 0 Rd Ra Rm 1 0 0 1 Rn MLS<c> <Rd>, <Rn>, <Rm>, <Ra>
|
||||
ARM_ cond 0 0 0 0 U 1 1 0 Rn Rt imm4H 1 0 1 1 imm4L STRHT<c> <Rt>, [<Rn>], #+/-<imm8>
|
||||
ARM_ cond 0 0 0 0 U 1 1 1 Rn Rt imm4H 1 0 1 1 imm4L LDRHT<c> <Rt>, [<Rn>], #+/-<imm8>
|
||||
ARM_ cond 0 0 0 0 U 1 1 1 Rn Rt imm4H 1 1 0 1 imm4L LDRSBT<c> <Rt>, [<Rn>], #+/-<imm8>
|
||||
ARM_ cond 0 0 0 0 U 1 1 1 Rn Rt imm4H 1 1 1 1 imm4L LDRSHT<c> <Rt>, [<Rn>], #+/-<imm8>
|
||||
ARMS cond 0 0 0 0 1 0 0 S Rn Rd imm5 type 0 Rm ADD{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
|
||||
ARM_ cond 0 0 0 0 1 0 0 S RdHi RdLo Rm 1 0 0 1 Rn UMULL{S}<c> <RdLo>, <RdHi>, <Rn>, <Rm>
|
||||
ARMS cond 0 0 0 0 1 0 1 S Rn Rd imm5 type 0 Rm ADC{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
|
||||
ARM_ cond 0 0 0 0 1 0 1 S RdHi RdLo Rm 1 0 0 1 Rn UMLAL{S}<c> <RdLo>, <RdHi>, <Rn>, <Rm>
|
||||
ARMS cond 0 0 0 0 1 1 0 S Rn Rd imm5 type 0 Rm SBC{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
|
||||
ARM_ cond 0 0 0 0 1 1 0 S RdHi RdLo Rm 1 0 0 1 Rn SMULL{S}<c> <RdLo>, <RdHi>, <Rn>, <Rm>
|
||||
ARMS cond 0 0 0 0 1 1 1 S Rn Rd imm5 type 0 Rm RSC{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
|
||||
ARM_ cond 0 0 0 0 1 1 1 S RdHi RdLo Rm 1 0 0 1 Rn SMLAL{S}<c> <RdLo>, <RdHi>, <Rn>, <Rm>
|
||||
ARM_ cond 0 0 0 1 0 0 0 0 Rd Ra Rm 1 0 0 0 Rn SMLABB<c> <Rd>, <Rn>, <Rm>, <Ra>
|
||||
ARM_ cond 0 0 0 1 0 0 0 0 Rd Ra Rm 1 0 1 0 Rn SMLATB<c> <Rd>, <Rn>, <Rm>, <Ra>
|
||||
ARM_ cond 0 0 0 1 0 0 0 0 Rd Ra Rm 1 1 0 0 Rn SMLABT<c> <Rd>, <Rn>, <Rm>, <Ra>
|
||||
ARM_ cond 0 0 0 1 0 0 0 0 Rd Ra Rm 1 1 1 0 Rn SMLATT<c> <Rd>, <Rn>, <Rm>, <Ra>
|
||||
ARM_ cond 0 0 0 1 0 0 0 0 Rn Rt (0) (0) (0) (0) 1 0 0 1 Rm SWP<c> <Rt>, <Rm>, [<Rn>]
|
||||
ARM_ cond 0 0 0 1 U 0 W 0 Rn Rt (0) (0) (0) (0) 1 0 1 1 Rm STRH<c> <Rt>, [<Rn>, +/-<Rm>]{!}
|
||||
ARM_ cond 0 0 0 1 U 0 W 0 Rn Rt (0) (0) (0) (0) 1 1 0 1 Rm LDRD<c> <Rt>, <Rt2>, [<Rn>, +/-<Rm>]{!}
|
||||
ARM_ cond 0 0 0 1 U 0 W 0 Rn Rt (0) (0) (0) (0) 1 1 1 1 Rm STRD<c> <Rt>, <Rt2>, [<Rn>, +/-<Rm>]{!}
|
||||
ARMS cond 0 0 0 1 0 0 0 1 Rn (0) (0) (0) (0) imm5 type 0 Rm TST<c> <Rn>, <Rm>{, <shift>}
|
||||
ARM_ cond 0 0 0 1 U 0 W 1 Rn Rt (0) (0) (0) (0) 1 0 1 1 Rm LDRH<c> <Rt>, [<Rn>, +/-<Rm>]{!}
|
||||
ARM_ cond 0 0 0 1 U 0 W 1 Rn Rt (0) (0) (0) (0) 1 1 0 1 Rm LDRSB<c> <Rt>, [<Rn>, +/-<Rm>]{!}
|
||||
ARM_ cond 0 0 0 1 U 0 W 1 Rn Rt (0) (0) (0) (0) 1 1 1 1 Rm LDRSH<c> <Rt>, [<Rn>, +/-<Rm>]{!}
|
||||
ARM_ cond 0 0 0 1 0 0 1 0 (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) 0 0 0 1 Rm BX<c> <Rm>
|
||||
ARM_ cond 0 0 0 1 0 0 1 0 (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) 0 0 1 0 Rm BXJ<c> <Rm>
|
||||
ARM_ cond 0 0 0 1 0 0 1 0 (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) 0 0 1 1 Rm BLX<c> <Rm>
|
||||
ARM_ cond/=1110 0 0 0 1 0 0 1 0 imm12 0 1 1 1 imm4 BKPT #<imm16>
|
||||
ARMS cond 0 0 0 1 0 0 1 1 Rn (0) (0) (0) (0) imm5 type 0 Rm TEQ<c> <Rn>, <Rm>{, <shift>}
|
||||
ARM_ cond 0 0 0 1 0 1 0 0 Rn Rt (0) (0) (0) (0) 1 0 0 1 Rm SWPB<c> <Rt>, <Rm>, [<Rn>]
|
||||
ARM_ cond 0 0 0 1 U 1 W 0 Rn Rt imm4H 1 0 1 1 imm4L STRH<c> <Rt>, [<Rn>, #+/-<imm8>]{!}
|
||||
ARM_ cond 0 0 0 1 U 1 W 0 Rn Rt imm4H 1 1 0 1 imm4L LDRD<c> <Rt>, <Rt2>, [<Rn>, #+/-<imm8>]{!}
|
||||
ARM_ cond 0 0 0 1 U 1 W 0 Rn Rt imm4H 1 1 1 1 imm4L STRD<c> <Rt>, <Rt2>, [<Rn>, #+/-<imm8>]{!}
|
||||
ARMS cond 0 0 0 1 0 1 0 1 Rn (0) (0) (0) (0) imm5 type 0 Rm CMP<c> <Rn>, <Rm>{, <shift>}
|
||||
ARMS cond 0 0 0 1 0 1 1 1 Rn (0) (0) (0) (0) imm5 type 0 Rm CMN<c> <Rn>, <Rm>{, <shift>}
|
||||
ARM_ cond 0 0 0 1 U 1 W 1 Rn Rt imm4H 1 0 1 1 imm4L LDRH<c> <Rt>, [<Rn>, #+/-<imm8>]{!}
|
||||
ARM_ cond 0 0 0 1 U 1 W 1 Rn Rt imm4H 1 1 0 1 imm4L LDRSB<c> <Rt>, [<Rn>, #+/-<imm8>]{!}
|
||||
ARM_ cond 0 0 0 1 U 1 W 1 Rn Rt imm4H 1 1 1 1 imm4L LDRSH<c> <Rt>, [<Rn>, #+/-<imm8>]{!}
|
||||
ARMS cond 0 0 0 1 1 0 0 S Rn Rd imm5 type 0 Rm ORR{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
|
||||
ARM_ cond 0 0 0 1 1 0 0 0 Rn Rd (1) (1) (1) (1) 1 0 0 1 Rt STREX<c> <Rd>, <Rt>, [<Rn>]
|
||||
ARM_ cond 0 0 0 1 1 0 0 1 Rn Rt (1) (1) (1) (1) 1 0 0 1 (1) (1) (1) (1) LDREX<c> <Rt>, [<Rn>]
|
||||
ARM_ cond 0 0 0 1 1 0 1 S (0) (0) (0) (0) Rd 0 0 0 0 0 0 0 0 Rm MOV{S}<c> <Rd>, <Rm>
|
||||
ARM_ cond 0 0 0 1 1 0 1 S (0) (0) (0) (0) Rd imm5 0 0 0 Rm LSL{S}<c> <Rd>, <Rm>, #<imm>
|
||||
ARM_ cond 0 0 0 1 1 0 1 S (0) (0) (0) (0) Rd Rm 0 0 0 1 Rn LSL{S}<c> <Rd>, <Rn>, <Rm>
|
||||
ARM_ cond 0 0 0 1 1 0 1 S (0) (0) (0) (0) Rd imm5 0 1 0 Rm LSR{S}<c> <Rd>, <Rm>, #<imm>
|
||||
ARM_ cond 0 0 0 1 1 0 1 S (0) (0) (0) (0) Rd Rm 0 0 1 1 Rn LSR{S}<c> <Rd>, <Rn>, <Rm>
|
||||
ARM_ cond 0 0 0 1 1 0 1 S (0) (0) (0) (0) Rd imm5 1 0 0 Rm ASR{S}<c> <Rd>, <Rm>, #<imm>
|
||||
ARM_ cond 0 0 0 1 1 0 1 S (0) (0) (0) (0) Rd Rm 0 1 0 1 Rn ASR{S}<c> <Rd>, <Rn>, <Rm>
|
||||
ARM_ cond 0 0 0 1 1 0 1 S (0) (0) (0) (0) Rd 0 0 0 0 0 1 1 0 Rm RRX{S}<c> <Rd>, <Rm>
|
||||
ARM_ cond 0 0 0 1 1 0 1 S (0) (0) (0) (0) Rd imm5 1 1 0 Rm ROR{S}<c> <Rd>, <Rm>, #<imm>
|
||||
ARM_ cond 0 0 0 1 1 0 1 S (0) (0) (0) (0) Rd Rm 0 1 1 1 Rn ROR{S}<c> <Rd>, <Rn>, <Rm>
|
||||
ARM_ cond 0 0 0 1 1 0 1 0 Rn Rd (1) (1) (1) (1) 1 0 0 1 Rt STREXD<c> <Rd>, <Rt>, <Rt2>, [<Rn>]
|
||||
ARM_ cond 0 0 0 1 1 0 1 1 Rn Rt (1) (1) (1) (1) 1 0 0 1 (1) (1) (1) (1) LDREXD<c> <Rt>, <Rt2>, [<Rn>]
|
||||
ARMS cond 0 0 0 1 1 1 0 S Rn Rd imm5 type 0 Rm BIC{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
|
||||
ARM_ cond 0 0 0 1 1 1 0 0 Rn Rd (1) (1) (1) (1) 1 0 0 1 Rt STREXB<c> <Rd>, <Rt>, [<Rn>]
|
||||
ARM_ cond 0 0 0 1 1 1 0 1 Rn Rt (1) (1) (1) (1) 1 0 0 1 (1) (1) (1) (1) LDREXB<c> <Rt>, [<Rn>]
|
||||
ARMS cond 0 0 0 1 1 1 1 S (0) (0) (0) (0) Rd imm5 type 0 Rm MVN{S}<c> <Rd>, <Rm>{, <shift>}
|
||||
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>, [<Rn>]
|
||||
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 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 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>
|
||||
ARM_ cond 0 0 1 0 1 1 1 S Rn Rd imm12 RSC{S}<c> <Rd>, <Rn>, #<const>
|
||||
ARM_ cond 0 0 1 1 0 0 0 0 imm4 Rd imm12 MOVW<c> <Rd>, #<imm16>
|
||||
ARM_ cond 0 0 1 1 0 0 0 1 Rn (0) (0) (0) (0) imm12 TST<c> <Rn>, #<const>
|
||||
ARM_ cond 0 0 1 1 0 0 1 0 0 0 0 0 (1) (1) (1) (1) (0) (0) (0) (0) 0 0 0 0 0 0 0 0 NOP<c>
|
||||
ARM_ cond 0 0 1 1 0 0 1 1 Rn (0) (0) (0) (0) imm12 TEQ<c> <Rn>, #<const>
|
||||
ARM_ cond 0 0 1 1 0 1 0 0 imm4 Rd imm12 MOVT<c> <Rd>, #<imm16>
|
||||
ARM_ cond 0 0 1 1 0 1 0 1 Rn (0) (0) (0) (0) imm12 CMP<c> <Rn>, #<const>
|
||||
ARM_ cond 0 0 1 1 0 1 1 1 Rn (0) (0) (0) (0) imm12 CMN<c> <Rn>, #<const>
|
||||
ARM_ cond 0 0 1 1 1 0 0 S Rn Rd imm12 ORR{S}<c> <Rd>, <Rn>, #<const>
|
||||
ARM_ cond 0 0 1 1 1 0 1 S (0) (0) (0) (0) Rd imm12 MOV{S}<c> <Rd>, #<const>
|
||||
ARM_ cond 0 0 1 1 1 1 0 S Rn Rd imm12 BIC{S}<c> <Rd>, <Rn>, #<const>
|
||||
ARM_ cond 0 0 1 1 1 1 1 S (0) (0) (0) (0) Rd imm12 MVN{S}<c> <Rd>, #<const>
|
||||
ARM_ cond 0 1 0 0 1 0 0 1 1 1 0 1 Rt 0 0 0 0 0 0 0 0 0 1 0 0 POP<c> {<Rt>}
|
||||
ARM_ cond 0 1 0 0 U 0 0 0 Rn Rt imm12 STR<c> <Rt>, [<Rn>], #+/-<imm12>
|
||||
ARM_ cond 0 1 0 0 U 0 0 1 Rn Rt imm12 LDR<c> <Rt>, [<Rn>], #+/-<imm12>
|
||||
ARM_ cond 0 1 0 0 U 0 1 0 Rn Rt imm12 STRT<c> <Rt>, [<Rn>], #+/-<imm12>
|
||||
ARM_ cond 0 1 0 0 U 0 1 1 Rn Rt imm12 LDRT<c> <Rt>, [<Rn>], #+/-<imm12>
|
||||
ARM_ cond 0 1 0 0 U 1 0 0 Rn Rt imm12 STRB<c> <Rt>, [<Rn>], #+/-<imm12>
|
||||
ARM_ cond 0 1 0 0 U 1 0 1 Rn Rt imm12 LDRB<c> <Rt>, [<Rn>], #+/-<imm12>
|
||||
ARM_ cond 0 1 0 0 U 1 1 0 Rn Rt imm12 STRBT<c> <Rt>, [<Rn>], #+/-<imm12>
|
||||
ARM_ cond 0 1 0 0 U 1 1 1 Rn Rt imm12 LDRBT<c> <Rt>, [<Rn>], #+/-<imm12>
|
||||
ARM_ cond 0 1 0 1 0 0 1 0 1 1 0 1 Rt 0 0 0 0 0 0 0 0 0 1 0 0 PUSH<c> {<Rt>}
|
||||
ARM_ cond 0 1 0 1 U 0 W 0 Rn Rt imm12 STR<c> <Rt>, [<Rn>, #+/-<imm12>]{!}
|
||||
ARM_ cond 0 1 0 1 U 0 W 1 Rn Rt imm12 LDR<c> <Rt>, [<Rn>, #+/-<imm12>]{!}
|
||||
ARM_ cond 0 1 0 1 U 1 W 0 Rn Rt imm12 STRB<c> <Rt>, [<Rn>, #+/-<imm12>]{!}
|
||||
ARM_ cond 0 1 0 1 U 1 W 1 Rn Rt imm12 LDRB<c> <Rt>, [<Rn>, #+/-<imm12>]{!}
|
||||
ARM_ cond 0 1 1 0 0 0 0 1 Rn Rd (1) (1) (1) (1) 0 1 0 1 Rm SSAX<c> <Rd>, <Rn>, <Rm>
|
||||
ARM_ cond 0 1 1 0 0 0 0 1 Rn Rd (1) (1) (1) (1) 0 1 1 1 Rm SSUB16<c> <Rd>, <Rn>, <Rm>
|
||||
ARM_ cond 0 1 1 0 0 0 0 1 Rn Rd (1) (1) (1) (1) 1 1 1 1 Rm SSUB8<c> <Rd>, <Rn>, <Rm>
|
||||
ARM_ cond 0 1 1 0 0 1 0 1 Rn Rd (1) (1) (1) (1) 0 1 0 1 Rm USAX<c> <Rd>, <Rn>, <Rm>
|
||||
ARM_ cond 0 1 1 0 0 1 0 1 Rn Rd (1) (1) (1) (1) 0 1 1 1 Rm USUB16<c> <Rd>, <Rn>, <Rm>
|
||||
ARM_ cond 0 1 1 0 0 1 0 1 Rn Rd (1) (1) (1) (1) 1 1 1 1 Rm USUB8<c> <Rd>, <Rn>, <Rm>
|
||||
ARMs cond 0 1 1 0 1 0 0 0 Rn Rd imm5 0 0 1 Rm PKHBT<c> <Rd>, <Rn>, <Rm>{, <shift>}
|
||||
ARMs cond 0 1 1 0 1 0 0 0 Rn Rd imm5 1 0 1 Rm PKHTB<c> <Rd>, <Rn>, <Rm>{, <shift>}
|
||||
ARM_ cond 0 1 1 0 1 0 0 0 1 1 1 1 Rd rotate (0) (0) 0 1 1 1 Rm SXTB16<c> <Rd>, <Rm>{, <rotation>}
|
||||
ARM_ cond 0 1 1 0 1 0 0 0 Rn Rd rotate (0) (0) 0 1 1 1 Rm SXTAB16<c> <Rd>, <Rn>, <Rm>{, <rotation>}
|
||||
ARMs cond 0 1 1 0 1 0 1 sat_imm Rd imm5 sh 0 1 Rn SSAT<c> <Rd>, #<imm>, <Rn>{, <shift>}
|
||||
ARM_ cond 0 1 1 0 1 0 1 0 sat_imm Rd (1) (1) (1) (1) 0 0 1 1 Rn SSAT16<c> <Rd>, #<imm>, <Rn>
|
||||
ARM_ cond 0 1 1 0 1 0 1 0 1 1 1 1 Rd rotate (0) (0) 0 1 1 1 Rm SXTB<c> <Rd>, <Rm>{, <rotation>}
|
||||
ARM_ cond 0 1 1 0 1 0 1 0 Rn Rd rotate (0) (0) 0 1 1 1 Rm SXTAB<c> <Rd>, <Rn>, <Rm>{, <rotation>}
|
||||
ARM_ cond 0 1 1 0 1 0 1 1 (1) (1) (1) (1) Rd (1) (1) (1) (1) 0 0 1 1 Rm REV<c> <Rd>, <Rm>
|
||||
ARM_ cond 0 1 1 0 1 0 1 1 (1) (1) (1) (1) Rd (1) (1) (1) (1) 1 0 1 1 Rm REV16<c> <Rd>, <Rm>
|
||||
ARM_ cond 0 1 1 0 1 0 1 1 1 1 1 1 Rd rotate (0) (0) 0 1 1 1 Rm SXTH<c> <Rd>, <Rm>{, <rotation>}
|
||||
ARM_ cond 0 1 1 0 1 0 1 1 Rn Rd rotate (0) (0) 0 1 1 1 Rm SXTAH<c> <Rd>, <Rn>, <Rm>{, <rotation>}
|
||||
ARM_ cond 0 1 1 0 1 1 0 0 1 1 1 1 Rd rotate (0) (0) 0 1 1 1 Rm UXTB16<c> <Rd>, <Rm>{, <rotation>}
|
||||
ARM_ cond 0 1 1 0 1 1 0 0 Rn Rd rotate (0) (0) 0 1 1 1 Rm UXTAB16<c> <Rd>, <Rn>, <Rm>{, <rotation>}
|
||||
ARMs cond 0 1 1 0 1 1 1 sat_imm Rd imm5 sh 0 1 Rn USAT<c> <Rd>, #<imm>, <Rn>{, <shift>}
|
||||
ARM_ cond 0 1 1 0 1 1 1 0 sat_imm Rd (1) (1) (1) (1) 0 0 1 1 Rn USAT16<c> <Rd>, #<imm>, <Rn>
|
||||
ARM_ cond 0 1 1 0 1 1 1 0 1 1 1 1 Rd rotate (0) (0) 0 1 1 1 Rm UXTB<c> <Rd>, <Rm>{, <rotation>}
|
||||
ARM_ cond 0 1 1 0 1 1 1 0 Rn Rd rotate (0) (0) 0 1 1 1 Rm UXTAB<c> <Rd>, <Rn>, <Rm>{, <rotation>}
|
||||
ARM_ cond 0 1 1 0 1 1 1 1 1 1 1 1 Rd rotate (0) (0) 0 1 1 1 Rm UXTH<c> <Rd>, <Rm>{, <rotation>}
|
||||
ARM_ cond 0 1 1 0 1 1 1 1 (1) (1) (1) (1) Rd (1) (1) (1) (1) 1 0 1 1 Rm REVSH<c> <Rd>, <Rm>
|
||||
ARM_ cond 0 1 1 0 1 1 1 1 Rn Rd rotate (0) (0) 0 1 1 1 Rm UXTAH<c> <Rd>, <Rn>, <Rm>{, <rotation>}
|
||||
ARMs cond 0 1 1 0 U 0 0 0 Rn Rt imm5 type 0 Rm STR<c> <Rt>, [<Rn>], +/-<Rm>{, <shift>}
|
||||
ARMs cond 0 1 1 0 U 0 0 1 Rn Rt imm5 type 0 Rm LDR<c> <Rt>, [<Rn>], +/-<Rm>{, <shift>}
|
||||
ARMs cond 0 1 1 0 U 0 1 0 Rn Rt imm5 type 0 Rm STRT<c> <Rt>, [<Rn>], +/-<Rm>{, <shift>}
|
||||
ARMs cond 0 1 1 0 U 0 1 1 Rn Rt imm5 type 0 Rm LDRT<c> <Rt>, [<Rn>], +/-<Rm>{, <shift>}
|
||||
ARMs cond 0 1 1 0 U 1 0 0 Rn Rt imm5 type 0 Rm STRB<c> <Rt>, [<Rn>], +/-<Rm>{, <shift>}
|
||||
ARMs cond 0 1 1 0 U 1 0 1 Rn Rt imm5 type 0 Rm LDRB<c> <Rt>, [<Rn>], +/-<Rm>{, <shift>}
|
||||
ARMs cond 0 1 1 0 U 1 1 0 Rn Rt imm5 type 0 Rm STRBT<c> <Rt>, [<Rn>], +/-<Rm>{, <shift>}
|
||||
ARMs cond 0 1 1 0 U 1 1 1 Rn Rt imm5 type 0 Rm LDRBT<c> <Rt>, [<Rn>], +/-<Rm>{, <shift>}
|
||||
ARMs cond 0 1 1 1 U 0 W 0 Rn Rt imm5 type 0 Rm STR<c> <Rt>, [<Rn>, +/-<Rm>{, <shift>}]{!}
|
||||
ARMs cond 0 1 1 1 U 0 W 1 Rn Rt imm5 type 0 Rm LDR<c> <Rt>, [<Rn>, +/-<Rm>{, <shift>}]{!}
|
||||
ARMs cond 0 1 1 1 U 1 W 0 Rn Rt imm5 type 0 Rm STRB<c> <Rt>, [<Rn>, +/-<Rm>{, <shift>}]{!}
|
||||
ARMs cond 0 1 1 1 U 1 W 1 Rn Rt imm5 type 0 Rm LDRB<c> <Rt>, [<Rn>, +/-<Rm>{, <shift>}]{!}
|
||||
ARM_ cond 0 1 1 1 1 0 0 0 Rd 1 1 1 1 Rm 0 0 0 1 Rn USAD8<c> <Rd>, <Rn>, <Rm>
|
||||
ARM_ cond 0 1 1 1 1 0 0 0 Rd Ra Rm 0 0 0 1 Rn USADA8<c> <Rd>, <Rn>, <Rm>, <Ra>
|
||||
ARM_ cond 0 1 1 1 1 1 0 msb Rd lsb 0 0 1 1 1 1 1 BFC<c> <Rd>, #<lsb>, #<width>
|
||||
ARM_ cond 0 1 1 1 1 1 0 msb Rd lsb 0 0 1 Rn BFI<c> <Rd>, <Rn>, #<lsb>, #<width>
|
||||
ARM_ cond 0 1 1 1 1 1 1 widthm1 Rd lsb 1 0 1 Rn UBFX<c> <Rd>, <Rn>, #<lsb>, #<width>
|
||||
ARM_ cond 1 0 0 0 0 0 W 0 Rn/=1101 register_list STMED<c> <Rn>{!}, <registers>
|
||||
ARM_ cond 1 0 0 0 0 0 W 0 Rn register_list STMDA<c> <Rn>{!}, <registers>
|
||||
ARM_ cond 1 0 0 0 0 0 W 1 Rn/=1101 register_list LDMED<c> <Rn>{!}, <registers>
|
||||
ARM_ cond 1 0 0 0 0 0 W 1 Rn register_list LDMDA<c> <Rn>{!}, <registers>
|
||||
ARM_ cond 1 0 0 0 1 0 W 0 Rn/=1101 register_list STMEA<c> <Rn>{!}, <registers>
|
||||
ARM_ cond 1 0 0 0 1 0 W 0 Rn register_list STM<c> <Rn>{!}, <registers>
|
||||
ARM_ cond 1 0 0 0 1 0 0 1 Rn/=1101 register_list LDMEA<c> <Rn>, <registers>
|
||||
ARM_ cond 1 0 0 0 1 0 1 1 1 1 0 1 register_list @ = const char* op @@ (reglist != 0) && ((reglist & (reglist - 1)) == 0)@ op,"POP","LDMEA"@ @ \op\<c> <registers>
|
||||
ARM_ cond 1 0 0 0 1 0 W 1 Rn register_list LDM<c> <Rn>{!}, <registers>
|
||||
ARM_ cond 1 0 0 1 0 0 0 0 Rn/=1101 register_list STMFD<c> <Rn>, <registers>
|
||||
ARM_ cond 1 0 0 1 0 0 1 0 1 1 0 1 register_list @ = const char* op @@ (reglist != 0) && ((reglist & (reglist - 1)) == 0)@ op,"PUSH","STMFD"@ @ \op\<c> <registers>
|
||||
ARM_ cond 1 0 0 1 0 0 W 0 Rn register_list STMDB<c> <Rn>{!}, <registers>
|
||||
ARM_ cond 1 0 0 1 0 0 W 1 Rn/=1101 register_list LDMFD<c> <Rn>{!}, <registers>
|
||||
ARM_ cond 1 0 0 1 0 0 W 1 Rn register_list LDMDB<c> <Rn>{!}, <registers>
|
||||
ARM_ cond 1 0 0 1 1 0 W 0 Rn/=1101 register_list STMFA<c> <Rn>{!}, <registers>
|
||||
ARM_ cond 1 0 0 1 1 0 W 0 Rn register_list STMIB<c> <Rn>{!}, <registers>
|
||||
ARM_ cond 1 0 0 1 1 0 W 1 Rn/=1101 register_list LDMFA<c> <Rn>{!}, <registers>
|
||||
ARM_ cond 1 0 0 1 1 0 W 1 Rn register_list LDMIB<c> <Rn>{!}, <registers>
|
||||
ARM_ cond 1 0 1 0 imm24 B<c> <label>
|
||||
ARM_ cond 1 0 1 1 imm24 BL<c> <label>
|
||||
|
||||
VFPU cond 1 1 0 0 0 1 0 0 Rn Rt 1 0 1 0 0 0 M 1 Vm VMOV<c> <Sm>, <Sm1>, <Rt>, <Rn>
|
||||
VFPU cond 1 1 0 0 0 1 0 1 Rn Rt 1 0 1 0 0 0 M 1 Vm VMOV<c> <Rt>, <Rn>, <Sm>, <Sm1>
|
||||
VFPU cond 1 1 0 0 0 1 0 0 Rn Rt 1 0 1 1 0 0 M 1 Vm VMOV<c> <Dm>, <Rt>, <Rn>
|
||||
VFPU cond 1 1 0 0 0 1 0 1 Rn Rt 1 0 1 1 0 0 M 1 Vm VMOV<c> <Rt>, <Rn>, <Dm>
|
||||
;INVALIDATE <4> 1 1 0 0 0 1 0 <9> 1 0 1 <9>
|
||||
|
||||
INVALIDATE <4> 1 1 0 0 0 <11> 1 0 1 <9>
|
||||
INVALIDATE <4> 1 1 0 0 0 <11> 1 0 1 <9>
|
||||
INVALIDATE <4> 1 1 0 1 1 <1> 1 <9> 1 0 1 <9>
|
||||
INVALIDATE <4> 1 1 0 1 1 <1> 1 <9> 1 0 1 <9>
|
||||
VFPU cond 1 1 0 1 0 D 1 0 1 1 0 1 Vd 1 0 1 1 imm8/01 @ set --imm8@ @ FSTMX<c> <LIst>
|
||||
VFPU cond 1 1 0 1 0 D 1 0 1 1 0 1 Vd 1 0 1 sz imm8 VPUSH<c> <list>
|
||||
VFPU cond 1 1 0 1 U D 0 0 Rn Vd 1 0 1 sz imm8 VSTR<c> <Dd>, [<Rn>{, #+/-<imm>}]
|
||||
VFPU cond 1 1 0 @<2> D W 0 Rn Vd 1 0 1 1 imm8/01 @ set --imm8@ @ FSTM\(param == 0b01 ? "IA" : "DB")\X<c> <Rn>{!}, <LIst>
|
||||
VFPU cond 1 1 0 @<2> D W 0 Rn Vd 1 0 1 sz imm8 VSTM\(param == 0b01 ? "IA" : "DB")\<c> <Rn>{!}, <list>
|
||||
VFPU cond 1 1 0 0 1 D 1 1 1 1 0 1 Vd 1 0 1 1 imm8/01 @ set --imm8@ @ FLDMX<c> <LIst>
|
||||
VFPU cond 1 1 0 0 1 D 1 1 1 1 0 1 Vd 1 0 1 sz imm8 VPOP<c> <list>
|
||||
VFPU cond 1 1 0 1 0 D 0 1 1 1 1 1 Vd 1 0 1 sz 0 0 0 0 0 0 0 0 VLDR<c> <Dd>, [PC, #-0]
|
||||
VFPU cond 1 1 0 1 U D 0 1 1 1 1 1 Vd 1 0 1 sz imm8 VLDR<c> <Dd>, <label>
|
||||
VFPU cond 1 1 0 1 U D 0 1 Rn Vd 1 0 1 sz imm8 VLDR<c> <Dd>, [<Rn>{, #+/-<imm>}]
|
||||
VFPU cond 1 1 0 @<2> D W 1 Rn Vd 1 0 1 1 imm8/01 @ set --imm8@ @ FLDM\(param == 0b01 ? "IA" : "DB")\X<c> <Rn>{!}, <LIst>
|
||||
VFPU cond 1 1 0 @<2> D W 1 Rn Vd 1 0 1 sz imm8 VLDM\(param == 0b01 ? "IA" : "DB")\<c> <Rn>{!}, <list>
|
||||
INVALIDATE <4> 1 1 0 <25>
|
||||
|
||||
INVALIDATE <4> 1 1 1 0 0 0 <1> 0 <8> 1 0 1 1 <1> 1 0 1 (0) (0) (0) (0)
|
||||
;INVALIDATE <4> 1 1 1 0 1 <2> 0 <8> 1 0 1 1 <1> 0 <1> 1 (0) (0) (0) (0)
|
||||
VFPU cond 1 1 1 0 0 0 0 0 Vn Rt 1 0 1 0 N (0) (0) 1 (0) (0) (0) (0) VMOV<c> <Sn>, <Rt>
|
||||
VFPU cond 1 1 1 0 1 1 1 0 0 0 0 1 Rt 1 0 1 0 (0) (0) (0) 1 (0) (0) (0) (0) VMSR<c> FPSCR, <Rt>
|
||||
VFPU cond 1 1 1 0 0 @<2> 0 Vd Rt 1 0 1 1 D @<2> 1 (0) (0) (0) (0) @ set uint8_t opc = (param1_2 << 2) + param2_2@ = uint8_t shift @@ (opc & 0b1000) == 0b1000@ @@ (opc & 0b1001) == 0b0001@ @@ (opc & 0b1011) == 0b0000@ shift,0,1,2,0xFF@ set uint8_t decodedImm = (opc & 0x7) >> shift@ @ VMOV<c>.\%d8 &l&l shift\ <Dd[x]>, <Rt>
|
||||
VFPU cond 1 1 1 0 1 0 Q 0 Vd Rt 1 0 1 1 D 0 0 1 (0) (0) (0) (0) VDUP<c>.32 <Qd>, <Rt>
|
||||
VFPU cond 1 1 1 0 1 0 Q 0 Vd Rt 1 0 1 1 D 0 1 1 (0) (0) (0) (0) VDUP<c>.16 <Qd>, <Rt>
|
||||
VFPU cond 1 1 1 0 1 1 Q 0 Vd Rt 1 0 1 1 D 0 0 1 (0) (0) (0) (0) VDUP<c>.8 <Qd>, <Rt>
|
||||
VFPU cond 1 1 1 0 0 0 0 1 Vn Rt 1 0 1 0 N (0) (0) 1 (0) (0) (0) (0) VMOV<c> <Rt>, <Sn>
|
||||
VFPU cond 1 1 1 0 1 1 1 1 0 0 0 1 Rt 1 0 1 0 (0) (0) (0) 1 (0) (0) (0) (0) VMRS<c> <Rt>, FPSCR
|
||||
VFPU cond 1 1 1 0 U @<2> 1 Vn Rt 1 0 1 1 N @<2> 1 (0) (0) (0) (0) @ set uint8_t opc = (u << 3) + (param1_2 << 2) + param2_2@ = uint8_t shift, size @@ (opc & 0b01000) == 0b01000@ @@ (opc & 0b01001) == 0b00001@ @@ (opc & 0b11011) == 0b00000@ shift,0,1,2,0xFF;size,0,1,2,4@ set uint8_t decodedImm = (opc & 0x7) >> shift@ @ VMOV<c>.<dt> <Rt>, <Dn[x]>
|
||||
INVALIDATE <4> 1 1 1 0 <12> 1 0 1 <4> 1 <4>
|
||||
|
||||
VFPU cond 1 1 1 0 0 D 0 0 Vn Vd 1 0 1 sz N op M 0 Vm VML\(op ? "S" : "A")\<c>.F\(size ? "64" : "32")\ <Dd>, <Dn>, <Dm>
|
||||
VFPU cond 1 1 1 0 0 D 0 1 Vn Vd 1 0 1 sz N op M 0 Vm VNML\(op ? "S" : "A")\<c>.F\(size ? "64" : "32")\ <Dd>, <Dn>, <Dm>
|
||||
VFPU cond 1 1 1 0 0 D 1 0 Vn Vd 1 0 1 sz N 0 M 0 Vm VMUL<c>.F\(size ? "64" : "32")\ <Dd>, <Dn>, <Dm>
|
||||
VFPU cond 1 1 1 0 0 D 1 0 Vn Vd 1 0 1 sz N 1 M 0 Vm VNMUL<c>.F\(size ? "64" : "32")\ <Dd>, <Dn>, <Dm>
|
||||
VFPU cond 1 1 1 0 0 D 1 1 Vn Vd 1 0 1 sz N 0 M 0 Vm VADD<c>.F\(size ? "64" : "32")\ <Dd>, <Dn>, <Dm>
|
||||
VFPU cond 1 1 1 0 0 D 1 1 Vn Vd 1 0 1 sz N 1 M 0 Vm VSUB<c>.F\(size ? "64" : "32")\ <Dd>, <Dn>, <Dm>
|
||||
VFPU cond 1 1 1 0 1 D 0 0 Vn Vd 1 0 1 sz N 0 M 0 Vm VDIV<c>.F\(size ? "64" : "32")\ <Dd>, <Dn>, <Dm>
|
||||
VFPU cond 1 1 1 0 1 D 0 1 Vn Vd 1 0 1 sz N op M 0 Vm VFNM\(op ? "A" : "S")\<c>.F\(size ? "64" : "32")\ <Dd>, <Dn>, <Dm>
|
||||
VFPU cond 1 1 1 0 1 D 1 0 Vn Vd 1 0 1 sz N op M 0 Vm VFM\(op ? "S" : "A")\<c>.F\(size ? "64" : "32")\ <Dd>, <Dn>, <Dm>
|
||||
|
||||
!/VFPU cond 1 1 1 0 1 x 1 1 opc2 <4> 1 0 1 <1> - - <1> 0 opc4 Table A7-17
|
||||
VFPU cond 1 1 1 0 1 D 1 1 @<4> Vd 1 0 1 0 (0) 0 (0) 0 @<4> @ set int8_t sign = (param1_4 >> 3) ? -1 : 1@ set uint8_t exp = ((param1_4 & 0b111) ^ 0b100)@ set float mantissa = 16 + param2_4@ set float imm = sign * (1 << exp) * mantissa / 128.@ @ VMOV<c>.F32 <Sd>, #\%fimm\
|
||||
VFPU cond 1 1 1 0 1 D 1 1 @<4> Vd 1 0 1 1 (0) 0 (0) 0 @<4> @ set int8_t sign = (param1_4 >> 3) ? -1 : 1@ set uint8_t exp = ((param1_4 & 0b111) ^ 0b100)@ set double mantissa = 16 + param2_4@ set double imm = sign * (1 << exp) * mantissa / 128.@ @ VMOV<c>.F64 <Dd>, #\%fimm\
|
||||
VFPU cond 1 1 1 0 1 D 1 1 0 0 0 0 Vd 1 0 1 sz 0 1 M 0 Vm VMOV<c>.F\(size ? "64" : "32")\ <Dd>, <Dm>
|
||||
VFPU cond 1 1 1 0 1 D 1 1 0 0 0 0 Vd 1 0 1 sz 1 1 M 0 Vm VABS<c>.F\(size ? "64" : "32")\ <Dd>, <Dm>
|
||||
VFPU cond 1 1 1 0 1 D 1 1 0 0 0 1 Vd 1 0 1 sz 0 1 M 0 Vm VNEG<c>.F\(size ? "64" : "32")\ <Dd>, <Dm>
|
||||
VFPU cond 1 1 1 0 1 D 1 1 0 0 0 1 Vd 1 0 1 sz 1 1 M 0 Vm VSQRT<c>.F\(size ? "64" : "32")\ <Dd>, <Dm>
|
||||
VFPU cond 1 1 1 0 1 D 1 1 0 0 1 0 Vd 1 0 1 (0) @<1> 1 M 0 Vm VCVT\(param ? "T" : "B")\<c>.F32.F16 <Sd>, <Sm>
|
||||
VFPU cond 1 1 1 0 1 D 1 1 0 0 1 1 Vd 1 0 1 (0) @<1> 1 M 0 Vm VCVT\(param ? "T" : "B")\<c>.F16.F32 <Sd>, <Sm>
|
||||
VFPU cond 1 1 1 0 1 D 1 1 0 1 0 0 Vd 1 0 1 sz op 1 M 0 Vm VCMP\(op ? "E" : "")\<c>.F\(size ? "64" : "32")\ <Dd>, <Dm>
|
||||
VFPU cond 1 1 1 0 1 D 1 1 0 1 0 1 Vd 1 0 1 sz op 1 (0) 0 (0) (0) (0) (0) VCMP\(op ? "E" : "")\<c>.F\(size ? "64" : "32")\ <Dd>, #0.0
|
||||
VFPU cond 1 1 1 0 1 D 1 1 0 1 1 1 Vd 1 0 1 0 1 1 M 0 Vm VCVT<c>.F64.F32 <Dd>, <Sm>
|
||||
VFPU cond 1 1 1 0 1 D 1 1 0 1 1 1 Vd 1 0 1 1 1 1 M 0 Vm VCVT<c>.F32.F64 <Sd>, <Dm>
|
||||
VFPU cond 1 1 1 0 1 D 1 1 1 0 0 0 Vd 1 0 1 sz op 1 M 0 Vm VCVT<c>.F\(size ? "64" : "32")\.\(op ? "S" : "U")\32 <Dd>, <Sm>
|
||||
VFPU cond 1 1 1 0 1 D 1 1 1 0 1 U Vd 1 0 1 sz op 1 i 0 imm4 @ set uint8_t td = (u << 2) + op + 1@ td=0b001=0b010=0b101 const char* Td Td,"S16","U16","S32","U32"@ set imm5 = (16 << op) - (imm5 >> 4) - ((imm5 & 0xF) << 1)@ @ VCVT<c>.F\(size ? "64" : "32")\.\Td\ <Dd>, <Dd>, #<imm>
|
||||
VFPU cond 1 1 1 0 1 D 1 1 1 1 0 U Vd 1 0 1 sz op 1 M 0 Vm VCVT\(op ? "" : "R")\<c>.\(u ? "U" : "S")\32.F\(size ? "64" : "32")\ <Sd>, <Dm>
|
||||
VFPU cond 1 1 1 0 1 D 1 1 1 1 1 U Vd 1 0 1 sz op 1 i 0 imm4 @ set uint8_t td = (u << 2) + op + 1@ td=0b001=0b010=0b101 const char* Td Td,"S16","U16","S32","U32"@ set imm5 = (16 << op) - (imm5 >> 4) - ((imm5 & 0xF) << 1)@ @ VCVT<c>.\Td\.F\(size ? "64" : "32")\ <Dd>, <Dd>, #<imm>
|
||||
;INVALIDATE <4> 1 1 1 0 1 <1> 1 1 <8> 1 0 1 <4> 0 <4>
|
||||
;INVALIDATE <4> 1 1 1 0 <12> 1 0 1 <4> 0 <4>
|
||||
|
||||
; ============= END OF REGISTERED INSTRUCTIONS ============
|
||||
INVALIDATE <32>
|
||||
Executable
+25
@@ -0,0 +1,25 @@
|
||||
//arm update linker table for dynarec
|
||||
//called with pointer to emu as 1st parameter
|
||||
//and address of table to as 2nd parameter
|
||||
//ip is at r12
|
||||
|
||||
.text
|
||||
.align 4
|
||||
|
||||
.extern UpdateLinkTable
|
||||
|
||||
.global arm_linker
|
||||
arm_linker:
|
||||
// emu is r0
|
||||
stm r0, {r4-r12} // put back reg value in emu, including EIP (easier debugging, and safer)
|
||||
// table offset is r1
|
||||
// IP address is r12
|
||||
push {r0, r1, r12}
|
||||
mov r2, r12
|
||||
// call the function
|
||||
bl UpdateLinkTable
|
||||
// return offset is jump address
|
||||
mov r3, r0
|
||||
pop {r0, r1, r12}
|
||||
bx r3
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,6 @@
|
||||
#ifndef _ARM_PRINTER_H_
|
||||
#define _ARM_PRINTER_H_
|
||||
|
||||
const char* arm_print(uint32_t opcode);
|
||||
|
||||
#endif //_ARM_PRINTER_H_
|
||||
Executable
+19
@@ -0,0 +1,19 @@
|
||||
//arm prologue for dynarec
|
||||
//Save stuff, prepare stack and register
|
||||
//called with pointer to emu as 1st parameter
|
||||
//and address to jump to as 2nd parameter
|
||||
|
||||
.text
|
||||
.align 4
|
||||
|
||||
.global arm_prolog
|
||||
arm_prolog:
|
||||
//save all used register
|
||||
push {r4-r11, lr}
|
||||
//vpush {d8-d15}
|
||||
//setup emu -> register
|
||||
//push {r0}
|
||||
ldm r0, {r4-r11} // all 8 register in direct access, no EIP (so r12 can be used as scratch)
|
||||
//TODO
|
||||
//jump to function
|
||||
bx r1
|
||||
Executable
+19
@@ -0,0 +1,19 @@
|
||||
//arm try to update linker table for dynarec
|
||||
//and address of table to as 1st parameter
|
||||
//jump addres as second and ip as third
|
||||
// don't retry if failed to write...
|
||||
|
||||
.text
|
||||
.align 4
|
||||
|
||||
.global arm_tableupdate
|
||||
arm_tableupdate:
|
||||
// jump address is r0 and IP address is r1
|
||||
// table offset is r2
|
||||
push {r4, r5}
|
||||
ldrexd r4, r5, [r2]
|
||||
strexd r3, r0, r1, [r2]
|
||||
pop {r4, r5}
|
||||
mov r0, r3
|
||||
bx lr
|
||||
|
||||
Executable
+587
@@ -0,0 +1,587 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x86emu_private.h"
|
||||
#include "tools/bridge_private.h"
|
||||
#include "x86run.h"
|
||||
#include "x86emu.h"
|
||||
#include "box86stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x86run_private.h"
|
||||
#include "x86trace.h"
|
||||
#include "dynablock.h"
|
||||
#include "dynablock_private.h"
|
||||
#include "dynarec_private.h"
|
||||
#include "elfloader.h"
|
||||
#ifdef ARM
|
||||
#include "dynarec_arm.h"
|
||||
#else
|
||||
#error Unsupported architecture!
|
||||
#endif
|
||||
|
||||
#include "khash.h"
|
||||
|
||||
KHASH_MAP_INIT_INT(dynablocks, dynablock_t*)
|
||||
|
||||
KHASH_SET_INIT_INT(mark)
|
||||
|
||||
uint32_t X31_hash_code(void* addr, int len)
|
||||
{
|
||||
if(!len) return 0;
|
||||
uint8_t* p = (uint8_t*)addr;
|
||||
int32_t h = *p;
|
||||
for (--len, ++p; len; --len, ++p) h = (h << 5) - h + (int32_t)*p;
|
||||
return (uint32_t)h;
|
||||
}
|
||||
|
||||
dynablocklist_t* NewDynablockList(uintptr_t base, uintptr_t text, int textsz, int nolinker, int direct)
|
||||
{
|
||||
dynablocklist_t* ret = (dynablocklist_t*)calloc(1, sizeof(dynablocklist_t));
|
||||
ret->blocks = (nolinker && direct)?NULL:kh_init(dynablocks);
|
||||
ret->base = base;
|
||||
ret->text = text;
|
||||
ret->textsz = textsz;
|
||||
ret->nolinker = nolinker;
|
||||
pthread_rwlock_init(&ret->rwlock_blocks, NULL);
|
||||
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 ret;
|
||||
}
|
||||
|
||||
void FreeDynablock(dynablock_t* db)
|
||||
{
|
||||
if(db) {
|
||||
dynarec_log(LOG_DEBUG, "FreeDynablock(%p), db->block=%p x86=%p:%p father=%p, tablesz=%d, %swith %d son(s)\n", db, db->block, db->x86_addr, db->x86_addr+db->x86_size, db->father, db->tablesz, db->marks?"with marks, ":"", db->sons_size);
|
||||
db->done = 0;
|
||||
// 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;
|
||||
}
|
||||
// remove from hash if there
|
||||
if (db->parent->blocks) {
|
||||
khint_t kdb;
|
||||
kdb = kh_get(dynablocks, db->parent->blocks, (uintptr_t) db->x86_addr - db->parent->base);
|
||||
if(kdb!=kh_end(db->parent->blocks))
|
||||
kh_del(dynablocks, db->parent->blocks, kdb);
|
||||
}
|
||||
|
||||
if(db->marks) {
|
||||
// Follow mark and set arm_linker instead
|
||||
khint_t k;
|
||||
kh_foreach_key(db->marks, k,
|
||||
void** p = (void**)(uintptr_t)k;
|
||||
dynarec_log(LOG_DEBUG, " -- resettable(%p)\n", p);
|
||||
resettable(p);
|
||||
);
|
||||
// free mark
|
||||
kh_destroy(mark, db->marks);
|
||||
db->marks = NULL;
|
||||
}
|
||||
for(int i=0; i<db->tablesz; i+=4) {
|
||||
dynablock_t* p = (dynablock_t*)db->table[i+3];
|
||||
dynarec_log(LOG_DEBUG, " -- table[%d+3] = %p ", i, p);
|
||||
if(p && p!=db && p->marks) {
|
||||
khint_t kd = kh_get(mark, p->marks, (uintptr_t)(&db->table[i+0]));
|
||||
if(kd!=kh_end(p->marks)) {
|
||||
kh_del(mark, p->marks, kd);
|
||||
dynarec_log(LOG_DEBUG, "cleaned");
|
||||
}
|
||||
else {dynarec_log(LOG_DEBUG, "not found");}
|
||||
}
|
||||
dynarec_log(LOG_DEBUG, "\n");
|
||||
}
|
||||
// remove and free the sons
|
||||
for (int i=0; i<db->sons_size; ++i) {
|
||||
dynablock_t *son = db->sons[i];
|
||||
db->sons[i] = NULL;
|
||||
FreeDynablock(son);
|
||||
}
|
||||
// only the father free the DynarecMap
|
||||
if(!db->father) {
|
||||
dynarec_log(LOG_DEBUG, " -- FreeDyrecMap(%p, %d)\n", db->block, db->size);
|
||||
FreeDynarecMap((uintptr_t)db->block, db->size);
|
||||
}
|
||||
free(db->sons);
|
||||
free(db->table);
|
||||
free(db);
|
||||
}
|
||||
}
|
||||
|
||||
void FreeDynablockList(dynablocklist_t** dynablocks)
|
||||
{
|
||||
if(!dynablocks)
|
||||
return;
|
||||
if(!*dynablocks)
|
||||
return;
|
||||
dynarec_log(LOG_INFO, "Free %d Blocks from Dynablocklist (with %d buckets, nolinker=%d) %s\n", (*dynablocks)->blocks?kh_size((*dynablocks)->blocks):0, (*dynablocks)->blocks?kh_n_buckets((*dynablocks)->blocks):0, (*dynablocks)->nolinker, ((*dynablocks)->direct)?" With Direct mapping enabled":"");
|
||||
dynablock_t* db;
|
||||
if((*dynablocks)->blocks) {
|
||||
// create a list of the parent db to delete (because there are sons in the middle that will be invalid if father is removed)
|
||||
dynablock_t** list = (dynablock_t**)calloc(kh_size((*dynablocks)->blocks), sizeof(dynablock_t*));
|
||||
int n = 0;
|
||||
kh_foreach_value((*dynablocks)->blocks, db,
|
||||
if(!db->father) list[n++] = db;
|
||||
);
|
||||
for (int i=0; i<n; ++i)
|
||||
FreeDynablock(list[i]);
|
||||
kh_destroy(dynablocks, (*dynablocks)->blocks);
|
||||
(*dynablocks)->blocks = NULL;
|
||||
free(list);
|
||||
}
|
||||
if((*dynablocks)->direct) {
|
||||
for (int i=0; i<(*dynablocks)->textsz; ++i) {
|
||||
if((*dynablocks)->direct[i] && !(*dynablocks)->direct[i]->father)
|
||||
FreeDynablock((*dynablocks)->direct[i]);
|
||||
}
|
||||
free((*dynablocks)->direct);
|
||||
}
|
||||
(*dynablocks)->direct = 0;
|
||||
|
||||
pthread_rwlock_destroy(&(*dynablocks)->rwlock_blocks);
|
||||
|
||||
free(*dynablocks);
|
||||
*dynablocks = NULL;
|
||||
}
|
||||
|
||||
void MarkDynablock(dynablock_t* db)
|
||||
{
|
||||
if(db) {
|
||||
if(db->father)
|
||||
db = db->father; // mark only father
|
||||
if(db->marks && !db->need_test) {
|
||||
// Follow mark and set arm_linker instead
|
||||
khint_t k;
|
||||
kh_foreach_key(db->marks, k,
|
||||
void** p = (void**)(uintptr_t)k;
|
||||
resettable(p);
|
||||
);
|
||||
// free mark
|
||||
kh_clear(mark, db->marks);
|
||||
}
|
||||
db->need_test = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void ProtectDynablock(dynablock_t* db)
|
||||
{
|
||||
if(db) {
|
||||
if(db->father)
|
||||
return; // protect only father, child(ren) will be automatically
|
||||
protectDB((uintptr_t)db->x86_addr, db->x86_size);
|
||||
}
|
||||
}
|
||||
|
||||
void RemoveMark(void** table)
|
||||
{
|
||||
// remove old value if any
|
||||
dynablock_t *old = (dynablock_t*)table[3];
|
||||
if(old && old->father)
|
||||
old = old->father;
|
||||
if(old && old->marks) {
|
||||
khint_t kd = kh_get(mark, old->marks, (uintptr_t)table);
|
||||
if(kd!=kh_end(old->marks))
|
||||
kh_del(mark, old->marks, kd);
|
||||
}
|
||||
table[3] = NULL;
|
||||
}
|
||||
|
||||
// source is linked to dest (i.e. source->table[x] = dest->block), so add a "mark" in dest, add a "linked" info to source
|
||||
void AddMark(dynablock_t* source, dynablock_t* dest, void** table)
|
||||
{
|
||||
int ret;
|
||||
// remove old value if any
|
||||
dynablock_t *old = (dynablock_t*)table[3];
|
||||
if(old && old->father)
|
||||
old = old->father;
|
||||
if(old && old->marks) {
|
||||
khint_t kd = kh_get(mark, old->marks, (uintptr_t)table);
|
||||
if(kd!=kh_end(old->marks))
|
||||
kh_del(mark, old->marks, kd);
|
||||
}
|
||||
// add mark if needed
|
||||
if(dest->father)
|
||||
dest = dest->father;
|
||||
if(dest->marks) {
|
||||
kh_put(mark, dest->marks, (uintptr_t)table, &ret);
|
||||
table[3] = (void*)dest;
|
||||
} else
|
||||
table[3] = NULL;
|
||||
}
|
||||
|
||||
void MarkDynablockList(dynablocklist_t** dynablocks)
|
||||
{
|
||||
if(!dynablocks)
|
||||
return;
|
||||
if(!*dynablocks)
|
||||
return;
|
||||
dynarec_log(LOG_DEBUG, "Marked %d Blocks from Dynablocklist (with %d buckets, nolinker=%d) %p:0x%x %s\n", (*dynablocks)->blocks?(kh_size((*dynablocks)->blocks)):0, (*dynablocks)->blocks?(kh_n_buckets((*dynablocks)->blocks)):0, (*dynablocks)->nolinker, (void*)(*dynablocks)->text, (*dynablocks)->textsz, ((*dynablocks)->direct)?" With Direct mapping enabled":"");
|
||||
dynablock_t* db;
|
||||
if((*dynablocks)->blocks) {
|
||||
kh_foreach_value((*dynablocks)->blocks, db,
|
||||
MarkDynablock(db);
|
||||
);
|
||||
}
|
||||
if((*dynablocks)->direct) {
|
||||
for (int i=0; i<(*dynablocks)->textsz; ++i) {
|
||||
MarkDynablock((*dynablocks)->direct[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ProtectkDynablockList(dynablocklist_t** dynablocks)
|
||||
{
|
||||
if(!dynablocks)
|
||||
return;
|
||||
if(!*dynablocks)
|
||||
return;
|
||||
dynarec_log(LOG_DEBUG, "Protect %d Blocks from Dynablocklist (with %d buckets, nolinker=%d) %p:0x%x %s\n", (*dynablocks)->blocks?(kh_size((*dynablocks)->blocks)):0, (*dynablocks)->blocks?(kh_n_buckets((*dynablocks)->blocks)):0, (*dynablocks)->nolinker, (void*)(*dynablocks)->text, (*dynablocks)->textsz, ((*dynablocks)->direct)?" With Direct mapping enabled":"");
|
||||
dynablock_t* db;
|
||||
if((*dynablocks)->blocks) {
|
||||
kh_foreach_value((*dynablocks)->blocks, db,
|
||||
ProtectDynablock(db);
|
||||
);
|
||||
}
|
||||
if((*dynablocks)->direct) {
|
||||
for (int i=0; i<(*dynablocks)->textsz; ++i) {
|
||||
ProtectDynablock((*dynablocks)->direct[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
return 0;
|
||||
}
|
||||
void FreeDirectDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
if(!dynablocks)
|
||||
return;
|
||||
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)
|
||||
if(dynablocks->direct[i-startdb]) {
|
||||
FreeDynablock(dynablocks->direct[i-startdb]);
|
||||
}
|
||||
}
|
||||
void MarkDirectDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
if(!dynablocks)
|
||||
return;
|
||||
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)
|
||||
if(dynablocks->direct[i-startdb]) {
|
||||
MarkDynablock(dynablocks->direct[i-startdb]);
|
||||
}
|
||||
}
|
||||
|
||||
void ProtectDirectDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
if(!dynablocks)
|
||||
return;
|
||||
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)
|
||||
protectDB(start, end-start); //no +1; as end/enddb is exclusive and not inclusive
|
||||
}
|
||||
|
||||
void FreeRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
if(!dynablocks)
|
||||
return;
|
||||
if(dynablocks->direct)
|
||||
FreeDirectDynablock(dynablocks, addr, size);
|
||||
if(dynablocks->blocks) {
|
||||
dynablock_t* db;
|
||||
uintptr_t s, e;
|
||||
kh_foreach_value(dynablocks->blocks, db,
|
||||
s = (uintptr_t)db->x86_addr;
|
||||
e = (uintptr_t)db->x86_addr+db->x86_size-1;
|
||||
if((s>=addr && s<(addr+size)) || (e>=addr && e<(addr+size)))
|
||||
ProtectDynablock(db);
|
||||
);
|
||||
}
|
||||
}
|
||||
void MarkRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
if(!dynablocks)
|
||||
return;
|
||||
if(dynablocks->direct)
|
||||
MarkDirectDynablock(dynablocks, addr, size);
|
||||
if(dynablocks->blocks) {
|
||||
dynablock_t* db;
|
||||
uintptr_t s, e;
|
||||
kh_foreach_value(dynablocks->blocks, db,
|
||||
s = (uintptr_t)db->x86_addr;
|
||||
e = (uintptr_t)db->x86_addr+db->x86_size-1;
|
||||
if((s>=addr && s<(addr+size)) || (e>=addr && e<(addr+size)))
|
||||
MarkDynablock(db);
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
dynablock_t* FindDynablockDynablocklist(void* addr, dynablocklist_t* dynablocks)
|
||||
{
|
||||
if(!dynablocks)
|
||||
return NULL;
|
||||
if(dynablocks->direct)
|
||||
for(int i=0; i<dynablocks->textsz; ++i) {
|
||||
if(dynablocks->direct[i]) {
|
||||
dynablock_t* db = dynablocks->direct[i];
|
||||
uintptr_t s = (uintptr_t)db->block;
|
||||
uintptr_t e = (uintptr_t)db->block+db->size;
|
||||
if(s>=(uintptr_t)addr && e<(uintptr_t)addr)
|
||||
return db->father?db->father:db;
|
||||
}
|
||||
}
|
||||
if(dynablocks->blocks) {
|
||||
dynablock_t* db;
|
||||
uintptr_t s, e;
|
||||
kh_foreach_value(dynablocks->blocks, db,
|
||||
s = (uintptr_t)db->block;
|
||||
e = (uintptr_t)db->block+db->size;
|
||||
if((uintptr_t)addr>=s && (uintptr_t)addr<e)
|
||||
return db->father?db->father:db;
|
||||
);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dynablock_t* FindDynablockFromNativeAddress(void* addr)
|
||||
{
|
||||
// unoptimized search through all dynablockslist for the dynablock that contains native addr (NULL if not found)
|
||||
// search "volatile" dynarec first
|
||||
dynablock_t *ret = NULL;
|
||||
for(int idx=0; idx<65536 && !ret; ++idx)
|
||||
if(my_context->dynmap[idx])
|
||||
ret = FindDynablockDynablocklist(addr, my_context->dynmap[idx]->dynablocks);
|
||||
if(ret)
|
||||
return ret;
|
||||
// search elfs
|
||||
for(int idx=0; idx<my_context->elfsize && !ret; ++idx)
|
||||
ret = FindDynablockDynablocklist(addr, GetDynablocksFromElf(my_context->elfs[idx]));
|
||||
// last, search context dynablocks
|
||||
if(my_context->dynablocks)
|
||||
ret = FindDynablockDynablocklist(addr, my_context->dynablocks);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ConvertHash2Direct(dynablocklist_t* dynablocks)
|
||||
{
|
||||
if(dynablocks->textsz==0 || dynablocks->text==0 || !dynablocks->blocks)
|
||||
return; // nothing to do
|
||||
// create the new set
|
||||
dynablock_t **direct = (dynablock_t**)calloc(dynablocks->textsz, sizeof(dynablock_t*));
|
||||
kh_dynablocks_t *blocks = kh_init(dynablocks);
|
||||
// transfert
|
||||
int ret;
|
||||
khint_t k;
|
||||
dynablock_t* db;
|
||||
uintptr_t key;
|
||||
uintptr_t start = dynablocks->text;
|
||||
uintptr_t end = start + dynablocks->textsz;
|
||||
kh_foreach(dynablocks->blocks, key, db,
|
||||
key += dynablocks->base;
|
||||
if(key>=start && key<end)
|
||||
direct[key-start] = db;
|
||||
else {
|
||||
k = kh_put(dynablocks, blocks, key-dynablocks->base, &ret);
|
||||
if(ret) { // don't try to insert if already done...
|
||||
kh_value(blocks, k) = db;
|
||||
}
|
||||
}
|
||||
);
|
||||
// destroy old and do the swap (should swap before destroy, but hash access is always behind mutex)
|
||||
kh_destroy(dynablocks, dynablocks->blocks);
|
||||
dynablocks->blocks = blocks;
|
||||
dynablocks->direct = direct;
|
||||
}
|
||||
|
||||
#define MAGIC_SIZE 256
|
||||
|
||||
dynablock_t *AddNewDynablock(dynablocklist_t* dynablocks, uintptr_t addr, int with_marks, int* created)
|
||||
{
|
||||
if(!dynablocks) {
|
||||
dynarec_log(LOG_INFO, "Warning: Ask to create a dynblock with a NULL dynablocklist (addr=%p)\n", (void*)addr);
|
||||
*created = 0;
|
||||
return NULL;
|
||||
}
|
||||
khint_t k;
|
||||
int ret;
|
||||
dynablock_t* block = NULL;
|
||||
// first, check if it exist in direct access mode
|
||||
if(dynablocks->direct && (addr>=dynablocks->text) && (addr<(dynablocks->text+dynablocks->textsz))) {
|
||||
block = dynablocks->direct[addr-dynablocks->text];
|
||||
if(block) {
|
||||
dynarec_log(LOG_DUMP, "Block already exist in Direct Map\n");
|
||||
*created = 0;
|
||||
return block;
|
||||
}
|
||||
}
|
||||
|
||||
if(dynablocks->blocks) {
|
||||
pthread_rwlock_rdlock(&dynablocks->rwlock_blocks);
|
||||
// check if the block exist
|
||||
khint_t k;
|
||||
k = kh_get(dynablocks, dynablocks->blocks, addr-dynablocks->base);
|
||||
if(k!=kh_end(dynablocks->blocks)) {
|
||||
block = kh_value(dynablocks->blocks, k);
|
||||
pthread_rwlock_unlock(&dynablocks->rwlock_blocks);
|
||||
dynarec_log(LOG_DUMP, "Block already exist in Hash Map\n");
|
||||
*created = 0;
|
||||
return block;
|
||||
}
|
||||
pthread_rwlock_unlock(&dynablocks->rwlock_blocks);
|
||||
}
|
||||
if (!*created)
|
||||
return block;
|
||||
|
||||
// Lock as write now!
|
||||
pthread_rwlock_wrlock(&dynablocks->rwlock_blocks);
|
||||
// create and add new block
|
||||
dynarec_log(LOG_DUMP, "Ask for DynaRec Block creation @%p\n", (void*)addr);
|
||||
if(dynablocks->direct && (addr>=dynablocks->text) && (addr<(dynablocks->text+dynablocks->textsz))) {
|
||||
block = dynablocks->direct[addr-dynablocks->text] = (dynablock_t*)calloc(1, sizeof(dynablock_t));
|
||||
} else {
|
||||
if(dynablocks->nolinker && ((addr<dynablocks->text) || (addr>=(dynablocks->text+dynablocks->textsz)))) {
|
||||
pthread_rwlock_unlock(&dynablocks->rwlock_blocks);
|
||||
//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, with_marks, created);
|
||||
}
|
||||
k = kh_put(dynablocks, dynablocks->blocks, addr-dynablocks->base, &ret);
|
||||
if(!ret) {
|
||||
// Ooops, block is already there? retreive it and bail out
|
||||
dynarec_log(LOG_DUMP, "Block already exist in Hash Map\n");
|
||||
block = kh_value(dynablocks->blocks, k);
|
||||
pthread_rwlock_unlock(&dynablocks->rwlock_blocks);
|
||||
*created = 0;
|
||||
return block;
|
||||
}
|
||||
block = kh_value(dynablocks->blocks, k) = (dynablock_t*)calloc(1, sizeof(dynablock_t));
|
||||
// check if size of hash map == magic size, if yes, convert to direct before unlocking
|
||||
if(!dynablocks->direct && kh_size(dynablocks->blocks)==MAGIC_SIZE)
|
||||
ConvertHash2Direct(dynablocks);
|
||||
}
|
||||
block->parent = dynablocks;
|
||||
// add mark if needed
|
||||
if(with_marks)
|
||||
block->marks = kh_init(mark);
|
||||
|
||||
// create an empty block first, so if other thread want to execute the same block, they can, but using interpretor path
|
||||
pthread_rwlock_unlock(&dynablocks->rwlock_blocks);
|
||||
|
||||
*created = 1;
|
||||
return block;
|
||||
}
|
||||
|
||||
/*
|
||||
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, int create, dynablock_t* current)
|
||||
{
|
||||
// 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(!(addr>=dynablocks->text && addr<(dynablocks->text+dynablocks->textsz)))
|
||||
dynablocks = NULL;
|
||||
else if(dynablocks->direct && (addr>=dynablocks->text) && (addr<(dynablocks->text+dynablocks->textsz))) {
|
||||
block = dynablocks->direct[addr-dynablocks->text];
|
||||
if(block)
|
||||
return block;
|
||||
}
|
||||
}
|
||||
// nope, lets do the long way
|
||||
if(!dynablocks)
|
||||
dynablocks = GetDynablocksFromAddress(emu->context, addr);
|
||||
if(!dynablocks)
|
||||
return NULL;
|
||||
// check direct first, without lock
|
||||
if(dynablocks->direct && (addr>=dynablocks->text) && (addr<(dynablocks->text+dynablocks->textsz)))
|
||||
block = dynablocks->direct[addr-dynablocks->text];
|
||||
if(block)
|
||||
return block;
|
||||
|
||||
int created = create;
|
||||
block = AddNewDynablock(dynablocks, addr, (dynablocks->nolinker)&&(dynablocks->direct), &created);
|
||||
if(!created || !create)
|
||||
return block; // existing block...
|
||||
|
||||
if(box86_dynarec_dump)
|
||||
pthread_mutex_lock(&my_context->mutex_lock);
|
||||
// fill the block
|
||||
block->x86_addr = (void*)addr;
|
||||
FillBlock(block);
|
||||
if(box86_dynarec_dump)
|
||||
pthread_mutex_unlock(&my_context->mutex_lock);
|
||||
|
||||
dynarec_log(LOG_DEBUG, " --- DynaRec Block %s @%p:%p (%p, 0x%x bytes, %swith %d son(s))\n", created?"created":"recycled", (void*)addr, (void*)(addr+block->x86_size), block->block, block->size, block->marks?"with Marks, ":"", block->sons_size);
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
dynablock_t* DBGetBlock(x86emu_t* emu, uintptr_t addr, int create, dynablock_t** current)
|
||||
{
|
||||
dynablock_t *db = internalDBGetBlock(emu, addr, create, *current);
|
||||
if(db && (db->need_test || (db->father && db->father->need_test))) {
|
||||
dynablock_t *father = db->father?db->father:db;
|
||||
uint32_t hash = X31_hash_code(father->x86_addr, father->x86_size);
|
||||
if(hash!=father->hash) {
|
||||
dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X/%X)%s with %d son(s)\n", father, father->x86_addr, father->x86_addr+father->x86_size, hash, father->hash, father->marks?" with Mark,":"", father->sons_size);
|
||||
// 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);
|
||||
// start again... (will create a new block)
|
||||
db = internalDBGetBlock(emu, addr, create, *current);
|
||||
} else {
|
||||
father->need_test = 0;
|
||||
protectDB((uintptr_t)father->x86_addr, father->x86_size);
|
||||
}
|
||||
}
|
||||
return db;
|
||||
}
|
||||
Executable
+36
@@ -0,0 +1,36 @@
|
||||
#ifndef __DYNABLOCK_PRIVATE_H_
|
||||
#define __DYNABLOCK_PRIVATE_H_
|
||||
|
||||
typedef struct dynablocklist_s dynablocklist_t;
|
||||
typedef struct kh_dynablocks_s kh_dynablocks_t;
|
||||
typedef struct kh_mark_s kh_mark_t;
|
||||
|
||||
typedef struct dynablock_s {
|
||||
dynablocklist_t* parent;
|
||||
kh_mark_t* marks; // List of blocks that marked this block
|
||||
void* block;
|
||||
int size;
|
||||
void* x86_addr;
|
||||
int x86_size;
|
||||
uint32_t hash;
|
||||
int need_test;
|
||||
uintptr_t* table;
|
||||
int tablesz;
|
||||
int done;
|
||||
int isize;
|
||||
dynablock_t** sons; // sons (kind-of dummy dynablock...)
|
||||
int sons_size;
|
||||
dynablock_t* father; // set only in the case of a son
|
||||
} dynablock_t;
|
||||
|
||||
typedef struct dynablocklist_s {
|
||||
kh_dynablocks_t *blocks;
|
||||
pthread_rwlock_t rwlock_blocks;
|
||||
uintptr_t base;
|
||||
uintptr_t text;
|
||||
int textsz;
|
||||
int nolinker; // in case this dynablock can disapear (also, block memory are allocated with a temporary scheme)
|
||||
dynablock_t **direct; // direct mapping (waste of space, so not always there)
|
||||
} dynablocklist_t;
|
||||
|
||||
#endif //__DYNABLOCK_PRIVATE_H_
|
||||
Executable
+186
@@ -0,0 +1,186 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x86emu_private.h"
|
||||
#include "tools/bridge_private.h"
|
||||
#include "x86run.h"
|
||||
#include "x86emu.h"
|
||||
#include "box86stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x86run_private.h"
|
||||
#include "x86trace.h"
|
||||
#ifdef DYNAREC
|
||||
#include "dynablock.h"
|
||||
#include "dynablock_private.h"
|
||||
#endif
|
||||
|
||||
#ifdef ARM
|
||||
void arm_prolog(x86emu_t* emu, void* addr) EXPORTDYN;
|
||||
void arm_epilog() EXPORTDYN;
|
||||
void arm_epilog_fast() EXPORTDYN;
|
||||
void arm_linker() EXPORTDYN;
|
||||
int arm_tableupdate(void* jump, uintptr_t addr, void** table) EXPORTDYN;
|
||||
#endif
|
||||
|
||||
void tableupdate(void* jumpto, uintptr_t ref, void** table)
|
||||
{
|
||||
#ifdef ARM
|
||||
if(arm_tableupdate(jumpto, ref, table))
|
||||
#endif
|
||||
{
|
||||
table[0] = jumpto;
|
||||
table[1] = (void*)ref;
|
||||
}
|
||||
}
|
||||
|
||||
void resettable(void** table)
|
||||
{
|
||||
void* p = table[1];
|
||||
#ifdef ARM
|
||||
tableupdate(arm_linker, (uintptr_t)p, table);
|
||||
#endif
|
||||
//table[2] = own_dynablock // unchanged
|
||||
table[3] = NULL; // removed "linked" information
|
||||
}
|
||||
|
||||
#ifdef DYNAREC
|
||||
void* UpdateLinkTable(x86emu_t* emu, void** table, uintptr_t addr)
|
||||
{
|
||||
dynablock_t* current = (dynablock_t*)table[2];
|
||||
if(current->father)
|
||||
current = current->father;
|
||||
dynablock_t* block = DBGetBlock(emu, addr, 1, ¤t);
|
||||
if(!current) { // current has been invalidated, stop running it...
|
||||
//dynarec_log(LOG_DEBUG, "--- Current invalidated while linking.\n");
|
||||
return arm_epilog_fast;
|
||||
}
|
||||
if(table[3]) {
|
||||
//dynarec_log(LOG_DEBUG, "--- Remove mark from %p (%p)\n", current, table[3]);
|
||||
RemoveMark(table);
|
||||
}
|
||||
if(!block) {
|
||||
// no block, don't try again, ever
|
||||
tableupdate(arm_epilog, addr, table);
|
||||
return arm_epilog_fast;
|
||||
}
|
||||
if(!block->done) {
|
||||
// not finished yet... leave linker
|
||||
//tableupdate(arm_linker, addr, table);
|
||||
return arm_epilog_fast;
|
||||
}
|
||||
if(!block->block) {
|
||||
// null block, but done: go to epilog, no linker here
|
||||
tableupdate(arm_epilog, addr, table);
|
||||
return arm_epilog_fast;
|
||||
}
|
||||
dynablock_t *father = block->father?block->father:block;
|
||||
if(!block->parent->nolinker || (current && father->marks)) {
|
||||
//dynarec_log(LOG_DEBUG, "--- Linking %p/%p to %p (table=%p[%p/%p/%p/%p])\n", block, block->block, current, table, table[0], table[1], table[2], table[3]);
|
||||
// only update block if linker is allowed or if marks is possibe
|
||||
if(current && father->marks && current!=father)
|
||||
AddMark(current, father, table);
|
||||
tableupdate(block->block, addr, table);
|
||||
}
|
||||
return block->block;
|
||||
}
|
||||
#endif
|
||||
|
||||
void DynaCall(x86emu_t* emu, uintptr_t addr)
|
||||
{
|
||||
#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 && !block->parent->nolinker)?block:NULL;
|
||||
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, "Calling Interpretor @%p, emu=%p\n", (void*)R_EIP, emu);
|
||||
Run(emu, 1);
|
||||
} else {
|
||||
dynarec_log(LOG_DEBUG, "Calling DynaRec Block @%p (%p) of %d x86 instructions (nolinker=%d, father=%p) emu=%p\n", (void*)R_EIP, block->block, block->isize ,block->parent->nolinker, 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);
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
int DynaRun(x86emu_t* emu)
|
||||
{
|
||||
#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 && !block->parent->nolinker)?block:NULL;
|
||||
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, "Running Interpretor @%p, emu=%p\n", (void*)R_EIP, emu);
|
||||
Run(emu, 1);
|
||||
} else {
|
||||
dynarec_log(LOG_DEBUG, "Running DynaRec Block @%p (%p) of %d x86 insts (nolinker=%d, father=%p) emu=%p\n", (void*)R_EIP, block->block, block->isize, block->parent->nolinker, block->father, 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
Executable
+281
@@ -0,0 +1,281 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x86emu_private.h"
|
||||
#include "tools/bridge_private.h"
|
||||
#include "x86run.h"
|
||||
#include "x86emu.h"
|
||||
#include "box86stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x86run_private.h"
|
||||
#include "x86trace.h"
|
||||
#include "dynablock.h"
|
||||
#include "dynablock_private.h"
|
||||
#include "dynarec_arm.h"
|
||||
#include "dynarec_arm_private.h"
|
||||
#include "elfloader.h"
|
||||
|
||||
void printf_x86_instruction(zydis_dec_t* dec, instruction_x86_t* inst, const char* name) {
|
||||
uint8_t *ip = (uint8_t*)inst->addr;
|
||||
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":"");
|
||||
} 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":"");
|
||||
}
|
||||
} else {
|
||||
if(dec) {
|
||||
dynarec_log(LOG_NONE, "%s%p: %s", (box86_dynarec_dump>1)?"\e[1m":"", ip, DecodeX86Trace(dec, inst->addr));
|
||||
} else {
|
||||
dynarec_log(LOG_NONE, "%s%p: ", (box86_dynarec_dump>1)?"\e[1m":"", ip);
|
||||
for(int i=0; i<inst->size; ++i) {
|
||||
dynarec_log(LOG_NONE, "%02X ", ip[i]);
|
||||
}
|
||||
dynarec_log(LOG_NONE, " %s", name);
|
||||
}
|
||||
// print Call function name if possible
|
||||
if(ip[0]==0xE8 || ip[0]==0xE9) { // Call / Jmp
|
||||
uintptr_t nextaddr = (uintptr_t)ip + 5 + *((int32_t*)(ip+1));
|
||||
printFunctionAddr(nextaddr, "=> ");
|
||||
} else if(ip[0]==0xFF) {
|
||||
if(ip[1]==0x25) {
|
||||
uintptr_t nextaddr = (uintptr_t)ip + 6 + *((int32_t*)(ip+2));
|
||||
printFunctionAddr(nextaddr, "=> ");
|
||||
}
|
||||
}
|
||||
// end of line and colors
|
||||
dynarec_log(LOG_NONE, "%s\n", (box86_dynarec_dump>1)?"\e[m":"");
|
||||
}
|
||||
}
|
||||
|
||||
void add_next(dynarec_arm_t *dyn, uintptr_t addr) {
|
||||
if(dyn->next_sz == dyn->next_cap) {
|
||||
dyn->next_cap += 16;
|
||||
dyn->next = (uintptr_t*)realloc(dyn->next, dyn->next_cap*sizeof(uintptr_t));
|
||||
}
|
||||
for(int i=0; i<dyn->next_sz; ++i)
|
||||
if(dyn->next[i]==addr)
|
||||
return;
|
||||
dyn->next[dyn->next_sz++] = addr;
|
||||
}
|
||||
uintptr_t get_closest_next(dynarec_arm_t *dyn, uintptr_t addr) {
|
||||
// get closest, but no addresses befores
|
||||
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;
|
||||
}
|
||||
}
|
||||
return best;
|
||||
}
|
||||
int is_nops(dynarec_arm_t *dyn, uintptr_t addr, int n)
|
||||
{
|
||||
#define PK(A) (*((uint8_t*)(addr+(A))))
|
||||
if(!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
|
||||
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);
|
||||
if(n>2 && PK(0)==0x8d && PK(1)==0x76 && PK(2)==0x00) // lea esi, [esi]
|
||||
return is_nops(dyn, addr+3, n-3);
|
||||
if(n>3 && PK(0)==0x0f && PK(1)==0x1f && PK(2)==0x40 && PK(3)==0x00)
|
||||
return is_nops(dyn, addr+4, n-4);
|
||||
if(n>3 && PK(0)==0x8d && PK(1)==0x74 && PK(2)==0x26 && PK(3)==0x00)
|
||||
return is_nops(dyn, addr+4, n-4);
|
||||
if(n>4 && PK(0)==0x0f && PK(1)==0x1f && PK(2)==0x44 && PK(3)==0x00 && PK(4)==0x00)
|
||||
return is_nops(dyn, addr+5, n-5);
|
||||
if(n>5 && PK(0)==0x8d && PK(1)==0xb6 && PK(2)==0x00 && PK(3)==0x00 && PK(4)==0x00 && PK(5)==0x00)
|
||||
return is_nops(dyn, addr+6, n-6);
|
||||
if(n>6 && PK(0)==0x0f && PK(1)==0x1f && PK(2)==0x80 && PK(3)==0x00 && PK(4)==0x00 && PK(5)==0x00 && PK(6)==0x00)
|
||||
return is_nops(dyn, addr+7, n-7);
|
||||
if(n>6 && PK(0)==0x8d && PK(1)==0xb4 && PK(2)==0x26 && PK(3)==0x00 && PK(4)==0x00 && PK(5)==0x00 && PK(6)==0x00) // lea esi, [esi+0]
|
||||
return is_nops(dyn, addr+7, n-7);
|
||||
if(n>7 && PK(0)==0x0f && PK(1)==0x1f && PK(2)==0x84 && PK(3)==0x00 && PK(4)==0x00 && PK(5)==0x00 && PK(6)==0x00 && PK(7)==0x00)
|
||||
return is_nops(dyn, addr+8, n-8);
|
||||
return 0;
|
||||
#undef PK
|
||||
}
|
||||
|
||||
uint32_t needed_flags(dynarec_arm_t *dyn, int ninst, uint32_t setf, int recurse)
|
||||
{
|
||||
if(ninst == dyn->size || (recurse==5))
|
||||
return X_ALL; // no more instructions, or too many jmp loop, stop
|
||||
uint32_t needed = dyn->insts[ninst].x86.use_flags;
|
||||
if(needed) {
|
||||
setf &= ~needed;
|
||||
if(!setf) // all flags already used, no need to continue
|
||||
return needed;
|
||||
}
|
||||
|
||||
if(!needed && !dyn->insts[ninst].x86.set_flags && !dyn->insts[ninst].x86.jmp_insts) {
|
||||
int start = ninst;
|
||||
int end = ninst;
|
||||
while(end<dyn->size && !dyn->insts[end].x86.use_flags && !dyn->insts[end].x86.set_flags && !dyn->insts[end].x86.jmp_insts)
|
||||
++end;
|
||||
needed = needed_flags(dyn, end, setf, recurse);
|
||||
for(int i=start; i<end; ++i)
|
||||
dyn->insts[i].x86.need_flags = needed;
|
||||
return needed;
|
||||
}
|
||||
|
||||
if(dyn->insts[ninst].x86.set_flags && (dyn->insts[ninst].x86.state_flags!=SF_MAYSET)) {
|
||||
if((setf & ~dyn->insts[ninst].x86.set_flags) == 0)
|
||||
return needed; // all done, gives all the flags needed
|
||||
setf |= dyn->insts[ninst].x86.set_flags; // add new flags to continue
|
||||
}
|
||||
|
||||
int jinst = dyn->insts[ninst].x86.jmp_insts;
|
||||
if(dyn->insts[ninst].x86.jmp) {
|
||||
dyn->insts[ninst].x86.need_flags = (jinst==-1)?X_PEND:needed_flags(dyn, jinst, setf, recurse+1);
|
||||
if(dyn->insts[ninst].x86.use_flags) // conditionnal jump
|
||||
dyn->insts[ninst].x86.need_flags |= needed_flags(dyn, ninst+1, setf, recurse);
|
||||
} else
|
||||
dyn->insts[ninst].x86.need_flags = needed_flags(dyn, ninst+1, setf, recurse);
|
||||
if(dyn->insts[ninst].x86.state_flags==SF_MAYSET)
|
||||
needed |= dyn->insts[ninst].x86.need_flags;
|
||||
else
|
||||
needed |= (dyn->insts[ninst].x86.need_flags & ~dyn->insts[ninst].x86.set_flags);
|
||||
if(needed == (X_PEND|X_ALL))
|
||||
needed = X_ALL;
|
||||
return needed;
|
||||
}
|
||||
|
||||
void arm_pass0(dynarec_arm_t* dyn, uintptr_t addr);
|
||||
void arm_pass1(dynarec_arm_t* dyn, uintptr_t addr);
|
||||
void arm_pass2(dynarec_arm_t* dyn, uintptr_t addr);
|
||||
void arm_pass3(dynarec_arm_t* dyn, uintptr_t addr);
|
||||
|
||||
void* FillBlock(dynablock_t* block) {
|
||||
// init the helper
|
||||
uintptr_t addr = (uintptr_t)block->x86_addr;
|
||||
dynarec_arm_t helper = {0};
|
||||
helper.nolinker = box86_dynarec_linker?(block->parent->nolinker):1;
|
||||
helper.start = addr;
|
||||
arm_pass0(&helper, addr);
|
||||
if(!helper.size) {
|
||||
dynarec_log(LOG_DEBUG, "Warning, null-sized dynarec block (%p)\n", (void*)addr);
|
||||
block->done = 1;
|
||||
free(helper.next);
|
||||
return (void*)block;
|
||||
}
|
||||
helper.cap = helper.size+3; // needs epilog handling
|
||||
helper.insts = (instruction_arm_t*)calloc(helper.cap, sizeof(instruction_arm_t));
|
||||
// pass 1, addresses, x86 jump addresses, flags
|
||||
arm_pass1(&helper, addr);
|
||||
// calculate barriers
|
||||
uintptr_t start = helper.insts[0].x86.addr;
|
||||
uintptr_t end = helper.insts[helper.size].x86.addr+helper.insts[helper.size].x86.size;
|
||||
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;
|
||||
}
|
||||
if(k!=-1) // -1 if not found, mmm, probably wrong, exit anyway
|
||||
helper.insts[k].x86.barrier = 1;
|
||||
helper.insts[i].x86.jmp_insts = k;
|
||||
}
|
||||
}
|
||||
for(int i=0; i<helper.size; ++i)
|
||||
if(helper.insts[i].x86.set_flags && !helper.insts[i].x86.need_flags) {
|
||||
helper.insts[i].x86.need_flags = needed_flags(&helper, i+1, helper.insts[i].x86.set_flags, 0);
|
||||
if((helper.insts[i].x86.need_flags&X_PEND) && (helper.insts[i].x86.state_flags==SF_MAYSET))
|
||||
helper.insts[i].x86.need_flags = X_ALL;
|
||||
}
|
||||
|
||||
// pass 2, instruction size
|
||||
arm_pass2(&helper, addr);
|
||||
// ok, now allocate mapped memory, with executable flag on
|
||||
int sz = helper.arm_size;
|
||||
void* p = (void*)AllocDynarecMap(sz, block->parent->nolinker);
|
||||
if(p==NULL) {
|
||||
free(helper.insts);
|
||||
free(helper.next);
|
||||
return (void*)block;
|
||||
}
|
||||
helper.block = p;
|
||||
helper.arm_start = (uintptr_t)p;
|
||||
helper.tablesz = helper.tablei;
|
||||
if(helper.tablesz)
|
||||
helper.table = (uintptr_t*)calloc(helper.tablesz, sizeof(uintptr_t));
|
||||
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)
|
||||
if(box86_dynarec_dump) {
|
||||
dynarec_log(LOG_NONE, "%sEmitting %d bytes for %d x86 bytes", (box86_dynarec_dump>1)?"\e[01;36m":"", helper.arm_size, helper.isize);
|
||||
printFunctionAddr(helper.start, " => ");
|
||||
dynarec_log(LOG_NONE, "%s\n", (box86_dynarec_dump>1)?"\e[m":"");
|
||||
}
|
||||
helper.arm_size = 0;
|
||||
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);}
|
||||
// all done...
|
||||
__builtin___clear_cache(p, p+sz); // need to clear the cache before execution...
|
||||
free(helper.insts);
|
||||
free(helper.next);
|
||||
block->table = helper.table;
|
||||
block->tablesz = helper.tablesz;
|
||||
for (int i=0; i<helper.tablesz/4; ++i)
|
||||
block->table[i*4+2] = (uintptr_t)block;
|
||||
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 = (helper.nolinker)?X31_hash_code(block->x86_addr, block->x86_size):0;
|
||||
// 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], 0, &created);
|
||||
if(created) { // avoid breaking a working block! also, block could be outside this parent...
|
||||
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(sons_size) {
|
||||
block->sons = sons;
|
||||
block->sons_size = sons_size;
|
||||
} else
|
||||
free(sons);
|
||||
}
|
||||
if(block->parent->nolinker)
|
||||
protectDB((uintptr_t)block->x86_addr, block->x86_size);
|
||||
block->done = 1;
|
||||
return (void*)block;
|
||||
}
|
||||
Executable
+2638
File diff suppressed because it is too large.
Load diff
Executable
+2253
File diff suppressed because it is too large.
Load diff
Executable
+155
@@ -0,0 +1,155 @@
|
||||
#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_helper.h"
|
||||
|
||||
uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
|
||||
{
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop;
|
||||
int32_t i32;
|
||||
uint32_t u32;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback;
|
||||
int fixedaddress;
|
||||
switch(opcode) {
|
||||
case 0x33:
|
||||
INST_NAME("XOR Gd, FS:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
grab_fsdata(dyn, addr, ninst, x12);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO(x12);
|
||||
emit_xor32(dyn, ninst, gd, ed, x3, x12);
|
||||
break;
|
||||
|
||||
case 0x3B:
|
||||
INST_NAME("CMP Gd, FS:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
grab_fsdata(dyn, addr, ninst, x12);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO(x12);
|
||||
emit_cmp32(dyn, ninst, gd, ed, x3, x12);
|
||||
break;
|
||||
|
||||
case 0x89:
|
||||
INST_NAME("MOV FS:Ed, Gd");
|
||||
grab_fsdata(dyn, addr, ninst, x12);
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) { // reg <= reg
|
||||
MOV_REG(xEAX+(nextop&7), gd);
|
||||
} else { // mem <= reg
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
|
||||
STR_REG_LSL_IMM5(gd, ed, x12, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x8B:
|
||||
INST_NAME("MOV Gd, FS:Ed");
|
||||
grab_fsdata(dyn, addr, ninst, x12);
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) { // reg <= reg
|
||||
MOV_REG(gd, xEAX+(nextop&7));
|
||||
} else { // mem <= reg
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
|
||||
LDR_REG_LSL_IMM5(gd, ed, x12, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x8F:
|
||||
INST_NAME("POP FS:Ed");
|
||||
grab_fsdata(dyn, addr, ninst, x12);
|
||||
nextop = F8;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
POP(xESP, (1<<(xEAX+(nextop&7))));
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
|
||||
POP(xESP, (1<<x2));
|
||||
STR_REG_LSL_IMM5(x2, ed, x12, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xA1:
|
||||
INST_NAME("MOV EAX, FS:Id");
|
||||
grab_fsdata(dyn, addr, ninst, x1);
|
||||
i32 = F32S;
|
||||
if(i32>-4096 && i32<4096) {
|
||||
LDR_IMM9(xEAX, x1, i32);
|
||||
} else {
|
||||
MOV32(x2, i32);
|
||||
ADD_REG_LSL_IMM5(x1, x1, x2, 0);
|
||||
LDR_IMM9(xEAX, x1, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xA3:
|
||||
INST_NAME("MOV FS:Od, EAX");
|
||||
grab_fsdata(dyn, addr, ninst, x1);
|
||||
u32 = F32;
|
||||
MOV32(x2, u32);
|
||||
ADD_REG_LSL_IMM5(x2, x1, x2, 0);
|
||||
STR_IMM9(xEAX, x2, 0);
|
||||
break;
|
||||
|
||||
case 0xC7:
|
||||
INST_NAME("MOV FS:Ed, Id");
|
||||
grab_fsdata(dyn, addr, ninst, x12);
|
||||
nextop=F8;
|
||||
if((nextop&0xC0)==0xC0) { // 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);
|
||||
i32 = F32S;
|
||||
MOV32(x3, i32);
|
||||
STR_REG_LSL_IMM5(x3, ed, x12, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xFF:
|
||||
nextop = F8;
|
||||
grab_fsdata(dyn, addr, ninst, x12);
|
||||
switch((nextop>>3)&7) {
|
||||
case 6: // Push Ed
|
||||
INST_NAME("PUSH Ed");
|
||||
if((nextop&0xC0)==0xC0) { // reg
|
||||
DEFAULT;
|
||||
} else { // mem <= i32
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
|
||||
LDR_REG_LSL_IMM5(x3, ed, x12, 0);
|
||||
PUSH(xESP, 1<<x3);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
Executable
+133
@@ -0,0 +1,133 @@
|
||||
#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_helper.h"
|
||||
|
||||
uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
|
||||
{
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop;
|
||||
int32_t i32;
|
||||
uint32_t u32;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback;
|
||||
int fixedaddress;
|
||||
switch(opcode) {
|
||||
case 0x03:
|
||||
INST_NAME("ADD Gd, GS:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
grab_tlsdata(dyn, addr, ninst, x12);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO(x12);
|
||||
emit_add32(dyn, ninst, gd, ed, x3, x12);
|
||||
break;
|
||||
|
||||
case 0x2B:
|
||||
INST_NAME("SUB Gd, GS:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
grab_tlsdata(dyn, addr, ninst, x12);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO(x12);
|
||||
emit_sub32(dyn, ninst, gd, ed, x3, x12);
|
||||
break;
|
||||
|
||||
case 0x33:
|
||||
INST_NAME("XOR Gd, GS:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
grab_tlsdata(dyn, addr, ninst, x12);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO(x12);
|
||||
emit_xor32(dyn, ninst, gd, ed, x3, x12);
|
||||
break;
|
||||
|
||||
case 0x89:
|
||||
INST_NAME("MOV GS:Ed, Gd");
|
||||
grab_tlsdata(dyn, addr, ninst, x12);
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) { // reg <= reg
|
||||
MOV_REG(xEAX+(nextop&7), gd);
|
||||
} else { // mem <= reg
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
|
||||
STR_REG_LSL_IMM5(gd, ed, x12, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x8B:
|
||||
INST_NAME("MOV Gd, GS:Ed");
|
||||
grab_tlsdata(dyn, addr, ninst, x12);
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) { // reg <= reg
|
||||
MOV_REG(gd, xEAX+(nextop&7));
|
||||
} else { // mem <= reg
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
|
||||
LDR_REG_LSL_IMM5(gd, ed, x12, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xA1:
|
||||
INST_NAME("MOV EAX, GS:Id");
|
||||
grab_tlsdata(dyn, addr, ninst, x1);
|
||||
i32 = F32S;
|
||||
if(i32>-4096 && i32<4096) {
|
||||
LDR_IMM9(xEAX, x1, i32);
|
||||
} else {
|
||||
MOV32(x2, i32);
|
||||
ADD_REG_LSL_IMM5(x1, x1, x2, 0);
|
||||
LDR_IMM9(xEAX, x1, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xA3:
|
||||
INST_NAME("MOV GS:Od, EAX");
|
||||
grab_tlsdata(dyn, addr, ninst, x1);
|
||||
u32 = F32;
|
||||
MOV32(x2, u32);
|
||||
ADD_REG_LSL_IMM5(x2, x1, x2, 0);
|
||||
STR_IMM9(xEAX, x2, 0);
|
||||
break;
|
||||
|
||||
case 0xC7:
|
||||
INST_NAME("MOV GS:Ed, Id");
|
||||
grab_tlsdata(dyn, addr, ninst, x12);
|
||||
nextop=F8;
|
||||
if((nextop&0xC0)==0xC0) { // 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);
|
||||
i32 = F32S;
|
||||
MOV32(x3, i32);
|
||||
STR_REG_LSL_IMM5(x3, ed, x12, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
Executable
+1004
File diff suppressed because it is too large.
Load diff
Executable
+1603
File diff suppressed because it is too large.
Load diff
Executable
+96
@@ -0,0 +1,96 @@
|
||||
#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_helper.h"
|
||||
|
||||
|
||||
uintptr_t dynarec67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
|
||||
{
|
||||
uint8_t nextop;
|
||||
int8_t i8;
|
||||
int32_t i32;
|
||||
MAYUSE(i32);
|
||||
nextop = F8;
|
||||
switch(nextop) {
|
||||
|
||||
|
||||
#define GO(NO, YES) \
|
||||
BARRIER(2); \
|
||||
JUMP(addr+i8);\
|
||||
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_linker(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); \
|
||||
} \
|
||||
}
|
||||
case 0xE0:
|
||||
INST_NAME("LOOPNZ (16bits)");
|
||||
READFLAGS(X_ZF);
|
||||
i8 = F8S;
|
||||
UXTH(x1, xECX, 0);
|
||||
SUBS_IMM8(x1, x1, 1);
|
||||
BFI(xECX, x1, 0, 16);
|
||||
B_NEXT(cEQ); // CX is 0, no LOOP
|
||||
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
TSTS_REG_LSL_IMM5(x1, x1, 0);
|
||||
GO(cNE, cEQ);
|
||||
break;
|
||||
case 0xE1:
|
||||
INST_NAME("LOOPZ (16bits)");
|
||||
READFLAGS(X_ZF);
|
||||
i8 = F8S;
|
||||
UXTH(x1, xECX, 0);
|
||||
SUBS_IMM8(x1, x1, 1);
|
||||
BFI(xECX, x1, 0, 16);
|
||||
B_NEXT(cEQ); // CX is 0, no LOOP
|
||||
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
TSTS_REG_LSL_IMM5(x1, x1, 0);
|
||||
GO(cEQ, cNE);
|
||||
break;
|
||||
case 0xE2:
|
||||
INST_NAME("LOOP (16bits)");
|
||||
i8 = F8S;
|
||||
UXTH(x1, xECX, 0);
|
||||
SUBS_IMM8(x1, x1, 1);
|
||||
BFI(xECX, x1, 0, 16);
|
||||
GO(cEQ, cNE);
|
||||
break;
|
||||
case 0xE3:
|
||||
INST_NAME("JCXZ");
|
||||
i8 = F8S;
|
||||
UXTH(x1, xECX, 0);
|
||||
TSTS_REG_LSL_IMM5(x1, x1, 0);
|
||||
GO(cNE, cEQ);
|
||||
break;
|
||||
#undef GO
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
Executable
+291
@@ -0,0 +1,291 @@
|
||||
#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 dynarecD8(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;
|
||||
int v1, v2;
|
||||
int s0;
|
||||
int d1;
|
||||
int fixedaddress;
|
||||
int parity;
|
||||
|
||||
MAYUSE(d1);
|
||||
MAYUSE(s0);
|
||||
MAYUSE(v1);
|
||||
MAYUSE(v2);
|
||||
MAYUSE(ed);
|
||||
|
||||
switch(nextop) {
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
case 0xC2:
|
||||
case 0xC3:
|
||||
case 0xC4:
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
INST_NAME("FADD ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VADD_F64(v1, v1, v2);
|
||||
break;
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
case 0xCA:
|
||||
case 0xCB:
|
||||
case 0xCC:
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF:
|
||||
INST_NAME("FMUL ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VMUL_F64(v1, v1, v2);
|
||||
break;
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
case 0xD2:
|
||||
case 0xD3:
|
||||
case 0xD4:
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
INST_NAME("FCOM ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VCMP_F64(v1, v2);
|
||||
FCOM(x1, x2);
|
||||
break;
|
||||
case 0xD8:
|
||||
case 0xD9:
|
||||
case 0xDA:
|
||||
case 0xDB:
|
||||
case 0xDC:
|
||||
case 0xDD:
|
||||
case 0xDE:
|
||||
case 0xDF:
|
||||
INST_NAME("FCOMP ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VCMP_F64(v1, v2);
|
||||
FCOM(x1, x2);
|
||||
x87_do_pop(dyn, ninst);
|
||||
break;
|
||||
case 0xE0:
|
||||
case 0xE1:
|
||||
case 0xE2:
|
||||
case 0xE3:
|
||||
case 0xE4:
|
||||
case 0xE5:
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
INST_NAME("FSUB ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VSUB_F64(v1, v1, v2);
|
||||
break;
|
||||
case 0xE8:
|
||||
case 0xE9:
|
||||
case 0xEA:
|
||||
case 0xEB:
|
||||
case 0xEC:
|
||||
case 0xED:
|
||||
case 0xEE:
|
||||
case 0xEF:
|
||||
INST_NAME("FSUBR ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VSUB_F64(v1, v2, v1);
|
||||
break;
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
case 0xF2:
|
||||
case 0xF3:
|
||||
case 0xF4:
|
||||
case 0xF5:
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
INST_NAME("FDIV ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VDIV_F64(v1, v1, v2);
|
||||
break;
|
||||
case 0xF8:
|
||||
case 0xF9:
|
||||
case 0xFA:
|
||||
case 0xFB:
|
||||
case 0xFC:
|
||||
case 0xFD:
|
||||
case 0xFE:
|
||||
case 0xFF:
|
||||
INST_NAME("FDIVR ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VDIV_F64(v1, v2, v1);
|
||||
break;
|
||||
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FADD ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
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);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
GETED;
|
||||
VMOVtoV(s0, ed);
|
||||
}
|
||||
VCVT_F64_F32(d1, s0);
|
||||
VADD_F64(v1, v1, d1);
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FMUL ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
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);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
GETED;
|
||||
VMOVtoV(s0, ed);
|
||||
}
|
||||
VCVT_F64_F32(d1, s0);
|
||||
VMUL_F64(v1, v1, d1);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FCOM ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
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);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
GETED;
|
||||
VMOVtoV(s0, ed);
|
||||
}
|
||||
VCVT_F64_F32(d1, s0);
|
||||
VCMP_F64(v1, d1);
|
||||
FCOM(x1, x2);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FCOMP ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
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);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
GETED;
|
||||
VMOVtoV(s0, ed);
|
||||
}
|
||||
VCVT_F64_F32(d1, s0);
|
||||
VCMP_F64(v1, d1);
|
||||
FCOM(x1, x2);
|
||||
x87_do_pop(dyn, ninst);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FSUB ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
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);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
GETED;
|
||||
VMOVtoV(s0, ed);
|
||||
}
|
||||
VCVT_F64_F32(d1, s0);
|
||||
VSUB_F64(v1, v1, d1);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FSUBR ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
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);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
GETED;
|
||||
VMOVtoV(s0, ed);
|
||||
}
|
||||
VCVT_F64_F32(d1, s0);
|
||||
VSUB_F64(v1, d1, v1);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FDIV ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
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);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
GETED;
|
||||
VMOVtoV(s0, ed);
|
||||
}
|
||||
VCVT_F64_F32(d1, s0);
|
||||
VDIV_F64(v1, v1, d1);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FDIVR ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
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);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
GETED;
|
||||
VMOVtoV(s0, ed);
|
||||
}
|
||||
VCVT_F64_F32(d1, s0);
|
||||
VDIV_F64(v1, d1, v1);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
Executable
+348
@@ -0,0 +1,348 @@
|
||||
#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 "emu/x87emu_private.h"
|
||||
|
||||
#include "dynarec_arm_functions.h"
|
||||
#include "dynarec_arm_helper.h"
|
||||
|
||||
static double d_1 = 1.0;
|
||||
static double d_l2t = L2T;
|
||||
static double d_l2e = L2E;
|
||||
static double d_pi = PI;
|
||||
static double d_lg2 = LG2;
|
||||
static double d_ln2 = LN2;
|
||||
static double d_0 = 0.0;
|
||||
|
||||
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;
|
||||
int fixedaddress;
|
||||
int v1, v2;
|
||||
int s0;
|
||||
int i1, i2, i3;
|
||||
int parity;
|
||||
|
||||
MAYUSE(s0);
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
|
||||
switch(nextop) {
|
||||
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
case 0xC2:
|
||||
case 0xC3:
|
||||
case 0xC4:
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
INST_NAME("FLD STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
v2 = x87_do_push(dyn, ninst);
|
||||
VMOV_64(v2, v1);
|
||||
break;
|
||||
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
case 0xCA:
|
||||
case 0xCB:
|
||||
case 0xCC:
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF:
|
||||
INST_NAME("FXCH STx");
|
||||
// swap the cache value, not the double value itself :p
|
||||
i1 = x87_get_cache(dyn, ninst, x1, x2, nextop&7);
|
||||
i2 = x87_get_cache(dyn, ninst, x1, x2, 0);
|
||||
i3 = dyn->x87cache[i1];
|
||||
dyn->x87cache[i1] = dyn->x87cache[i2];
|
||||
dyn->x87cache[i2] = i3;
|
||||
break;
|
||||
|
||||
case 0xD0:
|
||||
INST_NAME("FNOP");
|
||||
break;
|
||||
|
||||
case 0xE0:
|
||||
INST_NAME("FCHS");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
VNEG_F64(v1, v1);
|
||||
break;
|
||||
case 0xE1:
|
||||
INST_NAME("FABS");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
VABS_F64(v1, v1);
|
||||
break;
|
||||
|
||||
case 0xE4:
|
||||
INST_NAME("FTST");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
VCMP_F64_0(v1);
|
||||
FCOM(x1, x2); // same flags...
|
||||
break;
|
||||
case 0xE5:
|
||||
INST_NAME("FXAM");
|
||||
x87_refresh(dyn, ninst, x1, x2, 0);
|
||||
CALL(fpu_fxam, -1, 0); // should be possible inline, but is it worth it?
|
||||
break;
|
||||
|
||||
case 0xE8:
|
||||
INST_NAME("FLD1");
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
MOV32(x2, (&d_1));
|
||||
VLDR_64(v1, x2, 0);
|
||||
break;
|
||||
case 0xE9:
|
||||
INST_NAME("FLDL2T");
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
MOV32(x2, (&d_l2t));
|
||||
VLDR_64(v1, x2, 0);
|
||||
break;
|
||||
case 0xEA:
|
||||
INST_NAME("FLDL2E");
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
MOV32(x2, (&d_l2e));
|
||||
VLDR_64(v1, x2, 0);
|
||||
break;
|
||||
case 0xEB:
|
||||
INST_NAME("FLDPI");
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
MOV32(x2, (&d_pi));
|
||||
VLDR_64(v1, x2, 0);
|
||||
break;
|
||||
case 0xEC:
|
||||
INST_NAME("FLDLG2");
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
MOV32(x2, (&d_lg2));
|
||||
VLDR_64(v1, x2, 0);
|
||||
break;
|
||||
case 0xED:
|
||||
INST_NAME("FLDLN2");
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
MOV32(x2, (&d_ln2));
|
||||
VLDR_64(v1, x2, 0);
|
||||
break;
|
||||
case 0xEE:
|
||||
INST_NAME("FLDZ");
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
MOV32(x2, (&d_0));
|
||||
VLDR_64(v1, x2, 0);
|
||||
break;
|
||||
|
||||
case 0xFA:
|
||||
INST_NAME("FSQRT");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
VSQRT_F64(v1, v1);
|
||||
break;
|
||||
|
||||
case 0xFC:
|
||||
INST_NAME("FRNDINT");
|
||||
// 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");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
CALL(arm_f2xm1, -1, 0);
|
||||
break;
|
||||
case 0xF1:
|
||||
INST_NAME("FYL2X");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fyl2x, -1, 0);
|
||||
x87_do_pop(dyn, ninst);
|
||||
break;
|
||||
case 0xF2:
|
||||
INST_NAME("FTAN");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
CALL(arm_ftan, -1, 0);
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
MOV32(x2, (&d_1));
|
||||
VLDR_64(v1, x2, 0);
|
||||
break;
|
||||
case 0xF3:
|
||||
INST_NAME("FPATAN");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fpatan, -1, 0);
|
||||
x87_do_pop(dyn, ninst);
|
||||
break;
|
||||
case 0xF4:
|
||||
INST_NAME("FXTRACT");
|
||||
x87_do_push_empty(dyn, ninst, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fxtract, -1, 0);
|
||||
break;
|
||||
case 0xF8:
|
||||
INST_NAME("FPREM");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fprem, -1, 0);
|
||||
break;
|
||||
case 0xF9:
|
||||
INST_NAME("FYL2XP1");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fyl2xp1, -1, 0);
|
||||
x87_do_pop(dyn, ninst);
|
||||
break;
|
||||
case 0xFB:
|
||||
INST_NAME("FSINCOS");
|
||||
x87_do_push_empty(dyn, ninst, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fsincos, -1, 0);
|
||||
break;
|
||||
case 0xFD:
|
||||
INST_NAME("FSCALE");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fscale, -1, 0);
|
||||
break;
|
||||
case 0xFE:
|
||||
INST_NAME("FSIN");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
CALL(arm_fsin, -1, 0);
|
||||
break;
|
||||
case 0xFF:
|
||||
INST_NAME("FCOS");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
CALL(arm_fcos, -1, 0);
|
||||
break;
|
||||
|
||||
|
||||
case 0xD1:
|
||||
case 0xD4:
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
case 0xD8:
|
||||
case 0xD9:
|
||||
case 0xDA:
|
||||
case 0xDB:
|
||||
case 0xDC:
|
||||
case 0xDD:
|
||||
case 0xDE:
|
||||
case 0xDF:
|
||||
case 0xE2:
|
||||
case 0xE3:
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
case 0xEF:
|
||||
case 0xF5:
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
DEFAULT;
|
||||
break;
|
||||
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FLD ST0, float[ED]");
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
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);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0);
|
||||
LDR_IMM9(x2, ed, fixedaddress);
|
||||
VMOVtoV(s0, x2);
|
||||
}
|
||||
VCVT_F64_F32(v1, s0);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FST float[ED], ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
VCVT_F32_F64(s0, v1);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0);
|
||||
VSTR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0);
|
||||
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);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
VCVT_F32_F64(s0, v1);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0);
|
||||
VSTR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0);
|
||||
VMOVfrV(x2, s0);
|
||||
STR_IMM9(x2, ed, fixedaddress);
|
||||
}
|
||||
x87_do_pop(dyn, ninst);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FLDENV Ed");
|
||||
fpu_purgecache(dyn, ninst, x1, x2, x3); // maybe only x87, not SSE?
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
|
||||
if(ed!=x1) {
|
||||
MOV_REG(x1, ed);
|
||||
}
|
||||
MOVW(x2, 0);
|
||||
CALL(fpu_loadenv, -1, 0);
|
||||
break;
|
||||
case 5:
|
||||
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 7:
|
||||
INST_NAME("FNSTCW Ew");
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0);
|
||||
ed = x1;
|
||||
wb1 = 1;
|
||||
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, cw));
|
||||
EWBACK;
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
Executable
+222
@@ -0,0 +1,222 @@
|
||||
#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 dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
|
||||
{
|
||||
uint8_t nextop = F8;
|
||||
int32_t i32;
|
||||
uint8_t ed;
|
||||
uint8_t wback;
|
||||
int v1, v2;
|
||||
int d0;
|
||||
int s0;
|
||||
int fixedaddress;
|
||||
|
||||
MAYUSE(s0);
|
||||
MAYUSE(d0);
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
MAYUSE(ed);
|
||||
MAYUSE(i32);
|
||||
|
||||
switch(nextop) {
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
case 0xC2:
|
||||
case 0xC3:
|
||||
case 0xC4:
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
INST_NAME("FCMOVB ST0, STx");
|
||||
READFLAGS(X_CF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_CF]));
|
||||
TSTS_REG_LSL_IMM5(x1, x1, 0);
|
||||
VMOVcond_64(cNE, v1, v2); // F_CF==1
|
||||
break;
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
case 0xCA:
|
||||
case 0xCB:
|
||||
case 0xCC:
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF:
|
||||
INST_NAME("FCMOVE ST0, STx");
|
||||
READFLAGS(X_ZF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
TSTS_REG_LSL_IMM5(x1, x1, 0);
|
||||
VMOVcond_64(cNE, v1, v2); // F_ZF==1
|
||||
break;
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
case 0xD2:
|
||||
case 0xD3:
|
||||
case 0xD4:
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
INST_NAME("FCMOVBE ST0, STx");
|
||||
READFLAGS(X_CF|X_ZF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_CF]));
|
||||
ORRS_REG_LSL_IMM5(x1, x1, x2, 0);
|
||||
VMOVcond_64(cNE, v1, v2); // F_CF==1 | F_ZF==1
|
||||
break;
|
||||
case 0xD8:
|
||||
case 0xD9:
|
||||
case 0xDA:
|
||||
case 0xDB:
|
||||
case 0xDC:
|
||||
case 0xDD:
|
||||
case 0xDE:
|
||||
case 0xDF:
|
||||
INST_NAME("FCMOVU ST0, STx");
|
||||
READFLAGS(X_PF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_PF]));
|
||||
TSTS_REG_LSL_IMM5(x1, x1, 0);
|
||||
VMOVcond_64(cNE, v1, v2); // F_PF==1
|
||||
break;
|
||||
case 0xE9:
|
||||
INST_NAME("FUCOMPP ST0, ST1");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 1);
|
||||
VCMP_F64(v1, v2);
|
||||
FCOM(x1, x2);
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_do_pop(dyn, ninst);
|
||||
break;
|
||||
|
||||
case 0xE4:
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
case 0xF4:
|
||||
case 0xF5:
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
case 0xF8:
|
||||
case 0xF9:
|
||||
case 0xFD:
|
||||
DEFAULT;
|
||||
break;
|
||||
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FIADD ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
GETED;
|
||||
d0 = fpu_get_scratch_double(dyn);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
VMOVtoV(s0, ed);
|
||||
VCVT_F64_S32(d0, s0);
|
||||
VADD_F64(v1, v1, d0);
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FIMUL ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
GETED;
|
||||
d0 = fpu_get_scratch_double(dyn);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
VMOVtoV(s0, ed);
|
||||
VCVT_F64_S32(d0, s0);
|
||||
VMUL_F64(v1, v1, d0);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FICOM ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
GETED;
|
||||
d0 = fpu_get_scratch_double(dyn);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
VMOVtoV(s0, ed);
|
||||
VCVT_F64_S32(d0, s0);
|
||||
VCMP_F64(v1, d0);
|
||||
FCOM(x1, x2);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FICOMP ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
GETED;
|
||||
d0 = fpu_get_scratch_double(dyn);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
VMOVtoV(s0, ed);
|
||||
VCVT_F64_S32(d0, s0);
|
||||
VCMP_F64(v1, d0);
|
||||
FCOM(x1, x2);
|
||||
x87_do_pop(dyn, ninst);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FISUB ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
GETED;
|
||||
d0 = fpu_get_scratch_double(dyn);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
VMOVtoV(s0, ed);
|
||||
VCVT_F64_S32(d0, s0);
|
||||
VSUB_F64(v1, v1, d0);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FISUBR ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
GETED;
|
||||
d0 = fpu_get_scratch_double(dyn);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
VMOVtoV(s0, ed);
|
||||
VCVT_F64_S32(d0, s0);
|
||||
VSUB_F64(v1, d0, v1);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FIDIV ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
GETED;
|
||||
d0 = fpu_get_scratch_double(dyn);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
VMOVtoV(s0, ed);
|
||||
VCVT_F64_S32(d0, s0);
|
||||
VDIV_F64(v1, v1, d0);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FIDIVR ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
GETED;
|
||||
d0 = fpu_get_scratch_double(dyn);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
VMOVtoV(s0, ed);
|
||||
VCVT_F64_S32(d0, s0);
|
||||
VDIV_F64(v1, d0, v1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
Executable
+278
@@ -0,0 +1,278 @@
|
||||
#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 "emu/x87emu_private.h"
|
||||
#include "x86run.h"
|
||||
#include "x86emu.h"
|
||||
#include "box86stack.h"
|
||||
#include "callback.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 dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
|
||||
{
|
||||
uint8_t nextop = F8;
|
||||
uint8_t u8;
|
||||
int32_t i32;
|
||||
uint8_t ed;
|
||||
uint8_t wback;
|
||||
int v1, v2;
|
||||
int s0;
|
||||
int fixedaddress;
|
||||
int parity;
|
||||
|
||||
MAYUSE(s0);
|
||||
MAYUSE(v1);
|
||||
MAYUSE(v2);
|
||||
MAYUSE(i32);
|
||||
|
||||
switch(nextop) {
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
case 0xC2:
|
||||
case 0xC3:
|
||||
case 0xC4:
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
INST_NAME("FCMOVNB ST0, STx");
|
||||
READFLAGS(X_CF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_CF]));
|
||||
TSTS_REG_LSL_IMM5(x1, x1, 0);
|
||||
VMOVcond_64(cEQ, v1, v2); // F_CF==0
|
||||
break;
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
case 0xCA:
|
||||
case 0xCB:
|
||||
case 0xCC:
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF:
|
||||
INST_NAME("FCMOVNE ST0, STx");
|
||||
READFLAGS(X_ZF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
TSTS_REG_LSL_IMM5(x1, x1, 0);
|
||||
VMOVcond_64(cEQ, v1, v2); // F_ZF==0
|
||||
break;
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
case 0xD2:
|
||||
case 0xD3:
|
||||
case 0xD4:
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
INST_NAME("FCMOVNBE ST0, STx");
|
||||
READFLAGS(X_CF|X_ZF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_CF]));
|
||||
ORRS_REG_LSL_IMM5(x1, x1, x2, 0);
|
||||
VMOVcond_64(cEQ, v1, v2); // F_CF==0 | F_ZF==0
|
||||
break;
|
||||
case 0xD8:
|
||||
case 0xD9:
|
||||
case 0xDA:
|
||||
case 0xDB:
|
||||
case 0xDC:
|
||||
case 0xDD:
|
||||
case 0xDE:
|
||||
case 0xDF:
|
||||
INST_NAME("FCMOVNU ST0, STx");
|
||||
READFLAGS(X_PF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_PF]));
|
||||
TSTS_REG_LSL_IMM5(x1, x1, 0);
|
||||
VMOVcond_64(cEQ, v1, v2); // F_PF==0
|
||||
break;
|
||||
case 0xE2:
|
||||
INST_NAME("FNCLEX");
|
||||
MOVW(x1, 0);
|
||||
LDRH_IMM8(x2, xEmu, offsetof(x86emu_t, sw));
|
||||
BFI(x2, x1, 0, 8); // IE .. PE, SF, ES
|
||||
BFI(x2, x1, 15, 1); // B
|
||||
STRH_IMM8(x2, xEmu, offsetof(x86emu_t, sw));
|
||||
break;
|
||||
case 0xE3:
|
||||
INST_NAME("FNINIT");
|
||||
fpu_purgecache(dyn, ninst, x1, x2, x3); // maybe only x87, not SSE?
|
||||
CALL(reset_fpu, -1, 0);
|
||||
break;
|
||||
case 0xE8:
|
||||
case 0xE9:
|
||||
case 0xEA:
|
||||
case 0xEB:
|
||||
case 0xEC:
|
||||
case 0xED:
|
||||
case 0xEE:
|
||||
case 0xEF:
|
||||
INST_NAME("FUCOMI ST0, STx");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VCMP_F64(v1, v2);
|
||||
FCOMI(x1, x2);
|
||||
break;
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
case 0xF2:
|
||||
case 0xF3:
|
||||
case 0xF4:
|
||||
case 0xF5:
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
INST_NAME("FCOMI ST0, STx");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VCMP_F64(v1, v2);
|
||||
FCOMI(x1, x2);
|
||||
break;
|
||||
|
||||
case 0xE0:
|
||||
case 0xE1:
|
||||
case 0xE4:
|
||||
case 0xE5:
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
DEFAULT;
|
||||
break;
|
||||
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FILD ST0, Ed");
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
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);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
GETED;
|
||||
VMOVtoV(s0, ed);
|
||||
}
|
||||
VCVT_F64_S32(v1, s0);
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FISTTP Ed, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xEAX+(nextop&7);
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 4095, 0);
|
||||
ed = x1;
|
||||
}
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
MSR_nzcvq_0();
|
||||
VMRS(x12); // Get FPCSR reg to clear exceptions flags
|
||||
ORR_IMM8(x3, x12, 0b001, 6); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
VCVT_S32_F64(s0, v1);
|
||||
VMRS(x3); // get the FPCSR reg and test FPU exception (IO only)
|
||||
VMOVfrV(ed, s0);
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
MOV_IMM_COND(cNE, ed, 0b10, 1); // 0x80000000
|
||||
WBACK;
|
||||
VMSR(x12); // put back values
|
||||
x87_do_pop(dyn, ninst);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FIST Ed, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x12); // 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);
|
||||
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);
|
||||
VCVTR_S32_F64(s0, v1);
|
||||
VMRS(x3); // get the FPCSR reg and test FPU execption (invalid operation only)
|
||||
VMOVfrV(ed, s0);
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
MOV_IMM_COND(cNE, ed, 0b10, 1); // 0x80000000
|
||||
WBACK;
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FISTP Ed, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x12); // 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);
|
||||
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);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FLD tbyte");
|
||||
x87_do_push_empty(dyn, ninst, x1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
|
||||
if(ed!=x1) {
|
||||
MOV_REG(x1, ed);
|
||||
}
|
||||
CALL(arm_fld, -1, 0);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FSTP tbyte");
|
||||
x87_forget(dyn, ninst, x1, x3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
|
||||
if(ed!=x1) {
|
||||
MOV_REG(x1, ed);
|
||||
}
|
||||
CALL(arm_fstp, -1, 0);
|
||||
x87_do_pop(dyn, ninst);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
Executable
+284
@@ -0,0 +1,284 @@
|
||||
#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 dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
|
||||
{
|
||||
uint8_t nextop = F8;
|
||||
uint8_t wback;
|
||||
int v1, v2;
|
||||
int d1;
|
||||
int fixedaddress;
|
||||
int parity;
|
||||
|
||||
MAYUSE(d1);
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
|
||||
switch(nextop) {
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
case 0xC2:
|
||||
case 0xC3:
|
||||
case 0xC4:
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
INST_NAME("FADD STx, ST0");
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VADD_F64(v1, v1, v2);
|
||||
break;
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
case 0xCA:
|
||||
case 0xCB:
|
||||
case 0xCC:
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF:
|
||||
INST_NAME("FMUL STx, ST0");
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VMUL_F64(v1, v1, v2);
|
||||
break;
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
case 0xD2:
|
||||
case 0xD3:
|
||||
case 0xD4:
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
INST_NAME("FCOM ST0, STx"); //yep
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VCMP_F64(v1, v2);
|
||||
FCOM(x1, x2);
|
||||
break;
|
||||
case 0xD8:
|
||||
case 0xD9:
|
||||
case 0xDA:
|
||||
case 0xDB:
|
||||
case 0xDC:
|
||||
case 0xDD:
|
||||
case 0xDE:
|
||||
case 0xDF:
|
||||
INST_NAME("FCOMP ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VCMP_F64(v1, v2);
|
||||
FCOM(x1, x2);
|
||||
x87_do_pop(dyn, ninst);
|
||||
break;
|
||||
case 0xE0:
|
||||
case 0xE1:
|
||||
case 0xE2:
|
||||
case 0xE3:
|
||||
case 0xE4:
|
||||
case 0xE5:
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
INST_NAME("FSUBR STx, ST0");
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VSUB_F64(v1, v2, v1);
|
||||
break;
|
||||
case 0xE8:
|
||||
case 0xE9:
|
||||
case 0xEA:
|
||||
case 0xEB:
|
||||
case 0xEC:
|
||||
case 0xED:
|
||||
case 0xEE:
|
||||
case 0xEF:
|
||||
INST_NAME("FSUB STx, ST0");
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VSUB_F64(v1, v1, v2);
|
||||
break;
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
case 0xF2:
|
||||
case 0xF3:
|
||||
case 0xF4:
|
||||
case 0xF5:
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
INST_NAME("FDIVR STx, ST0");
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VDIV_F64(v1, v2, v1);
|
||||
break;
|
||||
case 0xF8:
|
||||
case 0xF9:
|
||||
case 0xFA:
|
||||
case 0xFB:
|
||||
case 0xFC:
|
||||
case 0xFD:
|
||||
case 0xFE:
|
||||
case 0xFF:
|
||||
INST_NAME("FDIV STx, ST0");
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VDIV_F64(v1, v1, v2);
|
||||
break;
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FADD ST0, double[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
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);
|
||||
VLDR_64(d1, wback, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0);
|
||||
LDR_IMM9(x2, wback, fixedaddress);
|
||||
LDR_IMM9(x3, wback, fixedaddress+4);
|
||||
VMOVtoV_D(d1, x2, x3);
|
||||
}
|
||||
VADD_F64(v1, v1, d1);
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FMUL ST0, double[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
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);
|
||||
VLDR_64(d1, wback, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0);
|
||||
LDR_IMM9(x2, wback, fixedaddress);
|
||||
LDR_IMM9(x3, wback, fixedaddress+4);
|
||||
VMOVtoV_D(d1, x2, x3);
|
||||
}
|
||||
VMUL_F64(v1, v1, d1);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FCOM ST0, double[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
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);
|
||||
VLDR_64(d1, wback, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0);
|
||||
LDR_IMM9(x2, wback, fixedaddress);
|
||||
LDR_IMM9(x3, wback, fixedaddress+4);
|
||||
VMOVtoV_D(d1, x2, x3);
|
||||
}
|
||||
VCMP_F64(v1, d1);
|
||||
FCOM(x1, x2);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FCOMP ST0, double[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
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);
|
||||
VLDR_64(d1, wback, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0);
|
||||
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);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FSUB ST0, double[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
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);
|
||||
VLDR_64(d1, wback, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0);
|
||||
LDR_IMM9(x2, wback, fixedaddress);
|
||||
LDR_IMM9(x3, wback, fixedaddress+4);
|
||||
VMOVtoV_D(d1, x2, x3);
|
||||
}
|
||||
VSUB_F64(v1, v1, d1);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FSUBR ST0, double[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
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);
|
||||
VLDR_64(d1, wback, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0);
|
||||
LDR_IMM9(x2, wback, fixedaddress);
|
||||
LDR_IMM9(x3, wback, fixedaddress+4);
|
||||
VMOVtoV_D(d1, x2, x3);
|
||||
}
|
||||
VSUB_F64(v1, d1, v1);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FDIV ST0, double[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
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);
|
||||
VLDR_64(d1, wback, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0);
|
||||
LDR_IMM9(x2, wback, fixedaddress);
|
||||
LDR_IMM9(x3, wback, fixedaddress+4);
|
||||
VMOVtoV_D(d1, x2, x3);
|
||||
}
|
||||
VDIV_F64(v1, v1, d1);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FDIVR ST0, double[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
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);
|
||||
VLDR_64(d1, wback, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0);
|
||||
LDR_IMM9(x2, wback, fixedaddress);
|
||||
LDR_IMM9(x3, wback, fixedaddress+4);
|
||||
VMOVtoV_D(d1, x2, x3);
|
||||
}
|
||||
VDIV_F64(v1, d1, v1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
Executable
+216
@@ -0,0 +1,216 @@
|
||||
#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 "emu/x87emu_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 dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
|
||||
{
|
||||
uint8_t nextop = F8;
|
||||
int fixedaddress;
|
||||
int parity;
|
||||
uint8_t ed;
|
||||
int v1, v2;
|
||||
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
|
||||
switch(nextop) {
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
case 0xC2:
|
||||
case 0xC3:
|
||||
case 0xC4:
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
INST_NAME("FFREE STx");
|
||||
break; // not handling Tag...
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
case 0xD2:
|
||||
case 0xD3:
|
||||
case 0xD4:
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
INST_NAME("FST ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VMOV_64(v2, v1);
|
||||
break;
|
||||
case 0xD8:
|
||||
INST_NAME("FSTP ST0, ST0");
|
||||
x87_do_pop(dyn, ninst);
|
||||
break;
|
||||
case 0xD9:
|
||||
case 0xDA:
|
||||
case 0xDB:
|
||||
case 0xDC:
|
||||
case 0xDD:
|
||||
case 0xDE:
|
||||
case 0xDF:
|
||||
INST_NAME("FSTP ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VMOV_64(v2, v1);
|
||||
x87_do_pop(dyn, ninst);
|
||||
break;
|
||||
|
||||
case 0xE0:
|
||||
case 0xE1:
|
||||
case 0xE2:
|
||||
case 0xE3:
|
||||
case 0xE4:
|
||||
case 0xE5:
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
INST_NAME("FUCOM ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VCMP_F64(v1, v2);
|
||||
FCOM(x1, x2);
|
||||
break;
|
||||
case 0xE8:
|
||||
case 0xE9:
|
||||
case 0xEA:
|
||||
case 0xEB:
|
||||
case 0xEC:
|
||||
case 0xED:
|
||||
case 0xEE:
|
||||
case 0xEF:
|
||||
INST_NAME("FUCOMP ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VCMP_F64(v1, v2);
|
||||
FCOM(x1, x2);
|
||||
x87_do_pop(dyn, ninst);
|
||||
break;
|
||||
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
case 0xCA:
|
||||
case 0xCB:
|
||||
case 0xCC:
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF:
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
case 0xF2:
|
||||
case 0xF3:
|
||||
case 0xF4:
|
||||
case 0xF5:
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
case 0xF8:
|
||||
case 0xF9:
|
||||
case 0xFA:
|
||||
case 0xFB:
|
||||
case 0xFC:
|
||||
case 0xFD:
|
||||
case 0xFE:
|
||||
case 0xFF:
|
||||
DEFAULT;
|
||||
break;
|
||||
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FLD double");
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
#if 0
|
||||
// can bus error...
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3);
|
||||
VLDR_64(v1, ed, fixedaddress);
|
||||
#else
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 3);
|
||||
if (parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3);
|
||||
VLDR_64(v1, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0);
|
||||
LDR_IMM9(x2, ed, fixedaddress);
|
||||
LDR_IMM9(x3, ed, fixedaddress + 4);
|
||||
VMOVtoV_D(v1, x2, x3);
|
||||
}
|
||||
#endif
|
||||
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);
|
||||
if(ed!=x1) {MOV_REG(x1, ed);}
|
||||
CALL(arm_fistp64, -1, 0);
|
||||
x87_do_pop(dyn, ninst);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FST double");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 3);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3);
|
||||
VSTR_64(v1, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0);
|
||||
VMOVfrV_D(x2, x3, v1);
|
||||
STR_IMM9(x2, ed, fixedaddress);
|
||||
STR_IMM9(x3, ed, fixedaddress+4);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FSTP double");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 3);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3);
|
||||
VSTR_64(v1, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0);
|
||||
VMOVfrV_D(x2, x3, v1);
|
||||
STR_IMM9(x2, ed, fixedaddress);
|
||||
STR_IMM9(x3, ed, fixedaddress+4);
|
||||
}
|
||||
x87_do_pop(dyn, ninst);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FRSTOR m108byte");
|
||||
fpu_purgecache(dyn, ninst, x1, x2, x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
|
||||
if(ed!=x1) {MOV_REG(x1, ed);}
|
||||
CALL(arm_frstor, -1, 0);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FSAVE m108byte");
|
||||
fpu_purgecache(dyn, ninst, x1, x2, x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
|
||||
if(ed!=x1) {MOV_REG(x1, ed);}
|
||||
CALL(arm_fsave, -1, 0);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
Executable
+155
@@ -0,0 +1,155 @@
|
||||
#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_helper.h"
|
||||
|
||||
|
||||
uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
|
||||
{
|
||||
uint8_t nextop = F8;
|
||||
int v1, v2;
|
||||
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
|
||||
switch(nextop) {
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
case 0xC2:
|
||||
case 0xC3:
|
||||
case 0xC4:
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
INST_NAME("FADDP STx, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VADD_F64(v2, v2, v1);
|
||||
x87_do_pop(dyn, ninst);
|
||||
break;
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
case 0xCA:
|
||||
case 0xCB:
|
||||
case 0xCC:
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF:
|
||||
INST_NAME("FMULP STx, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VMUL_F64(v2, v2, v1);
|
||||
x87_do_pop(dyn, ninst);
|
||||
break;
|
||||
case 0xD9: /* FCOMPP */
|
||||
INST_NAME("FCOMPP ST0, ST1");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 1);
|
||||
VCMP_F64(v1, v2);
|
||||
FCOM(x1, x2);
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_do_pop(dyn, ninst);
|
||||
break;
|
||||
case 0xE0:
|
||||
case 0xE1:
|
||||
case 0xE2:
|
||||
case 0xE3:
|
||||
case 0xE4:
|
||||
case 0xE5:
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
INST_NAME("FSUBRP STx, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VSUB_F64(v2, v1, v2);
|
||||
x87_do_pop(dyn, ninst);
|
||||
break;
|
||||
case 0xE8:
|
||||
case 0xE9:
|
||||
case 0xEA:
|
||||
case 0xEB:
|
||||
case 0xEC:
|
||||
case 0xED:
|
||||
case 0xEE:
|
||||
case 0xEF:
|
||||
INST_NAME("FSUBP STx, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VSUB_F64(v2, v2, v1);
|
||||
x87_do_pop(dyn, ninst);
|
||||
break;
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
case 0xF2:
|
||||
case 0xF3:
|
||||
case 0xF4:
|
||||
case 0xF5:
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
INST_NAME("FDIVRP STx, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VDIV_F64(v2, v1, v2);
|
||||
x87_do_pop(dyn, ninst);
|
||||
break;
|
||||
case 0xF8:
|
||||
case 0xF9:
|
||||
case 0xFA:
|
||||
case 0xFB:
|
||||
case 0xFC:
|
||||
case 0xFD:
|
||||
case 0xFE:
|
||||
case 0xFF:
|
||||
INST_NAME("FDIVP STx, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VDIV_F64(v2, v2, v1);
|
||||
x87_do_pop(dyn, ninst);
|
||||
break;
|
||||
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
case 0xD2:
|
||||
case 0xD3:
|
||||
case 0xD4:
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
case 0xD8:
|
||||
case 0xDA:
|
||||
case 0xDB:
|
||||
case 0xDC:
|
||||
case 0xDD:
|
||||
case 0xDE:
|
||||
case 0xDF:
|
||||
DEFAULT;
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
Executable
+241
@@ -0,0 +1,241 @@
|
||||
#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 "emu/x87emu_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 dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
|
||||
{
|
||||
uint8_t nextop = F8;
|
||||
uint8_t u8;
|
||||
int32_t i32;
|
||||
uint8_t wback;
|
||||
uint8_t ed;
|
||||
int v1, v2;
|
||||
int s0;
|
||||
int fixedaddress;
|
||||
|
||||
MAYUSE(s0);
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
MAYUSE(i32);
|
||||
|
||||
switch(nextop) {
|
||||
case 0xE0:
|
||||
INST_NAME("FNSTSW AX");
|
||||
LDR_IMM9(x2, xEmu, offsetof(x86emu_t, top));
|
||||
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
AND_IMM8(x2, x2, 7);
|
||||
BFI(x1, x2, 11, 3); // inject top
|
||||
BFI(xEAX, x1, 0, 16);
|
||||
break;
|
||||
case 0xE8:
|
||||
case 0xE9:
|
||||
case 0xEA:
|
||||
case 0xEB:
|
||||
case 0xEC:
|
||||
case 0xED:
|
||||
case 0xEE:
|
||||
case 0xEF:
|
||||
INST_NAME("FUCOMIP ST0, STx");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VCMP_F64(v1, v2);
|
||||
FCOMI(x1, x2);
|
||||
x87_do_pop(dyn, ninst);
|
||||
break;
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
case 0xF2:
|
||||
case 0xF3:
|
||||
case 0xF4:
|
||||
case 0xF5:
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
INST_NAME("FCOMIP ST0, STx");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VCMP_F64(v1, v2);
|
||||
FCOMI(x1, x2);
|
||||
x87_do_pop(dyn, ninst);
|
||||
break;
|
||||
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
case 0xC2:
|
||||
case 0xC3:
|
||||
case 0xC4:
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
case 0xCA:
|
||||
case 0xCB:
|
||||
case 0xCC:
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF:
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
case 0xD2:
|
||||
case 0xD3:
|
||||
case 0xD4:
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
case 0xD8:
|
||||
case 0xD9:
|
||||
case 0xDA:
|
||||
case 0xDB:
|
||||
case 0xDC:
|
||||
case 0xDD:
|
||||
case 0xDE:
|
||||
case 0xDF:
|
||||
case 0xE1:
|
||||
case 0xE2:
|
||||
case 0xE3:
|
||||
case 0xE4:
|
||||
case 0xE5:
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
case 0xF8:
|
||||
case 0xF9:
|
||||
case 0xFA:
|
||||
case 0xFB:
|
||||
case 0xFC:
|
||||
case 0xFD:
|
||||
case 0xFE:
|
||||
case 0xFF:
|
||||
DEFAULT;
|
||||
break;
|
||||
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FILD ST0, Ew");
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0);
|
||||
LDRSH_IMM8(x1, wback, fixedaddress);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
VMOVtoV(s0, x1);
|
||||
VCVT_F64_S32(v1, s0);
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FISTTP Ew, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x12);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 255, 0);
|
||||
ed = x1;
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
VCVT_S32_F64(s0, v1);
|
||||
VMOVfrV(ed, s0);
|
||||
MSR_nzcvq_0(); // reset Q flag (and all other flags too)
|
||||
SSAT_REG_LSL_IMM5(ed, 16, ed, 0);
|
||||
MRS_aspr(x3); // check Q flag
|
||||
TSTS_IMM8_ROR(x3, 0b10, 3);
|
||||
B_MARK(cEQ); // not saturated, continue
|
||||
MOV32(ed, 0xffff8000);
|
||||
MARK;
|
||||
STRH_IMM8(ed, wback, fixedaddress);
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FIST Ew, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x12);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 255, 0);
|
||||
ed = x1;
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
VCVTR_S32_F64(s0, v1);
|
||||
VMOVfrV(ed, s0);
|
||||
MSR_nzcvq_0(); // reset Q flag (and all other flags too)
|
||||
SSAT_REG_LSL_IMM5(ed, 16, ed, 0);
|
||||
MRS_aspr(x3); // check Q flag
|
||||
TSTS_IMM8_ROR(x3, 0b10, 3);
|
||||
B_MARK(cEQ); // not saturated, continue
|
||||
MOV32(ed, 0xffff8000);
|
||||
MARK;
|
||||
STRH_IMM8(ed, wback, fixedaddress);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FISTP Ew, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x12);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 255, 0);
|
||||
ed = x1;
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
VCVTR_S32_F64(s0, v1);
|
||||
VMOVfrV(ed, s0);
|
||||
MSR_nzcvq_0(); // reset Q flag (and all other flags too)
|
||||
SSAT_REG_LSL_IMM5(ed, 16, ed, 0);
|
||||
MRS_aspr(x3); // check Q flag
|
||||
TSTS_IMM8_ROR(x3, 0b10, 3);
|
||||
B_MARK(cEQ); // not saturated, continue
|
||||
MOV32(ed, 0xffff8000);
|
||||
MARK;
|
||||
STRH_IMM8(ed, wback, fixedaddress);
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FBLD ST0, tbytes");
|
||||
x87_do_push_empty(dyn, ninst, x1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
|
||||
if(ed!=x1) {MOV_REG(x1, ed);}
|
||||
CALL(fpu_fbld, -1, 0);
|
||||
break;
|
||||
case 5: // could be inlined for most thing, but is it usefull?
|
||||
INST_NAME("FILD ST0, i64");
|
||||
x87_do_push_empty(dyn, ninst, x1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
|
||||
if(ed!=x1) {MOV_REG(x1, ed);}
|
||||
CALL(arm_fild64, -1, 0);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FBSTP tbytes, ST0");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
|
||||
if(ed!=x1) {MOV_REG(x1, ed);}
|
||||
CALL(fpu_fbst, -1, 0);
|
||||
x87_do_pop(dyn, ninst);
|
||||
break;
|
||||
case 7: // could be inlined for most thing, but is it usefull?
|
||||
INST_NAME("FISTP i64, ST0");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
|
||||
if(ed!=x1) {MOV_REG(x1, ed);}
|
||||
CALL(arm_fistp64, -1, 0);
|
||||
x87_do_pop(dyn, ninst);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
Executable
+1066
File diff suppressed because it is too large.
Load diff
Executable
+2291
File diff suppressed because it is too large.
Load diff
Executable
+280
@@ -0,0 +1,280 @@
|
||||
#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 "../tools/bridge_private.h"
|
||||
|
||||
#include "dynarec_arm_functions.h"
|
||||
#include "dynarec_arm_helper.h"
|
||||
|
||||
// emit SHL32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_shl32c(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));
|
||||
MOVW(s4, d_shl32);
|
||||
} else IFX(X_ALL) {
|
||||
MOVW(s4, d_none);
|
||||
}
|
||||
IFX(X_PEND|X_ALL) {
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df));
|
||||
}
|
||||
if(c==0) {
|
||||
IFX(F_OF) {
|
||||
MOVW(s4, 0);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF]));
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
IFX(X_CF) {
|
||||
UBFX(s3, s1, c, 1);
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_CF]));
|
||||
}
|
||||
IFX(X_ZF|X_OF) {
|
||||
MOVS_REG_LSL_IMM5(s1, s1, c);
|
||||
} else {
|
||||
MOV_REG_LSL_IMM5(s1, s1, c);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
MOVW_COND(cNE, s3, 0);
|
||||
MOVW_COND(cEQ, s3, 1);
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
}
|
||||
IFX(X_SF) {
|
||||
UBFX(s3, s1, 31, 1);
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_SF]));
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
IFX(X_SF) {} else {UBFX(s3, s1, 31, 1);}
|
||||
XOR_IMM8_COND(cCS, s3, s3, 1);
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_OF]));
|
||||
} else {
|
||||
MOVW(s4, 0);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF]));
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
|
||||
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
|
||||
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
|
||||
AND_IMM8(s3, s1, 31);
|
||||
MVN_REG_LSR_REG(s4, s4, s3);
|
||||
AND_IMM8(s4, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_PF]));
|
||||
}
|
||||
}
|
||||
|
||||
// emit SHR32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_shr32c(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));
|
||||
MOVW(s4, d_shr32);
|
||||
} else IFX(X_ALL) {
|
||||
MOVW(s4, d_none);
|
||||
}
|
||||
IFX(X_PEND|X_ALL) {
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df));
|
||||
}
|
||||
if(!c) {
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
IFX(X_ZF|X_CF) {
|
||||
MOVS_REG_LSR_IMM5(s1, s1, c);
|
||||
} else {
|
||||
MOV_REG_LSR_IMM5(s1, s1, c);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
MOVW_COND(cNE, s3, 0);
|
||||
MOVW_COND(cEQ, s3, 1);
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
}
|
||||
IFX(X_CF) {
|
||||
MOVW_COND(cCC, s3, 0);
|
||||
MOVW_COND(cCS, s3, 1);
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_CF]));
|
||||
}
|
||||
IFX(X_SF) {
|
||||
UBFX(s3, s1, 31, 1);
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_SF]));
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 30);
|
||||
XOR_REG_LSR_IMM8(s4, s4, s4, 1);
|
||||
AND_IMM8(s4, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF]));
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
|
||||
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
|
||||
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
|
||||
AND_IMM8(s3, s1, 31);
|
||||
MVN_REG_LSR_REG(s4, s4, s3);
|
||||
AND_IMM8(s4, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_PF]));
|
||||
}
|
||||
}
|
||||
|
||||
// emit SAR32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_sar32c(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));
|
||||
MOVW(s4, d_sar32);
|
||||
} else IFX(X_ALL) {
|
||||
MOVW(s4, d_none);
|
||||
}
|
||||
IFX(X_PEND|X_ALL) {
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df));
|
||||
}
|
||||
if(!c) {
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
IFX(X_ZF|X_CF) {
|
||||
MOVS_REG_ASR_IMM5(s1, s1, c);
|
||||
} else {
|
||||
MOV_REG_ASR_IMM5(s1, s1, c);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
MOVW_COND(cNE, s3, 0);
|
||||
MOVW_COND(cEQ, s3, 1);
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
}
|
||||
IFX(X_CF) {
|
||||
MOVW_COND(cCC, s3, 0);
|
||||
MOVW_COND(cCS, s3, 1);
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_CF]));
|
||||
}
|
||||
IFX(X_SF) {
|
||||
UBFX(s3, s1, 31, 1);
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_SF]));
|
||||
}
|
||||
IFX(X_PF) {
|
||||
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
|
||||
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
|
||||
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
|
||||
AND_IMM8(s3, s1, 31);
|
||||
MVN_REG_LSR_REG(s4, s4, s3);
|
||||
AND_IMM8(s4, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_PF]));
|
||||
}
|
||||
}
|
||||
|
||||
// emit ROL32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_rol32c(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));
|
||||
MOVW(s4, d_rol32);
|
||||
} else IFX(X_ALL) {
|
||||
MOVW(s4, d_none);
|
||||
}
|
||||
IFX(X_PEND|X_ALL) {
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df));
|
||||
}
|
||||
if(!c) {
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
MOV_REG_ROR_IMM5(s1, s1, 32-c);
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_CF) {
|
||||
AND_IMM8(s3, s1, 1);
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_CF]));
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
ADD_REG_LSR_IMM5(s3, s1, s1, 31);
|
||||
AND_IMM8(s3, s3, 1);
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_OF]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// emit ROR32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_ror32c(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));
|
||||
MOVW(s4, d_ror32);
|
||||
} else IFX(X_ALL) {
|
||||
MOVW(s4, d_none);
|
||||
}
|
||||
IFX(X_PEND|X_ALL) {
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df));
|
||||
}
|
||||
if(!c) {
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
MOV_REG_ROR_IMM5(s1, s1, c);
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_CF) {
|
||||
UBFX(s3, s1, 31, 1);
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, flags[F_CF]));
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 30);
|
||||
XOR_REG_LSR_IMM8(s4, s4, s4, 1);
|
||||
AND_IMM8(s4, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF]));
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+484
@@ -0,0 +1,484 @@
|
||||
#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 "../tools/bridge_private.h"
|
||||
|
||||
#include "dynarec_arm_functions.h"
|
||||
#include "dynarec_arm_helper.h"
|
||||
|
||||
// emit CMP32 instruction, from cmp s1 , s2, using s3 and s4 as scratch
|
||||
void emit_cmp32(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));
|
||||
MOVW(s4, d_cmp32);
|
||||
} else {
|
||||
MOVW(s4, 0);
|
||||
}
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df)); // reset flags
|
||||
SUBS_REG_LSL_IMM5(s3, s1, s2, 0); // res = s1 - s2
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
IFX(X_PEND) {
|
||||
MOVW(s4, 0);
|
||||
}
|
||||
// first the easy flag, also found on ARM
|
||||
MOVW_COND(cEQ, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
}
|
||||
IFX(X_OF) {
|
||||
IFX(X_ZF|X_PEND) {
|
||||
MOVW(s4, 0);
|
||||
}
|
||||
MOVW_COND(cVS, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF]));
|
||||
}
|
||||
IFX(X_CF) {
|
||||
IFX(X_ZF|X_OF|X_PEND) {
|
||||
MOVW(s4, 0);
|
||||
}
|
||||
MOVW_COND(cCC, s4, 1); // Carry flags on ARM is reversed compared to x86 one
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_CF]));
|
||||
}
|
||||
IFX(X_SF) {
|
||||
UBFX(s4, s3, 31, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_SF]));
|
||||
}
|
||||
// and now the tricky ones (and mostly unused), PF and AF
|
||||
IFX(X_AF) {
|
||||
// bc = (res & (~d | s)) | (~d & s)
|
||||
MVN_REG_LSL_IMM5(s4, s1, 0); // s4 = ~d
|
||||
ORR_REG_LSL_IMM5(s4, s4, s2, 0); // s4 = ~d | s
|
||||
AND_REG_LSL_IMM5(s4, s4, s3, 0); // s4 = res & (~d | s)
|
||||
BIC_REG_LSL_IMM5(s3, s2, s1, 0); // loosing res... s3 = s & ~d
|
||||
ORR_REG_LSL_IMM5(s3, s4, s3, 0); // s3 = (res & (~d | s)) | (s & ~d)
|
||||
IFX(X_AF) {
|
||||
UBFX(s4, s3, 3, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_AF])); // 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
|
||||
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
|
||||
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);
|
||||
AND_IMM8(s4, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_PF]));
|
||||
}
|
||||
}
|
||||
|
||||
// emit CMP32 instruction, from cmp s1 , 0, using s3 and s4 as scratch
|
||||
void emit_cmp32_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
{
|
||||
MOVW(s4, 0);
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, op2));
|
||||
MOVW(s4, d_cmp32);
|
||||
}
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df)); // reset flags
|
||||
SUBS_IMM8(s3, s1, 0); // res = s1 - 0
|
||||
IFX(X_PEND) {
|
||||
IFX(X_ZF|X_OF|X_CF|X_AF) {
|
||||
MOVW(s4, 0);
|
||||
}
|
||||
}
|
||||
// and now the tricky ones (and mostly unused), PF and AF
|
||||
// bc = (res & (~d | s)) | (~d & s) => is 0 here...
|
||||
IFX(X_CF) {
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_CF])); // CF : bc & 0x80000000
|
||||
}
|
||||
IFX(X_AF) {
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_AF])); // AF: bc & 0x08
|
||||
}
|
||||
IFX(X_OF) {
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF]));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
// first the easy flags, also found on ARM
|
||||
MOVW_COND(cEQ, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
}
|
||||
IFX(X_SF) {
|
||||
UBFX(s4, s3, 31, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_SF]));
|
||||
}
|
||||
IFX(X_PF) {
|
||||
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
|
||||
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
|
||||
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
|
||||
AND_IMM8(s3, s1, 31);
|
||||
MVN_REG_LSR_REG(s4, s4, s3);
|
||||
AND_IMM8(s4, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_PF]));
|
||||
}
|
||||
}
|
||||
|
||||
// emit CMP16 instruction, from cmp s1 , s2, using s3 and s4 as scratch
|
||||
void emit_cmp16(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));
|
||||
MOVW(s3, d_cmp16);
|
||||
} else {
|
||||
MOVW(s3, 0);
|
||||
}
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, df)); // reset flags
|
||||
SUB_REG_LSL_IMM5(s3, s1, s2, 0); // res = s1 - s2
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
MOVW(s4, 0xffff);
|
||||
TSTS_REG_LSL_IMM5(s3, s4, 0);
|
||||
MOVW_COND(cNE, s4, 0);
|
||||
MOVW_COND(cEQ, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
}
|
||||
IFX(X_SF) {
|
||||
UBFX(s4, s3, 15, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_SF]));
|
||||
}
|
||||
// bc = (res & (~d | s)) | (~d & s)
|
||||
IFX(X_CF|X_AF|X_OF) {
|
||||
MVN_REG_LSL_IMM5(s4, s1, 0); // s4 = ~d
|
||||
ORR_REG_LSL_IMM5(s4, s4, s2, 0); // s4 = ~d | s
|
||||
AND_REG_LSL_IMM5(s4, s4, s3, 0); // s4 = res & (~d | s)
|
||||
BIC_REG_LSL_IMM5(s3, s2, s1, 0); // loosing res... s3 = s & ~d
|
||||
ORR_REG_LSL_IMM5(s3, s4, s3, 0); // s3 = (res & (~d | s)) | (s & ~d)
|
||||
IFX(X_CF) {
|
||||
UBFX(s4, s3, 15, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_CF])); // CF : bc & 0x8000
|
||||
}
|
||||
IFX(X_AF) {
|
||||
UBFX(s4, s3, 3, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_AF])); // AF: bc & 0x08
|
||||
}
|
||||
IFX(X_OF) {
|
||||
MOV_REG_LSR_IMM5(s4, s3, 14);
|
||||
XOR_REG_LSR_IMM8(s4, s4, s4, 1);
|
||||
AND_IMM8(s4, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF])); // OF: ((bc >> 14) ^ ((bc>>14)>>1)) & 1
|
||||
}
|
||||
}
|
||||
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
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
|
||||
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
|
||||
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);
|
||||
AND_IMM8(s4, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_PF]));
|
||||
}
|
||||
}
|
||||
|
||||
// emit CMP16 instruction, from cmp s1 , #0, using s3 and s4 as scratch
|
||||
void emit_cmp16_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
{
|
||||
MOVW(s3, 0);
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
MOVW(s3, d_cmp16);
|
||||
}
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, df)); // reset flags
|
||||
IFX(X_OF|X_CF|X_AF) {
|
||||
MOVW(s4, 0);
|
||||
}
|
||||
// bc = (res & (~d | s)) | (~d & s) = 0
|
||||
IFX(X_CF) {
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_CF])); // CF : bc & 0x8000
|
||||
}
|
||||
IFX(X_AF) {
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_AF])); // AF: bc & 0x08
|
||||
}
|
||||
IFX(X_OF) {
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF])); // OF: ((bc >> 14) ^ ((bc>>14)>>1)) & 1
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
MOVW(s4, 0xffff);
|
||||
TSTS_REG_LSL_IMM5(s1, s4, 0);
|
||||
MOVW(s4, 0);
|
||||
MOVW_COND(cEQ, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
}
|
||||
IFX(X_SF) {
|
||||
UBFX(s4, s1, 15, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_SF]));
|
||||
}
|
||||
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
IFX(X_PF) {
|
||||
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
|
||||
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
|
||||
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
|
||||
AND_IMM8(s3, s1, 31);
|
||||
MVN_REG_LSR_REG(s4, s4, s3);
|
||||
AND_IMM8(s4, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_PF]));
|
||||
}
|
||||
}
|
||||
// emit CMP8 instruction, from cmp s1 , s2, using s3 and s4 as scratch
|
||||
void emit_cmp8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOVW(s4, d_cmp8);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
} else {
|
||||
MOVW(s4, 0);
|
||||
}
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df)); // reset flags
|
||||
SUB_REG_LSL_IMM5(s3, s1, s2, 0); // res = s1 - s2
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
IFX(X_PEND) {
|
||||
MOVW(s4, 0);
|
||||
}
|
||||
TSTS_IMM8(s3, 0xff);
|
||||
MOVW_COND(cEQ, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
}
|
||||
IFX(X_SF) {
|
||||
UBFX(s4, s3, 7, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_SF]));
|
||||
}
|
||||
// bc = (res & (~d | s)) | (~d & s)
|
||||
IFX(X_CF|X_AF|X_OF) {
|
||||
MVN_REG_LSL_IMM5(s4, s1, 0); // s4 = ~d
|
||||
ORR_REG_LSL_IMM5(s4, s4, s2, 0); // s4 = ~d | s
|
||||
AND_REG_LSL_IMM5(s4, s4, s3, 0); // s4 = res & (~d | s)
|
||||
BIC_REG_LSL_IMM5(s3, s2, s1, 0); // loosing res... s3 = s & ~d
|
||||
ORR_REG_LSL_IMM5(s3, s4, s3, 0); // s3 = (res & (~d | s)) | (s & ~d)
|
||||
IFX(X_CF) {
|
||||
UBFX(s4, s3, 7, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_CF])); // CF : bc & 0x80
|
||||
}
|
||||
IFX(X_AF) {
|
||||
UBFX(s4, s3, 3, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_AF])); // AF: bc & 0x08
|
||||
}
|
||||
IFX(X_OF) {
|
||||
MOV_REG_LSR_IMM5(s4, s3, 6);
|
||||
XOR_REG_LSR_IMM8(s4, s4, s4, 1);
|
||||
AND_IMM8(s4, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF])); // OF: ((bc >> 6) ^ ((bc>>6)>>1)) & 1
|
||||
}
|
||||
}
|
||||
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
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
|
||||
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
|
||||
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);
|
||||
AND_IMM8(s4, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_PF]));
|
||||
}
|
||||
}
|
||||
// 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)
|
||||
{
|
||||
MOVW(s4, 0);
|
||||
IFX(X_PEND) {
|
||||
MOVW(s3, d_cmp8);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, op2));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, df));
|
||||
} else {
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df)); // reset flags
|
||||
}
|
||||
// bc = (res & (~d | s)) | (~d & s) = 0
|
||||
IFX(X_CF) {
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_CF])); // CF : bc & 0x80
|
||||
}
|
||||
IFX(X_AF) {
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_AF])); // AF: bc & 0x08
|
||||
}
|
||||
IFX(X_OF) {
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF])); // OF: ((bc >> 6) ^ ((bc>>6)>>1)) & 1
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTS_IMM8(s1, 0xff);
|
||||
MOVW_COND(cEQ, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
}
|
||||
IFX(X_SF) {
|
||||
UBFX(s4, s1, 7, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_SF]));
|
||||
}
|
||||
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
IFX(X_PF) {
|
||||
AND_IMM8(s3, s1, 0xE0); // lsr 5 masking pre-applied
|
||||
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
|
||||
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
|
||||
AND_IMM8(s3, s1, 31);
|
||||
MVN_REG_LSR_REG(s4, s4, s3);
|
||||
AND_IMM8(s4, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_PF]));
|
||||
}
|
||||
}
|
||||
|
||||
// emit TEST32 instruction, from test s1 , s2, using s3 and s4 as scratch
|
||||
void emit_test32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MOVW(s4, 0);
|
||||
IFX(X_PEND) {
|
||||
MOVW(s3, d_tst32);
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, df));
|
||||
} else {
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df)); // reset flags
|
||||
}
|
||||
IFX(X_OF) {
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF]));
|
||||
}
|
||||
IFX(X_CF) {
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_CF]));
|
||||
}
|
||||
ANDS_REG_LSL_IMM5(s3, s1, s2, 0); // res = s1 & s2
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
MOVW_COND(cEQ, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
}
|
||||
IFX(X_SF) {
|
||||
UBFX(s4, s3, 31, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_SF]));
|
||||
}
|
||||
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
IFX(X_PF) {
|
||||
AND_IMM8(s3, s3, 0xE0); // lsr 5 masking pre-applied
|
||||
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
|
||||
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);
|
||||
AND_IMM8(s4, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_PF]));
|
||||
}
|
||||
}
|
||||
|
||||
// emit TEST16 instruction, from test s1 , s2, using s3 and s4 as scratch
|
||||
void emit_test16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MOVW(s4, 0);
|
||||
IFX(X_PEND) {
|
||||
MOVW(s3, d_tst16);
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, df));
|
||||
} else {
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df)); // reset flags
|
||||
}
|
||||
IFX(X_OF) {
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF]));
|
||||
}
|
||||
IFX(X_CF) {
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_CF]));
|
||||
}
|
||||
ANDS_REG_LSL_IMM5(s3, s1, s2, 0); // res = s1 & s2
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
MOVW_COND(cEQ, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
}
|
||||
IFX(X_SF) {
|
||||
UBFX(s4, s3, 15, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_SF]));
|
||||
}
|
||||
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
IFX(X_PF) {
|
||||
AND_IMM8(s3, s3, 0xE0); // lsr 5 masking pre-applied
|
||||
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
|
||||
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);
|
||||
AND_IMM8(s4, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_PF]));
|
||||
}
|
||||
}
|
||||
|
||||
// emit TEST8 instruction, from test s1 , s2, using s3 and s4 as scratch
|
||||
void emit_test8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
MOVW(s4, 0);
|
||||
IFX(X_PEND) {
|
||||
MOVW(s3, d_tst8);
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, df));
|
||||
} else {
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, df)); // reset flags
|
||||
}
|
||||
IFX(X_OF) {
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_OF]));
|
||||
}
|
||||
IFX(X_CF) {
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_CF]));
|
||||
}
|
||||
ANDS_REG_LSL_IMM5(s3, s1, s2, 0); // res = s1 & s2
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
MOVW_COND(cEQ, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
}
|
||||
IFX(X_SF) {
|
||||
UBFX(s4, s3, 7, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_SF]));
|
||||
}
|
||||
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
IFX(X_PF) {
|
||||
AND_IMM8(s3, s3, 0xE0); // lsr 5 masking pre-applied
|
||||
LDR_IMM9(s4, xEmu, offsetof(x86emu_t, x86emu_parity_tab));
|
||||
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);
|
||||
AND_IMM8(s4, s4, 1);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, flags[F_PF]));
|
||||
}
|
||||
}
|
||||
Executable
+105
@@ -0,0 +1,105 @@
|
||||
#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_helper.h"
|
||||
|
||||
|
||||
uintptr_t dynarecF0(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
|
||||
{
|
||||
uint8_t nextop = PK(0); // don't increment addr
|
||||
int locked = 0;
|
||||
switch(nextop) {
|
||||
// generic case
|
||||
#define GO(A) \
|
||||
case A+0x00: \
|
||||
case A+0x01: \
|
||||
case A+0x02: \
|
||||
case A+0x03: \
|
||||
case A+0x04: \
|
||||
case A+0x05:
|
||||
GO(0x00);
|
||||
GO(0x08);
|
||||
GO(0x10);
|
||||
GO(0x18);
|
||||
GO(0x20);
|
||||
GO(0x28);
|
||||
GO(0x30);
|
||||
#undef GO
|
||||
|
||||
case 0x81:
|
||||
case 0x83:
|
||||
MESSAGE(LOG_DUMP, "LOCK\n");
|
||||
locked = 1;
|
||||
LOCK;
|
||||
addr = dynarec00(dyn, addr, ip, ninst, ok, need_epilog);
|
||||
break;
|
||||
|
||||
case 0x86: // for this two, the lock is already done by the opcode, so just ignoring it
|
||||
case 0x87:
|
||||
addr = dynarec00(dyn, addr, ip, ninst, ok, need_epilog);
|
||||
break;
|
||||
|
||||
case 0x0F:
|
||||
nextop = PK(1);
|
||||
switch(nextop) {
|
||||
case 0xB0:
|
||||
case 0xB1:
|
||||
case 0xB3:
|
||||
case 0xBA:
|
||||
case 0xBB:
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
case 0xC7:
|
||||
MESSAGE(LOG_DUMP, "LOCK\n");
|
||||
locked = 1;
|
||||
LOCK;
|
||||
addr = dynarec0F(dyn, addr+1, ip, ninst, ok, need_epilog);
|
||||
break;
|
||||
|
||||
default:
|
||||
addr = dynarec0F(dyn, addr+1, ip, ninst, ok, need_epilog); // no lock, regular instruction...
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xFF:
|
||||
nextop = PK(1);
|
||||
switch((nextop>>3)&7)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
MESSAGE(LOG_DUMP, "LOCK\n");
|
||||
locked = 1;
|
||||
LOCK;
|
||||
addr = dynarec00(dyn, addr, ip, ninst, ok, need_epilog);
|
||||
break;
|
||||
default:
|
||||
addr = dynarec00(dyn, addr, ip, ninst, ok, need_epilog); // no lock, regular instruction...
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
addr = dynarec00(dyn, addr, ip, ninst, ok, need_epilog); // no lock, regular instruction...
|
||||
}
|
||||
if(locked) {UNLOCK;}
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
Executable
+316
@@ -0,0 +1,316 @@
|
||||
#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"
|
||||
|
||||
// Get Ex as a double, not a quad (warning, x2 and x3 may get used)
|
||||
#define GETEX(a) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
a = sse_get_reg(dyn, ninst, x1, nextop&7); \
|
||||
} else { \
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 3); \
|
||||
a = fpu_get_scratch_double(dyn); \
|
||||
if(parity) { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3); \
|
||||
VLDR_64(a, ed, fixedaddress); \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0);\
|
||||
LDR_IMM9(x2, ed, fixedaddress+0); \
|
||||
LDR_IMM9(x3, ed, fixedaddress+4); \
|
||||
VMOVtoV_D(a, x2, x3); \
|
||||
} \
|
||||
}
|
||||
|
||||
uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
|
||||
{
|
||||
uint8_t nextop = F8;
|
||||
uint8_t u8;
|
||||
uint32_t u32;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback;
|
||||
int v0, v1;
|
||||
int d0, d1;
|
||||
int s0;
|
||||
int fixedaddress;
|
||||
int parity;
|
||||
|
||||
MAYUSE(s0);
|
||||
MAYUSE(d1);
|
||||
MAYUSE(d0);
|
||||
|
||||
switch(nextop) {
|
||||
|
||||
case 0x10:
|
||||
INST_NAME("MOVSD Gx, Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
d0 = sse_get_reg(dyn, ninst, x1, nextop&7);
|
||||
VMOVD(v0, d0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0);
|
||||
LDR_IMM9(x2, ed, fixedaddress+0);
|
||||
LDR_IMM9(x3, ed, fixedaddress+4);
|
||||
VMOVtoV_D(v0, x2, x3);
|
||||
VEOR(v0+1, v0+1, v0+1); // upper 64bits set to 0
|
||||
}
|
||||
break;
|
||||
case 0x11:
|
||||
INST_NAME("MOVSD Ex, Gx");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
d0 = sse_get_reg(dyn, ninst, x1, nextop&7);
|
||||
VMOVD(d0, v0);
|
||||
} else {
|
||||
VMOVfrV_D(x2, x3, v0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0);
|
||||
STR_IMM9(x2, ed, fixedaddress+0);
|
||||
STR_IMM9(x3, ed, fixedaddress+4);
|
||||
}
|
||||
break;
|
||||
case 0x12:
|
||||
INST_NAME("MOVDDUP Gx, Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
d0 = sse_get_reg(dyn, ninst, x1, nextop&7);
|
||||
VMOVD(v0, d0);
|
||||
VMOVD(v0+1, d0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0);
|
||||
LDR_IMM9(x2, ed, fixedaddress+0);
|
||||
LDR_IMM9(x3, ed, fixedaddress+4);
|
||||
VMOVtoV_D(v0, x2, x3);
|
||||
VMOVD(v0+1, v0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x2A:
|
||||
INST_NAME("CVTSI2SD Gx, Ed");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
GETED;
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
VMOVtoV(s0, ed);
|
||||
VCVT_F64_S32(v0, s0);
|
||||
break;
|
||||
|
||||
case 0x2C:
|
||||
INST_NAME("CVTTSD2SI Gd, Ex");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
d0 = sse_get_reg(dyn, ninst, x1, nextop&7);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3);
|
||||
d0 = fpu_get_scratch_double(dyn);
|
||||
VLDR_64(d0, ed, fixedaddress);
|
||||
}
|
||||
VCVT_S32_F64(s0, d0);
|
||||
VMOVfrV(gd, s0);
|
||||
break;
|
||||
case 0x2D:
|
||||
INST_NAME("CVTSD2SI Gd, Ex");
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x12);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
d0 = sse_get_reg(dyn, ninst, x1, nextop&7);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3);
|
||||
d0 = fpu_get_scratch_double(dyn);
|
||||
VLDR_64(d0, ed, fixedaddress);
|
||||
}
|
||||
VCVTR_S32_F64(s0, d0);
|
||||
VMOVfrV(gd, s0);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
|
||||
case 0x51:
|
||||
INST_NAME("SQRTSD Gx, Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
GETEX(d0);
|
||||
VSQRT_F64(v0, d0);
|
||||
break;
|
||||
|
||||
case 0x58:
|
||||
INST_NAME("ADDSD Gx, Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
GETEX(d0);
|
||||
VADD_F64(v0, v0, d0);
|
||||
break;
|
||||
case 0x59:
|
||||
INST_NAME("MULSD Gx, Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
GETEX(d0);
|
||||
VMUL_F64(v0, v0, d0);
|
||||
break;
|
||||
case 0x5A:
|
||||
INST_NAME("CVTSD2SS Gx, Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
GETEX(d0);
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
VCVT_F32_F64(s0, d0);
|
||||
VMOV_64(d1, v0);
|
||||
VMOV_32(d1*2, s0);
|
||||
VMOV_64(v0, d1);
|
||||
break;
|
||||
|
||||
case 0x5C:
|
||||
INST_NAME("SUBSD Gx, Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
GETEX(d0);
|
||||
VSUB_F64(v0, v0, d0);
|
||||
break;
|
||||
case 0x5D:
|
||||
INST_NAME("MINSD Gx, Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
GETEX(d0);
|
||||
// MINSD: if any input is NaN, or Ex[0]<Gx[0], copy Ex[0] -> Gx[0]
|
||||
VCMP_F64(v0, d0);
|
||||
VMRS_APSR();
|
||||
VMOVcond_64(cPL, v0, d0);
|
||||
break;
|
||||
case 0x5E:
|
||||
INST_NAME("DIVSD Gx, Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
GETEX(d0);
|
||||
VDIV_F64(v0, v0, d0);
|
||||
break;
|
||||
case 0x5F:
|
||||
INST_NAME("MAXSD Gx, Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
GETEX(d0);
|
||||
// MAXSD: if any input is NaN, or Ex[0]>Gx[0], copy Ex[0] -> Gx[0]
|
||||
VCMP_F64(d0, v0);
|
||||
VMRS_APSR();
|
||||
VMOVcond_64(cPL, v0, d0);
|
||||
break;
|
||||
|
||||
case 0x70:
|
||||
INST_NAME("PSHUFLW Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
|
||||
v1 = fpu_get_scratch_quad(dyn);
|
||||
VLD1Q_64(v1, ed);
|
||||
}
|
||||
|
||||
u8 = F8;
|
||||
// only low part need to be suffled. VTBL only handle 8bits value, so the 16bits suffles need to be changed in 8bits
|
||||
u32 = 0;
|
||||
for (int i=0; i<2; ++i) {
|
||||
u32 |= (((u8>>(i*2))&3)*2+0)<<(i*16+0);
|
||||
u32 |= (((u8>>(i*2))&3)*2+1)<<(i*16+8);
|
||||
}
|
||||
MOV32(x2, u32);
|
||||
u32 = 0;
|
||||
for (int i=2; i<4; ++i) {
|
||||
u32 |= (((u8>>(i*2))&3)*2+0)<<((i-2)*16+0);
|
||||
u32 |= (((u8>>(i*2))&3)*2+1)<<((i-2)*16+8);
|
||||
}
|
||||
MOV32(x3, u32);
|
||||
d0 = fpu_get_scratch_double(dyn);
|
||||
VMOVtoV_D(d0, x2, x3);
|
||||
VTBL1_8(v0, v1, d0);
|
||||
if(v0!=v1) {
|
||||
VMOVD(v0+1, v1+1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x7C:
|
||||
INST_NAME("HADDPS Gx, Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
|
||||
v1 = fpu_get_scratch_quad(dyn);
|
||||
VLD1Q_64(v1, ed);
|
||||
}
|
||||
VPADD_F32(v0, v0, v0+1);
|
||||
if(v0==v1) {
|
||||
VMOVD(v0+1, v0);
|
||||
} else {
|
||||
VPADD_F32(v0+1, v1, v1+1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC2:
|
||||
INST_NAME("CMPSD Gx, Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
GETEX(d0);
|
||||
VCMP_F64(v0, d0);
|
||||
VMRS_APSR();
|
||||
MOVW(x2, 0);
|
||||
u8 = F8;
|
||||
switch(u8&7) {
|
||||
case 0: MVN_COND_REG_LSL_IMM5(cEQ, x2, x2, 0); break; // Equal
|
||||
case 1: MVN_COND_REG_LSL_IMM5(cCC, x2, x2, 0); break; // Less than
|
||||
case 2: MVN_COND_REG_LSL_IMM5(cLS, x2, x2, 0); break; // Less or equal
|
||||
case 3: MVN_COND_REG_LSL_IMM5(cVS, x2, x2, 0); break; // NaN
|
||||
case 4: MVN_COND_REG_LSL_IMM5(cNE, x2, x2, 0); break; // Not Equal (or unordered on ARM, not on X86...)
|
||||
case 5: MVN_COND_REG_LSL_IMM5(cPL, x2, x2, 0); break; // Greater or equal or unordered
|
||||
case 6: MVN_COND_REG_LSL_IMM5(cHI, x2, x2, 0); break; // Greater or unordered
|
||||
case 7: MVN_COND_REG_LSL_IMM5(cVC, x2, x2, 0); break; // not NaN
|
||||
}
|
||||
VMOVtoV_D(v0, x2, x2);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
Executable
+575
@@ -0,0 +1,575 @@
|
||||
#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"
|
||||
|
||||
// Get Ex as a single, not a quad, with b a intermediary double
|
||||
#define GETEX(a, b) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
b = sse_get_reg(dyn, ninst, x1, nextop&7); \
|
||||
if(b<16) \
|
||||
a = b; \
|
||||
else { \
|
||||
a = fpu_get_scratch_double(dyn); \
|
||||
VMOV_64(a, b); \
|
||||
} \
|
||||
a *= 2; \
|
||||
} else { \
|
||||
b = fpu_get_scratch_double(dyn); \
|
||||
a = b*2; \
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2); \
|
||||
if(parity) { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 0); \
|
||||
VLDR_32(a, ed, fixedaddress); \
|
||||
} else { \
|
||||
GETED; \
|
||||
VMOVtoV(a, ed); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define GETGX(a) \
|
||||
gd = (nextop&0x38)>>3; \
|
||||
a = sse_get_reg(dyn, ninst, x1, gd)
|
||||
|
||||
|
||||
uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
|
||||
{
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop, u8;
|
||||
int32_t i32;
|
||||
uint32_t u32;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback;
|
||||
int fixedaddress;
|
||||
int v0, v1;
|
||||
int s0, s1, s2;
|
||||
int d0, d1;
|
||||
int q0;
|
||||
int parity;
|
||||
|
||||
MAYUSE(s1);
|
||||
MAYUSE(s2);
|
||||
MAYUSE(i32);
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0x10:
|
||||
INST_NAME("MOVSS Gx, Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
q0 = sse_get_reg(dyn, ninst, x1, nextop&7);
|
||||
if(v0<16)
|
||||
d0 = v0;
|
||||
else {
|
||||
d0 = fpu_get_scratch_double(dyn);
|
||||
VMOVD(d0, v0);
|
||||
}
|
||||
if(q0<16)
|
||||
d1 = q0;
|
||||
else {
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
VMOVD(d1, q0);
|
||||
}
|
||||
VMOV_32(d0*2, d1*2);
|
||||
if(v0!=d0) {
|
||||
VMOVD(v0, d0);
|
||||
}
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0);
|
||||
LDR_IMM9(x2, ed, fixedaddress); // to avoid bus errors
|
||||
VEORQ(v0, v0, v0);
|
||||
VMOVtoDx_32(v0, 0, x2);
|
||||
}
|
||||
break;
|
||||
case 0x11:
|
||||
INST_NAME("MOVSS Ex, Gx");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
q0 = sse_get_reg(dyn, ninst, x1, nextop&7);
|
||||
if(v0<16)
|
||||
d0 = v0;
|
||||
else {
|
||||
d0 = fpu_get_scratch_double(dyn);
|
||||
VMOVD(d0, v0);
|
||||
}
|
||||
if(q0<16)
|
||||
d1 = q0;
|
||||
else {
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
VMOVD(d1, q0);
|
||||
}
|
||||
VMOV_32(d1*2, d0*2);
|
||||
if(q0!=d1) {
|
||||
VMOVD(q0, d1);
|
||||
}
|
||||
} else {
|
||||
VMOVfrDx_32(x2, v0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0);
|
||||
STR_IMM9(x2, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x1E:
|
||||
INST_NAME("NOP / ENDBR32 / ENDBR64");
|
||||
nextop = F8;
|
||||
FAKEED;
|
||||
break;
|
||||
case 0x1F:
|
||||
INST_NAME("REP NOP");
|
||||
nextop = F8;
|
||||
FAKEED;
|
||||
break;
|
||||
|
||||
case 0x2A:
|
||||
INST_NAME("CVTSI2SS Gx, Ed");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
GETED;
|
||||
if(v0<16)
|
||||
d0 = v0;
|
||||
else {
|
||||
d0 = fpu_get_scratch_double(dyn);
|
||||
VMOV_64(d0, v0);
|
||||
}
|
||||
s0 = d0*2;
|
||||
VMOVtoV(s0, ed);
|
||||
VCVT_F32_S32(s0, s0);
|
||||
if(d0!=v0) {
|
||||
VMOV_64(v0, d0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x2C:
|
||||
INST_NAME("CVTTSS2SI Gd, Ex");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
v0 = sse_get_reg(dyn, ninst, x1, nextop&7);
|
||||
if(v0<16)
|
||||
d0 = v0;
|
||||
else {
|
||||
d0 = fpu_get_scratch_double(dyn);
|
||||
VMOV_64(d0, v0);
|
||||
}
|
||||
VMOV_32(s0, d0*2);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
}
|
||||
VCVT_S32_F32(s0, s0);
|
||||
VMOVfrV(gd, s0);
|
||||
break;
|
||||
case 0x2D:
|
||||
INST_NAME("CVTSS2SI Gd, Ex");
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x12);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
v0 = sse_get_reg(dyn, ninst, x1, nextop&7);
|
||||
if(v0<16)
|
||||
d0 = v0;
|
||||
else {
|
||||
d0 = fpu_get_scratch_double(dyn);
|
||||
VMOV_64(d0, v0);
|
||||
}
|
||||
VMOV_32(s0, d0*2);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
}
|
||||
VCVTR_S32_F32(s0, s0);
|
||||
VMOVfrV(gd, s0);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
|
||||
case 0x51:
|
||||
INST_NAME("SQRTSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(s1, v1);
|
||||
if(v0==v1)
|
||||
d0 = s1/2;
|
||||
else
|
||||
if(v0<16)
|
||||
d0 = v0;
|
||||
else {
|
||||
d0 = fpu_get_scratch_double(dyn);
|
||||
VMOV_64(d0, v0);
|
||||
}
|
||||
s0 = d0*2;
|
||||
VSQRT_F32(s0, s1);
|
||||
if(v0!=d0) {
|
||||
VMOV_64(v0, d0);
|
||||
}
|
||||
break;
|
||||
case 0x52:
|
||||
INST_NAME("RSQRTSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(s1, v1);
|
||||
if(v0==v1)
|
||||
d0 = s1/2;
|
||||
else
|
||||
if(v0<16)
|
||||
d0 = v0;
|
||||
else {
|
||||
d0 = fpu_get_scratch_double(dyn);
|
||||
VMOV_64(d0, v0);
|
||||
}
|
||||
s0 = d0*2;
|
||||
s2 = fpu_get_scratch_single(dyn);
|
||||
// so here: F32: Imm8 = abcd efgh that gives => aBbbbbbc defgh000 00000000 00000000
|
||||
// and want 1.0f = 0x3f800000
|
||||
// so 00111111 10000000 00000000 00000000
|
||||
// a = 0, b = 1, c = 1, d = 1, efgh=0
|
||||
// 0b01110000
|
||||
VMOV_i_32(s2, 0b01110000);
|
||||
VSQRT_F32(s0, s1);
|
||||
VDIV_F32(s0, s2, s0);
|
||||
if(v0!=d0) {
|
||||
VMOV_64(v0, d0);
|
||||
}
|
||||
break;
|
||||
case 0x53:
|
||||
INST_NAME("RCPSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(s1, v1);
|
||||
if(v0==v1)
|
||||
d0 = s1/2;
|
||||
else
|
||||
if(v0<16)
|
||||
d0 = v0;
|
||||
else {
|
||||
d0 = fpu_get_scratch_double(dyn);
|
||||
VMOV_64(d0, v0);
|
||||
}
|
||||
s0 = d0*2;
|
||||
s2 = fpu_get_scratch_single(dyn);
|
||||
VMOV_i_32(s2, 0b01110000);
|
||||
VDIV_F32(s0, s2, s1);
|
||||
if(v0!=d0) {
|
||||
VMOV_64(v0, d0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x58:
|
||||
INST_NAME("ADDSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(s1, v1);
|
||||
if(v0==v1)
|
||||
d0 = s1/2;
|
||||
else
|
||||
if(v0<16)
|
||||
d0 = v0;
|
||||
else {
|
||||
d0 = fpu_get_scratch_double(dyn);
|
||||
VMOV_64(d0, v0);
|
||||
}
|
||||
s0 = d0*2;
|
||||
VADD_F32(s0, s0, s1);
|
||||
if(v0!=d0) {
|
||||
VMOV_64(v0, d0);
|
||||
}
|
||||
break;
|
||||
case 0x59:
|
||||
INST_NAME("MULSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(s1, v1);
|
||||
if(v0==v1)
|
||||
d0 = s1/2;
|
||||
else
|
||||
if(v0<16)
|
||||
d0 = v0;
|
||||
else {
|
||||
d0 = fpu_get_scratch_double(dyn);
|
||||
VMOV_64(d0, v0);
|
||||
}
|
||||
s0 = d0*2;
|
||||
VMUL_F32(s0, s0, s1);
|
||||
if(v0!=d0) {
|
||||
VMOV_64(v0, d0);
|
||||
}
|
||||
break;
|
||||
case 0x5A:
|
||||
INST_NAME("CVTSS2SD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(s0, d0);
|
||||
VCVT_F64_F32(v0, s0);
|
||||
break;
|
||||
case 0x5B:
|
||||
INST_NAME("CVTTPS2DQ Gx, Ex");
|
||||
nextop = F8;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
|
||||
v1 = fpu_get_scratch_quad(dyn);
|
||||
VLD1Q_64(v1, ed);
|
||||
}
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VCVTQ_S32_F32(v0, v1);
|
||||
break;
|
||||
case 0x5C:
|
||||
INST_NAME("SUBSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(s1, v1);
|
||||
if(v0==v1)
|
||||
d0 = s1/2;
|
||||
else
|
||||
if(v0<16)
|
||||
d0 = v0;
|
||||
else {
|
||||
d0 = fpu_get_scratch_double(dyn);
|
||||
VMOV_64(d0, v0);
|
||||
}
|
||||
s0 = d0*2;
|
||||
VSUB_F32(s0, s0, s1);
|
||||
if(v0!=d0) {
|
||||
VMOV_64(v0, d0);
|
||||
}
|
||||
break;
|
||||
case 0x5D:
|
||||
INST_NAME("MINSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(s1, v1);
|
||||
if(v0==v1)
|
||||
d0 = s1/2;
|
||||
else
|
||||
if(v0<16)
|
||||
d0 = v0;
|
||||
else {
|
||||
d0 = fpu_get_scratch_double(dyn);
|
||||
VMOV_64(d0, v0);
|
||||
}
|
||||
s0 = d0*2;
|
||||
// MINSS: if any input is NaN, or Ex[0]<Gx[0], copy Ex[0] -> Gx[0]
|
||||
VCMP_F32(s0, s1);
|
||||
VMRS_APSR();
|
||||
VMOVcond_32(cPL, s0, s1);
|
||||
if(v0!=d0) {
|
||||
VMOV_64(v0, d0);
|
||||
}
|
||||
break;
|
||||
case 0x5E:
|
||||
INST_NAME("DIVSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(s1, v1);
|
||||
if(v0==v1)
|
||||
d0 = s1/2;
|
||||
else
|
||||
if(v0<16)
|
||||
d0 = v0;
|
||||
else {
|
||||
d0 = fpu_get_scratch_double(dyn);
|
||||
VMOV_64(d0, v0);
|
||||
}
|
||||
s0 = d0*2;
|
||||
VDIV_F32(s0, s0, s1);
|
||||
if(v0!=d0) {
|
||||
VMOV_64(v0, d0);
|
||||
}
|
||||
break;
|
||||
case 0x5F:
|
||||
INST_NAME("MAXSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(s1, v1);
|
||||
if(v0==v1)
|
||||
d0 = s1/2;
|
||||
else
|
||||
if(v0<16)
|
||||
d0 = v0;
|
||||
else {
|
||||
d0 = fpu_get_scratch_double(dyn);
|
||||
VMOV_64(d0, v0);
|
||||
}
|
||||
s0 = d0*2;
|
||||
// MAXSS: if any input is NaN, or Ex[0]>Gx[0], copy Ex[0] -> Gx[0]
|
||||
VCMP_F32(s1, s0);
|
||||
VMRS_APSR();
|
||||
VMOVcond_32(cPL, s0, s1);
|
||||
if(v0!=d0) {
|
||||
VMOV_64(v0, d0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x6F:
|
||||
INST_NAME("MOVDQU Gx,Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VMOVQ(v0, v1);
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-12, 0);
|
||||
LDR_IMM9(x2, ed, fixedaddress+0);
|
||||
LDR_IMM9(x3, ed, fixedaddress+4);
|
||||
VMOVtoV_D(v0, x2, x3);
|
||||
LDR_IMM9(x2, ed, fixedaddress+8);
|
||||
LDR_IMM9(x3, ed, fixedaddress+12);
|
||||
VMOVtoV_D(v0+1, x2, x3);
|
||||
}
|
||||
break;
|
||||
case 0x70:
|
||||
INST_NAME("PSHUFHW Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
|
||||
v1 = fpu_get_scratch_quad(dyn);
|
||||
VLD1Q_64(v1, ed);
|
||||
}
|
||||
u8 = F8;
|
||||
// only high part need to be suffled. VTBL only handle 8bits value, so the 16bits suffles need to be changed in 8bits
|
||||
u32 = 0;
|
||||
for (int i=0; i<2; ++i) {
|
||||
u32 |= (((u8>>(i*2))&3)*2+0)<<(i*16+0);
|
||||
u32 |= (((u8>>(i*2))&3)*2+1)<<(i*16+8);
|
||||
}
|
||||
MOV32(x2, u32);
|
||||
u32 = 0;
|
||||
for (int i=2; i<4; ++i) {
|
||||
u32 |= (((u8>>(i*2))&3)*2+0)<<((i-2)*16+0);
|
||||
u32 |= (((u8>>(i*2))&3)*2+1)<<((i-2)*16+8);
|
||||
}
|
||||
MOV32(x3, u32);
|
||||
d0 = fpu_get_scratch_double(dyn);
|
||||
VMOVtoV_D(d0, x2, x3);
|
||||
VTBL1_8(v0+1, v1+1, d0);
|
||||
if(v0!=v1) {
|
||||
VMOVD(v0, v1);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case 0x7E:
|
||||
INST_NAME("MOVQ Gx, Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VMOVD(v0, v1);
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
|
||||
VLD1_64(v0, ed);
|
||||
}
|
||||
VEOR(v0+1, v0+1, v0+1);
|
||||
break;
|
||||
case 0x7F:
|
||||
INST_NAME("MOVDQU Ex,Gx");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, nextop&7);
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-12, 0);
|
||||
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);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xBC:
|
||||
INST_NAME("TZCNT Gd, Ed");
|
||||
SETFLAGS(X_CF|X_ZF, SF_SET);
|
||||
nextop = F8;
|
||||
GETED;
|
||||
GETGD;
|
||||
TSTS_REG_LSL_IMM5(ed, ed, 0);
|
||||
RBIT(x1, ed); // reverse
|
||||
CLZ(gd, x1); // x2 gets leading 0 == TZCNT
|
||||
MOVW_COND(cEQ, x1, 1);
|
||||
MOVW_COND(cNE, x1, 0);
|
||||
STR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_CF]));
|
||||
RSB_IMM8(x1, x1, 1);
|
||||
STR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
MOVW(x1, d_none);
|
||||
STR_IMM9(x1, xEmu, offsetof(x86emu_t, df));
|
||||
break;
|
||||
|
||||
case 0xC2:
|
||||
INST_NAME("CMPSS Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(s1, v1);
|
||||
if(v0==v1)
|
||||
d0 = s1/2;
|
||||
else
|
||||
if(v0<16)
|
||||
d0 = v0;
|
||||
else {
|
||||
d0 = fpu_get_scratch_double(dyn);
|
||||
VMOV_64(d0, v0);
|
||||
}
|
||||
s0 = d0*2;
|
||||
VCMP_F32(s0, s1);
|
||||
VMRS_APSR();
|
||||
MOVW(x2, 0);
|
||||
u8 = F8;
|
||||
switch(u8&7) {
|
||||
case 0: MVN_COND_REG_LSL_IMM5(cEQ, x2, x2, 0); break; // Equal
|
||||
case 1: MVN_COND_REG_LSL_IMM5(cCC, x2, x2, 0); break; // Less than
|
||||
case 2: MVN_COND_REG_LSL_IMM5(cLS, x2, x2, 0); break; // Less or equal
|
||||
case 3: MVN_COND_REG_LSL_IMM5(cVS, x2, x2, 0); break; // NaN
|
||||
case 4: MVN_COND_REG_LSL_IMM5(cNE, x2, x2, 0); break; // Not Equal (or unordered on ARM, not on X86...)
|
||||
case 5: MVN_COND_REG_LSL_IMM5(cPL, x2, x2, 0); break; // Greater or equal or unordered
|
||||
case 6: MVN_COND_REG_LSL_IMM5(cHI, x2, x2, 0); break; // Greater or unordered
|
||||
case 7: MVN_COND_REG_LSL_IMM5(cVC, x2, x2, 0); break; // not NaN
|
||||
}
|
||||
VMOVtoDx_32(v0, 0, x2);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
Executable
+308
@@ -0,0 +1,308 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86context.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x86emu_private.h"
|
||||
#include "tools/bridge_private.h"
|
||||
#include "x86run.h"
|
||||
#include "x86emu.h"
|
||||
#include "box86stack.h"
|
||||
#include "callback.h"
|
||||
#include "emu/x86run_private.h"
|
||||
#include "emu/x87emu_private.h"
|
||||
#include "x86trace.h"
|
||||
#include "dynarec_arm.h"
|
||||
#include "dynarec_arm_private.h"
|
||||
#include "dynarec_arm_functions.h"
|
||||
|
||||
void arm_popf(x86emu_t* emu, uint32_t f)
|
||||
{
|
||||
emu->packed_eflags.x32 = (f & 0x3F7FD7) | 0x2; // mask off res2 and res3 and on res1
|
||||
UnpackFlags(emu);
|
||||
RESET_FLAGS(emu);
|
||||
}
|
||||
|
||||
void arm_fstp(x86emu_t* emu, void* p)
|
||||
{
|
||||
if(ST0.ll!=STld(0).ref)
|
||||
D2LD(&ST0.d, p);
|
||||
else
|
||||
memcpy(p, &STld(0).ld, 10);
|
||||
}
|
||||
|
||||
void arm_print_armreg(x86emu_t* emu, uintptr_t reg, uintptr_t n)
|
||||
{
|
||||
dynarec_log(LOG_DEBUG, "R%d=0x%x (%d)\n", n, reg, reg);
|
||||
}
|
||||
|
||||
void arm_f2xm1(x86emu_t* emu)
|
||||
{
|
||||
ST0.d = exp2(ST0.d) - 1.0;
|
||||
}
|
||||
void arm_fyl2x(x86emu_t* emu)
|
||||
{
|
||||
ST(1).d = log2(ST0.d)*ST(1).d;
|
||||
}
|
||||
void arm_ftan(x86emu_t* emu)
|
||||
{
|
||||
ST0.d = tan(ST0.d);
|
||||
}
|
||||
void arm_fpatan(x86emu_t* emu)
|
||||
{
|
||||
ST1.d = atan2(ST1.d, ST0.d);
|
||||
}
|
||||
void arm_fxtract(x86emu_t* emu)
|
||||
{
|
||||
int32_t tmp32s = (ST1.ll&0x7ff0000000000000LL)>>52;
|
||||
tmp32s -= 1023;
|
||||
ST1.d /= exp2(tmp32s);
|
||||
ST0.d = tmp32s;
|
||||
}
|
||||
void arm_fprem(x86emu_t* emu)
|
||||
{
|
||||
int32_t tmp32s = ST0.d / ST1.d;
|
||||
ST0.d -= ST1.d * tmp32s;
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
emu->sw.f.F87_C0 = (tmp32s&1);
|
||||
emu->sw.f.F87_C3 = ((tmp32s>>1)&1);
|
||||
emu->sw.f.F87_C1 = ((tmp32s>>2)&1);
|
||||
}
|
||||
void arm_fyl2xp1(x86emu_t* emu)
|
||||
{
|
||||
ST(1).d = log2(ST0.d + 1.0)*ST(1).d;
|
||||
}
|
||||
void arm_fsincos(x86emu_t* emu)
|
||||
{
|
||||
sincos(ST1.d, &ST1.d, &ST0.d);
|
||||
}
|
||||
void arm_frndint(x86emu_t* emu)
|
||||
{
|
||||
ST0.d = fpu_round(emu, ST0.d);
|
||||
}
|
||||
void arm_fscale(x86emu_t* emu)
|
||||
{
|
||||
ST0.d *= exp2(trunc(ST1.d));
|
||||
}
|
||||
void arm_fsin(x86emu_t* emu)
|
||||
{
|
||||
ST0.d = sin(ST0.d);
|
||||
}
|
||||
void arm_fcos(x86emu_t* emu)
|
||||
{
|
||||
ST0.d = cos(ST0.d);
|
||||
}
|
||||
|
||||
void arm_fbld(x86emu_t* emu, uint8_t* ed)
|
||||
{
|
||||
fpu_fbld(emu, ed);
|
||||
}
|
||||
|
||||
void arm_fild64(x86emu_t* emu, int64_t* ed)
|
||||
{
|
||||
ST0.d = *ed;
|
||||
STll(0).ll = *ed;
|
||||
STll(0).ref = ST0.ll;
|
||||
}
|
||||
|
||||
void arm_fbstp(x86emu_t* emu, uint8_t* ed)
|
||||
{
|
||||
fpu_fbst(emu, ed);
|
||||
}
|
||||
|
||||
void arm_fistp64(x86emu_t* emu, int64_t* ed)
|
||||
{
|
||||
if(STll(0).ref==ST(0).ll) {
|
||||
*ed = STll(0).ll;
|
||||
} else {
|
||||
if(isgreater(ST0.d, (double)(int64_t)0x7fffffffffffffffLL) || isless(ST0.d, (double)(int64_t)0x8000000000000000LL))
|
||||
*ed = 0x8000000000000000LL;
|
||||
else
|
||||
*ed = (int64_t)ST0.d;
|
||||
}
|
||||
}
|
||||
|
||||
void arm_fld(x86emu_t* emu, uint8_t* ed)
|
||||
{
|
||||
memcpy(&STld(0).ld, ed, 10);
|
||||
LD2D(&STld(0), &ST(0).d);
|
||||
STld(0).ref = ST0.ll;
|
||||
}
|
||||
|
||||
void arm_ud(x86emu_t* emu)
|
||||
{
|
||||
kill(getpid(), SIGILL);
|
||||
}
|
||||
|
||||
void arm_fxsave(x86emu_t* emu, uint8_t* ed)
|
||||
{
|
||||
// should save flags & all
|
||||
// copy MMX regs...
|
||||
for(int i=0; i<8; ++i)
|
||||
memcpy(ed+32+i*16, &emu->mmx[0], sizeof(emu->mmx[0]));
|
||||
// copy SSE regs
|
||||
memcpy(ed+160, &emu->xmm[0], sizeof(emu->xmm));
|
||||
// put also FPU regs in a reserved area...
|
||||
for(int i=0; i<8; ++i)
|
||||
memcpy(ed+416+i*8, &emu->fpu[0], sizeof(emu->fpu[0]));
|
||||
}
|
||||
|
||||
void arm_fxrstor(x86emu_t* emu, uint8_t* ed)
|
||||
{
|
||||
// should restore flags & all
|
||||
// copy back MMX regs...
|
||||
for(int i=0; i<8; ++i)
|
||||
memcpy(&emu->mmx[i], ed+32+i*16, sizeof(emu->mmx[0]));
|
||||
// copy SSE regs
|
||||
memcpy(&emu->xmm[0], ed+160/4, sizeof(emu->xmm));
|
||||
for(int i=0; i<8; ++i)
|
||||
memcpy(&emu->fpu[0], ed+416+i*8, sizeof(emu->fpu[0]));
|
||||
}
|
||||
|
||||
void arm_fsave(x86emu_t* emu, uint8_t* ed)
|
||||
{
|
||||
fpu_savenv(emu, (char*)ed, 0);
|
||||
|
||||
uint8_t* p = ed;
|
||||
p += 28;
|
||||
for (int i=0; i<8; ++i) {
|
||||
#ifdef USE_FLOAT
|
||||
d = ST(i).f;
|
||||
LD2D(p, &d);
|
||||
#else
|
||||
LD2D(p, &ST(i).d);
|
||||
#endif
|
||||
p+=10;
|
||||
}
|
||||
}
|
||||
void arm_frstor(x86emu_t* emu, uint8_t* ed)
|
||||
{
|
||||
fpu_loadenv(emu, (char*)ed, 0);
|
||||
|
||||
uint8_t* p = ed;
|
||||
p += 28;
|
||||
for (int i=0; i<8; ++i) {
|
||||
#ifdef USE_FLOAT
|
||||
D2LD(&d, p);
|
||||
ST(i).f = d;
|
||||
#else
|
||||
D2LD(&ST(i).d, p);
|
||||
#endif
|
||||
p+=10;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Get a FPU single scratch reg
|
||||
int fpu_get_scratch_single(dynarec_arm_t* dyn)
|
||||
{
|
||||
return dyn->fpu_scratch++; // return an Sx
|
||||
}
|
||||
// Get a FPU double scratch reg
|
||||
int fpu_get_scratch_double(dynarec_arm_t* dyn)
|
||||
{
|
||||
int i = (dyn->fpu_scratch+1)&(~1);
|
||||
dyn->fpu_scratch = i+2;
|
||||
return i/2; // return a Dx
|
||||
}
|
||||
// Get a FPU quad scratch reg
|
||||
int fpu_get_scratch_quad(dynarec_arm_t* dyn)
|
||||
{
|
||||
int i = (dyn->fpu_scratch+3)&(~3);
|
||||
dyn->fpu_scratch = i+4;
|
||||
return i/2; // Return a Dx, not a Qx
|
||||
}
|
||||
// Reset scratch regs counter
|
||||
void fpu_reset_scratch(dynarec_arm_t* dyn)
|
||||
{
|
||||
dyn->fpu_scratch = 0;
|
||||
}
|
||||
#define FPUFIRST 8
|
||||
// Get a FPU double reg
|
||||
int fpu_get_reg_double(dynarec_arm_t* dyn)
|
||||
{
|
||||
// TODO: check upper limit?
|
||||
int i=0;
|
||||
while (dyn->fpuused[i]) ++i;
|
||||
dyn->fpuused[i] = 1;
|
||||
return i+FPUFIRST; // return a Dx
|
||||
}
|
||||
// Free a FPU double reg
|
||||
void fpu_free_reg_double(dynarec_arm_t* dyn, int reg)
|
||||
{
|
||||
// TODO: check upper limit?
|
||||
int i=reg-FPUFIRST;
|
||||
dyn->fpuused[i] = 0;
|
||||
}
|
||||
// Get a FPU quad reg
|
||||
int fpu_get_reg_quad(dynarec_arm_t* dyn)
|
||||
{
|
||||
int i=0;
|
||||
while (dyn->fpuused[i] || dyn->fpuused[i+1]) i+=2;
|
||||
dyn->fpuused[i] = dyn->fpuused[i+1] = 1;
|
||||
return i+FPUFIRST; // Return a Dx, not a Qx
|
||||
}
|
||||
// Free a FPU quad reg
|
||||
void fpu_free_reg_quad(dynarec_arm_t* dyn, int reg)
|
||||
{
|
||||
int i=reg-FPUFIRST;
|
||||
dyn->fpuused[i] = dyn->fpuused[i+1] = 0;
|
||||
}
|
||||
// Reset fpu regs counter
|
||||
void fpu_reset_reg(dynarec_arm_t* dyn)
|
||||
{
|
||||
dyn->fpu_reg = 0;
|
||||
for (int i=0; i<24; ++i)
|
||||
dyn->fpuused[i]=0;
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
#define F8 *(uint8_t*)(addr++)
|
||||
#define F32 *(uint32_t*)(addr+=4, addr-4)
|
||||
|
||||
uint32_t tested = (1<<parity)-1;
|
||||
if((nextop&0xC0)==0xC0)
|
||||
return 0; // direct register, no parity...
|
||||
if(!(nextop&0xC0)) {
|
||||
if((nextop&7)==4) {
|
||||
uint8_t sib = F8;
|
||||
int sib_reg = (sib>>3)&7;
|
||||
if((sib&0x7)==5) {
|
||||
uint32_t tmp = F32;
|
||||
if (sib_reg!=4) {
|
||||
// if XXXXXX+reg<<N then check parity of XXXXX and N should be enough
|
||||
return ((tmp&tested)==0 && (sib>>6)>=parity)?1:0;
|
||||
} else {
|
||||
// just a constant...
|
||||
return (tmp&tested)?0:1;
|
||||
}
|
||||
} else {
|
||||
if(sib_reg==4)
|
||||
return 0; // simple [reg]
|
||||
// don't try [reg1 + reg2<<N], unless reg1 is ESP
|
||||
return ((sib&0x7)==4 && (sib>>6)>=parity)?1:0;
|
||||
}
|
||||
} else if((nextop&7)==5) {
|
||||
uint32_t tmp = F32;
|
||||
return (tmp&tested)?0:1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
return 0; //Form [reg1 + reg2<<N + XXXXXX]
|
||||
}
|
||||
#undef F8
|
||||
#undef F32
|
||||
}
|
||||
Executable
+57
@@ -0,0 +1,57 @@
|
||||
#ifndef __DYNAREC_ARM_FUNCTIONS_H__
|
||||
#define __DYNAREC_ARM_FUNCTIONS_H__
|
||||
|
||||
typedef struct x86emu_s x86emu_t;
|
||||
|
||||
void arm_popf(x86emu_t* emu, uint32_t f);
|
||||
void arm_fstp(x86emu_t* emu, void* p);
|
||||
|
||||
void arm_print_armreg(x86emu_t* emu, uintptr_t reg, uintptr_t n);
|
||||
|
||||
void arm_f2xm1(x86emu_t* emu);
|
||||
void arm_fyl2x(x86emu_t* emu);
|
||||
void arm_ftan(x86emu_t* emu);
|
||||
void arm_fpatan(x86emu_t* emu);
|
||||
void arm_fxtract(x86emu_t* emu);
|
||||
void arm_fprem(x86emu_t* emu);
|
||||
void arm_fyl2xp1(x86emu_t* emu);
|
||||
void arm_fsincos(x86emu_t* emu);
|
||||
void arm_frndint(x86emu_t* emu);
|
||||
void arm_fscale(x86emu_t* emu);
|
||||
void arm_fsin(x86emu_t* emu);
|
||||
void arm_fcos(x86emu_t* emu);
|
||||
void arm_fbld(x86emu_t* emu, uint8_t* ed);
|
||||
void arm_fild64(x86emu_t* emu, int64_t* ed);
|
||||
void arm_fbstp(x86emu_t* emu, uint8_t* ed);
|
||||
void arm_fistp64(x86emu_t* emu, int64_t* ed);
|
||||
void arm_fld(x86emu_t* emu, uint8_t* ed);
|
||||
void arm_fxsave(x86emu_t* emu, uint8_t* ed);
|
||||
void arm_fxrstor(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_ud(x86emu_t* emu);
|
||||
|
||||
// Get an FPU single scratch reg
|
||||
int fpu_get_scratch_single(dynarec_arm_t* dyn);
|
||||
// Get an FPU double scratch reg
|
||||
int fpu_get_scratch_double(dynarec_arm_t* dyn);
|
||||
// Get an FPU quad scratch reg
|
||||
int fpu_get_scratch_quad(dynarec_arm_t* dyn);
|
||||
// Reset scratch regs counter
|
||||
void fpu_reset_scratch(dynarec_arm_t* dyn);
|
||||
// Get an FPU double reg
|
||||
int fpu_get_reg_double(dynarec_arm_t* dyn);
|
||||
// Free a FPU double reg
|
||||
void fpu_free_reg_double(dynarec_arm_t* dyn, int reg);
|
||||
// Get an FPU quad reg
|
||||
int fpu_get_reg_quad(dynarec_arm_t* dyn);
|
||||
// Free a FPU quad reg
|
||||
void fpu_free_reg_quad(dynarec_arm_t* dyn, int reg);
|
||||
// Reset fpu regs counter
|
||||
void fpu_reset_reg(dynarec_arm_t* dyn);
|
||||
|
||||
// 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);
|
||||
|
||||
#endif //__DYNAREC_ARM_FUNCTIONS_H__
|
||||
Executable
+1147
File diff suppressed because it is too large.
Load diff
Executable
+629
@@ -0,0 +1,629 @@
|
||||
#ifndef __DYNAREC_ARM_HELPER_H__
|
||||
#define __DYNAREC_ARM_HELPER_H__
|
||||
|
||||
#if STEP == 0
|
||||
#include "dynarec_arm_pass0.h"
|
||||
#elif STEP == 1
|
||||
#include "dynarec_arm_pass1.h"
|
||||
#elif STEP == 2
|
||||
#include "dynarec_arm_pass2.h"
|
||||
#elif STEP == 3
|
||||
#include "dynarec_arm_pass3.h"
|
||||
#endif
|
||||
|
||||
#include "debug.h"
|
||||
#include "arm_emitter.h"
|
||||
#include "../emu/x86primop.h"
|
||||
|
||||
#define F8 *(uint8_t*)(addr++)
|
||||
#define F8S *(int8_t*)(addr++)
|
||||
#define F16 *(uint16_t*)(addr+=2, addr-2)
|
||||
#define F16S *(int16_t*)(addr+=2, addr-2)
|
||||
#define F32 *(uint32_t*)(addr+=4, addr-4)
|
||||
#define F32S *(int32_t*)(addr+=4, addr-4)
|
||||
#define PK(a) *(uint8_t*)(addr+a)
|
||||
#define PK32(a) *(uint32_t*)(addr+a)
|
||||
#define PK16(a) *(uint16_t*)(addr+a)
|
||||
#define PKip(a) *(uint8_t*)(ip+a)
|
||||
|
||||
// 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
|
||||
#define GETED if((nextop&0xC0)==0xC0) { \
|
||||
ed = xEAX+(nextop&7); \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 4095, 0); \
|
||||
LDR_IMM9(x1, wback, fixedaddress); \
|
||||
ed = x1; \
|
||||
}
|
||||
//GETEDH can use hint for ed, and r1 or r2 for wback (depending on hint). wback is 0 if ed is xEAX..xEDI
|
||||
#define GETEDH(hint) if((nextop&0xC0)==0xC0) { \
|
||||
ed = xEAX+(nextop&7); \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, (hint==x2)?x1:x2, &fixedaddress, 4095, 0); \
|
||||
LDR_IMM9(hint, wback, fixedaddress); \
|
||||
ed = hint; \
|
||||
}
|
||||
//GETEDW can use hint for wback and ret for ed. wback is 0 if ed is xEAX..xEDI
|
||||
#define GETEDW(hint, ret) if((nextop&0xC0)==0xC0) { \
|
||||
ed = xEAX+(nextop&7); \
|
||||
MOV_REG(ret, ed); \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, hint, &fixedaddress, 4095, 0); \
|
||||
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);}
|
||||
//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); \
|
||||
LDR_REG_LSL_IMM5(x1, wback, O, 0); \
|
||||
ed = x1; \
|
||||
}
|
||||
#define WBACKO(O) if(wback) {STR_REG_LSL_IMM5(ed, wback, O, 0);}
|
||||
//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;
|
||||
//GETEWW will use i for ed, and can use w for wback.
|
||||
#define GETEWW(w, i) if((nextop&0xC0)==0xC0) { \
|
||||
wback = xEAX+(nextop&7);\
|
||||
UXTH(i, wback, 0); \
|
||||
ed = i; \
|
||||
wb1 = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, w, &fixedaddress, 255, 0); \
|
||||
LDRH_IMM8(i, wback, fixedaddress); \
|
||||
ed = i; \
|
||||
wb1 = 1; \
|
||||
}
|
||||
//GETEW will use i for ed, and can use r3 for wback.
|
||||
#define GETEW(i) if((nextop&0xC0)==0xC0) { \
|
||||
wback = xEAX+(nextop&7);\
|
||||
UXTH(i, wback, 0); \
|
||||
ed = i; \
|
||||
wb1 = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0); \
|
||||
LDRH_IMM8(i, wback, fixedaddress); \
|
||||
ed = i; \
|
||||
wb1 = 1; \
|
||||
}
|
||||
//GETSEW will use i for ed, and can use r3 for wback. This is the Signed version
|
||||
#define GETSEW(i) if((nextop&0xC0)==0xC0) { \
|
||||
wback = xEAX+(nextop&7);\
|
||||
SXTH(i, wback, 0); \
|
||||
ed = i; \
|
||||
wb1 = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0); \
|
||||
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);}
|
||||
// Write w back to original register / memory
|
||||
#define EWBACKW(w) if(wb1) {STRH_IMM8(w, wback, fixedaddress);} 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.
|
||||
#define GETEB(i) if((nextop&0xC0)==0xC0) { \
|
||||
wback = (nextop&7); \
|
||||
wb2 = (wback>>2); \
|
||||
wback = xEAX+(wback&3); \
|
||||
UXTB(i, wback, wb2); \
|
||||
wb1 = 0; \
|
||||
ed = i; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 4095, 0); \
|
||||
LDRB_IMM9(i, wback, fixedaddress); \
|
||||
wb1 = 1; \
|
||||
ed = i; \
|
||||
}
|
||||
//GETSEB sign extend EB, will use i for ed, and can use r3 for wback.
|
||||
#define GETSEB(i) if((nextop&0xC0)==0xC0) { \
|
||||
wback = (nextop&7); \
|
||||
wb2 = (wback>>2); \
|
||||
wback = xEAX+(wback&3); \
|
||||
SXTB(i, wback, wb2); \
|
||||
wb1 = 0; \
|
||||
ed = i; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0); \
|
||||
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);}
|
||||
//GETGB will use i for gd
|
||||
#define GETGB(i) gd = (nextop&0x38)>>3; \
|
||||
gb2 = ((gd&4)>>2); \
|
||||
gb1 = xEAX+(gd&3); \
|
||||
gd = i; \
|
||||
UXTB(gd, gb1, gb2);
|
||||
//GETSGB signe extend GB, will use i for gd
|
||||
#define GETSGB(i) gd = (nextop&0x38)>>3; \
|
||||
gb2 = ((gd&4)>>2); \
|
||||
gb1 = xEAX+(gd&3); \
|
||||
gd = i; \
|
||||
SXTB(gd, gb1, gb2);
|
||||
// Write gb (gd) back to original register / memory
|
||||
#define GBBACK BFI(gb1, gd, gb2*8, 8);
|
||||
|
||||
// Get Direction with size Z and based of F_DF flag, on register r ready for LDR/STR fetching
|
||||
#define GETDIR(r, A) \
|
||||
LDR_IMM9(r, xEmu, offsetof(x86emu_t, flags[F_DF])); \
|
||||
CMPS_IMM8(r, 1); \
|
||||
MOVW(r, A); \
|
||||
RSB_COND_IMM8(cEQ, r, r, 0)
|
||||
|
||||
// CALL will use x12 for the call address. Return value can be put in ret (unless ret is -1)
|
||||
// R0 will not be pushed/popd if ret is -2
|
||||
#define CALL(F, ret, M) call_c(dyn, ninst, F, x12, ret, M)
|
||||
// CALL_ will use x3 for the call address. Return value can be put in ret (unless ret is -1)
|
||||
// R0 will not be pushed/popd if ret is -2
|
||||
#define CALL_(F, ret, M) call_c(dyn, ninst, F, x3, ret, M)
|
||||
#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))
|
||||
|
||||
// Branch to MARK if cond (use i32)
|
||||
#define B_MARK(cond) \
|
||||
i32 = GETMARK-(dyn->arm_size+8); \
|
||||
Bcond(cond, i32)
|
||||
// Branch to MARK2 if cond (use i32)
|
||||
#define B_MARK2(cond) \
|
||||
i32 = GETMARK2-(dyn->arm_size+8); \
|
||||
Bcond(cond, i32)
|
||||
// Branch to MARK3 if cond (use i32)
|
||||
#define B_MARK3(cond) \
|
||||
i32 = GETMARK3-(dyn->arm_size+8); \
|
||||
Bcond(cond, i32)
|
||||
// Branch to next instruction if cond (use i32)
|
||||
#define B_NEXT(cond) \
|
||||
i32 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->arm_size+8)):0; \
|
||||
Bcond(cond, i32)
|
||||
// Branch to MARKSEG if cond (use i32)
|
||||
#define B_MARKSEG(cond) \
|
||||
i32 = GETMARKSEG-(dyn->arm_size+8); \
|
||||
Bcond(cond, i32)
|
||||
|
||||
#define IFX(A) if(dyn->insts && (dyn->insts[ninst].x86.need_flags&(A)))
|
||||
#define IFXX(A) if(dyn->insts && (dyn->insts[ninst].x86.need_flags==(A)))
|
||||
#define IFX2X(A, B) if(dyn->insts && (dyn->insts[ninst].x86.need_flags==(A) || dyn->insts[ninst].x86.need_flags==(B) || dyn->insts[ninst].x86.need_flags==((A)|(B))))
|
||||
|
||||
// Generate FCOM with s1 and s2 scratch regs (the VCMP is already done)
|
||||
#define FCOM(s1, s2) \
|
||||
VMRS_APSR(); /* 0b0100011100000000 */ \
|
||||
LDRH_IMM8(s2, xEmu, offsetof(x86emu_t, sw)); /*offset is 8bits right?*/ \
|
||||
MOVW(s1, 0b0100011100000000); \
|
||||
BIC_REG_LSL_IMM5(s2, s2, s1, 0); \
|
||||
MOVW_COND(cVS, s1, 0b0100010100000000); /* unordered */ \
|
||||
MOVW_COND(cEQ, s1, 0b0100000000000000); /* zero */ \
|
||||
MOVW_COND(cGT, s1, 0b0000000000000000); /* greater than */ \
|
||||
MOVW_COND(cLO, s1, 0b0000000100000000); /* less than */ \
|
||||
ORR_REG_LSL_IMM5(s2, s2, s1, 0); \
|
||||
STRH_IMM8(s2, xEmu, offsetof(x86emu_t, sw))
|
||||
|
||||
// Generate FCOMI with s1 and s2 scratch regs (the VCMP is already done)
|
||||
#define FCOMI(s1, s2) \
|
||||
VMRS_APSR(); /* 0b111 */ \
|
||||
XOR_REG_LSL_IMM5(s2, s2, s2, 0); \
|
||||
MOVW_COND(cVS, s1, 0b111); /* unordered */ \
|
||||
MOVW_COND(cEQ, s1, 0b100); /* zero */ \
|
||||
MOVW_COND(cGT, s1, 0b000); /* greater than */ \
|
||||
MOVW_COND(cLO, s1, 0b001); /* less than */ \
|
||||
IFX(X_CF|X_PEND) { \
|
||||
UBFX(s2, s1, 0, 1); \
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, flags[F_CF]));\
|
||||
} \
|
||||
IFX(X_PF|X_PEND) { \
|
||||
UBFX(s2, s1, 1, 1); \
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, flags[F_PF]));\
|
||||
} \
|
||||
IFX(X_ZF|X_PEND) { \
|
||||
UBFX(s2, s1, 2, 1); \
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, flags[F_ZF]));\
|
||||
} \
|
||||
MOVW(s2, d_none); \
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, df)); \
|
||||
IFX(X_OF|X_PEND) { \
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, flags[F_OF]));\
|
||||
} \
|
||||
IFX(X_AF|X_PEND) { \
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, flags[F_AF]));\
|
||||
} \
|
||||
IFX(X_SF|X_PEND) { \
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, flags[F_SF]));\
|
||||
} \
|
||||
|
||||
|
||||
|
||||
#ifndef READFLAGS
|
||||
#define READFLAGS(A) \
|
||||
if(dyn->state_flags!=SF_SET) { \
|
||||
if(dyn->state_flags!=SF_PENDING) { \
|
||||
LDR_IMM9(x3, xEmu, offsetof(x86emu_t, df)); \
|
||||
TSTS_REG_LSL_IMM5(x3, x3, 0); \
|
||||
i32 = (GETMARKF)-(dyn->arm_size+8); \
|
||||
Bcond(cEQ, i32); \
|
||||
} \
|
||||
CALL_(UpdateFlags, -1, 0); \
|
||||
MARKF; \
|
||||
dyn->state_flags = SF_SET; \
|
||||
}
|
||||
#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))); \
|
||||
dyn->state_flags = (B==SF_SUBSET)?SF_SET:B
|
||||
#endif
|
||||
#ifndef JUMP
|
||||
#define JUMP(A)
|
||||
#endif
|
||||
#ifndef BARRIER
|
||||
#define BARRIER(A)
|
||||
#endif
|
||||
#ifndef BARRIER_NEXT
|
||||
#define BARRIER_NEXT(A)
|
||||
#endif
|
||||
#define UFLAG_OP1(A) if(dyn->insts && dyn->insts[ninst].x86.need_flags) {STR_IMM9(A, 0, offsetof(x86emu_t, op1));}
|
||||
#define UFLAG_OP2(A) if(dyn->insts && dyn->insts[ninst].x86.need_flags) {STR_IMM9(A, 0, offsetof(x86emu_t, op2));}
|
||||
#define UFLAG_OP12(A1, A2) if(dyn->insts && dyn->insts[ninst].x86.need_flags) {STR_IMM9(A1, 0, offsetof(x86emu_t, op1));STR_IMM9(A2, 0, offsetof(x86emu_t, op2));}
|
||||
#define UFLAG_RES(A) if(dyn->insts && dyn->insts[ninst].x86.need_flags) {STR_IMM9(A, 0, offsetof(x86emu_t, res));}
|
||||
#define UFLAG_DF(r, A) if(dyn->insts && dyn->insts[ninst].x86.need_flags) {MOVW(r, A); STR_IMM9(r, 0, offsetof(x86emu_t, df));}
|
||||
#define UFLAG_IF if(dyn->insts && dyn->insts[ninst].x86.need_flags)
|
||||
#ifndef DEFAULT
|
||||
#define DEFAULT *ok = -1; BARRIER(2)
|
||||
#endif
|
||||
#ifndef NEW_BARRIER_INST
|
||||
#define NEW_BARRIER_INST
|
||||
#endif
|
||||
|
||||
// Emit the LOCK mutex (x1, x2 and x3 are lost)
|
||||
#define LOCK emit_lock(dyn, addr, ninst)
|
||||
// Emit the UNLOCK mutex (x1, x2 and x3 are lost)
|
||||
#define UNLOCK emit_unlock(dyn, addr, ninst)
|
||||
|
||||
|
||||
void arm_epilog();
|
||||
void* arm_linker(x86emu_t* emu, void** table, uintptr_t addr);
|
||||
|
||||
#ifndef STEPNAME
|
||||
#define STEPNAME3(N,M) N##M
|
||||
#define STEPNAME2(N,M) STEPNAME3(N,M)
|
||||
#define STEPNAME(N) STEPNAME2(N, STEP)
|
||||
#endif
|
||||
|
||||
#define arm_pass STEPNAME(arm_pass)
|
||||
|
||||
#define dynarec00 STEPNAME(dynarec00)
|
||||
#define dynarec0F STEPNAME(dynarec0F)
|
||||
#define dynarecFS STEPNAME(dynarecFS)
|
||||
#define dynarecGS STEPNAME(dynarecGS)
|
||||
#define dynarec66 STEPNAME(dynarec66)
|
||||
#define dynarec67 STEPNAME(dynarec67)
|
||||
#define dynarecD8 STEPNAME(dynarecD8)
|
||||
#define dynarecD9 STEPNAME(dynarecD9)
|
||||
#define dynarecDA STEPNAME(dynarecDA)
|
||||
#define dynarecDB STEPNAME(dynarecDB)
|
||||
#define dynarecDC STEPNAME(dynarecDC)
|
||||
#define dynarecDD STEPNAME(dynarecDD)
|
||||
#define dynarecDE STEPNAME(dynarecDE)
|
||||
#define dynarecDF STEPNAME(dynarecDF)
|
||||
#define dynarecF0 STEPNAME(dynarecF0)
|
||||
#define dynarec660F STEPNAME(dynarec660F)
|
||||
#define dynarecF20F STEPNAME(dynarecF20F)
|
||||
#define dynarecF30F STEPNAME(dynarecF30F)
|
||||
|
||||
#define geted STEPNAME(geted_)
|
||||
#define fakeed STEPNAME(fakeed_)
|
||||
#define jump_to_epilog STEPNAME(jump_to_epilog_)
|
||||
#define jump_to_linker STEPNAME(jump_to_linker_)
|
||||
#define ret_to_epilog STEPNAME(ret_to_epilog_)
|
||||
#define retn_to_epilog STEPNAME(retn_to_epilog_)
|
||||
#define iret_to_epilog STEPNAME(iret_to_epilog_)
|
||||
#define call_c STEPNAME(call_c_)
|
||||
#define grab_fsdata STEPNAME(grab_fsdata_)
|
||||
#define grab_tlsdata STEPNAME(grab_tlsdata_)
|
||||
#define isNativeCall STEPNAME(isNativeCall_)
|
||||
#define emit_lock STEPNAME(emit_lock)
|
||||
#define emit_unlock STEPNAME(emit_unlock)
|
||||
#define emit_cmp8 STEPNAME(emit_cmp8)
|
||||
#define emit_cmp16 STEPNAME(emit_cmp16)
|
||||
#define emit_cmp32 STEPNAME(emit_cmp32)
|
||||
#define emit_cmp8_0 STEPNAME(emit_cmp8_0)
|
||||
#define emit_cmp16_0 STEPNAME(emit_cmp16_0)
|
||||
#define emit_cmp32_0 STEPNAME(emit_cmp32_0)
|
||||
#define emit_test8 STEPNAME(emit_test8)
|
||||
#define emit_test16 STEPNAME(emit_test16)
|
||||
#define emit_test32 STEPNAME(emit_test32)
|
||||
#define emit_add32 STEPNAME(emit_add32)
|
||||
#define emit_add32c STEPNAME(emit_add32c)
|
||||
#define emit_add8 STEPNAME(emit_add8)
|
||||
#define emit_add8c STEPNAME(emit_add8c)
|
||||
#define emit_sub32 STEPNAME(emit_sub32)
|
||||
#define emit_sub32c STEPNAME(emit_sub32c)
|
||||
#define emit_sub8 STEPNAME(emit_sub8)
|
||||
#define emit_sub8c STEPNAME(emit_sub8c)
|
||||
#define emit_or32 STEPNAME(emit_or32)
|
||||
#define emit_or32c STEPNAME(emit_or32c)
|
||||
#define emit_xor32 STEPNAME(emit_xor32)
|
||||
#define emit_xor32c STEPNAME(emit_xor32c)
|
||||
#define emit_and32 STEPNAME(emit_and32)
|
||||
#define emit_and32c STEPNAME(emit_and32c)
|
||||
#define emit_or8 STEPNAME(emit_or8)
|
||||
#define emit_or8c STEPNAME(emit_or8c)
|
||||
#define emit_xor8 STEPNAME(emit_xor8)
|
||||
#define emit_xor8c STEPNAME(emit_xor8c)
|
||||
#define emit_and8 STEPNAME(emit_and8)
|
||||
#define emit_and8c STEPNAME(emit_and8c)
|
||||
#define emit_add16 STEPNAME(emit_add16)
|
||||
#define emit_add16c STEPNAME(emit_add16c)
|
||||
#define emit_sub16 STEPNAME(emit_sub16)
|
||||
#define emit_sub16c STEPNAME(emit_sub16c)
|
||||
#define emit_or16 STEPNAME(emit_or16)
|
||||
#define emit_or16c STEPNAME(emit_or16c)
|
||||
#define emit_xor16 STEPNAME(emit_xor16)
|
||||
#define emit_xor16c STEPNAME(emit_xor16c)
|
||||
#define emit_and16 STEPNAME(emit_and16)
|
||||
#define emit_and16c STEPNAME(emit_and16c)
|
||||
#define emit_inc32 STEPNAME(emit_inc32)
|
||||
#define emit_inc16 STEPNAME(emit_inc16)
|
||||
#define emit_inc8 STEPNAME(emit_inc8)
|
||||
#define emit_dec32 STEPNAME(emit_dec32)
|
||||
#define emit_dec16 STEPNAME(emit_dec16)
|
||||
#define emit_dec8 STEPNAME(emit_dec8)
|
||||
#define emit_adc32 STEPNAME(emit_adc32)
|
||||
#define emit_adc32c STEPNAME(emit_adc32c)
|
||||
#define emit_adc8 STEPNAME(emit_adc8)
|
||||
#define emit_adc8c STEPNAME(emit_adc8c)
|
||||
#define emit_adc16 STEPNAME(emit_adc16)
|
||||
#define emit_adc16c STEPNAME(emit_adc16c)
|
||||
#define emit_sbb32 STEPNAME(emit_sbb32)
|
||||
#define emit_sbb32c STEPNAME(emit_sbb32c)
|
||||
#define emit_sbb8 STEPNAME(emit_sbb8)
|
||||
#define emit_sbb8c STEPNAME(emit_sbb8c)
|
||||
#define emit_sbb16 STEPNAME(emit_sbb16)
|
||||
#define emit_sbb16c STEPNAME(emit_sbb16c)
|
||||
#define emit_neg32 STEPNAME(emit_neg32)
|
||||
#define emit_neg16 STEPNAME(emit_neg16)
|
||||
#define emit_neg8 STEPNAME(emit_neg8)
|
||||
#define emit_shl32c STEPNAME(emit_shl32c)
|
||||
#define emit_shr32c STEPNAME(emit_shr32c)
|
||||
#define emit_sar32c STEPNAME(emit_sar32c)
|
||||
#define emit_rol32c STEPNAME(emit_rol32c)
|
||||
#define emit_ror32c STEPNAME(emit_ror32c)
|
||||
|
||||
#define x87_do_push STEPNAME(x87_do_push)
|
||||
#define x87_do_push_empty STEPNAME(x87_do_push_empty)
|
||||
#define x87_do_pop STEPNAME(x87_do_pop)
|
||||
#define x87_get_cache STEPNAME(x87_get_cache)
|
||||
#define x87_get_st STEPNAME(x87_get_st)
|
||||
#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_setround STEPNAME(x87_setround)
|
||||
#define x87_restoreround STEPNAME(x87_restoreround)
|
||||
#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 fpu_pushcache STEPNAME(fpu_pushcache)
|
||||
#define fpu_popcache STEPNAME(fpu_popcache)
|
||||
#define fpu_reset STEPNAME(fpu_reset)
|
||||
#define fpu_purgecache STEPNAME(fpu_purgecache)
|
||||
#ifdef HAVE_TRACE
|
||||
#define fpu_reflectcache STEPNAME(fpu_reflectcache)
|
||||
#endif
|
||||
#define cstack_push STEPNAME(cstack_push)
|
||||
#define cstack_pop STEPNAME(cstack_pop)
|
||||
|
||||
|
||||
// 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)
|
||||
|
||||
/* 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);
|
||||
|
||||
// Do the GETED, but don't emit anything...
|
||||
uintptr_t fakeed(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop);
|
||||
|
||||
// generic x86 helper
|
||||
void jump_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst);
|
||||
void jump_to_linker(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst);
|
||||
void ret_to_epilog(dynarec_arm_t* dyn, int ninst);
|
||||
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);
|
||||
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);
|
||||
int isNativeCall(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t* calladdress, int* retn);
|
||||
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);
|
||||
void emit_cmp8_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
|
||||
void emit_cmp16_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
|
||||
void emit_cmp32_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
|
||||
void emit_test8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_test16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_test32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_add32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_add32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_add8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int save_s4);
|
||||
void emit_add8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_sub32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_sub32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_sub8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int save_s4);
|
||||
void emit_sub8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
void emit_or8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int save_s4);
|
||||
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, int save_s4);
|
||||
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, int save_s4);
|
||||
void emit_and8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_add16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int save_s4);
|
||||
void emit_add16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_sub16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int save_s4);
|
||||
void emit_sub16c(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, int save_s4);
|
||||
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, int save_s4);
|
||||
void emit_xor16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_and16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int save_s4);
|
||||
void emit_and16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_inc32(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
|
||||
void emit_inc16(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
|
||||
void emit_inc8(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
|
||||
void emit_dec32(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
|
||||
void emit_dec16(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);
|
||||
void emit_adc32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_adc32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_adc8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int save_s4);
|
||||
void emit_adc8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_adc16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int save_s4);
|
||||
void emit_adc16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_sbb32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_sbb32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_sbb8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int save_s4);
|
||||
void emit_sbb8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_sbb16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4, int save_s4);
|
||||
void emit_sbb16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_neg32(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
|
||||
void emit_neg16(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
|
||||
void emit_neg8(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
|
||||
void emit_shl32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, 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_rol32c(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);
|
||||
|
||||
// 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);
|
||||
// fpu push. Return the Dd value to be used
|
||||
int x87_do_push(dynarec_arm_t* dyn, int ninst);
|
||||
// fpu push. Do not allocate a cache register. Needs a scratch register to do x87stack synch (or 0 to not do it)
|
||||
void x87_do_push_empty(dynarec_arm_t* dyn, int ninst, int s1);
|
||||
// fpu pop. All previous returned Dd should be considered invalid
|
||||
void x87_do_pop(dynarec_arm_t* dyn, int ninst);
|
||||
// get cache index for a x87 reg, create the entry if needed
|
||||
int x87_get_cache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int a);
|
||||
// get vfpu register for a x87 reg, create the entry if needed
|
||||
int x87_get_st(dynarec_arm_t* dyn, int ninst, int s1, int s2, int a);
|
||||
// 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)
|
||||
void x87_forget(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st);
|
||||
// refresh the cache value from emu
|
||||
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);
|
||||
// Restore round flag
|
||||
void x87_restoreround(dynarec_arm_t* dyn, int ninst, int s1);
|
||||
|
||||
//MMX helpers
|
||||
// get neon register for a MMX reg, create the entry if needed
|
||||
int mmx_get_reg(dynarec_arm_t* dyn, int ninst, int s1, int a);
|
||||
// get neon register for a MMX reg, but don't try to synch it if it needed to be created
|
||||
int mmx_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int a);
|
||||
|
||||
//SSE/SSE2 helpers
|
||||
// get neon register for a SSE reg, create the entry if needed
|
||||
int sse_get_reg(dynarec_arm_t* dyn, int ninst, int s1, int a);
|
||||
// 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);
|
||||
|
||||
// common coproc helpers
|
||||
// reset the cache
|
||||
void fpu_reset(dynarec_arm_t* dyn, int ninst);
|
||||
// purge the FPU cache (needs 3 scratch registers)
|
||||
void fpu_purgecache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
#ifdef HAVE_TRACE
|
||||
void fpu_reflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
#endif
|
||||
void fpu_pushcache(dynarec_arm_t* dyn, int ninst, int s1);
|
||||
void fpu_popcache(dynarec_arm_t* dyn, int ninst, int s1);
|
||||
|
||||
// get the single reg that from the double "reg" (so Dx[idx])
|
||||
int fpu_get_single_reg(dynarec_arm_t* dyn, int ninst, int reg, int idx);
|
||||
// put back (if needed) the single reg in place
|
||||
void fpu_putback_single_reg(dynarec_arm_t* dyn, int ninst, int reg, int idx, int s);
|
||||
|
||||
uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec0F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog);
|
||||
uintptr_t dynarecFS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog);
|
||||
uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec66(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog);
|
||||
uintptr_t dynarec67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog);
|
||||
uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog);
|
||||
uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog);
|
||||
uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog);
|
||||
uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog);
|
||||
uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog);
|
||||
uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog);
|
||||
uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog);
|
||||
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 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);
|
||||
|
||||
// PUSH a x86/native couple of address in cstack, using s1, s2, s2+1
|
||||
void cstack_push(dynarec_arm_t* dyn, int ninst, uintptr_t x86ip, uintptr_t armip, int s1, int s2);
|
||||
// POP a x86/native couple of address from cstack, and generate the jump is x86 address is s0, use s1, s2 and s2+1 as scratch
|
||||
void cstack_pop(dynarec_arm_t* dyn, int ninst, int s0, int s1, int s2);
|
||||
|
||||
#if STEP < 2
|
||||
#define PASS2(A)
|
||||
#else
|
||||
#define PASS2(A) A
|
||||
#endif
|
||||
|
||||
#if STEP < 3
|
||||
#define PASS3(A)
|
||||
#else
|
||||
#define PASS3(A) A
|
||||
#endif
|
||||
|
||||
#if STEP < 3
|
||||
#define MAYUSE(A) (void)A
|
||||
#else
|
||||
#define MAYUSE(A)
|
||||
#endif
|
||||
|
||||
#endif //__DYNAREC_ARM_HELPER_H__
|
||||
Executable
+94
@@ -0,0 +1,94 @@
|
||||
#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 "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"
|
||||
|
||||
#ifndef STEP
|
||||
#error No STEP defined
|
||||
#endif
|
||||
|
||||
void arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
|
||||
{
|
||||
int ok = 1;
|
||||
int ninst = 0;
|
||||
uintptr_t ip = addr;
|
||||
int need_epilog = 1;
|
||||
dyn->tablei = 0;
|
||||
dyn->sons_size = 0;
|
||||
// Clean up (because there are multiple passes)
|
||||
dyn->state_flags = 0;
|
||||
fpu_reset(dyn, ninst);
|
||||
// ok, go now
|
||||
INIT;
|
||||
while(ok) {
|
||||
if(dyn->insts && (ninst>dyn->size)) {dynarec_log(LOG_NONE, "Warning, too many inst treated (%d / %d)\n",ninst, dyn->size);}
|
||||
ip = addr;
|
||||
if(dyn->insts && (dyn->insts[ninst].x86.barrier==1)) {
|
||||
NEW_BARRIER_INST;
|
||||
}
|
||||
NEW_INST;
|
||||
fpu_reset_scratch(dyn);
|
||||
#ifdef HAVE_TRACE
|
||||
if(my_context->dec && box86_dynarec_trace) {
|
||||
if((trace_end == 0)
|
||||
|| ((ip >= trace_start) && (ip <= trace_end))) {
|
||||
MESSAGE(LOG_DUMP, "TRACE ----\n");
|
||||
fpu_reflectcache(dyn, ninst, x1, x2, x3);
|
||||
MOV32(1, ip);
|
||||
STM(0, (1<<4)|(1<<5)|(1<<6)|(1<<7)|(1<<8)|(1<<9)|(1<<10)|(1<<11));
|
||||
STR_IMM9(1, 0, offsetof(x86emu_t, ip));
|
||||
MOV32(2, 1);
|
||||
CALL(PrintTrace, -1, 0);
|
||||
MESSAGE(LOG_DUMP, "----------\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
addr = dynarec00(dyn, addr, ip, ninst, &ok, &need_epilog);
|
||||
|
||||
INST_EPILOG;
|
||||
|
||||
if(dyn->insts && dyn->insts[ninst+1].x86.barrier) {
|
||||
fpu_purgecache(dyn, ninst, x1, x2, x3);
|
||||
if(dyn->insts[ninst+1].x86.barrier!=2)
|
||||
dyn->state_flags = 0;
|
||||
}
|
||||
if(!ok && !need_epilog && dyn->insts && (addr < (dyn->start+dyn->isize))) {
|
||||
ok = 1;
|
||||
}
|
||||
if(!ok && !need_epilog && !dyn->insts) { // check if need to continue
|
||||
uintptr_t next = get_closest_next(dyn, addr);
|
||||
if(next && ((next-addr)<15) && is_nops(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)<15) {
|
||||
dynarec_log(LOG_DEBUG, "Cannot extend block %p -> %p (%02X %02X %02X %02X %02X)\n", (void*)addr, (void*)next, PK(0), PK(1), PK(2), PK(3), PK(4));
|
||||
}
|
||||
}
|
||||
if(ok<0) {ok = 0; need_epilog=1;}
|
||||
++ninst;
|
||||
}
|
||||
if(need_epilog) {
|
||||
fpu_purgecache(dyn, ninst, 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);
|
||||
}
|
||||
Executable
+22
@@ -0,0 +1,22 @@
|
||||
|
||||
#define INIT uintptr_t sav_addr=addr
|
||||
#define FINI dyn->isize = addr-sav_addr
|
||||
#define MESSAGE(A, ...)
|
||||
#define SETFLAGS(A, B)
|
||||
#define READFLAGS(A)
|
||||
#define EMIT(A)
|
||||
#define JUMP(A) add_next(dyn, (uintptr_t)A)
|
||||
#define NEW_INST ++dyn->size
|
||||
#define INST_EPILOG
|
||||
#define INST_NAME(name)
|
||||
#define DEFAULT \
|
||||
--dyn->size; \
|
||||
*ok = -1; \
|
||||
dynarec_log(LOG_INFO, "%p: Dynarec stopped because of Opcode %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X (%s)\n", \
|
||||
(void*)ip, PKip(0), \
|
||||
PKip(1), PKip(2), PKip(3), \
|
||||
PKip(4), PKip(5), PKip(6), \
|
||||
PKip(7), PKip(8), PKip(9), \
|
||||
PKip(10),PKip(11),PKip(12), \
|
||||
PKip(13),PKip(14), \
|
||||
GetNativeName((void*)addr))
|
||||
Executable
+17
@@ -0,0 +1,17 @@
|
||||
#define INIT
|
||||
#define FINI \
|
||||
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 EMIT(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 JUMP(A) dyn->insts[ninst].x86.jmp = A
|
||||
#define BARRIER(A) dyn->insts[ninst].x86.barrier = A
|
||||
#define BARRIER_NEXT(A) if(ninst+1<dyn->size) dyn->insts[ninst+1].x86.barrier = A
|
||||
|
||||
#define NEW_INST \
|
||||
dyn->insts[ninst].x86.addr = ip; \
|
||||
if(ninst) dyn->insts[ninst-1].x86.size = dyn->insts[ninst].x86.addr - dyn->insts[ninst-1].x86.addr;
|
||||
#define INST_EPILOG
|
||||
#define INST_NAME(name)
|
||||
Executable
+9
@@ -0,0 +1,9 @@
|
||||
#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 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 INST_EPILOG dyn->insts[ninst].epilog = dyn->arm_size;
|
||||
#define INST_NAME(name)
|
||||
#define NEW_BARRIER_INST if(ninst) ++dyn->sons_size
|
||||
Executable
+33
@@ -0,0 +1,33 @@
|
||||
#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
|
||||
|
||||
#define MESSAGE(A, ...) if(box86_dynarec_dump) dynarec_log(LOG_NONE, __VA_ARGS__)
|
||||
#define NEW_INST
|
||||
#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, state=%d/%d, set=%X, use=%X, need=%X%s\n", \
|
||||
(box86_dynarec_dump>1)?"\e[32m":"", \
|
||||
(void*)(dyn->arm_start+dyn->insts[ninst].address), \
|
||||
dyn->insts[ninst].size/4, \
|
||||
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, \
|
||||
(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; \
|
||||
}
|
||||
|
||||
Executable
+52
@@ -0,0 +1,52 @@
|
||||
#ifndef __DYNAREC_ARM_PRIVATE_H_
|
||||
#define __DYNAREC_ARM_PRIVATE_H_
|
||||
|
||||
#include "dynarec_private.h"
|
||||
|
||||
typedef struct x86emu_s x86emu_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
|
||||
uintptr_t mark, mark2, mark3;
|
||||
uintptr_t markf;
|
||||
uintptr_t markseg;
|
||||
} instruction_arm_t;
|
||||
|
||||
typedef struct dynarec_arm_s {
|
||||
instruction_arm_t *insts;
|
||||
int32_t size;
|
||||
int32_t cap;
|
||||
uintptr_t start; // start of the block
|
||||
uint32_t isize; // size in byte of x86 instructions included
|
||||
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
|
||||
uintptr_t* table; // jump table
|
||||
int tablesz; // size of the jump table
|
||||
int tablei; // index
|
||||
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
|
||||
int 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
|
||||
int x87stack; // cache stack counter
|
||||
int fpu_scratch;// scratch counter
|
||||
int fpu_reg; // x87/sse/mmx reg counter
|
||||
int nolinker; // disable use of (smart) linker in the block
|
||||
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
|
||||
} 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);
|
||||
int is_nops(dynarec_arm_t *dyn, uintptr_t addr, int n);
|
||||
|
||||
#endif //__DYNAREC_ARM_PRIVATE_H_
|
||||
Executable
+37
@@ -0,0 +1,37 @@
|
||||
#ifndef __DYNAREC_PRIVATE_H_
|
||||
#define __DYNAREC_PRIVATE_H_
|
||||
|
||||
// all flags for the use_flags field
|
||||
#define X_CF (1<<0)
|
||||
#define X_PF (1<<1)
|
||||
#define X_AF (1<<2)
|
||||
#define X_ZF (1<<3)
|
||||
#define X_SF (1<<4)
|
||||
#define X_OF (1<<5)
|
||||
#define X_ALL ((1<<6)-1)
|
||||
#define X_PEND (0x1000)
|
||||
|
||||
// all state flags
|
||||
#define SF_UNKNOWN 0
|
||||
#define SF_SET 1
|
||||
#define SF_PENDING 2
|
||||
#define SF_MAYSET 3
|
||||
#define SF_SUBSET 4
|
||||
|
||||
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_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
|
||||
} instruction_x86_t;
|
||||
|
||||
void printf_x86_instruction(zydis_dec_t* dec, instruction_x86_t* inst, const char* name);
|
||||
void tableupdate(void* jumpto, uintptr_t ref, void** table);
|
||||
void resettable(void** table);
|
||||
|
||||
#endif //__DYNAREC_PRIVATE_H_
|
||||
@@ -0,0 +1,475 @@
|
||||
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 0 op 0 N Q M 0 Vm VH\(op ? "SUB" : "ADD")\<c>.<dt> <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 0 0 0 N Q M 1 Vm VQADD<c>.<dt> <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 0 0 1 N Q M 0 Vm VRHADD<c>.<dt> <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 0 0 D 0 0 Vn Vd 0 0 0 1 N Q M 1 Vm VAND<c> <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 0 0 D 0 1 Vn Vd 0 0 0 1 N Q M 1 Vm VBIC<c> <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 0 0 D 1 0 Vn Vd 0 0 0 1 N Q M 1 Vm @ m=n const char* op op,"MOV","ORR"@ m=n char lastop[6] !@ %@ lastop[0] = '\0'@ sprintf(lastop, ", %s", vecname[(q << 5) + 0x20 + n])@ @ V\op\<c> <Qd>, <Qm>\lastop\
|
||||
NEON 1 1 1 1 0 0 1 0 0 D 1 1 Vn Vd 0 0 0 1 N Q M 1 Vm VORN<c> <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 0 D @<2> Vn Vd 0 0 0 1 N Q M 1 Vm @ param=0b00=0b01=0b10 const char* op op,"EOR","BSL","BIT","BIF"@ @ V\op\<c> <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 0 1 0 N Q M 1 Vm VQSUB<c>.<dt> <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 0 1 1 N Q M op Vm @ op=0 const char* strict strict,"T","E"@ @ VCG\strict\<c>.<dt> <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 0 0 N Q M 0 Vm VSHL<c>.<dt> <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 0 0 N Q M 1 Vm VQSHL<c>.<dt> <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 0 1 N Q M 0 Vm VRSHL<c>.<dt> <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 0 1 N Q M 1 Vm VQRSHL<c>.<dt> <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 1 0 N Q M op Vm @ op=0 const char* opname opname,"MAX","MIN"@ @ V\opname\<c>.<dt> <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 1 1 N Q M 0 Vm VABD<c>.<dt> <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 0 1 1 1 N Q M 1 Vm VABA<c>.<dt> <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 op 0 D size Vn Vd 1 0 0 0 N Q M 0 Vm @ op=0 const char* opname opname,"ADD","SUB"@ @ V\opname\<c>.<dt> <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 0 0 D size Vn Vd 1 0 0 0 N Q M 1 Vm VTST<c>.<dt> <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 0 D size Vn Vd 1 0 0 0 N Q M 1 Vm VCEQ<c>.<dt> <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 1 0 0 1 N Q M 0 Vm @ set size = 8 << size@ @ VML\(u ? "S" : "A")\<c>.I\%dsize\ <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 1 0 0 1 N Q M 1 Vm VMUL<c>.<dt> <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 U 0 D size Vn Vd 1 0 1 0 N Q M op Vm @ op=0 const char* opname opname,"MAX","MIN"@ @ VP\opname\<c>.<dt> <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 0 0 D size Vn Vd 1 0 1 1 N Q M 0 Vm VQDMULH<c>.<dt> <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 0 D size Vn Vd 1 0 1 1 N Q M 0 Vm VQRDMULH<c>.<dt> <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 0 0 D size Vn Vd 1 0 1 1 N Q/=0 M 1 Vm VPADD<c>.<dt> <Dd>, <Dn>, <Dm>
|
||||
NEON 1 1 1 1 0 0 1 0 0 D U sz/=0 Vn Vd 1 1 0 0 N Q M 1 Vm @ u=0 const char* y y,"A","S"@ @ VFM\y\<c>.F32 <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 0 0 D U sz/=0 Vn Vd 1 1 0 1 N Q M 0 Vm @ u=0 const char* op op,"ADD","SUB"@ @ V\op\<c>.F32 <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 0 D 0 sz/=0 Vn Vd 1 1 0 1 N Q/=0 M 0 Vm VPADD.F32 <Dd>, <Dn>, <Dm>
|
||||
NEON 1 1 1 1 0 0 1 1 0 D 1 sz/=0 Vn Vd 1 1 0 1 N Q M 0 Vm VABD.F32 <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 0 0 D op sz/=0 Vn Vd 1 1 0 1 N Q M 1 Vm VML\(op ? "S" : "A")\<c>.F32 <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 0 D 0 sz/=0 Vn Vd 1 1 0 1 N Q M 1 Vm VMUL.F32 <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 0 0 D 0 sz/=0 Vn Vd 1 1 1 0 N Q M 0 Vm VCEQ.F32 <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 0 D op sz/=0 Vn Vd 1 1 1 0 N Q M 0 Vm @ op=1 const char* strict strict,"T","E"@ @ VCG\strict\.F32 <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 0 D op sz/=0 Vn Vd 1 1 1 0 N Q M 1 Vm @ op=1 const char* strict strict,"T","E"@ @ VACG\strict\.F32 <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 0 0 D op sz/=0 Vn Vd 1 1 1 1 N Q M 0 Vm @ op=0 const char* opname opname,"MAX","MIN"@ @ V\opname\.F32 <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 0 D op sz/=0 Vn Vd 1 1 1 1 N Q M 0 Vm @ op=0 const char* opname opname,"MAX","MIN"@ @ VP\opname\.F32 <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 0 0 D 0 sz/=0 Vn Vd 1 1 1 1 N Q M 1 Vm VRECPS.F32 <Qd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 0 0 D 1 sz/=0 Vn Vd 1 1 1 1 N Q M 1 Vm VRSQRTS.F32 <Qd>, <Qn>, <Qm>
|
||||
INVALIDATE 1 1 1 1 0 0 1 <1> 0 <23>
|
||||
NEON 1 1 1 1 0 0 1 i 1 D 0 0 0 imm3 Vd cmode/=0xx0 0 Q op/=0 1 imm4 VMOV<c>.<dt> <Qd>, #<imm>
|
||||
NEON 1 1 1 1 0 0 1 i 1 D 0 0 0 imm3 Vd cmode/=0xx1 0 Q op/=0 1 imm4 VORR<c>.<dt> <Qd>, #<imm>
|
||||
NEON 1 1 1 1 0 0 1 i 1 D 0 0 0 imm3 Vd cmode/=10x0 0 Q op/=0 1 imm4 VMOV<c>.<dt> <Qd>, #<imm>
|
||||
NEON 1 1 1 1 0 0 1 i 1 D 0 0 0 imm3 Vd cmode/=10x1 0 Q op/=0 1 imm4 VORR<c>.<dt> <Qd>, #<imm>
|
||||
NEON 1 1 1 1 0 0 1 i 1 D 0 0 0 imm3 Vd cmode/=11xx 0 Q op/=0 1 imm4 VMOV<c>.<dt> <Qd>, #<imm>
|
||||
NEON 1 1 1 1 0 0 1 i 1 D 0 0 0 imm3 Vd cmode/=0xx0 0 Q op/=1 1 imm4 VMVN<c>.<dt> <Qd>, #<imm>
|
||||
NEON 1 1 1 1 0 0 1 i 1 D 0 0 0 imm3 Vd cmode/=0xx1 0 Q op/=1 1 imm4 VBIC<c>.<dt> <Qd>, #<imm>
|
||||
NEON 1 1 1 1 0 0 1 i 1 D 0 0 0 imm3 Vd cmode/=10x0 0 Q op/=1 1 imm4 VMVN<c>.<dt> <Qd>, #<imm>
|
||||
NEON 1 1 1 1 0 0 1 i 1 D 0 0 0 imm3 Vd cmode/=10x1 0 Q op/=1 1 imm4 BIC<c>.<dt> <Qd>, #<imm>
|
||||
NEON 1 1 1 1 0 0 1 i 1 D 0 0 0 imm3 Vd cmode/=110x 0 Q op/=1 1 imm4 VMVN<c>.<dt> <Qd>, #<imm>
|
||||
NEON 1 1 1 1 0 0 1 i 1 D 0 0 0 imm3 Vd cmode/=1110 0 Q op/=1 1 imm4 VMOV<c>.<dt> <Qd>, #<imm>
|
||||
INVALIDATE 1 1 1 1 0 0 1 <1> 1 <1> 0 0 0 <11> 0 <2> 1 <4>
|
||||
NEON 1 1 1 1 0 0 1 0 1 D 0 0 1 0 0 0 Vd 1 0 1 0 0 0 M 1 Vm VMOVL<c>.S8 <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 0 1 D 0 1 0 0 0 0 Vd 1 0 1 0 0 0 M 1 Vm VMOVL<c>.S16 <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 0 1 D 1 0 0 0 0 0 Vd 1 0 1 0 0 0 M 1 Vm VMOVL<c>.S32 <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 0 0 1 0 0 0 Vd 1 0 1 0 0 0 M 1 Vm VMOVL<c>.U8 <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 0 1 0 0 0 0 Vd 1 0 1 0 0 0 M 1 Vm VMOVL<c>.U16 <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 0 0 0 0 0 Vd 1 0 1 0 0 0 M 1 Vm VMOVL<c>.U32 <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 U 1 D imm6 Vd 0 0 0 0 L Q M 1 Vm VSHR<c>.<dt> <Qd>, <Qm>, #<imm>
|
||||
NEON 1 1 1 1 0 0 1 U 1 D imm6 Vd 0 0 0 1 L Q M 1 Vm VSRA<c>.<dt> <Qd>, <Qm>, #<imm>
|
||||
NEON 1 1 1 1 0 0 1 U 1 D imm6 Vd 0 0 1 0 L Q M 1 Vm VRSHR<c>.<dt> <Qd>, <Qm>, #<imm>
|
||||
NEON 1 1 1 1 0 0 1 U 1 D imm6 Vd 0 0 1 1 L Q M 1 Vm VRSRA<c>.<dt> <Qd>, <Qm>, #<imm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D imm6 Vd 0 1 0 0 L Q M 1 Vm VSRI<c>.<size> <Qd>, <Qm>, #<imm>
|
||||
NEON 1 1 1 1 0 0 1 0 1 D Imm6 Vd 0 1 0 1 L Q M 1 Vm VSHL<c>.I<size> <Qd>, <Qm>, #<imm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D Imm6 Vd 0 1 0 1 L Q M 1 Vm VSLI<c>.<size> <Qd>, <Qm>, #<imm>
|
||||
NEON 1 1 1 1 0 0 1 U 1 D Imm6 Vd 0 1 1 op L Q M 1 Vm VQSHL\((u & op) ? "U" : "")\<c>.<dt> <Qd>, <Qm>, #<imm>
|
||||
NEON 1 1 1 1 0 0 1 0 1 D imm6 Vd 1 0 0 0 0 0 M 1 Vm VSHRN<c>.I<size> <Dd>, <Qm>, #<imm>
|
||||
NEON 1 1 1 1 0 0 1 0 1 D imm6 Vd 1 0 0 0 0 1 M 1 Vm VRSHRN<c>.I<size> <Dd>, <Qm>, #<imm>
|
||||
NEON 1 1 1 1 0 0 1 U 1 D imm6 Vd 1 0 0 op 0 0 M 1 Vm VQSHR\((u & op) ? "U" : "")\N<c>.<dt> <Dd>, <Qm>, #<imm>
|
||||
NEON 1 1 1 1 0 0 1 U 1 D imm6 Vd 1 0 0 op 0 1 M 1 Vm VQRSHR\((u & op) ? "U" : "")\N<c>.<dt> <Dd>, <Qm>, #<imm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 0 Vd 0 0 1 1 0 0 M 1 Vm VSHLL<c>.<dt> <Qd>, <Dm>, #\%d8 &l&l size\
|
||||
NEON 1 1 1 1 0 0 1 U 1 D Imm6 Vd 1 0 1 0 0 0 M 1 Vm VSHLL<c>.<dt> <Qd>, <Dm>, #<imm>
|
||||
INVALIDATE 1 1 1 1 0 0 1 <1> 1 <1> 0 <9> 1 1 1 <1> 0 <2> 1 <4>
|
||||
NEON 1 1 1 1 0 0 1 0 1 D IMM6 Vd 1 1 1 0 0 Q M 1 Vm VCVT<c>.F32.S32 <Qd>, <Qm>, #<fbits>
|
||||
NEON 1 1 1 1 0 0 1 0 1 D IMM6 Vd 1 1 1 1 0 Q M 1 Vm VCVT<c>.S32.F32 <Qd>, <Qm>, #<fbits>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D IMM6 Vd 1 1 1 0 0 Q M 1 Vm VCVT<c>.F32.U32 <Qd>, <Qm>, #<fbits>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D IMM6 Vd 1 1 1 1 0 Q M 1 Vm VCVT<c>.U32.F32 <Qd>, <Qm>, #<fbits>
|
||||
INVALIDATE 1 1 1 1 0 0 1 <1> 1 <18> 1 <4>
|
||||
NEON 1 1 1 1 0 0 1 0 1 D 1 1 Vn Vd IMM4 N Q M 0 Vm VEXT<c>.8 <Qd>, <Qn>, <Qm>, #<imm>
|
||||
INVALIDATE 1 1 1 1 0 0 1 1 1 <1> 1 1 <2>/=11 0 0 <4> 0 0 0 <2> <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>/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 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>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size/=00 0 0 Vd 0 1 0 1 0 Q M 0 Vm VCNT<c>.8 <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size/=00 0 0 Vd 0 1 0 1 1 Q M 0 Vm VMVN<c> <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 1 1 0 U Q M 0 Vm VPADAL<c>.<dt> <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 1 1 1 0 Q M 0 Vm VQABS<c>.<dt> <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 0 Vd 0 1 1 1 1 Q M 0 Vm VQNEG<c>.<dt> <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 1 Vd 0 F 0 0 0 Q M 0 Vm VCGT<c>.<dt> <Qd>, <Qm>, #0
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 1 Vd 0 F 0 0 1 Q M 0 Vm VCGE<c>.<dt> <Qd>, <Qm>, #0
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 1 Vd 0 F 0 1 0 Q M 0 Vm VCEQ<c>.<dt> <Qd>, <Qm>, #0
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 1 Vd 0 F 0 1 1 Q M 0 Vm VCLE<c>.<dt> <Qd>, <Qm>, #0
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 1 Vd 0 F 1 0 0 Q M 0 Vm VCLT<c>.<dt> <Qd>, <Qm>, #0
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 1 Vd 0 F 1 1 0 Q M 0 Vm VABS<c>.<dt> <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 0 1 Vd 0 F 1 1 1 Q M 0 Vm VNEG<c>.<dt> <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size/=00 1 0 Vd 0 0 0 0 0 Q M 0 Vm VSWP<c> <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 0 Vd 0 0 0 0 1 Q M 0 Vm VTRN<c>.\%d8 &l&l size\ <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 0 Vd 0 0 0 1 0 Q M 0 Vm VUZP<c>.\%d8 &l&l size\ <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 0 Vd 0 0 0 1 1 Q M 0 Vm VZIP<c>.\%d8 &l&l size\ <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 0 Vd 0 0 1 0 0 0 M 0 Vm VMOVN<c>.<dt> <Dd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 0 Vd 0 0 1 0 0 1 M 0 Vm VQMOVUN<c>.S\%d16 &l&l size\ <Dd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 0 Vd 0 0 1 0 1 U M 0 Vm @ set u = 1 - u@ set ++size@ @ VQMOVN<c>.<dt> <Dd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 0 Vd 0 0 1 1 0 0 M 0 Vm VSHLL<c>.I\%d8 &l&l size\ <Qd>, <Dm>, #\%d8 &l&l size\
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size/=01 1 0 Vd 0 1 1 0 0 0 M 0 Vm VCVT<c>.F16.F32 <Dd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size/=01 1 0 Vd 0 1 1 1 0 0 M 0 Vm VCVT<c>.F32.F16 <Qd>, <Dm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 1 Vd 0 1 0 F 0 Q M 0 Vm VRECPE<c>.<dt> <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size 1 1 Vd 0 1 0 F 1 Q M 0 Vm VRSQRTE<c>.<dt> <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size/=10 1 1 Vd 0 1 1 0 0 Q M 0 Vm VCVT<c>.F32.S32 <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size/=10 1 1 Vd 0 1 1 0 1 Q M 0 Vm VCVT<c>.S32.F32 <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size/=10 1 1 Vd 0 1 1 1 0 Q M 0 Vm VCVT<c>.F32.U32 <Qd>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 size/=10 1 1 Vd 0 1 1 1 1 Q M 0 Vm VCVT<c>.U32.F32 <Qd>, <Qm>
|
||||
INVALIDATE 1 1 1 1 0 0 1 1 1 <1> 1 1 <8> 0 <6> 0 <4>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 Vn Vd 1 0 @<2> N op M 0 Vm @ param=0b00 char list[10] !@ sprintf(list, %)@ "{%s}", vecname[0x20 + n]@ "{%s-%s}", vecname[0x20 + n], vecname[0x20 + n + param]@ @ VTB\(op ? "X" : "L")\<c>.8 <Dd>, \list\, <Dm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D 1 1 imm4 Vd 1 1 0 0 0 Q M 0 Vm VDUP<c>.\%dsize\ <Qd>, <Dm[x]>
|
||||
INVALIDATE 1 1 1 1 0 0 1 <1> 1 <1> 1 1 <13> 0 <1> 0 <4>
|
||||
NEON 1 1 1 1 0 0 1 U 1 D size Vn Vd 0 0 0 Q N 0 M 0 Vm VADD\(q ? "W" : "L")\<c>.<dt> <qd>, <Qn>, <Dm>
|
||||
NEON 1 1 1 1 0 0 1 U 1 D size Vn Vd 0 0 1 Q N 0 M 0 Vm VSUB\(q ? "W" : "L")\<c>.<dt> <qd>, <Qn>, <Dm>
|
||||
NEON 1 1 1 1 0 0 1 0 1 D size Vn Vd 0 1 0 0 N 0 M 0 Vm @ set size = 16 << size@ @ VADDHN<c>.I\%dsize\ <Dd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D size Vn Vd 0 1 0 0 N 0 M 0 Vm VRADDHN<c>.<dt> <Dd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 U 1 D size Vn Vd 0 1 0 1 N 0 M 0 Vm VABAL<c>.<dt> <Qd>, <Dn>, <Dm>
|
||||
NEON 1 1 1 1 0 0 1 0 1 D size Vn Vd 0 1 1 0 N 0 M 0 Vm VSUBHN<c>.<dt> <Dd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 1 1 D size Vn Vd 0 1 1 0 N 0 M 0 Vm VRSUBHN<c>.<dt> <Dd>, <Qn>, <Qm>
|
||||
NEON 1 1 1 1 0 0 1 U 1 D size Vn Vd 0 1 1 1 N 0 M 0 Vm VABDL<c>.<dt> <Qd>, <Dn>, <Dm>
|
||||
NEON 1 1 1 1 0 0 1 U 1 D size Vn Vd 1 0 op 0 N 0 M 0 Vm VML\(op ? "S" : "A")\L<c>.<dt> <Qd>, <Dn>, <Dm>
|
||||
NEON 1 1 1 1 0 0 1 0 1 D size Vn Vd 1 0 op 1 N 0 M 0 Vm VQDML\(op ? "S" : "A")\L<c>.<dt> <Qd>, <Dn>, <Dm>
|
||||
NEON 1 1 1 1 0 0 1 U 1 D size Vn Vd 1 1 0 0 N 0 M 0 Vm VMULL<c>.<dt> <Qd>, <Dn>, <Dm>
|
||||
NEON 1 1 1 1 0 0 1 0 1 D size Vn Vd 1 1 0 1 N 0 M 0 Vm VQDMULL<c>.<dt> <Qd>, <Dn>, <Dm>
|
||||
NEON 1 1 1 1 0 0 1 U/=0 1 D size/=00 Vn Vd 1 1 1 0 N 0 M 0 Vm @ set uint8_t size = 0@ @ VMULL<c>.<dt> <Qd>, <Dn>, <Dm>
|
||||
INVALIDATE 1 1 1 1 0 0 1 <1> 1 <16> 0 <1> 0 <4>
|
||||
NEON 1 1 1 1 0 0 1 Q 1 D size Vn Vd 0 op 0 F N 1 M 0 Vm @ size=0b01=0b10 unsigned int decodedImm !@ decodedImm = m >> %; m %@ 3@ &= 0x7@ 4@ &= 0xF@ 5@ = 0x21@ @ VML\(op ? "S" : "A")\<c>.<dt> <Qd>, <Qn>, <Dm[x]>
|
||||
NEON 1 1 1 1 0 0 1 U 1 D size Vn Vd 0 op 1 0 N 1 M 0 Vm @ size=0b01=0b10 unsigned int decodedImm !@ decodedImm = m >> %; m %@ 3@ &= 0x7@ 4@ &= 0xF@ 5@ = 0x21@ @ VML\(op ? "S" : "A")\L<c>.<dt> <Qd>, <Dn>, <Dm[x]>
|
||||
NEON 1 1 1 1 0 0 1 0 1 D size Vn Vd 0 op 1 1 N 1 M 0 Vm @ size=0b01=0b10 unsigned int decodedImm !@ decodedImm = m >> %; m %@ 3@ &= 0x7@ 4@ &= 0xF@ 5@ = 0x21@ @ VQDML\(op ? "S" : "A")\L<c>.<dt> <Qd>, <Dn>, <Dm[x]>
|
||||
NEON 1 1 1 1 0 0 1 Q 1 D size Vn Vd 1 0 0 F N 1 M 0 Vm @ size=0b01=0b10 unsigned int decodedImm !@ decodedImm = m >> %; m %@ 3@ &= 0x7@ 4@ &= 0xF@ 5@ = 0x21@ @ VMUL<c>.<dt> <Qd>, <Qn>, <Dm[x]>
|
||||
NEON 1 1 1 1 0 0 1 U 1 D size Vn Vd 1 0 1 0 N 1 M 0 Vm @ size=0b01=0b10 unsigned int decodedImm !@ decodedImm = m >> %; m %@ 3@ &= 0x7@ 4@ &= 0xF@ 5@ = 0x21@ @ VMULL<c>.<dt> <Qd>, <Qn>, <Dm[x]>
|
||||
NEON 1 1 1 1 0 0 1 0 1 D size Vn Vd 1 0 1 1 N 1 M 0 Vm @ size=0b01=0b10 unsigned int decodedImm !@ decodedImm = m >> %; m %@ 3@ &= 0x7@ 4@ &= 0xF@ 5@ = 0x21@ @ VQDMULL<c>.<dt> <Qd>, <Qn>, <Dm[x]>
|
||||
NEON 1 1 1 1 0 0 1 Q 1 D size Vn Vd 1 1 0 0 N 1 M 0 Vm @ size=0b01=0b10 unsigned int decodedImm !@ decodedImm = m >> %; m %@ 3@ &= 0x7@ 4@ &= 0xF@ 5@ = 0x21@ @ VQDMULH<c>.<dt> <Qd>, <Qn>, <Dm[x]>
|
||||
NEON 1 1 1 1 0 0 1 Q 1 D size Vn Vd 1 1 0 1 N 1 M 0 Vm @ size=0b01=0b10 unsigned int decodedImm !@ decodedImm = m >> %; m %@ 3@ &= 0x7@ 4@ &= 0xF@ 5@ = 0x21@ @ VQRDMULH<c>.<dt> <Qd>, <Qn>, <Dm[x]>
|
||||
INVALIDATE 1 1 1 1 0 0 1 <1> 1 <16> 0 <1> 0 <4>
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 0 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\, \vecname[0x23 + d]\}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 0 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\, \vecname[0x23 + d]\}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 0 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\, \vecname[0x23 + d]\}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 0 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\, \vecname[0x26 + d]\}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 0 1 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\, \vecname[0x26 + d]\}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 0 1 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\, \vecname[0x26 + d]\}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 1 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 1 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 1 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 1 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 1 1 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 0 1 1 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 0 0 size @<2> 1 1 1 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 0 0 size @<2> 1 1 0 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 0 0 size @<2> Rm @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 0 1 size @<2> 1 1 1 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 0 1 size @<2> 1 1 0 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 0 1 size @<2> Rm @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 1 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x22 + d]\}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 1 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x22 + d]\}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 1 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x22 + d]\}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 1 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 1 1 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 0 1 1 1 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 0 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 0 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 0 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 0 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 0 1 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 0 1 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 1 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 1 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 0 0 Rn Vd 1 0 1 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\], <Rm>
|
||||
INVALIDATE 1 1 1 1 0 1 0 0 1 <1> 0 0 <8> 1 1 <10>
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 0 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)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 0 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)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 0 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)@ @ VST1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 0 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@ @ VST2<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 0 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@ @ VST2<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 0 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@ @ VST2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 1 @<4> 1 1 1 1 @ set uint8_t temp = param & (1 << size)@ temp=0 uint8_t spacing spacing,0,1@ set uint8_t x = param >> (size + 1)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\]}, [<Rn>]
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 1 @<4> 1 1 0 1 @ set uint8_t temp = param & (1 << size)@ temp=0 uint8_t spacing spacing,0,1@ set uint8_t x = param >> (size + 1)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\]}, [<Rn>]!
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 0 0 Rn Vd size 0 1 @<4> Rm @ set uint8_t temp = param & (1 << size)@ temp=0 uint8_t spacing spacing,0,1@ set uint8_t x = param >> (size + 1)@ @ VST3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\]}, [<Rn>], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 0 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=0b0=0b1=0b10 char align[6] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", (size ? 64 : 32))@ sprintf(align, ":128")@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\], \vecname[0x23 + d + 3*spacing]\[\%dx\]}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 0 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=0b0=0b1=0b10 char align[6] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", (size ? 64 : 32))@ sprintf(align, ":128")@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\], \vecname[0x23 + d + 3*spacing]\[\%dx\]}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 0 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=0b0=0b1=0b10 char align[6] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", (size ? 64 : 32))@ sprintf(align, ":128")@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VST4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\], \vecname[0x23 + d + 3*spacing]\[\%dx\]}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 0 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\, \vecname[0x23 + d]\}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 0 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\, \vecname[0x23 + d]\}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 0 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\, \vecname[0x23 + d]\}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 0 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\, \vecname[0x26 + d]\}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 0 1 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\, \vecname[0x26 + d]\}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 0 1 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\, \vecname[0x26 + d]\}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 1 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 1 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 1 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 1 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 1 1 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 0 1 1 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x23 + d]\}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 0 0 size @<2> 1 1 1 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 0 0 size @<2> 1 1 0 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 0 0 size @<2> Rm @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 0 1 size @<2> 1 1 1 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 0 1 size @<2> 1 1 0 1 @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 0 1 size @<2> Rm @ param=0b00 char align[4] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 63 + param)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\, \vecname[0x24 + d]\}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 1 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x22 + d]\}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 1 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x22 + d]\}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 1 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\-\vecname[0x22 + d]\}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 1 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 1 1 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 0 1 1 1 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 0 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 0 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 0 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 0 1 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 0 1 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 0 1 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x22 + d]\}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 1 0 size @<2> 1 1 1 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 1 0 size @<2> 1 1 0 1 @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 0 D 1 0 Rn Vd 1 0 1 0 size @<2> Rm @ param=0b00 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 32 << param)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\, \vecname[0x21 + d]\}, [<Rn>\align\], <Rm>
|
||||
INVALIDATE 1 1 1 1 0 1 0 0 1 <1> 1 0 <8> 1 1 <10>
|
||||
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> 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> 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 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> 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> 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>
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> 1 1 1 1 @ set uint8_t temp = param & (1 << size)@ temp=0 uint8_t spacing spacing,0,1@ set uint8_t x = param >> (size + 1)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\]}, [<Rn>]
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> 1 1 0 1 @ set uint8_t temp = param & (1 << size)@ temp=0 uint8_t spacing spacing,0,1@ set uint8_t x = param >> (size + 1)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\]}, [<Rn>]!
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> Rm @ set uint8_t temp = param & (1 << size)@ temp=0 uint8_t spacing spacing,0,1@ set uint8_t x = param >> (size + 1)@ @ VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\]}, [<Rn>], <Rm>
|
||||
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=0b0=0b1=0b10 char align[6] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", (size ? 64 : 32))@ sprintf(align, ":128")@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\], \vecname[0x23 + d + 3*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 0 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0b0=0b1=0b10 char align[6] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", (size ? 64 : 32))@ sprintf(align, ":128")@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\], \vecname[0x23 + d + 3*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=0b0=0b1=0b10 char align[6] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", (size ? 64 : 32))@ sprintf(align, ":128")@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\], \vecname[0x22 + d + 2*spacing]\[\%dx\], \vecname[0x23 + d + 3*spacing]\[\%dx\]}, [<Rn>\align\], <Rm>
|
||||
INVALIDATE 1 1 1 1 0 1 0 0 <3> 0 <20>
|
||||
INVALIDATE 1 1 1 1 <28>
|
||||
ARMS cond 0 0 0 0 0 0 0 S Rn Rd imm5 type 0 Rm AND{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
|
||||
ARM_ cond 0 0 0 0 0 0 0 S Rd (0) (0) (0) (0) Rm 1 0 0 1 Rn MUL{S}<c> <Rd>, <Rn>, <Rm>
|
||||
ARM_ cond 0 0 0 0 U 0 0 0 Rn Rt (0) (0) (0) (0) 1 0 1 1 Rm STRH<c> <Rt>, [<Rn>], +/-<Rm>
|
||||
ARM_ cond 0 0 0 0 U 0 0 0 Rn Rt (0) (0) (0) (0) 1 1 0 1 Rm LDRD<c> <Rt>, <Rt2>, [<Rn>], +/-<Rm>
|
||||
ARM_ cond 0 0 0 0 U 0 0 0 Rn Rt (0) (0) (0) (0) 1 1 1 1 Rm STRD<c> <Rt>, <Rt2>, [<Rn>], +/-<Rm>
|
||||
ARM_ cond 0 0 0 0 U 0 0 1 Rn Rt (0) (0) (0) (0) 1 0 1 1 Rm LDRH<c> <Rt>, [<Rn>], +/-<Rm>
|
||||
ARM_ cond 0 0 0 0 U 0 0 1 Rn Rt (0) (0) (0) (0) 1 1 0 1 Rm LDRSB<c> <Rt>, [<Rn>], +/-<Rm>
|
||||
ARM_ cond 0 0 0 0 U 0 0 1 Rn Rt (0) (0) (0) (0) 1 1 1 1 Rm LDRSH<c> <Rt>, [<Rn>], +/-<Rm>
|
||||
ARMS cond 0 0 0 0 0 0 1 S Rn Rd imm5 type 0 Rm EOR{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
|
||||
ARM_ cond 0 0 0 0 0 0 1 S Rd Ra Rm 1 0 0 1 Rn MLA{S}<c> <Rd>, <Rn>, <Rm>, <Ra>
|
||||
ARM_ cond 0 0 0 0 U 0 1 0 Rn Rt (0) (0) (0) (0) 1 0 1 1 Rm STRHT<c> <Rt>, [<Rn>], +/-<Rm>
|
||||
ARM_ cond 0 0 0 0 U 0 1 1 Rn Rt (0) (0) (0) (0) 1 0 1 1 Rm LDRHT<c> <Rt>, [<Rn>], +/-<Rm>
|
||||
ARM_ cond 0 0 0 0 U 0 1 1 Rn Rt (0) (0) (0) (0) 1 1 0 1 Rm LDRSBT<c> <Rt>, [<Rn>], +/-<Rm>
|
||||
ARM_ cond 0 0 0 0 U 0 1 1 Rn Rt (0) (0) (0) (0) 1 1 1 1 Rm LDRSHT<c> <Rt>, [<Rn>], +/-<Rm>
|
||||
ARMS cond 0 0 0 0 0 1 0 S Rn Rd imm5 type 0 Rm SUB{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
|
||||
ARM_ cond 0 0 0 0 0 1 0 0 RdHi RdLo Rm 1 0 0 1 Rn UMAAL<c> <RdLo>, <RdHi>, <Rn>, <Rm>
|
||||
ARM_ cond 0 0 0 0 U 1 0 0 Rn Rt imm4H 1 0 1 1 imm4L STRH<c> <Rt>, [<Rn>], #+/-<imm8>
|
||||
ARM_ cond 0 0 0 0 U 1 0 0 Rn Rt imm4H 1 1 0 1 imm4L LDRD<c> <Rt>, <Rt2>, [<Rn>], #+/-<imm8>
|
||||
ARM_ cond 0 0 0 0 U 1 0 0 Rn Rt imm4H 1 1 1 1 imm4L STRD<c> <Rt>, <Rt2>, [<Rn>], #+/-<imm8>
|
||||
ARM_ cond 0 0 0 0 U 1 0 1 Rn Rt imm4H 1 0 1 1 imm4L LDRH<c> <Rt>, [<Rn>], #+/-<imm8>
|
||||
ARM_ cond 0 0 0 0 U 1 0 1 Rn Rt imm4H 1 1 0 1 imm4L LDRSB<c> <Rt>, [<Rn>], #+/-<imm8>
|
||||
ARM_ cond 0 0 0 0 U 1 0 1 Rn Rt imm4H 1 1 1 1 imm4L LDRSH<c> <Rt>, [<Rn>], #+/-<imm8>
|
||||
ARMS cond 0 0 0 0 0 1 1 S Rn Rd imm5 type 0 Rm RSB{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
|
||||
ARM_ cond 0 0 0 0 0 1 1 0 Rd Ra Rm 1 0 0 1 Rn MLS<c> <Rd>, <Rn>, <Rm>, <Ra>
|
||||
ARM_ cond 0 0 0 0 U 1 1 0 Rn Rt imm4H 1 0 1 1 imm4L STRHT<c> <Rt>, [<Rn>], #+/-<imm8>
|
||||
ARM_ cond 0 0 0 0 U 1 1 1 Rn Rt imm4H 1 0 1 1 imm4L LDRHT<c> <Rt>, [<Rn>], #+/-<imm8>
|
||||
ARM_ cond 0 0 0 0 U 1 1 1 Rn Rt imm4H 1 1 0 1 imm4L LDRSBT<c> <Rt>, [<Rn>], #+/-<imm8>
|
||||
ARM_ cond 0 0 0 0 U 1 1 1 Rn Rt imm4H 1 1 1 1 imm4L LDRSHT<c> <Rt>, [<Rn>], #+/-<imm8>
|
||||
ARMS cond 0 0 0 0 1 0 0 S Rn Rd imm5 type 0 Rm ADD{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
|
||||
ARM_ cond 0 0 0 0 1 0 0 S RdHi RdLo Rm 1 0 0 1 Rn UMULL{S}<c> <RdLo>, <RdHi>, <Rn>, <Rm>
|
||||
ARMS cond 0 0 0 0 1 0 1 S Rn Rd imm5 type 0 Rm ADC{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
|
||||
ARM_ cond 0 0 0 0 1 0 1 S RdHi RdLo Rm 1 0 0 1 Rn UMLAL{S}<c> <RdLo>, <RdHi>, <Rn>, <Rm>
|
||||
ARMS cond 0 0 0 0 1 1 0 S Rn Rd imm5 type 0 Rm SBC{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
|
||||
ARM_ cond 0 0 0 0 1 1 0 S RdHi RdLo Rm 1 0 0 1 Rn SMULL{S}<c> <RdLo>, <RdHi>, <Rn>, <Rm>
|
||||
ARMS cond 0 0 0 0 1 1 1 S Rn Rd imm5 type 0 Rm RSC{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
|
||||
ARM_ cond 0 0 0 0 1 1 1 S RdHi RdLo Rm 1 0 0 1 Rn SMLAL{S}<c> <RdLo>, <RdHi>, <Rn>, <Rm>
|
||||
ARM_ cond 0 0 0 1 0 0 0 0 Rd Ra Rm 1 0 0 0 Rn SMLABB<c> <Rd>, <Rn>, <Rm>, <Ra>
|
||||
ARM_ cond 0 0 0 1 0 0 0 0 Rd Ra Rm 1 0 1 0 Rn SMLATB<c> <Rd>, <Rn>, <Rm>, <Ra>
|
||||
ARM_ cond 0 0 0 1 0 0 0 0 Rd Ra Rm 1 1 0 0 Rn SMLABT<c> <Rd>, <Rn>, <Rm>, <Ra>
|
||||
ARM_ cond 0 0 0 1 0 0 0 0 Rd Ra Rm 1 1 1 0 Rn SMLATT<c> <Rd>, <Rn>, <Rm>, <Ra>
|
||||
ARM_ cond 0 0 0 1 0 0 0 0 Rn Rt (0) (0) (0) (0) 1 0 0 1 Rm SWP<c> <Rt>, <Rm>, [<Rn>]
|
||||
ARM_ cond 0 0 0 1 U 0 W 0 Rn Rt (0) (0) (0) (0) 1 0 1 1 Rm STRH<c> <Rt>, [<Rn>, +/-<Rm>]{!}
|
||||
ARM_ cond 0 0 0 1 U 0 W 0 Rn Rt (0) (0) (0) (0) 1 1 0 1 Rm LDRD<c> <Rt>, <Rt2>, [<Rn>, +/-<Rm>]{!}
|
||||
ARM_ cond 0 0 0 1 U 0 W 0 Rn Rt (0) (0) (0) (0) 1 1 1 1 Rm STRD<c> <Rt>, <Rt2>, [<Rn>, +/-<Rm>]{!}
|
||||
ARMS cond 0 0 0 1 0 0 0 1 Rn (0) (0) (0) (0) imm5 type 0 Rm TST<c> <Rn>, <Rm>{, <shift>}
|
||||
ARM_ cond 0 0 0 1 U 0 W 1 Rn Rt (0) (0) (0) (0) 1 0 1 1 Rm LDRH<c> <Rt>, [<Rn>, +/-<Rm>]{!}
|
||||
ARM_ cond 0 0 0 1 U 0 W 1 Rn Rt (0) (0) (0) (0) 1 1 0 1 Rm LDRSB<c> <Rt>, [<Rn>, +/-<Rm>]{!}
|
||||
ARM_ cond 0 0 0 1 U 0 W 1 Rn Rt (0) (0) (0) (0) 1 1 1 1 Rm LDRSH<c> <Rt>, [<Rn>, +/-<Rm>]{!}
|
||||
ARM_ cond 0 0 0 1 0 0 1 0 (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) 0 0 0 1 Rm BX<c> <Rm>
|
||||
ARM_ cond 0 0 0 1 0 0 1 0 (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) 0 0 1 0 Rm BXJ<c> <Rm>
|
||||
ARM_ cond 0 0 0 1 0 0 1 0 (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) (1) 0 0 1 1 Rm BLX<c> <Rm>
|
||||
ARM_ cond/=1110 0 0 0 1 0 0 1 0 imm12 0 1 1 1 imm4 BKPT #<imm16>
|
||||
ARMS cond 0 0 0 1 0 0 1 1 Rn (0) (0) (0) (0) imm5 type 0 Rm TEQ<c> <Rn>, <Rm>{, <shift>}
|
||||
ARM_ cond 0 0 0 1 0 1 0 0 Rn Rt (0) (0) (0) (0) 1 0 0 1 Rm SWPB<c> <Rt>, <Rm>, [<Rn>]
|
||||
ARM_ cond 0 0 0 1 U 1 W 0 Rn Rt imm4H 1 0 1 1 imm4L STRH<c> <Rt>, [<Rn>, #+/-<imm8>]{!}
|
||||
ARM_ cond 0 0 0 1 U 1 W 0 Rn Rt imm4H 1 1 0 1 imm4L LDRD<c> <Rt>, <Rt2>, [<Rn>, #+/-<imm8>]{!}
|
||||
ARM_ cond 0 0 0 1 U 1 W 0 Rn Rt imm4H 1 1 1 1 imm4L STRD<c> <Rt>, <Rt2>, [<Rn>, #+/-<imm8>]{!}
|
||||
ARMS cond 0 0 0 1 0 1 0 1 Rn (0) (0) (0) (0) imm5 type 0 Rm CMP<c> <Rn>, <Rm>{, <shift>}
|
||||
ARMS cond 0 0 0 1 0 1 1 1 Rn (0) (0) (0) (0) imm5 type 0 Rm CMN<c> <Rn>, <Rm>{, <shift>}
|
||||
ARM_ cond 0 0 0 1 U 1 W 1 Rn Rt imm4H 1 0 1 1 imm4L LDRH<c> <Rt>, [<Rn>, #+/-<imm8>]{!}
|
||||
ARM_ cond 0 0 0 1 U 1 W 1 Rn Rt imm4H 1 1 0 1 imm4L LDRSB<c> <Rt>, [<Rn>, #+/-<imm8>]{!}
|
||||
ARM_ cond 0 0 0 1 U 1 W 1 Rn Rt imm4H 1 1 1 1 imm4L LDRSH<c> <Rt>, [<Rn>, #+/-<imm8>]{!}
|
||||
ARMS cond 0 0 0 1 1 0 0 S Rn Rd imm5 type 0 Rm ORR{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
|
||||
ARM_ cond 0 0 0 1 1 0 0 0 Rn Rd (1) (1) (1) (1) 1 0 0 1 Rt STREX<c> <Rd>, <Rt>, [<Rn>]
|
||||
ARM_ cond 0 0 0 1 1 0 0 1 Rn Rt (1) (1) (1) (1) 1 0 0 1 (1) (1) (1) (1) LDREX<c> <Rt>, [<Rn>]
|
||||
ARM_ cond 0 0 0 1 1 0 1 S (0) (0) (0) (0) Rd 0 0 0 0 0 0 0 0 Rm MOV{S}<c> <Rd>, <Rm>
|
||||
ARM_ cond 0 0 0 1 1 0 1 S (0) (0) (0) (0) Rd imm5 0 0 0 Rm LSL{S}<c> <Rd>, <Rm>, #<imm>
|
||||
ARM_ cond 0 0 0 1 1 0 1 S (0) (0) (0) (0) Rd Rm 0 0 0 1 Rn LSL{S}<c> <Rd>, <Rn>, <Rm>
|
||||
ARM_ cond 0 0 0 1 1 0 1 S (0) (0) (0) (0) Rd imm5 0 1 0 Rm LSR{S}<c> <Rd>, <Rm>, #<imm>
|
||||
ARM_ cond 0 0 0 1 1 0 1 S (0) (0) (0) (0) Rd Rm 0 0 1 1 Rn LSR{S}<c> <Rd>, <Rn>, <Rm>
|
||||
ARM_ cond 0 0 0 1 1 0 1 S (0) (0) (0) (0) Rd imm5 1 0 0 Rm ASR{S}<c> <Rd>, <Rm>, #<imm>
|
||||
ARM_ cond 0 0 0 1 1 0 1 S (0) (0) (0) (0) Rd Rm 0 1 0 1 Rn ASR{S}<c> <Rd>, <Rn>, <Rm>
|
||||
ARM_ cond 0 0 0 1 1 0 1 S (0) (0) (0) (0) Rd 0 0 0 0 0 1 1 0 Rm RRX{S}<c> <Rd>, <Rm>
|
||||
ARM_ cond 0 0 0 1 1 0 1 S (0) (0) (0) (0) Rd imm5 1 1 0 Rm ROR{S}<c> <Rd>, <Rm>, #<imm>
|
||||
ARM_ cond 0 0 0 1 1 0 1 S (0) (0) (0) (0) Rd Rm 0 1 1 1 Rn ROR{S}<c> <Rd>, <Rn>, <Rm>
|
||||
ARM_ cond 0 0 0 1 1 0 1 0 Rn Rd (1) (1) (1) (1) 1 0 0 1 Rt STREXD<c> <Rd>, <Rt>, <Rt2>, [<Rn>]
|
||||
ARM_ cond 0 0 0 1 1 0 1 1 Rn Rt (1) (1) (1) (1) 1 0 0 1 (1) (1) (1) (1) LDREXD<c> <Rt>, <Rt2>, [<Rn>]
|
||||
ARMS cond 0 0 0 1 1 1 0 S Rn Rd imm5 type 0 Rm BIC{S}<c> <Rd>, <Rn>, <Rm>{, <shift>}
|
||||
ARM_ cond 0 0 0 1 1 1 0 0 Rn Rd (1) (1) (1) (1) 1 0 0 1 Rt STREXB<c> <Rd>, <Rt>, [<Rn>]
|
||||
ARM_ cond 0 0 0 1 1 1 0 1 Rn Rt (1) (1) (1) (1) 1 0 0 1 (1) (1) (1) (1) LDREXB<c> <Rt>, [<Rn>]
|
||||
ARMS cond 0 0 0 1 1 1 1 S (0) (0) (0) (0) Rd imm5 type 0 Rm MVN{S}<c> <Rd>, <Rm>{, <shift>}
|
||||
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>, [<Rn>]
|
||||
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 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 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>
|
||||
ARM_ cond 0 0 1 0 1 1 1 S Rn Rd imm12 RSC{S}<c> <Rd>, <Rn>, #<const>
|
||||
ARM_ cond 0 0 1 1 0 0 0 0 imm4 Rd imm12 MOVW<c> <Rd>, #<imm16>
|
||||
ARM_ cond 0 0 1 1 0 0 0 1 Rn (0) (0) (0) (0) imm12 TST<c> <Rn>, #<const>
|
||||
ARM_ cond 0 0 1 1 0 0 1 0 0 0 0 0 (1) (1) (1) (1) (0) (0) (0) (0) 0 0 0 0 0 0 0 0 NOP<c>
|
||||
ARM_ cond 0 0 1 1 0 0 1 1 Rn (0) (0) (0) (0) imm12 TEQ<c> <Rn>, #<const>
|
||||
ARM_ cond 0 0 1 1 0 1 0 0 imm4 Rd imm12 MOVT<c> <Rd>, #<imm16>
|
||||
ARM_ cond 0 0 1 1 0 1 0 1 Rn (0) (0) (0) (0) imm12 CMP<c> <Rn>, #<const>
|
||||
ARM_ cond 0 0 1 1 0 1 1 1 Rn (0) (0) (0) (0) imm12 CMN<c> <Rn>, #<const>
|
||||
ARM_ cond 0 0 1 1 1 0 0 S Rn Rd imm12 ORR{S}<c> <Rd>, <Rn>, #<const>
|
||||
ARM_ cond 0 0 1 1 1 0 1 S (0) (0) (0) (0) Rd imm12 MOV{S}<c> <Rd>, #<const>
|
||||
ARM_ cond 0 0 1 1 1 1 0 S Rn Rd imm12 BIC{S}<c> <Rd>, <Rn>, #<const>
|
||||
ARM_ cond 0 0 1 1 1 1 1 S (0) (0) (0) (0) Rd imm12 MVN{S}<c> <Rd>, #<const>
|
||||
ARM_ cond 0 1 0 0 1 0 0 1 1 1 0 1 Rt 0 0 0 0 0 0 0 0 0 1 0 0 POP<c> {<Rt>}
|
||||
ARM_ cond 0 1 0 0 U 0 0 0 Rn Rt imm12 STR<c> <Rt>, [<Rn>], #+/-<imm12>
|
||||
ARM_ cond 0 1 0 0 U 0 0 1 Rn Rt imm12 LDR<c> <Rt>, [<Rn>], #+/-<imm12>
|
||||
ARM_ cond 0 1 0 0 U 0 1 0 Rn Rt imm12 STRT<c> <Rt>, [<Rn>], #+/-<imm12>
|
||||
ARM_ cond 0 1 0 0 U 0 1 1 Rn Rt imm12 LDRT<c> <Rt>, [<Rn>], #+/-<imm12>
|
||||
ARM_ cond 0 1 0 0 U 1 0 0 Rn Rt imm12 STRB<c> <Rt>, [<Rn>], #+/-<imm12>
|
||||
ARM_ cond 0 1 0 0 U 1 0 1 Rn Rt imm12 LDRB<c> <Rt>, [<Rn>], #+/-<imm12>
|
||||
ARM_ cond 0 1 0 0 U 1 1 0 Rn Rt imm12 STRBT<c> <Rt>, [<Rn>], #+/-<imm12>
|
||||
ARM_ cond 0 1 0 0 U 1 1 1 Rn Rt imm12 LDRBT<c> <Rt>, [<Rn>], #+/-<imm12>
|
||||
ARM_ cond 0 1 0 1 0 0 1 0 1 1 0 1 Rt 0 0 0 0 0 0 0 0 0 1 0 0 PUSH<c> {<Rt>}
|
||||
ARM_ cond 0 1 0 1 U 0 W 0 Rn Rt imm12 STR<c> <Rt>, [<Rn>, #+/-<imm12>]{!}
|
||||
ARM_ cond 0 1 0 1 U 0 W 1 Rn Rt imm12 LDR<c> <Rt>, [<Rn>, #+/-<imm12>]{!}
|
||||
ARM_ cond 0 1 0 1 U 1 W 0 Rn Rt imm12 STRB<c> <Rt>, [<Rn>, #+/-<imm12>]{!}
|
||||
ARM_ cond 0 1 0 1 U 1 W 1 Rn Rt imm12 LDRB<c> <Rt>, [<Rn>, #+/-<imm12>]{!}
|
||||
ARM_ cond 0 1 1 0 0 0 0 1 Rn Rd (1) (1) (1) (1) 0 1 0 1 Rm SSAX<c> <Rd>, <Rn>, <Rm>
|
||||
ARM_ cond 0 1 1 0 0 0 0 1 Rn Rd (1) (1) (1) (1) 0 1 1 1 Rm SSUB16<c> <Rd>, <Rn>, <Rm>
|
||||
ARM_ cond 0 1 1 0 0 0 0 1 Rn Rd (1) (1) (1) (1) 1 1 1 1 Rm SSUB8<c> <Rd>, <Rn>, <Rm>
|
||||
ARM_ cond 0 1 1 0 0 1 0 1 Rn Rd (1) (1) (1) (1) 0 1 0 1 Rm USAX<c> <Rd>, <Rn>, <Rm>
|
||||
ARM_ cond 0 1 1 0 0 1 0 1 Rn Rd (1) (1) (1) (1) 0 1 1 1 Rm USUB16<c> <Rd>, <Rn>, <Rm>
|
||||
ARM_ cond 0 1 1 0 0 1 0 1 Rn Rd (1) (1) (1) (1) 1 1 1 1 Rm USUB8<c> <Rd>, <Rn>, <Rm>
|
||||
ARMs cond 0 1 1 0 1 0 0 0 Rn Rd imm5 0 0 1 Rm PKHBT<c> <Rd>, <Rn>, <Rm>{, <shift>}
|
||||
ARMs cond 0 1 1 0 1 0 0 0 Rn Rd imm5 1 0 1 Rm PKHTB<c> <Rd>, <Rn>, <Rm>{, <shift>}
|
||||
ARM_ cond 0 1 1 0 1 0 0 0 1 1 1 1 Rd rotate (0) (0) 0 1 1 1 Rm SXTB16<c> <Rd>, <Rm>{, <rotation>}
|
||||
ARM_ cond 0 1 1 0 1 0 0 0 Rn Rd rotate (0) (0) 0 1 1 1 Rm SXTAB16<c> <Rd>, <Rn>, <Rm>{, <rotation>}
|
||||
ARMs cond 0 1 1 0 1 0 1 sat_imm Rd imm5 sh 0 1 Rn SSAT<c> <Rd>, #<imm>, <Rn>{, <shift>}
|
||||
ARM_ cond 0 1 1 0 1 0 1 0 sat_imm Rd (1) (1) (1) (1) 0 0 1 1 Rn SSAT16<c> <Rd>, #<imm>, <Rn>
|
||||
ARM_ cond 0 1 1 0 1 0 1 0 1 1 1 1 Rd rotate (0) (0) 0 1 1 1 Rm SXTB<c> <Rd>, <Rm>{, <rotation>}
|
||||
ARM_ cond 0 1 1 0 1 0 1 0 Rn Rd rotate (0) (0) 0 1 1 1 Rm SXTAB<c> <Rd>, <Rn>, <Rm>{, <rotation>}
|
||||
ARM_ cond 0 1 1 0 1 0 1 1 (1) (1) (1) (1) Rd (1) (1) (1) (1) 0 0 1 1 Rm REV<c> <Rd>, <Rm>
|
||||
ARM_ cond 0 1 1 0 1 0 1 1 (1) (1) (1) (1) Rd (1) (1) (1) (1) 1 0 1 1 Rm REV16<c> <Rd>, <Rm>
|
||||
ARM_ cond 0 1 1 0 1 0 1 1 1 1 1 1 Rd rotate (0) (0) 0 1 1 1 Rm SXTH<c> <Rd>, <Rm>{, <rotation>}
|
||||
ARM_ cond 0 1 1 0 1 0 1 1 Rn Rd rotate (0) (0) 0 1 1 1 Rm SXTAH<c> <Rd>, <Rn>, <Rm>{, <rotation>}
|
||||
ARM_ cond 0 1 1 0 1 1 0 0 1 1 1 1 Rd rotate (0) (0) 0 1 1 1 Rm UXTB16<c> <Rd>, <Rm>{, <rotation>}
|
||||
ARM_ cond 0 1 1 0 1 1 0 0 Rn Rd rotate (0) (0) 0 1 1 1 Rm UXTAB16<c> <Rd>, <Rn>, <Rm>{, <rotation>}
|
||||
ARMs cond 0 1 1 0 1 1 1 sat_imm Rd imm5 sh 0 1 Rn USAT<c> <Rd>, #<imm>, <Rn>{, <shift>}
|
||||
ARM_ cond 0 1 1 0 1 1 1 0 sat_imm Rd (1) (1) (1) (1) 0 0 1 1 Rn USAT16<c> <Rd>, #<imm>, <Rn>
|
||||
ARM_ cond 0 1 1 0 1 1 1 0 1 1 1 1 Rd rotate (0) (0) 0 1 1 1 Rm UXTB<c> <Rd>, <Rm>{, <rotation>}
|
||||
ARM_ cond 0 1 1 0 1 1 1 0 Rn Rd rotate (0) (0) 0 1 1 1 Rm UXTAB<c> <Rd>, <Rn>, <Rm>{, <rotation>}
|
||||
ARM_ cond 0 1 1 0 1 1 1 1 1 1 1 1 Rd rotate (0) (0) 0 1 1 1 Rm UXTH<c> <Rd>, <Rm>{, <rotation>}
|
||||
ARM_ cond 0 1 1 0 1 1 1 1 (1) (1) (1) (1) Rd (1) (1) (1) (1) 1 0 1 1 Rm REVSH<c> <Rd>, <Rm>
|
||||
ARM_ cond 0 1 1 0 1 1 1 1 Rn Rd rotate (0) (0) 0 1 1 1 Rm UXTAH<c> <Rd>, <Rn>, <Rm>{, <rotation>}
|
||||
ARMs cond 0 1 1 0 U 0 0 0 Rn Rt imm5 type 0 Rm STR<c> <Rt>, [<Rn>], +/-<Rm>{, <shift>}
|
||||
ARMs cond 0 1 1 0 U 0 0 1 Rn Rt imm5 type 0 Rm LDR<c> <Rt>, [<Rn>], +/-<Rm>{, <shift>}
|
||||
ARMs cond 0 1 1 0 U 0 1 0 Rn Rt imm5 type 0 Rm STRT<c> <Rt>, [<Rn>], +/-<Rm>{, <shift>}
|
||||
ARMs cond 0 1 1 0 U 0 1 1 Rn Rt imm5 type 0 Rm LDRT<c> <Rt>, [<Rn>], +/-<Rm>{, <shift>}
|
||||
ARMs cond 0 1 1 0 U 1 0 0 Rn Rt imm5 type 0 Rm STRB<c> <Rt>, [<Rn>], +/-<Rm>{, <shift>}
|
||||
ARMs cond 0 1 1 0 U 1 0 1 Rn Rt imm5 type 0 Rm LDRB<c> <Rt>, [<Rn>], +/-<Rm>{, <shift>}
|
||||
ARMs cond 0 1 1 0 U 1 1 0 Rn Rt imm5 type 0 Rm STRBT<c> <Rt>, [<Rn>], +/-<Rm>{, <shift>}
|
||||
ARMs cond 0 1 1 0 U 1 1 1 Rn Rt imm5 type 0 Rm LDRBT<c> <Rt>, [<Rn>], +/-<Rm>{, <shift>}
|
||||
ARMs cond 0 1 1 1 U 0 W 0 Rn Rt imm5 type 0 Rm STR<c> <Rt>, [<Rn>, +/-<Rm>{, <shift>}]{!}
|
||||
ARMs cond 0 1 1 1 U 0 W 1 Rn Rt imm5 type 0 Rm LDR<c> <Rt>, [<Rn>, +/-<Rm>{, <shift>}]{!}
|
||||
ARMs cond 0 1 1 1 U 1 W 0 Rn Rt imm5 type 0 Rm STRB<c> <Rt>, [<Rn>, +/-<Rm>{, <shift>}]{!}
|
||||
ARMs cond 0 1 1 1 U 1 W 1 Rn Rt imm5 type 0 Rm LDRB<c> <Rt>, [<Rn>, +/-<Rm>{, <shift>}]{!}
|
||||
ARM_ cond 0 1 1 1 1 0 0 0 Rd 1 1 1 1 Rm 0 0 0 1 Rn USAD8<c> <Rd>, <Rn>, <Rm>
|
||||
ARM_ cond 0 1 1 1 1 0 0 0 Rd Ra Rm 0 0 0 1 Rn USADA8<c> <Rd>, <Rn>, <Rm>, <Ra>
|
||||
ARM_ cond 0 1 1 1 1 1 0 msb Rd lsb 0 0 1 1 1 1 1 BFC<c> <Rd>, #<lsb>, #<width>
|
||||
ARM_ cond 0 1 1 1 1 1 0 msb Rd lsb 0 0 1 Rn BFI<c> <Rd>, <Rn>, #<lsb>, #<width>
|
||||
ARM_ cond 0 1 1 1 1 1 1 widthm1 Rd lsb 1 0 1 Rn UBFX<c> <Rd>, <Rn>, #<lsb>, #<width>
|
||||
ARM_ cond 1 0 0 0 0 0 W 0 Rn/=1101 register_list STMED<c> <Rn>{!}, <registers>
|
||||
ARM_ cond 1 0 0 0 0 0 W 0 Rn register_list STMDA<c> <Rn>{!}, <registers>
|
||||
ARM_ cond 1 0 0 0 0 0 W 1 Rn/=1101 register_list LDMED<c> <Rn>{!}, <registers>
|
||||
ARM_ cond 1 0 0 0 0 0 W 1 Rn register_list LDMDA<c> <Rn>{!}, <registers>
|
||||
ARM_ cond 1 0 0 0 1 0 W 0 Rn/=1101 register_list STMEA<c> <Rn>{!}, <registers>
|
||||
ARM_ cond 1 0 0 0 1 0 W 0 Rn register_list STM<c> <Rn>{!}, <registers>
|
||||
ARM_ cond 1 0 0 0 1 0 0 1 Rn/=1101 register_list LDMEA<c> <Rn>, <registers>
|
||||
ARM_ cond 1 0 0 0 1 0 1 1 1 1 0 1 register_list @ = const char* op @@ (reglist != 0) && ((reglist & (reglist - 1)) == 0)@ op,"POP","LDMEA"@ @ \op\<c> <registers>
|
||||
ARM_ cond 1 0 0 0 1 0 W 1 Rn register_list LDM<c> <Rn>{!}, <registers>
|
||||
ARM_ cond 1 0 0 1 0 0 0 0 Rn/=1101 register_list STMFD<c> <Rn>, <registers>
|
||||
ARM_ cond 1 0 0 1 0 0 1 0 1 1 0 1 register_list @ = const char* op @@ (reglist != 0) && ((reglist & (reglist - 1)) == 0)@ op,"PUSH","STMFD"@ @ \op\<c> <registers>
|
||||
ARM_ cond 1 0 0 1 0 0 W 0 Rn register_list STMDB<c> <Rn>{!}, <registers>
|
||||
ARM_ cond 1 0 0 1 0 0 W 1 Rn/=1101 register_list LDMFD<c> <Rn>{!}, <registers>
|
||||
ARM_ cond 1 0 0 1 0 0 W 1 Rn register_list LDMDB<c> <Rn>{!}, <registers>
|
||||
ARM_ cond 1 0 0 1 1 0 W 0 Rn/=1101 register_list STMFA<c> <Rn>{!}, <registers>
|
||||
ARM_ cond 1 0 0 1 1 0 W 0 Rn register_list STMIB<c> <Rn>{!}, <registers>
|
||||
ARM_ cond 1 0 0 1 1 0 W 1 Rn/=1101 register_list LDMFA<c> <Rn>{!}, <registers>
|
||||
ARM_ cond 1 0 0 1 1 0 W 1 Rn register_list LDMIB<c> <Rn>{!}, <registers>
|
||||
ARM_ cond 1 0 1 0 imm24 B<c> <label>
|
||||
ARM_ cond 1 0 1 1 imm24 BL<c> <label>
|
||||
VFPU cond 1 1 0 0 0 1 0 0 Rn Rt 1 0 1 0 0 0 M 1 Vm VMOV<c> <Sm>, <Sm1>, <Rt>, <Rn>
|
||||
VFPU cond 1 1 0 0 0 1 0 1 Rn Rt 1 0 1 0 0 0 M 1 Vm VMOV<c> <Rt>, <Rn>, <Sm>, <Sm1>
|
||||
VFPU cond 1 1 0 0 0 1 0 0 Rn Rt 1 0 1 1 0 0 M 1 Vm VMOV<c> <Dm>, <Rt>, <Rn>
|
||||
VFPU cond 1 1 0 0 0 1 0 1 Rn Rt 1 0 1 1 0 0 M 1 Vm VMOV<c> <Rt>, <Rn>, <Dm>
|
||||
INVALIDATE <4> 1 1 0 0 0 <11> 1 0 1 <9>
|
||||
INVALIDATE <4> 1 1 0 0 0 <11> 1 0 1 <9>
|
||||
INVALIDATE <4> 1 1 0 1 1 <1> 1 <9> 1 0 1 <9>
|
||||
INVALIDATE <4> 1 1 0 1 1 <1> 1 <9> 1 0 1 <9>
|
||||
VFPU cond 1 1 0 1 0 D 1 0 1 1 0 1 Vd 1 0 1 1 imm8/01 @ set --imm8@ @ FSTMX<c> <LIst>
|
||||
VFPU cond 1 1 0 1 0 D 1 0 1 1 0 1 Vd 1 0 1 sz imm8 VPUSH<c> <list>
|
||||
VFPU cond 1 1 0 1 U D 0 0 Rn Vd 1 0 1 sz imm8 VSTR<c> <Dd>, [<Rn>{, #+/-<imm>}]
|
||||
VFPU cond 1 1 0 @<2> D W 0 Rn Vd 1 0 1 1 imm8/01 @ set --imm8@ @ FSTM\(param == 0b01 ? "IA" : "DB")\X<c> <Rn>{!}, <LIst>
|
||||
VFPU cond 1 1 0 @<2> D W 0 Rn Vd 1 0 1 sz imm8 VSTM\(param == 0b01 ? "IA" : "DB")\<c> <Rn>{!}, <list>
|
||||
VFPU cond 1 1 0 0 1 D 1 1 1 1 0 1 Vd 1 0 1 1 imm8/01 @ set --imm8@ @ FLDMX<c> <LIst>
|
||||
VFPU cond 1 1 0 0 1 D 1 1 1 1 0 1 Vd 1 0 1 sz imm8 VPOP<c> <list>
|
||||
VFPU cond 1 1 0 1 0 D 0 1 1 1 1 1 Vd 1 0 1 sz 0 0 0 0 0 0 0 0 VLDR<c> <Dd>, [PC, #-0]
|
||||
VFPU cond 1 1 0 1 U D 0 1 1 1 1 1 Vd 1 0 1 sz imm8 VLDR<c> <Dd>, <label>
|
||||
VFPU cond 1 1 0 1 U D 0 1 Rn Vd 1 0 1 sz imm8 VLDR<c> <Dd>, [<Rn>{, #+/-<imm>}]
|
||||
VFPU cond 1 1 0 @<2> D W 1 Rn Vd 1 0 1 1 imm8/01 @ set --imm8@ @ FLDM\(param == 0b01 ? "IA" : "DB")\X<c> <Rn>{!}, <LIst>
|
||||
VFPU cond 1 1 0 @<2> D W 1 Rn Vd 1 0 1 sz imm8 VLDM\(param == 0b01 ? "IA" : "DB")\<c> <Rn>{!}, <list>
|
||||
INVALIDATE <4> 1 1 0 <25>
|
||||
INVALIDATE <4> 1 1 1 0 0 0 <1> 0 <8> 1 0 1 1 <1> 1 0 1 (0) (0) (0) (0)
|
||||
VFPU cond 1 1 1 0 0 0 0 0 Vn Rt 1 0 1 0 N (0) (0) 1 (0) (0) (0) (0) VMOV<c> <Sn>, <Rt>
|
||||
VFPU cond 1 1 1 0 1 1 1 0 0 0 0 1 Rt 1 0 1 0 (0) (0) (0) 1 (0) (0) (0) (0) VMSR<c> FPSCR, <Rt>
|
||||
VFPU cond 1 1 1 0 0 @<2> 0 Vd Rt 1 0 1 1 D @<2> 1 (0) (0) (0) (0) @ set uint8_t opc = (param1_2 << 2) + param2_2@ = uint8_t shift @@ (opc & 0b1000) == 0b1000@ @@ (opc & 0b1001) == 0b0001@ @@ (opc & 0b1011) == 0b0000@ shift,0,1,2,0xFF@ set uint8_t decodedImm = (opc & 0x7) >> shift@ @ VMOV<c>.\%d8 &l&l shift\ <Dd[x]>, <Rt>
|
||||
VFPU cond 1 1 1 0 1 0 Q 0 Vd Rt 1 0 1 1 D 0 0 1 (0) (0) (0) (0) VDUP<c>.32 <Qd>, <Rt>
|
||||
VFPU cond 1 1 1 0 1 0 Q 0 Vd Rt 1 0 1 1 D 0 1 1 (0) (0) (0) (0) VDUP<c>.16 <Qd>, <Rt>
|
||||
VFPU cond 1 1 1 0 1 1 Q 0 Vd Rt 1 0 1 1 D 0 0 1 (0) (0) (0) (0) VDUP<c>.8 <Qd>, <Rt>
|
||||
VFPU cond 1 1 1 0 0 0 0 1 Vn Rt 1 0 1 0 N (0) (0) 1 (0) (0) (0) (0) VMOV<c> <Rt>, <Sn>
|
||||
VFPU cond 1 1 1 0 1 1 1 1 0 0 0 1 Rt 1 0 1 0 (0) (0) (0) 1 (0) (0) (0) (0) VMRS<c> <Rt>, FPSCR
|
||||
VFPU cond 1 1 1 0 U @<2> 1 Vn Rt 1 0 1 1 N @<2> 1 (0) (0) (0) (0) @ set uint8_t opc = (u << 3) + (param1_2 << 2) + param2_2@ = uint8_t shift, size @@ (opc & 0b01000) == 0b01000@ @@ (opc & 0b01001) == 0b00001@ @@ (opc & 0b11011) == 0b00000@ shift,0,1,2,0xFF;size,0,1,2,4@ set uint8_t decodedImm = (opc & 0x7) >> shift@ @ VMOV<c>.<dt> <Rt>, <Dn[x]>
|
||||
INVALIDATE <4> 1 1 1 0 <12> 1 0 1 <4> 1 <4>
|
||||
VFPU cond 1 1 1 0 0 D 0 0 Vn Vd 1 0 1 sz N op M 0 Vm VML\(op ? "S" : "A")\<c>.F\(size ? "64" : "32")\ <Dd>, <Dn>, <Dm>
|
||||
VFPU cond 1 1 1 0 0 D 0 1 Vn Vd 1 0 1 sz N op M 0 Vm VNML\(op ? "S" : "A")\<c>.F\(size ? "64" : "32")\ <Dd>, <Dn>, <Dm>
|
||||
VFPU cond 1 1 1 0 0 D 1 0 Vn Vd 1 0 1 sz N 0 M 0 Vm VMUL<c>.F\(size ? "64" : "32")\ <Dd>, <Dn>, <Dm>
|
||||
VFPU cond 1 1 1 0 0 D 1 0 Vn Vd 1 0 1 sz N 1 M 0 Vm VNMUL<c>.F\(size ? "64" : "32")\ <Dd>, <Dn>, <Dm>
|
||||
VFPU cond 1 1 1 0 0 D 1 1 Vn Vd 1 0 1 sz N 0 M 0 Vm VADD<c>.F\(size ? "64" : "32")\ <Dd>, <Dn>, <Dm>
|
||||
VFPU cond 1 1 1 0 0 D 1 1 Vn Vd 1 0 1 sz N 1 M 0 Vm VSUB<c>.F\(size ? "64" : "32")\ <Dd>, <Dn>, <Dm>
|
||||
VFPU cond 1 1 1 0 1 D 0 0 Vn Vd 1 0 1 sz N 0 M 0 Vm VDIV<c>.F\(size ? "64" : "32")\ <Dd>, <Dn>, <Dm>
|
||||
VFPU cond 1 1 1 0 1 D 0 1 Vn Vd 1 0 1 sz N op M 0 Vm VFNM\(op ? "A" : "S")\<c>.F\(size ? "64" : "32")\ <Dd>, <Dn>, <Dm>
|
||||
VFPU cond 1 1 1 0 1 D 1 0 Vn Vd 1 0 1 sz N op M 0 Vm VFM\(op ? "S" : "A")\<c>.F\(size ? "64" : "32")\ <Dd>, <Dn>, <Dm>
|
||||
VFPU cond 1 1 1 0 1 D 1 1 @<4> Vd 1 0 1 0 (0) 0 (0) 0 @<4> @ set int8_t sign = (param1_4 >> 3) ? -1 : 1@ set uint8_t exp = ((param1_4 & 0b111) ^ 0b100)@ set float mantissa = 16 + param2_4@ set float imm = sign * (1 << exp) * mantissa / 128.@ @ VMOV<c>.F32 <Sd>, #\%fimm\
|
||||
VFPU cond 1 1 1 0 1 D 1 1 @<4> Vd 1 0 1 1 (0) 0 (0) 0 @<4> @ set int8_t sign = (param1_4 >> 3) ? -1 : 1@ set uint8_t exp = ((param1_4 & 0b111) ^ 0b100)@ set double mantissa = 16 + param2_4@ set double imm = sign * (1 << exp) * mantissa / 128.@ @ VMOV<c>.F64 <Dd>, #\%fimm\
|
||||
VFPU cond 1 1 1 0 1 D 1 1 0 0 0 0 Vd 1 0 1 sz 0 1 M 0 Vm VMOV<c>.F\(size ? "64" : "32")\ <Dd>, <Dm>
|
||||
VFPU cond 1 1 1 0 1 D 1 1 0 0 0 0 Vd 1 0 1 sz 1 1 M 0 Vm VABS<c>.F\(size ? "64" : "32")\ <Dd>, <Dm>
|
||||
VFPU cond 1 1 1 0 1 D 1 1 0 0 0 1 Vd 1 0 1 sz 0 1 M 0 Vm VNEG<c>.F\(size ? "64" : "32")\ <Dd>, <Dm>
|
||||
VFPU cond 1 1 1 0 1 D 1 1 0 0 0 1 Vd 1 0 1 sz 1 1 M 0 Vm VSQRT<c>.F\(size ? "64" : "32")\ <Dd>, <Dm>
|
||||
VFPU cond 1 1 1 0 1 D 1 1 0 0 1 0 Vd 1 0 1 (0) @<1> 1 M 0 Vm VCVT\(param ? "T" : "B")\<c>.F32.F16 <Sd>, <Sm>
|
||||
VFPU cond 1 1 1 0 1 D 1 1 0 0 1 1 Vd 1 0 1 (0) @<1> 1 M 0 Vm VCVT\(param ? "T" : "B")\<c>.F16.F32 <Sd>, <Sm>
|
||||
VFPU cond 1 1 1 0 1 D 1 1 0 1 0 0 Vd 1 0 1 sz op 1 M 0 Vm VCMP\(op ? "E" : "")\<c>.F\(size ? "64" : "32")\ <Dd>, <Dm>
|
||||
VFPU cond 1 1 1 0 1 D 1 1 0 1 0 1 Vd 1 0 1 sz op 1 (0) 0 (0) (0) (0) (0) VCMP\(op ? "E" : "")\<c>.F\(size ? "64" : "32")\ <Dd>, #0.0
|
||||
VFPU cond 1 1 1 0 1 D 1 1 0 1 1 1 Vd 1 0 1 0 1 1 M 0 Vm VCVT<c>.F64.F32 <Dd>, <Sm>
|
||||
VFPU cond 1 1 1 0 1 D 1 1 0 1 1 1 Vd 1 0 1 1 1 1 M 0 Vm VCVT<c>.F32.F64 <Sd>, <Dm>
|
||||
VFPU cond 1 1 1 0 1 D 1 1 1 0 0 0 Vd 1 0 1 sz op 1 M 0 Vm VCVT<c>.F\(size ? "64" : "32")\.\(op ? "S" : "U")\32 <Dd>, <Sm>
|
||||
VFPU cond 1 1 1 0 1 D 1 1 1 0 1 U Vd 1 0 1 sz op 1 i 0 imm4 @ set uint8_t td = (u << 2) + op + 1@ td=0b001=0b010=0b101 const char* Td Td,"S16","U16","S32","U32"@ set imm5 = (16 << op) - (imm5 >> 4) - ((imm5 & 0xF) << 1)@ @ VCVT<c>.F\(size ? "64" : "32")\.\Td\ <Dd>, <Dd>, #<imm>
|
||||
VFPU cond 1 1 1 0 1 D 1 1 1 1 0 U Vd 1 0 1 sz op 1 M 0 Vm VCVT\(op ? "" : "R")\<c>.\(u ? "U" : "S")\32.F\(size ? "64" : "32")\ <Sd>, <Dm>
|
||||
VFPU cond 1 1 1 0 1 D 1 1 1 1 1 U Vd 1 0 1 sz op 1 i 0 imm4 @ set uint8_t td = (u << 2) + op + 1@ td=0b001=0b010=0b101 const char* Td Td,"S16","U16","S32","U32"@ set imm5 = (16 << op) - (imm5 >> 4) - ((imm5 & 0xF) << 1)@ @ VCVT<c>.\Td\.F\(size ? "64" : "32")\ <Dd>, <Dd>, #<imm>
|
||||
INVALIDATE <32>
|
||||
-494
@@ -1,494 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <elf.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "box86version.h"
|
||||
#include "elfloader.h"
|
||||
#include "debug.h"
|
||||
#include "elfload_dump.h"
|
||||
#include "elfloader_private.h"
|
||||
#include "librarian.h"
|
||||
#include "x86run.h"
|
||||
#include "bridge.h"
|
||||
#include "wrapper.h"
|
||||
#include "box86context.h"
|
||||
#include "library.h"
|
||||
#include "x86emu.h"
|
||||
|
||||
void FreeElfHeader(elfheader_t** head)
|
||||
{
|
||||
if(!head || !*head)
|
||||
return;
|
||||
elfheader_t *h = *head;
|
||||
free(h->name);
|
||||
free(h->PHEntries);
|
||||
free(h->SHEntries);
|
||||
free(h->SHStrTab);
|
||||
free(h->StrTab);
|
||||
free(h->Dynamic);
|
||||
free(h->DynStr);
|
||||
free(h->SymTab);
|
||||
free(h->DynSym);
|
||||
FreeElfMemory(h);
|
||||
free(h);
|
||||
|
||||
*head = NULL;
|
||||
}
|
||||
|
||||
int CalcLoadAddr(elfheader_t* head)
|
||||
{
|
||||
head->memsz = 0;
|
||||
head->paddr = head->vaddr = (uintptr_t)~0;
|
||||
head->align = 1;
|
||||
for (int i=0; i<head->numPHEntries; ++i)
|
||||
if(head->PHEntries[i].p_type == PT_LOAD) {
|
||||
if(head->paddr > head->PHEntries[i].p_paddr)
|
||||
head->paddr = head->PHEntries[i].p_paddr;
|
||||
if(head->vaddr > head->PHEntries[i].p_vaddr)
|
||||
head->vaddr = head->PHEntries[i].p_vaddr;
|
||||
}
|
||||
|
||||
if(head->vaddr==~0 || head->paddr==~0) {
|
||||
printf_log(LOG_NONE, "Error: v/p Addr for Elf Load not set\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
head->stacksz = 1024*1024; //1M stack size default?
|
||||
head->stackalign = 4; // default align for stack
|
||||
for (int i=0; i<head->numPHEntries; ++i) {
|
||||
if(head->PHEntries[i].p_type == PT_LOAD) {
|
||||
uintptr_t phend = head->PHEntries[i].p_vaddr - head->vaddr + head->PHEntries[i].p_memsz;
|
||||
if(phend > head->memsz)
|
||||
head->memsz = phend;
|
||||
if(head->PHEntries[i].p_align > head->align)
|
||||
head->align = head->PHEntries[i].p_align;
|
||||
}
|
||||
if(head->PHEntries[i].p_type == PT_GNU_STACK) {
|
||||
if(head->stacksz < head->PHEntries[i].p_memsz)
|
||||
head->stacksz = head->PHEntries[i].p_memsz;
|
||||
if(head->stackalign < head->PHEntries[i].p_align)
|
||||
head->stackalign = head->PHEntries[i].p_align;
|
||||
}
|
||||
}
|
||||
printf_log(LOG_DEBUG, "Elf Addr(v/p)=%p/%p Memsize=0x%x (align=0x%x)\n", (void*)head->vaddr, (void*)head->paddr, head->memsz, head->align);
|
||||
printf_log(LOG_DEBUG, "Elf Stack Memsize=%u (align=%u)\n", head->stacksz, head->stackalign);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* ElfName(elfheader_t* head)
|
||||
{
|
||||
return head->name;
|
||||
}
|
||||
|
||||
int AllocElfMemory(elfheader_t* head)
|
||||
{
|
||||
#if 0
|
||||
printf_log(LOG_DEBUG, "Allocating memory for Elf \"%s\"\n", head->name);
|
||||
if (posix_memalign((void**)&head->memory, head->align, head->memsz)) {
|
||||
printf_log(LOG_NONE, "Cannot allocate aligned memory (0x%x/0x%x) for elf \"%s\"\n", head->memsz, head->align, head->name);
|
||||
return 1;
|
||||
}
|
||||
printf_log(LOG_DEBUG, "Address is %p\n", head->memory);
|
||||
printf_log(LOG_DEBUG, "And setting memory access to PROT_READ | PROT_WRITE | PROT_EXEC\n");
|
||||
if (mprotect(head->memory, head->memsz, PROT_READ | PROT_WRITE | PROT_EXEC)) {
|
||||
printf_log(LOG_NONE, "Cannot protect memory for elf \"%s\"\n", head->name);
|
||||
// memory protect error not fatal for now....
|
||||
}
|
||||
#else
|
||||
printf_log(LOG_DEBUG, "Allocating 0x%x memory @%p for Elf \"%s\"\n", head->memsz, (void*)head->vaddr, head->name);
|
||||
void* p = mmap((void*)head->vaddr, head->memsz
|
||||
, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED | MAP_ANONYMOUS | ((head->vaddr)?MAP_FIXED:0)
|
||||
, -1, 0);
|
||||
if(p==MAP_FAILED) {
|
||||
printf_log(LOG_NONE, "Cannot create memory map (@%p 0x%x/0x%x) for elf \"%s\"\n", (void*)head->vaddr, head->memsz, head->align, head->name);
|
||||
return 1;
|
||||
}
|
||||
head->memory = p;
|
||||
memset(p, 0, head->memsz);
|
||||
head->delta = (intptr_t)p - (intptr_t)head->vaddr;
|
||||
printf_log(LOG_DEBUG, "Got %p (delta=%p)\n", p, (void*)head->delta);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void FreeElfMemory(elfheader_t* head)
|
||||
{
|
||||
if(head->memory)
|
||||
munmap((void*)head->memory, head->memsz);
|
||||
}
|
||||
|
||||
int LoadElfMemory(FILE* f, elfheader_t* head)
|
||||
{
|
||||
for (int i=0; i<head->numPHEntries; ++i) {
|
||||
if(head->PHEntries[i].p_type == PT_LOAD) {
|
||||
Elf32_Phdr * e = &head->PHEntries[i];
|
||||
char* dest = (char*)e->p_paddr + head->delta;
|
||||
printf_log(LOG_DEBUG, "Loading block #%i @%p (0x%x/0x%x)\n", i, dest, e->p_filesz, e->p_memsz);
|
||||
fseek(f, e->p_offset, SEEK_SET);
|
||||
if(fread(dest, e->p_filesz, 1, f)!=1) {
|
||||
printf_log(LOG_NONE, "Fail to read PT_LOAD part #%d\n", i);
|
||||
return 1;
|
||||
}
|
||||
// zero'd difference between filesz and memsz
|
||||
if(e->p_filesz != e->p_memsz)
|
||||
memset(dest+e->p_filesz, 0, e->p_memsz - e->p_filesz);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int RelocateElfREL(lib_t *maplib, elfheader_t* head, int cnt, Elf32_Rel *rel)
|
||||
{
|
||||
for (int i=0; i<cnt; ++i) {
|
||||
Elf32_Sym *sym = &head->DynSym[ELF32_R_SYM(rel[i].r_info)];
|
||||
const char* symname = SymName(head, sym);
|
||||
uint32_t *p = (uint32_t*)(rel[i].r_offset + head->delta);
|
||||
uintptr_t offs = 0;
|
||||
uint32_t sz = 0;
|
||||
uintptr_t end = 0;
|
||||
GetGlobalSymbolStartEnd(maplib, symname, &offs, &end, 0);
|
||||
uintptr_t globoffs, globend;
|
||||
int t = ELF32_R_TYPE(rel[i].r_info);
|
||||
switch(t) {
|
||||
case R_386_NONE:
|
||||
// can be ignored
|
||||
printf_log(LOG_DEBUG, "Ignoring %s @%p (%p)\n", DumpRelType(t), p, (void*)(p?(*p):0));
|
||||
break;
|
||||
case R_386_PC32:
|
||||
offs = (*p) + (offs - (uintptr_t)p);
|
||||
printf_log(LOG_DEBUG, "Apply R_386_PC32 @%p with sym=%s (%p -> %p)\n", p, symname, *(void**)p, (void*)(*(uintptr_t*)p+offs));
|
||||
*p += offs;
|
||||
break;
|
||||
case R_386_GLOB_DAT:
|
||||
// Look for same symbol already loaded but not in self
|
||||
if (GetGlobalSymbolStartEnd(maplib, symname, &globoffs, &globend, 1)) {
|
||||
offs = globoffs;
|
||||
end = globend;
|
||||
}
|
||||
if (!offs) {
|
||||
printf_log(LOG_NONE, "Error: Symbol %s not found, cannot apply R_386_GLOB_DAT @%p (%p)\n", symname, p, *(void**)p);
|
||||
// return -1;
|
||||
} else {
|
||||
printf_log(LOG_DEBUG, "Apply R_386_GLOB_DAT @%p (%p -> %p) on sym=%s\n", p, (void*)(p?(*p):0), (void*)offs, symname);
|
||||
*p = offs;
|
||||
}
|
||||
break;
|
||||
case R_386_RELATIVE:
|
||||
printf_log(LOG_DEBUG, "Apply R_386_RELATIVE @%p (%p -> %p)\n", p, *(void**)p, (void*)((*p)+head->delta));
|
||||
*p += head->delta;
|
||||
break;
|
||||
case R_386_32:
|
||||
if (!offs) {
|
||||
printf_log(LOG_NONE, "Error: Symbol %s not found, cannot apply R_386_32 @%p (%p)\n", symname, p, *(void**)p);
|
||||
// return -1;
|
||||
} else {
|
||||
printf_log(LOG_DEBUG, "Apply R_386_32 @%p with sym=%s (%p -> %p)\n", p, symname, *(void**)p, (void*)(offs+*(uint32_t*)p));
|
||||
*p += offs;
|
||||
}
|
||||
break;
|
||||
//case R_386_TLS_DTPMOD32:
|
||||
// try to use _dl_next_tls_modid() ?
|
||||
case R_386_TLS_DTPOFF32:
|
||||
case R_386_JMP_SLOT:
|
||||
if (!offs) {
|
||||
printf_log(LOG_NONE, "Error: Symbol %s not found, cannot apply R_386_JMP_SLOT @%p (%p)\n", symname, p, *(void**)p);
|
||||
// return -1;
|
||||
} else {
|
||||
if(p) {
|
||||
printf_log(LOG_DEBUG, "Apply R_386_JMP_SLOT @%p with sym=%s (%p -> %p)\n", p, symname, *(void**)p, (void*)offs);
|
||||
*p = offs;
|
||||
} else {
|
||||
printf_log(LOG_NONE, "Warning, Symbol %s found, but Jump Slot Offset is NULL \n", symname);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case R_386_COPY:
|
||||
if(offs) {
|
||||
GetGlobalSymbolStartEnd(maplib, symname, &offs, &end, 1); // get original copy if any
|
||||
printf_log(LOG_DEBUG, "Apply R_386_COPY @%p with sym=%s, @%p size=%d (", p, symname, (void*)offs, sym->st_size);
|
||||
memmove(p, (void*)offs, sym->st_size);
|
||||
if(LOG_DEBUG<=box86_log) {
|
||||
uint32_t*k = (uint32_t*)p;
|
||||
for (int i=0; i<sym->st_size; i+=4, ++k)
|
||||
printf_log(LOG_DEBUG, "%s0x%08X", i?" ":"", *k);
|
||||
printf_log(LOG_DEBUG, ")\n");
|
||||
}
|
||||
} else {
|
||||
printf_log(LOG_NONE, "Error: Symbol %s not found, cannot apply R_386_COPY @%p (%p)\n", symname, p, *(void**)p);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
printf_log(LOG_INFO, "Warning, don't know of to handle rel #%d %s (%p)\n", i, DumpRelType(ELF32_R_TYPE(rel[i].r_info)), p);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int RelocateElfRELA(lib_t *maplib, elfheader_t* head, int cnt, Elf32_Rela *rela)
|
||||
{
|
||||
for (int i=0; i<cnt; ++i) {
|
||||
Elf32_Sym *sym = &head->DynSym[ELF32_R_SYM(rela[i].r_info)];
|
||||
const char* symname = SymName(head, sym);
|
||||
uint32_t *p = (uint32_t*)(rela[i].r_offset + head->delta);
|
||||
uintptr_t offs = 0;
|
||||
uint32_t sz = 0;
|
||||
uintptr_t end = 0;
|
||||
switch(ELF32_R_TYPE(rela[i].r_info)) {
|
||||
case R_386_NONE:
|
||||
case R_386_PC32:
|
||||
// can be ignored
|
||||
break;
|
||||
case R_386_COPY:
|
||||
GetGlobalSymbolStartEnd(maplib, symname, &offs, &end,1);
|
||||
if(offs) {
|
||||
// add r_addend to p?
|
||||
printf_log(LOG_DEBUG, "Apply R_386_COPY @%p with sym=%s, @%p size=%d\n", p, symname, (void*)offs, sym->st_size);
|
||||
memcpy(p, (void*)(offs+rela[i].r_addend), sym->st_size);
|
||||
} else {
|
||||
printf_log(LOG_NONE, "Error: Symbol %s not found, cannot apply R_386_COPY @%p (%p)\n", symname, p, *(void**)p);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
printf_log(LOG_INFO, "Warning, don't know of to handle rel #%d %s on %s\n", i, DumpRelType(ELF32_R_TYPE(rela[i].r_info)), symname);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int RelocateElf(lib_t *maplib, elfheader_t* head)
|
||||
{
|
||||
if(head->rel) {
|
||||
int cnt = head->relsz / head->relent;
|
||||
DumpRelTable(head, cnt, (Elf32_Rel *)(head->rel + head->delta), "Rel");
|
||||
printf_log(LOG_DEBUG, "Applying %d Relocation(s) for %s\n", cnt, head->name);
|
||||
if(RelocateElfREL(maplib, head, cnt, (Elf32_Rel *)(head->rel + head->delta)))
|
||||
return -1;
|
||||
}
|
||||
if(head->rela) {
|
||||
int cnt = head->relasz / head->relaent;
|
||||
DumpRelATable(head, cnt, (Elf32_Rela *)(head->rela + head->delta), "RelA");
|
||||
printf_log(LOG_DEBUG, "Applying %d Relocation(s) with Addend for %s\n", cnt, head->name);
|
||||
if(RelocateElfRELA(maplib, head, cnt, (Elf32_Rela *)(head->rela + head->delta)))
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int RelocateElfPlt(box86context_t* context, lib_t *maplib, elfheader_t* head)
|
||||
{
|
||||
if(head->pltrel) {
|
||||
int cnt = head->pltsz / head->pltent;
|
||||
if(head->pltrel==DT_REL) {
|
||||
DumpRelTable(head, cnt, (Elf32_Rel *)(head->jmprel + head->delta), "PLT");
|
||||
printf_log(LOG_DEBUG, "Applying %d PLT Relocation(s) for %s\n", cnt, head->name);
|
||||
if(RelocateElfREL(maplib, head, cnt, (Elf32_Rel *)(head->jmprel + head->delta)))
|
||||
return -1;
|
||||
} else if(head->pltrel==DT_RELA) {
|
||||
DumpRelATable(head, cnt, (Elf32_Rela *)(head->jmprel + head->delta), "PLT");
|
||||
printf_log(LOG_DEBUG, "Applying %d PLT Relocation(s) with Addend for %s\n", cnt, head->name);
|
||||
if(RelocateElfRELA(maplib, head, cnt, (Elf32_Rela *)(head->jmprel + head->delta)))
|
||||
return -1;
|
||||
}
|
||||
if(head->gotplt) {
|
||||
if(pltResolver==~0) {
|
||||
pltResolver = AddBridge(context->system, vFEpp, PltResolver); // should be vFEuu
|
||||
}
|
||||
*(uintptr_t*)(head->gotplt+head->delta+8) = pltResolver;
|
||||
printf_log(LOG_DEBUG, "PLT Resolver injected at %p\n", (void*)(head->gotplt+head->delta+8));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CalcStack(elfheader_t* elf, uint32_t* stacksz, int* stackalign)
|
||||
{
|
||||
if(*stacksz < elf->stacksz)
|
||||
*stacksz = elf->stacksz;
|
||||
if(*stackalign < elf->stackalign)
|
||||
*stackalign = elf->stackalign;
|
||||
}
|
||||
|
||||
Elf32_Sym* GetFunction(elfheader_t* h, const char* name)
|
||||
{
|
||||
// TODO: create a hash on named to avoid this loop
|
||||
for (int i=0; i<h->numSymTab; ++i) {
|
||||
if(h->SymTab[i].st_info == 18) { // TODO: this "18" is probably defined somewhere
|
||||
const char * symname = h->StrTab+h->SymTab[i].st_name;
|
||||
if(strcmp(symname, name)==0) {
|
||||
return h->SymTab+i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uintptr_t GetFunctionAddress(elfheader_t* h, const char* name)
|
||||
{
|
||||
Elf32_Sym* sym = GetFunction(h, name);
|
||||
if(sym) return sym->st_value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uintptr_t GetEntryPoint(lib_t* maplib, elfheader_t* h)
|
||||
{
|
||||
uintptr_t ep = h->entrypoint + h->delta;
|
||||
printf_log(LOG_DEBUG, "Entry Point is %p\n", (void*)ep);
|
||||
if(box86_log>=LOG_DUMP) {
|
||||
printf_log(LOG_DUMP, "(short) Dump of Entry point\n");
|
||||
int sz = 64;
|
||||
uintptr_t lastbyte = GetLastByte(h);
|
||||
if (ep + sz > lastbyte)
|
||||
sz = lastbyte - ep;
|
||||
DumpBinary((char*)ep, sz);
|
||||
}
|
||||
/*
|
||||
// but instead of regular entrypoint, lets grab "main", it will be easier to manage I guess
|
||||
uintptr_t m = FindSymbol(maplib, "main");
|
||||
if(m) {
|
||||
ep = m;
|
||||
printf_log(LOG_DEBUG, "Using \"main\" as Entry Point @%p\n", ep);
|
||||
if(box86_log>=LOG_DUMP) {
|
||||
printf_log(LOG_DUMP, "(short) Dump of Entry point\n");
|
||||
int sz = 64;
|
||||
uintptr_t lastbyte = GetLastByte(h);
|
||||
if (ep + sz > lastbyte)
|
||||
sz = lastbyte - ep;
|
||||
DumpBinary((char*)ep, sz);
|
||||
}
|
||||
}
|
||||
*/
|
||||
return ep;
|
||||
}
|
||||
|
||||
uintptr_t GetLastByte(elfheader_t* h)
|
||||
{
|
||||
return (uintptr_t)h->memory + h->delta + h->memsz;
|
||||
}
|
||||
|
||||
void AddGlobalsSymbols(lib_t *maplib, kh_mapsymbols_t* mapsymbols, elfheader_t* h)
|
||||
{
|
||||
// info == 161 => OBJECT UNIQUE
|
||||
// info == 33 => OBJECT WEAK
|
||||
printf_log(LOG_DUMP, "Will look for Symbol to add in SymTable(%d)\n", h->numSymTab);
|
||||
for (int i=0; i<h->numSymTab; ++i) {
|
||||
const char * symname = h->StrTab+h->SymTab[i].st_name;
|
||||
if(((h->SymTab[i].st_info & 2) || (h->SymTab[i].st_info == 17)
|
||||
|| (h->SymTab[i].st_info == 161 && !FindGlobalSymbol(maplib, symname))
|
||||
|| (h->SymTab[i].st_info == 33)
|
||||
)
|
||||
&& (h->SymTab[i].st_other==0) && (h->SymTab[i].st_shndx!=0)) {
|
||||
if(!h->SymTab[i].st_value && FindGlobalSymbol(maplib, symname))
|
||||
break;
|
||||
uintptr_t offs = h->SymTab[i].st_value + h->delta;
|
||||
uint32_t sz = h->SymTab[i].st_size;
|
||||
printf_log(LOG_DUMP, "Adding Symbol \"%s\" with offset=%p sz=%d\n", symname, (void*)offs, sz);
|
||||
AddSymbol(mapsymbols, symname, offs, sz);
|
||||
}
|
||||
}
|
||||
|
||||
printf_log(LOG_DUMP, "Will look for Symbol to add in DynSym (%d)\n", h->numDynSym);
|
||||
for (int i=0; i<h->numDynSym; ++i) {
|
||||
const char * symname = h->DynStr+h->DynSym[i].st_name;
|
||||
if(((h->DynSym[i].st_info & 2) || (h->DynSym[i].st_info == 17)
|
||||
|| (h->DynSym[i].st_info == 161 && !FindGlobalSymbol(maplib, symname))
|
||||
|| (h->DynSym[i].st_info == 33)
|
||||
)
|
||||
&& (h->DynSym[i].st_other==0) && (h->DynSym[i].st_shndx!=0 && h->DynSym[i].st_shndx<62521)) {
|
||||
if(!h->DynSym[i].st_value && FindGlobalSymbol(maplib, symname))
|
||||
break;
|
||||
uintptr_t offs = h->DynSym[i].st_value + h->delta;
|
||||
uint32_t sz = h->DynSym[i].st_size;
|
||||
printf_log(LOG_DUMP, "Adding Symbol \"%s\" with offset=%p sz=%d\n", symname, (void*)offs, sz);
|
||||
AddSymbol(mapsymbols, symname, offs, sz);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
$ORIGIN – Provides the directory the object was loaded from. This token is typical
|
||||
used for locating dependencies in unbundled packages. For more details of this
|
||||
token expansion, see “Locating Associated Dependencies”
|
||||
$OSNAME – Expands to the name of the operating system (see the uname(1) man
|
||||
page description of the -s option). For more details of this token expansion, see
|
||||
“System Specific Shared Objects”
|
||||
$OSREL – Expands to the operating system release level (see the uname(1) man
|
||||
page description of the -r option). For more details of this token expansion, see
|
||||
“System Specific Shared Objects”
|
||||
$PLATFORM – Expands to the processor type of the current machine (see the
|
||||
uname(1) man page description of the -i option). For more details of this token
|
||||
expansion, see “System Specific Shared Objects”
|
||||
*/
|
||||
int LoadNeededLib(elfheader_t* h, lib_t *maplib, box86context_t *box86, x86emu_t* emu)
|
||||
{
|
||||
DumpDynamicNeeded(h);
|
||||
// reverse order on needed libs
|
||||
for (int i=h->numDynamic-1; i>=0; --i)
|
||||
if(h->Dynamic[i].d_tag==DT_NEEDED) {
|
||||
char *needed = h->DynStrTab+h->delta+h->Dynamic[i].d_un.d_val;
|
||||
// TODO: Add LD_LIBRARY_PATH and RPATH Handling
|
||||
if(AddNeededLib(maplib, needed, box86, emu)) {
|
||||
printf_log(LOG_INFO, "Error loading needed lib: \"%s\"\n", needed);
|
||||
return 1; //error...
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RunElfInit(elfheader_t* h, x86emu_t *emu)
|
||||
{
|
||||
if(h->init_done || !h->initentry)
|
||||
return;
|
||||
uintptr_t p = h->initentry + h->delta;
|
||||
box86context_t* context = GetEmuContext(emu);
|
||||
if(context->deferedInit) {
|
||||
if(context->deferedInitSz==context->deferedInitCap) {
|
||||
context->deferedInitCap += 4;
|
||||
context->deferedInitList = (elfheader_t**)realloc(context->deferedInitList, context->deferedInitCap*sizeof(elfheader_t*));
|
||||
}
|
||||
context->deferedInitList[context->deferedInitSz++] = h;
|
||||
return;
|
||||
}
|
||||
printf_log(LOG_DEBUG, "Calling Init for %s @%p\n", ElfName(h), (void*)p);
|
||||
EmuCall(emu, p);
|
||||
h->init_done = 1;
|
||||
return;
|
||||
}
|
||||
void RunDeferedElfInit(x86emu_t *emu)
|
||||
{
|
||||
box86context_t* context = GetEmuContext(emu);
|
||||
if(!context->deferedInit)
|
||||
return;
|
||||
context->deferedInit = 0;
|
||||
if(!context->deferedInitList)
|
||||
return;
|
||||
for (int i=0; i<context->deferedInitSz; ++i)
|
||||
RunElfInit(context->deferedInitList[i], emu);
|
||||
free(context->deferedInitList);
|
||||
context->deferedInitList = NULL;
|
||||
context->deferedInitCap = context->deferedInitSz = 0;
|
||||
}
|
||||
void RunElfFini(elfheader_t* h, x86emu_t *emu)
|
||||
{
|
||||
if(h->fini_done || !h->finientry)
|
||||
return;
|
||||
uintptr_t p = h->finientry + h->delta;
|
||||
printf_log(LOG_DEBUG, "Calling Fini for %s @%p\n", ElfName(h), (void*)p);
|
||||
EmuCall(emu, p);
|
||||
h->fini_done = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
uintptr_t GetElfInit(elfheader_t* h)
|
||||
{
|
||||
return h->initentry + h->delta;
|
||||
}
|
||||
uintptr_t GetElfFini(elfheader_t* h)
|
||||
{
|
||||
return h->finientry + h->delta;
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
#ifndef __ELF_LOADER_H_
|
||||
#define __ELF_LOADER_H_
|
||||
#include <stdio.h>
|
||||
|
||||
typedef struct elfheader_s elfheader_t;
|
||||
typedef struct lib_s lib_t;
|
||||
typedef struct kh_mapsymbols_s kh_mapsymbols_t;
|
||||
typedef struct box86context_s box86context_t;
|
||||
typedef struct x86emu_s x86emu_t;
|
||||
|
||||
void* LoadAndCheckElfHeader(FILE* f, const char* name, int exec); // exec : 0 = lib, 1 = exec
|
||||
void FreeElfHeader(elfheader_t** head);
|
||||
const char* ElfName(elfheader_t* head);
|
||||
|
||||
// return 0 if OK
|
||||
int CalcLoadAddr(elfheader_t* head);
|
||||
int AllocElfMemory(elfheader_t* head);
|
||||
void FreeElfMemory(elfheader_t* head);
|
||||
int LoadElfMemory(FILE* f, elfheader_t* head);
|
||||
int RelocateElf(lib_t *maplib, elfheader_t* head);
|
||||
int RelocateElfPlt(box86context_t* context, lib_t *maplib, elfheader_t* head);
|
||||
void CalcStack(elfheader_t* h, uint32_t* stacksz, int* stackalign);
|
||||
uintptr_t GetEntryPoint(lib_t* maplib, elfheader_t* h);
|
||||
uintptr_t GetLastByte(elfheader_t* h);
|
||||
void AddGlobalsSymbols(lib_t *maplib, kh_mapsymbols_t* mapsymbols, elfheader_t* h);
|
||||
int LoadNeededLib(elfheader_t* h, lib_t *maplib, box86context_t* box86, x86emu_t* emu);
|
||||
uintptr_t GetElfInit(elfheader_t* h);
|
||||
uintptr_t GetElfFini(elfheader_t* h);
|
||||
void RunElfInit(elfheader_t* h, x86emu_t *emu);
|
||||
void RunElfFini(elfheader_t* h, x86emu_t *emu);
|
||||
void RunDeferedElfInit(x86emu_t *emu);
|
||||
|
||||
#endif //__ELF_LOADER_H_
|
||||
-271
@@ -1,271 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <elf.h>
|
||||
|
||||
#include "box86version.h"
|
||||
#include "elfloader.h"
|
||||
#include "debug.h"
|
||||
#include "elfload_dump.h"
|
||||
#include "elfloader_private.h"
|
||||
|
||||
#ifndef PN_XNUM
|
||||
#define PN_XNUM (0xffff)
|
||||
#endif
|
||||
|
||||
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);
|
||||
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));
|
||||
}
|
||||
*SH = calloc(1, s->sh_size);
|
||||
fseek(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);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int FindSection(Elf32_Shdr *s, int n, char* SHStrTab, const char* name)
|
||||
{
|
||||
for (int i=0; i<n; ++i) {
|
||||
if(s[i].sh_type!=SHT_NULL)
|
||||
if(!strcmp(SHStrTab+s[i].sh_name, name))
|
||||
return i;
|
||||
}
|
||||
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)
|
||||
{
|
||||
int n = FindSection(s, size, SHStrTab, name);
|
||||
printf_log(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) {
|
||||
if(*what && num)
|
||||
*num = s[n].sh_size / sizeof(Elf32_Sym);
|
||||
} else if(type==SHT_DYNAMIC) {
|
||||
if(*what && num)
|
||||
*num = s[n].sh_size / sizeof(Elf32_Dyn);
|
||||
}
|
||||
}
|
||||
|
||||
void* LoadAndCheckElfHeader(FILE* f, const char* name, int exec)
|
||||
{
|
||||
Elf32_Ehdr header;
|
||||
if(fread(&header, sizeof(Elf32_Ehdr), 1, f)!=1) {
|
||||
printf_log(LOG_INFO, "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]);
|
||||
return NULL;
|
||||
}
|
||||
if(header.e_ident[EI_CLASS]!=ELFCLASS32) {
|
||||
printf_log(LOG_INFO, "Not an 32bits ELF (%d)\n", header.e_ident[EI_CLASS]);
|
||||
return NULL;
|
||||
}
|
||||
if(header.e_ident[EI_DATA]!=ELFDATA2LSB) {
|
||||
printf_log(LOG_INFO, "Not an 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]);
|
||||
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]);
|
||||
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);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(header.e_machine != EM_386) {
|
||||
printf_log(LOG_INFO, "Not an i386 ELF (%d)\n", header.e_machine);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(header.e_entry == 0) {
|
||||
printf_log(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));
|
||||
return NULL;
|
||||
}
|
||||
if(header.e_shentsize != sizeof(Elf32_Shdr)) {
|
||||
printf_log(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);
|
||||
h->entrypoint = header.e_entry;
|
||||
h->numPHEntries = header.e_phnum;
|
||||
h->numSHEntries = header.e_shnum;
|
||||
h->SHIdx = header.e_shstrndx;
|
||||
// special cases for nums
|
||||
if(h->numSHEntries == 0) {
|
||||
printf_log(LOG_DEBUG, "Read number of Sections in 1st Section\n");
|
||||
// read 1st section header and grab actual number from here
|
||||
fseek(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");
|
||||
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));
|
||||
fseek(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");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(h->numPHEntries == PN_XNUM) {
|
||||
printf_log(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));
|
||||
fseek(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");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(h->SHIdx == SHN_XINDEX) {
|
||||
printf_log(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);
|
||||
FreeElfHeader(&h);
|
||||
return NULL;
|
||||
}
|
||||
// load Section table
|
||||
printf_log(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;
|
||||
}
|
||||
if(box86_log>=LOG_DUMP) DumpMainHeader(&header, h);
|
||||
|
||||
LoadNamedSection(f, h->SHEntries, h->numSHEntries, h->SHStrTab, ".strtab", "SymTab Strings", SHT_STRTAB, (void**)&h->StrTab, NULL);
|
||||
LoadNamedSection(f, h->SHEntries, h->numSHEntries, h->SHStrTab, ".symtab", "SymTab", SHT_SYMTAB, (void**)&h->SymTab, &h->numSymTab);
|
||||
if(box86_log>=LOG_DUMP && h->SymTab) DumpSymTab(h);
|
||||
|
||||
LoadNamedSection(f, h->SHEntries, h->numSHEntries, h->SHStrTab, ".dynamic", "Dynamic", SHT_DYNAMIC, (void**)&h->Dynamic, &h->numDynamic);
|
||||
if(box86_log>=LOG_DUMP && h->Dynamic) DumpDynamicSections(h);
|
||||
// grab DT_REL & DT_RELA stuffs
|
||||
// also grab the DT_STRTAB string table
|
||||
{
|
||||
for (int i=0; i<h->numDynamic; ++i) {
|
||||
if(h->Dynamic[i].d_tag == DT_REL)
|
||||
h->rel = h->Dynamic[i].d_un.d_ptr;
|
||||
else if(h->Dynamic[i].d_tag == DT_RELSZ)
|
||||
h->relsz = h->Dynamic[i].d_un.d_val;
|
||||
else if(h->Dynamic[i].d_tag == DT_RELENT)
|
||||
h->relent = h->Dynamic[i].d_un.d_val;
|
||||
else if(h->Dynamic[i].d_tag == DT_RELA)
|
||||
h->rela = h->Dynamic[i].d_un.d_ptr;
|
||||
else if(h->Dynamic[i].d_tag == DT_RELASZ)
|
||||
h->relasz = h->Dynamic[i].d_un.d_val;
|
||||
else if(h->Dynamic[i].d_tag == DT_RELAENT)
|
||||
h->relaent = h->Dynamic[i].d_un.d_val;
|
||||
else if(h->Dynamic[i].d_tag == DT_PLTREL)
|
||||
h->pltrel = h->Dynamic[i].d_un.d_val;
|
||||
else if(h->Dynamic[i].d_tag == DT_PLTRELSZ)
|
||||
h->pltsz = h->Dynamic[i].d_un.d_val;
|
||||
else if(h->Dynamic[i].d_tag == DT_JMPREL)
|
||||
h->jmprel = h->Dynamic[i].d_un.d_val;
|
||||
else if(h->Dynamic[i].d_tag == DT_STRTAB)
|
||||
h->DynStrTab = (char*)(h->Dynamic[i].d_un.d_ptr);
|
||||
else if(h->Dynamic[i].d_tag == DT_STRSZ)
|
||||
h->szDynStrTab = h->Dynamic[i].d_un.d_val;
|
||||
}
|
||||
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));
|
||||
FreeElfHeader(&h);
|
||||
return NULL;
|
||||
}
|
||||
printf_log(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));
|
||||
FreeElfHeader(&h);
|
||||
return NULL;
|
||||
}
|
||||
printf_log(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) {
|
||||
h->pltent = sizeof(Elf32_Rel);
|
||||
} 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);
|
||||
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);
|
||||
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);
|
||||
}
|
||||
if(h->DynStrTab && h->szDynStrTab) {
|
||||
//DumpDynamicNeeded(h); cannot dump now, it's not loaded yet
|
||||
}
|
||||
}
|
||||
// look for PLT Offset
|
||||
int ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".got.plt");
|
||||
if(ii) {
|
||||
h->gotplt = h->SHEntries[ii].sh_addr;
|
||||
printf_log(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;
|
||||
printf_log(LOG_DEBUG, "The GOT Table is at address %p\n", (void*)h->got);
|
||||
}
|
||||
// look for .init entry point
|
||||
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".init");
|
||||
if(ii) {
|
||||
h->initentry = h->SHEntries[ii].sh_addr;
|
||||
printf_log(LOG_DEBUG, "The .init is at address %p\n", (void*)h->initentry);
|
||||
}
|
||||
// look for .fini entry point
|
||||
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".fini");
|
||||
if(ii) {
|
||||
h->finientry = h->SHEntries[ii].sh_addr;
|
||||
printf_log(LOG_DEBUG, "The .fini is at address %p\n", (void*)h->finientry);
|
||||
}
|
||||
|
||||
LoadNamedSection(f, h->SHEntries, h->numSHEntries, h->SHStrTab, ".dynstr", "DynSym Strings", SHT_STRTAB, (void**)&h->DynStr, NULL);
|
||||
LoadNamedSection(f, h->SHEntries, h->numSHEntries, h->SHStrTab, ".dynsym", "DynSym", SHT_DYNSYM, (void**)&h->DynSym, &h->numDynSym);
|
||||
if(box86_log>=LOG_DUMP && h->DynSym) DumpDynSym(h);
|
||||
|
||||
return h;
|
||||
}
|
||||
@@ -183,6 +183,7 @@ const char* DumpRelType(int t)
|
||||
GO(R_386_GOTOFF);
|
||||
GO(R_386_GOTPC);
|
||||
GO(R_386_PC8);
|
||||
GO(R_386_TLS_TPOFF);
|
||||
GO(R_386_TLS_GD_32);
|
||||
GO(R_386_TLS_DTPMOD32);
|
||||
GO(R_386_TLS_DTPOFF32);
|
||||
@@ -283,6 +284,22 @@ void DumpDynamicNeeded(elfheader_t *h)
|
||||
}
|
||||
}
|
||||
|
||||
void DumpDynamicRPath(elfheader_t *h)
|
||||
{
|
||||
if(box86_log>=LOG_DUMP && h->DynStrTab) {
|
||||
printf_log(LOG_DUMP, "ELF Dump DT_RPATH/DT_RUNPATH=====\n");
|
||||
for (int i=0; i<h->numDynamic; ++i) {
|
||||
if(h->Dynamic[i].d_tag==DT_RPATH) {
|
||||
printf_log(LOG_DUMP, " RPATH : %s\n", h->DynStrTab+h->Dynamic[i].d_un.d_val + h->delta);
|
||||
}
|
||||
if(h->Dynamic[i].d_tag==DT_RUNPATH) {
|
||||
printf_log(LOG_DUMP, " RUNPATH : %s\n", h->DynStrTab+h->Dynamic[i].d_un.d_val + h->delta);
|
||||
}
|
||||
}
|
||||
printf_log(LOG_DUMP, "=====ELF Dump DT_RPATH/DT_RUNPATH\n");
|
||||
}
|
||||
}
|
||||
|
||||
void DumpRelTable(elfheader_t *h, int cnt, Elf32_Rel *rel, const char* name)
|
||||
{
|
||||
if(box86_log>=LOG_DUMP) {
|
||||
Executable
+1155
File diff suppressed because it is too large.
Load diff
@@ -1,8 +1,18 @@
|
||||
#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;
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
struct elfheader_s {
|
||||
char* name;
|
||||
char* path; // Resolved path to file
|
||||
int numPHEntries;
|
||||
Elf32_Phdr *PHEntries;
|
||||
int numSHEntries;
|
||||
@@ -25,7 +35,11 @@ struct elfheader_s {
|
||||
|
||||
uintptr_t entrypoint;
|
||||
uintptr_t initentry;
|
||||
uintptr_t initarray;
|
||||
int initarray_sz;
|
||||
uintptr_t finientry;
|
||||
uintptr_t finiarray;
|
||||
int finiarray_sz;
|
||||
|
||||
uintptr_t rel;
|
||||
int relsz;
|
||||
@@ -38,7 +52,10 @@ struct elfheader_s {
|
||||
int pltent;
|
||||
uint32_t pltrel;
|
||||
uintptr_t gotplt;
|
||||
uintptr_t pltgot;
|
||||
uintptr_t got;
|
||||
uintptr_t text;
|
||||
int textsz;
|
||||
|
||||
uintptr_t paddr;
|
||||
uintptr_t vaddr;
|
||||
@@ -46,11 +63,24 @@ struct elfheader_s {
|
||||
uint32_t memsz;
|
||||
uint32_t stacksz;
|
||||
int stackalign;
|
||||
uint32_t tlssize;
|
||||
int tlsalign;
|
||||
|
||||
int32_t tlsbase; // the base of the tlsdata in the global tlsdata (always negative)
|
||||
|
||||
int init_done;
|
||||
int fini_done;
|
||||
|
||||
char* memory; // char* and not void* to allow math on memory pointer
|
||||
void** multiblock;
|
||||
uintptr_t* multiblock_offs;
|
||||
uint32_t* multiblock_size;
|
||||
int multiblock_n;
|
||||
#ifdef DYNAREC
|
||||
dynablocklist_t *blocks;
|
||||
#endif
|
||||
library_t *lib;
|
||||
needed_libs_t *neededlibs;
|
||||
};
|
||||
|
||||
#define R_386_NONE 0
|
||||
@@ -65,4 +95,6 @@ struct elfheader_s {
|
||||
#define R_386_GOTOFF 9
|
||||
#define R_386_GOTPC 10
|
||||
|
||||
elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec);
|
||||
|
||||
#endif //__ELFLOADER_PRIVATE_H_
|
||||
Executable
+303
@@ -0,0 +1,303 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <elf.h>
|
||||
|
||||
#include "box86version.h"
|
||||
#include "elfloader.h"
|
||||
#include "debug.h"
|
||||
#include "elfload_dump.h"
|
||||
#include "elfloader_private.h"
|
||||
|
||||
#ifndef PN_XNUM
|
||||
#define PN_XNUM (0xffff)
|
||||
#endif
|
||||
|
||||
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);
|
||||
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));
|
||||
}
|
||||
*SH = 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);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int FindSection(Elf32_Shdr *s, int n, char* SHStrTab, const char* name)
|
||||
{
|
||||
for (int i=0; i<n; ++i) {
|
||||
if(s[i].sh_type!=SHT_NULL)
|
||||
if(!strcmp(SHStrTab+s[i].sh_name, name))
|
||||
return i;
|
||||
}
|
||||
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)
|
||||
{
|
||||
int n = FindSection(s, size, SHStrTab, name);
|
||||
printf_log(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) {
|
||||
if(*what && num)
|
||||
*num = s[n].sh_size / sizeof(Elf32_Sym);
|
||||
} else if(type==SHT_DYNAMIC) {
|
||||
if(*what && num)
|
||||
*num = s[n].sh_size / sizeof(Elf32_Dyn);
|
||||
}
|
||||
}
|
||||
|
||||
elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
{
|
||||
Elf32_Ehdr header;
|
||||
if(fread(&header, sizeof(Elf32_Ehdr), 1, f)!=1) {
|
||||
printf_log(LOG_INFO, "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]);
|
||||
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");
|
||||
} else {
|
||||
printf_log(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]);
|
||||
return NULL;
|
||||
}
|
||||
if(header.e_ident[EI_VERSION]!=EV_CURRENT) {
|
||||
printf_log(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]);
|
||||
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);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(header.e_machine != EM_386) {
|
||||
printf_log(LOG_INFO, "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");
|
||||
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));
|
||||
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));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
elfheader_t *h = calloc(1, sizeof(elfheader_t));
|
||||
h->name = strdup(name);
|
||||
h->entrypoint = header.e_entry;
|
||||
h->numPHEntries = header.e_phnum;
|
||||
h->numSHEntries = header.e_shnum;
|
||||
h->SHIdx = header.e_shstrndx;
|
||||
if(header.e_shentsize!=0) {
|
||||
// special cases for nums
|
||||
if(h->numSHEntries == 0) {
|
||||
printf_log(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");
|
||||
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));
|
||||
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");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(h->numPHEntries == PN_XNUM) {
|
||||
printf_log(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));
|
||||
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");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(header.e_shentsize!=0) {
|
||||
if(h->SHIdx == SHN_XINDEX) {
|
||||
printf_log(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);
|
||||
FreeElfHeader(&h);
|
||||
return NULL;
|
||||
}
|
||||
// load Section table
|
||||
printf_log(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;
|
||||
}
|
||||
if(box86_log>=LOG_DUMP) DumpMainHeader(&header, h);
|
||||
|
||||
LoadNamedSection(f, h->SHEntries, h->numSHEntries, h->SHStrTab, ".strtab", "SymTab Strings", SHT_STRTAB, (void**)&h->StrTab, NULL);
|
||||
LoadNamedSection(f, h->SHEntries, h->numSHEntries, h->SHStrTab, ".symtab", "SymTab", SHT_SYMTAB, (void**)&h->SymTab, &h->numSymTab);
|
||||
if(box86_log>=LOG_DUMP && h->SymTab) DumpSymTab(h);
|
||||
|
||||
LoadNamedSection(f, h->SHEntries, h->numSHEntries, h->SHStrTab, ".dynamic", "Dynamic", SHT_DYNAMIC, (void**)&h->Dynamic, &h->numDynamic);
|
||||
if(box86_log>=LOG_DUMP && h->Dynamic) DumpDynamicSections(h);
|
||||
// grab DT_REL & DT_RELA stuffs
|
||||
// also grab the DT_STRTAB string table
|
||||
{
|
||||
for (int i=0; i<h->numDynamic; ++i) {
|
||||
if(h->Dynamic[i].d_tag == DT_REL)
|
||||
h->rel = h->Dynamic[i].d_un.d_ptr;
|
||||
else if(h->Dynamic[i].d_tag == DT_RELSZ)
|
||||
h->relsz = h->Dynamic[i].d_un.d_val;
|
||||
else if(h->Dynamic[i].d_tag == DT_RELENT)
|
||||
h->relent = h->Dynamic[i].d_un.d_val;
|
||||
else if(h->Dynamic[i].d_tag == DT_RELA)
|
||||
h->rela = h->Dynamic[i].d_un.d_ptr;
|
||||
else if(h->Dynamic[i].d_tag == DT_RELASZ)
|
||||
h->relasz = h->Dynamic[i].d_un.d_val;
|
||||
else if(h->Dynamic[i].d_tag == DT_RELAENT)
|
||||
h->relaent = h->Dynamic[i].d_un.d_val;
|
||||
else if(h->Dynamic[i].d_tag == DT_PLTGOT)
|
||||
h->pltgot = h->Dynamic[i].d_un.d_val;
|
||||
else if(h->Dynamic[i].d_tag == DT_PLTREL)
|
||||
h->pltrel = h->Dynamic[i].d_un.d_val;
|
||||
else if(h->Dynamic[i].d_tag == DT_PLTRELSZ)
|
||||
h->pltsz = h->Dynamic[i].d_un.d_val;
|
||||
else if(h->Dynamic[i].d_tag == DT_JMPREL)
|
||||
h->jmprel = h->Dynamic[i].d_un.d_val;
|
||||
else if(h->Dynamic[i].d_tag == DT_STRTAB)
|
||||
h->DynStrTab = (char*)(h->Dynamic[i].d_un.d_ptr);
|
||||
else if(h->Dynamic[i].d_tag == DT_STRSZ)
|
||||
h->szDynStrTab = h->Dynamic[i].d_un.d_val;
|
||||
}
|
||||
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));
|
||||
FreeElfHeader(&h);
|
||||
return NULL;
|
||||
}
|
||||
printf_log(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));
|
||||
FreeElfHeader(&h);
|
||||
return NULL;
|
||||
}
|
||||
printf_log(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) {
|
||||
h->pltent = sizeof(Elf32_Rel);
|
||||
} 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);
|
||||
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);
|
||||
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);
|
||||
}
|
||||
if(h->DynStrTab && h->szDynStrTab) {
|
||||
//DumpDynamicNeeded(h); cannot dump now, it's not loaded yet
|
||||
}
|
||||
}
|
||||
// look for PLT Offset
|
||||
int ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".got.plt");
|
||||
if(ii) {
|
||||
h->gotplt = h->SHEntries[ii].sh_addr;
|
||||
printf_log(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;
|
||||
printf_log(LOG_DEBUG, "The GOT Table is at address %p\n", (void*)h->got);
|
||||
}
|
||||
// look for .init entry point
|
||||
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".init");
|
||||
if(ii) {
|
||||
h->initentry = h->SHEntries[ii].sh_addr;
|
||||
printf_log(LOG_DEBUG, "The .init is at address %p\n", (void*)h->initentry);
|
||||
}
|
||||
// and .init_array
|
||||
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".init_array");
|
||||
if(ii) {
|
||||
h->initarray_sz = h->SHEntries[ii].sh_size / sizeof(Elf32_Addr);
|
||||
h->initarray = (uintptr_t)(h->SHEntries[ii].sh_addr);
|
||||
printf_log(LOG_DEBUG, "The .init_array is at address %p, and have %d elements\n", (void*)h->initarray, h->initarray_sz);
|
||||
}
|
||||
// look for .fini entry point
|
||||
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".fini");
|
||||
if(ii) {
|
||||
h->finientry = h->SHEntries[ii].sh_addr;
|
||||
printf_log(LOG_DEBUG, "The .fini is at address %p\n", (void*)h->finientry);
|
||||
}
|
||||
// and .fini_array
|
||||
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".fini_array");
|
||||
if(ii) {
|
||||
h->finiarray_sz = h->SHEntries[ii].sh_size / sizeof(Elf32_Addr);
|
||||
h->finiarray = (uintptr_t)(h->SHEntries[ii].sh_addr);
|
||||
printf_log(LOG_DEBUG, "The .fini_array is at address %p, and have %d elements\n", (void*)h->finiarray, h->finiarray_sz);
|
||||
}
|
||||
// grab .text 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);
|
||||
}
|
||||
|
||||
LoadNamedSection(f, h->SHEntries, h->numSHEntries, h->SHStrTab, ".dynstr", "DynSym Strings", SHT_STRTAB, (void**)&h->DynStr, NULL);
|
||||
LoadNamedSection(f, h->SHEntries, h->numSHEntries, h->SHStrTab, ".dynsym", "DynSym", SHT_DYNSYM, (void**)&h->DynSym, &h->numDynSym);
|
||||
if(box86_log>=LOG_DUMP && h->DynSym) DumpDynSym(h);
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
Executable
+93
@@ -0,0 +1,93 @@
|
||||
// ModRM utilities macros
|
||||
#define getecommon(A, T) \
|
||||
if(!(nextop&0xC0)) { \
|
||||
if((nextop&7)==4) { \
|
||||
uint8_t sib = F8; \
|
||||
uintptr_t base = ((sib&0x7)==5)?(F32):(emu->regs[(sib&0x7)].dword[0]); \
|
||||
base += (emu->sbiidx[(sib>>3)&7]->sdword[0] << (sib>>6)); \
|
||||
A = (T*)base; \
|
||||
} else if((nextop&7)==5) { \
|
||||
A = (T*)(F32); \
|
||||
} else { \
|
||||
A = (T*)(emu->regs[nextop&7].dword[0]); \
|
||||
} \
|
||||
} else { \
|
||||
uintptr_t base; \
|
||||
if((nextop&7)==4) { \
|
||||
uint8_t sib = F8; \
|
||||
base = emu->regs[(sib&0x7)].dword[0]; \
|
||||
base += (emu->sbiidx[(sib>>3)&7]->sdword[0] << (sib>>6)); \
|
||||
} else { \
|
||||
base = emu->regs[(nextop&0x7)].dword[0]; \
|
||||
} \
|
||||
base+=(nextop&0x80)?(F32S):(F8S); \
|
||||
A = (T*)base; \
|
||||
}
|
||||
#define getecommono(A, T, O) \
|
||||
if(!(nextop&0xC0)) { \
|
||||
if((nextop&7)==4) { \
|
||||
uint8_t sib = F8; \
|
||||
uintptr_t base = ((sib&0x7)==5)?(F32):(emu->regs[(sib&0x7)].dword[0]); \
|
||||
base += (emu->sbiidx[(sib>>3)&7]->sdword[0] << (sib>>6)); \
|
||||
A = (T*)(base+O); \
|
||||
} else if((nextop&7)==5) { \
|
||||
A = (T*)(F32+O); \
|
||||
} else { \
|
||||
A = (T*)(emu->regs[nextop&7].dword[0]+O); \
|
||||
} \
|
||||
} else { \
|
||||
uintptr_t base; \
|
||||
if((nextop&7)==4) { \
|
||||
uint8_t sib = F8; \
|
||||
base = emu->regs[(sib&0x7)].dword[0]; \
|
||||
base += (emu->sbiidx[(sib>>3)&7]->sdword[0] << (sib>>6)); \
|
||||
} else { \
|
||||
base = emu->regs[(nextop&0x7)].dword[0]; \
|
||||
} \
|
||||
base+=(nextop&0x80)?(F32S):(F8S); \
|
||||
A = (T*)(base+O); \
|
||||
}
|
||||
#define geteb(A) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
A = (reg32_t*)&emu->regs[(nextop&3)].byte[((nextop&0x4)>>2)]; \
|
||||
} else getecommon(A, reg32_t)
|
||||
#define getebo(A, O) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
A = (reg32_t*)&emu->regs[(nextop&3)].byte[((nextop&0x4)>>2)]; \
|
||||
} else getecommono(A, reg32_t, O)
|
||||
#define geted(A) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
A = &emu->regs[(nextop&7)]; \
|
||||
} else getecommon(A, reg32_t)
|
||||
#define getedo(A, O) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
A = &emu->regs[(nextop&7)]; \
|
||||
} else getecommono(A, reg32_t, O)
|
||||
#define getem(A) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
A = &emu->mmx[(nextop&7)]; \
|
||||
} else getecommon(A, mmx_regs_t)
|
||||
#define getex(A) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
A = &emu->xmm[(nextop&7)]; \
|
||||
} else getecommon(A, sse_regs_t)
|
||||
// Macros for ModR/M gets
|
||||
#define GET_EB geteb(oped)
|
||||
#define GET_ED geted(oped)
|
||||
#define GET_ED_OFFS(o) getedo(oped, o)
|
||||
#define GET_EB_OFFS(o) getebo(oped, o)
|
||||
#define GET_EM getem(opem)
|
||||
#define GET_EX getex(opex)
|
||||
#define EB oped
|
||||
#define ED oped
|
||||
#define EM opem
|
||||
#define EX opex
|
||||
#define GB emu->regs[(nextop>>3)&3].byte[(nextop>>5)&0x1]
|
||||
#define GD emu->regs[((nextop&0x38)>>3)]
|
||||
#define GM emu->mmx[((nextop&0x38)>>3)]
|
||||
#define GX emu->xmm[((nextop&0x38)>>3)]
|
||||
|
||||
// Alias
|
||||
#define GET_EW GET_ED
|
||||
#define EW ED
|
||||
#define GW GD
|
||||
Executable
+1298
File diff suppressed because it is too large.
Load diff
+136
-13
@@ -25,11 +25,30 @@
|
||||
GO(0x30, xor) /* XOR 0x31 ~> 0x35 */
|
||||
//GO(0x38, cmp) /* CMP 0x39 ~> 0x3D */
|
||||
#undef GO
|
||||
_66_0x06: /* PUSH ES */
|
||||
Push16(emu, emu->segs[_ES]);
|
||||
NEXT;
|
||||
_66_0x07: /* POP ES */
|
||||
emu->segs[_ES] = Pop16(emu); // no check, no use....
|
||||
emu->segs_clean[_ES] = 0;
|
||||
NEXT;
|
||||
|
||||
_66_0x0F: /* 66 0f prefix */
|
||||
#include "run660f.h"
|
||||
|
||||
_66_0x26: /* ES: */
|
||||
// ignored
|
||||
opcode = F8;
|
||||
goto *opcodes66[opcode];
|
||||
_66_0x2E: /* CS: */
|
||||
// ignored
|
||||
NEXT;
|
||||
opcode = F8;
|
||||
goto *opcodes66[opcode];
|
||||
_66_0x36: /* SS: */
|
||||
// ignored
|
||||
opcode = F8;
|
||||
goto *opcodes66[opcode];
|
||||
|
||||
_66_0x39:
|
||||
nextop = F8;
|
||||
GET_EW;
|
||||
@@ -66,17 +85,67 @@
|
||||
tmp8u = opcode&7;
|
||||
emu->regs[tmp8u].word[0] = dec16(emu, emu->regs[tmp8u].word[0]);
|
||||
NEXT;
|
||||
_66_0x50:
|
||||
_66_0x51:
|
||||
_66_0x52:
|
||||
_66_0x53:
|
||||
_66_0x54:
|
||||
_66_0x55:
|
||||
_66_0x56:
|
||||
_66_0x57: /* PUSH Reg */
|
||||
tmp8u = opcode&7;
|
||||
Push16(emu, emu->regs[tmp8u].word[0]);
|
||||
NEXT;
|
||||
_66_0x58:
|
||||
_66_0x59:
|
||||
_66_0x5A:
|
||||
_66_0x5B:
|
||||
_66_0x5C:
|
||||
_66_0x5D:
|
||||
_66_0x5E:
|
||||
_66_0x5F: /* POP Reg */
|
||||
tmp8u = opcode&7;
|
||||
emu->regs[tmp8u].word[0] = Pop16(emu);
|
||||
NEXT;
|
||||
_66_0x60: /* PUSHA */
|
||||
tmp16u = R_SP;
|
||||
Push16(emu, R_AX);
|
||||
Push16(emu, R_CX);
|
||||
Push16(emu, R_DX);
|
||||
Push16(emu, R_BX);
|
||||
Push16(emu, tmp16u);
|
||||
Push16(emu, R_BP);
|
||||
Push16(emu, R_SI);
|
||||
Push16(emu, R_DI);
|
||||
NEXT;
|
||||
_66_0x61: /* POPA */
|
||||
R_DI = Pop16(emu);
|
||||
R_SI = Pop16(emu);
|
||||
R_BP = Pop16(emu);
|
||||
R_ESP+=2; // POP ESP
|
||||
R_BX = Pop16(emu);
|
||||
R_DX = Pop16(emu);
|
||||
R_CX = Pop16(emu);
|
||||
R_AX = Pop16(emu);
|
||||
NEXT;
|
||||
|
||||
_66_0x66:
|
||||
goto _0x66; // 0x66 0x66 => can remove one 0x66
|
||||
|
||||
_66_0x68: /* PUSH u16 */
|
||||
tmp16u = F16;
|
||||
Push16(emu, tmp16u);
|
||||
NEXT;
|
||||
_66_0x69: /* IMUL Gw,Ew,Iw */
|
||||
nextop = F8;
|
||||
GET_EW;
|
||||
tmp16u = F16;
|
||||
GW.word[0] = imul16(emu, EW->word[0], tmp16u);
|
||||
NEXT;
|
||||
|
||||
_66_0x6A: /* PUSH Ib (as signed word) */
|
||||
tmp16s = F8S;
|
||||
Push16(emu, (uint16_t)tmp16s);
|
||||
NEXT;
|
||||
_66_0x6B: /* IMUL Gw,Ew,Ib */
|
||||
nextop = F8;
|
||||
GET_EW;
|
||||
@@ -131,26 +200,56 @@
|
||||
GET_EW;
|
||||
GW.word[0] = EW->word[0];
|
||||
NEXT;
|
||||
_66_0x8C: /* MOV Ew,Seg */
|
||||
nextop = F8;
|
||||
GET_EW;
|
||||
EW->word[0] = emu->segs[(nextop&38)>>3];
|
||||
NEXT;
|
||||
|
||||
_66_0x8E: /* MOV Seg,Ew */
|
||||
nextop = F8;
|
||||
GET_EW;
|
||||
emu->segs[((nextop&0x38)>>3)] = EW->word[0];
|
||||
emu->segs_clean[((nextop&0x38)>>3)] = 0;
|
||||
NEXT;
|
||||
_66_0x8F: /* POP Ew */
|
||||
nextop = F8;
|
||||
GET_EW;
|
||||
EW->dword[0] = Pop16(emu);
|
||||
EW->word[0] = Pop16(emu);
|
||||
NEXT;
|
||||
_66_0x90: /* NOP */
|
||||
NEXT;
|
||||
|
||||
_66_0x92: /* XCHG DX,AX */
|
||||
_66_0x91:
|
||||
_66_0x92:
|
||||
_66_0x93:
|
||||
_66_0x94:
|
||||
_66_0x95:
|
||||
_66_0x96:
|
||||
_66_0x97: /* XCHG reg,EAX */
|
||||
tmp16u = R_AX;
|
||||
R_AX = R_DX;
|
||||
R_DX = tmp16u;
|
||||
R_AX = emu->regs[opcode&7].word[0];
|
||||
emu->regs[opcode&7].word[0] = tmp16u;
|
||||
NEXT;
|
||||
|
||||
_66_0x98: /* CBW */
|
||||
emu->regs[_AX].sword[0] = emu->regs[_AX].sbyte[0];
|
||||
NEXT;
|
||||
_66_0x99: /* CWD */
|
||||
R_DX=(R_AX & 0x8000)?0xFFFF:0x0000;
|
||||
R_DX=((R_AX & 0x8000)?0xFFFF:0x0000);
|
||||
NEXT;
|
||||
|
||||
_66_0x9C: /* PUSHFW */
|
||||
CHECK_FLAGS(emu);
|
||||
PackFlags(emu);
|
||||
Push16(emu, (uint16_t)emu->packed_eflags.x32);
|
||||
NEXT;
|
||||
_66_0x9D: /* POPFW */
|
||||
CHECK_FLAGS(emu);
|
||||
PackFlags(emu);
|
||||
emu->packed_eflags.x32 &=0xffff0000;
|
||||
emu->packed_eflags.x32 |= (Pop16(emu) & 0x3F7FD7) | 0x2;
|
||||
UnpackFlags(emu);
|
||||
NEXT;
|
||||
|
||||
_66_0xA1: /* MOV AX,Ow */
|
||||
@@ -174,6 +273,11 @@
|
||||
R_ESI += tmp8s;
|
||||
cmp16(emu, tmp16u2, tmp16u);
|
||||
NEXT;
|
||||
|
||||
_66_0xA9: /* TEST AX,Iw */
|
||||
test16(emu, R_AX, F16);
|
||||
NEXT;
|
||||
|
||||
_66_0xAB: /* STOSW */
|
||||
tmp8s = ACCESS_FLAG(F_DF)?-2:+2;
|
||||
*(uint16_t*)R_EDI = R_AX;
|
||||
@@ -241,7 +345,7 @@
|
||||
NEXT;
|
||||
|
||||
_66_0xD9:
|
||||
emu->old_ip = old_ip;
|
||||
emu->old_ip = R_EIP;
|
||||
R_EIP = ip;
|
||||
Run66D9(emu);
|
||||
ip = R_EIP;
|
||||
@@ -249,7 +353,7 @@
|
||||
NEXT;
|
||||
|
||||
_66_0xDD:
|
||||
emu->old_ip = old_ip;
|
||||
emu->old_ip = R_EIP;
|
||||
R_EIP = ip;
|
||||
Run66DD(emu);
|
||||
ip = R_EIP;
|
||||
@@ -263,6 +367,14 @@
|
||||
tmp8s = ACCESS_FLAG(F_DF)?-2:+2;
|
||||
tmp32u = R_ECX;
|
||||
switch(nextop) {
|
||||
case 0xA4: /* REP MOVSB */
|
||||
while(tmp32u) {
|
||||
--tmp32u;
|
||||
*(uint8_t*)R_EDI = *(uint8_t*)R_ESI;
|
||||
R_EDI += tmp8s;
|
||||
R_ESI += tmp8s;
|
||||
}
|
||||
break;
|
||||
case 0xA5: /* REP MOVSW */
|
||||
while(tmp32u) {
|
||||
--tmp32u;
|
||||
@@ -272,6 +384,8 @@
|
||||
}
|
||||
break;
|
||||
case 0xA7: /* REP(N)Z CMPSW */
|
||||
tmp16u = 0;
|
||||
tmp16u2 = 0;
|
||||
while(tmp32u) {
|
||||
--tmp32u;
|
||||
tmp16u = *(uint16_t*)R_EDI;
|
||||
@@ -298,6 +412,7 @@
|
||||
}
|
||||
break;
|
||||
case 0xAF: /* REP(N)Z SCASW */
|
||||
tmp16u = 0;
|
||||
while(tmp32u) {
|
||||
--tmp32u;
|
||||
tmp16u = *(uint16_t*)R_EDI;
|
||||
@@ -341,6 +456,14 @@
|
||||
break;
|
||||
}
|
||||
NEXT;
|
||||
_66_0xF8: /* CLC */
|
||||
CHECK_FLAGS(emu);
|
||||
CLEAR_FLAG(F_CF);
|
||||
NEXT;
|
||||
_66_0xF9: /* STC */
|
||||
CHECK_FLAGS(emu);
|
||||
SET_FLAG(F_CF);
|
||||
NEXT;
|
||||
|
||||
_66_0xFF: /* GRP 5 Ew */
|
||||
nextop = F8;
|
||||
@@ -352,8 +475,11 @@
|
||||
case 1: /* DEC Ed */
|
||||
EW->word[0] = dec16(emu, EW->word[0]);
|
||||
break;
|
||||
case 6:
|
||||
Push16(emu, EW->word[0]);
|
||||
break;
|
||||
default:
|
||||
emu->old_ip = old_ip;
|
||||
emu->old_ip = R_EIP;
|
||||
R_EIP = ip;
|
||||
printf_log(LOG_NONE, "Illegal Opcode 66 %02X %02X\n", opcode, nextop);
|
||||
emu->quit=1;
|
||||
@@ -361,6 +487,3 @@
|
||||
goto fini;
|
||||
}
|
||||
NEXT;
|
||||
|
||||
|
||||
|
||||
@@ -101,7 +101,16 @@
|
||||
GET_EX;
|
||||
memcpy(EX, &GX, 16); // unaligned...
|
||||
NEXT;
|
||||
|
||||
_6f_0x12: /* MOVLPD Gx, Eq */
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
GX.q[0] = *(uint64_t*)ED;
|
||||
NEXT;
|
||||
_6f_0x13: /* MOVLPD Eq, Gx */
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
*(uint64_t*)ED = GX.q[0];
|
||||
NEXT;
|
||||
_6f_0x14: /* UNPCKLPD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
@@ -150,12 +159,33 @@
|
||||
|
||||
|
||||
_6f_0x2C: /* CVTTPD2PI Gm, Ex */
|
||||
_6f_0x2D: /* CVTPD2PI Gm, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
GM.sd[0] = EX->d[0];
|
||||
GM.sd[1] = EX->d[1];
|
||||
NEXT;
|
||||
_6f_0x2D: /* CVTPD2PI Gm, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
switch(emu->round) {
|
||||
case ROUND_Nearest:
|
||||
GM.sd[0] = floor(EX->d[0]+0.5);
|
||||
GM.sd[1] = floor(EX->d[1]+0.5);
|
||||
break;
|
||||
case ROUND_Down:
|
||||
GM.sd[0] = floor(EX->d[0]);
|
||||
GM.sd[1] = floor(EX->d[1]);
|
||||
break;
|
||||
case ROUND_Up:
|
||||
GM.sd[0] = ceil(EX->d[0]);
|
||||
GM.sd[1] = ceil(EX->d[1]);
|
||||
break;
|
||||
case ROUND_Chop:
|
||||
GM.sd[0] = EX->d[0];
|
||||
GM.sd[1] = EX->d[1];
|
||||
break;
|
||||
}
|
||||
NEXT;
|
||||
_6f_0x2E: /* UCOMISD Gx, Ex */
|
||||
// no special check...
|
||||
_6f_0x2F: /* COMISD Gx, Ex */
|
||||
@@ -171,6 +201,69 @@
|
||||
} else {
|
||||
SET_FLAG(F_ZF); CLEAR_FLAG(F_PF); CLEAR_FLAG(F_CF);
|
||||
}
|
||||
CLEAR_FLAG(F_OF); CLEAR_FLAG(F_AF); CLEAR_FLAG(F_SF);
|
||||
NEXT;
|
||||
|
||||
_6f_0x38: // these are some SSE3 opcodes
|
||||
opcode = F8;
|
||||
switch(opcode) {
|
||||
case 0x00: /* PSHUFB */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
eax1 = GX;
|
||||
for (int i=0; i<15; ++i) {
|
||||
if(EX->ub[i]&128)
|
||||
GX.ub[i] = 0;
|
||||
else
|
||||
GX.ub[i] = eax1.ub[EX->ub[i]&15];
|
||||
}
|
||||
break;
|
||||
case 0x04: /* PMADDUBSW Gx,Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for (int i=0; i<8; ++i) {
|
||||
tmp32s = (int32_t)(GX.ub[i*2+0])*EX->ub[i*2+0] + (int32_t)(GX.ub[i*2+1])*EX->ub[i*2+1];
|
||||
GX.sw[i] = (tmp32s>32767)?32767:tmp32s; // no negative value to test
|
||||
}
|
||||
break;
|
||||
default:
|
||||
goto _default;
|
||||
}
|
||||
NEXT;
|
||||
|
||||
_6f_0x3A: // these are some SSE3 opcodes
|
||||
opcode = F8;
|
||||
switch(opcode) {
|
||||
case 0x0F: // PALIGNR
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
tmp8u = F8;
|
||||
if(tmp8u>31)
|
||||
{EX->q[0] = EX->q[1] = 0;}
|
||||
else if(tmp8u>15) {
|
||||
tmp8u=(tmp8u-16)*8;
|
||||
if (tmp8u < 64) {
|
||||
GX.q[0] = (EX->q[0] >> tmp8u) | (EX->q[1] << (64 - tmp8u));
|
||||
GX.q[1] = (EX->q[1] >> tmp8u);
|
||||
} else {
|
||||
GX.q[0] = EX->q[1] >> (tmp8u - 64);
|
||||
GX.q[1] = 0;
|
||||
}
|
||||
} else {
|
||||
tmp8u*=8;
|
||||
if (tmp8u < 64) {
|
||||
GX.q[0] = (GX.q[0] >> tmp8u) | (GX.q[1] << (64 - tmp8u));
|
||||
GX.q[1] = (GX.q[1] >> tmp8u) | (EX->q[0] << (64-tmp8u));
|
||||
} else {
|
||||
tmp8u -= 64;
|
||||
GX.q[0] = (GX.q[1] >> tmp8u) | (EX->q[0] << (64 - tmp8u));
|
||||
GX.q[1] = (EX->q[0] >> tmp8u) | (EX->q[1] >> (64 - tmp8u));
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
goto _default;
|
||||
}
|
||||
NEXT;
|
||||
|
||||
_6f_0x50: /* MOVMSKPD Gd, Ex */
|
||||
@@ -290,36 +383,44 @@
|
||||
GX.ud[2] = GX.ud[1];
|
||||
GX.ud[1] = EX->ud[0];
|
||||
NEXT;
|
||||
|
||||
_6f_0x63: /* PACKSSWB Gx,Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=0; i<8; ++i)
|
||||
GX.sb[i] = (GX.sw[i]<-128)?-128:((GX.sw[i]>127)?127:GX.sw[i]);
|
||||
for(int i=0; i<8; ++i)
|
||||
GX.sb[8+i] = (EX->sw[i]<-128)?-128:((EX->sw[i]>127)?127:EX->sw[i]);
|
||||
NEXT;
|
||||
_6f_0x64: /* PCMPGTB Gx,Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=0; i<16; ++i)
|
||||
GX.sb[i] = (GX.sb[i]>EX->sb[i])?0xFF:0x00;
|
||||
GX.ub[i] = (GX.sb[i]>EX->sb[i])?0xFF:0x00;
|
||||
NEXT;
|
||||
_6f_0x65: /* PCMPGTW Gx,Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=0; i<8; ++i)
|
||||
GX.sw[i] = (GX.sw[i]>EX->sw[i])?0xFFFF:0x0000;
|
||||
GX.uw[i] = (GX.sw[i]>EX->sw[i])?0xFFFF:0x0000;
|
||||
NEXT;
|
||||
_6f_0x66: /* PCMPGTD Gx,Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=0; i<4; ++i)
|
||||
GX.sd[i] = (GX.sd[i]>EX->sd[i])?0xFFFFFFFF:0x00000000;
|
||||
GX.ud[i] = (GX.sd[i]>EX->sd[i])?0xFFFFFFFF:0x00000000;
|
||||
NEXT;
|
||||
_6f_0x67: /* PACKUSWB */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=0; i<4; ++i)
|
||||
for(int i=0; i<8; ++i)
|
||||
GX.ub[i] = (GX.sw[i]<0)?0:((GX.sw[i]>0xff)?0xff:GX.sw[i]);
|
||||
for(int i=0; i<4; ++i)
|
||||
GX.ub[4+i] = (EX->sw[i]<0)?0:((EX->sw[i]>0xff)?0xff:EX->sw[i]);
|
||||
for(int i=0; i<8; ++i)
|
||||
GX.ub[8+i] = (EX->sw[i]<0)?0:((EX->sw[i]>0xff)?0xff:EX->sw[i]);
|
||||
NEXT;
|
||||
_6f_0x68: /* PUNPCKHBW Gx,Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
if(EX==&GX) {eax1 = GX; EX = &eax1;} // copy is needed
|
||||
for(int i=0; i<8; ++i)
|
||||
GX.ub[2 * i] = GX.ub[i + 8];
|
||||
for(int i=0; i<8; ++i)
|
||||
@@ -328,6 +429,7 @@
|
||||
_6f_0x69: /* PUNPCKHWD Gx,Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
if(EX==&GX) {eax1 = GX; EX = &eax1;} // copy is needed
|
||||
for(int i=0; i<4; ++i)
|
||||
GX.uw[2 * i] = GX.uw[i + 4];
|
||||
for(int i=0; i<4; ++i)
|
||||
@@ -336,6 +438,7 @@
|
||||
_6f_0x6A: /* PUNPCKHDQ Gx,Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
if(EX==&GX) {eax1 = GX; EX = &eax1;} // copy is needed
|
||||
GX.ud[0] = GX.ud[2];
|
||||
GX.ud[2] = GX.ud[3];
|
||||
GX.ud[1] = EX->ud[2];
|
||||
@@ -344,6 +447,7 @@
|
||||
_6f_0x6B: /* PACKSSDW Gx,Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
if(EX==&GX) {eax1 = GX; EX = &eax1;} // copy is needed
|
||||
for(int i=0; i<4; ++i)
|
||||
GX.sw[i] = (GX.sd[i]<-32768)?-32768:((GX.sd[i]>32767)?32767:GX.sd[i]);
|
||||
for(int i=0; i<4; ++i)
|
||||
@@ -376,31 +480,26 @@
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
tmp8u = F8;
|
||||
if(&GX!=EX)
|
||||
for (int i=0; i<4; ++i)
|
||||
GX.ud[i] = EX->ud[(tmp8u>>(i*2))&3];
|
||||
else {
|
||||
for (int i=0; i<4; ++i)
|
||||
eax1.ud[i] = EX->ud[(tmp8u>>(i*2))&3];
|
||||
memcpy(&GX, &eax1, sizeof(eax1));
|
||||
}
|
||||
if(EX==&GX) {eax1 = GX; EX = &eax1;} // copy is needed
|
||||
for (int i=0; i<4; ++i)
|
||||
GX.ud[i] = EX->ud[(tmp8u>>(i*2))&3];
|
||||
NEXT;
|
||||
_6f_0x71: /* GRP */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
switch((nextop>>3)&7) {
|
||||
case 2: /* PSRLW Gx, Ib */
|
||||
case 2: /* PSRLW Ex, Ib */
|
||||
tmp8u = F8;
|
||||
if(tmp8u>15)
|
||||
{EX->q[0] = EX->q[1] = 0;}
|
||||
else
|
||||
for (int i=0; i<8; ++i) EX->uw[i] >>= tmp8u;
|
||||
break;
|
||||
case 4: /* PSRAW Gx, Ib */
|
||||
case 4: /* PSRAW Ex, Ib */
|
||||
tmp8u = F8;
|
||||
for (int i=0; i<8; ++i) EX->sw[i] >>= tmp8u;
|
||||
break;
|
||||
case 6: /* PSLLW Gx, Ib */
|
||||
case 6: /* PSLLW Ex, Ib */
|
||||
tmp8u = F8;
|
||||
if(tmp8u>15)
|
||||
{EX->q[0] = EX->q[1] = 0;}
|
||||
@@ -453,10 +552,14 @@
|
||||
if(tmp8u>15)
|
||||
{EX->q[0] = EX->q[1] = 0;}
|
||||
else {
|
||||
for (int i=tmp8u; i<16; ++i)
|
||||
EX->ub[i-tmp8u] = EX->ub[i];
|
||||
for (int i=16-tmp8u; i<16; ++i)
|
||||
EX->ub[i] = 0;
|
||||
tmp8u*=8;
|
||||
if (tmp8u < 64) {
|
||||
EX->q[0] = (EX->q[0] >> tmp8u) | (EX->q[1] << (64 - tmp8u));
|
||||
EX->q[1] = (EX->q[1] >> tmp8u);
|
||||
} else {
|
||||
EX->q[0] = EX->q[1] >> (tmp8u - 64);
|
||||
EX->q[1] = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 6: /* PSLLQ Ex, Ib */
|
||||
@@ -471,10 +574,14 @@
|
||||
if(tmp8u>15)
|
||||
{EX->q[0] = EX->q[1] = 0;}
|
||||
else {
|
||||
for (int i=16-tmp8u; i>=0; --i)
|
||||
EX->ub[i+tmp8u] = EX->ub[i];
|
||||
for (int i=0; i<tmp8u; ++i)
|
||||
EX->ub[i] = 0;
|
||||
tmp8u*=8;
|
||||
if (tmp8u < 64) {
|
||||
EX->q[1] = (EX->q[1] << tmp8u) | (EX->q[0] >> (64 - tmp8u));
|
||||
EX->q[0] = (EX->q[0] << tmp8u);
|
||||
} else {
|
||||
EX->q[1] = EX->q[0] << (tmp8u - 64);
|
||||
EX->q[0] = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -582,6 +689,43 @@
|
||||
GW.word[0] = EB->byte[0];
|
||||
NEXT;
|
||||
|
||||
_6f_0xBA:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 4: /* BT Ew,Ib */
|
||||
CHECK_FLAGS(emu);
|
||||
GET_EW;
|
||||
tmp8u = F8;
|
||||
if((nextop&0xC0)!=0xC0)
|
||||
{
|
||||
EW=(reg32_t*)(((uint16_t*)(EW))+(tmp8u>>4));
|
||||
}
|
||||
tmp8u&=15;
|
||||
if(EW->word[0] & (1<<tmp8u))
|
||||
SET_FLAG(F_CF);
|
||||
else
|
||||
CLEAR_FLAG(F_CF);
|
||||
break;
|
||||
case 6: /* BTR Ew, Ib */
|
||||
CHECK_FLAGS(emu);
|
||||
GET_EW;
|
||||
tmp8u = F8;
|
||||
if((nextop&0xC0)!=0xC0)
|
||||
{
|
||||
EW=(reg32_t*)(((uint16_t*)(ED))+(tmp8u>>4));
|
||||
}
|
||||
tmp8u&=15;
|
||||
if(EW->word[0] & (1<<tmp8u)) {
|
||||
SET_FLAG(F_CF);
|
||||
EW->word[0] ^= (1<<tmp8u);
|
||||
} else
|
||||
CLEAR_FLAG(F_CF);
|
||||
break;
|
||||
|
||||
default:
|
||||
goto _default;
|
||||
}
|
||||
NEXT;
|
||||
_6f_0xBB: /* BTC Ew,Gw */
|
||||
CHECK_FLAGS(emu);
|
||||
nextop = F8;
|
||||
@@ -655,15 +799,15 @@
|
||||
|
||||
_6f_0xC4: /* PINSRW Gx,Ew,Ib */
|
||||
nextop = F8;
|
||||
GET_EW;
|
||||
GET_ED;
|
||||
tmp8u = F8;
|
||||
GX.uw[tmp8u&7] = EW->word[0];
|
||||
GX.uw[tmp8u&7] = ED->word[0]; // only low 16bits
|
||||
NEXT;
|
||||
_6f_0xC5: /* PEXTRW Gw,Ex,Ib */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
tmp8u = F8;
|
||||
GW.word[0] = EX->uw[tmp8u&7];
|
||||
GD.dword[0] = EX->uw[tmp8u&7]; // 16bits extract, 0 extended
|
||||
NEXT;
|
||||
_6f_0xC6: /* SHUFPD Gx, Ex, Ib */
|
||||
nextop = F8;
|
||||
@@ -681,7 +825,7 @@
|
||||
if(EX->q[0]>15)
|
||||
{GX.q[0] = GX.q[1] = 0;}
|
||||
else
|
||||
{tmp8u=EX->q[0]; for (int i=0; i<8; ++i) GX.uw[i] >>= tmp8u;}
|
||||
{tmp8u=EX->ub[0]; for (int i=0; i<8; ++i) GX.uw[i] >>= tmp8u;}
|
||||
NEXT;
|
||||
_6f_0xD2: /* PSRLD Gx, Ex */
|
||||
nextop = F8;
|
||||
@@ -689,7 +833,7 @@
|
||||
if(EX->q[0]>31)
|
||||
{GX.q[0] = GX.q[1] = 0;}
|
||||
else
|
||||
{tmp8u=EX->q[0]; for (int i=0; i<4; ++i) GX.ud[i] >>= tmp8u;}
|
||||
{tmp8u=EX->ub[0]; for (int i=0; i<4; ++i) GX.ud[i] >>= tmp8u;}
|
||||
NEXT;
|
||||
_6f_0xD3: /* PSRLQ Gx, Ex */
|
||||
nextop = F8;
|
||||
@@ -697,15 +841,22 @@
|
||||
if(EX->q[0]>63)
|
||||
{GX.q[0] = GX.q[1] = 0;}
|
||||
else
|
||||
{tmp8u=EX->q[0]; for (int i=0; i<2; ++i) GX.q[i] >>= tmp8u;}
|
||||
{tmp8u=EX->ub[0]; for (int i=0; i<2; ++i) GX.q[i] >>= tmp8u;}
|
||||
NEXT;
|
||||
_6f_0xD4: /* PADDQ Gx,Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
GX.q[0] += EX->q[0];
|
||||
GX.q[1] += EX->q[1];
|
||||
GX.sq[0] += EX->sq[0];
|
||||
GX.sq[1] += EX->sq[1];
|
||||
NEXT;
|
||||
_6f_0xD5: /* PMULLW Gx,Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=0; i<8; ++i) {
|
||||
tmp32s = (int32_t)GX.sw[i] * EX->sw[i];
|
||||
GX.sw[i] = tmp32s;
|
||||
}
|
||||
NEXT;
|
||||
|
||||
_6f_0xD6: /* MOVQ Ex,Gx */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
@@ -713,6 +864,30 @@
|
||||
if((nextop&0xC0)==0xC0)
|
||||
EX->q[1] = 0;
|
||||
NEXT;
|
||||
_6f_0xD7: /* PMOVMSKB Gd,Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
GD.dword[0] = 0;
|
||||
for (int i=0; i<16; ++i)
|
||||
if(EX->ub[i]&0x80)
|
||||
GD.dword[0] |= (1<<i);
|
||||
NEXT;
|
||||
_6f_0xD8: /* PSUBUSB Gx,Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=0; i<16; ++i) {
|
||||
tmp16s = (int16_t)GX.ub[i] - EX->ub[i];
|
||||
GX.ub[i] = (tmp16s<0)?0:((tmp16s>255)?255:tmp16s);
|
||||
}
|
||||
NEXT;
|
||||
_6f_0xD9: /* PSUBUSW Gx,Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=0; i<8; ++i) {
|
||||
tmp32s = (int32_t)GX.uw[i] - EX->uw[i];
|
||||
GX.uw[i] = (tmp32s<0)?0:((tmp32s>0xffff)?0xffff:tmp32s);
|
||||
}
|
||||
NEXT;
|
||||
|
||||
_6f_0xDB: /* PAND Gx,Ex */
|
||||
nextop = F8;
|
||||
@@ -720,26 +895,58 @@
|
||||
GX.q[0] &= EX->q[0];
|
||||
GX.q[1] &= EX->q[1];
|
||||
NEXT;
|
||||
_6f_0xDC: /* PADDUSB Gx,Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=0; i<16; ++i) {
|
||||
tmp16s = (int16_t)GX.ub[i] + EX->ub[i];
|
||||
GX.ub[i] = (tmp16s>255)?255:tmp16s;
|
||||
}
|
||||
NEXT;
|
||||
|
||||
_6f_0xDE: /* PMAXUB Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for (int i=0; i<16; ++i)
|
||||
if(EX->ub[i]>GX.ub[i]) GX.ub[i] = EX->ub[i];
|
||||
NEXT;
|
||||
_6f_0xDF: /* PANDN Gx,Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
GX.q[0] = (~GX.q[0]) & EX->q[0];
|
||||
GX.q[1] = (~GX.q[1]) & EX->q[1];
|
||||
NEXT;
|
||||
|
||||
_6f_0xE0: /* PAVGB Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for (int i=0; i<16; ++i) GX.ub[i] = ((uint16_t)GX.ub[i] + EX->ub[i] + 1)>>1;
|
||||
NEXT;
|
||||
_6f_0xE1: /* PSRAW Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
tmp8u=EX->q[0];
|
||||
tmp8u=(EX->q[0]>15)?16:EX->ub[0];
|
||||
for (int i=0; i<8; ++i) GX.sw[i] >>= tmp8u;
|
||||
NEXT;
|
||||
_6f_0xE2: /* PSRAD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
tmp8u=EX->q[0]; for (int i=0; i<4; ++i) GX.sd[i] >>= tmp8u;
|
||||
tmp8u=(EX->q[0]>31)?32:EX->ub[0];
|
||||
for (int i=0; i<4; ++i) GX.sd[i] >>= tmp8u;
|
||||
NEXT;
|
||||
_6f_0xE3: /* PAVGW Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for (int i=0; i<8; ++i) GX.uw[i] = ((uint16_t)GX.uw[i] + EX->uw[i] + 1)>>1;
|
||||
NEXT;
|
||||
|
||||
_6f_0xE5: /* PMULHW Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=0; i<8; ++i) {
|
||||
tmp32s = (int32_t)GX.sw[i] * EX->sw[i];
|
||||
GX.uw[i] = (tmp32s>>16)&0xffff;
|
||||
}
|
||||
NEXT;
|
||||
_6f_0xE6: /* CVTTPD2DQ Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
@@ -747,7 +954,34 @@
|
||||
GX.sd[1] = EX->d[1];
|
||||
GX.q[1] = 0;
|
||||
NEXT;
|
||||
|
||||
_6f_0xE7: /* MOVNTDQ Ex, Gx */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
EX->q[0] = GX.q[0];
|
||||
EX->q[1] = GX.q[1];
|
||||
NEXT;
|
||||
_6f_0xE8: /* PSUBSB Gx,Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=0; i<16; ++i) {
|
||||
tmp16s = (int16_t)GX.sb[i] - EX->sb[i];
|
||||
GX.ub[i] = (tmp16s<-128)?-128:((tmp16s>127)?127:tmp16s);
|
||||
}
|
||||
NEXT;
|
||||
_6f_0xE9: /* PSUBSW Gx,Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=0; i<8; ++i) {
|
||||
tmp32s = (int32_t)GX.sw[i] - EX->sw[i];
|
||||
GX.sw[i] = (tmp32s>32767)?32767:((tmp32s<-32768)?-32768:tmp32s);
|
||||
}
|
||||
NEXT;
|
||||
_6f_0xEA: /* PMINSW Gx,Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for (int i=0; i<8; ++i)
|
||||
GX.sw[i] = (GX.sw[i]<EX->sw[i])?GX.sw[i]:EX->sw[i];
|
||||
NEXT;
|
||||
_6f_0xEB: /* POR Gx,Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
@@ -760,7 +994,7 @@
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=0; i<16; ++i) {
|
||||
tmp16s = GX.sb[i] + EX->sb[i];
|
||||
tmp16s = (int16_t)GX.sb[i] + EX->sb[i];
|
||||
GX.sb[i] = (tmp16s>127)?127:((tmp16s<-128)?-128:tmp16s);
|
||||
}
|
||||
NEXT;
|
||||
@@ -768,7 +1002,7 @@
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=0; i<8; ++i) {
|
||||
tmp32s = GX.sw[i] + EX->sw[i];
|
||||
tmp32s = (int32_t)GX.sw[i] + EX->sw[i];
|
||||
GX.sw[i] = (tmp32s>32767)?32767:((tmp32s<-32768)?-32768:tmp32s);
|
||||
}
|
||||
NEXT;
|
||||
@@ -793,7 +1027,7 @@
|
||||
if(EX->q[0]>15)
|
||||
{GX.q[0] = GX.q[1] = 0;}
|
||||
else
|
||||
{tmp8u=EX->q[0]; for (int i=0; i<8; ++i) GX.uw[i] <<= tmp8u;}
|
||||
{tmp8u=EX->ub[0]; for (int i=0; i<8; ++i) GX.uw[i] <<= tmp8u;}
|
||||
NEXT;
|
||||
_6f_0xF2: /* PSLLD Gx, Ex */
|
||||
nextop = F8;
|
||||
@@ -801,7 +1035,7 @@
|
||||
if(EX->q[0]>31)
|
||||
{GX.q[0] = GX.q[1] = 0;}
|
||||
else
|
||||
{tmp8u=EX->q[0]; for (int i=0; i<4; ++i) GX.ud[i] <<= tmp8u;}
|
||||
{tmp8u=EX->ub[0]; for (int i=0; i<4; ++i) GX.ud[i] <<= tmp8u;}
|
||||
NEXT;
|
||||
_6f_0xF3: /* PSLLQ Gx, Ex */
|
||||
nextop = F8;
|
||||
@@ -817,35 +1051,78 @@
|
||||
GX.q[1] = (uint64_t)EX->ud[2]*GX.ud[2];
|
||||
GX.q[0] = (uint64_t)EX->ud[0]*GX.ud[0];
|
||||
NEXT;
|
||||
|
||||
_6f_0xF5: /* PMADDWD Gx,Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for (int i=0; i<4; ++i)
|
||||
GX.sd[i] = (int32_t)(GX.sw[i*2+0])*EX->sw[i*2+0] + (int32_t)(GX.sw[i*2+1])*EX->sw[i*2+1];
|
||||
NEXT;
|
||||
_6f_0xF6: /* PSADBW Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
tmp32u = 0;
|
||||
for (int i=0; i<8; ++i)
|
||||
tmp32u += (GX.ub[i]>EX->ub[i])?(GX.ub[i] - EX->ub[i]):(EX->ub[i] - GX.ub[i]);
|
||||
GX.q[0] = tmp32u;
|
||||
tmp32u = 0;
|
||||
for (int i=8; i<16; ++i)
|
||||
tmp32u += (GX.ub[i]>EX->ub[i])?(GX.ub[i] - EX->ub[i]):(EX->ub[i] - GX.ub[i]);
|
||||
GX.q[1] = tmp32u;
|
||||
NEXT;
|
||||
_6f_0xF7: /* MASKMOVDQU Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
opx2 = (sse_regs_t *)(R_EDI);
|
||||
for (int i=0; i<16; ++i) {
|
||||
if(EX->ub[i]&0x80)
|
||||
opx2->ub[i] = GX.ub[i];
|
||||
}
|
||||
NEXT;
|
||||
_6f_0xF8: /* PSUBB Gx,Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=0; i<16; ++i)
|
||||
GX.ub[i] -= EX->ub[i];
|
||||
NEXT;
|
||||
_6f_0xF9: /* PSUBW Gx,Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=0; i<8; ++i)
|
||||
GX.uw[i] -= EX->uw[i];
|
||||
NEXT;
|
||||
_6f_0xFA: /* PSUBD Gx,Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
GX.ud[0] -= EX->ud[0];
|
||||
GX.ud[1] -= EX->ud[1];
|
||||
GX.ud[2] -= EX->ud[2];
|
||||
GX.ud[3] -= EX->ud[3];
|
||||
GX.sd[0] -= EX->sd[0];
|
||||
GX.sd[1] -= EX->sd[1];
|
||||
GX.sd[2] -= EX->sd[2];
|
||||
GX.sd[3] -= EX->sd[3];
|
||||
NEXT;
|
||||
_6f_0xFB: /* PSUBQ Gx,Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
GX.q[0] -= EX->q[0];
|
||||
GX.q[1] -= EX->q[1];
|
||||
GX.sq[0] -= EX->sq[0];
|
||||
GX.sq[1] -= EX->sq[1];
|
||||
NEXT;
|
||||
_6f_0xFC: /* PADDB Gx,Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=0; i<16; ++i)
|
||||
GX.ub[i] += EX->ub[i];
|
||||
GX.sb[i] += EX->sb[i];
|
||||
NEXT;
|
||||
_6f_0xFD: /* PADDW Gx,Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
for(int i=0; i<8; ++i)
|
||||
GX.sw[i] += EX->sw[i];
|
||||
NEXT;
|
||||
|
||||
_6f_0xFE: /* PADDD Gx,Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
GX.ud[0] += EX->ud[0];
|
||||
GX.ud[1] += EX->ud[1];
|
||||
GX.ud[2] += EX->ud[2];
|
||||
GX.ud[3] += EX->ud[3];
|
||||
GX.sd[0] += EX->sd[0];
|
||||
GX.sd[1] += EX->sd[1];
|
||||
GX.sd[2] += EX->sd[2];
|
||||
GX.sd[3] += EX->sd[3];
|
||||
NEXT;
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
|
||||
nextop = F8;
|
||||
switch(nextop) {
|
||||
case 0xC0:
|
||||
@@ -8,7 +10,11 @@
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7: /* FADD */
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f += ST(nextop&7).f;
|
||||
#else
|
||||
ST0.d += ST(nextop&7).d;
|
||||
#endif
|
||||
break;
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
@@ -18,7 +24,11 @@
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF: /* FMUL */
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f *= ST(nextop&7).f;
|
||||
#else
|
||||
ST0.d *= ST(nextop&7).d;
|
||||
#endif
|
||||
break;
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
@@ -28,7 +38,11 @@
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7: /* FCOM */
|
||||
#ifdef USE_FLOAT
|
||||
fpu_fcom(emu, ST(nextop&7).f);
|
||||
#else
|
||||
fpu_fcom(emu, ST(nextop&7).d);
|
||||
#endif
|
||||
break;
|
||||
case 0xD8:
|
||||
case 0xD9:
|
||||
@@ -38,7 +52,11 @@
|
||||
case 0xDD:
|
||||
case 0xDE:
|
||||
case 0xDF: /* FCOMP */
|
||||
#ifdef USE_FLOAT
|
||||
fpu_fcom(emu, ST(nextop&7).f);
|
||||
#else
|
||||
fpu_fcom(emu, ST(nextop&7).d);
|
||||
#endif
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 0xE0:
|
||||
@@ -49,7 +67,11 @@
|
||||
case 0xE5:
|
||||
case 0xE6:
|
||||
case 0xE7: /* FSUB */
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f -= ST(nextop&7).f;
|
||||
#else
|
||||
ST0.d -= ST(nextop&7).d;
|
||||
#endif
|
||||
break;
|
||||
case 0xE8:
|
||||
case 0xE9:
|
||||
@@ -59,7 +81,11 @@
|
||||
case 0xED:
|
||||
case 0xEE:
|
||||
case 0xEF: /* FSUBR */
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = ST(nextop&7).f - ST0.f;
|
||||
#else
|
||||
ST0.d = ST(nextop&7).d - ST0.d;
|
||||
#endif
|
||||
break;
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
@@ -69,7 +95,11 @@
|
||||
case 0xF5:
|
||||
case 0xF6:
|
||||
case 0xF7: /* FDIV */
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f /= ST(nextop&7).f;
|
||||
#else
|
||||
ST0.d /= ST(nextop&7).d;
|
||||
#endif
|
||||
break;
|
||||
case 0xF8:
|
||||
case 0xF9:
|
||||
@@ -79,26 +109,46 @@
|
||||
case 0xFD:
|
||||
case 0xFE:
|
||||
case 0xFF: /* FDIVR */
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = ST(nextop&7).f / ST0.f;
|
||||
#else
|
||||
ST0.d = ST(nextop&7).d / ST0.d;
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: /* FADD ST0, float */
|
||||
GET_ED;
|
||||
if(!(((uintptr_t)ED)&3))
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f += *(float*)ED;
|
||||
#else
|
||||
ST0.d += *(float*)ED;
|
||||
#endif
|
||||
else {
|
||||
*(uint32_t*)&f = ED->dword[0];
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f += f;
|
||||
#else
|
||||
ST0.d += f;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case 1: /* FMUL ST0, float */
|
||||
GET_ED;
|
||||
if(!(((uintptr_t)ED)&3))
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f *= *(float*)ED;
|
||||
#else
|
||||
ST0.d *= *(float*)ED;
|
||||
#endif
|
||||
else {
|
||||
*(uint32_t*)&f = ED->dword[0];
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f *= f;
|
||||
#else
|
||||
ST0.d *= f;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case 2: /* FCOM ST0, float */
|
||||
@@ -123,40 +173,73 @@
|
||||
case 4: /* FSUB ST0, float */
|
||||
GET_ED;
|
||||
if(!(((uintptr_t)ED)&3))
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f -= *(float*)ED;
|
||||
#else
|
||||
ST0.d -= *(float*)ED;
|
||||
#endif
|
||||
else {
|
||||
*(uint32_t*)&f = ED->dword[0];
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f -= f;
|
||||
#else
|
||||
ST0.d -= f;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case 5: /* FSUBR ST0, float */
|
||||
GET_ED;
|
||||
if(!(((uintptr_t)ED)&3))
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = *(float*)ED - ST0.f;
|
||||
#else
|
||||
ST0.d = *(float*)ED - ST0.d;
|
||||
#endif
|
||||
else {
|
||||
*(uint32_t*)&f = ED->dword[0];
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = f - ST0.f;
|
||||
#else
|
||||
ST0.d = f - ST0.d;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case 6: /* FDIV ST0, float */
|
||||
GET_ED;
|
||||
if(!(((uintptr_t)ED)&3))
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f /= *(float*)ED;
|
||||
#else
|
||||
ST0.d /= *(float*)ED;
|
||||
#endif
|
||||
else {
|
||||
*(uint32_t*)&f = ED->dword[0];
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f /= f;
|
||||
#else
|
||||
ST0.d /= f;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case 7: /* FDIVR ST0, float */
|
||||
GET_ED;
|
||||
if(!(((uintptr_t)ED)&3))
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = *(float*)ED / ST0.f;
|
||||
#else
|
||||
ST0.d = *(float*)ED / ST0.d;
|
||||
#endif
|
||||
else {
|
||||
*(uint32_t*)&f = ED->dword[0];
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = f / ST0.f;
|
||||
#else
|
||||
ST0.d = f / ST0.d;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
default:
|
||||
goto _default;
|
||||
}
|
||||
}
|
||||
#pragma GCC diagnostic pop
|
||||
Executable
+362
@@ -0,0 +1,362 @@
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
|
||||
nextop = F8;
|
||||
switch (nextop) {
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
case 0xC2:
|
||||
case 0xC3:
|
||||
case 0xC4:
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7: /* FLD STx */
|
||||
ll = ST(nextop&7).ll;
|
||||
fpu_do_push(emu);
|
||||
ST0.ll = ll;
|
||||
break;
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
case 0xCA:
|
||||
case 0xCB:
|
||||
case 0xCC:
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF: /* FXCH STx */
|
||||
ll = ST(nextop&7).ll;
|
||||
ST(nextop&7).ll = ST0.ll;
|
||||
ST0.ll = ll;
|
||||
break;
|
||||
|
||||
case 0xD0: /* FNOP */
|
||||
break;
|
||||
|
||||
case 0xE0: /* FCHS */
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = -ST0.f;
|
||||
#else
|
||||
ST0.d = -ST0.d;
|
||||
#endif
|
||||
break;
|
||||
case 0xE1: /* FABS */
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = fabsf(ST0.f);
|
||||
#else
|
||||
ST0.d = fabs(ST0.d);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 0xE4: /* FTST */
|
||||
fpu_ftst(emu);
|
||||
break;
|
||||
case 0xE5: /* FXAM */
|
||||
fpu_fxam(emu);
|
||||
break;
|
||||
|
||||
case 0xE8: /* FLD1 */
|
||||
fpu_do_push(emu);
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = 1.0f;
|
||||
#else
|
||||
ST0.d = 1.0;
|
||||
#endif
|
||||
break;
|
||||
case 0xE9: /* FLDL2T */
|
||||
fpu_do_push(emu);
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = L2T;
|
||||
#else
|
||||
ST0.d = L2T;
|
||||
#endif
|
||||
break;
|
||||
case 0xEA: /* FLDL2E */
|
||||
fpu_do_push(emu);
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = L2E;
|
||||
#else
|
||||
ST0.d = L2E;
|
||||
#endif
|
||||
break;
|
||||
case 0xEB: /* FLDPI */
|
||||
fpu_do_push(emu);
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = PI;
|
||||
#else
|
||||
ST0.d = PI;
|
||||
#endif
|
||||
break;
|
||||
case 0xEC: /* FLDLG2 */
|
||||
fpu_do_push(emu);
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = LG2;
|
||||
#else
|
||||
ST0.d = LG2;
|
||||
#endif
|
||||
break;
|
||||
case 0xED: /* FLDLN2 */
|
||||
fpu_do_push(emu);
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = LN2;
|
||||
#else
|
||||
ST0.d = LN2;
|
||||
#endif
|
||||
break;
|
||||
case 0xEE: /* FLDZ */
|
||||
fpu_do_push(emu);
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = 0.0f;
|
||||
#else
|
||||
ST0.d = 0.0;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 0xF0: /* F2XM1 */
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = exp2f(ST0.f) - 1.0f;
|
||||
#else
|
||||
ST0.d = exp2(ST0.d) - 1.0;
|
||||
#endif
|
||||
break;
|
||||
case 0xF1: /* FYL2X */
|
||||
#ifdef USE_FLOAT
|
||||
ST(1).f = log2f(ST0.f)*ST(1).f;
|
||||
#else
|
||||
ST(1).d = log2(ST0.d)*ST(1).d;
|
||||
#endif
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 0xF2: /* FPTAN */
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = tanf(ST0.f);
|
||||
fpu_do_push(emu);
|
||||
ST0.f = 1.0f;
|
||||
#else
|
||||
ST0.d = tan(ST0.d);
|
||||
fpu_do_push(emu);
|
||||
ST0.d = 1.0;
|
||||
#endif
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
break;
|
||||
case 0xF3: /* FPATAN */
|
||||
#ifdef USE_FLOAT
|
||||
ST1.f = atan2f(ST1.f, ST0.f);
|
||||
#else
|
||||
ST1.d = atan2(ST1.d, ST0.d);
|
||||
#endif
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 0xF4: /* FXTRACT */
|
||||
#ifdef USE_FLOAT
|
||||
tmp32s = (ST0.ll&0x7f700000)>>23;
|
||||
tmp32s -= 127;
|
||||
ST0.f /= exp2f(tmp32s);
|
||||
fpu_do_push(emu);
|
||||
ST0.f = tmp32s;
|
||||
#else
|
||||
tmp32s = (ST0.ll&0x7ff0000000000000LL)>>52;
|
||||
tmp32s -= 1023;
|
||||
ST0.d /= exp2(tmp32s);
|
||||
fpu_do_push(emu);
|
||||
ST0.d = tmp32s;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 0xF8: /* FPREM */
|
||||
#ifdef USE_FLOAT
|
||||
ll = ST0.f / ST1.f;
|
||||
ST0.f -= ST1.f * ll;
|
||||
#else
|
||||
ll = ST0.d / ST1.d;
|
||||
ST0.d -= ST1.d * ll;
|
||||
#endif
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
emu->sw.f.F87_C0 = (ll&1);
|
||||
emu->sw.f.F87_C3 = ((ll>>1)&1);
|
||||
emu->sw.f.F87_C1 = ((ll>>2)&1);
|
||||
break;
|
||||
case 0xF5: /* FPREM1 */
|
||||
// get exponant(ST(0))-exponant(ST(1)) in temp32s
|
||||
#ifdef USE_FLOAT
|
||||
tmp32s = ((ST0.ll&0x7f700000)>>23) - ((ST1.ll&0x7f700000)>>23);
|
||||
#else
|
||||
tmp32s = ((ST0.ll&0x7ff0000000000000LL)>>52) - ((ST1.ll&0x7ff0000000000000LL)>>52);
|
||||
#endif
|
||||
if(tmp32s<64)
|
||||
{
|
||||
#ifdef USE_FLOAT
|
||||
ll = (int64_t)round(ST0.f/ST1.f);
|
||||
ST0.f = ST0.f - (ST1.f*ll);
|
||||
#else
|
||||
ll = (int64_t)round(ST0.d/ST1.d);
|
||||
ST0.d = ST0.d - (ST1.d*ll);
|
||||
#endif
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
emu->sw.f.F87_C1 = (ll&1)?1:0;
|
||||
emu->sw.f.F87_C3 = (ll&2)?1:0;
|
||||
emu->sw.f.F87_C0 = (ll&4)?1:0;
|
||||
} else {
|
||||
#ifdef USE_FLOAT
|
||||
ll = (int64_t)(floor((ST0.f/ST1.f))/powf(2, tmp32s - 32));
|
||||
ST0.f = ST0.f - ST1.f*ll*powf(2, 32);
|
||||
#else
|
||||
ll = (int64_t)(floor((ST0.d/ST1.d))/pow(2, tmp32s - 32));
|
||||
ST0.d = ST0.d - ST1.d*ll*pow(2, tmp32s - 32);
|
||||
#endif
|
||||
emu->sw.f.F87_C2 = 1;
|
||||
}
|
||||
break;
|
||||
case 0xF6: /* FDECSTP */
|
||||
emu->top=(emu->top-1)&7; // this will probably break a few things
|
||||
break;
|
||||
case 0xF7: /* FINCSTP */
|
||||
emu->top=(emu->top+1)&7; // this will probably break a few things
|
||||
break;
|
||||
case 0xF9: /* FYL2XP1 */
|
||||
#ifdef USE_FLOAT
|
||||
ST(1).f = log2f(ST0.f + 1.0f)*ST(1).f;
|
||||
#else
|
||||
ST(1).d = log2(ST0.d + 1.0)*ST(1).d;
|
||||
#endif
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 0xFA: /* FSQRT */
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = sqrtf(ST0.f);
|
||||
#else
|
||||
ST0.d = sqrt(ST0.d);
|
||||
#endif
|
||||
break;
|
||||
case 0xFB: /* FSINCOS */
|
||||
fpu_do_push(emu);
|
||||
#ifdef USE_FLOAT
|
||||
sincosf(ST1.f, &ST1.f, &ST0.f);
|
||||
#else
|
||||
sincos(ST1.d, &ST1.d, &ST0.d);
|
||||
#endif
|
||||
break;
|
||||
case 0xFC: /* FRNDINT */
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = fpu_round(emu, ST0.f);
|
||||
#else
|
||||
ST0.d = fpu_round(emu, ST0.d);
|
||||
#endif
|
||||
break;
|
||||
case 0xFD: /* FSCALE */
|
||||
// this could probably be done by just altering the exponant part of the float...
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f *= exp2f(truncf(ST1.f));
|
||||
#else
|
||||
ST0.d *= exp2(trunc(ST1.d));
|
||||
#endif
|
||||
break;
|
||||
case 0xFE: /* FSIN */
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = sinf(ST0.f);
|
||||
#else
|
||||
ST0.d = sin(ST0.d);
|
||||
#endif
|
||||
break;
|
||||
case 0xFF: /* FCOS */
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = cosf(ST0.f);
|
||||
#else
|
||||
ST0.d = cos(ST0.d);
|
||||
#endif
|
||||
break;
|
||||
|
||||
|
||||
case 0xD1:
|
||||
case 0xD4:
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
case 0xD8:
|
||||
case 0xD9:
|
||||
case 0xDA:
|
||||
case 0xDB:
|
||||
case 0xDC:
|
||||
case 0xDD:
|
||||
case 0xDE:
|
||||
case 0xDF:
|
||||
case 0xE2:
|
||||
case 0xE3:
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
case 0xEF:
|
||||
goto _default;
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: /* FLD ST0, Ed float */
|
||||
GET_ED;
|
||||
fpu_do_push(emu);
|
||||
#ifdef USE_FLOAT
|
||||
ST0.ll = ED->dword[0];
|
||||
#else
|
||||
if(!(((uintptr_t)ED)&3))
|
||||
ST0.d = *(float*)ED;
|
||||
else {
|
||||
memcpy(&f, ED->dword, sizeof(float));
|
||||
ST0.d = f;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case 2: /* FST Ed, ST0 */
|
||||
GET_ED;
|
||||
#ifdef USE_FLOAT
|
||||
*(float*)ED = ST0.f;
|
||||
#else
|
||||
if(!(((uintptr_t)ED)&3))
|
||||
*(float*)ED = ST0.d;
|
||||
else {
|
||||
f = ST0.d;
|
||||
memcpy(ED->dword, &f, sizeof(float));
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case 3: /* FSTP Ed, ST0 */
|
||||
GET_ED;
|
||||
#ifdef USE_FLOAT
|
||||
ED->dword[0] = ST0.ll;
|
||||
#else
|
||||
if(!(((uintptr_t)ED)&3))
|
||||
*(float*)ED = ST0.d;
|
||||
else {
|
||||
f = ST0.d;
|
||||
memcpy(ED->dword, &f, sizeof(float));
|
||||
}
|
||||
#endif
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 4: /* FLDENV m */
|
||||
// warning, incomplete
|
||||
GET_ED;
|
||||
fpu_loadenv(emu, (char*)ED, 0);
|
||||
break;
|
||||
case 5: /* FLDCW Ew */
|
||||
GET_EW;
|
||||
emu->cw = EW->word[0];
|
||||
// do something with cw?
|
||||
emu->round = (fpu_round_t)((emu->cw >> 10) & 3);
|
||||
break;
|
||||
case 6: /* FNSTENV m */
|
||||
// warning, incomplete
|
||||
GET_ED;
|
||||
fpu_savenv(emu, (char*)ED, 0);
|
||||
ED->dword[0] = emu->cw;
|
||||
ED->dword[1] = emu->sw.x16;
|
||||
// tagword: 2bits*8
|
||||
ED->word[4] = 0;
|
||||
for (int i=0; i<8; ++i)
|
||||
ED->word[4] |= (emu->p_regs[i].tag)<<(i*2);
|
||||
// intruction pointer: 48bits
|
||||
// data (operand) pointer: 48bits
|
||||
// last opcode: 11bits save: 16bits restaured (1st and 2nd opcode only)
|
||||
break;
|
||||
case 7: /* FNSTCW Ew */
|
||||
GET_EW;
|
||||
EW->word[0] = emu->cw;
|
||||
break;
|
||||
default:
|
||||
goto _default;
|
||||
}
|
||||
}
|
||||
#pragma GCC diagnostic pop
|
||||
@@ -51,7 +51,11 @@
|
||||
break;
|
||||
|
||||
case 0xE9: /* FUCOMPP */
|
||||
#ifdef USE_FLOAT
|
||||
fpu_fcom(emu, ST1.f);
|
||||
#else
|
||||
fpu_fcom(emu, ST1.d); // bad, should handle QNaN and IA interrupt
|
||||
#endif
|
||||
fpu_do_pop(emu);
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
@@ -72,25 +76,60 @@
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: /* FIADD ST0, Ed int */
|
||||
GET_ED;
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f += ED->sdword[0];
|
||||
#else
|
||||
ST0.d += ED->sdword[0];
|
||||
#endif
|
||||
break;
|
||||
case 1: /* FIMUL ST0, Ed int */
|
||||
GET_ED;
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f *= ED->sdword[0];
|
||||
#else
|
||||
ST0.d *= ED->sdword[0];
|
||||
#endif
|
||||
break;
|
||||
case 2: /* FICOM ST0, Ed int */
|
||||
GET_ED;
|
||||
fpu_fcom(emu, ED->sdword[0]);
|
||||
break;
|
||||
case 3: /* FICOMP ST0, Ed int */
|
||||
GET_ED;
|
||||
fpu_fcom(emu, ED->sdword[0]);
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 4: /* FISUB ST0, Ed int */
|
||||
GET_ED;
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f -= ED->sdword[0];
|
||||
#else
|
||||
ST0.d -= ED->sdword[0];
|
||||
#endif
|
||||
break;
|
||||
case 5: /* FISUBR ST0, Ed int */
|
||||
GET_ED;
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = ED->sdword[0] - ST0.f;
|
||||
#else
|
||||
ST0.d = ED->sdword[0] - ST0.d;
|
||||
#endif
|
||||
break;
|
||||
case 6: /* FIDIV ST0, Ed int */
|
||||
GET_ED;
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f /= ED->sdword[0];
|
||||
#else
|
||||
ST0.d /= ED->sdword[0];
|
||||
#endif
|
||||
break;
|
||||
case 7: /* FIDIVR ST0, Ed int */
|
||||
GET_ED;
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = ED->sdword[0] / ST0.f;
|
||||
#else
|
||||
ST0.d = ED->sdword[0] / ST0.d;
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
goto _default;
|
||||
}
|
||||
}
|
||||
Executable
+241
@@ -0,0 +1,241 @@
|
||||
nextop = F8;
|
||||
switch(nextop) {
|
||||
case 0xC0: /* FCMOVNB ST(0), ST(i) */
|
||||
case 0xC1:
|
||||
case 0xC2:
|
||||
case 0xC3:
|
||||
case 0xC4:
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
CHECK_FLAGS(emu);
|
||||
if(!ACCESS_FLAG(F_CF))
|
||||
ST0.ll = ST(nextop&7).ll;
|
||||
break;
|
||||
case 0xC8: /* FCMOVNE ST(0), ST(i) */
|
||||
case 0xC9:
|
||||
case 0xCA:
|
||||
case 0xCB:
|
||||
case 0xCC:
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF:
|
||||
CHECK_FLAGS(emu);
|
||||
if(!ACCESS_FLAG(F_ZF))
|
||||
ST0.ll = ST(nextop&7).ll;
|
||||
break;
|
||||
case 0xD0: /* FCMOVNBE ST(0), ST(i) */
|
||||
case 0xD1:
|
||||
case 0xD2:
|
||||
case 0xD3:
|
||||
case 0xD4:
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
CHECK_FLAGS(emu);
|
||||
if(!(ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF)))
|
||||
ST0.ll = ST(nextop&7).ll;
|
||||
break;
|
||||
case 0xD8: /* FCMOVNU ST(0), ST(i) */
|
||||
case 0xD9:
|
||||
case 0xDA:
|
||||
case 0xDB:
|
||||
case 0xDC:
|
||||
case 0xDD:
|
||||
case 0xDE:
|
||||
case 0xDF:
|
||||
CHECK_FLAGS(emu);
|
||||
if(!ACCESS_FLAG(F_PF))
|
||||
ST0.ll = ST(nextop&7).ll;
|
||||
break;
|
||||
|
||||
case 0xE2: /* FNCLEX */
|
||||
//Clears the floating-point exception flags (PE, UE, OE, ZE, DE, and IE),
|
||||
// the exception summary status flag (ES), the stack fault flag (SF), and the busy flag (B) in the FPU status word
|
||||
emu->sw.f.F87_PE = 0;
|
||||
emu->sw.f.F87_UE = 0;
|
||||
emu->sw.f.F87_OE = 0;
|
||||
emu->sw.f.F87_ZE = 0;
|
||||
emu->sw.f.F87_DE = 0;
|
||||
emu->sw.f.F87_IE = 0;
|
||||
emu->sw.f.F87_ES = 0;
|
||||
emu->sw.f.F87_SF = 0;
|
||||
emu->sw.f.F87_B = 0;
|
||||
break;
|
||||
case 0xE3: /* FNINIT */
|
||||
reset_fpu(emu);
|
||||
break;
|
||||
case 0xE8: /* FUCOMI ST0, STx */
|
||||
case 0xE9:
|
||||
case 0xEA:
|
||||
case 0xEB:
|
||||
case 0xEC:
|
||||
case 0xED:
|
||||
case 0xEE:
|
||||
case 0xEF:
|
||||
#ifdef USE_FLOAT
|
||||
fpu_fcomi(emu, ST(nextop&7).f);
|
||||
#else
|
||||
fpu_fcomi(emu, ST(nextop&7).d); // bad, should handle QNaN and IA interrupt
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 0xF0: /* FCOMI ST0, STx */
|
||||
case 0xF1:
|
||||
case 0xF2:
|
||||
case 0xF3:
|
||||
case 0xF4:
|
||||
case 0xF5:
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
#ifdef USE_FLOAT
|
||||
fpu_fcomi(emu, ST(nextop&7).f);
|
||||
#else
|
||||
fpu_fcomi(emu, ST(nextop&7).d);
|
||||
#endif
|
||||
break;
|
||||
case 0xE0:
|
||||
case 0xE1:
|
||||
case 0xE4:
|
||||
case 0xE5:
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
goto _default;
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: /* FILD ST0, Gd */
|
||||
GET_ED;
|
||||
fpu_do_push(emu);
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = ED->sdword[0];
|
||||
#else
|
||||
ST0.d = ED->sdword[0];
|
||||
#endif
|
||||
break;
|
||||
case 1: /* FISTTP Ed, ST0 */
|
||||
GET_ED;
|
||||
#ifdef USE_FLOAT
|
||||
tmp32s = ST0.f; // TODO: Handling of FPU Exception
|
||||
if(tmp32s==0x7fffffff && isgreater(ST0.f, (float)(int32_t)0x7fffffff))
|
||||
tmp32s = 0x80000000;
|
||||
#else
|
||||
tmp32s = ST0.d; // TODO: Handling of FPU Exception
|
||||
if(tmp32s==0x7fffffff && isgreater(ST0.d, (double)(int32_t)0x7fffffff))
|
||||
tmp32s = 0x80000000;
|
||||
#endif
|
||||
fpu_do_pop(emu);
|
||||
ED->sdword[0] = tmp32s;
|
||||
break;
|
||||
case 2: /* FIST Ed, ST0 */
|
||||
GET_ED;
|
||||
#ifdef USE_FLOAT
|
||||
if(isgreater(ST0.f, (float)(int32_t)0x7fffffff) || isless(ST0.f, -(float)(int32_t)0x7fffffff))
|
||||
ED->sdword[0] = 0x80000000;
|
||||
else {
|
||||
switch(emu->round) {
|
||||
case ROUND_Nearest:
|
||||
ED->sdword[0] = floorf(ST0.f+0.5);
|
||||
break;
|
||||
case ROUND_Down:
|
||||
ED->sdword[0] = floorf(ST0.f);
|
||||
break;
|
||||
case ROUND_Up:
|
||||
ED->sdword[0] = ceilf(ST0.f);
|
||||
break;
|
||||
case ROUND_Chop:
|
||||
ED->sdword[0] = ST0.f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
if(isgreater(ST0.d, (double)(int32_t)0x7fffffff) || isless(ST0.d, -(double)(int32_t)0x7fffffff))
|
||||
ED->sdword[0] = 0x80000000;
|
||||
else {
|
||||
switch(emu->round) {
|
||||
case ROUND_Nearest:
|
||||
ED->sdword[0] = floor(ST0.d+0.5);
|
||||
break;
|
||||
case ROUND_Down:
|
||||
ED->sdword[0] = floor(ST0.d);
|
||||
break;
|
||||
case ROUND_Up:
|
||||
ED->sdword[0] = ceil(ST0.d);
|
||||
break;
|
||||
case ROUND_Chop:
|
||||
ED->sdword[0] = ST0.d;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case 3: /* FISTP Ed, ST0 */
|
||||
GET_ED;
|
||||
#ifdef USE_FLOAT
|
||||
if(isgreater(ST0.f, (float)(int32_t)0x7fffffff) || isless(ST0.f, -(float)(int32_t)0x7fffffff))
|
||||
ED->sdword[0] = 0x80000000;
|
||||
else {
|
||||
switch(emu->round) {
|
||||
case ROUND_Nearest:
|
||||
ED->sdword[0] = floorf(ST0.f+0.5);
|
||||
break;
|
||||
case ROUND_Down:
|
||||
ED->sdword[0] = floorf(ST0.f);
|
||||
break;
|
||||
case ROUND_Up:
|
||||
ED->sdword[0] = ceilf(ST0.f);
|
||||
break;
|
||||
case ROUND_Chop:
|
||||
ED->sdword[0] = ST0.f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
if(isgreater(ST0.d, (double)(int32_t)0x7fffffff) || isless(ST0.d, -(double)(int32_t)0x7fffffff))
|
||||
ED->sdword[0] = 0x80000000;
|
||||
else {
|
||||
switch(emu->round) {
|
||||
case ROUND_Nearest:
|
||||
ED->sdword[0] = floor(ST0.d+0.5);
|
||||
break;
|
||||
case ROUND_Down:
|
||||
ED->sdword[0] = floor(ST0.d);
|
||||
break;
|
||||
case ROUND_Up:
|
||||
ED->sdword[0] = ceil(ST0.d);
|
||||
break;
|
||||
case ROUND_Chop:
|
||||
ED->sdword[0] = ST0.d;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 5: /* FLD ST0, Gt */
|
||||
GET_ED;
|
||||
fpu_do_push(emu);
|
||||
memcpy(&STld(0).ld, ED, 10);
|
||||
#ifdef USE_FLOAT
|
||||
LD2D(&STld(0), &d);
|
||||
ST0.f = d;
|
||||
#else
|
||||
LD2D(&STld(0), &ST(0).d);
|
||||
#endif
|
||||
STld(0).ref = ST0.ll;
|
||||
break;
|
||||
case 7: /* FSTP tbyte */
|
||||
GET_ED;
|
||||
if(ST0.ll!=STld(0).ref)
|
||||
#ifdef USE_FLOAT
|
||||
{d = ST0.f; D2LD(&d, ED);}
|
||||
#else
|
||||
D2LD(&ST0.d, ED);
|
||||
#endif
|
||||
else
|
||||
memcpy(ED, &STld(0).ld, 10);
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
default:
|
||||
goto _default;
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
|
||||
nextop = F8;
|
||||
switch(nextop) {
|
||||
case 0xC0:
|
||||
@@ -8,7 +10,11 @@
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7: /* FADD */
|
||||
#ifdef USE_FLOAT
|
||||
ST(nextop&7).f += ST0.f;
|
||||
#else
|
||||
ST(nextop&7).d += ST0.d;
|
||||
#endif
|
||||
break;
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
@@ -18,7 +24,11 @@
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF: /* FMUL */
|
||||
#ifdef USE_FLOAT
|
||||
ST(nextop&7).f *= ST0.f;
|
||||
#else
|
||||
ST(nextop&7).d *= ST0.d;
|
||||
#endif
|
||||
break;
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
@@ -28,7 +38,11 @@
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7: /* FCOM */
|
||||
fpu_fcom(emu, ST(nextop&7).d); // TODO: is this ok?
|
||||
#ifdef USE_FLOAT
|
||||
fpu_fcom(emu, ST(nextop&7).f);
|
||||
#else
|
||||
fpu_fcom(emu, ST(nextop&7).d);
|
||||
#endif
|
||||
break;
|
||||
case 0xD8:
|
||||
case 0xD9:
|
||||
@@ -38,7 +52,11 @@
|
||||
case 0xDD:
|
||||
case 0xDE:
|
||||
case 0xDF: /* FCOMP */
|
||||
#ifdef USE_FLOAT
|
||||
fpu_fcom(emu, ST(nextop&7).f);
|
||||
#else
|
||||
fpu_fcom(emu, ST(nextop&7).d); // TODO: is this ok?
|
||||
#endif
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 0xE0:
|
||||
@@ -49,7 +67,11 @@
|
||||
case 0xE5:
|
||||
case 0xE6:
|
||||
case 0xE7: /* FSUBR */
|
||||
#ifdef USE_FLOAT
|
||||
ST(nextop&7).f = ST0.f -ST(nextop&7).f;
|
||||
#else
|
||||
ST(nextop&7).d = ST0.d -ST(nextop&7).d;
|
||||
#endif
|
||||
break;
|
||||
case 0xE8:
|
||||
case 0xE9:
|
||||
@@ -59,7 +81,11 @@
|
||||
case 0xED:
|
||||
case 0xEE:
|
||||
case 0xEF: /* FSUB */
|
||||
#ifdef USE_FLOAT
|
||||
ST(nextop&7).f -= ST0.f;
|
||||
#else
|
||||
ST(nextop&7).d -= ST0.d;
|
||||
#endif
|
||||
break;
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
@@ -69,7 +95,11 @@
|
||||
case 0xF5:
|
||||
case 0xF6:
|
||||
case 0xF7: /* FDIVR */
|
||||
#ifdef USE_FLOAT
|
||||
ST(nextop&7).f = ST0.f / ST(nextop&7).f;
|
||||
#else
|
||||
ST(nextop&7).d = ST0.d / ST(nextop&7).d;
|
||||
#endif
|
||||
break;
|
||||
case 0xF8:
|
||||
case 0xF9:
|
||||
@@ -79,26 +109,48 @@
|
||||
case 0xFD:
|
||||
case 0xFE:
|
||||
case 0xFF: /* FDIV */
|
||||
#ifdef USE_FLOAT
|
||||
ST(nextop&7).f /= ST0.f;
|
||||
#else
|
||||
ST(nextop&7).d /= ST0.d;
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
GET_ED;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: /* FADD ST0, double */
|
||||
#ifdef USE_FLOAT
|
||||
if(!(((uintptr_t)ED)&7))
|
||||
ST0.f += *(double*)ED;
|
||||
else {
|
||||
*(uint64_t*)&d = *(uint64_t*)ED;
|
||||
ST0.f += d;
|
||||
}
|
||||
#else
|
||||
if(!(((uintptr_t)ED)&7))
|
||||
ST0.d += *(double*)ED;
|
||||
else {
|
||||
*(uint64_t*)&d = *(uint64_t*)ED;
|
||||
ST0.d += d;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case 1: /* FMUL ST0, double */
|
||||
#ifdef USE_FLOAT
|
||||
if(!(((uintptr_t)ED)&7))
|
||||
ST0.f *= *(double*)ED;
|
||||
else {
|
||||
*(uint64_t*)&d = *(uint64_t*)ED;
|
||||
ST0.f *= d;
|
||||
}
|
||||
#else
|
||||
if(!(((uintptr_t)ED)&7))
|
||||
ST0.d *= *(double*)ED;
|
||||
else {
|
||||
*(uint64_t*)&d = *(uint64_t*)ED;
|
||||
ST0.d *= d;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case 2: /* FCOM ST0, double */
|
||||
if(!(((uintptr_t)ED)&7))
|
||||
@@ -118,38 +170,75 @@
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 4: /* FSUB ST0, double */
|
||||
#ifdef USE_FLOAT
|
||||
if(!(((uintptr_t)ED)&7))
|
||||
ST0.f -= *(double*)ED;
|
||||
else {
|
||||
*(uint64_t*)&d = *(uint64_t*)ED;
|
||||
ST0.f -= d;
|
||||
}
|
||||
#else
|
||||
if(!(((uintptr_t)ED)&7))
|
||||
ST0.d -= *(double*)ED;
|
||||
else {
|
||||
*(uint64_t*)&d = *(uint64_t*)ED;
|
||||
ST0.d -= d;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case 5: /* FSUBR ST0, double */
|
||||
#ifdef USE_FLOAT
|
||||
if(!(((uintptr_t)ED)&7))
|
||||
ST0.f = *(double*)ED - ST0.f;
|
||||
else {
|
||||
*(uint64_t*)&d = *(uint64_t*)ED;
|
||||
ST0.f = d - ST0.f;
|
||||
}
|
||||
#else
|
||||
if(!(((uintptr_t)ED)&7))
|
||||
ST0.d = *(double*)ED - ST0.d;
|
||||
else {
|
||||
*(uint64_t*)&d = *(uint64_t*)ED;
|
||||
ST0.d = d - ST0.d;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case 6: /* FDIV ST0, double */
|
||||
#ifdef USE_FLOAT
|
||||
if(!(((uintptr_t)ED)&7))
|
||||
ST0.f /= *(double*)ED;
|
||||
else {
|
||||
*(uint64_t*)&d = *(uint64_t*)ED;
|
||||
ST0.f /= d;
|
||||
}
|
||||
#else
|
||||
if(!(((uintptr_t)ED)&7))
|
||||
ST0.d /= *(double*)ED;
|
||||
else {
|
||||
*(uint64_t*)&d = *(uint64_t*)ED;
|
||||
ST0.d /= d;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case 7: /* FDIVR ST0, double */
|
||||
#ifdef USE_FLOAT
|
||||
if(!(((uintptr_t)ED)&7))
|
||||
ST0.f = *(double*)ED / ST0.f;
|
||||
else {
|
||||
*(uint64_t*)&d = *(uint64_t*)ED;
|
||||
ST0.f = d / ST0.f;
|
||||
}
|
||||
#else
|
||||
if(!(((uintptr_t)ED)&7))
|
||||
ST0.d = *(double*)ED / ST0.d;
|
||||
else {
|
||||
*(uint64_t*)&d = *(uint64_t*)ED;
|
||||
ST0.d = d / ST0.d;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
goto _default;
|
||||
}
|
||||
}
|
||||
#pragma GCC diagnostic pop
|
||||
@@ -9,7 +9,8 @@
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
break; // not handling Tag...
|
||||
fpu_do_free(emu, nextop-0xC0);
|
||||
break;
|
||||
|
||||
case 0xD0: /* FST ST0, STx */
|
||||
case 0xD1:
|
||||
@@ -40,7 +41,11 @@
|
||||
case 0xE5:
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
#ifdef USE_FLOAT
|
||||
fpu_fcom(emu, ST(nextop&7).f);
|
||||
#else
|
||||
fpu_fcom(emu, ST(nextop&7).d); // bad, should handle QNaN and IA interrupt
|
||||
#endif
|
||||
break;
|
||||
case 0xE8: /* FUCOMP ST0, STx */
|
||||
case 0xE9:
|
||||
@@ -50,7 +55,11 @@
|
||||
case 0xED:
|
||||
case 0xEE:
|
||||
case 0xEF:
|
||||
#ifdef USE_FLOAT
|
||||
fpu_fcom(emu, ST(nextop&7).f);
|
||||
#else
|
||||
fpu_fcom(emu, ST(nextop&7).d); // bad, should handle QNaN and IA interrupt
|
||||
#endif
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
|
||||
@@ -85,15 +94,39 @@
|
||||
case 0: /* FLD double */
|
||||
GET_ED;
|
||||
fpu_do_push(emu);
|
||||
#ifdef USE_FLOAT
|
||||
*(uint64_t*)&d = *(int64_t*)ED;
|
||||
ST0.f = d;
|
||||
#else
|
||||
ST0.ll = *(int64_t*)ED;
|
||||
#endif
|
||||
break;
|
||||
case 1: /* FISTTP ED qword */
|
||||
GET_ED;
|
||||
#ifdef USE_FLOAT
|
||||
*(int64_t*)ED = ST0.f;
|
||||
#else
|
||||
*(int64_t*)ED = ST0.d;
|
||||
#endif
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 2: /* FST double */
|
||||
GET_ED;
|
||||
#ifdef USE_FLOAT
|
||||
d = ST0.f;
|
||||
*(int64_t*)ED = *(uint64_t*)&d;
|
||||
#else
|
||||
*(int64_t*)ED = ST0.ll;
|
||||
#endif
|
||||
break;
|
||||
case 3: /* FSTP double */
|
||||
GET_ED;
|
||||
#ifdef USE_FLOAT
|
||||
d = ST0.f;
|
||||
*(int64_t*)ED = *(uint64_t*)&d;
|
||||
#else
|
||||
*(int64_t*)ED = ST0.ll;
|
||||
#endif
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 4: /* FRSTOR m108byte */
|
||||
@@ -104,7 +137,12 @@
|
||||
char* p =(char*)ED;
|
||||
p += 28;
|
||||
for (int i=0; i<8; ++i) {
|
||||
#ifdef USE_FLOAT
|
||||
d = ST(i).f;
|
||||
LD2D(p, &d);
|
||||
#else
|
||||
LD2D(p, &ST(i).d);
|
||||
#endif
|
||||
p+=10;
|
||||
}
|
||||
}
|
||||
@@ -119,12 +157,22 @@
|
||||
char* p =(char*)ED;
|
||||
p += 28;
|
||||
for (int i=0; i<8; ++i) {
|
||||
#ifdef USE_FLOAT
|
||||
D2LD(&d, p);
|
||||
ST(i).f = d;
|
||||
#else
|
||||
D2LD(&ST(i).d, p);
|
||||
#endif
|
||||
p+=10;
|
||||
}
|
||||
}
|
||||
reset_fpu(emu);
|
||||
break;
|
||||
case 7: /* FNSTSW m2byte */
|
||||
GET_ED;
|
||||
emu->sw.f.F87_TOP = emu->top&7;
|
||||
*(uint16_t*)ED = emu->sw.x16;
|
||||
break;
|
||||
default:
|
||||
goto _default;
|
||||
}
|
||||
@@ -1,7 +1,11 @@
|
||||
nextop = F8;
|
||||
switch (nextop) {
|
||||
case 0xC1: /* FADDP ST1, ST0 */
|
||||
#ifdef USE_FLOAT
|
||||
ST(1).f += ST0.f;
|
||||
#else
|
||||
ST(1).d += ST0.d;
|
||||
#endif
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 0xC0: /* FADDP STx, ST0 */
|
||||
@@ -11,11 +15,19 @@
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
#ifdef USE_FLOAT
|
||||
ST(nextop&7).f += ST0.f;
|
||||
#else
|
||||
ST(nextop&7).d += ST0.d;
|
||||
#endif
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 0xC9: /* FMULP ST1, ST0 */
|
||||
#ifdef USE_FLOAT
|
||||
ST1.f *= ST0.f;
|
||||
#else
|
||||
ST1.d *= ST0.d;
|
||||
#endif
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 0xC8: /* FMULP STx, ST0 */
|
||||
@@ -25,11 +37,19 @@
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF:
|
||||
#ifdef USE_FLOAT
|
||||
ST(nextop&7).f *= ST0.f;
|
||||
#else
|
||||
ST(nextop&7).d *= ST0.d;
|
||||
#endif
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 0xD9: /* FCOMPP */
|
||||
#ifdef USE_FLOAT
|
||||
fpu_fcom(emu, ST1.f);
|
||||
#else
|
||||
fpu_fcom(emu, ST1.d);
|
||||
#endif
|
||||
fpu_do_pop(emu);
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
@@ -45,11 +65,19 @@
|
||||
case 0xE5:
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
#ifdef USE_FLOAT
|
||||
ST(nextop&7).f = ST0.f - ST(nextop&7).f;
|
||||
#else
|
||||
ST(nextop&7).d = ST0.d - ST(nextop&7).d;
|
||||
#endif
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 0xE9: /* FSUBP ST1, ST0 */
|
||||
#ifdef USE_FLOAT
|
||||
ST1.f -= ST0.f;
|
||||
#else
|
||||
ST1.d -= ST0.d;
|
||||
#endif
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 0xE8: /* FSUBP STx, ST0 */
|
||||
@@ -59,12 +87,13 @@
|
||||
case 0xED:
|
||||
case 0xEE:
|
||||
case 0xEF:
|
||||
#ifdef USE_FLOAT
|
||||
ST(nextop&7).f -= ST0.f;
|
||||
#else
|
||||
ST(nextop&7).d -= ST0.d;
|
||||
#endif
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
/*ST(1).d = ST0.d / ST(1).d;
|
||||
fpu_do_pop(emu);
|
||||
break;*/
|
||||
case 0xF0: /* FDIVRP STx, ST0 */
|
||||
case 0xF1: /* FDIVRP ST1, ST0 */
|
||||
case 0xF2:
|
||||
@@ -73,13 +102,13 @@
|
||||
case 0xF5:
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
#ifdef USE_FLOAT
|
||||
ST(nextop&7).f = ST0.f / ST(nextop&7).f;
|
||||
#else
|
||||
ST(nextop&7).d = ST0.d / ST(nextop&7).d;
|
||||
#endif
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
/*d = ST0.d;
|
||||
fpu_do_pop(emu);
|
||||
ST0.d /= d;
|
||||
break;*/
|
||||
case 0xF8: /* FDIVP STx, ST0 */
|
||||
case 0xF9: /* FDIVP ST1, ST0 */
|
||||
case 0xFA:
|
||||
@@ -88,7 +117,11 @@
|
||||
case 0xFD:
|
||||
case 0xFE:
|
||||
case 0xFF:
|
||||
#ifdef USE_FLOAT
|
||||
ST(nextop&7).f /= ST0.f;
|
||||
#else
|
||||
ST(nextop&7).d /= ST0.d;
|
||||
#endif
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
|
||||
@@ -113,23 +146,51 @@
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: /* FIADD ST0, Ew int */
|
||||
GET_EW;
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f += EW->sword[0];
|
||||
#else
|
||||
ST0.d += EW->sword[0];
|
||||
#endif
|
||||
break;
|
||||
case 1: /* FIMUL ST0, Ew int */
|
||||
GET_EW;
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f *= EW->sword[0];
|
||||
#else
|
||||
ST0.d *= EW->sword[0];
|
||||
#endif
|
||||
break;
|
||||
case 4: /* FISUB ST0, Ew int */
|
||||
GET_EW;
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f -= EW->sword[0];
|
||||
#else
|
||||
ST0.d -= EW->sword[0];
|
||||
#endif
|
||||
break;
|
||||
case 5: /* FISUBR ST0, Ew int */
|
||||
GET_EW;
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = EW->sword[0] - ST0.f;
|
||||
#else
|
||||
ST0.d = EW->sword[0] - ST0.d;
|
||||
#endif
|
||||
break;
|
||||
case 6: /* FIDIV ST0, Ew int */
|
||||
GET_EW;
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f /= EW->sword[0];
|
||||
#else
|
||||
ST0.d /= EW->sword[0];
|
||||
#endif
|
||||
break;
|
||||
case 7: /* FIDIVR ST0, Ew int */
|
||||
GET_EW;
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = EW->sword[0] / ST0.f;
|
||||
#else
|
||||
ST0.d = EW->sword[0] / ST0.d;
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
goto _default;
|
||||
Executable
+240
@@ -0,0 +1,240 @@
|
||||
nextop = F8;
|
||||
switch (nextop) {
|
||||
case 0xE0: /* FNSTSW AX */
|
||||
emu->sw.f.F87_TOP = emu->top&7;
|
||||
R_AX = emu->sw.x16;
|
||||
break;
|
||||
|
||||
case 0xE8: /* FUCOMIP ST0, STx */
|
||||
case 0xE9:
|
||||
case 0xEA:
|
||||
case 0xEB:
|
||||
case 0xEC:
|
||||
case 0xED:
|
||||
case 0xEE:
|
||||
case 0xEF:
|
||||
#ifdef USE_FLOAT
|
||||
fpu_fcomi(emu, ST(nextop&7).f);
|
||||
#else
|
||||
fpu_fcomi(emu, ST(nextop&7).d); // bad, should handle QNaN and IA interrupt
|
||||
#endif
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
|
||||
case 0xF0: /* FCOMIP ST0, STx */
|
||||
case 0xF1:
|
||||
case 0xF2:
|
||||
case 0xF3:
|
||||
case 0xF4:
|
||||
case 0xF5:
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
#ifdef USE_FLOAT
|
||||
fpu_fcomi(emu, ST(nextop&7).f);
|
||||
#else
|
||||
fpu_fcomi(emu, ST(nextop&7).d);
|
||||
#endif
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
case 0xC2:
|
||||
case 0xC3:
|
||||
case 0xC4:
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
case 0xCA:
|
||||
case 0xCB:
|
||||
case 0xCC:
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF:
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
case 0xD2:
|
||||
case 0xD3:
|
||||
case 0xD4:
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
case 0xD8:
|
||||
case 0xD9:
|
||||
case 0xDA:
|
||||
case 0xDB:
|
||||
case 0xDC:
|
||||
case 0xDD:
|
||||
case 0xDE:
|
||||
case 0xDF:
|
||||
case 0xE1:
|
||||
case 0xE2:
|
||||
case 0xE3:
|
||||
case 0xE4:
|
||||
case 0xE5:
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
case 0xF8:
|
||||
case 0xF9:
|
||||
case 0xFA:
|
||||
case 0xFB:
|
||||
case 0xFC:
|
||||
case 0xFD:
|
||||
case 0xFE:
|
||||
case 0xFF:
|
||||
goto _default;
|
||||
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: /* FILD ST0, Gw */
|
||||
GET_EW;
|
||||
tmp16s = EW->sword[0];
|
||||
fpu_do_push(emu);
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = tmp16s;
|
||||
#else
|
||||
ST0.d = tmp16s;
|
||||
#endif
|
||||
break;
|
||||
case 1: /* FISTTP Ew, ST0 */
|
||||
GET_EW;
|
||||
#ifdef USE_FLOAT
|
||||
tmp16s = ST0.f;
|
||||
#else
|
||||
tmp16s = ST0.d;
|
||||
#endif
|
||||
EW->sword[0] = tmp16s;
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 2: /* FIST Ew, ST0 */
|
||||
GET_EW;
|
||||
#ifdef USE_FLOAT
|
||||
if(isgreater(ST0.f, (float)(int32_t)0x7fff) || isless(ST0.f, -(float)(int32_t)0x7fff))
|
||||
EW->sword[0] = 0x8000;
|
||||
else {
|
||||
switch(emu->round) {
|
||||
case ROUND_Nearest:
|
||||
EW->sword[0] = floorf(ST0.f+0.5);
|
||||
break;
|
||||
case ROUND_Down:
|
||||
EW->sword[0] = floorf(ST0.f);
|
||||
break;
|
||||
case ROUND_Up:
|
||||
EW->sword[0] = ceilf(ST0.f);
|
||||
break;
|
||||
case ROUND_Chop:
|
||||
EW->sword[0] = ST0.f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
if(isgreater(ST0.d, (double)(int32_t)0x7fff) || isless(ST0.d, -(double)(int32_t)0x7fff))
|
||||
EW->sword[0] = 0x8000;
|
||||
else {
|
||||
switch(emu->round) {
|
||||
case ROUND_Nearest:
|
||||
EW->sword[0] = floor(ST0.d+0.5);
|
||||
break;
|
||||
case ROUND_Down:
|
||||
EW->sword[0] = floor(ST0.d);
|
||||
break;
|
||||
case ROUND_Up:
|
||||
EW->sword[0] = ceil(ST0.d);
|
||||
break;
|
||||
case ROUND_Chop:
|
||||
EW->sword[0] = ST0.d;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case 3: /* FISTP Ew, ST0 */
|
||||
GET_EW;
|
||||
#ifdef USE_FLOAT
|
||||
if(isgreater(ST0.f, (float)(int32_t)0x7fff) || isless(ST0.f, -(float)(int32_t)0x7fff))
|
||||
EW->sword[0] = 0x8000;
|
||||
else {
|
||||
switch(emu->round) {
|
||||
case ROUND_Nearest:
|
||||
EW->sword[0] = floorf(ST0.f+0.5);
|
||||
break;
|
||||
case ROUND_Down:
|
||||
EW->sword[0] = floorf(ST0.f);
|
||||
break;
|
||||
case ROUND_Up:
|
||||
EW->sword[0] = ceilf(ST0.f);
|
||||
break;
|
||||
case ROUND_Chop:
|
||||
EW->sword[0] = ST0.f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
if(isgreater(ST0.d, (double)(int32_t)0x7fff) || isless(ST0.d, -(double)(int32_t)0x7fff))
|
||||
EW->sword[0] = 0x8000;
|
||||
else {
|
||||
switch(emu->round) {
|
||||
case ROUND_Nearest:
|
||||
EW->sword[0] = floor(ST0.d+0.5);
|
||||
break;
|
||||
case ROUND_Down:
|
||||
EW->sword[0] = floor(ST0.d);
|
||||
break;
|
||||
case ROUND_Up:
|
||||
EW->sword[0] = ceil(ST0.d);
|
||||
break;
|
||||
case ROUND_Chop:
|
||||
EW->sword[0] = ST0.d;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 4: /* FBLD ST0, tbytes */
|
||||
GET_ED;
|
||||
fpu_do_push(emu);
|
||||
fpu_fbld(emu, (uint8_t*)ED);
|
||||
break;
|
||||
case 5: /* FILD ST0, Gq */
|
||||
GET_ED;
|
||||
tmp64s = *(int64_t*)ED;
|
||||
fpu_do_push(emu);
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = tmp64s;
|
||||
#else
|
||||
ST0.d = tmp64s;
|
||||
#endif
|
||||
STll(0).ll = tmp64s;
|
||||
STll(0).ref = ST0.ll;
|
||||
break;
|
||||
case 6: /* FBSTP tbytes, ST0 */
|
||||
GET_ED;
|
||||
fpu_fbst(emu, (uint8_t*)ED);
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 7: /* FISTP i64 */
|
||||
GET_ED;
|
||||
if(STll(0).ref==ST(0).ll) {
|
||||
*(int64_t*)ED = STll(0).ll;
|
||||
} else {
|
||||
#ifdef USE_FLOAT
|
||||
if(isgreater(ST0.f, (float)(int64_t)0x7fffffffffffffffLL) || isless(ST0.f, (float)(int64_t)0x8000000000000000LL))
|
||||
*(int64_t*)ED = 0x8000000000000000LL;
|
||||
else
|
||||
*(int64_t*)ED = (int64_t)ST0.f;
|
||||
#else
|
||||
if(isgreater(ST0.d, (double)(int64_t)0x7fffffffffffffffLL) || isless(ST0.d, (double)(int64_t)0x8000000000000000LL))
|
||||
*(int64_t*)ED = 0x8000000000000000LL;
|
||||
else
|
||||
*(int64_t*)ED = (int64_t)ST0.d;
|
||||
#endif
|
||||
}
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
default:
|
||||
goto _default;
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,11 @@
|
||||
GET_EX;
|
||||
EX->q[0] = GX.q[0];
|
||||
break;
|
||||
case 0x12: /* MOVDDUP Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
GX.q[1] = GX.q[0] = EX->q[0];
|
||||
break;
|
||||
|
||||
case 0x2A: /* CVTSI2SD Gx, Ed */
|
||||
nextop = F8;
|
||||
@@ -23,12 +28,28 @@
|
||||
break;
|
||||
|
||||
case 0x2C: /* CVTTSD2SI Gd, Ex */
|
||||
case 0x2D: /* CVTSD2SI Gd, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
GD.sdword[0] = EX->d[0];
|
||||
break;
|
||||
|
||||
case 0x2D: /* CVTSD2SI Gd, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
switch(emu->round) {
|
||||
case ROUND_Nearest:
|
||||
GD.sdword[0] = floor(EX->d[0]+0.5);
|
||||
break;
|
||||
case ROUND_Down:
|
||||
GD.sdword[0] = floor(EX->d[0]);
|
||||
break;
|
||||
case ROUND_Up:
|
||||
GD.sdword[0] = ceil(EX->d[0]);
|
||||
break;
|
||||
case ROUND_Chop:
|
||||
GD.sdword[0] = EX->d[0];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x51: /* SQRTSD Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
@@ -90,6 +111,20 @@
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x7C: /* HADDPS Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
GX.f[0] += GX.f[1];
|
||||
GX.f[1] = GX.f[2] + GX.f[3];
|
||||
if(EX==&GX) {
|
||||
GX.f[2] = GX.f[0];
|
||||
GX.f[3] = GX.f[1];
|
||||
} else {
|
||||
GX.f[2] = EX->f[0] + EX->f[1];
|
||||
GX.f[3] = EX->f[2] + EX->f[3];
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC2: /* CMPSD Gx, Ex, Ib */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
@@ -15,6 +15,15 @@
|
||||
GET_EX;
|
||||
EX->ud[0] = GX.ud[0];
|
||||
break;
|
||||
|
||||
case 0x1E: /* NOP / ENDBR32 / ENDBR64 */
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
break;
|
||||
case 0x1F: /* REP NOP */
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
break;
|
||||
|
||||
case 0x2A: /* CVTSI2SS Gx, Ed */
|
||||
nextop = F8;
|
||||
@@ -23,17 +32,44 @@
|
||||
break;
|
||||
|
||||
case 0x2C: /* CVTTSS2SI Gd, Ex */
|
||||
case 0x2D: /* CVTSS2SI Gd, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
GD.sdword[0] = EX->f[0];
|
||||
break;
|
||||
case 0x2D: /* CVTSS2SI Gd, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
switch(emu->round) {
|
||||
case ROUND_Nearest:
|
||||
GD.sdword[0] = floor(EX->f[0]+0.5);
|
||||
break;
|
||||
case ROUND_Down:
|
||||
GD.sdword[0] = floor(EX->f[0]);
|
||||
break;
|
||||
case ROUND_Up:
|
||||
GD.sdword[0] = ceil(EX->f[0]);
|
||||
break;
|
||||
case ROUND_Chop:
|
||||
GD.sdword[0] = EX->f[0];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x51: /* SQRTSS Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
GX.f[0] = sqrtf(EX->f[0]);
|
||||
break;
|
||||
case 0x52: /* RSQRTSS Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
GX.f[0] = 1.0f/sqrtf(EX->f[0]);
|
||||
break;
|
||||
case 0x53: /* RCPSS Gx, Ex */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
GX.f[0] = 1.0f/EX->f[0];
|
||||
break;
|
||||
|
||||
case 0x58: /* ADDSS Gx, Ex */
|
||||
nextop = F8;
|
||||
@@ -114,6 +150,25 @@
|
||||
memcpy(EX, &GX, 16); // unaligned...
|
||||
break;
|
||||
|
||||
case 0xBC: /* TZCNT Ed,Gd */
|
||||
CHECK_FLAGS(emu);
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
tmp32u = ED->dword[0];
|
||||
if(tmp32u) {
|
||||
CLEAR_FLAG(F_ZF);
|
||||
tmp8u = 0;
|
||||
while(!(tmp32u&(1<<tmp8u))) ++tmp8u;
|
||||
GD.dword[0] = tmp8u;
|
||||
CONDITIONAL_SET_FLAG(tmp8u==0, F_ZF);
|
||||
CLEAR_FLAG(F_CF);
|
||||
} else {
|
||||
CLEAR_FLAG(F_ZF);
|
||||
SET_FLAG(F_CF);
|
||||
GD.dword[0] = 32;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC2: /* CMPSS Gx, Ex, Ib */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
Executable
+466
@@ -0,0 +1,466 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86stack.h"
|
||||
#include "x86emu.h"
|
||||
#include "x86emu_private.h"
|
||||
#include "x87emu_private.h"
|
||||
#include "box86context.h"
|
||||
#include "x86run.h"
|
||||
#include "x86run_private.h"
|
||||
#include "callback.h"
|
||||
|
||||
typedef struct cleanup_s {
|
||||
void* f;
|
||||
int arg;
|
||||
void* a;
|
||||
} cleanup_t;
|
||||
|
||||
static uint32_t x86emu_parity_tab[8] =
|
||||
{
|
||||
0x96696996,
|
||||
0x69969669,
|
||||
0x69969669,
|
||||
0x96696996,
|
||||
0x69969669,
|
||||
0x96696996,
|
||||
0x96696996,
|
||||
0x69969669,
|
||||
};
|
||||
|
||||
static uint8_t EndEmuMarker[] = {0xcc, 'S', 'C', 0, 0, 0, 0};
|
||||
void PushExit(x86emu_t* emu)
|
||||
{
|
||||
Push(emu, (uint32_t)&EndEmuMarker);
|
||||
}
|
||||
|
||||
void* GetExit()
|
||||
{
|
||||
return &EndEmuMarker;
|
||||
}
|
||||
|
||||
static void internalX86Setup(x86emu_t* emu, box86context_t *context, uintptr_t start, uintptr_t stack, int stacksize, int ownstack)
|
||||
{
|
||||
emu->context = context;
|
||||
// setup cpu helpers
|
||||
for (int i=0; i<8; ++i)
|
||||
emu->sbiidx[i] = &emu->regs[i];
|
||||
emu->sbiidx[4] = &emu->zero;
|
||||
emu->x86emu_parity_tab = x86emu_parity_tab;
|
||||
emu->packed_eflags.x32 = 0x202; // default flags?
|
||||
UnpackFlags(emu);
|
||||
// own stack?
|
||||
emu->stack2free = (ownstack)?(void*)stack:NULL;
|
||||
emu->init_stack = (void*)stack;
|
||||
emu->size_stack = stacksize;
|
||||
// set default value
|
||||
R_EIP = start;
|
||||
R_ESP = (stack + stacksize) & ~7; // align stack start, always
|
||||
// fake init of segments...
|
||||
emu->segs[_CS] = 0x73;
|
||||
emu->segs[_DS] = emu->segs[_ES] = emu->segs[_SS] = 0x7b;
|
||||
emu->segs[_FS] = default_fs;
|
||||
emu->segs[_GS] = 0x33;
|
||||
// setup fpu regs
|
||||
reset_fpu(emu);
|
||||
}
|
||||
|
||||
EXPORTDYN
|
||||
x86emu_t *NewX86Emu(box86context_t *context, uintptr_t start, uintptr_t stack, int stacksize, int ownstack)
|
||||
{
|
||||
printf_log(LOG_DEBUG, "Allocate a new X86 Emu, with EIP=%p and Stack=%p/0x%X\n", (void*)start, (void*)stack, stacksize);
|
||||
|
||||
x86emu_t *emu = (x86emu_t*)calloc(1, sizeof(x86emu_t));
|
||||
|
||||
internalX86Setup(emu, context, start, stack, stacksize, ownstack);
|
||||
|
||||
return emu;
|
||||
}
|
||||
|
||||
x86emu_t *NewX86EmuFromStack(x86emu_t* emu, box86context_t *context, uintptr_t start, uintptr_t stack, int stacksize, int ownstack)
|
||||
{
|
||||
printf_log(LOG_DEBUG, "New X86 Emu from stack, with EIP=%p and Stack=%p/0x%X\n", (void*)start, (void*)stack, stacksize);
|
||||
|
||||
internalX86Setup(emu, context, start, stack, stacksize, ownstack);
|
||||
|
||||
return emu;
|
||||
}
|
||||
|
||||
EXPORTDYN
|
||||
void SetupX86Emu(x86emu_t *emu)
|
||||
{
|
||||
printf_log(LOG_DEBUG, "Setup X86 Emu\n");
|
||||
}
|
||||
|
||||
void SetTraceEmu(uintptr_t start, uintptr_t end)
|
||||
{
|
||||
if(my_context->zydis) {
|
||||
if (end == 0) {
|
||||
printf_log(LOG_INFO, "Setting trace\n");
|
||||
} else {
|
||||
if(end!=1) { // 0-1 is basically no trace, so don't printf it...
|
||||
printf_log(LOG_INFO, "Setting trace only between %p and %p\n", (void*)start, (void*)end);
|
||||
}
|
||||
}
|
||||
}
|
||||
trace_start = start;
|
||||
trace_end = end;
|
||||
}
|
||||
|
||||
void AddCleanup(x86emu_t *emu, void *p)
|
||||
{
|
||||
if(my_context->clean_sz == my_context->clean_cap) {
|
||||
my_context->clean_cap += 4;
|
||||
my_context->cleanups = (cleanup_t*)realloc(my_context->cleanups, sizeof(cleanup_t)*my_context->clean_cap);
|
||||
}
|
||||
my_context->cleanups[my_context->clean_sz].arg = 0;
|
||||
my_context->cleanups[my_context->clean_sz].a = NULL;
|
||||
my_context->cleanups[my_context->clean_sz++].f = p;
|
||||
}
|
||||
|
||||
void AddCleanup1Arg(x86emu_t *emu, void *p, void* a)
|
||||
{
|
||||
if(my_context->clean_sz == my_context->clean_cap) {
|
||||
my_context->clean_cap += 4;
|
||||
my_context->cleanups = (cleanup_t*)realloc(my_context->cleanups, sizeof(cleanup_t)*my_context->clean_cap);
|
||||
}
|
||||
my_context->cleanups[my_context->clean_sz].arg = 1;
|
||||
my_context->cleanups[my_context->clean_sz].a = a;
|
||||
my_context->cleanups[my_context->clean_sz++].f = p;
|
||||
}
|
||||
|
||||
void CallCleanup(x86emu_t *emu, void* p)
|
||||
{
|
||||
printf_log(LOG_DEBUG, "Calling atexit registered functions for %p mask\n", p);
|
||||
for(int i=my_context->clean_sz-1; i>=0; --i) {
|
||||
if(p==my_context->cleanups[i].f) {
|
||||
printf_log(LOG_DEBUG, "Call cleanup #%d\n", i);
|
||||
RunFunctionWithEmu(emu, 0, (uintptr_t)(my_context->cleanups[i].f), my_context->cleanups[i].arg, my_context->cleanups[i].a );
|
||||
// now remove the cleanup
|
||||
if(i!=my_context->clean_sz-1)
|
||||
memmove(my_context->cleanups+i, my_context->cleanups+i+1, (my_context->clean_sz-i-1)*sizeof(cleanup_t));
|
||||
--my_context->clean_sz;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CallAllCleanup(x86emu_t *emu)
|
||||
{
|
||||
printf_log(LOG_DEBUG, "Calling atexit registered functions\n");
|
||||
for(int i=my_context->clean_sz-1; i>=0; --i) {
|
||||
printf_log(LOG_DEBUG, "Call cleanup #%d\n", i);
|
||||
RunFunctionWithEmu(emu, 0, (uintptr_t)(my_context->cleanups[i].f), my_context->cleanups[i].arg, my_context->cleanups[i].a );
|
||||
}
|
||||
my_context->clean_sz = 0;
|
||||
}
|
||||
|
||||
static void internalFreeX86(x86emu_t* emu)
|
||||
{
|
||||
free(emu->stack2free);
|
||||
}
|
||||
|
||||
EXPORTDYN
|
||||
void FreeX86Emu(x86emu_t **emu)
|
||||
{
|
||||
if(!emu)
|
||||
return;
|
||||
printf_log(LOG_DEBUG, "Free a X86 Emu (%p)\n", *emu);
|
||||
|
||||
internalFreeX86(*emu);
|
||||
|
||||
free(*emu);
|
||||
*emu = NULL;
|
||||
}
|
||||
|
||||
void FreeX86EmuFromStack(x86emu_t **emu)
|
||||
{
|
||||
if(!emu)
|
||||
return;
|
||||
printf_log(LOG_DEBUG, "Free a X86 Emu from stack (%p)\n", *emu);
|
||||
|
||||
internalFreeX86(*emu);
|
||||
}
|
||||
|
||||
void CloneEmu(x86emu_t *newemu, const x86emu_t* emu)
|
||||
{
|
||||
memcpy(newemu->regs, emu->regs, sizeof(emu->regs));
|
||||
memcpy(&newemu->ip, &emu->ip, sizeof(emu->ip));
|
||||
memcpy(&newemu->packed_eflags, &emu->packed_eflags, sizeof(emu->packed_eflags));
|
||||
memcpy(&newemu->flags, &emu->flags, sizeof(emu->flags));
|
||||
newemu->old_ip = emu->old_ip;
|
||||
memcpy(newemu->segs, emu->segs, sizeof(emu->segs));
|
||||
memset(newemu->segs_clean, 0, sizeof(newemu->segs_clean));
|
||||
memcpy(newemu->fpu, emu->fpu, sizeof(emu->fpu));
|
||||
memcpy(newemu->fpu_ld, emu->fpu_ld, sizeof(emu->fpu_ld));
|
||||
memcpy(newemu->fpu_ll, emu->fpu_ll, sizeof(emu->fpu_ll));
|
||||
memcpy(newemu->p_regs, emu->p_regs, sizeof(emu->p_regs));
|
||||
newemu->cw = emu->cw;
|
||||
newemu->cw_mask_all = emu->cw_mask_all;
|
||||
memcpy(&newemu->sw, &emu->sw, sizeof(emu->sw));
|
||||
newemu->top = emu->top;
|
||||
newemu->fpu_stack = emu->fpu_stack;
|
||||
memcpy(&newemu->round, &emu->round, sizeof(emu->round));
|
||||
memcpy(newemu->mmx, emu->mmx, sizeof(emu->mmx));
|
||||
memcpy(newemu->xmm, emu->xmm, sizeof(emu->xmm));
|
||||
newemu->mxcsr = emu->mxcsr;
|
||||
newemu->quit = emu->quit;
|
||||
newemu->error = emu->error;
|
||||
// adapt R_ESP to new stack frame
|
||||
uintptr_t oldst = (uintptr_t)((emu->init_stack)?emu->init_stack:emu->context->stack);
|
||||
uintptr_t newst = (uintptr_t)((newemu->init_stack)?newemu->init_stack:newemu->context->stack);
|
||||
newemu->regs[_SP].dword[0] = emu->regs[_SP].dword[0] + (intptr_t)(newst - oldst);
|
||||
}
|
||||
|
||||
box86context_t* GetEmuContext(x86emu_t* emu)
|
||||
{
|
||||
return emu->context;
|
||||
}
|
||||
|
||||
uint32_t GetEAX(x86emu_t *emu)
|
||||
{
|
||||
return R_EAX;
|
||||
}
|
||||
uint64_t GetEDXEAX(x86emu_t *emu)
|
||||
{
|
||||
return ((uint64_t)R_EAX)|(((uint64_t)R_EDX)<<32);
|
||||
}
|
||||
void SetEAX(x86emu_t *emu, uint32_t v)
|
||||
{
|
||||
R_EAX = v;
|
||||
}
|
||||
void SetEBX(x86emu_t *emu, uint32_t v)
|
||||
{
|
||||
R_EBX = v;
|
||||
}
|
||||
void SetECX(x86emu_t *emu, uint32_t v)
|
||||
{
|
||||
R_ECX = v;
|
||||
}
|
||||
void SetEDX(x86emu_t *emu, uint32_t v)
|
||||
{
|
||||
R_EDX = v;
|
||||
}
|
||||
void SetEIP(x86emu_t *emu, uint32_t v)
|
||||
{
|
||||
R_EIP = v;
|
||||
}
|
||||
void SetESI(x86emu_t *emu, uint32_t v)
|
||||
{
|
||||
R_ESI = v;
|
||||
}
|
||||
void SetEDI(x86emu_t *emu, uint32_t v)
|
||||
{
|
||||
R_EDI = v;
|
||||
}
|
||||
void SetEBP(x86emu_t *emu, uint32_t v)
|
||||
{
|
||||
R_EBP = v;
|
||||
}
|
||||
void SetESP(x86emu_t *emu, uint32_t v)
|
||||
{
|
||||
R_ESP = v;
|
||||
}
|
||||
uint32_t GetESP(x86emu_t *emu)
|
||||
{
|
||||
return R_ESP;
|
||||
}
|
||||
void SetFS(x86emu_t *emu, uint16_t v)
|
||||
{
|
||||
emu->segs[_FS] = v;
|
||||
}
|
||||
uint16_t GetFS(x86emu_t *emu)
|
||||
{
|
||||
return emu->segs[_FS];
|
||||
}
|
||||
|
||||
|
||||
void ResetFlags(x86emu_t *emu)
|
||||
{
|
||||
emu->df = d_none;
|
||||
}
|
||||
|
||||
const char* DumpCPURegs(x86emu_t* emu, uintptr_t ip)
|
||||
{
|
||||
static char buff[800];
|
||||
char* regname[] = {"EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI", "EDI"};
|
||||
char tmp[80];
|
||||
buff[0] = '\0';
|
||||
if(trace_emm) {
|
||||
// do emm reg is needed
|
||||
for(int i=0; i<8; ++i) {
|
||||
sprintf(tmp, "mm%d:%016llx", i, emu->mmx[i].q);
|
||||
strcat(buff, tmp);
|
||||
if ((i&3)==3) strcat(buff, "\n"); else strcat(buff, " ");
|
||||
}
|
||||
}
|
||||
if(trace_xmm) {
|
||||
// do xmm reg is needed
|
||||
for(int i=0; i<8; ++i) {
|
||||
sprintf(tmp, "%d:%016llx%016llx", i, emu->xmm[i].q[1], emu->xmm[i].q[0]);
|
||||
strcat(buff, tmp);
|
||||
if ((i&3)==3) strcat(buff, "\n"); else strcat(buff, " ");
|
||||
}
|
||||
}
|
||||
// start with FPU regs...
|
||||
if(emu->fpu_stack) {
|
||||
for (int i=0; i<emu->fpu_stack; i++) {
|
||||
#ifdef USE_FLOAT
|
||||
sprintf(tmp, "ST%d=%f", i, emu->fpu[(emu->top+i)&7].f);
|
||||
#else
|
||||
sprintf(tmp, "ST%d=%f", i, emu->fpu[(emu->top+i)&7].d);
|
||||
#endif
|
||||
strcat(buff, tmp);
|
||||
int c = 10-strlen(tmp);
|
||||
if(c<1) c=1;
|
||||
while(c--) strcat(buff, " ");
|
||||
if(i==3) strcat(buff, "\n");
|
||||
}
|
||||
strcat(buff, "\n");
|
||||
}
|
||||
for (int i=_AX; i<=_DI; ++i) {
|
||||
sprintf(tmp, "%s=%08x ", regname[i], emu->regs[i].dword[0]);
|
||||
strcat(buff, tmp);
|
||||
|
||||
if (i==3) {
|
||||
if(emu->df) {
|
||||
strcat(buff, "FLAGS=??????\n");
|
||||
} else {
|
||||
#define FLAG_CHAR(f) (ACCESS_FLAG(F_##f##F)) ? #f : "-"
|
||||
sprintf(tmp, "FLAGS=%s%s%s%s%s%s\n", FLAG_CHAR(O), FLAG_CHAR(C), FLAG_CHAR(P), FLAG_CHAR(A), FLAG_CHAR(Z), FLAG_CHAR(S));
|
||||
strcat(buff, tmp);
|
||||
#undef FLAG_CHAR
|
||||
}
|
||||
}
|
||||
}
|
||||
sprintf(tmp, "EIP=%08x ", ip);
|
||||
strcat(buff, tmp);
|
||||
return buff;
|
||||
}
|
||||
|
||||
void StopEmu(x86emu_t* emu, const char* reason)
|
||||
{
|
||||
emu->quit = 1;
|
||||
printf_log(LOG_NONE, "%s", reason);
|
||||
// dump stuff...
|
||||
printf_log(LOG_NONE, "CPU Regs=%s\n", DumpCPURegs(emu, R_EIP));
|
||||
// TODO: stack, memory/instruction around EIP, etc..
|
||||
}
|
||||
|
||||
void UnimpOpcode(x86emu_t* emu)
|
||||
{
|
||||
R_EIP = emu->old_ip;
|
||||
|
||||
int tid = syscall(SYS_gettid);
|
||||
printf_log(LOG_NONE, "%04d|%p: Unimplemented Opcode %02X %02X %02X %02X %02X %02X %02X %02X\n",
|
||||
tid, (void*)emu->old_ip,
|
||||
Peek(emu, 0), Peek(emu, 1), Peek(emu, 2), Peek(emu, 3),
|
||||
Peek(emu, 4), Peek(emu, 5), Peek(emu, 6), Peek(emu, 7));
|
||||
emu->quit=1;
|
||||
emu->error |= ERR_UNIMPL;
|
||||
}
|
||||
|
||||
void EmuCall(x86emu_t* emu, uintptr_t addr)
|
||||
{
|
||||
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;
|
||||
Run(emu, 0);
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__ARM_ARCH)
|
||||
#if (__ARM_ARCH >= 6)
|
||||
static inline unsigned int arm_perf (void)
|
||||
{
|
||||
unsigned int value;
|
||||
// Read CCNT Register
|
||||
asm volatile ("MRC p15, 0, %0, c9, c13, 0\t\n": "=r"(value));
|
||||
return value;
|
||||
}
|
||||
static inline void init_perfcounters (int32_t do_reset, int32_t enable_divider)
|
||||
{
|
||||
// in general enable all counters (including cycle counter)
|
||||
int32_t value = 1;
|
||||
|
||||
// peform reset:
|
||||
if (do_reset)
|
||||
{
|
||||
value |= 2; // reset all counters to zero.
|
||||
value |= 4; // reset cycle counter to zero.
|
||||
}
|
||||
|
||||
if (enable_divider)
|
||||
value |= 8; // enable "by 64" divider for CCNT.
|
||||
|
||||
value |= 16;
|
||||
|
||||
// program the performance-counter control-register:
|
||||
asm volatile ("MCR p15, 0, %0, c9, c12, 0\t\n" :: "r"(value));
|
||||
|
||||
// enable all counters:
|
||||
asm volatile ("MCR p15, 0, %0, c9, c12, 1\t\n" :: "r"(0x8000000f));
|
||||
|
||||
// clear overflows:
|
||||
asm volatile ("MCR p15, 0, %0, c9, c12, 3\t\n" :: "r"(0x8000000f));
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
uint64_t ReadTSC(x86emu_t* emu)
|
||||
{
|
||||
// Read the TimeStamp Counter as 64bits.
|
||||
// this is supposed to be the number of instrunctions executed since last reset
|
||||
#if defined(__i386__)
|
||||
uint64_t ret;
|
||||
__asm__ volatile("rdtsc" : "=A"(ret));
|
||||
return ret;
|
||||
#if 0
|
||||
#elif defined(__ARM_ARCH)
|
||||
#if (__ARM_ARCH >= 6)
|
||||
static int init = 1;
|
||||
if(init) {
|
||||
init_perfcounters(1, 1);
|
||||
init = 0;
|
||||
}
|
||||
uint32_t perf = arm_perf();
|
||||
if(perf) {
|
||||
return ((uint64_t)perf)*64;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
// fall back to gettime...
|
||||
#ifndef NOGETCLOCK
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC_COARSE, &ts);
|
||||
return (uint64_t)(ts.tv_sec) * 1000000000LL + ts.tv_nsec;
|
||||
#else
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
return (uint64_t)(tv.tv_sec) * 1000000 + tv.tv_usec;
|
||||
#endif
|
||||
}
|
||||
@@ -3,14 +3,25 @@
|
||||
|
||||
#include "regs.h"
|
||||
|
||||
typedef struct zydis_dec_s zydis_dec_t;
|
||||
typedef struct box86context_s box86context_t;
|
||||
typedef struct i386_ucontext_s i386_ucontext_t;
|
||||
|
||||
#define ERR_UNIMPL 1
|
||||
#define ERR_DIVBY0 2
|
||||
#define ERR_ILLEGAL 4
|
||||
|
||||
typedef struct cleanup_s cleanup_t;
|
||||
#ifdef DYNAREC
|
||||
#define CSTACK 32
|
||||
#define CSTACKMASK 31
|
||||
#endif
|
||||
|
||||
typedef struct forkpty_s {
|
||||
void* amaster;
|
||||
void* name;
|
||||
void* termp;
|
||||
void* winp;
|
||||
void* f; // forkpty function
|
||||
} forkpty_t;
|
||||
|
||||
typedef struct x86emu_s {
|
||||
// cpu
|
||||
@@ -18,51 +29,59 @@ typedef struct x86emu_s {
|
||||
int flags[F_LAST];
|
||||
x86flags_t packed_eflags;
|
||||
uintptr_t old_ip;
|
||||
// segments
|
||||
uint32_t segs[6]; // only 32bits value?
|
||||
// fpu
|
||||
fpu_reg_t fpu[9];
|
||||
fpu_ld_t fpu_ld[9]; // for long double emulation / 80bits fld fst
|
||||
fpu_ll_t fpu_ll[9]; // for 64bits fild / fist sequence
|
||||
fpu_p_reg_t p_regs[9];
|
||||
uint16_t cw,cw_mask_all;
|
||||
x87flags_t sw;
|
||||
uint32_t top; // top is part of sw, but it's faster to have it separatly
|
||||
int fpu_stack;
|
||||
fpu_round_t round;
|
||||
fpu_ld_t fpu_ld[9]; // for long double emulation / 80bits fld fst
|
||||
fpu_ll_t fpu_ll[9]; // for 64bits fild / fist sequence
|
||||
fpu_p_reg_t p_regs[9];
|
||||
// mmx
|
||||
mmx_regs_t mmx[8];
|
||||
// sse
|
||||
sse_regs_t xmm[8];
|
||||
uint32_t mxcsr;
|
||||
// cpu helpers
|
||||
reg32_t zero;
|
||||
reg32_t *sbiidx[8];
|
||||
// defered flags
|
||||
defered_flags_t df;
|
||||
uint32_t op1;
|
||||
uint32_t op2;
|
||||
uint32_t res;
|
||||
uint32_t *x86emu_parity_tab; // helper
|
||||
#ifdef HAVE_TRACE
|
||||
uintptr_t prev2_ip, prev_ip;
|
||||
#endif
|
||||
// segments
|
||||
uint32_t segs[6]; // only 32bits value?
|
||||
uintptr_t segs_offs[6]; // computed offset associate with segment
|
||||
int segs_clean[6]; // are seg offset clean (1) or does they need to be re-computed (0)?
|
||||
// emu control
|
||||
int quit;
|
||||
int error;
|
||||
int fork; // quit because need to fork
|
||||
// trace
|
||||
zydis_dec_t *dec;
|
||||
uintptr_t trace_start, trace_end;
|
||||
// global stuffs, pointed with GS: segment
|
||||
void *globals;
|
||||
int *shared_global;
|
||||
forkpty_t* forkpty_info;
|
||||
int exit;
|
||||
int quitonlongjmp; // quit if longjmp is called
|
||||
int longjmp; // if quit because of longjmp
|
||||
#ifdef DYNAREC
|
||||
int cstacki; // current index
|
||||
uint64_t cstack[CSTACK+1]; // pair of x86 address / native address for call/ret, using uint64_t for alignement, +1 for allignment
|
||||
#endif
|
||||
// parent context
|
||||
box86context_t *context;
|
||||
// atexit and fini functions
|
||||
cleanup_t *cleanups;
|
||||
int clean_sz;
|
||||
int clean_cap;
|
||||
// scratch stack, used for alignement of double and 64bits ints on arm
|
||||
uint32_t *scratch;
|
||||
// cpu helpers
|
||||
reg32_t zero;
|
||||
reg32_t *sbiidx[8];
|
||||
// scratch stack, used for alignement of double and 64bits ints on arm. 200 elements should be enough
|
||||
uint32_t scratch[200];
|
||||
// local stack, do be deleted when emu is freed
|
||||
void* stack;
|
||||
void* stack2free; // this is the stack to free (can be NULL)
|
||||
void* init_stack; // initial stack (owned or not)
|
||||
uint32_t size_stack; // stack size (owned or not)
|
||||
|
||||
i386_ucontext_t *uc_link; // to handle setcontext
|
||||
|
||||
} x86emu_t;
|
||||
|
||||
Executable
+265
@@ -0,0 +1,265 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/types.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86stack.h"
|
||||
#include "x86emu.h"
|
||||
#include "x86run.h"
|
||||
#include "x86emu_private.h"
|
||||
#include "x86run_private.h"
|
||||
#include "x87emu_private.h"
|
||||
#include "x86primop.h"
|
||||
#include "x86trace.h"
|
||||
#include "wrapper.h"
|
||||
#include "box86context.h"
|
||||
#include "librarian.h"
|
||||
|
||||
#include <elf.h>
|
||||
#include "elfloader.h"
|
||||
#include "elfs/elfloader_private.h"
|
||||
|
||||
typedef int32_t (*iFpppp_t)(void*, void*, void*, void*);
|
||||
|
||||
x86emu_t* x86emu_fork(x86emu_t* emu, int forktype)
|
||||
{
|
||||
// execute atforks prepare functions, in reverse order
|
||||
for (int i=my_context->atfork_sz-1; i>=0; --i)
|
||||
if(my_context->atforks[i].prepare)
|
||||
EmuCall(emu, my_context->atforks[i].prepare);
|
||||
int v;
|
||||
if(forktype==2) {
|
||||
iFpppp_t forkpty = (iFpppp_t)emu->forkpty_info->f;
|
||||
v = forkpty(emu->forkpty_info->amaster, emu->forkpty_info->name, emu->forkpty_info->termp, emu->forkpty_info->winp);
|
||||
emu->forkpty_info = NULL;
|
||||
} else
|
||||
v = fork();
|
||||
if(v==EAGAIN || v==ENOMEM) {
|
||||
// error...
|
||||
} else if(v!=0) {
|
||||
// execute atforks parent functions
|
||||
for (int i=0; i<my_context->atfork_sz; --i)
|
||||
if(my_context->atforks[i].parent)
|
||||
EmuCall(emu, my_context->atforks[i].parent);
|
||||
|
||||
} else if(v==0) {
|
||||
// execute atforks child functions
|
||||
for (int i=0; i<my_context->atfork_sz; --i)
|
||||
if(my_context->atforks[i].child)
|
||||
EmuCall(emu, my_context->atforks[i].child);
|
||||
}
|
||||
R_EAX = v;
|
||||
return emu;
|
||||
}
|
||||
|
||||
extern int errno;
|
||||
void x86Int3(x86emu_t* emu)
|
||||
{
|
||||
if(Peek(emu, 0)=='S' && Peek(emu, 1)=='C') // Signature for "Out of x86 door"
|
||||
{
|
||||
R_EIP += 2;
|
||||
uint32_t addr = Fetch32(emu);
|
||||
if(addr==0) {
|
||||
//printf_log(LOG_INFO, "%p:Exit x86 emu (emu=%p)\n", *(void**)(R_ESP), emu);
|
||||
emu->quit=1; // normal quit
|
||||
} else {
|
||||
RESET_FLAGS(emu);
|
||||
wrapper_t w = (wrapper_t)addr;
|
||||
addr = Fetch32(emu);
|
||||
/* This party can be used to trace only 1 specific lib (but it is quite slow)
|
||||
elfheader_t *h = FindElfAddress(my_context, *(uintptr_t*)(R_ESP));
|
||||
int have_trace = 0;
|
||||
if(h && strstr(ElfName(h), "libMiles")) have_trace = 1;*/
|
||||
if(box86_log>=LOG_DEBUG /*|| have_trace*/) {
|
||||
pthread_mutex_lock(&emu->context->mutex_trace);
|
||||
int tid = GetTID();
|
||||
char buff[256] = "\0";
|
||||
char buff2[64] = "\0";
|
||||
char buff3[64] = "\0";
|
||||
char *tmp;
|
||||
int post = 0;
|
||||
int perr = 0;
|
||||
uint32_t *pu32 = NULL;
|
||||
const char *s = GetNativeName((void*)addr);
|
||||
if(addr==(uintptr_t)PltResolver) {
|
||||
snprintf(buff, 256, "%s", " ... ");
|
||||
} else
|
||||
if(strstr(s, "SDL_RWFromFile")==s || strstr(s, "SDL_RWFromFile")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%s, %s)", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(char**)(R_ESP+8));
|
||||
} else if(strstr(s, "glColor4f")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%f, %f, %f, %f)", tid, *(void**)(R_ESP), s, *(float*)(R_ESP+4), *(float*)(R_ESP+8), *(float*)(R_ESP+12), *(float*)(R_ESP+16));
|
||||
} else if(strstr(s, "glTexCoord2f")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%f, %f)", tid, *(void**)(R_ESP), s, *(float*)(R_ESP+4), *(float*)(R_ESP+8));
|
||||
} else if(strstr(s, "glVertex2f")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%f, %f)", tid, *(void**)(R_ESP), s, *(float*)(R_ESP+4), *(float*)(R_ESP+8));
|
||||
} else if(strstr(s, "glVertex3f")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%f, %f, %f)", tid, *(void**)(R_ESP), s, *(float*)(R_ESP+4), *(float*)(R_ESP+8), *(float*)(R_ESP+12));
|
||||
} else if(strstr(s, "__open64")==s || strcmp(s, "open64")==0) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", %d, %d)", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(int*)(R_ESP+8), *(int*)(R_ESP+12));
|
||||
perr = 1;
|
||||
} else if(!strcmp(s, "opendir")) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\")", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4));
|
||||
perr = 1;
|
||||
} else if(strstr(s, "__open")==s || strcmp(s, "open")==0) {
|
||||
tmp = *(char**)(R_ESP+4);
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", %d (,%d))", tid, *(void**)(R_ESP), s, (tmp)?tmp:"(nil)", *(int*)(R_ESP+8), *(int*)(R_ESP+12));
|
||||
perr = 1;
|
||||
} else if(!strcmp(s, "fopen")) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", \"%s\")", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(char**)(R_ESP+8));
|
||||
perr = 1;
|
||||
} else if(!strcmp(s, "fopen64")) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", \"%s\")", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(char**)(R_ESP+8));
|
||||
perr = 2;
|
||||
} else if(!strcmp(s, "chdir")) {
|
||||
pu32=*(uint32_t**)(R_ESP+4);
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\")", tid, *(void**)(R_ESP), s, pu32?((pu32==(uint32_t*)1)?"/1/":(char*)pu32):"/0/");
|
||||
} else if(strstr(s, "getenv")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\")", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4));
|
||||
post = 2;
|
||||
} else if(strstr(s, "pread")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p, %u, %d)", tid, *(void**)(R_ESP), s, *(int32_t*)(R_ESP+4), *(void**)(R_ESP+8), *(uint32_t*)(R_ESP+12), *(int32_t*)(R_ESP+16));
|
||||
perr = 1;
|
||||
} else if(strstr(s, "ioctl")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%d, 0x%x, %p)", tid, *(void**)(R_ESP), s, *(int32_t*)(R_ESP+4), *(int32_t*)(R_ESP+8), *(void**)(R_ESP+12));
|
||||
perr = 1;
|
||||
} else if(strstr(s, "statvfs64")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p(\"%s\"), %p)", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(char**)(R_ESP+4), *(void**)(R_ESP+8));
|
||||
} else if(strstr(s, "index")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p(\"%s\"), %i(%c))", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(char**)(R_ESP+4), *(int32_t*)(R_ESP+8), *(int32_t*)(R_ESP+8));
|
||||
} else if(strstr(s, "rindex")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p(\"%s\"), %i(%c))", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(char**)(R_ESP+4), *(int32_t*)(R_ESP+8), *(int32_t*)(R_ESP+8));
|
||||
} else if(strstr(s, "__xstat64")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p(\"%s\"), %p)", tid, *(void**)(R_ESP), s, *(int32_t*)(R_ESP+4), *(char**)(R_ESP+8), *(char**)(R_ESP+8), *(void**)(R_ESP+12));
|
||||
perr = 1;
|
||||
} else if(strstr(s, "__lxstat64")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p(\"%s\"), %p)", tid, *(void**)(R_ESP), s, *(int32_t*)(R_ESP+4), *(char**)(R_ESP+8), *(char**)(R_ESP+8), *(void**)(R_ESP+12));
|
||||
perr = 1;
|
||||
} else if(strstr(s, "sem_timedwait")==s) {
|
||||
pu32 = *(uint32_t**)(R_ESP+8);
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p, %p[%d sec %d ns])", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(void**)(R_ESP+8), pu32?pu32[0]:-1, pu32?pu32[1]:-1);
|
||||
perr = 1;
|
||||
} else if(strstr(s, "clock_gettime")==s || strstr(s, "__clock_gettime")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p)", tid, *(void**)(R_ESP), s, *(uint32_t*)(R_ESP+4), *(void**)(R_ESP+8));
|
||||
post = 1;
|
||||
pu32 = *(uint32_t**)(R_ESP+8);
|
||||
} else if(strstr(s, "semop")==s) {
|
||||
int16_t* p16 = *(int16_t**)(R_ESP+8);
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p[%u/%d/%d], %d)", tid, *(void**)(R_ESP), s, *(int*)(R_ESP+4), p16, p16[0], p16[1], p16[2], *(int*)(R_ESP+12));
|
||||
perr = 1;
|
||||
} else if(!strcmp(s, "mmap64")) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p, 0x%x, %d, 0x%x, %d, %lld)", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(size_t*)(R_ESP+8), *(int*)(R_ESP+12), *(int*)(R_ESP+16), *(int*)(R_ESP+20), *(int64_t*)(R_ESP+24));
|
||||
perr = 1;
|
||||
} else if(!strcmp(s, "mmap")) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p, 0x%x, %d, 0x%x, %d, %d)", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(size_t*)(R_ESP+8), *(int*)(R_ESP+12), *(int*)(R_ESP+16), *(int*)(R_ESP+20), *(int*)(R_ESP+24));
|
||||
perr = 1;
|
||||
} else if(strstr(s, "strcasecmp")==s || strstr(s, "__strcasecmp")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", \"%s\")", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(char**)(R_ESP+8));
|
||||
} else if(strstr(s, "gtk_signal_connect_full")) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p, \"%s\", %p, %p, %p, %p, %d, %d)", tid, *(void**)(R_ESP), "gtk_signal_connect_full", *(void**)(R_ESP+4), *(char**)(R_ESP+8), *(void**)(R_ESP+12), *(void**)(R_ESP+16), *(void**)(R_ESP+20), *(void**)(R_ESP+24), *(int32_t*)(R_ESP+28), *(int32_t*)(R_ESP+32));
|
||||
} else if(strstr(s, "strcmp")==s || strstr(s, "__strcmp")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", \"%s\")", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(char**)(R_ESP+8));
|
||||
} else if(strstr(s, "strstr")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%.127s\", \"%.127s\")", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(char**)(R_ESP+8));
|
||||
} else if(strstr(s, "strlen")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p(\"%s\"))", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), ((R_ESP+4))?(*(char**)(R_ESP+4)):"nil");
|
||||
} else if(strstr(s, "vsnprintf")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%08X, %u, %08X...)", tid, *(void**)(R_ESP), s, *(uint32_t*)(R_ESP+4), *(uint32_t*)(R_ESP+8), *(uint32_t*)(R_ESP+12));
|
||||
pu32 = *(uint32_t**)(R_ESP+4);
|
||||
post = 3;
|
||||
} else if(strstr(s, "vsprintf")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%08X, \"%s\"...)", tid, *(void**)(R_ESP), s, *(uint32_t*)(R_ESP+4), *(char**)(R_ESP+8));
|
||||
pu32 = *(uint32_t**)(R_ESP+4);
|
||||
post = 3;
|
||||
} else if(strstr(s, "snprintf")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%08X, %u, %08X...)", tid, *(void**)(R_ESP), s, *(uint32_t*)(R_ESP+4), *(uint32_t*)(R_ESP+8), *(uint32_t*)(R_ESP+12));
|
||||
pu32 = *(uint32_t**)(R_ESP+4);
|
||||
post = 3;
|
||||
} else if(strstr(s, "sprintf")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%08X, %08X...)", tid, *(void**)(R_ESP), s, *(uint32_t*)(R_ESP+4), *(uint32_t*)(R_ESP+8));
|
||||
pu32 = *(uint32_t**)(R_ESP+4);
|
||||
post = 3;
|
||||
} else if(strstr(s, "fprintf")==s) {
|
||||
pu32 = *(uint32_t**)(R_ESP+8);
|
||||
if(((uintptr_t)pu32)<0x5) // probably a __fprint_chk
|
||||
pu32 = *(uint32_t**)(R_ESP+12);
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%08X, \"%s\", ...)", tid, *(void**)(R_ESP), s, *(uint32_t*)(R_ESP+4), pu32?((char*)(pu32)):"nil");
|
||||
} else if(strstr(s, "vfprintf")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%08X, \"%s\", ...)", tid, *(void**)(R_ESP), s, *(uint32_t*)(R_ESP+4), *(char**)(R_ESP+8));
|
||||
} else if(strstr(s, "sscanf")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", \"%s\", ...)", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(char**)(R_ESP+8));
|
||||
} else if(strstr(s, "XCreateWindow")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p, %p, %d, %d, %u, %u, %u, %d, %u, %p, %u, %p)", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(void**)(R_ESP+8), *(int*)(R_ESP+12), *(int*)(R_ESP+16), *(uint32_t*)(R_ESP+20), *(uint32_t*)(R_ESP+24), *(uint32_t*)(R_ESP+28), *(int32_t*)(R_ESP+32), *(uint32_t*)(R_ESP+36), *(void**)(R_ESP+40), *(uint32_t*)(R_ESP+44), *(void**)(R_ESP+48));
|
||||
} else if(strstr(s, "XLoadQueryFont")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p, \"%s\")", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(char**)(R_ESP+8));
|
||||
} else if(strstr(s, "pthread_mutex_lock")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p)", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4));
|
||||
} else if(!strcmp(s, "fmodf")) {
|
||||
post = 4;
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%f, %f)", tid, *(void**)(R_ESP), s, *(float*)(R_ESP+4), *(float*)(R_ESP+8));
|
||||
} else if(!strcmp(s, "fmod")) {
|
||||
post = 4;
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%f, %f)", tid, *(void**)(R_ESP), s, *(double*)(R_ESP+4), *(double*)(R_ESP+12));
|
||||
} else if(strstr(s, "SDL_GetWindowSurface")==s) {
|
||||
post = 5;
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p)", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4));
|
||||
} else if(strstr(s, "udev_monitor_new_from_netlink")==s) {
|
||||
post = 5;
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%p, \"%s\")", tid, *(void**)(R_ESP), s, *(void**)(R_ESP+4), *(char**)(R_ESP+8));
|
||||
} else if(!strcmp(s, "syscall")) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%d, %p, %p, %p...)", tid, *(void**)(R_ESP), s, *(int32_t*)(R_ESP+4), *(void**)(R_ESP+8), *(void**)(R_ESP+12), *(void**)(R_ESP+16));
|
||||
perr = 1;
|
||||
} else {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s (%08X, %08X, %08X...)", tid, *(void**)(R_ESP), s, *(uint32_t*)(R_ESP+4), *(uint32_t*)(R_ESP+8), *(uint32_t*)(R_ESP+12));
|
||||
}
|
||||
printf_log(LOG_NONE, "%s =>", buff);
|
||||
pthread_mutex_unlock(&emu->context->mutex_trace);
|
||||
w(emu, addr); // some function never come back, so unlock the mutex first!
|
||||
pthread_mutex_lock(&emu->context->mutex_trace);
|
||||
if(post)
|
||||
switch(post) {
|
||||
case 1: snprintf(buff2, 63, " [%d sec %d nsec]", pu32?pu32[0]:-1, pu32?pu32[1]:-1);
|
||||
break;
|
||||
case 2: snprintf(buff2, 63, "(%s)", R_EAX?((char*)R_EAX):"nil");
|
||||
break;
|
||||
case 3: snprintf(buff2, 63, "(%s)", pu32?((char*)pu32):"nil");
|
||||
break;
|
||||
#ifdef USE_FLOAT
|
||||
case 4: snprintf(buff2, 63, " (%f)", ST0.f);
|
||||
#else
|
||||
case 4: snprintf(buff2, 63, " (%f)", ST0.d);
|
||||
#endif
|
||||
break;
|
||||
case 5: {
|
||||
uint32_t* p = (uint32_t*)R_EAX;
|
||||
if(p)
|
||||
snprintf(buff2, 63, " size=%dx%d, pitch=%d, pixels=%p", p[2], p[3], p[4], p+5);
|
||||
else
|
||||
snprintf(buff2, 63, "NULL Surface");
|
||||
}
|
||||
break;
|
||||
}
|
||||
if(perr==1 && ((int)R_EAX)<0)
|
||||
snprintf(buff3, 63, " (errno=%d:\"%s\")", errno, strerror(errno));
|
||||
else if(perr==2 && R_EAX==0)
|
||||
snprintf(buff3, 63, " (errno=%d:\"%s\")", errno, strerror(errno));
|
||||
printf_log(LOG_NONE, " return 0x%08X%s%s\n", R_EAX, buff2, buff3);
|
||||
pthread_mutex_unlock(&emu->context->mutex_trace);
|
||||
} else
|
||||
w(emu, addr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
printf_log(LOG_INFO, "Warning, ignoring unsupported Int 3 call\n");
|
||||
//emu->quit = 1;
|
||||
}
|
||||
|
||||
int GetTID()
|
||||
{
|
||||
return syscall(SYS_gettid);
|
||||
}
|
||||
@@ -105,19 +105,7 @@
|
||||
|
||||
/*------------------------- Global Variables ------------------------------*/
|
||||
|
||||
static uint32_t x86emu_parity_tab[8] =
|
||||
{
|
||||
0x96696996,
|
||||
0x69969669,
|
||||
0x69969669,
|
||||
0x96696996,
|
||||
0x69969669,
|
||||
0x96696996,
|
||||
0x96696996,
|
||||
0x69969669,
|
||||
};
|
||||
|
||||
#define PARITY(x) (((x86emu_parity_tab[(x) / 32] >> ((x) % 32)) & 1) == 0)
|
||||
#define PARITY(x) (((emu->x86emu_parity_tab[(x) / 32] >> ((x) % 32)) & 1) == 0)
|
||||
#define XOR2(x) (((x) ^ ((x)>>1)) & 0x1)
|
||||
|
||||
/*----------------------------- Implementation ----------------------------*/
|
||||
@@ -223,8 +211,8 @@ Implements the ADC instruction and side effects.
|
||||
****************************************************************************/
|
||||
uint8_t adc8(x86emu_t *emu, uint8_t d, uint8_t s)
|
||||
{
|
||||
register uint32_t res; /* all operands in native machine order */
|
||||
register uint32_t cc;
|
||||
uint32_t res; /* all operands in native machine order */
|
||||
uint32_t cc;
|
||||
|
||||
CHECK_FLAGS(emu);
|
||||
|
||||
@@ -251,8 +239,8 @@ Implements the ADC instruction and side effects.
|
||||
****************************************************************************/
|
||||
uint16_t adc16(x86emu_t *emu, uint16_t d, uint16_t s)
|
||||
{
|
||||
register uint32_t res; /* all operands in native machine order */
|
||||
register uint32_t cc;
|
||||
uint32_t res; /* all operands in native machine order */
|
||||
uint32_t cc;
|
||||
|
||||
CHECK_FLAGS(emu);
|
||||
|
||||
@@ -279,10 +267,10 @@ Implements the ADC instruction and side effects.
|
||||
****************************************************************************/
|
||||
uint32_t adc32(x86emu_t *emu, uint32_t d, uint32_t s)
|
||||
{
|
||||
register uint32_t lo; /* all operands in native machine order */
|
||||
register uint32_t hi;
|
||||
register uint32_t res;
|
||||
register uint32_t cc;
|
||||
uint32_t lo; /* all operands in native machine order */
|
||||
uint32_t hi;
|
||||
uint32_t res;
|
||||
uint32_t cc;
|
||||
|
||||
CHECK_FLAGS(emu);
|
||||
|
||||
@@ -297,7 +285,7 @@ uint32_t adc32(x86emu_t *emu, uint32_t d, uint32_t s)
|
||||
hi = (lo >> 16) + (d >> 16) + (s >> 16);
|
||||
|
||||
CONDITIONAL_SET_FLAG(hi & 0x10000, F_CF);
|
||||
CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(!res, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
|
||||
|
||||
@@ -314,8 +302,8 @@ Implements the CMP instruction and side effects.
|
||||
****************************************************************************/
|
||||
uint8_t cmp8(x86emu_t *emu, uint8_t d, uint8_t s)
|
||||
{
|
||||
register uint32_t res; /* all operands in native machine order */
|
||||
register uint32_t bc;
|
||||
uint32_t res; /* all operands in native machine order */
|
||||
uint32_t bc;
|
||||
|
||||
RESET_FLAGS(emu);
|
||||
|
||||
@@ -339,8 +327,8 @@ Implements the CMP instruction and side effects.
|
||||
****************************************************************************/
|
||||
uint16_t cmp16(x86emu_t *emu, uint16_t d, uint16_t s)
|
||||
{
|
||||
register uint32_t res; /* all operands in native machine order */
|
||||
register uint32_t bc;
|
||||
uint32_t res; /* all operands in native machine order */
|
||||
uint32_t bc;
|
||||
|
||||
RESET_FLAGS(emu);
|
||||
|
||||
@@ -363,14 +351,14 @@ Implements the CMP instruction and side effects.
|
||||
****************************************************************************/
|
||||
uint32_t cmp32(x86emu_t *emu, uint32_t d, uint32_t s)
|
||||
{
|
||||
register uint32_t res; /* all operands in native machine order */
|
||||
register uint32_t bc;
|
||||
uint32_t res; /* all operands in native machine order */
|
||||
uint32_t bc;
|
||||
|
||||
RESET_FLAGS(emu);
|
||||
|
||||
res = d - s;
|
||||
CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
|
||||
CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(!res, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
|
||||
|
||||
/* calculate the borrow chain. See note at top */
|
||||
@@ -393,10 +381,11 @@ uint8_t daa8(x86emu_t *emu, uint8_t d)
|
||||
res += 6;
|
||||
SET_FLAG(F_AF);
|
||||
}
|
||||
if (res > 0x9F || ACCESS_FLAG(F_CF)) {
|
||||
if (d > 0x99 || ACCESS_FLAG(F_CF)) {
|
||||
res += 0x60;
|
||||
SET_FLAG(F_CF);
|
||||
}
|
||||
} else
|
||||
CLEAR_FLAG(F_CF);
|
||||
CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
|
||||
CONDITIONAL_SET_FLAG((res & 0xFF) == 0, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
|
||||
@@ -409,21 +398,24 @@ Implements the DAS instruction and side effects.
|
||||
****************************************************************************/
|
||||
uint8_t das8(x86emu_t *emu, uint8_t d)
|
||||
{
|
||||
uint32_t res = d;
|
||||
CHECK_FLAGS(emu);
|
||||
uint32_t newcf = 0;
|
||||
if ((d & 0xf) > 9 || ACCESS_FLAG(F_AF)) {
|
||||
d -= 6;
|
||||
res -= 6;
|
||||
newcf = (d < 6);
|
||||
SET_FLAG(F_AF);
|
||||
} else
|
||||
CLEAR_FLAG(F_AF);
|
||||
if (d > 0x9F || ACCESS_FLAG(F_CF)) {
|
||||
d -= 0x60;
|
||||
SET_FLAG(F_CF);
|
||||
} else
|
||||
CLEAR_FLAG(F_CF);
|
||||
CONDITIONAL_SET_FLAG(d & 0x80, F_SF);
|
||||
CONDITIONAL_SET_FLAG(d == 0, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(d & 0xff), F_PF);
|
||||
return d;
|
||||
if (d > 0x99 || ACCESS_FLAG(F_CF)) {
|
||||
res -= 0x60;
|
||||
newcf = 1;
|
||||
}
|
||||
CONDITIONAL_SET_FLAG(newcf, F_CF);
|
||||
CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
|
||||
CONDITIONAL_SET_FLAG((res & 0xFF) == 0, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
|
||||
return res;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@@ -432,7 +424,7 @@ Implements the RCL instruction and side effects.
|
||||
****************************************************************************/
|
||||
uint8_t rcl8(x86emu_t *emu, uint8_t d, uint8_t s)
|
||||
{
|
||||
register unsigned int res, cnt, mask, cf;
|
||||
unsigned int res, cnt, mask, cf;
|
||||
CHECK_FLAGS(emu);
|
||||
s = s&0x1f;
|
||||
|
||||
@@ -507,7 +499,7 @@ Implements the RCL instruction and side effects.
|
||||
****************************************************************************/
|
||||
uint16_t rcl16(x86emu_t *emu, uint16_t d, uint8_t s)
|
||||
{
|
||||
register unsigned int res, cnt, mask, cf;
|
||||
unsigned int res, cnt, mask, cf;
|
||||
CHECK_FLAGS(emu);
|
||||
s = s&0x1f;
|
||||
|
||||
@@ -533,14 +525,14 @@ Implements the RCL instruction and side effects.
|
||||
****************************************************************************/
|
||||
uint32_t rcl32(x86emu_t *emu, uint32_t d, uint8_t s)
|
||||
{
|
||||
register uint32_t res, cnt, mask, cf;
|
||||
uint32_t res, cnt, mask, cf;
|
||||
CHECK_FLAGS(emu);
|
||||
s = s&0x1f;
|
||||
|
||||
res = d;
|
||||
if ((cnt = s % 33) != 0) {
|
||||
cf = (d >> (32 - cnt)) & 0x1;
|
||||
res = (d << cnt) & 0xffffffff;
|
||||
res = (d << cnt);
|
||||
mask = (1 << (cnt - 1)) - 1;
|
||||
res |= (d >> (33 - cnt)) & mask;
|
||||
if (ACCESS_FLAG(F_CF)) { /* carry flag is set */
|
||||
@@ -722,7 +714,7 @@ uint8_t rol8(x86emu_t *emu, uint8_t d, uint8_t s)
|
||||
if((cnt = s % 8) != 0) {
|
||||
d = (d << cnt) + ((d >> (8 - cnt)) & ((1 << cnt) - 1));
|
||||
}
|
||||
CHECK_FLAGS(emu);
|
||||
RESET_FLAGS(emu);
|
||||
|
||||
/* OF flag is set if s == 1; OF = CF _XOR_ MSB of result */
|
||||
if(s == 1) {
|
||||
@@ -749,7 +741,7 @@ uint16_t rol16(x86emu_t *emu, uint16_t d, uint8_t s)
|
||||
if((cnt = s % 16) != 0) {
|
||||
d = (d << cnt) + ((d >> (16 - cnt)) & ((1 << cnt) - 1));
|
||||
}
|
||||
CHECK_FLAGS(emu);
|
||||
RESET_FLAGS(emu);
|
||||
|
||||
/* OF flag is set if s == 1; OF = CF _XOR_ MSB of result */
|
||||
if(s == 1) {
|
||||
@@ -776,7 +768,7 @@ uint32_t rol32(x86emu_t *emu, uint32_t d, uint8_t s)
|
||||
if((cnt = s % 32) != 0) {
|
||||
d = (d << cnt) + ((d >> (32 - cnt)) & ((1 << cnt) - 1));
|
||||
}
|
||||
CHECK_FLAGS(emu);
|
||||
RESET_FLAGS(emu);
|
||||
|
||||
/* OF flag is set if s == 1; OF = CF _XOR_ MSB of result */
|
||||
if(s == 1) {
|
||||
@@ -803,7 +795,7 @@ uint8_t ror8(x86emu_t *emu, uint8_t d, uint8_t s)
|
||||
if((cnt = s % 8) != 0) {
|
||||
d = (d << (8 - cnt)) + ((d >> (cnt)) & ((1 << (8 - cnt)) - 1));
|
||||
}
|
||||
CHECK_FLAGS(emu);
|
||||
RESET_FLAGS(emu);
|
||||
|
||||
/* OF flag is set if s == 1; OF = MSB _XOR_ (M-1)SB of result */
|
||||
if(s == 1) {
|
||||
@@ -830,7 +822,7 @@ uint16_t ror16(x86emu_t *emu, uint16_t d, uint8_t s)
|
||||
if((cnt = s % 16) != 0) {
|
||||
d = (d << (16 - cnt)) + ((d >> (cnt)) & ((1 << (16 - cnt)) - 1));
|
||||
}
|
||||
CHECK_FLAGS(emu);
|
||||
RESET_FLAGS(emu);
|
||||
|
||||
/* OF flag is set if s == 1; OF = MSB _XOR_ (M-1)SB of result */
|
||||
if(s == 1) {
|
||||
@@ -857,7 +849,7 @@ uint32_t ror32(x86emu_t *emu, uint32_t d, uint8_t s)
|
||||
if((cnt = s % 32) != 0) {
|
||||
d = (d << (32 - cnt)) + ((d >> (cnt)) & ((1 << (32 - cnt)) - 1));
|
||||
}
|
||||
CHECK_FLAGS(emu);
|
||||
RESET_FLAGS(emu);
|
||||
|
||||
/* OF flag is set if s == 1; OF = MSB _XOR_ (M-1)SB of result */
|
||||
if(s == 1) {
|
||||
@@ -899,7 +891,7 @@ uint16_t shld16 (x86emu_t *emu, uint16_t d, uint16_t fill, uint8_t s)
|
||||
CLEAR_FLAG(F_OF);
|
||||
}
|
||||
} else {
|
||||
res = (fill << (cnt)) | (d >> (16 - cnt));
|
||||
res = (fill << (cnt)) | (fill >> (16 - cnt));
|
||||
if(s==16)
|
||||
cf = d & 1;
|
||||
else
|
||||
@@ -928,7 +920,7 @@ uint32_t shld32 (x86emu_t *emu, uint32_t d, uint32_t fill, uint8_t s)
|
||||
res = (d << cnt) | (fill >> (32-cnt));
|
||||
cf = d & (1 << (32 - cnt));
|
||||
CONDITIONAL_SET_FLAG(cf, F_CF);
|
||||
CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(!res, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
|
||||
} else {
|
||||
@@ -973,7 +965,7 @@ uint16_t shrd16 (x86emu_t *emu, uint16_t d, uint16_t fill, uint8_t s)
|
||||
}
|
||||
} else {
|
||||
cf = fill & (1 << (cnt - 1));
|
||||
res = (fill >> cnt) | (d << (16 - cnt));
|
||||
res = (fill >> cnt) | (fill << (16 - cnt));
|
||||
CONDITIONAL_SET_FLAG(cf, F_CF);
|
||||
CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
|
||||
@@ -1006,7 +998,7 @@ uint32_t shrd32 (x86emu_t *emu, uint32_t d, uint32_t fill, uint8_t s)
|
||||
cf = d & (1 << (cnt - 1));
|
||||
res = (d >> cnt) | (fill << (32 - cnt));
|
||||
CONDITIONAL_SET_FLAG(cf, F_CF);
|
||||
CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(!res, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
|
||||
} else {
|
||||
@@ -1026,8 +1018,8 @@ Implements the SBB instruction and side effects.
|
||||
****************************************************************************/
|
||||
uint8_t sbb8(x86emu_t *emu, uint8_t d, uint8_t s)
|
||||
{
|
||||
register uint32_t res; /* all operands in native machine order */
|
||||
register uint32_t bc;
|
||||
uint32_t res; /* all operands in native machine order */
|
||||
uint32_t bc;
|
||||
CHECK_FLAGS(emu);
|
||||
|
||||
if (ACCESS_FLAG(F_CF))
|
||||
@@ -1052,8 +1044,8 @@ Implements the SBB instruction and side effects.
|
||||
****************************************************************************/
|
||||
uint16_t sbb16(x86emu_t *emu, uint16_t d, uint16_t s)
|
||||
{
|
||||
register uint32_t res; /* all operands in native machine order */
|
||||
register uint32_t bc;
|
||||
uint32_t res; /* all operands in native machine order */
|
||||
uint32_t bc;
|
||||
CHECK_FLAGS(emu);
|
||||
|
||||
if (ACCESS_FLAG(F_CF))
|
||||
@@ -1078,8 +1070,8 @@ Implements the SBB instruction and side effects.
|
||||
****************************************************************************/
|
||||
uint32_t sbb32(x86emu_t *emu, uint32_t d, uint32_t s)
|
||||
{
|
||||
register uint32_t res; /* all operands in native machine order */
|
||||
register uint32_t bc;
|
||||
uint32_t res; /* all operands in native machine order */
|
||||
uint32_t bc;
|
||||
CHECK_FLAGS(emu);
|
||||
|
||||
if (ACCESS_FLAG(F_CF))
|
||||
@@ -1087,7 +1079,7 @@ uint32_t sbb32(x86emu_t *emu, uint32_t d, uint32_t s)
|
||||
else
|
||||
res = d - s;
|
||||
CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
|
||||
CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(!res, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
|
||||
|
||||
/* calculate the borrow chain. See note at top */
|
||||
@@ -1104,7 +1096,7 @@ Implements the TEST instruction and side effects.
|
||||
****************************************************************************/
|
||||
void test8(x86emu_t *emu, uint8_t d, uint8_t s)
|
||||
{
|
||||
register uint32_t res; /* all operands in native machine order */
|
||||
uint32_t res; /* all operands in native machine order */
|
||||
RESET_FLAGS(emu);
|
||||
|
||||
res = d & s;
|
||||
@@ -1123,7 +1115,7 @@ Implements the TEST instruction and side effects.
|
||||
****************************************************************************/
|
||||
void test16(x86emu_t *emu, uint16_t d, uint16_t s)
|
||||
{
|
||||
register uint32_t res; /* all operands in native machine order */
|
||||
uint32_t res; /* all operands in native machine order */
|
||||
RESET_FLAGS(emu);
|
||||
|
||||
res = d & s;
|
||||
@@ -1142,7 +1134,7 @@ Implements the TEST instruction and side effects.
|
||||
****************************************************************************/
|
||||
void test32(x86emu_t *emu, uint32_t d, uint32_t s)
|
||||
{
|
||||
register uint32_t res; /* all operands in native machine order */
|
||||
uint32_t res; /* all operands in native machine order */
|
||||
RESET_FLAGS(emu);
|
||||
|
||||
res = d & s;
|
||||
@@ -1155,196 +1147,13 @@ void test32(x86emu_t *emu, uint32_t d, uint32_t s)
|
||||
CLEAR_FLAG(F_CF);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
REMARKS:
|
||||
Implements the IMUL instruction and side effects.
|
||||
****************************************************************************/
|
||||
void imul8(x86emu_t *emu, uint8_t s)
|
||||
{
|
||||
int16_t res = (int16_t)(int8_t)R_AL * (int8_t)s;
|
||||
RESET_FLAGS(emu);
|
||||
|
||||
R_AX = res;
|
||||
if (((R_AL & 0x80) == 0 && R_AH == 0x00) ||
|
||||
((R_AL & 0x80) != 0 && R_AH == 0xFF)) {
|
||||
CLEAR_FLAG(F_CF);
|
||||
CLEAR_FLAG(F_OF);
|
||||
} else {
|
||||
SET_FLAG(F_CF);
|
||||
SET_FLAG(F_OF);
|
||||
}
|
||||
CONDITIONAL_SET_FLAG(PARITY(R_AL & 0xff), F_PF);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
REMARKS:
|
||||
Implements the IMUL instruction and side effects.
|
||||
****************************************************************************/
|
||||
void imul16_eax(x86emu_t *emu, uint16_t s)
|
||||
{
|
||||
int32_t res = (int32_t)(int16_t)R_AX * (int16_t)s;
|
||||
RESET_FLAGS(emu);
|
||||
|
||||
R_AX = (uint16_t)res;
|
||||
R_DX = (uint16_t)(res >> 16);
|
||||
if (((R_AX & 0x8000) == 0 && R_DX == 0x00) ||
|
||||
((R_AX & 0x8000) != 0 && R_DX == 0xFFFF)) {
|
||||
CLEAR_FLAG(F_CF);
|
||||
CLEAR_FLAG(F_OF);
|
||||
} else {
|
||||
SET_FLAG(F_CF);
|
||||
SET_FLAG(F_OF);
|
||||
}
|
||||
CONDITIONAL_SET_FLAG(PARITY(R_AL & 0xff), F_PF);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
REMARKS:
|
||||
Implements the IMUL instruction and side effects.
|
||||
****************************************************************************/
|
||||
uint16_t imul16(x86emu_t *emu, uint16_t op1, uint16_t op2)
|
||||
{
|
||||
int32_t res = (int32_t)(int16_t)op1 * (int16_t)op2;
|
||||
RESET_FLAGS(emu);
|
||||
|
||||
op1 = (uint16_t)res;
|
||||
uint16_t tmp = (uint16_t)(res >> 16);
|
||||
if (((op1 & 0x8000) == 0 && tmp == 0x00) ||
|
||||
((op1 & 0x8000) != 0 && tmp == 0xFFFF)) {
|
||||
CLEAR_FLAG(F_CF);
|
||||
CLEAR_FLAG(F_OF);
|
||||
} else {
|
||||
SET_FLAG(F_CF);
|
||||
SET_FLAG(F_OF);
|
||||
}
|
||||
CONDITIONAL_SET_FLAG(PARITY(R_AL & 0xff), F_PF);
|
||||
|
||||
return op1;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
REMARKS:
|
||||
Implements the IMUL instruction and side effects.
|
||||
****************************************************************************/
|
||||
void imul32_direct(uint32_t *res_lo, uint32_t* res_hi,uint32_t d, uint32_t s)
|
||||
{
|
||||
int64_t res = (int64_t)(int32_t)d * (int32_t)s;
|
||||
|
||||
*res_lo = (uint32_t)res;
|
||||
*res_hi = (uint32_t)(res >> 32);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
REMARKS:
|
||||
Implements the IMUL instruction and side effects.
|
||||
****************************************************************************/
|
||||
uint32_t imul32(x86emu_t *emu, uint32_t op1, uint32_t op2)
|
||||
{
|
||||
uint32_t s;
|
||||
uint32_t r;
|
||||
RESET_FLAGS(emu);
|
||||
imul32_direct(&r,&s,op1,op2);
|
||||
if (((r & 0x80000000) == 0 && s == 0x00) ||
|
||||
((r & 0x80000000) != 0 && s == 0xFFFFFFFF)) {
|
||||
CLEAR_FLAG(F_CF);
|
||||
CLEAR_FLAG(F_OF);
|
||||
} else {
|
||||
SET_FLAG(F_CF);
|
||||
SET_FLAG(F_OF);
|
||||
}
|
||||
CONDITIONAL_SET_FLAG(PARITY(r & 0xff), F_PF);
|
||||
return r;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
REMARKS:
|
||||
Implements the IMUL instruction and side effects.
|
||||
****************************************************************************/
|
||||
void imul32_eax(x86emu_t *emu, uint32_t s)
|
||||
{
|
||||
RESET_FLAGS(emu);
|
||||
imul32_direct(&R_EAX,&R_EDX,R_EAX,s);
|
||||
if (((R_EAX & 0x80000000) == 0 && R_EDX == 0x00) ||
|
||||
((R_EAX & 0x80000000) != 0 && R_EDX == 0xFFFFFFFF)) {
|
||||
CLEAR_FLAG(F_CF);
|
||||
CLEAR_FLAG(F_OF);
|
||||
} else {
|
||||
SET_FLAG(F_CF);
|
||||
SET_FLAG(F_OF);
|
||||
}
|
||||
CONDITIONAL_SET_FLAG(PARITY(R_AL & 0xff), F_PF);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
REMARKS:
|
||||
Implements the MUL instruction and side effects.
|
||||
****************************************************************************/
|
||||
void mul8(x86emu_t *emu, uint8_t s)
|
||||
{
|
||||
uint16_t res = (uint16_t)(R_AL) * s;
|
||||
RESET_FLAGS(emu);
|
||||
|
||||
R_AX = res;
|
||||
if (R_AH == 0) {
|
||||
CLEAR_FLAG(F_CF);
|
||||
CLEAR_FLAG(F_OF);
|
||||
} else {
|
||||
SET_FLAG(F_CF);
|
||||
SET_FLAG(F_OF);
|
||||
}
|
||||
CONDITIONAL_SET_FLAG(PARITY(R_AL & 0xff), F_PF);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
REMARKS:
|
||||
Implements the MUL instruction and side effects.
|
||||
****************************************************************************/
|
||||
void mul16(x86emu_t *emu, uint16_t s)
|
||||
{
|
||||
uint32_t res = (uint32_t)R_AX * s;
|
||||
RESET_FLAGS(emu);
|
||||
|
||||
R_AX = (uint16_t)res;
|
||||
R_DX = (uint16_t)(res >> 16);
|
||||
if (R_DX == 0) {
|
||||
CLEAR_FLAG(F_CF);
|
||||
CLEAR_FLAG(F_OF);
|
||||
} else {
|
||||
SET_FLAG(F_CF);
|
||||
SET_FLAG(F_OF);
|
||||
}
|
||||
CONDITIONAL_SET_FLAG(PARITY(R_AL & 0xff), F_PF);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
REMARKS:
|
||||
Implements the MUL instruction and side effects.
|
||||
****************************************************************************/
|
||||
void mul32_eax(x86emu_t *emu, uint32_t s)
|
||||
{
|
||||
uint64_t res = (uint64_t)R_EAX * s;
|
||||
RESET_FLAGS(emu);
|
||||
|
||||
R_EAX = (uint32_t)res;
|
||||
R_EDX = (uint32_t)(res >> 32);
|
||||
|
||||
if (R_EDX == 0) {
|
||||
CLEAR_FLAG(F_CF);
|
||||
CLEAR_FLAG(F_OF);
|
||||
} else {
|
||||
SET_FLAG(F_CF);
|
||||
SET_FLAG(F_OF);
|
||||
}
|
||||
CONDITIONAL_SET_FLAG(PARITY(R_AL & 0xff), F_PF);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
REMARKS:
|
||||
Implements the IDIV instruction and side effects.
|
||||
****************************************************************************/
|
||||
void idiv8(x86emu_t *emu, uint8_t s)
|
||||
{
|
||||
int32_t dvd, div, mod;
|
||||
int32_t dvd, quot, mod;
|
||||
RESET_FLAGS(emu);
|
||||
|
||||
dvd = (int16_t)R_AX;
|
||||
@@ -1352,13 +1161,14 @@ void idiv8(x86emu_t *emu, uint8_t s)
|
||||
INTR_RAISE_DIV0(emu);
|
||||
return;
|
||||
}
|
||||
div = dvd / (int8_t)s;
|
||||
mod = dvd % (int8_t)s;
|
||||
if (abs(div) > 0x7f) {
|
||||
div_t p = div(dvd, (int8_t)s);
|
||||
quot = p.quot;
|
||||
mod = p.rem;
|
||||
if (abs(quot) > 0x7f) {
|
||||
INTR_RAISE_DIV0(emu);
|
||||
return;
|
||||
}
|
||||
R_AL = (int8_t) div;
|
||||
R_AL = (int8_t) quot;
|
||||
R_AH = (int8_t) mod;
|
||||
}
|
||||
|
||||
@@ -1368,25 +1178,26 @@ Implements the IDIV instruction and side effects.
|
||||
****************************************************************************/
|
||||
void idiv16(x86emu_t *emu, uint16_t s)
|
||||
{
|
||||
int32_t dvd, div, mod;
|
||||
int32_t dvd, quot, mod;
|
||||
|
||||
dvd = (((int32_t)R_DX) << 16) | R_AX;
|
||||
if (s == 0) {
|
||||
INTR_RAISE_DIV0(emu);
|
||||
return;
|
||||
}
|
||||
div = dvd / (int16_t)s;
|
||||
mod = dvd % (int16_t)s;
|
||||
if (abs(div) > 0x7fff) {
|
||||
div_t p = div(dvd, (int16_t)s);
|
||||
quot = p.quot;
|
||||
mod = p.rem;
|
||||
if (abs(quot) > 0x7fff) {
|
||||
INTR_RAISE_DIV0(emu);
|
||||
return;
|
||||
}
|
||||
CLEAR_FLAG(F_CF);
|
||||
CLEAR_FLAG(F_SF);
|
||||
CONDITIONAL_SET_FLAG(div == 0, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(quot == 0, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF);
|
||||
|
||||
R_AX = (uint16_t)div;
|
||||
R_AX = (uint16_t)quot;
|
||||
R_DX = (uint16_t)mod;
|
||||
}
|
||||
|
||||
@@ -1396,7 +1207,7 @@ Implements the IDIV instruction and side effects.
|
||||
****************************************************************************/
|
||||
void idiv32(x86emu_t *emu, uint32_t s)
|
||||
{
|
||||
int64_t dvd, div, mod;
|
||||
int64_t dvd, quot, mod;
|
||||
RESET_FLAGS(emu);
|
||||
|
||||
dvd = (((int64_t)R_EDX) << 32) | R_EAX;
|
||||
@@ -1404,9 +1215,10 @@ void idiv32(x86emu_t *emu, uint32_t s)
|
||||
INTR_RAISE_DIV0(emu);
|
||||
return;
|
||||
}
|
||||
div = dvd / (int32_t)s;
|
||||
mod = dvd % (int32_t)s;
|
||||
if (llabs(div) > 0x7fffffff) {
|
||||
lldiv_t p = lldiv(dvd, (int32_t)s);
|
||||
quot = p.quot;
|
||||
mod = p.rem;
|
||||
if (llabs(quot) > 0x7fffffff) {
|
||||
INTR_RAISE_DIV0(emu);
|
||||
return;
|
||||
}
|
||||
@@ -1416,7 +1228,7 @@ void idiv32(x86emu_t *emu, uint32_t s)
|
||||
SET_FLAG(F_ZF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF);
|
||||
|
||||
R_EAX = (uint32_t)div;
|
||||
R_EAX = (uint32_t)quot;
|
||||
R_EDX = (uint32_t)mod;
|
||||
}
|
||||
|
||||
@@ -81,8 +81,6 @@ Implements the AND instruction and side effects.
|
||||
****************************************************************************/
|
||||
static inline uint32_t and32(x86emu_t *emu, uint32_t d, uint32_t s)
|
||||
{
|
||||
register uint32_t res; /* all operands in native machine order */
|
||||
|
||||
emu->res = d & s;
|
||||
emu->df = d_and32;
|
||||
|
||||
@@ -161,6 +159,14 @@ Implements the INC instruction and side effects.
|
||||
****************************************************************************/
|
||||
static inline uint32_t inc32(x86emu_t *emu, uint32_t d)
|
||||
{
|
||||
if(emu->df == d_shr32) {
|
||||
// workaround for some wine trickery
|
||||
uint32_t cnt = emu->op2;
|
||||
if (cnt > 0) {
|
||||
uint32_t cc = emu->op1 & (1 << (cnt - 1));
|
||||
CONDITIONAL_SET_FLAG(cc, F_CF);
|
||||
}
|
||||
}
|
||||
emu->res = d + 1;
|
||||
emu->op1 = d;
|
||||
emu->df = d_inc32;
|
||||
@@ -239,7 +245,7 @@ static inline uint32_t neg32(x86emu_t *emu, uint32_t s)
|
||||
|
||||
/****************************************************************************
|
||||
REMARKS:
|
||||
Implements the NOT instruction and side effects.
|
||||
Implements the NOT instruction
|
||||
****************************************************************************/
|
||||
static inline uint8_t not8(x86emu_t *emu, uint8_t s)
|
||||
{
|
||||
@@ -248,7 +254,7 @@ static inline uint8_t not8(x86emu_t *emu, uint8_t s)
|
||||
|
||||
/****************************************************************************
|
||||
REMARKS:
|
||||
Implements the NOT instruction and side effects.
|
||||
Implements the NOT instruction
|
||||
****************************************************************************/
|
||||
static inline uint16_t not16(x86emu_t *emu, uint16_t s)
|
||||
{
|
||||
@@ -257,7 +263,7 @@ static inline uint16_t not16(x86emu_t *emu, uint16_t s)
|
||||
|
||||
/****************************************************************************
|
||||
REMARKS:
|
||||
Implements the NOT instruction and side effects.
|
||||
Implements the NOT instruction
|
||||
****************************************************************************/
|
||||
static inline uint32_t not32(x86emu_t *emu, uint32_t s)
|
||||
{
|
||||
@@ -503,15 +509,100 @@ static inline uint32_t xor32(x86emu_t *emu, uint32_t d, uint32_t s)
|
||||
return emu->res;
|
||||
}
|
||||
|
||||
void imul8 (x86emu_t *emu, uint8_t s);
|
||||
void imul16_eax (x86emu_t *emu, uint16_t s);
|
||||
uint16_t imul16 (x86emu_t *emu, uint16_t op1, uint16_t op2);
|
||||
void imul32_eax (x86emu_t *emu, uint32_t s);
|
||||
uint32_t imul32(x86emu_t *emu, uint32_t op1, uint32_t op2);
|
||||
void imul32_direct(uint32_t *res_lo, uint32_t* res_hi, uint32_t d, uint32_t s);
|
||||
void mul8 (x86emu_t *emu, uint8_t s);
|
||||
void mul16 (x86emu_t *emu, uint16_t s);
|
||||
void mul32_eax (x86emu_t *emu, uint32_t s);
|
||||
/****************************************************************************
|
||||
REMARKS:
|
||||
Implements the IMUL instruction and side effects.
|
||||
****************************************************************************/
|
||||
static inline void imul8(x86emu_t *emu, uint8_t s)
|
||||
{
|
||||
emu->df = d_imul8;
|
||||
R_AX = emu->res = (int16_t)(int8_t)R_AL * (int8_t)s;
|
||||
}
|
||||
/****************************************************************************
|
||||
REMARKS:
|
||||
Implements the IMUL instruction and side effects.
|
||||
****************************************************************************/
|
||||
static inline void imul16_eax(x86emu_t *emu, uint16_t s)
|
||||
{
|
||||
emu->df = d_imul16;
|
||||
emu->res = (int32_t)(int16_t)R_AX * (int16_t)s;
|
||||
R_AX = (uint16_t)emu->res;
|
||||
R_DX = (uint16_t)(emu->res >> 16);
|
||||
}
|
||||
/****************************************************************************
|
||||
REMARKS:
|
||||
Implements the IMUL instruction and side effects.
|
||||
****************************************************************************/
|
||||
static inline uint16_t imul16(x86emu_t *emu, uint16_t op1, uint16_t op2)
|
||||
{
|
||||
emu->df = d_imul16;
|
||||
emu->res = (int32_t)(int16_t)op1 * (int16_t)op2;
|
||||
return (uint16_t)emu->res;
|
||||
}
|
||||
/****************************************************************************
|
||||
REMARKS:
|
||||
Implements the IMUL instruction and side effects.
|
||||
****************************************************************************/
|
||||
static inline void imul32_direct(uint32_t *res_lo, uint32_t* res_hi,uint32_t d, uint32_t s)
|
||||
{
|
||||
int64_t res = (int64_t)(int32_t)d * (int32_t)s;
|
||||
|
||||
*res_lo = (uint32_t)res;
|
||||
*res_hi = (uint32_t)(res >> 32);
|
||||
}
|
||||
/****************************************************************************
|
||||
REMARKS:
|
||||
Implements the IMUL instruction and side effects.
|
||||
****************************************************************************/
|
||||
static inline uint32_t imul32(x86emu_t *emu, uint32_t op1, uint32_t op2)
|
||||
{
|
||||
emu->df = d_imul32;
|
||||
imul32_direct(&emu->res,&emu->op1,op1,op2);
|
||||
return emu->res;
|
||||
}
|
||||
/****************************************************************************
|
||||
REMARKS:
|
||||
Implements the IMUL instruction and side effects.
|
||||
****************************************************************************/
|
||||
static inline void imul32_eax(x86emu_t *emu, uint32_t s)
|
||||
{
|
||||
emu->df = d_imul32;
|
||||
imul32_direct(&R_EAX,&R_EDX,R_EAX,s);
|
||||
emu->res = R_EAX;
|
||||
emu->op1 = R_EDX;
|
||||
}
|
||||
/****************************************************************************
|
||||
REMARKS:
|
||||
Implements the MUL instruction and side effects.
|
||||
****************************************************************************/
|
||||
static inline void mul8(x86emu_t *emu, uint8_t s)
|
||||
{
|
||||
emu->df = d_mul8;
|
||||
R_AX = emu->res = (uint16_t)(R_AL) * s;
|
||||
}
|
||||
/****************************************************************************
|
||||
REMARKS:
|
||||
Implements the MUL instruction and side effects.
|
||||
****************************************************************************/
|
||||
static inline void mul16(x86emu_t *emu, uint16_t s)
|
||||
{
|
||||
emu->df = d_mul16;
|
||||
emu->res = (uint32_t)R_AX * s;
|
||||
R_AX = (uint16_t)emu->res;
|
||||
R_DX = (uint16_t)(emu->res >> 16);
|
||||
}
|
||||
/****************************************************************************
|
||||
REMARKS:
|
||||
Implements the MUL instruction and side effects.
|
||||
****************************************************************************/
|
||||
static inline void mul32_eax(x86emu_t *emu, uint32_t s)
|
||||
{
|
||||
emu->df = d_mul32;
|
||||
uint64_t res = (uint64_t)R_EAX * s;
|
||||
emu->res = R_EAX = (uint32_t)res;
|
||||
emu->op1 = R_EDX = (uint32_t)(res >> 32);
|
||||
}
|
||||
|
||||
void idiv8 (x86emu_t *emu, uint8_t s);
|
||||
void idiv16 (x86emu_t *emu, uint16_t s);
|
||||
void idiv32 (x86emu_t *emu, uint32_t s);
|
||||
@@ -519,4 +610,4 @@ void div8 (x86emu_t *emu, uint8_t s);
|
||||
void div16 (x86emu_t *emu, uint16_t s);
|
||||
void div32 (x86emu_t *emu, uint32_t s);
|
||||
|
||||
#endif //__X86PRIMOP_H_
|
||||
#endif //__X86PRIMOP_H_
|
||||
Executable
+1573
File diff suppressed because it is too large.
Load diff
Executable
+805
@@ -0,0 +1,805 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86stack.h"
|
||||
#include "x86emu.h"
|
||||
#include "x86run.h"
|
||||
#include "x86emu_private.h"
|
||||
#include "x86run_private.h"
|
||||
#include "x86primop.h"
|
||||
#include "x86trace.h"
|
||||
#include "box86context.h"
|
||||
|
||||
|
||||
#define F8 *(uint8_t*)(ip++)
|
||||
#define F8S *(int8_t*)(ip++)
|
||||
#define F16 *(uint16_t*)(ip+=2, ip-2)
|
||||
#define F16S *(int16_t*)(ip+=2, ip-2)
|
||||
#define F32 *(uint32_t*)(ip+=4, ip-4)
|
||||
#define F32S *(int32_t*)(ip+=4, ip-4)
|
||||
#define PK(a) *(uint8_t*)(ip+a)
|
||||
|
||||
#include "modrm.h"
|
||||
|
||||
void Run6766(x86emu_t *emu)
|
||||
{
|
||||
uintptr_t ip = R_EIP+2; //skip 67 66
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop;
|
||||
reg32_t *op1, *op2;
|
||||
switch(opcode) {
|
||||
|
||||
case 0x8D: /* LEA Gw,Ew */
|
||||
nextop = F8;
|
||||
op1=GetEw16(emu, nextop);
|
||||
op2=GetG(emu, nextop);
|
||||
op2->word[0] = (uint16_t)(uintptr_t)op1;
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
ip-=2; //unfetch
|
||||
UnimpOpcode(emu);
|
||||
}
|
||||
R_EIP = ip;
|
||||
}
|
||||
|
||||
void Run67(x86emu_t *emu)
|
||||
{
|
||||
uintptr_t ip = R_EIP+1; //skip 67
|
||||
uint8_t opcode = F8;
|
||||
int8_t tmp8s;
|
||||
int32_t tmp32s;
|
||||
switch(opcode) {
|
||||
|
||||
case 0x66: /* MoooRE opcodes */
|
||||
Run6766(emu);
|
||||
break;
|
||||
|
||||
case 0x6C: /* INSB */
|
||||
*(int8_t*)(R_DI+GetESBaseEmu(emu)) = 0; // faking port read, using actual segment ES, just in case
|
||||
if(ACCESS_FLAG(F_DF))
|
||||
R_DI-=1;
|
||||
else
|
||||
R_DI+=1;
|
||||
break;
|
||||
|
||||
case 0xE0: /* LOOPNZ */
|
||||
CHECK_FLAGS(emu);
|
||||
tmp8s = F8S;
|
||||
--R_CX; // don't update flags
|
||||
if(R_CX && !ACCESS_FLAG(F_ZF))
|
||||
R_EIP += tmp8s;
|
||||
break;
|
||||
case 0xE1: /* LOOPZ */
|
||||
CHECK_FLAGS(emu);
|
||||
tmp8s = F8S;
|
||||
--R_CX; // don't update flags
|
||||
if(R_CX && ACCESS_FLAG(F_ZF))
|
||||
R_EIP += tmp8s;
|
||||
break;
|
||||
case 0xE2: /* LOOP */
|
||||
tmp8s = F8S;
|
||||
--R_CX; // don't update flags
|
||||
if(R_CX)
|
||||
R_EIP += tmp8s;
|
||||
break;
|
||||
case 0xE3: /* JCXZ */
|
||||
tmp8s = F8S;
|
||||
if(!R_CX)
|
||||
R_EIP += tmp8s;
|
||||
break;
|
||||
|
||||
case 0xE8: /* CALL Id */
|
||||
tmp32s = F32S; // call is relative
|
||||
Push(emu, R_EIP);
|
||||
R_EIP += tmp32s;
|
||||
break;
|
||||
|
||||
default:
|
||||
UnimpOpcode(emu);
|
||||
}
|
||||
R_EIP = ip;
|
||||
}
|
||||
|
||||
void RunLock(x86emu_t *emu)
|
||||
{
|
||||
uintptr_t ip = R_EIP+1;
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop;
|
||||
reg32_t *oped;
|
||||
uint8_t tmp8u;
|
||||
uint32_t tmp32u, tmp32u2;
|
||||
int32_t tmp32s;
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
switch(opcode) {
|
||||
#define GO(B, OP) \
|
||||
case B+0: \
|
||||
nextop = F8; \
|
||||
GET_EB; \
|
||||
EB->byte[0] = OP##8(emu, EB->byte[0], GB); \
|
||||
break; \
|
||||
case B+1: \
|
||||
nextop = F8; \
|
||||
GET_ED; \
|
||||
ED->dword[0] = OP##32(emu, ED->dword[0], GD.dword[0]); \
|
||||
break; \
|
||||
case B+2: \
|
||||
nextop = F8; \
|
||||
GET_EB; \
|
||||
GB = OP##8(emu, GB, EB->byte[0]); \
|
||||
break; \
|
||||
case B+3: \
|
||||
nextop = F8; \
|
||||
GET_ED; \
|
||||
GD.dword[0] = OP##32(emu, GD.dword[0], ED->dword[0]); \
|
||||
break; \
|
||||
case B+4: \
|
||||
R_AL = OP##8(emu, R_AL, F8); \
|
||||
break; \
|
||||
case B+5: \
|
||||
R_EAX = OP##32(emu, R_EAX, F32); \
|
||||
break;
|
||||
|
||||
GO(0x00, add) /* ADD 0x00 -> 0x05 */
|
||||
GO(0x08, or) /* OR 0x08 -> 0x0D */
|
||||
GO(0x10, adc) /* ADC 0x10 -> 0x15 */
|
||||
GO(0x18, sbb) /* SBB 0x18 -> 0x1D */
|
||||
GO(0x20, and) /* AND 0x20 -> 0x25 */
|
||||
GO(0x28, sub) /* SUB 0x28 -> 0x2D */
|
||||
GO(0x30, xor) /* XOR 0x30 -> 0x35 */
|
||||
#undef GO
|
||||
|
||||
case 0x0f:
|
||||
opcode = F8;
|
||||
switch (opcode) {
|
||||
case 0xB0: /* CMPXCHG Eb,Gb */
|
||||
CHECK_FLAGS(emu);
|
||||
nextop = F8;
|
||||
GET_EB;
|
||||
cmp8(emu, R_AL, EB->byte[0]);
|
||||
if(ACCESS_FLAG(F_ZF)) {
|
||||
EB->byte[0] = GB;
|
||||
} else {
|
||||
R_AL = EB->byte[0];
|
||||
}
|
||||
break;
|
||||
case 0xB1: /* CMPXCHG Ed,Gd */
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
cmp32(emu, R_EAX, ED->dword[0]);
|
||||
if(ACCESS_FLAG(F_ZF)) {
|
||||
ED->dword[0] = GD.dword[0];
|
||||
} else {
|
||||
R_EAX = ED->dword[0];
|
||||
}
|
||||
break;
|
||||
case 0xB3: /* BTR Ed,Gd */
|
||||
CHECK_FLAGS(emu);
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
tmp8u = GD.byte[0];
|
||||
if((nextop&0xC0)!=0xC0)
|
||||
{
|
||||
ED=(reg32_t*)(((uint32_t*)(ED))+(tmp8u>>5));
|
||||
}
|
||||
tmp8u&=31;
|
||||
if(ED->dword[0] & (1<<tmp8u)) {
|
||||
SET_FLAG(F_CF);
|
||||
ED->dword[0] ^= (1<<tmp8u);
|
||||
} else
|
||||
CLEAR_FLAG(F_CF);
|
||||
break;
|
||||
case 0xBA:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 4: /* BT Ed,Ib */
|
||||
CHECK_FLAGS(emu);
|
||||
GET_ED;
|
||||
tmp8u = F8;
|
||||
if((nextop&0xC0)!=0xC0)
|
||||
{
|
||||
ED=(reg32_t*)(((uint32_t*)(ED))+(tmp8u>>5));
|
||||
}
|
||||
tmp8u&=31;
|
||||
if(ED->dword[0] & (1<<tmp8u))
|
||||
SET_FLAG(F_CF);
|
||||
else
|
||||
CLEAR_FLAG(F_CF);
|
||||
break;
|
||||
case 6: /* BTR Ed, Ib */
|
||||
CHECK_FLAGS(emu);
|
||||
GET_ED;
|
||||
tmp8u = F8;
|
||||
if((nextop&0xC0)!=0xC0)
|
||||
{
|
||||
ED=(reg32_t*)(((uint32_t*)(ED))+(tmp8u>>5));
|
||||
}
|
||||
tmp8u&=31;
|
||||
if(ED->dword[0] & (1<<tmp8u)) {
|
||||
SET_FLAG(F_CF);
|
||||
ED->dword[0] ^= (1<<tmp8u);
|
||||
} else
|
||||
CLEAR_FLAG(F_CF);
|
||||
break;
|
||||
|
||||
default:
|
||||
ip -= 3; //unfetch
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0xBB: /* BTC Ed,Gd */
|
||||
CHECK_FLAGS(emu);
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
tmp8u = GD.byte[0];
|
||||
if((nextop&0xC0)!=0xC0)
|
||||
{
|
||||
ED=(reg32_t*)(((uint32_t*)(ED))+(tmp8u>>5));
|
||||
}
|
||||
tmp8u&=31;
|
||||
if(ED->dword[0] & (1<<tmp8u))
|
||||
SET_FLAG(F_CF);
|
||||
else
|
||||
CLEAR_FLAG(F_CF);
|
||||
ED->dword[0] ^= (1<<tmp8u);
|
||||
break;
|
||||
case 0xC0: /* XADD Gb,Eb */
|
||||
nextop = F8;
|
||||
GET_EB;
|
||||
tmp8u = add8(emu, EB->byte[0], GB);
|
||||
GB = EB->byte[0];
|
||||
EB->byte[0] = tmp8u;
|
||||
break;
|
||||
case 0xC1: /* XADD Gd,Ed */
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
tmp32u = add32(emu, ED->dword[0], GD.dword[0]);
|
||||
GD.dword[0] = ED->dword[0];
|
||||
ED->dword[0] = tmp32u;
|
||||
break;
|
||||
case 0xC7: /* CMPXCHG8B Gq */
|
||||
CHECK_FLAGS(emu);
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
tmp32u = ED->dword[0];
|
||||
tmp32u2= ED->dword[1];
|
||||
if(R_EAX == tmp32u && R_EDX == tmp32u2) {
|
||||
SET_FLAG(F_ZF);
|
||||
ED->dword[0] = R_EBX;
|
||||
ED->dword[1] = R_ECX;
|
||||
} else {
|
||||
CLEAR_FLAG(F_ZF);
|
||||
R_EAX = tmp32u;
|
||||
R_EDX = tmp32u2;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// trigger invalid lock?
|
||||
ip -= 2; // unfetch
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x81: /* GRP Ed,Id */
|
||||
case 0x83: /* GRP Ed,Ib */
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
if(opcode==0x83) {
|
||||
tmp32s = F8S;
|
||||
tmp32u = (uint32_t)tmp32s;
|
||||
} else
|
||||
tmp32u = F32;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: ED->dword[0] = add32(emu, ED->dword[0], tmp32u); break;
|
||||
case 1: ED->dword[0] = or32(emu, ED->dword[0], tmp32u); break;
|
||||
case 2: ED->dword[0] = adc32(emu, ED->dword[0], tmp32u); break;
|
||||
case 3: ED->dword[0] = sbb32(emu, ED->dword[0], tmp32u); break;
|
||||
case 4: ED->dword[0] = and32(emu, ED->dword[0], tmp32u); break;
|
||||
case 5: ED->dword[0] = sub32(emu, ED->dword[0], tmp32u); break;
|
||||
case 6: ED->dword[0] = xor32(emu, ED->dword[0], tmp32u); break;
|
||||
case 7: cmp32(emu, ED->dword[0], tmp32u); break;
|
||||
}
|
||||
break;
|
||||
case 0x86: /* XCHG Eb,Gb */
|
||||
nextop = F8;
|
||||
GET_EB;
|
||||
tmp8u = GB;
|
||||
GB = EB->byte[0];
|
||||
EB->byte[0] = tmp8u;
|
||||
break;
|
||||
case 0x87: /* XCHG Ed,Gd */
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
tmp32u = GD.dword[0];
|
||||
GD.dword[0] = ED->dword[0];
|
||||
ED->dword[0] = tmp32u;
|
||||
break;
|
||||
case 0xFF: /* GRP 5 Ed */
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: /* INC Ed */
|
||||
ED->dword[0] = inc32(emu, ED->dword[0]);
|
||||
break;
|
||||
case 1: /* DEC Ed */
|
||||
ED->dword[0] = dec32(emu, ED->dword[0]);
|
||||
break;
|
||||
default:
|
||||
printf_log(LOG_NONE, "Illegal Opcode 0xF0 0x%02X 0x%02X\n", opcode, PK(0));
|
||||
emu->quit=1;
|
||||
emu->error |= ERR_ILLEGAL;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
//UnimpOpcode(emu);
|
||||
// should trigger invalid unlock ?
|
||||
ip--; // "unfetch" to use normal instruction
|
||||
}
|
||||
R_EIP = ip;
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
}
|
||||
|
||||
void RunGS(x86emu_t *emu)
|
||||
{
|
||||
uintptr_t ip = R_EIP+1;
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop;
|
||||
reg32_t *oped;
|
||||
uint8_t tmp8u;
|
||||
uint32_t tmp32u;
|
||||
int32_t tmp32s;
|
||||
uintptr_t tlsdata = GetGSBaseEmu(emu);
|
||||
switch(opcode) {
|
||||
case 0x01: /* ADD GS:Ed, Gd */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
ED->dword[0] = add32(emu, ED->dword[0], GD.dword[0]);
|
||||
break;
|
||||
|
||||
case 0x03: /* ADD Gd, GS:Ed */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
GD.dword[0] = add32(emu, GD.dword[0], ED->dword[0]);
|
||||
break;
|
||||
|
||||
case 0x11: /* ADC GS:Ed, Gd */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
ED->dword[0] = adc32(emu, ED->dword[0], GD.dword[0]);
|
||||
|
||||
case 0x2B: /* SUB Gd, GS:Ed */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
GD.dword[0] = sub32(emu, GD.dword[0], ED->dword[0]);
|
||||
break;
|
||||
|
||||
case 0x33: /* XOR Gd,Ed */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
GD.dword[0] = xor32(emu, GD.dword[0], ED->dword[0]);
|
||||
break;
|
||||
|
||||
case 0x64: /* FS: */
|
||||
// so just ignore that GS: prefix then
|
||||
--ip; // put FS back
|
||||
break;
|
||||
|
||||
case 0x69: /* IMUL Gd,Ed,Id */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
tmp32u = F32;
|
||||
GD.dword[0] = imul32(emu, ED->dword[0], tmp32u);
|
||||
break;
|
||||
|
||||
case 0x70:
|
||||
case 0x71:
|
||||
case 0x72:
|
||||
case 0x73:
|
||||
case 0x74:
|
||||
case 0x75:
|
||||
case 0x76:
|
||||
case 0x77:
|
||||
case 0x78:
|
||||
case 0x79:
|
||||
case 0x7A:
|
||||
case 0x7B:
|
||||
case 0x7C:
|
||||
case 0x7D:
|
||||
case 0x7E:
|
||||
case 0x7F:
|
||||
// just ignore the prefix
|
||||
--ip;
|
||||
break;
|
||||
|
||||
case 0x80: /* GRP Eb,Ib */
|
||||
case 0x82: // 0x82 and 0x80 are the same opcodes it seems?
|
||||
nextop = F8;
|
||||
GET_EB_OFFS(tlsdata);
|
||||
tmp8u = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: EB->byte[0] = add8(emu, EB->byte[0], tmp8u); break;
|
||||
case 1: EB->byte[0] = or8(emu, EB->byte[0], tmp8u); break;
|
||||
case 2: EB->byte[0] = adc8(emu, EB->byte[0], tmp8u); break;
|
||||
case 3: EB->byte[0] = sbb8(emu, EB->byte[0], tmp8u); break;
|
||||
case 4: EB->byte[0] = and8(emu, EB->byte[0], tmp8u); break;
|
||||
case 5: EB->byte[0] = sub8(emu, EB->byte[0], tmp8u); break;
|
||||
case 6: EB->byte[0] = xor8(emu, EB->byte[0], tmp8u); break;
|
||||
case 7: cmp8(emu, EB->byte[0], tmp8u); break;
|
||||
}
|
||||
break;
|
||||
case 0x81: /* GRP Ed,Id */
|
||||
case 0x83: /* GRP Ed,Ib */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
if(opcode==0x83) {
|
||||
tmp32s = F8S;
|
||||
tmp32u = (uint32_t)tmp32s;
|
||||
} else
|
||||
tmp32u = F32;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: ED->dword[0] = add32(emu, ED->dword[0], tmp32u); break;
|
||||
case 1: ED->dword[0] = or32(emu, ED->dword[0], tmp32u); break;
|
||||
case 2: ED->dword[0] = adc32(emu, ED->dword[0], tmp32u); break;
|
||||
case 3: ED->dword[0] = sbb32(emu, ED->dword[0], tmp32u); break;
|
||||
case 4: ED->dword[0] = and32(emu, ED->dword[0], tmp32u); break;
|
||||
case 5: ED->dword[0] = sub32(emu, ED->dword[0], tmp32u); break;
|
||||
case 6: ED->dword[0] = xor32(emu, ED->dword[0], tmp32u); break;
|
||||
case 7: cmp32(emu, ED->dword[0], tmp32u); break;
|
||||
}
|
||||
break;
|
||||
case 0x89: /* MOV Ed,Gd */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
ED->dword[0] = GD.dword[0];
|
||||
break;
|
||||
case 0x8A: /* MOV Gb,GS:Eb */
|
||||
nextop = F8;
|
||||
GET_EB_OFFS(tlsdata);
|
||||
GB = EB->byte[0];
|
||||
break;
|
||||
case 0x8B: /* MOV Gd,Ed */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
GD.dword[0] = ED->dword[0];
|
||||
break;
|
||||
case 0xA1: /* MOV EAX,Ov */
|
||||
tmp32s = F32S;
|
||||
R_EAX = *(uint32_t*)((tlsdata) + tmp32s);
|
||||
break;
|
||||
case 0xA2: /* MOV Ob,AL */
|
||||
tmp32s = F32S;
|
||||
*(uint8_t*)((tlsdata) + tmp32s) = R_AL;
|
||||
break;
|
||||
case 0xA3: /* MOV Od,EAX */
|
||||
tmp32s = F32S;
|
||||
*(uint32_t*)((tlsdata) + tmp32s) = R_EAX;
|
||||
break;
|
||||
|
||||
case 0xC0: /* GRP2 Eb,Ib */
|
||||
nextop = F8;
|
||||
GET_EB_OFFS(tlsdata);
|
||||
tmp8u = F8/* & 0x1f*/; // masking done in each functions
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: EB->byte[0] = rol8(emu, EB->byte[0], tmp8u); break;
|
||||
case 1: EB->byte[0] = ror8(emu, EB->byte[0], tmp8u); break;
|
||||
case 2: EB->byte[0] = rcl8(emu, EB->byte[0], tmp8u); break;
|
||||
case 3: EB->byte[0] = rcr8(emu, EB->byte[0], tmp8u); break;
|
||||
case 4:
|
||||
case 6: EB->byte[0] = shl8(emu, EB->byte[0], tmp8u); break;
|
||||
case 5: EB->byte[0] = shr8(emu, EB->byte[0], tmp8u); break;
|
||||
case 7: EB->byte[0] = sar8(emu, EB->byte[0], tmp8u); break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC6: /* MOV Eb,Ib */
|
||||
nextop = F8;
|
||||
GET_EB_OFFS(tlsdata);
|
||||
EB->byte[0] = F8;
|
||||
break;
|
||||
case 0xC7: /* MOV Ed,Id */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
ED->dword[0] = F32;
|
||||
break;
|
||||
|
||||
case 0xFF: /* GRP 5 Ed */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: /* INC Ed */
|
||||
ED->dword[0] = inc32(emu, ED->dword[0]);
|
||||
break;
|
||||
case 1: /* DEC Ed */
|
||||
ED->dword[0] = dec32(emu, ED->dword[0]);
|
||||
break;
|
||||
case 2: /* CALL NEAR Ed */
|
||||
Push(emu, R_EIP);
|
||||
R_EIP = ED->dword[0]; // should get value in temp var. in case ED use ESP?
|
||||
break;
|
||||
case 3: /* CALL FAR Ed */
|
||||
if(nextop>0xc0) {
|
||||
printf_log(LOG_NONE, "Illegal Opcode %02X %02X\n", opcode, nextop);
|
||||
emu->quit=1;
|
||||
emu->error |= ERR_ILLEGAL;
|
||||
} else {
|
||||
Push16(emu, R_CS);
|
||||
Push(emu, R_EIP);
|
||||
R_EIP = ED->dword[0];
|
||||
R_CS = (ED+1)->word[0];
|
||||
}
|
||||
break;
|
||||
case 4: /* JMP NEAR Ed */
|
||||
R_EIP = ED->dword[0];
|
||||
break;
|
||||
case 5: /* JMP FAR Ed */
|
||||
if(nextop>0xc0) {
|
||||
printf_log(LOG_NONE, "Illegal Opcode 0x%02X 0x%02X\n", opcode, nextop);
|
||||
emu->quit=1;
|
||||
emu->error |= ERR_ILLEGAL;
|
||||
} else {
|
||||
R_EIP = ED->dword[0];
|
||||
R_CS = (ED+1)->word[0];
|
||||
}
|
||||
break;
|
||||
case 6: /* Push Ed */
|
||||
Push(emu, ED->dword[0]);
|
||||
break;
|
||||
default:
|
||||
printf_log(LOG_NONE, "Illegal Opcode 0x%02X 0x%02X\n", opcode, nextop);
|
||||
emu->quit=1;
|
||||
emu->error |= ERR_ILLEGAL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ip--;
|
||||
UnimpOpcode(emu);
|
||||
}
|
||||
R_EIP = ip;
|
||||
}
|
||||
|
||||
void RunFS(x86emu_t *emu)
|
||||
{
|
||||
uintptr_t ip = R_EIP+1;
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop;
|
||||
reg32_t *oped;
|
||||
uint8_t tmp8u;
|
||||
uint32_t tmp32u;
|
||||
int32_t tmp32s;
|
||||
int16_t tmp16s;
|
||||
uintptr_t tlsdata = GetFSBaseEmu(emu);
|
||||
switch(opcode) {
|
||||
case 0x33: /* XOR Gd,Ed */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
GD.dword[0] = xor32(emu, GD.dword[0], ED->dword[0]);
|
||||
break;
|
||||
case 0x3B: /* CMP GD, FS:Ed */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
cmp32(emu, GD.dword[0], ED->dword[0]);
|
||||
break;
|
||||
|
||||
case 0x54: /* PUSH ESP */
|
||||
tmp32u = R_ESP;
|
||||
R_ESP -= 4;
|
||||
*((uint32_t*)(R_ESP+tlsdata)) = tmp32u; //Push(emu, tmp32u);
|
||||
break;
|
||||
case 0x50:
|
||||
case 0x51:
|
||||
case 0x52:
|
||||
case 0x53:
|
||||
case 0x55:
|
||||
case 0x56:
|
||||
case 0x57: /* PUSH Reg */
|
||||
tmp8u = opcode&7;
|
||||
*((uint32_t*)(R_ESP+tlsdata)) = emu->regs[tmp8u].dword[0]; //Push(emu, emu->regs[tmp8u].dword[0]);
|
||||
break;
|
||||
case 0x58:
|
||||
case 0x59:
|
||||
case 0x5A:
|
||||
case 0x5B:
|
||||
case 0x5C: /* POP ESP */
|
||||
case 0x5D:
|
||||
case 0x5E:
|
||||
case 0x5F: /* POP Reg */
|
||||
tmp8u = opcode&7;
|
||||
emu->regs[tmp8u].dword[0] = *((uint32_t*)(R_ESP+tlsdata)); // Pop(emu);
|
||||
R_ESP += 4;
|
||||
break;
|
||||
|
||||
case 0x67:
|
||||
opcode = F8;
|
||||
switch(opcode) {
|
||||
case 0x89: /* MOV ED16,Gd */
|
||||
nextop = F8;
|
||||
oped=GetEw16off(emu, nextop, tlsdata);
|
||||
ED->dword[0] = GD.dword[0];
|
||||
break;
|
||||
case 0x8B: /* MOV Gd,Ed16 */
|
||||
nextop = F8;
|
||||
oped=GetEw16off(emu, nextop, tlsdata);
|
||||
GD.dword[0] = ED->dword[0];
|
||||
break;
|
||||
case 0xA1: /* MOV EAX,Ov16 */
|
||||
tmp16s = F16S;
|
||||
R_EAX = *(uint32_t*)((tlsdata) + tmp16s);
|
||||
break;
|
||||
case 0xA3: /* MOV Ov16,EAX */
|
||||
tmp16s = F16S;
|
||||
*(uint32_t*)((tlsdata) + tmp16s) = R_EAX;
|
||||
break;
|
||||
case 0xFF: /* GRP 5 Ed */
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 6: /* Push Ed */
|
||||
oped=GetEw16off(emu, nextop, tlsdata);
|
||||
Push(emu, ED->dword[0]);
|
||||
break;
|
||||
default:
|
||||
ip-=2;
|
||||
UnimpOpcode(emu);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ip-=2;
|
||||
UnimpOpcode(emu);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x69: /* IMUL Gd,Ed,Id */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
tmp32u = F32;
|
||||
GD.dword[0] = imul32(emu, ED->dword[0], tmp32u);
|
||||
break;
|
||||
case 0x80: /* GRP Eb,Ib */
|
||||
case 0x82: // 0x82 and 0x80 are the same opcodes it seems?
|
||||
nextop = F8;
|
||||
GET_EB_OFFS(tlsdata);
|
||||
tmp8u = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: EB->byte[0] = add8(emu, EB->byte[0], tmp8u); break;
|
||||
case 1: EB->byte[0] = or8(emu, EB->byte[0], tmp8u); break;
|
||||
case 2: EB->byte[0] = adc8(emu, EB->byte[0], tmp8u); break;
|
||||
case 3: EB->byte[0] = sbb8(emu, EB->byte[0], tmp8u); break;
|
||||
case 4: EB->byte[0] = and8(emu, EB->byte[0], tmp8u); break;
|
||||
case 5: EB->byte[0] = sub8(emu, EB->byte[0], tmp8u); break;
|
||||
case 6: EB->byte[0] = xor8(emu, EB->byte[0], tmp8u); break;
|
||||
case 7: cmp8(emu, EB->byte[0], tmp8u); break;
|
||||
}
|
||||
break;
|
||||
case 0x81: /* GRP Ed,Id */
|
||||
case 0x83: /* GRP Ed,Ib */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
if(opcode==0x83) {
|
||||
tmp32s = F8S;
|
||||
tmp32u = (uint32_t)tmp32s;
|
||||
} else
|
||||
tmp32u = F32;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: ED->dword[0] = add32(emu, ED->dword[0], tmp32u); break;
|
||||
case 1: ED->dword[0] = or32(emu, ED->dword[0], tmp32u); break;
|
||||
case 2: ED->dword[0] = adc32(emu, ED->dword[0], tmp32u); break;
|
||||
case 3: ED->dword[0] = sbb32(emu, ED->dword[0], tmp32u); break;
|
||||
case 4: ED->dword[0] = and32(emu, ED->dword[0], tmp32u); break;
|
||||
case 5: ED->dword[0] = sub32(emu, ED->dword[0], tmp32u); break;
|
||||
case 6: ED->dword[0] = xor32(emu, ED->dword[0], tmp32u); break;
|
||||
case 7: cmp32(emu, ED->dword[0], tmp32u); break;
|
||||
}
|
||||
break;
|
||||
case 0x89: /* MOV Ed,Gd */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
ED->dword[0] = GD.dword[0];
|
||||
break;
|
||||
case 0x8B: /* MOV Gd,Ed */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
GD.dword[0] = ED->dword[0];
|
||||
break;
|
||||
case 0x8F: /* POP Ed */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
ED->dword[0] = Pop(emu);
|
||||
break;
|
||||
case 0xA1: /* MOV EAX,Ov */
|
||||
tmp32s = F32S;
|
||||
R_EAX = *(uint32_t*)((tlsdata) + tmp32s);
|
||||
break;
|
||||
case 0xA2: /* MOV Ob,AL */
|
||||
tmp32s = F32S;
|
||||
*(uint8_t*)((tlsdata) + tmp32s) = R_AL;
|
||||
break;
|
||||
case 0xA3: /* MOV Od,EAX */
|
||||
tmp32s = F32S;
|
||||
*(uint32_t*)((tlsdata) + tmp32s) = R_EAX;
|
||||
break;
|
||||
|
||||
case 0xC0: /* GRP2 Eb,Ib */
|
||||
nextop = F8;
|
||||
GET_EB_OFFS(tlsdata);
|
||||
tmp8u = F8/* & 0x1f*/; // masking done in each functions
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: EB->byte[0] = rol8(emu, EB->byte[0], tmp8u); break;
|
||||
case 1: EB->byte[0] = ror8(emu, EB->byte[0], tmp8u); break;
|
||||
case 2: EB->byte[0] = rcl8(emu, EB->byte[0], tmp8u); break;
|
||||
case 3: EB->byte[0] = rcr8(emu, EB->byte[0], tmp8u); break;
|
||||
case 4:
|
||||
case 6: EB->byte[0] = shl8(emu, EB->byte[0], tmp8u); break;
|
||||
case 5: EB->byte[0] = shr8(emu, EB->byte[0], tmp8u); break;
|
||||
case 7: EB->byte[0] = sar8(emu, EB->byte[0], tmp8u); break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC6: /* MOV Eb,Ib */
|
||||
nextop = F8;
|
||||
GET_EB_OFFS(tlsdata);
|
||||
EB->byte[0] = F8;
|
||||
break;
|
||||
case 0xC7: /* MOV Ed,Id */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
ED->dword[0] = F32;
|
||||
break;
|
||||
|
||||
case 0xFF: /* GRP 5 Ed */
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(tlsdata);
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: /* INC Ed */
|
||||
ED->dword[0] = inc32(emu, ED->dword[0]);
|
||||
break;
|
||||
case 1: /* DEC Ed */
|
||||
ED->dword[0] = dec32(emu, ED->dword[0]);
|
||||
break;
|
||||
case 2: /* CALL NEAR Ed */
|
||||
Push(emu, R_EIP);
|
||||
R_EIP = ED->dword[0]; // should get value in temp var. in case ED use ESP?
|
||||
break;
|
||||
case 3: /* CALL FAR Ed */
|
||||
if(nextop>0xc0) {
|
||||
printf_log(LOG_NONE, "Illegal Opcode %02X %02X\n", opcode, nextop);
|
||||
emu->quit=1;
|
||||
emu->error |= ERR_ILLEGAL;
|
||||
} else {
|
||||
Push16(emu, R_CS);
|
||||
Push(emu, R_EIP);
|
||||
R_EIP = ED->dword[0];
|
||||
R_CS = (ED+1)->word[0];
|
||||
}
|
||||
break;
|
||||
case 4: /* JMP NEAR Ed */
|
||||
R_EIP = ED->dword[0];
|
||||
break;
|
||||
case 5: /* JMP FAR Ed */
|
||||
if(nextop>0xc0) {
|
||||
printf_log(LOG_NONE, "Illegal Opcode 0x%02X 0x%02X\n", opcode, nextop);
|
||||
emu->quit=1;
|
||||
emu->error |= ERR_ILLEGAL;
|
||||
} else {
|
||||
R_EIP = ED->dword[0];
|
||||
R_CS = (ED+1)->word[0];
|
||||
}
|
||||
break;
|
||||
case 6: /* Push Ed */
|
||||
Push(emu, ED->dword[0]);
|
||||
break;
|
||||
default:
|
||||
printf_log(LOG_NONE, "Illegal Opcode 0x%02X 0x%02X\n", opcode, nextop);
|
||||
ip-=2;
|
||||
emu->quit=1;
|
||||
emu->error |= ERR_ILLEGAL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ip--;
|
||||
UnimpOpcode(emu);
|
||||
}
|
||||
R_EIP = ip;
|
||||
}
|
||||
@@ -4,61 +4,67 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#ifdef HAVE_TRACE
|
||||
#include <unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
#endif
|
||||
|
||||
#include "debug.h"
|
||||
#include "stack.h"
|
||||
#include "box86stack.h"
|
||||
#include "x86emu.h"
|
||||
#include "x86run.h"
|
||||
#include "x86run_private.h"
|
||||
#include "x86emu_private.h"
|
||||
#include "box86context.h"
|
||||
#include "x86run.h"
|
||||
#include "librarian.h"
|
||||
#include "elfloader.h"
|
||||
#ifdef HAVE_TRACE
|
||||
#include "x86trace.h"
|
||||
#endif
|
||||
#include "x86tls.h"
|
||||
|
||||
static uint32_t x86emu_parity_tab[8] =
|
||||
{
|
||||
0x96696996,
|
||||
0x69969669,
|
||||
0x69969669,
|
||||
0x96696996,
|
||||
0x69969669,
|
||||
0x96696996,
|
||||
0x96696996,
|
||||
0x69969669,
|
||||
};
|
||||
|
||||
#define PARITY(x) (((x86emu_parity_tab[(x) / 32] >> ((x) % 32)) & 1) == 0)
|
||||
#define PARITY(x) (((emu->x86emu_parity_tab[(x) / 32] >> ((x) % 32)) & 1) == 0)
|
||||
#define XOR2(x) (((x) ^ ((x)>>1)) & 0x1)
|
||||
|
||||
int32_t EXPORT my___libc_start_main(x86emu_t* emu, int *(main) (int, char * *, char * *), int argc, char * * ubp_av, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void (* stack_end))
|
||||
{
|
||||
//TODO: register rtld_fini
|
||||
//TODO: register fini
|
||||
// let's cheat and set all args...
|
||||
Push(emu, (uint32_t)my_context->envv);
|
||||
Push(emu, (uint32_t)my_context->argv);
|
||||
Push(emu, (uint32_t)my_context->argc);
|
||||
if(init) {
|
||||
PushExit(emu);
|
||||
R_EIP=(uint32_t)*init;
|
||||
printf_log(LOG_DEBUG, "Calling init(%p) from __libc_start_main\n", *init);
|
||||
Run(emu);
|
||||
DynaRun(emu);
|
||||
if(emu->error) // any error, don't bother with more
|
||||
return 0;
|
||||
emu->quit = 0;
|
||||
}
|
||||
// let's cheat and set all args...
|
||||
printf_log(LOG_DEBUG, "Transfert to main(%d, %p, %p)=>%p from __libc_start_main\n", my_context->argc, my_context->argv, my_context->envv, main);
|
||||
// call main and finish
|
||||
Push(emu, (uint32_t)emu->context->envv);
|
||||
Push(emu, (uint32_t)emu->context->argv);
|
||||
Push(emu, (uint32_t)emu->context->argc);
|
||||
PushExit(emu);
|
||||
R_EIP=(uint32_t)main;
|
||||
printf_log(LOG_DEBUG, "Transfert to main(%d, %p, %p)=>%p from __libc_start_main\n", emu->context->argc, emu->context->argv, emu->context->envv, main);
|
||||
#ifdef DYNAREC
|
||||
DynaRun(emu);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* GetNativeName(void* p)
|
||||
{
|
||||
static char unknown[10] = "???";
|
||||
const char *ret = GetNameOffset(my_context->maplib, p);
|
||||
if(ret)
|
||||
return ret;
|
||||
|
||||
static char buff[500] = {0};
|
||||
Dl_info info;
|
||||
if(dladdr(p, &info)==0)
|
||||
strcpy(buff, "???");
|
||||
return unknown;
|
||||
else {
|
||||
if(info.dli_sname) {
|
||||
strcpy(buff, info.dli_sname);
|
||||
@@ -66,18 +72,11 @@ const char* GetNativeName(void* p)
|
||||
strcat(buff, " ("); strcat(buff, info.dli_fname); strcat(buff, ")");
|
||||
}
|
||||
} else
|
||||
strcpy(buff, "unknown");
|
||||
return unknown;
|
||||
}
|
||||
return buff;
|
||||
}
|
||||
|
||||
uintptr_t pltResolver = ~0;
|
||||
void PltResolver(x86emu_t* emu, uint32_t id, uintptr_t ofs)
|
||||
{
|
||||
printf_log(LOG_INFO, "PltResolver: Ofs=%p, Id=%d (IP=%p)", (void*)ofs, id, *(void**)(R_ESP));
|
||||
emu->quit=1;
|
||||
}
|
||||
|
||||
void UpdateFlags(x86emu_t *emu)
|
||||
{
|
||||
uint32_t cc;
|
||||
@@ -111,7 +110,7 @@ void UpdateFlags(x86emu_t *emu)
|
||||
lo = (emu->op2 & 0xFFFF) + (emu->op1 & 0xFFFF);
|
||||
hi = (lo >> 16) + (emu->op2 >> 16) + (emu->op1 >> 16);
|
||||
CONDITIONAL_SET_FLAG(hi & 0x10000, F_CF);
|
||||
CONDITIONAL_SET_FLAG((emu->res & 0xffffffff) == 0, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(!emu->res, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
|
||||
cc = (emu->op1 & emu->op2) | ((~emu->res) & (emu->op1 | emu->op2));
|
||||
@@ -124,7 +123,7 @@ void UpdateFlags(x86emu_t *emu)
|
||||
CLEAR_FLAG(F_AF);
|
||||
CONDITIONAL_SET_FLAG(emu->res & 0x80, F_SF);
|
||||
CONDITIONAL_SET_FLAG(emu->res == 0, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(emu->res), F_PF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
|
||||
break;
|
||||
case d_and16:
|
||||
CLEAR_FLAG(F_OF);
|
||||
@@ -160,7 +159,7 @@ void UpdateFlags(x86emu_t *emu)
|
||||
break;
|
||||
case d_dec32:
|
||||
CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF);
|
||||
CONDITIONAL_SET_FLAG((emu->res & 0xffffffff) == 0, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(!emu->res, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
|
||||
bc = (emu->res & (~emu->op1 | 1)) | (~emu->op1 & 1);
|
||||
CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF);
|
||||
@@ -183,20 +182,91 @@ void UpdateFlags(x86emu_t *emu)
|
||||
CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
|
||||
break;
|
||||
case d_inc32:
|
||||
CONDITIONAL_SET_FLAG((emu->res & 0xffffffff) == 0, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(!emu->res, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
|
||||
cc = (1 & emu->op1) | ((~emu->res) & (1 | emu->op1));
|
||||
CONDITIONAL_SET_FLAG(XOR2(cc >> 30), F_OF);
|
||||
CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
|
||||
break;
|
||||
case d_imul8:
|
||||
lo = emu->res & 0xff;
|
||||
hi = (emu->res>>8)&0xff;
|
||||
if (((lo & 0x80) == 0 && hi == 0x00) ||
|
||||
((lo & 0x80) != 0 && hi == 0xFF)) {
|
||||
CLEAR_FLAG(F_CF);
|
||||
CLEAR_FLAG(F_OF);
|
||||
} else {
|
||||
SET_FLAG(F_CF);
|
||||
SET_FLAG(F_OF);
|
||||
}
|
||||
CONDITIONAL_SET_FLAG(PARITY(lo & 0xff), F_PF);
|
||||
break;
|
||||
case d_imul16:
|
||||
lo = (uint16_t)emu->res;
|
||||
hi = (uint16_t)(emu->res >> 16);
|
||||
if (((lo & 0x8000) == 0 && hi == 0x00) ||
|
||||
((lo & 0x8000) != 0 && hi == 0xFFFF)) {
|
||||
CLEAR_FLAG(F_CF);
|
||||
CLEAR_FLAG(F_OF);
|
||||
} else {
|
||||
SET_FLAG(F_CF);
|
||||
SET_FLAG(F_OF);
|
||||
}
|
||||
CONDITIONAL_SET_FLAG(PARITY(lo & 0xff), F_PF);
|
||||
break;
|
||||
case d_imul32:
|
||||
if (((emu->res & 0x80000000) == 0 && emu->op1 == 0x00) ||
|
||||
((emu->res & 0x80000000) != 0 && emu->op1 == 0xFFFFFFFF)) {
|
||||
CLEAR_FLAG(F_CF);
|
||||
CLEAR_FLAG(F_OF);
|
||||
} else {
|
||||
SET_FLAG(F_CF);
|
||||
SET_FLAG(F_OF);
|
||||
}
|
||||
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
|
||||
break;
|
||||
case d_mul8:
|
||||
lo = emu->res & 0xff;
|
||||
hi = (emu->res>>8)&0xff;
|
||||
if (hi == 0) {
|
||||
CLEAR_FLAG(F_CF);
|
||||
CLEAR_FLAG(F_OF);
|
||||
} else {
|
||||
SET_FLAG(F_CF);
|
||||
SET_FLAG(F_OF);
|
||||
}
|
||||
CONDITIONAL_SET_FLAG(PARITY(lo & 0xff), F_PF);
|
||||
break;
|
||||
case d_mul16:
|
||||
lo = (uint16_t)emu->res;
|
||||
hi = (uint16_t)(emu->res >> 16);
|
||||
if (hi == 0) {
|
||||
CLEAR_FLAG(F_CF);
|
||||
CLEAR_FLAG(F_OF);
|
||||
} else {
|
||||
SET_FLAG(F_CF);
|
||||
SET_FLAG(F_OF);
|
||||
}
|
||||
CONDITIONAL_SET_FLAG(PARITY(lo & 0xff), F_PF);
|
||||
break;
|
||||
case d_mul32:
|
||||
if (emu->op1 == 0) {
|
||||
CLEAR_FLAG(F_CF);
|
||||
CLEAR_FLAG(F_OF);
|
||||
} else {
|
||||
SET_FLAG(F_CF);
|
||||
SET_FLAG(F_OF);
|
||||
}
|
||||
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
|
||||
break;
|
||||
case d_or8:
|
||||
CLEAR_FLAG(F_OF);
|
||||
CLEAR_FLAG(F_CF);
|
||||
CLEAR_FLAG(F_AF);
|
||||
CONDITIONAL_SET_FLAG(emu->res & 0x80, F_SF);
|
||||
CONDITIONAL_SET_FLAG(emu->res == 0, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(emu->res), F_PF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
|
||||
break;
|
||||
case d_or16:
|
||||
CLEAR_FLAG(F_OF);
|
||||
@@ -218,7 +288,7 @@ void UpdateFlags(x86emu_t *emu)
|
||||
CONDITIONAL_SET_FLAG(emu->op1 != 0, F_CF);
|
||||
CONDITIONAL_SET_FLAG((emu->res & 0xff) == 0, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(emu->res & 0x80, F_SF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(emu->res), F_PF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
|
||||
bc = emu->res | emu->op1;
|
||||
CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF);
|
||||
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
|
||||
@@ -234,7 +304,7 @@ void UpdateFlags(x86emu_t *emu)
|
||||
break;
|
||||
case d_neg32:
|
||||
CONDITIONAL_SET_FLAG(emu->op1 != 0, F_CF);
|
||||
CONDITIONAL_SET_FLAG((emu->res & 0xffffffff) == 0, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(!emu->res, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
|
||||
bc = emu->res | emu->op1;
|
||||
@@ -291,7 +361,7 @@ void UpdateFlags(x86emu_t *emu)
|
||||
if (emu->op2 > 0) {
|
||||
cc = emu->op1 & (1 << (32 - emu->op2));
|
||||
CONDITIONAL_SET_FLAG(cc, F_CF);
|
||||
CONDITIONAL_SET_FLAG((emu->res & 0xffffffff) == 0, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(!emu->res, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
|
||||
}
|
||||
@@ -402,7 +472,7 @@ void UpdateFlags(x86emu_t *emu)
|
||||
if (cnt > 0) {
|
||||
cc = emu->op1 & (1 << (cnt - 1));
|
||||
CONDITIONAL_SET_FLAG(cc, F_CF);
|
||||
CONDITIONAL_SET_FLAG((emu->res & 0xffffffff) == 0, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(!emu->res, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
|
||||
}
|
||||
@@ -430,7 +500,7 @@ void UpdateFlags(x86emu_t *emu)
|
||||
break;
|
||||
case d_sub32:
|
||||
CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF);
|
||||
CONDITIONAL_SET_FLAG((emu->res & 0xffffffff) == 0, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(!emu->res, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
|
||||
bc = (emu->res & (~emu->op1 | emu->op2)) | (~emu->op1 & emu->op2);
|
||||
CONDITIONAL_SET_FLAG(bc & 0x80000000, F_CF);
|
||||
@@ -441,7 +511,7 @@ void UpdateFlags(x86emu_t *emu)
|
||||
CLEAR_FLAG(F_OF);
|
||||
CONDITIONAL_SET_FLAG(emu->res & 0x80, F_SF);
|
||||
CONDITIONAL_SET_FLAG(emu->res == 0, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(emu->res), F_PF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
|
||||
CLEAR_FLAG(F_CF);
|
||||
CLEAR_FLAG(F_AF);
|
||||
break;
|
||||
@@ -461,6 +531,155 @@ void UpdateFlags(x86emu_t *emu)
|
||||
CLEAR_FLAG(F_CF);
|
||||
CLEAR_FLAG(F_AF);
|
||||
break;
|
||||
case d_cmp8:
|
||||
CLEAR_FLAG(F_CF);
|
||||
CONDITIONAL_SET_FLAG(emu->res & 0x80, F_SF);
|
||||
CONDITIONAL_SET_FLAG((emu->res & 0xff) == 0, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
|
||||
bc = (emu->res & (~emu->op1 | emu->op2)) | (~emu->op1 & emu->op2);
|
||||
CONDITIONAL_SET_FLAG(bc & 0x80, F_CF);
|
||||
CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF);
|
||||
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
|
||||
break;
|
||||
case d_cmp16:
|
||||
CONDITIONAL_SET_FLAG(emu->res & 0x8000, F_SF);
|
||||
CONDITIONAL_SET_FLAG((emu->res & 0xffff) == 0, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
|
||||
bc = (emu->res & (~emu->op1 | emu->op2)) | (~emu->op1 & emu->op2);
|
||||
CONDITIONAL_SET_FLAG(bc & 0x8000, F_CF);
|
||||
CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF);
|
||||
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
|
||||
break;
|
||||
case d_cmp32:
|
||||
CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF);
|
||||
CONDITIONAL_SET_FLAG(!emu->res, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
|
||||
bc = (emu->res & (~emu->op1 | emu->op2)) | (~emu->op1 & emu->op2);
|
||||
CONDITIONAL_SET_FLAG(bc & 0x80000000, F_CF);
|
||||
CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF);
|
||||
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
|
||||
break;
|
||||
case d_tst8:
|
||||
CLEAR_FLAG(F_OF);
|
||||
CONDITIONAL_SET_FLAG(emu->res & 0x80, F_SF);
|
||||
CONDITIONAL_SET_FLAG(emu->res == 0, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
|
||||
CLEAR_FLAG(F_CF);
|
||||
break;
|
||||
case d_tst16:
|
||||
CLEAR_FLAG(F_OF);
|
||||
CONDITIONAL_SET_FLAG(emu->res & 0x8000, F_SF);
|
||||
CONDITIONAL_SET_FLAG(emu->res == 0, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
|
||||
CLEAR_FLAG(F_CF);
|
||||
break;
|
||||
case d_tst32:
|
||||
CLEAR_FLAG(F_OF);
|
||||
CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF);
|
||||
CONDITIONAL_SET_FLAG(emu->res == 0, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
|
||||
CLEAR_FLAG(F_CF);
|
||||
break;
|
||||
case d_adc8:
|
||||
CONDITIONAL_SET_FLAG(emu->res & 0x100, F_CF);
|
||||
CONDITIONAL_SET_FLAG((emu->res & 0xff) == 0, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(emu->res & 0x80, F_SF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
|
||||
cc = (emu->op1 & emu->op2) | ((~emu->res) & (emu->op1 | emu->op2));
|
||||
CONDITIONAL_SET_FLAG(XOR2(cc >> 6), F_OF);
|
||||
CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
|
||||
break;
|
||||
case d_adc16:
|
||||
CONDITIONAL_SET_FLAG(emu->res & 0x10000, F_CF);
|
||||
CONDITIONAL_SET_FLAG((emu->res & 0xffff) == 0, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(emu->res & 0x8000, F_SF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
|
||||
cc = (emu->op1 & emu->op2) | ((~emu->res) & (emu->op1 | emu->op2));
|
||||
CONDITIONAL_SET_FLAG(XOR2(cc >> 14), F_OF);
|
||||
CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
|
||||
break;
|
||||
case d_adc32:
|
||||
if(emu->res == (emu->op1+emu->op2)) {
|
||||
lo = (emu->op1 & 0xFFFF) + (emu->op2 & 0xFFFF);
|
||||
} else {
|
||||
lo = 1 + (emu->op1 & 0xFFFF) + (emu->op2 & 0xFFFF);
|
||||
}
|
||||
hi = (lo >> 16) + (emu->op1 >> 16) + (emu->op2 >> 16);
|
||||
CONDITIONAL_SET_FLAG(hi & 0x10000, F_CF);
|
||||
CONDITIONAL_SET_FLAG(!emu->res, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
|
||||
cc = (emu->op2 & emu->op1) | ((~emu->res) & (emu->op2 | emu->op1));
|
||||
CONDITIONAL_SET_FLAG(XOR2(cc >> 30), F_OF);
|
||||
CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
|
||||
break;
|
||||
case d_sbb8:
|
||||
CONDITIONAL_SET_FLAG(emu->res & 0x80, F_SF);
|
||||
CONDITIONAL_SET_FLAG((emu->res & 0xff) == 0, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
|
||||
bc = (emu->res & (~emu->op1 | emu->op2)) | (~emu->op1 & emu->op2);
|
||||
CONDITIONAL_SET_FLAG(bc & 0x80, F_CF);
|
||||
CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF);
|
||||
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
|
||||
break;
|
||||
case d_sbb16:
|
||||
CONDITIONAL_SET_FLAG(emu->res & 0x8000, F_SF);
|
||||
CONDITIONAL_SET_FLAG((emu->res & 0xffff) == 0, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
|
||||
bc = (emu->res & (~emu->op1 | emu->op2)) | (~emu->op1 & emu->op2);
|
||||
CONDITIONAL_SET_FLAG(bc & 0x8000, F_CF);
|
||||
CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF);
|
||||
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
|
||||
break;
|
||||
case d_sbb32:
|
||||
CONDITIONAL_SET_FLAG(emu->res & 0x80000000, F_SF);
|
||||
CONDITIONAL_SET_FLAG(!emu->res, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(PARITY(emu->res & 0xff), F_PF);
|
||||
bc = (emu->res & (~emu->op1 | emu->op2)) | (~emu->op1 & emu->op2);
|
||||
CONDITIONAL_SET_FLAG(bc & 0x80000000, F_CF);
|
||||
CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF);
|
||||
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
|
||||
break;
|
||||
case d_rol8:
|
||||
if(emu->op2 == 1) {
|
||||
CONDITIONAL_SET_FLAG((emu->res + (emu->res >> 7)) & 1, F_OF);
|
||||
}
|
||||
CONDITIONAL_SET_FLAG(emu->res & 0x1, F_CF);
|
||||
break;
|
||||
case d_rol16:
|
||||
if(emu->op2 == 1) {
|
||||
CONDITIONAL_SET_FLAG((emu->res + (emu->res >> 15)) & 1, F_OF);
|
||||
}
|
||||
CONDITIONAL_SET_FLAG(emu->res & 0x1, F_CF);
|
||||
break;
|
||||
case d_rol32:
|
||||
if(emu->op2 == 1) {
|
||||
CONDITIONAL_SET_FLAG((emu->res + (emu->res >> 31)) & 1, F_OF);
|
||||
}
|
||||
CONDITIONAL_SET_FLAG(emu->res & 0x1, F_CF);
|
||||
break;
|
||||
case d_ror8:
|
||||
if(emu->op2 == 1) {
|
||||
CONDITIONAL_SET_FLAG(XOR2(emu->res >> 6), F_OF);
|
||||
}
|
||||
CONDITIONAL_SET_FLAG(emu->res & (1 << 7), F_CF);
|
||||
break;
|
||||
case d_ror16:
|
||||
if(emu->op2 == 1) {
|
||||
CONDITIONAL_SET_FLAG(XOR2(emu->res >> 14), F_OF);
|
||||
}
|
||||
CONDITIONAL_SET_FLAG(emu->res & (1 << 15), F_CF);
|
||||
break;
|
||||
case d_ror32:
|
||||
if(emu->op2 == 1) {
|
||||
CONDITIONAL_SET_FLAG(XOR2(emu->res >> 30), F_OF);
|
||||
}
|
||||
CONDITIONAL_SET_FLAG(emu->res & (1 << 31), F_CF);
|
||||
break;
|
||||
|
||||
case d_unknown:
|
||||
printf_log(LOG_NONE, "Box86: %p trying to evaluate Unknown defered Flags\n", (void*)R_EIP);
|
||||
break;
|
||||
}
|
||||
RESET_FLAGS(emu);
|
||||
}
|
||||
@@ -469,12 +688,13 @@ void UpdateFlags(x86emu_t *emu)
|
||||
void PackFlags(x86emu_t* emu)
|
||||
{
|
||||
#define GO(A) emu->packed_eflags.f.F__##A = emu->flags[F_##A];
|
||||
#define GOC(A, C) emu->packed_eflags.f.F__##A = C;
|
||||
GO(CF);
|
||||
GO(res1);
|
||||
GOC(res1, 1);
|
||||
GO(PF);
|
||||
GO(res2);
|
||||
GOC(res2, 0);
|
||||
GO(AF);
|
||||
GO(res3);
|
||||
GOC(res3, 0);
|
||||
GO(ZF);
|
||||
GO(SF);
|
||||
GO(TF);
|
||||
@@ -483,7 +703,7 @@ void PackFlags(x86emu_t* emu)
|
||||
GO(OF);
|
||||
GO(IOPL);
|
||||
GO(NT);
|
||||
GO(dummy);
|
||||
GOC(dummy, 0);
|
||||
GO(RF);
|
||||
GO(VM);
|
||||
GO(AC);
|
||||
@@ -491,16 +711,18 @@ void PackFlags(x86emu_t* emu)
|
||||
GO(VIP);
|
||||
GO(ID);
|
||||
#undef GO
|
||||
#undef GOC
|
||||
}
|
||||
void UnpackFlags(x86emu_t* emu)
|
||||
{
|
||||
#define GO(A) emu->flags[F_##A] = emu->packed_eflags.f.F__##A;
|
||||
#define GOC(A, C) emu->flags[F_##A] = C;
|
||||
GO(CF);
|
||||
GO(res1);
|
||||
GOC(res1, 1);
|
||||
GO(PF);
|
||||
GO(res2);
|
||||
GOC(res2, 0);
|
||||
GO(AF);
|
||||
GO(res3);
|
||||
GOC(res3, 0);
|
||||
GO(ZF);
|
||||
GO(SF);
|
||||
GO(TF);
|
||||
@@ -509,7 +731,7 @@ void UnpackFlags(x86emu_t* emu)
|
||||
GO(OF);
|
||||
GO(IOPL);
|
||||
GO(NT);
|
||||
GO(dummy);
|
||||
GOC(dummy, 0);
|
||||
GO(RF);
|
||||
GO(VM);
|
||||
GO(AC);
|
||||
@@ -517,4 +739,103 @@ void UnpackFlags(x86emu_t* emu)
|
||||
GO(VIP);
|
||||
GO(ID);
|
||||
#undef GO
|
||||
#undef GOC
|
||||
}
|
||||
|
||||
uintptr_t GetSegmentBaseEmu(x86emu_t* emu, int seg)
|
||||
{
|
||||
if(!emu->segs_clean[seg] || seg==_GS) {
|
||||
emu->segs_offs[seg] = (uintptr_t)GetSegmentBase(emu->segs[seg]);
|
||||
emu->segs_clean[seg] = 1;
|
||||
}
|
||||
return emu->segs_offs[seg];
|
||||
}
|
||||
|
||||
|
||||
const char* getAddrFunctionName(uintptr_t addr)
|
||||
{
|
||||
static char ret[1000];
|
||||
uint32_t sz = 0;
|
||||
uintptr_t start = 0;
|
||||
const char* symbname = FindNearestSymbolName(FindElfAddress(my_context, addr), (void*)addr, &start, &sz);
|
||||
if(symbname && addr>=start && (addr<(start+sz) || !sz)) {
|
||||
if(addr==start)
|
||||
sprintf(ret, "%s/%s", ElfName(FindElfAddress(my_context, addr)), symbname);
|
||||
else
|
||||
sprintf(ret, "%s/%s + %d", ElfName(FindElfAddress(my_context, addr)), symbname, addr - start);
|
||||
} else
|
||||
sprintf(ret, "???");
|
||||
return ret;
|
||||
}
|
||||
|
||||
void printFunctionAddr(uintptr_t nextaddr, const char* text)
|
||||
{
|
||||
uint32_t sz = 0;
|
||||
uintptr_t start = 0;
|
||||
const char* symbname = FindNearestSymbolName(FindElfAddress(my_context, nextaddr), (void*)nextaddr, &start, &sz);
|
||||
if(symbname && nextaddr>=start && (nextaddr<(start+sz) || !sz)) {
|
||||
if(nextaddr==start)
|
||||
printf_log(LOG_NONE, " (%s%s/%s)", text, ElfName(FindElfAddress(my_context, nextaddr)), symbname);
|
||||
else
|
||||
printf_log(LOG_NONE, " (%s%s/%s + %d)", text, ElfName(FindElfAddress(my_context, nextaddr)), symbname, nextaddr - start);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_TRACE
|
||||
extern uint64_t start_cnt;
|
||||
#define PK(a) (*(uint8_t*)(ip+a))
|
||||
#define PK32(a) (*(int32_t*)((uint8_t*)(ip+a)))
|
||||
|
||||
void PrintTrace(x86emu_t* emu, uintptr_t ip, int dynarec)
|
||||
{
|
||||
if(start_cnt) --start_cnt;
|
||||
if(!start_cnt && my_context->dec && (
|
||||
(trace_end == 0)
|
||||
|| ((ip >= trace_start) && (ip < trace_end))) ) {
|
||||
pthread_mutex_lock(&my_context->mutex_trace);
|
||||
int tid = syscall(SYS_gettid);
|
||||
#ifdef DYNAREC
|
||||
if((my_context->trace_tid != tid) || (my_context->trace_dynarec!=dynarec)) {
|
||||
printf_log(LOG_NONE, "Thread %04d| (%s) |\n", tid, dynarec?"dyn":"int");
|
||||
my_context->trace_tid = tid;
|
||||
my_context->trace_dynarec = dynarec;
|
||||
}
|
||||
#else
|
||||
if(my_context->trace_tid != tid) {
|
||||
printf_log(LOG_NONE, "Thread %04d|\n", tid);
|
||||
my_context->trace_tid = tid;
|
||||
}
|
||||
#endif
|
||||
printf_log(LOG_NONE, "%s", DumpCPURegs(emu, ip));
|
||||
if(PK(0)==0xcc && PK(1)=='S' && PK(2)=='C') {
|
||||
uint32_t a = *(uint32_t*)(ip+3);
|
||||
if(a==0) {
|
||||
printf_log(LOG_NONE, "%p: Exit x86emu\n", (void*)ip);
|
||||
} else {
|
||||
printf_log(LOG_NONE, "%p: Native call to %p => %s\n", (void*)ip, (void*)a, GetNativeName(*(void**)(ip+7)));
|
||||
}
|
||||
} else {
|
||||
printf_log(LOG_NONE, "%s", DecodeX86Trace(my_context->dec, ip));
|
||||
uint8_t peek = PK(0);
|
||||
if(peek==0xC3 || peek==0xC2) {
|
||||
printf_log(LOG_NONE, " => %p", *(void**)(R_ESP));
|
||||
printFunctionAddr(*(uintptr_t*)(R_ESP), "=> ");
|
||||
} else if(peek==0x55) {
|
||||
printf_log(LOG_NONE, " => STACK_TOP: %p", *(void**)(R_ESP));
|
||||
printFunctionAddr(ip, "here: ");
|
||||
} else if(peek==0xE8) { // Call
|
||||
uintptr_t nextaddr = ip + 5 + PK32(1);
|
||||
printFunctionAddr(nextaddr, "=> ");
|
||||
} else if(peek==0xFF) {
|
||||
if(PK(1)==0x25) {
|
||||
uintptr_t nextaddr = ip + 6 + PK32(2);
|
||||
printFunctionAddr(nextaddr, "=> ");
|
||||
}
|
||||
}
|
||||
printf_log(LOG_NONE, "\n");
|
||||
}
|
||||
pthread_mutex_unlock(&my_context->mutex_trace);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -6,42 +6,42 @@
|
||||
#include "x86emu_private.h"
|
||||
typedef struct x86emu_s x86emu_t;
|
||||
|
||||
inline uint8_t Fetch8(x86emu_t *emu) {return *(uint8_t*)(R_EIP++);}
|
||||
inline int8_t Fetch8s(x86emu_t *emu) {return *(int8_t*)(R_EIP++);}
|
||||
inline uint16_t Fetch16(x86emu_t *emu)
|
||||
static inline uint8_t Fetch8(x86emu_t *emu) {return *(uint8_t*)(R_EIP++);}
|
||||
static inline int8_t Fetch8s(x86emu_t *emu) {return *(int8_t*)(R_EIP++);}
|
||||
static inline uint16_t Fetch16(x86emu_t *emu)
|
||||
{
|
||||
uint16_t val = *(uint16_t*)R_EIP;
|
||||
R_EIP+=2;
|
||||
return val;
|
||||
}
|
||||
inline int16_t Fetch16s(x86emu_t *emu)
|
||||
static inline int16_t Fetch16s(x86emu_t *emu)
|
||||
{
|
||||
int16_t val = *(int16_t*)R_EIP;
|
||||
R_EIP+=2;
|
||||
return val;
|
||||
}
|
||||
inline uint32_t Fetch32(x86emu_t *emu)
|
||||
static inline uint32_t Fetch32(x86emu_t *emu)
|
||||
{
|
||||
uint32_t val = *(uint32_t*)R_EIP;
|
||||
R_EIP+=4;
|
||||
return val;
|
||||
}
|
||||
inline int32_t Fetch32s(x86emu_t *emu)
|
||||
static inline int32_t Fetch32s(x86emu_t *emu)
|
||||
{
|
||||
int32_t val = *(int32_t*)R_EIP;
|
||||
R_EIP+=4;
|
||||
return val;
|
||||
}
|
||||
inline uint8_t Peek(x86emu_t *emu, int offset){return *(uint8_t*)(R_EIP + offset);}
|
||||
static inline uint8_t Peek(x86emu_t *emu, int offset){return *(uint8_t*)(R_EIP + offset);}
|
||||
|
||||
inline uint32_t Pop(x86emu_t *emu)
|
||||
static inline uint32_t Pop(x86emu_t *emu)
|
||||
{
|
||||
uint32_t* st = ((uint32_t*)(R_ESP));
|
||||
R_ESP += 4;
|
||||
return *st;
|
||||
}
|
||||
|
||||
inline void Push(x86emu_t *emu, uint32_t v)
|
||||
static inline void Push(x86emu_t *emu, uint32_t v)
|
||||
{
|
||||
R_ESP -= 4;
|
||||
*((uint32_t*)R_ESP) = v;
|
||||
@@ -122,6 +122,33 @@ static inline reg32_t* GetEw16(x86emu_t *emu, uint32_t v)
|
||||
}
|
||||
}
|
||||
|
||||
static inline reg32_t* GetEw16off(x86emu_t *emu, uint32_t v, uintptr_t offset)
|
||||
{
|
||||
uint32_t m = v&0xC7; // filter Ed
|
||||
if(m>=0xC0) {
|
||||
return &emu->regs[(m&0x07)];
|
||||
} else {
|
||||
uint32_t base = 0;
|
||||
switch(m&7) {
|
||||
case 0: base = R_BX+R_SI; break;
|
||||
case 1: base = R_BX+R_DI; break;
|
||||
case 2: base = R_BP+R_SI; break;
|
||||
case 3: base = R_BP+R_DI; break;
|
||||
case 4: base = R_SI; break;
|
||||
case 5: base = R_DI; break;
|
||||
case 6: base = R_BP; break;
|
||||
case 7: base = R_BX; break;
|
||||
}
|
||||
switch((m>>6)&3) {
|
||||
case 0: if(m==6) base = Fetch16(emu); break;
|
||||
case 1: base += Fetch8s(emu); break;
|
||||
case 2: base += Fetch16s(emu); break;
|
||||
// case 3 is C0..C7, already dealt with
|
||||
}
|
||||
return (reg32_t*)(base+offset);
|
||||
}
|
||||
}
|
||||
|
||||
static inline mmx_regs_t* GetEm(x86emu_t *emu, uint32_t v)
|
||||
{
|
||||
uint32_t m = v&0xC7; // filter Ed
|
||||
@@ -172,15 +199,26 @@ void Run0F(x86emu_t *emu);
|
||||
void Run660F(x86emu_t *emu);
|
||||
void Run66D9(x86emu_t *emu); // x87
|
||||
void Run6766(x86emu_t *emu);
|
||||
void RunGS(x86emu_t *emu);
|
||||
void RunFS(x86emu_t *emu);
|
||||
void RunLock(x86emu_t *emu);
|
||||
|
||||
void x86Syscall(x86emu_t *emu);
|
||||
void x86Int3(x86emu_t* emu);
|
||||
x86emu_t* x86emu_fork(x86emu_t* e);
|
||||
x86emu_t* x86emu_fork(x86emu_t* e, int forktype);
|
||||
|
||||
void PackFlags(x86emu_t* emu);
|
||||
void UnpackFlags(x86emu_t* emu);
|
||||
|
||||
uintptr_t GetSegmentBaseEmu(x86emu_t* emu, int seg);
|
||||
#define GetGSBaseEmu(emu) GetSegmentBaseEmu(emu, _GS)
|
||||
#define GetFSBaseEmu(emu) GetSegmentBaseEmu(emu, _FS)
|
||||
#define GetESBaseEmu(emu) GetSegmentBaseEmu(emu, _ES)
|
||||
|
||||
const char* GetNativeName(void* p);
|
||||
|
||||
#ifdef HAVE_TRACE
|
||||
void PrintTrace(x86emu_t* emu, uintptr_t ip, int dynarec);
|
||||
#endif
|
||||
|
||||
#endif //__X86RUN_PRIVATE_H_
|
||||
Executable
+668
@@ -0,0 +1,668 @@
|
||||
#define _GNU_SOURCE /* See feature_test_macros(7) */
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/syscall.h> /* For SYS_xxx definitions */
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <asm/stat.h>
|
||||
#include <errno.h>
|
||||
#include <sched.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/utsname.h>
|
||||
#ifndef __NR_socketcall
|
||||
#include <linux/net.h>
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#include <sys/resource.h>
|
||||
#include <poll.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86stack.h"
|
||||
#include "x86emu.h"
|
||||
#include "x86run.h"
|
||||
#include "x86emu_private.h"
|
||||
#include "x86run_private.h"
|
||||
#include "x86primop.h"
|
||||
#include "x86trace.h"
|
||||
#include "myalign.h"
|
||||
#include "box86context.h"
|
||||
#include "callback.h"
|
||||
#include "signals.h"
|
||||
#include "x86tls.h"
|
||||
|
||||
#ifndef __NR_socketcall
|
||||
#ifndef SYS_RECVMMSG
|
||||
#define SYS_RECVMMSG 19
|
||||
#endif
|
||||
#ifndef SYS_SENDMMSG
|
||||
#define SYS_SENDMMSG 20
|
||||
#endif
|
||||
int32_t my_accept4(x86emu_t* emu, int32_t fd, void* a, void* l, int32_t flags); // not always present, so used wrapped version
|
||||
#ifdef SYS_RECVMMSG
|
||||
int32_t my_recvmmsg(x86emu_t* emu, int32_t fd, void* msgvec, uint32_t vlen, uint32_t flags, void* timeout);
|
||||
int32_t my___sendmmsg(x86emu_t* emu, int32_t fd, void* msgvec, uint32_t vlen, uint32_t flags);
|
||||
#endif
|
||||
#endif
|
||||
typedef struct x86_sigaction_s x86_sigaction_t;
|
||||
|
||||
|
||||
int32_t my_getrandom(x86emu_t* emu, void* buf, uint32_t buflen, uint32_t flags);
|
||||
int of_convert(int flag);
|
||||
int32_t my_open(x86emu_t* emu, void* pathname, int32_t flags, uint32_t mode);
|
||||
|
||||
#ifndef NOALIGN
|
||||
int my_epoll_create(x86emu_t* emu, int size);
|
||||
int my_epoll_create1(x86emu_t* emu, int flags);
|
||||
int32_t my_epoll_ctl(x86emu_t* emu, int32_t epfd, int32_t op, int32_t fd, void* event);
|
||||
int32_t my_epoll_wait(x86emu_t* emu, int32_t epfd, void* events, int32_t maxevents, int32_t timeout);
|
||||
#endif
|
||||
int my_sigaction(x86emu_t* emu, int signum, const x86_sigaction_t *act, x86_sigaction_t *oldact);
|
||||
|
||||
// cannot include <fcntl.h>, it conflict with some asm includes...
|
||||
#ifndef O_NONBLOCK
|
||||
#define O_NONBLOCK 04000
|
||||
#endif
|
||||
#undef fcntl
|
||||
int fcntl(int fd, int cmd, ... /* arg */ );
|
||||
|
||||
// Syscall table for x86 can be found here: http://shell-storm.org/shellcode/files/syscalls.html
|
||||
typedef struct scwrap_s {
|
||||
int x86s;
|
||||
int nats;
|
||||
int nbpars;
|
||||
} scwrap_t;
|
||||
|
||||
scwrap_t syscallwrap[] = {
|
||||
{ 2, __NR_fork, 1 }, // should wrap this one, because of the struct pt_regs (the only arg)?
|
||||
//{ 3, __NR_read, 3 }, // wrapped so SA_RESTART can be handled by libc
|
||||
//{ 4, __NR_write, 3 }, // same
|
||||
//{ 5, __NR_open, 3 }, // flags need transformation
|
||||
//{ 6, __NR_close, 1 }, // wrapped so SA_RESTART can be handled by libc
|
||||
#ifdef __NR_waitpid
|
||||
{ 7, __NR_waitpid, 3 },
|
||||
#endif
|
||||
{ 10, __NR_unlink, 1 },
|
||||
{ 12, __NR_chdir, 1 },
|
||||
#ifdef __NR_time
|
||||
{ 13, __NR_time, 1 },
|
||||
#endif
|
||||
{ 15, __NR_chmod, 2 },
|
||||
{ 19, __NR_lseek, 3 },
|
||||
{ 20, __NR_getpid, 0 },
|
||||
{ 24, __NR_getuid, 0 },
|
||||
{ 33, __NR_access, 2 },
|
||||
{ 37, __NR_kill, 2 },
|
||||
{ 38, __NR_rename, 2 },
|
||||
{ 39, __NR_mkdir, 2 },
|
||||
{ 40, __NR_rmdir, 1 },
|
||||
{ 41, __NR_dup, 1 },
|
||||
{ 42, __NR_pipe, 1 },
|
||||
{ 45, __NR_brk, 1 },
|
||||
{ 47, __NR_getgid, 0 },
|
||||
{ 49, __NR_geteuid, 0 },
|
||||
{ 50, __NR_getegid, 0 },
|
||||
{ 54, __NR_ioctl, 3 }, // should be wrapped to allow SA_RESTART handling by libc, but syscall is only 3 arguments, ioctl can be 5
|
||||
//{ 55, __NR_fcntl, 3 }, // wrapped to allow filter of F_SETFD
|
||||
{ 60, __NR_umask, 1 },
|
||||
{ 63, __NR_dup2, 2 },
|
||||
{ 64, __NR_getppid, 0 },
|
||||
{ 66, __NR_setsid, 0 },
|
||||
{ 75, __NR_setrlimit, 2 },
|
||||
#ifdef __NR_getrlimit
|
||||
{ 76, __NR_getrlimit, 2 },
|
||||
#endif
|
||||
{ 77, __NR_getrusage, 2 },
|
||||
{ 78, __NR_gettimeofday, 2 },
|
||||
{ 83, __NR_symlink, 2 },
|
||||
#ifdef __NR_select
|
||||
{ 82, __NR_select, 5 },
|
||||
#endif
|
||||
{ 85, __NR_readlink, 3 },
|
||||
{ 91, __NR_munmap, 2 },
|
||||
{ 94, __NR_fchmod, 2 },
|
||||
{ 99, __NR_statfs, 2 },
|
||||
#ifdef __NR_socketcall
|
||||
{ 102, __NR_socketcall, 2 },
|
||||
#endif
|
||||
{ 104, __NR_setitimer, 3 },
|
||||
{ 105, __NR_getitimer, 2 },
|
||||
#ifdef __NR_newstat
|
||||
{ 106, __NR_newstat, 2 },
|
||||
#else
|
||||
{ 106, __NR_stat, 2 },
|
||||
#endif
|
||||
#ifdef __NR_newlstat
|
||||
{ 107, __NR_newlstat, 2 },
|
||||
#else
|
||||
{ 107, __NR_lstat, 2 },
|
||||
#endif
|
||||
#ifdef __NR_newfstat
|
||||
{ 108, __NR_newfstat, 2 },
|
||||
#else
|
||||
{ 108, __NR_fstat, 2 },
|
||||
#endif
|
||||
#ifdef __NR_olduname
|
||||
{ 109, __NR_olduname, 1 },
|
||||
#endif
|
||||
#ifdef __NR_iopl
|
||||
{ 110, __NR_iopl, 1 },
|
||||
#endif
|
||||
{ 114, __NR_wait4, 4 }, //TODO: check struct rusage alignment
|
||||
#ifdef __NR_ipc
|
||||
{ 117, __NR_ipc, 6 },
|
||||
#endif
|
||||
//{ 119, __NR_sigreturn, 0},
|
||||
//{ 120, __NR_clone, 5 }, // need works
|
||||
//{ 122, __NR_uname, 1 },
|
||||
//{ 123, __NR_modify_ldt },
|
||||
{ 125, __NR_mprotect, 3 },
|
||||
{ 136, __NR_personality, 1 },
|
||||
{ 140, __NR__llseek, 5 },
|
||||
{ 141, __NR_getdents, 3 },
|
||||
{ 142, __NR__newselect, 5 },
|
||||
{ 143, __NR_flock, 2 },
|
||||
{ 144, __NR_msync, 3 },
|
||||
{ 145, __NR_readv, 3 },
|
||||
{ 146, __NR_writev, 3 },
|
||||
{ 148, __NR_fdatasync, 1 },
|
||||
{ 149, __NR__sysctl, 1 }, // need wrapping?
|
||||
{ 156, __NR_sched_setscheduler, 3 },
|
||||
{ 157, __NR_sched_getscheduler, 1 },
|
||||
{ 158, __NR_sched_yield, 0 },
|
||||
{ 162, __NR_nanosleep, 2 },
|
||||
{ 164, __NR_setresuid, 3 },
|
||||
//{ 168, __NR_poll, 3 }, // wrapped to allow SA_RESTART wrapping by libc
|
||||
{ 172, __NR_prctl, 5 },
|
||||
//{ 173, __NR_rt_sigreturn, 0 },
|
||||
{ 175, __NR_rt_sigprocmask, 4 },
|
||||
{ 179, __NR_rt_sigsuspend, 2 },
|
||||
{ 183, __NR_getcwd, 2 },
|
||||
{ 186, __NR_sigaltstack, 2 }, // neeed wrap or something?
|
||||
{ 191, __NR_ugetrlimit, 2 },
|
||||
{ 192, __NR_mmap2, 6},
|
||||
//{ 195, __NR_stat64, 2 }, // need proprer wrap because of structure size change
|
||||
//{ 196, __NR_lstat64, 2 }, // need proprer wrap because of structure size change
|
||||
//{ 197, __NR_fstat64, 2 }, // need proprer wrap because of structure size change
|
||||
{ 199, __NR_getuid32, 0 },
|
||||
{ 200, __NR_getgid32, 0 },
|
||||
{ 201, __NR_geteuid32, 0 },
|
||||
{ 202, __NR_getegid32, 0 },
|
||||
{ 208, __NR_setresuid32, 3 },
|
||||
{ 220, __NR_getdents64, 3 },
|
||||
//{ 221, __NR_fcntl64, 3 },
|
||||
{ 224, __NR_gettid, 0 },
|
||||
{ 240, __NR_futex, 6 },
|
||||
{ 252, __NR_exit_group, 1 },
|
||||
#ifdef NOALIGN
|
||||
{ 254, __NR_epoll_create, 1 },
|
||||
{ 255, __NR_epoll_ctl, 4 },
|
||||
{ 256, __NR_epoll_wait, 4 },
|
||||
#endif
|
||||
{ 265, __NR_clock_gettime, 2 },
|
||||
{ 266, __NR_clock_getres, 2 },
|
||||
//{ 270, __NR_tgkill, 3 },
|
||||
{ 271, __NR_utimes, 2 },
|
||||
{ 311, __NR_set_robust_list, 2 },
|
||||
{ 312, __NR_get_robust_list, 4 },
|
||||
#ifdef NOALIGN
|
||||
{ 329, __NR_epoll_create1, 1 },
|
||||
#endif
|
||||
#ifdef __NR_getrandom
|
||||
{ 355, __NR_getrandom, 3 },
|
||||
#endif
|
||||
};
|
||||
|
||||
struct mmap_arg_struct {
|
||||
unsigned long addr;
|
||||
unsigned long len;
|
||||
unsigned long prot;
|
||||
unsigned long flags;
|
||||
unsigned long fd;
|
||||
unsigned long offset;
|
||||
};
|
||||
|
||||
#undef st_atime
|
||||
#undef st_ctime
|
||||
#undef st_mtime
|
||||
|
||||
struct x86_pt_regs {
|
||||
long ebx;
|
||||
long ecx;
|
||||
long edx;
|
||||
long esi;
|
||||
long edi;
|
||||
long ebp;
|
||||
long eax;
|
||||
int xds;
|
||||
int xes;
|
||||
int xfs;
|
||||
int xgs;
|
||||
long orig_eax;
|
||||
long eip;
|
||||
int xcs;
|
||||
long eflags;
|
||||
long esp;
|
||||
int xss;
|
||||
};
|
||||
|
||||
#ifndef __NR_olduname
|
||||
struct oldold_utsname {
|
||||
char sysname[9];
|
||||
char nodename[9];
|
||||
char release[9];
|
||||
char version[9];
|
||||
char machine[9];
|
||||
};
|
||||
#endif
|
||||
struct old_utsname {
|
||||
char sysname[65];
|
||||
char nodename[65];
|
||||
char release[65];
|
||||
char version[65];
|
||||
char machine[65];
|
||||
};
|
||||
|
||||
struct i386_user_desc {
|
||||
unsigned int entry_number;
|
||||
unsigned long base_addr;
|
||||
unsigned int limit;
|
||||
unsigned int seg_32bit:1;
|
||||
unsigned int contents:2;
|
||||
unsigned int read_exec_only:1;
|
||||
unsigned int limit_in_pages:1;
|
||||
unsigned int seg_not_present:1;
|
||||
unsigned int useable:1;
|
||||
};
|
||||
|
||||
int clone_fn(void* arg)
|
||||
{
|
||||
x86emu_t *emu = (x86emu_t*)arg;
|
||||
R_EAX = 0;
|
||||
DynaRun(emu);
|
||||
int ret = R_EAX;
|
||||
FreeX86Emu(&emu);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void EXPORT x86Syscall(x86emu_t *emu)
|
||||
{
|
||||
RESET_FLAGS(emu);
|
||||
uint32_t s = R_EAX;
|
||||
printf_log(LOG_DEBUG, "%p: Calling syscall 0x%02X (%d) %p %p %p %p %p", (void*)R_EIP, s, s, (void*)R_EBX, (void*)R_ECX, (void*)R_EDX, (void*)R_ESI, (void*)R_EDI);
|
||||
// check wrapper first
|
||||
int cnt = sizeof(syscallwrap) / sizeof(scwrap_t);
|
||||
for (int i=0; i<cnt; i++) {
|
||||
if(syscallwrap[i].x86s == s) {
|
||||
int sc = syscallwrap[i].nats;
|
||||
switch(syscallwrap[i].nbpars) {
|
||||
case 0: *(int32_t*)&R_EAX = syscall(sc); break;
|
||||
case 1: *(int32_t*)&R_EAX = syscall(sc, R_EBX); break;
|
||||
case 2: if(s==33) {printf_log(LOG_DUMP, " => sys_access(\"%s\", %d)\n", (char*)R_EBX, R_ECX);}; *(int32_t*)&R_EAX = syscall(sc, R_EBX, R_ECX); break;
|
||||
case 3: *(int32_t*)&R_EAX = syscall(sc, R_EBX, R_ECX, R_EDX); break;
|
||||
case 4: *(int32_t*)&R_EAX = syscall(sc, R_EBX, R_ECX, R_EDX, R_ESI); break;
|
||||
case 5: *(int32_t*)&R_EAX = syscall(sc, R_EBX, R_ECX, R_EDX, R_ESI, R_EDI); break;
|
||||
case 6: *(int32_t*)&R_EAX = syscall(sc, R_EBX, R_ECX, R_EDX, R_ESI, R_EDI, R_EBP); break;
|
||||
default:
|
||||
printf_log(LOG_NONE, "ERROR, Unimplemented syscall wrapper (%d, %d)\n", s, syscallwrap[i].nbpars);
|
||||
emu->quit = 1;
|
||||
return;
|
||||
}
|
||||
printf_log(LOG_DEBUG, " => 0x%x\n", R_EAX);
|
||||
return;
|
||||
}
|
||||
}
|
||||
switch (s) {
|
||||
case 1: // sys_exit
|
||||
emu->quit = 1;
|
||||
emu->exit = 1;
|
||||
R_EAX = R_EBX; // faking the syscall here, we don't want to really terminate the program now
|
||||
break;
|
||||
case 3: // sys_read
|
||||
R_EAX = (uint32_t)read((int)R_EBX, (void*)R_ECX, (size_t)R_EDX);
|
||||
break;
|
||||
case 4: // sys_write
|
||||
R_EAX = (uint32_t)write((int)R_EBX, (void*)R_ECX, (size_t)R_EDX);
|
||||
break;
|
||||
case 5: // sys_open
|
||||
if(s==5) {printf_log(LOG_DEBUG, " => sys_open(\"%s\", %d, %d)", (char*)R_EBX, of_convert(R_ECX), R_EDX);};
|
||||
//R_EAX = (uint32_t)open((void*)R_EBX, of_convert(R_ECX), R_EDX);
|
||||
R_EAX = (uint32_t)my_open(emu, (void*)R_EBX, of_convert(R_ECX), R_EDX);
|
||||
break;
|
||||
case 6: // sys_close
|
||||
R_EAX = (uint32_t)close((int)R_EBX);
|
||||
break;
|
||||
#ifndef __NR_waitpid
|
||||
case 7: //sys_waitpid
|
||||
R_EAX = waitpid((pid_t)R_EBX, (int*)R_ECX, (int)R_EDX);
|
||||
break;
|
||||
#endif
|
||||
case 11: // sys_execve
|
||||
{
|
||||
char* prog = (char*)R_EBX;
|
||||
char** argv = (char**)R_ECX;
|
||||
char** envv = (char**)R_EDX;
|
||||
printf_log(LOG_DUMP, " => sys_execve(\"%s\", %p(\"%s\", \"%s\", \"%s\"...), %p)\n", prog, argv, (argv && argv[0])?argv[0]:"nil", (argv && argv[0] && argv[1])?argv[1]:"nil", (argv && argv[0] && argv[1] && argv[2])?argv[2]:"nil", envv);
|
||||
R_EAX = execve((const char*)R_EBX, (void*)R_ECX, (void*)R_EDX);
|
||||
}
|
||||
break;
|
||||
#ifndef __NR_time
|
||||
case 13: // sys_time (it's deprecated and remove on ARM EABI it seems)
|
||||
R_EAX = time(NULL);
|
||||
break;
|
||||
#endif
|
||||
case 54: // sys_ioctl
|
||||
R_EAX = (uint32_t)ioctl((int)R_EBX, R_ECX, R_EDX, R_ESI, R_EDI);
|
||||
break;
|
||||
case 55: // sys_fcntl
|
||||
if(R_ECX==4) {
|
||||
// filter out O_NONBLOCK so old stacally linked games that access X11 don't get EAGAIN error sometimes
|
||||
int tmp = of_convert((int)R_EDX)&(~O_NONBLOCK);
|
||||
if(R_EDX==0xFFFFF7FF) {
|
||||
// special case for ~O_NONBLOCK...
|
||||
int flags = fcntl(R_EBX, 3);
|
||||
tmp = flags&~O_NONBLOCK;
|
||||
}
|
||||
R_EAX = (uint32_t)fcntl((int)R_EBX, (int)R_ECX, tmp);
|
||||
} else
|
||||
R_EAX = (uint32_t)fcntl((int)R_EBX, (int)R_ECX, R_EDX);
|
||||
break;
|
||||
#ifndef __NR_getrlimit
|
||||
case 76: // sys_getrlimit... this is the old version, using the new one. Maybe some tranform is needed?
|
||||
R_EAX = getrlimit(R_EBX, (void*)R_ECX);
|
||||
break;
|
||||
#endif
|
||||
#ifndef __NR_select
|
||||
case 82: // select
|
||||
R_EAX = select(R_EBX, (fd_set*)R_ECX, (fd_set*)R_EDX, (fd_set*)R_ESI, (struct timeval*)R_EDI);
|
||||
break;
|
||||
#endif
|
||||
case 90: // old_mmap
|
||||
{
|
||||
struct mmap_arg_struct *st = (struct mmap_arg_struct*)R_EBX;
|
||||
R_EAX = (uintptr_t)mmap((void*)st->addr, st->len, st->prot, st->flags, st->fd, st->offset);
|
||||
}
|
||||
break;
|
||||
#ifndef __NR_socketcall
|
||||
case 102: {
|
||||
unsigned long *args = (unsigned long *)R_ECX;
|
||||
// need to do all call "by hand"
|
||||
switch(R_EBX) {
|
||||
case SYS_SOCKET: R_EAX = socket(args[0], args[1], args[2]); break;
|
||||
case SYS_BIND: R_EAX = bind(args[0], (void*)args[1], args[2]); break;
|
||||
case SYS_CONNECT: R_EAX = connect(args[0], (void*)args[1], args[2]); break;
|
||||
case SYS_LISTEN: R_EAX = listen(args[0], args[1]); break;
|
||||
case SYS_ACCEPT: R_EAX = accept(args[0], (void*)args[1], (void*)args[2]); break;
|
||||
case SYS_GETSOCKNAME: R_EAX = getsockname(args[0], (void*)args[1], (void*)args[2]); break;
|
||||
case SYS_GETPEERNAME: R_EAX = getpeername(args[0], (void*)args[1], (void*)args[2]); break;
|
||||
case SYS_SOCKETPAIR: R_EAX = socketpair(args[0], args[1], args[2], (int*)args[3]); break;
|
||||
case SYS_SEND: R_EAX = send(args[0], (void*)args[1], args[2], args[3]); break;
|
||||
case SYS_RECV: R_EAX = recv(args[0], (void*)args[1], args[2], args[3]); break;
|
||||
case SYS_SENDTO: R_EAX = sendto(args[0], (void*)args[1], args[2], args[3], (void*)args[4], args[5]); break;
|
||||
case SYS_RECVFROM: R_EAX = recvfrom(args[0], (void*)args[1], args[2], args[3], (void*)args[4], (void*)args[5]); break;
|
||||
case SYS_SHUTDOWN: R_EAX = shutdown(args[0], args[1]); break;
|
||||
case SYS_SETSOCKOPT: R_EAX = setsockopt(args[0], args[1], args[2], (void*)args[3], args[4]); break;
|
||||
case SYS_GETSOCKOPT: R_EAX = getsockopt(args[0], args[1], args[2], (void*)args[3], (void*)args[4]); break;
|
||||
case SYS_SENDMSG: R_EAX = sendmsg(args[0], (void*)args[1], args[2]); break;
|
||||
case SYS_RECVMSG: R_EAX = recvmsg(args[0], (void*)args[1], args[2]); break;
|
||||
case SYS_ACCEPT4: R_EAX = my_accept4(emu, args[0], (void*)args[1], (void*)args[2], args[3]); break;
|
||||
#ifdef SYS_RECVMMSG
|
||||
case SYS_RECVMMSG: R_EAX = my_recvmmsg(emu, args[0], (void*)args[1], args[2], args[3], (void*)args[4]); break;
|
||||
case SYS_SENDMMSG: R_EAX = my___sendmmsg(emu, args[0], (void*)args[1], args[2], args[3]); break;
|
||||
#endif
|
||||
default:
|
||||
printf_log(LOG_DEBUG, "BOX86 Error on Syscall 102: Unknown Soket command %d\n", R_EBX);
|
||||
R_EAX = -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifndef __NR_olduname
|
||||
case 109: // olduname
|
||||
{
|
||||
struct utsname un;
|
||||
R_EAX = uname(&un);
|
||||
if(!R_EAX) {
|
||||
struct oldold_utsname *old = (struct oldold_utsname*)R_EBX;
|
||||
memcpy(old->sysname, un.sysname, 9);
|
||||
memcpy(old->nodename, un.nodename, 9);
|
||||
memcpy(old->release, un.release, 9);
|
||||
memcpy(old->version, un.version, 9);
|
||||
strcpy(old->machine, "i686");
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifndef __NR_iopl
|
||||
case 110: // iopl
|
||||
R_EAX = 0; // only on x86, so return 0...
|
||||
break;
|
||||
#endif
|
||||
case 119: // sys_sigreturn
|
||||
emu->quit = 1; // we should be inside a DynaCall in a sigaction callback....
|
||||
break;
|
||||
case 120: // clone
|
||||
{
|
||||
//struct x86_pt_regs *regs = (struct x86_pt_regs *)R_EDI;
|
||||
// lets duplicate the emu
|
||||
void* stack_base = (void*)R_ECX;
|
||||
int stack_size = 0;
|
||||
if(!R_ECX) {
|
||||
// allocate a new stack...
|
||||
stack_size = 1024*1024;
|
||||
stack_base = malloc(stack_size); // why not 1M... (normal operation do copy on write, simpler to just copy)
|
||||
// copy value from old stack to new stack
|
||||
int size_to_copy = (uintptr_t)emu->init_stack + emu->size_stack - (R_ESP);
|
||||
memcpy(stack_base-size_to_copy, (void*)R_ESP, size_to_copy);
|
||||
}
|
||||
x86emu_t * newemu = NewX86Emu(emu->context, R_EIP, (uintptr_t)stack_base, stack_size, (R_ECX)?0:1);
|
||||
SetupX86Emu(newemu);
|
||||
CloneEmu(newemu, emu);
|
||||
SetESP(newemu, (uintptr_t)stack_base);
|
||||
// setup registers
|
||||
/*if(regs) {
|
||||
SetEAX(newemu, regs->eax);
|
||||
SetEBX(newemu, regs->ebx);
|
||||
SetECX(newemu, regs->ecx);
|
||||
SetEDX(newemu, regs->edx);
|
||||
SetEDI(newemu, regs->edi);
|
||||
SetESI(newemu, regs->esi);
|
||||
SetEBP(newemu, regs->ebp);
|
||||
SetESP(newemu, (uintptr_t)stack_base - size_to_copy);
|
||||
}
|
||||
SetESP(newemu, (uintptr_t)stack_base - size_to_copy);*/
|
||||
void* mystack = (R_EBX&CLONE_VM)?malloc(1024*1024):NULL; // stack for own process... memory leak, but no practical way to remove it
|
||||
int ret = clone(clone_fn, (void*)((R_EBX&CLONE_VM)?((uintptr_t)mystack+1024*1024):0), R_EBX, newemu, R_ESI, R_EDI, R_EBP);
|
||||
//int r = syscall(__NR_clone, R_EBX, (R_EBX&CLONE_VM)?((uintptr_t)mystack):0, R_EDX, R_ESI, NULL); // cannot use that syscall in C: how to setup the stack?!
|
||||
R_EAX = ret;
|
||||
}
|
||||
break;
|
||||
case 122: // uname
|
||||
{
|
||||
struct utsname un;
|
||||
R_EAX = uname(&un);
|
||||
if(!R_EAX) {
|
||||
struct old_utsname *old = (struct old_utsname*)R_EBX;
|
||||
memcpy(old->sysname, un.sysname, 65);
|
||||
memcpy(old->nodename, un.nodename, 65);
|
||||
memcpy(old->release, un.release, 65);
|
||||
memcpy(old->version, un.version, 65);
|
||||
strcpy(old->machine, "i686");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 123: // SYS_modify_ldt
|
||||
R_EAX = my_modify_ldt(emu, R_EBX, (thread_area_t*)R_ECX, R_EDX);
|
||||
break;
|
||||
case 168: // sys_poll
|
||||
R_EAX = (uint32_t)poll((void*)R_EBX, R_ECX, (int)R_EDX);
|
||||
break;
|
||||
case 173: // sys_rt_sigreturn
|
||||
emu->quit = 1; // we should be inside a DynaCall in a sigaction callback....
|
||||
break;
|
||||
case 174: // sys_rt_sigaction
|
||||
//printf_log(LOG_NONE, "Warning, Ignoring sys_rt_sigaction(0x%02X, %p, %p)\n", R_EBX, (void*)R_ECX, (void*)R_EDX);
|
||||
R_EAX = my_syscall_sigaction(emu, R_EBX, (void*)R_ECX, (void*)R_EDX, R_ESI);
|
||||
break;
|
||||
case 190: // vfork
|
||||
{
|
||||
int r = vfork();
|
||||
R_EAX = r;
|
||||
}
|
||||
break;
|
||||
case 195: // stat64
|
||||
{
|
||||
struct stat64 st;
|
||||
unsigned int r = syscall(__NR_stat64, R_EBX, &st);
|
||||
UnalignStat64(&st, (void*)R_ECX);
|
||||
|
||||
R_EAX = r;
|
||||
}
|
||||
break;
|
||||
case 196: // lstat64
|
||||
{
|
||||
struct stat64 st;
|
||||
unsigned int r = syscall(__NR_lstat64, R_EBX, &st);
|
||||
UnalignStat64(&st, (void*)R_ECX);
|
||||
|
||||
R_EAX = r;
|
||||
}
|
||||
break;
|
||||
case 197: // fstat64
|
||||
{
|
||||
struct stat64 st;
|
||||
unsigned int r = syscall(__NR_fstat64, R_EBX, &st);
|
||||
UnalignStat64(&st, (void*)R_ECX);
|
||||
|
||||
R_EAX = r;
|
||||
}
|
||||
break;
|
||||
case 221: // sys_fcntl64
|
||||
if(R_ECX==4) {
|
||||
int tmp = of_convert((int)R_EDX);
|
||||
R_EAX = (uint32_t)fcntl((int)R_EBX, R_ECX, tmp);
|
||||
} else
|
||||
R_EAX = (uint32_t)fcntl((int)R_EBX, (int)R_ECX, R_EDX);
|
||||
break;
|
||||
case 243: // set_thread_area
|
||||
R_EAX = my_set_thread_area((thread_area_t*)R_EBX);
|
||||
break;
|
||||
#ifndef NOALIGN
|
||||
case 254: // epoll_create
|
||||
R_EAX = my_epoll_create(emu, (int)R_EBX);
|
||||
break;
|
||||
case 255: // epoll_ctl
|
||||
R_EAX = my_epoll_ctl(emu, (int)R_EBX, (int)R_ECX, (int)R_EDX, (void*)R_ESI);
|
||||
break;
|
||||
case 256: // epoll_wait
|
||||
R_EAX = my_epoll_wait(emu, (int)R_EBX, (void*)R_ECX, (int)R_EDX, (int)R_ESI);
|
||||
break;
|
||||
#endif
|
||||
case 270: // tgkill
|
||||
R_EAX = syscall(__NR_tgkill, R_EBX, R_ECX, R_EDX);
|
||||
break;
|
||||
#ifndef NOALIGN
|
||||
case 329: // epoll_create1
|
||||
R_EAX = my_epoll_create1(emu, of_convert(R_EBX));
|
||||
break;
|
||||
#endif
|
||||
#ifndef __NR_getrandom
|
||||
case 355: // getrandom
|
||||
R_EAX = my_getrandom(emu, (void*)R_EBX, R_ECX, R_EDX);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
printf_log(LOG_INFO, "Error: Unsupported Syscall 0x%02Xh (%d)\n", s, s);
|
||||
emu->quit = 1;
|
||||
emu->error |= ERR_UNIMPL;
|
||||
return;
|
||||
}
|
||||
printf_log(LOG_DEBUG, " => 0x%x\n", R_EAX);
|
||||
}
|
||||
|
||||
#define stack(n) (R_ESP+4+n)
|
||||
#define i32(n) *(int32_t*)stack(n)
|
||||
#define u32(n) *(uint32_t*)stack(n)
|
||||
#define p(n) *(void**)stack(n)
|
||||
|
||||
uint32_t EXPORT my_syscall(x86emu_t *emu)
|
||||
{
|
||||
uint32_t s = u32(0);
|
||||
printf_log(LOG_DUMP, "%p: Calling libc syscall 0x%02X (%d) %p %p %p %p %p\n", (void*)R_EIP, s, s, (void*)u32(4), (void*)u32(8), (void*)u32(12), (void*)u32(16), (void*)u32(20));
|
||||
// check wrapper first
|
||||
int cnt = sizeof(syscallwrap) / sizeof(scwrap_t);
|
||||
for (int i=0; i<cnt; i++) {
|
||||
if(syscallwrap[i].x86s == s) {
|
||||
int sc = syscallwrap[i].nats;
|
||||
switch(syscallwrap[i].nbpars) {
|
||||
case 0: return syscall(sc);
|
||||
case 1: return syscall(sc, u32(4));
|
||||
case 2: return syscall(sc, u32(4), u32(8));
|
||||
case 3: return syscall(sc, u32(4), u32(8), u32(12));
|
||||
case 4: return syscall(sc, u32(4), u32(8), u32(12), u32(16));
|
||||
case 5: return syscall(sc, u32(4), u32(8), u32(12), u32(16), u32(20));
|
||||
case 6: return syscall(sc, u32(4), u32(8), u32(12), u32(16), u32(20), u32(24));
|
||||
default:
|
||||
printf_log(LOG_NONE, "ERROR, Unimplemented syscall wrapper (%d, %d)\n", s, syscallwrap[i].nbpars);
|
||||
emu->quit = 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
switch (s) {
|
||||
case 1: // __NR_exit
|
||||
emu->quit = 1;
|
||||
return u32(4); // faking the syscall here, we don't want to really terminate the program now
|
||||
case 3: // sys_read
|
||||
return (uint32_t)read(i32(4), p(8), u32(12));
|
||||
case 4: // sys_write
|
||||
return (uint32_t)write(i32(4), p(8), u32(12));
|
||||
case 5: // sys_open
|
||||
return my_open(emu, p(4), of_convert(u32(8)), u32(12));
|
||||
case 6: // sys_close
|
||||
return (uint32_t)close(i32(4));
|
||||
case 123: // SYS_modify_ldt
|
||||
return my_modify_ldt(emu, i32(4), (thread_area_t*)p(8), i32(12));
|
||||
case 174: // sys_rt_sigaction
|
||||
return (uint32_t)my_sigaction(emu, i32(4), (x86_sigaction_t*)p(8), (x86_sigaction_t*)p(12));
|
||||
case 243: // set_thread_area
|
||||
return my_set_thread_area((thread_area_t*)p(4));
|
||||
#ifndef NOALIGN
|
||||
case 254: // epoll_create
|
||||
return my_epoll_create(emu, i32(4));
|
||||
case 255: // epoll_ctl
|
||||
return my_epoll_ctl(emu, i32(4), i32(8), i32(12), p(16));
|
||||
case 256: // epoll_wait
|
||||
return my_epoll_wait(emu, i32(4), p(8), i32(12), i32(16));
|
||||
#endif
|
||||
case 270: //_NR_tgkill
|
||||
/*if(!u32(12))*/ {
|
||||
//printf("tgkill(%u, %u, %u) => ", u32(4), u32(8), u32(12));
|
||||
uint32_t ret = (uint32_t)syscall(__NR_tgkill, u32(4), u32(8), u32(12));
|
||||
//printf("%u (errno=%d)\n", ret, (ret==(uint32_t)-1)?errno:0);
|
||||
return ret;
|
||||
}/* else {
|
||||
printf_log(LOG_INFO, "Warning: ignoring libc Syscall tgkill (%u, %u, %u)\n", u32(4), u32(8), u32(12));
|
||||
}*/
|
||||
return 0;
|
||||
#ifndef NOALIGN
|
||||
case 329: // epoll_create1
|
||||
return my_epoll_create1(emu, of_convert(i32(4)));
|
||||
#endif
|
||||
#ifndef __NR_getrandom
|
||||
case 355: // getrandom
|
||||
return (uint32_t)my_getrandom(emu, p(4), u32(8), u32(12));
|
||||
#endif
|
||||
default:
|
||||
printf_log(LOG_INFO, "Error: Unsupported libc Syscall 0x%02X (%d)\n", s, s);
|
||||
emu->quit = 1;
|
||||
emu->error |= ERR_UNIMPL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Executable
+209
@@ -0,0 +1,209 @@
|
||||
// Handling of TLS calls, include x86 specifi set_thread_area
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86context.h"
|
||||
#include "x86emu.h"
|
||||
#include "x86tls.h"
|
||||
#include "elfloader.h"
|
||||
|
||||
typedef struct thread_area_s
|
||||
{
|
||||
int entry_number;
|
||||
uintptr_t base_addr;
|
||||
unsigned int limit;
|
||||
unsigned int seg_32bit:1;
|
||||
unsigned int contents:2;
|
||||
unsigned int read_exec_only:1;
|
||||
unsigned int limit_in_pages:1;
|
||||
unsigned int seg_not_present:1;
|
||||
unsigned int useable:1;
|
||||
} thread_area_t;
|
||||
|
||||
static pthread_once_t thread_key_once0 = PTHREAD_ONCE_INIT;
|
||||
static pthread_once_t thread_key_once1 = PTHREAD_ONCE_INIT;
|
||||
static pthread_once_t thread_key_once2 = PTHREAD_ONCE_INIT;
|
||||
|
||||
static void thread_key_alloc0() {
|
||||
pthread_key_create(&my_context->segtls[0].key, NULL);
|
||||
}
|
||||
static void thread_key_alloc1() {
|
||||
pthread_key_create(&my_context->segtls[1].key, NULL);
|
||||
}
|
||||
static void thread_key_alloc2() {
|
||||
pthread_key_create(&my_context->segtls[2].key, NULL);
|
||||
}
|
||||
|
||||
uint32_t my_set_thread_area(thread_area_t* td)
|
||||
{
|
||||
printf_log(LOG_DEBUG, "set_thread_area(%p[%d/base=%p/limit=%u/32bits:%u/%u/%u...])\n", td, td->entry_number, (void*)td->base_addr, td->limit_in_pages, td->seg_32bit, td->contents, td->read_exec_only);
|
||||
|
||||
int isempty = 0;
|
||||
// first, check if the "user_desc", here td, is "empty"
|
||||
if(td->read_exec_only==1 && td->seg_not_present==1)
|
||||
if( !td->base_addr
|
||||
&& !td->limit
|
||||
&& !td->seg_32bit
|
||||
&& !td->contents
|
||||
&& !td->limit_in_pages
|
||||
&& !td->useable)
|
||||
isempty = 1;
|
||||
int idx = td->entry_number;
|
||||
if(idx==-1) {
|
||||
// find a free one
|
||||
for (int i=0; i<3 && idx==-1; ++i)
|
||||
if(!my_context->segtls[i].present)
|
||||
idx=i;
|
||||
if(idx==-1) {
|
||||
errno = ESRCH;
|
||||
return (uint32_t)-1;
|
||||
}
|
||||
idx+=7;
|
||||
td->entry_number = idx;
|
||||
}
|
||||
if(isempty && (td->entry_number<7 || td->entry_number>7+2)) {
|
||||
errno = EINVAL;
|
||||
return (uint32_t)-1;
|
||||
}
|
||||
if(isempty) {
|
||||
memset(&my_context->segtls[td->entry_number-7], 0, sizeof(base_segment_t));
|
||||
return 0;
|
||||
}
|
||||
if((idx<7 || idx>7+2)) {
|
||||
errno = EINVAL;
|
||||
return (uint32_t)-1;
|
||||
}
|
||||
|
||||
my_context->segtls[idx-7].base = td->base_addr;
|
||||
my_context->segtls[idx-7].limit = td->limit;
|
||||
my_context->segtls[idx-7].present = 1;
|
||||
switch (idx-7) {
|
||||
case 0: pthread_once(&thread_key_once0, thread_key_alloc0); break;
|
||||
case 1: pthread_once(&thread_key_once1, thread_key_alloc1); break;
|
||||
case 2: pthread_once(&thread_key_once2, thread_key_alloc2); break;
|
||||
}
|
||||
|
||||
pthread_setspecific(my_context->segtls[idx-7].key, (void*)my_context->segtls[idx-7].base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t my_modify_ldt(x86emu_t* emu, int op, thread_area_t* td, int size)
|
||||
{
|
||||
printf_log(/*LOG_DEBUG*/LOG_INFO, "modify_ldt(0x%x, %p[0x%x/base=%p/limit=%u/32bits:%u/%u/%u...], %d)\n", op, td, td->entry_number, (void*)td->base_addr, td->limit_in_pages, td->seg_32bit, td->contents, td->read_exec_only, size);
|
||||
if(!td) {
|
||||
errno = EFAULT;
|
||||
return (uint32_t)-1;
|
||||
}
|
||||
if(op!=0x11) {
|
||||
errno = ENOSYS;
|
||||
return (uint32_t)-1;
|
||||
}
|
||||
if(!td->seg_32bit) {
|
||||
// not handling 16bits segments for now
|
||||
errno = EINVAL;
|
||||
return (uint32_t)-1;
|
||||
}
|
||||
|
||||
int idx = td->entry_number - 7;
|
||||
if(idx<0 || idx>2) {
|
||||
errno = EINVAL;
|
||||
return (uint32_t)-1;
|
||||
}
|
||||
|
||||
/*
|
||||
my_context->segtls[idx].base = td->base_addr;
|
||||
my_context->segtls[idx].limit = td->limit;
|
||||
pthread_setspecific(my_context->segtls[idx].key, (void*)my_context->segtls[idx].base);
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define POS_TLS 0x50
|
||||
|
||||
static tlsdatasize_t* setupTLSData(box86context_t* context)
|
||||
{
|
||||
// Setup the GS segment:
|
||||
int dtsize = context->elfsize*8;
|
||||
void *ptr = (char*)malloc(context->tlssize+4+POS_TLS+dtsize);
|
||||
memcpy(ptr, context->tlsdata, context->tlssize);
|
||||
tlsdatasize_t *data = (tlsdatasize_t*)calloc(1, sizeof(tlsdatasize_t));
|
||||
data->tlsdata = ptr;
|
||||
data->tlssize = context->tlssize;
|
||||
pthread_setspecific(context->tlskey, data);
|
||||
// copy canary...
|
||||
memset((void*)((uintptr_t)ptr+context->tlssize), 0, POS_TLS+dtsize); // set to 0 remining bytes
|
||||
memcpy((void*)((uintptr_t)ptr+context->tlssize+0x14), context->canary, 4); // put canary in place
|
||||
uintptr_t tlsptr = (uintptr_t)ptr+context->tlssize;
|
||||
memcpy((void*)((uintptr_t)ptr+context->tlssize+0x0), &tlsptr, 4);
|
||||
uintptr_t dtp = (uintptr_t)ptr+context->tlssize+POS_TLS;
|
||||
memcpy((void*)(tlsptr+0x4), &dtp, 4);
|
||||
if(dtsize) {
|
||||
for (int i=0; i<context->elfsize; ++i) {
|
||||
// set pointer
|
||||
dtp = (uintptr_t)ptr + (context->tlssize + GetTLSBase(context->elfs[i]));
|
||||
memcpy((void*)((uintptr_t)ptr+context->tlssize+POS_TLS+i*8), &dtp, 4);
|
||||
memcpy((void*)((uintptr_t)ptr+context->tlssize+POS_TLS+i*8+4), &i, 4); // index
|
||||
}
|
||||
}
|
||||
memcpy((void*)((uintptr_t)ptr+context->tlssize+0x10), &context->vsyscall, 4); // address of vsyscall
|
||||
return data;
|
||||
}
|
||||
|
||||
void* fillTLSData(box86context_t *context)
|
||||
{
|
||||
pthread_mutex_lock(&context->mutex_lock);
|
||||
tlsdatasize_t *data = setupTLSData(context);
|
||||
pthread_mutex_unlock(&context->mutex_lock);
|
||||
return data;
|
||||
}
|
||||
|
||||
void* resizeTLSData(box86context_t *context, void* oldptr)
|
||||
{
|
||||
pthread_mutex_lock(&context->mutex_lock);
|
||||
tlsdatasize_t* oldata = (tlsdatasize_t*)oldptr;
|
||||
tlsdatasize_t *data = setupTLSData(context);
|
||||
// copy the relevent old part, in case something changed
|
||||
memcpy((void*)((uintptr_t)data->tlsdata+(context->tlssize-oldata->tlssize)), oldata->tlsdata, oldata->tlssize);
|
||||
// all done, update new size, free old pointer and exit
|
||||
pthread_mutex_unlock(&context->mutex_lock);
|
||||
free_tlsdatasize(oldptr);
|
||||
return data;
|
||||
}
|
||||
|
||||
static void* GetSeg33Base()
|
||||
{
|
||||
tlsdatasize_t* ptr;
|
||||
if ((ptr = (tlsdatasize_t*)pthread_getspecific(my_context->tlskey)) == NULL) {
|
||||
ptr = (tlsdatasize_t*)fillTLSData(my_context);
|
||||
}
|
||||
if(ptr->tlssize != my_context->tlssize)
|
||||
ptr = (tlsdatasize_t*)resizeTLSData(my_context, ptr);
|
||||
return ptr->tlsdata+ptr->tlssize;
|
||||
}
|
||||
|
||||
void* GetSegmentBase(uint32_t desc)
|
||||
{
|
||||
if(!desc) {
|
||||
printf_log(LOG_NONE, "Warning, accessing segment NULL\n");
|
||||
return NULL;
|
||||
}
|
||||
int base = desc>>3;
|
||||
if(base==0xe || base==0xf)
|
||||
return NULL; // regular value...
|
||||
if(base==0x6)
|
||||
return GetSeg33Base();
|
||||
|
||||
if(base>6 && base<10 && my_context->segtls[base-7].present) {
|
||||
void* ptr = pthread_getspecific(my_context->segtls[base-7].key);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
printf_log(LOG_NONE, "Warning, accessing segment unknown 0x%x or unset\n", desc);
|
||||
return NULL;
|
||||
}
|
||||
Loaded 100 of 425 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user