mirror of
https://github.com/ptitSeb/box86.git
synced 2026-11-09 04:09:45 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5368285be0 | ||
|
|
096ff18ee8 | ||
|
|
2cde569916 | ||
|
|
f0afcb2e62 | ||
|
|
5b606a785d | ||
|
|
6bfa4a390c | ||
|
|
1b91e9d614 | ||
|
|
bff458d636 | ||
|
|
8814b73eb3 | ||
|
|
d116855eb8 | ||
|
|
5dd4a31f17 | ||
|
|
a32bf25289 | ||
|
|
eac21c4f59 | ||
|
|
f4f5cb2e80 | ||
|
|
f559a75353 | ||
|
|
aff26ce1c0 | ||
|
|
49717bf706 | ||
|
|
283eecadd6 | ||
|
|
9069f56a9d | ||
|
|
422c095ebf | ||
|
|
8373bee595 | ||
|
|
a474c66e26 | ||
|
|
b933efedd1 | ||
|
|
8719e9a857 | ||
|
|
2995c5312e | ||
|
|
0bed0d5b9c | ||
|
|
4e4d4515d0 | ||
|
|
6b46117211 | ||
|
|
679dbafc9e | ||
|
|
f6415a746c | ||
|
|
b5623128b2 | ||
|
|
cdcf85bdfa | ||
|
|
41f301c3c4 | ||
|
|
2641c5b274 | ||
|
|
9f4c37104a | ||
|
|
428d59a1b0 | ||
|
|
f3532ccb99 | ||
|
|
64f7ff5880 | ||
|
|
79fd8562bf | ||
|
|
b2aab80ef0 | ||
|
|
cb9698a5b0 | ||
|
|
3c0ac75fc7 | ||
|
|
00c7e88da0 | ||
|
|
e26d7981b0 | ||
|
|
2d184211bf | ||
|
|
1d7072bf86 | ||
|
|
33401074e7 | ||
|
|
35fcd0b269 | ||
|
|
6ce9ba83df | ||
|
|
0ee881cf0d | ||
|
|
9bf5db778b | ||
|
|
bcdeff5217 | ||
|
|
4a7c16c336 | ||
|
|
fa4b5fe75a | ||
|
|
7cf983f765 | ||
|
|
102e0a8ab3 | ||
|
|
754d7fc8a6 | ||
|
|
79d355668f | ||
|
|
189cd84c41 | ||
|
|
a5b13f592b | ||
|
|
987c87595a | ||
|
|
dc26964fd2 | ||
|
|
5a94979c69 | ||
|
|
028f700093 | ||
|
|
e782ffc98d | ||
|
|
6675da0661 | ||
|
|
ba965fce28 | ||
|
|
aeca17a36f | ||
|
|
0e64848623 | ||
|
|
52bf1907c5 | ||
|
|
40a2e18034 | ||
|
|
535db78525 | ||
|
|
aee4ee9430 | ||
|
|
20fd7e5b23 | ||
|
|
1cf3dd1cb1 | ||
|
|
a9a88c2f6e | ||
|
|
1b8dd6fa19 | ||
|
|
cffafe8b65 | ||
|
|
1d2752a0be | ||
|
|
6151667c84 | ||
|
|
d87c72298f | ||
|
|
2e1b3d23dc | ||
|
|
1955c22501 | ||
|
|
6378359fd8 | ||
|
|
fe83210938 | ||
|
|
aae0a76d2b | ||
|
|
34d7177768 | ||
|
|
28131360b2 | ||
|
|
7e0f3af5a0 | ||
|
|
cb6c9e8ceb | ||
|
|
b30a071783 | ||
|
|
0e8ab73e49 | ||
|
|
7475e7f68d | ||
|
|
25902550fa | ||
|
|
883b7bf054 | ||
|
|
b3077791b2 | ||
|
|
46fbe2a9a8 | ||
|
|
d5fab7c7b1 | ||
|
|
860a404cb1 | ||
|
|
0fa9c01549 | ||
|
|
b34652d862 | ||
|
|
fcd7578b9a | ||
|
|
f5e0c61d12 | ||
|
|
92d2d2c638 | ||
|
|
79a1dc0564 | ||
|
|
a22c0d3343 | ||
|
|
46114235f9 | ||
|
|
2bb62e419d | ||
|
|
ac6f71b188 | ||
|
|
a438985c8c | ||
|
|
9f310e6be2 | ||
|
|
edfb61a452 | ||
|
|
3b30a559b6 | ||
|
|
497d4dc804 | ||
|
|
631856ae54 | ||
|
|
8b887c7714 | ||
|
|
852f6af362 | ||
|
|
cd6cb2352f | ||
|
|
5bc7a1bf4f | ||
|
|
844566a78a | ||
|
|
2320c0de77 | ||
|
|
6afddae6d8 | ||
|
|
5de22d4ce1 | ||
|
|
3162ae83b4 | ||
|
|
e5bcae6e43 | ||
|
|
a110b60a2a | ||
|
|
9190a20ca1 | ||
|
|
7a7f746782 | ||
|
|
6c148b77a1 | ||
|
|
e30eae7652 | ||
|
|
811ffe83f8 | ||
|
|
ae8d61c3a3 | ||
|
|
0e54aaf70f | ||
|
|
4498f216a0 | ||
|
|
3b4a1e6861 | ||
|
|
83a9f96f20 | ||
|
|
dad2601f0d | ||
|
|
fb79a9eb22 | ||
|
|
5fded645fb | ||
|
|
84f16804bb | ||
|
|
e6969267e9 | ||
|
|
1655a98997 | ||
|
|
4444bd2286 | ||
|
|
fe402954f8 | ||
|
|
9ae3543879 | ||
|
|
e88fa9ab45 | ||
|
|
c707150666 | ||
|
|
c2e5f60526 | ||
|
|
395629f678 | ||
|
|
f77b80899d | ||
|
|
5720619bd2 | ||
|
|
e33ac88379 | ||
|
|
96c9bf168e | ||
|
|
3711622f66 | ||
|
|
a3cd9f7de7 | ||
|
|
389927dc1d | ||
|
|
ff63fa7437 | ||
|
|
b480d6856b | ||
|
|
76786e9e43 | ||
|
|
aa9ff80137 | ||
|
|
2e60a6b6e7 | ||
|
|
f24684f478 | ||
|
|
f43a507e91 | ||
|
|
25f7283af9 | ||
|
|
ea29d3f6df | ||
|
|
1592f9246b | ||
|
|
b481c25ee5 | ||
|
|
e6fa77b3c0 | ||
|
|
3da5f56257 | ||
|
|
d97dfa768a | ||
|
|
1d671b104b | ||
|
|
d7cb28a66b | ||
|
|
d153456653 | ||
|
|
ad77202a05 | ||
|
|
20ffd3681e | ||
|
|
d66c1f4510 | ||
|
|
fcdd6f7947 | ||
|
|
1b54190c15 | ||
|
|
7550203dc9 | ||
|
|
380e9fa09e | ||
|
|
c04aeec3e5 | ||
|
|
b758d842c4 | ||
|
|
ff9da0c850 | ||
|
|
87681ffcaa | ||
|
|
47c33cd5a9 | ||
|
|
ea9e9da829 | ||
|
|
0ffcfcb0c0 | ||
|
|
132d2dc3fc | ||
|
|
de61c33093 | ||
|
|
38b12c9773 | ||
|
|
2734536fa7 | ||
|
|
d4e7852598 | ||
|
|
fd3da6af08 | ||
|
|
de3ec8e7af | ||
|
|
2256560985 | ||
|
|
342ee45558 | ||
|
|
c207597409 | ||
|
|
2f5198eb9f | ||
|
|
96fb201246 | ||
|
|
ff36508548 | ||
|
|
02612749c8 | ||
|
|
7648cd9a56 | ||
|
|
95feb02d97 | ||
|
|
36a49e135e | ||
|
|
8fe7b90daa | ||
|
|
238103a5e0 | ||
|
|
72e0d80af9 | ||
|
|
21b61f07da | ||
|
|
1d67fb050c | ||
|
|
40eaacc33b | ||
|
|
4b47e699f5 | ||
|
|
d845f048ea | ||
|
|
e70dc0af56 | ||
|
|
3c3c64f3c7 | ||
|
|
87a9ce334a | ||
|
|
ace58063e4 | ||
|
|
33ef14cd5d | ||
|
|
4f6196b330 | ||
|
|
fbe1ff93e9 | ||
|
|
b2581fccaa | ||
|
|
056e29c9a8 | ||
|
|
0bf409fc10 | ||
|
|
6d2a3883ac | ||
|
|
d7dcb56105 | ||
|
|
a62a9f6c75 | ||
|
|
b4c32dd56b | ||
|
|
3a323abc9a | ||
|
|
1fefd5c82c | ||
|
|
e470a28bda | ||
|
|
435f1c2a16 | ||
|
|
e9f72c1e33 | ||
|
|
f8d8c6c7a4 | ||
|
|
0c7022a756 | ||
|
|
7254e5558b | ||
|
|
17cdb30ab1 | ||
|
|
db743b1226 | ||
|
|
e9cc8d43a9 | ||
|
|
4dd9bf74d9 | ||
|
|
722909a9cf | ||
|
|
13287a114c | ||
|
|
1a6659d577 | ||
|
|
3a7cc57fde | ||
|
|
c093f18d20 | ||
|
|
f2ebd77ace | ||
|
|
ad55a85b89 | ||
|
|
779e0bdc50 | ||
|
|
80c4d80952 | ||
|
|
42e54c0241 | ||
|
|
b393356b4b | ||
|
|
f65555c810 | ||
|
|
174bf29f28 | ||
|
|
1776027e63 | ||
|
|
4018df12cd | ||
|
|
c400cd5f61 | ||
|
|
4710c4777e | ||
|
|
a872136418 | ||
|
|
da15c9619a | ||
|
|
a67b510cae | ||
|
|
c84d1a827e | ||
|
|
0e2cac5505 | ||
|
|
aa4f39a51b | ||
|
|
3c0b7830de | ||
|
|
25f43108fe | ||
|
|
da64e491bb | ||
|
|
23fe11278c | ||
|
|
f27361bf17 | ||
|
|
91e0120780 | ||
|
|
e4f2af21c3 | ||
|
|
2edb0ed1e3 | ||
|
|
e317c61084 | ||
|
|
5506dbbc77 | ||
|
|
2ed175ee3b | ||
|
|
2a2631075e | ||
|
|
406226bd2b | ||
|
|
6f105f0720 | ||
|
|
e30430be48 | ||
|
|
3a52af11bd | ||
|
|
c73b427d42 | ||
|
|
85f5a619ab | ||
|
|
a6d94027db | ||
|
|
45a3044a61 | ||
|
|
d25b3a307e | ||
|
|
d5e3bc9ceb | ||
|
|
cd8f2997ca | ||
|
|
df65e97491 | ||
|
|
abbb60a4fa | ||
|
|
ff05035bc0 | ||
|
|
71d9d78ed5 | ||
|
|
d8b2e96552 | ||
|
|
c974ce057e | ||
|
|
ddbe50c5ef | ||
|
|
2aaf87bbcf | ||
|
|
8c74fde404 | ||
|
|
dbe5afeaba | ||
|
|
9bf035539b | ||
|
|
5cb73d58cd | ||
|
|
1e3eba1b5b | ||
|
|
87af935494 | ||
|
|
86cc204693 | ||
|
|
d1e6d744ae | ||
|
|
cea3dcea67 | ||
|
|
72a896a95a | ||
|
|
9ca0c429bf | ||
|
|
681e06ce73 | ||
|
|
3a3e393d20 | ||
|
|
6b86cb7d1e | ||
|
|
4a772f1bb6 | ||
|
|
d8309595cf | ||
|
|
6000f4f25c | ||
|
|
3cabeb4f27 | ||
|
|
53b525d758 | ||
|
|
06ebc4cb03 | ||
|
|
25245e2a46 | ||
|
|
4d8adae071 | ||
|
|
d65216df76 | ||
|
|
155c4ba1f9 | ||
|
|
f6ff832e51 | ||
|
|
0b4045ffb1 | ||
|
|
677d9feb87 | ||
|
|
043ac1fdab | ||
|
|
dacd75ca7e | ||
|
|
3e5352f79c | ||
|
|
2f56a667f3 | ||
|
|
cefa19ec6a | ||
|
|
ab2ab88581 | ||
|
|
a5c28c6020 | ||
|
|
ac3ddc134e | ||
|
|
86659b40bd | ||
|
|
fd7c7e356c | ||
|
|
10c4e0323a | ||
|
|
53a647af56 | ||
|
|
026185da74 | ||
|
|
951a85d3b7 | ||
|
|
d6db825ec3 | ||
|
|
d9ab158b97 | ||
|
|
f9305d58e8 | ||
|
|
8da827d06f | ||
|
|
4ee29a6d57 | ||
|
|
e060e060af | ||
|
|
81a63edcbc | ||
|
|
8b1ca1330f | ||
|
|
7bc1a6d7c7 | ||
|
|
9e24a71225 | ||
|
|
8d89e7efdb | ||
|
|
4ca4e84878 | ||
|
|
9461f7d24e | ||
|
|
e29ba9e43e | ||
|
|
a875a16c92 | ||
|
|
de92a8a41b | ||
|
|
d719809440 | ||
|
|
656e7552b5 | ||
|
|
9715a2fef6 | ||
|
|
268166b20a | ||
|
|
f03fb651c2 | ||
|
|
6b05e42582 | ||
|
|
0d42b42459 | ||
|
|
2159d407ee | ||
|
|
2b9645e3a6 | ||
|
|
5d0d1e4eb2 | ||
|
|
0d82e52aa6 | ||
|
|
28cfc17bb6 | ||
|
|
5c8d387c27 | ||
|
|
213f51c14b | ||
|
|
d2e5f715a9 | ||
|
|
bedacef673 | ||
|
|
78bafd8b33 | ||
|
|
6ae9b28325 | ||
|
|
68f01f4267 | ||
|
|
d9f953ec82 | ||
|
|
d06795e979 | ||
|
|
979ce28de9 | ||
|
|
4aa2a95b59 | ||
|
|
b588709ad9 | ||
|
|
ca95cdcb91 | ||
|
|
bf046a68c4 | ||
|
|
490a4ab31c | ||
|
|
205133554f | ||
|
|
4df9b9ac6f | ||
|
|
0b5a943799 | ||
|
|
ede0e9d4c3 | ||
|
|
d33d231120 | ||
|
|
0c1ee23f55 | ||
|
|
f5554dec6e | ||
|
|
6239168118 | ||
|
|
fe9fea0807 | ||
|
|
d33917421b | ||
|
|
7c0b11e5e0 | ||
|
|
6a84e2eee9 | ||
|
|
26bad84244 | ||
|
|
eafd7081f3 | ||
|
|
2ad2851b2c | ||
|
|
f4924f6fd3 | ||
|
|
78920a61ad | ||
|
|
160f9f964f | ||
|
|
f81435cc2e | ||
|
|
62df3cbe98 | ||
|
|
b0b000a3f2 | ||
|
|
9e244e068d | ||
|
|
4a8d19da78 | ||
|
|
5a0fbcd7ba | ||
|
|
1ca20269b7 | ||
|
|
5b3eb577fc | ||
|
|
337d08d466 | ||
|
|
e784c34cb4 | ||
|
|
525c54a035 | ||
|
|
65cc054c9c | ||
|
|
64639ae623 | ||
|
|
74fb70a675 | ||
|
|
ca142fbc56 | ||
|
|
af498728b0 | ||
|
|
a68c5dc00e | ||
|
|
7e279e1963 | ||
|
|
01395347ce | ||
|
|
b5493c779f | ||
|
|
919b071990 | ||
|
|
46a9718d29 | ||
|
|
82e3fbfbad | ||
|
|
9004d2b80f | ||
|
|
ddb91106c2 | ||
|
|
9d7505a61c | ||
|
|
e1140c0401 | ||
|
|
76a0d9bfa3 | ||
|
|
a015c7a368 | ||
|
|
329ed0bb5b | ||
|
|
c3bc2808e9 | ||
|
|
584586dea8 | ||
|
|
8f84f73162 | ||
|
|
ce3bf7151a | ||
|
|
5cb5eb296d | ||
|
|
336b0a42e9 | ||
|
|
a32af2cf76 | ||
|
|
307a4f5010 | ||
|
|
5320b4f22f | ||
|
|
70a1d452f3 | ||
|
|
61869a91c7 | ||
|
|
68bc003fd2 | ||
|
|
f29912620d | ||
|
|
4a780af9fe | ||
|
|
6b6e6c874b | ||
|
|
d42d067945 | ||
|
|
17e80a3a09 | ||
|
|
674c5b5819 | ||
|
|
01629e1faf | ||
|
|
38a33ab15b | ||
|
|
2163365115 | ||
|
|
f67902f098 | ||
|
|
bfe47b408d | ||
|
|
aa2bea2d84 | ||
|
|
40c5b1b8d3 | ||
|
|
ee714259df | ||
|
|
aa7b620d8e | ||
|
|
794c16644b | ||
|
|
dda64c5b5e | ||
|
|
6784a79db0 | ||
|
|
564dfea143 | ||
|
|
7e9f514d8b | ||
|
|
68809a753d | ||
|
|
4ba390abd6 | ||
|
|
fe2b4cb8f3 | ||
|
|
dbef73bd75 | ||
|
|
ec19cc1e41 | ||
|
|
63e099a912 | ||
|
|
282309ee9b | ||
|
|
bd48cae19f | ||
|
|
b2d8a5ceb8 | ||
|
|
438677e61a | ||
|
|
44a7535791 | ||
|
|
2117a62dc1 | ||
|
|
99c27bed99 | ||
|
|
161cd9dc3f | ||
|
|
0228fcd7d3 | ||
|
|
3da4e03ddc | ||
|
|
8030af55b8 | ||
|
|
ee757c117c | ||
|
|
a93665abf4 | ||
|
|
e3c39f4f97 | ||
|
|
9bf5c20a9a | ||
|
|
c02a069c5e | ||
|
|
e5bf05c5c2 | ||
|
|
017d82d16e | ||
|
|
5f6d75da12 | ||
|
|
633919dd74 | ||
|
|
e83a119cbb | ||
|
|
00ac8ec1aa | ||
|
|
491f111caf | ||
|
|
8e92453f4c | ||
|
|
bc198c37d7 | ||
|
|
5ab84a6e78 | ||
|
|
334080dfd0 | ||
|
|
46012a6a8c | ||
|
|
3b546a6048 | ||
|
|
522b8d5fc0 | ||
|
|
74d3bb76da | ||
|
|
a28080e065 | ||
|
|
638b341ba5 | ||
|
|
c254dc3121 | ||
|
|
fe0778656b | ||
|
|
e478b99307 | ||
|
|
9d2cd89a7c | ||
|
|
be82ccbfcd | ||
|
|
18dfbb61b4 | ||
|
|
0f8e39d785 | ||
|
|
c4fdf490a2 | ||
|
|
55764011db | ||
|
|
9a483890b6 | ||
|
|
4421377624 | ||
|
|
f817d06e14 | ||
|
|
6b0b389a69 | ||
|
|
496899ffe3 | ||
|
|
7a05331e76 | ||
|
|
e7e725cb5e | ||
|
|
8385f6ad4e | ||
|
|
aeb3f7a438 | ||
|
|
d9fa04d2ed | ||
|
|
d4b5e585d1 | ||
|
|
8579037bb1 | ||
|
|
13cce1a4dd | ||
|
|
5724dfad87 | ||
|
|
f370bf77a8 | ||
|
|
fc3540ac08 | ||
|
|
c16f361c4a | ||
|
|
92a0f507af | ||
|
|
6bb7cdbdd4 | ||
|
|
1809a2bac3 | ||
|
|
430658c1a4 | ||
|
|
746383b72b | ||
|
|
d244151ca2 | ||
|
|
e4c1626638 | ||
|
|
c07cee0d01 | ||
|
|
43132bd9b0 | ||
|
|
ed982e1d2c | ||
|
|
7420ea052d | ||
|
|
044326d337 | ||
|
|
96c126bbcc | ||
|
|
ba0e524805 | ||
|
|
ba19f56338 | ||
|
|
14df602fa4 | ||
|
|
d972e205ac | ||
|
|
114f2b8cd2 | ||
|
|
87f8830d16 | ||
|
|
a0afe05995 | ||
|
|
ddd4d37ad1 | ||
|
|
ede296ef01 | ||
|
|
1307ce364d | ||
|
|
37fa84d762 | ||
|
|
b3e984bd22 | ||
|
|
7da5b9b7eb | ||
|
|
55b979f656 | ||
|
|
815a6c3ade | ||
|
|
33db7a8005 | ||
|
|
963ac3039e | ||
|
|
552db005b1 | ||
|
|
2d1e8cf1f2 | ||
|
|
8e44e8bf13 | ||
|
|
e7cc7b3409 | ||
|
|
4e5473150a | ||
|
|
e8e7597c62 | ||
|
|
f9b03600d1 | ||
|
|
88a8ebb1dc | ||
|
|
4445785ee1 | ||
|
|
3b3460cbba | ||
|
|
7eb6789a25 | ||
|
|
870fed75ad | ||
|
|
833c2809d9 | ||
|
|
24ec881fe5 | ||
|
|
d7d7bc91a2 | ||
|
|
1ea8dc828a | ||
|
|
ade7d82e52 | ||
|
|
fa5c6652b6 | ||
|
|
a5ab6b1520 | ||
|
|
bf74640917 | ||
|
|
420d309db6 | ||
|
|
c4d170ebb8 | ||
|
|
9cc69095d5 | ||
|
|
eb5dd2c005 | ||
|
|
39fbbe61a3 | ||
|
|
ba71080fb2 | ||
|
|
db176ad3e3 | ||
|
|
002638ef96 | ||
|
|
22b74477ac | ||
|
|
9c5a9ebba7 | ||
|
|
fce3f38e3a | ||
|
|
aabb600aed | ||
|
|
a062a8efa6 | ||
|
|
9b690667dc | ||
|
|
de7897c5c2 | ||
|
|
d3d431d5b1 | ||
|
|
6409f5d40a | ||
|
|
aeab3c815e | ||
|
|
4837797fae | ||
|
|
0ffc8682b1 | ||
|
|
cb35a8d85c | ||
|
|
5999255b5d | ||
|
|
a7654c6a80 | ||
|
|
2b3791f701 | ||
|
|
7f52a18fac | ||
|
|
ff8bb3b2e4 | ||
|
|
5b7cc6d4de | ||
|
|
1d9774c913 | ||
|
|
8b13ba26d7 | ||
|
|
8730f4daa6 | ||
|
|
52f4d2a1a6 | ||
|
|
6a498c373c | ||
|
|
007c7a887e | ||
|
|
922a8864e8 | ||
|
|
16383f4577 | ||
|
|
bc66bb5be9 | ||
|
|
84360f24c1 | ||
|
|
cad160205f | ||
|
|
807519e3c4 | ||
|
|
425ffb6e68 | ||
|
|
0ede6b8fa5 | ||
|
|
381d723462 | ||
|
|
cad8de8cd8 | ||
|
|
7d7d275e7e | ||
|
|
80db7d9a21 | ||
|
|
d8943af79a | ||
|
|
bcbf9360af | ||
|
|
6320b0928e | ||
|
|
74afa2551a | ||
|
|
dd733c4128 | ||
|
|
0eaa1b6c5e | ||
|
|
f595859cf0 | ||
|
|
85e0d01451 | ||
|
|
ec57e035d6 | ||
|
|
0d0b4d7364 | ||
|
|
aeb91fce74 | ||
|
|
e163bd842e | ||
|
|
2ff7bd1bc7 | ||
|
|
533c703b0d | ||
|
|
1d1a82f529 | ||
|
|
911b95a505 | ||
|
|
8209cf8398 | ||
|
|
02423d4a2d | ||
|
|
ba5c13fb6c | ||
|
|
ddd13bcab0 | ||
|
|
3b6800e38e | ||
|
|
6c2ebf91c0 | ||
|
|
a64d1de7cd | ||
|
|
d6ce7f5c16 | ||
|
|
1fe29c512f | ||
|
|
e76176b663 | ||
|
|
acbe0527d7 | ||
|
|
81d8f2f5c3 | ||
|
|
8976e77109 | ||
|
|
31bd7ebfbc | ||
|
|
487b979842 | ||
|
|
efd1408809 | ||
|
|
867e8aaa00 | ||
|
|
e3e5fd7568 | ||
|
|
7e6b012a08 | ||
|
|
546fe18836 | ||
|
|
1cb7683636 | ||
|
|
f89c7faf3c | ||
|
|
cf36c668b3 | ||
|
|
dd41352392 | ||
|
|
ec42322f23 | ||
|
|
3b8a9b5cc5 | ||
|
|
6d3b2fe902 | ||
|
|
819ec41320 | ||
|
|
40fd950b40 | ||
|
|
4f64c106a7 | ||
|
|
b2d5587ea1 | ||
|
|
4b020ab4f5 | ||
|
|
088a85c125 | ||
|
|
2bf60dc00d | ||
|
|
b5ffa0e92a | ||
|
|
258f7f9b50 | ||
|
|
07c403243d | ||
|
|
709de6a858 | ||
|
|
dfed557f61 | ||
|
|
f143771be8 | ||
|
|
fc20c410c0 | ||
|
|
677205a288 | ||
|
|
abb9acfd42 | ||
|
|
75dca68db0 | ||
|
|
5c1a8ad128 | ||
|
|
e4cf8f8c94 | ||
|
|
30968917a4 | ||
|
|
84ea9e3301 | ||
|
|
1f9c046919 | ||
|
|
cefe210184 | ||
|
|
02aa791fd9 | ||
|
|
d8c1341068 | ||
|
|
ca648ea128 | ||
|
|
daf5a9d91d | ||
|
|
16b95f2088 | ||
|
|
41dfcb559a | ||
|
|
37c871ec2e | ||
|
|
34bd1ff42f | ||
|
|
e0f1d4fecf | ||
|
|
c94d992ef6 | ||
|
|
bfe83d827d | ||
|
|
1c45795828 | ||
|
|
8dc5c164d8 | ||
|
|
326032aa23 | ||
|
|
b79e234da2 | ||
|
|
5bc6962a9d | ||
|
|
168717a90a | ||
|
|
dd6b0f6c9a | ||
|
|
0a3c678877 | ||
|
|
e2df6f6ce0 | ||
|
|
e58ebdac18 | ||
|
|
537312a91f | ||
|
|
11c08acd6c | ||
|
|
cf9a38fb02 | ||
|
|
83dff2bf25 | ||
|
|
49694f300a | ||
|
|
daddc8246e | ||
|
|
9f92377edc | ||
|
|
1ce392d968 | ||
|
|
bf730b43e2 | ||
|
|
a4adb47caf | ||
|
|
9317572874 | ||
|
|
eca39e6a8f | ||
|
|
4639dc8ffd | ||
|
|
5a9b34f54b | ||
|
|
dc07d477de | ||
|
|
db5efa8908 | ||
|
|
7d462dd837 | ||
|
|
76010f63c0 | ||
|
|
be7f72808b | ||
|
|
25f1e8e6fa | ||
|
|
047df311f0 | ||
|
|
bcdd99328c | ||
|
|
5cc76a0071 | ||
|
|
dee55a9ac2 | ||
|
|
9ff20da9bb | ||
|
|
0520f5abcd | ||
|
|
e1201ff0de | ||
|
|
bc2d7e7396 | ||
|
|
9a058a2416 | ||
|
|
49fea86b28 | ||
|
|
1617439d37 | ||
|
|
540459cb78 | ||
|
|
54b8522df6 | ||
|
|
bf65e606d3 | ||
|
|
5335a641df | ||
|
|
323ece7417 | ||
|
|
ca1fc0ffad | ||
|
|
c0706e227e | ||
|
|
995e4a9b68 | ||
|
|
7f53379552 | ||
|
|
3e17299a34 | ||
|
|
c63cdc9506 | ||
|
|
7965186817 | ||
|
|
f107612753 | ||
|
|
2295f7bb8b | ||
|
|
cc0845a9d3 | ||
|
|
e9019461b7 | ||
|
|
a19e3ed3dd | ||
|
|
10ec424e96 | ||
|
|
b838c8a7d0 | ||
|
|
0331af0643 | ||
|
|
24561fc37c | ||
|
|
d4ad5334b8 | ||
|
|
7fe3299282 | ||
|
|
23fef75ed5 | ||
|
|
62722b0618 | ||
|
|
e810dba2c9 | ||
|
|
7dfe545161 | ||
|
|
a5f3966b44 | ||
|
|
886573ed8b | ||
|
|
2758c1c955 | ||
|
|
591bafe8c3 | ||
|
|
211a8f42db | ||
|
|
fbc9029a8e | ||
|
|
ceb4b8b06d | ||
|
|
b88dda442f | ||
|
|
6e8163bded | ||
|
|
9b253abb53 | ||
|
|
e5e51e3ea3 | ||
|
|
6a2d9d7663 | ||
|
|
0546b1e212 | ||
|
|
320e6dae72 | ||
|
|
96f944c804 | ||
|
|
fd0e2195f7 | ||
|
|
d2f130a834 | ||
|
|
a3459712ce | ||
|
|
8bf2e49164 | ||
|
|
0f5cd39a64 | ||
|
|
e0ed0076f2 | ||
|
|
bfd4ad39af | ||
|
|
a8ff7d8769 | ||
|
|
39c77beb1c | ||
|
|
d576f7af39 | ||
|
|
74c3f43f75 | ||
|
|
ecacace01d | ||
|
|
a3b0149a84 | ||
|
|
63111577ec | ||
|
|
eb68520709 | ||
|
|
a7bf2c6cc3 | ||
|
|
190788efd9 | ||
|
|
2592a6a342 | ||
|
|
16ee4c348d | ||
|
|
8389097cd3 | ||
|
|
79a885c15e | ||
|
|
eb7c683a6d | ||
|
|
95b2b314f6 | ||
|
|
07eb0aa5cd | ||
|
|
fdce28590a | ||
|
|
572613e377 | ||
|
|
29e597b4ed | ||
|
|
981c464c36 | ||
|
|
d406c5717c | ||
|
|
92208efd24 | ||
|
|
3c98cbccbe | ||
|
|
3a5c6751e2 | ||
|
|
002d3d7b9b | ||
|
|
e57a66da04 | ||
|
|
b1ecad2d49 | ||
|
|
658a107f60 | ||
|
|
7b419ce5f1 | ||
|
|
367df08989 | ||
|
|
2004006a9d | ||
|
|
bed0f24f2b | ||
|
|
7995dfc70a | ||
|
|
b29d569f6b | ||
|
|
3c166c438a | ||
|
|
03dac0ef6a | ||
|
|
27cb5219ae | ||
|
|
97a7459f5d | ||
|
|
1eac337e59 | ||
|
|
1613358927 | ||
|
|
2f0da26f14 | ||
|
|
45fa32cb9d | ||
|
|
9e9f2a37be | ||
|
|
7b37bb6825 | ||
|
|
081378a178 | ||
|
|
ff72343429 | ||
|
|
b0b8a2ca1c | ||
|
|
55be6835b8 | ||
|
|
c465e1de21 | ||
|
|
0f255de201 | ||
|
|
deb04610b5 | ||
|
|
a9887fe471 | ||
|
|
4b3c5a7f6f | ||
|
|
0058d3563d | ||
|
|
52a4808f2c | ||
|
|
7a0874165f | ||
|
|
7c7acd134b | ||
|
|
ddd4874baa | ||
|
|
23f91b1a0d | ||
|
|
b8c32d580b | ||
|
|
c0e67004d5 | ||
|
|
38a557b7e9 | ||
|
|
7d6d5d673d | ||
|
|
2cf067f004 | ||
|
|
92d9bc525f | ||
|
|
dca91b1efc | ||
|
|
6bf1ea7539 | ||
|
|
670b13595b | ||
|
|
dcbb8b29de | ||
|
|
7284c817b2 | ||
|
|
b16912132f | ||
|
|
9805ad7f3a | ||
|
|
4e7e0f6aab | ||
|
|
c905ebfdd2 | ||
|
|
b5c787938c | ||
|
|
69ca5351b4 | ||
|
|
3f42372603 | ||
|
|
595028e9ec | ||
|
|
7358a049ef | ||
|
|
792aeda72e | ||
|
|
53bf2d277b | ||
|
|
0cbc55ba24 | ||
|
|
7b0d228972 | ||
|
|
8ac0b66836 | ||
|
|
2756b1b9dd | ||
|
|
e3f44bae26 | ||
|
|
1963589186 | ||
|
|
a5c9675b84 | ||
|
|
76747d5c38 | ||
|
|
59bfeb9fb2 | ||
|
|
c40669b429 | ||
|
|
d83cdbfeeb | ||
|
|
d8773e96d6 | ||
|
|
78571698c2 | ||
|
|
77282f1ff1 | ||
|
|
953fcb7f1b | ||
|
|
edef6d7f99 | ||
|
|
1905e4a7f6 | ||
|
|
31e6ae0705 | ||
|
|
31a108b685 | ||
|
|
b122c68b16 | ||
|
|
0efae1fdf5 | ||
|
|
0850180861 | ||
|
|
528478b379 | ||
|
|
65302010db | ||
|
|
6b32440347 | ||
|
|
5a0b6c419e | ||
|
|
94c5d0205b | ||
|
|
0f2998a672 | ||
|
|
1ba7936ef7 | ||
|
|
5192aacb22 | ||
|
|
ac2adcaf52 | ||
|
|
1b3e707f62 | ||
|
|
925fc67c66 | ||
|
|
54ce6deb1c | ||
|
|
754859d28a | ||
|
|
269bc9e289 | ||
|
|
35c768c040 | ||
|
|
ff45cfed83 | ||
|
|
38c5c1c17a | ||
|
|
423b301596 | ||
|
|
000c11f9ea | ||
|
|
cea4a02ad9 | ||
|
|
4e9bc39381 | ||
|
|
ad084da13d | ||
|
|
27e5262f1d | ||
|
|
363464092e | ||
|
|
b2cab70427 | ||
|
|
44d5301244 | ||
|
|
8e4f4feb3c | ||
|
|
e9f6f8824c | ||
|
|
be6f9870d0 | ||
|
|
bb086223c7 | ||
|
|
be6a3bff3f | ||
|
|
adfc5fda2e | ||
|
|
d833f136a0 | ||
|
|
1703e9d1b7 | ||
|
|
011b9f93e4 | ||
|
|
e449a4e247 | ||
|
|
fe7f0ff842 | ||
|
|
2033e5764d | ||
|
|
55175263ac | ||
|
|
c484221cd6 | ||
|
|
e9862cb30d | ||
|
|
0c7b99cbc6 | ||
|
|
824f39e4db | ||
|
|
66a5ce1e52 | ||
|
|
f39637a652 | ||
|
|
eaf7d0a277 | ||
|
|
b61bb908a2 | ||
|
|
2e891b807c | ||
|
|
f0b236df88 | ||
|
|
08904dbe0d | ||
|
|
c9c4e226af | ||
|
|
ab3dc70145 | ||
|
|
4d8c841f3f | ||
|
|
a8b247cde9 | ||
|
|
416e161285 | ||
|
|
cc8d1f9bf2 | ||
|
|
ae95f1b0e5 | ||
|
|
c10441bec4 | ||
|
|
6ab334fc34 | ||
|
|
10e849ce60 | ||
|
|
c2206f5452 | ||
|
|
3b66cd3cee | ||
|
|
731a083bb7 | ||
|
|
d35c6ab864 | ||
|
|
e9cade872c | ||
|
|
b2a8146851 | ||
|
|
6fd3d6c452 | ||
|
|
bc3e72a87d | ||
|
|
e50e050aa9 | ||
|
|
c1a75607fa | ||
|
|
b203cd2af3 | ||
|
|
84063f026f | ||
|
|
3ec1ce25d7 | ||
|
|
0e70c543ee | ||
|
|
e4d522a8d2 | ||
|
|
272ecbd8ff | ||
|
|
369fa03f9b | ||
|
|
1675ea3ba2 | ||
|
|
5b7a1bb9e6 | ||
|
|
ace3effa2d | ||
|
|
bd0a14b3ce | ||
|
|
29a82f83c5 | ||
|
|
f7232f09de | ||
|
|
f3eeae9edd | ||
|
|
874468ca07 | ||
|
|
7a972af610 | ||
|
|
4ed42c38c9 | ||
|
|
6a73719a6b | ||
|
|
6efcfc6b93 | ||
|
|
25f30c220e | ||
|
|
2e9665f10e | ||
|
|
197881b430 | ||
|
|
96fe98d71f | ||
|
|
d1ecd4c933 | ||
|
|
fad25caa08 | ||
|
|
98c481e045 | ||
|
|
6082e655e6 | ||
|
|
6a97367242 | ||
|
|
bbcfffdab9 | ||
|
|
2dfb6c1012 | ||
|
|
82317343aa | ||
|
|
0ea0d0ec98 | ||
|
|
33aa27c590 | ||
|
|
c31f990183 | ||
|
|
791956bee0 | ||
|
|
6cebf4f6fd | ||
|
|
1782136e02 | ||
|
|
2f381192dd | ||
|
|
dac2009cab | ||
|
|
d592af694f | ||
|
|
e5ea3f9e49 | ||
|
|
f0af865401 | ||
|
|
1e20a9effe | ||
|
|
ce968f7756 | ||
|
|
00aaf316ef | ||
|
|
3ad9a0ca73 | ||
|
|
14a2d24fba | ||
|
|
e374886fcf | ||
|
|
e25b373f00 | ||
|
|
6fbd270d24 | ||
|
|
6adb55a9c4 | ||
|
|
16aa5cac04 | ||
|
|
dca0009df5 | ||
|
|
1cae441cbc | ||
|
|
8b21d8f74a | ||
|
|
ff141e30ee | ||
|
|
2c970a1b8d | ||
|
|
b433f8194e | ||
|
|
7b2f5e5de0 | ||
|
|
3d1400e347 | ||
|
|
8b5d68f79b | ||
|
|
ded4b461b4 | ||
|
|
13a7be57f2 | ||
|
|
e8fdcd5c06 | ||
|
|
b8e263d7e6 | ||
|
|
b76d17e7b9 | ||
|
|
ce3151b256 | ||
|
|
dd0c3ac51e | ||
|
|
f06c5897db | ||
|
|
7dac72f796 | ||
|
|
e5a55114b7 | ||
|
|
a66d0b3d39 | ||
|
|
b01ad69ba1 | ||
|
|
bbe183e8d4 | ||
|
|
f6c9e5079a | ||
|
|
0b8408d50a | ||
|
|
51682eac11 | ||
|
|
aea38c682c | ||
|
|
6edbe97290 | ||
|
|
304eaab4d2 | ||
|
|
f4e5839931 | ||
|
|
4bac9ea9d5 | ||
|
|
64c9b21849 | ||
|
|
34828b66a2 | ||
|
|
957ba00723 | ||
|
|
d548ee48c1 | ||
|
|
d0e93a22a2 | ||
|
|
fe6c1e260b | ||
|
|
1e5add91d3 | ||
|
|
f4c7329c30 | ||
|
|
b1742ccb8e | ||
|
|
870a0d8361 | ||
|
|
1f0adf92d4 | ||
|
|
18ce562698 | ||
|
|
77af926336 | ||
|
|
33f2269896 | ||
|
|
c477e14a04 | ||
|
|
373494094a | ||
|
|
72ca666007 | ||
|
|
5be299b897 | ||
|
|
49afd5077b | ||
|
|
e7336de8a7 | ||
|
|
5b0f4f5b94 | ||
|
|
0edc037441 | ||
|
|
d4a7f7e658 | ||
|
|
fcf9668e8b | ||
|
|
76e53e0869 | ||
|
|
74764253b4 | ||
|
|
c029c6c152 | ||
|
|
bb4b0d5f92 | ||
|
|
a355cf941b | ||
|
|
e7c5ef1cca | ||
|
|
09d0f7a3cb | ||
|
|
3e7dd07b4c | ||
|
|
c536eed349 | ||
|
|
93948021e6 | ||
|
|
77317f87c0 | ||
|
|
b091ea9c6d | ||
|
|
208493da88 | ||
|
|
7015745c4f | ||
|
|
41a5c72d46 | ||
|
|
2b428641fb | ||
|
|
4ebb1e60db | ||
|
|
5e4c1feed1 | ||
|
|
d13e1da1a7 | ||
|
|
9f57cff43b | ||
|
|
b9d9776d5c | ||
|
|
b57ab8470d | ||
|
|
fe402d2faa | ||
|
|
3d38210752 | ||
|
|
6c4b047b58 | ||
|
|
e861d3415a | ||
|
|
cb251fe88b | ||
|
|
b1e594f4d7 | ||
|
|
f9505f3c9f | ||
|
|
52ee2bb769 | ||
|
|
f0471fac14 | ||
|
|
7baac98959 | ||
|
|
9119443c2a | ||
|
|
c9c33929f0 | ||
|
|
60717d38d4 | ||
|
|
858757f8d1 | ||
|
|
f15a22a3cb | ||
|
|
f6022de7d3 | ||
|
|
8214301231 | ||
|
|
a4745098c5 | ||
|
|
647b06a615 | ||
|
|
a7cbafee07 | ||
|
|
ee0eb2345c | ||
|
|
d37c42761d | ||
|
|
d4984fd0ee | ||
|
|
c770ea1859 | ||
|
|
4d1307e223 | ||
|
|
e9308c11ba | ||
|
|
5206ec0fcb | ||
|
|
c65671a6f9 | ||
|
|
ec99203dc6 | ||
|
|
1cdde047ff | ||
|
|
2375d70782 | ||
|
|
5b0c395293 | ||
|
|
ea0c1abb0b | ||
|
|
cc841812ce | ||
|
|
5104bce7bb | ||
|
|
357ce483a8 | ||
|
|
1a40b4b984 | ||
|
|
cdd0e542f1 | ||
|
|
a9d87a938d | ||
|
|
549ff980a3 | ||
|
|
545af93972 | ||
|
|
72b9ed9f54 | ||
|
|
536c7dd04b | ||
|
|
274d5d1e75 | ||
|
|
7b478e42c0 | ||
|
|
d0ac1e61d4 | ||
|
|
31d73927a3 | ||
|
|
7713bd042a | ||
|
|
664dab76e3 | ||
|
|
6e2c33866d | ||
|
|
7b6dd6765e | ||
|
|
d55d2d0303 | ||
|
|
4df7bec913 | ||
|
|
4ddab1b691 | ||
|
|
b0c0e96fca | ||
|
|
aeee2fc391 | ||
|
|
4f28cb5617 | ||
|
|
a442a841f2 | ||
|
|
9201170ab8 | ||
|
|
4f06cfa0da | ||
|
|
fe03daa01f | ||
|
|
b64c4f6043 | ||
|
|
5884c78b56 | ||
|
|
b01b7373ac | ||
|
|
3cc9482a08 | ||
|
|
83c6b01fae | ||
|
|
1f169bc67e | ||
|
|
ea25675264 | ||
|
|
c302cd680c | ||
|
|
ebf46d0cfd | ||
|
|
2c9b504688 | ||
|
|
41d3de565c | ||
|
|
88430d845d | ||
|
|
c6e5e5d27e | ||
|
|
cd673028b7 | ||
|
|
2cafe12e4f | ||
|
|
febbaca66b | ||
|
|
e410ca748a | ||
|
|
524c04296e | ||
|
|
ef360bf93e | ||
|
|
bd4f7a4783 | ||
|
|
3c2c242225 | ||
|
|
a8e657c86e | ||
|
|
70e103af49 | ||
|
|
006f7a79b4 | ||
|
|
c7a4dbe84b | ||
|
|
31c0c52d7f | ||
|
|
a4590d3771 | ||
|
|
02b5e39c39 | ||
|
|
85dd704f86 | ||
|
|
b4d4efd40c | ||
|
|
8745b0f31a | ||
|
|
3787b3bbfc | ||
|
|
765e1b1231 | ||
|
|
2a2e2bf957 | ||
|
|
c93913732b | ||
|
|
f5bbc99d7d | ||
|
|
27ce42b9b0 | ||
|
|
008d51aeec | ||
|
|
8d0d264c0f | ||
|
|
28717352b4 | ||
|
|
f9e492dfdc | ||
|
|
a8e029f0e0 | ||
|
|
f5be4503c5 | ||
|
|
cd1d3f5026 | ||
|
|
4f55733bdd | ||
|
|
81819d04e8 | ||
|
|
4d4adea6eb | ||
|
|
ca981fbc8e | ||
|
|
b4c64abd1e | ||
|
|
a8787330d8 | ||
|
|
7725234b69 | ||
|
|
062d897fb1 | ||
|
|
e1ed95a638 | ||
|
|
7ffa5d076c | ||
|
|
1ae0ae630a | ||
|
|
d3e8daa9b5 | ||
|
|
5f8be26b73 | ||
|
|
0eb575b472 | ||
|
|
1888d905a4 | ||
|
|
3bc4dc8450 | ||
|
|
78719df8d4 | ||
|
|
d3616b335f | ||
|
|
e72cd086b4 | ||
|
|
c82e67c39a | ||
|
|
9885cf6f10 | ||
|
|
d923b5bc0f | ||
|
|
611d2fcaff | ||
|
|
9b2b312719 | ||
|
|
f84161dafc | ||
|
|
8546a0d0bd | ||
|
|
09f5873806 | ||
|
|
18dc905a8c | ||
|
|
30d64a0aa5 | ||
|
|
8359c9e19f | ||
|
|
571f0c0564 | ||
|
|
736a9ef442 | ||
|
|
aee94b0e14 | ||
|
|
4cfed0d394 | ||
|
|
c714d5d881 | ||
|
|
1c2d07ee56 | ||
|
|
96f7f3d88f | ||
|
|
c743577369 | ||
|
|
e5ea60fe88 | ||
|
|
330d93f335 | ||
|
|
f4936144d0 | ||
|
|
bbaa5dde92 | ||
|
|
e6b46151ec | ||
|
|
655a8de652 | ||
|
|
771d69f38b | ||
|
|
2a46dbf149 | ||
|
|
95a0535462 | ||
|
|
041758fead | ||
|
|
d6bb723c6a | ||
|
|
95f97e1c9f | ||
|
|
b029292dd2 | ||
|
|
82ba663c24 | ||
|
|
fabd5b9d32 | ||
|
|
58736b707d | ||
|
|
9219384650 | ||
|
|
14a904cfa9 | ||
|
|
e73f7a9c10 | ||
|
|
09acd36c08 | ||
|
|
69a6f44b8b | ||
|
|
3ee8fd4ec6 | ||
|
|
4f6c0b45f8 | ||
|
|
06a756a5eb | ||
|
|
b312df3b53 | ||
|
|
8e4b2a90a4 | ||
|
|
85b3091b8a | ||
|
|
3838fc3d22 | ||
|
|
0f4722d580 | ||
|
|
4241258158 | ||
|
|
13c446c918 | ||
|
|
9255026b84 | ||
|
|
119eb57a38 | ||
|
|
731f379bed | ||
|
|
bedcf304e1 | ||
|
|
a4655484cb | ||
|
|
babc5aba4f | ||
|
|
763a6f8b02 | ||
|
|
b08960d4b9 | ||
|
|
2c6e91622f | ||
|
|
4679977612 | ||
|
|
0e387904b0 | ||
|
|
f4238621a6 | ||
|
|
2fa19e8cae | ||
|
|
ab644d0638 | ||
|
|
8d1db88e1a | ||
|
|
12215ac5dd | ||
|
|
97d0b386ba | ||
|
|
f8526be667 | ||
|
|
22624f6a29 | ||
|
|
e70584e7fc | ||
|
|
ebd2346f3e | ||
|
|
03ce553620 | ||
|
|
9418a37846 | ||
|
|
4f186dec68 | ||
|
|
5867fd9912 | ||
|
|
cd327cfc5a | ||
|
|
a3f95871b2 | ||
|
|
53021b770b | ||
|
|
7f93731d0c | ||
|
|
570f82d7f8 | ||
|
|
2c8a069f47 | ||
|
|
bbf23be1f3 | ||
|
|
accca4e700 | ||
|
|
ecc8ebef6a | ||
|
|
6c8a807c8c | ||
|
|
dfb2d5eaaa | ||
|
|
71c7ec6fed | ||
|
|
55d216f024 | ||
|
|
5e22febd54 | ||
|
|
436d871ea9 | ||
|
|
02099912c5 | ||
|
|
601aedb25a | ||
|
|
c65aa3d507 | ||
|
|
9b02837d5a | ||
|
|
dbbff7b833 | ||
|
|
e306db4d0c | ||
|
|
985266fc77 | ||
|
|
a3f771cc7c | ||
|
|
71a1bea9c7 | ||
|
|
565543fbba | ||
|
|
9193194596 | ||
|
|
83ea28ded7 | ||
|
|
1a69782f51 | ||
|
|
394ea0f3d3 | ||
|
|
0241bbdbc0 | ||
|
|
5e00739776 | ||
|
|
5d214ac965 | ||
|
|
d35ae51fbb | ||
|
|
717f319dc7 | ||
|
|
fbd2f52da2 | ||
|
|
853d89ca9c | ||
|
|
9c9e3cef29 | ||
|
|
2237afceff | ||
|
|
180d036fd4 | ||
|
|
7248ee7ed2 | ||
|
|
d1e7944ad2 | ||
|
|
2f53752e05 | ||
|
|
3c0de68a00 | ||
|
|
ef22236f35 | ||
|
|
563fc27eae | ||
|
|
d453e120c8 | ||
|
|
57bd72f147 | ||
|
|
298c62e00b | ||
|
|
3d4abfeba2 | ||
|
|
b412118a79 | ||
|
|
c2b5c32a14 | ||
|
|
06cd0a518f | ||
|
|
947dcc3f3d | ||
|
|
fa5eb23cae | ||
|
|
c43895b602 | ||
|
|
18cb2a2047 | ||
|
|
91637c7b11 | ||
|
|
7b70e987ba | ||
|
|
74dfef3424 | ||
|
|
65255edec5 | ||
|
|
5b00412ba0 | ||
|
|
ef43e3f8a0 | ||
|
|
3fa06d865a | ||
|
|
96f2f12dec | ||
|
|
972079532c | ||
|
|
996d4efa32 | ||
|
|
4704bfb7e6 | ||
|
|
5d3b237854 | ||
|
|
dca290b3f0 | ||
|
|
a84473036d | ||
|
|
1b3cb7abb5 | ||
|
|
7dd99ae13e | ||
|
|
7af511b01a | ||
|
|
bb3dc2d889 | ||
|
|
76268c41bc | ||
|
|
b6963ba7c6 | ||
|
|
bd3ff8f828 | ||
|
|
385326f3a8 | ||
|
|
d896fd9106 | ||
|
|
9c18afee35 | ||
|
|
f0b87c8312 | ||
|
|
297b7d548a | ||
|
|
7c406e8f8a | ||
|
|
f458d8dc39 | ||
|
|
66ed78cf4d | ||
|
|
f6205182b9 | ||
|
|
a661016824 | ||
|
|
448afcea7a | ||
|
|
23881ad861 | ||
|
|
9d41f49741 | ||
|
|
b302ebfbb5 | ||
|
|
88d428f03c | ||
|
|
7396b30615 | ||
|
|
6fe1cc9ed7 | ||
|
|
7622959657 | ||
|
|
6f94fdf133 | ||
|
|
b348ce3660 | ||
|
|
f8638fef92 | ||
|
|
9e895da7ed | ||
|
|
cb659fef0d | ||
|
|
1a9042c8d1 | ||
|
|
aac8cb9775 | ||
|
|
99962a68b6 | ||
|
|
8ce6d7f369 | ||
|
|
3bc5a586fa | ||
|
|
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: ptitSeb
|
||||
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
|
||||
@@ -0,0 +1,88 @@
|
||||
### Auto build Box86 and release its binary with Github Action
|
||||
name: Build and Release Box86
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
release:
|
||||
push:
|
||||
paths:
|
||||
- "**/*.c"
|
||||
- "**/*.h"
|
||||
- "**/*.S"
|
||||
- "**/*.py"
|
||||
- "CMakeList.txt"
|
||||
- "**/*.yml"
|
||||
pull_request:
|
||||
types: [assigned, opened, synchronize, reopened]
|
||||
paths:
|
||||
- "**/*.c"
|
||||
- "**/*.h"
|
||||
- "**/*.S"
|
||||
- "**/*.py"
|
||||
- "CMakeList.txt"
|
||||
- "**/*.yml"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [I386, OTHER_ARM, PANDORA, PYRA, GAMESHELL, RPI4, RPI4ARM64, ODROID, RK3399, RK3288, A64, SD845, PHYTIUM]
|
||||
type: [Release, Trace]
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: "Checkout Box86 Repository"
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: "Environment preparation"
|
||||
run: |
|
||||
sudo apt-get update
|
||||
|
||||
if [[ ${{ matrix.platform }} != 'I386' && ${{ matrix.platform }} != 'OTHER_ARM' ]]; then
|
||||
echo "BOX86_PLATFORM_MARCRO=-D${{ matrix.platform }}=1" >> $GITHUB_ENV
|
||||
echo "BOX86_COMPILER=arm-linux-gnueabihf-gcc" >> $GITHUB_ENV
|
||||
sudo apt-get -y install git gcc-arm-linux-gnueabihf cmake make python3
|
||||
else
|
||||
if [[ ${{ matrix.platform }} == 'I386' ]]; then
|
||||
echo "BOX86_PLATFORM_MARCRO=-DLD80BITS=1 -DNOALIGN=1" >> $GITHUB_ENV
|
||||
echo "BOX86_COMPILER=/bin/i686-linux-gnu-gcc-10" >> $GITHUB_ENV
|
||||
sudo apt-get -y install git libc6-dev-i386-amd64-cross gcc-10-i686-linux-gnu cmake make python3
|
||||
ls /bin/*gcc*
|
||||
else
|
||||
echo BOX86_PLATFORM_MARCRO="-DARM_DYNAREC=ON -DCMAKE_C_FLAGS=-marm" >> $GITHUB_ENV
|
||||
echo "BOX86_COMPILER=arm-linux-gnueabihf-gcc" >> $GITHUB_ENV
|
||||
sudo apt-get -y install git gcc-arm-linux-gnueabihf cmake make python3
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ ${{ matrix.type }} == 'Release' ]]; then
|
||||
echo BOX86_BUILD_TYPE=Release >> $GITHUB_ENV
|
||||
echo BOX86_HAVE_TRACE=0 >> $GITHUB_ENV
|
||||
else
|
||||
echo BOX86_BUILD_TYPE=RelWithDebInfo >> $GITHUB_ENV
|
||||
echo BOX86_HAVE_TRACE=1 >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
- name: "Display Build info"
|
||||
run: |
|
||||
echo "CMake Platform Macro: ${{ env.BOX86_PLATFORM_MARCRO }}"
|
||||
echo "CMake C Compiler: ${{ env.BOX86_COMPILER }}"
|
||||
echo "Build type: ${{ env.BOX86_BUILD_TYPE }}"
|
||||
echo "Trace Enabled: ${{ env.BOX86_HAVE_TRACE }}"
|
||||
|
||||
- name: "Build Box86"
|
||||
run: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_C_COMPILER=${{ env.BOX86_COMPILER }} ${{ env.BOX86_PLATFORM_MARCRO }} -DCMAKE_BUILD_TYPE=${{ env.BOX86_BUILD_TYPE }} -DHAVE_TRACE=${{ env.BOX86_HAVE_TRACE }} -DCMAKE_VERBOSE_MAKEFILE:BOOL=ON
|
||||
make -j$(nproc) VERBOSE=1
|
||||
|
||||
- name: "Upload Artifact"
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: box86-${{ matrix.platform }}-${{ matrix.type }}
|
||||
path: build/box86
|
||||
|
||||
|
||||
|
||||
+6
-2
@@ -1,4 +1,8 @@
|
||||
build
|
||||
build*
|
||||
build/
|
||||
build*/
|
||||
.vscode
|
||||
.gdb_history
|
||||
src/git_head.h
|
||||
backup/
|
||||
box86_update.sh
|
||||
restore_backup.sh
|
||||
Executable
+26
@@ -0,0 +1,26 @@
|
||||
language: c
|
||||
arch:
|
||||
- arm64-graviton2
|
||||
- amd64
|
||||
os: linux
|
||||
dist: focal
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- python3
|
||||
|
||||
compiler:
|
||||
- gcc
|
||||
|
||||
#Build steps
|
||||
before_script:
|
||||
- if [ "$TRAVIS_CPU_ARCH" = "arm64" ]; then sudo dpkg --add-architecture armhf ; else sudo dpkg --add-architecture i386 ; fi
|
||||
- if [ "$TRAVIS_CPU_ARCH" = "arm64" ]; then sudo apt-get -y install gcc-arm-linux-gnueabihf ; else sudo apt-get -y install gcc-multilib libc6-dev:i386 libgcc1:i386 ; fi
|
||||
- mkdir build
|
||||
- cd build
|
||||
- if [ "$TRAVIS_CPU_ARCH" = "arm64" ]; then cmake .. -DRK3399=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo ; else CFLAGS="-m32" cmake .. -DLD80BITS=1 -DNOALIGN=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo ; fi
|
||||
|
||||
script:
|
||||
- make
|
||||
- if [ "$TRAVIS_CPU_ARCH" != "arm64" ]; then ctest --output-on-failure ; fi
|
||||
@@ -1,40 +0,0 @@
|
||||
v0.1.0
|
||||
=======
|
||||
* Dynarec!!! Only for ARM (note that dynarec doesn't support JITed code for now)
|
||||
* Added real support for getcontext/set/context/makecontext/swapcontext
|
||||
* Preliminary signal handling
|
||||
* Fixes to SDL(1/2) Image and SDL1 Mixer, and to SDL1.2 RWops usage
|
||||
* Fixed numerous issues in opcodes (both interpretor and dynarec). FTL works fine now, among many others
|
||||
* Added wrapped gtk support (still ongoing, many libs involved)
|
||||
* Make loading of libs more configurable
|
||||
* If a wrapped native libs is not found, try to use emulated one
|
||||
* Add en env. var. to force use of emulated lib for certain libs
|
||||
* Add an env. var. to define wich libGL to use
|
||||
* Added Install / Uninstall target (using systemd binfmt)
|
||||
* Added more hardware target (RPis, GameShell...)
|
||||
* Wrapped more libs (including FreeType, smpeg, ncurses, sndfile...)
|
||||
|
||||
v0.0.4
|
||||
=======
|
||||
* Improved the Init of dependant Libs. More things work now.
|
||||
* Added a lot of wrapped functions.
|
||||
* Added a few wrapped libs (like libz or some other x11 related libs)
|
||||
* For trace enabled build, Trace can be enabled only after a certain amount of opcodes (still, a debugger would be better)
|
||||
* Some fixes in a few opcodes, and implemented x87 rounding (SuperMeatBoy behaves better now)
|
||||
* FTL 1.6.9 still have corrupted music, but older 1.5.13 seems fine (different set of libs)
|
||||
|
||||
v0.0.2
|
||||
=======
|
||||
* A full commercial games runs fine on the Pandora: Airline Tycoon Deluxe
|
||||
* Implemented all planed subpart of Box86 except JIT
|
||||
* CPU Emulation is at 75%, roughly, including x87 and SSE/SSE2. MMX is barely implemented, but barely used anyway
|
||||
* x87 emulation is simplified, no real x87 State handling (but should not be mandatory, as native libm is used)
|
||||
* No Signal handling yet
|
||||
* ELF Loader is crude and probably full of bug. Also, the Init of libs is defered after all symbols are resolved for now.
|
||||
* Wrapped lib include libc, libm, rt, pthread, libdl, dllinux, libasound, GL, GLU, SDL1/mixer/image, SDL2/mixer/image/smpeg, OpenAL/ALUT, libz, libpng16, vorbisfile, x11/xrandr/xxf86vm.
|
||||
* Most wrapped libs are still partially implemented (SDL1 & GL should be complete)
|
||||
* Implemented specific mecanism for SDL(1/2) RWops, to be able to used them both in Native and x86 world
|
||||
* WorldOfGoo works, but painfully slow on th Pandora (too much double math, and lack of JIT)
|
||||
* FTL works, but sound is broken (issue with thread? asound? or CPU core?)
|
||||
* Limbo launch but crash before main menu
|
||||
|
||||
+400
-89
@@ -1,84 +1,156 @@
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
|
||||
project(box86)
|
||||
|
||||
enable_testing()
|
||||
enable_language(C)
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
|
||||
option(PANDORA "Set to ON if targeting an OpenPandora device" ${PANDORA})
|
||||
option(PYRA "Set to ON if targeting an OpenPandora device" ${PYRA})
|
||||
option(RPI2 "Set to ON if targeting an RaspberryPI2 device" ${RPI2})
|
||||
option(RPI3 "Set to ON if targeting an RaspberryPI3 device" ${RPI3})
|
||||
option(RPI4 "Set to ON if targeting an RaspberryPI4 device" ${RPI4})
|
||||
option(GAMESHELL "Set to ON if targeting a Gameshell device" ${GAMESHELL})
|
||||
option(RPI4ARM64 "Set to ON if targeting an RaspberryPI4 device with multiarch arm64 and armhf" ${RPI4ARM64})
|
||||
option(GOA_CLONE "Set to ON if targeting GO Advance clones, like RG351p/v, Gameforce Chi, RGB10..." ${GOA_CLONE})
|
||||
option(RK3288 "Set to ON if targeting an Rockchip RK3288 based device" ${RK3288})
|
||||
option(RK3399 "Set to ON if targeting an Rockchip RK3399 based device" ${RK3399})
|
||||
option(PHYTIUM "Set to ON if targeting an Phytium (D2000 or FT2000/4) based device" ${PHYTIUM})
|
||||
option(GAMESHELL "Set to ON if targeting a GameShell device" ${GAMESHELL})
|
||||
option(ODROID "Set to ON if targeting an ODroid device" ${ODROID})
|
||||
option(POWER9 "Set to ON if targeting a POWER9 processor" ${POWER9})
|
||||
option(SD845 "Set to ON if targeting a Snapragon 845 based device" ${SD845})
|
||||
option(A64 "Set to ON if targeting an Allwinner A64 based device" ${A64})
|
||||
option(ANDROID "Set to ON if targeting an Android device" ${ANDROID})
|
||||
option(USE_CCACHE "Set to ON to use ccache if present in the system" ${USE_CCACHE})
|
||||
option(HAVE_TRACE "Set to ON to have Trace ability (needs ZydisInfo library)" ${HAVE_TRACE})
|
||||
option(NOLOADADDR "Set to ON to avoid fixing the load address of Box86" ${NO_LOADAADR})
|
||||
option(NOGETCLOCK "Set to ON to avoid using clock_gettime with CLOCK_MONOTONIC_COARSE for RDTSC opcode (use gltimeofday instead)" ${NOGETCLOCK})
|
||||
option(NOGIT "Set to ON if not building from a git clone repo (like when building from a zip download from github)" ${NOGIT})
|
||||
if(PANDORA OR PYRA OR RPI2 OR RPI3 OR RPI4 OR GAMESHELL OR ODROID OR GOA_CLONE OR RK3288 OR RK3399 OR RPI4ARM64 OR PHYTIUM OR SD845 OR A64)
|
||||
set(LD80BITS OFF CACHE BOOL "")
|
||||
set(NOALIGN OFF CACHE BOOL "")
|
||||
set(ARM_DYNAREC ON CACHE BOOL "")
|
||||
endif()
|
||||
if(ANDROID)
|
||||
set(NOLOADADDR ON CACHE BOOL "")
|
||||
endif()
|
||||
option(LD80BITS "Set to ON if host device have 80bits long double (i.e. i386)" ${LD80BITS})
|
||||
option(NOALIGN "Set to ON if host device doesn't need re-align (i.e. i386)" ${NOALIGN})
|
||||
option(HAVE_TRACE "Set to ON to have Trace ability (needs ZydisInfo library)" ${HAVE_TRACE})
|
||||
option(USE_FLOAT "Set to ON to use only float, no double, in all x87 Emulation" ${USE_FLOAT})
|
||||
option(NOLOADADDR "Set to ON to avoid fixing the load address of Box86" ${NO_LOADAADR})
|
||||
option(ARM_DYNAREC "Set to ON to use ARM Dynamic Recompilation (WIP, don't use yet)" ${ARM_DYNAREC})
|
||||
option(NOGETCLOCK "Set to ON to avoid using clock_gettime with CLOCK_MONOTONIC_COARSE for RDTSC opcode (use gltimeofday instead)" ${NOGETCLOCK})
|
||||
option(ARM_DYNAREC "Set to ON to use ARM Dynamic Recompilation" ${ARM_DYNAREC})
|
||||
option(POWERPCLE "Set to ON if targeting a little-endian PowerPC device" ${POWERPCLE})
|
||||
option(SYSV_VARARG "Set to ON if host device uses SysVR4 vararg calling convention" ${SYSV_VARARG})
|
||||
|
||||
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()
|
||||
|
||||
if(RK3399 OR RPI4ARM64 OR PHYTIUM OR SD845 OR A64)
|
||||
set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
|
||||
#set(CMAKE_ASM_COMPILER arm-linux-gnueabihf-as) #will use gcc in fact
|
||||
set(CMAKE_C_COMPILER_TARGET arm-linux-gnueabihf)
|
||||
endif()
|
||||
|
||||
project(box86 C ASM)
|
||||
|
||||
enable_testing()
|
||||
|
||||
set(default_build_type "RelwithDebInfo")
|
||||
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||
message(STATUS "Setting build type to '${default_build_type}' as none was specified.")
|
||||
set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE STRING "Choose the type of build." FORCE)
|
||||
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
|
||||
endif()
|
||||
|
||||
# Pandora
|
||||
if(PANDORA)
|
||||
add_definitions(-DPANDORA)
|
||||
#add_definitions(-mcpu=cortex-a8 -mfpu=neon -mfloat-abi=softfp -ftree-vectorize -fsingle-precision-constant -ffast-math)
|
||||
set(ARM_DYNAREC ON)
|
||||
set(LD80BITS OFF)
|
||||
set(NOALIGN OFF)
|
||||
endif()
|
||||
|
||||
# Gameshell
|
||||
if(GAMESHELL)
|
||||
elseif(GAMESHELL)
|
||||
add_definitions(-DGAMESHELL)
|
||||
add_definitions(-marm -mcpu=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-marm -mcpu=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard")
|
||||
set(ARM_DYNAREC ON)
|
||||
set(LD80BITS OFF)
|
||||
set(NOALIGN OFF)
|
||||
endif()
|
||||
|
||||
if(PYRA)
|
||||
elseif(PYRA)
|
||||
add_definitions(-DPYRA)
|
||||
add_definitions(-mcpu=cortex-a15 -mfpu=neon -mfloat-abi=hard -marm)
|
||||
set(CMAKE_ASM_FLAGS "-marm -mcpu=cortex-a15 -mfpu=neon -mfloat-abi=hard")
|
||||
set(ARM_DYNAREC ON)
|
||||
set(LD80BITS OFF)
|
||||
set(NOALIGN OFF)
|
||||
endif()
|
||||
|
||||
if(RPI2)
|
||||
elseif(RPI2)
|
||||
add_definitions(-DRPI)
|
||||
add_definitions(-DRPI2)
|
||||
add_definitions(-marm -mcpu=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-marm -mcpu=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard")
|
||||
set(ARM_DYNAREC ON)
|
||||
set(LD80BITS OFF)
|
||||
set(NOALIGN OFF)
|
||||
endif()
|
||||
if(RPI3)
|
||||
elseif(RPI3)
|
||||
add_definitions(-DRPI)
|
||||
add_definitions(-DRPI3)
|
||||
add_definitions(-marm -march=armv8-a+crc -mtune=cortex-a53 -mfpu=neon-fp-armv8 -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-marm -march=armv8-a+crc -mtune=cortex-a53 -mfpu=neon-fp-armv8 -mfloat-abi=hard")
|
||||
set(ARM_DYNAREC ON)
|
||||
set(LD80BITS OFF)
|
||||
set(NOALIGN OFF)
|
||||
endif()
|
||||
if(RPI4)
|
||||
elseif(RPI4)
|
||||
add_definitions(-DRPI)
|
||||
add_definitions(-DRPI3)
|
||||
add_definitions(-DRPI4)
|
||||
add_definitions(-marm -march=armv8-a+crc -mtune=cortex-a72 -mfpu=neon-fp-armv8 -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-marm -march=armv8-a+crc -mtune=cortex-a72 -mfpu=neon-fp-armv8 -mfloat-abi=hard")
|
||||
set(ARM_DYNAREC ON)
|
||||
set(LD80BITS OFF)
|
||||
set(NOALIGN OFF)
|
||||
elseif(RPI4ARM64)
|
||||
add_definitions(-DRPI)
|
||||
add_definitions(-DRPI4ARM64)
|
||||
add_definitions(-marm -march=armv8-a+crc -mtune=cortex-a72 -mfpu=neon-fp-armv8 -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-marm -march=armv8-a+crc -mtune=cortex-a72 -mfpu=neon-fp-armv8 -mfloat-abi=hard")
|
||||
elseif(ODROID)
|
||||
add_definitions(-DODROID)
|
||||
add_definitions(-mcpu=cortex-a9 -mfpu=neon-vfpv4 -mfloat-abi=hard -marm)
|
||||
set(CMAKE_ASM_FLAGS "-marm -mcpu=cortex-a9 -mfpu=neon-vfpv4 -mfloat-abi=hard")
|
||||
elseif(RK3288)
|
||||
add_definitions(-DRK3288)
|
||||
add_definitions(-mcpu=cortex-a17 -mfpu=neon -mfloat-abi=hard -marm)
|
||||
set(CMAKE_ASM_FLAGS "-marm -mcpu=cortex-a17 -mfpu=neon -mfloat-abi=hard")
|
||||
elseif(SD845)
|
||||
add_definitions(-DSD845)
|
||||
add_definitions(-marm -march=armv8.2-a+simd+crypto -mtune=cortex-a75.cortex-a55 -mfpu=neon-fp-armv8 -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-marm -march=armv8.2-a+simd+crypto -mtune=cortex-a75.cortex-a55 -mfpu=neon-fp-armv8 -mfloat-abi=hard")
|
||||
elseif(A64)
|
||||
add_definitions(-DA64)
|
||||
add_definitions(-marm -march=armv8-a+crc+simd+crypto -mcpu=cortex-a53+crypto -mfpu=neon-fp-armv8 -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-marm -march=armv8-a+crc+simd+crypto -mcpu=cortex-a53+crypto -mfpu=neon-fp-armv8 -mfloat-abi=hard")
|
||||
elseif(GOA_CLONE)
|
||||
add_definitions(-DGOA_CLONE)
|
||||
add_definitions(-marm -mcpu=cortex-a35 -mfpu=neon-vfpv3 -march=armv8-a+crc+simd+crypto -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-marm -mcpu=cortex-a35 -mfpu=neon-vfpv3 -march=armv8-a+crc+simd+crypto -mfloat-abi=hard")
|
||||
elseif(RK3399)
|
||||
add_definitions(-DRK3399)
|
||||
add_definitions(-pipe -march=armv8-a+crc+simd+crypto -mcpu=cortex-a72+crypto -mfpu=neon-fp-armv8 -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8-a+crc+simd+crypto -mcpu=cortex-a72+crypto -mfpu=neon-fp-armv8 -mfloat-abi=hard")
|
||||
elseif(PHYTIUM)
|
||||
add_definitions(-DPHYTIUM)
|
||||
add_definitions(-pipe -march=armv8.1-a+simd+crypto -mfpu=neon-fp-armv8 -mfloat-abi=hard)
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv8.1-a+simd+crypto -mfpu=neon-fp-armv8 -mfloat-abi=hard")
|
||||
elseif(ARM_DYNAREC)
|
||||
#if DYNAREC is selected alone, without any arch
|
||||
set(CMAKE_ASM_FLAGS "-pipe -march=armv7-a+simd -mfpu=neon")
|
||||
endif()
|
||||
|
||||
if(POWER9)
|
||||
add_definitions(-mcpu=power9 -mtune=power9)
|
||||
endif()
|
||||
|
||||
if(NOGIT)
|
||||
add_definitions(-DNOGIT)
|
||||
endif()
|
||||
|
||||
if(BOX86LIB)
|
||||
set(BOX86 box86)
|
||||
elseif(HAVE_TRACE)
|
||||
set(BOX86 box86)
|
||||
else()
|
||||
set(BOX86 box86)
|
||||
endif()
|
||||
|
||||
|
||||
set(BOX86_ELF_ADDRESS "0x62800000")
|
||||
|
||||
if(LD80BITS)
|
||||
add_definitions(-DHAVE_LD80BITS)
|
||||
endif()
|
||||
@@ -91,10 +163,6 @@ if(HAVE_TRACE)
|
||||
add_definitions(-DHAVE_TRACE)
|
||||
endif()
|
||||
|
||||
if(USE_FLOAT)
|
||||
add_definitions(-DUSE_FLOAT)
|
||||
endif()
|
||||
|
||||
if(ARM_DYNAREC)
|
||||
add_definitions(-DDYNAREC)
|
||||
add_definitions(-DARM)
|
||||
@@ -102,22 +170,33 @@ if(ARM_DYNAREC)
|
||||
enable_language(ASM)
|
||||
endif()
|
||||
|
||||
if(POWERPCLE)
|
||||
add_definitions(-DPOWERPCLE)
|
||||
endif()
|
||||
|
||||
if(SYSV_VARARG)
|
||||
add_definitions(-DSYSV_VARARG)
|
||||
endif()
|
||||
|
||||
if(NOGETCLOCK)
|
||||
add_definitions(-DNOGETCLOCK)
|
||||
endif()
|
||||
|
||||
if(BOX86LIB)
|
||||
add_definitions(-DBUILD_LIB)
|
||||
if(BOX86DYNAMIC)
|
||||
add_definitions(-DBUILD_DYNAMIC)
|
||||
endif()
|
||||
add_definitions(-fPIC)
|
||||
if(NOT BOX86_ROOT)
|
||||
message(FATAL_ERROR "BOX86_ROOT not set when build as lib")
|
||||
endif()
|
||||
else()
|
||||
set(BOX86_ROOT ${CMAKE_HOME_DIRECTORY})
|
||||
set(BOX86_ROOT ${CMAKE_SOURCE_DIR})
|
||||
endif()
|
||||
|
||||
|
||||
add_definitions(-g -std=gnu99 -funwind-tables -O3 -fvisibility=hidden)
|
||||
add_definitions(-std=gnu11 -funwind-tables -fvisibility=hidden)
|
||||
|
||||
if(USE_CCACHE)
|
||||
find_program(CCACHE_FOUND ccache)
|
||||
@@ -133,39 +212,60 @@ include_directories(
|
||||
"${BOX86_ROOT}/src/wrapped/generated"
|
||||
)
|
||||
|
||||
# git_head.h is a generated file
|
||||
set_source_files_properties(
|
||||
"${BOX86_ROOT}/src/git_head.h"
|
||||
PROPERTIES GENERATED TRUE
|
||||
HEADER_FILE_ONLY TRUE)
|
||||
|
||||
set(ELFLOADER_SRC
|
||||
"${BOX86_ROOT}/src/main.c"
|
||||
"${BOX86_ROOT}/src/box86context.c"
|
||||
"${BOX86_ROOT}/src/build_info.c"
|
||||
"${BOX86_ROOT}/src/custommem.c"
|
||||
"${BOX86_ROOT}/src/tools/bridge.c"
|
||||
"${BOX86_ROOT}/src/tools/pathcoll.c"
|
||||
"${BOX86_ROOT}/src/tools/fileutils.c"
|
||||
"${BOX86_ROOT}/src/tools/callback.c"
|
||||
"${BOX86_ROOT}/src/tools/box86stack.c"
|
||||
"${BOX86_ROOT}/src/tools/my_cpuid.c"
|
||||
"${BOX86_ROOT}/src/tools/gtkclass.c"
|
||||
"${BOX86_ROOT}/src/tools/wine_tools.c"
|
||||
"${BOX86_ROOT}/src/elfs/elfloader.c"
|
||||
"${BOX86_ROOT}/src/elfs/elfparser.c"
|
||||
"${BOX86_ROOT}/src/elfs/elfload_dump.c"
|
||||
"${BOX86_ROOT}/src/librarian/library.c"
|
||||
"${BOX86_ROOT}/src/librarian/librarian.c"
|
||||
"${BOX86_ROOT}/src/librarian/dictionnary.c"
|
||||
"${BOX86_ROOT}/src/librarian/symbols.c"
|
||||
"${BOX86_ROOT}/src/librarian/globalsymbols.c"
|
||||
"${BOX86_ROOT}/src/emu/x86emu.c"
|
||||
"${BOX86_ROOT}/src/emu/x86run.c"
|
||||
"${BOX86_ROOT}/src/emu/x86run66.c"
|
||||
"${BOX86_ROOT}/src/emu/x86run660f.c"
|
||||
"${BOX86_ROOT}/src/emu/x86run_private.c"
|
||||
"${BOX86_ROOT}/src/emu/x86syscall.c"
|
||||
"${BOX86_ROOT}/src/emu/x86primop.c"
|
||||
"${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/sdl1rwops.c"
|
||||
"${BOX86_ROOT}/src/libtools/sdl2rwops.c"
|
||||
"${BOX86_ROOT}/src/libtools/signals.c"
|
||||
"${BOX86_ROOT}/src/libtools/threads.c"
|
||||
"${BOX86_ROOT}/src/libtools/vkalign.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec.c"
|
||||
"${BOX86_ROOT}/src/wrapped/generated/wrapper.c"
|
||||
)
|
||||
if(NOT ANDROID)
|
||||
list(APPEND ELFLOADER_SRC "${BOX86_ROOT}/src/libtools/obstack.c")
|
||||
endif()
|
||||
|
||||
set(WRAPPEDS
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibc.c"
|
||||
@@ -179,11 +279,15 @@ set(WRAPPEDS
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibm.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedsdl1.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedsdl1mixer.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedsdl1net.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedsdl1image.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedsdl1sound.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedsdl1ttf.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedsdl2.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedsdl2mixer.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedsdl2net.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedsdl2image.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedsdl2ttf.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedsmpeg.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedsmpeg2.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedvorbisfile.c"
|
||||
@@ -198,6 +302,7 @@ set(WRAPPEDS
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxfixes.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxcursor.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxrender.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxft.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxi.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxss.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxpm.c"
|
||||
@@ -205,18 +310,34 @@ set(WRAPPEDS
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxdmcp.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibx11xcb.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxcb.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxcbxfixes.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxcbshape.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxcbshm.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxcbrandr.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxcbimage.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxcbkeysyms.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxcbxtest.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxcbdri2.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxcbdri3.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibxcbpresent.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/wrappedalure.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/wrappedlibcrypt.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedutil.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibuuid.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibresolv.c"
|
||||
@@ -226,23 +347,34 @@ set(WRAPPEDS
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedfontconfig.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedfreetype.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedbz2.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedexpat.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibsm.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibice.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibusb1.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibncursesw.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibformw.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibncurses.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibtinfo.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibpanel.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/wrappedgtk3.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgdk3.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgdkpixbuf2.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgio2.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgmodule2.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgobject2.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedglib2.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgconf2.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgstreamer010.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgstinterfaces010.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappeddbusmenugtk.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappeddbusmenuglib.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedappindicator.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedatk.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedatkbridge.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedpangoft2.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedpangocairo.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgthread2.c"
|
||||
@@ -250,19 +382,81 @@ 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/wrappedlibcups.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedd3dadapter9.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedvulkan.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedwaylandclient.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedxml2.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedxslt.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedldapr.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlber.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappednsl.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlcms2.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedkrb5.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedgssapikrb5.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibtiff.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedldlinux.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedcrashhandler.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibv4l2.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappednspr4.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedsmime3.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappednssutil3.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappednss3.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedplds4.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedplc4.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedssl3.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedsecret1.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedtbbmalloc.c"
|
||||
)
|
||||
if(ANDROID)
|
||||
list(APPEND WRAPPEDS
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedandroidshmem.c"
|
||||
)
|
||||
else()
|
||||
list(APPEND WRAPPEDS
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibjpeg.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedlibjpeg62.c"
|
||||
"${BOX86_ROOT}/src/wrapped/wrappedturbojpeg.c"
|
||||
)
|
||||
endif()
|
||||
|
||||
set(WRAPPEDS_HEAD "")
|
||||
# If BOX86_ROOT contains a ".c", the build breaks...
|
||||
string(REPLACE ".c" "_private.h" MODROOT ${BOX86_ROOT})
|
||||
set(WRAPPEDS_HEAD "${BOX86_ROOT}/src/wrapped/wrappedd3dadapter9_genvate.h")
|
||||
foreach(A ${WRAPPEDS})
|
||||
string(REPLACE ".c" "_private.h" B ${A})
|
||||
string(REPLACE ".c" "_private.h" C ${A})
|
||||
string(REPLACE "${MODROOT}" "${BOX86_ROOT}" B ${C})
|
||||
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" "POWERPCLE" "ANDROID" "--"
|
||||
${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")
|
||||
|
||||
if(ARM_DYNAREC)
|
||||
set(DYNAREC_SRC
|
||||
@@ -274,15 +468,20 @@ if(ARM_DYNAREC)
|
||||
|
||||
"${BOX86_ROOT}/src/dynarec/arm_prolog.S"
|
||||
"${BOX86_ROOT}/src/dynarec/arm_epilog.S"
|
||||
"${BOX86_ROOT}/src/dynarec/arm_linker.S"
|
||||
"${BOX86_ROOT}/src/dynarec/arm_table.S"
|
||||
"${BOX86_ROOT}/src/dynarec/arm_next.S"
|
||||
"${BOX86_ROOT}/src/dynarec/arm_lock_helper.S"
|
||||
)
|
||||
|
||||
set(DYNAREC_PASS
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_helper.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_emit_tests.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_emit_math.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_emit_logic.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_emit_shift.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_pass.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_00.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_0f.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_64.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_65.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_66.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_67.c"
|
||||
@@ -312,6 +511,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>
|
||||
@@ -320,40 +523,88 @@ if(ARM_DYNAREC)
|
||||
$<TARGET_OBJECTS:arm_pass2>
|
||||
$<TARGET_OBJECTS:arm_pass3>
|
||||
)
|
||||
|
||||
endif()
|
||||
|
||||
# creates git_head.h
|
||||
if(ARM_DYNAREC)
|
||||
add_custom_command(
|
||||
OUTPUT "${BOX86_ROOT}/src/git_head.h"
|
||||
COMMAND bash -c "echo \\\#define GITREV \\\"$(git rev-parse --short HEAD)\\\">\"${BOX86_ROOT}/src/git_head.h\""
|
||||
DEPENDS dynarec ${ELFLOADER_SRC} ${WRAPPEDS}
|
||||
VERBATIM)
|
||||
else()
|
||||
add_custom_command(
|
||||
OUTPUT "${BOX86_ROOT}/src/git_head.h"
|
||||
COMMAND bash -c "echo \\\#define GITREV \\\"$(git rev-parse --short HEAD)\\\">\"${BOX86_ROOT}/src/git_head.h\""
|
||||
DEPENDS ${ELFLOADER_SRC} ${WRAPPEDS}
|
||||
VERBATIM)
|
||||
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} "${BOX86_ROOT}/src/git_head.h")
|
||||
else()
|
||||
add_library(${BOX86} OBJECT ${ELFLOADER_SRC} ${WRAPPEDS} "${BOX86_ROOT}/src/git_head.h")
|
||||
endif()
|
||||
if(ARM_DYNAREC)
|
||||
if(ANDROID)
|
||||
target_link_libraries(${BOX86} dynarec m dl)
|
||||
else()
|
||||
target_link_libraries(${BOX86} dynarec m dl rt pthread)
|
||||
endif()
|
||||
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)
|
||||
|
||||
add_custom_target(buildinfo ${BOX86}
|
||||
DEPENDS dynarec ${BOX86} )
|
||||
|
||||
else(BOX86LIB)
|
||||
|
||||
if(USE_FLOAT)
|
||||
set(BOX86 box86f)
|
||||
elseif(HAVE_TRACE)
|
||||
set(BOX86 box86t)
|
||||
add_executable(${BOX86} ${ELFLOADER_SRC} ${WRAPPEDS} "${BOX86_ROOT}/src/git_head.h")
|
||||
add_dependencies(${BOX86} WRAPPERS)
|
||||
add_dependencies(${BOX86} PRINTER)
|
||||
if(ANDROID)
|
||||
target_link_libraries(${BOX86} m dl)
|
||||
else()
|
||||
set(BOX86 box86)
|
||||
target_link_libraries(${BOX86} m dl rt pthread)
|
||||
endif()
|
||||
|
||||
add_executable(${BOX86} ${ELFLOADER_SRC} ${WRAPPEDS})
|
||||
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)
|
||||
string(COMPARE EQUAL "${CMAKE_HOST_SYSTEM_PROCESSOR}" "x86_64" _x86_64)
|
||||
string(COMPARE EQUAL "${CMAKE_HOST_SYSTEM_PROCESSOR}" "aarch64" _aarch64)
|
||||
string(COMPARE EQUAL "${CMAKE_HOST_SYSTEM_PROCESSOR}" "armhf" _armhf)
|
||||
|
||||
if(NOT _x86 AND NOT _x86_64)
|
||||
install(TARGETS ${BOX86}
|
||||
RUNTIME DESTINATION bin)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/system/box86.conf DESTINATION /etc/binfmt.d/)
|
||||
configure_file(system/box86.conf.cmake system/box86.conf)
|
||||
install(FILES ${CMAKE_BINARY_DIR}/system/box86.conf DESTINATION /etc/binfmt.d/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libstdc++.so.6 DESTINATION /usr/lib/i386-linux-gnu/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libstdc++.so.5 DESTINATION /usr/lib/i386-linux-gnu/)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/x86lib/libgcc_s.so.1 DESTINATION /usr/lib/i386-linux-gnu/)
|
||||
endif()
|
||||
|
||||
@@ -367,72 +618,132 @@ if(NOT TARGET uninstall)
|
||||
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
|
||||
endif()
|
||||
|
||||
add_test(test01 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
set(CPACK_GENERATOR "DEB")
|
||||
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "ptitSeb")
|
||||
set(CPACK_PACKAGE_CONTACT "[email protected]")
|
||||
set(CPACK_PACKAGE_DESCRIPTION "Box86 - Linux Userspace x86 Emulator with a twist")
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6")
|
||||
set(CPACK_PACKAGE_HOMEPAGE_URL, "https://box86.org")
|
||||
file(STRINGS "${BOX86_ROOT}/src/box86version.h" TEMP_STRING REGEX "BOX86_MAJOR\\s*")
|
||||
string(REGEX REPLACE "BOX86_MAJOR" "" TEMP_STRING ${TEMP_STRING})
|
||||
string(REGEX MATCH "[0-9]" BOX86_MAJOR ${TEMP_STRING})
|
||||
file(STRINGS "${BOX86_ROOT}/src/box86version.h" TEMP_STRING REGEX "BOX86_MINOR\\s*")
|
||||
string(REGEX REPLACE "BOX86_MINOR" "" TEMP_STRING ${TEMP_STRING})
|
||||
string(REGEX MATCH "[0-9]" BOX86_MINOR ${TEMP_STRING})
|
||||
file(STRINGS "${BOX86_ROOT}/src/box86version.h" TEMP_STRING REGEX "BOX86_REVISION\\s*")
|
||||
string(REGEX REPLACE "BOX86_REVISION" "" TEMP_STRING ${TEMP_STRING})
|
||||
string(REGEX MATCH "[0-9]" BOX86_REVISION ${TEMP_STRING})
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR ${BOX86_MAJOR})
|
||||
set(CPACK_PACKAGE_VERSION_MINOR ${BOX86_MINOR})
|
||||
set(CPACK_PACKAGE_VERSION_PATCH ${BOX86_REVISION})
|
||||
set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_CURRENT_SOURCE_DIR}/postinst")
|
||||
if(_aarch64 OR _armhf)
|
||||
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "armhf")
|
||||
elseif(_x86_64 OR _x86)
|
||||
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "i386")
|
||||
else()
|
||||
#probably wrong...
|
||||
execute_process(COMMAND "dpkg --print-architecture" OUTPUT_VARIABLE CPACK_DEBIAN_PACKAGE_ARCHITECTURE)
|
||||
endif()
|
||||
set(CPACK_DEBIAN_FILE_NAME "${BOX86}-${BOX86_MAJOR}.${BOX86_MINOR}.${BOX86_REVISION}_Linux-${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}.deb")
|
||||
INCLUDE(CPack)
|
||||
|
||||
add_test(NAME bootSyscall COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test01 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref01.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test02 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
add_test(NAME bootSyscallC COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test02 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref02.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test03 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
add_test(NAME printf COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test03 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref03.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test04 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
add_test(NAME args COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test04 -D TEST_ARGS2=yeah -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref04.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test05 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
add_test(NAME maths1 COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test05 -D TEST_ARGS2=7 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref05.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test06 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
add_test(NAME threadsStart COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test06 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref06.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test07 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
add_test(NAME trig COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test07 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref07.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test08 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
add_test(NAME pi COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test08 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref08.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test09 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
add_test(NAME fork COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test09 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref09.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test10 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
add_test(NAME cppThreads COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test10 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref10.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test11 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
add_test(NAME tlsData COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test11 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref11.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test12 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
add_test(NAME fpu COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test12 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref12.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(test13 ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
add_test(NAME contexts COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test13 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_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(NAME conditionalThreads COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test14 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref14.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME linkingIndirectNoversion COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test15 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref15.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME linkingIndirectVersion COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test16 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref16.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME ucomiss COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test17 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref17.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME longjumpInSignals COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test18 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref18.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
add_test(NAME x87 COMMAND ${CMAKE_COMMAND} -D TEST_PROGRAM=${CMAKE_BINARY_DIR}/${BOX86}
|
||||
-D TEST_ARGS=${CMAKE_SOURCE_DIR}/tests/test19 -D TEST_OUTPUT=tmpfile.txt
|
||||
-D TEST_REFERENCE=${CMAKE_SOURCE_DIR}/tests/ref19.txt
|
||||
-P ${CMAKE_SOURCE_DIR}/runTest.cmake )
|
||||
|
||||
file(GLOB extension_tests "${CMAKE_SOURCE_DIR}/tests/extensions/*.c")
|
||||
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}
|
||||
|
||||
-54
@@ -1,54 +0,0 @@
|
||||
Compiling
|
||||
----
|
||||
#### for Pandora
|
||||
|
||||
`mkdir build; cd build; cmake .. -DPANDORA=1; make`
|
||||
|
||||
#### for Pyra
|
||||
|
||||
`mkdir build; cd build; cmake .. -DPYRA=1; make`
|
||||
|
||||
#### for Gameshell
|
||||
|
||||
`mkdir build; cd build; cmake .. -DGAMESHELL=1; 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`
|
||||
|
||||
_For Pi4. Change to RPI2 or RPI3 for other models._
|
||||
|
||||
#### for Other ARM Linux
|
||||
|
||||
`mkdir build; cd build; cmake .. ; make`
|
||||
|
||||
#### for x86 Linux
|
||||
|
||||
`mkdir build; cd build; cmake .. -DLD80BITS=1 -DNOALIGN=1; make`
|
||||
|
||||
#### use ccmake
|
||||
|
||||
Alternatively, you can use the curses-bases ccmake (or any other gui frontend for cmake) to select wich platform to use interactively.
|
||||
|
||||
#### Customize your build
|
||||
|
||||
*use ccache if you have it*
|
||||
Add `-DUSE_CCACHE=1` if you have ccache (it's better if you plan to touch the sources)
|
||||
|
||||
|
||||
*to have a Trace Enabled build*
|
||||
To have a trace enabled build (warning, it will be slower), add `-DHAVE_TRACE=1` but you will need, at runtime, to have the [Zydis library](https://github.com/zyantific/zydis) library in your `LD_LIBRARY_PATH` or in the system lib folders.
|
||||
|
||||
*to have ARM Dynarec*
|
||||
The Dynarec is only avaiable on ARM Cpu. Notes also that VFPv3 and NEON are required for the Dynarec. Activate it by using `-DARM_DYNAREC=1`. Also, be sure to use `-marm` in compilation flags (because many compileur use Thumb as default, and the dynarec will not work in this mode).
|
||||
|
||||
----
|
||||
|
||||
Testing
|
||||
----
|
||||
A few tests are included.
|
||||
They can be launched with `ctest`
|
||||
They are very basic and don't test much for now.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2018-2019 Sebastien Chevalier ("ptitSeb")
|
||||
Copyright (c) 2018-2021 Sebastien Chevalier ("ptitSeb")
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
# box86
|
||||
|
||||
Linux Userspace x86 Emulator with a twist
|
||||
|
||||
[](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=LU8Y2T62ZWFHU)
|
||||
|
||||
Box86 will let you run x86 Linux programs (games) on non-x86 Linux, like ARM (host system needs to be 32bit little-endian).
|
||||
|
||||
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.
|
||||
|
||||
Most x86 Games need OpenGL, so on ARM platforms, a solution like [gl4es](https://github.com/ptitSeb/gl4es) is probably needed.
|
||||
|
||||
Box86 now integrate a DynaRec for ARM platform, providing a speed boost between 5 to 10 times compared to only the interpretor.
|
||||
|
||||
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)
|
||||
|
||||
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.
|
||||
|
||||
Some x86 internal opcodes use parts of "Realmode X86 Emulator Library", see [x86primop.c](src/x86primop.c) for copyright details
|
||||
|
||||
Here are 6 videos, the first 2 of "Airline Tycoon Deluxe" and "Heretic 2" running on a gigahertz OpenPandora (the second one use the dynarec), and the next 2 of "Bit.Trip.Runner" and "Neverwinter Night" running on an ODroid XU4 (without dynarec), and the last 2 on a Pi4: Shovel Knight (video from @ITotalJustice) and Freedom Planet (video from @djazz), also without dynarec.
|
||||
|
||||
[](https://www.youtube.com/watch?v=bLt0hMoFDLk) [](https://www.youtube.com/watch?v=MM7kWYts7IA) [](https://www.youtube.com/watch?v=8hr71S029Hg) [](https://www.youtube.com/watch?v=B4YN37z3-ws) [](https://www.youtube.com/watch?v=xk8Q30mxqPg) [](https://www.youtube.com/watch?v=_QMRMVvYrqU)
|
||||
|
||||
----
|
||||
|
||||
Compiling
|
||||
----
|
||||
How to compile can be found [here](COMPILE.md)
|
||||
|
||||
----
|
||||
|
||||
Usage
|
||||
----
|
||||
|
||||
There are a few environment variables to control Box86 behaviour.
|
||||
|
||||
See [here](USAGE.md) for all variables and what they do.
|
||||
|
||||
----
|
||||
|
||||
Version history
|
||||
----
|
||||
|
||||
The change log is [here](CHANGELOG.md)
|
||||
|
||||
----
|
||||
|
||||
A note about 64bits platform
|
||||
----
|
||||
|
||||
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.
|
||||
|
||||
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)
|
||||
|
||||
----
|
||||
|
||||
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.
|
||||
|
||||
TL;DR: mono games are not working for now anyway.
|
||||
|
||||
----
|
||||
|
||||
Final words
|
||||
----
|
||||
|
||||
(If you use Box86 in your project, please don't forget to mention Box86)
|
||||
@@ -1,112 +0,0 @@
|
||||
Usage
|
||||
----
|
||||
|
||||
There are many environment variable to control Box86 behaviour.
|
||||
|
||||
##### BOX86_LOG
|
||||
Controls the Verbose level of the log
|
||||
* 0
|
||||
* NONE : No message (except some fatal error)
|
||||
* 1
|
||||
* INFO : Current default. Show some log
|
||||
* 2
|
||||
* DEBUG : Verbose a lot of stuffs (like relocations or function called)
|
||||
* 3
|
||||
* DUMP : All DEBUG plus DUMP of all ELF Info
|
||||
|
||||
#### BOX86_LD_LIBRARY_PATH
|
||||
Controls the folder scanned to look for x86 libs. Default is current folder and `lib` in current folder.
|
||||
Also `/usr/lib/i386-linux-gnu` and `/lib/i386-linux-gnu` are added if they exists
|
||||
|
||||
#### BOX86_PATH
|
||||
Controls the folder scanned to look for x86 executable. Default is current folder and `bin` in current folder.
|
||||
|
||||
#### BOX86_DLSYM_ERROR
|
||||
* 0 : default. Don't log `dlsym` error
|
||||
* 1 : Log dlsym error
|
||||
|
||||
#### BOX86_TRACE_FILE
|
||||
Send all log and trace to a file instead of `stdout`
|
||||
|
||||
#### BOX86_TRACE
|
||||
Only on build with trace enabled. Trace allow the logging of all instruction execute, along with register dump
|
||||
* 0 : No trace
|
||||
* 1 : Trace enabled. The trace start after the init of all depending libs is done
|
||||
* symbolname : Trace only `symbolname` (trace is disable if the symbol is not found)
|
||||
* 0xXXXXXXX-0xYYYYYYY : trace only between the 2 addresses
|
||||
|
||||
#### BOX86_TRACE_INIT
|
||||
Use BOX86_TRACE_INIT instead of BOX_TRACE to start trace before init of Libs and main program
|
||||
* 0 : No trace
|
||||
* 1 : Trace enabled. The trace start with the init of all depending libs is done
|
||||
|
||||
#### BOX86_TRACE_START
|
||||
Only on build with trace enabled.
|
||||
* NNNNNNN : Start trace only after NNNNNNNN opcode execute (number is an `uint64_t`)
|
||||
|
||||
#### BOX86_TRACE_XMM
|
||||
Only on build with trace enabled.
|
||||
* 0 : Default, the XMM (i.e. SSE/SSE2) register will not be logged with the general and x87 registers
|
||||
* 1 : Dump the XMM registers
|
||||
|
||||
#### BOX86_LOAD_ADDR
|
||||
Try to load at 0xXXXXXX main binaray (if binary is a PIE)
|
||||
* 0xXXXXXXXX the load address (only active on PIE programs)
|
||||
|
||||
#### BOX86_NOSIGSEGV
|
||||
To disable handling of SigSEGV (to ease debugging mainly)
|
||||
* 0 : default, let x86 program set sighandler for SEGV
|
||||
* 1 : disable handling of SigSEGV
|
||||
|
||||
#### BOX86_X11COLOR16
|
||||
PANDORA only: to try convert X11 color from 32 bits to 16 bits (to avoid light green on light cyan windows
|
||||
* 0 : default, don't touch X11 colors
|
||||
* 1 : Change colors arguments in XSetForeground, XSetBackground and XCreateGC
|
||||
|
||||
#### BOX86_X11THREADS
|
||||
To call XInitThreads when loading X11 (for old Loki games with Loki_Compat lib)
|
||||
* 0 : default, don't force call XInitThreads
|
||||
* 1 : Call XInitThreads as soon as libX11 is loaded
|
||||
|
||||
#### BOX86_DYNAREC_LOG
|
||||
Set level of DynaRec log
|
||||
* 0 :
|
||||
* NONE : No Log for DynaRec
|
||||
* 1 :
|
||||
* INFO : Minimum Dynarec Log (only unimplemented OpCode)
|
||||
* 2 :
|
||||
* DEBUG : Debug Log for Dynarec (with detail on block created / executed)
|
||||
* 3 :
|
||||
* DUMP : All above plus dump of the x86 -> native opcode conversions
|
||||
|
||||
#### BOX86_DYNAREC
|
||||
* 0 : Disable Dynarec
|
||||
* 1 : Enable Dynarec (default)
|
||||
|
||||
#### BOX86_DYNAREC_LINKER
|
||||
* 0 : Disable Dynarec Linker (use that on debug, with dynarec log >= 2, to have detail on wich block get executed)
|
||||
* 1 : Enable Dynarec Linker (default)
|
||||
|
||||
#### BOX86_DYNAREC_TRACE
|
||||
* 0 : Disable trace for generated code (default)
|
||||
* 1 : Enable trace for generated code (like regular Trace, this will slow down a lot and generate huge logs)
|
||||
|
||||
#### BOX86_LIBGL
|
||||
* libXXXX set the name for libGL (default to libGL.so.1)
|
||||
* /PATH/TO/libGLXXX set the name and path for libGL
|
||||
You can also use SDL_VIDEO_GL_DRIVER
|
||||
|
||||
#### BOX86_LD_PRELOAD
|
||||
* XXXX[:YYYYY] force loading XXXX (and YYYY...) libraries with the binary
|
||||
PreLoaded libs can be emulated or native, and are treated the same way as if they were comming from the binary
|
||||
|
||||
#### BOX86_EMULATED_LIBS
|
||||
* XXXX[:YYYYY] force lib XXXX (and YYYY...) to be emulated (and not wrapped)
|
||||
Some games use old version of some lib, with an ABI incompatible with native version.
|
||||
Note that LittleInforno for example is auto detected, and libvorbis.so.0 is automatical added to emulated libs
|
||||
|
||||
#### 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.
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
theme: jekyll-theme-hacker
|
||||
Executable
+153
@@ -0,0 +1,153 @@
|
||||
v0.2.4
|
||||
======
|
||||
* Some work on Dynarec to limit the number of mutex use, and also allow smaller block to be built (for JIT'd programs)
|
||||
* Introduce BOX86_DYNAREC_STRONGMEM, like with box64 (not found any program that needs that yet)
|
||||
* More vulkan wrapped function (so dkvk works, at least with RX550)
|
||||
* Reworked Elfloader part, with better handling of versionned symbols
|
||||
* Improve speed for x87 code (by avoiding many float<->double conversion)
|
||||
* Improve speed of the custom allocator used by dynarec and Hash (speedup loading)
|
||||
* Added a detection of box64 in uname call, to expose an x86_64 system instead of i386 one
|
||||
* Added a fix for linking box86 on system using glibc 2.34+
|
||||
* A few more wrapped libs
|
||||
* More ARM hardware option in CMake (Phytium, SD845)
|
||||
* Changed a bit struture of Dynarec, switching some operations from Pass1 to Pass0
|
||||
* Small fixes to elfloader
|
||||
* Some fixes and improvments on wrapped libs (mainly gtk2, gtk3 and d3dadpter)
|
||||
* Better VSyscall implementation
|
||||
* Fixed the "Alternate" handling (address shadowing on x86 side)
|
||||
* A few opcodes border case fixes
|
||||
* Improved wrapper helpers (from rajdakin)
|
||||
* Added a mecanism to cancel a Dynarec block construction if it triggers a segfault (instead of a crash)
|
||||
* Improvment to the handling of longjmp inside signal handlers
|
||||
|
||||
v0.2.2
|
||||
======
|
||||
* Reworked some elfloader relocation mecanism
|
||||
* Removed old "smart linker" and replace with a simple "jump table"
|
||||
* Also removed CALL/RET optomisation from Dynarec, simple Jump Table is faster
|
||||
* Reworked all memory protection tracking
|
||||
* A few more wrapped libs and wrapped functions
|
||||
* A few more opcodes
|
||||
* A few more dynarec opcodes
|
||||
* Some optimisation in Dynarec around ZF and CF flags handlings, and LL/GE/LE/G conditionnal opcodes
|
||||
* Some changes to the "cancel threads" handling
|
||||
* Some changes to the "thread once" handling
|
||||
|
||||
v0.2.0
|
||||
======
|
||||
* Improvements on x86 Flags handling.
|
||||
* A few more opcode has been added.
|
||||
* A few potential BusError are now fixed.
|
||||
* Added the BOX86_NOVULKAN en. var. . This is used to disable the wrapping of vulkan libraries.
|
||||
* Improvments on libc O_XXXX flags handling.
|
||||
* Box86 now uses a custom allocator for Dynarec and Hash tables.
|
||||
* Improved the wrapping of pulse audio.
|
||||
* Optimisation to a few Dynarec opcode (like SHRD/SHLD).
|
||||
* Improved the tracking of memory protection.
|
||||
* A few more wrapping of libraries (like libgssapi_krb5).
|
||||
* More function wrapping on libturbojpeg
|
||||
* Preliminary support for POWER9 (ppcle) build
|
||||
* Many contributions to remove typos and rephrase the README, COMPILE and USAGE documents
|
||||
|
||||
v0.1.8
|
||||
======
|
||||
* Fixes on some float to int x86 convertions opcodes.
|
||||
* Reworked all callback mecanisms.
|
||||
* Added libturbojpeg wrapping (and a hack for zoom to force using native one).
|
||||
* Added the BOX86_SAFEMMAP env. var.
|
||||
* Reworked Dynarec's memory manager.
|
||||
* Added a few opcodes.
|
||||
* Improve elfloader to not force PltResolver all the time (fixing SuperHexagon and maybe other)
|
||||
* Reworked Exet and Cancel Thread mecanism.
|
||||
* Added wrapped libldap_r and liblber library (used by wine)
|
||||
* Reworked Dynarec block handling, and remove the "AddMark" mecanism that wasn't efficient enough
|
||||
* Added TokiTori 2+ detection and runtime patch on the Raspberry Pi platform
|
||||
* Fixes on elfloader with TLS object.
|
||||
|
||||
v0.1.6
|
||||
======
|
||||
* Changes in Dynarec to make flags optimizations before CALL and RET opcode less aggressive.
|
||||
* Added a Vulkan wrapper.
|
||||
* Improved wrapping of SDL_mixer/ SDL2_mixer libraries.
|
||||
* Improved wrapping of some GTK structures.
|
||||
* Added a quick and dirty wrapping of GTK3 (based on current GTK2).
|
||||
* Improved the signal handling, should be more stable now (the signal handler from syscall still need some works).
|
||||
* Added the RK3399 profile, and some hints to build 32bits box86 on 64bits OS.
|
||||
* Fixed some wrapped printf formating not handled correctly.
|
||||
* Fixed some buserror with the new LOCK mecanism handling.
|
||||
* A few more Dynarec opcodes added.
|
||||
* If winedbg is tried to be launched, exit without launching it (it doesn't work anyways).
|
||||
|
||||
v0.1.4
|
||||
======
|
||||
* Change in Dynarec's memory handling, to simplify it (and hopefully optimized it).
|
||||
* Even more opcodes added.
|
||||
* And some more Dynarec opcodes.
|
||||
* Fixed some issue were PltResolver was injected but should not be.
|
||||
* Fixed many Dynarec and non dynarec opcodes.
|
||||
* Improved Signal handling.
|
||||
* Added a few more wrapped libraries (like curl).
|
||||
* Gallium9 is now wrapped (thx @icecream95).
|
||||
* Fixed and simplied many wrapped functions (especialy the one where a callback is involved).
|
||||
* Fixed Dynarec "freeing" a Dynablock sometimes causing a corruption of the heap (generally happens in case of JIT code).
|
||||
* Optimized the way LOCK prefix work when using Dynarec on ARM.
|
||||
* improvements to the ARM opcode Printer (for dumping Dynarec blocks) improvement (thx @rajdakin).
|
||||
|
||||
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 functionalities on 32bits (only mini-mode is available).
|
||||
* More wrapped libs
|
||||
* Added support for the "PltResolver". This makes the order of libraries less important and many symbols are now resolved at runtime.
|
||||
* Added an option to build Box86 as a library (to wrap 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 has a logo!
|
||||
* Added options handling (only version and help for now). Now it's much usefull exept for version printing.
|
||||
|
||||
|
||||
v0.1.0
|
||||
=======
|
||||
* Dynarec!!! Only for ARM (note that Dynarec doesn't support JITed code for now).
|
||||
* Added real support for getcontext/set/context/makecontext/swapcontext.
|
||||
* Preliminary signal handling.
|
||||
* Fixes to SDL(1/2) Image and SDL1 Mixer, and to SDL1.2 RWops usage.
|
||||
* Fixed numerous issues in opcodes (both interpretor and dynarec). FTL works fine now, among many others.
|
||||
* Added wrapped GTK support (still ongoing, many libraries involved).
|
||||
* Make loading of libraries more configurable.
|
||||
* If a wrapped native library is not found, try to use an emulated one.
|
||||
* Added an env. var. to force the use of emulated libraries for certain libraries.
|
||||
* Added an env. var. to precise which libGL to use.
|
||||
* Added Install / Uninstall target (using systemd binfmt).
|
||||
* Added more hardware targets (RPis, GameShell...).
|
||||
* Wrapped more libraries (including FreeType, smpeg, ncurses, sndfile...).
|
||||
|
||||
v0.0.4
|
||||
=======
|
||||
* Improved the initialisation of dependent libraries. More things work now.
|
||||
* Added a lot of wrapped functions.
|
||||
* Added a few wrapped libraries (like libz or some other x11 related library).
|
||||
* For trace enabled build, Trace can be enabled only after a certain amount of opcodes (still, a debugger would be better).
|
||||
* Some fixes in a few opcodes, and implemented x87 rounding (SuperMeatBoy behaves better now).
|
||||
* FTL 1.6.9 still has corrupted music, but older 1.5.13 seems fine (different set of libraries).
|
||||
|
||||
v0.0.2
|
||||
=======
|
||||
* A full commercial games runs fine on the Pandora platform: Airline Tycoon Deluxe.
|
||||
* Implemented all planned subparts of Box86 except JIT support.
|
||||
* CPU Emulation is at roughly 75%. This includes x87 and SSE/SSE2. MMX is barely implemented (but barely used anyway).
|
||||
* x87 emulation is simplified, no real x87 State handling (but should not be mandatory, as the native libm library is used)
|
||||
* No Signal handling yet
|
||||
* ELF Loader is crude and probably full of bugs. Also, the initialisation of libraries are defered after all symbols are resolved for now.
|
||||
* Wrapped libraries include libc, libm, rt, pthread, libdl, dllinux, libasound, GL, GLU, SDL1/mixer/image, SDL2/mixer/image/smpeg, OpenAL/ALUT, libz, libpng16, vorbisfile, x11/xrandr/xxf86vm.
|
||||
* Most wrapped libraries are still partially implemented ( the SDL1 & GL libraries should be complete).
|
||||
* Implemented specific mecanism for SDL(1/2) RWops, to be able to used them both in Native and x86 world.
|
||||
* WorldOfGoo works, but is painfully slow on the Pandora platform (there is too much double math, and lack of JIT).
|
||||
* FTL works, but sound is broken (issue with thread? asound? or CPU core?)
|
||||
* Limbo launches but crashes before main menu.
|
||||
|
||||
Executable
+120
@@ -0,0 +1,120 @@
|
||||
Compiling
|
||||
----
|
||||
#### for Pandora
|
||||
|
||||
`mkdir build; cd build; cmake .. -DPANDORA=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make`
|
||||
|
||||
#### for Pyra
|
||||
|
||||
`mkdir build; cd build; cmake .. -DPYRA=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make`
|
||||
|
||||
#### for Gameshell
|
||||
|
||||
`mkdir build; cd build; cmake .. -DGAMESHELL=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make`
|
||||
|
||||
#### for Raspberry Pi
|
||||
|
||||
_a build for model 2, 3 and 4 can be done. Model 1 and 0 cannot (at least not with Dynarec, as they lack NEON support)_
|
||||
|
||||
```
|
||||
git clone https://github.com/ptitSeb/box86
|
||||
cd box86
|
||||
mkdir build; cd build; cmake .. -DRPI4=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
make
|
||||
sudo make install
|
||||
sudo systemctl restart systemd-binfmt
|
||||
```
|
||||
Note that you can use `make -j2` or more to speed up 1st build, but beware of the memory requirement if you go to high.
|
||||
|
||||
#### for Raspberry Pi on 64bits OS
|
||||
|
||||
_For Pi4. Change to RPI2 or RPI3 for other models. Change `-DRPI4=1` to `-DRPI4ARM64=1` for compiling on arm64. (armhf multiarch or chroot required alongside armhf gcc. Install it with 'sudo apt install gcc-arm-linux-gnueabihf'.)_
|
||||
|
||||
```
|
||||
git clone https://github.com/ptitSeb/box86
|
||||
cd box86
|
||||
mkdir build; cd build; cmake .. -DRPI4ARM64=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
make -j2
|
||||
sudo make install
|
||||
sudo systemctl restart systemd-binfmt
|
||||
```
|
||||
|
||||
#### for ODROID
|
||||
|
||||
`mkdir build; cd build; cmake .. -DODROID=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j3`
|
||||
|
||||
#### for RK3399
|
||||
|
||||
`mkdir build; cd build; cmake .. -DRK3399=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j3`
|
||||
|
||||
As most RK3399 device run AARCH64 OS, you'll need an `armhf` multiarch environment, and an armhf gcc: On debian, install it with `sudo apt install gcc-arm-linux-gnueabihf`.
|
||||
|
||||
#### for Tinker Board (1/1S) or RK3288
|
||||
|
||||
`mkdir build; cd build; cmake .. -DRK3288=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j3`
|
||||
|
||||
#### for Allwinner A64
|
||||
|
||||
`mkdir build; cd build; cmake .. -DA64=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j3`
|
||||
|
||||
As most Allwinner A64 device run AARCH64 OS, you'll need an `armhf` multiarch environment, and an armhf gcc: On debian, install it with `sudo apt install gcc-arm-linux-gnueabihf`.
|
||||
|
||||
#### for Snapdragon 845
|
||||
|
||||
`mkdir build; cd build; cmake .. -DSD845=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j4`
|
||||
|
||||
As most Snapdragon 845 device run AARCH64 OS, in most cases you'll need an `armhf` multiarch environment, and an armhf gcc: On mobian, install it with `sudo apt install gcc-arm-linux-gnueabihf`.
|
||||
|
||||
#### for Phytium
|
||||
|
||||
`mkdir build; cd build; cmake .. -DPHYTIUM=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j4`
|
||||
|
||||
As most Phytium (D2000 or FT2000/4) device run AARCH64 OS, you'll need an `armhf` multiarch environment, and an armhf gcc: On debian/ubuntu, install it with `sudo apt install gcc-arm-linux-gnueabihf`.
|
||||
|
||||
#### for Other ARM Linux platforms
|
||||
|
||||
`mkdir build; cd build; cmake .. -DARM_DYNAREC=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j3`
|
||||
|
||||
#### for x86 Linux
|
||||
|
||||
`mkdir build; cd build; cmake .. -DCMAKE_C_FLAGS="-m32" -DLD80BITS=1 -DNOALIGN=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo; make -j3`
|
||||
|
||||
#### use ccmake
|
||||
|
||||
Alternatively, you can use the curses-bases ccmake (or any other gui frontend for cmake) to select wich platform to use interactively.
|
||||
|
||||
#### Customize your build
|
||||
|
||||
*use ccache if you have it*
|
||||
|
||||
Add `-DUSE_CCACHE=1` if you have ccache (it's better if you plan to touch the sources)
|
||||
|
||||
*have some debug info*
|
||||
|
||||
The `-DCMAKE_BUILD_TYPE=RelWithDebInfo` argument makes a build that is both optimized for speed, and has debug information embedded. That way, if you have a crash or try to analyse performance, you'll have some symbols.
|
||||
|
||||
*to have a Trace Enabled build*
|
||||
|
||||
To have a trace enabled build ( ***it will be slower***), add `-DHAVE_TRACE=1` but you will need, at runtime, to have the [Zydis library](https://github.com/zyantific/zydis) library in your `LD_LIBRARY_PATH` or in the system library folders.
|
||||
|
||||
*to have ARM Dynarec*
|
||||
|
||||
The Dynarec is only available on the ARM architecture(Right now, anyways.). Notes also that VFPv3 and NEON are required for the Dynarec. Activate it by using `-DARM_DYNAREC=1`. Also, be sure to use `-marm` in compilation flags (because many compileur use Thumb as default, and the dynarec will not work in this mode). Note that compiling with `ARM_DYNAREC` but without hardware profile is not advise. If you get error building that "target CPU does not support ARM mode", then try to pick hardware profile (like ODROID for armv7 or PI4 for armv8). Also, if you are using a 64bits with armhf multiarch, it's much easier to pick one of the hardware profile like `RPI4ARM64`, `RK3399`, `PHYTIUM` or `SD845`.
|
||||
|
||||
*not building from a git clone*
|
||||
|
||||
If you are not building from a git clone (for example, downloading a release source zipped from github), you need to activate `-DNOGIT=1` from cmake to be able to build (normal process include git sha1 of HEAD in the version that box86 print).
|
||||
|
||||
----
|
||||
|
||||
Testing
|
||||
----
|
||||
A few tests are included.
|
||||
They can be launched with `ctest`
|
||||
They are very basic and don't test much for now.
|
||||
|
||||
----
|
||||
|
||||
Note about devices with Tegra X1 and newer.
|
||||
|
||||
Nvidia don't provide armhf libraries for their GPU drivers at this moment so there is no special variable to compile it for them as it would be missleading for many people. If you still want to use it wihout GPU acceleration, building it with RPI4 configuration should work just fine. As instalation of Mesa can break Nvidia driver, safest option is usage of chroot.
|
||||
Executable
+126
@@ -0,0 +1,126 @@
|
||||
# box86
|
||||
|
||||

|
||||
Linux Userspace x86 Emulator with a twist
|
||||
|
||||
[](https://app.travis-ci.com/ptitSeb/box86)
|
||||
|
||||
----
|
||||
|
||||
Compiling/Installation
|
||||
----
|
||||
> Compilation instructions can be found [here](COMPILE.md)
|
||||
> Instructions for installing Wine for Box86 can be found [here](X86WINE.md)
|
||||
|
||||
Box86 lets you run x86 Linux programs (such as games) on non-x86 Linux systems, like ARM (host system needs to be 32bit little-endian).
|
||||
|
||||
You *NEED* a 32-bit subsystem to run and build Box86. Box86 is useless on 64-bit only systems. Also, you *NEED* a 32-bit toolchain to build Box86. A toolchain that only supports 64-bit will not compile Box86, and you'll get errors (typically on aarch64, you get "-marm" not recognized, and you'll need a multiarch or chroot environnement).
|
||||
|
||||
Because Box86 uses the native versions of some "system" libraries, like libc, libm, SDL, and OpenGL, it's easy to integrate and use with most applications, and performance can be surprisingly high in many cases. Take a look at thoses bench analysis for an example [here](https://box86.org/index.php/2021/06/game-performances/).
|
||||
|
||||
Most x86 Games need OpenGL, so on ARM platforms a solution like [gl4es](https://github.com/ptitSeb/gl4es) is usually necessary. (Most ARM platforms only support OpenGL ES and/or their OpenGL implementation is dodgy (see OpenGL on Android).)
|
||||
|
||||
Box86 now integrates a DynaRec (dynamic recompiler) for the ARM platform, providing a speed boost between 5 to 10 times faster than only using the interpreter. Some high level information on how the Dynarec work can be found [here](https://box86.org/2021/07/inner-workings-a-high%e2%80%91level-view-of-box86-and-a-low%e2%80%91level-view-of-the-dynarec/).
|
||||
|
||||
Many games already work without much tweaking, for example: WorldOfGoo, Airline Tycoon Deluxe, and FTL. Many of the GameMaker Linux games also run fine. (there's a long list, among them are UNDERTALE, A Risk of Rain, and Cook Serve Delicious)
|
||||
|
||||
If you are serious about developing Box86, you should install ccache and build Box86 with it. (Use ccmake for example.)
|
||||
To enable TRACE (i.e. dumping to stdout all individual x86 instructions executed, with dump of registers), you'll also need [Zydis library](https://github.com/zyantific/zydis) available on your system.
|
||||
|
||||
Some x86 internal opcodes use parts of "Realmode X86 Emulator Library", see [x86primop.c](../src/emu/x86primop.c) for copyright details
|
||||
|
||||
Here's 6 videos, the first 2 videos are videos of "Airline Tycoon Deluxe" and "Heretic 2" running on a GigaHertz OpenPandora (the second one is using the dynarec), and the next 2 videos are videos of of "Bit.Trip.Runner" and "Neverwinter Night" running on an ODroid XU4 (without dynarec), and the last 2 videos are on on a Pi4: Shovel Knight (video from @ITotalJustice) and Freedom Planet (video from @djazz), also without dynarec.
|
||||
|
||||
[](https://www.youtube.com/watch?v=bLt0hMoFDLk) [](https://www.youtube.com/watch?v=MM7kWYts7IA) [](https://www.youtube.com/watch?v=8hr71S029Hg) [](https://www.youtube.com/watch?v=B4YN37z3-ws) [](https://www.youtube.com/watch?v=xk8Q30mxqPg) [](https://www.youtube.com/watch?v=_QMRMVvYrqU)
|
||||
|
||||
You can find many more Box86 video on Youtube in the [MicroLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ), [Pi Labs](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g) or [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA) Channels
|
||||
|
||||
Compatibility list is there: https://github.com/ptitSeb/box86-compatibility-list/issues
|
||||
|
||||
<img src="img/Box86Icon.png" width="96" height="96">
|
||||
|
||||
Logo and Icon made by @grayduck, thanks!
|
||||
|
||||
Note that this project is not to be mistaken with [86box](https://github.com/86Box/86Box), a nice "Full system" emulator specialized in early (to fairly recent) PC hardware.
|
||||
|
||||
----
|
||||
|
||||
Usage
|
||||
----
|
||||
|
||||
There are a few environment variables to control the behaviour of Box86.
|
||||
|
||||
See [here](USAGE.md) for all environment variables and what they do.
|
||||
|
||||
Note: Box86's Dynarec uses a mechanism with Memory Protection and a SegFault signal handler to handle JIT code. In simpler terms, if you want to use GDB to debug a running program that use JIT'd code (like mono/Unity3D), you will still have many "normal" segfaults triggering. It is suggested to use something like `handle SIGSEGV nostop` in GDB to not stop at each segfault, and maybe put a breakpoint inside `my_memprotectionhandler` in `signals.c` if you want to trap SegFaults.
|
||||
|
||||
----
|
||||
|
||||
Version history
|
||||
----
|
||||
|
||||
The change log is available [here](CHANGELOG.md)
|
||||
|
||||
----
|
||||
|
||||
Notes about 64-bit platforms
|
||||
----
|
||||
|
||||
Because Box86 works by directly translating function calls from x86 to host system, the host system (the one Box86 is running on) needs to have 32-bit libraries. Box86 doesn't include any 32-bit <-> 64-bit translation. So basically, to run Box86 on, for example, an ARM64 platform, you will need to build Box86 for ARM 32-bit, and also need to have a chroot with 32-bit libraries.
|
||||
|
||||
If you look at a 64bits version of box86, look at [Box64](https://github.com/ptitSeb/box64): this one is able to run x86_64 binaries on 64-bit platforms. But note that you still need Box86 (and a 32-bit chroot) to run x86 binaries (as it also happens on actual x86_64 Linux that need x86 libs and binary on multiarch to run).
|
||||
|
||||
----
|
||||
|
||||
Notes about Unity game emulation
|
||||
----
|
||||
|
||||
Running Unity games is a hit or miss for now. Unity uses Mono (which uses signals that are not well emulated enough), and a runtime embedded in the main binary. A solution would be to use a native version of the libmono library used by Unity (it can be found here: https://github.com/Unity-Technologies/mono and needs to be built from source). But the wrapping of this lib is tricky, and not done for now, so the only solution is to emulate everything. The tricky part is to emulate the "JIT" code emitted by Mono, however with the new "protected memory" mechanism implemented it should be running with correct performance now.
|
||||
You should also note that some Unity3D games require OpenGL 3+ which can be tricky to provide on ARM SBC (single-board computers) for now.
|
||||
|
||||
TL;DR: Not all Unity games work and can require a high OpenGL profile, but the speed, for the ones running, should be correct now.
|
||||
|
||||
----
|
||||
|
||||
Notes about Steam
|
||||
----
|
||||
|
||||
Linux Steam's can run now with box86. But it's still a bit unstable, and not everything works:
|
||||
- First problem is Steam crashing after the sign-in window, if you encounter this issue, you may need to add libappindicator. To install it on Debian, run `sudo apt install libappindicator1`.
|
||||
- If you select to "Remember password", Steam is crashing on subsequent starts, unless you have libnm intalled. To install it on Debian, run `sudo apt install libnm0`.
|
||||
- Once open, Steam will only work on "Small Mode" and in "Big Picture", not in the regular "Large Mode". This is because some Steam components used in the browser view are only 64-bit now. So go in the "View" menu and switch to "Small view", else the list will stay empty. Alternatively, Steam can be started in small mode directly by using `+open steam://open/minigameslist` command line arguments.
|
||||
- To avoid the "libc.so.6 is absent" message, you can use `STEAMOS=1` and `STEAM_RUNTIME=1` as environment variables.
|
||||
- Some Steam games (most Source engine games, like "Portal" or "Half-Life 2") use libtcmalloc. Box86 will detect it and will try to LD_PRELOAD it, for better compatibility. While it should work without the aformentionned feature, it is safer to add it to your system if you intend to play those game. To install it on Debian, run `sudo apt install libtcmalloc-minimal4`.
|
||||
|
||||
Steam for Windows installs fine but doesn't work yet.
|
||||
|
||||
----
|
||||
|
||||
Notes about Wine
|
||||
----
|
||||
|
||||
Wine is now supported. Wine integrated program all runs, and many windows programs and games also runs fine. Don't forget most Windows games use Direct3D, this may require a complete OpenGL driver and a as high profile as possible (and gl4es with ES2 backend have issue with Wine for now).
|
||||
Note: if you plan to use box86 with Wine on Raspberry Pi 3 or earlier, those models use a default OS that have a kernel with a 2/2 Split (meaning 2G of space for user program, and 2G of space for the Kernel). This is not compatible with Wine programs that needs to access memory > 2Gb address. So you'll need to reconfigure your kernel for a 3G/1G split.
|
||||
|
||||
----
|
||||
|
||||
Notes about Vulkan
|
||||
----
|
||||
|
||||
Box86 already wrap vulikan. If your system has a 32bits vulkan driver, box86 will use it when needed. Note that vulkan wrapping has not been tested much, due to the limited vulkan support on the hardware I currently own. Profile 1.0 and 1.1, whith some extension, should be OK. 1.2 is not really wrapped. I know some demos work on Pi4 (Sascha Willems demos build for x86 work the same as if build on armhf directly). Note that the Vulkan driver of the Pi4 DOES NOT support dxvk for now (wine DirectX->Vulkan wrapper). It's not a box86 issue, it's missing extensions (hardxware support) and a few other things that make dxvk not working on pi4. On Panfrost side, PanVK is a bit young and I haven't tested dxvk with it yet.
|
||||
|
||||
----
|
||||
Final word
|
||||
----
|
||||
|
||||
I want to thank everyone who has contributed to box86 developpement.
|
||||
There are many ways to contribute: code, financial, hardware and advertisement!
|
||||
So, in no particular order, I want to thank:
|
||||
* For their major code contribution: rajdakin, icecream95, M-HT
|
||||
* For their major financial contribution: FlyingFathead, stormchaser3000
|
||||
* For their hardware contribution: [Radxa](https://rockpi.org/), [Pine64](https://www.pine64.org/), [DragonBox](https://pyra-handheld.com/), [Novaspirit](https://www.youtube.com/channel/UCrjKdwxaQMSV_NDywgKXVmw), [HardKernel](https://www.hardkernel.com/), [TwisterOS team](https://twisteros.com/)
|
||||
* For their continous advertisement of box86 project: salva ([microLinux](https://www.youtube.com/channel/UCwFQAEj1lp3out4n7BeBatQ)), [PILab](https://www.youtube.com/channel/UCgfQjdc5RceRlTGfuthBs7g)/[TwisterOS team](https://twisteros.com/), [The Byteman](https://www.youtube.com/channel/UCEr8lpIJ3B5Ctc5BvcOHSnA), [NicoD](https://www.youtube.com/channel/UCpv7NFr0-9AB5xoklh3Snhg)
|
||||
|
||||
And I also thank the many other people who participated even once in the project.
|
||||
|
||||
(If you use Box86 in your project, please don't forget to mention it!)
|
||||
Executable
+178
@@ -0,0 +1,178 @@
|
||||
|
||||
Usage
|
||||
----
|
||||
|
||||
There are many environment variables to control Box86 behaviour.
|
||||
|
||||
#### BOX86_LOG
|
||||
Controls the Verbosity level of the logs
|
||||
* 0: NONE : No message (except some fatal error). (Default.)
|
||||
* 1: INFO : Show some minimum log (Example: librairies not found)
|
||||
* 2: DEBUG : Details a lot of stuff (Example: relocations or functions called).
|
||||
* 3: DUMP : All DEBUG plus DUMP of all ELF Info (so same as `BOX86_LOG=2 BOX86_DUMP=1`)
|
||||
|
||||
#### BOX86_DUMP
|
||||
Controls the Dump of elf content
|
||||
* 0: No dump of elf information (Default)
|
||||
* 1: Dump elf sections and relocations and other information (also active if using `BOX86_LOG=3`)
|
||||
|
||||
#### BOX86_NOBANNER
|
||||
Disables Box86 printing its version and build
|
||||
* 0 : Enable printing its banner. (Default.)
|
||||
* 1 : Disable printing its banner.
|
||||
|
||||
#### BOX86_LD_LIBRARY_PATH
|
||||
Path to look for x86 libraries. Default is current folder and `lib` in current folder.
|
||||
Also, `/usr/lib/i386-linux-gnu` and `/lib/i386-linux-gnu` are added if they exist.
|
||||
|
||||
#### BOX86_PATH
|
||||
Path to look for x86 executable. Default is current folder and `bin` in current folder.
|
||||
|
||||
#### BOX86_DLSYM_ERROR
|
||||
Enables/Disables the logging of `dlsym` errors.
|
||||
* 0 : Don't log `dlsym` errors. (Default.)
|
||||
* 1 : Log dlsym errors.
|
||||
|
||||
#### BOX86_TRACE_FILE
|
||||
Send all log and trace to a file instead of `stdout`
|
||||
Also, if name contains `%pid` then this is replaced by the actual PID of box86 instance
|
||||
Use `stderr` to use this instead of default `stdout`
|
||||
|
||||
#### BOX86_TRACE
|
||||
Only on build with trace enabled. Trace allow the logging of all instruction executed, along with register dump
|
||||
* 0 : No trace. (Default.)
|
||||
* 1 : Trace enabled. Trace start after the initialisation of all depending libraries is done.
|
||||
* symbolname : Trace only `symbolname` (trace is disable if the symbol is not found).
|
||||
* 0xXXXXXXX-0xYYYYYYY : Trace only between the 2 addresses.
|
||||
|
||||
#### BOX86_TRACE_INIT
|
||||
Use BOX86_TRACE_INIT instead of BOX_TRACE to start trace before the initialisation of libraries and the running program
|
||||
* 0 : No trace. (Default.)
|
||||
* 1 : Trace enabled. The trace start with the initialisation of all depending libraries is done.
|
||||
|
||||
#### BOX86_TRACE_START
|
||||
Only on builds with trace enabled.
|
||||
* NNNNNNN : Start trace only after NNNNNNNN opcode execute (number is an `uint64_t`).
|
||||
|
||||
#### BOX86_TRACE_XMM
|
||||
Only on builds with trace enabled.
|
||||
* 0 : The XMM (i.e. SSE/SSE2) register will not be logged with the general and x86 registers. (Default.)
|
||||
* 1 : Dump the XMM registers.
|
||||
|
||||
#### BOX86_LOAD_ADDR
|
||||
Try to load at 0xXXXXXX main binary (if binary is a PIE)
|
||||
* 0xXXXXXXXX : The load address . (Only active on PIE programs.)
|
||||
|
||||
#### BOX86_NOSIGSEGV
|
||||
Disable handling of SigSEGV. (Very useful for debugging.)
|
||||
* 0 : Let the x86 program set sighandler for SEGV (Default.)
|
||||
* 1 : Disable the handling of SigSEGV.
|
||||
|
||||
#### BOX86_NOSIGILL
|
||||
Disable handling of SigILL (to ease debugging mainly).
|
||||
* 0 : Let x86 program set sighandler for Illegal Instruction
|
||||
* 1 : Disables the handling of SigILL
|
||||
|
||||
#### BOX86_X11COLOR16
|
||||
PANDORA only: Try converting X11 color from 32 bits to 16 bits (to avoid light green on light cyan windows).
|
||||
* 0 : Don't touch X11 colors. (Default.)
|
||||
* 1 : Change colors arguments in XSetForeground, XSetBackground and XCreateGC.
|
||||
|
||||
#### BOX86_X11THREADS
|
||||
Call XInitThreads when loading X11. (This is mostly for old Loki games with the Loki_Compat library.)
|
||||
* 0 : Don't force call XInitThreads. (Default.)
|
||||
* 1 : Call XInitThreads as soon as libX11 is loaded.
|
||||
|
||||
#### BOX86_X11GLX
|
||||
Force libX11's GLX extension to be present.
|
||||
* 0 : Do not force libX11's GLX extension to be present.
|
||||
* 1 : GLX will always be present when using XQueryExtension. (Default.)
|
||||
|
||||
#### BOX86_DYNAREC_DUMP
|
||||
Enables/disables Box86's Dynarec's dump.
|
||||
* 0 : Disable Dynarec's blocks dump. (Default.)
|
||||
* 1 : Enable Dynarec's blocks dump.
|
||||
* 2 : Enable Dynarec's blocks dump with some colors.
|
||||
|
||||
#### BOX86_DYNAREC_LOG
|
||||
Set the level of DynaRec's logs.
|
||||
* 0 : NONE : No Logs for DynaRec. (Default.)
|
||||
* 1 :INFO : Minimum Dynarec Logs (only unimplemented OpCode).
|
||||
* 2 : DEBUG : Debug Logs for Dynarec (with details on block created / executed).
|
||||
* 3 : VERBOSE : All of the above plus more.
|
||||
|
||||
#### BOX86_DYNAREC
|
||||
Enables/Disables Box86's Dynarec.
|
||||
* 0 : Disables Dynarec.
|
||||
* 1 : Enable Dynarec. (Default.)
|
||||
|
||||
#### BOX86_DYNAREC_TRACE
|
||||
Enables/Disables trace for generated code.
|
||||
* 0 : Disable trace for generated code. (Default.)
|
||||
* 1 : Enable trace for generated code (like regular Trace, this will slow down the program a lot and generate huge logs).
|
||||
|
||||
#### BOX86_NODYNAREC
|
||||
Forbid dynablock creation in the interval specified (helpfull for debugging behaviour difference between Dynarec and Interpretor)
|
||||
* 0xXXXXXXXX-0xYYYYYYYY : define the interval where dynablock cannot start (inclusive-exclusive)
|
||||
|
||||
#### BOX86_DYNAREC_BIGBLOCK
|
||||
Enables/Disables Box86's Dynarec building BigBlock.
|
||||
* 0 : Don't try to build block as big as possible (can help program using lots of thread and a JIT, like C#/Unity) (Default when libmonobdwgc-2.0.so is loaded)
|
||||
* 1 : Build Dynarec block as big as possible (Default.)
|
||||
|
||||
#### BOX86_DYNAREC_STRONGMEM
|
||||
Enable/Disable simulation of Strong Memory model
|
||||
* 0 : Don't try anything special (Default.)
|
||||
* 1 : Enable some Memory Barrier when reading from memory (on some MOV opcode) to simulate Strong Memory Model while trying to limit performance impact (Default when libmonobdwgc-2.0.so is loaded)
|
||||
* 2 : Enable some Memory Barrier when reading from memory (on some MOV opcode) to simulate Strong Memory Model
|
||||
|
||||
#### BOX86_LIBGL
|
||||
* libXXXX set the name for libGL (defaults to libGL.so.1).
|
||||
* /PATH/TO/libGLXXX : Sets the name and path for libGL
|
||||
You can also use SDL_VIDEO_GL_DRIVER
|
||||
|
||||
#### BOX86_LD_PRELOAD
|
||||
* XXXX[:YYYYY] force loading XXXX (and YYYY...) libraries with the binary
|
||||
PreLoaded libs can be emulated or native, and are treated the same way as if they were comming from the binary
|
||||
|
||||
#### BOX86_EMULATED_LIBS
|
||||
* XXXX[:YYYYY] force lib XXXX (and YYYY...) to be emulated (and not wrapped)
|
||||
Some games uses an old version of some libraries, with an ABI incompatible with native version.
|
||||
Note that LittleInferno for example is auto detected, and libvorbis.so.0 is automatical added to emulated libs, and same for Don't Starve (and Together / Server variant) that use an old SDL2 too
|
||||
|
||||
#### BOX86_ALLOWMISSINGLIBS
|
||||
Allow Box86 to continue even if a library is missing.
|
||||
* 0 : Box86 will stop if a library cannot be loaded. (Default.)
|
||||
* 1 : Continue even if a needed library cannot be loaded. Unadvised, this will, in most cases, crash later on.
|
||||
|
||||
#### BOX86_NOPULSE
|
||||
Disables the load of pulseaudio libraries.
|
||||
* 0 : Load pulseaudio libraries if found. (Default.)
|
||||
* 1 : Disables the load of pulse audio libraries (libpulse and libpulse-simple), both the native library and the x86 library
|
||||
|
||||
#### BOX86_NOGTK
|
||||
Disables the loading of wrapped GTK libraries.
|
||||
* 0 : Load wrapped GTK libraries if found. (Default.)
|
||||
* 1 : Disables loading wrapped GTK libraries (can be used with Steam, along with STEAM_RUNTIME=1 to use the i386 version of GTK).
|
||||
|
||||
#### BOX86_NOVULKAN
|
||||
Disables the load of vulkan libraries.
|
||||
* 0 : Load vulkan libraries if found.
|
||||
* 1 : Disables the load of vulkan libraries, both the native and the i386 version (can be useful on Pi4, where the vulkan driver is not quite there yet.)
|
||||
|
||||
#### BOX86_FIX_64BIT_INODES
|
||||
Fix/Don't fix 64bit inodes
|
||||
* 0 : Don't fix 64bit inodes. (Default.)
|
||||
* 1 : Fix 64bit inodes. Helps when running on Filesystems with 64bit inodes. Is useful when a program uses API functions which doesn't support it and the program doesn't use inodes information.
|
||||
|
||||
#### BOX86_JITGDB
|
||||
|
||||
* 0 : Just print the Segfault message on segfault (default)
|
||||
* 1 : Launch `gdb` when a segfault, bus error or illegal instruction signal is trapped, attached to the offending process and go in an endless loop, waiting.
|
||||
When in gdb, you need to find the correct thread yourself (the one with `my_box86signalhandler` in is stack)
|
||||
then probably need to `finish` 1 or 2 functions (inside `usleep(..)`) and then you'll be in `my_box86signalhandler`,
|
||||
just before the printf of the Segfault message. Then simply
|
||||
`set waiting=0` to exit the infinite loop.
|
||||
* 2 : Launch `gdbserver` when a segfault, bus error or illegal instruction signal is trapped, attached to the offending process, and go in an endless loop, waiting.
|
||||
Use `gdb /PATH/TO/box86` and then `target remote 127.0.0.1:1234` to connect to the gdbserver (or use actual IP if not on the machine). After that, the procedure is the same as with ` BOX86_JITGDB=1`.
|
||||
This mode can be usefullwhen programs redirect all console output to a file (like Unity3D Games)
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
# Installing Wine (and winetricks)
|
||||
_TwisterOS users: Wine, winetricks, and Box86 are already installed in TwisterOS. You do not have to install anything._
|
||||
|
||||
_Raspberry Pi users: Wine requires a 3G/1G split memory kernel. Raspberry Pi OS for the Pi 4 already has a 3G/1G split kernel and works with Wine, but **the Pi 3B+ and earlier models have a 2G/2G kernel and require a custom-compiled 3G/1G kernel to get Wine working.**_
|
||||
|
||||
Using Wine with Box86 allows (x86) Windows programs to run on ARM Linux computers (x64 is not yet implemented).
|
||||
See installation steps below (in the [Examples](#examples) section).
|
||||
|
||||
Box86 needs `wine-i386` to be installed **manually** on ARM devices. Even though `wine-armhf` is available in many repo's on ARM devices (ie using _apt-get_ will attempt to install `wine-armhf` by default), `wine-armhf` will not work with Box86. Note that manual installation is required since using `multiarch` will result in your ARM device thinking it needs to install lots of i386 dependencies to make `wine-i386` work. The "twist" in Box86 is that Box86 "wraps" many of Wine's core Linux i386 libraries (.so files) so that their calls are interpretable by your ARM devices other armhf Linux system libraries. Also note that wrapping libraries is an ongoing process throughout Box86 development and that some programs may not run properly until all of their i386 library dependencies are wrapped.
|
||||
|
||||
Installation files for Wine can be found in the [WineHQ repository](https://dl.winehq.org/wine-builds/debian/dists/buster/main/binary-i386/), the [TwisterOS FAQ](https://twisteros.com/faq.html) page, or the [PlayOnLinux website repository](https://www.playonlinux.com/wine/). Box86 requires the "i386" (x86) version of Wine even though we are installing it on an ARM processor.
|
||||
|
||||
## Overview
|
||||
The general procedure for installing Wine for Box86 is to...
|
||||
- Download all the install files (.deb, .zip, or even .pol files) for the version of Wine you wish to install
|
||||
- Unzip or dpkg the install files into one folder
|
||||
- Move that folder to the directory that you wish Wine to run from (in TwisterOS, this is `~/wine/` by default)
|
||||
- Go to `/usr/local/bin` and make symlinks or scripts that will point to your main wine binaries (`wine`, `winecfg`, and `wineserver`).
|
||||
- Boot wine to create a new wineprefix (`wine wineboot`).
|
||||
- Download winetricks (which is simply a very complicated bash script), make it executable, then copy it to `/usr/local/bin`.
|
||||
|
||||
## Examples
|
||||
### Installing Wine for Box86 on Raspberry Pi OS from Twister OS FAQ .tgz files
|
||||
_Links from the [TwisterOS FAQ](https://twisteros.com/faq.html)_
|
||||
|
||||
This installs Wine v5.13 (which is the version of Wine that comes pre-installed in TwisterOS). When submitting bug reports, other Box86 users may assume you are using this version of Wine unless you specify otherwise.
|
||||
```
|
||||
# Backup any old wine installations
|
||||
sudo mv ~/wine ~/wine-old
|
||||
sudo mv ~/.wine ~/.wine-old
|
||||
sudo mv /usr/local/bin/wine /usr/local/bin/wine-old
|
||||
sudo mv /usr/local/bin/wineboot /usr/local/bin/wineboot-old
|
||||
sudo mv /usr/local/bin/winecfg /usr/local/bin/winecfg-old
|
||||
sudo mv /usr/local/bin/wineserver /usr/local/bin/wineserver-old
|
||||
|
||||
# Download, extract wine, and install wine (last I checked, the Twister OS FAQ page had Wine 5.13-devel)
|
||||
wget https://twisteros.com/wine.tgz -O ~/wine.tgz
|
||||
tar -xzvf ~/wine.tgz
|
||||
rm ~/wine.tgz # clean up
|
||||
|
||||
# Install shortcuts (make launcher & symlinks. Credits: grayduck, Botspot)
|
||||
echo -e '#!/bin/bash\nsetarch linux32 -L '"$HOME/wine/bin/wine "'"$@"' | sudo tee -a /usr/local/bin/wine >/dev/null # Create a script to launch wine programs as 32bit only
|
||||
#sudo ln -s ~/wine/bin/wine /usr/local/bin/wine # You could aslo just make a symlink, but box86 only works for 32bit apps at the moment
|
||||
sudo ln -s ~/wine/bin/wineboot /usr/local/bin/wineboot
|
||||
sudo ln -s ~/wine/bin/winecfg /usr/local/bin/winecfg
|
||||
sudo ln -s ~/wine/bin/wineserver /usr/local/bin/wineserver
|
||||
sudo chmod +x /usr/local/bin/wine /usr/local/bin/wineboot /usr/local/bin/winecfg /usr/local/bin/wineserver
|
||||
|
||||
# Boot wine (make fresh wineprefix in ~/.wine )
|
||||
wine wineboot
|
||||
```
|
||||
|
||||
### Installing Wine for Box86 on Raspberry Pi OS Buster from WineHQ .deb files
|
||||
_Links from the [WineHQ repo](https://dl.winehq.org/wine-builds/debian/dists/buster/main/binary-i386/)_
|
||||
|
||||
This install method allows you to install different versions of Wine. You may install any version and any branch of Wine that you wish (wine-devel, wine-stable, or wine-staging).
|
||||
```
|
||||
# Backup any old wine installations
|
||||
sudo mv ~/wine ~/wine-old
|
||||
sudo mv ~/.wine ~/.wine-old
|
||||
sudo mv /usr/local/bin/wine /usr/local/bin/wine-old
|
||||
sudo mv /usr/local/bin/wineboot /usr/local/bin/wineboot-old
|
||||
sudo mv /usr/local/bin/winecfg /usr/local/bin/winecfg-old
|
||||
sudo mv /usr/local/bin/wineserver /usr/local/bin/wineserver-old
|
||||
|
||||
# Download, extract wine, and install wine
|
||||
# (Replace the links/versions below with links/versions from the WineHQ site for the version of wine you wish to install. Note that we need the i386 version for Box86 even though we're installing it on our ARM processor.)
|
||||
# (Pick an i386 version of wine-devel, wine-staging, or wine-stable)
|
||||
cd ~/Downloads
|
||||
wget https://dl.winehq.org/wine-builds/debian/dists/buster/main/binary-i386/wine-devel-i386_5.21~buster_i386.deb # NOTE: Replace this link with the version you want
|
||||
wget https://dl.winehq.org/wine-builds/debian/dists/buster/main/binary-i386/wine-devel_5.21~buster_i386.deb # NOTE: Also replace this link with the version you want
|
||||
dpkg-deb -xv wine-devel-i386_5.21~buster_i386.deb wine-installer # NOTE: Make sure these dpkg command matches the filename of the deb package you just downloaded
|
||||
dpkg-deb -xv wine-devel_5.21~buster_i386.deb wine-installer
|
||||
mv ~/Downloads/wine-installer/opt/wine* ~/wine
|
||||
rm wine*.deb # clean up
|
||||
rm -rf wine-installer # clean up
|
||||
|
||||
# Install shortcuts (make 32bit launcher & symlinks. Credits: grayduck, Botspot)
|
||||
echo -e '#!/bin/bash\nsetarch linux32 -L '"$HOME/wine/bin/wine "'"$@"' | sudo tee -a /usr/local/bin/wine >/dev/null # Create a script to launch wine programs as 32bit only
|
||||
#sudo ln -s ~/wine/bin/wine /usr/local/bin/wine # You could aslo just make a symlink, but box86 only works for 32bit apps at the moment
|
||||
sudo ln -s ~/wine/bin/wineboot /usr/local/bin/wineboot
|
||||
sudo ln -s ~/wine/bin/winecfg /usr/local/bin/winecfg
|
||||
sudo ln -s ~/wine/bin/wineserver /usr/local/bin/wineserver
|
||||
sudo chmod +x /usr/local/bin/wine /usr/local/bin/wineboot /usr/local/bin/winecfg /usr/local/bin/wineserver
|
||||
|
||||
# These packages are needed for running wine-staging on RPi 4 (Credits: chills340)
|
||||
sudo apt install libstb0 -y
|
||||
cd ~/Downloads
|
||||
wget -r -l1 -np -nd -A "libfaudio0_*~bpo10+1_i386.deb" http://ftp.us.debian.org/debian/pool/main/f/faudio/ # Download libfaudio i386 no matter its version number
|
||||
dpkg-deb -xv libfaudio0_*~bpo10+1_i386.deb libfaudio
|
||||
sudo cp -TRv libfaudio/usr/ /usr/
|
||||
rm libfaudio0_*~bpo10+1_i386.deb # clean up
|
||||
rm -rf libfaudio # clean up
|
||||
|
||||
# Boot wine (make fresh wineprefix in ~/.wine )
|
||||
wine wineboot
|
||||
```
|
||||
|
||||
## Installing winetricks
|
||||
Winetricks is a bash script which makes it easier to install & configure any desired Windows core system software packages which may be dependencies for certain Windows programs. You can either install it with `apt`, or manually using the steps below.
|
||||
|
||||
```
|
||||
sudo apt-get install cabextract -y # winetricks needs this installed
|
||||
sudo mv /usr/local/bin/winetricks /usr/local/bin/winetricks-old # Backup old winetricks
|
||||
cd ~/Downloads && wget https://raw.githubusercontent.com/Winetricks/winetricks/master/src/winetricks # Download
|
||||
sudo chmod +x winetricks && sudo mv winetricks /usr/local/bin/ # Install
|
||||
```
|
||||
|
||||
Whenever we run winetricks, we must tell Box86 to supress its info banner, otherwise winetricks will crash. Box86's info banner can be suppressed using the `BOX86_NOBANNER=1` environment variable before invoking winetricks (example: `BOX86_NOBANNER=1 winetricks`).
|
||||
|
||||
If `apt` installed a desktop menu shortcut for winetricks (or if you make your own desktop shortcut for winetricks) then you may need to edit that shortcut to include Box86's BOX86_NOBANNER=1 env var. With your favorite text editor, edit `/usr/share/applications/winetricks.desktop` and change `Exec=winetricks --gui` to `Exec=env BOX86_NOBANNER=1 winetricks --gui`.
|
||||
|
||||
## Example commands
|
||||
Here is an example of how we should run a winetricks command with box86:
|
||||
`BOX86_NOBANNER=1 winetricks -q corefonts vcrun2010 dotnet20sp1`
|
||||
_This command will silently install three packages in series: Windows core fonts, VC++ 2010 Runtimes, and .NET 2.0 SP1. `-q` is the "install silent/quiet" command._
|
||||
|
||||
Whenever we run winetricks, we must suppress Box86's banner by typing `BOX86_NOBANNER=1` to prevent winetricks from crashing. Invoking Box86's logging features (with `BOX86_LOG=1` or similar) will also cause winetricks to crash. (If Box86 logging is necessary though, we can patch winetricks to avoid these crashes - see the *Troubleshooting* section) # future work.
|
||||
|
||||
For a list of all the different Windows packages & libraries that winetricks can help you install, run `winetricks list-all`
|
||||
|
||||
## Other notes
|
||||
|
||||
### Wineprefixes (and Wine initialization)
|
||||
When you first run or boot Wine (`wine wineboot`), Wine will create a new user environment within which to install Windows software. This user environment is called a "wineprefix" (or "wine bottle") and is located (by default) in `~/.wine` (note that Linux folders with a `.` in front of them are "hidden" folders). Think of a wineprefix as Wine's virtual 'harddrive' where it installs software and saves settings. Wineprefixes are portable and deletable. For more Wine documentation, see [WineHQ](https://www.winehq.org/documentation).
|
||||
|
||||
If you at any point corrupt something inside your default wineprefix, you can start "fresh" by deleting your `~/.wine` directory (with the `rm -rf ~/.wine` command) and boot wine again to create a new default wineprefix.
|
||||
|
||||
### Transplanting wineprefixes (side-loading)
|
||||
If software isn't installing in Wine with Box86, but is installing for you in Wine on a regular x86 Linux computer, you can copy a wineprefix from your x86 Linux computer to the device you're running Box86 on. This is most easily done by tarring the `~/.wine` folder on your x86 Linux computer (`tar -cvf winebottle.tar ~/.wine`), transferring the tar file to your device, then un-tarring the tar file (`tar -xf winebottle.tar`) on your device running Box86 & Wine. Tarring the wineprefix preserves any symlinks that are inside it.
|
||||
|
||||
### Swapping out different versions of Wine
|
||||
Some versions of Wine work better with certain software. It is best to install a version of Wine that is known to work with the software you would like to run. There are three main development branches of Wine you can pick from, referred to as wine-stable, wine-devel, and wine-staging. _Note that the wine-staging branch requires extra installation steps on Raspberry Pi._
|
||||
|
||||
Your entire Wine installation can reside within a single folder on your Linux computer. TwisterOS assumes that your Wine installation is located inside the `~/wine/` directory. The actual directory where you put your `wine` folder doesn't matter as long as you have symlinks within the `/usr/local/bin/` directory which point to the `wine` folder so that Linux can find Wine when you type `wine` into the terminal).
|
||||
|
||||
You can change which version of Wine you are running simply by renaming your old `wine` and `.wine` folders to something else, then putting a new `wine` folder (containing your new version of Wine) in its place. Running `wine wineboot` again will migrate a wineprefix from an older version of Wine to be usable by the newer version of Wine you just installed. You can check which version of Wine you're running with the `wine --version` command.
|
||||
@@ -0,0 +1 @@
|
||||
theme: jekyll-theme-hacker
|
||||
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 68 KiB |
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 171 KiB |
@@ -0,0 +1,44 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-arm-git
|
||||
pkgver=3494.bedacef
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
url="https://github.com/ptitSeb/box86"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-arm-git}-git" "${pkgname%-arm-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-arm-git}-git" "${pkgname%-arm-git}")
|
||||
source=('git+https://github.com/ptitSeb/box86')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-arm-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-arm-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DARM_DYNAREC=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
fi
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-arm-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-arm-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-gameshell-git
|
||||
pkgver=3494.bedacef
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
url="https://github.com/ptitSeb/box86"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-gameshell-git}-git" "${pkgname%-gameshell-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-gameshell-git}-git" "${pkgname%-gameshell-git}")
|
||||
source=('git+https://github.com/ptitSeb/box86')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-gameshell-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-gameshell-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DGAMESHELL=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
fi
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-gameshell-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-gameshell-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-odroid-git
|
||||
pkgver=3494.bedacef
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
url="https://github.com/ptitSeb/box86"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-odroid-git}-git" "${pkgname%-odroid-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-odroid-git}-git" "${pkgname%-odroid-git}")
|
||||
source=('git+https://github.com/ptitSeb/box86')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-odroid-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-odroid-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DODROID=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
fi
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-odroid-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-odroid-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-pandora-git
|
||||
pkgver=3494.bedacef
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
url="https://github.com/ptitSeb/box86"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-pandora-git}"-git "${pkgname%-pandora-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-pandora-git}"-git "${pkgname%-pandora-git}")
|
||||
source=('git+https://github.com/ptitSeb/box86')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-pandora-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-pandora-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DPANDORA=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
fi
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-pandora-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-pyra-git
|
||||
pkgver=3494.bedacef
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
url="https://github.com/ptitSeb/box86"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-pyra-git}-git" "${pkgname%-pyra-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-pyra-git}-git" "${pkgname%-pyra-git}")
|
||||
source=('git+https://github.com/ptitSeb/box86')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-pyra-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-pyra-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DPYRA=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
fi
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-pyra-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-pyra-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-rpi-git
|
||||
pkgver=3494.bedacef
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
url="https://github.com/ptitSeb/box86"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-rpi-git}-git" "${pkgname%-rpi-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-rpi-git}-git" "${pkgname%-rpi-git}")
|
||||
source=('git+https://github.com/ptitSeb/box86')
|
||||
md5sums=('SKIP')
|
||||
_pimodel=`tr -d '\0' < /sys/firmware/devicetree/base/model`
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-rpi-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-rpi-git}"
|
||||
# Check for Pi version number
|
||||
if [[ ${_pimodel} =~ "Raspberry Pi 4" ]]; then
|
||||
_piversion=4
|
||||
elif [[ ${_pimodel} =~ "Raspberry Pi 3" ]]; then
|
||||
_piversion=3
|
||||
elif [[ ${_pimodel} =~ "Raspberry Pi 2" ]]; then
|
||||
_piversion=2
|
||||
else
|
||||
# This RPI is not supported or this device is not a pi.
|
||||
# We should cancel then the build.
|
||||
echo -e "\033[01m\033[01;31m==> ERROR:\033[00;01m Your device is not supported! This script is for RPi model 4/3/2 (1/0 isn't supported yet).\033[00m"
|
||||
exit 1
|
||||
fi
|
||||
echo -e "\033[01m\033[01;34m==> INFO:\033[00;01m Your detected Pi verion number is: \033[01;31m${_piversion}\033[01m.\033[00m"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DRPI${_piversion}=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
fi
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-rpi-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-rpi-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-rk3399-git
|
||||
pkgver=3494.bedacef
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('armv7h')
|
||||
url="https://github.com/ptitSeb/box86"
|
||||
license=('MIT')
|
||||
optdepends=('gl4es: OpenGL 2 for GLES 2 devices')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-rk3399-git}-git" "${pkgname%-rk3399-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-rk3399-git}-git" "${pkgname%-rk3399-git}")
|
||||
source=('git+https://github.com/ptitSeb/box86')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-rk3399-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-rk3399-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DRK3399=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
fi
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-rk3399-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-arm-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
# Maintainer: Jai-JAP <[email protected]>, SpacingBat3 <[email protected]>
|
||||
# Author: Sebastien Chevalier <[email protected]>
|
||||
pkgname=box86-x86-git
|
||||
pkgver=3494.bedacef
|
||||
pkgrel=1
|
||||
pkgdesc="Linux Userspace x86 Emulator with a twist, targeted at ARM Linux devices."
|
||||
arch=('i386')
|
||||
url="https://github.com/ptitSeb/box86"
|
||||
license=('MIT')
|
||||
makedepends=('git' 'cmake' 'make')
|
||||
provides=("${pkgname%-git}" "${pkgname%-x86-git}-git" "${pkgname%-x86-git}")
|
||||
conflicts=("${pkgname%-git}" "${pkgname%-x86-git}-git" "${pkgname%-x86-git}")
|
||||
source=('git+https://github.com/ptitSeb/box86')
|
||||
md5sums=('SKIP')
|
||||
|
||||
pkgver() {
|
||||
cd "$srcdir/${pkgname%-x86-git}"
|
||||
printf "r%s.%s" "$(git rev-list --count HEAD)" "$(git rev-parse --short HEAD)"
|
||||
}
|
||||
|
||||
prepare() {
|
||||
cd "${srcdir}/${pkgname%-x86-git}"
|
||||
if [[ ! -d ./build ]]; then
|
||||
mkdir build && cd build
|
||||
cmake .. -DLD80BITS=1 -DNOALIGN=1 -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
fi
|
||||
}
|
||||
|
||||
build() {
|
||||
cd "$srcdir/${pkgname%-x86-git}/build"
|
||||
make -j$(nproc)
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "$srcdir/${pkgname%-x86-git}/build"
|
||||
make DESTDIR="${pkgdir}/" install
|
||||
# /usr/local/bin isn't in PATH by the default,
|
||||
# we should move it to /usr/bin
|
||||
cd ${pkgdir}
|
||||
mv usr/local/bin/ usr/bin/
|
||||
# cleanup when dir is empty
|
||||
rmdir usr/local || exit 0
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
# The directory containing all PKGBUILDs for BOX86
|
||||
## FAQ
|
||||
### 1. How to use it?
|
||||
Just download the `PKGBUILD-<your-platform>` (no need to download the whole repository), go to directory where you downloaded and type:
|
||||
```sh
|
||||
mv ./PKGBUILD-<your-platform> ./PKGBUILD
|
||||
cd ..
|
||||
makepkg -si
|
||||
```
|
||||
This will copy the PKGBUILD for your platform (where you type your platform name instead of `<your-platform>`), build it and install the PKGBUILD on 32-bit Archlinux ARM.
|
||||
|
||||
In the future, I might try to do an unified PKGBUILD for all platforms that will recognize your platform automatically.
|
||||
|
||||
### 2. What platforms are currently supported.
|
||||
All specified in [COMPILE.md](../COMPILE.md).
|
||||
|
||||
### 3. Any advantages with that sollution?
|
||||
This might give you some advantages like those:
|
||||
- automatic updates (with some AUR frontends like [`pamac-aur`](https://aur.archlinux.org/packages/pamac-aur/) or [`yay`](https://aur.archlinux.org/packages/yay));
|
||||
- easily uninstall with `pacman -R` when no needed (no need other scripts nor Makefile to do this);
|
||||
- your `box86` installation is recognized as a package (where it wasn't when installing with `make install`).
|
||||
|
||||
|
||||
### Note: You can use [makedeb](https://github.com/makedeb/makedeb) (or) [pkgbuild2spec](https://github.com/prozum/pkgbuild2spec) to compile box86 to .deb or .rpm installer files.
|
||||
Executable
+1993
File diff suppressed because it is too large.
Load diff
+1342
-383
File diff suppressed because it is too large.
Load diff
+16
-2
@@ -13,7 +13,15 @@ if( NOT TEST_REFERENCE )
|
||||
endif( NOT TEST_REFERENCE )
|
||||
|
||||
set(ENV{BOX86_LOG} 0)
|
||||
set(ENV{LD_LIBRARY_PATH} ${CMAKE_SOURCE_DIR}/x86lib)
|
||||
set(ENV{BOX86_NOBANNER} 1)
|
||||
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}
|
||||
@@ -24,17 +32,23 @@ execute_process(
|
||||
|
||||
# if the return value is !=0 bail out
|
||||
if( TEST_RESULT )
|
||||
get_filename_component(TESTNAME "${TEST_ARGS}" NAME)
|
||||
file(RENAME "${TEST_OUTPUT}" "${CMAKE_BINARY_DIR}/${TESTNAME}.out")
|
||||
file(WRITE "${CMAKE_BINARY_DIR}/${TESTNAME}.err" ${TEST_ERROR})
|
||||
message( FATAL_ERROR "Failed: Test program ${TEST_PROGRAM} exited != 0.\n${TEST_ERROR}" )
|
||||
endif( TEST_RESULT )
|
||||
|
||||
# now compare the output with the reference
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} -E compare_files ${TEST_OUTPUT} ${TEST_REFERENCE}
|
||||
COMMAND "${CMAKE_COMMAND}" -E compare_files "${TEST_OUTPUT}" "${TEST_REFERENCE}"
|
||||
RESULT_VARIABLE TEST_RESULT
|
||||
)
|
||||
|
||||
# again, if return value is !=0 scream and shout
|
||||
if( TEST_RESULT )
|
||||
get_filename_component(TESTNAME "${TEST_ARGS}" NAME)
|
||||
file(RENAME "${TEST_OUTPUT}" "${CMAKE_BINARY_DIR}/${TESTNAME}.out")
|
||||
file(WRITE "${CMAKE_BINARY_DIR}/${TESTNAME}.err" ${TEST_ERROR})
|
||||
message( FATAL_ERROR "Failed: The output of ${TEST_PROGRAM} did not match ${TEST_REFERENCE}")
|
||||
endif( TEST_RESULT )
|
||||
|
||||
|
||||
+238
-134
@@ -16,49 +16,45 @@
|
||||
#include "callback.h"
|
||||
#include "wrapper.h"
|
||||
#include "myfts.h"
|
||||
#ifdef DYNAREC
|
||||
#include "threads.h"
|
||||
#include "x86trace.h"
|
||||
#include "signals.h"
|
||||
#include <sys/mman.h>
|
||||
#include "custommem.h"
|
||||
#include "dictionnary.h"
|
||||
#ifdef DYNAREC
|
||||
#include "dynablock.h"
|
||||
|
||||
typedef struct mmaplist_s {
|
||||
void* block;
|
||||
uintptr_t offset; // offset in the block
|
||||
} mmaplist_t;
|
||||
|
||||
#define MMAPSIZE (4*1024*1024) // allocate 4Mo sized blocks
|
||||
|
||||
uintptr_t AllocDynarecMap(box86context_t *context, 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;
|
||||
}
|
||||
}
|
||||
// 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));
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
context->mmaplist[i].block = p;
|
||||
context->mmaplist[i].offset=size;
|
||||
pthread_mutex_unlock(&context->mutex_mmap);
|
||||
return (uintptr_t)p;
|
||||
}
|
||||
#include "dynarec/arm_lock_helper.h"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
EXPORTDYN
|
||||
void initAllHelpers(box86context_t* context)
|
||||
{
|
||||
static int inited = 0;
|
||||
if(inited)
|
||||
return;
|
||||
my_context = context;
|
||||
init_pthread_helper();
|
||||
init_bridge_helper();
|
||||
init_signal_helper(context);
|
||||
inited = 1;
|
||||
}
|
||||
|
||||
EXPORTDYN
|
||||
void finiAllHelpers(box86context_t* context)
|
||||
{
|
||||
static int finied = 0;
|
||||
if(finied)
|
||||
return;
|
||||
fini_pthread_helper(context);
|
||||
fini_signal_helper();
|
||||
fini_bridge_helper();
|
||||
fini_custommem_helper(context);
|
||||
finied = 1;
|
||||
}
|
||||
|
||||
void x86Syscall(x86emu_t *emu);
|
||||
|
||||
/// maxval not inclusive
|
||||
@@ -66,11 +62,11 @@ int getrand(int maxval)
|
||||
{
|
||||
if(maxval<1024) {
|
||||
return ((random()&0x7fff)*maxval)/0x7fff;
|
||||
} else {
|
||||
}
|
||||
uint64_t r = random();
|
||||
r = (r*maxval) / RAND_MAX;
|
||||
return r;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void free_tlsdatasize(void* p)
|
||||
@@ -82,17 +78,107 @@ void free_tlsdatasize(void* p)
|
||||
free(p);
|
||||
}
|
||||
|
||||
int unlockMutex()
|
||||
{
|
||||
int ret = unlockCustommemMutex();
|
||||
int i;
|
||||
#define GO(A, B) \
|
||||
i = checkUnlockMutex(&A); \
|
||||
if(i) { \
|
||||
ret|=(1<<B); \
|
||||
}
|
||||
|
||||
GO(my_context->mutex_once, 5)
|
||||
GO(my_context->mutex_once2, 6)
|
||||
GO(my_context->mutex_trace, 7)
|
||||
#ifdef DYNAREC
|
||||
GO(my_context->mutex_dyndump, 8)
|
||||
#else
|
||||
GO(my_context->mutex_lock, 8)
|
||||
#endif
|
||||
GO(my_context->mutex_tls, 9)
|
||||
GO(my_context->mutex_thread, 10)
|
||||
GO(my_context->mutex_bridge, 11)
|
||||
#undef GO
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void relockMutex(int locks)
|
||||
{
|
||||
#define GO(A, B) \
|
||||
if(locks&(1<<B)) \
|
||||
pthread_mutex_lock(&A); \
|
||||
|
||||
GO(my_context->mutex_once, 5)
|
||||
GO(my_context->mutex_once2, 6)
|
||||
GO(my_context->mutex_trace, 7)
|
||||
#ifdef DYNAREC
|
||||
GO(my_context->mutex_dyndump, 8)
|
||||
#else
|
||||
GO(my_context->mutex_lock, 8)
|
||||
#endif
|
||||
GO(my_context->mutex_tls, 9)
|
||||
GO(my_context->mutex_thread, 10)
|
||||
GO(my_context->mutex_bridge, 11)
|
||||
#undef GO
|
||||
relockCustommemMutex(locks);
|
||||
}
|
||||
|
||||
static void init_mutexes(box86context_t* context)
|
||||
{
|
||||
pthread_mutexattr_t attr;
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
|
||||
pthread_mutex_init(&context->mutex_once, &attr);
|
||||
pthread_mutex_init(&context->mutex_once2, &attr);
|
||||
pthread_mutex_init(&context->mutex_trace, &attr);
|
||||
#ifdef DYNAREC
|
||||
pthread_mutex_init(&context->mutex_dyndump, &attr);
|
||||
#else
|
||||
pthread_mutex_init(&context->mutex_lock, &attr);
|
||||
#endif
|
||||
pthread_mutex_init(&context->mutex_tls, &attr);
|
||||
pthread_mutex_init(&context->mutex_thread, &attr);
|
||||
pthread_mutex_init(&context->mutex_bridge, &attr);
|
||||
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
}
|
||||
|
||||
static void atfork_child_box64context(void)
|
||||
{
|
||||
// (re)init mutex if it was lock before the fork
|
||||
init_mutexes(my_context);
|
||||
}
|
||||
|
||||
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));
|
||||
box86context_t *context = my_context = (box86context_t*)calloc(1, sizeof(box86context_t));
|
||||
|
||||
#ifdef BUILD_LIB
|
||||
context->deferedInit = 0;
|
||||
#else
|
||||
context->deferedInit = 1;
|
||||
#endif
|
||||
context->sel_serial = 1;
|
||||
|
||||
context->maplib = NewLibrarian(context);
|
||||
init_custommem_helper(context);
|
||||
|
||||
context->maplib = NewLibrarian(context, 1);
|
||||
context->local_maplib = NewLibrarian(context, 1);
|
||||
context->versym = NewDictionnary();
|
||||
context->system = NewBridge();
|
||||
// create vsyscall
|
||||
context->vsyscall = AddBridge(context->system, vFv, x86Syscall, 0);
|
||||
context->vsyscall = AddBridge(context->system, iFEv, x86Syscall, 0, NULL);
|
||||
addAlternate((void*)0xffffe400, (void*)context->vsyscall);
|
||||
#ifdef BUILD_LIB
|
||||
context->box86lib = RTLD_DEFAULT; // not ideal
|
||||
#else
|
||||
@@ -100,132 +186,140 @@ box86context_t *NewBox86Context(int argc)
|
||||
#endif
|
||||
context->dlprivate = NewDLPrivate();
|
||||
|
||||
context->callbacks = NewCallbackList();
|
||||
|
||||
context->argc = argc;
|
||||
context->argv = (char**)calloc(context->argc+1, sizeof(char*));
|
||||
|
||||
pthread_mutex_init(&context->mutex_once, NULL);
|
||||
pthread_mutex_init(&context->mutex_once2, NULL);
|
||||
pthread_mutex_init(&context->mutex_trace, NULL);
|
||||
pthread_mutex_init(&context->mutex_lock, NULL);
|
||||
init_mutexes(context);
|
||||
pthread_atfork(NULL, NULL, atfork_child_box64context);
|
||||
|
||||
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);
|
||||
#endif
|
||||
InitFTSMap(context);
|
||||
|
||||
for (int i=0; i<4; ++i) context->canary[i] = 1 + getrand(255);
|
||||
context->canary[getrand(4)] = 0;
|
||||
context->canary[/*getrand(4)*/0] = 0;
|
||||
printf_log(LOG_DEBUG, "Setting up canary (for Stack protector) at GS:0x14, value:%08X\n", *(uint32_t*)context->canary);
|
||||
|
||||
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);
|
||||
if(ctx->local_maplib)
|
||||
FreeLibrarian(&ctx->local_maplib, NULL);
|
||||
if(ctx->maplib)
|
||||
FreeLibrarian(&ctx->maplib, NULL);
|
||||
FreeDictionnary(&ctx->versym);
|
||||
|
||||
#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);
|
||||
#endif
|
||||
|
||||
if((*context)->emu)
|
||||
FreeX86Emu(&(*context)->emu);
|
||||
|
||||
FreeCollection(&(*context)->box86_path);
|
||||
FreeCollection(&(*context)->box86_ld_lib);
|
||||
FreeCollection(&(*context)->box86_emulated_libs);
|
||||
if((*context)->zydis)
|
||||
DeleteX86Trace(*context);
|
||||
|
||||
if((*context)->deferedInitList)
|
||||
free((*context)->deferedInitList);
|
||||
|
||||
#ifndef BUILD_LIB
|
||||
if((*context)->box86lib)
|
||||
dlclose((*context)->box86lib);
|
||||
#endif
|
||||
|
||||
FreeDLPrivate(&(*context)->dlprivate);
|
||||
|
||||
for(int i=0; i<(*context)->argc; ++i)
|
||||
free((*context)->argv[i]);
|
||||
free((*context)->argv);
|
||||
|
||||
for (int i=0; i<(*context)->envc; ++i)
|
||||
free((*context)->envv[i]);
|
||||
free((*context)->envv);
|
||||
|
||||
for(int i=0; i<(*context)->elfsize; ++i) {
|
||||
FreeElfHeader(&(*context)->elfs[i]);
|
||||
for(int i=0; i<ctx->elfsize; ++i) {
|
||||
FreeElfHeader(&ctx->elfs[i]);
|
||||
}
|
||||
free((*context)->elfs);
|
||||
free(ctx->elfs);
|
||||
|
||||
free((*context)->stack);
|
||||
FreeFTSMap(ctx);
|
||||
|
||||
free((*context)->fullpath);
|
||||
free((*context)->box86path);
|
||||
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);
|
||||
|
||||
FreeBridge(&(*context)->system);
|
||||
if(ctx->deferedInitList)
|
||||
free(ctx->deferedInitList);
|
||||
|
||||
if((*context)->glwrappers)
|
||||
freeProcWrapper(&(*context)->glwrappers);
|
||||
if((*context)->alwrappers)
|
||||
freeProcWrapper(&(*context)->alwrappers);
|
||||
free(ctx->argv);
|
||||
|
||||
for (int i=0; i<ctx->envc; ++i)
|
||||
free(ctx->envv[i]);
|
||||
free(ctx->envv);
|
||||
|
||||
FreeCallbackList(&(*context)->callbacks);
|
||||
|
||||
void* ptr;
|
||||
if ((ptr = pthread_getspecific((*context)->tlskey)) != NULL) {
|
||||
free_tlsdatasize(ptr);
|
||||
pthread_setspecific((*context)->tlskey, NULL);
|
||||
}
|
||||
pthread_key_delete((*context)->tlskey);
|
||||
|
||||
if((*context)->tlsdata)
|
||||
free((*context)->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);
|
||||
|
||||
if((*context)->atfork_sz) {
|
||||
free((*context)->atforks);
|
||||
(*context)->atforks = NULL;
|
||||
(*context)->atfork_sz = (*context)->atfork_cap = 0;
|
||||
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);
|
||||
}
|
||||
|
||||
*context = NULL; // bye bye my_context
|
||||
|
||||
free(*context);
|
||||
*context = NULL;
|
||||
CleanStackSize(ctx);
|
||||
|
||||
#ifndef BUILD_LIB
|
||||
if(ctx->box86lib)
|
||||
dlclose(ctx->box86lib);
|
||||
#endif
|
||||
|
||||
FreeDLPrivate(&ctx->dlprivate);
|
||||
|
||||
// free(ctx->stack); // don't free the stack, it's owned by main emu!
|
||||
|
||||
free(ctx->fullpath);
|
||||
free(ctx->box86path);
|
||||
|
||||
FreeBridge(&ctx->system);
|
||||
|
||||
freeGLProcWrapper(ctx);
|
||||
freeALProcWrapper(ctx);
|
||||
|
||||
void* ptr;
|
||||
if ((ptr = pthread_getspecific(ctx->tlskey)) != NULL) {
|
||||
free_tlsdatasize(ptr);
|
||||
pthread_setspecific(ctx->tlskey, NULL);
|
||||
}
|
||||
pthread_key_delete(ctx->tlskey);
|
||||
|
||||
if(ctx->tlsdata)
|
||||
free(ctx->tlsdata);
|
||||
|
||||
for(int i=0; i<3; ++i) {
|
||||
if(ctx->segtls[i].present) {
|
||||
// key content not handled by box86, so not doing anything with it
|
||||
pthread_key_delete(ctx->segtls[i].key);
|
||||
}
|
||||
}
|
||||
|
||||
free_neededlib(&ctx->neededlibs);
|
||||
|
||||
if(ctx->emu_sig)
|
||||
FreeX86Emu(&ctx->emu_sig);
|
||||
|
||||
finiAllHelpers(ctx);
|
||||
|
||||
pthread_mutex_destroy(&ctx->mutex_once);
|
||||
pthread_mutex_destroy(&ctx->mutex_once2);
|
||||
pthread_mutex_destroy(&ctx->mutex_trace);
|
||||
#ifdef DYNAREC
|
||||
pthread_mutex_destroy(&ctx->mutex_dyndump);
|
||||
#else
|
||||
pthread_mutex_destroy(&ctx->mutex_lock);
|
||||
#endif
|
||||
pthread_mutex_destroy(&ctx->mutex_tls);
|
||||
pthread_mutex_destroy(&ctx->mutex_thread);
|
||||
pthread_mutex_destroy(&ctx->mutex_bridge);
|
||||
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
int AddElfHeader(box86context_t* ctx, elfheader_t* head) {
|
||||
@@ -242,7 +336,17 @@ 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)
|
||||
// clean GS segment for current emu
|
||||
if(my_context) {
|
||||
ResetSegmentsCache(thread_get_emu());
|
||||
if(!(++context->sel_serial))
|
||||
++context->sel_serial;
|
||||
}
|
||||
|
||||
return -context->tlssize; // negative offset
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -2,7 +2,7 @@
|
||||
#define __BOX86_VERSION_H_
|
||||
|
||||
#define BOX86_MAJOR 0
|
||||
#define BOX86_MINOR 1
|
||||
#define BOX86_REVISION 0
|
||||
#define BOX86_MINOR 2
|
||||
#define BOX86_REVISION 4
|
||||
|
||||
#endif //__BOX86_VERSION_H_
|
||||
Executable
+27
@@ -0,0 +1,27 @@
|
||||
#include <stdio.h>
|
||||
#include "debug.h"
|
||||
#include "box86version.h"
|
||||
#ifdef NOGIT
|
||||
#define GITREV "nogit"
|
||||
#else
|
||||
#include "git_head.h"
|
||||
#endif
|
||||
|
||||
void PrintBox86Version()
|
||||
{
|
||||
printf("Box86%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
|
||||
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__
|
||||
+824
@@ -0,0 +1,824 @@
|
||||
#define _GNU_SOURCE /* See feature_test_macros(7) */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <dlfcn.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "box86context.h"
|
||||
#include "elfloader.h"
|
||||
#include "debug.h"
|
||||
#include "x86trace.h"
|
||||
#include "x86emu.h"
|
||||
#include "librarian.h"
|
||||
#include "bridge.h"
|
||||
#include "library.h"
|
||||
#include "callback.h"
|
||||
#include "wrapper.h"
|
||||
#include "myfts.h"
|
||||
#include "threads.h"
|
||||
#include "x86trace.h"
|
||||
#include "signals.h"
|
||||
#include <sys/mman.h>
|
||||
#include "custommem.h"
|
||||
#include "threads.h"
|
||||
#ifdef DYNAREC
|
||||
#include "dynablock.h"
|
||||
#include "dynarec/arm_lock_helper.h"
|
||||
#include "khash.h"
|
||||
|
||||
#define USE_MMAP
|
||||
|
||||
// init inside dynablocks.c
|
||||
KHASH_MAP_INIT_INT(dynablocks, dynablock_t*)
|
||||
static dynablocklist_t* dynmap[DYNAMAP_SIZE]; // 4G of memory mapped by 4K block
|
||||
static mmaplist_t *mmaplist = NULL;
|
||||
static int mmapsize = 0;
|
||||
static int mmapcap = 0;
|
||||
static kh_dynablocks_t *dblist_oversized; // store the list of oversized dynablocks (normal sized are inside mmaplist)
|
||||
static uintptr_t *box86_jumptable[JMPTABL_SIZE];
|
||||
static uintptr_t box86_jmptbl_default[1<<JMPTABL_SHIFT];
|
||||
#endif
|
||||
#define MEMPROT_SHIFT 12
|
||||
#define MEMPROT_SIZE (1<<(32-MEMPROT_SHIFT))
|
||||
static uint8_t memprot[MEMPROT_SIZE] = {0}; // protection flags by 4K block
|
||||
static int inited = 0;
|
||||
|
||||
typedef struct blocklist_s {
|
||||
void* block;
|
||||
int maxfree;
|
||||
size_t size;
|
||||
} blocklist_t;
|
||||
|
||||
#define MMAPSIZE (256*1024) // allocate 256kb sized blocks
|
||||
|
||||
static pthread_mutex_t mutex_blocks;
|
||||
static int n_blocks = 0; // number of blocks for custom malloc
|
||||
static blocklist_t* p_blocks = NULL; // actual blocks for custom malloc
|
||||
|
||||
typedef union mark_s {
|
||||
struct {
|
||||
unsigned int size:31;
|
||||
unsigned int fill:1;
|
||||
};
|
||||
uint32_t x32;
|
||||
} mark_t;
|
||||
typedef struct blockmark_s {
|
||||
mark_t prev;
|
||||
mark_t next;
|
||||
} blockmark_t;
|
||||
|
||||
#define NEXT_BLOCK(b) (blockmark_t*)((uintptr_t)(b) + (b)->next.size + sizeof(blockmark_t))
|
||||
#define PREV_BLOCK(b) (blockmark_t*)(((uintptr_t)(b) - (b)->prev.size) - sizeof(blockmark_t))
|
||||
#define LAST_BLOCK(b, s) (blockmark_t*)(((uintptr_t)(b)+(s))-sizeof(blockmark_t))
|
||||
|
||||
static void printBlock(blockmark_t* b, void* start)
|
||||
{
|
||||
printf_log(LOG_INFO, "========== Block is:\n");
|
||||
do {
|
||||
printf_log(LOG_INFO, "%c%p, fill=%d, size=0x%x (prev=%d/0x%x)\n", b==start?'*':' ', b, b->next.fill, b->next.size, b->prev.fill, b->prev.size);
|
||||
b = NEXT_BLOCK(b);
|
||||
} while(b->next.x32);
|
||||
printf_log(LOG_INFO, "===================\n");
|
||||
}
|
||||
|
||||
// get first subblock free in block. Return NULL if no block, else first subblock free (mark included), filling size
|
||||
static void* getFirstBlock(void* block, size_t maxsize, size_t* size, void* start)
|
||||
{
|
||||
// get start of block
|
||||
blockmark_t *m = (blockmark_t*)((start)?start:block);
|
||||
while(m->next.x32) { // while there is a subblock
|
||||
if(!m->next.fill && m->next.size>=maxsize) {
|
||||
*size = m->next.size;
|
||||
return m;
|
||||
}
|
||||
m = NEXT_BLOCK(m);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static size_t getMaxFreeBlock(void* block, size_t block_size, void* start)
|
||||
{
|
||||
// get start of block
|
||||
if(start) {
|
||||
blockmark_t *m = (blockmark_t*)start;
|
||||
int maxsize = 0;
|
||||
while(m->next.x32) { // while there is a subblock
|
||||
if(!m->next.fill && m->next.size>maxsize) {
|
||||
maxsize = m->next.size;
|
||||
}
|
||||
m = NEXT_BLOCK(m);
|
||||
}
|
||||
return (maxsize>=sizeof(blockmark_t))?maxsize:0;
|
||||
} else {
|
||||
blockmark_t *m = LAST_BLOCK(block, block_size); // start with the end
|
||||
int maxsize = 0;
|
||||
while(m->prev.x32) { // while there is a subblock
|
||||
if(!m->prev.fill && m->prev.size>maxsize) {
|
||||
maxsize = m->prev.size;
|
||||
if((uintptr_t)block+maxsize>(uintptr_t)m)
|
||||
return (maxsize>=sizeof(blockmark_t))?maxsize:0; // no block large enough left...
|
||||
}
|
||||
m = PREV_BLOCK(m);
|
||||
}
|
||||
return (maxsize>=sizeof(blockmark_t))?maxsize:0;
|
||||
}
|
||||
}
|
||||
|
||||
static void* allocBlock(void* block, void *sub, size_t size, void** pstart)
|
||||
{
|
||||
(void)block;
|
||||
|
||||
blockmark_t *s = (blockmark_t*)sub;
|
||||
blockmark_t *n = NEXT_BLOCK(s);
|
||||
|
||||
s->next.fill = 1;
|
||||
// check if a new mark is worth it
|
||||
if(s->next.size>size+2*sizeof(blockmark_t))
|
||||
s->next.size = size;
|
||||
blockmark_t *m = NEXT_BLOCK(s); // this is new n
|
||||
m->prev.fill = 1;
|
||||
if(n!=m) {
|
||||
// new mark
|
||||
m->prev.size = s->next.size;
|
||||
m->next.fill = 0;
|
||||
m->next.size = ((uintptr_t)n - (uintptr_t)m) - sizeof(blockmark_t);
|
||||
n->prev.fill = 0;
|
||||
n->prev.size = m->next.size;
|
||||
}
|
||||
|
||||
if(pstart && sub==*pstart) {
|
||||
// get the next free block
|
||||
m = (blockmark_t*)*pstart;
|
||||
while(m->next.fill)
|
||||
m = NEXT_BLOCK(m);
|
||||
*pstart = (void*)m;
|
||||
}
|
||||
return (void*)((uintptr_t)sub + sizeof(blockmark_t));
|
||||
}
|
||||
static size_t freeBlock(void *block, void* sub, void** pstart)
|
||||
{
|
||||
blockmark_t *m = (blockmark_t*)block;
|
||||
blockmark_t *s = (blockmark_t*)sub;
|
||||
blockmark_t *n = NEXT_BLOCK(s);
|
||||
if(block!=sub)
|
||||
m = PREV_BLOCK(s);
|
||||
s->next.fill = 0;
|
||||
n->prev.fill = 0;
|
||||
// check if merge with previous
|
||||
if (s->prev.x32 && !s->prev.fill) {
|
||||
// remove s...
|
||||
m->next.size += s->next.size + sizeof(blockmark_t);
|
||||
n->prev.size = m->next.size;
|
||||
s = m;
|
||||
}
|
||||
// check if merge with next
|
||||
if(n->next.x32 && !n->next.fill) {
|
||||
blockmark_t *n2 = NEXT_BLOCK(n);
|
||||
//remove n
|
||||
s->next.size += n->next.size + sizeof(blockmark_t);
|
||||
n2->prev.size = s->next.size;
|
||||
}
|
||||
if(pstart && (uintptr_t)*pstart>(uintptr_t)sub) {
|
||||
*pstart = (void*)s;
|
||||
}
|
||||
// return free size at current block (might be bigger)
|
||||
return s->next.size;
|
||||
}
|
||||
// return 1 if block has been expanded to new size, 0 if not
|
||||
static int expandBlock(void* block, void* sub, size_t newsize)
|
||||
{
|
||||
(void)block;
|
||||
|
||||
newsize = (newsize+3)&~3;
|
||||
blockmark_t *s = (blockmark_t*)sub;
|
||||
blockmark_t *n = NEXT_BLOCK(s);
|
||||
if(s->next.size>=newsize)
|
||||
// big enough, no shrinking...
|
||||
return 1;
|
||||
if(s->next.fill)
|
||||
return 0; // next block is filled
|
||||
// unsigned bitfield of this length gets "promoted" to *signed* int...
|
||||
if((size_t)(s->next.size + n->next.size + sizeof(blockmark_t)) < newsize)
|
||||
return 0; // free space too short
|
||||
// ok, doing the alloc!
|
||||
if((s->next.size+n->next.size+sizeof(blockmark_t))-newsize<2*sizeof(blockmark_t))
|
||||
s->next.size += n->next.size+sizeof(blockmark_t);
|
||||
else
|
||||
s->next.size = newsize+sizeof(blockmark_t);
|
||||
blockmark_t *m = NEXT_BLOCK(s); // this is new n
|
||||
m->prev.fill = 1;
|
||||
m->prev.size = s->next.size;
|
||||
if(n!=m) {
|
||||
// new mark
|
||||
m->prev.fill = 1;
|
||||
m->prev.size = s->next.size;
|
||||
m->next.fill = 0;
|
||||
m->next.size = (uintptr_t)n - (uintptr_t)m;
|
||||
n->prev.fill = 0;
|
||||
n->prev.size = m->next.size;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
// return size of block
|
||||
static size_t sizeBlock(void* sub)
|
||||
{
|
||||
blockmark_t *s = (blockmark_t*)sub;
|
||||
return s->next.size;
|
||||
}
|
||||
|
||||
void* customMalloc(size_t size)
|
||||
{
|
||||
// look for free space
|
||||
void* sub = NULL;
|
||||
pthread_mutex_lock(&mutex_blocks);
|
||||
for(int i=0; i<n_blocks; ++i) {
|
||||
if(p_blocks[i].maxfree>=size) {
|
||||
size_t rsize = 0;
|
||||
sub = getFirstBlock(p_blocks[i].block, size, &rsize, NULL);
|
||||
if(sub) {
|
||||
void* ret = allocBlock(p_blocks[i].block, sub, size, NULL);
|
||||
if(rsize==p_blocks[i].maxfree)
|
||||
p_blocks[i].maxfree = getMaxFreeBlock(p_blocks[i].block, p_blocks[i].size, NULL);
|
||||
pthread_mutex_unlock(&mutex_blocks);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
// add a new block
|
||||
int i = n_blocks++;
|
||||
p_blocks = (blocklist_t*)realloc(p_blocks, n_blocks*sizeof(blocklist_t));
|
||||
size_t allocsize = MMAPSIZE;
|
||||
if(size+2*sizeof(blockmark_t)>allocsize)
|
||||
allocsize = size+2*sizeof(blockmark_t);
|
||||
#ifdef USE_MMAP
|
||||
void* p = mmap(NULL, allocsize, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
|
||||
memset(p, 0, allocsize);
|
||||
#else
|
||||
void* p = calloc(1, allocsize);
|
||||
#endif
|
||||
p_blocks[i].block = p;
|
||||
p_blocks[i].size = allocsize;
|
||||
// setup marks
|
||||
blockmark_t* m = (blockmark_t*)p;
|
||||
m->prev.x32 = 0;
|
||||
m->next.fill = 0;
|
||||
m->next.size = allocsize-2*sizeof(blockmark_t);
|
||||
blockmark_t* n = NEXT_BLOCK(m);
|
||||
n->next.x32 = 0;
|
||||
n->prev.fill = 0;
|
||||
n->prev.size = m->next.size;
|
||||
// alloc 1st block
|
||||
void* ret = allocBlock(p_blocks[i].block, p, size, NULL);
|
||||
p_blocks[i].maxfree = getMaxFreeBlock(p_blocks[i].block, p_blocks[i].size, NULL);
|
||||
pthread_mutex_unlock(&mutex_blocks);
|
||||
return ret;
|
||||
}
|
||||
void* customCalloc(size_t n, size_t size)
|
||||
{
|
||||
size_t newsize = n*size;
|
||||
void* ret = customMalloc(newsize);
|
||||
memset(ret, 0, newsize);
|
||||
return ret;
|
||||
}
|
||||
void* customRealloc(void* p, size_t size)
|
||||
{
|
||||
if(!p)
|
||||
return customMalloc(size);
|
||||
uintptr_t addr = (uintptr_t)p;
|
||||
pthread_mutex_lock(&mutex_blocks);
|
||||
for(int i=0; i<n_blocks; ++i) {
|
||||
if ((addr>(uintptr_t)p_blocks[i].block)
|
||||
&& (addr<((uintptr_t)p_blocks[i].block+p_blocks[i].size))) {
|
||||
void* sub = (void*)(addr-sizeof(blockmark_t));
|
||||
if(expandBlock(p_blocks[i].block, sub, size)) {
|
||||
p_blocks[i].maxfree = getMaxFreeBlock(p_blocks[i].block, p_blocks[i].size, NULL);
|
||||
pthread_mutex_unlock(&mutex_blocks);
|
||||
return p;
|
||||
}
|
||||
pthread_mutex_unlock(&mutex_blocks);
|
||||
void* newp = customMalloc(size);
|
||||
memcpy(newp, p, sizeBlock(sub));
|
||||
customFree(p);
|
||||
return newp;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&mutex_blocks);
|
||||
if(n_blocks)
|
||||
dynarec_log(LOG_NONE, "Warning, block %p not found in p_blocks for realloc, malloc'ing again without free\n", (void*)addr);
|
||||
return customMalloc(size);
|
||||
}
|
||||
void customFree(void* p)
|
||||
{
|
||||
if(!p)
|
||||
return;
|
||||
uintptr_t addr = (uintptr_t)p;
|
||||
pthread_mutex_lock(&mutex_blocks);
|
||||
for(int i=0; i<n_blocks; ++i) {
|
||||
if ((addr>(uintptr_t)p_blocks[i].block)
|
||||
&& (addr<((uintptr_t)p_blocks[i].block+p_blocks[i].size))) {
|
||||
void* sub = (void*)(addr-sizeof(blockmark_t));
|
||||
size_t newfree = freeBlock(p_blocks[i].block, sub, NULL);
|
||||
if(p_blocks[i].maxfree < newfree) p_blocks[i].maxfree = newfree;
|
||||
pthread_mutex_unlock(&mutex_blocks);
|
||||
return;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&mutex_blocks);
|
||||
if(n_blocks)
|
||||
dynarec_log(LOG_NONE, "Warning, block %p not found in p_blocks for Free\n", (void*)addr);
|
||||
}
|
||||
|
||||
#ifdef DYNAREC
|
||||
typedef struct mmaplist_s {
|
||||
void* block;
|
||||
int maxfree;
|
||||
size_t size;
|
||||
kh_dynablocks_t* dblist;
|
||||
uint8_t* helper;
|
||||
void* first; // first free block, to speed up things
|
||||
int locked; // don't try to add stuff on locked block
|
||||
} mmaplist_t;
|
||||
|
||||
uintptr_t FindFreeDynarecMap(dynablock_t* db, int size)
|
||||
{
|
||||
// look for free space
|
||||
void* sub = NULL;
|
||||
for(int i=0; i<mmapsize; ++i) {
|
||||
if(mmaplist[i].maxfree>=size+sizeof(blockmark_t) && !mmaplist[i].locked) {
|
||||
mmaplist[i].locked = 1;
|
||||
int rsize = 0;
|
||||
sub = getFirstBlock(mmaplist[i].block, size, &rsize, mmaplist[i].first);
|
||||
if(sub) {
|
||||
uintptr_t ret = (uintptr_t)allocBlock(mmaplist[i].block, sub, size, &mmaplist[i].first);
|
||||
if(rsize==mmaplist[i].maxfree) {
|
||||
mmaplist[i].maxfree = getMaxFreeBlock(mmaplist[i].block, mmaplist[i].size, mmaplist[i].first);
|
||||
}
|
||||
kh_dynablocks_t *blocks = mmaplist[i].dblist;
|
||||
if(!blocks) {
|
||||
blocks = mmaplist[i].dblist = kh_init(dynablocks);
|
||||
kh_resize(dynablocks, blocks, 64);
|
||||
}
|
||||
khint_t k;
|
||||
int r;
|
||||
k = kh_put(dynablocks, blocks, (uintptr_t)ret, &r);
|
||||
kh_value(blocks, k) = db;
|
||||
int size255=(size<256)?size:255;
|
||||
for(size_t j=0; j<size255; ++j)
|
||||
mmaplist[i].helper[(uintptr_t)ret-(uintptr_t)mmaplist[i].block+j] = j;
|
||||
if(size!=size255)
|
||||
memset(&mmaplist[i].helper[(uintptr_t)ret-(uintptr_t)mmaplist[i].block+256], -1, size-255);
|
||||
mmaplist[i].locked = 0;
|
||||
return ret;
|
||||
} else {
|
||||
printf_log(LOG_INFO, "BOX86: Warning, sub not found, corrupted mmaplist[%d] info?\n", i);
|
||||
if(box86_log >= LOG_DEBUG)
|
||||
printBlock(mmaplist[i].block, mmaplist[i].first);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uintptr_t AddNewDynarecMap(dynablock_t* db, int size)
|
||||
{
|
||||
int i = mmapsize++; // yeah, useful post incrementation
|
||||
dynarec_log(LOG_DEBUG, "Ask for DynaRec Block Alloc #%zu/%zu\n", mmapsize, mmapcap);
|
||||
if(mmapsize>mmapcap) {
|
||||
mmapcap += 32;
|
||||
mmaplist = (mmaplist_t*)realloc(mmaplist, mmapcap*sizeof(mmaplist_t));
|
||||
}
|
||||
#ifndef USE_MMAP
|
||||
void *p = NULL;
|
||||
if(posix_memalign(&p, box86_pagesize, MMAPSIZE)) {
|
||||
dynarec_log(LOG_INFO, "Cannot create memory map of %d byte for dynarec block #%d\n", MMAPSIZE, i);
|
||||
--mmapsize;
|
||||
return 0;
|
||||
}
|
||||
mprotect(p, MMAPSIZE, PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||
#else
|
||||
void* p = mmap(NULL, MMAPSIZE, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
|
||||
if(p==(void*)-1) {
|
||||
dynarec_log(LOG_INFO, "Cannot create memory map of %d byte for dynarec block #%d\n", MMAPSIZE, i);
|
||||
--mmapsize;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
setProtection((uintptr_t)p, MMAPSIZE, PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||
|
||||
mmaplist[i].locked = 1;
|
||||
mmaplist[i].block = p;
|
||||
mmaplist[i].size = MMAPSIZE;
|
||||
mmaplist[i].helper = (uint8_t*)calloc(1, MMAPSIZE);
|
||||
mmaplist[i].first = p;
|
||||
// setup marks
|
||||
blockmark_t* m = (blockmark_t*)p;
|
||||
m->prev.x32 = 0;
|
||||
m->next.fill = 0;
|
||||
m->next.size = MMAPSIZE-2*sizeof(blockmark_t);
|
||||
blockmark_t* n = NEXT_BLOCK(m);
|
||||
n->next.x32 = 0;
|
||||
n->prev.fill = 0;
|
||||
n->prev.size = m->next.size;
|
||||
// alloc 1st block
|
||||
uintptr_t sub = (uintptr_t)allocBlock(mmaplist[i].block, p, size, &mmaplist[i].first);
|
||||
mmaplist[i].maxfree = getMaxFreeBlock(mmaplist[i].block, mmaplist[i].size, mmaplist[i].first);
|
||||
kh_dynablocks_t *blocks = mmaplist[i].dblist = kh_init(dynablocks);
|
||||
kh_resize(dynablocks, blocks, 64);
|
||||
khint_t k;
|
||||
int ret;
|
||||
k = kh_put(dynablocks, blocks, (uintptr_t)sub, &ret);
|
||||
kh_value(blocks, k) = db;
|
||||
for(int j=0; j<size; ++j)
|
||||
mmaplist[i].helper[(uintptr_t)sub-(uintptr_t)mmaplist[i].block + j] = (j<256)?j:255;
|
||||
mmaplist[i].locked = 0;
|
||||
return sub;
|
||||
}
|
||||
|
||||
void ActuallyFreeDynarecMap(dynablock_t* db, uintptr_t addr, int size)
|
||||
{
|
||||
if(!addr || !size)
|
||||
return;
|
||||
for(int i=0; i<mmapsize; ++i) {
|
||||
if ((addr>(uintptr_t)mmaplist[i].block)
|
||||
&& (addr<((uintptr_t)mmaplist[i].block+mmaplist[i].size))) {
|
||||
void* sub = (void*)(addr-sizeof(blockmark_t));
|
||||
size_t newfree = freeBlock(mmaplist[i].block, sub, &mmaplist[i].first);
|
||||
if(mmaplist[i].maxfree < newfree) mmaplist[i].maxfree = newfree;
|
||||
kh_dynablocks_t *blocks = mmaplist[i].dblist;
|
||||
if(blocks) {
|
||||
khint_t k = kh_get(dynablocks, blocks, (uintptr_t)sub);
|
||||
if(k!=kh_end(blocks))
|
||||
kh_del(dynablocks, blocks, k);
|
||||
memset(&mmaplist[i].helper[(uintptr_t)sub-(uintptr_t)mmaplist[i].block], 0, size);
|
||||
}
|
||||
if(mmaplist[i].locked) {
|
||||
printf_log(LOG_INFO, "BOX86: Warning, Free a chunk in a locked mmaplist[%d]\n", i);
|
||||
++mmaplist[i].locked;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(mmapsize)
|
||||
dynarec_log(LOG_NONE, "Warning, block %p (size %d) not found in mmaplist for Free\n", (void*)addr, size);
|
||||
}
|
||||
|
||||
dynablock_t* FindDynablockFromNativeAddress(void* addr)
|
||||
{
|
||||
// look in actual list
|
||||
for(int i=0; i<mmapsize; ++i) {
|
||||
if ((uintptr_t)addr>=(uintptr_t)mmaplist[i].block
|
||||
&& ((uintptr_t)addr<(uintptr_t)mmaplist[i].block+mmaplist[i].size)) {
|
||||
if(!mmaplist[i].helper)
|
||||
return FindDynablockDynablocklist(addr, mmaplist[i].dblist);
|
||||
else {
|
||||
uintptr_t p = (uintptr_t)addr - (uintptr_t)mmaplist[i].block;
|
||||
while(mmaplist[i].helper[p]) p -= mmaplist[i].helper[p];
|
||||
khint_t k = kh_get(dynablocks, mmaplist[i].dblist, (uintptr_t)mmaplist[i].block + p);
|
||||
if(k!=kh_end(mmaplist[i].dblist))
|
||||
return kh_value(mmaplist[i].dblist, k);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
// look in oversized
|
||||
return FindDynablockDynablocklist(addr, dblist_oversized);
|
||||
}
|
||||
|
||||
uintptr_t AllocDynarecMap(dynablock_t* db, int size)
|
||||
{
|
||||
if(!size)
|
||||
return 0;
|
||||
if(size>MMAPSIZE-2*sizeof(blockmark_t)) {
|
||||
#ifndef USE_MMAP
|
||||
void *p = NULL;
|
||||
if(posix_memalign(&p, box86_pagesize, size)) {
|
||||
dynarec_log(LOG_INFO, "Cannot create dynamic map of %d bytes\n", size);
|
||||
return 0;
|
||||
}
|
||||
mprotect(p, size, PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||
#else
|
||||
void* p = mmap(NULL, size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
|
||||
if(p==(void*)-1) {
|
||||
dynarec_log(LOG_INFO, "Cannot create dynamic map of %d bytes\n", size);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
setProtection((uintptr_t)p, size, PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||
kh_dynablocks_t *blocks = dblist_oversized;
|
||||
if(!blocks) {
|
||||
blocks = dblist_oversized = kh_init(dynablocks);
|
||||
kh_resize(dynablocks, blocks, 64);
|
||||
}
|
||||
khint_t k;
|
||||
int ret;
|
||||
k = kh_put(dynablocks, blocks, (uintptr_t)p, &ret);
|
||||
kh_value(blocks, k) = db;
|
||||
return (uintptr_t)p;
|
||||
}
|
||||
|
||||
uintptr_t ret = FindFreeDynarecMap(db, size);
|
||||
if(!ret)
|
||||
ret = AddNewDynarecMap(db, size);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void FreeDynarecMap(dynablock_t* db, uintptr_t addr, uint32_t size)
|
||||
{
|
||||
if(!addr || !size)
|
||||
return;
|
||||
if(size>MMAPSIZE-2*sizeof(blockmark_t)) {
|
||||
#ifndef USE_MMAP
|
||||
free((void*)addr);
|
||||
#else
|
||||
munmap((void*)addr, size);
|
||||
#endif
|
||||
kh_dynablocks_t *blocks = dblist_oversized;
|
||||
if(blocks) {
|
||||
khint_t k = kh_get(dynablocks, blocks, addr);
|
||||
if(k!=kh_end(blocks))
|
||||
kh_del(dynablocks, blocks, k);
|
||||
}
|
||||
return;
|
||||
}
|
||||
ActuallyFreeDynarecMap(db, addr, size);
|
||||
}
|
||||
|
||||
dynablocklist_t* getDB(uintptr_t idx)
|
||||
{
|
||||
return dynmap[idx];
|
||||
}
|
||||
|
||||
// each dynmap is 64k of size
|
||||
|
||||
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>>DYNAMAP_SHIFT);
|
||||
uintptr_t end = ((addr+size-1)>>DYNAMAP_SHIFT);
|
||||
for (uintptr_t i=idx; i<=end; ++i) {
|
||||
if(!dynmap[i]) {
|
||||
dynablocklist_t* p = NewDynablockList(i<<DYNAMAP_SHIFT, 1<<DYNAMAP_SHIFT, 0);
|
||||
if(arm_lock_storeifnull(&dynmap[i], p)!=p)
|
||||
FreeDynablockList(&p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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>>DYNAMAP_SHIFT);
|
||||
uintptr_t end = ((addr+size-1)>>DYNAMAP_SHIFT);
|
||||
for (uintptr_t i=idx; i<=end; ++i) {
|
||||
dynablocklist_t* dblist = dynmap[i];
|
||||
if(dblist) {
|
||||
if(destroy)
|
||||
FreeRangeDynablock(dblist, addr, size);
|
||||
else
|
||||
MarkRangeDynablock(dblist, addr, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ARM
|
||||
void arm_next(void);
|
||||
#endif
|
||||
|
||||
void addJumpTableIfDefault(void* addr, void* jmp)
|
||||
{
|
||||
const uintptr_t idx = ((uintptr_t)addr>>JMPTABL_SHIFT);
|
||||
if(box86_jumptable[idx] == box86_jmptbl_default) {
|
||||
uintptr_t* tbl = (uintptr_t*)malloc((1<<JMPTABL_SHIFT)*sizeof(uintptr_t));
|
||||
for(int i=0; i<(1<<JMPTABL_SHIFT); ++i)
|
||||
tbl[i] = (uintptr_t)arm_next;
|
||||
if(arm_lock_storeifref(&box86_jumptable[idx], tbl, box86_jmptbl_default)!=tbl)
|
||||
free(tbl);
|
||||
}
|
||||
const uintptr_t off = (uintptr_t)addr&((1<<JMPTABL_SHIFT)-1);
|
||||
arm_lock_storeifref(&box86_jumptable[idx][off], jmp, arm_next);
|
||||
}
|
||||
void setJumpTableDefault(void* addr)
|
||||
{
|
||||
const uintptr_t idx = ((uintptr_t)addr>>JMPTABL_SHIFT);
|
||||
if(box86_jumptable[idx] == box86_jmptbl_default) {
|
||||
return;
|
||||
}
|
||||
const uintptr_t off = (uintptr_t)addr&((1<<JMPTABL_SHIFT)-1);
|
||||
box86_jumptable[idx][off] = (uintptr_t)arm_next;
|
||||
}
|
||||
int isJumpTableDefault(void* addr)
|
||||
{
|
||||
const uintptr_t idx = ((uintptr_t)addr>>JMPTABL_SHIFT);
|
||||
if(box86_jumptable[idx] == box86_jmptbl_default) {
|
||||
return 1;
|
||||
}
|
||||
const uintptr_t off = (uintptr_t)addr&((1<<JMPTABL_SHIFT)-1);
|
||||
return (box86_jumptable[idx][off]==(uintptr_t)arm_next)?1:0;
|
||||
}
|
||||
uintptr_t getJumpTable()
|
||||
{
|
||||
return (uintptr_t)box86_jumptable;
|
||||
}
|
||||
|
||||
uintptr_t getJumpTableAddress(uintptr_t addr)
|
||||
{
|
||||
const uintptr_t idx = ((uintptr_t)addr>>JMPTABL_SHIFT);
|
||||
if(box86_jumptable[idx] == box86_jmptbl_default) {
|
||||
uintptr_t* tbl = (uintptr_t*)malloc((1<<JMPTABL_SHIFT)*sizeof(uintptr_t));
|
||||
for(int i=0; i<(1<<JMPTABL_SHIFT); ++i)
|
||||
tbl[i] = (uintptr_t)arm_next;
|
||||
if(arm_lock_storeifref(&box86_jumptable[idx], tbl, box86_jmptbl_default)!=tbl)
|
||||
free(tbl);
|
||||
}
|
||||
const uintptr_t off = (uintptr_t)addr&((1<<JMPTABL_SHIFT)-1);
|
||||
return (uintptr_t)&box86_jumptable[idx][off];
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
dynarec_log(LOG_DEBUG, "protectDB %p -> %p\n", (void*)addr, (void*)(addr+size-1));
|
||||
uintptr_t idx = (addr>>MEMPROT_SHIFT);
|
||||
uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT);
|
||||
for (uintptr_t i=idx; i<=end; ++i) {
|
||||
uint32_t prot = memprot[i];
|
||||
if(!(prot&PROT_DYNAREC)) {
|
||||
if(!prot)
|
||||
prot = PROT_READ | PROT_WRITE; // comes from malloc & co, so should not be able to execute
|
||||
memprot[i] = prot|PROT_DYNAREC;
|
||||
mprotect((void*)(i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, prot&~PROT_WRITE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
dynarec_log(LOG_DEBUG, "unprotectDB %p -> %p\n", (void*)addr, (void*)(addr+size-1));
|
||||
uintptr_t idx = (addr>>MEMPROT_SHIFT);
|
||||
uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT);
|
||||
for (uintptr_t i=idx; i<=end; ++i) {
|
||||
uint32_t prot = memprot[i];
|
||||
if(prot&PROT_DYNAREC) {
|
||||
memprot[i] = prot&~PROT_DYNAREC;
|
||||
mprotect((void*)(i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, prot&~PROT_DYNAREC);
|
||||
cleanDBFromAddressRange((i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void updateProtection(uintptr_t addr, uintptr_t size, uint32_t prot)
|
||||
{
|
||||
const uintptr_t idx = (addr>>MEMPROT_SHIFT);
|
||||
const uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT);
|
||||
for (uintptr_t i=idx; i<=end; ++i) {
|
||||
uint32_t dyn=(memprot[i]&PROT_DYNAREC);
|
||||
if(dyn && (prot&PROT_WRITE)) // need to remove the write protection from this block
|
||||
mprotect((void*)(i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, prot&~PROT_WRITE);
|
||||
memprot[i] = prot|dyn;
|
||||
}
|
||||
}
|
||||
|
||||
void forceProtection(uintptr_t addr, uintptr_t size, uint32_t prot)
|
||||
{
|
||||
const uintptr_t idx = (addr>>MEMPROT_SHIFT);
|
||||
const uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT);
|
||||
for (uintptr_t i=idx; i<=end; ++i) {
|
||||
mprotect((void*)(i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, prot&~PROT_DYNAREC);
|
||||
memprot[i] = prot;
|
||||
}
|
||||
}
|
||||
|
||||
void setProtection(uintptr_t addr, uintptr_t size, uint32_t prot)
|
||||
{
|
||||
const uintptr_t idx = (addr>>MEMPROT_SHIFT);
|
||||
const uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT);
|
||||
for (uintptr_t i=idx; i<=end; ++i) {
|
||||
memprot[i] = prot;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t getProtection(uintptr_t addr)
|
||||
{
|
||||
const uintptr_t idx = (addr>>MEMPROT_SHIFT);
|
||||
uint32_t ret = memprot[idx];
|
||||
return ret;
|
||||
}
|
||||
|
||||
int unlockCustommemMutex()
|
||||
{
|
||||
int ret = 0;
|
||||
int i = 0;
|
||||
#define GO(A, B) \
|
||||
i = checkUnlockMutex(&A); \
|
||||
if(i) { \
|
||||
ret|=(1<<B); \
|
||||
}
|
||||
GO(mutex_blocks, 0)
|
||||
#undef GO
|
||||
return ret;
|
||||
}
|
||||
|
||||
void relockCustommemMutex(int locks)
|
||||
{
|
||||
#define GO(A, B) \
|
||||
if(locks&(1<<B)) \
|
||||
pthread_mutex_lock(&A); \
|
||||
|
||||
GO(mutex_blocks, 0)
|
||||
#undef GO
|
||||
}
|
||||
|
||||
static void init_mutexes(void)
|
||||
{
|
||||
pthread_mutexattr_t attr;
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
|
||||
pthread_mutex_init(&mutex_blocks, &attr);
|
||||
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
}
|
||||
|
||||
static void atfork_child_custommem(void)
|
||||
{
|
||||
// (re))init mutex if it was lock before the fork
|
||||
init_mutexes();
|
||||
}
|
||||
|
||||
void init_custommem_helper(box86context_t* ctx)
|
||||
{
|
||||
if(inited) // already initialized
|
||||
return;
|
||||
inited = 1;
|
||||
init_mutexes();
|
||||
#ifdef DYNAREC
|
||||
#ifdef ARM
|
||||
for(int i=0; i<(1<<JMPTABL_SHIFT); ++i)
|
||||
box86_jmptbl_default[i] = (uintptr_t)arm_next;
|
||||
for(int i=0; i<JMPTABL_SIZE; ++i)
|
||||
box86_jumptable[i] = box86_jmptbl_default;
|
||||
#else
|
||||
#error Unsupported architecture!
|
||||
#endif
|
||||
#endif
|
||||
pthread_atfork(NULL, NULL, atfork_child_custommem);
|
||||
}
|
||||
|
||||
void fini_custommem_helper(box86context_t *ctx)
|
||||
{
|
||||
if(!inited)
|
||||
return;
|
||||
inited = 0;
|
||||
#ifdef DYNAREC
|
||||
if(box86_dynarec) {
|
||||
dynarec_log(LOG_DEBUG, "Free global Dynarecblocks\n");
|
||||
for (int i=0; i<mmapsize; ++i) {
|
||||
if(mmaplist[i].block)
|
||||
#ifdef USE_MMAP
|
||||
munmap(mmaplist[i].block, mmaplist[i].size);
|
||||
#else
|
||||
free(mmaplist[i].block);
|
||||
#endif
|
||||
if(mmaplist[i].dblist) {
|
||||
kh_destroy(dynablocks, mmaplist[i].dblist);
|
||||
mmaplist[i].dblist = NULL;
|
||||
}
|
||||
if(mmaplist[i].helper) {
|
||||
free(mmaplist[i].helper);
|
||||
mmaplist[i].helper = NULL;
|
||||
}
|
||||
}
|
||||
if(dblist_oversized) {
|
||||
kh_destroy(dynablocks, dblist_oversized);
|
||||
dblist_oversized = NULL;
|
||||
}
|
||||
mmapsize = 0;
|
||||
mmapcap = 0;
|
||||
dynarec_log(LOG_DEBUG, "Free dynamic Dynarecblocks\n");
|
||||
uintptr_t idx = 0;
|
||||
uintptr_t end = ((0xFFFFFFFF)>>DYNAMAP_SHIFT);
|
||||
for (uintptr_t i=idx; i<=end; ++i)
|
||||
if(dynmap[i])
|
||||
FreeDynablockList(&dynmap[i]);
|
||||
free(mmaplist);
|
||||
for (int i=0; i<DYNAMAP_SIZE; ++i)
|
||||
if(box86_jumptable[i]!=box86_jmptbl_default)
|
||||
free(box86_jumptable[i]);
|
||||
}
|
||||
#endif
|
||||
for(int i=0; i<n_blocks; ++i)
|
||||
#ifdef USE_MMAP
|
||||
munmap(p_blocks[i].block, p_blocks[i].size);
|
||||
#else
|
||||
free(p_blocks[i].block);
|
||||
#endif
|
||||
free(p_blocks);
|
||||
pthread_mutex_destroy(&mutex_blocks);
|
||||
}
|
||||
+487
-90
@@ -21,28 +21,29 @@ Op is 20-27
|
||||
#define xEBP 9
|
||||
#define xESI 10
|
||||
#define xEDI 11
|
||||
#define xEIP 12
|
||||
#define xFlags 12
|
||||
#define xEIP 14
|
||||
// scratch registers
|
||||
#define x1 1
|
||||
#define x2 2
|
||||
#define x3 3
|
||||
#define x12 12
|
||||
#define x14 14
|
||||
// emu is r0
|
||||
#define xEmu 0
|
||||
// ARM SP is r13
|
||||
#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
|
||||
@@ -77,14 +78,18 @@ Op is 20-27
|
||||
// movt dst, #imm16
|
||||
#define MOVT(dst, imm16) EMIT(0xe3400000 | ((dst) << 12) | (((imm16) & 0xf000) << 4) | brIMM((imm16) & 0x0fff) )
|
||||
// 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) { \
|
||||
MOVT(dst, (((uint32_t)imm32)>>16)); }
|
||||
#define MOV32(dst, imm32) \
|
||||
if((~(uint32_t)(imm32))<0x100) { \
|
||||
MVN_IMM8(dst, ~(uint32_t)(imm32), 0); \
|
||||
} else { \
|
||||
MOVW(dst, ((uint32_t)imm32)&0xffff); \
|
||||
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))
|
||||
#define MOV32_(dst, imm32) \
|
||||
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,49 +98,84 @@ 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.cond dst, src lsr imm5
|
||||
#define MOV_REG_LSR_IMM5_COND(cond, dst, src, imm5) EMIT(cond | 0x01a00000 | ((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 dst, src rrx (1)
|
||||
#define MOV_REG_RRX(dst, src) EMIT(0xe1a00000 | ((dst) << 12) | (src) | (0<<4) | (3<<5) | ((0)<<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.s dst, src rrx (1)
|
||||
#define MOVS_REG_RRX(dst, src) EMIT(0xe1b00000 | ((dst) << 12) | (src) | (0<<4) | (3<<5) | ((0)<<7))
|
||||
|
||||
// mov.s dst, src lsl rs
|
||||
#define MOVS_REG_LSL_REG(dst, src, rs) EMIT(0xe1b00000 | ((dst) << 12) | (src) | (1<<4) | (0<<5) | ((rs)<<8))
|
||||
// mov.s dst, src lsr rs
|
||||
#define MOVS_REG_LSR_REG(dst, src, rs) EMIT(0xe1b00000 | ((dst) << 12) | (src) | (1<<4) | (1<<5) | ((rs)<<8))
|
||||
// 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.cond dst, src lsl rs
|
||||
#define MOV_REG_LSL_REG_COND(cond, dst, src, rs) EMIT(cond | 0x01a00000 | ((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) \
|
||||
EMIT(0xe2400000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
|
||||
// sub cond dst, src, #(imm8)
|
||||
#define SUB_COND_IMM8(dst, src, imm8) \
|
||||
#define SUB_COND_IMM8(cond, dst, src, imm8) \
|
||||
EMIT((cond) | 0x02400000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
|
||||
// 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) )
|
||||
// rsc dst, src, #(imm8)
|
||||
#define RSC_IMM8(dst, src, imm8) \
|
||||
EMIT(0xe2E00000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
|
||||
|
||||
// and dst, src1, src2, lsl #imm
|
||||
#define AND_REG_LSL_IMM5(dst, src1, src2, imm5) \
|
||||
@@ -149,33 +189,65 @@ Op is 20-27
|
||||
// and dst, src, #(imm8)
|
||||
#define AND_IMM8(dst, src, imm8) \
|
||||
EMIT(0xe2000000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
|
||||
// and dst, src1, #imm ror rot*2
|
||||
#define AND_IMM8_ROR(dst, src, imm8, rot) \
|
||||
EMIT(0xe2000000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | brIMM(imm8) )
|
||||
// and.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(dst, 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 dst, src, #imm8 ror rot*2
|
||||
#define ADD_IMM8_ROR(dst, src, imm8, rot) \
|
||||
EMIT(0xe2800000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | 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) )
|
||||
// cmp.cond.s dst, src1, src2, lsl #imm
|
||||
#define CMPS_REG_LSL_IMM5_COND(cond, src1, src2, imm5) \
|
||||
EMIT((cond) | 0x01500000 | ((0) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
|
||||
// cmp.s dst, src, #imm
|
||||
#define CMPS_IMM8_COND(cond, src, imm8) \
|
||||
EMIT((cond) | 0x03500000 | ((0) << 12) | ((src) << 16) | brIMM(imm8) )
|
||||
// cmp.s dst, src, #imm
|
||||
#define CMPS_IMM8(src, imm8) \
|
||||
EMIT(0xe3500000 | ((0) << 12) | ((src) << 16) | brIMM(imm8) )
|
||||
// cmn.s dst, src, #imm
|
||||
#define CMNS_IMM8_COND(cond, src, imm8) \
|
||||
EMIT((cond) | 0x03700000 | ((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 +255,48 @@ 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, src2, lsr #imm
|
||||
#define ORR_REG_LSR_IMM5(dst, src1, src2, imm5) \
|
||||
EMIT(0xe1800000 | ((dst) << 12) | ((src1) << 16) | brLSR(imm5, src2) )
|
||||
// orr.s dst, src1, src2, lsr #imm
|
||||
#define ORRS_REG_LSR_IMM5(dst, src1, src2, imm5) \
|
||||
EMIT(0xe1900000 | ((dst) << 12) | ((src1) << 16) | brLSR(imm5, src2) )
|
||||
// orr.s dst, src1, src2, lsl rs
|
||||
#define ORRS_REG_LSL_REG(dst, src1, src2, rs) \
|
||||
EMIT(0xe1900000 | ((dst) << 12) | ((src1) << 16) | brRLSL(rs, src2) )
|
||||
// orr dst, src1, #imm8
|
||||
#define ORR_IMM8(dst, src, imm8, rot) \
|
||||
EMIT(0xe3800000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | imm8 )
|
||||
// orr dst, src1, src2, lsl #rs
|
||||
// orr.s dst, src1, #imm8
|
||||
#define ORRS_IMM8(dst, src, imm8, rot) \
|
||||
EMIT(0xe3900000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | imm8 )
|
||||
// orr.cond dst, src1, #imm8 ror rot*2
|
||||
#define ORR_IMM8_COND(cond, dst, src, imm8, rot) \
|
||||
EMIT((cond) | 0x03800000 | ((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 dst, src, #(imm8 ror rot*2)
|
||||
#define XOR_IMM8_ROR(dst, src, imm8, rot) \
|
||||
EMIT(0xe2200000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | brIMM(imm8) )
|
||||
// xor.cond dst, src, #(imm8)
|
||||
#define XOR_IMM8_COND(cond, dst, src, imm8) \
|
||||
EMIT(cond | 0x02200000 | ((dst) << 12) | ((src) << 16) | brIMM(imm8) )
|
||||
@@ -212,21 +306,33 @@ Op is 20-27
|
||||
// xor dst, src1, src2, lsl #imm
|
||||
#define XOR_REG_LSR_IMM8(dst, src1, src2, imm8) \
|
||||
EMIT(0xe0200000 | ((dst) << 12) | ((src1) << 16) | brLSR(imm8, src2) )
|
||||
// xor.cond dst, src1, src2, lsl #imm
|
||||
#define XOR_REG_LSR_IMM8_COND(cond, dst, src1, src2, imm8) \
|
||||
EMIT(cond | 0x00200000 | ((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) )
|
||||
// bic dst, src, IMM8
|
||||
#define BIC_REG_LSL_IMM5(dst, src1, src2, imm5) \
|
||||
EMIT(0xe1c00000 | ((dst) << 12) | ((src1) << 16) | brLSL(imm5, src2) )
|
||||
// bic dst, src, IMM8 ror rot*2
|
||||
#define BIC_IMM8(dst, src, imm8, rot) \
|
||||
EMIT(0xe3c00000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | imm8 )
|
||||
// bic.cond dst, src, IMM8
|
||||
#define BIC_IMM8_COND(cond, dst, src, imm8, rot) \
|
||||
EMIT((cond) | 0x03c00000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | imm8 )
|
||||
// bic dst, src1, #imm ror rot*2
|
||||
#define BIC_IMM8_ROR(dst, src, imm8, rot) \
|
||||
EMIT(0xe3c00000 | ((dst) << 12) | ((src) << 16) | ((rot)<<8) | brIMM(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 )
|
||||
#define MVN_IMM8(dst, imm8, rot) \
|
||||
EMIT(0xe3e00000 | ((dst) << 12) | (rot)<<8 | ((imm8)&0xff) )
|
||||
// mvn dst, src1, src2, lsr #imm
|
||||
#define MVN_REG_LSR_IMM8(dst, rm, imm8) \
|
||||
EMIT(0xe1e00000 | ((dst) << 12) | (0 << 16) | brLSR(imm8, rm) )
|
||||
@@ -234,12 +340,9 @@ 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)
|
||||
#define SDT_OFF(Cond, P, U, B, W, L, Rn, Rd, Imm12) (Cond | (0b00<<26) | (0<<25) | (P<<24) | (U<<23) | (B<<22) | (U<<23) | (W<<21) | (L<<20) | (Rn<<16) | (Rd<<12) | Imm12)
|
||||
// ldr reg, [addr, #+/-imm9]
|
||||
#define LDR_IMM9(reg, addr, imm9) EMIT(0xe5100000 | (((imm9)<0)?0:1)<<23 | ((reg) << 12) | ((addr) << 16) | brIMM(imm9) )
|
||||
// ldrxx reg, [addr, #+/-imm9]
|
||||
@@ -264,9 +367,15 @@ 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) )
|
||||
// str with cond reg, [addr, #+/-imm9]
|
||||
#define STR_IMM9_COND(cond, reg, addr, imm9) EMIT(cond | 0x05000000 | (((imm9)<0)?0:1)<<23 | ((reg) << 12) | ((addr) << 16) | brIMM(imm9) )
|
||||
// str reg, [addr, #+/-imm9]!
|
||||
#define STR_IMM9_W(reg, addr, imm9) EMIT(0xe5200000 | (((imm9)<0)?0:1)<<23 | ((reg) << 12) | ((addr) << 16) | brIMM(imm9) )
|
||||
// strb reg, [addr, #+/-imm9]
|
||||
#define STRB_IMM9(reg, addr, imm9) EMIT(0xe5400000 | (((imm9)<0)?0:1)<<23 | ((reg) << 12) | ((addr) << 16) | brIMM(imm9) )
|
||||
// str reg, [addr], #+/-imm9
|
||||
@@ -283,6 +392,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 +404,39 @@ 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))
|
||||
|
||||
// push reg to xESP
|
||||
#define PUSH1(reg) STR_IMM9_W(reg, xESP, -4)
|
||||
|
||||
// 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))
|
||||
|
||||
// pop reg from xESP
|
||||
#define POP1(reg) LDRAI_IMM9_W(reg, xESP, 4)
|
||||
|
||||
// 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,19 +445,32 @@ 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 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))
|
||||
#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))
|
||||
#define LDRHB_IMM8(reg, addr, imm8) EMIT(HWS_OFF(c__, 1, (((imm8)<0)?0:1), 1, 1, addr, reg, 0, 1, abs(imm8)))
|
||||
#define LDRHA_IMM8(reg, addr, imm8) EMIT(HWS_OFF(c__, 0, (((imm8)<0)?0:1), 0, 1, addr, reg, 0, 1, abs(imm8)))
|
||||
#define STRHB_IMM8(reg, addr, imm8) EMIT(HWS_OFF(c__, 1, (((imm8)<0)?0:1), 1, 0, addr, reg, 0, 1, abs(imm8)))
|
||||
#define STRHA_IMM8(reg, addr, imm8) EMIT(HWS_OFF(c__, 0, (((imm8)<0)?0:1), 0, 0, addr, reg, 0, 1, abs(imm8)))
|
||||
#define PUSH16(reg, addr) EMIT(HWS_OFF(c__, 1, 0, 1, 0, addr, reg, 0, 1, 2))
|
||||
#define POP16(reg, addr) EMIT(HWS_OFF(c__, 0, 1, 0, 1, addr, reg, 0, 1, 2))
|
||||
|
||||
// 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 MLS_gen(Cond, Rd, Ra, Rm, Rn) (Cond | 0b00000110<<20 | (Rd)<<16 | (Ra)<<12 | (Rm)<<8 | 0b1001<<4 | (Rn))
|
||||
//MLS : Rd = Ra - Rm*Rn
|
||||
#define MLS(Rd, Rm, Rn, Ra) EMIT(MLS_gen(c__, Rd, Ra, 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))
|
||||
// Signed Mul between Rn[0..15] * Rm[0..15] => Rd
|
||||
#define SMULBB(Rd, Rn, Rm) EMIT(SMUL_16_gen(c__, Rd, Rm, 0, 0, Rn))
|
||||
@@ -356,18 +486,30 @@ Op is 20-27
|
||||
|
||||
// UBFX: Unsigned Bit Field Extract: extract any number of bits from Rn, zero extend and put in Rd
|
||||
#define UBFX(rd, rn, lsb, width) EMIT(c__ | (0b0111111<<21) | (((width)-1)<<16) | ((rd)<<12) | ((lsb)<<7) | (0b101<<4) | (rn))
|
||||
// SBFX: Signed Bit Field Extract: extract any number of bits from Rn, zero extend and put in Rd
|
||||
#define SBFX(rd, rn, lsb, width) EMIT(c__ | (0b0111101<<21) | (((width)-1)<<16) | ((rd)<<12) | ((lsb)<<7) | (0b101<<4) | (rn))
|
||||
|
||||
// BFI: Bit Field Insert: copy any number of low order bit from Rn to any position of Rd
|
||||
#define BFI(rd, rn, lsb, width) EMIT(c__ | (0b0111110<<21) | (((lsb)+(width)-1)<<16) | ((rd)<<12) | ((lsb)<<7) | (0b001<<4) | (rn))
|
||||
// BFI_COND: Bit Field Insert with condition: copy any number of low order bit from Rn to any position of Rd
|
||||
#define BFI_COND(cond, rd, rn, lsb, width) EMIT(cond | (0b0111110<<21) | (((lsb)+(width)-1)<<16) | ((rd)<<12) | ((lsb)<<7) | (0b001<<4) | (rn))
|
||||
|
||||
// BFC: Bit Field Clear: clear any number of adjacent bit from Rd
|
||||
#define BFC(rd, lsb, width) EMIT(c__ | (0b0111110<<21) | (((lsb)+(width)-1)<<16) | ((rd)<<12) | ((lsb)<<7) | (0b001<<4) | 0b1111)
|
||||
// BFC_COND: Bit Field Clear with condition: clear any number of adjacent bit from Rd
|
||||
#define BFC_COND(cond, rd, lsb, width) EMIT(cond | (0b0111110<<21) | (((lsb)+(width)-1)<<16) | ((rd)<<12) | ((lsb)<<7) | (0b001<<4) | 0b1111)
|
||||
|
||||
// REV: Reverse byte of a 32bits word
|
||||
#define REV(rd, rm) EMIT(c__ | (0b01101<<23) | (0<<22) | (0b11<<20) | (0b1111<<16) | ((rd)<<12) | (0b1111<<8) | (0b0011<<4) | (rm))
|
||||
#define REV(rd, rm) EMIT(c__ | (0b01101<<23) | (0<<22) | (0b11<<20) | (0b1111<<16) | ((rd)<<12) | (0b1111<<8) | (0b0011<<4) | (rm))
|
||||
// REV16: Reverse byte of a 16bits word
|
||||
#define REV16(rd, rm) EMIT(c__ | (0b01101<<23) | (0<<22) | (0b11<<20) | (0b1111<<16) | ((rd)<<12) | (0b1111<<8) | (0b1011<<4) | (rm))
|
||||
|
||||
#define SSAT_gen(cond, sat_imm, Rd, imm5, sh, Rn) (cond | 0b0110101<<21 | (sat_imm)<<16 | (Rd)<<12 | (imm5)<<7 | (sh)<<6 | 0b01<<4 | (Rn))
|
||||
// Signed Staturate Rn to 2^(staturate_to-1) into Rd. Optionnaly shift left Rn before saturate
|
||||
#define SSAT_REG_LSL_IMM5(Rd, saturate_to, Rn, shift) EMIT(SSAT_gen(c__, (saturate_to)-1, Rd, shift, 0, Rn))
|
||||
// Signed Staturate Rn to 2^(staturate_to-1) into Rd. Optionnaly shift left Rn before saturate
|
||||
#define SSAT_REG_LSL_IMM5_COND(cond, Rd, saturate_to, Rn, shift) EMIT(SSAT_gen((cond), (saturate_to)-1, Rd, shift, 0, Rn))
|
||||
|
||||
#define USAT_gen(cond, sat_imm, Rd, imm5, sh, Rn) (cond | 0b0110111<<21 | (sat_imm)<<16 | (Rd)<<12 | (imm5)<<7 | (sh)<<6 | 0b01<<4 | (Rn))
|
||||
// Unsigned Staturate Rn to 2^(staturate_to-1) into Rd. Optionnaly shift left Rn before saturate
|
||||
#define USAT_REG_LSL_IMM5(Rd, saturate_to, Rn, shift) EMIT(SSAT_gen(c__, (saturate_to), Rd, shift, 0, Rn))
|
||||
@@ -384,11 +526,33 @@ Op is 20-27
|
||||
|
||||
#define LDREXD_gen(cond, Rn, Rt) (cond | 0b000<<25 | 0b11011<<20 | (Rn)<<16 | (Rt)<<12 | 0b1111<<8 | 0b1001<<4 | 0b1111)
|
||||
// Load Exclusive Rt/Rt+1 from Rn (tagging the memory)
|
||||
#define LDREXD(Rn, Rt) EMIT(LDREXD_gen(c__, Rn, Rt))
|
||||
#define LDREXD(Rt, Rn) EMIT(LDREXD_gen(c__, Rn, Rt))
|
||||
#define LDREXD_COND(cond, Rt, Rn) EMIT(LDREXD_gen(cond, Rn, Rt))
|
||||
|
||||
#define STREXD_gen(cond, Rd, Rn, Rt) (cond | 0b000<<25 | 0b11010<<20 | (Rn)<<16 | (Rd)<<12 | 0b1111<<8 | 0b1001<<4 | (Rt))
|
||||
// Store Exclusive Rt/Rt+1 to Rn, with result in Rd if tag is ok (Rd!=Rn && Rd!=Rt && Rd!=Rt+1), Rd==1 if store failed
|
||||
#define STREXD(Rd, Rn, Rt) EMIT(STREXD_gen(c__, Rd, Rn, Rt))
|
||||
#define STREXD(Rd, Rt, Rn) EMIT(STREXD_gen(c__, Rd, Rn, Rt))
|
||||
#define STREXD_COND(cond, Rd, Rt, Rn) EMIT(STREXD_gen(cond, Rd, Rn, Rt))
|
||||
|
||||
#define LDREX_gen(cond, Rn, Rt) (cond | 0b0001100<<21 | 1<<20 | (Rn)<<16 | (Rt)<<12 | 0b1111<<8 | 0b1001<<4 | 0b1111)
|
||||
// Load Exclusive Rt from Rn (tagging the memory)
|
||||
#define LDREX(Rt, Rn) EMIT(LDREX_gen(c__, Rn, Rt))
|
||||
#define LDREX_COND(cond, Rt, Rn) EMIT(LDREX_gen(cond, Rn, Rt))
|
||||
|
||||
#define STREX_gen(cond, Rd, Rn, Rt) (cond | 0b0001100<<21 | 0<<20 | (Rn)<<16 | (Rd)<<12 | 0b1111<<8 | 0b1001<<4 | (Rt))
|
||||
// Store Exclusive Rt to Rn, with result in Rd=0 if tag is ok, Rd==1 if store failed (Rd!=Rn && Rd!=Rt)
|
||||
#define STREX(Rd, Rt, Rn) EMIT(STREX_gen(c__, Rd, Rn, Rt))
|
||||
#define STREX_COND(cond, Rd, Rt, Rn) EMIT(STREX_gen(cond, Rd, Rn, Rt))
|
||||
|
||||
#define LDREXB_gen(cond, Rn, Rt) (cond | 0b0001110<<21 | 1<<20 | (Rn)<<16 | (Rt)<<12 | 0b1111<<8 | 0b1001<<4 | 0b1111)
|
||||
// Load Exclusive Byte Rt from Rn (tagging the memory)
|
||||
#define LDREXB(Rt, Rn) EMIT(LDREXB_gen(c__, Rn, Rt))
|
||||
#define LDREXB_COND(cond, Rt, Rn) EMIT(LDREXB_gen(cond, Rn, Rt))
|
||||
|
||||
#define STREXB_gen(cond, Rd, Rn, Rt) (cond | 0b0001110<<21 | 0<<20 | (Rn)<<16 | (Rd)<<12 | 0b1111<<8 | 0b1001<<4 | (Rt))
|
||||
// Store Exclusive byte Rt to Rn, with result in Rd=0 if tag is ok, Rd==1 if store failed (Rd!=Rn && Rd!=Rt)
|
||||
#define STREXB(Rd, Rt, Rn) EMIT(STREXB_gen(c__, Rd, Rn, Rt))
|
||||
#define STREXB_COND(cond, Rd, Rt, Rn) EMIT(STREXB_gen(cond, Rd, Rn, Rt))
|
||||
|
||||
// Count leading 0 bit of Rm, store result in Rd
|
||||
#define CLZ(Rd, Rm) EMIT(c__ | 0b00010110<<20 | 0b1111<<16 | (Rd)<<12 | 0b1111<<8 | 0b0001<<4 | (Rm))
|
||||
@@ -401,8 +565,29 @@ Op is 20-27
|
||||
// Preload Cache Rn-Rm
|
||||
#define PLDn(Rn, Rm) EMIT(PLD_gen(0, 1, Rn, 0, 0, Rm))
|
||||
|
||||
// VFPU
|
||||
#define TRANSFERT64(C, op) ((0b1100<<24) | (0b010<<21) | (0b101<<9) | ((C)<<8) | ((op)<<4))
|
||||
#define DMB_gen(opt) (0b1111<<28 | 0b01010111<<20 | 0b1111<<16 | 0b1111<<12 | 0b0000<<8 | 0b0101<<4 | (opt))
|
||||
// Data memory barrier Inner Sharable
|
||||
#define DMB_ISH() EMIT(DMB_gen(0b1011))
|
||||
|
||||
#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, Rn, Rm) 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, Rn, Rm) EMIT(UDIV_gen(c__, Rd, Rm, Rn))
|
||||
|
||||
// Yield
|
||||
#define YIELD(cond) EMIT(cond | 0b00110010<<20 | 0b1111<<12 | 1)
|
||||
|
||||
// UDF
|
||||
#define UDF(imm16) EMIT(0b1110<<28 | 0b011<<25 | 0b11111<<20 | (((imm16)>>4)&0xfff) | 0b1111<<4 | ((imm16)&0xf))
|
||||
|
||||
// Move from FPSCR to Arm register
|
||||
#define VMRS(Rt) EMIT(c__ | (0b1110<<24) | (0b1111<<20) | (0b0001<<16) | ((Rt)<<12) | (0b1010<<8) | (0b0001<<4) | (0b0000))
|
||||
@@ -436,6 +621,8 @@ Op is 20-27
|
||||
#define VMOVcond_32(cond, Sd, Sm) EMIT(cond | (0b11101<<23) | (((Sd)&1)<<22) | (0b11<<20) | ((((Sd)>>1)&15)<<12) | (0b101<<9) | (0<<8) | (0b01<<6) | (((Sm)&1)<<5) | (((Sm)>>1)&15))
|
||||
// Move between Sd and Imm
|
||||
#define VMOV_i_32(Sd, Imm8) EMIT(c__ | (0b11101<<23) | (((Sd)&1)<<22) | (0b11<<20) | ((((Imm8)>>4)&0xf)<<16) | ((((Sd)>>1)&15)<<12) | (0b101<<9) | (0<<8) | (0b00<<6) | ((Imm8)&15))
|
||||
// Move between Dd and Imm
|
||||
#define VMOV_i_64(Dd, Imm8) EMIT(c__ | (0b11101<<23) | ((((Dd)>>4)&1)<<22) | (0b11<<20) | ((((Imm8)>>4)&0xf)<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | (0b00<<6) | ((Imm8)&15))
|
||||
|
||||
#define VMOVtoDx_gen(Vd, D, Rt, opc1, opc2) (0b1110<<24 | 0<<23 | (opc1)<<21 | (Vd)<<16 | (Rt)<<12 | 0b1011<<8 | (D)<<7 | (opc2)<<5 | 1<<4)
|
||||
// Move between Rt and Dm[x]
|
||||
@@ -474,10 +661,14 @@ Op is 20-27
|
||||
|
||||
// Convert from double Dm to int32 Sd, with Round toward Zero mode
|
||||
#define VCVT_S32_F64(Sd, Dm) EMIT(c__ | (0b1110<<24) | (1<<23) | (((Sd)&1)<<22) | (0b111<<19) | (0b101<<16) | ((((Sd)>>1)&15)<<12) | (0b101<<9) | (1<<8) | (1<<7) | (1<<6) | ((((Dm)>>4)&1)<<5) | ((Dm)&15) )
|
||||
// Convert from double Dm to uint32 Sd, with Round toward Zero mode
|
||||
#define VCVT_U32_F64(Sd, Dm) EMIT(c__ | (0b1110<<24) | (1<<23) | (((Sd)&1)<<22) | (0b111<<19) | (0b100<<16) | ((((Sd)>>1)&15)<<12) | (0b101<<9) | (1<<8) | (1<<7) | (1<<6) | ((((Dm)>>4)&1)<<5) | ((Dm)&15) )
|
||||
// Convert from double Dm to int32 Sd, with Round selection from FPSCR
|
||||
#define VCVTR_S32_F64(Sd, Dm) EMIT(c__ | (0b1110<<24) | (1<<23) | (((Sd)&1)<<22) | (0b111<<19) | (0b101<<16) | ((((Sd)>>1)&15)<<12) | (0b101<<9) | (1<<8) | (0<<7) | (1<<6) | ((((Dm)>>4)&1)<<5) | ((Dm)&15) )
|
||||
// Convert from int32 Sm to double Dd
|
||||
#define VCVT_F64_S32(Dd, Sm) EMIT(c__ | (0b1110<<24) | (1<<23) | ((((Dd)>>4)&1)<<22) | (0b111<<19) | (0b000<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | (1<<7) | (1<<6) | (((Sm)&1)<<5) | (((Sm)>>1)&15) )
|
||||
// Convert from uint32 Sm to double Dd
|
||||
#define VCVT_F64_U32(Dd, Sm) EMIT(c__ | (0b1110<<24) | (1<<23) | ((((Dd)>>4)&1)<<22) | (0b111<<19) | (0b000<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | (0<<7) | (1<<6) | (((Sm)&1)<<5) | (((Sm)>>1)&15) )
|
||||
// Convert from single Sm to int32 Sd, with Round toward Zero mode
|
||||
#define VCVT_S32_F32(Sd, Sm) EMIT(c__ | (0b1110<<24) | (1<<23) | (((Sd)&1)<<22) | (0b111<<19) | (0b101<<16) | ((((Sd)>>1)&15)<<12) | (0b101<<9) | (0<<8) | (1<<7) | (1<<6) | (((Sm)&1)<<5) | (((Sm)>>1)&15) )
|
||||
// Convert from single Sm to int32 Sd, with Round selection from FPSCR
|
||||
@@ -485,21 +676,21 @@ Op is 20-27
|
||||
// Convert from int32 Sm to single Dd
|
||||
#define VCVT_F32_S32(Sd, Sm) EMIT(c__ | (0b1110<<24) | (1<<23) | (((Sd)&1)<<22) | (0b111<<19) | (0b000<<16) | ((((Sd)>>1)&15)<<12) | (0b101<<9) | (0<<8) | (1<<7) | (1<<6) | (((Sm)&1)<<5) | (((Sm)>>1)&15) )
|
||||
|
||||
#define VCVT_16_gen(cond, D, op, U, Vd, sf, sx, i, imm4) (cond | 0b1110<<24 | 1<<23 | (D)<<22 | 0b11<<20 | 1<<19 | (op)<<18 | 1<<17 | (U)<<16 | (Vd)<<12 | 0b101<<9 | (sf)<<8 | (sx)<<7 | 1<<6 | (i)<<5 | (imm4))
|
||||
#define VCVT_FP_gen(cond, D, op, U, Vd, sf, sx, i, imm4) (cond | 0b1110<<24 | 1<<23 | (D)<<22 | 0b11<<20 | 1<<19 | (op)<<18 | 1<<17 | (U)<<16 | (Vd)<<12 | 0b101<<9 | (sf)<<8 | (sx)<<7 | 1<<6 | (i)<<5 | (imm4))
|
||||
// Inplace convert from F64 to S16. Rounding is not selectable
|
||||
#define VCVT_S16_F64(Dd) EMIT(VCVT_16_gen(c__, ((Dd)>>4)&1, 1, 0, (Dd)&15, 1, 0, 16&1, (16>>1)&15))
|
||||
#define VCVT_S16_F64(Dd) EMIT(VCVT_FP_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 +705,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,15 +714,26 @@ 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) )
|
||||
// Neg F64 Dd = - Dm
|
||||
#define VNEG_F64_cond(cond, Dd, Dm) EMIT((cond) | (0b1110<<24) | (1<<23) | ((((Dd)>>4)&1)<<22) | (0b11<<20) | (0b0001<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | (0b01<<6) | ((((Dm)>>4)&1)<<5) | ((Dm)&15) )
|
||||
// Neg F32 Dd = - Dm
|
||||
#define VNEG_F32(Sd, Sm) EMIT(c__ | (0b1110<<24) | (1<<23) | (((Sd)&1)<<22) | (0b11<<20) | (0b0001<<16) | ((((Sd)>>1)&15)<<12) | (0b101<<9) | (0<<8) | (0b01<<6) | (((Sm)&1)<<5) | (((Sm)>>1)&15) )
|
||||
|
||||
// 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) )
|
||||
|
||||
// Abs Dd = |Dm|
|
||||
#define VABS_F64(Dd, Dm) EMIT(c__ | (0b11101<<23) | ((((Dd)>>4)&1)<<22) | (0b11<<20) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | (0b11<<6) | ((((Dm)>>4)&1)<<5) | ((Dm)&15))
|
||||
// Abs Dd = |Dm|
|
||||
#define VABS_F32(Sd, Sm) EMIT(c__ | (0b11101<<23) | (((Sd)&1)<<22) | (0b11<<20) | ((((Sd)>>1)&15)<<12) | (0b101<<9) | (0<<8) | (0b11<<6) | (((Sm)&1)<<5) | (((Sm)>>1)&15))
|
||||
|
||||
// MLS Dd = Dd - Dn*Dm
|
||||
#define VMLS_F64(Dd, Dn, Dm) EMIT(c__ | (0b1110<<24) | (0<<23) | ((((Dd)>>4)&1)<<22) | (0b00<<20) | (((Dn)&15)<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | ((((Dn)>>4)&1)<<7) | 1<<6 | ((((Dm)>>4)&1)<<5) | ((Dm)&15) )
|
||||
// MLA Dd = Dd + Dn*Dm
|
||||
#define VMLA_F64(Dd, Dn, Dm) EMIT(c__ | (0b1110<<24) | (0<<23) | ((((Dd)>>4)&1)<<22) | (0b00<<20) | (((Dn)&15)<<16) | (((Dd)&15)<<12) | (0b101<<9) | (1<<8) | ((((Dn)>>4)&1)<<7) | 0<<6 | ((((Dm)>>4)&1)<<5) | ((Dm)&15) )
|
||||
|
||||
// NEON
|
||||
|
||||
@@ -590,12 +792,26 @@ Op is 20-27
|
||||
#define VEORQ(Dd, Dn, Dm) EMIT(VEOR_gen(((Dd)>>4)&1, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#define VMOVL_gen(U, D, imm3, Vd, M, Vm) (0b1111<<28 | 0b001<<25 | (U)<<24 | 1<<23 | (D)<<22 | (imm3)<<19 | (Vd)<<12 | 0b1010<<8 | (M)<<5 | 1<<4 | (Vm))
|
||||
#define VMOVL_S8(Dd, Dm) EMIT(VMOVL_gen(0, ((Dd)>>4)&1, 0b001, (Dd)&15, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VMOVL_U8(Dd, Dm) EMIT(VMOVL_gen(1, ((Dd)>>4)&1, 0b001, (Dd)&15, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VMOVL_S32(Dd, Dm) EMIT(VMOVL_gen(0, ((Dd)>>4)&1, 0b100, (Dd)&15, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VMOVL_U32(Dd, Dm) EMIT(VMOVL_gen(1, ((Dd)>>4)&1, 0b100, (Dd)&15, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#define VMOV_gen(D,Vd, M, Vm, Q) (0b1111<<28 | 0b0010<<24 | 0<<23 | (D)<<22 | 0b10<<20 | (Vm)<<16 | (Vd)<<12 | 0b0001<<8 | (M)<<7 | (Q)<<6 | (M)<<5 | 1<<4 | (Vm))
|
||||
#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 VMOVD(Dd, Dm) if((Dd)!=(Dm)) {EMIT(VMOV_gen(((Dd)>>4)&1, (Dd)&15, ((Dm)>>4)&1, (Dm)&15, 0));}
|
||||
#define VMOVQ(Dd, Dm) if((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))
|
||||
// Dd <= imm8 in high bits
|
||||
#define VMOV_H32(Dd, imm8) EMIT(VMOV_igen(((imm8)>>7)&1, ((Dd)>>4)&1, ((imm8)>>4)&7, (Dd)&15, 0b0110, 0, 0, (imm8)&15))
|
||||
// Dd <= imm8 in high bits
|
||||
#define VMOV_H16(Dd, imm8) EMIT(VMOV_igen(((imm8)>>7)&1, ((Dd)>>4)&1, ((imm8)>>4)&7, (Dd)&15, 0b1010, 0, 0, (imm8)&15))
|
||||
// Qd <= imm8 in high bits
|
||||
#define VMOVQ_H32(Dd, imm8) EMIT(VMOV_igen(((imm8)>>7)&1, ((Dd)>>4)&1, ((imm8)>>4)&7, (Dd)&15, 0b0110, 1, 0, (imm8)&15))
|
||||
// Qd <= imm8 in high bits
|
||||
#define VMOVQ_H16(Dd, imm8) EMIT(VMOV_igen(((imm8)>>7)&1, ((Dd)>>4)&1, ((imm8)>>4)&7, (Dd)&15, 0b1010, 1, 0, (imm8)&15))
|
||||
|
||||
#define VLD1LANE_gen(D, Rn, Vd, size, index_align, Rm) (0b1111<<28 | 0b0100<<24 | 1<<23 | (D)<<22 | 0b10<<20 | (Rn)<<16 | (Vd)<<12 | (size)<<10 | (index_align)<<4 | (Rm))
|
||||
#define VLD1LANE_8(Dd, Rn, index) EMIT(VLD1LANE_gen(((Dd)>>4)&1, Rn, (Dd)&15, 0, (index)<<1, 15))
|
||||
@@ -644,6 +860,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))
|
||||
@@ -657,6 +876,14 @@ Op is 20-27
|
||||
#define VCEQ_F32(Dd, Dn, Dm) EMIT(VCEQ_F_gen(0, ((Dd)>>4)&1, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VCEQQ_F32(Dd, Dn, Dm) EMIT(VCEQ_F_gen(0, ((Dd)>>4)&1, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#define VCEQ_0_gen(D, size, Vd, F, Q, M, Vm) (0b1111<<28 | 0b0011<<24 | 1<<23 | (D)<<22 | 0b11<<20 | (size)<<18 | 0b01<<16 | (Vd)<<12 | (F)<<10 | 0b010<<7 | (Q)<<6 | (M)<<5 | (Vm))
|
||||
#define VCEQ_0_8(Dd, Dm) EMIT(VCEQ_0_gen(((Dd)>>4)&1, 0, (Dd)&15, 0, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VCEQ_0_16(Dd, Dm) EMIT(VCEQ_0_gen(((Dd)>>4)&1, 1, (Dd)&15, 0, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VCEQ_0_32(Dd, Dm) EMIT(VCEQ_0_gen(((Dd)>>4)&1, 2, (Dd)&15, 0, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VCEQQ_0_8(Dd, Dm) EMIT(VCEQ_0_gen(((Dd)>>4)&1, 0, (Dd)&15, 0, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VCEQQ_0_16(Dd, Dm) EMIT(VCEQ_0_gen(((Dd)>>4)&1, 1, (Dd)&15, 0, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VCEQQ_0_32(Dd, Dm) EMIT(VCEQ_0_gen(((Dd)>>4)&1, 2, (Dd)&15, 0, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#define VCGT_I_gen(U, D, size, Vn, Vd, N, Q, M, Vm) (0b1111<<28 | 0b001<<25 | (U)<<24 | 0<<23 | (D)<<22 | (size)<<20 | (Vn)<<16 | (Vd)<<12 | 0b0011<<8 | (N)<<7 | (Q)<<6 | (M)<<5 | (Vm))
|
||||
#define VCGT_U8(Dd, Dn, Dm) EMIT(VCGT_I_gen(1, ((Dd)>>4)&1, 0, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VCGTQ_U8(Dd, Dn, Dm) EMIT(VCGT_I_gen(1, ((Dd)>>4)&1, 0, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
@@ -682,6 +909,15 @@ Op is 20-27
|
||||
#define VCGE_F32(Dd, Dn, Dm) EMIT(VCGE_F_gen(((Dd)>>4)&1, 0, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VCGEQ_F32(Dd, Dn, Dm) EMIT(VCGE_F_gen(((Dd)>>4)&1, 0, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#define VCLT_0_gen(D, size, Vd, F, Q, M, Vm) (0b1111<<28 | 0b0011<<24 | 1<<23 | (D)<<22 | 0b11<<20 | (size)<<18 | 0b01<<16 | (Vd)<<12 | (F)<<10 | 0b100<<7 | (Q)<<6 | (M)<<5 | (Vm))
|
||||
#define VCLT_0_8(Dd, Dm) EMIT(VCLT_0_gen(((Dd)>>4)&1, 0, (Dd)&15, 0, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VCLT_0_16(Dd, Dm) EMIT(VCLT_0_gen(((Dd)>>4)&1, 1, (Dd)&15, 0, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VCLT_0_32(Dd, Dm) EMIT(VCLT_0_gen(((Dd)>>4)&1, 2, (Dd)&15, 0, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VCLTQ_0_8(Dd, Dm) EMIT(VCLT_0_gen(((Dd)>>4)&1, 0, (Dd)&15, 0, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VCLTQ_0_16(Dd, Dm) EMIT(VCLT_0_gen(((Dd)>>4)&1, 1, (Dd)&15, 0, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VCLTQ_0_32(Dd, Dm) EMIT(VCLT_0_gen(((Dd)>>4)&1, 2, (Dd)&15, 0, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
|
||||
#define VSHR_gen(U, D, imm6, Vd, L, Q, M, Vm) (0b1111<<28 | 0b001<<25 | (U)<<24 | 1<<23 | (D)<<22 | (imm6)<<16 | (Vd)<<12 | (L)<<7 | (Q)<<6 | (M)<<5 | 1<<4 | (Vm))
|
||||
#define VSHR_U8(Dd, Dm, imm3) EMIT(VSHR_gen(1, ((Dd)>>4)&1, 0b001<<3 | (8-(imm3)), (Dd)&15, 0, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VSHR_S8(Dd, Dm, imm3) EMIT(VSHR_gen(0, ((Dd)>>4)&1, 0b001<<3 | (8-(imm3)), (Dd)&15, 0, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
@@ -728,6 +964,11 @@ Op is 20-27
|
||||
#define VSHLQ_S32(Dd, Dm, Dn) EMIT(VSHLR_gen(0, ((Dd)>>4)&1, 0b10, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VSHLQ_S64(Dd, Dm, Dn) EMIT(VSHLR_gen(0, ((Dd)>>4)&1, 0b11, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#define VSHRN_gen(D, imm6, Vd, M, Vm) (0b1111<<28 | 0b0010<<24 | 1<<23 | (D)<<22 | (imm6)<<16 | (Vd)<<12 | 1<<11 | (M)<<5 | 1<<4 | (Vm))
|
||||
#define VSHRN_16(Dd, Dm, imm3) EMIT(VSHRN_gen(((Dd)>>4)&1, 0b001<<3 | (8-(imm3)), (Dd)&15, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VSHRN_32(Dd, Dm, imm4) EMIT(VSHRN_gen(((Dd)>>4)&1, 0b01<<4 | (16-(imm4)), (Dd)&15, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VSHRN_64(Dd, Dm, imm5) EMIT(VSHRN_gen(((Dd)>>4)&1, 0b1<<5 | (32-(imm5)), (Dd)&15, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#define VTRN_gen(D, size, Vd, Q, M, Vm) (0b1111<<28 | 0b0011<<24 | 1<<23 | (D)<<22 | 0b11<<20 | (size)<<18 | 0b10<<16 | (Vd)<<12 | 0b0000<<8 | 1<<7 | (Q)<<6 | (M)<<5 | (Vm))
|
||||
#define VTRN_32(Dd, Dm) EMIT(VTRN_gen(((Dd)>>4)&1, 2, (Dd)&15, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
@@ -766,6 +1007,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 +1021,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)&0xf, ((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)&0xf, ((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 +1052,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 +1065,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 +1159,145 @@ 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_Fgen(((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))
|
||||
|
||||
#define VQRDMULH_gen(D, size, Vn, Vd, N, Q, M, Vm) (0b1111<<28 | 0b0011 <<24 | (D)<<22 | (size)<<20 | (Vn)<<16 | (Vd)<<12 | 0b1011<<8 | (N)<<7 | (Q)<<6 | (M)<<5 | (Vm))
|
||||
// Dd <= (2*Dn*Dm + 1<<(size-1))>>size
|
||||
#define VQRDMULH_S16(Dd, Dn, Dm) EMIT(VQRDMULH_gen(((Dd)>>4)&1, 0b01, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VQRDMULH_S32(Dd, Dn, Dm) EMIT(VQRDMULH_gen(((Dd)>>4)&1, 0b10, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VQRDMULHQ_S16(Dd, Dn, Dm) EMIT(VQRDMULH_gen(((Dd)>>4)&1, 0b01, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VQRDMULHQ_S32(Dd, Dn, Dm) EMIT(VQRDMULH_gen(((Dd)>>4)&1, 0b10, (Dn)&15, (Dd)&15, ((Dn)>>4)&1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#define VDUP_sgen(D, imm4, Vd, Q, M, Vm) (0b1111<<28 | 0b0011<<24 | 1<<23 | (D)<<22 | 0b11<<20 | (imm4)<<16 | (Vd)<<12 | 0b1100<<8 | (Q)<<6 | (M)<<5 | (Vm))
|
||||
// Dd <= Dup(Dm[x])
|
||||
#define VDUP_32(Dd, Dm, x) EMIT(VDUP_sgen(((Dd)>>4)&1, (((x)<<3)|0b100), (Dd)&15, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#define VABS_vgen(D, size, Vd, F, Q, M, Vm) (0b1111<<28 | 0b0011<<24 | 1<<23 | (D)<<22 | 0b11<<20 | (size)<<18 | 0b01<<16 | (Vd)<<12 | (F)<<10 | 0b110<<7 | (Q)<<6 | (M)<<5 | (Vm))
|
||||
#define VABS_S32(Dd, Dm) EMIT(VABS_vgen(((Dd)>>4)&1, 2, (Dd)&15, 0, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VABS_S16(Dd, Dm) EMIT(VABS_vgen(((Dd)>>4)&1, 1, (Dd)&15, 0, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VABS_S8(Dd, Dm) EMIT(VABS_vgen(((Dd)>>4)&1, 0, (Dd)&15, 0, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VABS_F(Dd, Dm) EMIT(VABS_vgen(((Dd)>>4)&1, 2, (Dd)&15, 1, 0, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VABSQ_S32(Dd, Dm) EMIT(VABS_vgen(((Dd)>>4)&1, 2, (Dd)&15, 0, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VABSQ_S16(Dd, Dm) EMIT(VABS_vgen(((Dd)>>4)&1, 1, (Dd)&15, 0, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VABSQ_S8(Dd, Dm) EMIT(VABS_vgen(((Dd)>>4)&1, 0, (Dd)&15, 0, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
#define VABSQ_F(Dd, Dm) EMIT(VABS_vgen(((Dd)>>4)&1, 2, (Dd)&15, 1, 1, ((Dm)>>4)&1, (Dm)&15))
|
||||
|
||||
#endif //__ARM_EMITTER_H__
|
||||
@@ -10,9 +10,18 @@
|
||||
arm_epilog:
|
||||
//update register -> emu
|
||||
//pop {r0}
|
||||
stm r0, {r4-r12} // put back reg value in emu, including EIP (so r12 must be EIP now)
|
||||
stm r0, {r4-r12,r14} // put back reg value in emu, including EIP (so r14 must be Flags now)
|
||||
//restore all used register
|
||||
//vpop {d8-d15}
|
||||
pop {r4-r11, pc}
|
||||
vpop {d8-d15}
|
||||
pop {r4-r12, pc}
|
||||
//end, return...
|
||||
//bx lr
|
||||
|
||||
|
||||
.global arm_epilog_fast
|
||||
arm_epilog_fast:
|
||||
//restore all used register
|
||||
vpop {d8-d15}
|
||||
pop {r4-r12, pc}
|
||||
//end, return...
|
||||
//bx lr
|
||||
@@ -0,0 +1,655 @@
|
||||
; 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)
|
||||
! MRS: always APSR since program is always in userspace
|
||||
! DBG: option (field and assembly) -> imm (field and assembly)
|
||||
|
||||
; ========== 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>
|
||||
|
||||
# CPS marked as invalid (in userspace, treated as NOP)
|
||||
;INVALIDATE 1 1 1 1 0 0 0 1 0 0 0 0 <4> <8> <2> 0 <1> <4>
|
||||
ARM_ 1 1 1 1 0 0 0 1 0 0 0 0 (0) (0) (0) 1 (0) (0) (0) (0) (0) (0) @<1> (0) 0 0 0 0 (0) (0) (0) (0) SETEND \%cparam ? 'B' : 'L'\E
|
||||
;INVALIDATE 1 1 1 1 0 0 0 1 0 0 1 0 <4> <8> 0 1 1 1 <4>
|
||||
|
||||
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>, <Qm>, <Qn>
|
||||
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>, <Qm>, <Qn>
|
||||
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>, <Qm>, <Qn>
|
||||
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>, <Qm>, <Qn>
|
||||
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>, <Dm>
|
||||
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>, <Dm>
|
||||
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>, <Dm>
|
||||
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>, <Dm>
|
||||
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>, <Dm>
|
||||
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>, <Dm>
|
||||
|
||||
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 @ set ++size@ @ 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 ++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 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> 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> 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 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> 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> 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 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> 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> 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 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> 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> 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 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> 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> 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 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> 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> 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 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> 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> 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 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> 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> 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 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> 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> 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 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> 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> 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 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> 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> 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>
|
||||
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> 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> 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 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> 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> 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 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> 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> 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 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> 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> 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 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> 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> 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 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> 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> 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 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> 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> 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 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> 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> 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 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> 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> 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 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> 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> 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 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> 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> 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> 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 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> 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> 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 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> 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> 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 1 0 @<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 1 0 @<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 1 0 @<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 1 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 1 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 1 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> 1 0 <8> 1 1 <2> 1 1 <6>
|
||||
INVALIDATE 1 1 1 1 0 1 0 0 1 <1> 1 0 <8> 1 1 <2> 0 0 <1> 1 <4>
|
||||
INVALIDATE 1 1 1 1 0 1 0 0 1 <1> 1 0 <8> 1 1 1 0 <3> 1 <4>
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 0 size 0 @<1> 1 1 0 1 @ param=1 char align[4] !@ %@ sprintf(align, ":%d", 8 << size)@ align[0] = '\0'@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[]}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 0 size 0 @<1> 1 1 1 1 @ param=1 char align[4] !@ %@ sprintf(align, ":%d", 8 << size)@ align[0] = '\0'@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[]}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 0 size 0 @<1> Rm @ param=1 char align[4] !@ %@ sprintf(align, ":%d", 8 << size)@ align[0] = '\0'@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[]}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 0 size 1 @<1> 1 1 0 1 @ param=1 char align[4] !@ %@ sprintf(align, ":%d", 8 << size)@ align[0] = '\0'@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + d]\[]}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 0 size 1 @<1> 1 1 1 1 @ param=1 char align[4] !@ %@ sprintf(align, ":%d", 8 << size)@ align[0] = '\0'@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + d]\[]}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 0 size 1 @<1> Rm @ param=1 char align[4] !@ %@ sprintf(align, ":%d", 8 << size)@ align[0] = '\0'@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + d]\[]}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 0 @<4> 1 1 0 1 @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 0 @<4> 1 1 1 1 @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 0 @<4> Rm @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 1 size @<1> @<1> 1 1 0 1 @ param2_1=1 char align[4] !@ %@ sprintf(align, ":%d", 16 << size)@ align[0] = '\0'@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[]}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 1 size @<1> @<1> 1 1 1 1 @ param2_1=1 char align[4] !@ %@ sprintf(align, ":%d", 16 << size)@ align[0] = '\0'@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[]}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 1 size @<1> @<1> Rm @ param2_1=1 char align[4] !@ %@ sprintf(align, ":%d", 16 << size)@ align[0] = '\0'@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[]}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> 1 1 0 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> 1 1 1 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> Rm @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 1 0 size @<1> @<1> 1 1 0 1 VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[], \vecname[0x22 + param1_1+param1_1 + d]\[]}, [<Rn>]!
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 1 0 size @<1> @<1> 1 1 1 1 VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[], \vecname[0x22 + param1_1+param1_1 + d]\[]}, [<Rn>]
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 1 0 size @<1> @<1> Rm VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[], \vecname[0x22 + param1_1+param1_1 + d]\[]}, [<Rn>], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 1 0 @<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 1 0 @<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 1 0 @<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 1 1 1 1 size @<1> @<1> 1 1 0 1 @ param2_1=1 char align[5] !@ %@ sprintf(align, ":%d", 32 << size)@ align[0] = '\0'@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[], \vecname[0x22 + param1_1+param1_1 + d]\[], \vecname[0x23 + param1_1+param1_1+param1_1 + d]\[]}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 1 1 size @<1> @<1> 1 1 1 1 @ param2_1=1 char align[5] !@ %@ sprintf(align, ":%d", 32 << size)@ align[0] = '\0'@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[], \vecname[0x22 + param1_1+param1_1 + d]\[], \vecname[0x23 + param1_1+param1_1+param1_1 + d]\[]}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 1 1 size @<1> @<1> Rm @ param2_1=1 char align[5] !@ %@ sprintf(align, ":%d", 32 << size)@ align[0] = '\0'@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[], \vecname[0x22 + param1_1+param1_1 + d]\[], \vecname[0x23 + param1_1+param1_1+param1_1 + d]\[]}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 1 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 1 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 1 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>
|
||||
|
||||
ARM_ 1 1 1 1 0 1 0 0 @<1> 0 0 1 Rn @<8> @<4> @<4> 'NOP'
|
||||
ARM_ 1 1 1 1 0 1 0 0 U 1 0 1 Rn (1) (1) (1) (1) imm12 PLI [<Rn>, #+/-<imm12>]
|
||||
;INVALIDATE 1 1 1 1 0 1 0 0 <2> 1 1 <4> <8> <4> <4>
|
||||
ARM_ 1 1 1 1 0 1 0 1 U @<1> 0 1 Rn (1) (1) (1) (1) imm12 PLD\param ? "W" : ""\ [<Rn>, #+/-<imm12>]
|
||||
ARM_ 1 1 1 1 0 1 0 1 U (1) 0 1 1 1 1 1 (1) (1) (1) (1) imm12 PLD [PC, #+/-<imm>]
|
||||
;INVALIDATE 1 1 1 1 0 1 0 1 0 0 1 1 <4> <8> <4> <4>
|
||||
;INVALIDATE 1 1 1 1 0 1 0 1 0 1 1 1 <4> <8> 0 0 0 0 <4>
|
||||
ARM_ 1 1 1 1 0 1 0 1 0 1 1 1 (1) (1) (1) (1) (1) (1) (1) (1) (0) (0) (0) (0) 0 0 0 1 (1) (1) (1) (1) CLREX
|
||||
;INVALIDATE 1 1 1 1 0 1 0 1 0 1 1 1 <4> <8> 0 0 1 <1> <4>
|
||||
ARM_ 1 1 1 1 0 1 0 1 0 1 1 1 (1) (1) (1) (1) (1) (1) (1) (1) (0) (0) (0) (0) 0 1 0 0 @<4> @ param=0b1111=0b1110=0b1011=0b1010=0b0111=0b0110=0b0011=0b0010 const char* option option,"SY","ST","ISH","ISHST","NSH","NSHST","OSH","OSHST","!!!"@ @ DSB \option\
|
||||
ARM_ 1 1 1 1 0 1 0 1 0 1 1 1 (1) (1) (1) (1) (1) (1) (1) (1) (0) (0) (0) (0) 0 1 0 1 @<4> @ param=0b1111=0b1110=0b1011=0b1010=0b0111=0b0110=0b0011=0b0010 const char* option option,"SY","ST","ISH","ISHST","NSH","NSHST","OSH","OSHST","!!!"@ @ DMB \option\
|
||||
ARM_ 1 1 1 1 0 1 0 1 0 1 1 1 (1) (1) (1) (1) (1) (1) (1) (1) (0) (0) (0) (0) 0 1 1 0 @<4> @ param=0b1111 const char* option option,"SY","!!!"@ @ ISB \option\
|
||||
;INVALIDATE 1 1 1 1 0 1 0 1 0 1 1 1 <4> <8> 0 1 1 1 <4>
|
||||
;INVALIDATE 1 1 1 1 0 1 0 1 0 1 1 1 <4> <8> 1 <3> <4>
|
||||
;INVALIDATE 1 1 1 1 0 1 0 1 0 1 1 1 <4> <8> <4> <4>
|
||||
;INVALIDATE 1 1 1 1 0 1 0 1 1 <1> 1 1 <4> <8> <4> <4>
|
||||
ARM_ 1 1 1 1 0 1 1 0 @<1> 0 0 1 Rn @<8> @<3> 0 @<4> 'NOP'
|
||||
ARMs 1 1 1 1 0 1 1 0 U 1 0 1 Rn (1) (1) (1) (1) imm5 type 0 Rm PLI [<Rn>, +/-<Rm>{, <shift>}]
|
||||
ARMs 1 1 1 1 0 1 1 1 U @<1> 0 1 Rn (1) (1) (1) (1) imm5 type 0 Rm PLD\param ? "W" : ""\ [<Rn>, +/-<Rm>{, <shift>}]
|
||||
;INVALIDATE 1 1 1 1 0 1 1 <3> 1 1 <4> <8> <3> 0 <4>
|
||||
# Permanently undefined
|
||||
INVALIDATE 1 1 1 1 0 1 1 1 1 1 1 1 <4> <8> 1 1 1 1 <4>
|
||||
;INVALIDATE 1 1 1 1 0 <7> <4> <8> <4> <4>
|
||||
|
||||
; ===== 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 0 0 (1) (1) (1) (1) Rd (0) (0) 0 (0) 0 0 0 0 (0) (0) (0) (0) MRS<c> <Rd>, APSR
|
||||
ARM_ cond 0 0 0 1 0 0 1 0 @<2> 0 0 (1) (1) (1) (1) (0) (0) 0 (0) 0 0 0 0 Rn @ param=0b01=0b10 const char* spec_reg spec_reg,"APSR_g","APSR_nzcvq","APSR_nzcvqg"@ @ MSR<c> \spec_reg\, <Rn>
|
||||
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 0 1 1 0 (1) (1) (1) (1) Rd (1) (1) (1) (1) 0 0 0 1 Rm CLZ<c> <Rd>, <Rm>
|
||||
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 0 0 0 0 0 (1) (1) (1) (1) (0) (0) (0) (0) 0 0 0 0 0 0 0 1 YIELD<c>
|
||||
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 1 0 WFE<c>
|
||||
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 1 1 WFI<c>
|
||||
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 1 0 0 SEV<c>
|
||||
ARM_ cond/=1110 0 0 1 1 0 0 1 0 0 0 0 0 (1) (1) (1) (1) (0) (0) (0) (0) 0 0 0 1 0 1 0 0 CSDB<c>
|
||||
ARM_ cond 0 0 1 1 0 0 1 0 0 0 0 0 (1) (1) (1) (1) (0) (0) (0) (0) 1 1 1 1 imm4 DBG<c> #<imm>
|
||||
INVALIDATE <4> 0 0 1 1 0 0 1 0 0 0 0 0 <8> <8>
|
||||
ARM_ cond 0 0 1 1 0 0 1 0 @<2> 0 0 (1) (1) (1) (1) imm12 @ param=0b01=0b10 const char* spec_reg spec_reg,"APSR_g","APSR_nzcvq","APSR_nzcvqg"@ @ MSR<c> \spec_reg\, #<imm>
|
||||
# MSR in system level is invalid/useless in application level
|
||||
INVALIDATE <4> 0 0 1 1 0 0 1 0 <2> 0 1 <8> <8>
|
||||
INVALIDATE <4> 0 0 1 1 0 0 1 0 <2> 1 <1> <8> <8>
|
||||
INVALIDATE <4> 0 0 1 1 0 1 1 0 <4> <8> <8>
|
||||
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 (1) (1) (1) (1) 0 0 1 1 Rm RBIT<c> <Rd>, <Rm>
|
||||
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>}
|
||||
ARM_ cond 0 1 1 1 0 0 0 1 Rd (1) (1) (1) (1) Rm 0 0 0 1 Rn SDIV<c> <Rd>, <Rn>, <Rm>
|
||||
ARM_ cond 0 1 1 1 0 0 1 1 Rd (1) (1) (1) (1) Rm 0 0 0 1 Rn UDIV<c> <Rd>, <Rn>, <Rm>
|
||||
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/=1110 0 1 1 1 1 1 1 1 imm12 1 1 1 1 imm4 UDF<c> #<imm16>
|
||||
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 @ set imm8*=4@ @ 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 @ set imm8*=4@ @ 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/=1111 1 0 1 0 (0) (0) (0) 1 (0) (0) (0) (0) VMRS<c> APSR_nzcv, FPSCR
|
||||
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 << 4) + (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 U 1 Vd 1 0 1 sz op 1 M 0 Vm VCVT\(op ? "" : "R")\<c>.\(u ? "U" : "S")\32.F\(size ? "64" : "32")\ <Sd>, <Dm>
|
||||
VFPU cond 1 1 1 0 1 D 1 1 1 1 1 U Vd 1 0 1 sz op 1 i 0 imm4 @ set uint8_t td = (u << 2) + op + 1@ td=0b001=0b010=0b101 const char* Td Td,"S16","U16","S32","U32"@ set imm5 = (16 << op) - (imm5 >> 4) - ((imm5 & 0xF) << 1)@ @ VCVT<c>.\Td\.F\(size ? "64" : "32")\ <Dd>, <Dd>, #<imm>
|
||||
;INVALIDATE <4> 1 1 1 0 1 <1> 1 1 <8> 1 0 1 <4> 0 <4>
|
||||
;INVALIDATE <4> 1 1 1 0 <12> 1 0 1 <4> 0 <4>
|
||||
|
||||
; ============= END OF REGISTERED INSTRUCTIONS ============
|
||||
INVALIDATE <32>
|
||||
Executable
+115
@@ -0,0 +1,115 @@
|
||||
// arm lock helper
|
||||
// there is 2 part: read and write
|
||||
// write return 0 on success, 1 on fail (value has been changed)
|
||||
|
||||
.text
|
||||
.align 4
|
||||
|
||||
.global arm_lock_read_b
|
||||
.global arm_lock_write_b
|
||||
.global arm_lock_read_h
|
||||
.global arm_lock_write_h
|
||||
.global arm_lock_read_d
|
||||
.global arm_lock_write_d
|
||||
.global arm_lock_read_dd
|
||||
.global arm_lock_write_dd
|
||||
.global arm_lock_xchg
|
||||
.global arm_lock_storeifnull
|
||||
.global arm_lock_storeifref
|
||||
|
||||
|
||||
arm_lock_read_b:
|
||||
// address is r0, return is r0
|
||||
dmb ish
|
||||
ldrexb r0, [r0]
|
||||
bx lr
|
||||
|
||||
arm_lock_write_b:
|
||||
// address is r0, value is r1, return is r0
|
||||
mov r2, r0
|
||||
strexb r0, r1, [r2]
|
||||
bx lr
|
||||
|
||||
arm_lock_read_h:
|
||||
// address is r0, return is r0
|
||||
dmb ish
|
||||
ldrexh r0, [r0]
|
||||
bx lr
|
||||
|
||||
arm_lock_write_h:
|
||||
// address is r0, value is r1, return is r0
|
||||
mov r2, r0
|
||||
strexh r0, r1, [r2]
|
||||
bx lr
|
||||
|
||||
arm_lock_read_d:
|
||||
// address is r0, return is r0
|
||||
// r0 needs to be aligned
|
||||
dmb ish
|
||||
ldrex r0, [r0]
|
||||
bx lr
|
||||
|
||||
arm_lock_write_d:
|
||||
// address is r0, value is r1, return is r0
|
||||
// r0 needs to be aligned
|
||||
mov r2, r0
|
||||
strex r0, r1, [r2]
|
||||
bx lr
|
||||
|
||||
arm_lock_read_dd:
|
||||
// address is r2, return is r0, r1
|
||||
dmb ish
|
||||
ldrexd r2, r3, [r2]
|
||||
str r2, [r0]
|
||||
str r3, [r1]
|
||||
bx lr
|
||||
|
||||
arm_lock_write_dd:
|
||||
// address is r2, value is r0, r1, return is r0
|
||||
// r0 needs to be aligned
|
||||
strexd r3, r0, r1, [r2]
|
||||
mov r0, r3
|
||||
bx lr
|
||||
|
||||
arm_lock_xchg:
|
||||
// address is r0, value is r1, return old value in r0
|
||||
// r0 needs to be aligned
|
||||
dmb ish
|
||||
ldrex r2, [r0]
|
||||
strex r3, r1, [r0]
|
||||
cmp r3, #1
|
||||
beq arm_lock_xchg
|
||||
mov r0, r2
|
||||
bx lr
|
||||
|
||||
arm_lock_storeifnull:
|
||||
// address is r0, value is r1, r1 store to r0 only if [r0] is 0. return new [r0] value (so r1 or old value)
|
||||
// r0 needs to be aligned
|
||||
dmb ish
|
||||
ldrex r2, [r0]
|
||||
cmp r2, #0
|
||||
bne arm_lock_storeifnull_exit
|
||||
mov r2, r1
|
||||
strex r3, r2, [r0]
|
||||
cmp r3, #1
|
||||
beq arm_lock_storeifnull
|
||||
arm_lock_storeifnull_exit:
|
||||
mov r0, r2
|
||||
bx lr
|
||||
|
||||
arm_lock_storeifref:
|
||||
push {r4}
|
||||
dmb ish
|
||||
arm_lock_storeifref_loop:
|
||||
// address is r0, value is r1, r1 store to r0 only if [r0] is r2. return new [r0] value (so r1 or old value)
|
||||
ldrex r3, [r0]
|
||||
cmp r3, r2
|
||||
bne arm_lock_storeifref_exit
|
||||
mov r3, r1
|
||||
strex r4, r3, [r0]
|
||||
cmp r4, #1
|
||||
beq arm_lock_storeifref_loop
|
||||
arm_lock_storeifref_exit:
|
||||
mov r0, r3
|
||||
pop {r4}
|
||||
bx lr
|
||||
Executable
+34
@@ -0,0 +1,34 @@
|
||||
#ifndef __ARM_LOCK_HELPER__H__
|
||||
#define __ARM_LOCK_HELPER__H__
|
||||
#include <stdint.h>
|
||||
|
||||
// LDREXB of ADDR
|
||||
extern uint8_t arm_lock_read_b(void* addr);
|
||||
// STREXB of ADDR, return 0 if ok, 1 if not
|
||||
extern int arm_lock_write_b(void* addr, uint8_t val);
|
||||
|
||||
// LDREXH of ADDR
|
||||
extern uint16_t arm_lock_read_h(void* addr);
|
||||
// STREXH of ADDR, return 0 if ok, 1 if not
|
||||
extern int arm_lock_write_h(void* addr, uint16_t val);
|
||||
|
||||
// LDREX of ADDR
|
||||
extern uint32_t arm_lock_read_d(void* addr);
|
||||
// STREX of ADDR, return 0 if ok, 1 if not
|
||||
extern int arm_lock_write_d(void* addr, uint32_t val);
|
||||
|
||||
// LDREXD of ADDR
|
||||
extern void arm_lock_read_dd(uint32_t* a, uint32_t* b, void* addr);
|
||||
// STREX of ADDR, return 0 if ok, 1 if not
|
||||
extern int arm_lock_write_dd(uint32_t a, uint32_t b, void* addr);
|
||||
|
||||
// Atomically exchange value at [p] with val, return old p
|
||||
extern uintptr_t arm_lock_xchg(void* p, uintptr_t val);
|
||||
|
||||
// Atomically store value to [p] only if [p] is NULL. Return new [p] value (so val or old)
|
||||
extern void* arm_lock_storeifnull(void* p, void* val);
|
||||
|
||||
// Atomically store value to [p] only if [p] is ref. Return new [p] value (so val or old)
|
||||
extern void* arm_lock_storeifref(void* p, void* val, void* ref);
|
||||
|
||||
#endif //__ARM_LOCK_HELPER__H__
|
||||
@@ -6,19 +6,18 @@
|
||||
.text
|
||||
.align 4
|
||||
|
||||
.extern UpdateLinkTable
|
||||
.extern LinkNext
|
||||
|
||||
.global arm_linker
|
||||
arm_linker:
|
||||
.global arm_next
|
||||
arm_next:
|
||||
// emu is r0
|
||||
// table offset is r1
|
||||
// IP address is r12
|
||||
push {r0, r1, r12}
|
||||
mov r2, r12
|
||||
//stm r0, {r4-r12,r14} // don't put put back reg value in emu, faster but more tricky to debug
|
||||
// IP address is r1
|
||||
push {r0, r1, r12, r14}
|
||||
// call the function
|
||||
bl UpdateLinkTable
|
||||
bl LinkNext
|
||||
// return offset is jump address
|
||||
mov r3, r0
|
||||
pop {r0, r1, r12}
|
||||
pop {r0, r1, r12, r14}
|
||||
bx r3
|
||||
|
||||
Executable → Regular
+5480
-886
File diff suppressed because it is too large.
Load diff
@@ -9,11 +9,11 @@
|
||||
.global arm_prolog
|
||||
arm_prolog:
|
||||
//save all used register
|
||||
push {r4-r11, lr}
|
||||
//vpush {d8-d15}
|
||||
push {r4-r12, lr}
|
||||
vpush {d8-d15}
|
||||
//setup emu -> register
|
||||
//push {r0}
|
||||
ldm r0, {r4-r11} // all 8 register in direct access, no EIP (so r12 can be used as scratch)
|
||||
ldm r0, {r4-r12} // all 8 register in direct access, plus flags, no EIP (so r14 can be used as scratch)
|
||||
//TODO
|
||||
//jump to function
|
||||
bx r1
|
||||
@@ -1,19 +0,0 @@
|
||||
//arm try to update linker table for dynarec
|
||||
//and address of table to as 1st parameter
|
||||
//jump addres as second and ip as third
|
||||
// don't retry if failed to write...
|
||||
|
||||
.text
|
||||
.align 4
|
||||
|
||||
.global arm_tableupdate
|
||||
arm_tableupdate:
|
||||
// jump address is r0 and IP address is r1
|
||||
// table offset is r2
|
||||
push {r4, r5}
|
||||
ldrexd r4, r5, [r2]
|
||||
strexd r3, r0, r1, [r2]
|
||||
pop {r4, r5}
|
||||
mov r0, r3
|
||||
bx lr
|
||||
|
||||
+377
-108
@@ -2,7 +2,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86context.h"
|
||||
@@ -17,163 +18,431 @@
|
||||
#include "x86trace.h"
|
||||
#include "dynablock.h"
|
||||
#include "dynablock_private.h"
|
||||
#include "dynarec_private.h"
|
||||
#include "elfloader.h"
|
||||
#ifdef ARM
|
||||
#include "dynarec_arm.h"
|
||||
#include "arm_lock_helper.h"
|
||||
#else
|
||||
#error Unsupported architecture!
|
||||
#endif
|
||||
|
||||
#include "custommem.h"
|
||||
#include "khash.h"
|
||||
|
||||
KHASH_MAP_INIT_INT(dynablocks, dynablock_t*)
|
||||
|
||||
|
||||
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 text, int textsz, int direct)
|
||||
{
|
||||
if(!textsz) {
|
||||
printf_log(LOG_NONE, "Error, creating a NULL sized Dynablock\n");
|
||||
return NULL;
|
||||
}
|
||||
dynablocklist_t* ret = (dynablocklist_t*)calloc(1, sizeof(dynablocklist_t));
|
||||
ret->blocks = kh_init(dynablocks);
|
||||
ret->base = base;
|
||||
ret->text = text;
|
||||
ret->textsz = textsz;
|
||||
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);}
|
||||
}
|
||||
dynarec_log(LOG_DEBUG, "New Dynablocklist %p, from %p->%p\n", ret, (void*)text, (void*)(text+textsz));
|
||||
return ret;
|
||||
}
|
||||
|
||||
void FreeDynablock(dynablock_t* db, int need_lock)
|
||||
{
|
||||
if(db) {
|
||||
if(db->gone)
|
||||
return; // already in the process of deletion!
|
||||
dynarec_log(LOG_DEBUG, "FreeDynablock(%p), db->block=%p x86=%p:%p father=%p, with %d son(s) already gone=%d\n", db, db->block, db->x86_addr, db->x86_addr+db->x86_size, db->father, db->sons_size, db->gone);
|
||||
if(need_lock)
|
||||
pthread_mutex_lock(&my_context->mutex_dyndump);
|
||||
db->done = 0;
|
||||
db->gone = 1;
|
||||
// remove from direct if there
|
||||
uintptr_t startdb = db->parent->text;
|
||||
uintptr_t enddb = db->parent->text + db->parent->textsz;
|
||||
if(db->parent->direct) {
|
||||
uintptr_t addr = (uintptr_t)db->x86_addr;
|
||||
if(addr>=startdb && addr<enddb)
|
||||
db->parent->direct[addr-startdb] = NULL;
|
||||
}
|
||||
// remove jumptable
|
||||
setJumpTableDefault(db->x86_addr);
|
||||
// remove and free the sons
|
||||
for (int i=0; i<db->sons_size; ++i) {
|
||||
dynablock_t *son = (dynablock_t*)arm_lock_xchg(&db->sons[i], 0);
|
||||
FreeDynablock(son, 0);
|
||||
}
|
||||
// only the father free the DynarecMap
|
||||
if(!db->father) {
|
||||
dynarec_log(LOG_DEBUG, " -- FreeDyrecMap(%p, %d)\n", db->block, db->size);
|
||||
FreeDynarecMap(db, (uintptr_t)db->block, db->size);
|
||||
free(db->sons);
|
||||
free(db->instsize);
|
||||
}
|
||||
free(db);
|
||||
if(need_lock)
|
||||
pthread_mutex_unlock(&my_context->mutex_dyndump);
|
||||
}
|
||||
}
|
||||
|
||||
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":"");
|
||||
dynablock_t* db;
|
||||
kh_foreach_value((*dynablocks)->blocks, db,
|
||||
free(db->table);
|
||||
free(db);
|
||||
);
|
||||
kh_destroy(dynablocks, (*dynablocks)->blocks);
|
||||
if((*dynablocks)->direct)
|
||||
dynarec_log(LOG_DEBUG, "Free Dynablocklist %p, with Direct Blocks %p\n", *dynablocks, (*dynablocks)->direct);
|
||||
if((*dynablocks)->direct) {
|
||||
for (int i=0; i<(*dynablocks)->textsz; ++i) {
|
||||
if((*dynablocks)->direct[i] && !(*dynablocks)->direct[i]->father)
|
||||
FreeDynablock((*dynablocks)->direct[i], my_context?1:0);
|
||||
}
|
||||
free((*dynablocks)->direct);
|
||||
(*dynablocks)->direct = 0;
|
||||
|
||||
pthread_rwlock_destroy(&(*dynablocks)->rwlock_blocks);
|
||||
}
|
||||
(*dynablocks)->direct = NULL;
|
||||
|
||||
free(*dynablocks);
|
||||
*dynablocks = NULL;
|
||||
}
|
||||
|
||||
void ConvertHash2Direct(dynablocklist_t* dynablocks)
|
||||
void MarkDynablock(dynablock_t* db)
|
||||
{
|
||||
if(dynablocks->textsz==0 || dynablocks->text==0)
|
||||
return; // nothing to do
|
||||
// create the new set
|
||||
dynablock_t **direct = (dynablock_t**)calloc(dynablocks->textsz, sizeof(dynablock_t*));
|
||||
kh_dynablocks_t *blocks = kh_init(dynablocks);
|
||||
// transfert
|
||||
int ret;
|
||||
khint_t k;
|
||||
if(db) {
|
||||
if(db->father)
|
||||
db = db->father; // mark only father
|
||||
if(db->need_test)
|
||||
return; // already done
|
||||
db->need_test = 1;
|
||||
setJumpTableDefault(db->x86_addr);
|
||||
for(int i=0; i<db->sons_size; ++i)
|
||||
setJumpTableDefault(db->sons[i]->x86_addr);
|
||||
}
|
||||
}
|
||||
|
||||
uintptr_t StartDynablockList(dynablocklist_t* db)
|
||||
{
|
||||
if(db)
|
||||
return db->text;
|
||||
return 0;
|
||||
}
|
||||
uintptr_t EndDynablockList(dynablocklist_t* db)
|
||||
{
|
||||
if(db)
|
||||
return db->text+db->textsz-1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int IntervalIntersects(uintptr_t start1, uintptr_t end1, uintptr_t start2, uintptr_t end2)
|
||||
{
|
||||
if(start1 > end2 || start2 > end1)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void MarkDirectDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
if(!dynablocks)
|
||||
return;
|
||||
if(!dynablocks->direct)
|
||||
return;
|
||||
uintptr_t startdb = dynablocks->text;
|
||||
uintptr_t enddb = startdb + dynablocks->textsz -1;
|
||||
uintptr_t start = addr;
|
||||
uintptr_t end = addr+size-1;
|
||||
if(start<startdb)
|
||||
start = startdb;
|
||||
if(end>enddb)
|
||||
end = enddb;
|
||||
dynablock_t *db;
|
||||
if(end>startdb && start<enddb)
|
||||
for(uintptr_t i = start; i<end; ++i)
|
||||
if((db=dynablocks->direct[i-startdb]))
|
||||
if(IntervalIntersects((uintptr_t)db->x86_addr, (uintptr_t)db->x86_addr+db->x86_size-1, addr, addr+size+1))
|
||||
MarkDynablock(db);
|
||||
}
|
||||
|
||||
void FreeRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
if(!dynablocks)
|
||||
return;
|
||||
|
||||
if(dynablocks->direct) {
|
||||
dynablock_t* db;
|
||||
int ret;
|
||||
khint_t k;
|
||||
kh_dynablocks_t *blocks = kh_init(dynablocks);
|
||||
// copy in a temporary list
|
||||
if(dynablocks->direct) {
|
||||
uintptr_t startdb = dynablocks->text;
|
||||
uintptr_t enddb = startdb + dynablocks->textsz;
|
||||
uintptr_t start = addr;
|
||||
uintptr_t end = addr+size;
|
||||
if(start<startdb)
|
||||
start = startdb;
|
||||
if(end>enddb)
|
||||
end = enddb;
|
||||
if(end>startdb && start<enddb)
|
||||
for(uintptr_t i = start; i<end; ++i) {
|
||||
db = (dynablock_t*)arm_lock_xchg(&dynablocks->direct[i-startdb], 0);
|
||||
if(db) {
|
||||
if(db->father)
|
||||
db = db->father;
|
||||
if(db->parent==dynablocks) {
|
||||
k = kh_put(dynablocks, blocks, (uintptr_t)db, &ret);
|
||||
kh_value(blocks, k) = db;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// purge the list
|
||||
kh_foreach_value(blocks, db,
|
||||
FreeDynablock(db, 1);
|
||||
);
|
||||
kh_destroy(dynablocks, blocks);
|
||||
}
|
||||
}
|
||||
void MarkRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
if(!dynablocks)
|
||||
return;
|
||||
if(dynablocks->direct) {
|
||||
uintptr_t new_addr = addr - dynablocks->maxsz;
|
||||
uintptr_t new_size = size + dynablocks->maxsz;
|
||||
MarkDirectDynablock(dynablocks, new_addr, new_size);
|
||||
// the blocks check before
|
||||
for(int idx=(new_addr)>>DYNAMAP_SHIFT; idx<(addr>>DYNAMAP_SHIFT); ++idx)
|
||||
MarkDirectDynablock(getDB(idx), new_addr, new_size);
|
||||
}
|
||||
}
|
||||
|
||||
dynablock_t* FindDynablockDynablocklist(void* addr, kh_dynablocks_t* dynablocks)
|
||||
{
|
||||
if(!dynablocks)
|
||||
return NULL;
|
||||
dynablock_t* db;
|
||||
uintptr_t key;
|
||||
uintptr_t start = dynablocks->text-dynablocks->base;
|
||||
uintptr_t end = dynablocks->text + dynablocks->textsz-dynablocks->base;
|
||||
kh_foreach(dynablocks->blocks, key, db,
|
||||
if(key>=start && key<end)
|
||||
direct[key-start] = db;
|
||||
else {
|
||||
k = kh_put(dynablocks, blocks, key, &ret);
|
||||
if(ret) { // don't try to insert if already done...
|
||||
kh_value(blocks, k) = db;
|
||||
}
|
||||
kh_foreach_value(dynablocks, db,
|
||||
const uintptr_t s = (uintptr_t)db->block;
|
||||
const uintptr_t e = (uintptr_t)db->block+db->size;
|
||||
if((uintptr_t)addr>=s && (uintptr_t)addr<e)
|
||||
return db->father?db->father:db;
|
||||
)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static dynablocklist_t* getDBFromAddress(uintptr_t addr)
|
||||
{
|
||||
const int idx = (addr>>DYNAMAP_SHIFT);
|
||||
return getDB(idx);
|
||||
}
|
||||
|
||||
dynablock_t *AddNewDynablock(dynablocklist_t* dynablocks, uintptr_t addr, int* created)
|
||||
{
|
||||
if(!dynablocks) {
|
||||
dynarec_log(LOG_INFO, "Warning: Ask to create a dynablock with a NULL dynablocklist (addr=%p)\n", (void*)addr);
|
||||
*created = 0;
|
||||
return NULL;
|
||||
}
|
||||
if((addr<dynablocks->text) || (addr>=(dynablocks->text+dynablocks->textsz))) {
|
||||
// this should be useless
|
||||
//dynarec_log(LOG_INFO, "Warning: Refused to create a Direct Block that is out-of-bound: dynablocks=%p (%p:%p), addr=%p\n", dynablocks, (void*)(dynablocks->text), (void*)(dynablocks->text+dynablocks->textsz), (void*)addr);
|
||||
//*created = 0;
|
||||
//return NULL;
|
||||
return AddNewDynablock(getDBFromAddress(addr), addr, created);
|
||||
}
|
||||
dynablock_t* block = NULL;
|
||||
// first, check if it exist in direct access mode
|
||||
if(dynablocks->direct) {
|
||||
block = dynablocks->direct[addr-dynablocks->text];
|
||||
if(block) {
|
||||
dynarec_log(LOG_VERBOSE, "Block already exist in Direct Map\n");
|
||||
*created = 0;
|
||||
return block;
|
||||
}
|
||||
);
|
||||
// destroy old and do the swap (should swap before destroy, but hash access is always behind mutex)
|
||||
kh_destroy(dynablocks, dynablocks->blocks);
|
||||
dynablocks->blocks = blocks;
|
||||
dynablocks->direct = direct;
|
||||
}
|
||||
|
||||
if (!*created)
|
||||
return block;
|
||||
|
||||
pthread_mutex_lock(&my_context->mutex_dyndump);
|
||||
if(!dynablocks->direct) {
|
||||
dynablock_t** p = (dynablock_t**)calloc(dynablocks->textsz, sizeof(dynablock_t*));
|
||||
if(arm_lock_storeifnull(&dynablocks->direct, p)!=p)
|
||||
free(p); // someone already create the direct array, too late...
|
||||
}
|
||||
|
||||
// create and add new block
|
||||
dynarec_log(LOG_VERBOSE, "Ask for DynaRec Block creation @%p\n", (void*)addr);
|
||||
|
||||
block = (dynablock_t*)calloc(1, sizeof(dynablock_t));
|
||||
block->parent = dynablocks;
|
||||
dynablock_t* tmp = (dynablock_t*)arm_lock_storeifnull(&dynablocks->direct[addr-dynablocks->text], block);
|
||||
pthread_mutex_unlock(&my_context->mutex_dyndump);
|
||||
if(tmp != block) {
|
||||
// a block appeard!
|
||||
free(block);
|
||||
*created = 0;
|
||||
return tmp;
|
||||
}
|
||||
*created = 1;
|
||||
return block;
|
||||
}
|
||||
|
||||
//TODO: move this to dynrec_arm.c and track allocated structure to avoid memory leak
|
||||
static __thread struct __jmp_buf_tag dynarec_jmpbuf;
|
||||
|
||||
void cancelFillBlock()
|
||||
{
|
||||
longjmp(&dynarec_jmpbuf, 1);
|
||||
}
|
||||
|
||||
#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)
|
||||
static dynablock_t* internalDBGetBlock(x86emu_t* emu, uintptr_t addr, uintptr_t filladdr, int create, dynablock_t* current, int need_lock)
|
||||
{
|
||||
// try the quickest way first: get parent of current and check if ok!
|
||||
dynablocklist_t *dynablocks = NULL;
|
||||
dynablock_t* block = NULL;
|
||||
if(current) {
|
||||
dynablocks = current->parent;
|
||||
if(dynablocks->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 = current->parent;
|
||||
if(dynablocks && !(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)
|
||||
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
|
||||
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;
|
||||
}
|
||||
// unlock now
|
||||
pthread_rwlock_unlock(&dynablocks->rwlock_blocks);
|
||||
// Blocks doesn't exist. If creation is not allow, just return NULL
|
||||
if(!create)
|
||||
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)
|
||||
{
|
||||
block = dynablocks->direct[addr-dynablocks->text] = (dynablock_t*)calloc(1, sizeof(dynablock_t));
|
||||
} else {
|
||||
k = kh_put(dynablocks, dynablocks->blocks, addr-dynablocks->base, &ret);
|
||||
if(!ret) {
|
||||
// Ooops, block is already there? retreive it and bail out
|
||||
block = kh_value(dynablocks->blocks, k);
|
||||
pthread_rwlock_unlock(&dynablocks->rwlock_blocks);
|
||||
return block;
|
||||
if(!dynablocks) {
|
||||
dynablocks = getDBFromAddress(addr);
|
||||
if(!dynablocks) {
|
||||
dynablocks = GetDynablocksFromAddress(emu->context, addr);
|
||||
if(!dynablocks)
|
||||
return NULL;
|
||||
}
|
||||
block = kh_value(dynablocks->blocks, k) = (dynablock_t*)calloc(1, sizeof(dynablock_t));
|
||||
// check if size of hash map == magic size, if yes, convert to direct before unlocking
|
||||
if(!dynablocks->direct && kh_size(dynablocks->blocks)==MAGIC_SIZE)
|
||||
ConvertHash2Direct(dynablocks);
|
||||
}
|
||||
block->parent = dynablocks;
|
||||
// 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);
|
||||
// check direct first, without lock
|
||||
if(dynablocks->direct/* && (addr>=dynablocks->text) && (addr<(dynablocks->text+dynablocks->textsz))*/)
|
||||
if((block = dynablocks->direct[addr-dynablocks->text]))
|
||||
return block;
|
||||
|
||||
int created = create;
|
||||
block = AddNewDynablock(dynablocks, addr, &created);
|
||||
if(!created)
|
||||
return block; // existing block...
|
||||
|
||||
// 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;
|
||||
if(need_lock)
|
||||
pthread_mutex_lock(&my_context->mutex_dyndump);
|
||||
if(sigsetjmp(&dynarec_jmpbuf, 1)) {
|
||||
printf_log(LOG_INFO, "FillBlock at %p triggered a segfault, cancelling\n", (void*)addr);
|
||||
if(need_lock)
|
||||
pthread_mutex_unlock(&my_context->mutex_dyndump);
|
||||
return NULL;
|
||||
}
|
||||
void* ret = FillBlock(block, filladdr);
|
||||
if(need_lock)
|
||||
pthread_mutex_unlock(&my_context->mutex_dyndump);
|
||||
if(!ret) {
|
||||
dynarec_log(LOG_DEBUG, "Fillblock of block %p for %p returned an error\n", block, (void*)addr);
|
||||
void* old = (void*)arm_lock_storeifref(&dynablocks->direct[addr-dynablocks->text], 0, block);
|
||||
if(old!=block && old) { // put it back in place, strange things are happening here!
|
||||
dynarec_log(LOG_INFO, "Warning, a wild block appeared at %p: %p\n", (void*)addr, old);
|
||||
// Doing nothing else, the block has not been written
|
||||
}
|
||||
free(block);
|
||||
block = NULL;
|
||||
}
|
||||
// check size
|
||||
if(block && block->x86_size) {
|
||||
int blocksz = block->x86_size;
|
||||
if(dynablocks->maxsz<blocksz) {
|
||||
dynablocks->maxsz = blocksz;
|
||||
for(int idx=(addr>>DYNAMAP_SHIFT)+1; idx<=((addr+blocksz)>>DYNAMAP_SHIFT); ++idx) {
|
||||
dynablocklist_t* dblist;
|
||||
if((dblist = getDB(idx)))
|
||||
if(dblist->maxsz<blocksz)
|
||||
dblist->maxsz = blocksz;
|
||||
}
|
||||
}
|
||||
//protectDB((uintptr_t)block->x86_addr, block->x86_size); // already protected in FillBlock
|
||||
// but check if it already need test
|
||||
if(block->need_test || (block->father && block->father->need_test))
|
||||
return NULL;
|
||||
// fill-in jumptable
|
||||
addJumpTableIfDefault(block->x86_addr, block->block);
|
||||
for(int i=0; i<block->sons_size; ++i)
|
||||
addJumpTableIfDefault(block->sons[i]->x86_addr, block->sons[i]->block);
|
||||
}
|
||||
|
||||
dynarec_log(LOG_DEBUG, " --- DynaRec Block %s @%p:%p (%p, 0x%x bytes, with %d son(s))\n", created?"created":"recycled", (void*)addr, (void*)(addr+((block)?block->x86_size:0)), (block)?block->block:0, (block)?block->size:0, (block)?block->sons_size:0);
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
dynablock_t* DBGetBlock(x86emu_t* emu, uintptr_t addr, int create, dynablock_t** current)
|
||||
{
|
||||
dynablock_t *db = internalDBGetBlock(emu, addr, addr, create, *current, 1);
|
||||
if(db && db->done && db->block && (db->need_test || (db->father && db->father->need_test))) {
|
||||
if(pthread_mutex_trylock(&my_context->mutex_dyndump))
|
||||
return NULL;
|
||||
dynablock_t *father = db->father?db->father:db;
|
||||
uint32_t hash = (getProtection((uintptr_t)father->x86_addr)&PROT_READ)?X31_hash_code(father->x86_addr, father->x86_size):0;
|
||||
if(hash!=father->hash) {
|
||||
dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X/%X) with %d son(s) for %p\n", father, father->x86_addr, father->x86_addr+father->x86_size, hash, father->hash, father->sons_size, (void*)addr);
|
||||
// no more current if it gets invalidated too
|
||||
if(*current && father->x86_addr>=(*current)->x86_addr && (father->x86_addr+father->x86_size)<(*current)->x86_addr)
|
||||
*current = NULL;
|
||||
// Free father, it's now invalid!
|
||||
FreeDynablock(father, 0);
|
||||
// start again... (will create a new block)
|
||||
db = internalDBGetBlock(emu, addr, addr, create, *current, 0);
|
||||
} else {
|
||||
father->need_test = 0;
|
||||
protectDB((uintptr_t)father->x86_addr, father->x86_size);
|
||||
// fill back jumptable
|
||||
addJumpTableIfDefault(father->x86_addr, father->block);
|
||||
for(int i=0; i<father->sons_size; ++i)
|
||||
addJumpTableIfDefault(father->sons[i]->x86_addr, father->sons[i]->block);
|
||||
}
|
||||
pthread_mutex_unlock(&my_context->mutex_dyndump);
|
||||
}
|
||||
return db;
|
||||
}
|
||||
|
||||
dynablock_t* DBAlternateBlock(x86emu_t* emu, uintptr_t addr, uintptr_t filladdr)
|
||||
{
|
||||
dynarec_log(LOG_DEBUG, "Creating AlternateBlock at %p for %p\n", (void*)addr, (void*)filladdr);
|
||||
int create = 1;
|
||||
dynablock_t *db = internalDBGetBlock(emu, addr, filladdr, create, NULL, 1);
|
||||
if(db && db->done && db->block && (db->need_test || (db->father && db->father->need_test))) {
|
||||
if(pthread_mutex_trylock(&my_context->mutex_dyndump))
|
||||
return NULL;
|
||||
dynablock_t *father = db->father?db->father:db;
|
||||
uint32_t hash = (getProtection((uintptr_t)father->x86_addr)&PROT_READ)?X31_hash_code(father->x86_addr, father->x86_size):0;
|
||||
if(hash!=father->hash) {
|
||||
dynarec_log(LOG_DEBUG, "Invalidating alt block %p from %p:%p (hash:%X/%X) with %d son(s) for %p\n", father, father->x86_addr, father->x86_addr+father->x86_size, hash, father->hash, father->sons_size, (void*)addr);
|
||||
// Free father, it's now invalid!
|
||||
FreeDynablock(father, 0);
|
||||
// start again... (will create a new block)
|
||||
db = internalDBGetBlock(emu, addr, filladdr, create, NULL, 0);
|
||||
} else {
|
||||
father->need_test = 0;
|
||||
protectDB((uintptr_t)father->x86_addr, father->x86_size);
|
||||
// fill back jumptable
|
||||
addJumpTableIfDefault(father->x86_addr, father->block);
|
||||
for(int i=0; i<father->sons_size; ++i)
|
||||
addJumpTableIfDefault(father->sons[i]->x86_addr, father->sons[i]->block);
|
||||
}
|
||||
pthread_mutex_unlock(&my_context->mutex_dyndump);
|
||||
}
|
||||
return db;
|
||||
}
|
||||
@@ -1,26 +1,36 @@
|
||||
#ifndef __DYNABLOCK_PRIVATE_H_
|
||||
#define __DYNABLOCK_PRIVATE_H_
|
||||
|
||||
typedef struct dynablocklist_s dynablocklist_t;
|
||||
typedef struct dynablocklist_s dynablocklist_t;
|
||||
|
||||
typedef struct instsize_s {
|
||||
unsigned int x86:4;
|
||||
unsigned int nat:4;
|
||||
} instsize_t;
|
||||
|
||||
typedef struct dynablock_s {
|
||||
dynablocklist_t *parent;
|
||||
void* block;
|
||||
int size;
|
||||
uintptr_t* table;
|
||||
int tablesz;
|
||||
int done;
|
||||
dynablocklist_t* parent;
|
||||
void* block;
|
||||
int size;
|
||||
void* x86_addr;
|
||||
uintptr_t x86_size;
|
||||
uint32_t hash;
|
||||
uint8_t need_test;
|
||||
uint8_t done;
|
||||
uint8_t gone;
|
||||
uint8_t dummy;
|
||||
int isize;
|
||||
dynablock_t** sons; // sons (kind-of dummy dynablock...)
|
||||
int sons_size;
|
||||
dynablock_t* father; // set only in the case of a son
|
||||
instsize_t* instsize;
|
||||
} 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;
|
||||
dynablock_t **direct; // direct mapping (waste of space, so not always there)
|
||||
int maxsz; // maxblock size (for this block or previous block)
|
||||
dynablock_t** direct; // direct mapping (waste of space, so the array is created at first write)
|
||||
} dynablocklist_t;
|
||||
|
||||
#endif //__DYNABLOCK_PRIVATE_H_
|
||||
+116
-47
@@ -2,6 +2,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86context.h"
|
||||
@@ -14,69 +15,87 @@
|
||||
#include "callback.h"
|
||||
#include "emu/x86run_private.h"
|
||||
#include "x86trace.h"
|
||||
#include "threads.h"
|
||||
#ifdef DYNAREC
|
||||
#include "dynablock.h"
|
||||
#include "dynablock_private.h"
|
||||
#include "bridge.h"
|
||||
#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;
|
||||
#endif
|
||||
|
||||
#ifdef DYNAREC
|
||||
void* UpdateLinkTable(x86emu_t* emu, void** table, uintptr_t addr)
|
||||
#ifdef HAVE_TRACE
|
||||
uintptr_t getX86Address(dynablock_t* db, uintptr_t arm_addr);
|
||||
#endif
|
||||
void* LinkNext(x86emu_t* emu, uintptr_t addr, void* x2)
|
||||
{
|
||||
dynablock_t* block = DBGetBlock(emu, addr, 1, NULL); // keep a copy of parent block?
|
||||
int r;
|
||||
if(block==0) {
|
||||
// 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;
|
||||
#ifdef HAVE_TRACE
|
||||
if(!addr) {
|
||||
x2-=8; // actual PC is 2 instructions ahead
|
||||
dynablock_t* db = FindDynablockFromNativeAddress(x2);
|
||||
printf_log(LOG_NONE, "Warning, jumping to NULL address from %p (db=%p, x86addr=%p)\n", x2, db, db?(void*)getX86Address(db, (uintptr_t)x2):NULL);
|
||||
}
|
||||
#endif
|
||||
dynablock_t* current = NULL;
|
||||
void * jblock;
|
||||
dynablock_t* block = DBGetBlock(emu, addr, 1, ¤t);
|
||||
if(!block) {
|
||||
// no block, let link table as is...
|
||||
if(hasAlternate((void*)addr)) {
|
||||
printf_log(LOG_INFO, "Jmp address has alternate: %p", (void*)addr);
|
||||
addr = (uintptr_t)getAlternate((void*)addr);
|
||||
R_EIP = addr;
|
||||
printf_log(LOG_INFO, " -> %p\n", (void*)addr);
|
||||
block = DBGetBlock(emu, addr, 1, ¤t);
|
||||
}
|
||||
if(!block) {
|
||||
#ifdef HAVE_TRACE
|
||||
dynablock_t* db = FindDynablockFromNativeAddress(x2);
|
||||
dynarec_log(LOG_INFO, "Warning, jumping to a no-block address %p from %p (db=%p, x86addr=%p)\n", (void*)addr, x2, db, db?(void*)getX86Address(db, (uintptr_t)x2):NULL);
|
||||
#endif
|
||||
//tableupdate(arm_epilog, addr, table);
|
||||
return arm_epilog;
|
||||
}
|
||||
}
|
||||
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
|
||||
//tableupdate(arm_linker, addr, table);
|
||||
return arm_epilog;
|
||||
}
|
||||
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
|
||||
if(!(jblock=block->block)) {
|
||||
// null block, but done: go to epilog, no linker here
|
||||
return arm_epilog;
|
||||
}
|
||||
#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;
|
||||
//dynablock_t *father = block->father?block->father:block;
|
||||
return jblock;
|
||||
}
|
||||
#endif
|
||||
|
||||
void DynaCall(x86emu_t* emu, uintptr_t addr)
|
||||
{
|
||||
// prepare setjump for signal handling
|
||||
emu_jmpbuf_t *ejb = NULL;
|
||||
int jmpbuf_reset = 0;
|
||||
if(emu->type == EMUTYPE_MAIN) {
|
||||
ejb = GetJmpBuf();
|
||||
if(!ejb->jmpbuf_ok) {
|
||||
ejb->emu = emu;
|
||||
ejb->jmpbuf_ok = 1;
|
||||
jmpbuf_reset = 1;
|
||||
int a;
|
||||
if((a=sigsetjmp((struct __jmp_buf_tag*)ejb->jmpbuf, 1))) {
|
||||
printf_log(LOG_DEBUG, "Setjmp DynaCall %d, fs=0x%x\n", a, ejb->emu->segs[_FS]);
|
||||
addr = R_EIP; // not sure if it should still be inside DynaCall!
|
||||
if(a==2)
|
||||
Run(emu, 1); // "single step" next instruction that is doing auto-smc
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef DYNAREC
|
||||
if(!box86_dynarec)
|
||||
#endif
|
||||
@@ -93,15 +112,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;
|
||||
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, "%04d|Calling Interpretor @%p, emu=%p\n", GetTID(), (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, "%04d|Calling DynaRec Block @%p (%p) of %d x86 instructions (father=%p) emu=%p\n", GetTID(), (void*)R_EIP, block->block, block->isize ,block->father, emu);
|
||||
CHECK_FLAGS(emu);
|
||||
// block is here, let's run it!
|
||||
#ifdef ARM
|
||||
@@ -113,6 +134,16 @@ void DynaCall(x86emu_t* emu, uintptr_t addr)
|
||||
emu->quit = 0;
|
||||
emu->fork = 0;
|
||||
emu = x86emu_fork(emu, forktype);
|
||||
if(emu->type == EMUTYPE_MAIN) {
|
||||
ejb = GetJmpBuf();
|
||||
ejb->emu = emu;
|
||||
ejb->jmpbuf_ok = 1;
|
||||
jmpbuf_reset = 1;
|
||||
if(sigsetjmp((struct __jmp_buf_tag*)ejb->jmpbuf, 1)) {
|
||||
printf_log(LOG_DEBUG, "Setjmp inner DynaCall, fs=0x%x\n", ejb->emu->segs[_FS]);
|
||||
addr = R_EIP;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
emu->quit = 0; // reset Quit flags...
|
||||
@@ -129,10 +160,35 @@ void DynaCall(x86emu_t* emu, uintptr_t addr)
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// clear the setjmp
|
||||
if(ejb && jmpbuf_reset)
|
||||
ejb->jmpbuf_ok = 0;
|
||||
}
|
||||
|
||||
int DynaRun(x86emu_t* emu)
|
||||
{
|
||||
// prepare setjump for signal handling
|
||||
emu_jmpbuf_t *ejb = NULL;
|
||||
#ifdef DYNAREC
|
||||
int jmpbuf_reset = 1;
|
||||
#endif
|
||||
if(emu->type == EMUTYPE_MAIN) {
|
||||
ejb = GetJmpBuf();
|
||||
if(!ejb->jmpbuf_ok) {
|
||||
ejb->emu = emu;
|
||||
ejb->jmpbuf_ok = 1;
|
||||
int a;
|
||||
#ifdef DYNAREC
|
||||
jmpbuf_reset = 1;
|
||||
#endif
|
||||
if((a=sigsetjmp((struct __jmp_buf_tag*)ejb->jmpbuf, 1))) {
|
||||
printf_log(LOG_DEBUG, "Setjmp DynaRun %d, fs=0x%x\n", a, ejb->emu->segs[_FS]);
|
||||
if(a==2)
|
||||
Run(emu, 1); // "single step" next instruction that is doing auto-smc
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef DYNAREC
|
||||
if(!box86_dynarec)
|
||||
#endif
|
||||
@@ -140,15 +196,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;
|
||||
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, "%04d|Running Interpretor @%p, emu=%p\n", GetTID(), (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, "%04d|Running DynaRec Block @%p (%p) of %d x86 insts (father=%p) emu=%p\n", GetTID(), (void*)R_EIP, block->block, block->isize, block->father, emu);
|
||||
// block is here, let's run it!
|
||||
#ifdef ARM
|
||||
arm_prolog(emu, block->block);
|
||||
@@ -159,9 +217,20 @@ int DynaRun(x86emu_t* emu)
|
||||
emu->quit = 0;
|
||||
emu->fork = 0;
|
||||
emu = x86emu_fork(emu, forktype);
|
||||
if(emu->type == EMUTYPE_MAIN) {
|
||||
ejb = GetJmpBuf();
|
||||
ejb->emu = emu;
|
||||
ejb->jmpbuf_ok = 1;
|
||||
jmpbuf_reset = 1;
|
||||
if(sigsetjmp((struct __jmp_buf_tag*)ejb->jmpbuf, 1))
|
||||
printf_log(LOG_DEBUG, "Setjmp inner DynaRun, fs=0x%x\n", ejb->emu->segs[_FS]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// clear the setjmp
|
||||
if(ejb && jmpbuf_reset)
|
||||
ejb->jmpbuf_ok = 0;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
+442
-45
@@ -2,9 +2,11 @@
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86context.h"
|
||||
#include "custommem.h"
|
||||
#include "dynarec.h"
|
||||
#include "emu/x86emu_private.h"
|
||||
#include "tools/bridge_private.h"
|
||||
@@ -18,57 +20,325 @@
|
||||
#include "dynablock_private.h"
|
||||
#include "dynarec_arm.h"
|
||||
#include "dynarec_arm_private.h"
|
||||
#include "dynarec_arm_functions.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 arm_pass0(dynarec_arm_t* dyn, uintptr_t addr);
|
||||
void arm_pass1(dynarec_arm_t* dyn, uintptr_t addr);
|
||||
void arm_pass2(dynarec_arm_t* dyn, uintptr_t addr);
|
||||
void arm_pass3(dynarec_arm_t* dyn, uintptr_t addr);
|
||||
void add_next(dynarec_arm_t *dyn, uintptr_t addr) {
|
||||
if(!box86_dynarec_bigblock)
|
||||
return;
|
||||
for(int i=0; i<dyn->next_sz; ++i)
|
||||
if(dyn->next[i]==addr)
|
||||
return;
|
||||
if(dyn->next_sz == dyn->next_cap) {
|
||||
dyn->next_cap += 16;
|
||||
dyn->next = (uintptr_t*)realloc(dyn->next, dyn->next_cap*sizeof(uintptr_t));
|
||||
}
|
||||
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;
|
||||
}
|
||||
#define PK(A) (*((uint8_t*)(addr+(A))))
|
||||
int is_nops(dynarec_arm_t *dyn, uintptr_t addr, int n)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
void FillBlock(x86emu_t* emu, dynablock_t* block, uintptr_t addr) {
|
||||
// return size of next instuciton, -1 is unknown
|
||||
// not all instrction are setup
|
||||
int next_instruction(dynarec_arm_t *dyn, uintptr_t addr)
|
||||
{
|
||||
uint8_t opcode = PK(0);
|
||||
uint8_t nextop;
|
||||
switch (opcode) {
|
||||
case 0x66:
|
||||
opcode = PK(1);
|
||||
switch(opcode) {
|
||||
case 0x90:
|
||||
return 2;
|
||||
}
|
||||
break;
|
||||
case 0x81:
|
||||
nextop = PK(1);
|
||||
return fakeed(dyn, addr+2, 0, nextop)-addr + 4;
|
||||
case 0x83:
|
||||
nextop = PK(1);
|
||||
return fakeed(dyn, addr+2, 0, nextop)-addr + 1;
|
||||
case 0x84:
|
||||
case 0x85:
|
||||
case 0x88:
|
||||
case 0x89:
|
||||
case 0x8A:
|
||||
case 0x8B:
|
||||
case 0x8C:
|
||||
case 0x8D:
|
||||
case 0x8E:
|
||||
case 0x8F:
|
||||
nextop = PK(1);
|
||||
return fakeed(dyn, addr+2, 0, nextop)-addr;
|
||||
case 0x50:
|
||||
case 0x51:
|
||||
case 0x52:
|
||||
case 0x53:
|
||||
case 0x54:
|
||||
case 0x55:
|
||||
case 0x56:
|
||||
case 0x57:
|
||||
case 0x58:
|
||||
case 0x59:
|
||||
case 0x5A:
|
||||
case 0x5B:
|
||||
case 0x5C:
|
||||
case 0x5D:
|
||||
case 0x5E:
|
||||
case 0x5F:
|
||||
case 0x90:
|
||||
case 0x91:
|
||||
case 0x92:
|
||||
case 0x93:
|
||||
case 0x94:
|
||||
case 0x95:
|
||||
case 0x96:
|
||||
case 0x97:
|
||||
case 0x98:
|
||||
case 0x99:
|
||||
case 0x9B:
|
||||
case 0x9C:
|
||||
case 0x9D:
|
||||
case 0x9E:
|
||||
case 0x9F:
|
||||
return 1;
|
||||
case 0xA0:
|
||||
case 0xA1:
|
||||
case 0xA2:
|
||||
case 0xA3:
|
||||
return 5;
|
||||
case 0xB0:
|
||||
case 0xB1:
|
||||
case 0xB2:
|
||||
case 0xB3:
|
||||
case 0xB4:
|
||||
case 0xB5:
|
||||
case 0xB6:
|
||||
case 0xB7:
|
||||
return 2;
|
||||
case 0xB8:
|
||||
case 0xB9:
|
||||
case 0xBA:
|
||||
case 0xBB:
|
||||
case 0xBC:
|
||||
case 0xBD:
|
||||
case 0xBE:
|
||||
case 0xBF:
|
||||
return 5;
|
||||
case 0xFF:
|
||||
nextop = PK(1);
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: // INC Ed
|
||||
case 1: //DEC Ed
|
||||
case 2: // CALL Ed
|
||||
case 4: // JMP Ed
|
||||
case 6: // Push Ed
|
||||
return fakeed(dyn, addr+2, 0, nextop)-addr;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#undef PK
|
||||
|
||||
int is_instructions(dynarec_arm_t *dyn, uintptr_t addr, int n)
|
||||
{
|
||||
int i = 0;
|
||||
while(i<n) {
|
||||
int j=next_instruction(dyn, addr+i);
|
||||
if(j<=0) return 0;
|
||||
i+=j;
|
||||
}
|
||||
return (i==n)?1:0;
|
||||
}
|
||||
|
||||
instsize_t* addInst(instsize_t* insts, size_t* size, size_t* cap, int x86_size, int arm_size)
|
||||
{
|
||||
// x86 instruction is <16 bytes
|
||||
int toadd;
|
||||
if(x86_size>arm_size)
|
||||
toadd = 1 + x86_size/15;
|
||||
else
|
||||
toadd = 1 + arm_size/15;
|
||||
if((*size)+toadd>(*cap)) {
|
||||
*cap = (*size)+toadd;
|
||||
insts = (instsize_t*)realloc(insts, (*cap)*sizeof(instsize_t));
|
||||
}
|
||||
while(toadd) {
|
||||
if(x86_size>15)
|
||||
insts[*size].x86 = 15;
|
||||
else
|
||||
insts[*size].x86 = x86_size;
|
||||
x86_size -= insts[*size].x86;
|
||||
if(arm_size>15)
|
||||
insts[*size].nat = 15;
|
||||
else
|
||||
insts[*size].nat = arm_size;
|
||||
arm_size -= insts[*size].nat;
|
||||
++(*size);
|
||||
--toadd;
|
||||
}
|
||||
return insts;
|
||||
}
|
||||
|
||||
uintptr_t arm_pass0(dynarec_arm_t* dyn, uintptr_t addr);
|
||||
uintptr_t arm_pass1(dynarec_arm_t* dyn, uintptr_t addr);
|
||||
uintptr_t arm_pass2(dynarec_arm_t* dyn, uintptr_t addr);
|
||||
uintptr_t arm_pass3(dynarec_arm_t* dyn, uintptr_t addr);
|
||||
|
||||
__thread void* current_helper = NULL;
|
||||
|
||||
void CancelBlock()
|
||||
{
|
||||
dynarec_arm_t* helper = (dynarec_arm_t*)current_helper;
|
||||
current_helper = NULL;
|
||||
if(!helper)
|
||||
return;
|
||||
free(helper->next);
|
||||
free(helper->insts);
|
||||
free(helper->sons_x86);
|
||||
free(helper->sons_arm);
|
||||
if(helper->dynablock && helper->dynablock->block)
|
||||
FreeDynarecMap(helper->dynablock, (uintptr_t)helper->dynablock->block, helper->dynablock->size);
|
||||
}
|
||||
|
||||
void* FillBlock(dynablock_t* block, uintptr_t addr) {
|
||||
dynarec_log(LOG_DEBUG, "Asked to Fill block %p with %p\n", block, (void*)addr);
|
||||
if(addr>=box86_nodynarec_start && addr<box86_nodynarec_end) {
|
||||
dynarec_log(LOG_DEBUG, "Asked to fill a block in fobidden zone\n");
|
||||
return NULL;
|
||||
}
|
||||
if(!isJumpTableDefault((void*)addr)) {
|
||||
dynarec_log(LOG_DEBUG, "Asked to fill a block at %p, but JumpTable is not default\n", (void*)addr);
|
||||
return NULL;
|
||||
}
|
||||
// init the helper
|
||||
dynarec_arm_t helper = {0};
|
||||
helper.emu = emu;
|
||||
arm_pass0(&helper, addr);
|
||||
current_helper = &helper;
|
||||
helper.dynablock = block;
|
||||
helper.start = addr;
|
||||
uintptr_t start = addr;
|
||||
helper.cap = 64; // needs epilog handling
|
||||
helper.insts = (instruction_arm_t*)calloc(helper.cap, sizeof(instruction_arm_t));
|
||||
// pass 0, addresses, x86 jump addresses, overall size of the block
|
||||
uintptr_t end = arm_pass0(&helper, addr);
|
||||
// no need for next anymore
|
||||
free(helper.next);
|
||||
helper.next_sz = helper.next_cap = 0;
|
||||
helper.next = NULL;
|
||||
// basic checks
|
||||
if(!helper.size) {
|
||||
dynarec_log(LOG_DEBUG, "Warning, null-sized dynarec block (%p)\n", (void*)addr);
|
||||
block->done = 1;
|
||||
return;
|
||||
CancelBlock();
|
||||
return (void*)block;
|
||||
}
|
||||
// already protect the block and compute hash signature
|
||||
protectDB(addr, end-addr); //end is 1byte after actual end
|
||||
uint32_t hash = X31_hash_code((void*)addr, end-addr);
|
||||
// Compute flag_need, without taking into account any barriers
|
||||
uint32_t last_need = X_PEND;
|
||||
for(int i = helper.size; i-- > 0;) {
|
||||
last_need |= helper.insts[i].x86.use_flags;
|
||||
if((helper.insts[i].x86.state_flags == SF_SUBSET) && (last_need&X_PEND))
|
||||
last_need = (X_ALL & (~helper.insts[i].x86.set_flags) ) | helper.insts[i].x86.use_flags;
|
||||
if (last_need == (X_PEND | X_ALL)) {
|
||||
last_need = X_ALL;
|
||||
}
|
||||
helper.insts[i].x86.need_flags = last_need;
|
||||
if ((helper.insts[i].x86.set_flags) && !(helper.insts[i].x86.state_flags & SF_MAYSET)) {
|
||||
if (last_need & X_PEND) {
|
||||
last_need = (~helper.insts[i].x86.set_flags) & X_ALL;
|
||||
} else {
|
||||
last_need &= ~helper.insts[i].x86.set_flags;
|
||||
}
|
||||
}
|
||||
}
|
||||
helper.cap = helper.size+3; // needs epilog handling
|
||||
helper.insts = (instruction_arm_t*)calloc(helper.cap, sizeof(instruction_arm_t));
|
||||
// pass 1, addresses, x86 jump addresses, flags
|
||||
arm_pass1(&helper, addr);
|
||||
// calculate barriers
|
||||
uintptr_t start = helper.insts[0].x86.addr;
|
||||
uintptr_t end = helper.insts[helper.size].x86.addr+helper.insts[helper.size].x86.size;
|
||||
for(int i=0; i<helper.size; ++i)
|
||||
if(helper.insts[i].x86.jmp) {
|
||||
uintptr_t j = helper.insts[i].x86.jmp;
|
||||
if(j<start || j>=end)
|
||||
if(j<start || j>=end) {
|
||||
helper.insts[i].x86.jmp_insts = -1;
|
||||
else {
|
||||
} else {
|
||||
// find jump address instruction
|
||||
int k=-1;
|
||||
for(int i2=0; i2<helper.size && k==-1; ++i2) {
|
||||
@@ -80,44 +350,171 @@ 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;
|
||||
}
|
||||
// check for the optionnal barriers now
|
||||
for(int i=helper.size-1; i>=0; --i) {
|
||||
if(helper.insts[i].x86.barrier==3)
|
||||
if(helper.insts[i].x86.jmp_insts == -1) {
|
||||
if(i==helper.size-1 || helper.insts[i+1].x86.barrier)
|
||||
helper.insts[i].x86.barrier=2; // nope, end of block or barrier just after
|
||||
else
|
||||
helper.insts[i].x86.barrier=0; // ok, no need for a barrier here after all
|
||||
} else
|
||||
helper.insts[i].x86.barrier=2;
|
||||
}
|
||||
// check to remove useless barrier, in case of jump when destination doesn't needs flags
|
||||
for(int i=helper.size-1; i>=0; --i) {
|
||||
if(helper.insts[i].x86.jmp
|
||||
&& helper.insts[i].x86.jmp_insts>=0
|
||||
&& helper.insts[helper.insts[i].x86.jmp_insts].x86.barrier==1) {
|
||||
int k = helper.insts[i].x86.jmp_insts;
|
||||
//TODO: optimize FPU barrier too
|
||||
if((!helper.insts[k].x86.need_flags)
|
||||
||(helper.insts[k].x86.set_flags==X_ALL
|
||||
&& helper.insts[k].x86.state_flags==SF_SET)
|
||||
||(helper.insts[k].x86.state_flags==SF_SET_PENDING)) {
|
||||
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "Removed barrier for inst %d\n", k);
|
||||
helper.insts[k].x86.barrier = 4; // remove barrier (keep FPU barrier, and still reset state flag)
|
||||
}
|
||||
}
|
||||
}
|
||||
// reset need_flags and compute again, now taking barrier into account (because barrier change use_flags)
|
||||
for(int i = helper.size; i-- > 0;) {
|
||||
if(helper.insts[i].x86.barrier==1)
|
||||
// immediate barrier
|
||||
helper.insts[i].x86.use_flags |= X_PEND;
|
||||
else if(helper.insts[i].x86.jmp
|
||||
&& helper.insts[i].x86.jmp_insts>=0
|
||||
) {
|
||||
if(helper.insts[helper.insts[i].x86.jmp_insts].x86.barrier==1)
|
||||
// jumpto barrier
|
||||
helper.insts[i].x86.use_flags |= X_PEND;
|
||||
else
|
||||
helper.insts[i].x86.use_flags |= helper.insts[helper.insts[i].x86.jmp_insts].x86.need_flags;
|
||||
}
|
||||
}
|
||||
for(int i = helper.size; i-- > 0;)
|
||||
helper.insts[i].x86.need_flags = 0;
|
||||
last_need = X_PEND;
|
||||
for(int i = helper.size; i-- > 0;) {
|
||||
helper.insts[i].x86.need_flags = last_need;
|
||||
if((helper.insts[i].x86.state_flags == SF_SUBSET) && (last_need&X_PEND))
|
||||
last_need = (X_ALL & (~helper.insts[i].x86.set_flags) ) | helper.insts[i].x86.use_flags;
|
||||
if ((helper.insts[i].x86.set_flags) && !(helper.insts[i].x86.state_flags & SF_MAYSET)) {
|
||||
if (last_need & X_PEND) {
|
||||
last_need = (~helper.insts[i].x86.set_flags) & X_ALL;
|
||||
} else {
|
||||
last_need &= ~helper.insts[i].x86.set_flags;
|
||||
}
|
||||
}
|
||||
last_need |= helper.insts[i].x86.use_flags;
|
||||
if (last_need == (X_PEND | X_ALL)) {
|
||||
last_need = X_ALL;
|
||||
}
|
||||
}
|
||||
|
||||
// pass 1, float optimisations
|
||||
arm_pass1(&helper, addr);
|
||||
|
||||
// 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(block, sz);
|
||||
if(p==NULL) {
|
||||
free(helper.insts);
|
||||
return;
|
||||
dynarec_log(LOG_DEBUG, "AllocDynarecMap(%p, %d) failed, cancelling block\n", block, sz);
|
||||
CancelBlock();
|
||||
return NULL;
|
||||
}
|
||||
helper.block = p;
|
||||
helper.tablesz = helper.tablei;
|
||||
if(helper.tablesz)
|
||||
helper.table = (uintptr_t*)calloc(helper.tablesz, sizeof(uintptr_t));
|
||||
helper.arm_start = (uintptr_t)p;
|
||||
if(helper.sons_size) {
|
||||
helper.sons_x86 = (uintptr_t*)calloc(helper.sons_size, sizeof(uintptr_t));
|
||||
helper.sons_arm = (void**)calloc(helper.sons_size, sizeof(void*));
|
||||
}
|
||||
// pass 3, emit (log emit arm opcode)
|
||||
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, "%s%04d|Emitting %d bytes for %d x86 bytes", (box86_dynarec_dump>1)?"\e[01;36m":"", GetTID(), helper.arm_size, helper.isize);
|
||||
printFunctionAddr(helper.start, " => ");
|
||||
dynarec_log(LOG_NONE, "%s\n", (box86_dynarec_dump>1)?"\e[m":"");
|
||||
}
|
||||
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);
|
||||
uint8_t *dump = (uint8_t*)helper.start;
|
||||
printf_log(LOG_NONE, "Dump of %d x86 opcodes:\n", helper.size);
|
||||
for(int i=0; i<helper.size; ++i) {
|
||||
printf_log(LOG_NONE, "%p:", dump);
|
||||
for(; dump<(uint8_t*)helper.insts[i+1].x86.addr; ++dump)
|
||||
printf_log(LOG_NONE, " %02X", *dump);
|
||||
printf_log(LOG_NONE, "\t%d -> %d\n", helper.insts[i].size2, helper.insts[i].size);
|
||||
}
|
||||
printf_log(LOG_NONE, " ------------\n");
|
||||
}
|
||||
// all done...
|
||||
__builtin___clear_cache(p, p+helper.arm_size); // need to clear the cache before execution...
|
||||
__clear_cache(p, p+sz); // need to clear the cache before execution...
|
||||
// keep size of instructions for signal handling
|
||||
{
|
||||
size_t cap = 1;
|
||||
for(int i=0; i<helper.size; ++i)
|
||||
cap += 1 + ((helper.insts[i].x86.size>helper.insts[i].size)?helper.insts[i].x86.size:helper.insts[i].size)/15;
|
||||
size_t size = 0;
|
||||
block->instsize = (instsize_t*)calloc(cap, sizeof(instsize_t));
|
||||
for(int i=0; i<helper.size; ++i)
|
||||
block->instsize = addInst(block->instsize, &size, &cap, helper.insts[i].x86.size, helper.insts[i].size/4);
|
||||
block->instsize = addInst(block->instsize, &size, &cap, 0, 0); // add a "end of block" mark, just in case
|
||||
}
|
||||
// ok, free the helper now
|
||||
free(helper.insts);
|
||||
block->table = helper.table;
|
||||
block->tablesz = helper.tablesz;
|
||||
helper.insts = NULL;
|
||||
free(helper.next);
|
||||
helper.next = NULL;
|
||||
block->size = sz;
|
||||
block->isize = helper.size;
|
||||
block->block = p;
|
||||
block->need_test = 0;
|
||||
//block->x86_addr = (void*)start;
|
||||
block->x86_size = end-start;
|
||||
if(box86_dynarec_largest<block->x86_size)
|
||||
box86_dynarec_largest = block->x86_size;
|
||||
block->hash = X31_hash_code(block->x86_addr, block->x86_size);
|
||||
// Check if something changed, to abbort if it as
|
||||
if(block->hash != hash) {
|
||||
dynarec_log(LOG_INFO, "Warning, a block changed while beeing processed hash(%p:%d)=%x/%x\n", block->x86_addr, block->x86_size, block->hash, hash);
|
||||
CancelBlock();
|
||||
return NULL;
|
||||
}
|
||||
// fill sons if any
|
||||
dynablock_t** sons = NULL;
|
||||
int sons_size = 0;
|
||||
if(helper.sons_size) {
|
||||
sons = (dynablock_t**)calloc(helper.sons_size, sizeof(dynablock_t*));
|
||||
for (int i=0; i<helper.sons_size; ++i) {
|
||||
int created = 1;
|
||||
dynablock_t *son = AddNewDynablock(block->parent, helper.sons_x86[i], &created);
|
||||
if(created) { // avoid breaking a working block!
|
||||
son->block = helper.sons_arm[i];
|
||||
son->x86_addr = (void*)helper.sons_x86[i];
|
||||
son->x86_size = end-helper.sons_x86[i];
|
||||
if(!son->x86_size) {printf_log(LOG_NONE, "Warning, son with null x86 size! (@%p / ARM=%p)", son->x86_addr, son->block);}
|
||||
son->father = block;
|
||||
son->done = 1;
|
||||
sons[sons_size++] = son;
|
||||
if(!son->parent)
|
||||
son->parent = block->parent;
|
||||
}
|
||||
}
|
||||
if(sons_size) {
|
||||
block->sons = sons;
|
||||
block->sons_size = sons_size;
|
||||
} else
|
||||
free(sons);
|
||||
}
|
||||
free(helper.sons_x86);
|
||||
helper.sons_x86 = NULL;
|
||||
free(helper.sons_arm);
|
||||
helper.sons_arm = NULL;
|
||||
current_helper = NULL;
|
||||
block->done = 1;
|
||||
return (void*)block;
|
||||
}
|
||||
+997
-973
File diff suppressed because it is too large.
Load diff
+951
-498
File diff suppressed because it is too large.
Load diff
Executable
+333
@@ -0,0 +1,333 @@
|
||||
#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, j32;
|
||||
uint32_t u32;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback;
|
||||
int fixedaddress;
|
||||
|
||||
MAYUSE(j32);
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0x03:
|
||||
INST_NAME("ADD Gd, FS:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO(x14);
|
||||
emit_add32(dyn, ninst, gd, ed, x3, x14);
|
||||
break;
|
||||
|
||||
case 0x2B:
|
||||
INST_NAME("SUB Gd, FS:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO(x14);
|
||||
emit_sub32(dyn, ninst, gd, ed, x3, x14);
|
||||
break;
|
||||
|
||||
case 0x33:
|
||||
INST_NAME("XOR Gd, FS:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO(x14);
|
||||
emit_xor32(dyn, ninst, gd, ed, x3, x14);
|
||||
break;
|
||||
|
||||
case 0x39:
|
||||
INST_NAME("CMP FS:Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO(x14);
|
||||
emit_cmp32(dyn, ninst, ed, gd, x3, x14);
|
||||
break;
|
||||
|
||||
case 0x3B:
|
||||
INST_NAME("CMP Gd, FS:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO(x14);
|
||||
emit_cmp32(dyn, ninst, gd, ed, x3, x14);
|
||||
break;
|
||||
|
||||
case 0x67:
|
||||
// reduced EA size...
|
||||
opcode = F8;
|
||||
switch(opcode) {
|
||||
case 0x89:
|
||||
INST_NAME("MOV FS:Ew16, Gw");
|
||||
nextop = F8;
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
GETGD; // don't need GETGW here
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xEAX+(nextop&7);
|
||||
if(ed!=gd) {
|
||||
BFI(ed, gd, 0, 16);
|
||||
}
|
||||
} else {
|
||||
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
|
||||
STRH_REG(gd, x14, ed);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x8B:
|
||||
INST_NAME("MOV Gd, FS:Ew16");
|
||||
nextop=F8;
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) { // reg <= reg
|
||||
MOV_REG(gd, xEAX+(nextop&7));
|
||||
} else { // mem <= reg
|
||||
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
|
||||
LDR_REG_LSL_IMM5(gd, ed, x14, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x8F:
|
||||
INST_NAME("POP FS:Ew16");
|
||||
nextop=F8;
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
POP1(xEAX+(nextop&7)); // 67 ignored
|
||||
} else {
|
||||
addr = geted16(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
|
||||
POP1(x2);
|
||||
STR_REG_LSL_IMM5(x2, x1, x14, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xA1:
|
||||
INST_NAME("MOV EAX, FS:Ow");
|
||||
grab_fsdata(dyn, addr, ninst, x1);
|
||||
u32 = F16;
|
||||
if(u32) {
|
||||
MOV32(x2, u32);
|
||||
ADD_REG_LSL_IMM5(x1, x1, x2, 0);
|
||||
}
|
||||
LDR_IMM9(xEAX, x1, 0);
|
||||
break;
|
||||
|
||||
case 0xA3:
|
||||
INST_NAME("MOV FS:Ow, EAX");
|
||||
grab_fsdata(dyn, addr, ninst, x1);
|
||||
u32 = F16;
|
||||
if(u32) {
|
||||
MOV32(x2, u32);
|
||||
ADD_REG_LSL_IMM5(x1, x1, x2, 0);
|
||||
}
|
||||
STR_IMM9(xEAX, x1, 0);
|
||||
break;
|
||||
|
||||
case 0xFF:
|
||||
nextop = F8;
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
switch((nextop>>3)&7) {
|
||||
case 6: // Push Ed
|
||||
INST_NAME("PUSH FS:Ew");
|
||||
if((nextop&0xC0)==0xC0) { // reg
|
||||
DEFAULT;
|
||||
} else { // mem <= i32
|
||||
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
|
||||
LDR_REG_LSL_IMM5(x3, ed, x14, 0);
|
||||
PUSH1(x3);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x89:
|
||||
INST_NAME("MOV FS:Ed, Gd");
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
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, 0);
|
||||
STR_REG_LSL_IMM5(gd, ed, x14, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x8B:
|
||||
INST_NAME("MOV Gd, FS:Ed");
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
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, 0);
|
||||
LDR_REG_LSL_IMM5(gd, ed, x14, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x8F:
|
||||
INST_NAME("POP FS:Ed");
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
nextop = F8;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
POP1(xEAX+(nextop&7));
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
POP1(x2);
|
||||
STR_REG_LSL_IMM5(x2, ed, x14, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xA0:
|
||||
INST_NAME("MOV AL, FS:Id");
|
||||
grab_fsdata(dyn, addr, ninst, x1);
|
||||
i32 = F32S;
|
||||
if(i32>-4096 && i32<4096) {
|
||||
LDRB_IMM9(xEAX, x1, i32);
|
||||
} else {
|
||||
MOV32(x2, i32);
|
||||
LDRB_REG_LSL_IMM5(xEAX, x1, x2, 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);
|
||||
LDR_REG_LSL_IMM5(xEAX, x1, x2, 0);
|
||||
}
|
||||
break;
|
||||
case 0xA2:
|
||||
INST_NAME("MOV FS:Od, AL");
|
||||
grab_fsdata(dyn, addr, ninst, x1);
|
||||
i32 = F32S;
|
||||
if(i32>-4096 && i32<4096) {
|
||||
STRB_IMM9(xEAX, x1, i32);
|
||||
} else {
|
||||
MOV32(x2, i32);
|
||||
STRB_REG_LSL_IMM5(xEAX, x1, x2, 0);
|
||||
}
|
||||
break;
|
||||
case 0xA3:
|
||||
INST_NAME("MOV FS:Od, EAX");
|
||||
grab_fsdata(dyn, addr, ninst, x1);
|
||||
i32 = F32S;
|
||||
if(i32>-4096 && i32<4096) {
|
||||
STR_IMM9(xEAX, x1, i32);
|
||||
} else {
|
||||
MOV32(x2, i32);
|
||||
STR_REG_LSL_IMM5(xEAX, x2, x1, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC7:
|
||||
INST_NAME("MOV FS:Ed, Id");
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
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, 0);
|
||||
i32 = F32S;
|
||||
MOV32(x3, i32);
|
||||
STR_REG_LSL_IMM5(x3, ed, x14, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xE9:
|
||||
case 0xEB:
|
||||
INST_NAME("(ignored) FS:");
|
||||
--addr;
|
||||
break;
|
||||
|
||||
case 0xFF:
|
||||
nextop = F8;
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
switch((nextop>>3)&7) {
|
||||
case 2: // CALL Ed
|
||||
INST_NAME("CALL FS:Ed");
|
||||
PASS2IF(ninst && dyn->insts[ninst-1].x86.set_flags, 1) {
|
||||
READFLAGS(X_PEND); // that's suspicious
|
||||
} else {
|
||||
SETFLAGS(X_ALL, SF_SET); //Hack to put flag in "don't care" state
|
||||
}
|
||||
if((nextop&0xC0)==0xC0) { // reg
|
||||
MOV_REG(xEIP, xEAX+(nextop&7));
|
||||
} else { // mem
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0);
|
||||
LDR_REG_LSL_IMM5(xEIP, ed, x14, 0);
|
||||
}
|
||||
BARRIER(1);
|
||||
BARRIER_NEXT(1);
|
||||
if(!dyn->insts || ninst!=dyn->size-1) {
|
||||
} else {
|
||||
*need_epilog = 0;
|
||||
*ok = 0;
|
||||
}
|
||||
MOV32(x2, addr);
|
||||
PUSH1(x2);
|
||||
jump_to_next(dyn, 0, xEIP, ninst);
|
||||
break;
|
||||
case 6: // Push Ed
|
||||
INST_NAME("PUSH FS:Ed");
|
||||
if((nextop&0xC0)==0xC0) { // reg
|
||||
DEFAULT;
|
||||
} else { // mem <= i32
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0);
|
||||
LDR_REG_LSL_IMM5(x3, ed, x14, 0);
|
||||
PUSH1(x3);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
+521
-22
@@ -25,53 +25,362 @@ uintptr_t dynarecGS(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
{
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop;
|
||||
int32_t i32;
|
||||
int32_t i32, j32;
|
||||
uint32_t u32;
|
||||
uint8_t gd, ed;
|
||||
uint8_t wback, wb1, wb2;
|
||||
uint8_t wback, wb1, wb2, wb;
|
||||
uint8_t u8;
|
||||
int fixedaddress;
|
||||
|
||||
MAYUSE(j32);
|
||||
MAYUSE(wback);
|
||||
MAYUSE(wb2);
|
||||
|
||||
switch(opcode) {
|
||||
case 0x33:
|
||||
grab_tlsdata(dyn, addr, ninst, x12);
|
||||
INST_NAME("GS:XOR Gd, Ed");
|
||||
|
||||
case 0x03:
|
||||
INST_NAME("ADD Gd, GS:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO(x12);
|
||||
XOR_REG_LSL_IMM8(gd, gd, ed, 0);
|
||||
UFLAG_RES(gd);
|
||||
UFLAG_DF(1, d_xor32);
|
||||
UFLAGS(0);
|
||||
GETEDO(x14);
|
||||
emit_add32(dyn, ninst, gd, ed, x3, x14);
|
||||
break;
|
||||
|
||||
case 0x0F: // more opcodes
|
||||
opcode = F8;
|
||||
switch(opcode) {
|
||||
|
||||
case 0xAF:
|
||||
INST_NAME("IMUL Gd, Ed");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO(x14);
|
||||
UFLAG_IF {
|
||||
SMULL(x3, gd, gd, ed);
|
||||
UFLAG_OP1(x3);
|
||||
UFLAG_RES(gd);
|
||||
UFLAG_DF(x3, d_imul32);
|
||||
} else {
|
||||
MUL(gd, gd, ed);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x21:
|
||||
INST_NAME("AND Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO2(x14);
|
||||
emit_and32(dyn, ninst, ed, gd, x3, x14);
|
||||
WBACK;
|
||||
break;
|
||||
|
||||
case 0x23:
|
||||
INST_NAME("AND Gd, GS:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO(x14);
|
||||
emit_and32(dyn, ninst, gd, ed, x3, x14);
|
||||
break;
|
||||
|
||||
case 0x29:
|
||||
INST_NAME("SUB GS:Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO2(x14);
|
||||
emit_sub32(dyn, ninst, ed, gd, x3, x14);
|
||||
WBACK;
|
||||
break;
|
||||
|
||||
case 0x2B:
|
||||
INST_NAME("SUB Gd, GS:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO(x14);
|
||||
emit_sub32(dyn, ninst, gd, ed, x3, x14);
|
||||
break;
|
||||
|
||||
case 0x31:
|
||||
INST_NAME("XOR GS:Ed, Gd");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO2(x14);
|
||||
emit_xor32(dyn, ninst, gd, ed, x3, x14);
|
||||
WBACK;
|
||||
break;
|
||||
|
||||
case 0x33:
|
||||
INST_NAME("XOR Gd, GS:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO(x14);
|
||||
emit_xor32(dyn, ninst, gd, ed, x3, x14);
|
||||
break;
|
||||
|
||||
case 0x3B:
|
||||
INST_NAME("CMP Gd, GS:Ed");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO(x14);
|
||||
emit_cmp32(dyn, ninst, gd, ed, x3, x14);
|
||||
break;
|
||||
|
||||
case 0x69:
|
||||
INST_NAME("IMUL Gd, GS:Ed, Id");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
GETEDO(x14);
|
||||
i32 = F32S;
|
||||
MOV32(x14, i32);
|
||||
UFLAG_IF {
|
||||
SMULL(x3, gd, x14, ed);
|
||||
UFLAG_OP1(x3);
|
||||
UFLAG_RES(gd);
|
||||
UFLAG_DF(x3, d_imul32);
|
||||
} else {
|
||||
MUL(gd, ed, x14);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x80:
|
||||
case 0x82:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: //ADD
|
||||
INST_NAME("ADD GS:Eb, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_tlsdata(dyn, addr, ninst, x1);
|
||||
GETEBO(x1);
|
||||
u8 = F8;
|
||||
emit_add8c(dyn, ninst, x1, u8, x2, x14);
|
||||
EBBACK;
|
||||
break;
|
||||
case 1: //OR
|
||||
INST_NAME("OR GS:Eb, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_tlsdata(dyn, addr, ninst, x1);
|
||||
GETEBO(x1);
|
||||
u8 = F8;
|
||||
emit_or8c(dyn, ninst, x1, u8, x2, x14);
|
||||
EBBACK;
|
||||
break;
|
||||
case 2: //ADC
|
||||
INST_NAME("ADC GS:Eb, Ib");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_tlsdata(dyn, addr, ninst, x1);
|
||||
GETEBO(x1);
|
||||
u8 = F8;
|
||||
emit_adc8c(dyn, ninst, x1, u8, x2, x14);
|
||||
EBBACK;
|
||||
break;
|
||||
case 3: //SBB
|
||||
INST_NAME("SBB GS:Eb, Ib");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_tlsdata(dyn, addr, ninst, x1);
|
||||
GETEBO(x1);
|
||||
u8 = F8;
|
||||
emit_sbb8c(dyn, ninst, x1, u8, x2, x14);
|
||||
EBBACK;
|
||||
break;
|
||||
case 4: //AND
|
||||
INST_NAME("AND GS:Eb, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_tlsdata(dyn, addr, ninst, x1);
|
||||
GETEBO(x1);
|
||||
u8 = F8;
|
||||
emit_and8c(dyn, ninst, x1, u8, x2, x14);
|
||||
EBBACK;
|
||||
break;
|
||||
case 5: //SUB
|
||||
INST_NAME("SUB GS:Eb, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_tlsdata(dyn, addr, ninst, x1);
|
||||
GETEBO(x1);
|
||||
u8 = F8;
|
||||
emit_sub8c(dyn, ninst, x1, u8, x2, x14);
|
||||
EBBACK;
|
||||
break;
|
||||
case 6: //XOR
|
||||
INST_NAME("XOR GS:Eb, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_tlsdata(dyn, addr, ninst, x1);
|
||||
GETEBO(x1);
|
||||
u8 = F8;
|
||||
emit_xor8c(dyn, ninst, x1, u8, x2, x14);
|
||||
EBBACK;
|
||||
break;
|
||||
case 7: //CMP
|
||||
INST_NAME("CMP GS:Eb, Ib");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_tlsdata(dyn, addr, ninst, x1);
|
||||
GETEBO(x1);
|
||||
u8 = F8;
|
||||
if(u8) {
|
||||
MOVW(x2, u8);
|
||||
emit_cmp8(dyn, ninst, x1, x2, x3, x14);
|
||||
} else {
|
||||
emit_cmp8_0(dyn, ninst, x1, x3, x14);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x81:
|
||||
case 0x83:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: //ADD
|
||||
if(opcode==0x81) {
|
||||
INST_NAME("ADD Ed, Id");
|
||||
} else {
|
||||
INST_NAME("ADD Ed, Ib");
|
||||
}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
GETEDO2(x14);
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
emit_add32c(dyn, ninst, ed, i32, x3, x14);
|
||||
WBACK;
|
||||
break;
|
||||
case 1: //OR
|
||||
if(opcode==0x81) {INST_NAME("OR Ed, Id");} else {INST_NAME("OR Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
GETEDO2(x14);
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
emit_or32c(dyn, ninst, ed, i32, x3, x14);
|
||||
WBACK;
|
||||
break;
|
||||
case 2: //ADC
|
||||
if(opcode==0x81) {INST_NAME("ADC Ed, Id");} else {INST_NAME("ADC Ed, Ib");}
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
GETEDO2(x14);
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
emit_adc32c(dyn, ninst, ed, i32, x3, x14);
|
||||
WBACK;
|
||||
break;
|
||||
case 3: //SBB
|
||||
if(opcode==0x81) {INST_NAME("SBB Ed, Id");} else {INST_NAME("SBB Ed, Ib");}
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
GETEDO2(x14);
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
emit_sbb32c(dyn, ninst, ed, i32, x3, x14);
|
||||
WBACK;
|
||||
break;
|
||||
case 4: //AND
|
||||
if(opcode==0x81) {INST_NAME("AND Ed, Id");} else {INST_NAME("AND Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
GETEDO2(x14);
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
emit_and32c(dyn, ninst, ed, i32, x3, x14);
|
||||
WBACK;
|
||||
break;
|
||||
case 5: //SUB
|
||||
if(opcode==0x81) {INST_NAME("SUB Ed, Id");} else {INST_NAME("SUB Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
GETEDO2(x14);
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
emit_sub32c(dyn, ninst, ed, i32, x3, x14);
|
||||
WBACK;
|
||||
break;
|
||||
case 6: //XOR
|
||||
if(opcode==0x81) {INST_NAME("XOR Ed, Id");} else {INST_NAME("XOR Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
GETEDO2(x14);
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
emit_xor32c(dyn, ninst, ed, i32, x3, x14);
|
||||
WBACK;
|
||||
break;
|
||||
case 7: //CMP
|
||||
if(opcode==0x81) {INST_NAME("CMP Ed, Id");} else {INST_NAME("CMP Ed, Ib");}
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING);
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
GETEDO2(x14);
|
||||
if(opcode==0x81) i32 = F32S; else i32 = F8S;
|
||||
if(i32) {
|
||||
MOV32(x2, i32);
|
||||
emit_cmp32(dyn, ninst, ed, x2, x3, x14);
|
||||
} else {
|
||||
emit_cmp32_0(dyn, ninst, ed, x3, x14);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x89:
|
||||
grab_tlsdata(dyn, addr, ninst, x12);
|
||||
INST_NAME("MOV GS:Ed, Gd");
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
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);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0);
|
||||
STR_REG_LSL_IMM5(gd, ed, x14, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x8B:
|
||||
grab_tlsdata(dyn, addr, ninst, x12);
|
||||
INST_NAME("MOV Gd, GS:Ed");
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
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);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0);
|
||||
LDR_REG_LSL_IMM5(gd, ed, x14, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x8F:
|
||||
INST_NAME("POP GS:Ed");
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
nextop = F8;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
POP1((xEAX+(nextop&7)));
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
POP1(x2);
|
||||
STR_REG_LSL_IMM5(x2, ed, x14, 0);
|
||||
}
|
||||
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 +392,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,23 +401,213 @@ 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, x14);
|
||||
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);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0);
|
||||
i32 = F32S;
|
||||
MOV32(x3, i32);
|
||||
STR_REG_LSL_IMM5(x3, ed, x12, 0);
|
||||
STR_REG_LSL_IMM5(x3, ed, x14, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xD1:
|
||||
nextop = F8;
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("ROL Ed, 1");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET);
|
||||
GETEDO2(x14);
|
||||
emit_rol32c(dyn, ninst, ed, 1, x3, x14);
|
||||
WBACK;
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("ROR Ed, 1");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET);
|
||||
GETEDO2(x14);
|
||||
emit_ror32c(dyn, ninst, ed, 1, x3, x14);
|
||||
WBACK;
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("RCL Ed, 1");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
MOVW(x2, 1);
|
||||
GETEDO2(x14);
|
||||
wb = ed;
|
||||
if(ed!=x1) {MOV_REG(x1, ed); wb = x1;}
|
||||
CALL_(rcl32, ed, (1<<x14));
|
||||
SBACK(wb);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("RCR Ed, 1");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
MOVW(x2, 1);
|
||||
wb = ed;
|
||||
if(ed!=x1) {MOV_REG(x1, ed); wb = x1;}
|
||||
CALL_(rcr32, ed, (1<<x14));
|
||||
SBACK(wb);
|
||||
break;
|
||||
case 4:
|
||||
case 6:
|
||||
INST_NAME("SHL Ed, 1");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
GETEDO2(x14);
|
||||
emit_shl32c(dyn, ninst, ed, 1, x3, x14);
|
||||
WBACK;
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("SHR Ed, 1");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
GETEDO2(x14);
|
||||
emit_shr32c(dyn, ninst, ed, 1, x3, x14);
|
||||
WBACK;
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("SAR Ed, 1");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
GETEDO2(x14);
|
||||
emit_sar32c(dyn, ninst, ed, 1, x3, x14);
|
||||
WBACK;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0xD3:
|
||||
nextop = F8;
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("ROL Ed, CL");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET);
|
||||
AND_IMM8(x3, xECX, 0x1f);
|
||||
TSTS_REG_LSL_IMM5(x3, x3, 0);
|
||||
B_MARK2(cEQ);
|
||||
RSB_IMM8(x3, x3, 0x20);
|
||||
GETEDO2(x14);
|
||||
MOV_REG_ROR_REG(ed, ed, x3);
|
||||
WBACK;
|
||||
UFLAG_IF { // calculate flags directly
|
||||
CMPS_IMM8(x3, 31);
|
||||
B_MARK(cNE);
|
||||
MOV_REG_LSR_IMM5(x1, ed, 31);
|
||||
ADD_REG_LSL_IMM5(x1, x1, ed, 0);
|
||||
BFI(xFlags, x1, F_OF, 1);
|
||||
MARK;
|
||||
BFI(xFlags, ed, F_CF, 1);
|
||||
UFLAG_DF(x2, d_none);
|
||||
}
|
||||
MARK2;
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("ROR Ed, CL");
|
||||
SETFLAGS(X_OF|X_CF, SF_SUBSET);
|
||||
AND_IMM8(x3, xECX, 0x1f);
|
||||
TSTS_REG_LSL_IMM5(x3, x3, 0);
|
||||
B_MARK2(cEQ);
|
||||
GETEDO2(x14);
|
||||
MOV_REG_ROR_REG(ed, ed, x3);
|
||||
WBACK;
|
||||
UFLAG_IF { // calculate flags directly
|
||||
CMPS_IMM8(x3, 1);
|
||||
B_MARK(cNE);
|
||||
MOV_REG_LSR_IMM5(x2, ed, 30); // x2 = d>>30
|
||||
XOR_REG_LSR_IMM8(x2, x2, x2, 1); // x2 = ((d>>30) ^ ((d>>30)>>1))
|
||||
BFI(xFlags, x2, F_OF, 1);
|
||||
MARK;
|
||||
MOV_REG_LSR_IMM5(x2, ed, 31);
|
||||
BFI(xFlags, x2, F_CF, 1);
|
||||
UFLAG_DF(x2, d_none);
|
||||
}
|
||||
MARK2;
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("RCL Ed, CL");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
AND_IMM8(x2, xECX, 0x1f);
|
||||
wb = ed;
|
||||
if(ed!=x1) {MOV_REG(x1, ed); wb = x1;}
|
||||
CALL_(rcl32, ed, (1<<x14));
|
||||
SBACK(wb);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("RCR Ed, CL");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
READFLAGS(X_CF);
|
||||
SETFLAGS(X_OF|X_CF, SF_SET);
|
||||
AND_IMM8(x2, xECX, 0x1f);
|
||||
wb = ed;
|
||||
if(ed!=x1) {MOV_REG(x1, ed); wb = x1;}
|
||||
CALL_(rcr32, ed, (1<<x14));
|
||||
SBACK(wb);
|
||||
break;
|
||||
case 4:
|
||||
case 6:
|
||||
INST_NAME("SHL Ed, CL");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
AND_IMM8(x3, xECX, 0x1f);
|
||||
GETEDO2(x14);
|
||||
emit_shl32(dyn, ninst, ed, x3, x3, x14);
|
||||
WBACK;
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("SHR Ed, CL");
|
||||
SETFLAGS(X_ALL, SF_SET_PENDING); // some flags are left undefined
|
||||
AND_IMM8(x3, xECX, 0x1f);
|
||||
GETEDO2(x14);
|
||||
emit_shr32(dyn, ninst, ed, x3, x3, x14);
|
||||
WBACK;
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("SAR Ed, CL");
|
||||
SETFLAGS(X_ALL, SF_PENDING);
|
||||
AND_IMM8(x3, xECX, 0x1f);
|
||||
GETEDO2(x14);
|
||||
UFLAG_OP12(ed, x3);
|
||||
MOV_REG_ASR_REG(ed, ed, x3);
|
||||
WBACK;
|
||||
UFLAG_RES(ed);
|
||||
UFLAG_DF(x3, d_sar32);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xE9:
|
||||
case 0xEB:
|
||||
INST_NAME("(ignored) GS:");
|
||||
--addr;
|
||||
break;
|
||||
|
||||
case 0xFF:
|
||||
nextop = F8;
|
||||
grab_tlsdata(dyn, addr, ninst, x14);
|
||||
switch((nextop>>3)&7) {
|
||||
case 6: // Push Ed
|
||||
INST_NAME("PUSH GS:Ed");
|
||||
if((nextop&0xC0)==0xC0) { // reg
|
||||
DEFAULT;
|
||||
} else { // mem <= i32
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0, 0);
|
||||
LDR_REG_LSL_IMM5(x3, ed, x14, 0);
|
||||
PUSH1(x3);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
*ok = 0;
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
|
||||
+393
-297
File diff suppressed because it is too large.
Load diff
+1205
-328
File diff suppressed because it is too large.
Load diff
+112
-22
@@ -21,31 +21,126 @@
|
||||
|
||||
#include "dynarec_arm_helper.h"
|
||||
|
||||
|
||||
uintptr_t dynarec67(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, int* ok, int* need_epilog)
|
||||
{
|
||||
uint8_t opcode = F8;
|
||||
uint8_t nextop, u8;
|
||||
uint8_t nextop, opcode;
|
||||
int8_t i8;
|
||||
int32_t i32, j32;
|
||||
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);
|
||||
MAYUSE(j32);
|
||||
|
||||
nextop = F8;
|
||||
|
||||
switch(nextop) {
|
||||
|
||||
|
||||
#define GO(NO, YES) \
|
||||
BARRIER(2); \
|
||||
JUMP(addr+i8);\
|
||||
case 0x64:
|
||||
// reduced EA size...
|
||||
opcode = F8;
|
||||
switch(opcode) {
|
||||
case 0x89:
|
||||
INST_NAME("MOV FS:Ew16, Gw");
|
||||
nextop = F8;
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
GETGD; // don't need GETGW here
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xEAX+(nextop&7);
|
||||
if(ed!=gd) {
|
||||
BFI(ed, gd, 0, 16);
|
||||
}
|
||||
} else {
|
||||
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
|
||||
STRH_REG(gd, x14, ed);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x8B:
|
||||
INST_NAME("MOV Gd, FS:Ew16");
|
||||
nextop=F8;
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
GETGD;
|
||||
if((nextop&0xC0)==0xC0) { // reg <= reg
|
||||
ed = xEAX+(nextop&7);
|
||||
if(ed!=gd) {
|
||||
BFI(gd, ed, 0, 16);
|
||||
}
|
||||
} else { // mem <= reg
|
||||
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
|
||||
LDR_REG_LSL_IMM5(gd, x14, ed, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x8F:
|
||||
INST_NAME("POP FS:Ew16");
|
||||
nextop=F8;
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
POP1(xEAX+(nextop&7)); // 67 ignored
|
||||
} else {
|
||||
addr = geted16(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
|
||||
POP1(x2);
|
||||
STR_REG_LSL_IMM5(x2, x14, ed, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xA1:
|
||||
INST_NAME("MOV EAX, FS:Ow");
|
||||
grab_fsdata(dyn, addr, ninst, x1);
|
||||
u32 = F16;
|
||||
if(u32) {
|
||||
MOV32(x2, u32);
|
||||
ADD_REG_LSL_IMM5(x1, x1, x2, 0);
|
||||
}
|
||||
LDR_IMM9(xEAX, x1, 0);
|
||||
break;
|
||||
|
||||
case 0xA3:
|
||||
INST_NAME("MOV FS:Ow, EAX");
|
||||
grab_fsdata(dyn, addr, ninst, x1);
|
||||
u32 = F16;
|
||||
if(u32) {
|
||||
MOV32(x2, u32);
|
||||
ADD_REG_LSL_IMM5(x1, x1, x2, 0);
|
||||
}
|
||||
STR_IMM9(xEAX, x1, 0);
|
||||
break;
|
||||
|
||||
case 0xFF:
|
||||
nextop = F8;
|
||||
grab_fsdata(dyn, addr, ninst, x14);
|
||||
switch((nextop>>3)&7) {
|
||||
case 6: // Push Ed
|
||||
INST_NAME("PUSH FS:Ew");
|
||||
if((nextop&0xC0)==0xC0) { // reg
|
||||
DEFAULT;
|
||||
} else { // mem <= i32
|
||||
addr = geted16(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 0, 0);
|
||||
LDR_REG_LSL_IMM5(x3, ed, x14, 0);
|
||||
PUSH1(x3);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEFAULT;
|
||||
}
|
||||
break;
|
||||
|
||||
#define GO(NO, YES) \
|
||||
BARRIER(2); \
|
||||
JUMP(addr+i8, 1); \
|
||||
if(dyn->insts) { \
|
||||
if(dyn->insts[ninst].x86.jmp_insts==-1) { \
|
||||
/* out of the block */ \
|
||||
i32 = dyn->insts[ninst+1].address-(dyn->arm_size+8); \
|
||||
Bcond(NO, i32); \
|
||||
jump_to_linker(dyn, addr+i8, 0, ninst); \
|
||||
jump_to_next(dyn, addr+i8, 0, ninst); \
|
||||
} else { \
|
||||
/* inside the block */ \
|
||||
i32 = dyn->insts[dyn->insts[ninst].x86.jmp_insts].address-(dyn->arm_size+8); \
|
||||
@@ -54,31 +149,28 @@ 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_IMM8(xFlags, 1<<F_ZF);
|
||||
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_IMM8(xFlags, 1<<F_ZF);
|
||||
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 +179,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;
|
||||
|
||||
+190
-77
@@ -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:
|
||||
@@ -48,9 +50,13 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
INST_NAME("FADD ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VADD_F64(v1, v1, v2);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
VADD_F32(v1, v1, v2);
|
||||
} else {
|
||||
VADD_F64(v1, v1, v2);
|
||||
}
|
||||
break;
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
@@ -61,9 +67,13 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xCE:
|
||||
case 0xCF:
|
||||
INST_NAME("FMUL ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VMUL_F64(v1, v1, v2);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
VMUL_F32(v1, v1, v2);
|
||||
} else {
|
||||
VMUL_F64(v1, v1, v2);
|
||||
}
|
||||
break;
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
@@ -74,9 +84,13 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
INST_NAME("FCOM ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VCMP_F64(v1, v2);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
VCMP_F32(v1, v2);
|
||||
} else {
|
||||
VCMP_F64(v1, v2);
|
||||
}
|
||||
FCOM(x1, x2);
|
||||
break;
|
||||
case 0xD8:
|
||||
@@ -88,11 +102,15 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xDE:
|
||||
case 0xDF:
|
||||
INST_NAME("FCOMP ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VCMP_F64(v1, v2);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
VCMP_F32(v1, v2);
|
||||
} else {
|
||||
VCMP_F64(v1, v2);
|
||||
}
|
||||
FCOM(x1, x2);
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xE0:
|
||||
case 0xE1:
|
||||
@@ -103,9 +121,13 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
INST_NAME("FSUB ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VSUB_F64(v1, v1, v2);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
VSUB_F32(v1, v1, v2);
|
||||
} else {
|
||||
VSUB_F64(v1, v1, v2);
|
||||
}
|
||||
break;
|
||||
case 0xE8:
|
||||
case 0xE9:
|
||||
@@ -116,9 +138,13 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xEE:
|
||||
case 0xEF:
|
||||
INST_NAME("FSUBR ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VSUB_F64(v1, v2, v1);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
VSUB_F32(v1, v2, v1);
|
||||
} else {
|
||||
VSUB_F64(v1, v2, v1);
|
||||
}
|
||||
break;
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
@@ -129,9 +155,13 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
INST_NAME("FDIV ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VDIV_F64(v1, v1, v2);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
VDIV_F32(v1, v1, v2);
|
||||
} else {
|
||||
VDIV_F64(v1, v1, v2);
|
||||
}
|
||||
break;
|
||||
case 0xF8:
|
||||
case 0xF9:
|
||||
@@ -142,98 +172,181 @@ uintptr_t dynarecD8(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xFE:
|
||||
case 0xFF:
|
||||
INST_NAME("FDIVR ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VDIV_F64(v1, v2, v1);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
VDIV_F32(v1, v2, v1);
|
||||
} else {
|
||||
VDIV_F64(v1, v2, v1);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FADD ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
GETED;
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
VMOVtoV(s0, ed);
|
||||
VCVT_F64_F32(d1, s0);
|
||||
VADD_F64(v1, v1, d1);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
GETED;
|
||||
VMOVtoV(s0, ed);
|
||||
}
|
||||
if(ST_IS_F(0)) {
|
||||
VADD_F32(v1, v1, s0);
|
||||
} else {
|
||||
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;
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
VMOVtoV(s0, ed);
|
||||
VCVT_F64_F32(d1, s0);
|
||||
VMUL_F64(v1, v1, d1);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
GETED;
|
||||
VMOVtoV(s0, ed);
|
||||
}
|
||||
if(ST_IS_F(0)) {
|
||||
VMUL_F32(v1, v1, s0);
|
||||
} else {
|
||||
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;
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
VMOVtoV(s0, ed);
|
||||
VCVT_F64_F32(d1, s0);
|
||||
VCMP_F64(v1, d1);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
GETED;
|
||||
VMOVtoV(s0, ed);
|
||||
}
|
||||
if(ST_IS_F(0)) {
|
||||
VCMP_F32(v1, s0);
|
||||
} else {
|
||||
VCVT_F64_F32(d1, s0);
|
||||
VCMP_F64(v1, d1);
|
||||
}
|
||||
FCOM(x1, x2);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FCOMP ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
GETED;
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
VMOVtoV(s0, ed);
|
||||
VCVT_F64_F32(d1, s0);
|
||||
VCMP_F64(v1, d1);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
GETED;
|
||||
VMOVtoV(s0, ed);
|
||||
}
|
||||
if(ST_IS_F(0)) {
|
||||
VCMP_F32(v1, s0);
|
||||
} else {
|
||||
VCVT_F64_F32(d1, s0);
|
||||
VCMP_F64(v1, d1);
|
||||
}
|
||||
FCOM(x1, x2);
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FSUB ST0, float[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
GETED;
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
VMOVtoV(s0, ed);
|
||||
VCVT_F64_F32(d1, s0);
|
||||
VSUB_F64(v1, v1, d1);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
GETED;
|
||||
VMOVtoV(s0, ed);
|
||||
}
|
||||
if(ST_IS_F(0)) {
|
||||
VSUB_F32(v1, v1, s0);
|
||||
} else {
|
||||
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;
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
VMOVtoV(s0, ed);
|
||||
VCVT_F64_F32(d1, s0);
|
||||
VSUB_F64(v1, d1, v1);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
GETED;
|
||||
VMOVtoV(s0, ed);
|
||||
}
|
||||
if(ST_IS_F(0)) {
|
||||
VSUB_F32(v1, s0, v1);
|
||||
} else {
|
||||
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;
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
VMOVtoV(s0, ed);
|
||||
VCVT_F64_F32(d1, s0);
|
||||
VDIV_F64(v1, v1, d1);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
GETED;
|
||||
VMOVtoV(s0, ed);
|
||||
}
|
||||
if(ST_IS_F(0)) {
|
||||
VDIV_F32(v1, v1, s0);
|
||||
} else {
|
||||
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;
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
VMOVtoV(s0, ed);
|
||||
VCVT_F64_F32(d1, s0);
|
||||
VDIV_F64(v1, d1, v1);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
GETED;
|
||||
VMOVtoV(s0, ed);
|
||||
}
|
||||
if(ST_IS_F(0)) {
|
||||
VDIV_F32(v1, s0, v1);
|
||||
} else {
|
||||
VCVT_F64_F32(d1, s0);
|
||||
VDIV_F64(v1, d1, v1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
*ok = 0;
|
||||
DEFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
+343
-108
@@ -23,28 +23,34 @@
|
||||
#include "dynarec_arm_functions.h"
|
||||
#include "dynarec_arm_helper.h"
|
||||
|
||||
static double d_1 = 1.0;
|
||||
static double d_l2t = L2T;
|
||||
static double d_l2e = L2E;
|
||||
static double d_pi = PI;
|
||||
static double d_lg2 = LG2;
|
||||
static double d_ln2 = LN2;
|
||||
static double d_0 = 0.0;
|
||||
static const double d_l2t = L2T;
|
||||
static const double d_l2e = L2E;
|
||||
static const double d_pi = PI;
|
||||
static const double d_lg2 = LG2;
|
||||
static const double d_ln2 = LN2;
|
||||
static const float f_l2t = L2T;
|
||||
static const float f_l2e = L2E;
|
||||
static const float f_pi = PI;
|
||||
static const float f_lg2 = LG2;
|
||||
static const float f_ln2 = LN2;
|
||||
|
||||
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 j32;
|
||||
int parity;
|
||||
|
||||
MAYUSE(s0);
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
MAYUSE(j32);
|
||||
|
||||
switch(nextop) {
|
||||
|
||||
case 0xC0:
|
||||
@@ -56,9 +62,13 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
INST_NAME("FLD STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
v2 = x87_do_push(dyn, ninst);
|
||||
VMOV_64(v2, v1);
|
||||
v2 = x87_do_push(dyn, ninst, x3, X87_ST(nextop&7));
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, (nextop&7)+1, X87_COMBINE(0, (nextop&7)+1));
|
||||
if(ST_IS_F(0)) {
|
||||
VMOV_32(v2, v1);
|
||||
} else {
|
||||
VMOV_64(v2, v1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC8:
|
||||
@@ -71,11 +81,17 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xCF:
|
||||
INST_NAME("FXCH STx");
|
||||
// swap the cache value, not the double value itself :p
|
||||
i1 = x87_get_cache(dyn, ninst, x1, x2, nextop&7);
|
||||
i2 = x87_get_cache(dyn, ninst, x1, x2, 0);
|
||||
i1 = x87_get_cache(dyn, ninst, 1, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
i2 = x87_get_cache(dyn, ninst, 1, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
i3 = dyn->x87cache[i1];
|
||||
dyn->x87cache[i1] = dyn->x87cache[i2];
|
||||
dyn->x87cache[i2] = i3;
|
||||
// swap those too
|
||||
i1 = x87_get_neoncache(dyn, ninst, x1, x2, nextop&7);
|
||||
i2 = x87_get_neoncache(dyn, ninst, x1, x2, 0);
|
||||
i3 = dyn->n.neoncache[i1].v;
|
||||
dyn->n.neoncache[i1].v = dyn->n.neoncache[i2].v;
|
||||
dyn->n.neoncache[i2].v = i3;
|
||||
break;
|
||||
|
||||
case 0xD0:
|
||||
@@ -84,78 +100,184 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
|
||||
case 0xE0:
|
||||
INST_NAME("FCHS");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
VNEG_F64(v1, v1);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
if(ST_IS_F(0)) {
|
||||
VNEG_F32(v1, v1);
|
||||
} else {
|
||||
VNEG_F64(v1, v1);
|
||||
}
|
||||
break;
|
||||
case 0xE1:
|
||||
INST_NAME("FABS");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
VABS_F64(v1, v1);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
if(ST_IS_F(0)) {
|
||||
VABS_F32(v1, v1);
|
||||
} else {
|
||||
VABS_F64(v1, v1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xE4:
|
||||
INST_NAME("FTST");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
VCMP_F64_0(v1);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
if(ST_IS_F(0)) {
|
||||
VCMP_F32_0(v1);
|
||||
} else {
|
||||
VCMP_F64_0(v1);
|
||||
}
|
||||
FCOM(x1, x2); // same flags...
|
||||
break;
|
||||
case 0xE5:
|
||||
INST_NAME("FXAM");
|
||||
#if 1
|
||||
i1 = x87_get_current_cache(dyn, ninst, 0, NEON_CACHE_ST_D);
|
||||
// value put in x14
|
||||
if(i1==-1) {
|
||||
// not in cache, so check Empty status and load it
|
||||
// x14 will be the actual top
|
||||
LDR_IMM9(x14, xEmu, offsetof(x86emu_t, top));
|
||||
i2 = -dyn->x87stack;
|
||||
if(i2) {
|
||||
if(i2<0) {
|
||||
SUB_IMM8(x14, x14, -i2);
|
||||
} else {
|
||||
ADD_IMM8(x14, x14, i2);
|
||||
}
|
||||
AND_IMM8(x14, x14, 7); // (emu->top + i)&7
|
||||
}
|
||||
ADD_REG_LSL_IMM5(x1, xEmu, x14, 3);
|
||||
LDRD_IMM8(x2, x1, offsetof(x86emu_t, x87)); // load r2/r3 with ST0 anyway, for sign extraction
|
||||
ADD_REG_LSL_IMM5(x1, xEmu, x14, 2);
|
||||
LDR_IMM9(x1, x1, offsetof(x86emu_t, p_regs));
|
||||
CMPS_IMM8(x1, 0b11);
|
||||
MOVW_COND(cEQ, x14, 0b100000100000000); // empty: C3,C2,C0 = 101
|
||||
B_MARK3(cEQ);
|
||||
} else {
|
||||
// simply move from cache reg to r2/r3
|
||||
v1 = dyn->x87reg[i1];
|
||||
VMOVfrV_D(x2, x3, v1);
|
||||
}
|
||||
// get exponant in r1
|
||||
MOV_REG_LSR_IMM5(x1, x3, 20);
|
||||
MOVW(x14, 0x7ff);
|
||||
ANDS_REG_LSL_IMM5(x1, x1, x14, 0);
|
||||
B_MARK(cNE); // not zero or denormal
|
||||
BIC_IMM8_ROR(x1, x3, 0b10, 1); // remove sign bit
|
||||
ORRS_REG_LSL_IMM5(x1, x1, x2, 0);
|
||||
MOVW_COND(cEQ, x14, 0b100000000000000); // Zero: C3,C2,C0 = 100
|
||||
MOVW_COND(cNE, x14, 0b100010000000000); // Denormal: C3,C2,C0 = 110
|
||||
B_MARK3(c__);
|
||||
MARK;
|
||||
CMPS_REG_LSL_IMM5(x1, x14, 0); // infinite/NaN?
|
||||
MOVW_COND(cNE, x14, 0b000010000000000); // normal: C3,C2,C0 = 010
|
||||
B_MARK3(cNE);
|
||||
ORR_IMM8(x1, x1, 0x08, 12); //prepare mask, 0x7ff | 0x800 => 0xfff
|
||||
BIC_REG_LSL_IMM5(x1, x3, x1, 20);
|
||||
ORRS_REG_LSL_IMM5(x1, x1, x2, 0);
|
||||
MOVW_COND(cEQ, x14, 0b000010100000000); // infinity: C3,C2,C0 = 011
|
||||
MOVW_COND(cNE, x14, 0b000000100000000); // NaN: C3,C2,C0 = 001
|
||||
MARK3;
|
||||
// Extract signa & Update SW
|
||||
MOV_REG_LSR_IMM5(x1, x3, 31);
|
||||
BFI(x14, x1, 9, 1); //C1
|
||||
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
BIC_IMM8(x1, x1, 0b01000111, 12);
|
||||
ORR_REG_LSL_IMM5(x14, x14, x1, 0);
|
||||
STRH_IMM8(x14, xEmu, offsetof(x86emu_t, sw));
|
||||
#else
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_refresh(dyn, ninst, x1, x2, 0);
|
||||
CALL(fpu_fxam, -1, 0); // should be possible inline, but is it worth it?
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 0xE8:
|
||||
INST_NAME("FLD1");
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
MOV32(x2, (&d_1));
|
||||
VLDR_64(v1, x2, 0);
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0)) {
|
||||
VMOV_i_32(v1, 0b01110000);
|
||||
} else {
|
||||
VMOV_i_64(v1, 0b01110000);
|
||||
}
|
||||
break;
|
||||
case 0xE9:
|
||||
INST_NAME("FLDL2T");
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
MOV32(x2, (&d_l2t));
|
||||
VLDR_64(v1, x2, 0);
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0)) {
|
||||
MOV32(x2, (&f_l2t));
|
||||
VLDR_32(v1, x2, 0);
|
||||
} else {
|
||||
MOV32(x2, (&d_l2t));
|
||||
VLDR_64(v1, x2, 0);
|
||||
}
|
||||
break;
|
||||
case 0xEA:
|
||||
INST_NAME("FLDL2E");
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
MOV32(x2, (&d_l2e));
|
||||
VLDR_64(v1, x2, 0);
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0)) {
|
||||
MOV32(x2, (&f_l2e));
|
||||
VLDR_32(v1, x2, 0);
|
||||
} else {
|
||||
MOV32(x2, (&d_l2e));
|
||||
VLDR_64(v1, x2, 0);
|
||||
}
|
||||
break;
|
||||
case 0xEB:
|
||||
INST_NAME("FLDPI");
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
MOV32(x2, (&d_pi));
|
||||
VLDR_64(v1, x2, 0);
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0)) {
|
||||
MOV32(x2, (&f_pi));
|
||||
VLDR_32(v1, x2, 0);
|
||||
} else {
|
||||
MOV32(x2, (&d_pi));
|
||||
VLDR_64(v1, x2, 0);
|
||||
}
|
||||
break;
|
||||
case 0xEC:
|
||||
INST_NAME("FLDLG2");
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
MOV32(x2, (&d_lg2));
|
||||
VLDR_64(v1, x2, 0);
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0)) {
|
||||
MOV32(x2, (&f_lg2));
|
||||
VLDR_32(v1, x2, 0);
|
||||
} else {
|
||||
MOV32(x2, (&d_lg2));
|
||||
VLDR_64(v1, x2, 0);
|
||||
}
|
||||
break;
|
||||
case 0xED:
|
||||
INST_NAME("FLDLN2");
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
MOV32(x2, (&d_ln2));
|
||||
VLDR_64(v1, x2, 0);
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0)) {
|
||||
MOV32(x2, (&f_ln2));
|
||||
VLDR_32(v1, x2, 0);
|
||||
} else {
|
||||
MOV32(x2, (&d_ln2));
|
||||
VLDR_64(v1, x2, 0);
|
||||
}
|
||||
break;
|
||||
case 0xEE:
|
||||
INST_NAME("FLDZ");
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
MOV32(x2, (&d_0));
|
||||
VLDR_64(v1, x2, 0);
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0)) {
|
||||
VMOV_8(v1/2, 0); // float is *2...
|
||||
} else {
|
||||
VMOV_8(v1, 0); // cannot use VMOV_i_F64
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xFA:
|
||||
INST_NAME("FSQRT");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
VSQRT_F64(v1, v1);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_ST0);
|
||||
if(ST_IS_F(0)) {
|
||||
VSQRT_F32(v1, v1);
|
||||
} else {
|
||||
VSQRT_F64(v1, v1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xFC:
|
||||
INST_NAME("FRNDINT");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
// use C helper for now, nothing staightforward is available
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
CALL(arm_frndint, -1, 0);
|
||||
@@ -173,71 +295,142 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 0xF0:
|
||||
INST_NAME("F2XM1");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
CALL(arm_f2xm1, -1, 0);
|
||||
break;
|
||||
case 0xF1:
|
||||
INST_NAME("FYL2X");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fyl2x, -1, 0);
|
||||
x87_do_pop(dyn, ninst);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 1, NEON_CACHE_ST_D);
|
||||
VMOV_64(0, v1); // prepare call to log2
|
||||
CALL_1D(log2, 0);
|
||||
VMUL_F64(v2, v2, 0); //ST(1).d = log2(ST0.d)*ST(1).d
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xF2:
|
||||
INST_NAME("FTAN");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
CALL(arm_ftan, -1, 0);
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
MOV32(x2, (&d_1));
|
||||
VLDR_64(v1, x2, 0);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
VMOV_64(0, v1); // prepare call to tan
|
||||
CALL_1D(tan, 0);
|
||||
VMOV_64(v1, 0);
|
||||
//emu->sw.f.F87_C2 = 0;
|
||||
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
BFC(x1, 10, 1); //C2 = 0
|
||||
STRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
v2 = x87_do_push(dyn, ninst, x3, NEON_CACHE_ST_D);
|
||||
// so here: F64: Imm8 = abcd efgh that gives => aBbbbbbb bbcdefgh 0000000 00000000 00000000...
|
||||
// and want 1.0 = 0x3ff0000000000000
|
||||
// so 00111111 11110000 00000000 00000000....
|
||||
// a = 0, b = 1, c = 1, d = 1, efgh=0
|
||||
// 0b01110000
|
||||
VMOV_i_64(v2, 0b01110000);
|
||||
break;
|
||||
case 0xF3:
|
||||
INST_NAME("FPATAN");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fpatan, -1, 0);
|
||||
x87_do_pop(dyn, ninst);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 1, NEON_CACHE_ST_D);
|
||||
VMOV_64(0, v2); // prepare call to atan2
|
||||
VMOV_64(1, v1);
|
||||
CALL_2D(atan2, 0);
|
||||
VMOV_64(v2, 0); //ST(1).d = atan2(ST1.d, ST0.d);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xF4:
|
||||
INST_NAME("FXTRACT");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_do_push_empty(dyn, ninst, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fxtract, -1, 0);
|
||||
break;
|
||||
case 0xF5:
|
||||
INST_NAME("FPREM1");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fprem1, -1, 0);
|
||||
break;
|
||||
case 0xF6:
|
||||
INST_NAME("FDECSTP");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
LDR_IMM9(x2, xEmu, offsetof(x86emu_t, top));
|
||||
SUB_IMM8(x2, x2, 1);
|
||||
AND_IMM8(x2, x2, 7);
|
||||
STR_IMM9(x2, xEmu, offsetof(x86emu_t, top));
|
||||
break;
|
||||
case 0xF7:
|
||||
INST_NAME("FINCSTP");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
LDR_IMM9(x2, xEmu, offsetof(x86emu_t, top));
|
||||
ADD_IMM8(x2, x2, 1);
|
||||
AND_IMM8(x2, x2, 7);
|
||||
STR_IMM9(x2, xEmu, offsetof(x86emu_t, top));
|
||||
break;
|
||||
case 0xF8:
|
||||
INST_NAME("FPREM");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fprem, -1, 0);
|
||||
break;
|
||||
case 0xF9:
|
||||
INST_NAME("FYL2XP1");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fyl2xp1, -1, 0);
|
||||
x87_do_pop(dyn, ninst);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 1, NEON_CACHE_ST_D);
|
||||
VMOV_i_64(0, 0b01110000); // D0 = 1.0
|
||||
VADD_F64(0, 0, v1); // prepare call to log2
|
||||
CALL_1D(log2, 0);
|
||||
VMUL_F64(v2, v2, 0); //ST(1).d = log2(ST0.d + 1.0)*ST(1).d;
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xFB:
|
||||
INST_NAME("FSINCOS");
|
||||
x87_do_push_empty(dyn, ninst, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fsincos, -1, 0);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = x87_do_push(dyn, ninst, x3, NEON_CACHE_ST_D);
|
||||
VMOV_64(0, v1);
|
||||
CALL_1D(sin, 0);
|
||||
VSWP(v1, 0);
|
||||
CALL_1D(cos, 0);
|
||||
VMOV_64(v2, 0);
|
||||
//emu->sw.f.F87_C2 = 0;
|
||||
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
BFC(x1, 10, 1); //C2 = 0
|
||||
STRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
break;
|
||||
case 0xFD:
|
||||
INST_NAME("FSCALE");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
x87_forget(dyn, ninst, x1, x2, 1);
|
||||
CALL(arm_fscale, -1, 0);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 1, NEON_CACHE_ST_D);
|
||||
//if(ST0.d!=0.0)
|
||||
// ST0.d *= exp2(trunc(ST1.d));
|
||||
VCMP_F64_0(v1);
|
||||
VMRS_APSR();
|
||||
B_NEXT(cEQ);
|
||||
VMOV_64(0, v2);
|
||||
CALL_1DD(trunc, exp2, 0);
|
||||
VMUL_F64(v1, v1, 0);
|
||||
break;
|
||||
case 0xFE:
|
||||
INST_NAME("FSIN");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
CALL(arm_fsin, -1, 0);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
VMOV_64(0, v1); // prepare call to sin
|
||||
CALL_1D(sin, 0);
|
||||
VMOV_64(v1, 0);
|
||||
//emu->sw.f.F87_C2 = 0;
|
||||
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
BFC(x1, 10, 1); //C2 = 0
|
||||
STRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
break;
|
||||
case 0xFF:
|
||||
INST_NAME("FCOS");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
CALL(arm_fcos, -1, 0);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
VMOV_64(0, v1); // prepare call to cos
|
||||
CALL_1D(cos, 0);
|
||||
VMOV_64(v1, 0);
|
||||
//emu->sw.f.F87_C2 = 0;
|
||||
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
BFC(x1, 10, 1); //C2 = 0
|
||||
STRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
break;
|
||||
|
||||
|
||||
@@ -259,10 +452,6 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
case 0xEF:
|
||||
case 0xF5:
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
*ok = 0;
|
||||
DEFAULT;
|
||||
break;
|
||||
|
||||
@@ -270,37 +459,73 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FLD ST0, float[ED]");
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
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);
|
||||
VCVT_F64_F32(v1, s0);
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0))
|
||||
s0 = v1;
|
||||
else
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0);
|
||||
LDR_IMM9(x2, ed, fixedaddress);
|
||||
VMOVtoV(s0, x2);
|
||||
}
|
||||
if(!ST_IS_F(0)) {
|
||||
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);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0))
|
||||
s0 = v1;
|
||||
else {
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
VCVT_F32_F64(s0, v1);
|
||||
}
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0);
|
||||
VSTR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 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);
|
||||
x87_do_pop(dyn, ninst);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_F);
|
||||
if(ST_IS_F(0))
|
||||
s0 = v1;
|
||||
else {
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
VCVT_F32_F64(s0, v1);
|
||||
}
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 2);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x2, &fixedaddress, 1023, 0, 0);
|
||||
VSTR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0);
|
||||
VMOVfrV(x2, s0);
|
||||
STR_IMM9(x2, ed, fixedaddress);
|
||||
}
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FLDENV Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3); // maybe only x87, not SSE?
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
if(ed!=x1) {
|
||||
MOV_REG(x1, ed);
|
||||
}
|
||||
MOVW(x2, 0);
|
||||
CALL(fpu_loadenv, -1, 0);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FLDCW Ew");
|
||||
@@ -309,16 +534,26 @@ uintptr_t dynarecD9(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
UBFX(x1, x1, 10, 2); // extract round
|
||||
STR_IMM9(x1, xEmu, offsetof(x86emu_t, round));
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FNSTENV Ed");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3); // maybe only x87, not SSE?
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
if(ed!=x1) {
|
||||
MOV_REG(x1, ed);
|
||||
}
|
||||
MOVW(x2, 0);
|
||||
CALL(fpu_savenv, -1, 0);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FNSTCW Ew");
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0);
|
||||
ed = x1;
|
||||
wb1 = 1;
|
||||
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, cw));
|
||||
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;
|
||||
int32_t j32;
|
||||
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(j32);
|
||||
|
||||
switch(nextop) {
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
@@ -47,12 +51,15 @@ 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);
|
||||
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);
|
||||
VMOVcond_64(cNE, v1, v2); // F_CF==1
|
||||
READFLAGS(X_CF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
TSTS_IMM8(xFlags, 1<<F_CF);
|
||||
if(ST_IS_F(0)) {
|
||||
VMOVcond_32(cNE, v1, v2); // F_CF==1
|
||||
} else {
|
||||
VMOVcond_64(cNE, v1, v2); // F_CF==1
|
||||
}
|
||||
break;
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
@@ -63,12 +70,15 @@ 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);
|
||||
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);
|
||||
VMOVcond_64(cNE, v1, v2); // F_ZF==1
|
||||
READFLAGS(X_ZF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
TSTS_IMM8(xFlags, 1<<F_ZF);
|
||||
if(ST_IS_F(0)) {
|
||||
VMOVcond_32(cNE, v1, v2); // F_ZF==1
|
||||
} else {
|
||||
VMOVcond_64(cNE, v1, v2); // F_ZF==1
|
||||
}
|
||||
break;
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
@@ -79,13 +89,15 @@ 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);
|
||||
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);
|
||||
VMOVcond_64(cNE, v1, v2); // F_CF==1 | F_ZF==1
|
||||
READFLAGS(X_CF|X_ZF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
TSTS_IMM8(xFlags, (1<<F_CF)|(1<<F_ZF));
|
||||
if(ST_IS_F(0)) {
|
||||
VMOVcond_32(cNE, v1, v2); // F_CF==1 | F_ZF==1
|
||||
} else {
|
||||
VMOVcond_64(cNE, v1, v2); // F_CF==1 | F_ZF==1
|
||||
}
|
||||
break;
|
||||
case 0xD8:
|
||||
case 0xD9:
|
||||
@@ -96,21 +108,28 @@ 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);
|
||||
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);
|
||||
VMOVcond_64(cNE, v1, v2); // F_PF==1
|
||||
READFLAGS(X_PF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
TSTS_IMM8(xFlags, 1<<F_PF);
|
||||
if(ST_IS_F(0)) {
|
||||
VMOVcond_32(cNE, v1, v2); // F_PF==1
|
||||
} else {
|
||||
VMOVcond_64(cNE, v1, v2); // F_PF==1
|
||||
}
|
||||
break;
|
||||
case 0xE9:
|
||||
INST_NAME("FUCOMPP ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VCMP_F64(v1, v2);
|
||||
INST_NAME("FUCOMPP ST0, ST1");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 1, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
VCMP_F32(v1, v2);
|
||||
} else {
|
||||
VCMP_F64(v1, v2);
|
||||
}
|
||||
FCOM(x1, x2);
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
case 0xE4:
|
||||
@@ -123,7 +142,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;
|
||||
|
||||
@@ -131,7 +149,7 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FIADD ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
GETED;
|
||||
d0 = fpu_get_scratch_double(dyn);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
@@ -141,7 +159,7 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FIMUL ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
GETED;
|
||||
d0 = fpu_get_scratch_double(dyn);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
@@ -151,7 +169,7 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FICOM ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
GETED;
|
||||
d0 = fpu_get_scratch_double(dyn);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
@@ -162,7 +180,7 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FICOMP ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
GETED;
|
||||
d0 = fpu_get_scratch_double(dyn);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
@@ -170,11 +188,11 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
VCVT_F64_S32(d0, s0);
|
||||
VCMP_F64(v1, d0);
|
||||
FCOM(x1, x2);
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FISUB ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
GETED;
|
||||
d0 = fpu_get_scratch_double(dyn);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
@@ -184,7 +202,7 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FISUBR ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
GETED;
|
||||
d0 = fpu_get_scratch_double(dyn);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
@@ -194,7 +212,7 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FIDIV ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
GETED;
|
||||
d0 = fpu_get_scratch_double(dyn);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
@@ -204,7 +222,7 @@ uintptr_t dynarecDA(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FIDIVR ST0, Ed");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
GETED;
|
||||
d0 = fpu_get_scratch_double(dyn);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
|
||||
+115
-74
@@ -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;
|
||||
int32_t j32;
|
||||
uint8_t ed;
|
||||
uint8_t wback;
|
||||
int v1, v2;
|
||||
int s0;
|
||||
int fixedaddress;
|
||||
int parity;
|
||||
|
||||
MAYUSE(s0);
|
||||
MAYUSE(v1);
|
||||
MAYUSE(v2);
|
||||
MAYUSE(j32);
|
||||
|
||||
switch(nextop) {
|
||||
case 0xC0:
|
||||
@@ -49,12 +49,15 @@ 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);
|
||||
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);
|
||||
VMOVcond_64(cEQ, v1, v2); // F_CF==0
|
||||
READFLAGS(X_CF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
TSTS_IMM8(xFlags, 1<<F_CF);
|
||||
if(ST_IS_F(0)) {
|
||||
VMOVcond_32(cEQ, v1, v2); // F_CF==0
|
||||
} else {
|
||||
VMOVcond_64(cEQ, v1, v2); // F_CF==0
|
||||
}
|
||||
break;
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
@@ -65,12 +68,15 @@ 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);
|
||||
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);
|
||||
VMOVcond_64(cEQ, v1, v2); // F_ZF==0
|
||||
READFLAGS(X_ZF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
TSTS_IMM8(xFlags, 1<<F_ZF);
|
||||
if(ST_IS_F(0)) {
|
||||
VMOVcond_32(cEQ, v1, v2); // F_ZF==0
|
||||
} else {
|
||||
VMOVcond_64(cEQ, v1, v2); // F_ZF==0
|
||||
}
|
||||
break;
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
@@ -81,13 +87,15 @@ 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);
|
||||
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);
|
||||
VMOVcond_64(cEQ, v1, v2); // F_CF==0 | F_ZF==0
|
||||
READFLAGS(X_CF|X_ZF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
TSTS_IMM8(xFlags, (1<<F_CF)|(1<<F_ZF));
|
||||
if(ST_IS_F(0)) {
|
||||
VMOVcond_32(cEQ, v1, v2); // F_CF==0 & F_ZF==0
|
||||
} else {
|
||||
VMOVcond_64(cEQ, v1, v2); // F_CF==0 & F_ZF==0
|
||||
}
|
||||
break;
|
||||
case 0xD8:
|
||||
case 0xD9:
|
||||
@@ -98,24 +106,31 @@ 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);
|
||||
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);
|
||||
VMOVcond_64(cEQ, v1, v2); // F_PF==0
|
||||
READFLAGS(X_PF);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
TSTS_IMM8(xFlags, 1<<F_PF);
|
||||
if(ST_IS_F(0)) {
|
||||
VMOVcond_32(cEQ, v1, v2); // F_PF==0
|
||||
} else {
|
||||
VMOVcond_64(cEQ, v1, v2); // F_PF==0
|
||||
}
|
||||
break;
|
||||
case 0xE1:
|
||||
INST_NAME("FDISI8087_NOP"); // so.. NOP?
|
||||
break;
|
||||
case 0xE2:
|
||||
INST_NAME("FNCLEX");
|
||||
MOVW(x1, 0);
|
||||
LDRH_IMM8(x2, xEmu, offsetof(x86emu_t, sw));
|
||||
MOVW(x1, 0);
|
||||
BFI(x2, x1, 0, 8); // IE .. PE, SF, ES
|
||||
BFI(x2, x1, 15, 1); // B
|
||||
STRH_IMM8(x2, xEmu, offsetof(x86emu_t, sw));
|
||||
break;
|
||||
case 0xE3:
|
||||
INST_NAME("FNINIT");
|
||||
fpu_purgecache(dyn, ninst, x1, x2, x3); // maybe only x87, not SSE?
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3); // maybe only x87, not SSE?
|
||||
CALL(reset_fpu, -1, 0);
|
||||
break;
|
||||
case 0xE8:
|
||||
@@ -127,12 +142,15 @@ 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);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VCMP_F64(v1, v2);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
VCMP_F32(v1, v2);
|
||||
} else {
|
||||
VCMP_F64(v1, v2);
|
||||
}
|
||||
FCOMI(x1, x2);
|
||||
UFLAGS(1);
|
||||
break;
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
@@ -143,21 +161,22 @@ 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);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VCMP_F64(v1, v2);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
VCMP_F32(v1, v2);
|
||||
} else {
|
||||
VCMP_F64(v1, v2);
|
||||
}
|
||||
FCOMI(x1, x2);
|
||||
UFLAGS(1);
|
||||
break;
|
||||
|
||||
case 0xE0:
|
||||
case 0xE1:
|
||||
case 0xE4:
|
||||
case 0xE5:
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
*ok = 0;
|
||||
DEFAULT;
|
||||
break;
|
||||
|
||||
@@ -165,26 +184,32 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FILD ST0, Ed");
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
GETED;
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
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, 0);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
GETED;
|
||||
VMOVtoV(s0, ed);
|
||||
}
|
||||
VCVT_F64_S32(v1, s0);
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FISTTP Ed, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xEAX+(nextop&7);
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 4095, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 4095, 0, 0);
|
||||
ed = x1;
|
||||
}
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
MSR_nzcvq_0();
|
||||
VMRS(x12); // Get FPCSR reg to clear exceptions flags
|
||||
ORR_IMM8(x3, x12, 0b001, 6); // enable exceptions
|
||||
VMRS(x14); // Get FPCSR reg to clear exceptions flags
|
||||
ORR_IMM8(x3, x14, 0b001, 6); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
VCVT_S32_F64(s0, v1);
|
||||
@@ -193,18 +218,18 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
MOV_IMM_COND(cNE, ed, 0b10, 1); // 0x80000000
|
||||
WBACK;
|
||||
VMSR(x12); // put back values
|
||||
x87_do_pop(dyn, ninst);
|
||||
VMSR(x14); // put back values
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FIST Ed, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x12); // x1 have the modified RPSCR reg
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14); // x1 have the modified RPSCR reg
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xEAX+(nextop&7);
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 4095, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 4095, 0, 0);
|
||||
ed = x1;
|
||||
}
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
@@ -223,13 +248,13 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FISTP Ed, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x12); // x1 have the modified RPSCR reg
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14); // x1 have the modified RPSCR reg
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
ed = xEAX+(nextop&7);
|
||||
wback = 0;
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 4095, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 4095, 0, 0);
|
||||
ed = x1;
|
||||
}
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
@@ -244,30 +269,46 @@ uintptr_t dynarecDB(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
MOV_IMM_COND(cNE, ed, 0b10, 1); // 0x80000000
|
||||
WBACK;
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 5:
|
||||
INST_NAME("FLD tbyte");
|
||||
x87_do_push_empty(dyn, ninst, x1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
|
||||
if(ed!=x1) {
|
||||
MOV_REG(x1, ed);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
if(PK(0)==0xDB && ((PK(1)>>3)&7)==7) {
|
||||
// the FLD is immediatly followed by an FSTP
|
||||
LDR_IMM9(x2, ed, 0);
|
||||
LDR_IMM9(x3, ed, 4);
|
||||
LDRH_IMM8(x14, ed, 8);
|
||||
// no persistant scratch register, so unrool both instruction here...
|
||||
MESSAGE(LOG_DUMP, "\tHack: FSTP tbyte\n");
|
||||
nextop = F8; //0xDB
|
||||
nextop = F8; //modrm
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
STR_IMM9(x2, ed, 0);
|
||||
STR_IMM9(x3, ed, 4);
|
||||
STRH_IMM8(x14, ed, 8);
|
||||
} else {
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
if(ed!=x1) {
|
||||
MOV_REG(x1, ed);
|
||||
}
|
||||
x87_do_push_empty(dyn, ninst, x3);
|
||||
CALL(arm_fld, -1, 0);
|
||||
}
|
||||
CALL(arm_fld, -1, 0);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FSTP tbyte");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x3, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
if(ed!=x1) {
|
||||
MOV_REG(x1, ed);
|
||||
}
|
||||
CALL(arm_fstp, -1, 0);
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
default:
|
||||
*ok = 0;
|
||||
DEFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
+155
-60
@@ -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:
|
||||
@@ -47,9 +46,13 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
INST_NAME("FADD STx, ST0");
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VADD_F64(v1, v1, v2);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
VADD_F32(v1, v1, v2);
|
||||
} else {
|
||||
VADD_F64(v1, v1, v2);
|
||||
}
|
||||
break;
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
@@ -60,9 +63,13 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xCE:
|
||||
case 0xCF:
|
||||
INST_NAME("FMUL STx, ST0");
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VMUL_F64(v1, v1, v2);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
VMUL_F32(v1, v1, v2);
|
||||
} else {
|
||||
VMUL_F64(v1, v1, v2);
|
||||
}
|
||||
break;
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
@@ -73,9 +80,13 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
INST_NAME("FCOM ST0, STx"); //yep
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VCMP_F64(v1, v2);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
VCMP_F32(v1, v2);
|
||||
} else {
|
||||
VCMP_F64(v1, v2);
|
||||
}
|
||||
FCOM(x1, x2);
|
||||
break;
|
||||
case 0xD8:
|
||||
@@ -87,11 +98,15 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xDE:
|
||||
case 0xDF:
|
||||
INST_NAME("FCOMP ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VCMP_F64(v1, v2);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
VCMP_F32(v1, v2);
|
||||
} else {
|
||||
VCMP_F64(v1, v2);
|
||||
}
|
||||
FCOM(x1, x2);
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xE0:
|
||||
case 0xE1:
|
||||
@@ -102,9 +117,13 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
INST_NAME("FSUBR STx, ST0");
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VSUB_F64(v1, v2, v1);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
VSUB_F32(v1, v2, v1);
|
||||
} else {
|
||||
VSUB_F64(v1, v2, v1);
|
||||
}
|
||||
break;
|
||||
case 0xE8:
|
||||
case 0xE9:
|
||||
@@ -115,9 +134,13 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xEE:
|
||||
case 0xEF:
|
||||
INST_NAME("FSUB STx, ST0");
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VSUB_F64(v1, v1, v2);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
VSUB_F32(v1, v1, v2);
|
||||
} else {
|
||||
VSUB_F64(v1, v1, v2);
|
||||
}
|
||||
break;
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
@@ -128,9 +151,13 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
INST_NAME("FDIVR STx, ST0");
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VDIV_F64(v1, v2, v1);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
VDIV_F32(v1, v2, v1);
|
||||
} else {
|
||||
VDIV_F64(v1, v2, v1);
|
||||
}
|
||||
break;
|
||||
case 0xF8:
|
||||
case 0xF9:
|
||||
@@ -141,77 +168,145 @@ uintptr_t dynarecDC(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xFE:
|
||||
case 0xFF:
|
||||
INST_NAME("FDIV STx, ST0");
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VDIV_F64(v1, v1, v2);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
VDIV_F32(v1, v1, v2);
|
||||
} else {
|
||||
VDIV_F64(v1, v1, v2);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FADD ST0, double[ED]");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 1023, 3);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
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, 0);
|
||||
VLDR_64(d1, wback, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0, 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);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
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, 0);
|
||||
VLDR_64(d1, wback, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0, 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);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
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, 0);
|
||||
VLDR_64(d1, wback, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0, 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);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
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, 0);
|
||||
VLDR_64(d1, wback, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0, 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);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
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);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
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, 0);
|
||||
VLDR_64(d1, wback, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0, 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);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
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, 0);
|
||||
VLDR_64(d1, wback, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0, 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);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
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, 0);
|
||||
VLDR_64(d1, wback, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0, 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);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
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, 0);
|
||||
VLDR_64(d1, wback, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 4095-4, 0, 0);
|
||||
LDR_IMM9(x2, wback, fixedaddress);
|
||||
LDR_IMM9(x3, wback, fixedaddress+4);
|
||||
VMOVtoV_D(d1, x2, x3);
|
||||
}
|
||||
VDIV_F64(v1, d1, v1);
|
||||
break;
|
||||
}
|
||||
|
||||
+115
-46
@@ -27,15 +27,14 @@
|
||||
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;
|
||||
int i1, i2, i3;
|
||||
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
|
||||
switch(nextop) {
|
||||
case 0xC0:
|
||||
@@ -47,7 +46,10 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
INST_NAME("FFREE STx");
|
||||
break; // not handling Tag...
|
||||
x87_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
MOVW(x1, nextop&7);
|
||||
CALL(fpu_do_free, -1, 0);
|
||||
break;
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
case 0xD2:
|
||||
@@ -57,13 +59,17 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
INST_NAME("FST ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VMOV_64(v2, v1);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
VMOV_32(v2, v1);
|
||||
} else {
|
||||
VMOV_64(v2, v1);
|
||||
}
|
||||
break;
|
||||
case 0xD8:
|
||||
INST_NAME("FSTP ST0, ST0");
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xD9:
|
||||
case 0xDA:
|
||||
@@ -73,10 +79,19 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xDE:
|
||||
case 0xDF:
|
||||
INST_NAME("FSTP ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VMOV_64(v2, v1);
|
||||
x87_do_pop(dyn, ninst);
|
||||
// copy the cache value for st0 to stx
|
||||
i1 = x87_get_cache(dyn, ninst, 0, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
i2 = x87_get_cache(dyn, ninst, 1, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
i3 = dyn->x87cache[i1];
|
||||
dyn->x87cache[i1] = dyn->x87cache[i2];
|
||||
dyn->x87cache[i2] = i3;
|
||||
// swap those too
|
||||
i1 = x87_get_neoncache(dyn, ninst, x1, x2, nextop&7);
|
||||
i2 = x87_get_neoncache(dyn, ninst, x1, x2, 0);
|
||||
i3 = dyn->n.neoncache[i1].v;
|
||||
dyn->n.neoncache[i1].v = dyn->n.neoncache[i2].v;
|
||||
dyn->n.neoncache[i2].v = i3;
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
case 0xE0:
|
||||
@@ -88,9 +103,13 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
INST_NAME("FUCOM ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VCMP_F64(v1, v2);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
VCMP_F32(v1, v2);
|
||||
} else {
|
||||
VCMP_F64(v1, v2);
|
||||
}
|
||||
FCOM(x1, x2);
|
||||
break;
|
||||
case 0xE8:
|
||||
@@ -102,11 +121,15 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xEE:
|
||||
case 0xEF:
|
||||
INST_NAME("FUCOMP ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VCMP_F64(v1, v2);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
VCMP_F32(v1, v2);
|
||||
} else {
|
||||
VCMP_F64(v1, v2);
|
||||
}
|
||||
FCOM(x1, x2);
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
case 0xC8:
|
||||
@@ -133,7 +156,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;
|
||||
|
||||
@@ -141,40 +163,87 @@ uintptr_t dynarecDD(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FLD double");
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
#if 0
|
||||
// can bus error...
|
||||
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);
|
||||
#endif
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 3);
|
||||
if (parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0);
|
||||
VLDR_64(v1, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0);
|
||||
LDR_IMM9(x2, ed, fixedaddress);
|
||||
LDR_IMM9(x3, ed, fixedaddress + 4);
|
||||
VMOVtoV_D(v1, x2, x3);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FISTTP i64, ST0");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
if(ed!=x1) {MOV_REG(x1, ed);}
|
||||
CALL(arm_fistp64, -1, 0);
|
||||
x87_do_pop(dyn, ninst);
|
||||
CALL(arm_fistt64, -1, 0);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
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?
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 3);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0);
|
||||
VSTR_64(v1, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 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?
|
||||
x87_do_pop(dyn, ninst);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_D);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 3);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0);
|
||||
VSTR_64(v1, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0);
|
||||
VMOVfrV_D(x2, x3, v1);
|
||||
STR_IMM9(x2, ed, fixedaddress);
|
||||
STR_IMM9(x3, ed, fixedaddress+4);
|
||||
}
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FRSTOR m108byte");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
if(ed!=x1) {MOV_REG(x1, ed);}
|
||||
CALL(arm_frstor, -1, 0);
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FSAVE m108byte");
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
if(ed!=x1) {MOV_REG(x1, ed);}
|
||||
CALL(arm_fsave, -1, 0);
|
||||
break;
|
||||
case 7:
|
||||
INST_NAME("FNSTSW m2byte");
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x14, &fixedaddress, 0, 0, 0);
|
||||
LDR_IMM9(x2, xEmu, offsetof(x86emu_t, top));
|
||||
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
if(dyn->x87stack) {
|
||||
// update top
|
||||
if(dyn->x87stack>0) {
|
||||
SUB_IMM8(x2, x2, dyn->x87stack);
|
||||
} else {
|
||||
ADD_IMM8(x2, x2, -dyn->x87stack);
|
||||
}
|
||||
AND_IMM8(x2, x2, 7);
|
||||
}
|
||||
BFI(x1, x2, 11, 3); // inject top
|
||||
STRH_IMM8(x1, ed, 0); // store whole sw flags
|
||||
break;
|
||||
default:
|
||||
*ok = 0;
|
||||
DEFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "x86trace.h"
|
||||
#include "dynarec_arm.h"
|
||||
#include "dynarec_arm_private.h"
|
||||
#include "dynarec_arm_functions.h"
|
||||
#include "arm_printer.h"
|
||||
|
||||
#include "dynarec_arm_helper.h"
|
||||
@@ -25,16 +26,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:
|
||||
@@ -46,10 +41,14 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
INST_NAME("FADDP STx, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VADD_F64(v2, v2, v1);
|
||||
x87_do_pop(dyn, ninst);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
VADD_F32(v2, v2, v1);
|
||||
} else {
|
||||
VADD_F64(v2, v2, v1);
|
||||
}
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
@@ -60,19 +59,47 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xCE:
|
||||
case 0xCF:
|
||||
INST_NAME("FMULP STx, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VMUL_F64(v2, v2, v1);
|
||||
x87_do_pop(dyn, ninst);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
VMUL_F32(v2, v2, v1);
|
||||
} else {
|
||||
VMUL_F64(v2, v2, v1);
|
||||
}
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xD9: /* FCOMPP */
|
||||
INST_NAME("FCOMPP ST0, ST1");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 1);
|
||||
VCMP_F64(v1, v2);
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
case 0xD2:
|
||||
case 0xD3:
|
||||
case 0xD4:
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
INST_NAME("FCOMP ST0, STx");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
VCMP_F32(v1, v2);
|
||||
} else {
|
||||
VCMP_F64(v1, v2);
|
||||
}
|
||||
FCOM(x1, x2);
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
case 0xD9:
|
||||
INST_NAME("FCOMPP ST0, ST1");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, 1));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, 1, X87_COMBINE(0, 1));
|
||||
if(ST_IS_F(0)) {
|
||||
VCMP_F32(v1, v2);
|
||||
} else {
|
||||
VCMP_F64(v1, v2);
|
||||
}
|
||||
FCOM(x1, x2);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xE0:
|
||||
case 0xE1:
|
||||
@@ -83,10 +110,14 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
INST_NAME("FSUBRP STx, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VSUB_F64(v2, v1, v2);
|
||||
x87_do_pop(dyn, ninst);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
VSUB_F32(v2, v1, v2);
|
||||
} else {
|
||||
VSUB_F64(v2, v1, v2);
|
||||
}
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xE8:
|
||||
case 0xE9:
|
||||
@@ -97,10 +128,14 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xEE:
|
||||
case 0xEF:
|
||||
INST_NAME("FSUBP STx, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VSUB_F64(v2, v2, v1);
|
||||
x87_do_pop(dyn, ninst);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
VSUB_F32(v2, v2, v1);
|
||||
} else {
|
||||
VSUB_F64(v2, v2, v1);
|
||||
}
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
@@ -111,10 +146,14 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
INST_NAME("FDIVRP STx, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VDIV_F64(v2, v1, v2);
|
||||
x87_do_pop(dyn, ninst);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
VDIV_F32(v2, v1, v2);
|
||||
} else {
|
||||
VDIV_F64(v2, v1, v2);
|
||||
}
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xF8:
|
||||
case 0xF9:
|
||||
@@ -125,20 +164,16 @@ uintptr_t dynarecDE(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
case 0xFE:
|
||||
case 0xFF:
|
||||
INST_NAME("FDIVP STx, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VDIV_F64(v2, v2, v1);
|
||||
x87_do_pop(dyn, ninst);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0)) {
|
||||
VDIV_F32(v2, v2, v1);
|
||||
} else {
|
||||
VDIV_F64(v2, v2, v1);
|
||||
}
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
case 0xD2:
|
||||
case 0xD3:
|
||||
case 0xD4:
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
case 0xD8:
|
||||
case 0xDA:
|
||||
case 0xDB:
|
||||
@@ -146,7 +181,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 +188,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;
|
||||
}
|
||||
}
|
||||
|
||||
+270
-89
@@ -28,23 +28,47 @@ 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;
|
||||
int32_t j32;
|
||||
uint8_t wback;
|
||||
uint8_t ed;
|
||||
int v0, v1, v2;
|
||||
int s0;
|
||||
int fixedaddress;
|
||||
int parity;
|
||||
|
||||
MAYUSE(s0);
|
||||
MAYUSE(v2);
|
||||
MAYUSE(v1);
|
||||
MAYUSE(v0);
|
||||
MAYUSE(j32);
|
||||
|
||||
switch(nextop) {
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
case 0xC2:
|
||||
case 0xC3:
|
||||
case 0xC4:
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
INST_NAME("FFREEP STx");
|
||||
// not handling Tag...
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
case 0xE0:
|
||||
INST_NAME("FNSTSW AX");
|
||||
LDR_IMM9(x2, xEmu, offsetof(x86emu_t, top));
|
||||
LDRH_IMM8(x1, xEmu, offsetof(x86emu_t, sw));
|
||||
AND_IMM8(x2, x2, 7);
|
||||
if(dyn->x87stack) {
|
||||
// update top
|
||||
if(dyn->x87stack>0) {
|
||||
SUB_IMM8(x2, x2, dyn->x87stack);
|
||||
} else {
|
||||
ADD_IMM8(x2, x2, -dyn->x87stack);
|
||||
}
|
||||
AND_IMM8(x2, x2, 7);
|
||||
}
|
||||
BFI(x1, x2, 11, 3); // inject top
|
||||
BFI(xEAX, x1, 0, 16);
|
||||
break;
|
||||
@@ -57,13 +81,17 @@ 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);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VCMP_F64(v1, v2);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0))
|
||||
{
|
||||
VCMP_F32(v1, v2);
|
||||
} else {
|
||||
VCMP_F64(v1, v2);
|
||||
}
|
||||
FCOMI(x1, x2);
|
||||
x87_do_pop(dyn, ninst);
|
||||
UFLAGS(1);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
@@ -74,23 +102,19 @@ 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);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7);
|
||||
VCMP_F64(v1, v2);
|
||||
SETFLAGS(X_ALL, SF_SET);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, X87_COMBINE(0, nextop&7));
|
||||
v2 = x87_get_st(dyn, ninst, x1, x2, nextop&7, X87_COMBINE(0, nextop&7));
|
||||
if(ST_IS_F(0))
|
||||
{
|
||||
VCMP_F32(v1, v2);
|
||||
} else {
|
||||
VCMP_F64(v1, v2);
|
||||
}
|
||||
FCOMI(x1, x2);
|
||||
x87_do_pop(dyn, ninst);
|
||||
UFLAGS(1);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
case 0xC2:
|
||||
case 0xC3:
|
||||
case 0xC4:
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
case 0xCA:
|
||||
@@ -130,7 +154,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;
|
||||
|
||||
@@ -138,104 +161,262 @@ uintptr_t dynarecDF(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst,
|
||||
switch((nextop>>3)&7) {
|
||||
case 0:
|
||||
INST_NAME("FILD ST0, Ew");
|
||||
v1 = x87_do_push(dyn, ninst);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0);
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_F);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0);
|
||||
LDRSH_IMM8(x1, wback, fixedaddress);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
VMOVtoV(s0, x1);
|
||||
VCVT_F64_S32(v1, s0);
|
||||
if(ST_IS_F(0)) {
|
||||
VMOVtoV(v1, x1);
|
||||
VCVT_F32_S32(v1, v1);
|
||||
} else {
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
VMOVtoV(s0, x1);
|
||||
VCVT_F64_S32(v1, s0);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
INST_NAME("FISTTP Ew, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x12);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 255, 0);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_F);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 255, 0, 0);
|
||||
ed = x1;
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
VCVT_S32_F64(s0, v1);
|
||||
MSR_nzcvq_0();
|
||||
VMRS(x14); // get fpscr
|
||||
// x1 already have FPCSR reg to clear exceptions flags
|
||||
ORR_IMM8(x3, x14, 0b001, 6); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
if(ST_IS_F(0)) {
|
||||
VCVTR_S32_F32(s0, v1);
|
||||
} else {
|
||||
VCVTR_S32_F64(s0, v1);
|
||||
}
|
||||
VMRS(x3); // get the FPCSR reg and test FPU execption (invalid operation only)
|
||||
VMOVfrV(ed, s0);
|
||||
MSR_nzcvq_0(); // reset Q flag (and all other flags too)
|
||||
SSAT_REG_LSL_IMM5(ed, 16, ed, 0);
|
||||
MRS_aspr(x3); // check Q flag
|
||||
TSTS_IMM8_ROR(x3, 0b10, 3);
|
||||
B_MARK(cEQ); // not saturated, continue
|
||||
MOV32(ed, 0xffff8000);
|
||||
MARK;
|
||||
STRH_IMM8(ed, wback, fixedaddress);
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
SSAT_REG_LSL_IMM5_COND(cEQ, x3, 16, ed, 0);
|
||||
CMPS_REG_LSL_IMM5_COND(cEQ, ed, x3, 0);
|
||||
MOVW_COND(cNE, x3, 0x8000); // saturated
|
||||
STRH_IMM8(x3, wback, fixedaddress);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
VMSR(x14);
|
||||
break;
|
||||
case 2:
|
||||
INST_NAME("FIST Ew, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x12);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 255, 0);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_F);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 255, 0, 0);
|
||||
ed = x1;
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
VCVTR_S32_F64(s0, v1);
|
||||
MSR_nzcvq_0();
|
||||
// x1 already have FPCSR reg to clear exceptions flags
|
||||
ORR_IMM8(x3, x1, 0b001, 6); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
if(ST_IS_F(0)) {
|
||||
VCVTR_S32_F32(s0, v1);
|
||||
} else {
|
||||
VCVTR_S32_F64(s0, v1);
|
||||
}
|
||||
VMRS(x3); // get the FPCSR reg and test FPU execption (invalid operation only)
|
||||
VMOVfrV(ed, s0);
|
||||
MSR_nzcvq_0(); // reset Q flag (and all other flags too)
|
||||
SSAT_REG_LSL_IMM5(ed, 16, ed, 0);
|
||||
MRS_aspr(x3); // check Q flag
|
||||
TSTS_IMM8_ROR(x3, 0b10, 3);
|
||||
B_MARK(cEQ); // not saturated, continue
|
||||
MOV32(ed, 0xffff8000);
|
||||
MARK;
|
||||
STRH_IMM8(ed, wback, fixedaddress);
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
SSAT_REG_LSL_IMM5_COND(cEQ, x3, 16, ed, 0);
|
||||
CMPS_REG_LSL_IMM5_COND(cEQ, ed, x3, 0);
|
||||
MOVW_COND(cNE, x3, 0x8000); // saturated
|
||||
STRH_IMM8(x3, wback, fixedaddress);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 3:
|
||||
INST_NAME("FISTP Ew, ST0");
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x12);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 255, 0);
|
||||
v1 = x87_get_st(dyn, ninst, x1, x2, 0, NEON_CACHE_ST_F);
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x14);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 255, 0, 0);
|
||||
ed = x1;
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
VCVTR_S32_F64(s0, v1);
|
||||
MSR_nzcvq_0();
|
||||
// x1 already have FPCSR reg to clear exceptions flags
|
||||
ORR_IMM8(x3, x1, 0b001, 6); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
if(ST_IS_F(0)) {
|
||||
VCVTR_S32_F32(s0, v1);
|
||||
} else {
|
||||
VCVTR_S32_F64(s0, v1);
|
||||
}
|
||||
VMRS(x3); // get the FPCSR reg and test FPU execption (invalid operation only)
|
||||
VMOVfrV(ed, s0);
|
||||
MSR_nzcvq_0(); // reset Q flag (and all other flags too)
|
||||
SSAT_REG_LSL_IMM5(ed, 16, ed, 0);
|
||||
MRS_aspr(x3); // check Q flag
|
||||
TSTS_IMM8_ROR(x3, 0b10, 3);
|
||||
B_MARK(cEQ); // not saturated, continue
|
||||
MOV32(ed, 0xffff8000);
|
||||
MARK;
|
||||
STRH_IMM8(ed, wback, fixedaddress);
|
||||
x87_do_pop(dyn, ninst);
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
SSAT_REG_LSL_IMM5_COND(cEQ, x3, 16, ed, 0);
|
||||
CMPS_REG_LSL_IMM5_COND(cEQ, ed, x3, 0);
|
||||
MOVW_COND(cNE, x3, 0x8000); // saturated
|
||||
STRH_IMM8(x3, wback, fixedaddress);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
x87_restoreround(dyn, ninst, u8);
|
||||
break;
|
||||
case 4:
|
||||
INST_NAME("FBLD ST0, tbytes");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_do_push_empty(dyn, ninst, x1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
if(ed!=x1) {MOV_REG(x1, ed);}
|
||||
CALL(fpu_fbld, -1, 0);
|
||||
break;
|
||||
case 5: // could be inlined for most thing, but is it usefull?
|
||||
case 5:
|
||||
INST_NAME("FILD ST0, i64");
|
||||
x87_do_push_empty(dyn, ninst, x1);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
|
||||
if(ed!=x1) {MOV_REG(x1, ed);}
|
||||
CALL(arm_fild64, -1, 0);
|
||||
v1 = x87_do_push(dyn, ninst, x1, NEON_CACHE_ST_D);
|
||||
v2 = fpu_get_scratch_double(dyn);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x1, &fixedaddress, 0, 0, 0);
|
||||
if(parity) {
|
||||
LDRD_IMM8(x2, wback, 0); // x2/x3 is 64bits
|
||||
} else {
|
||||
LDR_IMM9(x2, wback, 0);
|
||||
LDR_IMM9(x3, wback, 4);
|
||||
}
|
||||
if(ninst<dyn->size
|
||||
&& dyn->insts[ninst+1].x86.addr
|
||||
&& *(uint8_t*)dyn->insts[ninst+1].x86.addr==0xDF
|
||||
&& (((*(uint8_t*)(dyn->insts[ninst+1].x86.addr+1))>>3)&7)==7)
|
||||
{
|
||||
MESSAGE(LOG_DUMP, "Hack for FILD/FISTP i64");
|
||||
} else {
|
||||
// Save xFlags to use it as scratch...
|
||||
STR_IMM9(xFlags, xEmu, offsetof(x86emu_t, eflags));
|
||||
// set STll(0).ll=i64 and ref=ST(0).q later (emu->fpu_ll[emu->top].ref == emu->mmx87[emu->top])
|
||||
// get TOP
|
||||
LDR_IMM9(xFlags, xEmu, offsetof(x86emu_t, top));
|
||||
int a = 0 - dyn->x87stack;
|
||||
if(a<0) {
|
||||
SUB_IMM8(xFlags, xFlags, -a);
|
||||
AND_IMM8(xFlags, xFlags, 7);
|
||||
} else if(a>0) {
|
||||
ADD_IMM8(xFlags, xFlags, a);
|
||||
AND_IMM8(xFlags, xFlags, 7);
|
||||
}
|
||||
ADD_REG_LSL_IMM5(xFlags, xEmu, xFlags, 4); // each fpu_ll is 2 int64: ref than ll
|
||||
ADD_IMM8_ROR(xFlags, xFlags, offsetof(x86emu_t, fpu_ll)>>2, 15);
|
||||
STRD_IMM8(x2, xFlags, 8); // save ll
|
||||
// continue with conversion
|
||||
MOVS_REG_LSR_IMM5(x14, x3, 31); // x14 is sign bit
|
||||
B_MARK(cEQ); // no NEG is no sign bit
|
||||
RSBS_IMM8(x2, x2, 0);
|
||||
RSC_IMM8(x3, x3, 0);
|
||||
MARK;
|
||||
VMOVtoV(s0, x3);
|
||||
VCVT_F64_U32(v1, s0);
|
||||
VEOR(v2, v2, v2);
|
||||
MOVW(x1, 0x41F0);
|
||||
VMOVtoDx_16(v2, 3, x1);
|
||||
VMUL_F64(v1, v1, v2); // v1 = double high part of i64
|
||||
VMOVtoV(s0, x2);
|
||||
VCVT_F64_U32(v2, s0);
|
||||
VADD_F64(v1, v1, v2);
|
||||
TSTS_IMM8(x14, 1);
|
||||
VNEG_F64_cond(cNE, v1, v1);
|
||||
VST1_64(v1, xFlags); // Store STll(0).ref
|
||||
LDR_IMM9(xFlags, xEmu, offsetof(x86emu_t, eflags));
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
INST_NAME("FBSTP tbytes, ST0");
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
if(ed!=x1) {MOV_REG(x1, ed);}
|
||||
CALL(fpu_fbst, -1, 0);
|
||||
x87_do_pop(dyn, ninst);
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
case 7: // could be inlined for most thing, but is it usefull?
|
||||
INST_NAME("FISTP i64, ST0");
|
||||
x87_forget(dyn, ninst, x1, x2, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
|
||||
if(ed!=x1) {MOV_REG(x1, ed);}
|
||||
CALL(arm_fistp64, -1, 0);
|
||||
x87_do_pop(dyn, ninst);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
if(ninst
|
||||
&& dyn->insts[ninst-1].x86.addr
|
||||
&& *(uint8_t*)dyn->insts[ninst-1].x86.addr==0xDF
|
||||
&& (((*(uint8_t*)(dyn->insts[ninst-1].x86.addr+1))>>3)&7)==5)
|
||||
{
|
||||
if(parity) {
|
||||
STRD_IMM8(x2, ed, 0); // x2/x3 is 64bits
|
||||
} else {
|
||||
STR_IMM9(x2, ed, 0);
|
||||
STR_IMM9(x3, ed, 4);
|
||||
}
|
||||
} else {
|
||||
#if 0
|
||||
v1 = x87_get_st(dyn, ninst, x2, x3, 0);
|
||||
//addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
v2 = fpu_get_scratch_double(dyn);
|
||||
v0 = fpu_get_scratch_double(dyn);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
// check STll(0).ref==ST(0).q so emu->fpu_ll[emu->top].ref == emu->mmx87[emu->top]
|
||||
// get TOP
|
||||
LDR_IMM9(x14, xEmu, offsetof(x86emu_t, top));
|
||||
int a = 0 - dyn->x87stack;
|
||||
if(a<0) {
|
||||
SUB_IMM8(x14, x14, -a);
|
||||
AND_IMM8(x14, x14, 7); // (emu->top + i)&7
|
||||
} else if(a>0) {
|
||||
ADD_IMM8(x14, x14, a);
|
||||
AND_IMM8(x14, x14, 7); // (emu->top + i)&7
|
||||
}
|
||||
ADD_REG_LSL_IMM5(x14, xEmu, x14, 4); // each fpu_ll is 2 int64: ref than ll
|
||||
MOVW(x2, offsetof(x86emu_t, fpu_ll)); //can be optimized?
|
||||
ADD_REG_LSL_IMM5(x14, x14, x2, 0);
|
||||
VLDR_64(v2, x14, 0);
|
||||
VCEQ_32(v2, v2, v1); // compare
|
||||
VMOVfrV_D(x2, x3, v2);
|
||||
ANDS_REG_LSL_IMM5(x2, x2, x3, 0); // if NE then values are the same!
|
||||
B_MARK(cEQ); // do the i64 conversion
|
||||
// memcpy(ed, &STll(0).ll, sizeof(int64_t));
|
||||
LDRD_IMM8(x2, x14, 8); // load ll
|
||||
B_MARK3(c__);
|
||||
MARK;
|
||||
VEOR(v0, v0, v0);
|
||||
MOVW(x2, 0x41F0);
|
||||
VMOVtoDx_16(v0, 3, x2); // V0 = (1<<32) as double
|
||||
VMOVfrDx_32(x14, v1, 1); // get high part to extract sign
|
||||
VABS_F64(v1 ,v1); //ST0 will be poped, so lost...
|
||||
VDIV_F64(v2, v1, v0); // v2 = abs(ST0)/(1<<32) : so 32 bits high part
|
||||
MSR_nzcvq_0();
|
||||
VMRS(x2); // get fpscr
|
||||
ORR_IMM8(x3, x2, 0b001, 6); // enable exceptions
|
||||
BIC_IMM8(x3, x3, 0b10011111, 0);
|
||||
VMSR(x3);
|
||||
VCVT_U32_F64(s0, v2); // convert high part to U32
|
||||
VMRS(x3); // get the FPCSR reg and test FPU execption (invalid operation only)
|
||||
VMSR(x2); // put back fpscr
|
||||
TSTS_IMM8_ROR(x3, 0b00000001, 0);
|
||||
B_MARK2(cEQ); // not overflow...
|
||||
MARKLOCK;
|
||||
MOV_IMM(x3, 0b10, 1); // 0x80000000
|
||||
MOVW(x2, 0);
|
||||
B_MARK3(c__);
|
||||
MARK2; // continue conversion, it fits an int64!
|
||||
VCVT_F64_U32(v2, s0); // int part now
|
||||
VMLS_F64(v1, v2, v0); // compute low part
|
||||
VMOVfrV(x3, s0); // transfert high path
|
||||
TSTS_IMM8_ROR(x14, 0b10, 1); // test high part with 0x800000000
|
||||
B_MARKLOCK(cNE); // int overflow...
|
||||
VCVT_U32_F64(s0, v1); // convert low part
|
||||
VMOVfrV(x2, s0); // transfert low part
|
||||
TSTS_IMM8_ROR(x14, 0b10, 1); // 0x800000000
|
||||
B_MARK3(cEQ);
|
||||
RSBS_IMM8(x2, x2, 0); // NEG(i64)
|
||||
RSC_IMM8(x3, x3, 0);
|
||||
MARK3;
|
||||
STR_IMM9(x2, x1, 0);
|
||||
STR_IMM9(x3, x1, 4);
|
||||
#else
|
||||
MESSAGE(LOG_DUMP, "Need Optimization\n");
|
||||
x87_forget(dyn, ninst, x2, x3, 0);
|
||||
if(ed!=x1) {MOV_REG(x1, ed);}
|
||||
CALL(arm_fistp64, -1, 0);
|
||||
#endif
|
||||
}
|
||||
x87_do_pop(dyn, ninst, x3);
|
||||
break;
|
||||
default:
|
||||
*ok = 0;
|
||||
DEFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
Executable
+744
@@ -0,0 +1,744 @@
|
||||
#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 OR32 instruction, from s1 , s2, store result in s1 using s3 and s4 as scratch
|
||||
void emit_or32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_or32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_ALL) {
|
||||
ORRS_REG_LSL_IMM5(s1, s1, s2, 0);
|
||||
} else {
|
||||
ORR_REG_LSL_IMM5(s1, s1, s2, 0);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_ZF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s3, s1, 31);
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit OR32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_or32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOV32(s3, c);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_or32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(c>=0 && c<256) {
|
||||
IFX(X_ALL) {
|
||||
ORRS_IMM8(s1, s1, c, 0);
|
||||
} else {
|
||||
ORR_IMM8(s1, s1, c, 0);
|
||||
}
|
||||
} else {
|
||||
IFX(X_PEND) {} else {MOV32(s3, c);}
|
||||
IFX(X_ALL) {
|
||||
ORRS_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
} else {
|
||||
ORR_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
}
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_ZF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s3, s1, 31);
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit XOR32 instruction, from s1 , s2, store result in s1 using s3 and s4 as scratch
|
||||
void emit_xor32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_xor32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_ALL) {
|
||||
XORS_REG_LSL_IMM5(s1, s1, s2, 0);
|
||||
} else {
|
||||
XOR_REG_LSL_IMM5(s1, s1, s2, 0);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_ZF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s3, s1, 31);
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit XOR32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_xor32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOV32(s3, c);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_xor32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(c>=0 && c<256) {
|
||||
IFX(X_ALL) {
|
||||
XORS_IMM8(s1, s1, c);
|
||||
} else {
|
||||
XOR_IMM8(s1, s1, c);
|
||||
}
|
||||
} else {
|
||||
IFX(X_PEND) {} else {MOV32(s3, c);}
|
||||
IFX(X_ALL) {
|
||||
XORS_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
} else {
|
||||
XOR_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
}
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_ZF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s3, s1, 31);
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit AND32 instruction, from s1 , s2, store result in s1 using s3 and s4 as scratch
|
||||
void emit_and32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_and32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_ALL) {
|
||||
ANDS_REG_LSL_IMM5(s1, s1, s2, 0);
|
||||
} else {
|
||||
AND_REG_LSL_IMM5(s1, s1, s2, 0);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_ZF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s3, s1, 31);
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit AND32 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_and32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOV32(s3, c);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_and32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(c>=0 && c<256) {
|
||||
IFX(X_ALL) {
|
||||
ANDS_IMM8(s1, s1, c);
|
||||
} else {
|
||||
AND_IMM8(s1, s1, c);
|
||||
}
|
||||
} else {
|
||||
if(((~c)>=0 && (~c)<256)) {
|
||||
IFX(X_ALL) {
|
||||
BICS_IMM8_ROR(s1, s1, ~c, 0);
|
||||
} else {
|
||||
BIC_IMM8(s1, s1, ~c, 0);
|
||||
}
|
||||
} else {
|
||||
IFX(X_PEND) {} else {MOV32(s3, c);}
|
||||
IFX(X_ALL) {
|
||||
ANDS_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
} else {
|
||||
AND_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_ZF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s3, s1, 31);
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit OR8 instruction, from s1 , s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed)
|
||||
void emit_or8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s3, d_or8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
IFX(X_ALL) {
|
||||
ORRS_REG_LSL_IMM5(s1, s1, s2, 0);
|
||||
} else {
|
||||
ORR_REG_LSL_IMM5(s1, s1, s2, 0);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_ZF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s3, s1, 7);
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit OR8 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_or8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOV32(s3, c&0xff);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_or8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_ALL) {
|
||||
ORRS_IMM8(s1, s1, c, 0);
|
||||
} else {
|
||||
ORR_IMM8(s1, s1, c, 0);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_ZF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s3, s1, 7);
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit XOR8 instruction, from s1 , s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed)
|
||||
void emit_xor8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s3, d_xor8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
IFX(X_ALL) {
|
||||
XORS_REG_LSL_IMM5(s1, s1, s2, 0);
|
||||
} else {
|
||||
XOR_REG_LSL_IMM5(s1, s1, s2, 0);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_ZF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s3, s1, 7);
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit XOR8 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_xor8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOV32(s3, c&0xff);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_xor8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_ALL) {
|
||||
XORS_IMM8(s1, s1, c);
|
||||
} else {
|
||||
XOR_IMM8(s1, s1, c);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_ZF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s3, s1, 7);
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit AND8 instruction, from s1 , s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed)
|
||||
void emit_and8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s3, d_and8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
IFX(X_ALL) {
|
||||
ANDS_REG_LSL_IMM5(s1, s1, s2, 0);
|
||||
} else {
|
||||
AND_REG_LSL_IMM5(s1, s1, s2, 0);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_ZF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s3, s1, 7);
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit AND8 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_and8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOV32(s3, c&0xff);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_and8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_ALL) {
|
||||
ANDS_IMM8(s1, s1, c);
|
||||
} else {
|
||||
AND_IMM8(s1, s1, c);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_ZF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s3, s1, 7);
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// emit OR16 instruction, from s1 , s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed)
|
||||
void emit_or16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s3, d_or16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
IFX(X_ALL) {
|
||||
ORRS_REG_LSL_IMM5(s1, s1, s2, 0);
|
||||
} else {
|
||||
ORR_REG_LSL_IMM5(s1, s1, s2, 0);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_ZF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s3, s1, 15);
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit OR16 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_or16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOVW(s3, c);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_or16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(c>=0 && c<256) {
|
||||
IFX(X_ALL) {
|
||||
ORRS_IMM8(s1, s1, c, 0);
|
||||
} else {
|
||||
ORR_IMM8(s1, s1, c, 0);
|
||||
}
|
||||
} else {
|
||||
IFX(X_PEND) {} else {MOVW(s3, c);}
|
||||
IFX(X_ALL) {
|
||||
ORRS_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
} else {
|
||||
ORR_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
}
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_ZF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s3, s1, 15);
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit XOR16 instruction, from s1 , s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed)
|
||||
void emit_xor16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s3, d_xor16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
IFX(X_ALL) {
|
||||
XORS_REG_LSL_IMM5(s1, s1, s2, 0);
|
||||
} else {
|
||||
XOR_REG_LSL_IMM5(s1, s1, s2, 0);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_ZF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s3, s1, 15);
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit XOR16 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_xor16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOVW(s3, c);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_xor16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(c>=0 && c<256) {
|
||||
IFX(X_ALL) {
|
||||
XORS_IMM8(s1, s1, c);
|
||||
} else {
|
||||
XOR_IMM8(s1, s1, c);
|
||||
}
|
||||
} else {
|
||||
IFX(X_PEND) {} else {MOVW(s3, c);}
|
||||
IFX(X_ALL) {
|
||||
XORS_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
} else {
|
||||
XOR_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
}
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_ZF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s3, s1, 15);
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit AND16 instruction, from s1 , s2, store result in s1 using s3 and s4 as scratch, s4 can be same as s2 (and so s2 destroyed)
|
||||
void emit_and16(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s3, d_and16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
IFX(X_ALL) {
|
||||
ANDS_REG_LSL_IMM5(s1, s1, s2, 0);
|
||||
} else {
|
||||
AND_REG_LSL_IMM5(s1, s1, s2, 0);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_ZF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s3, s1, 15);
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit AND16 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_and16c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOVW(s3, c);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_and16);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(c>=0 && c<256) {
|
||||
IFX(X_ALL) {
|
||||
ANDS_IMM8(s1, s1, c);
|
||||
} else {
|
||||
AND_IMM8(s1, s1, c);
|
||||
}
|
||||
} else {
|
||||
IFX(X_PEND) {} else {MOVW(s3, c);}
|
||||
IFX(X_ALL) {
|
||||
ANDS_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
} else {
|
||||
AND_REG_LSL_IMM5(s1, s1, s3, 0);
|
||||
}
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_CF | X_AF | X_ZF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s3, s1, 15);
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
Executable
+1860
File diff suppressed because it is too large.
Load diff
Executable
+594
@@ -0,0 +1,594 @@
|
||||
#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 , shift s2, store result in s1 using s3 and s4 as scratch. s3 can be same as s2
|
||||
void emit_shl32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
int32_t j32;
|
||||
MAYUSE(j32);
|
||||
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_shl32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(F_OF) {
|
||||
CMPS_IMM8(s2, 0);
|
||||
IFX(F_OF) {
|
||||
BIC_IMM8_COND(cEQ, xFlags, xFlags, 0b10, 0x0b);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9_COND(cEQ, s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
B_NEXT(cEQ);
|
||||
}
|
||||
IFX(X_CF | X_OF) {
|
||||
RSB_IMM8(s4, s2, 32);
|
||||
MOV_REG_LSR_REG(s4, s1, s4);
|
||||
BFI(xFlags, s4, F_CF, 1);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
MOVS_REG_LSL_REG(s1, s1, s2);
|
||||
} else {
|
||||
MOV_REG_LSL_REG(s1, s1, s2);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 31);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CMPS_IMM8(s2, 1); // if s3==1
|
||||
IFX(X_SF) {} else {MOV_REG_LSR_IMM5_COND(cEQ, s4, s1, 31);}
|
||||
XOR_REG_LSL_IMM5_COND(cEQ, s4, s4, xFlags, 0); // CF is set if OF is asked
|
||||
BFI_COND(cEQ, xFlags, s4, F_OF, 1);
|
||||
// else
|
||||
BFC_COND(cNE, xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// 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));
|
||||
SET_DF(s4, d_shl32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(c==0) {
|
||||
IFX(F_OF) {
|
||||
BIC_IMM8(xFlags, xFlags, 0b10, 0x0b);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
IFX(X_CF) {
|
||||
MOV_REG_LSR_IMM5(s3, s1, 32-c);
|
||||
BFI(xFlags, s3, F_CF, 1);
|
||||
}
|
||||
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) {
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s3, s1, 31);
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
IFX(X_SF) {} else {MOV_REG_LSR_IMM5(s3, s1, 31);}
|
||||
XOR_IMM8_COND(cCS, s3, s3, 1);
|
||||
BFI(xFlags, s3, F_OF, 1);
|
||||
} else {
|
||||
BFC(xFlags, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit SHR32 instruction, from s1 , s2, store result in s1 using s3 and s4 as scratch, s2 can be same as s3
|
||||
void emit_shr32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
int32_t j32;
|
||||
MAYUSE(j32);
|
||||
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_shr32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_ALL) {
|
||||
CMPS_IMM8(s2, 0); //if(!c)
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9_COND(cEQ, s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
B_NEXT(cEQ);
|
||||
}
|
||||
IFX(X_ZF|X_CF) {
|
||||
MOVS_REG_LSR_REG(s1, s1, s2);
|
||||
} else {
|
||||
MOV_REG_LSR_REG(s1, s1, s2);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF|X_CF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
ORR_IMM8_COND(cCS, xFlags, xFlags, 1<<F_CF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 31);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CMPS_IMM8(s2, 1);
|
||||
MOV_REG_LSR_IMM5_COND(cEQ, s4, s1, 30);
|
||||
XOR_REG_LSR_IMM8_COND(cEQ, s4, s4, s4, 1);
|
||||
BFI_COND(cEQ, xFlags, s4, F_OF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit 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));
|
||||
SET_DF(s4, d_shr32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
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|X_CF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
ORR_IMM8_COND(cCS, xFlags, xFlags, 1<<F_CF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s3, s1, 31);
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 30);
|
||||
XOR_REG_LSR_IMM8(s4, s4, s4, 1);
|
||||
BFI(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit 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));
|
||||
SET_DF(s4, d_sar32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
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|X_CF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
ORR_IMM8_COND(cCS, xFlags, xFlags, 1<<F_CF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s3, s1, 31);
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
if(!c)
|
||||
return;
|
||||
IFX(X_PEND) {
|
||||
MOVW(s3, c);
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_rol32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
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) {
|
||||
BFI(xFlags, s1, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
ADD_REG_LSR_IMM5(s3, s1, s1, 31);
|
||||
BFI(xFlags, s3, F_OF, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
if(!c)
|
||||
return;
|
||||
IFX(X_PEND) {
|
||||
MOVW(s3, c);
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_ror32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
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) {
|
||||
MOV_REG_LSR_IMM5(s3, s1, 31);
|
||||
BFI(xFlags, s3, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 30);
|
||||
XOR_REG_LSR_IMM8(s4, s4, s4, 1);
|
||||
BFI(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// emit SHRD32 instruction, from s1, fill s2 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_shrd32c(dynarec_arm_t* dyn, int ninst, int s1, int s2, int32_t c, int s3, int s4)
|
||||
{
|
||||
c&=0x1f;
|
||||
IFX(X_PEND) {
|
||||
MOVW(s3, c);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
// same flags calc as shr32
|
||||
SET_DF(s4, d_shr32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(!c) {
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
IFX(X_CF) {
|
||||
MOVS_REG_LSR_IMM5(s1, s1, c);
|
||||
} else {
|
||||
MOV_REG_LSR_IMM5(s1, s1, c);
|
||||
}
|
||||
IFX(X_ZF|X_CF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
ORR_IMM8_COND(cCS, xFlags, xFlags, 1<<F_CF, 0);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ORRS_REG_LSL_IMM5(s1, s1, s2, 32-c);
|
||||
} else {
|
||||
ORR_REG_LSL_IMM5(s1, s1, s2, 32-c);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s3, s1, 31);
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 30);
|
||||
XOR_REG_LSR_IMM8(s4, s4, s4, 1);
|
||||
BFI(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
void emit_shld32c(dynarec_arm_t* dyn, int ninst, int s1, int s2, int32_t c, int s3, int s4)
|
||||
{
|
||||
c&=0x1f;
|
||||
IFX(X_PEND) {
|
||||
MOVW(s3, c);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
// same flags computation as with shl32
|
||||
SET_DF(s4, d_shl32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(c==0) {
|
||||
IFX(F_OF) {
|
||||
BFC(xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
IFX(X_CF) {
|
||||
MOV_REG_LSR_IMM5(s3, s1, 32-c);
|
||||
BFI(xFlags, s3, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
MOVS_REG_LSL_IMM5(s1, s1, c);
|
||||
} else {
|
||||
MOV_REG_LSL_IMM5(s1, s1, c);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
UBFX(s3, s1, (31-c), 1);
|
||||
XOR_IMM8_COND(cCS, s3, s3, 1);
|
||||
BFI(xFlags, s3, F_OF, 1);
|
||||
} else {
|
||||
BFC(xFlags, F_OF, 1);
|
||||
}
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ORRS_REG_LSR_IMM5(s1, s1, s2, 32-c);
|
||||
} else {
|
||||
ORR_REG_LSR_IMM5(s1, s1, s2, 32-c);
|
||||
}
|
||||
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s3, s1, 31);
|
||||
BFI(xFlags, s3, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit SHRD32 instruction, from s1, fill s2 , shift s3, store result in s1 using s4 and s3 as scratch
|
||||
void emit_shrd32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4)
|
||||
{
|
||||
int j32;
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
// same flags calc as shr32
|
||||
SET_DF(s4, d_shr32);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
CMPS_IMM8(s3, 0);
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9_COND(cEQ, s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
B_NEXT(cEQ);
|
||||
|
||||
IFX(X_CF) {
|
||||
MOVS_REG_LSR_REG(s1, s1, s3);
|
||||
} else {
|
||||
MOV_REG_LSR_REG(s1, s1, s3);
|
||||
}
|
||||
IFX(X_ZF|X_CF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
ORR_IMM8_COND(cCS, xFlags, xFlags, 1<<F_CF, 0);
|
||||
}
|
||||
RSB_IMM8(s3, s3, 32);
|
||||
IFX(X_ZF) {
|
||||
ORRS_REG_LSL_REG(s1, s1, s2, s3);
|
||||
} else {
|
||||
ORR_REG_LSL_REG(s1, s1, s2, s3);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 31);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
CMPS_IMM8(s3, 31); // 32-c
|
||||
MOV_REG_LSR_IMM5_COND(cEQ, s4, s1, 30);
|
||||
XOR_REG_LSR_IMM8_COND(cEQ, s4, s4, s4, 1);
|
||||
BFI_COND(cEQ, xFlags, s4, F_OF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// emit ROL8 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_rol8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOVW(s3, c);
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_rol8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(!c) {
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(c&7) {
|
||||
BFI(s1, s1, 24, 8); // duplicate the value for rotate left
|
||||
MOV_REG_ROR_IMM5(s1, s1, 32-(c&7));
|
||||
}
|
||||
//AND_IMM8(s1, s1, 0xff);
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_CF) {
|
||||
BFI(xFlags, s1, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
ADD_REG_LSR_IMM5(s3, s1, s1, 7);
|
||||
BFI(xFlags, s3, F_OF, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// emit ROR8 instruction, from s1 , constant c, store result in s1 using s3 and s4 as scratch
|
||||
void emit_ror8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4)
|
||||
{
|
||||
IFX(X_PEND) {
|
||||
MOVW(s3, c);
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_ror8);
|
||||
} else IFX(X_ALL) {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
if(!c) {
|
||||
IFX(X_PEND) {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(c&7) {
|
||||
BFI(s1, s1, 8, 8); // duplicate the value for Rotate right
|
||||
MOV_REG_ROR_IMM5(s1, s1, c&7);
|
||||
}
|
||||
IFX(X_PEND) {
|
||||
AND_IMM8(s1, s1, 0xff);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_CF) {
|
||||
MOV_REG_LSR_IMM5(s3, s1, 7);
|
||||
BFI(xFlags, s3, F_CF, 1);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
if(c==1) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 6);
|
||||
XOR_REG_LSR_IMM8(s4, s4, s4, 1);
|
||||
BFI(xFlags, s4, F_OF, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+412
@@ -0,0 +1,412 @@
|
||||
#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_PENDOR0 {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_cmp32);
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
SUBS_REG_LSL_IMM5(s3, s1, s2, 0); // res = s1 - s2
|
||||
IFX_PENDOR0 {
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF|X_CF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
ORR_IMM8_COND(cVS, xFlags, xFlags, 0b10, 0x0b);
|
||||
BIC_IMM8_COND(cVC, xFlags, xFlags, 0b10, 0x0b);
|
||||
}
|
||||
IFX(X_CF) {
|
||||
// reversed carry
|
||||
ORR_IMM8_COND(cCC, xFlags, xFlags, 1<<F_CF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s4, s3, 31);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
// and now the tricky ones (and mostly unused), PF and AF
|
||||
IFX(X_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) {
|
||||
MOV_REG_LSR_IMM5(s4, s3, 3);
|
||||
BFI(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
IFX(X_CF|X_AF) {
|
||||
SUB_REG_LSL_IMM5(s3, s1, s2, 0);
|
||||
}
|
||||
AND_IMM8(s3, s3, 0xE0); // lsr 5 masking pre-applied
|
||||
MOV32(s4, GetParityTab());
|
||||
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
|
||||
SUB_REG_LSL_IMM5(s3, s1, s2, 0);
|
||||
AND_IMM8(s3, s3, 31);
|
||||
MVN_REG_LSR_REG(s4, s4, s3);
|
||||
BFI(xFlags, s4, F_PF, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// emit CMP32 instruction, from cmp s1 , 0, using s3 and s4 as scratch
|
||||
void emit_cmp32_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
{
|
||||
IFX_PENDOR0 {
|
||||
MOVW(s4, 0);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, op2));
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
SET_DF(s4, d_cmp32);
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
SUBS_IMM8(s3, s1, 0); // res = s1 - 0
|
||||
// and now the tricky ones (and mostly unused), PF and AF
|
||||
// bc = (res & (~d | s)) | (~d & s) => is 0 here...
|
||||
IFX(X_CF | X_AF | X_ZF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BFC(xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s4, s3, 31);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// 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_PENDOR0 {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s3, d_cmp16);
|
||||
} else {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
SUB_REG_LSL_IMM5(s3, s1, s2, 0); // res = s1 - s2
|
||||
IFX_PENDOR0 {
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
MOVW(s4, 0xffff);
|
||||
TSTS_REG_LSL_IMM5(s3, s4, 0);
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s4, s3, 15);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
// 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) {
|
||||
MOV_REG_LSR_IMM5(s4, s3, 15);
|
||||
BFI(xFlags, s4, F_CF, 1); // CF : bc & 0x8000
|
||||
}
|
||||
IFX(X_AF) {
|
||||
MOV_REG_LSR_IMM5(s4, s3, 3);
|
||||
BFI(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
}
|
||||
IFX(X_OF) {
|
||||
MOV_REG_LSR_IMM5(s4, s3, 14);
|
||||
XOR_REG_LSR_IMM8(s4, s4, s4, 1);
|
||||
BFI(xFlags, s4, F_OF, 1); // OF: ((bc >> 14) ^ ((bc>>14)>>1)) & 1
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
IFX(X_CF|X_AF|X_OF) {
|
||||
SUB_REG_LSL_IMM5(s3, s1, s2, 0);
|
||||
}
|
||||
AND_IMM8(s3, s3, 0xE0); // lsr 5 masking pre-applied
|
||||
MOV32(s4, GetParityTab());
|
||||
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
|
||||
SUB_REG_LSL_IMM5(s3, s1, s2, 0);
|
||||
AND_IMM8(s3, s3, 31);
|
||||
MVN_REG_LSR_REG(s4, s4, s3);
|
||||
BFI(xFlags, s4, F_PF, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// emit CMP16 instruction, from cmp s1 , #0, using s3 and s4 as scratch
|
||||
void emit_cmp16_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
{
|
||||
IFX_PENDOR0 {
|
||||
MOVW(s3, 0);
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, op2));
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
SET_DF(s3, d_cmp16);
|
||||
} else {
|
||||
SET_DFNONE(s3);
|
||||
}
|
||||
// bc = (res & (~d | s)) | (~d & s) = 0
|
||||
IFX(X_CF | X_AF | X_ZF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BFC(xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
MOVW(s4, 0xffff);
|
||||
TSTS_REG_LSL_IMM5(s1, s4, 0);
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 15);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
// 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_PENDOR0 {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, op2));
|
||||
SET_DF(s4, d_cmp8);
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
SUB_REG_LSL_IMM5(s3, s1, s2, 0); // res = s1 - s2
|
||||
IFX_PENDOR0 {
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTS_IMM8(s3, 0xff);
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
BIC_IMM8_COND(cNE, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s4, s3, 7);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
// 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) {
|
||||
MOV_REG_LSR_IMM5(s4, s3, 7);
|
||||
BFI(xFlags, s4, F_CF, 1); // CF : bc & 0x80
|
||||
}
|
||||
IFX(X_AF) {
|
||||
MOV_REG_LSR_IMM5(s4, s3, 3);
|
||||
BFI(xFlags, s4, F_AF, 1); // AF: bc & 0x08
|
||||
}
|
||||
IFX(X_OF) {
|
||||
MOV_REG_LSR_IMM5(s4, s3, 6);
|
||||
XOR_REG_LSR_IMM8(s4, s4, s4, 1);
|
||||
BFI(xFlags, s4, F_OF, 1); // OF: ((bc >> 6) ^ ((bc>>6)>>1)) & 1
|
||||
}
|
||||
}
|
||||
IFX(X_PF) {
|
||||
IFX(X_CF|X_AF|X_OF) {
|
||||
SUB_REG_LSL_IMM5(s3, s1, s2, 0);
|
||||
}
|
||||
AND_IMM8(s3, s3, 0xE0); // lsr 5 masking pre-applied
|
||||
MOV32(s4, GetParityTab());
|
||||
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
|
||||
SUB_REG_LSL_IMM5(s3, s1, s2, 0);
|
||||
AND_IMM8(s3, s3, 31);
|
||||
MVN_REG_LSR_REG(s4, s4, s3);
|
||||
BFI(xFlags, s4, F_PF, 1);
|
||||
}
|
||||
}
|
||||
// emit CMP8 instruction, from cmp s1 , 0, using s3 and s4 as scratch
|
||||
void emit_cmp8_0(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4)
|
||||
{
|
||||
IFX_PENDOR0 {
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, op1));
|
||||
MOVW(s4, 0);
|
||||
STR_IMM9(s4, xEmu, offsetof(x86emu_t, op2));
|
||||
STR_IMM9(s1, xEmu, offsetof(x86emu_t, res));
|
||||
SET_DF(s3, d_cmp8);
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
// bc = (res & (~d | s)) | (~d & s) = 0
|
||||
IFX(X_CF | X_AF | X_ZF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_CF)|(1<<F_AF)|(1<<F_ZF), 0);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BFC(xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
TSTS_IMM8(s1, 0xff);
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s4, s1, 7);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
IFX(X_PF) {
|
||||
emit_pf(dyn, ninst, s1, s3, s4);
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
IFX_PENDOR0 {
|
||||
SET_DF(s3, d_tst32);
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BFC(xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_ZF|X_CF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
|
||||
}
|
||||
ANDS_REG_LSL_IMM5(s3, s1, s2, 0); // res = s1 & s2
|
||||
IFX_PENDOR0 {
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s4, s3, 31);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
IFX(X_PF) {
|
||||
AND_IMM8(s3, s3, 0xE0); // lsr 5 masking pre-applied
|
||||
MOV32(s4, GetParityTab());
|
||||
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
|
||||
if(s1==s2) {
|
||||
AND_IMM8(s3, s1, 31);
|
||||
} else {
|
||||
AND_REG_LSL_IMM5(s3, s1, s2, 0);
|
||||
AND_IMM8(s3, s3, 31);
|
||||
}
|
||||
MVN_REG_LSR_REG(s4, s4, s3);
|
||||
BFI(xFlags, s4, F_PF, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// emit 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)
|
||||
{
|
||||
IFX_PENDOR0 {
|
||||
SET_DF(s3, d_tst16);
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BFC(xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_ZF|X_CF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
|
||||
}
|
||||
ANDS_REG_LSL_IMM5(s3, s1, s2, 0); // res = s1 & s2
|
||||
IFX_PENDOR0 {
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s4, s3, 15);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
IFX(X_PF) {
|
||||
AND_IMM8(s3, s3, 0xE0); // lsr 5 masking pre-applied
|
||||
MOV32(s4, GetParityTab());
|
||||
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
|
||||
AND_REG_LSL_IMM5(s3, s1, s2, 0);
|
||||
AND_IMM8(s3, s3, 31);
|
||||
MVN_REG_LSR_REG(s4, s4, s3);
|
||||
BFI(xFlags, s4, F_PF, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// emit 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)
|
||||
{
|
||||
IFX_PENDOR0 {
|
||||
SET_DF(s3, d_tst8);
|
||||
} else {
|
||||
SET_DFNONE(s4);
|
||||
}
|
||||
IFX(X_OF) {
|
||||
BFC(xFlags, F_OF, 1);
|
||||
}
|
||||
IFX(X_ZF|X_CF) {
|
||||
BIC_IMM8(xFlags, xFlags, (1<<F_ZF)|(1<<F_CF), 0);
|
||||
}
|
||||
ANDS_REG_LSL_IMM5(s3, s1, s2, 0); // res = s1 & s2
|
||||
IFX_PENDOR0 {
|
||||
STR_IMM9(s3, xEmu, offsetof(x86emu_t, res));
|
||||
}
|
||||
IFX(X_ZF) {
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 1<<F_ZF, 0);
|
||||
}
|
||||
IFX(X_SF) {
|
||||
MOV_REG_LSR_IMM5(s4, s3, 7);
|
||||
BFI(xFlags, s4, F_SF, 1);
|
||||
}
|
||||
// PF: (((emu->x86emu_parity_tab[(res) / 32] >> ((res) % 32)) & 1) == 0)
|
||||
IFX(X_PF) {
|
||||
AND_IMM8(s3, s3, 0xE0); // lsr 5 masking pre-applied
|
||||
MOV32(s4, GetParityTab());
|
||||
LDR_REG_LSR_IMM5(s4, s4, s3, 5-2); // x/32 and then *4 because array is integer
|
||||
AND_REG_LSL_IMM5(s3, s1, s2, 0);
|
||||
AND_IMM8(s3, s3, 31);
|
||||
MVN_REG_LSR_REG(s4, s4, s3);
|
||||
BFI(xFlags, s4, F_PF, 1);
|
||||
}
|
||||
}
|
||||
+1009
-40
File diff suppressed because it is too large.
Load diff
+121
-70
@@ -22,44 +22,54 @@
|
||||
#include "dynarec_arm_functions.h"
|
||||
#include "dynarec_arm_helper.h"
|
||||
|
||||
// Get Ex as a double, not a quad
|
||||
#define GETEX(a) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
a = sse_get_reg(dyn, ninst, x1, nextop&7); \
|
||||
// Get Ex as a double, not a quad (warning, x2 and x3 may get used)
|
||||
#define GETEX(a, w) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
a = sse_get_reg(dyn, ninst, x1, nextop&7,w);\
|
||||
} 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, 0); \
|
||||
VLDR_64(a, ed, fixedaddress); \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 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:
|
||||
INST_NAME("MOVSD Gx, Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
d0 = sse_get_reg(dyn, ninst, x1, nextop&7);
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
d0 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
VMOVD(v0, d0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0);
|
||||
LDR_IMM9(x2, ed, fixedaddress+0);
|
||||
LDR_IMM9(x3, ed, fixedaddress+4);
|
||||
VMOVtoV_D(v0, x2, x3);
|
||||
@@ -70,13 +80,13 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("MOVSD Ex, Gx");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
d0 = sse_get_reg(dyn, ninst, x1, nextop&7);
|
||||
d0 = sse_get_reg(dyn, ninst, x1, nextop&7, 1);
|
||||
VMOVD(d0, v0);
|
||||
} else {
|
||||
VMOVfrV_D(x2, x3, v0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0);
|
||||
STR_IMM9(x2, ed, fixedaddress+0);
|
||||
STR_IMM9(x3, ed, fixedaddress+4);
|
||||
}
|
||||
@@ -85,25 +95,25 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("MOVDDUP Gx, Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
d0 = sse_get_reg(dyn, ninst, x1, nextop&7);
|
||||
d0 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VMOVD(v0, d0);
|
||||
VMOVD(v0+1, d0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-4, 0, 0);
|
||||
LDR_IMM9(x2, ed, fixedaddress+0);
|
||||
LDR_IMM9(x3, ed, fixedaddress+4);
|
||||
VMOVtoV_D(v0, x2, x3);
|
||||
VMOVD(v0+1, v0);
|
||||
}
|
||||
VMOVD(v0+1, v0);
|
||||
break;
|
||||
|
||||
case 0x2A:
|
||||
INST_NAME("CVTSI2SD Gx, Ed");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
GETED;
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
VMOVtoV(s0, ed);
|
||||
@@ -116,9 +126,9 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
GETGD;
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
d0 = sse_get_reg(dyn, ninst, x1, nextop&7);
|
||||
d0 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0);
|
||||
d0 = fpu_get_scratch_double(dyn);
|
||||
VLDR_64(d0, ed, fixedaddress);
|
||||
}
|
||||
@@ -127,14 +137,14 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
break;
|
||||
case 0x2D:
|
||||
INST_NAME("CVTSD2SI Gd, Ex");
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x12);
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x14);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
d0 = sse_get_reg(dyn, ninst, x1, nextop&7);
|
||||
d0 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0);
|
||||
d0 = fpu_get_scratch_double(dyn);
|
||||
VLDR_64(d0, ed, fixedaddress);
|
||||
}
|
||||
@@ -147,8 +157,8 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("SQRTSD Gx, Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
GETEX(d0);
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
GETEX(d0, 0);
|
||||
VSQRT_F64(v0, d0);
|
||||
break;
|
||||
|
||||
@@ -156,80 +166,82 @@ uintptr_t dynarecF20F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("ADDSD Gx, Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
GETEX(d0);
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
GETEX(d0, 0);
|
||||
VADD_F64(v0, v0, d0);
|
||||
break;
|
||||
case 0x59:
|
||||
INST_NAME("MULSD Gx, Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
GETEX(d0);
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
GETEX(d0, 0);
|
||||
VMUL_F64(v0, v0, d0);
|
||||
break;
|
||||
case 0x5A:
|
||||
INST_NAME("CVTSD2SS Gx, Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
GETEX(d0);
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
VCVT_F32_F64(s0, d0);
|
||||
VMOV_64(d1, v0);
|
||||
VMOV_32(d1*2, s0);
|
||||
VMOV_64(v0, d1);
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
GETEX(d0, 0);
|
||||
if(v0<16) {
|
||||
VCVT_F32_F64(v0*2, d0);
|
||||
} else {
|
||||
d1 = fpu_get_scratch_double(dyn);
|
||||
VMOV_64(d1, v0);
|
||||
VCVT_F32_F64(d1*2, d0);
|
||||
VMOV_64(v0, d1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x5C:
|
||||
INST_NAME("SUBSD Gx, Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
GETEX(d0);
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
GETEX(d0, 0);
|
||||
VSUB_F64(v0, v0, d0);
|
||||
break;
|
||||
case 0x5D:
|
||||
INST_NAME("MINSD Gx, Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
GETEX(d0);
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
GETEX(d0, 0);
|
||||
// MINSD: if any input is NaN, or Ex[0]<Gx[0], copy Ex[0] -> Gx[0]
|
||||
VCMP_F64(v0, d0);
|
||||
VMRS_APSR();
|
||||
VMOVcond_64(cPL, v0, d0);
|
||||
VMOVcond_64(cCS, v0, d0); // move v0 <- d0 if v0 or d0 unordered or v0 >= d0
|
||||
break;
|
||||
case 0x5E:
|
||||
INST_NAME("DIVSD Gx, Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
GETEX(d0);
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
GETEX(d0, 0);
|
||||
VDIV_F64(v0, v0, d0);
|
||||
break;
|
||||
case 0x5F:
|
||||
INST_NAME("MAXSD Gx, Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
GETEX(d0);
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
GETEX(d0, 0);
|
||||
// MAXSD: if any input is NaN, or Ex[0]>Gx[0], copy Ex[0] -> Gx[0]
|
||||
VCMP_F64(d0, v0);
|
||||
VMRS_APSR();
|
||||
VMOVcond_64(cPL, v0, d0);
|
||||
VMOVcond_64(cCS, v0, d0); // move v0 <- d0 if v0 or d0 is unordered or d0 >= v0
|
||||
break;
|
||||
|
||||
case 0x70:
|
||||
INST_NAME("PSHUFLW Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7);
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
v1 = fpu_get_scratch_quad(dyn);
|
||||
VLD1Q_64(v1, ed);
|
||||
}
|
||||
@@ -256,31 +268,70 @@ 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, 1);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
v1 = fpu_get_scratch_quad(dyn);
|
||||
VLD1Q_64(v1, ed);
|
||||
}
|
||||
VPADD_F32(v0, v0, v0+1);
|
||||
if(v0==v1) {
|
||||
VMOVD(v0+1, v0);
|
||||
} else {
|
||||
VPADD_F32(v0+1, v1, v1+1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xC2:
|
||||
INST_NAME("CMPSD Gx, Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
GETEX(d0);
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
GETEX(d0, 0);
|
||||
u8 = F8;
|
||||
VCMP_F64(v0, d0);
|
||||
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
|
||||
case 5: MVN_COND_REG_LSL_IMM5(cCS, x2, x2, 0); break; // Greater or equal or unordered
|
||||
case 6: MVN_COND_REG_LSL_IMM5(cHI, x2, x2, 0); break; // Greater or unordered, test inverted, N!=V so unordereded or less than (inverted)
|
||||
case 7: MVN_COND_REG_LSL_IMM5(cVC, x2, x2, 0); break; // not NaN
|
||||
}
|
||||
VMOVtoV_D(v0, x2, x2);
|
||||
break;
|
||||
|
||||
case 0xF0:
|
||||
INST_NAME("LDDQ Gx,Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VMOVQ(v0, v1);
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-12, 0, 0);
|
||||
LDR_IMM9(x2, ed, fixedaddress+0);
|
||||
LDR_IMM9(x3, ed, fixedaddress+4);
|
||||
VMOVtoV_D(v0, x2, x3);
|
||||
LDR_IMM9(x2, ed, fixedaddress+8);
|
||||
LDR_IMM9(x3, ed, fixedaddress+12);
|
||||
VMOVtoV_D(v0+1, x2, x3);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
*ok = 0;
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
|
||||
+326
-176
@@ -23,9 +23,9 @@
|
||||
#include "dynarec_arm_helper.h"
|
||||
|
||||
// Get Ex as a single, not a quad, with b a intermediary double
|
||||
#define GETEX(a, b) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
b = sse_get_reg(dyn, ninst, x1, nextop&7); \
|
||||
#define GETEX(a, b) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
b = sse_get_reg(dyn, ninst, x1, nextop&7,0);\
|
||||
if(b<16) \
|
||||
a = b; \
|
||||
else { \
|
||||
@@ -34,27 +34,43 @@
|
||||
} \
|
||||
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, 0); \
|
||||
VLDR_32(a, ed, fixedaddress); \
|
||||
} else { \
|
||||
GETED; \
|
||||
VMOVtoV(a, ed); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define GETGX(a, w) \
|
||||
gd = (nextop&0x38)>>3; \
|
||||
a = sse_get_reg(dyn, ninst, x1, gd, w)
|
||||
|
||||
|
||||
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 j32;
|
||||
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 parity;
|
||||
|
||||
MAYUSE(q1);
|
||||
MAYUSE(s1);
|
||||
MAYUSE(s2);
|
||||
MAYUSE(j32);
|
||||
|
||||
switch(opcode) {
|
||||
|
||||
case 0x10:
|
||||
@@ -62,8 +78,8 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
q0 = sse_get_reg(dyn, ninst, x1, nextop&7);
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
q0 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
if(v0<16)
|
||||
d0 = v0;
|
||||
else {
|
||||
@@ -82,7 +98,7 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
}
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0);
|
||||
LDR_IMM9(x2, ed, fixedaddress); // to avoid bus errors
|
||||
VEORQ(v0, v0, v0);
|
||||
VMOVtoDx_32(v0, 0, x2);
|
||||
@@ -92,9 +108,9 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("MOVSS Ex, Gx");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
q0 = sse_get_reg(dyn, ninst, x1, nextop&7);
|
||||
q0 = sse_get_reg(dyn, ninst, x1, nextop&7, 1);
|
||||
if(v0<16)
|
||||
d0 = v0;
|
||||
else {
|
||||
@@ -113,16 +129,59 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
}
|
||||
} else {
|
||||
VMOVfrDx_32(x2, v0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0);
|
||||
STR_IMM9(x2, ed, fixedaddress);
|
||||
}
|
||||
break;
|
||||
case 0x12:
|
||||
INST_NAME("MOVSLDUP Gx, Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
q1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
q1 = fpu_get_scratch_quad(dyn);
|
||||
VLD1Q_64(q1, ed);
|
||||
}
|
||||
q0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VDUP_32(q0+0, q1+0, 0);
|
||||
VDUP_32(q0+1, q1+1, 0);
|
||||
break;
|
||||
|
||||
case 0x16:
|
||||
INST_NAME("MOVSHDUP Gx, Ex");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
q1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
q1 = fpu_get_scratch_quad(dyn);
|
||||
VLD1Q_64(q1, ed);
|
||||
}
|
||||
q0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VDUP_32(q0+0, q1+0, 1);
|
||||
VDUP_32(q0+1, q1+1, 1);
|
||||
break;
|
||||
|
||||
|
||||
case 0x1E:
|
||||
INST_NAME("NOP / ENDBR32 / ENDBR64");
|
||||
nextop = F8;
|
||||
FAKEED;
|
||||
break;
|
||||
case 0x1F:
|
||||
INST_NAME("REP NOP");
|
||||
nextop = F8;
|
||||
FAKEED;
|
||||
break;
|
||||
|
||||
case 0x2A:
|
||||
INST_NAME("CVTSI2SS Gx, Ed");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
GETED;
|
||||
if(v0<16)
|
||||
d0 = v0;
|
||||
@@ -144,7 +203,7 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
GETGD;
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
v0 = sse_get_reg(dyn, ninst, x1, nextop&7);
|
||||
v0 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
if(v0<16)
|
||||
d0 = v0;
|
||||
else {
|
||||
@@ -153,20 +212,27 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
}
|
||||
VMOV_32(s0, d0*2);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 3);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0);
|
||||
LDR_IMM9(x2, ed, fixedaddress);
|
||||
VMOVtoV(s0, x2);
|
||||
}
|
||||
}
|
||||
VCVT_S32_F32(s0, s0);
|
||||
VMOVfrV(gd, s0);
|
||||
break;
|
||||
case 0x2D:
|
||||
INST_NAME("CVTSS2SI Gd, Ex");
|
||||
u8 = x87_setround(dyn, ninst, x1, x2, x12);
|
||||
u8 = sse_setround(dyn, ninst, x1, x2, x14);
|
||||
nextop = F8;
|
||||
GETGD;
|
||||
s0 = fpu_get_scratch_single(dyn);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
v0 = sse_get_reg(dyn, ninst, x1, nextop&7);
|
||||
v0 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
if(v0<16)
|
||||
d0 = v0;
|
||||
else {
|
||||
@@ -175,8 +241,15 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
}
|
||||
VMOV_32(s0, d0*2);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 3);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0);
|
||||
VLDR_32(s0, ed, fixedaddress);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095, 0, 0);
|
||||
LDR_IMM9(x2, ed, fixedaddress);
|
||||
VMOVtoV(s0, x2);
|
||||
}
|
||||
}
|
||||
VCVTR_S32_F32(s0, s0);
|
||||
VMOVfrV(gd, s0);
|
||||
@@ -186,104 +259,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, 1);
|
||||
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, 1);
|
||||
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, 1);
|
||||
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, 1);
|
||||
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, 1);
|
||||
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, 1);
|
||||
GETEX(s0, d0);
|
||||
VCVT_F64_F32(v0, s0);
|
||||
break;
|
||||
@@ -291,9 +378,9 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("CVTTPS2DQ Gx, Ex");
|
||||
nextop = F8;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7);
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
v1 = fpu_get_scratch_quad(dyn);
|
||||
VLD1Q_64(v1, ed);
|
||||
}
|
||||
@@ -304,75 +391,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, 1);
|
||||
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, 1);
|
||||
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(cCS, s0, s1); // move s0 <- s1 if s0 or s1 unordered or 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, 1);
|
||||
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, 1);
|
||||
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(cCS, s0, s1); // move s0 <- s1 if s0 or s1 is unordered or s1 >= s0
|
||||
if(v0!=d0) {
|
||||
VMOV_64(v0, d0);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -381,12 +480,12 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7);
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VMOVQ(v0, v1);
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-12, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-12, 0, 0);
|
||||
LDR_IMM9(x2, ed, fixedaddress+0);
|
||||
LDR_IMM9(x3, ed, fixedaddress+4);
|
||||
VMOVtoV_D(v0, x2, x3);
|
||||
@@ -399,16 +498,16 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("PSHUFHW Gx, Ex, Ib");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 1);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7);
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
v1 = fpu_get_scratch_quad(dyn);
|
||||
VLD1Q_64(v1, ed);
|
||||
}
|
||||
u8 = F8;
|
||||
// only high part need to be suffled. VTBL only handle 8bits value, so the 16bits suffles need to be changed in 8bits
|
||||
// only high part need to be shuffled. VTBL only handle 8bits value, so the 16bits shuffles need to be changed in 8bits
|
||||
u32 = 0;
|
||||
for (int i=0; i<2; ++i) {
|
||||
u32 |= (((u8>>(i*2))&3)*2+0)<<(i*16+0);
|
||||
@@ -435,12 +534,12 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7);
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
VMOVD(v0, v1);
|
||||
} else {
|
||||
v0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 0, 0, 0);
|
||||
VLD1_64(v0, ed);
|
||||
}
|
||||
VEOR(v0+1, v0+1, v0+1);
|
||||
@@ -449,13 +548,12 @@ uintptr_t dynarecF30F(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nins
|
||||
INST_NAME("MOVDQU Ex,Gx");
|
||||
nextop = F8;
|
||||
gd = (nextop&0x38)>>3;
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd, 0);
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
v1 = sse_get_reg_empty(dyn, ninst, x1, nextop&7);
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
VMOVQ(v1, v0);
|
||||
} else {
|
||||
v0 = sse_get_reg(dyn, ninst, x1, gd);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-12, 0);
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-12, 0, 0);
|
||||
VMOVfrV_D(x2, x3, v0);
|
||||
STR_IMM9(x2, ed, fixedaddress+0);
|
||||
STR_IMM9(x3, ed, fixedaddress+4);
|
||||
@@ -465,37 +563,89 @@ 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_SUBSET);
|
||||
SET_DFNONE(x3);
|
||||
nextop = F8;
|
||||
GETED;
|
||||
GETGD;
|
||||
TSTS_REG_LSL_IMM5(ed, ed, 0);
|
||||
MOVW_COND(cEQ, x3, 1);
|
||||
MOVW_COND(cNE, x3, 0);
|
||||
BFI(xFlags, x3, F_CF, 1); // CF = is source 0?
|
||||
RBIT(x3, ed); // reverse
|
||||
CLZ(gd, x3); // x2 gets leading 0 == TZCNT
|
||||
TSTS_REG_LSL_IMM5(gd, gd, 0);
|
||||
MOVW_COND(cEQ, x3, 1);
|
||||
MOVW_COND(cNE, x3, 0);
|
||||
BFI(xFlags, x3, F_ZF, 1); // ZF = is dest 0?
|
||||
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, 1);
|
||||
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;
|
||||
u8 = F8;
|
||||
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
|
||||
case 5: MVN_COND_REG_LSL_IMM5(cCS, 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;
|
||||
|
||||
case 0xE6:
|
||||
INST_NAME("CVTDQ2PD Gx, Ex");
|
||||
nextop = F8;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
v1 = sse_get_reg(dyn, ninst, x1, nextop&7, 0);
|
||||
if(v1<16)
|
||||
v0 = v1;
|
||||
else {
|
||||
v0 = fpu_get_scratch_double(dyn);
|
||||
VMOV_64(v0, v1); // vfpu opcode here
|
||||
}
|
||||
} else {
|
||||
v0 = fpu_get_scratch_double(dyn);
|
||||
parity = getedparity(dyn, ninst, addr, nextop, 3);
|
||||
if(parity) {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 1023, 3, 0);
|
||||
VLDR_64(v0, ed, fixedaddress); // vfpu opcode here
|
||||
} else {
|
||||
addr = geted(dyn, addr, ninst, nextop, &ed, x1, &fixedaddress, 4095-8, 0, 0);
|
||||
LDR_IMM9(x2, ed, fixedaddress);
|
||||
LDR_IMM9(x3, ed, fixedaddress+4);
|
||||
VMOVtoV_D(v0, x2, x3);
|
||||
}
|
||||
}
|
||||
gd = (nextop&0x38)>>3;
|
||||
q0 = sse_get_reg_empty(dyn, ninst, x1, gd);
|
||||
//v0 is a low reg now
|
||||
VCVT_F64_S32(q0+1, v0*2+1);
|
||||
VCVT_F64_S32(q0+0, v0*2+0);
|
||||
break;
|
||||
|
||||
default:
|
||||
*ok = 0;
|
||||
DEFAULT;
|
||||
}
|
||||
return addr;
|
||||
|
||||
+338
-130
@@ -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"
|
||||
@@ -18,20 +21,15 @@
|
||||
#include "emu/x86run_private.h"
|
||||
#include "emu/x87emu_private.h"
|
||||
#include "x86trace.h"
|
||||
#include "signals.h"
|
||||
#include "dynarec_arm.h"
|
||||
#include "dynarec_arm_private.h"
|
||||
#include "dynarec_arm_functions.h"
|
||||
|
||||
void arm_popf(x86emu_t* emu, uint32_t f)
|
||||
{
|
||||
emu->packed_eflags.x32 = (f & 0x3F7FD7) | 0x2; // mask off res2 and res3 and on res1
|
||||
UnpackFlags(emu);
|
||||
RESET_FLAGS(emu);
|
||||
}
|
||||
#include "bridge.h"
|
||||
|
||||
void arm_fstp(x86emu_t* emu, void* p)
|
||||
{
|
||||
if(ST0.ll!=STld(0).ref)
|
||||
if(ST0.q!=STld(0).uref)
|
||||
D2LD(&ST0.d, p);
|
||||
else
|
||||
memcpy(p, &STld(0).ld, 10);
|
||||
@@ -53,6 +51,7 @@ void arm_fyl2x(x86emu_t* emu)
|
||||
void arm_ftan(x86emu_t* emu)
|
||||
{
|
||||
ST0.d = tan(ST0.d);
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
}
|
||||
void arm_fpatan(x86emu_t* emu)
|
||||
{
|
||||
@@ -60,7 +59,7 @@ void arm_fpatan(x86emu_t* emu)
|
||||
}
|
||||
void arm_fxtract(x86emu_t* emu)
|
||||
{
|
||||
int32_t tmp32s = (ST1.ll&0x7ff0000000000000LL)>>52;
|
||||
int32_t tmp32s = (ST1.q&0x7ff0000000000000LL)>>52;
|
||||
tmp32s -= 1023;
|
||||
ST1.d /= exp2(tmp32s);
|
||||
ST0.d = tmp32s;
|
||||
@@ -74,31 +73,15 @@ void arm_fprem(x86emu_t* emu)
|
||||
emu->sw.f.F87_C3 = ((tmp32s>>1)&1);
|
||||
emu->sw.f.F87_C1 = ((tmp32s>>2)&1);
|
||||
}
|
||||
void arm_fyl2xp1(x86emu_t* emu)
|
||||
{
|
||||
ST(1).d = log2(ST0.d + 1.0)*ST(1).d;
|
||||
}
|
||||
void arm_fsincos(x86emu_t* emu)
|
||||
{
|
||||
sincos(ST1.d, &ST1.d, &ST0.d);
|
||||
}
|
||||
void arm_frndint(x86emu_t* emu)
|
||||
{
|
||||
ST0.d = fpu_round(emu, ST0.d);
|
||||
}
|
||||
void arm_fscale(x86emu_t* emu)
|
||||
{
|
||||
ST0.d *= exp2(trunc(ST1.d));
|
||||
if(ST0.d!=0.0)
|
||||
ST0.d *= exp2(trunc(ST1.d));
|
||||
}
|
||||
void arm_fsin(x86emu_t* emu)
|
||||
{
|
||||
ST0.d = sin(ST0.d);
|
||||
}
|
||||
void arm_fcos(x86emu_t* emu)
|
||||
{
|
||||
ST0.d = cos(ST0.d);
|
||||
}
|
||||
|
||||
void arm_fbld(x86emu_t* emu, uint8_t* ed)
|
||||
{
|
||||
fpu_fbld(emu, ed);
|
||||
@@ -106,9 +89,11 @@ void arm_fbld(x86emu_t* emu, uint8_t* ed)
|
||||
|
||||
void arm_fild64(x86emu_t* emu, int64_t* ed)
|
||||
{
|
||||
ST0.d = *ed;
|
||||
STll(0).ll = *ed;
|
||||
STll(0).ref = ST0.ll;
|
||||
int64_t tmp;
|
||||
memcpy(&tmp, ed, sizeof(tmp));
|
||||
ST0.d = tmp;
|
||||
STll(0).sq = tmp;
|
||||
STll(0).sref = ST0.sq;
|
||||
}
|
||||
|
||||
void arm_fbstp(x86emu_t* emu, uint8_t* ed)
|
||||
@@ -118,114 +103,74 @@ void arm_fbstp(x86emu_t* emu, uint8_t* ed)
|
||||
|
||||
void arm_fistp64(x86emu_t* emu, int64_t* ed)
|
||||
{
|
||||
if(STll(0).ref==ST(0).ll) {
|
||||
*ed = STll(0).ll;
|
||||
// used of memcpy to avoid aligments issues
|
||||
if(STll(0).sref==ST(0).sq) {
|
||||
memcpy(ed, &STll(0).sq, sizeof(int64_t));
|
||||
} else {
|
||||
if(isgreater(ST0.d, (double)(int64_t)0x7fffffffffffffffLL) || isless(ST0.d, (double)(int64_t)0x8000000000000000LL))
|
||||
*ed = 0x8000000000000000LL;
|
||||
int64_t tmp;
|
||||
if(isgreater(ST0.d, (double)(int64_t)0x7fffffffffffffffLL) || isless(ST0.d, (double)(int64_t)0x8000000000000000LL) || !isfinite(ST0.d))
|
||||
tmp = 0x8000000000000000LL;
|
||||
else
|
||||
*ed = (int64_t)ST0.d;
|
||||
tmp = fpu_round(emu, ST0.d);
|
||||
memcpy(ed, &tmp, sizeof(tmp));
|
||||
}
|
||||
}
|
||||
|
||||
void arm_fistt64(x86emu_t* emu, int64_t* ed)
|
||||
{
|
||||
// used of memcpy to avoid aligments issues
|
||||
int64_t tmp = ST0.d;
|
||||
memcpy(ed, &tmp, sizeof(tmp));
|
||||
}
|
||||
|
||||
void arm_fld(x86emu_t* emu, uint8_t* ed)
|
||||
{
|
||||
memcpy(&STld(0).ld, ed, 10);
|
||||
LD2D(&STld(0), &ST(0).d);
|
||||
STld(0).ref = ST0.ll;
|
||||
STld(0).uref = ST0.q;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
emit_signal(emu, SIGILL, (void*)R_EIP, 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) {
|
||||
LD2D(p, &ST(i).d);
|
||||
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) {
|
||||
D2LD(&ST(i).d, p);
|
||||
p+=10;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void arm_fprem1(x86emu_t* emu)
|
||||
{
|
||||
// simplified version
|
||||
int32_t tmp32s = round(ST0.d / ST1.d);
|
||||
ST0.d -= ST1.d*tmp32s;
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
emu->sw.f.F87_C0 = (tmp32s&1);
|
||||
emu->sw.f.F87_C3 = ((tmp32s>>1)&1);
|
||||
emu->sw.f.F87_C1 = ((tmp32s>>2)&1);
|
||||
}
|
||||
|
||||
|
||||
// Get a FPU single scratch reg
|
||||
int fpu_get_scratch_single(dynarec_arm_t* dyn)
|
||||
{
|
||||
@@ -241,23 +186,35 @@ int fpu_get_scratch_double(dynarec_arm_t* dyn)
|
||||
// Get a FPU quad scratch reg
|
||||
int fpu_get_scratch_quad(dynarec_arm_t* dyn)
|
||||
{
|
||||
if(dyn->fpu_scratch>4) {
|
||||
if(dyn->fpu_extra_qscratch) {
|
||||
dynarec_log(LOG_NONE, "Warning, Extra QScratch slot taken and need another one!\n");
|
||||
} else
|
||||
dyn->fpu_extra_qscratch = fpu_get_reg_quad(dyn, NEON_CACHE_SCR, 0);
|
||||
return dyn->fpu_extra_qscratch;
|
||||
}
|
||||
int i = (dyn->fpu_scratch+3)&(~3);
|
||||
dyn->fpu_scratch = i+4;
|
||||
return i/2; // Return a Dx, not a Qx
|
||||
}
|
||||
// Reset scratch regs counter
|
||||
int fpu_reset_scratch(dynarec_arm_t* dyn)
|
||||
void fpu_reset_scratch(dynarec_arm_t* dyn)
|
||||
{
|
||||
dyn->fpu_scratch = 0;
|
||||
if(dyn->fpu_extra_qscratch) {
|
||||
fpu_free_reg_quad(dyn, dyn->fpu_extra_qscratch);
|
||||
dyn->fpu_extra_qscratch = 0;
|
||||
}
|
||||
}
|
||||
#define FPUFIRST 8
|
||||
// Get a FPU double reg
|
||||
int fpu_get_reg_double(dynarec_arm_t* dyn)
|
||||
int fpu_get_reg_double(dynarec_arm_t* dyn, unsigned int t, unsigned int n)
|
||||
{
|
||||
// TODO: check upper limit?
|
||||
int i=0;
|
||||
while (dyn->fpuused[i]) ++i;
|
||||
dyn->fpuused[i] = 1;
|
||||
dyn->n.neoncache[i].n = n;
|
||||
dyn->n.neoncache[i].t = t;
|
||||
return i+FPUFIRST; // return a Dx
|
||||
}
|
||||
// Free a FPU double reg
|
||||
@@ -266,13 +223,19 @@ void fpu_free_reg_double(dynarec_arm_t* dyn, int reg)
|
||||
// TODO: check upper limit?
|
||||
int i=reg-FPUFIRST;
|
||||
dyn->fpuused[i] = 0;
|
||||
if(dyn->n.neoncache[i].t!=NEON_CACHE_ST_F && dyn->n.neoncache[i].t!=NEON_CACHE_ST_D)
|
||||
dyn->n.neoncache[i].v = 0;
|
||||
}
|
||||
// Get a FPU quad reg
|
||||
int fpu_get_reg_quad(dynarec_arm_t* dyn)
|
||||
int fpu_get_reg_quad(dynarec_arm_t* dyn, unsigned int t, unsigned int n)
|
||||
{
|
||||
int i=0;
|
||||
while (dyn->fpuused[i] || dyn->fpuused[i+1]) i+=2;
|
||||
dyn->fpuused[i] = dyn->fpuused[i+1] = 1;
|
||||
dyn->n.neoncache[i].t = t;
|
||||
dyn->n.neoncache[i].n = n;
|
||||
dyn->n.neoncache[i+1].t = t;
|
||||
dyn->n.neoncache[i+1].n = n;
|
||||
return i+FPUFIRST; // Return a Dx, not a Qx
|
||||
}
|
||||
// Free a FPU quad reg
|
||||
@@ -280,11 +243,256 @@ void fpu_free_reg_quad(dynarec_arm_t* dyn, int reg)
|
||||
{
|
||||
int i=reg-FPUFIRST;
|
||||
dyn->fpuused[i] = dyn->fpuused[i+1] = 0;
|
||||
dyn->n.neoncache[i].v = 0;
|
||||
dyn->n.neoncache[i+1].v = 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)
|
||||
for (int i=0; i<24; ++i) {
|
||||
dyn->fpuused[i]=0;
|
||||
dyn->n.neoncache[i].v = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int neoncache_get_st(dynarec_arm_t* dyn, int ninst, int a)
|
||||
{
|
||||
if(!dyn->insts)
|
||||
return NEON_CACHE_ST_D;
|
||||
for(int i=0; i<24; ++i)
|
||||
if((dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_ST_F
|
||||
|| dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_ST_D)
|
||||
&& dyn->insts[ninst].n.neoncache[i].n==a)
|
||||
return dyn->insts[ninst].n.neoncache[i].t;
|
||||
// not in the cache yet, so will be fetched...
|
||||
return NEON_CACHE_ST_D;
|
||||
}
|
||||
|
||||
int neoncache_get_current_st(dynarec_arm_t* dyn, int ninst, int a)
|
||||
{
|
||||
(void)ninst;
|
||||
if(!dyn->insts)
|
||||
return NEON_CACHE_ST_D;
|
||||
for(int i=0; i<24; ++i)
|
||||
if((dyn->n.neoncache[i].t==NEON_CACHE_ST_F
|
||||
|| dyn->n.neoncache[i].t==NEON_CACHE_ST_D)
|
||||
&& dyn->n.neoncache[i].n==a)
|
||||
return dyn->n.neoncache[i].t;
|
||||
// not in the cache yet, so will be fetched...
|
||||
return NEON_CACHE_ST_D;
|
||||
}
|
||||
|
||||
int neoncache_get_st_f(dynarec_arm_t* dyn, int ninst, int a, int st)
|
||||
{
|
||||
if(a+dyn->insts[ninst].n.stack_next-st<0)
|
||||
// The STx has been pushed at the end of instructon, so stop going back
|
||||
return -1;
|
||||
for(int i=0; i<24; ++i)
|
||||
if(dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_ST_F
|
||||
&& dyn->insts[ninst].n.neoncache[i].n==a+dyn->insts[ninst].n.stack-st)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
int neoncache_get_st_f_noback(dynarec_arm_t* dyn, int ninst, int a, int st)
|
||||
{
|
||||
for(int i=0; i<24; ++i)
|
||||
if(dyn->insts[ninst].n.neoncache[i].t==NEON_CACHE_ST_F
|
||||
&& dyn->insts[ninst].n.neoncache[i].n==a+dyn->insts[ninst].n.stack-st)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
int neoncache_get_current_st_f(dynarec_arm_t* dyn, int a, int st)
|
||||
{
|
||||
for(int i=0; i<24; ++i)
|
||||
if(dyn->n.neoncache[i].t==NEON_CACHE_ST_F
|
||||
&& dyn->n.neoncache[i].n==a+dyn->n.stack-st)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
static void neoncache_promote_double_forward(dynarec_arm_t* dyn, int ninst, int maxinst, int a, int st);
|
||||
static void neoncache_promote_double_internal(dynarec_arm_t* dyn, int ninst, int maxinst, int a, int st);
|
||||
static void neoncache_promote_double_combined(dynarec_arm_t* dyn, int ninst, int maxinst, int a, int st)
|
||||
{
|
||||
if(a == dyn->insts[ninst].n.combined1) {
|
||||
int i = neoncache_get_st_f_noback(dyn, ninst, dyn->insts[ninst].n.combined2, st);
|
||||
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_internal, ninst=%d combined2 %d i=%d\n", ninst, dyn->insts[ninst].n.combined2 ,i);
|
||||
if(i>=0) {
|
||||
dyn->insts[ninst].n.neoncache[i].t = NEON_CACHE_ST_D;
|
||||
neoncache_promote_double_internal(dyn, ninst-1, maxinst, dyn->insts[ninst].n.combined2, st);
|
||||
// go forward is combined is not pop'd
|
||||
if(dyn->insts[ninst].n.stack_next-dyn->insts[ninst].n.stack<=dyn->insts[ninst].n.combined2)
|
||||
neoncache_promote_double_forward(dyn, ninst+1, maxinst, dyn->insts[ninst].n.combined2, st);
|
||||
}
|
||||
} else if(a == dyn->insts[ninst].n.combined2) {
|
||||
int i = neoncache_get_st_f_noback(dyn, ninst, dyn->insts[ninst].n.combined1, st);
|
||||
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_internal, ninst=%d combined1 %d i=%d\n", ninst, dyn->insts[ninst].n.combined1 ,i);
|
||||
if(i>=0) {
|
||||
dyn->insts[ninst].n.neoncache[i].t = NEON_CACHE_ST_D;
|
||||
neoncache_promote_double_internal(dyn, ninst-1, maxinst, dyn->insts[ninst].n.combined1, st);
|
||||
// go forward is combined is not pop'd
|
||||
if(dyn->insts[ninst].n.stack_next-dyn->insts[ninst].n.stack<=dyn->insts[ninst].n.combined1)
|
||||
neoncache_promote_double_forward(dyn, ninst+1, maxinst, dyn->insts[ninst].n.combined1, st);
|
||||
}
|
||||
}
|
||||
}
|
||||
static void neoncache_promote_double_internal(dynarec_arm_t* dyn, int ninst, int maxinst, int a, int st)
|
||||
{
|
||||
while(ninst>=0) {
|
||||
int i = neoncache_get_st_f(dyn, ninst, a, st);
|
||||
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_internal, ninst=%d, a=%d st=%d:%d/%d, i=%d\n", ninst, a, st, dyn->insts[ninst].n.stack, dyn->insts[ninst].n.stack_next, i);
|
||||
if(i<0) return;
|
||||
dyn->insts[ninst].n.neoncache[i].t = NEON_CACHE_ST_D;
|
||||
a+=dyn->insts[ninst].n.stack-st; // adjust STx
|
||||
st = dyn->insts[ninst].n.stack; // new stack depth
|
||||
// check combined propagation too
|
||||
if(dyn->insts[ninst].n.combined1 || dyn->insts[ninst].n.combined2) {
|
||||
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_internal, ninst=%d combined %d/%d vs %d with st %d/%d\n", ninst, dyn->insts[ninst].n.combined1 ,dyn->insts[ninst].n.combined2, a, st, dyn->insts[ninst].n.stack);
|
||||
neoncache_promote_double_combined(dyn, ninst, maxinst, a, st);
|
||||
}
|
||||
--ninst;
|
||||
}
|
||||
}
|
||||
|
||||
static void neoncache_promote_double_forward(dynarec_arm_t* dyn, int ninst, int maxinst, int a, int st)
|
||||
{
|
||||
while(ninst<maxinst) {
|
||||
int i = neoncache_get_st_f_noback(dyn, ninst, a, st);
|
||||
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_forward, ninst=%d, a=%d st=%d:%d/%d, i=%d\n", ninst, a, st, dyn->insts[ninst].n.stack, dyn->insts[ninst].n.stack_next, i);
|
||||
if(i<0) return;
|
||||
dyn->insts[ninst].n.neoncache[i].t = NEON_CACHE_ST_D;
|
||||
a+=dyn->insts[ninst].n.stack-st; // adjust STx
|
||||
st = dyn->insts[ninst].n.stack; // new stack depth
|
||||
// check combined propagation too
|
||||
if(dyn->insts[ninst].n.combined1 || dyn->insts[ninst].n.combined2) {
|
||||
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double_forward, ninst=%d combined %d/%d vs %d with st %d/%d\n", ninst, dyn->insts[ninst].n.combined1 ,dyn->insts[ninst].n.combined2, a, st, dyn->insts[ninst].n.stack);
|
||||
neoncache_promote_double_combined(dyn, ninst, maxinst, a, st);
|
||||
}
|
||||
++ninst;
|
||||
}
|
||||
neoncache_promote_double(dyn, ninst, a, st);
|
||||
}
|
||||
|
||||
void neoncache_promote_double(dynarec_arm_t* dyn, int ninst, int a, int st)
|
||||
{
|
||||
int i = neoncache_get_current_st_f(dyn, a, st);
|
||||
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double, ninst=%d a=%d st=%d/%d i=%d\n", ninst, a, st, dyn->n.stack, i);
|
||||
if(i<0) return;
|
||||
dyn->n.neoncache[i].t = NEON_CACHE_ST_D;
|
||||
a+=dyn->n.stack-st;
|
||||
st = dyn->n.stack;
|
||||
// check combined propagation too
|
||||
if(dyn->n.combined1 || dyn->n.combined2) {
|
||||
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "neoncache_promote_double, ninst=%d combined! %d/%d vs %d\n", ninst, dyn->n.combined1 ,dyn->n.combined2, a);
|
||||
if(dyn->n.combined1 == a)
|
||||
neoncache_promote_double(dyn, ninst, dyn->n.combined2, st);
|
||||
else if(dyn->n.combined2 == a)
|
||||
neoncache_promote_double(dyn, ninst, dyn->n.combined1, st);
|
||||
}
|
||||
if(!ninst) return;
|
||||
neoncache_promote_double_internal(dyn, ninst-1, ninst, a, st);
|
||||
}
|
||||
|
||||
int neoncache_combine_st(dynarec_arm_t* dyn, int ninst, int a, int b)
|
||||
{
|
||||
dyn->n.combined1=a;
|
||||
dyn->n.combined2=b;
|
||||
if( neoncache_get_current_st(dyn, ninst, a)==NEON_CACHE_ST_F
|
||||
&& neoncache_get_current_st(dyn, ninst, b)==NEON_CACHE_ST_F )
|
||||
return NEON_CACHE_ST_F;
|
||||
return NEON_CACHE_ST_D;
|
||||
}
|
||||
|
||||
#define F8 *(uint8_t*)(addr++)
|
||||
#define F32 *(uint32_t*)(addr+=4, addr-4)
|
||||
// Get if ED will have the correct parity. Not emiting anything. Parity is 2 for DWORD or 3 for QWORD
|
||||
int getedparity(dynarec_arm_t* dyn, int ninst, uintptr_t addr, uint8_t nextop, int parity)
|
||||
{
|
||||
|
||||
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 && parity<3)
|
||||
return 0; // simple [reg]
|
||||
// don't try [reg1 + reg2<<N], unless reg1 is ESP
|
||||
return ((sib&0x7)==4 && (sib>>6)>=parity)?1:0;
|
||||
}
|
||||
} else if((nextop&7)==5) {
|
||||
uint32_t tmp = F32;
|
||||
return (tmp&tested)?0:1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
return 0; //Form [reg1 + reg2<<N + XXXXXX]
|
||||
}
|
||||
}
|
||||
|
||||
// Do the GETED, but don't emit anything...
|
||||
uintptr_t fakeed(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop)
|
||||
{
|
||||
if((nextop&0xC0)==0xC0)
|
||||
return addr;
|
||||
if(!(nextop&0xC0)) {
|
||||
if((nextop&7)==4) {
|
||||
uint8_t sib = F8;
|
||||
if((sib&0x7)==5) {
|
||||
addr+=4;
|
||||
}
|
||||
} else if((nextop&7)==5) {
|
||||
addr+=4;
|
||||
}
|
||||
} else {
|
||||
if((nextop&7)==4) {
|
||||
++addr;
|
||||
}
|
||||
if(nextop&0x80) {
|
||||
addr+=4;
|
||||
} else {
|
||||
++addr;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
#undef F8
|
||||
#undef F32
|
||||
|
||||
int isNativeCall(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t* calladdress, int* retn)
|
||||
{
|
||||
#define PK(a) *(uint8_t*)(addr+a)
|
||||
#define PK32(a) *(uint32_t*)(addr+a)
|
||||
|
||||
if(!addr)
|
||||
return 0;
|
||||
if(PK(0)==0xff && PK(1)==0x25) { // absolute jump, maybe the GOT
|
||||
uintptr_t a1 = (PK32(2)); // need to add a check to see if the address is from the GOT !
|
||||
addr = (uintptr_t)getAlternate(*(void**)a1);
|
||||
}
|
||||
if(addr<0x10000) // too low, that is suspicious
|
||||
return 0;
|
||||
onebridge_t *b = (onebridge_t*)(addr);
|
||||
if(b->CC==0xCC && b->S=='S' && b->C=='C' && b->w!=(wrapper_t)0 && b->f!=(uintptr_t)PltResolver) {
|
||||
// found !
|
||||
if(retn) *retn = (b->C3==0xC2)?b->N:0;
|
||||
if(calladdress) *calladdress = addr+1;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
#undef PK32
|
||||
#undef PK
|
||||
}
|
||||
|
||||
@@ -3,30 +3,29 @@
|
||||
|
||||
typedef struct x86emu_s x86emu_t;
|
||||
|
||||
void arm_popf(x86emu_t* emu, uint32_t f);
|
||||
void arm_fstp(x86emu_t* emu, void* p);
|
||||
|
||||
void arm_print_armreg(x86emu_t* emu, uintptr_t reg, uintptr_t n);
|
||||
|
||||
void arm_f2xm1(x86emu_t* emu);
|
||||
void arm_fyl2x(x86emu_t* emu);
|
||||
void arm_ftan(x86emu_t* emu);
|
||||
void arm_fpatan(x86emu_t* emu);
|
||||
void arm_fxtract(x86emu_t* emu);
|
||||
void arm_fprem(x86emu_t* emu);
|
||||
void arm_fyl2xp1(x86emu_t* emu);
|
||||
void arm_fsincos(x86emu_t* emu);
|
||||
void arm_frndint(x86emu_t* emu);
|
||||
void arm_fscale(x86emu_t* emu);
|
||||
void arm_fsin(x86emu_t* emu);
|
||||
void arm_fcos(x86emu_t* emu);
|
||||
void arm_fbld(x86emu_t* emu, uint8_t* ed);
|
||||
void arm_fild64(x86emu_t* emu, int64_t* ed);
|
||||
void arm_fbstp(x86emu_t* emu, uint8_t* ed);
|
||||
void arm_fbst(x86emu_t* emu, uint8_t* ed);
|
||||
void arm_fistp64(x86emu_t* emu, int64_t* ed);
|
||||
void arm_fistt64(x86emu_t* emu, int64_t* ed);
|
||||
void arm_fld(x86emu_t* emu, uint8_t* ed);
|
||||
void arm_fsave(x86emu_t* emu, uint8_t* ed);
|
||||
void arm_frstor(x86emu_t* emu, uint8_t* ed);
|
||||
void arm_fprem1(x86emu_t* emu);
|
||||
|
||||
void arm_cpuid(x86emu_t* emu, uint32_t tmp32u);
|
||||
void arm_ud(x86emu_t* emu);
|
||||
|
||||
#define FPUFIRST 8
|
||||
|
||||
// Get an FPU single scratch reg
|
||||
int fpu_get_scratch_single(dynarec_arm_t* dyn);
|
||||
@@ -35,16 +34,35 @@ 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);
|
||||
// Get an FPU double reg
|
||||
int fpu_get_reg_double(dynarec_arm_t* dyn);
|
||||
void fpu_reset_scratch(dynarec_arm_t* dyn);
|
||||
// Get an FPU double reg, with NEON_CACHE_TYPE
|
||||
int fpu_get_reg_double(dynarec_arm_t* dyn, unsigned int t, unsigned int n);
|
||||
// Free a FPU double reg
|
||||
void fpu_free_reg_double(dynarec_arm_t* dyn, int reg);
|
||||
// Get an FPU quad reg
|
||||
int fpu_get_reg_quad(dynarec_arm_t* dyn);
|
||||
int fpu_get_reg_quad(dynarec_arm_t* dyn, unsigned int t, unsigned int n);
|
||||
// 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);
|
||||
|
||||
// ---- Neon cache functions
|
||||
// Get type for STx
|
||||
int neoncache_get_st(dynarec_arm_t* dyn, int ninst, int a);
|
||||
// Get if STx is FLOAT or DOUBLE
|
||||
int neoncache_get_st_f(dynarec_arm_t* dyn, int ninst, int a, int st);
|
||||
// Get actual type for STx
|
||||
int neoncache_get_current_st(dynarec_arm_t* dyn, int ninst, int a);
|
||||
// Back-propagate a change float->double
|
||||
void neoncache_promote_double(dynarec_arm_t* dyn, int ninst, int a, int st);
|
||||
// Combine and propagate if needed (pass 1 only)
|
||||
int neoncache_combine_st(dynarec_arm_t* dyn, int ninst, int a, int b); // with stack current dyn->n_stack*
|
||||
// Get if ED will have the correct parity. Not emiting anything. Parity is 2 for DWORD or 3 for QWORD
|
||||
int getedparity(dynarec_arm_t* dyn, int ninst, uintptr_t addr, uint8_t nextop, int parity);
|
||||
// Do the GETED, but don't emit anything...
|
||||
uintptr_t fakeed(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop);
|
||||
|
||||
// Is what pointed at addr a native call? And if yes, to what function?
|
||||
int isNativeCall(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t* calladdress, int* retn);
|
||||
|
||||
#endif //__DYNAREC_ARM_FUNCTIONS_H__
|
||||
+665
-561
File diff suppressed because it is too large.
Load diff
+370
-105
@@ -22,9 +22,10 @@
|
||||
#define F32 *(uint32_t*)(addr+=4, addr-4)
|
||||
#define F32S *(int32_t*)(addr+=4, addr-4)
|
||||
#define PK(a) *(uint8_t*)(addr+a)
|
||||
#define PK32(a) *(uint32_t*)(addr+a)
|
||||
#define PK16(a) *(uint16_t*)(addr+a)
|
||||
#define PKip(a) *(uint8_t*)(ip+a)
|
||||
#define PK32(a) *(uint32_t*)(addr+a)
|
||||
#define PK16(a) *(uint16_t*)(addr+a)
|
||||
#define PKip(a) *(uint8_t*)(ip+a)
|
||||
#define PKa(a) *(uint8_t*)(a)
|
||||
|
||||
// GETGD get x86 register in gd
|
||||
#define GETGD gd = xEAX+((nextop&0x38)>>3)
|
||||
@@ -33,7 +34,7 @@
|
||||
ed = xEAX+(nextop&7); \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 4095, 0); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 4095, 0, 0); \
|
||||
LDR_IMM9(x1, wback, fixedaddress); \
|
||||
ed = x1; \
|
||||
}
|
||||
@@ -42,7 +43,7 @@
|
||||
ed = xEAX+(nextop&7); \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, (hint==x2)?x1:x2, &fixedaddress, 4095, 0); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, (hint==x2)?x1:x2, &fixedaddress, 4095, 0, 0); \
|
||||
LDR_IMM9(hint, wback, fixedaddress); \
|
||||
ed = hint; \
|
||||
}
|
||||
@@ -52,7 +53,7 @@
|
||||
MOV_REG(ret, ed); \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, hint, &fixedaddress, 4095, 0); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, hint, &fixedaddress, 4095, 0, 0); \
|
||||
ed = ret; \
|
||||
LDR_IMM9(ed, wback, fixedaddress); \
|
||||
}
|
||||
@@ -65,10 +66,20 @@
|
||||
ed = xEAX+(nextop&7); \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 0); \
|
||||
LDR_REG_LSL_IMM5(x1, wback, O, 0); \
|
||||
ed = x1; \
|
||||
}
|
||||
//GETEDO can use r1 for ed, and r2 for wback. wback is 0 if ed is xEAX..xEDI, else O is added to wback
|
||||
#define GETEDO2(O) if((nextop&0xC0)==0xC0) { \
|
||||
ed = xEAX+(nextop&7); \
|
||||
wback = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x2, &fixedaddress, 0, 0, 0); \
|
||||
ADD_REG_LSL_IMM5(wback, wback, O, 0);\
|
||||
LDR_IMM9(x1, wback, 0); \
|
||||
ed = x1; \
|
||||
}
|
||||
#define WBACKO(O) if(wback) {STR_REG_LSL_IMM5(ed, wback, O, 0);}
|
||||
//FAKEELike GETED, but doesn't get anything
|
||||
#define FAKEED if((nextop&0xC0)!=0xC0) { \
|
||||
@@ -83,7 +94,7 @@
|
||||
ed = i; \
|
||||
wb1 = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, w, &fixedaddress, 255, 0); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, w, &fixedaddress, 255, 0, 0); \
|
||||
LDRH_IMM8(i, wback, fixedaddress); \
|
||||
ed = i; \
|
||||
wb1 = 1; \
|
||||
@@ -95,7 +106,7 @@
|
||||
ed = i; \
|
||||
wb1 = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0); \
|
||||
LDRH_IMM8(i, wback, fixedaddress); \
|
||||
ed = i; \
|
||||
wb1 = 1; \
|
||||
@@ -107,7 +118,7 @@
|
||||
ed = i; \
|
||||
wb1 = 0; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0); \
|
||||
LDRSH_IMM8(i, wback, fixedaddress);\
|
||||
ed = i; \
|
||||
wb1 = 1; \
|
||||
@@ -127,11 +138,26 @@
|
||||
wb1 = 0; \
|
||||
ed = i; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 4095, 0); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 4095, 0, 0); \
|
||||
LDRB_IMM9(i, wback, fixedaddress); \
|
||||
wb1 = 1; \
|
||||
ed = i; \
|
||||
}
|
||||
//GETEBO will use i for ed, i is also Offset, and can use r3 for wback.
|
||||
#define GETEBO(i) if((nextop&0xC0)==0xC0) { \
|
||||
wback = (nextop&7); \
|
||||
wb2 = (wback>>2); \
|
||||
wback = xEAX+(wback&3); \
|
||||
UXTB(i, wback, wb2); \
|
||||
wb1 = 0; \
|
||||
ed = i; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 0, 0, 0); \
|
||||
ADD_REG_LSL_IMM5(wback, wback, i, 0); \
|
||||
LDRB_IMM9(i, wback, fixedaddress); \
|
||||
wb1 = 1; \
|
||||
ed = i; \
|
||||
}
|
||||
//GETSEB sign extend EB, will use i for ed, and can use r3 for wback.
|
||||
#define GETSEB(i) if((nextop&0xC0)==0xC0) { \
|
||||
wback = (nextop&7); \
|
||||
@@ -141,7 +167,7 @@
|
||||
wb1 = 0; \
|
||||
ed = i; \
|
||||
} else { \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0); \
|
||||
addr = geted(dyn, addr, ninst, nextop, &wback, x3, &fixedaddress, 255, 0, 0); \
|
||||
LDRSB_IMM8(i, wback, fixedaddress);\
|
||||
wb1 = 1; \
|
||||
ed = i; \
|
||||
@@ -164,16 +190,28 @@
|
||||
#define GBBACK BFI(gb1, gd, gb2*8, 8);
|
||||
|
||||
// Get Direction with size Z and based of F_DF flag, on register r ready for LDR/STR fetching
|
||||
// F_DF is 1<<10, so 1 ROR 11*2 (so F_OF)
|
||||
#define GETDIR(r, A) \
|
||||
LDR_IMM9(r, xEmu, offsetof(x86emu_t, flags[F_DF])); \
|
||||
CMPS_IMM8(r, 1); \
|
||||
MOVW(r, A); \
|
||||
RSB_COND_IMM8(cEQ, r, r, 0)
|
||||
TSTS_IMM8_ROR(xFlags, 1, 0x0b); \
|
||||
MOVW(r, A); \
|
||||
RSB_COND_IMM8(cNE, r, r, 0)
|
||||
|
||||
// CALL will use x12 for the call address. Return value can be put in ret (unless ret is -1)
|
||||
#define CALL(F, ret, M) call_c(dyn, ninst, F, x12, ret, M)
|
||||
// CALL will use x14 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, x14, ret, M, 1)
|
||||
// CALL_ will use x3 for the call address. Return value can be put in ret (unless ret is -1)
|
||||
#define CALL_(F, ret, M) call_c(dyn, ninst, F, x3, ret, M)
|
||||
// R0 will not be pushed/popd if ret is -2
|
||||
#define CALL_(F, ret, M) call_c(dyn, ninst, F, x3, ret, M, 1)
|
||||
// CALL_S 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. Flags are not save/restored
|
||||
#define CALL_S(F, ret, M) call_c(dyn, ninst, F, x3, ret, M, 0)
|
||||
// CALL_1D will use x3 for the call address. Return value in D0, 1 ARG in D0
|
||||
#define CALL_1D(F, M) call_d(dyn, ninst, F, NULL, 1, x3, -1, M, 0)
|
||||
// CALL_2D will use x3 for the call address. Return value in D0, 2 ARGs in D0, D1
|
||||
#define CALL_2D(F, M) call_d(dyn, ninst, F, NULL, 2, x3, -1, M, 0)
|
||||
// CALL_1DD will use x3 for the call address. Return value in D0, 1 ARG in D0, cals 2 functions in a row
|
||||
#define CALL_1DD(F, F2, M) call_d(dyn, ninst, F, F2, 1, x3, -1, M, 0)
|
||||
|
||||
#define MARK if(dyn->insts) {dyn->insts[ninst].mark = (uintptr_t)dyn->arm_size;}
|
||||
#define GETMARK ((dyn->insts)?dyn->insts[ninst].mark:(dyn->arm_size+4))
|
||||
#define MARK2 if(dyn->insts) {dyn->insts[ninst].mark2 = (uintptr_t)dyn->arm_size;}
|
||||
@@ -182,94 +220,129 @@
|
||||
#define GETMARK3 ((dyn->insts)?dyn->insts[ninst].mark3:(dyn->arm_size+4))
|
||||
#define MARKF if(dyn->insts) {dyn->insts[ninst].markf = (uintptr_t)dyn->arm_size;}
|
||||
#define GETMARKF ((dyn->insts)?dyn->insts[ninst].markf:(dyn->arm_size+4))
|
||||
#define MARKSEG if(dyn->insts) {dyn->insts[ninst].markseg = (uintptr_t)dyn->arm_size;}
|
||||
#define GETMARKSEG ((dyn->insts)?dyn->insts[ninst].markseg:(dyn->arm_size+4))
|
||||
#define MARKLOCK if(dyn->insts) {dyn->insts[ninst].marklock = (uintptr_t)dyn->arm_size;}
|
||||
#define GETMARKLOCK ((dyn->insts)?dyn->insts[ninst].marklock:(dyn->arm_size+4))
|
||||
|
||||
// Branch to MARK if cond (use i32)
|
||||
// Branch to MARK if cond (use j32)
|
||||
#define B_MARK(cond) \
|
||||
i32 = GETMARK-(dyn->arm_size+8); \
|
||||
Bcond(cond, i32)
|
||||
// Branch to MARK2 if cond (use i32)
|
||||
j32 = GETMARK-(dyn->arm_size+8); \
|
||||
Bcond(cond, j32)
|
||||
// Branch to MARK2 if cond (use j32)
|
||||
#define B_MARK2(cond) \
|
||||
i32 = GETMARK2-(dyn->arm_size+8); \
|
||||
Bcond(cond, i32)
|
||||
// Branch to MARK3 if cond (use i32)
|
||||
j32 = GETMARK2-(dyn->arm_size+8); \
|
||||
Bcond(cond, j32)
|
||||
// Branch to MARK3 if cond (use j32)
|
||||
#define B_MARK3(cond) \
|
||||
i32 = GETMARK3-(dyn->arm_size+8); \
|
||||
Bcond(cond, i32)
|
||||
// Branch to next instruction if cond (use i32)
|
||||
j32 = GETMARK3-(dyn->arm_size+8); \
|
||||
Bcond(cond, j32)
|
||||
// Branch to next instruction if cond (use j32)
|
||||
#define B_NEXT(cond) \
|
||||
i32 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->arm_size+8)):0; \
|
||||
Bcond(cond, i32)
|
||||
j32 = (dyn->insts)?(dyn->insts[ninst].epilog-(dyn->arm_size+8)):0; \
|
||||
Bcond(cond, j32)
|
||||
// Branch to MARKSEG if cond (use j32)
|
||||
#define B_MARKSEG(cond) \
|
||||
j32 = GETMARKSEG-(dyn->arm_size+8); \
|
||||
Bcond(cond, j32)
|
||||
// Branch to MARKLOCK if cond (use j32)
|
||||
#define B_MARKLOCK(cond) \
|
||||
j32 = GETMARKLOCK-(dyn->arm_size+8); \
|
||||
Bcond(cond, j32)
|
||||
|
||||
#define IFX(A) if((dyn->insts[ninst].x86.need_flags&(A)))
|
||||
#define IFX_PENDOR0 if((dyn->insts[ninst].x86.need_flags&(X_PEND) || !dyn->insts[ninst].x86.need_flags))
|
||||
#define IFXX(A) if((dyn->insts[ninst].x86.need_flags==(A)))
|
||||
#define IFX2X(A, B) if((dyn->insts[ninst].x86.need_flags==(A) || dyn->insts[ninst].x86.need_flags==(B) || dyn->insts[ninst].x86.need_flags==((A)|(B))))
|
||||
#define IFXN(A, B) if((dyn->insts[ninst].x86.need_flags&(A) && !(dyn->insts[ninst].x86.need_flags&(B))))
|
||||
|
||||
// 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); \
|
||||
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); \
|
||||
STRH_IMM8(s2, xEmu, offsetof(x86emu_t, sw))
|
||||
LDRH_IMM8(s1, xEmu, offsetof(x86emu_t, sw)); /*offset is 8bits right?*/ \
|
||||
BIC_IMM8(s1, s1, 0b01000111, 12); \
|
||||
ORR_IMM8_COND(cVS, s1, s1, 0b01000101, 12); /* unordered */ \
|
||||
ORR_IMM8_COND(cEQ, s1, s1, 0b01000000, 12); /* equal */ \
|
||||
ORR_IMM8_COND(cMI, s1, s1, 0b00000001, 12); /* less than */ \
|
||||
/* greater than leave 0 */ \
|
||||
STRH_IMM8(s1, xEmu, offsetof(x86emu_t, sw))
|
||||
|
||||
// Generate FCOMI with s1 and s2 scratch regs (the VCMP is already done)
|
||||
#define FCOMI(s1, s2) \
|
||||
VMRS_APSR(); /* 0b111 */ \
|
||||
XOR_REG_LSL_IMM8(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])); \
|
||||
MOVW(s2, d_none); \
|
||||
STR_IMM9(s2, xEmu, offsetof(x86emu_t, df));
|
||||
IFX(X_CF|X_PF|X_ZF|X_PEND) { \
|
||||
VMRS_APSR(); /* 0b111 */ \
|
||||
BIC_IMM8(xFlags, xFlags, 0b1000101, 0); \
|
||||
ORR_IMM8_COND(cVS, xFlags, xFlags, 0b01000101, 0); /* unordered */ \
|
||||
ORR_IMM8_COND(cEQ, xFlags, xFlags, 0b01000000, 0); /* zero */ \
|
||||
ORR_IMM8_COND(cMI, xFlags, xFlags, 0b00000001, 0); /* less than */ \
|
||||
/* greater than leave 0 */ \
|
||||
} \
|
||||
SET_DFNONE(s1); \
|
||||
IFX(X_OF|X_AF|X_SF|X_PEND) { \
|
||||
/* clear 0b100010010000 */ \
|
||||
BIC_IMM8(xFlags, xFlags, 0b10001001, 14); \
|
||||
} \
|
||||
|
||||
|
||||
#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) { \
|
||||
#define SET_DFNONE(S) if(!dyn->dfnone) {MOVW(S, d_none); STR_IMM9(S, xEmu, offsetof(x86emu_t, df)); dyn->dfnone=1;}
|
||||
#define SET_DF(S, N) if(N) {MOVW(S, N); STR_IMM9(S, xEmu, offsetof(x86emu_t, df)); dyn->dfnone=0;} else SET_DFNONE(S)
|
||||
#define SET_NODF() dyn->dfnone = 0
|
||||
#define SET_DFOK() dyn->dfnone = 1
|
||||
|
||||
#ifndef READFLAGS
|
||||
#define READFLAGS(A) \
|
||||
if(((A)!=X_PEND) && dyn->state_flags!=SF_SET && dyn->state_flags!=SF_SET_PENDING) { \
|
||||
if(dyn->state_flags!=SF_PENDING) { \
|
||||
LDR_IMM9(x3, xEmu, offsetof(x86emu_t, df)); \
|
||||
TSTS_REG_LSL_IMM8(x3, x3, 0); \
|
||||
i32 = (GETMARKF)-(dyn->arm_size+8); \
|
||||
Bcond(cEQ, i32); \
|
||||
CALL_(UpdateFlags, -1, 0); \
|
||||
MARKF; \
|
||||
dyn->cleanflags=1; \
|
||||
} \
|
||||
TSTS_REG_LSL_IMM5(x3, x3, 0); \
|
||||
j32 = (GETMARKF)-(dyn->arm_size+8); \
|
||||
Bcond(cEQ, j32); \
|
||||
} \
|
||||
CALL_(UpdateFlags, -1, 0); \
|
||||
MARKF; \
|
||||
dyn->state_flags = SF_SET; \
|
||||
SET_DFOK(); \
|
||||
}
|
||||
#endif
|
||||
#ifndef SETFLAGS
|
||||
#define SETFLAGS(A, B) \
|
||||
if(dyn->state_flags!=SF_SET && B==SF_SUBSET && (dyn->insts[ninst].x86.need_flags&(~((A)/*|X_PEND*/)))) \
|
||||
READFLAGS(dyn->insts[ninst].x86.need_flags&(~(A)|X_PEND)); \
|
||||
dyn->state_flags = (B==SF_SUBSET)?SF_SET: \
|
||||
((B==SF_SET_PENDING && !(dyn->insts[ninst].x86.need_flags&X_PEND)?SF_SET:B))
|
||||
#endif
|
||||
#ifndef JUMP
|
||||
#define JUMP(A)
|
||||
#define JUMP(A, C)
|
||||
#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 BARRIER
|
||||
#define BARRIER(A)
|
||||
#endif
|
||||
#ifndef BARRIER_NEXT
|
||||
#define BARRIER_NEXT(A)
|
||||
#endif
|
||||
#define UFLAG_OP1(A) if(dyn->insts[ninst].x86.need_flags) {STR_IMM9(A, xEmu, offsetof(x86emu_t, op1));}
|
||||
#define UFLAG_OP2(A) if(dyn->insts[ninst].x86.need_flags) {STR_IMM9(A, xEmu, offsetof(x86emu_t, op2));}
|
||||
#define UFLAG_OP12(A1, A2) if(dyn->insts[ninst].x86.need_flags) {STR_IMM9(A1, xEmu, offsetof(x86emu_t, op1));STR_IMM9(A2, 0, offsetof(x86emu_t, op2));}
|
||||
#define UFLAG_RES(A) if(dyn->insts[ninst].x86.need_flags) {STR_IMM9(A, xEmu, offsetof(x86emu_t, res));}
|
||||
#define UFLAG_DF(r, A) if(dyn->insts[ninst].x86.need_flags) {SET_DF(r, A)}
|
||||
#define UFLAG_IF if(dyn->insts[ninst].x86.need_flags)
|
||||
#ifndef DEFAULT
|
||||
#define DEFAULT BARRIER(2)
|
||||
#define DEFAULT *ok = -1; BARRIER(2)
|
||||
#endif
|
||||
#ifndef NEW_BARRIER_INST
|
||||
#define NEW_BARRIER_INST
|
||||
#endif
|
||||
// Emit the LOCK mutex (x1, x2 and x3 are lost)
|
||||
#define LOCK emit_lock(dyn, addr, ninst)
|
||||
// Emit the UNLOCK mutex (x1, x2 and x3 are lost)
|
||||
#define UNLOCK emit_unlock(dyn, addr, ninst)
|
||||
|
||||
#if STEP < 2
|
||||
#define PASS2IF(A, B) if(A)
|
||||
#elif STEP == 2
|
||||
#define PASS2IF(A, B) if(A) dyn->insts[ninst].pass2choice = B; if(dyn->insts[ninst].pass2choice == B)
|
||||
#else
|
||||
#define PASS2IF(A, B) if(dyn->insts[ninst].pass2choice == B)
|
||||
#endif
|
||||
|
||||
void arm_epilog();
|
||||
void* arm_linker(x86emu_t* emu, void** table, uintptr_t addr);
|
||||
void* arm_next(x86emu_t* emu, uintptr_t addr);
|
||||
|
||||
#ifndef STEPNAME
|
||||
#define STEPNAME3(N,M) N##M
|
||||
@@ -281,6 +354,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)
|
||||
@@ -298,37 +372,106 @@ void* arm_linker(x86emu_t* emu, void** table, uintptr_t addr);
|
||||
#define dynarecF30F STEPNAME(dynarecF30F)
|
||||
|
||||
#define geted STEPNAME(geted_)
|
||||
#define fakeed STEPNAME(fakeed_)
|
||||
#define geted16 STEPNAME(geted16_)
|
||||
#define jump_to_epilog STEPNAME(jump_to_epilog_)
|
||||
#define jump_to_linker STEPNAME(jump_to_linker_)
|
||||
#define jump_to_next STEPNAME(jump_to_next_)
|
||||
#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 call_d STEPNAME(call_d_)
|
||||
#define grab_fsdata STEPNAME(grab_fsdata_)
|
||||
#define grab_tlsdata STEPNAME(grab_tlsdata_)
|
||||
#define isNativeCall STEPNAME(isNativeCall_)
|
||||
#define emit_lock STEPNAME(emit_lock)
|
||||
#define emit_unlock STEPNAME(emit_unlock)
|
||||
#define emit_cmp8 STEPNAME(emit_cmp8)
|
||||
#define emit_cmp16 STEPNAME(emit_cmp16)
|
||||
#define emit_cmp32 STEPNAME(emit_cmp32)
|
||||
#define emit_cmp8_0 STEPNAME(emit_cmp8_0)
|
||||
#define emit_cmp16_0 STEPNAME(emit_cmp16_0)
|
||||
#define emit_cmp32_0 STEPNAME(emit_cmp32_0)
|
||||
#define emit_test8 STEPNAME(emit_test8)
|
||||
#define emit_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_shl32 STEPNAME(emit_shl32)
|
||||
#define emit_shl32c STEPNAME(emit_shl32c)
|
||||
#define emit_shr32 STEPNAME(emit_shr32)
|
||||
#define emit_shr32c STEPNAME(emit_shr32c)
|
||||
#define emit_sar32c STEPNAME(emit_sar32c)
|
||||
#define emit_rol32c STEPNAME(emit_rol32c)
|
||||
#define emit_rol8c STEPNAME(emit_rol8c)
|
||||
#define emit_ror32c STEPNAME(emit_ror32c)
|
||||
#define emit_ror8c STEPNAME(emit_ror8c)
|
||||
#define emit_shrd32c STEPNAME(emit_shrd32c)
|
||||
#define emit_shld32c STEPNAME(emit_shld32c)
|
||||
#define emit_shrd32 STEPNAME(emit_shrd32)
|
||||
|
||||
#define emit_pf STEPNAME(emit_pf)
|
||||
|
||||
#define x87_do_push STEPNAME(x87_do_push)
|
||||
#define x87_do_push_empty STEPNAME(x87_do_push_empty)
|
||||
#define x87_do_pop STEPNAME(x87_do_pop)
|
||||
#define x87_get_current_cache STEPNAME(x87_get_current_cache)
|
||||
#define x87_get_cache STEPNAME(x87_get_cache)
|
||||
#define x87_get_neoncache STEPNAME(x87_get_neoncache)
|
||||
#define x87_get_st STEPNAME(x87_get_st)
|
||||
#define x87_get_st_empty STEPNAME(x87_get_st)
|
||||
#define x87_refresh STEPNAME(x87_refresh)
|
||||
#define x87_forget STEPNAME(x87_forget)
|
||||
#define x87_reget_st STEPNAME(x87_reget_st)
|
||||
#define x87_stackcount STEPNAME(x87_stackcount)
|
||||
#define x87_setround STEPNAME(x87_setround)
|
||||
#define x87_restoreround STEPNAME(x87_restoreround)
|
||||
#define sse_setround STEPNAME(sse_setround)
|
||||
#define mmx_get_reg STEPNAME(mmx_get_reg)
|
||||
#define mmx_get_reg_empty STEPNAME(mmx_get_reg_empty)
|
||||
#define sse_get_reg STEPNAME(sse_get_reg)
|
||||
@@ -338,6 +481,8 @@ void* arm_linker(x86emu_t* emu, void** table, uintptr_t addr);
|
||||
#define fpu_popcache STEPNAME(fpu_popcache)
|
||||
#define fpu_reset STEPNAME(fpu_reset)
|
||||
#define fpu_purgecache STEPNAME(fpu_purgecache)
|
||||
#define x87_purgecache STEPNAME(x87_purgecache)
|
||||
#define mmx_purgecache STEPNAME(mmx_purgecache)
|
||||
#ifdef HAVE_TRACE
|
||||
#define fpu_reflectcache STEPNAME(fpu_reflectcache)
|
||||
#endif
|
||||
@@ -348,19 +493,22 @@ void* arm_linker(x86emu_t* emu, void** table, uintptr_t addr);
|
||||
#define fpu_putback_single_reg STEPNAME(fpu_putback_single_reg)
|
||||
|
||||
/* setup r2 to address pointed by */
|
||||
uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int* fixedaddress, uint32_t absmax, uint32_t mask);
|
||||
uintptr_t geted(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int* fixedaddress, uint32_t absmax, uint32_t mask, int getfixonly);
|
||||
|
||||
/* setup r2 to address pointed by */
|
||||
uintptr_t geted16(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop, uint8_t* ed, uint8_t hint, int* fixedaddress, uint32_t absmax, uint32_t mask);
|
||||
|
||||
// Do the GETED, but don't emit anything...
|
||||
uintptr_t fakeed(dynarec_arm_t* dyn, uintptr_t addr, int ninst, uint8_t nextop);
|
||||
|
||||
// generic x86 helper
|
||||
void jump_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst);
|
||||
void jump_to_linker(dynarec_arm_t* dyn, uintptr_t ip, int reg, int ninst);
|
||||
void jump_to_next(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 call_c(dynarec_arm_t* dyn, int ninst, void* fnc, int reg, int ret, uint32_t mask);
|
||||
void iret_to_epilog(dynarec_arm_t* dyn, int ninst);
|
||||
void call_c(dynarec_arm_t* dyn, int ninst, void* fnc, int reg, int ret, uint32_t mask, int saveflags);
|
||||
void call_d(dynarec_arm_t* dyn, int ninst, void* fnc, void* fnc2, int n, int reg, int ret, uint32_t mask, int saveflags);
|
||||
void grab_fsdata(dynarec_arm_t* dyn, uintptr_t addr, int ninst, int reg);
|
||||
void grab_tlsdata(dynarec_arm_t* dyn, uintptr_t addr, int ninst, int reg);
|
||||
int isNativeCall(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t* calladdress, int* retn);
|
||||
void emit_lock(dynarec_arm_t* dyn, uintptr_t addr, int ninst);
|
||||
void emit_unlock(dynarec_arm_t* dyn, uintptr_t addr, int ninst);
|
||||
void emit_cmp8(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
@@ -372,20 +520,91 @@ 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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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_shl32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_shl32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_shr32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
void emit_shr32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_sar32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_rol32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_rol8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_ror32c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_ror8c(dynarec_arm_t* dyn, int ninst, int s1, int32_t c, int s3, int s4);
|
||||
void emit_shrd32c(dynarec_arm_t* dyn, int ninst, int s1, int s2, int32_t c, int s3, int s4);
|
||||
void emit_shld32c(dynarec_arm_t* dyn, int ninst, int s1, int s2, int32_t c, int s3, int s4);
|
||||
void emit_shrd32(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int s4);
|
||||
|
||||
void emit_pf(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4);
|
||||
|
||||
// x87 helper
|
||||
// cache of the local stack counter, to avoid upadte at every call
|
||||
void x87_stackcount(dynarec_arm_t* dyn, int ninst, int scratch);
|
||||
// fpu push. Return the Dd value to be used
|
||||
int x87_do_push(dynarec_arm_t* dyn, int ninst);
|
||||
int x87_do_push(dynarec_arm_t* dyn, int ninst, int s1, int t);
|
||||
// fpu push. Do not allocate a cache register. Needs a scratch register to do x87stack synch (or 0 to not do it)
|
||||
void x87_do_push_empty(dynarec_arm_t* dyn, int ninst, int s1);
|
||||
// fpu pop. All previous returned Dd should be considered invalid
|
||||
void x87_do_pop(dynarec_arm_t* dyn, int ninst);
|
||||
void x87_do_pop(dynarec_arm_t* dyn, int ninst, int s1);
|
||||
// get cache index for a x87 reg, return -1 if cache doesn't exist
|
||||
int x87_get_current_cache(dynarec_arm_t* dyn, int ninst, int st, int t);
|
||||
// get cache index for a x87 reg, create the entry if needed
|
||||
int x87_get_cache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int a);
|
||||
int x87_get_cache(dynarec_arm_t* dyn, int ninst, int populate, int s1, int s2, int a, int t);
|
||||
// get neoncache index for a x87 reg
|
||||
int x87_get_neoncache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int a);
|
||||
// get vfpu register for a x87 reg, create the entry if needed
|
||||
int x87_get_st(dynarec_arm_t* dyn, int ninst, int s1, int s2, int a);
|
||||
int x87_get_st(dynarec_arm_t* dyn, int ninst, int s1, int s2, int a, int t);
|
||||
// get vfpu register for a x87 reg, create the entry if needed. Do not fetch the Stx if not already in cache
|
||||
int x87_get_st_empty(dynarec_arm_t* dyn, int ninst, int s1, int s2, int a, int t);
|
||||
// refresh a value from the cache ->emu (nothing done if value is not cached)
|
||||
void x87_refresh(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st);
|
||||
// refresh a value from the cache ->emu and then forget the cache (nothing done if value is not cached)
|
||||
@@ -396,24 +615,52 @@ void x87_reget_st(dynarec_arm_t* dyn, int ninst, int s1, int s2, int st);
|
||||
int x87_setround(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
// Restore round flag
|
||||
void x87_restoreround(dynarec_arm_t* dyn, int ninst, int s1);
|
||||
// Set rounding according to mxcsr flags, return reg to restore flags
|
||||
int sse_setround(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
|
||||
#define neoncache_st_coherency STEPNAME(neoncache_st_coherency)
|
||||
int neoncache_st_coherency(dynarec_arm_t* dyn, int ninst, int a, int b);
|
||||
|
||||
#if STEP == 0
|
||||
#define ST_IS_F(A) 0
|
||||
#define X87_COMBINE(A, B) NEON_CACHE_ST_D
|
||||
#define X87_ST0 NEON_CACHE_ST_D
|
||||
#define X87_ST(A) NEON_CACHE_ST_D
|
||||
#elif STEP == 1
|
||||
#define ST_IS_F(A) (neoncache_get_current_st(dyn, ninst, A)==NEON_CACHE_ST_F)
|
||||
#define X87_COMBINE(A, B) neoncache_combine_st(dyn, ninst, A, B)
|
||||
#define X87_ST0 neoncache_get_current_st(dyn, ninst, 0)
|
||||
#define X87_ST(A) neoncache_get_current_st(dyn, ninst, A)
|
||||
#else
|
||||
#define ST_IS_F(A) (neoncache_get_st(dyn, ninst, A)==NEON_CACHE_ST_F)
|
||||
#if STEP == 3
|
||||
#define X87_COMBINE(A, B) neoncache_st_coherency(dyn, ninst, A, B)
|
||||
#else
|
||||
#define X87_COMBINE(A, B) neoncache_get_st(dyn, ninst, A)
|
||||
#endif
|
||||
#define X87_ST0 neoncache_get_st(dyn, ninst, 0)
|
||||
#define X87_ST(A) neoncache_get_st(dyn, ninst, A)
|
||||
#endif
|
||||
|
||||
//MMX helpers
|
||||
// get neon register for a MMX reg, create the entry if needed
|
||||
int mmx_get_reg(dynarec_arm_t* dyn, int ninst, int s1, int a);
|
||||
int mmx_get_reg(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int a);
|
||||
// get neon register for a MMX reg, but don't try to synch it if it needed to be created
|
||||
int mmx_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int a);
|
||||
int mmx_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3, int a);
|
||||
|
||||
//SSE/SSE2 helpers
|
||||
// get neon register for a SSE reg, create the entry if needed
|
||||
int sse_get_reg(dynarec_arm_t* dyn, int ninst, int s1, int a);
|
||||
int sse_get_reg(dynarec_arm_t* dyn, int ninst, int s1, int a, int forwrite);
|
||||
// get neon register for a SSE reg, but don't try to synch it if it needed to be created
|
||||
int sse_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int a);
|
||||
|
||||
// common coproc helpers
|
||||
// reset the cache
|
||||
void fpu_reset(dynarec_arm_t* dyn, int ninst);
|
||||
// purge the FPU cache (needs 3 scratch registers)
|
||||
void fpu_purgecache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
// purge the FPU cache (needs 3 scratch registers) next=1 if for a conditionnal branch jumping out of block (no tracking updated)
|
||||
void fpu_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1, int s2, int s3);
|
||||
void x87_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1, int s2, int s3);
|
||||
void mmx_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1);
|
||||
#ifdef HAVE_TRACE
|
||||
void fpu_reflectcache(dynarec_arm_t* dyn, int ninst, int s1, int s2, int s3);
|
||||
#endif
|
||||
@@ -425,9 +672,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 +691,22 @@ 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);
|
||||
|
||||
#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__
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <stddef.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86context.h"
|
||||
@@ -19,50 +20,56 @@
|
||||
#include "arm_printer.h"
|
||||
#include "dynarec_arm_functions.h"
|
||||
#include "dynarec_arm_helper.h"
|
||||
#include "custommem.h"
|
||||
|
||||
#ifndef STEP
|
||||
#error No STEP defined
|
||||
#endif
|
||||
|
||||
#include "dynarec_arm_helper.h"
|
||||
|
||||
void arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
|
||||
uintptr_t 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;
|
||||
uintptr_t init_addr = addr;
|
||||
MAYUSE(init_addr);
|
||||
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;
|
||||
dyn->dfnone = 0;
|
||||
fpu_reset(dyn, ninst);
|
||||
// ok, go now
|
||||
INIT;
|
||||
while(ok) {
|
||||
ip = addr;
|
||||
if((dyn->insts[ninst].x86.barrier==1)) {
|
||||
NEW_BARRIER_INST;
|
||||
}
|
||||
// propagate ST stack state, especial stack pop that are defered
|
||||
if(dyn->n.stack_pop) {
|
||||
for(int j=0; j<24; ++j)
|
||||
if((dyn->n.neoncache[j].t == NEON_CACHE_ST_D || dyn->n.neoncache[j].t == NEON_CACHE_ST_F)) {
|
||||
if(dyn->n.neoncache[j].n<dyn->n.stack_pop)
|
||||
dyn->n.neoncache[j].v = 0;
|
||||
else
|
||||
dyn->n.neoncache[j].n-=dyn->n.stack_pop;
|
||||
}
|
||||
dyn->n.stack_pop = 0;
|
||||
}
|
||||
dyn->n.stack = dyn->n.stack_next;
|
||||
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);
|
||||
STM(0, (1<<4)|(1<<5)|(1<<6)|(1<<7)|(1<<8)|(1<<9)|(1<<10)|(1<<11));
|
||||
STR_IMM9(1, 0, offsetof(x86emu_t, ip));
|
||||
MOV32(2, 1);
|
||||
MOV32(x1, ip);
|
||||
STM(xEmu, (1<<xEAX)|(1<<xEBX)|(1<<xECX)|(1<<xEDX)|(1<<xESI)|(1<<xEDI)|(1<<xESP)|(1<<xEBP));
|
||||
STR_IMM9(x1, xEmu, offsetof(x86emu_t, ip));
|
||||
MOVW(x2, 1);
|
||||
CALL(PrintTrace, -1, 0);
|
||||
MESSAGE(LOG_DUMP, "----------\n");
|
||||
}
|
||||
@@ -73,16 +80,53 @@ void arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
|
||||
|
||||
INST_EPILOG;
|
||||
|
||||
if(dyn->insts && dyn->insts[ninst+1].x86.barrier) {
|
||||
fpu_purgecache(dyn, ninst, x1, x2, x3);
|
||||
if(dyn->insts[ninst+1].x86.barrier!=2)
|
||||
dyn->cleanflags = 0;
|
||||
if(dyn->insts[ninst+1].x86.barrier) {
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
if(dyn->insts[ninst+1].x86.barrier!=2) {
|
||||
dyn->state_flags = 0;
|
||||
dyn->dfnone = 0;
|
||||
}
|
||||
}
|
||||
if(!ok && !need_epilog && (addr < (dyn->start+dyn->isize))) {
|
||||
ok = 1;
|
||||
}
|
||||
#if STEP == 0
|
||||
if(!ok && !need_epilog && box86_dynarec_bigblock && getProtection(addr+3))
|
||||
if(*(uint32_t*)addr!=0) { // check if need to continue (but is next 4 bytes are 0, stop)
|
||||
uintptr_t next = get_closest_next(dyn, addr);
|
||||
if(next && (
|
||||
(((next-addr)<15) && is_nops(dyn, addr, next-addr))
|
||||
||(((next-addr)<30) && is_instructions(dyn, addr, next-addr)) ))
|
||||
{
|
||||
dynarec_log(LOG_DEBUG, "Extend block %p, %p -> %p (ninst=%d)\n", dyn, (void*)addr, (void*)next, ninst);
|
||||
ok = 1;
|
||||
} else if(next && (next-addr)<30) {
|
||||
dynarec_log(LOG_DEBUG, "Cannot extend block %p -> %p (%02X %02X %02X %02X %02X %02X %02X %02x)\n", (void*)addr, (void*)next, PK(0), PK(1), PK(2), PK(3), PK(4), PK(5), PK(6), PK(7));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if(ok<0) {ok = 0; need_epilog=1;}
|
||||
++ninst;
|
||||
#if STEP == 0
|
||||
if(ok && !isJumpTableDefault((void*)addr))
|
||||
#else
|
||||
if(ok && (ninst==dyn->size))
|
||||
#endif
|
||||
{
|
||||
#if STEP == 3
|
||||
dynarec_log(LOG_DEBUG, "Stopping block %p (%d / %d)\n",(void*)init_addr, ninst, dyn->size);
|
||||
#endif
|
||||
BARRIER(2);
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
jump_to_next(dyn, addr, 0, ninst);
|
||||
ok=0; need_epilog=0;
|
||||
}
|
||||
}
|
||||
if(need_epilog) {
|
||||
fpu_purgecache(dyn, ninst, x1, x2, x3);
|
||||
fpu_purgecache(dyn, ninst, 0, x1, x2, x3);
|
||||
jump_to_epilog(dyn, ip, 0, ninst); // no linker here, it's an unknow instruction
|
||||
}
|
||||
FINI;
|
||||
MESSAGE(LOG_DUMP, "---- END OF BLOCK ---- (%d, %d sons)\n", dyn->size, dyn->sons_size);
|
||||
return addr;
|
||||
}
|
||||
@@ -1,16 +1,39 @@
|
||||
|
||||
#define INIT uintptr_t sav_addr=addr
|
||||
#define FINI dyn->isize = addr-sav_addr
|
||||
#define FINI \
|
||||
dyn->isize = addr-sav_addr;\
|
||||
dyn->insts[ninst].x86.addr = addr;\
|
||||
if(ninst) dyn->insts[ninst-1].x86.size = dyn->insts[ninst].x86.addr - dyn->insts[ninst-1].x86.addr
|
||||
#define MESSAGE(A, ...)
|
||||
#define READFLAGS(A) dyn->insts[ninst].x86.use_flags = A
|
||||
#define SETFLAGS(A,B) {dyn->insts[ninst].x86.set_flags = A; dyn->insts[ninst].x86.state_flags = B;}
|
||||
#define EMIT(A)
|
||||
#define UFLAGS(A) {}
|
||||
#define USEFLAGS(A) {}
|
||||
#define NEW_INST ++dyn->size
|
||||
#define JUMP(A, C) if((A)>addr) add_next(dyn, (uintptr_t)A); dyn->insts[ninst].x86.jmp = A; dyn->insts[ninst].x86.jmp_cond = C
|
||||
#define BARRIER(A) dyn->insts[ninst].x86.barrier = A
|
||||
#define BARRIER_NEXT(A) if(ninst<dyn->size) dyn->insts[ninst+1].x86.barrier = A
|
||||
#define NEW_INST \
|
||||
++dyn->size; \
|
||||
if(dyn->size+3>=dyn->cap) { \
|
||||
dyn->insts = (instruction_arm_t*)realloc(dyn->insts, sizeof(instruction_arm_t)*dyn->cap*2); \
|
||||
memset(&dyn->insts[dyn->cap], 0, sizeof(instruction_arm_t)*dyn->cap); \
|
||||
dyn->cap *= 2; \
|
||||
} \
|
||||
dyn->insts[ninst].x86.addr = ip; \
|
||||
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 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; \
|
||||
if(box86_dynarec_log>=LOG_INFO) {\
|
||||
dynarec_log(LOG_NONE, "%p: Dynarec stopped because of Opcode %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", \
|
||||
(void*)ip, PKip(0), \
|
||||
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)); \
|
||||
printFunctionAddr(ip, " => "); \
|
||||
dynarec_log(LOG_NONE, "\n"); \
|
||||
}
|
||||
@@ -1,15 +1,12 @@
|
||||
#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 FINI
|
||||
#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 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 READFLAGS(A)
|
||||
#define SETFLAGS(A,B)
|
||||
|
||||
#define NEW_INST dyn->n.combined1 = dyn->n.combined2 = 0
|
||||
|
||||
#define INST_EPILOG dyn->insts[ninst].n = dyn->n
|
||||
|
||||
#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,52 @@
|
||||
#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));} \
|
||||
*(uint32_t*)(dyn->block) = A; \
|
||||
dyn->block += 4; dyn->arm_size += 4
|
||||
if(box86_dynarec_dump) {dynarec_log(LOG_NONE, "\t%08x\t%s\n", (A), arm_print(A));} \
|
||||
*(uint32_t*)(dyn->block) = A; \
|
||||
dyn->block += 4; dyn->arm_size += 4;\
|
||||
dyn->insts[ninst].size2 += 4
|
||||
|
||||
#define 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, inst=%d, barrier=%d state=%d/%d, set=%X, use=%X, need=%X", \
|
||||
(box86_dynarec_dump>1)?"\e[32m":"", \
|
||||
(void*)(dyn->arm_start+dyn->insts[ninst].address), \
|
||||
dyn->insts[ninst].size/4, \
|
||||
ninst, \
|
||||
dyn->insts[ninst].x86.barrier, \
|
||||
dyn->insts[ninst].x86.state_flags, \
|
||||
dyn->state_flags, \
|
||||
dyn->insts[ninst].x86.set_flags, \
|
||||
dyn->insts[ninst].x86.use_flags, \
|
||||
dyn->insts[ninst].x86.need_flags); \
|
||||
for(int ii=0; ii<24; ++ii) { \
|
||||
switch(dyn->insts[ninst].n.neoncache[ii].t) { \
|
||||
case NEON_CACHE_ST_D: dynarec_log(LOG_NONE, " D%d:ST%d", ii+8, dyn->insts[ninst].n.neoncache[ii].n); break; \
|
||||
case NEON_CACHE_ST_F: dynarec_log(LOG_NONE, " S%d:st%d", (ii+8)*2, dyn->insts[ninst].n.neoncache[ii].n); break; \
|
||||
case NEON_CACHE_MM: dynarec_log(LOG_NONE, " D%d:MM%d", ii+8, dyn->insts[ninst].n.neoncache[ii].n); break; \
|
||||
case NEON_CACHE_XMMW: dynarec_log(LOG_NONE, " Q%d:XMM%d", (ii+8)/2, dyn->insts[ninst].n.neoncache[ii].n); ++ii; break; \
|
||||
case NEON_CACHE_XMMR: dynarec_log(LOG_NONE, " Q%d:xmm%d", (ii+8)/2, dyn->insts[ninst].n.neoncache[ii].n); ++ii; break; \
|
||||
case NEON_CACHE_SCR: dynarec_log(LOG_NONE, " D%d:Scratch", ii+8); break; \
|
||||
case NEON_CACHE_NONE: \
|
||||
default: break; \
|
||||
} \
|
||||
} \
|
||||
if(dyn->n.stack || dyn->insts[ninst].n.stack_next) \
|
||||
printf_log(LOG_NONE, " X87:%d/%d", dyn->n.stack, dyn->insts[ninst].n.stack_next);\
|
||||
if(dyn->insts[ninst].n.combined1 || dyn->insts[ninst].n.combined2) \
|
||||
printf_log(LOG_NONE, " CMB:%d/%d", dyn->insts[ninst].n.combined1, dyn->insts[ninst].n.combined2); \
|
||||
dynarec_log(LOG_NONE, "%s\n", (box86_dynarec_dump>1)?"\e[m":""); \
|
||||
}
|
||||
|
||||
#define NEW_BARRIER_INST \
|
||||
if(ninst) { \
|
||||
dyn->sons_x86[dyn->sons_size] = (uintptr_t)ip; \
|
||||
dyn->sons_arm[dyn->sons_size] = dyn->block; \
|
||||
MESSAGE(LOG_DUMP, "----> potential Son here\n");\
|
||||
++dyn->sons_size; \
|
||||
}
|
||||
|
||||
@@ -4,16 +4,55 @@
|
||||
#include "dynarec_private.h"
|
||||
|
||||
typedef struct x86emu_s x86emu_t;
|
||||
typedef struct dynablock_s dynablock_t;
|
||||
|
||||
#define NEON_CACHE_NONE 0
|
||||
#define NEON_CACHE_ST_D 1
|
||||
#define NEON_CACHE_ST_F 2
|
||||
#define NEON_CACHE_MM 3
|
||||
#define NEON_CACHE_XMMW 4
|
||||
#define NEON_CACHE_XMMR 5
|
||||
#define NEON_CACHE_SCR 6
|
||||
typedef union neon_cache_s {
|
||||
int8_t v;
|
||||
struct {
|
||||
unsigned int t:4; // reg type
|
||||
unsigned int n:4; // reg number
|
||||
};
|
||||
} neon_cache_t;
|
||||
typedef struct neoncache_s {
|
||||
neon_cache_t neoncache[24];
|
||||
int8_t stack;
|
||||
int8_t stack_next;
|
||||
int8_t stack_pop;
|
||||
uint8_t combined1;
|
||||
uint8_t combined2;
|
||||
} neoncache_t;
|
||||
|
||||
typedef struct instruction_arm_s {
|
||||
instruction_x86_t x86;
|
||||
uintptr_t address; // (start) address of the arm emited instruction
|
||||
uintptr_t epilog; // epilog of current instruction (can be start of next, of barrier stuff)
|
||||
int size; // size of the arm emited instruction
|
||||
int size2; // size of the arm emited instrucion after pass2
|
||||
uintptr_t mark, mark2, mark3;
|
||||
uintptr_t markf;
|
||||
uintptr_t markseg;
|
||||
uintptr_t marklock;
|
||||
int pass2choice;// value for choices that are fixed on pass2 for pass3
|
||||
uintptr_t natcall;
|
||||
int retn;
|
||||
neoncache_t n;
|
||||
} instruction_arm_t;
|
||||
|
||||
typedef union sse_cache_s {
|
||||
int v;
|
||||
struct {
|
||||
uint8_t reg;
|
||||
uint8_t write;
|
||||
};
|
||||
} sse_cache_t;
|
||||
|
||||
typedef struct dynarec_arm_s {
|
||||
instruction_arm_t *insts;
|
||||
int32_t size;
|
||||
@@ -21,21 +60,33 @@ 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
|
||||
int ssecache[8];// cache status for the 8 SSE(2) registers
|
||||
sse_cache_t ssecache[8];// cache status for the 8 SSE(2) registers
|
||||
int fpuused[24];// all 8..31 double reg from fpu, used by x87, sse and mmx
|
||||
neoncache_t n; // cache for the 8..31 double reg from fpu, plus x87 stack delta
|
||||
int x87stack; // cache stack counter
|
||||
int mmxcount; // number of mmx register used (not both mmx and x87 at the same time)
|
||||
int fpu_scratch;// scratch counter
|
||||
int fpu_extra_qscratch; // some opcode need an extra quad scratch register
|
||||
int fpu_reg; // x87/sse/mmx reg counter
|
||||
int dfnone; // if defered flags is already set to df_none
|
||||
uintptr_t* next; // variable array of "next" jump address
|
||||
int next_sz;
|
||||
int next_cap;
|
||||
uintptr_t* sons_x86; // the x86 address of potential dynablock sons
|
||||
void** sons_arm; // the arm address of potential dynablock sons
|
||||
int sons_size; // number of potential dynablock sons
|
||||
dynablock_t* dynablock;
|
||||
} 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);
|
||||
int is_instructions(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_SET_PENDING 3
|
||||
#define SF_MAYSET 4
|
||||
#define SF_SUBSET 5
|
||||
|
||||
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_cond; // 1 of conditionnal jump
|
||||
int jmp_insts; // instuction to jump to (-1 if out of the block)
|
||||
uint32_t use_flags; // 0 or combination of X_?F
|
||||
uint32_t set_flags; // 0 or combination of X_?F
|
||||
uint32_t need_flags; // calculated
|
||||
int state_flags; // One of SF_XXX state
|
||||
} instruction_x86_t;
|
||||
|
||||
void printf_x86_instruction(zydis_dec_t* dec, instruction_x86_t* inst, const char* name);
|
||||
|
||||
#endif //__DYNAREC_PRIVATE_H_
|
||||
#endif //__DYNAREC_PRIVATE_H_
|
||||
@@ -0,0 +1,524 @@
|
||||
ARM_ 1 1 1 1 0 0 0 1 0 0 0 0 (0) (0) (0) 1 (0) (0) (0) (0) (0) (0) @<1> (0) 0 0 0 0 (0) (0) (0) (0) SETEND \%cparam ? 'B' : 'L'\E
|
||||
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>, <Qm>, <Qn>
|
||||
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>, <Qm>, <Qn>
|
||||
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>, <Qm>, <Qn>
|
||||
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>, <Qm>, <Qn>
|
||||
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>, <Dm>
|
||||
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>, <Dm>
|
||||
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>, <Dm>
|
||||
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>, <Dm>
|
||||
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>, <Dm>
|
||||
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>, <Dm>
|
||||
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 @ set ++size@ @ 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 ++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 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> 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> 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 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> 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> 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 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> 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> 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 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> 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> 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 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> 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> 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 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> 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> 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 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> 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> 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 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> 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> 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 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> 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> 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 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> 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> 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 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> 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> 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>
|
||||
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> 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> 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 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> 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> 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 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> 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> 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 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> 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> 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 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> 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> 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 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> 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> 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 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> 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> 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 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> 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> 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 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> 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> 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 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> 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> 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 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> 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> 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> 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 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> 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> 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 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> 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> 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 1 0 @<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 1 0 @<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 1 0 @<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 1 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 1 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 1 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> 1 0 <8> 1 1 <2> 1 1 <6>
|
||||
INVALIDATE 1 1 1 1 0 1 0 0 1 <1> 1 0 <8> 1 1 <2> 0 0 <1> 1 <4>
|
||||
INVALIDATE 1 1 1 1 0 1 0 0 1 <1> 1 0 <8> 1 1 1 0 <3> 1 <4>
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 0 size 0 @<1> 1 1 0 1 @ param=1 char align[4] !@ %@ sprintf(align, ":%d", 8 << size)@ align[0] = '\0'@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[]}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 0 size 0 @<1> 1 1 1 1 @ param=1 char align[4] !@ %@ sprintf(align, ":%d", 8 << size)@ align[0] = '\0'@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[]}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 0 size 0 @<1> Rm @ param=1 char align[4] !@ %@ sprintf(align, ":%d", 8 << size)@ align[0] = '\0'@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[]}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 0 size 1 @<1> 1 1 0 1 @ param=1 char align[4] !@ %@ sprintf(align, ":%d", 8 << size)@ align[0] = '\0'@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + d]\[]}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 0 size 1 @<1> 1 1 1 1 @ param=1 char align[4] !@ %@ sprintf(align, ":%d", 8 << size)@ align[0] = '\0'@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + d]\[]}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 0 size 1 @<1> Rm @ param=1 char align[4] !@ %@ sprintf(align, ":%d", 8 << size)@ align[0] = '\0'@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + d]\[]}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 0 @<4> 1 1 0 1 @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 0 @<4> 1 1 1 1 @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 0 @<4> Rm @ set uint8_t temp = (2 << size) - 1@ set uint8_t temp2 = param & temp@ temp2=0=param>>1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 8 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ @ VLD1<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\]}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 1 size @<1> @<1> 1 1 0 1 @ param2_1=1 char align[4] !@ %@ sprintf(align, ":%d", 16 << size)@ align[0] = '\0'@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[]}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 1 size @<1> @<1> 1 1 1 1 @ param2_1=1 char align[4] !@ %@ sprintf(align, ":%d", 16 << size)@ align[0] = '\0'@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[]}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 0 1 size @<1> @<1> Rm @ param2_1=1 char align[4] !@ %@ sprintf(align, ":%d", 16 << size)@ align[0] = '\0'@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[]}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> 1 1 0 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> 1 1 1 1 @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 0 1 @<4> Rm @ size=0b00=0b01 uint8_t temp temp,1,1,3@ set uint8_t temp2 = param & temp@ temp2=0=1 char align[5] !@ %@ align[0] = '\0'@ sprintf(align, ":%d", 16 << size)@ sprintf(align, "???")@ set uint8_t x = param >> (size + 1)@ set int spacing = size ? ((param >> size) & 1) : 0@ @ VLD2<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[\%dx\], \vecname[0x21 + d + spacing]\[\%dx\]}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 1 0 size @<1> @<1> 1 1 0 1 VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[], \vecname[0x22 + param1_1+param1_1 + d]\[]}, [<Rn>]!
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 1 0 size @<1> @<1> 1 1 1 1 VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[], \vecname[0x22 + param1_1+param1_1 + d]\[]}, [<Rn>]
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 1 0 size @<1> @<1> Rm VLD3<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[], \vecname[0x22 + param1_1+param1_1 + d]\[]}, [<Rn>], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 1 0 @<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 1 0 @<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 1 0 @<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 1 1 1 1 size @<1> @<1> 1 1 0 1 @ param2_1=1 char align[5] !@ %@ sprintf(align, ":%d", 32 << size)@ align[0] = '\0'@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[], \vecname[0x22 + param1_1+param1_1 + d]\[], \vecname[0x23 + param1_1+param1_1+param1_1 + d]\[]}, [<Rn>\align\]!
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 1 1 size @<1> @<1> 1 1 1 1 @ param2_1=1 char align[5] !@ %@ sprintf(align, ":%d", 32 << size)@ align[0] = '\0'@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[], \vecname[0x22 + param1_1+param1_1 + d]\[], \vecname[0x23 + param1_1+param1_1+param1_1 + d]\[]}, [<Rn>\align\]
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd 1 1 1 1 size @<1> @<1> Rm @ param2_1=1 char align[5] !@ %@ sprintf(align, ":%d", 32 << size)@ align[0] = '\0'@ @ VLD4<c>.\%d8 &l&l size\ {\vecname[0x20 + d]\[], \vecname[0x21 + param1_1 + d]\[], \vecname[0x22 + param1_1+param1_1 + d]\[], \vecname[0x23 + param1_1+param1_1+param1_1 + d]\[]}, [<Rn>\align\], <Rm>
|
||||
NEON 1 1 1 1 0 1 0 0 1 D 1 0 Rn Vd size 1 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 1 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 1 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>
|
||||
ARM_ 1 1 1 1 0 1 0 0 @<1> 0 0 1 Rn @<8> @<4> @<4> 'NOP'
|
||||
ARM_ 1 1 1 1 0 1 0 0 U 1 0 1 Rn (1) (1) (1) (1) imm12 PLI [<Rn>, #+/-<imm12>]
|
||||
ARM_ 1 1 1 1 0 1 0 1 U @<1> 0 1 Rn (1) (1) (1) (1) imm12 PLD\param ? "W" : ""\ [<Rn>, #+/-<imm12>]
|
||||
ARM_ 1 1 1 1 0 1 0 1 U (1) 0 1 1 1 1 1 (1) (1) (1) (1) imm12 PLD [PC, #+/-<imm>]
|
||||
ARM_ 1 1 1 1 0 1 0 1 0 1 1 1 (1) (1) (1) (1) (1) (1) (1) (1) (0) (0) (0) (0) 0 0 0 1 (1) (1) (1) (1) CLREX
|
||||
ARM_ 1 1 1 1 0 1 0 1 0 1 1 1 (1) (1) (1) (1) (1) (1) (1) (1) (0) (0) (0) (0) 0 1 0 0 @<4> @ param=0b1111=0b1110=0b1011=0b1010=0b0111=0b0110=0b0011=0b0010 const char* option option,"SY","ST","ISH","ISHST","NSH","NSHST","OSH","OSHST","!!!"@ @ DSB \option\
|
||||
ARM_ 1 1 1 1 0 1 0 1 0 1 1 1 (1) (1) (1) (1) (1) (1) (1) (1) (0) (0) (0) (0) 0 1 0 1 @<4> @ param=0b1111=0b1110=0b1011=0b1010=0b0111=0b0110=0b0011=0b0010 const char* option option,"SY","ST","ISH","ISHST","NSH","NSHST","OSH","OSHST","!!!"@ @ DMB \option\
|
||||
ARM_ 1 1 1 1 0 1 0 1 0 1 1 1 (1) (1) (1) (1) (1) (1) (1) (1) (0) (0) (0) (0) 0 1 1 0 @<4> @ param=0b1111 const char* option option,"SY","!!!"@ @ ISB \option\
|
||||
ARM_ 1 1 1 1 0 1 1 0 @<1> 0 0 1 Rn @<8> @<3> 0 @<4> 'NOP'
|
||||
ARMs 1 1 1 1 0 1 1 0 U 1 0 1 Rn (1) (1) (1) (1) imm5 type 0 Rm PLI [<Rn>, +/-<Rm>{, <shift>}]
|
||||
ARMs 1 1 1 1 0 1 1 1 U @<1> 0 1 Rn (1) (1) (1) (1) imm5 type 0 Rm PLD\param ? "W" : ""\ [<Rn>, +/-<Rm>{, <shift>}]
|
||||
INVALIDATE 1 1 1 1 0 1 1 1 1 1 1 1 <4> <8> 1 1 1 1 <4>
|
||||
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 0 0 (1) (1) (1) (1) Rd (0) (0) 0 (0) 0 0 0 0 (0) (0) (0) (0) MRS<c> <Rd>, APSR
|
||||
ARM_ cond 0 0 0 1 0 0 1 0 @<2> 0 0 (1) (1) (1) (1) (0) (0) 0 (0) 0 0 0 0 Rn @ param=0b01=0b10 const char* spec_reg spec_reg,"APSR_g","APSR_nzcvq","APSR_nzcvqg"@ @ MSR<c> \spec_reg\, <Rn>
|
||||
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 0 1 1 0 (1) (1) (1) (1) Rd (1) (1) (1) (1) 0 0 0 1 Rm CLZ<c> <Rd>, <Rm>
|
||||
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 0 0 0 0 0 (1) (1) (1) (1) (0) (0) (0) (0) 0 0 0 0 0 0 0 1 YIELD<c>
|
||||
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 1 0 WFE<c>
|
||||
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 1 1 WFI<c>
|
||||
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 1 0 0 SEV<c>
|
||||
ARM_ cond/=1110 0 0 1 1 0 0 1 0 0 0 0 0 (1) (1) (1) (1) (0) (0) (0) (0) 0 0 0 1 0 1 0 0 CSDB<c>
|
||||
ARM_ cond 0 0 1 1 0 0 1 0 0 0 0 0 (1) (1) (1) (1) (0) (0) (0) (0) 1 1 1 1 imm4 DBG<c> #<imm>
|
||||
INVALIDATE <4> 0 0 1 1 0 0 1 0 0 0 0 0 <8> <8>
|
||||
ARM_ cond 0 0 1 1 0 0 1 0 @<2> 0 0 (1) (1) (1) (1) imm12 @ param=0b01=0b10 const char* spec_reg spec_reg,"APSR_g","APSR_nzcvq","APSR_nzcvqg"@ @ MSR<c> \spec_reg\, #<imm>
|
||||
INVALIDATE <4> 0 0 1 1 0 0 1 0 <2> 0 1 <8> <8>
|
||||
INVALIDATE <4> 0 0 1 1 0 0 1 0 <2> 1 <1> <8> <8>
|
||||
INVALIDATE <4> 0 0 1 1 0 1 1 0 <4> <8> <8>
|
||||
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 (1) (1) (1) (1) 0 0 1 1 Rm RBIT<c> <Rd>, <Rm>
|
||||
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>}
|
||||
ARM_ cond 0 1 1 1 0 0 0 1 Rd (1) (1) (1) (1) Rm 0 0 0 1 Rn SDIV<c> <Rd>, <Rn>, <Rm>
|
||||
ARM_ cond 0 1 1 1 0 0 1 1 Rd (1) (1) (1) (1) Rm 0 0 0 1 Rn UDIV<c> <Rd>, <Rn>, <Rm>
|
||||
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/=1110 0 1 1 1 1 1 1 1 imm12 1 1 1 1 imm4 UDF<c> #<imm16>
|
||||
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 @ set imm8*=4@ @ 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 @ set imm8*=4@ @ 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/=1111 1 0 1 0 (0) (0) (0) 1 (0) (0) (0) (0) VMRS<c> APSR_nzcv, FPSCR
|
||||
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 << 4) + (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 U 1 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>
|
||||
+80
-54
@@ -40,6 +40,7 @@ const char* DumpSection(Elf32_Shdr *s, char* SST) {
|
||||
GO(SHT_HIPROC);
|
||||
GO(SHT_LOUSER);
|
||||
GO(SHT_HIUSER);
|
||||
#if defined(SHT_GNU_versym) && defined(SHT_GNU_ATTRIBUTES)
|
||||
GO(SHT_GNU_versym);
|
||||
GO(SHT_GNU_ATTRIBUTES);
|
||||
GO(SHT_GNU_HASH);
|
||||
@@ -51,6 +52,7 @@ const char* DumpSection(Elf32_Shdr *s, char* SST) {
|
||||
GO(SHT_SUNW_syminfo);
|
||||
GO(SHT_GNU_verdef);
|
||||
GO(SHT_GNU_verneed);
|
||||
#endif
|
||||
#undef GO
|
||||
default:
|
||||
sprintf(buff, "0x%X unknown type", s->sh_type);
|
||||
@@ -98,6 +100,7 @@ const char* DumpDynamic(Elf32_Dyn *s) {
|
||||
GO(DT_RUNPATH, 0);
|
||||
GO(DT_FLAGS, 0);
|
||||
GO(DT_ENCODING, 0);
|
||||
#if defined(DT_NUM) && defined(DT_TLSDESC_PLT)
|
||||
GO(DT_NUM, 0);
|
||||
GO(DT_VALRNGLO, 0);
|
||||
GO(DT_GNU_PRELINKED, 0);
|
||||
@@ -133,6 +136,7 @@ const char* DumpDynamic(Elf32_Dyn *s) {
|
||||
GO(DT_VERNEEDNUM, 0);
|
||||
GO(DT_AUXILIARY, 0);
|
||||
GO(DT_FILTER, 0);
|
||||
#endif
|
||||
#undef GO
|
||||
default:
|
||||
sprintf(buff, "0x%X unknown type", s->d_tag);
|
||||
@@ -154,11 +158,13 @@ const char* DumpPHEntry(Elf32_Phdr *e)
|
||||
GO(PT_SHLIB);
|
||||
GO(PT_PHDR);
|
||||
GO(PT_TLS);
|
||||
#ifdef PT_NUM
|
||||
GO(PT_NUM);
|
||||
GO(PT_LOOS);
|
||||
GO(PT_GNU_EH_FRAME);
|
||||
GO(PT_GNU_STACK);
|
||||
GO(PT_GNU_RELRO);
|
||||
#endif
|
||||
#undef GO
|
||||
default: sprintf(buff, "type: %x, Off=%x vaddr=%p paddr=%p filesz=%u memsz=%u flags=%x align=%u", e->p_type, e->p_offset, (void*)e->p_vaddr, (void*)e->p_paddr, e->p_filesz, e->p_memsz, e->p_flags, e->p_align); break;
|
||||
}
|
||||
@@ -187,19 +193,21 @@ const char* DumpRelType(int t)
|
||||
GO(R_386_TLS_GD_32);
|
||||
GO(R_386_TLS_DTPMOD32);
|
||||
GO(R_386_TLS_DTPOFF32);
|
||||
GO(R_386_TLS_TPOFF32);
|
||||
#undef GO
|
||||
default: sprintf(buff, "type: 0x%x (unknown)", t); break;
|
||||
}
|
||||
return buff;
|
||||
}
|
||||
|
||||
const char* DumpSym(elfheader_t *h, Elf32_Sym* sym)
|
||||
const char* DumpSym(elfheader_t *h, Elf32_Sym* sym, int version)
|
||||
{
|
||||
static char buff[4096];
|
||||
const char* vername = (version==-1)?"(none)":((version==0)?"*local*":((version==1)?"*global*":GetSymbolVersion(h, version)));
|
||||
memset(buff, 0, sizeof(buff));
|
||||
sprintf(buff, "\"%s\", value=%p, size=%d, info/other=%d/%d index=%d",
|
||||
sprintf(buff, "\"%s\", value=%p, size=%d, info/other=%d/%d index=%d (ver=%d/%s)",
|
||||
h->DynStr+sym->st_name, (void*)sym->st_value, sym->st_size,
|
||||
sym->st_info, sym->st_other, sym->st_shndx);
|
||||
sym->st_info, sym->st_other, sym->st_shndx, version, vername);
|
||||
return buff;
|
||||
}
|
||||
|
||||
@@ -214,100 +222,118 @@ const char* IdxSymName(elfheader_t *h, int sym)
|
||||
|
||||
void DumpMainHeader(Elf32_Ehdr *header, elfheader_t *h)
|
||||
{
|
||||
if(box86_log>=LOG_DUMP) {
|
||||
printf_log(LOG_DUMP, "ELF Dump main header\n");
|
||||
printf_log(LOG_DUMP, " Entry point = %p\n", (void*)header->e_entry);
|
||||
printf_log(LOG_DUMP, " Program Header table offset = %p\n", (void*)header->e_phoff);
|
||||
printf_log(LOG_DUMP, " Section Header table offset = %p\n", (void*)header->e_shoff);
|
||||
printf_log(LOG_DUMP, " Flags = 0x%X\n", header->e_flags);
|
||||
printf_log(LOG_DUMP, " ELF Header size = %d\n", header->e_ehsize);
|
||||
printf_log(LOG_DUMP, " Program Header Entry num/size = %d(%d)/%d\n", h->numPHEntries, header->e_phnum, header->e_phentsize);
|
||||
printf_log(LOG_DUMP, " Section Header Entry num/size = %d(%d)/%d\n", h->numSHEntries, header->e_shnum, header->e_shentsize);
|
||||
printf_log(LOG_DUMP, " Section Header index num = %d(%d)\n", h->SHIdx, header->e_shstrndx);
|
||||
printf_log(LOG_DUMP, "ELF Dump ==========\n");
|
||||
if(box86_dump) {
|
||||
printf_dump(LOG_NEVER, "ELF Dump main header\n");
|
||||
printf_dump(LOG_NEVER, " Entry point = %p\n", (void*)header->e_entry);
|
||||
printf_dump(LOG_NEVER, " Program Header table offset = %p\n", (void*)header->e_phoff);
|
||||
printf_dump(LOG_NEVER, " Section Header table offset = %p\n", (void*)header->e_shoff);
|
||||
printf_dump(LOG_NEVER, " Flags = 0x%X\n", header->e_flags);
|
||||
printf_dump(LOG_NEVER, " ELF Header size = %d\n", header->e_ehsize);
|
||||
printf_dump(LOG_NEVER, " Program Header Entry num/size = %d(%d)/%d\n", h->numPHEntries, header->e_phnum, header->e_phentsize);
|
||||
printf_dump(LOG_NEVER, " Section Header Entry num/size = %d(%d)/%d\n", h->numSHEntries, header->e_shnum, header->e_shentsize);
|
||||
printf_dump(LOG_NEVER, " Section Header index num = %d(%d)\n", h->SHIdx, header->e_shstrndx);
|
||||
printf_dump(LOG_NEVER, "ELF Dump ==========\n");
|
||||
|
||||
printf_log(LOG_DUMP, "ELF Dump PEntries (%d)\n", h->numSHEntries);
|
||||
printf_dump(LOG_NEVER, "ELF Dump PEntries (%d)\n", h->numSHEntries);
|
||||
for (int i=0; i<h->numPHEntries; ++i)
|
||||
printf_log(LOG_DUMP, " PHEntry %04d : %s\n", i, DumpPHEntry(h->PHEntries+i));
|
||||
printf_log(LOG_DUMP, "ELF Dump PEntries ====\n");
|
||||
printf_dump(LOG_NEVER, " PHEntry %04d : %s\n", i, DumpPHEntry(h->PHEntries+i));
|
||||
printf_dump(LOG_NEVER, "ELF Dump PEntries ====\n");
|
||||
|
||||
printf_log(LOG_DUMP, "ELF Dump Sections (%d)\n", h->numSHEntries);
|
||||
printf_dump(LOG_NEVER, "ELF Dump Sections (%d)\n", h->numSHEntries);
|
||||
for (int i=0; i<h->numSHEntries; ++i)
|
||||
printf_log(LOG_DUMP, " Section %04d : %s\n", i, DumpSection(h->SHEntries+i, h->SHStrTab));
|
||||
printf_log(LOG_DUMP, "ELF Dump Sections ====\n");
|
||||
printf_dump(LOG_NEVER, " Section %04d : %s\n", i, DumpSection(h->SHEntries+i, h->SHStrTab));
|
||||
printf_dump(LOG_NEVER, "ELF Dump Sections ====\n");
|
||||
}
|
||||
}
|
||||
|
||||
void DumpSymTab(elfheader_t *h)
|
||||
{
|
||||
if(box86_log>=LOG_DUMP && h->SymTab) {
|
||||
if(box86_dump && h->SymTab) {
|
||||
const char* name = ElfName(h);
|
||||
printf_log(LOG_DUMP, "ELF Dump SymTab(%d)=\n", h->numSymTab);
|
||||
printf_dump(LOG_NEVER, "ELF Dump SymTab(%d)=\n", h->numSymTab);
|
||||
for (int i=0; i<h->numSymTab; ++i)
|
||||
printf_log(LOG_DUMP, " %s:SymTab[%d] = \"%s\", value=%p, size=%d, info/other=%d/%d index=%d\n", name,
|
||||
printf_dump(LOG_NEVER, " %s:SymTab[%d] = \"%s\", value=%p, size=%d, info/other=%d/%d index=%d\n", name,
|
||||
i, h->StrTab+h->SymTab[i].st_name, (void*)h->SymTab[i].st_value, h->SymTab[i].st_size,
|
||||
h->SymTab[i].st_info, h->SymTab[i].st_other, h->SymTab[i].st_shndx);
|
||||
printf_log(LOG_DUMP, "ELF Dump SymTab=====\n");
|
||||
printf_dump(LOG_NEVER, "ELF Dump SymTab=====\n");
|
||||
}
|
||||
}
|
||||
|
||||
void DumpDynamicSections(elfheader_t *h)
|
||||
{
|
||||
if(box86_log>=LOG_DUMP && h->Dynamic) {
|
||||
printf_log(LOG_DUMP, "ELF Dump Dynamic(%d)=\n", h->numDynamic);
|
||||
if(box86_dump && h->Dynamic) {
|
||||
printf_dump(LOG_NEVER, "ELF Dump Dynamic(%d)=\n", h->numDynamic);
|
||||
for (int i=0; i<h->numDynamic; ++i)
|
||||
printf_log(LOG_DUMP, " Dynamic %04d : %s\n", i, DumpDynamic(h->Dynamic+i));
|
||||
printf_log(LOG_DUMP, "ELF Dump Dynamic=====\n");
|
||||
printf_dump(LOG_NEVER, " Dynamic %04d : %s\n", i, DumpDynamic(h->Dynamic+i));
|
||||
printf_dump(LOG_NEVER, "ELF Dump Dynamic=====\n");
|
||||
}
|
||||
}
|
||||
|
||||
void DumpDynSym(elfheader_t *h)
|
||||
{
|
||||
if(box86_log>=LOG_DUMP && h->DynSym) {
|
||||
if(box86_dump && h->DynSym) {
|
||||
const char* name = ElfName(h);
|
||||
printf_log(LOG_DUMP, "ELF Dump DynSym(%d)=\n", h->numDynSym);
|
||||
for (int i=0; i<h->numDynSym; ++i)
|
||||
printf_log(LOG_DUMP, " %s:DynSym[%d] = %s\n", name, i, DumpSym(h, h->DynSym+i));
|
||||
printf_log(LOG_DUMP, "ELF Dump DynSym=====\n");
|
||||
printf_dump(LOG_NEVER, "ELF Dump DynSym(%d)=\n", h->numDynSym);
|
||||
for (int i=0; i<h->numDynSym; ++i) {
|
||||
int version = h->VerSym?((Elf32_Half*)((uintptr_t)h->VerSym+h->delta))[i]:-1;
|
||||
printf_dump(LOG_NEVER, " %s:DynSym[%d] = %s\n", name, i, DumpSym(h, h->DynSym+i, version));
|
||||
}
|
||||
printf_dump(LOG_NEVER, "ELF Dump DynSym=====\n");
|
||||
}
|
||||
}
|
||||
|
||||
void DumpDynamicNeeded(elfheader_t *h)
|
||||
{
|
||||
if(box86_log>=LOG_DUMP && h->DynStrTab) {
|
||||
printf_log(LOG_DUMP, "ELF Dump DT_NEEDED=====\n");
|
||||
if(box86_dump && h->DynStrTab) {
|
||||
printf_dump(LOG_NEVER, "ELF Dump DT_NEEDED=====\n");
|
||||
for (int i=0; i<h->numDynamic; ++i)
|
||||
if(h->Dynamic[i].d_tag==DT_NEEDED) {
|
||||
printf_log(LOG_DUMP, " Needed : %s\n", h->DynStrTab+h->Dynamic[i].d_un.d_val + h->delta);
|
||||
printf_dump(LOG_NEVER, " Needed : %s\n", h->DynStrTab+h->Dynamic[i].d_un.d_val + h->delta);
|
||||
}
|
||||
printf_log(LOG_DUMP, "ELF Dump DT_NEEDED=====\n");
|
||||
printf_dump(LOG_NEVER, "ELF Dump DT_NEEDED=====\n");
|
||||
}
|
||||
}
|
||||
|
||||
void DumpDynamicRPath(elfheader_t *h)
|
||||
{
|
||||
if(box86_dump && h->DynStrTab) {
|
||||
printf_dump(LOG_NEVER, "ELF Dump DT_RPATH/DT_RUNPATH=====\n");
|
||||
for (int i=0; i<h->numDynamic; ++i) {
|
||||
if(h->Dynamic[i].d_tag==DT_RPATH) {
|
||||
printf_dump(LOG_NEVER, " RPATH : %s\n", h->DynStrTab+h->Dynamic[i].d_un.d_val + h->delta);
|
||||
}
|
||||
if(h->Dynamic[i].d_tag==DT_RUNPATH) {
|
||||
printf_dump(LOG_NEVER, " RUNPATH : %s\n", h->DynStrTab+h->Dynamic[i].d_un.d_val + h->delta);
|
||||
}
|
||||
}
|
||||
printf_dump(LOG_NEVER, "=====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) {
|
||||
if(box86_dump) {
|
||||
const char* elfname = ElfName(h);
|
||||
printf_log(LOG_DUMP, "ELF Dump %s Table(%d) @%p\n", name, cnt, rel);
|
||||
printf_dump(LOG_NEVER, "ELF Dump %s Table(%d) @%p\n", name, cnt, rel);
|
||||
for (int i = 0; i<cnt; ++i)
|
||||
printf_log(LOG_DUMP, " %s:Rel[%d] = %p (0x%X: %s, sym=0x%0X/%s)\n", elfname,
|
||||
printf_dump(LOG_NEVER, " %s:Rel[%d] = %p (0x%X: %s, sym=0x%0X/%s)\n", elfname,
|
||||
i, (void*)rel[i].r_offset, rel[i].r_info, DumpRelType(ELF32_R_TYPE(rel[i].r_info)),
|
||||
ELF32_R_SYM(rel[i].r_info), IdxSymName(h, ELF32_R_SYM(rel[i].r_info)));
|
||||
printf_log(LOG_DUMP, "ELF Dump Rel Table=====\n");
|
||||
printf_dump(LOG_NEVER, "ELF Dump Rel Table=====\n");
|
||||
}
|
||||
}
|
||||
|
||||
void DumpRelATable(elfheader_t *h, int cnt, Elf32_Rela *rela, const char* name)
|
||||
{
|
||||
if(box86_log>=LOG_DUMP && h->rela) {
|
||||
if(box86_dump && h->rela) {
|
||||
const char* elfname = ElfName(h);
|
||||
printf_log(LOG_DUMP, "ELF Dump %s Table(%d) @%p\n", name, cnt, rela);
|
||||
printf_dump(LOG_NEVER, "ELF Dump %s Table(%d) @%p\n", name, cnt, rela);
|
||||
for (int i = 0; i<cnt; ++i)
|
||||
printf_log(LOG_DUMP, " %s:RelA[%d] = %p (0x%X: %s, sym=0x%X/%s) Addend=%d\n", elfname,
|
||||
printf_dump(LOG_NEVER, " %s:RelA[%d] = %p (0x%X: %s, sym=0x%X/%s) Addend=%d\n", elfname,
|
||||
i, (void*)rela[i].r_offset, rela[i].r_info, DumpRelType(ELF32_R_TYPE(rela[i].r_info)),
|
||||
ELF32_R_SYM(rela[i].r_info), IdxSymName(h, ELF32_R_SYM(rela[i].r_info)),
|
||||
rela[i].r_addend);
|
||||
printf_log(LOG_DUMP, "ELF Dump RelA Table=====\n");
|
||||
printf_dump(LOG_NEVER, "ELF Dump RelA Table=====\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -318,24 +344,24 @@ void DumpBinary(char* p, int sz)
|
||||
unsigned char* d = (unsigned char*)p;
|
||||
int delta = ((uintptr_t)p)&0xf;
|
||||
for (int i = 0; sz; ++i) {
|
||||
printf_log(LOG_DUMP, "%p ", (void*)(((uintptr_t)d)&~0xf));
|
||||
printf_dump(LOG_NEVER, "%p ", (void*)(((uintptr_t)d)&~0xf));
|
||||
int n = 16 - delta;
|
||||
if (n>sz) n = sz;
|
||||
int fill = 16-sz;
|
||||
for (int j = 0; j<delta; ++j)
|
||||
printf_log(LOG_DUMP, " ");
|
||||
printf_dump(LOG_NEVER, " ");
|
||||
for (int j = 0; j<n; ++j)
|
||||
printf_log(LOG_DUMP, "%02X ", d[j]);
|
||||
printf_dump(LOG_NEVER, "%02X ", d[j]);
|
||||
for (int j = 0; j<fill; ++j)
|
||||
printf_log(LOG_DUMP, " ");
|
||||
printf_log(LOG_DUMP, " | ");
|
||||
printf_dump(LOG_NEVER, " ");
|
||||
printf_dump(LOG_NEVER, " | ");
|
||||
for (int j = 0; j<delta; ++j)
|
||||
printf_log(LOG_DUMP, " ");
|
||||
printf_dump(LOG_NEVER, " ");
|
||||
for (int j = 0; j<n; ++j)
|
||||
printf_log(LOG_DUMP, "%c", (d[j]<32 || d[j]>127)?'.':d[j]);
|
||||
printf_dump(LOG_NEVER, "%c", (d[j]<32 || d[j]>127)?'.':d[j]);
|
||||
for (int j = 0; j<fill; ++j)
|
||||
printf_log(LOG_DUMP, " ");
|
||||
printf_log(LOG_DUMP, "\n");
|
||||
printf_dump(LOG_NEVER, " ");
|
||||
printf_dump(LOG_NEVER, "\n");
|
||||
d+=n;
|
||||
sz-=n;
|
||||
delta=0;
|
||||
|
||||
+832
-307
File diff suppressed because it is too large.
Load diff
@@ -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;
|
||||
@@ -26,6 +30,12 @@ struct elfheader_s {
|
||||
int numDynamic;
|
||||
char* DynStrTab;
|
||||
int szDynStrTab;
|
||||
Elf32_Half* VerSym;
|
||||
Elf32_Verneed* VerNeed;
|
||||
int szVerNeed;
|
||||
Elf32_Verdef* VerDef;
|
||||
int szVerDef;
|
||||
int e_type;
|
||||
|
||||
intptr_t delta; // should be 0
|
||||
|
||||
@@ -48,7 +58,12 @@ struct elfheader_s {
|
||||
int pltent;
|
||||
uint32_t pltrel;
|
||||
uintptr_t gotplt;
|
||||
uintptr_t gotplt_end;
|
||||
uintptr_t pltgot;
|
||||
uintptr_t got;
|
||||
uintptr_t got_end;
|
||||
uintptr_t plt;
|
||||
uintptr_t plt_end;
|
||||
uintptr_t text;
|
||||
int textsz;
|
||||
|
||||
@@ -58,7 +73,9 @@ struct elfheader_s {
|
||||
uint32_t memsz;
|
||||
uint32_t stacksz;
|
||||
int stackalign;
|
||||
uintptr_t tlsaddr;
|
||||
uint32_t tlssize;
|
||||
uint32_t tlsfilesize;
|
||||
int tlsalign;
|
||||
|
||||
int32_t tlsbase; // the base of the tlsdata in the global tlsdata (always negative)
|
||||
@@ -67,9 +84,13 @@ struct elfheader_s {
|
||||
int fini_done;
|
||||
|
||||
char* memory; // char* and not void* to allow math on memory pointer
|
||||
#ifdef DYNAREC
|
||||
dynablocklist_t *blocks;
|
||||
#endif
|
||||
void** multiblock;
|
||||
uintptr_t* multiblock_offs;
|
||||
uint32_t* multiblock_size;
|
||||
int multiblock_n;
|
||||
|
||||
library_t *lib;
|
||||
needed_libs_t *neededlibs;
|
||||
};
|
||||
|
||||
#define R_386_NONE 0
|
||||
|
||||
+150
-59
@@ -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;
|
||||
@@ -60,8 +61,9 @@ void LoadNamedSection(FILE *f, Elf32_Shdr *s, int size, char* SHStrTab, const ch
|
||||
elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
{
|
||||
Elf32_Ehdr header;
|
||||
int level = (exec)?LOG_INFO:LOG_DEBUG;
|
||||
if(fread(&header, sizeof(Elf32_Ehdr), 1, f)!=1) {
|
||||
printf_log(LOG_INFO, "Cannot read ELF Header\n");
|
||||
printf_log(level, "Cannot read ELF Header\n");
|
||||
return NULL;
|
||||
}
|
||||
if(memcmp(header.e_ident, ELFMAG, SELFMAG)!=0) {
|
||||
@@ -69,11 +71,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) {
|
||||
@@ -91,7 +97,7 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
}
|
||||
|
||||
if(header.e_machine != EM_386) {
|
||||
printf_log(LOG_INFO, "Not an i386 ELF (%d)\n", header.e_machine);
|
||||
printf_log(level, "Not an i386 ELF (%d)\n", header.e_machine);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -114,12 +120,13 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
h->numPHEntries = header.e_phnum;
|
||||
h->numSHEntries = header.e_shnum;
|
||||
h->SHIdx = header.e_shstrndx;
|
||||
if(header.e_shentsize!=0) {
|
||||
h->e_type = header.e_type;
|
||||
if(header.e_shentsize && header.e_shnum) {
|
||||
// special cases for nums
|
||||
if(h->numSHEntries == 0) {
|
||||
printf_log(LOG_DEBUG, "Read number of Sections in 1st Section\n");
|
||||
// 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 +138,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,14 +154,14 @@ 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");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(header.e_shentsize!=0) {
|
||||
if(header.e_shentsize && header.e_shnum) {
|
||||
if(h->SHIdx == SHN_XINDEX) {
|
||||
printf_log(LOG_DEBUG, "Read number of String Table in 1st Section\n");
|
||||
h->SHIdx = h->SHEntries[0].sh_link;
|
||||
@@ -170,40 +177,99 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
FreeElfHeader(&h);
|
||||
return NULL;
|
||||
}
|
||||
if(box86_log>=LOG_DUMP) DumpMainHeader(&header, h);
|
||||
if(box86_dump) DumpMainHeader(&header, h);
|
||||
|
||||
LoadNamedSection(f, h->SHEntries, h->numSHEntries, h->SHStrTab, ".strtab", "SymTab Strings", SHT_STRTAB, (void**)&h->StrTab, NULL);
|
||||
LoadNamedSection(f, h->SHEntries, h->numSHEntries, h->SHStrTab, ".symtab", "SymTab", SHT_SYMTAB, (void**)&h->SymTab, &h->numSymTab);
|
||||
if(box86_log>=LOG_DUMP && h->SymTab) DumpSymTab(h);
|
||||
if(box86_dump && h->SymTab) DumpSymTab(h);
|
||||
|
||||
LoadNamedSection(f, h->SHEntries, h->numSHEntries, h->SHStrTab, ".dynamic", "Dynamic", SHT_DYNAMIC, (void**)&h->Dynamic, &h->numDynamic);
|
||||
if(box86_log>=LOG_DUMP && h->Dynamic) DumpDynamicSections(h);
|
||||
if(box86_dump && h->Dynamic) DumpDynamicSections(h);
|
||||
// grab DT_REL & DT_RELA stuffs
|
||||
// also grab the DT_STRTAB string table
|
||||
{
|
||||
for (int i=0; i<h->numDynamic; ++i) {
|
||||
if(h->Dynamic[i].d_tag == DT_REL)
|
||||
h->rel = h->Dynamic[i].d_un.d_ptr;
|
||||
else if(h->Dynamic[i].d_tag == DT_RELSZ)
|
||||
h->relsz = h->Dynamic[i].d_un.d_val;
|
||||
else if(h->Dynamic[i].d_tag == DT_RELENT)
|
||||
h->relent = h->Dynamic[i].d_un.d_val;
|
||||
else if(h->Dynamic[i].d_tag == DT_RELA)
|
||||
h->rela = h->Dynamic[i].d_un.d_ptr;
|
||||
else if(h->Dynamic[i].d_tag == DT_RELASZ)
|
||||
h->relasz = h->Dynamic[i].d_un.d_val;
|
||||
else if(h->Dynamic[i].d_tag == DT_RELAENT)
|
||||
h->relaent = h->Dynamic[i].d_un.d_val;
|
||||
else if(h->Dynamic[i].d_tag == DT_PLTREL)
|
||||
h->pltrel = h->Dynamic[i].d_un.d_val;
|
||||
else if(h->Dynamic[i].d_tag == DT_PLTRELSZ)
|
||||
h->pltsz = h->Dynamic[i].d_un.d_val;
|
||||
else if(h->Dynamic[i].d_tag == DT_JMPREL)
|
||||
h->jmprel = h->Dynamic[i].d_un.d_val;
|
||||
else if(h->Dynamic[i].d_tag == DT_STRTAB)
|
||||
h->DynStrTab = (char*)(h->Dynamic[i].d_un.d_ptr);
|
||||
else if(h->Dynamic[i].d_tag == DT_STRSZ)
|
||||
h->szDynStrTab = h->Dynamic[i].d_un.d_val;
|
||||
Elf32_Dyn d = h->Dynamic[i];
|
||||
Elf32_Word val = d.d_un.d_val;
|
||||
Elf32_Addr ptr = d.d_un.d_ptr;
|
||||
switch (d.d_tag) {
|
||||
case DT_REL:
|
||||
h->rel = ptr;
|
||||
break;
|
||||
case DT_RELSZ:
|
||||
h->relsz = val;
|
||||
break;
|
||||
case DT_RELENT:
|
||||
h->relent = val;
|
||||
break;
|
||||
case DT_RELA:
|
||||
h->rela = ptr;
|
||||
break;
|
||||
case DT_RELASZ:
|
||||
h->relasz = val;
|
||||
break;
|
||||
case DT_RELAENT:
|
||||
h->relaent = val;
|
||||
break;
|
||||
case DT_PLTGOT:
|
||||
h->pltgot = ptr;
|
||||
break;
|
||||
case DT_PLTREL:
|
||||
h->pltrel = val;
|
||||
break;
|
||||
case DT_PLTRELSZ:
|
||||
h->pltsz = val;
|
||||
break;
|
||||
case DT_JMPREL:
|
||||
h->jmprel = ptr;
|
||||
break;
|
||||
case DT_STRTAB:
|
||||
h->DynStrTab = (char *)(ptr);
|
||||
break;
|
||||
case DT_STRSZ:
|
||||
h->szDynStrTab = val;
|
||||
break;
|
||||
case DT_INIT: // Entry point
|
||||
h->initentry = ptr;
|
||||
printf_log(LOG_DEBUG, "The DT_INIT is at address %p\n", (void*)h->initentry);
|
||||
break;
|
||||
case DT_INIT_ARRAY:
|
||||
h->initarray = ptr;
|
||||
printf_log(LOG_DEBUG, "The DT_INIT_ARRAY is at address %p\n", (void*)h->initarray);
|
||||
break;
|
||||
case DT_INIT_ARRAYSZ:
|
||||
h->initarray_sz = val / sizeof(Elf32_Addr);
|
||||
printf_log(LOG_DEBUG, "The DT_INIT_ARRAYSZ is %d\n", h->initarray_sz);
|
||||
break;
|
||||
case DT_FINI: // Exit hook
|
||||
h->finientry = ptr;
|
||||
printf_log(LOG_DEBUG, "The DT_FINI is at address %p\n", (void*)h->finientry);
|
||||
break;
|
||||
case DT_FINI_ARRAY:
|
||||
h->finiarray = ptr;
|
||||
printf_log(LOG_DEBUG, "The DT_FINI_ARRAY is at address %p\n", (void*)h->finiarray);
|
||||
break;
|
||||
case DT_FINI_ARRAYSZ:
|
||||
h->finiarray_sz = val / sizeof(Elf32_Addr);
|
||||
printf_log(LOG_DEBUG, "The DT_FINI_ARRAYSZ is %d\n", h->finiarray_sz);
|
||||
break;
|
||||
case DT_VERNEEDNUM:
|
||||
h->szVerNeed = val;
|
||||
printf_log(LOG_DEBUG, "The DT_VERNEEDNUM is %d\n", h->szVerNeed);
|
||||
break;
|
||||
case DT_VERNEED:
|
||||
h->VerNeed = (Elf32_Verneed*)ptr;
|
||||
printf_log(LOG_DEBUG, "The DT_VERNEED is at address %p\n", h->VerNeed);
|
||||
break;
|
||||
case DT_VERDEFNUM:
|
||||
h->szVerDef = val;
|
||||
printf_log(LOG_DEBUG, "The DT_VERDEFNUM is %d\n", h->szVerDef);
|
||||
break;
|
||||
case DT_VERDEF:
|
||||
h->VerDef = (Elf32_Verdef*)ptr;
|
||||
printf_log(LOG_DEBUG, "The DT_VERDEF is at address %p\n", h->VerDef);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(h->rel) {
|
||||
if(h->relent != sizeof(Elf32_Rel)) {
|
||||
@@ -246,38 +312,26 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
int ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".got.plt");
|
||||
if(ii) {
|
||||
h->gotplt = h->SHEntries[ii].sh_addr;
|
||||
h->gotplt_end = h->gotplt + h->SHEntries[ii].sh_size;
|
||||
printf_log(LOG_DEBUG, "The GOT.PLT Table is at address %p\n", (void*)h->gotplt);
|
||||
}
|
||||
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".got");
|
||||
if(ii) {
|
||||
h->got = h->SHEntries[ii].sh_addr;
|
||||
printf_log(LOG_DEBUG, "The GOT Table is at address %p\n", (void*)h->got);
|
||||
h->got_end = h->got + h->SHEntries[ii].sh_size;
|
||||
printf_log(LOG_DEBUG, "The GOT Table is at address %p..%p\n", (void*)h->got, (void*)h->got_end);
|
||||
}
|
||||
// look for .init entry point
|
||||
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".init");
|
||||
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".plt");
|
||||
if(ii) {
|
||||
h->initentry = h->SHEntries[ii].sh_addr;
|
||||
printf_log(LOG_DEBUG, "The .init is at address %p\n", (void*)h->initentry);
|
||||
h->plt = h->SHEntries[ii].sh_addr;
|
||||
h->plt_end = h->plt + h->SHEntries[ii].sh_size;
|
||||
printf_log(LOG_DEBUG, "The PLT Table is at address %p..%p\n", (void*)h->plt, (void*)h->plt_end);
|
||||
}
|
||||
// and .init_array
|
||||
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".init_array");
|
||||
// grab version of symbols
|
||||
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".gnu.version");
|
||||
if(ii) {
|
||||
h->initarray_sz = h->SHEntries[ii].sh_size / sizeof(Elf32_Addr);
|
||||
h->initarray = (uintptr_t)(h->SHEntries[ii].sh_addr);
|
||||
printf_log(LOG_DEBUG, "The .init_array is at address %p, and have %d elements\n", (void*)h->initarray, h->initarray_sz);
|
||||
}
|
||||
// look for .fini entry point
|
||||
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".fini");
|
||||
if(ii) {
|
||||
h->finientry = h->SHEntries[ii].sh_addr;
|
||||
printf_log(LOG_DEBUG, "The .fini is at address %p\n", (void*)h->finientry);
|
||||
}
|
||||
// and .fini_array
|
||||
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".fini_array");
|
||||
if(ii) {
|
||||
h->finiarray_sz = h->SHEntries[ii].sh_size / sizeof(Elf32_Addr);
|
||||
h->finiarray = (uintptr_t)(h->SHEntries[ii].sh_addr);
|
||||
printf_log(LOG_DEBUG, "The .fini_array is at address %p, and have %d elements\n", (void*)h->finiarray, h->finiarray_sz);
|
||||
h->VerSym = (Elf32_Half*)(h->SHEntries[ii].sh_addr);
|
||||
printf_log(LOG_DEBUG, "The .gnu.version is at address %p\n", h->VerSym);
|
||||
}
|
||||
// grab .text for main code
|
||||
ii = FindSection(h->SHEntries, h->numSHEntries, h->SHStrTab, ".text");
|
||||
@@ -289,8 +343,45 @@ elfheader_t* ParseElfHeader(FILE* f, const char* name, int exec)
|
||||
|
||||
LoadNamedSection(f, h->SHEntries, h->numSHEntries, h->SHStrTab, ".dynstr", "DynSym Strings", SHT_STRTAB, (void**)&h->DynStr, NULL);
|
||||
LoadNamedSection(f, h->SHEntries, h->numSHEntries, h->SHStrTab, ".dynsym", "DynSym", SHT_DYNSYM, (void**)&h->DynSym, &h->numDynSym);
|
||||
if(box86_log>=LOG_DUMP && h->DynSym) DumpDynSym(h);
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
const char* GetSymbolVersion(elfheader_t* h, int version)
|
||||
{
|
||||
if(!h->VerNeed || (version<2))
|
||||
return NULL;
|
||||
/*if(version==1)
|
||||
return "*";*/
|
||||
Elf32_Verneed *ver = (Elf32_Verneed*)((uintptr_t)h->VerNeed + h->delta);
|
||||
while(ver) {
|
||||
Elf32_Vernaux *aux = (Elf32_Vernaux*)((uintptr_t)ver + ver->vn_aux);
|
||||
for(int j=0; j<ver->vn_cnt; ++j) {
|
||||
if(aux->vna_other==version)
|
||||
return h->DynStr+aux->vna_name;
|
||||
aux = (Elf32_Vernaux*)((uintptr_t)aux + aux->vna_next);
|
||||
}
|
||||
ver = ver->vn_next?((Elf32_Verneed*)((uintptr_t)ver + ver->vn_next)):NULL;
|
||||
}
|
||||
return GetParentSymbolVersion(h, version); // if symbol is "internal", use Def table instead
|
||||
}
|
||||
|
||||
const char* GetParentSymbolVersion(elfheader_t* h, int index)
|
||||
{
|
||||
if(!h->VerDef || (index<1))
|
||||
return NULL;
|
||||
Elf32_Verdef *def = (Elf32_Verdef*)((uintptr_t)h->VerDef + h->delta);
|
||||
while(def) {
|
||||
if(def->vd_ndx==index) {
|
||||
if(def->vd_cnt<1)
|
||||
return NULL;
|
||||
/*if(def->vd_flags&VER_FLG_BASE)
|
||||
return NULL;*/
|
||||
Elf32_Verdaux *aux = (Elf32_Verdaux*)((uintptr_t)def + def->vd_aux);
|
||||
return h->DynStr+aux->vda_name; // return Parent, so 1st aux
|
||||
}
|
||||
def = def->vd_next?((Elf32_Verdef*)((uintptr_t)def + def->vd_next)):NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
+64
-1
@@ -47,10 +47,60 @@
|
||||
base+=(nextop&0x80)?(F32S):(F8S); \
|
||||
A = (T*)(base+O); \
|
||||
}
|
||||
|
||||
#define getecommon16(A, T) \
|
||||
{ \
|
||||
uint32_t m = nextop&0xC7; \
|
||||
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 = F16; break; \
|
||||
case 1: base += F8S; break; \
|
||||
case 2: base += F16S; break; \
|
||||
} \
|
||||
A = (T*)base; \
|
||||
}
|
||||
|
||||
#define getecommon16o(A, T, O) \
|
||||
{ \
|
||||
uint32_t m = nextop&0xC7; \
|
||||
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 = F16; break; \
|
||||
case 1: base += F8S; break; \
|
||||
case 2: base += F16S; break; \
|
||||
} \
|
||||
A = (T*)(base+O); \
|
||||
}
|
||||
|
||||
|
||||
#define geteb(A) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
A = (reg32_t*)&emu->regs[(nextop&3)].byte[((nextop&0x4)>>2)]; \
|
||||
} else getecommon(A, reg32_t)
|
||||
#define getebo(A, O) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
A = (reg32_t*)&emu->regs[(nextop&3)].byte[((nextop&0x4)>>2)]; \
|
||||
} else getecommono(A, reg32_t, O)
|
||||
#define geted(A) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
A = &emu->regs[(nextop&7)]; \
|
||||
@@ -62,17 +112,29 @@
|
||||
#define getem(A) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
A = &emu->mmx[(nextop&7)]; \
|
||||
} else getecommon(A, mmx_regs_t)
|
||||
} else getecommon(A, mmx87_regs_t)
|
||||
#define getex(A) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
A = &emu->xmm[(nextop&7)]; \
|
||||
} else getecommon(A, sse_regs_t)
|
||||
#define getew16(A) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
A = &emu->regs[(nextop&7)]; \
|
||||
} else getecommon16(A, reg32_t)
|
||||
#define getew16o(A, O) \
|
||||
if((nextop&0xC0)==0xC0) { \
|
||||
A = &emu->regs[(nextop&7)]; \
|
||||
} else getecommon16o(A, reg32_t, O)
|
||||
|
||||
// Macros for ModR/M gets
|
||||
#define GET_EB geteb(oped)
|
||||
#define GET_ED geted(oped)
|
||||
#define GET_ED_OFFS(o) getedo(oped, o)
|
||||
#define GET_EB_OFFS(o) getebo(oped, o)
|
||||
#define GET_EM getem(opem)
|
||||
#define GET_EX getex(opex)
|
||||
#define GET_EW16 getew16(oped)
|
||||
#define GET_EW16_OFFS(o) getew16o(oped, o)
|
||||
#define EB oped
|
||||
#define ED oped
|
||||
#define EM opem
|
||||
@@ -84,5 +146,6 @@
|
||||
|
||||
// Alias
|
||||
#define GET_EW GET_ED
|
||||
#define GET_EW_OFFS GET_ED_OFFS
|
||||
#define EW ED
|
||||
#define GW GD
|
||||
+338
-151
@@ -1,7 +1,64 @@
|
||||
opcode = F8;
|
||||
goto *opcodes0f[opcode];
|
||||
_0f_0x00: /* VERx Ed */
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: /* SLDT Ew */
|
||||
GET_EW;
|
||||
EW->word[0] = 0;
|
||||
if((nextop&0xC0)==0xC0)
|
||||
EW->word[1] = 0;
|
||||
break;
|
||||
case 1: /* STR Ew */
|
||||
GET_EW;
|
||||
EW->word[0] = 0x7f; // dummy return
|
||||
if((nextop&0xC0)==0xC0)
|
||||
EW->word[1] = 0;
|
||||
break;
|
||||
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_0x01:
|
||||
nextop = F8;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: /* SGDT Ed */
|
||||
GET_ED;
|
||||
ED->word[0] = 0x7f; // dummy return...
|
||||
ED->word[1] = 0x000c;
|
||||
ED->word[2] = 0xd000;
|
||||
break;
|
||||
case 1: /* SIDT Ed */
|
||||
GET_ED;
|
||||
ED->word[0] = 0xfff; // dummy return, like "disabled"
|
||||
ED->word[1] = 0;
|
||||
ED->word[2] = 0;
|
||||
break;
|
||||
case 4: /* SMSW Ew */
|
||||
GET_ED;
|
||||
// dummy for now... Do I need to track CR0 state?
|
||||
ED->word[0] = (1<<0) | (1<<4); // only PE and ET set...
|
||||
break;
|
||||
default:
|
||||
goto _default;
|
||||
}
|
||||
NEXT;
|
||||
|
||||
_0f_0x0B: /* UD2 */
|
||||
kill(getpid(), SIGILL); // this is undefined instruction
|
||||
emu->old_ip = R_EIP;
|
||||
R_EIP = ip-2;
|
||||
emit_signal(emu, SIGILL, (void*)R_EIP, 0);
|
||||
ip = R_EIP;
|
||||
if(emu->quit) goto fini;
|
||||
STEP;
|
||||
NEXT;
|
||||
_0f_0x10: /* MOVUPS Gx,Ex */
|
||||
nextop = F8;
|
||||
@@ -54,7 +111,27 @@
|
||||
_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_0x1A: /* NOP (multi-byte) / ignored BNDLDX */
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
NEXT;
|
||||
_0f_0x1B: /* NOP (multi-byte) / ignored BNDSTX */
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
NEXT;
|
||||
|
||||
_0f_0x1F: /* NOP (multi-byte) */
|
||||
@@ -96,7 +173,7 @@
|
||||
// rounding should be done; and indefinite integer should also be assigned if overflow or NaN/Inf
|
||||
nextop = F8;
|
||||
GET_EX;
|
||||
switch(emu->round) {
|
||||
switch((emu->mxcsr>>13)&3) {
|
||||
case ROUND_Nearest:
|
||||
GM.sd[1] = floorf(EX->f[1]+0.5f);
|
||||
GM.sd[0] = floorf(EX->f[0]+0.5f);
|
||||
@@ -139,6 +216,109 @@
|
||||
R_EAX = tmp64u&0xFFFFFFFF;
|
||||
NEXT;
|
||||
|
||||
_0f_0x38: // these are some SSE3 opcodes
|
||||
opcode = F8;
|
||||
switch(opcode) {
|
||||
case 0x00: /* PSHUFB */
|
||||
nextop = F8;
|
||||
GET_EM;
|
||||
eam1 = GM;
|
||||
for (int i=0; i<8; ++i) {
|
||||
if(EM->ub[i]&128)
|
||||
GM.ub[i] = 0;
|
||||
else
|
||||
GM.ub[i] = eax1.ub[EM->ub[i]&7];
|
||||
}
|
||||
break;
|
||||
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->sb[i*2+0] + (int32_t)(GM.ub[i*2+1])*EM->sb[i*2+1];
|
||||
GM.sw[i] = (tmp32s>32767)?32767:((tmp32s<-32768)?-32768:tmp32s);
|
||||
}
|
||||
break;
|
||||
case 0x09: /* PSIGNW Gm, Em */
|
||||
nextop = F8;
|
||||
GET_EM;
|
||||
for (int i=0; i<4; ++i) {
|
||||
if (EM->sw[i] < 0) {
|
||||
GM.sw[i] = -GM.sw[i];
|
||||
} else if (EM->sw[i] == 0) {
|
||||
GM.sw[i] = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0x0B: /* PMULHRSW Gm, Em */
|
||||
nextop = F8;
|
||||
GET_EM;
|
||||
for (int i=0; i<4; ++i) {
|
||||
tmp32s = ((((int32_t)(GM.sw[i])*(int32_t)(EM->sw[i]))>>14) + 1)>>1;
|
||||
GM.uw[i] = tmp32s&0xffff;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x1C: /* PABSB Gm, Em */
|
||||
nextop = F8;
|
||||
GET_EM;
|
||||
for (int i=0; i<8; ++i) {
|
||||
GM.sb[i] = abs(EM->sb[i]);
|
||||
}
|
||||
break;
|
||||
case 0x1D: /* PABSW Gm, Em */
|
||||
nextop = F8;
|
||||
GET_EM;
|
||||
for (int i=0; i<4; ++i) {
|
||||
GM.sw[i] = abs(EM->sw[i]);
|
||||
}
|
||||
break;
|
||||
case 0x1E: /* PABSD Gm, Em */
|
||||
nextop = F8;
|
||||
GET_EM;
|
||||
for (int i=0; i<2; ++i) {
|
||||
GM.sd[i] = abs(EM->sd[i]);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
goto _default;
|
||||
}
|
||||
NEXT;
|
||||
|
||||
_0f_0x3A:
|
||||
opcode = F8;
|
||||
switch(opcode) {
|
||||
case 0xF: /* palignr */
|
||||
nextop = F8;
|
||||
GET_EM;
|
||||
tmp8u = F8;
|
||||
if (tmp8u >= 16) {
|
||||
GM.q = 0;
|
||||
} else if (tmp8u > 8) {
|
||||
tmp8u -= 8;
|
||||
GM.q >>= tmp8u*8;
|
||||
} else if (tmp8u == 8 || tmp8u == 0) {
|
||||
|
||||
} else {
|
||||
GM.q <<= (8-tmp8u)*8;
|
||||
GM.q |= (EM->q >> tmp8u*8);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
goto _default;
|
||||
}
|
||||
NEXT;
|
||||
|
||||
_0f_0x3F:
|
||||
emu->old_ip = R_EIP;
|
||||
R_EIP = ip-2;
|
||||
emit_signal(emu, SIGILL, (void*)R_EIP, 0);
|
||||
ip = R_EIP;
|
||||
if(emu->quit) goto fini;
|
||||
STEP;
|
||||
NEXT;
|
||||
|
||||
#define GOCOND(BASE, PREFIX, CONDITIONAL) \
|
||||
_0f_##BASE##_0: \
|
||||
PREFIX \
|
||||
@@ -372,10 +552,14 @@
|
||||
GM.sb[1] = (GM.sw[1] > 127) ? 127 : ((GM.sw[1] < -128) ? -128 : GM.sw[1]);
|
||||
GM.sb[2] = (GM.sw[2] > 127) ? 127 : ((GM.sw[2] < -128) ? -128 : GM.sw[2]);
|
||||
GM.sb[3] = (GM.sw[3] > 127) ? 127 : ((GM.sw[3] < -128) ? -128 : GM.sw[3]);
|
||||
GM.sb[4] = (EM->sw[0] > 127) ? 127 : ((EM->sw[0] < -128) ? -128 : EM->sw[0]);
|
||||
GM.sb[5] = (EM->sw[1] > 127) ? 127 : ((EM->sw[1] < -128) ? -128 : EM->sw[1]);
|
||||
GM.sb[6] = (EM->sw[2] > 127) ? 127 : ((EM->sw[2] < -128) ? -128 : EM->sw[2]);
|
||||
GM.sb[7] = (EM->sw[3] > 127) ? 127 : ((EM->sw[3] < -128) ? -128 : EM->sw[3]);
|
||||
if(EM==&GM)
|
||||
GM.ud[1] = GM.ud[0];
|
||||
else {
|
||||
GM.sb[4] = (EM->sw[0] > 127) ? 127 : ((EM->sw[0] < -128) ? -128 : EM->sw[0]);
|
||||
GM.sb[5] = (EM->sw[1] > 127) ? 127 : ((EM->sw[1] < -128) ? -128 : EM->sw[1]);
|
||||
GM.sb[6] = (EM->sw[2] > 127) ? 127 : ((EM->sw[2] < -128) ? -128 : EM->sw[2]);
|
||||
GM.sb[7] = (EM->sw[3] > 127) ? 127 : ((EM->sw[3] < -128) ? -128 : EM->sw[3]);
|
||||
}
|
||||
NEXT;
|
||||
_0f_0x64: /* PCMPGTB Gm,Em */
|
||||
nextop = F8;
|
||||
@@ -403,33 +587,42 @@
|
||||
GET_EM;
|
||||
for(int i=0; i<4; ++i)
|
||||
GM.ub[i] = (GM.sw[i]<0)?0:((GM.sw[i]>0xff)?0xff:GM.sw[i]);
|
||||
for(int i=0; i<4; ++i)
|
||||
GM.ub[4+i] = (EM->sw[i]<0)?0:((EM->sw[i]>0xff)?0xff:EM->sw[i]);
|
||||
if(EM==&GM)
|
||||
GM.ud[1] = GM.ud[0];
|
||||
else
|
||||
for(int i=0; i<4; ++i)
|
||||
GM.ub[4+i] = (EM->sw[i]<0)?0:((EM->sw[i]>0xff)?0xff:EM->sw[i]);
|
||||
NEXT;
|
||||
_0f_0x68: /* PUNPCKHBW Gm,Em */
|
||||
nextop = F8;
|
||||
GET_EM;
|
||||
if(EM==&GM) {eam1 = GM; EM = &eam1;} // copy is needed
|
||||
for(int i=0; i<4; ++i)
|
||||
GM.ub[2 * i] = GM.ub[i + 4];
|
||||
for(int i=0; i<4; ++i)
|
||||
GM.ub[2 * i + 1] = EM->ub[i + 4];
|
||||
if(EM==&GM)
|
||||
for(int i=0; i<4; ++i)
|
||||
GM.ub[2 * i + 1] = GM.ub[2 * i];
|
||||
else
|
||||
for(int i=0; i<4; ++i)
|
||||
GM.ub[2 * i + 1] = EM->ub[i + 4];
|
||||
NEXT;
|
||||
_0f_0x69: /* PUNPCKHWD Gm,Em */
|
||||
nextop = F8;
|
||||
GET_EM;
|
||||
if(EM==&GM) {eam1 = GM; EM = &eam1;} // copy is needed
|
||||
for(int i=0; i<2; ++i)
|
||||
GM.uw[2 * i] = GM.uw[i + 2];
|
||||
for(int i=0; i<2; ++i)
|
||||
GM.uw[2 * i + 1] = EM->uw[i + 2];
|
||||
if(EM==&GM)
|
||||
for(int i=0; i<2; ++i)
|
||||
GM.uw[2 * i + 1] = GM.uw[2 * i];
|
||||
else
|
||||
for(int i=0; i<2; ++i)
|
||||
GM.uw[2 * i + 1] = EM->uw[i + 2];
|
||||
NEXT;
|
||||
_0f_0x6A: /* PUNPCKHDQ Gm,Em */
|
||||
nextop = F8;
|
||||
GET_EM;
|
||||
if(EM==&GM) {eam1 = GM; EM = &eam1;} // copy is needed
|
||||
GM.ud[0] = GM.ud[1];
|
||||
GM.ud[1] = EM->ud[1];
|
||||
if(EM!=&GM)
|
||||
GM.ud[1] = EM->ud[1];
|
||||
NEXT;
|
||||
_0f_0x6B: /* PACKSSDW Gm,Em */
|
||||
nextop = F8;
|
||||
@@ -437,8 +630,11 @@
|
||||
if(EM==&GM) {eam1 = GM; EM = &eam1;} // copy is needed
|
||||
for(int i=0; i<2; ++i)
|
||||
GM.sw[i] = (GM.sd[i]<-32768)?-32768:((GM.sd[i]>32767)?32767:GM.sd[i]);
|
||||
for(int i=0; i<2; ++i)
|
||||
GM.sw[2+i] = (EM->sd[i]<-32768)?-32768:((EM->sd[i]>32767)?32767:EM->sd[i]);
|
||||
if(EM==&GM)
|
||||
GM.ud[1] = GM.ud[0];
|
||||
else
|
||||
for(int i=0; i<2; ++i)
|
||||
GM.sw[2+i] = (EM->sd[i]<-32768)?-32768:((EM->sd[i]>32767)?32767:EM->sd[i]);
|
||||
NEXT;
|
||||
|
||||
_0f_0x6E: /* MOVD Gm, Ed */
|
||||
@@ -571,106 +767,28 @@
|
||||
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_serial[_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);
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
tmp8u = GD.byte[0];
|
||||
tmp32s = GD.sdword[0];
|
||||
tmp8u=tmp32s&31;
|
||||
tmp32s >>= 5;
|
||||
if((nextop&0xC0)!=0xC0)
|
||||
{
|
||||
ED=(reg32_t*)(((uint32_t*)(ED))+(tmp8u>>5));
|
||||
ED=(reg32_t*)(((uint32_t*)(ED))+tmp32s);
|
||||
}
|
||||
tmp8u&=31;
|
||||
if(ED->dword[0] & (1<<tmp8u))
|
||||
SET_FLAG(F_CF);
|
||||
else
|
||||
@@ -684,16 +802,26 @@
|
||||
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_serial[_GS] = 0;
|
||||
NEXT;
|
||||
|
||||
|
||||
_0f_0xAB: /* BTS Ed,Gd */
|
||||
CHECK_FLAGS(emu);
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
tmp8u = GD.byte[0];
|
||||
tmp32s = GD.sdword[0];
|
||||
tmp8u=tmp32s&31;
|
||||
tmp32s >>= 5;
|
||||
if((nextop&0xC0)!=0xC0)
|
||||
{
|
||||
ED=(reg32_t*)(((uint32_t*)(ED))+(tmp8u>>5));
|
||||
ED=(reg32_t*)(((uint32_t*)(ED))+tmp32s);
|
||||
}
|
||||
tmp8u&=31;
|
||||
if(ED->dword[0] & (1<<tmp8u))
|
||||
SET_FLAG(F_CF);
|
||||
else {
|
||||
@@ -723,18 +851,10 @@
|
||||
GET_ED;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: /* FXSAVE m512byte */
|
||||
// should save flags & all
|
||||
// copy MMX regs...
|
||||
memcpy(ED->dword+32/4, &emu->mmx[0], sizeof(emu->mmx));
|
||||
// copy SSE regs
|
||||
memcpy(ED->dword+160/4, &emu->xmm[0], sizeof(emu->xmm));
|
||||
fpu_fxsave(emu, ED);
|
||||
break;
|
||||
case 1: /* FXRSTOR m512byte */
|
||||
// should restore flags & all
|
||||
// copy MMX regs...
|
||||
memcpy(&emu->mmx[0], ED->dword+32/4, sizeof(emu->mmx));
|
||||
// copy SSE regs
|
||||
memcpy(&emu->xmm[0], ED->dword+160/4, sizeof(emu->xmm));
|
||||
fpu_fxrstor(emu, ED);
|
||||
break;
|
||||
case 2: /* LDMXCSR Md */
|
||||
emu->mxcsr = ED->dword[0];
|
||||
@@ -752,7 +872,6 @@
|
||||
GD.dword[0] = imul32(emu, GD.dword[0], ED->dword[0]);
|
||||
NEXT;
|
||||
_0f_0xB0: /* CMPXCHG Eb,Gb */
|
||||
CHECK_FLAGS(emu);
|
||||
nextop = F8;
|
||||
GET_EB;
|
||||
cmp8(emu, R_AL, EB->byte[0]);
|
||||
@@ -777,12 +896,13 @@
|
||||
CHECK_FLAGS(emu);
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
tmp8u = GD.byte[0];
|
||||
tmp32s = GD.sdword[0];
|
||||
tmp8u=tmp32s&31;
|
||||
tmp32s >>= 5;
|
||||
if((nextop&0xC0)!=0xC0)
|
||||
{
|
||||
ED=(reg32_t*)(((uint32_t*)(ED))+(tmp8u>>5));
|
||||
ED=(reg32_t*)(((uint32_t*)(ED))+tmp32s);
|
||||
}
|
||||
tmp8u&=31;
|
||||
if(ED->dword[0] & (1<<tmp8u)) {
|
||||
SET_FLAG(F_CF);
|
||||
ED->dword[0] ^= (1<<tmp8u);
|
||||
@@ -808,24 +928,28 @@
|
||||
CHECK_FLAGS(emu);
|
||||
GET_ED;
|
||||
tmp8u = F8;
|
||||
if((nextop&0xC0)!=0xC0)
|
||||
{
|
||||
ED=(reg32_t*)(((uint32_t*)(ED))+(tmp8u>>5));
|
||||
}
|
||||
tmp8u&=31;
|
||||
if(ED->dword[0] & (1<<tmp8u))
|
||||
SET_FLAG(F_CF);
|
||||
else
|
||||
CLEAR_FLAG(F_CF);
|
||||
break;
|
||||
case 5: /* BTS Ed, Ib */
|
||||
CHECK_FLAGS(emu);
|
||||
GET_ED;
|
||||
tmp8u = F8;
|
||||
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;
|
||||
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);
|
||||
@@ -833,6 +957,17 @@
|
||||
} else
|
||||
CLEAR_FLAG(F_CF);
|
||||
break;
|
||||
case 7: /* BTC Ed, Ib */
|
||||
CHECK_FLAGS(emu);
|
||||
GET_ED;
|
||||
tmp8u = F8;
|
||||
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;
|
||||
@@ -842,12 +977,13 @@
|
||||
CHECK_FLAGS(emu);
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
tmp8u = GD.byte[0];
|
||||
tmp32s = GD.sdword[0];
|
||||
tmp8u=tmp32s&31;
|
||||
tmp32s >>= 5;
|
||||
if((nextop&0xC0)!=0xC0)
|
||||
{
|
||||
ED=(reg32_t*)(((uint32_t*)(ED))+(tmp8u>>5));
|
||||
ED=(reg32_t*)(((uint32_t*)(ED))+tmp32s);
|
||||
}
|
||||
tmp8u&=31;
|
||||
if(ED->dword[0] & (1<<tmp8u))
|
||||
SET_FLAG(F_CF);
|
||||
else
|
||||
@@ -926,7 +1062,11 @@
|
||||
GX.ud[i]=(tmp8s)?0xffffffff:0;
|
||||
}
|
||||
NEXT;
|
||||
|
||||
_0f_0xC3: /* MOVNTI Ed,Gd */
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
ED->dword[0] = GD.dword[0];
|
||||
NEXT;
|
||||
_0f_0xC4: /* PINSRW Gm,Ew,Ib */
|
||||
nextop = F8;
|
||||
GET_ED;
|
||||
@@ -1021,6 +1161,17 @@
|
||||
}
|
||||
NEXT;
|
||||
|
||||
_0f_0xD7: /* PMOVMSKB Gd,Em */
|
||||
nextop = F8;
|
||||
if((nextop&0xC0)==0xC0) {
|
||||
GET_EM;
|
||||
GD.dword[0] = 0;
|
||||
for (int i=0; i<8; ++i)
|
||||
if(EM->ub[i]&0x80)
|
||||
GD.dword[0] |= (1<<i);
|
||||
NEXT;
|
||||
} else
|
||||
goto _default;
|
||||
_0f_0xD8: /* PSUBUSB Gm,Em */
|
||||
nextop = F8;
|
||||
GET_EM;
|
||||
@@ -1037,7 +1188,12 @@
|
||||
GM.uw[i] = (tmp32s < 0) ? 0 : tmp32s;
|
||||
}
|
||||
NEXT;
|
||||
|
||||
_0f_0xDA: /* PMINUB Gm,Em */
|
||||
nextop = F8;
|
||||
GET_EM;
|
||||
for (int i=0; i<8; ++i)
|
||||
GM.ub[i] = (GM.ub[i]<EM->ub[i])?GM.ub[i]:EM->ub[i];
|
||||
NEXT;
|
||||
_0f_0xDB: /* PAND Gm,Em */
|
||||
nextop = F8;
|
||||
GET_EM;
|
||||
@@ -1059,7 +1215,12 @@
|
||||
GM.uw[i] = (tmp32u>65535) ? 65535 : tmp32u;
|
||||
}
|
||||
NEXT;
|
||||
|
||||
_0f_0xDE: /* PMAXUB Gm,Em */
|
||||
nextop = F8;
|
||||
GET_EM;
|
||||
for (int i=0; i<8; ++i)
|
||||
GM.ub[i] = (GM.ub[i]>EM->ub[i])?GM.ub[i]:EM->ub[i];
|
||||
NEXT;
|
||||
_0f_0xDF: /* PANDN Gm,Em */
|
||||
nextop = F8;
|
||||
GET_EM;
|
||||
@@ -1093,20 +1254,17 @@
|
||||
GM.sd[i] >>= tmp8u;
|
||||
}
|
||||
NEXT;
|
||||
_0f_0xE3: /* PSRAQ Gm, Em */
|
||||
_0f_0xE3: /* PAVGW Gm, Em */
|
||||
nextop = F8;
|
||||
GET_EM;
|
||||
if(EM->q>63)
|
||||
tmp8u = 64;
|
||||
else
|
||||
tmp8u = EM->ub[0];
|
||||
GM.sq >>= tmp8u;
|
||||
for(int i=0; i<4; ++i)
|
||||
GM.uw[i] = ((uint32_t)GM.uw[i]+EM->uw[i]+1)>>1;
|
||||
NEXT;
|
||||
_0f_0xE4: /* PMULHUW Gm, Em */
|
||||
nextop = F8;
|
||||
GET_EM;
|
||||
for(int i=0; i<4; ++i) {
|
||||
tmp32u = (int32_t)GM.uw[i] * EM->uw[i];
|
||||
tmp32u = (uint32_t)GM.uw[i] * EM->uw[i];
|
||||
GM.uw[i] = (tmp32u>>16)&0xffff;
|
||||
}
|
||||
NEXT;
|
||||
@@ -1119,6 +1277,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 +1300,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 +1327,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 +1390,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;
|
||||
@@ -1234,7 +1417,11 @@
|
||||
for(int i=0; i<2; ++i)
|
||||
GM.sd[i] -= EM->sd[i];
|
||||
NEXT;
|
||||
|
||||
_0f_0xFB: /* PSUBQ Gm,Em */
|
||||
nextop = F8;
|
||||
GET_EM;
|
||||
GM.sq -= EM->sq;
|
||||
NEXT;
|
||||
_0f_0xFC: /* PADDB Gm, Em */
|
||||
nextop = F8;
|
||||
GET_EM;
|
||||
|
||||
+128
-12
@@ -2,16 +2,29 @@
|
||||
goto *opcodes66[opcode];
|
||||
|
||||
#define GO(B, OP) \
|
||||
_66_##B##_0: \
|
||||
nextop = F8; \
|
||||
GET_EB; \
|
||||
EB->byte[0] = OP##8(emu, EB->byte[0], GB); \
|
||||
NEXT; \
|
||||
_66_##B##_1: \
|
||||
nextop = F8; \
|
||||
GET_EW; \
|
||||
EW->word[0] = OP##16(emu, EW->word[0], GW.word[0]); \
|
||||
NEXT; \
|
||||
_66_##B##_2: \
|
||||
nextop = F8; \
|
||||
GET_EB; \
|
||||
GB = OP##8(emu, GB, EB->byte[0]); \
|
||||
NEXT; \
|
||||
_66_##B##_3: \
|
||||
nextop = F8; \
|
||||
GET_EW; \
|
||||
GW.word[0] = OP##16(emu, GW.word[0], EW->word[0]); \
|
||||
NEXT; \
|
||||
_66_##B##_4: \
|
||||
R_AL = OP##8(emu, R_AL, F8); \
|
||||
NEXT; \
|
||||
_66_##B##_5: \
|
||||
R_AX = OP##16(emu, R_AX, F16); \
|
||||
NEXT;
|
||||
@@ -30,17 +43,36 @@
|
||||
NEXT;
|
||||
_66_0x07: /* POP ES */
|
||||
emu->segs[_ES] = Pop16(emu); // no check, no use....
|
||||
emu->segs_serial[_ES] = 0;
|
||||
NEXT;
|
||||
|
||||
_66_0x0F: /* 66 0f prefix */
|
||||
#include "run660f.h"
|
||||
emu->old_ip = R_EIP;
|
||||
R_EIP = ip-2; // don't count 66 0F yet
|
||||
Run660F(emu); // implemented in Run660f.c
|
||||
ip = R_EIP;
|
||||
if(emu->quit) goto fini;
|
||||
STEP
|
||||
NEXT;
|
||||
|
||||
_66_0x1F: /* POP DS */
|
||||
emu->segs[_DS] = Pop16(emu); // no check, no use....
|
||||
emu->segs_serial[_DS] = 0;
|
||||
NEXT;
|
||||
|
||||
_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 +131,34 @@
|
||||
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_0x64:
|
||||
R_EIP = ip-2;
|
||||
RunFS66(emu, GetFSBaseEmu(emu));
|
||||
ip = R_EIP;
|
||||
STEP;
|
||||
NEXT;
|
||||
|
||||
_66_0x66:
|
||||
goto _0x66; // 0x66 0x66 => can remove one 0x66
|
||||
@@ -174,13 +234,14 @@
|
||||
_66_0x8C: /* MOV Ew,Seg */
|
||||
nextop = F8;
|
||||
GET_EW;
|
||||
EW->word[0] = emu->segs[(nextop&38)>>3];
|
||||
EW->word[0] = emu->segs[(nextop&0x38)>>3];
|
||||
NEXT;
|
||||
|
||||
_66_0x8E: /* MOV Seg,Ew */
|
||||
nextop = F8;
|
||||
GET_EW;
|
||||
emu->segs[((nextop&0x38)>>3)] = EW->word[0];
|
||||
emu->segs_serial[((nextop&0x38)>>3)] = 0;
|
||||
NEXT;
|
||||
_66_0x8F: /* POP Ew */
|
||||
nextop = F8;
|
||||
@@ -190,10 +251,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 */
|
||||
@@ -205,8 +272,12 @@
|
||||
|
||||
_66_0x9C: /* PUSHFW */
|
||||
CHECK_FLAGS(emu);
|
||||
PackFlags(emu);
|
||||
Push16(emu, (uint16_t)emu->packed_eflags.x32);
|
||||
Push16(emu, (uint16_t)emu->eflags.x32);
|
||||
NEXT;
|
||||
_66_0x9D: /* POPFW */
|
||||
CHECK_FLAGS(emu);
|
||||
emu->eflags.x32 &=0xffff0000;
|
||||
emu->eflags.x32 |= (Pop16(emu) & 0x3F7FD7) | 0x2;
|
||||
NEXT;
|
||||
|
||||
_66_0xA1: /* MOV AX,Ow */
|
||||
@@ -284,6 +355,22 @@
|
||||
EW->word[0] = F16;
|
||||
NEXT;
|
||||
|
||||
_66_0xCB: /* FAR RET */
|
||||
ip = Pop(emu);
|
||||
emu->segs[_CS] = Pop(emu); // no check, no use....
|
||||
emu->segs_serial[_CS] = 0;
|
||||
// need to check status of CS register!
|
||||
STEP
|
||||
NEXT;
|
||||
_66_0xCC: /* INT3 */
|
||||
emu->old_ip = R_EIP;
|
||||
R_EIP = ip-1;
|
||||
if(my_context->signals[SIGTRAP])
|
||||
raise(SIGTRAP);
|
||||
ip = R_EIP;
|
||||
if(emu->quit) goto fini;
|
||||
STEP
|
||||
NEXT;
|
||||
_66_0xD1: /* GRP2 Ew,1 */
|
||||
_66_0xD3: /* GRP2 Ew,CL */
|
||||
nextop = F8;
|
||||
@@ -302,21 +389,31 @@
|
||||
NEXT;
|
||||
|
||||
_66_0xD9:
|
||||
emu->old_ip = old_ip;
|
||||
emu->old_ip = R_EIP;
|
||||
R_EIP = ip;
|
||||
Run66D9(emu);
|
||||
ip = R_EIP;
|
||||
if(emu->quit) goto fini;
|
||||
STEP
|
||||
NEXT;
|
||||
|
||||
_66_0xDD:
|
||||
emu->old_ip = old_ip;
|
||||
emu->old_ip = R_EIP;
|
||||
R_EIP = ip;
|
||||
Run66DD(emu);
|
||||
ip = R_EIP;
|
||||
if(emu->quit) goto fini;
|
||||
STEP
|
||||
NEXT;
|
||||
|
||||
_66_0xF0: /* LOCK prefix */
|
||||
emu->old_ip = R_EIP;
|
||||
R_EIP = ip - 2;
|
||||
RunLock66(emu);
|
||||
ip = R_EIP;
|
||||
if(emu->quit) goto fini;
|
||||
STEP
|
||||
NEXT;
|
||||
|
||||
_66_0xF2: /* REPNZ prefix */
|
||||
_66_0xF3: /* REPZ prefix */
|
||||
@@ -324,6 +421,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 +510,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 +529,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;
|
||||
|
||||
-1068
File diff suppressed because it is too large.
Load diff
+8
-88
@@ -10,11 +10,7 @@
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7: /* FADD */
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f += ST(nextop&7).f;
|
||||
#else
|
||||
ST0.d += ST(nextop&7).d;
|
||||
#endif
|
||||
break;
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
@@ -24,11 +20,7 @@
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF: /* FMUL */
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f *= ST(nextop&7).f;
|
||||
#else
|
||||
ST0.d *= ST(nextop&7).d;
|
||||
#endif
|
||||
break;
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
@@ -38,11 +30,7 @@
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7: /* FCOM */
|
||||
#ifdef USE_FLOAT
|
||||
fpu_fcom(emu, ST(nextop&7).f);
|
||||
#else
|
||||
fpu_fcom(emu, ST(nextop&7).d);
|
||||
#endif
|
||||
break;
|
||||
case 0xD8:
|
||||
case 0xD9:
|
||||
@@ -52,11 +40,7 @@
|
||||
case 0xDD:
|
||||
case 0xDE:
|
||||
case 0xDF: /* FCOMP */
|
||||
#ifdef USE_FLOAT
|
||||
fpu_fcom(emu, ST(nextop&7).f);
|
||||
#else
|
||||
fpu_fcom(emu, ST(nextop&7).d);
|
||||
#endif
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 0xE0:
|
||||
@@ -67,11 +51,7 @@
|
||||
case 0xE5:
|
||||
case 0xE6:
|
||||
case 0xE7: /* FSUB */
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f -= ST(nextop&7).f;
|
||||
#else
|
||||
ST0.d -= ST(nextop&7).d;
|
||||
#endif
|
||||
break;
|
||||
case 0xE8:
|
||||
case 0xE9:
|
||||
@@ -81,11 +61,7 @@
|
||||
case 0xED:
|
||||
case 0xEE:
|
||||
case 0xEF: /* FSUBR */
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = ST(nextop&7).f - ST0.f;
|
||||
#else
|
||||
ST0.d = ST(nextop&7).d - ST0.d;
|
||||
#endif
|
||||
break;
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
@@ -95,11 +71,7 @@
|
||||
case 0xF5:
|
||||
case 0xF6:
|
||||
case 0xF7: /* FDIV */
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f /= ST(nextop&7).f;
|
||||
#else
|
||||
ST0.d /= ST(nextop&7).d;
|
||||
#endif
|
||||
break;
|
||||
case 0xF8:
|
||||
case 0xF9:
|
||||
@@ -109,46 +81,26 @@
|
||||
case 0xFD:
|
||||
case 0xFE:
|
||||
case 0xFF: /* FDIVR */
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = ST(nextop&7).f / ST0.f;
|
||||
#else
|
||||
ST0.d = ST(nextop&7).d / ST0.d;
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: /* FADD ST0, float */
|
||||
GET_ED;
|
||||
if(!(((uintptr_t)ED)&3))
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f += *(float*)ED;
|
||||
#else
|
||||
ST0.d += *(float*)ED;
|
||||
#endif
|
||||
else {
|
||||
*(uint32_t*)&f = ED->dword[0];
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f += f;
|
||||
#else
|
||||
memcpy(&f, ED, sizeof(float));
|
||||
ST0.d += f;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case 1: /* FMUL ST0, float */
|
||||
GET_ED;
|
||||
if(!(((uintptr_t)ED)&3))
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f *= *(float*)ED;
|
||||
#else
|
||||
ST0.d *= *(float*)ED;
|
||||
#endif
|
||||
else {
|
||||
*(uint32_t*)&f = ED->dword[0];
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f *= f;
|
||||
#else
|
||||
memcpy(&f, ED, sizeof(float));
|
||||
ST0.d *= f;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case 2: /* FCOM ST0, float */
|
||||
@@ -156,7 +108,7 @@
|
||||
if(!(((uintptr_t)ED)&3))
|
||||
fpu_fcom(emu, *(float*)ED);
|
||||
else {
|
||||
*(uint32_t*)&f = ED->dword[0];
|
||||
memcpy(&f, ED, sizeof(float));
|
||||
fpu_fcom(emu, f);
|
||||
}
|
||||
break;
|
||||
@@ -165,7 +117,7 @@
|
||||
if(!(((uintptr_t)ED)&3))
|
||||
fpu_fcom(emu, *(float*)ED);
|
||||
else {
|
||||
*(uint32_t*)&f = ED->dword[0];
|
||||
memcpy(&f, ED, sizeof(float));
|
||||
fpu_fcom(emu, f);
|
||||
}
|
||||
fpu_do_pop(emu);
|
||||
@@ -173,69 +125,37 @@
|
||||
case 4: /* FSUB ST0, float */
|
||||
GET_ED;
|
||||
if(!(((uintptr_t)ED)&3))
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f -= *(float*)ED;
|
||||
#else
|
||||
ST0.d -= *(float*)ED;
|
||||
#endif
|
||||
else {
|
||||
*(uint32_t*)&f = ED->dword[0];
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f -= f;
|
||||
#else
|
||||
memcpy(&f, ED, sizeof(float));
|
||||
ST0.d -= f;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case 5: /* FSUBR ST0, float */
|
||||
GET_ED;
|
||||
if(!(((uintptr_t)ED)&3))
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = *(float*)ED - ST0.f;
|
||||
#else
|
||||
ST0.d = *(float*)ED - ST0.d;
|
||||
#endif
|
||||
else {
|
||||
*(uint32_t*)&f = ED->dword[0];
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = f - ST0.f;
|
||||
#else
|
||||
memcpy(&f, ED, sizeof(float));
|
||||
ST0.d = f - ST0.d;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case 6: /* FDIV ST0, float */
|
||||
GET_ED;
|
||||
if(!(((uintptr_t)ED)&3))
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f /= *(float*)ED;
|
||||
#else
|
||||
ST0.d /= *(float*)ED;
|
||||
#endif
|
||||
else {
|
||||
*(uint32_t*)&f = ED->dword[0];
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f /= f;
|
||||
#else
|
||||
memcpy(&f, ED, sizeof(float));
|
||||
ST0.d /= f;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case 7: /* FDIVR ST0, float */
|
||||
GET_ED;
|
||||
if(!(((uintptr_t)ED)&3))
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = *(float*)ED / ST0.f;
|
||||
#else
|
||||
ST0.d = *(float*)ED / ST0.d;
|
||||
#endif
|
||||
else {
|
||||
*(uint32_t*)&f = ED->dword[0];
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = f / ST0.f;
|
||||
#else
|
||||
memcpy(&f, ED, sizeof(float));
|
||||
ST0.d = f / ST0.d;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
||||
+65
-137
@@ -1,5 +1,3 @@
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
|
||||
nextop = F8;
|
||||
switch (nextop) {
|
||||
case 0xC0:
|
||||
@@ -10,9 +8,9 @@
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7: /* FLD STx */
|
||||
ll = ST(nextop&7).ll;
|
||||
ll = ST(nextop&7).sq;
|
||||
fpu_do_push(emu);
|
||||
ST0.ll = ll;
|
||||
ST0.sq = ll;
|
||||
break;
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
@@ -22,27 +20,19 @@
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF: /* FXCH STx */
|
||||
ll = ST(nextop&7).ll;
|
||||
ST(nextop&7).ll = ST0.ll;
|
||||
ST0.ll = ll;
|
||||
ll = ST(nextop&7).sq;
|
||||
ST(nextop&7).sq = ST0.sq;
|
||||
ST0.sq = ll;
|
||||
break;
|
||||
|
||||
case 0xD0: /* FNOP */
|
||||
break;
|
||||
|
||||
case 0xE0: /* FCHS */
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = -ST0.f;
|
||||
#else
|
||||
ST0.d = -ST0.d;
|
||||
#endif
|
||||
break;
|
||||
case 0xE1: /* FABS */
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = fabsf(ST0.f);
|
||||
#else
|
||||
ST0.d = fabs(ST0.d);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 0xE4: /* FTST */
|
||||
@@ -54,175 +44,132 @@
|
||||
|
||||
case 0xE8: /* FLD1 */
|
||||
fpu_do_push(emu);
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = 1.0f;
|
||||
#else
|
||||
ST0.d = 1.0;
|
||||
#endif
|
||||
break;
|
||||
case 0xE9: /* FLDL2T */
|
||||
fpu_do_push(emu);
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = L2T;
|
||||
#else
|
||||
ST0.d = L2T;
|
||||
#endif
|
||||
break;
|
||||
case 0xEA: /* FLDL2E */
|
||||
fpu_do_push(emu);
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = L2E;
|
||||
#else
|
||||
ST0.d = L2E;
|
||||
#endif
|
||||
break;
|
||||
case 0xEB: /* FLDPI */
|
||||
fpu_do_push(emu);
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = PI;
|
||||
#else
|
||||
ST0.d = PI;
|
||||
#endif
|
||||
break;
|
||||
case 0xEC: /* FLDLG2 */
|
||||
fpu_do_push(emu);
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = LG2;
|
||||
#else
|
||||
ST0.d = LG2;
|
||||
#endif
|
||||
break;
|
||||
case 0xED: /* FLDLN2 */
|
||||
fpu_do_push(emu);
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = LN2;
|
||||
#else
|
||||
ST0.d = LN2;
|
||||
#endif
|
||||
break;
|
||||
case 0xEE: /* FLDZ */
|
||||
fpu_do_push(emu);
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = 0.0f;
|
||||
#else
|
||||
ST0.d = 0.0;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 0xF0: /* F2XM1 */
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = exp2f(ST0.f) - 1.0f;
|
||||
#else
|
||||
ST0.d = exp2(ST0.d) - 1.0;
|
||||
#endif
|
||||
break;
|
||||
case 0xF1: /* FYL2X */
|
||||
#ifdef USE_FLOAT
|
||||
ST(1).f = log2f(ST0.f)*ST(1).f;
|
||||
#else
|
||||
ST(1).d = log2(ST0.d)*ST(1).d;
|
||||
#endif
|
||||
ST(1).d *= log2(ST0.d);
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 0xF2: /* FTAN */
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = tanf(ST0.f);
|
||||
fpu_do_push(emu);
|
||||
ST0.f = 1.0f;
|
||||
#else
|
||||
case 0xF2: /* FPTAN */
|
||||
ST0.d = tan(ST0.d);
|
||||
fpu_do_push(emu);
|
||||
ST0.d = 1.0;
|
||||
#endif
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
break;
|
||||
case 0xF3: /* FPATAN */
|
||||
#ifdef USE_FLOAT
|
||||
ST1.f = atan2f(ST1.f, ST0.f);
|
||||
#else
|
||||
ST1.d = atan2(ST1.d, ST0.d);
|
||||
#endif
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 0xF4: /* FXTRACT */
|
||||
#ifdef USE_FLOAT
|
||||
tmp32s = (ST0.ll&0x7f700000)>>23;
|
||||
tmp32s -= 127;
|
||||
ST0.f /= exp2f(tmp32s);
|
||||
fpu_do_push(emu);
|
||||
ST0.f = tmp32s;
|
||||
#else
|
||||
tmp32s = (ST0.ll&0x7ff0000000000000LL)>>52;
|
||||
tmp32s -= 1023;
|
||||
ST0.d /= exp2(tmp32s);
|
||||
ST0.d = frexp(ST0.d, &tmp32s);
|
||||
fpu_do_push(emu);
|
||||
ST0.d = tmp32s;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 0xF8: /* FPREM */
|
||||
#ifdef USE_FLOAT
|
||||
tmp32s = ST0.f / ST1.f;
|
||||
ST0.f -= ST1.f * tmp32s;
|
||||
#else
|
||||
tmp32s = ST0.d / ST1.d;
|
||||
ST0.d -= ST1.d * tmp32s;
|
||||
#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);
|
||||
{
|
||||
int e0, e1;
|
||||
frexp(ST0.d, &e0);
|
||||
frexp(ST1.d, &e1);
|
||||
tmp32s = e0 - e1;
|
||||
}
|
||||
if(tmp32s<64)
|
||||
{
|
||||
ll = (int64_t)floor(ST0.d/ST1.d);
|
||||
ST0.d = ST0.d - (ST1.d*ll);
|
||||
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 {
|
||||
ll = (int64_t)(floor((ST0.d/ST1.d))/exp2(tmp32s - 32));
|
||||
ST0.d = ST0.d - ST1.d*ll*exp2(tmp32s - 32);
|
||||
emu->sw.f.F87_C2 = 1;
|
||||
}
|
||||
break;
|
||||
case 0xF5: /* FPREM1 */
|
||||
// get exponant(ST(0))-exponant(ST(1)) in temp32s
|
||||
{
|
||||
int e0, e1;
|
||||
frexp(ST0.d, &e0);
|
||||
frexp(ST1.d, &e1);
|
||||
tmp32s = e0 - e1;
|
||||
}
|
||||
if(tmp32s<64)
|
||||
{
|
||||
ll = (int64_t)round(ST0.d/ST1.d);
|
||||
ST0.d = ST0.d - (ST1.d*ll);
|
||||
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 {
|
||||
ll = (int64_t)(trunc((ST0.d/ST1.d))/exp2(tmp32s - 32));
|
||||
ST0.d = ST0.d - ST1.d*ll*exp2(tmp32s - 32);
|
||||
emu->sw.f.F87_C2 = 1;
|
||||
}
|
||||
break;
|
||||
case 0xF6: /* FDECSTP */
|
||||
emu->top=(emu->top-1)&7; // this will probably break a few things
|
||||
break;
|
||||
case 0xF7: /* FINCSTP */
|
||||
emu->top=(emu->top+1)&7; // this will probably break a few things
|
||||
break;
|
||||
case 0xF9: /* FYL2XP1 */
|
||||
#ifdef USE_FLOAT
|
||||
ST(1).f = log2f(ST0.f + 1.0f)*ST(1).f;
|
||||
#else
|
||||
ST(1).d = log2(ST0.d + 1.0)*ST(1).d;
|
||||
#endif
|
||||
ST(1).d *= log2(ST0.d + 1.0);
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 0xFA: /* FSQRT */
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = sqrtf(ST0.f);
|
||||
#else
|
||||
ST0.d = sqrt(ST0.d);
|
||||
#endif
|
||||
break;
|
||||
case 0xFB: /* FSINCOS */
|
||||
fpu_do_push(emu);
|
||||
#ifdef USE_FLOAT
|
||||
sincosf(ST1.f, &ST1.f, &ST0.f);
|
||||
#else
|
||||
sincos(ST1.d, &ST1.d, &ST0.d);
|
||||
#endif
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
break;
|
||||
case 0xFC: /* FRNDINT */
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = fpu_round(emu, ST0.f);
|
||||
#else
|
||||
ST0.d = fpu_round(emu, ST0.d);
|
||||
#endif
|
||||
break;
|
||||
case 0xFD: /* FSCALE */
|
||||
// this could probably be done by just altering the exponant part of the float...
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f *= exp2f(truncf(ST1.f));
|
||||
#else
|
||||
ST0.d *= exp2(trunc(ST1.d));
|
||||
#endif
|
||||
if(ST0.d!=0.0)
|
||||
ST0.d *= exp2(trunc(ST1.d));
|
||||
break;
|
||||
case 0xFE: /* FSIN */
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = sinf(ST0.f);
|
||||
#else
|
||||
ST0.d = sin(ST0.d);
|
||||
#endif
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
break;
|
||||
case 0xFF: /* FCOS */
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = cosf(ST0.f);
|
||||
#else
|
||||
ST0.d = cos(ST0.d);
|
||||
#endif
|
||||
emu->sw.f.F87_C2 = 0;
|
||||
break;
|
||||
|
||||
|
||||
@@ -244,51 +191,36 @@
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
case 0xEF:
|
||||
case 0xF5:
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
goto _default;
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: /* FLD ST0, Ed float */
|
||||
GET_ED;
|
||||
fpu_do_push(emu);
|
||||
#ifdef USE_FLOAT
|
||||
ST0.ll = ED->dword[0];
|
||||
#else
|
||||
if(!(((uintptr_t)ED)&3))
|
||||
ST0.d = *(float*)ED;
|
||||
else {
|
||||
memcpy(&f, ED->dword, sizeof(float));
|
||||
memcpy(&f, ED, sizeof(float));
|
||||
ST0.d = f;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case 2: /* FST Ed, ST0 */
|
||||
GET_ED;
|
||||
#ifdef USE_FLOAT
|
||||
*(float*)ED = ST0.f;
|
||||
#else
|
||||
if(!(((uintptr_t)ED)&3))
|
||||
*(float*)ED = ST0.d;
|
||||
else {
|
||||
f = ST0.d;
|
||||
memcpy(ED->dword, &f, sizeof(float));
|
||||
memcpy(ED, &f, sizeof(float));
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case 3: /* FSTP Ed, ST0 */
|
||||
GET_ED;
|
||||
#ifdef USE_FLOAT
|
||||
ED->dword[0] = ST0.ll;
|
||||
#else
|
||||
if(!(((uintptr_t)ED)&3))
|
||||
*(float*)ED = ST0.d;
|
||||
else {
|
||||
f = ST0.d;
|
||||
memcpy(ED->dword, &f, sizeof(float));
|
||||
memcpy(ED, &f, sizeof(float));
|
||||
}
|
||||
#endif
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 4: /* FLDENV m */
|
||||
@@ -306,9 +238,6 @@
|
||||
// warning, incomplete
|
||||
GET_ED;
|
||||
fpu_savenv(emu, (char*)ED, 0);
|
||||
ED->dword[0] = emu->cw;
|
||||
ED->dword[1] = emu->sw.x16;
|
||||
// tagword: 2bits*8
|
||||
// intruction pointer: 48bits
|
||||
// data (operand) pointer: 48bits
|
||||
// last opcode: 11bits save: 16bits restaured (1st and 2nd opcode only)
|
||||
@@ -321,4 +250,3 @@
|
||||
goto _default;
|
||||
}
|
||||
}
|
||||
#pragma GCC diagnostic pop
|
||||
+6
-34
@@ -11,7 +11,7 @@
|
||||
case 0xC7:
|
||||
CHECK_FLAGS(emu);
|
||||
if(ACCESS_FLAG(F_CF))
|
||||
ST0.ll = ST(nextop&7).ll;
|
||||
ST0.q = ST(nextop&7).q;
|
||||
break;
|
||||
case 0xC8: /* FCMOVE ST(0), ST(i) */
|
||||
case 0xC9:
|
||||
@@ -23,7 +23,7 @@
|
||||
case 0xCF:
|
||||
CHECK_FLAGS(emu);
|
||||
if(ACCESS_FLAG(F_ZF))
|
||||
ST0.ll = ST(nextop&7).ll;
|
||||
ST0.q = ST(nextop&7).q;
|
||||
break;
|
||||
case 0xD0: /* FCMOVBE ST(0), ST(i) */
|
||||
case 0xD1:
|
||||
@@ -35,7 +35,7 @@
|
||||
case 0xD7:
|
||||
CHECK_FLAGS(emu);
|
||||
if(ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF))
|
||||
ST0.ll = ST(nextop&7).ll;
|
||||
ST0.q = ST(nextop&7).q;
|
||||
break;
|
||||
case 0xD8: /* FCMOVU ST(0), ST(i) */
|
||||
case 0xD9:
|
||||
@@ -47,15 +47,11 @@
|
||||
case 0xDF:
|
||||
CHECK_FLAGS(emu);
|
||||
if(ACCESS_FLAG(F_PF))
|
||||
ST0.ll = ST(nextop&7).ll;
|
||||
ST0.q = ST(nextop&7).q;
|
||||
break;
|
||||
|
||||
case 0xE9: /* FUCOMPP */
|
||||
#ifdef USE_FLOAT
|
||||
fpu_fcom(emu, ST1.f);
|
||||
#else
|
||||
fpu_fcom(emu, ST1.d); // bad, should handle QNaN and IA interrupt
|
||||
#endif
|
||||
fpu_do_pop(emu);
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
@@ -76,19 +72,11 @@
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: /* FIADD ST0, Ed int */
|
||||
GET_ED;
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f += ED->sdword[0];
|
||||
#else
|
||||
ST0.d += ED->sdword[0];
|
||||
#endif
|
||||
break;
|
||||
case 1: /* FIMUL ST0, Ed int */
|
||||
GET_ED;
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f *= ED->sdword[0];
|
||||
#else
|
||||
ST0.d *= ED->sdword[0];
|
||||
#endif
|
||||
break;
|
||||
case 2: /* FICOM ST0, Ed int */
|
||||
GET_ED;
|
||||
@@ -101,35 +89,19 @@
|
||||
break;
|
||||
case 4: /* FISUB ST0, Ed int */
|
||||
GET_ED;
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f -= ED->sdword[0];
|
||||
#else
|
||||
ST0.d -= ED->sdword[0];
|
||||
#endif
|
||||
break;
|
||||
case 5: /* FISUBR ST0, Ed int */
|
||||
GET_ED;
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = ED->sdword[0] - ST0.f;
|
||||
#else
|
||||
ST0.d = ED->sdword[0] - ST0.d;
|
||||
#endif
|
||||
ST0.d = (double)ED->sdword[0] - ST0.d;
|
||||
break;
|
||||
case 6: /* FIDIV ST0, Ed int */
|
||||
GET_ED;
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f /= ED->sdword[0];
|
||||
#else
|
||||
ST0.d /= ED->sdword[0];
|
||||
#endif
|
||||
break;
|
||||
case 7: /* FIDIVR ST0, Ed int */
|
||||
GET_ED;
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = ED->sdword[0] / ST0.f;
|
||||
#else
|
||||
ST0.d = ED->sdword[0] / ST0.d;
|
||||
#endif
|
||||
ST0.d = (double)ED->sdword[0] / ST0.d;
|
||||
break;
|
||||
}
|
||||
}
|
||||
+16
-108
@@ -10,7 +10,7 @@
|
||||
case 0xC7:
|
||||
CHECK_FLAGS(emu);
|
||||
if(!ACCESS_FLAG(F_CF))
|
||||
ST0.ll = ST(nextop&7).ll;
|
||||
ST0.q = ST(nextop&7).q;
|
||||
break;
|
||||
case 0xC8: /* FCMOVNE ST(0), ST(i) */
|
||||
case 0xC9:
|
||||
@@ -22,7 +22,7 @@
|
||||
case 0xCF:
|
||||
CHECK_FLAGS(emu);
|
||||
if(!ACCESS_FLAG(F_ZF))
|
||||
ST0.ll = ST(nextop&7).ll;
|
||||
ST0.q = ST(nextop&7).q;
|
||||
break;
|
||||
case 0xD0: /* FCMOVNBE ST(0), ST(i) */
|
||||
case 0xD1:
|
||||
@@ -34,7 +34,7 @@
|
||||
case 0xD7:
|
||||
CHECK_FLAGS(emu);
|
||||
if(!(ACCESS_FLAG(F_CF) || ACCESS_FLAG(F_ZF)))
|
||||
ST0.ll = ST(nextop&7).ll;
|
||||
ST0.q = ST(nextop&7).q;
|
||||
break;
|
||||
case 0xD8: /* FCMOVNU ST(0), ST(i) */
|
||||
case 0xD9:
|
||||
@@ -46,9 +46,11 @@
|
||||
case 0xDF:
|
||||
CHECK_FLAGS(emu);
|
||||
if(!ACCESS_FLAG(F_PF))
|
||||
ST0.ll = ST(nextop&7).ll;
|
||||
ST0.q = ST(nextop&7).q;
|
||||
break;
|
||||
|
||||
case 0xE1: /* FDISI8087_NOP */
|
||||
break;
|
||||
case 0xE2: /* FNCLEX */
|
||||
//Clears the floating-point exception flags (PE, UE, OE, ZE, DE, and IE),
|
||||
// the exception summary status flag (ES), the stack fault flag (SF), and the busy flag (B) in the FPU status word
|
||||
@@ -73,11 +75,7 @@
|
||||
case 0xED:
|
||||
case 0xEE:
|
||||
case 0xEF:
|
||||
#ifdef USE_FLOAT
|
||||
fpu_fcomi(emu, ST(nextop&7).f);
|
||||
#else
|
||||
fpu_fcomi(emu, ST(nextop&7).d); // bad, should handle QNaN and IA interrupt
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 0xF0: /* FCOMI ST0, STx */
|
||||
@@ -88,14 +86,9 @@
|
||||
case 0xF5:
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
#ifdef USE_FLOAT
|
||||
fpu_fcomi(emu, ST(nextop&7).f);
|
||||
#else
|
||||
fpu_fcomi(emu, ST(nextop&7).d);
|
||||
#endif
|
||||
break;
|
||||
case 0xE0:
|
||||
case 0xE1:
|
||||
case 0xE4:
|
||||
case 0xE5:
|
||||
case 0xE6:
|
||||
@@ -103,134 +96,49 @@
|
||||
goto _default;
|
||||
default:
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: /* FILD ST0, Gd */
|
||||
case 0: /* FILD ST0, Ed */
|
||||
GET_ED;
|
||||
fpu_do_push(emu);
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = ED->sdword[0];
|
||||
#else
|
||||
ST0.d = ED->sdword[0];
|
||||
#endif
|
||||
break;
|
||||
case 1: /* FISTTP Ed, ST0 */
|
||||
GET_ED;
|
||||
#ifdef USE_FLOAT
|
||||
tmp32s = ST0.f; // TODO: Handling of FPU Exception
|
||||
if(tmp32s==0x7fffffff && isgreater(ST0.f, (float)(int32_t)0x7fffffff))
|
||||
tmp32s = 0x80000000;
|
||||
#else
|
||||
tmp32s = ST0.d; // TODO: Handling of FPU Exception
|
||||
if(tmp32s==0x7fffffff && isgreater(ST0.d, (double)(int32_t)0x7fffffff))
|
||||
tmp32s = 0x80000000;
|
||||
#endif
|
||||
fpu_do_pop(emu);
|
||||
ED->sdword[0] = tmp32s;
|
||||
break;
|
||||
case 2: /* FIST Ed, ST0 */
|
||||
GET_ED;
|
||||
#ifdef USE_FLOAT
|
||||
if(isgreater(ST0.f, (float)(int32_t)0x7fffffff) || isless(ST0.f, -(float)(int32_t)0x7fffffff))
|
||||
if(isgreater(ST0.d, (double)(int32_t)0x7fffffff) || isless(ST0.d, -(double)(int32_t)0x7fffffff) || !isfinite(ST0.d))
|
||||
ED->sdword[0] = 0x80000000;
|
||||
else {
|
||||
switch(emu->round) {
|
||||
case ROUND_Nearest:
|
||||
ED->sdword[0] = floorf(ST0.f+0.5);
|
||||
break;
|
||||
case ROUND_Down:
|
||||
ED->sdword[0] = floorf(ST0.f);
|
||||
break;
|
||||
case ROUND_Up:
|
||||
ED->sdword[0] = ceilf(ST0.f);
|
||||
break;
|
||||
case ROUND_Chop:
|
||||
ED->sdword[0] = ST0.f;
|
||||
break;
|
||||
}
|
||||
volatile int32_t tmp = fpu_round(emu, ST0.d); // tmp to avoid BUS ERROR
|
||||
ED->sdword[0] = tmp;
|
||||
}
|
||||
#else
|
||||
if(isgreater(ST0.d, (double)(int32_t)0x7fffffff) || isless(ST0.d, -(double)(int32_t)0x7fffffff))
|
||||
ED->sdword[0] = 0x80000000;
|
||||
else {
|
||||
switch(emu->round) {
|
||||
case ROUND_Nearest:
|
||||
ED->sdword[0] = floor(ST0.d+0.5);
|
||||
break;
|
||||
case ROUND_Down:
|
||||
ED->sdword[0] = floor(ST0.d);
|
||||
break;
|
||||
case ROUND_Up:
|
||||
ED->sdword[0] = ceil(ST0.d);
|
||||
break;
|
||||
case ROUND_Chop:
|
||||
ED->sdword[0] = ST0.d;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case 3: /* FISTP Ed, ST0 */
|
||||
GET_ED;
|
||||
#ifdef USE_FLOAT
|
||||
if(isgreater(ST0.f, (float)(int32_t)0x7fffffff) || isless(ST0.f, -(float)(int32_t)0x7fffffff))
|
||||
if(isgreater(ST0.d, (double)(int32_t)0x7fffffff) || isless(ST0.d, -(double)(int32_t)0x7fffffff) || !isfinite(ST0.d))
|
||||
ED->sdword[0] = 0x80000000;
|
||||
else {
|
||||
switch(emu->round) {
|
||||
case ROUND_Nearest:
|
||||
ED->sdword[0] = floorf(ST0.f+0.5);
|
||||
break;
|
||||
case ROUND_Down:
|
||||
ED->sdword[0] = floorf(ST0.f);
|
||||
break;
|
||||
case ROUND_Up:
|
||||
ED->sdword[0] = ceilf(ST0.f);
|
||||
break;
|
||||
case ROUND_Chop:
|
||||
ED->sdword[0] = ST0.f;
|
||||
break;
|
||||
}
|
||||
volatile int32_t tmp = fpu_round(emu, ST0.d); // tmp to avoid BUS ERROR
|
||||
ED->sdword[0] = tmp;
|
||||
}
|
||||
#else
|
||||
if(isgreater(ST0.d, (double)(int32_t)0x7fffffff) || isless(ST0.d, -(double)(int32_t)0x7fffffff))
|
||||
ED->sdword[0] = 0x80000000;
|
||||
else {
|
||||
switch(emu->round) {
|
||||
case ROUND_Nearest:
|
||||
ED->sdword[0] = floor(ST0.d+0.5);
|
||||
break;
|
||||
case ROUND_Down:
|
||||
ED->sdword[0] = floor(ST0.d);
|
||||
break;
|
||||
case ROUND_Up:
|
||||
ED->sdword[0] = ceil(ST0.d);
|
||||
break;
|
||||
case ROUND_Chop:
|
||||
ED->sdword[0] = ST0.d;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 5: /* FLD ST0, Gt */
|
||||
case 5: /* FLD ST0, Et */
|
||||
GET_ED;
|
||||
fpu_do_push(emu);
|
||||
memcpy(&STld(0).ld, ED, 10);
|
||||
#ifdef USE_FLOAT
|
||||
LD2D(&STld(0), &d);
|
||||
ST0.f = d;
|
||||
#else
|
||||
LD2D(&STld(0), &ST(0).d);
|
||||
#endif
|
||||
STld(0).ref = ST0.ll;
|
||||
STld(0).uref = ST0.q;
|
||||
break;
|
||||
case 7: /* FSTP tbyte */
|
||||
GET_ED;
|
||||
if(ST0.ll!=STld(0).ref)
|
||||
#ifdef USE_FLOAT
|
||||
{d = ST0.f; D2LD(&d, ED);}
|
||||
#else
|
||||
if(ST0.q!=STld(0).uref)
|
||||
D2LD(&ST0.d, ED);
|
||||
#endif
|
||||
else
|
||||
memcpy(ED, &STld(0).ld, 10);
|
||||
fpu_do_pop(emu);
|
||||
|
||||
+9
-97
@@ -1,5 +1,3 @@
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
|
||||
nextop = F8;
|
||||
switch(nextop) {
|
||||
case 0xC0:
|
||||
@@ -10,11 +8,7 @@
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7: /* FADD */
|
||||
#ifdef USE_FLOAT
|
||||
ST(nextop&7).f += ST0.f;
|
||||
#else
|
||||
ST(nextop&7).d += ST0.d;
|
||||
#endif
|
||||
break;
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
@@ -24,11 +18,7 @@
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF: /* FMUL */
|
||||
#ifdef USE_FLOAT
|
||||
ST(nextop&7).f *= ST0.f;
|
||||
#else
|
||||
ST(nextop&7).d *= ST0.d;
|
||||
#endif
|
||||
break;
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
@@ -38,11 +28,7 @@
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7: /* FCOM */
|
||||
#ifdef USE_FLOAT
|
||||
fpu_fcom(emu, ST(nextop&7).f);
|
||||
#else
|
||||
fpu_fcom(emu, ST(nextop&7).d);
|
||||
#endif
|
||||
break;
|
||||
case 0xD8:
|
||||
case 0xD9:
|
||||
@@ -52,11 +38,7 @@
|
||||
case 0xDD:
|
||||
case 0xDE:
|
||||
case 0xDF: /* FCOMP */
|
||||
#ifdef USE_FLOAT
|
||||
fpu_fcom(emu, ST(nextop&7).f);
|
||||
#else
|
||||
fpu_fcom(emu, ST(nextop&7).d); // TODO: is this ok?
|
||||
#endif
|
||||
fpu_fcom(emu, ST(nextop&7).d);
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 0xE0:
|
||||
@@ -67,11 +49,7 @@
|
||||
case 0xE5:
|
||||
case 0xE6:
|
||||
case 0xE7: /* FSUBR */
|
||||
#ifdef USE_FLOAT
|
||||
ST(nextop&7).f = ST0.f -ST(nextop&7).f;
|
||||
#else
|
||||
ST(nextop&7).d = ST0.d -ST(nextop&7).d;
|
||||
#endif
|
||||
break;
|
||||
case 0xE8:
|
||||
case 0xE9:
|
||||
@@ -81,11 +59,7 @@
|
||||
case 0xED:
|
||||
case 0xEE:
|
||||
case 0xEF: /* FSUB */
|
||||
#ifdef USE_FLOAT
|
||||
ST(nextop&7).f -= ST0.f;
|
||||
#else
|
||||
ST(nextop&7).d -= ST0.d;
|
||||
#endif
|
||||
break;
|
||||
case 0xF0:
|
||||
case 0xF1:
|
||||
@@ -95,11 +69,7 @@
|
||||
case 0xF5:
|
||||
case 0xF6:
|
||||
case 0xF7: /* FDIVR */
|
||||
#ifdef USE_FLOAT
|
||||
ST(nextop&7).f = ST0.f / ST(nextop&7).f;
|
||||
#else
|
||||
ST(nextop&7).d = ST0.d / ST(nextop&7).d;
|
||||
#endif
|
||||
break;
|
||||
case 0xF8:
|
||||
case 0xF9:
|
||||
@@ -109,54 +79,32 @@
|
||||
case 0xFD:
|
||||
case 0xFE:
|
||||
case 0xFF: /* FDIV */
|
||||
#ifdef USE_FLOAT
|
||||
ST(nextop&7).f /= ST0.f;
|
||||
#else
|
||||
ST(nextop&7).d /= ST0.d;
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
GET_ED;
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: /* FADD ST0, double */
|
||||
#ifdef USE_FLOAT
|
||||
if(!(((uintptr_t)ED)&7))
|
||||
ST0.f += *(double*)ED;
|
||||
else {
|
||||
*(uint64_t*)&d = *(uint64_t*)ED;
|
||||
ST0.f += d;
|
||||
}
|
||||
#else
|
||||
if(!(((uintptr_t)ED)&7))
|
||||
ST0.d += *(double*)ED;
|
||||
else {
|
||||
*(uint64_t*)&d = *(uint64_t*)ED;
|
||||
memcpy(&d, ED, sizeof(double));
|
||||
ST0.d += d;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case 1: /* FMUL ST0, double */
|
||||
#ifdef USE_FLOAT
|
||||
if(!(((uintptr_t)ED)&7))
|
||||
ST0.f *= *(double*)ED;
|
||||
else {
|
||||
*(uint64_t*)&d = *(uint64_t*)ED;
|
||||
ST0.f *= d;
|
||||
}
|
||||
#else
|
||||
if(!(((uintptr_t)ED)&7))
|
||||
ST0.d *= *(double*)ED;
|
||||
else {
|
||||
*(uint64_t*)&d = *(uint64_t*)ED;
|
||||
memcpy(&d, ED, sizeof(double));
|
||||
ST0.d *= d;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case 2: /* FCOM ST0, double */
|
||||
if(!(((uintptr_t)ED)&7))
|
||||
fpu_fcom(emu, *(double*)ED);
|
||||
else {
|
||||
*(uint64_t*)&d = *(uint64_t*)ED;
|
||||
memcpy(&d, ED, sizeof(double));
|
||||
fpu_fcom(emu, d);
|
||||
}
|
||||
break;
|
||||
@@ -164,78 +112,42 @@
|
||||
if(!(((uintptr_t)ED)&7))
|
||||
fpu_fcom(emu, *(double*)ED);
|
||||
else {
|
||||
*(uint64_t*)&d = *(uint64_t*)ED;
|
||||
memcpy(&d, ED, sizeof(double));
|
||||
fpu_fcom(emu, d);
|
||||
}
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 4: /* FSUB ST0, double */
|
||||
#ifdef USE_FLOAT
|
||||
if(!(((uintptr_t)ED)&7))
|
||||
ST0.f -= *(double*)ED;
|
||||
else {
|
||||
*(uint64_t*)&d = *(uint64_t*)ED;
|
||||
ST0.f -= d;
|
||||
}
|
||||
#else
|
||||
if(!(((uintptr_t)ED)&7))
|
||||
ST0.d -= *(double*)ED;
|
||||
else {
|
||||
*(uint64_t*)&d = *(uint64_t*)ED;
|
||||
memcpy(&d, ED, sizeof(double));
|
||||
ST0.d -= d;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case 5: /* FSUBR ST0, double */
|
||||
#ifdef USE_FLOAT
|
||||
if(!(((uintptr_t)ED)&7))
|
||||
ST0.f = *(double*)ED - ST0.f;
|
||||
else {
|
||||
*(uint64_t*)&d = *(uint64_t*)ED;
|
||||
ST0.f = d - ST0.f;
|
||||
}
|
||||
#else
|
||||
if(!(((uintptr_t)ED)&7))
|
||||
ST0.d = *(double*)ED - ST0.d;
|
||||
else {
|
||||
*(uint64_t*)&d = *(uint64_t*)ED;
|
||||
memcpy(&d, ED, sizeof(double));
|
||||
ST0.d = d - ST0.d;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case 6: /* FDIV ST0, double */
|
||||
#ifdef USE_FLOAT
|
||||
if(!(((uintptr_t)ED)&7))
|
||||
ST0.f /= *(double*)ED;
|
||||
else {
|
||||
*(uint64_t*)&d = *(uint64_t*)ED;
|
||||
ST0.f /= d;
|
||||
}
|
||||
#else
|
||||
if(!(((uintptr_t)ED)&7))
|
||||
ST0.d /= *(double*)ED;
|
||||
else {
|
||||
*(uint64_t*)&d = *(uint64_t*)ED;
|
||||
memcpy(&d, ED, sizeof(double));
|
||||
ST0.d /= d;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case 7: /* FDIVR ST0, double */
|
||||
#ifdef USE_FLOAT
|
||||
if(!(((uintptr_t)ED)&7))
|
||||
ST0.f = *(double*)ED / ST0.f;
|
||||
else {
|
||||
*(uint64_t*)&d = *(uint64_t*)ED;
|
||||
ST0.f = d / ST0.f;
|
||||
}
|
||||
#else
|
||||
if(!(((uintptr_t)ED)&7))
|
||||
ST0.d = *(double*)ED / ST0.d;
|
||||
else {
|
||||
*(uint64_t*)&d = *(uint64_t*)ED;
|
||||
memcpy(&d, ED, sizeof(double));
|
||||
ST0.d = d / ST0.d;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
goto _default;
|
||||
|
||||
+25
-44
@@ -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:
|
||||
@@ -19,7 +20,7 @@
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
ST(nextop&7).ll = ST0.ll;
|
||||
ST(nextop&7).q = ST0.q;
|
||||
break;
|
||||
case 0xD8: /* FSTP ST0, STx */
|
||||
case 0xD9:
|
||||
@@ -29,7 +30,7 @@
|
||||
case 0xDD:
|
||||
case 0xDE:
|
||||
case 0xDF:
|
||||
ST(nextop&7).ll = ST0.ll;
|
||||
ST(nextop&7).q = ST0.q;
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 0xE0: /* FUCOM ST0, STx */
|
||||
@@ -40,11 +41,7 @@
|
||||
case 0xE5:
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
#ifdef USE_FLOAT
|
||||
fpu_fcom(emu, ST(nextop&7).f);
|
||||
#else
|
||||
fpu_fcom(emu, ST(nextop&7).d); // bad, should handle QNaN and IA interrupt
|
||||
#endif
|
||||
break;
|
||||
case 0xE8: /* FUCOMP ST0, STx */
|
||||
case 0xE9:
|
||||
@@ -54,11 +51,7 @@
|
||||
case 0xED:
|
||||
case 0xEE:
|
||||
case 0xEF:
|
||||
#ifdef USE_FLOAT
|
||||
fpu_fcom(emu, ST(nextop&7).f);
|
||||
#else
|
||||
fpu_fcom(emu, ST(nextop&7).d); // bad, should handle QNaN and IA interrupt
|
||||
#endif
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
|
||||
@@ -93,39 +86,37 @@
|
||||
case 0: /* FLD double */
|
||||
GET_ED;
|
||||
fpu_do_push(emu);
|
||||
#ifdef USE_FLOAT
|
||||
*(uint64_t*)&d = *(int64_t*)ED;
|
||||
ST0.f = d;
|
||||
#else
|
||||
ST0.ll = *(int64_t*)ED;
|
||||
#endif
|
||||
if(!(((uintptr_t)ED)&7))
|
||||
ST0.d = *(double*)ED;
|
||||
else {
|
||||
memcpy(&ST0.d, ED, sizeof(double));
|
||||
}
|
||||
break;
|
||||
case 1: /* FISTTP ED qword */
|
||||
GET_ED;
|
||||
#ifdef USE_FLOAT
|
||||
*(int64_t*)ED = ST0.f;
|
||||
#else
|
||||
*(int64_t*)ED = ST0.d;
|
||||
#endif
|
||||
if(!(((uintptr_t)ED)&7))
|
||||
*(int64_t*)ED = ST0.d;
|
||||
else {
|
||||
int64_t i64 = ST0.d;
|
||||
memcpy(ED, &i64, sizeof(int64_t));
|
||||
}
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 2: /* FST double */
|
||||
GET_ED;
|
||||
#ifdef USE_FLOAT
|
||||
d = ST0.f;
|
||||
*(int64_t*)ED = *(uint64_t*)&d;
|
||||
#else
|
||||
*(int64_t*)ED = ST0.ll;
|
||||
#endif
|
||||
if(!(((uintptr_t)ED)&7))
|
||||
*(double*)ED = ST0.d;
|
||||
else {
|
||||
memcpy(ED, &ST0.d, sizeof(double));
|
||||
}
|
||||
break;
|
||||
case 3: /* FSTP double */
|
||||
GET_ED;
|
||||
#ifdef USE_FLOAT
|
||||
d = ST0.f;
|
||||
*(int64_t*)ED = *(uint64_t*)&d;
|
||||
#else
|
||||
*(int64_t*)ED = ST0.ll;
|
||||
#endif
|
||||
if(!(((uintptr_t)ED)&7))
|
||||
*(double*)ED = ST0.d;
|
||||
else {
|
||||
memcpy(ED, &ST0.d, sizeof(double));
|
||||
}
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 4: /* FRSTOR m108byte */
|
||||
@@ -136,12 +127,7 @@
|
||||
char* p =(char*)ED;
|
||||
p += 28;
|
||||
for (int i=0; i<8; ++i) {
|
||||
#ifdef USE_FLOAT
|
||||
d = ST(i).f;
|
||||
LD2D(p, &d);
|
||||
#else
|
||||
LD2D(p, &ST(i).d);
|
||||
#endif
|
||||
p+=10;
|
||||
}
|
||||
}
|
||||
@@ -156,12 +142,7 @@
|
||||
char* p =(char*)ED;
|
||||
p += 28;
|
||||
for (int i=0; i<8; ++i) {
|
||||
#ifdef USE_FLOAT
|
||||
D2LD(&d, p);
|
||||
ST(i).f = d;
|
||||
#else
|
||||
D2LD(&ST(i).d, p);
|
||||
#endif
|
||||
p+=10;
|
||||
}
|
||||
}
|
||||
|
||||
+18
-87
@@ -1,55 +1,41 @@
|
||||
nextop = F8;
|
||||
switch (nextop) {
|
||||
case 0xC1: /* FADDP ST1, ST0 */
|
||||
#ifdef USE_FLOAT
|
||||
ST(1).f += ST0.f;
|
||||
#else
|
||||
ST(1).d += ST0.d;
|
||||
#endif
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 0xC0: /* FADDP STx, ST0 */
|
||||
case 0xC1: /* FADDP ST1, ST0 */
|
||||
case 0xC2:
|
||||
case 0xC3:
|
||||
case 0xC4:
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
#ifdef USE_FLOAT
|
||||
ST(nextop&7).f += ST0.f;
|
||||
#else
|
||||
ST(nextop&7).d += ST0.d;
|
||||
#endif
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 0xC9: /* FMULP ST1, ST0 */
|
||||
#ifdef USE_FLOAT
|
||||
ST1.f *= ST0.f;
|
||||
#else
|
||||
ST1.d *= ST0.d;
|
||||
#endif
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 0xC8: /* FMULP STx, ST0 */
|
||||
case 0xC9: /* FMULP ST1, ST0 */
|
||||
case 0xCA:
|
||||
case 0xCB:
|
||||
case 0xCC:
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF:
|
||||
#ifdef USE_FLOAT
|
||||
ST(nextop&7).f *= ST0.f;
|
||||
#else
|
||||
ST(nextop&7).d *= ST0.d;
|
||||
#endif
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
case 0xD2:
|
||||
case 0xD3:
|
||||
case 0xD4:
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7: /* FCOMP */
|
||||
fpu_fcom(emu, ST(nextop&7).d);
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
|
||||
case 0xD9: /* FCOMPP */
|
||||
#ifdef USE_FLOAT
|
||||
fpu_fcom(emu, ST1.f);
|
||||
#else
|
||||
fpu_fcom(emu, ST1.d);
|
||||
#endif
|
||||
fpu_do_pop(emu);
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
@@ -65,33 +51,18 @@
|
||||
case 0xE5:
|
||||
case 0xE6:
|
||||
case 0xE7:
|
||||
#ifdef USE_FLOAT
|
||||
ST(nextop&7).f = ST0.f - ST(nextop&7).f;
|
||||
#else
|
||||
ST(nextop&7).d = ST0.d - ST(nextop&7).d;
|
||||
#endif
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 0xE9: /* FSUBP ST1, ST0 */
|
||||
#ifdef USE_FLOAT
|
||||
ST1.f -= ST0.f;
|
||||
#else
|
||||
ST1.d -= ST0.d;
|
||||
#endif
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 0xE8: /* FSUBP STx, ST0 */
|
||||
case 0xE9: /* FSUBP ST1, ST0 */
|
||||
case 0xEA:
|
||||
case 0xEB:
|
||||
case 0xEC:
|
||||
case 0xED:
|
||||
case 0xEE:
|
||||
case 0xEF:
|
||||
#ifdef USE_FLOAT
|
||||
ST(nextop&7).f -= ST0.f;
|
||||
#else
|
||||
ST(nextop&7).d -= ST0.d;
|
||||
#endif
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 0xF0: /* FDIVRP STx, ST0 */
|
||||
@@ -102,11 +73,7 @@
|
||||
case 0xF5:
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
#ifdef USE_FLOAT
|
||||
ST(nextop&7).f = ST0.f / ST(nextop&7).f;
|
||||
#else
|
||||
ST(nextop&7).d = ST0.d / ST(nextop&7).d;
|
||||
#endif
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 0xF8: /* FDIVP STx, ST0 */
|
||||
@@ -117,23 +84,11 @@
|
||||
case 0xFD:
|
||||
case 0xFE:
|
||||
case 0xFF:
|
||||
#ifdef USE_FLOAT
|
||||
ST(nextop&7).f /= ST0.f;
|
||||
#else
|
||||
ST(nextop&7).d /= ST0.d;
|
||||
#endif
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
case 0xD2:
|
||||
case 0xD3:
|
||||
case 0xD4:
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
case 0xD8:
|
||||
case 0xD8:
|
||||
case 0xDA:
|
||||
case 0xDB:
|
||||
case 0xDC:
|
||||
@@ -146,51 +101,27 @@
|
||||
switch((nextop>>3)&7) {
|
||||
case 0: /* FIADD ST0, Ew int */
|
||||
GET_EW;
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f += EW->sword[0];
|
||||
#else
|
||||
ST0.d += EW->sword[0];
|
||||
#endif
|
||||
break;
|
||||
case 1: /* FIMUL ST0, Ew int */
|
||||
GET_EW;
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f *= EW->sword[0];
|
||||
#else
|
||||
ST0.d *= EW->sword[0];
|
||||
#endif
|
||||
break;
|
||||
case 4: /* FISUB ST0, Ew int */
|
||||
GET_EW;
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f -= EW->sword[0];
|
||||
#else
|
||||
ST0.d -= EW->sword[0];
|
||||
#endif
|
||||
break;
|
||||
case 5: /* FISUBR ST0, Ew int */
|
||||
GET_EW;
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = EW->sword[0] - ST0.f;
|
||||
#else
|
||||
ST0.d = EW->sword[0] - ST0.d;
|
||||
#endif
|
||||
ST0.d = (double)EW->sword[0] - ST0.d;
|
||||
break;
|
||||
case 6: /* FIDIV ST0, Ew int */
|
||||
GET_EW;
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f /= EW->sword[0];
|
||||
#else
|
||||
ST0.d /= EW->sword[0];
|
||||
#endif
|
||||
break;
|
||||
case 7: /* FIDIVR ST0, Ew int */
|
||||
GET_EW;
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = EW->sword[0] / ST0.f;
|
||||
#else
|
||||
ST0.d = EW->sword[0] / ST0.d;
|
||||
#endif
|
||||
ST0.d = (double)EW->sword[0] / ST0.d;
|
||||
break;
|
||||
default:
|
||||
goto _default;
|
||||
|
||||
+52
-127
@@ -1,5 +1,29 @@
|
||||
nextop = F8;
|
||||
switch (nextop) {
|
||||
case 0xC0: /* FFREEP STx */
|
||||
case 0xC1:
|
||||
case 0xC2:
|
||||
case 0xC3:
|
||||
case 0xC4:
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
fpu_do_free(emu, nextop-0xC0);
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
|
||||
case 0xD0: /* FSTP STx, ST0 */
|
||||
case 0xD1:
|
||||
case 0xD2:
|
||||
case 0xD3:
|
||||
case 0xD4:
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
ST(nextop&7).q = ST0.q;
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
|
||||
case 0xE0: /* FNSTSW AX */
|
||||
emu->sw.f.F87_TOP = emu->top&7;
|
||||
R_AX = emu->sw.x16;
|
||||
@@ -13,11 +37,7 @@
|
||||
case 0xED:
|
||||
case 0xEE:
|
||||
case 0xEF:
|
||||
#ifdef USE_FLOAT
|
||||
fpu_fcomi(emu, ST(nextop&7).f);
|
||||
#else
|
||||
fpu_fcomi(emu, ST(nextop&7).d); // bad, should handle QNaN and IA interrupt
|
||||
#endif
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
|
||||
@@ -29,22 +49,10 @@
|
||||
case 0xF5:
|
||||
case 0xF6:
|
||||
case 0xF7:
|
||||
#ifdef USE_FLOAT
|
||||
fpu_fcomi(emu, ST(nextop&7).f);
|
||||
#else
|
||||
fpu_fcomi(emu, ST(nextop&7).d);
|
||||
#endif
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
|
||||
case 0xC0:
|
||||
case 0xC1:
|
||||
case 0xC2:
|
||||
case 0xC3:
|
||||
case 0xC4:
|
||||
case 0xC5:
|
||||
case 0xC6:
|
||||
case 0xC7:
|
||||
case 0xC8:
|
||||
case 0xC9:
|
||||
case 0xCA:
|
||||
@@ -53,14 +61,6 @@
|
||||
case 0xCD:
|
||||
case 0xCE:
|
||||
case 0xCF:
|
||||
case 0xD0:
|
||||
case 0xD1:
|
||||
case 0xD2:
|
||||
case 0xD3:
|
||||
case 0xD4:
|
||||
case 0xD5:
|
||||
case 0xD6:
|
||||
case 0xD7:
|
||||
case 0xD8:
|
||||
case 0xD9:
|
||||
case 0xDA:
|
||||
@@ -92,105 +92,27 @@
|
||||
GET_EW;
|
||||
tmp16s = EW->sword[0];
|
||||
fpu_do_push(emu);
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = tmp16s;
|
||||
#else
|
||||
ST0.d = tmp16s;
|
||||
#endif
|
||||
break;
|
||||
case 1: /* FISTTP Ew, ST0 */
|
||||
GET_EW;
|
||||
#ifdef USE_FLOAT
|
||||
tmp16s = ST0.f;
|
||||
#else
|
||||
tmp16s = ST0.d;
|
||||
#endif
|
||||
EW->sword[0] = tmp16s;
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 2: /* FIST Ew, ST0 */
|
||||
GET_EW;
|
||||
#ifdef USE_FLOAT
|
||||
if(isgreater(ST0.f, (float)(int32_t)0x7fff) || isless(ST0.f, -(float)(int32_t)0x7fff))
|
||||
if(isgreater(ST0.d, (double)(int32_t)0x7fff) || isless(ST0.d, -(double)(int32_t)0x7fff) || !isfinite(ST0.d))
|
||||
EW->sword[0] = 0x8000;
|
||||
else {
|
||||
switch(emu->round) {
|
||||
case ROUND_Nearest:
|
||||
EW->sword[0] = floorf(ST0.f+0.5);
|
||||
break;
|
||||
case ROUND_Down:
|
||||
EW->sword[0] = floorf(ST0.f);
|
||||
break;
|
||||
case ROUND_Up:
|
||||
EW->sword[0] = ceilf(ST0.f);
|
||||
break;
|
||||
case ROUND_Chop:
|
||||
EW->sword[0] = ST0.f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
if(isgreater(ST0.d, (double)(int32_t)0x7fff) || isless(ST0.d, -(double)(int32_t)0x7fff))
|
||||
EW->sword[0] = 0x8000;
|
||||
else {
|
||||
switch(emu->round) {
|
||||
case ROUND_Nearest:
|
||||
EW->sword[0] = floor(ST0.d+0.5);
|
||||
break;
|
||||
case ROUND_Down:
|
||||
EW->sword[0] = floor(ST0.d);
|
||||
break;
|
||||
case ROUND_Up:
|
||||
EW->sword[0] = ceil(ST0.d);
|
||||
break;
|
||||
case ROUND_Chop:
|
||||
EW->sword[0] = ST0.d;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else
|
||||
EW->sword[0] = fpu_round(emu, ST0.d);
|
||||
break;
|
||||
case 3: /* FISTP Ew, ST0 */
|
||||
GET_EW;
|
||||
#ifdef USE_FLOAT
|
||||
if(isgreater(ST0.f, (float)(int32_t)0x7fff) || isless(ST0.f, -(float)(int32_t)0x7fff))
|
||||
if(isgreater(ST0.d, (double)(int32_t)0x7fff) || isless(ST0.d, -(double)(int32_t)0x7fff) || !isfinite(ST0.d))
|
||||
EW->sword[0] = 0x8000;
|
||||
else {
|
||||
switch(emu->round) {
|
||||
case ROUND_Nearest:
|
||||
EW->sword[0] = floorf(ST0.f+0.5);
|
||||
break;
|
||||
case ROUND_Down:
|
||||
EW->sword[0] = floorf(ST0.f);
|
||||
break;
|
||||
case ROUND_Up:
|
||||
EW->sword[0] = ceilf(ST0.f);
|
||||
break;
|
||||
case ROUND_Chop:
|
||||
EW->sword[0] = ST0.f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
if(isgreater(ST0.d, (double)(int32_t)0x7fff) || isless(ST0.d, -(double)(int32_t)0x7fff))
|
||||
EW->sword[0] = 0x8000;
|
||||
else {
|
||||
switch(emu->round) {
|
||||
case ROUND_Nearest:
|
||||
EW->sword[0] = floor(ST0.d+0.5);
|
||||
break;
|
||||
case ROUND_Down:
|
||||
EW->sword[0] = floor(ST0.d);
|
||||
break;
|
||||
case ROUND_Up:
|
||||
EW->sword[0] = ceil(ST0.d);
|
||||
break;
|
||||
case ROUND_Chop:
|
||||
EW->sword[0] = ST0.d;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else
|
||||
EW->sword[0] = fpu_round(emu, ST0.d);
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
case 4: /* FBLD ST0, tbytes */
|
||||
@@ -202,13 +124,9 @@
|
||||
GET_ED;
|
||||
tmp64s = *(int64_t*)ED;
|
||||
fpu_do_push(emu);
|
||||
#ifdef USE_FLOAT
|
||||
ST0.f = tmp64s;
|
||||
#else
|
||||
ST0.d = tmp64s;
|
||||
#endif
|
||||
STll(0).ll = tmp64s;
|
||||
STll(0).ref = ST0.ll;
|
||||
STll(0).sq = tmp64s;
|
||||
STll(0).sref = ST0.sq;
|
||||
break;
|
||||
case 6: /* FBSTP tbytes, ST0 */
|
||||
GET_ED;
|
||||
@@ -217,20 +135,27 @@
|
||||
break;
|
||||
case 7: /* FISTP i64 */
|
||||
GET_ED;
|
||||
if(STll(0).ref==ST(0).ll) {
|
||||
*(int64_t*)ED = STll(0).ll;
|
||||
if((uintptr_t)ED & 0x7) {
|
||||
// un-aligned!
|
||||
if(STll(0).sref==ST(0).sq)
|
||||
memcpy(ED, &STll(0).sq, sizeof(int64_t));
|
||||
else {
|
||||
int64_t i64;
|
||||
if(isgreater(ST0.d, (double)(int64_t)0x7fffffffffffffffLL) || isless(ST0.d, -(double)(int64_t)0x7fffffffffffffffLL) || !isfinite(ST0.d))
|
||||
i64 = 0x8000000000000000LL;
|
||||
else
|
||||
i64 = fpu_round(emu, ST0.d);
|
||||
memcpy(ED, &i64, sizeof(int64_t));
|
||||
}
|
||||
} else {
|
||||
#ifdef USE_FLOAT
|
||||
if(isgreater(ST0.f, (float)(int64_t)0x7fffffffffffffffLL) || isless(ST0.f, (float)(int64_t)0x8000000000000000LL))
|
||||
*(int64_t*)ED = 0x8000000000000000LL;
|
||||
else
|
||||
*(int64_t*)ED = (int64_t)ST0.f;
|
||||
#else
|
||||
if(isgreater(ST0.d, (double)(int64_t)0x7fffffffffffffffLL) || isless(ST0.d, (double)(int64_t)0x8000000000000000LL))
|
||||
*(int64_t*)ED = 0x8000000000000000LL;
|
||||
else
|
||||
*(int64_t*)ED = (int64_t)ST0.d;
|
||||
#endif
|
||||
if(STll(0).sref==ST(0).sq)
|
||||
*(int64_t*)ED = STll(0).sq;
|
||||
else {
|
||||
if(isgreater(ST0.d, (double)(int64_t)0x7fffffffffffffffLL) || isless(ST0.d, -(double)(int64_t)0x7fffffffffffffffLL) || !isfinite(ST0.d))
|
||||
*(int64_t*)ED = 0x8000000000000000LL;
|
||||
else
|
||||
*(int64_t*)ED = fpu_round(emu, ST0.d);
|
||||
}
|
||||
}
|
||||
fpu_do_pop(emu);
|
||||
break;
|
||||
|
||||
Loaded 100 of 909 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user