mirror of
https://github.com/ptitSeb/box86.git
synced 2026-11-09 04:09:45 -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 |
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
|
||||
+3
-2
@@ -1,4 +1,5 @@
|
||||
build
|
||||
build*
|
||||
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 |
@@ -1,3 +1,21 @@
|
||||
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)
|
||||
|
||||
+132
-12
@@ -10,7 +10,8 @@ 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(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})
|
||||
@@ -20,11 +21,30 @@ option(NOLOADADDR "Set to ON to avoid fixing the load address of Box86" ${NO_LOA
|
||||
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})
|
||||
|
||||
find_package(PythonInterp)
|
||||
if(NOT PYTHONINTERP_FOUND)
|
||||
message( FATAL_ERROR "You need a Python interpretor, CMake will exit." )
|
||||
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)
|
||||
@@ -78,6 +98,15 @@ if(RPI4)
|
||||
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)
|
||||
@@ -108,6 +137,9 @@ 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")
|
||||
@@ -117,7 +149,7 @@ else()
|
||||
endif()
|
||||
|
||||
|
||||
add_definitions(-g -std=gnu99 -funwind-tables -O3 -fvisibility=hidden)
|
||||
add_definitions(-std=gnu99 -funwind-tables -fvisibility=hidden)
|
||||
|
||||
if(USE_CCACHE)
|
||||
find_program(CCACHE_FOUND ccache)
|
||||
@@ -133,15 +165,26 @@ include_directories(
|
||||
"${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
|
||||
"${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"
|
||||
@@ -155,10 +198,14 @@ set(ELFLOADER_SRC
|
||||
"${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"
|
||||
@@ -207,14 +254,19 @@ set(WRAPPEDS
|
||||
"${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"
|
||||
@@ -231,7 +283,10 @@ set(WRAPPEDS
|
||||
"${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"
|
||||
@@ -242,6 +297,7 @@ set(WRAPPEDS
|
||||
"${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"
|
||||
@@ -250,7 +306,10 @@ set(WRAPPEDS
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedpango.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappeddbusglib1.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgudev1.c"
|
||||
# "${BOX86_ROOT}/src/wrapped/wrappedmonounity.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"
|
||||
)
|
||||
|
||||
@@ -258,11 +317,32 @@ 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()
|
||||
|
||||
set(WRAPPER "${BOX86_ROOT}/src/wrapped/generated/wrapper.c" "${BOX86_ROOT}/src/wrapped/generated/wrapper.h")
|
||||
|
||||
add_custom_command(OUTPUT ${WRAPPER} COMMAND "${PYTHON_EXECUTABLE}" "${BOX86_ROOT}/rebuild_wrappers.py" "${BOX86_ROOT}" "PANDORA" "HAVE_LD80BITS" "NOALIGN" "HAVE_TRACE" "USE_FLOAT" MAIN_DEPENDENCY "${BOX86_ROOT}/rebuild_wrappers.py" DEPENDS ${WRAPPEDS} ${WRAPPEDS_HEAD})
|
||||
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
|
||||
@@ -280,9 +360,14 @@ if(ARM_DYNAREC)
|
||||
|
||||
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"
|
||||
@@ -312,6 +397,10 @@ if(ARM_DYNAREC)
|
||||
set_target_properties(arm_pass2 PROPERTIES COMPILE_FLAGS "-DSTEP=2")
|
||||
add_library(arm_pass3 OBJECT ${DYNAREC_PASS})
|
||||
set_target_properties(arm_pass3 PROPERTIES COMPILE_FLAGS "-DSTEP=3")
|
||||
add_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>
|
||||
@@ -323,8 +412,22 @@ if(ARM_DYNAREC)
|
||||
endif()
|
||||
|
||||
if(BOX86LIB)
|
||||
#build a static lib...
|
||||
add_library(box86 OBJECT ${ELFLOADER_SRC} ${WRAPPEDS})
|
||||
#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)
|
||||
|
||||
@@ -337,13 +440,24 @@ else()
|
||||
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(NOT NOLOADADDR)
|
||||
target_link_libraries(${BOX86} -Wl,-Ttext-segment,0x03800000)
|
||||
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)
|
||||
@@ -354,6 +468,7 @@ if(NOT _x86 AND NOT _x86_64)
|
||||
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()
|
||||
|
||||
@@ -432,7 +547,12 @@ add_test(test13 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref13.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
file(GLOB extension_tests "${CMAKE_SOURCE_DIR}/tests/extensions/*.c")
|
||||
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}
|
||||
|
||||
+18
-8
@@ -2,31 +2,35 @@ Compiling
|
||||
----
|
||||
#### for Pandora
|
||||
|
||||
`mkdir build; cd build; cmake .. -DPANDORA=1; make`
|
||||
`mkdir build; cd build; cmake .. -DPANDORA=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make`
|
||||
|
||||
#### for Pyra
|
||||
|
||||
`mkdir build; cd build; cmake .. -DPYRA=1; make`
|
||||
`mkdir build; cd build; cmake .. -DPYRA=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make`
|
||||
|
||||
#### for Gameshell
|
||||
|
||||
`mkdir build; cd build; cmake .. -DGAMESHELL=1; make`
|
||||
`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; make`
|
||||
`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 .. ; make`
|
||||
`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; make`
|
||||
`mkdir build; cd build; cmake .. -DLD80BITS=1 -DNOALIGN=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make`
|
||||
|
||||
#### use ccmake
|
||||
|
||||
@@ -34,14 +38,20 @@ Alternatively, you can use the curses-bases ccmake (or any other gui frontend fo
|
||||
|
||||
#### Customize your build
|
||||
|
||||
*use ccache if you have it*
|
||||
*use ccache if you have it*
|
||||
|
||||
Add `-DUSE_CCACHE=1` if you have ccache (it's better if you plan to touch the sources)
|
||||
|
||||
*have some debug info*
|
||||
|
||||
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*
|
||||
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).
|
||||
|
||||
----
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
# box86
|
||||
|
||||

|
||||
Linux Userspace x86 Emulator with a twist
|
||||
|
||||
[](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=LU8Y2T62ZWFHU)
|
||||
Box86 lets you run x86 Linux programs (such as games) on non-x86 Linux, like ARM (host system needs to be 32bit little-endian).
|
||||
|
||||
Box86 will let you run x86 Linux programs (games) on non-x86 Linux, like ARM (host system needs to be 32bit little-endian).
|
||||
You *NEED* a 32-bit subsystem to run and build Box86. Box86 is useless on 64-bit only systems. Also, you *NEED* a 32-bit toolchain to build Box86. A toolchain that only support 64-bit will not compile Box86, and you'll get errors (typically on aarch64, you get "-marm" not recognized).
|
||||
|
||||
Because Box86 uses the native version for some "system" libraries, like libc, libm, or SDL and OpenGL, it's easy to integrate and use, and performances can be surprinsigly high in some cases.
|
||||
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.
|
||||
|
||||
Most x86 Games need OpenGL, so on ARM platforms, a solution like [gl4es](https://github.com/ptitSeb/gl4es) is probably needed.
|
||||
Most x86 Games need OpenGL, so on ARM platforms a solution like [gl4es](https://github.com/ptitSeb/gl4es) is usually necessary.
|
||||
|
||||
Box86 now integrate a DynaRec for ARM platform, providing a speed boost between 5 to 10 times compared to only the interpretor.
|
||||
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.
|
||||
|
||||
Many games already work, like for example: WorldOfGoo, Airline Tycoon Deluxe or 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)
|
||||
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)
|
||||
|
||||
If you are serious about developing Box86, you should install ccache and activate it's support in the cmake project (use ccmake for example)
|
||||
To have TRACE enabled (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) accessible on your system.
|
||||
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
|
||||
|
||||
@@ -23,46 +24,63 @@ Here are 6 videos, the first 2 of "Airline Tycoon Deluxe" and "Heretic 2" runnin
|
||||
|
||||
[](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
|
||||
----
|
||||
How to compile can be found [here](COMPILE.md)
|
||||
Compilation instructions can be found [here](COMPILE.md)
|
||||
|
||||
----
|
||||
|
||||
Usage
|
||||
----
|
||||
|
||||
There are a few environment variables to control Box86 behaviour.
|
||||
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 [here](CHANGELOG.md)
|
||||
The change log is available [here](CHANGELOG.md)
|
||||
|
||||
----
|
||||
|
||||
A note about 64bits platform
|
||||
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 32bits library. Box86 doesn't include any 32bits <-> 64bits translation. So basically, to run box86 on, for example, an ARM64 platform, you will need to build box86 for arm 32bits, and also need to have a chroot with 32bits library.
|
||||
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 binary on 64bits platform. You will still need box86 (and see 32bits chroot) to run x86 binary (in fact, like it is the case on actual x86_64 linux)
|
||||
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 not possible for now. Mono itself uses signals that are not well emulated enough. So the solution is to use a native version of the libmono used by Unity. It can be found here: https://github.com/Unity-Technologies/mono and it needs to be built from source. When built copy `libmonosgen-2.0.so` to `libmonounity.so` and put it somewhere it can be dlopen'd (so in `usr/lib` or friend or somewhere in your `LD_LIBRARY_PATH`).
|
||||
Note that libmonounity is not completely wrapped yet, and the mechanism to call x86 library from libmonounity is not done yet, so the use of libmonounity is not enable for now.
|
||||
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: mono games are not working for now anyway.
|
||||
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.
|
||||
|
||||
----
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ Controls the folder scanned to look for x86 executable. Default is current folde
|
||||
|
||||
#### 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
|
||||
@@ -58,6 +59,11 @@ 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
|
||||
@@ -68,6 +74,16 @@ 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 :
|
||||
@@ -77,7 +93,7 @@ Set level of DynaRec log
|
||||
* 2 :
|
||||
* DEBUG : Debug Log for Dynarec (with detail on block created / executed)
|
||||
* 3 :
|
||||
* DUMP : All above plus dump of the x86 -> native opcode conversions
|
||||
* VERBOSE : All above plus more
|
||||
|
||||
#### BOX86_DYNAREC
|
||||
* 0 : Disable Dynarec
|
||||
@@ -103,10 +119,14 @@ Set level of DynaRec log
|
||||
#### 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 LittleInforno for example is auto detected, and libvorbis.so.0 is automatical added to emulated libs
|
||||
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.
|
||||
|
||||
Executable
+1984
File diff suppressed because it is too large.
Load diff
+113
-109
@@ -1,19 +1,17 @@
|
||||
#!/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', 'K', 'l', 'L', 'p', 'V', "O", "S"]
|
||||
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))
|
||||
return ret
|
||||
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]
|
||||
@@ -36,16 +34,16 @@ def splitdef(dnf, defines):
|
||||
def invert(define):
|
||||
return define[1:] if define.startswith("!") else ("!" + define)
|
||||
|
||||
def main(root, defines, ver):
|
||||
# Initialize variables: gbl for all values, vals for file-per-file values, redirects for redirections
|
||||
def main(root, defines, files, ver):
|
||||
global values
|
||||
|
||||
# Initialize variables: gbl for all values, redirects for redirections
|
||||
gbl = {}
|
||||
vals = {}
|
||||
redirects = {}
|
||||
|
||||
# First read the files inside the headers
|
||||
for filepath in glob.glob(os.path.join(root, "src/wrapped/", "wrapped*_private.h")):
|
||||
for filepath in files:
|
||||
filename = filepath.split("/")[-1]
|
||||
locval = {}
|
||||
dependants = []
|
||||
with open(filepath, 'r') as file:
|
||||
for line in file:
|
||||
@@ -68,8 +66,8 @@ def main(root, defines, ver):
|
||||
raise KeyError(preproc_cmd[5:].strip())
|
||||
dependants.append("defined(" + preproc_cmd[5:].strip() + ")")
|
||||
elif preproc_cmd.startswith("ifndef"):
|
||||
if preproc_cmd[5:].strip() not in defines:
|
||||
raise KeyError(preproc_cmd[5:].strip())
|
||||
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])
|
||||
@@ -91,29 +89,20 @@ def main(root, defines, ver):
|
||||
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}:{2})".format(ln[2:], filename, line[:-1]))
|
||||
# Ok, this is acceptable: there is 0, 1, stdout and void
|
||||
# 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.setdefault(" && ".join(dependants), {})
|
||||
redirects[" && ".join(dependants)][old] = ln
|
||||
# Simply append the function name if it's not yet existing
|
||||
locval.setdefault(" && ".join(dependants), [])
|
||||
gbl.setdefault(" && ".join(dependants), [])
|
||||
if ln not in locval[" && ".join(dependants)]:
|
||||
locval[" && ".join(dependants)].append(ln)
|
||||
if ln not in gbl[" && ".join(dependants)]:
|
||||
gbl[" && ".join(dependants)].append(ln)
|
||||
|
||||
# Sort the file local values and add it to the dictionary
|
||||
for k in locval:
|
||||
locval[k].sort(key=splitchar)
|
||||
vals[filename] = locval
|
||||
|
||||
gbl_vals = {}
|
||||
for k in gbl:
|
||||
@@ -180,24 +169,44 @@ def main(root, defines, ver):
|
||||
redirects_idxs = []
|
||||
for k, v in redirects_vals:
|
||||
key = "(" + (") || (".join(redirects_vals[(k, v)])) + ")"
|
||||
val = redirects.get(key, {})
|
||||
val[k] = v
|
||||
redirects[key] = val
|
||||
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 table
|
||||
# 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]
|
||||
|
||||
def length(s):
|
||||
l = len(s)
|
||||
if l < 10:
|
||||
ret = "0" + str(l)
|
||||
else:
|
||||
ret = str(l)
|
||||
return ret
|
||||
# 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
|
||||
@@ -243,11 +252,7 @@ static void* io_convert(void* v)
|
||||
#else
|
||||
#define ST0val ST0.d
|
||||
#endif
|
||||
#ifndef NOALIGN
|
||||
int of_convert(int flag) { return (flag&~0740000) | ((flag&0140000)<<2) | ((flag&0600000)>>2);}
|
||||
#else
|
||||
int of_convert(int flag) { return flag; }
|
||||
#endif
|
||||
int of_convert(int);
|
||||
""",
|
||||
"wrapper.h": """/*****************************************************************
|
||||
* File automatically generated by rebuild_wrappers.py (v%s)
|
||||
@@ -284,57 +289,50 @@ typedef void (*wrapper_t)(x86emu_t* emu, uintptr_t fnc);
|
||||
"""
|
||||
}
|
||||
|
||||
# Transform strings into arrays
|
||||
for k in gbl:
|
||||
gbl[k] = [[c for c in v] for v in gbl[k]]
|
||||
|
||||
# Rewrite the wrapper.h file:
|
||||
with open(os.path.join(root, "src/wrapped/generated/", "wrapper.h"), 'w') as file:
|
||||
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 " + ''.join(v) + "(x86emu_t *emu, uintptr_t fnc);\n")
|
||||
file.write("void " + v + "(x86emu_t *emu, uintptr_t fnc);\n")
|
||||
for k in gbl_idxs:
|
||||
if k != "()":
|
||||
file.write("\n#if " + k + "\n")
|
||||
for v in gbl[k]:
|
||||
file.write("void " + ''.join(v) + "(x86emu_t *emu, uintptr_t fnc);\n")
|
||||
file.write("#endif\n")
|
||||
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 " + ''.join(v) + "(x86emu_t *emu, uintptr_t fnc);\n")
|
||||
file.write("void " + v[0] + "(x86emu_t *emu, uintptr_t fnc);\n")
|
||||
for k in redirects_idxs:
|
||||
if k != "()":
|
||||
file.write("\n#if " + k + "\n")
|
||||
for v in redirects[k]:
|
||||
file.write("void " + ''.join(v) + "(x86emu_t *emu, uintptr_t fnc);\n")
|
||||
file.write("#endif\n")
|
||||
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/wrapped/generated/", "wrapper.c"), 'w') as file:
|
||||
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 K l L p V O S
|
||||
# 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])] + " (*" + ''.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:
|
||||
if k != "()":
|
||||
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])] + " (*" + ''.join(v) + "_t)"
|
||||
+ "(" + ', '.join(types[values.index(t)] for t in v[2:]) + ");\n")
|
||||
file.write("#endif\n")
|
||||
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
|
||||
@@ -352,27 +350,27 @@ typedef void (*wrapper_t)(x86emu_t* emu, uintptr_t fnc);
|
||||
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})), ", # 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
|
||||
"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 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]
|
||||
@@ -412,28 +410,34 @@ typedef void (*wrapper_t)(x86emu_t* emu, uintptr_t fnc);
|
||||
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:])
|
||||
function_writer(file, v, v + "_t", v[0], v[2:])
|
||||
for k in gbl_idxs:
|
||||
if k != "()":
|
||||
file.write("\n#if " + k + "\n")
|
||||
for v in gbl[k]:
|
||||
function_writer(file, ''.join(v), ''.join(v) + "_t", v[0], v[2:])
|
||||
file.write("#endif\n")
|
||||
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, redirects["()"][v] + "_t", v[0], v[2:])
|
||||
function_writer(file, v[0], v[1] + "_t", v[0][0], v[0][2:])
|
||||
for k in redirects_idxs:
|
||||
if k != "()":
|
||||
file.write("\n#if " + k + "\n")
|
||||
for v in redirects[k]:
|
||||
function_writer(file, v, redirects[k][v] + "_t", v[0], v[2:])
|
||||
file.write("#endif\n")
|
||||
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], sys.argv[2:], "1.1.1.06") != 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)
|
||||
+8
-1
@@ -13,7 +13,14 @@ if( NOT TEST_REFERENCE )
|
||||
endif( NOT TEST_REFERENCE )
|
||||
|
||||
set(ENV{BOX86_LOG} 0)
|
||||
set(ENV{LD_LIBRARY_PATH} ${CMAKE_SOURCE_DIR}/x86lib)
|
||||
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}
|
||||
|
||||
+328
-87
@@ -16,49 +16,227 @@
|
||||
#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;
|
||||
uintptr_t offset; // offset in the block
|
||||
uint8_t map[MMAPSIZE/(8*MMAPBLOCK)]; // map of allocated sub-block
|
||||
} mmaplist_t;
|
||||
|
||||
#define MMAPSIZE (4*1024*1024) // allocate 4Mo sized blocks
|
||||
|
||||
uintptr_t AllocDynarecMap(box86context_t *context, int size)
|
||||
// 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)
|
||||
{
|
||||
// make size 0x10 bytes aligned
|
||||
size = (size+0x0f)&~0x0f;
|
||||
pthread_mutex_lock(&context->mutex_mmap);
|
||||
// look for free space
|
||||
for(int i=0; i<context->mmapsize; ++i) {
|
||||
if(context->mmaplist[i].offset+size < MMAPSIZE) {
|
||||
uintptr_t ret = context->mmaplist[i].offset + (uintptr_t)context->mmaplist[i].block;
|
||||
context->mmaplist[i].offset+=size;
|
||||
pthread_mutex_unlock(&context->mutex_mmap);
|
||||
return ret;
|
||||
#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 = context->mmapsize++; // yeah, usefull post incrementation
|
||||
dynarec_log(LOG_DEBUG, "Ask for DynaRec Block Alloc #%d\n", context->mmapsize);
|
||||
context->mmaplist = (mmaplist_t*)realloc(context->mmaplist, context->mmapsize*sizeof(mmaplist_t));
|
||||
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_INFO, "Cannot create memory map of %d byte for dynarec block #%d\n", MMAPSIZE, i);
|
||||
--context->mmapsize;
|
||||
pthread_mutex_unlock(&context->mutex_mmap);
|
||||
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;
|
||||
}
|
||||
context->mmaplist[i].block = p;
|
||||
context->mmaplist[i].offset=size;
|
||||
pthread_mutex_unlock(&context->mutex_mmap);
|
||||
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
|
||||
@@ -82,14 +260,25 @@ void free_tlsdatasize(void* p)
|
||||
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(context);
|
||||
#endif
|
||||
context->maplib = NewLibrarian(context, 1);
|
||||
context->local_maplib = NewLibrarian(context, 1);
|
||||
context->system = NewBridge();
|
||||
// create vsyscall
|
||||
context->vsyscall = AddBridge(context->system, vFv, x86Syscall, 0);
|
||||
@@ -109,13 +298,14 @@ box86context_t *NewBox86Context(int argc)
|
||||
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);
|
||||
context->dynablocks = NewDynablockList(0, 0, 0, 0, 0);
|
||||
#endif
|
||||
InitFTSMap(context);
|
||||
|
||||
@@ -123,109 +313,135 @@ box86context_t *NewBox86Context(int argc)
|
||||
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;
|
||||
|
||||
FreeFTSMap(*context);
|
||||
box86context_t* ctx = *context; // local copy to do the cleanning
|
||||
|
||||
if((*context)->maplib)
|
||||
FreeLibrarian(&(*context)->maplib);
|
||||
for(int i=0; i<ctx->elfsize; ++i) {
|
||||
FreeElfHeader(&ctx->elfs[i]);
|
||||
}
|
||||
free(ctx->elfs);
|
||||
|
||||
FreeFTSMap(ctx);
|
||||
|
||||
if(ctx->maplib)
|
||||
FreeLibrarian(&ctx->maplib);
|
||||
if(ctx->local_maplib)
|
||||
FreeLibrarian(&ctx->local_maplib);
|
||||
|
||||
#ifdef DYNAREC
|
||||
dynarec_log(LOG_INFO, "Free global Dynarecblocks\n");
|
||||
if((*context)->dynablocks)
|
||||
FreeDynablockList(&(*context)->dynablocks);
|
||||
for (int i=0; i<(*context)->mmapsize; ++i)
|
||||
if((*context)->mmaplist[i].block)
|
||||
munmap((*context)->mmaplist[i].block, MMAPSIZE);
|
||||
free((*context)->mmaplist);
|
||||
pthread_mutex_destroy(&(*context)->mutex_blocks);
|
||||
pthread_mutex_destroy(&(*context)->mutex_mmap);
|
||||
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
|
||||
|
||||
if((*context)->emu)
|
||||
FreeX86Emu(&(*context)->emu);
|
||||
*context = NULL; // bye bye my_context
|
||||
|
||||
FreeCollection(&(*context)->box86_path);
|
||||
FreeCollection(&(*context)->box86_ld_lib);
|
||||
FreeCollection(&(*context)->box86_emulated_libs);
|
||||
if((*context)->zydis)
|
||||
DeleteX86Trace(*context);
|
||||
CleanStackSize(ctx);
|
||||
|
||||
if((*context)->deferedInitList)
|
||||
free((*context)->deferedInitList);
|
||||
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);
|
||||
|
||||
if(ctx->deferedInitList)
|
||||
free(ctx->deferedInitList);
|
||||
|
||||
#ifndef BUILD_LIB
|
||||
if((*context)->box86lib)
|
||||
dlclose((*context)->box86lib);
|
||||
if(ctx->box86lib)
|
||||
dlclose(ctx->box86lib);
|
||||
#endif
|
||||
|
||||
FreeDLPrivate(&(*context)->dlprivate);
|
||||
FreeDLPrivate(&ctx->dlprivate);
|
||||
|
||||
for(int i=0; i<(*context)->argc; ++i)
|
||||
free((*context)->argv[i]);
|
||||
free((*context)->argv);
|
||||
free(ctx->argv);
|
||||
|
||||
for (int i=0; i<(*context)->envc; ++i)
|
||||
free((*context)->envv[i]);
|
||||
free((*context)->envv);
|
||||
for (int i=0; i<ctx->envc; ++i)
|
||||
free(ctx->envv[i]);
|
||||
free(ctx->envv);
|
||||
|
||||
for(int i=0; i<(*context)->elfsize; ++i) {
|
||||
FreeElfHeader(&(*context)->elfs[i]);
|
||||
}
|
||||
free((*context)->elfs);
|
||||
free(ctx->stack);
|
||||
|
||||
free((*context)->stack);
|
||||
free(ctx->fullpath);
|
||||
free(ctx->box86path);
|
||||
|
||||
free((*context)->fullpath);
|
||||
free((*context)->box86path);
|
||||
FreeBridge(&ctx->system);
|
||||
|
||||
FreeBridge(&(*context)->system);
|
||||
freeGLProcWrapper(ctx);
|
||||
freeALProcWrapper(ctx);
|
||||
|
||||
if((*context)->glwrappers)
|
||||
freeProcWrapper(&(*context)->glwrappers);
|
||||
if((*context)->alwrappers)
|
||||
freeProcWrapper(&(*context)->alwrappers);
|
||||
|
||||
FreeCallbackList(&(*context)->callbacks);
|
||||
FreeCallbackList(&ctx->callbacks);
|
||||
|
||||
void* ptr;
|
||||
if ((ptr = pthread_getspecific((*context)->tlskey)) != NULL) {
|
||||
if ((ptr = pthread_getspecific(ctx->tlskey)) != NULL) {
|
||||
free_tlsdatasize(ptr);
|
||||
pthread_setspecific((*context)->tlskey, NULL);
|
||||
pthread_setspecific(ctx->tlskey, NULL);
|
||||
}
|
||||
pthread_key_delete((*context)->tlskey);
|
||||
pthread_key_delete(ctx->tlskey);
|
||||
|
||||
if((*context)->tlsdata)
|
||||
free((*context)->tlsdata);
|
||||
if(ctx->tlsdata)
|
||||
free(ctx->tlsdata);
|
||||
|
||||
pthread_mutex_destroy(&(*context)->mutex_once);
|
||||
pthread_mutex_destroy(&(*context)->mutex_once2);
|
||||
pthread_mutex_destroy(&(*context)->mutex_trace);
|
||||
pthread_mutex_destroy(&(*context)->mutex_lock);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
if((*context)->atfork_sz) {
|
||||
free((*context)->atforks);
|
||||
(*context)->atforks = NULL;
|
||||
(*context)->atfork_sz = (*context)->atfork_cap = 0;
|
||||
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((*context)->signals[i]!=0 && (*context)->signals[i]!=1) {
|
||||
if(ctx->signals[i]!=0 && ctx->signals[i]!=1) {
|
||||
signal(i, SIG_DFL);
|
||||
}
|
||||
|
||||
if(ctx->emu_sig)
|
||||
FreeX86Emu(&ctx->emu_sig);
|
||||
|
||||
free(*context);
|
||||
*context = NULL;
|
||||
finiAllHelpers();
|
||||
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
int AddElfHeader(box86context_t* ctx, elfheader_t* head) {
|
||||
@@ -242,7 +458,32 @@ int AddElfHeader(box86context_t* ctx, elfheader_t* head) {
|
||||
}
|
||||
|
||||
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
-1
@@ -3,6 +3,6 @@
|
||||
|
||||
#define BOX86_MAJOR 0
|
||||
#define BOX86_MINOR 1
|
||||
#define BOX86_REVISION 0
|
||||
#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__
|
||||
+275
-65
@@ -33,16 +33,16 @@ Op is 20-27
|
||||
#define xSP 13
|
||||
|
||||
// barel roll operations (4 possibles)
|
||||
#define brLSL(i, r) (0<<4 | 0<<5 | ((i&31)<<7) | r)
|
||||
#define brLSR(i, r) (0<<4 | 1<<5 | ((i&31)<<7) | r)
|
||||
#define brASR(i, r) (0<<4 | 2<<5 | ((i&31)<<7) | r)
|
||||
#define brROR(i, r) (0<<4 | 3<<5 | ((i&31)<<7) | r)
|
||||
#define brLSL(i, r) (0<<4 | 0<<5 | (((i)&31)<<7) | (r))
|
||||
#define brLSR(i, r) (0<<4 | 1<<5 | (((i)&31)<<7) | (r))
|
||||
#define brASR(i, r) (0<<4 | 2<<5 | (((i)&31)<<7) | (r))
|
||||
#define brROR(i, r) (0<<4 | 3<<5 | (((i)&31)<<7) | (r))
|
||||
#define brIMM(r) (abs(r))
|
||||
// barel roll with a register
|
||||
#define brRLSL(i, r) (1<<4 | 0<<5 | ((i&15)<<8) | r)
|
||||
#define brRLSR(i, r) (1<<4 | 1<<5 | ((i&15)<<8) | r)
|
||||
#define brRASR(i, r) (1<<4 | 2<<5 | ((i&15)<<8) | r)
|
||||
#define brRROR(i, r) (1<<4 | 3<<5 | ((i&15)<<8) | r)
|
||||
#define brRLSL(i, r) (1<<4 | 0<<5 | (((i)&15)<<8) | (r))
|
||||
#define brRLSR(i, r) (1<<4 | 1<<5 | (((i)&15)<<8) | (r))
|
||||
#define brRASR(i, r) (1<<4 | 2<<5 | (((i)&15)<<8) | (r))
|
||||
#define brRROR(i, r) (1<<4 | 3<<5 | (((i)&15)<<8) | (r))
|
||||
|
||||
|
||||
// conditions
|
||||
@@ -79,12 +79,12 @@ Op is 20-27
|
||||
// pseudo insruction: mov reg, #imm with imm a 32bits value
|
||||
#define MOV32(dst, imm32) \
|
||||
MOVW(dst, ((uint32_t)imm32)&0xffff); \
|
||||
if (((uint32_t)imm32)>>16) { \
|
||||
if (((uint32_t)(imm32))>>16) { \
|
||||
MOVT(dst, (((uint32_t)imm32)>>16)); }
|
||||
// pseudo insruction: mov reg, #imm with imm a 32bits value, fixed size
|
||||
#define MOV32_(dst, imm32) \
|
||||
MOVW(dst, ((uint32_t)imm32)&0xffff); \
|
||||
MOVT(dst, (((uint32_t)imm32)>>16))
|
||||
MOVW(dst, ((uint32_t)(imm32))&0xffff); \
|
||||
MOVT(dst, (((uint32_t)(imm32))>>16))
|
||||
// movw.cond dst, #imm16
|
||||
#define MOVW_COND(cond, dst, imm16) EMIT(cond | 0x03000000 | ((dst) << 12) | (((imm16) & 0xf000) << 4) | brIMM((imm16) & 0x0fff) )
|
||||
// mov dst #imm8 ror imm4*2
|
||||
@@ -93,22 +93,30 @@ Op is 20-27
|
||||
#define MOV_IMM_COND(cond, dst, imm8, rimm4) EMIT(cond | 0x03a00000 | ((dst) << 12) | (imm8) | ((rimm4) << 8) )
|
||||
|
||||
// mov dst, src lsl imm5
|
||||
#define MOV_REG_LSL_IMM5(dst, src, imm5) EMIT(0xe1a00000 | ((dst) << 12) | (src) | (0<<4) | (0<<5) | (imm5<<7))
|
||||
#define MOV_REG_LSL_IMM5(dst, src, imm5) EMIT(0xe1a00000 | ((dst) << 12) | (src) | (0<<4) | (0<<5) | ((imm5)<<7))
|
||||
// mov dst, src lsr imm5
|
||||
#define MOV_REG_LSR_IMM5(dst, src, imm5) EMIT(0xe1a00000 | ((dst) << 12) | (src) | (0<<4) | (1<<5) | (imm5<<7))
|
||||
#define MOV_REG_LSR_IMM5(dst, src, imm5) EMIT(0xe1a00000 | ((dst) << 12) | (src) | (0<<4) | (1<<5) | ((imm5)<<7))
|
||||
// mov dst, src asr imm5
|
||||
#define MOV_REG_ASR_IMM5(dst, src, imm5) EMIT(0xe1a00000 | ((dst) << 12) | (src) | (0<<4) | (2<<5) | (imm5<<7))
|
||||
#define MOV_REG_ASR_IMM5(dst, src, imm5) EMIT(0xe1a00000 | ((dst) << 12) | (src) | (0<<4) | (2<<5) | ((imm5)<<7))
|
||||
// mov dst, src ror imm5
|
||||
#define MOV_REG_ROR_IMM5(dst, src, imm5) EMIT(0xe1a00000 | ((dst) << 12) | (src) | (0<<4) | (3<<5) | (imm5<<7))
|
||||
#define MOV_REG_ROR_IMM5(dst, src, imm5) EMIT(0xe1a00000 | ((dst) << 12) | (src) | (0<<4) | (3<<5) | ((imm5)<<7))
|
||||
// mov.s dst, src lsl imm5
|
||||
#define MOVS_REG_LSL_IMM5(dst, src, imm5) EMIT(0xe1b00000 | ((dst) << 12) | (src) | (0<<4) | (0<<5) | ((imm5)<<7))
|
||||
// mov.s dst, src lsr imm5
|
||||
#define MOVS_REG_LSR_IMM5(dst, src, imm5) EMIT(0xe1b00000 | ((dst) << 12) | (src) | (0<<4) | (1<<5) | ((imm5)<<7))
|
||||
// mov.s dst, src asr imm5
|
||||
#define MOVS_REG_ASR_IMM5(dst, src, imm5) EMIT(0xe1b00000 | ((dst) << 12) | (src) | (0<<4) | (2<<5) | ((imm5)<<7))
|
||||
// mov.s dst, src ror imm5
|
||||
#define MOVS_REG_ROR_IMM5(dst, src, imm5) EMIT(0xe1b00000 | ((dst) << 12) | (src) | (0<<4) | (3<<5) | ((imm5)<<7))
|
||||
|
||||
// mov dst, src lsl rs
|
||||
#define MOV_REG_LSL_REG(dst, src, rs) EMIT(0xe1a00000 | ((dst) << 12) | (src) | (1<<4) | (0<<5) | (rs<<8))
|
||||
#define MOV_REG_LSL_REG(dst, src, rs) EMIT(0xe1a00000 | ((dst) << 12) | (src) | (1<<4) | (0<<5) | ((rs)<<8))
|
||||
// mov dst, src lsr rs
|
||||
#define MOV_REG_LSR_REG(dst, src, rs) EMIT(0xe1a00000 | ((dst) << 12) | (src) | (1<<4) | (1<<5) | (rs<<8))
|
||||
#define MOV_REG_LSR_REG(dst, src, rs) EMIT(0xe1a00000 | ((dst) << 12) | (src) | (1<<4) | (1<<5) | ((rs)<<8))
|
||||
// mov dst, src asr rs
|
||||
#define MOV_REG_ASR_REG(dst, src, rs) EMIT(0xe1a00000 | ((dst) << 12) | (src) | (1<<4) | (2<<5) | (rs<<8))
|
||||
#define MOV_REG_ASR_REG(dst, src, rs) EMIT(0xe1a00000 | ((dst) << 12) | (src) | (1<<4) | (2<<5) | ((rs)<<8))
|
||||
// mov dst, src ror rs
|
||||
#define MOV_REG_ROR_REG(dst, src, rs) EMIT(0xe1a00000 | ((dst) << 12) | (src) | (1<<4) | (3<<5) | (rs<<8))
|
||||
#define MOV_REG_ROR_REG(dst, src, rs) EMIT(0xe1a00000 | ((dst) << 12) | (src) | (1<<4) | (3<<5) | ((rs)<<8))
|
||||
|
||||
// sub dst, src, #(imm8)
|
||||
#define SUB_IMM8(dst, src, imm8) \
|
||||
@@ -119,20 +127,32 @@ Op is 20-27
|
||||
// sub.s dst, src, #(imm8)
|
||||
#define SUBS_IMM8(dst, src, imm8) \
|
||||
EMIT(0xe2500000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
|
||||
// add dst, src1, src2, lsl #imm
|
||||
#define SUB_REG_LSL_IMM8(dst, src1, src2, imm8) \
|
||||
EMIT(0xe0400000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm8, src2) )
|
||||
// add.s dst, src1, src2, lsl #imm
|
||||
#define SUBS_REG_LSL_IMM8(dst, src1, src2, imm8) \
|
||||
EMIT(0xe0500000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm8, src2) )
|
||||
// sub dst, src1, src2, lsl #imm
|
||||
#define SUB_REG_LSL_IMM5(dst, src1, src2, imm5) \
|
||||
EMIT(0xe0400000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
|
||||
// sub.s dst, src1, src2, lsl #imm
|
||||
#define SUBS_REG_LSL_IMM5(dst, src1, src2, imm5) \
|
||||
EMIT(0xe0500000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
|
||||
|
||||
// sbc dst, src, #(imm8)
|
||||
#define SBC_IMM8(dst, src, imm8) \
|
||||
EMIT(0xe2c00000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
|
||||
// sbc.s dst, src, #(imm8)
|
||||
#define SBCS_IMM8(dst, src, imm8) \
|
||||
EMIT(0xe2d00000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
|
||||
// sbc dst, src1, src2, lsl #imm
|
||||
#define SBC_REG_LSL_IMM5(dst, src1, src2, imm5) \
|
||||
EMIT(0xe0c00000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
|
||||
// sbc.s dst, src1, src2, lsl #imm
|
||||
#define SBCS_REG_LSL_IMM5(dst, src1, src2, imm5) \
|
||||
EMIT(0xe0d00000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
|
||||
|
||||
// rsb dst, src, #(imm8)
|
||||
#define RSB_IMM8(dst, src, imm8) \
|
||||
EMIT(0xe2600000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
|
||||
// rsb.s dst, src, #(imm8)
|
||||
#define RSBS_IMM8(dst, src, imm8) \
|
||||
EMIT(0xe2700000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
|
||||
// rsb cond dst, src, #(imm8)
|
||||
#define RSB_COND_IMM8(cond, dst, src, imm8) \
|
||||
EMIT((cond) | 0x02600000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
|
||||
@@ -152,21 +172,38 @@ Op is 20-27
|
||||
// and.s dst, src, #(imm8)
|
||||
#define ANDS_IMM8(dst, src, imm8) \
|
||||
EMIT(0xe2100000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
|
||||
// and.s dst, src1, #imm ror rot*2
|
||||
#define ANDS_IMM8_ROR(src, imm8, rot) \
|
||||
EMIT(0xe2100000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | brIMM(imm8) )
|
||||
// add dst, src, #(imm8)
|
||||
#define ADD_IMM8(dst, src, imm8) \
|
||||
EMIT(0xe2800000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
|
||||
// add.s dst, src, #(imm8)
|
||||
#define ADDS_IMM8(dst, src, imm8) \
|
||||
EMIT(0xe2900000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
|
||||
// add.c dst, src, #(imm8)
|
||||
#define ADD_IMM8_cond(cond, dst, src, imm8) \
|
||||
EMIT((cond) | 0x02800000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
|
||||
// add dst, src1, src2, lsl #imm
|
||||
#define ADD_REG_LSL_IMM5(dst, src1, src2, imm5) \
|
||||
EMIT(0xe0800000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
|
||||
// add.s dst, src1, src2, lsl #imm
|
||||
#define ADDS_REG_LSL_IMM5(dst, src1, src2, imm8) \
|
||||
#define ADDS_REG_LSL_IMM5(dst, src1, src2, imm5) \
|
||||
EMIT(0xe0900000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
|
||||
// add dst, src1, src2, lsr #imm
|
||||
#define ADD_REG_LSR_IMM5(dst, src1, src2, imm5) \
|
||||
EMIT(0xe0800000 | ((dst) << 12) | ((src1) << 16) | brLSR(imm5, src2) )
|
||||
#define ADC_IMM8(dst, src, imm8) \
|
||||
EMIT(0xe2a00000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
|
||||
// add.s dst, src, #(imm8)
|
||||
#define ADCS_IMM8(dst, src, imm8) \
|
||||
EMIT(0xe2b00000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
|
||||
// add dst, src1, src2, lsl #imm
|
||||
#define ADC_REG_LSL_IMM5(dst, src1, src2, imm5) \
|
||||
EMIT(0xe0a00000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
|
||||
// add.s dst, src1, src2, lsl #imm
|
||||
#define ADCS_REG_LSL_IMM5(dst, src1, src2, imm5) \
|
||||
EMIT(0xe0b00000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
|
||||
// cmp.s dst, src1, src2, lsl #imm
|
||||
#define CMPS_REG_LSL_IMM5(src1, src2, imm5) \
|
||||
EMIT(0xe1500000 | ((0) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
|
||||
@@ -174,8 +211,8 @@ Op is 20-27
|
||||
#define CMPS_IMM8(src, imm8) \
|
||||
EMIT(0xe3500000 | ((0) << 12) | ((src) << 16) | brIMM(imm8) )
|
||||
// tst.s dst, src1, src2, lsl #imm
|
||||
#define TSTS_REG_LSL_IMM8(src1, src2, imm8) \
|
||||
EMIT(0xe1100000 | ((0) << 12) | ((src1) << 16) | brLSL(imm8, src2) )
|
||||
#define TSTS_REG_LSL_IMM5(src1, src2, imm5) \
|
||||
EMIT(0xe1100000 | ((0) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
|
||||
// tst.s dst, src1, #imm
|
||||
#define TSTS_IMM8(src, imm8) \
|
||||
EMIT(0xe3100000 | ((0) << 12) | ((src) << 16) | brIMM(imm8) )
|
||||
@@ -183,26 +220,33 @@ Op is 20-27
|
||||
#define TSTS_IMM8_ROR(src, imm8, rot) \
|
||||
EMIT(0xe3100000 | ((0) << 12) | ((src) << 16) | ((rot)<<8) | brIMM(imm8) )
|
||||
// orr dst, src1, src2, lsl #imm
|
||||
#define ORR_REG_LSL_IMM8(dst, src1, src2, imm8) \
|
||||
EMIT(0xe1800000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm8, src2) )
|
||||
#define ORR_REG_LSL_IMM5(dst, src1, src2, imm5) \
|
||||
EMIT(0xe1800000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
|
||||
// orr.s dst, src1, src2, lsl #imm
|
||||
#define ORRS_REG_LSL_IMM8(dst, src1, src2, imm8) \
|
||||
EMIT(0xe1900000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm8, src2) )
|
||||
#define ORRS_REG_LSL_IMM5(dst, src1, src2, imm5) \
|
||||
EMIT(0xe1900000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
|
||||
// orr dst, src1, #imm8
|
||||
#define ORR_IMM8(dst, src, imm8, rot) \
|
||||
EMIT(0xe3800000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | imm8 )
|
||||
// orr.s dst, src1, #imm8
|
||||
#define ORRS_IMM8(dst, src, imm8, rot) \
|
||||
EMIT(0xe3900000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | imm8 )
|
||||
// orr dst, src1, src2, lsl #rs
|
||||
#define ORR_REG_LSL_REG(dst, src1, src2, rs) \
|
||||
EMIT(0xe1800000 | ((dst) << 12) | ((src1) << 16) | brRLSL(rs, src2) )
|
||||
// xor dst, src1, src2, lsl #imm
|
||||
#define XOR_REG_LSL_IMM8(dst, src1, src2, imm8) \
|
||||
EMIT(0xe0200000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm8, src2) )
|
||||
#define XOR_REG_LSL_IMM5(dst, src1, src2, imm5) \
|
||||
EMIT(0xe0200000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
|
||||
// xor.s dst, src1, src2, lsl #imm
|
||||
#define XORS_REG_LSL_IMM8(dst, src1, src2, imm8) \
|
||||
EMIT(0xe0300000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm8, src2) )
|
||||
#define XORS_REG_LSL_IMM5(dst, src1, src2, imm5) \
|
||||
EMIT(0xe0300000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
|
||||
#define XOR_REG_LSL_IMM5_COND(cond, dst, src1, src2, imm5) \
|
||||
EMIT((cond) | 0x00200000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
|
||||
// xor dst, src, #(imm8)
|
||||
#define XOR_IMM8(dst, src, imm8) \
|
||||
EMIT(0xe2200000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
|
||||
#define XORS_IMM8(dst, src, imm8) \
|
||||
EMIT(0xe2300000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
|
||||
// xor.cond dst, src, #(imm8)
|
||||
#define XOR_IMM8_COND(cond, dst, src, imm8) \
|
||||
EMIT(cond | 0x02200000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
|
||||
@@ -213,17 +257,20 @@ Op is 20-27
|
||||
#define XOR_REG_LSR_IMM8(dst, src1, src2, imm8) \
|
||||
EMIT(0xe0200000 | ((dst) << 12) | ((src1) << 16) | brLSR(imm8, src2) )
|
||||
// bic dst, src1, src2, lsl #imm
|
||||
#define BIC_REG_LSL_IMM8(dst, src1, src2, imm8) \
|
||||
EMIT(0xe1c00000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm8, src2) )
|
||||
#define BIC_REG_LSL_IMM5(dst, src1, src2, imm5) \
|
||||
EMIT(0xe1c00000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
|
||||
// bic dst, src, IMM8
|
||||
#define BIC_IMM8(dst, src, imm8, rot) \
|
||||
EMIT(0xe3c00000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | imm8 )
|
||||
// bic.s dst, src1, #imm ror rot*2
|
||||
#define BICS_IMM8_ROR(dst, src, imm8, rot) \
|
||||
EMIT(0xe3d00000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | brIMM(imm8) )
|
||||
// bic dst, src1, src2, lsl #imm
|
||||
#define BIC_REG_LSL_REG(dst, src1, src2, rs) \
|
||||
EMIT(0xe1c00000 | ((dst) << 12) | ((src1) << 16) | brRLSL(rs, src2) )
|
||||
// mvn dst, src1, src2, lsl #imm
|
||||
#define MVN_REG_LSL_IMM8(dst, rm, imm8) \
|
||||
EMIT(0xe1e00000 | ((dst) << 12) | (0 << 16) | brLSL(imm8, rm) )
|
||||
#define MVN_REG_LSL_IMM5(dst, rm, imm5) \
|
||||
EMIT(0xe1e00000 | ((dst) << 12) | (0 << 16) | brLSL(imm5, rm) )
|
||||
// mvn dst, src, IMM8
|
||||
#define MVN_IMM8(dst, src, imm8, rot) \
|
||||
EMIT(0xe3e00000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | imm8 )
|
||||
@@ -234,8 +281,8 @@ Op is 20-27
|
||||
#define MVN_REG_LSR_REG(dst, rm, rs) \
|
||||
EMIT(0xe1e00000 | ((dst) << 12) | (0 << 16) | (1<<4) | (1<<5) | (rs<<8) | (rm) )
|
||||
// mvn with condition dst, src1, src2, lsl #imm
|
||||
#define MVN_COND_REG_LSL_IMM8(cond, dst, rm, imm8) \
|
||||
EMIT(cond | 0x01e00000 | ((dst) << 12) | (0 << 16) | brLSL(imm8, rm) )
|
||||
#define MVN_COND_REG_LSL_IMM5(cond, dst, rm, imm5) \
|
||||
EMIT(cond | 0x01e00000 | ((dst) << 12) | (0 << 16) | brLSL(imm5, rm) )
|
||||
|
||||
// Single data transfert construction
|
||||
#define SDT_REG(Cond, P, U, B, W, L, Rn, Rd, ShiftRm) (Cond | (0b00<<26) | (1<<25) | (P<<24) | (U<<23) | (B<<22) | (U<<23) | (W<<21) | (L<<20) | (Rn<<16) | (Rd<<12) | ShiftRm)
|
||||
@@ -264,6 +311,8 @@ Op is 20-27
|
||||
#define LDRBAI_REG_LSL_IMM5(reg, addr, rm, imm5) EMIT(0xe6d00000 | ((reg) << 12) | ((addr) << 16) | (1<<25) | brLSL(imm5, rm) )
|
||||
// ldrd reg, reg+1, [addr, #+/-imm9], reg must be even, reg+1 is implicit
|
||||
#define LDRD_IMM8(reg, addr, imm8) EMIT(c__ | 0b000<<25 | 1<<24 | (((imm8)<0)?0:1)<<23 | 1<<22 | 0<<21 | 0<<20 | ((reg) << 12) | ((addr) << 16) | ((abs(imm8))&0xf0)<<(8-4) | (0b1101<<4) | ((abs(imm8))&0x0f) )
|
||||
// ldrd reg, reg+1, [addr, +rm], reg must be even, reg+1 is implicit
|
||||
#define LDRD_REG(reg, addr, rm) EMIT(c__ | 0b000<<25 | 1<<24 | 1<<23 | 0<<22 | 0<<21 | 0<<20 | ((reg) << 12) | ((addr) << 16) | 0b1101<<4 | (rm) )
|
||||
|
||||
// str reg, [addr, #+/-imm9]
|
||||
#define STR_IMM9(reg, addr, imm9) EMIT(0xe5000000 | (((imm9)<0)?0:1)<<23 | ((reg) << 12) | ((addr) << 16) | brIMM(imm9) )
|
||||
@@ -283,6 +332,8 @@ Op is 20-27
|
||||
#define STRBAI_REG_LSL_IMM5(reg, addr, rm, imm5) EMIT(0xe6c00000 | ((reg) << 12) | ((addr) << 16) | (1<<25) | brLSL(imm5, rm) )
|
||||
// strd reg, reg+1, [addr, #+/-imm8], reg must be even, reg+1 is implicit
|
||||
#define STRD_IMM8(reg, addr, imm8) EMIT(c__ | 0b000<<25 | 1<<24 | (((imm8)<0)?0:1)<<23 | 1<<22 | 0<<21 | 0<<20 | ((reg) << 12) | ((addr) << 16) | ((abs(imm8))&0xf0)<<(8-4) | (0b1111<<4) | ((abs(imm8))&0x0f) )
|
||||
// strd reg, reg+1, [addr, +rm], reg must be even, reg+1 is implicit
|
||||
#define STRD_REG(reg, addr, rm) EMIT(c__ | 0b000<<25 | 1<<24 | 1<<23 | 0<<22 | 0<<21 | 0<<20 | ((reg) << 12) | ((addr) << 16) | 0b1111<<4 | (rm) )
|
||||
|
||||
// bx reg
|
||||
#define BX(reg) EMIT(0xe12fff10 | (reg) )
|
||||
@@ -293,33 +344,33 @@ Op is 20-27
|
||||
#define BLX(reg) EMIT(0xe12fff30 | (reg) )
|
||||
|
||||
// b cond offset
|
||||
#define Bcond(C, O) EMIT(C | (0b101<<25) | (0<<24) | ((O)>>2)&0xffffff)
|
||||
#define Bcond(C, O) EMIT(C | (0b101<<25) | (0<<24) | (((O)>>2)&0xffffff))
|
||||
|
||||
// bl cond offset
|
||||
#define BLcond(C, O) EMIT(C | (0b101<<25) | (1<<24) | ((O)>>2)&0xffffff)
|
||||
#define BLcond(C, O) EMIT(C | (0b101<<25) | (1<<24) | (((O)>>2)&0xffffff))
|
||||
|
||||
// push reg!, {list}
|
||||
// all | const |pre-index| subs | no PSR |writeback| store | base |reg list
|
||||
#define PUSH(reg, list) EMIT(c__ | (0b100<<25) | (1<<24) | (0<<23) | (0<<22) | (1<<21) | (0<<20) | (reg<<16) | (list))
|
||||
#define PUSH(reg, list) EMIT(c__ | (0b100<<25) | (1<<24) | (0<<23) | (0<<22) | (1<<21) | (0<<20) | ((reg)<<16) | (list))
|
||||
|
||||
// pop reg!, {list}
|
||||
// all | const |postindex| add | no PSR |writeback| load | base |reg list
|
||||
#define POP(reg, list) EMIT(c__ | (0b100<<25) | (0<<24) | (1<<23) | (0<<22) | (1<<21) | (1<<20) | (reg<<16) | (list))
|
||||
#define POP(reg, list) EMIT(c__ | (0b100<<25) | (0<<24) | (1<<23) | (0<<22) | (1<<21) | (1<<20) | ((reg)<<16) | (list))
|
||||
|
||||
// STMDB reg, {list}
|
||||
// all | const |pre-index| subs | no PSR | no wb | store | base |reg list
|
||||
#define STMDB(reg, list) EMIT(c__ | (0b100<<25) | (1<<24) | (0<<23) | (0<<22) | (0<<21) | (0<<20) | (reg<<16) | (list))
|
||||
#define STMDB(reg, list) EMIT(c__ | (0b100<<25) | (1<<24) | (0<<23) | (0<<22) | (0<<21) | (0<<20) | ((reg)<<16) | (list))
|
||||
// STMia reg, {list}
|
||||
// all | const |postindex| add | no PSR | no wb | store | base |reg list
|
||||
#define STM(reg, list) EMIT(c__ | (0b100<<25) | (0<<24) | (1<<23) | (0<<22) | (0<<21) | (0<<20) | (reg<<16) | (list))
|
||||
#define STM(reg, list) EMIT(c__ | (0b100<<25) | (0<<24) | (1<<23) | (0<<22) | (0<<21) | (0<<20) | ((reg)<<16) | (list))
|
||||
// LDMia reg, {list}
|
||||
// all | const |postindex| add | no PSR | no wb | load | base |reg list
|
||||
#define LDM(reg, list) EMIT(c__ | (0b100<<25) | (0<<24) | (1<<23) | (0<<22) | (0<<21) | (1<<20) | (reg<<16) | (list))
|
||||
#define LDM(reg, list) EMIT(c__ | (0b100<<25) | (0<<24) | (1<<23) | (0<<22) | (0<<21) | (1<<20) | ((reg)<<16) | (list))
|
||||
|
||||
|
||||
// Half Word and signed data transfert construction
|
||||
#define HWS_REG(Cond, P, U, W, L, Rn, Rd, S, H, Rm) (Cond | (0b000<<25) | (P<<24) | (U<<23) | (0<<22) | (W<<21) | (L<<20) | (Rn<<16) | (Rd<<12) | (1<<7) | (S<<6) | (H<<5) | (1<<4) | Rm)
|
||||
#define HWS_OFF(Cond, P, U, W, L, Rn, Rd, S, H, Imm8) (Cond | (0b000<<25) | (P<<24) | (U<<23) | (1<<22) | (W<<21) | (L<<20) | (Rn<<16) | (Rd<<12) | ((Imm8&0xf0)<<(8-4)) | (1<<7) | (S<<6) | (H<<5) | (1<<4) | (Imm8&0x0f))
|
||||
#define HWS_REG(Cond, P, U, W, L, Rn, Rd, S, H, Rm) (Cond | 0b000<<25 | (P)<<24 | (U)<<23 | 0<<22 | (W)<<21 | (L)<<20 | (Rn)<<16 | (Rd)<<12 | 1<<7 | (S)<<6 | (H)<<5 | 1<<4 | (Rm))
|
||||
#define HWS_OFF(Cond, P, U, W, L, Rn, Rd, S, H, Imm8) (Cond | 0b000<<25 | (P)<<24 | (U)<<23 | 1<<22 | (W)<<21 | (L)<<20 | (Rn)<<16 | (Rd)<<12 | ((Imm8)&0xf0)<<(8-4) | 1<<7 | (S)<<6 | (H)<<5 | 1<<4 | ((Imm8)&0x0f))
|
||||
|
||||
#define LDRSB_IMM8(reg, addr, imm8) EMIT(HWS_OFF(c__, 1, (((imm8)<0)?0:1), 0, 1, addr, reg, 1, 0, abs(imm8)))
|
||||
#define LDRSH_IMM8(reg, addr, imm8) EMIT(HWS_OFF(c__, 1, (((imm8)<0)?0:1), 0, 1, addr, reg, 1, 1, abs(imm8)))
|
||||
@@ -328,17 +379,20 @@ Op is 20-27
|
||||
#define STRH_IMM8(reg, addr, imm8) EMIT(HWS_OFF(c__, 1, (((imm8)<0)?0:1), 0, 0, addr, reg, 0, 1, abs(imm8)))
|
||||
#define STRSH_IMM8(reg, addr, imm8) EMIT(HWS_OFF(c__, 1, (((imm8)<0)?0:1), 0, 0, addr, reg, 1, 1, abs(imm8)))
|
||||
|
||||
#define LDRH_REG(reg, addr, rm) EMIT(HWS_REG(c__, 1, 1, 0, 1, addr, reg, 0, 1, rm))
|
||||
#define STRH_REG(reg, addr, rm) EMIT(HWS_REG(c__, 1, 1, 0, 0, addr, reg, 0, 1, rm))
|
||||
|
||||
#define LDRHAI_REG_LSL_IMM5(reg, addr, rm) EMIT(HWS_REG(c__, 0, 1, 0, 1, addr, reg, 0, 1, rm))
|
||||
#define STRHAI_REG_LSL_IMM5(reg, addr, rm) EMIT(HWS_REG(c__, 0, 1, 0, 0, addr, reg, 0, 1, rm))
|
||||
|
||||
// Mul Long construction
|
||||
#define MULLONG(Cond, U, A, S, RdHi, RdLo, Rs, Rm) (Cond | (0b00001<<23) | (U<<22) | (A<<21) | (S<<20) | (RdHi<<16) | (RdLo<<12) | (Rs<<8) | (0b1001<<4) | (Rm))
|
||||
#define MULLONG(Cond, U, A, S, RdHi, RdLo, Rs, Rm) (Cond | 0b00001<<23 | (U)<<22 | (A)<<21 | (S)<<20 | (RdHi)<<16 | (RdLo)<<12 | (Rs)<<8 | 0b1001<<4 | (Rm))
|
||||
|
||||
#define UMULL(RdHi, RdLo, Rs, Rm) EMIT(MULLONG(c__, 0, 0, 0, RdHi, RdLo, Rs, Rm))
|
||||
#define SMULL(RdHi, RdLo, Rs, Rm) EMIT(MULLONG(c__, 1, 0, 0, RdHi, RdLo, Rs, Rm))
|
||||
|
||||
// Mul and MulA
|
||||
#define MULMULA(Cond, A, S, Rd, Rn, Rs, Rm) (Cond | (0b000000<<22) | (A<<21) | (S<<20) | (Rd<<16) | (Rn<<12) | (Rs<<8) | (0b1001<<4) | (Rm))
|
||||
#define MULMULA(Cond, A, S, Rd, Rn, Rs, Rm) (Cond | 0b000000<<22 | (A)<<21 | (S)<<20 | (Rd)<<16 | (Rn)<<12 | (Rs)<<8 | 0b1001<<4 | (Rm))
|
||||
#define MUL(Rd, Rm, Rn) EMIT(MULMULA(c__, 0, 0, (Rd), 0, (Rm), (Rn)))
|
||||
|
||||
#define SMUL_16_gen(cond, Rd, Rm, M, N, Rn) (cond | 0b00010110<<20 | (Rd)<<16 | (Rm)<<8 | 1<<7 | (M)<<6 | (N)<<5 | (Rn))
|
||||
@@ -401,6 +455,20 @@ Op is 20-27
|
||||
// Preload Cache Rn-Rm
|
||||
#define PLDn(Rn, Rm) EMIT(PLD_gen(0, 1, Rn, 0, 0, Rm))
|
||||
|
||||
#define SWP_gen(cond, B, Rn, Rt, Rt2) (cond | 0b0001<<24 | (B)<<22 | (Rn)<<16 | (Rt)<<12 | 0b1001<<4 | (Rt2))
|
||||
// SWAP (atomic) [Rn]->Rt2 / Rt->[Rn], Rt can be same as Rt2
|
||||
#define SWP(Rt, Rt2, Rn) EMIT(SWP_gen(c__, 0, Rn, Rt, Rt2))
|
||||
// SWAP Byte (atomic) [Rn]->Rt2 / Rt->[Rn], Rt can be same as Rt2, Byte is zero extended
|
||||
#define SWPB(Rt, Rt2, Rn) EMIT(SWP_gen(c__, 1, Rn, Rt, Rt2))
|
||||
|
||||
#define SDIV_gen(cond, Rd, Rm, Rn) (cond | 0b0111<<24 | 0b0001<<20 | (Rd)<<16 | 0b1111<<12 | (Rm)<<8 | 0b0001<<4 | (Rn))
|
||||
// Signed Div Rd <- Rn/Rm
|
||||
#define SDIV(Rd, Rm, Rn) EMIT(SDIV_gen(c__, Rd, Rm, Rn))
|
||||
|
||||
#define UDIV_gen(cond, Rd, Rm, Rn) (cond | 0b0111<<24 | 0b0011<<20 | (Rd)<<16 | 0b1111<<12 | (Rm)<<8 | 0b0001<<4 | (Rn))
|
||||
// Unsigned Div Rd <- Rn/Rm
|
||||
#define UDIV(Rd, Rm, Rn) EMIT(UDIV_gen(c__, Rd, Rm, Rn))
|
||||
|
||||
// VFPU
|
||||
#define TRANSFERT64(C, op) ((0b1100<<24) | (0b010<<21) | (0b101<<9) | ((C)<<8) | ((op)<<4))
|
||||
|
||||
@@ -490,16 +558,16 @@ Op is 20-27
|
||||
#define VCVT_S16_F64(Dd) EMIT(VCVT_16_gen(c__, ((Dd)>>4)&1, 1, 0, (Dd)&15, 1, 0, 16&1, (16>>1)&15))
|
||||
|
||||
// Mutiply F64 Dd = Dn*Dm
|
||||
#define VMUL_F64(Dd, Dn, Dm) EMIT(c__ | (0b1110<<24) | (0<<23) | ((((Dd)>>4)&1)<<22) | (0b10<<20) | (((Dn)&15)<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | (((Dn>>4)&1)<<7) | (((Dm>>4)&1)<<5) | ((Dm)&15) )
|
||||
#define VMUL_F64(Dd, Dn, Dm) EMIT(c__ | (0b1110<<24) | (0<<23) | ((((Dd)>>4)&1)<<22) | (0b10<<20) | (((Dn)&15)<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | ((((Dn)>>4)&1)<<7) | ((((Dm)>>4)&1)<<5) | ((Dm)&15) )
|
||||
|
||||
// Divide F64 Dd = Dn/Dm
|
||||
#define VDIV_F64(Dd, Dn, Dm) EMIT(c__ | (0b1110<<24) | (1<<23) | ((((Dd)>>4)&1)<<22) | (0b00<<20) | (((Dn)&15)<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | (((Dn>>4)&1)<<7) | (((Dm>>4)&1)<<5) | ((Dm)&15) )
|
||||
#define VDIV_F64(Dd, Dn, Dm) EMIT(c__ | (0b1110<<24) | (1<<23) | ((((Dd)>>4)&1)<<22) | (0b00<<20) | (((Dn)&15)<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | ((((Dn)>>4)&1)<<7) | ((((Dm)>>4)&1)<<5) | ((Dm)&15) )
|
||||
|
||||
// Add F64 Dd = Dn + Dm
|
||||
#define VADD_F64(Dd, Dn, Dm) EMIT(c__ | (0b1110<<24) | (0<<23) | ((((Dd)>>4)&1)<<22) | (0b11<<20) | (((Dn)&15)<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | (((Dn>>4)&1)<<7) | (0<<6) | (((Dm>>4)&1)<<5) | ((Dm)&15) )
|
||||
#define VADD_F64(Dd, Dn, Dm) EMIT(c__ | (0b1110<<24) | (0<<23) | ((((Dd)>>4)&1)<<22) | (0b11<<20) | (((Dn)&15)<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | ((((Dn)>>4)&1)<<7) | (0<<6) | ((((Dm)>>4)&1)<<5) | ((Dm)&15) )
|
||||
|
||||
// Sub F64 Dd = Dn + Dm
|
||||
#define VSUB_F64(Dd, Dn, Dm) EMIT(c__ | (0b1110<<24) | (0<<23) | ((((Dd)>>4)&1)<<22) | (0b11<<20) | (((Dn)&15)<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | (((Dn>>4)&1)<<7) | (1<<6) | (((Dm>>4)&1)<<5) | ((Dm)&15) )
|
||||
#define VSUB_F64(Dd, Dn, Dm) EMIT(c__ | (0b1110<<24) | (0<<23) | ((((Dd)>>4)&1)<<22) | (0b11<<20) | (((Dn)&15)<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | ((((Dn)>>4)&1)<<7) | (1<<6) | ((((Dm)>>4)&1)<<5) | ((Dm)&15) )
|
||||
|
||||
// Mutiply F32 Sd = Sn*Sm
|
||||
#define VMUL_F32(Sd, Sn, Sm) EMIT(c__ | (0b1110<<24) | (0<<23) | (((Sd)&1)<<22) | (0b10<<20) | ((((Sn)>>1)&15)<<16) | ((((Sd)>>1)&15)<<12) | (0b101<<9) | (0<<8) | (((Sn)&1)<<7) | (((Sm)&1)<<5) | (((Sm)>>1)&15) )
|
||||
@@ -514,7 +582,7 @@ Op is 20-27
|
||||
#define VSUB_F32(Sd, Sn, Sm) EMIT(c__ | (0b1110<<24) | (0<<23) | (((Sd)&1)<<22) | (0b11<<20) | ((((Sn)>>1)&15)<<16) | ((((Sd)>>1)&15)<<12) | (0b101<<9) | (0<<8) | (((Sn)&1)<<7) | (1<<6) | (((Sm)&1)<<5) | (((Sm)>>1)&15) )
|
||||
|
||||
// Cmp between 2 double Dd and Dm
|
||||
#define VCMP_F64(Dd, Dm) EMIT(c__ | (0b1110<<24) | (1<<23) | ((((Dd)>>4)&1)<<22) | (0b11<<20) | (0b0100<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | (0<<7) | (1<<6) | (((Dm>>4)&1)<<5) | ((Dm)&15) )
|
||||
#define VCMP_F64(Dd, Dm) EMIT(c__ | (0b1110<<24) | (1<<23) | ((((Dd)>>4)&1)<<22) | (0b11<<20) | (0b0100<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | (0<<7) | (1<<6) | ((((Dm)>>4)&1)<<5) | ((Dm)&15) )
|
||||
// Cmp between 1 double Dd and 0.0
|
||||
#define VCMP_F64_0(Dd) EMIT(c__ | (0b1110<<24) | (1<<23) | ((((Dd)>>4)&1)<<22) | (0b11<<20) | (0b0101<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | (0<<7) | (1<<6) | (0<<5) | (0) )
|
||||
// Cmp between 2 single Sd and Sm
|
||||
@@ -523,10 +591,10 @@ Op is 20-27
|
||||
#define VCMP_F32_0(Sd) EMIT(c__ | (0b1110<<24) | (1<<23) | (((Sd)&1)<<22) | (0b11<<20) | (0b0101<<16) | ((((Sd)>>1)&15)<<12) | (0b101<<9) | (0<<8) | (0<<7) | (1<<6) | (0<<5) | (0) )
|
||||
|
||||
// Neg F64 Dd = - Dm
|
||||
#define VNEG_F64(Dd, Dm) EMIT(c__ | (0b1110<<24) | (1<<23) | ((((Dd)>>4)&1)<<22) | (0b11<<20) | (0b0001<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | (0b01<<6) | (((Dm>>4)&1)<<5) | ((Dm)&15) )
|
||||
#define VNEG_F64(Dd, Dm) EMIT(c__ | (0b1110<<24) | (1<<23) | ((((Dd)>>4)&1)<<22) | (0b11<<20) | (0b0001<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | (0b01<<6) | ((((Dm)>>4)&1)<<5) | ((Dm)&15) )
|
||||
|
||||
// Sqrt F64 Dd = - Dm
|
||||
#define VSQRT_F64(Dd, Dm) EMIT(c__ | (0b1110<<24) | (1<<23) | ((((Dd)>>4)&1)<<22) | (0b11<<20) | (0b0001<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | (0b11<<6) | (((Dm>>4)&1)<<5) | ((Dm)&15) )
|
||||
#define VSQRT_F64(Dd, Dm) EMIT(c__ | (0b1110<<24) | (1<<23) | ((((Dd)>>4)&1)<<22) | (0b11<<20) | (0b0001<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | (0b11<<6) | ((((Dm)>>4)&1)<<5) | ((Dm)&15) )
|
||||
// Sqrt F32 Dd = - Dm
|
||||
#define VSQRT_F32(Sd, Sm) EMIT(c__ | (0b1110<<24) | (1<<23) | (((Sd)&1)<<22) | (0b11<<20) | (0b0001<<16) | ((((Sd)>>1)&15)<<12) | (0b101<<9) | (0<<8) | (0b11<<6) | (((Sm)&1)<<5) | (((Sm)>>1)&15) )
|
||||
|
||||
@@ -597,6 +665,10 @@ Op is 20-27
|
||||
#define VMOVD(Dd, Dm) EMIT(VMOV_gen(((Dd)>>4)&1, (Dd)&15, ((Dm)>>4)&1, (Dm)&15, 0))
|
||||
#define VMOVQ(Dd, Dm) EMIT(VMOV_gen(((Dd)>>4)&1, (Dd)&15, ((Dm)>>4)&1, (Dm)&15, 1))
|
||||
|
||||
#define VMOV_igen(i, D, imm3, Vd, cmode, Q, op, imm4) (0b1111<<28 | 0b001<<25 | (i)<<24 | 1<<23 | (D)<<22 | (imm3)<<16 | (Vd)<<12 | (cmode)<<8 | (Q)<<6 | (op)<<5 | 1<<4 | (imm4))
|
||||
#define VMOV_8(Dd, imm) EMIT(VMOV_igen(((imm)>>7)&1, ((Dd)>>4)&1, ((imm)>>4)&7, (Dd)&15, 0b1110, 0, 0, (imm)&15))
|
||||
#define VMOVQ_8(Dd, imm) EMIT(VMOV_igen(((imm)>>7)&1, ((Dd)>>4)&1, ((imm)>>4)&7, (Dd)&15, 0b1110, 1, 0, (imm)&15))
|
||||
|
||||
#define VLD1LANE_gen(D, Rn, Vd, size, index_align, Rm) (0b1111<<28 | 0b0100<<24 | 1<<23 | (D)<<22 | 0b10<<20 | (Rn)<<16 | (Vd)<<12 | (size)<<10 | (index_align)<<4 | (Rm))
|
||||
#define VLD1LANE_8(Dd, Rn, index) EMIT(VLD1LANE_gen(((Dd)>>4)&1, Rn, (Dd)&15, 0, (index)<<1, 15))
|
||||
#define VLD1LANE_16(Dd, Rn, index) EMIT(VLD1LANE_gen(((Dd)>>4)&1, Rn, (Dd)&15, 1, (index)<<2, 15))
|
||||
@@ -644,6 +716,9 @@ Op is 20-27
|
||||
#define VBICD(Dd, Dn, Dm) EMIT(VBIC_gen(((Dd)>>4)&1, (Dd)&15, ((Dn)>>4)&1, (Dn)&15, ((Dm)>>4)&1, (Dm)&15, 0))
|
||||
#define VBICQ(Dd, Dn, Dm) EMIT(VBIC_gen(((Dd)>>4)&1, (Dd)&15, ((Dn)>>4)&1, (Dn)&15, ((Dm)>>4)&1, (Dm)&15, 1))
|
||||
|
||||
#define VBIC_igen(i, D, imm3, Vd, cmode, Q, imm4) (0b1111<<28 | 0b001<<25 | (i)<<24 | 1<<23 | (D)<<22 | (imm3)<<16 | (Vd)<<12 | (cmode)<<8 | (Q)<<6 | 0b11<<4 | (imm4))
|
||||
#define VBICQ_16_imm(Dd, imm) EMIT(VBIC_16_imm(((imm)>>7)&1, (Dd>>4)&1, ((imm)>>4)&7, (Dd)&15, 0b1001, 1, (imm)&15))
|
||||
|
||||
#define VCEQ_I_gen(size, D, Vn, Vd, N, Q, M, Vm) (0b1111<<28 | 0b0011<<24 | 0<<23 | (D)<<22 | (size)<<20 | (Vn)<<16 | (Vd)<<12 | 0b1000<<8 | (N)<<7 | (Q)<<6 | (M)<<5 | 1<<4 | (Vm))
|
||||
#define VCEQ_8(Dd, Dn, Dm) EMIT(VCEQ_I_gen(0, ((Dd)>>4)&1, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VCEQQ_8(Dd, Dn, Dm) EMIT(VCEQ_I_gen(0, ((Dd)>>4)&1, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
@@ -766,6 +841,8 @@ Op is 20-27
|
||||
#define VCVTn_S32_F32(Dd, Dm) EMIT(VCVT_NEON_gen(((Dd)>>4)&1, 2, (Dd)&15, 0b10, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#define VMULL_NEON_gen(U, D, size, Vn, Vd, op, N, M, Vm) (0b1111<<28 | 0b001<<25 | (U)<<24 | 1<<23 | (D)<<22 | (size)<<20 | (Vn)<<16 | (Vd)<<12 | 0b11<<10 | (op)<<9 | (N)<<7 | (M)<<5 | (Vm))
|
||||
#define VMULL_S16_S8(Dd, Dn, Dm) EMIT(VMULL_NEON_gen(0, ((Dd)>>4)&1, 0, (Dn)&15, (Dd)&15, 0, ((Dn)>>4)&1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VMULL_U16_U8(Dd, Dn, Dm) EMIT(VMULL_NEON_gen(1, ((Dd)>>4)&1, 0, (Dn)&15, (Dd)&15, 0, ((Dn)>>4)&1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VMULL_S32_S16(Dd, Dn, Dm) EMIT(VMULL_NEON_gen(0, ((Dd)>>4)&1, 1, (Dn)&15, (Dd)&15, 0, ((Dn)>>4)&1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VMULL_U32_U16(Dd, Dn, Dm) EMIT(VMULL_NEON_gen(1, ((Dd)>>4)&1, 1, (Dn)&15, (Dd)&15, 0, ((Dn)>>4)&1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VMULL_S64_S32(Dd, Dn, Dm) EMIT(VMULL_NEON_gen(0, ((Dd)>>4)&1, 2, (Dn)&15, (Dd)&15, 0, ((Dn)>>4)&1, ((Dm)>>4)&1, (Dm)&15))
|
||||
@@ -778,8 +855,8 @@ Op is 20-27
|
||||
#define VMUL_16(Dd, Dn, Dm) EMIT(VMUL_NEON_gen(0, ((Dd)>>4)&1, 0b01, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#define VEXT_gen(D, Vn, Vd, imm4, N, Q, M, Vm) (0b1111<<28 | 0b0010<<24 | 1<<23 | (D)<<22 | 0b11<<20 | (Vn)<<16 | (Vd)<<12 | (imm4)<<8 | (N)<<7 | (Q)<<6 | (M)<<5 | (Vm))
|
||||
#define VEXT_8(Dd, Dn, Dm, imm4) EMIT(VEXT_gen(((Dd)>>4)&1, (Dn)&15, (Dd)&15, imm4, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VEXTQ_8(Dd, Dn, Dm, imm4) EMIT(VEXT_gen(((Dd)>>4)&1, (Dn)&15, (Dd)&15, imm4, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VEXT_8(Dd, Dn, Dm, imm4) EMIT(VEXT_gen(((Dd)>>4)&1, (Dn)&15, (Dd)&15, (imm4), ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VEXTQ_8(Dd, Dn, Dm, imm4) EMIT(VEXT_gen(((Dd)>>4)&1, (Dn)&15, (Dd)&15, (imm4), ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#define VMVN_gen(D, size, Vd, Q, M, Vm) (0b1111<<28 | 0b0011<<24 | 1<<23 | (D)<<22 | 0b11<<20 | (size)<<18 | (Vd)<<12 | 0b1011<<7 | (Q)<<6 | (M)<<5 | 0<<4 | (Vm))
|
||||
#define VMVNQ(Dd, Dm) EMIT(VMVN_gen(((Dd)>>4)&1, 0, (Dd)&15, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
@@ -809,6 +886,10 @@ Op is 20-27
|
||||
#define VTBL1_8(Dd, Dn, Dm) EMIT(VTBL_gen(((Dd)>>4)&1, (Dn)&15, (Dd)&15, 0b00, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
// Vector Table lookup, take elements from Dn/Dn+1, and using lookup table Dm, put elements in Dd
|
||||
#define VTBL2_8(Dd, Dn, Dm) EMIT(VTBL_gen(((Dd)>>4)&1, (Dn)&15, (Dd)&15, 0b01, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
// Vector Table lookup eXtension, take elements from Dn, and using lookup table Dm, put elements in Dd, outer element untouched
|
||||
#define VTBLX1_8(Dd, Dn, Dm) EMIT(VTBL_gen(((Dd)>>4)&1, (Dn)&15, (Dd)&15, 0b00, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
// Vector Table lookup eXtension, take elements from Dn/Dn+1, and using lookup table Dm, put elements in Dd, outer element untouched
|
||||
#define VTBLX2_8(Dd, Dn, Dm) EMIT(VTBL_gen(((Dd)>>4)&1, (Dn)&15, (Dd)&15, 0b01, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#define VRECPE_gen(D, size, Vd, F, Q, M, Vm) (0b1111<<28 | 0b0011<<24 | 1<<23 | (D)<<22 | 0b11<<20 | (size)<<18 | 0b11<<16 | (Vd)<<12 | 0b010<<9 | (F)<<8 | (Q)<<6 | (M)<<5 | (Vm))
|
||||
// Vector Reciprocal Estimate of Dm to Dd
|
||||
@@ -818,11 +899,20 @@ Op is 20-27
|
||||
// Vector Reciprocal Step of Dn and Dm to Dd
|
||||
#define VRECPSQ_F32(Dd, Dn, Dm) EMIT(VRECPS_gen(((Dd)>>4)&1, 0, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#define VSWAP_gen(D, size, Vd, Q, M, Vm) (0b1111<<28 | 0b0011<<24 | 1<<23 | (D)<<22 | 0b11<20 | (size)<<18 | 0b10<<16 | (Vd)<<12 | 0b0000<<7 | (Q)<<6 | (M)<<5 | (Vm))
|
||||
#define VRSQRTE_gen(D, size, Vd, F, Q, M, Vm) (0b1111<<28 | 0b0011<<24 | 1<<23 | (D)<<22 | 0b11<<20 | (size)<<18 | 0b11<<16 | (Vd)<<12 | 0b010<<9 | (F)<<8 | 1<<7 | (Q)<<6 | (M)<<5 | (Vm))
|
||||
// Vector Reciprocal Square Root Estimate of Dm to Dd
|
||||
#define VRSQRTEQ_F32(Dd, Dm) EMIT(VRSQRTE_gen(((Dd)>>4)&1, 0b10, (Dd)&15, 1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#define VRSQRTS_gen(D, size, Vn, Vd, N, Q, M, Vm) (0b1111<<28 | 0b0010<<24 | 0<<23 | (D)<<22 | 1<<21 | (size)<<20 | (Vn)<<16 | (Vd)<<12 | 0b1111<<8 | (N)<<7 | (Q)<<6 | (M)<<5 | 1<<4 | (Vm))
|
||||
// Vector Reciprocal Square Root Step of Dn and Dm to Dd
|
||||
#define VRSQRTSQ_F32(Dd, Dn, Dm) EMIT(VRSQRTS_gen(((Dd)>>4)&1, 0, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
|
||||
#define VSWP_gen(D, size, Vd, Q, M, Vm) (0b1111<<28 | 0b0011<<24 | 1<<23 | (D)<<22 | 0b11<<20 | (size)<<18 | 0b10<<16 | (Vd)<<12 | 0b0000<<7 | (Q)<<6 | (M)<<5 | (Vm))
|
||||
// Swap Double vectors content
|
||||
#define VSWAP(Dd, Dm) EMIT(VSWAP_gen(((Dd)>>4)&1, 0b00, (Dd)&15, 0, ((Dm)>>4)&1, (Dm)&15)))
|
||||
#define VSWP(Dd, Dm) EMIT(VSWP_gen(((Dd)>>4)&1, 0b00, (Dd)&15, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
// Swap Quad vectors content
|
||||
#define VSWAPQ(Dd, Dm) EMIT(VSWAP_gen(((Dd)>>4)&1, 0b00, (Dd)&15, 1, ((Dm)>>4)&1, (Dm)&15)))
|
||||
#define VSWPQ(Dd, Dm) EMIT(VSWP_gen(((Dd)>>4)&1, 0b00, (Dd)&15, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#define VQADD_gen(U, D, size, Vn, Vd, N, Q, M, Vm) (0b1111<<28 | 0b001<<25 | (U)<<24 | (D)<<22 | (size)<<20 | (Vn)<<16 | (Vd)<<12 | 0b0000<<8 | (N)<<7 | (Q)<<6 | (M)<<5 | 1<<4 | (Vm))
|
||||
// Add with saturation unsigned 8bits
|
||||
@@ -903,4 +993,124 @@ Op is 20-27
|
||||
#define VNEGN_F32(Dd, Dm) EMIT(VNEGN_gen(((Dd)>>4)&1, 0b10, (Dd)&15, 1, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VNEGNQ_F32(Dd, Dm) EMIT(VNEGN_gen(((Dd)>>4)&1, 0b10, (Dd)&15, 1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#define VMINMAXF_gen(D, op, sz, Vn, Vd, N, Q, M, Vm) (0b1111<<28 | 0b0010<<24 | (D)<<22 | (op)<<21 | (sz)<<20 | (Vn)<<16 | (Vd)<<12 | 0b1111<<8 | (N)<<7 | (Q)<<6 | (M)<<5 | (Vm))
|
||||
#define VMINQ_F32(Dd, Dn, Dm) EMIT(VMINMAXF_gen(((Dd)>>4)&1, 1, 0, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VMAXQ_F32(Dd, Dn, Dm) EMIT(VMINMAXF_gen(((Dd)>>4)&1, 0, 0, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#define VABD_gen(U, D, size, Vn, Vd, N, Q, M, Vm) (0b1111<<28 | 1<<25 | (U)<<24 | 0<<23 | (D)<<22 | (size)<<20 | (Vn)<<16 | (Vd)<<12 | 0b0111<<8 | (N)<<7 | (Q)<<6 | (M)<<5 | (Vm))
|
||||
// Compute absolute difference of U8
|
||||
#define VABD_U8(Dd, Dn, Dm) EMIT(VABD_gen(1, ((Dd)>>4)&1, 0, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VABDQ_U8(Dd, Dn, Dm) EMIT(VABD_gen(1, ((Dd)>>4)&1, 0, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#define VPADAL_gen(D, size, Vd, op, Q, M, Vm) (0b1111<<28 | 0b0011<<24 | 1<<23 | (D)<<22 | 0b11<<20 | (size)<<18 | (Vd)<<12 | 0b0110<<8 | (op)<<7 | (Q)<<6 | (M)<<5 | (Vm))
|
||||
// Add pair of U8 from Dm, Add result in U16 in Dd (some position as U8U8)
|
||||
#define VPADAL_U8(Dd, Dm) EMIT(VPADAL_gen(((Dd)>>4)&1, 0b00, (Dd)&15, 1, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
// Add pair of U16 from Dm, Add result in U32 in Dd
|
||||
#define VPADAL_U16(Dd, Dm) EMIT(VPADAL_gen(((Dd)>>4)&1, 0b01, (Dd)&15, 1, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
// Add pair of U32 from Dm, Add result in U64 in Dd
|
||||
#define VPADAL_U32(Dd, Dm) EMIT(VPADAL_gen(((Dd)>>4)&1, 0b10, (Dd)&15, 1, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
// Add pair of S8 from Dm, Add result in S16 in Dd (some position as S8S8)
|
||||
#define VPADAL_S8(Dd, Dm) EMIT(VPADAL_gen(((Dd)>>4)&1, 0b00, (Dd)&15, 0, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
// Add pair of S16 from Dm, Add result in S32 in Dd
|
||||
#define VPADAL_S16(Dd, Dm) EMIT(VPADAL_gen(((Dd)>>4)&1, 0b01, (Dd)&15, 0, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
// Add pair of S32 from Dm, Add result in S64 in Dd
|
||||
#define VPADAL_S32(Dd, Dm) EMIT(VPADAL_gen(((Dd)>>4)&1, 0b10, (Dd)&15, 0, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
// Add pair of U8 from Dm, Add result in U16 in Dd (some position as U8U8)
|
||||
#define VPADALQ_U8(Dd, Dm) EMIT(VPADAL_gen(((Dd)>>4)&1, 0b00, (Dd)&15, 1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
// Add pair of U16 from Dm, Add result in U32 in Dd
|
||||
#define VPADALQ_U16(Dd, Dm) EMIT(VPADAL_gen(((Dd)>>4)&1, 0b01, (Dd)&15, 1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
// Add pair of U32 from Dm, Add result in U64 in Dd
|
||||
#define VPADALQ_U32(Dd, Dm) EMIT(VPADAL_gen(((Dd)>>4)&1, 0b10, (Dd)&15, 1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
// Add pair of S8 from Dm, Add result in S16 in Dd (some position as S8S8)
|
||||
#define VPADALQ_S8(Dd, Dm) EMIT(VPADAL_gen(((Dd)>>4)&1, 0b00, (Dd)&15, 0, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
// Add pair of S16 from Dm, Add result in S32 in Dd
|
||||
#define VPADALQ_S16(Dd, Dm) EMIT(VPADAL_gen(((Dd)>>4)&1, 0b01, (Dd)&15, 0, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
// Add pair of S32 from Dm, Add result in S64 in Dd
|
||||
#define VPADALQ_S32(Dd, Dm) EMIT(VPADAL_gen(((Dd)>>4)&1, 0b10, (Dd)&15, 0, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#define VPADDL_gen(D, size, Vd, op, Q, M, Vm) (0b1111<<28 | 0b0011<<24 | 1<<23 | (D)<<22 | 0b11<<20 | (size)<<18 | (Vd)<<12 | 0b0010<<8 | (op)<<7 | (Q)<<6 | (M)<<5 | (Vm))
|
||||
// Add pair of U8, store result in U16
|
||||
#define VPADDL_U8(Dd, Dm) EMIT(VPADDL_gen(((Dd)>>4)&1, 0b00, (Dd)&15, 1, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
// Add pair of U16, store result in U32
|
||||
#define VPADDL_U16(Dd, Dm) EMIT(VPADDL_gen(((Dd)>>4)&1, 0b01, (Dd)&15, 1, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
// Add pair of U32, store result in U64
|
||||
#define VPADDL_U32(Dd, Dm) EMIT(VPADDL_gen(((Dd)>>4)&1, 0b10, (Dd)&15, 1, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
// Add pair of S8, store result in S16
|
||||
#define VPADDL_S8(Dd, Dm) EMIT(VPADDL_gen(((Dd)>>4)&1, 0b00, (Dd)&15, 0, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
// Add pair of S16, store result in S32
|
||||
#define VPADDL_S16(Dd, Dm) EMIT(VPADDL_gen(((Dd)>>4)&1, 0b01, (Dd)&15, 0, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
// Add pair of S32, store result in S64
|
||||
#define VPADDL_S32(Dd, Dm) EMIT(VPADDL_gen(((Dd)>>4)&1, 0b10, (Dd)&15, 0, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
// Add pair of U8, store result in U16
|
||||
#define VPADDLQ_U8(Dd, Dm) EMIT(VPADDL_gen(((Dd)>>4)&1, 0b00, (Dd)&15, 1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
// Add pair of U16, store result in U32
|
||||
#define VPADDLQ_U16(Dd, Dm) EMIT(VPADDL_gen(((Dd)>>4)&1, 0b01, (Dd)&15, 1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
// Add pair of U32, store result in U64
|
||||
#define VPADDLQ_U32(Dd, Dm) EMIT(VPADDL_gen(((Dd)>>4)&1, 0b10, (Dd)&15, 1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
// Add pair of S8, store result in S16
|
||||
#define VPADDLQ_S8(Dd, Dm) EMIT(VPADDL_gen(((Dd)>>4)&1, 0b00, (Dd)&15, 0, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
// Add pair of S16, store result in S32
|
||||
#define VPADDLQ_S16(Dd, Dm) EMIT(VPADDL_gen(((Dd)>>4)&1, 0b01, (Dd)&15, 0, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
// Add pair of S32, store result in S64
|
||||
#define VPADDLQ_S32(Dd, Dm) EMIT(VPADDL_gen(((Dd)>>4)&1, 0b10, (Dd)&15, 0, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#define VPADD_gen(D, size, Vn, Vd, N, Q, M, Vm) (0b1111<<28 | 0b0010<<24 | (D)<<22 | (size)<<20 | (Vn)<<16 | (Vd)<<12 | 0b1011<<8 | (N)<<7 | (Q)<<6 | (M)<<5 | 1<<4 | (Vm))
|
||||
#define VPADD_8(Dd, Dn, Dm) EMIT(VPADD_gen(((Dd)>>4)&1, 0b00, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VPADD_16(Dd, Dn, Dm) EMIT(VPADD_gen(((Dd)>>4)&1, 0b01, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VPADD_32(Dd, Dn, Dm) EMIT(VPADD_gen(((Dd)>>4)&1, 0b10, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
// NO VPADDQ....
|
||||
|
||||
#define VPADD_Fgen(D, size, Vn, Vd, N, Q, M, Vm) (0b1111<<28 | 0b0011<<24 | (D)<<22 | (size)<<20 | (Vn)<<16 | (Vd)<<12 | 0b1101<<8 | (N)<<7 | (Q)<<6 | (M)<<5 | 0<<4 | (Vm))
|
||||
// Add pair of F32, store result in F32
|
||||
#define VPADD_F32(Dd, Dn, Dm) EMIT(VPADD_gen(((Dd)>>4)&1, 0, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#define VMINMAX_gen(U, D, size, Vn, Vd, N, Q, M, op, Vm) (0b1111<<28 | 0b001<<25 | (U)<<24 | (D)<<22 | (size)<<20 | (Vn)<<16 | (Vd)<<12 | 0b110<<8 | (N)<<7 | (Q)<<6 | (M)<<5 | (op)<<4 | (Vm))
|
||||
#define VMIN_U8(Dd, Dn, Dm) EMIT(VMINMAX_gen(1, ((Dd)>>4)&1, 0b00, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, 1, (Dm)&15))
|
||||
#define VMIN_U16(Dd, Dn, Dm) EMIT(VMINMAX_gen(1, ((Dd)>>4)&1, 0b01, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, 1, (Dm)&15))
|
||||
#define VMIN_U32(Dd, Dn, Dm) EMIT(VMINMAX_gen(1, ((Dd)>>4)&1, 0b10, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, 1, (Dm)&15))
|
||||
#define VMIN_U64(Dd, Dn, Dm) EMIT(VMINMAX_gen(1, ((Dd)>>4)&1, 0b11, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, 1, (Dm)&15))
|
||||
#define VMIN_S8(Dd, Dn, Dm) EMIT(VMINMAX_gen(0, ((Dd)>>4)&1, 0b00, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, 1, (Dm)&15))
|
||||
#define VMIN_S16(Dd, Dn, Dm) EMIT(VMINMAX_gen(0, ((Dd)>>4)&1, 0b01, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, 1, (Dm)&15))
|
||||
#define VMIN_S32(Dd, Dn, Dm) EMIT(VMINMAX_gen(0, ((Dd)>>4)&1, 0b10, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, 1, (Dm)&15))
|
||||
#define VMIN_S64(Dd, Dn, Dm) EMIT(VMINMAX_gen(0, ((Dd)>>4)&1, 0b11, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, 1, (Dm)&15))
|
||||
#define VMINQ_U8(Dd, Dn, Dm) EMIT(VMINMAX_gen(1, ((Dd)>>4)&1, 0b00, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, 1, (Dm)&15))
|
||||
#define VMINQ_U16(Dd, Dn, Dm) EMIT(VMINMAX_gen(1, ((Dd)>>4)&1, 0b01, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, 1, (Dm)&15))
|
||||
#define VMINQ_U32(Dd, Dn, Dm) EMIT(VMINMAX_gen(1, ((Dd)>>4)&1, 0b10, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, 1, (Dm)&15))
|
||||
#define VMINQ_U64(Dd, Dn, Dm) EMIT(VMINMAX_gen(1, ((Dd)>>4)&1, 0b11, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, 1, (Dm)&15))
|
||||
#define VMINQ_S8(Dd, Dn, Dm) EMIT(VMINMAX_gen(0, ((Dd)>>4)&1, 0b00, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, 1, (Dm)&15))
|
||||
#define VMINQ_S16(Dd, Dn, Dm) EMIT(VMINMAX_gen(0, ((Dd)>>4)&1, 0b01, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, 1, (Dm)&15))
|
||||
#define VMINQ_S32(Dd, Dn, Dm) EMIT(VMINMAX_gen(0, ((Dd)>>4)&1, 0b10, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, 1, (Dm)&15))
|
||||
#define VMINQ_S64(Dd, Dn, Dm) EMIT(VMINMAX_gen(0, ((Dd)>>4)&1, 0b11, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, 1, (Dm)&15))
|
||||
#define VMAX_U8(Dd, Dn, Dm) EMIT(VMINMAX_gen(1, ((Dd)>>4)&1, 0b00, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, 0, (Dm)&15))
|
||||
#define VMAX_U16(Dd, Dn, Dm) EMIT(VMINMAX_gen(1, ((Dd)>>4)&1, 0b01, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, 0, (Dm)&15))
|
||||
#define VMAX_U32(Dd, Dn, Dm) EMIT(VMINMAX_gen(1, ((Dd)>>4)&1, 0b10, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, 0, (Dm)&15))
|
||||
#define VMAX_U64(Dd, Dn, Dm) EMIT(VMINMAX_gen(1, ((Dd)>>4)&1, 0b11, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, 0, (Dm)&15))
|
||||
#define VMAX_S8(Dd, Dn, Dm) EMIT(VMINMAX_gen(0, ((Dd)>>4)&1, 0b00, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, 0, (Dm)&15))
|
||||
#define VMAX_S16(Dd, Dn, Dm) EMIT(VMINMAX_gen(0, ((Dd)>>4)&1, 0b01, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, 0, (Dm)&15))
|
||||
#define VMAX_S32(Dd, Dn, Dm) EMIT(VMINMAX_gen(0, ((Dd)>>4)&1, 0b10, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, 0, (Dm)&15))
|
||||
#define VMAX_S64(Dd, Dn, Dm) EMIT(VMINMAX_gen(0, ((Dd)>>4)&1, 0b11, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, 0, (Dm)&15))
|
||||
#define VMAXQ_U8(Dd, Dn, Dm) EMIT(VMINMAX_gen(1, ((Dd)>>4)&1, 0b00, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, 0, (Dm)&15))
|
||||
#define VMAXQ_U16(Dd, Dn, Dm) EMIT(VMINMAX_gen(1, ((Dd)>>4)&1, 0b01, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, 0, (Dm)&15))
|
||||
#define VMAXQ_U32(Dd, Dn, Dm) EMIT(VMINMAX_gen(1, ((Dd)>>4)&1, 0b10, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, 0, (Dm)&15))
|
||||
#define VMAXQ_U64(Dd, Dn, Dm) EMIT(VMINMAX_gen(1, ((Dd)>>4)&1, 0b11, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, 0, (Dm)&15))
|
||||
#define VMAXQ_S8(Dd, Dn, Dm) EMIT(VMINMAX_gen(0, ((Dd)>>4)&1, 0b00, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, 0, (Dm)&15))
|
||||
#define VMAXQ_S16(Dd, Dn, Dm) EMIT(VMINMAX_gen(0, ((Dd)>>4)&1, 0b01, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, 0, (Dm)&15))
|
||||
#define VMAXQ_S32(Dd, Dn, Dm) EMIT(VMINMAX_gen(0, ((Dd)>>4)&1, 0b10, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, 0, (Dm)&15))
|
||||
#define VMAXQ_S64(Dd, Dn, Dm) EMIT(VMINMAX_gen(0, ((Dd)>>4)&1, 0b11, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, 0, (Dm)&15))
|
||||
|
||||
#define VRHADD_gen(U, D, size, Vn, Vd, N, Q, M, Vm) (0b1111<<28 | 1<<25 | (U)<<24 | (D)<<22 | (size)<<20 | (Vn)<<16 | (Vd)<<12 | 0b0001<<8 | (N)<<7 | (Q)<<6 | (M)<<5 | (Vm))
|
||||
// Dd <= (Dn + Dm + 1)>>1
|
||||
#define VRHADD_U8(Dd, Dn, Dm) EMIT(VRHADD_gen(1, ((Dd)>>4)&1, 0b00, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VRHADD_U16(Dd, Dn, Dm) EMIT(VRHADD_gen(1, ((Dd)>>4)&1, 0b01, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VRHADD_U32(Dd, Dn, Dm) EMIT(VRHADD_gen(1, ((Dd)>>4)&1, 0b10, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VRHADD_S8(Dd, Dn, Dm) EMIT(VRHADD_gen(0, ((Dd)>>4)&1, 0b00, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VRHADD_S16(Dd, Dn, Dm) EMIT(VRHADD_gen(0, ((Dd)>>4)&1, 0b01, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VRHADD_S32(Dd, Dn, Dm) EMIT(VRHADD_gen(0, ((Dd)>>4)&1, 0b10, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VRHADDQ_U8(Dd, Dn, Dm) EMIT(VRHADD_gen(1, ((Dd)>>4)&1, 0b00, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VRHADDQ_U16(Dd, Dn, Dm) EMIT(VRHADD_gen(1, ((Dd)>>4)&1, 0b01, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VRHADDQ_U32(Dd, Dn, Dm) EMIT(VRHADD_gen(1, ((Dd)>>4)&1, 0b10, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VRHADDQ_S8(Dd, Dn, Dm) EMIT(VRHADD_gen(0, ((Dd)>>4)&1, 0b00, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VRHADDQ_S16(Dd, Dn, Dm) EMIT(VRHADD_gen(0, ((Dd)>>4)&1, 0b01, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VRHADDQ_S32(Dd, Dn, Dm) EMIT(VRHADD_gen(0, ((Dd)>>4)&1, 0b10, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#endif //__ARM_EMITTER_H__
|
||||
@@ -16,3 +16,12 @@ arm_epilog:
|
||||
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>
|
||||
@@ -11,6 +11,7 @@
|
||||
.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}
|
||||
|
||||
Executable → Regular
+5047
-886
File diff suppressed because it is too large.
Load diff
+474
-66
@@ -3,7 +3,6 @@
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86context.h"
|
||||
#include "dynarec.h"
|
||||
@@ -17,6 +16,7 @@
|
||||
#include "x86trace.h"
|
||||
#include "dynablock.h"
|
||||
#include "dynablock_private.h"
|
||||
#include "dynarec_private.h"
|
||||
#include "elfloader.h"
|
||||
#ifdef ARM
|
||||
#include "dynarec_arm.h"
|
||||
@@ -28,34 +28,124 @@
|
||||
|
||||
KHASH_MAP_INIT_INT(dynablocks, dynablock_t*)
|
||||
|
||||
KHASH_SET_INIT_INT(mark)
|
||||
|
||||
dynablocklist_t* NewDynablockList(uintptr_t base, uintptr_t text, int textsz)
|
||||
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 = kh_init(dynablocks);
|
||||
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)%s\n", kh_size((*dynablocks)->blocks), kh_n_buckets((*dynablocks)->blocks), ((*dynablocks)->direct)?" With Direct mapping enabled":"");
|
||||
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;
|
||||
kh_foreach_value((*dynablocks)->blocks, db,
|
||||
free(db->table);
|
||||
free(db);
|
||||
);
|
||||
kh_destroy(dynablocks, (*dynablocks)->blocks);
|
||||
if((*dynablocks)->direct)
|
||||
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);
|
||||
@@ -64,9 +154,260 @@ void FreeDynablockList(dynablocklist_t** 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)
|
||||
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*));
|
||||
@@ -76,13 +417,14 @@ void ConvertHash2Direct(dynablocklist_t* dynablocks)
|
||||
khint_t k;
|
||||
dynablock_t* db;
|
||||
uintptr_t key;
|
||||
uintptr_t start = dynablocks->text-dynablocks->base;
|
||||
uintptr_t end = dynablocks->text + dynablocks->textsz-dynablocks->base;
|
||||
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, &ret);
|
||||
k = kh_put(dynablocks, blocks, key-dynablocks->base, &ret);
|
||||
if(ret) { // don't try to insert if already done...
|
||||
kh_value(blocks, k) = db;
|
||||
}
|
||||
@@ -95,71 +437,65 @@ void ConvertHash2Direct(dynablocklist_t* dynablocks)
|
||||
}
|
||||
|
||||
#define MAGIC_SIZE 256
|
||||
/*
|
||||
return NULL if block is not found / cannot be created.
|
||||
Don't create if create==0
|
||||
*/
|
||||
dynablock_t* DBGetBlock(x86emu_t* emu, uintptr_t addr, int create, dynablock_t* current)
|
||||
|
||||
dynablock_t *AddNewDynablock(dynablocklist_t* dynablocks, uintptr_t addr, int with_marks, int* created)
|
||||
{
|
||||
// try the quickest way first: get parent of current and check if ok!
|
||||
dynablocklist_t *dynablocks = NULL;
|
||||
dynablock_t* block = NULL;
|
||||
if(current) {
|
||||
dynablocks = current->parent;
|
||||
if(dynablocks->direct && addr>=dynablocks->text && addr<=dynablocks->text+dynablocks->textsz) {
|
||||
block = dynablocks->direct[addr-dynablocks->text];
|
||||
if(block)
|
||||
return block;
|
||||
}
|
||||
if(!(addr>=dynablocks->text && addr<=dynablocks->text+dynablocks->textsz))
|
||||
dynablocks = NULL;
|
||||
}
|
||||
// nope, lets do the long way
|
||||
if(!dynablocks)
|
||||
dynablocks = GetDynablocksFromAddress(emu->context, addr);
|
||||
if(!dynablocks)
|
||||
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;
|
||||
// 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;
|
||||
// nope, put rwlock in read mode and check hash
|
||||
pthread_rwlock_rdlock(&dynablocks->rwlock_blocks);
|
||||
// but first, check again just in case it has been created while waiting for mutex
|
||||
if(dynablocks->direct && addr>=dynablocks->text && addr<=dynablocks->text+dynablocks->textsz)
|
||||
block = dynablocks->direct[addr-dynablocks->text];
|
||||
if(block) {
|
||||
pthread_rwlock_unlock(&dynablocks->rwlock_blocks);
|
||||
return block;
|
||||
}
|
||||
// check if the block exist
|
||||
khint_t k;
|
||||
int ret;
|
||||
khint_t k = kh_get(dynablocks, dynablocks->blocks, addr-dynablocks->base);
|
||||
if(k!=kh_end(dynablocks->blocks)) {
|
||||
/*atomic_store(&dynalock, 0);*/
|
||||
block = kh_value(dynablocks->blocks, k);
|
||||
pthread_rwlock_unlock(&dynablocks->rwlock_blocks);
|
||||
return block;
|
||||
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;
|
||||
}
|
||||
}
|
||||
// unlock now
|
||||
pthread_rwlock_unlock(&dynablocks->rwlock_blocks);
|
||||
// Blocks doesn't exist. If creation is not allow, just return NULL
|
||||
if(!create)
|
||||
|
||||
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_DEBUG, "Ask for DynaRec Block creation @%p\n", addr);
|
||||
if(dynablocks->direct && addr>=dynablocks->text && addr<=dynablocks->text+dynablocks->textsz)
|
||||
{
|
||||
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));
|
||||
@@ -168,12 +504,84 @@ dynablock_t* DBGetBlock(x86emu_t* emu, uintptr_t addr, int create, dynablock_t*
|
||||
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
|
||||
FillBlock(emu, block, addr);
|
||||
dynarec_log(LOG_DEBUG, " --- DynaRec Block created @%p (%p, 0x%x bytes)\n", addr, block->block, block->size);
|
||||
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;
|
||||
}
|
||||
@@ -1,25 +1,35 @@
|
||||
#ifndef __DYNABLOCK_PRIVATE_H_
|
||||
#define __DYNABLOCK_PRIVATE_H_
|
||||
|
||||
typedef struct dynablocklist_s dynablocklist_t;
|
||||
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;
|
||||
void* block;
|
||||
int size;
|
||||
uintptr_t* table;
|
||||
int tablesz;
|
||||
int done;
|
||||
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 kh_dynablocks_s kh_dynablocks_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;
|
||||
|
||||
|
||||
+64
-45
@@ -20,57 +20,72 @@
|
||||
#endif
|
||||
|
||||
#ifdef ARM
|
||||
void arm_prolog(x86emu_t* emu, void* addr);
|
||||
void arm_epilog();
|
||||
void arm_linker();
|
||||
int arm_tableupdate(void* jump, uintptr_t addr, void** table);
|
||||
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* block = DBGetBlock(emu, addr, 1, NULL); // keep a copy of parent block?
|
||||
int r;
|
||||
if(block==0) {
|
||||
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
|
||||
#ifdef ARM
|
||||
r = arm_tableupdate(arm_epilog, addr, table);
|
||||
if(r) dynarec_log(LOG_DEBUG, "Linker: failed to set table data @%p, for emu=%p\n", table, emu);
|
||||
#else
|
||||
table[0] = arm_epilog;
|
||||
table[1] = addr;
|
||||
#endif
|
||||
return arm_epilog;
|
||||
tableupdate(arm_epilog, addr, table);
|
||||
return arm_epilog_fast;
|
||||
}
|
||||
if(!block->done) {
|
||||
// not finished yet... leave linker
|
||||
#ifdef ARM
|
||||
r = arm_tableupdate(arm_linker, addr, table);
|
||||
if(r) dynarec_log(LOG_DEBUG, "Linker: failed to set table data @%p, for emu=%p\n", table, emu);
|
||||
#else
|
||||
table[0] = arm_linker;
|
||||
table[1] = addr;
|
||||
#endif
|
||||
return arm_epilog;
|
||||
//tableupdate(arm_linker, addr, table);
|
||||
return arm_epilog_fast;
|
||||
}
|
||||
if(!block->block) {
|
||||
// null block, but done, go to epilog
|
||||
#ifdef ARM
|
||||
r = arm_tableupdate(arm_epilog, addr, table);
|
||||
if(r) dynarec_log(LOG_DEBUG, "Linker: failed to set table data @%p, for emu=%p\n", table, emu);
|
||||
#else
|
||||
table[0] = arm_epilog;
|
||||
table[1] = addr;
|
||||
#endif
|
||||
return arm_epilog;
|
||||
// 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);
|
||||
}
|
||||
#ifdef ARM
|
||||
r = arm_tableupdate(block->block, addr, table);
|
||||
if(r) dynarec_log(LOG_DEBUG, "Linker: failed to set table data @%p, for emu=%p\n", table, emu);
|
||||
#else
|
||||
table[0] = block->block;
|
||||
table[1] = addr;
|
||||
#endif
|
||||
return block->block;
|
||||
}
|
||||
#endif
|
||||
@@ -93,15 +108,17 @@ void DynaCall(x86emu_t* emu, uintptr_t addr)
|
||||
R_EIP = addr;
|
||||
emu->df = d_none;
|
||||
dynablock_t* block = NULL;
|
||||
dynablock_t* current = NULL;
|
||||
while(!emu->quit) {
|
||||
block = DBGetBlock(emu, R_EIP, 1, block);
|
||||
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", R_EIP, emu);
|
||||
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) emu=%p\n", R_EIP, block->block, emu);
|
||||
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
|
||||
@@ -140,15 +157,17 @@ int DynaRun(x86emu_t* emu)
|
||||
#ifdef DYNAREC
|
||||
else {
|
||||
dynablock_t* block = NULL;
|
||||
dynablock_t* current = NULL;
|
||||
while(!emu->quit) {
|
||||
block = DBGetBlock(emu, R_EIP, 1, block);
|
||||
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", R_EIP, emu);
|
||||
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) emu=%p\n", R_EIP, block->block, emu);
|
||||
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);
|
||||
|
||||
+183
-25
@@ -2,6 +2,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86context.h"
|
||||
@@ -18,27 +19,141 @@
|
||||
#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, "%p: Exit x86emu\n", (void*)ip);
|
||||
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, "%p: Native call to %p\n", (void*)ip, (void*)a);
|
||||
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, "%p: %s\n", inst->addr, DecodeX86Trace(dec, inst->addr));
|
||||
dynarec_log(LOG_NONE, "%s%p: %s", (box86_dynarec_dump>1)?"\e[1m":"", ip, DecodeX86Trace(dec, inst->addr));
|
||||
} else {
|
||||
dynarec_log(LOG_NONE, "%p: ", inst->addr);
|
||||
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\n", name);
|
||||
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);
|
||||
@@ -46,15 +161,18 @@ 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(x86emu_t* emu, dynablock_t* block, 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.emu = emu;
|
||||
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;
|
||||
return;
|
||||
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));
|
||||
@@ -80,44 +198,84 @@ void FillBlock(x86emu_t* emu, dynablock_t* block, uintptr_t addr) {
|
||||
helper.insts[i].x86.jmp_insts = k;
|
||||
}
|
||||
}
|
||||
// remove useless flags calulation
|
||||
for(int i=0; i<helper.size; ++i)
|
||||
if(helper.insts[i].x86.flags==X86_FLAGS_CHANGE) {
|
||||
int done = 0;
|
||||
for(int i2=i+1; i2<helper.size+1 && done==0; ++i2) {
|
||||
if(helper.insts[i2].x86.barrier || helper.insts[i2].x86.jmp)
|
||||
done = 1;
|
||||
else if(helper.insts[i2].x86.flags==X86_FLAGS_USE)
|
||||
done = 1;
|
||||
else if(helper.insts[i2].x86.flags==X86_FLAGS_CHANGE) {
|
||||
done = 1;
|
||||
helper.insts[i].x86.flags=X86_FLAGS_NONE;
|
||||
}
|
||||
}
|
||||
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(emu->context, sz);
|
||||
void* p = (void*)AllocDynarecMap(sz, block->parent->nolinker);
|
||||
if(p==NULL) {
|
||||
free(helper.insts);
|
||||
return;
|
||||
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)
|
||||
dynarec_log(LOG_DEBUG, "Emitting %d bytes for %d x86 bytes\n", helper.arm_size, helper.isize);
|
||||
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+helper.arm_size); // need to clear the cache before execution...
|
||||
__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;
|
||||
}
|
||||
+578
-708
File diff suppressed because it is too large.
Load diff
+415
-144
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;
|
||||
}
|
||||
|
||||
@@ -28,24 +28,42 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
int32_t i32;
|
||||
uint32_t u32;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback, wb1, wb2;
|
||||
uint8_t wback;
|
||||
int fixedaddress;
|
||||
switch(opcode) {
|
||||
case 0x33:
|
||||
case 0x03:
|
||||
INST_NAME("ADD Gd, GS:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
grab_tlsdata(dyn, addr, ninst, x12);
|
||||
INST_NAME("GS:XOR Gd, Ed");
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO(x12);
|
||||
XOR_REG_LSL_IMM8(gd, gd, ed, 0);
|
||||
UFLAG_RES(gd);
|
||||
UFLAG_DF(1, d_xor32);
|
||||
UFLAGS(0);
|
||||
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:
|
||||
grab_tlsdata(dyn, addr, ninst, x12);
|
||||
INST_NAME("MOV GS:Ed, Gd");
|
||||
grab_tlsdata(dyn, addr, ninst, x12);
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) { // reg <= reg
|
||||
@@ -57,8 +75,8 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
|
||||
case 0x8B:
|
||||
grab_tlsdata(dyn, addr, ninst, x12);
|
||||
INST_NAME("MOV Gd, GS:Ed");
|
||||
grab_tlsdata(dyn, addr, ninst, x12);
|
||||
nextop=F8;
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) { // reg <= reg
|
||||
@@ -70,8 +88,8 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
|
||||
case 0xA1:
|
||||
grab_tlsdata(dyn, addr, ninst, x1);
|
||||
INST_NAME("MOV EAX, GS:Id");
|
||||
grab_tlsdata(dyn, addr, ninst, x1);
|
||||
i32 = F32S;
|
||||
if(i32>-4096 && i32<4096) {
|
||||
LDR_IMM9(xEAX, x1, i32);
|
||||
@@ -83,8 +101,8 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
|
||||
case 0xA3:
|
||||
grab_tlsdata(dyn, addr, ninst, x1);
|
||||
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);
|
||||
@@ -92,8 +110,8 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
|
||||
case 0xC7:
|
||||
grab_tlsdata(dyn, addr, ninst, x12);
|
||||
INST_NAME("MOV GS:Ed, Id");
|
||||
grab_tlsdata(dyn, addr, ninst, x12);
|
||||
nextop=F8;
|
||||
if((nextop&0xC0)==0xC0) { // reg <= i32
|
||||
i32 = F32S;
|
||||
@@ -108,7 +126,6 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
|
||||
default:
|
||||
*ok = 0;
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
|
||||
+248
-259
File diff suppressed because it is too large.
Load diff
+392
-66
@@ -29,7 +29,7 @@
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0); \
|
||||
a = fpu_get_scratch_quad(dyn); \
|
||||
VLD1Q_64(a, ed); \
|
||||
VLD1Q_8(a, ed); \
|
||||
}
|
||||
#define GETGX(a) \
|
||||
gd = (nextop&0x38)>>3; \
|
||||
@@ -39,17 +39,22 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
{
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop, u8;
|
||||
int32_t i32, i32_;
|
||||
int16_t i16;
|
||||
uint16_t u16;
|
||||
int32_t i32;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback, wb1, wb2;
|
||||
uint8_t wback, wb1;
|
||||
uint8_t eb1, eb2;
|
||||
int v0, v1;
|
||||
int q0, q1;
|
||||
int d0, d1;
|
||||
int s0, s1;
|
||||
int d0;
|
||||
int s0;
|
||||
int fixedaddress;
|
||||
int parity;
|
||||
|
||||
MAYUSE(d0);
|
||||
MAYUSE(q1);
|
||||
MAYUSE(eb1);
|
||||
MAYUSE(eb2);
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0x10:
|
||||
@@ -94,7 +99,6 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
GETGX(v0);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
// access register instead of memory is bad opcode!
|
||||
*ok = 0;
|
||||
DEFAULT;
|
||||
return addr;
|
||||
}
|
||||
@@ -107,7 +111,6 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
GETGX(v0);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
// access register instead of memory is bad opcode!
|
||||
*ok = 0;
|
||||
DEFAULT;
|
||||
return addr;
|
||||
}
|
||||
@@ -126,14 +129,25 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
VLDR_64(v0+1, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x15:
|
||||
INST_NAME("UNPCKHPD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
VMOVD(v0, v0+1);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7);
|
||||
VMOVD(v0+1, v1+1);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023-4, 3);
|
||||
VLDR_64(v0+1, ed, fixedaddress+4);
|
||||
}
|
||||
break;
|
||||
case 0x16:
|
||||
INST_NAME("MOVHPD Gx, Ed");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
// access register instead of memory is bad opcode!
|
||||
*ok = 0;
|
||||
DEFAULT;
|
||||
return addr;
|
||||
}
|
||||
@@ -146,7 +160,6 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
GETGX(v0);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
// access register instead of memory is bad opcode!
|
||||
*ok = 0;
|
||||
DEFAULT;
|
||||
return addr;
|
||||
}
|
||||
@@ -191,17 +204,56 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
// no special check...
|
||||
case 0x2F:
|
||||
if(opcode==0x2F) {INST_NAME("COMISD Gx, Ex");} else {INST_NAME("UCOMISD Gx, Ex");}
|
||||
UFLAGS(0);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
GETEX(q0);
|
||||
VCMP_F64(v0, q0);
|
||||
FCOMI(x1, x2);
|
||||
UFLAGS(1);
|
||||
break;
|
||||
|
||||
case 0x3A: // these are some SSE3 opcodes
|
||||
case 0x38: // SSSE3 opcodes
|
||||
nextop = F8;
|
||||
switch(nextop) {
|
||||
case 0x00:
|
||||
INST_NAME("PSHUFB Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0);
|
||||
q1 = fpu_get_scratch_quad(dyn);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
v0 = sse_get_reg(dyn, ninst, x1, nextop&7);
|
||||
VMOVQ(q1, v0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
|
||||
VLD1Q_64(q1, ed);
|
||||
}
|
||||
v1 = fpu_get_scratch_quad(dyn);
|
||||
VMOVQ_8(v1, 0b10001111);
|
||||
VANDQ(q1, q1, v1); // mask the index
|
||||
VMOVQ(v1, q0);
|
||||
VTBL2_8(q0+0, v1, q1+0);
|
||||
VTBL2_8(q0+1, v1, q1+1);
|
||||
break;
|
||||
case 0x04:
|
||||
INST_NAME("PMADDUBSW Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0);
|
||||
GETEX(q1);
|
||||
v0 = fpu_get_scratch_quad(dyn);
|
||||
VMULL_U16_U8(v0, q0+0, q1+0);
|
||||
VPADDLQ_U16(v0, v0);
|
||||
VQMOVN_S32(q0+0, v0);
|
||||
VMULL_U16_U8(v0, q0+1, q1+1);
|
||||
VPADDLQ_U16(v0, v0);
|
||||
VQMOVN_S32(q0+1, v0);
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x3A: // these are some more SSSE3 opcodes
|
||||
opcode = F8;
|
||||
switch(opcode) {
|
||||
case 0x0F:
|
||||
@@ -220,13 +272,12 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
}
|
||||
break;
|
||||
default:
|
||||
*ok = 0;
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
#define GO(GETFLAGS, NO, YES) \
|
||||
USEFLAG(1); \
|
||||
#define GO(GETFLAGS, NO, YES, F) \
|
||||
READFLAGS(F); \
|
||||
GETFLAGS; \
|
||||
nextop=F8; \
|
||||
GETGD; \
|
||||
@@ -243,107 +294,107 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("CMOVO Gw, Ew");
|
||||
GO( LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_OF]));
|
||||
CMPS_IMM8(x2, 1)
|
||||
, cNE, cEQ)
|
||||
, cNE, cEQ, X_OF)
|
||||
break;
|
||||
case 0x41:
|
||||
INST_NAME("CMOVNO Gw, Ew");
|
||||
GO( LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_OF]));
|
||||
CMPS_IMM8(x2, 1)
|
||||
, cEQ, cNE)
|
||||
, cEQ, cNE, X_OF)
|
||||
break;
|
||||
case 0x42:
|
||||
INST_NAME("CMOVC Gw, Ew");
|
||||
GO( LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_CF]));
|
||||
CMPS_IMM8(x2, 1)
|
||||
, cNE, cEQ)
|
||||
, cNE, cEQ, X_CF)
|
||||
break;
|
||||
case 0x43:
|
||||
INST_NAME("CMOVNC Gw, Ew");
|
||||
GO( LDR_IMM9(2, 0, offsetof(x86emu_t, flags[F_CF]));
|
||||
CMPS_IMM8(2, 1)
|
||||
, cEQ, cNE)
|
||||
, cEQ, cNE, X_CF)
|
||||
break;
|
||||
case 0x44:
|
||||
INST_NAME("CMOVZ Gw, Ew");
|
||||
GO( LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
CMPS_IMM8(x2, 1)
|
||||
, cNE, cEQ)
|
||||
, cNE, cEQ, X_ZF)
|
||||
break;
|
||||
case 0x45:
|
||||
INST_NAME("CMOVNZ Gw, Ew");
|
||||
GO( LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
CMPS_IMM8(x2, 1)
|
||||
, cEQ, cNE)
|
||||
, cEQ, cNE, X_ZF)
|
||||
break;
|
||||
case 0x46:
|
||||
INST_NAME("CMOVBE Gw, Ew");
|
||||
GO( LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_CF]));
|
||||
LDR_IMM9(x3, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
ORRS_REG_LSL_IMM8(x2, x2, x3, 0);
|
||||
, cEQ, cNE)
|
||||
ORRS_REG_LSL_IMM5(x2, x2, x3, 0);
|
||||
, cEQ, cNE, X_CF|X_ZF)
|
||||
break;
|
||||
case 0x47:
|
||||
INST_NAME("CMOVNBE Gw, Ew");
|
||||
GO( LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_CF]));
|
||||
LDR_IMM9(x3, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
ORRS_REG_LSL_IMM8(x2, x2, x3, 0);
|
||||
, cNE, cEQ)
|
||||
ORRS_REG_LSL_IMM5(x2, x2, x3, 0);
|
||||
, cNE, cEQ, X_CF|X_ZF)
|
||||
break;
|
||||
case 0x48:
|
||||
INST_NAME("CMOVS Gw, Ew");
|
||||
GO( LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_SF]));
|
||||
CMPS_IMM8(x2, 1)
|
||||
, cNE, cEQ)
|
||||
, cNE, cEQ, X_SF)
|
||||
break;
|
||||
case 0x49:
|
||||
INST_NAME("CMOVNS Gw, Ew");
|
||||
GO( LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_SF]));
|
||||
CMPS_IMM8(x2, 1)
|
||||
, cEQ, cNE)
|
||||
, cEQ, cNE, X_SF)
|
||||
break;
|
||||
case 0x4A:
|
||||
INST_NAME("CMOVP Gw, Ew");
|
||||
GO( LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_PF]));
|
||||
CMPS_IMM8(x2, 1)
|
||||
, cNE, cEQ)
|
||||
, cNE, cEQ, X_PF)
|
||||
break;
|
||||
case 0x4B:
|
||||
INST_NAME("CMOVNP Gw, Ew");
|
||||
GO( LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_PF]));
|
||||
CMPS_IMM8(x2, 1)
|
||||
, cEQ, cNE)
|
||||
, cEQ, cNE, X_PF)
|
||||
break;
|
||||
case 0x4C:
|
||||
INST_NAME("CMOVL Gw, Ew");
|
||||
GO( LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_SF]));
|
||||
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_OF]));
|
||||
CMPS_REG_LSL_IMM5(x1, x2, 0)
|
||||
, cEQ, cNE)
|
||||
, cEQ, cNE, X_OF|X_SF)
|
||||
break;
|
||||
case 0x4D:
|
||||
INST_NAME("CMOVGE Gw, Ew");
|
||||
GO( LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_SF]));
|
||||
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_OF]));
|
||||
CMPS_REG_LSL_IMM5(x1, x2, 0)
|
||||
, cNE, cEQ)
|
||||
, cNE, cEQ, X_OF|X_SF)
|
||||
break;
|
||||
case 0x4E:
|
||||
INST_NAME("CMOVLE Gw, Ew");
|
||||
GO( LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_SF]));
|
||||
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_OF]));
|
||||
XOR_REG_LSL_IMM8(x1, x1, x2, 0);
|
||||
XOR_REG_LSL_IMM5(x1, x1, x2, 0);
|
||||
LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
ORRS_REG_LSL_IMM8(x2, x1, x2, 0);
|
||||
, cEQ, cNE)
|
||||
ORRS_REG_LSL_IMM5(x2, x1, x2, 0);
|
||||
, cEQ, cNE, X_OF|X_SF|X_ZF)
|
||||
break;
|
||||
case 0x4F:
|
||||
INST_NAME("CMOVG Gw, Ew");
|
||||
GO( LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_SF]));
|
||||
LDR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_OF]));
|
||||
XOR_REG_LSL_IMM8(x1, x1, x2, 0);
|
||||
XOR_REG_LSL_IMM5(x1, x1, x2, 0);
|
||||
LDR_IMM9(x2, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
ORRS_REG_LSL_IMM8(x2, x1, x2, 0);
|
||||
, cNE, cEQ)
|
||||
ORRS_REG_LSL_IMM5(x2, x1, x2, 0);
|
||||
, cNE, cEQ, X_OF|X_SF|X_ZF)
|
||||
break;
|
||||
#undef GO
|
||||
|
||||
@@ -404,7 +455,55 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
fpu_putback_single_reg(dyn, ninst, v0, 1, s0);
|
||||
VEOR(v0+1, v0+1, v0+1);
|
||||
break;
|
||||
|
||||
case 0x5B:
|
||||
INST_NAME("CVTPS2DQ Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(v1);
|
||||
VCVTQ_F32_S32(v0, v1);
|
||||
break;
|
||||
case 0x5C:
|
||||
INST_NAME("SUBPD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0);
|
||||
GETGX(v0);
|
||||
VSUB_F64(v0, v0, q0);
|
||||
VSUB_F64(v0+1, v0+1, q0+1);
|
||||
break;
|
||||
case 0x5D:
|
||||
INST_NAME("MINPD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0);
|
||||
GETGX(v0);
|
||||
// MINPD: if any input is NaN, or Ex[i]<Gx[i], copy Ex[i] -> Gx[i]
|
||||
VCMP_F64(v0, q0);
|
||||
VMRS_APSR();
|
||||
VMOVcond_64(cPL, v0, q0);
|
||||
VCMP_F64(v0+1, q0+1);
|
||||
VMRS_APSR();
|
||||
VMOVcond_64(cPL, v0+1, q0+1);
|
||||
break;
|
||||
case 0x5E:
|
||||
INST_NAME("DIVPD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0);
|
||||
GETGX(v0);
|
||||
VDIV_F64(v0, v0, q0);
|
||||
VDIV_F64(v0+1, v0+1, q0+1);
|
||||
break;
|
||||
case 0x5F:
|
||||
INST_NAME("MAXPD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETEX(q0);
|
||||
GETGX(v0);
|
||||
// MAXPD: if any input is NaN, or Ex[i]>Gx[i], copy Ex[i] -> Gx[i]
|
||||
VCMP_F64(q0, v0);
|
||||
VMRS_APSR();
|
||||
VMOVcond_64(cPL, v0, q0);
|
||||
VCMP_F64(q0+1, v0+1);
|
||||
VMRS_APSR();
|
||||
VMOVcond_64(cPL, v0+1, q0+1);
|
||||
break;
|
||||
case 0x60:
|
||||
INST_NAME("PUNPCKLBW Gx,Ex");
|
||||
nextop = F8;
|
||||
@@ -435,7 +534,14 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
} else q1 = q0;
|
||||
VZIPQ_32(v0, q1);
|
||||
break;
|
||||
|
||||
case 0x63:
|
||||
INST_NAME("PACKSSWB Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0);
|
||||
GETEX(q1);
|
||||
VQMOVN_S16(q0+0, q0);
|
||||
VQMOVN_S16(q0+1, q1);
|
||||
break;
|
||||
case 0x64:
|
||||
INST_NAME("PCMPGTB Gx,Ex");
|
||||
nextop = F8;
|
||||
@@ -742,7 +848,6 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
}
|
||||
break;
|
||||
default:
|
||||
*ok = 0;
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
@@ -838,11 +943,16 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
}
|
||||
break;
|
||||
default:
|
||||
*ok = 0;
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x74:
|
||||
INST_NAME("PCMPEQB Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(q0);
|
||||
VCEQQ_8(v0, v0, q0);
|
||||
break;
|
||||
case 0x75:
|
||||
INST_NAME("PCMPEQW Gx,Ex");
|
||||
nextop = F8;
|
||||
@@ -867,10 +977,9 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
ed = xEAX + (nextop&7);
|
||||
VMOVfrDx_32(ed, v0, 0);
|
||||
} else {
|
||||
d0 = fpu_get_scratch_double(dyn);
|
||||
VMOVD(d0, v0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3);
|
||||
VSTR_32(d0*2, ed, fixedaddress);
|
||||
VMOVfrDx_32(x2, v0, 0); // to avoid Bus Error, using regular store
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0);
|
||||
STR_IMM9(x2, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0x7F:
|
||||
@@ -888,8 +997,8 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
|
||||
case 0xA3:
|
||||
INST_NAME("BT Ew, Gw");
|
||||
SETFLAGS(X_CF, SF_SET);
|
||||
nextop = F8;
|
||||
USEFLAG(1);
|
||||
GETGD; // there is an AND below, so 32bits is the same (no need for GETGW)
|
||||
GETEW(x1);
|
||||
AND_IMM8(x2, gd, 15);
|
||||
@@ -906,6 +1015,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("SHLD Ew, Gw, CL");
|
||||
UXTB(x3, xECX, 0);
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETEWW(x12, x1);
|
||||
GETGW(x2);
|
||||
if(opcode==0xA4) {
|
||||
@@ -914,13 +1024,12 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
}
|
||||
CALL(shld16, x1, (1<<wback));
|
||||
EWBACKW(x1);
|
||||
UFLAGS(1);
|
||||
break;
|
||||
|
||||
case 0xAB:
|
||||
INST_NAME("BTS Ew, Gw");
|
||||
SETFLAGS(X_CF, SF_SET);
|
||||
nextop = F8;
|
||||
USEFLAG(1);
|
||||
GETGD; // there is an AND below, to 32bits is the same
|
||||
GETEW(x12);
|
||||
AND_IMM8(x2, gd, 15);
|
||||
@@ -941,6 +1050,7 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("SHRD Ew, Gw, CL");
|
||||
UXTB(x3, xECX, 0);
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
GETEWW(x12, x1);
|
||||
GETGW(x2);
|
||||
if(opcode==0xAC) {
|
||||
@@ -949,11 +1059,11 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
}
|
||||
CALL(shrd16, x1, (1<<wback));
|
||||
EWBACKW(x1);
|
||||
UFLAGS(1);
|
||||
break;
|
||||
|
||||
case 0xAF:
|
||||
INST_NAME("IMUL Gw,Ew");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
nextop = F8;
|
||||
UFLAG_DF(x1, d_imul16);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
@@ -967,13 +1077,12 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
SMULBB(x2, gd, ed);
|
||||
UFLAG_RES(x2);
|
||||
BFI((xEAX+((nextop&0x38)>>3)), x2, 0, 16);
|
||||
UFLAGS(0);
|
||||
break;
|
||||
|
||||
case 0xB3:
|
||||
INST_NAME("BTR Ew, Gw");
|
||||
SETFLAGS(X_CF, SF_SET);
|
||||
nextop = F8;
|
||||
USEFLAG(1);
|
||||
GETGD; // there is an AND below, to 32bits is the same
|
||||
GETEW(x12);
|
||||
AND_IMM8(x2, gd, 15);
|
||||
@@ -1004,8 +1113,8 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
|
||||
case 0xBB:
|
||||
INST_NAME("BTC Ew, Gw");
|
||||
SETFLAGS(X_CF, SF_SET);
|
||||
nextop = F8;
|
||||
USEFLAG(1);
|
||||
GETGD; // there is an AND below, to 32bits is the same
|
||||
GETEW(x12);
|
||||
AND_IMM8(x2, gd, 15);
|
||||
@@ -1018,38 +1127,38 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
break;
|
||||
case 0xBC:
|
||||
INST_NAME("BSF Ew,Gw");
|
||||
SETFLAGS(X_ZF, SF_SET);
|
||||
nextop = F8;
|
||||
GETEW(x1); // Get EW
|
||||
TSTS_REG_LSL_IMM8(x1, x1, 0);
|
||||
TSTS_REG_LSL_IMM5(x1, x1, 0);
|
||||
XOR_IMM8_COND(cEQ, x1, x1, 1);
|
||||
B_MARK(cEQ);
|
||||
RBIT(x1, x1); // reverse
|
||||
CLZ(x2, x1); // x2 gets leading 0 == BSF
|
||||
BFI(xEAX+((nextop&0x38)>>3), x2, 0, 16);
|
||||
XOR_REG_LSL_IMM8(x1, x1, x1, 0); //ZF not set
|
||||
XOR_REG_LSL_IMM5(x1, x1, x1, 0); //ZF not set
|
||||
MARK;
|
||||
STR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
MOVW(x1, d_none);
|
||||
STR_IMM9(x1, xEmu, offsetof(x86emu_t, df));
|
||||
UFLAGS(1);
|
||||
break;
|
||||
case 0xBD:
|
||||
INST_NAME("BSR Ew,Gw");
|
||||
SETFLAGS(X_ZF, SF_SET);
|
||||
nextop = F8;
|
||||
GETEW(x1); // Get EW
|
||||
TSTS_REG_LSL_IMM8(x1, x1, 0);
|
||||
TSTS_REG_LSL_IMM5(x1, x1, 0);
|
||||
XOR_IMM8_COND(cEQ, x1, x1, 1);
|
||||
B_MARK(cEQ);
|
||||
MOV_REG_LSL_IMM5(x1, x1, 16); // put bits on top
|
||||
CLZ(x2, x1); // x2 gets leading 0
|
||||
RSB_IMM8(x2, x2, 15); // complement
|
||||
BFI(xEAX+((nextop&0x38)>>3), x2, 0, 16);
|
||||
XOR_REG_LSL_IMM8(x1, x1, x1, 0); //ZF not set
|
||||
XOR_REG_LSL_IMM5(x1, x1, x1, 0); //ZF not set
|
||||
MARK;
|
||||
STR_IMM9(x1, xEmu, offsetof(x86emu_t, flags[F_ZF]));
|
||||
MOVW(x1, d_none);
|
||||
STR_IMM9(x1, xEmu, offsetof(x86emu_t, df));
|
||||
UFLAGS(1);
|
||||
break;
|
||||
case 0xBE:
|
||||
INST_NAME("MOVSX Gw, Eb");
|
||||
@@ -1067,6 +1176,45 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
BFI(gd, x1, 0, 16);
|
||||
break;
|
||||
|
||||
case 0xC2:
|
||||
INST_NAME("CMPPD Gx, Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
GETEX(d0);
|
||||
u8 = F8;
|
||||
// 0
|
||||
VCMP_F64(v0, d0);
|
||||
VMRS_APSR();
|
||||
MOVW(x2, 0);
|
||||
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);
|
||||
// 1
|
||||
VCMP_F64(v0+1, d0+1);
|
||||
VMRS_APSR();
|
||||
MOVW(x2, 0);
|
||||
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+1, x2, x2);
|
||||
break;
|
||||
|
||||
case 0xC4:
|
||||
INST_NAME("PINSRW Gx,Ed,Ib");
|
||||
nextop = F8;
|
||||
@@ -1101,16 +1249,45 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
GETGX(v0);
|
||||
GETEX(v1);
|
||||
u8 = F8;
|
||||
q0 = fpu_get_scratch_quad(dyn);
|
||||
if(v0==v1 && u8==0) {
|
||||
VMOVD(q0+1, q0);
|
||||
} else {
|
||||
q0 = fpu_get_scratch_quad(dyn);
|
||||
VMOVD(q0, v0+(u8&1));
|
||||
VMOVD(q0+1, v1+((u8>>1)&1));
|
||||
VMOVQ(v0, q0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xD1:
|
||||
INST_NAME("PSRLW Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0);
|
||||
GETEX(q1);
|
||||
v0 = fpu_get_scratch_quad(dyn);
|
||||
VMOVD(v0, q1);
|
||||
VMOVD(v0+1, q1);
|
||||
VQMOVN_S64(v0, v0); // 2*q1 in 32bits now
|
||||
VMOVD(v0+1, v0);
|
||||
VQMOVN_S32(v0, v0); // 4*q1 in 16bits now
|
||||
VNEGN_16(v0, v0); // because we want SHR and not SHL
|
||||
VMOVD(v0+1, v0);
|
||||
VSHLQ_U16(q0, q0, v0);
|
||||
break;
|
||||
case 0xD2:
|
||||
INST_NAME("PSRLD Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0);
|
||||
GETEX(q1);
|
||||
v0 = fpu_get_scratch_quad(dyn);
|
||||
VMOVD(v0, q1);
|
||||
VMOVD(v0+1, q1);
|
||||
VQMOVN_S64(v0, v0); // 2*q1 in 32bits now
|
||||
VNEGN_32(v0, v0); // because we want SHR and not SHL
|
||||
VMOVD(v0+1, v0);
|
||||
VSHLQ_U32(q0, q0, v0);
|
||||
break;
|
||||
|
||||
case 0xD4:
|
||||
INST_NAME("PADDQ Gx,Ex");
|
||||
nextop = F8;
|
||||
@@ -1129,13 +1306,22 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("MOVQ Ex,Gx");
|
||||
nextop = F8;
|
||||
GETGX(q0);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 3);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
q1 = sse_get_reg_empty(dyn, ninst, x1, nextop&7);
|
||||
VMOVD(q1, q0);
|
||||
VEOR(q1+1, q1+1, q1+1);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3);
|
||||
VSTR_64(q0, ed, fixedaddress);
|
||||
// can be unaligned sometimes
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3);
|
||||
VSTR_64(q0, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0);
|
||||
VMOVfrV_D(x2, x3, q0);
|
||||
STR_IMM9(x2, ed, fixedaddress+0);
|
||||
STR_IMM9(x3, ed, fixedaddress+4);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1161,7 +1347,21 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
GETEX(q0);
|
||||
VANDQ(v0, v0, q0);
|
||||
break;
|
||||
case 0xDC:
|
||||
INST_NAME("PADDUSB Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0);
|
||||
GETEX(q1);
|
||||
VQADDQ_U8(q0, q0, q1);
|
||||
break;
|
||||
|
||||
case 0xDE:
|
||||
INST_NAME("PMAXUB Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0);
|
||||
GETEX(q1);
|
||||
VMAXQ_U8(q0, q0, q1);
|
||||
break;
|
||||
case 0xDF:
|
||||
INST_NAME("PANDN Gx,Ex");
|
||||
nextop = F8;
|
||||
@@ -1169,7 +1369,78 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
GETEX(q0);
|
||||
VBICQ(v0, q0, v0);
|
||||
break;
|
||||
case 0xE0:
|
||||
INST_NAME("PAVGB Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(q0);
|
||||
VRHADDQ_U8(v0, v0, q0);
|
||||
break;
|
||||
case 0xE1:
|
||||
INST_NAME("PSRAW Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0);
|
||||
GETEX(q1);
|
||||
v0 = fpu_get_scratch_quad(dyn);
|
||||
VMOVD(v0, q1);
|
||||
VMOVD(v0+1, q1);
|
||||
VQMOVN_S64(v0, v0); // 2*q1 in 32bits now
|
||||
VMOVD(v0+1, v0);
|
||||
VQMOVN_S32(v0, v0); // 4*q1 in 16bits now
|
||||
VNEGN_16(v0, v0); // because we want SHR and not SHL
|
||||
VMOVD(v0+1, v0);
|
||||
VSHLQ_S16(q0, q0, v0);
|
||||
break;
|
||||
case 0xE2:
|
||||
INST_NAME("PSRAD Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0);
|
||||
GETEX(q1);
|
||||
v0 = fpu_get_scratch_quad(dyn);
|
||||
VMOVD(v0, q1);
|
||||
VMOVD(v0+1, q1);
|
||||
VQMOVN_S64(v0, v0); // 2*q1 in 32bits now
|
||||
VNEGN_32(v0, v0); // because we want SHR and not SHL
|
||||
VMOVD(v0+1, v0);
|
||||
VSHLQ_S32(q0, q0, v0);
|
||||
break;
|
||||
case 0xE3:
|
||||
INST_NAME("PAVGW Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(q0);
|
||||
VRHADDQ_U16(v0, v0, q0);
|
||||
break;
|
||||
|
||||
case 0xE5:
|
||||
INST_NAME("PMULHW Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(v1);
|
||||
q0 = fpu_get_scratch_quad(dyn);
|
||||
VMULL_S32_S16(q0, v0, v1);
|
||||
VUZP_16(q0, q0+1);
|
||||
VMOVD(v0, q0+1);
|
||||
VMULL_S32_S16(q0, v0+1, v1+1);
|
||||
VUZP_16(q0, q0+1);
|
||||
VMOVD(v0+1, q0+1);
|
||||
break;
|
||||
case 0xE6:
|
||||
INST_NAME("CVTTPD2DQ Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0);
|
||||
GETEX(q1);
|
||||
if(q0<16) {
|
||||
VCVT_S32_F64(q0*2, q1);
|
||||
VCVT_S32_F64(q0*2+1, q1+1);
|
||||
} else {
|
||||
d0 = fpu_get_scratch_double(dyn);
|
||||
VCVT_S32_F64(d0*2, q1);
|
||||
VCVT_S32_F64(d0*2+1, q1+1);
|
||||
VMOVD(q0, d0);
|
||||
}
|
||||
VEOR(q0+1, q0+1, q0+1);
|
||||
break;
|
||||
case 0xE7:
|
||||
INST_NAME("MOVNTDQ Ex, Gx");
|
||||
nextop = F8;
|
||||
@@ -1183,6 +1454,20 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
VST1Q_32(v0, ed);
|
||||
}
|
||||
break;
|
||||
case 0xE8:
|
||||
INST_NAME("PSUBSB Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(q0);
|
||||
VQSUBQ_S8(v0, v0, q0);
|
||||
break;
|
||||
case 0xE9:
|
||||
INST_NAME("PSUBSW Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(q0);
|
||||
VQSUBQ_S16(v0, v0, q0);
|
||||
break;
|
||||
|
||||
case 0xEB:
|
||||
INST_NAME("POR Gx,Ex");
|
||||
@@ -1191,6 +1476,20 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
GETEX(q0);
|
||||
VORRQ(v0, v0, q0);
|
||||
break;
|
||||
case 0xEC:
|
||||
INST_NAME("PADDSB Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(q0);
|
||||
VQADDQ_S8(v0, v0, q0);
|
||||
break;
|
||||
case 0xED:
|
||||
INST_NAME("PADDSW Gx,Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(q0);
|
||||
VQADDQ_S16(v0, v0, q0);
|
||||
break;
|
||||
|
||||
case 0xEF:
|
||||
INST_NAME("PXOR Gx,Ex");
|
||||
@@ -1217,6 +1516,34 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
VTRN_32(q1, q1+1); // transpose EX
|
||||
VMULL_U64_U32(v0, q0, q1);
|
||||
break;
|
||||
case 0xF5:
|
||||
INST_NAME("PMADDWD Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(v0);
|
||||
GETEX(v1);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
q1 = fpu_get_scratch_quad(dyn);
|
||||
VMOVQ(q1, v1);
|
||||
} else {
|
||||
q1 = v1;
|
||||
}
|
||||
VUZP_16(v0, v0+1);
|
||||
VUZP_16(q1, q1+1);
|
||||
VSWP(v0, q1+1);
|
||||
VMULL_S32_S16(q1, q1, q1+1);
|
||||
VMULL_S32_S16(v0, v0, v0+1);
|
||||
VADDQ_32(v0, v0, q1);
|
||||
break;
|
||||
case 0xF6:
|
||||
INST_NAME("PSADBW Gx, Ex");
|
||||
nextop = F8;
|
||||
GETGX(q0);
|
||||
GETEX(q1);
|
||||
VABDQ_U8(q0, q0, q1);
|
||||
VPADDLQ_U8(q0, q0);
|
||||
VPADDLQ_U16(q0, q0);
|
||||
VPADDLQ_U32(q0, q0);
|
||||
break;
|
||||
|
||||
case 0xF8:
|
||||
INST_NAME("PSUBB Gx,Ex");
|
||||
@@ -1269,7 +1596,6 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
break;
|
||||
|
||||
default:
|
||||
*ok = 0;
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
|
||||
@@ -24,17 +24,12 @@
|
||||
|
||||
uintptr_t dynarec67(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;
|
||||
uint8_t nextop;
|
||||
int8_t i8;
|
||||
uint32_t u32;
|
||||
int32_t i32;
|
||||
int16_t i16;
|
||||
uint16_t u16;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback, wb1, wb2;
|
||||
int fixedaddress;
|
||||
switch(opcode) {
|
||||
MAYUSE(i32);
|
||||
nextop = F8;
|
||||
switch(nextop) {
|
||||
|
||||
|
||||
#define GO(NO, YES) \
|
||||
@@ -54,31 +49,30 @@ uintptr_t dynarec67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
}
|
||||
case 0xE0:
|
||||
INST_NAME("LOOPNZ (16bits)");
|
||||
USEFLAG(1);
|
||||
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_IMM8(x1, x1, 0);
|
||||
TSTS_REG_LSL_IMM5(x1, x1, 0);
|
||||
GO(cNE, cEQ);
|
||||
break;
|
||||
case 0xE1:
|
||||
INST_NAME("LOOPZ (16bits)");
|
||||
USEFLAG(1);
|
||||
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_IMM8(x1, x1, 0);
|
||||
TSTS_REG_LSL_IMM5(x1, x1, 0);
|
||||
GO(cEQ, cNE);
|
||||
break;
|
||||
case 0xE2:
|
||||
INST_NAME("LOOP (16bits)");
|
||||
USEFLAG(1);
|
||||
i8 = F8S;
|
||||
UXTH(x1, xECX, 0);
|
||||
SUBS_IMM8(x1, x1, 1);
|
||||
@@ -87,16 +81,14 @@ uintptr_t dynarec67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 0xE3:
|
||||
INST_NAME("JCXZ");
|
||||
USEFLAG(1);
|
||||
i8 = F8S;
|
||||
UXTH(x1, xECX, 0);
|
||||
TSTS_REG_LSL_IMM8(x1, x1, 0);
|
||||
TSTS_REG_LSL_IMM5(x1, x1, 0);
|
||||
GO(cNE, cEQ);
|
||||
break;
|
||||
#undef GO
|
||||
|
||||
default:
|
||||
*ok = 0;
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
|
||||
@@ -26,17 +26,19 @@
|
||||
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 u8;
|
||||
uint32_t u32;
|
||||
int32_t i32;
|
||||
int16_t i16;
|
||||
uint16_t u16;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback, wb1, wb2;
|
||||
int v1, v2, v3;
|
||||
int s0, s1, s2;
|
||||
int d0, d1;
|
||||
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:
|
||||
@@ -152,30 +154,48 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0:
|
||||
INST_NAME("FADD ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
GETED;
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
VMOVtoV(s0, ed);
|
||||
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);
|
||||
GETED;
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
VMOVtoV(s0, ed);
|
||||
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);
|
||||
GETED;
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
VMOVtoV(s0, ed);
|
||||
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);
|
||||
@@ -183,10 +203,16 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 3:
|
||||
INST_NAME("FCOMP ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
GETED;
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
VMOVtoV(s0, ed);
|
||||
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);
|
||||
@@ -195,45 +221,68 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 4:
|
||||
INST_NAME("FSUB ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
GETED;
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
VMOVtoV(s0, ed);
|
||||
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);
|
||||
GETED;
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
VMOVtoV(s0, ed);
|
||||
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);
|
||||
GETED;
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
VMOVtoV(s0, ed);
|
||||
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);
|
||||
GETED;
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
VMOVtoV(s0, ed);
|
||||
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:
|
||||
*ok = 0;
|
||||
DEFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,17 +34,18 @@ 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 u8;
|
||||
uint32_t u32;
|
||||
int32_t i32;
|
||||
int16_t i16;
|
||||
uint16_t u16;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback, wb1, wb2;
|
||||
uint8_t ed;
|
||||
uint8_t wback, wb1;
|
||||
int fixedaddress;
|
||||
int v1, v2, v3;
|
||||
int s0, s1, s2;
|
||||
int v1, v2;
|
||||
int s0;
|
||||
int i1, i2, i3;
|
||||
int parity;
|
||||
|
||||
MAYUSE(s0);
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
|
||||
switch(nextop) {
|
||||
|
||||
case 0xC0:
|
||||
@@ -262,7 +263,6 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xF5:
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
*ok = 0;
|
||||
DEFAULT;
|
||||
break;
|
||||
|
||||
@@ -271,37 +271,59 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0:
|
||||
INST_NAME("FLD ST0, float[ED]");
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
// to avoid bus error
|
||||
//VLDR_32(s0, ed, 0);
|
||||
LDR_IMM9(x2, ed, fixedaddress);
|
||||
VMOVtoV(s0, x2);
|
||||
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);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
VCVT_F32_F64(s0, v1);
|
||||
// to avoid bus error...
|
||||
//VSTR_32(s0, ed, 0);
|
||||
VMOVfrV(x2, s0);
|
||||
STR_IMM9(x2, ed, fixedaddress);
|
||||
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);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
VCVT_F32_F64(s0, v1);
|
||||
// to avoid bus error...
|
||||
//VSTR_32(s0, ed, 0);
|
||||
VMOVfrV(x2, s0);
|
||||
STR_IMM9(x2, ed, fixedaddress);
|
||||
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);
|
||||
@@ -318,7 +340,6 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
EWBACK;
|
||||
break;
|
||||
default:
|
||||
*ok = 0;
|
||||
DEFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,17 +26,21 @@
|
||||
uintptr_t dynarecDA(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;
|
||||
int32_t i32;
|
||||
int16_t i16;
|
||||
uint16_t u16;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback, wb1, wb2;
|
||||
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:
|
||||
@@ -47,11 +51,11 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
INST_NAME("FCMOVB ST0, STx");
|
||||
USEFLAG(1);
|
||||
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_IMM8(x1, x1, 0);
|
||||
TSTS_REG_LSL_IMM5(x1, x1, 0);
|
||||
VMOVcond_64(cNE, v1, v2); // F_CF==1
|
||||
break;
|
||||
case 0xC8:
|
||||
@@ -63,11 +67,11 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xCE:
|
||||
case 0xCF:
|
||||
INST_NAME("FCMOVE ST0, STx");
|
||||
USEFLAG(1);
|
||||
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_IMM8(x1, x1, 0);
|
||||
TSTS_REG_LSL_IMM5(x1, x1, 0);
|
||||
VMOVcond_64(cNE, v1, v2); // F_ZF==1
|
||||
break;
|
||||
case 0xD0:
|
||||
@@ -79,12 +83,12 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
INST_NAME("FCMOVBE ST0, STx");
|
||||
USEFLAG(1);
|
||||
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_IMM8(x1, x1, x2, 0);
|
||||
ORRS_REG_LSL_IMM5(x1, x1, x2, 0);
|
||||
VMOVcond_64(cNE, v1, v2); // F_CF==1 | F_ZF==1
|
||||
break;
|
||||
case 0xD8:
|
||||
@@ -96,17 +100,17 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xDE:
|
||||
case 0xDF:
|
||||
INST_NAME("FCMOVU ST0, STx");
|
||||
USEFLAG(1);
|
||||
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_IMM8(x1, x1, 0);
|
||||
TSTS_REG_LSL_IMM5(x1, x1, 0);
|
||||
VMOVcond_64(cNE, v1, v2); // F_PF==1
|
||||
break;
|
||||
case 0xE9:
|
||||
INST_NAME("FUCOMPP ST0, STx");
|
||||
INST_NAME("FUCOMPP ST0, ST1");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 1);
|
||||
VCMP_F64(v1, v2);
|
||||
FCOM(x1, x2);
|
||||
x87_do_pop(dyn, ninst);
|
||||
@@ -123,7 +127,6 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xF8:
|
||||
case 0xF9:
|
||||
case 0xFD:
|
||||
*ok = 0;
|
||||
DEFAULT;
|
||||
break;
|
||||
|
||||
|
||||
@@ -22,22 +22,22 @@
|
||||
#include "dynarec_arm_functions.h"
|
||||
#include "dynarec_arm_helper.h"
|
||||
|
||||
static double maxint32 = (double)0x7fffffff;
|
||||
|
||||
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;
|
||||
uint32_t u32;
|
||||
int32_t i32;
|
||||
int16_t i16;
|
||||
uint16_t u16;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback, wb1, wb2;
|
||||
int v1, v2, v3;
|
||||
int s0, s1, s2;
|
||||
int d0;
|
||||
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:
|
||||
@@ -49,11 +49,11 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
INST_NAME("FCMOVNB ST0, STx");
|
||||
USEFLAG(1);
|
||||
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_IMM8(x1, x1, 0);
|
||||
TSTS_REG_LSL_IMM5(x1, x1, 0);
|
||||
VMOVcond_64(cEQ, v1, v2); // F_CF==0
|
||||
break;
|
||||
case 0xC8:
|
||||
@@ -65,11 +65,11 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xCE:
|
||||
case 0xCF:
|
||||
INST_NAME("FCMOVNE ST0, STx");
|
||||
USEFLAG(1);
|
||||
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_IMM8(x1, x1, 0);
|
||||
TSTS_REG_LSL_IMM5(x1, x1, 0);
|
||||
VMOVcond_64(cEQ, v1, v2); // F_ZF==0
|
||||
break;
|
||||
case 0xD0:
|
||||
@@ -81,12 +81,12 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
INST_NAME("FCMOVNBE ST0, STx");
|
||||
USEFLAG(1);
|
||||
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_IMM8(x1, x1, x2, 0);
|
||||
ORRS_REG_LSL_IMM5(x1, x1, x2, 0);
|
||||
VMOVcond_64(cEQ, v1, v2); // F_CF==0 | F_ZF==0
|
||||
break;
|
||||
case 0xD8:
|
||||
@@ -98,11 +98,11 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xDE:
|
||||
case 0xDF:
|
||||
INST_NAME("FCMOVNU ST0, STx");
|
||||
USEFLAG(1);
|
||||
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_IMM8(x1, x1, 0);
|
||||
TSTS_REG_LSL_IMM5(x1, x1, 0);
|
||||
VMOVcond_64(cEQ, v1, v2); // F_PF==0
|
||||
break;
|
||||
case 0xE2:
|
||||
@@ -127,12 +127,11 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xEE:
|
||||
case 0xEF:
|
||||
INST_NAME("FUCOMI ST0, STx");
|
||||
UFLAGS(0);
|
||||
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);
|
||||
UFLAGS(1);
|
||||
break;
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
@@ -143,12 +142,11 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
INST_NAME("FCOMI ST0, STx");
|
||||
UFLAGS(0);
|
||||
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);
|
||||
UFLAGS(1);
|
||||
break;
|
||||
|
||||
case 0xE0:
|
||||
@@ -157,7 +155,6 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xE5:
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
*ok = 0;
|
||||
DEFAULT;
|
||||
break;
|
||||
|
||||
@@ -166,9 +163,15 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0:
|
||||
INST_NAME("FILD ST0, Ed");
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
GETED;
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
VMOVtoV(s0, ed);
|
||||
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:
|
||||
@@ -267,7 +270,6 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
x87_do_pop(dyn, ninst);
|
||||
break;
|
||||
default:
|
||||
*ok = 0;
|
||||
DEFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,17 +26,16 @@
|
||||
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 u8;
|
||||
uint32_t u32;
|
||||
int32_t i32;
|
||||
int16_t i16;
|
||||
uint16_t u16;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback, wb1, wb2;
|
||||
int v1, v2, v3;
|
||||
int s0, s1;
|
||||
int d0, d1;
|
||||
uint8_t wback;
|
||||
int v1, v2;
|
||||
int d1;
|
||||
int fixedaddress;
|
||||
int parity;
|
||||
|
||||
MAYUSE(d1);
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
|
||||
switch(nextop) {
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
@@ -150,34 +149,66 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0:
|
||||
INST_NAME("FADD ST0, double[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3);
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
VLDR_64(d1, wback, fixedaddress);
|
||||
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);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3);
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
VLDR_64(d1, wback, fixedaddress);
|
||||
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);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3);
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
VLDR_64(d1, wback, fixedaddress);
|
||||
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);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3);
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
VLDR_64(d1, wback, fixedaddress);
|
||||
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);
|
||||
@@ -185,33 +216,65 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 4:
|
||||
INST_NAME("FSUB ST0, double[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3);
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
VLDR_64(d1, wback, fixedaddress);
|
||||
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);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3);
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
VLDR_64(d1, wback, fixedaddress);
|
||||
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);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3);
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
VLDR_64(d1, wback, fixedaddress);
|
||||
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);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3);
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
VLDR_64(d1, wback, fixedaddress);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -27,15 +27,13 @@
|
||||
uintptr_t dynarecDD(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;
|
||||
int32_t i32;
|
||||
int16_t i16;
|
||||
uint16_t u16;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback, wb1, wb2;
|
||||
int fixedaddress;
|
||||
int v1, v2, v3;
|
||||
int parity;
|
||||
uint8_t ed;
|
||||
int v1, v2;
|
||||
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
|
||||
switch(nextop) {
|
||||
case 0xC0:
|
||||
@@ -133,7 +131,6 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xFD:
|
||||
case 0xFE:
|
||||
case 0xFF:
|
||||
*ok = 0;
|
||||
DEFAULT;
|
||||
break;
|
||||
|
||||
@@ -147,9 +144,16 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
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, 255, 0);
|
||||
LDRD_IMM8(x2, ed, fixedaddress);
|
||||
VMOVtoV_D(v1, x2, x3);
|
||||
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:
|
||||
@@ -163,18 +167,47 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 2:
|
||||
INST_NAME("FST double");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3);
|
||||
VSTR_64(v1, ed, fixedaddress); // check alignment?
|
||||
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);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3);
|
||||
VSTR_64(v1, ed, fixedaddress); // check alignment?
|
||||
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:
|
||||
*ok = 0;
|
||||
DEFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,16 +25,10 @@
|
||||
uintptr_t dynarecDE(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;
|
||||
int32_t i32;
|
||||
int16_t i16;
|
||||
uint16_t u16;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback, wb1, wb2;
|
||||
int v1, v2, v3;
|
||||
int s0, s1, s2;
|
||||
int fixedaddress;
|
||||
int v1, v2;
|
||||
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
|
||||
switch(nextop) {
|
||||
case 0xC0:
|
||||
@@ -146,7 +140,6 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xDD:
|
||||
case 0xDE:
|
||||
case 0xDF:
|
||||
*ok = 0;
|
||||
DEFAULT;
|
||||
break;
|
||||
|
||||
@@ -154,7 +147,6 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
default:
|
||||
*ok = 0;
|
||||
DEFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,17 +28,18 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
{
|
||||
uint8_t nextop = F8;
|
||||
uint8_t u8;
|
||||
uint32_t u32;
|
||||
int32_t i32;
|
||||
int16_t i16;
|
||||
uint16_t u16;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback, wb1, wb2;
|
||||
int v1, v2, v3;
|
||||
int s0, s1;
|
||||
int d0;
|
||||
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");
|
||||
@@ -57,13 +58,12 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xEE:
|
||||
case 0xEF:
|
||||
INST_NAME("FUCOMIP ST0, STx");
|
||||
UFLAGS(0);
|
||||
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);
|
||||
UFLAGS(1);
|
||||
break;
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
@@ -74,13 +74,12 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
INST_NAME("FCOMIP ST0, STx");
|
||||
UFLAGS(0);
|
||||
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);
|
||||
UFLAGS(1);
|
||||
break;
|
||||
|
||||
case 0xC0:
|
||||
@@ -130,7 +129,6 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xFD:
|
||||
case 0xFE:
|
||||
case 0xFF:
|
||||
*ok = 0;
|
||||
DEFAULT;
|
||||
break;
|
||||
|
||||
@@ -235,7 +233,6 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
x87_do_pop(dyn, ninst);
|
||||
break;
|
||||
default:
|
||||
*ok = 0;
|
||||
DEFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
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]));
|
||||
}
|
||||
}
|
||||
@@ -25,14 +25,6 @@
|
||||
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
|
||||
uint8_t u8;
|
||||
uint32_t u32;
|
||||
int32_t i32;
|
||||
int16_t i16;
|
||||
uint16_t u16;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback, wb1, wb2;
|
||||
int fixedaddress;
|
||||
int locked = 0;
|
||||
switch(nextop) {
|
||||
// generic case
|
||||
|
||||
@@ -22,32 +22,41 @@
|
||||
#include "dynarec_arm_functions.h"
|
||||
#include "dynarec_arm_helper.h"
|
||||
|
||||
// Get Ex as a double, not a quad
|
||||
// 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 { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3); \
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 3); \
|
||||
a = fpu_get_scratch_double(dyn); \
|
||||
VLDR_64(a, ed, fixedaddress); \
|
||||
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;
|
||||
int32_t i32, i32_;
|
||||
int16_t i16;
|
||||
uint32_t u32;
|
||||
uint16_t u16;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback, wb1, wb2;
|
||||
uint8_t eb1, eb2;
|
||||
uint8_t wback;
|
||||
int v0, v1;
|
||||
int q0, q1;
|
||||
int d0, d1;
|
||||
int s0, s1;
|
||||
int s0;
|
||||
int fixedaddress;
|
||||
int parity;
|
||||
|
||||
MAYUSE(s0);
|
||||
MAYUSE(d1);
|
||||
MAYUSE(d0);
|
||||
|
||||
switch(nextop) {
|
||||
|
||||
case 0x10:
|
||||
@@ -256,6 +265,26 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
}
|
||||
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;
|
||||
@@ -267,20 +296,19 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
MOVW(x2, 0);
|
||||
u8 = F8;
|
||||
switch(u8&7) {
|
||||
case 0: MVN_COND_REG_LSL_IMM8(cEQ, x2, x2, 0); break; // Equal
|
||||
case 1: MVN_COND_REG_LSL_IMM8(cCC, x2, x2, 0); break; // Less than
|
||||
case 2: MVN_COND_REG_LSL_IMM8(cLS, x2, x2, 0); break; // Less or equal
|
||||
case 3: MVN_COND_REG_LSL_IMM8(cVS, x2, x2, 0); break; // NaN
|
||||
case 4: MVN_COND_REG_LSL_IMM8(cNE, x2, x2, 0); break; // Not Equal (or unordered on ARM, not on X86...)
|
||||
case 5: MVN_COND_REG_LSL_IMM8(cPL, x2, x2, 0); break; // Greater or equal or unordered
|
||||
case 6: MVN_COND_REG_LSL_IMM8(cHI, x2, x2, 0); break; // Greater or unordered
|
||||
case 7: MVN_COND_REG_LSL_IMM8(cVC, x2, x2, 0); break; // not NaN
|
||||
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:
|
||||
*ok = 0;
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
|
||||
+218
-146
@@ -34,27 +34,42 @@
|
||||
} \
|
||||
a *= 2; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3); \
|
||||
a = fpu_get_scratch_single(dyn); \
|
||||
VLDR_32(a, ed, fixedaddress); \
|
||||
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, i32_;
|
||||
int32_t i32;
|
||||
uint32_t u32;
|
||||
int16_t i16;
|
||||
uint16_t u16;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback, wb1, wb2;
|
||||
uint8_t eb1, eb2;
|
||||
uint8_t wback;
|
||||
int fixedaddress;
|
||||
int v0, v1;
|
||||
int s0, s1;
|
||||
int s0, s1, s2;
|
||||
int d0, d1;
|
||||
int q0, q1;
|
||||
int q0;
|
||||
int parity;
|
||||
|
||||
MAYUSE(s1);
|
||||
MAYUSE(s2);
|
||||
MAYUSE(i32);
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0x10:
|
||||
@@ -117,6 +132,17 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
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");
|
||||
@@ -186,104 +212,118 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
case 0x51:
|
||||
INST_NAME("SQRTSS Gx, Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
GETEX(s0, d0);
|
||||
if(v0<16)
|
||||
d1 = v0;
|
||||
else {
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
VMOV_64(d1, v0);
|
||||
}
|
||||
VSQRT_F32(d1*2, s0);
|
||||
if(v0!=d1) {
|
||||
VMOV_64(v0, d1);
|
||||
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;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
GETEX(s0, d0);
|
||||
if(v0<16)
|
||||
d1 = v0;
|
||||
else {
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
VMOV_64(d1, v0);
|
||||
}
|
||||
s1 = fpu_get_scratch_single(dyn);
|
||||
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(s1, 0b01110000);
|
||||
VDIV_F32(s0, s1, s0);
|
||||
VSQRT_F32(d1*2, s0);
|
||||
if(v0!=d1) {
|
||||
VMOV_64(v0, d1);
|
||||
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;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
GETEX(s0, d0);
|
||||
if(v0<16)
|
||||
d1 = v0;
|
||||
else {
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
VMOV_64(d1, v0);
|
||||
}
|
||||
s1 = fpu_get_scratch_single(dyn);
|
||||
VMOV_i_32(s1, 0b01110000);
|
||||
VDIV_F32(d1*2, s1, s0);
|
||||
if(v0!=d1) {
|
||||
VMOV_64(v0, d1);
|
||||
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;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
GETEX(s0, d0);
|
||||
if(v0<16)
|
||||
d1 = v0;
|
||||
else {
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
VMOV_64(d1, v0);
|
||||
}
|
||||
VADD_F32(d1*2, d1*2, s0);
|
||||
if(v0!=d1) {
|
||||
VMOV_64(v0, d1);
|
||||
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;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
GETEX(s0, d0);
|
||||
if(v0<16)
|
||||
d1 = v0;
|
||||
else {
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
VMOV_64(d1, v0);
|
||||
}
|
||||
VMUL_F32(d1*2, d1*2, s0);
|
||||
if(v0!=d1) {
|
||||
VMOV_64(v0, d1);
|
||||
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;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
GETGX(v0);
|
||||
GETEX(s0, d0);
|
||||
VCVT_F64_F32(v0, s0);
|
||||
break;
|
||||
@@ -304,75 +344,87 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
case 0x5C:
|
||||
INST_NAME("SUBSS Gx, Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
GETEX(s0, d0);
|
||||
if(v0<16)
|
||||
d1 = v0;
|
||||
else {
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
VMOV_64(d1, v0);
|
||||
}
|
||||
VSUB_F32(d1*2, d1*2, s0);
|
||||
if(v0!=d1) {
|
||||
VMOV_64(v0, d1);
|
||||
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;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
GETEX(s0, d0);
|
||||
if(v0<16)
|
||||
d1 = v0;
|
||||
else {
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
VMOV_64(d1, v0);
|
||||
}
|
||||
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(d1*2, s0);
|
||||
VCMP_F32(s0, s1);
|
||||
VMRS_APSR();
|
||||
VMOVcond_32(cPL, d1*2, s0);
|
||||
if(v0!=d1) {
|
||||
VMOV_64(v0, d1);
|
||||
VMOVcond_32(cPL, s0, s1);
|
||||
if(v0!=d0) {
|
||||
VMOV_64(v0, d0);
|
||||
}
|
||||
break;
|
||||
case 0x5E:
|
||||
INST_NAME("DIVSS Gx, Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
GETEX(s0, d0);
|
||||
if(v0<16)
|
||||
d1 = v0;
|
||||
else {
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
VMOV_64(d1, v0);
|
||||
}
|
||||
VDIV_F32(d1*2, d1*2, s0);
|
||||
if(v0!=d1) {
|
||||
VMOV_64(v0, d1);
|
||||
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;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
GETEX(s0, d0);
|
||||
if(v0<16)
|
||||
d1 = v0;
|
||||
else {
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
VMOV_64(d1, v0);
|
||||
}
|
||||
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(s0, d1*2);
|
||||
VCMP_F32(s1, s0);
|
||||
VMRS_APSR();
|
||||
VMOVcond_32(cPL, d1*2, s0);
|
||||
if(v0!=d1) {
|
||||
VMOV_64(v0, d1);
|
||||
VMOVcond_32(cPL, s0, s1);
|
||||
if(v0!=d0) {
|
||||
VMOV_64(v0, d0);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -465,37 +517,57 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
}
|
||||
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;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
GETEX(s0, d0);
|
||||
if(v0<16)
|
||||
d1 = v0;
|
||||
else {
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
VMOV_64(d1, v0);
|
||||
}
|
||||
VCMP_F32(d1*2, s0);
|
||||
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_IMM8(cEQ, x2, x2, 0); break; // Equal
|
||||
case 1: MVN_COND_REG_LSL_IMM8(cCC, x2, x2, 0); break; // Less than
|
||||
case 2: MVN_COND_REG_LSL_IMM8(cLS, x2, x2, 0); break; // Less or equal
|
||||
case 3: MVN_COND_REG_LSL_IMM8(cVS, x2, x2, 0); break; // NaN
|
||||
case 4: MVN_COND_REG_LSL_IMM8(cNE, x2, x2, 0); break; // Not Equal (or unordered on ARM, not on X86...)
|
||||
case 5: MVN_COND_REG_LSL_IMM8(cPL, x2, x2, 0); break; // Greater or equal or unordered
|
||||
case 6: MVN_COND_REG_LSL_IMM8(cHI, x2, x2, 0); break; // Greater or unordered
|
||||
case 7: MVN_COND_REG_LSL_IMM8(cVC, x2, x2, 0); break; // not NaN
|
||||
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:
|
||||
*ok = 0;
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
#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"
|
||||
@@ -135,97 +138,71 @@ void arm_fld(x86emu_t* emu, uint8_t* ed)
|
||||
STld(0).ref = ST0.ll;
|
||||
}
|
||||
|
||||
void arm_cpuid(x86emu_t* emu, uint32_t tmp32u)
|
||||
void arm_ud(x86emu_t* emu)
|
||||
{
|
||||
switch(tmp32u) {
|
||||
case 0x0:
|
||||
// emulate a P4
|
||||
R_EAX = 0x80000004;
|
||||
// return GenuineIntel
|
||||
R_EBX = 0x756E6547;
|
||||
R_EDX = 0x49656E69;
|
||||
R_ECX = 0x6C65746E;
|
||||
break;
|
||||
case 0x1:
|
||||
R_EAX = 0x00000101; // familly and all
|
||||
R_EBX = 0; // Brand indexe, CLFlush, Max APIC ID, Local APIC ID
|
||||
R_EDX = 1 // fpu
|
||||
| 1<<8 // cmpxchg8
|
||||
| 1<<11 // sep (sysenter & sysexit)
|
||||
| 1<<15 // cmov
|
||||
| 1<<19 // clflush (seems to be with SSE2)
|
||||
| 1<<23 // mmx
|
||||
//| 1<<24 // fxsr (fxsave, fxrestore)
|
||||
| 1<<25 // SSE
|
||||
| 1<<26 // SSE2
|
||||
;
|
||||
R_ECX = 1<<12 // fma
|
||||
| 1<<13 // cx16 (cmpxchg16)
|
||||
; // also 1<<0 is SSE3 and 1<<9 is SSSE3
|
||||
break;
|
||||
case 0x2: // TLB and Cache info. Sending 1st gen P4 info...
|
||||
R_EAX = 0x665B5001;
|
||||
R_EBX = 0x00000000;
|
||||
R_ECX = 0x00000000;
|
||||
R_EDX = 0x007A7000;
|
||||
break;
|
||||
|
||||
case 0x4: // Cache info
|
||||
switch (R_ECX) {
|
||||
case 0: // L1 data cache
|
||||
R_EAX = (1 | (1<<5) | (1<<8)); //type
|
||||
R_EBX = (63 | (7<<22)); // size
|
||||
R_ECX = 63;
|
||||
R_EDX = 1;
|
||||
break;
|
||||
case 1: // L1 inst cache
|
||||
R_EAX = (2 | (1<<5) | (1<<8)); //type
|
||||
R_EBX = (63 | (7<<22)); // size
|
||||
R_ECX = 63;
|
||||
R_EDX = 1;
|
||||
break;
|
||||
case 2: // L2 cache
|
||||
R_EAX = (3 | (2<<5) | (1<<8)); //type
|
||||
R_EBX = (63 | (15<<22)); // size
|
||||
R_ECX = 4095;
|
||||
R_EDX = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
R_EAX = 0x00000000;
|
||||
R_EBX = 0x00000000;
|
||||
R_ECX = 0x00000000;
|
||||
R_EDX = 0x00000000;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x5: //mwait info
|
||||
R_EAX = 0;
|
||||
R_EBX = 0;
|
||||
R_ECX = 1 | 2;
|
||||
R_EDX = 0;
|
||||
break;
|
||||
case 0x6: // thermal
|
||||
case 0x9: // direct cache access
|
||||
case 0xA: // Architecture performance monitor
|
||||
R_EAX = 0;
|
||||
R_EBX = 0;
|
||||
R_ECX = 0;
|
||||
R_EDX = 0;
|
||||
break;
|
||||
case 0x7: // extended bits...
|
||||
/*if(R_ECX==0) R_EAX = 0;
|
||||
else*/ R_EAX = R_ECX = R_EBX = R_EDX = 0;
|
||||
break;
|
||||
|
||||
case 0x80000000: // max extended
|
||||
break; // no extended, so return same value as beeing the max value!
|
||||
default:
|
||||
printf_log(LOG_INFO, "Warning, CPUID command %X unsupported (ECX=%08x)\n", tmp32u, R_ECX);
|
||||
R_EAX = 0;
|
||||
}
|
||||
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)
|
||||
{
|
||||
@@ -246,7 +223,7 @@ int fpu_get_scratch_quad(dynarec_arm_t* dyn)
|
||||
return i/2; // Return a Dx, not a Qx
|
||||
}
|
||||
// Reset scratch regs counter
|
||||
int fpu_reset_scratch(dynarec_arm_t* dyn)
|
||||
void fpu_reset_scratch(dynarec_arm_t* dyn)
|
||||
{
|
||||
dyn->fpu_scratch = 0;
|
||||
}
|
||||
@@ -282,9 +259,50 @@ void fpu_free_reg_quad(dynarec_arm_t* dyn, int reg)
|
||||
dyn->fpuused[i] = dyn->fpuused[i+1] = 0;
|
||||
}
|
||||
// Reset fpu regs counter
|
||||
int fpu_reset_reg(dynarec_arm_t* dyn)
|
||||
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
|
||||
}
|
||||
@@ -25,8 +25,12 @@ 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_cpuid(x86emu_t* emu, uint32_t tmp32u);
|
||||
void arm_ud(x86emu_t* emu);
|
||||
|
||||
// Get an FPU single scratch reg
|
||||
int fpu_get_scratch_single(dynarec_arm_t* dyn);
|
||||
@@ -35,7 +39,7 @@ 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
|
||||
int fpu_reset_scratch(dynarec_arm_t* dyn);
|
||||
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
|
||||
@@ -45,6 +49,9 @@ 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
|
||||
int fpu_reset_reg(dynarec_arm_t* dyn);
|
||||
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__
|
||||
+279
-327
File diff suppressed because it is too large.
Load diff
@@ -171,8 +171,10 @@
|
||||
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))
|
||||
@@ -182,6 +184,8 @@
|
||||
#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) \
|
||||
@@ -199,69 +203,104 @@
|
||||
#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_IMM8(s2, s2, s1, 0); \
|
||||
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_IMM8(s2, s2, s1, 0); \
|
||||
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_IMM8(s2, s2, s2, 0); \
|
||||
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 */ \
|
||||
UBFX(s2, s1, 0, 1); \
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, flags[F_CF])); \
|
||||
UBFX(s2, s1, 1, 1); \
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, flags[F_PF])); \
|
||||
UBFX(s2, s1, 2, 1); \
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, flags[F_ZF])); \
|
||||
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));
|
||||
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 UFLAGS
|
||||
#define UFLAGS(A) dyn->cleanflags=A
|
||||
#endif
|
||||
#ifndef USEFLAG
|
||||
// USEFLAG will check status of defered flags the call update flags if needed. x3 will be used
|
||||
#define USEFLAG(A) \
|
||||
if(!dyn->cleanflags) { \
|
||||
if(A) { \
|
||||
|
||||
#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_IMM8(x3, x3, 0); \
|
||||
TSTS_REG_LSL_IMM5(x3, x3, 0); \
|
||||
i32 = (GETMARKF)-(dyn->arm_size+8); \
|
||||
Bcond(cEQ, i32); \
|
||||
CALL_(UpdateFlags, -1, 0); \
|
||||
MARKF; \
|
||||
dyn->cleanflags=1; \
|
||||
} \
|
||||
} \
|
||||
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
|
||||
#define BARRIER(A) if (dyn->insts && !dyn->insts[ninst].x86.barrier) dyn->insts[ninst].x86.barrier = A
|
||||
#define UFLAG_OP1(A) if(dyn->insts && dyn->insts[ninst].x86.flags) {STR_IMM9(A, 0, offsetof(x86emu_t, op1));}
|
||||
#define UFLAG_OP2(A) if(dyn->insts && dyn->insts[ninst].x86.flags) {STR_IMM9(A, 0, offsetof(x86emu_t, op2));}
|
||||
#define UFLAG_OP12(A1, A2) if(dyn->insts && dyn->insts[ninst].x86.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.flags) {STR_IMM9(A, 0, offsetof(x86emu_t, res));}
|
||||
#define UFLAG_DF(r, A) if(dyn->insts && dyn->insts[ninst].x86.flags) {MOVW(r, A); STR_IMM9(r, 0, offsetof(x86emu_t, df));}
|
||||
#define UFLAG_IF if(dyn->insts && dyn->insts[ninst].x86.flags)
|
||||
#ifndef DEFAULT
|
||||
#define DEFAULT BARRIER(2)
|
||||
#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)
|
||||
@@ -281,6 +320,7 @@ void* arm_linker(x86emu_t* emu, void** table, uintptr_t addr);
|
||||
|
||||
#define dynarec00 STEPNAME(dynarec00)
|
||||
#define dynarec0F STEPNAME(dynarec0F)
|
||||
#define dynarecFS STEPNAME(dynarecFS)
|
||||
#define dynarecGS STEPNAME(dynarecGS)
|
||||
#define dynarec66 STEPNAME(dynarec66)
|
||||
#define dynarec67 STEPNAME(dynarec67)
|
||||
@@ -303,7 +343,9 @@ void* arm_linker(x86emu_t* emu, void** table, uintptr_t addr);
|
||||
#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)
|
||||
@@ -314,9 +356,65 @@ void* arm_linker(x86emu_t* emu, void** table, uintptr_t addr);
|
||||
#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_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)
|
||||
@@ -341,6 +439,9 @@ void* arm_linker(x86emu_t* emu, void** table, uintptr_t addr);
|
||||
#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)
|
||||
@@ -358,7 +459,9 @@ 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);
|
||||
@@ -372,6 +475,62 @@ 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
|
||||
@@ -425,9 +584,9 @@ 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);
|
||||
@@ -444,4 +603,27 @@ uintptr_t dynarec660F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
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__
|
||||
@@ -24,39 +24,31 @@
|
||||
#error No STEP defined
|
||||
#endif
|
||||
|
||||
#include "dynarec_arm_helper.h"
|
||||
|
||||
void arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
|
||||
{
|
||||
uint8_t nextop, opcode;
|
||||
int ok = 1;
|
||||
int ninst = 0;
|
||||
uintptr_t ip = addr;
|
||||
uintptr_t natcall;
|
||||
int retn;
|
||||
uint8_t gd, ed;
|
||||
int8_t i8;
|
||||
int32_t i32, tmp;
|
||||
uint8_t u8;
|
||||
uint8_t gb1, gb2, eb1, eb2;
|
||||
uint32_t u32;
|
||||
int need_epilog = 1;
|
||||
uint8_t wback, wb1, wb2;
|
||||
int fixedaddress;
|
||||
dyn->tablei = 0;
|
||||
dyn->sons_size = 0;
|
||||
// Clean up (because there are multiple passes)
|
||||
dyn->cleanflags = 0;
|
||||
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(dyn->emu->dec && box86_dynarec_trace) {
|
||||
if((dyn->emu->trace_end == 0)
|
||||
|| ((ip >= dyn->emu->trace_start) && (ip <= dyn->emu->trace_end))) {
|
||||
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);
|
||||
@@ -76,8 +68,21 @@ void arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
|
||||
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->cleanflags = 0;
|
||||
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) {
|
||||
@@ -85,4 +90,5 @@ void arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
|
||||
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);
|
||||
}
|
||||
@@ -2,15 +2,21 @@
|
||||
#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 UFLAGS(A) {}
|
||||
#define USEFLAGS(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; \
|
||||
dynarec_log(LOG_INFO, "%p: Dynarec stopped because of Opcode %02X %02X %02X %02X %02X %02X %02X\n", \
|
||||
ip, PKip(0), \
|
||||
PKip(1), PKip(2), PKip(3), \
|
||||
PKip(4), PKip(5), PKip(6))
|
||||
#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))
|
||||
@@ -1,15 +1,17 @@
|
||||
#define INIT
|
||||
#define FINI \
|
||||
dyn->insts[ninst].x86.addr = addr; \
|
||||
dyn->insts[ninst].x86.flags = X86_FLAGS_USE; \
|
||||
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 UFLAGS(A) dyn->insts[ninst+(A?1:0)].x86.flags = X86_FLAGS_CHANGE
|
||||
#define USEFLAG(A) dyn->insts[ninst].x86.flags = X86_FLAGS_USE
|
||||
#define JUMP(A) dyn->insts[ninst].x86.jmp = 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)
|
||||
#define INST_NAME(name)
|
||||
@@ -6,3 +6,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
|
||||
@@ -1,12 +1,33 @@
|
||||
#define INIT
|
||||
#define FINI
|
||||
#define EMIT(A) \
|
||||
if(box86_dynarec_log>=LOG_DUMP) {dynarec_log(LOG_NONE, "\t%08x\t%s\n", (A), arm_print(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, ...) dynarec_log(A, __VA_ARGS__);
|
||||
#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_log>=LOG_DUMP) printf_x86_instruction(dyn->emu->dec, &dyn->insts[ninst].x86, name)
|
||||
#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; \
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ typedef struct instruction_arm_s {
|
||||
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 {
|
||||
@@ -21,12 +22,12 @@ typedef struct dynarec_arm_s {
|
||||
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
|
||||
x86emu_t* emu;
|
||||
uintptr_t* table; // jump table
|
||||
int tablesz; // size of the jump table
|
||||
int tablei; // index
|
||||
int cleanflags; // flags are clean (CMP or TST have been just executed)
|
||||
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
|
||||
@@ -35,7 +36,17 @@ typedef struct dynarec_arm_s {
|
||||
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_
|
||||
@@ -1,19 +1,37 @@
|
||||
#ifndef __DYNAREC_PRIVATE_H_
|
||||
#define __DYNAREC_PRIVATE_H_
|
||||
|
||||
#define X86_FLAGS_NONE 0
|
||||
#define X86_FLAGS_CHANGE 1
|
||||
#define X86_FLAGS_USE 2
|
||||
// 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 flags; // flags for this instruction (see X86_FLAGS_XXXX)
|
||||
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_
|
||||
#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>
|
||||
@@ -284,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) {
|
||||
|
||||
+413
-214
@@ -4,7 +4,12 @@
|
||||
#include <string.h>
|
||||
#include <elf.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/sysmacros.h>
|
||||
#include <sys/types.h>
|
||||
#include <link.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "box86version.h"
|
||||
#include "elfloader.h"
|
||||
@@ -21,10 +26,12 @@
|
||||
#include "box86stack.h"
|
||||
#include "callback.h"
|
||||
#include "dynarec.h"
|
||||
#include "box86stack.h"
|
||||
#ifdef DYNAREC
|
||||
#include "dynablock.h"
|
||||
#endif
|
||||
#include "../emu/x86emu_private.h"
|
||||
#include "x86tls.h"
|
||||
|
||||
void* my__IO_2_1_stderr_ = NULL;
|
||||
void* my__IO_2_1_stdin_ = NULL;
|
||||
@@ -44,6 +51,10 @@ elfheader_t* LoadAndCheckElfHeader(FILE* f, const char* name, int exec)
|
||||
if(!h)
|
||||
return NULL;
|
||||
|
||||
if ((h->path = realpath(name, NULL)) == NULL) {
|
||||
h->path = (char*)malloc(1);
|
||||
h->path[0] = '\0';
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
@@ -53,10 +64,11 @@ void FreeElfHeader(elfheader_t** head)
|
||||
return;
|
||||
elfheader_t *h = *head;
|
||||
#ifdef DYNAREC
|
||||
dynarec_log(LOG_INFO, "Free Dynarec block for %s\n", h->name);
|
||||
dynarec_log(LOG_INFO, "Free Dynarec block for %s\n", h->path);
|
||||
FreeDynablockList(&h->blocks);
|
||||
#endif
|
||||
free(h->name);
|
||||
free(h->path);
|
||||
free(h->PHEntries);
|
||||
free(h->SHEntries);
|
||||
free(h->SHStrTab);
|
||||
@@ -124,6 +136,8 @@ int CalcLoadAddr(elfheader_t* head)
|
||||
|
||||
const char* ElfName(elfheader_t* head)
|
||||
{
|
||||
if(!head)
|
||||
return "(noelf)";
|
||||
return head->name;
|
||||
}
|
||||
|
||||
@@ -138,23 +152,91 @@ int AllocElfMemory(box86context_t* context, elfheader_t* head, int mainbin)
|
||||
}
|
||||
if(!offs)
|
||||
offs = head->vaddr;
|
||||
printf_log(LOG_DEBUG, "Allocating 0x%x memory @%p for Elf \"%s\"\n", head->memsz, (void*)offs, head->name);
|
||||
void* p = mmap((void*)offs, head->memsz
|
||||
, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS | ((offs)?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*)offs, head->memsz, head->align, head->name);
|
||||
return 1;
|
||||
if(head->vaddr) {
|
||||
head->multiblock_n = 0; // count PHEntrie with LOAD
|
||||
for (int i=0; i<head->numPHEntries; ++i)
|
||||
if(head->PHEntries[i].p_type == PT_LOAD)
|
||||
++head->multiblock_n;
|
||||
head->multiblock_size = (uint32_t*)calloc(head->multiblock_n, sizeof(uint32_t));
|
||||
head->multiblock_offs = (uintptr_t*)calloc(head->multiblock_n, sizeof(uintptr_t));
|
||||
head->multiblock = (void**)calloc(head->multiblock_n, sizeof(void*));
|
||||
// and now, create all individual blocks
|
||||
head->memory = (char*)0xffffffff;
|
||||
int n = 0;
|
||||
for (int i=0; i<head->numPHEntries; ++i)
|
||||
if(head->PHEntries[i].p_type == PT_LOAD) {
|
||||
Elf32_Phdr * e = &head->PHEntries[i];
|
||||
uintptr_t bstart = e->p_vaddr;
|
||||
uint32_t bsize = e->p_memsz;
|
||||
uintptr_t balign = e->p_align;
|
||||
if (balign) balign = balign-1; else balign = 1;
|
||||
if(balign<4095) balign = 4095;
|
||||
uintptr_t bend = (bstart + bsize + balign)&(~balign);
|
||||
bstart &= ~balign;
|
||||
int ok = 0;
|
||||
for (int j=0; !ok && j<n; ++j) {
|
||||
uintptr_t start = head->multiblock_offs[j];
|
||||
uintptr_t end = head->multiblock_offs[j] + head->multiblock_size[j];
|
||||
start &= ~balign;
|
||||
if(((bstart>=start) && (bstart<=end)) || ((bend>=start) && (bend<=end)) || ((bstart<start) && (bend>end))) {
|
||||
// merge
|
||||
ok = 1;
|
||||
if(bstart<start)
|
||||
head->multiblock_offs[j] = bstart;
|
||||
head->multiblock_size[j] = ((bend>end)?bend:end) - head->multiblock_offs[j];
|
||||
--head->multiblock_n;
|
||||
}
|
||||
}
|
||||
if(!ok) {
|
||||
head->multiblock_offs[n] = bstart;
|
||||
head->multiblock_size[n] = bend - head->multiblock_offs[n];
|
||||
++n;
|
||||
}
|
||||
}
|
||||
for (int i=0; i<head->multiblock_n; ++i) {
|
||||
|
||||
printf_log(LOG_DEBUG, "Allocating 0x%x memory @%p for Elf \"%s\"\n", head->multiblock_size[i], (void*)head->multiblock_offs[i], head->name);
|
||||
void* p = mmap((void*)head->multiblock_offs[i], head->multiblock_size[i]
|
||||
, PROT_READ | PROT_WRITE | PROT_EXEC
|
||||
, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED
|
||||
, -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->multiblock_offs[i], head->multiblock_size[i], head->align, head->name);
|
||||
return 1;
|
||||
}
|
||||
head->multiblock[i] = p;
|
||||
if(p<(void*)head->memory)
|
||||
head->memory = (char*)p;
|
||||
}
|
||||
} else {
|
||||
// vaddr is 0, load everything has a One block
|
||||
printf_log(LOG_DEBUG, "Allocating 0x%x memory @%p for Elf \"%s\"\n", head->memsz, (void*)offs, head->name);
|
||||
void* p = mmap((void*)offs, head->memsz
|
||||
, PROT_READ | PROT_WRITE | PROT_EXEC
|
||||
, MAP_PRIVATE | MAP_ANONYMOUS | (((offs)?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*)offs, 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);
|
||||
|
||||
head->multiblock_n = 1;
|
||||
head->multiblock_size = (uint32_t*)calloc(head->multiblock_n, sizeof(uint32_t));
|
||||
head->multiblock_offs = (uintptr_t*)calloc(head->multiblock_n, sizeof(uintptr_t));
|
||||
head->multiblock = (void**)calloc(head->multiblock_n, sizeof(void*));
|
||||
head->multiblock_size[0] = head->memsz;
|
||||
head->multiblock_offs[0] = (uintptr_t)p;
|
||||
head->multiblock[0] = p;
|
||||
}
|
||||
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);
|
||||
|
||||
head->tlsbase = AddTLSPartition(context, head->tlssize);
|
||||
|
||||
#ifdef DYNAREC
|
||||
head->blocks = NewDynablockList((uintptr_t)GetBaseAddress(head), head->text + head->delta, head->textsz);
|
||||
head->blocks = NewDynablockList((uintptr_t)GetBaseAddress(head), head->text + head->delta, head->textsz, 0, mainbin);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
@@ -162,8 +244,13 @@ int AllocElfMemory(box86context_t* context, elfheader_t* head, int mainbin)
|
||||
|
||||
void FreeElfMemory(elfheader_t* head)
|
||||
{
|
||||
if(head->memory)
|
||||
munmap((void*)head->memory, head->memsz);
|
||||
if(head->multiblock_n) {
|
||||
for(int i=0; i<head->multiblock_n; ++i)
|
||||
munmap(head->multiblock[i], head->multiblock_size[i]);
|
||||
free(head->multiblock);
|
||||
free(head->multiblock_size);
|
||||
free(head->multiblock_offs);
|
||||
}
|
||||
}
|
||||
|
||||
int LoadElfMemory(FILE* f, box86context_t* context, elfheader_t* head)
|
||||
@@ -173,10 +260,10 @@ int LoadElfMemory(FILE* f, box86context_t* context, elfheader_t* head)
|
||||
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);
|
||||
fseeko64(f, e->p_offset, SEEK_SET);
|
||||
if(e->p_filesz) {
|
||||
if(fread(dest, e->p_filesz, 1, f)!=1) {
|
||||
printf_log(LOG_NONE, "Fail to read PT_LOAD part #%d\n", i);
|
||||
printf_log(LOG_NONE, "Fail to read PT_LOAD part #%d (size=%d)\n", i, e->p_filesz);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -186,12 +273,12 @@ int LoadElfMemory(FILE* f, box86context_t* context, elfheader_t* head)
|
||||
}
|
||||
if(head->PHEntries[i].p_type == PT_TLS) {
|
||||
Elf32_Phdr * e = &head->PHEntries[i];
|
||||
char* dest = (char*)context->tlsdata;
|
||||
char* dest = (char*)(context->tlsdata+context->tlssize+head->tlsbase);
|
||||
printf_log(LOG_DEBUG, "Loading TLS block #%i @%p (0x%x/0x%x)\n", i, dest, e->p_filesz, e->p_memsz);
|
||||
fseek(f, e->p_offset, SEEK_SET);
|
||||
if(e->p_filesz) {
|
||||
fseeko64(f, e->p_offset, SEEK_SET);
|
||||
if(fread(dest, e->p_filesz, 1, f)!=1) {
|
||||
printf_log(LOG_NONE, "Fail to read PT_TLS part #%d\n", i);
|
||||
printf_log(LOG_NONE, "Fail to read PT_TLS part #%d (size=%d)\n", i, e->p_filesz);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -210,10 +297,15 @@ int ReloadElfMemory(FILE* f, box86context_t* context, elfheader_t* head)
|
||||
Elf32_Phdr * e = &head->PHEntries[i];
|
||||
char* dest = (char*)e->p_paddr + head->delta;
|
||||
printf_log(LOG_DEBUG, "Re-loading block #%i @%p (0x%x/0x%x)\n", i, dest, e->p_filesz, e->p_memsz);
|
||||
fseek(f, e->p_offset, SEEK_SET);
|
||||
int ret = fseeko64(f, e->p_offset, SEEK_SET);
|
||||
if(ret==-1) {printf_log(LOG_NONE, "Fail to (re)seek PT_LOAD part #%d (offset=%d, errno=%d/%s)\n", i, e->p_offset, errno, strerror(errno)); return 1;}
|
||||
if(e->p_filesz) {
|
||||
if(fread(dest, e->p_filesz, 1, f)!=1) {
|
||||
printf_log(LOG_NONE, "Fail to read PT_LOAD part #%d\n", i);
|
||||
ssize_t r = -1;
|
||||
#ifdef DYNAREC
|
||||
unprotectDB((uintptr_t)dest, e->p_filesz);
|
||||
#endif
|
||||
if((r=fread(dest, e->p_filesz, 1, f))!=1) {
|
||||
printf_log(LOG_NONE, "Fail to (re)read PT_LOAD part #%d (dest=%p, size=%d, return=%d, feof=%d/ferror=%d/%s)\n", i, dest, e->p_filesz, r, feof(f), ferror(f), strerror(ferror(f)));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -226,24 +318,39 @@ int ReloadElfMemory(FILE* f, box86context_t* context, elfheader_t* head)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int RelocateElfREL(lib_t *maplib, elfheader_t* head, int cnt, Elf32_Rel *rel)
|
||||
int RelocateElfREL(lib_t *maplib, lib_t *local_maplib, elfheader_t* head, int cnt, Elf32_Rel *rel)
|
||||
{
|
||||
for (int i=0; i<cnt; ++i) {
|
||||
int t = ELF32_R_TYPE(rel[i].r_info);
|
||||
Elf32_Sym *sym = &head->DynSym[ELF32_R_SYM(rel[i].r_info)];
|
||||
int type = ELF32_ST_TYPE(sym->st_info);
|
||||
int bind = ELF32_ST_BIND(sym->st_info);
|
||||
const char* symname = SymName(head, sym);
|
||||
uint32_t ndx = sym->st_shndx;
|
||||
uint32_t *p = (uint32_t*)(rel[i].r_offset + head->delta);
|
||||
uintptr_t offs = 0;
|
||||
uint32_t sz = 0;
|
||||
uintptr_t end = 0;
|
||||
if(bind==STB_LOCAL)
|
||||
GetLocalSymbolStartEnd(maplib, symname, &offs, &end, head);
|
||||
else
|
||||
GetGlobalSymbolStartEnd(maplib, symname, &offs, &end);
|
||||
elfheader_t* h_tls = head;
|
||||
if(bind==STB_LOCAL) {
|
||||
offs = sym->st_value + head->delta;
|
||||
end = offs + sym->st_size;
|
||||
} else {
|
||||
// this is probably very very wrong. A proprer way to get reloc need to be writen, but this hack seems ok for now
|
||||
// at least it work for half-life, unreal, ut99, zsnes, Undertale, ColinMcRae Remake, FTL, ShovelKnight...
|
||||
if(bind==STB_GLOBAL && (ndx==10 || ndx==19) && t!=R_386_GLOB_DAT) {
|
||||
offs = sym->st_value + head->delta;
|
||||
end = offs + sym->st_size;
|
||||
}
|
||||
// so weak symbol are the one left
|
||||
if(!offs && !end) {
|
||||
h_tls = NULL;
|
||||
if(local_maplib)
|
||||
GetGlobalSymbolStartEnd(local_maplib, symname, &offs, &end);
|
||||
if(!offs && !end)
|
||||
GetGlobalSymbolStartEnd(maplib, symname, &offs, &end);
|
||||
}
|
||||
}
|
||||
uintptr_t globoffs, globend;
|
||||
int delta;
|
||||
int t = ELF32_R_TYPE(rel[i].r_info);
|
||||
switch(t) {
|
||||
case R_386_NONE:
|
||||
// can be ignored
|
||||
@@ -252,31 +359,41 @@ int RelocateElfREL(lib_t *maplib, elfheader_t* head, int cnt, Elf32_Rel *rel)
|
||||
case R_386_TLS_TPOFF:
|
||||
// Negated offset in static TLS block
|
||||
{
|
||||
elfheader_t *h = GetGlobalSymbolElf(maplib, symname);
|
||||
if(h) {
|
||||
if(h_tls)
|
||||
offs = sym->st_value;
|
||||
else {
|
||||
if(local_maplib)
|
||||
h_tls = GetGlobalSymbolElf(local_maplib, symname);
|
||||
if(!h_tls)
|
||||
h_tls = GetGlobalSymbolElf(maplib, symname);
|
||||
}
|
||||
if(h_tls) {
|
||||
delta = *(int*)p;
|
||||
printf_log(LOG_DEBUG, "Applying %s %s on %s @%p (%d -> %d)\n", (bind==STB_LOCAL)?"Local":"Global", DumpRelType(t), symname, p, delta, (int32_t)offs + h->tlsbase);
|
||||
*p = (uint32_t)((int32_t)offs + h->tlsbase);
|
||||
printf_log(LOG_DEBUG, "Applying %s %s on %s @%p (%d -> %d)\n", (bind==STB_LOCAL)?"Local":"Global", DumpRelType(t), symname, p, delta, (int32_t)offs + h_tls->tlsbase);
|
||||
*p = (uint32_t)((int32_t)offs + h_tls->tlsbase);
|
||||
} else {
|
||||
printf_log(LOG_INFO, "Warning, cannot apply %s %s on %s @%p (%d), no elf_header found\n", (bind==STB_LOCAL)?"Local":"Global", DumpRelType(t), symname, p, (int32_t)offs);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case R_386_PC32:
|
||||
if (!offs) {
|
||||
printf_log(LOG_NONE, "Error: Global Symbol %s not found, cannot apply R_386_PC32 @%p (%p)\n", symname, p, *(void**)p);
|
||||
printf_log(LOG_NONE, "Error: Global Symbol %s not found, cannot apply R_386_PC32 @%p (%p) in %s\n", symname, p, *(void**)p, head->name);
|
||||
}
|
||||
offs = (offs - (uintptr_t)p);
|
||||
if(!offs)
|
||||
printf_log(LOG_DEBUG, "Apply %s R_386_PC32 @%p with sym=%s (%p -> %p)\n", (bind==STB_LOCAL)?"Local":"Global", p, symname, *(void**)p, (void*)(*(uintptr_t*)p+offs));
|
||||
printf_log(LOG_DEBUG, "Apply %s R_386_PC32 @%p with sym=%s (%p -> %p)\n", (bind==STB_LOCAL)?"Local":"Global", 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
|
||||
// Look for same symbol already loaded but not in self (so no need for local_maplib here)
|
||||
if (GetGlobalNoWeakSymbolStartEnd(maplib, symname, &globoffs, &globend)) {
|
||||
offs = globoffs;
|
||||
end = globend;
|
||||
}
|
||||
if (!offs) {
|
||||
printf_log(LOG_NONE, "Error: Global Symbol %s not found, cannot apply R_386_GLOB_DAT @%p (%p)\n", symname, p, *(void**)p);
|
||||
if(strcmp(symname, "__gmon_start__"))
|
||||
printf_log(LOG_NONE, "Error: Global Symbol %s not found, cannot apply R_386_GLOB_DAT @%p (%p) in %s\n", symname, p, *(void**)p, head->name);
|
||||
// return -1;
|
||||
} else {
|
||||
printf_log(LOG_DEBUG, "Apply %s R_386_GLOB_DAT @%p (%p -> %p) on sym=%s\n", (bind==STB_LOCAL)?"Local":"Global", p, (void*)(p?(*p):0), (void*)offs, symname);
|
||||
@@ -289,7 +406,7 @@ int RelocateElfREL(lib_t *maplib, elfheader_t* head, int cnt, Elf32_Rel *rel)
|
||||
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);
|
||||
printf_log(LOG_NONE, "Error: Symbol %s not found, cannot apply R_386_32 @%p (%p) in %s\n", symname, p, *(void**)p, head->name);
|
||||
// return -1;
|
||||
} else {
|
||||
printf_log(LOG_DEBUG, "Apply %s R_386_32 @%p with sym=%s (%p -> %p)\n", (bind==STB_LOCAL)?"Local":"Global", p, symname, *(void**)p, (void*)(offs+*(uint32_t*)p));
|
||||
@@ -299,10 +416,15 @@ int RelocateElfREL(lib_t *maplib, elfheader_t* head, int cnt, Elf32_Rel *rel)
|
||||
case R_386_TLS_DTPMOD32:
|
||||
// ID of module containing symbol
|
||||
if(!symname || symname[0]=='\0' || bind==STB_LOCAL)
|
||||
offs = getElfIndex(GetLibrarianContext(maplib), head);
|
||||
offs = getElfIndex(my_context, head);
|
||||
else {
|
||||
elfheader_t *h = GetGlobalSymbolElf(maplib, symname);
|
||||
offs = getElfIndex(GetLibrarianContext(maplib), h);
|
||||
if(!h_tls) {
|
||||
if(local_maplib)
|
||||
h_tls = GetGlobalSymbolElf(local_maplib, symname);
|
||||
if(!h_tls)
|
||||
h_tls = GetGlobalSymbolElf(maplib, symname);
|
||||
}
|
||||
offs = getElfIndex(my_context, h_tls);
|
||||
}
|
||||
if(p) {
|
||||
printf_log(LOG_DEBUG, "Apply %s %s @%p with sym=%s (%p -> %p)\n", "R_386_TLS_DTPMOD32", (bind==STB_LOCAL)?"Local":"Global", p, symname, *(void**)p, (void*)offs);
|
||||
@@ -313,14 +435,16 @@ int RelocateElfREL(lib_t *maplib, elfheader_t* head, int cnt, Elf32_Rel *rel)
|
||||
break;
|
||||
case R_386_TLS_DTPOFF32:
|
||||
// Offset in TLS block
|
||||
if (!offs) {
|
||||
if (!offs && !end) {
|
||||
if(bind==STB_WEAK) {
|
||||
printf_log(LOG_INFO, "Warning: Weak Symbol %s not found, cannot apply R_386_TLS_DTPOFF32 @%p (%p)\n", symname, p, *(void**)p);
|
||||
} else {
|
||||
printf_log(LOG_NONE, "Error: Symbol %s not found, cannot apply R_386_TLS_DTPOFF32 @%p (%p)\n", symname, p, *(void**)p);
|
||||
printf_log(LOG_NONE, "Error: Symbol %s not found, cannot apply R_386_TLS_DTPOFF32 @%p (%p) in %s\n", symname, p, *(void**)p, head->name);
|
||||
}
|
||||
// return -1;
|
||||
} else {
|
||||
if(h_tls)
|
||||
offs = sym->st_value;
|
||||
if(p) {
|
||||
int tlsoffset = offs; // it's not an offset in elf memory
|
||||
printf_log(LOG_DEBUG, "Apply %s R_386_TLS_DTPOFF32 @%p with sym=%s (%p -> %p)\n", (bind==STB_LOCAL)?"Local":"Global", p, symname, (void*)tlsoffset, (void*)offs);
|
||||
@@ -331,25 +455,34 @@ int RelocateElfREL(lib_t *maplib, elfheader_t* head, int cnt, Elf32_Rel *rel)
|
||||
}
|
||||
break;
|
||||
case R_386_JMP_SLOT:
|
||||
if (!offs) {
|
||||
if(bind==STB_WEAK) {
|
||||
printf_log(LOG_INFO, "Warning: Weak Symbol %s not found, cannot apply R_386_JMP_SLOT @%p (%p)\n", symname, p, *(void**)p);
|
||||
if(bind==STB_LOCAL) {
|
||||
if (!offs) {
|
||||
if(bind==STB_WEAK) {
|
||||
printf_log(LOG_INFO, "Warning: Weak Symbol %s not found, cannot apply R_386_JMP_SLOT @%p (%p)\n", symname, p, *(void**)p);
|
||||
} else {
|
||||
printf_log(LOG_NONE, "Error: Symbol %s not found, cannot apply R_386_JMP_SLOT @%p (%p) in %s\n", symname, p, *(void**)p, head->name);
|
||||
}
|
||||
// return -1;
|
||||
} else {
|
||||
printf_log(LOG_NONE, "Error: Symbol %s not found, cannot apply R_386_JMP_SLOT @%p (%p)\n", symname, p, *(void**)p);
|
||||
if(p) {
|
||||
printf_log(LOG_DEBUG, "Apply %s R_386_JMP_SLOT @%p with sym=%s (%p -> %p)\n", (bind==STB_LOCAL)?"Local":"Global", 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);
|
||||
}
|
||||
}
|
||||
// return -1;
|
||||
} else {
|
||||
if(p) {
|
||||
printf_log(LOG_DEBUG, "Apply %s R_386_JMP_SLOT @%p with sym=%s (%p -> %p)\n", (bind==STB_LOCAL)?"Local":"Global", 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);
|
||||
}
|
||||
printf_log(LOG_DEBUG, "Preparing (if needed) %s R_386_JMP_SLOT @%p (0x%x->0x%0x) with sym=%s to be apply later\n", (bind==STB_LOCAL)?"Local":"Global", p, *p, *p+head->delta, symname);
|
||||
*p += head->delta;
|
||||
}
|
||||
break;
|
||||
case R_386_COPY:
|
||||
if(offs) {
|
||||
GetNoSelfSymbolStartEnd(maplib, symname, &offs, &end, head); // get original copy if any
|
||||
offs = 0;
|
||||
if(local_maplib)
|
||||
GetNoSelfSymbolStartEnd(local_maplib, symname, &offs, &end, head);
|
||||
if(!offs)
|
||||
GetNoSelfSymbolStartEnd(maplib, symname, &offs, &end, head); // get original copy if any
|
||||
printf_log(LOG_DEBUG, "Apply %s R_386_COPY @%p with sym=%s, @%p size=%d (", (bind==STB_LOCAL)?"Local":"Global", p, symname, (void*)offs, sym->st_size);
|
||||
memmove(p, (void*)offs, sym->st_size);
|
||||
if(LOG_DEBUG<=box86_log) {
|
||||
@@ -359,7 +492,7 @@ int RelocateElfREL(lib_t *maplib, elfheader_t* head, int cnt, Elf32_Rel *rel)
|
||||
printf_log(LOG_DEBUG, "%s)\n", (sym->st_size>128)?" ...":"");
|
||||
}
|
||||
} else {
|
||||
printf_log(LOG_NONE, "Error: Symbol %s not found, cannot apply R_386_COPY @%p (%p)\n", symname, p, *(void**)p);
|
||||
printf_log(LOG_NONE, "Error: Symbol %s not found, cannot apply R_386_COPY @%p (%p) in %s\n", symname, p, *(void**)p, head->name);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -369,14 +502,13 @@ int RelocateElfREL(lib_t *maplib, elfheader_t* head, int cnt, Elf32_Rel *rel)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int RelocateElfRELA(lib_t *maplib, elfheader_t* head, int cnt, Elf32_Rela *rela)
|
||||
int RelocateElfRELA(lib_t *maplib, lib_t *local_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:
|
||||
@@ -384,13 +516,16 @@ int RelocateElfRELA(lib_t *maplib, elfheader_t* head, int cnt, Elf32_Rela *rela)
|
||||
// can be ignored
|
||||
break;
|
||||
case R_386_COPY:
|
||||
GetNoSelfSymbolStartEnd(maplib, symname, &offs, &end, head);
|
||||
if(local_maplib)
|
||||
GetNoSelfSymbolStartEnd(local_maplib, symname, &offs, &end, head);
|
||||
if(!offs)
|
||||
GetNoSelfSymbolStartEnd(maplib, symname, &offs, &end, head);
|
||||
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);
|
||||
printf_log(LOG_NONE, "Error: Symbol %s not found, cannot apply RELA R_386_COPY @%p (%p) in %s\n", symname, p, *(void**)p, head->name);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -399,48 +534,53 @@ int RelocateElfRELA(lib_t *maplib, elfheader_t* head, int cnt, Elf32_Rela *rela)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int RelocateElf(lib_t *maplib, elfheader_t* head)
|
||||
int RelocateElf(lib_t *maplib, lib_t *local_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)))
|
||||
if(RelocateElfREL(maplib, local_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)))
|
||||
if(RelocateElfRELA(maplib, local_maplib, head, cnt, (Elf32_Rela *)(head->rela + head->delta)))
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int RelocateElfPlt(box86context_t* context, lib_t *maplib, elfheader_t* head)
|
||||
int RelocateElfPlt(lib_t *maplib, lib_t *local_maplib, elfheader_t* head)
|
||||
{
|
||||
if(pltResolver==~0) {
|
||||
pltResolver = AddBridge(my_context->system, vFE, PltResolver, 0);
|
||||
}
|
||||
if(head->pltgot) {
|
||||
*(uintptr_t*)(head->pltgot+head->delta+8) = pltResolver;
|
||||
*(uintptr_t*)(head->pltgot+head->delta+4) = (uintptr_t)head;
|
||||
printf_log(LOG_DEBUG, "PLT Resolver injected in plt.got at %p\n", (void*)(head->pltgot+head->delta+8));
|
||||
} else if(head->got) {
|
||||
*(uintptr_t*)(head->got+head->delta+8) = pltResolver;
|
||||
*(uintptr_t*)(head->got+head->delta+4) = (uintptr_t)head;
|
||||
printf_log(LOG_DEBUG, "PLT Resolver injected in got at %p\n", (void*)(head->got+head->delta+8));
|
||||
}
|
||||
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)))
|
||||
if(RelocateElfREL(maplib, local_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)))
|
||||
if(RelocateElfRELA(maplib, local_maplib, head, cnt, (Elf32_Rela *)(head->jmprel + head->delta)))
|
||||
return -1;
|
||||
}
|
||||
if(head->gotplt) {
|
||||
if(pltResolver==~0) {
|
||||
pltResolver = AddBridge(context->system, vFEpp, PltResolver, 0); // 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;
|
||||
@@ -555,8 +695,9 @@ void AddSymbols(lib_t *maplib, kh_mapsymbols_t* mapsymbols, kh_mapsymbols_t* wea
|
||||
const char * symname = h->DynStr+h->DynSym[i].st_name;
|
||||
int bind = ELF32_ST_BIND(h->DynSym[i].st_info);
|
||||
int type = ELF32_ST_TYPE(h->DynSym[i].st_info);
|
||||
//st_shndx==65521 means ABS value
|
||||
if((type==STT_OBJECT || type==STT_FUNC || type==STT_COMMON || type==STT_TLS || type==STT_NOTYPE)
|
||||
&& (h->DynSym[i].st_other==0) && (h->DynSym[i].st_shndx!=0 && h->DynSym[i].st_shndx<62521)) {
|
||||
&& (h->DynSym[i].st_other==0) && (h->DynSym[i].st_shndx!=0 && h->DynSym[i].st_shndx<=65521)) {
|
||||
if(bind==10/*STB_GNU_UNIQUE*/ && FindGlobalSymbol(maplib, symname))
|
||||
continue;
|
||||
uintptr_t offs = (type==STT_TLS)?h->DynSym[i].st_value:(h->DynSym[i].st_value + h->delta);
|
||||
@@ -589,14 +730,46 @@ $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 LoadNeededLibs(elfheader_t* h, lib_t *maplib, library_t* parent, box86context_t *box86, x86emu_t* emu)
|
||||
int LoadNeededLibs(elfheader_t* h, lib_t *maplib, needed_libs_t* neededlibs, int local, box86context_t *box86, x86emu_t* emu)
|
||||
{
|
||||
DumpDynamicNeeded(h);
|
||||
for (int i=0; i<h->numDynamic; ++i)
|
||||
DumpDynamicRPath(h);
|
||||
// update RPATH first
|
||||
for (int i=0; i<h->numDynamic; ++i)
|
||||
if(h->Dynamic[i].d_tag==DT_RPATH || h->Dynamic[i].d_tag==DT_RUNPATH) {
|
||||
char *rpathref = h->DynStrTab+h->delta+h->Dynamic[i].d_un.d_val;
|
||||
char* rpath = rpathref;
|
||||
while(strstr(rpath, "$ORIGIN")) {
|
||||
char* origin = strdup(h->path);
|
||||
char* p = strrchr(origin, '/');
|
||||
if(p) *p = '\0'; // remove file name to have only full path, without last '/'
|
||||
char* tmp = (char*)calloc(1, strlen(rpath)-strlen("$ORIGIN")+strlen(origin)+1);
|
||||
p = strstr(rpath, "$ORIGIN");
|
||||
memcpy(tmp, rpath, p-rpath);
|
||||
strcat(tmp, origin);
|
||||
strcat(tmp, p+strlen("$ORIGIN"));
|
||||
if(rpath!=rpathref)
|
||||
free(rpath);
|
||||
rpath = tmp;
|
||||
}
|
||||
if(strchr(rpath, '$')) {
|
||||
printf_log(LOG_INFO, "BOX86: Warning, RPATH with $ variable not supported yet (%s)\n", rpath);
|
||||
} else {
|
||||
printf_log(LOG_DEBUG, "Prepending path \"%s\" to BOX86_LD_LIBRARY_PATH\n", rpath);
|
||||
PrependPath(rpath, &box86->box86_ld_lib, 1);
|
||||
}
|
||||
if(rpath!=rpathref)
|
||||
free(rpath);
|
||||
}
|
||||
|
||||
if(!h->neededlibs && neededlibs)
|
||||
h->neededlibs = neededlibs;
|
||||
|
||||
DumpDynamicNeeded(h);
|
||||
for (int i=0; i<h->numDynamic; ++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, parent, needed, box86, emu)) {
|
||||
if(AddNeededLib(maplib, neededlibs, local, needed, box86, emu)) {
|
||||
printf_log(LOG_INFO, "Error loading needed lib: \"%s\"\n", needed);
|
||||
if(!allow_missing_libs)
|
||||
return 1; //error...
|
||||
@@ -604,25 +777,13 @@ int LoadNeededLibs(elfheader_t* h, lib_t *maplib, library_t* parent, box86contex
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int FinalizeNeededLibs(elfheader_t* h, lib_t *maplib, box86context_t *box86, x86emu_t* emu)
|
||||
{
|
||||
DumpDynamicNeeded(h);
|
||||
for (int i=0; i<h->numDynamic; ++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(FinalizeLibrary(GetLib(maplib, needed), emu)) {
|
||||
printf_log(LOG_INFO, "Error finalizing needed lib: \"%s\"\n", needed);
|
||||
return 1; //error...
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void RunElfInit(elfheader_t* h, x86emu_t *emu)
|
||||
{
|
||||
if(h->init_done || !h->initentry)
|
||||
if(!h || h->init_done)
|
||||
return;
|
||||
// reset Segs Cache
|
||||
memset(emu->segs_clean, 0, sizeof(emu->segs_clean));
|
||||
uintptr_t p = h->initentry + h->delta;
|
||||
box86context_t* context = GetEmuContext(emu);
|
||||
if(context->deferedInit) {
|
||||
@@ -634,25 +795,23 @@ void RunElfInit(elfheader_t* h, x86emu_t *emu)
|
||||
return;
|
||||
}
|
||||
printf_log(LOG_DEBUG, "Calling Init for %s @%p\n", ElfName(h), (void*)p);
|
||||
Push32(emu, (uintptr_t)context->envv);
|
||||
Push32(emu, (uintptr_t)context->argv);
|
||||
Push32(emu, context->argc);
|
||||
DynaCall(emu, p);
|
||||
if(h->initentry)
|
||||
RunFunctionWithEmu(emu, 0, p, 3, context->argc, context->argv, context->envv);
|
||||
printf_log(LOG_DEBUG, "Done Init for %s\n", ElfName(h));
|
||||
// and check init array now
|
||||
Elf32_Addr *addr = (Elf32_Addr*)(h->initarray + h->delta);
|
||||
for (int i=0; i<h->initarray_sz; ++i) {
|
||||
printf_log(LOG_DEBUG, "Calling Init[%d] for %s @%p\n", i, ElfName(h), (void*)addr[i]);
|
||||
DynaCall(emu, (uintptr_t)addr[i]);
|
||||
RunFunctionWithEmu(emu, 0, (uintptr_t)addr[i], 3, context->argc, context->argv, context->envv);
|
||||
}
|
||||
Pop32(emu);
|
||||
Pop32(emu);
|
||||
Pop32(emu);
|
||||
|
||||
h->init_done = 1;
|
||||
h->fini_done = 0; // can be fini'd now (in case it was re-inited)
|
||||
printf_log(LOG_DEBUG, "All Init Done for %s\n", ElfName(h));
|
||||
return;
|
||||
}
|
||||
|
||||
EXPORTDYN
|
||||
void RunDeferedElfInit(x86emu_t *emu)
|
||||
{
|
||||
box86context_t* context = GetEmuContext(emu);
|
||||
@@ -667,25 +826,24 @@ void RunDeferedElfInit(x86emu_t *emu)
|
||||
context->deferedInitList = NULL;
|
||||
context->deferedInitCap = context->deferedInitSz = 0;
|
||||
}
|
||||
|
||||
void RunElfFini(elfheader_t* h, x86emu_t *emu)
|
||||
{
|
||||
if(h->fini_done || !h->finientry)
|
||||
if(!h || h->fini_done)
|
||||
return;
|
||||
uintptr_t p = h->finientry + h->delta;
|
||||
printf_log(LOG_DEBUG, "Calling Fini for %s @%p\n", ElfName(h), (void*)p);
|
||||
uint32_t sESP = GetESP(emu);
|
||||
Push32(emu, (uintptr_t)GetEmuContext(emu)->envv);
|
||||
Push32(emu, (uintptr_t)GetEmuContext(emu)->argv);
|
||||
Push32(emu, GetEmuContext(emu)->argc);
|
||||
DynaCall(emu, p);
|
||||
// and check fini array now
|
||||
h->fini_done = 1;
|
||||
// first check fini array
|
||||
Elf32_Addr *addr = (Elf32_Addr*)(h->finiarray + h->delta);
|
||||
for (int i=0; i<h->finiarray_sz; ++i) {
|
||||
printf_log(LOG_DEBUG, "Calling Fini[%d] for %s @%p\n", i, ElfName(h), (void*)addr[i]);
|
||||
DynaCall(emu, (uintptr_t)addr[i]);
|
||||
RunFunctionWithEmu(emu, 0, (uintptr_t)addr[i], 0);
|
||||
}
|
||||
// then the "old-style" fini
|
||||
if(h->finientry) {
|
||||
uintptr_t p = h->finientry + h->delta;
|
||||
printf_log(LOG_DEBUG, "Calling Fini for %s @%p\n", ElfName(h), (void*)p);
|
||||
RunFunctionWithEmu(emu, 0, p, 0);
|
||||
}
|
||||
SetESP(emu, sESP);
|
||||
h->fini_done = 1;
|
||||
h->init_done = 0; // can be re-inited again...
|
||||
return;
|
||||
}
|
||||
@@ -704,6 +862,11 @@ void* GetBaseAddress(elfheader_t* h)
|
||||
return h->memory;
|
||||
}
|
||||
|
||||
void* GetElfDelta(elfheader_t* h)
|
||||
{
|
||||
return (void*)h->delta;
|
||||
}
|
||||
|
||||
uint32_t GetBaseSize(elfheader_t* h)
|
||||
{
|
||||
return h->memsz;
|
||||
@@ -713,10 +876,13 @@ int IsAddressInElfSpace(elfheader_t* h, uintptr_t addr)
|
||||
{
|
||||
if(!h)
|
||||
return 0;
|
||||
uintptr_t base = (uintptr_t)GetBaseAddress(h);
|
||||
uintptr_t end = GetLastByte(h);
|
||||
if(addr>=base && addr<=end)
|
||||
return 1;
|
||||
for(int i=0; i<h->multiblock_n; ++i) {
|
||||
uintptr_t base = h->multiblock_offs[i];
|
||||
uintptr_t end = h->multiblock_offs[i] + h->multiblock_size[i] - 1;
|
||||
if(addr>=base && addr<=end)
|
||||
return 1;
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
elfheader_t* FindElfAddress(box86context_t *context, uintptr_t addr)
|
||||
@@ -743,7 +909,7 @@ const char* FindNearestSymbolName(elfheader_t* h, void* p, uintptr_t* start, uin
|
||||
const char * symname = h->StrTab+h->SymTab[i].st_name;
|
||||
uintptr_t offs = h->SymTab[i].st_value + h->delta;
|
||||
|
||||
if(offs<addr) {
|
||||
if(offs<=addr) {
|
||||
if(distance>addr-offs) {
|
||||
distance = addr-offs;
|
||||
ret = symname;
|
||||
@@ -756,7 +922,7 @@ const char* FindNearestSymbolName(elfheader_t* h, void* p, uintptr_t* start, uin
|
||||
const char * symname = h->DynStr+h->DynSym[i].st_name;
|
||||
uintptr_t offs = h->DynSym[i].st_value + h->delta;
|
||||
|
||||
if(offs<addr) {
|
||||
if(offs<=addr) {
|
||||
if(distance>addr-offs) {
|
||||
distance = addr-offs;
|
||||
ret = symname;
|
||||
@@ -774,87 +940,6 @@ const char* FindNearestSymbolName(elfheader_t* h, void* p, uintptr_t* start, uin
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void* fillTLSData(box86context_t *context)
|
||||
{
|
||||
void* ptr = NULL;
|
||||
pthread_mutex_lock(&context->mutex_lock);
|
||||
// Setup the GS segment:
|
||||
int dtsize = context->elfsize*8;
|
||||
ptr = (char*)malloc(context->tlssize+0x50+dtsize+24); // plan a 8*4 dtp table
|
||||
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, 0x50+dtsize+24); // set to 0 remining bytes
|
||||
memcpy((void*)((uintptr_t)ptr+context->tlssize+0x14), context->canary, 4); // put canary in place
|
||||
uintptr_t unknown = (uintptr_t)ptr+context->tlssize;
|
||||
memcpy((void*)((uintptr_t)ptr+context->tlssize+0x0), &unknown, 4);
|
||||
uintptr_t dtp = (uintptr_t)ptr+context->tlssize+0x50;
|
||||
memcpy((void*)((uintptr_t)ptr+context->tlssize+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+0x50+i*8), &dtp, 4);
|
||||
memcpy((void*)((uintptr_t)ptr+context->tlssize+0x50+i*8+4), &i, 4); // index
|
||||
}
|
||||
}
|
||||
memcpy((void*)((uintptr_t)ptr+context->tlssize+0x10), &context->vsyscall, 4); // address of vsyscall
|
||||
pthread_mutex_unlock(&context->mutex_lock);
|
||||
return data;
|
||||
}
|
||||
|
||||
static void* resizeTLSData(box86context_t *context, void* oldptr)
|
||||
{
|
||||
void* ptr = NULL;
|
||||
pthread_mutex_lock(&context->mutex_lock);
|
||||
tlsdatasize_t* oldata = (tlsdatasize_t*)oldptr;
|
||||
tlsdatasize_t *data = (tlsdatasize_t*)calloc(1, sizeof(tlsdatasize_t));
|
||||
// Setup the GS segment:
|
||||
int dtsize = context->elfsize*8;
|
||||
ptr = (char*)malloc(context->tlssize+0x50+dtsize+24); // plan a 8*4 dtp table
|
||||
data->tlsdata = ptr;
|
||||
data->tlssize = context->tlssize;
|
||||
|
||||
memcpy(ptr, context->tlsdata, context->tlssize);
|
||||
pthread_setspecific(context->tlskey, data);
|
||||
// copy canary...
|
||||
memset((void*)((uintptr_t)ptr+context->tlssize), 0, 0x50+dtsize+24); // set to 0 remining bytes
|
||||
memcpy((void*)((uintptr_t)ptr+context->tlssize+0x14), context->canary, 4); // put canary in place
|
||||
uintptr_t unknown = (uintptr_t)ptr+context->tlssize;
|
||||
memcpy((void*)((uintptr_t)ptr+context->tlssize+0x0), &unknown, 4);
|
||||
uintptr_t dtp = (uintptr_t)ptr+context->tlssize+0x50;
|
||||
memcpy((void*)((uintptr_t)ptr+context->tlssize+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+0x50+i*8), &dtp, 4);
|
||||
memcpy((void*)((uintptr_t)ptr+context->tlssize+0x50+i*8+4), &i, 4); // index
|
||||
}
|
||||
}
|
||||
memcpy((void*)((uintptr_t)ptr+context->tlssize+0x10), &context->vsyscall, 4); // address of vsyscall
|
||||
// copy the relevent old part, in case something changed
|
||||
memcpy((void*)((uintptr_t)ptr+(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;
|
||||
}
|
||||
|
||||
void* GetGSBase(box86context_t *context)
|
||||
{
|
||||
tlsdatasize_t* ptr;
|
||||
if ((ptr = (tlsdatasize_t*)pthread_getspecific(context->tlskey)) == NULL) {
|
||||
ptr = (tlsdatasize_t*)fillTLSData(context);
|
||||
}
|
||||
if(ptr->tlssize != context->tlssize)
|
||||
ptr = (tlsdatasize_t*)resizeTLSData(context, ptr);
|
||||
return ptr->tlsdata+ptr->tlssize;
|
||||
}
|
||||
|
||||
void* GetDTatOffset(box86context_t* context, int index, int offset)
|
||||
{
|
||||
return (void*)((char*)GetTLSPointer(context, context->elfs[index])+offset);
|
||||
@@ -886,17 +971,31 @@ void* GetTLSPointer(box86context_t* context, elfheader_t* h)
|
||||
#ifdef DYNAREC
|
||||
dynablocklist_t* GetDynablocksFromAddress(box86context_t *context, uintptr_t addr)
|
||||
{
|
||||
// this is one is fast, so start with that
|
||||
dynablocklist_t* ret = getDBFromAddress(addr);
|
||||
if(ret) {
|
||||
return ret;
|
||||
}
|
||||
// nope, then find in elfs
|
||||
elfheader_t* elf = FindElfAddress(context, addr);
|
||||
if(!elf) {
|
||||
if((*(uint8_t*)addr)==0xCC)
|
||||
return context->dynablocks;
|
||||
// still nope
|
||||
if(addr>0x100)
|
||||
if((*(uint8_t*)addr)==0xCC || (((*(uint8_t*)addr)==0xC3 || (*(uint8_t*)addr)==0xC2) && (*(uint8_t*)(addr-11))==0xCC) )
|
||||
return context->dynablocks;
|
||||
if(box86_dynarec_forced)
|
||||
return context->dynablocks;
|
||||
dynarec_log(LOG_INFO, "Address %p not found in Elf memory and is not a native call wrapper\n", addr);
|
||||
dynarec_log(LOG_INFO, "Address %p not found in Elf memory and is not a native call wrapper\n", (void*)addr);
|
||||
return NULL;
|
||||
}
|
||||
return elf->blocks;
|
||||
}
|
||||
dynablocklist_t* GetDynablocksFromElf(elfheader_t* h)
|
||||
{
|
||||
if(!h)
|
||||
return NULL;
|
||||
return h->blocks;
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef struct my_dl_phdr_info_s {
|
||||
@@ -908,8 +1007,20 @@ typedef struct my_dl_phdr_info_s {
|
||||
|
||||
static int dl_iterate_phdr_callback(x86emu_t *emu, my_dl_phdr_info_t *info, size_t size, void* data)
|
||||
{
|
||||
SetCallbackArg(emu, 0, info);
|
||||
SetCallbackArg(emu, 1, (void*)size);
|
||||
SetCallbackArgs(emu, 2, info, size);
|
||||
int ret = RunCallback(emu);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dl_iterate_phdr_native(struct dl_phdr_info* info, size_t size, void* data)
|
||||
{
|
||||
if(!info->dlpi_name)
|
||||
return 0;
|
||||
if(!info->dlpi_name[0]) // don't send informations about box86 itself
|
||||
return 0;
|
||||
|
||||
x86emu_t* emu = (x86emu_t*)data;
|
||||
SetCallbackArgs(emu, 2, info, size);
|
||||
int ret = RunCallback(emu);
|
||||
return ret;
|
||||
}
|
||||
@@ -919,17 +1030,23 @@ EXPORT int my_dl_iterate_phdr(x86emu_t *emu, void* F, void *data) {
|
||||
x86emu_t* cbemu = AddSharedCallback(emu, (uintptr_t)F, 3, NULL, NULL, data, NULL);
|
||||
box86context_t *context = GetEmuContext(emu);
|
||||
const char* empty = "";
|
||||
int ret = 0;
|
||||
for (int idx=0; idx<context->elfsize; ++idx) {
|
||||
my_dl_phdr_info_t info;
|
||||
info.dlpi_addr = GetBaseAddress(context->elfs[idx]);
|
||||
info.dlpi_addr = GetElfDelta(context->elfs[idx]);
|
||||
info.dlpi_name = idx?context->elfs[idx]->name:empty; //1st elf is program, and this one doesn't get a name
|
||||
info.dlpi_phdr = context->elfs[idx]->PHEntries;
|
||||
info.dlpi_phnum = context->elfs[idx]->numPHEntries;
|
||||
if(dl_iterate_phdr_callback(cbemu, &info, sizeof(info), data))
|
||||
break;
|
||||
if((ret = dl_iterate_phdr_callback(cbemu, &info, sizeof(info), data))) {
|
||||
FreeCallback(cbemu);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
// and now, go on native version
|
||||
ret = dl_iterate_phdr(dl_iterate_phdr_native, cbemu);
|
||||
// all done
|
||||
FreeCallback(cbemu);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ResetSpecialCaseMainElf(elfheader_t* h)
|
||||
@@ -939,18 +1056,100 @@ void ResetSpecialCaseMainElf(elfheader_t* h)
|
||||
if(h->DynSym[i].st_info == 17) {
|
||||
sym = h->DynSym+i;
|
||||
const char * symname = h->DynStr+sym->st_name;
|
||||
if(strcmp(symname, "_IO_2_1_stderr_")==0) {
|
||||
if(strcmp(symname, "_IO_2_1_stderr_")==0 && ((void*)sym->st_value+h->delta)) {
|
||||
memcpy((void*)sym->st_value+h->delta, stderr, sym->st_size);
|
||||
my__IO_2_1_stderr_ = (void*)sym->st_value+h->delta;
|
||||
printf_log(LOG_DEBUG, "BOX86: Set @_IO_2_1_stderr_ to %p\n", my__IO_2_1_stderr_);
|
||||
} else
|
||||
if(strcmp(symname, "_IO_2_1_stdin_")==0) {
|
||||
if(strcmp(symname, "_IO_2_1_stdin_")==0 && ((void*)sym->st_value+h->delta)) {
|
||||
memcpy((void*)sym->st_value+h->delta, stdin, sym->st_size);
|
||||
my__IO_2_1_stdin_ = (void*)sym->st_value+h->delta;
|
||||
printf_log(LOG_DEBUG, "BOX86: Set @_IO_2_1_stdin_ to %p\n", my__IO_2_1_stdin_);
|
||||
} else
|
||||
if(strcmp(symname, "_IO_2_1_stdout_")==0) {
|
||||
if(strcmp(symname, "_IO_2_1_stdout_")==0 && ((void*)sym->st_value+h->delta)) {
|
||||
memcpy((void*)sym->st_value+h->delta, stdout, sym->st_size);
|
||||
my__IO_2_1_stdout_ = (void*)sym->st_value+h->delta;
|
||||
printf_log(LOG_DEBUG, "BOX86: Set @_IO_2_1_stdout_ to %p\n", my__IO_2_1_stdout_);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CreateMemorymapFile(box86context_t* context, int fd)
|
||||
{
|
||||
char buff[1024];
|
||||
struct stat st;
|
||||
int dummy;
|
||||
(void)dummy;
|
||||
|
||||
elfheader_t *h = context->elfs[0];
|
||||
|
||||
if (stat(h->path, &st)) {
|
||||
printf_log(LOG_INFO, "Failed to stat file %s (creating memory maps \"file\")!", h->path);
|
||||
// Some constants, to have "valid" values
|
||||
st.st_dev = makedev(0x03, 0x00);
|
||||
st.st_ino = 0;
|
||||
}
|
||||
|
||||
for (int i=0; i<h->numPHEntries; ++i) {
|
||||
if (h->PHEntries[i].p_memsz == 0) continue;
|
||||
|
||||
sprintf(buff, "%08x-%08x %c%c%c%c %08x %02x:%02x %ld %s\n", (uintptr_t)h->PHEntries[i].p_vaddr + h->delta,
|
||||
(uintptr_t)h->PHEntries[i].p_vaddr + h->PHEntries[i].p_memsz + h->delta,
|
||||
(h->PHEntries[i].p_type & (PF_R|PF_X) ? 'r':'-'), (h->PHEntries[i].p_type & PF_W ? 'w':'-'),
|
||||
(h->PHEntries[i].p_type & PF_X ? 'x':'-'), 'p', // p for private or s for shared
|
||||
(uintptr_t)h->PHEntries[i].p_offset,
|
||||
major(st.st_dev), minor(st.st_dev), st.st_ino, h->path);
|
||||
|
||||
dummy = write(fd, buff, strlen(buff));
|
||||
}
|
||||
}
|
||||
|
||||
void ElfAttachLib(elfheader_t* head, library_t* lib)
|
||||
{
|
||||
if(!head)
|
||||
return;
|
||||
head->lib = lib;
|
||||
}
|
||||
|
||||
uintptr_t pltResolver = ~0;
|
||||
EXPORT void PltResolver(x86emu_t* emu)
|
||||
{
|
||||
uintptr_t addr = Pop32(emu);
|
||||
int slot = (int)Pop32(emu);
|
||||
elfheader_t *h = (elfheader_t*)addr;
|
||||
printf_log(LOG_DEBUG, "PltResolver: Addr=%p, Slot=%d Return=%p: elf is %s\n", (void*)addr, slot, *(void**)(R_ESP), h->name);
|
||||
|
||||
Elf32_Rel * rel = (Elf32_Rel *)(h->jmprel + h->delta + slot);
|
||||
|
||||
Elf32_Sym *sym = &h->DynSym[ELF32_R_SYM(rel->r_info)];
|
||||
int bind = ELF32_ST_BIND(sym->st_info);
|
||||
const char* symname = SymName(h, sym);
|
||||
uint32_t *p = (uint32_t*)(rel->r_offset + h->delta);
|
||||
uintptr_t offs = 0;
|
||||
uintptr_t end = 0;
|
||||
|
||||
library_t* lib = h->lib;
|
||||
lib_t* local_maplib = GetMaplib(lib);
|
||||
if(local_maplib)
|
||||
GetGlobalSymbolStartEnd(local_maplib, symname, &offs, &end);
|
||||
if(!offs && !end)
|
||||
GetGlobalSymbolStartEnd(my_context->maplib, symname, &offs, &end);
|
||||
|
||||
if (!offs) {
|
||||
printf_log(LOG_NONE, "Error: PltReolver: Symbol %s not found, cannot apply R_386_JMP_SLOT @%p (%p) in %s\n", symname, p, *(void**)p, h->name);
|
||||
emu->quit = 1;
|
||||
return;
|
||||
} else {
|
||||
if(p) {
|
||||
printf_log(LOG_DEBUG, "PltReolver: Apply %s R_386_JMP_SLOT @%p with sym=%s (%p -> %p / %s)\n", (bind==STB_LOCAL)?"Local":"Global", p, symname, *(void**)p, (void*)offs, ElfName(FindElfAddress(my_context, offs)));
|
||||
*p = offs;
|
||||
} else {
|
||||
printf_log(LOG_NONE, "PltReolver: Warning, Symbol %s found, but Jump Slot Offset is NULL \n", symname);
|
||||
}
|
||||
}
|
||||
|
||||
// jmp to function
|
||||
R_EIP = offs;
|
||||
}
|
||||
@@ -5,10 +5,14 @@
|
||||
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;
|
||||
@@ -48,6 +52,7 @@ struct elfheader_s {
|
||||
int pltent;
|
||||
uint32_t pltrel;
|
||||
uintptr_t gotplt;
|
||||
uintptr_t pltgot;
|
||||
uintptr_t got;
|
||||
uintptr_t text;
|
||||
int textsz;
|
||||
@@ -67,9 +72,15 @@ struct elfheader_s {
|
||||
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
|
||||
|
||||
+13
-6
@@ -1,3 +1,4 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -23,7 +24,7 @@ int LoadSH(FILE *f, Elf32_Shdr *s, void** SH, const char* name, uint32_t type)
|
||||
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);
|
||||
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;
|
||||
@@ -69,11 +70,15 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
return NULL;
|
||||
}
|
||||
if(header.e_ident[EI_CLASS]!=ELFCLASS32) {
|
||||
printf_log(LOG_INFO, "Not an 32bits ELF (%d)\n", header.e_ident[EI_CLASS]);
|
||||
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 an LittleEndian ELF (%d)\n", header.e_ident[EI_DATA]);
|
||||
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) {
|
||||
@@ -119,7 +124,7 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
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);
|
||||
fseeko64(f, header.e_shoff, SEEK_SET);
|
||||
Elf32_Shdr section;
|
||||
if(fread(§ion, sizeof(Elf32_Shdr), 1, f)!=1) {
|
||||
free(h);
|
||||
@@ -131,7 +136,7 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
// 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);
|
||||
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");
|
||||
@@ -147,7 +152,7 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
|
||||
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);
|
||||
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");
|
||||
@@ -194,6 +199,8 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
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)
|
||||
|
||||
@@ -51,6 +51,10 @@
|
||||
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)]; \
|
||||
@@ -71,6 +75,7 @@
|
||||
#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
|
||||
|
||||
+138
-95
@@ -1,5 +1,21 @@
|
||||
opcode = F8;
|
||||
goto *opcodes0f[opcode];
|
||||
_0f_0x00: /* VERx Ed */
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 4: //VERR
|
||||
case 5: //VERW
|
||||
GET_EW;
|
||||
if(!EW->word[0])
|
||||
CLEAR_FLAG(F_ZF);
|
||||
else
|
||||
SET_FLAG(F_ZF); // should test if selector is ok
|
||||
break;
|
||||
default:
|
||||
goto _default;
|
||||
}
|
||||
NEXT;
|
||||
|
||||
_0f_0x0B: /* UD2 */
|
||||
kill(getpid(), SIGILL); // this is undefined instruction
|
||||
NEXT;
|
||||
@@ -54,7 +70,18 @@
|
||||
_0f_0x18: /* PREFETCHh Ed */
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
__builtin_prefetch((void*)ED->dword[0], 0, 0); // inoring wich level of cache (roughly (nextop>>3)&7)
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
} else
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: //PREFETCHnta
|
||||
case 1: //PREFETCH1
|
||||
case 2: //PREFETCH2
|
||||
case 3: //PREFETCH3
|
||||
__builtin_prefetch((void*)ED, 0, 0); // ignoring wich level of cache
|
||||
break;
|
||||
default: //NOP
|
||||
break;
|
||||
}
|
||||
NEXT;
|
||||
|
||||
_0f_0x1F: /* NOP (multi-byte) */
|
||||
@@ -139,6 +166,22 @@
|
||||
R_EAX = tmp64u&0xFFFFFFFF;
|
||||
NEXT;
|
||||
|
||||
_0f_0x38: // these are some SSE3 opcodes
|
||||
opcode = F8;
|
||||
switch(opcode) {
|
||||
case 0x04: /* PMADDUBSW Gm,Em */
|
||||
nextop = F8;
|
||||
GET_EM;
|
||||
for (int i=0; i<4; ++i) {
|
||||
tmp32s = (int32_t)(GM.ub[i*2+0])*EM->ub[i*2+0] + (int32_t)(GM.ub[i*2+1])*EM->ub[i*2+1];
|
||||
GM.sw[i] = (tmp32s>32767)?32767:tmp32s; // no negative value to test
|
||||
}
|
||||
break;
|
||||
default:
|
||||
goto _default;
|
||||
}
|
||||
NEXT;
|
||||
|
||||
#define GOCOND(BASE, PREFIX, CONDITIONAL) \
|
||||
_0f_##BASE##_0: \
|
||||
PREFIX \
|
||||
@@ -571,95 +614,16 @@
|
||||
EM->q = GM.q;
|
||||
NEXT;
|
||||
|
||||
_0f_0xA0: /* PUSH FS */
|
||||
Push(emu, emu->segs[_FS]); // even if a segment is a 16bits, a 32bits push/pop is done
|
||||
NEXT;
|
||||
_0f_0xA1: /* POP FS */
|
||||
emu->segs[_FS] = Pop(emu); // no check, no use....
|
||||
emu->segs_clean[_FS] = 0;
|
||||
NEXT;
|
||||
_0f_0xA2: /* CPUID */
|
||||
tmp32u = R_EAX;
|
||||
switch(tmp32u) {
|
||||
case 0x0:
|
||||
// emulate a P4
|
||||
R_EAX = 0x80000004;
|
||||
// return GenuineIntel
|
||||
R_EBX = 0x756E6547;
|
||||
R_EDX = 0x49656E69;
|
||||
R_ECX = 0x6C65746E;
|
||||
break;
|
||||
case 0x1:
|
||||
R_EAX = 0x00000101; // familly and all
|
||||
R_EBX = 0; // Brand indexe, CLFlush, Max APIC ID, Local APIC ID
|
||||
R_EDX = 1 // fpu
|
||||
| 1<<8 // cmpxchg8
|
||||
| 1<<11 // sep (sysenter & sysexit)
|
||||
| 1<<15 // cmov
|
||||
| 1<<19 // clflush (seems to be with SSE2)
|
||||
| 1<<23 // mmx
|
||||
//| 1<<24 // fxsr (fxsave, fxrestore)
|
||||
| 1<<25 // SSE
|
||||
| 1<<26 // SSE2
|
||||
;
|
||||
R_ECX = 1<<12 // fma
|
||||
| 1<<13 // cx16 (cmpxchg16)
|
||||
; // also 1<<0 is SSE3 and 1<<9 is SSSE3
|
||||
break;
|
||||
case 0x2: // TLB and Cache info. Sending 1st gen P4 info...
|
||||
R_EAX = 0x665B5001;
|
||||
R_EBX = 0x00000000;
|
||||
R_ECX = 0x00000000;
|
||||
R_EDX = 0x007A7000;
|
||||
break;
|
||||
|
||||
case 0x4: // Cache info
|
||||
switch (R_ECX) {
|
||||
case 0: // L1 data cache
|
||||
R_EAX = (1 | (1<<5) | (1<<8)); //type
|
||||
R_EBX = (63 | (7<<22)); // size
|
||||
R_ECX = 63;
|
||||
R_EDX = 1;
|
||||
break;
|
||||
case 1: // L1 inst cache
|
||||
R_EAX = (2 | (1<<5) | (1<<8)); //type
|
||||
R_EBX = (63 | (7<<22)); // size
|
||||
R_ECX = 63;
|
||||
R_EDX = 1;
|
||||
break;
|
||||
case 2: // L2 cache
|
||||
R_EAX = (3 | (2<<5) | (1<<8)); //type
|
||||
R_EBX = (63 | (15<<22)); // size
|
||||
R_ECX = 4095;
|
||||
R_EDX = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
R_EAX = 0x00000000;
|
||||
R_EBX = 0x00000000;
|
||||
R_ECX = 0x00000000;
|
||||
R_EDX = 0x00000000;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x5: //mwait info
|
||||
R_EAX = 0;
|
||||
R_EBX = 0;
|
||||
R_ECX = 1 | 2;
|
||||
R_EDX = 0;
|
||||
break;
|
||||
case 0x6: // thermal
|
||||
case 0x9: // direct cache access
|
||||
case 0xA: // Architecture performance monitor
|
||||
R_EAX = 0;
|
||||
R_EBX = 0;
|
||||
R_ECX = 0;
|
||||
R_EDX = 0;
|
||||
break;
|
||||
case 0x7: // extended bits...
|
||||
/*if(R_ECX==0) R_EAX = 0;
|
||||
else*/ R_EAX = R_ECX = R_EBX = R_EDX = 0;
|
||||
break;
|
||||
|
||||
case 0x80000000: // max extended
|
||||
break; // no extended, so return same value as beeing the max value!
|
||||
default:
|
||||
printf_log(LOG_INFO, "Warning, CPUID command %X unsupported (ECX=%08x)\n", tmp32u, R_ECX);
|
||||
R_EAX = 0;
|
||||
}
|
||||
my_cpuid(emu, tmp32u);
|
||||
NEXT;
|
||||
_0f_0xA3: /* BT Ed,Gd */
|
||||
CHECK_FLAGS(emu);
|
||||
@@ -684,6 +648,15 @@
|
||||
ED->dword[0] = shld32(emu, ED->dword[0], GD.dword[0], tmp8u);
|
||||
NEXT;
|
||||
|
||||
_0f_0xA8: /* PUSH GS */
|
||||
Push(emu, emu->segs[_GS]); // even if a segment is a 16bits, a 32bits push/pop is done
|
||||
NEXT;
|
||||
_0f_0xA9: /* POP GS */
|
||||
emu->segs[_GS] = Pop(emu);
|
||||
emu->segs_clean[_GS] = 0;
|
||||
NEXT;
|
||||
|
||||
|
||||
_0f_0xAB: /* BTS Ed,Gd */
|
||||
CHECK_FLAGS(emu);
|
||||
nextop = F8;
|
||||
@@ -725,16 +698,23 @@
|
||||
case 0: /* FXSAVE m512byte */
|
||||
// should save flags & all
|
||||
// copy MMX regs...
|
||||
memcpy(ED->dword+32/4, &emu->mmx[0], sizeof(emu->mmx));
|
||||
for(int i=0; i<8; ++i)
|
||||
memcpy(ED->dword+32+i*16, &emu->mmx[0], sizeof(emu->mmx[0]));
|
||||
// copy SSE regs
|
||||
memcpy(ED->dword+160/4, &emu->xmm[0], sizeof(emu->xmm));
|
||||
memcpy(ED->dword+160, &emu->xmm[0], sizeof(emu->xmm));
|
||||
// put also FPU regs in a reserved area...
|
||||
for(int i=0; i<8; ++i)
|
||||
memcpy(ED->dword+416+i*8, &emu->fpu[0], sizeof(emu->fpu[0]));
|
||||
break;
|
||||
case 1: /* FXRSTOR m512byte */
|
||||
// should restore flags & all
|
||||
// copy MMX regs...
|
||||
memcpy(&emu->mmx[0], ED->dword+32/4, sizeof(emu->mmx));
|
||||
// copy back MMX regs...
|
||||
for(int i=0; i<8; ++i)
|
||||
memcpy(&emu->mmx[i], ED->dword+32+i*16, sizeof(emu->mmx[0]));
|
||||
// copy SSE regs
|
||||
memcpy(&emu->xmm[0], ED->dword+160/4, sizeof(emu->xmm));
|
||||
for(int i=0; i<8; ++i)
|
||||
memcpy(&emu->fpu[0], ED->dword+416+i*8, sizeof(emu->fpu[0]));
|
||||
break;
|
||||
case 2: /* LDMXCSR Md */
|
||||
emu->mxcsr = ED->dword[0];
|
||||
@@ -818,6 +798,21 @@
|
||||
else
|
||||
CLEAR_FLAG(F_CF);
|
||||
break;
|
||||
case 5: /* BTS 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
|
||||
ED->dword[0] ^= (1<<tmp8u);
|
||||
CLEAR_FLAG(F_CF);
|
||||
break;
|
||||
case 6: /* BTR Ed, Ib */
|
||||
CHECK_FLAGS(emu);
|
||||
GET_ED;
|
||||
@@ -833,6 +828,21 @@
|
||||
} else
|
||||
CLEAR_FLAG(F_CF);
|
||||
break;
|
||||
case 7: /* BTC 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);
|
||||
ED->dword[0] ^= (1<<tmp8u);
|
||||
break;
|
||||
|
||||
default:
|
||||
goto _default;
|
||||
@@ -1021,6 +1031,14 @@
|
||||
}
|
||||
NEXT;
|
||||
|
||||
_0f_0xD7: /* PMOVMSKB Gd,Em */
|
||||
nextop = F8;
|
||||
GET_EM;
|
||||
GD.dword[0] = 0;
|
||||
for (int i=0; i<8; ++i)
|
||||
if(EM->ub[i]&0x80)
|
||||
GD.dword[0] |= (1<<i);
|
||||
NEXT;
|
||||
_0f_0xD8: /* PSUBUSB Gm,Em */
|
||||
nextop = F8;
|
||||
GET_EM;
|
||||
@@ -1119,6 +1137,13 @@
|
||||
}
|
||||
NEXT;
|
||||
|
||||
_0f_0xE7: /* MOVNTQ Em,Gm */
|
||||
nextop = F8;
|
||||
if((nextop&0xC0)==0xC0)
|
||||
goto _default;
|
||||
GET_EM;
|
||||
EM->q = GM.q;
|
||||
NEXT;
|
||||
_0f_0xE8: /* PSUBSB Gm,Em */
|
||||
nextop = F8;
|
||||
GET_EM;
|
||||
@@ -1135,7 +1160,12 @@
|
||||
GM.sw[i] = (tmp32s>32767)?32767:((tmp32s<-32768)?-32768:tmp32s);
|
||||
}
|
||||
NEXT;
|
||||
|
||||
_0f_0xEA: /* PMINSW Gm,Em */
|
||||
nextop = F8;
|
||||
GET_EM;
|
||||
for (int i=0; i<4; ++i)
|
||||
GM.sw[i] = (GM.sw[i]<EM->sw[i])?GM.sw[i]:EM->sw[i];
|
||||
NEXT;
|
||||
_0f_0xEB: /* POR Gm, Em */
|
||||
nextop = F8;
|
||||
GET_EM;
|
||||
@@ -1157,7 +1187,12 @@
|
||||
GM.sw[i] = (tmp32s>32767)?32767:((tmp32s<-32768)?-32768:tmp32s);
|
||||
}
|
||||
NEXT;
|
||||
|
||||
_0f_0xEE: /* PMAXSW Gm,Em */
|
||||
nextop = F8;
|
||||
GET_EM;
|
||||
for (int i=0; i<4; ++i)
|
||||
GM.sw[i] = (GM.sw[i]>EM->sw[i])?GM.sw[i]:EM->sw[i];
|
||||
NEXT;
|
||||
_0f_0xEF: /* PXOR Gm, Em */
|
||||
nextop = F8;
|
||||
GET_EM;
|
||||
@@ -1215,7 +1250,15 @@
|
||||
tmp32u += (GM.ub[i]>EM->ub[i])?(GM.ub[i] - EM->ub[i]):(EM->ub[i] - GM.ub[i]);
|
||||
GM.q = tmp32u;
|
||||
NEXT;
|
||||
|
||||
_0f_0xF7: /* MASKMOVQ Gm, Em */
|
||||
nextop = F8;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
GET_EM;
|
||||
for (int i=0; i<8; ++i)
|
||||
if(EM->ub[i]&0x80) ((uint8_t*)(R_EDI))[i] = GM.ub[i];
|
||||
} else
|
||||
goto _default;
|
||||
NEXT;
|
||||
_0f_0xF8: /* PSUBB Gm,Em */
|
||||
nextop = F8;
|
||||
GET_EM;
|
||||
|
||||
+70
-8
@@ -30,6 +30,7 @@
|
||||
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 */
|
||||
@@ -37,10 +38,17 @@
|
||||
|
||||
_66_0x26: /* ES: */
|
||||
// ignored
|
||||
NEXT;
|
||||
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;
|
||||
@@ -99,6 +107,27 @@
|
||||
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
|
||||
@@ -181,6 +210,7 @@
|
||||
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;
|
||||
@@ -190,10 +220,16 @@
|
||||
_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 */
|
||||
@@ -208,6 +244,13 @@
|
||||
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 */
|
||||
R_AX = *(uint16_t*)F32;
|
||||
@@ -302,7 +345,7 @@
|
||||
NEXT;
|
||||
|
||||
_66_0xD9:
|
||||
emu->old_ip = old_ip;
|
||||
emu->old_ip = R_EIP;
|
||||
R_EIP = ip;
|
||||
Run66D9(emu);
|
||||
ip = R_EIP;
|
||||
@@ -310,7 +353,7 @@
|
||||
NEXT;
|
||||
|
||||
_66_0xDD:
|
||||
emu->old_ip = old_ip;
|
||||
emu->old_ip = R_EIP;
|
||||
R_EIP = ip;
|
||||
Run66DD(emu);
|
||||
ip = R_EIP;
|
||||
@@ -324,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;
|
||||
@@ -405,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;
|
||||
@@ -416,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;
|
||||
|
||||
+65
-5
@@ -207,7 +207,7 @@
|
||||
_6f_0x38: // these are some SSE3 opcodes
|
||||
opcode = F8;
|
||||
switch(opcode) {
|
||||
case 0x00: // PSHUFB
|
||||
case 0x00: /* PSHUFB */
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
eax1 = GX;
|
||||
@@ -218,6 +218,14 @@
|
||||
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;
|
||||
}
|
||||
@@ -247,8 +255,9 @@
|
||||
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 {
|
||||
GX.q[0] = GX.q[1] >> (tmp8u - 64) | (EX->q[0] << (tmp8u));
|
||||
GX.q[1] = (EX->q[0] << (64-tmp8u)) | (EX->q[1] >> (tmp8u - 64));
|
||||
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;
|
||||
@@ -680,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;
|
||||
@@ -870,7 +916,11 @@
|
||||
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;
|
||||
@@ -883,6 +933,11 @@
|
||||
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;
|
||||
@@ -1023,7 +1078,12 @@
|
||||
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;
|
||||
|
||||
+49
-11
@@ -124,7 +124,7 @@
|
||||
#endif
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 0xF2: /* FTAN */
|
||||
case 0xF2: /* FPTAN */
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = tanf(ST0.f);
|
||||
fpu_do_push(emu);
|
||||
@@ -134,6 +134,7 @@
|
||||
fpu_do_push(emu);
|
||||
ST0.d = 1.0;
|
||||
#endif
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
break;
|
||||
case 0xF3: /* FPATAN */
|
||||
#ifdef USE_FLOAT
|
||||
@@ -161,16 +162,53 @@
|
||||
|
||||
case 0xF8: /* FPREM */
|
||||
#ifdef USE_FLOAT
|
||||
tmp32s = ST0.f / ST1.f;
|
||||
ST0.f -= ST1.f * tmp32s;
|
||||
ll = ST0.f / ST1.f;
|
||||
ST0.f -= ST1.f * ll;
|
||||
#else
|
||||
tmp32s = ST0.d / ST1.d;
|
||||
ST0.d -= ST1.d * tmp32s;
|
||||
ll = ST0.d / ST1.d;
|
||||
ST0.d -= ST1.d * ll;
|
||||
#endif
|
||||
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);
|
||||
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
|
||||
@@ -244,9 +282,6 @@
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
case 0xEF:
|
||||
case 0xF5:
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
goto _default;
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
@@ -309,6 +344,9 @@
|
||||
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)
|
||||
|
||||
+2
-1
@@ -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:
|
||||
|
||||
@@ -111,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;
|
||||
|
||||
+11
-2
@@ -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;
|
||||
@@ -141,7 +150,7 @@
|
||||
memcpy(EX, &GX, 16); // unaligned...
|
||||
break;
|
||||
|
||||
case 0xBC: /* TZCNT Ew,Gw */
|
||||
case 0xBC: /* TZCNT Ed,Gd */
|
||||
CHECK_FLAGS(emu);
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
@@ -151,7 +160,7 @@
|
||||
tmp8u = 0;
|
||||
while(!(tmp32u&(1<<tmp8u))) ++tmp8u;
|
||||
GD.dword[0] = tmp8u;
|
||||
CONDITIONAL_SET_FLAG(tmp8u, F_ZF);
|
||||
CONDITIONAL_SET_FLAG(tmp8u==0, F_ZF);
|
||||
CLEAR_FLAG(F_CF);
|
||||
} else {
|
||||
CLEAR_FLAG(F_ZF);
|
||||
|
||||
+49
-65
@@ -12,9 +12,9 @@
|
||||
#include "x86emu_private.h"
|
||||
#include "x87emu_private.h"
|
||||
#include "box86context.h"
|
||||
#include "x86trace.h"
|
||||
#include "x86run.h"
|
||||
#include "x86run_private.h"
|
||||
#include "callback.h"
|
||||
|
||||
typedef struct cleanup_s {
|
||||
void* f;
|
||||
@@ -56,8 +56,7 @@ static void internalX86Setup(x86emu_t* emu, box86context_t *context, uintptr_t s
|
||||
emu->packed_eflags.x32 = 0x202; // default flags?
|
||||
UnpackFlags(emu);
|
||||
// own stack?
|
||||
if(ownstack)
|
||||
emu->stack = (void*)stack;
|
||||
emu->stack2free = (ownstack)?(void*)stack:NULL;
|
||||
emu->init_stack = (void*)stack;
|
||||
emu->size_stack = stacksize;
|
||||
// set default value
|
||||
@@ -66,18 +65,13 @@ static void internalX86Setup(x86emu_t* emu, box86context_t *context, uintptr_t s
|
||||
// fake init of segments...
|
||||
emu->segs[_CS] = 0x73;
|
||||
emu->segs[_DS] = emu->segs[_ES] = emu->segs[_SS] = 0x7b;
|
||||
emu->segs[_FS] = 0;
|
||||
emu->segs[_FS] = default_fs;
|
||||
emu->segs[_GS] = 0x33;
|
||||
// setup fpu regs
|
||||
reset_fpu(emu);
|
||||
// if trace is activated
|
||||
if(context->x86trace) {
|
||||
emu->dec = InitX86TraceDecoder(context);
|
||||
if(!emu->dec)
|
||||
printf_log(LOG_INFO, "Failed to initialize Zydis decoder and formater, no trace activated\n");
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -98,96 +92,80 @@ x86emu_t *NewX86EmuFromStack(x86emu_t* emu, box86context_t *context, uintptr_t s
|
||||
return emu;
|
||||
}
|
||||
|
||||
EXPORTDYN
|
||||
void SetupX86Emu(x86emu_t *emu)
|
||||
{
|
||||
printf_log(LOG_DEBUG, "Setup X86 Emu\n");
|
||||
}
|
||||
|
||||
void SetTraceEmu(x86emu_t *emu, uintptr_t trace_start, uintptr_t trace_end)
|
||||
void SetTraceEmu(uintptr_t start, uintptr_t end)
|
||||
{
|
||||
if(emu->dec) {
|
||||
if (trace_end == 0) {
|
||||
if(my_context->zydis) {
|
||||
if (end == 0) {
|
||||
printf_log(LOG_INFO, "Setting trace\n");
|
||||
} else {
|
||||
if(trace_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*)trace_start, (void*)trace_end);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
emu->trace_start = trace_start;
|
||||
emu->trace_end = trace_end;
|
||||
trace_start = start;
|
||||
trace_end = end;
|
||||
}
|
||||
|
||||
void AddCleanup(x86emu_t *emu, void *p)
|
||||
{
|
||||
if(emu->clean_sz == emu->clean_cap) {
|
||||
emu->clean_cap += 4;
|
||||
emu->cleanups = (cleanup_t*)realloc(emu->cleanups, sizeof(cleanup_t)*emu->clean_cap);
|
||||
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);
|
||||
}
|
||||
emu->cleanups[emu->clean_sz].arg = 0;
|
||||
emu->cleanups[emu->clean_sz++].f = p;
|
||||
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(emu->clean_sz == emu->clean_cap) {
|
||||
emu->clean_cap += 4;
|
||||
emu->cleanups = (cleanup_t*)realloc(emu->cleanups, sizeof(cleanup_t)*emu->clean_cap);
|
||||
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);
|
||||
}
|
||||
emu->cleanups[emu->clean_sz].arg = 1;
|
||||
emu->cleanups[emu->clean_sz].a = a;
|
||||
emu->cleanups[emu->clean_sz++].f = p;
|
||||
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)
|
||||
{
|
||||
for(int i=emu->clean_sz-1; i>=0; --i) {
|
||||
if(p==emu->cleanups[i].f) {
|
||||
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);
|
||||
if(emu->cleanups[i].arg)
|
||||
Push(emu, (uintptr_t)emu->cleanups[i].a);
|
||||
PushExit(emu);
|
||||
emu->ip.dword[0] = (uintptr_t)(emu->cleanups[i].f);
|
||||
Run(emu, 0);
|
||||
emu->quit = 0;
|
||||
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!=emu->clean_sz-1)
|
||||
memmove(emu->cleanups+i, emu->cleanups+i+1, (emu->clean_sz-i-1)*sizeof(cleanup_t));
|
||||
--emu->clean_sz;
|
||||
return;
|
||||
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)
|
||||
{
|
||||
/* disabling for now...
|
||||
for(int i=emu->clean_sz-1; i>=0; --i) {
|
||||
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);
|
||||
if(emu->cleanups[i].arg)
|
||||
Push(emu, (uintptr_t)emu->cleanups[i].a);
|
||||
PushExit(emu);
|
||||
emu->ip.dword[0] = (uintptr_t)(emu->cleanups[i].f);
|
||||
Run(emu);
|
||||
emu->quit = 0;
|
||||
RunFunctionWithEmu(emu, 0, (uintptr_t)(my_context->cleanups[i].f), my_context->cleanups[i].arg, my_context->cleanups[i].a );
|
||||
}
|
||||
*/
|
||||
emu->clean_sz = 0;
|
||||
my_context->clean_sz = 0;
|
||||
}
|
||||
|
||||
static void internalFreeX86(x86emu_t* emu)
|
||||
{
|
||||
// stop trace now
|
||||
if(emu->dec)
|
||||
DeleteX86TraceDecoder(&emu->dec);
|
||||
emu->dec = NULL;
|
||||
// call atexit and fini first!
|
||||
CallAllCleanup(emu);
|
||||
free(emu->cleanups);
|
||||
|
||||
free(emu->stack);
|
||||
free(emu->stack2free);
|
||||
}
|
||||
|
||||
EXPORTDYN
|
||||
void FreeX86Emu(x86emu_t **emu)
|
||||
{
|
||||
if(!emu)
|
||||
@@ -207,8 +185,6 @@ void FreeX86EmuFromStack(x86emu_t **emu)
|
||||
printf_log(LOG_DEBUG, "Free a X86 Emu from stack (%p)\n", *emu);
|
||||
|
||||
internalFreeX86(*emu);
|
||||
|
||||
*emu = NULL;
|
||||
}
|
||||
|
||||
void CloneEmu(x86emu_t *newemu, const x86emu_t* emu)
|
||||
@@ -219,6 +195,7 @@ void CloneEmu(x86emu_t *newemu, const x86emu_t* emu)
|
||||
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));
|
||||
@@ -234,10 +211,9 @@ void CloneEmu(x86emu_t *newemu, const x86emu_t* emu)
|
||||
newemu->mxcsr = emu->mxcsr;
|
||||
newemu->quit = emu->quit;
|
||||
newemu->error = emu->error;
|
||||
SetTraceEmu(newemu, emu->trace_start, emu->trace_end);
|
||||
// addapt R_ESP to new stack frame
|
||||
uintptr_t oldst = (uintptr_t)((emu->stack)?emu->stack:emu->context->stack);
|
||||
uintptr_t newst = (uintptr_t)((newemu->stack)?newemu->stack:newemu->context->stack);
|
||||
// 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);
|
||||
}
|
||||
|
||||
@@ -294,6 +270,14 @@ 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)
|
||||
|
||||
+12
-11
@@ -3,7 +3,6 @@
|
||||
|
||||
#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;
|
||||
|
||||
@@ -11,7 +10,10 @@ typedef struct i386_ucontext_s i386_ucontext_t;
|
||||
#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;
|
||||
@@ -52,7 +54,9 @@ typedef struct x86emu_s {
|
||||
uintptr_t prev2_ip, prev_ip;
|
||||
#endif
|
||||
// segments
|
||||
uint32_t segs[6]; // only 32bits value?
|
||||
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;
|
||||
@@ -61,22 +65,19 @@ typedef struct x86emu_s {
|
||||
int exit;
|
||||
int quitonlongjmp; // quit if longjmp is called
|
||||
int longjmp; // if quit because of longjmp
|
||||
// trace
|
||||
zydis_dec_t *dec;
|
||||
uintptr_t trace_start, trace_end;
|
||||
#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;
|
||||
// cpu helpers
|
||||
reg32_t zero;
|
||||
reg32_t *sbiidx[8];
|
||||
// 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. 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)
|
||||
|
||||
|
||||
+102
-53
@@ -21,13 +21,18 @@
|
||||
#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=emu->context->atfork_sz-1; i>=0; --i)
|
||||
EmuCall(emu, emu->context->atforks[i].prepare);
|
||||
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;
|
||||
@@ -39,13 +44,15 @@ x86emu_t* x86emu_fork(x86emu_t* emu, int forktype)
|
||||
// error...
|
||||
} else if(v!=0) {
|
||||
// execute atforks parent functions
|
||||
for (int i=0; i<emu->context->atfork_sz; --i)
|
||||
EmuCall(emu, emu->context->atforks[i].parent);
|
||||
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<emu->context->atfork_sz; --i)
|
||||
EmuCall(emu, emu->context->atforks[i].child);
|
||||
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;
|
||||
@@ -65,9 +72,13 @@ void x86Int3(x86emu_t* emu)
|
||||
RESET_FLAGS(emu);
|
||||
wrapper_t w = (wrapper_t)addr;
|
||||
addr = Fetch32(emu);
|
||||
if(box86_log>=LOG_DEBUG /*&& emu->trace_end==0 && !emu->context->x86trace*/) {
|
||||
/* 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 = syscall(SYS_gettid);
|
||||
int tid = GetTID();
|
||||
char buff[256] = "\0";
|
||||
char buff2[64] = "\0";
|
||||
char buff3[64] = "\0";
|
||||
@@ -75,107 +86,138 @@ void x86Int3(x86emu_t* emu)
|
||||
int post = 0;
|
||||
int perr = 0;
|
||||
uint32_t *pu32 = NULL;
|
||||
const char *s = GetNativeName(emu, (void*)addr);
|
||||
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), "glColor4f", *(float*)(R_ESP+4), *(float*)(R_ESP+8), *(float*)(R_ESP+12), *(float*)(R_ESP+16));
|
||||
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), "glTexCoord2f", *(float*)(R_ESP+4), *(float*)(R_ESP+8));
|
||||
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), "glVertex2f", *(float*)(R_ESP+4), *(float*)(R_ESP+8));
|
||||
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), "glVertex3f", *(float*)(R_ESP+4), *(float*)(R_ESP+8), *(float*)(R_ESP+12));
|
||||
} else if(strstr(s, "__open64")==s || strstr(s, "open64")==s || strstr(s, "open64")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", %d, %d)", tid, *(void**)(R_ESP), "open64", *(char**)(R_ESP+4), *(int*)(R_ESP+8), *(int*)(R_ESP+12));
|
||||
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(strstr(s, "__open")==s || strstr(s, "open")==s || strstr(s, "open")==s) {
|
||||
} 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)", tid, *(void**)(R_ESP), s, (tmp)?tmp:"(nil)", *(int*)(R_ESP+8));
|
||||
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(strstr(s, "fopen")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", \"%s\")", tid, *(void**)(R_ESP), "fopen", *(char**)(R_ESP+4), *(char**)(R_ESP+8));
|
||||
} 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(strstr(s, "chdir")==s) {
|
||||
} 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), "chdir", pu32?((pu32==(uint32_t*)1)?"/1/":(char*)pu32):"/0/");
|
||||
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), "getenv", *(char**)(R_ESP+4));
|
||||
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, %i)", tid, *(void**)(R_ESP), "pread", *(int32_t*)(R_ESP+4), *(void**)(R_ESP+8), *(uint32_t*)(R_ESP+12), *(int32_t*)(R_ESP+16));
|
||||
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), "statvfs64", *(void**)(R_ESP+4), *(char**)(R_ESP+4), *(void**)(R_ESP+8));
|
||||
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), "index", *(char**)(R_ESP+4), *(char**)(R_ESP+4), *(int32_t*)(R_ESP+8), *(int32_t*)(R_ESP+8));
|
||||
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), "rindex", *(char**)(R_ESP+4), *(char**)(R_ESP+4), *(int32_t*)(R_ESP+8), *(int32_t*)(R_ESP+8));
|
||||
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), "__xstat64", *(int32_t*)(R_ESP+4), *(char**)(R_ESP+8), *(char**)(R_ESP+8), *(void**)(R_ESP+12));
|
||||
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), "__lxstat64", *(int32_t*)(R_ESP+4), *(char**)(R_ESP+8), *(char**)(R_ESP+8), *(void**)(R_ESP+12));
|
||||
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), "sem_timedwait", *(void**)(R_ESP+4), *(void**)(R_ESP+8), pu32?pu32[0]:-1, pu32?pu32[1]:-1);
|
||||
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), "clock_gettime", *(uint32_t*)(R_ESP+4), *(void**)(R_ESP+8));
|
||||
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), "strcasecmp", *(char**)(R_ESP+4), *(char**)(R_ESP+8));
|
||||
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, "strncasecmp")==s || strstr(s, "__strncasecmp")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", \"%s\", %u)", tid, *(void**)(R_ESP), "strcasecmp", *(char**)(R_ESP+4), *(char**)(R_ESP+8), *(uint32_t*)(R_ESP+12));
|
||||
} else if(strstr(s, "strcmp")==s || strstr(s, "__strcmp")==s) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", \"%s\")", tid, *(void**)(R_ESP), "strcmp", *(char**)(R_ESP+4), *(char**)(R_ESP+8));
|
||||
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(\"%s\", \"%s\")", tid, *(void**)(R_ESP), "strstr", *(char**)(R_ESP+4), *(char**)(R_ESP+8));
|
||||
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), "strlen", *(char**)(R_ESP+4), ((R_ESP+4))?(*(char**)(R_ESP+4)):"nil");
|
||||
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), "vsnprintf", *(uint32_t*)(R_ESP+4), *(uint32_t*)(R_ESP+8), *(uint32_t*)(R_ESP+12));
|
||||
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), "vsprintf", *(uint32_t*)(R_ESP+4), *(char**)(R_ESP+8));
|
||||
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), "snprintf", *(uint32_t*)(R_ESP+4), *(uint32_t*)(R_ESP+8), *(uint32_t*)(R_ESP+12));
|
||||
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), "sprintf", *(uint32_t*)(R_ESP+4), *(uint32_t*)(R_ESP+8));
|
||||
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) {
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%08X, \"%s\", ...)", tid, *(void**)(R_ESP), "fprintf", *(uint32_t*)(R_ESP+4), *(char**)(R_ESP+8));
|
||||
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), "XCreateWindow", *(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));
|
||||
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), "XLoadQueryFont", *(void**)(R_ESP+4), *(char**)(R_ESP+8));
|
||||
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), "pthread_mutex_lock", *(void**)(R_ESP+4));
|
||||
} else if(strstr(s, "fmodf")==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), "fmodf", *(float*)(R_ESP+4), *(float*)(R_ESP+8));
|
||||
} else if(strstr(s, "fmod")==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(!strcmp(s, "fmod")) {
|
||||
post = 4;
|
||||
snprintf(buff, 255, "%04d|%p: Calling %s(%f, %f)", tid, *(void**)(R_ESP), "fmod", *(double*)(R_ESP+4), *(double*)(R_ESP+12));
|
||||
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), "SDL_GetWindowSurface", *(void**)(R_ESP+4));
|
||||
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_DEBUG, "%s =>", buff);
|
||||
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);
|
||||
@@ -202,9 +244,11 @@ void x86Int3(x86emu_t* emu)
|
||||
}
|
||||
break;
|
||||
}
|
||||
if(perr && ((int)R_EAX)<0)
|
||||
snprintf(buff3, 63, " (errno=%d)", errno);
|
||||
printf_log(LOG_DEBUG, " return 0x%08X%s%s\n", R_EAX, buff2, buff3);
|
||||
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);
|
||||
@@ -214,3 +258,8 @@ void x86Int3(x86emu_t* emu)
|
||||
printf_log(LOG_INFO, "Warning, ignoring unsupported Int 3 call\n");
|
||||
//emu->quit = 1;
|
||||
}
|
||||
|
||||
int GetTID()
|
||||
{
|
||||
return syscall(SYS_gettid);
|
||||
}
|
||||
+25
-22
@@ -714,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) {
|
||||
@@ -741,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) {
|
||||
@@ -768,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) {
|
||||
@@ -795,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) {
|
||||
@@ -822,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) {
|
||||
@@ -849,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) {
|
||||
@@ -1153,7 +1153,7 @@ 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;
|
||||
@@ -1161,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;
|
||||
}
|
||||
|
||||
@@ -1177,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;
|
||||
}
|
||||
|
||||
@@ -1205,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;
|
||||
@@ -1213,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;
|
||||
}
|
||||
@@ -1225,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;
|
||||
}
|
||||
|
||||
|
||||
+17
-11
@@ -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;
|
||||
@@ -507,7 +513,7 @@ static inline uint32_t xor32(x86emu_t *emu, uint32_t d, uint32_t s)
|
||||
REMARKS:
|
||||
Implements the IMUL instruction and side effects.
|
||||
****************************************************************************/
|
||||
static void imul8(x86emu_t *emu, uint8_t s)
|
||||
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;
|
||||
@@ -516,7 +522,7 @@ static void imul8(x86emu_t *emu, uint8_t s)
|
||||
REMARKS:
|
||||
Implements the IMUL instruction and side effects.
|
||||
****************************************************************************/
|
||||
static void imul16_eax(x86emu_t *emu, uint16_t s)
|
||||
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;
|
||||
@@ -527,7 +533,7 @@ static void imul16_eax(x86emu_t *emu, uint16_t s)
|
||||
REMARKS:
|
||||
Implements the IMUL instruction and side effects.
|
||||
****************************************************************************/
|
||||
static uint16_t imul16(x86emu_t *emu, uint16_t op1, uint16_t op2)
|
||||
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;
|
||||
@@ -537,7 +543,7 @@ static uint16_t imul16(x86emu_t *emu, uint16_t op1, uint16_t op2)
|
||||
REMARKS:
|
||||
Implements the IMUL instruction and side effects.
|
||||
****************************************************************************/
|
||||
static void imul32_direct(uint32_t *res_lo, uint32_t* res_hi,uint32_t d, uint32_t s)
|
||||
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;
|
||||
|
||||
@@ -548,7 +554,7 @@ static void imul32_direct(uint32_t *res_lo, uint32_t* res_hi,uint32_t d, uint32_
|
||||
REMARKS:
|
||||
Implements the IMUL instruction and side effects.
|
||||
****************************************************************************/
|
||||
static uint32_t imul32(x86emu_t *emu, uint32_t op1, uint32_t op2)
|
||||
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);
|
||||
@@ -558,7 +564,7 @@ static uint32_t imul32(x86emu_t *emu, uint32_t op1, uint32_t op2)
|
||||
REMARKS:
|
||||
Implements the IMUL instruction and side effects.
|
||||
****************************************************************************/
|
||||
static void imul32_eax(x86emu_t *emu, uint32_t s)
|
||||
static inline void imul32_eax(x86emu_t *emu, uint32_t s)
|
||||
{
|
||||
emu->df = d_imul32;
|
||||
imul32_direct(&R_EAX,&R_EDX,R_EAX,s);
|
||||
@@ -569,7 +575,7 @@ static void imul32_eax(x86emu_t *emu, uint32_t s)
|
||||
REMARKS:
|
||||
Implements the MUL instruction and side effects.
|
||||
****************************************************************************/
|
||||
static void mul8(x86emu_t *emu, uint8_t s)
|
||||
static inline void mul8(x86emu_t *emu, uint8_t s)
|
||||
{
|
||||
emu->df = d_mul8;
|
||||
R_AX = emu->res = (uint16_t)(R_AL) * s;
|
||||
@@ -578,7 +584,7 @@ static void mul8(x86emu_t *emu, uint8_t s)
|
||||
REMARKS:
|
||||
Implements the MUL instruction and side effects.
|
||||
****************************************************************************/
|
||||
static void mul16(x86emu_t *emu, uint16_t s)
|
||||
static inline void mul16(x86emu_t *emu, uint16_t s)
|
||||
{
|
||||
emu->df = d_mul16;
|
||||
emu->res = (uint32_t)R_AX * s;
|
||||
@@ -589,7 +595,7 @@ static void mul16(x86emu_t *emu, uint16_t s)
|
||||
REMARKS:
|
||||
Implements the MUL instruction and side effects.
|
||||
****************************************************************************/
|
||||
static void mul32_eax(x86emu_t *emu, uint32_t s)
|
||||
static inline void mul32_eax(x86emu_t *emu, uint32_t s)
|
||||
{
|
||||
emu->df = d_mul32;
|
||||
uint64_t res = (uint64_t)R_EAX * s;
|
||||
|
||||
+235
-81
@@ -18,6 +18,7 @@
|
||||
#include "x86trace.h"
|
||||
#include "x87emu_private.h"
|
||||
#include "box86context.h"
|
||||
#include "my_cpuid.h"
|
||||
|
||||
int my_setcontext(x86emu_t* emu, void* ucp);
|
||||
|
||||
@@ -26,7 +27,6 @@ int Run(x86emu_t *emu, int step)
|
||||
uint8_t opcode;
|
||||
uint8_t nextop;
|
||||
reg32_t *oped;
|
||||
reg32_t ea1;
|
||||
uint8_t tmp8u, tmp8u2;
|
||||
int8_t tmp8s;
|
||||
uint16_t tmp16u, tmp16u2;
|
||||
@@ -35,7 +35,7 @@ int Run(x86emu_t *emu, int step)
|
||||
int32_t tmp32s, tmp32s2;
|
||||
uint64_t tmp64u;
|
||||
int64_t tmp64s;
|
||||
uintptr_t ip, old_ip;
|
||||
uintptr_t ip;
|
||||
double d;
|
||||
float f;
|
||||
int64_t ll;
|
||||
@@ -45,8 +45,6 @@ int Run(x86emu_t *emu, int step)
|
||||
if(emu->quit)
|
||||
return 0;
|
||||
|
||||
old_ip = 0;
|
||||
|
||||
//ref opcode: http://ref.x86asm.net/geek32.html#xA1
|
||||
printf_log(LOG_DEBUG, "Run X86 (%p), EIP=%p, Stack=%p\n", emu, (void*)R_EIP, emu->context->stack);
|
||||
#define F8 *(uint8_t*)(ip++)
|
||||
@@ -63,23 +61,23 @@ int Run(x86emu_t *emu, int step)
|
||||
|
||||
static const void* baseopcodes[256] ={
|
||||
&&_0x00_0, &&_0x00_1, &&_0x00_2, &&_0x00_3, &&_0x00_4, &&_0x00_5, &&_0x06, &&_0x07, //0x00-0x07
|
||||
&&_0x08_0, &&_0x08_1, &&_0x08_2, &&_0x08_3, &&_0x08_4, &&_0x08_5, &&_default, &&_0x0F, //0x08-0x0F
|
||||
&&_0x10_0, &&_0x10_1, &&_0x10_2, &&_0x10_3, &&_0x10_4, &&_0x10_5, &&_default, &&_default, //0x10-0x17
|
||||
&&_0x08_0, &&_0x08_1, &&_0x08_2, &&_0x08_3, &&_0x08_4, &&_0x08_5, &&_0x0E, &&_0x0F, //0x08-0x0F
|
||||
&&_0x10_0, &&_0x10_1, &&_0x10_2, &&_0x10_3, &&_0x10_4, &&_0x10_5, &&_0x16, &&_0x17, //0x10-0x17
|
||||
&&_0x18_0, &&_0x18_1, &&_0x18_2, &&_0x18_3, &&_0x18_4, &&_0x18_5, &&_0x1E, &&_0x1F, //0x18-0x1F
|
||||
&&_0x20_0, &&_0x20_1, &&_0x20_2, &&_0x20_3, &&_0x20_4, &&_0x20_5, &&_0x26, &&_0x27, //0x20-0x27
|
||||
&&_0x28_0, &&_0x28_1, &&_0x28_2, &&_0x28_3, &&_0x28_4, &&_0x28_5, &&_0x2E, &&_0x2F, //0x28-0x2F
|
||||
&&_0x30_0, &&_0x30_1, &&_0x30_2, &&_0x30_3, &&_0x30_4, &&_0x30_5, &&_default, &&_0x37, //0x30-0x37
|
||||
&&_0x38, &&_0x39, &&_0x3A, &&_0x3B, &&_0x3C, &&_0x3D, &&_default, &&_0x3F, //0x38-0x3F
|
||||
&&_0x30_0, &&_0x30_1, &&_0x30_2, &&_0x30_3, &&_0x30_4, &&_0x30_5, &&_0x36, &&_0x37, //0x30-0x37
|
||||
&&_0x38, &&_0x39, &&_0x3A, &&_0x3B, &&_0x3C, &&_0x3D, &&_0x3E, &&_0x3F, //0x38-0x3F
|
||||
&&_0x40, &&_0x41, &&_0x42, &&_0x43, &&_0x44, &&_0x45, &&_0x46, &&_0x47,
|
||||
&&_0x48, &&_0x49, &&_0x4A, &&_0x4B, &&_0x4C, &&_0x4D, &&_0x4E, &&_0x4F,
|
||||
&&_0x50, &&_0x51, &&_0x52, &&_0x53, &&_0x54, &&_0x55, &&_0x56, &&_0x57,
|
||||
&&_0x58, &&_0x59, &&_0x5A, &&_0x5B, &&_0x5C, &&_0x5D, &&_0x5E, &&_0x5F,
|
||||
&&_0x60, &&_0x61, &&_default, &&_default, &&_0x64, &&_0x65, &&_0x66, &&_0x67,
|
||||
&&_0x68, &&_0x69, &&_0x6A, &&_0x6B, &&_0x6C, &&_0x6D, &&_default, &&_default, //0x68-0x6F
|
||||
&&_0x60, &&_0x61, &&_0x62, &&_default, &&_0x64, &&_0x65, &&_0x66, &&_0x67,
|
||||
&&_0x68, &&_0x69, &&_0x6A, &&_0x6B, &&_0x6C, &&_0x6D, &&_0x6E, &&_0x6F, //0x68-0x6F
|
||||
&&_0x70_0, &&_0x70_1, &&_0x70_2, &&_0x70_3, &&_0x70_4, &&_0x70_5, &&_0x70_6, &&_0x70_7, //0x70-0x77
|
||||
&&_0x70_8, &&_0x70_9, &&_0x70_A, &&_0x70_B, &&_0x70_C, &&_0x70_D, &&_0x70_E, &&_0x70_F, //0x78-0x7F
|
||||
&&_0x80, &&_0x81, &&_default, &&_0x83, &&_0x84, &&_0x85, &&_0x86, &&_0x87,
|
||||
&&_0x88, &&_0x89, &&_0x8A, &&_0x8B, &&_default, &&_0x8D, &&_0x8E, &&_0x8F,
|
||||
&&_0x80, &&_0x81, &&_0x82, &&_0x83, &&_0x84, &&_0x85, &&_0x86, &&_0x87,
|
||||
&&_0x88, &&_0x89, &&_0x8A, &&_0x8B, &&_0x8C, &&_0x8D, &&_0x8E, &&_0x8F,
|
||||
&&_0x90, &&_0x91, &&_0x92, &&_0x93, &&_0x94, &&_0x95, &&_0x96, &&_0x97,
|
||||
&&_0x98, &&_0x99, &&_default, &&_0x9B, &&_0x9C, &&_0x9D, &&_0x9E, &&_0x9F,
|
||||
&&_0xA0, &&_0xA1, &&_0xA2, &&_0xA3, &&_0xA4, &&_0xA5, &&_0xA6, &&_0xA7,
|
||||
@@ -87,24 +85,24 @@ int Run(x86emu_t *emu, int step)
|
||||
&&_0xB0, &&_0xB1, &&_0xB2, &&_0xB3, &&_0xB4, &&_0xB5, &&_0xB6, &&_0xB7,
|
||||
&&_0xB8, &&_0xB9, &&_0xBA, &&_0xBB, &&_0xBC, &&_0xBD, &&_0xBE, &&_0xBF,
|
||||
&&_0xC0, &&_0xC1, &&_0xC2, &&_0xC3, &&_default, &&_default, &&_0xC6, &&_0xC7,
|
||||
&&_0xC8, &&_0xC9, &&_default, &&_default, &&_0xCC, &&_0xCD, &&_default, &&_default, //0xC8-0xCF
|
||||
&&_0xC8, &&_0xC9, &&_default, &&_default, &&_0xCC, &&_0xCD, &&_default, &&_0xCF, //0xC8-0xCF
|
||||
&&_0xD0, &&_0xD1, &&_0xD2, &&_0xD3, &&_0xD4, &&_0xD5, &&_default, &&_0xD7,
|
||||
&&_0xD8, &&_0xD9, &&_0xDA, &&_0xDB, &&_0xDC, &&_0xDD, &&_0xDE, &&_0xDF,
|
||||
&&_0xE0, &&_0xE1, &&_0xE2, &&_0xE3, &&_default, &&_0xE5, &&_default, &&_default,
|
||||
&&_0xE8, &&_0xE9, &&_default, &&_0xEB, &&_default, &&_default, &&_default, &&_default,
|
||||
&&_0xF0, &&_default, &&_0xF2, &&_0xF3, &&_default, &&_0xF5, &&_0xF6, &&_0xF7,
|
||||
&&_0xF8, &&_0xF9, &&_default, &&_default, &&_0xFC, &&_0xFD, &&_0xFE, &&_0xFF
|
||||
&&_0xE0, &&_0xE1, &&_0xE2, &&_0xE3, &&_0xE4, &&_0xE5, &&_0xE6, &&_0xE7,
|
||||
&&_0xE8, &&_0xE9, &&_default, &&_0xEB, &&_0xEC, &&_0xED, &&_default, &&_default,
|
||||
&&_0xF0, &&_0xF1, &&_0xF2, &&_0xF3, &&_default, &&_0xF5, &&_0xF6, &&_0xF7,
|
||||
&&_0xF8, &&_0xF9, &&_0xFA, &&_0xFB, &&_0xFC, &&_0xFD, &&_0xFE, &&_0xFF
|
||||
};
|
||||
|
||||
static const void* opcodes0f[256] = {
|
||||
&&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0x00-0x07
|
||||
&&_0f_0x00, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0x00-0x07
|
||||
&&_default, &&_default, &&_default, &&_0f_0x0B, &&_default ,&&_default, &&_default, &&_default, //0x08-0x0F
|
||||
&&_0f_0x10, &&_0f_0x11, &&_0f_0x12, &&_0f_0x13, &&_0f_0x14, &&_0f_0x15, &&_0f_0x16, &&_0f_0x17, //0x10-0x17
|
||||
&&_0f_0x18, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_0f_0x1F, //0x18-0x1F
|
||||
&&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0x20-0x27
|
||||
&&_0f_0x28, &&_0f_0x29, &&_0f_0x2A, &&_0f_0x2B, &&_0f_0x2C, &&_0f_0x2D, &&_0f_0x2E, &&_0f_0x2F,
|
||||
&&_default, &&_0f_0x31, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0x30-0x37
|
||||
&&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0x38-0x3F
|
||||
&&_0f_0x38, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0x38-0x3F
|
||||
&&_0f_0x40_0, &&_0f_0x40_1, &&_0f_0x40_2, &&_0f_0x40_3, &&_0f_0x40_4, &&_0f_0x40_5, &&_0f_0x40_6, &&_0f_0x40_7,
|
||||
&&_0f_0x40_8, &&_0f_0x40_9, &&_0f_0x40_A, &&_0f_0x40_B, &&_0f_0x40_C, &&_0f_0x40_D, &&_0f_0x40_E, &&_0f_0x40_F,
|
||||
&&_0f_0x50, &&_0f_0x51, &&_0f_0x52, &&_0f_0x53, &&_0f_0x54, &&_0f_0x55, &&_0f_0x56, &&_0f_0x57, //0x50-0x57
|
||||
@@ -117,17 +115,17 @@ int Run(x86emu_t *emu, int step)
|
||||
&&_0f_0x80_8, &&_0f_0x80_9, &&_0f_0x80_A, &&_0f_0x80_B, &&_0f_0x80_C, &&_0f_0x80_D, &&_0f_0x80_E, &&_0f_0x80_F,
|
||||
&&_0f_0x90_0, &&_0f_0x90_1, &&_0f_0x90_2, &&_0f_0x90_3, &&_0f_0x90_4, &&_0f_0x90_5, &&_0f_0x90_6, &&_0f_0x90_7,
|
||||
&&_0f_0x90_8, &&_0f_0x90_9, &&_0f_0x90_A, &&_0f_0x90_B, &&_0f_0x90_C, &&_0f_0x90_D, &&_0f_0x90_E, &&_0f_0x90_F,
|
||||
&&_default, &&_default, &&_0f_0xA2, &&_0f_0xA3, &&_0f_0xA4, &&_0f_0xA5, &&_default, &&_default, //0xA0-0xA7
|
||||
&&_default, &&_default, &&_default, &&_0f_0xAB, &&_0f_0xAC, &&_0f_0xAD, &&_0f_0xAE, &&_0f_0xAF,
|
||||
&&_0f_0xA0, &&_0f_0xA1, &&_0f_0xA2, &&_0f_0xA3, &&_0f_0xA4, &&_0f_0xA5, &&_default, &&_default, //0xA0-0xA7
|
||||
&&_0f_0xA8, &&_0f_0xA9, &&_default, &&_0f_0xAB, &&_0f_0xAC, &&_0f_0xAD, &&_0f_0xAE, &&_0f_0xAF,
|
||||
&&_0f_0xB0, &&_0f_0xB1, &&_default, &&_0f_0xB3, &&_default, &&_default, &&_0f_0xB6, &&_0f_0xB7,
|
||||
&&_default, &&_default, &&_0f_0xBA, &&_0f_0xBB, &&_0f_0xBC, &&_0f_0xBD, &&_0f_0xBE, &&_0f_0xBF,
|
||||
&&_0f_0xC0, &&_0f_0xC1, &&_0f_0xC2, &&_default, &&_0f_0xC4, &&_0f_0xC5, &&_0f_0xC6, &&_0f_0xC7,
|
||||
&&_0f_0xC8, &&_0f_0xC9, &&_0f_0xCA, &&_0f_0xCB, &&_0f_0xCC, &&_0f_0xCD, &&_0f_0xCE, &&_0f_0xCF, //0xC8-0xCF
|
||||
&&_default, &&_0f_0xD1, &&_0f_0xD2, &&_0f_0xD3, &&_0f_0xD4 ,&&_0f_0xD5, &&_default, &&_default, //0xD0-0xD7
|
||||
&&_default, &&_0f_0xD1, &&_0f_0xD2, &&_0f_0xD3, &&_0f_0xD4 ,&&_0f_0xD5, &&_default, &&_0f_0xD7, //0xD0-0xD7
|
||||
&&_0f_0xD8, &&_0f_0xD9, &&_default, &&_0f_0xDB, &&_0f_0xDC ,&&_0f_0xDD, &&_default, &&_0f_0xDF, //0xD8-0xDF
|
||||
&&_0f_0xE0, &&_0f_0xE1, &&_0f_0xE2, &&_0f_0xE3, &&_0f_0xE4 ,&&_0f_0xE5, &&_default, &&_default, //0xE0-0xE7
|
||||
&&_0f_0xE8, &&_0f_0xE9, &&_default, &&_0f_0xEB, &&_0f_0xEC ,&&_0f_0xED, &&_default, &&_0f_0xEF, //0xE8-0xEF
|
||||
&&_default, &&_0f_0xF1, &&_0f_0xF2, &&_0f_0xF3, &&_0f_0xF4 ,&&_0f_0xF5, &&_0f_0xF6, &&_default, //0xF0-0xF7
|
||||
&&_0f_0xE0, &&_0f_0xE1, &&_0f_0xE2, &&_0f_0xE3, &&_0f_0xE4 ,&&_0f_0xE5, &&_default, &&_0f_0xE7, //0xE0-0xE7
|
||||
&&_0f_0xE8, &&_0f_0xE9, &&_0f_0xEA, &&_0f_0xEB, &&_0f_0xEC ,&&_0f_0xED, &&_0f_0xEE, &&_0f_0xEF, //0xE8-0xEF
|
||||
&&_default, &&_0f_0xF1, &&_0f_0xF2, &&_0f_0xF3, &&_0f_0xF4 ,&&_0f_0xF5, &&_0f_0xF6, &&_0f_0xF7, //0xF0-0xF7
|
||||
&&_0f_0xF8, &&_0f_0xF9, &&_0f_0xFA, &&_default, &&_0f_0xFC ,&&_0f_0xFD, &&_0f_0xFE, &&_default //0xF8-0xFF
|
||||
};
|
||||
|
||||
@@ -138,20 +136,20 @@ int Run(x86emu_t *emu, int step)
|
||||
&&_default, &&_66_0x18_1, &&_default, &&_66_0x18_3, &&_default ,&&_66_0x18_5, &&_default, &&_default, //0x18-0x1F
|
||||
&&_default, &&_66_0x20_1, &&_default, &&_66_0x20_3, &&_default ,&&_66_0x20_5, &&_66_0x26, &&_default, //0x20-0x27
|
||||
&&_default, &&_66_0x28_1, &&_default, &&_66_0x28_3, &&_default ,&&_66_0x28_5, &&_66_0x2E, &&_default, //0x28-0x2F
|
||||
&&_default, &&_66_0x30_1, &&_default, &&_66_0x30_3, &&_default ,&&_66_0x30_5, &&_default, &&_default, //0x30-0x37
|
||||
&&_default, &&_66_0x30_1, &&_default, &&_66_0x30_3, &&_default ,&&_66_0x30_5, &&_66_0x36, &&_default, //0x30-0x37
|
||||
&&_default, &&_66_0x39, &&_default, &&_66_0x3B, &&_default, &&_66_0x3D, &&_default, &&_default, //0x38-0x3F
|
||||
&&_66_0x40, &&_66_0x41, &&_66_0x42, &&_66_0x43, &&_66_0x44, &&_66_0x45, &&_66_0x46, &&_66_0x47,
|
||||
&&_66_0x48, &&_66_0x49, &&_66_0x4A, &&_66_0x4B, &&_66_0x4C, &&_66_0x4D, &&_66_0x4E, &&_66_0x4F,
|
||||
&&_66_0x50, &&_66_0x51, &&_66_0x52, &&_66_0x53, &&_66_0x54, &&_66_0x55, &&_66_0x56, &&_66_0x57, //0x50-0x57
|
||||
&&_66_0x58, &&_66_0x59, &&_66_0x5A, &&_66_0x5B, &&_66_0x5C, &&_66_0x5D, &&_66_0x5E, &&_66_0x5F, //0x58-0x5F
|
||||
&&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_66_0x66, &&_default, //0x60-0x67
|
||||
&&_66_0x60, &&_66_0x61, &&_default, &&_default, &&_default ,&&_default, &&_66_0x66, &&_default, //0x60-0x67
|
||||
&&_66_0x68, &&_66_0x69, &&_66_0x6A, &&_66_0x6B, &&_default, &&_default, &&_default, &&_default, //0x68-0x6F
|
||||
&&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0x70-0x77
|
||||
&&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0x78-0x7F
|
||||
&&_default, &&_66_0x81, &&_default, &&_66_0x83, &&_default, &&_66_0x85, &&_default, &&_66_0x87,
|
||||
&&_default, &&_66_0x89, &&_default, &&_66_0x8B, &&_66_0x8C, &&_default, &&_66_0x8E, &&_66_0x8F,
|
||||
&&_66_0x90, &&_default, &&_66_0x92, &&_default, &&_default, &&_default, &&_default, &&_default,
|
||||
&&_66_0x98, &&_66_0x99, &&_default, &&_default, &&_66_0x9C, &&_default, &&_default, &&_default, //0x98-0x9F
|
||||
&&_66_0x90, &&_66_0x91, &&_66_0x92, &&_66_0x93, &&_66_0x94, &&_66_0x95, &&_66_0x96, &&_66_0x97,
|
||||
&&_66_0x98, &&_66_0x99, &&_default, &&_default, &&_66_0x9C, &&_66_0x9D, &&_default, &&_default, //0x98-0x9F
|
||||
&&_default, &&_66_0xA1, &&_default, &&_66_0xA3, &&_default, &&_66_0xA5, &&_default, &&_66_0xA7,
|
||||
&&_default, &&_66_0xA9, &&_default, &&_66_0xAB, &&_default, &&_66_0xAD, &&_default, &&_66_0xAF, //0xA8-0xAF
|
||||
&&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0xB0-0xB7
|
||||
@@ -163,7 +161,7 @@ int Run(x86emu_t *emu, int step)
|
||||
&&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0xE0-0xE7
|
||||
&&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0xE8-0xEF
|
||||
&&_default, &&_default, &&_66_0xF2, &&_66_0xF3, &&_default, &&_default, &&_default, &&_66_0xF7,
|
||||
&&_default, &&_default, &&_default, &&_default, &&_default, &&_default, &&_default, &&_66_0xFF
|
||||
&&_66_0xF8, &&_66_0xF9, &&_default, &&_default, &&_default, &&_default, &&_default, &&_66_0xFF
|
||||
};
|
||||
|
||||
static const void* opcodes660f[256] = {
|
||||
@@ -190,15 +188,15 @@ int Run(x86emu_t *emu, int step)
|
||||
&&_default, &&_default, &&_default, &&_6f_0xA3, &&_6f_0xA4, &&_6f_0xA5, &&_default, &&_default,
|
||||
&&_default, &&_default, &&_default, &&_6f_0xAB, &&_6f_0xAC, &&_6f_0xAD, &&_default, &&_6f_0xAF,
|
||||
&&_default, &&_6f_0xB1, &&_default, &&_6f_0xB3, &&_default, &&_default, &&_6f_0xB6, &&_default,
|
||||
&&_default, &&_default, &&_default, &&_6f_0xBB, &&_6f_0xBC, &&_6f_0xBD, &&_6f_0xBE, &&_default, //0xB8-0xBF
|
||||
&&_default, &&_default, &&_6f_0xBA, &&_6f_0xBB, &&_6f_0xBC, &&_6f_0xBD, &&_6f_0xBE, &&_default, //0xB8-0xBF
|
||||
&&_default, &&_6f_0xC1, &&_6f_0xC2, &&_default, &&_6f_0xC4, &&_6f_0xC5, &&_6f_0xC6, &&_default,
|
||||
&&_default, &&_default, &&_default, &&_default, &&_default ,&&_default, &&_default, &&_default, //0xC8-0xCF
|
||||
&&_default, &&_6f_0xD1, &&_6f_0xD2, &&_6f_0xD3, &&_6f_0xD4, &&_6f_0xD5, &&_6f_0xD6, &&_6f_0xD7,
|
||||
&&_6f_0xD8, &&_6f_0xD9, &&_default, &&_6f_0xDB, &&_6f_0xDC, &&_default, &&_6f_0xDE, &&_6f_0xDF,
|
||||
&&_default, &&_6f_0xE1, &&_6f_0xE2, &&_default, &&_default, &&_6f_0xE5, &&_6f_0xE6, &&_6f_0xE7,
|
||||
&&_6f_0xE0, &&_6f_0xE1, &&_6f_0xE2, &&_6f_0xE3, &&_default, &&_6f_0xE5, &&_6f_0xE6, &&_6f_0xE7,
|
||||
&&_6f_0xE8, &&_6f_0xE9, &&_6f_0xEA, &&_6f_0xEB, &&_6f_0xEC, &&_6f_0xED, &&_6f_0xEE, &&_6f_0xEF,
|
||||
&&_default, &&_6f_0xF1, &&_6f_0xF2, &&_6f_0xF3, &&_6f_0xF4, &&_6f_0xF5, &&_6f_0xF6, &&_6f_0xF7,
|
||||
&&_default, &&_6f_0xF9, &&_6f_0xFA, &&_6f_0xFB, &&_6f_0xFC, &&_6f_0xFD, &&_6f_0xFE, &&_default
|
||||
&&_6f_0xF8, &&_6f_0xF9, &&_6f_0xFA, &&_6f_0xFB, &&_6f_0xFC, &&_6f_0xFD, &&_6f_0xFE, &&_default
|
||||
};
|
||||
|
||||
x86emurun:
|
||||
@@ -206,17 +204,18 @@ x86emurun:
|
||||
// UnpackFlags(emu);
|
||||
#ifdef HAVE_TRACE
|
||||
_trace:
|
||||
__builtin_prefetch((void*)ip, 0, 0);
|
||||
emu->prev2_ip = emu->prev_ip;
|
||||
emu->prev_ip = old_ip;
|
||||
old_ip = ip;
|
||||
if(emu->dec && (
|
||||
(emu->trace_end == 0)
|
||||
|| ((ip >= emu->trace_start) && (ip < emu->trace_end))) )
|
||||
emu->prev_ip = R_EIP;
|
||||
R_EIP=ip;
|
||||
if(my_context->dec && (
|
||||
(trace_end == 0)
|
||||
|| ((ip >= trace_start) && (ip < trace_end))) )
|
||||
PrintTrace(emu, ip, 0);
|
||||
|
||||
#define NEXT __builtin_prefetch((void*)ip, 0, 0); goto _trace;
|
||||
#define NEXT goto _trace
|
||||
#else
|
||||
#define NEXT old_ip = ip; __builtin_prefetch((void*)ip, 0, 0); goto *baseopcodes[(opcode=F8)];
|
||||
#define NEXT goto *baseopcodes[(R_EIP=ip, opcode=F8)]
|
||||
#endif
|
||||
|
||||
#include "modrm.h"
|
||||
@@ -295,17 +294,30 @@ _trace:
|
||||
NEXT;
|
||||
_0x07: /* POP ES */
|
||||
emu->segs[_ES] = Pop(emu); // no check, no use....
|
||||
emu->segs_clean[_ES] = 0;
|
||||
NEXT;
|
||||
|
||||
_0x0E: /* PUSH CS */
|
||||
Push(emu, emu->segs[_CS]);
|
||||
NEXT;
|
||||
_0x0F: /* More instructions */
|
||||
#include "run0f.h"
|
||||
NEXT;
|
||||
|
||||
_0x16: /* PUSH SS */
|
||||
Push(emu, emu->segs[_SS]); // even if a segment is a 16bits, a 32bits push/pop is done
|
||||
NEXT;
|
||||
_0x17: /* POP SS */
|
||||
emu->segs[_SS] = Pop(emu); // no check, no use....
|
||||
emu->segs_clean[_SS] = 0;
|
||||
NEXT;
|
||||
|
||||
_0x1E: /* PUSH DS */
|
||||
Push(emu, emu->segs[_DS]); // even if a segment is a 16bits, a 32bits push/pop is done
|
||||
NEXT;
|
||||
_0x1F: /* POP DS */
|
||||
emu->segs[_DS] = Pop(emu); // no check, no use....
|
||||
emu->segs_clean[_DS] = 0;
|
||||
NEXT;
|
||||
|
||||
_0x26: /* ES: */
|
||||
@@ -315,18 +327,24 @@ _trace:
|
||||
NEXT;
|
||||
|
||||
_0x2E: /* CS: */
|
||||
// Can also happens before a condition branch: Branch Not Taken Hint
|
||||
NEXT; //ignored...
|
||||
_0x2F: /* DAS */
|
||||
R_AL = das8(emu, R_AL);
|
||||
NEXT;
|
||||
|
||||
_0x36: /* SS: */
|
||||
NEXT;
|
||||
_0x37: /* AAA */
|
||||
R_AX = aaa16(emu, R_AX);
|
||||
NEXT;
|
||||
|
||||
_0x3E: /* DS: */
|
||||
// Can also happens before a condition branch: Branch Taken Hint
|
||||
NEXT;
|
||||
_0x3F: /* AAS */
|
||||
R_AX = aas16(emu, R_AX);
|
||||
NEXT;
|
||||
|
||||
|
||||
_0x40:
|
||||
_0x41:
|
||||
_0x42:
|
||||
@@ -395,28 +413,21 @@ _trace:
|
||||
R_ECX = Pop(emu);
|
||||
R_EAX = Pop(emu);
|
||||
NEXT;
|
||||
_0x62: /* BOUND Gd, Ed */
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
// ignoring the test for now
|
||||
NEXT;
|
||||
_0x64: /* FS: */
|
||||
|
||||
switch(F8)
|
||||
{
|
||||
case 0xA1:
|
||||
tmp32s = F32S;
|
||||
R_EAX = *(uint32_t*)((emu->segs[_FS]) + tmp32s);
|
||||
break;
|
||||
case 0x89:
|
||||
nextop = F8;
|
||||
GET_ED_OFFS(emu->segs[_FS]);
|
||||
ED->dword[0] = GD.dword[0];
|
||||
break;
|
||||
default:
|
||||
UnimpOpcode(emu);
|
||||
}
|
||||
|
||||
emu->old_ip = R_EIP;
|
||||
R_EIP = ip-1;
|
||||
RunFS(emu); // implemented in Run66.c
|
||||
ip = R_EIP;
|
||||
if(emu->quit) goto fini;
|
||||
NEXT;
|
||||
_0x65: /* GS: */
|
||||
emu->old_ip = old_ip;
|
||||
R_EIP = ip;
|
||||
emu->old_ip = R_EIP;
|
||||
R_EIP = ip-1;
|
||||
RunGS(emu); // implemented in Run66.c
|
||||
ip = R_EIP;
|
||||
if(emu->quit) goto fini;
|
||||
@@ -425,8 +436,8 @@ _trace:
|
||||
_0x66: /* Prefix to change width of intructions, so here, down to 16bits */
|
||||
#include "run66.h"
|
||||
_0x67: /* Prefix to change width of registers */
|
||||
emu->old_ip = old_ip;
|
||||
R_EIP = ip;
|
||||
emu->old_ip = R_EIP;
|
||||
R_EIP = ip-1; // don't count 0x67 yet
|
||||
Run67(emu); // implemented in Run66.c
|
||||
ip = R_EIP;
|
||||
if(emu->quit) goto fini;
|
||||
@@ -452,19 +463,33 @@ _trace:
|
||||
GD.dword[0] = imul32(emu, ED->dword[0], (uint32_t)tmp32s);
|
||||
NEXT;
|
||||
_0x6C: /* INSB */
|
||||
*(int8_t*)R_EDI = 0; // faking port read
|
||||
*(int8_t*)(R_EDI+GetESBaseEmu(emu)) = 0; // faking port read, using explicit ES segment
|
||||
if(ACCESS_FLAG(F_DF))
|
||||
R_EDI-=1;
|
||||
else
|
||||
R_EDI+=1;
|
||||
NEXT;
|
||||
_0x6D: /* INSD */
|
||||
*(int32_t*)R_EDI = 0; // faking port read
|
||||
*(int32_t*)(R_EDI+GetESBaseEmu(emu)) = 0; // faking port read, using explicit ES segment
|
||||
if(ACCESS_FLAG(F_DF))
|
||||
R_EDI-=4;
|
||||
else
|
||||
R_EDI+=4;
|
||||
NEXT;
|
||||
_0x6E: /* OUTSB */
|
||||
// faking port write, using explicit ES segment
|
||||
if(ACCESS_FLAG(F_DF))
|
||||
R_ESI-=1;
|
||||
else
|
||||
R_ESI+=1;
|
||||
NEXT;
|
||||
_0x6F: /* OUTSD */
|
||||
// faking port write, using explicit ES segment
|
||||
if(ACCESS_FLAG(F_DF))
|
||||
R_ESI-=4;
|
||||
else
|
||||
R_ESI+=4;
|
||||
NEXT;
|
||||
|
||||
#define GOCOND(BASE, PREFIX, CONDITIONAL) \
|
||||
_##BASE##_0: \
|
||||
@@ -555,6 +580,7 @@ _trace:
|
||||
|
||||
|
||||
_0x80: /* GRP Eb,Ib */
|
||||
_0x82: // 0x82 and 0x80 are the same opcodes it seems?
|
||||
nextop = F8;
|
||||
GET_EB;
|
||||
tmp8u = F8;
|
||||
@@ -643,7 +669,11 @@ _trace:
|
||||
GET_ED;
|
||||
GD.dword[0] = ED->dword[0];
|
||||
NEXT;
|
||||
|
||||
_0x8C: /* MOV Ed, Seg */
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
ED->dword[0] = emu->segs[((nextop&0x38)>>3)];
|
||||
NEXT;
|
||||
_0x8D: /* LEA Gd,M */
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
@@ -653,6 +683,7 @@ _trace:
|
||||
nextop = F8;
|
||||
GET_EW;
|
||||
emu->segs[((nextop&0x38)>>3)] = EW->word[0];
|
||||
emu->segs_clean[((nextop&0x38)>>3)] = 0;
|
||||
NEXT;
|
||||
_0x8F: /* POP Ed */
|
||||
nextop = F8;
|
||||
@@ -881,7 +912,7 @@ _trace:
|
||||
NEXT;
|
||||
|
||||
_0xCC: /* INT 3 */
|
||||
emu->old_ip = old_ip;
|
||||
emu->old_ip = R_EIP;
|
||||
R_EIP = ip;
|
||||
x86Int3(emu);
|
||||
ip = R_EIP;
|
||||
@@ -890,14 +921,15 @@ _trace:
|
||||
_0xCD: /* INT Ib */
|
||||
nextop = F8;
|
||||
if(nextop == 0x80) {
|
||||
emu->old_ip = old_ip;
|
||||
emu->old_ip = R_EIP;
|
||||
R_EIP = ip;
|
||||
x86Syscall(emu);
|
||||
ip = R_EIP;
|
||||
if(emu->quit) goto fini;
|
||||
} else {
|
||||
printf_log(LOG_NONE, "Unsupported Int %02Xh\n", nextop);
|
||||
emu->old_ip = old_ip;
|
||||
int tid = GetTID();
|
||||
printf_log(LOG_NONE, "%04d|%p: Ignoring Unsupported Int %02Xh\n", tid, (void*)ip, nextop);
|
||||
emu->old_ip = R_EIP;
|
||||
R_EIP = ip;
|
||||
emu->quit = 1;
|
||||
emu->error |= ERR_UNIMPL;
|
||||
@@ -905,6 +937,14 @@ _trace:
|
||||
}
|
||||
NEXT;
|
||||
|
||||
_0xCF: /* IRET */
|
||||
ip = Pop(emu);
|
||||
emu->segs[_CS] = Pop(emu);
|
||||
emu->segs_clean[_CS] = 0;
|
||||
emu->packed_eflags.x32 = ((Pop(emu) & 0x3F7FD7)/* & (0xffff-40)*/ ) | 0x2; // mask off res2 and res3 and on res1
|
||||
UnpackFlags(emu);
|
||||
RESET_FLAGS(emu);
|
||||
NEXT;
|
||||
_0xD0: /* GRP2 Eb,1 */
|
||||
_0xD2: /* GRP2 Eb,CL */
|
||||
nextop = F8;
|
||||
@@ -1000,12 +1040,22 @@ _trace:
|
||||
STEP
|
||||
}
|
||||
NEXT;
|
||||
|
||||
_0xE4: /* IN AL, Ib */
|
||||
tmp32s = F8; // port address
|
||||
R_AL = 0; // nothing... should do a warning maybe?
|
||||
NEXT;
|
||||
_0xE5: /* IN EAX, Ib */
|
||||
tmp32s = F8; // port address
|
||||
R_EAX = 0; // nothing... should do a warning maybe?
|
||||
NEXT;
|
||||
|
||||
_0xE6: /* OUT Ib, AL */
|
||||
tmp32s = F8; // port address
|
||||
//nothing goes out...
|
||||
NEXT;
|
||||
_0xE7: /* OUT Ib, EAX */
|
||||
tmp32s = F8; // port address
|
||||
//nothing goes out...
|
||||
NEXT;
|
||||
_0xE8: /* CALL Id */
|
||||
tmp32s = F32S; // call is relative
|
||||
Push(emu, ip);
|
||||
@@ -1023,15 +1073,23 @@ _trace:
|
||||
ip += tmp32s;
|
||||
STEP
|
||||
NEXT;
|
||||
_0xEC: /* IN AL, DX */
|
||||
R_AL = 0; // nothing... should do a warning maybe?
|
||||
NEXT;
|
||||
_0xED: /* IN EAX, DX */
|
||||
R_EAX = 0; // nothing... should do a warning maybe?
|
||||
NEXT;
|
||||
|
||||
_0xF0: /* LOCK */
|
||||
emu->old_ip = old_ip;
|
||||
R_EIP = ip;
|
||||
emu->old_ip = R_EIP;
|
||||
R_EIP = ip-1; // dont't count F0 yet
|
||||
RunLock(emu); // implemented in Run66.c
|
||||
ip = R_EIP;
|
||||
if(emu->quit) goto fini;
|
||||
NEXT;
|
||||
|
||||
_0xF1: /* INT1 */
|
||||
// does nothing for now
|
||||
NEXT;
|
||||
_0xF2: /* REPNZ prefix */
|
||||
_0xF3: /* REPZ prefix */
|
||||
nextop = F8;
|
||||
@@ -1064,6 +1122,55 @@ _trace:
|
||||
R_EDI += tmp8s;
|
||||
}
|
||||
break;
|
||||
case 0xA7: /* REP(N)Z CMPSW */
|
||||
tmp16u = 0;
|
||||
tmp16u2 = 0;
|
||||
tmp8s *= 2;
|
||||
if(opcode==0xF2) {
|
||||
while(tmp32u) {
|
||||
--tmp32u;
|
||||
tmp16u2 = *(uint16_t*)R_EDI;
|
||||
tmp16u = *(uint16_t*)R_ESI;
|
||||
R_EDI += tmp8s;
|
||||
R_ESI += tmp8s;
|
||||
if(tmp16u2==tmp16u)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
while(tmp32u) {
|
||||
--tmp32u;
|
||||
tmp16u2 = *(uint16_t*)R_EDI;
|
||||
tmp16u = *(uint16_t*)R_ESI;
|
||||
R_EDI += tmp8s;
|
||||
R_ESI += tmp8s;
|
||||
if(tmp16u2!=tmp16u)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(R_ECX) cmp16(emu, tmp16u, tmp16u2);
|
||||
break;
|
||||
case 0xAF: /* REP(N)Z SCASW */
|
||||
tmp16u = 0;
|
||||
tmp8s *= 2;
|
||||
if(opcode==0xF2) {
|
||||
while(tmp32u) {
|
||||
--tmp32u;
|
||||
tmp16u = *(uint16_t*)R_EDI;
|
||||
R_EDI += tmp8s;
|
||||
if(R_AX==tmp16u)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
while(tmp32u) {
|
||||
--tmp32u;
|
||||
tmp16u = *(uint16_t*)R_EDI;
|
||||
R_EDI += tmp8s;
|
||||
if(R_AX!=tmp16u)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(R_ECX) cmp16(emu, R_AX, tmp16u);
|
||||
break;
|
||||
default:
|
||||
goto _default;
|
||||
}
|
||||
@@ -1072,6 +1179,48 @@ _trace:
|
||||
tmp8s = ACCESS_FLAG(F_DF)?-1:+1;
|
||||
tmp32u = R_ECX;
|
||||
switch(nextop) {
|
||||
case 0x18:
|
||||
case 0x19:
|
||||
case 0x1A:
|
||||
case 0x1B:
|
||||
case 0x1C:
|
||||
case 0x1D:
|
||||
case 0x40:
|
||||
case 0x41:
|
||||
case 0x42:
|
||||
case 0x43:
|
||||
case 0x44:
|
||||
case 0x45:
|
||||
case 0x46:
|
||||
case 0x47:
|
||||
case 0x48:
|
||||
case 0x49:
|
||||
case 0x4A:
|
||||
case 0x4B:
|
||||
case 0x4C:
|
||||
case 0x4D:
|
||||
case 0x4E:
|
||||
case 0x4F:
|
||||
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: /* BND / NOP */
|
||||
case 0xE8:
|
||||
case 0xE9:
|
||||
--ip;
|
||||
NEXT;
|
||||
case 0x90: /* PAUSE */
|
||||
NEXT;
|
||||
case 0xC3: /* REPZ RET... yup */
|
||||
@@ -1297,7 +1446,12 @@ _trace:
|
||||
CHECK_FLAGS(emu);
|
||||
SET_FLAG(F_CF);
|
||||
NEXT;
|
||||
|
||||
_0xFA: /* CLI */
|
||||
CLEAR_FLAG(F_IF); //not really handled...
|
||||
NEXT;
|
||||
_0xFB: /* STI */
|
||||
SET_FLAG(F_IF);
|
||||
NEXT;
|
||||
_0xFC: /* CLD */
|
||||
CLEAR_FLAG(F_DF);
|
||||
NEXT;
|
||||
@@ -1315,7 +1469,7 @@ _trace:
|
||||
EB->byte[0] = dec8(emu, EB->byte[0]);
|
||||
break;
|
||||
default:
|
||||
emu->old_ip = old_ip;
|
||||
emu->old_ip = R_EIP;
|
||||
R_EIP = ip;
|
||||
printf_log(LOG_NONE, "Illegal Opcode %02X %02X\n", opcode, nextop);
|
||||
emu->quit=1;
|
||||
@@ -1340,7 +1494,7 @@ _trace:
|
||||
break;
|
||||
case 3: /* CALL FAR Ed */
|
||||
if(nextop>0xc0) {
|
||||
emu->old_ip = old_ip;
|
||||
emu->old_ip = R_EIP;
|
||||
R_EIP = ip;
|
||||
printf_log(LOG_NONE, "Illegal Opcode %02X %02X\n", opcode, nextop);
|
||||
emu->quit=1;
|
||||
@@ -1360,7 +1514,7 @@ _trace:
|
||||
break;
|
||||
case 5: /* JMP FAR Ed */
|
||||
if(nextop>0xc0) {
|
||||
emu->old_ip = old_ip;
|
||||
emu->old_ip = R_EIP;
|
||||
R_EIP = ip;
|
||||
printf_log(LOG_NONE, "Illegal Opcode 0x%02X 0x%02X\n", opcode, nextop);
|
||||
emu->quit=1;
|
||||
@@ -1376,7 +1530,7 @@ _trace:
|
||||
Push(emu, ED->dword[0]);
|
||||
break;
|
||||
default:
|
||||
emu->old_ip = old_ip;
|
||||
emu->old_ip = R_EIP;
|
||||
R_EIP = ip;
|
||||
printf_log(LOG_NONE, "Illegal Opcode 0x%02X 0x%02X\n", opcode, nextop);
|
||||
emu->quit=1;
|
||||
@@ -1386,13 +1540,13 @@ _trace:
|
||||
NEXT;
|
||||
|
||||
_default:
|
||||
emu->old_ip = old_ip;
|
||||
emu->old_ip = R_EIP;
|
||||
R_EIP = ip;
|
||||
UnimpOpcode(emu);
|
||||
goto fini;
|
||||
#ifdef DYNAREC
|
||||
stepout:
|
||||
emu->old_ip = old_ip;
|
||||
emu->old_ip = R_EIP;
|
||||
R_EIP = ip;
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
+379
-53
@@ -13,33 +13,26 @@
|
||||
#include "box86context.h"
|
||||
|
||||
|
||||
#define F8 *(uint8_t*)(R_EIP++)
|
||||
#define F8S *(int8_t*)(R_EIP++)
|
||||
#define F16 *(uint16_t*)(R_EIP+=2, R_EIP-2)
|
||||
#define F32 *(uint32_t*)(R_EIP+=4, R_EIP-4)
|
||||
#define F32S *(int32_t*)(R_EIP+=4, R_EIP-4)
|
||||
#define PK(a) *(uint8_t*)(R_EIP+a)
|
||||
#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)
|
||||
{
|
||||
uint8_t opcode = Fetch8(emu);
|
||||
uintptr_t ip = R_EIP+2; //skip 67 66
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop;
|
||||
reg32_t *op1, *op2, *op3, *op4;
|
||||
reg32_t ea1, ea2, ea3, ea4;
|
||||
uint8_t tmp8u;
|
||||
int8_t tmp8s;
|
||||
uint16_t tmp16u, tmp16u2;
|
||||
int16_t tmp16s;
|
||||
uint32_t tmp32u;
|
||||
int32_t tmp32s;
|
||||
uint64_t tmp64u;
|
||||
int64_t tmp64s;
|
||||
reg32_t *op1, *op2;
|
||||
switch(opcode) {
|
||||
|
||||
case 0x8D: /* LEA Gw,Ew */
|
||||
nextop = Fetch8(emu);
|
||||
nextop = F8;
|
||||
op1=GetEw16(emu, nextop);
|
||||
op2=GetG(emu, nextop);
|
||||
op2->word[0] = (uint16_t)(uintptr_t)op1;
|
||||
@@ -47,77 +40,79 @@ void Run6766(x86emu_t *emu)
|
||||
|
||||
|
||||
default:
|
||||
ip-=2; //unfetch
|
||||
UnimpOpcode(emu);
|
||||
}
|
||||
R_EIP = ip;
|
||||
}
|
||||
|
||||
void Run67(x86emu_t *emu)
|
||||
{
|
||||
uint8_t opcode = Fetch8(emu);
|
||||
uint8_t nextop;
|
||||
reg32_t *op1, *op2, *op3, *op4;
|
||||
reg32_t ea1, ea2, ea3, ea4;
|
||||
uint8_t tmp8u;
|
||||
uintptr_t ip = R_EIP+1; //skip 67
|
||||
uint8_t opcode = F8;
|
||||
int8_t tmp8s;
|
||||
uint16_t tmp16u;
|
||||
int16_t tmp16s;
|
||||
uint32_t tmp32u;
|
||||
int32_t tmp32s;
|
||||
uint64_t tmp64u;
|
||||
int64_t tmp64s;
|
||||
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 = Fetch8s(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 = Fetch8s(emu);
|
||||
tmp8s = F8S;
|
||||
--R_CX; // don't update flags
|
||||
if(R_CX && ACCESS_FLAG(F_ZF))
|
||||
R_EIP += tmp8s;
|
||||
break;
|
||||
case 0xE2: /* LOOP */
|
||||
tmp8s = Fetch8s(emu);
|
||||
tmp8s = F8S;
|
||||
--R_CX; // don't update flags
|
||||
if(R_CX)
|
||||
R_EIP += tmp8s;
|
||||
break;
|
||||
case 0xE3: /* JCXZ */
|
||||
tmp8s = Fetch8s(emu);
|
||||
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)
|
||||
{
|
||||
uint8_t opcode = Fetch8(emu);
|
||||
uintptr_t ip = R_EIP+1;
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop;
|
||||
reg32_t *oped;
|
||||
reg32_t ea1;
|
||||
sse_regs_t *opex, eax1;
|
||||
mmx_regs_t *opem;
|
||||
uint8_t tmp8u;
|
||||
int8_t tmp8s;
|
||||
uint16_t tmp16u;
|
||||
int16_t tmp16s;
|
||||
uint32_t tmp32u, tmp32u2;
|
||||
int32_t tmp32s;
|
||||
uint64_t tmp64u;
|
||||
int64_t tmp64s;
|
||||
pthread_mutex_lock(&emu->context->mutex_lock);
|
||||
switch(opcode) {
|
||||
#define GO(B, OP) \
|
||||
@@ -231,7 +226,7 @@ void RunLock(x86emu_t *emu)
|
||||
break;
|
||||
|
||||
default:
|
||||
R_EIP -= 3; //unfetch
|
||||
ip -= 3; //unfetch
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -283,7 +278,7 @@ void RunLock(x86emu_t *emu)
|
||||
break;
|
||||
default:
|
||||
// trigger invalid lock?
|
||||
R_EIP -= 2; // unfetch
|
||||
ip -= 2; // unfetch
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -342,40 +337,100 @@ void RunLock(x86emu_t *emu)
|
||||
default:
|
||||
//UnimpOpcode(emu);
|
||||
// should trigger invalid unlock ?
|
||||
R_EIP--; // "unfetch" to use normal instruction
|
||||
ip--; // "unfetch" to use normal instruction
|
||||
}
|
||||
R_EIP = ip;
|
||||
pthread_mutex_unlock(&emu->context->mutex_lock);
|
||||
}
|
||||
|
||||
void RunGS(x86emu_t *emu)
|
||||
{
|
||||
uint8_t opcode = Fetch8(emu);
|
||||
uintptr_t ip = R_EIP+1;
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop;
|
||||
reg32_t *oped;
|
||||
reg32_t ea1;
|
||||
sse_regs_t *opex, eax1;
|
||||
mmx_regs_t *opem;
|
||||
uint8_t tmp8u;
|
||||
int8_t tmp8s;
|
||||
uint16_t tmp16u;
|
||||
int16_t tmp16s;
|
||||
uint32_t tmp32u;
|
||||
int32_t tmp32s;
|
||||
uint64_t tmp64u;
|
||||
int64_t tmp64s;
|
||||
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;
|
||||
@@ -401,6 +456,11 @@ void RunGS(x86emu_t *emu)
|
||||
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);
|
||||
@@ -419,6 +479,27 @@ void RunGS(x86emu_t *emu)
|
||||
*(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);
|
||||
@@ -474,6 +555,251 @@ void RunGS(x86emu_t *emu)
|
||||
}
|
||||
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;
|
||||
}
|
||||
+222
-57
@@ -22,6 +22,7 @@
|
||||
#ifdef HAVE_TRACE
|
||||
#include "x86trace.h"
|
||||
#endif
|
||||
#include "x86tls.h"
|
||||
|
||||
#define PARITY(x) (((emu->x86emu_parity_tab[(x) / 32] >> ((x) % 32)) & 1) == 0)
|
||||
#define XOR2(x) (((x) ^ ((x)>>1)) & 0x1)
|
||||
@@ -31,9 +32,9 @@ int32_t EXPORT my___libc_start_main(x86emu_t* emu, int *(main) (int, char * *, c
|
||||
//TODO: register rtld_fini
|
||||
//TODO: register fini
|
||||
// let's cheat and set all args...
|
||||
Push(emu, (uint32_t)emu->context->envv);
|
||||
Push(emu, (uint32_t)emu->context->argv);
|
||||
Push(emu, (uint32_t)emu->context->argc);
|
||||
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;
|
||||
@@ -43,7 +44,7 @@ int32_t EXPORT my___libc_start_main(x86emu_t* emu, int *(main) (int, char * *, c
|
||||
return 0;
|
||||
emu->quit = 0;
|
||||
}
|
||||
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);
|
||||
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
|
||||
PushExit(emu);
|
||||
R_EIP=(uint32_t)main;
|
||||
@@ -53,10 +54,10 @@ int32_t EXPORT my___libc_start_main(x86emu_t* emu, int *(main) (int, char * *, c
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* GetNativeName(x86emu_t* emu, void* p)
|
||||
const char* GetNativeName(void* p)
|
||||
{
|
||||
static char unknown[10] = "???";
|
||||
const char *ret = GetNameOffset(emu->context->maplib, p);
|
||||
const char *ret = GetNameOffset(my_context->maplib, p);
|
||||
if(ret)
|
||||
return ret;
|
||||
|
||||
@@ -76,13 +77,6 @@ const char* GetNativeName(x86emu_t* emu, void* p)
|
||||
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, ESP+4=%p)", (void*)ofs, id, *(void**)(R_ESP), *(void**)(R_ESP+4));
|
||||
emu->quit=1;
|
||||
}
|
||||
|
||||
void UpdateFlags(x86emu_t *emu)
|
||||
{
|
||||
uint32_t cc;
|
||||
@@ -537,6 +531,152 @@ 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;
|
||||
@@ -548,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);
|
||||
@@ -562,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);
|
||||
@@ -570,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);
|
||||
@@ -588,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);
|
||||
@@ -596,80 +739,102 @@ void UnpackFlags(x86emu_t* emu)
|
||||
GO(VIP);
|
||||
GO(ID);
|
||||
#undef GO
|
||||
#undef GOC
|
||||
}
|
||||
|
||||
uintptr_t GetGSBaseEmu(x86emu_t* emu)
|
||||
uintptr_t GetSegmentBaseEmu(x86emu_t* emu, int seg)
|
||||
{
|
||||
return (uintptr_t)GetGSBase(emu->context);
|
||||
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) *(uint32_t*)(uint8_t*)(ip+a)
|
||||
|
||||
static void printFunctionAddr(x86emu_t* emu, uintptr_t nextaddr, const char* text)
|
||||
{
|
||||
uint32_t sz = 0;
|
||||
uintptr_t start = 0;
|
||||
const char* symbname = FindNearestSymbolName(FindElfAddress(emu->context, nextaddr), (void*)nextaddr, &start, &sz);
|
||||
if(symbname && nextaddr>=start && nextaddr<(start+sz)) {
|
||||
if(nextaddr==start)
|
||||
printf_log(LOG_NONE, " (%s%s)", text, symbname);
|
||||
else
|
||||
printf_log(LOG_NONE, " (%s%s + 0x%x)", text, symbname, nextaddr - start);
|
||||
}
|
||||
}
|
||||
#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 && emu->dec && (
|
||||
(emu->trace_end == 0)
|
||||
|| ((ip >= emu->trace_start) && (ip < emu->trace_end))) ) {
|
||||
pthread_mutex_lock(&emu->context->mutex_trace);
|
||||
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((emu->context->trace_tid != tid) || (emu->context->trace_dynarec!=dynarec)) {
|
||||
if((my_context->trace_tid != tid) || (my_context->trace_dynarec!=dynarec)) {
|
||||
printf_log(LOG_NONE, "Thread %04d| (%s) |\n", tid, dynarec?"dyn":"int");
|
||||
emu->context->trace_tid = tid;
|
||||
emu->context->trace_dynarec = dynarec;
|
||||
my_context->trace_tid = tid;
|
||||
my_context->trace_dynarec = dynarec;
|
||||
}
|
||||
#else
|
||||
if(emu->context->trace_tid != tid) {
|
||||
if(my_context->trace_tid != tid) {
|
||||
printf_log(LOG_NONE, "Thread %04d|\n", tid);
|
||||
emu->context->trace_tid = 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, "0x%p: Exit x86emu\n", (void*)ip);
|
||||
printf_log(LOG_NONE, "%p: Exit x86emu\n", (void*)ip);
|
||||
} else {
|
||||
printf_log(LOG_NONE, "0x%p: Native call to %p => %s\n", (void*)ip, (void*)a, GetNativeName(emu, *(void**)(ip+7)));
|
||||
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(emu->dec, ip));
|
||||
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(emu, *(uintptr_t*)(R_ESP), "=> ");
|
||||
printFunctionAddr(*(uintptr_t*)(R_ESP), "=> ");
|
||||
} else if(peek==0x55) {
|
||||
printf_log(LOG_NONE, " => STACK_TOP: %p", *(void**)(R_ESP));
|
||||
printFunctionAddr(emu, ip, "here: ");
|
||||
printFunctionAddr(ip, "here: ");
|
||||
} else if(peek==0xE8) { // Call
|
||||
uintptr_t nextaddr = ip + PK32(1);
|
||||
printFunctionAddr(emu, nextaddr, "=> ");
|
||||
uintptr_t nextaddr = ip + 5 + PK32(1);
|
||||
printFunctionAddr(nextaddr, "=> ");
|
||||
} else if(peek==0xFF) {
|
||||
if(PK(1)==0x25) {
|
||||
uintptr_t nextaddr = ip + PK32(2);
|
||||
printFunctionAddr(emu, nextaddr, "=> ");
|
||||
uintptr_t nextaddr = ip + 6 + PK32(2);
|
||||
printFunctionAddr(nextaddr, "=> ");
|
||||
}
|
||||
}
|
||||
printf_log(LOG_NONE, "\n");
|
||||
}
|
||||
pthread_mutex_unlock(&emu->context->mutex_trace);
|
||||
pthread_mutex_unlock(&my_context->mutex_trace);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -173,6 +200,7 @@ 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);
|
||||
@@ -182,9 +210,12 @@ x86emu_t* x86emu_fork(x86emu_t* e, int forktype);
|
||||
void PackFlags(x86emu_t* emu);
|
||||
void UnpackFlags(x86emu_t* emu);
|
||||
|
||||
uintptr_t GetGSBaseEmu(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(x86emu_t* emu, void* p);
|
||||
const char* GetNativeName(void* p);
|
||||
|
||||
#ifdef HAVE_TRACE
|
||||
void PrintTrace(x86emu_t* emu, uintptr_t ip, int dynarec);
|
||||
|
||||
+106
-19
@@ -35,22 +35,36 @@
|
||||
#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
|
||||
#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
|
||||
@@ -75,6 +89,7 @@ scwrap_t syscallwrap[] = {
|
||||
{ 7, __NR_waitpid, 3 },
|
||||
#endif
|
||||
{ 10, __NR_unlink, 1 },
|
||||
{ 12, __NR_chdir, 1 },
|
||||
#ifdef __NR_time
|
||||
{ 13, __NR_time, 1 },
|
||||
#endif
|
||||
@@ -93,11 +108,12 @@ scwrap_t syscallwrap[] = {
|
||||
{ 47, __NR_getgid, 0 },
|
||||
{ 49, __NR_geteuid, 0 },
|
||||
{ 50, __NR_getegid, 0 },
|
||||
//{ 54, __NR_ioctl, 5 }, // wrapped to allow SA_RESTART handling by libc
|
||||
{ 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 },
|
||||
@@ -145,6 +161,7 @@ scwrap_t syscallwrap[] = {
|
||||
//{ 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 },
|
||||
@@ -171,6 +188,7 @@ scwrap_t syscallwrap[] = {
|
||||
{ 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 },
|
||||
@@ -182,10 +200,23 @@ scwrap_t syscallwrap[] = {
|
||||
{ 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 {
|
||||
@@ -300,7 +331,7 @@ void EXPORT x86Syscall(x86emu_t *emu)
|
||||
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_DUMP, " => sys_open(\"%s\", %d, %d)", (char*)R_EBX, of_convert(R_ECX), R_EDX);};
|
||||
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;
|
||||
@@ -333,6 +364,11 @@ void EXPORT x86Syscall(x86emu_t *emu)
|
||||
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);
|
||||
@@ -377,9 +413,8 @@ void EXPORT x86Syscall(x86emu_t *emu)
|
||||
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
|
||||
// TODO: Create my_ version of recvmmsg and sendmmsg
|
||||
case SYS_RECVMMSG: R_EAX = recvmmsg(args[0], (void*)args[1], args[2], args[3], (void*)args[4]); break;
|
||||
case SYS_SENDMMSG: R_EAX = sendmmsg(args[0], (void*)args[1], args[2], args[3]); break;
|
||||
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);
|
||||
@@ -462,6 +497,9 @@ void EXPORT x86Syscall(x86emu_t *emu)
|
||||
}
|
||||
}
|
||||
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;
|
||||
@@ -487,6 +525,15 @@ void EXPORT x86Syscall(x86emu_t *emu)
|
||||
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;
|
||||
@@ -503,12 +550,33 @@ void EXPORT x86Syscall(x86emu_t *emu)
|
||||
} 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;
|
||||
case 355: // get_random
|
||||
#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;
|
||||
@@ -553,25 +621,44 @@ uint32_t EXPORT my_syscall(x86emu_t *emu)
|
||||
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));
|
||||
break;
|
||||
case 4: // sys_write
|
||||
return (uint32_t)write(i32(4), p(8), u32(12));
|
||||
break;
|
||||
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));
|
||||
break;
|
||||
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)) {
|
||||
/*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 {
|
||||
}/* 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;
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -58,6 +58,8 @@ int InitX86Trace(box86context_t *context)
|
||||
GO(ZydisFormatterFormatInstruction);
|
||||
#undef GO
|
||||
|
||||
context->dec = InitX86TraceDecoder(context);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@ void reset_fpu(x86emu_t* emu)
|
||||
emu->sw.x16 = 0x0000;
|
||||
emu->top = 0;
|
||||
emu->fpu_stack = 0;
|
||||
for(int i=0; i<9; ++i)
|
||||
emu->p_regs[i].tag = 0b11; // STx is empty
|
||||
}
|
||||
|
||||
void fpu_fbst(x86emu_t* emu, uint8_t* d) {
|
||||
@@ -226,11 +228,10 @@ void fpu_loadenv(x86emu_t* emu, char* p, int b16)
|
||||
emu->top = emu->sw.f.F87_TOP;
|
||||
p+=(b16)?2:4;
|
||||
// tagword: 2bits*8
|
||||
// simplied tags... just reading back the top pointer
|
||||
// tags... (only full = 0b11 / free = 0b00)
|
||||
uint16_t tags = *(uint16_t*)p;
|
||||
for (emu->fpu_stack=0; emu->fpu_stack<8; ++emu->fpu_stack)
|
||||
if(tags & (3<<(emu->fpu_stack*2)))
|
||||
break;
|
||||
for(int i=0; i<8; ++i)
|
||||
emu->p_regs[i].tag = (tags>>(i*2))&0b11;
|
||||
// intruction pointer: 16bits
|
||||
// data (operand) pointer: 16bits
|
||||
// last opcode: 11bits save: 16bits restaured (1st and 2nd opcode only)
|
||||
@@ -246,11 +247,10 @@ void fpu_savenv(x86emu_t* emu, char* p, int b16)
|
||||
p+=2;
|
||||
if(!b16) {*(uint16_t*)p = 0; p+=2;}
|
||||
// tagword: 2bits*8
|
||||
// simplied tags...
|
||||
// tags...
|
||||
uint16_t tags = 0;
|
||||
for (int i=0; i<8; ++i)
|
||||
if(i>=emu->fpu_stack)
|
||||
tags |= (3)<<(i*2);
|
||||
tags |= (emu->p_regs[i].tag)<<(i*2);
|
||||
*(uint16_t*)p = tags;
|
||||
// other stuff are not pushed....
|
||||
}
|
||||
+31
-12
@@ -27,25 +27,41 @@ void RunDF(x86emu_t *emu);
|
||||
|
||||
static inline void fpu_do_push(x86emu_t* emu)
|
||||
{
|
||||
++emu->fpu_stack;
|
||||
if(emu->fpu_stack == 9) {// overflow
|
||||
printf_log(LOG_NONE, "Error: %p: FPU Stack overflow\n", (void*)emu->old_ip); // probably better to raise something
|
||||
emu->quit = 1;
|
||||
int newtop = (emu->top-1)&7;
|
||||
/*if(emu->p_regs[newtop].tag!=0b11) {// not empty, overflow!
|
||||
printf_log(LOG_NONE, "Warning: %p: FPU Stack overflow\n", (void*)emu->old_ip); // probably better to raise something
|
||||
//emu->quit = 1;
|
||||
return;
|
||||
}
|
||||
emu->top = (emu->top-1)&7;
|
||||
}*/
|
||||
if(emu->fpu_stack<8)
|
||||
++emu->fpu_stack;
|
||||
emu->p_regs[newtop].tag = 0; // full
|
||||
emu->top = newtop;
|
||||
}
|
||||
|
||||
static inline void fpu_do_pop(x86emu_t* emu)
|
||||
{
|
||||
emu->top = (emu->top+1)&7;
|
||||
--emu->fpu_stack;
|
||||
if(emu->fpu_stack < 0) {// underflow
|
||||
printf_log(LOG_NONE, "Error: %p: FPU Stack underflow\n", (void*)emu->old_ip); // probably better to raise something
|
||||
emu->quit = 1;
|
||||
int curtop = (emu->top)&7;
|
||||
/*if(emu->p_regs[(emu->top)&7].tag==0b11) {// underflow
|
||||
printf_log(LOG_NONE, "Warning: %p: FPU Stack underflow\n", (void*)emu->old_ip); // probably better to raise something
|
||||
//emu->quit = 1;
|
||||
return;
|
||||
}
|
||||
}*/
|
||||
if(emu->fpu_stack>0)
|
||||
--emu->fpu_stack;
|
||||
|
||||
emu->p_regs[curtop].tag = 0b11; // empty
|
||||
emu->top = (emu->top+1)&7;
|
||||
}
|
||||
|
||||
static inline void fpu_do_free(x86emu_t* emu, int i)
|
||||
{
|
||||
emu->p_regs[(emu->top+i)&7].tag = 0b11; // empty
|
||||
// check if all empty
|
||||
for(int i=0; i<8; ++i)
|
||||
if(emu->p_regs[i].tag != 0b11)
|
||||
return;
|
||||
emu->fpu_stack = 0;
|
||||
}
|
||||
|
||||
void reset_fpu(x86emu_t* emu);
|
||||
@@ -100,6 +116,9 @@ static inline void fpu_fcomi(x86emu_t* emu, double b)
|
||||
#endif
|
||||
{
|
||||
RESET_FLAGS(emu);
|
||||
emu->flags[F_AF] = 0;
|
||||
emu->flags[F_OF] = 0;
|
||||
emu->flags[F_SF] = 0;
|
||||
emu->sw.f.F87_C1 = 0;
|
||||
#ifdef USE_FLOAT
|
||||
if(isnan(ST0.f) || isnan(b)) {
|
||||
|
||||
+2
-11
@@ -19,12 +19,7 @@
|
||||
void Run66D9(x86emu_t *emu)
|
||||
{
|
||||
uint8_t nextop;
|
||||
reg32_t *op1, *op2;
|
||||
reg32_t ea1, ea2;
|
||||
float f;
|
||||
double d;
|
||||
long double ld;
|
||||
int64_t ll;
|
||||
reg32_t *op1;
|
||||
nextop = Fetch8(emu);
|
||||
switch (nextop) {
|
||||
case 0xC0:
|
||||
@@ -94,11 +89,7 @@ void Run66D9(x86emu_t *emu)
|
||||
void Run66DD(x86emu_t *emu)
|
||||
{
|
||||
uint8_t nextop;
|
||||
reg32_t *op1, *op2;
|
||||
reg32_t ea1, ea2;
|
||||
float f;
|
||||
double d;
|
||||
long double ld;
|
||||
reg32_t *op1;
|
||||
nextop = Fetch8(emu);
|
||||
switch(nextop) {
|
||||
|
||||
|
||||
Executable
+13
@@ -0,0 +1,13 @@
|
||||
#ifndef __AUXVAL_H__
|
||||
#define __AUXVAL_H__
|
||||
|
||||
typedef struct x86emu_s x86emu_t;
|
||||
|
||||
#ifndef BUILD_LIB
|
||||
int init_auxval(int argc, const char **argv, const char **env);
|
||||
#endif
|
||||
|
||||
unsigned long real_getauxval(unsigned long type);
|
||||
unsigned long my_getauxval(x86emu_t* emu, unsigned long type);
|
||||
|
||||
#endif //__AUXVAL_H__
|
||||
@@ -5,7 +5,7 @@
|
||||
#include "pathcoll.h"
|
||||
|
||||
typedef struct elfheader_s elfheader_t;
|
||||
|
||||
typedef struct cleanup_s cleanup_t;
|
||||
typedef struct x86emu_s x86emu_t;
|
||||
typedef struct zydis_s zydis_t;
|
||||
typedef struct lib_s lib_t;
|
||||
@@ -15,14 +15,21 @@ typedef struct kh_symbolmap_s kh_symbolmap_t;
|
||||
typedef struct callbacklist_s callbacklist_t;
|
||||
typedef struct library_s library_t;
|
||||
typedef struct kh_fts_s kh_fts_t;
|
||||
typedef struct kh_threadstack_s kh_threadstack_t;
|
||||
typedef struct kh_cancelthread_s kh_cancelthread_t;
|
||||
typedef struct zydis_dec_s zydis_dec_t;
|
||||
typedef struct atfork_fnc_s {
|
||||
uintptr_t prepare;
|
||||
uintptr_t parent;
|
||||
uintptr_t child;
|
||||
void* handle;
|
||||
} atfork_fnc_t;
|
||||
#ifdef DYNAREC
|
||||
typedef struct dynablocklist_s dynablocklist_t;
|
||||
typedef struct mmaplist_s mmaplist_t;
|
||||
typedef struct mmaplist_s mmaplist_t;
|
||||
typedef struct dynmap_s {
|
||||
dynablocklist_t* dynablocks; // the dynabockist of the block
|
||||
} dynmap_t;
|
||||
#endif
|
||||
|
||||
typedef void* (*procaddess_t)(const char* name);
|
||||
@@ -36,6 +43,22 @@ typedef struct tlsdatasize_s {
|
||||
|
||||
void free_tlsdatasize(void* p);
|
||||
|
||||
typedef struct needed_libs_s {
|
||||
int cap;
|
||||
int size;
|
||||
library_t **libs;
|
||||
} needed_libs_t;
|
||||
|
||||
void add_neededlib(needed_libs_t* needed, library_t* lib);
|
||||
void free_neededlib(needed_libs_t* needed);
|
||||
|
||||
typedef struct base_segment_s {
|
||||
uintptr_t base;
|
||||
uint32_t limit;
|
||||
int present;
|
||||
pthread_key_t key;
|
||||
} base_segment_t;
|
||||
|
||||
typedef struct box86context_s {
|
||||
path_collection_t box86_path; // PATH env. variable
|
||||
path_collection_t box86_ld_lib; // LD_LIBRARY_PATH env. variable
|
||||
@@ -67,19 +90,24 @@ typedef struct box86context_s {
|
||||
int elfcap;
|
||||
int elfsize; // number of elf loaded
|
||||
|
||||
needed_libs_t neededlibs; // needed libs for main elf
|
||||
|
||||
uintptr_t ep; // entry point
|
||||
|
||||
x86emu_t *emu; // CPU / FPU / MMX&SSE regs
|
||||
|
||||
lib_t *maplib; // lib and symbols handling
|
||||
lib_t *local_maplib; // libs and symbols openned has local (only collection of libs, no symbols)
|
||||
|
||||
kh_threadstack_t *stacksizes; // stack sizes attributes for thread (temporary)
|
||||
kh_cancelthread_t *cancelthread; // thread cancel mecanism is bit complex, create a map to ease it
|
||||
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)
|
||||
kh_symbolmap_t *glmymap; // link to the mysymbolmap of libGL
|
||||
procaddess_t glxprocaddress;
|
||||
kh_symbolmap_t *alwrappers; // the map of wrapper for alGetProcAddress
|
||||
kh_symbolmap_t *almymap; // link to the mysymbolmap if libOpenAL
|
||||
|
||||
callbacklist_t *callbacks; // all callbacks
|
||||
|
||||
@@ -87,6 +115,7 @@ typedef struct box86context_s {
|
||||
pthread_mutex_t mutex_once2;
|
||||
pthread_mutex_t mutex_trace;
|
||||
pthread_mutex_t mutex_lock;
|
||||
pthread_mutex_t mutex_thread;
|
||||
|
||||
library_t *libclib; // shortcut to libc library (if loaded, so probably yes)
|
||||
library_t *sdl1lib; // shortcut to SDL1 library (if loaded)
|
||||
@@ -102,11 +131,12 @@ typedef struct box86context_s {
|
||||
library_t *sdl2imagelib;
|
||||
library_t *sdl2ttflib;
|
||||
library_t *x11lib;
|
||||
library_t *libxcb;
|
||||
library_t *zlib;
|
||||
library_t *vorbisfile;
|
||||
library_t *vorbis;
|
||||
library_t *asound;
|
||||
library_t *monounity;
|
||||
library_t *pulse;
|
||||
|
||||
int deferedInit;
|
||||
elfheader_t **deferedInitList;
|
||||
@@ -116,17 +146,25 @@ typedef struct box86context_s {
|
||||
pthread_key_t tlskey; // then tls key to have actual tlsdata
|
||||
void* tlsdata; // the initial global tlsdata
|
||||
int32_t tlssize; // wanted size of tlsdata
|
||||
base_segment_t segtls[3]; // only handling 0/1/2 descriptors
|
||||
|
||||
uintptr_t *auxval_start;
|
||||
|
||||
cleanup_t *cleanups; // atexit functions
|
||||
int clean_sz;
|
||||
int clean_cap;
|
||||
#ifdef DYNAREC
|
||||
pthread_mutex_t mutex_blocks;
|
||||
pthread_mutex_t mutex_mmap;
|
||||
dynablocklist_t *dynablocks;
|
||||
mmaplist_t *mmaplist;
|
||||
int mmapsize;
|
||||
dynmap_t* dynmap[65536]; // 4G of memory mapped by 64K block
|
||||
#endif
|
||||
#ifndef NOALIGN
|
||||
kh_fts_t *ftsmap;
|
||||
#endif
|
||||
zydis_dec_t *dec; // trace
|
||||
|
||||
int forked; // how many forks... cleanup only when < 0
|
||||
|
||||
@@ -138,8 +176,13 @@ typedef struct box86context_s {
|
||||
|
||||
uintptr_t signals[MAX_SIGNAL];
|
||||
uintptr_t restorer[MAX_SIGNAL];
|
||||
int is_sigaction[MAX_SIGNAL];
|
||||
x86emu_t *emu_sig; // the emu with stack used for signal handling (must be separated from main ones)
|
||||
int no_sigsegv;
|
||||
|
||||
int no_sigill;
|
||||
#ifdef BUILD_DYNAMIC
|
||||
int count; // number of instances
|
||||
#endif
|
||||
} box86context_t;
|
||||
|
||||
box86context_t *NewBox86Context(int argc);
|
||||
@@ -152,7 +195,20 @@ int AddElfHeader(box86context_t* ctx, elfheader_t* head);
|
||||
int AddTLSPartition(box86context_t* context, int tlssize);
|
||||
|
||||
#ifdef DYNAREC
|
||||
uintptr_t AllocDynarecMap(box86context_t *context, int size);
|
||||
// the nolinker specified if static map or dynamic (can be deleted) has to be used
|
||||
uintptr_t AllocDynarecMap(int size, int nolinker);
|
||||
void FreeDynarecMap(uintptr_t addr, uint32_t size);
|
||||
|
||||
dynablocklist_t* getDBFromAddress(uintptr_t addr);
|
||||
void addDBFromAddressRange(uintptr_t addr, uintptr_t size);
|
||||
void cleanDBFromAddressRange(uintptr_t addr, uintptr_t size, int destroy);
|
||||
|
||||
void protectDB(uintptr_t addr, uintptr_t size);
|
||||
void unprotectDB(uintptr_t addr, uintptr_t size);
|
||||
#endif
|
||||
|
||||
// defined in fact in threads.c
|
||||
void thread_set_emu(x86emu_t* emu);
|
||||
x86emu_t* thread_get_emu();
|
||||
|
||||
#endif //__BOX86CONTEXT_H_
|
||||
@@ -3,11 +3,21 @@
|
||||
|
||||
typedef struct path_collection_s path_collection_t;
|
||||
typedef struct box86context_s box86context_t;
|
||||
typedef struct x86emu_s x86emu_t;
|
||||
|
||||
void LoadLogEnv();
|
||||
void LoadEnvPath(path_collection_t *col, const char* defpath, const char* env);
|
||||
int CountEnv(const char** env);
|
||||
int GatherEnv(char*** dest, const char** env, const char* prog);
|
||||
void LoadEnvVars(box86context_t *context);
|
||||
void setupTraceInit(box86context_t* context);
|
||||
void setupTrace(box86context_t* context);
|
||||
void initAllHelpers(box86context_t* context);
|
||||
void finiAllHelpers();
|
||||
|
||||
#ifdef BUILD_DYNAMIC
|
||||
box86context_t* GetBox86Context();
|
||||
x86emu_t* GetX86Emu();
|
||||
#endif
|
||||
|
||||
#endif //_BOX86LIB_H_
|
||||
@@ -7,7 +7,7 @@ typedef struct box86context_s box86context_t;
|
||||
typedef struct x86emu_s x86emu_t;
|
||||
|
||||
int CalcStackSize(box86context_t *context);
|
||||
void SetupInitialStack(box86context_t *context);
|
||||
void SetupInitialStack(x86emu_t *emu);
|
||||
|
||||
uint16_t Pop16(x86emu_t *emu);
|
||||
void Push16(x86emu_t *emu, uint16_t v);
|
||||
|
||||
+10
-4
@@ -17,14 +17,20 @@ x86emu_t* GetCallback1Arg(x86emu_t* emu, uintptr_t fnc, int nb_args, void* arg1)
|
||||
x86emu_t* FreeCallback(x86emu_t* emu);
|
||||
uint32_t RunCallback(x86emu_t* emu);
|
||||
void SetCallbackArg(x86emu_t* emu, int arg, void* val);
|
||||
void SetCallbackArgs(x86emu_t* emu, int nargs, ...); // set args starting from 0
|
||||
void SetCallbackNArgs(x86emu_t* emu, int N, int nargs, ...); // set args starting from N
|
||||
// set args starting from 0
|
||||
void SetCallbackArgs(x86emu_t* emu, int nargs, ...);
|
||||
// set args starting from N
|
||||
void SetCallbackNArgs(x86emu_t* emu, int N, int nargs, ...);
|
||||
void* GetCallbackArg(x86emu_t* emu, int arg);
|
||||
void SetCallbackNArg(x86emu_t* emu, int narg);
|
||||
void SetCallbackAddress(x86emu_t* emu, uintptr_t address);
|
||||
uintptr_t GetCallbackAddress(x86emu_t* emu);
|
||||
int IsCallback(box86context_t* context, x86emu_t* cb);
|
||||
uint32_t RunFunction(box86context_t *context, uintptr_t fnc, int nargs, ...); // use a local stack from the stack of 128K
|
||||
uint32_t RunFunctionWithEmu(x86emu_t *emu, uintptr_t fnc, int nargs, ...);
|
||||
// use thread local emu to run the function (context is unused now)
|
||||
uint32_t RunFunction(box86context_t *context, uintptr_t fnc, int nargs, ...);
|
||||
// use emu state to run function
|
||||
uint32_t RunFunctionWithEmu(x86emu_t *emu, int QuitOnLongJump, uintptr_t fnc, int nargs, ...);
|
||||
// Find a cb using FNC address and argN as a key
|
||||
x86emu_t* FindCallbackFnc1Arg(x86emu_t* emu, uintptr_t fnc, int argn, void* arg);
|
||||
|
||||
#endif //__CALLBACK_H__
|
||||
+23
-4
@@ -1,18 +1,34 @@
|
||||
#ifndef __DEBUG_H_
|
||||
#define __DEBUG_H_
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct box86context_s box86context_t;
|
||||
extern int box86_log; // log level
|
||||
#ifdef DYNAREC
|
||||
extern int box86_dynarec_log;
|
||||
extern int box86_dynarec;
|
||||
extern int box86_pagesize;
|
||||
#ifdef DYNAREC
|
||||
extern int box86_dynarec_dump;
|
||||
extern int box86_dynarec_linker;
|
||||
extern int box86_dynarec_trace;
|
||||
extern int box86_dynarec_forced;
|
||||
extern int box86_dynarec_largest;
|
||||
#ifdef ARM
|
||||
extern int arm_vfp; // vfp version (3 or 4), with 32 registers is mendatory
|
||||
extern int arm_swap;
|
||||
extern int arm_div;
|
||||
#endif
|
||||
#endif
|
||||
extern int dlsym_error; // log dlsym error
|
||||
extern int trace_xmm; // include XMM reg in trace?
|
||||
extern int trace_emm; // include EMM reg in trace?
|
||||
extern int allow_missing_libs;
|
||||
extern int box86_steam;
|
||||
extern uintptr_t trace_start, trace_end;
|
||||
extern box86context_t *my_context; // global context
|
||||
extern char* trace_func;
|
||||
extern uintptr_t fmod_smc_start, fmod_smc_end; // to handle libfmod (from Unreal) SMC (self modifying code)
|
||||
extern uint16_t default_fs;
|
||||
#define LOG_NONE 0
|
||||
#define LOG_INFO 1
|
||||
#define LOG_DEBUG 2
|
||||
@@ -22,10 +38,13 @@ extern FILE* ftrace;
|
||||
|
||||
#define printf_log(L, ...) do {if(L<=box86_log) {fprintf(ftrace, __VA_ARGS__); fflush(ftrace);}} while(0)
|
||||
|
||||
#ifdef DYNAREC
|
||||
#define dynarec_log(L, ...) do {if(L<=box86_dynarec_log) {fprintf(ftrace, __VA_ARGS__); fflush(ftrace);}} while(0)
|
||||
#endif
|
||||
|
||||
#define EXPORT __attribute__((visibility("default")))
|
||||
#ifdef BUILD_DYNAMIC
|
||||
#define EXPORTDYN __attribute__((visibility("default")))
|
||||
#else
|
||||
#define EXPORTDYN
|
||||
#endif
|
||||
|
||||
#endif //__DEBUG_H_
|
||||
#endif //__DEBUG_H_
|
||||
+26
-2
@@ -7,11 +7,35 @@ typedef struct dynablock_s dynablock_t;
|
||||
|
||||
typedef struct dynablocklist_s dynablocklist_t;
|
||||
|
||||
dynablocklist_t* NewDynablockList(uintptr_t base, uintptr_t text, int textsz);
|
||||
uint32_t X31_hash_code(void* addr, int len);
|
||||
dynablocklist_t* NewDynablockList(uintptr_t base, uintptr_t text, int textsz, int nolinker, int direct);
|
||||
void FreeDynablockList(dynablocklist_t** dynablocks);
|
||||
void FreeDynablock(dynablock_t* db);
|
||||
void MarkDynablock(dynablock_t* db);
|
||||
void MarkDynablockList(dynablocklist_t** dynablocks);
|
||||
void ProtectDynablock(dynablock_t* db);
|
||||
void ProtectkDynablockList(dynablocklist_t** dynablocks);
|
||||
void ProtectDirectDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size);
|
||||
void FreeRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size);
|
||||
void MarkRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size);
|
||||
|
||||
// for debugging purpose
|
||||
dynablock_t* FindDynablockFromNativeAddress(void* addr);
|
||||
|
||||
uintptr_t StartDynablockList(dynablocklist_t* db);
|
||||
uintptr_t EndDynablockList(dynablocklist_t* db);
|
||||
void FreeDirectDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size);
|
||||
void MarkDirectDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size);
|
||||
|
||||
// Handling of Dynarec block (i.e. an exectable chunk of x86 translated code)
|
||||
dynablock_t* DBGetBlock(x86emu_t* emu, uintptr_t addr, int create, dynablock_t* current); // return NULL if block is not found / cannot be created. Don't create if create==0
|
||||
dynablock_t* DBGetBlock(x86emu_t* emu, uintptr_t addr, int create, dynablock_t** current); // return NULL if block is not found / cannot be created. Don't create if create==0
|
||||
|
||||
// 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);
|
||||
// remove a Table mark (and also remove lined info from other dynablock, if any)
|
||||
void RemoveMark(void** table);
|
||||
|
||||
// Create and Add an new dynablock in the list, handling direct/map
|
||||
dynablock_t *AddNewDynablock(dynablocklist_t* dynablocks, uintptr_t addr, int with_marks, int* created);
|
||||
|
||||
#endif //__DYNABLOCK_H_
|
||||
@@ -4,6 +4,6 @@
|
||||
typedef struct dynablock_s dynablock_t;
|
||||
typedef struct x86emu_s x86emu_t;
|
||||
|
||||
void FillBlock(x86emu_t* emu, dynablock_t* block, uintptr_t addr);
|
||||
void* FillBlock(dynablock_t* block);
|
||||
|
||||
#endif //__DYNAREC_ARM_H_
|
||||
@@ -14,6 +14,7 @@ void DumpMainHeader(Elf32_Ehdr *header, elfheader_t *h);
|
||||
void DumpSymTab(elfheader_t *h);
|
||||
void DumpDynamicSections(elfheader_t *h);
|
||||
void DumpDynamicNeeded(elfheader_t *h);
|
||||
void DumpDynamicRPath(elfheader_t *h);
|
||||
void DumpDynSym(elfheader_t *h);
|
||||
void DumpRelTable(elfheader_t *h, int cnt, Elf32_Rel *rel, const char* name);
|
||||
void DumpRelATable(elfheader_t *h, int cnt, Elf32_Rela *rela, const char* name);
|
||||
|
||||
@@ -8,6 +8,7 @@ typedef struct library_s library_t;
|
||||
typedef struct kh_mapsymbols_s kh_mapsymbols_t;
|
||||
typedef struct box86context_s box86context_t;
|
||||
typedef struct x86emu_s x86emu_t;
|
||||
typedef struct needed_libs_s needed_libs_t;
|
||||
#ifdef DYNAREC
|
||||
typedef struct dynablocklist_s dynablocklist_t;
|
||||
#endif
|
||||
@@ -15,6 +16,7 @@ typedef struct dynablocklist_s dynablocklist_t;
|
||||
elfheader_t* LoadAndCheckElfHeader(FILE* f, const char* name, int exec); // exec : 0 = lib, 1 = exec
|
||||
void FreeElfHeader(elfheader_t** head);
|
||||
const char* ElfName(elfheader_t* head);
|
||||
void ElfAttachLib(elfheader_t* head, library_t* lib);
|
||||
|
||||
// return 0 if OK
|
||||
int CalcLoadAddr(elfheader_t* head);
|
||||
@@ -22,33 +24,34 @@ int AllocElfMemory(box86context_t* context, elfheader_t* head, int mainbin);
|
||||
void FreeElfMemory(elfheader_t* head);
|
||||
int LoadElfMemory(FILE* f, box86context_t* context, elfheader_t* head);
|
||||
int ReloadElfMemory(FILE* f, box86context_t* context, elfheader_t* head);
|
||||
int RelocateElf(lib_t *maplib, elfheader_t* head);
|
||||
int RelocateElfPlt(box86context_t* context, lib_t *maplib, elfheader_t* head);
|
||||
int RelocateElf(lib_t *maplib, lib_t* local_maplib, elfheader_t* head);
|
||||
int RelocateElfPlt(lib_t *maplib, lib_t* local_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 AddSymbols(lib_t *maplib, kh_mapsymbols_t* mapsymbols, kh_mapsymbols_t* weaksymbols, kh_mapsymbols_t* localsymbols, elfheader_t* h);
|
||||
int LoadNeededLibs(elfheader_t* h, lib_t *maplib, library_t* parent, box86context_t* box86, x86emu_t* emu);
|
||||
int FinalizeNeededLibs(elfheader_t* h, lib_t *maplib, box86context_t *box86, x86emu_t* emu);
|
||||
int LoadNeededLibs(elfheader_t* h, lib_t *maplib, needed_libs_t* neededlibs, int local, 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);
|
||||
void* GetBaseAddress(elfheader_t* h);
|
||||
void* GetElfDelta(elfheader_t* h);
|
||||
uint32_t GetBaseSize(elfheader_t* h);
|
||||
int IsAddressInElfSpace(elfheader_t* h, uintptr_t addr);
|
||||
elfheader_t* FindElfAddress(box86context_t *context, uintptr_t addr);
|
||||
const char* FindNearestSymbolName(elfheader_t* h, void* p, uintptr_t* start, uint32_t* sz);
|
||||
void* GetGSBase(box86context_t *context);
|
||||
int32_t GetTLSBase(elfheader_t* h);
|
||||
uint32_t GetTLSSize(elfheader_t* h);
|
||||
void* GetTLSPointer(box86context_t* context, elfheader_t* h);
|
||||
void* GetDTatOffset(box86context_t* context, int index, int offset);
|
||||
#ifdef DYNAREC
|
||||
dynablocklist_t* GetDynablocksFromAddress(box86context_t *context, uintptr_t addr);
|
||||
dynablocklist_t* GetDynablocksFromElf(elfheader_t* h);
|
||||
#endif
|
||||
void ResetSpecialCaseMainElf(elfheader_t* h);
|
||||
void CreateMemorymapFile(box86context_t* context, int fd);
|
||||
|
||||
|
||||
#endif //__ELF_LOADER_H_
|
||||
@@ -177,7 +177,7 @@ my_GTypeValueTable_t* findFreeGTypeValueTable(my_GTypeValueTable_t* fcts);
|
||||
my_GTypeInfo_t* findFreeGTypeInfo(my_GTypeInfo_t* fcts, int parent);
|
||||
my_GtkTypeInfo_t* findFreeGtkTypeInfo(my_GtkTypeInfo_t* fcts, int parent);
|
||||
|
||||
void InitGTKClass(box86context_t* context, bridge_t *bridge);
|
||||
void InitGTKClass(bridge_t *bridge);
|
||||
void FiniGTKClass();
|
||||
|
||||
void SetGObjectID(int id);
|
||||
@@ -188,8 +188,11 @@ void SetGTypeName(void* f);
|
||||
|
||||
void* wrapCopyGTKClass(void* class, int type);
|
||||
|
||||
void my_checkGlobalGdkDisplay(box86context_t* context);
|
||||
void my_setGlobalGThreadsInit(box86context_t* context);
|
||||
void my_checkGlobalGdkDisplay();
|
||||
void my_setGlobalGThreadsInit();
|
||||
|
||||
void** my_GetGTKDisplay();
|
||||
void** my_GetGthreadsGotInitialized();
|
||||
|
||||
typedef struct my_signal_s {
|
||||
uint32_t sign; // signature
|
||||
|
||||
@@ -552,6 +552,19 @@ static kh_inline khint_t __ac_Wang_hash(khint_t key)
|
||||
code; \
|
||||
} }
|
||||
|
||||
/*! @function
|
||||
@abstract Iterate over the entries in the hash table
|
||||
@param h Pointer to the hash table [khash_t(name)*]
|
||||
@param kvar Variable to which key will be assigned
|
||||
@param code Block of code to execute
|
||||
*/
|
||||
#define kh_foreach_key(h, kvar, code) { khint_t __i; \
|
||||
for (__i = kh_begin(h); __i != kh_end(h); ++__i) { \
|
||||
if (!kh_exist(h,__i)) continue; \
|
||||
(kvar) = kh_key(h,__i); \
|
||||
code; \
|
||||
} }
|
||||
|
||||
/*! @function
|
||||
@abstract Iterate over the values in the hash table
|
||||
@param h Pointer to the hash table [khash_t(name)*]
|
||||
|
||||
@@ -11,10 +11,11 @@ typedef struct box86context_s box86context_t;
|
||||
typedef struct x86emu_s x86emu_t;
|
||||
typedef struct elfheader_s elfheader_t;
|
||||
typedef struct box86context_s box86context_t;
|
||||
typedef struct needed_libs_s needed_libs_t;
|
||||
typedef struct kh_mapoffsets_s kh_mapoffsets_t;
|
||||
typedef char* cstr_t;
|
||||
|
||||
lib_t *NewLibrarian(box86context_t* context);
|
||||
lib_t *NewLibrarian(box86context_t* context, int ownlibs);
|
||||
void FreeLibrarian(lib_t **maplib);
|
||||
dlprivate_t *NewDLPrivate();
|
||||
void FreeDLPrivate(dlprivate_t **lib);
|
||||
@@ -23,11 +24,12 @@ box86context_t* GetLibrarianContext(lib_t* maplib);
|
||||
kh_mapsymbols_t* GetMapSymbol(lib_t* maplib);
|
||||
kh_mapsymbols_t* GetWeakSymbol(lib_t* maplib);
|
||||
kh_mapsymbols_t* GetLocalSymbol(lib_t* maplib);
|
||||
int AddNeededLib(lib_t* maplib, library_t* parent, const char* path, box86context_t* box86, x86emu_t* emu); // 0=success, 1=error
|
||||
int FinalizeNeededLib(lib_t* maplib, const char* path, box86context_t* box86, x86emu_t* emu);
|
||||
library_t* GetLib(lib_t* maplib, const char* name);
|
||||
int AddNeededLib(lib_t* maplib, needed_libs_t* neededlibs, int local, const char* path, box86context_t* box86, x86emu_t* emu); // 0=success, 1=error
|
||||
library_t* GetLibMapLib(lib_t* maplib, const char* name);
|
||||
library_t* GetLibInternal(const char* name);
|
||||
uintptr_t FindGlobalSymbol(lib_t *maplib, const char* name);
|
||||
int GetNoSelfSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end, elfheader_t* self);
|
||||
int GetSelfSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end, elfheader_t *self);
|
||||
int GetGlobalSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end);
|
||||
int GetGlobalNoWeakSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end);
|
||||
int GetLocalSymbolStartEnd(lib_t *maplib, const char* name, uintptr_t* start, uintptr_t* end, elfheader_t *self);
|
||||
|
||||
+11
-5
@@ -3,13 +3,15 @@
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct library_s library_t;
|
||||
typedef struct lib_s lib_t;
|
||||
typedef struct kh_symbolmap_s kh_symbolmap_t;
|
||||
typedef struct box86context_s box86context_t;
|
||||
typedef struct x86emu_s x86emu_t;
|
||||
typedef struct needed_libs_s needed_libs_t;
|
||||
|
||||
library_t *NewLibrary(const char* path, box86context_t* box86);
|
||||
int AddSymbolsLibrary(library_t* lib, x86emu_t* emu);
|
||||
int FinalizeLibrary(library_t* lib, x86emu_t* emu);
|
||||
int AddSymbolsLibrary(lib_t* maplib, library_t* lib, x86emu_t* emu);
|
||||
int FinalizeLibrary(library_t* lib, lib_t* local_maplib, x86emu_t* emu);
|
||||
int ReloadLibrary(library_t* lib, x86emu_t* emu);
|
||||
void InactiveLibrary(library_t* lib);
|
||||
void Free1Library(library_t **lib);
|
||||
@@ -19,12 +21,16 @@ int IsSameLib(library_t* lib, const char* path); // check if lib is same (pat
|
||||
int GetLibSymbolStartEnd(library_t* lib, const char* name, uintptr_t* start, uintptr_t* end);
|
||||
int GetLibNoWeakSymbolStartEnd(library_t* lib, const char* name, uintptr_t* start, uintptr_t* end);
|
||||
int GetLibLocalSymbolStartEnd(library_t* lib, const char* name, uintptr_t* start, uintptr_t* end);
|
||||
kh_symbolmap_t * fillGLProcWrapper();
|
||||
void freeProcWrapper(kh_symbolmap_t** symbolmap);
|
||||
void LibAddNeededLib(library_t* lib, library_t* needed);
|
||||
void fillGLProcWrapper(box86context_t* context);
|
||||
void freeGLProcWrapper(box86context_t* context);
|
||||
void fillALProcWrapper(box86context_t* context);
|
||||
void freeALProcWrapper(box86context_t* context);
|
||||
needed_libs_t* GetNeededLibs(library_t* lib);
|
||||
int GetNeededLibN(library_t* lib);
|
||||
library_t* GetNeededLib(library_t* lib, int idx);
|
||||
lib_t* GetMaplib(library_t* lib);
|
||||
|
||||
int GetElfIndex(library_t* lib); // -1 if no elf (i.e. native)
|
||||
void* GetHandle(library_t* lib); // NULL if not native
|
||||
|
||||
#endif //__LIBRARY_H_
|
||||
Loaded 100 of 258 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user